|
1 /** |
|
2 * Sizzle.js |
|
3 * |
|
4 * Copyright, Moxiecode Systems AB |
|
5 * Released under LGPL License. |
|
6 * |
|
7 * License: http://www.tinymce.com/license |
|
8 * Contributing: http://www.tinymce.com/contributing |
|
9 * |
|
10 * @ignore-file |
|
11 */ |
|
12 |
|
13 /*jshint bitwise:false, expr:true, noempty:false, sub:true, eqnull:true, latedef:false, maxlen:255 */ |
|
14 /*eslint dot-notation:0, no-empty:0, no-cond-assign:0, no-unused-expressions:0, new-cap:0 */ |
|
15 /*eslint no-nested-ternary:0, func-style:0, no-bitwise:0, max-len:0, brace-style:0, no-return-assign:0, no-multi-spaces:0 */ |
|
16 |
|
17 /** |
|
18 * Sizzle CSS Selector Engine v@VERSION |
|
19 * http://sizzlejs.com/ |
|
20 * |
|
21 * Copyright 2008, 2014 jQuery Foundation, Inc. and other contributors |
|
22 * Released under the MIT license |
|
23 * http://jquery.org/license |
|
24 * |
|
25 * Date: @DATE |
|
26 */ |
|
27 define("tinymce/dom/Sizzle", [], function() { |
|
28 var i, |
|
29 support, |
|
30 Expr, |
|
31 getText, |
|
32 isXML, |
|
33 tokenize, |
|
34 compile, |
|
35 select, |
|
36 outermostContext, |
|
37 sortInput, |
|
38 hasDuplicate, |
|
39 |
|
40 // Local document vars |
|
41 setDocument, |
|
42 document, |
|
43 docElem, |
|
44 documentIsHTML, |
|
45 rbuggyQSA, |
|
46 rbuggyMatches, |
|
47 matches, |
|
48 contains, |
|
49 |
|
50 // Instance-specific data |
|
51 expando = "sizzle" + -(new Date()), |
|
52 preferredDoc = window.document, |
|
53 dirruns = 0, |
|
54 done = 0, |
|
55 classCache = createCache(), |
|
56 tokenCache = createCache(), |
|
57 compilerCache = createCache(), |
|
58 sortOrder = function( a, b ) { |
|
59 if ( a === b ) { |
|
60 hasDuplicate = true; |
|
61 } |
|
62 return 0; |
|
63 }, |
|
64 |
|
65 // General-purpose constants |
|
66 strundefined = typeof undefined, |
|
67 MAX_NEGATIVE = 1 << 31, |
|
68 |
|
69 // Instance methods |
|
70 hasOwn = ({}).hasOwnProperty, |
|
71 arr = [], |
|
72 pop = arr.pop, |
|
73 push_native = arr.push, |
|
74 push = arr.push, |
|
75 slice = arr.slice, |
|
76 // Use a stripped-down indexOf if we can't use a native one |
|
77 indexOf = arr.indexOf || function( elem ) { |
|
78 var i = 0, |
|
79 len = this.length; |
|
80 for ( ; i < len; i++ ) { |
|
81 if ( this[i] === elem ) { |
|
82 return i; |
|
83 } |
|
84 } |
|
85 return -1; |
|
86 }, |
|
87 |
|
88 booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped", |
|
89 |
|
90 // Regular expressions |
|
91 |
|
92 // http://www.w3.org/TR/css3-selectors/#whitespace |
|
93 whitespace = "[\\x20\\t\\r\\n\\f]", |
|
94 |
|
95 // http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier |
|
96 identifier = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+", |
|
97 |
|
98 // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors |
|
99 attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + |
|
100 // Operator (capture 2) |
|
101 "*([*^$|!~]?=)" + whitespace + |
|
102 // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]" |
|
103 "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace + |
|
104 "*\\]", |
|
105 |
|
106 pseudos = ":(" + identifier + ")(?:\\((" + |
|
107 // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: |
|
108 // 1. quoted (capture 3; capture 4 or capture 5) |
|
109 "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + |
|
110 // 2. simple (capture 6) |
|
111 "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + |
|
112 // 3. anything else (capture 2) |
|
113 ".*" + |
|
114 ")\\)|)", |
|
115 |
|
116 // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter |
|
117 rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), |
|
118 |
|
119 rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), |
|
120 rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ), |
|
121 |
|
122 rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ), |
|
123 |
|
124 rpseudo = new RegExp( pseudos ), |
|
125 ridentifier = new RegExp( "^" + identifier + "$" ), |
|
126 |
|
127 matchExpr = { |
|
128 "ID": new RegExp( "^#(" + identifier + ")" ), |
|
129 "CLASS": new RegExp( "^\\.(" + identifier + ")" ), |
|
130 "TAG": new RegExp( "^(" + identifier + "|[*])" ), |
|
131 "ATTR": new RegExp( "^" + attributes ), |
|
132 "PSEUDO": new RegExp( "^" + pseudos ), |
|
133 "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + |
|
134 "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + |
|
135 "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), |
|
136 "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), |
|
137 // For use in libraries implementing .is() |
|
138 // We use this for POS matching in `select` |
|
139 "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + |
|
140 whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) |
|
141 }, |
|
142 |
|
143 rinputs = /^(?:input|select|textarea|button)$/i, |
|
144 rheader = /^h\d$/i, |
|
145 |
|
146 rnative = /^[^{]+\{\s*\[native \w/, |
|
147 |
|
148 // Easily-parseable/retrievable ID or TAG or CLASS selectors |
|
149 rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, |
|
150 |
|
151 rsibling = /[+~]/, |
|
152 rescape = /'|\\/g, |
|
153 |
|
154 // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters |
|
155 runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ), |
|
156 funescape = function( _, escaped, escapedWhitespace ) { |
|
157 var high = "0x" + escaped - 0x10000; |
|
158 // NaN means non-codepoint |
|
159 // Support: Firefox<24 |
|
160 // Workaround erroneous numeric interpretation of +"0x" |
|
161 return high !== high || escapedWhitespace ? |
|
162 escaped : |
|
163 high < 0 ? |
|
164 // BMP codepoint |
|
165 String.fromCharCode( high + 0x10000 ) : |
|
166 // Supplemental Plane codepoint (surrogate pair) |
|
167 String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); |
|
168 }; |
|
169 |
|
170 // Optimize for push.apply( _, NodeList ) |
|
171 try { |
|
172 push.apply( |
|
173 (arr = slice.call( preferredDoc.childNodes )), |
|
174 preferredDoc.childNodes |
|
175 ); |
|
176 // Support: Android<4.0 |
|
177 // Detect silently failing push.apply |
|
178 arr[ preferredDoc.childNodes.length ].nodeType; |
|
179 } catch ( e ) { |
|
180 push = { apply: arr.length ? |
|
181 |
|
182 // Leverage slice if possible |
|
183 function( target, els ) { |
|
184 push_native.apply( target, slice.call(els) ); |
|
185 } : |
|
186 |
|
187 // Support: IE<9 |
|
188 // Otherwise append directly |
|
189 function( target, els ) { |
|
190 var j = target.length, |
|
191 i = 0; |
|
192 // Can't trust NodeList.length |
|
193 while ( (target[j++] = els[i++]) ) {} |
|
194 target.length = j - 1; |
|
195 } |
|
196 }; |
|
197 } |
|
198 |
|
199 function Sizzle( selector, context, results, seed ) { |
|
200 var match, elem, m, nodeType, |
|
201 // QSA vars |
|
202 i, groups, old, nid, newContext, newSelector; |
|
203 |
|
204 if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) { |
|
205 setDocument( context ); |
|
206 } |
|
207 |
|
208 context = context || document; |
|
209 results = results || []; |
|
210 |
|
211 if ( !selector || typeof selector !== "string" ) { |
|
212 return results; |
|
213 } |
|
214 |
|
215 if ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) { |
|
216 return []; |
|
217 } |
|
218 |
|
219 if ( documentIsHTML && !seed ) { |
|
220 |
|
221 // Shortcuts |
|
222 if ( (match = rquickExpr.exec( selector )) ) { |
|
223 // Speed-up: Sizzle("#ID") |
|
224 if ( (m = match[1]) ) { |
|
225 if ( nodeType === 9 ) { |
|
226 elem = context.getElementById( m ); |
|
227 // Check parentNode to catch when Blackberry 4.6 returns |
|
228 // nodes that are no longer in the document (jQuery #6963) |
|
229 if ( elem && elem.parentNode ) { |
|
230 // Handle the case where IE, Opera, and Webkit return items |
|
231 // by name instead of ID |
|
232 if ( elem.id === m ) { |
|
233 results.push( elem ); |
|
234 return results; |
|
235 } |
|
236 } else { |
|
237 return results; |
|
238 } |
|
239 } else { |
|
240 // Context is not a document |
|
241 if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) && |
|
242 contains( context, elem ) && elem.id === m ) { |
|
243 results.push( elem ); |
|
244 return results; |
|
245 } |
|
246 } |
|
247 |
|
248 // Speed-up: Sizzle("TAG") |
|
249 } else if ( match[2] ) { |
|
250 push.apply( results, context.getElementsByTagName( selector ) ); |
|
251 return results; |
|
252 |
|
253 // Speed-up: Sizzle(".CLASS") |
|
254 } else if ( (m = match[3]) && support.getElementsByClassName ) { |
|
255 push.apply( results, context.getElementsByClassName( m ) ); |
|
256 return results; |
|
257 } |
|
258 } |
|
259 |
|
260 // QSA path |
|
261 if ( support.qsa && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) { |
|
262 nid = old = expando; |
|
263 newContext = context; |
|
264 newSelector = nodeType === 9 && selector; |
|
265 |
|
266 // qSA works strangely on Element-rooted queries |
|
267 // We can work around this by specifying an extra ID on the root |
|
268 // and working up from there (Thanks to Andrew Dupont for the technique) |
|
269 // IE 8 doesn't work on object elements |
|
270 if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) { |
|
271 groups = tokenize( selector ); |
|
272 |
|
273 if ( (old = context.getAttribute("id")) ) { |
|
274 nid = old.replace( rescape, "\\$&" ); |
|
275 } else { |
|
276 context.setAttribute( "id", nid ); |
|
277 } |
|
278 nid = "[id='" + nid + "'] "; |
|
279 |
|
280 i = groups.length; |
|
281 while ( i-- ) { |
|
282 groups[i] = nid + toSelector( groups[i] ); |
|
283 } |
|
284 newContext = rsibling.test( selector ) && testContext( context.parentNode ) || context; |
|
285 newSelector = groups.join(","); |
|
286 } |
|
287 |
|
288 if ( newSelector ) { |
|
289 try { |
|
290 push.apply( results, |
|
291 newContext.querySelectorAll( newSelector ) |
|
292 ); |
|
293 return results; |
|
294 } catch(qsaError) { |
|
295 } finally { |
|
296 if ( !old ) { |
|
297 context.removeAttribute("id"); |
|
298 } |
|
299 } |
|
300 } |
|
301 } |
|
302 } |
|
303 |
|
304 // All others |
|
305 return select( selector.replace( rtrim, "$1" ), context, results, seed ); |
|
306 } |
|
307 |
|
308 /** |
|
309 * Create key-value caches of limited size |
|
310 * @returns {Function(string, Object)} Returns the Object data after storing it on itself with |
|
311 * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) |
|
312 * deleting the oldest entry |
|
313 */ |
|
314 function createCache() { |
|
315 var keys = []; |
|
316 |
|
317 function cache( key, value ) { |
|
318 // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) |
|
319 if ( keys.push( key + " " ) > Expr.cacheLength ) { |
|
320 // Only keep the most recent entries |
|
321 delete cache[ keys.shift() ]; |
|
322 } |
|
323 return (cache[ key + " " ] = value); |
|
324 } |
|
325 return cache; |
|
326 } |
|
327 |
|
328 /** |
|
329 * Mark a function for special use by Sizzle |
|
330 * @param {Function} fn The function to mark |
|
331 */ |
|
332 function markFunction( fn ) { |
|
333 fn[ expando ] = true; |
|
334 return fn; |
|
335 } |
|
336 |
|
337 /** |
|
338 * Support testing using an element |
|
339 * @param {Function} fn Passed the created div and expects a boolean result |
|
340 */ |
|
341 function assert( fn ) { |
|
342 var div = document.createElement("div"); |
|
343 |
|
344 try { |
|
345 return !!fn( div ); |
|
346 } catch (e) { |
|
347 return false; |
|
348 } finally { |
|
349 // Remove from its parent by default |
|
350 if ( div.parentNode ) { |
|
351 div.parentNode.removeChild( div ); |
|
352 } |
|
353 // release memory in IE |
|
354 div = null; |
|
355 } |
|
356 } |
|
357 |
|
358 /** |
|
359 * Adds the same handler for all of the specified attrs |
|
360 * @param {String} attrs Pipe-separated list of attributes |
|
361 * @param {Function} handler The method that will be applied |
|
362 */ |
|
363 function addHandle( attrs, handler ) { |
|
364 var arr = attrs.split("|"), |
|
365 i = attrs.length; |
|
366 |
|
367 while ( i-- ) { |
|
368 Expr.attrHandle[ arr[i] ] = handler; |
|
369 } |
|
370 } |
|
371 |
|
372 /** |
|
373 * Checks document order of two siblings |
|
374 * @param {Element} a |
|
375 * @param {Element} b |
|
376 * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b |
|
377 */ |
|
378 function siblingCheck( a, b ) { |
|
379 var cur = b && a, |
|
380 diff = cur && a.nodeType === 1 && b.nodeType === 1 && |
|
381 ( ~b.sourceIndex || MAX_NEGATIVE ) - |
|
382 ( ~a.sourceIndex || MAX_NEGATIVE ); |
|
383 |
|
384 // Use IE sourceIndex if available on both nodes |
|
385 if ( diff ) { |
|
386 return diff; |
|
387 } |
|
388 |
|
389 // Check if b follows a |
|
390 if ( cur ) { |
|
391 while ( (cur = cur.nextSibling) ) { |
|
392 if ( cur === b ) { |
|
393 return -1; |
|
394 } |
|
395 } |
|
396 } |
|
397 |
|
398 return a ? 1 : -1; |
|
399 } |
|
400 |
|
401 /** |
|
402 * Returns a function to use in pseudos for input types |
|
403 * @param {String} type |
|
404 */ |
|
405 function createInputPseudo( type ) { |
|
406 return function( elem ) { |
|
407 var name = elem.nodeName.toLowerCase(); |
|
408 return name === "input" && elem.type === type; |
|
409 }; |
|
410 } |
|
411 |
|
412 /** |
|
413 * Returns a function to use in pseudos for buttons |
|
414 * @param {String} type |
|
415 */ |
|
416 function createButtonPseudo( type ) { |
|
417 return function( elem ) { |
|
418 var name = elem.nodeName.toLowerCase(); |
|
419 return (name === "input" || name === "button") && elem.type === type; |
|
420 }; |
|
421 } |
|
422 |
|
423 /** |
|
424 * Returns a function to use in pseudos for positionals |
|
425 * @param {Function} fn |
|
426 */ |
|
427 function createPositionalPseudo( fn ) { |
|
428 return markFunction(function( argument ) { |
|
429 argument = +argument; |
|
430 return markFunction(function( seed, matches ) { |
|
431 var j, |
|
432 matchIndexes = fn( [], seed.length, argument ), |
|
433 i = matchIndexes.length; |
|
434 |
|
435 // Match elements found at the specified indexes |
|
436 while ( i-- ) { |
|
437 if ( seed[ (j = matchIndexes[i]) ] ) { |
|
438 seed[j] = !(matches[j] = seed[j]); |
|
439 } |
|
440 } |
|
441 }); |
|
442 }); |
|
443 } |
|
444 |
|
445 /** |
|
446 * Checks a node for validity as a Sizzle context |
|
447 * @param {Element|Object=} context |
|
448 * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value |
|
449 */ |
|
450 function testContext( context ) { |
|
451 return context && typeof context.getElementsByTagName !== strundefined && context; |
|
452 } |
|
453 |
|
454 // Expose support vars for convenience |
|
455 support = Sizzle.support = {}; |
|
456 |
|
457 /** |
|
458 * Detects XML nodes |
|
459 * @param {Element|Object} elem An element or a document |
|
460 * @returns {Boolean} True iff elem is a non-HTML XML node |
|
461 */ |
|
462 isXML = Sizzle.isXML = function( elem ) { |
|
463 // documentElement is verified for cases where it doesn't yet exist |
|
464 // (such as loading iframes in IE - #4833) |
|
465 var documentElement = elem && (elem.ownerDocument || elem).documentElement; |
|
466 return documentElement ? documentElement.nodeName !== "HTML" : false; |
|
467 }; |
|
468 |
|
469 /** |
|
470 * Sets document-related variables once based on the current document |
|
471 * @param {Element|Object} [doc] An element or document object to use to set the document |
|
472 * @returns {Object} Returns the current document |
|
473 */ |
|
474 setDocument = Sizzle.setDocument = function( node ) { |
|
475 var hasCompare, |
|
476 doc = node ? node.ownerDocument || node : preferredDoc, |
|
477 parent = doc.defaultView; |
|
478 |
|
479 // If no document and documentElement is available, return |
|
480 if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) { |
|
481 return document; |
|
482 } |
|
483 |
|
484 // Set our document |
|
485 document = doc; |
|
486 docElem = doc.documentElement; |
|
487 |
|
488 // Support tests |
|
489 documentIsHTML = !isXML( doc ); |
|
490 |
|
491 // Support: IE>8 |
|
492 // If iframe document is assigned to "document" variable and if iframe has been reloaded, |
|
493 // IE will throw "permission denied" error when accessing "document" variable, see jQuery #13936 |
|
494 // IE6-8 do not support the defaultView property so parent will be undefined |
|
495 if ( parent && parent !== parent.top ) { |
|
496 // IE11 does not have attachEvent, so all must suffer |
|
497 if ( parent.addEventListener ) { |
|
498 parent.addEventListener( "unload", function() { |
|
499 setDocument(); |
|
500 }, false ); |
|
501 } else if ( parent.attachEvent ) { |
|
502 parent.attachEvent( "onunload", function() { |
|
503 setDocument(); |
|
504 }); |
|
505 } |
|
506 } |
|
507 |
|
508 /* Attributes |
|
509 ---------------------------------------------------------------------- */ |
|
510 |
|
511 // Support: IE<8 |
|
512 // Verify that getAttribute really returns attributes and not properties (excepting IE8 booleans) |
|
513 support.attributes = assert(function( div ) { |
|
514 div.className = "i"; |
|
515 return !div.getAttribute("className"); |
|
516 }); |
|
517 |
|
518 /* getElement(s)By* |
|
519 ---------------------------------------------------------------------- */ |
|
520 |
|
521 // Check if getElementsByTagName("*") returns only elements |
|
522 support.getElementsByTagName = assert(function( div ) { |
|
523 div.appendChild( doc.createComment("") ); |
|
524 return !div.getElementsByTagName("*").length; |
|
525 }); |
|
526 |
|
527 // Support: IE<9 |
|
528 support.getElementsByClassName = rnative.test( doc.getElementsByClassName ); |
|
529 |
|
530 // Support: IE<10 |
|
531 // Check if getElementById returns elements by name |
|
532 // The broken getElementById methods don't pick up programatically-set names, |
|
533 // so use a roundabout getElementsByName test |
|
534 support.getById = assert(function( div ) { |
|
535 docElem.appendChild( div ).id = expando; |
|
536 return !doc.getElementsByName || !doc.getElementsByName( expando ).length; |
|
537 }); |
|
538 |
|
539 // ID find and filter |
|
540 if ( support.getById ) { |
|
541 Expr.find["ID"] = function( id, context ) { |
|
542 if ( typeof context.getElementById !== strundefined && documentIsHTML ) { |
|
543 var m = context.getElementById( id ); |
|
544 // Check parentNode to catch when Blackberry 4.6 returns |
|
545 // nodes that are no longer in the document #6963 |
|
546 return m && m.parentNode ? [ m ] : []; |
|
547 } |
|
548 }; |
|
549 Expr.filter["ID"] = function( id ) { |
|
550 var attrId = id.replace( runescape, funescape ); |
|
551 return function( elem ) { |
|
552 return elem.getAttribute("id") === attrId; |
|
553 }; |
|
554 }; |
|
555 } else { |
|
556 // Support: IE6/7 |
|
557 // getElementById is not reliable as a find shortcut |
|
558 delete Expr.find["ID"]; |
|
559 |
|
560 Expr.filter["ID"] = function( id ) { |
|
561 var attrId = id.replace( runescape, funescape ); |
|
562 return function( elem ) { |
|
563 var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id"); |
|
564 return node && node.value === attrId; |
|
565 }; |
|
566 }; |
|
567 } |
|
568 |
|
569 // Tag |
|
570 Expr.find["TAG"] = support.getElementsByTagName ? |
|
571 function( tag, context ) { |
|
572 if ( typeof context.getElementsByTagName !== strundefined ) { |
|
573 return context.getElementsByTagName( tag ); |
|
574 } |
|
575 } : |
|
576 function( tag, context ) { |
|
577 var elem, |
|
578 tmp = [], |
|
579 i = 0, |
|
580 results = context.getElementsByTagName( tag ); |
|
581 |
|
582 // Filter out possible comments |
|
583 if ( tag === "*" ) { |
|
584 while ( (elem = results[i++]) ) { |
|
585 if ( elem.nodeType === 1 ) { |
|
586 tmp.push( elem ); |
|
587 } |
|
588 } |
|
589 |
|
590 return tmp; |
|
591 } |
|
592 return results; |
|
593 }; |
|
594 |
|
595 // Class |
|
596 Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) { |
|
597 if ( documentIsHTML ) { |
|
598 return context.getElementsByClassName( className ); |
|
599 } |
|
600 }; |
|
601 |
|
602 /* QSA/matchesSelector |
|
603 ---------------------------------------------------------------------- */ |
|
604 |
|
605 // QSA and matchesSelector support |
|
606 |
|
607 // matchesSelector(:active) reports false when true (IE9/Opera 11.5) |
|
608 rbuggyMatches = []; |
|
609 |
|
610 // qSa(:focus) reports false when true (Chrome 21) |
|
611 // We allow this because of a bug in IE8/9 that throws an error |
|
612 // whenever `document.activeElement` is accessed on an iframe |
|
613 // So, we allow :focus to pass through QSA all the time to avoid the IE error |
|
614 // See http://bugs.jquery.com/ticket/13378 |
|
615 rbuggyQSA = []; |
|
616 |
|
617 if ( (support.qsa = rnative.test( doc.querySelectorAll )) ) { |
|
618 // Build QSA regex |
|
619 // Regex strategy adopted from Diego Perini |
|
620 assert(function( div ) { |
|
621 // Select is set to empty string on purpose |
|
622 // This is to test IE's treatment of not explicitly |
|
623 // setting a boolean content attribute, |
|
624 // since its presence should be enough |
|
625 // http://bugs.jquery.com/ticket/12359 |
|
626 div.innerHTML = "<select msallowcapture=''><option selected=''></option></select>"; |
|
627 |
|
628 // Support: IE8, Opera 11-12.16 |
|
629 // Nothing should be selected when empty strings follow ^= or $= or *= |
|
630 // The test attribute must be unknown in Opera but "safe" for WinRT |
|
631 // http://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section |
|
632 if ( div.querySelectorAll("[msallowcapture^='']").length ) { |
|
633 rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); |
|
634 } |
|
635 |
|
636 // Support: IE8 |
|
637 // Boolean attributes and "value" are not treated correctly |
|
638 if ( !div.querySelectorAll("[selected]").length ) { |
|
639 rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); |
|
640 } |
|
641 |
|
642 // Webkit/Opera - :checked should return selected option elements |
|
643 // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked |
|
644 // IE8 throws error here and will not see later tests |
|
645 if ( !div.querySelectorAll(":checked").length ) { |
|
646 rbuggyQSA.push(":checked"); |
|
647 } |
|
648 }); |
|
649 |
|
650 assert(function( div ) { |
|
651 // Support: Windows 8 Native Apps |
|
652 // The type and name attributes are restricted during .innerHTML assignment |
|
653 var input = doc.createElement("input"); |
|
654 input.setAttribute( "type", "hidden" ); |
|
655 div.appendChild( input ).setAttribute( "name", "D" ); |
|
656 |
|
657 // Support: IE8 |
|
658 // Enforce case-sensitivity of name attribute |
|
659 if ( div.querySelectorAll("[name=d]").length ) { |
|
660 rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); |
|
661 } |
|
662 |
|
663 // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) |
|
664 // IE8 throws error here and will not see later tests |
|
665 if ( !div.querySelectorAll(":enabled").length ) { |
|
666 rbuggyQSA.push( ":enabled", ":disabled" ); |
|
667 } |
|
668 |
|
669 // Opera 10-11 does not throw on post-comma invalid pseudos |
|
670 div.querySelectorAll("*,:x"); |
|
671 rbuggyQSA.push(",.*:"); |
|
672 }); |
|
673 } |
|
674 |
|
675 if ( (support.matchesSelector = rnative.test( (matches = docElem.matches || |
|
676 docElem.webkitMatchesSelector || |
|
677 docElem.mozMatchesSelector || |
|
678 docElem.oMatchesSelector || |
|
679 docElem.msMatchesSelector) )) ) { |
|
680 |
|
681 assert(function( div ) { |
|
682 // Check to see if it's possible to do matchesSelector |
|
683 // on a disconnected node (IE 9) |
|
684 support.disconnectedMatch = matches.call( div, "div" ); |
|
685 |
|
686 // This should fail with an exception |
|
687 // Gecko does not error, returns false instead |
|
688 matches.call( div, "[s!='']:x" ); |
|
689 rbuggyMatches.push( "!=", pseudos ); |
|
690 }); |
|
691 } |
|
692 |
|
693 rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") ); |
|
694 rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") ); |
|
695 |
|
696 /* Contains |
|
697 ---------------------------------------------------------------------- */ |
|
698 hasCompare = rnative.test( docElem.compareDocumentPosition ); |
|
699 |
|
700 // Element contains another |
|
701 // Purposefully does not implement inclusive descendent |
|
702 // As in, an element does not contain itself |
|
703 contains = hasCompare || rnative.test( docElem.contains ) ? |
|
704 function( a, b ) { |
|
705 var adown = a.nodeType === 9 ? a.documentElement : a, |
|
706 bup = b && b.parentNode; |
|
707 return a === bup || !!( bup && bup.nodeType === 1 && ( |
|
708 adown.contains ? |
|
709 adown.contains( bup ) : |
|
710 a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 |
|
711 )); |
|
712 } : |
|
713 function( a, b ) { |
|
714 if ( b ) { |
|
715 while ( (b = b.parentNode) ) { |
|
716 if ( b === a ) { |
|
717 return true; |
|
718 } |
|
719 } |
|
720 } |
|
721 return false; |
|
722 }; |
|
723 |
|
724 /* Sorting |
|
725 ---------------------------------------------------------------------- */ |
|
726 |
|
727 // Document order sorting |
|
728 sortOrder = hasCompare ? |
|
729 function( a, b ) { |
|
730 |
|
731 // Flag for duplicate removal |
|
732 if ( a === b ) { |
|
733 hasDuplicate = true; |
|
734 return 0; |
|
735 } |
|
736 |
|
737 // Sort on method existence if only one input has compareDocumentPosition |
|
738 var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; |
|
739 if ( compare ) { |
|
740 return compare; |
|
741 } |
|
742 |
|
743 // Calculate position if both inputs belong to the same document |
|
744 compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ? |
|
745 a.compareDocumentPosition( b ) : |
|
746 |
|
747 // Otherwise we know they are disconnected |
|
748 1; |
|
749 |
|
750 // Disconnected nodes |
|
751 if ( compare & 1 || |
|
752 (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) { |
|
753 |
|
754 // Choose the first element that is related to our preferred document |
|
755 if ( a === doc || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) { |
|
756 return -1; |
|
757 } |
|
758 if ( b === doc || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) { |
|
759 return 1; |
|
760 } |
|
761 |
|
762 // Maintain original order |
|
763 return sortInput ? |
|
764 ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) : |
|
765 0; |
|
766 } |
|
767 |
|
768 return compare & 4 ? -1 : 1; |
|
769 } : |
|
770 function( a, b ) { |
|
771 // Exit early if the nodes are identical |
|
772 if ( a === b ) { |
|
773 hasDuplicate = true; |
|
774 return 0; |
|
775 } |
|
776 |
|
777 var cur, |
|
778 i = 0, |
|
779 aup = a.parentNode, |
|
780 bup = b.parentNode, |
|
781 ap = [ a ], |
|
782 bp = [ b ]; |
|
783 |
|
784 // Parentless nodes are either documents or disconnected |
|
785 if ( !aup || !bup ) { |
|
786 return a === doc ? -1 : |
|
787 b === doc ? 1 : |
|
788 aup ? -1 : |
|
789 bup ? 1 : |
|
790 sortInput ? |
|
791 ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) : |
|
792 0; |
|
793 |
|
794 // If the nodes are siblings, we can do a quick check |
|
795 } else if ( aup === bup ) { |
|
796 return siblingCheck( a, b ); |
|
797 } |
|
798 |
|
799 // Otherwise we need full lists of their ancestors for comparison |
|
800 cur = a; |
|
801 while ( (cur = cur.parentNode) ) { |
|
802 ap.unshift( cur ); |
|
803 } |
|
804 cur = b; |
|
805 while ( (cur = cur.parentNode) ) { |
|
806 bp.unshift( cur ); |
|
807 } |
|
808 |
|
809 // Walk down the tree looking for a discrepancy |
|
810 while ( ap[i] === bp[i] ) { |
|
811 i++; |
|
812 } |
|
813 |
|
814 return i ? |
|
815 // Do a sibling check if the nodes have a common ancestor |
|
816 siblingCheck( ap[i], bp[i] ) : |
|
817 |
|
818 // Otherwise nodes in our document sort first |
|
819 ap[i] === preferredDoc ? -1 : |
|
820 bp[i] === preferredDoc ? 1 : |
|
821 0; |
|
822 }; |
|
823 |
|
824 return doc; |
|
825 }; |
|
826 |
|
827 Sizzle.matches = function( expr, elements ) { |
|
828 return Sizzle( expr, null, null, elements ); |
|
829 }; |
|
830 |
|
831 Sizzle.matchesSelector = function( elem, expr ) { |
|
832 // Set document vars if needed |
|
833 if ( ( elem.ownerDocument || elem ) !== document ) { |
|
834 setDocument( elem ); |
|
835 } |
|
836 |
|
837 // Make sure that attribute selectors are quoted |
|
838 expr = expr.replace( rattributeQuotes, "='$1']" ); |
|
839 |
|
840 if ( support.matchesSelector && documentIsHTML && |
|
841 ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && |
|
842 ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { |
|
843 |
|
844 try { |
|
845 var ret = matches.call( elem, expr ); |
|
846 |
|
847 // IE 9's matchesSelector returns false on disconnected nodes |
|
848 if ( ret || support.disconnectedMatch || |
|
849 // As well, disconnected nodes are said to be in a document |
|
850 // fragment in IE 9 |
|
851 elem.document && elem.document.nodeType !== 11 ) { |
|
852 return ret; |
|
853 } |
|
854 } catch(e) {} |
|
855 } |
|
856 |
|
857 return Sizzle( expr, document, null, [ elem ] ).length > 0; |
|
858 }; |
|
859 |
|
860 Sizzle.contains = function( context, elem ) { |
|
861 // Set document vars if needed |
|
862 if ( ( context.ownerDocument || context ) !== document ) { |
|
863 setDocument( context ); |
|
864 } |
|
865 return contains( context, elem ); |
|
866 }; |
|
867 |
|
868 Sizzle.attr = function( elem, name ) { |
|
869 // Set document vars if needed |
|
870 if ( ( elem.ownerDocument || elem ) !== document ) { |
|
871 setDocument( elem ); |
|
872 } |
|
873 |
|
874 var fn = Expr.attrHandle[ name.toLowerCase() ], |
|
875 // Don't get fooled by Object.prototype properties (jQuery #13807) |
|
876 val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? |
|
877 fn( elem, name, !documentIsHTML ) : |
|
878 undefined; |
|
879 |
|
880 return val !== undefined ? |
|
881 val : |
|
882 support.attributes || !documentIsHTML ? |
|
883 elem.getAttribute( name ) : |
|
884 (val = elem.getAttributeNode(name)) && val.specified ? |
|
885 val.value : |
|
886 null; |
|
887 }; |
|
888 |
|
889 Sizzle.error = function( msg ) { |
|
890 throw new Error( "Syntax error, unrecognized expression: " + msg ); |
|
891 }; |
|
892 |
|
893 /** |
|
894 * Document sorting and removing duplicates |
|
895 * @param {ArrayLike} results |
|
896 */ |
|
897 Sizzle.uniqueSort = function( results ) { |
|
898 var elem, |
|
899 duplicates = [], |
|
900 j = 0, |
|
901 i = 0; |
|
902 |
|
903 // Unless we *know* we can detect duplicates, assume their presence |
|
904 hasDuplicate = !support.detectDuplicates; |
|
905 sortInput = !support.sortStable && results.slice( 0 ); |
|
906 results.sort( sortOrder ); |
|
907 |
|
908 if ( hasDuplicate ) { |
|
909 while ( (elem = results[i++]) ) { |
|
910 if ( elem === results[ i ] ) { |
|
911 j = duplicates.push( i ); |
|
912 } |
|
913 } |
|
914 while ( j-- ) { |
|
915 results.splice( duplicates[ j ], 1 ); |
|
916 } |
|
917 } |
|
918 |
|
919 // Clear input after sorting to release objects |
|
920 // See https://github.com/jquery/sizzle/pull/225 |
|
921 sortInput = null; |
|
922 |
|
923 return results; |
|
924 }; |
|
925 |
|
926 /** |
|
927 * Utility function for retrieving the text value of an array of DOM nodes |
|
928 * @param {Array|Element} elem |
|
929 */ |
|
930 getText = Sizzle.getText = function( elem ) { |
|
931 var node, |
|
932 ret = "", |
|
933 i = 0, |
|
934 nodeType = elem.nodeType; |
|
935 |
|
936 if ( !nodeType ) { |
|
937 // If no nodeType, this is expected to be an array |
|
938 while ( (node = elem[i++]) ) { |
|
939 // Do not traverse comment nodes |
|
940 ret += getText( node ); |
|
941 } |
|
942 } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { |
|
943 // Use textContent for elements |
|
944 // innerText usage removed for consistency of new lines (jQuery #11153) |
|
945 if ( typeof elem.textContent === "string" ) { |
|
946 return elem.textContent; |
|
947 } else { |
|
948 // Traverse its children |
|
949 for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { |
|
950 ret += getText( elem ); |
|
951 } |
|
952 } |
|
953 } else if ( nodeType === 3 || nodeType === 4 ) { |
|
954 return elem.nodeValue; |
|
955 } |
|
956 // Do not include comment or processing instruction nodes |
|
957 |
|
958 return ret; |
|
959 }; |
|
960 |
|
961 Expr = Sizzle.selectors = { |
|
962 |
|
963 // Can be adjusted by the user |
|
964 cacheLength: 50, |
|
965 |
|
966 createPseudo: markFunction, |
|
967 |
|
968 match: matchExpr, |
|
969 |
|
970 attrHandle: {}, |
|
971 |
|
972 find: {}, |
|
973 |
|
974 relative: { |
|
975 ">": { dir: "parentNode", first: true }, |
|
976 " ": { dir: "parentNode" }, |
|
977 "+": { dir: "previousSibling", first: true }, |
|
978 "~": { dir: "previousSibling" } |
|
979 }, |
|
980 |
|
981 preFilter: { |
|
982 "ATTR": function( match ) { |
|
983 match[1] = match[1].replace( runescape, funescape ); |
|
984 |
|
985 // Move the given value to match[3] whether quoted or unquoted |
|
986 match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape ); |
|
987 |
|
988 if ( match[2] === "~=" ) { |
|
989 match[3] = " " + match[3] + " "; |
|
990 } |
|
991 |
|
992 return match.slice( 0, 4 ); |
|
993 }, |
|
994 |
|
995 "CHILD": function( match ) { |
|
996 /* matches from matchExpr["CHILD"] |
|
997 1 type (only|nth|...) |
|
998 2 what (child|of-type) |
|
999 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) |
|
1000 4 xn-component of xn+y argument ([+-]?\d*n|) |
|
1001 5 sign of xn-component |
|
1002 6 x of xn-component |
|
1003 7 sign of y-component |
|
1004 8 y of y-component |
|
1005 */ |
|
1006 match[1] = match[1].toLowerCase(); |
|
1007 |
|
1008 if ( match[1].slice( 0, 3 ) === "nth" ) { |
|
1009 // nth-* requires argument |
|
1010 if ( !match[3] ) { |
|
1011 Sizzle.error( match[0] ); |
|
1012 } |
|
1013 |
|
1014 // numeric x and y parameters for Expr.filter.CHILD |
|
1015 // remember that false/true cast respectively to 0/1 |
|
1016 match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) ); |
|
1017 match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" ); |
|
1018 |
|
1019 // other types prohibit arguments |
|
1020 } else if ( match[3] ) { |
|
1021 Sizzle.error( match[0] ); |
|
1022 } |
|
1023 |
|
1024 return match; |
|
1025 }, |
|
1026 |
|
1027 "PSEUDO": function( match ) { |
|
1028 var excess, |
|
1029 unquoted = !match[6] && match[2]; |
|
1030 |
|
1031 if ( matchExpr["CHILD"].test( match[0] ) ) { |
|
1032 return null; |
|
1033 } |
|
1034 |
|
1035 // Accept quoted arguments as-is |
|
1036 if ( match[3] ) { |
|
1037 match[2] = match[4] || match[5] || ""; |
|
1038 |
|
1039 // Strip excess characters from unquoted arguments |
|
1040 } else if ( unquoted && rpseudo.test( unquoted ) && |
|
1041 // Get excess from tokenize (recursively) |
|
1042 (excess = tokenize( unquoted, true )) && |
|
1043 // advance to the next closing parenthesis |
|
1044 (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) { |
|
1045 |
|
1046 // excess is a negative index |
|
1047 match[0] = match[0].slice( 0, excess ); |
|
1048 match[2] = unquoted.slice( 0, excess ); |
|
1049 } |
|
1050 |
|
1051 // Return only captures needed by the pseudo filter method (type and argument) |
|
1052 return match.slice( 0, 3 ); |
|
1053 } |
|
1054 }, |
|
1055 |
|
1056 filter: { |
|
1057 |
|
1058 "TAG": function( nodeNameSelector ) { |
|
1059 var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); |
|
1060 return nodeNameSelector === "*" ? |
|
1061 function() { return true; } : |
|
1062 function( elem ) { |
|
1063 return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; |
|
1064 }; |
|
1065 }, |
|
1066 |
|
1067 "CLASS": function( className ) { |
|
1068 var pattern = classCache[ className + " " ]; |
|
1069 |
|
1070 return pattern || |
|
1071 (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) && |
|
1072 classCache( className, function( elem ) { |
|
1073 return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== strundefined && elem.getAttribute("class") || "" ); |
|
1074 }); |
|
1075 }, |
|
1076 |
|
1077 "ATTR": function( name, operator, check ) { |
|
1078 return function( elem ) { |
|
1079 var result = Sizzle.attr( elem, name ); |
|
1080 |
|
1081 if ( result == null ) { |
|
1082 return operator === "!="; |
|
1083 } |
|
1084 if ( !operator ) { |
|
1085 return true; |
|
1086 } |
|
1087 |
|
1088 result += ""; |
|
1089 |
|
1090 return operator === "=" ? result === check : |
|
1091 operator === "!=" ? result !== check : |
|
1092 operator === "^=" ? check && result.indexOf( check ) === 0 : |
|
1093 operator === "*=" ? check && result.indexOf( check ) > -1 : |
|
1094 operator === "$=" ? check && result.slice( -check.length ) === check : |
|
1095 operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 : |
|
1096 operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : |
|
1097 false; |
|
1098 }; |
|
1099 }, |
|
1100 |
|
1101 "CHILD": function( type, what, argument, first, last ) { |
|
1102 var simple = type.slice( 0, 3 ) !== "nth", |
|
1103 forward = type.slice( -4 ) !== "last", |
|
1104 ofType = what === "of-type"; |
|
1105 |
|
1106 return first === 1 && last === 0 ? |
|
1107 |
|
1108 // Shortcut for :nth-*(n) |
|
1109 function( elem ) { |
|
1110 return !!elem.parentNode; |
|
1111 } : |
|
1112 |
|
1113 function( elem, context, xml ) { |
|
1114 var cache, outerCache, node, diff, nodeIndex, start, |
|
1115 dir = simple !== forward ? "nextSibling" : "previousSibling", |
|
1116 parent = elem.parentNode, |
|
1117 name = ofType && elem.nodeName.toLowerCase(), |
|
1118 useCache = !xml && !ofType; |
|
1119 |
|
1120 if ( parent ) { |
|
1121 |
|
1122 // :(first|last|only)-(child|of-type) |
|
1123 if ( simple ) { |
|
1124 while ( dir ) { |
|
1125 node = elem; |
|
1126 while ( (node = node[ dir ]) ) { |
|
1127 if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) { |
|
1128 return false; |
|
1129 } |
|
1130 } |
|
1131 // Reverse direction for :only-* (if we haven't yet done so) |
|
1132 start = dir = type === "only" && !start && "nextSibling"; |
|
1133 } |
|
1134 return true; |
|
1135 } |
|
1136 |
|
1137 start = [ forward ? parent.firstChild : parent.lastChild ]; |
|
1138 |
|
1139 // non-xml :nth-child(...) stores cache data on `parent` |
|
1140 if ( forward && useCache ) { |
|
1141 // Seek `elem` from a previously-cached index |
|
1142 outerCache = parent[ expando ] || (parent[ expando ] = {}); |
|
1143 cache = outerCache[ type ] || []; |
|
1144 nodeIndex = cache[0] === dirruns && cache[1]; |
|
1145 diff = cache[0] === dirruns && cache[2]; |
|
1146 node = nodeIndex && parent.childNodes[ nodeIndex ]; |
|
1147 |
|
1148 while ( (node = ++nodeIndex && node && node[ dir ] || |
|
1149 |
|
1150 // Fallback to seeking `elem` from the start |
|
1151 (diff = nodeIndex = 0) || start.pop()) ) { |
|
1152 |
|
1153 // When found, cache indexes on `parent` and break |
|
1154 if ( node.nodeType === 1 && ++diff && node === elem ) { |
|
1155 outerCache[ type ] = [ dirruns, nodeIndex, diff ]; |
|
1156 break; |
|
1157 } |
|
1158 } |
|
1159 |
|
1160 // Use previously-cached element index if available |
|
1161 } else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) { |
|
1162 diff = cache[1]; |
|
1163 |
|
1164 // xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...) |
|
1165 } else { |
|
1166 // Use the same loop as above to seek `elem` from the start |
|
1167 while ( (node = ++nodeIndex && node && node[ dir ] || |
|
1168 (diff = nodeIndex = 0) || start.pop()) ) { |
|
1169 |
|
1170 if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) { |
|
1171 // Cache the index of each encountered element |
|
1172 if ( useCache ) { |
|
1173 (node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ]; |
|
1174 } |
|
1175 |
|
1176 if ( node === elem ) { |
|
1177 break; |
|
1178 } |
|
1179 } |
|
1180 } |
|
1181 } |
|
1182 |
|
1183 // Incorporate the offset, then check against cycle size |
|
1184 diff -= last; |
|
1185 return diff === first || ( diff % first === 0 && diff / first >= 0 ); |
|
1186 } |
|
1187 }; |
|
1188 }, |
|
1189 |
|
1190 "PSEUDO": function( pseudo, argument ) { |
|
1191 // pseudo-class names are case-insensitive |
|
1192 // http://www.w3.org/TR/selectors/#pseudo-classes |
|
1193 // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters |
|
1194 // Remember that setFilters inherits from pseudos |
|
1195 var args, |
|
1196 fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || |
|
1197 Sizzle.error( "unsupported pseudo: " + pseudo ); |
|
1198 |
|
1199 // The user may use createPseudo to indicate that |
|
1200 // arguments are needed to create the filter function |
|
1201 // just as Sizzle does |
|
1202 if ( fn[ expando ] ) { |
|
1203 return fn( argument ); |
|
1204 } |
|
1205 |
|
1206 // But maintain support for old signatures |
|
1207 if ( fn.length > 1 ) { |
|
1208 args = [ pseudo, pseudo, "", argument ]; |
|
1209 return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? |
|
1210 markFunction(function( seed, matches ) { |
|
1211 var idx, |
|
1212 matched = fn( seed, argument ), |
|
1213 i = matched.length; |
|
1214 while ( i-- ) { |
|
1215 idx = indexOf.call( seed, matched[i] ); |
|
1216 seed[ idx ] = !( matches[ idx ] = matched[i] ); |
|
1217 } |
|
1218 }) : |
|
1219 function( elem ) { |
|
1220 return fn( elem, 0, args ); |
|
1221 }; |
|
1222 } |
|
1223 |
|
1224 return fn; |
|
1225 } |
|
1226 }, |
|
1227 |
|
1228 pseudos: { |
|
1229 // Potentially complex pseudos |
|
1230 "not": markFunction(function( selector ) { |
|
1231 // Trim the selector passed to compile |
|
1232 // to avoid treating leading and trailing |
|
1233 // spaces as combinators |
|
1234 var input = [], |
|
1235 results = [], |
|
1236 matcher = compile( selector.replace( rtrim, "$1" ) ); |
|
1237 |
|
1238 return matcher[ expando ] ? |
|
1239 markFunction(function( seed, matches, context, xml ) { |
|
1240 var elem, |
|
1241 unmatched = matcher( seed, null, xml, [] ), |
|
1242 i = seed.length; |
|
1243 |
|
1244 // Match elements unmatched by `matcher` |
|
1245 while ( i-- ) { |
|
1246 if ( (elem = unmatched[i]) ) { |
|
1247 seed[i] = !(matches[i] = elem); |
|
1248 } |
|
1249 } |
|
1250 }) : |
|
1251 function( elem, context, xml ) { |
|
1252 input[0] = elem; |
|
1253 matcher( input, null, xml, results ); |
|
1254 return !results.pop(); |
|
1255 }; |
|
1256 }), |
|
1257 |
|
1258 "has": markFunction(function( selector ) { |
|
1259 return function( elem ) { |
|
1260 return Sizzle( selector, elem ).length > 0; |
|
1261 }; |
|
1262 }), |
|
1263 |
|
1264 "contains": markFunction(function( text ) { |
|
1265 text = text.replace( runescape, funescape ); |
|
1266 return function( elem ) { |
|
1267 return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; |
|
1268 }; |
|
1269 }), |
|
1270 |
|
1271 // "Whether an element is represented by a :lang() selector |
|
1272 // is based solely on the element's language value |
|
1273 // being equal to the identifier C, |
|
1274 // or beginning with the identifier C immediately followed by "-". |
|
1275 // The matching of C against the element's language value is performed case-insensitively. |
|
1276 // The identifier C does not have to be a valid language name." |
|
1277 // http://www.w3.org/TR/selectors/#lang-pseudo |
|
1278 "lang": markFunction( function( lang ) { |
|
1279 // lang value must be a valid identifier |
|
1280 if ( !ridentifier.test(lang || "") ) { |
|
1281 Sizzle.error( "unsupported lang: " + lang ); |
|
1282 } |
|
1283 lang = lang.replace( runescape, funescape ).toLowerCase(); |
|
1284 return function( elem ) { |
|
1285 var elemLang; |
|
1286 do { |
|
1287 if ( (elemLang = documentIsHTML ? |
|
1288 elem.lang : |
|
1289 elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) { |
|
1290 |
|
1291 elemLang = elemLang.toLowerCase(); |
|
1292 return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; |
|
1293 } |
|
1294 } while ( (elem = elem.parentNode) && elem.nodeType === 1 ); |
|
1295 return false; |
|
1296 }; |
|
1297 }), |
|
1298 |
|
1299 // Miscellaneous |
|
1300 "target": function( elem ) { |
|
1301 var hash = window.location && window.location.hash; |
|
1302 return hash && hash.slice( 1 ) === elem.id; |
|
1303 }, |
|
1304 |
|
1305 "root": function( elem ) { |
|
1306 return elem === docElem; |
|
1307 }, |
|
1308 |
|
1309 "focus": function( elem ) { |
|
1310 return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex); |
|
1311 }, |
|
1312 |
|
1313 // Boolean properties |
|
1314 "enabled": function( elem ) { |
|
1315 return elem.disabled === false; |
|
1316 }, |
|
1317 |
|
1318 "disabled": function( elem ) { |
|
1319 return elem.disabled === true; |
|
1320 }, |
|
1321 |
|
1322 "checked": function( elem ) { |
|
1323 // In CSS3, :checked should return both checked and selected elements |
|
1324 // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked |
|
1325 var nodeName = elem.nodeName.toLowerCase(); |
|
1326 return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); |
|
1327 }, |
|
1328 |
|
1329 "selected": function( elem ) { |
|
1330 // Accessing this property makes selected-by-default |
|
1331 // options in Safari work properly |
|
1332 if ( elem.parentNode ) { |
|
1333 elem.parentNode.selectedIndex; |
|
1334 } |
|
1335 |
|
1336 return elem.selected === true; |
|
1337 }, |
|
1338 |
|
1339 // Contents |
|
1340 "empty": function( elem ) { |
|
1341 // http://www.w3.org/TR/selectors/#empty-pseudo |
|
1342 // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), |
|
1343 // but not by others (comment: 8; processing instruction: 7; etc.) |
|
1344 // nodeType < 6 works because attributes (2) do not appear as children |
|
1345 for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { |
|
1346 if ( elem.nodeType < 6 ) { |
|
1347 return false; |
|
1348 } |
|
1349 } |
|
1350 return true; |
|
1351 }, |
|
1352 |
|
1353 "parent": function( elem ) { |
|
1354 return !Expr.pseudos["empty"]( elem ); |
|
1355 }, |
|
1356 |
|
1357 // Element/input types |
|
1358 "header": function( elem ) { |
|
1359 return rheader.test( elem.nodeName ); |
|
1360 }, |
|
1361 |
|
1362 "input": function( elem ) { |
|
1363 return rinputs.test( elem.nodeName ); |
|
1364 }, |
|
1365 |
|
1366 "button": function( elem ) { |
|
1367 var name = elem.nodeName.toLowerCase(); |
|
1368 return name === "input" && elem.type === "button" || name === "button"; |
|
1369 }, |
|
1370 |
|
1371 "text": function( elem ) { |
|
1372 var attr; |
|
1373 return elem.nodeName.toLowerCase() === "input" && |
|
1374 elem.type === "text" && |
|
1375 |
|
1376 // Support: IE<8 |
|
1377 // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" |
|
1378 ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" ); |
|
1379 }, |
|
1380 |
|
1381 // Position-in-collection |
|
1382 "first": createPositionalPseudo(function() { |
|
1383 return [ 0 ]; |
|
1384 }), |
|
1385 |
|
1386 "last": createPositionalPseudo(function( matchIndexes, length ) { |
|
1387 return [ length - 1 ]; |
|
1388 }), |
|
1389 |
|
1390 "eq": createPositionalPseudo(function( matchIndexes, length, argument ) { |
|
1391 return [ argument < 0 ? argument + length : argument ]; |
|
1392 }), |
|
1393 |
|
1394 "even": createPositionalPseudo(function( matchIndexes, length ) { |
|
1395 var i = 0; |
|
1396 for ( ; i < length; i += 2 ) { |
|
1397 matchIndexes.push( i ); |
|
1398 } |
|
1399 return matchIndexes; |
|
1400 }), |
|
1401 |
|
1402 "odd": createPositionalPseudo(function( matchIndexes, length ) { |
|
1403 var i = 1; |
|
1404 for ( ; i < length; i += 2 ) { |
|
1405 matchIndexes.push( i ); |
|
1406 } |
|
1407 return matchIndexes; |
|
1408 }), |
|
1409 |
|
1410 "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { |
|
1411 var i = argument < 0 ? argument + length : argument; |
|
1412 for ( ; --i >= 0; ) { |
|
1413 matchIndexes.push( i ); |
|
1414 } |
|
1415 return matchIndexes; |
|
1416 }), |
|
1417 |
|
1418 "gt": createPositionalPseudo(function( matchIndexes, length, argument ) { |
|
1419 var i = argument < 0 ? argument + length : argument; |
|
1420 for ( ; ++i < length; ) { |
|
1421 matchIndexes.push( i ); |
|
1422 } |
|
1423 return matchIndexes; |
|
1424 }) |
|
1425 } |
|
1426 }; |
|
1427 |
|
1428 Expr.pseudos["nth"] = Expr.pseudos["eq"]; |
|
1429 |
|
1430 // Add button/input type pseudos |
|
1431 for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { |
|
1432 Expr.pseudos[ i ] = createInputPseudo( i ); |
|
1433 } |
|
1434 for ( i in { submit: true, reset: true } ) { |
|
1435 Expr.pseudos[ i ] = createButtonPseudo( i ); |
|
1436 } |
|
1437 |
|
1438 // Easy API for creating new setFilters |
|
1439 function setFilters() {} |
|
1440 setFilters.prototype = Expr.filters = Expr.pseudos; |
|
1441 Expr.setFilters = new setFilters(); |
|
1442 |
|
1443 tokenize = Sizzle.tokenize = function( selector, parseOnly ) { |
|
1444 var matched, match, tokens, type, |
|
1445 soFar, groups, preFilters, |
|
1446 cached = tokenCache[ selector + " " ]; |
|
1447 |
|
1448 if ( cached ) { |
|
1449 return parseOnly ? 0 : cached.slice( 0 ); |
|
1450 } |
|
1451 |
|
1452 soFar = selector; |
|
1453 groups = []; |
|
1454 preFilters = Expr.preFilter; |
|
1455 |
|
1456 while ( soFar ) { |
|
1457 |
|
1458 // Comma and first run |
|
1459 if ( !matched || (match = rcomma.exec( soFar )) ) { |
|
1460 if ( match ) { |
|
1461 // Don't consume trailing commas as valid |
|
1462 soFar = soFar.slice( match[0].length ) || soFar; |
|
1463 } |
|
1464 groups.push( (tokens = []) ); |
|
1465 } |
|
1466 |
|
1467 matched = false; |
|
1468 |
|
1469 // Combinators |
|
1470 if ( (match = rcombinators.exec( soFar )) ) { |
|
1471 matched = match.shift(); |
|
1472 tokens.push({ |
|
1473 value: matched, |
|
1474 // Cast descendant combinators to space |
|
1475 type: match[0].replace( rtrim, " " ) |
|
1476 }); |
|
1477 soFar = soFar.slice( matched.length ); |
|
1478 } |
|
1479 |
|
1480 // Filters |
|
1481 for ( type in Expr.filter ) { |
|
1482 if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || |
|
1483 (match = preFilters[ type ]( match ))) ) { |
|
1484 matched = match.shift(); |
|
1485 tokens.push({ |
|
1486 value: matched, |
|
1487 type: type, |
|
1488 matches: match |
|
1489 }); |
|
1490 soFar = soFar.slice( matched.length ); |
|
1491 } |
|
1492 } |
|
1493 |
|
1494 if ( !matched ) { |
|
1495 break; |
|
1496 } |
|
1497 } |
|
1498 |
|
1499 // Return the length of the invalid excess |
|
1500 // if we're just parsing |
|
1501 // Otherwise, throw an error or return tokens |
|
1502 return parseOnly ? |
|
1503 soFar.length : |
|
1504 soFar ? |
|
1505 Sizzle.error( selector ) : |
|
1506 // Cache the tokens |
|
1507 tokenCache( selector, groups ).slice( 0 ); |
|
1508 }; |
|
1509 |
|
1510 function toSelector( tokens ) { |
|
1511 var i = 0, |
|
1512 len = tokens.length, |
|
1513 selector = ""; |
|
1514 for ( ; i < len; i++ ) { |
|
1515 selector += tokens[i].value; |
|
1516 } |
|
1517 return selector; |
|
1518 } |
|
1519 |
|
1520 function addCombinator( matcher, combinator, base ) { |
|
1521 var dir = combinator.dir, |
|
1522 checkNonElements = base && dir === "parentNode", |
|
1523 doneName = done++; |
|
1524 |
|
1525 return combinator.first ? |
|
1526 // Check against closest ancestor/preceding element |
|
1527 function( elem, context, xml ) { |
|
1528 while ( (elem = elem[ dir ]) ) { |
|
1529 if ( elem.nodeType === 1 || checkNonElements ) { |
|
1530 return matcher( elem, context, xml ); |
|
1531 } |
|
1532 } |
|
1533 } : |
|
1534 |
|
1535 // Check against all ancestor/preceding elements |
|
1536 function( elem, context, xml ) { |
|
1537 var oldCache, outerCache, |
|
1538 newCache = [ dirruns, doneName ]; |
|
1539 |
|
1540 // We can't set arbitrary data on XML nodes, so they don't benefit from dir caching |
|
1541 if ( xml ) { |
|
1542 while ( (elem = elem[ dir ]) ) { |
|
1543 if ( elem.nodeType === 1 || checkNonElements ) { |
|
1544 if ( matcher( elem, context, xml ) ) { |
|
1545 return true; |
|
1546 } |
|
1547 } |
|
1548 } |
|
1549 } else { |
|
1550 while ( (elem = elem[ dir ]) ) { |
|
1551 if ( elem.nodeType === 1 || checkNonElements ) { |
|
1552 outerCache = elem[ expando ] || (elem[ expando ] = {}); |
|
1553 if ( (oldCache = outerCache[ dir ]) && |
|
1554 oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { |
|
1555 |
|
1556 // Assign to newCache so results back-propagate to previous elements |
|
1557 return (newCache[ 2 ] = oldCache[ 2 ]); |
|
1558 } else { |
|
1559 // Reuse newcache so results back-propagate to previous elements |
|
1560 outerCache[ dir ] = newCache; |
|
1561 |
|
1562 // A match means we're done; a fail means we have to keep checking |
|
1563 if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) { |
|
1564 return true; |
|
1565 } |
|
1566 } |
|
1567 } |
|
1568 } |
|
1569 } |
|
1570 }; |
|
1571 } |
|
1572 |
|
1573 function elementMatcher( matchers ) { |
|
1574 return matchers.length > 1 ? |
|
1575 function( elem, context, xml ) { |
|
1576 var i = matchers.length; |
|
1577 while ( i-- ) { |
|
1578 if ( !matchers[i]( elem, context, xml ) ) { |
|
1579 return false; |
|
1580 } |
|
1581 } |
|
1582 return true; |
|
1583 } : |
|
1584 matchers[0]; |
|
1585 } |
|
1586 |
|
1587 function multipleContexts( selector, contexts, results ) { |
|
1588 var i = 0, |
|
1589 len = contexts.length; |
|
1590 for ( ; i < len; i++ ) { |
|
1591 Sizzle( selector, contexts[i], results ); |
|
1592 } |
|
1593 return results; |
|
1594 } |
|
1595 |
|
1596 function condense( unmatched, map, filter, context, xml ) { |
|
1597 var elem, |
|
1598 newUnmatched = [], |
|
1599 i = 0, |
|
1600 len = unmatched.length, |
|
1601 mapped = map != null; |
|
1602 |
|
1603 for ( ; i < len; i++ ) { |
|
1604 if ( (elem = unmatched[i]) ) { |
|
1605 if ( !filter || filter( elem, context, xml ) ) { |
|
1606 newUnmatched.push( elem ); |
|
1607 if ( mapped ) { |
|
1608 map.push( i ); |
|
1609 } |
|
1610 } |
|
1611 } |
|
1612 } |
|
1613 |
|
1614 return newUnmatched; |
|
1615 } |
|
1616 |
|
1617 function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { |
|
1618 if ( postFilter && !postFilter[ expando ] ) { |
|
1619 postFilter = setMatcher( postFilter ); |
|
1620 } |
|
1621 if ( postFinder && !postFinder[ expando ] ) { |
|
1622 postFinder = setMatcher( postFinder, postSelector ); |
|
1623 } |
|
1624 return markFunction(function( seed, results, context, xml ) { |
|
1625 var temp, i, elem, |
|
1626 preMap = [], |
|
1627 postMap = [], |
|
1628 preexisting = results.length, |
|
1629 |
|
1630 // Get initial elements from seed or context |
|
1631 elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ), |
|
1632 |
|
1633 // Prefilter to get matcher input, preserving a map for seed-results synchronization |
|
1634 matcherIn = preFilter && ( seed || !selector ) ? |
|
1635 condense( elems, preMap, preFilter, context, xml ) : |
|
1636 elems, |
|
1637 |
|
1638 matcherOut = matcher ? |
|
1639 // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, |
|
1640 postFinder || ( seed ? preFilter : preexisting || postFilter ) ? |
|
1641 |
|
1642 // ...intermediate processing is necessary |
|
1643 [] : |
|
1644 |
|
1645 // ...otherwise use results directly |
|
1646 results : |
|
1647 matcherIn; |
|
1648 |
|
1649 // Find primary matches |
|
1650 if ( matcher ) { |
|
1651 matcher( matcherIn, matcherOut, context, xml ); |
|
1652 } |
|
1653 |
|
1654 // Apply postFilter |
|
1655 if ( postFilter ) { |
|
1656 temp = condense( matcherOut, postMap ); |
|
1657 postFilter( temp, [], context, xml ); |
|
1658 |
|
1659 // Un-match failing elements by moving them back to matcherIn |
|
1660 i = temp.length; |
|
1661 while ( i-- ) { |
|
1662 if ( (elem = temp[i]) ) { |
|
1663 matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem); |
|
1664 } |
|
1665 } |
|
1666 } |
|
1667 |
|
1668 if ( seed ) { |
|
1669 if ( postFinder || preFilter ) { |
|
1670 if ( postFinder ) { |
|
1671 // Get the final matcherOut by condensing this intermediate into postFinder contexts |
|
1672 temp = []; |
|
1673 i = matcherOut.length; |
|
1674 while ( i-- ) { |
|
1675 if ( (elem = matcherOut[i]) ) { |
|
1676 // Restore matcherIn since elem is not yet a final match |
|
1677 temp.push( (matcherIn[i] = elem) ); |
|
1678 } |
|
1679 } |
|
1680 postFinder( null, (matcherOut = []), temp, xml ); |
|
1681 } |
|
1682 |
|
1683 // Move matched elements from seed to results to keep them synchronized |
|
1684 i = matcherOut.length; |
|
1685 while ( i-- ) { |
|
1686 if ( (elem = matcherOut[i]) && |
|
1687 (temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) { |
|
1688 |
|
1689 seed[temp] = !(results[temp] = elem); |
|
1690 } |
|
1691 } |
|
1692 } |
|
1693 |
|
1694 // Add elements to results, through postFinder if defined |
|
1695 } else { |
|
1696 matcherOut = condense( |
|
1697 matcherOut === results ? |
|
1698 matcherOut.splice( preexisting, matcherOut.length ) : |
|
1699 matcherOut |
|
1700 ); |
|
1701 if ( postFinder ) { |
|
1702 postFinder( null, results, matcherOut, xml ); |
|
1703 } else { |
|
1704 push.apply( results, matcherOut ); |
|
1705 } |
|
1706 } |
|
1707 }); |
|
1708 } |
|
1709 |
|
1710 function matcherFromTokens( tokens ) { |
|
1711 var checkContext, matcher, j, |
|
1712 len = tokens.length, |
|
1713 leadingRelative = Expr.relative[ tokens[0].type ], |
|
1714 implicitRelative = leadingRelative || Expr.relative[" "], |
|
1715 i = leadingRelative ? 1 : 0, |
|
1716 |
|
1717 // The foundational matcher ensures that elements are reachable from top-level context(s) |
|
1718 matchContext = addCombinator( function( elem ) { |
|
1719 return elem === checkContext; |
|
1720 }, implicitRelative, true ), |
|
1721 matchAnyContext = addCombinator( function( elem ) { |
|
1722 return indexOf.call( checkContext, elem ) > -1; |
|
1723 }, implicitRelative, true ), |
|
1724 matchers = [ function( elem, context, xml ) { |
|
1725 return ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( |
|
1726 (checkContext = context).nodeType ? |
|
1727 matchContext( elem, context, xml ) : |
|
1728 matchAnyContext( elem, context, xml ) ); |
|
1729 } ]; |
|
1730 |
|
1731 for ( ; i < len; i++ ) { |
|
1732 if ( (matcher = Expr.relative[ tokens[i].type ]) ) { |
|
1733 matchers = [ addCombinator(elementMatcher( matchers ), matcher) ]; |
|
1734 } else { |
|
1735 matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches ); |
|
1736 |
|
1737 // Return special upon seeing a positional matcher |
|
1738 if ( matcher[ expando ] ) { |
|
1739 // Find the next relative operator (if any) for proper handling |
|
1740 j = ++i; |
|
1741 for ( ; j < len; j++ ) { |
|
1742 if ( Expr.relative[ tokens[j].type ] ) { |
|
1743 break; |
|
1744 } |
|
1745 } |
|
1746 return setMatcher( |
|
1747 i > 1 && elementMatcher( matchers ), |
|
1748 i > 1 && toSelector( |
|
1749 // If the preceding token was a descendant combinator, insert an implicit any-element `*` |
|
1750 tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" }) |
|
1751 ).replace( rtrim, "$1" ), |
|
1752 matcher, |
|
1753 i < j && matcherFromTokens( tokens.slice( i, j ) ), |
|
1754 j < len && matcherFromTokens( (tokens = tokens.slice( j )) ), |
|
1755 j < len && toSelector( tokens ) |
|
1756 ); |
|
1757 } |
|
1758 matchers.push( matcher ); |
|
1759 } |
|
1760 } |
|
1761 |
|
1762 return elementMatcher( matchers ); |
|
1763 } |
|
1764 |
|
1765 function matcherFromGroupMatchers( elementMatchers, setMatchers ) { |
|
1766 var bySet = setMatchers.length > 0, |
|
1767 byElement = elementMatchers.length > 0, |
|
1768 superMatcher = function( seed, context, xml, results, outermost ) { |
|
1769 var elem, j, matcher, |
|
1770 matchedCount = 0, |
|
1771 i = "0", |
|
1772 unmatched = seed && [], |
|
1773 setMatched = [], |
|
1774 contextBackup = outermostContext, |
|
1775 // We must always have either seed elements or outermost context |
|
1776 elems = seed || byElement && Expr.find["TAG"]( "*", outermost ), |
|
1777 // Use integer dirruns iff this is the outermost matcher |
|
1778 dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1), |
|
1779 len = elems.length; |
|
1780 |
|
1781 if ( outermost ) { |
|
1782 outermostContext = context !== document && context; |
|
1783 } |
|
1784 |
|
1785 // Add elements passing elementMatchers directly to results |
|
1786 // Keep `i` a string if there are no elements so `matchedCount` will be "00" below |
|
1787 // Support: IE<9, Safari |
|
1788 // Tolerate NodeList properties (IE: "length"; Safari: <number>) matching elements by id |
|
1789 for ( ; i !== len && (elem = elems[i]) != null; i++ ) { |
|
1790 if ( byElement && elem ) { |
|
1791 j = 0; |
|
1792 while ( (matcher = elementMatchers[j++]) ) { |
|
1793 if ( matcher( elem, context, xml ) ) { |
|
1794 results.push( elem ); |
|
1795 break; |
|
1796 } |
|
1797 } |
|
1798 if ( outermost ) { |
|
1799 dirruns = dirrunsUnique; |
|
1800 } |
|
1801 } |
|
1802 |
|
1803 // Track unmatched elements for set filters |
|
1804 if ( bySet ) { |
|
1805 // They will have gone through all possible matchers |
|
1806 if ( (elem = !matcher && elem) ) { |
|
1807 matchedCount--; |
|
1808 } |
|
1809 |
|
1810 // Lengthen the array for every element, matched or not |
|
1811 if ( seed ) { |
|
1812 unmatched.push( elem ); |
|
1813 } |
|
1814 } |
|
1815 } |
|
1816 |
|
1817 // Apply set filters to unmatched elements |
|
1818 matchedCount += i; |
|
1819 if ( bySet && i !== matchedCount ) { |
|
1820 j = 0; |
|
1821 while ( (matcher = setMatchers[j++]) ) { |
|
1822 matcher( unmatched, setMatched, context, xml ); |
|
1823 } |
|
1824 |
|
1825 if ( seed ) { |
|
1826 // Reintegrate element matches to eliminate the need for sorting |
|
1827 if ( matchedCount > 0 ) { |
|
1828 while ( i-- ) { |
|
1829 if ( !(unmatched[i] || setMatched[i]) ) { |
|
1830 setMatched[i] = pop.call( results ); |
|
1831 } |
|
1832 } |
|
1833 } |
|
1834 |
|
1835 // Discard index placeholder values to get only actual matches |
|
1836 setMatched = condense( setMatched ); |
|
1837 } |
|
1838 |
|
1839 // Add matches to results |
|
1840 push.apply( results, setMatched ); |
|
1841 |
|
1842 // Seedless set matches succeeding multiple successful matchers stipulate sorting |
|
1843 if ( outermost && !seed && setMatched.length > 0 && |
|
1844 ( matchedCount + setMatchers.length ) > 1 ) { |
|
1845 |
|
1846 Sizzle.uniqueSort( results ); |
|
1847 } |
|
1848 } |
|
1849 |
|
1850 // Override manipulation of globals by nested matchers |
|
1851 if ( outermost ) { |
|
1852 dirruns = dirrunsUnique; |
|
1853 outermostContext = contextBackup; |
|
1854 } |
|
1855 |
|
1856 return unmatched; |
|
1857 }; |
|
1858 |
|
1859 return bySet ? |
|
1860 markFunction( superMatcher ) : |
|
1861 superMatcher; |
|
1862 } |
|
1863 |
|
1864 compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { |
|
1865 var i, |
|
1866 setMatchers = [], |
|
1867 elementMatchers = [], |
|
1868 cached = compilerCache[ selector + " " ]; |
|
1869 |
|
1870 if ( !cached ) { |
|
1871 // Generate a function of recursive functions that can be used to check each element |
|
1872 if ( !match ) { |
|
1873 match = tokenize( selector ); |
|
1874 } |
|
1875 i = match.length; |
|
1876 while ( i-- ) { |
|
1877 cached = matcherFromTokens( match[i] ); |
|
1878 if ( cached[ expando ] ) { |
|
1879 setMatchers.push( cached ); |
|
1880 } else { |
|
1881 elementMatchers.push( cached ); |
|
1882 } |
|
1883 } |
|
1884 |
|
1885 // Cache the compiled function |
|
1886 cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); |
|
1887 |
|
1888 // Save selector and tokenization |
|
1889 cached.selector = selector; |
|
1890 } |
|
1891 return cached; |
|
1892 }; |
|
1893 |
|
1894 /** |
|
1895 * A low-level selection function that works with Sizzle's compiled |
|
1896 * selector functions |
|
1897 * @param {String|Function} selector A selector or a pre-compiled |
|
1898 * selector function built with Sizzle.compile |
|
1899 * @param {Element} context |
|
1900 * @param {Array} [results] |
|
1901 * @param {Array} [seed] A set of elements to match against |
|
1902 */ |
|
1903 select = Sizzle.select = function( selector, context, results, seed ) { |
|
1904 var i, tokens, token, type, find, |
|
1905 compiled = typeof selector === "function" && selector, |
|
1906 match = !seed && tokenize( (selector = compiled.selector || selector) ); |
|
1907 |
|
1908 results = results || []; |
|
1909 |
|
1910 // Try to minimize operations if there is no seed and only one group |
|
1911 if ( match.length === 1 ) { |
|
1912 |
|
1913 // Take a shortcut and set the context if the root selector is an ID |
|
1914 tokens = match[0] = match[0].slice( 0 ); |
|
1915 if ( tokens.length > 2 && (token = tokens[0]).type === "ID" && |
|
1916 support.getById && context.nodeType === 9 && documentIsHTML && |
|
1917 Expr.relative[ tokens[1].type ] ) { |
|
1918 |
|
1919 context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0]; |
|
1920 if ( !context ) { |
|
1921 return results; |
|
1922 |
|
1923 // Precompiled matchers will still verify ancestry, so step up a level |
|
1924 } else if ( compiled ) { |
|
1925 context = context.parentNode; |
|
1926 } |
|
1927 |
|
1928 selector = selector.slice( tokens.shift().value.length ); |
|
1929 } |
|
1930 |
|
1931 // Fetch a seed set for right-to-left matching |
|
1932 i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length; |
|
1933 while ( i-- ) { |
|
1934 token = tokens[i]; |
|
1935 |
|
1936 // Abort if we hit a combinator |
|
1937 if ( Expr.relative[ (type = token.type) ] ) { |
|
1938 break; |
|
1939 } |
|
1940 if ( (find = Expr.find[ type ]) ) { |
|
1941 // Search, expanding context for leading sibling combinators |
|
1942 if ( (seed = find( |
|
1943 token.matches[0].replace( runescape, funescape ), |
|
1944 rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context |
|
1945 )) ) { |
|
1946 |
|
1947 // If seed is empty or no tokens remain, we can return early |
|
1948 tokens.splice( i, 1 ); |
|
1949 selector = seed.length && toSelector( tokens ); |
|
1950 if ( !selector ) { |
|
1951 push.apply( results, seed ); |
|
1952 return results; |
|
1953 } |
|
1954 |
|
1955 break; |
|
1956 } |
|
1957 } |
|
1958 } |
|
1959 } |
|
1960 |
|
1961 // Compile and execute a filtering function if one is not provided |
|
1962 // Provide `match` to avoid retokenization if we modified the selector above |
|
1963 ( compiled || compile( selector, match ) )( |
|
1964 seed, |
|
1965 context, |
|
1966 !documentIsHTML, |
|
1967 results, |
|
1968 rsibling.test( selector ) && testContext( context.parentNode ) || context |
|
1969 ); |
|
1970 return results; |
|
1971 }; |
|
1972 |
|
1973 // One-time assignments |
|
1974 |
|
1975 // Sort stability |
|
1976 support.sortStable = expando.split("").sort( sortOrder ).join("") === expando; |
|
1977 |
|
1978 // Support: Chrome 14-35+ |
|
1979 // Always assume duplicates if they aren't passed to the comparison function |
|
1980 support.detectDuplicates = !!hasDuplicate; |
|
1981 |
|
1982 // Initialize against the default document |
|
1983 setDocument(); |
|
1984 |
|
1985 // Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) |
|
1986 // Detached nodes confoundingly follow *each other* |
|
1987 support.sortDetached = assert(function( div1 ) { |
|
1988 // Should return 1, but returns 4 (following) |
|
1989 return div1.compareDocumentPosition( document.createElement("div") ) & 1; |
|
1990 }); |
|
1991 |
|
1992 // Support: IE<8 |
|
1993 // Prevent attribute/property "interpolation" |
|
1994 // http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx |
|
1995 if ( !assert(function( div ) { |
|
1996 div.innerHTML = "<a href='#'></a>"; |
|
1997 return div.firstChild.getAttribute("href") === "#" ; |
|
1998 }) ) { |
|
1999 addHandle( "type|href|height|width", function( elem, name, isXML ) { |
|
2000 if ( !isXML ) { |
|
2001 return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); |
|
2002 } |
|
2003 }); |
|
2004 } |
|
2005 |
|
2006 // Support: IE<9 |
|
2007 // Use defaultValue in place of getAttribute("value") |
|
2008 if ( !support.attributes || !assert(function( div ) { |
|
2009 div.innerHTML = "<input/>"; |
|
2010 div.firstChild.setAttribute( "value", "" ); |
|
2011 return div.firstChild.getAttribute( "value" ) === ""; |
|
2012 }) ) { |
|
2013 addHandle( "value", function( elem, name, isXML ) { |
|
2014 if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { |
|
2015 return elem.defaultValue; |
|
2016 } |
|
2017 }); |
|
2018 } |
|
2019 |
|
2020 // Support: IE<9 |
|
2021 // Use getAttributeNode to fetch booleans when getAttribute lies |
|
2022 if ( !assert(function( div ) { |
|
2023 return div.getAttribute("disabled") == null; |
|
2024 }) ) { |
|
2025 addHandle( booleans, function( elem, name, isXML ) { |
|
2026 var val; |
|
2027 if ( !isXML ) { |
|
2028 return elem[ name ] === true ? name.toLowerCase() : |
|
2029 (val = elem.getAttributeNode( name )) && val.specified ? |
|
2030 val.value : |
|
2031 null; |
|
2032 } |
|
2033 }); |
|
2034 } |
|
2035 |
|
2036 // EXPOSE |
|
2037 return Sizzle; |
|
2038 }); |