Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

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