1 /*! 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/ 6 */ 7 (function(){ 8 9 var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, 10 done = 0, 11 toString = Object.prototype.toString, 12 hasDuplicate = false, 13 baseHasDuplicate = true, 14 rBackslash = /\\/g, 15 rNonWord = /\W/; 16 17 // Here we check if the JavaScript engine is using some sort of 18 // optimization where it does not always call our comparision 19 // function. If that is the case, discard the hasDuplicate value. 20 // Thus far that includes Google Chrome. 21 [0, 0].sort(function() { 22 baseHasDuplicate = false; 23 return 0; 24 }); 25 26 var Sizzle = function( selector, context, results, seed ) { 27 results = results || []; 28 context = context || document; 29 30 var origContext = context; 31 32 if ( context.nodeType !== 1 && context.nodeType !== 9 ) { 33 return []; 34 } 35 36 if ( !selector || typeof selector !== "string" ) { 37 return results; 38 } 39 40 var m, set, checkSet, extra, ret, cur, pop, i, 41 prune = true, 42 contextXML = Sizzle.isXML( context ), 43 parts = [], 44 soFar = selector; 45 46 // Reset the position of the chunker regexp (start from head) 47 do { 48 chunker.exec( "" ); 49 m = chunker.exec( soFar ); 50 51 if ( m ) { 52 soFar = m[3]; 53 54 parts.push( m[1] ); 55 56 if ( m[2] ) { 57 extra = m[3]; 58 break; 59 } 60 } 61 } while ( m ); 62 63 if ( parts.length > 1 && origPOS.exec( selector ) ) { 64 65 if ( parts.length === 2 && Expr.relative[ parts[0] ] ) { 66 set = posProcess( parts[0] + parts[1], context ); 67 68 } else { 69 set = Expr.relative[ parts[0] ] ? 70 [ context ] : 71 Sizzle( parts.shift(), context ); 72 73 while ( parts.length ) { 74 selector = parts.shift(); 75 76 if ( Expr.relative[ selector ] ) { 77 selector += parts.shift(); 78 } 79 80 set = posProcess( selector, set ); 81 } 82 } 83 84 } else { 85 // Take a shortcut and set the context if the root selector is an ID 86 // (but not if it'll be faster if the inner selector is an ID) 87 if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML && 88 Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) { 89 90 ret = Sizzle.find( parts.shift(), context, contextXML ); 91 context = ret.expr ? 92 Sizzle.filter( ret.expr, ret.set )[0] : 93 ret.set[0]; 94 } 95 96 if ( context ) { 97 ret = seed ? 98 { expr: parts.pop(), set: makeArray(seed) } : 99 Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML ); 100 101 set = ret.expr ? 102 Sizzle.filter( ret.expr, ret.set ) : 103 ret.set; 104 105 if ( parts.length > 0 ) { 106 checkSet = makeArray( set ); 107 108 } else { 109 prune = false; 110 } 111 112 while ( parts.length ) { 113 cur = parts.pop(); 114 pop = cur; 115 116 if ( !Expr.relative[ cur ] ) { 117 cur = ""; 118 } else { 119 pop = parts.pop(); 120 } 121 122 if ( pop == null ) { 123 pop = context; 124 } 125 126 Expr.relative[ cur ]( checkSet, pop, contextXML ); 127 } 128 129 } else { 130 checkSet = parts = []; 131 } 132 } 133 134 if ( !checkSet ) { 135 checkSet = set; 136 } 137 138 if ( !checkSet ) { 139 Sizzle.error( cur || selector ); 140 } 141 142 if ( toString.call(checkSet) === "[object Array]" ) { 143 if ( !prune ) { 144 results.push.apply( results, checkSet ); 145 146 } else if ( context && context.nodeType === 1 ) { 147 for ( i = 0; checkSet[i] != null; i++ ) { 148 if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && Sizzle.contains(context, checkSet[i])) ) { 149 results.push( set[i] ); 150 } 151 } 152 153 } else { 154 for ( i = 0; checkSet[i] != null; i++ ) { 155 if ( checkSet[i] && checkSet[i].nodeType === 1 ) { 156 results.push( set[i] ); 157 } 158 } 159 } 160 161 } else { 162 makeArray( checkSet, results ); 163 } 164 165 if ( extra ) { 166 Sizzle( extra, origContext, results, seed ); 167 Sizzle.uniqueSort( results ); 168 } 169 170 return results; 171 }; 172 173 Sizzle.uniqueSort = function( results ) { 174 if ( sortOrder ) { 175 hasDuplicate = baseHasDuplicate; 176 results.sort( sortOrder ); 177 178 if ( hasDuplicate ) { 179 for ( var i = 1; i < results.length; i++ ) { 180 if ( results[i] === results[ i - 1 ] ) { 181 results.splice( i--, 1 ); 182 } 183 } 184 } 185 } 186 187 return results; 188 }; 189 190 Sizzle.matches = function( expr, set ) { 191 return Sizzle( expr, null, null, set ); 192 }; 193 194 Sizzle.matchesSelector = function( node, expr ) { 195 return Sizzle( expr, null, null, [node] ).length > 0; 196 }; 197 198 Sizzle.find = function( expr, context, isXML ) { 199 var set; 200 201 if ( !expr ) { 202 return []; 203 } 204 205 for ( var i = 0, l = Expr.order.length; i < l; i++ ) { 206 var match, 207 type = Expr.order[i]; 208 209 if ( (match = Expr.leftMatch[ type ].exec( expr )) ) { 210 var left = match[1]; 211 match.splice( 1, 1 ); 212 213 if ( left.substr( left.length - 1 ) !== "\\" ) { 214 match[1] = (match[1] || "").replace( rBackslash, "" ); 215 set = Expr.find[ type ]( match, context, isXML ); 216 217 if ( set != null ) { 218 expr = expr.replace( Expr.match[ type ], "" ); 219 break; 220 } 221 } 222 } 223 } 224 225 if ( !set ) { 226 set = typeof context.getElementsByTagName !== "undefined" ? 227 context.getElementsByTagName( "*" ) : 228 []; 229 } 230 231 return { set: set, expr: expr }; 232 }; 233 234 Sizzle.filter = function( expr, set, inplace, not ) { 235 var match, anyFound, 236 old = expr, 237 result = [], 238 curLoop = set, 239 isXMLFilter = set && set[0] && Sizzle.isXML( set[0] ); 240 241 while ( expr && set.length ) { 242 for ( var type in Expr.filter ) { 243 if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) { 244 var found, item, 245 filter = Expr.filter[ type ], 246 left = match[1]; 247 248 anyFound = false; 249 250 match.splice(1,1); 251 252 if ( left.substr( left.length - 1 ) === "\\" ) { 253 continue; 254 } 255 256 if ( curLoop === result ) { 257 result = []; 258 } 259 260 if ( Expr.preFilter[ type ] ) { 261 match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter ); 262 263 if ( !match ) { 264 anyFound = found = true; 265 266 } else if ( match === true ) { 267 continue; 268 } 269 } 270 271 if ( match ) { 272 for ( var i = 0; (item = curLoop[i]) != null; i++ ) { 273 if ( item ) { 274 found = filter( item, match, i, curLoop ); 275 var pass = not ^ !!found; 276 277 if ( inplace && found != null ) { 278 if ( pass ) { 279 anyFound = true; 280 281 } else { 282 curLoop[i] = false; 283 } 284 285 } else if ( pass ) { 286 result.push( item ); 287 anyFound = true; 288 } 289 } 290 } 291 } 292 293 if ( found !== undefined ) { 294 if ( !inplace ) { 295 curLoop = result; 296 } 297 298 expr = expr.replace( Expr.match[ type ], "" ); 299 300 if ( !anyFound ) { 301 return []; 302 } 303 304 break; 305 } 306 } 307 } 308 309 // Improper expression 310 if ( expr === old ) { 311 if ( anyFound == null ) { 312 Sizzle.error( expr ); 313 314 } else { 315 break; 316 } 317 } 318 319 old = expr; 320 } 321 322 return curLoop; 323 }; 324 325 Sizzle.error = function( msg ) { 326 throw "Syntax error, unrecognized expression: " + msg; 327 }; 328 329 var Expr = Sizzle.selectors = { 330 order: [ "ID", "NAME", "TAG" ], 331 332 match: { 333 ID: /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/, 334 CLASS: /\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/, 335 NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/, 336 ATTR: /\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/, 337 TAG: /^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/, 338 CHILD: /:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/, 339 POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/, 340 PSEUDO: /:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/ 341 }, 342 343 leftMatch: {}, 344 345 attrMap: { 346 "class": "className", 347 "for": "htmlFor" 348 }, 349 350 attrHandle: { 351 href: function( elem ) { 352 return elem.getAttribute( "href" ); 353 }, 354 type: function( elem ) { 355 return elem.getAttribute( "type" ); 356 } 357 }, 358 359 relative: { 360 "+": function(checkSet, part){ 361 var isPartStr = typeof part === "string", 362 isTag = isPartStr && !rNonWord.test( part ), 363 isPartStrNotTag = isPartStr && !isTag; 364 365 if ( isTag ) { 366 part = part.toLowerCase(); 367 } 368 369 for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) { 370 if ( (elem = checkSet[i]) ) { 371 while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {} 372 373 checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ? 374 elem || false : 375 elem === part; 376 } 377 } 378 379 if ( isPartStrNotTag ) { 380 Sizzle.filter( part, checkSet, true ); 381 } 382 }, 383 384 ">": function( checkSet, part ) { 385 var elem, 386 isPartStr = typeof part === "string", 387 i = 0, 388 l = checkSet.length; 389 390 if ( isPartStr && !rNonWord.test( part ) ) { 391 part = part.toLowerCase(); 392 393 for ( ; i < l; i++ ) { 394 elem = checkSet[i]; 395 396 if ( elem ) { 397 var parent = elem.parentNode; 398 checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false; 399 } 400 } 401 402 } else { 403 for ( ; i < l; i++ ) { 404 elem = checkSet[i]; 405 406 if ( elem ) { 407 checkSet[i] = isPartStr ? 408 elem.parentNode : 409 elem.parentNode === part; 410 } 411 } 412 413 if ( isPartStr ) { 414 Sizzle.filter( part, checkSet, true ); 415 } 416 } 417 }, 418 419 "": function(checkSet, part, isXML){ 420 var nodeCheck, 421 doneName = done++, 422 checkFn = dirCheck; 423 424 if ( typeof part === "string" && !rNonWord.test( part ) ) { 425 part = part.toLowerCase(); 426 nodeCheck = part; 427 checkFn = dirNodeCheck; 428 } 429 430 checkFn( "parentNode", part, doneName, checkSet, nodeCheck, isXML ); 431 }, 432 433 "~": function( checkSet, part, isXML ) { 434 var nodeCheck, 435 doneName = done++, 436 checkFn = dirCheck; 437 438 if ( typeof part === "string" && !rNonWord.test( part ) ) { 439 part = part.toLowerCase(); 440 nodeCheck = part; 441 checkFn = dirNodeCheck; 442 } 443 444 checkFn( "previousSibling", part, doneName, checkSet, nodeCheck, isXML ); 445 } 446 }, 447 448 find: { 449 ID: function( match, context, isXML ) { 450 if ( typeof context.getElementById !== "undefined" && !isXML ) { 451 var m = context.getElementById(match[1]); 452 // Check parentNode to catch when Blackberry 4.6 returns 453 // nodes that are no longer in the document #6963 454 return m && m.parentNode ? [m] : []; 455 } 456 }, 457 458 NAME: function( match, context ) { 459 if ( typeof context.getElementsByName !== "undefined" ) { 460 var ret = [], 461 results = context.getElementsByName( match[1] ); 462 463 for ( var i = 0, l = results.length; i < l; i++ ) { 464 if ( results[i].getAttribute("name") === match[1] ) { 465 ret.push( results[i] ); 466 } 467 } 468 469 return ret.length === 0 ? null : ret; 470 } 471 }, 472 473 TAG: function( match, context ) { 474 if ( typeof context.getElementsByTagName !== "undefined" ) { 475 return context.getElementsByTagName( match[1] ); 476 } 477 } 478 }, 479 preFilter: { 480 CLASS: function( match, curLoop, inplace, result, not, isXML ) { 481 match = " " + match[1].replace( rBackslash, "" ) + " "; 482 483 if ( isXML ) { 484 return match; 485 } 486 487 for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) { 488 if ( elem ) { 489 if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n\r]/g, " ").indexOf(match) >= 0) ) { 490 if ( !inplace ) { 491 result.push( elem ); 492 } 493 494 } else if ( inplace ) { 495 curLoop[i] = false; 496 } 497 } 498 } 499 500 return false; 501 }, 502 503 ID: function( match ) { 504 return match[1].replace( rBackslash, "" ); 505 }, 506 507 TAG: function( match, curLoop ) { 508 return match[1].replace( rBackslash, "" ).toLowerCase(); 509 }, 510 511 CHILD: function( match ) { 512 if ( match[1] === "nth" ) { 513 if ( !match[2] ) { 514 Sizzle.error( match[0] ); 515 } 516 517 match[2] = match[2].replace(/^\+|\s*/g, ''); 518 519 // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6' 520 var test = /(-?)(\d*)(?:n([+\-]?\d*))?/.exec( 521 match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" || 522 !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]); 523 524 // calculate the numbers (first)n+(last) including if they are negative 525 match[2] = (test[1] + (test[2] || 1)) - 0; 526 match[3] = test[3] - 0; 527 } 528 else if ( match[2] ) { 529 Sizzle.error( match[0] ); 530 } 531 532 // TODO: Move to normal caching system 533 match[0] = done++; 534 535 return match; 536 }, 537 538 ATTR: function( match, curLoop, inplace, result, not, isXML ) { 539 var name = match[1] = match[1].replace( rBackslash, "" ); 540 541 if ( !isXML && Expr.attrMap[name] ) { 542 match[1] = Expr.attrMap[name]; 543 } 544 545 // Handle if an un-quoted value was used 546 match[4] = ( match[4] || match[5] || "" ).replace( rBackslash, "" ); 547 548 if ( match[2] === "~=" ) { 549 match[4] = " " + match[4] + " "; 550 } 551 552 return match; 553 }, 554 555 PSEUDO: function( match, curLoop, inplace, result, not ) { 556 if ( match[1] === "not" ) { 557 // If we're dealing with a complex expression, or a simple one 558 if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) { 559 match[3] = Sizzle(match[3], null, null, curLoop); 560 561 } else { 562 var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not); 563 564 if ( !inplace ) { 565 result.push.apply( result, ret ); 566 } 567 568 return false; 569 } 570 571 } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) { 572 return true; 573 } 574 575 return match; 576 }, 577 578 POS: function( match ) { 579 match.unshift( true ); 580 581 return match; 582 } 583 }, 584 585 filters: { 586 enabled: function( elem ) { 587 return elem.disabled === false && elem.type !== "hidden"; 588 }, 589 590 disabled: function( elem ) { 591 return elem.disabled === true; 592 }, 593 594 checked: function( elem ) { 595 return elem.checked === true; 596 }, 597 598 selected: function( elem ) { 599 // Accessing this property makes selected-by-default 600 // options in Safari work properly 601 if ( elem.parentNode ) { 602 elem.parentNode.selectedIndex; 603 } 604 605 return elem.selected === true; 606 }, 607 608 parent: function( elem ) { 609 return !!elem.firstChild; 610 }, 611 612 empty: function( elem ) { 613 return !elem.firstChild; 614 }, 615 616 has: function( elem, i, match ) { 617 return !!Sizzle( match[3], elem ).length; 618 }, 619 620 header: function( elem ) { 621 return (/h\d/i).test( elem.nodeName ); 622 }, 623 624 text: function( elem ) { 625 // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) 626 // use getAttribute instead to test this case 627 return "text" === elem.getAttribute( 'type' ); 628 }, 629 radio: function( elem ) { 630 return "radio" === elem.type; 631 }, 632 633 checkbox: function( elem ) { 634 return "checkbox" === elem.type; 635 }, 636 637 file: function( elem ) { 638 return "file" === elem.type; 639 }, 640 password: function( elem ) { 641 return "password" === elem.type; 642 }, 643 644 submit: function( elem ) { 645 return "submit" === elem.type; 646 }, 647 648 image: function( elem ) { 649 return "image" === elem.type; 650 }, 651 652 reset: function( elem ) { 653 return "reset" === elem.type; 654 }, 655 656 button: function( elem ) { 657 return "button" === elem.type || elem.nodeName.toLowerCase() === "button"; 658 }, 659 660 input: function( elem ) { 661 return (/input|select|textarea|button/i).test( elem.nodeName ); 662 } 663 }, 664 setFilters: { 665 first: function( elem, i ) { 666 return i === 0; 667 }, 668 669 last: function( elem, i, match, array ) { 670 return i === array.length - 1; 671 }, 672 673 even: function( elem, i ) { 674 return i % 2 === 0; 675 }, 676 677 odd: function( elem, i ) { 678 return i % 2 === 1; 679 }, 680 681 lt: function( elem, i, match ) { 682 return i < match[3] - 0; 683 }, 684 685 gt: function( elem, i, match ) { 686 return i > match[3] - 0; 687 }, 688 689 nth: function( elem, i, match ) { 690 return match[3] - 0 === i; 691 }, 692 693 eq: function( elem, i, match ) { 694 return match[3] - 0 === i; 695 } 696 }, 697 filter: { 698 PSEUDO: function( elem, match, i, array ) { 699 var name = match[1], 700 filter = Expr.filters[ name ]; 701 702 if ( filter ) { 703 return filter( elem, i, match, array ); 704 705 } else if ( name === "contains" ) { 706 return (elem.textContent || elem.innerText || Sizzle.getText([ elem ]) || "").indexOf(match[3]) >= 0; 707 708 } else if ( name === "not" ) { 709 var not = match[3]; 710 711 for ( var j = 0, l = not.length; j < l; j++ ) { 712 if ( not[j] === elem ) { 713 return false; 714 } 715 } 716 717 return true; 718 719 } else { 720 Sizzle.error( name ); 721 } 722 }, 723 724 CHILD: function( elem, match ) { 725 var type = match[1], 726 node = elem; 727 728 switch ( type ) { 729 case "only": 730 case "first": 731 while ( (node = node.previousSibling) ) { 732 if ( node.nodeType === 1 ) { 733 return false; 734 } 735 } 736 737 if ( type === "first" ) { 738 return true; 739 } 740 741 node = elem; 742 743 case "last": 744 while ( (node = node.nextSibling) ) { 745 if ( node.nodeType === 1 ) { 746 return false; 747 } 748 } 749 750 return true; 751 752 case "nth": 753 var first = match[2], 754 last = match[3]; 755 756 if ( first === 1 && last === 0 ) { 757 return true; 758 } 759 760 var doneName = match[0], 761 parent = elem.parentNode; 762 763 if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) { 764 var count = 0; 765 766 for ( node = parent.firstChild; node; node = node.nextSibling ) { 767 if ( node.nodeType === 1 ) { 768 node.nodeIndex = ++count; 769 } 770 } 771 772 parent.sizcache = doneName; 773 } 774 775 var diff = elem.nodeIndex - last; 776 777 if ( first === 0 ) { 778 return diff === 0; 779 780 } else { 781 return ( diff % first === 0 && diff / first >= 0 ); 782 } 783 } 784 }, 785 786 ID: function( elem, match ) { 787 return elem.nodeType === 1 && elem.getAttribute("id") === match; 788 }, 789 790 TAG: function( elem, match ) { 791 return (match === "*" && elem.nodeType === 1) || elem.nodeName.toLowerCase() === match; 792 }, 793 794 CLASS: function( elem, match ) { 795 return (" " + (elem.className || elem.getAttribute("class")) + " ") 796 .indexOf( match ) > -1; 797 }, 798 799 ATTR: function( elem, match ) { 800 var name = match[1], 801 result = Expr.attrHandle[ name ] ? 802 Expr.attrHandle[ name ]( elem ) : 803 elem[ name ] != null ? 804 elem[ name ] : 805 elem.getAttribute( name ), 806 value = result + "", 807 type = match[2], 808 check = match[4]; 809 810 return result == null ? 811 type === "!=" : 812 type === "=" ? 813 value === check : 814 type === "*=" ? 815 value.indexOf(check) >= 0 : 816 type === "~=" ? 817 (" " + value + " ").indexOf(check) >= 0 : 818 !check ? 819 value && result !== false : 820 type === "!=" ? 821 value !== check : 822 type === "^=" ? 823 value.indexOf(check) === 0 : 824 type === "$=" ? 825 value.substr(value.length - check.length) === check : 826 type === "|=" ? 827 value === check || value.substr(0, check.length + 1) === check + "-" : 828 false; 829 }, 830 831 POS: function( elem, match, i, array ) { 832 var name = match[2], 833 filter = Expr.setFilters[ name ]; 834 835 if ( filter ) { 836 return filter( elem, i, match, array ); 837 } 838 } 839 } 840 }; 841 842 var origPOS = Expr.match.POS, 843 fescape = function(all, num){ 844 return "\\" + (num - 0 + 1); 845 }; 846 847 for ( var type in Expr.match ) { 848 Expr.match[ type ] = new RegExp( Expr.match[ type ].source + (/(?![^\[]*\])(?![^\(]*\))/.source) ); 849 Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, fescape) ); 850 } 851 852 var makeArray = function( array, results ) { 853 array = Array.prototype.slice.call( array, 0 ); 854 855 if ( results ) { 856 results.push.apply( results, array ); 857 return results; 858 } 859 860 return array; 861 }; 862 863 // Perform a simple check to determine if the browser is capable of 864 // converting a NodeList to an array using builtin methods. 865 // Also verifies that the returned array holds DOM nodes 866 // (which is not the case in the Blackberry browser) 867 try { 868 Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType; 869 870 // Provide a fallback method if it does not work 871 } catch( e ) { 872 makeArray = function( array, results ) { 873 var i = 0, 874 ret = results || []; 875 876 if ( toString.call(array) === "[object Array]" ) { 877 Array.prototype.push.apply( ret, array ); 878 879 } else { 880 if ( typeof array.length === "number" ) { 881 for ( var l = array.length; i < l; i++ ) { 882 ret.push( array[i] ); 883 } 884 885 } else { 886 for ( ; array[i]; i++ ) { 887 ret.push( array[i] ); 888 } 889 } 890 } 891 892 return ret; 893 }; 894 } 895 896 var sortOrder, siblingCheck; 897 898 if ( document.documentElement.compareDocumentPosition ) { 899 sortOrder = function( a, b ) { 900 if ( a === b ) { 901 hasDuplicate = true; 902 return 0; 903 } 904 905 if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) { 906 return a.compareDocumentPosition ? -1 : 1; 907 } 908 909 return a.compareDocumentPosition(b) & 4 ? -1 : 1; 910 }; 911 912 } else { 913 sortOrder = function( a, b ) { 914 var al, bl, 915 ap = [], 916 bp = [], 917 aup = a.parentNode, 918 bup = b.parentNode, 919 cur = aup; 920 921 // The nodes are identical, we can exit early 922 if ( a === b ) { 923 hasDuplicate = true; 924 return 0; 925 926 // If the nodes are siblings (or identical) we can do a quick check 927 } else if ( aup === bup ) { 928 return siblingCheck( a, b ); 929 930 // If no parents were found then the nodes are disconnected 931 } else if ( !aup ) { 932 return -1; 933 934 } else if ( !bup ) { 935 return 1; 936 } 937 938 // Otherwise they're somewhere else in the tree so we need 939 // to build up a full list of the parentNodes for comparison 940 while ( cur ) { 941 ap.unshift( cur ); 942 cur = cur.parentNode; 943 } 944 945 cur = bup; 946 947 while ( cur ) { 948 bp.unshift( cur ); 949 cur = cur.parentNode; 950 } 951 952 al = ap.length; 953 bl = bp.length; 954 955 // Start walking down the tree looking for a discrepancy 956 for ( var i = 0; i < al && i < bl; i++ ) { 957 if ( ap[i] !== bp[i] ) { 958 return siblingCheck( ap[i], bp[i] ); 959 } 960 } 961 962 // We ended someplace up the tree so do a sibling check 963 return i === al ? 964 siblingCheck( a, bp[i], -1 ) : 965 siblingCheck( ap[i], b, 1 ); 966 }; 967 968 siblingCheck = function( a, b, ret ) { 969 if ( a === b ) { 970 return ret; 971 } 972 973 var cur = a.nextSibling; 974 975 while ( cur ) { 976 if ( cur === b ) { 977 return -1; 978 } 979 980 cur = cur.nextSibling; 981 } 982 983 return 1; 984 }; 985 } 986 987 // Utility function for retreiving the text value of an array of DOM nodes 988 Sizzle.getText = function( elems ) { 989 var ret = "", elem; 990 991 for ( var i = 0; elems[i]; i++ ) { 992 elem = elems[i]; 993 994 // Get the text from text nodes and CDATA nodes 995 if ( elem.nodeType === 3 || elem.nodeType === 4 ) { 996 ret += elem.nodeValue; 997 998 // Traverse everything else, except comment nodes 999 } else if ( elem.nodeType !== 8 ) { 1000 ret += Sizzle.getText( elem.childNodes ); 1001 } 1002 } 1003 1004 return ret; 1005 }; 1006 1007 // Check to see if the browser returns elements by name when 1008 // querying by getElementById (and provide a workaround) 1009 (function(){ 1010 // We're going to inject a fake input element with a specified name 1011 var form = document.createElement("div"), 1012 id = "script" + (new Date()).getTime(), 1013 root = document.documentElement; 1014 1015 form.innerHTML = "<a name='" + id + "'/>"; 1016 1017 // Inject it into the root element, check its status, and remove it quickly 1018 root.insertBefore( form, root.firstChild ); 1019 1020 // The workaround has to do additional checks after a getElementById 1021 // Which slows things down for other browsers (hence the branching) 1022 if ( document.getElementById( id ) ) { 1023 Expr.find.ID = function( match, context, isXML ) { 1024 if ( typeof context.getElementById !== "undefined" && !isXML ) { 1025 var m = context.getElementById(match[1]); 1026 1027 return m ? 1028 m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? 1029 [m] : 1030 undefined : 1031 []; 1032 } 1033 }; 1034 1035 Expr.filter.ID = function( elem, match ) { 1036 var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id"); 1037 1038 return elem.nodeType === 1 && node && node.nodeValue === match; 1039 }; 1040 } 1041 1042 root.removeChild( form ); 1043 1044 // release memory in IE 1045 root = form = null; 1046 })(); 1047 1048 (function(){ 1049 // Check to see if the browser returns only elements 1050 // when doing getElementsByTagName("*") 1051 1052 // Create a fake element 1053 var div = document.createElement("div"); 1054 div.appendChild( document.createComment("") ); 1055 1056 // Make sure no comments are found 1057 if ( div.getElementsByTagName("*").length > 0 ) { 1058 Expr.find.TAG = function( match, context ) { 1059 var results = context.getElementsByTagName( match[1] ); 1060 1061 // Filter out possible comments 1062 if ( match[1] === "*" ) { 1063 var tmp = []; 1064 1065 for ( var i = 0; results[i]; i++ ) { 1066 if ( results[i].nodeType === 1 ) { 1067 tmp.push( results[i] ); 1068 } 1069 } 1070 1071 results = tmp; 1072 } 1073 1074 return results; 1075 }; 1076 } 1077 1078 // Check to see if an attribute returns normalized href attributes 1079 div.innerHTML = "<a href='#'></a>"; 1080 1081 if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" && 1082 div.firstChild.getAttribute("href") !== "#" ) { 1083 1084 Expr.attrHandle.href = function( elem ) { 1085 return elem.getAttribute( "href", 2 ); 1086 }; 1087 } 1088 1089 // release memory in IE 1090 div = null; 1091 })(); 1092 1093 if ( document.querySelectorAll ) { 1094 (function(){ 1095 var oldSizzle = Sizzle, 1096 div = document.createElement("div"), 1097 id = "__sizzle__"; 1098 1099 div.innerHTML = "<p class='TEST'></p>"; 1100 1101 // Safari can't handle uppercase or unicode characters when 1102 // in quirks mode. 1103 if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) { 1104 return; 1105 } 1106 1107 Sizzle = function( query, context, extra, seed ) { 1108 context = context || document; 1109 1110 // Only use querySelectorAll on non-XML documents 1111 // (ID selectors don't work in non-HTML documents) 1112 if ( !seed && !Sizzle.isXML(context) ) { 1113 // See if we find a selector to speed up 1114 var match = /^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec( query ); 1115 1116 if ( match && (context.nodeType === 1 || context.nodeType === 9) ) { 1117 // Speed-up: Sizzle("TAG") 1118 if ( match[1] ) { 1119 return makeArray( context.getElementsByTagName( query ), extra ); 1120 1121 // Speed-up: Sizzle(".CLASS") 1122 } else if ( match[2] && Expr.find.CLASS && context.getElementsByClassName ) { 1123 return makeArray( context.getElementsByClassName( match[2] ), extra ); 1124 } 1125 } 1126 1127 if ( context.nodeType === 9 ) { 1128 // Speed-up: Sizzle("body") 1129 // The body element only exists once, optimize finding it 1130 if ( query === "body" && context.body ) { 1131 return makeArray( [ context.body ], extra ); 1132 1133 // Speed-up: Sizzle("#ID") 1134 } else if ( match && match[3] ) { 1135 var elem = context.getElementById( match[3] ); 1136 1137 // Check parentNode to catch when Blackberry 4.6 returns 1138 // nodes that are no longer in the document #6963 1139 if ( elem && elem.parentNode ) { 1140 // Handle the case where IE and Opera return items 1141 // by name instead of ID 1142 if ( elem.id === match[3] ) { 1143 return makeArray( [ elem ], extra ); 1144 } 1145 1146 } else { 1147 return makeArray( [], extra ); 1148 } 1149 } 1150 1151 try { 1152 return makeArray( context.querySelectorAll(query), extra ); 1153 } catch(qsaError) {} 1154 1155 // qSA works strangely on Element-rooted queries 1156 // We can work around this by specifying an extra ID on the root 1157 // and working up from there (Thanks to Andrew Dupont for the technique) 1158 // IE 8 doesn't work on object elements 1159 } else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) { 1160 var oldContext = context, 1161 old = context.getAttribute( "id" ), 1162 nid = old || id, 1163 hasParent = context.parentNode, 1164 relativeHierarchySelector = /^\s*[+~]/.test( query ); 1165 1166 if ( !old ) { 1167 context.setAttribute( "id", nid ); 1168 } else { 1169 nid = nid.replace( /'/g, "\\$&" ); 1170 } 1171 if ( relativeHierarchySelector && hasParent ) { 1172 context = context.parentNode; 1173 } 1174 1175 try { 1176 if ( !relativeHierarchySelector || hasParent ) { 1177 return makeArray( context.querySelectorAll( "[id='" + nid + "'] " + query ), extra ); 1178 } 1179 1180 } catch(pseudoError) { 1181 } finally { 1182 if ( !old ) { 1183 oldContext.removeAttribute( "id" ); 1184 } 1185 } 1186 } 1187 } 1188 1189 return oldSizzle(query, context, extra, seed); 1190 }; 1191 1192 for ( var prop in oldSizzle ) { 1193 Sizzle[ prop ] = oldSizzle[ prop ]; 1194 } 1195 1196 // release memory in IE 1197 div = null; 1198 })(); 1199 } 1200 1201 (function(){ 1202 var html = document.documentElement, 1203 matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector, 1204 pseudoWorks = false; 1205 1206 try { 1207 // This should fail with an exception 1208 // Gecko does not error, returns false instead 1209 matches.call( document.documentElement, "[test!='']:sizzle" ); 1210 1211 } catch( pseudoError ) { 1212 pseudoWorks = true; 1213 } 1214 1215 if ( matches ) { 1216 Sizzle.matchesSelector = function( node, expr ) { 1217 // Make sure that attribute selectors are quoted 1218 expr = expr.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']"); 1219 1220 if ( !Sizzle.isXML( node ) ) { 1221 try { 1222 if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) { 1223 return matches.call( node, expr ); 1224 } 1225 } catch(e) {} 1226 } 1227 1228 return Sizzle(expr, null, null, [node]).length > 0; 1229 }; 1230 } 1231 })(); 1232 1233 (function(){ 1234 var div = document.createElement("div"); 1235 1236 div.innerHTML = "<div class='test e'></div><div class='test'></div>"; 1237 1238 // Opera can't find a second classname (in 9.6) 1239 // Also, make sure that getElementsByClassName actually exists 1240 if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) { 1241 return; 1242 } 1243 1244 // Safari caches class attributes, doesn't catch changes (in 3.2) 1245 div.lastChild.className = "e"; 1246 1247 if ( div.getElementsByClassName("e").length === 1 ) { 1248 return; 1249 } 1250 1251 Expr.order.splice(1, 0, "CLASS"); 1252 Expr.find.CLASS = function( match, context, isXML ) { 1253 if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) { 1254 return context.getElementsByClassName(match[1]); 1255 } 1256 }; 1257 1258 // release memory in IE 1259 div = null; 1260 })(); 1261 1262 function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { 1263 for ( var i = 0, l = checkSet.length; i < l; i++ ) { 1264 var elem = checkSet[i]; 1265 1266 if ( elem ) { 1267 var match = false; 1268 1269 elem = elem[dir]; 1270 1271 while ( elem ) { 1272 if ( elem.sizcache === doneName ) { 1273 match = checkSet[elem.sizset]; 1274 break; 1275 } 1276 1277 if ( elem.nodeType === 1 && !isXML ){ 1278 elem.sizcache = doneName; 1279 elem.sizset = i; 1280 } 1281 1282 if ( elem.nodeName.toLowerCase() === cur ) { 1283 match = elem; 1284 break; 1285 } 1286 1287 elem = elem[dir]; 1288 } 1289 1290 checkSet[i] = match; 1291 } 1292 } 1293 } 1294 1295 function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { 1296 for ( var i = 0, l = checkSet.length; i < l; i++ ) { 1297 var elem = checkSet[i]; 1298 1299 if ( elem ) { 1300 var match = false; 1301 1302 elem = elem[dir]; 1303 1304 while ( elem ) { 1305 if ( elem.sizcache === doneName ) { 1306 match = checkSet[elem.sizset]; 1307 break; 1308 } 1309 1310 if ( elem.nodeType === 1 ) { 1311 if ( !isXML ) { 1312 elem.sizcache = doneName; 1313 elem.sizset = i; 1314 } 1315 1316 if ( typeof cur !== "string" ) { 1317 if ( elem === cur ) { 1318 match = true; 1319 break; 1320 } 1321 1322 } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) { 1323 match = elem; 1324 break; 1325 } 1326 } 1327 1328 elem = elem[dir]; 1329 } 1330 1331 checkSet[i] = match; 1332 } 1333 } 1334 } 1335 1336 if ( document.documentElement.contains ) { 1337 Sizzle.contains = function( a, b ) { 1338 return a !== b && (a.contains ? a.contains(b) : true); 1339 }; 1340 1341 } else if ( document.documentElement.compareDocumentPosition ) { 1342 Sizzle.contains = function( a, b ) { 1343 return !!(a.compareDocumentPosition(b) & 16); 1344 }; 1345 1346 } else { 1347 Sizzle.contains = function() { 1348 return false; 1349 }; 1350 } 1351 1352 Sizzle.isXML = function( elem ) { 1353 // documentElement is verified for cases where it doesn't yet exist 1354 // (such as loading iframes in IE - #4833) 1355 var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement; 1356 1357 return documentElement ? documentElement.nodeName !== "HTML" : false; 1358 }; 1359 1360 var posProcess = function( selector, context ) { 1361 var match, 1362 tmpSet = [], 1363 later = "", 1364 root = context.nodeType ? [context] : context; 1365 1366 // Position selectors must be done after the filter 1367 // And so must :not(positional) so we move all PSEUDOs to the end 1368 while ( (match = Expr.match.PSEUDO.exec( selector )) ) { 1369 later += match[0]; 1370 selector = selector.replace( Expr.match.PSEUDO, "" ); 1371 } 1372 1373 selector = Expr.relative[selector] ? selector + "*" : selector; 1374 1375 for ( var i = 0, l = root.length; i < l; i++ ) { 1376 Sizzle( selector, root[i], tmpSet ); 1377 } 1378 1379 return Sizzle.filter( later, tmpSet ); 1380 }; 1381 1382 // EXPOSE 1383 1384 window.i$.query = Sizzle; 1385 1386 })(); 1387