[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/lib/yuilib/2in3/2.9.0/build/yui2-dom/ -> yui2-dom.js (source)

   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"]});


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1