Skip to content

Instantly share code, notes, and snippets.

@godmar
Created September 7, 2012 15:40
Show Gist options
  • Save godmar/3667258 to your computer and use it in GitHub Desktop.
Save godmar/3667258 to your computer and use it in GitHub Desktop.
Updating sizzle for jsdom to github 20120907 version.
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
+};
--- 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