]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - include/javascript/yui/build/element/element.js
Release 6.5.0
[Github/sugarcrm.git] / include / javascript / yui / build / element / element.js
1 /*
2 Copyright (c) 2011, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.com/yui/license.html
5 version: 2.9.0
6 */
7 /**
8  * Provides Attribute configurations.
9  * @namespace YAHOO.util
10  * @class Attribute
11  * @constructor
12  * @param hash {Object} The intial Attribute.
13  * @param {YAHOO.util.AttributeProvider} The owner of the Attribute instance.
14  */
15
16 YAHOO.util.Attribute = function(hash, owner) {
17     if (owner) { 
18         this.owner = owner;
19         this.configure(hash, true);
20     }
21 };
22
23 YAHOO.util.Attribute.INVALID_VALUE = {};
24
25 YAHOO.util.Attribute.prototype = {
26     /**
27      * The name of the attribute.
28      * @property name
29      * @type String
30      */
31     name: undefined,
32     
33     /**
34      * The value of the attribute.
35      * @property value
36      * @type String
37      */
38     value: null,
39     
40     /**
41      * The owner of the attribute.
42      * @property owner
43      * @type YAHOO.util.AttributeProvider
44      */
45     owner: null,
46     
47     /**
48      * Whether or not the attribute is read only.
49      * @property readOnly
50      * @type Boolean
51      */
52     readOnly: false,
53     
54     /**
55      * Whether or not the attribute can only be written once.
56      * @property writeOnce
57      * @type Boolean
58      */
59     writeOnce: false,
60
61     /**
62      * The attribute's initial configuration.
63      * @private
64      * @property _initialConfig
65      * @type Object
66      */
67     _initialConfig: null,
68     
69     /**
70      * Whether or not the attribute's value has been set.
71      * @private
72      * @property _written
73      * @type Boolean
74      */
75     _written: false,
76     
77     /**
78      * A function to call when setting the attribute's value.
79      * The method receives the new value as the first arg and the attribute name as the 2nd
80      * @property method
81      * @type Function
82      */
83     method: null,
84     
85     /**
86      * The function to use when setting the attribute's value.
87      * The setter receives the new value as the first arg and the attribute name as the 2nd
88      * The return value of the setter replaces the value passed to set(). 
89      * @property setter
90      * @type Function
91      */
92     setter: null,
93     
94     /**
95      * The function to use when getting the attribute's value.
96      * The getter receives the new value as the first arg and the attribute name as the 2nd
97      * The return value of the getter will be used as the return from get().
98      * @property getter
99      * @type Function
100      */
101     getter: null,
102
103     /**
104      * The validator to use when setting the attribute's value.
105      * @property validator
106      * @type Function
107      * @return Boolean
108      */
109     validator: null,
110     
111     /**
112      * Retrieves the current value of the attribute.
113      * @method getValue
114      * @return {any} The current value of the attribute.
115      */
116     getValue: function() {
117         var val = this.value;
118
119         if (this.getter) {
120             val = this.getter.call(this.owner, this.name, val);
121         }
122
123         return val;
124     },
125     
126     /**
127      * Sets the value of the attribute and fires beforeChange and change events.
128      * @method setValue
129      * @param {Any} value The value to apply to the attribute.
130      * @param {Boolean} silent If true the change events will not be fired.
131      * @return {Boolean} Whether or not the value was set.
132      */
133     setValue: function(value, silent) {
134         var beforeRetVal,
135             owner = this.owner,
136             name = this.name,
137             invalidValue = YAHOO.util.Attribute.INVALID_VALUE,
138         
139             event = {
140                 type: name, 
141                 prevValue: this.getValue(),
142                 newValue: value
143         };
144         
145         if (this.readOnly || ( this.writeOnce && this._written) ) {
146             return false; // write not allowed
147         }
148         
149         if (this.validator && !this.validator.call(owner, value) ) {
150             return false; // invalid value
151         }
152
153         if (!silent) {
154             beforeRetVal = owner.fireBeforeChangeEvent(event);
155             if (beforeRetVal === false) {
156                 return false;
157             }
158         }
159
160         if (this.setter) {
161             value = this.setter.call(owner, value, this.name);
162             if (value === undefined) {
163             }
164
165             if (value === invalidValue) {
166                 return false;
167             }
168         }
169         
170         if (this.method) {
171             if (this.method.call(owner, value, this.name) === invalidValue) {
172                 return false; 
173             }
174         }
175         
176         this.value = value; // TODO: set before calling setter/method?
177         this._written = true;
178         
179         event.type = name;
180         
181         if (!silent) {
182             this.owner.fireChangeEvent(event);
183         }
184         
185         return true;
186     },
187     
188     /**
189      * Allows for configuring the Attribute's properties.
190      * @method configure
191      * @param {Object} map A key-value map of Attribute properties.
192      * @param {Boolean} init Whether or not this should become the initial config.
193      */
194     configure: function(map, init) {
195         map = map || {};
196
197         if (init) {
198             this._written = false; // reset writeOnce
199         }
200
201         this._initialConfig = this._initialConfig || {};
202         
203         for (var key in map) {
204             if ( map.hasOwnProperty(key) ) {
205                 this[key] = map[key];
206                 if (init) {
207                     this._initialConfig[key] = map[key];
208                 }
209             }
210         }
211     },
212     
213     /**
214      * Resets the value to the initial config value.
215      * @method resetValue
216      * @return {Boolean} Whether or not the value was set.
217      */
218     resetValue: function() {
219         return this.setValue(this._initialConfig.value);
220     },
221     
222     /**
223      * Resets the attribute config to the initial config state.
224      * @method resetConfig
225      */
226     resetConfig: function() {
227         this.configure(this._initialConfig, true);
228     },
229     
230     /**
231      * Resets the value to the current value.
232      * Useful when values may have gotten out of sync with actual properties.
233      * @method refresh
234      * @return {Boolean} Whether or not the value was set.
235      */
236     refresh: function(silent) {
237         this.setValue(this.value, silent);
238     }
239 };
240
241 (function() {
242     var Lang = YAHOO.util.Lang;
243
244     /*
245     Copyright (c) 2006, Yahoo! Inc. All rights reserved.
246     Code licensed under the BSD License:
247     http://developer.yahoo.net/yui/license.txt
248     */
249     
250     /**
251      * Provides and manages YAHOO.util.Attribute instances
252      * @namespace YAHOO.util
253      * @class AttributeProvider
254      * @uses YAHOO.util.EventProvider
255      */
256     YAHOO.util.AttributeProvider = function() {};
257
258     YAHOO.util.AttributeProvider.prototype = {
259         
260         /**
261          * A key-value map of Attribute configurations
262          * @property _configs
263          * @protected (may be used by subclasses and augmentors)
264          * @private
265          * @type {Object}
266          */
267         _configs: null,
268         /**
269          * Returns the current value of the attribute.
270          * @method get
271          * @param {String} key The attribute whose value will be returned.
272          * @return {Any} The current value of the attribute.
273          */
274         get: function(key){
275             this._configs = this._configs || {};
276             var config = this._configs[key];
277             
278             if (!config || !this._configs.hasOwnProperty(key)) {
279                 return null;
280             }
281             
282             return config.getValue();
283         },
284         
285         /**
286          * Sets the value of a config.
287          * @method set
288          * @param {String} key The name of the attribute
289          * @param {Any} value The value to apply to the attribute
290          * @param {Boolean} silent Whether or not to suppress change events
291          * @return {Boolean} Whether or not the value was set.
292          */
293         set: function(key, value, silent){
294             this._configs = this._configs || {};
295             var config = this._configs[key];
296             
297             if (!config) {
298                 return false;
299             }
300             
301             return config.setValue(value, silent);
302         },
303     
304         /**
305          * Returns an array of attribute names.
306          * @method getAttributeKeys
307          * @return {Array} An array of attribute names.
308          */
309         getAttributeKeys: function(){
310             this._configs = this._configs;
311             var keys = [], key;
312
313             for (key in this._configs) {
314                 if ( Lang.hasOwnProperty(this._configs, key) && 
315                         !Lang.isUndefined(this._configs[key]) ) {
316                     keys[keys.length] = key;
317                 }
318             }
319             
320             return keys;
321         },
322         
323         /**
324          * Sets multiple attribute values.
325          * @method setAttributes
326          * @param {Object} map  A key-value map of attributes
327          * @param {Boolean} silent Whether or not to suppress change events
328          */
329         setAttributes: function(map, silent){
330             for (var key in map) {
331                 if ( Lang.hasOwnProperty(map, key) ) {
332                     this.set(key, map[key], silent);
333                 }
334             }
335         },
336     
337         /**
338          * Resets the specified attribute's value to its initial value.
339          * @method resetValue
340          * @param {String} key The name of the attribute
341          * @param {Boolean} silent Whether or not to suppress change events
342          * @return {Boolean} Whether or not the value was set
343          */
344         resetValue: function(key, silent){
345             this._configs = this._configs || {};
346             if (this._configs[key]) {
347                 this.set(key, this._configs[key]._initialConfig.value, silent);
348                 return true;
349             }
350             return false;
351         },
352     
353         /**
354          * Sets the attribute's value to its current value.
355          * @method refresh
356          * @param {String | Array} key The attribute(s) to refresh
357          * @param {Boolean} silent Whether or not to suppress change events
358          */
359         refresh: function(key, silent) {
360             this._configs = this._configs || {};
361             var configs = this._configs;
362             
363             key = ( ( Lang.isString(key) ) ? [key] : key ) || 
364                     this.getAttributeKeys();
365             
366             for (var i = 0, len = key.length; i < len; ++i) { 
367                 if (configs.hasOwnProperty(key[i])) {
368                     this._configs[key[i]].refresh(silent);
369                 }
370             }
371         },
372     
373         /**
374          * Adds an Attribute to the AttributeProvider instance. 
375          * @method register
376          * @param {String} key The attribute's name
377          * @param {Object} map A key-value map containing the
378          * attribute's properties.
379          * @deprecated Use setAttributeConfig
380          */
381         register: function(key, map) {
382             this.setAttributeConfig(key, map);
383         },
384         
385         
386         /**
387          * Returns the attribute's properties.
388          * @method getAttributeConfig
389          * @param {String} key The attribute's name
390          * @private
391          * @return {object} A key-value map containing all of the
392          * attribute's properties.
393          */
394         getAttributeConfig: function(key) {
395             this._configs = this._configs || {};
396             var config = this._configs[key] || {};
397             var map = {}; // returning a copy to prevent overrides
398             
399             for (key in config) {
400                 if ( Lang.hasOwnProperty(config, key) ) {
401                     map[key] = config[key];
402                 }
403             }
404     
405             return map;
406         },
407         
408         /**
409          * Sets or updates an Attribute instance's properties. 
410          * @method setAttributeConfig
411          * @param {String} key The attribute's name.
412          * @param {Object} map A key-value map of attribute properties
413          * @param {Boolean} init Whether or not this should become the intial config.
414          */
415         setAttributeConfig: function(key, map, init) {
416             this._configs = this._configs || {};
417             map = map || {};
418             if (!this._configs[key]) {
419                 map.name = key;
420                 this._configs[key] = this.createAttribute(map);
421             } else {
422                 this._configs[key].configure(map, init);
423             }
424         },
425         
426         /**
427          * Sets or updates an Attribute instance's properties. 
428          * @method configureAttribute
429          * @param {String} key The attribute's name.
430          * @param {Object} map A key-value map of attribute properties
431          * @param {Boolean} init Whether or not this should become the intial config.
432          * @deprecated Use setAttributeConfig
433          */
434         configureAttribute: function(key, map, init) {
435             this.setAttributeConfig(key, map, init);
436         },
437         
438         /**
439          * Resets an attribute to its intial configuration. 
440          * @method resetAttributeConfig
441          * @param {String} key The attribute's name.
442          * @private
443          */
444         resetAttributeConfig: function(key){
445             this._configs = this._configs || {};
446             this._configs[key].resetConfig();
447         },
448         
449         // wrapper for EventProvider.subscribe
450         // to create events on the fly
451         subscribe: function(type, callback) {
452             this._events = this._events || {};
453
454             if ( !(type in this._events) ) {
455                 this._events[type] = this.createEvent(type);
456             }
457
458             YAHOO.util.EventProvider.prototype.subscribe.apply(this, arguments);
459         },
460
461         on: function() {
462             this.subscribe.apply(this, arguments);
463         },
464
465         addListener: function() {
466             this.subscribe.apply(this, arguments);
467         },
468
469         /**
470          * Fires the attribute's beforeChange event. 
471          * @method fireBeforeChangeEvent
472          * @param {String} key The attribute's name.
473          * @param {Obj} e The event object to pass to handlers.
474          */
475         fireBeforeChangeEvent: function(e) {
476             var type = 'before';
477             type += e.type.charAt(0).toUpperCase() + e.type.substr(1) + 'Change';
478             e.type = type;
479             return this.fireEvent(e.type, e);
480         },
481         
482         /**
483          * Fires the attribute's change event. 
484          * @method fireChangeEvent
485          * @param {String} key The attribute's name.
486          * @param {Obj} e The event object to pass to the handlers.
487          */
488         fireChangeEvent: function(e) {
489             e.type += 'Change';
490             return this.fireEvent(e.type, e);
491         },
492
493         createAttribute: function(map) {
494             return new YAHOO.util.Attribute(map, this);
495         }
496     };
497     
498     YAHOO.augment(YAHOO.util.AttributeProvider, YAHOO.util.EventProvider);
499 })();
500
501 (function() {
502 // internal shorthand
503 var Dom = YAHOO.util.Dom,
504     AttributeProvider = YAHOO.util.AttributeProvider,
505         specialTypes = {
506                 mouseenter: true,
507                 mouseleave: true
508         };
509
510 /**
511  * Element provides an wrapper object to simplify adding
512  * event listeners, using dom methods, and managing attributes. 
513  * @module element
514  * @namespace YAHOO.util
515  * @requires yahoo, dom, event
516  */
517
518 /**
519  * Element provides an wrapper object to simplify adding
520  * event listeners, using dom methods, and managing attributes. 
521  * @class Element
522  * @uses YAHOO.util.AttributeProvider
523  * @constructor
524  * @param el {HTMLElement | String} The html element that 
525  * represents the Element.
526  * @param {Object} map A key-value map of initial config names and values
527  */
528 var Element = function(el, map) {
529     this.init.apply(this, arguments);
530 };
531
532 Element.DOM_EVENTS = {
533     'click': true,
534     'dblclick': true,
535     'keydown': true,
536     'keypress': true,
537     'keyup': true,
538     'mousedown': true,
539     'mousemove': true,
540     'mouseout': true, 
541     'mouseover': true, 
542     'mouseup': true,
543     'mouseenter': true, 
544     'mouseleave': true,
545     'focus': true,
546     'blur': true,
547     'submit': true,
548     'change': true
549 };
550
551 Element.prototype = {
552     /**
553      * Dom events supported by the Element instance.
554      * @property DOM_EVENTS
555      * @type Object
556      */
557     DOM_EVENTS: null,
558
559     DEFAULT_HTML_SETTER: function(value, key) {
560         var el = this.get('element');
561         
562         if (el) {
563             el[key] = value;
564         }
565
566                 return value;
567
568     },
569
570     DEFAULT_HTML_GETTER: function(key) {
571         var el = this.get('element'),
572             val;
573
574         if (el) {
575             val = el[key];
576         }
577
578         return val;
579     },
580
581     /**
582      * Wrapper for HTMLElement method.
583      * @method appendChild
584      * @param {YAHOO.util.Element || HTMLElement} child The element to append. 
585      * @return {HTMLElement} The appended DOM element. 
586      */
587     appendChild: function(child) {
588         child = child.get ? child.get('element') : child;
589         return this.get('element').appendChild(child);
590     },
591     
592     /**
593      * Wrapper for HTMLElement method.
594      * @method getElementsByTagName
595      * @param {String} tag The tagName to collect
596      * @return {HTMLCollection} A collection of DOM elements. 
597      */
598     getElementsByTagName: function(tag) {
599         return this.get('element').getElementsByTagName(tag);
600     },
601     
602     /**
603      * Wrapper for HTMLElement method.
604      * @method hasChildNodes
605      * @return {Boolean} Whether or not the element has childNodes
606      */
607     hasChildNodes: function() {
608         return this.get('element').hasChildNodes();
609     },
610     
611     /**
612      * Wrapper for HTMLElement method.
613      * @method insertBefore
614      * @param {HTMLElement} element The HTMLElement to insert
615      * @param {HTMLElement} before The HTMLElement to insert
616      * the element before.
617      * @return {HTMLElement} The inserted DOM element. 
618      */
619     insertBefore: function(element, before) {
620         element = element.get ? element.get('element') : element;
621         before = (before && before.get) ? before.get('element') : before;
622         
623         return this.get('element').insertBefore(element, before);
624     },
625     
626     /**
627      * Wrapper for HTMLElement method.
628      * @method removeChild
629      * @param {HTMLElement} child The HTMLElement to remove
630      * @return {HTMLElement} The removed DOM element. 
631      */
632     removeChild: function(child) {
633         child = child.get ? child.get('element') : child;
634         return this.get('element').removeChild(child);
635     },
636     
637     /**
638      * Wrapper for HTMLElement method.
639      * @method replaceChild
640      * @param {HTMLElement} newNode The HTMLElement to insert
641      * @param {HTMLElement} oldNode The HTMLElement to replace
642      * @return {HTMLElement} The replaced DOM element. 
643      */
644     replaceChild: function(newNode, oldNode) {
645         newNode = newNode.get ? newNode.get('element') : newNode;
646         oldNode = oldNode.get ? oldNode.get('element') : oldNode;
647         return this.get('element').replaceChild(newNode, oldNode);
648     },
649
650     
651     /**
652      * Registers Element specific attributes.
653      * @method initAttributes
654      * @param {Object} map A key-value map of initial attribute configs
655      */
656     initAttributes: function(map) {
657     },
658
659     /**
660      * Adds a listener for the given event.  These may be DOM or 
661      * customEvent listeners.  Any event that is fired via fireEvent
662      * can be listened for.  All handlers receive an event object. 
663      * @method addListener
664      * @param {String} type The name of the event to listen for
665      * @param {Function} fn The handler to call when the event fires
666      * @param {Any} obj A variable to pass to the handler
667      * @param {Object} scope The object to use for the scope of the handler 
668      */
669     addListener: function(type, fn, obj, scope) {
670
671         scope = scope || this;
672
673         var Event = YAHOO.util.Event,
674                         el = this.get('element') || this.get('id'),
675                 self = this;
676
677
678                 if (specialTypes[type] && !Event._createMouseDelegate) {
679                 return false;   
680                 }
681
682
683         if (!this._events[type]) { // create on the fly
684
685             if (el && this.DOM_EVENTS[type]) {
686                                 Event.on(el, type, function(e, matchedEl) {
687
688                                         // Supplement IE with target, currentTarget relatedTarget
689
690                         if (e.srcElement && !e.target) { 
691                             e.target = e.srcElement;
692                         }
693
694                                         if ((e.toElement && !e.relatedTarget) || (e.fromElement && !e.relatedTarget)) {
695                                                 e.relatedTarget = Event.getRelatedTarget(e);
696                                         }
697                                         
698                                         if (!e.currentTarget) {
699                                                 e.currentTarget = el;
700                                         }
701
702                                         //      Note: matchedEl el is passed back for delegated listeners
703                             self.fireEvent(type, e, matchedEl);
704
705                         }, obj, scope);
706             }
707             this.createEvent(type, {scope: this});
708         }
709         
710         return YAHOO.util.EventProvider.prototype.subscribe.apply(this, arguments); // notify via customEvent
711     },
712
713
714     /**
715      * Alias for addListener
716      * @method on
717      * @param {String} type The name of the event to listen for
718      * @param {Function} fn The function call when the event fires
719      * @param {Any} obj A variable to pass to the handler
720      * @param {Object} scope The object to use for the scope of the handler 
721      */
722     on: function() {
723         return this.addListener.apply(this, arguments);
724     },
725     
726     /**
727      * Alias for addListener
728      * @method subscribe
729      * @param {String} type The name of the event to listen for
730      * @param {Function} fn The function call when the event fires
731      * @param {Any} obj A variable to pass to the handler
732      * @param {Object} scope The object to use for the scope of the handler 
733      */
734     subscribe: function() {
735         return this.addListener.apply(this, arguments);
736     },
737     
738     /**
739      * Remove an event listener
740      * @method removeListener
741      * @param {String} type The name of the event to listen for
742      * @param {Function} fn The function call when the event fires
743      */
744     removeListener: function(type, fn) {
745         return this.unsubscribe.apply(this, arguments);
746     },
747     
748     /**
749      * Wrapper for Dom method.
750      * @method addClass
751      * @param {String} className The className to add
752      */
753     addClass: function(className) {
754         Dom.addClass(this.get('element'), className);
755     },
756     
757     /**
758      * Wrapper for Dom method.
759      * @method getElementsByClassName
760      * @param {String} className The className to collect
761      * @param {String} tag (optional) The tag to use in
762      * conjunction with class name
763      * @return {Array} Array of HTMLElements
764      */
765     getElementsByClassName: function(className, tag) {
766         return Dom.getElementsByClassName(className, tag,
767                 this.get('element') );
768     },
769     
770     /**
771      * Wrapper for Dom method.
772      * @method hasClass
773      * @param {String} className The className to add
774      * @return {Boolean} Whether or not the element has the class name
775      */
776     hasClass: function(className) {
777         return Dom.hasClass(this.get('element'), className); 
778     },
779     
780     /**
781      * Wrapper for Dom method.
782      * @method removeClass
783      * @param {String} className The className to remove
784      */
785     removeClass: function(className) {
786         return Dom.removeClass(this.get('element'), className);
787     },
788     
789     /**
790      * Wrapper for Dom method.
791      * @method replaceClass
792      * @param {String} oldClassName The className to replace
793      * @param {String} newClassName The className to add
794      */
795     replaceClass: function(oldClassName, newClassName) {
796         return Dom.replaceClass(this.get('element'), 
797                 oldClassName, newClassName);
798     },
799     
800     /**
801      * Wrapper for Dom method.
802      * @method setStyle
803      * @param {String} property The style property to set
804      * @param {String} value The value to apply to the style property
805      */
806     setStyle: function(property, value) {
807         return Dom.setStyle(this.get('element'),  property, value); // TODO: always queuing?
808     },
809     
810     /**
811      * Wrapper for Dom method.
812      * @method getStyle
813      * @param {String} property The style property to retrieve
814      * @return {String} The current value of the property
815      */
816     getStyle: function(property) {
817         return Dom.getStyle(this.get('element'),  property);
818     },
819     
820     /**
821      * Apply any queued set calls.
822      * @method fireQueue
823      */
824     fireQueue: function() {
825         var queue = this._queue;
826         for (var i = 0, len = queue.length; i < len; ++i) {
827             this[queue[i][0]].apply(this, queue[i][1]);
828         }
829     },
830     
831     /**
832      * Appends the HTMLElement into either the supplied parentNode.
833      * @method appendTo
834      * @param {HTMLElement | Element} parentNode The node to append to
835      * @param {HTMLElement | Element} before An optional node to insert before
836      * @return {HTMLElement} The appended DOM element. 
837      */
838     appendTo: function(parent, before) {
839         parent = (parent.get) ?  parent.get('element') : Dom.get(parent);
840         
841         this.fireEvent('beforeAppendTo', {
842             type: 'beforeAppendTo',
843             target: parent
844         });
845         
846         
847         before = (before && before.get) ? 
848                 before.get('element') : Dom.get(before);
849         var element = this.get('element');
850         
851         if (!element) {
852             return false;
853         }
854         
855         if (!parent) {
856             return false;
857         }
858         
859         if (element.parent != parent) {
860             if (before) {
861                 parent.insertBefore(element, before);
862             } else {
863                 parent.appendChild(element);
864             }
865         }
866         
867         
868         this.fireEvent('appendTo', {
869             type: 'appendTo',
870             target: parent
871         });
872
873         return element;
874     },
875     
876     get: function(key) {
877         var configs = this._configs || {},
878             el = configs.element; // avoid loop due to 'element'
879
880         if (el && !configs[key] && !YAHOO.lang.isUndefined(el.value[key]) ) {
881             this._setHTMLAttrConfig(key);
882         }
883
884         return AttributeProvider.prototype.get.call(this, key);
885     },
886
887     setAttributes: function(map, silent) {
888         // set based on configOrder
889         var done = {},
890             configOrder = this._configOrder;
891
892         // set based on configOrder
893         for (var i = 0, len = configOrder.length; i < len; ++i) {
894             if (map[configOrder[i]] !== undefined) {
895                 done[configOrder[i]] = true;
896                 this.set(configOrder[i], map[configOrder[i]], silent);
897             }
898         }
899
900         // unconfigured (e.g. Dom attributes)
901         for (var att in map) {
902             if (map.hasOwnProperty(att) && !done[att]) {
903                 this.set(att, map[att], silent);
904             }
905         }
906     },
907
908     set: function(key, value, silent) {
909         var el = this.get('element');
910         if (!el) {
911             this._queue[this._queue.length] = ['set', arguments];
912             if (this._configs[key]) {
913                 this._configs[key].value = value; // so "get" works while queueing
914             
915             }
916             return;
917         }
918         
919         // set it on the element if not configured and is an HTML attribute
920         if ( !this._configs[key] && !YAHOO.lang.isUndefined(el[key]) ) {
921             this._setHTMLAttrConfig(key);
922         }
923
924         return AttributeProvider.prototype.set.apply(this, arguments);
925     },
926     
927     setAttributeConfig: function(key, map, init) {
928         this._configOrder.push(key);
929         AttributeProvider.prototype.setAttributeConfig.apply(this, arguments);
930     },
931
932     createEvent: function(type, config) {
933         this._events[type] = true;
934         return AttributeProvider.prototype.createEvent.apply(this, arguments);
935     },
936     
937     init: function(el, attr) {
938         this._initElement(el, attr); 
939     },
940
941     destroy: function() {
942         var el = this.get('element');
943         YAHOO.util.Event.purgeElement(el, true); // purge DOM listeners recursively
944         this.unsubscribeAll(); // unsubscribe all custom events
945
946         if (el && el.parentNode) {
947             el.parentNode.removeChild(el); // pull from the DOM
948         }
949
950         // revert initial configs
951         this._queue = [];
952         this._events = {};
953         this._configs = {};
954         this._configOrder = []; 
955     },
956
957     _initElement: function(el, attr) {
958         this._queue = this._queue || [];
959         this._events = this._events || {};
960         this._configs = this._configs || {};
961         this._configOrder = []; 
962         attr = attr || {};
963         attr.element = attr.element || el || null;
964
965         var isReady = false;  // to determine when to init HTMLElement and content
966
967         var DOM_EVENTS = Element.DOM_EVENTS;
968         this.DOM_EVENTS = this.DOM_EVENTS || {};
969
970         for (var event in DOM_EVENTS) {
971             if (DOM_EVENTS.hasOwnProperty(event)) {
972                 this.DOM_EVENTS[event] = DOM_EVENTS[event];
973             }
974         }
975
976         if (typeof attr.element === 'string') { // register ID for get() access
977             this._setHTMLAttrConfig('id', { value: attr.element });
978         }
979
980         if (Dom.get(attr.element)) {
981             isReady = true;
982             this._initHTMLElement(attr);
983             this._initContent(attr);
984         }
985
986         YAHOO.util.Event.onAvailable(attr.element, function() {
987             if (!isReady) { // otherwise already done
988                 this._initHTMLElement(attr);
989             }
990
991             this.fireEvent('available', { type: 'available', target: Dom.get(attr.element) });  
992         }, this, true);
993         
994         YAHOO.util.Event.onContentReady(attr.element, function() {
995             if (!isReady) { // otherwise already done
996                 this._initContent(attr);
997             }
998             this.fireEvent('contentReady', { type: 'contentReady', target: Dom.get(attr.element) });  
999         }, this, true);
1000     },
1001
1002     _initHTMLElement: function(attr) {
1003         /**
1004          * The HTMLElement the Element instance refers to.
1005          * @attribute element
1006          * @type HTMLElement
1007          */
1008         this.setAttributeConfig('element', {
1009             value: Dom.get(attr.element),
1010             readOnly: true
1011          });
1012     },
1013
1014     _initContent: function(attr) {
1015         this.initAttributes(attr);
1016         this.setAttributes(attr, true);
1017         this.fireQueue();
1018
1019     },
1020
1021     /**
1022      * Sets the value of the property and fires beforeChange and change events.
1023      * @private
1024      * @method _setHTMLAttrConfig
1025      * @param {YAHOO.util.Element} element The Element instance to
1026      * register the config to.
1027      * @param {String} key The name of the config to register
1028      * @param {Object} map A key-value map of the config's params
1029      */
1030     _setHTMLAttrConfig: function(key, map) {
1031         var el = this.get('element');
1032         map = map || {};
1033         map.name = key;
1034
1035         map.setter = map.setter || this.DEFAULT_HTML_SETTER;
1036         map.getter = map.getter || this.DEFAULT_HTML_GETTER;
1037
1038         map.value = map.value || el[key];
1039         this._configs[key] = new YAHOO.util.Attribute(map, this);
1040     }
1041 };
1042
1043 /**
1044  * Fires when the Element's HTMLElement can be retrieved by Id.
1045  * <p>See: <a href="#addListener">Element.addListener</a></p>
1046  * <p><strong>Event fields:</strong><br>
1047  * <code>&lt;String&gt; type</code> available<br>
1048  * <code>&lt;HTMLElement&gt;
1049  * target</code> the HTMLElement bound to this Element instance<br>
1050  * <p><strong>Usage:</strong><br>
1051  * <code>var handler = function(e) {var target = e.target};<br>
1052  * myTabs.addListener('available', handler);</code></p>
1053  * @event available
1054  */
1055  
1056 /**
1057  * Fires when the Element's HTMLElement subtree is rendered.
1058  * <p>See: <a href="#addListener">Element.addListener</a></p>
1059  * <p><strong>Event fields:</strong><br>
1060  * <code>&lt;String&gt; type</code> contentReady<br>
1061  * <code>&lt;HTMLElement&gt;
1062  * target</code> the HTMLElement bound to this Element instance<br>
1063  * <p><strong>Usage:</strong><br>
1064  * <code>var handler = function(e) {var target = e.target};<br>
1065  * myTabs.addListener('contentReady', handler);</code></p>
1066  * @event contentReady
1067  */
1068
1069 /**
1070  * Fires before the Element is appended to another Element.
1071  * <p>See: <a href="#addListener">Element.addListener</a></p>
1072  * <p><strong>Event fields:</strong><br>
1073  * <code>&lt;String&gt; type</code> beforeAppendTo<br>
1074  * <code>&lt;HTMLElement/Element&gt;
1075  * target</code> the HTMLElement/Element being appended to 
1076  * <p><strong>Usage:</strong><br>
1077  * <code>var handler = function(e) {var target = e.target};<br>
1078  * myTabs.addListener('beforeAppendTo', handler);</code></p>
1079  * @event beforeAppendTo
1080  */
1081
1082 /**
1083  * Fires after the Element is appended to another Element.
1084  * <p>See: <a href="#addListener">Element.addListener</a></p>
1085  * <p><strong>Event fields:</strong><br>
1086  * <code>&lt;String&gt; type</code> appendTo<br>
1087  * <code>&lt;HTMLElement/Element&gt;
1088  * target</code> the HTMLElement/Element being appended to 
1089  * <p><strong>Usage:</strong><br>
1090  * <code>var handler = function(e) {var target = e.target};<br>
1091  * myTabs.addListener('appendTo', handler);</code></p>
1092  * @event appendTo
1093  */
1094
1095 YAHOO.augment(Element, AttributeProvider);
1096 YAHOO.util.Element = Element;
1097 })();
1098
1099 YAHOO.register("element", YAHOO.util.Element, {version: "2.9.0", build: "2800"});