10
10
* The Node Utility provides a DOM-like interface for interacting with DOM nodes.
12
12
* @submodule node-base
16
16
* The Node class provides a wrapper for manipulating DOM Nodes.
17
17
* Node properties can be accessed via the set/get methods.
18
18
* Use Y.get() to retrieve Node instances.
20
* <strong>NOTE:</strong> All node properties are accessed using the
21
* <code>set</code> and <code>get</code> methods.
20
* <strong>NOTE:</strong> Node properties are accessed using
21
* the <code>set</code> and <code>get</code> methods.
31
//CDATA_SECTION_NODE = 4,
32
//ENTITY_REFERENCE_NODE = 5,
34
//PROCESSING_INSTRUCTION_NODE = 7,
36
DOCUMENT_NODE = 9; //,
37
//DOCUMENT_TYPE_NODE = 10,
38
//DOCUMENT_FRAGMENT_NODE = 11,
41
27
var OWNER_DOCUMENT = 'ownerDocument',
42
28
TAG_NAME = 'tagName',
43
29
NODE_NAME = 'nodeName',
44
NODE_TYPE = 'nodeType';
46
var RE_VALID_PROP_TYPES = /(?:string|boolean|number)/;
48
var Selector = Y.Selector;
56
var wrapDOM = function(node) {
58
yuid = (node) ? node._yuid : null,
59
instance = _instances[yuid],
60
existingNode = _nodes[yuid];
63
if (NODE_TYPE in node) {
64
if (instance && existingNode && node === existingNode) {
65
ret = instance; // reuse existing Nodes if nodes match
69
} else if ('item' in node || 'push' in node) {
70
ret = new Y.NodeList(node);
76
var wrapFn = function(fn) {
30
NODE_TYPE = 'nodeType',
32
Selector = Y.Selector,
37
// used with previous/next/ancestor tests
38
var _wrapFn = function(fn) {
79
41
ret = (typeof fn === 'string') ?
81
43
return Y.Selector.test(n, fn);
84
return fn(_instances[n._yuid]);
91
var getDoc = function(node) {
92
node = _nodes[node._yuid];
93
return (node[NODE_TYPE] === 9) ? node : node[OWNER_DOCUMENT];
53
var _getDoc = function(node) {
54
var doc = Y.config.doc;
57
if (node[NODE_TYPE]) {
58
if (node[NODE_TYPE] === 9) { // already a document node
61
doc = node[OWNER_DOCUMENT];
63
} else if (Node[node._yuid]) { // Node instance document
64
doc = Node[node._yuid]()[0];
96
// returns HTMLElement
97
var getDOMNode = function(node) {
98
if (node && !node.nodeType && node._yuid) {
99
node = _nodes[node._yuid];
71
var _getDOMNode = function(node) {
72
if (node && !node[NODE_TYPE] && node._yuid) {
73
node = Node[node._yuid]()[0];
102
76
return node || null;
107
* Wraps the input and outputs of a node instance
109
var nodeInOut = function(method, a, b, c, d, e) {
110
if (a) { // first 2 may be Node instances or nodes (TODO: or strings?)
116
return wrapDOM(_nodes[this._yuid][method](a, b, c, d, e));
120
* Wraps the return value in a node instance
122
var nodeOut = function(method, a, b, c, d, e) {
123
return wrapDOM(_nodes[this._yuid][method](a, b, c, d, e));
127
* Returns directy from node method call
129
var rawOut = function(method, a, b, c, d, e) {
130
return _nodes[this._yuid][method](a, b, c, d, e);
133
var noOut = function(method, a, b, c, d, e) {
134
_nodes[this._yuid][method](a, b, c, d, e);
140
* Returns a Node instance.
141
* @property parentNode
144
'parentNode': BASE_NODE,
147
* Returns a NodeList instance.
148
* @property childNodes
151
'childNodes': BASE_NODE,
79
var Node = function() {
80
this.init.apply(this, arguments);
85
Node._deepGet = function (path, val) {
90
for (i = 0; val !== undefined && i < pl; ++i) {
98
Node._deepSet = function(path, val, subval) {
99
var leafIdx = path.length-1,
106
for (i = 0; o !== undefined && i < leafIdx; ++i) {
110
if (o !== undefined && o[path[i]] !== undefined) {
116
Node.scrubVal = function(val, node, depth) {
117
if (val !== undefined) {
118
if (typeof val === 'object' || typeof val === 'function') { // safari nodeList === function
119
if (val !== null && (
120
NODE_TYPE in val || // dom node
121
val.item || // dom collection or Node instance
122
(val[0] && val[0][NODE_TYPE]) || // assume array of nodes
123
val.document) // window TODO: restrict?
125
if (node && _restrict && _restrict[node._yuid] && !node.contains(val)) {
126
val = null; // not allowed to go outside of root node
128
if (val[NODE_TYPE] || val.document) { // node or window
135
depth = (depth === undefined) ? 4 : depth;
138
if (val.hasOwnProperty && val.hasOwnProperty(i)) {
139
val[i] = Node.scrubVal(val[i], node, --depth);
147
val = node; // for chaining
156
* Normalizes nodeInnerText and textContent.
160
'text': function(node) {
161
return Y.DOM.getText(node);
164
'options': function(node) {
165
return (node) ? node.getElementsByTagName('option') : [];
154
169
* Returns a NodeList instance.
176
* Returns a Node instance.
177
* @property firstChild
180
'firstChild': BASE_NODE,
183
* Returns a Node instance.
184
* @property lastChild
187
'lastChild': BASE_NODE,
190
* Returns a Node instance.
191
* @property previousSibling
194
'previousSibling': BASE_NODE,
197
* Returns a Node instance.
198
* @property previousSibling
201
'nextSibling': BASE_NODE,
204
* Returns a Node instance.
205
* @property ownerDocument
208
'ownerDocument': BASE_NODE,
211
* Returns a Node instance.
212
* @property offsetParent
215
'offsetParent': ELEMENT_NODE,
218
* Returns a Node instance.
219
* @property documentElement
222
'documentElement': DOCUMENT_NODE,
225
* Returns a Node instance.
229
'body': DOCUMENT_NODE,
233
* Returns a NodeList instance.
237
'elements': ELEMENT_NODE,
241
* Returns a NodeList instance.
245
'rows': ELEMENT_NODE,
248
* Returns a NodeList instance.
252
'cells': ELEMENT_NODE,
255
* Returns a Node instance.
259
'tHead': ELEMENT_NODE,
262
* Returns a Node instance.
266
'tFoot': ELEMENT_NODE,
269
* Returns a NodeList instance.
273
'tBodies': ELEMENT_NODE
277
* Passes through to DOM method.
278
* @method replaceChild
279
* @param {HTMLElement | Node} node Node to be inserted
280
* @param {HTMLElement | Node} refNode Node to be replaced
281
* @return {Node} The replaced node
283
replaceChild: nodeInOut,
286
* Passes through to DOM method.
287
* @method appendChild
288
* @param {HTMLElement | Node} node Node to be appended
289
* @return {Node} The appended node
291
appendChild: nodeInOut,
294
* Passes through to DOM method.
295
* @method insertBefore
296
* @param {HTMLElement | Node} newNode Node to be appended
297
* @param {HTMLElement | Node} refNode Node to be inserted before
298
* @return {Node} The inserted node
300
insertBefore: nodeInOut,
303
* Passes through to DOM method.
304
* @method removeChild
305
* @param {HTMLElement | Node} node Node to be removed
306
* @return {Node} The removed node
308
removeChild: nodeInOut,
311
* Passes through to DOM method.
312
* @method hasChildNodes
313
* @return {Boolean} Whether or not the node has any childNodes
315
hasChildNodes: rawOut,
318
* Passes through to DOM method.
320
* @param {HTMLElement | Node} node Node to be cloned
321
* @return {Node} The clone
326
* Passes through to DOM method.
327
* @method getAttribute
328
* @param {String} attribute The attribute to retrieve
329
* @return {String} The current value of the attribute
331
getAttribute: rawOut,
334
* Passes through to DOM method.
335
* @method setAttribute
336
* @param {String} attribute The attribute to set
337
* @param {String} The value to apply to the attribute
343
* Passes through to DOM method.
344
* @method hasAttribute
345
* @param {String} attribute The attribute to test for
346
* @return {Boolean} Whether or not the attribute is present
348
hasAttribute: rawOut,
351
* Passes through to DOM method.
352
* @method scrollIntoView
355
scrollIntoView: noOut,
358
* Passes through to DOM method.
359
* @method getElementsByTagName
360
* @param {String} tagName The tagName to collect
361
* @return {NodeList} A NodeList representing the HTMLCollection
363
getElementsByTagName: nodeOut,
366
* Passes through to DOM method.
373
* Passes through to DOM method.
380
* Passes through to DOM method.
381
* Only valid on FORM elements
388
* Passes through to DOM method.
389
* Only valid on FORM elements
396
var addNodeListMethod = function(name) {
397
NodeList.prototype[name] = function() {
399
nodes = _nodelists[this._yuid],
402
for (var i = 0, len = nodes.length; i < len; ++i) {
403
_nodes[_tmpNode._yuid] = nodes[i];
404
ret = _tmpNode[name].apply(_tmpNode, arguments);
405
if (ret !== _tmpNode) {
410
return a.length ? a : this;
414
var METHODS_INVOKE = {
415
'getBoundingClientRect': true
418
var Node = function(node) {
419
if (!node || !node[NODE_TYPE]) {
424
try { // IE errors on non-element expandos (cant be reused)
429
_instances[yuid] = this;
436
* Normalizes nodeInnerText and textContent.
440
'text': function(node) {
441
return Y.DOM.getText(_nodes[node._yuid]);
445
* Returns a nodeList of option elements
449
'options': function(node) {
450
return (node) ? node.getElementsByTagName('option') : [];
454
Node.setters = function(prop, fn) {
455
if (typeof prop == 'string') {
457
} else { // assume object
458
Y.each(prop, function(fn, prop) {
459
Node.setters(prop, fn);
464
Node.getters = function(prop, fn) {
465
if (typeof prop == 'string') {
467
} else { // assume object
468
Y.each(prop, function(fn, prop) {
469
Node.getters(prop, fn);
474
190
Node.methods = function(name, fn) {
475
191
if (typeof name == 'string') {
476
192
Node.prototype[name] = function() {
477
var args = slice.call(arguments);
479
var ret = fn.apply(null, args);
480
if (ret === undefined) {
193
var args = _slice.call(arguments, 0),
195
getAll = (_instances[this._yuid]) ? false : true, // return array of vals for lists
196
ret = (getAll) ? [] : null,
199
var getValue = function(node) {
201
val = Node.scrubVal(fn.apply(instance, args), instance);
203
ret[ret.length] = val;
210
Node[instance._yuid](getValue);
486
addNodeListMethod(name);
489
213
} else { // assume object
490
214
Y.each(name, function(fn, name) {
491
215
Node.methods(name, fn);
496
Node.getDOMNode = function(node) {
501
} else if (typeof node === 'string') {
502
ret = Selector.query(node, null, true);
504
ret = _nodes[node._yuid];
221
Node.getDOMNode = _getDOMNode;
509
223
Node.wrapDOMMethod = function(name) {
510
224
return function() {
511
var args = slice.call(arguments);
512
args.unshift(Y.Node.getDOMNode(args.shift()));
513
return Y.DOM[name].apply(Y.DOM, args);
225
return Y.DOM[name].apply(Y.DOM, arguments);
527
239
Node.prototype = {
240
init: function(nodes, doc, isRoot, getAll) {
245
this.getId = function() {
249
var _all = function(fn, i) {
252
for (var node; node = nodes[i++];) {
259
// uid = selector || Y.guid(); // to cache queryAll results
262
if (nodes) { // zero length collection returns null
263
if (nodes[NODE_TYPE] || nodes.document) { // node or window
270
if (!getAll && nodes.length) { // stamp the dom node
271
try { // IE only allows ID on Element
272
if (nodes[0].uniqueID) {
273
uid = nodes[0].uniqueID;
275
nodes[0]._yuid = uid;
276
} catch(e) { // not cacheable
281
Node[uid] = _all; // for applying/returning dom nodes
284
_instances[uid] = this;
290
initPlugins: function() {
291
Y.each(Node.PLUGINS, function(config, fn) {
292
this.plug(fn, config);
297
* Filters the NodeList instance down to only nodes matching the given selector.
299
* @param {String} selector The selector to filter against
300
* @return {NodeList} NodeList containing the updated collection
303
filter: function(selector) {
304
return Node.scrubVal(Selector.filter(Node[this._yuid](), selector), this);
308
* Applies the given function to each Node in the NodeList.
310
* @param {Function} fn The function to apply
311
* @param {Object} context optional An optional context to apply the function with
312
* Default context is the NodeList instance
313
* @return {NodeList} NodeList containing the updated collection
316
each: function(fn, context) {
317
context = context || this;
318
Node[this._yuid](function(node) {
319
fn.call(context, Node.get(node));
324
* Returns the current number of items in the NodeList.
326
* @return {Int} The number of items in the NodeList.
329
return Node[this._yuid]().length;
333
* Retrieves the Node instance at the given index.
336
* @param {Number} index The index of the target Node.
337
* @return {Node} The Node instance at the given index.
339
item: function(index) {
340
var node = Node[this._yuid]()[index];
341
return Node.get(node);
345
* Attaches a DOM event handler.
347
* @param {String} type The type of DOM Event to listen for
348
* @param {Function} fn The handler to call when the event fires
349
* @param {Object} arg An argument object to pass to the handler
352
attach: function(type, fn, arg) {
353
var args = _slice.call(arguments, 0);
354
args.splice(2, 0, Node[this._yuid]());
355
return Y.Event.attach.apply(Y.Event, args);
361
* @param {String} type The type of DOM Event to listen for
362
* @param {Function} fn The handler to call when the event fires
363
* @param {Object} arg An argument object to pass to the handler
366
on: function(type, fn, arg) {
367
return this.attach.apply(this, arguments);
371
* Detaches a DOM event handler.
373
* @param {String} type The type of DOM Event
374
* @param {Function} fn The handler to call when the event fires
376
detach: function(type, fn) {
377
var args = _slice.call(arguments, 0);
378
args.splice(2, 0, Node[this._yuid]());
379
return Y.Event.detach.apply(Y.Event, args);
383
* Creates a Node instance from HTML string
385
* @param {String|Array} html The string of html to create
386
* @return {Node} A new Node instance
388
create: function(html) {
389
return Y.Node.create(html);
393
* Applies the supplied plugin to the node.
395
* @param {Function} The plugin Class to apply
396
* @param {Object} config An optional config to pass to the constructor
399
plug: function(PluginClass, config) {
400
config = config || {};
402
if (PluginClass && PluginClass.NS) {
403
this[PluginClass.NS] = new PluginClass(config);
408
//normalize: function() {},
409
//isSupported: function(feature, version) {},
410
toString: function() {
412
node = Node[this._yuid]()[0] || {};
415
str += node[NODE_NAME];
417
str += '#' + node.id;
420
if (node.className) {
421
str += '.' + node.className.replace(' ', '.');
424
'no nodes for ' + this._yuid;
431
addEventListener: function() {
432
return Y.Event.nativeAdd.apply(Y.Event, arguments);
435
removeEventListener: function() {
436
return Y.Event.nativeRemove.apply(Y.Event, arguments);
529
440
* Set the value of the property/attribute on the HTMLElement bound to this Node.
530
441
* Only strings/numbers/booleans are passed through unless a SETTER exists.
550
465
* @param {String} prop Property to get
551
466
* @return {any} Current value of the property
553
get: function(prop) {
468
get: function(node, prop) {
555
var node = _nodes[this._yuid];
556
if (prop in GETTERS) { // use custom getter
557
val = GETTERS[prop](this, prop);
558
} else if (prop in PROPS_WRAP) { // wrap DOM object (HTMLElement, HTMLCollection, Document)
559
if (typeof PROPS_WRAP[prop] === 'function') {
560
val = PROPS_WRAP[prop](this);
470
if (prop.indexOf('.') < 0) {
471
if (prop in Node.getters) { // use custom getter
472
val = Node.getters[prop].call(this, node, prop);
562
474
val = node[prop];
565
if (_restrict && _restrict[this._yuid] && !Y.DOM.contains(node, val)) {
566
val = null; // not allowed to go outside of root node
477
// method wrapper uses undefined in chaining test
478
if (val === undefined) {
570
} else if (RE_VALID_PROP_TYPES.test(typeof node[prop])) { // safe to read
482
val = Node._deepGet(prop.split('.'), node);
576
invoke: function(method, a, b, c, d, e) {
577
if (a) { // first 2 may be Node instances or strings
578
a = (a[NODE_TYPE]) ? a : getDOMNode(a);
488
invoke: function(node, method, a, b, c, d, e) {
491
if (a) { // first 2 may be Node instances
492
a = (a[NODE_TYPE]) ? a : _getDOMNode(a);
580
b = (b[NODE_TYPE]) ? b : getDOMNode(b);
494
b = (b[NODE_TYPE]) ? b : _getDOMNode(b);
583
var node = _nodes[this._yuid];
584
if (node && METHODS_INVOKE[method] && node[method]) {
585
return node[method](a, b, c, d, e);
590
hasMethod: function(method) {
591
return !!(METHODS_INVOKE[method] && _nodes[this._yuid][method]);
594
//normalize: function() {},
595
//isSupported: function(feature, version) {},
596
toString: function() {
597
var node = _nodes[this._yuid] || {};
598
return node.id || node[NODE_NAME] || 'undefined node';
498
ret = node[method](a, b, c, d, e);
502
hasMethod: function(node, method) {
503
return !! node[method];
602
* Retrieves a single node based on the given CSS selector.
507
* Retrieves a Node instance of nodes based on the given CSS selector.
605
510
* @param {string} selector The CSS selector to test against.
606
511
* @return {Node} A Node instance for the matching HTMLElement.
608
query: function(selector) {
609
return wrapDOM(Selector.query(selector, _nodes[this._yuid], true));
513
query: function(node, selector) {
514
var ret = Selector.query(selector, node, true);
613
523
* Retrieves a nodeList based on the given CSS selector.
614
524
* @method queryAll
525
* @deprecated Use query() which returns all matches
616
527
* @param {string} selector The CSS selector to test against.
617
528
* @return {NodeList} A NodeList instance for the matching HTMLCollection/Array.
619
queryAll: function(selector) {
620
return wrapDOM(Selector.query(selector, _nodes[this._yuid]));
530
queryAll: function(node, selector) {
531
var ret = Selector.query(selector, node);
676
592
* @param {Boolean} all optional Whether all node types should be returned, or just element nodes.
677
593
* @return {Node} Node instance or null if not found
679
next: function(fn, all) {
680
return wrapDOM(Y.DOM.elementByAxis(_nodes[this._yuid], 'nextSibling', wrapFn(fn)), all);
684
* Attaches a DOM event handler.
686
* @param {String} type The type of DOM Event to listen for
687
* @param {Function} fn The handler to call when the event fires
688
* @param {Object} arg An argument object to pass to the handler
691
attach: function(type, fn, arg) {
692
var args = slice.call(arguments, 0);
693
args.unshift(_nodes[this._yuid]);
694
return Y.Event.addListener.apply(Y.Event, args);
700
* @param {String} type The type of DOM Event to listen for
701
* @param {Function} fn The handler to call when the event fires
702
* @param {Object} arg An argument object to pass to the handler
706
on: function(type, fn, arg) {
707
return this.attach.apply(this, arguments);
710
addEventListener: function(type, fn, arg) {
711
return Y.Event.nativeAdd(_nodes[this._yuid], type, fn, arg);
715
* Detaches a DOM event handler.
717
* @param {String} type The type of DOM Event
718
* @param {Function} fn The handler to call when the event fires
720
detach: function(type, fn) {
721
var args = slice.call(arguments, 0);
722
args.unshift(_nodes[this._yuid]);
723
return Y.Event.removeListener.apply(Y.Event, args);
726
removeEventListener: function(type, fn) {
727
return Y.Event.nativeRemove(_nodes[this._yuid], type, fn);
731
* Creates a Node instance from HTML string
733
* @param {String|Array} html The string of html to create
734
* @return {Node} A new Node instance
736
create: function(html) {
737
return Y.Node.create(html);
595
next: function(node, fn, all) {
596
return Y.DOM.elementByAxis(node, 'nextSibling', _wrapFn(fn), all);
741
600
* Determines whether the ndoe is an ancestor of another HTML element in the DOM hierarchy.
742
601
* @method contains
743
602
* @param {Node | HTMLElement} needle The possible node or descendent
744
603
* @return {Boolean} Whether or not this node is the needle its ancestor
746
contains: function(needle) {
747
return Y.DOM.contains(_nodes[this._yuid], getDOMNode(needle));
751
* Applies the supplied plugin to the node.
753
* @param {Function} The plugin Class to apply
754
* @param {Object} config An optional config to pass to the constructor
757
plug: function(PluginClass, config) {
758
config = config || {};
760
if (PluginClass && PluginClass.NS) {
761
this[PluginClass.NS] = new PluginClass(config);
605
contains: function(node, needle) {
606
return Y.DOM.contains(node, _getDOMNode(needle));
791
636
* @param {String} html HTML string
793
638
Node.create = function(html) {
794
return wrapDOM(Y.DOM.create(html));
639
return Node.get(Y.DOM.create(html));
797
642
Node.getById = function(id, doc) {
798
643
doc = (doc && doc[NODE_TYPE]) ? doc : Y.config.doc;
799
return wrapDOM(doc.getElementById(id));
644
return Node.get(doc.getElementById(id));
803
* Retrieves a Node instance for the given object/string.
648
* Retrieves a Node instance for the given query or nodes.
804
649
* Note: Use 'document' string to retrieve document Node instance from string
807
652
* @param {document|HTMLElement|HTMLCollection|Array|String} node The object to wrap.
808
653
* @param {document|Node} doc optional The document containing the node. Defaults to current document.
809
654
* @param {boolean} isRoot optional Whether or not this node should be treated as a root node. Root nodes
810
655
* aren't allowed to traverse outside their DOM tree.
811
* @return {Node} A wrapper instance for the supplied object.
656
* @return {Node} A Node instance bound to the supplied node(s).
813
Node.get = function(node, doc, isRoot) {
814
if (node instanceof Node) {
820
} else if (doc._yuid && _nodes[doc._yuid]) {
821
doc = _nodes[doc._yuid];
824
if (node && typeof node === 'string') {
825
if (node === 'document') {
828
node = Y.Selector.query(node, doc, true);
832
node = wrapDOM(node);
835
_restrict = _restrict || {};
836
_restrict[node._yuid] = node;
658
Node.get = function(node, doc, isRoot, getAll) {
662
if (typeof node === 'string') {
663
if (node === 'document') { // TODO: allow 'doc'? 'window'?
664
node = [Y.config.doc];
666
node = Selector.query(node, doc, !getAll); // Selector arg is getFirst
671
if (!getAll) { // reuse single element node instances
673
// verify IE's uniqueID in case the node was cloned
674
if (!node.uniqueID || (node.uniqueID === node._yuid)) {
675
instance = _instances[node._yuid];
681
instance = new Node(node, doc, isRoot, getAll);
684
if (instance && isRoot && !getAll) {
685
_restrict[instance._yuid] = true;
690
// zero length collection returns null
691
return (instance && instance.size()) ? instance : null;
843
695
* Retrieves a NodeList instance for the given object/string.
846
698
* @param {HTMLCollection|Array|String} node The object to wrap.
847
699
* @param {document|Node} doc optional The document containing the node. Defaults to current document.
700
* @param {boolean} isRoot optional Whether or not this node should be treated as a root node. Root nodes
848
701
* @return {NodeList} A NodeList instance for the supplied nodes.
850
Node.all = function(nodes, doc) {
851
if (nodes instanceof NodeList) {
857
} else if (doc._yuid && _nodes[doc._yuid]) {
858
doc = _nodes[doc._yuid];
861
if (nodes && typeof nodes == 'string') {
862
nodes = Selector.query(nodes, doc);
865
return wrapDOM(nodes);
870
* A wrapper for manipulating multiple DOM elements
875
var NodeList = function(nodes) {
876
// TODO: input validation
877
_nodelists[Y.stamp(this)] = nodes;
703
Node.all = function(node, doc, isRoot) {
704
return Node.get.call(Node, node, doc, isRoot, true);
709
* Passes through to DOM method.
710
* @method replaceChild
711
* @param {HTMLElement | Node} node Node to be inserted
712
* @param {HTMLElement | Node} refNode Node to be replaced
713
* @return {Node} The replaced node
718
* Passes through to DOM method.
719
* @method appendChild
720
* @param {HTMLElement | Node} node Node to be appended
721
* @return {Node} The appended node
726
* Passes through to DOM method.
727
* @method insertBefore
728
* @param {HTMLElement | Node} newNode Node to be appended
729
* @param {HTMLElement | Node} refNode Node to be inserted before
730
* @return {Node} The inserted node
735
* Passes through to DOM method.
736
* @method removeChild
737
* @param {HTMLElement | Node} node Node to be removed
738
* @return {Node} The removed node
743
* Passes through to DOM method.
744
* @method hasChildNodes
745
* @return {Boolean} Whether or not the node has any childNodes
750
* Passes through to DOM method.
752
* @param {HTMLElement | Node} node Node to be cloned
753
* @return {Node} The clone
758
* Passes through to DOM method.
759
* @method getAttribute
760
* @param {String} attribute The attribute to retrieve
761
* @return {String} The current value of the attribute
766
* Passes through to DOM method.
767
* @method setAttribute
768
* @param {String} attribute The attribute to set
769
* @param {String} The value to apply to the attribute
775
* Passes through to DOM method.
776
* @method hasAttribute
777
* @param {String} attribute The attribute to test for
778
* @return {Boolean} Whether or not the attribute is present
783
* Passes through to DOM method.
784
* @method removeAttribute
785
* @param {String} attribute The attribute to be removed
791
* Passes through to DOM method.
792
* @method scrollIntoView
798
* Passes through to DOM method.
799
* @method getElementsByTagName
800
* @param {String} tagName The tagName to collect
801
* @return {NodeList} A NodeList representing the HTMLCollection
803
'getElementsByTagName',
806
* Passes through to DOM method.
813
* Passes through to DOM method.
820
* Passes through to DOM method.
821
* Only valid on FORM elements
828
* Passes through to DOM method.
829
* Only valid on FORM elements
836
* Passes through to DOM method.
841
], function(method) {
842
Node.prototype[method] = function(arg1, arg2, arg3) {
843
var ret = this.invoke(method, arg1, arg2, arg3);
848
if (!document.documentElement.hasAttribute) {
850
'hasAttribute': function(node, att) {
851
return !! node.getAttribute(att);
880
856
// used to call Node methods against NodeList nodes
881
var _tmpNode = Node.create('<div></div>');
882
NodeList.prototype = {};
884
Y.each(Node.prototype, function(fn, name) {
885
if (typeof Node.prototype[name] == 'function') {
886
addNodeListMethod(name);
890
Y.mix(NodeList.prototype, {
892
* Retrieves the Node instance at the given index.
895
* @param {Number} index The index of the target Node.
896
* @return {Node} The Node instance at the given index.
898
item: function(index) {
899
var node = _nodelists[this._yuid][index];
900
return (node && node[TAG_NAME]) ? wrapDOM(node) : (node && node.get) ? node : null;
904
* Set the value of the property/attribute on all HTMLElements bound to this NodeList.
905
* Only strings/numbers/booleans are passed through unless a SETTER exists.
907
* @param {String} prop Property to set
908
* @param {any} val Value to apply to the given property
912
set: function(name, val) {
913
var nodes = _nodelists[this._yuid];
914
for (var i = 0, len = nodes.length; i < len; ++i) {
915
_nodes[_tmpNode._yuid] = nodes[i];
916
_tmpNode.set(name, val);
923
* Get the value of the property/attribute for each of the HTMLElements bound to this NodeList.
924
* Only strings/numbers/booleans are passed through unless a GETTER exists.
926
* @param {String} prop Property to get
927
* @return {Array} Array containing the current values mapped to the Node indexes
930
get: function(name) {
931
if (name == 'length') { // TODO: remove
932
return _nodelists[this._yuid].length;
934
var nodes = _nodelists[this._yuid];
936
for (var i = 0, len = nodes.length; i < len; ++i) {
937
_nodes[_tmpNode._yuid] = nodes[i];
938
ret[i] = _tmpNode.get(name);
945
* Filters the NodeList instance down to only nodes matching the given selector.
947
* @param {String} selector The selector to filter against
948
* @return {NodeList} NodeList containing the updated collection
951
filter: function(selector) {
952
return wrapDOM(Selector.filter(_nodelists[this._yuid], selector));
956
* Applies the given function to each Node in the NodeList.
958
* @param {Function} fn The function to apply
959
* @param {Object} context optional An optional context to apply the function with
960
* Default context is the NodeList instance
961
* @return {NodeList} NodeList containing the updated collection
964
each: function(fn, context) {
965
context = context || this;
966
var nodes = _nodelists[this._yuid];
967
for (var i = 0, len = nodes.length; i < len; ++i) {
968
fn.call(context, Y.Node.get(nodes[i]), i, this);
974
* Returns the current number of items in the NodeList.
976
* @return {Int} The number of items in the NodeList.
979
return _nodelists[this._yuid].length;
982
toString: function() {
983
var nodes = _nodelists[this._yuid] || [];
984
return 'NodeList (' + nodes.length + ' items)';
990
Y.NodeList = NodeList;
991
858
Y.all = Y.Node.all;
992
859
Y.get = Y.Node.get;
994
861
* Extended Node interface for managing classNames.