3
Copyright 2012 Yahoo! Inc. All rights reserved.
4
Licensed under the BSD License.
5
http://yuilibrary.com/license/
7
YUI.add('node-core', function(Y) {
10
* The Node Utility provides a DOM-like interface for interacting with DOM nodes.
13
* @submodule node-core
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.one()` to retrieve Node instances.
21
* <strong>NOTE:</strong> Node properties are accessed using
22
* the <code>set</code> and <code>get</code> methods.
26
* @param {DOMNode} node the DOM node to be mapped to the Node instance.
32
NODE_NAME = 'nodeName',
33
NODE_TYPE = 'nodeType',
34
OWNER_DOCUMENT = 'ownerDocument',
39
_slice = Array.prototype.slice,
43
Y_Node = function(node) {
44
if (!this.getDOMNode) { // support optional "new"
45
return new Y_Node(node);
48
if (typeof node == 'string') {
49
node = Y_Node._fromString(node);
51
return null; // NOTE: return
55
var uid = (node.nodeType !== 9) ? node.uniqueID : node[UID];
57
if (uid && Y_Node._instances[uid] && Y_Node._instances[uid]._node !== node) {
58
node[UID] = null; // unset existing uid to prevent collision (via clone or hack)
61
uid = uid || Y.stamp(node);
62
if (!uid) { // stamp failed; likely IE non-HTMLElement
69
* The underlying DOM node bound to the Y.Node instance
75
this._stateProxy = node; // when augmented with Attribute
77
if (this._initPlugins) { // when augmented with Plugin.Host
82
// used with previous/next/ancestor tests
83
_wrapFn = function(fn) {
86
ret = (typeof fn == 'string') ?
88
return Y.Selector.test(n, fn);
100
Y_Node.DOM_EVENTS = {};
102
Y_Node._fromString = function(node) {
104
if (node.indexOf('doc') === 0) { // doc OR document
106
} else if (node.indexOf('win') === 0) { // win OR window
109
node = Y.Selector.query(node, null, true);
117
* The name of the component
121
Y_Node.NAME = 'node';
124
* The pattern used to identify ARIA attributes
126
Y_Node.re_aria = /^(?:role$|aria-)/;
128
Y_Node.SHOW_TRANSITION = 'fadeIn';
129
Y_Node.HIDE_TRANSITION = 'fadeOut';
132
* A list of Node instances that have been created
134
* @property _instances
138
Y_Node._instances = {};
141
* Retrieves the DOM node bound to a Node instance
145
* @param {Node | HTMLNode} node The Node instance or an HTMLNode
146
* @return {HTMLNode} The DOM node bound to the Node instance. If a DOM node is passed
147
* as the node argument, it is simply returned.
149
Y_Node.getDOMNode = function(node) {
151
return (node.nodeType) ? node : node._node || null;
157
* Checks Node return values and wraps DOM Nodes as Y.Node instances
158
* and DOM Collections / Arrays as Y.NodeList instances.
159
* Other return values just pass thru. If undefined is returned (e.g. no return)
160
* then the Node instance is returned for chainability.
164
* @param {any} node The Node instance or an HTMLNode
165
* @return {Node | NodeList | Any} Depends on what is returned from the DOM node.
167
Y_Node.scrubVal = function(val, node) {
168
if (val) { // only truthy values are risky
169
if (typeof val == 'object' || typeof val == 'function') { // safari nodeList === function
170
if (NODE_TYPE in val || Y_DOM.isWindow(val)) {// node || window
172
} else if ((val.item && !val._nodes) || // dom collection or Node instance
173
(val[0] && val[0][NODE_TYPE])) { // array of DOM Nodes
177
} else if (typeof val === 'undefined') {
178
val = node; // for chaining
179
} else if (val === null) {
180
val = null; // IE: DOM null not the same as null
187
* Adds methods to the Y.Node prototype, routing through scrubVal.
191
* @param {String} name The name of the method to add
192
* @param {Function} fn The function that becomes the method
193
* @param {Object} context An optional context to call the method with
194
* (defaults to the Node instance)
195
* @return {any} Depends on what is returned from the DOM node.
197
Y_Node.addMethod = function(name, fn, context) {
198
if (name && fn && typeof fn == 'function') {
199
Y_Node.prototype[name] = function() {
200
var args = _slice.call(arguments),
204
if (args[0] && args[0]._node) {
205
args[0] = args[0]._node;
208
if (args[1] && args[1]._node) {
209
args[1] = args[1]._node;
211
args.unshift(node._node);
213
ret = fn.apply(node, args);
215
if (ret) { // scrub truthy
216
ret = Y_Node.scrubVal(ret, node);
219
(typeof ret != 'undefined') || (ret = node);
227
* Imports utility methods to be added as Y.Node methods.
228
* @method importMethod
231
* @param {Object} host The object that contains the method to import.
232
* @param {String} name The name of the method to import
233
* @param {String} altName An optional name to use in place of the host name
234
* @param {Object} context An optional context to call the method with
236
Y_Node.importMethod = function(host, name, altName) {
237
if (typeof name == 'string') {
238
altName = altName || name;
239
Y_Node.addMethod(altName, host[name], host);
241
Y.Array.each(name, function(n) {
242
Y_Node.importMethod(host, n);
248
* Retrieves a NodeList based on the given CSS selector.
251
* @param {string} selector The CSS selector to test against.
252
* @return {NodeList} A NodeList instance for the matching HTMLCollection/Array.
257
* Returns a single Node instance bound to the node or the
258
* first element matching the given selector. Returns null if no match found.
259
* <strong>Note:</strong> For chaining purposes you may want to
260
* use <code>Y.all</code>, which returns a NodeList when no match is found.
262
* @param {String | HTMLElement} node a node or Selector
263
* @return {Node | null} a Node instance or null if no match found.
268
* Returns a single Node instance bound to the node or the
269
* first element matching the given selector. Returns null if no match found.
270
* <strong>Note:</strong> For chaining purposes you may want to
271
* use <code>Y.all</code>, which returns a NodeList when no match is found.
274
* @param {String | HTMLElement} node a node or Selector
275
* @return {Node | null} a Node instance or null if no match found.
278
Y_Node.one = function(node) {
284
if (typeof node == 'string') {
285
node = Y_Node._fromString(node);
287
return null; // NOTE: return
289
} else if (node.getDOMNode) {
290
return node; // NOTE: return
293
if (node.nodeType || Y.DOM.isWindow(node)) { // avoid bad input (numbers, boolean, etc)
294
uid = (node.uniqueID && node.nodeType !== 9) ? node.uniqueID : node._yuid;
295
instance = Y_Node._instances[uid]; // reuse exising instances
296
cachedNode = instance ? instance._node : null;
297
if (!instance || (cachedNode && node !== cachedNode)) { // new Node when nodes don't match
298
instance = new Y_Node(node);
299
if (node.nodeType != 11) { // dont cache document fragment
300
Y_Node._instances[instance[UID]] = instance; // cache node
310
* The default setter for DOM properties
311
* Called with instance context (this === the Node instance)
312
* @method DEFAULT_SETTER
314
* @param {String} name The attribute/property being set
315
* @param {any} val The value to be set
316
* @return {any} The value
318
Y_Node.DEFAULT_SETTER = function(name, val) {
319
var node = this._stateProxy,
322
if (name.indexOf(DOT) > -1) {
324
name = name.split(DOT);
325
// only allow when defined on node
326
Y.Object.setValue(node, name, val);
327
} else if (typeof node[name] != 'undefined') { // pass thru DOM properties
335
* The default getter for DOM properties
336
* Called with instance context (this === the Node instance)
337
* @method DEFAULT_GETTER
339
* @param {String} name The attribute/property to look up
340
* @return {any} The current value
342
Y_Node.DEFAULT_GETTER = function(name) {
343
var node = this._stateProxy,
346
if (name.indexOf && name.indexOf(DOT) > -1) {
347
val = Y.Object.getValue(node, name.split(DOT));
348
} else if (typeof node[name] != 'undefined') { // pass thru from DOM
355
Y.mix(Y_Node.prototype, {
356
DATA_PREFIX: 'data-',
359
* The method called when outputting Node instances as strings
361
* @return {String} A string representation of the Node instance
363
toString: function() {
364
var str = this[UID] + ': not bound to a node',
366
attrs, id, className;
369
attrs = node.attributes;
370
id = (attrs && attrs.id) ? node.getAttribute('id') : null;
371
className = (attrs && attrs.className) ? node.getAttribute('className') : null;
372
str = node[NODE_NAME];
379
str += '.' + className.replace(' ', '.');
383
str += ' ' + this[UID];
389
* Returns an attribute value on the Node instance.
390
* Unless pre-configured (via `Node.ATTRS`), get hands
391
* off to the underlying DOM node. Only valid
392
* attributes/properties for the node will be queried.
394
* @param {String} attr The attribute
395
* @return {any} The current value of the attribute
397
get: function(attr) {
400
if (this._getAttr) { // use Attribute imple
401
val = this._getAttr(attr);
403
val = this._get(attr);
407
val = Y_Node.scrubVal(val, this);
408
} else if (val === null) {
409
val = null; // IE: DOM null is not true null (even though they ===)
415
* Helper method for get.
418
* @param {String} attr The attribute
419
* @return {any} The current value of the attribute
421
_get: function(attr) {
422
var attrConfig = Y_Node.ATTRS[attr],
425
if (attrConfig && attrConfig.getter) {
426
val = attrConfig.getter.call(this);
427
} else if (Y_Node.re_aria.test(attr)) {
428
val = this._node.getAttribute(attr, 2);
430
val = Y_Node.DEFAULT_GETTER.apply(this, arguments);
437
* Sets an attribute on the Node instance.
438
* Unless pre-configured (via Node.ATTRS), set hands
439
* off to the underlying DOM node. Only valid
440
* attributes/properties for the node will be set.
441
* To set custom attributes use setAttribute.
443
* @param {String} attr The attribute to be set.
444
* @param {any} val The value to set the attribute to.
447
set: function(attr, val) {
448
var attrConfig = Y_Node.ATTRS[attr];
450
if (this._setAttr) { // use Attribute imple
451
this._setAttr.apply(this, arguments);
452
} else { // use setters inline
453
if (attrConfig && attrConfig.setter) {
454
attrConfig.setter.call(this, val, attr);
455
} else if (Y_Node.re_aria.test(attr)) { // special case Aria
456
this._node.setAttribute(attr, val);
458
Y_Node.DEFAULT_SETTER.apply(this, arguments);
466
* Sets multiple attributes.
468
* @param {Object} attrMap an object of name/value pairs to set
471
setAttrs: function(attrMap) {
472
if (this._setAttrs) { // use Attribute imple
473
this._setAttrs(attrMap);
474
} else { // use setters inline
475
Y.Object.each(attrMap, function(v, n) {
484
* Returns an object containing the values for the requested attributes.
486
* @param {Array} attrs an array of attributes to get values
487
* @return {Object} An object with attribute name/value pairs.
489
getAttrs: function(attrs) {
491
if (this._getAttrs) { // use Attribute imple
492
this._getAttrs(attrs);
493
} else { // use setters inline
494
Y.Array.each(attrs, function(v, n) {
495
ret[v] = this.get(v);
503
* Compares nodes to determine if they match.
504
* Node instances can be compared to each other and/or HTMLElements.
506
* @param {HTMLElement | Node} refNode The reference node to compare to the node.
507
* @return {Boolean} True if the nodes match, false if they do not.
509
compareTo: function(refNode) {
510
var node = this._node;
512
if (refNode && refNode._node) {
513
refNode = refNode._node;
515
return node === refNode;
519
* Determines whether the node is appended to the document.
521
* @param {Node|HTMLElement} doc optional An optional document to check against.
522
* Defaults to current document.
523
* @return {Boolean} Whether or not this node is appended to the document.
525
inDoc: function(doc) {
526
var node = this._node;
527
doc = (doc) ? doc._node || doc : node[OWNER_DOCUMENT];
528
if (doc.documentElement) {
529
return Y_DOM.contains(doc.documentElement, node);
533
getById: function(id) {
534
var node = this._node,
535
ret = Y_DOM.byId(id, node[OWNER_DOCUMENT]);
536
if (ret && Y_DOM.contains(node, ret)) {
545
* Returns the nearest ancestor that passes the test applied by supplied boolean method.
547
* @param {String | Function} fn A selector string or boolean method for testing elements.
548
* If a function is used, it receives the current node being tested as the only argument.
549
* @param {Boolean} testSelf optional Whether or not to include the element in the scan
550
* @param {String | Function} stopFn optional A selector string or boolean
551
* method to indicate when the search should stop. The search bails when the function
552
* returns true or the selector matches.
553
* If a function is used, it receives the current node being tested as the only argument.
554
* @return {Node} The matching Node instance or null if not found
556
ancestor: function(fn, testSelf, stopFn) {
557
// testSelf is optional, check for stopFn as 2nd arg
558
if (arguments.length === 2 &&
559
(typeof testSelf == 'string' || typeof testSelf == 'function')) {
563
return Y.one(Y_DOM.ancestor(this._node, _wrapFn(fn), testSelf, _wrapFn(stopFn)));
567
* Returns the ancestors that pass the test applied by supplied boolean method.
569
* @param {String | Function} fn A selector string or boolean method for testing elements.
570
* @param {Boolean} testSelf optional Whether or not to include the element in the scan
571
* If a function is used, it receives the current node being tested as the only argument.
572
* @return {NodeList} A NodeList instance containing the matching elements
574
ancestors: function(fn, testSelf, stopFn) {
575
if (arguments.length === 2 &&
576
(typeof testSelf == 'string' || typeof testSelf == 'function')) {
579
return Y.all(Y_DOM.ancestors(this._node, _wrapFn(fn), testSelf, _wrapFn(stopFn)));
583
* Returns the previous matching sibling.
584
* Returns the nearest element node sibling if no method provided.
586
* @param {String | Function} fn A selector or boolean method for testing elements.
587
* If a function is used, it receives the current node being tested as the only argument.
588
* @return {Node} Node instance or null if not found
590
previous: function(fn, all) {
591
return Y.one(Y_DOM.elementByAxis(this._node, 'previousSibling', _wrapFn(fn), all));
595
* Returns the next matching sibling.
596
* Returns the nearest element node sibling if no method provided.
598
* @param {String | Function} fn A selector or boolean method for testing elements.
599
* If a function is used, it receives the current node being tested as the only argument.
600
* @return {Node} Node instance or null if not found
602
next: function(fn, all) {
603
return Y.one(Y_DOM.elementByAxis(this._node, 'nextSibling', _wrapFn(fn), all));
607
* Returns all matching siblings.
608
* Returns all siblings if no method provided.
610
* @param {String | Function} fn A selector or boolean method for testing elements.
611
* If a function is used, it receives the current node being tested as the only argument.
612
* @return {NodeList} NodeList instance bound to found siblings
614
siblings: function(fn) {
615
return Y.all(Y_DOM.siblings(this._node, _wrapFn(fn)));
619
* Retrieves a Node instance of nodes based on the given CSS selector.
622
* @param {string} selector The CSS selector to test against.
623
* @return {Node} A Node instance for the matching HTMLElement.
625
one: function(selector) {
626
return Y.one(Y.Selector.query(selector, this._node, true));
630
* Retrieves a NodeList based on the given CSS selector.
633
* @param {string} selector The CSS selector to test against.
634
* @return {NodeList} A NodeList instance for the matching HTMLCollection/Array.
636
all: function(selector) {
637
var nodelist = Y.all(Y.Selector.query(selector, this._node));
638
nodelist._query = selector;
639
nodelist._queryRoot = this._node;
643
// TODO: allow fn test
645
* Test if the supplied node matches the supplied selector.
648
* @param {string} selector The CSS selector to test against.
649
* @return {boolean} Whether or not the node matches the selector.
651
test: function(selector) {
652
return Y.Selector.test(this._node, selector);
656
* Removes the node from its parent.
657
* Shortcut for myNode.get('parentNode').removeChild(myNode);
659
* @param {Boolean} destroy whether or not to call destroy() on the node
664
remove: function(destroy) {
665
var node = this._node;
667
if (node && node.parentNode) {
668
node.parentNode.removeChild(node);
679
* Replace the node with the other node. This is a DOM update only
680
* and does not change the node bound to the Node instance.
681
* Shortcut for myNode.get('parentNode').replaceChild(newNode, myNode);
683
* @param {Node | HTMLNode} newNode Node to be inserted
687
replace: function(newNode) {
688
var node = this._node;
689
if (typeof newNode == 'string') {
690
newNode = Y_Node.create(newNode);
692
node.parentNode.replaceChild(Y_Node.getDOMNode(newNode), node);
697
* @method replaceChild
699
* @param {String | HTMLElement | Node} node Node to be inserted
700
* @param {HTMLElement | Node} refNode Node to be replaced
701
* @return {Node} The replaced node
703
replaceChild: function(node, refNode) {
704
if (typeof node == 'string') {
705
node = Y_DOM.create(node);
708
return Y.one(this._node.replaceChild(Y_Node.getDOMNode(node), Y_Node.getDOMNode(refNode)));
712
* Nulls internal node references, removes any plugins and event listeners
714
* @param {Boolean} recursivePurge (optional) Whether or not to remove listeners from the
715
* node's subtree (default is false)
718
destroy: function(recursive) {
719
var UID = Y.config.doc.uniqueID ? 'uniqueID' : '_yuid',
722
this.purge(); // TODO: only remove events add via this Node
724
if (this.unplug) { // may not be a PluginHost
731
Y.NodeList.each(this.all('*'), function(node) {
732
instance = Y_Node._instances[node[UID]];
740
this._stateProxy = null;
742
delete Y_Node._instances[this._yuid];
746
* Invokes a method on the Node instance
748
* @param {String} method The name of the method to invoke
749
* @param {Any} a, b, c, etc. Arguments to invoke the method with.
750
* @return Whatever the underly method returns.
751
* DOM Nodes and Collections return values
752
* are converted to Node/NodeList instances.
755
invoke: function(method, a, b, c, d, e) {
756
var node = this._node,
767
ret = node[method](a, b, c, d, e);
768
return Y_Node.scrubVal(ret, this);
773
* @description Swap DOM locations with the given node.
774
* This does not change which DOM node each Node instance refers to.
775
* @param {Node} otherNode The node to swap with
778
swap: Y.config.doc.documentElement.swapNode ?
779
function(otherNode) {
780
this._node.swapNode(Y_Node.getDOMNode(otherNode));
782
function(otherNode) {
783
otherNode = Y_Node.getDOMNode(otherNode);
784
var node = this._node,
785
parent = otherNode.parentNode,
786
nextSibling = otherNode.nextSibling;
788
if (nextSibling === node) {
789
parent.insertBefore(node, otherNode);
790
} else if (otherNode === node.nextSibling) {
791
parent.insertBefore(otherNode, node);
793
node.parentNode.replaceChild(otherNode, node);
794
Y_DOM.addHTML(parent, node, nextSibling);
800
hasMethod: function(method) {
801
var node = this._node;
802
return !!(node && method in node &&
803
typeof node[method] != 'unknown' &&
804
(typeof node[method] == 'function' ||
805
String(node[method]).indexOf('function') === 1)); // IE reports as object, prepends space
808
isFragment: function() {
809
return (this.get('nodeType') === 11);
813
* Removes and destroys all of the nodes within the node.
818
this.get('childNodes').remove().destroy(true);
823
* Returns the DOM node bound to the Node instance
827
getDOMNode: function() {
835
* The NodeList module provides support for managing collections of Nodes.
837
* @submodule node-core
841
* The NodeList class provides a wrapper for manipulating DOM NodeLists.
842
* NodeList properties can be accessed via the set/get methods.
843
* Use Y.all() to retrieve NodeList instances.
849
var NodeList = function(nodes) {
853
if (typeof nodes === 'string') { // selector query
855
nodes = Y.Selector.query(nodes);
856
} else if (nodes.nodeType || Y_DOM.isWindow(nodes)) { // domNode || window
858
} else if (nodes._node) { // Y.Node
859
nodes = [nodes._node];
860
} else if (nodes[0] && nodes[0]._node) { // allow array of Y.Nodes
861
Y.Array.each(nodes, function(node) {
863
tmp.push(node._node);
867
} else { // array of domNodes or domNodeList (no mixed array of Y.Node/domNodes)
868
nodes = Y.Array(nodes, 0, true);
873
* The underlying array of DOM nodes bound to the Y.NodeList instance
877
this._nodes = nodes || [];
880
NodeList.NAME = 'NodeList';
883
* Retrieves the DOM nodes bound to a NodeList instance
884
* @method getDOMNodes
887
* @param {NodeList} nodelist The NodeList instance
888
* @return {Array} The array of DOM nodes bound to the NodeList
890
NodeList.getDOMNodes = function(nodelist) {
891
return (nodelist && nodelist._nodes) ? nodelist._nodes : nodelist;
894
NodeList.each = function(instance, fn, context) {
895
var nodes = instance._nodes;
896
if (nodes && nodes.length) {
897
Y.Array.each(nodes, fn, context || instance);
902
NodeList.addMethod = function(name, fn, context) {
904
NodeList.prototype[name] = function() {
908
Y.Array.each(this._nodes, function(node) {
909
var UID = (node.uniqueID && node.nodeType !== 9 ) ? 'uniqueID' : '_yuid',
910
instance = Y.Node._instances[node[UID]],
915
instance = NodeList._getTempNode(node);
917
ctx = context || instance;
918
result = fn.apply(ctx, args);
919
if (result !== undefined && result !== instance) {
920
ret[ret.length] = result;
924
// TODO: remove tmp pointer
925
return ret.length ? ret : this;
931
NodeList.importMethod = function(host, name, altName) {
932
if (typeof name === 'string') {
933
altName = altName || name;
934
NodeList.addMethod(name, host[name]);
936
Y.Array.each(name, function(n) {
937
NodeList.importMethod(host, n);
942
NodeList._getTempNode = function(node) {
943
var tmp = NodeList._tempNode;
945
tmp = Y.Node.create('<div></div>');
946
NodeList._tempNode = tmp;
950
tmp._stateProxy = node;
954
Y.mix(NodeList.prototype, {
955
_invoke: function(method, args, getter) {
956
var ret = (getter) ? [] : this;
958
this.each(function(node) {
959
var val = node[method].apply(node, args);
969
* Retrieves the Node instance at the given index.
972
* @param {Number} index The index of the target Node.
973
* @return {Node} The Node instance at the given index.
975
item: function(index) {
976
return Y.one((this._nodes || [])[index]);
980
* Applies the given function to each Node in the NodeList.
982
* @param {Function} fn The function to apply. It receives 3 arguments:
983
* the current node instance, the node's index, and the NodeList instance
984
* @param {Object} context optional An optional context to apply the function with
985
* Default context is the current Node instance
988
each: function(fn, context) {
990
Y.Array.each(this._nodes, function(node, index) {
992
return fn.call(context || node, node, index, instance);
997
batch: function(fn, context) {
1000
Y.Array.each(this._nodes, function(node, index) {
1001
var instance = Y.Node._instances[node[UID]];
1003
instance = NodeList._getTempNode(node);
1006
return fn.call(context || instance, instance, index, nodelist);
1012
* Executes the function once for each node until a true value is returned.
1014
* @param {Function} fn The function to apply. It receives 3 arguments:
1015
* the current node instance, the node's index, and the NodeList instance
1016
* @param {Object} context optional An optional context to execute the function from.
1017
* Default context is the current Node instance
1018
* @return {Boolean} Whether or not the function returned true for any node.
1020
some: function(fn, context) {
1021
var instance = this;
1022
return Y.Array.some(this._nodes, function(node, index) {
1024
context = context || node;
1025
return fn.call(context, node, index, instance);
1030
* Creates a documenFragment from the nodes bound to the NodeList instance
1032
* @return {Node} a Node instance bound to the documentFragment
1034
toFrag: function() {
1035
return Y.one(Y.DOM._nl2frag(this._nodes));
1039
* Returns the index of the node in the NodeList instance
1040
* or -1 if the node isn't found.
1042
* @param {Node | DOMNode} node the node to search for
1043
* @return {Int} the index of the node value or -1 if not found
1045
indexOf: function(node) {
1046
return Y.Array.indexOf(this._nodes, Y.Node.getDOMNode(node));
1050
* Filters the NodeList instance down to only nodes matching the given selector.
1052
* @param {String} selector The selector to filter against
1053
* @return {NodeList} NodeList containing the updated collection
1056
filter: function(selector) {
1057
return Y.all(Y.Selector.filter(this._nodes, selector));
1062
* Creates a new NodeList containing all nodes at every n indices, where
1063
* remainder n % index equals r.
1064
* (zero-based index).
1066
* @param {Int} n The offset to use (return every nth node)
1067
* @param {Int} r An optional remainder to use with the modulus operation (defaults to zero)
1068
* @return {NodeList} NodeList containing the updated collection
1070
modulus: function(n, r) {
1073
NodeList.each(this, function(node, i) {
1079
return Y.all(nodes);
1083
* Creates a new NodeList containing all nodes at odd indices
1084
* (zero-based index).
1086
* @return {NodeList} NodeList containing the updated collection
1089
return this.modulus(2, 1);
1093
* Creates a new NodeList containing all nodes at even indices
1094
* (zero-based index), including zero.
1096
* @return {NodeList} NodeList containing the updated collection
1099
return this.modulus(2);
1102
destructor: function() {
1106
* Reruns the initial query, when created using a selector query
1110
refresh: function() {
1112
nodes = this._nodes,
1113
query = this._query,
1114
root = this._queryRoot;
1118
if (nodes && nodes[0] && nodes[0].ownerDocument) {
1119
root = nodes[0].ownerDocument;
1123
this._nodes = Y.Selector.query(query, root);
1130
* Returns the current number of items in the NodeList.
1132
* @return {Int} The number of items in the NodeList.
1135
return this._nodes.length;
1139
* Determines if the instance is bound to any nodes
1141
* @return {Boolean} Whether or not the NodeList is bound to any nodes
1143
isEmpty: function() {
1144
return this._nodes.length < 1;
1147
toString: function() {
1149
errorMsg = this[UID] + ': not bound to any nodes',
1150
nodes = this._nodes,
1153
if (nodes && nodes[0]) {
1155
str += node[NODE_NAME];
1157
str += '#' + node.id;
1160
if (node.className) {
1161
str += '.' + node.className.replace(' ', '.');
1164
if (nodes.length > 1) {
1165
str += '...[' + nodes.length + ' items]';
1168
return str || errorMsg;
1172
* Returns the DOM node bound to the Node instance
1173
* @method getDOMNodes
1176
getDOMNodes: function() {
1181
NodeList.importMethod(Y.Node.prototype, [
1183
* Called on each Node instance. Nulls internal node references,
1184
* removes any plugins and event listeners
1186
* @param {Boolean} recursivePurge (optional) Whether or not to
1187
* remove listeners from the node's subtree (default is false)
1193
* Called on each Node instance. Removes and destroys all of the nodes
1202
* Called on each Node instance. Removes the node from its parent.
1203
* Shortcut for myNode.get('parentNode').removeChild(myNode);
1205
* @param {Boolean} destroy whether or not to call destroy() on the node
1213
* Called on each Node instance. Sets an attribute on the Node instance.
1214
* Unless pre-configured (via Node.ATTRS), set hands
1215
* off to the underlying DOM node. Only valid
1216
* attributes/properties for the node will be set.
1217
* To set custom attributes use setAttribute.
1219
* @param {String} attr The attribute to be set.
1220
* @param {any} val The value to set the attribute to.
1227
// one-off implementation to convert array of Nodes to NodeList
1228
// e.g. Y.all('input').get('parentNode');
1230
/** Called on each Node instance
1234
NodeList.prototype.get = function(attr) {
1236
nodes = this._nodes,
1238
getTemp = NodeList._getTempNode,
1243
instance = Y.Node._instances[nodes[0]._yuid] || getTemp(nodes[0]);
1244
val = instance._get(attr);
1245
if (val && val.nodeType) {
1250
Y.Array.each(nodes, function(node) {
1251
instance = Y.Node._instances[node._yuid];
1254
instance = getTemp(node);
1257
val = instance._get(attr);
1258
if (!isNodeList) { // convert array of Nodes to NodeList
1259
val = Y.Node.scrubVal(val, instance);
1265
return (isNodeList) ? Y.all(ret) : ret;
1268
Y.NodeList = NodeList;
1270
Y.all = function(nodes) {
1271
return new NodeList(nodes);
1277
* @submodule node-core
1280
var Y_NodeList = Y.NodeList,
1281
ArrayProto = Array.prototype,
1283
/** Returns a new NodeList combining the given NodeList(s)
1286
* @param {NodeList | Array} valueN Arrays/NodeLists and/or values to
1287
* concatenate to the resulting NodeList
1288
* @return {NodeList} A new NodeList comprised of this NodeList joined with the input.
1291
/** Removes the last from the NodeList and returns it.
1294
* @return {Node} The last item in the NodeList.
1297
/** Adds the given Node(s) to the end of the NodeList.
1300
* @param {Node | DOMNode} nodes One or more nodes to add to the end of the NodeList.
1303
/** Removes the first item from the NodeList and returns it.
1306
* @return {Node} The first item in the NodeList.
1309
/** Returns a new NodeList comprising the Nodes in the given range.
1312
* @param {Number} begin Zero-based index at which to begin extraction.
1313
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.
1314
* @param {Number} end Zero-based index at which to end extraction. slice extracts up to but not including end.
1315
slice(1,4) extracts the second element through the fourth element (elements indexed 1, 2, and 3).
1316
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.
1317
If end is omitted, slice extracts to the end of the sequence.
1318
* @return {NodeList} A new NodeList comprised of this NodeList joined with the input.
1321
/** Changes the content of the NodeList, adding new elements while removing old elements.
1324
* @param {Number} index Index at which to start changing the array. If negative, will begin that many elements from the end.
1325
* @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.
1326
* {Node | DOMNode| element1, ..., elementN
1327
The elements to add to the array. If you don't specify any elements, splice simply removes elements from the array.
1328
* @return {NodeList} The element(s) removed.
1331
/** Adds the given Node(s) to the beginning of the NodeList.
1334
* @param {Node | DOMNode} nodes One or more nodes to add to the NodeList.
1340
Y.Object.each(ArrayMethods, function(returnNodeList, name) {
1341
Y_NodeList.prototype[name] = function() {
1347
while (typeof (arg = arguments[i++]) != 'undefined') { // use DOM nodes/nodeLists
1348
args.push(arg._node || arg._nodes || arg);
1351
ret = ArrayProto[name].apply(this._nodes, args);
1353
if (returnNodeList) {
1356
ret = Y.Node.scrubVal(ret);
1364
* @submodule node-core
1369
* Passes through to DOM method.
1371
* @method removeChild
1372
* @param {HTMLElement | Node} node Node to be removed
1373
* @return {Node} The removed node
1378
* Passes through to DOM method.
1379
* @method hasChildNodes
1380
* @return {Boolean} Whether or not the node has any childNodes
1385
* Passes through to DOM method.
1387
* @param {Boolean} deep Whether or not to perform a deep clone, which includes
1388
* subtree and attributes
1389
* @return {Node} The clone
1394
* Passes through to DOM method.
1395
* @method hasAttribute
1396
* @param {String} attribute The attribute to test for
1397
* @return {Boolean} Whether or not the attribute is present
1402
* Passes through to DOM method.
1403
* @method scrollIntoView
1409
* Passes through to DOM method.
1410
* @method getElementsByTagName
1411
* @param {String} tagName The tagName to collect
1412
* @return {NodeList} A NodeList representing the HTMLCollection
1414
'getElementsByTagName',
1417
* Passes through to DOM method.
1424
* Passes through to DOM method.
1431
* Passes through to DOM method.
1432
* Only valid on FORM elements
1439
* Passes through to DOM method.
1440
* Only valid on FORM elements
1447
* Passes through to DOM method.
1454
* Passes through to DOM method.
1455
* Only valid on TABLE elements
1456
* @method createCaption
1461
], function(method) {
1462
Y.Node.prototype[method] = function(arg1, arg2, arg3) {
1463
var ret = this.invoke(method, arg1, arg2, arg3);
1469
* Passes through to DOM method.
1470
* @method removeAttribute
1471
* @param {String} attribute The attribute to be removed
1474
// one-off implementation due to IE returning boolean, breaking chaining
1475
Y.Node.prototype.removeAttribute = function(attr) {
1476
var node = this._node;
1478
node.removeAttribute(attr, 0); // comma zero for IE < 8 to force case-insensitive
1484
Y.Node.importMethod(Y.DOM, [
1486
* Determines whether the node is an ancestor of another HTML element in the DOM hierarchy.
1488
* @param {Node | HTMLElement} needle The possible node or descendent
1489
* @return {Boolean} Whether or not this node is the needle its ancestor
1493
* Allows setting attributes on DOM nodes, normalizing in some cases.
1494
* This passes through to the DOM node, allowing for custom attributes.
1495
* @method setAttribute
1498
* @param {string} name The attribute name
1499
* @param {string} value The value to set
1503
* Allows getting attributes on DOM nodes, normalizing in some cases.
1504
* This passes through to the DOM node, allowing for custom attributes.
1505
* @method getAttribute
1507
* @param {string} name The attribute name
1508
* @return {string} The attribute value
1513
* Wraps the given HTML around the node.
1515
* @param {String} html The markup to wrap around the node.
1522
* Removes the node's parent node.
1529
* Applies a unique ID to the node if none exists
1530
* @method generateID
1531
* @return {String} The existing or generated ID
1536
Y.NodeList.importMethod(Y.Node.prototype, [
1538
* Allows getting attributes on DOM nodes, normalizing in some cases.
1539
* This passes through to the DOM node, allowing for custom attributes.
1540
* @method getAttribute
1543
* @param {string} name The attribute name
1544
* @return {string} The attribute value
1549
* Allows setting attributes on DOM nodes, normalizing in some cases.
1550
* This passes through to the DOM node, allowing for custom attributes.
1551
* @method setAttribute
1555
* @param {string} name The attribute name
1556
* @param {string} value The value to set
1561
* Allows for removing attributes on DOM nodes.
1562
* This passes through to the DOM node, allowing for custom attributes.
1563
* @method removeAttribute
1566
* @param {string} name The attribute to remove
1570
* Removes the parent node from node in the list.
1576
* Wraps the given HTML around each node.
1578
* @param {String} html The markup to wrap around the node.
1584
* Applies a unique ID to each node if none exists
1585
* @method generateID
1586
* @return {String} The existing or generated ID
1592
}, '3.5.1' ,{requires:['dom-core', 'selector']});