Automatic installer.php lang files by installer_builder (20070726)
[moodle-linuxchix.git] / lib / yui / tabview / tabview.js
blob8f5d4bb02bb2495e57779114471c38cbe319ccaf
1 /*
2 Copyright (c) 2006, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.net/yui/license.txt
5 version: 0.12.2
6 */
7 YAHOO.util.Lang = {
8     isArray: function(val) { // frames lose type, so test constructor string
9         if (val.constructor && val.constructor.toString().indexOf('Array') > -1) {
10             return true;
11         } else {
12             return YAHOO.util.Lang.isObject(val) && val.constructor == Array;
13         }
14     },
15         
16     isBoolean: function(val) {
17         return typeof val == 'boolean';
18     },
19     
20     isFunction: function(val) {
21         return typeof val == 'function';
22     },
23         
24     isNull: function(val) {
25         return val === null;
26     },
27         
28     isNumber: function(val) {
29         return !isNaN(val);
30     },
31         
32     isObject: function(val) {
33         return typeof val == 'object' || YAHOO.util.Lang.isFunction(val);
34     },
35         
36     isString: function(val) {
37         return typeof val == 'string';
38     },
39         
40     isUndefined: function(val) {
41         return typeof val == 'undefined';
42     }
45 /**
46  * Provides Attribute configurations.
47  * @namespace YAHOO.util
48  * @class Attribute
49  * @constructor
50  * @param hash {Object} The intial Attribute.
51  * @param {YAHOO.util.AttributeProvider} The owner of the Attribute instance.
52  */
54 YAHOO.util.Attribute = function(hash, owner) {
55     if (owner) { 
56         this.owner = owner;
57         this.configure(hash, true);
58     }
61 YAHOO.util.Attribute.prototype = {
62         /**
63      * The name of the attribute.
64          * @property name
65          * @type String
66          */
67     name: undefined,
68     
69         /**
70      * The value of the attribute.
71          * @property value
72          * @type String
73          */
74     value: null,
75     
76         /**
77      * The owner of the attribute.
78          * @property owner
79          * @type YAHOO.util.AttributeProvider
80          */
81     owner: null,
82     
83         /**
84      * Whether or not the attribute is read only.
85          * @property readOnly
86          * @type Boolean
87          */
88     readOnly: false,
89     
90         /**
91      * Whether or not the attribute can only be written once.
92          * @property writeOnce
93          * @type Boolean
94          */
95     writeOnce: false,
97         /**
98      * The attribute's initial configuration.
99      * @private
100          * @property _initialConfig
101          * @type Object
102          */
103     _initialConfig: null,
104     
105         /**
106      * Whether or not the attribute's value has been set.
107      * @private
108          * @property _written
109          * @type Boolean
110          */
111     _written: false,
112     
113         /**
114      * The method to use when setting the attribute's value.
115      * The method recieves the new value as the only argument.
116          * @property method
117          * @type Function
118          */
119     method: null,
120     
121         /**
122      * The validator to use when setting the attribute's value.
123          * @property validator
124          * @type Function
125      * @return Boolean
126          */
127     validator: null,
128     
129     /**
130      * Retrieves the current value of the attribute.
131      * @method getValue
132      * @return {any} The current value of the attribute.
133      */
134     getValue: function() {
135         return this.value;
136     },
137     
138     /**
139      * Sets the value of the attribute and fires beforeChange and change events.
140      * @method setValue
141      * @param {Any} value The value to apply to the attribute.
142      * @param {Boolean} silent If true the change events will not be fired.
143      * @return {Boolean} Whether or not the value was set.
144      */
145     setValue: function(value, silent) {
146         var beforeRetVal;
147         var owner = this.owner;
148         var name = this.name;
149         
150         var event = {
151             type: name, 
152             prevValue: this.getValue(),
153             newValue: value
154         };
155         
156         if (this.readOnly || ( this.writeOnce && this._written) ) {
157             return false; // write not allowed
158         }
159         
160         if (this.validator && !this.validator.call(owner, value) ) {
161             return false; // invalid value
162         }
164         if (!silent) {
165             beforeRetVal = owner.fireBeforeChangeEvent(event);
166             if (beforeRetVal === false) {
167                 return false;
168             }
169         }
171         if (this.method) {
172             this.method.call(owner, value);
173         }
174         
175         this.value = value;
176         this._written = true;
177         
178         event.type = name;
179         
180         if (!silent) {
181             this.owner.fireChangeEvent(event);
182         }
183         
184         return true;
185     },
186     
187     /**
188      * Allows for configuring the Attribute's properties.
189      * @method configure
190      * @param {Object} map A key-value map of Attribute properties.
191      * @param {Boolean} init Whether or not this should become the initial config.
192      */
193     configure: function(map, init) {
194         map = map || {};
195         this._written = false; // reset writeOnce
196         this._initialConfig = this._initialConfig || {};
197         
198         for (var key in map) {
199             if ( key && map.hasOwnProperty(key) ) {
200                 this[key] = map[key];
201                 if (init) {
202                     this._initialConfig[key] = map[key];
203                 }
204             }
205         }
206     },
207     
208     /**
209      * Resets the value to the initial config value.
210      * @method resetValue
211      * @return {Boolean} Whether or not the value was set.
212      */
213     resetValue: function() {
214         return this.setValue(this._initialConfig.value);
215     },
216     
217     /**
218      * Resets the attribute config to the initial config state.
219      * @method resetConfig
220      */
221     resetConfig: function() {
222         this.configure(this._initialConfig);
223     },
224     
225     /**
226      * Resets the value to the current value.
227      * Useful when values may have gotten out of sync with actual properties.
228      * @method refresh
229      * @return {Boolean} Whether or not the value was set.
230      */
231     refresh: function(silent) {
232         this.setValue(this.value, silent);
233     }
236 (function() {
237     var Lang = YAHOO.util.Lang;
239     /*
240     Copyright (c) 2006, Yahoo! Inc. All rights reserved.
241     Code licensed under the BSD License:
242     http://developer.yahoo.net/yui/license.txt
243     */
244     
245     /**
246      * Provides and manages YAHOO.util.Attribute instances
247      * @namespace YAHOO.util
248      * @class AttributeProvider
249      * @uses YAHOO.util.EventProvider
250      */
251     YAHOO.util.AttributeProvider = function() {};
252     
253     YAHOO.util.AttributeProvider.prototype = {
254         
255         /**
256          * A key-value map of Attribute configurations
257          * @property _configs
258          * @protected (may be used by subclasses and augmentors)
259          * @private
260          * @type {Object}
261          */
262         _configs: null,
263         /**
264          * Returns the current value of the attribute.
265          * @method get
266          * @param {String} key The attribute whose value will be returned.
267          */
268         get: function(key){
269             var configs = this._configs || {};
270             var config = configs[key];
271             
272             if (!config) {
273                 return undefined;
274             }
275             
276             return config.value;
277         },
278         
279         /**
280          * Sets the value of a config.
281          * @method set
282          * @param {String} key The name of the attribute
283          * @param {Any} value The value to apply to the attribute
284          * @param {Boolean} silent Whether or not to suppress change events
285          * @return {Boolean} Whether or not the value was set.
286          */
287         set: function(key, value, silent){
288             var configs = this._configs || {};
289             var config = configs[key];
290             
291             if (!config) {
292                 return false;
293             }
294             
295             return config.setValue(value, silent);
296         },
297     
298         /**
299          * Returns an array of attribute names.
300          * @method getAttributeKeys
301          * @return {Array} An array of attribute names.
302          */
303         getAttributeKeys: function(){
304             var configs = this._configs;
305             var keys = [];
306             var config;
307             for (var key in configs) {
308                 config = configs[key];
309                 if ( configs.hasOwnProperty(key) && 
310                         !Lang.isUndefined(config) ) {
311                     keys[keys.length] = key;
312                 }
313             }
314             
315             return keys;
316         },
317         
318         /**
319          * Sets multiple attribute values.
320          * @method setAttributes
321          * @param {Object} map  A key-value map of attributes
322          * @param {Boolean} silent Whether or not to suppress change events
323          */
324         setAttributes: function(map, silent){
325             for (var key in map) {
326                 if ( map.hasOwnProperty(key) ) {
327                     this.set(key, map[key], silent);
328                 }
329             }
330         },
331     
332         /**
333          * Resets the specified attribute's value to its initial value.
334          * @method resetValue
335          * @param {String} key The name of the attribute
336          * @param {Boolean} silent Whether or not to suppress change events
337          * @return {Boolean} Whether or not the value was set
338          */
339         resetValue: function(key, silent){
340             var configs = this._configs || {};
341             if (configs[key]) {
342                 this.set(key, configs[key]._initialConfig.value, silent);
343                 return true;
344             }
345             return false;
346         },
347     
348         /**
349          * Sets the attribute's value to its current value.
350          * @method refresh
351          * @param {String | Array} key The attribute(s) to refresh
352          * @param {Boolean} silent Whether or not to suppress change events
353          */
354         refresh: function(key, silent){
355             var configs = this._configs;
356             
357             key = ( ( Lang.isString(key) ) ? [key] : key ) || 
358                     this.getAttributeKeys();
359             
360             for (var i = 0, len = key.length; i < len; ++i) { 
361                 if ( // only set if there is a value and not null
362                     configs[key[i]] && 
363                     ! Lang.isUndefined(configs[key[i]].value) &&
364                     ! Lang.isNull(configs[key[i]].value) ) {
365                     configs[key[i]].refresh(silent);
366                 }
367             }
368         },
369     
370         /**
371          * Adds an Attribute to the AttributeProvider instance. 
372          * @method register
373          * @param {String} key The attribute's name
374          * @param {Object} map A key-value map containing the
375          * attribute's properties.
376          */
377         register: function(key, map) {
378             this._configs = this._configs || {};
379             
380             if (this._configs[key]) { // dont override
381                 return false;
382             }
383             
384             map.name = key;
385             this._configs[key] = new YAHOO.util.Attribute(map, this);
386             return true;
387         },
388         
389         /**
390          * Returns the attribute's properties.
391          * @method getAttributeConfig
392          * @param {String} key The attribute's name
393          * @private
394          * @return {object} A key-value map containing all of the
395          * attribute's properties.
396          */
397         getAttributeConfig: function(key) {
398             var configs = this._configs || {};
399             var config = configs[key] || {};
400             var map = {}; // returning a copy to prevent overrides
401             
402             for (key in config) {
403                 if ( config.hasOwnProperty(key) ) {
404                     map[key] = config[key];
405                 }
406             }
407     
408             return map;
409         },
410         
411         /**
412          * Sets or updates an Attribute instance's properties. 
413          * @method configureAttribute
414          * @param {String} key The attribute's name.
415          * @param {Object} map A key-value map of attribute properties
416          * @param {Boolean} init Whether or not this should become the intial config.
417          */
418         configureAttribute: function(key, map, init) {
419             var configs = this._configs || {};
420             
421             if (!configs[key]) {
422                 return false;
423             }
424             
425             configs[key].configure(map, init);
426         },
427         
428         /**
429          * Resets an attribute to its intial configuration. 
430          * @method resetAttributeConfig
431          * @param {String} key The attribute's name.
432          * @private
433          */
434         resetAttributeConfig: function(key){
435             var configs = this._configs || {};
436             configs[key].resetConfig();
437         },
438         
439         /**
440          * Fires the attribute's beforeChange event. 
441          * @method fireBeforeChangeEvent
442          * @param {String} key The attribute's name.
443          * @param {Obj} e The event object to pass to handlers.
444          */
445         fireBeforeChangeEvent: function(e) {
446             var type = 'before';
447             type += e.type.charAt(0).toUpperCase() + e.type.substr(1) + 'Change';
448             e.type = type;
449             return this.fireEvent(e.type, e);
450         },
451         
452         /**
453          * Fires the attribute's change event. 
454          * @method fireChangeEvent
455          * @param {String} key The attribute's name.
456          * @param {Obj} e The event object to pass to the handlers.
457          */
458         fireChangeEvent: function(e) {
459             e.type += 'Change';
460             return this.fireEvent(e.type, e);
461         }
462     };
463     
464     YAHOO.augment(YAHOO.util.AttributeProvider, YAHOO.util.EventProvider);
465 })();
467 (function() {
468 // internal shorthand
469 var Dom = YAHOO.util.Dom,
470     Lang = YAHOO.util.Lang,
471     EventPublisher = YAHOO.util.EventPublisher,
472     AttributeProvider = YAHOO.util.AttributeProvider;
475  * Element provides an interface to an HTMLElement's attributes and common
476  * methods.  Other commonly used attributes are added as well.
477  * @namespace YAHOO.util
478  * @class Element
479  * @uses YAHOO.util.AttributeProvider
480  * @constructor
481  * @param el {HTMLElement | String} The html element that 
482  * represents the Element.
483  * @param {Object} map A key-value map of initial config names and values
484  */
485 YAHOO.util.Element = function(el, map) {
486     if (arguments.length) {
487         this.init(el, map);
488     }
491 YAHOO.util.Element.prototype = {
492         /**
493      * Dom events supported by the Element instance.
494          * @property DOM_EVENTS
495          * @type Object
496          */
497     DOM_EVENTS: null,
499         /**
500      * Wrapper for HTMLElement method.
501          * @method appendChild
502          * @param {Boolean} deep Whether or not to do a deep clone
503          */
504     appendChild: function(child) {
505         child = child.get ? child.get('element') : child;
506         this.get('element').appendChild(child);
507     },
508     
509         /**
510      * Wrapper for HTMLElement method.
511          * @method getElementsByTagName
512          * @param {String} tag The tagName to collect
513          */
514     getElementsByTagName: function(tag) {
515         return this.get('element').getElementsByTagName(tag);
516     },
517     
518         /**
519      * Wrapper for HTMLElement method.
520          * @method hasChildNodes
521          * @return {Boolean} Whether or not the element has childNodes
522          */
523     hasChildNodes: function() {
524         return this.get('element').hasChildNodes();
525     },
526     
527         /**
528      * Wrapper for HTMLElement method.
529          * @method insertBefore
530          * @param {HTMLElement} element The HTMLElement to insert
531          * @param {HTMLElement} before The HTMLElement to insert
532      * the element before.
533          */
534     insertBefore: function(element, before) {
535         element = element.get ? element.get('element') : element;
536         before = (before && before.get) ? before.get('element') : before;
537         
538         this.get('element').insertBefore(element, before);
539     },
540     
541         /**
542      * Wrapper for HTMLElement method.
543          * @method removeChild
544          * @param {HTMLElement} child The HTMLElement to remove
545          */
546     removeChild: function(child) {
547         child = child.get ? child.get('element') : child;
548         this.get('element').removeChild(child);
549         return true;
550     },
551     
552         /**
553      * Wrapper for HTMLElement method.
554          * @method replaceChild
555          * @param {HTMLElement} newNode The HTMLElement to insert
556          * @param {HTMLElement} oldNode The HTMLElement to replace
557          */
558     replaceChild: function(newNode, oldNode) {
559         newNode = newNode.get ? newNode.get('element') : newNode;
560         oldNode = oldNode.get ? oldNode.get('element') : oldNode;
561         return this.get('element').replaceChild(newNode, oldNode);
562     },
564     
565     /**
566      * Registers Element specific attributes.
567      * @method initAttributes
568      * @param {Object} map A key-value map of initial attribute configs
569      */
570     initAttributes: function(map) {
571         map = map || {}; 
572         var element = Dom.get(map.element) || null;
573         
574         /**
575          * The HTMLElement the Element instance refers to.
576          * @config element
577          * @type HTMLElement
578          */
579         this.register('element', {
580             value: element,
581             readOnly: true
582          });
583     },
585     /**
586      * Adds a listener for the given event.  These may be DOM or 
587      * customEvent listeners.  Any event that is fired via fireEvent
588      * can be listened for.  All handlers receive an event object. 
589      * @method addListener
590      * @param {String} type The name of the event to listen for
591      * @param {Function} fn The handler to call when the event fires
592      * @param {Any} obj A variable to pass to the handler
593      * @param {Object} scope The object to use for the scope of the handler 
594      */
595     addListener: function(type, fn, obj, scope) {
596         var el = this.get('element');
597         var scope = scope || this;
598         
599         el = this.get('id') || el;
600         
601         if (!this._events[type]) { // create on the fly
602             if ( this.DOM_EVENTS[type] ) {
603                 YAHOO.util.Event.addListener(el, type, function(e) {
604                     if (e.srcElement && !e.target) { // supplement IE with target
605                         e.target = e.srcElement;
606                     }
607                     this.fireEvent(type, e);
608                 }, obj, scope);
609             }
610             
611             this.createEvent(type, this);
612             this._events[type] = true;
613         }
614         
615         this.subscribe.apply(this, arguments); // notify via customEvent
616     },
617     
618     
619     /**
620      * Alias for addListener
621      * @method on
622      * @param {String} type The name of the event to listen for
623      * @param {Function} fn The function call when the event fires
624      * @param {Any} obj A variable to pass to the handler
625      * @param {Object} scope The object to use for the scope of the handler 
626      */
627     on: function() { this.addListener.apply(this, arguments); },
628     
629     
630     /**
631      * Remove an event listener
632      * @method removeListener
633      * @param {String} type The name of the event to listen for
634      * @param {Function} fn The function call when the event fires
635      */
636     removeListener: function(type, fn) {
637         this.unsubscribe.apply(this, arguments);
638     },
639     
640         /**
641      * Wrapper for Dom method.
642          * @method addClass
643          * @param {String} className The className to add
644          */
645     addClass: function(className) {
646         Dom.addClass(this.get('element'), className);
647     },
648     
649         /**
650      * Wrapper for Dom method.
651          * @method getElementsByClassName
652          * @param {String} className The className to collect
653          * @param {String} tag (optional) The tag to use in
654      * conjunction with class name
655      * @return {Array} Array of HTMLElements
656          */
657     getElementsByClassName: function(className, tag) {
658         return Dom.getElementsByClassName(className, tag,
659                 this.get('element') );
660     },
661     
662         /**
663      * Wrapper for Dom method.
664          * @method hasClass
665          * @param {String} className The className to add
666      * @return {Boolean} Whether or not the element has the class name
667          */
668     hasClass: function(className) {
669         return Dom.hasClass(this.get('element'), className); 
670     },
671     
672         /**
673      * Wrapper for Dom method.
674          * @method removeClass
675          * @param {String} className The className to remove
676          */
677     removeClass: function(className) {
678         return Dom.removeClass(this.get('element'), className);
679     },
680     
681         /**
682      * Wrapper for Dom method.
683          * @method replaceClass
684          * @param {String} oldClassName The className to replace
685          * @param {String} newClassName The className to add
686          */
687     replaceClass: function(oldClassName, newClassName) {
688         return Dom.replaceClass(this.get('element'), 
689                 oldClassName, newClassName);
690     },
691     
692         /**
693      * Wrapper for Dom method.
694          * @method setStyle
695          * @param {String} property The style property to set
696          * @param {String} value The value to apply to the style property
697          */
698     setStyle: function(property, value) {
699         return Dom.setStyle(this.get('element'),  property, value);
700     },
701     
702         /**
703      * Wrapper for Dom method.
704          * @method getStyle
705          * @param {String} property The style property to retrieve
706          * @return {String} The current value of the property
707          */
708     getStyle: function(property) {
709         return Dom.getStyle(this.get('element'),  property);
710     },
711     
712         /**
713      * Apply any queued set calls.
714          * @method fireQueue
715          */
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]);
720         }
721     },
722     
723         /**
724      * Appends the HTMLElement into either the supplied parentNode.
725          * @method appendTo
726          * @param {HTMLElement | Element} parentNode The node to append to
727          * @param {HTMLElement | Element} before An optional node to insert before
728          */
729     appendTo: function(parent, before) {
730         parent = (parent.get) ?  parent.get('element') : Dom.get(parent);
731         
732         before = (before && before.get) ? 
733                 before.get('element') : Dom.get(before);
734         var element = this.get('element');
735         
736         var newAddition =  !Dom.inDocument(element);
737         
738         if (!element) {
739             return false;
740         }
741         
742         if (!parent) {
743             return false;
744         }
745         
746         if (element.parent != parent) {
747             if (before) {
748                 parent.insertBefore(element, before);
749             } else {
750                 parent.appendChild(element);
751             }
752         }
753         
754         
755         if (!newAddition) {
756             return false; // note return; no refresh if in document
757         }
758         
759         // if a new addition, refresh HTMLElement any applied attributes
760         var keys = this.getAttributeKeys();
761         
762         for (var key in keys) { // only refresh HTMLElement attributes
763             if ( !Lang.isUndefined(element[key]) ) {
764                 this.refresh(key);
765             }
766         }
767     },
768     
769     get: function(key) {
770         var configs = this._configs || {};
771         var el = configs.element; // avoid loop due to 'element'
772         if (el && !configs[key] && !Lang.isUndefined(el.value[key]) ) {
773             return el.value[key];
774         }
776         return AttributeProvider.prototype.get.call(this, key);
777     },
779     set: function(key, value, silent) {
780         var el = this.get('element');
781         if (!el) {
782             this._queue[this._queue.length] = ['set', arguments];
783             return false;
784         }
785         
786         // set it on the element if not a property
787         if ( !this._configs[key] && !Lang.isUndefined(el[key]) ) {
788             _registerHTMLAttr.call(this, key);
789         }
791         return AttributeProvider.prototype.set.apply(this, arguments);
792     },
793     
794     register: function(key) { // protect html attributes
795         var configs = this._configs || {};
796         var element = this.get('element') || null;
797         
798         if ( element && !Lang.isUndefined(element[key]) ) {
799             return false;
800         }
801         
802         return AttributeProvider.prototype.register.apply(this, arguments);
803     },
804     
805     configureAttribute: function(property, map, init) { // protect html attributes
806         var el = this.get('element');
807         if (!el) {
808             this._queue[this._queue.length] = ['configureAttribute', arguments];
809             return;
810         }
811         
812         if (!this._configs[property] && !Lang.isUndefined(el[property]) ) {
813             _registerHTMLAttr.call(this, property, map);
814         }
815         
816         return AttributeProvider.prototype.configureAttribute.apply(this, arguments);
817     },
818     
819     getAttributeKeys: function() {
820         var el = this.get('element');
821         var keys = AttributeProvider.prototype.getAttributeKeys.call(this);
822         
823         //add any unconfigured element keys
824         for (var key in el) {
825             if (!this._configs[key]) {
826                 keys[key] = keys[key] || el[key];
827             }
828         }
829         
830         return keys;
831     },
832     
833     init: function(el, attr) {
834         this._queue = this._queue || [];
835         this._events = this._events || {};
836         this._configs = this._configs || {};
837         attr = attr || {};
838         attr.element = attr.element || el || null;
840         this.DOM_EVENTS = {
841             'click': true,
842             'keydown': true,
843             'keypress': true,
844             'keyup': true,
845             'mousedown': true,
846             'mousemove': true,
847             'mouseout': true, 
848             'mouseover': true, 
849             'mouseup': true
850         };
851         
852         var readyHandler = function() {
853             this.initAttributes(attr);
855             this.setAttributes(attr, true);
856             this.fireQueue();
857             this.fireEvent('contentReady', {
858                 type: 'contentReady',
859                 target: attr.element
860             });
861         };
863         if ( Lang.isString(el) ) {
864             _registerHTMLAttr.call(this, 'id', { value: el });
865             YAHOO.util.Event.onAvailable(el, function() {
866                 attr.element = Dom.get(el);
867                 this.fireEvent('available', {
868                     type: 'available',
869                     target: attr.element
870                 }); 
871             }, this, true);
872             
873             YAHOO.util.Event.onContentReady(el, function() {
874                 readyHandler.call(this);
875             }, this, true);
876         } else {
877             readyHandler.call(this);
878         }        
879     }
883  * Sets the value of the property and fires beforeChange and change events.
884  * @private
885  * @method _registerHTMLAttr
886  * @param {YAHOO.util.Element} element The Element instance to
887  * register the config to.
888  * @param {String} key The name of the config to register
889  * @param {Object} map A key-value map of the config's params
890  */
891 var _registerHTMLAttr = function(key, map) {
892     var el = this.get('element');
893     map = map || {};
894     map.name = key;
895     map.method = map.method || function(value) {
896         el[key] = value;
897     };
898     map.value = map.value || el[key];
899     this._configs[key] = new YAHOO.util.Attribute(map, this);
903  * Fires when the Element's HTMLElement can be retrieved by Id.
904  * <p>See: <a href="#addListener">Element.addListener</a></p>
905  * <p><strong>Event fields:</strong><br>
906  * <code>&lt;String&gt; type</code> available<br>
907  * <code>&lt;HTMLElement&gt;
908  * target</code> the HTMLElement bound to this Element instance<br>
909  * <p><strong>Usage:</strong><br>
910  * <code>var handler = function(e) {var target = e.target};<br>
911  * myTabs.addListener('available', handler);</code></p>
912  * @event available
913  */
916  * Fires when the Element's HTMLElement subtree is rendered.
917  * <p>See: <a href="#addListener">Element.addListener</a></p>
918  * <p><strong>Event fields:</strong><br>
919  * <code>&lt;String&gt; type</code> contentReady<br>
920  * <code>&lt;HTMLElement&gt;
921  * target</code> the HTMLElement bound to this Element instance<br>
922  * <p><strong>Usage:</strong><br>
923  * <code>var handler = function(e) {var target = e.target};<br>
924  * myTabs.addListener('contentReady', handler);</code></p>
925  * @event contentReady
926  */
928 YAHOO.augment(YAHOO.util.Element, AttributeProvider);
929 })();
931 (function() {
932     var Dom = YAHOO.util.Dom,
933         Event = YAHOO.util.Event,
934         Lang = YAHOO.util.Lang;
935     
936     /**
937      * A representation of a Tab's label and content.
938      * @namespace YAHOO.widget
939      * @class Tab
940      * @extends YAHOO.util.Element
941      * @constructor
942      * @param element {HTMLElement | String} (optional) The html element that 
943      * represents the TabView. An element will be created if none provided.
944      * @param {Object} properties A key map of initial properties
945      */
946     var Tab = function(el, attr) {
947         attr = attr || {};
948         if (arguments.length == 1 && !Lang.isString(el) && !el.nodeName) {
949             attr = el;
950             el = attr.element;
951         }
953         if (!el && !attr.element) {
954             el = _createTabElement.call(this, attr);
955         }
957         this.loadHandler =  {
958             success: function(o) {
959                 this.set('content', o.responseText);
960             },
961             failure: function(o) {
962             }
963         };
964         
965         Tab.superclass.constructor.call(this, el, attr);
966         
967         this.DOM_EVENTS = {}; // delegating to tabView
968     };
970     YAHOO.extend(Tab, YAHOO.util.Element);
971     var proto = Tab.prototype;
972     
973     /**
974      * The default tag name for a Tab's inner element.
975      * @property LABEL_INNER_TAGNAME
976      * @type String
977      * @default "em"
978      */
979     proto.LABEL_TAGNAME = 'em';
980     
981     /**
982      * The class name applied to active tabs.
983      * @property ACTIVE_CLASSNAME
984      * @type String
985      * @default "on"
986      */
987     proto.ACTIVE_CLASSNAME = 'selected';
988     
989     /**
990      * The class name applied to disabled tabs.
991      * @property DISABLED_CLASSNAME
992      * @type String
993      * @default "disabled"
994      */
995     proto.DISABLED_CLASSNAME = 'disabled';
996     
997     /**
998      * The class name applied to dynamic tabs while loading.
999      * @property LOADING_CLASSNAME
1000      * @type String
1001      * @default "disabled"
1002      */
1003     proto.LOADING_CLASSNAME = 'loading';
1005     /**
1006      * Provides a reference to the connection request object when data is
1007      * loaded dynamically.
1008      * @property dataConnection
1009      * @type Object
1010      */
1011     proto.dataConnection = null;
1012     
1013     /**
1014      * Object containing success and failure callbacks for loading data.
1015      * @property loadHandler
1016      * @type object
1017      */
1018     proto.loadHandler = null;
1019     
1020     /**
1021      * Provides a readable name for the tab.
1022      * @method toString
1023      * @return String
1024      */
1025     proto.toString = function() {
1026         var el = this.get('element');
1027         var id = el.id || el.tagName;
1028         return "Tab " + id; 
1029     };
1030     
1031     /**
1032      * Registers TabView specific properties.
1033      * @method initAttributes
1034      * @param {Object} attr Hash of initial attributes
1035      */
1036     proto.initAttributes = function(attr) {
1037         attr = attr || {};
1038         Tab.superclass.initAttributes.call(this, attr);
1039         
1040         var el = this.get('element');
1041         
1042         /**
1043          * The event that triggers the tab's activation.
1044          * @config activationEvent
1045          * @type String
1046          */
1047         this.register('activationEvent', {
1048             value: attr.activationEvent || 'click'
1049         });        
1051         /**
1052          * The element that contains the tab's label.
1053          * @config labelEl
1054          * @type HTMLElement
1055          */
1056         this.register('labelEl', {
1057             value: attr.labelEl || _getlabelEl.call(this),
1058             method: function(value) {
1059                 var current = this.get('labelEl');
1061                 if (current) {
1062                     if (current == value) {
1063                         return false; // already set
1064                     }
1065                     
1066                     this.replaceChild(value, current);
1067                 } else if (el.firstChild) { // ensure label is firstChild by default
1068                     this.insertBefore(value, el.firstChild);
1069                 } else {
1070                     this.appendChild(value);
1071                 }  
1072             } 
1073         });
1075         /**
1076          * The tab's label text (or innerHTML).
1077          * @config label
1078          * @type String
1079          */
1080         this.register('label', {
1081             value: attr.label || _getLabel.call(this),
1082             method: function(value) {
1083                 var labelEl = this.get('labelEl');
1084                 if (!labelEl) { // create if needed
1085                     this.set('labelEl', _createlabelEl.call(this));
1086                 }
1087                 
1088                 _setLabel.call(this, value);
1089             }
1090         });
1091         
1092         /**
1093          * The HTMLElement that contains the tab's content.
1094          * @config contentEl
1095          * @type HTMLElement
1096          */
1097         this.register('contentEl', { // TODO: apply className?
1098             value: attr.contentEl || document.createElement('div'),
1099             method: function(value) {
1100                 var current = this.get('contentEl');
1102                 if (current) {
1103                     if (current == value) {
1104                         return false; // already set
1105                     }
1106                     this.replaceChild(value, current);
1107                 }
1108             }
1109         });
1110         
1111         /**
1112          * The tab's content.
1113          * @config content
1114          * @type String
1115          */
1116         this.register('content', {
1117             value: attr.content, // TODO: what about existing?
1118             method: function(value) {
1119                 this.get('contentEl').innerHTML = value;
1120             }
1121         });
1123         var _dataLoaded = false;
1124         
1125         /**
1126          * The tab's data source, used for loading content dynamically.
1127          * @config dataSrc
1128          * @type String
1129          */
1130         this.register('dataSrc', {
1131             value: attr.dataSrc
1132         });
1133         
1134         /**
1135          * Whether or not content should be reloaded for every view.
1136          * @config cacheData
1137          * @type Boolean
1138          * @default false
1139          */
1140         this.register('cacheData', {
1141             value: attr.cacheData || false,
1142             validator: Lang.isBoolean
1143         });
1144         
1145         /**
1146          * The method to use for the data request.
1147          * @config loadMethod
1148          * @type String
1149          * @default "GET"
1150          */
1151         this.register('loadMethod', {
1152             value: attr.loadMethod || 'GET',
1153             validator: Lang.isString
1154         });
1156         /**
1157          * Whether or not any data has been loaded from the server.
1158          * @config dataLoaded
1159          * @type Boolean
1160          */        
1161         this.register('dataLoaded', {
1162             value: false,
1163             validator: Lang.isBoolean,
1164             writeOnce: true
1165         });
1166         
1167         /**
1168          * Number if milliseconds before aborting and calling failure handler.
1169          * @config dataTimeout
1170          * @type Number
1171          * @default null
1172          */
1173         this.register('dataTimeout', {
1174             value: attr.dataTimeout || null,
1175             validator: Lang.isNumber
1176         });
1177         
1178         /**
1179          * Whether or not the tab is currently active.
1180          * If a dataSrc is set for the tab, the content will be loaded from
1181          * the given source.
1182          * @config active
1183          * @type Boolean
1184          */
1185         this.register('active', {
1186             value: attr.active || this.hasClass(this.ACTIVE_CLASSNAME),
1187             method: function(value) {
1188                 if (value === true) {
1189                     this.addClass(this.ACTIVE_CLASSNAME);
1190                     this.set('title', 'active');
1191                 } else {
1192                     this.removeClass(this.ACTIVE_CLASSNAME);
1193                     this.set('title', '');
1194                 }
1195             },
1196             validator: function(value) {
1197                 return Lang.isBoolean(value) && !this.get('disabled') ;
1198             }
1199         });
1200         
1201         /**
1202          * Whether or not the tab is disabled.
1203          * @config disabled
1204          * @type Boolean
1205          */
1206         this.register('disabled', {
1207             value: attr.disabled || this.hasClass(this.DISABLED_CLASSNAME),
1208             method: function(value) {
1209                 if (value === true) {
1210                     Dom.addClass(this.get('element'), this.DISABLED_CLASSNAME);
1211                 } else {
1212                     Dom.removeClass(this.get('element'), this.DISABLED_CLASSNAME);
1213                 }
1214             },
1215             validator: Lang.isBoolean
1216         });
1217         
1218         /**
1219          * The href of the tab's anchor element.
1220          * @config href
1221          * @type String
1222          * @default '#'
1223          */
1224         this.register('href', {
1225             value: attr.href || '#',
1226             method: function(value) {
1227                 this.getElementsByTagName('a')[0].href = value;
1228             },
1229             validator: Lang.isString
1230         });
1231         
1232         /**
1233          * The Whether or not the tab's content is visible.
1234          * @config contentVisible
1235          * @type Boolean
1236          * @default false
1237          */
1238         this.register('contentVisible', {
1239             value: attr.contentVisible,
1240             method: function(value) {
1241                 if (value == true) {
1242                     this.get('contentEl').style.display = 'block';
1243                     
1244                     if ( this.get('dataSrc') ) {
1245                      // load dynamic content unless already loaded and caching
1246                         if ( !this.get('dataLoaded') || !this.get('cacheData') ) {
1247                             _dataConnect.call(this);
1248                         }
1249                     }
1250                 } else {
1251                     this.get('contentEl').style.display = 'none';
1252                 }
1253             },
1254             validator: Lang.isBoolean
1255         });
1256     };
1257     
1258     var _createTabElement = function(attr) {
1259         var el = document.createElement('li');
1260         var a = document.createElement('a');
1261         
1262         a.href = attr.href || '#';
1263         
1264         el.appendChild(a);
1265         
1266         var label = attr.label || null;
1267         var labelEl = attr.labelEl || null;
1268         
1269         if (labelEl) { // user supplied labelEl
1270             if (!label) { // user supplied label
1271                 label = _getLabel.call(this, labelEl);
1272             }
1273         } else {
1274             labelEl = _createlabelEl.call(this);
1275         }
1276         
1277         a.appendChild(labelEl);
1278         
1279         return el;
1280     };
1281     
1282     var _getlabelEl = function() {
1283         return this.getElementsByTagName(this.LABEL_TAGNAME)[0];
1284     };
1285     
1286     var _createlabelEl = function() {
1287         var el = document.createElement(this.LABEL_TAGNAME);
1288         return el;
1289     };
1290     
1291     var _setLabel = function(label) {
1292         var el = this.get('labelEl');
1293         el.innerHTML = label;
1294     };
1295     
1296     var _getLabel = function() {
1297         var label,
1298             el = this.get('labelEl');
1299             
1300             if (!el) {
1301                 return undefined;
1302             }
1303         
1304         return el.innerHTML;
1305     };
1306     
1307     var _dataConnect = function() {
1308         if (!YAHOO.util.Connect) {
1309             return false;
1310         }
1312         Dom.addClass(this.get('contentEl').parentNode, this.LOADING_CLASSNAME);
1313         
1314         this.dataConnection = YAHOO.util.Connect.asyncRequest(
1315             this.get('loadMethod'),
1316             this.get('dataSrc'), 
1317             {
1318                 success: function(o) {
1319                     this.loadHandler.success.call(this, o);
1320                     this.set('dataLoaded', true);
1321                     this.dataConnection = null;
1322                     Dom.removeClass(this.get('contentEl').parentNode,
1323                             this.LOADING_CLASSNAME);
1324                 },
1325                 failure: function(o) {
1326                     this.loadHandler.failure.call(this, o);
1327                     this.dataConnection = null;
1328                     Dom.removeClass(this.get('contentEl').parentNode,
1329                             this.LOADING_CLASSNAME);
1330                 },
1331                 scope: this,
1332                 timeout: this.get('dataTimeout')
1333             }
1334         );
1335     };
1336     
1337     YAHOO.widget.Tab = Tab;
1338     
1339     /**
1340      * Fires before the active state is changed.
1341      * <p>See: <a href="YAHOO.util.Element.html#addListener">Element.addListener</a></p>
1342      * <p>If handler returns false, the change will be cancelled, and the value will not
1343      * be set.</p>
1344      * <p><strong>Event fields:</strong><br>
1345      * <code>&lt;String&gt; type</code> beforeActiveChange<br>
1346      * <code>&lt;Boolean&gt;
1347      * prevValue</code> the current value<br>
1348      * <code>&lt;Boolean&gt;
1349      * newValue</code> the new value</p>
1350      * <p><strong>Usage:</strong><br>
1351      * <code>var handler = function(e) {var previous = e.prevValue};<br>
1352      * myTabs.addListener('beforeActiveChange', handler);</code></p>
1353      * @event beforeActiveChange
1354      */
1355         
1356     /**
1357      * Fires after the active state is changed.
1358      * <p>See: <a href="YAHOO.util.Element.html#addListener">Element.addListener</a></p>
1359      * <p><strong>Event fields:</strong><br>
1360      * <code>&lt;String&gt; type</code> activeChange<br>
1361      * <code>&lt;Boolean&gt;
1362      * prevValue</code> the previous value<br>
1363      * <code>&lt;Boolean&gt;
1364      * newValue</code> the updated value</p>
1365      * <p><strong>Usage:</strong><br>
1366      * <code>var handler = function(e) {var previous = e.prevValue};<br>
1367      * myTabs.addListener('activeChange', handler);</code></p>
1368      * @event activeChange
1369      */
1370      
1371     /**
1372      * Fires before the tab label is changed.
1373      * <p>See: <a href="YAHOO.util.Element.html#addListener">Element.addListener</a></p>
1374      * <p>If handler returns false, the change will be cancelled, and the value will not
1375      * be set.</p>
1376      * <p><strong>Event fields:</strong><br>
1377      * <code>&lt;String&gt; type</code> beforeLabelChange<br>
1378      * <code>&lt;String&gt;
1379      * prevValue</code> the current value<br>
1380      * <code>&lt;String&gt;
1381      * newValue</code> the new value</p>
1382      * <p><strong>Usage:</strong><br>
1383      * <code>var handler = function(e) {var previous = e.prevValue};<br>
1384      * myTabs.addListener('beforeLabelChange', handler);</code></p>
1385      * @event beforeLabelChange
1386      */
1387         
1388     /**
1389      * Fires after the tab label is changed.
1390      * <p>See: <a href="YAHOO.util.Element.html#addListener">Element.addListener</a></p>
1391      * <p><strong>Event fields:</strong><br>
1392      * <code>&lt;String&gt; type</code> labelChange<br>
1393      * <code>&lt;String&gt;
1394      * prevValue</code> the previous value<br>
1395      * <code>&lt;String&gt;
1396      * newValue</code> the updated value</p>
1397      * <p><strong>Usage:</strong><br>
1398      * <code>var handler = function(e) {var previous = e.prevValue};<br>
1399      * myTabs.addListener('labelChange', handler);</code></p>
1400      * @event labelChange
1401      */
1402      
1403     /**
1404      * Fires before the tab content is changed.
1405      * <p>See: <a href="YAHOO.util.Element.html#addListener">Element.addListener</a></p>
1406      * <p>If handler returns false, the change will be cancelled, and the value will not
1407      * be set.</p>
1408      * <p><strong>Event fields:</strong><br>
1409      * <code>&lt;String&gt; type</code> beforeContentChange<br>
1410      * <code>&lt;String&gt;
1411      * prevValue</code> the current value<br>
1412      * <code>&lt;String&gt;
1413      * newValue</code> the new value</p>
1414      * <p><strong>Usage:</strong><br>
1415      * <code>var handler = function(e) {var previous = e.prevValue};<br>
1416      * myTabs.addListener('beforeContentChange', handler);</code></p>
1417      * @event beforeContentChange
1418      */
1419         
1420     /**
1421      * Fires after the tab content is changed.
1422      * <p>See: <a href="YAHOO.util.Element.html#addListener">Element.addListener</a></p>
1423      * <p><strong>Event fields:</strong><br>
1424      * <code>&lt;String&gt; type</code> contentChange<br>
1425      * <code>&lt;String&gt;
1426      * prevValue</code> the previous value<br>
1427      * <code>&lt;Boolean&gt;
1428      * newValue</code> the updated value</p>
1429      * <p><strong>Usage:</strong><br>
1430      * <code>var handler = function(e) {var previous = e.prevValue};<br>
1431      * myTabs.addListener('contentChange', handler);</code></p>
1432      * @event contentChange
1433      */
1434 })();
1436 (function() {
1438     /**
1439      * The tabview module provides a widget for managing content bound to tabs.
1440      * @module tabview
1441      * @requires yahoo, dom, event
1442      *
1443      */
1444     /**
1445      * A widget to control tabbed views.
1446      * @namespace YAHOO.widget
1447      * @class TabView
1448      * @extends YAHOO.util.Element
1449      * @constructor
1450      * @param {HTMLElement | String | Object} el(optional) The html 
1451      * element that represents the TabView, or the attribute object to use. 
1452      * An element will be created if none provided.
1453      * @param {Object} attr (optional) A key map of the tabView's 
1454      * initial attributes.  Ignored if first arg is attributes object.
1455      */
1456     YAHOO.widget.TabView = function(el, attr) {
1457         attr = attr || {};
1458         if (arguments.length == 1 && !Lang.isString(el) && !el.nodeName) {
1459             attr = el; // treat first arg as attr object
1460             el = attr.element || null;
1461         }
1462         
1463         if (!el && !attr.element) { // create if we dont have one
1464             el = _createTabViewElement.call(this, attr);
1465         }
1466         YAHOO.widget.TabView.superclass.constructor.call(this, el, attr); 
1467     };
1469     YAHOO.extend(YAHOO.widget.TabView, YAHOO.util.Element);
1470     
1471     var proto = YAHOO.widget.TabView.prototype;
1472     var Dom = YAHOO.util.Dom;
1473     var Lang = YAHOO.util.Lang;
1474     var Event = YAHOO.util.Event;
1475     var Tab = YAHOO.widget.Tab;
1476     
1477     
1478     /**
1479      * The className to add when building from scratch. 
1480      * @property CLASSNAME
1481      * @default "navset"
1482      */
1483     proto.CLASSNAME = 'yui-navset';
1484     
1485     /**
1486      * The className of the HTMLElement containing the TabView's tab elements
1487      * to look for when building from existing markup, or to add when building
1488      * from scratch. 
1489      * All childNodes of the tab container are treated as Tabs when building
1490      * from existing markup.
1491      * @property TAB_PARENT_CLASSNAME
1492      * @default "nav"
1493      */
1494     proto.TAB_PARENT_CLASSNAME = 'yui-nav';
1495     
1496     /**
1497      * The className of the HTMLElement containing the TabView's label elements
1498      * to look for when building from existing markup, or to add when building
1499      * from scratch. 
1500      * All childNodes of the content container are treated as content elements when
1501      * building from existing markup.
1502      * @property CONTENT_PARENT_CLASSNAME
1503      * @default "nav-content"
1504      */
1505     proto.CONTENT_PARENT_CLASSNAME = 'yui-content';
1506     
1507     proto._tabParent = null;
1508     proto._contentParent = null; 
1509     
1510     /**
1511      * Adds a Tab to the TabView instance.  
1512      * If no index is specified, the tab is added to the end of the tab list.
1513      * @method addTab
1514      * @param {YAHOO.widget.Tab} tab A Tab instance to add.
1515      * @param {Integer} index The position to add the tab. 
1516      * @return void
1517      */
1518     proto.addTab = function(tab, index) {
1519         var tabs = this.get('tabs');
1520         if (!tabs) { // not ready yet
1521             this._queue[this._queue.length] = ['addTab', arguments];
1522             return false;
1523         }
1524         
1525         index = (index === undefined) ? tabs.length : index;
1526         
1527         var before = this.getTab(index);
1528         
1529         var self = this;
1530         var el = this.get('element');
1531         var tabParent = this._tabParent;
1532         var contentParent = this._contentParent;
1534         var tabElement = tab.get('element');
1535         var contentEl = tab.get('contentEl');
1537         if ( before ) {
1538             tabParent.insertBefore(tabElement, before.get('element'));
1539         } else {
1540             tabParent.appendChild(tabElement);
1541         }
1543         if ( contentEl && !Dom.isAncestor(contentParent, contentEl) ) {
1544             contentParent.appendChild(contentEl);
1545         }
1546         
1547         if ( !tab.get('active') ) {
1548             tab.set('contentVisible', false, true); /* hide if not active */
1549         } else {
1550             this.set('activeTab', tab, true);
1551             
1552         }
1554         var activate = function(e) {
1555             YAHOO.util.Event.preventDefault(e);
1556             self.set('activeTab', this);
1557         };
1558         
1559         tab.addListener( tab.get('activationEvent'), activate);
1560         
1561         tab.addListener('activationEventChange', function(e) {
1562             if (e.prevValue != e.newValue) {
1563                 tab.removeListener(e.prevValue, activate);
1564                 tab.addListener(e.newValue, activate);
1565             }
1566         });
1567         
1568         tabs.splice(index, 0, tab);
1569     };
1571     /**
1572      * Routes childNode events.
1573      * @method DOMEventHandler
1574      * @param {event} e The Dom event that is being handled.
1575      * @return void
1576      */
1577     proto.DOMEventHandler = function(e) {
1578         var el = this.get('element');
1579         var target = YAHOO.util.Event.getTarget(e);
1580         var tabParent = this._tabParent;
1581         
1582         if (Dom.isAncestor(tabParent, target) ) {
1583             var tabEl;
1584             var tab = null;
1585             var contentEl;
1586             var tabs = this.get('tabs');
1588             for (var i = 0, len = tabs.length; i < len; i++) {
1589                 tabEl = tabs[i].get('element');
1590                 contentEl = tabs[i].get('contentEl');
1592                 if ( target == tabEl || Dom.isAncestor(tabEl, target) ) {
1593                     tab = tabs[i];
1594                     break; // note break
1595                 }
1596             } 
1597             
1598             if (tab) {
1599                 tab.fireEvent(e.type, e);
1600             }
1601         }
1602     };
1603     
1604     /**
1605      * Returns the Tab instance at the specified index.
1606      * @method getTab
1607      * @param {Integer} index The position of the Tab.
1608      * @return YAHOO.widget.Tab
1609      */
1610     proto.getTab = function(index) {
1611         return this.get('tabs')[index];
1612     };
1613     
1614     /**
1615      * Returns the index of given tab.
1616      * @method getTabIndex
1617      * @param {YAHOO.widget.Tab} tab The tab whose index will be returned.
1618      * @return int
1619      */
1620     proto.getTabIndex = function(tab) {
1621         var index = null;
1622         var tabs = this.get('tabs');
1623         for (var i = 0, len = tabs.length; i < len; ++i) {
1624             if (tab == tabs[i]) {
1625                 index = i;
1626                 break;
1627             }
1628         }
1629         
1630         return index;
1631     };
1632     
1633     /**
1634      * Removes the specified Tab from the TabView.
1635      * @method removeTab
1636      * @param {YAHOO.widget.Tab} item The Tab instance to be removed.
1637      * @return void
1638      */
1639     proto.removeTab = function(tab) {
1640         var tabCount = this.get('tabs').length;
1642         var index = this.getTabIndex(tab);
1643         var nextIndex = index + 1;
1644         if ( tab == this.get('activeTab') ) { // select next tab
1645             if (tabCount > 1) {
1646                 if (index + 1 == tabCount) {
1647                     this.set('activeIndex', index - 1);
1648                 } else {
1649                     this.set('activeIndex', index + 1);
1650                 }
1651             }
1652         }
1653         
1654         this._tabParent.removeChild( tab.get('element') );
1655         this._contentParent.removeChild( tab.get('contentEl') );
1656         this._configs.tabs.value.splice(index, 1);
1657         
1658     };
1659     
1660     /**
1661      * Provides a readable name for the TabView instance.
1662      * @method toString
1663      * @return String
1664      */
1665     proto.toString = function() {
1666         var name = this.get('id') || this.get('tagName');
1667         return "TabView " + name; 
1668     };
1669     
1670     /**
1671      * The transiton to use when switching between tabs.
1672      * @method contentTransition
1673      */
1674     proto.contentTransition = function(newTab, oldTab) {
1675         newTab.set('contentVisible', true);
1676         oldTab.set('contentVisible', false);
1677     };
1678     
1679     /**
1680      * Registers TabView specific properties.
1681      * @method initAttributes
1682      * @param {Object} attr Hash of initial attributes
1683      */
1684     proto.initAttributes = function(attr) {
1685         YAHOO.widget.TabView.superclass.initAttributes.call(this, attr);
1686         
1687         if (!attr.orientation) {
1688             attr.orientation = 'top';
1689         }
1690         
1691         var el = this.get('element');
1692         
1693         /**
1694          * The Tabs belonging to the TabView instance.
1695          * @config tabs
1696          * @type Array
1697          */
1698         this.register('tabs', {
1699             value: [],
1700             readOnly: true
1701         });
1703         /**
1704          * The container of the tabView's label elements.
1705          * @property _tabParent
1706          * @private
1707          * @type HTMLElement
1708          */
1709         this._tabParent = 
1710                 this.getElementsByClassName(this.TAB_PARENT_CLASSNAME,
1711                         'ul' )[0] || _createTabParent.call(this);
1712             
1713         /**
1714          * The container of the tabView's content elements.
1715          * @property _contentParent
1716          * @type HTMLElement
1717          * @private
1718          */
1719         this._contentParent = 
1720                 this.getElementsByClassName(this.CONTENT_PARENT_CLASSNAME,
1721                         'div')[0] ||  _createContentParent.call(this);
1722         
1723         /**
1724          * How the Tabs should be oriented relative to the TabView.
1725          * @config orientation
1726          * @type String
1727          * @default "top"
1728          */
1729         this.register('orientation', {
1730             value: attr.orientation,
1731             method: function(value) {
1732                 var current = this.get('orientation');
1733                 this.addClass('yui-navset-' + value);
1734                 
1735                 if (current != value) {
1736                     this.removeClass('yui-navset-' + current);
1737                 }
1738                 
1739                 switch(value) {
1740                     case 'bottom':
1741                     this.appendChild(this._tabParent);
1742                     break;
1743                 }
1744             }
1745         });
1746         
1747         /**
1748          * The index of the tab currently active.
1749          * @config activeIndex
1750          * @type Int
1751          */
1752         this.register('activeIndex', {
1753             value: attr.activeIndex,
1754             method: function(value) {
1755                 this.set('activeTab', this.getTab(value));
1756             },
1757             validator: function(value) {
1758                 return !this.getTab(value).get('disabled'); // cannot activate if disabled
1759             }
1760         });
1761         
1762         /**
1763          * The tab currently active.
1764          * @config activeTab
1765          * @type YAHOO.widget.Tab
1766          */
1767         this.register('activeTab', {
1768             value: attr.activeTab,
1769             method: function(tab) {
1770                 var activeTab = this.get('activeTab');
1771                 
1772                 if (tab) {  
1773                     tab.set('active', true);
1774                 }
1775                 
1776                 if (activeTab && activeTab != tab) {
1777                     activeTab.set('active', false);
1778                 }
1779                 
1780                 if (activeTab && tab != activeTab) { // no transition if only 1
1781                     this.contentTransition(tab, activeTab);
1782                 } else if (tab) {
1783                     tab.set('contentVisible', true);
1784                 }
1785             },
1786             validator: function(value) {
1787                 return !value.get('disabled'); // cannot activate if disabled
1788             }
1789         });
1791         if ( this._tabParent ) {
1792             _initTabs.call(this);
1793         }
1794         
1795         for (var type in this.DOM_EVENTS) {
1796             if ( this.DOM_EVENTS.hasOwnProperty(type) ) {
1797                 this.addListener.call(this, type, this.DOMEventHandler);
1798             }
1799         }
1800     };
1801     
1802     /**
1803      * Creates Tab instances from a collection of HTMLElements.
1804      * @method createTabs
1805      * @private
1806      * @param {Array|HTMLCollection} elements The elements to use for Tabs.
1807      * @return void
1808      */
1809     var _initTabs = function() {
1810         var tab,
1811             attr,
1812             contentEl;
1813             
1814         var el = this.get('element');   
1815         var tabs = _getChildNodes(this._tabParent);
1816         var contentElements = _getChildNodes(this._contentParent);
1818         for (var i = 0, len = tabs.length; i < len; ++i) {
1819             attr = {};
1820             
1821             if (contentElements[i]) {
1822                 attr.contentEl = contentElements[i];
1823             }
1825             tab = new YAHOO.widget.Tab(tabs[i], attr);
1826             this.addTab(tab);
1827             
1828             if (tab.hasClass(tab.ACTIVE_CLASSNAME) ) {
1829                 this._configs.activeTab.value = tab; // dont invoke method
1830             }
1831         }
1832     };
1833     
1834     var _createTabViewElement = function(attr) {
1835         var el = document.createElement('div');
1837         if ( this.CLASSNAME ) {
1838             el.className = this.CLASSNAME;
1839         }
1840         
1841         return el;
1842     };
1843     
1844     var _createTabParent = function(attr) {
1845         var el = document.createElement('ul');
1847         if ( this.TAB_PARENT_CLASSNAME ) {
1848             el.className = this.TAB_PARENT_CLASSNAME;
1849         }
1850         
1851         this.get('element').appendChild(el);
1852         
1853         return el;
1854     };
1855     
1856     var _createContentParent = function(attr) {
1857         var el = document.createElement('div');
1859         if ( this.CONTENT_PARENT_CLASSNAME ) {
1860             el.className = this.CONTENT_PARENT_CLASSNAME;
1861         }
1862         
1863         this.get('element').appendChild(el);
1864         
1865         return el;
1866     };
1867     
1868     var _getChildNodes = function(el) {
1869         var nodes = [];
1870         var childNodes = el.childNodes;
1871         
1872         for (var i = 0, len = childNodes.length; i < len; ++i) {
1873             if (childNodes[i].nodeType == 1) {
1874                 nodes[nodes.length] = childNodes[i];
1875             }
1876         }
1877         
1878         return nodes;
1879     };
1882  * Fires before the activeTab is changed.
1883  * <p>See: <a href="YAHOO.util.Element.html#addListener">Element.addListener</a></p>
1884  * <p>If handler returns false, the change will be cancelled, and the value will not
1885  * be set.</p>
1886  * <p><strong>Event fields:</strong><br>
1887  * <code>&lt;String&gt; type</code> beforeActiveTabChange<br>
1888  * <code>&lt;<a href="YAHOO.widget.Tab.html">YAHOO.widget.Tab</a>&gt;
1889  * prevValue</code> the currently active tab<br>
1890  * <code>&lt;<a href="YAHOO.widget.Tab.html">YAHOO.widget.Tab</a>&gt;
1891  * newValue</code> the tab to be made active</p>
1892  * <p><strong>Usage:</strong><br>
1893  * <code>var handler = function(e) {var previous = e.prevValue};<br>
1894  * myTabs.addListener('beforeActiveTabChange', handler);</code></p>
1895  * @event beforeActiveTabChange
1896  */
1897     
1899  * Fires after the activeTab is changed.
1900  * <p>See: <a href="YAHOO.util.Element.html#addListener">Element.addListener</a></p>
1901  * <p><strong>Event fields:</strong><br>
1902  * <code>&lt;String&gt; type</code> activeTabChange<br>
1903  * <code>&lt;<a href="YAHOO.widget.Tab.html">YAHOO.widget.Tab</a>&gt;
1904  * prevValue</code> the formerly active tab<br>
1905  * <code>&lt;<a href="YAHOO.widget.Tab.html">YAHOO.widget.Tab</a>&gt;
1906  * newValue</code> the new active tab</p>
1907  * <p><strong>Usage:</strong><br>
1908  * <code>var handler = function(e) {var previous = e.prevValue};<br>
1909  * myTabs.addListener('activeTabChange', handler);</code></p>
1910  * @event activeTabChange
1911  */
1914  * Fires before the orientation is changed.
1915  * <p>See: <a href="YAHOO.util.Element.html#addListener">Element.addListener</a></p>
1916  * <p>If handler returns false, the change will be cancelled, and the value will not
1917  * be set.</p>
1918  * <p><strong>Event fields:</strong><br>
1919  * <code>&lt;String&gt; type</code> beforeOrientationChange<br>
1920  * <code>&lt;String&gt;
1921  * prevValue</code> the current orientation<br>
1922  * <code>&lt;String&gt;
1923  * newValue</code> the new orientation to be applied</p>
1924  * <p><strong>Usage:</strong><br>
1925  * <code>var handler = function(e) {var previous = e.prevValue};<br>
1926  * myTabs.addListener('beforeOrientationChange', handler);</code></p>
1927  * @event beforeOrientationChange
1928  */
1929     
1931  * Fires after the orientation is changed.
1932  * <p>See: <a href="YAHOO.util.Element.html#addListener">Element.addListener</a></p>
1933  * <p><strong>Event fields:</strong><br>
1934  * <code>&lt;String&gt; type</code> orientationChange<br>
1935  * <code>&lt;String&gt;
1936  * prevValue</code> the former orientation<br>
1937  * <code>&lt;String&gt;
1938  * newValue</code> the new orientation</p>
1939  * <p><strong>Usage:</strong><br>
1940  * <code>var handler = function(e) {var previous = e.prevValue};<br>
1941  * myTabs.addListener('orientationChange', handler);</code></p>
1942  * @event orientationChange
1943  */
1944 })();