1 /* 2 * ! Sizzle CSS Selector Engine - v1.0 Copyright 2009, The Dojo Foundation 3 * Released under the MIT, BSD, and GPL Licenses. More information: 4 * http://sizzlejs.com/ 5 */ 6 (function() { 7 8 var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?/g, 9 done = 0, 10 toString = Object.prototype.toString, 11 hasDuplicate = false; 12 13 var Sizzle = function(selector, context, results, seed) { 14 results = results || []; 15 var origContext = context = context || document; 16 17 if (context.nodeType !== 1 && context.nodeType !== 9) { 18 return []; 19 } 20 21 if (!selector || typeof selector !== "string") { 22 return results; 23 } 24 25 var parts = [], sortOrder, m, set, checkSet, extra, 26 prune = true, 27 contextXML = isXML(context); 28 29 // Reset the position of the chunker regexp (start from head) 30 chunker.lastIndex = 0; 31 32 while ((m = chunker.exec(selector)) !== null) { 33 parts.push(m[1]); 34 35 if (m[2]) { 36 extra = RegExp.rightContext; 37 break; 38 } 39 } 40 41 if (parts.length > 1 && origPOS.exec(selector)) { 42 if (parts.length === 2 && Expr.relative[parts[0]]) { 43 set = posProcess(parts[0] + parts[1], context); 44 } else { 45 set = Expr.relative[parts[0]] 46 ? [context] 47 : Sizzle(parts.shift(), context); 48 49 while (parts.length) { 50 selector = parts.shift(); 51 52 if (Expr.relative[selector]) selector += parts.shift(); 53 54 set = posProcess(selector, set); 55 } 56 } 57 } else { 58 // Take a shortcut and set the context if the root selector is an ID 59 // (but not if it'll be faster if the inner selector is an ID) 60 if (!seed && parts.length > 1 && context.nodeType === 9 && 61 !contextXML && Expr.match.ID.test(parts[0]) && 62 !Expr.match.ID.test(parts[parts.length - 1])) { 63 var ret = Sizzle.find(parts.shift(), context, contextXML); 64 context = ret.expr 65 ? Sizzle.filter(ret.expr, ret.set)[0] 66 : ret.set[0]; 67 } 68 69 if (context) { 70 var ret = seed 71 ? { 72 expr : parts.pop(), 73 set : makeArray(seed) 74 } 75 : Sizzle.find(parts.pop(), parts.length === 1 && 76 (parts[0] === "~" || parts[0] === "+") && 77 context.parentNode 78 ? context.parentNode 79 : context, contextXML); 80 set = ret.expr 81 ? Sizzle.filter(ret.expr, ret.set) 82 : ret.set; 83 84 if (parts.length > 0) { 85 checkSet = makeArray(set); 86 } else { 87 prune = false; 88 } 89 90 while (parts.length) { 91 var cur = parts.pop(), 92 pop = cur; 93 94 if (!Expr.relative[cur]) { 95 cur = ""; 96 } else { 97 pop = parts.pop(); 98 } 99 100 if (pop == null) { 101 pop = context; 102 } 103 104 Expr.relative[cur](checkSet, pop, contextXML); 105 } 106 } else { 107 checkSet = parts = []; 108 } 109 } 110 111 if (!checkSet) { 112 checkSet = set; 113 } 114 115 if (!checkSet) { 116 throw "Syntax error, unrecognized expression: " + (cur || selector); 117 } 118 119 if (toString.call(checkSet) === "[object Array]") { 120 if (!prune) { 121 results.push.apply(results, checkSet); 122 } else if (context && context.nodeType === 1) { 123 for (var i = 0; checkSet[i] != null; i++) { 124 if (checkSet[i] && 125 (checkSet[i] === true || checkSet[i].nodeType === 1 && 126 contains(context, checkSet[i]))) { 127 results.push(set[i]); 128 } 129 } 130 } else { 131 for (var i = 0; checkSet[i] != null; i++) { 132 if (checkSet[i] && checkSet[i].nodeType === 1) { 133 results.push(set[i]); 134 } 135 } 136 } 137 } else { 138 makeArray(checkSet, results); 139 } 140 141 if (extra) { 142 Sizzle(extra, origContext, results, seed); 143 Sizzle.uniqueSort(results); 144 } 145 146 return results; 147 }; 148 149 Sizzle.uniqueSort = function(results) { 150 if (sortOrder) { 151 hasDuplicate = false; 152 results.sort(sortOrder); 153 154 if (hasDuplicate) { 155 for (var i = 1; i < results.length; i++) { 156 if (results[i] === results[i - 1]) { 157 results.splice(i--, 1); 158 } 159 } 160 } 161 } 162 }; 163 164 Sizzle.matches = function(expr, set) { 165 return Sizzle(expr, null, null, set); 166 }; 167 168 Sizzle.find = function(expr, context, isXML) { 169 var set, match; 170 171 if (!expr) { 172 return []; 173 } 174 175 for (var i = 0, l = Expr.order.length; i < l; i++) { 176 var type = Expr.order[i], match; 177 178 if ((match = Expr.match[type].exec(expr))) { 179 var left = RegExp.leftContext; 180 181 if (left.substr(left.length - 1) !== "\\") { 182 match[1] = (match[1] || "").replace(/\\/g, ""); 183 set = Expr.find[type](match, context, isXML); 184 if (set != null) { 185 expr = expr.replace(Expr.match[type], ""); 186 break; 187 } 188 } 189 } 190 } 191 192 if (!set) { 193 set = context.getElementsByTagName("*"); 194 } 195 196 return { 197 set : set, 198 expr : expr 199 }; 200 }; 201 202 Sizzle.filter = function(expr, set, inplace, not) { 203 var old = expr, 204 result = [], 205 curLoop = set, match, anyFound, 206 isXMLFilter = set && set[0] && isXML(set[0]); 207 208 while (expr && set.length) { 209 for (var type in Expr.filter) { 210 if ((match = Expr.match[type].exec(expr)) != null) { 211 var filter = Expr.filter[type], found, item; 212 anyFound = false; 213 214 if (curLoop == result) { 215 result = []; 216 } 217 218 if (Expr.preFilter[type]) { 219 match = Expr.preFilter[type](match, curLoop, inplace, result, not, isXMLFilter); 220 221 if (!match) { 222 anyFound = found = true; 223 } else if (match === true) { 224 continue; 225 } 226 } 227 228 if (match) { 229 for (var i = 0; (item = curLoop[i]) != null; i++) { 230 if (item) { 231 found = filter(item, match, i, curLoop); 232 var pass = not ^ !!found; 233 234 if (inplace && found != null) { 235 if (pass) { 236 anyFound = true; 237 } else { 238 curLoop[i] = false; 239 } 240 } else if (pass) { 241 result.push(item); 242 anyFound = true; 243 } 244 } 245 } 246 } 247 248 if (found !== undefined) { 249 if (!inplace) { 250 curLoop = result; 251 } 252 253 expr = expr.replace(Expr.match[type], ""); 254 255 if (!anyFound) { 256 return []; 257 } 258 259 break; 260 } 261 } 262 } 263 264 // Improper expression 265 if (expr == old) { 266 if (anyFound == null) { 267 throw "Syntax error, unrecognized expression: " + expr; 268 } else { 269 break; 270 } 271 } 272 273 old = expr; 274 } 275 276 return curLoop; 277 }; 278 279 var Expr = Sizzle.selectors = { 280 order : ["ID", "NAME", "TAG"], 281 match : { 282 ID : /#((?:[\w\u00c0-\uFFFF_-]|\\.)+)/, 283 CLASS : /\.((?:[\w\u00c0-\uFFFF_-]|\\.)+)/, 284 NAME : /\[name=['"]*((?:[\w\u00c0-\uFFFF_-]|\\.)+)['"]*\]/, 285 ATTR : /\[\s*((?:[\w\u00c0-\uFFFF_-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/, 286 TAG : /^((?:[\w\u00c0-\uFFFF\*_-]|\\.)+)/, 287 CHILD : /:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/, 288 POS : /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/, 289 PSEUDO : /:((?:[\w\u00c0-\uFFFF_-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/ 290 }, 291 attrMap : { 292 "class" : "className", 293 "for" : "htmlFor" 294 }, 295 attrHandle : { 296 href : function(elem) { 297 return elem.getAttribute("href"); 298 } 299 }, 300 relative : { 301 "+" : function(checkSet, part, isXML) { 302 var isPartStr = typeof part === "string", 303 isTag = isPartStr && !/\W/.test(part), 304 isPartStrNotTag = isPartStr && !isTag; 305 306 if (isTag && !isXML) { 307 part = part.toUpperCase(); 308 } 309 310 for (var i = 0, l = checkSet.length, elem; i < l; i++) { 311 if ((elem = checkSet[i])) { 312 while ((elem = elem.previousSibling) && 313 elem.nodeType !== 1) {} 314 315 checkSet[i] = isPartStrNotTag || elem && 316 elem.nodeName === part 317 ? elem || false 318 : elem === part; 319 } 320 } 321 322 if (isPartStrNotTag) { 323 Sizzle.filter(part, checkSet, true); 324 } 325 }, 326 ">" : function(checkSet, part, isXML) { 327 var isPartStr = typeof part === "string"; 328 329 if (isPartStr && !/\W/.test(part)) { 330 part = isXML 331 ? part 332 : part.toUpperCase(); 333 334 for (var i = 0, l = checkSet.length; i < l; i++) { 335 var elem = checkSet[i]; 336 if (elem) { 337 var parent = elem.parentNode; 338 checkSet[i] = parent.nodeName === part 339 ? parent 340 : false; 341 } 342 } 343 } else { 344 for (var i = 0, l = checkSet.length; i < l; i++) { 345 var elem = checkSet[i]; 346 if (elem) { 347 checkSet[i] = isPartStr 348 ? elem.parentNode 349 : elem.parentNode === part; 350 } 351 } 352 353 if (isPartStr) { 354 Sizzle.filter(part, checkSet, true); 355 } 356 } 357 }, 358 "" : function(checkSet, part, isXML) { 359 var doneName = done++, 360 checkFn = dirCheck; 361 362 if (!part.match(/\W/)) { 363 var nodeCheck = part = isXML 364 ? part 365 : part.toUpperCase(); 366 checkFn = dirNodeCheck; 367 } 368 369 checkFn("parentNode", part, doneName, checkSet, nodeCheck, isXML); 370 }, 371 "~" : function(checkSet, part, isXML) { 372 var doneName = done++, 373 checkFn = dirCheck; 374 375 if (typeof part === "string" && !part.match(/\W/)) { 376 var nodeCheck = part = isXML 377 ? part 378 : part.toUpperCase(); 379 checkFn = dirNodeCheck; 380 } 381 382 checkFn("previousSibling", part, doneName, checkSet, nodeCheck, isXML); 383 } 384 }, 385 find : { 386 ID : function(match, context, isXML) { 387 if (typeof context.getElementById !== "undefined" && !isXML) { 388 var m = context.getElementById(match[1]); 389 return m 390 ? [m] 391 : []; 392 } 393 }, 394 NAME : function(match, context, isXML) { 395 if (typeof context.getElementsByName !== "undefined") { 396 var ret = [], 397 results = context.getElementsByName(match[1]); 398 399 for (var i = 0, l = results.length; i < l; i++) { 400 if (results[i].getAttribute("name") === match[1]) { 401 ret.push(results[i]); 402 } 403 } 404 405 return ret.length === 0 406 ? null 407 : ret; 408 } 409 }, 410 TAG : function(match, context) { 411 return context.getElementsByTagName(match[1]); 412 } 413 }, 414 preFilter : { 415 CLASS : function(match, curLoop, inplace, result, not, isXML) { 416 match = " " + match[1].replace(/\\/g, "") + " "; 417 418 if (isXML) { 419 return match; 420 } 421 422 for (var i = 0, elem; (elem = curLoop[i]) != null; i++) { 423 if (elem) { 424 if (not ^ 425 (elem.className && (" " + elem.className + " ").indexOf(match) >= 0)) { 426 if (!inplace) result.push(elem); 427 } else if (inplace) { 428 curLoop[i] = false; 429 } 430 } 431 } 432 433 return false; 434 }, 435 ID : function(match) { 436 return match[1].replace(/\\/g, ""); 437 }, 438 TAG : function(match, curLoop) { 439 for (var i = 0; curLoop[i] === false; i++) {} 440 return curLoop[i] && isXML(curLoop[i]) 441 ? match[1] 442 : match[1].toUpperCase(); 443 }, 444 CHILD : function(match) { 445 if (match[1] == "nth") { 446 // parse equations like 'even', 'odd', '5', '2n', '3n+2', 447 // '4n-1', '-n+6' 448 var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec(match[2] == "even" && 449 "2n" || 450 match[2] == "odd" && 451 "2n+1" || 452 !/\D/.test(match[2]) && "0n+" + match[2] || match[2]); 453 454 // calculate the numbers (first)n+(last) including if they 455 // are negative 456 match[2] = (test[1] + (test[2] || 1)) - 0; 457 match[3] = test[3] - 0; 458 } 459 460 // TODO: Move to normal caching system 461 match[0] = done++; 462 463 return match; 464 }, 465 ATTR : function(match, curLoop, inplace, result, not, isXML) { 466 var name = match[1].replace(/\\/g, ""); 467 468 if (!isXML && Expr.attrMap[name]) { 469 match[1] = Expr.attrMap[name]; 470 } 471 472 if (match[2] === "~=") { 473 match[4] = " " + match[4] + " "; 474 } 475 476 return match; 477 }, 478 PSEUDO : function(match, curLoop, inplace, result, not) { 479 if (match[1] === "not") { 480 // If we're dealing with a complex expression, or a simple 481 // one 482 if (match[3].match(chunker).length > 1 || 483 /^\w/.test(match[3])) { 484 match[3] = Sizzle(match[3], null, null, curLoop); 485 } else { 486 var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not); 487 if (!inplace) { 488 result.push.apply(result, ret); 489 } 490 return false; 491 } 492 } else if (Expr.match.POS.test(match[0]) || 493 Expr.match.CHILD.test(match[0])) { 494 return true; 495 } 496 497 return match; 498 }, 499 POS : function(match) { 500 match.unshift(true); 501 return match; 502 } 503 }, 504 filters : { 505 enabled : function(elem) { 506 return elem.disabled === false && elem.type !== "hidden"; 507 }, 508 disabled : function(elem) { 509 return elem.disabled === true; 510 }, 511 checked : function(elem) { 512 return elem.checked === true; 513 }, 514 selected : function(elem) { 515 // Accessing this property makes selected-by-default 516 // options in Safari work properly 517 elem.parentNode.selectedIndex; 518 return elem.selected === true; 519 }, 520 parent : function(elem) { 521 return !!elem.firstChild; 522 }, 523 empty : function(elem) { 524 return !elem.firstChild; 525 }, 526 has : function(elem, i, match) { 527 return !!Sizzle(match[3], elem).length; 528 }, 529 header : function(elem) { 530 return /h\d/i.test(elem.nodeName); 531 }, 532 text : function(elem) { 533 return "text" === elem.type; 534 }, 535 radio : function(elem) { 536 return "radio" === elem.type; 537 }, 538 checkbox : function(elem) { 539 return "checkbox" === elem.type; 540 }, 541 file : function(elem) { 542 return "file" === elem.type; 543 }, 544 password : function(elem) { 545 return "password" === elem.type; 546 }, 547 submit : function(elem) { 548 return "submit" === elem.type; 549 }, 550 image : function(elem) { 551 return "image" === elem.type; 552 }, 553 reset : function(elem) { 554 return "reset" === elem.type; 555 }, 556 button : function(elem) { 557 return "button" === elem.type || 558 elem.nodeName.toUpperCase() === "BUTTON"; 559 }, 560 input : function(elem) { 561 return /input|select|textarea|button/i.test(elem.nodeName); 562 } 563 }, 564 setFilters : { 565 first : function(elem, i) { 566 return i === 0; 567 }, 568 last : function(elem, i, match, array) { 569 return i === array.length - 1; 570 }, 571 even : function(elem, i) { 572 return i % 2 === 0; 573 }, 574 odd : function(elem, i) { 575 return i % 2 === 1; 576 }, 577 lt : function(elem, i, match) { 578 return i < match[3] - 0; 579 }, 580 gt : function(elem, i, match) { 581 return i > match[3] - 0; 582 }, 583 nth : function(elem, i, match) { 584 return match[3] - 0 == i; 585 }, 586 eq : function(elem, i, match) { 587 return match[3] - 0 == i; 588 } 589 }, 590 filter : { 591 PSEUDO : function(elem, match, i, array) { 592 var name = match[1], 593 filter = Expr.filters[name]; 594 595 if (filter) { 596 return filter(elem, i, match, array); 597 } else if (name === "contains") { 598 return (elem.textContent || elem.innerText || "").indexOf(match[3]) >= 0; 599 } else if (name === "not") { 600 var not = match[3]; 601 602 for (i = 0, l = not.length; i < l; i++) { 603 if (not[i] === elem) { 604 return false; 605 } 606 } 607 608 return true; 609 } 610 }, 611 CHILD : function(elem, match) { 612 var type = match[1], 613 node = elem; 614 switch (type) { 615 case 'only' : 616 case 'first' : 617 while ((node = node.previousSibling)) { 618 if (node.nodeType === 1) return false; 619 } 620 if (type == 'first') return true; 621 node = elem; 622 case 'last' : 623 while ((node = node.nextSibling)) { 624 if (node.nodeType === 1) return false; 625 } 626 return true; 627 case 'nth' : 628 var first = match[2], 629 last = match[3]; 630 631 if (first == 1 && last == 0) { 632 return true; 633 } 634 635 var doneName = match[0], 636 parent = elem.parentNode; 637 638 if (parent && 639 (parent.sizcache !== doneName || !elem.nodeIndex)) { 640 var count = 0; 641 for (node = parent.firstChild; node; node = node.nextSibling) { 642 if (node.nodeType === 1) { 643 node.nodeIndex = ++count; 644 } 645 } 646 parent.sizcache = doneName; 647 } 648 649 var diff = elem.nodeIndex - last; 650 if (first == 0) { 651 return diff == 0; 652 } else { 653 return (diff % first == 0 && diff / first >= 0); 654 } 655 } 656 }, 657 ID : function(elem, match) { 658 return elem.nodeType === 1 && elem.getAttribute("id") === match; 659 }, 660 TAG : function(elem, match) { 661 return (match === "*" && elem.nodeType === 1) || 662 elem.nodeName === match; 663 }, 664 CLASS : function(elem, match) { 665 return (" " + (elem.className || elem.getAttribute("class")) + " ").indexOf(match) > -1; 666 }, 667 ATTR : function(elem, match) { 668 var name = match[1], 669 result = Expr.attrHandle[name] 670 ? Expr.attrHandle[name](elem) 671 : elem[name] != null 672 ? elem[name] 673 : elem.getAttribute(name), 674 value = result + "", 675 type = match[2], 676 check = match[4]; 677 678 return result == null 679 ? type === "!=" 680 : type === "=" 681 ? value === check 682 : type === "*=" 683 ? value.indexOf(check) >= 0 684 : type === "~=" 685 ? (" " + value + " ").indexOf(check) >= 0 686 : !check 687 ? value && result !== false 688 : type === "!=" 689 ? value != check 690 : type === "^=" 691 ? value.indexOf(check) === 0 692 : type === "$=" 693 ? value.substr(value.length - 694 check.length) === check 695 : type === "|=" 696 ? value === check || 697 value.substr(0, check.length + 698 1) === check + "-" 699 : false; 700 }, 701 POS : function(elem, match, i, array) { 702 var name = match[2], 703 filter = Expr.setFilters[name]; 704 705 if (filter) { 706 return filter(elem, i, match, array); 707 } 708 } 709 } 710 }; 711 712 var origPOS = Expr.match.POS; 713 714 for (var type in Expr.match) { 715 Expr.match[type] = new RegExp(Expr.match[type].source + 716 /(?![^\[]*\])(?![^\(]*\))/.source); 717 } 718 719 var makeArray = function(array, results) { 720 array = Array.prototype.slice.call(array); 721 722 if (results) { 723 results.push.apply(results, array); 724 return results; 725 } 726 727 return array; 728 }; 729 730 // Perform a simple check to determine if the browser is capable of 731 // converting a NodeList to an array using builtin methods. 732 try { 733 Array.prototype.slice.call(document.documentElement.childNodes); 734 735 // Provide a fallback method if it does not work 736 } catch (e) { 737 makeArray = function(array, results) { 738 var ret = results || []; 739 740 if (toString.call(array) === "[object Array]") { 741 Array.prototype.push.apply(ret, array); 742 } else { 743 if (typeof array.length === "number") { 744 for (var i = 0, l = array.length; i < l; i++) { 745 ret.push(array[i]); 746 } 747 } else { 748 for (var i = 0; array[i]; i++) { 749 ret.push(array[i]); 750 } 751 } 752 } 753 754 return ret; 755 }; 756 } 757 758 if (document.documentElement.compareDocumentPosition) { 759 /** @ignore */ 760 sortOrder = function(a, b) { 761 var ret = a.compareDocumentPosition(b) & 4 762 ? -1 763 : a === b 764 ? 0 765 : 1; 766 if (ret === 0) { 767 hasDuplicate = true; 768 } 769 return ret; 770 }; 771 } else if ("sourceIndex" in document.documentElement) { 772 /** @ignore */ 773 sortOrder = function(a, b) { 774 var ret = a.sourceIndex - b.sourceIndex; 775 if (ret === 0) { 776 hasDuplicate = true; 777 } 778 return ret; 779 }; 780 } else if (document.createRange) { 781 /** @ignore */ 782 sortOrder = function(a, b) { 783 var aRange = a.ownerDocument.createRange(), 784 bRange = b.ownerDocument.createRange(); 785 aRange.selectNode(a); 786 aRange.collapse(true); 787 bRange.selectNode(b); 788 bRange.collapse(true); 789 var ret = aRange.compareBoundaryPoints(Range.START_TO_END, bRange); 790 if (ret === 0) { 791 hasDuplicate = true; 792 } 793 return ret; 794 }; 795 } 796 797 // Check to see if the browser returns elements by name when 798 // querying by getElementById (and provide a workaround) 799 (function() { 800 // We're going to inject a fake input element with a specified name 801 var form = document.createElement("div"), 802 id = "script" + (new Date).getTime(); 803 form.innerHTML = "<a name='" + id + "'/>"; 804 805 // Inject it into the root element, check its status, and remove it 806 // quickly 807 var root = document.documentElement; 808 root.insertBefore(form, root.firstChild); 809 810 // The workaround has to do additional checks after a getElementById 811 // Which slows things down for other browsers (hence the branching) 812 if (!!document.getElementById(id)) { 813 Expr.find.ID = function(match, context, isXML) { 814 if (typeof context.getElementById !== "undefined" && !isXML) { 815 var m = context.getElementById(match[1]); 816 return m 817 ? m.id === match[1] || 818 typeof m.getAttributeNode !== "undefined" && 819 m.getAttributeNode("id").nodeValue === match[1] 820 ? [m] 821 : undefined 822 : []; 823 } 824 }; 825 826 Expr.filter.ID = function(elem, match) { 827 var node = typeof elem.getAttributeNode !== "undefined" && 828 elem.getAttributeNode("id"); 829 return elem.nodeType === 1 && node && node.nodeValue === match; 830 }; 831 } 832 833 root.removeChild(form); 834 root = form = null; // release memory in IE 835 })(); 836 837 (function() { 838 // Check to see if the browser returns only elements 839 // when doing getElementsByTagName("*") 840 841 // Create a fake element 842 var div = document.createElement("div"); 843 div.appendChild(document.createComment("")); 844 845 // Make sure no comments are found 846 if (div.getElementsByTagName("*").length > 0) { 847 Expr.find.TAG = function(match, context) { 848 var results = context.getElementsByTagName(match[1]); 849 850 // Filter out possible comments 851 if (match[1] === "*") { 852 var tmp = []; 853 854 for (var i = 0; results[i]; i++) { 855 if (results[i].nodeType === 1) { 856 tmp.push(results[i]); 857 } 858 } 859 860 results = tmp; 861 } 862 863 return results; 864 }; 865 } 866 867 // Check to see if an attribute returns normalized href attributes 868 div.innerHTML = "<a href='#'></a>"; 869 if (div.firstChild && 870 typeof div.firstChild.getAttribute !== "undefined" && 871 div.firstChild.getAttribute("href") !== "#") { 872 Expr.attrHandle.href = function(elem) { 873 return elem.getAttribute("href", 2); 874 }; 875 } 876 877 div = null; // release memory in IE 878 })(); 879 880 if (document.querySelectorAll) (function() { 881 var oldSizzle = Sizzle, 882 div = document.createElement("div"); 883 div.innerHTML = "<p class='TEST'></p>"; 884 885 // Safari can't handle uppercase or unicode characters when 886 // in quirks mode. 887 if (div.querySelectorAll && div.querySelectorAll(".TEST").length === 0) { 888 return; 889 } 890 891 Sizzle = function(query, context, extra, seed) { 892 context = context || document; 893 894 // Only use querySelectorAll on non-XML documents 895 // (ID selectors don't work in non-HTML documents) 896 if (!seed && context.nodeType === 9 && !isXML(context)) { 897 try { 898 return makeArray(context.querySelectorAll(query), extra); 899 } catch (e) {} 900 } 901 902 return oldSizzle(query, context, extra, seed); 903 }; 904 905 for (var prop in oldSizzle) { 906 Sizzle[prop] = oldSizzle[prop]; 907 } 908 909 div = null; // release memory in IE 910 })(); 911 912 if (document.getElementsByClassName && 913 document.documentElement.getElementsByClassName) (function() { 914 var div = document.createElement("div"); 915 div.innerHTML = "<div class='test e'></div><div class='test'></div>"; 916 917 // Opera can't find a second classname (in 9.6) 918 if (div.getElementsByClassName("e").length === 0) return; 919 920 // Safari caches class attributes, doesn't catch changes (in 3.2) 921 div.lastChild.className = "e"; 922 923 if (div.getElementsByClassName("e").length === 1) return; 924 925 Expr.order.splice(1, 0, "CLASS"); 926 Expr.find.CLASS = function(match, context, isXML) { 927 if (typeof context.getElementsByClassName !== "undefined" && !isXML) { 928 return context.getElementsByClassName(match[1]); 929 } 930 }; 931 932 div = null; // release memory in IE 933 })(); 934 935 function dirNodeCheck(dir, cur, doneName, checkSet, nodeCheck, isXML) { 936 var sibDir = dir == "previousSibling" && !isXML; 937 for (var i = 0, l = checkSet.length; i < l; i++) { 938 var elem = checkSet[i]; 939 if (elem) { 940 if (sibDir && elem.nodeType === 1) { 941 elem.sizcache = doneName; 942 elem.sizset = i; 943 } 944 elem = elem[dir]; 945 var match = false; 946 947 while (elem) { 948 if (elem.sizcache === doneName) { 949 match = checkSet[elem.sizset]; 950 break; 951 } 952 953 if (elem.nodeType === 1 && !isXML) { 954 elem.sizcache = doneName; 955 elem.sizset = i; 956 } 957 958 if (elem.nodeName === cur) { 959 match = elem; 960 break; 961 } 962 963 elem = elem[dir]; 964 } 965 966 checkSet[i] = match; 967 } 968 } 969 } 970 971 function dirCheck(dir, cur, doneName, checkSet, nodeCheck, isXML) { 972 var sibDir = dir == "previousSibling" && !isXML; 973 for (var i = 0, l = checkSet.length; i < l; i++) { 974 var elem = checkSet[i]; 975 if (elem) { 976 if (sibDir && elem.nodeType === 1) { 977 elem.sizcache = doneName; 978 elem.sizset = i; 979 } 980 elem = elem[dir]; 981 var match = false; 982 983 while (elem) { 984 if (elem.sizcache === doneName) { 985 match = checkSet[elem.sizset]; 986 break; 987 } 988 989 if (elem.nodeType === 1) { 990 if (!isXML) { 991 elem.sizcache = doneName; 992 elem.sizset = i; 993 } 994 if (typeof cur !== "string") { 995 if (elem === cur) { 996 match = true; 997 break; 998 } 999 1000 } else if (Sizzle.filter(cur, [elem]).length > 0) { 1001 match = elem; 1002 break; 1003 } 1004 } 1005 1006 elem = elem[dir]; 1007 } 1008 1009 checkSet[i] = match; 1010 } 1011 } 1012 } 1013 1014 var contains = document.compareDocumentPosition 1015 ? function(a, b) { 1016 return a.compareDocumentPosition(b) & 16; 1017 } 1018 : function(a, b) { 1019 return a !== b && (a.contains 1020 ? a.contains(b) 1021 : true); 1022 }; 1023 1024 var isXML = function(elem) { 1025 return elem.nodeType === 9 && 1026 elem.documentElement.nodeName !== "HTML" || !!elem.ownerDocument && 1027 elem.ownerDocument.documentElement.nodeName !== "HTML"; 1028 }; 1029 1030 var posProcess = function(selector, context) { 1031 var tmpSet = [], 1032 later = "", match, 1033 root = context.nodeType 1034 ? [context] 1035 : context; 1036 1037 // Position selectors must be done after the filter 1038 // And so must :not(positional) so we move all PSEUDOs to the end 1039 while ((match = Expr.match.PSEUDO.exec(selector))) { 1040 later += match[0]; 1041 selector = selector.replace(Expr.match.PSEUDO, ""); 1042 } 1043 1044 selector = Expr.relative[selector] 1045 ? selector + "*" 1046 : selector; 1047 1048 for (var i = 0, l = root.length; i < l; i++) { 1049 Sizzle(selector, root[i], tmpSet); 1050 } 1051 1052 return Sizzle.filter(later, tmpSet); 1053 }; 1054 1055 // EXPOSE 1056 window.Sizzle = Sizzle; 1057 1058 })(); 1059 1060 /** 1061 * @namespace Provides methods to collect and filter DOM elements. 1062 */ 1063 Jelo.Dom = function() { 1064 1065 /** @scope Jelo.Dom */ 1066 return { 1067 /** 1068 * Converts a string of HTML to actual DOM elements. 1069 * 1070 * @param {String} html The HTML to convert to DOM nodes. 1071 * @returns {Node} A DocumentFragment object containing the specified 1072 * nodes. 1073 */ 1074 fromString : function(str) { 1075 var frag = document.createDocumentFragment(); 1076 if (typeof str != 'string') { 1077 return frag; 1078 } 1079 var div = document.createElement('div'); 1080 div.innerHTML = str; 1081 while (div.firstChild) { 1082 frag.appendChild(div.firstChild); 1083 } 1084 return frag; 1085 }, 1086 /** 1087 * Reduces a set of DOM nodes to those that also match the given CSS 1088 * selector. The selector can be a full selector (for example, "div > 1089 * span.foo") and not just a fragment or simple selector. 1090 * 1091 * @param {String} selector The CSS selector or xpath query. 1092 * @param {Array} [set] The set of elements to filter. 1093 */ 1094 filter : function(selector, set) { 1095 return Sizzle.matches(selector, set); 1096 }, 1097 /** 1098 * Selects a group of elements that match a given CSS selector. 1099 * 1100 * @param {String} selector The CSS selector or xpath query. 1101 * @param {Node} [context=document] The root node within which to 1102 * conduct this search. 1103 * @param {Array} [results] The collection returned from this function. 1104 * @returns {Array} 1105 */ 1106 select : function(selector, context, results) { 1107 return (selector && selector.isArray) 1108 ? selector 1109 : Sizzle(selector, context, results); 1110 }, 1111 /** 1112 * Selects the FIRST instance of a matching element. 1113 * 1114 * @param {String} selector The CSS selector or xpath query. 1115 * @param {Node} [context=document] The root node within which to 1116 * conduct this search. 1117 * @param {Array} [results] The collection returned from this function. 1118 * @returns {Node} 1119 */ 1120 selectNode : function(selector, context, results) { 1121 return (selector && selector.nodeType) 1122 ? selector 1123 : Sizzle(selector, context, results)[0]; 1124 }, 1125 /** 1126 * Finds the position of an element on the page. 1127 * 1128 * @param {HTMLElement} The element to inspect 1129 * @returns {Array} [left, top] calculated in pixels, output as Numbers. 1130 */ 1131 findPosition : function(el) { 1132 var l = 0; 1133 var t = 0; 1134 if (el.offsetParent) { 1135 do { 1136 l += el.offsetLeft; 1137 t += el.offsetTop; 1138 } while (el = el.offsetParent); 1139 } 1140 return [l, t]; 1141 } 1142 }; 1143 }(); 1144 1145 $ = window['$'] || Jelo.Dom.selectNode; 1146 $$ = window['$$'] || Jelo.Dom.select; 1147