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