2 Copyright (c) 2008, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.net/yui/license.txt
8 * Provides Attribute configurations.
9 * @namespace YAHOO.util
12 * @param hash {Object} The intial Attribute.
13 * @param {YAHOO.util.AttributeProvider} The owner of the Attribute instance.
16 YAHOO
.util
.Attribute = function(hash
, owner
) {
19 this.configure(hash
, true);
23 YAHOO
.util
.Attribute
.prototype = {
25 * The name of the attribute.
32 * The value of the attribute.
39 * The owner of the attribute.
41 * @type YAHOO.util.AttributeProvider
46 * Whether or not the attribute is read only.
53 * Whether or not the attribute can only be written once.
60 * The attribute's initial configuration.
62 * @property _initialConfig
68 * Whether or not the attribute's value has been set.
76 * The method to use when setting the attribute's value.
77 * The method recieves the new value as the only argument.
84 * The validator to use when setting the attribute's value.
92 * Retrieves the current value of the attribute.
94 * @return {any} The current value of the attribute.
96 getValue: function() {
101 * Sets the value of the attribute and fires beforeChange and change events.
103 * @param {Any} value The value to apply to the attribute.
104 * @param {Boolean} silent If true the change events will not be fired.
105 * @return {Boolean} Whether or not the value was set.
107 setValue: function(value
, silent
) {
109 var owner
= this.owner
;
110 var name
= this.name
;
114 prevValue
: this.getValue(),
118 if (this.readOnly
|| ( this.writeOnce
&& this._written
) ) {
119 return false; // write not allowed
122 if (this.validator
&& !this.validator
.call(owner
, value
) ) {
123 return false; // invalid value
127 beforeRetVal
= owner
.fireBeforeChangeEvent(event
);
128 if (beforeRetVal
=== false) {
134 this.method
.call(owner
, value
);
138 this._written
= true;
143 this.owner
.fireChangeEvent(event
);
150 * Allows for configuring the Attribute's properties.
152 * @param {Object} map A key-value map of Attribute properties.
153 * @param {Boolean} init Whether or not this should become the initial config.
155 configure: function(map
, init
) {
157 this._written
= false; // reset writeOnce
158 this._initialConfig
= this._initialConfig
|| {};
160 for (var key
in map
) {
161 if ( key
&& YAHOO
.lang
.hasOwnProperty(map
, key
) ) {
162 this[key
] = map
[key
];
164 this._initialConfig
[key
] = map
[key
];
171 * Resets the value to the initial config value.
173 * @return {Boolean} Whether or not the value was set.
175 resetValue: function() {
176 return this.setValue(this._initialConfig
.value
);
180 * Resets the attribute config to the initial config state.
181 * @method resetConfig
183 resetConfig: function() {
184 this.configure(this._initialConfig
);
188 * Resets the value to the current value.
189 * Useful when values may have gotten out of sync with actual properties.
191 * @return {Boolean} Whether or not the value was set.
193 refresh: function(silent
) {
194 this.setValue(this.value
, silent
);
199 var Lang
= YAHOO
.util
.Lang
;
202 Copyright (c) 2006, Yahoo! Inc. All rights reserved.
203 Code licensed under the BSD License:
204 http://developer.yahoo.net/yui/license.txt
208 * Provides and manages YAHOO.util.Attribute instances
209 * @namespace YAHOO.util
210 * @class AttributeProvider
211 * @uses YAHOO.util.EventProvider
213 YAHOO
.util
.AttributeProvider = function() {};
215 YAHOO
.util
.AttributeProvider
.prototype = {
218 * A key-value map of Attribute configurations
220 * @protected (may be used by subclasses and augmentors)
226 * Returns the current value of the attribute.
228 * @param {String} key The attribute whose value will be returned.
231 this._configs
= this._configs
|| {};
232 var config
= this._configs
[key
];
242 * Sets the value of a config.
244 * @param {String} key The name of the attribute
245 * @param {Any} value The value to apply to the attribute
246 * @param {Boolean} silent Whether or not to suppress change events
247 * @return {Boolean} Whether or not the value was set.
249 set: function(key
, value
, silent
){
250 this._configs
= this._configs
|| {};
251 var config
= this._configs
[key
];
257 return config
.setValue(value
, silent
);
261 * Returns an array of attribute names.
262 * @method getAttributeKeys
263 * @return {Array} An array of attribute names.
265 getAttributeKeys: function(){
266 this._configs
= this._configs
;
269 for (var key
in this._configs
) {
270 config
= this._configs
[key
];
271 if ( Lang
.hasOwnProperty(this._configs
, key
) &&
272 !Lang
.isUndefined(config
) ) {
273 keys
[keys
.length
] = key
;
281 * Sets multiple attribute values.
282 * @method setAttributes
283 * @param {Object} map A key-value map of attributes
284 * @param {Boolean} silent Whether or not to suppress change events
286 setAttributes: function(map
, silent
){
287 for (var key
in map
) {
288 if ( Lang
.hasOwnProperty(map
, key
) ) {
289 this.set(key
, map
[key
], silent
);
295 * Resets the specified attribute's value to its initial value.
297 * @param {String} key The name of the attribute
298 * @param {Boolean} silent Whether or not to suppress change events
299 * @return {Boolean} Whether or not the value was set
301 resetValue: function(key
, silent
){
302 this._configs
= this._configs
|| {};
303 if (this._configs
[key
]) {
304 this.set(key
, this._configs
[key
]._initialConfig
.value
, silent
);
311 * Sets the attribute's value to its current value.
313 * @param {String | Array} key The attribute(s) to refresh
314 * @param {Boolean} silent Whether or not to suppress change events
316 refresh: function(key
, silent
){
317 this._configs
= this._configs
;
319 key
= ( ( Lang
.isString(key
) ) ? [key
] : key
) ||
320 this.getAttributeKeys();
322 for (var i
= 0, len
= key
.length
; i
< len
; ++i
) {
323 if ( // only set if there is a value and not null
324 this._configs
[key
[i
]] &&
325 ! Lang
.isUndefined(this._configs
[key
[i
]].value
) &&
326 ! Lang
.isNull(this._configs
[key
[i
]].value
) ) {
327 this._configs
[key
[i
]].refresh(silent
);
333 * Adds an Attribute to the AttributeProvider instance.
335 * @param {String} key The attribute's name
336 * @param {Object} map A key-value map containing the
337 * attribute's properties.
338 * @deprecated Use setAttributeConfig
340 register: function(key
, map
) {
341 this.setAttributeConfig(key
, map
);
346 * Returns the attribute's properties.
347 * @method getAttributeConfig
348 * @param {String} key The attribute's name
350 * @return {object} A key-value map containing all of the
351 * attribute's properties.
353 getAttributeConfig: function(key
) {
354 this._configs
= this._configs
|| {};
355 var config
= this._configs
[key
] || {};
356 var map
= {}; // returning a copy to prevent overrides
358 for (key
in config
) {
359 if ( Lang
.hasOwnProperty(config
, key
) ) {
360 map
[key
] = config
[key
];
368 * Sets or updates an Attribute instance's properties.
369 * @method setAttributeConfig
370 * @param {String} key The attribute's name.
371 * @param {Object} map A key-value map of attribute properties
372 * @param {Boolean} init Whether or not this should become the intial config.
374 setAttributeConfig: function(key
, map
, init
) {
375 this._configs
= this._configs
|| {};
377 if (!this._configs
[key
]) {
379 this._configs
[key
] = this.createAttribute(map
);
381 this._configs
[key
].configure(map
, init
);
386 * Sets or updates an Attribute instance's properties.
387 * @method configureAttribute
388 * @param {String} key The attribute's name.
389 * @param {Object} map A key-value map of attribute properties
390 * @param {Boolean} init Whether or not this should become the intial config.
391 * @deprecated Use setAttributeConfig
393 configureAttribute: function(key
, map
, init
) {
394 this.setAttributeConfig(key
, map
, init
);
398 * Resets an attribute to its intial configuration.
399 * @method resetAttributeConfig
400 * @param {String} key The attribute's name.
403 resetAttributeConfig: function(key
){
404 this._configs
= this._configs
|| {};
405 this._configs
[key
].resetConfig();
408 // wrapper for EventProvider.subscribe
409 // to create events on the fly
410 subscribe: function(type
, callback
) {
411 this._events
= this._events
|| {};
413 if ( !(type
in this._events
) ) {
414 this._events
[type
] = this.createEvent(type
);
417 YAHOO
.util
.EventProvider
.prototype.subscribe
.apply(this, arguments
);
421 this.subscribe
.apply(this, arguments
);
424 addListener: function() {
425 this.subscribe
.apply(this, arguments
);
429 * Fires the attribute's beforeChange event.
430 * @method fireBeforeChangeEvent
431 * @param {String} key The attribute's name.
432 * @param {Obj} e The event object to pass to handlers.
434 fireBeforeChangeEvent: function(e
) {
436 type
+= e
.type
.charAt(0).toUpperCase() + e
.type
.substr(1) + 'Change';
438 return this.fireEvent(e
.type
, e
);
442 * Fires the attribute's change event.
443 * @method fireChangeEvent
444 * @param {String} key The attribute's name.
445 * @param {Obj} e The event object to pass to the handlers.
447 fireChangeEvent: function(e
) {
449 return this.fireEvent(e
.type
, e
);
452 createAttribute: function(map
) {
453 return new YAHOO
.util
.Attribute(map
, this);
457 YAHOO
.augment(YAHOO
.util
.AttributeProvider
, YAHOO
.util
.EventProvider
);
461 // internal shorthand
462 var Dom
= YAHOO
.util
.Dom
,
463 AttributeProvider
= YAHOO
.util
.AttributeProvider
;
466 * Element provides an wrapper object to simplify adding
467 * event listeners, using dom methods, and managing attributes.
469 * @namespace YAHOO.util
470 * @requires yahoo, dom, event
475 * Element provides an wrapper object to simplify adding
476 * event listeners, using dom methods, and managing attributes.
478 * @uses YAHOO.util.AttributeProvider
480 * @param el {HTMLElement | String} The html element that
481 * represents the Element.
482 * @param {Object} map A key-value map of initial config names and values
484 YAHOO
.util
.Element = function(el
, map
) {
485 if (arguments
.length
) {
490 YAHOO
.util
.Element
.prototype = {
492 * Dom events supported by the Element instance.
493 * @property DOM_EVENTS
499 * Wrapper for HTMLElement method.
500 * @method appendChild
501 * @param {YAHOO.util.Element || HTMLElement} child The element to append.
503 appendChild: function(child
) {
504 child
= child
.get ? child
.get('element') : child
;
505 this.get('element').appendChild(child
);
509 * Wrapper for HTMLElement method.
510 * @method getElementsByTagName
511 * @param {String} tag The tagName to collect
513 getElementsByTagName: function(tag
) {
514 return this.get('element').getElementsByTagName(tag
);
518 * Wrapper for HTMLElement method.
519 * @method hasChildNodes
520 * @return {Boolean} Whether or not the element has childNodes
522 hasChildNodes: function() {
523 return this.get('element').hasChildNodes();
527 * Wrapper for HTMLElement method.
528 * @method insertBefore
529 * @param {HTMLElement} element The HTMLElement to insert
530 * @param {HTMLElement} before The HTMLElement to insert
531 * the element before.
533 insertBefore: function(element
, before
) {
534 element
= element
.get ? element
.get('element') : element
;
535 before
= (before
&& before
.get) ? before
.get('element') : before
;
537 this.get('element').insertBefore(element
, before
);
541 * Wrapper for HTMLElement method.
542 * @method removeChild
543 * @param {HTMLElement} child The HTMLElement to remove
545 removeChild: function(child
) {
546 child
= child
.get ? child
.get('element') : child
;
547 this.get('element').removeChild(child
);
552 * Wrapper for HTMLElement method.
553 * @method replaceChild
554 * @param {HTMLElement} newNode The HTMLElement to insert
555 * @param {HTMLElement} oldNode The HTMLElement to replace
557 replaceChild: function(newNode
, oldNode
) {
558 newNode
= newNode
.get ? newNode
.get('element') : newNode
;
559 oldNode
= oldNode
.get ? oldNode
.get('element') : oldNode
;
560 return this.get('element').replaceChild(newNode
, oldNode
);
565 * Registers Element specific attributes.
566 * @method initAttributes
567 * @param {Object} map A key-value map of initial attribute configs
569 initAttributes: function(map
) {
573 * Adds a listener for the given event. These may be DOM or
574 * customEvent listeners. Any event that is fired via fireEvent
575 * can be listened for. All handlers receive an event object.
576 * @method addListener
577 * @param {String} type The name of the event to listen for
578 * @param {Function} fn The handler to call when the event fires
579 * @param {Any} obj A variable to pass to the handler
580 * @param {Object} scope The object to use for the scope of the handler
582 addListener: function(type
, fn
, obj
, scope
) {
583 var el
= this.get('element');
584 scope
= scope
|| this;
586 el
= this.get('id') || el
;
588 if (!this._events
[type
]) { // create on the fly
589 if ( this.DOM_EVENTS
[type
] ) {
590 YAHOO
.util
.Event
.addListener(el
, type
, function(e
) {
591 if (e
.srcElement
&& !e
.target
) { // supplement IE with target
592 e
.target
= e
.srcElement
;
594 self
.fireEvent(type
, e
);
598 this.createEvent(type
, this);
601 YAHOO
.util
.EventProvider
.prototype.subscribe
.apply(this, arguments
); // notify via customEvent
606 * Alias for addListener
608 * @param {String} type The name of the event to listen for
609 * @param {Function} fn The function call when the event fires
610 * @param {Any} obj A variable to pass to the handler
611 * @param {Object} scope The object to use for the scope of the handler
613 on: function() { this.addListener
.apply(this, arguments
); },
616 * Alias for addListener
618 * @param {String} type The name of the event to listen for
619 * @param {Function} fn The function call when the event fires
620 * @param {Any} obj A variable to pass to the handler
621 * @param {Object} scope The object to use for the scope of the handler
623 subscribe: function() { this.addListener
.apply(this, arguments
); },
626 * Remove an event listener
627 * @method removeListener
628 * @param {String} type The name of the event to listen for
629 * @param {Function} fn The function call when the event fires
631 removeListener: function(type
, fn
) {
632 this.unsubscribe
.apply(this, arguments
);
636 * Wrapper for Dom method.
638 * @param {String} className The className to add
640 addClass: function(className
) {
641 Dom
.addClass(this.get('element'), className
);
645 * Wrapper for Dom method.
646 * @method getElementsByClassName
647 * @param {String} className The className to collect
648 * @param {String} tag (optional) The tag to use in
649 * conjunction with class name
650 * @return {Array} Array of HTMLElements
652 getElementsByClassName: function(className
, tag
) {
653 return Dom
.getElementsByClassName(className
, tag
,
654 this.get('element') );
658 * Wrapper for Dom method.
660 * @param {String} className The className to add
661 * @return {Boolean} Whether or not the element has the class name
663 hasClass: function(className
) {
664 return Dom
.hasClass(this.get('element'), className
);
668 * Wrapper for Dom method.
669 * @method removeClass
670 * @param {String} className The className to remove
672 removeClass: function(className
) {
673 return Dom
.removeClass(this.get('element'), className
);
677 * Wrapper for Dom method.
678 * @method replaceClass
679 * @param {String} oldClassName The className to replace
680 * @param {String} newClassName The className to add
682 replaceClass: function(oldClassName
, newClassName
) {
683 return Dom
.replaceClass(this.get('element'),
684 oldClassName
, newClassName
);
688 * Wrapper for Dom method.
690 * @param {String} property The style property to set
691 * @param {String} value The value to apply to the style property
693 setStyle: function(property
, value
) {
694 var el
= this.get('element');
696 return this._queue
[this._queue
.length
] = ['setStyle', arguments
];
699 return Dom
.setStyle(el
, property
, value
); // TODO: always queuing?
703 * Wrapper for Dom method.
705 * @param {String} property The style property to retrieve
706 * @return {String} The current value of the property
708 getStyle: function(property
) {
709 return Dom
.getStyle(this.get('element'), property
);
713 * Apply any queued set calls.
716 fireQueue: function() {
717 var queue
= this._queue
;
718 for (var i
= 0, len
= queue
.length
; i
< len
; ++i
) {
719 this[queue
[i
][0]].apply(this, queue
[i
][1]);
724 * Appends the HTMLElement into either the supplied parentNode.
726 * @param {HTMLElement | Element} parentNode The node to append to
727 * @param {HTMLElement | Element} before An optional node to insert before
729 appendTo: function(parent
, before
) {
730 parent
= (parent
.get) ? parent
.get('element') : Dom
.get(parent
);
732 this.fireEvent('beforeAppendTo', {
733 type
: 'beforeAppendTo',
738 before
= (before
&& before
.get) ?
739 before
.get('element') : Dom
.get(before
);
740 var element
= this.get('element');
750 if (element
.parent
!= parent
) {
752 parent
.insertBefore(element
, before
);
754 parent
.appendChild(element
);
759 this.fireEvent('appendTo', {
766 var configs
= this._configs
|| {};
767 var el
= configs
.element
; // avoid loop due to 'element'
768 if (el
&& !configs
[key
] && !YAHOO
.lang
.isUndefined(el
.value
[key
]) ) {
769 return el
.value
[key
];
772 return AttributeProvider
.prototype.get.call(this, key
);
775 setAttributes: function(map
, silent
){
776 var el
= this.get('element');
777 for (var key
in map
) {
778 // need to configure if setting unconfigured HTMLElement attribute
779 if ( !this._configs
[key
] && !YAHOO
.lang
.isUndefined(el
[key
]) ) {
780 this.setAttributeConfig(key
);
784 // set based on configOrder
785 for (var i
= 0, len
= this._configOrder
.length
; i
< len
; ++i
) {
786 if (map
[this._configOrder
[i
]] !== undefined) {
787 this.set(this._configOrder
[i
], map
[this._configOrder
[i
]], silent
);
792 set: function(key
, value
, silent
) {
793 var el
= this.get('element');
795 this._queue
[this._queue
.length
] = ['set', arguments
];
796 if (this._configs
[key
]) {
797 this._configs
[key
].value
= value
; // so "get" works while queueing
803 // set it on the element if not configured and is an HTML attribute
804 if ( !this._configs
[key
] && !YAHOO
.lang
.isUndefined(el
[key
]) ) {
805 _registerHTMLAttr
.call(this, key
);
808 return AttributeProvider
.prototype.set.apply(this, arguments
);
811 setAttributeConfig: function(key
, map
, init
) {
812 var el
= this.get('element');
814 if (el
&& !this._configs
[key
] && !YAHOO
.lang
.isUndefined(el
[key
]) ) {
815 _registerHTMLAttr
.call(this, key
, map
);
817 AttributeProvider
.prototype.setAttributeConfig
.apply(this, arguments
);
819 this._configOrder
.push(key
);
822 getAttributeKeys: function() {
823 var el
= this.get('element');
824 var keys
= AttributeProvider
.prototype.getAttributeKeys
.call(this);
826 //add any unconfigured element keys
827 for (var key
in el
) {
828 if (!this._configs
[key
]) {
829 keys
[key
] = keys
[key
] || el
[key
];
836 createEvent: function(type
, scope
) {
837 this._events
[type
] = true;
838 AttributeProvider
.prototype.createEvent
.apply(this, arguments
);
841 init: function(el
, attr
) {
842 _initElement
.apply(this, arguments
);
846 var _initElement = function(el
, attr
) {
847 this._queue
= this._queue
|| [];
848 this._events
= this._events
|| {};
849 this._configs
= this._configs
|| {};
850 this._configOrder
= [];
852 attr
.element
= attr
.element
|| el
|| null;
870 var isReady
= false; // to determine when to init HTMLElement and content
872 if (YAHOO
.lang
.isString(el
) ) { // defer until available/ready
873 _registerHTMLAttr
.call(this, 'id', { value
: attr
.element
});
878 _initHTMLElement
.call(this, attr
);
879 _initContent
.call(this, attr
);
882 YAHOO
.util
.Event
.onAvailable(attr
.element
, function() {
883 if (!isReady
) { // otherwise already done
884 _initHTMLElement
.call(this, attr
);
887 this.fireEvent('available', { type
: 'available', target
: attr
.element
});
890 YAHOO
.util
.Event
.onContentReady(attr
.element
, function() {
891 if (!isReady
) { // otherwise already done
892 _initContent
.call(this, attr
);
894 this.fireEvent('contentReady', { type
: 'contentReady', target
: attr
.element
});
898 var _initHTMLElement = function(attr
) {
900 * The HTMLElement the Element instance refers to.
904 this.setAttributeConfig('element', {
905 value
: Dom
.get(attr
.element
),
910 var _initContent = function(attr
) {
911 this.initAttributes(attr
);
912 this.setAttributes(attr
, true);
918 * Sets the value of the property and fires beforeChange and change events.
920 * @method _registerHTMLAttr
921 * @param {YAHOO.util.Element} element The Element instance to
922 * register the config to.
923 * @param {String} key The name of the config to register
924 * @param {Object} map A key-value map of the config's params
926 var _registerHTMLAttr = function(key
, map
) {
927 var el
= this.get('element');
930 map
.method
= map
.method
|| function(value
) {
933 map
.value
= map
.value
|| el
[key
];
934 this._configs
[key
] = new YAHOO
.util
.Attribute(map
, this);
938 * Fires when the Element's HTMLElement can be retrieved by Id.
939 * <p>See: <a href="#addListener">Element.addListener</a></p>
940 * <p><strong>Event fields:</strong><br>
941 * <code><String> type</code> available<br>
942 * <code><HTMLElement>
943 * target</code> the HTMLElement bound to this Element instance<br>
944 * <p><strong>Usage:</strong><br>
945 * <code>var handler = function(e) {var target = e.target};<br>
946 * myTabs.addListener('available', handler);</code></p>
951 * Fires when the Element's HTMLElement subtree is rendered.
952 * <p>See: <a href="#addListener">Element.addListener</a></p>
953 * <p><strong>Event fields:</strong><br>
954 * <code><String> type</code> contentReady<br>
955 * <code><HTMLElement>
956 * target</code> the HTMLElement bound to this Element instance<br>
957 * <p><strong>Usage:</strong><br>
958 * <code>var handler = function(e) {var target = e.target};<br>
959 * myTabs.addListener('contentReady', handler);</code></p>
960 * @event contentReady
964 * Fires before the Element is appended to another Element.
965 * <p>See: <a href="#addListener">Element.addListener</a></p>
966 * <p><strong>Event fields:</strong><br>
967 * <code><String> type</code> beforeAppendTo<br>
968 * <code><HTMLElement/Element>
969 * target</code> the HTMLElement/Element being appended to
970 * <p><strong>Usage:</strong><br>
971 * <code>var handler = function(e) {var target = e.target};<br>
972 * myTabs.addListener('beforeAppendTo', handler);</code></p>
973 * @event beforeAppendTo
977 * Fires after the Element is appended to another Element.
978 * <p>See: <a href="#addListener">Element.addListener</a></p>
979 * <p><strong>Event fields:</strong><br>
980 * <code><String> type</code> appendTo<br>
981 * <code><HTMLElement/Element>
982 * target</code> the HTMLElement/Element being appended to
983 * <p><strong>Usage:</strong><br>
984 * <code>var handler = function(e) {var target = e.target};<br>
985 * myTabs.addListener('appendTo', handler);</code></p>
989 YAHOO
.augment(YAHOO
.util
.Element
, AttributeProvider
);
992 YAHOO
.register("element", YAHOO
.util
.Element
, {version
: "2.5.2", build
: "1076"});