pathgl
Version:
A webgl renderer for data visualization, motion graphics and explorable explanations.
63 lines (54 loc) • 3.4 kB
JavaScript
//regexes sourced from sizzle
function querySelectorAll(selector, r) {
return selector.replace(/^\s+|\s*([,\s\+\~>]|$)\s*/g, '$1').split(',')
.forEach(function (s) { query(s, this).forEach(push.bind(r = [])) }, this) || r
}
function query(selector, root) {
var symbols = selector.split(/[\s\>\+\~](?![\s\w\-\/\?\&\=\:\.\(\)\!,@#%<>\{\}\$\*\^'"]*\]|[\s\w\+\-]*\))/)
, dividedTokens = selector.match(/([\s\>\+\~])(?![\s\w\-\/\?\&\=\:\.\(\)\!,@#%<>\{\}\$\*\^'"]*\]|[\s\w\+\-]*\))/)
, last = chunk(symbols.pop()), right = [], left = [], item
byTagName.call(root, last[1] || '*').forEach(function (d) { if (item = checkRight.apply(d, last)) right.push(item) })
return symbols.length ? right.forEach(function (e) { if (leftCheck(e, symbols, dividedTokens)) left.push(e) }) || left : right
}
function leftCheck(doc, symbols, divided, cand) {
return cand = function recur(e, i, p) {
while (p = combinators[divided[i]](p, e))
if (checkRight.apply(p, chunk(symbols[i]))) {
if (i) if (cand = recur(p, i - 1, p)) return cand
else return p
}
}(doc, symbols.length - 1, doc)
}
function checkRight(_, tag, classId, attribute, attr, attrCmp, attrVal, _, pseudo, _, pseudoVal, m) {
return pseudo && pseudos[pseudo] && !pseudos[pseudo](this, pseudoVal)
|| tag && tag !== '*' && this.tag && this.tag.toLowerCase() !== tag
|| attribute && !checkAttr(attrCmp, this.attr[attr] || '', attrVal)
|| classId && (m = classId.match(/#([\w\-]+)/)) && m[1] !== this.attr.id
|| classId && (classId.match(/\.[\w\-]+/g) || []).some(matchClass.bind(this)) ? 0 : this
}
function checkAttr(cmp, actual, val) {
return actual.match(RegExp({ '=' : val
, '^=' : '^' + clean(val)
, '$=' : clean(val) + '$'
, '*=' : clean(val)
, '~=' : '(?:^|\\s+)' + clean(val) + '(?:\\s+|$)'
, '|=' : '^' + clean(val) + '(-|$)'
}[cmp] || 'adnan^'))
}
function chunk(query) { return query.match(chunker) }
function byId(id) { return querySelectorAll('[id="' + id + '"]')[0] }
function isNode(el) { return el && typeof el === 'object' }
function previous(n) { while (n = n.previousSibling()) if (n.top) return n }
function clean(s) { return s.replace(/([.*+?\^=!:${}()|\[\]\/\\])/, '\\$1') }
function matchClass(d) { return ! RegExp('(^|\\s+)' + d.slice(1) + '(\\s+|$)').test(this.attr.class) }
function byTagName(name) { return traverse(this, function (doc) { return name == '*' || doc.tagName == name }, []) }
function traverse(node, fn, val) {
return (node.__scene__ || node.children).forEach(function (node) { traverse(node, fn, val), fn(node) && val.push(node) }) || val }
var pseudos = {} //todo
var combinators = { ' ': function (d) { return d && d !== __scene__ && d.parent() }
, '>': function (d, maybe) { return d && d.parent() == maybe.parent() && d.parent() }
, '~': function (d) { return d && d.previousSibling() }
, '+': function (d, ct, p1, p2) { return ! d || ((p1 = previous(d)) && (p2 = previous(ct)) && p1 == p2 && p1) }
}
var chunker =
/^(\*|\w+)?(?:([\.\#]+[\w\-\.#]+)?)(\[([\w\-]+)(?:([\|\^\$\*\~]?\=)['"]?([ \w\-\/\?\&\=\:\.\(\)\!,@#%<>\{\}\$\*\^]+)["']?)?\])?(:([\w\-]+)(\(['"]?([^()]+)['"]?\))?)?/