]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - jssource/src_files/include/javascript/yui3/build/node/node-base.js
Release 6.5.0
[Github/sugarcrm.git] / jssource / src_files / include / javascript / yui3 / build / node / node-base.js
1 /*
2 Copyright (c) 2010, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.com/yui/license.html
5 version: 3.3.0
6 build: 3167
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  * @param {DOMNode} node the DOM node to be mapped to the Node instance.
27  * @for Node
28  */
29
30 // "globals"
31 var DOT = '.',
32     NODE_NAME = 'nodeName',
33     NODE_TYPE = 'nodeType',
34     OWNER_DOCUMENT = 'ownerDocument',
35     TAG_NAME = 'tagName',
36     UID = '_yuid',
37
38     _slice = Array.prototype.slice,
39
40     Y_DOM = Y.DOM,
41
42     Y_Node = function(node) {
43         var uid = (node.nodeType !== 9) ? node.uniqueID : node[UID];
44
45         if (uid && Y_Node._instances[uid] && Y_Node._instances[uid]._node !== node) {
46             node[UID] = null; // unset existing uid to prevent collision (via clone or hack)
47         }
48
49         uid = uid || Y.stamp(node);
50         if (!uid) { // stamp failed; likely IE non-HTMLElement
51             uid = Y.guid();
52         }
53
54         this[UID] = uid;
55
56         /**
57          * The underlying DOM node bound to the Y.Node instance
58          * @property _node
59          * @private
60          */
61         this._node = node;
62         Y_Node._instances[uid] = this;
63
64         this._stateProxy = node; // when augmented with Attribute
65
66         Y.EventTarget.call(this, {emitFacade:true});
67
68         if (this._initPlugins) { // when augmented with Plugin.Host
69             this._initPlugins();
70         }
71
72         this.SHOW_TRANSITION = Y_Node.SHOW_TRANSITION;
73         this.HIDE_TRANSITION = Y_Node.HIDE_TRANSITION;
74     },
75
76     // used with previous/next/ancestor tests
77     _wrapFn = function(fn) {
78         var ret = null;
79         if (fn) {
80             ret = (typeof fn == 'string') ?
81             function(n) {
82                 return Y.Selector.test(n, fn);
83             } :
84             function(n) {
85                 return fn(Y.one(n));
86             };
87         }
88
89         return ret;
90     };
91 // end "globals"
92
93 /**
94  * The name of the component
95  * @static
96  * @property NAME
97  */
98 Y_Node.NAME = 'node';
99
100 /*
101  * The pattern used to identify ARIA attributes
102  */
103 Y_Node.re_aria = /^(?:role$|aria-)/;
104
105 Y_Node.SHOW_TRANSITION = 'fadeIn';
106 Y_Node.HIDE_TRANSITION = 'fadeOut';
107
108 /**
109  * List of events that route to DOM events
110  * @static
111  * @property DOM_EVENTS
112  */
113
114 Y_Node.DOM_EVENTS = {
115     abort: 1,
116     beforeunload: 1,
117     blur: 1,
118     change: 1,
119     click: 1,
120     close: 1,
121     command: 1,
122     contextmenu: 1,
123     dblclick: 1,
124     DOMMouseScroll: 1,
125     drag: 1,
126     dragstart: 1,
127     dragenter: 1,
128     dragover: 1,
129     dragleave: 1,
130     dragend: 1,
131     drop: 1,
132     error: 1,
133     focus: 1,
134     key: 1,
135     keydown: 1,
136     keypress: 1,
137     keyup: 1,
138     load: 1,
139     message: 1,
140     mousedown: 1,
141     mouseenter: 1,
142     mouseleave: 1,
143     mousemove: 1,
144     mousemultiwheel: 1,
145     mouseout: 1,
146     mouseover: 1,
147     mouseup: 1,
148     mousewheel: 1,
149     orientationchange: 1,
150     reset: 1,
151     resize: 1,
152     select: 1,
153     selectstart: 1,
154     submit: 1,
155     scroll: 1,
156     textInput: 1,
157     unload: 1
158 };
159
160 // Add custom event adaptors to this list.  This will make it so
161 // that delegate, key, available, contentready, etc all will
162 // be available through Node.on
163 Y.mix(Y_Node.DOM_EVENTS, Y.Env.evt.plugins);
164
165 /**
166  * A list of Node instances that have been created
167  * @private
168  * @property _instances
169  * @static
170  *
171  */
172 Y_Node._instances = {};
173
174 /**
175  * Retrieves the DOM node bound to a Node instance
176  * @method getDOMNode
177  * @static
178  *
179  * @param {Y.Node || HTMLNode} node The Node instance or an HTMLNode
180  * @return {HTMLNode} The DOM node bound to the Node instance.  If a DOM node is passed
181  * as the node argument, it is simply returned.
182  */
183 Y_Node.getDOMNode = function(node) {
184     if (node) {
185         return (node.nodeType) ? node : node._node || null;
186     }
187     return null;
188 };
189
190 /**
191  * Checks Node return values and wraps DOM Nodes as Y.Node instances
192  * and DOM Collections / Arrays as Y.NodeList instances.
193  * Other return values just pass thru.  If undefined is returned (e.g. no return)
194  * then the Node instance is returned for chainability.
195  * @method scrubVal
196  * @static
197  *
198  * @param {any} node The Node instance or an HTMLNode
199  * @return {Y.Node | Y.NodeList | any} Depends on what is returned from the DOM node.
200  */
201 Y_Node.scrubVal = function(val, node) {
202     if (val) { // only truthy values are risky
203          if (typeof val == 'object' || typeof val == 'function') { // safari nodeList === function
204             if (NODE_TYPE in val || Y_DOM.isWindow(val)) {// node || window
205                 val = Y.one(val);
206             } else if ((val.item && !val._nodes) || // dom collection or Node instance
207                     (val[0] && val[0][NODE_TYPE])) { // array of DOM Nodes
208                 val = Y.all(val);
209             }
210         }
211     } else if (typeof val === 'undefined') {
212         val = node; // for chaining
213     } else if (val === null) {
214         val = null; // IE: DOM null not the same as null
215     }
216
217     return val;
218 };
219
220 /**
221  * Adds methods to the Y.Node prototype, routing through scrubVal.
222  * @method addMethod
223  * @static
224  *
225  * @param {String} name The name of the method to add
226  * @param {Function} fn The function that becomes the method
227  * @param {Object} context An optional context to call the method with
228  * (defaults to the Node instance)
229  * @return {any} Depends on what is returned from the DOM node.
230  */
231 Y_Node.addMethod = function(name, fn, context) {
232     if (name && fn && typeof fn == 'function') {
233         Y_Node.prototype[name] = function() {
234             var args = _slice.call(arguments),
235                 node = this,
236                 ret;
237
238             if (args[0] && Y.instanceOf(args[0], Y_Node)) {
239                 args[0] = args[0]._node;
240             }
241
242             if (args[1] && Y.instanceOf(args[1], Y_Node)) {
243                 args[1] = args[1]._node;
244             }
245             args.unshift(node._node);
246
247             ret = fn.apply(node, args);
248
249             if (ret) { // scrub truthy
250                 ret = Y_Node.scrubVal(ret, node);
251             }
252
253             (typeof ret != 'undefined') || (ret = node);
254             return ret;
255         };
256     } else {
257     }
258 };
259
260 /**
261  * Imports utility methods to be added as Y.Node methods.
262  * @method importMethod
263  * @static
264  *
265  * @param {Object} host The object that contains the method to import.
266  * @param {String} name The name of the method to import
267  * @param {String} altName An optional name to use in place of the host name
268  * @param {Object} context An optional context to call the method with
269  */
270 Y_Node.importMethod = function(host, name, altName) {
271     if (typeof name == 'string') {
272         altName = altName || name;
273         Y_Node.addMethod(altName, host[name], host);
274     } else {
275         Y.Array.each(name, function(n) {
276             Y_Node.importMethod(host, n);
277         });
278     }
279 };
280
281 /**
282  * Returns a single Node instance bound to the node or the
283  * first element matching the given selector. Returns null if no match found.
284  * <strong>Note:</strong> For chaining purposes you may want to
285  * use <code>Y.all</code>, which returns a NodeList when no match is found.
286  * @method Y.one
287  * @static
288  * @param {String | HTMLElement} node a node or Selector
289  * @return {Y.Node | null} a Node instance or null if no match found.
290  */
291 Y_Node.one = function(node) {
292     var instance = null,
293         cachedNode,
294         uid;
295
296     if (node) {
297         if (typeof node == 'string') {
298             if (node.indexOf('doc') === 0) { // doc OR document
299                 node = Y.config.doc;
300             } else if (node.indexOf('win') === 0) { // win OR window
301                 node = Y.config.win;
302             } else {
303                 node = Y.Selector.query(node, null, true);
304             }
305             if (!node) {
306                 return null;
307             }
308         } else if (Y.instanceOf(node, Y_Node)) {
309             return node; // NOTE: return
310         }
311
312         if (node.nodeType || Y.DOM.isWindow(node)) { // avoid bad input (numbers, boolean, etc)
313             uid = (node.uniqueID && node.nodeType !== 9) ? node.uniqueID : node._yuid;
314             instance = Y_Node._instances[uid]; // reuse exising instances
315             cachedNode = instance ? instance._node : null;
316             if (!instance || (cachedNode && node !== cachedNode)) { // new Node when nodes don't match
317                 instance = new Y_Node(node);
318             }
319         }
320     }
321     return instance;
322 };
323
324 /**
325  * Returns a new dom node using the provided markup string.
326  * @method create
327  * @static
328  * @param {String} html The markup used to create the element
329  * @param {HTMLDocument} doc An optional document context
330  * @return {Node} A Node instance bound to a DOM node or fragment
331  */
332 Y_Node.create = function(html, doc) {
333     if (doc && doc._node) {
334         doc = doc._node;
335     }
336     return Y.one(Y_DOM.create(html, doc));
337 };
338
339 /**
340  * Static collection of configuration attributes for special handling
341  * @property ATTRS
342  * @static
343  * @type object
344  */
345 Y_Node.ATTRS = {
346     /**
347      * Allows for getting and setting the text of an element.
348      * Formatting is preserved and special characters are treated literally.
349      * @config text
350      * @type String
351      */
352     text: {
353         getter: function() {
354             return Y_DOM.getText(this._node);
355         },
356
357         setter: function(content) {
358             Y_DOM.setText(this._node, content);
359             return content;
360         }
361     },
362
363     'options': {
364         getter: function() {
365             return this._node.getElementsByTagName('option');
366         }
367     },
368
369     /**
370      * Returns a NodeList instance of all HTMLElement children.
371      * @readOnly
372      * @config children
373      * @type NodeList
374      */
375     'children': {
376         getter: function() {
377             var node = this._node,
378                 children = node.children,
379                 childNodes, i, len;
380
381             if (!children) {
382                 childNodes = node.childNodes;
383                 children = [];
384
385                 for (i = 0, len = childNodes.length; i < len; ++i) {
386                     if (childNodes[i][TAG_NAME]) {
387                         children[children.length] = childNodes[i];
388                     }
389                 }
390             }
391             return Y.all(children);
392         }
393     },
394
395     value: {
396         getter: function() {
397             return Y_DOM.getValue(this._node);
398         },
399
400         setter: function(val) {
401             Y_DOM.setValue(this._node, val);
402             return val;
403         }
404     }
405 };
406
407 /**
408  * The default setter for DOM properties
409  * Called with instance context (this === the Node instance)
410  * @method DEFAULT_SETTER
411  * @static
412  * @param {String} name The attribute/property being set
413  * @param {any} val The value to be set
414  * @return {any} The value
415  */
416 Y_Node.DEFAULT_SETTER = function(name, val) {
417     var node = this._stateProxy,
418         strPath;
419
420     if (name.indexOf(DOT) > -1) {
421         strPath = name;
422         name = name.split(DOT);
423         // only allow when defined on node
424         Y.Object.setValue(node, name, val);
425     } else if (typeof node[name] != 'undefined') { // pass thru DOM properties
426         node[name] = val;
427     }
428
429     return val;
430 };
431
432 /**
433  * The default getter for DOM properties
434  * Called with instance context (this === the Node instance)
435  * @method DEFAULT_GETTER
436  * @static
437  * @param {String} name The attribute/property to look up
438  * @return {any} The current value
439  */
440 Y_Node.DEFAULT_GETTER = function(name) {
441     var node = this._stateProxy,
442         val;
443
444     if (name.indexOf && name.indexOf(DOT) > -1) {
445         val = Y.Object.getValue(node, name.split(DOT));
446     } else if (typeof node[name] != 'undefined') { // pass thru from DOM
447         val = node[name];
448     }
449
450     return val;
451 };
452
453 // Basic prototype augment - no lazy constructor invocation.
454 Y.mix(Y_Node, Y.EventTarget, false, null, 1);
455
456 Y.mix(Y_Node.prototype, {
457 /**
458  * The method called when outputting Node instances as strings
459  * @method toString
460  * @return {String} A string representation of the Node instance
461  */
462     toString: function() {
463         var str = this[UID] + ': not bound to a node',
464             node = this._node,
465             attrs, id, className;
466
467         if (node) {
468             attrs = node.attributes;
469             id = (attrs && attrs.id) ? node.getAttribute('id') : null;
470             className = (attrs && attrs.className) ? node.getAttribute('className') : null;
471             str = node[NODE_NAME];
472
473             if (id) {
474                 str += '#' + id;
475             }
476
477             if (className) {
478                 str += '.' + className.replace(' ', '.');
479             }
480
481             // TODO: add yuid?
482             str += ' ' + this[UID];
483         }
484         return str;
485     },
486
487     /**
488      * Returns an attribute value on the Node instance.
489      * Unless pre-configured (via Node.ATTRS), get hands
490      * off to the underlying DOM node.  Only valid
491      * attributes/properties for the node will be set.
492      * @method get
493      * @param {String} attr The attribute
494      * @return {any} The current value of the attribute
495      */
496     get: function(attr) {
497         var val;
498
499         if (this._getAttr) { // use Attribute imple
500             val = this._getAttr(attr);
501         } else {
502             val = this._get(attr);
503         }
504
505         if (val) {
506             val = Y_Node.scrubVal(val, this);
507         } else if (val === null) {
508             val = null; // IE: DOM null is not true null (even though they ===)
509         }
510         return val;
511     },
512
513     /**
514      * Helper method for get.
515      * @method _get
516      * @private
517      * @param {String} attr The attribute
518      * @return {any} The current value of the attribute
519      */
520     _get: function(attr) {
521         var attrConfig = Y_Node.ATTRS[attr],
522             val;
523
524         if (attrConfig && attrConfig.getter) {
525             val = attrConfig.getter.call(this);
526         } else if (Y_Node.re_aria.test(attr)) {
527             val = this._node.getAttribute(attr, 2);
528         } else {
529             val = Y_Node.DEFAULT_GETTER.apply(this, arguments);
530         }
531
532         return val;
533     },
534
535     /**
536      * Sets an attribute on the Node instance.
537      * Unless pre-configured (via Node.ATTRS), set hands
538      * off to the underlying DOM node.  Only valid
539      * attributes/properties for the node will be set.
540      * To set custom attributes use setAttribute.
541      * @method set
542      * @param {String} attr The attribute to be set.
543      * @param {any} val The value to set the attribute to.
544      * @chainable
545      */
546     set: function(attr, val) {
547         var attrConfig = Y_Node.ATTRS[attr];
548
549         if (this._setAttr) { // use Attribute imple
550             this._setAttr.apply(this, arguments);
551         } else { // use setters inline
552             if (attrConfig && attrConfig.setter) {
553                 attrConfig.setter.call(this, val, attr);
554             } else if (Y_Node.re_aria.test(attr)) { // special case Aria
555                 this._node.setAttribute(attr, val);
556             } else {
557                 Y_Node.DEFAULT_SETTER.apply(this, arguments);
558             }
559         }
560
561         return this;
562     },
563
564     /**
565      * Sets multiple attributes.
566      * @method setAttrs
567      * @param {Object} attrMap an object of name/value pairs to set
568      * @chainable
569      */
570     setAttrs: function(attrMap) {
571         if (this._setAttrs) { // use Attribute imple
572             this._setAttrs(attrMap);
573         } else { // use setters inline
574             Y.Object.each(attrMap, function(v, n) {
575                 this.set(n, v);
576             }, this);
577         }
578
579         return this;
580     },
581
582     /**
583      * Returns an object containing the values for the requested attributes.
584      * @method getAttrs
585      * @param {Array} attrs an array of attributes to get values
586      * @return {Object} An object with attribute name/value pairs.
587      */
588     getAttrs: function(attrs) {
589         var ret = {};
590         if (this._getAttrs) { // use Attribute imple
591             this._getAttrs(attrs);
592         } else { // use setters inline
593             Y.Array.each(attrs, function(v, n) {
594                 ret[v] = this.get(v);
595             }, this);
596         }
597
598         return ret;
599     },
600
601     /**
602      * Creates a new Node using the provided markup string.
603      * @method create
604      * @param {String} html The markup used to create the element
605      * @param {HTMLDocument} doc An optional document context
606      * @return {Node} A Node instance bound to a DOM node or fragment
607      */
608     create: Y_Node.create,
609
610     /**
611      * Compares nodes to determine if they match.
612      * Node instances can be compared to each other and/or HTMLElements.
613      * @method compareTo
614      * @param {HTMLElement | Node} refNode The reference node to compare to the node.
615      * @return {Boolean} True if the nodes match, false if they do not.
616      */
617     compareTo: function(refNode) {
618         var node = this._node;
619
620         if (Y.instanceOf(refNode, Y_Node)) {
621             refNode = refNode._node;
622         }
623         return node === refNode;
624     },
625
626     /**
627      * Determines whether the node is appended to the document.
628      * @method inDoc
629      * @param {Node|HTMLElement} doc optional An optional document to check against.
630      * Defaults to current document.
631      * @return {Boolean} Whether or not this node is appended to the document.
632      */
633     inDoc: function(doc) {
634         var node = this._node;
635         doc = (doc) ? doc._node || doc : node[OWNER_DOCUMENT];
636         if (doc.documentElement) {
637             return Y_DOM.contains(doc.documentElement, node);
638         }
639     },
640
641     getById: function(id) {
642         var node = this._node,
643             ret = Y_DOM.byId(id, node[OWNER_DOCUMENT]);
644         if (ret && Y_DOM.contains(node, ret)) {
645             ret = Y.one(ret);
646         } else {
647             ret = null;
648         }
649         return ret;
650     },
651
652    /**
653      * Returns the nearest ancestor that passes the test applied by supplied boolean method.
654      * @method ancestor
655      * @param {String | Function} fn A selector string or boolean method for testing elements.
656      * @param {Boolean} testSelf optional Whether or not to include the element in the scan
657      * If a function is used, it receives the current node being tested as the only argument.
658      * @return {Node} The matching Node instance or null if not found
659      */
660     ancestor: function(fn, testSelf) {
661         return Y.one(Y_DOM.ancestor(this._node, _wrapFn(fn), testSelf));
662     },
663
664    /**
665      * Returns the ancestors that pass the test applied by supplied boolean method.
666      * @method ancestors
667      * @param {String | Function} fn A selector string or boolean method for testing elements.
668      * @param {Boolean} testSelf optional Whether or not to include the element in the scan
669      * If a function is used, it receives the current node being tested as the only argument.
670      * @return {NodeList} A NodeList instance containing the matching elements 
671      */
672     ancestors: function(fn, testSelf) {
673         return Y.all(Y_DOM.ancestors(this._node, _wrapFn(fn), testSelf));
674     },
675
676     /**
677      * Returns the previous matching sibling.
678      * Returns the nearest element node sibling if no method provided.
679      * @method previous
680      * @param {String | Function} fn A selector or boolean method for testing elements.
681      * If a function is used, it receives the current node being tested as the only argument.
682      * @return {Node} Node instance or null if not found
683      */
684     previous: function(fn, all) {
685         return Y.one(Y_DOM.elementByAxis(this._node, 'previousSibling', _wrapFn(fn), all));
686     },
687
688     /**
689      * Returns the next matching sibling.
690      * Returns the nearest element node sibling if no method provided.
691      * @method next
692      * @param {String | Function} fn A selector or boolean method for testing elements.
693      * If a function is used, it receives the current node being tested as the only argument.
694      * @return {Node} Node instance or null if not found
695      */
696     next: function(fn, all) {
697         return Y.one(Y_DOM.elementByAxis(this._node, 'nextSibling', _wrapFn(fn), all));
698     },
699
700     /**
701      * Returns all matching siblings.
702      * Returns all siblings if no method provided.
703      * @method siblings
704      * @param {String | Function} fn A selector or boolean method for testing elements.
705      * If a function is used, it receives the current node being tested as the only argument.
706      * @return {NodeList} NodeList instance bound to found siblings
707      */
708     siblings: function(fn) {
709         return Y.all(Y_DOM.siblings(this._node, _wrapFn(fn)));
710     },
711
712     /**
713      * Retrieves a Node instance of nodes based on the given CSS selector.
714      * @method one
715      *
716      * @param {string} selector The CSS selector to test against.
717      * @return {Node} A Node instance for the matching HTMLElement.
718      */
719     one: function(selector) {
720         return Y.one(Y.Selector.query(selector, this._node, true));
721     },
722
723     /**
724      * Retrieves a nodeList based on the given CSS selector.
725      * @method all
726      *
727      * @param {string} selector The CSS selector to test against.
728      * @return {NodeList} A NodeList instance for the matching HTMLCollection/Array.
729      */
730     all: function(selector) {
731         var nodelist = Y.all(Y.Selector.query(selector, this._node));
732         nodelist._query = selector;
733         nodelist._queryRoot = this._node;
734         return nodelist;
735     },
736
737     // TODO: allow fn test
738     /**
739      * Test if the supplied node matches the supplied selector.
740      * @method test
741      *
742      * @param {string} selector The CSS selector to test against.
743      * @return {boolean} Whether or not the node matches the selector.
744      */
745     test: function(selector) {
746         return Y.Selector.test(this._node, selector);
747     },
748
749     /**
750      * Removes the node from its parent.
751      * Shortcut for myNode.get('parentNode').removeChild(myNode);
752      * @method remove
753      * @param {Boolean} destroy whether or not to call destroy() on the node
754      * after removal.
755      * @chainable
756      *
757      */
758     remove: function(destroy) {
759         var node = this._node,
760             parentNode = node.parentNode;
761
762         if (parentNode) {
763             parentNode.removeChild(node);
764         }
765
766         if (destroy) {
767             this.destroy();
768         }
769
770         return this;
771     },
772
773     /**
774      * Replace the node with the other node. This is a DOM update only
775      * and does not change the node bound to the Node instance.
776      * Shortcut for myNode.get('parentNode').replaceChild(newNode, myNode);
777      * @method replace
778      * @param {Y.Node || HTMLNode} newNode Node to be inserted
779      * @chainable
780      *
781      */
782     replace: function(newNode) {
783         var node = this._node;
784         if (typeof newNode == 'string') {
785             newNode = Y_Node.create(newNode);
786         }
787         node.parentNode.replaceChild(Y_Node.getDOMNode(newNode), node);
788         return this;
789     },
790
791     /**
792      * @method replaceChild
793      * @for Node
794      * @param {String | HTMLElement | Node} node Node to be inserted 
795      * @param {HTMLElement | Node} refNode Node to be replaced 
796      * @return {Node} The replaced node
797      */
798     replaceChild: function(node, refNode) {
799         if (typeof node == 'string') {
800             node = Y_DOM.create(node);
801         }
802
803         return Y.one(this._node.replaceChild(Y_Node.getDOMNode(node), Y_Node.getDOMNode(refNode)));
804     },
805
806     /**
807      * @method appendChild
808      * @param {String | HTMLElement | Node} node Node to be appended 
809      * @return {Node} The appended node 
810      */
811     appendChild: function(node) {
812         return Y_Node.scrubVal(this._insert(node));
813     },
814
815     /**
816      * @method insertBefore
817      * @param {String | HTMLElement | Node} newNode Node to be appended 
818      * @param {HTMLElement | Node} refNode Node to be inserted before 
819      * @return {Node} The inserted node 
820      */
821     insertBefore: function(newNode, refNode) {
822         return Y.Node.scrubVal(this._insert(newNode, refNode));
823     },
824
825     /**
826      * Removes event listeners from the node and (optionally) its subtree
827      * @method purge
828      * @param {Boolean} recurse (optional) Whether or not to remove listeners from the
829      * node's subtree
830      * @param {String} type (optional) Only remove listeners of the specified type
831      * @chainable
832      *
833      */
834     purge: function(recurse, type) {
835         Y.Event.purgeElement(this._node, recurse, type);
836         return this;
837     },
838
839     /**
840      * Nulls internal node references, removes any plugins and event listeners
841      * @method destroy
842      * @param {Boolean} recursivePurge (optional) Whether or not to remove listeners from the
843      * node's subtree (default is false)
844      *
845      */
846     destroy: function(recursive) {
847         this.purge(); // TODO: only remove events add via this Node
848
849         if (this.unplug) { // may not be a PluginHost
850             this.unplug();
851         }
852
853         this.clearData();
854
855         if (recursive) {
856             this.all('*').destroy();
857         }
858
859         this._node = null;
860         this._stateProxy = null;
861
862         delete Y_Node._instances[this[UID]];
863     },
864
865     /**
866      * Invokes a method on the Node instance
867      * @method invoke
868      * @param {String} method The name of the method to invoke
869      * @param {Any}  a, b, c, etc. Arguments to invoke the method with.
870      * @return Whatever the underly method returns.
871      * DOM Nodes and Collections return values
872      * are converted to Node/NodeList instances.
873      *
874      */
875     invoke: function(method, a, b, c, d, e) {
876         var node = this._node,
877             ret;
878
879         if (a && Y.instanceOf(a, Y_Node)) {
880             a = a._node;
881         }
882
883         if (b && Y.instanceOf(b, Y_Node)) {
884             b = b._node;
885         }
886
887         ret = node[method](a, b, c, d, e);
888         return Y_Node.scrubVal(ret, this);
889     },
890
891     /**
892      * Inserts the content before the reference node.
893      * @method insert
894      * @param {String | Y.Node | HTMLElement | Y.NodeList | HTMLCollection} content The content to insert
895      * @param {Int | Y.Node | HTMLElement | String} where The position to insert at.
896      * Possible "where" arguments
897      * <dl>
898      * <dt>Y.Node</dt>
899      * <dd>The Node to insert before</dd>
900      * <dt>HTMLElement</dt>
901      * <dd>The element to insert before</dd>
902      * <dt>Int</dt>
903      * <dd>The index of the child element to insert before</dd>
904      * <dt>"replace"</dt>
905      * <dd>Replaces the existing HTML</dd>
906      * <dt>"before"</dt>
907      * <dd>Inserts before the existing HTML</dd>
908      * <dt>"before"</dt>
909      * <dd>Inserts content before the node</dd>
910      * <dt>"after"</dt>
911      * <dd>Inserts content after the node</dd>
912      * </dl>
913      * @chainable
914      */
915     insert: function(content, where) {
916         this._insert(content, where);
917         return this;
918     },
919
920     _insert: function(content, where) {
921         var node = this._node,
922             ret = null;
923
924         if (typeof where == 'number') { // allow index
925             where = this._node.childNodes[where];
926         } else if (where && where._node) { // Node
927             where = where._node;
928         }
929
930         if (content && typeof content != 'string') { // allow Node or NodeList/Array instances
931             content = content._node || content._nodes || content;
932         }
933         ret = Y_DOM.addHTML(node, content, where);
934
935         return ret;
936     },
937
938     /**
939      * Inserts the content as the firstChild of the node.
940      * @method prepend
941      * @param {String | Y.Node | HTMLElement} content The content to insert
942      * @chainable
943      */
944     prepend: function(content) {
945         return this.insert(content, 0);
946     },
947
948     /**
949      * Inserts the content as the lastChild of the node.
950      * @method append
951      * @param {String | Y.Node | HTMLElement} content The content to insert
952      * @chainable
953      */
954     append: function(content) {
955         return this.insert(content, null);
956     },
957
958     /**
959      * Appends the node to the given node. 
960      * @method appendTo
961      * @param {Y.Node | HTMLElement} node The node to append to
962      * @chainable
963      */
964     appendTo: function(node) {
965         Y.one(node).append(this);
966         return this;
967     },
968
969     /**
970      * Replaces the node's current content with the content.
971      * @method setContent
972      * @param {String | Y.Node | HTMLElement | Y.NodeList | HTMLCollection} content The content to insert
973      * @chainable
974      */
975     setContent: function(content) {
976         this._insert(content, 'replace');
977         return this;
978     },
979
980     /**
981      * Returns the node's current content (e.g. innerHTML) 
982      * @method getContent
983      * @return {String} The current content
984      */
985     getContent: function(content) {
986         return this.get('innerHTML');
987     },
988
989     /**
990     * @method swap
991     * @description Swap DOM locations with the given node.
992     * This does not change which DOM node each Node instance refers to.
993     * @param {Node} otherNode The node to swap with
994      * @chainable
995     */
996     swap: Y.config.doc.documentElement.swapNode ?
997         function(otherNode) {
998             this._node.swapNode(Y_Node.getDOMNode(otherNode));
999         } :
1000         function(otherNode) {
1001             otherNode = Y_Node.getDOMNode(otherNode);
1002             var node = this._node,
1003                 parent = otherNode.parentNode,
1004                 nextSibling = otherNode.nextSibling;
1005
1006             if (nextSibling === node) {
1007                 parent.insertBefore(node, otherNode);
1008             } else if (otherNode === node.nextSibling) {
1009                 parent.insertBefore(otherNode, node);
1010             } else {
1011                 node.parentNode.replaceChild(otherNode, node);
1012                 Y_DOM.addHTML(parent, node, nextSibling);
1013             }
1014             return this;
1015         },
1016
1017
1018     /**
1019     * @method getData
1020     * @description Retrieves arbitrary data stored on a Node instance.
1021     * This is not stored with the DOM node.
1022     * @param {string} name Optional name of the data field to retrieve.
1023     * If no name is given, all data is returned.
1024     * @return {any | Object} Whatever is stored at the given field,
1025     * or an object hash of all fields.
1026     */
1027     getData: function(name) {
1028         var ret;
1029         this._data = this._data || {};
1030         if (arguments.length) {
1031             ret = this._data[name];
1032         } else {
1033             ret = this._data;
1034         }
1035
1036         return ret;
1037
1038     },
1039
1040     /**
1041     * @method setData
1042     * @description Stores arbitrary data on a Node instance.
1043     * This is not stored with the DOM node.
1044     * @param {string} name The name of the field to set. If no name
1045     * is given, name is treated as the data and overrides any existing data.
1046     * @param {any} val The value to be assigned to the field.
1047     * @chainable
1048     */
1049     setData: function(name, val) {
1050         this._data = this._data || {};
1051         if (arguments.length > 1) {
1052             this._data[name] = val;
1053         } else {
1054             this._data = name;
1055         }
1056
1057        return this;
1058     },
1059
1060     /**
1061     * @method clearData
1062     * @description Clears stored data.
1063     * @param {string} name The name of the field to clear. If no name
1064     * is given, all data is cleared.
1065     * @chainable
1066     */
1067     clearData: function(name) {
1068         if ('_data' in this) {
1069             if (name) {
1070                 delete this._data[name];
1071             } else {
1072                 delete this._data;
1073             }
1074         }
1075
1076         return this;
1077     },
1078
1079     hasMethod: function(method) {
1080         var node = this._node;
1081         return !!(node && method in node &&
1082                 typeof node[method] != 'unknown' &&
1083             (typeof node[method] == 'function' ||
1084                 String(node[method]).indexOf('function') === 1)); // IE reports as object, prepends space
1085     },
1086
1087     SHOW_TRANSITION: null,
1088     HIDE_TRANSITION: null,
1089
1090     /**
1091      * Makes the node visible.
1092      * If the "transition" module is loaded, show optionally
1093      * animates the showing of the node using either the default
1094      * transition effect ('fadeIn'), or the given named effect.
1095      * @method show
1096      * @param {String} name A named Transition effect to use as the show effect. 
1097      * @param {Object} config Options to use with the transition. 
1098      * @param {Function} callback An optional function to run after the transition completes. 
1099      * @chainable
1100      */
1101     show: function(callback) {
1102         callback = arguments[arguments.length - 1];
1103         this.toggleView(true, callback);
1104         return this;
1105     },
1106
1107     /**
1108      * The implementation for showing nodes.
1109      * Default is to toggle the style.display property.
1110      * @protected
1111      * @chainable
1112      */
1113     _show: function() {
1114         this.setStyle('display', '');
1115
1116     },
1117
1118     _isHidden: function() {
1119         return Y.DOM.getStyle(this._node, 'display') === 'none';
1120     },
1121
1122     toggleView: function(on, callback) {
1123         this._toggleView.apply(this, arguments);
1124     },
1125
1126     _toggleView: function(on, callback) {
1127         callback = arguments[arguments.length - 1];
1128
1129         // base on current state if not forcing 
1130         if (typeof on != 'boolean') {
1131             on = (this._isHidden()) ? 1 : 0;
1132         }
1133
1134         if (on) {
1135             this._show();
1136         }  else {
1137             this._hide();
1138         }
1139
1140         if (typeof callback == 'function') {
1141             callback.call(this);
1142         }
1143
1144         return this;
1145     },
1146
1147     /**
1148      * Hides the node.
1149      * If the "transition" module is loaded, hide optionally
1150      * animates the hiding of the node using either the default
1151      * transition effect ('fadeOut'), or the given named effect.
1152      * @method hide
1153      * @param {String} name A named Transition effect to use as the show effect. 
1154      * @param {Object} config Options to use with the transition. 
1155      * @param {Function} callback An optional function to run after the transition completes. 
1156      * @chainable
1157      */
1158     hide: function(callback) {
1159         callback = arguments[arguments.length - 1];
1160         this.toggleView(false, callback);
1161         return this;
1162     },
1163
1164     /**
1165      * The implementation for hiding nodes.
1166      * Default is to toggle the style.display property.
1167      * @protected
1168      * @chainable
1169      */
1170     _hide: function() {
1171         this.setStyle('display', 'none');
1172     },
1173
1174     isFragment: function() {
1175         return (this.get('nodeType') === 11);
1176     },
1177
1178     /**
1179      * Removes all of the child nodes from the node.
1180      * @param {Boolean} destroy Whether the nodes should also be destroyed. 
1181      * @chainable
1182      */
1183     empty: function(destroy) {
1184         this.get('childNodes').remove(destroy);
1185         return this;
1186     }
1187
1188 }, true);
1189
1190 Y.Node = Y_Node;
1191 Y.one = Y.Node.one;
1192 /**
1193  * The NodeList module provides support for managing collections of Nodes.
1194  * @module node
1195  * @submodule nodelist
1196  */
1197
1198 /**
1199  * The NodeList class provides a wrapper for manipulating DOM NodeLists.
1200  * NodeList properties can be accessed via the set/get methods.
1201  * Use Y.all() to retrieve NodeList instances.
1202  *
1203  * @class NodeList
1204  * @constructor
1205  */
1206
1207 var NodeList = function(nodes) {
1208     var tmp = [];
1209     if (typeof nodes === 'string') { // selector query
1210         this._query = nodes;
1211         nodes = Y.Selector.query(nodes);
1212     } else if (nodes.nodeType || Y_DOM.isWindow(nodes)) { // domNode || window
1213         nodes = [nodes];
1214     } else if (Y.instanceOf(nodes, Y.Node)) {
1215         nodes = [nodes._node];
1216     } else if (Y.instanceOf(nodes[0], Y.Node)) { // allow array of Y.Nodes
1217         Y.Array.each(nodes, function(node) {
1218             if (node._node) {
1219                 tmp.push(node._node);
1220             }
1221         });
1222         nodes = tmp;
1223     } else { // array of domNodes or domNodeList (no mixed array of Y.Node/domNodes)
1224         nodes = Y.Array(nodes, 0, true);
1225     }
1226
1227     /**
1228      * The underlying array of DOM nodes bound to the Y.NodeList instance
1229      * @property _nodes
1230      * @private
1231      */
1232     this._nodes = nodes;
1233 };
1234
1235 NodeList.NAME = 'NodeList';
1236
1237 /**
1238  * Retrieves the DOM nodes bound to a NodeList instance
1239  * @method NodeList.getDOMNodes
1240  * @static
1241  *
1242  * @param {Y.NodeList} nodelist The NodeList instance
1243  * @return {Array} The array of DOM nodes bound to the NodeList
1244  */
1245 NodeList.getDOMNodes = function(nodelist) {
1246     return (nodelist && nodelist._nodes) ? nodelist._nodes : nodelist;
1247 };
1248
1249 NodeList.each = function(instance, fn, context) {
1250     var nodes = instance._nodes;
1251     if (nodes && nodes.length) {
1252         Y.Array.each(nodes, fn, context || instance);
1253     } else {
1254     }
1255 };
1256
1257 NodeList.addMethod = function(name, fn, context) {
1258     if (name && fn) {
1259         NodeList.prototype[name] = function() {
1260             var ret = [],
1261                 args = arguments;
1262
1263             Y.Array.each(this._nodes, function(node) {
1264                 var UID = (node.uniqueID && node.nodeType !== 9 ) ? 'uniqueID' : '_yuid',
1265                     instance = Y.Node._instances[node[UID]],
1266                     ctx,
1267                     result;
1268
1269                 if (!instance) {
1270                     instance = NodeList._getTempNode(node);
1271                 }
1272                 ctx = context || instance;
1273                 result = fn.apply(ctx, args);
1274                 if (result !== undefined && result !== instance) {
1275                     ret[ret.length] = result;
1276                 }
1277             });
1278
1279             // TODO: remove tmp pointer
1280             return ret.length ? ret : this;
1281         };
1282     } else {
1283     }
1284 };
1285
1286 NodeList.importMethod = function(host, name, altName) {
1287     if (typeof name === 'string') {
1288         altName = altName || name;
1289         NodeList.addMethod(name, host[name]);
1290     } else {
1291         Y.Array.each(name, function(n) {
1292             NodeList.importMethod(host, n);
1293         });
1294     }
1295 };
1296
1297 NodeList._getTempNode = function(node) {
1298     var tmp = NodeList._tempNode;
1299     if (!tmp) {
1300         tmp = Y.Node.create('<div></div>');
1301         NodeList._tempNode = tmp;
1302     }
1303
1304     tmp._node = node;
1305     tmp._stateProxy = node;
1306     return tmp;
1307 };
1308
1309 Y.mix(NodeList.prototype, {
1310     /**
1311      * Retrieves the Node instance at the given index.
1312      * @method item
1313      *
1314      * @param {Number} index The index of the target Node.
1315      * @return {Node} The Node instance at the given index.
1316      */
1317     item: function(index) {
1318         return Y.one((this._nodes || [])[index]);
1319     },
1320
1321     /**
1322      * Applies the given function to each Node in the NodeList.
1323      * @method each
1324      * @param {Function} fn The function to apply. It receives 3 arguments:
1325      * the current node instance, the node's index, and the NodeList instance
1326      * @param {Object} context optional An optional context to apply the function with
1327      * Default context is the current Node instance
1328      * @chainable
1329      */
1330     each: function(fn, context) {
1331         var instance = this;
1332         Y.Array.each(this._nodes, function(node, index) {
1333             node = Y.one(node);
1334             return fn.call(context || node, node, index, instance);
1335         });
1336         return instance;
1337     },
1338
1339     batch: function(fn, context) {
1340         var nodelist = this;
1341
1342         Y.Array.each(this._nodes, function(node, index) {
1343             var instance = Y.Node._instances[node[UID]];
1344             if (!instance) {
1345                 instance = NodeList._getTempNode(node);
1346             }
1347
1348             return fn.call(context || instance, instance, index, nodelist);
1349         });
1350         return nodelist;
1351     },
1352
1353     /**
1354      * Executes the function once for each node until a true value is returned.
1355      * @method some
1356      * @param {Function} fn The function to apply. It receives 3 arguments:
1357      * the current node instance, the node's index, and the NodeList instance
1358      * @param {Object} context optional An optional context to execute the function from.
1359      * Default context is the current Node instance
1360      * @return {Boolean} Whether or not the function returned true for any node.
1361      */
1362     some: function(fn, context) {
1363         var instance = this;
1364         return Y.Array.some(this._nodes, function(node, index) {
1365             node = Y.one(node);
1366             context = context || node;
1367             return fn.call(context, node, index, instance);
1368         });
1369     },
1370
1371     /**
1372      * Creates a documenFragment from the nodes bound to the NodeList instance
1373      * @method toFrag
1374      * @return Node a Node instance bound to the documentFragment
1375      */
1376     toFrag: function() {
1377         return Y.one(Y.DOM._nl2frag(this._nodes));
1378     },
1379
1380     /**
1381      * Returns the index of the node in the NodeList instance
1382      * or -1 if the node isn't found.
1383      * @method indexOf
1384      * @param {Y.Node || DOMNode} node the node to search for
1385      * @return {Int} the index of the node value or -1 if not found
1386      */
1387     indexOf: function(node) {
1388         return Y.Array.indexOf(this._nodes, Y.Node.getDOMNode(node));
1389     },
1390
1391     /**
1392      * Filters the NodeList instance down to only nodes matching the given selector.
1393      * @method filter
1394      * @param {String} selector The selector to filter against
1395      * @return {NodeList} NodeList containing the updated collection
1396      * @see Selector
1397      */
1398     filter: function(selector) {
1399         return Y.all(Y.Selector.filter(this._nodes, selector));
1400     },
1401
1402
1403     /**
1404      * Creates a new NodeList containing all nodes at every n indices, where
1405      * remainder n % index equals r.
1406      * (zero-based index).
1407      * @method modulus
1408      * @param {Int} n The offset to use (return every nth node)
1409      * @param {Int} r An optional remainder to use with the modulus operation (defaults to zero)
1410      * @return {NodeList} NodeList containing the updated collection
1411      */
1412     modulus: function(n, r) {
1413         r = r || 0;
1414         var nodes = [];
1415         NodeList.each(this, function(node, i) {
1416             if (i % n === r) {
1417                 nodes.push(node);
1418             }
1419         });
1420
1421         return Y.all(nodes);
1422     },
1423
1424     /**
1425      * Creates a new NodeList containing all nodes at odd indices
1426      * (zero-based index).
1427      * @method odd
1428      * @return {NodeList} NodeList containing the updated collection
1429      */
1430     odd: function() {
1431         return this.modulus(2, 1);
1432     },
1433
1434     /**
1435      * Creates a new NodeList containing all nodes at even indices
1436      * (zero-based index), including zero.
1437      * @method even
1438      * @return {NodeList} NodeList containing the updated collection
1439      */
1440     even: function() {
1441         return this.modulus(2);
1442     },
1443
1444     destructor: function() {
1445     },
1446
1447     /**
1448      * Reruns the initial query, when created using a selector query
1449      * @method refresh
1450      * @chainable
1451      */
1452     refresh: function() {
1453         var doc,
1454             nodes = this._nodes,
1455             query = this._query,
1456             root = this._queryRoot;
1457
1458         if (query) {
1459             if (!root) {
1460                 if (nodes && nodes[0] && nodes[0].ownerDocument) {
1461                     root = nodes[0].ownerDocument;
1462                 }
1463             }
1464
1465             this._nodes = Y.Selector.query(query, root);
1466         }
1467
1468         return this;
1469     },
1470
1471     _prepEvtArgs: function(type, fn, context) {
1472         // map to Y.on/after signature (type, fn, nodes, context, arg1, arg2, etc)
1473         var args = Y.Array(arguments, 0, true);
1474
1475         if (args.length < 2) { // type only (event hash) just add nodes
1476             args[2] = this._nodes;
1477         } else {
1478             args.splice(2, 0, this._nodes);
1479         }
1480
1481         args[3] = context || this; // default to NodeList instance as context
1482
1483         return args;
1484     },
1485
1486     /**
1487      * Applies an event listener to each Node bound to the NodeList.
1488      * @method on
1489      * @param {String} type The event being listened for
1490      * @param {Function} fn The handler to call when the event fires
1491      * @param {Object} context The context to call the handler with.
1492      * Default is the NodeList instance.
1493      * @param {Object} context The context to call the handler with.
1494      * param {mixed} arg* 0..n additional arguments to supply to the subscriber
1495      * when the event fires.
1496      * @return {Object} Returns an event handle that can later be use to detach().
1497      * @see Event.on
1498      */
1499     on: function(type, fn, context) {
1500         return Y.on.apply(Y, this._prepEvtArgs.apply(this, arguments));
1501     },
1502
1503     /**
1504      * Applies an one-time event listener to each Node bound to the NodeList.
1505      * @method once
1506      * @param {String} type The event being listened for
1507      * @param {Function} fn The handler to call when the event fires
1508      * @param {Object} context The context to call the handler with.
1509      * Default is the NodeList instance.
1510      * @return {Object} Returns an event handle that can later be use to detach().
1511      * @see Event.on
1512      */
1513     once: function(type, fn, context) {
1514         return Y.once.apply(Y, this._prepEvtArgs.apply(this, arguments));
1515     },
1516
1517     /**
1518      * Applies an event listener to each Node bound to the NodeList.
1519      * The handler is called only after all on() handlers are called
1520      * and the event is not prevented.
1521      * @method after
1522      * @param {String} type The event being listened for
1523      * @param {Function} fn The handler to call when the event fires
1524      * @param {Object} context The context to call the handler with.
1525      * Default is the NodeList instance.
1526      * @return {Object} Returns an event handle that can later be use to detach().
1527      * @see Event.on
1528      */
1529     after: function(type, fn, context) {
1530         return Y.after.apply(Y, this._prepEvtArgs.apply(this, arguments));
1531     },
1532
1533     /**
1534      * Returns the current number of items in the NodeList.
1535      * @method size
1536      * @return {Int} The number of items in the NodeList.
1537      */
1538     size: function() {
1539         return this._nodes.length;
1540     },
1541
1542     /**
1543      * Determines if the instance is bound to any nodes
1544      * @method isEmpty
1545      * @return {Boolean} Whether or not the NodeList is bound to any nodes
1546      */
1547     isEmpty: function() {
1548         return this._nodes.length < 1;
1549     },
1550
1551     toString: function() {
1552         var str = '',
1553             errorMsg = this[UID] + ': not bound to any nodes',
1554             nodes = this._nodes,
1555             node;
1556
1557         if (nodes && nodes[0]) {
1558             node = nodes[0];
1559             str += node[NODE_NAME];
1560             if (node.id) {
1561                 str += '#' + node.id;
1562             }
1563
1564             if (node.className) {
1565                 str += '.' + node.className.replace(' ', '.');
1566             }
1567
1568             if (nodes.length > 1) {
1569                 str += '...[' + nodes.length + ' items]';
1570             }
1571         }
1572         return str || errorMsg;
1573     }
1574
1575 }, true);
1576
1577 NodeList.importMethod(Y.Node.prototype, [
1578     /**
1579      * Called on each Node instance
1580      * @for NodeList
1581      * @method append
1582      * @see Node.append
1583      */
1584     'append',
1585
1586     /** Called on each Node instance
1587       * @method destroy
1588       * @see Node.destroy
1589       */
1590     'destroy',
1591
1592     /**
1593       * Called on each Node instance
1594       * @method detach
1595       * @see Node.detach
1596       */
1597     'detach',
1598
1599     /** Called on each Node instance
1600       * @method detachAll
1601       * @see Node.detachAll
1602       */
1603     'detachAll',
1604
1605     /** Called on each Node instance
1606       * @method empty
1607       * @see Node.empty
1608       */
1609     'empty',
1610
1611     /** Called on each Node instance
1612       * @method insert
1613       * @see Node.insert
1614       */
1615     'insert',
1616
1617     /** Called on each Node instance
1618       * @method prepend
1619       * @see Node.prepend
1620       */
1621     'prepend',
1622
1623     /** Called on each Node instance
1624       * @method remove
1625       * @see Node.remove
1626       */
1627     'remove',
1628
1629     /** Called on each Node instance
1630       * @method set
1631       * @see Node.set
1632       */
1633     'set',
1634
1635     /** Called on each Node instance
1636       * @method setContent
1637       * @see Node.setContent
1638       */
1639     'setContent',
1640
1641     /**
1642      * Makes each node visible.
1643      * If the "transition" module is loaded, show optionally
1644      * animates the showing of the node using either the default
1645      * transition effect ('fadeIn'), or the given named effect.
1646      * @method show
1647      * @param {String} name A named Transition effect to use as the show effect. 
1648      * @param {Object} config Options to use with the transition. 
1649      * @param {Function} callback An optional function to run after the transition completes. 
1650      * @chainable
1651      */
1652     'show',
1653
1654     /**
1655      * Hides each node.
1656      * If the "transition" module is loaded, hide optionally
1657      * animates the hiding of the node using either the default
1658      * transition effect ('fadeOut'), or the given named effect.
1659      * @method hide
1660      * @param {String} name A named Transition effect to use as the show effect. 
1661      * @param {Object} config Options to use with the transition. 
1662      * @param {Function} callback An optional function to run after the transition completes. 
1663      * @chainable
1664      */
1665     'hide',
1666
1667     'toggleView'
1668 ]);
1669
1670 // one-off implementation to convert array of Nodes to NodeList
1671 // e.g. Y.all('input').get('parentNode');
1672
1673 /** Called on each Node instance
1674   * @method get
1675   * @see Node
1676   */
1677 NodeList.prototype.get = function(attr) {
1678     var ret = [],
1679         nodes = this._nodes,
1680         isNodeList = false,
1681         getTemp = NodeList._getTempNode,
1682         instance,
1683         val;
1684
1685     if (nodes[0]) {
1686         instance = Y.Node._instances[nodes[0]._yuid] || getTemp(nodes[0]);
1687         val = instance._get(attr);
1688         if (val && val.nodeType) {
1689             isNodeList = true;
1690         }
1691     }
1692
1693     Y.Array.each(nodes, function(node) {
1694         instance = Y.Node._instances[node._yuid];
1695
1696         if (!instance) {
1697             instance = getTemp(node);
1698         }
1699
1700         val = instance._get(attr);
1701         if (!isNodeList) { // convert array of Nodes to NodeList
1702             val = Y.Node.scrubVal(val, instance);
1703         }
1704
1705         ret.push(val);
1706     });
1707
1708     return (isNodeList) ? Y.all(ret) : ret;
1709 };
1710
1711 Y.NodeList = NodeList;
1712
1713 Y.all = function(nodes) {
1714     return new NodeList(nodes);
1715 };
1716
1717 Y.Node.all = Y.all;
1718 Y.Array.each([
1719     /**
1720      * Passes through to DOM method.
1721      * @for Node
1722      * @method removeChild
1723      * @param {HTMLElement | Node} node Node to be removed 
1724      * @return {Node} The removed node 
1725      */
1726     'removeChild',
1727
1728     /**
1729      * Passes through to DOM method.
1730      * @method hasChildNodes
1731      * @return {Boolean} Whether or not the node has any childNodes 
1732      */
1733     'hasChildNodes',
1734
1735     /**
1736      * Passes through to DOM method.
1737      * @method cloneNode
1738      * @param {Boolean} deep Whether or not to perform a deep clone, which includes
1739      * subtree and attributes
1740      * @return {Node} The clone 
1741      */
1742     'cloneNode',
1743
1744     /**
1745      * Passes through to DOM method.
1746      * @method hasAttribute
1747      * @param {String} attribute The attribute to test for 
1748      * @return {Boolean} Whether or not the attribute is present 
1749      */
1750     'hasAttribute',
1751
1752     /**
1753      * Passes through to DOM method.
1754      * @method removeAttribute
1755      * @param {String} attribute The attribute to be removed 
1756      * @chainable
1757      */
1758     'removeAttribute',
1759
1760     /**
1761      * Passes through to DOM method.
1762      * @method scrollIntoView
1763      * @chainable
1764      */
1765     'scrollIntoView',
1766
1767     /**
1768      * Passes through to DOM method.
1769      * @method getElementsByTagName
1770      * @param {String} tagName The tagName to collect 
1771      * @return {NodeList} A NodeList representing the HTMLCollection
1772      */
1773     'getElementsByTagName',
1774
1775     /**
1776      * Passes through to DOM method.
1777      * @method focus
1778      * @chainable
1779      */
1780     'focus',
1781
1782     /**
1783      * Passes through to DOM method.
1784      * @method blur
1785      * @chainable
1786      */
1787     'blur',
1788
1789     /**
1790      * Passes through to DOM method.
1791      * Only valid on FORM elements
1792      * @method submit
1793      * @chainable
1794      */
1795     'submit',
1796
1797     /**
1798      * Passes through to DOM method.
1799      * Only valid on FORM elements
1800      * @method reset
1801      * @chainable
1802      */
1803     'reset',
1804
1805     /**
1806      * Passes through to DOM method.
1807      * @method select
1808      * @chainable
1809      */
1810      'select',
1811
1812     /**
1813      * Passes through to DOM method.
1814      * Only valid on TABLE elements
1815      * @method createCaption
1816      * @chainable
1817      */
1818     'createCaption'
1819
1820 ], function(method) {
1821     Y.Node.prototype[method] = function(arg1, arg2, arg3) {
1822         var ret = this.invoke(method, arg1, arg2, arg3);
1823         return ret;
1824     };
1825 });
1826
1827 Y.Node.importMethod(Y.DOM, [
1828     /**
1829      * Determines whether the node is an ancestor of another HTML element in the DOM hierarchy.
1830      * @method contains
1831      * @param {Node | HTMLElement} needle The possible node or descendent
1832      * @return {Boolean} Whether or not this node is the needle its ancestor
1833      */
1834     'contains',
1835     /**
1836      * Allows setting attributes on DOM nodes, normalizing in some cases.
1837      * This passes through to the DOM node, allowing for custom attributes.
1838      * @method setAttribute
1839      * @for Node
1840      * @for NodeList
1841      * @chainable
1842      * @param {string} name The attribute name 
1843      * @param {string} value The value to set
1844      */
1845     'setAttribute',
1846     /**
1847      * Allows getting attributes on DOM nodes, normalizing in some cases.
1848      * This passes through to the DOM node, allowing for custom attributes.
1849      * @method getAttribute
1850      * @for Node
1851      * @for NodeList
1852      * @param {string} name The attribute name 
1853      * @return {string} The attribute value 
1854      */
1855     'getAttribute',
1856
1857     /**
1858      * Wraps the given HTML around the node.
1859      * @method wrap
1860      * @param {String} html The markup to wrap around the node. 
1861      * @chainable
1862      */
1863     'wrap',
1864
1865     /**
1866      * Removes the node's parent node. 
1867      * @method unwrap
1868      * @chainable
1869      */
1870     'unwrap',
1871
1872     /**
1873      * Applies a unique ID to the node if none exists
1874      * @method generateID
1875      * @return {String} The existing or generated ID
1876      */
1877     'generateID'
1878 ]);
1879
1880 Y.NodeList.importMethod(Y.Node.prototype, [
1881 /**
1882  * Allows getting attributes on DOM nodes, normalizing in some cases.
1883  * This passes through to the DOM node, allowing for custom attributes.
1884  * @method getAttribute
1885  * @see Node
1886  * @for NodeList
1887  * @param {string} name The attribute name 
1888  * @return {string} The attribute value 
1889  */
1890
1891     'getAttribute',
1892 /**
1893  * Allows setting attributes on DOM nodes, normalizing in some cases.
1894  * This passes through to the DOM node, allowing for custom attributes.
1895  * @method setAttribute
1896  * @see Node
1897  * @for NodeList
1898  * @chainable
1899  * @param {string} name The attribute name 
1900  * @param {string} value The value to set
1901  */
1902     'setAttribute',
1903  
1904 /**
1905  * Allows for removing attributes on DOM nodes.
1906  * This passes through to the DOM node, allowing for custom attributes.
1907  * @method removeAttribute
1908  * @see Node
1909  * @for NodeList
1910  * @param {string} name The attribute to remove 
1911  */
1912     'removeAttribute',
1913 /**
1914  * Removes the parent node from node in the list. 
1915  * @method unwrap
1916  * @chainable
1917  */
1918     'unwrap',
1919 /**
1920  * Wraps the given HTML around each node.
1921  * @method wrap
1922  * @param {String} html The markup to wrap around the node. 
1923  * @chainable
1924  */
1925     'wrap',
1926
1927 /**
1928  * Applies a unique ID to each node if none exists
1929  * @method generateID
1930  * @return {String} The existing or generated ID
1931  */
1932     'generateID'
1933 ]);
1934 (function(Y) {
1935     var methods = [
1936     /**
1937      * Determines whether each node has the given className.
1938      * @method hasClass
1939      * @for Node
1940      * @param {String} className the class name to search for
1941      * @return {Boolean} Whether or not the element has the specified class 
1942      */
1943      'hasClass',
1944
1945     /**
1946      * Adds a class name to each node.
1947      * @method addClass         
1948      * @param {String} className the class name to add to the node's class attribute
1949      * @chainable
1950      */
1951      'addClass',
1952
1953     /**
1954      * Removes a class name from each node.
1955      * @method removeClass         
1956      * @param {String} className the class name to remove from the node's class attribute
1957      * @chainable
1958      */
1959      'removeClass',
1960
1961     /**
1962      * Replace a class with another class for each node.
1963      * If no oldClassName is present, the newClassName is simply added.
1964      * @method replaceClass  
1965      * @param {String} oldClassName the class name to be replaced
1966      * @param {String} newClassName the class name that will be replacing the old class name
1967      * @chainable
1968      */
1969      'replaceClass',
1970
1971     /**
1972      * If the className exists on the node it is removed, if it doesn't exist it is added.
1973      * @method toggleClass  
1974      * @param {String} className the class name to be toggled
1975      * @param {Boolean} force Option to force adding or removing the class. 
1976      * @chainable
1977      */
1978      'toggleClass'
1979     ];
1980
1981     Y.Node.importMethod(Y.DOM, methods);
1982     /**
1983      * Determines whether each node has the given className.
1984      * @method hasClass
1985      * @see Node.hasClass
1986      * @for NodeList
1987      * @param {String} className the class name to search for
1988      * @return {Array} An array of booleans for each node bound to the NodeList. 
1989      */
1990
1991     /**
1992      * Adds a class name to each node.
1993      * @method addClass         
1994      * @see Node.addClass
1995      * @param {String} className the class name to add to the node's class attribute
1996      * @chainable
1997      */
1998
1999     /**
2000      * Removes a class name from each node.
2001      * @method removeClass         
2002      * @see Node.removeClass
2003      * @param {String} className the class name to remove from the node's class attribute
2004      * @chainable
2005      */
2006
2007     /**
2008      * Replace a class with another class for each node.
2009      * If no oldClassName is present, the newClassName is simply added.
2010      * @method replaceClass  
2011      * @see Node.replaceClass
2012      * @param {String} oldClassName the class name to be replaced
2013      * @param {String} newClassName the class name that will be replacing the old class name
2014      * @chainable
2015      */
2016
2017     /**
2018      * If the className exists on the node it is removed, if it doesn't exist it is added.
2019      * @method toggleClass  
2020      * @see Node.toggleClass
2021      * @param {String} className the class name to be toggled
2022      * @chainable
2023      */
2024     Y.NodeList.importMethod(Y.Node.prototype, methods);
2025 })(Y);
2026
2027 if (!Y.config.doc.documentElement.hasAttribute) { // IE < 8
2028     Y.Node.prototype.hasAttribute = function(attr) {
2029         if (attr === 'value') {
2030             if (this.get('value') !== "") { // IE < 8 fails to populate specified when set in HTML
2031                 return true;
2032             }
2033         }
2034         return !!(this._node.attributes[attr] &&
2035                 this._node.attributes[attr].specified);
2036     };
2037 }
2038
2039 // IE throws an error when calling focus() on an element that's invisible, not
2040 // displayed, or disabled.
2041 Y.Node.prototype.focus = function () {
2042     try {
2043         this._node.focus();
2044     } catch (e) {
2045     }
2046 };
2047
2048 // IE throws error when setting input.type = 'hidden',
2049 // input.setAttribute('type', 'hidden') and input.attributes.type.value = 'hidden'
2050 Y.Node.ATTRS.type = {
2051     setter: function(val) {
2052         if (val === 'hidden') {
2053             try {
2054                 this._node.type = 'hidden';
2055             } catch(e) {
2056                 this.setStyle('display', 'none');
2057                 this._inputType = 'hidden';
2058             }
2059         } else {
2060             try { // IE errors when changing the type from "hidden'
2061                 this._node.type = val;
2062             } catch (e) {
2063             }
2064         }
2065         return val;
2066     },
2067
2068     getter: function() {
2069         return this._inputType || this._node.type;
2070     },
2071
2072     _bypassProxy: true // don't update DOM when using with Attribute
2073 };
2074
2075 if (Y.config.doc.createElement('form').elements.nodeType) {
2076     // IE: elements collection is also FORM node which trips up scrubVal.
2077     Y.Node.ATTRS.elements = {
2078             getter: function() {
2079                 return this.all('input, textarea, button, select');
2080             }
2081     };
2082 }
2083
2084 Y.mix(Y.Node.ATTRS, {
2085     offsetHeight: {
2086         setter: function(h) {
2087             Y.DOM.setHeight(this._node, h);
2088             return h;
2089         },
2090
2091         getter: function() {
2092             return this._node.offsetHeight;
2093         }
2094     },
2095
2096     offsetWidth: {
2097         setter: function(w) {
2098             Y.DOM.setWidth(this._node, w);
2099             return w;
2100         },
2101
2102         getter: function() {
2103             return this._node.offsetWidth;
2104         }
2105     }
2106 });
2107
2108 Y.mix(Y.Node.prototype, {
2109     sizeTo: function(w, h) {
2110         var node;
2111         if (arguments.length < 2) {
2112             node = Y.one(w);
2113             w = node.get('offsetWidth');
2114             h = node.get('offsetHeight');
2115         }
2116
2117         this.setAttrs({
2118             offsetWidth: w,
2119             offsetHeight: h
2120         });
2121     }
2122 });
2123 var Y_NodeList = Y.NodeList,
2124     ArrayProto = Array.prototype,
2125     ArrayMethods = [
2126         /** Returns a new NodeList combining the given NodeList(s) 
2127           * @for NodeList
2128           * @method concat
2129           * @param {NodeList | Array} valueN Arrays/NodeLists and/or values to
2130           * concatenate to the resulting NodeList
2131           * @return {NodeList} A new NodeList comprised of this NodeList joined with the input.
2132           */
2133         'concat',
2134         /** Removes the first last from the NodeList and returns it.
2135           * @for NodeList
2136           * @method pop
2137           * @return {Node} The last item in the NodeList.
2138           */
2139         'pop',
2140         /** Adds the given Node(s) to the end of the NodeList. 
2141           * @for NodeList
2142           * @method push
2143           * @param {Node | DOMNode} nodeN One or more nodes to add to the end of the NodeList. 
2144           */
2145         'push',
2146         /** Removes the first item from the NodeList and returns it.
2147           * @for NodeList
2148           * @method shift
2149           * @return {Node} The first item in the NodeList.
2150           */
2151         'shift',
2152         /** Returns a new NodeList comprising the Nodes in the given range. 
2153           * @for NodeList
2154           * @method slice
2155           * @param {Number} begin Zero-based index at which to begin extraction.
2156           As a negative index, start indicates an offset from the end of the sequence. slice(-2) extracts the second-to-last element and the last element in the sequence.
2157           * @param {Number} end Zero-based index at which to end extraction. slice extracts up to but not including end.
2158           slice(1,4) extracts the second element through the fourth element (elements indexed 1, 2, and 3).
2159           As a negative index, end indicates an offset from the end of the sequence. slice(2,-1) extracts the third element through the second-to-last element in the sequence.
2160           If end is omitted, slice extracts to the end of the sequence.
2161           * @return {NodeList} A new NodeList comprised of this NodeList joined with the input.
2162           */
2163         'slice',
2164         /** Changes the content of the NodeList, adding new elements while removing old elements.
2165           * @for NodeList
2166           * @method splice
2167           * @param {Number} index Index at which to start changing the array. If negative, will begin that many elements from the end.
2168           * @param {Number} howMany An integer indicating the number of old array elements to remove. If howMany is 0, no elements are removed. In this case, you should specify at least one new element. If no howMany parameter is specified (second syntax above, which is a SpiderMonkey extension), all elements after index are removed.
2169           * {Node | DOMNode| element1, ..., elementN 
2170           The elements to add to the array. If you don't specify any elements, splice simply removes elements from the array.
2171           * @return {NodeList} The element(s) removed.
2172           */
2173         'splice',
2174         /** Adds the given Node(s) to the beginning of the NodeList. 
2175           * @for NodeList
2176           * @method push
2177           * @param {Node | DOMNode} nodeN One or more nodes to add to the NodeList. 
2178           */
2179         'unshift'
2180     ];
2181
2182
2183 Y.Array.each(ArrayMethods, function(name) {
2184     Y_NodeList.prototype[name] = function() {
2185         var args = [],
2186             i = 0,
2187             arg;
2188
2189         while ((arg = arguments[i++])) { // use DOM nodes/nodeLists 
2190             args.push(arg._node || arg._nodes || arg);
2191         }
2192         return Y.Node.scrubVal(ArrayProto[name].apply(this._nodes, args));
2193     };
2194 });
2195
2196
2197 }, '3.3.0' ,{requires:['dom-base', 'selector-css2', 'event-base']});