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