~landscape/lazr-js/trunk

« back to all changes in this revision

Viewing changes to src-js/lazrjs/yui/3.0.0/build/node/node-base.js

  • Committer: Sidnei da Silva
  • Date: 2009-10-21 21:43:07 UTC
  • mfrom: (120.2.15 yui-3.0.0)
  • mto: (124.5.1 trunk)
  • mto: This revision was merged to the branch mainline in revision 126.
  • Revision ID: sidnei.da.silva@canonical.com-20091021214307-mpul9404n317puk5
- Merge from yui-3.0.0, resolving conflicts

Show diffs side-by-side

added added

removed removed

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