[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
1 YUI.add('yui2-dom', function(Y) { 2 var YAHOO = Y.YUI2; 3 /* 4 Copyright (c) 2011, Yahoo! Inc. All rights reserved. 5 Code licensed under the BSD License: 6 http://developer.yahoo.com/yui/license.html 7 version: 2.9.0 8 */ 9 /** 10 * The dom module provides helper methods for manipulating Dom elements. 11 * @module dom 12 * 13 */ 14 15 (function() { 16 // for use with generateId (global to save state if Dom is overwritten) 17 YAHOO.env._id_counter = YAHOO.env._id_counter || 0; 18 19 // internal shorthand 20 var Y = YAHOO.util, 21 lang = YAHOO.lang, 22 UA = YAHOO.env.ua, 23 trim = YAHOO.lang.trim, 24 propertyCache = {}, // for faster hyphen converts 25 reCache = {}, // cache className regexes 26 RE_TABLE = /^t(?:able|d|h)$/i, // for _calcBorders 27 RE_COLOR = /color$/i, 28 29 // DOM aliases 30 document = window.document, 31 documentElement = document.documentElement, 32 33 // string constants 34 OWNER_DOCUMENT = 'ownerDocument', 35 DEFAULT_VIEW = 'defaultView', 36 DOCUMENT_ELEMENT = 'documentElement', 37 COMPAT_MODE = 'compatMode', 38 OFFSET_LEFT = 'offsetLeft', 39 OFFSET_TOP = 'offsetTop', 40 OFFSET_PARENT = 'offsetParent', 41 PARENT_NODE = 'parentNode', 42 NODE_TYPE = 'nodeType', 43 TAG_NAME = 'tagName', 44 SCROLL_LEFT = 'scrollLeft', 45 SCROLL_TOP = 'scrollTop', 46 GET_BOUNDING_CLIENT_RECT = 'getBoundingClientRect', 47 GET_COMPUTED_STYLE = 'getComputedStyle', 48 CURRENT_STYLE = 'currentStyle', 49 CSS1_COMPAT = 'CSS1Compat', 50 _BACK_COMPAT = 'BackCompat', 51 _CLASS = 'class', // underscore due to reserved word 52 CLASS_NAME = 'className', 53 EMPTY = '', 54 SPACE = ' ', 55 C_START = '(?:^|\\s)', 56 C_END = '(?= |$)', 57 G = 'g', 58 POSITION = 'position', 59 FIXED = 'fixed', 60 RELATIVE = 'relative', 61 LEFT = 'left', 62 TOP = 'top', 63 MEDIUM = 'medium', 64 BORDER_LEFT_WIDTH = 'borderLeftWidth', 65 BORDER_TOP_WIDTH = 'borderTopWidth', 66 67 // brower detection 68 isOpera = UA.opera, 69 isSafari = UA.webkit, 70 isGecko = UA.gecko, 71 isIE = UA.ie; 72 73 /** 74 * Provides helper methods for DOM elements. 75 * @namespace YAHOO.util 76 * @class Dom 77 * @requires yahoo, event 78 */ 79 Y.Dom = { 80 CUSTOM_ATTRIBUTES: (!documentElement.hasAttribute) ? { // IE < 8 81 'for': 'htmlFor', 82 'class': CLASS_NAME 83 } : { // w3c 84 'htmlFor': 'for', 85 'className': _CLASS 86 }, 87 88 DOT_ATTRIBUTES: { 89 checked: true 90 }, 91 92 /** 93 * Returns an HTMLElement reference. 94 * @method get 95 * @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. 96 * @return {HTMLElement | Array} A DOM reference to an HTML element or an array of HTMLElements. 97 */ 98 get: function(el) { 99 var id, nodes, c, i, len, attr, ret = null; 100 101 if (el) { 102 if (typeof el == 'string' || typeof el == 'number') { // id 103 id = el + ''; 104 el = document.getElementById(el); 105 attr = (el) ? el.attributes : null; 106 if (el && attr && attr.id && attr.id.value === id) { // IE: avoid false match on "name" attribute 107 return el; 108 } else if (el && document.all) { // filter by name 109 el = null; 110 nodes = document.all[id]; 111 if (nodes && nodes.length) { 112 for (i = 0, len = nodes.length; i < len; ++i) { 113 if (nodes[i].id === id) { 114 return nodes[i]; 115 } 116 } 117 } 118 } 119 } else if (Y.Element && el instanceof Y.Element) { 120 el = el.get('element'); 121 } else if (!el.nodeType && 'length' in el) { // array-like 122 c = []; 123 for (i = 0, len = el.length; i < len; ++i) { 124 c[c.length] = Y.Dom.get(el[i]); 125 } 126 127 el = c; 128 } 129 130 ret = el; 131 } 132 133 return ret; 134 }, 135 136 getComputedStyle: function(el, property) { 137 if (window[GET_COMPUTED_STYLE]) { 138 return el[OWNER_DOCUMENT][DEFAULT_VIEW][GET_COMPUTED_STYLE](el, null)[property]; 139 } else if (el[CURRENT_STYLE]) { 140 return Y.Dom.IE_ComputedStyle.get(el, property); 141 } 142 }, 143 144 /** 145 * Normalizes currentStyle and ComputedStyle. 146 * @method getStyle 147 * @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. 148 * @param {String} property The style property whose value is returned. 149 * @return {String | Array} The current value of the style property for the element(s). 150 */ 151 getStyle: function(el, property) { 152 return Y.Dom.batch(el, Y.Dom._getStyle, property); 153 }, 154 155 // branching at load instead of runtime 156 _getStyle: function() { 157 if (window[GET_COMPUTED_STYLE]) { // W3C DOM method 158 return function(el, property) { 159 property = (property === 'float') ? property = 'cssFloat' : 160 Y.Dom._toCamel(property); 161 162 var value = el.style[property], 163 computed; 164 165 if (!value) { 166 computed = el[OWNER_DOCUMENT][DEFAULT_VIEW][GET_COMPUTED_STYLE](el, null); 167 if (computed) { // test computed before touching for safari 168 value = computed[property]; 169 } 170 } 171 172 return value; 173 }; 174 } else if (documentElement[CURRENT_STYLE]) { 175 return function(el, property) { 176 var value; 177 178 switch(property) { 179 case 'opacity' :// IE opacity uses filter 180 value = 100; 181 try { // will error if no DXImageTransform 182 value = el.filters['DXImageTransform.Microsoft.Alpha'].opacity; 183 184 } catch(e) { 185 try { // make sure its in the document 186 value = el.filters('alpha').opacity; 187 } catch(err) { 188 } 189 } 190 return value / 100; 191 case 'float': // fix reserved word 192 property = 'styleFloat'; // fall through 193 default: 194 property = Y.Dom._toCamel(property); 195 value = el[CURRENT_STYLE] ? el[CURRENT_STYLE][property] : null; 196 return ( el.style[property] || value ); 197 } 198 }; 199 } 200 }(), 201 202 /** 203 * Wrapper for setting style properties of HTMLElements. Normalizes "opacity" across modern browsers. 204 * @method setStyle 205 * @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. 206 * @param {String} property The style property to be set. 207 * @param {String} val The value to apply to the given property. 208 */ 209 setStyle: function(el, property, val) { 210 Y.Dom.batch(el, Y.Dom._setStyle, { prop: property, val: val }); 211 }, 212 213 _setStyle: function() { 214 if (!window.getComputedStyle && document.documentElement.currentStyle) { 215 return function(el, args) { 216 var property = Y.Dom._toCamel(args.prop), 217 val = args.val; 218 219 if (el) { 220 switch (property) { 221 case 'opacity': 222 // remove filter if unsetting or full opacity 223 if (val === '' || val === null || val === 1) { 224 el.style.removeAttribute('filter'); 225 } else if ( lang.isString(el.style.filter) ) { // in case not appended 226 el.style.filter = 'alpha(opacity=' + val * 100 + ')'; 227 228 if (!el[CURRENT_STYLE] || !el[CURRENT_STYLE].hasLayout) { 229 el.style.zoom = 1; // when no layout or cant tell 230 } 231 } 232 break; 233 case 'float': 234 property = 'styleFloat'; 235 default: 236 el.style[property] = val; 237 } 238 } else { 239 } 240 }; 241 } else { 242 return function(el, args) { 243 var property = Y.Dom._toCamel(args.prop), 244 val = args.val; 245 if (el) { 246 if (property == 'float') { 247 property = 'cssFloat'; 248 } 249 el.style[property] = val; 250 } else { 251 } 252 }; 253 } 254 255 }(), 256 257 /** 258 * Gets the current position of an element based on page coordinates. 259 * Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false). 260 * @method getXY 261 * @param {String | HTMLElement | Array} el Accepts a string to use as an ID, an actual DOM 262 * reference, or an Array of IDs and/or HTMLElements 263 * @return {Array} The XY position of the element(s) 264 */ 265 getXY: function(el) { 266 return Y.Dom.batch(el, Y.Dom._getXY); 267 }, 268 269 _canPosition: function(el) { 270 return ( Y.Dom._getStyle(el, 'display') !== 'none' && Y.Dom._inDoc(el) ); 271 }, 272 273 _getXY: function(node) { 274 var scrollLeft, scrollTop, box, doc, 275 clientTop, clientLeft, 276 round = Math.round, // TODO: round? 277 xy = false; 278 279 if (Y.Dom._canPosition(node)) { 280 box = node[GET_BOUNDING_CLIENT_RECT](); 281 doc = node[OWNER_DOCUMENT]; 282 scrollLeft = Y.Dom.getDocumentScrollLeft(doc); 283 scrollTop = Y.Dom.getDocumentScrollTop(doc); 284 xy = [box[LEFT], box[TOP]]; 285 286 // remove IE default documentElement offset (border) 287 if (clientTop || clientLeft) { 288 xy[0] -= clientLeft; 289 xy[1] -= clientTop; 290 } 291 292 if ((scrollTop || scrollLeft)) { 293 xy[0] += scrollLeft; 294 xy[1] += scrollTop; 295 } 296 297 // gecko may return sub-pixel (non-int) values 298 xy[0] = round(xy[0]); 299 xy[1] = round(xy[1]); 300 } else { 301 } 302 303 return xy; 304 }, 305 306 /** 307 * 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). 308 * @method getX 309 * @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 310 * @return {Number | Array} The X position of the element(s) 311 */ 312 getX: function(el) { 313 var f = function(el) { 314 return Y.Dom.getXY(el)[0]; 315 }; 316 317 return Y.Dom.batch(el, f, Y.Dom, true); 318 }, 319 320 /** 321 * 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). 322 * @method getY 323 * @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 324 * @return {Number | Array} The Y position of the element(s) 325 */ 326 getY: function(el) { 327 var f = function(el) { 328 return Y.Dom.getXY(el)[1]; 329 }; 330 331 return Y.Dom.batch(el, f, Y.Dom, true); 332 }, 333 334 /** 335 * Set the position of an html element in page coordinates, regardless of how the element is positioned. 336 * The element(s) must be part of the DOM tree to have page coordinates (display:none or elements not appended return false). 337 * @method setXY 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 * @param {Array} pos Contains X & Y values for new position (coordinates are page-based) 340 * @param {Boolean} noRetry By default we try and set the position a second time if the first fails 341 */ 342 setXY: function(el, pos, noRetry) { 343 Y.Dom.batch(el, Y.Dom._setXY, { pos: pos, noRetry: noRetry }); 344 }, 345 346 _setXY: function(node, args) { 347 var pos = Y.Dom._getStyle(node, POSITION), 348 setStyle = Y.Dom.setStyle, 349 xy = args.pos, 350 noRetry = args.noRetry, 351 352 delta = [ // assuming pixels; if not we will have to retry 353 parseInt( Y.Dom.getComputedStyle(node, LEFT), 10 ), 354 parseInt( Y.Dom.getComputedStyle(node, TOP), 10 ) 355 ], 356 357 currentXY, 358 newXY; 359 360 currentXY = Y.Dom._getXY(node); 361 362 if (!xy || currentXY === false) { // has to be part of doc to have xy 363 return false; 364 } 365 366 if (pos == 'static') { // default to relative 367 pos = RELATIVE; 368 setStyle(node, POSITION, pos); 369 } 370 371 if ( isNaN(delta[0]) ) {// in case of 'auto' 372 delta[0] = (pos == RELATIVE) ? 0 : node[OFFSET_LEFT]; 373 } 374 if ( isNaN(delta[1]) ) { // in case of 'auto' 375 delta[1] = (pos == RELATIVE) ? 0 : node[OFFSET_TOP]; 376 } 377 378 if (xy[0] !== null) { // from setX 379 setStyle(node, LEFT, xy[0] - currentXY[0] + delta[0] + 'px'); 380 } 381 382 if (xy[1] !== null) { // from setY 383 setStyle(node, TOP, xy[1] - currentXY[1] + delta[1] + 'px'); 384 } 385 386 if (!noRetry) { 387 newXY = Y.Dom._getXY(node); 388 389 // if retry is true, try one more time if we miss 390 if ( (xy[0] !== null && newXY[0] != xy[0]) || 391 (xy[1] !== null && newXY[1] != xy[1]) ) { 392 Y.Dom._setXY(node, { pos: xy, noRetry: true }); 393 } 394 } 395 396 }, 397 398 /** 399 * Set the X position of an html element in page coordinates, regardless of how the element is positioned. 400 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false). 401 * @method setX 402 * @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. 403 * @param {Int} x The value to use as the X coordinate for the element(s). 404 */ 405 setX: function(el, x) { 406 Y.Dom.setXY(el, [x, null]); 407 }, 408 409 /** 410 * Set the Y position of an html element in page coordinates, regardless of how the element is positioned. 411 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false). 412 * @method setY 413 * @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. 414 * @param {Int} x To use as the Y coordinate for the element(s). 415 */ 416 setY: function(el, y) { 417 Y.Dom.setXY(el, [null, y]); 418 }, 419 420 /** 421 * Returns the region position of the given element. 422 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false). 423 * @method getRegion 424 * @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. 425 * @return {Region | Array} A Region or array of Region instances containing "top, left, bottom, right" member data. 426 */ 427 getRegion: function(el) { 428 var f = function(el) { 429 var region = false; 430 if ( Y.Dom._canPosition(el) ) { 431 region = Y.Region.getRegion(el); 432 } else { 433 } 434 435 return region; 436 }; 437 438 return Y.Dom.batch(el, f, Y.Dom, true); 439 }, 440 441 /** 442 * Returns the width of the client (viewport). 443 * @method getClientWidth 444 * @deprecated Now using getViewportWidth. This interface left intact for back compat. 445 * @return {Int} The width of the viewable area of the page. 446 */ 447 getClientWidth: function() { 448 return Y.Dom.getViewportWidth(); 449 }, 450 451 /** 452 * Returns the height of the client (viewport). 453 * @method getClientHeight 454 * @deprecated Now using getViewportHeight. This interface left intact for back compat. 455 * @return {Int} The height of the viewable area of the page. 456 */ 457 getClientHeight: function() { 458 return Y.Dom.getViewportHeight(); 459 }, 460 461 /** 462 * Returns an array of HTMLElements with the given class. 463 * For optimized performance, include a tag and/or root node when possible. 464 * Note: This method operates against a live collection, so modifying the 465 * collection in the callback (removing/appending nodes, etc.) will have 466 * side effects. Instead you should iterate the returned nodes array, 467 * as you would with the native "getElementsByTagName" method. 468 * @method getElementsByClassName 469 * @param {String} className The class name to match against 470 * @param {String} tag (optional) The tag name of the elements being collected 471 * @param {String | HTMLElement} root (optional) The HTMLElement or an ID to use as the starting point. 472 * This element is not included in the className scan. 473 * @param {Function} apply (optional) A function to apply to each element when found 474 * @param {Any} o (optional) An optional arg that is passed to the supplied method 475 * @param {Boolean} overrides (optional) Whether or not to override the scope of "method" with "o" 476 * @return {Array} An array of elements that have the given class name 477 */ 478 getElementsByClassName: function(className, tag, root, apply, o, overrides) { 479 tag = tag || '*'; 480 root = (root) ? Y.Dom.get(root) : null || document; 481 if (!root) { 482 return []; 483 } 484 485 var nodes = [], 486 elements = root.getElementsByTagName(tag), 487 hasClass = Y.Dom.hasClass; 488 489 for (var i = 0, len = elements.length; i < len; ++i) { 490 if ( hasClass(elements[i], className) ) { 491 nodes[nodes.length] = elements[i]; 492 } 493 } 494 495 if (apply) { 496 Y.Dom.batch(nodes, apply, o, overrides); 497 } 498 499 return nodes; 500 }, 501 502 /** 503 * Determines whether an HTMLElement has the given className. 504 * @method hasClass 505 * @param {String | HTMLElement | Array} el The element or collection to test 506 * @param {String | RegExp} className the class name to search for, or a regular 507 * expression to match against 508 * @return {Boolean | Array} A boolean value or array of boolean values 509 */ 510 hasClass: function(el, className) { 511 return Y.Dom.batch(el, Y.Dom._hasClass, className); 512 }, 513 514 _hasClass: function(el, className) { 515 var ret = false, 516 current; 517 518 if (el && className) { 519 current = Y.Dom._getAttribute(el, CLASS_NAME) || EMPTY; 520 if (current) { // convert line breaks, tabs and other delims to spaces 521 current = current.replace(/\s+/g, SPACE); 522 } 523 524 if (className.exec) { 525 ret = className.test(current); 526 } else { 527 ret = className && (SPACE + current + SPACE). 528 indexOf(SPACE + className + SPACE) > -1; 529 } 530 } else { 531 } 532 533 return ret; 534 }, 535 536 /** 537 * Adds a class name to a given element or collection of elements. 538 * @method addClass 539 * @param {String | HTMLElement | Array} el The element or collection to add the class to 540 * @param {String} className the class name to add to the class attribute 541 * @return {Boolean | Array} A pass/fail boolean or array of booleans 542 */ 543 addClass: function(el, className) { 544 return Y.Dom.batch(el, Y.Dom._addClass, className); 545 }, 546 547 _addClass: function(el, className) { 548 var ret = false, 549 current; 550 551 if (el && className) { 552 current = Y.Dom._getAttribute(el, CLASS_NAME) || EMPTY; 553 if ( !Y.Dom._hasClass(el, className) ) { 554 Y.Dom.setAttribute(el, CLASS_NAME, trim(current + SPACE + className)); 555 ret = true; 556 } 557 } else { 558 } 559 560 return ret; 561 }, 562 563 /** 564 * Removes a class name from a given element or collection of elements. 565 * @method removeClass 566 * @param {String | HTMLElement | Array} el The element or collection to remove the class from 567 * @param {String} className the class name to remove from the class attribute 568 * @return {Boolean | Array} A pass/fail boolean or array of booleans 569 */ 570 removeClass: function(el, className) { 571 return Y.Dom.batch(el, Y.Dom._removeClass, className); 572 }, 573 574 _removeClass: function(el, className) { 575 var ret = false, 576 current, 577 newClass, 578 attr; 579 580 if (el && className) { 581 current = Y.Dom._getAttribute(el, CLASS_NAME) || EMPTY; 582 Y.Dom.setAttribute(el, CLASS_NAME, current.replace(Y.Dom._getClassRegex(className), EMPTY)); 583 584 newClass = Y.Dom._getAttribute(el, CLASS_NAME); 585 if (current !== newClass) { // else nothing changed 586 Y.Dom.setAttribute(el, CLASS_NAME, trim(newClass)); // trim after comparing to current class 587 ret = true; 588 589 if (Y.Dom._getAttribute(el, CLASS_NAME) === '') { // remove class attribute if empty 590 attr = (el.hasAttribute && el.hasAttribute(_CLASS)) ? _CLASS : CLASS_NAME; 591 el.removeAttribute(attr); 592 } 593 } 594 595 } else { 596 } 597 598 return ret; 599 }, 600 601 /** 602 * Replace a class with another class for a given element or collection of elements. 603 * If no oldClassName is present, the newClassName is simply added. 604 * @method replaceClass 605 * @param {String | HTMLElement | Array} el The element or collection to remove the class from 606 * @param {String} oldClassName the class name to be replaced 607 * @param {String} newClassName the class name that will be replacing the old class name 608 * @return {Boolean | Array} A pass/fail boolean or array of booleans 609 */ 610 replaceClass: function(el, oldClassName, newClassName) { 611 return Y.Dom.batch(el, Y.Dom._replaceClass, { from: oldClassName, to: newClassName }); 612 }, 613 614 _replaceClass: function(el, classObj) { 615 var className, 616 from, 617 to, 618 ret = false, 619 current; 620 621 if (el && classObj) { 622 from = classObj.from; 623 to = classObj.to; 624 625 if (!to) { 626 ret = false; 627 } else if (!from) { // just add if no "from" 628 ret = Y.Dom._addClass(el, classObj.to); 629 } else if (from !== to) { // else nothing to replace 630 // May need to lead with DBLSPACE? 631 current = Y.Dom._getAttribute(el, CLASS_NAME) || EMPTY; 632 className = (SPACE + current.replace(Y.Dom._getClassRegex(from), SPACE + to). 633 replace(/\s+/g, SPACE)). // normalize white space 634 split(Y.Dom._getClassRegex(to)); 635 636 // insert to into what would have been the first occurrence slot 637 className.splice(1, 0, SPACE + to); 638 Y.Dom.setAttribute(el, CLASS_NAME, trim(className.join(EMPTY))); 639 ret = true; 640 } 641 } else { 642 } 643 644 return ret; 645 }, 646 647 /** 648 * Returns an ID and applies it to the element "el", if provided. 649 * @method generateId 650 * @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). 651 * @param {String} prefix (optional) an optional prefix to use (defaults to "yui-gen"). 652 * @return {String | Array} The generated ID, or array of generated IDs (or original ID if already present on an element) 653 */ 654 generateId: function(el, prefix) { 655 prefix = prefix || 'yui-gen'; 656 657 var f = function(el) { 658 if (el && el.id) { // do not override existing ID 659 return el.id; 660 } 661 662 var id = prefix + YAHOO.env._id_counter++; 663 664 if (el) { 665 if (el[OWNER_DOCUMENT] && el[OWNER_DOCUMENT].getElementById(id)) { // in case one already exists 666 // use failed id plus prefix to help ensure uniqueness 667 return Y.Dom.generateId(el, id + prefix); 668 } 669 el.id = id; 670 } 671 672 return id; 673 }; 674 675 // batch fails when no element, so just generate and return single ID 676 return Y.Dom.batch(el, f, Y.Dom, true) || f.apply(Y.Dom, arguments); 677 }, 678 679 /** 680 * Determines whether an HTMLElement is an ancestor of another HTML element in the DOM hierarchy. 681 * @method isAncestor 682 * @param {String | HTMLElement} haystack The possible ancestor 683 * @param {String | HTMLElement} needle The possible descendent 684 * @return {Boolean} Whether or not the haystack is an ancestor of needle 685 */ 686 isAncestor: function(haystack, needle) { 687 haystack = Y.Dom.get(haystack); 688 needle = Y.Dom.get(needle); 689 690 var ret = false; 691 692 if ( (haystack && needle) && (haystack[NODE_TYPE] && needle[NODE_TYPE]) ) { 693 if (haystack.contains && haystack !== needle) { // contains returns true when equal 694 ret = haystack.contains(needle); 695 } 696 else if (haystack.compareDocumentPosition) { // gecko 697 ret = !!(haystack.compareDocumentPosition(needle) & 16); 698 } 699 } else { 700 } 701 return ret; 702 }, 703 704 /** 705 * Determines whether an HTMLElement is present in the current document. 706 * @method inDocument 707 * @param {String | HTMLElement} el The element to search for 708 * @param {Object} doc An optional document to search, defaults to element's owner document 709 * @return {Boolean} Whether or not the element is present in the current document 710 */ 711 inDocument: function(el, doc) { 712 return Y.Dom._inDoc(Y.Dom.get(el), doc); 713 }, 714 715 _inDoc: function(el, doc) { 716 var ret = false; 717 if (el && el[TAG_NAME]) { 718 doc = doc || el[OWNER_DOCUMENT]; 719 ret = Y.Dom.isAncestor(doc[DOCUMENT_ELEMENT], el); 720 } else { 721 } 722 return ret; 723 }, 724 725 /** 726 * Returns an array of HTMLElements that pass the test applied by supplied boolean method. 727 * For optimized performance, include a tag and/or root node when possible. 728 * Note: This method operates against a live collection, so modifying the 729 * collection in the callback (removing/appending nodes, etc.) will have 730 * side effects. Instead you should iterate the returned nodes array, 731 * as you would with the native "getElementsByTagName" method. 732 * @method getElementsBy 733 * @param {Function} method - A boolean method for testing elements which receives the element as its only argument. 734 * @param {String} tag (optional) The tag name of the elements being collected 735 * @param {String | HTMLElement} root (optional) The HTMLElement or an ID to use as the starting point 736 * @param {Function} apply (optional) A function to apply to each element when found 737 * @param {Any} o (optional) An optional arg that is passed to the supplied method 738 * @param {Boolean} overrides (optional) Whether or not to override the scope of "method" with "o" 739 * @return {Array} Array of HTMLElements 740 */ 741 getElementsBy: function(method, tag, root, apply, o, overrides, firstOnly) { 742 tag = tag || '*'; 743 root = (root) ? Y.Dom.get(root) : null || document; 744 745 var ret = (firstOnly) ? null : [], 746 elements; 747 748 // in case Dom.get() returns null 749 if (root) { 750 elements = root.getElementsByTagName(tag); 751 for (var i = 0, len = elements.length; i < len; ++i) { 752 if ( method(elements[i]) ) { 753 if (firstOnly) { 754 ret = elements[i]; 755 break; 756 } else { 757 ret[ret.length] = elements[i]; 758 } 759 } 760 } 761 762 if (apply) { 763 Y.Dom.batch(ret, apply, o, overrides); 764 } 765 } 766 767 768 return ret; 769 }, 770 771 /** 772 * Returns the first HTMLElement that passes the test applied by the supplied boolean method. 773 * @method getElementBy 774 * @param {Function} method - A boolean method for testing elements which receives the element as its only argument. 775 * @param {String} tag (optional) The tag name of the elements being collected 776 * @param {String | HTMLElement} root (optional) The HTMLElement or an ID to use as the starting point 777 * @return {HTMLElement} 778 */ 779 getElementBy: function(method, tag, root) { 780 return Y.Dom.getElementsBy(method, tag, root, null, null, null, true); 781 }, 782 783 /** 784 * Runs the supplied method against each item in the Collection/Array. 785 * The method is called with the element(s) as the first arg, and the optional param as the second ( method(el, o) ). 786 * @method batch 787 * @param {String | HTMLElement | Array} el (optional) An element or array of elements to apply the method to 788 * @param {Function} method The method to apply to the element(s) 789 * @param {Any} o (optional) An optional arg that is passed to the supplied method 790 * @param {Boolean} overrides (optional) Whether or not to override the scope of "method" with "o" 791 * @return {Any | Array} The return value(s) from the supplied method 792 */ 793 batch: function(el, method, o, overrides) { 794 var collection = [], 795 scope = (overrides) ? o : null; 796 797 el = (el && (el[TAG_NAME] || el.item)) ? el : Y.Dom.get(el); // skip get() when possible 798 if (el && method) { 799 if (el[TAG_NAME] || el.length === undefined) { // element or not array-like 800 return method.call(scope, el, o); 801 } 802 803 for (var i = 0; i < el.length; ++i) { 804 collection[collection.length] = method.call(scope || el[i], el[i], o); 805 } 806 } else { 807 return false; 808 } 809 return collection; 810 }, 811 812 /** 813 * Returns the height of the document. 814 * @method getDocumentHeight 815 * @return {Int} The height of the actual document (which includes the body and its margin). 816 */ 817 getDocumentHeight: function() { 818 var scrollHeight = (document[COMPAT_MODE] != CSS1_COMPAT || isSafari) ? document.body.scrollHeight : documentElement.scrollHeight, 819 h = Math.max(scrollHeight, Y.Dom.getViewportHeight()); 820 821 return h; 822 }, 823 824 /** 825 * Returns the width of the document. 826 * @method getDocumentWidth 827 * @return {Int} The width of the actual document (which includes the body and its margin). 828 */ 829 getDocumentWidth: function() { 830 var scrollWidth = (document[COMPAT_MODE] != CSS1_COMPAT || isSafari) ? document.body.scrollWidth : documentElement.scrollWidth, 831 w = Math.max(scrollWidth, Y.Dom.getViewportWidth()); 832 return w; 833 }, 834 835 /** 836 * Returns the current height of the viewport. 837 * @method getViewportHeight 838 * @return {Int} The height of the viewable area of the page (excludes scrollbars). 839 */ 840 getViewportHeight: function() { 841 var height = self.innerHeight, // Safari, Opera 842 mode = document[COMPAT_MODE]; 843 844 if ( (mode || isIE) && !isOpera ) { // IE, Gecko 845 height = (mode == CSS1_COMPAT) ? 846 documentElement.clientHeight : // Standards 847 document.body.clientHeight; // Quirks 848 } 849 850 return height; 851 }, 852 853 /** 854 * Returns the current width of the viewport. 855 * @method getViewportWidth 856 * @return {Int} The width of the viewable area of the page (excludes scrollbars). 857 */ 858 859 getViewportWidth: function() { 860 var width = self.innerWidth, // Safari 861 mode = document[COMPAT_MODE]; 862 863 if (mode || isIE) { // IE, Gecko, Opera 864 width = (mode == CSS1_COMPAT) ? 865 documentElement.clientWidth : // Standards 866 document.body.clientWidth; // Quirks 867 } 868 return width; 869 }, 870 871 /** 872 * Returns the nearest ancestor that passes the test applied by supplied boolean method. 873 * For performance reasons, IDs are not accepted and argument validation omitted. 874 * @method getAncestorBy 875 * @param {HTMLElement} node The HTMLElement to use as the starting point 876 * @param {Function} method - A boolean method for testing elements which receives the element as its only argument. 877 * @return {Object} HTMLElement or null if not found 878 */ 879 getAncestorBy: function(node, method) { 880 while ( (node = node[PARENT_NODE]) ) { // NOTE: assignment 881 if ( Y.Dom._testElement(node, method) ) { 882 return node; 883 } 884 } 885 886 return null; 887 }, 888 889 /** 890 * Returns the nearest ancestor with the given className. 891 * @method getAncestorByClassName 892 * @param {String | HTMLElement} node The HTMLElement or an ID to use as the starting point 893 * @param {String} className 894 * @return {Object} HTMLElement 895 */ 896 getAncestorByClassName: function(node, className) { 897 node = Y.Dom.get(node); 898 if (!node) { 899 return null; 900 } 901 var method = function(el) { return Y.Dom.hasClass(el, className); }; 902 return Y.Dom.getAncestorBy(node, method); 903 }, 904 905 /** 906 * Returns the nearest ancestor with the given tagName. 907 * @method getAncestorByTagName 908 * @param {String | HTMLElement} node The HTMLElement or an ID to use as the starting point 909 * @param {String} tagName 910 * @return {Object} HTMLElement 911 */ 912 getAncestorByTagName: function(node, tagName) { 913 node = Y.Dom.get(node); 914 if (!node) { 915 return null; 916 } 917 var method = function(el) { 918 return el[TAG_NAME] && el[TAG_NAME].toUpperCase() == tagName.toUpperCase(); 919 }; 920 921 return Y.Dom.getAncestorBy(node, method); 922 }, 923 924 /** 925 * Returns the previous sibling that is an HTMLElement. 926 * For performance reasons, IDs are not accepted and argument validation omitted. 927 * Returns the nearest HTMLElement sibling if no method provided. 928 * @method getPreviousSiblingBy 929 * @param {HTMLElement} node The HTMLElement to use as the starting point 930 * @param {Function} method A boolean function used to test siblings 931 * that receives the sibling node being tested as its only argument 932 * @return {Object} HTMLElement or null if not found 933 */ 934 getPreviousSiblingBy: function(node, method) { 935 while (node) { 936 node = node.previousSibling; 937 if ( Y.Dom._testElement(node, method) ) { 938 return node; 939 } 940 } 941 return null; 942 }, 943 944 /** 945 * Returns the previous sibling that is an HTMLElement 946 * @method getPreviousSibling 947 * @param {String | HTMLElement} node The HTMLElement or an ID to use as the starting point 948 * @return {Object} HTMLElement or null if not found 949 */ 950 getPreviousSibling: function(node) { 951 node = Y.Dom.get(node); 952 if (!node) { 953 return null; 954 } 955 956 return Y.Dom.getPreviousSiblingBy(node); 957 }, 958 959 /** 960 * Returns the next HTMLElement sibling that passes the boolean method. 961 * For performance reasons, IDs are not accepted and argument validation omitted. 962 * Returns the nearest HTMLElement sibling if no method provided. 963 * @method getNextSiblingBy 964 * @param {HTMLElement} node The HTMLElement to use as the starting point 965 * @param {Function} method A boolean function used to test siblings 966 * that receives the sibling node being tested as its only argument 967 * @return {Object} HTMLElement or null if not found 968 */ 969 getNextSiblingBy: function(node, method) { 970 while (node) { 971 node = node.nextSibling; 972 if ( Y.Dom._testElement(node, method) ) { 973 return node; 974 } 975 } 976 return null; 977 }, 978 979 /** 980 * Returns the next sibling that is an HTMLElement 981 * @method getNextSibling 982 * @param {String | HTMLElement} node The HTMLElement or an ID to use as the starting point 983 * @return {Object} HTMLElement or null if not found 984 */ 985 getNextSibling: function(node) { 986 node = Y.Dom.get(node); 987 if (!node) { 988 return null; 989 } 990 991 return Y.Dom.getNextSiblingBy(node); 992 }, 993 994 /** 995 * Returns the first HTMLElement child that passes the test method. 996 * @method getFirstChildBy 997 * @param {HTMLElement} node The HTMLElement to use as the starting point 998 * @param {Function} method A boolean function used to test children 999 * that receives the node being tested as its only argument 1000 * @return {Object} HTMLElement or null if not found 1001 */ 1002 getFirstChildBy: function(node, method) { 1003 var child = ( Y.Dom._testElement(node.firstChild, method) ) ? node.firstChild : null; 1004 return child || Y.Dom.getNextSiblingBy(node.firstChild, method); 1005 }, 1006 1007 /** 1008 * Returns the first HTMLElement child. 1009 * @method getFirstChild 1010 * @param {String | HTMLElement} node The HTMLElement or an ID to use as the starting point 1011 * @return {Object} HTMLElement or null if not found 1012 */ 1013 getFirstChild: function(node, method) { 1014 node = Y.Dom.get(node); 1015 if (!node) { 1016 return null; 1017 } 1018 return Y.Dom.getFirstChildBy(node); 1019 }, 1020 1021 /** 1022 * Returns the last HTMLElement child that passes the test method. 1023 * @method getLastChildBy 1024 * @param {HTMLElement} node The HTMLElement to use as the starting point 1025 * @param {Function} method A boolean function used to test children 1026 * that receives the node being tested as its only argument 1027 * @return {Object} HTMLElement or null if not found 1028 */ 1029 getLastChildBy: function(node, method) { 1030 if (!node) { 1031 return null; 1032 } 1033 var child = ( Y.Dom._testElement(node.lastChild, method) ) ? node.lastChild : null; 1034 return child || Y.Dom.getPreviousSiblingBy(node.lastChild, method); 1035 }, 1036 1037 /** 1038 * Returns the last HTMLElement child. 1039 * @method getLastChild 1040 * @param {String | HTMLElement} node The HTMLElement or an ID to use as the starting point 1041 * @return {Object} HTMLElement or null if not found 1042 */ 1043 getLastChild: function(node) { 1044 node = Y.Dom.get(node); 1045 return Y.Dom.getLastChildBy(node); 1046 }, 1047 1048 /** 1049 * Returns an array of HTMLElement childNodes that pass the test method. 1050 * @method getChildrenBy 1051 * @param {HTMLElement} node The HTMLElement to start from 1052 * @param {Function} method A boolean function used to test children 1053 * that receives the node being tested as its only argument 1054 * @return {Array} A static array of HTMLElements 1055 */ 1056 getChildrenBy: function(node, method) { 1057 var child = Y.Dom.getFirstChildBy(node, method), 1058 children = child ? [child] : []; 1059 1060 Y.Dom.getNextSiblingBy(child, function(node) { 1061 if ( !method || method(node) ) { 1062 children[children.length] = node; 1063 } 1064 return false; // fail test to collect all children 1065 }); 1066 1067 return children; 1068 }, 1069 1070 /** 1071 * Returns an array of HTMLElement childNodes. 1072 * @method getChildren 1073 * @param {String | HTMLElement} node The HTMLElement or an ID to use as the starting point 1074 * @return {Array} A static array of HTMLElements 1075 */ 1076 getChildren: function(node) { 1077 node = Y.Dom.get(node); 1078 if (!node) { 1079 } 1080 1081 return Y.Dom.getChildrenBy(node); 1082 }, 1083 1084 /** 1085 * Returns the left scroll value of the document 1086 * @method getDocumentScrollLeft 1087 * @param {HTMLDocument} document (optional) The document to get the scroll value of 1088 * @return {Int} The amount that the document is scrolled to the left 1089 */ 1090 getDocumentScrollLeft: function(doc) { 1091 doc = doc || document; 1092 return Math.max(doc[DOCUMENT_ELEMENT].scrollLeft, doc.body.scrollLeft); 1093 }, 1094 1095 /** 1096 * Returns the top scroll value of the document 1097 * @method getDocumentScrollTop 1098 * @param {HTMLDocument} document (optional) The document to get the scroll value of 1099 * @return {Int} The amount that the document is scrolled to the top 1100 */ 1101 getDocumentScrollTop: function(doc) { 1102 doc = doc || document; 1103 return Math.max(doc[DOCUMENT_ELEMENT].scrollTop, doc.body.scrollTop); 1104 }, 1105 1106 /** 1107 * Inserts the new node as the previous sibling of the reference node 1108 * @method insertBefore 1109 * @param {String | HTMLElement} newNode The node to be inserted 1110 * @param {String | HTMLElement} referenceNode The node to insert the new node before 1111 * @return {HTMLElement} The node that was inserted (or null if insert fails) 1112 */ 1113 insertBefore: function(newNode, referenceNode) { 1114 newNode = Y.Dom.get(newNode); 1115 referenceNode = Y.Dom.get(referenceNode); 1116 1117 if (!newNode || !referenceNode || !referenceNode[PARENT_NODE]) { 1118 return null; 1119 } 1120 1121 return referenceNode[PARENT_NODE].insertBefore(newNode, referenceNode); 1122 }, 1123 1124 /** 1125 * Inserts the new node as the next sibling of the reference node 1126 * @method insertAfter 1127 * @param {String | HTMLElement} newNode The node to be inserted 1128 * @param {String | HTMLElement} referenceNode The node to insert the new node after 1129 * @return {HTMLElement} The node that was inserted (or null if insert fails) 1130 */ 1131 insertAfter: function(newNode, referenceNode) { 1132 newNode = Y.Dom.get(newNode); 1133 referenceNode = Y.Dom.get(referenceNode); 1134 1135 if (!newNode || !referenceNode || !referenceNode[PARENT_NODE]) { 1136 return null; 1137 } 1138 1139 if (referenceNode.nextSibling) { 1140 return referenceNode[PARENT_NODE].insertBefore(newNode, referenceNode.nextSibling); 1141 } else { 1142 return referenceNode[PARENT_NODE].appendChild(newNode); 1143 } 1144 }, 1145 1146 /** 1147 * Creates a Region based on the viewport relative to the document. 1148 * @method getClientRegion 1149 * @return {Region} A Region object representing the viewport which accounts for document scroll 1150 */ 1151 getClientRegion: function() { 1152 var t = Y.Dom.getDocumentScrollTop(), 1153 l = Y.Dom.getDocumentScrollLeft(), 1154 r = Y.Dom.getViewportWidth() + l, 1155 b = Y.Dom.getViewportHeight() + t; 1156 1157 return new Y.Region(t, r, b, l); 1158 }, 1159 1160 /** 1161 * Provides a normalized attribute interface. 1162 * @method setAttribute 1163 * @param {String | HTMLElement} el The target element for the attribute. 1164 * @param {String} attr The attribute to set. 1165 * @param {String} val The value of the attribute. 1166 */ 1167 setAttribute: function(el, attr, val) { 1168 Y.Dom.batch(el, Y.Dom._setAttribute, { attr: attr, val: val }); 1169 }, 1170 1171 _setAttribute: function(el, args) { 1172 var attr = Y.Dom._toCamel(args.attr), 1173 val = args.val; 1174 1175 if (el && el.setAttribute) { 1176 // set as DOM property, except for BUTTON, which errors on property setter 1177 if (Y.Dom.DOT_ATTRIBUTES[attr] && el.tagName && el.tagName != 'BUTTON') { 1178 el[attr] = val; 1179 } else { 1180 attr = Y.Dom.CUSTOM_ATTRIBUTES[attr] || attr; 1181 el.setAttribute(attr, val); 1182 } 1183 } else { 1184 } 1185 }, 1186 1187 /** 1188 * Provides a normalized attribute interface. 1189 * @method getAttribute 1190 * @param {String | HTMLElement} el The target element for the attribute. 1191 * @param {String} attr The attribute to get. 1192 * @return {String} The current value of the attribute. 1193 */ 1194 getAttribute: function(el, attr) { 1195 return Y.Dom.batch(el, Y.Dom._getAttribute, attr); 1196 }, 1197 1198 1199 _getAttribute: function(el, attr) { 1200 var val; 1201 attr = Y.Dom.CUSTOM_ATTRIBUTES[attr] || attr; 1202 1203 if (Y.Dom.DOT_ATTRIBUTES[attr]) { 1204 val = el[attr]; 1205 } else if (el && 'getAttribute' in el) { 1206 if (/^(?:href|src)$/.test(attr)) { // use IE flag to return exact value 1207 val = el.getAttribute(attr, 2); 1208 } else { 1209 val = el.getAttribute(attr); 1210 } 1211 } else { 1212 } 1213 1214 return val; 1215 }, 1216 1217 _toCamel: function(property) { 1218 var c = propertyCache; 1219 1220 function tU(x,l) { 1221 return l.toUpperCase(); 1222 } 1223 1224 return c[property] || (c[property] = property.indexOf('-') === -1 ? 1225 property : 1226 property.replace( /-([a-z])/gi, tU )); 1227 }, 1228 1229 _getClassRegex: function(className) { 1230 var re; 1231 if (className !== undefined) { // allow empty string to pass 1232 if (className.exec) { // already a RegExp 1233 re = className; 1234 } else { 1235 re = reCache[className]; 1236 if (!re) { 1237 // escape special chars (".", "[", etc.) 1238 className = className.replace(Y.Dom._patterns.CLASS_RE_TOKENS, '\\$1'); 1239 className = className.replace(/\s+/g, SPACE); // convert line breaks and other delims 1240 re = reCache[className] = new RegExp(C_START + className + C_END, G); 1241 } 1242 } 1243 } 1244 return re; 1245 }, 1246 1247 _patterns: { 1248 ROOT_TAG: /^body|html$/i, // body for quirks mode, html for standards, 1249 CLASS_RE_TOKENS: /([\.\(\)\^\$\*\+\?\|\[\]\{\}\\])/g 1250 }, 1251 1252 1253 _testElement: function(node, method) { 1254 return node && node[NODE_TYPE] == 1 && ( !method || method(node) ); 1255 }, 1256 1257 _calcBorders: function(node, xy2) { 1258 var t = parseInt(Y.Dom[GET_COMPUTED_STYLE](node, BORDER_TOP_WIDTH), 10) || 0, 1259 l = parseInt(Y.Dom[GET_COMPUTED_STYLE](node, BORDER_LEFT_WIDTH), 10) || 0; 1260 if (isGecko) { 1261 if (RE_TABLE.test(node[TAG_NAME])) { 1262 t = 0; 1263 l = 0; 1264 } 1265 } 1266 xy2[0] += l; 1267 xy2[1] += t; 1268 return xy2; 1269 } 1270 }; 1271 1272 var _getComputedStyle = Y.Dom[GET_COMPUTED_STYLE]; 1273 // fix opera computedStyle default color unit (convert to rgb) 1274 if (UA.opera) { 1275 Y.Dom[GET_COMPUTED_STYLE] = function(node, att) { 1276 var val = _getComputedStyle(node, att); 1277 if (RE_COLOR.test(att)) { 1278 val = Y.Dom.Color.toRGB(val); 1279 } 1280 1281 return val; 1282 }; 1283 1284 } 1285 1286 // safari converts transparent to rgba(), others use "transparent" 1287 if (UA.webkit) { 1288 Y.Dom[GET_COMPUTED_STYLE] = function(node, att) { 1289 var val = _getComputedStyle(node, att); 1290 1291 if (val === 'rgba(0, 0, 0, 0)') { 1292 val = 'transparent'; 1293 } 1294 1295 return val; 1296 }; 1297 1298 } 1299 1300 if (UA.ie && UA.ie >= 8) { 1301 Y.Dom.DOT_ATTRIBUTES.type = true; // IE 8 errors on input.setAttribute('type') 1302 } 1303 })(); 1304 /** 1305 * A region is a representation of an object on a grid. It is defined 1306 * by the top, right, bottom, left extents, so is rectangular by default. If 1307 * other shapes are required, this class could be extended to support it. 1308 * @namespace YAHOO.util 1309 * @class Region 1310 * @param {Int} t the top extent 1311 * @param {Int} r the right extent 1312 * @param {Int} b the bottom extent 1313 * @param {Int} l the left extent 1314 * @constructor 1315 */ 1316 YAHOO.util.Region = function(t, r, b, l) { 1317 1318 /** 1319 * The region's top extent 1320 * @property top 1321 * @type Int 1322 */ 1323 this.top = t; 1324 1325 /** 1326 * The region's top extent 1327 * @property y 1328 * @type Int 1329 */ 1330 this.y = t; 1331 1332 /** 1333 * The region's top extent as index, for symmetry with set/getXY 1334 * @property 1 1335 * @type Int 1336 */ 1337 this[1] = t; 1338 1339 /** 1340 * The region's right extent 1341 * @property right 1342 * @type int 1343 */ 1344 this.right = r; 1345 1346 /** 1347 * The region's bottom extent 1348 * @property bottom 1349 * @type Int 1350 */ 1351 this.bottom = b; 1352 1353 /** 1354 * The region's left extent 1355 * @property left 1356 * @type Int 1357 */ 1358 this.left = l; 1359 1360 /** 1361 * The region's left extent 1362 * @property x 1363 * @type Int 1364 */ 1365 this.x = l; 1366 1367 /** 1368 * The region's left extent as index, for symmetry with set/getXY 1369 * @property 0 1370 * @type Int 1371 */ 1372 this[0] = l; 1373 1374 /** 1375 * The region's total width 1376 * @property width 1377 * @type Int 1378 */ 1379 this.width = this.right - this.left; 1380 1381 /** 1382 * The region's total height 1383 * @property height 1384 * @type Int 1385 */ 1386 this.height = this.bottom - this.top; 1387 }; 1388 1389 /** 1390 * Returns true if this region contains the region passed in 1391 * @method contains 1392 * @param {Region} region The region to evaluate 1393 * @return {Boolean} True if the region is contained with this region, 1394 * else false 1395 */ 1396 YAHOO.util.Region.prototype.contains = function(region) { 1397 return ( region.left >= this.left && 1398 region.right <= this.right && 1399 region.top >= this.top && 1400 region.bottom <= this.bottom ); 1401 1402 }; 1403 1404 /** 1405 * Returns the area of the region 1406 * @method getArea 1407 * @return {Int} the region's area 1408 */ 1409 YAHOO.util.Region.prototype.getArea = function() { 1410 return ( (this.bottom - this.top) * (this.right - this.left) ); 1411 }; 1412 1413 /** 1414 * Returns the region where the passed in region overlaps with this one 1415 * @method intersect 1416 * @param {Region} region The region that intersects 1417 * @return {Region} The overlap region, or null if there is no overlap 1418 */ 1419 YAHOO.util.Region.prototype.intersect = function(region) { 1420 var t = Math.max( this.top, region.top ), 1421 r = Math.min( this.right, region.right ), 1422 b = Math.min( this.bottom, region.bottom ), 1423 l = Math.max( this.left, region.left ); 1424 1425 if (b >= t && r >= l) { 1426 return new YAHOO.util.Region(t, r, b, l); 1427 } else { 1428 return null; 1429 } 1430 }; 1431 1432 /** 1433 * Returns the region representing the smallest region that can contain both 1434 * the passed in region and this region. 1435 * @method union 1436 * @param {Region} region The region that to create the union with 1437 * @return {Region} The union region 1438 */ 1439 YAHOO.util.Region.prototype.union = function(region) { 1440 var t = Math.min( this.top, region.top ), 1441 r = Math.max( this.right, region.right ), 1442 b = Math.max( this.bottom, region.bottom ), 1443 l = Math.min( this.left, region.left ); 1444 1445 return new YAHOO.util.Region(t, r, b, l); 1446 }; 1447 1448 /** 1449 * toString 1450 * @method toString 1451 * @return string the region properties 1452 */ 1453 YAHOO.util.Region.prototype.toString = function() { 1454 return ( "Region {" + 1455 "top: " + this.top + 1456 ", right: " + this.right + 1457 ", bottom: " + this.bottom + 1458 ", left: " + this.left + 1459 ", height: " + this.height + 1460 ", width: " + this.width + 1461 "}" ); 1462 }; 1463 1464 /** 1465 * Returns a region that is occupied by the DOM element 1466 * @method getRegion 1467 * @param {HTMLElement} el The element 1468 * @return {Region} The region that the element occupies 1469 * @static 1470 */ 1471 YAHOO.util.Region.getRegion = function(el) { 1472 var p = YAHOO.util.Dom.getXY(el), 1473 t = p[1], 1474 r = p[0] + el.offsetWidth, 1475 b = p[1] + el.offsetHeight, 1476 l = p[0]; 1477 1478 return new YAHOO.util.Region(t, r, b, l); 1479 }; 1480 1481 ///////////////////////////////////////////////////////////////////////////// 1482 1483 1484 /** 1485 * A point is a region that is special in that it represents a single point on 1486 * the grid. 1487 * @namespace YAHOO.util 1488 * @class Point 1489 * @param {Int} x The X position of the point 1490 * @param {Int} y The Y position of the point 1491 * @constructor 1492 * @extends YAHOO.util.Region 1493 */ 1494 YAHOO.util.Point = function(x, y) { 1495 if (YAHOO.lang.isArray(x)) { // accept input from Dom.getXY, Event.getXY, etc. 1496 y = x[1]; // dont blow away x yet 1497 x = x[0]; 1498 } 1499 1500 YAHOO.util.Point.superclass.constructor.call(this, y, x, y, x); 1501 }; 1502 1503 YAHOO.extend(YAHOO.util.Point, YAHOO.util.Region); 1504 1505 (function() { 1506 /** 1507 * Internal methods used to add style management functionality to DOM. 1508 * @module dom 1509 * @class IEStyle 1510 * @namespace YAHOO.util.Dom 1511 */ 1512 1513 var Y = YAHOO.util, 1514 CLIENT_TOP = 'clientTop', 1515 CLIENT_LEFT = 'clientLeft', 1516 PARENT_NODE = 'parentNode', 1517 RIGHT = 'right', 1518 HAS_LAYOUT = 'hasLayout', 1519 PX = 'px', 1520 OPACITY = 'opacity', 1521 AUTO = 'auto', 1522 BORDER_LEFT_WIDTH = 'borderLeftWidth', 1523 BORDER_TOP_WIDTH = 'borderTopWidth', 1524 BORDER_RIGHT_WIDTH = 'borderRightWidth', 1525 BORDER_BOTTOM_WIDTH = 'borderBottomWidth', 1526 VISIBLE = 'visible', 1527 TRANSPARENT = 'transparent', 1528 HEIGHT = 'height', 1529 WIDTH = 'width', 1530 STYLE = 'style', 1531 CURRENT_STYLE = 'currentStyle', 1532 1533 // IE getComputedStyle 1534 // TODO: unit-less lineHeight (e.g. 1.22) 1535 re_size = /^width|height$/, 1536 re_unit = /^(\d[.\d]*)+(em|ex|px|gd|rem|vw|vh|vm|ch|mm|cm|in|pt|pc|deg|rad|ms|s|hz|khz|%){1}?/i, 1537 1538 ComputedStyle = { 1539 /** 1540 * @method get 1541 * @description Method used by DOM to get style information for IE 1542 * @param {HTMLElement} el The element to check 1543 * @param {String} property The property to check 1544 * @returns {String} The computed style 1545 */ 1546 get: function(el, property) { 1547 var value = '', 1548 current = el[CURRENT_STYLE][property]; 1549 1550 if (property === OPACITY) { 1551 value = Y.Dom.getStyle(el, OPACITY); 1552 } else if (!current || (current.indexOf && current.indexOf(PX) > -1)) { // no need to convert 1553 value = current; 1554 } else if (Y.Dom.IE_COMPUTED[property]) { // use compute function 1555 value = Y.Dom.IE_COMPUTED[property](el, property); 1556 } else if (re_unit.test(current)) { // convert to pixel 1557 value = Y.Dom.IE.ComputedStyle.getPixel(el, property); 1558 } else { 1559 value = current; 1560 } 1561 1562 return value; 1563 }, 1564 /** 1565 * @method getOffset 1566 * @description Determine the offset of an element 1567 * @param {HTMLElement} el The element to check 1568 * @param {String} prop The property to check. 1569 * @return {String} The offset 1570 */ 1571 getOffset: function(el, prop) { 1572 var current = el[CURRENT_STYLE][prop], // value of "width", "top", etc. 1573 capped = prop.charAt(0).toUpperCase() + prop.substr(1), // "Width", "Top", etc. 1574 offset = 'offset' + capped, // "offsetWidth", "offsetTop", etc. 1575 pixel = 'pixel' + capped, // "pixelWidth", "pixelTop", etc. 1576 value = '', 1577 actual; 1578 1579 if (current == AUTO) { 1580 actual = el[offset]; // offsetHeight/Top etc. 1581 if (actual === undefined) { // likely "right" or "bottom" 1582 value = 0; 1583 } 1584 1585 value = actual; 1586 if (re_size.test(prop)) { // account for box model diff 1587 el[STYLE][prop] = actual; 1588 if (el[offset] > actual) { 1589 // the difference is padding + border (works in Standards & Quirks modes) 1590 value = actual - (el[offset] - actual); 1591 } 1592 el[STYLE][prop] = AUTO; // revert to auto 1593 } 1594 } else { // convert units to px 1595 if (!el[STYLE][pixel] && !el[STYLE][prop]) { // need to map style.width to currentStyle (no currentStyle.pixelWidth) 1596 el[STYLE][prop] = current; // no style.pixelWidth if no style.width 1597 } 1598 value = el[STYLE][pixel]; 1599 } 1600 return value + PX; 1601 }, 1602 /** 1603 * @method getBorderWidth 1604 * @description Try to determine the width of an elements border 1605 * @param {HTMLElement} el The element to check 1606 * @param {String} property The property to check 1607 * @return {String} The elements border width 1608 */ 1609 getBorderWidth: function(el, property) { 1610 // clientHeight/Width = paddingBox (e.g. offsetWidth - borderWidth) 1611 // clientTop/Left = borderWidth 1612 var value = null; 1613 if (!el[CURRENT_STYLE][HAS_LAYOUT]) { // TODO: unset layout? 1614 el[STYLE].zoom = 1; // need layout to measure client 1615 } 1616 1617 switch(property) { 1618 case BORDER_TOP_WIDTH: 1619 value = el[CLIENT_TOP]; 1620 break; 1621 case BORDER_BOTTOM_WIDTH: 1622 value = el.offsetHeight - el.clientHeight - el[CLIENT_TOP]; 1623 break; 1624 case BORDER_LEFT_WIDTH: 1625 value = el[CLIENT_LEFT]; 1626 break; 1627 case BORDER_RIGHT_WIDTH: 1628 value = el.offsetWidth - el.clientWidth - el[CLIENT_LEFT]; 1629 break; 1630 } 1631 return value + PX; 1632 }, 1633 /** 1634 * @method getPixel 1635 * @description Get the pixel value from a style property 1636 * @param {HTMLElement} node The element to check 1637 * @param {String} att The attribute to check 1638 * @return {String} The pixel value 1639 */ 1640 getPixel: function(node, att) { 1641 // use pixelRight to convert to px 1642 var val = null, 1643 styleRight = node[CURRENT_STYLE][RIGHT], 1644 current = node[CURRENT_STYLE][att]; 1645 1646 node[STYLE][RIGHT] = current; 1647 val = node[STYLE].pixelRight; 1648 node[STYLE][RIGHT] = styleRight; // revert 1649 1650 return val + PX; 1651 }, 1652 1653 /** 1654 * @method getMargin 1655 * @description Get the margin value from a style property 1656 * @param {HTMLElement} node The element to check 1657 * @param {String} att The attribute to check 1658 * @return {String} The margin value 1659 */ 1660 getMargin: function(node, att) { 1661 var val; 1662 if (node[CURRENT_STYLE][att] == AUTO) { 1663 val = 0 + PX; 1664 } else { 1665 val = Y.Dom.IE.ComputedStyle.getPixel(node, att); 1666 } 1667 return val; 1668 }, 1669 1670 /** 1671 * @method getVisibility 1672 * @description Get the visibility of an element 1673 * @param {HTMLElement} node The element to check 1674 * @param {String} att The attribute to check 1675 * @return {String} The value 1676 */ 1677 getVisibility: function(node, att) { 1678 var current; 1679 while ( (current = node[CURRENT_STYLE]) && current[att] == 'inherit') { // NOTE: assignment in test 1680 node = node[PARENT_NODE]; 1681 } 1682 return (current) ? current[att] : VISIBLE; 1683 }, 1684 1685 /** 1686 * @method getColor 1687 * @description Get the color of an element 1688 * @param {HTMLElement} node The element to check 1689 * @param {String} att The attribute to check 1690 * @return {String} The value 1691 */ 1692 getColor: function(node, att) { 1693 return Y.Dom.Color.toRGB(node[CURRENT_STYLE][att]) || TRANSPARENT; 1694 }, 1695 1696 /** 1697 * @method getBorderColor 1698 * @description Get the bordercolor of an element 1699 * @param {HTMLElement} node The element to check 1700 * @param {String} att The attribute to check 1701 * @return {String} The value 1702 */ 1703 getBorderColor: function(node, att) { 1704 var current = node[CURRENT_STYLE], 1705 val = current[att] || current.color; 1706 return Y.Dom.Color.toRGB(Y.Dom.Color.toHex(val)); 1707 } 1708 1709 }, 1710 1711 //fontSize: getPixelFont, 1712 IEComputed = {}; 1713 1714 IEComputed.top = IEComputed.right = IEComputed.bottom = IEComputed.left = 1715 IEComputed[WIDTH] = IEComputed[HEIGHT] = ComputedStyle.getOffset; 1716 1717 IEComputed.color = ComputedStyle.getColor; 1718 1719 IEComputed[BORDER_TOP_WIDTH] = IEComputed[BORDER_RIGHT_WIDTH] = 1720 IEComputed[BORDER_BOTTOM_WIDTH] = IEComputed[BORDER_LEFT_WIDTH] = 1721 ComputedStyle.getBorderWidth; 1722 1723 IEComputed.marginTop = IEComputed.marginRight = IEComputed.marginBottom = 1724 IEComputed.marginLeft = ComputedStyle.getMargin; 1725 1726 IEComputed.visibility = ComputedStyle.getVisibility; 1727 IEComputed.borderColor = IEComputed.borderTopColor = 1728 IEComputed.borderRightColor = IEComputed.borderBottomColor = 1729 IEComputed.borderLeftColor = ComputedStyle.getBorderColor; 1730 1731 Y.Dom.IE_COMPUTED = IEComputed; 1732 Y.Dom.IE_ComputedStyle = ComputedStyle; 1733 })(); 1734 (function() { 1735 /** 1736 * Add style management functionality to DOM. 1737 * @module dom 1738 * @class Color 1739 * @namespace YAHOO.util.Dom 1740 */ 1741 1742 var TO_STRING = 'toString', 1743 PARSE_INT = parseInt, 1744 RE = RegExp, 1745 Y = YAHOO.util; 1746 1747 Y.Dom.Color = { 1748 /** 1749 * @property KEYWORDS 1750 * @type Object 1751 * @description Color keywords used when converting to Hex 1752 */ 1753 KEYWORDS: { 1754 black: '000', 1755 silver: 'c0c0c0', 1756 gray: '808080', 1757 white: 'fff', 1758 maroon: '800000', 1759 red: 'f00', 1760 purple: '800080', 1761 fuchsia: 'f0f', 1762 green: '008000', 1763 lime: '0f0', 1764 olive: '808000', 1765 yellow: 'ff0', 1766 navy: '000080', 1767 blue: '00f', 1768 teal: '008080', 1769 aqua: '0ff' 1770 }, 1771 /** 1772 * @property re_RGB 1773 * @private 1774 * @type Regex 1775 * @description Regex to parse rgb(0,0,0) formatted strings 1776 */ 1777 re_RGB: /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i, 1778 /** 1779 * @property re_hex 1780 * @private 1781 * @type Regex 1782 * @description Regex to parse #123456 formatted strings 1783 */ 1784 re_hex: /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i, 1785 /** 1786 * @property re_hex3 1787 * @private 1788 * @type Regex 1789 * @description Regex to parse #123 formatted strings 1790 */ 1791 re_hex3: /([0-9A-F])/gi, 1792 /** 1793 * @method toRGB 1794 * @description Converts a hex or color string to an rgb string: rgb(0,0,0) 1795 * @param {String} val The string to convert to RGB notation. 1796 * @returns {String} The converted string 1797 */ 1798 toRGB: function(val) { 1799 if (!Y.Dom.Color.re_RGB.test(val)) { 1800 val = Y.Dom.Color.toHex(val); 1801 } 1802 1803 if(Y.Dom.Color.re_hex.exec(val)) { 1804 val = 'rgb(' + [ 1805 PARSE_INT(RE.$1, 16), 1806 PARSE_INT(RE.$2, 16), 1807 PARSE_INT(RE.$3, 16) 1808 ].join(', ') + ')'; 1809 } 1810 return val; 1811 }, 1812 /** 1813 * @method toHex 1814 * @description Converts an rgb or color string to a hex string: #123456 1815 * @param {String} val The string to convert to hex notation. 1816 * @returns {String} The converted string 1817 */ 1818 toHex: function(val) { 1819 val = Y.Dom.Color.KEYWORDS[val] || val; 1820 if (Y.Dom.Color.re_RGB.exec(val)) { 1821 val = [ 1822 Number(RE.$1).toString(16), 1823 Number(RE.$2).toString(16), 1824 Number(RE.$3).toString(16) 1825 ]; 1826 1827 for (var i = 0; i < val.length; i++) { 1828 if (val[i].length < 2) { 1829 val[i] = '0' + val[i]; 1830 } 1831 } 1832 1833 val = val.join(''); 1834 } 1835 1836 if (val.length < 6) { 1837 val = val.replace(Y.Dom.Color.re_hex3, '$1$1'); 1838 } 1839 1840 if (val !== 'transparent' && val.indexOf('#') < 0) { 1841 val = '#' + val; 1842 } 1843 1844 return val.toUpperCase(); 1845 } 1846 }; 1847 }()); 1848 YAHOO.register("dom", YAHOO.util.Dom, {version: "2.9.0", build: "2800"}); 1849 1850 if (YAHOO.env._id_counter < 1e+6) { 1851 YAHOO.env._id_counter = Y.Env._yidx * 1e+6; 1852 } 1853 }, '2.9.0' ,{"requires": ["yui2-yahoo"]});
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Aug 11 10:00:09 2016 | Cross-referenced by PHPXref 0.7.1 |