src/cm/media/js/lib/yui/yui3.0.0/build/dom/dom-base.js
changeset 0 40c8f766c9b8
equal deleted inserted replaced
-1:000000000000 0:40c8f766c9b8
       
     1 /*
       
     2 Copyright (c) 2009, Yahoo! Inc. All rights reserved.
       
     3 Code licensed under the BSD License:
       
     4 http://developer.yahoo.net/yui/license.txt
       
     5 version: 3.0.0
       
     6 build: 1549
       
     7 */
       
     8 YUI.add('dom-base', function(Y) {
       
     9 
       
    10 (function(Y) {
       
    11 /** 
       
    12  * The DOM utility provides a cross-browser abtraction layer
       
    13  * normalizing DOM tasks, and adds extra helper functionality
       
    14  * for other common tasks. 
       
    15  * @module dom
       
    16  * @submodule dom-base
       
    17  *
       
    18  */
       
    19 
       
    20 /**
       
    21  * Provides DOM helper methods.
       
    22  * @class DOM
       
    23  *
       
    24  */
       
    25 var NODE_TYPE = 'nodeType',
       
    26     OWNER_DOCUMENT = 'ownerDocument',
       
    27     DEFAULT_VIEW = 'defaultView',
       
    28     PARENT_WINDOW = 'parentWindow',
       
    29     TAG_NAME = 'tagName',
       
    30     PARENT_NODE = 'parentNode',
       
    31     FIRST_CHILD = 'firstChild',
       
    32     PREVIOUS_SIBLING = 'previousSibling',
       
    33     NEXT_SIBLING = 'nextSibling',
       
    34     CONTAINS = 'contains',
       
    35     COMPARE_DOCUMENT_POSITION = 'compareDocumentPosition',
       
    36 
       
    37     documentElement = document.documentElement,
       
    38 
       
    39     re_tag = /<([a-z]+)/i;
       
    40 
       
    41 Y.DOM = {
       
    42     /**
       
    43      * Returns the HTMLElement with the given ID (Wrapper for document.getElementById).
       
    44      * @method byId         
       
    45      * @param {String} id the id attribute 
       
    46      * @param {Object} doc optional The document to search. Defaults to current document 
       
    47      * @return {HTMLElement | null} The HTMLElement with the id, or null if none found. 
       
    48      */
       
    49     byId: function(id, doc) {
       
    50         doc = doc || Y.config.doc;
       
    51         // TODO: IE Name
       
    52         return doc.getElementById(id);
       
    53     },
       
    54 
       
    55     // @deprecated
       
    56     children: function(node, tag) {
       
    57         var ret = [];
       
    58         if (node) {
       
    59             tag = tag || '*';
       
    60             ret = Y.Selector.query('> ' + tag, node); 
       
    61         }
       
    62         return ret;
       
    63     },
       
    64 
       
    65     // @deprecated
       
    66     firstByTag: function(tag, root) {
       
    67         var ret;
       
    68         root = root || Y.config.doc;
       
    69 
       
    70         if (tag && root.getElementsByTagName) {
       
    71             ret = root.getElementsByTagName(tag)[0];
       
    72         }
       
    73 
       
    74         return ret || null;
       
    75     },
       
    76 
       
    77     /**
       
    78      * Returns the text content of the HTMLElement. 
       
    79      * @method getText         
       
    80      * @param {HTMLElement} element The html element. 
       
    81      * @return {String} The text content of the element (includes text of any descending elements).
       
    82      */
       
    83     getText: (documentElement.textContent !== undefined) ?
       
    84         function(element) {
       
    85             var ret = '';
       
    86             if (element) {
       
    87                 ret = element.textContent;
       
    88             }
       
    89             return ret || '';
       
    90         } : function(element) {
       
    91             var ret = '';
       
    92             if (element) {
       
    93                 ret = element.innerText;
       
    94             }
       
    95             return ret || '';
       
    96         },
       
    97 
       
    98     /**
       
    99      * Sets the text content of the HTMLElement. 
       
   100      * @method setText         
       
   101      * @param {HTMLElement} element The html element. 
       
   102      * @param {String} content The content to add. 
       
   103      */
       
   104     setText: (documentElement.textContent !== undefined) ?
       
   105         function(element, content) {
       
   106             if (element) {
       
   107                 element.textContent = content;
       
   108             }
       
   109         } : function(element, content) {
       
   110             if (element) {
       
   111                 element.innerText = content;
       
   112             }
       
   113         },
       
   114 
       
   115     /*
       
   116      * Finds the previous sibling of the element.
       
   117      * @method previous
       
   118      * @deprecated Use elementByAxis
       
   119      * @param {HTMLElement} element The html element.
       
   120      * @param {Function} fn optional An optional boolean test to apply.
       
   121      * The optional function is passed the current DOM node being tested as its only argument.
       
   122      * If no function is given, the first sibling is returned.
       
   123      * @param {Boolean} all optional Whether all node types should be scanned, or just element nodes.
       
   124      * @return {HTMLElement | null} The matching DOM node or null if none found. 
       
   125      */
       
   126     previous: function(element, fn, all) {
       
   127         return Y.DOM.elementByAxis(element, PREVIOUS_SIBLING, fn, all);
       
   128     },
       
   129 
       
   130     /*
       
   131      * Finds the next sibling of the element.
       
   132      * @method next
       
   133      * @deprecated Use elementByAxis
       
   134      * @param {HTMLElement} element The html element.
       
   135      * @param {Function} fn optional An optional boolean test to apply.
       
   136      * The optional function is passed the current DOM node being tested as its only argument.
       
   137      * If no function is given, the first sibling is returned.
       
   138      * @param {Boolean} all optional Whether all node types should be scanned, or just element nodes.
       
   139      * @return {HTMLElement | null} The matching DOM node or null if none found. 
       
   140      */
       
   141     next: function(element, fn, all) {
       
   142         return Y.DOM.elementByAxis(element, NEXT_SIBLING, fn, all);
       
   143     },
       
   144 
       
   145     /*
       
   146      * Finds the ancestor of the element.
       
   147      * @method ancestor
       
   148      * @deprecated Use elementByAxis
       
   149      * @param {HTMLElement} element The html element.
       
   150      * @param {Function} fn optional An optional boolean test to apply.
       
   151      * The optional function is passed the current DOM node being tested as its only argument.
       
   152      * If no function is given, the parentNode is returned.
       
   153      * @param {Boolean} all optional Whether all node types should be scanned, or just element nodes.
       
   154      * @return {HTMLElement | null} The matching DOM node or null if none found. 
       
   155      */
       
   156      // TODO: optional stopAt node?
       
   157     ancestor: function(element, fn, all) {
       
   158         return Y.DOM.elementByAxis(element, PARENT_NODE, fn, all);
       
   159     },
       
   160 
       
   161     /**
       
   162      * Searches the element by the given axis for the first matching element.
       
   163      * @method elementByAxis
       
   164      * @param {HTMLElement} element The html element.
       
   165      * @param {String} axis The axis to search (parentNode, nextSibling, previousSibling).
       
   166      * @param {Function} fn optional An optional boolean test to apply.
       
   167      * @param {Boolean} all optional Whether all node types should be returned, or just element nodes.
       
   168      * The optional function is passed the current HTMLElement being tested as its only argument.
       
   169      * If no function is given, the first element is returned.
       
   170      * @return {HTMLElement | null} The matching element or null if none found.
       
   171      */
       
   172     elementByAxis: function(element, axis, fn, all) {
       
   173         while (element && (element = element[axis])) { // NOTE: assignment
       
   174                 if ( (all || element[TAG_NAME]) && (!fn || fn(element)) ) {
       
   175                     return element;
       
   176                 }
       
   177         }
       
   178         return null;
       
   179     },
       
   180 
       
   181     /**
       
   182      * Determines whether or not one HTMLElement is or contains another HTMLElement.
       
   183      * @method contains
       
   184      * @param {HTMLElement} element The containing html element.
       
   185      * @param {HTMLElement} needle The html element that may be contained.
       
   186      * @return {Boolean} Whether or not the element is or contains the needle.
       
   187      */
       
   188     contains: function(element, needle) {
       
   189         var ret = false;
       
   190 
       
   191         if ( !needle || !element || !needle[NODE_TYPE] || !element[NODE_TYPE]) {
       
   192             ret = false;
       
   193         } else if (element[CONTAINS])  {
       
   194             if (Y.UA.opera || needle[NODE_TYPE] === 1) { // IE & SAF contains fail if needle not an ELEMENT_NODE
       
   195                 ret = element[CONTAINS](needle);
       
   196             } else {
       
   197                 ret = Y.DOM._bruteContains(element, needle); 
       
   198             }
       
   199         } else if (element[COMPARE_DOCUMENT_POSITION]) { // gecko
       
   200             if (element === needle || !!(element[COMPARE_DOCUMENT_POSITION](needle) & 16)) { 
       
   201                 ret = true;
       
   202             }
       
   203         }
       
   204 
       
   205         return ret;
       
   206     },
       
   207 
       
   208     /**
       
   209      * Determines whether or not the HTMLElement is part of the document.
       
   210      * @method inDoc
       
   211      * @param {HTMLElement} element The containing html element.
       
   212      * @param {HTMLElement} doc optional The document to check.
       
   213      * @return {Boolean} Whether or not the element is attached to the document. 
       
   214      */
       
   215     inDoc: function(element, doc) {
       
   216         doc = doc || element[OWNER_DOCUMENT];
       
   217         var id = element.id;
       
   218         if (!id) { // TODO: remove when done?
       
   219             id = element.id = Y.guid();
       
   220         }
       
   221 
       
   222         return !! (doc.getElementById(id));
       
   223     },
       
   224 
       
   225     /**
       
   226      * Creates a new dom node using the provided markup string. 
       
   227      * @method create
       
   228      * @param {String} html The markup used to create the element
       
   229      * @param {HTMLDocument} doc An optional document context 
       
   230      */
       
   231     create: function(html, doc) {
       
   232         if (typeof html === 'string') {
       
   233             html = Y.Lang.trim(html); // match IE which trims whitespace from innerHTML
       
   234         }
       
   235 
       
   236         if (!doc && Y.DOM._cloneCache[html]) {
       
   237             return Y.DOM._cloneCache[html].cloneNode(true); // NOTE: return
       
   238         }
       
   239 
       
   240         doc = doc || Y.config.doc;
       
   241         var m = re_tag.exec(html),
       
   242             create = Y.DOM._create,
       
   243             custom = Y.DOM.creators,
       
   244             ret = null,
       
   245             tag, nodes;
       
   246 
       
   247         if (m && custom[m[1]]) {
       
   248             if (typeof custom[m[1]] === 'function') {
       
   249                 create = custom[m[1]];
       
   250             } else {
       
   251                 tag = custom[m[1]];
       
   252             }
       
   253         }
       
   254 
       
   255         nodes = create(html, doc, tag).childNodes;
       
   256 
       
   257         if (nodes.length === 1) { // return single node, breaking parentNode ref from "fragment"
       
   258             ret = nodes[0].parentNode.removeChild(nodes[0]);
       
   259         } else { // return multiple nodes as a fragment
       
   260              ret = Y.DOM._nl2frag(nodes, doc);
       
   261         }
       
   262 
       
   263         if (ret) {
       
   264             Y.DOM._cloneCache[html] = ret.cloneNode(true);
       
   265         }
       
   266         return ret;
       
   267     },
       
   268 
       
   269     _nl2frag: function(nodes, doc) {
       
   270         var ret = null,
       
   271             i, len;
       
   272 
       
   273         if (nodes && (nodes.push || nodes.item) && nodes[0]) {
       
   274             doc = doc || nodes[0].ownerDocument; 
       
   275             ret = doc.createDocumentFragment();
       
   276 
       
   277             if (nodes.item) { // convert live list to static array
       
   278                 nodes = Y.Array(nodes, 0, true);
       
   279             }
       
   280 
       
   281             for (i = 0, len = nodes.length; i < len; i++) {
       
   282                 ret.appendChild(nodes[i]); 
       
   283             }
       
   284         } // else inline with log for minification
       
   285         return ret;
       
   286     },
       
   287 
       
   288 
       
   289     CUSTOM_ATTRIBUTES: (!documentElement.hasAttribute) ? { // IE < 8
       
   290         'for': 'htmlFor',
       
   291         'class': 'className'
       
   292     } : { // w3c
       
   293         'htmlFor': 'for',
       
   294         'className': 'class'
       
   295     },
       
   296 
       
   297     /**
       
   298      * Provides a normalized attribute interface. 
       
   299      * @method setAttibute
       
   300      * @param {String | HTMLElement} el The target element for the attribute.
       
   301      * @param {String} attr The attribute to set.
       
   302      * @param {String} val The value of the attribute.
       
   303      */
       
   304     setAttribute: function(el, attr, val, ieAttr) {
       
   305         if (el && el.setAttribute) {
       
   306             attr = Y.DOM.CUSTOM_ATTRIBUTES[attr] || attr;
       
   307             el.setAttribute(attr, val, ieAttr);
       
   308         }
       
   309     },
       
   310 
       
   311 
       
   312     /**
       
   313      * Provides a normalized attribute interface. 
       
   314      * @method getAttibute
       
   315      * @param {String | HTMLElement} el The target element for the attribute.
       
   316      * @param {String} attr The attribute to get.
       
   317      * @return {String} The current value of the attribute. 
       
   318      */
       
   319     getAttribute: function(el, attr, ieAttr) {
       
   320         ieAttr = (ieAttr !== undefined) ? ieAttr : 2;
       
   321         var ret = '';
       
   322         if (el && el.getAttribute) {
       
   323             attr = Y.DOM.CUSTOM_ATTRIBUTES[attr] || attr;
       
   324             ret = el.getAttribute(attr, ieAttr);
       
   325 
       
   326             if (ret === null) {
       
   327                 ret = ''; // per DOM spec
       
   328             }
       
   329         }
       
   330         return ret;
       
   331     },
       
   332 
       
   333     isWindow: function(obj) {
       
   334         return obj.alert && obj.document;
       
   335     },
       
   336 
       
   337     _fragClones: {
       
   338         div: document.createElement('div')
       
   339     },
       
   340 
       
   341     _create: function(html, doc, tag) {
       
   342         tag = tag || 'div';
       
   343 
       
   344         var frag = Y.DOM._fragClones[tag];
       
   345         if (frag) {
       
   346             frag = frag.cloneNode(false);
       
   347         } else {
       
   348             frag = Y.DOM._fragClones[tag] = doc.createElement(tag);
       
   349         }
       
   350         frag.innerHTML = html;
       
   351         return frag;
       
   352     },
       
   353 
       
   354     _removeChildNodes: function(node) {
       
   355         while (node.firstChild) {
       
   356             node.removeChild(node.firstChild);
       
   357         }
       
   358     },
       
   359 
       
   360     _cloneCache: {},
       
   361 
       
   362     /**
       
   363      * Inserts content in a node at the given location 
       
   364      * @method addHTML
       
   365      * @param {HTMLElement} node The node to insert into
       
   366      * @param {String} content The content to be inserted 
       
   367      * @param {String} where Where to insert the content; default is after lastChild 
       
   368      */
       
   369     addHTML: function(node, content, where) {
       
   370         if (typeof content === 'string') {
       
   371             content = Y.Lang.trim(content); // match IE which trims whitespace from innerHTML
       
   372         }
       
   373 
       
   374         var newNode = Y.DOM._cloneCache[content],
       
   375             nodeParent = node.parentNode;
       
   376             
       
   377         if (newNode) {
       
   378             newNode = newNode.cloneNode(true);
       
   379         } else {
       
   380             if (content.nodeType) { // domNode
       
   381                 newNode = content;
       
   382             } else { // create from string and cache
       
   383                 newNode = Y.DOM.create(content);
       
   384             }
       
   385         }
       
   386 
       
   387         if (where) {
       
   388             if (where.nodeType) { // insert regardless of relationship to node
       
   389                 // TODO: check if node.contains(where)?
       
   390                 where.parentNode.insertBefore(newNode, where);
       
   391             } else {
       
   392                 switch (where) {
       
   393                     case 'replace':
       
   394                         while (node.firstChild) {
       
   395                             node.removeChild(node.firstChild);
       
   396                         }
       
   397                         node.appendChild(newNode);
       
   398                         break;
       
   399                     case 'before':
       
   400                         nodeParent.insertBefore(newNode, node);
       
   401                         break;
       
   402                     case 'after':
       
   403                         if (node.nextSibling) { // IE errors if refNode is null
       
   404                             nodeParent.insertBefore(newNode, node.nextSibling);
       
   405                         } else {
       
   406                             nodeParent.appendChild(newNode);
       
   407                         }
       
   408                         break;
       
   409                     default:
       
   410                         node.appendChild(newNode);
       
   411                 }
       
   412             }
       
   413         } else {
       
   414             node.appendChild(newNode);
       
   415         }
       
   416 
       
   417         return newNode;
       
   418     },
       
   419 
       
   420     VALUE_SETTERS: {},
       
   421 
       
   422     VALUE_GETTERS: {},
       
   423 
       
   424     getValue: function(node) {
       
   425         var ret = '', // TODO: return null?
       
   426             getter;
       
   427 
       
   428         if (node && node[TAG_NAME]) {
       
   429             getter = Y.DOM.VALUE_GETTERS[node[TAG_NAME].toLowerCase()];
       
   430 
       
   431             if (getter) {
       
   432                 ret = getter(node);
       
   433             } else {
       
   434                 ret = node.value;
       
   435             }
       
   436         }
       
   437 
       
   438         return (typeof ret === 'string') ? ret : '';
       
   439     },
       
   440 
       
   441     setValue: function(node, val) {
       
   442         var setter;
       
   443 
       
   444         if (node && node[TAG_NAME]) {
       
   445             setter = Y.DOM.VALUE_SETTERS[node[TAG_NAME].toLowerCase()];
       
   446 
       
   447             if (setter) {
       
   448                 setter(node, val);
       
   449             } else {
       
   450                 node.value = val;
       
   451             }
       
   452         }
       
   453     },
       
   454 
       
   455     /**
       
   456      * Brute force version of contains.
       
   457      * Used for browsers without contains support for non-HTMLElement Nodes (textNodes, etc).
       
   458      * @method _bruteContains
       
   459      * @private
       
   460      * @param {HTMLElement} element The containing html element.
       
   461      * @param {HTMLElement} needle The html element that may be contained.
       
   462      * @return {Boolean} Whether or not the element is or contains the needle.
       
   463      */
       
   464     _bruteContains: function(element, needle) {
       
   465         while (needle) {
       
   466             if (element === needle) {
       
   467                 return true;
       
   468             }
       
   469             needle = needle.parentNode;
       
   470         }
       
   471         return false;
       
   472     },
       
   473 
       
   474 // TODO: move to Lang?
       
   475     /**
       
   476      * Memoizes dynamic regular expressions to boost runtime performance. 
       
   477      * @method _getRegExp
       
   478      * @private
       
   479      * @param {String} str The string to convert to a regular expression.
       
   480      * @param {String} flags optional An optinal string of flags.
       
   481      * @return {RegExp} An instance of RegExp
       
   482      */
       
   483     _getRegExp: function(str, flags) {
       
   484         flags = flags || '';
       
   485         Y.DOM._regexCache = Y.DOM._regexCache || {};
       
   486         if (!Y.DOM._regexCache[str + flags]) {
       
   487             Y.DOM._regexCache[str + flags] = new RegExp(str, flags);
       
   488         }
       
   489         return Y.DOM._regexCache[str + flags];
       
   490     },
       
   491 
       
   492 // TODO: make getDoc/Win true privates?
       
   493     /**
       
   494      * returns the appropriate document.
       
   495      * @method _getDoc
       
   496      * @private
       
   497      * @param {HTMLElement} element optional Target element.
       
   498      * @return {Object} The document for the given element or the default document. 
       
   499      */
       
   500     _getDoc: function(element) {
       
   501         element = element || {};
       
   502 
       
   503         return (element[NODE_TYPE] === 9) ? element : // element === document
       
   504                 element[OWNER_DOCUMENT] || // element === DOM node
       
   505                 element.document || // element === window
       
   506                 Y.config.doc; // default
       
   507     },
       
   508 
       
   509     /**
       
   510      * returns the appropriate window.
       
   511      * @method _getWin
       
   512      * @private
       
   513      * @param {HTMLElement} element optional Target element.
       
   514      * @return {Object} The window for the given element or the default window. 
       
   515      */
       
   516     _getWin: function(element) {
       
   517         var doc = Y.DOM._getDoc(element);
       
   518         return doc[DEFAULT_VIEW] || doc[PARENT_WINDOW] || Y.config.win;
       
   519     },
       
   520 
       
   521     _batch: function(nodes, fn, arg1, arg2, arg3, etc) {
       
   522         fn = (typeof name === 'string') ? Y.DOM[fn] : fn;
       
   523         var result,
       
   524             ret = [];
       
   525 
       
   526         if (fn && nodes) {
       
   527             Y.each(nodes, function(node) {
       
   528                 if ((result = fn.call(Y.DOM, node, arg1, arg2, arg3, etc)) !== undefined) {
       
   529                     ret[ret.length] = result;
       
   530                 }
       
   531             });
       
   532         }
       
   533 
       
   534         return ret.length ? ret : nodes;
       
   535     },
       
   536 
       
   537     _testElement: function(element, tag, fn) {
       
   538         tag = (tag && tag !== '*') ? tag.toUpperCase() : null;
       
   539         return (element && element[TAG_NAME] &&
       
   540                 (!tag || element[TAG_NAME].toUpperCase() === tag) &&
       
   541                 (!fn || fn(element)));
       
   542     },
       
   543 
       
   544     creators: {},
       
   545 
       
   546     _IESimpleCreate: function(html, doc) {
       
   547         doc = doc || Y.config.doc;
       
   548         return doc.createElement(html);
       
   549     }
       
   550 };
       
   551 
       
   552 
       
   553 (function(Y) {
       
   554     var creators = Y.DOM.creators,
       
   555         create = Y.DOM.create,
       
   556         re_tbody = /(?:\/(?:thead|tfoot|tbody|caption|col|colgroup)>)+\s*<tbody/,
       
   557 
       
   558         TABLE_OPEN = '<table>',
       
   559         TABLE_CLOSE = '</table>';
       
   560 
       
   561     if (Y.UA.ie) {
       
   562         Y.mix(creators, {
       
   563         // TODO: thead/tfoot with nested tbody
       
   564             // IE adds TBODY when creating TABLE elements (which may share this impl)
       
   565             tbody: function(html, doc) {
       
   566                 var frag = create(TABLE_OPEN + html + TABLE_CLOSE, doc),
       
   567                     tb = frag.children.tags('tbody')[0];
       
   568 
       
   569                 if (frag.children.length > 1 && tb && !re_tbody.test(html)) {
       
   570                     tb[PARENT_NODE].removeChild(tb); // strip extraneous tbody
       
   571                 }
       
   572                 return frag;
       
   573             },
       
   574 
       
   575             script: function(html, doc) {
       
   576                 var frag = doc.createElement('div');
       
   577 
       
   578                 frag.innerHTML = '-' + html;
       
   579                 frag.removeChild(frag[FIRST_CHILD]);
       
   580                 return frag;
       
   581             }
       
   582 
       
   583         }, true);
       
   584 
       
   585         Y.mix(Y.DOM.VALUE_GETTERS, {
       
   586             button: function(node) {
       
   587                 return (node.attributes && node.attributes.value) ? node.attributes.value.value : '';
       
   588             }
       
   589         });
       
   590 
       
   591         Y.mix(Y.DOM.VALUE_SETTERS, {
       
   592             // IE: node.value changes the button text, which should be handled via innerHTML
       
   593             button: function(node, val) {
       
   594                 var attr = node.attributes.value;
       
   595                 if (!attr) {
       
   596                     attr = node[OWNER_DOCUMENT].createAttribute('value');
       
   597                     node.setAttributeNode(attr);
       
   598                 }
       
   599 
       
   600                 attr.value = val;
       
   601             }
       
   602         });
       
   603     }
       
   604 
       
   605     if (Y.UA.gecko || Y.UA.ie) {
       
   606         Y.mix(creators, {
       
   607             option: function(html, doc) {
       
   608                 return create('<select>' + html + '</select>', doc);
       
   609             },
       
   610 
       
   611             tr: function(html, doc) {
       
   612                 return create('<tbody>' + html + '</tbody>', doc);
       
   613             },
       
   614 
       
   615             td: function(html, doc) {
       
   616                 return create('<tr>' + html + '</tr>', doc);
       
   617             }, 
       
   618 
       
   619             tbody: function(html, doc) {
       
   620                 return create(TABLE_OPEN + html + TABLE_CLOSE, doc);
       
   621             }
       
   622         });
       
   623 
       
   624         Y.mix(creators, {
       
   625             legend: 'fieldset',
       
   626             th: creators.td,
       
   627             thead: creators.tbody,
       
   628             tfoot: creators.tbody,
       
   629             caption: creators.tbody,
       
   630             colgroup: creators.tbody,
       
   631             col: creators.tbody,
       
   632             optgroup: creators.option
       
   633         });
       
   634     }
       
   635 
       
   636     Y.mix(Y.DOM.VALUE_GETTERS, {
       
   637         option: function(node) {
       
   638             var attrs = node.attributes;
       
   639             return (attrs.value && attrs.value.specified) ? node.value : node.text;
       
   640         },
       
   641 
       
   642         select: function(node) {
       
   643             var val = node.value,
       
   644                 options = node.options;
       
   645 
       
   646             if (options && val === '') {
       
   647                 if (node.multiple) {
       
   648                 } else {
       
   649                     val = Y.DOM.getValue(options[node.selectedIndex], 'value');
       
   650                 }
       
   651             }
       
   652 
       
   653             return val;
       
   654         }
       
   655     });
       
   656 })(Y);
       
   657 
       
   658 })(Y);
       
   659 var addClass, hasClass, removeClass;
       
   660 
       
   661 Y.mix(Y.DOM, {
       
   662     /**
       
   663      * Determines whether a DOM element has the given className.
       
   664      * @method hasClass
       
   665      * @param {HTMLElement} element The DOM element. 
       
   666      * @param {String} className the class name to search for
       
   667      * @return {Boolean} Whether or not the element has the given class. 
       
   668      */
       
   669     hasClass: function(node, className) {
       
   670         var re = Y.DOM._getRegExp('(?:^|\\s+)' + className + '(?:\\s+|$)');
       
   671         return re.test(node.className);
       
   672     },
       
   673 
       
   674     /**
       
   675      * Adds a class name to a given DOM element.
       
   676      * @method addClass         
       
   677      * @param {HTMLElement} element The DOM element. 
       
   678      * @param {String} className the class name to add to the class attribute
       
   679      */
       
   680     addClass: function(node, className) {
       
   681         if (!Y.DOM.hasClass(node, className)) { // skip if already present 
       
   682             node.className = Y.Lang.trim([node.className, className].join(' '));
       
   683         }
       
   684     },
       
   685 
       
   686     /**
       
   687      * Removes a class name from a given element.
       
   688      * @method removeClass         
       
   689      * @param {HTMLElement} element The DOM element. 
       
   690      * @param {String} className the class name to remove from the class attribute
       
   691      */
       
   692     removeClass: function(node, className) {
       
   693         if (className && hasClass(node, className)) {
       
   694             node.className = Y.Lang.trim(node.className.replace(Y.DOM._getRegExp('(?:^|\\s+)' +
       
   695                             className + '(?:\\s+|$)'), ' '));
       
   696 
       
   697             if ( hasClass(node, className) ) { // in case of multiple adjacent
       
   698                 removeClass(node, className);
       
   699             }
       
   700         }                 
       
   701     },
       
   702 
       
   703     /**
       
   704      * Replace a class with another class for a given element.
       
   705      * If no oldClassName is present, the newClassName is simply added.
       
   706      * @method replaceClass  
       
   707      * @param {HTMLElement} element The DOM element. 
       
   708      * @param {String} oldClassName the class name to be replaced
       
   709      * @param {String} newClassName the class name that will be replacing the old class name
       
   710      */
       
   711     replaceClass: function(node, oldC, newC) {
       
   712         addClass(node, newC);
       
   713         removeClass(node, oldC);
       
   714     },
       
   715 
       
   716     /**
       
   717      * If the className exists on the node it is removed, if it doesn't exist it is added.
       
   718      * @method toggleClass  
       
   719      * @param {HTMLElement} element The DOM element. 
       
   720      * @param {String} className the class name to be toggled
       
   721      */
       
   722     toggleClass: function(node, className) {
       
   723         if (hasClass(node, className)) {
       
   724             removeClass(node, className);
       
   725         } else {
       
   726             addClass(node, className);
       
   727         }
       
   728     }
       
   729 });
       
   730 
       
   731 hasClass = Y.DOM.hasClass;
       
   732 removeClass = Y.DOM.removeClass;
       
   733 addClass = Y.DOM.addClass;
       
   734 
       
   735 
       
   736 
       
   737 }, '3.0.0' ,{requires:['oop']});