]>
git.wh0rd.org - tt-rss.git/blob - lib/dojo/_base/query-sizzle.js
2 Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved.
3 Available via Academic Free License >= 2.1 OR the modified BSD license.
4 see: http://dojotoolkit.org/license for details
8 if(!dojo
._hasResource
["dojo._base.query"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
9 dojo
._hasResource
["dojo._base.query"] = true;
11 * Sizzle CSS Selector Engine - v0.9
12 * Copyright 2009, John Resig
13 * Redistributed with the Dojo Toolkit under the terms of the New BSD license.
14 * More information: http://sizzlejs.com/
16 * This version from github, dated 1/23/2009, commit: e374a73bbffc12ec3b5f252e7f76e593c508dfa5
17 * Modified for dojo loader, and to fit into dojo namespace. This was done by passing
18 * dojo object to anonymous function, then assigning Sizzle to dojo.Sizzle instead of window.Sizzle.
19 * Then an alias for dojo.query and dojo._filterQueryResult(). dojo.psuedos is not mapped.
20 * Finally, dojo.provide/require added.
23 var startDojoMappings= function(dojo
) {
24 //Start Dojo mappings.
25 dojo
.query = function(/*String*/ query
, /*String|DOMNode?*/ root
, /*Function?*/listCtor
){
26 listCtor
= listCtor
|| dojo
.NodeList
;
29 return new listCtor();
32 if(query
.constructor == listCtor
){
35 if(!dojo
.isString(query
)){
36 return new listCtor(query
); // dojo.NodeList
38 if(dojo
.isString(root
)){
39 root
= dojo
.byId(root
);
40 if(!root
){ return new listCtor(); }
43 return dojo
.Sizzle(query
, root
, new listCtor());
46 dojo
._filterQueryResult = function(nodeList
, simpleFilter
){
47 return dojo
.Sizzle
.filter(simpleFilter
, nodeList
);
51 //Main Sizzle code follows...
52 //ns argument, added for dojo, used at the end of the file.
53 var defineSizzle= function(ns
){
55 var chunker
= /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|[^[\]]+)+\]|\\.|[^ >+~,(\[]+)+|[>+~])(\s*,\s*)?/g,
57 toString
= Object
.prototype.toString
;
59 var Sizzle = function(selector
, context
, results
, seed
) {
60 results
= results
|| [];
61 context
= context
|| document
;
63 if ( context
.nodeType
!== 1 && context
.nodeType
!== 9 )
66 if ( !selector
|| typeof selector
!== "string" ) {
70 var parts
= [], m
, set, checkSet
, check
, mode
, extra
, prune
= true;
72 // Reset the position of the chunker regexp (start from head)
73 chunker
.lastIndex
= 0;
75 while ( (m
= chunker
.exec(selector
)) !== null ) {
79 extra
= RegExp
.rightContext
;
84 if ( parts
.length
> 1 && Expr
.match
.POS
.exec( selector
) ) {
85 if ( parts
.length
=== 2 && Expr
.relative
[ parts
[0] ] ) {
86 var later
= "", match
;
88 // Position selectors must be done after the filter
89 while ( (match
= Expr
.match
.POS
.exec( selector
)) ) {
91 selector
= selector
.replace( Expr
.match
.POS
, "" );
94 set = Sizzle
.filter( later
, Sizzle( selector
, context
) );
96 set = Expr
.relative
[ parts
[0] ] ?
98 Sizzle( parts
.shift(), context
);
100 while ( parts
.length
) {
103 selector
= parts
.shift();
104 if ( Expr
.relative
[ selector
] )
105 selector
+= parts
.shift();
107 for ( var i
= 0, l
= set.length
; i
< l
; i
++ ) {
108 Sizzle( selector
, set[i
], tmpSet
);
116 { expr
: parts
.pop(), set: makeArray(seed
) } :
117 Sizzle
.find( parts
.pop(), parts
.length
=== 1 && context
.parentNode
? context
.parentNode
: context
);
118 set = Sizzle
.filter( ret
.expr
, ret
.set );
120 if ( parts
.length
> 0 ) {
121 checkSet
= makeArray(set);
126 while ( parts
.length
) {
127 var cur
= parts
.pop(), pop
= cur
;
129 if ( !Expr
.relative
[ cur
] ) {
139 Expr
.relative
[ cur
]( checkSet
, pop
);
148 throw "Syntax error, unrecognized expression: " + (cur
|| selector
);
151 if ( toString
.call(checkSet
) === "[object Array]" ) {
153 results
.push
.apply( results
, checkSet
);
154 } else if ( context
.nodeType
=== 1 ) {
155 for ( var i
= 0; checkSet
[i
] != null; i
++ ) {
156 if ( checkSet
[i
] && (checkSet
[i
] === true || checkSet
[i
].nodeType
=== 1 && contains(context
, checkSet
[i
])) ) {
157 results
.push( set[i
] );
161 for ( var i
= 0; checkSet
[i
] != null; i
++ ) {
162 if ( checkSet
[i
] && checkSet
[i
].nodeType
=== 1 ) {
163 results
.push( set[i
] );
168 makeArray( checkSet
, results
);
172 Sizzle( extra
, context
, results
, seed
);
178 Sizzle
.matches = function(expr
, set){
179 return Sizzle(expr
, null, null, set);
182 Sizzle
.find = function(expr
, context
){
189 for ( var i
= 0, l
= Expr
.order
.length
; i
< l
; i
++ ) {
190 var type
= Expr
.order
[i
], match
;
192 if ( (match
= Expr
.match
[ type
].exec( expr
)) ) {
193 var left
= RegExp
.leftContext
;
195 if ( left
.substr( left
.length
- 1 ) !== "\\" ) {
196 match
[1] = (match
[1] || "").replace(/\\/g
, "");
197 set = Expr
.find
[ type
]( match
, context
);
199 expr
= expr
.replace( Expr
.match
[ type
], "" );
207 set = context
.getElementsByTagName("*");
210 return {set: set, expr
: expr
};
213 Sizzle
.filter = function(expr
, set, inplace
, not
){
214 var old
= expr
, result
= [], curLoop
= set, match
, anyFound
;
216 while ( expr
&& set.length
) {
217 for ( var type
in Expr
.filter
) {
218 if ( (match
= Expr
.match
[ type
].exec( expr
)) != null ) {
219 var filter
= Expr
.filter
[ type
], goodArray
= null, goodPos
= 0, found
, item
;
222 if ( curLoop
== result
) {
226 if ( Expr
.preFilter
[ type
] ) {
227 match
= Expr
.preFilter
[ type
]( match
, curLoop
, inplace
, result
, not
);
230 anyFound
= found
= true;
231 } else if ( match
[0] === true ) {
233 var last
= null, elem
;
234 for ( var i
= 0; (elem
= curLoop
[i
]) !== undefined; i
++ ) {
235 if ( elem
&& last
!== elem
) {
236 goodArray
.push( elem
);
244 for ( var i
= 0; (item
= curLoop
[i
]) !== undefined; i
++ ) {
246 if ( goodArray
&& item
!= goodArray
[goodPos
] ) {
250 found
= filter( item
, match
, goodPos
, goodArray
);
251 var pass
= not
^ !!found
;
253 if ( inplace
&& found
!= null ) {
267 if ( found
!== undefined ) {
272 expr
= expr
.replace( Expr
.match
[ type
], "" );
283 expr
= expr
.replace(/\s*,\s*/, "");
285 // Improper expression
287 if ( anyFound
== null ) {
288 throw "Syntax error, unrecognized expression: " + expr
;
300 var Expr
= Sizzle
.selectors
= {
301 order
: [ "ID", "NAME", "TAG" ],
303 ID
: /#((?:[\w\u0128-\uFFFF_-]|\\.)+)/,
304 CLASS
: /\.((?:[\w\u0128-\uFFFF_-]|\\.)+)/,
305 NAME
: /\[name=['"]*((?:[\w\u0128-\uFFFF_-]|\\.)+)['"]*\]/,
306 ATTR
: /\[((?:[\w\u0128-\uFFFF_-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\]/,
307 TAG
: /^((?:[\w\u0128-\uFFFF\*_-]|\\.)+)/,
308 CHILD
: /:(only|nth|last|first)-child\(?(even|odd|[\dn+-]*)\)?/,
309 POS
: /:(nth|eq|gt|lt|first|last|even|odd)\(?(\d*)\)?(?:[^-]|$)/,
310 PSEUDO
: /:((?:[\w\u0128-\uFFFF_-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/
313 "class": "className",
317 "+": function(checkSet
, part
){
318 for ( var i
= 0, l
= checkSet
.length
; i
< l
; i
++ ) {
319 var elem
= checkSet
[i
];
321 var cur
= elem
.previousSibling
;
322 while ( cur
&& cur
.nodeType
!== 1 ) {
323 cur
= cur
.previousSibling
;
325 checkSet
[i
] = typeof part
=== "string" ?
331 if ( typeof part
=== "string" ) {
332 Sizzle
.filter( part
, checkSet
, true );
335 ">": function(checkSet
, part
){
336 if ( typeof part
=== "string" && !/\W/.test(part
) ) {
337 part
= part
.toUpperCase();
339 for ( var i
= 0, l
= checkSet
.length
; i
< l
; i
++ ) {
340 var elem
= checkSet
[i
];
342 var parent
= elem
.parentNode
;
343 checkSet
[i
] = parent
.nodeName
=== part
? parent
: false;
347 for ( var i
= 0, l
= checkSet
.length
; i
< l
; i
++ ) {
348 var elem
= checkSet
[i
];
350 checkSet
[i
] = typeof part
=== "string" ?
352 elem
.parentNode
=== part
;
356 if ( typeof part
=== "string" ) {
357 Sizzle
.filter( part
, checkSet
, true );
361 "": function(checkSet
, part
){
362 var doneName
= "done" + (done
++), checkFn
= dirCheck
;
364 if ( !part
.match(/\W/) ) {
365 var nodeCheck
= part
= part
.toUpperCase();
366 checkFn
= dirNodeCheck
;
369 checkFn("parentNode", part
, doneName
, checkSet
, nodeCheck
);
371 "~": function(checkSet
, part
){
372 var doneName
= "done" + (done
++), checkFn
= dirCheck
;
374 if ( typeof part
=== "string" && !part
.match(/\W/) ) {
375 var nodeCheck
= part
= part
.toUpperCase();
376 checkFn
= dirNodeCheck
;
379 checkFn("previousSibling", part
, doneName
, checkSet
, nodeCheck
);
383 ID: function(match
, context
){
384 if ( context
.getElementById
) {
385 var m
= context
.getElementById(match
[1]);
389 NAME: function(match
, context
){
390 return context
.getElementsByName
? context
.getElementsByName(match
[1]) : null;
392 TAG: function(match
, context
){
393 return context
.getElementsByTagName(match
[1]);
397 CLASS: function(match
, curLoop
, inplace
, result
, not
){
398 match
= " " + match
[1].replace(/\\/g
, "") + " ";
400 for ( var i
= 0; curLoop
[i
]; i
++ ) {
401 if ( not
^ (" " + curLoop
[i
].className
+ " ").indexOf(match
) >= 0 ) {
403 result
.push( curLoop
[i
] );
404 } else if ( inplace
) {
414 TAG: function(match
){
415 return match
[1].toUpperCase();
417 CHILD: function(match
){
418 if ( match
[1] == "nth" ) {
419 // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'
420 var test
= /(-?)(\d*)n((?:\+|-)?\d*)/.exec(
421 match
[2] == "even" && "2n" || match
[2] == "odd" && "2n+1" ||
422 !/\D/.test( match
[2] ) && "0n+" + match
[2] || match
[2]);
424 // calculate the numbers (first)n+(last) including if they are negative
425 match
[2] = (test
[1] + (test
[2] || 1)) - 0;
426 match
[3] = test
[3] - 0;
429 // TODO: Move to normal caching system
430 match
[0] = "done" + (done
++);
434 ATTR: function(match
){
437 if ( Expr
.attrMap
[name
] ) {
438 match
[1] = Expr
.attrMap
[name
];
441 if ( match
[2] === "~=" ) {
442 match
[4] = " " + match
[4] + " ";
447 PSEUDO: function(match
, curLoop
, inplace
, result
, not
){
448 if ( match
[1] === "not" ) {
449 // If we're dealing with a complex expression, or a simple one
450 if ( match
[3].match(chunker
).length
> 1 ) {
451 match
[3] = Sizzle(match
[3], null, null, curLoop
);
453 var ret
= Sizzle
.filter(match
[3], curLoop
, inplace
, true ^ not
);
455 result
.push
.apply( result
, ret
);
463 POS: function(match
){
464 match
.unshift( true );
469 enabled: function(elem
){
470 return elem
.disabled
=== false && elem
.type
!== "hidden";
472 disabled: function(elem
){
473 return elem
.disabled
=== true;
475 checked: function(elem
){
476 return elem
.checked
=== true;
478 selected: function(elem
){
479 // Accessing this property makes selected-by-default
480 // options in Safari work properly
481 elem
.parentNode
.selectedIndex
;
482 return elem
.selected
=== true;
484 parent: function(elem
){
485 return !!elem
.firstChild
;
487 empty: function(elem
){
488 return !elem
.firstChild
;
490 has: function(elem
, i
, match
){
491 return !!Sizzle( match
[3], elem
).length
;
493 header: function(elem
){
494 return /h\d/i.test( elem
.nodeName
);
496 text: function(elem
){
497 return "text" === elem
.type
;
499 radio: function(elem
){
500 return "radio" === elem
.type
;
502 checkbox: function(elem
){
503 return "checkbox" === elem
.type
;
505 file: function(elem
){
506 return "file" === elem
.type
;
508 password: function(elem
){
509 return "password" === elem
.type
;
511 submit: function(elem
){
512 return "submit" === elem
.type
;
514 image: function(elem
){
515 return "image" === elem
.type
;
517 reset: function(elem
){
518 return "reset" === elem
.type
;
520 button: function(elem
){
521 return "button" === elem
.type
|| elem
.nodeName
.toUpperCase() === "BUTTON";
523 input: function(elem
){
524 return /input|select|textarea|button/i.test(elem
.nodeName
);
528 first: function(elem
, i
){
531 last: function(elem
, i
, match
, array
){
532 return i
=== array
.length
- 1;
534 even: function(elem
, i
){
537 odd: function(elem
, i
){
540 lt: function(elem
, i
, match
){
541 return i
< match
[3] - 0;
543 gt: function(elem
, i
, match
){
544 return i
> match
[3] - 0;
546 nth: function(elem
, i
, match
){
547 return match
[3] - 0 == i
;
549 eq: function(elem
, i
, match
){
550 return match
[3] - 0 == i
;
554 CHILD: function(elem
, match
){
555 var type
= match
[1], parent
= elem
.parentNode
;
557 var doneName
= match
[0];
559 if ( parent
&& !parent
[ doneName
] ) {
562 for ( var node
= parent
.firstChild
; node
; node
= node
.nextSibling
) {
563 if ( node
.nodeType
== 1 ) {
564 node
.nodeIndex
= count
++;
568 parent
[ doneName
] = count
- 1;
571 if ( type
== "first" ) {
572 return elem
.nodeIndex
== 1;
573 } else if ( type
== "last" ) {
574 return elem
.nodeIndex
== parent
[ doneName
];
575 } else if ( type
== "only" ) {
576 return parent
[ doneName
] == 1;
577 } else if ( type
== "nth" ) {
578 var add
= false, first
= match
[2], last
= match
[3];
580 if ( first
== 1 && last
== 0 ) {
585 if ( elem
.nodeIndex
== last
) {
588 } else if ( (elem
.nodeIndex
- last
) % first
== 0 && (elem
.nodeIndex
- last
) / first
>= 0 ) {
595 PSEUDO: function(elem
, match
, i
, array
){
596 var name
= match
[1], filter
= Expr
.filters
[ name
];
599 return filter( elem
, i
, match
, array
);
600 } else if ( name
=== "contains" ) {
601 return (elem
.textContent
|| elem
.innerText
|| "").indexOf(match
[3]) >= 0;
602 } else if ( name
=== "not" ) {
605 for ( var i
= 0, l
= not
.length
; i
< l
; i
++ ) {
606 if ( not
[i
] === elem
) {
614 ID: function(elem
, match
){
615 return elem
.nodeType
=== 1 && elem
.getAttribute("id") === match
;
617 TAG: function(elem
, match
){
618 return (match
=== "*" && elem
.nodeType
=== 1) || elem
.nodeName
=== match
;
620 CLASS: function(elem
, match
){
621 return match
.test( elem
.className
);
623 ATTR: function(elem
, match
){
624 var result
= elem
[ match
[1] ] || elem
.getAttribute( match
[1] ), value
= result
+ "", type
= match
[2], check
= match
[4];
625 return result
== null ?
630 value
.indexOf(check
) >= 0 :
632 (" " + value
+ " ").indexOf(check
) >= 0 :
638 value
.indexOf(check
) === 0 :
640 value
.substr(value
.length
- check
.length
) === check
:
642 value
=== check
|| value
.substr(0, check
.length
+ 1) === check
+ "-" :
645 POS: function(elem
, match
, i
, array
){
646 var name
= match
[2], filter
= Expr
.setFilters
[ name
];
649 return filter( elem
, i
, match
, array
);
655 for ( var type
in Expr
.match
) {
656 Expr
.match
[ type
] = RegExp( Expr
.match
[ type
].source
+ /(?![^\[]*\])(?![^\(]*\))/.source
);
659 var makeArray = function(array
, results
) {
660 array
= Array
.prototype.slice
.call( array
);
663 results
.push
.apply( results
, array
);
670 // Perform a simple check to determine if the browser is capable of
671 // converting a NodeList to an array using builtin methods.
673 Array
.prototype.slice
.call( document
.documentElement
.childNodes
);
675 // Provide a fallback method if it does not work
677 makeArray = function(array
, results
) {
678 var ret
= results
|| [];
680 if ( toString
.call(array
) === "[object Array]" ) {
681 Array
.prototype.push
.apply( ret
, array
);
683 if ( typeof array
.length
=== "number" ) {
684 for ( var i
= 0, l
= array
.length
; i
< l
; i
++ ) {
685 ret
.push( array
[i
] );
688 for ( var i
= 0; array
[i
]; i
++ ) {
689 ret
.push( array
[i
] );
698 // Check to see if the browser returns elements by name when
699 // querying by getElementById (and provide a workaround)
701 // We're going to inject a fake input element with a specified name
702 var form
= document
.createElement("form"),
703 id
= "script" + (new Date
).getTime();
704 form
.innerHTML
= "<input name='" + id
+ "'/>";
706 // Inject it into the root element, check its status, and remove it quickly
707 var root
= document
.documentElement
;
708 root
.insertBefore( form
, root
.firstChild
);
710 // The workaround has to do additional checks after a getElementById
711 // Which slows things down for other browsers (hence the branching)
712 if ( !!document
.getElementById( id
) ) {
713 Expr
.find
.ID = function(match
, context
){
714 if ( context
.getElementById
) {
715 var m
= context
.getElementById(match
[1]);
716 return m
? m
.id
=== match
[1] || m
.getAttributeNode
&& m
.getAttributeNode("id").nodeValue
=== match
[1] ? [m
] : undefined : [];
720 Expr
.filter
.ID = function(elem
, match
){
721 var node
= elem
.getAttributeNode
&& elem
.getAttributeNode("id");
722 return elem
.nodeType
=== 1 && node
&& node
.nodeValue
=== match
;
726 root
.removeChild( form
);
729 // Check to see if the browser returns only elements
730 // when doing getElementsByTagName("*")
732 // Create a fake element
733 var div
= document
.createElement("div");
734 div
.appendChild( document
.createComment("") );
736 // Make sure no comments are found
737 if ( div
.getElementsByTagName("*").length
> 0 ) {
738 Expr
.find
.TAG = function(match
, context
){
739 var results
= context
.getElementsByTagName(match
[1]);
741 // Filter out possible comments
742 if ( match
[1] === "*" ) {
745 for ( var i
= 0; results
[i
]; i
++ ) {
746 if ( results
[i
].nodeType
=== 1 ) {
747 tmp
.push( results
[i
] );
759 if ( document
.querySelectorAll
) (function(){
760 var oldSizzle
= Sizzle
;
762 Sizzle = function(query
, context
, extra
, seed
){
763 context
= context
|| document
;
765 if ( !seed
&& context
.nodeType
=== 9 ) {
767 return makeArray( context
.querySelectorAll(query
), extra
);
771 return oldSizzle(query
, context
, extra
, seed
);
774 Sizzle
.find
= oldSizzle
.find
;
775 Sizzle
.filter
= oldSizzle
.filter
;
776 Sizzle
.selectors
= oldSizzle
.selectors
;
777 Sizzle
.matches
= oldSizzle
.matches
;
780 if ( document
.documentElement
.getElementsByClassName
) {
781 Expr
.order
.splice(1, 0, "CLASS");
782 Expr
.find
.CLASS = function(match
, context
) {
783 return context
.getElementsByClassName(match
[1]);
787 function dirNodeCheck( dir
, cur
, doneName
, checkSet
, nodeCheck
) {
788 for ( var i
= 0, l
= checkSet
.length
; i
< l
; i
++ ) {
789 var elem
= checkSet
[i
];
794 while ( elem
&& elem
.nodeType
) {
795 var done
= elem
[doneName
];
797 match
= checkSet
[ done
];
801 if ( elem
.nodeType
=== 1 )
804 if ( elem
.nodeName
=== cur
) {
817 function dirCheck( dir
, cur
, doneName
, checkSet
, nodeCheck
) {
818 for ( var i
= 0, l
= checkSet
.length
; i
< l
; i
++ ) {
819 var elem
= checkSet
[i
];
824 while ( elem
&& elem
.nodeType
) {
825 if ( elem
[doneName
] ) {
826 match
= checkSet
[ elem
[doneName
] ];
830 if ( elem
.nodeType
=== 1 ) {
833 if ( typeof cur
!== "string" ) {
834 if ( elem
=== cur
) {
839 } else if ( Sizzle
.filter( cur
, [elem
] ).length
> 0 ) {
853 var contains
= document
.compareDocumentPosition
? function(a
, b
){
854 return a
.compareDocumentPosition(b
) & 16;
856 return a
!== b
&& (a
.contains
? a
.contains(b
) : true);
868 // must be in a built version that stripped out the define above
869 dojo
.provide("dojo._base.query");
870 dojo
.require("dojo._base.NodeList");
872 } // else must be in a source version (or a build that likes define)
874 defineSizzle(window
);