Skip to content

Commit c78fa5a

Browse files
committed
😘👌 improve regex extraction in XPathy and Selectory, improve selector lists in Aspecty, XPathy, and Selectory
1 parent 3bf94e9 commit c78fa5a

File tree

6 files changed

+136
-113
lines changed

6 files changed

+136
-113
lines changed

‎aspecty.js

+35-29
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
/*
33
44
# Aspecty
5-
## version 0.0.9
5+
## version 0.0.10
66
77
Aspecty is a CSS reprocessor that adds support for an aspect-ratio property using JS. This plugin allows you to define a desired aspect-ratio for an element, based on its rendered width on the page.
88
@@ -175,46 +175,52 @@ License: MIT
175175
height = parseInt(value.split('/')[1])
176176
specificity = important || ''
177177

178-
// For each element matching this selector
179-
Array.from(document.querySelectorAll(selector), (tag, i) => {
178+
let selectorList = (selector.split(','))
180179

181-
elWidth = tag.offsetWidth || 0
180+
selectorList.map(partial => {
182181

183-
// If the matching element has a non-zero width
184-
if (elWidth) {
182+
// For each element matching this selector
183+
Array.from(document.querySelectorAll(partial), (tag, i) => {
185184

186-
// Increment the plugin element count
187-
aspecty.count ++
185+
elWidth = tag.offsetWidth || 0
188186

189-
// Create a new selector for our new CSS rule
190-
let newSelector = `${selector}[data-aspecty~="${aspecty.count}"]`
187+
// If the matching element has a non-zero width
188+
if (elWidth) {
191189

192-
// If element has no preexisting attribute, add event listeners
193-
if (!tag.getAttribute('data-aspecty')) {
190+
// Increment the plugin element count
191+
aspecty.count++
194192

195-
tag.addEventListener('mouseenter', aspecty.load)
196-
tag.addEventListener('mouseleave', aspecty.load)
197-
tag.addEventListener('mousedown', aspecty.load)
198-
tag.addEventListener('mouseup', aspecty.load)
199-
tag.addEventListener('focus', aspecty.load)
200-
tag.addEventListener('blur', aspecty.load)
193+
// Create a new selector for our new CSS rule
194+
let newSelector = `${partial}[data-aspecty~="${aspecty.count}"]`
201195

202-
}
196+
// If element has no preexisting attribute, add event listeners
197+
if (!tag.getAttribute('data-aspecty')) {
198+
199+
tag.addEventListener('mouseenter', aspecty.load)
200+
tag.addEventListener('mouseleave', aspecty.load)
201+
tag.addEventListener('mousedown', aspecty.load)
202+
tag.addEventListener('mouseup', aspecty.load)
203+
tag.addEventListener('focus', aspecty.load)
204+
tag.addEventListener('blur', aspecty.load)
205+
206+
}
203207

204-
// Mark matching element with attribute and plugin element count
205-
let currentAttr = tag.getAttribute('data-aspecty')
206-
tag.setAttribute('data-aspecty', `${currentAttr} ${aspecty.count}`)
208+
// Mark matching element with attribute and plugin element count
209+
let currentAttr = tag.getAttribute('data-aspecty')
210+
tag.setAttribute('data-aspecty', `${currentAttr} ${aspecty.count}`)
207211

208-
// Height for new rule from offsetWidth, divided by aspect ratio
209-
let newHeight = elWidth / (width/height)
212+
// Height for new rule from offsetWidth, divided by aspect ratio
213+
let newHeight = elWidth / (width/height)
210214

211-
// Create new `height` declaration with new value and !important text
212-
let newRuleText = `height: ${newHeight}px${specificity};`
215+
// Create new `height` declaration with new value and !important text
216+
let newRuleText = `height: ${newHeight}px${specificity};`
213217

214-
// And add our new rule to the rule list
215-
newRule += `\n/* ${selector} */\n${newSelector} {\n ${newRuleText}\n}\n`
218+
// And add our new rule to the rule list
219+
newRule += `\n/* ${selector} */\n${newSelector} {\n ${newRuleText}\n}\n`
220+
221+
}
216222

217-
}
223+
})
218224

219225
})
220226

‎cursory.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
/*
33
44
# Cursory
5-
## version 0.0.9
5+
## version 0.0.10
66
77
Cursory is a CSS reprocessor that makes the following JS values available as CSS variables:
88

‎scrollery.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
/*
33
44
# Scrollery
5-
## version 0.0.9
5+
## version 0.0.10
66
77
Scrollery is a CSS reprocessor that makes the following JS values available as CSS variables for any element you tell the plugin to watch:
88

‎selectory.js

+44-32
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
/*
33
44
# Selectory
5-
## version 0.0.9
5+
## version 0.0.10
66
77
Selectory is a CSS reprocessor that resolves selectors using JS. This plugin will read CSS selectors that end with a `[test]` attribute and use JavaScript to determine whether or not to apply that style to elements matching the other part of that selector. For example, the JS test `1 == 1` will always resolve to `true`, so a selector written for `div[test="1 == 1"] {}` will always apply to each `div` element.
88
@@ -141,57 +141,69 @@ License: MIT
141141
let ruleText = rule.cssText.replace(/.*\{(.*)\}/gi, '$1')
142142

143143
// Start a new list of matching selectors
144-
let selectorList = []
144+
let ruleList = []
145145

146-
// If `[test=` is present anywhere in the selector
147-
if (selector && selector.indexOf('[test=') !== -1) {
146+
let selectorList = selector.split(',')
148147

149-
// Extract the full selector name and test
150-
selector.replace(/^(.*)\[test=(".*"|'.*')\]/i, (string, selectorText, test) => {
148+
selectorList.map(partial => {
151149

152-
// Use asterisk (*) if selectorText is an empty string
153-
selectorText = selectorText === '' ? '*' : selectorText
150+
// If `[test=` is present anywhere in the selector
151+
if (partial && partial.indexOf('[test=') !== -1) {
154152

155-
// For each tag matching the selector (minus the test)
156-
Array.from(document.querySelectorAll(selectorText), (tag, i) => {
153+
// Extract the full selector name and test
154+
partial.replace(/^(.*)\[test=("(?:[^"]*)"|'(?:[^']*)')\].*/i, (string, selectorText, test) => {
157155

158-
// Create a new function with our test
159-
const func = new Function(`return (${test})`)
156+
test = test.replace(/'([^']*)'/m, '$1')
157+
test = test.replace(/"([^"]*)"/m, '$1')
160158

161-
// Run the test with our matching element
162-
if (func.call(tag)) {
159+
// Use asterisk if last character is a space, +, >, or ~
160+
selectorText = selectorText.replace(/[ \+\>\~]$/m, ' *')
163161

164-
// Increment the plugin element count
165-
selectory.count++
162+
// Use asterisk (*) if selectorText is an empty string
163+
selectorText = selectorText === '' ? '*' : selectorText
166164

167-
// Create a new selector for our new CSS rule
168-
let newSelector = selector.replace(/^(.*\[)(test=(?:".*"|'.*'))(\])/i, (string, before, test, after) => {
165+
// For each tag matching the selector (minus the test)
166+
Array.from(document.querySelectorAll(selectorText), (tag, i) => {
169167

170-
return `${before}data-selectory~="${selectory.count}"${after}`
168+
// Create a new function with our test
169+
const func = new Function(`return (${test})`)
171170

172-
})
171+
// Run the test with our matching element
172+
if (func.call(tag)) {
173173

174-
// Mark matching element with attribute and plugin element count
175-
let currentAttr = tag.getAttribute('data-selectory')
176-
tag.setAttribute('data-selectory', `${currentAttr} ${selectory.count}`)
174+
// Increment the plugin element count
175+
selectory.count++
177176

178-
// And add our new attribute to the selector list for that rule
179-
selectorList.push(newSelector)
177+
// Create a new selector for our new CSS rule
178+
let newSelector = partial.replace(/^(.*\[)(test=(?:".*"|'.*'))(\])/i, (string, before, test, after) => {
180179

181-
}
180+
return `${before}data-selectory~="${selectory.count}"${after}`
181+
182+
})
183+
184+
// Mark matching element with attribute and plugin element count
185+
let currentAttr = tag.getAttribute('data-selectory')
186+
tag.setAttribute('data-selectory', `${currentAttr} ${selectory.count}`)
187+
188+
// And add our new attribute to the selector list for that rule
189+
ruleList.push(newSelector)
190+
191+
}
192+
193+
})
182194

183195
})
184196

185-
})
197+
}
186198

187-
}
199+
// If at least one element passed the test
200+
if (ruleList.length > 0) {
188201

189-
// If at least one element passed the test
190-
if (selectorList.length > 0) {
202+
newRule = `\n/* ${selector} */\n${ruleList} {\n ${ruleText.replace(/(; )([^\{])/g,';\n $2')}\n}\n`
191203

192-
newRule = `\n/* ${selector} */\n${selectorList} {\n ${ruleText.replace(/(; )([^\{])/g,';\n $2')}\n}\n`
204+
}
193205

194-
}
206+
})
195207

196208
return newRule
197209

‎varsity.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
/*
33
44
# Varsity
5-
## version 0.0.9
5+
## version 0.0.10
66
77
Varsity is a CSS reprocessor that makes the following JS values available as CSS variables for any element you tell the plugin to watch:
88

‎xpathy.js

+54-49
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
/*
33
44
# XPathy
5-
## version 0.0.9
5+
## version 0.0.10
66
77
XPathy is a CSS reprocessor that resolves selectors using XPath. This plugin will read CSS selectors that end with a `[xpath]` attribute and use JavaScript and XPath to determine whether or not to apply that style to elements matching the other part of that selector. For example, the XPath selector `//div` will always resolve to `div`, so a selector written for `div [xpath="//div"] {}` will always apply to each `div div {}` element.
88
@@ -140,80 +140,85 @@ License: MIT
140140
let selector = rule.selectorText.replace(/(.*)\s{/gi, '$1')
141141
let ruleText = rule.cssText.replace(/.*\{(.*)\}/gi, '$1')
142142

143-
// Start a new list of matching selectors
144-
let selectorList = []
143+
// Start a new list of matching rules
144+
let ruleList = []
145145

146-
// If `[test=` is present anywhere in the selector
147-
if (selector && selector.indexOf('[xpath=') !== -1) {
146+
let selectorList = selector.split(',')
148147

149-
// Extract the full selector name and test
150-
selector.replace(/^(.*)\[xpath=(".*"|'.*')\]/i, (string, selectorText, xpath) => {
148+
selectorList.map(partial => {
151149

152-
// Create new array to hold nodes selected by XPath
153-
let list = new Array()
150+
// If `[test=` is present anywhere in the selector
151+
if (partial && partial.indexOf('[xpath=') !== -1) {
154152

155-
let trimmedPath = xpath.replace(/^["'](.*)["']$/gm, '$1')
156-
trimmedPath = trimmedPath.replace(/\\'/g, "'")
157-
trimmedPath = trimmedPath.replace(/\\"/g, '"')
153+
// Extract the full selector name and test
154+
partial.replace(/^(.*)\[xpath=("(?:[^"]*)"|'(?:[^']*)')\]/i, (string, selectorText, xpath) => {
158155

159-
// use document.evaluate() to query DOM with our XPath
160-
let nodes = document.evaluate(
161-
trimmedPath,
162-
document,
163-
null,
164-
XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
165-
null
166-
)
156+
xpath = xpath.replace(/'([^']*)'/m, '$1')
157+
xpath = xpath.replace(/"([^"]*)"/m, '$1')
167158

168-
// If at least one node matches our XPath
169-
if (nodes) {
159+
// Create new array to hold nodes selected by XPath
160+
let list = new Array()
170161

171-
for (let i=0; i<nodes.snapshotLength; i++) {
162+
// use document.evaluate() to query DOM with our XPath
163+
let nodes = document.evaluate(
164+
xpath,
165+
document,
166+
null,
167+
XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
168+
null
169+
)
172170

173-
// Add each element to our list
174-
list.push(nodes.snapshotItem(i))
171+
// If at least one node matches our XPath
172+
if (nodes) {
173+
174+
for (let i=0; i<nodes.snapshotLength; i++) {
175+
176+
// Add each element to our list
177+
list.push(nodes.snapshotItem(i))
178+
179+
}
175180

176181
}
177182

178-
}
183+
// If our list contains at least one node
184+
if (list.length > 0) {
179185

180-
// If our list contains at least one node
181-
if (list.length > 0) {
186+
// For each tag matching the selector
187+
Array.from(list, (tag, i) => {
182188

183-
// For each tag matching the selector
184-
Array.from(list, (tag, i) => {
189+
// Increment the plugin element count
190+
xpathy.count++
185191

186-
// Increment the plugin element count
187-
xpathy.count++
192+
// Create a new selector for our new CSS rule
193+
let newSelector = partial.replace(/^(.*\[)(xpath=(?:".*"|'.*'))(\])/i, (string, before, test, after) => {
188194

189-
// Create a new selector for our new CSS rule
190-
let newSelector = selector.replace(/^(.*\[)(xpath=(?:".*"|'.*'))(\])/i, (string, before, test, after) => {
195+
return `${before}data-xpathy~="${xpathy.count}"${after}`
191196

192-
return `${before}data-xpathy~="${xpathy.count}"${after}`
197+
})
193198

194-
})
199+
// Mark matching element with attribute and plugin element count
200+
let currentAttr = tag.getAttribute('data-xpathy')
201+
tag.setAttribute('data-xpathy', `${currentAttr} ${xpathy.count}`)
195202

196-
// Mark matching element with attribute and plugin element count
197-
let currentAttr = tag.getAttribute('data-xpathy')
198-
tag.setAttribute('data-xpathy', `${currentAttr} ${xpathy.count}`)
203+
// And add our new attribute to the selector list for that rule
204+
ruleList.push(newSelector)
199205

200-
// And add our new attribute to the selector list for that rule
201-
selectorList.push(newSelector)
206+
})
202207

203-
})
208+
}
204209

205-
}
210+
})
206211

207-
})
212+
}
208213

209-
}
214+
// If at least one element passed the test
215+
if (ruleList.length > 0) {
210216

211-
// If at least one element passed the test
212-
if (selectorList.length > 0) {
217+
newRule = `\n/* ${selector} */\n${ruleList} {\n ${ruleText.replace(/(; )([^\{])/g,';\n $2')}\n}\n`
213218

214-
newRule = `\n/* ${selector} */\n${selectorList} {\n ${ruleText.replace(/(; )([^\{])/g,';\n $2')}\n}\n`
219+
}
215220

216-
}
221+
})
217222

218223
return newRule
219224

0 commit comments

Comments
 (0)