您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Standalone CSS Selector Parser and Engine. An official MooTools project.
此脚本不应直接安装,它是供其他脚本使用的外部库。如果您需要使用该库,请在脚本元属性加入:// @require https://update.greasyfork.icu/scripts/371600/623833/Slick.js
/* --- name: Slick.Parser description: Standalone CSS3 Selector parser provides: Slick.Parser ... */ ;(function(){ var parsed, separatorIndex, combinatorIndex, reversed, cache = {}, reverseCache = {}, reUnescape = /\\/g; var parse = function(expression, isReversed){ if (expression == null) return null; if (expression.Slick === true) return expression; expression = ('' + expression).replace(/^\s+|\s+$/g, ''); reversed = !!isReversed; var currentCache = (reversed) ? reverseCache : cache; if (currentCache[expression]) return currentCache[expression]; parsed = { Slick: true, expressions: [], raw: expression, reverse: function(){ return parse(this.raw, true); } }; separatorIndex = -1; while (expression != (expression = expression.replace(regexp, parser))); parsed.length = parsed.expressions.length; return currentCache[parsed.raw] = (reversed) ? reverse(parsed) : parsed; }; var reverseCombinator = function(combinator){ if (combinator === '!') return ' '; else if (combinator === ' ') return '!'; else if ((/^!/).test(combinator)) return combinator.replace(/^!/, ''); else return '!' + combinator; }; var reverse = function(expression){ var expressions = expression.expressions; for (var i = 0; i < expressions.length; i++){ var exp = expressions[i]; var last = {parts: [], tag: '*', combinator: reverseCombinator(exp[0].combinator)}; for (var j = 0; j < exp.length; j++){ var cexp = exp[j]; if (!cexp.reverseCombinator) cexp.reverseCombinator = ' '; cexp.combinator = cexp.reverseCombinator; delete cexp.reverseCombinator; } exp.reverse().push(last); } return expression; }; var escapeRegExp = (function(){ // Credit: XRegExp 0.6.1 (c) 2007-2008 Steven Levithan <http://stevenlevithan.com/regex/xregexp/> MIT License var from = /(?=[\-\[\]{}()*+?.\\\^$|,#\s])/g, to = '\\'; return function(string){ return string.replace(from, to) } }()) var regexp = new RegExp( /* #!/usr/bin/env ruby puts "\t\t" + DATA.read.gsub(/\(\?x\)|\s+#.*$|\s+|\\$|\\n/,'') __END__ "(?x)^(?:\ \\s* ( , ) \\s* # Separator \n\ | \\s* ( <combinator>+ ) \\s* # Combinator \n\ | ( \\s+ ) # CombinatorChildren \n\ | ( <unicode>+ | \\* ) # Tag \n\ | \\# ( <unicode>+ ) # ID \n\ | \\. ( <unicode>+ ) # ClassName \n\ | # Attribute \n\ \\[ \ \\s* (<unicode1>+) (?: \ \\s* ([*^$!~|]?=) (?: \ \\s* (?:\ ([\"']?)(.*?)\\9 \ )\ ) \ )? \\s* \ \\](?!\\]) \n\ | :+ ( <unicode>+ )(?:\ \\( (?:\ (?:([\"'])([^\\12]*)\\12)|((?:\\([^)]+\\)|[^()]*)+)\ ) \\)\ )?\ )" */ "^(?:\\s*(,)\\s*|\\s*(<combinator>+)\\s*|(\\s+)|(<unicode>+|\\*)|\\#(<unicode>+)|\\.(<unicode>+)|\\[\\s*(<unicode1>+)(?:\\s*([*^$!~|]?=)(?:\\s*(?:([\"']?)(.*?)\\9)))?\\s*\\](?!\\])|(:+)(<unicode>+)(?:\\((?:(?:([\"'])([^\\13]*)\\13)|((?:\\([^)]+\\)|[^()]*)+))\\))?)" .replace(/<combinator>/, '[' + escapeRegExp(">+~`!@$%^&={}\\;</") + ']') .replace(/<unicode>/g, '(?:[\\w\\u00a1-\\uFFFF-]|\\\\[^\\s0-9a-f])') .replace(/<unicode1>/g, '(?:[:\\w\\u00a1-\\uFFFF-]|\\\\[^\\s0-9a-f])') ); function parser( rawMatch, separator, combinator, combinatorChildren, tagName, id, className, attributeKey, attributeOperator, attributeQuote, attributeValue, pseudoMarker, pseudoClass, pseudoQuote, pseudoClassQuotedValue, pseudoClassValue ){ if (separator || separatorIndex === -1){ parsed.expressions[++separatorIndex] = []; combinatorIndex = -1; if (separator) return ''; } if (combinator || combinatorChildren || combinatorIndex === -1){ combinator = combinator || ' '; var currentSeparator = parsed.expressions[separatorIndex]; if (reversed && currentSeparator[combinatorIndex]) currentSeparator[combinatorIndex].reverseCombinator = reverseCombinator(combinator); currentSeparator[++combinatorIndex] = {combinator: combinator, tag: '*'}; } var currentParsed = parsed.expressions[separatorIndex][combinatorIndex]; if (tagName){ currentParsed.tag = tagName.replace(reUnescape, ''); } else if (id){ currentParsed.id = id.replace(reUnescape, ''); } else if (className){ className = className.replace(reUnescape, ''); if (!currentParsed.classList) currentParsed.classList = []; if (!currentParsed.classes) currentParsed.classes = []; currentParsed.classList.push(className); currentParsed.classes.push({ value: className, regexp: new RegExp('(^|\\s)' + escapeRegExp(className) + '(\\s|$)') }); } else if (pseudoClass){ pseudoClassValue = pseudoClassValue || pseudoClassQuotedValue; pseudoClassValue = pseudoClassValue ? pseudoClassValue.replace(reUnescape, '') : null; if (!currentParsed.pseudos) currentParsed.pseudos = []; currentParsed.pseudos.push({ key: pseudoClass.replace(reUnescape, ''), value: pseudoClassValue, type: pseudoMarker.length == 1 ? 'class' : 'element' }); } else if (attributeKey){ attributeKey = attributeKey.replace(reUnescape, ''); attributeValue = (attributeValue || '').replace(reUnescape, ''); var test, regexp; switch (attributeOperator){ case '^=' : regexp = new RegExp( '^'+ escapeRegExp(attributeValue) ); break; case '$=' : regexp = new RegExp( escapeRegExp(attributeValue) +'$' ); break; case '~=' : regexp = new RegExp( '(^|\\s)'+ escapeRegExp(attributeValue) +'(\\s|$)' ); break; case '|=' : regexp = new RegExp( '^'+ escapeRegExp(attributeValue) +'(-|$)' ); break; case '=' : test = function(value){ return attributeValue == value; }; break; case '*=' : test = function(value){ return value && value.indexOf(attributeValue) > -1; }; break; case '!=' : test = function(value){ return attributeValue != value; }; break; default : test = function(value){ return !!value; }; } if (attributeValue == '' && (/^[*$^]=$/).test(attributeOperator)) test = function(){ return false; }; if (!test) test = function(value){ return value && regexp.test(value); }; if (!currentParsed.attributes) currentParsed.attributes = []; currentParsed.attributes.push({ key: attributeKey, operator: attributeOperator, value: attributeValue, test: test }); } return ''; }; // Slick NS var Slick = (this.Slick || {}); Slick.parse = function(expression){ return parse(expression); }; Slick.escapeRegExp = escapeRegExp; if (!this.Slick) this.Slick = Slick; }).apply(/*<CommonJS>*/(typeof exports != 'undefined') ? exports : /*</CommonJS>*/this); /* --- name: Slick.Finder description: The new, superfast css selector engine. provides: Slick.Finder requires: Slick.Parser ... */ ;(function(){ var local = {}, featuresCache = {}, toString = Object.prototype.toString; // Feature / Bug detection local.isNativeCode = function(fn){ return (/\{\s*\[native code\]\s*\}/).test('' + fn); }; local.isXML = function(document){ return (!!document.xmlVersion) || (!!document.xml) || (toString.call(document) == '[object XMLDocument]') || (document.nodeType == 9 && document.documentElement.nodeName != 'HTML'); }; local.setDocument = function(document){ // convert elements / window arguments to document. if document cannot be extrapolated, the function returns. var nodeType = document.nodeType; if (nodeType == 9); // document else if (nodeType) document = document.ownerDocument; // node else if (document.navigator) document = document.document; // window else return; // check if it's the old document if (this.document === document) return; this.document = document; // check if we have done feature detection on this document before var root = document.documentElement, rootUid = this.getUIDXML(root), features = featuresCache[rootUid], feature; if (features){ for (feature in features){ this[feature] = features[feature]; } return; } features = featuresCache[rootUid] = {}; features.root = root; features.isXMLDocument = this.isXML(document); features.brokenStarGEBTN = features.starSelectsClosedQSA = features.idGetsName = features.brokenMixedCaseQSA = features.brokenGEBCN = features.brokenCheckedQSA = features.brokenEmptyAttributeQSA = features.isHTMLDocument = features.nativeMatchesSelector = false; var starSelectsClosed, starSelectsComments, brokenSecondClassNameGEBCN, cachedGetElementsByClassName, brokenFormAttributeGetter; var selected, id = 'slick_uniqueid'; var testNode = document.createElement('div'); var testRoot = document.body || document.getElementsByTagName('body')[0] || root; testRoot.appendChild(testNode); // on non-HTML documents innerHTML and getElementsById doesnt work properly try { testNode.innerHTML = '<a id="'+id+'"></a>'; features.isHTMLDocument = !!document.getElementById(id); } catch(e){} if (features.isHTMLDocument){ testNode.style.display = 'none'; // IE returns comment nodes for getElementsByTagName('*') for some documents testNode.appendChild(document.createComment('')); starSelectsComments = (testNode.getElementsByTagName('*').length > 1); // IE returns closed nodes (EG:"</foo>") for getElementsByTagName('*') for some documents // Should never inject incorrect markup on XML documents if (!features.isXMLDocument){ try { testNode.innerHTML = 'foo</foo>'; selected = testNode.getElementsByTagName('*'); starSelectsClosed = (selected && !!selected.length && selected[0].nodeName.charAt(0) == '/'); } catch(e){} } features.brokenStarGEBTN = starSelectsComments || starSelectsClosed; // native matchesSelector function features.nativeMatchesSelector = root.matchesSelector || /*root.msMatchesSelector ||*/ root.mozMatchesSelector || root.webkitMatchesSelector; if (features.nativeMatchesSelector) try { // if matchesSelector trows errors on incorrect sintaxes we can use it features.nativeMatchesSelector.call(root, ':slick'); features.nativeMatchesSelector = null; } catch(e){} // IE returns elements with the name instead of just id for getElementsById for some documents try { testNode.innerHTML = '<a name="'+ id +'"></a><b id="'+ id +'"></b>'; features.idGetsName = document.getElementById(id) === testNode.firstChild; } catch(e){} if (testNode.getElementsByClassName){ // Safari 3.2 getElementsByClassName caches results try { testNode.innerHTML = '<a class="f"></a><a class="b"></a>'; testNode.getElementsByClassName('b').length; testNode.firstChild.className = 'b'; cachedGetElementsByClassName = (testNode.getElementsByClassName('b').length != 2); } catch(e){} // Opera 9.6 getElementsByClassName doesnt detects the class if its not the first one try { testNode.innerHTML = '<a class="a"></a><a class="f b a"></a>'; brokenSecondClassNameGEBCN = (testNode.getElementsByClassName('a').length != 2); } catch(e){} features.brokenGEBCN = cachedGetElementsByClassName || brokenSecondClassNameGEBCN; } if (testNode.querySelectorAll){ // IE 8 returns closed nodes (EG:"</foo>") for querySelectorAll('*') for some documents // Should never inject incorrect markup on XML documents if (!features.isXMLDocument){ try { testNode.innerHTML = 'foo</foo>'; selected = testNode.querySelectorAll('*'); features.starSelectsClosedQSA = (selected && !!selected.length && selected[0].nodeName.charAt(0) == '/'); } catch(e){} } // Safari 3.2 querySelectorAll doesnt work with mixedcase on quirksmode try { testNode.innerHTML = '<a class="MiX"></a>'; features.brokenMixedCaseQSA = !testNode.querySelectorAll('.MiX').length; } catch(e){} // Webkit and Opera dont return selected options on querySelectorAll try { testNode.innerHTML = '<select><option selected="selected">a</option></select>'; features.brokenCheckedQSA = (testNode.querySelectorAll(':checked').length == 0); } catch(e){} // IE returns incorrect results for attr[*^$]="" selectors on querySelectorAll try { testNode.innerHTML = '<a class=""></a>'; features.brokenEmptyAttributeQSA = (testNode.querySelectorAll('[class*=""]').length != 0); } catch(e){} } if (features.nativeMatchesSelector) { // Webkit does not match correctly with the :nth-child pseudo on elements inside the body // but if a style is applyed using this selector, the match starts working try { testNode.innerHTML = '_<style>:nth-child(2){}</style>'; } catch(e){} } // IE6-7, if a form has an input of id x, form.getAttribute(x) returns a reference to the input try { testNode.innerHTML = '<form action="s"><input id="action"/></form>'; brokenFormAttributeGetter = (testNode.firstChild.getAttribute('action') != 's'); } catch(e){} } try { root.slick_expando = 1; delete root.slick_expando; features.getUID = this.getUIDHTML; } catch(e) { features.getUID = this.getUIDXML; } testRoot.removeChild(testNode); testNode = selected = testRoot = null; // getAttribute features.getAttribute = (features.isHTMLDocument && brokenFormAttributeGetter) ? function(node, name){ var method = this.attributeGetters[name]; if (method) return method.call(node); var attributeNode = node.getAttributeNode(name); return (attributeNode) ? attributeNode.nodeValue : null; } : function(node, name){ var method = this.attributeGetters[name]; return (method) ? method.call(node) : node.getAttribute(name); }; // hasAttribute features.hasAttribute = (root && this.isNativeCode(root.hasAttribute)) ? function(node, attribute) { return node.hasAttribute(attribute); } : function(node, attribute) { node = node.getAttributeNode(attribute); return !!(node && (node.specified || node.nodeValue)); }; // contains // FIXME: Add specs: local.contains should be different for xml and html documents? var nativeRootContains = root && this.isNativeCode(root.contains), nativeDocumentContains = document && this.isNativeCode(document.contains); features.contains = (nativeRootContains && nativeDocumentContains) ? function(context, node){ return context.contains(node); } : (nativeRootContains && !nativeDocumentContains) ? function(context, node){ // IE8 does not have .contains on document. return context === node || ((context === document) ? document.documentElement : context).contains(node); } : (root && root.compareDocumentPosition) ? function(context, node){ return context === node || !!(context.compareDocumentPosition(node) & 16); } : function(context, node){ if (node) do { if (node === context) return true; } while ((node = node.parentNode)); return false; }; // document order sorting // credits to Sizzle (http://sizzlejs.com/) features.documentSorter = (root.compareDocumentPosition) ? function(a, b){ if (!a.compareDocumentPosition || !b.compareDocumentPosition) return 0; return a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1; } : ('sourceIndex' in root) ? function(a, b){ if (!a.sourceIndex || !b.sourceIndex) return 0; return a.sourceIndex - b.sourceIndex; } : (document.createRange) ? function(a, b){ if (!a.ownerDocument || !b.ownerDocument) return 0; var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange(); aRange.setStart(a, 0); aRange.setEnd(a, 0); bRange.setStart(b, 0); bRange.setEnd(b, 0); return aRange.compareBoundaryPoints(Range.START_TO_END, bRange); } : null ; root = null; for (feature in features){ this[feature] = features[feature]; } }; // Main Method var reSiblingContextSelector = /^\s*[+~]/, reSimpleSelector = /^([#.]?)((?:[\w-]+|\*))$/, reEmptyAttribute = /\[.+[*$^]=(?:""|'')?\]/, qsaFailExpCache = {}; local.search = function(context, expression, append, first){ var found = this.found = (first) ? null : (append || []); if (!context) return found; else if (context.navigator) context = context.document; // Convert the node from a window to a document else if (!context.nodeType) return found; // setup var parsed, i, uniques = this.uniques = {}, hasOthers = !!(append && append.length), contextIsDocument = (context.nodeType == 9); if (this.document !== (contextIsDocument ? context : context.ownerDocument)) this.setDocument(context); // avoid duplicating items already in the append array if (hasOthers) for (i = found.length; i--;) uniques[this.getUID(found[i])] = true; // expression checks if (typeof expression == 'string'){ // expression is a string /*<simple-selectors-override>*/ var simpleSelector = expression.match(reSimpleSelector); simpleSelectors: if (simpleSelector) { var symbol = simpleSelector[1], name = simpleSelector[2], node, nodes; if (!symbol){ if (name == '*' && this.brokenStarGEBTN) break simpleSelectors; nodes = context.getElementsByTagName(name); if (first) return nodes[0] || null; for (i = 0; node = nodes[i++];){ if (!(hasOthers && uniques[this.getUID(node)])) found.push(node); } } else if (symbol == '#'){ if (!this.isHTMLDocument || !contextIsDocument) break simpleSelectors; node = context.getElementById(name); if (!node) return found; if (this.idGetsName && this.getAttribute(node, 'id') != name) break simpleSelectors; if (first) return node || null; if (!(hasOthers && uniques[this.getUID(node)])) found.push(node); } else if (symbol == '.'){ if (!this.isHTMLDocument || ((!context.getElementsByClassName || this.brokenGEBCN) && context.querySelectorAll)) break simpleSelectors; if (context.getElementsByClassName && !this.brokenGEBCN){ nodes = context.getElementsByClassName(name); if (first) return nodes[0] || null; for (i = 0; node = nodes[i++];){ if (!(hasOthers && uniques[this.getUID(node)])) found.push(node); } } else { var matchClass = new RegExp('(^|\\s)'+ Slick.escapeRegExp(name) +'(\\s|$)'); nodes = context.getElementsByTagName('*'); for (i = 0; node = nodes[i++];){ className = node.className; if (!(className && matchClass.test(className))) continue; if (first) return node; if (!(hasOthers && uniques[this.getUID(node)])) found.push(node); } } } if (hasOthers) this.sort(found); return (first) ? null : found; } /*</simple-selectors-override>*/ /*<query-selector-override>*/ querySelector: if (context.querySelectorAll) { if (!this.isHTMLDocument || qsaFailExpCache[expression] //TODO: only skip when expression is actually mixed case || this.brokenMixedCaseQSA || (this.brokenCheckedQSA && expression.indexOf(':checked') > -1) || (this.brokenEmptyAttributeQSA && reEmptyAttribute.test(expression)) || (!contextIsDocument //Abort when !contextIsDocument and... // there are multiple expressions in the selector // since we currently only fix non-document rooted QSA for single expression selectors && expression.indexOf(',') > -1 ) || Slick.disableQSA ) break querySelector; var _expression = expression, _context = context; if (!contextIsDocument){ if (reSiblingContextSelector.test(_expression)) { context = _context.parentNode; } // non-document rooted QSA // credits to Andrew Dupont var currentId = _context.getAttribute('id'), slickid = 'slickid__'; _context.setAttribute('id', slickid); _expression = '#' + slickid + ' ' + _expression; } try { if (first) return context.querySelector(_expression) || null; else nodes = context.querySelectorAll(_expression); } catch(e) { qsaFailExpCache[expression] = 1; break querySelector; } finally { if (!contextIsDocument){ if (currentId) _context.setAttribute('id', currentId); else _context.removeAttribute('id'); context = _context; } } if (this.starSelectsClosedQSA) for (i = 0; node = nodes[i++];){ if (node.nodeName > '@' && !(hasOthers && uniques[this.getUID(node)])) found.push(node); } else for (i = 0; node = nodes[i++];){ if (!(hasOthers && uniques[this.getUID(node)])) found.push(node); } if (hasOthers) this.sort(found); return found; } /*</query-selector-override>*/ parsed = this.Slick.parse(expression); if (!parsed.length) return found; } else if (expression == null){ // there is no expression return found; } else if (expression.Slick){ // expression is a parsed Slick object parsed = expression; } else if (this.contains(context.documentElement || context, expression)){ // expression is a node (found) ? found.push(expression) : found = expression; return found; } else { // other junk return found; } /*<pseudo-selectors>*//*<nth-pseudo-selectors>*/ // cache elements for the nth selectors this.posNTH = {}; this.posNTHLast = {}; this.posNTHType = {}; this.posNTHTypeLast = {}; /*</nth-pseudo-selectors>*//*</pseudo-selectors>*/ // if append is null and there is only a single selector with one expression use pushArray, else use pushUID this.push = (!hasOthers && (first || (parsed.length == 1 && parsed.expressions[0].length == 1))) ? this.pushArray : this.pushUID; if (found == null) found = []; // default engine var j, m, n, combinator, tag, id, classList, classes, attributes, pseudos, currentItems, currentExpression, currentBit, lastBit, expressions = parsed.expressions; search: for (i = 0; (currentExpression = expressions[i]); i++) for (j = 0; (currentBit = currentExpression[j]); j++){ combinator = 'combinator:' + currentBit.combinator; if (!this[combinator]) continue search; tag = (this.isXMLDocument) ? currentBit.tag : currentBit.tag.toUpperCase(); id = currentBit.id; classList = currentBit.classList; classes = currentBit.classes; attributes = currentBit.attributes; pseudos = currentBit.pseudos; lastBit = (j === (currentExpression.length - 1)); this.bitUniques = {}; if (lastBit){ this.uniques = uniques; this.found = found; } else { this.uniques = {}; this.found = []; } if (j === 0){ this[combinator](context, tag, id, classes, attributes, pseudos, classList); if (first && lastBit && found.length) break search; } else { if (first && lastBit) for (m = 0, n = currentItems.length; m < n; m++){ this[combinator](currentItems[m], tag, id, classes, attributes, pseudos, classList); if (found.length) break search; } else for (m = 0, n = currentItems.length; m < n; m++) this[combinator](currentItems[m], tag, id, classes, attributes, pseudos, classList); } currentItems = this.found; } // should sort if there are nodes in append and if you pass multiple expressions. if (hasOthers || (parsed.expressions.length > 1)) this.sort(found); return (first) ? (found[0] || null) : found; }; // Utils local.uidx = 1; local.uidk = 'slick-uniqueid'; local.getUIDXML = function(node){ var uid = node.getAttribute(this.uidk); if (!uid){ uid = this.uidx++; node.setAttribute(this.uidk, uid); } return uid; }; local.getUIDHTML = function(node){ return node.uniqueNumber || (node.uniqueNumber = this.uidx++); }; // sort based on the setDocument documentSorter method. local.sort = function(results){ if (!this.documentSorter) return results; results.sort(this.documentSorter); return results; }; /*<pseudo-selectors>*//*<nth-pseudo-selectors>*/ local.cacheNTH = {}; local.matchNTH = /^([+-]?\d*)?([a-z]+)?([+-]\d+)?$/; local.parseNTHArgument = function(argument){ var parsed = argument.match(this.matchNTH); if (!parsed) return false; var special = parsed[2] || false; var a = parsed[1] || 1; if (a == '-') a = -1; var b = +parsed[3] || 0; parsed = (special == 'n') ? {a: a, b: b} : (special == 'odd') ? {a: 2, b: 1} : (special == 'even') ? {a: 2, b: 0} : {a: 0, b: a}; return (this.cacheNTH[argument] = parsed); }; local.createNTHPseudo = function(child, sibling, positions, ofType){ return function(node, argument){ var uid = this.getUID(node); if (!this[positions][uid]){ var parent = node.parentNode; if (!parent) return false; var el = parent[child], count = 1; if (ofType){ var nodeName = node.nodeName; do { if (el.nodeName != nodeName) continue; this[positions][this.getUID(el)] = count++; } while ((el = el[sibling])); } else { do { if (el.nodeType != 1) continue; this[positions][this.getUID(el)] = count++; } while ((el = el[sibling])); } } argument = argument || 'n'; var parsed = this.cacheNTH[argument] || this.parseNTHArgument(argument); if (!parsed) return false; var a = parsed.a, b = parsed.b, pos = this[positions][uid]; if (a == 0) return b == pos; if (a > 0){ if (pos < b) return false; } else { if (b < pos) return false; } return ((pos - b) % a) == 0; }; }; /*</nth-pseudo-selectors>*//*</pseudo-selectors>*/ local.pushArray = function(node, tag, id, classes, attributes, pseudos){ if (this.matchSelector(node, tag, id, classes, attributes, pseudos)) this.found.push(node); }; local.pushUID = function(node, tag, id, classes, attributes, pseudos){ var uid = this.getUID(node); if (!this.uniques[uid] && this.matchSelector(node, tag, id, classes, attributes, pseudos)){ this.uniques[uid] = true; this.found.push(node); } }; local.matchNode = function(node, selector){ if (this.isHTMLDocument && this.nativeMatchesSelector){ try { return this.nativeMatchesSelector.call(node, selector.replace(/\[([^=]+)=\s*([^'"\]]+?)\s*\]/g, '[$1="$2"]')); } catch(matchError) {} } var parsed = this.Slick.parse(selector); if (!parsed) return true; // simple (single) selectors var expressions = parsed.expressions, simpleExpCounter = 0, i; for (i = 0; (currentExpression = expressions[i]); i++){ if (currentExpression.length == 1){ var exp = currentExpression[0]; if (this.matchSelector(node, (this.isXMLDocument) ? exp.tag : exp.tag.toUpperCase(), exp.id, exp.classes, exp.attributes, exp.pseudos)) return true; simpleExpCounter++; } } if (simpleExpCounter == parsed.length) return false; var nodes = this.search(this.document, parsed), item; for (i = 0; item = nodes[i++];){ if (item === node) return true; } return false; }; local.matchPseudo = function(node, name, argument){ var pseudoName = 'pseudo:' + name; if (this[pseudoName]) { // saves a this.found reference so if the pseudo-selector // uses Slick it wont mess with the current reference var found = this.found, result = this[pseudoName](node, argument); this.found = found; return result; } var attribute = this.getAttribute(node, name); return (argument) ? argument == attribute : !!attribute; }; local.matchSelector = function(node, tag, id, classes, attributes, pseudos){ if (tag){ var nodeName = (this.isXMLDocument) ? node.nodeName : node.nodeName.toUpperCase(); if (tag == '*'){ if (nodeName < '@') return false; // Fix for comment nodes and closed nodes } else { if (nodeName != tag) return false; } } if (id && node.getAttribute('id') != id) return false; var i, part, cls; if (classes) for (i = classes.length; i--;){ cls = this.getAttribute(node, 'class'); if (!(cls && classes[i].regexp.test(cls))) return false; } if (attributes) for (i = attributes.length; i--;){ part = attributes[i]; if (part.operator ? !part.test(this.getAttribute(node, part.key)) : !this.hasAttribute(node, part.key)) return false; } if (pseudos) for (i = pseudos.length; i--;){ part = pseudos[i]; if (!this.matchPseudo(node, part.key, part.value)) return false; } return true; }; var combinators = { ' ': function(node, tag, id, classes, attributes, pseudos, classList){ // all child nodes, any level var i, item, children; if (this.isHTMLDocument){ getById: if (id){ item = this.document.getElementById(id); if ((!item && node.all) || (this.idGetsName && item && this.getAttribute(item, 'id') != id)){ // all[id] returns all the elements with that name or id inside node // if theres just one it will return the element, else it will be a collection children = node.all[id]; if (!children) return; if (!children[0]) children = [children]; for (i = 0; item = children[i++];){ if (this.getAttribute(item, 'id') == id){ this.push(item, tag, null, classes, attributes, pseudos); break; } } return; } if (!item){ // if the context is in the dom we return, else we will try GEBTN, breaking the getById label if (this.contains(this.root, node)) return; else break getById; } else if (this.document !== node && !this.contains(node, item)) return; this.push(item, tag, null, classes, attributes, pseudos); return; } getByClass: if (classes && node.getElementsByClassName && !this.brokenGEBCN){ children = node.getElementsByClassName(classList.join(' ')); if (!(children && children.length)) break getByClass; for (i = 0; item = children[i++];) this.push(item, tag, id, null, attributes, pseudos); return; } } getByTag: { children = node.getElementsByTagName(tag); if (!(children && children.length)) break getByTag; if (!this.brokenStarGEBTN) tag = null; for (i = 0; item = children[i++];) this.push(item, tag, id, classes, attributes, pseudos); } }, '>': function(node, tag, id, classes, attributes, pseudos){ // direct children if ((node = node.firstChild)) do { if (node.nodeType == 1) this.push(node, tag, id, classes, attributes, pseudos); } while ((node = node.nextSibling)); }, '+': function(node, tag, id, classes, attributes, pseudos){ // next sibling while ((node = node.nextSibling)) if (node.nodeType == 1){ this.push(node, tag, id, classes, attributes, pseudos); break; } }, '^': function(node, tag, id, classes, attributes, pseudos){ // first child node = node.firstChild; if (node){ if (node.nodeType == 1) this.push(node, tag, id, classes, attributes, pseudos); else this['combinator:+'](node, tag, id, classes, attributes, pseudos); } }, '~': function(node, tag, id, classes, attributes, pseudos){ // next siblings while ((node = node.nextSibling)){ if (node.nodeType != 1) continue; var uid = this.getUID(node); if (this.bitUniques[uid]) break; this.bitUniques[uid] = true; this.push(node, tag, id, classes, attributes, pseudos); } }, '++': function(node, tag, id, classes, attributes, pseudos){ // next sibling and previous sibling this['combinator:+'](node, tag, id, classes, attributes, pseudos); this['combinator:!+'](node, tag, id, classes, attributes, pseudos); }, '~~': function(node, tag, id, classes, attributes, pseudos){ // next siblings and previous siblings this['combinator:~'](node, tag, id, classes, attributes, pseudos); this['combinator:!~'](node, tag, id, classes, attributes, pseudos); }, '!': function(node, tag, id, classes, attributes, pseudos){ // all parent nodes up to document while ((node = node.parentNode)) if (node !== this.document) this.push(node, tag, id, classes, attributes, pseudos); }, '!>': function(node, tag, id, classes, attributes, pseudos){ // direct parent (one level) node = node.parentNode; if (node !== this.document) this.push(node, tag, id, classes, attributes, pseudos); }, '!+': function(node, tag, id, classes, attributes, pseudos){ // previous sibling while ((node = node.previousSibling)) if (node.nodeType == 1){ this.push(node, tag, id, classes, attributes, pseudos); break; } }, '!^': function(node, tag, id, classes, attributes, pseudos){ // last child node = node.lastChild; if (node){ if (node.nodeType == 1) this.push(node, tag, id, classes, attributes, pseudos); else this['combinator:!+'](node, tag, id, classes, attributes, pseudos); } }, '!~': function(node, tag, id, classes, attributes, pseudos){ // previous siblings while ((node = node.previousSibling)){ if (node.nodeType != 1) continue; var uid = this.getUID(node); if (this.bitUniques[uid]) break; this.bitUniques[uid] = true; this.push(node, tag, id, classes, attributes, pseudos); } } }; for (var c in combinators) local['combinator:' + c] = combinators[c]; var pseudos = { /*<pseudo-selectors>*/ 'empty': function(node){ var child = node.firstChild; return !(child && child.nodeType == 1) && !(node.innerText || node.textContent || '').length; }, 'not': function(node, expression){ return !this.matchNode(node, expression); }, 'contains': function(node, text){ return (node.innerText || node.textContent || '').indexOf(text) > -1; }, 'first-child': function(node){ while ((node = node.previousSibling)) if (node.nodeType == 1) return false; return true; }, 'last-child': function(node){ while ((node = node.nextSibling)) if (node.nodeType == 1) return false; return true; }, 'only-child': function(node){ var prev = node; while ((prev = prev.previousSibling)) if (prev.nodeType == 1) return false; var next = node; while ((next = next.nextSibling)) if (next.nodeType == 1) return false; return true; }, /*<nth-pseudo-selectors>*/ 'nth-child': local.createNTHPseudo('firstChild', 'nextSibling', 'posNTH'), 'nth-last-child': local.createNTHPseudo('lastChild', 'previousSibling', 'posNTHLast'), 'nth-of-type': local.createNTHPseudo('firstChild', 'nextSibling', 'posNTHType', true), 'nth-last-of-type': local.createNTHPseudo('lastChild', 'previousSibling', 'posNTHTypeLast', true), 'index': function(node, index){ return this['pseudo:nth-child'](node, '' + ((+index) + 1)); }, 'even': function(node){ return this['pseudo:nth-child'](node, '2n'); }, 'odd': function(node){ return this['pseudo:nth-child'](node, '2n+1'); }, /*</nth-pseudo-selectors>*/ /*<of-type-pseudo-selectors>*/ 'first-of-type': function(node){ var nodeName = node.nodeName; while ((node = node.previousSibling)) if (node.nodeName == nodeName) return false; return true; }, 'last-of-type': function(node){ var nodeName = node.nodeName; while ((node = node.nextSibling)) if (node.nodeName == nodeName) return false; return true; }, 'only-of-type': function(node){ var prev = node, nodeName = node.nodeName; while ((prev = prev.previousSibling)) if (prev.nodeName == nodeName) return false; var next = node; while ((next = next.nextSibling)) if (next.nodeName == nodeName) return false; return true; }, /*</of-type-pseudo-selectors>*/ // custom pseudos 'enabled': function(node){ return !node.disabled; }, 'disabled': function(node){ return node.disabled; }, 'checked': function(node){ return node.checked || node.selected; }, 'focus': function(node){ return this.isHTMLDocument && this.document.activeElement === node && (node.href || node.type || this.hasAttribute(node, 'tabindex')); }, 'root': function(node){ return (node === this.root); }, 'selected': function(node){ return node.selected; } /*</pseudo-selectors>*/ }; for (var p in pseudos) local['pseudo:' + p] = pseudos[p]; // attributes methods var attributeGetters = local.attributeGetters = { 'for': function(){ return ('htmlFor' in this) ? this.htmlFor : this.getAttribute('for'); }, 'href': function(){ return ('href' in this) ? this.getAttribute('href', 2) : this.getAttribute('href'); }, 'style': function(){ return (this.style) ? this.style.cssText : this.getAttribute('style'); }, 'type': function(){ return this.getAttribute('type'); }, 'tabindex': function(){ var attributeNode = this.getAttributeNode('tabindex'); return (attributeNode && attributeNode.specified) ? attributeNode.nodeValue : null; }, 'maxlength': function(){ var attributeNode = this.getAttributeNode('maxLength'); return (attributeNode && attributeNode.specified) ? attributeNode.nodeValue : null; } }; attributeGetters.MAXLENGTH = attributeGetters.maxLength = attributeGetters.maxlength; // Slick var Slick = local.Slick = (this.Slick || {}); Slick.version = '1.1.7'; // Slick finder Slick.search = function(context, expression, append){ return local.search(context, expression, append); }; Slick.find = function(context, expression){ return local.search(context, expression, null, true); }; // Slick containment checker Slick.contains = function(container, node){ local.setDocument(container); return local.contains(container, node); }; // Slick attribute getter Slick.getAttribute = function(node, name){ local.setDocument(node); return local.getAttribute(node, name); }; Slick.hasAttribute = function(node, name){ local.setDocument(node); return local.hasAttribute(node, name); }; // Slick matcher Slick.match = function(node, selector){ if (!(node && selector)) return false; if (!selector || selector === node) return true; local.setDocument(node); return local.matchNode(node, selector); }; // Slick attribute accessor Slick.defineAttributeGetter = function(name, fn){ local.attributeGetters[name] = fn; return this; }; Slick.lookupAttributeGetter = function(name){ return local.attributeGetters[name]; }; // Slick pseudo accessor Slick.definePseudo = function(name, fn){ local['pseudo:' + name] = function(node, argument){ return fn.call(node, argument); }; return this; }; Slick.lookupPseudo = function(name){ var pseudo = local['pseudo:' + name]; if (pseudo) return function(argument){ return pseudo.call(this, argument); }; return null; }; // Slick overrides accessor Slick.override = function(regexp, fn){ local.override(regexp, fn); return this; }; Slick.isXML = local.isXML; Slick.uidOf = function(node){ return local.getUIDHTML(node); }; if (!this.Slick) this.Slick = Slick; }).apply(/*<CommonJS>*/(typeof exports != 'undefined') ? exports : /*</CommonJS>*/this);