| [ Index ] |
PHP Cross Reference of Moodle 1.9.3 [Build 15-Oct-2008] |
[Summary view] [Print] [Text view]
1 /* 2 Copyright (c) 2008, Yahoo! Inc. All rights reserved. 3 Code licensed under the BSD License: 4 http://developer.yahoo.net/yui/license.txt 5 version: 2.6.0 6 */ 7 /** 8 * The dom module provides helper methods for manipulating Dom elements. 9 * @module dom 10 * 11 */ 12 13 (function() { 14 var Y = YAHOO.util, // internal shorthand 15 lang = YAHOO.lang, 16 getStyle, // for load time browser branching 17 setStyle, // ditto 18 propertyCache = {}, // for faster hyphen converts 19 reClassNameCache = {}, // cache regexes for className 20 document = window.document; // cache for faster lookups 21 22 YAHOO.env._id_counter = YAHOO.env._id_counter || 0; // for use with generateId (global to save state if Dom is overwritten) 23 24 // brower detection 25 var isOpera = YAHOO.env.ua.opera, 26 isSafari = YAHOO.env.ua.webkit, 27 isGecko = YAHOO.env.ua.gecko, 28 isIE = YAHOO.env.ua.ie; 29 30 // regex cache 31 var patterns = { 32 HYPHEN: /(-[a-z])/i, // to normalize get/setStyle 33 ROOT_TAG: /^body|html$/i, // body for quirks mode, html for standards, 34 OP_SCROLL:/^(?:inline|table-row)$/i 35 }; 36 37 var toCamel = function(property) { 38 if ( !patterns.HYPHEN.test(property) ) { 39 return property; // no hyphens 40 } 41 42 if (propertyCache[property]) { // already converted 43 return propertyCache[property]; 44 } 45 46 var converted = property; 47 48 while( patterns.HYPHEN.exec(converted) ) { 49 converted = converted.replace(RegExp.$1, 50 RegExp.$1.substr(1).toUpperCase()); 51 } 52 53 propertyCache[property] = converted; 54 return converted; 55 //return property.replace(/-([a-z])/gi, function(m0, m1) {return m1.toUpperCase()}) // cant use function as 2nd arg yet due to safari bug 56 }; 57 58 var getClassRegEx = function(className) { 59 var re = reClassNameCache[className]; 60 if (!re) { 61 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)'); 62 reClassNameCache[className] = re; 63 } 64 return re; 65 }; 66 67 // branching at load instead of runtime 68 if (document.defaultView && document.defaultView.getComputedStyle) { // W3C DOM method 69 getStyle = function(el, property) { 70 var value = null; 71 72 if (property == 'float') { // fix reserved word 73 property = 'cssFloat'; 74 } 75 76 var computed = el.ownerDocument.defaultView.getComputedStyle(el, ''); 77 if (computed) { // test computed before touching for safari 78 value = computed[toCamel(property)]; 79 } 80 81 return el.style[property] || value; 82 }; 83 } else if (document.documentElement.currentStyle && isIE) { // IE method 84 getStyle = function(el, property) { 85 switch( toCamel(property) ) { 86 case 'opacity' :// IE opacity uses filter 87 var val = 100; 88 try { // will error if no DXImageTransform 89 val = el.filters['DXImageTransform.Microsoft.Alpha'].opacity; 90 91 } catch(e) { 92 try { // make sure its in the document 93 val = el.filters('alpha').opacity; 94 } catch(e) { 95 } 96 } 97 return val / 100; 98 case 'float': // fix reserved word 99 property = 'styleFloat'; // fall through 100 default: 101 // test currentStyle before touching 102 var value = el.currentStyle ? el.currentStyle[property] : null; 103 return ( el.style[property] || value ); 104 } 105 }; 106 } else { // default to inline only 107 getStyle = function(el, property) { return el.style[property]; }; 108 } 109 110 if (isIE) { 111 setStyle = function(el, property, val) { 112 switch (property) { 113 case 'opacity': 114 if ( lang.isString(el.style.filter) ) { // in case not appended 115 el.style.filter = 'alpha(opacity=' + val * 100 + ')'; 116 117 if (!el.currentStyle || !el.currentStyle.hasLayout) { 118 el.style.zoom = 1; // when no layout or cant tell 119 } 120 } 121 break; 122 case 'float': 123 property = 'styleFloat'; 124 default: 125 el.style[property] = val; 126 } 127 }; 128 } else { 129 setStyle = function(el, property, val) { 130 if (property == 'float') { 131 property = 'cssFloat'; 132 } 133 el.style[property] = val; 134 }; 135 } 136 137 var testElement = function(node, method) { 138 return node && node.nodeType == 1 && ( !method || method(node) ); 139 }; 140 141 /** 142 * Provides helper methods for DOM elements. 143 * @namespace YAHOO.util 144 * @class Dom 145 */ 146 YAHOO.util.Dom = { 147 /** 148 * Returns an HTMLElement reference. 149 * @method get 150 * @param {String | HTMLElement |Array} el Accepts a string to use as an ID for getting a DOM reference, an actual DOM reference, or an Array of IDs and/or HTMLElements. 151 * @return {HTMLElement | Array} A DOM reference to an HTML element or an array of HTMLElements. 152 */ 153 get: function(el) { 154 if (el) { 155 if (el.nodeType || el.item) { // Node, or NodeList 156 return el; 157 } 158 159 if (typeof el === 'string') { // id 160 return document.getElementById(el); 161 } 162 163 if ('length' in el) { // array-like 164 var c = []; 165 for (var i = 0, len = el.length; i < len; ++i) { 166 c[c.length] = Y.Dom.get(el[i]); 167 } 168 169 return c; 170 } 171 172 return el; // some other object, just pass it back 173 } 174 175 return null; 176 }, 177 178 /** 179 * Normalizes currentStyle and ComputedStyle. 180 * @method getStyle 181 * @param {String | HTMLElement |Array} el Accepts a string to use as an ID, an actual DOM reference, or an Array of IDs and/or HTMLElements. 182 * @param {String} property The style property whose value is returned. 183 * @return {String | Array} The current value of the style property for the element(s). 184 */ 185 getStyle: function(el, property) { 186 property = toCamel(property); 187 188 var f = function(element) { 189 return getStyle(element, property); 190 }; 191 192 return Y.Dom.batch(el, f, Y.Dom, true); 193 }, 194 195 /** 196 * Wrapper for setting style properties of HTMLElements. Normalizes "opacity" across modern browsers. 197 * @method setStyle 198 * @param {String | HTMLElement | Array} el Accepts a string to use as an ID, an actual DOM reference, or an Array of IDs and/or HTMLElements. 199 * @param {String} property The style property to be set. 200 * @param {String} val The value to apply to the given property. 201 */ 202 setStyle: function(el, property, val) { 203 property = toCamel(property); 204 205 var f = function(element) { 206 setStyle(element, property, val); 207 208 }; 209 210 Y.Dom.batch(el, f, Y.Dom, true); 211 }, 212 213 /** 214 * Gets the current position of an element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false). 215 * @method getXY 216 * @param {String | HTMLElement | Array} el Accepts a string to use as an ID, an actual DOM reference, or an Array of IDs and/or HTMLElements 217 * @return {Array} The XY position of the element(s) 218 */ 219 getXY: function(el) { 220 var f = function(el) { 221 // has to be part of document to have pageXY 222 if ( (el.parentNode === null || el.offsetParent === null || 223 this.getStyle(el, 'display') == 'none') && el != el.ownerDocument.body) { 224 return false; 225 } 226 227 return getXY(el); 228 }; 229 230 return Y.Dom.batch(el, f, Y.Dom, true); 231 }, 232 233 /** 234 * Gets the current X position of an element based on page coordinates. The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false). 235 * @method getX 236 * @param {String | HTMLElement | Array} el Accepts a string to use as an ID, an actual DOM reference, or an Array of IDs and/or HTMLElements 237 * @return {Number | Array} The X position of the element(s) 238 */ 239 getX: function(el) { 240 var f = function(el) { 241 return Y.Dom.getXY(el)[0]; 242 }; 243 244 return Y.Dom.batch(el, f, Y.Dom, true); 245 }, 246 247 /** 248 * Gets the current Y position of an element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false). 249 * @method getY 250 * @param {String | HTMLElement | Array} el Accepts a string to use as an ID, an actual DOM reference, or an Array of IDs and/or HTMLElements 251 * @return {Number | Array} The Y position of the element(s) 252 */ 253 getY: function(el) { 254 var f = function(el) { 255 return Y.Dom.getXY(el)[1]; 256 }; 257 258 return Y.Dom.batch(el, f, Y.Dom, true); 259 }, 260 261 /** 262 * Set the position of an html element in page coordinates, regardless of how the element is positioned. 263 * The element(s) must be part of the DOM tree to have page coordinates (display:none or elements not appended return false). 264 * @method setXY 265 * @param {String | HTMLElement | Array} el Accepts a string to use as an ID, an actual DOM reference, or an Array of IDs and/or HTMLElements 266 * @param {Array} pos Contains X & Y values for new position (coordinates are page-based) 267 * @param {Boolean} noRetry By default we try and set the position a second time if the first fails 268 */ 269 setXY: function(el, pos, noRetry) { 270 var f = function(el) { 271 var style_pos = this.getStyle(el, 'position'); 272 if (style_pos == 'static') { // default to relative 273 this.setStyle(el, 'position', 'relative'); 274 style_pos = 'relative'; 275 } 276 277 var pageXY = this.getXY(el); 278 if (pageXY === false) { // has to be part of doc to have pageXY 279 return false; 280 } 281 282 var delta = [ // assuming pixels; if not we will have to retry 283 parseInt( this.getStyle(el, 'left'), 10 ), 284 parseInt( this.getStyle(el, 'top'), 10 ) 285 ]; 286 287 if ( isNaN(delta[0]) ) {// in case of 'auto' 288 delta[0] = (style_pos == 'relative') ? 0 : el.offsetLeft; 289 } 290 if ( isNaN(delta[1]) ) { // in case of 'auto' 291 delta[1] = (style_pos == 'relative') ? 0 : el.offsetTop; 292 } 293 294 if (pos[0] !== null) { el.style.left = pos[0] - pageXY[0] + delta[0] + 'px'; } 295 if (pos[1] !== null) { el.style.top = pos[1] - pageXY[1] + delta[1] + 'px'; } 296 297 if (!noRetry) { 298 var newXY = this.getXY(el); 299 300 // if retry is true, try one more time if we miss 301 if ( (pos[0] !== null && newXY[0] != pos[0]) || 302 (pos[1] !== null && newXY[1] != pos[1]) ) { 303 this.setXY(el, pos, true); 304 } 305 } 306 307 }; 308 309 Y.Dom.batch(el, f, Y.Dom, true); 310 }, 311 312 /** 313 * Set the X position of an html element in page coordinates, regardless of how the element is positioned. 314 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false). 315 * @method setX 316 * @param {String | HTMLElement | Array} el Accepts a string to use as an ID, an actual DOM reference, or an Array of IDs and/or HTMLElements. 317 * @param {Int} x The value to use as the X coordinate for the element(s). 318 */ 319 setX: function(el, x) { 320 Y.Dom.setXY(el, [x, null]); 321 }, 322 323 /** 324 * Set the Y position of an html element in page coordinates, regardless of how the element is positioned. 325 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false). 326 * @method setY 327 * @param {String | HTMLElement | Array} el Accepts a string to use as an ID, an actual DOM reference, or an Array of IDs and/or HTMLElements. 328 * @param {Int} x To use as the Y coordinate for the element(s). 329 */ 330 setY: function(el, y) { 331 Y.Dom.setXY(el, [null, y]); 332 }, 333 334 /** 335 * Returns the region position of the given element. 336 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false). 337 * @method getRegion 338 * @param {String | HTMLElement | Array} el Accepts a string to use as an ID, an actual DOM reference, or an Array of IDs and/or HTMLElements. 339 * @return {Region | Array} A Region or array of Region instances containing "top, left, bottom, right" member data. 340 */ 341 getRegion: function(el) { 342 var f = function(el) { 343 if ( (el.parentNode === null || el.offsetParent === null || 344 this.getStyle(el, 'display') == 'none') && el != el.ownerDocument.body) { 345 return false; 346 } 347 348 var region = Y.Region.getRegion(el); 349 return region; 350 }; 351 352 return Y.Dom.batch(el, f, Y.Dom, true); 353 }, 354 355 /** 356 * Returns the width of the client (viewport). 357 * @method getClientWidth 358 * @deprecated Now using getViewportWidth. This interface left intact for back compat. 359 * @return {Int} The width of the viewable area of the page. 360 */ 361 getClientWidth: function() { 362 return Y.Dom.getViewportWidth(); 363 }, 364 365 /** 366 * Returns the height of the client (viewport). 367 * @method getClientHeight 368 * @deprecated Now using getViewportHeight. This interface left intact for back compat. 369 * @return {Int} The height of the viewable area of the page. 370 */ 371 getClientHeight: function() { 372 return Y.Dom.getViewportHeight(); 373 }, 374 375 /** 376 * Returns a array of HTMLElements with the given class. 377 * For optimized performance, include a tag and/or root node when possible. 378 * Note: This method operates against a live collection, so modifying the 379 * collection in the callback (removing/appending nodes, etc.) will have 380 * side effects. Instead you should iterate the returned nodes array, 381 * as you would with the native "getElementsByTagName" method. 382 * @method getElementsByClassName 383 * @param {String} className The class name to match against 384 * @param {String} tag (optional) The tag name of the elements being collected 385 * @param {String | HTMLElement} root (optional) The HTMLElement or an ID to use as the starting point 386 * @param {Function} apply (optional) A function to apply to each element when found 387 * @return {Array} An array of elements that have the given class name 388 */ 389 getElementsByClassName: function(className, tag, root, apply) { 390 className = lang.trim(className); 391 tag = tag || '*'; 392 root = (root) ? Y.Dom.get(root) : null || document; 393 if (!root) { 394 return []; 395 } 396 397 var nodes = [], 398 elements = root.getElementsByTagName(tag), 399 re = getClassRegEx(className); 400 401 for (var i = 0, len = elements.length; i < len; ++i) { 402 if ( re.test(elements[i].className) ) { 403 nodes[nodes.length] = elements[i]; 404 if (apply) { 405 apply.call(elements[i], elements[i]); 406 } 407 } 408 } 409 410 return nodes; 411 }, 412 413 /** 414 * Determines whether an HTMLElement has the given className. 415 * @method hasClass 416 * @param {String | HTMLElement | Array} el The element or collection to test 417 * @param {String} className the class name to search for 418 * @return {Boolean | Array} A boolean value or array of boolean values 419 */ 420 hasClass: function(el, className) { 421 var re = getClassRegEx(className); 422 423 var f = function(el) { 424 return re.test(el.className); 425 }; 426 427 return Y.Dom.batch(el, f, Y.Dom, true); 428 }, 429 430 /** 431 * Adds a class name to a given element or collection of elements. 432 * @method addClass 433 * @param {String | HTMLElement | Array} el The element or collection to add the class to 434 * @param {String} className the class name to add to the class attribute 435 * @return {Boolean | Array} A pass/fail boolean or array of booleans 436 */ 437 addClass: function(el, className) { 438 var f = function(el) { 439 if (this.hasClass(el, className)) { 440 return false; // already present 441 } 442 443 444 el.className = lang.trim([el.className, className].join(' ')); 445 return true; 446 }; 447 448 return Y.Dom.batch(el, f, Y.Dom, true); 449 }, 450 451 /** 452 * Removes a class name from a given element or collection of elements. 453 * @method removeClass 454 * @param {String | HTMLElement | Array} el The element or collection to remove the class from 455 * @param {String} className the class name to remove from the class attribute 456 * @return {Boolean | Array} A pass/fail boolean or array of booleans 457 */ 458 removeClass: function(el, className) { 459 var re = getClassRegEx(className); 460 461 var f = function(el) { 462 var ret = false, 463 current = el.className; 464 465 if (className && current && this.hasClass(el, className)) { 466 467 el.className = current.replace(re, ' '); 468 if ( this.hasClass(el, className) ) { // in case of multiple adjacent 469 this.removeClass(el, className); 470 } 471 472 el.className = lang.trim(el.className); // remove any trailing spaces 473 if (el.className === '') { // remove class attribute if empty 474 var attr = (el.hasAttribute) ? 'class' : 'className'; 475 el.removeAttribute(attr); 476 } 477 ret = true; 478 } 479 return ret; 480 }; 481 482 return Y.Dom.batch(el, f, Y.Dom, true); 483 }, 484 485 /** 486 * Replace a class with another class for a given element or collection of elements. 487 * If no oldClassName is present, the newClassName is simply added. 488 * @method replaceClass 489 * @param {String | HTMLElement | Array} el The element or collection to remove the class from 490 * @param {String} oldClassName the class name to be replaced 491 * @param {String} newClassName the class name that will be replacing the old class name 492 * @return {Boolean | Array} A pass/fail boolean or array of booleans 493 */ 494 replaceClass: function(el, oldClassName, newClassName) { 495 if (!newClassName || oldClassName === newClassName) { // avoid infinite loop 496 return false; 497 } 498 499 var re = getClassRegEx(oldClassName); 500 501 var f = function(el) { 502 503 if ( !this.hasClass(el, oldClassName) ) { 504 this.addClass(el, newClassName); // just add it if nothing to replace 505 return true; // NOTE: return 506 } 507 508 el.className = el.className.replace(re, ' ' + newClassName + ' '); 509 510 if ( this.hasClass(el, oldClassName) ) { // in case of multiple adjacent 511 this.removeClass(el, oldClassName); 512 } 513 514 el.className = lang.trim(el.className); // remove any trailing spaces 515 return true; 516 }; 517 518 return Y.Dom.batch(el, f, Y.Dom, true); 519 }, 520 521 /** 522 * Returns an ID and applies it to the element "el", if provided. 523 * @method generateId 524 * @param {String | HTMLElement | Array} el (optional) An optional element array of elements to add an ID to (no ID is added if one is already present). 525 * @param {String} prefix (optional) an optional prefix to use (defaults to "yui-gen"). 526 * @return {String | Array} The generated ID, or array of generated IDs (or original ID if already present on an element) 527 */ 528 generateId: function(el, prefix) { 529 prefix = prefix || 'yui-gen'; 530 531 var f = function(el) { 532 if (el && el.id) { // do not override existing ID 533 return el.id; 534 } 535 536 var id = prefix + YAHOO.env._id_counter++; 537 538 if (el) { 539 el.id = id; 540 } 541 542 return id; 543 }; 544 545 // batch fails when no element, so just generate and return single ID 546 return Y.Dom.batch(el, f, Y.Dom, true) || f.apply(Y.Dom, arguments); 547 }, 548 549 /** 550 * Determines whether an HTMLElement is an ancestor of another HTML element in the DOM hierarchy. 551 * @method isAncestor 552 * @param {String | HTMLElement} haystack The possible ancestor 553 * @param {String | HTMLElement} needle The possible descendent 554 * @return {Boolean} Whether or not the haystack is an ancestor of needle 555 */ 556 isAncestor: function(haystack, needle) { 557 haystack = Y.Dom.get(haystack); 558 needle = Y.Dom.get(needle); 559 560 var ret = false; 561 562 if ( (haystack && needle) && (haystack.nodeType && needle.nodeType) ) { 563 if (haystack.contains && haystack !== needle) { // contains returns true when equal 564 ret = haystack.contains(needle); 565 } 566 else if (haystack.compareDocumentPosition) { // gecko 567 ret = !!(haystack.compareDocumentPosition(needle) & 16); 568 } 569 } else { 570 } 571 return ret; 572 }, 573 574 /** 575 * Determines whether an HTMLElement is present in the current document. 576 * @method inDocument 577 * @param {String | HTMLElement} el The element to search for 578 * @return {Boolean} Whether or not the element is present in the current document 579 */ 580 inDocument: function(el) { 581 return this.isAncestor(document.documentElement, el); 582 }, 583 584 /** 585 * Returns a array of HTMLElements that pass the test applied by supplied boolean method. 586 * For optimized performance, include a tag and/or root node when possible. 587 * Note: This method operates against a live collection, so modifying the 588 * collection in the callback (removing/appending nodes, etc.) will have 589 * side effects. Instead you should iterate the returned nodes array, 590 * as you would with the native "getElementsByTagName" method. 591 * @method getElementsBy 592 * @param {Function} method - A boolean method for testing elements which receives the element as its only argument. 593 * @param {String} tag (optional) The tag name of the elements being collected 594 * @param {String | HTMLElement} root (optional) The HTMLElement or an ID to use as the starting point 595 * @param {Function} apply (optional) A function to apply to each element when found 596 * @return {Array} Array of HTMLElements 597 */ 598 getElementsBy: function(method, tag, root, apply) { 599 tag = tag || '*'; 600 root = (root) ? Y.Dom.get(root) : null || document; 601 602 if (!root) { 603 return []; 604 } 605 606 var nodes = [], 607 elements = root.getElementsByTagName(tag); 608 609 for (var i = 0, len = elements.length; i < len; ++i) { 610 if ( method(elements[i]) ) { 611 nodes[nodes.length] = elements[i]; 612 if (apply) { 613 apply(elements[i]); 614 } 615 } 616 } 617 618 619 return nodes; 620 }, 621 622 /** 623 * Runs the supplied method against each item in the Collection/Array. 624 * The method is called with the element(s) as the first arg, and the optional param as the second ( method(el, o) ). 625 * @method batch 626 * @param {String | HTMLElement | Array} el (optional) An element or array of elements to apply the method to 627 * @param {Function} method The method to apply to the element(s) 628 * @param {Any} o (optional) An optional arg that is passed to the supplied method 629 * @param {Boolean} override (optional) Whether or not to override the scope of "method" with "o" 630 * @return {Any | Array} The return value(s) from the supplied method 631 */ 632 batch: function(el, method, o, override) { 633 el = (el && (el.tagName || el.item)) ? el : Y.Dom.get(el); // skip get() when possible 634 635 if (!el || !method) { 636 return false; 637 } 638 var scope = (override) ? o : window; 639 640 if (el.tagName || el.length === undefined) { // element or not array-like 641 return method.call(scope, el, o); 642 } 643 644 var collection = []; 645 646 for (var i = 0, len = el.length; i < len; ++i) { 647 collection[collection.length] = method.call(scope, el[i], o); 648 } 649 650 return collection; 651 }, 652 653 /** 654 * Returns the height of the document. 655 * @method getDocumentHeight 656 * @return {Int} The height of the actual document (which includes the body and its margin). 657 */ 658 getDocumentHeight: function() { 659 var scrollHeight = (document.compatMode != 'CSS1Compat') ? document.body.scrollHeight : document.documentElement.scrollHeight; 660 661 var h = Math.max(scrollHeight, Y.Dom.getViewportHeight()); 662 return h; 663 }, 664 665 /** 666 * Returns the width of the document. 667 * @method getDocumentWidth 668 * @return {Int} The width of the actual document (which includes the body and its margin). 669 */ 670 getDocumentWidth: function() { 671 var scrollWidth = (document.compatMode != 'CSS1Compat') ? document.body.scrollWidth : document.documentElement.scrollWidth; 672 var w = Math.max(scrollWidth, Y.Dom.getViewportWidth()); 673 return w; 674 }, 675 676 /** 677 * Returns the current height of the viewport. 678 * @method getViewportHeight 679 * @return {Int} The height of the viewable area of the page (excludes scrollbars). 680 */ 681 getViewportHeight: function() { 682 var height = self.innerHeight; // Safari, Opera 683 var mode = document.compatMode; 684 685 if ( (mode || isIE) && !isOpera ) { // IE, Gecko 686 height = (mode == 'CSS1Compat') ? 687 document.documentElement.clientHeight : // Standards 688 document.body.clientHeight; // Quirks 689 } 690 691 return height; 692 }, 693 694 /** 695 * Returns the current width of the viewport. 696 * @method getViewportWidth 697 * @return {Int} The width of the viewable area of the page (excludes scrollbars). 698 */ 699 700 getViewportWidth: function() { 701 var width = self.innerWidth; // Safari 702 var mode = document.compatMode; 703 704 if (mode || isIE) { // IE, Gecko, Opera 705 width = (mode == 'CSS1Compat') ? 706 document.documentElement.clientWidth : // Standards 707 document.body.clientWidth; // Quirks 708 } 709 return width; 710 }, 711 712 /** 713 * Returns the nearest ancestor that passes the test applied by supplied boolean method. 714 * For performance reasons, IDs are not accepted and argument validation omitted. 715 * @method getAncestorBy 716 * @param {HTMLElement} node The HTMLElement to use as the starting point 717 * @param {Function} method - A boolean method for testing elements which receives the element as its only argument. 718 * @return {Object} HTMLElement or null if not found 719 */ 720 getAncestorBy: function(node, method) { 721 while ( (node = node.parentNode) ) { // NOTE: assignment 722 if ( testElement(node, method) ) { 723 return node; 724 } 725 } 726 727 return null; 728 }, 729 730 /** 731 * Returns the nearest ancestor with the given className. 732 * @method getAncestorByClassName 733 * @param {String | HTMLElement} node The HTMLElement or an ID to use as the starting point 734 * @param {String} className 735 * @return {Object} HTMLElement 736 */ 737 getAncestorByClassName: function(node, className) { 738 node = Y.Dom.get(node); 739 if (!node) { 740 return null; 741 } 742 var method = function(el) { return Y.Dom.hasClass(el, className); }; 743 return Y.Dom.getAncestorBy(node, method); 744 }, 745 746 /** 747 * Returns the nearest ancestor with the given tagName. 748 * @method getAncestorByTagName 749 * @param {String | HTMLElement} node The HTMLElement or an ID to use as the starting point 750 * @param {String} tagName 751 * @return {Object} HTMLElement 752 */ 753 getAncestorByTagName: function(node, tagName) { 754 node = Y.Dom.get(node); 755 if (!node) { 756 return null; 757 } 758 var method = function(el) { 759 return el.tagName && el.tagName.toUpperCase() == tagName.toUpperCase(); 760 }; 761 762 return Y.Dom.getAncestorBy(node, method); 763 }, 764 765 /** 766 * Returns the previous sibling that is an HTMLElement. 767 * For performance reasons, IDs are not accepted and argument validation omitted. 768 * Returns the nearest HTMLElement sibling if no method provided. 769 * @method getPreviousSiblingBy 770 * @param {HTMLElement} node The HTMLElement to use as the starting point 771 * @param {Function} method A boolean function used to test siblings 772 * that receives the sibling node being tested as its only argument 773 * @return {Object} HTMLElement or null if not found 774 */ 775 getPreviousSiblingBy: function(node, method) { 776 while (node) { 777 node = node.previousSibling; 778 if ( testElement(node, method) ) { 779 return node; 780 } 781 } 782 return null; 783 }, 784 785 /** 786 * Returns the previous sibling that is an HTMLElement 787 * @method getPreviousSibling 788 * @param {String | HTMLElement} node The HTMLElement or an ID to use as the starting point 789 * @return {Object} HTMLElement or null if not found 790 */ 791 getPreviousSibling: function(node) { 792 node = Y.Dom.get(node); 793 if (!node) { 794 return null; 795 } 796 797 return Y.Dom.getPreviousSiblingBy(node); 798 }, 799 800 /** 801 * Returns the next HTMLElement sibling that passes the boolean method. 802 * For performance reasons, IDs are not accepted and argument validation omitted. 803 * Returns the nearest HTMLElement sibling if no method provided. 804 * @method getNextSiblingBy 805 * @param {HTMLElement} node The HTMLElement to use as the starting point 806 * @param {Function} method A boolean function used to test siblings 807 * that receives the sibling node being tested as its only argument 808 * @return {Object} HTMLElement or null if not found 809 */ 810 getNextSiblingBy: function(node, method) { 811 while (node) { 812 node = node.nextSibling; 813 if ( testElement(node, method) ) { 814 return node; 815 } 816 } 817 return null; 818 }, 819 820 /** 821 * Returns the next sibling that is an HTMLElement 822 * @method getNextSibling 823 * @param {String | HTMLElement} node The HTMLElement or an ID to use as the starting point 824 * @return {Object} HTMLElement or null if not found 825 */ 826 getNextSibling: function(node) { 827 node = Y.Dom.get(node); 828 if (!node) { 829 return null; 830 } 831 832 return Y.Dom.getNextSiblingBy(node); 833 }, 834 835 /** 836 * Returns the first HTMLElement child that passes the test method. 837 * @method getFirstChildBy 838 * @param {HTMLElement} node The HTMLElement to use as the starting point 839 * @param {Function} method A boolean function used to test children 840 * that receives the node being tested as its only argument 841 * @return {Object} HTMLElement or null if not found 842 */ 843 getFirstChildBy: function(node, method) { 844 var child = ( testElement(node.firstChild, method) ) ? node.firstChild : null; 845 return child || Y.Dom.getNextSiblingBy(node.firstChild, method); 846 }, 847 848 /** 849 * Returns the first HTMLElement child. 850 * @method getFirstChild 851 * @param {String | HTMLElement} node The HTMLElement or an ID to use as the starting point 852 * @return {Object} HTMLElement or null if not found 853 */ 854 getFirstChild: function(node, method) { 855 node = Y.Dom.get(node); 856 if (!node) { 857 return null; 858 } 859 return Y.Dom.getFirstChildBy(node); 860 }, 861 862 /** 863 * Returns the last HTMLElement child that passes the test method. 864 * @method getLastChildBy 865 * @param {HTMLElement} node The HTMLElement to use as the starting point 866 * @param {Function} method A boolean function used to test children 867 * that receives the node being tested as its only argument 868 * @return {Object} HTMLElement or null if not found 869 */ 870 getLastChildBy: function(node, method) { 871 if (!node) { 872 return null; 873 } 874 var child = ( testElement(node.lastChild, method) ) ? node.lastChild : null; 875 return child || Y.Dom.getPreviousSiblingBy(node.lastChild, method); 876 }, 877 878 /** 879 * Returns the last HTMLElement child. 880 * @method getLastChild 881 * @param {String | HTMLElement} node The HTMLElement or an ID to use as the starting point 882 * @return {Object} HTMLElement or null if not found 883 */ 884 getLastChild: function(node) { 885 node = Y.Dom.get(node); 886 return Y.Dom.getLastChildBy(node); 887 }, 888 889 /** 890 * Returns an array of HTMLElement childNodes that pass the test method. 891 * @method getChildrenBy 892 * @param {HTMLElement} node The HTMLElement to start from 893 * @param {Function} method A boolean function used to test children 894 * that receives the node being tested as its only argument 895 * @return {Array} A static array of HTMLElements 896 */ 897 getChildrenBy: function(node, method) { 898 var child = Y.Dom.getFirstChildBy(node, method); 899 var children = child ? [child] : []; 900 901 Y.Dom.getNextSiblingBy(child, function(node) { 902 if ( !method || method(node) ) { 903 children[children.length] = node; 904 } 905 return false; // fail test to collect all children 906 }); 907 908 return children; 909 }, 910 911 /** 912 * Returns an array of HTMLElement childNodes. 913 * @method getChildren 914 * @param {String | HTMLElement} node The HTMLElement or an ID to use as the starting point 915 * @return {Array} A static array of HTMLElements 916 */ 917 getChildren: function(node) { 918 node = Y.Dom.get(node); 919 if (!node) { 920 } 921 922 return Y.Dom.getChildrenBy(node); 923 }, 924 925 /** 926 * Returns the left scroll value of the document 927 * @method getDocumentScrollLeft 928 * @param {HTMLDocument} document (optional) The document to get the scroll value of 929 * @return {Int} The amount that the document is scrolled to the left 930 */ 931 getDocumentScrollLeft: function(doc) { 932 doc = doc || document; 933 return Math.max(doc.documentElement.scrollLeft, doc.body.scrollLeft); 934 }, 935 936 /** 937 * Returns the top scroll value of the document 938 * @method getDocumentScrollTop 939 * @param {HTMLDocument} document (optional) The document to get the scroll value of 940 * @return {Int} The amount that the document is scrolled to the top 941 */ 942 getDocumentScrollTop: function(doc) { 943 doc = doc || document; 944 return Math.max(doc.documentElement.scrollTop, doc.body.scrollTop); 945 }, 946 947 /** 948 * Inserts the new node as the previous sibling of the reference node 949 * @method insertBefore 950 * @param {String | HTMLElement} newNode The node to be inserted 951 * @param {String | HTMLElement} referenceNode The node to insert the new node before 952 * @return {HTMLElement} The node that was inserted (or null if insert fails) 953 */ 954 insertBefore: function(newNode, referenceNode) { 955 newNode = Y.Dom.get(newNode); 956 referenceNode = Y.Dom.get(referenceNode); 957 958 if (!newNode || !referenceNode || !referenceNode.parentNode) { 959 return null; 960 } 961 962 return referenceNode.parentNode.insertBefore(newNode, referenceNode); 963 }, 964 965 /** 966 * Inserts the new node as the next sibling of the reference node 967 * @method insertAfter 968 * @param {String | HTMLElement} newNode The node to be inserted 969 * @param {String | HTMLElement} referenceNode The node to insert the new node after 970 * @return {HTMLElement} The node that was inserted (or null if insert fails) 971 */ 972 insertAfter: function(newNode, referenceNode) { 973 newNode = Y.Dom.get(newNode); 974 referenceNode = Y.Dom.get(referenceNode); 975 976 if (!newNode || !referenceNode || !referenceNode.parentNode) { 977 return null; 978 } 979 980 if (referenceNode.nextSibling) { 981 return referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling); 982 } else { 983 return referenceNode.parentNode.appendChild(newNode); 984 } 985 }, 986 987 /** 988 * Creates a Region based on the viewport relative to the document. 989 * @method getClientRegion 990 * @return {Region} A Region object representing the viewport which accounts for document scroll 991 */ 992 getClientRegion: function() { 993 var t = Y.Dom.getDocumentScrollTop(), 994 l = Y.Dom.getDocumentScrollLeft(), 995 r = Y.Dom.getViewportWidth() + l, 996 b = Y.Dom.getViewportHeight() + t; 997 998 return new Y.Region(t, r, b, l); 999 } 1000 }; 1001 1002 var getXY = function() { 1003 if (document.documentElement.getBoundingClientRect) { // IE 1004 return function(el) { 1005 var box = el.getBoundingClientRect(), 1006 round = Math.round; 1007 1008 var rootNode = el.ownerDocument; 1009 return [round(box.left + Y.Dom.getDocumentScrollLeft(rootNode)), round(box.top + 1010 Y.Dom.getDocumentScrollTop(rootNode))]; 1011 }; 1012 } else { 1013 return function(el) { // manually calculate by crawling up offsetParents 1014 var pos = [el.offsetLeft, el.offsetTop]; 1015 var parentNode = el.offsetParent; 1016 1017 // safari: subtract body offsets if el is abs (or any offsetParent), unless body is offsetParent 1018 var accountForBody = (isSafari && 1019 Y.Dom.getStyle(el, 'position') == 'absolute' && 1020 el.offsetParent == el.ownerDocument.body); 1021 1022 if (parentNode != el) { 1023 while (parentNode) { 1024 pos[0] += parentNode.offsetLeft; 1025 pos[1] += parentNode.offsetTop; 1026 if (!accountForBody && isSafari && 1027 Y.Dom.getStyle(parentNode,'position') == 'absolute' ) { 1028 accountForBody = true; 1029 } 1030 parentNode = parentNode.offsetParent; 1031 } 1032 } 1033 1034 if (accountForBody) { //safari doubles in this case 1035 pos[0] -= el.ownerDocument.body.offsetLeft; 1036 pos[1] -= el.ownerDocument.body.offsetTop; 1037 } 1038 parentNode = el.parentNode; 1039 1040 // account for any scrolled ancestors 1041 while ( parentNode.tagName && !patterns.ROOT_TAG.test(parentNode.tagName) ) 1042 { 1043 if (parentNode.scrollTop || parentNode.scrollLeft) { 1044 pos[0] -= parentNode.scrollLeft; 1045 pos[1] -= parentNode.scrollTop; 1046 } 1047 1048 parentNode = parentNode.parentNode; 1049 } 1050 1051 return pos; 1052 }; 1053 } 1054 }() // NOTE: Executing for loadtime branching 1055 })(); 1056 /** 1057 * A region is a representation of an object on a grid. It is defined 1058 * by the top, right, bottom, left extents, so is rectangular by default. If 1059 * other shapes are required, this class could be extended to support it. 1060 * @namespace YAHOO.util 1061 * @class Region 1062 * @param {Int} t the top extent 1063 * @param {Int} r the right extent 1064 * @param {Int} b the bottom extent 1065 * @param {Int} l the left extent 1066 * @constructor 1067 */ 1068 YAHOO.util.Region = function(t, r, b, l) { 1069 1070 /** 1071 * The region's top extent 1072 * @property top 1073 * @type Int 1074 */ 1075 this.top = t; 1076 1077 /** 1078 * The region's top extent as index, for symmetry with set/getXY 1079 * @property 1 1080 * @type Int 1081 */ 1082 this[1] = t; 1083 1084 /** 1085 * The region's right extent 1086 * @property right 1087 * @type int 1088 */ 1089 this.right = r; 1090 1091 /** 1092 * The region's bottom extent 1093 * @property bottom 1094 * @type Int 1095 */ 1096 this.bottom = b; 1097 1098 /** 1099 * The region's left extent 1100 * @property left 1101 * @type Int 1102 */ 1103 this.left = l; 1104 1105 /** 1106 * The region's left extent as index, for symmetry with set/getXY 1107 * @property 0 1108 * @type Int 1109 */ 1110 this[0] = l; 1111 }; 1112 1113 /** 1114 * Returns true if this region contains the region passed in 1115 * @method contains 1116 * @param {Region} region The region to evaluate 1117 * @return {Boolean} True if the region is contained with this region, 1118 * else false 1119 */ 1120 YAHOO.util.Region.prototype.contains = function(region) { 1121 return ( region.left >= this.left && 1122 region.right <= this.right && 1123 region.top >= this.top && 1124 region.bottom <= this.bottom ); 1125 1126 }; 1127 1128 /** 1129 * Returns the area of the region 1130 * @method getArea 1131 * @return {Int} the region's area 1132 */ 1133 YAHOO.util.Region.prototype.getArea = function() { 1134 return ( (this.bottom - this.top) * (this.right - this.left) ); 1135 }; 1136 1137 /** 1138 * Returns the region where the passed in region overlaps with this one 1139 * @method intersect 1140 * @param {Region} region The region that intersects 1141 * @return {Region} The overlap region, or null if there is no overlap 1142 */ 1143 YAHOO.util.Region.prototype.intersect = function(region) { 1144 var t = Math.max( this.top, region.top ); 1145 var r = Math.min( this.right, region.right ); 1146 var b = Math.min( this.bottom, region.bottom ); 1147 var l = Math.max( this.left, region.left ); 1148 1149 if (b >= t && r >= l) { 1150 return new YAHOO.util.Region(t, r, b, l); 1151 } else { 1152 return null; 1153 } 1154 }; 1155 1156 /** 1157 * Returns the region representing the smallest region that can contain both 1158 * the passed in region and this region. 1159 * @method union 1160 * @param {Region} region The region that to create the union with 1161 * @return {Region} The union region 1162 */ 1163 YAHOO.util.Region.prototype.union = function(region) { 1164 var t = Math.min( this.top, region.top ); 1165 var r = Math.max( this.right, region.right ); 1166 var b = Math.max( this.bottom, region.bottom ); 1167 var l = Math.min( this.left, region.left ); 1168 1169 return new YAHOO.util.Region(t, r, b, l); 1170 }; 1171 1172 /** 1173 * toString 1174 * @method toString 1175 * @return string the region properties 1176 */ 1177 YAHOO.util.Region.prototype.toString = function() { 1178 return ( "Region {" + 1179 "top: " + this.top + 1180 ", right: " + this.right + 1181 ", bottom: " + this.bottom + 1182 ", left: " + this.left + 1183 "}" ); 1184 }; 1185 1186 /** 1187 * Returns a region that is occupied by the DOM element 1188 * @method getRegion 1189 * @param {HTMLElement} el The element 1190 * @return {Region} The region that the element occupies 1191 * @static 1192 */ 1193 YAHOO.util.Region.getRegion = function(el) { 1194 var p = YAHOO.util.Dom.getXY(el); 1195 1196 var t = p[1]; 1197 var r = p[0] + el.offsetWidth; 1198 var b = p[1] + el.offsetHeight; 1199 var l = p[0]; 1200 1201 return new YAHOO.util.Region(t, r, b, l); 1202 }; 1203 1204 ///////////////////////////////////////////////////////////////////////////// 1205 1206 1207 /** 1208 * A point is a region that is special in that it represents a single point on 1209 * the grid. 1210 * @namespace YAHOO.util 1211 * @class Point 1212 * @param {Int} x The X position of the point 1213 * @param {Int} y The Y position of the point 1214 * @constructor 1215 * @extends YAHOO.util.Region 1216 */ 1217 YAHOO.util.Point = function(x, y) { 1218 if (YAHOO.lang.isArray(x)) { // accept input from Dom.getXY, Event.getXY, etc. 1219 y = x[1]; // dont blow away x yet 1220 x = x[0]; 1221 } 1222 1223 /** 1224 * The X position of the point, which is also the right, left and index zero (for Dom.getXY symmetry) 1225 * @property x 1226 * @type Int 1227 */ 1228 1229 this.x = this.right = this.left = this[0] = x; 1230 1231 /** 1232 * The Y position of the point, which is also the top, bottom and index one (for Dom.getXY symmetry) 1233 * @property y 1234 * @type Int 1235 */ 1236 this.y = this.top = this.bottom = this[1] = y; 1237 }; 1238 1239 YAHOO.util.Point.prototype = new YAHOO.util.Region(); 1240 1241 YAHOO.register("dom", YAHOO.util.Dom, {version: "2.6.0", build: "1321"});
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Wed Jan 14 11:33:29 2009 | Cross-referenced by PHPXref 0.7 |