/* Copyright (c) 2009, Yahoo! Inc. All rights reserved. Code licensed under the BSD License: http://developer.yahoo.net/yui/license.txt version: 3.0.0 build: 1549 */ YUI.add('node-base', function(Y) { /** * The Node Utility provides a DOM-like interface for interacting with DOM nodes. * @module node * @submodule node-base */ /** * The Node class provides a wrapper for manipulating DOM Nodes. * Node properties can be accessed via the set/get methods. * Use Y.get() to retrieve Node instances. * * NOTE: Node properties are accessed using * the set and get methods. * * @class Node * @constructor * @for Node */ // "globals" var DOT = '.', NODE_NAME = 'nodeName', NODE_TYPE = 'nodeType', OWNER_DOCUMENT = 'ownerDocument', TAG_NAME = 'tagName', UID = '_yuid', Node = function(node) { var uid = node[UID]; if (uid && Node._instances[uid] && Node._instances[uid]._node !== node) { node[UID] = null; // unset existing uid to prevent collision (via clone or hack) } uid = Y.stamp(node); if (!uid) { // stamp failed; likely IE non-HTMLElement uid = Y.guid(); } this[UID] = uid; this._node = node; Node._instances[uid] = this; this._stateProxy = node; // when augmented with Attribute if (this._initPlugins) { // when augmented with Plugin.Host this._initPlugins(); } }, // used with previous/next/ancestor tests _wrapFn = function(fn) { var ret = null; if (fn) { ret = (typeof fn === 'string') ? function(n) { return Y.Selector.test(n, fn); } : function(n) { return fn(Node.get(n)); }; } return ret; }; // end "globals" Node.NAME = 'Node'; Node.re_aria = /^(?:role$|aria-)/; Node.DOM_EVENTS = { abort: true, beforeunload: true, blur: true, change: true, click: true, close: true, command: true, contextmenu: true, drag: true, dragstart: true, dragenter: true, dragover: true, dragleave: true, dragend: true, drop: true, dblclick: true, error: true, focus: true, keydown: true, keypress: true, keyup: true, load: true, message: true, mousedown: true, mousemove: true, mouseout: true, mouseover: true, mouseup: true, mousemultiwheel: true, mousewheel: true, submit: true, mouseenter: true, mouseleave: true, scroll: true, reset: true, resize: true, select: true, textInput: true, unload: true }; // Add custom event adaptors to this list. This will make it so // that delegate, key, available, contentready, etc all will // be available through Node.on Y.mix(Node.DOM_EVENTS, Y.Env.evt.plugins); Node._instances = {}; /** * Retrieves the DOM node bound to a Node instance * @method Node.getDOMNode * @static * * @param {Y.Node || HTMLNode} node The Node instance or an HTMLNode * @return {HTMLNode} The DOM node bound to the Node instance. If a DOM node is passed * as the node argument, it is simply returned. */ Node.getDOMNode = function(node) { if (node) { return (node.nodeType) ? node : node._node || null; } return null; }; Node.scrubVal = function(val, node) { if (node && val) { // only truthy values are risky if (typeof val === 'object' || typeof val === 'function') { // safari nodeList === function if (NODE_TYPE in val || Y.DOM.isWindow(val)) {// node || window val = Node.get(val); } else if ((val.item && !val._nodes) || // dom collection or Node instance (val[0] && val[0][NODE_TYPE])) { // array of DOM Nodes val = Y.all(val); } } } else if (val === undefined) { val = node; // for chaining } return val; }; Node.addMethod = function(name, fn, context) { if (name && fn && typeof fn === 'function') { Node.prototype[name] = function() { context = context || this; var args = Y.Array(arguments), ret; if (args[0] && args[0] instanceof Node) { args[0] = args[0]._node; } if (args[1] && args[1] instanceof Node) { args[1] = args[1]._node; } args.unshift(this._node); ret = Node.scrubVal(fn.apply(context, args), this); return ret; }; } else { } }; Node.importMethod = function(host, name, altName) { if (typeof name === 'string') { altName = altName || name; Node.addMethod(altName, host[name], host); } else { Y.each(name, function(n) { Node.importMethod(host, n); }); } }; /** * Returns a single Node instance bound to the node or the * first element matching the given selector. * @method Y.one * @static * @param {String | HTMLElement} node a node or Selector * @param {Y.Node || HTMLElement} doc an optional document to scan. Defaults to Y.config.doc. */ Node.one = function(node) { var instance = null, cachedNode, uid; if (node) { if (typeof node === 'string') { if (node.indexOf('doc') === 0) { // doc OR document node = Y.config.doc; } else if (node.indexOf('win') === 0) { // win OR window node = Y.config.win; } else { node = Y.Selector.query(node, null, true); } if (!node) { return null; } } else if (node instanceof Node) { return node; // NOTE: return } uid = node._yuid; instance = Node._instances[uid]; // reuse exising instances cachedNode = instance ? instance._node : null; if (!instance || (cachedNode && node !== cachedNode)) { // new Node when nodes don't match instance = new Node(node); } } return instance; }; /** * Returns a single Node instance bound to the node or the * first element matching the given selector. * @method Y.get * @deprecated Use Y.one * @static * @param {String | HTMLElement} node a node or Selector * @param {Y.Node || HTMLElement} doc an optional document to scan. Defaults to Y.config.doc. */ Node.get = function() { return Node.one.apply(Node, arguments); }; /** * Creates a new dom node using the provided markup string. * @method create * @static * @param {String} html The markup used to create the element * @param {HTMLDocument} doc An optional document context * @return {Node} A Node instance bound to a DOM node or fragment */ Node.create = function() { return Node.get(Y.DOM.create.apply(Y.DOM, arguments)); }; Node.ATTRS = { /** * Allows for getting and setting the text of an element. * Formatting is preserved and special characters are treated literally. * @config text * @type String */ text: { getter: function() { return Y.DOM.getText(this._node); }, setter: function(content) { Y.DOM.setText(this._node, content); return content; } }, 'options': { getter: function() { return this._node.getElementsByTagName('option'); } }, // IE: elements collection is also FORM node which trips up scrubVal. // preconverting to NodeList // TODO: break out for IE only 'elements': { getter: function() { return Y.all(this._node.elements); } }, /** * Returns a NodeList instance of all HTMLElement children. * @readOnly * @config children * @type NodeList */ 'children': { getter: function() { var node = this._node, children = node.children, childNodes, i, len; if (!children) { childNodes = node.childNodes; children = []; for (i = 0, len = childNodes.length; i < len; ++i) { if (childNodes[i][TAG_NAME]) { children[children.length] = childNodes[i]; } } } return Y.all(children); } }, value: { getter: function() { return Y.DOM.getValue(this._node); }, setter: function(val) { Y.DOM.setValue(this._node, val); return val; } }, data: { getter: function() { return this._data; }, setter: function(val) { this._data = val; return val; } } }; // call with instance context Node.DEFAULT_SETTER = function(name, val) { var node = this._stateProxy, strPath; if (name.indexOf(DOT) > -1) { strPath = name; name = name.split(DOT); // only allow when defined on node Y.Object.setValue(node, name, val); } else if (node[name] !== undefined) { // pass thru DOM properties node[name] = val; } return val; }; // call with instance context Node.DEFAULT_GETTER = function(name) { var node = this._stateProxy, val; if (name.indexOf && name.indexOf(DOT) > -1) { val = Y.Object.getValue(node, name.split(DOT)); } else if (node[name] !== undefined) { // pass thru from DOM val = node[name]; } return val; }; Y.augment(Node, Y.Event.Target); Y.mix(Node.prototype, { toString: function() { var str = '', errorMsg = this[UID] + ': not bound to a node', node = this._node; if (node) { str += node[NODE_NAME]; if (node.id) { str += '#' + node.id; } if (node.className) { str += '.' + node.className.replace(' ', '.'); } // TODO: add yuid? str += ' ' + this[UID]; } return str || errorMsg; }, /** * Returns an attribute value on the Node instance * @method get * @param {String} attr The attribute to be set * @return {any} The current value of the attribute */ get: function(attr) { var val; if (this._getAttr) { // use Attribute imple val = this._getAttr(attr); } else { val = this._get(attr); } if (val) { val = Y.Node.scrubVal(val, this); } return val; }, _get: function(attr) { var attrConfig = Node.ATTRS[attr], val; if (attrConfig && attrConfig.getter) { val = attrConfig.getter.call(this); } else if (Node.re_aria.test(attr)) { val = this._node.getAttribute(attr, 2); } else { val = Node.DEFAULT_GETTER.apply(this, arguments); } return val; }, /** * Sets an attribute on the Node instance. * @method set * @param {String} attr The attribute to be set. * @param {any} val The value to set the attribute to. * @chainable */ set: function(attr, val) { var attrConfig = Node.ATTRS[attr]; if (this._setAttr) { // use Attribute imple this._setAttr.apply(this, arguments); } else { // use setters inline if (attrConfig && attrConfig.setter) { attrConfig.setter.call(this, val); } else if (Node.re_aria.test(attr)) { // special case Aria this._node.setAttribute(attr, val); } else { Node.DEFAULT_SETTER.apply(this, arguments); } } return this; }, /** * Sets multiple attributes. * @method setAttrs * @param {Object} attrMap an object of name/value pairs to set * @chainable */ setAttrs: function(attrMap) { if (this._setAttrs) { // use Attribute imple this._setAttrs(attrMap); } else { // use setters inline Y.Object.each(attrMap, function(v, n) { this.set(n, v); }, this); } return this; }, /** * Returns an object containing the values for the requested attributes. * @method getAttrs * @param {Array} attrs an array of attributes to get values * @return {Object} An object with attribute name/value pairs. */ getAttrs: function(attrs) { var ret = {}; if (this._getAttrs) { // use Attribute imple this._getAttrs(attrs); } else { // use setters inline Y.Array.each(attrs, function(v, n) { ret[v] = this.get(v); }, this); } return ret; }, /** * Creates a new Node using the provided markup string. * @method create * @param {String} html The markup used to create the element * @param {HTMLDocument} doc An optional document context * @return {Node} A Node instance bound to a DOM node or fragment */ create: Node.create, /** * Compares nodes to determine if they match. * Node instances can be compared to each other and/or HTMLElements. * @method compareTo * @param {HTMLElement | Node} refNode The reference node to compare to the node. * @return {Boolean} True if the nodes match, false if they do not. */ compareTo: function(refNode) { var node = this._node; if (refNode instanceof Y.Node) { refNode = refNode._node; } return node === refNode; }, /** * Determines whether the node is appended to the document. * @method inDoc * @param {Node|HTMLElement} doc optional An optional document to check against. * Defaults to current document. * @return {Boolean} Whether or not this node is appended to the document. */ inDoc: function(doc) { var node = this._node; doc = (doc) ? doc._node || doc : node[OWNER_DOCUMENT]; if (doc.documentElement) { return Y.DOM.contains(doc.documentElement, node); } }, getById: function(id) { var node = this._node, ret = Y.DOM.byId(id, node[OWNER_DOCUMENT]); if (ret && Y.DOM.contains(node, ret)) { ret = Y.one(ret); } else { ret = null; } return ret; }, /** * Returns the nearest ancestor that passes the test applied by supplied boolean method. * @method ancestor * @param {String | Function} fn A selector string or boolean method for testing elements. * If a function is used, it receives the current node being tested as the only argument. * @return {Node} The matching Node instance or null if not found */ ancestor: function(fn) { return Node.get(Y.DOM.elementByAxis(this._node, 'parentNode', _wrapFn(fn))); }, /** * Returns the previous matching sibling. * Returns the nearest element node sibling if no method provided. * @method previous * @param {String | Function} fn A selector or boolean method for testing elements. * If a function is used, it receives the current node being tested as the only argument. * @return {Node} Node instance or null if not found */ previous: function(fn, all) { return Node.get(Y.DOM.elementByAxis(this._node, 'previousSibling', _wrapFn(fn), all)); }, /** * Returns the next matching sibling. * Returns the nearest element node sibling if no method provided. * @method next * @param {String | Function} fn A selector or boolean method for testing elements. * If a function is used, it receives the current node being tested as the only argument. * @return {Node} Node instance or null if not found */ next: function(node, fn, all) { return Node.get(Y.DOM.elementByAxis(this._node, 'nextSibling', _wrapFn(fn), all)); }, /** * Retrieves a Node instance of nodes based on the given CSS selector. * @method one * * @param {string} selector The CSS selector to test against. * @return {Node} A Node instance for the matching HTMLElement. */ one: function(selector) { return Y.one(Y.Selector.query(selector, this._node, true)); }, /** * Retrieves a Node instance of nodes based on the given CSS selector. * @method query * @deprecated Use one() * @param {string} selector The CSS selector to test against. * @return {Node} A Node instance for the matching HTMLElement. */ query: function(selector) { return this.one(selector); }, /** * Retrieves a nodeList based on the given CSS selector. * @method all * * @param {string} selector The CSS selector to test against. * @return {NodeList} A NodeList instance for the matching HTMLCollection/Array. */ all: function(selector) { var nodelist = Y.all(Y.Selector.query(selector, this._node)); nodelist._query = selector; return nodelist; }, /** * Retrieves a nodeList based on the given CSS selector. * @method queryAll * @deprecated Use all() * @param {string} selector The CSS selector to test against. * @return {NodeList} A NodeList instance for the matching HTMLCollection/Array. */ queryAll: function(selector) { return this.all(selector); }, // TODO: allow fn test /** * Test if the supplied node matches the supplied selector. * @method test * * @param {string} selector The CSS selector to test against. * @return {boolean} Whether or not the node matches the selector. */ test: function(selector) { return Y.Selector.test(this._node, selector); }, /** * Removes the node from its parent. * Shortcut for myNode.get('parentNode').removeChild(myNode); * @method remove * @chainable * */ remove: function(destroy) { var node = this._node; node.parentNode.removeChild(node); if (destroy) { this.destroy(true); } return this; }, /** * Replace the node with the other node. This is a DOM update only * and does not change the node bound to the Node instance. * Shortcut for myNode.get('parentNode').replaceChild(newNode, myNode); * @method replace * @chainable * */ replace: function(newNode) { var node = this._node; node.parentNode.replaceChild(newNode, node); return this; }, purge: function(recurse, type) { Y.Event.purgeElement(this._node, recurse, type); }, destroy: function(purge) { delete Node._instances[this[UID]]; if (purge) { this.purge(true); } if (this.unplug) { this.unplug(); } this._node._yuid = null; this._node = null; this._stateProxy = null; }, /** * Invokes a method on the Node instance * @method invoke * @param {String} method The name of the method to invoke * @param {Any} a, b, c, etc. Arguments to invoke the method with. * @return Whatever the underly method returns. * DOM Nodes and Collections return values * are converted to Node/NodeList instances. * */ invoke: function(method, a, b, c, d, e) { var node = this._node, ret; if (a && a instanceof Y.Node) { a = a._node; } if (b && b instanceof Y.Node) { b = b._node; } ret = node[method](a, b, c, d, e); return Y.Node.scrubVal(ret, this); }, /** * Applies the given function to each Node in the NodeList. * @method each * @deprecated Use NodeList * @param {Function} fn The function to apply * @param {Object} context optional An optional context to apply the function with * Default context is the NodeList instance * @chainable */ each: function(fn, context) { context = context || this; return fn.call(context, this); }, /** * Retrieves the Node instance at the given index. * @method item * @deprecated Use NodeList * * @param {Number} index The index of the target Node. * @return {Node} The Node instance at the given index. */ item: function(index) { return this; }, /** * Returns the current number of items in the Node. * @method size * @deprecated Use NodeList * @return {Int} The number of items in the Node. */ size: function() { return this._node ? 1 : 0; }, /** * Inserts the content before the reference node. * @method insert * @param {String | Y.Node | HTMLElement} content The content to insert * @param {Int | Y.Node | HTMLElement | String} where The position to insert at. * @chainable */ insert: function(content, where) { var node = this._node; if (content) { if (typeof where === 'number') { // allow index where = this._node.childNodes[where]; } if (typeof content !== 'string') { // allow Node or NodeList/Array instances if (content._node) { // Node content = content._node; } else if (content._nodes || (!content.nodeType && content.length)) { // NodeList or Array Y.each(content._nodes, function(n) { Y.DOM.addHTML(node, n, where); }); return this; // NOTE: early return } } Y.DOM.addHTML(node, content, where); } return this; }, /** * Inserts the content as the firstChild of the node. * @method prepend * @param {String | Y.Node | HTMLElement} content The content to insert * @chainable */ prepend: function(content) { return this.insert(content, 0); }, /** * Inserts the content as the lastChild of the node. * @method append * @param {String | Y.Node | HTMLElement} content The content to insert * @chainable */ append: function(content) { return this.insert(content, null); }, /** * Replaces the node's current content with the content. * @method setContent * @param {String | Y.Node | HTMLElement} content The content to insert * @chainable */ setContent: function(content) { Y.DOM.addHTML(this._node, content, 'replace'); return this; }, // TODO: need this? hasMethod: function(method) { var node = this._node; return (node && (typeof node === 'function')); } }, true); Y.Node = Node; Y.get = Y.Node.get; Y.one = Y.Node.one; /** * The NodeList module provides support for managing collections of Nodes. * @module node * @submodule nodelist */ /** * The NodeList class provides a wrapper for manipulating DOM NodeLists. * NodeList properties can be accessed via the set/get methods. * Use Y.all() to retrieve NodeList instances. * * @class NodeList * @constructor */ var NodeList = function(nodes) { if (typeof nodes === 'string') { this._query = nodes; nodes = Y.Selector.query(nodes); } else { nodes = Y.Array(nodes, 0, true); } NodeList._instances[Y.stamp(this)] = this; this._nodes = nodes; }; // end "globals" NodeList.NAME = 'NodeList'; /** * Retrieves the DOM nodes bound to a NodeList instance * @method NodeList.getDOMNodes * @static * * @param {Y.NodeList} node The NodeList instance * @return {Array} The array of DOM nodes bound to the NodeList */ NodeList.getDOMNodes = function(nodeList) { return nodeList._nodes; }; NodeList._instances = []; NodeList.each = function(instance, fn, context) { var nodes = instance._nodes; if (nodes && nodes.length) { Y.Array.each(nodes, fn, context || instance); } else { } }; NodeList.addMethod = function(name, fn, context) { if (name && fn) { NodeList.prototype[name] = function() { var ret = [], args = arguments; Y.Array.each(this._nodes, function(node) { var UID = '_yuid', instance = Y.Node._instances[node[UID]], ctx, result; if (!instance) { instance = NodeList._getTempNode(node); } ctx = context || instance; result = fn.apply(ctx, args); if (result !== undefined && result !== instance) { ret[ret.length] = result; } }); // TODO: remove tmp pointer return ret.length ? ret : this; }; } else { } }; NodeList.importMethod = function(host, name, altName) { if (typeof name === 'string') { altName = altName || name; NodeList.addMethod(name, host[name]); } else { Y.each(name, function(n) { NodeList.importMethod(host, n); }); } }; NodeList._getTempNode = function(node) { var tmp = NodeList._tempNode; if (!tmp) { tmp = Y.Node.create('
'); NodeList._tempNode = tmp; } tmp._node = node; tmp._stateProxy = node; return tmp; }; Y.mix(NodeList.prototype, { /** * Retrieves the Node instance at the given index. * @method item * * @param {Number} index The index of the target Node. * @return {Node} The Node instance at the given index. */ item: function(index) { return Y.one((this._nodes || [])[index]); }, /** * Applies the given function to each Node in the NodeList. * @method each * @param {Function} fn The function to apply. It receives 3 arguments: * the current node instance, the node's index, and the NodeList instance * @param {Object} context optional An optional context to apply the function with * Default context is the current Node instance * @chainable */ each: function(fn, context) { var instance = this; Y.Array.each(this._nodes, function(node, index) { node = Y.one(node); return fn.call(context || node, node, index, instance); }); return instance; }, batch: function(fn, context) { var nodelist = this; Y.Array.each(this._nodes, function(node, index) { var instance = Y.Node._instances[node[UID]]; if (!instance) { instance = NodeList._getTempNode(node); } return fn.call(context || instance, instance, index, nodelist); }); return nodelist; }, /** * Executes the function once for each node until a true value is returned. * @method some * @param {Function} fn The function to apply. It receives 3 arguments: * the current node instance, the node's index, and the NodeList instance * @param {Object} context optional An optional context to execute the function from. * Default context is the current Node instance * @return {Boolean} Whether or not the function returned true for any node. */ some: function(fn, context) { var instance = this; return Y.Array.some(this._nodes, function(node, index) { node = Y.one(node); context = context || node; return fn.call(context, node, index, instance); }); }, /** * Creates a documenFragment from the nodes bound to the NodeList instance * @method toDocFrag * @return Node a Node instance bound to the documentFragment */ toFrag: function() { return Y.one(Y.DOM._nl2frag(this._nodes)); }, /** * Returns the index of the node in the NodeList instance * or -1 if the node isn't found. * @method indexOf * @param {Y.Node || DOMNode} node the node to search for * @return {Int} the index of the node value or -1 if not found */ indexOf: function(node) { return Y.Array.indexOf(this._nodes, Y.Node.getDOMNode(node)); }, /** * Filters the NodeList instance down to only nodes matching the given selector. * @method filter * @param {String} selector The selector to filter against * @return {NodeList} NodeList containing the updated collection * @see Selector */ filter: function(selector) { return Y.all(Y.Selector.filter(this._nodes, selector)); }, /** * Creates a new NodeList containing all nodes at every n indices, where * remainder n % index equals r. * (zero-based index). * @method modulus * @param {Int} n The offset to use (return every nth node) * @param {Int} r An optional remainder to use with the modulus operation (defaults to zero) * @return {NodeList} NodeList containing the updated collection */ modulus: function(n, r) { r = r || 0; var nodes = []; NodeList.each(this, function(node, i) { if (i % n === r) { nodes.push(node); } }); return Y.all(nodes); }, /** * Creates a new NodeList containing all nodes at odd indices * (zero-based index). * @method odd * @return {NodeList} NodeList containing the updated collection */ odd: function() { return this.modulus(2, 1); }, /** * Creates a new NodeList containing all nodes at even indices * (zero-based index), including zero. * @method even * @return {NodeList} NodeList containing the updated collection */ even: function() { return this.modulus(2); }, destructor: function() { delete NodeList._instances[this[UID]]; }, /** * Reruns the initial query, when created using a selector query * @method refresh * @chainable */ refresh: function() { var doc, nodes = this._nodes; if (this._query) { if (nodes && nodes[0] && nodes[0].ownerDocument) { doc = nodes[0].ownerDocument; } this._nodes = Y.Selector.query(this._query, doc || Y.config.doc); } return this; }, /** * Applies an event listener to each Node bound to the NodeList. * @method on * @param {String} type The event being listened for * @param {Function} fn The handler to call when the event fires * @param {Object} context The context to call the handler with. * Default is the NodeList instance. * @return {Object} Returns an event handle that can later be use to detach(). * @see Event.on */ on: function(type, fn, context) { var args = Y.Array(arguments, 0, true); args.splice(2, 0, this._nodes); args[3] = context || this; return Y.on.apply(Y, args); }, /** * Applies an event listener to each Node bound to the NodeList. * The handler is called only after all on() handlers are called * and the event is not prevented. * @method after * @param {String} type The event being listened for * @param {Function} fn The handler to call when the event fires * @param {Object} context The context to call the handler with. * Default is the NodeList instance. * @return {Object} Returns an event handle that can later be use to detach(). * @see Event.on */ after: function(type, fn, context) { var args = Y.Array(arguments, 0, true); args.splice(2, 0, this._nodes); args[3] = context || this; return Y.after.apply(Y, args); }, /** * Returns the current number of items in the NodeList. * @method size * @return {Int} The number of items in the NodeList. */ size: function() { return this._nodes.length; }, toString: function() { var str = '', errorMsg = this[UID] + ': not bound to any nodes', nodes = this._nodes, node; if (nodes && nodes[0]) { node = nodes[0]; str += node[NODE_NAME]; if (node.id) { str += '#' + node.id; } if (node.className) { str += '.' + node.className.replace(' ', '.'); } if (nodes.length > 1) { str += '...[' + nodes.length + ' items]'; } } return str || errorMsg; } }, true); NodeList.importMethod(Y.Node.prototype, [ /** * Called on each Node instance * @for NodeList * @method append * @see Node.append */ 'append', /** * Called on each Node instance * @method detach * @see Node.detach */ 'detach', /** Called on each Node instance * @method detachAll * @see Node.detachAll */ 'detachAll', /** Called on each Node instance * @method insert * @see NodeInsert */ 'insert', /** Called on each Node instance * @method prepend * @see Node.prepend */ 'prepend', /** Called on each Node instance * @method remove * @see Node.remove */ 'remove', /** Called on each Node instance * @method set * @see Node.set */ 'set', /** Called on each Node instance * @method setContent * @see Node.setContent */ 'setContent' ]); // one-off implementation to convert array of Nodes to NodeList // e.g. Y.all('input').get('parentNode'); /** Called on each Node instance * @method get * @see Node */ NodeList.prototype.get = function(attr) { var ret = [], nodes = this._nodes, isNodeList = false, getTemp = NodeList._getTempNode, instance, val; if (nodes[0]) { instance = Y.Node._instances[nodes[0]._yuid] || getTemp(nodes[0]); val = instance._get(attr); if (val && val.nodeType) { isNodeList = true; } } Y.Array.each(nodes, function(node) { instance = Y.Node._instances[node._yuid]; if (!instance) { instance = getTemp(node); } val = instance._get(attr); if (!isNodeList) { // convert array of Nodes to NodeList val = Y.Node.scrubVal(val, instance); } ret.push(val); }); return (isNodeList) ? Y.all(ret) : ret; }; Y.NodeList = NodeList; Y.all = function(nodes) { return new NodeList(nodes); }; Y.Node.all = Y.all; Y.Array.each([ /** * Passes through to DOM method. * @method replaceChild * @for Node * @param {HTMLElement | Node} node Node to be inserted * @param {HTMLElement | Node} refNode Node to be replaced * @return {Node} The replaced node */ 'replaceChild', /** * Passes through to DOM method. * @method appendChild * @param {HTMLElement | Node} node Node to be appended * @return {Node} The appended node */ 'appendChild', /** * Passes through to DOM method. * @method insertBefore * @param {HTMLElement | Node} newNode Node to be appended * @param {HTMLElement | Node} refNode Node to be inserted before * @return {Node} The inserted node */ 'insertBefore', /** * Passes through to DOM method. * @method removeChild * @param {HTMLElement | Node} node Node to be removed * @return {Node} The removed node */ 'removeChild', /** * Passes through to DOM method. * @method hasChildNodes * @return {Boolean} Whether or not the node has any childNodes */ 'hasChildNodes', /** * Passes through to DOM method. * @method cloneNode * @param {Boolean} deep Whether or not to perform a deep clone, which includes * subtree and attributes * @return {Node} The clone */ 'cloneNode', /** * Passes through to DOM method. * @method hasAttribute * @param {String} attribute The attribute to test for * @return {Boolean} Whether or not the attribute is present */ 'hasAttribute', /** * Passes through to DOM method. * @method removeAttribute * @param {String} attribute The attribute to be removed * @chainable */ 'removeAttribute', /** * Passes through to DOM method. * @method scrollIntoView * @chainable */ 'scrollIntoView', /** * Passes through to DOM method. * @method getElementsByTagName * @param {String} tagName The tagName to collect * @return {NodeList} A NodeList representing the HTMLCollection */ 'getElementsByTagName', /** * Passes through to DOM method. * @method focus * @chainable */ 'focus', /** * Passes through to DOM method. * @method blur * @chainable */ 'blur', /** * Passes through to DOM method. * Only valid on FORM elements * @method submit * @chainable */ 'submit', /** * Passes through to DOM method. * Only valid on FORM elements * @method reset * @chainable */ 'reset', /** * Passes through to DOM method. * @method select * @chainable */ 'select' ], function(method) { Y.Node.prototype[method] = function(arg1, arg2, arg3) { var ret = this.invoke(method, arg1, arg2, arg3); return ret; }; }); Node.importMethod(Y.DOM, [ /** * Determines whether the ndoe is an ancestor of another HTML element in the DOM hierarchy. * @method contains * @param {Node | HTMLElement} needle The possible node or descendent * @return {Boolean} Whether or not this node is the needle its ancestor */ 'contains', /** * Allows setting attributes on DOM nodes, normalizing in some cases. * This passes through to the DOM node, allowing for custom attributes. * @method setAttribute * @for Node * @for NodeList * @chainable * @param {string} name The attribute name * @param {string} value The value to set */ 'setAttribute', /** * Allows getting attributes on DOM nodes, normalizing in some cases. * This passes through to the DOM node, allowing for custom attributes. * @method getAttribute * @for Node * @for NodeList * @param {string} name The attribute name * @return {string} The attribute value */ 'getAttribute' ]); /** * Allows setting attributes on DOM nodes, normalizing in some cases. * This passes through to the DOM node, allowing for custom attributes. * @method setAttribute * @see Node * @for NodeList * @chainable * @param {string} name The attribute name * @param {string} value The value to set */ /** * Allows getting attributes on DOM nodes, normalizing in some cases. * This passes through to the DOM node, allowing for custom attributes. * @method getAttribute * @see Node * @for NodeList * @param {string} name The attribute name * @return {string} The attribute value */ Y.NodeList.importMethod(Y.Node.prototype, ['getAttribute', 'setAttribute']); (function(Y) { var methods = [ /** * Determines whether each node has the given className. * @method hasClass * @for Node * @param {String} className the class name to search for * @return {Array} An array of booleans for each node bound to the NodeList. */ 'hasClass', /** * Adds a class name to each node. * @method addClass * @param {String} className the class name to add to the node's class attribute * @chainable */ 'addClass', /** * Removes a class name from each node. * @method removeClass * @param {String} className the class name to remove from the node's class attribute * @chainable */ 'removeClass', /** * Replace a class with another class for each node. * If no oldClassName is present, the newClassName is simply added. * @method replaceClass * @param {String} oldClassName the class name to be replaced * @param {String} newClassName the class name that will be replacing the old class name * @chainable */ 'replaceClass', /** * If the className exists on the node it is removed, if it doesn't exist it is added. * @method toggleClass * @param {String} className the class name to be toggled * @chainable */ 'toggleClass' ]; Y.Node.importMethod(Y.DOM, methods); /** * Determines whether each node has the given className. * @method hasClass * @see Node.hasClass * @for NodeList * @param {String} className the class name to search for * @return {Array} An array of booleans for each node bound to the NodeList. */ /** * Adds a class name to each node. * @method addClass * @see Node.addClass * @param {String} className the class name to add to the node's class attribute * @chainable */ /** * Removes a class name from each node. * @method removeClass * @see Node.removeClass * @param {String} className the class name to remove from the node's class attribute * @chainable */ /** * Replace a class with another class for each node. * If no oldClassName is present, the newClassName is simply added. * @method replaceClass * @see Node.replaceClass * @param {String} oldClassName the class name to be replaced * @param {String} newClassName the class name that will be replacing the old class name * @chainable */ /** * If the className exists on the node it is removed, if it doesn't exist it is added. * @method toggleClass * @see Node.toggleClass * @param {String} className the class name to be toggled * @chainable */ Y.NodeList.importMethod(Y.Node.prototype, methods); })(Y); if (!document.documentElement.hasAttribute) { // IE < 8 Y.Node.prototype.hasAttribute = function(attr) { return Y.DOM.getAttribute(this._node, attr) !== ''; }; } // IE throws error when setting input.type = 'hidden', // input.setAttribute('type', 'hidden') and input.attributes.type.value = 'hidden' Y.Node.ATTRS.type = { setter: function(val) { if (val === 'hidden') { try { this._node.type = 'hidden'; } catch(e) { this.setStyle('display', 'none'); this._inputType = 'hidden'; } } else { try { // IE errors when changing the type from "hidden' this._node.type = val; } catch (e) { } } return val; }, getter: function() { return this._inputType || this._node.type; }, _bypassProxy: true // don't update DOM when using with Attribute }; }, '3.0.0' ,{requires:['dom-base', 'selector-css2', 'event-base']});