src/cm/media/js/lib/yui/yui_3.0.0b1/build/node/node-base-debug.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.0b1
       
     6 build: 1163
       
     7 */
       
     8 YUI.add('node-base', function(Y) {
       
     9 
       
    10 /**
       
    11  * The Node Utility provides a DOM-like interface for interacting with DOM nodes.
       
    12  * @module node
       
    13  * @submodule node-base
       
    14  */    
       
    15 
       
    16 /**
       
    17  * The Node class provides a wrapper for manipulating DOM Nodes.
       
    18  * Node properties can be accessed via the set/get methods.
       
    19  * Use Y.get() to retrieve Node instances.
       
    20  *
       
    21  * <strong>NOTE:</strong> Node properties are accessed using
       
    22  * the <code>set</code> and <code>get</code> methods.
       
    23  *
       
    24  * @class Node
       
    25  * @constructor
       
    26  * @for Node
       
    27  */
       
    28 
       
    29 // "globals"
       
    30 var g_nodes = {},
       
    31     g_nodelists = {},
       
    32     g_restrict = {},
       
    33     g_slice = Array.prototype.slice,
       
    34 
       
    35     DOT = '.',
       
    36     NODE_NAME = 'nodeName',
       
    37     NODE_TYPE = 'nodeType',
       
    38     OWNER_DOCUMENT = 'ownerDocument',
       
    39     TAG_NAME = 'tagName',
       
    40     UID = '_yuid',
       
    41 
       
    42     SuperConstr = Y.Base,
       
    43     SuperConstrProto = Y.Base.prototype,
       
    44 
       
    45     Node = function(node, restricted) {
       
    46         var config = null;
       
    47         this[UID] = Y.stamp(node);
       
    48         if (!this[UID]) { // stamp failed; likely IE non-HTMLElement
       
    49             this[UID] = Y.guid(); 
       
    50         }
       
    51 
       
    52         g_nodes[this[UID]] = node;
       
    53         Node._instances[this[UID]] = this;
       
    54 
       
    55         if (restricted) {
       
    56             config = {
       
    57                 restricted: restricted
       
    58             };
       
    59             g_restrict[this[UID]] = true; 
       
    60         }
       
    61 
       
    62         this._lazyAttrInit = true;
       
    63         this._silentInit = true;
       
    64         SuperConstr.call(this, config);
       
    65     },
       
    66 
       
    67     // used with previous/next/ancestor tests
       
    68     _wrapFn = function(fn) {
       
    69         var ret = null;
       
    70         if (fn) {
       
    71             ret = (typeof fn === 'string') ?
       
    72             function(n) {
       
    73                 return Y.Selector.test(n, fn);
       
    74             } : 
       
    75             function(n) {
       
    76                 return fn(Node.get(n));
       
    77             };
       
    78         }
       
    79 
       
    80         return ret;
       
    81     };
       
    82 // end "globals"
       
    83 
       
    84 Node.NAME = 'Node';
       
    85 
       
    86 Node.DOM_EVENTS = {
       
    87     abort: true,
       
    88     blur: true,
       
    89     change: true,
       
    90     click: true,
       
    91     close: true,
       
    92     command: true,
       
    93     contextmenu: true,
       
    94     drag: true,
       
    95     dragstart: true,
       
    96     dragenter: true,
       
    97     dragover: true,
       
    98     dragleave: true,
       
    99     dragend: true,
       
   100     drop: true,
       
   101     dblclick: true,
       
   102     error: true,
       
   103     focus: true,
       
   104     keydown: true,
       
   105     keypress: true,
       
   106     keyup: true,
       
   107     load: true,
       
   108     mousedown: true,
       
   109     mousemove: true,
       
   110     mouseout: true, 
       
   111     mouseover: true, 
       
   112     mouseup: true,
       
   113     mousemultiwheel: true,
       
   114     mousewheel: true,
       
   115     submit: true,
       
   116     mouseenter: true,
       
   117     mouseleave: true,
       
   118     scroll: true,
       
   119     reset: true,
       
   120     resize: true,
       
   121     select: true,
       
   122     textInput: true,
       
   123     unload: true
       
   124 };
       
   125 
       
   126 // Add custom event adaptors to this list.  This will make it so
       
   127 // that delegate, key, available, contentready, etc all will
       
   128 // be available through Node.on
       
   129 Y.mix(Node.DOM_EVENTS, Y.Env.evt.plugins);
       
   130 
       
   131 Node._instances = {};
       
   132 
       
   133 /**
       
   134  * Registers plugins to be instantiated at the class level (plugins 
       
   135  * which should be plugged into every instance of Node by default).
       
   136  *
       
   137  * @method Node.plug
       
   138  * @static
       
   139  *
       
   140  * @param {Function | Array} plugin Either the plugin class, an array of plugin classes or an array of objects (with fn and cfg properties defined)
       
   141  * @param {Object} config (Optional) If plugin is the plugin class, the configuration for the plugin
       
   142  */
       
   143 Node.plug = function() {
       
   144     var args = g_slice.call(arguments, 0);
       
   145     args.unshift(Node);
       
   146     Y.Base.plug.apply(Y.Base, args);
       
   147     return Node;
       
   148 };
       
   149 
       
   150 /**
       
   151  * Unregisters any class level plugins which have been registered by the Node
       
   152  *
       
   153  * @method Node.unplug
       
   154  * @static
       
   155  *
       
   156  * @param {Function | Array} plugin The plugin class, or an array of plugin classes
       
   157  */
       
   158 Node.unplug = function() {
       
   159     var args = g_slice.call(arguments, 0);
       
   160     args.unshift(Node);
       
   161     Y.Base.unplug.apply(Y.Base, args);
       
   162     return Node;
       
   163 };
       
   164 
       
   165 /**
       
   166  * Retrieves the DOM node bound to a Node instance
       
   167  * @method Node.getDOMNode
       
   168  * @static
       
   169  *
       
   170  * @param {Y.Node || HTMLNode} node The Node instance or an HTMLNode
       
   171  * @return {HTMLNode} The DOM node bound to the Node instance.  If a DOM node is passed
       
   172  * as the node argument, it is simply returned.
       
   173  */
       
   174 Node.getDOMNode = function(node) {
       
   175     if (node) {
       
   176         if (node instanceof Node) {
       
   177             node = g_nodes[node[UID]];
       
   178         } else if (!node[NODE_NAME] || Y.DOM.isWindow(node)) { // must already be a DOMNode 
       
   179             node = null;
       
   180         }
       
   181     }
       
   182     return node || null;
       
   183 };
       
   184  
       
   185 Node.scrubVal = function(val, node, depth) {
       
   186     if (node && val) { // only truthy values are risky
       
   187         if (typeof val === 'object' || typeof val === 'function') { // safari nodeList === function
       
   188             if (NODE_TYPE in val || Y.DOM.isWindow(val)) {// node || window
       
   189                 if (g_restrict[node[UID]] && !node.contains(val)) {
       
   190                     val = null; // not allowed to go outside of root node
       
   191                 } else {
       
   192                     val = Node.get(val);
       
   193                 }
       
   194             } else if (val.item || // dom collection or Node instance // TODO: check each node for restrict? block ancestor?
       
   195                     (val[0] && val[0][NODE_TYPE])) { // array of DOM Nodes
       
   196                 val = Y.all(val);
       
   197             } else {
       
   198                 depth = (depth === undefined) ? 4 : depth;
       
   199                 if (depth > 0) {
       
   200                     for (var i in val) { // TODO: test this and pull hasOwnProperty check if safe?
       
   201                         if (val.hasOwnProperty && val.hasOwnProperty(i)) {
       
   202                             val[i] = Node.scrubVal(val[i], node, --depth);
       
   203                         }
       
   204                     }
       
   205                 }
       
   206             }
       
   207         }
       
   208     } else if (val === undefined) {
       
   209         val = node; // for chaining
       
   210     }
       
   211 
       
   212     return val;
       
   213 };
       
   214 
       
   215 Node.addMethod = function(name, fn, context) {
       
   216     if (name && fn && typeof fn === 'function') {
       
   217         Node.prototype[name] = function() {
       
   218             context = context || this;
       
   219             var args = g_slice.call(arguments),
       
   220                 ret;
       
   221 
       
   222             if (args[0] && args[0] instanceof Node) {
       
   223                 args[0] = Node.getDOMNode(args[0]);
       
   224             }
       
   225 
       
   226             if (args[1] && args[1] instanceof Node) {
       
   227                 args[1] = Node.getDOMNode(args[1]);
       
   228             }
       
   229             args.unshift(g_nodes[this[UID]]);
       
   230             ret = Node.scrubVal(fn.apply(context, args), this);
       
   231             return ret;
       
   232         };
       
   233     } else {
       
   234         Y.log('unable to add method: ' + name, 'warn', 'Node');
       
   235     }
       
   236 };
       
   237 
       
   238 Node.importMethod = function(host, name, altName) {
       
   239     if (typeof name === 'string') {
       
   240         altName = altName || name;
       
   241         Node.addMethod(altName, host[name], host);
       
   242     } else {
       
   243         Y.each(name, function(n) {
       
   244             Node.importMethod(host, n);
       
   245         });
       
   246     }
       
   247 };
       
   248 
       
   249 /**
       
   250  * Returns a single Node instance bound to the node or the
       
   251  * first element matching the given selector.
       
   252  * @method Y.get
       
   253  * @static
       
   254  * @param {String | HTMLElement} node a node or Selector 
       
   255  * @param {Y.Node || HTMLElement} doc an optional document to scan. Defaults to Y.config.doc. 
       
   256  * @param {Boolean} restrict Whether or not the Node instance should be restricted to accessing
       
   257  * its subtree only.
       
   258  */
       
   259 Node.get = function(node, doc, restrict) {
       
   260     var instance = null;
       
   261 
       
   262     if (typeof node === 'string') {
       
   263         if (node.indexOf('doc') === 0) { // doc OR document
       
   264             node = Y.config.doc;
       
   265         } else if (node.indexOf('win') === 0) { // doc OR document
       
   266             node = Y.config.win;
       
   267         } else {
       
   268             node = Y.Selector.query(node, doc, true);
       
   269         }
       
   270     }
       
   271 
       
   272     if (node) {
       
   273         instance = Node._instances[node[UID]]; // reuse exising instances
       
   274         if (!instance) {
       
   275             instance = new Node(node, restrict);
       
   276         } else if (restrict) {
       
   277             g_restrict[instance[UID]] = true;
       
   278             instance._set('restricted', true);
       
   279         }
       
   280     }
       
   281     // TODO: restrict on subsequent call?
       
   282     return instance;
       
   283 };
       
   284 
       
   285 /**
       
   286  * Creates a new dom node using the provided markup string. 
       
   287  * @method create
       
   288  * @static
       
   289  * @param {String} html The markup used to create the element
       
   290  * @param {HTMLDocument} doc An optional document context 
       
   291  */
       
   292 Node.create = function() {
       
   293     return Node.get(Y.DOM.create.apply(Y.DOM, arguments));
       
   294 };
       
   295 
       
   296 Node.ATTRS = {
       
   297     /**
       
   298      * Allows for getting and setting the text of an element.
       
   299      * Formatting is preserved and special characters are treated literally.
       
   300      * @config text
       
   301      * @type String
       
   302      */
       
   303     text: {
       
   304         getter: function() {
       
   305             return Y.DOM.getText(g_nodes[this[UID]]);
       
   306         },
       
   307 
       
   308         setter: function(content) {
       
   309             Y.DOM.setText(g_nodes[this[UID]], content);
       
   310             return content;
       
   311         }
       
   312     },
       
   313 
       
   314     'options': {
       
   315         getter: function() {
       
   316             return this.getElementsByTagName('option');
       
   317         }
       
   318     },
       
   319 
       
   320     /**
       
   321      * Returns a NodeList instance of all HTMLElement children.
       
   322      * @readOnly
       
   323      * @config children
       
   324      * @type NodeList
       
   325      */
       
   326     'children': {
       
   327         getter: function() {
       
   328             var node = g_nodes[this[UID]],
       
   329                 children = node.children,
       
   330                 childNodes, i, len;
       
   331 
       
   332             if (children === undefined) {
       
   333                 childNodes = node.childNodes;
       
   334                 children = [];
       
   335 
       
   336                 for (i = 0, len = childNodes.length; i < len; ++i) {
       
   337                     if (childNodes[i][TAG_NAME]) {
       
   338                         children[children.length] = childNodes[i];
       
   339                     }
       
   340                 }
       
   341             }
       
   342             return Y.all(children);
       
   343         }
       
   344     },
       
   345 
       
   346     value: {
       
   347         getter: function() {
       
   348             return Y.DOM.getValue(g_nodes[this[UID]]);
       
   349         },
       
   350 
       
   351         setter: function(val) {
       
   352             Y.DOM.setValue(g_nodes[this[UID]], val);
       
   353             return val;
       
   354         }
       
   355     },
       
   356 
       
   357 /*
       
   358     style: {
       
   359         getter: function(attr) {
       
   360             return Y.DOM.getStyle(g_nodes[this[UID]].style, attr);
       
   361         }
       
   362     },
       
   363 */
       
   364 
       
   365     /**
       
   366      * Whether or not this Node can traverse outside of its subtree.
       
   367      * @config restricted
       
   368      * @writeOnce
       
   369      * @type Boolean
       
   370      */
       
   371     restricted: {
       
   372         writeOnce: true,
       
   373         value: false
       
   374     }
       
   375 };
       
   376 
       
   377 // call with instance context
       
   378 Node.DEFAULT_SETTER = function(name, val) {
       
   379     var node = g_nodes[this[UID]],
       
   380         strPath;
       
   381 
       
   382     if (name.indexOf(DOT) > -1) {
       
   383         strPath = name;
       
   384         name = name.split(DOT);
       
   385         Y.Object.setValue(node, name, val);
       
   386     } else if (node[name] !== undefined) { // only set DOM attributes
       
   387         node[name] = val;
       
   388     }
       
   389 
       
   390     return val;
       
   391 };
       
   392 
       
   393 // call with instance context
       
   394 Node.DEFAULT_GETTER = function(name) {
       
   395     var node = g_nodes[this[UID]],
       
   396         val;
       
   397 
       
   398     if (name.indexOf && name.indexOf(DOT) > -1) {
       
   399         val = Y.Object.getValue(node, name.split(DOT));
       
   400     } else {
       
   401         val = node[name];
       
   402     }
       
   403 
       
   404     return val ? Y.Node.scrubVal(val, this) : val;
       
   405 };
       
   406 
       
   407 Y.extend(Node, Y.Base);
       
   408 
       
   409 Y.mix(Node.prototype, {
       
   410     toString: function() {
       
   411         var str = '',
       
   412             errorMsg = this[UID] + ': not bound to a node',
       
   413             node = g_nodes[this[UID]];
       
   414 
       
   415         if (node) {
       
   416             str += node[NODE_NAME];
       
   417             if (node.id) {
       
   418                 str += '#' + node.id; 
       
   419             }
       
   420 
       
   421             if (node.className) {
       
   422                 str += '.' + node.className.replace(' ', '.'); 
       
   423             }
       
   424 
       
   425             // TODO: add yuid?
       
   426             str += ' ' + this[UID];
       
   427         }
       
   428         return str || errorMsg;
       
   429     },
       
   430 
       
   431     _addDOMAttr: function(attr) {
       
   432         var domNode = g_nodes[this[UID]];
       
   433 
       
   434         if (domNode && domNode[attr] !== undefined) {
       
   435             this.addAttr(attr, {
       
   436                 getter: function() {
       
   437                     return Node.DEFAULT_GETTER.call(this, attr);
       
   438                 },
       
   439 
       
   440                 setter: function(val) {
       
   441                     return Node.DEFAULT_SETTER.call(this, attr, val);
       
   442                 }
       
   443             });
       
   444         } else {
       
   445             Y.log('unable to add DOM attribute: ' + attr + ' to node: ' + this, 'warn', 'Node');
       
   446         }
       
   447     },
       
   448 
       
   449     get: function(attr) {
       
   450         if (!this.attrAdded(attr)) { // use DEFAULT_GETTER for unconfigured attrs
       
   451             if (Node.re_aria && Node.re_aria.test(attr)) { // except for aria
       
   452                 this._addAriaAttr(attr);
       
   453             } else {
       
   454                 return Node.DEFAULT_GETTER.apply(this, arguments);
       
   455             }
       
   456         }
       
   457 
       
   458         return SuperConstrProto.get.apply(this, arguments);
       
   459     },
       
   460 
       
   461     set: function(attr, val) {
       
   462         if (!this.attrAdded(attr)) { // use DEFAULT_SETTER for unconfigured attrs
       
   463             // except for aria
       
   464             if (Node.re_aria && Node.re_aria.test(attr)) {
       
   465                 this._addAriaAttr(attr);
       
   466             //  or chained properties or if no change listeners
       
   467             } else if (attr.indexOf(DOT) < 0 && this._yuievt.events['Node:' + attr + 'Change']) {
       
   468                 this._addDOMAttr(attr);
       
   469             } else {
       
   470                 Node.DEFAULT_SETTER.call(this, attr, val);
       
   471                 return this; // NOTE: return
       
   472             }
       
   473         }
       
   474         SuperConstrProto.set.apply(this, arguments);
       
   475         return this;
       
   476     },
       
   477 
       
   478     /**
       
   479      * Creates a new Node using the provided markup string. 
       
   480      * @method create
       
   481      * @param {String} html The markup used to create the element
       
   482      * @param {HTMLDocument} doc An optional document context 
       
   483      */
       
   484     create: Node.create,
       
   485 
       
   486     /**
       
   487      * Compares nodes to determine if they match.
       
   488      * Node instances can be compared to each other and/or HTMLElements.
       
   489      * @method compareTo
       
   490      * @param {HTMLElement | Node} refNode The reference node to compare to the node.
       
   491      * @return {Boolean} True if the nodes match, false if they do not. 
       
   492      */
       
   493     compareTo: function(refNode) {
       
   494         var node = g_nodes[this[UID]];
       
   495         if (refNode instanceof Y.Node) { 
       
   496             refNode = Y.Node.getDOMNode(refNode);
       
   497         }
       
   498         return node === refNode;
       
   499     },
       
   500 
       
   501     /**
       
   502      * Determines whether the node is appended to the document.
       
   503      * @method inDoc
       
   504      * @param {Node|HTMLElement} doc optional An optional document to check against.
       
   505      * Defaults to current document. 
       
   506      * @return {Boolean} Whether or not this node is appended to the document. 
       
   507      */
       
   508     inDoc: function(doc) {
       
   509         var node = g_nodes[this[UID]];
       
   510         doc = (doc) ? Node.getDOMNode(doc) : node[OWNER_DOCUMENT];
       
   511         if (doc.documentElement) {
       
   512             return Y.DOM.contains(doc.documentElement, node);
       
   513         }
       
   514     },
       
   515 
       
   516     getById: function(id) {
       
   517         var node = g_nodes[this[UID]],
       
   518             ret = Y.DOM.byId(id, node[OWNER_DOCUMENT]);
       
   519         if (ret && Y.DOM.contains(node, ret)) {
       
   520             ret = Y.get(ret);
       
   521         } else {
       
   522             ret = null;
       
   523         }
       
   524         return ret;
       
   525     },
       
   526 
       
   527    /**
       
   528      * Returns the nearest ancestor that passes the test applied by supplied boolean method.
       
   529      * @method ancestor
       
   530      * @param {String | Function} fn A selector or boolean method for testing elements.
       
   531      * If a function is used, it receives the current node being tested as the only argument.
       
   532      * @return {Node} The matching Node instance or null if not found
       
   533      */
       
   534     ancestor: function(fn) {
       
   535         return Node.get(Y.DOM.elementByAxis(g_nodes[this[UID]], 'parentNode', _wrapFn(fn)));
       
   536     },
       
   537 
       
   538     /**
       
   539      * Returns the previous matching sibling. 
       
   540      * Returns the nearest element node sibling if no method provided.
       
   541      * @method previous
       
   542      * @param {String | Function} fn A selector or boolean method for testing elements.
       
   543      * If a function is used, it receives the current node being tested as the only argument.
       
   544      * @return {Node} Node instance or null if not found
       
   545      */
       
   546     previous: function(fn, all) {
       
   547         return Node.get(Y.DOM.elementByAxis(g_nodes[this[UID]], 'previousSibling', _wrapFn(fn), all));
       
   548     }, 
       
   549 
       
   550     /**
       
   551      * Returns the next matching sibling. 
       
   552      * Returns the nearest element node sibling if no method provided.
       
   553      * @method next
       
   554      * @param {String | Function} fn A selector or boolean method for testing elements.
       
   555      * If a function is used, it receives the current node being tested as the only argument.
       
   556      * @return {Node} Node instance or null if not found
       
   557      */
       
   558     next: function(node, fn, all) {
       
   559         return Node.get(Y.DOM.elementByAxis(g_nodes[this[UID]], 'nextSibling', _wrapFn(fn), all));
       
   560     },
       
   561         
       
   562     /**
       
   563      * Retrieves a Node instance of nodes based on the given CSS selector. 
       
   564      * @method query
       
   565      *
       
   566      * @param {string} selector The CSS selector to test against.
       
   567      * @return {Node} A Node instance for the matching HTMLElement.
       
   568      */
       
   569     query: function(selector) {
       
   570         return Y.get(Y.Selector.query(selector, g_nodes[this[UID]], true));
       
   571     },
       
   572 
       
   573     /**
       
   574      * Retrieves a nodeList based on the given CSS selector. 
       
   575      * @method queryAll
       
   576      *
       
   577      * @param {string} selector The CSS selector to test against.
       
   578      * @return {NodeList} A NodeList instance for the matching HTMLCollection/Array.
       
   579      */
       
   580     queryAll: function(selector) {
       
   581         return Y.all(Y.Selector.query(selector, g_nodes[this[UID]]));
       
   582     },
       
   583 
       
   584     // TODO: allow fn test
       
   585     /**
       
   586      * Test if the supplied node matches the supplied selector.
       
   587      * @method test
       
   588      *
       
   589      * @param {string} selector The CSS selector to test against.
       
   590      * @return {boolean} Whether or not the node matches the selector.
       
   591      */
       
   592     test: function(selector) {
       
   593         return Y.Selector.test(g_nodes[this[UID]], selector);
       
   594     },
       
   595 
       
   596     /**
       
   597      * Removes the node from its parent.
       
   598      * Shortcut for myNode.get('parentNode').removeChild(myNode);
       
   599      * @method remove
       
   600      * @chainable
       
   601      *
       
   602      */
       
   603     remove: function() {
       
   604         var node = g_nodes[this[UID]];
       
   605         node.parentNode.removeChild(node);
       
   606         return this;
       
   607     },
       
   608 
       
   609     /**
       
   610      * Invokes a method on the Node instance 
       
   611      * @method invoke
       
   612      * @param {String} method The name of the method to invoke
       
   613      * @param {Any}  a, b, c, etc. Arguments to invoke the method with. 
       
   614      * @return Whatever the underly method returns. 
       
   615      * DOM Nodes and Collections return values
       
   616      * are converted to Node/NodeList instances.
       
   617      *
       
   618      */
       
   619     invoke: function(method, a, b, c, d, e) {
       
   620         var node = g_nodes[this[UID]],
       
   621             ret;
       
   622 
       
   623         if (a && a instanceof Y.Node) {
       
   624             a = Node.getDOMNode(a);
       
   625         }
       
   626 
       
   627         if (b && b instanceof Y.Node) {
       
   628             b = Node.getDOMNode(b);
       
   629         }
       
   630 
       
   631         ret = node[method](a, b, c, d, e);    
       
   632         return Y.Node.scrubVal(ret, this);
       
   633     },
       
   634 
       
   635     destructor: function() {
       
   636         // TODO: What about shared instances?
       
   637         //var uid = this[UID];
       
   638 
       
   639         //delete g_nodes[uid];
       
   640         //delete g_restrict[uid];
       
   641         //delete Node._instances[uid];
       
   642     },
       
   643 
       
   644     /**
       
   645      * Applies the given function to each Node in the NodeList.
       
   646      * @method each
       
   647      * @deprecated Use NodeList
       
   648      * @param {Function} fn The function to apply 
       
   649      * @param {Object} context optional An optional context to apply the function with
       
   650      * Default context is the NodeList instance
       
   651      * @chainable
       
   652      */
       
   653     each: function(fn, context) {
       
   654         context = context || this;
       
   655         Y.log('each is deprecated on Node', 'warn', 'Node');
       
   656         return fn.call(context, this);
       
   657     },
       
   658 
       
   659     /**
       
   660      * Retrieves the Node instance at the given index. 
       
   661      * @method item
       
   662      * @deprecated Use NodeList
       
   663      *
       
   664      * @param {Number} index The index of the target Node.
       
   665      * @return {Node} The Node instance at the given index.
       
   666      */
       
   667     item: function(index) {
       
   668         Y.log('item is deprecated on Node', 'warn', 'Node');
       
   669         return this;
       
   670     },
       
   671 
       
   672     /**
       
   673      * Returns the current number of items in the Node.
       
   674      * @method size
       
   675      * @deprecated Use NodeList
       
   676      * @return {Int} The number of items in the Node. 
       
   677      */
       
   678     size: function() {
       
   679         Y.log('size is deprecated on Node', 'warn', 'Node');
       
   680         return g_nodes[this[UID]] ? 1 : 0;
       
   681     },
       
   682 
       
   683     /**
       
   684      * Inserts the content before the reference node. 
       
   685      * @method insert
       
   686      * @param {String | Y.Node | HTMLElement} content The content to insert 
       
   687      * @param {Int | Y.Node | HTMLElement | String} where The position to insert at.
       
   688      * @chainable
       
   689      */
       
   690     insert: function(content, where) {
       
   691         if (content) {
       
   692             if (typeof where === 'number') { // allow index
       
   693                 where = g_nodes[this[UID]].childNodes[where];
       
   694             }
       
   695             if (typeof content !== 'string') { // pass the DOM node
       
   696                 content = Y.Node.getDOMNode(content);
       
   697             }
       
   698             if (!where || // only allow inserting into this Node's subtree
       
   699                 (!g_restrict[this[UID]] || 
       
   700                     (typeof where !== 'string' && this.contains(where)))) { 
       
   701                 Y.DOM.addHTML(g_nodes[this[UID]], content, where);
       
   702             }
       
   703         }
       
   704         return this;
       
   705     },
       
   706 
       
   707     /**
       
   708      * Inserts the content as the firstChild of the node. 
       
   709      * @method prepend
       
   710      * @param {String | Y.Node | HTMLElement} content The content to insert 
       
   711      * @chainable
       
   712      */
       
   713     prepend: function(content) {
       
   714         return this.insert(content, 0);
       
   715     },
       
   716 
       
   717     /**
       
   718      * Inserts the content as the lastChild of the node. 
       
   719      * @method append
       
   720      * @param {String | Y.Node | HTMLElement} content The content to insert 
       
   721      * @chainable
       
   722      */
       
   723     append: function(content) {
       
   724         return this.insert(content, null);
       
   725     },
       
   726 
       
   727     /**
       
   728      * Replaces the node's current content with the content.
       
   729      * @method setContent
       
   730      * @param {String | Y.Node | HTMLElement} content The content to insert 
       
   731      * @chainable
       
   732      */
       
   733     setContent: function(content) {
       
   734         Y.DOM.addHTML(g_nodes[this[UID]], content, 'replace');
       
   735         return this;
       
   736     },
       
   737 
       
   738     // TODO: need this?
       
   739     hasMethod: function(method) {
       
   740         var node = g_nodes[this[UID]];
       
   741         return (node && (typeof node === 'function'));
       
   742     }
       
   743 }, true);
       
   744 
       
   745 Y.Node = Node;
       
   746 Y.get = Y.Node.get;
       
   747 /**
       
   748  * The NodeList module provides support for managing collections of Nodes.
       
   749  * @module node
       
   750  * @submodule nodelist
       
   751  */    
       
   752 
       
   753 /**
       
   754  * The NodeList class provides a wrapper for manipulating DOM NodeLists.
       
   755  * NodeList properties can be accessed via the set/get methods.
       
   756  * Use Y.all() to retrieve NodeList instances.
       
   757  *
       
   758  * @class NodeList
       
   759  * @constructor
       
   760  */
       
   761 
       
   762 Y.Array._diff = function(a, b) {
       
   763     var removed = [],
       
   764         present = false,
       
   765         i, j, lenA, lenB;
       
   766 
       
   767     outer:
       
   768     for (i = 0, lenA = a.length; i < lenA; i++) {
       
   769         present = false;
       
   770         for (j = 0, lenB = b.length; j < lenB; j++) {
       
   771             if (a[i] === b[j]) {
       
   772                 present = true;
       
   773                 continue outer;
       
   774             }
       
   775         }
       
   776         if (!present) {
       
   777             removed[removed.length] = a[i];
       
   778         }
       
   779     }
       
   780     return removed;
       
   781 };
       
   782 
       
   783 Y.Array.diff = function(a, b) {
       
   784     return {
       
   785         added: Y.Array._diff(b, a),
       
   786         removed: Y.Array._diff(a, b)
       
   787     }; 
       
   788 };
       
   789 
       
   790 var NodeList = function(config) {
       
   791     var doc = config.doc || Y.config.doc,
       
   792         nodes = config.nodes || [];
       
   793 
       
   794     if (typeof nodes === 'string') {
       
   795         this._query = nodes;
       
   796         nodes = Y.Selector.query(nodes, doc);
       
   797     }
       
   798 
       
   799     Y.stamp(this);
       
   800     NodeList._instances[this[UID]] = this;
       
   801     g_nodelists[this[UID]] = nodes;
       
   802 
       
   803     if (config.restricted) {
       
   804         g_restrict = this[UID];
       
   805     }
       
   806 };
       
   807 // end "globals"
       
   808 
       
   809 NodeList.NAME = 'NodeList';
       
   810 
       
   811 /**
       
   812  * Retrieves the DOM nodes bound to a NodeList instance
       
   813  * @method NodeList.getDOMNodes
       
   814  * @static
       
   815  *
       
   816  * @param {Y.NodeList} node The NodeList instance
       
   817  * @return {Array} The array of DOM nodes bound to the NodeList
       
   818  */
       
   819 NodeList.getDOMNodes = function(nodeList) {
       
   820     return g_nodelists[nodeList[UID]];
       
   821 };
       
   822 
       
   823 NodeList._instances = [];
       
   824 
       
   825 NodeList.each = function(instance, fn, context) {
       
   826     var nodes = g_nodelists[instance[UID]];
       
   827     if (nodes && nodes.length) {
       
   828         Y.Array.each(nodes, fn, context || instance);
       
   829     } else {
       
   830         Y.log('no nodes bound to ' + this, 'warn', 'NodeList');
       
   831     }
       
   832 };
       
   833 
       
   834 NodeList.addMethod = function(name, fn, context) {
       
   835     var tmp = NodeList._getTempNode();
       
   836     if (name && fn) {
       
   837         NodeList.prototype[name] = function() {
       
   838             var ret = [],
       
   839                 args = arguments;
       
   840 
       
   841             Y.Array.each(g_nodelists[this[UID]], function(node) {
       
   842                 var UID = '_yuid',
       
   843                     instance = Y.Node._instances[node[UID]],
       
   844                     ctx,
       
   845                     result;
       
   846 
       
   847                 if (!instance) {
       
   848                     g_nodes[tmp[UID]] = node;
       
   849                     instance = tmp;
       
   850                 }
       
   851                 ctx = context || instance;
       
   852                 result = fn.apply(ctx, args);
       
   853                 if (result !== undefined && result !== instance) {
       
   854                     ret[ret.length] = result;
       
   855                 }
       
   856             });
       
   857 
       
   858             // TODO: remove tmp pointer
       
   859             return ret.length ? ret : this;
       
   860         };
       
   861     } else {
       
   862         Y.log('unable to add method: ' + name, 'warn', 'Node');
       
   863     }
       
   864 };
       
   865 
       
   866 NodeList.importMethod = function(host, name, altName) {
       
   867     if (typeof name === 'string') {
       
   868         altName = altName || name;
       
   869         NodeList.addMethod(name, host[name]);
       
   870     } else {
       
   871         Y.each(name, function(n) {
       
   872             NodeList.importMethod(host, n);
       
   873         });
       
   874     }
       
   875 };
       
   876 
       
   877 NodeList._getTempNode = function() {
       
   878     var tmp = NodeList._tempNode;
       
   879         if (!tmp) {
       
   880             tmp = Y.Node.create('<div></div>');
       
   881             NodeList._tempNode = tmp;
       
   882         }
       
   883     return tmp;
       
   884 };
       
   885 
       
   886 Y.mix(NodeList.prototype, {
       
   887     /**
       
   888      * Retrieves the Node instance at the given index. 
       
   889      * @method item
       
   890      *
       
   891      * @param {Number} index The index of the target Node.
       
   892      * @return {Node} The Node instance at the given index.
       
   893      */
       
   894     item: function(index) {
       
   895         return Y.get((g_nodelists[this[UID]] || [])[index]);
       
   896     },
       
   897 
       
   898     /**
       
   899      * Applies the given function to each Node in the NodeList.
       
   900      * @method each
       
   901      * @param {Function} fn The function to apply. It receives 3 arguments:
       
   902      * the current node instance, the node's index, and the NodeList instance
       
   903      * @param {Object} context optional An optional context to apply the function with
       
   904      * Default context is the current Node instance
       
   905      * @chainable
       
   906      */
       
   907     each: function(fn, context) {
       
   908         var instance = this;
       
   909         Y.Array.each(g_nodelists[this[UID]], function(node, index) {
       
   910             node = Y.get(node);
       
   911             return fn.call(context || node, node, index, instance);
       
   912         });
       
   913         return instance;
       
   914     },
       
   915 
       
   916     batch: function(fn, context) {
       
   917         var nodelist = this,
       
   918             tmp = NodeList._getTempNode();
       
   919 
       
   920         Y.Array.each(g_nodelists[this[UID]], function(node, index) {
       
   921             var instance = Y.Node._instances[node[UID]];
       
   922             if (!instance) {
       
   923                 g_nodes[tmp[UID]] = node;
       
   924                 instance = tmp;
       
   925             }
       
   926 
       
   927             return fn.call(context || instance, instance, index, nodelist);
       
   928         });
       
   929         return nodelist;
       
   930     },
       
   931 
       
   932     /**
       
   933      * Executes the function once for each node until a true value is returned.
       
   934      * @method some
       
   935      * @param {Function} fn The function to apply. It receives 3 arguments:
       
   936      * the current node instance, the node's index, and the NodeList instance
       
   937      * @param {Object} context optional An optional context to execute the function from.
       
   938      * Default context is the current Node instance
       
   939      * @return {Boolean} Whether or not the function returned true for any node.
       
   940      */
       
   941     some: function(fn, context) {
       
   942         var instance = this;
       
   943         return Y.Array.some(g_nodelists[this[UID]], function(node, index) {
       
   944             node = Y.get(node);
       
   945             context = context || node;
       
   946             return fn.call(context, node, index, instance);
       
   947         });
       
   948     },
       
   949 
       
   950     /**
       
   951      * Returns the index of the node in the NodeList instance
       
   952      * or -1 if the node isn't found.
       
   953      * @method indexOf
       
   954      * @param {Y.Node || DOMNode} node the node to search for
       
   955      * @return {Int} the index of the node value or -1 if not found
       
   956      */
       
   957     indexOf: function(node) {
       
   958         return Y.Array.indexOf(g_nodelists[this[UID]], Y.Node.getDOMNode(node));
       
   959     },
       
   960 
       
   961     /**
       
   962      * Filters the NodeList instance down to only nodes matching the given selector.
       
   963      * @method filter
       
   964      * @param {String} selector The selector to filter against
       
   965      * @return {NodeList} NodeList containing the updated collection 
       
   966      * @see Selector
       
   967      */
       
   968     filter: function(selector) {
       
   969         return Y.all(Y.Selector.filter(g_nodelists[this[UID]], selector));
       
   970     },
       
   971 
       
   972     modulus: function(n, r) {
       
   973         r = r || 0;
       
   974         var nodes = [];
       
   975         NodeList.each(this, function(node, i) {
       
   976             if (i % n === r) {
       
   977                 nodes.push(node);
       
   978             }
       
   979         });
       
   980 
       
   981         return Y.all(nodes);
       
   982     },
       
   983 
       
   984     /**
       
   985      * Creates a new NodeList containing all nodes at odd indices
       
   986      * (zero-based index).
       
   987      * @method odd
       
   988      * @return {NodeList} NodeList containing the updated collection 
       
   989      */
       
   990     odd: function() {
       
   991         return this.modulus(2, 1);
       
   992     },
       
   993 
       
   994     /**
       
   995      * Creates a new NodeList containing all nodes at even indices
       
   996      * (zero-based index), including zero. 
       
   997      * @method even
       
   998      * @return {NodeList} NodeList containing the updated collection 
       
   999      */
       
  1000     even: function() {
       
  1001         return this.modulus(2);
       
  1002     },
       
  1003 
       
  1004     destructor: function() {
       
  1005         delete NodeList._instances[this[UID]];
       
  1006     },
       
  1007 
       
  1008     refresh: function() {
       
  1009         var doc,
       
  1010             diff,
       
  1011             oldList = g_nodelists[this[UID]];
       
  1012         if (this._query) {
       
  1013             if (g_nodelists[this[UID]] &&
       
  1014                     g_nodelists[this[UID]][0] && 
       
  1015                     g_nodelists[this[UID]][0].ownerDocument) {
       
  1016                 doc = g_nodelists[this[UID]][0].ownerDocument;
       
  1017             }
       
  1018 
       
  1019             g_nodelists[this[UID]] = Y.Selector.query(this._query, doc || Y.config.doc);        
       
  1020             diff = Y.Array.diff(oldList, g_nodelists[this[UID]]); 
       
  1021             diff.added = diff.added ? Y.all(diff.added) : null;
       
  1022             diff.removed = diff.removed ? Y.all(diff.removed) : null;
       
  1023             this.fire('refresh', diff);
       
  1024         }
       
  1025         return this;
       
  1026     },
       
  1027 
       
  1028     /**
       
  1029      * Applies an event listens to each Node bound to the NodeList. 
       
  1030      * @method on
       
  1031      * @param {String} type The event being listened for
       
  1032      * @param {Function} fn The handler to call when the event fires
       
  1033      * @param {Object} context The context to call the handler with.
       
  1034      * Default is the NodeList instance. 
       
  1035      * @return {Object} Returns an event handle that can later be use to detach(). 
       
  1036      * @see Event.on
       
  1037      */
       
  1038     on: function(type, fn, context) {
       
  1039         context = context || this;
       
  1040         this.batch(function(node) {
       
  1041             node.on.call(node, type, fn, context);
       
  1042         });
       
  1043     },
       
  1044 
       
  1045     /**
       
  1046      * Applies an event listens to each Node bound to the NodeList. 
       
  1047      * The handler is called only after all on() handlers are called
       
  1048      * and the event is not prevented.
       
  1049      * @method after
       
  1050      * @param {String} type The event being listened for
       
  1051      * @param {Function} fn The handler to call when the event fires
       
  1052      * @param {Object} context The context to call the handler with.
       
  1053      * Default is the NodeList instance. 
       
  1054      * @return {Object} Returns an event handle that can later be use to detach(). 
       
  1055      * @see Event.on
       
  1056      */
       
  1057     after: function(type, fn, context) {
       
  1058         context = context || this;
       
  1059         this.batch(function(node) {
       
  1060             node.after.call(node, type, fn, context);
       
  1061         });
       
  1062     },
       
  1063 
       
  1064     /**
       
  1065      * Returns the current number of items in the NodeList.
       
  1066      * @method size
       
  1067      * @return {Int} The number of items in the NodeList. 
       
  1068      */
       
  1069     size: function() {
       
  1070         return g_nodelists[this[UID]].length;
       
  1071     },
       
  1072 
       
  1073     /** Called on each Node instance
       
  1074       * @get
       
  1075       * @see Node
       
  1076       */
       
  1077     // one-off because we cant import from Node due to undefined return values
       
  1078     get: function(name) {
       
  1079         var ret = [],
       
  1080             tmp = NodeList._getTempNode();
       
  1081 
       
  1082         NodeList.each(this, function(node) {
       
  1083             var instance = Y.Node._instances[node[UID]];
       
  1084             if (!instance) {
       
  1085                 g_nodes[tmp[UID]] = node;
       
  1086                 instance = tmp;
       
  1087             }
       
  1088             ret[ret.length] = instance.get(name);
       
  1089         });
       
  1090 
       
  1091         return ret;
       
  1092     },
       
  1093 
       
  1094     toString: function() {
       
  1095         var str = '',
       
  1096             errorMsg = this[UID] + ': not bound to any nodes',
       
  1097             nodes = g_nodelists[this[UID]],
       
  1098             node;
       
  1099 
       
  1100         if (nodes && nodes[0]) {
       
  1101             node = nodes[0];
       
  1102             str += node[NODE_NAME];
       
  1103             if (node.id) {
       
  1104                 str += '#' + node.id; 
       
  1105             }
       
  1106 
       
  1107             if (node.className) {
       
  1108                 str += '.' + node.className.replace(' ', '.'); 
       
  1109             }
       
  1110 
       
  1111             if (nodes.length > 1) {
       
  1112                 str += '...[' + nodes.length + ' items]';
       
  1113             }
       
  1114         }
       
  1115         return str || errorMsg;
       
  1116     }
       
  1117 
       
  1118 }, true);
       
  1119 
       
  1120 NodeList.importMethod(Y.Node.prototype, [
       
  1121     /**
       
  1122      * Called on each Node instance
       
  1123      * @for NodeList
       
  1124      * @method append
       
  1125      * @see Node.append
       
  1126      */
       
  1127     'append',
       
  1128 
       
  1129     /**
       
  1130       * Called on each Node instance
       
  1131       * @method detach
       
  1132       * @see Node.detach
       
  1133       */
       
  1134     'detach',
       
  1135     
       
  1136     /** Called on each Node instance
       
  1137       * @method detachAll
       
  1138       * @see Node.detachAll
       
  1139       */
       
  1140     'detachAll',
       
  1141 
       
  1142     /** Called on each Node instance
       
  1143       * @method insert
       
  1144       * @see NodeInsert
       
  1145       */
       
  1146     'insert',
       
  1147 
       
  1148     /** Called on each Node instance
       
  1149       * @method plug
       
  1150       * @see Node.plug
       
  1151       */
       
  1152     'plug',
       
  1153 
       
  1154     /** Called on each Node instance
       
  1155       * @method prepend
       
  1156       * @see Node.prepend
       
  1157       */
       
  1158     'prepend',
       
  1159 
       
  1160     /** Called on each Node instance
       
  1161       * @method remove
       
  1162       * @see Node.remove
       
  1163       */
       
  1164     'remove',
       
  1165 
       
  1166     /** Called on each Node instance
       
  1167       * @method set
       
  1168       * @see Node.set
       
  1169       */
       
  1170     'set',
       
  1171 
       
  1172     /** Called on each Node instance
       
  1173       * @method setContent
       
  1174       * @see Node.setContent
       
  1175       */
       
  1176     'setContent',
       
  1177 
       
  1178     /** Called on each Node instance
       
  1179       * @method unplug
       
  1180       * @see Node.unplug
       
  1181       */
       
  1182     'unplug'
       
  1183 ]);
       
  1184 
       
  1185 Y.NodeList = NodeList;
       
  1186 Y.all = function(nodes, doc, restrict) {
       
  1187     // TODO: propagate restricted to nodes?
       
  1188     var nodeList = new NodeList({
       
  1189         nodes: nodes,
       
  1190         doc: doc,
       
  1191         restricted: restrict
       
  1192     });
       
  1193 
       
  1194     // zero-length result returns null
       
  1195     return nodeList;
       
  1196 };
       
  1197 Y.Node.all = Y.all; // TODO: deprecated
       
  1198 Y.Array.each([
       
  1199     /**
       
  1200      * Passes through to DOM method.
       
  1201      * @method replaceChild
       
  1202      * @for Node
       
  1203      * @param {HTMLElement | Node} node Node to be inserted 
       
  1204      * @param {HTMLElement | Node} refNode Node to be replaced 
       
  1205      * @return {Node} The replaced node 
       
  1206      */
       
  1207     'replaceChild',
       
  1208 
       
  1209     /**
       
  1210      * Passes through to DOM method.
       
  1211      * @method appendChild
       
  1212      * @param {HTMLElement | Node} node Node to be appended 
       
  1213      * @return {Node} The appended node 
       
  1214      */
       
  1215     'appendChild',
       
  1216 
       
  1217     /**
       
  1218      * Passes through to DOM method.
       
  1219      * @method insertBefore
       
  1220      * @param {HTMLElement | Node} newNode Node to be appended 
       
  1221      * @param {HTMLElement | Node} refNode Node to be inserted before 
       
  1222      * @return {Node} The inserted node 
       
  1223      */
       
  1224     'insertBefore',
       
  1225 
       
  1226     /**
       
  1227      * Passes through to DOM method.
       
  1228      * @method removeChild
       
  1229      * @param {HTMLElement | Node} node Node to be removed 
       
  1230      * @return {Node} The removed node 
       
  1231      */
       
  1232     'removeChild',
       
  1233 
       
  1234     /**
       
  1235      * Passes through to DOM method.
       
  1236      * @method hasChildNodes
       
  1237      * @return {Boolean} Whether or not the node has any childNodes 
       
  1238      */
       
  1239     'hasChildNodes',
       
  1240 
       
  1241     /**
       
  1242      * Passes through to DOM method.
       
  1243      * @method cloneNode
       
  1244      * @param {HTMLElement | Node} node Node to be cloned 
       
  1245      * @return {Node} The clone 
       
  1246      */
       
  1247     'cloneNode',
       
  1248 
       
  1249     /**
       
  1250      * Passes through to DOM method.
       
  1251      * @method hasAttribute
       
  1252      * @param {String} attribute The attribute to test for 
       
  1253      * @return {Boolean} Whether or not the attribute is present 
       
  1254      */
       
  1255     'hasAttribute',
       
  1256 
       
  1257     /**
       
  1258      * Passes through to DOM method.
       
  1259      * @method removeAttribute
       
  1260      * @param {String} attribute The attribute to be removed 
       
  1261      * @chainable
       
  1262      */
       
  1263     'removeAttribute',
       
  1264 
       
  1265     /**
       
  1266      * Passes through to DOM method.
       
  1267      * @method scrollIntoView
       
  1268      * @chainable
       
  1269      */
       
  1270     'scrollIntoView',
       
  1271 
       
  1272     /**
       
  1273      * Passes through to DOM method.
       
  1274      * @method getElementsByTagName
       
  1275      * @param {String} tagName The tagName to collect 
       
  1276      * @return {NodeList} A NodeList representing the HTMLCollection
       
  1277      */
       
  1278     'getElementsByTagName',
       
  1279 
       
  1280     /**
       
  1281      * Passes through to DOM method.
       
  1282      * @method focus
       
  1283      * @chainable
       
  1284      */
       
  1285     'focus',
       
  1286 
       
  1287     /**
       
  1288      * Passes through to DOM method.
       
  1289      * @method blur
       
  1290      * @chainable
       
  1291      */
       
  1292     'blur',
       
  1293 
       
  1294     /**
       
  1295      * Passes through to DOM method.
       
  1296      * Only valid on FORM elements
       
  1297      * @method submit
       
  1298      * @chainable
       
  1299      */
       
  1300     'submit',
       
  1301 
       
  1302     /**
       
  1303      * Passes through to DOM method.
       
  1304      * Only valid on FORM elements
       
  1305      * @method reset
       
  1306      * @chainable
       
  1307      */
       
  1308     'reset',
       
  1309 
       
  1310     /**
       
  1311      * Passes through to DOM method.
       
  1312      * @method select
       
  1313      * @chainable
       
  1314      */
       
  1315      'select'
       
  1316 ], function(method) {
       
  1317     Y.Node.prototype[method] = function(arg1, arg2, arg3) {
       
  1318         var ret = this.invoke(method, arg1, arg2, arg3);
       
  1319         return ret;
       
  1320     };
       
  1321 });
       
  1322 
       
  1323 Node.importMethod(Y.DOM, [
       
  1324     /**
       
  1325      * Determines whether the ndoe is an ancestor of another HTML element in the DOM hierarchy.
       
  1326      * @method contains
       
  1327      * @param {Node | HTMLElement} needle The possible node or descendent
       
  1328      * @return {Boolean} Whether or not this node is the needle its ancestor
       
  1329      */
       
  1330     'contains',
       
  1331     /**
       
  1332      * Allows setting attributes on DOM nodes, normalizing in some cases.
       
  1333      * This passes through to the DOM node, allowing for custom attributes.
       
  1334      * @method setAttribute
       
  1335      * @for Node
       
  1336      * @for NodeList
       
  1337      * @chainable
       
  1338      * @param {string} name The attribute name 
       
  1339      * @param {string} value The value to set
       
  1340      */
       
  1341     'setAttribute',
       
  1342     /**
       
  1343      * Allows getting attributes on DOM nodes, normalizing in some cases.
       
  1344      * This passes through to the DOM node, allowing for custom attributes.
       
  1345      * @method getAttribute
       
  1346      * @for Node
       
  1347      * @for NodeList
       
  1348      * @param {string} name The attribute name 
       
  1349      * @return {string} The attribute value 
       
  1350      */
       
  1351     'getAttribute'
       
  1352 ]);
       
  1353 
       
  1354 if (!document.documentElement.hasAttribute) { // IE < 8
       
  1355     Y.Node.prototype.hasAttribute = function(attr) {
       
  1356         return Y.DOM.getAttribute(Y.Node.getDOMNode(this), attr) !== '';
       
  1357     };
       
  1358 }
       
  1359 
       
  1360 /**
       
  1361  * Allows setting attributes on DOM nodes, normalizing in some cases.
       
  1362  * This passes through to the DOM node, allowing for custom attributes.
       
  1363  * @method setAttribute
       
  1364  * @see Node
       
  1365  * @for NodeList
       
  1366  * @chainable
       
  1367  * @param {string} name The attribute name 
       
  1368  * @param {string} value The value to set
       
  1369  */
       
  1370 
       
  1371 /**
       
  1372  * Allows getting attributes on DOM nodes, normalizing in some cases.
       
  1373  * This passes through to the DOM node, allowing for custom attributes.
       
  1374  * @method getAttribute
       
  1375  * @see Node
       
  1376  * @for NodeList
       
  1377  * @param {string} name The attribute name 
       
  1378  * @return {string} The attribute value 
       
  1379  */
       
  1380 Y.NodeList.importMethod(Y.Node.prototype, ['getAttribute', 'setAttribute']);
       
  1381 
       
  1382 (function() { // IE clones expandos; regenerate UID
       
  1383     var node = document.createElement('div'),
       
  1384         UID = '_yuid';
       
  1385 
       
  1386     Y.stamp(node);
       
  1387     if (node[UID] === node.cloneNode(true)[UID]) {
       
  1388         Y.Node.prototype.cloneNode = function(deep) {
       
  1389             var node = Y.Node.getDOMNode(this).cloneNode(deep);
       
  1390             node[UID] = Y.guid();
       
  1391             return Y.get(node);
       
  1392         };
       
  1393     }
       
  1394 })();
       
  1395 (function(Y) {
       
  1396     var methods = [
       
  1397     /**
       
  1398      * Determines whether each node has the given className.
       
  1399      * @method hasClass
       
  1400      * @for Node
       
  1401      * @param {String} className the class name to search for
       
  1402      * @return {Array} An array of booleans for each node bound to the NodeList. 
       
  1403      */
       
  1404      'hasClass',
       
  1405 
       
  1406     /**
       
  1407      * Adds a class name to each node.
       
  1408      * @method addClass         
       
  1409      * @param {String} className the class name to add to the node's class attribute
       
  1410      * @chainable
       
  1411      */
       
  1412      'addClass',
       
  1413 
       
  1414     /**
       
  1415      * Removes a class name from each node.
       
  1416      * @method removeClass         
       
  1417      * @param {String} className the class name to remove from the node's class attribute
       
  1418      * @chainable
       
  1419      */
       
  1420      'removeClass',
       
  1421 
       
  1422     /**
       
  1423      * Replace a class with another class for each node.
       
  1424      * If no oldClassName is present, the newClassName is simply added.
       
  1425      * @method replaceClass  
       
  1426      * @param {String} oldClassName the class name to be replaced
       
  1427      * @param {String} newClassName the class name that will be replacing the old class name
       
  1428      * @chainable
       
  1429      */
       
  1430      'replaceClass',
       
  1431 
       
  1432     /**
       
  1433      * If the className exists on the node it is removed, if it doesn't exist it is added.
       
  1434      * @method toggleClass  
       
  1435      * @param {String} className the class name to be toggled
       
  1436      * @chainable
       
  1437      */
       
  1438      'toggleClass'
       
  1439     ];
       
  1440 
       
  1441     Y.Node.importMethod(Y.DOM, methods);
       
  1442     /**
       
  1443      * Determines whether each node has the given className.
       
  1444      * @method hasClass
       
  1445      * @see Node.hasClass
       
  1446      * @for NodeList
       
  1447      * @param {String} className the class name to search for
       
  1448      * @return {Array} An array of booleans for each node bound to the NodeList. 
       
  1449      */
       
  1450 
       
  1451     /**
       
  1452      * Adds a class name to each node.
       
  1453      * @method addClass         
       
  1454      * @see Node.addClass
       
  1455      * @param {String} className the class name to add to the node's class attribute
       
  1456      * @chainable
       
  1457      */
       
  1458 
       
  1459     /**
       
  1460      * Removes a class name from each node.
       
  1461      * @method removeClass         
       
  1462      * @see Node.removeClass
       
  1463      * @param {String} className the class name to remove from the node's class attribute
       
  1464      * @chainable
       
  1465      */
       
  1466 
       
  1467     /**
       
  1468      * Replace a class with another class for each node.
       
  1469      * If no oldClassName is present, the newClassName is simply added.
       
  1470      * @method replaceClass  
       
  1471      * @see Node.replaceClass
       
  1472      * @param {String} oldClassName the class name to be replaced
       
  1473      * @param {String} newClassName the class name that will be replacing the old class name
       
  1474      * @chainable
       
  1475      */
       
  1476 
       
  1477     /**
       
  1478      * If the className exists on the node it is removed, if it doesn't exist it is added.
       
  1479      * @method toggleClass  
       
  1480      * @see Node.toggleClass
       
  1481      * @param {String} className the class name to be toggled
       
  1482      * @chainable
       
  1483      */
       
  1484     Y.NodeList.importMethod(Y.Node.prototype, methods);
       
  1485 })(Y);
       
  1486 /**
       
  1487  * Functionality to make the node a delegated event container
       
  1488  * @module node
       
  1489  * @submodule node-event-delegate
       
  1490  */
       
  1491 
       
  1492 /**
       
  1493  * Functionality to make the node a delegated event container
       
  1494  * @method delegate
       
  1495  * @param type {String} the event type to delegate
       
  1496  * @param fn {Function} the function to execute
       
  1497  * @param selector {String} a selector that must match the target of the event.
       
  1498  * @return {Event.Handle} the detach handle
       
  1499  * @for Node
       
  1500  */
       
  1501 Y.Node.prototype.delegate = function(type, fn, selector, context) {
       
  1502     context = context || this;
       
  1503     var args = Array.prototype.slice.call(arguments, 4),
       
  1504         a = ['delegate', fn, Y.Node.getDOMNode(this), type, selector, context];
       
  1505     a = a.concat(args);
       
  1506     return Y.on.apply(Y, a);
       
  1507 };
       
  1508 
       
  1509 
       
  1510 
       
  1511 }, '3.0.0b1' ,{requires:['dom-base', 'base', 'selector']});