react / wstein / node_modules / jest-cli / node_modules / jsdom / node_modules / nwmatcher / src / nwmatcher.js
81141 views/*1* Copyright (C) 2007-2015 Diego Perini2* All rights reserved.3*4* nwmatcher.js - A fast CSS selector engine and matcher5*6* Author: Diego Perini <diego.perini at gmail com>7* Version: 1.3.48* Created: 200707229* Release: 2015010110*11* License:12* http://javascript.nwbox.com/NWMatcher/MIT-LICENSE13* Download:14* http://javascript.nwbox.com/NWMatcher/nwmatcher.js15*/1617(function(global, factory) {1819if (typeof module == 'object' && typeof exports == 'object') {20// in a Node.js environment, the nwmatcher functions will operate on21// the passed "browserGlobal" and will be returned in an object22module.exports = function (browserGlobal) {23// passed global does not contain24// references to native objects25browserGlobal.console = console;26browserGlobal.parseInt = parseInt;27browserGlobal.Function = Function;28browserGlobal.Boolean = Boolean;29browserGlobal.Number = Number;30browserGlobal.RegExp = RegExp;31browserGlobal.String = String;32browserGlobal.Object = Object;33browserGlobal.Array = Array;34browserGlobal.Error = Error;35browserGlobal.Date = Date;36browserGlobal.Math = Math;37var exports = browserGlobal.Object();38factory(browserGlobal, exports);39return exports;40};41module.factory = factory;42} else {43// in a browser environment, the nwmatcher functions will operate on44// the "global" loading them and be attached to "global.NW.Dom"45factory(global,46(global.NW || (global.NW = global.Object())) &&47(global.NW.Dom || (global.NW.Dom = global.Object())));48global.NW.Dom.factory = factory;49}5051})(this, function(global, exports) {5253var version = 'nwmatcher-1.3.4',5455Dom = exports,5657// processing context & root element58doc = global.document,59root = doc.documentElement,6061// save utility methods references62slice = global.Array.prototype.slice,63string = global.Object.prototype.toString,6465// persist previous parsed data66isSingleMatch,67isSingleSelect,6869lastSlice,70lastContext,71lastPosition,7273lastMatcher,74lastSelector,7576lastPartsMatch,77lastPartsSelect,7879// accepted prefix identifiers80// (id, class & pseudo-class)81prefixes = '[#.:]?',8283// accepted attribute operators84operators = '([~*^$|!]?={1})',8586// accepted whitespace characters87whitespace = '[\\x20\\t\\n\\r\\f]*',8889// 4 combinators F E, F>E, F+E, F~E90combinators = '[\\x20]|[>+~][^>+~]',9192// an+b format params for pseudo-classes93pseudoparms = '(?:[-+]?\\d*n)?[-+]?\\d*',9495// CSS quoted string values96quotedvalue = '"[^"\\\\]*(?:\\\\.[^"\\\\]*)*"' + "|'[^'\\\\]*(?:\\\\.[^'\\\\]*)*'",9798// skip round brackets groups99skipround = '\\([^()]+\\)|\\(.*\\)',100// skip curly brackets groups101skipcurly = '\\{[^{}]+\\}|\\{.*\\}',102// skip square brackets groups103skipsquare = '\\[[^[\\]]*\\]|\\[.*\\]',104105// skip [ ], ( ), { } brackets groups106skipgroup = '\\[.*\\]|\\(.*\\)|\\{.*\\}',107108// http://www.w3.org/TR/css3-syntax/#characters109// unicode/ISO 10646 characters 161 and higher110// NOTE: Safari 2.0.x crashes with escaped (\\)111// Unicode ranges in regular expressions so we112// use a negated character range class instead113encoding = '(?:[-\\w]|[^\\x00-\\xa0]|\\\\.)',114115// CSS identifier syntax116identifier = '(?:-?[_a-zA-Z]{1}[-\\w]*|[^\\x00-\\xa0]+|\\\\.+)+',117118// build attribute string119attrcheck = '(' + quotedvalue + '|' + identifier + ')',120attributes = whitespace + '(' + encoding + '*:?' + encoding + '+)' +121whitespace + '(?:' + operators + whitespace + attrcheck + ')?' + whitespace,122attrmatcher = attributes.replace(attrcheck, '([\\x22\\x27]*)((?:\\\\?.)*?)\\3'),123124// build pseudoclass string125pseudoclass = '((?:' +126// an+b parameters or quoted string127pseudoparms + '|' + quotedvalue + '|' +128// id, class, pseudo-class selector129prefixes + '|' + encoding + '+|' +130// nested HTML attribute selector131'\\[' + attributes + '\\]|' +132// nested pseudo-class selector133'\\(.+\\)|' + whitespace + '|' +134// nested pseudos/separators135',)+)',136137// placeholder for extensions138extensions = '.+',139140// CSS3: syntax scanner and141// one pass validation only142// using regular expression143standardValidator =144// discard start145'(?=[\\x20\\t\\n\\r\\f]*[^>+~(){}<>])' +146// open match group147'(' +148//universal selector149'\\*' +150// id/class/tag/pseudo-class identifier151'|(?:' + prefixes + identifier + ')' +152// combinator selector153'|' + combinators +154// HTML attribute selector155'|\\[' + attributes + '\\]' +156// pseudo-classes parameters157'|\\(' + pseudoclass + '\\)' +158// dom properties selector (extension)159'|\\{' + extensions + '\\}' +160// selector group separator (comma)161'|(?:,|' + whitespace + ')' +162// close match group163')+',164165// validator for complex selectors in ':not()' pseudo-classes166extendedValidator = standardValidator.replace(pseudoclass, '.*'),167168// validator for standard selectors as default169reValidator = new global.RegExp(standardValidator, 'g'),170171// whitespace is any combination of these 5 character [\x20\t\n\r\f]172// http://www.w3.org/TR/css3-selectors/#selector-syntax173reTrimSpaces = new global.RegExp('^' +174whitespace + '|' + whitespace + '$', 'g'),175176// only allow simple selectors nested in ':not()' pseudo-classes177reSimpleNot = new global.RegExp('^(' +178'(?!:not)' +179'(' + prefixes +180'|' + identifier +181'|\\([^()]*\\))+' +182'|\\[' + attributes + '\\]' +183')$'),184185// split comma groups, exclude commas from186// quotes '' "" and from brackets () [] {}187reSplitGroup = new global.RegExp('(' +188'[^,\\\\()[\\]]+' +189'|' + skipsquare +190'|' + skipround +191'|' + skipcurly +192'|\\\\.' +193')+', 'g'),194195// split last, right most, selector group token196reSplitToken = new global.RegExp('(' +197'\\[' + attributes + '\\]|' +198'\\(' + pseudoclass + '\\)|' +199'\\\\.|[^\\x20\\t\\r\\n\\f>+~])+', 'g'),200201// for in excess whitespace removal202reWhiteSpace = /[\x20\t\n\r\f]+/g,203204reOptimizeSelector = new global.RegExp(identifier + '|^$'),205206/*----------------------------- FEATURE TESTING ----------------------------*/207208// detect native methods209isNative = (function() {210var re = / \w+\(/,211isnative = String(Object.prototype.toString).replace(re, ' (');212return function(method) {213return method && typeof method != 'string' &&214isnative == String(method).replace(re, ' (');215};216})(),217218// NATIVE_XXXXX true if method exist and is callable219// detect if DOM methods are native in browsers220NATIVE_FOCUS = isNative(doc.hasFocus),221NATIVE_QSAPI = isNative(doc.querySelector),222NATIVE_GEBID = isNative(doc.getElementById),223NATIVE_GEBTN = isNative(root.getElementsByTagName),224NATIVE_GEBCN = isNative(root.getElementsByClassName),225226// detect native getAttribute/hasAttribute methods,227// frameworks extend these to elements, but it seems228// this does not work for XML namespaced attributes,229// used to check both getAttribute/hasAttribute in IE230NATIVE_GET_ATTRIBUTE = isNative(root.getAttribute),231NATIVE_HAS_ATTRIBUTE = isNative(root.hasAttribute),232233// check if slice() can convert nodelist to array234// see http://yura.thinkweb2.com/cft/235NATIVE_SLICE_PROTO =236(function() {237var isBuggy = false;238try {239isBuggy = !!slice.call(doc.childNodes, 0)[0];240} catch(e) { }241return isBuggy;242})(),243244// supports the new traversal API245NATIVE_TRAVERSAL_API =246'nextElementSibling' in root && 'previousElementSibling' in root,247248// BUGGY_XXXXX true if method is feature tested and has known bugs249// detect buggy gEBID250BUGGY_GEBID = NATIVE_GEBID ?251(function() {252var isBuggy = true, x = 'x' + global.String(+new global.Date),253a = doc.createElementNS ? 'a' : '<a name="' + x + '">';254(a = doc.createElement(a)).name = x;255root.insertBefore(a, root.firstChild);256isBuggy = !!doc.getElementById(x);257root.removeChild(a);258return isBuggy;259})() :260true,261262// detect IE gEBTN comment nodes bug263BUGGY_GEBTN = NATIVE_GEBTN ?264(function() {265var div = doc.createElement('div');266div.appendChild(doc.createComment(''));267return !!div.getElementsByTagName('*')[0];268})() :269true,270271// detect Opera gEBCN second class and/or UTF8 bugs as well as Safari 3.2272// caching class name results and not detecting when changed,273// tests are based on the jQuery selector test suite274BUGGY_GEBCN = NATIVE_GEBCN ?275(function() {276var isBuggy, div = doc.createElement('div'), test = '\u53f0\u5317';277278// Opera tests279div.appendChild(doc.createElement('span')).280setAttribute('class', test + 'abc ' + test);281div.appendChild(doc.createElement('span')).282setAttribute('class', 'x');283284isBuggy = !div.getElementsByClassName(test)[0];285286// Safari test287div.lastChild.className = test;288return isBuggy || div.getElementsByClassName(test).length != 2;289})() :290true,291292// detect IE bug with dynamic attributes293BUGGY_GET_ATTRIBUTE = NATIVE_GET_ATTRIBUTE ?294(function() {295var input = doc.createElement('input');296input.setAttribute('value', 5);297return input.defaultValue != 5;298})() :299true,300301// detect IE bug with non-standard boolean attributes302BUGGY_HAS_ATTRIBUTE = NATIVE_HAS_ATTRIBUTE ?303(function() {304var option = doc.createElement('option');305option.setAttribute('selected', 'selected');306return !option.hasAttribute('selected');307})() :308true,309310// detect Safari bug with selected option elements311BUGGY_SELECTED =312(function() {313var select = doc.createElement('select');314select.appendChild(doc.createElement('option'));315return !select.firstChild.selected;316})(),317318// initialized with the loading context319// and reset for each different context320BUGGY_QUIRKS_GEBCN,321BUGGY_QUIRKS_QSAPI,322323QUIRKS_MODE,324XML_DOCUMENT,325326// detect Opera browser327OPERA = /opera/i.test(string.call(global.opera)),328329// skip simple selector optimizations for Opera >= 11330OPERA_QSAPI = OPERA && global.parseFloat(global.opera.version()) >= 11,331332// check Selector API implementations333RE_BUGGY_QSAPI = NATIVE_QSAPI ?334(function() {335var pattern = new global.Array(), context, element,336337expect = function(selector, element, n) {338var result = false;339context.appendChild(element);340try { result = context.querySelectorAll(selector).length == n; } catch(e) { }341while (context.firstChild) { context.removeChild(context.firstChild); }342return result;343};344345// certain bugs can only be detected in standard documents346// to avoid writing a live loading document create a fake one347if (doc.implementation && doc.implementation.createDocument) {348// use a shadow document body as context349context = doc.implementation.createDocument('', '', null).350appendChild(doc.createElement('html')).351appendChild(doc.createElement('head')).parentNode.352appendChild(doc.createElement('body'));353} else {354// use an unattached div node as context355context = doc.createElement('div');356}357358// fix for Safari 8.x and other engines that359// fail querying filtered sibling combinators360element = doc.createElement('div');361element.innerHTML = '<p id="a"></p><br>';362expect('p#a+*', element, 0) &&363pattern.push('\\w+#\\w+.*[+~]');364365// ^= $= *= operators bugs with empty values (Opera 10 / IE8)366element = doc.createElement('p');367element.setAttribute('class', '');368expect('[class^=""]', element, 1) &&369pattern.push('[*^$]=[\\x20\\t\\n\\r\\f]*(?:""|' + "'')");370371// :checked bug with option elements (Firefox 3.6.x)372// it wrongly includes 'selected' options elements373// HTML5 rules says selected options also match374element = doc.createElement('option');375element.setAttribute('selected', 'selected');376expect(':checked', element, 0) &&377pattern.push(':checked');378379// :enabled :disabled bugs with hidden fields (Firefox 3.5)380// http://www.w3.org/TR/html5/links.html#selector-enabled381// http://www.w3.org/TR/css3-selectors/#enableddisabled382// not supported by IE8 Query Selector383element = doc.createElement('input');384element.setAttribute('type', 'hidden');385expect(':enabled', element, 0) &&386pattern.push(':enabled', ':disabled');387388// :link bugs with hyperlinks matching (Firefox/Safari)389element = doc.createElement('link');390element.setAttribute('href', 'x');391expect(':link', element, 1) ||392pattern.push(':link');393394// avoid attribute selectors for IE QSA395if (BUGGY_HAS_ATTRIBUTE) {396// IE fails in reading:397// - original values for input/textarea398// - original boolean values for controls399pattern.push('\\[[\\x20\\t\\n\\r\\f]*(?:checked|disabled|ismap|multiple|readonly|selected|value)');400}401402return pattern.length ?403new global.RegExp(pattern.join('|')) :404{ 'test': function() { return false; } };405406})() :407true,408409// matches class selectors410RE_CLASS = new global.RegExp('(?:\\[[\\x20\\t\\n\\r\\f]*class\\b|\\.' + identifier + ')'),411412// matches simple id, tag & class selectors413RE_SIMPLE_SELECTOR = new global.RegExp(414BUGGY_GEBTN && BUGGY_GEBCN || OPERA ?415'^#?-?[_a-zA-Z]{1}' + encoding + '*$' : BUGGY_GEBTN ?416'^[.#]?-?[_a-zA-Z]{1}' + encoding + '*$' : BUGGY_GEBCN ?417'^(?:\\*|#-?[_a-zA-Z]{1}' + encoding + '*)$' :418'^(?:\\*|[.#]?-?[_a-zA-Z]{1}' + encoding + '*)$'),419420/*----------------------------- LOOKUP OBJECTS -----------------------------*/421422LINK_NODES = new global.Object({ 'a': 1, 'A': 1, 'area': 1, 'AREA': 1, 'link': 1, 'LINK': 1 }),423424// boolean attributes should return attribute name instead of true/false425ATTR_BOOLEAN = new global.Object({426'checked': 1, 'disabled': 1, 'ismap': 1,427'multiple': 1, 'readonly': 1, 'selected': 1428}),429430// dynamic attributes that needs to be checked against original HTML value431ATTR_DEFAULT = new global.Object({432'value': 'defaultValue',433'checked': 'defaultChecked',434'selected': 'defaultSelected'435}),436437// attributes referencing URI data values need special treatment in IE438ATTR_URIDATA = new global.Object({439'action': 2, 'cite': 2, 'codebase': 2, 'data': 2, 'href': 2,440'longdesc': 2, 'lowsrc': 2, 'src': 2, 'usemap': 2441}),442443// HTML 5 draft specifications444// http://www.whatwg.org/specs/web-apps/current-work/#selectors445HTML_TABLE = new global.Object({446// class attribute must be treated case-insensitive in HTML quirks mode447// initialized by default to Standard Mode (case-sensitive),448// set dynamically by the attribute resolver449'class': 0,450'accept': 1, 'accept-charset': 1, 'align': 1, 'alink': 1, 'axis': 1,451'bgcolor': 1, 'charset': 1, 'checked': 1, 'clear': 1, 'codetype': 1, 'color': 1,452'compact': 1, 'declare': 1, 'defer': 1, 'dir': 1, 'direction': 1, 'disabled': 1,453'enctype': 1, 'face': 1, 'frame': 1, 'hreflang': 1, 'http-equiv': 1, 'lang': 1,454'language': 1, 'link': 1, 'media': 1, 'method': 1, 'multiple': 1, 'nohref': 1,455'noresize': 1, 'noshade': 1, 'nowrap': 1, 'readonly': 1, 'rel': 1, 'rev': 1,456'rules': 1, 'scope': 1, 'scrolling': 1, 'selected': 1, 'shape': 1, 'target': 1,457'text': 1, 'type': 1, 'valign': 1, 'valuetype': 1, 'vlink': 1458}),459460// the following attributes must be treated case-insensitive in XHTML mode461// Niels Leenheer http://rakaz.nl/item/css_selector_bugs_case_sensitivity462XHTML_TABLE = new global.Object({463'accept': 1, 'accept-charset': 1, 'alink': 1, 'axis': 1,464'bgcolor': 1, 'charset': 1, 'codetype': 1, 'color': 1,465'enctype': 1, 'face': 1, 'hreflang': 1, 'http-equiv': 1,466'lang': 1, 'language': 1, 'link': 1, 'media': 1, 'rel': 1,467'rev': 1, 'target': 1, 'text': 1, 'type': 1, 'vlink': 1468}),469470/*-------------------------- REGULAR EXPRESSIONS ---------------------------*/471472// placeholder to add functionalities473Selectors = new global.Object({474// as a simple example this will check475// for chars not in standard ascii table476//477// 'mySpecialSelector': {478// 'Expression': /\u0080-\uffff/,479// 'Callback': mySelectorCallback480// }481//482// 'mySelectorCallback' will be invoked483// only after passing all other standard484// checks and only if none of them worked485}),486487// attribute operators488Operators = new global.Object({489'=': "n=='%m'",490'^=': "n.indexOf('%m')==0",491'*=': "n.indexOf('%m')>-1",492'|=': "(n+'-').indexOf('%m-')==0",493'~=': "(' '+n+' ').indexOf(' %m ')>-1",494'$=': "n.substr(n.length-'%m'.length)=='%m'"495}),496497// optimization expressions498Optimize = new global.Object({499ID: new global.RegExp('^\\*?#(' + encoding + '+)|' + skipgroup),500TAG: new global.RegExp('^(' + encoding + '+)|' + skipgroup),501CLASS: new global.RegExp('^\\*?\\.(' + encoding + '+$)|' + skipgroup)502}),503504// precompiled Regular Expressions505Patterns = new global.Object({506// structural pseudo-classes and child selectors507spseudos: /^\:(root|empty|(?:first|last|only)(?:-child|-of-type)|nth(?:-last)?(?:-child|-of-type)\(\s*(even|odd|(?:[-+]{0,1}\d*n\s*)?[-+]{0,1}\s*\d*)\s*\))?(.*)/i,508// uistates + dynamic + negation pseudo-classes509dpseudos: /^\:(link|visited|target|active|focus|hover|checked|disabled|enabled|selected|lang\(([-\w]{2,})\)|not\(([^()]*|.*)\))?(.*)/i,510// element attribute matcher511attribute: new global.RegExp('^\\[' + attrmatcher + '\\](.*)'),512// E > F513children: /^[\x20\t\n\r\f]*\>[\x20\t\n\r\f]*(.*)/,514// E + F515adjacent: /^[\x20\t\n\r\f]*\+[\x20\t\n\r\f]*(.*)/,516// E ~ F517relative: /^[\x20\t\n\r\f]*\~[\x20\t\n\r\f]*(.*)/,518// E F519ancestor: /^[\x20\t\n\r\f]+(.*)/,520// all521universal: /^\*(.*)/,522// id523id: new global.RegExp('^#(' + encoding + '+)(.*)'),524// tag525tagName: new global.RegExp('^(' + encoding + '+)(.*)'),526// class527className: new global.RegExp('^\\.(' + encoding + '+)(.*)')528}),529530/*------------------------------ UTIL METHODS ------------------------------*/531532// concat elements to data533concatList =534function(data, elements) {535var i = -1, element;536if (!data.length && global.Array.slice)537return global.Array.slice(elements);538while ((element = elements[++i]))539data[data.length] = element;540return data;541},542543// concat elements to data and callback544concatCall =545function(data, elements, callback) {546var i = -1, element;547while ((element = elements[++i])) {548if (false === callback(data[data.length] = element)) { break; }549}550return data;551},552553// change context specific variables554switchContext =555function(from, force) {556var div, oldDoc = doc;557// save passed context558lastContext = from;559// set new context document560doc = from.ownerDocument || from;561if (force || oldDoc !== doc) {562// set document root563root = doc.documentElement;564// set host environment flags565XML_DOCUMENT = doc.createElement('DiV').nodeName == 'DiV';566567// In quirks mode css class names are case insensitive.568// In standards mode they are case sensitive. See docs:569// https://developer.mozilla.org/en/Mozilla_Quirks_Mode_Behavior570// http://www.whatwg.org/specs/web-apps/current-work/#selectors571QUIRKS_MODE = !XML_DOCUMENT &&572typeof doc.compatMode == 'string' ?573doc.compatMode.indexOf('CSS') < 0 :574(function() {575var style = doc.createElement('div').style;576return style && (style.width = 1) && style.width == '1px';577})();578579div = doc.createElement('div');580div.appendChild(doc.createElement('p')).setAttribute('class', 'xXx');581div.appendChild(doc.createElement('p')).setAttribute('class', 'xxx');582583// GEBCN buggy in quirks mode, match count is:584// Firefox 3.0+ [xxx = 1, xXx = 1]585// Opera 10.63+ [xxx = 0, xXx = 2]586BUGGY_QUIRKS_GEBCN =587!XML_DOCUMENT && NATIVE_GEBCN && QUIRKS_MODE &&588(div.getElementsByClassName('xxx').length != 2 ||589div.getElementsByClassName('xXx').length != 2);590591// QSAPI buggy in quirks mode, match count is:592// At least Chrome 4+, Firefox 3.5+, Opera 10.x+, Safari 4+ [xxx = 1, xXx = 2]593// Safari 3.2 QSA doesn't work with mixedcase in quirksmode [xxx = 1, xXx = 0]594// https://bugs.webkit.org/show_bug.cgi?id=19047595// must test the attribute selector '[class~=xxx]'596// before '.xXx' or the bug may not present itself597BUGGY_QUIRKS_QSAPI =598!XML_DOCUMENT && NATIVE_QSAPI && QUIRKS_MODE &&599(div.querySelectorAll('[class~=xxx]').length != 2 ||600div.querySelectorAll('.xXx').length != 2);601602Config.CACHING && Dom.setCache(true, doc);603}604},605606// convert a CSS string or identifier containing escape sequence to a607// javascript string with javascript escape sequences608convertEscapes =609function(str) {610return str.replace(/\\([0-9a-fA-F]{1,6}\x20?|.)|([\x22\x27])/g, function(substring, p1, p2) {611var codePoint, highHex, highSurrogate, lowHex, lowSurrogate;612613if (p2) {614// unescaped " or '615return '\\' + p2;616}617618if (/^[0-9a-fA-F]/.test(p1)) {619// \1f23620codePoint = parseInt(p1, 16);621622if (codePoint < 0 || codePoint > 0x10ffff) {623// the replacement character624return '\\ufffd';625}626627// javascript strings are in UTF-16628if (codePoint <= 0xffff) {629// Basic630lowHex = '000' + codePoint.toString(16);631return '\\u' + lowHex.substr(lowHex.length - 4);632}633634// Supplementary635codePoint -= 0x10000;636highSurrogate = (codePoint >> 10) + 0xd800;637lowSurrogate = (codePoint % 0x400) + 0xdc00;638highHex = '000' + highSurrogate.toString(16);639lowHex = '000' + lowSurrogate.toString(16);640641return '\\u' + highHex.substr(highHex.length - 4) +642'\\u' + lowHex.substr(lowHex.length - 4);643}644645if (/^[\\\x22\x27]/.test(p1)) {646// \' \"647return substring;648}649650// \g \h \. \# etc651return p1;652});653},654655/*------------------------------ DOM METHODS -------------------------------*/656657// element by id (raw)658// @return reference or null659byIdRaw =660function(id, elements) {661var i = -1, element = null;662while ((element = elements[++i])) {663if (element.getAttribute('id') == id) {664break;665}666}667return element;668},669670// element by id671// @return reference or null672_byId = !BUGGY_GEBID ?673function(id, from) {674id = id.replace(/\\([^\\]{1})/g, '$1');675return from.getElementById && from.getElementById(id) ||676byIdRaw(id, from.getElementsByTagName('*'));677} :678function(id, from) {679var element = null;680id = id.replace(/\\([^\\]{1})/g, '$1');681if (XML_DOCUMENT || from.nodeType != 9) {682return byIdRaw(id, from.getElementsByTagName('*'));683}684if ((element = from.getElementById(id)) &&685element.name == id && from.getElementsByName) {686return byIdRaw(id, from.getElementsByName(id));687}688return element;689},690691// publicly exposed byId692// @return reference or null693byId =694function(id, from) {695from || (from = doc);696if (lastContext !== from) { switchContext(from); }697return _byId(id, from);698},699700// elements by tag (raw)701// @return array702byTagRaw =703function(tag, from) {704var any = tag == '*', element = from, elements = new global.Array(), next = element.firstChild;705any || (tag = tag.toUpperCase());706while ((element = next)) {707if (element.tagName > '@' && (any || element.tagName.toUpperCase() == tag)) {708elements[elements.length] = element;709}710if ((next = element.firstChild || element.nextSibling)) continue;711while (!next && (element = element.parentNode) && element !== from) {712next = element.nextSibling;713}714}715return elements;716},717718// elements by tag719// @return array720_byTag = !BUGGY_GEBTN && NATIVE_SLICE_PROTO ?721function(tag, from) {722return XML_DOCUMENT || from.nodeType == 11 ? byTagRaw(tag, from) :723slice.call(from.getElementsByTagName(tag), 0);724} :725function(tag, from) {726var i = -1, j = i, data = new global.Array(),727element, elements = from.getElementsByTagName(tag);728if (tag == '*') {729while ((element = elements[++i])) {730if (element.nodeName > '@')731data[++j] = element;732}733} else {734while ((element = elements[++i])) {735data[i] = element;736}737}738return data;739},740741// publicly exposed byTag742// @return array743byTag =744function(tag, from) {745from || (from = doc);746if (lastContext !== from) { switchContext(from); }747return _byTag(tag, from);748},749750// publicly exposed byName751// @return array752byName =753function(name, from) {754return select('[name="' + name.replace(/\\([^\\]{1})/g, '$1') + '"]', from);755},756757// elements by class (raw)758// @return array759byClassRaw =760function(name, from) {761var i = -1, j = i, data = new global.Array(), element, elements = _byTag('*', from), n;762name = ' ' + (QUIRKS_MODE ? name.toLowerCase() : name).replace(/\\([^\\]{1})/g, '$1') + ' ';763while ((element = elements[++i])) {764n = XML_DOCUMENT ? element.getAttribute('class') : element.className;765if (n && n.length && (' ' + (QUIRKS_MODE ? n.toLowerCase() : n).766replace(reWhiteSpace, ' ') + ' ').indexOf(name) > -1) {767data[++j] = element;768}769}770return data;771},772773// elements by class774// @return array775_byClass =776function(name, from) {777return (BUGGY_GEBCN || BUGGY_QUIRKS_GEBCN || XML_DOCUMENT || !from.getElementsByClassName) ?778byClassRaw(name, from) : slice.call(from.getElementsByClassName(name.replace(/\\([^\\]{1})/g, '$1')), 0);779},780781// publicly exposed byClass782// @return array783byClass =784function(name, from) {785from || (from = doc);786if (lastContext !== from) { switchContext(from); }787return _byClass(name, from);788},789790// check element is descendant of container791// @return boolean792contains = 'compareDocumentPosition' in root ?793function(container, element) {794return (container.compareDocumentPosition(element) & 16) == 16;795} : 'contains' in root ?796function(container, element) {797return container !== element && container.contains(element);798} :799function(container, element) {800while ((element = element.parentNode)) {801if (element === container) return true;802}803return false;804},805806// attribute value807// @return string808getAttribute = !BUGGY_GET_ATTRIBUTE ?809function(node, attribute) {810return node.getAttribute(attribute) || '';811} :812function(node, attribute) {813attribute = attribute.toLowerCase();814if (typeof node[attribute] == 'object') {815return node.attributes[attribute] &&816node.attributes[attribute].value || '';817}818return (819// 'type' can only be read by using native getAttribute820attribute == 'type' ? node.getAttribute(attribute) || '' :821// specific URI data attributes (parameter 2 to fix IE bug)822ATTR_URIDATA[attribute] ? node.getAttribute(attribute, 2) || '' :823// boolean attributes should return name instead of true/false824ATTR_BOOLEAN[attribute] ? node.getAttribute(attribute) ? attribute : 'false' :825((node = node.getAttributeNode(attribute)) && node.value) || '');826},827828// attribute presence829// @return boolean830hasAttribute = !BUGGY_HAS_ATTRIBUTE ?831function(node, attribute) {832return XML_DOCUMENT ?833!!node.getAttribute(attribute) :834node.hasAttribute(attribute);835} :836function(node, attribute) {837attribute = attribute.toLowerCase();838if (ATTR_DEFAULT[attribute]) {839return !!node[ATTR_DEFAULT[attribute]];840}841// read the attribute node842node = node.getAttributeNode(attribute);843return !!(node && node.specified);844},845846// check node emptyness847// @return boolean848isEmpty =849function(node) {850node = node.firstChild;851while (node) {852if (node.nodeType == 3 || node.nodeName > '@') return false;853node = node.nextSibling;854}855return true;856},857858// check if element matches the :link pseudo859// @return boolean860isLink =861function(element) {862return hasAttribute(element,'href') && LINK_NODES[element.nodeName];863},864865// child position by nodeType866// @return number867nthElement =868function(element, last) {869var count = 1, succ = last ? 'nextSibling' : 'previousSibling';870while ((element = element[succ])) {871if (element.nodeName > '@') ++count;872}873return count;874},875876// child position by nodeName877// @return number878nthOfType =879function(element, last) {880var count = 1, succ = last ? 'nextSibling' : 'previousSibling', type = element.nodeName;881while ((element = element[succ])) {882if (element.nodeName == type) ++count;883}884return count;885},886887/*------------------------------- DEBUGGING --------------------------------*/888889// get/set (string/object) working modes890configure =891function(option) {892if (typeof option == 'string') { return Config[option] || Config; }893if (typeof option != 'object') { return false; }894for (var i in option) {895Config[i] = !!option[i];896if (i == 'SIMPLENOT') {897matchContexts = new global.Object();898matchResolvers = new global.Object();899selectContexts = new global.Object();900selectResolvers = new global.Object();901if (!Config[i]) { Config['USE_QSAPI'] = false; }902} else if (i == 'USE_QSAPI') {903Config[i] = !!option[i] && NATIVE_QSAPI;904}905}906reValidator = new global.RegExp(Config.SIMPLENOT ?907standardValidator : extendedValidator, 'g');908return true;909},910911// control user notifications912emit =913function(message) {914if (Config.VERBOSITY) { throw new global.Error(message); }915if (global.console && global.console.log) {916global.console.log(message);917}918},919920Config = new global.Object({921922// used to enable/disable caching of result sets923CACHING: false,924925// by default do not add missing left/right context926// to selector string shortcuts like "+div" or "ul>"927// callable Dom.shortcuts method has to be available928SHORTCUTS: false,929930// by default disable complex selectors nested in931// ':not()' pseudo-classes, as for specifications932SIMPLENOT: true,933934// strict QSA match all non-unique IDs (false)935// speed & libs compat match unique ID (true)936UNIQUE_ID: true,937938// HTML5 handling for the ":checked" pseudo-class939USE_HTML5: true,940941// controls enabling the Query Selector API branch942USE_QSAPI: NATIVE_QSAPI,943944// controls the engine error/warning notifications945VERBOSITY: true946947}),948949/*---------------------------- COMPILER METHODS ----------------------------*/950951// code string reused to build compiled functions952ACCEPT_NODE = 'r[r.length]=c[k];if(f&&false===f(c[k]))break main;else continue main;',953954// compile a comma separated group of selector955// @mode boolean true for select, false for match956// return a compiled function957compile =958function(selector, source, mode) {959960var parts = typeof selector == 'string' ? selector.match(reSplitGroup) : selector;961962// ensures that source is a string963typeof source == 'string' || (source = '');964965if (parts.length == 1) {966source += compileSelector(parts[0], mode ? ACCEPT_NODE : 'f&&f(k);return true;', mode);967} else {968// for each selector in the group969var i = -1, seen = new global.Object(), token;970while ((token = parts[++i])) {971token = token.replace(reTrimSpaces, '');972// avoid repeating the same token973// in comma separated group (p, p)974if (!seen[token] && (seen[token] = true)) {975source += compileSelector(token, mode ? ACCEPT_NODE : 'f&&f(k);return true;', mode);976}977}978}979980if (mode) {981// for select method982return new global.Function('c,s,r,d,h,g,f,v',983'var N,n,x=0,k=-1,e;main:while((e=c[++k])){' + source + '}return r;');984} else {985// for match method986return new global.Function('e,s,r,d,h,g,f,v',987'var N,n,x=0,k=e;' + source + 'return false;');988}989},990991// allows to cache already visited nodes992FILTER =993'var z=v[@]||(v[@]=[]),l=z.length-1;' +994'while(l>=0&&z[l]!==e)--l;' +995'if(l!==-1){break;}' +996'z[z.length]=e;',997998// compile a CSS3 string selector into ad-hoc javascript matching function999// @return string (to be compiled)1000compileSelector =1001function(selector, source, mode) {10021003var a, b, n, k = 0, expr, match, result, status, test, type;10041005while (selector) {10061007k++;10081009// *** Universal selector1010// * match all (empty block, do not remove)1011if ((match = selector.match(Patterns.universal))) {1012// do nothing, handled in the compiler where1013// BUGGY_GEBTN return comment nodes (ex: IE)1014expr = '';1015}10161017// *** ID selector1018// #Foo Id case sensitive1019else if ((match = selector.match(Patterns.id))) {1020// document can contain conflicting elements (id/name)1021// prototype selector unit need this method to recover bad HTML forms1022source = 'if(' + (XML_DOCUMENT ?1023's.getAttribute(e,"id")' :1024'(e.submit?s.getAttribute(e,"id"):e.id)') +1025'=="' + match[1] + '"' +1026'){' + source + '}';1027}10281029// *** Type selector1030// Foo Tag (case insensitive)1031else if ((match = selector.match(Patterns.tagName))) {1032// both tagName and nodeName properties may be upper/lower case1033// depending on their creation NAMESPACE in createElementNS()1034source = 'if(e.nodeName' + (XML_DOCUMENT ?1035'=="' + match[1] + '"' : '.toUpperCase()' +1036'=="' + match[1].toUpperCase() + '"') +1037'){' + source + '}';1038}10391040// *** Class selector1041// .Foo Class (case sensitive)1042else if ((match = selector.match(Patterns.className))) {1043// W3C CSS3 specs: element whose "class" attribute has been assigned a1044// list of whitespace-separated values, see section 6.4 Class selectors1045// and notes at the bottom; explicitly non-normative in this specification.1046source = 'if((n=' + (XML_DOCUMENT ?1047's.getAttribute(e,"class")' : 'e.className') +1048')&&n.length&&(" "+' + (QUIRKS_MODE ? 'n.toLowerCase()' : 'n') +1049'.replace(' + reWhiteSpace + '," ")+" ").indexOf(" ' +1050(QUIRKS_MODE ? match[1].toLowerCase() : match[1]) + ' ")>-1' +1051'){' + source + '}';1052}10531054// *** Attribute selector1055// [attr] [attr=value] [attr="value"] [attr='value'] and !=, *=, ~=, |=, ^=, $=1056// case sensitivity is treated differently depending on the document type (see map)1057else if ((match = selector.match(Patterns.attribute))) {10581059// xml namespaced attribute ?1060expr = match[1].split(':');1061expr = expr.length == 2 ? expr[1] : expr[0] + '';10621063if (match[2] && !Operators[match[2]]) {1064emit('Unsupported operator in attribute selectors "' + selector + '"');1065return '';1066}10671068test = 'false';10691070// replace Operators parameter if needed1071if (match[2] && match[4] && (test = Operators[match[2]])) {1072match[4] = convertEscapes(match[4]);1073// case treatment depends on document1074HTML_TABLE['class'] = QUIRKS_MODE ? 1 : 0;1075type = (XML_DOCUMENT ? XHTML_TABLE : HTML_TABLE)[expr.toLowerCase()];1076test = test.replace(/\%m/g, type ? match[4].toLowerCase() : match[4]);1077} else if (match[2] == '!=' || match[2] == '=') {1078test = 'n' + match[2] + '=""';1079}10801081// build expression for has/getAttribute1082expr = 'n=s.' + (match[2] ? 'get' : 'has') +1083'Attribute(e,"' + match[1] + '")' +1084(type && match[2] ? '.toLowerCase();' : ';');10851086source = expr + 'if(' + (match[2] ? test : 'n') + '){' + source + '}';1087}10881089// *** Adjacent sibling combinator1090// E + F (F adiacent sibling of E)1091else if ((match = selector.match(Patterns.adjacent))) {1092source = (mode ? '' : FILTER.replace(/@/g, k)) + source;1093source = NATIVE_TRAVERSAL_API ?1094'var N' + k + '=e;while(e&&(e=e.previousElementSibling)){' + source + 'break;}e=N' + k + ';' :1095'var N' + k + '=e;while(e&&(e=e.previousSibling)){if(e.nodeName>"@"){' + source + 'break;}}e=N' + k + ';';1096}10971098// *** General sibling combinator1099// E ~ F (F relative sibling of E)1100else if ((match = selector.match(Patterns.relative))) {1101source = (mode ? '' : FILTER.replace(/@/g, k)) + source;1102source = NATIVE_TRAVERSAL_API ?1103('var N' + k + '=e;e=e.parentNode.firstElementChild;' +1104'while(e&&e!==N' + k + '){' + source + 'e=e.nextElementSibling;}e=N' + k + ';') :1105('var N' + k + '=e;e=e.parentNode.firstChild;' +1106'while(e&&e!==N' + k + '){if(e.nodeName>"@"){' + source + '}e=e.nextSibling;}e=N' + k + ';');1107}11081109// *** Child combinator1110// E > F (F children of E)1111else if ((match = selector.match(Patterns.children))) {1112source = (mode ? '' : FILTER.replace(/@/g, k)) + source;1113source = 'var N' + k + '=e;while(e&&e!==h&&e!==g&&(e=e.parentNode)){' + source + 'break;}e=N' + k + ';';1114}11151116// *** Descendant combinator1117// E F (E ancestor of F)1118else if ((match = selector.match(Patterns.ancestor))) {1119source = (mode ? '' : FILTER.replace(/@/g, k)) + source;1120source = 'var N' + k + '=e;while(e&&e!==h&&e!==g&&(e=e.parentNode)){' + source + '}e=N' + k + ';';1121}11221123// *** Structural pseudo-classes1124// :root, :empty,1125// :first-child, :last-child, :only-child,1126// :first-of-type, :last-of-type, :only-of-type,1127// :nth-child(), :nth-last-child(), :nth-of-type(), :nth-last-of-type()1128else if ((match = selector.match(Patterns.spseudos)) && match[1]) {11291130switch (match[1]) {1131case 'root':1132// element root of the document1133if (match[3]) {1134source = 'if(e===h||s.contains(h,e)){' + source + '}';1135} else {1136source = 'if(e===h){' + source + '}';1137}1138break;11391140case 'empty':1141// element that has no children1142source = 'if(s.isEmpty(e)){' + source + '}';1143break;11441145default:1146if (match[1] && match[2]) {1147if (match[2] == 'n') {1148source = 'if(e!==h){' + source + '}';1149break;1150} else if (match[2] == 'even') {1151a = 2;1152b = 0;1153} else if (match[2] == 'odd') {1154a = 2;1155b = 1;1156} else {1157// assumes correct "an+b" format, "b" before "a" to keep "n" values1158b = ((n = match[2].match(/(-?\d+)$/)) ? global.parseInt(n[1], 10) : 0);1159a = ((n = match[2].match(/(-?\d*)n/i)) ? global.parseInt(n[1], 10) : 0);1160if (n && n[1] == '-') a = -1;1161}11621163// build test expression out of structural pseudo (an+b) parameters1164// see here: http://www.w3.org/TR/css3-selectors/#nth-child-pseudo1165test = a > 1 ?1166(/last/i.test(match[1])) ? '(n-(' + b + '))%' + a + '==0' :1167'n>=' + b + '&&(n-(' + b + '))%' + a + '==0' : a < -1 ?1168(/last/i.test(match[1])) ? '(n-(' + b + '))%' + a + '==0' :1169'n<=' + b + '&&(n-(' + b + '))%' + a + '==0' : a === 0 ?1170'n==' + b : a == -1 ? 'n<=' + b : 'n>=' + b;11711172// 4 cases: 1 (nth) x 4 (child, of-type, last-child, last-of-type)1173source =1174'if(e!==h){' +1175'n=s[' + (/-of-type/i.test(match[1]) ? '"nthOfType"' : '"nthElement"') + ']' +1176'(e,' + (/last/i.test(match[1]) ? 'true' : 'false') + ');' +1177'if(' + test + '){' + source + '}' +1178'}';11791180} else {1181// 6 cases: 3 (first, last, only) x 1 (child) x 2 (-of-type)1182a = /first/i.test(match[1]) ? 'previous' : 'next';1183n = /only/i.test(match[1]) ? 'previous' : 'next';1184b = /first|last/i.test(match[1]);11851186type = /-of-type/i.test(match[1]) ? '&&n.nodeName!=e.nodeName' : '&&n.nodeName<"@"';11871188source = 'if(e!==h){' +1189( 'n=e;while((n=n.' + a + 'Sibling)' + type + ');if(!n){' + (b ? source :1190'n=e;while((n=n.' + n + 'Sibling)' + type + ');if(!n){' + source + '}') + '}' ) + '}';1191}1192break;1193}11941195}11961197// *** negation, user action and target pseudo-classes1198// *** UI element states and dynamic pseudo-classes1199// CSS3 :not, :checked, :enabled, :disabled, :target1200// CSS3 :active, :hover, :focus1201// CSS3 :link, :visited1202else if ((match = selector.match(Patterns.dpseudos)) && match[1]) {12031204switch (match[1].match(/^\w+/)[0]) {1205// CSS3 negation pseudo-class1206case 'not':1207// compile nested selectors, DO NOT pass the callback parameter1208// SIMPLENOT allow disabling complex selectors nested1209// in ':not()' pseudo-classes, breaks some test units1210expr = match[3].replace(reTrimSpaces, '');12111212if (Config.SIMPLENOT && !reSimpleNot.test(expr)) {1213// see above, log error but continue execution1214emit('Negation pseudo-class only accepts simple selectors "' + selector + '"');1215return '';1216} else {1217if ('compatMode' in doc) {1218source = 'if(!' + compile(expr, '', false) + '(e,s,r,d,h,g)){' + source + '}';1219} else {1220source = 'if(!s.match(e, "' + expr.replace(/\x22/g, '\\"') + '",g)){' + source +'}';1221}1222}1223break;12241225// CSS3 UI element states1226case 'checked':1227// for radio buttons checkboxes (HTML4) and options (HTML5)1228source = 'if((typeof e.form!=="undefined"&&(/^(?:radio|checkbox)$/i).test(e.type)&&e.checked)' +1229(Config.USE_HTML5 ? '||(/^option$/i.test(e.nodeName)&&(e.selected||e.checked))' : '') +1230'){' + source + '}';1231break;1232case 'disabled':1233// does not consider hidden input fields1234source = 'if(((typeof e.form!=="undefined"' +1235(Config.USE_HTML5 ? '' : '&&!(/^hidden$/i).test(e.type)') +1236')||s.isLink(e))&&e.disabled===true){' + source + '}';1237break;1238case 'enabled':1239// does not consider hidden input fields1240source = 'if(((typeof e.form!=="undefined"' +1241(Config.USE_HTML5 ? '' : '&&!(/^hidden$/i).test(e.type)') +1242')||s.isLink(e))&&e.disabled===false){' + source + '}';1243break;12441245// CSS3 lang pseudo-class1246case 'lang':1247test = '';1248if (match[2]) test = match[2].substr(0, 2) + '-';1249source = 'do{(n=e.lang||"").toLowerCase();' +1250'if((n==""&&h.lang=="' + match[2].toLowerCase() + '")||' +1251'(n&&(n=="' + match[2].toLowerCase() +1252'"||n.substr(0,3)=="' + test.toLowerCase() + '")))' +1253'{' + source + 'break;}}while((e=e.parentNode)&&e!==g);';1254break;12551256// CSS3 target pseudo-class1257case 'target':1258source = 'if(e.id==d.location.hash.slice(1)){' + source + '}';1259break;12601261// CSS3 dynamic pseudo-classes1262case 'link':1263source = 'if(s.isLink(e)&&!e.visited){' + source + '}';1264break;1265case 'visited':1266source = 'if(s.isLink(e)&&e.visited){' + source + '}';1267break;12681269// CSS3 user action pseudo-classes IE & FF3 have native support1270// these capabilities may be emulated by some event managers1271case 'active':1272if (XML_DOCUMENT) break;1273source = 'if(e===d.activeElement){' + source + '}';1274break;1275case 'hover':1276if (XML_DOCUMENT) break;1277source = 'if(e===d.hoverElement){' + source + '}';1278break;1279case 'focus':1280if (XML_DOCUMENT) break;1281source = NATIVE_FOCUS ?1282'if(e===d.activeElement&&d.hasFocus()&&(e.type||e.href||typeof e.tabIndex=="number")){' + source + '}' :1283'if(e===d.activeElement&&(e.type||e.href)){' + source + '}';1284break;12851286// CSS2 selected pseudo-classes, not part of current CSS3 drafts1287// the 'selected' property is only available for option elements1288case 'selected':1289// fix Safari selectedIndex property bug1290expr = BUGGY_SELECTED ? '||(n=e.parentNode)&&n.options[n.selectedIndex]===e' : '';1291source = 'if(/^option$/i.test(e.nodeName)&&(e.selected||e.checked' + expr + ')){' + source + '}';1292break;12931294default:1295break;1296}12971298}12991300else {13011302// this is where external extensions are1303// invoked if expressions match selectors1304expr = false;1305status = false;1306for (expr in Selectors) {1307if ((match = selector.match(Selectors[expr].Expression)) && match[1]) {1308result = Selectors[expr].Callback(match, source);1309source = result.source;1310status = result.status;1311if (status) { break; }1312}1313}13141315// if an extension fails to parse the selector1316// it must return a false boolean in "status"1317if (!status) {1318// log error but continue execution, don't throw real exceptions1319// because blocking following processes maybe is not a good idea1320emit('Unknown pseudo-class selector "' + selector + '"');1321return '';1322}13231324if (!expr) {1325// see above, log error but continue execution1326emit('Unknown token in selector "' + selector + '"');1327return '';1328}13291330}13311332// error if no matches found by the pattern scan1333if (!match) {1334emit('Invalid syntax in selector "' + selector + '"');1335return '';1336}13371338// ensure "match" is not null or empty since1339// we do not throw real DOMExceptions above1340selector = match && match[match.length - 1];1341}13421343return source;1344},13451346/*----------------------------- QUERY METHODS ------------------------------*/13471348// match element with selector1349// @return boolean1350match =1351function(element, selector, from, callback) {13521353var parts;13541355if (!(element && element.nodeType == 1)) {1356emit('Invalid element argument');1357return false;1358} else if (typeof selector != 'string') {1359emit('Invalid selector argument');1360return false;1361} else if (from && from.nodeType == 1 && !contains(from, element)) {1362return false;1363} else if (lastContext !== from) {1364// reset context data when it changes1365// and ensure context is set to a default1366switchContext(from || (from = element.ownerDocument));1367}13681369selector = selector.replace(reTrimSpaces, '');13701371Config.SHORTCUTS && (selector = Dom.shortcuts(selector, element, from));13721373if (lastMatcher != selector) {1374// process valid selector strings1375if ((parts = selector.match(reValidator)) && parts[0] == selector) {1376isSingleMatch = (parts = selector.match(reSplitGroup)).length < 2;1377// save passed selector1378lastMatcher = selector;1379lastPartsMatch = parts;1380} else {1381emit('The string "' + selector + '", is not a valid CSS selector');1382return false;1383}1384} else parts = lastPartsMatch;13851386// compile matcher resolvers if necessary1387if (!matchResolvers[selector] || matchContexts[selector] !== from) {1388matchResolvers[selector] = compile(isSingleMatch ? [selector] : parts, '', false);1389matchContexts[selector] = from;1390}13911392return matchResolvers[selector](element, Snapshot, [ ], doc, root, from, callback, new global.Object());1393},13941395// select only the first element1396// matching selector (document ordered)1397first =1398function(selector, from) {1399return select(selector, from, function() { return false; })[0] || null;1400},14011402// select elements matching selector1403// using new Query Selector API1404// or cross-browser client API1405// @return array1406select =1407function(selector, from, callback) {14081409var i, changed, element, elements, parts, token, original = selector;14101411if (arguments.length === 0) {1412emit('Not enough arguments');1413return [ ];1414} else if (typeof selector != 'string') {1415return [ ];1416} else if (from && !(/1|9|11/).test(from.nodeType)) {1417emit('Invalid or illegal context element');1418return [ ];1419} else if (lastContext !== from) {1420// reset context data when it changes1421// and ensure context is set to a default1422switchContext(from || (from = doc));1423}14241425if (Config.CACHING && (elements = Dom.loadResults(original, from, doc, root))) {1426return callback ? concatCall([ ], elements, callback) : elements;1427}14281429if (!OPERA_QSAPI && RE_SIMPLE_SELECTOR.test(selector)) {1430switch (selector.charAt(0)) {1431case '#':1432if (Config.UNIQUE_ID) {1433elements = (element = _byId(selector.slice(1), from)) ? [ element ] : [ ];1434}1435break;1436case '.':1437elements = _byClass(selector.slice(1), from);1438break;1439default:1440elements = _byTag(selector, from);1441break;1442}1443}14441445else if (!XML_DOCUMENT && Config.USE_QSAPI &&1446!(BUGGY_QUIRKS_QSAPI && RE_CLASS.test(selector)) &&1447!RE_BUGGY_QSAPI.test(selector)) {1448try {1449elements = from.querySelectorAll(selector);1450} catch(e) { }1451}14521453if (elements) {1454elements = callback ? concatCall([ ], elements, callback) :1455NATIVE_SLICE_PROTO ? slice.call(elements) : concatList([ ], elements);1456Config.CACHING && Dom.saveResults(original, from, doc, elements);1457return elements;1458}14591460selector = selector.replace(reTrimSpaces, '');14611462Config.SHORTCUTS && (selector = Dom.shortcuts(selector, from));14631464if ((changed = lastSelector != selector)) {1465// process valid selector strings1466if ((parts = selector.match(reValidator)) && parts[0] == selector) {1467isSingleSelect = (parts = selector.match(reSplitGroup)).length < 2;1468// save passed selector1469lastSelector = selector;1470lastPartsSelect = parts;1471} else {1472emit('The string "' + selector + '", is not a valid CSS selector');1473return [ ];1474}1475} else parts = lastPartsSelect;14761477// commas separators are treated sequentially to maintain order1478if (from.nodeType == 11) {14791480elements = byTagRaw('*', from);14811482} else if (!XML_DOCUMENT && isSingleSelect) {14831484if (changed) {1485// get right most selector token1486parts = selector.match(reSplitToken);1487token = parts[parts.length - 1];14881489// only last slice before :not rules1490lastSlice = token.split(':not')[0];14911492// position where token was found1493lastPosition = selector.length - token.length;1494}14951496// ID optimization RTL, to reduce number of elements to visit1497if (Config.UNIQUE_ID && (parts = lastSlice.match(Optimize.ID)) && (token = parts[1])) {1498if ((element = _byId(token, from))) {1499if (match(element, selector)) {1500callback && callback(element);1501elements = new global.Array(element);1502} else elements = new global.Array();1503}1504}15051506// ID optimization LTR, to reduce selection context searches1507else if (Config.UNIQUE_ID && (parts = selector.match(Optimize.ID)) && (token = parts[1])) {1508if ((element = _byId(token, doc))) {1509if ('#' + token == selector) {1510callback && callback(element);1511elements = new global.Array(element);1512} else if (/[>+~]/.test(selector)) {1513from = element.parentNode;1514} else {1515from = element;1516}1517} else elements = new global.Array();1518}15191520if (elements) {1521Config.CACHING && Dom.saveResults(original, from, doc, elements);1522return elements;1523}15241525if (!NATIVE_GEBCN && (parts = lastSlice.match(Optimize.TAG)) && (token = parts[1])) {1526if ((elements = _byTag(token, from)).length === 0) { return [ ]; }1527selector = selector.slice(0, lastPosition) + selector.slice(lastPosition).replace(token, '*');1528}15291530else if ((parts = lastSlice.match(Optimize.CLASS)) && (token = parts[1])) {1531if ((elements = _byClass(token, from)).length === 0) { return [ ]; }1532if (reOptimizeSelector.test(selector.charAt(selector.indexOf(token) - 1))) {1533selector = selector.slice(0, lastPosition) + selector.slice(lastPosition).replace('.' + token, '');1534} else {1535selector = selector.slice(0, lastPosition) + selector.slice(lastPosition).replace('.' + token, '*');1536}1537}15381539else if ((parts = selector.match(Optimize.CLASS)) && (token = parts[1])) {1540if ((elements = _byClass(token, from)).length === 0) { return [ ]; }1541for (i = 0, els = new global.Array(); elements.length > i; ++i) {1542els = concatList(els, elements[i].getElementsByTagName('*'));1543}1544elements = els;1545if (reOptimizeSelector.test(selector.charAt(selector.indexOf(token) - 1))) {1546selector = selector.slice(0, lastPosition) + selector.slice(lastPosition).replace('.' + token, '');1547} else {1548selector = selector.slice(0, lastPosition) + selector.slice(lastPosition).replace('.' + token, '*');1549}1550}15511552else if (NATIVE_GEBCN && (parts = lastSlice.match(Optimize.TAG)) && (token = parts[1])) {1553if ((elements = _byTag(token, from)).length === 0) { return [ ]; }1554selector = selector.slice(0, lastPosition) + selector.slice(lastPosition).replace(token, '*');1555}15561557}15581559if (!elements) {1560elements = /^(?:applet|object)$/i.test(from.nodeName) ? from.childNodes : _byTag('*', from);1561}1562// end of prefiltering pass15631564// compile selector resolver if necessary1565if (!selectResolvers[selector] || selectContexts[selector] !== from) {1566selectResolvers[selector] = compile(isSingleSelect ? [selector] : parts, '', true);1567selectContexts[selector] = from;1568}15691570elements = selectResolvers[selector](elements, Snapshot, [ ], doc, root, from, callback, new global.Object());15711572Config.CACHING && Dom.saveResults(original, from, doc, elements);15731574return elements;1575},15761577/*-------------------------------- STORAGE ---------------------------------*/15781579// empty function handler1580FN = function(x) { return x; },15811582// compiled match functions returning booleans1583matchContexts = new global.Object(),1584matchResolvers = new global.Object(),15851586// compiled select functions returning collections1587selectContexts = new global.Object(),1588selectResolvers = new global.Object(),15891590// used to pass methods to compiled functions1591Snapshot = new global.Object({15921593// element indexing methods1594nthElement: nthElement,1595nthOfType: nthOfType,15961597// element inspection methods1598getAttribute: getAttribute,1599hasAttribute: hasAttribute,16001601// element selection methods1602byClass: _byClass,1603byName: byName,1604byTag: _byTag,1605byId: _byId,16061607// helper/check methods1608contains: contains,1609isEmpty: isEmpty,1610isLink: isLink,16111612// selection/matching1613select: select,1614match: match1615}),16161617Tokens = new global.Object({1618prefixes: prefixes,1619encoding: encoding,1620operators: operators,1621whitespace: whitespace,1622identifier: identifier,1623attributes: attributes,1624combinators: combinators,1625pseudoclass: pseudoclass,1626pseudoparms: pseudoparms,1627quotedvalue: quotedvalue1628});16291630/*------------------------------- PUBLIC API -------------------------------*/16311632// code referenced by extensions1633Dom.ACCEPT_NODE = ACCEPT_NODE;16341635// retrieve element by id attr1636Dom.byId = byId;16371638// retrieve elements by tag name1639Dom.byTag = byTag;16401641// retrieve elements by name attr1642Dom.byName = byName;16431644// retrieve elements by class name1645Dom.byClass = byClass;16461647// read the value of the attribute1648// as was in the original HTML code1649Dom.getAttribute = getAttribute;16501651// check for the attribute presence1652// as was in the original HTML code1653Dom.hasAttribute = hasAttribute;16541655// element match selector, return boolean true/false1656Dom.match = match;16571658// first element match only, return element or null1659Dom.first = first;16601661// elements matching selector, starting from element1662Dom.select = select;16631664// compile selector into ad-hoc javascript resolver1665Dom.compile = compile;16661667// check that two elements are ancestor/descendant1668Dom.contains = contains;16691670// handle selector engine configuration settings1671Dom.configure = configure;16721673// initialize caching for each document1674Dom.setCache = FN;16751676// load previously collected result set1677Dom.loadResults = FN;16781679// save previously collected result set1680Dom.saveResults = FN;16811682// handle missing context in selector strings1683Dom.shortcuts = FN;16841685// log resolvers errors/warnings1686Dom.emit = emit;16871688// options enabing specific engine functionality1689Dom.Config = Config;16901691// pass methods references to compiled resolvers1692Dom.Snapshot = Snapshot;16931694// operators descriptor1695// for attribute operators extensions1696Dom.Operators = Operators;16971698// selectors descriptor1699// for pseudo-class selectors extensions1700Dom.Selectors = Selectors;17011702// export string patterns1703Dom.Tokens = Tokens;17041705// export version string1706Dom.Version = version;17071708// add or overwrite user defined operators1709Dom.registerOperator =1710function(symbol, resolver) {1711Operators[symbol] || (Operators[symbol] = resolver);1712};17131714// add selector patterns for user defined callbacks1715Dom.registerSelector =1716function(name, rexp, func) {1717Selectors[name] || (Selectors[name] = new global.Object({1718Expression: rexp,1719Callback: func1720}));1721};17221723/*---------------------------------- INIT ----------------------------------*/17241725// init context specific variables1726switchContext(doc, true);17271728});172917301731