1// SpryDOMUtils.js - version 0.13 - Spry Pre-Release 1.7 2// 3// Copyright (c) 2007. Adobe Systems Incorporated. 4// All rights reserved. 5// 6// Redistribution and use in source and binary forms, with or without 7// modification, are permitted provided that the following conditions are met: 8// 9// * Redistributions of source code must retain the above copyright notice, 10// this list of conditions and the following disclaimer. 11// * Redistributions in binary form must reproduce the above copyright notice, 12// this list of conditions and the following disclaimer in the documentation 13// and/or other materials provided with the distribution. 14// * Neither the name of Adobe Systems Incorporated nor the names of its 15// contributors may be used to endorse or promote products derived from this 16// software without specific prior written permission. 17// 18// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28// POSSIBILITY OF SUCH DAMAGE. 29 30(function() { // BeginSpryComponent 31 32if (typeof Spry == "undefined") window.Spry = {}; if (!Spry.Utils) Spry.Utils = {}; 33 34////////////////////////////////////////////////////////////////////// 35// 36// Define Prototype's $() convenience function, but make sure it is 37// namespaced under Spry so that we avoid collisions with other 38// toolkits. 39// 40////////////////////////////////////////////////////////////////////// 41 42Spry.$ = function(element) 43{ 44 if (arguments.length > 1) 45 { 46 for (var i = 0, elements = [], length = arguments.length; i < length; i++) 47 elements.push(Spry.$(arguments[i])); 48 return elements; 49 } 50 if (typeof element == 'string') 51 element = document.getElementById(element); 52 return element; 53}; 54 55////////////////////////////////////////////////////////////////////// 56// 57// DOM Utils 58// 59////////////////////////////////////////////////////////////////////// 60 61Spry.Utils.getAttribute = function(ele, name) 62{ 63 ele = Spry.$(ele); 64 if (!ele || !name) 65 return null; 66 67 // We need to wrap getAttribute with a try/catch because IE will throw 68 // an exception if you call it with a namespace prefixed attribute name 69 // that doesn't exist. 70 71 try { var value = ele.getAttribute(name); } 72 catch (e) { value == undefined; } 73 74 // XXX: Workaround for Safari 2.x and earlier: 75 // 76 // If value is undefined, the attribute didn't exist. Check to see if this is 77 // a namespace prefixed attribute name. If it is, remove the ':' from the name 78 // and try again. This allows us to support spry attributes of the form 79 // "spry:region" and "spryregion". 80 81 if (value == undefined && name.search(/:/) != -1) 82 { 83 try { var value = ele.getAttribute(name.replace(/:/, "")); } 84 catch (e) { value == undefined; } 85 } 86 87 return value; 88}; 89 90Spry.Utils.setAttribute = function(ele, name, value) 91{ 92 ele = Spry.$(ele); 93 if (!ele || !name) 94 return; 95 96 // IE doesn't allow you to set the "class" attribute. You 97 // have to set the className property instead. 98 99 if (name == "class") 100 ele.className = value; 101 else 102 { 103 // I'm probably being a bit paranoid, but given the fact that 104 // getAttribute() throws exceptions when dealing with namespace 105 // prefixed attributes, I'm going to wrap this setAttribute() 106 // call with try/catch just in case ... 107 108 try { ele.setAttribute(name, value); } catch(e) {} 109 110 // XXX: Workaround for Safari 2.x and earlier: 111 // 112 // If this is a namespace prefixed attribute, check to make 113 // sure an attribute was created. This is necessary because some 114 // older versions of Safari (2.x and earlier) drop the namespace 115 // prefixes. If the attribute was munged, try removing the ':' 116 // character from the attribute name and setting the attribute 117 // using the resulting name. The idea here is that even if we 118 // remove the ':' character, Spry.Utils.getAttribute() will still 119 // find the attribute. 120 121 if (name.search(/:/) != -1 && ele.getAttribute(name) == undefined) 122 ele.setAttribute(name.replace(/:/, ""), value); 123 } 124}; 125 126Spry.Utils.removeAttribute = function(ele, name) 127{ 128 ele = Spry.$(ele); 129 if (!ele || !name) 130 return; 131 132 try { ele.removeAttribute(name); } catch(e) {} 133 134 // XXX: Workaround for Safari 2.x and earlier: 135 // 136 // If this is a namespace prefixed attribute, make sure we 137 // also remove any attributes with the same name, but without 138 // the ':' character. 139 140 if (name.search(/:/) != -1) 141 ele.removeAttribute(name.replace(/:/, "")); 142 143 // XXX: Workaround for IE 144 // 145 // IE doesn't allow you to remove the "class" attribute. 146 // It requires you to remove "className" instead, so go 147 // ahead and try to remove that too. 148 149 if (name == "class") 150 ele.removeAttribute("className"); 151};
152 153Spry.Utils.addClassName = function(ele, className) 154{ 155 ele = Spry.$(ele); 156 if (!ele || !className || (ele.className && ele.className.search(new RegExp("\\b" + className + "\\b")) != -1)) 157 return; 158 ele.className += (ele.className ? " " : "") + className; 159}; 160 161Spry.Utils.removeClassName = function(ele, className) 162{ 163 ele = Spry.$(ele); 164 if (Spry.Utils.hasClassName(ele, className)) 165 ele.className = ele.className.replace(new RegExp("\\s*\\b" + className + "\\b", "g"), ""); 166}; 167 168Spry.Utils.toggleClassName = function(ele, className) 169{ 170 if (Spry.Utils.hasClassName(ele, className)) 171 Spry.Utils.removeClassName(ele, className); 172 else 173 Spry.Utils.addClassName(ele, className); 174}; 175 176Spry.Utils.hasClassName = function(ele, className) 177{ 178 ele = Spry.$(ele); 179 if (!ele || !className || !ele.className || ele.className.search(new RegExp("\\b" + className + "\\b")) == -1) 180 return false; 181 return true; 182}; 183 184Spry.Utils.camelizeString = function(str) 185{ 186 var cStr = ""; 187 var a = str.split("-"); 188 for (var i = 0; i < a.length; i++) 189 { 190 var s = a[i]; 191 if (s) 192 cStr = cStr ? (cStr + s.charAt(0).toUpperCase() + s.substring(1)) : s; 193 } 194 return cStr; 195}; 196 197Spry.Utils.styleStringToObject = function(styleStr) 198{ 199 var o = {}; 200 if (styleStr) 201 { 202 var pvA = styleStr.split(";"); 203 for (var i = 0; i < pvA.length; i++) 204 { 205 var pv = pvA[i]; 206 if (pv && pv.indexOf(":") != -1) 207 { 208 var nvA = pv.split(":"); 209 var n = nvA[0].replace(/^\s*|\s*$/g, ""); 210 var v = nvA[1].replace(/^\s*|\s*$/g, ""); 211 if (n && v) 212 o[Spry.Utils.camelizeString(n)] = v; 213 } 214 } 215 } 216 return o; 217}; 218 219Spry.Utils.addEventListener = function(element, eventType, handler, capture) 220{ 221 try 222 { 223 if (!Spry.Utils.eventListenerIsBoundToElement(element, eventType, handler, capture)) 224 { 225 element = Spry.$(element); 226 handler = Spry.Utils.bindEventListenerToElement(element, eventType, handler, capture); 227 if (element.addEventListener) 228 element.addEventListener(eventType, handler, capture); 229 else if (element.attachEvent) 230 element.attachEvent("on" + eventType, handler); 231 } 232 } 233 catch (e) {} 234}; 235 236Spry.Utils.removeEventListener = function(element, eventType, handler, capture) 237{ 238 try 239 { 240 element = Spry.$(element); 241 handler = Spry.Utils.unbindEventListenerFromElement(element, eventType, handler, capture); 242 if (element.removeEventListener) 243 element.removeEventListener(eventType, handler, capture); 244 else if (element.detachEvent) 245 element.detachEvent("on" + eventType, handler); 246 } 247 catch (e) {} 248}; 249 250Spry.Utils.eventListenerHash = {}; 251Spry.Utils.nextEventListenerID = 1; 252 253Spry.Utils.getHashForElementAndHandler = function(element, eventType, handler, capture) 254{ 255 var hash = null; 256 element = Spry.$(element); 257 if (element) 258 { 259 if (typeof element.spryEventListenerID == "undefined") 260 element.spryEventListenerID = "e" + (Spry.Utils.nextEventListenerID++); 261 if (typeof handler.spryEventHandlerID == "undefined") 262 handler.spryEventHandlerID = "h" + (Spry.Utils.nextEventListenerID++); 263 hash = element.spryEventListenerID + "-" + handler.spryEventHandlerID + "-" + eventType + (capture?"-capture":""); 264 } 265 return hash; 266}; 267 268Spry.Utils.eventListenerIsBoundToElement = function(element, eventType, handler, capture) 269{ 270 element = Spry.$(element); 271 var hash = Spry.Utils.getHashForElementAndHandler(element, eventType, handler, capture); 272 return Spry.Utils.eventListenerHash[hash] != undefined; 273}; 274 275Spry.Utils.bindEventListenerToElement = function(element, eventType, handler, capture) 276{ 277 element = Spry.$(element); 278 var hash = Spry.Utils.getHashForElementAndHandler(element, eventType, handler, capture); 279 if (Spry.Utils.eventListenerHash[hash]) 280 return Spry.Utils.eventListenerHash[hash]; 281 return Spry.Utils.eventListenerHash[hash] = function(e) 282 { 283 e = e || window.event; 284 285 if (!e.preventDefault) e.preventDefault = function() { this.returnValue = false; }; 286 if (!e.stopPropagation) e.stopPropagation = function() { this.cancelBubble = true; }; 287 288 var result = handler.call(element, e); 289 if (result == false) 290 { 291 e.preventDefault(); 292 e.stopPropagation(); 293 } 294 return result; 295 }; 296}; 297 298Spry.Utils.unbindEventListenerFromElement = function(element, eventType, handler, capture) 299{ 300 element = Spry.$(element); 301 var hash = Spry.Utils.getHashForElementAndHandler(element, eventType, handler, capture); 302 if (Spry.Utils.eventListenerHash[hash]) 303 { 304 handler = Spry.Utils.eventListenerHash[hash]; 305 Spry.Utils.eventListenerHash[hash] = undefined; 306 } 307 return handler; 308}; 309 310Spry.Utils.cancelEvent = function(e) 311{ 312 if (e.preventDefault) e.preventDefault(); 313 else e.returnValue = false; 314 if (e.stopPropagation) e.stopPropagation(); 315 else e.cancelBubble = true; 316 317 return false; 318}; 319 320 321Spry.Utils.addLoadListener = function(handler) 322{ 323 if (typeof window.addEventListener != 'undefined') 324 window.addEventListener('load', handler, false); 325 else if (typeof document.addEventListener != 'undefined') 326 document.addEventListener('load', handler, false); 327 else if (typeof window.attachEvent != 'undefined') 328 window.attachEvent('onload', handler); 329};
330 331Spry.Utils.isDescendant = function(parent, child) 332{ 333 if (parent && child) 334 { 335 child = child.parentNode; 336 while (child) 337 { 338 if (parent == child) 339 return true; 340 child = child.parentNode; 341 } 342 } 343 return false; 344}; 345 346Spry.Utils.getAncestor = function(ele, selector) 347{ 348 ele = Spry.$(ele); 349 if (ele) 350 { 351 var s = Spry.$$.tokenizeSequence(selector ? selector : "*")[0]; 352 var t = s ? s[0] : null; 353 if (t) 354 { 355 var p = ele.parentNode; 356 while (p) 357 { 358 if (t.match(p)) 359 return p; 360 p = p.parentNode; 361 } 362 } 363 } 364 return null; 365}; 366 367////////////////////////////////////////////////////////////////////// 368// 369// CSS Selector Matching 370// 371////////////////////////////////////////////////////////////////////// 372 373Spry.$$ = function(selectorSequence, rootNode) 374{ 375 var matches = []; 376 Spry.$$.addExtensions(matches); 377 378 // If the first argument to $$() is an object, it 379 // is assumed that all args are either a DOM element 380 // or an array of DOM elements, in which case we 381 // simply append all DOM elements to our special 382 // matches array and return immediately. 383 384 if (typeof arguments[0] == "object") 385 { 386 for (var i = 0; i < arguments.length; i++) 387 { 388 if (arguments[i].constructor == Array) 389 matches.push.apply(matches, arguments[i]); 390 else 391 matches.push(arguments[i]); 392 } 393 return matches; 394 } 395 396 if (!rootNode) 397 rootNode = document; 398 else 399 rootNode = Spry.$(rootNode); 400 401 var sequences = Spry.$$.tokenizeSequence(selectorSequence); 402 403 ++Spry.$$.queryID; 404 405 var nid = 0; 406 var ns = sequences.length; 407 for (var i = 0; i < ns; i++) 408 { 409 var m = Spry.$$.processTokens(sequences[i], rootNode); 410 var nm = m.length; 411 for (var j = 0; j < nm; j++) 412 { 413 var n = m[j]; 414 if (!n.spry$$ID) 415 { 416 n.spry$$ID = ++nid; 417 matches.push(n); 418 } 419 } 420 } 421 422 var nm = matches.length; 423 for (i = 0; i < nm; i++) 424 matches[i].spry$$ID = undefined; 425 426 return matches; 427}; 428 429Spry.$$.cache = {}; 430Spry.$$.queryID = 0; 431 432Spry.$$.Token = function() 433{ 434 this.type = Spry.$$.Token.SELECTOR; 435 this.name = "*"; 436 this.id = ""; 437 this.classes = []; 438 this.attrs = []; 439 440 this.pseudos = []; 441}; 442 443Spry.$$.Token.Attr = function(n, v) 444{ 445 this.name = n; 446 this.value = v ? new RegExp(v) : undefined; 447}; 448 449Spry.$$.Token.PseudoClass = function(pstr) 450{ 451 this.name = pstr.replace(/\(.*/, ""); 452 this.arg = pstr.replace(/^[^\(\)]*\(?\s*|\)\s*$/g, ""); 453 this.func = Spry.$$.pseudoFuncs[this.name]; 454}; 455 456Spry.$$.Token.SELECTOR = 0; 457Spry.$$.Token.COMBINATOR = 1; 458 459Spry.$$.Token.prototype.match = function(ele, nameAlreadyMatches) 460{ 461 if (this.type == Spry.$$.Token.COMBINATOR) 462 return false; 463 if (!nameAlreadyMatches && this.name != '*' && this.name != ele.nodeName.toLowerCase()) 464 return false; 465 if (this.id && this.id != ele.id) 466 return false; 467 var classes = this.classes; 468 var len = classes.length; 469 for (var i = 0; i < len; i++) 470 { 471 if (!ele.className || !classes[i].value.test(ele.className)) 472 return false; 473 } 474 475 var attrs = this.attrs; 476 len = attrs.length; 477 for (var i = 0; i < len; i++) 478 { 479 var a = attrs[i]; 480 var an = ele.attributes.getNamedItem(a.name); 481 if (!an || (!a.value && an.nodeValue == undefined) || (a.value && !a.value.test(an.nodeValue))) 482 return false; 483 } 484 485 var ps = this.pseudos; 486 var len = ps.length; 487 for (var i = 0; i < len; i++) 488 { 489 var p = ps[i]; 490 if (p && p.func && !p.func(p.arg, ele, this)) 491 return false; 492 } 493 494 return true; 495}; 496 497Spry.$$.Token.prototype.getNodeNameIfTypeMatches = function(ele) 498{ 499 var nodeName = ele.nodeName.toLowerCase(); 500 if (this.name != '*') 501 { 502 if (this.name != nodeName) 503 return null; 504 return this.name; 505 } 506 return nodeName; 507}; 508 509Spry.$$.escapeRegExpCharsRE = /\/|\.|\*|\+|\(|\)|\[|\]|\{|\}|\\|\|/g; 510 511Spry.$$.tokenizeSequence = function(s) 512{ 513 var cc = Spry.$$.cache[s]; 514 if (cc) return cc; 515 516 // Attribute Selector: /(\[[^\"'~\^\$\*\|\]=]+([~\^\$\*\|]?=\s*('[^']*'|"[^"]*"|[^"'\]]+))?\s*\])/g 517 // Simple Selector: /((:[^\.#:\s,>~\+\[\]]+\(([^\(\)]+|\([^\(\)]*\))*\))|[\.#:]?[^\.#:\s,>~\+\[\]]+)/g 518 // Combinator: /(\s*[\s,>~\+]\s*)/g 519 520 var tokenExpr = /(\[[^\"'~\^\$\*\|\]=]+([~\^\$\*\|]?=\s*('[^']*'|"[^"]*"|[^"'\]]+))?\s*\])|((:[^\.#:\s,>~\+\[\]]+\(([^\(\)]+|\([^\(\)]*\))*\))|[\.#:]?[^\.#:\s,>~\+\[\]]+)|(\s*[\s,>~\+]\s*)/g; 521 522 var tkn = new Spry.$$.Token; 523 var sequence = []; 524 sequence.push(tkn); 525 var tokenSequences = []; 526 tokenSequences.push(sequence); 527 528 s = s.replace(/^\s*|\s*$/, ""); 529 530 var expMatch = tokenExpr.exec(s); 531 while (expMatch) 532 { 533 var tstr = expMatch[0]; 534 var c = tstr.charAt(0);
535 switch (c) 536 { 537 case '.': 538 tkn.classes.push(new Spry.$$.Token.Attr("class", "\\b" + tstr.substr(1) + "\\b")); 539 break; 540 case '#': 541 tkn.id = tstr.substr(1); 542 break; 543 case ':': 544 tkn.pseudos.push(new Spry.$$.Token.PseudoClass(tstr)); 545 break; 546 case '[': 547 var attrComps = tstr.match(/\[([^\"'~\^\$\*\|\]=]+)(([~\^\$\*\|]?=)\s*('[^']*'|"[^"]*"|[^"'\]]+))?\s*\]/); 548 var name = attrComps[1]; 549 var matchType = attrComps[3]; 550 var val = attrComps[4]; 551 if (val) 552 { 553 val = val.replace(/^['"]|['"]$/g, ""); 554 val = val.replace(Spry.$$.escapeRegExpCharsRE, '\\$&'); 555 } 556 557 var matchStr = undefined; 558 559 switch(matchType) 560 { 561 case "=": 562 matchStr = "^" + val + "$"; 563 break; 564 case "^=": 565 matchStr = "^" + val; 566 break; 567 case "$=": 568 matchStr = val + "$"; 569 break; 570 case "~=": 571 case "|=": 572 matchStr = "\\b" + val + "\\b"; 573 break; 574 case "*=": 575 matchStr = val; 576 break; 577 } 578 579 tkn.attrs.push(new Spry.$$.Token.Attr(name, matchStr)); 580 break; 581 default: 582 var combiMatch = tstr.match(/^\s*([\s,~>\+])\s*$/); 583 if (combiMatch) 584 { 585 if (combiMatch[1] == ',') 586 { 587 sequence = new Array; 588 tokenSequences.push(sequence); 589 tkn = new Spry.$$.Token; 590 sequence.push(tkn); 591 } 592 else 593 { 594 tkn = new Spry.$$.Token; 595 tkn.type = Spry.$$.Token.COMBINATOR; 596 tkn.name = combiMatch[1]; 597 sequence.push(tkn); 598 tkn = new Spry.$$.Token(); 599 sequence.push(tkn); 600 } 601 } 602 else 603 tkn.name = tstr.toLowerCase(); 604 break; 605 } 606 expMatch = tokenExpr.exec(s); 607 } 608 609 Spry.$$.cache[s] = tokenSequences; 610 611 return tokenSequences; 612}; 613 614Spry.$$.combinatorFuncs = { 615 // Element Descendant 616 617 " ": function(nodes, token) 618 { 619 var uid = ++Spry.$$.uniqueID; 620 var results = []; 621 var nn = nodes.length; 622 for (var i = 0; i < nn; i++) 623 { 624 var n = nodes[i]; 625 if (uid != n.spry$$uid) 626 { 627 // n.spry$$uid = uid; 628 var ea = nodes[i].getElementsByTagName(token.name); 629 var ne = ea.length; 630 for (var j = 0; j < ne; j++) 631 { 632 var e = ea[j]; 633 634 // If the token matches, add it to our results. We have 635 // to make sure e is an element because IE6 returns the DOCTYPE 636 // tag as a comment when '*' is used in the call to getElementsByTagName(). 637 638 if (e.nodeType == 1 /* Node.ELEMENT_NODE */ && token.match(e, true)) 639 results.push(e); 640 e.spry$$uid = uid; 641 } 642 } 643 } 644 return results; 645 }, 646 647 // Element Child 648 649 ">": function(nodes, token) 650 { 651 var results = []; 652 var nn = nodes.length; 653 for (var i = 0; i < nn; i++) 654 { 655 var n = nodes[i].firstChild; 656 while (n) 657 { 658 if (n.nodeType == 1 /* Node.ELEMENT_NODE */ && token.match(n)) 659 results.push(n); 660 n = n.nextSibling; 661 } 662 } 663 return results; 664 }, 665 666 // Element Immediately Preceded By 667 668 "+": function(nodes, token) 669 { 670 var results = []; 671 var nn = nodes.length; 672 for (var i = 0; i < nn; i++) 673 { 674 var n = nodes[i].nextSibling; 675 while (n && n.nodeType != 1 /* Node.ELEMENT_NODE */) 676 n = n.nextSibling; 677 if (n && token.match(n)) 678 results.push(n); 679 } 680 return results; 681 }, 682 683 // Element Preceded By 684 685 "~": function(nodes, token) 686 { 687 var uid = ++Spry.$$.uniqueID; 688 var results = []; 689 var nn = nodes.length; 690 for (var i = 0; i < nn; i++) 691 { 692 var n = nodes[i].nextSibling; 693 while (n) 694 { 695 if (n.nodeType == 1 /* Node.ELEMENT_NODE */) 696 { 697 if (uid == n.spry$$uid) 698 break; 699 700 if (token.match(n)) 701 { 702 results.push(n); 703 n.spry$$uid = uid; 704 } 705 } 706 n = n.nextSibling; 707 } 708 } 709 return results; 710 } 711}; 712 713Spry.$$.uniqueID = 0; 714 715Spry.$$.pseudoFuncs = { 716 ":first-child": function(arg, node, token) 717 { 718 var n = node.previousSibling; 719 while (n) 720 { 721 if (n.nodeType == 1) return false; // Node.ELEMENT_NODE 722 n = n.previousSibling; 723 } 724 725 return true; 726 }, 727 728 ":last-child": function(arg, node, token) 729 { 730 var n = node.nextSibling; 731 while (n) 732 { 733 if (n.nodeType == 1) // Node.ELEMENT_NODE 734 return false; 735 n = n.nextSibling; 736 } 737 return true; 738 }, 739 740 ":empty": function(arg, node, token) 741 { 742 var n = node.firstChild; 743 while (n) 744 { 745 switch(n.nodeType) 746 { 747 case 1: // Node.ELEMENT_NODE 748 case 3: // Node.TEXT_NODE 749 case 4: // Node.CDATA_NODE 750 case 5: // Node.ENTITY_REFERENCE_NODE 751 return false; 752 } 753 n = n.nextSibling; 754 } 755 return true; 756 }, 757 758 ":nth-child": function(arg, node, token) 759 { 760 return Spry.$$.nthChild(arg, node, token); 761 }, 762 763 ":nth-last-child": function(arg, node, token) 764 { 765 return Spry.$$.nthChild(arg, node, token, true); 766 }, 767 768 ":nth-of-type": function(arg, node, token) 769 { 770 return Spry.$$.nthChild(arg, node, token, false, true); 771 }, 772 773 ":nth-last-of-type": function(arg, node, token) 774 { 775 return Spry.$$.nthChild(arg, node, token, true, true); 776 }, 777 778 ":first-of-type": function(arg, node, token) 779 { 780 var nodeName = token.getNodeNameIfTypeMatches(node); 781 if (!nodeName) return false; 782 783 var n = node.previousSibling; 784 while (n) 785 { 786 if (n.nodeType == 1 && nodeName == n.nodeName.toLowerCase()) return false; // Node.ELEMENT_NODE 787 n = n.previousSibling; 788 } 789 790 return true; 791 }, 792 793 ":last-of-type": function(arg, node, token) 794 { 795 var nodeName = token.getNodeNameIfTypeMatches(node); 796 if (!nodeName) return false; 797 798 var n = node.nextSibling; 799 while (n) 800 { 801 if (n.nodeType == 1 && nodeName == n.nodeName.toLowerCase()) // Node.ELEMENT_NODE 802 return false; 803 n = n.nextSibling; 804 } 805 return true; 806 }, 807 808 ":only-child": function(arg, node, token) 809 { 810 var f = Spry.$$.pseudoFuncs; 811 return f[":first-child"](arg, node, token) && f[":last-child"](arg, node, token); 812 }, 813 814 ":only-of-type": function(arg, node, token) 815 { 816 var f = Spry.$$.pseudoFuncs; 817 return f[":first-of-type"](arg, node, token) && f[":last-of-type"](arg, node, token); 818 }, 819 820 ":not": function(arg, node, token) 821 { 822 var s = Spry.$$.tokenizeSequence(arg)[0]; 823 var t = s ? s[0] : null; 824 return !t || !t.match(node); 825 }, 826 827 ":enabled": function(arg, node, token) 828 { 829 return !node.disabled; 830 }, 831 832 ":disabled": function(arg, node, token) 833 { 834 return node.disabled; 835 }, 836 837 ":checked": function(arg, node, token) 838 { 839 return node.checked; 840 }, 841 842 ":root": function(arg, node, token) 843 { 844 return node.parentNode && node.ownerDocument && node.parentNode == node.ownerDocument; 845 } 846}; 847 848Spry.$$.nthRegExp = /((-|[0-9]+)?n)?([+-]?[0-9]*)/; 849 850Spry.$$.nthCache = { 851 "even": { a: 2, b: 0, mode: 1, invalid: false } 852 , "odd": { a: 2, b: 1, mode: 1, invalid: false } 853 , "2n": { a: 2, b: 0, mode: 1, invalid: false } 854 , "2n+1": { a: 2, b: 1, mode: 1, invalid: false } 855}; 856 857Spry.$$.parseNthChildString = function(str) 858{ 859 var o = Spry.$$.nthCache[str]; 860 if (!o) 861 { 862 var m = str.match(Spry.$$.nthRegExp); 863 var n = m[1];
864 var a = m[2]; 865 var b = m[3]; 866 867 if (!a) 868 { 869 // An 'a' value was not specified. Was there an 'n' present? 870 // If so, we treat it as an increment of 1, otherwise we're 871 // in no-repeat mode. 872 873 a = n ? 1 : 0; 874 } 875 else if (a == "-") 876 { 877 // The string is using the "-n" short-hand which is 878 // short for -1. 879 880 a = -1; 881 } 882 else 883 { 884 // An integer repeat value for 'a' was specified. Convert 885 // it into number. 886 887 a = parseInt(a, 10); 888 } 889 890 // If a 'b' value was specified, turn it into a number. 891 // If no 'b' value was specified, default to zero. 892 893 b = b ? parseInt(b, 10) : 0; 894 895 // Figure out the mode: 896 // 897 // -1 - repeat backwards 898 // 0 - no repeat 899 // 1 - repeat forwards 900 901 var mode = (a == 0) ? 0 : ((a > 0) ? 1 : -1); 902 var invalid = false; 903 904 // Fix up 'a' and 'b' for proper repeating. 905 906 if (a > 0 && b < 0) 907 { 908 b = b % a; 909 b = ((b=(b%a)) < 0) ? a + b : b; 910 } 911 else if (a < 0) 912 { 913 if (b < 0) 914 invalid = true; 915 else 916 a = Math.abs(a); 917 } 918 919 o = new Object; 920 o.a = a; 921 o.b = b; 922 o.mode = mode; 923 o.invalid = invalid; 924 925 Spry.$$.nthCache[str] = o; 926 } 927 928 return o; 929}; 930 931Spry.$$.nthChild = function(arg, node, token, fromLastSib, matchNodeName) 932{ 933 if (matchNodeName) 934 { 935 var nodeName = token.getNodeNameIfTypeMatches(node); 936 if (!nodeName) return false; 937 } 938 939 var o = Spry.$$.parseNthChildString(arg); 940 941 if (o.invalid) 942 return false; 943 944 var qidProp = "spry$$ncQueryID"; 945 var posProp = "spry$$ncPos"; 946 var countProp = "spry$$ncCount"; 947 if (matchNodeName) 948 { 949 qidProp += nodeName; 950 posProp += nodeName; 951 countProp += nodeName; 952 } 953 954 var parent = node.parentNode; 955 if (parent[qidProp] != Spry.$$.queryID) 956 { 957 var pos = 0; 958 parent[qidProp] = Spry.$$.queryID; 959 var c = parent.firstChild; 960 while (c) 961 { 962 if (c.nodeType == 1 && (!matchNodeName || nodeName == c.nodeName.toLowerCase())) 963 c[posProp] = ++pos; 964 c = c.nextSibling; 965 } 966 parent[countProp] = pos; 967 } 968 969 pos = node[posProp]; 970 if (fromLastSib) 971 pos = parent[countProp] - pos + 1; 972 973/* 974 var sib = fromLastSib ? "nextSibling" : "previousSibling"; 975 976 var pos = 1; 977 var n = node[sib]; 978 while (n) 979 { 980 if (n.nodeType == 1 && (!matchNodeName || nodeName == n.nodeName.toLowerCase())) 981 { 982 if (n == node) break; 983 ++pos; 984 } 985 n = n[sib]; 986 } 987*/ 988 989 if (o.mode == 0) // Exact match 990 return pos == o.b; 991 if (o.mode > 0) // Forward Repeat 992 return (pos < o.b) ? false : (!((pos - o.b) % o.a)); 993 return (pos > o.b) ? false : (!((o.b - pos) % o.a)); // Backward Repeat 994}; 995 996Spry.$$.processTokens = function(tokens, root) 997{ 998 var numTokens = tokens.length; 999 var nodeSet = [ root ]; 1000 var combiFunc = null; 1001 1002 for (var i = 0; i < numTokens && nodeSet.length > 0; i++) 1003 { 1004 var t = tokens[i]; 1005 if (t.type == Spry.$$.Token.SELECTOR) 1006 { 1007 if (combiFunc) 1008 {
1009 nodeSet = combiFunc(nodeSet, t); 1010 combiFunc = null; 1011 } 1012 else 1013 nodeSet = Spry.$$.getMatchingElements(nodeSet, t); 1014 } 1015 else // Spry.$$.Token.COMBINATOR 1016 combiFunc = Spry.$$.combinatorFuncs[t.name]; 1017 } 1018 return nodeSet; 1019}; 1020 1021Spry.$$.getMatchingElements = function(nodes, token) 1022{ 1023 var results = []; 1024 if (token.id) 1025 { 1026 n = nodes[0]; 1027 if (n && n.ownerDocument) 1028 { 1029 var e = n.ownerDocument.getElementById(token.id); 1030 if (e) 1031 { 1032 // XXX: We need to make sure that the element 1033 // we found is actually underneath the root 1034 // we were given! 1035 1036 if (token.match(e)) 1037 results.push(e); 1038 } 1039 return results; 1040 } 1041 } 1042 1043 var nn = nodes.length; 1044 for (var i = 0; i < nn; i++) 1045 { 1046 var n = nodes[i]; 1047 // if (token.match(n)) results.push(n); 1048 1049 var ea = n.getElementsByTagName(token.name); 1050 var ne = ea.length; 1051 for (var j = 0; j < ne; j++) 1052 { 1053 var e = ea[j]; 1054 1055 // If the token matches, add it to our results. We have 1056 // to make sure e is an element because IE6 returns the DOCTYPE 1057 // tag as a comment when '*' is used in the call to getElementsByTagName(). 1058 1059 if (e.nodeType == 1 /* Node.ELEMENT_NODE */ && token.match(e, true)) 1060 results.push(e); 1061 } 1062 } 1063 return results; 1064}; 1065 1066/* 1067Spry.$$.dumpSequences = function(sequences) 1068{ 1069 Spry.Debug.trace("<hr />Number of Sequences: " + sequences.length); 1070 for (var i = 0; i < sequences.length; i++) 1071 { 1072 var str = ""; 1073 var s = sequences[i]; 1074 Spry.Debug.trace("<hr />Sequence " + i + " -- Tokens: " + s.length); 1075 for (var j = 0; j < s.length; j++) 1076 { 1077 var t = s[j]; 1078 if (t.type == Spry.$$.Token.SELECTOR) 1079 { 1080 str += " SELECTOR:\n Name: " + t.name + "\n ID: " + t.id + "\n Attrs:\n"; 1081 for (var k = 0; k < t.classes.length; k++) 1082 str += " " + t.classes[k].name + ": " + t.classes[k].value + "\n"; 1083 for (var k = 0; k < t.attrs.length; k++) 1084 str += " " + t.attrs[k].name + ": " + t.attrs[k].value + "\n"; 1085 str += " Pseudos:\n"; 1086 for (var k = 0; k < t.pseudos.length; k++) 1087 str += " " + t.pseudos[k].name + (t.pseudos[k].arg ? "(" + t.pseudos[k].arg + ")" : "") + "\n"; 1088 } 1089 else 1090 { 1091 str += " COMBINATOR:\n Name: '" + t.name + "'\n"; 1092 } 1093 } 1094 Spry.Debug.trace("<pre>" + Spry.Utils.encodeEntities(str) + "</pre>"); 1095 } 1096}; 1097*/ 1098 1099Spry.$$.addExtensions = function(a) 1100{ 1101 for (var f in Spry.$$.Results) 1102 a[f] = Spry.$$.Results[f]; 1103}; 1104 1105Spry.$$.Results = {}; 1106 1107Spry.$$.Results.forEach = function(func) 1108{ 1109 var n = this.length; 1110 for (var i = 0; i < n; i++) 1111 func(this[i]); 1112 return this; 1113}; 1114 1115Spry.$$.Results.setAttribute = function(name, value) 1116{ 1117 return this.forEach(function(n) { Spry.Utils.setAttribute(n, name, value); }); 1118}; 1119 1120Spry.$$.Results.removeAttribute = function(name) 1121{ 1122 return this.forEach(function(n) { Spry.Utils.removeAttribute(n, name); }); 1123}; 1124 1125Spry.$$.Results.addClassName = function(className) 1126{ 1127 return this.forEach(function(n) { Spry.Utils.addClassName(n, className); }); 1128}; 1129 1130Spry.$$.Results.removeClassName = function(className) 1131{ 1132 return this.forEach(function(n) { Spry.Utils.removeClassName(n, className); }); 1133}; 1134 1135Spry.$$.Results.toggleClassName = function(className) 1136{ 1137 return this.forEach(function(n) { Spry.Utils.toggleClassName(n, className); }); 1138}; 1139 1140Spry.$$.Results.addEventListener = function(eventType, handler, capture, bindHandler) 1141{ 1142 return this.forEach(function(n) { Spry.Utils.addEventListener(n, eventType, handler, capture, bindHandler); }); 1143}; 1144 1145Spry.$$.Results.removeEventListener = function(eventType, handler, capture) 1146{ 1147 return this.forEach(function(n) { Spry.Utils.removeEventListener(n, eventType, handler, capture); }); 1148}; 1149 1150Spry.$$.Results.setStyle = function(style) 1151{ 1152 if (style) 1153 { 1154 style = Spry.Utils.styleStringToObject(style); 1155 this.forEach(function(n) 1156 { 1157 for (var p in style) 1158 try { n.style[p] = style[p]; } catch (e) {} 1159 }); 1160 } 1161 return this; 1162}; 1163 1164Spry.$$.Results.setProperty = function(prop, value) 1165{ 1166 if (prop) 1167 { 1168 if (typeof prop == "string") 1169 { 1170 var p = {}; 1171 p[prop] = value; 1172 prop = p; 1173 } 1174 1175 this.forEach(function(n) 1176 { 1177 for (var p in prop)
1178 try { n[p] = prop[p]; } catch (e) {} 1179 }); 1180 } 1181 return this; 1182}; 1183 1184})(); // EndSpryComponent
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.