2 * Sizzle CSS Selector Engine
3 * Copyright 2011, The Dojo Foundation
4 * Released under the MIT, BSD, and GPL Licenses.
5 * More information: http://sizzlejs.com/
8 module
.exports = function(document
){
10 var chunker
= /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
11 expando
= "sizcache" + (Math
.random() + '').replace('.', ''),
13 toString
= Object
.prototype.toString
,
15 baseHasDuplicate
= true,
21 // Here we check if the JavaScript engine is using some sort of
22 // optimization where it does not always call our comparision
23 // function. If that is the case, discard the hasDuplicate value.
24 // Thus far that includes Google Chrome.
25 [0, 0].sort(function() {
26 baseHasDuplicate
= false;
30 var Sizzle = function( selector
, context
, results
, seed
) {
31 results
= results
|| [];
33 // context = context || document;
34 // See: https://github.com/tmpvar/jsdom/issues/375
35 context
= context
|| seed
[0].ownerDocument
;
36 var origContext
= context
;
38 if ( context
.nodeType
!== 1 && context
.nodeType
!== 9 ) {
42 if ( !selector
|| typeof selector
!== "string" ) {
46 var m
, set, checkSet
, extra
, ret
, cur
, pop
, i
,
48 contextXML
= Sizzle
.isXML( context
),
52 // Reset the position of the chunker regexp (start from head)
55 m
= chunker
.exec( soFar
);
69 if ( parts
.length
> 1 && origPOS
.exec( selector
) ) {
71 if ( parts
.length
=== 2 && Expr
.relative
[ parts
[0] ] ) {
72 set = posProcess( parts
[0] + parts
[1], context
, seed
);
75 set = Expr
.relative
[ parts
[0] ] ?
77 Sizzle( parts
.shift(), context
);
79 while ( parts
.length
) {
80 selector
= parts
.shift();
82 if ( Expr
.relative
[ selector
] ) {
83 selector
+= parts
.shift();
86 set = posProcess( selector
, set, seed
);
91 // Take a shortcut and set the context if the root selector is an ID
92 // (but not if it'll be faster if the inner selector is an ID)
93 if ( !seed
&& parts
.length
> 1 && context
.nodeType
=== 9 && !contextXML
&&
94 Expr
.match
.ID
.test(parts
[0]) && !Expr
.match
.ID
.test(parts
[parts
.length
- 1]) ) {
96 ret
= Sizzle
.find( parts
.shift(), context
, contextXML
);
98 Sizzle
.filter( ret
.expr
, ret
.set )[0] :
104 { expr
: parts
.pop(), set: makeArray(seed
) } :
105 Sizzle
.find( parts
.pop(), parts
.length
=== 1 && (parts
[0] === "~" || parts
[0] === "+") && context
.parentNode
? context
.parentNode
: context
, contextXML
);
108 Sizzle
.filter( ret
.expr
, ret
.set ) :
111 if ( parts
.length
> 0 ) {
112 checkSet
= makeArray( set );
118 while ( parts
.length
) {
122 if ( !Expr
.relative
[ cur
] ) {
132 Expr
.relative
[ cur
]( checkSet
, pop
, contextXML
);
136 checkSet
= parts
= [];
145 Sizzle
.error( cur
|| selector
);
148 if ( toString
.call(checkSet
) === "[object Array]" ) {
150 results
.push
.apply( results
, checkSet
);
152 } else if ( context
&& context
.nodeType
=== 1 ) {
153 for ( i
= 0; checkSet
[i
] != null; i
++ ) {
154 if ( checkSet
[i
] && (checkSet
[i
] === true || checkSet
[i
].nodeType
=== 1 && Sizzle
.contains(context
, checkSet
[i
])) ) {
155 results
.push( set[i
] );
160 for ( i
= 0; checkSet
[i
] != null; i
++ ) {
161 if ( checkSet
[i
] && checkSet
[i
].nodeType
=== 1 ) {
162 results
.push( set[i
] );
168 makeArray( checkSet
, results
);
172 Sizzle( extra
, origContext
, results
, seed
);
173 Sizzle
.uniqueSort( results
);
179 Sizzle
.uniqueSort = function( results
) {
181 hasDuplicate
= baseHasDuplicate
;
182 results
.sort( sortOrder
);
184 if ( hasDuplicate
) {
185 for ( var i
= 1; i
< results
.length
; i
++ ) {
186 if ( results
[i
] === results
[ i
- 1 ] ) {
187 results
.splice( i
--, 1 );
196 Sizzle
.matches = function( expr
, set ) {
197 return Sizzle( expr
, null, null, set );
200 Sizzle
.matchesSelector = function( node
, expr
) {
201 return Sizzle( expr
, null, null, [node
] ).length
> 0;
204 Sizzle
.find = function( expr
, context
, isXML
) {
205 var set, i
, len
, match
, type
, left
;
211 for ( i
= 0, len
= Expr
.order
.length
; i
< len
; i
++ ) {
212 type
= Expr
.order
[i
];
214 if ( (match
= Expr
.leftMatch
[ type
].exec( expr
)) ) {
216 match
.splice( 1, 1 );
218 if ( left
.substr( left
.length
- 1 ) !== "\\" ) {
219 match
[1] = (match
[1] || "").replace( rBackslash
, "" );
220 set = Expr
.find
[ type
]( match
, context
, isXML
);
223 expr
= expr
.replace( Expr
.match
[ type
], "" );
231 set = typeof context
.getElementsByTagName
!== "undefined" ?
232 context
.getElementsByTagName( "*" ) :
236 return { set: set, expr
: expr
};
239 Sizzle
.filter = function( expr
, set, inplace
, not
) {
241 type
, found
, item
, filter
, left
,
246 isXMLFilter
= set && set[0] && Sizzle
.isXML( set[0] );
248 while ( expr
&& set.length
) {
249 for ( type
in Expr
.filter
) {
250 if ( (match
= Expr
.leftMatch
[ type
].exec( expr
)) != null && match
[2] ) {
251 filter
= Expr
.filter
[ type
];
258 if ( left
.substr( left
.length
- 1 ) === "\\" ) {
262 if ( curLoop
=== result
) {
266 if ( Expr
.preFilter
[ type
] ) {
267 match
= Expr
.preFilter
[ type
]( match
, curLoop
, inplace
, result
, not
, isXMLFilter
);
270 anyFound
= found
= true;
272 } else if ( match
=== true ) {
278 for ( i
= 0; (item
= curLoop
[i
]) != null; i
++ ) {
280 found
= filter( item
, match
, i
, curLoop
);
283 if ( inplace
&& found
!= null ) {
299 if ( found
!== undefined ) {
304 expr
= expr
.replace( Expr
.match
[ type
], "" );
315 // Improper expression
316 if ( expr
=== old
) {
317 if ( anyFound
== null ) {
318 Sizzle
.error( expr
);
331 Sizzle
.error = function( msg
) {
332 throw new Error( "Syntax error, unrecognized expression: " + msg
);
336 * Utility function for retreiving the text value of an array of DOM nodes
337 * @param {Array|Element} elem
339 var getText
= Sizzle
.getText = function( elem
) {
341 nodeType
= elem
.nodeType
,
345 if ( nodeType
=== 1 || nodeType
=== 9 || nodeType
=== 11 ) {
346 // Use textContent || innerText for elements
347 if ( typeof elem
.textContent
=== 'string' ) {
348 return elem
.textContent
;
349 } else if ( typeof elem
.innerText
=== 'string' ) {
350 // Replace IE's carriage returns
351 return elem
.innerText
.replace( rReturn
, '' );
353 // Traverse it's children
354 for ( elem
= elem
.firstChild
; elem
; elem
= elem
.nextSibling
) {
355 ret
+= getText( elem
);
358 } else if ( nodeType
=== 3 || nodeType
=== 4 ) {
359 return elem
.nodeValue
;
363 // If no nodeType, this is expected to be an array
364 for ( i
= 0; (node
= elem
[i
]); i
++ ) {
365 // Do not traverse comment nodes
366 if ( node
.nodeType
!== 8 ) {
367 ret
+= getText( node
);
374 var Expr
= Sizzle
.selectors
= {
375 order
: [ "ID", "NAME", "TAG" ],
378 ID
: /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,
379 CLASS
: /\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,
380 NAME
: /\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,
381 ATTR
: /\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/,
382 TAG
: /^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,
383 CHILD
: /:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/,
384 POS
: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,
385 PSEUDO
: /:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/
391 "class": "className",
396 href: function( elem
) {
397 return elem
.getAttribute( "href" );
399 type: function( elem
) {
400 return elem
.getAttribute( "type" );
405 "+": function(checkSet
, part
){
406 var isPartStr
= typeof part
=== "string",
407 isTag
= isPartStr
&& !rNonWord
.test( part
),
408 isPartStrNotTag
= isPartStr
&& !isTag
;
411 part
= part
.toLowerCase();
414 for ( var i
= 0, l
= checkSet
.length
, elem
; i
< l
; i
++ ) {
415 if ( (elem
= checkSet
[i
]) ) {
416 while ( (elem
= elem
.previousSibling
) && elem
.nodeType
!== 1 ) {}
418 checkSet
[i
] = isPartStrNotTag
|| elem
&& elem
.nodeName
.toLowerCase() === part
?
424 if ( isPartStrNotTag
) {
425 Sizzle
.filter( part
, checkSet
, true );
429 ">": function( checkSet
, part
) {
431 isPartStr
= typeof part
=== "string",
435 if ( isPartStr
&& !rNonWord
.test( part
) ) {
436 part
= part
.toLowerCase();
438 for ( ; i
< l
; i
++ ) {
442 var parent
= elem
.parentNode
;
443 checkSet
[i
] = parent
.nodeName
.toLowerCase() === part
? parent
: false;
448 for ( ; i
< l
; i
++ ) {
452 checkSet
[i
] = isPartStr
?
454 elem
.parentNode
=== part
;
459 Sizzle
.filter( part
, checkSet
, true );
464 "": function(checkSet
, part
, isXML
){
469 if ( typeof part
=== "string" && !rNonWord
.test( part
) ) {
470 part
= part
.toLowerCase();
472 checkFn
= dirNodeCheck
;
475 checkFn( "parentNode", part
, doneName
, checkSet
, nodeCheck
, isXML
);
478 "~": function( checkSet
, part
, isXML
) {
483 if ( typeof part
=== "string" && !rNonWord
.test( part
) ) {
484 part
= part
.toLowerCase();
486 checkFn
= dirNodeCheck
;
489 checkFn( "previousSibling", part
, doneName
, checkSet
, nodeCheck
, isXML
);
494 ID: function( match
, context
, isXML
) {
495 if ( typeof context
.getElementById
!== "undefined" && !isXML
) {
496 var m
= context
.getElementById(match
[1]);
497 // Check parentNode to catch when Blackberry 4.6 returns
498 // nodes that are no longer in the document #6963
499 return m
&& m
.parentNode
? [m
] : [];
503 NAME: function( match
, context
) {
504 if ( typeof context
.getElementsByName
!== "undefined" ) {
506 results
= context
.getElementsByName( match
[1] );
508 for ( var i
= 0, l
= results
.length
; i
< l
; i
++ ) {
509 if ( results
[i
].getAttribute("name") === match
[1] ) {
510 ret
.push( results
[i
] );
514 return ret
.length
=== 0 ? null : ret
;
518 TAG: function( match
, context
) {
519 if ( typeof context
.getElementsByTagName
!== "undefined" ) {
520 return context
.getElementsByTagName( match
[1] );
525 CLASS: function( match
, curLoop
, inplace
, result
, not
, isXML
) {
526 match
= " " + match
[1].replace( rBackslash
, "" ) + " ";
532 for ( var i
= 0, elem
; (elem
= curLoop
[i
]) != null; i
++ ) {
534 if ( not
^ (elem
.className
&& (" " + elem
.className
+ " ").replace(/[\t\n\r]/g, " ").indexOf(match
) >= 0) ) {
539 } else if ( inplace
) {
548 ID: function( match
) {
549 return match
[1].replace( rBackslash
, "" );
552 TAG: function( match
, curLoop
) {
553 return match
[1].replace( rBackslash
, "" ).toLowerCase();
556 CHILD: function( match
) {
557 if ( match
[1] === "nth" ) {
559 Sizzle
.error( match
[0] );
562 match
[2] = match
[2].replace(/^\+|\s*/g, '');
564 // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'
565 var test
= /(-?)(\d*)(?:n([+\-]?\d*))?/.exec(
566 match
[2] === "even" && "2n" || match
[2] === "odd" && "2n+1" ||
567 !/\D/.test( match
[2] ) && "0n+" + match
[2] || match
[2]);
569 // calculate the numbers (first)n+(last) including if they are negative
570 match
[2] = (test
[1] + (test
[2] || 1)) - 0;
571 match
[3] = test
[3] - 0;
573 else if ( match
[2] ) {
574 Sizzle
.error( match
[0] );
577 // TODO: Move to normal caching system
583 ATTR: function( match
, curLoop
, inplace
, result
, not
, isXML
) {
584 var name
= match
[1] = match
[1].replace( rBackslash
, "" );
586 if ( !isXML
&& Expr
.attrMap
[name
] ) {
587 match
[1] = Expr
.attrMap
[name
];
590 // Handle if an un-quoted value was used
591 match
[4] = ( match
[4] || match
[5] || "" ).replace( rBackslash
, "" );
593 if ( match
[2] === "~=" ) {
594 match
[4] = " " + match
[4] + " ";
600 PSEUDO: function( match
, curLoop
, inplace
, result
, not
) {
601 if ( match
[1] === "not" ) {
602 // If we're dealing with a complex expression, or a simple one
603 if ( ( chunker
.exec(match
[3]) || "" ).length
> 1 || /^\w/.test(match
[3]) ) {
604 match
[3] = Sizzle(match
[3], null, null, curLoop
);
607 var ret
= Sizzle
.filter(match
[3], curLoop
, inplace
, true ^ not
);
610 result
.push
.apply( result
, ret
);
616 } else if ( Expr
.match
.POS
.test( match
[0] ) || Expr
.match
.CHILD
.test( match
[0] ) ) {
623 POS: function( match
) {
624 match
.unshift( true );
631 enabled: function( elem
) {
632 return elem
.disabled
=== false && elem
.type
!== "hidden";
635 disabled: function( elem
) {
636 return elem
.disabled
=== true;
639 checked: function( elem
) {
640 return elem
.checked
=== true;
643 selected: function( elem
) {
644 // Accessing this property makes selected-by-default
645 // options in Safari work properly
646 if ( elem
.parentNode
) {
647 elem
.parentNode
.selectedIndex
;
650 return elem
.selected
=== true;
653 parent: function( elem
) {
654 return !!elem
.firstChild
;
657 empty: function( elem
) {
658 return !elem
.firstChild
;
661 has: function( elem
, i
, match
) {
662 return !!Sizzle( match
[3], elem
).length
;
665 header: function( elem
) {
666 return (/h\d/i).test( elem
.nodeName
);
669 text: function( elem
) {
670 var attr
= elem
.getAttribute( "type" ), type
= elem
.type
;
671 // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc)
672 // use getAttribute instead to test this case
673 return elem
.nodeName
.toLowerCase() === "input" && "text" === type
&& ( attr
=== type
|| attr
=== null );
676 radio: function( elem
) {
677 return elem
.nodeName
.toLowerCase() === "input" && "radio" === elem
.type
;
680 checkbox: function( elem
) {
681 return elem
.nodeName
.toLowerCase() === "input" && "checkbox" === elem
.type
;
684 file: function( elem
) {
685 return elem
.nodeName
.toLowerCase() === "input" && "file" === elem
.type
;
688 password: function( elem
) {
689 return elem
.nodeName
.toLowerCase() === "input" && "password" === elem
.type
;
692 submit: function( elem
) {
693 var name
= elem
.nodeName
.toLowerCase();
694 return (name
=== "input" || name
=== "button") && "submit" === elem
.type
;
697 image: function( elem
) {
698 return elem
.nodeName
.toLowerCase() === "input" && "image" === elem
.type
;
701 reset: function( elem
) {
702 var name
= elem
.nodeName
.toLowerCase();
703 return (name
=== "input" || name
=== "button") && "reset" === elem
.type
;
706 button: function( elem
) {
707 var name
= elem
.nodeName
.toLowerCase();
708 return name
=== "input" && "button" === elem
.type
|| name
=== "button";
711 input: function( elem
) {
712 return (/input|select|textarea|button/i).test( elem
.nodeName
);
715 focus: function( elem
) {
716 return elem
=== elem
.ownerDocument
.activeElement
;
720 first: function( elem
, i
) {
724 last: function( elem
, i
, match
, array
) {
725 return i
=== array
.length
- 1;
728 even: function( elem
, i
) {
732 odd: function( elem
, i
) {
736 lt: function( elem
, i
, match
) {
737 return i
< match
[3] - 0;
740 gt: function( elem
, i
, match
) {
741 return i
> match
[3] - 0;
744 nth: function( elem
, i
, match
) {
745 return match
[3] - 0 === i
;
748 eq: function( elem
, i
, match
) {
749 return match
[3] - 0 === i
;
753 PSEUDO: function( elem
, match
, i
, array
) {
755 filter
= Expr
.filters
[ name
];
758 return filter( elem
, i
, match
, array
);
760 } else if ( name
=== "contains" ) {
761 return (elem
.textContent
|| elem
.innerText
|| getText([ elem
]) || "").indexOf(match
[3]) >= 0;
763 } else if ( name
=== "not" ) {
766 for ( var j
= 0, l
= not
.length
; j
< l
; j
++ ) {
767 if ( not
[j
] === elem
) {
775 Sizzle
.error( name
);
779 CHILD: function( elem
, match
) {
781 doneName
, parent
, cache
,
789 while ( (node
= node
.previousSibling
) ) {
790 if ( node
.nodeType
=== 1 ) {
795 if ( type
=== "first" ) {
803 while ( (node
= node
.nextSibling
) ) {
804 if ( node
.nodeType
=== 1 ) {
815 if ( first
=== 1 && last
=== 0 ) {
820 parent
= elem
.parentNode
;
822 if ( parent
&& (parent
[ expando
] !== doneName
|| !elem
.nodeIndex
) ) {
825 for ( node
= parent
.firstChild
; node
; node
= node
.nextSibling
) {
826 if ( node
.nodeType
=== 1 ) {
827 node
.nodeIndex
= ++count
;
831 parent
[ expando
] = doneName
;
834 diff
= elem
.nodeIndex
- last
;
840 return ( diff
% first
=== 0 && diff
/ first
>= 0 );
845 ID: function( elem
, match
) {
846 return elem
.nodeType
=== 1 && elem
.getAttribute("id") === match
;
849 TAG: function( elem
, match
) {
850 return (match
=== "*" && elem
.nodeType
=== 1) || !!elem
.nodeName
&& elem
.nodeName
.toLowerCase() === match
;
853 CLASS: function( elem
, match
) {
854 return (" " + (elem
.className
|| elem
.getAttribute("class")) + " ")
855 .indexOf( match
) > -1;
858 ATTR: function( elem
, match
) {
860 result
= Sizzle
.attr
?
861 Sizzle
.attr( elem
, name
) :
862 Expr
.attrHandle
[ name
] ?
863 Expr
.attrHandle
[ name
]( elem
) :
864 elem
[ name
] != null ?
866 elem
.getAttribute( name
),
871 return result
== null ?
873 !type
&& Sizzle
.attr
?
878 value
.indexOf(check
) >= 0 :
880 (" " + value
+ " ").indexOf(check
) >= 0 :
882 value
&& result
!== false :
886 value
.indexOf(check
) === 0 :
888 value
.substr(value
.length
- check
.length
) === check
:
890 value
=== check
|| value
.substr(0, check
.length
+ 1) === check
+ "-" :
894 POS: function( elem
, match
, i
, array
) {
896 filter
= Expr
.setFilters
[ name
];
899 return filter( elem
, i
, match
, array
);
905 var origPOS
= Expr
.match
.POS
,
906 fescape = function(all
, num
){
907 return "\\" + (num
- 0 + 1);
910 for ( var type
in Expr
.match
) {
911 Expr
.match
[ type
] = new RegExp( Expr
.match
[ type
].source
+ (/(?![^\[]*\])(?![^\(]*\))/.source
) );
912 Expr
.leftMatch
[ type
] = new RegExp( /(^(?:.|\r|\n)*?)/.source
+ Expr
.match
[ type
].source
.replace(/\\(\d+)/g, fescape
) );
915 // "global" as in regardless of relation to brackets/parens
916 Expr
.match
.globalPOS
= origPOS
;
918 var makeArray = function( array
, results
) {
919 array
= Array
.prototype.slice
.call( array
, 0 );
922 results
.push
.apply( results
, array
);
929 // Perform a simple check to determine if the browser is capable of
930 // converting a NodeList to an array using builtin methods.
931 // Also verifies that the returned array holds DOM nodes
932 // (which is not the case in the Blackberry browser)
934 Array
.prototype.slice
.call( document
.documentElement
.childNodes
, 0 )[0].nodeType
;
936 // Provide a fallback method if it does not work
938 makeArray = function( array
, results
) {
942 if ( toString
.call(array
) === "[object Array]" ) {
943 Array
.prototype.push
.apply( ret
, array
);
946 if ( typeof array
.length
=== "number" ) {
947 for ( var l
= array
.length
; i
< l
; i
++ ) {
948 ret
.push( array
[i
] );
952 for ( ; array
[i
]; i
++ ) {
953 ret
.push( array
[i
] );
962 var sortOrder
, siblingCheck
;
964 if ( document
.documentElement
.compareDocumentPosition
) {
965 sortOrder = function( a
, b
) {
971 if ( !a
.compareDocumentPosition
|| !b
.compareDocumentPosition
) {
972 return a
.compareDocumentPosition
? -1 : 1;
975 return a
.compareDocumentPosition(b
) & 4 ? -1 : 1;
979 sortOrder = function( a
, b
) {
980 // The nodes are identical, we can exit early
985 // Fallback to using sourceIndex (in IE) if it's available on both nodes
986 } else if ( a
.sourceIndex
&& b
.sourceIndex
) {
987 return a
.sourceIndex
- b
.sourceIndex
;
997 // If the nodes are siblings (or identical) we can do a quick check
999 return siblingCheck( a
, b
);
1001 // If no parents were found then the nodes are disconnected
1002 } else if ( !aup
) {
1005 } else if ( !bup
) {
1009 // Otherwise they're somewhere else in the tree so we need
1010 // to build up a full list of the parentNodes for comparison
1013 cur
= cur
.parentNode
;
1020 cur
= cur
.parentNode
;
1026 // Start walking down the tree looking for a discrepancy
1027 for ( var i
= 0; i
< al
&& i
< bl
; i
++ ) {
1028 if ( ap
[i
] !== bp
[i
] ) {
1029 return siblingCheck( ap
[i
], bp
[i
] );
1033 // We ended someplace up the tree so do a sibling check
1035 siblingCheck( a
, bp
[i
], -1 ) :
1036 siblingCheck( ap
[i
], b
, 1 );
1039 siblingCheck = function( a
, b
, ret
) {
1044 var cur
= a
.nextSibling
;
1051 cur
= cur
.nextSibling
;
1058 // Check to see if the browser returns elements by name when
1059 // querying by getElementById (and provide a workaround)
1061 // We're going to inject a fake input element with a specified name
1062 var form
= document
.createElement("div"),
1063 id
= "script" + (new Date()).getTime(),
1064 root
= document
.documentElement
;
1066 form
.innerHTML
= "<a name='" + id
+ "'/>";
1068 // Inject it into the root element, check its status, and remove it quickly
1069 root
.insertBefore( form
, root
.firstChild
);
1071 // The workaround has to do additional checks after a getElementById
1072 // Which slows things down for other browsers (hence the branching)
1073 if ( document
.getElementById( id
) ) {
1074 Expr
.find
.ID = function( match
, context
, isXML
) {
1075 if ( typeof context
.getElementById
!== "undefined" && !isXML
) {
1076 var m
= context
.getElementById(match
[1]);
1079 m
.id
=== match
[1] || typeof m
.getAttributeNode
!== "undefined" && m
.getAttributeNode("id").nodeValue
=== match
[1] ?
1086 Expr
.filter
.ID = function( elem
, match
) {
1087 var node
= typeof elem
.getAttributeNode
!== "undefined" && elem
.getAttributeNode("id");
1089 return elem
.nodeType
=== 1 && node
&& node
.nodeValue
=== match
;
1093 root
.removeChild( form
);
1095 // release memory in IE
1100 // Check to see if the browser returns only elements
1101 // when doing getElementsByTagName("*")
1103 // Create a fake element
1104 var div
= document
.createElement("div");
1105 div
.appendChild( document
.createComment("") );
1107 // Make sure no comments are found
1108 if ( div
.getElementsByTagName("*").length
> 0 ) {
1109 Expr
.find
.TAG = function( match
, context
) {
1110 var results
= context
.getElementsByTagName( match
[1] );
1112 // Filter out possible comments
1113 if ( match
[1] === "*" ) {
1116 for ( var i
= 0; results
[i
]; i
++ ) {
1117 if ( results
[i
].nodeType
=== 1 ) {
1118 tmp
.push( results
[i
] );
1129 // Check to see if an attribute returns normalized href attributes
1130 div
.innerHTML
= "<a href='#'></a>";
1132 if ( div
.firstChild
&& typeof div
.firstChild
.getAttribute
!== "undefined" &&
1133 div
.firstChild
.getAttribute("href") !== "#" ) {
1135 Expr
.attrHandle
.href = function( elem
) {
1136 return elem
.getAttribute( "href", 2 );
1140 // release memory in IE
1145 if ( document
.querySelectorAll
&& false ) {
1147 var oldSizzle
= Sizzle
,
1148 div
= document
.createElement("div"),
1151 div
.innerHTML
= "<p class='TEST'></p>";
1153 // Safari can't handle uppercase or unicode characters when
1155 if ( div
.querySelectorAll
&& div
.querySelectorAll(".TEST").length
=== 0 ) {
1159 Sizzle = function( query
, context
, extra
, seed
) {
1160 context
= context
|| document
;
1162 // Only use querySelectorAll on non-XML documents
1163 // (ID selectors don't work in non-HTML documents)
1164 if ( !seed
&& !Sizzle
.isXML(context
) ) {
1165 // See if we find a selector to speed up
1166 var match
= /^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec( query
);
1168 if ( match
&& (context
.nodeType
=== 1 || context
.nodeType
=== 9) ) {
1169 // Speed-up: Sizzle("TAG")
1171 return makeArray( context
.getElementsByTagName( query
), extra
);
1173 // Speed-up: Sizzle(".CLASS")
1174 } else if ( match
[2] && Expr
.find
.CLASS
&& context
.getElementsByClassName
) {
1175 return makeArray( context
.getElementsByClassName( match
[2] ), extra
);
1179 if ( context
.nodeType
=== 9 ) {
1180 // Speed-up: Sizzle("body")
1181 // The body element only exists once, optimize finding it
1182 if ( query
=== "body" && context
.body
) {
1183 return makeArray( [ context
.body
], extra
);
1185 // Speed-up: Sizzle("#ID")
1186 } else if ( match
&& match
[3] ) {
1187 var elem
= context
.getElementById( match
[3] );
1189 // Check parentNode to catch when Blackberry 4.6 returns
1190 // nodes that are no longer in the document #6963
1191 if ( elem
&& elem
.parentNode
) {
1192 // Handle the case where IE and Opera return items
1193 // by name instead of ID
1194 if ( elem
.id
=== match
[3] ) {
1195 return makeArray( [ elem
], extra
);
1199 return makeArray( [], extra
);
1204 return makeArray( context
.querySelectorAll(query
), extra
);
1205 } catch(qsaError
) {}
1207 // qSA works strangely on Element-rooted queries
1208 // We can work around this by specifying an extra ID on the root
1209 // and working up from there (Thanks to Andrew Dupont for the technique)
1210 // IE 8 doesn't work on object elements
1211 } else if ( context
.nodeType
=== 1 && context
.nodeName
.toLowerCase() !== "object" ) {
1212 var oldContext
= context
,
1213 old
= context
.getAttribute( "id" ),
1215 hasParent
= context
.parentNode
,
1216 relativeHierarchySelector
= /^\s*[+~]/.test( query
);
1219 context
.setAttribute( "id", nid
);
1221 nid
= nid
.replace( /'/g, "\\$&" );
1223 if ( relativeHierarchySelector && hasParent ) {
1224 context = context.parentNode;
1228 if ( !relativeHierarchySelector || hasParent ) {
1229 return makeArray( context.querySelectorAll( "[id='" + nid + "'] " + query ), extra );
1232 } catch(pseudoError) {
1235 oldContext.removeAttribute( "id" );
1241 return oldSizzle(query, context, extra, seed);
1244 for ( var prop in oldSizzle ) {
1245 Sizzle[ prop ] = oldSizzle[ prop ];
1248 // release memory in IE
1254 var html = document.documentElement,
1255 matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector;
1258 // Check to see if it's possible to
do matchesSelector
1259 // on a disconnected node (IE 9 fails this)
1260 var disconnectedMatch
= !matches
.call( document
.createElement( "div" ), "div" ),
1261 pseudoWorks
= false;
1264 // This should fail with an exception
1265 // Gecko does not error, returns false instead
1266 matches
.call( document
.documentElement
, "[test!='']:sizzle" );
1268 } catch( pseudoError
) {
1272 Sizzle
.matchesSelector = function( node
, expr
) {
1273 // Make sure that attribute selectors are quoted
1274 expr
= expr
.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']");
1276 if ( !Sizzle
.isXML( node
) ) {
1278 if ( pseudoWorks
|| !Expr
.match
.PSEUDO
.test( expr
) && !/!=/.test( expr
) ) {
1279 var ret
= matches
.call( node
, expr
);
1281 // IE 9's matchesSelector returns false on disconnected nodes
1282 if ( ret
|| !disconnectedMatch
||
1283 // As well, disconnected nodes are said to be in a document
1284 // fragment in IE 9, so check for that
1285 node
.document
&& node
.document
.nodeType
!== 11 ) {
1292 return Sizzle(expr
, null, null, [node
]).length
> 0;
1298 var div
= document
.createElement("div");
1300 div
.innerHTML
= "<div class='test e'></div><div class='test'></div>";
1302 // Opera can't find a second classname (in 9.6)
1303 // Also, make sure that getElementsByClassName actually exists
1304 if ( !div
.getElementsByClassName
|| div
.getElementsByClassName("e").length
=== 0 ) {
1308 // Safari caches class attributes, doesn't catch changes (in 3.2)
1309 div
.lastChild
.className
= "e";
1311 if ( div
.getElementsByClassName("e").length
=== 1 ) {
1315 Expr
.order
.splice(1, 0, "CLASS");
1316 Expr
.find
.CLASS = function( match
, context
, isXML
) {
1317 if ( typeof context
.getElementsByClassName
!== "undefined" && !isXML
) {
1318 return context
.getElementsByClassName(match
[1]);
1322 // release memory in IE
1326 function dirNodeCheck( dir
, cur
, doneName
, checkSet
, nodeCheck
, isXML
) {
1327 for ( var i
= 0, l
= checkSet
.length
; i
< l
; i
++ ) {
1328 var elem
= checkSet
[i
];
1336 if ( elem
[ expando
] === doneName
) {
1337 match
= checkSet
[elem
.sizset
];
1341 if ( elem
.nodeType
=== 1 && !isXML
){
1342 elem
[ expando
] = doneName
;
1346 if ( elem
.nodeName
.toLowerCase() === cur
) {
1354 checkSet
[i
] = match
;
1359 function dirCheck( dir
, cur
, doneName
, checkSet
, nodeCheck
, isXML
) {
1360 for ( var i
= 0, l
= checkSet
.length
; i
< l
; i
++ ) {
1361 var elem
= checkSet
[i
];
1369 if ( elem
[ expando
] === doneName
) {
1370 match
= checkSet
[elem
.sizset
];
1374 if ( elem
.nodeType
=== 1 ) {
1376 elem
[ expando
] = doneName
;
1380 if ( typeof cur
!== "string" ) {
1381 if ( elem
=== cur
) {
1386 } else if ( Sizzle
.filter( cur
, [elem
] ).length
> 0 ) {
1395 checkSet
[i
] = match
;
1400 if ( document
.documentElement
.contains
) {
1401 Sizzle
.contains = function( a
, b
) {
1402 return a
!== b
&& (a
.contains
? a
.contains(b
) : true);
1405 } else if ( document
.documentElement
.compareDocumentPosition
) {
1406 Sizzle
.contains = function( a
, b
) {
1407 return !!(a
.compareDocumentPosition(b
) & 16);
1411 Sizzle
.contains = function() {
1416 Sizzle
.isXML = function( elem
) {
1417 // documentElement is verified for cases where it doesn't yet exist
1418 // (such as loading iframes in IE - #4833)
1419 var documentElement
= (elem
? elem
.ownerDocument
|| elem
: 0).documentElement
;
1421 return documentElement
? documentElement
.nodeName
!== "HTML" : false;
1424 var posProcess = function( selector
, context
, seed
) {
1428 root
= context
.nodeType
? [context
] : context
;
1430 // Position selectors must be done after the filter
1431 // And so must :not(positional) so we move all PSEUDOs to the end
1432 while ( (match
= Expr
.match
.PSEUDO
.exec( selector
)) ) {
1434 selector
= selector
.replace( Expr
.match
.PSEUDO
, "" );
1437 selector
= Expr
.relative
[selector
] ? selector
+ "*" : selector
;
1439 for ( var i
= 0, l
= root
.length
; i
< l
; i
++ ) {
1440 Sizzle( selector
, root
[i
], tmpSet
, seed
);
1443 return Sizzle
.filter( later
, tmpSet
);