2 Copyright (c) 2009, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.net/yui/license.txt
8 YUI.add('node-base', function(Y) {
11 * The Node Utility provides a DOM-like interface for interacting with DOM nodes.
13 * @submodule node-base
17 * The Node class provides a wrapper for manipulating DOM Nodes.
18 * Node properties can be accessed via the set/get methods.
19 * Use Y.get() to retrieve Node instances.
21 * <strong>NOTE:</strong> Node properties are accessed using
22 * the <code>set</code> and <code>get</code> methods.
31 NODE_NAME = 'nodeName',
32 NODE_TYPE = 'nodeType',
33 OWNER_DOCUMENT = 'ownerDocument',
37 Node = function(node) {
40 if (uid && Node._instances[uid] && Node._instances[uid]._node !== node) {
41 node[UID] = null; // unset existing uid to prevent collision (via clone or hack)
45 if (!uid) { // stamp failed; likely IE non-HTMLElement
52 Node._instances[uid] = this;
54 this._stateProxy = node; // when augmented with Attribute
56 if (this._initPlugins) { // when augmented with Plugin.Host
61 // used with previous/next/ancestor tests
62 _wrapFn = function(fn) {
65 ret = (typeof fn === 'string') ?
67 return Y.Selector.test(n, fn);
70 return fn(Node.get(n));
80 Node.re_aria = /^(?:role$|aria-)/;
111 mousemultiwheel: true,
124 // Add custom event adaptors to this list. This will make it so
125 // that delegate, key, available, contentready, etc all will
126 // be available through Node.on
127 Y.mix(Node.DOM_EVENTS, Y.Env.evt.plugins);
129 Node._instances = {};
132 * Retrieves the DOM node bound to a Node instance
133 * @method Node.getDOMNode
136 * @param {Y.Node || HTMLNode} node The Node instance or an HTMLNode
137 * @return {HTMLNode} The DOM node bound to the Node instance. If a DOM node is passed
138 * as the node argument, it is simply returned.
140 Node.getDOMNode = function(node) {
142 return (node.nodeType) ? node : node._node || null;
147 Node.scrubVal = function(val, node) {
148 if (node && val) { // only truthy values are risky
149 if (typeof val === 'object' || typeof val === 'function') { // safari nodeList === function
150 if (NODE_TYPE in val || Y.DOM.isWindow(val)) {// node || window
152 } else if ((val.item && !val._nodes) || // dom collection or Node instance
153 (val[0] && val[0][NODE_TYPE])) { // array of DOM Nodes
157 } else if (val === undefined) {
158 val = node; // for chaining
164 Node.addMethod = function(name, fn, context) {
165 if (name && fn && typeof fn === 'function') {
166 Node.prototype[name] = function() {
167 context = context || this;
168 var args = Y.Array(arguments),
171 if (args[0] && args[0] instanceof Node) {
172 args[0] = args[0]._node;
175 if (args[1] && args[1] instanceof Node) {
176 args[1] = args[1]._node;
178 args.unshift(this._node);
179 ret = Node.scrubVal(fn.apply(context, args), this);
186 Node.importMethod = function(host, name, altName) {
187 if (typeof name === 'string') {
188 altName = altName || name;
189 Node.addMethod(altName, host[name], host);
191 Y.each(name, function(n) {
192 Node.importMethod(host, n);
198 * Returns a single Node instance bound to the node or the
199 * first element matching the given selector.
202 * @param {String | HTMLElement} node a node or Selector
203 * @param {Y.Node || HTMLElement} doc an optional document to scan. Defaults to Y.config.doc.
205 Node.one = function(node) {
211 if (typeof node === 'string') {
212 if (node.indexOf('doc') === 0) { // doc OR document
214 } else if (node.indexOf('win') === 0) { // win OR window
217 node = Y.Selector.query(node, null, true);
222 } else if (node instanceof Node) {
223 return node; // NOTE: return
227 instance = Node._instances[uid]; // reuse exising instances
228 cachedNode = instance ? instance._node : null;
229 if (!instance || (cachedNode && node !== cachedNode)) { // new Node when nodes don't match
230 instance = new Node(node);
237 * Returns a single Node instance bound to the node or the
238 * first element matching the given selector.
240 * @deprecated Use Y.one
242 * @param {String | HTMLElement} node a node or Selector
243 * @param {Y.Node || HTMLElement} doc an optional document to scan. Defaults to Y.config.doc.
245 Node.get = function() {
246 return Node.one.apply(Node, arguments);
250 * Creates a new dom node using the provided markup string.
253 * @param {String} html The markup used to create the element
254 * @param {HTMLDocument} doc An optional document context
255 * @return {Node} A Node instance bound to a DOM node or fragment
257 Node.create = function() {
258 return Node.get(Y.DOM.create.apply(Y.DOM, arguments));
263 * Allows for getting and setting the text of an element.
264 * Formatting is preserved and special characters are treated literally.
270 return Y.DOM.getText(this._node);
273 setter: function(content) {
274 Y.DOM.setText(this._node, content);
281 return this._node.getElementsByTagName('option');
285 // IE: elements collection is also FORM node which trips up scrubVal.
286 // preconverting to NodeList
287 // TODO: break out for IE only
290 return Y.all(this._node.elements);
295 * Returns a NodeList instance of all HTMLElement children.
302 var node = this._node,
303 children = node.children,
307 childNodes = node.childNodes;
310 for (i = 0, len = childNodes.length; i < len; ++i) {
311 if (childNodes[i][TAG_NAME]) {
312 children[children.length] = childNodes[i];
316 return Y.all(children);
322 return Y.DOM.getValue(this._node);
325 setter: function(val) {
326 Y.DOM.setValue(this._node, val);
336 setter: function(val) {
343 // call with instance context
344 Node.DEFAULT_SETTER = function(name, val) {
345 var node = this._stateProxy,
348 if (name.indexOf(DOT) > -1) {
350 name = name.split(DOT);
351 // only allow when defined on node
352 Y.Object.setValue(node, name, val);
353 } else if (node[name] !== undefined) { // pass thru DOM properties
360 // call with instance context
361 Node.DEFAULT_GETTER = function(name) {
362 var node = this._stateProxy,
365 if (name.indexOf && name.indexOf(DOT) > -1) {
366 val = Y.Object.getValue(node, name.split(DOT));
367 } else if (node[name] !== undefined) { // pass thru from DOM
374 Y.augment(Node, Y.Event.Target);
376 Y.mix(Node.prototype, {
377 toString: function() {
379 errorMsg = this[UID] + ': not bound to a node',
383 str += node[NODE_NAME];
385 str += '#' + node.id;
388 if (node.className) {
389 str += '.' + node.className.replace(' ', '.');
393 str += ' ' + this[UID];
395 return str || errorMsg;
399 * Returns an attribute value on the Node instance
401 * @param {String} attr The attribute to be set
402 * @return {any} The current value of the attribute
404 get: function(attr) {
407 if (this._getAttr) { // use Attribute imple
408 val = this._getAttr(attr);
410 val = this._get(attr);
414 val = Y.Node.scrubVal(val, this);
419 _get: function(attr) {
420 var attrConfig = Node.ATTRS[attr],
423 if (attrConfig && attrConfig.getter) {
424 val = attrConfig.getter.call(this);
425 } else if (Node.re_aria.test(attr)) {
426 val = this._node.getAttribute(attr, 2);
428 val = Node.DEFAULT_GETTER.apply(this, arguments);
435 * Sets an attribute on the Node instance.
437 * @param {String} attr The attribute to be set.
438 * @param {any} val The value to set the attribute to.
441 set: function(attr, val) {
442 var attrConfig = Node.ATTRS[attr];
444 if (this._setAttr) { // use Attribute imple
445 this._setAttr.apply(this, arguments);
446 } else { // use setters inline
447 if (attrConfig && attrConfig.setter) {
448 attrConfig.setter.call(this, val);
449 } else if (Node.re_aria.test(attr)) { // special case Aria
450 this._node.setAttribute(attr, val);
452 Node.DEFAULT_SETTER.apply(this, arguments);
460 * Sets multiple attributes.
462 * @param {Object} attrMap an object of name/value pairs to set
465 setAttrs: function(attrMap) {
466 if (this._setAttrs) { // use Attribute imple
467 this._setAttrs(attrMap);
468 } else { // use setters inline
469 Y.Object.each(attrMap, function(v, n) {
478 * Returns an object containing the values for the requested attributes.
480 * @param {Array} attrs an array of attributes to get values
481 * @return {Object} An object with attribute name/value pairs.
483 getAttrs: function(attrs) {
485 if (this._getAttrs) { // use Attribute imple
486 this._getAttrs(attrs);
487 } else { // use setters inline
488 Y.Array.each(attrs, function(v, n) {
489 ret[v] = this.get(v);
497 * Creates a new Node using the provided markup string.
499 * @param {String} html The markup used to create the element
500 * @param {HTMLDocument} doc An optional document context
501 * @return {Node} A Node instance bound to a DOM node or fragment
506 * Compares nodes to determine if they match.
507 * Node instances can be compared to each other and/or HTMLElements.
509 * @param {HTMLElement | Node} refNode The reference node to compare to the node.
510 * @return {Boolean} True if the nodes match, false if they do not.
512 compareTo: function(refNode) {
513 var node = this._node;
514 if (refNode instanceof Y.Node) {
515 refNode = refNode._node;
517 return node === refNode;
521 * Determines whether the node is appended to the document.
523 * @param {Node|HTMLElement} doc optional An optional document to check against.
524 * Defaults to current document.
525 * @return {Boolean} Whether or not this node is appended to the document.
527 inDoc: function(doc) {
528 var node = this._node;
529 doc = (doc) ? doc._node || doc : node[OWNER_DOCUMENT];
530 if (doc.documentElement) {
531 return Y.DOM.contains(doc.documentElement, node);
535 getById: function(id) {
536 var node = this._node,
537 ret = Y.DOM.byId(id, node[OWNER_DOCUMENT]);
538 if (ret && Y.DOM.contains(node, ret)) {
547 * Returns the nearest ancestor that passes the test applied by supplied boolean method.
549 * @param {String | Function} fn A selector string or boolean method for testing elements.
550 * If a function is used, it receives the current node being tested as the only argument.
551 * @return {Node} The matching Node instance or null if not found
553 ancestor: function(fn) {
554 return Node.get(Y.DOM.elementByAxis(this._node, 'parentNode', _wrapFn(fn)));
558 * Returns the previous matching sibling.
559 * Returns the nearest element node sibling if no method provided.
561 * @param {String | Function} fn A selector or boolean method for testing elements.
562 * If a function is used, it receives the current node being tested as the only argument.
563 * @return {Node} Node instance or null if not found
565 previous: function(fn, all) {
566 return Node.get(Y.DOM.elementByAxis(this._node, 'previousSibling', _wrapFn(fn), all));
570 * Returns the next matching sibling.
571 * Returns the nearest element node sibling if no method provided.
573 * @param {String | Function} fn A selector or boolean method for testing elements.
574 * If a function is used, it receives the current node being tested as the only argument.
575 * @return {Node} Node instance or null if not found
577 next: function(node, fn, all) {
578 return Node.get(Y.DOM.elementByAxis(this._node, 'nextSibling', _wrapFn(fn), all));
582 * Retrieves a Node instance of nodes based on the given CSS selector.
585 * @param {string} selector The CSS selector to test against.
586 * @return {Node} A Node instance for the matching HTMLElement.
588 one: function(selector) {
589 return Y.one(Y.Selector.query(selector, this._node, true));
593 * Retrieves a Node instance of nodes based on the given CSS selector.
595 * @deprecated Use one()
596 * @param {string} selector The CSS selector to test against.
597 * @return {Node} A Node instance for the matching HTMLElement.
599 query: function(selector) {
600 return this.one(selector);
604 * Retrieves a nodeList based on the given CSS selector.
607 * @param {string} selector The CSS selector to test against.
608 * @return {NodeList} A NodeList instance for the matching HTMLCollection/Array.
610 all: function(selector) {
611 var nodelist = Y.all(Y.Selector.query(selector, this._node));
612 nodelist._query = selector;
617 * Retrieves a nodeList based on the given CSS selector.
619 * @deprecated Use all()
620 * @param {string} selector The CSS selector to test against.
621 * @return {NodeList} A NodeList instance for the matching HTMLCollection/Array.
623 queryAll: function(selector) {
624 return this.all(selector);
627 // TODO: allow fn test
629 * Test if the supplied node matches the supplied selector.
632 * @param {string} selector The CSS selector to test against.
633 * @return {boolean} Whether or not the node matches the selector.
635 test: function(selector) {
636 return Y.Selector.test(this._node, selector);
640 * Removes the node from its parent.
641 * Shortcut for myNode.get('parentNode').removeChild(myNode);
646 remove: function(destroy) {
647 var node = this._node;
648 node.parentNode.removeChild(node);
656 * Replace the node with the other node. This is a DOM update only
657 * and does not change the node bound to the Node instance.
658 * Shortcut for myNode.get('parentNode').replaceChild(newNode, myNode);
663 replace: function(newNode) {
664 var node = this._node;
665 node.parentNode.replaceChild(newNode, node);
669 purge: function(recurse, type) {
670 Y.Event.purgeElement(this._node, recurse, type);
673 destroy: function(purge) {
674 delete Node._instances[this[UID]];
683 this._node._yuid = null;
685 this._stateProxy = null;
689 * Invokes a method on the Node instance
691 * @param {String} method The name of the method to invoke
692 * @param {Any} a, b, c, etc. Arguments to invoke the method with.
693 * @return Whatever the underly method returns.
694 * DOM Nodes and Collections return values
695 * are converted to Node/NodeList instances.
698 invoke: function(method, a, b, c, d, e) {
699 var node = this._node,
702 if (a && a instanceof Y.Node) {
706 if (b && b instanceof Y.Node) {
710 ret = node[method](a, b, c, d, e);
711 return Y.Node.scrubVal(ret, this);
715 * Applies the given function to each Node in the NodeList.
717 * @deprecated Use NodeList
718 * @param {Function} fn The function to apply
719 * @param {Object} context optional An optional context to apply the function with
720 * Default context is the NodeList instance
723 each: function(fn, context) {
724 context = context || this;
725 return fn.call(context, this);
729 * Retrieves the Node instance at the given index.
731 * @deprecated Use NodeList
733 * @param {Number} index The index of the target Node.
734 * @return {Node} The Node instance at the given index.
736 item: function(index) {
741 * Returns the current number of items in the Node.
743 * @deprecated Use NodeList
744 * @return {Int} The number of items in the Node.
747 return this._node ? 1 : 0;
751 * Inserts the content before the reference node.
753 * @param {String | Y.Node | HTMLElement} content The content to insert
754 * @param {Int | Y.Node | HTMLElement | String} where The position to insert at.
757 insert: function(content, where) {
758 var node = this._node;
761 if (typeof where === 'number') { // allow index
762 where = this._node.childNodes[where];
765 if (typeof content !== 'string') { // allow Node or NodeList/Array instances
766 if (content._node) { // Node
767 content = content._node;
768 } else if (content._nodes || (!content.nodeType && content.length)) { // NodeList or Array
769 Y.each(content._nodes, function(n) {
770 Y.DOM.addHTML(node, n, where);
773 return this; // NOTE: early return
776 Y.DOM.addHTML(node, content, where);
782 * Inserts the content as the firstChild of the node.
784 * @param {String | Y.Node | HTMLElement} content The content to insert
787 prepend: function(content) {
788 return this.insert(content, 0);
792 * Inserts the content as the lastChild of the node.
794 * @param {String | Y.Node | HTMLElement} content The content to insert
797 append: function(content) {
798 return this.insert(content, null);
802 * Replaces the node's current content with the content.
804 * @param {String | Y.Node | HTMLElement} content The content to insert
807 setContent: function(content) {
808 Y.DOM.addHTML(this._node, content, 'replace');
813 hasMethod: function(method) {
814 var node = this._node;
815 return (node && (typeof node === 'function'));
823 * The NodeList module provides support for managing collections of Nodes.
825 * @submodule nodelist
829 * The NodeList class provides a wrapper for manipulating DOM NodeLists.
830 * NodeList properties can be accessed via the set/get methods.
831 * Use Y.all() to retrieve NodeList instances.
837 var NodeList = function(nodes) {
838 if (typeof nodes === 'string') {
840 nodes = Y.Selector.query(nodes);
842 nodes = Y.Array(nodes, 0, true);
845 NodeList._instances[Y.stamp(this)] = this;
850 NodeList.NAME = 'NodeList';
853 * Retrieves the DOM nodes bound to a NodeList instance
854 * @method NodeList.getDOMNodes
857 * @param {Y.NodeList} node The NodeList instance
858 * @return {Array} The array of DOM nodes bound to the NodeList
860 NodeList.getDOMNodes = function(nodeList) {
861 return nodeList._nodes;
864 NodeList._instances = [];
866 NodeList.each = function(instance, fn, context) {
867 var nodes = instance._nodes;
868 if (nodes && nodes.length) {
869 Y.Array.each(nodes, fn, context || instance);
874 NodeList.addMethod = function(name, fn, context) {
876 NodeList.prototype[name] = function() {
880 Y.Array.each(this._nodes, function(node) {
882 instance = Y.Node._instances[node[UID]],
887 instance = NodeList._getTempNode(node);
889 ctx = context || instance;
890 result = fn.apply(ctx, args);
891 if (result !== undefined && result !== instance) {
892 ret[ret.length] = result;
896 // TODO: remove tmp pointer
897 return ret.length ? ret : this;
903 NodeList.importMethod = function(host, name, altName) {
904 if (typeof name === 'string') {
905 altName = altName || name;
906 NodeList.addMethod(name, host[name]);
908 Y.each(name, function(n) {
909 NodeList.importMethod(host, n);
914 NodeList._getTempNode = function(node) {
915 var tmp = NodeList._tempNode;
917 tmp = Y.Node.create('<div></div>');
918 NodeList._tempNode = tmp;
922 tmp._stateProxy = node;
926 Y.mix(NodeList.prototype, {
928 * Retrieves the Node instance at the given index.
931 * @param {Number} index The index of the target Node.
932 * @return {Node} The Node instance at the given index.
934 item: function(index) {
935 return Y.one((this._nodes || [])[index]);
939 * Applies the given function to each Node in the NodeList.
941 * @param {Function} fn The function to apply. It receives 3 arguments:
942 * the current node instance, the node's index, and the NodeList instance
943 * @param {Object} context optional An optional context to apply the function with
944 * Default context is the current Node instance
947 each: function(fn, context) {
949 Y.Array.each(this._nodes, function(node, index) {
951 return fn.call(context || node, node, index, instance);
956 batch: function(fn, context) {
959 Y.Array.each(this._nodes, function(node, index) {
960 var instance = Y.Node._instances[node[UID]];
962 instance = NodeList._getTempNode(node);
965 return fn.call(context || instance, instance, index, nodelist);
971 * Executes the function once for each node until a true value is returned.
973 * @param {Function} fn The function to apply. It receives 3 arguments:
974 * the current node instance, the node's index, and the NodeList instance
975 * @param {Object} context optional An optional context to execute the function from.
976 * Default context is the current Node instance
977 * @return {Boolean} Whether or not the function returned true for any node.
979 some: function(fn, context) {
981 return Y.Array.some(this._nodes, function(node, index) {
983 context = context || node;
984 return fn.call(context, node, index, instance);
989 * Creates a documenFragment from the nodes bound to the NodeList instance
991 * @return Node a Node instance bound to the documentFragment
994 return Y.one(Y.DOM._nl2frag(this._nodes));
998 * Returns the index of the node in the NodeList instance
999 * or -1 if the node isn't found.
1001 * @param {Y.Node || DOMNode} node the node to search for
1002 * @return {Int} the index of the node value or -1 if not found
1004 indexOf: function(node) {
1005 return Y.Array.indexOf(this._nodes, Y.Node.getDOMNode(node));
1009 * Filters the NodeList instance down to only nodes matching the given selector.
1011 * @param {String} selector The selector to filter against
1012 * @return {NodeList} NodeList containing the updated collection
1015 filter: function(selector) {
1016 return Y.all(Y.Selector.filter(this._nodes, selector));
1021 * Creates a new NodeList containing all nodes at every n indices, where
1022 * remainder n % index equals r.
1023 * (zero-based index).
1025 * @param {Int} n The offset to use (return every nth node)
1026 * @param {Int} r An optional remainder to use with the modulus operation (defaults to zero)
1027 * @return {NodeList} NodeList containing the updated collection
1029 modulus: function(n, r) {
1032 NodeList.each(this, function(node, i) {
1038 return Y.all(nodes);
1042 * Creates a new NodeList containing all nodes at odd indices
1043 * (zero-based index).
1045 * @return {NodeList} NodeList containing the updated collection
1048 return this.modulus(2, 1);
1052 * Creates a new NodeList containing all nodes at even indices
1053 * (zero-based index), including zero.
1055 * @return {NodeList} NodeList containing the updated collection
1058 return this.modulus(2);
1061 destructor: function() {
1062 delete NodeList._instances[this[UID]];
1066 * Reruns the initial query, when created using a selector query
1070 refresh: function() {
1072 nodes = this._nodes;
1074 if (nodes && nodes[0] && nodes[0].ownerDocument) {
1075 doc = nodes[0].ownerDocument;
1078 this._nodes = Y.Selector.query(this._query, doc || Y.config.doc);
1085 * Applies an event listener to each Node bound to the NodeList.
1087 * @param {String} type The event being listened for
1088 * @param {Function} fn The handler to call when the event fires
1089 * @param {Object} context The context to call the handler with.
1090 * Default is the NodeList instance.
1091 * @return {Object} Returns an event handle that can later be use to detach().
1094 on: function(type, fn, context) {
1095 var args = Y.Array(arguments, 0, true);
1096 args.splice(2, 0, this._nodes);
1097 args[3] = context || this;
1098 return Y.on.apply(Y, args);
1102 * Applies an event listener to each Node bound to the NodeList.
1103 * The handler is called only after all on() handlers are called
1104 * and the event is not prevented.
1106 * @param {String} type The event being listened for
1107 * @param {Function} fn The handler to call when the event fires
1108 * @param {Object} context The context to call the handler with.
1109 * Default is the NodeList instance.
1110 * @return {Object} Returns an event handle that can later be use to detach().
1113 after: function(type, fn, context) {
1114 var args = Y.Array(arguments, 0, true);
1115 args.splice(2, 0, this._nodes);
1116 args[3] = context || this;
1117 return Y.after.apply(Y, args);
1121 * Returns the current number of items in the NodeList.
1123 * @return {Int} The number of items in the NodeList.
1126 return this._nodes.length;
1129 toString: function() {
1131 errorMsg = this[UID] + ': not bound to any nodes',
1132 nodes = this._nodes,
1135 if (nodes && nodes[0]) {
1137 str += node[NODE_NAME];
1139 str += '#' + node.id;
1142 if (node.className) {
1143 str += '.' + node.className.replace(' ', '.');
1146 if (nodes.length > 1) {
1147 str += '...[' + nodes.length + ' items]';
1150 return str || errorMsg;
1155 NodeList.importMethod(Y.Node.prototype, [
1157 * Called on each Node instance
1165 * Called on each Node instance
1171 /** Called on each Node instance
1173 * @see Node.detachAll
1177 /** Called on each Node instance
1183 /** Called on each Node instance
1189 /** Called on each Node instance
1195 /** Called on each Node instance
1201 /** Called on each Node instance
1202 * @method setContent
1203 * @see Node.setContent
1208 // one-off implementation to convert array of Nodes to NodeList
1209 // e.g. Y.all('input').get('parentNode');
1211 /** Called on each Node instance
1215 NodeList.prototype.get = function(attr) {
1217 nodes = this._nodes,
1219 getTemp = NodeList._getTempNode,
1224 instance = Y.Node._instances[nodes[0]._yuid] || getTemp(nodes[0]);
1225 val = instance._get(attr);
1226 if (val && val.nodeType) {
1231 Y.Array.each(nodes, function(node) {
1232 instance = Y.Node._instances[node._yuid];
1235 instance = getTemp(node);
1238 val = instance._get(attr);
1239 if (!isNodeList) { // convert array of Nodes to NodeList
1240 val = Y.Node.scrubVal(val, instance);
1246 return (isNodeList) ? Y.all(ret) : ret;
1249 Y.NodeList = NodeList;
1251 Y.all = function(nodes) {
1252 return new NodeList(nodes);
1258 * Passes through to DOM method.
1259 * @method replaceChild
1261 * @param {HTMLElement | Node} node Node to be inserted
1262 * @param {HTMLElement | Node} refNode Node to be replaced
1263 * @return {Node} The replaced node
1268 * Passes through to DOM method.
1269 * @method appendChild
1270 * @param {HTMLElement | Node} node Node to be appended
1271 * @return {Node} The appended node
1276 * Passes through to DOM method.
1277 * @method insertBefore
1278 * @param {HTMLElement | Node} newNode Node to be appended
1279 * @param {HTMLElement | Node} refNode Node to be inserted before
1280 * @return {Node} The inserted node
1285 * Passes through to DOM method.
1286 * @method removeChild
1287 * @param {HTMLElement | Node} node Node to be removed
1288 * @return {Node} The removed node
1293 * Passes through to DOM method.
1294 * @method hasChildNodes
1295 * @return {Boolean} Whether or not the node has any childNodes
1300 * Passes through to DOM method.
1302 * @param {Boolean} deep Whether or not to perform a deep clone, which includes
1303 * subtree and attributes
1304 * @return {Node} The clone
1309 * Passes through to DOM method.
1310 * @method hasAttribute
1311 * @param {String} attribute The attribute to test for
1312 * @return {Boolean} Whether or not the attribute is present
1317 * Passes through to DOM method.
1318 * @method removeAttribute
1319 * @param {String} attribute The attribute to be removed
1325 * Passes through to DOM method.
1326 * @method scrollIntoView
1332 * Passes through to DOM method.
1333 * @method getElementsByTagName
1334 * @param {String} tagName The tagName to collect
1335 * @return {NodeList} A NodeList representing the HTMLCollection
1337 'getElementsByTagName',
1340 * Passes through to DOM method.
1347 * Passes through to DOM method.
1354 * Passes through to DOM method.
1355 * Only valid on FORM elements
1362 * Passes through to DOM method.
1363 * Only valid on FORM elements
1370 * Passes through to DOM method.
1375 ], function(method) {
1376 Y.Node.prototype[method] = function(arg1, arg2, arg3) {
1377 var ret = this.invoke(method, arg1, arg2, arg3);
1382 Node.importMethod(Y.DOM, [
1384 * Determines whether the ndoe is an ancestor of another HTML element in the DOM hierarchy.
1386 * @param {Node | HTMLElement} needle The possible node or descendent
1387 * @return {Boolean} Whether or not this node is the needle its ancestor
1391 * Allows setting attributes on DOM nodes, normalizing in some cases.
1392 * This passes through to the DOM node, allowing for custom attributes.
1393 * @method setAttribute
1397 * @param {string} name The attribute name
1398 * @param {string} value The value to set
1402 * Allows getting attributes on DOM nodes, normalizing in some cases.
1403 * This passes through to the DOM node, allowing for custom attributes.
1404 * @method getAttribute
1407 * @param {string} name The attribute name
1408 * @return {string} The attribute value
1414 * Allows setting attributes on DOM nodes, normalizing in some cases.
1415 * This passes through to the DOM node, allowing for custom attributes.
1416 * @method setAttribute
1420 * @param {string} name The attribute name
1421 * @param {string} value The value to set
1425 * Allows getting attributes on DOM nodes, normalizing in some cases.
1426 * This passes through to the DOM node, allowing for custom attributes.
1427 * @method getAttribute
1430 * @param {string} name The attribute name
1431 * @return {string} The attribute value
1433 Y.NodeList.importMethod(Y.Node.prototype, ['getAttribute', 'setAttribute']);
1437 * Determines whether each node has the given className.
1440 * @param {String} className the class name to search for
1441 * @return {Array} An array of booleans for each node bound to the NodeList.
1446 * Adds a class name to each node.
1448 * @param {String} className the class name to add to the node's class attribute
1454 * Removes a class name from each node.
1455 * @method removeClass
1456 * @param {String} className the class name to remove from the node's class attribute
1462 * Replace a class with another class for each node.
1463 * If no oldClassName is present, the newClassName is simply added.
1464 * @method replaceClass
1465 * @param {String} oldClassName the class name to be replaced
1466 * @param {String} newClassName the class name that will be replacing the old class name
1472 * If the className exists on the node it is removed, if it doesn't exist it is added.
1473 * @method toggleClass
1474 * @param {String} className the class name to be toggled
1480 Y.Node.importMethod(Y.DOM, methods);
1482 * Determines whether each node has the given className.
1484 * @see Node.hasClass
1486 * @param {String} className the class name to search for
1487 * @return {Array} An array of booleans for each node bound to the NodeList.
1491 * Adds a class name to each node.
1493 * @see Node.addClass
1494 * @param {String} className the class name to add to the node's class attribute
1499 * Removes a class name from each node.
1500 * @method removeClass
1501 * @see Node.removeClass
1502 * @param {String} className the class name to remove from the node's class attribute
1507 * Replace a class with another class for each node.
1508 * If no oldClassName is present, the newClassName is simply added.
1509 * @method replaceClass
1510 * @see Node.replaceClass
1511 * @param {String} oldClassName the class name to be replaced
1512 * @param {String} newClassName the class name that will be replacing the old class name
1517 * If the className exists on the node it is removed, if it doesn't exist it is added.
1518 * @method toggleClass
1519 * @see Node.toggleClass
1520 * @param {String} className the class name to be toggled
1523 Y.NodeList.importMethod(Y.Node.prototype, methods);
1526 if (!document.documentElement.hasAttribute) { // IE < 8
1527 Y.Node.prototype.hasAttribute = function(attr) {
1528 return Y.DOM.getAttribute(this._node, attr) !== '';
1532 // IE throws error when setting input.type = 'hidden',
1533 // input.setAttribute('type', 'hidden') and input.attributes.type.value = 'hidden'
1534 Y.Node.ATTRS.type = {
1535 setter: function(val) {
1536 if (val === 'hidden') {
1538 this._node.type = 'hidden';
1540 this.setStyle('display', 'none');
1541 this._inputType = 'hidden';
1544 try { // IE errors when changing the type from "hidden'
1545 this._node.type = val;
1552 getter: function() {
1553 return this._inputType || this._node.type;
1556 _bypassProxy: true // don't update DOM when using with Attribute
1560 }, '3.0.0' ,{requires:['dom-base', 'selector-css2', 'event-base']});
1561 YUI.add('node-style', function(Y) {
1565 * Extended Node interface for managing node styles.
1567 * @submodule node-style
1572 * Returns the style's current value.
1575 * @param {String} attr The style attribute to retrieve.
1576 * @return {String} The current value of the style property for the element.
1581 * Returns the computed value for the given style property.
1582 * @method getComputedStyle
1583 * @param {String} attr The style attribute to retrieve.
1584 * @return {String} The computed value of the style property for the element.
1589 * Sets a style property of the node.
1591 * @param {String} attr The style attribute to set.
1592 * @param {String|Number} val The value.
1598 * Sets multiple style properties on the node.
1600 * @param {Object} hash An object literal of property:value pairs.
1605 Y.Node.importMethod(Y.DOM, methods);
1607 * Returns an array of values for each node.
1610 * @see Node.getStyle
1611 * @param {String} attr The style attribute to retrieve.
1612 * @return {Array} The current values of the style property for the element.
1616 * Returns an array of the computed value for each node.
1617 * @method getComputedStyle
1618 * @see Node.getComputedStyle
1619 * @param {String} attr The style attribute to retrieve.
1620 * @return {Array} The computed values for each node.
1624 * Sets a style property on each node.
1626 * @see Node.setStyle
1627 * @param {String} attr The style attribute to set.
1628 * @param {String|Number} val The value.
1633 * Sets multiple style properties on each node.
1635 * @see Node.setStyles
1636 * @param {Object} hash An object literal of property:value pairs.
1639 Y.NodeList.importMethod(Y.Node.prototype, methods);
1643 }, '3.0.0' ,{requires:['dom-style', 'node-base']});
1644 YUI.add('node-screen', function(Y) {
1647 * Extended Node interface for managing regions and screen positioning.
1648 * Adds support for positioning elements and normalizes window size and scroll detection.
1650 * @submodule node-screen
1653 // these are all "safe" returns, no wrapping required
1656 * Returns the inner width of the viewport (exludes scrollbar).
1664 * Returns the inner height of the viewport (exludes scrollbar).
1685 * Amount page has been scroll vertically
1686 * @config docScrollX
1692 * Amount page has been scroll horizontally
1693 * @config docScrollY
1699 Y.Node.ATTRS[name] = {
1700 getter: function() {
1701 var args = Array.prototype.slice.call(arguments);
1702 args.unshift(Y.Node.getDOMNode(this));
1704 return Y.DOM[name].apply(this, args);
1710 Y.Node.ATTRS.scrollLeft = {
1711 getter: function() {
1712 var node = Y.Node.getDOMNode(this);
1713 return ('scrollLeft' in node) ? node.scrollLeft : Y.DOM.docScrollX(node);
1716 setter: function(val) {
1717 var node = Y.Node.getDOMNode(this);
1719 if ('scrollLeft' in node) {
1720 node.scrollLeft = val;
1721 } else if (node.document || node.nodeType === 9) {
1722 Y.DOM._getWin(node).scrollTo(val, Y.DOM.docScrollY(node)); // scroll window if win or doc
1729 Y.Node.ATTRS.scrollTop = {
1730 getter: function() {
1731 var node = Y.Node.getDOMNode(this);
1732 return ('scrollTop' in node) ? node.scrollTop : Y.DOM.docScrollY(node);
1735 setter: function(val) {
1736 var node = Y.Node.getDOMNode(this);
1738 if ('scrollTop' in node) {
1739 node.scrollTop = val;
1740 } else if (node.document || node.nodeType === 9) {
1741 Y.DOM._getWin(node).scrollTo(Y.DOM.docScrollX(node), val); // scroll window if win or doc
1748 Y.Node.importMethod(Y.DOM, [
1750 * Gets the current position of the node in page coordinates.
1753 * @return {Array} The XY position of the node
1758 * Set the position of the node in page coordinates, regardless of how the node is positioned.
1760 * @param {Array} xy Contains X & Y values for new position (coordinates are page-based)
1766 * Gets the current position of the node in page coordinates.
1768 * @return {Int} The X position of the node
1773 * Set the position of the node in page coordinates, regardless of how the node is positioned.
1775 * @param {Int} x X value for new position (coordinates are page-based)
1781 * Gets the current position of the node in page coordinates.
1783 * @return {Int} The Y position of the node
1788 * Set the position of the node in page coordinates, regardless of how the node is positioned.
1790 * @param {Int} y Y value for new position (coordinates are page-based)
1797 * Returns a region object for the node
1802 Y.Node.ATTRS.region = {
1803 getter: function() {
1804 var node = Y.Node.getDOMNode(this);
1805 if (node && !node.tagName) {
1806 if (node.nodeType === 9) { // document
1807 node = node.documentElement;
1808 } else if (node.alert) { // window
1809 node = node.document.documentElement;
1812 return Y.DOM.region(node);
1817 * Returns a region object for the node's viewport
1818 * @config viewportRegion
1821 Y.Node.ATTRS.viewportRegion = {
1822 getter: function() {
1823 return Y.DOM.viewportRegion(Y.Node.getDOMNode(this));
1827 Y.Node.importMethod(Y.DOM, 'inViewportRegion');
1829 // these need special treatment to extract 2nd node arg
1831 * Compares the intersection of the node with another node or region
1834 * @param {Node|Object} node2 The node or region to compare with.
1835 * @param {Object} altRegion An alternate region to use (rather than this node's).
1836 * @return {Object} An object representing the intersection of the regions.
1838 Y.Node.prototype.intersect = function(node2, altRegion) {
1839 var node1 = Y.Node.getDOMNode(this);
1840 if (node2 instanceof Y.Node) { // might be a region object
1841 node2 = Y.Node.getDOMNode(node2);
1843 return Y.DOM.intersect(node1, node2, altRegion);
1847 * Determines whether or not the node is within the giving region.
1849 * @param {Node|Object} node2 The node or region to compare with.
1850 * @param {Boolean} all Whether or not all of the node must be in the region.
1851 * @param {Object} altRegion An alternate region to use (rather than this node's).
1852 * @return {Object} An object representing the intersection of the regions.
1854 Y.Node.prototype.inRegion = function(node2, all, altRegion) {
1855 var node1 = Y.Node.getDOMNode(this);
1856 if (node2 instanceof Y.Node) { // might be a region object
1857 node2 = Y.Node.getDOMNode(node2);
1859 return Y.DOM.inRegion(node1, node2, all, altRegion);
1863 }, '3.0.0' ,{requires:['dom-screen']});
1864 YUI.add('node-pluginhost', function(Y) {
1867 * Registers plugins to be instantiated at the class level (plugins
1868 * which should be plugged into every instance of Node by default).
1873 * @param {Function | Array} plugin Either the plugin class, an array of plugin classes or an array of objects (with fn and cfg properties defined)
1874 * @param {Object} config (Optional) If plugin is the plugin class, the configuration for the plugin
1876 Y.Node.plug = function() {
1877 var args = Y.Array(arguments);
1878 args.unshift(Y.Node);
1879 Y.Plugin.Host.plug.apply(Y.Base, args);
1884 * Unregisters any class level plugins which have been registered by the Node
1886 * @method Node.unplug
1889 * @param {Function | Array} plugin The plugin class, or an array of plugin classes
1891 Y.Node.unplug = function() {
1892 var args = Y.Array(arguments);
1893 args.unshift(Y.Node);
1894 Y.Plugin.Host.unplug.apply(Y.Base, args);
1898 Y.mix(Y.Node, Y.Plugin.Host, false, null, 1);
1900 // allow batching of plug/unplug via NodeList
1901 // doesn't use NodeList.importMethod because we need real Nodes (not tmpNode)
1902 Y.NodeList.prototype.plug = function() {
1903 var args = arguments;
1904 Y.NodeList.each(this, function(node) {
1905 Y.Node.prototype.plug.apply(Y.one(node), args);
1909 Y.NodeList.prototype.unplug = function() {
1910 var args = arguments;
1911 Y.NodeList.each(this, function(node) {
1912 Y.Node.prototype.unplug.apply(Y.one(node), args);
1917 }, '3.0.0' ,{requires:['node-base', 'pluginhost']});
1918 YUI.add('node-event-delegate', function(Y) {
1921 * Functionality to make the node a delegated event container
1923 * @submodule node-event-delegate
1927 * Functionality to make the node a delegated event container
1929 * @param type {String} the event type to delegate
1930 * @param fn {Function} the function to execute
1931 * @param selector {String} a selector that must match the target of the event.
1932 * @return {Event.Handle} the detach handle
1935 Y.Node.prototype.delegate = function(type, fn, selector) {
1937 var args = Array.prototype.slice.call(arguments, 3),
1938 a = [type, fn, Y.Node.getDOMNode(this), selector];
1941 return Y.delegate.apply(Y, a);
1945 }, '3.0.0' ,{requires:['node-base', 'event-delegate', 'pluginhost']});
1948 YUI.add('node', function(Y){}, '3.0.0' ,{skinnable:false, use:['node-base', 'node-style', 'node-screen', 'node-pluginhost', 'node-event-delegate'], requires:['dom', 'event-base', 'event-delegate', 'pluginhost']});