Created
September 7, 2012 15:40
-
-
Save godmar/3667258 to your computer and use it in GitHub Desktop.
Updating sizzle for jsdom to github 20120907 version.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/lib/jsdom/selectors/sizzle.js b/lib/jsdom/selectors/sizzle.js | |
index f8c890c..5870d19 100755 | |
--- a/lib/jsdom/selectors/sizzle.js | |
+++ b/lib/jsdom/selectors/sizzle.js | |
@@ -1,982 +1,900 @@ | |
/*! | |
* Sizzle CSS Selector Engine | |
- * Copyright 2011, The Dojo Foundation | |
- * Released under the MIT, BSD, and GPL Licenses. | |
- * More information: http://sizzlejs.com/ | |
+ * Copyright 2012 jQuery Foundation and other contributors | |
+ * Released under the MIT license | |
+ * http://sizzlejs.com/ | |
*/ | |
// Patch for jsdom | |
-module.exports = function(document){ | |
+module.exports = function( document ) { | |
+ | |
+var dirruns, | |
+ cachedruns, | |
+ assertGetIdNotName, | |
+ Expr, | |
+ getText, | |
+ isXML, | |
+ contains, | |
+ compile, | |
+ sortOrder, | |
+ hasDuplicate, | |
-var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, | |
- expando = "sizcache" + (Math.random() + '').replace('.', ''), | |
- done = 0, | |
- toString = Object.prototype.toString, | |
- hasDuplicate = false, | |
baseHasDuplicate = true, | |
- rBackslash = /\\/g, | |
- rReturn = /\r\n/g, | |
- rNonWord = /\W/; | |
- | |
- | |
-// Here we check if the JavaScript engine is using some sort of | |
-// optimization where it does not always call our comparision | |
-// function. If that is the case, discard the hasDuplicate value. | |
-// Thus far that includes Google Chrome. | |
-[0, 0].sort(function() { | |
- baseHasDuplicate = false; | |
- return 0; | |
-}); | |
- | |
-var Sizzle = function( selector, context, results, seed ) { | |
- results = results || []; | |
- // PATCH for jsdom | |
- // context = context || document; | |
- // See: https://github.com/tmpvar/jsdom/issues/375 | |
- context = context || seed[0].ownerDocument; | |
- var origContext = context; | |
- | |
- if ( context.nodeType !== 1 && context.nodeType !== 9 ) { | |
- return []; | |
- } | |
- | |
- if ( !selector || typeof selector !== "string" ) { | |
- return results; | |
- } | |
- | |
- var m, set, checkSet, extra, ret, cur, pop, i, | |
- prune = true, | |
- contextXML = Sizzle.isXML( context ), | |
- parts = [], | |
- soFar = selector; | |
- | |
- // Reset the position of the chunker regexp (start from head) | |
- do { | |
- chunker.exec( "" ); | |
- m = chunker.exec( soFar ); | |
- | |
- if ( m ) { | |
- soFar = m[3]; | |
- | |
- parts.push( m[1] ); | |
- | |
- if ( m[2] ) { | |
- extra = m[3]; | |
- break; | |
- } | |
- } | |
- } while ( m ); | |
+ strundefined = "undefined", | |
- if ( parts.length > 1 && origPOS.exec( selector ) ) { | |
+ expando = ( "sizcache" + Math.random() ).replace( ".", "" ), | |
- if ( parts.length === 2 && Expr.relative[ parts[0] ] ) { | |
- set = posProcess( parts[0] + parts[1], context, seed ); | |
+ // jsdom document = window.document, | |
+ docElem = document.documentElement, | |
+ done = 0, | |
+ slice = [].slice, | |
+ push = [].push, | |
- } else { | |
- set = Expr.relative[ parts[0] ] ? | |
- [ context ] : | |
- Sizzle( parts.shift(), context ); | |
+ // Augment a function for special use by Sizzle | |
+ markFunction = function( fn, value ) { | |
+ fn[ expando ] = value || true; | |
+ return fn; | |
+ }, | |
- while ( parts.length ) { | |
- selector = parts.shift(); | |
+ createCache = function() { | |
+ var cache = {}, | |
+ keys = []; | |
- if ( Expr.relative[ selector ] ) { | |
- selector += parts.shift(); | |
- } | |
- | |
- set = posProcess( selector, set, seed ); | |
+ return markFunction(function( key, value ) { | |
+ // Only keep the most recent entries | |
+ if ( keys.push( key ) > Expr.cacheLength ) { | |
+ delete cache[ keys.shift() ]; | |
} | |
- } | |
- | |
- } else { | |
- // Take a shortcut and set the context if the root selector is an ID | |
- // (but not if it'll be faster if the inner selector is an ID) | |
- if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML && | |
- Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) { | |
- | |
- ret = Sizzle.find( parts.shift(), context, contextXML ); | |
- context = ret.expr ? | |
- Sizzle.filter( ret.expr, ret.set )[0] : | |
- ret.set[0]; | |
- } | |
- | |
- if ( context ) { | |
- ret = seed ? | |
- { expr: parts.pop(), set: makeArray(seed) } : | |
- Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML ); | |
- | |
- set = ret.expr ? | |
- Sizzle.filter( ret.expr, ret.set ) : | |
- ret.set; | |
- if ( parts.length > 0 ) { | |
- checkSet = makeArray( set ); | |
- | |
- } else { | |
- prune = false; | |
- } | |
+ return (cache[ key ] = value); | |
+ }, cache ); | |
+ }, | |
- while ( parts.length ) { | |
- cur = parts.pop(); | |
- pop = cur; | |
+ classCache = createCache(), | |
+ tokenCache = createCache(), | |
+ compilerCache = createCache(), | |
+ | |
+ // Regex | |
+ | |
+ // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace | |
+ whitespace = "[\\x20\\t\\r\\n\\f]", | |
+ // http://www.w3.org/TR/css3-syntax/#characters | |
+ characterEncoding = "(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+", | |
+ | |
+ // Loosely modeled on CSS identifier characters | |
+ // An unquoted value should be a CSS identifier (http://www.w3.org/TR/css3-selectors/#attribute-selectors) | |
+ // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier | |
+ identifier = characterEncoding.replace( "w", "w#" ), | |
+ | |
+ // Acceptable operators http://www.w3.org/TR/selectors/#attribute-selectors | |
+ operators = "([*^$|!~]?=)", | |
+ attributes = "\\[" + whitespace + "*(" + characterEncoding + ")" + whitespace + | |
+ "*(?:" + operators + whitespace + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier + ")|)|)" + whitespace + "*\\]", | |
+ | |
+ // Prefer arguments not in parens/brackets, | |
+ // then attribute selectors and non-pseudos (denoted by :), | |
+ // then anything else | |
+ // These preferences are here to reduce the number of selectors | |
+ // needing tokenize in the PSEUDO preFilter | |
+ pseudos = ":(" + characterEncoding + ")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|([^()[\\]]*|(?:(?:" + attributes + ")|[^:]|\\\\.)*|.*))\\)|)", | |
+ | |
+ // For matchExpr.POS and matchExpr.needsContext | |
+ pos = ":(nth|eq|gt|lt|first|last|even|odd)(?:\\(((?:-\\d)?\\d*)\\)|)(?=[^-]|$)", | |
+ | |
+ // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter | |
+ rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), | |
+ | |
+ rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), | |
+ rcombinators = new RegExp( "^" + whitespace + "*([\\x20\\t\\r\\n\\f>+~])" + whitespace + "*" ), | |
+ rpseudo = new RegExp( pseudos ), | |
+ | |
+ // Easily-parseable/retrievable ID or TAG or CLASS selectors | |
+ rquickExpr = /^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/, | |
+ | |
+ rnot = /^:not/, | |
+ rsibling = /[\x20\t\r\n\f]*[+~]/, | |
+ rendsWithNot = /:not\($/, | |
+ | |
+ rheader = /h\d/i, | |
+ rinputs = /input|select|textarea|button/i, | |
+ | |
+ rbackslash = /\\(?!\\)/g, | |
+ | |
+ matchExpr = { | |
+ "ID": new RegExp( "^#(" + characterEncoding + ")" ), | |
+ "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ), | |
+ "NAME": new RegExp( "^\\[name=['\"]?(" + characterEncoding + ")['\"]?\\]" ), | |
+ "TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ), | |
+ "ATTR": new RegExp( "^" + attributes ), | |
+ "PSEUDO": new RegExp( "^" + pseudos ), | |
+ "CHILD": new RegExp( "^:(only|nth|last|first)-child(?:\\(" + whitespace + | |
+ "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + | |
+ "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), | |
+ "POS": new RegExp( pos, "ig" ), | |
+ // For use in libraries implementing .is() | |
+ "needsContext": new RegExp( "^" + whitespace + "*[>+~]|" + pos, "i" ) | |
+ }, | |
- if ( !Expr.relative[ cur ] ) { | |
- cur = ""; | |
- } else { | |
- pop = parts.pop(); | |
- } | |
+ // Support | |
- if ( pop == null ) { | |
- pop = context; | |
- } | |
+ // Used for testing something on an element | |
+ assert = function( fn ) { | |
+ var div = document.createElement("div"); | |
- Expr.relative[ cur ]( checkSet, pop, contextXML ); | |
- } | |
- | |
- } else { | |
- checkSet = parts = []; | |
+ try { | |
+ return fn( div ); | |
+ } catch (e) { | |
+ return false; | |
+ } finally { | |
+ // release memory in IE | |
+ div = null; | |
} | |
- } | |
- | |
- if ( !checkSet ) { | |
- checkSet = set; | |
- } | |
- | |
- if ( !checkSet ) { | |
- Sizzle.error( cur || selector ); | |
- } | |
- | |
- if ( toString.call(checkSet) === "[object Array]" ) { | |
- if ( !prune ) { | |
- results.push.apply( results, checkSet ); | |
- | |
- } else if ( context && context.nodeType === 1 ) { | |
- for ( i = 0; checkSet[i] != null; i++ ) { | |
- if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && Sizzle.contains(context, checkSet[i])) ) { | |
- results.push( set[i] ); | |
- } | |
- } | |
+ }, | |
- } else { | |
- for ( i = 0; checkSet[i] != null; i++ ) { | |
- if ( checkSet[i] && checkSet[i].nodeType === 1 ) { | |
- results.push( set[i] ); | |
- } | |
- } | |
+ // Check if getElementsByTagName("*") returns only elements | |
+ assertTagNameNoComments = assert(function( div ) { | |
+ div.appendChild( document.createComment("") ); | |
+ return !div.getElementsByTagName("*").length; | |
+ }), | |
+ | |
+ // Check if getAttribute returns normalized href attributes | |
+ assertHrefNotNormalized = assert(function( div ) { | |
+ div.innerHTML = "<a href='#'></a>"; | |
+ return div.firstChild && typeof div.firstChild.getAttribute !== strundefined && | |
+ div.firstChild.getAttribute("href") === "#"; | |
+ }), | |
+ | |
+ // Check if attributes should be retrieved by attribute nodes | |
+ assertAttributes = assert(function( div ) { | |
+ div.innerHTML = "<select></select>"; | |
+ var type = typeof div.lastChild.getAttribute("multiple"); | |
+ // IE8 returns a string for some attributes even when not present | |
+ return type !== "boolean" && type !== "string"; | |
+ }), | |
+ | |
+ // Check if getElementsByClassName can be trusted | |
+ assertUsableClassName = assert(function( div ) { | |
+ // Opera can't find a second classname (in 9.6) | |
+ div.innerHTML = "<div class='hidden e'></div><div class='hidden'></div>"; | |
+ if ( !div.getElementsByClassName || !div.getElementsByClassName("e").length ) { | |
+ return false; | |
} | |
- } else { | |
- makeArray( checkSet, results ); | |
- } | |
- | |
- if ( extra ) { | |
- Sizzle( extra, origContext, results, seed ); | |
- Sizzle.uniqueSort( results ); | |
- } | |
- | |
- return results; | |
-}; | |
- | |
-Sizzle.uniqueSort = function( results ) { | |
- if ( sortOrder ) { | |
- hasDuplicate = baseHasDuplicate; | |
- results.sort( sortOrder ); | |
- | |
- if ( hasDuplicate ) { | |
- for ( var i = 1; i < results.length; i++ ) { | |
- if ( results[i] === results[ i - 1 ] ) { | |
- results.splice( i--, 1 ); | |
- } | |
- } | |
+ // Safari 3.2 caches class attributes and doesn't catch changes | |
+ div.lastChild.className = "e"; | |
+ return div.getElementsByClassName("e").length === 2; | |
+ }), | |
+ | |
+ // Check if getElementById returns elements by name | |
+ // Check if getElementsByName privileges form controls or returns elements by ID | |
+ assertUsableName = assert(function( div ) { | |
+ // Inject content | |
+ div.id = expando + 0; | |
+ div.innerHTML = "<a name='" + expando + "'></a><div name='" + expando + "'></div>"; | |
+ docElem.insertBefore( div, docElem.firstChild ); | |
+ | |
+ // Test | |
+ var pass = document.getElementsByName && | |
+ // buggy browsers will return fewer than the correct 2 | |
+ document.getElementsByName( expando ).length === 2 + | |
+ // buggy browsers will return more than the correct 0 | |
+ document.getElementsByName( expando + 0 ).length; | |
+ assertGetIdNotName = !document.getElementById( expando ); | |
+ | |
+ // Cleanup | |
+ docElem.removeChild( div ); | |
+ | |
+ return pass; | |
+ }); | |
+ | |
+// If slice is not available, provide a backup | |
+try { | |
+ slice.call( docElem.childNodes, 0 )[0].nodeType; | |
+} catch ( e ) { | |
+ slice = function( i ) { | |
+ var elem, results = []; | |
+ for ( ; (elem = this[i]); i++ ) { | |
+ results.push( elem ); | |
} | |
- } | |
- | |
- return results; | |
-}; | |
- | |
-Sizzle.matches = function( expr, set ) { | |
- return Sizzle( expr, null, null, set ); | |
-}; | |
- | |
-Sizzle.matchesSelector = function( node, expr ) { | |
- return Sizzle( expr, null, null, [node] ).length > 0; | |
-}; | |
+ return results; | |
+ }; | |
+} | |
-Sizzle.find = function( expr, context, isXML ) { | |
- var set, i, len, match, type, left; | |
+function Sizzle( selector, context, results, seed ) { | |
+ results = results || []; | |
+ // PATCH for jsdom | |
+ // context = context || document; | |
+ // See: https://github.com/tmpvar/jsdom/issues/375 | |
+ context = context || seed[0].ownerDocument; | |
+ var match, elem, xml, m, | |
+ nodeType = context.nodeType; | |
- if ( !expr ) { | |
+ if ( nodeType !== 1 && nodeType !== 9 ) { | |
return []; | |
} | |
- for ( i = 0, len = Expr.order.length; i < len; i++ ) { | |
- type = Expr.order[i]; | |
- | |
- if ( (match = Expr.leftMatch[ type ].exec( expr )) ) { | |
- left = match[1]; | |
- match.splice( 1, 1 ); | |
- | |
- if ( left.substr( left.length - 1 ) !== "\\" ) { | |
- match[1] = (match[1] || "").replace( rBackslash, "" ); | |
- set = Expr.find[ type ]( match, context, isXML ); | |
- | |
- if ( set != null ) { | |
- expr = expr.replace( Expr.match[ type ], "" ); | |
- break; | |
- } | |
- } | |
- } | |
- } | |
- | |
- if ( !set ) { | |
- set = typeof context.getElementsByTagName !== "undefined" ? | |
- context.getElementsByTagName( "*" ) : | |
- []; | |
+ if ( !selector || typeof selector !== "string" ) { | |
+ return results; | |
} | |
- return { set: set, expr: expr }; | |
-}; | |
- | |
-Sizzle.filter = function( expr, set, inplace, not ) { | |
- var match, anyFound, | |
- type, found, item, filter, left, | |
- i, pass, | |
- old = expr, | |
- result = [], | |
- curLoop = set, | |
- isXMLFilter = set && set[0] && Sizzle.isXML( set[0] ); | |
- | |
- while ( expr && set.length ) { | |
- for ( type in Expr.filter ) { | |
- if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) { | |
- filter = Expr.filter[ type ]; | |
- left = match[1]; | |
- | |
- anyFound = false; | |
- | |
- match.splice(1,1); | |
- | |
- if ( left.substr( left.length - 1 ) === "\\" ) { | |
- continue; | |
- } | |
- | |
- if ( curLoop === result ) { | |
- result = []; | |
- } | |
- | |
- if ( Expr.preFilter[ type ] ) { | |
- match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter ); | |
- | |
- if ( !match ) { | |
- anyFound = found = true; | |
- | |
- } else if ( match === true ) { | |
- continue; | |
- } | |
- } | |
- | |
- if ( match ) { | |
- for ( i = 0; (item = curLoop[i]) != null; i++ ) { | |
- if ( item ) { | |
- found = filter( item, match, i, curLoop ); | |
- pass = not ^ found; | |
- | |
- if ( inplace && found != null ) { | |
- if ( pass ) { | |
- anyFound = true; | |
- | |
- } else { | |
- curLoop[i] = false; | |
- } | |
- | |
- } else if ( pass ) { | |
- result.push( item ); | |
- anyFound = true; | |
- } | |
+ xml = isXML( context ); | |
+ | |
+ if ( !xml && !seed ) { | |
+ if ( (match = rquickExpr.exec( selector )) ) { | |
+ // Speed-up: Sizzle("#ID") | |
+ if ( (m = match[1]) ) { | |
+ if ( nodeType === 9 ) { | |
+ elem = context.getElementById( m ); | |
+ // Check parentNode to catch when Blackberry 4.6 returns | |
+ // nodes that are no longer in the document #6963 | |
+ if ( elem && elem.parentNode ) { | |
+ // Handle the case where IE, Opera, and Webkit return items | |
+ // by name instead of ID | |
+ if ( elem.id === m ) { | |
+ results.push( elem ); | |
+ return results; | |
} | |
+ } else { | |
+ return results; | |
} | |
- } | |
- | |
- if ( found !== undefined ) { | |
- if ( !inplace ) { | |
- curLoop = result; | |
- } | |
- | |
- expr = expr.replace( Expr.match[ type ], "" ); | |
- | |
- if ( !anyFound ) { | |
- return []; | |
+ } else { | |
+ // Context is not a document | |
+ if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) && | |
+ contains( context, elem ) && elem.id === m ) { | |
+ results.push( elem ); | |
+ return results; | |
} | |
- | |
- break; | |
} | |
- } | |
- } | |
- // Improper expression | |
- if ( expr === old ) { | |
- if ( anyFound == null ) { | |
- Sizzle.error( expr ); | |
+ // Speed-up: Sizzle("TAG") | |
+ } else if ( match[2] ) { | |
+ push.apply( results, slice.call(context.getElementsByTagName( selector ), 0) ); | |
+ return results; | |
- } else { | |
- break; | |
+ // Speed-up: Sizzle(".CLASS") | |
+ } else if ( (m = match[3]) && assertUsableClassName && context.getElementsByClassName ) { | |
+ push.apply( results, slice.call(context.getElementsByClassName( m ), 0) ); | |
+ return results; | |
} | |
} | |
- | |
- old = expr; | |
} | |
- return curLoop; | |
+ // All others | |
+ return select( selector, context, results, seed, xml ); | |
+} | |
+ | |
+Sizzle.matches = function( expr, elements ) { | |
+ return Sizzle( expr, null, null, elements ); | |
}; | |
-Sizzle.error = function( msg ) { | |
- throw new Error( "Syntax error, unrecognized expression: " + msg ); | |
+Sizzle.matchesSelector = function( elem, expr ) { | |
+ return Sizzle( expr, null, null, [ elem ] ).length > 0; | |
}; | |
+// Returns a function to use in pseudos for input types | |
+function createInputPseudo( type ) { | |
+ return function( elem ) { | |
+ var name = elem.nodeName.toLowerCase(); | |
+ return name === "input" && elem.type === type; | |
+ }; | |
+} | |
+ | |
+// Returns a function to use in pseudos for buttons | |
+function createButtonPseudo( type ) { | |
+ return function( elem ) { | |
+ var name = elem.nodeName.toLowerCase(); | |
+ return (name === "input" || name === "button") && elem.type === type; | |
+ }; | |
+} | |
+ | |
/** | |
- * Utility function for retreiving the text value of an array of DOM nodes | |
+ * Utility function for retrieving the text value of an array of DOM nodes | |
* @param {Array|Element} elem | |
*/ | |
-var getText = Sizzle.getText = function( elem ) { | |
- var i, node, | |
- nodeType = elem.nodeType, | |
- ret = ""; | |
+getText = Sizzle.getText = function( elem ) { | |
+ var node, | |
+ ret = "", | |
+ i = 0, | |
+ nodeType = elem.nodeType; | |
if ( nodeType ) { | |
if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { | |
- // Use textContent || innerText for elements | |
- if ( typeof elem.textContent === 'string' ) { | |
+ // Use textContent for elements | |
+ // innerText usage removed for consistency of new lines (see #11153) | |
+ if ( typeof elem.textContent === "string" ) { | |
return elem.textContent; | |
- } else if ( typeof elem.innerText === 'string' ) { | |
- // Replace IE's carriage returns | |
- return elem.innerText.replace( rReturn, '' ); | |
} else { | |
- // Traverse it's children | |
- for ( elem = elem.firstChild; elem; elem = elem.nextSibling) { | |
+ // Traverse its children | |
+ for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { | |
ret += getText( elem ); | |
} | |
} | |
} else if ( nodeType === 3 || nodeType === 4 ) { | |
return elem.nodeValue; | |
} | |
+ // Do not include comment or processing instruction nodes | |
} else { | |
// If no nodeType, this is expected to be an array | |
- for ( i = 0; (node = elem[i]); i++ ) { | |
+ for ( ; (node = elem[i]); i++ ) { | |
// Do not traverse comment nodes | |
- if ( node.nodeType !== 8 ) { | |
- ret += getText( node ); | |
- } | |
+ ret += getText( node ); | |
} | |
} | |
return ret; | |
}; | |
-var Expr = Sizzle.selectors = { | |
- order: [ "ID", "NAME", "TAG" ], | |
- | |
- match: { | |
- ID: /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/, | |
- CLASS: /\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/, | |
- NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/, | |
- ATTR: /\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/, | |
- TAG: /^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/, | |
- CHILD: /:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/, | |
- POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/, | |
- PSEUDO: /:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/ | |
- }, | |
- | |
- leftMatch: {}, | |
- | |
- attrMap: { | |
- "class": "className", | |
- "for": "htmlFor" | |
- }, | |
+isXML = Sizzle.isXML = function isXML( elem ) { | |
+ // documentElement is verified for cases where it doesn't yet exist | |
+ // (such as loading iframes in IE - #4833) | |
+ var documentElement = elem && (elem.ownerDocument || elem).documentElement; | |
+ return documentElement ? documentElement.nodeName !== "HTML" : false; | |
+}; | |
- attrHandle: { | |
- href: function( elem ) { | |
- return elem.getAttribute( "href" ); | |
- }, | |
- type: function( elem ) { | |
- return elem.getAttribute( "type" ); | |
+// Element contains another | |
+contains = Sizzle.contains = docElem.contains ? | |
+ function( a, b ) { | |
+ var adown = a.nodeType === 9 ? a.documentElement : a, | |
+ bup = b && b.parentNode; | |
+ return a === bup || !!( bup && bup.nodeType === 1 && adown.contains && adown.contains(bup) ); | |
+ } : | |
+ docElem.compareDocumentPosition ? | |
+ function( a, b ) { | |
+ return b && !!( a.compareDocumentPosition( b ) & 16 ); | |
+ } : | |
+ function( a, b ) { | |
+ while ( (b = b.parentNode) ) { | |
+ if ( b === a ) { | |
+ return true; | |
+ } | |
} | |
- }, | |
+ return false; | |
+ }; | |
- relative: { | |
- "+": function(checkSet, part){ | |
- var isPartStr = typeof part === "string", | |
- isTag = isPartStr && !rNonWord.test( part ), | |
- isPartStrNotTag = isPartStr && !isTag; | |
+Sizzle.attr = function( elem, name ) { | |
+ var attr, | |
+ xml = isXML( elem ); | |
- if ( isTag ) { | |
- part = part.toLowerCase(); | |
- } | |
+ if ( !xml ) { | |
+ name = name.toLowerCase(); | |
+ } | |
+ if ( Expr.attrHandle[ name ] ) { | |
+ return Expr.attrHandle[ name ]( elem ); | |
+ } | |
+ if ( assertAttributes || xml ) { | |
+ return elem.getAttribute( name ); | |
+ } | |
+ attr = elem.getAttributeNode( name ); | |
+ return attr ? | |
+ typeof elem[ name ] === "boolean" ? | |
+ elem[ name ] ? name : null : | |
+ attr.specified ? attr.value : null : | |
+ null; | |
+}; | |
- for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) { | |
- if ( (elem = checkSet[i]) ) { | |
- while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {} | |
+Expr = Sizzle.selectors = { | |
- checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ? | |
- elem || false : | |
- elem === part; | |
- } | |
- } | |
+ // Can be adjusted by the user | |
+ cacheLength: 50, | |
- if ( isPartStrNotTag ) { | |
- Sizzle.filter( part, checkSet, true ); | |
- } | |
- }, | |
+ createPseudo: markFunction, | |
- ">": function( checkSet, part ) { | |
- var elem, | |
- isPartStr = typeof part === "string", | |
- i = 0, | |
- l = checkSet.length; | |
+ match: matchExpr, | |
- if ( isPartStr && !rNonWord.test( part ) ) { | |
- part = part.toLowerCase(); | |
+ order: new RegExp( "ID|TAG" + | |
+ (assertUsableName ? "|NAME" : "") + | |
+ (assertUsableClassName ? "|CLASS" : "") | |
+ ), | |
- for ( ; i < l; i++ ) { | |
- elem = checkSet[i]; | |
+ // IE6/7 return a modified href | |
+ attrHandle: assertHrefNotNormalized ? | |
+ {} : | |
+ { | |
+ "href": function( elem ) { | |
+ return elem.getAttribute( "href", 2 ); | |
+ }, | |
+ "type": function( elem ) { | |
+ return elem.getAttribute("type"); | |
+ } | |
+ }, | |
- if ( elem ) { | |
- var parent = elem.parentNode; | |
- checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false; | |
- } | |
+ find: { | |
+ "ID": assertGetIdNotName ? | |
+ function( id, context, xml ) { | |
+ if ( typeof context.getElementById !== strundefined && !xml ) { | |
+ var m = context.getElementById( id ); | |
+ // Check parentNode to catch when Blackberry 4.6 returns | |
+ // nodes that are no longer in the document #6963 | |
+ return m && m.parentNode ? [m] : []; | |
} | |
- | |
- } else { | |
- for ( ; i < l; i++ ) { | |
- elem = checkSet[i]; | |
- | |
- if ( elem ) { | |
- checkSet[i] = isPartStr ? | |
- elem.parentNode : | |
- elem.parentNode === part; | |
- } | |
+ } : | |
+ function( id, context, xml ) { | |
+ if ( typeof context.getElementById !== strundefined && !xml ) { | |
+ var m = context.getElementById( id ); | |
+ | |
+ return m ? | |
+ m.id === id || typeof m.getAttributeNode !== strundefined && m.getAttributeNode("id").value === id ? | |
+ [m] : | |
+ undefined : | |
+ []; | |
} | |
+ }, | |
- if ( isPartStr ) { | |
- Sizzle.filter( part, checkSet, true ); | |
+ "TAG": assertTagNameNoComments ? | |
+ function( tag, context ) { | |
+ if ( typeof context.getElementsByTagName !== strundefined ) { | |
+ return context.getElementsByTagName( tag ); | |
} | |
- } | |
- }, | |
+ } : | |
+ function( tag, context ) { | |
+ var results = context.getElementsByTagName( tag ); | |
+ | |
+ // Filter out possible comments | |
+ if ( tag === "*" ) { | |
+ var elem, | |
+ tmp = [], | |
+ i = 0; | |
+ | |
+ for ( ; (elem = results[i]); i++ ) { | |
+ if ( elem.nodeType === 1 ) { | |
+ tmp.push( elem ); | |
+ } | |
+ } | |
- "": function(checkSet, part, isXML){ | |
- var nodeCheck, | |
- doneName = done++, | |
- checkFn = dirCheck; | |
+ return tmp; | |
+ } | |
+ return results; | |
+ }, | |
- if ( typeof part === "string" && !rNonWord.test( part ) ) { | |
- part = part.toLowerCase(); | |
- nodeCheck = part; | |
- checkFn = dirNodeCheck; | |
+ "NAME": function( tag, context ) { | |
+ if ( typeof context.getElementsByName !== strundefined ) { | |
+ return context.getElementsByName( name ); | |
} | |
- | |
- checkFn( "parentNode", part, doneName, checkSet, nodeCheck, isXML ); | |
}, | |
- "~": function( checkSet, part, isXML ) { | |
- var nodeCheck, | |
- doneName = done++, | |
- checkFn = dirCheck; | |
- | |
- if ( typeof part === "string" && !rNonWord.test( part ) ) { | |
- part = part.toLowerCase(); | |
- nodeCheck = part; | |
- checkFn = dirNodeCheck; | |
+ "CLASS": function( className, context, xml ) { | |
+ if ( typeof context.getElementsByClassName !== strundefined && !xml ) { | |
+ return context.getElementsByClassName( className ); | |
} | |
- | |
- checkFn( "previousSibling", part, doneName, checkSet, nodeCheck, isXML ); | |
} | |
}, | |
- find: { | |
- ID: function( match, context, isXML ) { | |
- if ( typeof context.getElementById !== "undefined" && !isXML ) { | |
- var m = context.getElementById(match[1]); | |
- // Check parentNode to catch when Blackberry 4.6 returns | |
- // nodes that are no longer in the document #6963 | |
- return m && m.parentNode ? [m] : []; | |
- } | |
- }, | |
- | |
- NAME: function( match, context ) { | |
- if ( typeof context.getElementsByName !== "undefined" ) { | |
- var ret = [], | |
- results = context.getElementsByName( match[1] ); | |
- | |
- for ( var i = 0, l = results.length; i < l; i++ ) { | |
- if ( results[i].getAttribute("name") === match[1] ) { | |
- ret.push( results[i] ); | |
- } | |
- } | |
- | |
- return ret.length === 0 ? null : ret; | |
- } | |
- }, | |
- | |
- TAG: function( match, context ) { | |
- if ( typeof context.getElementsByTagName !== "undefined" ) { | |
- return context.getElementsByTagName( match[1] ); | |
- } | |
- } | |
+ relative: { | |
+ ">": { dir: "parentNode", first: true }, | |
+ " ": { dir: "parentNode" }, | |
+ "+": { dir: "previousSibling", first: true }, | |
+ "~": { dir: "previousSibling" } | |
}, | |
- preFilter: { | |
- CLASS: function( match, curLoop, inplace, result, not, isXML ) { | |
- match = " " + match[1].replace( rBackslash, "" ) + " "; | |
- if ( isXML ) { | |
- return match; | |
- } | |
+ preFilter: { | |
+ "ATTR": function( match ) { | |
+ match[1] = match[1].replace( rbackslash, "" ); | |
- for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) { | |
- if ( elem ) { | |
- if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n\r]/g, " ").indexOf(match) >= 0) ) { | |
- if ( !inplace ) { | |
- result.push( elem ); | |
- } | |
+ // Move the given value to match[3] whether quoted or unquoted | |
+ match[3] = ( match[4] || match[5] || "" ).replace( rbackslash, "" ); | |
- } else if ( inplace ) { | |
- curLoop[i] = false; | |
- } | |
- } | |
+ if ( match[2] === "~=" ) { | |
+ match[3] = " " + match[3] + " "; | |
} | |
- return false; | |
+ return match.slice( 0, 4 ); | |
}, | |
- ID: function( match ) { | |
- return match[1].replace( rBackslash, "" ); | |
- }, | |
+ "CHILD": function( match ) { | |
+ /* matches from matchExpr.CHILD | |
+ 1 type (only|nth|...) | |
+ 2 argument (even|odd|\d*|\d*n([+-]\d+)?|...) | |
+ 3 xn-component of xn+y argument ([+-]?\d*n|) | |
+ 4 sign of xn-component | |
+ 5 x of xn-component | |
+ 6 sign of y-component | |
+ 7 y of y-component | |
+ */ | |
+ match[1] = match[1].toLowerCase(); | |
- TAG: function( match, curLoop ) { | |
- return match[1].replace( rBackslash, "" ).toLowerCase(); | |
- }, | |
- | |
- CHILD: function( match ) { | |
if ( match[1] === "nth" ) { | |
+ // nth-child requires argument | |
if ( !match[2] ) { | |
Sizzle.error( match[0] ); | |
} | |
- match[2] = match[2].replace(/^\+|\s*/g, ''); | |
- | |
- // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6' | |
- var test = /(-?)(\d*)(?:n([+\-]?\d*))?/.exec( | |
- match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" || | |
- !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]); | |
+ // numeric x and y parameters for Expr.filter.CHILD | |
+ // remember that false/true cast respectively to 0/1 | |
+ match[3] = +( match[3] ? match[4] + (match[5] || 1) : 2 * ( match[2] === "even" || match[2] === "odd" ) ); | |
+ match[4] = +( ( match[6] + match[7] ) || match[2] === "odd" ); | |
- // calculate the numbers (first)n+(last) including if they are negative | |
- match[2] = (test[1] + (test[2] || 1)) - 0; | |
- match[3] = test[3] - 0; | |
- } | |
- else if ( match[2] ) { | |
+ // other types prohibit arguments | |
+ } else if ( match[2] ) { | |
Sizzle.error( match[0] ); | |
} | |
- // TODO: Move to normal caching system | |
- match[0] = done++; | |
- | |
return match; | |
}, | |
- ATTR: function( match, curLoop, inplace, result, not, isXML ) { | |
- var name = match[1] = match[1].replace( rBackslash, "" ); | |
+ "PSEUDO": function( match, context, xml ) { | |
+ var unquoted, excess; | |
+ if ( matchExpr["CHILD"].test( match[0] ) ) { | |
+ return null; | |
+ } | |
- if ( !isXML && Expr.attrMap[name] ) { | |
- match[1] = Expr.attrMap[name]; | |
+ if ( match[3] ) { | |
+ match[2] = match[3]; | |
+ } else if ( (unquoted = match[4]) ) { | |
+ // Only check arguments that contain a pseudo | |
+ if ( rpseudo.test(unquoted) && | |
+ // Get excess from tokenize (recursively) | |
+ (excess = tokenize( unquoted, context, xml, true )) && | |
+ // advance to the next closing parenthesis | |
+ (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) { | |
+ | |
+ // excess is a negative index | |
+ unquoted = unquoted.slice( 0, excess ); | |
+ match[0] = match[0].slice( 0, excess ); | |
+ } | |
+ match[2] = unquoted; | |
} | |
- // Handle if an un-quoted value was used | |
- match[4] = ( match[4] || match[5] || "" ).replace( rBackslash, "" ); | |
+ // Return only captures needed by the pseudo filter method (type and argument) | |
+ return match.slice( 0, 3 ); | |
+ } | |
+ }, | |
- if ( match[2] === "~=" ) { | |
- match[4] = " " + match[4] + " "; | |
+ filter: { | |
+ "ID": assertGetIdNotName ? | |
+ function( id ) { | |
+ id = id.replace( rbackslash, "" ); | |
+ return function( elem ) { | |
+ return elem.getAttribute("id") === id; | |
+ }; | |
+ } : | |
+ function( id ) { | |
+ id = id.replace( rbackslash, "" ); | |
+ return function( elem ) { | |
+ var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id"); | |
+ return node && node.value === id; | |
+ }; | |
+ }, | |
+ | |
+ "TAG": function( nodeName ) { | |
+ if ( nodeName === "*" ) { | |
+ return function() { return true; }; | |
} | |
+ nodeName = nodeName.replace( rbackslash, "" ).toLowerCase(); | |
- return match; | |
+ return function( elem ) { | |
+ return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; | |
+ }; | |
}, | |
- PSEUDO: function( match, curLoop, inplace, result, not ) { | |
- if ( match[1] === "not" ) { | |
- // If we're dealing with a complex expression, or a simple one | |
- if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) { | |
- match[3] = Sizzle(match[3], null, null, curLoop); | |
+ "CLASS": function( className ) { | |
+ var pattern = classCache[ expando ][ className ]; | |
+ if ( !pattern ) { | |
+ pattern = classCache( className, new RegExp("(^|" + whitespace + ")" + className + "(" + whitespace + "|$)") ); | |
+ } | |
+ return function( elem ) { | |
+ return pattern.test( elem.className || (typeof elem.getAttribute !== strundefined && elem.getAttribute("class")) || "" ); | |
+ }; | |
+ }, | |
- } else { | |
- var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not); | |
+ "ATTR": function( name, operator, check ) { | |
+ if ( !operator ) { | |
+ return function( elem ) { | |
+ return Sizzle.attr( elem, name ) != null; | |
+ }; | |
+ } | |
- if ( !inplace ) { | |
- result.push.apply( result, ret ); | |
- } | |
+ return function( elem ) { | |
+ var result = Sizzle.attr( elem, name ), | |
+ value = result + ""; | |
- return false; | |
+ if ( result == null ) { | |
+ return operator === "!="; | |
} | |
- } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) { | |
- return true; | |
- } | |
- | |
- return match; | |
+ switch ( operator ) { | |
+ case "=": | |
+ return value === check; | |
+ case "!=": | |
+ return value !== check; | |
+ case "^=": | |
+ return check && value.indexOf( check ) === 0; | |
+ case "*=": | |
+ return check && value.indexOf( check ) > -1; | |
+ case "$=": | |
+ return check && value.substr( value.length - check.length ) === check; | |
+ case "~=": | |
+ return ( " " + value + " " ).indexOf( check ) > -1; | |
+ case "|=": | |
+ return value === check || value.substr( 0, check.length + 1 ) === check + "-"; | |
+ } | |
+ }; | |
}, | |
- POS: function( match ) { | |
- match.unshift( true ); | |
+ "CHILD": function( type, argument, first, last ) { | |
- return match; | |
- } | |
- }, | |
+ if ( type === "nth" ) { | |
+ var doneName = done++; | |
- filters: { | |
- enabled: function( elem ) { | |
- return elem.disabled === false && elem.type !== "hidden"; | |
- }, | |
+ return function( elem ) { | |
+ var parent, diff, | |
+ count = 0, | |
+ node = elem; | |
- disabled: function( elem ) { | |
- return elem.disabled === true; | |
- }, | |
- | |
- checked: function( elem ) { | |
- return elem.checked === true; | |
- }, | |
- | |
- selected: function( elem ) { | |
- // Accessing this property makes selected-by-default | |
- // options in Safari work properly | |
- if ( elem.parentNode ) { | |
- elem.parentNode.selectedIndex; | |
- } | |
+ if ( first === 1 && last === 0 ) { | |
+ return true; | |
+ } | |
- return elem.selected === true; | |
- }, | |
+ parent = elem.parentNode; | |
- parent: function( elem ) { | |
- return !!elem.firstChild; | |
- }, | |
+ if ( parent && (parent[ expando ] !== doneName || !elem.sizset) ) { | |
+ for ( node = parent.firstChild; node; node = node.nextSibling ) { | |
+ if ( node.nodeType === 1 ) { | |
+ node.sizset = ++count; | |
+ if ( node === elem ) { | |
+ break; | |
+ } | |
+ } | |
+ } | |
- empty: function( elem ) { | |
- return !elem.firstChild; | |
- }, | |
+ parent[ expando ] = doneName; | |
+ } | |
- has: function( elem, i, match ) { | |
- return !!Sizzle( match[3], elem ).length; | |
- }, | |
+ diff = elem.sizset - last; | |
- header: function( elem ) { | |
- return (/h\d/i).test( elem.nodeName ); | |
- }, | |
+ if ( first === 0 ) { | |
+ return diff === 0; | |
- text: function( elem ) { | |
- var attr = elem.getAttribute( "type" ), type = elem.type; | |
- // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) | |
- // use getAttribute instead to test this case | |
- return elem.nodeName.toLowerCase() === "input" && "text" === type && ( attr === type || attr === null ); | |
- }, | |
+ } else { | |
+ return ( diff % first === 0 && diff / first >= 0 ); | |
+ } | |
+ }; | |
+ } | |
- radio: function( elem ) { | |
- return elem.nodeName.toLowerCase() === "input" && "radio" === elem.type; | |
- }, | |
+ return function( elem ) { | |
+ var node = elem; | |
- checkbox: function( elem ) { | |
- return elem.nodeName.toLowerCase() === "input" && "checkbox" === elem.type; | |
- }, | |
+ switch ( type ) { | |
+ case "only": | |
+ case "first": | |
+ while ( (node = node.previousSibling) ) { | |
+ if ( node.nodeType === 1 ) { | |
+ return false; | |
+ } | |
+ } | |
- file: function( elem ) { | |
- return elem.nodeName.toLowerCase() === "input" && "file" === elem.type; | |
- }, | |
+ if ( type === "first" ) { | |
+ return true; | |
+ } | |
- password: function( elem ) { | |
- return elem.nodeName.toLowerCase() === "input" && "password" === elem.type; | |
- }, | |
+ node = elem; | |
- submit: function( elem ) { | |
- var name = elem.nodeName.toLowerCase(); | |
- return (name === "input" || name === "button") && "submit" === elem.type; | |
- }, | |
+ /* falls through */ | |
+ case "last": | |
+ while ( (node = node.nextSibling) ) { | |
+ if ( node.nodeType === 1 ) { | |
+ return false; | |
+ } | |
+ } | |
- image: function( elem ) { | |
- return elem.nodeName.toLowerCase() === "input" && "image" === elem.type; | |
+ return true; | |
+ } | |
+ }; | |
}, | |
- reset: function( elem ) { | |
- var name = elem.nodeName.toLowerCase(); | |
- return (name === "input" || name === "button") && "reset" === elem.type; | |
- }, | |
+ "PSEUDO": function( pseudo, argument, context, xml ) { | |
+ // pseudo-class names are case-insensitive | |
+ // http://www.w3.org/TR/selectors/#pseudo-classes | |
+ // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters | |
+ var args, | |
+ fn = Expr.pseudos[ pseudo ] || Expr.pseudos[ pseudo.toLowerCase() ]; | |
- button: function( elem ) { | |
- var name = elem.nodeName.toLowerCase(); | |
- return name === "input" && "button" === elem.type || name === "button"; | |
- }, | |
+ if ( !fn ) { | |
+ Sizzle.error( "unsupported pseudo: " + pseudo ); | |
+ } | |
- input: function( elem ) { | |
- return (/input|select|textarea|button/i).test( elem.nodeName ); | |
- }, | |
+ // The user may use createPseudo to indicate that | |
+ // arguments are needed to create the filter function | |
+ // just as Sizzle does | |
+ if ( !fn[ expando ] ) { | |
+ if ( fn.length > 1 ) { | |
+ args = [ pseudo, pseudo, "", argument ]; | |
+ return function( elem ) { | |
+ return fn( elem, 0, args ); | |
+ }; | |
+ } | |
+ return fn; | |
+ } | |
- focus: function( elem ) { | |
- return elem === elem.ownerDocument.activeElement; | |
+ return fn( argument, context, xml ); | |
} | |
}, | |
- setFilters: { | |
- first: function( elem, i ) { | |
- return i === 0; | |
- }, | |
- last: function( elem, i, match, array ) { | |
- return i === array.length - 1; | |
+ pseudos: { | |
+ "not": markFunction(function( selector, context, xml ) { | |
+ // Trim the selector passed to compile | |
+ // to avoid treating leading and trailing | |
+ // spaces as combinators | |
+ var matcher = compile( selector.replace( rtrim, "$1" ), context, xml ); | |
+ return function( elem ) { | |
+ return !matcher( elem ); | |
+ }; | |
+ }), | |
+ | |
+ "enabled": function( elem ) { | |
+ return elem.disabled === false; | |
}, | |
- even: function( elem, i ) { | |
- return i % 2 === 0; | |
+ "disabled": function( elem ) { | |
+ return elem.disabled === true; | |
}, | |
- odd: function( elem, i ) { | |
- return i % 2 === 1; | |
+ "checked": function( elem ) { | |
+ // In CSS3, :checked should return both checked and selected elements | |
+ // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked | |
+ var nodeName = elem.nodeName.toLowerCase(); | |
+ return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); | |
}, | |
- lt: function( elem, i, match ) { | |
- return i < match[3] - 0; | |
- }, | |
+ "selected": function( elem ) { | |
+ // Accessing this property makes selected-by-default | |
+ // options in Safari work properly | |
+ if ( elem.parentNode ) { | |
+ elem.parentNode.selectedIndex; | |
+ } | |
- gt: function( elem, i, match ) { | |
- return i > match[3] - 0; | |
+ return elem.selected === true; | |
}, | |
- nth: function( elem, i, match ) { | |
- return match[3] - 0 === i; | |
+ "parent": function( elem ) { | |
+ return !Expr.pseudos["empty"]( elem ); | |
}, | |
- eq: function( elem, i, match ) { | |
- return match[3] - 0 === i; | |
- } | |
- }, | |
- filter: { | |
- PSEUDO: function( elem, match, i, array ) { | |
- var name = match[1], | |
- filter = Expr.filters[ name ]; | |
- | |
- if ( filter ) { | |
- return filter( elem, i, match, array ); | |
- | |
- } else if ( name === "contains" ) { | |
- return (elem.textContent || elem.innerText || getText([ elem ]) || "").indexOf(match[3]) >= 0; | |
- | |
- } else if ( name === "not" ) { | |
- var not = match[3]; | |
- | |
- for ( var j = 0, l = not.length; j < l; j++ ) { | |
- if ( not[j] === elem ) { | |
- return false; | |
- } | |
+ "empty": function( elem ) { | |
+ // http://www.w3.org/TR/selectors/#empty-pseudo | |
+ // :empty is only affected by element nodes and content nodes(including text(3), cdata(4)), | |
+ // not comment, processing instructions, or others | |
+ // Thanks to Diego Perini for the nodeName shortcut | |
+ // Greater than "@" means alpha characters (specifically not starting with "#" or "?") | |
+ var nodeType; | |
+ elem = elem.firstChild; | |
+ while ( elem ) { | |
+ if ( elem.nodeName > "@" || (nodeType = elem.nodeType) === 3 || nodeType === 4 ) { | |
+ return false; | |
} | |
- | |
- return true; | |
- | |
- } else { | |
- Sizzle.error( name ); | |
+ elem = elem.nextSibling; | |
} | |
+ return true; | |
}, | |
- CHILD: function( elem, match ) { | |
- var first, last, | |
- doneName, parent, cache, | |
- count, diff, | |
- type = match[1], | |
- node = elem; | |
- | |
- switch ( type ) { | |
- case "only": | |
- case "first": | |
- while ( (node = node.previousSibling) ) { | |
- if ( node.nodeType === 1 ) { | |
- return false; | |
- } | |
- } | |
- | |
- if ( type === "first" ) { | |
- return true; | |
- } | |
- | |
- node = elem; | |
- | |
- /* falls through */ | |
- case "last": | |
- while ( (node = node.nextSibling) ) { | |
- if ( node.nodeType === 1 ) { | |
- return false; | |
- } | |
- } | |
- | |
- return true; | |
- | |
- case "nth": | |
- first = match[2]; | |
- last = match[3]; | |
- | |
- if ( first === 1 && last === 0 ) { | |
- return true; | |
- } | |
- | |
- doneName = match[0]; | |
- parent = elem.parentNode; | |
- | |
- if ( parent && (parent[ expando ] !== doneName || !elem.nodeIndex) ) { | |
- count = 0; | |
- | |
- for ( node = parent.firstChild; node; node = node.nextSibling ) { | |
- if ( node.nodeType === 1 ) { | |
- node.nodeIndex = ++count; | |
- } | |
- } | |
- | |
- parent[ expando ] = doneName; | |
- } | |
+ "contains": markFunction(function( text ) { | |
+ return function( elem ) { | |
+ return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; | |
+ }; | |
+ }), | |
- diff = elem.nodeIndex - last; | |
+ "has": markFunction(function( selector ) { | |
+ return function( elem ) { | |
+ return Sizzle( selector, elem ).length > 0; | |
+ }; | |
+ }), | |
- if ( first === 0 ) { | |
- return diff === 0; | |
+ "header": function( elem ) { | |
+ return rheader.test( elem.nodeName ); | |
+ }, | |
- } else { | |
- return ( diff % first === 0 && diff / first >= 0 ); | |
- } | |
- } | |
+ "text": function( elem ) { | |
+ var type, attr; | |
+ // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) | |
+ // use getAttribute instead to test this case | |
+ return elem.nodeName.toLowerCase() === "input" && | |
+ (type = elem.type) === "text" && | |
+ ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === type ); | |
}, | |
- ID: function( elem, match ) { | |
- return elem.nodeType === 1 && elem.getAttribute("id") === match; | |
+ // Input types | |
+ "radio": createInputPseudo("radio"), | |
+ "checkbox": createInputPseudo("checkbox"), | |
+ "file": createInputPseudo("file"), | |
+ "password": createInputPseudo("password"), | |
+ "image": createInputPseudo("image"), | |
+ | |
+ "submit": createButtonPseudo("submit"), | |
+ "reset": createButtonPseudo("reset"), | |
+ | |
+ "button": function( elem ) { | |
+ var name = elem.nodeName.toLowerCase(); | |
+ return name === "input" && elem.type === "button" || name === "button"; | |
}, | |
- TAG: function( elem, match ) { | |
- return (match === "*" && elem.nodeType === 1) || !!elem.nodeName && elem.nodeName.toLowerCase() === match; | |
+ "input": function( elem ) { | |
+ return rinputs.test( elem.nodeName ); | |
}, | |
- CLASS: function( elem, match ) { | |
- return (" " + (elem.className || elem.getAttribute("class")) + " ") | |
- .indexOf( match ) > -1; | |
+ "focus": function( elem ) { | |
+ var doc = elem.ownerDocument; | |
+ return elem === doc.activeElement && (!doc.hasFocus || doc.hasFocus()) && !!(elem.type || elem.href); | |
}, | |
- ATTR: function( elem, match ) { | |
- var name = match[1], | |
- result = Sizzle.attr ? | |
- Sizzle.attr( elem, name ) : | |
- Expr.attrHandle[ name ] ? | |
- Expr.attrHandle[ name ]( elem ) : | |
- elem[ name ] != null ? | |
- elem[ name ] : | |
- elem.getAttribute( name ), | |
- value = result + "", | |
- type = match[2], | |
- check = match[4]; | |
- | |
- return result == null ? | |
- type === "!=" : | |
- !type && Sizzle.attr ? | |
- result != null : | |
- type === "=" ? | |
- value === check : | |
- type === "*=" ? | |
- value.indexOf(check) >= 0 : | |
- type === "~=" ? | |
- (" " + value + " ").indexOf(check) >= 0 : | |
- !check ? | |
- value && result !== false : | |
- type === "!=" ? | |
- value !== check : | |
- type === "^=" ? | |
- value.indexOf(check) === 0 : | |
- type === "$=" ? | |
- value.substr(value.length - check.length) === check : | |
- type === "|=" ? | |
- value === check || value.substr(0, check.length + 1) === check + "-" : | |
- false; | |
+ "active": function( elem ) { | |
+ return elem === elem.ownerDocument.activeElement; | |
+ } | |
+ }, | |
+ | |
+ setFilters: { | |
+ "first": function( elements, argument, not ) { | |
+ return not ? elements.slice( 1 ) : [ elements[0] ]; | |
}, | |
- POS: function( elem, match, i, array ) { | |
- var name = match[2], | |
- filter = Expr.setFilters[ name ]; | |
+ "last": function( elements, argument, not ) { | |
+ var elem = elements.pop(); | |
+ return not ? elements : [ elem ]; | |
+ }, | |
- if ( filter ) { | |
- return filter( elem, i, match, array ); | |
+ "even": function( elements, argument, not ) { | |
+ var results = [], | |
+ i = not ? 1 : 0, | |
+ len = elements.length; | |
+ for ( ; i < len; i = i + 2 ) { | |
+ results.push( elements[i] ); | |
} | |
- } | |
- } | |
-}; | |
+ return results; | |
+ }, | |
-var origPOS = Expr.match.POS, | |
- fescape = function(all, num){ | |
- return "\\" + (num - 0 + 1); | |
- }; | |
+ "odd": function( elements, argument, not ) { | |
+ var results = [], | |
+ i = not ? 0 : 1, | |
+ len = elements.length; | |
+ for ( ; i < len; i = i + 2 ) { | |
+ results.push( elements[i] ); | |
+ } | |
+ return results; | |
+ }, | |
-for ( var type in Expr.match ) { | |
- Expr.match[ type ] = new RegExp( Expr.match[ type ].source + (/(?![^\[]*\])(?![^\(]*\))/.source) ); | |
- Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, fescape) ); | |
-} | |
-// Expose origPOS | |
-// "global" as in regardless of relation to brackets/parens | |
-Expr.match.globalPOS = origPOS; | |
+ "lt": function( elements, argument, not ) { | |
+ return not ? elements.slice( +argument ) : elements.slice( 0, +argument ); | |
+ }, | |
-var makeArray = function( array, results ) { | |
- array = Array.prototype.slice.call( array, 0 ); | |
+ "gt": function( elements, argument, not ) { | |
+ return not ? elements.slice( 0, +argument + 1 ) : elements.slice( +argument + 1 ); | |
+ }, | |
- if ( results ) { | |
- results.push.apply( results, array ); | |
- return results; | |
+ "eq": function( elements, argument, not ) { | |
+ var elem = elements.splice( +argument, 1 ); | |
+ return not ? elements : elem; | |
+ } | |
} | |
- | |
- return array; | |
}; | |
-// Perform a simple check to determine if the browser is capable of | |
-// converting a NodeList to an array using builtin methods. | |
-// Also verifies that the returned array holds DOM nodes | |
-// (which is not the case in the Blackberry browser) | |
-try { | |
- Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType; | |
- | |
-// Provide a fallback method if it does not work | |
-} catch( e ) { | |
- makeArray = function( array, results ) { | |
- var i = 0, | |
- ret = results || []; | |
- | |
- if ( toString.call(array) === "[object Array]" ) { | |
- Array.prototype.push.apply( ret, array ); | |
+function siblingCheck( a, b, ret ) { | |
+ if ( a === b ) { | |
+ return ret; | |
+ } | |
- } else { | |
- if ( typeof array.length === "number" ) { | |
- for ( var l = array.length; i < l; i++ ) { | |
- ret.push( array[i] ); | |
- } | |
+ var cur = a.nextSibling; | |
- } else { | |
- for ( ; array[i]; i++ ) { | |
- ret.push( array[i] ); | |
- } | |
- } | |
+ while ( cur ) { | |
+ if ( cur === b ) { | |
+ return -1; | |
} | |
- return ret; | |
- }; | |
-} | |
+ cur = cur.nextSibling; | |
+ } | |
-var sortOrder, siblingCheck; | |
+ return 1; | |
+} | |
-if ( document.documentElement.compareDocumentPosition ) { | |
- sortOrder = function( a, b ) { | |
+sortOrder = docElem.compareDocumentPosition ? | |
+ function( a, b ) { | |
if ( a === b ) { | |
hasDuplicate = true; | |
return 0; | |
} | |
- if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) { | |
- return a.compareDocumentPosition ? -1 : 1; | |
- } | |
- | |
- return a.compareDocumentPosition(b) & 4 ? -1 : 1; | |
- }; | |
- | |
-} else { | |
- sortOrder = function( a, b ) { | |
+ return ( !a.compareDocumentPosition || !b.compareDocumentPosition ? | |
+ a.compareDocumentPosition : | |
+ a.compareDocumentPosition(b) & 4 | |
+ ) ? -1 : 1; | |
+ } : | |
+ function( a, b ) { | |
// The nodes are identical, we can exit early | |
if ( a === b ) { | |
hasDuplicate = true; | |
@@ -1036,414 +954,592 @@ if ( document.documentElement.compareDocumentPosition ) { | |
siblingCheck( ap[i], b, 1 ); | |
}; | |
- siblingCheck = function( a, b, ret ) { | |
- if ( a === b ) { | |
- return ret; | |
- } | |
+// Always assume the presence of duplicates if sort doesn't | |
+// pass them to our comparison function (as in Google Chrome). | |
+[0, 0].sort( sortOrder ); | |
+baseHasDuplicate = !hasDuplicate; | |
- var cur = a.nextSibling; | |
+// Document sorting and removing duplicates | |
+Sizzle.uniqueSort = function( results ) { | |
+ var elem, | |
+ i = 1; | |
- while ( cur ) { | |
- if ( cur === b ) { | |
- return -1; | |
- } | |
+ hasDuplicate = baseHasDuplicate; | |
+ results.sort( sortOrder ); | |
- cur = cur.nextSibling; | |
+ if ( hasDuplicate ) { | |
+ for ( ; (elem = results[i]); i++ ) { | |
+ if ( elem === results[ i - 1 ] ) { | |
+ results.splice( i--, 1 ); | |
+ } | |
} | |
+ } | |
- return 1; | |
- }; | |
-} | |
- | |
-// Check to see if the browser returns elements by name when | |
-// querying by getElementById (and provide a workaround) | |
-(function(){ | |
- // We're going to inject a fake input element with a specified name | |
- var form = document.createElement("div"), | |
- id = "script" + (new Date()).getTime(), | |
- root = document.documentElement; | |
- | |
- form.innerHTML = "<a name='" + id + "'/>"; | |
- | |
- // Inject it into the root element, check its status, and remove it quickly | |
- root.insertBefore( form, root.firstChild ); | |
- | |
- // The workaround has to do additional checks after a getElementById | |
- // Which slows things down for other browsers (hence the branching) | |
- if ( document.getElementById( id ) ) { | |
- Expr.find.ID = function( match, context, isXML ) { | |
- if ( typeof context.getElementById !== "undefined" && !isXML ) { | |
- var m = context.getElementById(match[1]); | |
- | |
- return m ? | |
- m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? | |
- [m] : | |
- undefined : | |
- []; | |
- } | |
- }; | |
+ return results; | |
+}; | |
- Expr.filter.ID = function( elem, match ) { | |
- var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id"); | |
+Sizzle.error = function( msg ) { | |
+ throw new Error( "Syntax error, unrecognized expression: " + msg ); | |
+}; | |
- return elem.nodeType === 1 && node && node.nodeValue === match; | |
- }; | |
+function tokenize( selector, context, xml, parseOnly ) { | |
+ var matched, match, tokens, type, | |
+ soFar, groups, group, i, | |
+ preFilters, filters, | |
+ checkContext = !xml && context !== document, | |
+ // Token cache should maintain spaces | |
+ key = ( checkContext ? "<s>" : "" ) + selector.replace( rtrim, "$1<s>" ), | |
+ cached = tokenCache[ expando ][ key ]; | |
+ | |
+ if ( cached ) { | |
+ return parseOnly ? 0 : slice.call( cached, 0 ); | |
} | |
- root.removeChild( form ); | |
+ soFar = selector; | |
+ groups = []; | |
+ i = 0; | |
+ preFilters = Expr.preFilter; | |
+ filters = Expr.filter; | |
- // release memory in IE | |
- root = form = null; | |
-})(); | |
+ while ( soFar ) { | |
-(function(){ | |
- // Check to see if the browser returns only elements | |
- // when doing getElementsByTagName("*") | |
+ // Comma and first run | |
+ if ( !matched || (match = rcomma.exec( soFar )) ) { | |
+ if ( match ) { | |
+ soFar = soFar.slice( match[0].length ); | |
+ tokens.selector = group; | |
+ } | |
+ groups.push( tokens = [] ); | |
+ group = ""; | |
- // Create a fake element | |
- var div = document.createElement("div"); | |
- div.appendChild( document.createComment("") ); | |
+ // Need to make sure we're within a narrower context if necessary | |
+ // Adding a descendant combinator will generate what is needed | |
+ if ( checkContext ) { | |
+ soFar = " " + soFar; | |
+ } | |
+ } | |
- // Make sure no comments are found | |
- if ( div.getElementsByTagName("*").length > 0 ) { | |
- Expr.find.TAG = function( match, context ) { | |
- var results = context.getElementsByTagName( match[1] ); | |
+ matched = false; | |
- // Filter out possible comments | |
- if ( match[1] === "*" ) { | |
- var tmp = []; | |
+ // Combinators | |
+ if ( (match = rcombinators.exec( soFar )) ) { | |
+ group += match[0]; | |
+ soFar = soFar.slice( match[0].length ); | |
- for ( var i = 0; results[i]; i++ ) { | |
- if ( results[i].nodeType === 1 ) { | |
- tmp.push( results[i] ); | |
- } | |
- } | |
+ // Cast descendant combinators to space | |
+ matched = tokens.push({ | |
+ part: match.pop().replace( rtrim, " " ), | |
+ string: match[0], | |
+ captures: match | |
+ }); | |
+ } | |
- results = tmp; | |
+ // Filters | |
+ for ( type in filters ) { | |
+ if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || | |
+ ( match = preFilters[ type ](match, context, xml) )) ) { | |
+ | |
+ group += match[0]; | |
+ soFar = soFar.slice( match[0].length ); | |
+ matched = tokens.push({ | |
+ part: type, | |
+ string: match.shift(), | |
+ captures: match | |
+ }); | |
} | |
+ } | |
- return results; | |
- }; | |
+ if ( !matched ) { | |
+ break; | |
+ } | |
} | |
- // Check to see if an attribute returns normalized href attributes | |
- div.innerHTML = "<a href='#'></a>"; | |
- | |
- if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" && | |
- div.firstChild.getAttribute("href") !== "#" ) { | |
- | |
- Expr.attrHandle.href = function( elem ) { | |
- return elem.getAttribute( "href", 2 ); | |
- }; | |
+ // Attach the full group as a selector | |
+ if ( group ) { | |
+ tokens.selector = group; | |
} | |
- // release memory in IE | |
- div = null; | |
-})(); | |
- | |
-// Patch for jsdom | |
-if ( document.querySelectorAll && false ) { | |
- (function(){ | |
- var oldSizzle = Sizzle, | |
- div = document.createElement("div"), | |
- id = "__sizzle__"; | |
- | |
- div.innerHTML = "<p class='TEST'></p>"; | |
- | |
- // Safari can't handle uppercase or unicode characters when | |
- // in quirks mode. | |
- if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) { | |
- return; | |
- } | |
- | |
- Sizzle = function( query, context, extra, seed ) { | |
- context = context || document; | |
- | |
- // Only use querySelectorAll on non-XML documents | |
- // (ID selectors don't work in non-HTML documents) | |
- if ( !seed && !Sizzle.isXML(context) ) { | |
- // See if we find a selector to speed up | |
- var match = /^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec( query ); | |
+ // Return the length of the invalid excess | |
+ // if we're just parsing | |
+ // Otherwise, throw an error or return tokens | |
+ return parseOnly ? | |
+ soFar.length : | |
+ soFar ? | |
+ Sizzle.error( selector ) : | |
+ // Cache the tokens | |
+ slice.call( tokenCache(key, groups), 0 ); | |
+} | |
- if ( match && (context.nodeType === 1 || context.nodeType === 9) ) { | |
- // Speed-up: Sizzle("TAG") | |
- if ( match[1] ) { | |
- return makeArray( context.getElementsByTagName( query ), extra ); | |
+function addCombinator( matcher, combinator, context, xml ) { | |
+ var dir = combinator.dir, | |
+ doneName = done++; | |
- // Speed-up: Sizzle(".CLASS") | |
- } else if ( match[2] && Expr.find.CLASS && context.getElementsByClassName ) { | |
- return makeArray( context.getElementsByClassName( match[2] ), extra ); | |
+ if ( !matcher ) { | |
+ // If there is no matcher to check, check against the context | |
+ matcher = function( elem ) { | |
+ return elem === context; | |
+ }; | |
+ } | |
+ return combinator.first ? | |
+ function( elem ) { | |
+ while ( (elem = elem[ dir ]) ) { | |
+ if ( elem.nodeType === 1 ) { | |
+ return matcher( elem ) && elem; | |
+ } | |
+ } | |
+ } : | |
+ xml ? | |
+ function( elem ) { | |
+ while ( (elem = elem[ dir ]) ) { | |
+ if ( elem.nodeType === 1 ) { | |
+ if ( matcher( elem ) ) { | |
+ return elem; | |
+ } | |
} | |
} | |
- | |
- if ( context.nodeType === 9 ) { | |
- // Speed-up: Sizzle("body") | |
- // The body element only exists once, optimize finding it | |
- if ( query === "body" && context.body ) { | |
- return makeArray( [ context.body ], extra ); | |
- | |
- // Speed-up: Sizzle("#ID") | |
- } else if ( match && match[3] ) { | |
- var elem = context.getElementById( match[3] ); | |
- | |
- // Check parentNode to catch when Blackberry 4.6 returns | |
- // nodes that are no longer in the document #6963 | |
- if ( elem && elem.parentNode ) { | |
- // Handle the case where IE and Opera return items | |
- // by name instead of ID | |
- if ( elem.id === match[3] ) { | |
- return makeArray( [ elem ], extra ); | |
+ } : | |
+ function( elem ) { | |
+ var cache, | |
+ dirkey = doneName + "." + dirruns, | |
+ cachedkey = dirkey + "." + cachedruns; | |
+ while ( (elem = elem[ dir ]) ) { | |
+ if ( elem.nodeType === 1 ) { | |
+ if ( (cache = elem[ expando ]) === cachedkey ) { | |
+ return elem.sizset; | |
+ } else if ( typeof cache === "string" && cache.indexOf(dirkey) === 0 ) { | |
+ if ( elem.sizset ) { | |
+ return elem; | |
} | |
- | |
} else { | |
- return makeArray( [], extra ); | |
+ elem[ expando ] = cachedkey; | |
+ if ( matcher( elem ) ) { | |
+ elem.sizset = true; | |
+ return elem; | |
+ } | |
+ elem.sizset = false; | |
} | |
} | |
+ } | |
+ }; | |
+} | |
- try { | |
- return makeArray( context.querySelectorAll(query), extra ); | |
- } catch(qsaError) {} | |
+function addMatcher( higher, deeper ) { | |
+ return higher ? | |
+ function( elem ) { | |
+ var result = deeper( elem ); | |
+ return result && higher( result === true ? elem : result ); | |
+ } : | |
+ deeper; | |
+} | |
- // qSA works strangely on Element-rooted queries | |
- // We can work around this by specifying an extra ID on the root | |
- // and working up from there (Thanks to Andrew Dupont for the technique) | |
- // IE 8 doesn't work on object elements | |
- } else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) { | |
- var oldContext = context, | |
- old = context.getAttribute( "id" ), | |
- nid = old || id, | |
- hasParent = context.parentNode, | |
- relativeHierarchySelector = /^\s*[+~]/.test( query ); | |
+// ["TAG", ">", "ID", " ", "CLASS"] | |
+function matcherFromTokens( tokens, context, xml ) { | |
+ var token, matcher, | |
+ i = 0; | |
- if ( !old ) { | |
- context.setAttribute( "id", nid ); | |
- } else { | |
- nid = nid.replace( /'/g, "\\$&" ); | |
- } | |
- if ( relativeHierarchySelector && hasParent ) { | |
- context = context.parentNode; | |
- } | |
+ for ( ; (token = tokens[i]); i++ ) { | |
+ if ( Expr.relative[ token.part ] ) { | |
+ matcher = addCombinator( matcher, Expr.relative[ token.part ], context, xml ); | |
+ } else { | |
+ matcher = addMatcher( matcher, Expr.filter[ token.part ].apply(null, token.captures.concat( context, xml )) ); | |
+ } | |
+ } | |
- try { | |
- if ( !relativeHierarchySelector || hasParent ) { | |
- return makeArray( context.querySelectorAll( "[id='" + nid + "'] " + query ), extra ); | |
- } | |
+ return matcher; | |
+} | |
- } catch(pseudoError) { | |
- } finally { | |
- if ( !old ) { | |
- oldContext.removeAttribute( "id" ); | |
- } | |
- } | |
- } | |
+function matcherFromGroupMatchers( matchers ) { | |
+ return function( elem ) { | |
+ var matcher, | |
+ j = 0; | |
+ for ( ; (matcher = matchers[j]); j++ ) { | |
+ if ( matcher(elem) ) { | |
+ return true; | |
} | |
+ } | |
+ return false; | |
+ }; | |
+} | |
- return oldSizzle(query, context, extra, seed); | |
- }; | |
+compile = Sizzle.compile = function( selector, context, xml ) { | |
+ var group, i, len, | |
+ cached = compilerCache[ expando ][ selector ]; | |
- for ( var prop in oldSizzle ) { | |
- Sizzle[ prop ] = oldSizzle[ prop ]; | |
- } | |
+ // Return a cached group function if already generated (context dependent) | |
+ if ( cached && cached.context === context ) { | |
+ return cached; | |
+ } | |
- // release memory in IE | |
- div = null; | |
- })(); | |
+ // Generate a function of recursive functions that can be used to check each element | |
+ group = tokenize( selector, context, xml ); | |
+ for ( i = 0, len = group.length; i < len; i++ ) { | |
+ group[i] = matcherFromTokens(group[i], context, xml); | |
+ } | |
+ | |
+ // Cache the compiled function | |
+ cached = compilerCache( selector, matcherFromGroupMatchers(group) ); | |
+ cached.context = context; | |
+ cached.runs = cached.dirruns = 0; | |
+ return cached; | |
+}; | |
+ | |
+function multipleContexts( selector, contexts, results, seed ) { | |
+ var i = 0, | |
+ len = contexts.length; | |
+ for ( ; i < len; i++ ) { | |
+ Sizzle( selector, contexts[i], results, seed ); | |
+ } | |
} | |
-(function(){ | |
- var html = document.documentElement, | |
- matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector; | |
+function handlePOSGroup( selector, posfilter, argument, contexts, seed, not ) { | |
+ var results, | |
+ fn = Expr.setFilters[ posfilter.toLowerCase() ]; | |
- if ( matches ) { | |
- // Check to see if it's possible to do matchesSelector | |
- // on a disconnected node (IE 9 fails this) | |
- var disconnectedMatch = !matches.call( document.createElement( "div" ), "div" ), | |
- pseudoWorks = false; | |
+ if ( !fn ) { | |
+ Sizzle.error( posfilter ); | |
+ } | |
- try { | |
- // This should fail with an exception | |
- // Gecko does not error, returns false instead | |
- matches.call( document.documentElement, "[test!='']:sizzle" ); | |
+ if ( selector || !(results = seed) ) { | |
+ multipleContexts( selector || "*", contexts, (results = []), seed ); | |
+ } | |
- } catch( pseudoError ) { | |
- pseudoWorks = true; | |
- } | |
+ return results.length > 0 ? fn( results, argument, not ) : []; | |
+} | |
- Sizzle.matchesSelector = function( node, expr ) { | |
- // Make sure that attribute selectors are quoted | |
- expr = expr.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']"); | |
+function handlePOS( groups, context, results, seed ) { | |
+ var group, part, j, groupLen, token, selector, | |
+ anchor, elements, match, matched, | |
+ lastIndex, currentContexts, not, | |
+ i = 0, | |
+ len = groups.length, | |
+ rpos = matchExpr["POS"], | |
+ // This is generated here in case matchExpr["POS"] is extended | |
+ rposgroups = new RegExp( "^" + rpos.source + "(?!" + whitespace + ")", "i" ), | |
+ // This is for making sure non-participating | |
+ // matching groups are represented cross-browser (IE6-8) | |
+ setUndefined = function() { | |
+ var i = 1, | |
+ len = arguments.length - 2; | |
+ for ( ; i < len; i++ ) { | |
+ if ( arguments[i] === undefined ) { | |
+ match[i] = undefined; | |
+ } | |
+ } | |
+ }; | |
- if ( !Sizzle.isXML( node ) ) { | |
- try { | |
- if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) { | |
- var ret = matches.call( node, expr ); | |
+ for ( ; i < len; i++ ) { | |
+ group = groups[i]; | |
+ part = ""; | |
+ elements = seed; | |
+ for ( j = 0, groupLen = group.length; j < groupLen; j++ ) { | |
+ token = group[j]; | |
+ selector = token.string; | |
+ if ( token.part === "PSEUDO" ) { | |
+ // Reset regex index to 0 | |
+ rpos.exec(""); | |
+ anchor = 0; | |
+ while ( (match = rpos.exec( selector )) ) { | |
+ matched = true; | |
+ lastIndex = rpos.lastIndex = match.index + match[0].length; | |
+ if ( lastIndex > anchor ) { | |
+ part += selector.slice( anchor, match.index ); | |
+ anchor = lastIndex; | |
+ currentContexts = [ context ]; | |
+ | |
+ if ( rcombinators.test(part) ) { | |
+ if ( elements ) { | |
+ currentContexts = elements; | |
+ } | |
+ elements = seed; | |
+ } | |
- // IE 9's matchesSelector returns false on disconnected nodes | |
- if ( ret || !disconnectedMatch || | |
- // As well, disconnected nodes are said to be in a document | |
- // fragment in IE 9, so check for that | |
- node.document && node.document.nodeType !== 11 ) { | |
- return ret; | |
+ if ( (not = rendsWithNot.test( part )) ) { | |
+ part = part.slice( 0, -5 ).replace( rcombinators, "$&*" ); | |
+ anchor++; | |
} | |
- } | |
- } catch(e) {} | |
- } | |
- return Sizzle(expr, null, null, [node]).length > 0; | |
- }; | |
- } | |
-})(); | |
+ if ( match.length > 1 ) { | |
+ match[0].replace( rposgroups, setUndefined ); | |
+ } | |
+ elements = handlePOSGroup( part, match[1], match[2], currentContexts, elements, not ); | |
+ } | |
+ part = ""; | |
+ } | |
-(function(){ | |
- var div = document.createElement("div"); | |
+ } | |
- div.innerHTML = "<div class='test e'></div><div class='test'></div>"; | |
+ if ( !matched ) { | |
+ part += selector; | |
+ } | |
+ matched = false; | |
+ } | |
- // Opera can't find a second classname (in 9.6) | |
- // Also, make sure that getElementsByClassName actually exists | |
- if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) { | |
- return; | |
+ if ( part ) { | |
+ if ( rcombinators.test(part) ) { | |
+ multipleContexts( part, elements || [ context ], results, seed ); | |
+ } else { | |
+ Sizzle( part, context, results, seed ? seed.concat(elements) : elements ); | |
+ } | |
+ } else { | |
+ push.apply( results, elements ); | |
+ } | |
} | |
- // Safari caches class attributes, doesn't catch changes (in 3.2) | |
- div.lastChild.className = "e"; | |
+ // Do not sort if this is a single filter | |
+ return len === 1 ? results : Sizzle.uniqueSort( results ); | |
+} | |
- if ( div.getElementsByClassName("e").length === 1 ) { | |
- return; | |
+function select( selector, context, results, seed, xml ) { | |
+ // Remove excessive whitespace | |
+ selector = selector.replace( rtrim, "$1" ); | |
+ var elements, matcher, cached, elem, | |
+ i, tokens, token, lastToken, findContext, type, | |
+ match = tokenize( selector, context, xml ), | |
+ contextNodeType = context.nodeType; | |
+ | |
+ // POS handling | |
+ if ( matchExpr["POS"].test(selector) ) { | |
+ return handlePOS( match, context, results, seed ); | |
} | |
- Expr.order.splice(1, 0, "CLASS"); | |
- Expr.find.CLASS = function( match, context, isXML ) { | |
- if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) { | |
- return context.getElementsByClassName(match[1]); | |
- } | |
- }; | |
+ if ( seed ) { | |
+ elements = slice.call( seed, 0 ); | |
- // release memory in IE | |
- div = null; | |
-})(); | |
+ // To maintain document order, only narrow the | |
+ // set if there is one group | |
+ } else if ( match.length === 1 ) { | |
-function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { | |
- for ( var i = 0, l = checkSet.length; i < l; i++ ) { | |
- var elem = checkSet[i]; | |
+ // Take a shortcut and set the context if the root selector is an ID | |
+ if ( (tokens = slice.call( match[0], 0 )).length > 2 && | |
+ (token = tokens[0]).part === "ID" && | |
+ contextNodeType === 9 && !xml && | |
+ Expr.relative[ tokens[1].part ] ) { | |
+ | |
+ context = Expr.find["ID"]( token.captures[0].replace( rbackslash, "" ), context, xml )[0]; | |
+ if ( !context ) { | |
+ return results; | |
+ } | |
- if ( elem ) { | |
- var match = false; | |
+ selector = selector.slice( tokens.shift().string.length ); | |
+ } | |
- elem = elem[dir]; | |
+ findContext = ( (match = rsibling.exec( tokens[0].string )) && !match.index && context.parentNode ) || context; | |
- while ( elem ) { | |
- if ( elem[ expando ] === doneName ) { | |
- match = checkSet[elem.sizset]; | |
- break; | |
- } | |
+ // Reduce the set if possible | |
+ lastToken = ""; | |
+ for ( i = tokens.length - 1; i >= 0; i-- ) { | |
+ token = tokens[i]; | |
+ type = token.part; | |
+ lastToken = token.string + lastToken; | |
+ if ( Expr.relative[ type ] ) { | |
+ break; | |
+ } | |
+ if ( Expr.order.test(type) ) { | |
+ elements = Expr.find[ type ]( token.captures[0].replace( rbackslash, "" ), findContext, xml ); | |
+ if ( elements == null ) { | |
+ continue; | |
+ } else { | |
+ selector = selector.slice( 0, selector.length - lastToken.length ) + | |
+ lastToken.replace( matchExpr[ type ], "" ); | |
- if ( elem.nodeType === 1 && !isXML ){ | |
- elem[ expando ] = doneName; | |
- elem.sizset = i; | |
- } | |
+ if ( !selector ) { | |
+ push.apply( results, slice.call(elements, 0) ); | |
+ } | |
- if ( elem.nodeName.toLowerCase() === cur ) { | |
- match = elem; | |
break; | |
} | |
- | |
- elem = elem[dir]; | |
} | |
+ } | |
+ } | |
+ | |
+ // Only loop over the given elements once | |
+ if ( selector ) { | |
+ matcher = compile( selector, context, xml ); | |
+ dirruns = matcher.dirruns++; | |
+ if ( elements == null ) { | |
+ elements = Expr.find["TAG"]( "*", (rsibling.test( selector ) && context.parentNode) || context ); | |
+ } | |
- checkSet[i] = match; | |
+ for ( i = 0; (elem = elements[i]); i++ ) { | |
+ cachedruns = matcher.runs++; | |
+ if ( matcher(elem) ) { | |
+ results.push( elem ); | |
+ } | |
} | |
} | |
+ | |
+ return results; | |
} | |
-function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { | |
- for ( var i = 0, l = checkSet.length; i < l; i++ ) { | |
- var elem = checkSet[i]; | |
+// Patch for jsdom | |
+// we use sizzle to implement querySelectorAll, so sizzle cannot use it | |
+if ( document.querySelectorAll && false ) { | |
+ (function() { | |
+ var disconnectedMatch, | |
+ oldSelect = select, | |
+ rescape = /'|\\/g, | |
+ rattributeQuotes = /\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g, | |
+ rbuggyQSA = [], | |
+ // matchesSelector(:active) reports false when true (IE9/Opera 11.5) | |
+ // A support test would require too much code (would include document ready) | |
+ // just skip matchesSelector for :active | |
+ rbuggyMatches = [":active"], | |
+ matches = docElem.matchesSelector || | |
+ docElem.mozMatchesSelector || | |
+ docElem.webkitMatchesSelector || | |
+ docElem.oMatchesSelector || | |
+ docElem.msMatchesSelector; | |
+ | |
+ // Build QSA regex | |
+ // Regex strategy adopted from Diego Perini | |
+ assert(function( div ) { | |
+ // Select is set to empty string on purpose | |
+ // This is to test IE's treatment of not explictly | |
+ // setting a boolean content attribute, | |
+ // since its presence should be enough | |
+ // http://bugs.jquery.com/ticket/12359 | |
+ div.innerHTML = "<select><option selected=''></option></select>"; | |
+ | |
+ // IE8 - Some boolean attributes are not treated correctly | |
+ if ( !div.querySelectorAll("[selected]").length ) { | |
+ rbuggyQSA.push( "\\[" + whitespace + "*(?:checked|disabled|ismap|multiple|readonly|selected|value)" ); | |
+ } | |
+ | |
+ // Webkit/Opera - :checked should return selected option elements | |
+ // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked | |
+ // IE8 throws error here (do not put tests after this one) | |
+ if ( !div.querySelectorAll(":checked").length ) { | |
+ rbuggyQSA.push(":checked"); | |
+ } | |
+ }); | |
- if ( elem ) { | |
- var match = false; | |
+ assert(function( div ) { | |
- elem = elem[dir]; | |
+ // Opera 10-12/IE9 - ^= $= *= and empty values | |
+ // Should not select anything | |
+ div.innerHTML = "<p test=''></p>"; | |
+ if ( div.querySelectorAll("[test^='']").length ) { | |
+ rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:\"\"|'')" ); | |
+ } | |
- while ( elem ) { | |
- if ( elem[ expando ] === doneName ) { | |
- match = checkSet[elem.sizset]; | |
- break; | |
- } | |
+ // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) | |
+ // IE8 throws error here (do not put tests after this one) | |
+ div.innerHTML = "<input type='hidden'/>"; | |
+ if ( !div.querySelectorAll(":enabled").length ) { | |
+ rbuggyQSA.push(":enabled", ":disabled"); | |
+ } | |
+ }); | |
- if ( elem.nodeType === 1 ) { | |
- if ( !isXML ) { | |
- elem[ expando ] = doneName; | |
- elem.sizset = i; | |
+ rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") ); | |
+ | |
+ select = function( selector, context, results, seed, xml ) { | |
+ // Only use querySelectorAll when not filtering, | |
+ // when this is not xml, | |
+ // and when no QSA bugs apply | |
+ if ( !seed && !xml && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) { | |
+ if ( context.nodeType === 9 ) { | |
+ try { | |
+ push.apply( results, slice.call(context.querySelectorAll( selector ), 0) ); | |
+ return results; | |
+ } catch(qsaError) {} | |
+ // qSA works strangely on Element-rooted queries | |
+ // We can work around this by specifying an extra ID on the root | |
+ // and working up from there (Thanks to Andrew Dupont for the technique) | |
+ // IE 8 doesn't work on object elements | |
+ } else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) { | |
+ var groups, i, len, | |
+ old = context.getAttribute("id"), | |
+ nid = old || expando, | |
+ newContext = rsibling.test( selector ) && context.parentNode || context; | |
+ | |
+ if ( old ) { | |
+ nid = nid.replace( rescape, "\\$&" ); | |
+ } else { | |
+ context.setAttribute( "id", nid ); | |
} | |
- if ( typeof cur !== "string" ) { | |
- if ( elem === cur ) { | |
- match = true; | |
- break; | |
+ groups = tokenize(selector, context, xml); | |
+ // Trailing space is unnecessary | |
+ // There is always a context check | |
+ nid = "[id='" + nid + "']"; | |
+ for ( i = 0, len = groups.length; i < len; i++ ) { | |
+ groups[i] = nid + groups[i].selector; | |
+ } | |
+ try { | |
+ push.apply( results, slice.call( newContext.querySelectorAll( | |
+ groups.join(",") | |
+ ), 0 ) ); | |
+ return results; | |
+ } catch(qsaError) { | |
+ } finally { | |
+ if ( !old ) { | |
+ context.removeAttribute("id"); | |
} | |
- | |
- } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) { | |
- match = elem; | |
- break; | |
} | |
} | |
- | |
- elem = elem[dir]; | |
} | |
- checkSet[i] = match; | |
- } | |
- } | |
-} | |
+ return oldSelect( selector, context, results, seed, xml ); | |
+ }; | |
-if ( document.documentElement.contains ) { | |
- Sizzle.contains = function( a, b ) { | |
- return a !== b && (a.contains ? a.contains(b) : true); | |
- }; | |
+ if ( matches ) { | |
+ assert(function( div ) { | |
+ // Check to see if it's possible to do matchesSelector | |
+ // on a disconnected node (IE 9) | |
+ disconnectedMatch = matches.call( div, "div" ); | |
-} else if ( document.documentElement.compareDocumentPosition ) { | |
- Sizzle.contains = function( a, b ) { | |
- return !!(a.compareDocumentPosition(b) & 16); | |
- }; | |
+ // This should fail with an exception | |
+ // Gecko does not error, returns false instead | |
+ try { | |
+ matches.call( div, "[test!='']:sizzle" ); | |
+ rbuggyMatches.push( matchExpr["PSEUDO"].source, matchExpr["POS"].source, "!=" ); | |
+ } catch ( e ) {} | |
+ }); | |
-} else { | |
- Sizzle.contains = function() { | |
- return false; | |
- }; | |
-} | |
+ // rbuggyMatches always contains :active, so no need for a length check | |
+ rbuggyMatches = /* rbuggyMatches.length && */ new RegExp( rbuggyMatches.join("|") ); | |
-Sizzle.isXML = function( elem ) { | |
- // documentElement is verified for cases where it doesn't yet exist | |
- // (such as loading iframes in IE - #4833) | |
- var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement; | |
+ Sizzle.matchesSelector = function( elem, expr ) { | |
+ // Make sure that attribute selectors are quoted | |
+ expr = expr.replace( rattributeQuotes, "='$1']" ); | |
- return documentElement ? documentElement.nodeName !== "HTML" : false; | |
-}; | |
+ // rbuggyMatches always contains :active, so no need for an existence check | |
+ if ( !isXML( elem ) && !rbuggyMatches.test( expr ) && (!rbuggyQSA || !rbuggyQSA.test( expr )) ) { | |
+ try { | |
+ var ret = matches.call( elem, expr ); | |
-var posProcess = function( selector, context, seed ) { | |
- var match, | |
- tmpSet = [], | |
- later = "", | |
- root = context.nodeType ? [context] : context; | |
- | |
- // Position selectors must be done after the filter | |
- // And so must :not(positional) so we move all PSEUDOs to the end | |
- while ( (match = Expr.match.PSEUDO.exec( selector )) ) { | |
- later += match[0]; | |
- selector = selector.replace( Expr.match.PSEUDO, "" ); | |
- } | |
+ // IE 9's matchesSelector returns false on disconnected nodes | |
+ if ( ret || disconnectedMatch || | |
+ // As well, disconnected nodes are said to be in a document | |
+ // fragment in IE 9 | |
+ elem.document && elem.document.nodeType !== 11 ) { | |
+ return ret; | |
+ } | |
+ } catch(e) {} | |
+ } | |
- selector = Expr.relative[selector] ? selector + "*" : selector; | |
+ return Sizzle( expr, null, null, [ elem ] ).length > 0; | |
+ }; | |
+ } | |
+ })(); | |
+} | |
- for ( var i = 0, l = root.length; i < l; i++ ) { | |
- Sizzle( selector, root[i], tmpSet, seed ); | |
- } | |
+// Deprecated | |
+Expr.setFilters["nth"] = Expr.setFilters["eq"]; | |
- return Sizzle.filter( later, tmpSet ); | |
-}; | |
+// Back-compat | |
+Expr.filters = Expr.pseudos; | |
// EXPOSE | |
+/* patch for jsdom */ | |
return Sizzle; | |
+/* | |
+if ( typeof define === "function" && define.amd ) { | |
+ define(function() { return Sizzle; }); | |
+} else { | |
+ window.Sizzle = Sizzle; | |
+} | |
+*/ | |
+// EXPOSE | |
-}; | |
\ No newline at end of file | |
+}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--- sizzle.js.github-20120907 2012-09-07 11:19:33.655864433 -0400 | |
+++ ./sizzle.js 2012-09-07 11:28:10.044305054 -0400 | |
@@ -4,7 +4,8 @@ | |
* Released under the MIT license | |
* http://sizzlejs.com/ | |
*/ | |
-(function( window, undefined ) { | |
+// Patch for jsdom | |
+module.exports = function( document ) { | |
var dirruns, | |
cachedruns, | |
@@ -22,7 +23,7 @@ | |
expando = ( "sizcache" + Math.random() ).replace( ".", "" ), | |
- document = window.document, | |
+ // jsdom document = window.document, | |
docElem = document.documentElement, | |
done = 0, | |
slice = [].slice, | |
@@ -200,7 +201,10 @@ | |
function Sizzle( selector, context, results, seed ) { | |
results = results || []; | |
- context = context || document; | |
+ // PATCH for jsdom | |
+ // context = context || document; | |
+ // See: https://github.com/tmpvar/jsdom/issues/375 | |
+ context = context || seed[0].ownerDocument; | |
var match, elem, xml, m, | |
nodeType = context.nodeType; | |
@@ -1367,7 +1371,9 @@ | |
return results; | |
} | |
-if ( document.querySelectorAll ) { | |
+// Patch for jsdom | |
+// we use sizzle to implement querySelectorAll, so sizzle cannot use it | |
+if ( document.querySelectorAll && false ) { | |
(function() { | |
var disconnectedMatch, | |
oldSelect = select, | |
@@ -1525,11 +1531,15 @@ | |
Expr.filters = Expr.pseudos; | |
// EXPOSE | |
+/* patch for jsdom */ | |
+return Sizzle; | |
+/* | |
if ( typeof define === "function" && define.amd ) { | |
define(function() { return Sizzle; }); | |
} else { | |
window.Sizzle = Sizzle; | |
} | |
+*/ | |
// EXPOSE | |
-})( window ); | |
+}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment