3
Copyright 2011 Yahoo! Inc. All rights reserved.
4
Licensed under the BSD License.
5
http://yuilibrary.com/license/
7
YUI.add('node-base', function(Y) {
11
* @submodule node-base
16
* Determines whether each node has the given className.
19
* @param {String} className the class name to search for
20
* @return {Boolean} Whether or not the element has the specified class
25
* Adds a class name to each node.
27
* @param {String} className the class name to add to the node's class attribute
33
* Removes a class name from each node.
35
* @param {String} className the class name to remove from the node's class attribute
41
* Replace a class with another class for each node.
42
* If no oldClassName is present, the newClassName is simply added.
43
* @method replaceClass
44
* @param {String} oldClassName the class name to be replaced
45
* @param {String} newClassName the class name that will be replacing the old class name
51
* If the className exists on the node it is removed, if it doesn't exist it is added.
53
* @param {String} className the class name to be toggled
54
* @param {Boolean} force Option to force adding or removing the class.
60
Y.Node.importMethod(Y.DOM, methods);
62
* Determines whether each node has the given className.
66
* @param {String} className the class name to search for
67
* @return {Array} An array of booleans for each node bound to the NodeList.
71
* Adds a class name to each node.
74
* @param {String} className the class name to add to the node's class attribute
79
* Removes a class name from each node.
81
* @see Node.removeClass
82
* @param {String} className the class name to remove from the node's class attribute
87
* Replace a class with another class for each node.
88
* If no oldClassName is present, the newClassName is simply added.
89
* @method replaceClass
90
* @see Node.replaceClass
91
* @param {String} oldClassName the class name to be replaced
92
* @param {String} newClassName the class name that will be replacing the old class name
97
* If the className exists on the node it is removed, if it doesn't exist it is added.
99
* @see Node.toggleClass
100
* @param {String} className the class name to be toggled
103
Y.NodeList.importMethod(Y.Node.prototype, methods);
106
* @submodule node-base
113
* Returns a new dom node using the provided markup string.
116
* @param {String} html The markup used to create the element
117
* @param {HTMLDocument} doc An optional document context
118
* @return {Node} A Node instance bound to a DOM node or fragment
121
Y_Node.create = function(html, doc) {
122
if (doc && doc._node) {
125
return Y.one(Y_DOM.create(html, doc));
128
Y.mix(Y_Node.prototype, {
130
* Creates a new Node using the provided markup string.
132
* @param {String} html The markup used to create the element
133
* @param {HTMLDocument} doc An optional document context
134
* @return {Node} A Node instance bound to a DOM node or fragment
136
create: Y_Node.create,
139
* Inserts the content before the reference node.
141
* @param {String | Node | HTMLElement | NodeList | HTMLCollection} content The content to insert
142
* @param {Int | Node | HTMLElement | String} where The position to insert at.
143
* Possible "where" arguments
146
* <dd>The Node to insert before</dd>
147
* <dt>HTMLElement</dt>
148
* <dd>The element to insert before</dd>
150
* <dd>The index of the child element to insert before</dd>
152
* <dd>Replaces the existing HTML</dd>
154
* <dd>Inserts before the existing HTML</dd>
156
* <dd>Inserts content before the node</dd>
158
* <dd>Inserts content after the node</dd>
162
insert: function(content, where) {
163
this._insert(content, where);
167
_insert: function(content, where) {
168
var node = this._node,
171
if (typeof where == 'number') { // allow index
172
where = this._node.childNodes[where];
173
} else if (where && where._node) { // Node
177
if (content && typeof content != 'string') { // allow Node or NodeList/Array instances
178
content = content._node || content._nodes || content;
180
ret = Y_DOM.addHTML(node, content, where);
186
* Inserts the content as the firstChild of the node.
188
* @param {String | Node | HTMLElement} content The content to insert
191
prepend: function(content) {
192
return this.insert(content, 0);
196
* Inserts the content as the lastChild of the node.
198
* @param {String | Node | HTMLElement} content The content to insert
201
append: function(content) {
202
return this.insert(content, null);
206
* @method appendChild
207
* @param {String | HTMLElement | Node} node Node to be appended
208
* @return {Node} The appended node
210
appendChild: function(node) {
211
return Y_Node.scrubVal(this._insert(node));
215
* @method insertBefore
216
* @param {String | HTMLElement | Node} newNode Node to be appended
217
* @param {HTMLElement | Node} refNode Node to be inserted before
218
* @return {Node} The inserted node
220
insertBefore: function(newNode, refNode) {
221
return Y.Node.scrubVal(this._insert(newNode, refNode));
225
* Appends the node to the given node.
227
* @param {Node | HTMLElement} node The node to append to
230
appendTo: function(node) {
231
Y.one(node).append(this);
236
* Replaces the node's current content with the content.
238
* @param {String | Node | HTMLElement | NodeList | HTMLCollection} content The content to insert
241
setContent: function(content) {
242
this._insert(content, 'replace');
247
* Returns the node's current content (e.g. innerHTML)
249
* @return {String} The current content
251
getContent: function(content) {
252
return this.get('innerHTML');
256
Y.NodeList.importMethod(Y.Node.prototype, [
258
* Called on each Node instance
265
/** Called on each Node instance
272
* Called on each Node instance
274
* @method appendChild
275
* @see Node.appendChild
279
/** Called on each Node instance
280
* @method insertBefore
281
* @see Node.insertBefore
285
/** Called on each Node instance
291
/** Called on each Node instance
293
* @see Node.setContent
297
/** Called on each Node instance
299
* @see Node.getContent
305
* @submodule node-base
312
* Static collection of configuration attributes for special handling
319
* Allows for getting and setting the text of an element.
320
* Formatting is preserved and special characters are treated literally.
326
return Y_DOM.getText(this._node);
329
setter: function(content) {
330
Y_DOM.setText(this._node, content);
336
* Allows for getting and setting the text of an element.
337
* Formatting is preserved and special characters are treated literally.
343
return Y_DOM.getAttribute(this._node, 'for');
346
setter: function(val) {
347
Y_DOM.setAttribute(this._node, 'for', val);
354
return this._node.getElementsByTagName('option');
359
* Returns a NodeList instance of all HTMLElement children.
366
var node = this._node,
367
children = node.children,
371
childNodes = node.childNodes;
374
for (i = 0, len = childNodes.length; i < len; ++i) {
375
if (childNodes[i][TAG_NAME]) {
376
children[children.length] = childNodes[i];
380
return Y.all(children);
386
return Y_DOM.getValue(this._node);
389
setter: function(val) {
390
Y_DOM.setValue(this._node, val);
396
Y.Node.importMethod(Y.DOM, [
398
* Allows setting attributes on DOM nodes, normalizing in some cases.
399
* This passes through to the DOM node, allowing for custom attributes.
400
* @method setAttribute
404
* @param {string} name The attribute name
405
* @param {string} value The value to set
409
* Allows getting attributes on DOM nodes, normalizing in some cases.
410
* This passes through to the DOM node, allowing for custom attributes.
411
* @method getAttribute
414
* @param {string} name The attribute name
415
* @return {string} The attribute value
422
* @submodule node-base
426
var Y_NodeList = Y.NodeList;
428
* List of events that route to DOM events
430
* @property DOM_EVENTS
434
Y_Node.DOM_EVENTS = {
469
orientationchange: 1,
480
// Add custom event adaptors to this list. This will make it so
481
// that delegate, key, available, contentready, etc all will
482
// be available through Node.on
483
Y.mix(Y_Node.DOM_EVENTS, Y.Env.evt.plugins);
485
Y.augment(Y_Node, Y.EventTarget);
487
Y.mix(Y_Node.prototype, {
489
* Removes event listeners from the node and (optionally) its subtree
491
* @param {Boolean} recurse (optional) Whether or not to remove listeners from the
493
* @param {String} type (optional) Only remove listeners of the specified type
497
purge: function(recurse, type) {
498
Y.Event.purgeElement(this._node, recurse, type);
504
Y.mix(Y.NodeList.prototype, {
505
_prepEvtArgs: function(type, fn, context) {
506
// map to Y.on/after signature (type, fn, nodes, context, arg1, arg2, etc)
507
var args = Y.Array(arguments, 0, true);
509
if (args.length < 2) { // type only (event hash) just add nodes
510
args[2] = this._nodes;
512
args.splice(2, 0, this._nodes);
515
args[3] = context || this; // default to NodeList instance as context
521
Subscribe a callback function for each `Node` in the collection to execute
522
in response to a DOM event.
524
NOTE: Generally, the `on()` method should be avoided on `NodeLists`, in
525
favor of using event delegation from a parent Node. See the Event user
528
Most DOM events are associated with a preventable default behavior, such as
529
link clicks navigating to a new page. Callbacks are passed a
530
`DOMEventFacade` object as their first argument (usually called `e`) that
531
can be used to prevent this default behavior with `e.preventDefault()`. See
532
the `DOMEventFacade` API for all available properties and methods on the
535
By default, the `this` object will be the `NodeList` that the subscription
536
came from, <em>not the `Node` that received the event</em>. Use
537
`e.currentTarget` to refer to the `Node`.
539
Returning `false` from a callback is supported as an alternative to calling
540
`e.preventDefault(); e.stopPropagation();`. However, it is recommended to
541
use the event methods.
545
Y.all(".sku").on("keydown", function (e) {
546
if (e.keyCode === 13) {
549
// Use e.currentTarget to refer to the individual Node
550
var item = Y.MyApp.searchInventory( e.currentTarget.get('value') );
556
@param {String} type The name of the event
557
@param {Function} fn The callback to execute in response to the event
558
@param {Object} [context] Override `this` object in callback
559
@param {Any} [arg*] 0..n additional arguments to supply to the subscriber
560
@return {EventHandle} A subscription handle capable of detaching that
564
on: function(type, fn, context) {
565
return Y.on.apply(Y, this._prepEvtArgs.apply(this, arguments));
569
* Applies an one-time event listener to each Node bound to the NodeList.
571
* @param {String} type The event being listened for
572
* @param {Function} fn The handler to call when the event fires
573
* @param {Object} context The context to call the handler with.
574
* Default is the NodeList instance.
575
* @return {EventHandle} A subscription handle capable of detaching that
579
once: function(type, fn, context) {
580
return Y.once.apply(Y, this._prepEvtArgs.apply(this, arguments));
584
* Applies an event listener to each Node bound to the NodeList.
585
* The handler is called only after all on() handlers are called
586
* and the event is not prevented.
588
* @param {String} type The event being listened for
589
* @param {Function} fn The handler to call when the event fires
590
* @param {Object} context The context to call the handler with.
591
* Default is the NodeList instance.
592
* @return {EventHandle} A subscription handle capable of detaching that
596
after: function(type, fn, context) {
597
return Y.after.apply(Y, this._prepEvtArgs.apply(this, arguments));
601
* Applies an one-time event listener to each Node bound to the NodeList
602
* that will be called only after all on() handlers are called and the
603
* event is not prevented.
606
* @param {String} type The event being listened for
607
* @param {Function} fn The handler to call when the event fires
608
* @param {Object} context The context to call the handler with.
609
* Default is the NodeList instance.
610
* @return {EventHandle} A subscription handle capable of detaching that
614
onceAfter: function(type, fn, context) {
615
return Y.onceAfter.apply(Y, this._prepEvtArgs.apply(this, arguments));
619
Y_NodeList.importMethod(Y.Node.prototype, [
621
* Called on each Node instance
628
/** Called on each Node instance
630
* @see Node.detachAll
637
Subscribe a callback function to execute in response to a DOM event or custom
640
Most DOM events are associated with a preventable default behavior such as
641
link clicks navigating to a new page. Callbacks are passed a `DOMEventFacade`
642
object as their first argument (usually called `e`) that can be used to
643
prevent this default behavior with `e.preventDefault()`. See the
644
`DOMEventFacade` API for all available properties and methods on the object.
646
If the event name passed as the first parameter is not a whitelisted DOM event,
647
it will be treated as a custom event subscriptions, allowing
648
`node.fire('customEventName')` later in the code. Refer to the Event user guide
649
for the full DOM event whitelist.
651
By default, the `this` object in the callback will refer to the subscribed
654
Returning `false` from a callback is supported as an alternative to calling
655
`e.preventDefault(); e.stopPropagation();`. However, it is recommended to use
660
Y.one("#my-form").on("submit", function (e) {
663
// proceed with ajax form submission instead...
667
@param {String} type The name of the event
668
@param {Function} fn The callback to execute in response to the event
669
@param {Object} [context] Override `this` object in callback
670
@param {Any} [arg*] 0..n additional arguments to supply to the subscriber
671
@return {EventHandle} A subscription handle capable of detaching that
676
Y.mix(Y.Node.ATTRS, {
678
setter: function(h) {
679
Y.DOM.setHeight(this._node, h);
684
return this._node.offsetHeight;
689
setter: function(w) {
690
Y.DOM.setWidth(this._node, w);
695
return this._node.offsetWidth;
700
Y.mix(Y.Node.prototype, {
701
sizeTo: function(w, h) {
703
if (arguments.length < 2) {
705
w = node.get('offsetWidth');
706
h = node.get('offsetHeight');
717
* @submodule node-base
722
Y.mix(Y_Node.prototype, {
724
* Makes the node visible.
725
* If the "transition" module is loaded, show optionally
726
* animates the showing of the node using either the default
727
* transition effect ('fadeIn'), or the given named effect.
730
* @param {String} name A named Transition effect to use as the show effect.
731
* @param {Object} config Options to use with the transition.
732
* @param {Function} callback An optional function to run after the transition completes.
735
show: function(callback) {
736
callback = arguments[arguments.length - 1];
737
this.toggleView(true, callback);
742
* The implementation for showing nodes.
743
* Default is to toggle the style.display property.
749
this.setStyle('display', '');
753
_isHidden: function() {
754
return Y.DOM.getStyle(this._node, 'display') === 'none';
757
toggleView: function(on, callback) {
758
this._toggleView.apply(this, arguments);
761
_toggleView: function(on, callback) {
762
callback = arguments[arguments.length - 1];
764
// base on current state if not forcing
765
if (typeof on != 'boolean') {
766
on = (this._isHidden()) ? 1 : 0;
775
if (typeof callback == 'function') {
784
* If the "transition" module is loaded, hide optionally
785
* animates the hiding of the node using either the default
786
* transition effect ('fadeOut'), or the given named effect.
788
* @param {String} name A named Transition effect to use as the show effect.
789
* @param {Object} config Options to use with the transition.
790
* @param {Function} callback An optional function to run after the transition completes.
793
hide: function(callback) {
794
callback = arguments[arguments.length - 1];
795
this.toggleView(false, callback);
800
* The implementation for hiding nodes.
801
* Default is to toggle the style.display property.
807
this.setStyle('display', 'none');
811
Y.NodeList.importMethod(Y.Node.prototype, [
813
* Makes each node visible.
814
* If the "transition" module is loaded, show optionally
815
* animates the showing of the node using either the default
816
* transition effect ('fadeIn'), or the given named effect.
818
* @param {String} name A named Transition effect to use as the show effect.
819
* @param {Object} config Options to use with the transition.
820
* @param {Function} callback An optional function to run after the transition completes.
828
* If the "transition" module is loaded, hide optionally
829
* animates the hiding of the node using either the default
830
* transition effect ('fadeOut'), or the given named effect.
832
* @param {String} name A named Transition effect to use as the show effect.
833
* @param {Object} config Options to use with the transition.
834
* @param {Function} callback An optional function to run after the transition completes.
842
if (!Y.config.doc.documentElement.hasAttribute) { // IE < 8
843
Y.Node.prototype.hasAttribute = function(attr) {
844
if (attr === 'value') {
845
if (this.get('value') !== "") { // IE < 8 fails to populate specified when set in HTML
849
return !!(this._node.attributes[attr] &&
850
this._node.attributes[attr].specified);
854
// IE throws an error when calling focus() on an element that's invisible, not
855
// displayed, or disabled.
856
Y.Node.prototype.focus = function () {
860
Y.log('error focusing node: ' + e.toString(), 'error', 'node');
866
// IE throws error when setting input.type = 'hidden',
867
// input.setAttribute('type', 'hidden') and input.attributes.type.value = 'hidden'
868
Y.Node.ATTRS.type = {
869
setter: function(val) {
870
if (val === 'hidden') {
872
this._node.type = 'hidden';
874
this.setStyle('display', 'none');
875
this._inputType = 'hidden';
878
try { // IE errors when changing the type from "hidden'
879
this._node.type = val;
881
Y.log('error setting type: ' + val, 'info', 'node');
888
return this._inputType || this._node.type;
891
_bypassProxy: true // don't update DOM when using with Attribute
894
if (Y.config.doc.createElement('form').elements.nodeType) {
895
// IE: elements collection is also FORM node which trips up scrubVal.
896
Y.Node.ATTRS.elements = {
898
return this.all('input, textarea, button, select');
905
}, '3.4.1' ,{requires:['dom-base', 'node-core', 'event-base']});