src/cm/media/js/lib/yui/yui_3.0.0b1/build/node/node.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     }
       
   235 };
       
   236 
       
   237 Node.importMethod = function(host, name, altName) {
       
   238     if (typeof name === 'string') {
       
   239         altName = altName || name;
       
   240         Node.addMethod(altName, host[name], host);
       
   241     } else {
       
   242         Y.each(name, function(n) {
       
   243             Node.importMethod(host, n);
       
   244         });
       
   245     }
       
   246 };
       
   247 
       
   248 /**
       
   249  * Returns a single Node instance bound to the node or the
       
   250  * first element matching the given selector.
       
   251  * @method Y.get
       
   252  * @static
       
   253  * @param {String | HTMLElement} node a node or Selector 
       
   254  * @param {Y.Node || HTMLElement} doc an optional document to scan. Defaults to Y.config.doc. 
       
   255  * @param {Boolean} restrict Whether or not the Node instance should be restricted to accessing
       
   256  * its subtree only.
       
   257  */
       
   258 Node.get = function(node, doc, restrict) {
       
   259     var instance = null;
       
   260 
       
   261     if (typeof node === 'string') {
       
   262         if (node.indexOf('doc') === 0) { // doc OR document
       
   263             node = Y.config.doc;
       
   264         } else if (node.indexOf('win') === 0) { // doc OR document
       
   265             node = Y.config.win;
       
   266         } else {
       
   267             node = Y.Selector.query(node, doc, true);
       
   268         }
       
   269     }
       
   270 
       
   271     if (node) {
       
   272         instance = Node._instances[node[UID]]; // reuse exising instances
       
   273         if (!instance) {
       
   274             instance = new Node(node, restrict);
       
   275         } else if (restrict) {
       
   276             g_restrict[instance[UID]] = true;
       
   277             instance._set('restricted', true);
       
   278         }
       
   279     }
       
   280     // TODO: restrict on subsequent call?
       
   281     return instance;
       
   282 };
       
   283 
       
   284 /**
       
   285  * Creates a new dom node using the provided markup string. 
       
   286  * @method create
       
   287  * @static
       
   288  * @param {String} html The markup used to create the element
       
   289  * @param {HTMLDocument} doc An optional document context 
       
   290  */
       
   291 Node.create = function() {
       
   292     return Node.get(Y.DOM.create.apply(Y.DOM, arguments));
       
   293 };
       
   294 
       
   295 Node.ATTRS = {
       
   296     /**
       
   297      * Allows for getting and setting the text of an element.
       
   298      * Formatting is preserved and special characters are treated literally.
       
   299      * @config text
       
   300      * @type String
       
   301      */
       
   302     text: {
       
   303         getter: function() {
       
   304             return Y.DOM.getText(g_nodes[this[UID]]);
       
   305         },
       
   306 
       
   307         setter: function(content) {
       
   308             Y.DOM.setText(g_nodes[this[UID]], content);
       
   309             return content;
       
   310         }
       
   311     },
       
   312 
       
   313     'options': {
       
   314         getter: function() {
       
   315             return this.getElementsByTagName('option');
       
   316         }
       
   317     },
       
   318 
       
   319     /**
       
   320      * Returns a NodeList instance of all HTMLElement children.
       
   321      * @readOnly
       
   322      * @config children
       
   323      * @type NodeList
       
   324      */
       
   325     'children': {
       
   326         getter: function() {
       
   327             var node = g_nodes[this[UID]],
       
   328                 children = node.children,
       
   329                 childNodes, i, len;
       
   330 
       
   331             if (children === undefined) {
       
   332                 childNodes = node.childNodes;
       
   333                 children = [];
       
   334 
       
   335                 for (i = 0, len = childNodes.length; i < len; ++i) {
       
   336                     if (childNodes[i][TAG_NAME]) {
       
   337                         children[children.length] = childNodes[i];
       
   338                     }
       
   339                 }
       
   340             }
       
   341             return Y.all(children);
       
   342         }
       
   343     },
       
   344 
       
   345     value: {
       
   346         getter: function() {
       
   347             return Y.DOM.getValue(g_nodes[this[UID]]);
       
   348         },
       
   349 
       
   350         setter: function(val) {
       
   351             Y.DOM.setValue(g_nodes[this[UID]], val);
       
   352             return val;
       
   353         }
       
   354     },
       
   355 
       
   356 /*
       
   357     style: {
       
   358         getter: function(attr) {
       
   359             return Y.DOM.getStyle(g_nodes[this[UID]].style, attr);
       
   360         }
       
   361     },
       
   362 */
       
   363 
       
   364     /**
       
   365      * Whether or not this Node can traverse outside of its subtree.
       
   366      * @config restricted
       
   367      * @writeOnce
       
   368      * @type Boolean
       
   369      */
       
   370     restricted: {
       
   371         writeOnce: true,
       
   372         value: false
       
   373     }
       
   374 };
       
   375 
       
   376 // call with instance context
       
   377 Node.DEFAULT_SETTER = function(name, val) {
       
   378     var node = g_nodes[this[UID]],
       
   379         strPath;
       
   380 
       
   381     if (name.indexOf(DOT) > -1) {
       
   382         strPath = name;
       
   383         name = name.split(DOT);
       
   384         Y.Object.setValue(node, name, val);
       
   385     } else if (node[name] !== undefined) { // only set DOM attributes
       
   386         node[name] = val;
       
   387     }
       
   388 
       
   389     return val;
       
   390 };
       
   391 
       
   392 // call with instance context
       
   393 Node.DEFAULT_GETTER = function(name) {
       
   394     var node = g_nodes[this[UID]],
       
   395         val;
       
   396 
       
   397     if (name.indexOf && name.indexOf(DOT) > -1) {
       
   398         val = Y.Object.getValue(node, name.split(DOT));
       
   399     } else {
       
   400         val = node[name];
       
   401     }
       
   402 
       
   403     return val ? Y.Node.scrubVal(val, this) : val;
       
   404 };
       
   405 
       
   406 Y.extend(Node, Y.Base);
       
   407 
       
   408 Y.mix(Node.prototype, {
       
   409     toString: function() {
       
   410         var str = '',
       
   411             errorMsg = this[UID] + ': not bound to a node',
       
   412             node = g_nodes[this[UID]];
       
   413 
       
   414         if (node) {
       
   415             str += node[NODE_NAME];
       
   416             if (node.id) {
       
   417                 str += '#' + node.id; 
       
   418             }
       
   419 
       
   420             if (node.className) {
       
   421                 str += '.' + node.className.replace(' ', '.'); 
       
   422             }
       
   423 
       
   424             // TODO: add yuid?
       
   425             str += ' ' + this[UID];
       
   426         }
       
   427         return str || errorMsg;
       
   428     },
       
   429 
       
   430     _addDOMAttr: function(attr) {
       
   431         var domNode = g_nodes[this[UID]];
       
   432 
       
   433         if (domNode && domNode[attr] !== undefined) {
       
   434             this.addAttr(attr, {
       
   435                 getter: function() {
       
   436                     return Node.DEFAULT_GETTER.call(this, attr);
       
   437                 },
       
   438 
       
   439                 setter: function(val) {
       
   440                     return Node.DEFAULT_SETTER.call(this, attr, val);
       
   441                 }
       
   442             });
       
   443         } else {
       
   444         }
       
   445     },
       
   446 
       
   447     get: function(attr) {
       
   448         if (!this.attrAdded(attr)) { // use DEFAULT_GETTER for unconfigured attrs
       
   449             if (Node.re_aria && Node.re_aria.test(attr)) { // except for aria
       
   450                 this._addAriaAttr(attr);
       
   451             } else {
       
   452                 return Node.DEFAULT_GETTER.apply(this, arguments);
       
   453             }
       
   454         }
       
   455 
       
   456         return SuperConstrProto.get.apply(this, arguments);
       
   457     },
       
   458 
       
   459     set: function(attr, val) {
       
   460         if (!this.attrAdded(attr)) { // use DEFAULT_SETTER for unconfigured attrs
       
   461             // except for aria
       
   462             if (Node.re_aria && Node.re_aria.test(attr)) {
       
   463                 this._addAriaAttr(attr);
       
   464             //  or chained properties or if no change listeners
       
   465             } else if (attr.indexOf(DOT) < 0 && this._yuievt.events['Node:' + attr + 'Change']) {
       
   466                 this._addDOMAttr(attr);
       
   467             } else {
       
   468                 Node.DEFAULT_SETTER.call(this, attr, val);
       
   469                 return this; // NOTE: return
       
   470             }
       
   471         }
       
   472         SuperConstrProto.set.apply(this, arguments);
       
   473         return this;
       
   474     },
       
   475 
       
   476     /**
       
   477      * Creates a new Node using the provided markup string. 
       
   478      * @method create
       
   479      * @param {String} html The markup used to create the element
       
   480      * @param {HTMLDocument} doc An optional document context 
       
   481      */
       
   482     create: Node.create,
       
   483 
       
   484     /**
       
   485      * Compares nodes to determine if they match.
       
   486      * Node instances can be compared to each other and/or HTMLElements.
       
   487      * @method compareTo
       
   488      * @param {HTMLElement | Node} refNode The reference node to compare to the node.
       
   489      * @return {Boolean} True if the nodes match, false if they do not. 
       
   490      */
       
   491     compareTo: function(refNode) {
       
   492         var node = g_nodes[this[UID]];
       
   493         if (refNode instanceof Y.Node) { 
       
   494             refNode = Y.Node.getDOMNode(refNode);
       
   495         }
       
   496         return node === refNode;
       
   497     },
       
   498 
       
   499     /**
       
   500      * Determines whether the node is appended to the document.
       
   501      * @method inDoc
       
   502      * @param {Node|HTMLElement} doc optional An optional document to check against.
       
   503      * Defaults to current document. 
       
   504      * @return {Boolean} Whether or not this node is appended to the document. 
       
   505      */
       
   506     inDoc: function(doc) {
       
   507         var node = g_nodes[this[UID]];
       
   508         doc = (doc) ? Node.getDOMNode(doc) : node[OWNER_DOCUMENT];
       
   509         if (doc.documentElement) {
       
   510             return Y.DOM.contains(doc.documentElement, node);
       
   511         }
       
   512     },
       
   513 
       
   514     getById: function(id) {
       
   515         var node = g_nodes[this[UID]],
       
   516             ret = Y.DOM.byId(id, node[OWNER_DOCUMENT]);
       
   517         if (ret && Y.DOM.contains(node, ret)) {
       
   518             ret = Y.get(ret);
       
   519         } else {
       
   520             ret = null;
       
   521         }
       
   522         return ret;
       
   523     },
       
   524 
       
   525    /**
       
   526      * Returns the nearest ancestor that passes the test applied by supplied boolean method.
       
   527      * @method ancestor
       
   528      * @param {String | Function} fn A selector or boolean method for testing elements.
       
   529      * If a function is used, it receives the current node being tested as the only argument.
       
   530      * @return {Node} The matching Node instance or null if not found
       
   531      */
       
   532     ancestor: function(fn) {
       
   533         return Node.get(Y.DOM.elementByAxis(g_nodes[this[UID]], 'parentNode', _wrapFn(fn)));
       
   534     },
       
   535 
       
   536     /**
       
   537      * Returns the previous matching sibling. 
       
   538      * Returns the nearest element node sibling if no method provided.
       
   539      * @method previous
       
   540      * @param {String | Function} fn A selector or boolean method for testing elements.
       
   541      * If a function is used, it receives the current node being tested as the only argument.
       
   542      * @return {Node} Node instance or null if not found
       
   543      */
       
   544     previous: function(fn, all) {
       
   545         return Node.get(Y.DOM.elementByAxis(g_nodes[this[UID]], 'previousSibling', _wrapFn(fn), all));
       
   546     }, 
       
   547 
       
   548     /**
       
   549      * Returns the next matching sibling. 
       
   550      * Returns the nearest element node sibling if no method provided.
       
   551      * @method next
       
   552      * @param {String | Function} fn A selector or boolean method for testing elements.
       
   553      * If a function is used, it receives the current node being tested as the only argument.
       
   554      * @return {Node} Node instance or null if not found
       
   555      */
       
   556     next: function(node, fn, all) {
       
   557         return Node.get(Y.DOM.elementByAxis(g_nodes[this[UID]], 'nextSibling', _wrapFn(fn), all));
       
   558     },
       
   559         
       
   560     /**
       
   561      * Retrieves a Node instance of nodes based on the given CSS selector. 
       
   562      * @method query
       
   563      *
       
   564      * @param {string} selector The CSS selector to test against.
       
   565      * @return {Node} A Node instance for the matching HTMLElement.
       
   566      */
       
   567     query: function(selector) {
       
   568         return Y.get(Y.Selector.query(selector, g_nodes[this[UID]], true));
       
   569     },
       
   570 
       
   571     /**
       
   572      * Retrieves a nodeList based on the given CSS selector. 
       
   573      * @method queryAll
       
   574      *
       
   575      * @param {string} selector The CSS selector to test against.
       
   576      * @return {NodeList} A NodeList instance for the matching HTMLCollection/Array.
       
   577      */
       
   578     queryAll: function(selector) {
       
   579         return Y.all(Y.Selector.query(selector, g_nodes[this[UID]]));
       
   580     },
       
   581 
       
   582     // TODO: allow fn test
       
   583     /**
       
   584      * Test if the supplied node matches the supplied selector.
       
   585      * @method test
       
   586      *
       
   587      * @param {string} selector The CSS selector to test against.
       
   588      * @return {boolean} Whether or not the node matches the selector.
       
   589      */
       
   590     test: function(selector) {
       
   591         return Y.Selector.test(g_nodes[this[UID]], selector);
       
   592     },
       
   593 
       
   594     /**
       
   595      * Removes the node from its parent.
       
   596      * Shortcut for myNode.get('parentNode').removeChild(myNode);
       
   597      * @method remove
       
   598      * @chainable
       
   599      *
       
   600      */
       
   601     remove: function() {
       
   602         var node = g_nodes[this[UID]];
       
   603         node.parentNode.removeChild(node);
       
   604         return this;
       
   605     },
       
   606 
       
   607     /**
       
   608      * Invokes a method on the Node instance 
       
   609      * @method invoke
       
   610      * @param {String} method The name of the method to invoke
       
   611      * @param {Any}  a, b, c, etc. Arguments to invoke the method with. 
       
   612      * @return Whatever the underly method returns. 
       
   613      * DOM Nodes and Collections return values
       
   614      * are converted to Node/NodeList instances.
       
   615      *
       
   616      */
       
   617     invoke: function(method, a, b, c, d, e) {
       
   618         var node = g_nodes[this[UID]],
       
   619             ret;
       
   620 
       
   621         if (a && a instanceof Y.Node) {
       
   622             a = Node.getDOMNode(a);
       
   623         }
       
   624 
       
   625         if (b && b instanceof Y.Node) {
       
   626             b = Node.getDOMNode(b);
       
   627         }
       
   628 
       
   629         ret = node[method](a, b, c, d, e);    
       
   630         return Y.Node.scrubVal(ret, this);
       
   631     },
       
   632 
       
   633     destructor: function() {
       
   634         // TODO: What about shared instances?
       
   635         //var uid = this[UID];
       
   636 
       
   637         //delete g_nodes[uid];
       
   638         //delete g_restrict[uid];
       
   639         //delete Node._instances[uid];
       
   640     },
       
   641 
       
   642     /**
       
   643      * Applies the given function to each Node in the NodeList.
       
   644      * @method each
       
   645      * @deprecated Use NodeList
       
   646      * @param {Function} fn The function to apply 
       
   647      * @param {Object} context optional An optional context to apply the function with
       
   648      * Default context is the NodeList instance
       
   649      * @chainable
       
   650      */
       
   651     each: function(fn, context) {
       
   652         context = context || this;
       
   653         return fn.call(context, this);
       
   654     },
       
   655 
       
   656     /**
       
   657      * Retrieves the Node instance at the given index. 
       
   658      * @method item
       
   659      * @deprecated Use NodeList
       
   660      *
       
   661      * @param {Number} index The index of the target Node.
       
   662      * @return {Node} The Node instance at the given index.
       
   663      */
       
   664     item: function(index) {
       
   665         return this;
       
   666     },
       
   667 
       
   668     /**
       
   669      * Returns the current number of items in the Node.
       
   670      * @method size
       
   671      * @deprecated Use NodeList
       
   672      * @return {Int} The number of items in the Node. 
       
   673      */
       
   674     size: function() {
       
   675         return g_nodes[this[UID]] ? 1 : 0;
       
   676     },
       
   677 
       
   678     /**
       
   679      * Inserts the content before the reference node. 
       
   680      * @method insert
       
   681      * @param {String | Y.Node | HTMLElement} content The content to insert 
       
   682      * @param {Int | Y.Node | HTMLElement | String} where The position to insert at.
       
   683      * @chainable
       
   684      */
       
   685     insert: function(content, where) {
       
   686         if (content) {
       
   687             if (typeof where === 'number') { // allow index
       
   688                 where = g_nodes[this[UID]].childNodes[where];
       
   689             }
       
   690             if (typeof content !== 'string') { // pass the DOM node
       
   691                 content = Y.Node.getDOMNode(content);
       
   692             }
       
   693             if (!where || // only allow inserting into this Node's subtree
       
   694                 (!g_restrict[this[UID]] || 
       
   695                     (typeof where !== 'string' && this.contains(where)))) { 
       
   696                 Y.DOM.addHTML(g_nodes[this[UID]], content, where);
       
   697             }
       
   698         }
       
   699         return this;
       
   700     },
       
   701 
       
   702     /**
       
   703      * Inserts the content as the firstChild of the node. 
       
   704      * @method prepend
       
   705      * @param {String | Y.Node | HTMLElement} content The content to insert 
       
   706      * @chainable
       
   707      */
       
   708     prepend: function(content) {
       
   709         return this.insert(content, 0);
       
   710     },
       
   711 
       
   712     /**
       
   713      * Inserts the content as the lastChild of the node. 
       
   714      * @method append
       
   715      * @param {String | Y.Node | HTMLElement} content The content to insert 
       
   716      * @chainable
       
   717      */
       
   718     append: function(content) {
       
   719         return this.insert(content, null);
       
   720     },
       
   721 
       
   722     /**
       
   723      * Replaces the node's current content with the content.
       
   724      * @method setContent
       
   725      * @param {String | Y.Node | HTMLElement} content The content to insert 
       
   726      * @chainable
       
   727      */
       
   728     setContent: function(content) {
       
   729         Y.DOM.addHTML(g_nodes[this[UID]], content, 'replace');
       
   730         return this;
       
   731     },
       
   732 
       
   733     // TODO: need this?
       
   734     hasMethod: function(method) {
       
   735         var node = g_nodes[this[UID]];
       
   736         return (node && (typeof node === 'function'));
       
   737     }
       
   738 }, true);
       
   739 
       
   740 Y.Node = Node;
       
   741 Y.get = Y.Node.get;
       
   742 /**
       
   743  * The NodeList module provides support for managing collections of Nodes.
       
   744  * @module node
       
   745  * @submodule nodelist
       
   746  */    
       
   747 
       
   748 /**
       
   749  * The NodeList class provides a wrapper for manipulating DOM NodeLists.
       
   750  * NodeList properties can be accessed via the set/get methods.
       
   751  * Use Y.all() to retrieve NodeList instances.
       
   752  *
       
   753  * @class NodeList
       
   754  * @constructor
       
   755  */
       
   756 
       
   757 Y.Array._diff = function(a, b) {
       
   758     var removed = [],
       
   759         present = false,
       
   760         i, j, lenA, lenB;
       
   761 
       
   762     outer:
       
   763     for (i = 0, lenA = a.length; i < lenA; i++) {
       
   764         present = false;
       
   765         for (j = 0, lenB = b.length; j < lenB; j++) {
       
   766             if (a[i] === b[j]) {
       
   767                 present = true;
       
   768                 continue outer;
       
   769             }
       
   770         }
       
   771         if (!present) {
       
   772             removed[removed.length] = a[i];
       
   773         }
       
   774     }
       
   775     return removed;
       
   776 };
       
   777 
       
   778 Y.Array.diff = function(a, b) {
       
   779     return {
       
   780         added: Y.Array._diff(b, a),
       
   781         removed: Y.Array._diff(a, b)
       
   782     }; 
       
   783 };
       
   784 
       
   785 var NodeList = function(config) {
       
   786     var doc = config.doc || Y.config.doc,
       
   787         nodes = config.nodes || [];
       
   788 
       
   789     if (typeof nodes === 'string') {
       
   790         this._query = nodes;
       
   791         nodes = Y.Selector.query(nodes, doc);
       
   792     }
       
   793 
       
   794     Y.stamp(this);
       
   795     NodeList._instances[this[UID]] = this;
       
   796     g_nodelists[this[UID]] = nodes;
       
   797 
       
   798     if (config.restricted) {
       
   799         g_restrict = this[UID];
       
   800     }
       
   801 };
       
   802 // end "globals"
       
   803 
       
   804 NodeList.NAME = 'NodeList';
       
   805 
       
   806 /**
       
   807  * Retrieves the DOM nodes bound to a NodeList instance
       
   808  * @method NodeList.getDOMNodes
       
   809  * @static
       
   810  *
       
   811  * @param {Y.NodeList} node The NodeList instance
       
   812  * @return {Array} The array of DOM nodes bound to the NodeList
       
   813  */
       
   814 NodeList.getDOMNodes = function(nodeList) {
       
   815     return g_nodelists[nodeList[UID]];
       
   816 };
       
   817 
       
   818 NodeList._instances = [];
       
   819 
       
   820 NodeList.each = function(instance, fn, context) {
       
   821     var nodes = g_nodelists[instance[UID]];
       
   822     if (nodes && nodes.length) {
       
   823         Y.Array.each(nodes, fn, context || instance);
       
   824     } else {
       
   825     }
       
   826 };
       
   827 
       
   828 NodeList.addMethod = function(name, fn, context) {
       
   829     var tmp = NodeList._getTempNode();
       
   830     if (name && fn) {
       
   831         NodeList.prototype[name] = function() {
       
   832             var ret = [],
       
   833                 args = arguments;
       
   834 
       
   835             Y.Array.each(g_nodelists[this[UID]], function(node) {
       
   836                 var UID = '_yuid',
       
   837                     instance = Y.Node._instances[node[UID]],
       
   838                     ctx,
       
   839                     result;
       
   840 
       
   841                 if (!instance) {
       
   842                     g_nodes[tmp[UID]] = node;
       
   843                     instance = tmp;
       
   844                 }
       
   845                 ctx = context || instance;
       
   846                 result = fn.apply(ctx, args);
       
   847                 if (result !== undefined && result !== instance) {
       
   848                     ret[ret.length] = result;
       
   849                 }
       
   850             });
       
   851 
       
   852             // TODO: remove tmp pointer
       
   853             return ret.length ? ret : this;
       
   854         };
       
   855     } else {
       
   856     }
       
   857 };
       
   858 
       
   859 NodeList.importMethod = function(host, name, altName) {
       
   860     if (typeof name === 'string') {
       
   861         altName = altName || name;
       
   862         NodeList.addMethod(name, host[name]);
       
   863     } else {
       
   864         Y.each(name, function(n) {
       
   865             NodeList.importMethod(host, n);
       
   866         });
       
   867     }
       
   868 };
       
   869 
       
   870 NodeList._getTempNode = function() {
       
   871     var tmp = NodeList._tempNode;
       
   872         if (!tmp) {
       
   873             tmp = Y.Node.create('<div></div>');
       
   874             NodeList._tempNode = tmp;
       
   875         }
       
   876     return tmp;
       
   877 };
       
   878 
       
   879 Y.mix(NodeList.prototype, {
       
   880     /**
       
   881      * Retrieves the Node instance at the given index. 
       
   882      * @method item
       
   883      *
       
   884      * @param {Number} index The index of the target Node.
       
   885      * @return {Node} The Node instance at the given index.
       
   886      */
       
   887     item: function(index) {
       
   888         return Y.get((g_nodelists[this[UID]] || [])[index]);
       
   889     },
       
   890 
       
   891     /**
       
   892      * Applies the given function to each Node in the NodeList.
       
   893      * @method each
       
   894      * @param {Function} fn The function to apply. It receives 3 arguments:
       
   895      * the current node instance, the node's index, and the NodeList instance
       
   896      * @param {Object} context optional An optional context to apply the function with
       
   897      * Default context is the current Node instance
       
   898      * @chainable
       
   899      */
       
   900     each: function(fn, context) {
       
   901         var instance = this;
       
   902         Y.Array.each(g_nodelists[this[UID]], function(node, index) {
       
   903             node = Y.get(node);
       
   904             return fn.call(context || node, node, index, instance);
       
   905         });
       
   906         return instance;
       
   907     },
       
   908 
       
   909     batch: function(fn, context) {
       
   910         var nodelist = this,
       
   911             tmp = NodeList._getTempNode();
       
   912 
       
   913         Y.Array.each(g_nodelists[this[UID]], function(node, index) {
       
   914             var instance = Y.Node._instances[node[UID]];
       
   915             if (!instance) {
       
   916                 g_nodes[tmp[UID]] = node;
       
   917                 instance = tmp;
       
   918             }
       
   919 
       
   920             return fn.call(context || instance, instance, index, nodelist);
       
   921         });
       
   922         return nodelist;
       
   923     },
       
   924 
       
   925     /**
       
   926      * Executes the function once for each node until a true value is returned.
       
   927      * @method some
       
   928      * @param {Function} fn The function to apply. It receives 3 arguments:
       
   929      * the current node instance, the node's index, and the NodeList instance
       
   930      * @param {Object} context optional An optional context to execute the function from.
       
   931      * Default context is the current Node instance
       
   932      * @return {Boolean} Whether or not the function returned true for any node.
       
   933      */
       
   934     some: function(fn, context) {
       
   935         var instance = this;
       
   936         return Y.Array.some(g_nodelists[this[UID]], function(node, index) {
       
   937             node = Y.get(node);
       
   938             context = context || node;
       
   939             return fn.call(context, node, index, instance);
       
   940         });
       
   941     },
       
   942 
       
   943     /**
       
   944      * Returns the index of the node in the NodeList instance
       
   945      * or -1 if the node isn't found.
       
   946      * @method indexOf
       
   947      * @param {Y.Node || DOMNode} node the node to search for
       
   948      * @return {Int} the index of the node value or -1 if not found
       
   949      */
       
   950     indexOf: function(node) {
       
   951         return Y.Array.indexOf(g_nodelists[this[UID]], Y.Node.getDOMNode(node));
       
   952     },
       
   953 
       
   954     /**
       
   955      * Filters the NodeList instance down to only nodes matching the given selector.
       
   956      * @method filter
       
   957      * @param {String} selector The selector to filter against
       
   958      * @return {NodeList} NodeList containing the updated collection 
       
   959      * @see Selector
       
   960      */
       
   961     filter: function(selector) {
       
   962         return Y.all(Y.Selector.filter(g_nodelists[this[UID]], selector));
       
   963     },
       
   964 
       
   965     modulus: function(n, r) {
       
   966         r = r || 0;
       
   967         var nodes = [];
       
   968         NodeList.each(this, function(node, i) {
       
   969             if (i % n === r) {
       
   970                 nodes.push(node);
       
   971             }
       
   972         });
       
   973 
       
   974         return Y.all(nodes);
       
   975     },
       
   976 
       
   977     /**
       
   978      * Creates a new NodeList containing all nodes at odd indices
       
   979      * (zero-based index).
       
   980      * @method odd
       
   981      * @return {NodeList} NodeList containing the updated collection 
       
   982      */
       
   983     odd: function() {
       
   984         return this.modulus(2, 1);
       
   985     },
       
   986 
       
   987     /**
       
   988      * Creates a new NodeList containing all nodes at even indices
       
   989      * (zero-based index), including zero. 
       
   990      * @method even
       
   991      * @return {NodeList} NodeList containing the updated collection 
       
   992      */
       
   993     even: function() {
       
   994         return this.modulus(2);
       
   995     },
       
   996 
       
   997     destructor: function() {
       
   998         delete NodeList._instances[this[UID]];
       
   999     },
       
  1000 
       
  1001     refresh: function() {
       
  1002         var doc,
       
  1003             diff,
       
  1004             oldList = g_nodelists[this[UID]];
       
  1005         if (this._query) {
       
  1006             if (g_nodelists[this[UID]] &&
       
  1007                     g_nodelists[this[UID]][0] && 
       
  1008                     g_nodelists[this[UID]][0].ownerDocument) {
       
  1009                 doc = g_nodelists[this[UID]][0].ownerDocument;
       
  1010             }
       
  1011 
       
  1012             g_nodelists[this[UID]] = Y.Selector.query(this._query, doc || Y.config.doc);        
       
  1013             diff = Y.Array.diff(oldList, g_nodelists[this[UID]]); 
       
  1014             diff.added = diff.added ? Y.all(diff.added) : null;
       
  1015             diff.removed = diff.removed ? Y.all(diff.removed) : null;
       
  1016             this.fire('refresh', diff);
       
  1017         }
       
  1018         return this;
       
  1019     },
       
  1020 
       
  1021     /**
       
  1022      * Applies an event listens to each Node bound to the NodeList. 
       
  1023      * @method on
       
  1024      * @param {String} type The event being listened for
       
  1025      * @param {Function} fn The handler to call when the event fires
       
  1026      * @param {Object} context The context to call the handler with.
       
  1027      * Default is the NodeList instance. 
       
  1028      * @return {Object} Returns an event handle that can later be use to detach(). 
       
  1029      * @see Event.on
       
  1030      */
       
  1031     on: function(type, fn, context) {
       
  1032         context = context || this;
       
  1033         this.batch(function(node) {
       
  1034             node.on.call(node, type, fn, context);
       
  1035         });
       
  1036     },
       
  1037 
       
  1038     /**
       
  1039      * Applies an event listens to each Node bound to the NodeList. 
       
  1040      * The handler is called only after all on() handlers are called
       
  1041      * and the event is not prevented.
       
  1042      * @method after
       
  1043      * @param {String} type The event being listened for
       
  1044      * @param {Function} fn The handler to call when the event fires
       
  1045      * @param {Object} context The context to call the handler with.
       
  1046      * Default is the NodeList instance. 
       
  1047      * @return {Object} Returns an event handle that can later be use to detach(). 
       
  1048      * @see Event.on
       
  1049      */
       
  1050     after: function(type, fn, context) {
       
  1051         context = context || this;
       
  1052         this.batch(function(node) {
       
  1053             node.after.call(node, type, fn, context);
       
  1054         });
       
  1055     },
       
  1056 
       
  1057     /**
       
  1058      * Returns the current number of items in the NodeList.
       
  1059      * @method size
       
  1060      * @return {Int} The number of items in the NodeList. 
       
  1061      */
       
  1062     size: function() {
       
  1063         return g_nodelists[this[UID]].length;
       
  1064     },
       
  1065 
       
  1066     /** Called on each Node instance
       
  1067       * @get
       
  1068       * @see Node
       
  1069       */
       
  1070     // one-off because we cant import from Node due to undefined return values
       
  1071     get: function(name) {
       
  1072         var ret = [],
       
  1073             tmp = NodeList._getTempNode();
       
  1074 
       
  1075         NodeList.each(this, function(node) {
       
  1076             var instance = Y.Node._instances[node[UID]];
       
  1077             if (!instance) {
       
  1078                 g_nodes[tmp[UID]] = node;
       
  1079                 instance = tmp;
       
  1080             }
       
  1081             ret[ret.length] = instance.get(name);
       
  1082         });
       
  1083 
       
  1084         return ret;
       
  1085     },
       
  1086 
       
  1087     toString: function() {
       
  1088         var str = '',
       
  1089             errorMsg = this[UID] + ': not bound to any nodes',
       
  1090             nodes = g_nodelists[this[UID]],
       
  1091             node;
       
  1092 
       
  1093         if (nodes && nodes[0]) {
       
  1094             node = nodes[0];
       
  1095             str += node[NODE_NAME];
       
  1096             if (node.id) {
       
  1097                 str += '#' + node.id; 
       
  1098             }
       
  1099 
       
  1100             if (node.className) {
       
  1101                 str += '.' + node.className.replace(' ', '.'); 
       
  1102             }
       
  1103 
       
  1104             if (nodes.length > 1) {
       
  1105                 str += '...[' + nodes.length + ' items]';
       
  1106             }
       
  1107         }
       
  1108         return str || errorMsg;
       
  1109     }
       
  1110 
       
  1111 }, true);
       
  1112 
       
  1113 NodeList.importMethod(Y.Node.prototype, [
       
  1114     /**
       
  1115      * Called on each Node instance
       
  1116      * @for NodeList
       
  1117      * @method append
       
  1118      * @see Node.append
       
  1119      */
       
  1120     'append',
       
  1121 
       
  1122     /**
       
  1123       * Called on each Node instance
       
  1124       * @method detach
       
  1125       * @see Node.detach
       
  1126       */
       
  1127     'detach',
       
  1128     
       
  1129     /** Called on each Node instance
       
  1130       * @method detachAll
       
  1131       * @see Node.detachAll
       
  1132       */
       
  1133     'detachAll',
       
  1134 
       
  1135     /** Called on each Node instance
       
  1136       * @method insert
       
  1137       * @see NodeInsert
       
  1138       */
       
  1139     'insert',
       
  1140 
       
  1141     /** Called on each Node instance
       
  1142       * @method plug
       
  1143       * @see Node.plug
       
  1144       */
       
  1145     'plug',
       
  1146 
       
  1147     /** Called on each Node instance
       
  1148       * @method prepend
       
  1149       * @see Node.prepend
       
  1150       */
       
  1151     'prepend',
       
  1152 
       
  1153     /** Called on each Node instance
       
  1154       * @method remove
       
  1155       * @see Node.remove
       
  1156       */
       
  1157     'remove',
       
  1158 
       
  1159     /** Called on each Node instance
       
  1160       * @method set
       
  1161       * @see Node.set
       
  1162       */
       
  1163     'set',
       
  1164 
       
  1165     /** Called on each Node instance
       
  1166       * @method setContent
       
  1167       * @see Node.setContent
       
  1168       */
       
  1169     'setContent',
       
  1170 
       
  1171     /** Called on each Node instance
       
  1172       * @method unplug
       
  1173       * @see Node.unplug
       
  1174       */
       
  1175     'unplug'
       
  1176 ]);
       
  1177 
       
  1178 Y.NodeList = NodeList;
       
  1179 Y.all = function(nodes, doc, restrict) {
       
  1180     // TODO: propagate restricted to nodes?
       
  1181     var nodeList = new NodeList({
       
  1182         nodes: nodes,
       
  1183         doc: doc,
       
  1184         restricted: restrict
       
  1185     });
       
  1186 
       
  1187     // zero-length result returns null
       
  1188     return nodeList;
       
  1189 };
       
  1190 Y.Node.all = Y.all; // TODO: deprecated
       
  1191 Y.Array.each([
       
  1192     /**
       
  1193      * Passes through to DOM method.
       
  1194      * @method replaceChild
       
  1195      * @for Node
       
  1196      * @param {HTMLElement | Node} node Node to be inserted 
       
  1197      * @param {HTMLElement | Node} refNode Node to be replaced 
       
  1198      * @return {Node} The replaced node 
       
  1199      */
       
  1200     'replaceChild',
       
  1201 
       
  1202     /**
       
  1203      * Passes through to DOM method.
       
  1204      * @method appendChild
       
  1205      * @param {HTMLElement | Node} node Node to be appended 
       
  1206      * @return {Node} The appended node 
       
  1207      */
       
  1208     'appendChild',
       
  1209 
       
  1210     /**
       
  1211      * Passes through to DOM method.
       
  1212      * @method insertBefore
       
  1213      * @param {HTMLElement | Node} newNode Node to be appended 
       
  1214      * @param {HTMLElement | Node} refNode Node to be inserted before 
       
  1215      * @return {Node} The inserted node 
       
  1216      */
       
  1217     'insertBefore',
       
  1218 
       
  1219     /**
       
  1220      * Passes through to DOM method.
       
  1221      * @method removeChild
       
  1222      * @param {HTMLElement | Node} node Node to be removed 
       
  1223      * @return {Node} The removed node 
       
  1224      */
       
  1225     'removeChild',
       
  1226 
       
  1227     /**
       
  1228      * Passes through to DOM method.
       
  1229      * @method hasChildNodes
       
  1230      * @return {Boolean} Whether or not the node has any childNodes 
       
  1231      */
       
  1232     'hasChildNodes',
       
  1233 
       
  1234     /**
       
  1235      * Passes through to DOM method.
       
  1236      * @method cloneNode
       
  1237      * @param {HTMLElement | Node} node Node to be cloned 
       
  1238      * @return {Node} The clone 
       
  1239      */
       
  1240     'cloneNode',
       
  1241 
       
  1242     /**
       
  1243      * Passes through to DOM method.
       
  1244      * @method hasAttribute
       
  1245      * @param {String} attribute The attribute to test for 
       
  1246      * @return {Boolean} Whether or not the attribute is present 
       
  1247      */
       
  1248     'hasAttribute',
       
  1249 
       
  1250     /**
       
  1251      * Passes through to DOM method.
       
  1252      * @method removeAttribute
       
  1253      * @param {String} attribute The attribute to be removed 
       
  1254      * @chainable
       
  1255      */
       
  1256     'removeAttribute',
       
  1257 
       
  1258     /**
       
  1259      * Passes through to DOM method.
       
  1260      * @method scrollIntoView
       
  1261      * @chainable
       
  1262      */
       
  1263     'scrollIntoView',
       
  1264 
       
  1265     /**
       
  1266      * Passes through to DOM method.
       
  1267      * @method getElementsByTagName
       
  1268      * @param {String} tagName The tagName to collect 
       
  1269      * @return {NodeList} A NodeList representing the HTMLCollection
       
  1270      */
       
  1271     'getElementsByTagName',
       
  1272 
       
  1273     /**
       
  1274      * Passes through to DOM method.
       
  1275      * @method focus
       
  1276      * @chainable
       
  1277      */
       
  1278     'focus',
       
  1279 
       
  1280     /**
       
  1281      * Passes through to DOM method.
       
  1282      * @method blur
       
  1283      * @chainable
       
  1284      */
       
  1285     'blur',
       
  1286 
       
  1287     /**
       
  1288      * Passes through to DOM method.
       
  1289      * Only valid on FORM elements
       
  1290      * @method submit
       
  1291      * @chainable
       
  1292      */
       
  1293     'submit',
       
  1294 
       
  1295     /**
       
  1296      * Passes through to DOM method.
       
  1297      * Only valid on FORM elements
       
  1298      * @method reset
       
  1299      * @chainable
       
  1300      */
       
  1301     'reset',
       
  1302 
       
  1303     /**
       
  1304      * Passes through to DOM method.
       
  1305      * @method select
       
  1306      * @chainable
       
  1307      */
       
  1308      'select'
       
  1309 ], function(method) {
       
  1310     Y.Node.prototype[method] = function(arg1, arg2, arg3) {
       
  1311         var ret = this.invoke(method, arg1, arg2, arg3);
       
  1312         return ret;
       
  1313     };
       
  1314 });
       
  1315 
       
  1316 Node.importMethod(Y.DOM, [
       
  1317     /**
       
  1318      * Determines whether the ndoe is an ancestor of another HTML element in the DOM hierarchy.
       
  1319      * @method contains
       
  1320      * @param {Node | HTMLElement} needle The possible node or descendent
       
  1321      * @return {Boolean} Whether or not this node is the needle its ancestor
       
  1322      */
       
  1323     'contains',
       
  1324     /**
       
  1325      * Allows setting attributes on DOM nodes, normalizing in some cases.
       
  1326      * This passes through to the DOM node, allowing for custom attributes.
       
  1327      * @method setAttribute
       
  1328      * @for Node
       
  1329      * @for NodeList
       
  1330      * @chainable
       
  1331      * @param {string} name The attribute name 
       
  1332      * @param {string} value The value to set
       
  1333      */
       
  1334     'setAttribute',
       
  1335     /**
       
  1336      * Allows getting attributes on DOM nodes, normalizing in some cases.
       
  1337      * This passes through to the DOM node, allowing for custom attributes.
       
  1338      * @method getAttribute
       
  1339      * @for Node
       
  1340      * @for NodeList
       
  1341      * @param {string} name The attribute name 
       
  1342      * @return {string} The attribute value 
       
  1343      */
       
  1344     'getAttribute'
       
  1345 ]);
       
  1346 
       
  1347 if (!document.documentElement.hasAttribute) { // IE < 8
       
  1348     Y.Node.prototype.hasAttribute = function(attr) {
       
  1349         return Y.DOM.getAttribute(Y.Node.getDOMNode(this), attr) !== '';
       
  1350     };
       
  1351 }
       
  1352 
       
  1353 /**
       
  1354  * Allows setting attributes on DOM nodes, normalizing in some cases.
       
  1355  * This passes through to the DOM node, allowing for custom attributes.
       
  1356  * @method setAttribute
       
  1357  * @see Node
       
  1358  * @for NodeList
       
  1359  * @chainable
       
  1360  * @param {string} name The attribute name 
       
  1361  * @param {string} value The value to set
       
  1362  */
       
  1363 
       
  1364 /**
       
  1365  * Allows getting attributes on DOM nodes, normalizing in some cases.
       
  1366  * This passes through to the DOM node, allowing for custom attributes.
       
  1367  * @method getAttribute
       
  1368  * @see Node
       
  1369  * @for NodeList
       
  1370  * @param {string} name The attribute name 
       
  1371  * @return {string} The attribute value 
       
  1372  */
       
  1373 Y.NodeList.importMethod(Y.Node.prototype, ['getAttribute', 'setAttribute']);
       
  1374 
       
  1375 (function() { // IE clones expandos; regenerate UID
       
  1376     var node = document.createElement('div'),
       
  1377         UID = '_yuid';
       
  1378 
       
  1379     Y.stamp(node);
       
  1380     if (node[UID] === node.cloneNode(true)[UID]) {
       
  1381         Y.Node.prototype.cloneNode = function(deep) {
       
  1382             var node = Y.Node.getDOMNode(this).cloneNode(deep);
       
  1383             node[UID] = Y.guid();
       
  1384             return Y.get(node);
       
  1385         };
       
  1386     }
       
  1387 })();
       
  1388 (function(Y) {
       
  1389     var methods = [
       
  1390     /**
       
  1391      * Determines whether each node has the given className.
       
  1392      * @method hasClass
       
  1393      * @for Node
       
  1394      * @param {String} className the class name to search for
       
  1395      * @return {Array} An array of booleans for each node bound to the NodeList. 
       
  1396      */
       
  1397      'hasClass',
       
  1398 
       
  1399     /**
       
  1400      * Adds a class name to each node.
       
  1401      * @method addClass         
       
  1402      * @param {String} className the class name to add to the node's class attribute
       
  1403      * @chainable
       
  1404      */
       
  1405      'addClass',
       
  1406 
       
  1407     /**
       
  1408      * Removes a class name from each node.
       
  1409      * @method removeClass         
       
  1410      * @param {String} className the class name to remove from the node's class attribute
       
  1411      * @chainable
       
  1412      */
       
  1413      'removeClass',
       
  1414 
       
  1415     /**
       
  1416      * Replace a class with another class for each node.
       
  1417      * If no oldClassName is present, the newClassName is simply added.
       
  1418      * @method replaceClass  
       
  1419      * @param {String} oldClassName the class name to be replaced
       
  1420      * @param {String} newClassName the class name that will be replacing the old class name
       
  1421      * @chainable
       
  1422      */
       
  1423      'replaceClass',
       
  1424 
       
  1425     /**
       
  1426      * If the className exists on the node it is removed, if it doesn't exist it is added.
       
  1427      * @method toggleClass  
       
  1428      * @param {String} className the class name to be toggled
       
  1429      * @chainable
       
  1430      */
       
  1431      'toggleClass'
       
  1432     ];
       
  1433 
       
  1434     Y.Node.importMethod(Y.DOM, methods);
       
  1435     /**
       
  1436      * Determines whether each node has the given className.
       
  1437      * @method hasClass
       
  1438      * @see Node.hasClass
       
  1439      * @for NodeList
       
  1440      * @param {String} className the class name to search for
       
  1441      * @return {Array} An array of booleans for each node bound to the NodeList. 
       
  1442      */
       
  1443 
       
  1444     /**
       
  1445      * Adds a class name to each node.
       
  1446      * @method addClass         
       
  1447      * @see Node.addClass
       
  1448      * @param {String} className the class name to add to the node's class attribute
       
  1449      * @chainable
       
  1450      */
       
  1451 
       
  1452     /**
       
  1453      * Removes a class name from each node.
       
  1454      * @method removeClass         
       
  1455      * @see Node.removeClass
       
  1456      * @param {String} className the class name to remove from the node's class attribute
       
  1457      * @chainable
       
  1458      */
       
  1459 
       
  1460     /**
       
  1461      * Replace a class with another class for each node.
       
  1462      * If no oldClassName is present, the newClassName is simply added.
       
  1463      * @method replaceClass  
       
  1464      * @see Node.replaceClass
       
  1465      * @param {String} oldClassName the class name to be replaced
       
  1466      * @param {String} newClassName the class name that will be replacing the old class name
       
  1467      * @chainable
       
  1468      */
       
  1469 
       
  1470     /**
       
  1471      * If the className exists on the node it is removed, if it doesn't exist it is added.
       
  1472      * @method toggleClass  
       
  1473      * @see Node.toggleClass
       
  1474      * @param {String} className the class name to be toggled
       
  1475      * @chainable
       
  1476      */
       
  1477     Y.NodeList.importMethod(Y.Node.prototype, methods);
       
  1478 })(Y);
       
  1479 /**
       
  1480  * Functionality to make the node a delegated event container
       
  1481  * @module node
       
  1482  * @submodule node-event-delegate
       
  1483  */
       
  1484 
       
  1485 /**
       
  1486  * Functionality to make the node a delegated event container
       
  1487  * @method delegate
       
  1488  * @param type {String} the event type to delegate
       
  1489  * @param fn {Function} the function to execute
       
  1490  * @param selector {String} a selector that must match the target of the event.
       
  1491  * @return {Event.Handle} the detach handle
       
  1492  * @for Node
       
  1493  */
       
  1494 Y.Node.prototype.delegate = function(type, fn, selector, context) {
       
  1495     context = context || this;
       
  1496     var args = Array.prototype.slice.call(arguments, 4),
       
  1497         a = ['delegate', fn, Y.Node.getDOMNode(this), type, selector, context];
       
  1498     a = a.concat(args);
       
  1499     return Y.on.apply(Y, a);
       
  1500 };
       
  1501 
       
  1502 
       
  1503 
       
  1504 }, '3.0.0b1' ,{requires:['dom-base', 'base', 'selector']});
       
  1505 YUI.add('node-style', function(Y) {
       
  1506 
       
  1507 (function(Y) {
       
  1508 /**
       
  1509  * Extended Node interface for managing node styles.
       
  1510  * @module node
       
  1511  * @submodule node-style
       
  1512  */
       
  1513 
       
  1514 var methods = [
       
  1515     /**
       
  1516      * Returns the style's current value.
       
  1517      * @method getStyle
       
  1518      * @for Node
       
  1519      * @param {String} attr The style attribute to retrieve. 
       
  1520      * @return {String} The current value of the style property for the element.
       
  1521      */
       
  1522     'getStyle',
       
  1523 
       
  1524     /**
       
  1525      * Returns the computed value for the given style property.
       
  1526      * @method getComputedStyle
       
  1527      * @param {String} attr The style attribute to retrieve. 
       
  1528      * @return {String} The computed value of the style property for the element.
       
  1529      */
       
  1530     'getComputedStyle',
       
  1531 
       
  1532     /**
       
  1533      * Sets a style property of the node.
       
  1534      * @method setStyle
       
  1535      * @param {String} attr The style attribute to set. 
       
  1536      * @param {String|Number} val The value. 
       
  1537      * @chainable
       
  1538      */
       
  1539     'setStyle',
       
  1540 
       
  1541     /**
       
  1542      * Sets multiple style properties on the node.
       
  1543      * @method setStyles
       
  1544      * @param {Object} hash An object literal of property:value pairs. 
       
  1545      * @chainable
       
  1546      */
       
  1547     'setStyles'
       
  1548 ];
       
  1549 Y.Node.importMethod(Y.DOM, methods);
       
  1550 /**
       
  1551  * Returns an array of values for each node.
       
  1552  * @method getStyle
       
  1553  * @for NodeList
       
  1554  * @see Node.getStyle
       
  1555  * @param {String} attr The style attribute to retrieve. 
       
  1556  * @return {Array} The current values of the style property for the element.
       
  1557  */
       
  1558 
       
  1559 /**
       
  1560  * Returns an array of the computed value for each node.
       
  1561  * @method getComputedStyle
       
  1562  * @see Node.getComputedStyle
       
  1563  * @param {String} attr The style attribute to retrieve. 
       
  1564  * @return {Array} The computed values for each node.
       
  1565  */
       
  1566 'getComputedStyle',
       
  1567 
       
  1568 /**
       
  1569  * Sets a style property on each node.
       
  1570  * @method setStyle
       
  1571  * @see Node.setStyle
       
  1572  * @param {String} attr The style attribute to set. 
       
  1573  * @param {String|Number} val The value. 
       
  1574  * @chainable
       
  1575  */
       
  1576 'setStyle',
       
  1577 
       
  1578 /**
       
  1579  * Sets multiple style properties on each node.
       
  1580  * @method setStyles
       
  1581  * @see Node.setStyles
       
  1582  * @param {Object} hash An object literal of property:value pairs. 
       
  1583  * @chainable
       
  1584  */
       
  1585 'setStyles'
       
  1586 Y.NodeList.importMethod(Y.Node.prototype, methods);
       
  1587 })(Y);
       
  1588 
       
  1589 
       
  1590 }, '3.0.0b1' ,{requires:['dom-style', 'node-base']});
       
  1591 YUI.add('node-screen', function(Y) {
       
  1592 
       
  1593 /**
       
  1594  * Extended Node interface for managing regions and screen positioning.
       
  1595  * Adds support for positioning elements and normalizes window size and scroll detection. 
       
  1596  * @module node
       
  1597  * @submodule node-screen
       
  1598  */
       
  1599 
       
  1600 // these are all "safe" returns, no wrapping required
       
  1601 Y.each([
       
  1602     /**
       
  1603      * Returns the inner width of the viewport (exludes scrollbar). 
       
  1604      * @config winWidth
       
  1605      * @for Node
       
  1606      * @type {Int}
       
  1607      */
       
  1608     'winWidth',
       
  1609 
       
  1610     /**
       
  1611      * Returns the inner height of the viewport (exludes scrollbar). 
       
  1612      * @config winHeight
       
  1613      * @type {Int}
       
  1614      */
       
  1615     'winHeight',
       
  1616 
       
  1617     /**
       
  1618      * Document width 
       
  1619      * @config winHeight
       
  1620      * @type {Int}
       
  1621      */
       
  1622     'docWidth',
       
  1623 
       
  1624     /**
       
  1625      * Document height 
       
  1626      * @config docHeight
       
  1627      * @type {Int}
       
  1628      */
       
  1629     'docHeight',
       
  1630 
       
  1631     /**
       
  1632      * Amount page has been scroll vertically 
       
  1633      * @config docScrollX
       
  1634      * @type {Int}
       
  1635      */
       
  1636     'docScrollX',
       
  1637 
       
  1638     /**
       
  1639      * Amount page has been scroll horizontally 
       
  1640      * @config docScrollY
       
  1641      * @type {Int}
       
  1642      */
       
  1643     'docScrollY'
       
  1644     ],
       
  1645     function(name) {
       
  1646         Y.Node.ATTRS[name] = {
       
  1647             getter: function() {
       
  1648                 var args = Array.prototype.slice.call(arguments);
       
  1649                 args.unshift(Y.Node.getDOMNode(this));
       
  1650 
       
  1651                 return Y.DOM[name].apply(this, args);
       
  1652             }
       
  1653         };
       
  1654     }
       
  1655 );
       
  1656 
       
  1657 Y.Node.ATTRS.scrollLeft = {
       
  1658     getter: function() {
       
  1659         var node = Y.Node.getDOMNode(this);
       
  1660         return ('scrollLeft' in node) ? node.scrollLeft : Y.DOM.docScrollX(node);
       
  1661     },
       
  1662 
       
  1663     setter: function(val) {
       
  1664         var node = Y.Node.getDOMNode(this);
       
  1665         if (node) {
       
  1666             if ('scrollLeft' in node) {
       
  1667                 node.scrollLeft = val;
       
  1668             } else if (node.document || node.nodeType === 9) {
       
  1669                 Y.DOM._getWin(node).scrollTo(val, Y.DOM.docScrollY(node)); // scroll window if win or doc
       
  1670             }
       
  1671         } else {
       
  1672         }
       
  1673     }
       
  1674 };
       
  1675 
       
  1676 Y.Node.ATTRS.scrollTop = {
       
  1677     getter: function() {
       
  1678         var node = Y.Node.getDOMNode(this);
       
  1679         return ('scrollTop' in node) ? node.scrollTop : Y.DOM.docScrollY(node);
       
  1680     },
       
  1681 
       
  1682     setter: function(val) {
       
  1683         var node = Y.Node.getDOMNode(this);
       
  1684         if (node) {
       
  1685             if ('scrollTop' in node) {
       
  1686                 node.scrollTop = val;
       
  1687             } else if (node.document || node.nodeType === 9) {
       
  1688                 Y.DOM._getWin(node).scrollTo(Y.DOM.docScrollX(node), val); // scroll window if win or doc
       
  1689             }
       
  1690         } else {
       
  1691         }
       
  1692     }
       
  1693 };
       
  1694 
       
  1695 Y.Node.importMethod(Y.DOM, [
       
  1696 /**
       
  1697  * Gets the current position of the node in page coordinates. 
       
  1698  * @method getXY
       
  1699  * @for Node
       
  1700  * @return {Array} The XY position of the node
       
  1701 */
       
  1702     'getXY',
       
  1703 
       
  1704 /**
       
  1705  * Set the position of the node in page coordinates, regardless of how the node is positioned.
       
  1706  * @method setXY
       
  1707  * @param {Array} xy Contains X & Y values for new position (coordinates are page-based)
       
  1708  * @chainable
       
  1709  */
       
  1710     'setXY',
       
  1711 
       
  1712 /**
       
  1713  * Gets the current position of the node in page coordinates. 
       
  1714  * @method getX
       
  1715  * @return {Int} The X position of the node
       
  1716 */
       
  1717     'getX',
       
  1718 
       
  1719 /**
       
  1720  * Set the position of the node in page coordinates, regardless of how the node is positioned.
       
  1721  * @method setX
       
  1722  * @param {Int} x X value for new position (coordinates are page-based)
       
  1723  * @chainable
       
  1724  */
       
  1725     'setX',
       
  1726 
       
  1727 /**
       
  1728  * Gets the current position of the node in page coordinates. 
       
  1729  * @method getY
       
  1730  * @return {Int} The Y position of the node
       
  1731 */
       
  1732     'getY',
       
  1733 
       
  1734 /**
       
  1735  * Set the position of the node in page coordinates, regardless of how the node is positioned.
       
  1736  * @method setY
       
  1737  * @param {Int} y Y value for new position (coordinates are page-based)
       
  1738  * @chainable
       
  1739  */
       
  1740     'setY'
       
  1741 ]);
       
  1742 
       
  1743 /**
       
  1744  * Returns a region object for the node 
       
  1745  * @config region
       
  1746  * @for Node
       
  1747  * @type Node
       
  1748  */
       
  1749 Y.Node.ATTRS.region = {
       
  1750     getter: function() {
       
  1751         var node = Y.Node.getDOMNode(this);
       
  1752         if (node && !node.tagName) {
       
  1753             if (node.nodeType === 9) { // document
       
  1754                 node = node.documentElement;
       
  1755             } else if (node.alert) { // window
       
  1756                 node = node.document.documentElement;
       
  1757             }
       
  1758         }
       
  1759         return Y.DOM.region(node);
       
  1760     }
       
  1761 };
       
  1762     
       
  1763 /**
       
  1764  * Returns a region object for the node's viewport 
       
  1765  * @config viewportRegion
       
  1766  * @type Node
       
  1767  */
       
  1768 Y.Node.ATTRS.viewportRegion = {
       
  1769     getter: function() {
       
  1770         return Y.DOM.viewportRegion(Y.Node.getDOMNode(this));
       
  1771     }
       
  1772 };
       
  1773 
       
  1774 Y.Node.importMethod(Y.DOM, 'inViewportRegion');
       
  1775 
       
  1776 // these need special treatment to extract 2nd node arg
       
  1777 /**
       
  1778  * Compares the intersection of the node with another node or region 
       
  1779  * @method intersect         
       
  1780  * @for Node
       
  1781  * @param {Node|Object} node2 The node or region to compare with.
       
  1782  * @param {Object} altRegion An alternate region to use (rather than this node's). 
       
  1783  * @return {Object} An object representing the intersection of the regions. 
       
  1784  */
       
  1785 Y.Node.prototype.intersect = function(node2, altRegion) {
       
  1786     var node1 = Y.Node.getDOMNode(this);
       
  1787     if (node2 instanceof Y.Node) { // might be a region object
       
  1788         node2 = Y.Node.getDOMNode(node2);
       
  1789     }
       
  1790     return Y.DOM.intersect(node1, node2, altRegion); 
       
  1791 };
       
  1792 
       
  1793 /**
       
  1794  * Determines whether or not the node is within the giving region.
       
  1795  * @method inRegion         
       
  1796  * @param {Node|Object} node2 The node or region to compare with.
       
  1797  * @param {Boolean} all Whether or not all of the node must be in the region. 
       
  1798  * @param {Object} altRegion An alternate region to use (rather than this node's). 
       
  1799  * @return {Object} An object representing the intersection of the regions. 
       
  1800  */
       
  1801 Y.Node.prototype.inRegion = function(node2, all, altRegion) {
       
  1802     var node1 = Y.Node.getDOMNode(this);
       
  1803     if (node2 instanceof Y.Node) { // might be a region object
       
  1804         node2 = Y.Node.getDOMNode(node2);
       
  1805     }
       
  1806     return Y.DOM.inRegion(node1, node2, all, altRegion); 
       
  1807 };
       
  1808 
       
  1809 
       
  1810 }, '3.0.0b1' ,{requires:['dom-screen']});
       
  1811 YUI.add('node-aria', function(Y) {
       
  1812 
       
  1813 /**
       
  1814  * Aria support for Node
       
  1815  * @module node
       
  1816  * @submodule node-aria
       
  1817  */
       
  1818 
       
  1819 Y.Node.re_aria = /^(?:role$|aria-)/;
       
  1820 
       
  1821 Y.Node.prototype._addAriaAttr = function(name) {
       
  1822     this.addAttr(name, {
       
  1823         getter: function() {
       
  1824             return Y.Node.getDOMNode(this).getAttribute(name, 2); 
       
  1825         },
       
  1826 
       
  1827         setter: function(val) {
       
  1828             Y.Node.getDOMNode(this).setAttribute(name, val);
       
  1829             return val; 
       
  1830         }
       
  1831     });
       
  1832 };
       
  1833 
       
  1834 
       
  1835 }, '3.0.0b1' ,{requires:['node-base']});
       
  1836 
       
  1837 
       
  1838 YUI.add('node', function(Y){}, '3.0.0b1' ,{skinnable:false, use:['node-base', 'node-style', 'node-screen', 'node-aria']});
       
  1839