]> ToastFreeware Gitweb - philipp/winterrodeln/wradmin.git/blob - wradmin/static/yui/tabview/tabview.js
Rename public directory to static.
[philipp/winterrodeln/wradmin.git] / wradmin / static / yui / tabview / tabview.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.7.0
6 */
7 (function() {
8
9     /**
10      * The tabview module provides a widget for managing content bound to tabs.
11      * @module tabview
12      * @requires yahoo, dom, event, element
13      *
14      */
15
16     var Y = YAHOO.util,
17         Dom = Y.Dom,
18         Event = Y.Event,
19         document = window.document,
20     
21         // STRING CONSTANTS
22         ACTIVE = 'active',
23         ACTIVE_INDEX = 'activeIndex',
24         ACTIVE_TAB = 'activeTab',
25         CONTENT_EL = 'contentEl',
26         ELEMENT = 'element',
27     
28     /**
29      * A widget to control tabbed views.
30      * @namespace YAHOO.widget
31      * @class TabView
32      * @extends YAHOO.util.Element
33      * @constructor
34      * @param {HTMLElement | String | Object} el(optional) The html 
35      * element that represents the TabView, or the attribute object to use. 
36      * An element will be created if none provided.
37      * @param {Object} attr (optional) A key map of the tabView's 
38      * initial attributes.  Ignored if first arg is attributes object.
39      */
40     TabView = function(el, attr) {
41         attr = attr || {};
42         if (arguments.length == 1 && !YAHOO.lang.isString(el) && !el.nodeName) {
43             attr = el; // treat first arg as attr object
44             el = attr.element || null;
45         }
46         
47         if (!el && !attr.element) { // create if we dont have one
48             el = this._createTabViewElement(attr);
49         }
50         TabView.superclass.constructor.call(this, el, attr); 
51     };
52
53     YAHOO.extend(TabView, Y.Element, {
54         /**
55          * The className to add when building from scratch. 
56          * @property CLASSNAME
57          * @default "navset"
58          */
59         CLASSNAME: 'yui-navset',
60         
61         /**
62          * The className of the HTMLElement containing the TabView's tab elements
63          * to look for when building from existing markup, or to add when building
64          * from scratch. 
65          * All childNodes of the tab container are treated as Tabs when building
66          * from existing markup.
67          * @property TAB_PARENT_CLASSNAME
68          * @default "nav"
69          */
70         TAB_PARENT_CLASSNAME: 'yui-nav',
71         
72         /**
73          * The className of the HTMLElement containing the TabView's label elements
74          * to look for when building from existing markup, or to add when building
75          * from scratch. 
76          * All childNodes of the content container are treated as content elements when
77          * building from existing markup.
78          * @property CONTENT_PARENT_CLASSNAME
79          * @default "nav-content"
80          */
81         CONTENT_PARENT_CLASSNAME: 'yui-content',
82         
83         _tabParent: null,
84         _contentParent: null,
85         
86         /**
87          * Adds a Tab to the TabView instance.  
88          * If no index is specified, the tab is added to the end of the tab list.
89          * @method addTab
90          * @param {YAHOO.widget.Tab} tab A Tab instance to add.
91          * @param {Integer} index The position to add the tab. 
92          * @return void
93          */
94         addTab: function(tab, index) {
95             var tabs = this.get('tabs'),
96                 before = this.getTab(index),
97                 tabParent = this._tabParent,
98                 contentParent = this._contentParent,
99                 tabElement = tab.get(ELEMENT),
100                 contentEl = tab.get(CONTENT_EL);
101
102             if (!tabs) { // not ready yet
103                 this._queue[this._queue.length] = ['addTab', arguments];
104                 return false;
105             }
106             
107             index = (index === undefined) ? tabs.length : index;
108             
109             if ( before ) {
110                 tabParent.insertBefore(tabElement, before.get(ELEMENT));
111             } else {
112                 tabParent.appendChild(tabElement);
113             }
114
115             if ( contentEl && !Dom.isAncestor(contentParent, contentEl) ) {
116                 contentParent.appendChild(contentEl);
117             }
118             
119             if ( !tab.get(ACTIVE) ) {
120                 tab.set('contentVisible', false, true); /* hide if not active */
121             } else {
122                 this.set(ACTIVE_TAB, tab, true);
123                 
124             }
125
126             this._initTabEvents(tab);
127             tabs.splice(index, 0, tab);
128         },
129
130         _initTabEvents: function(tab) {
131             tab.addListener( tab.get('activationEvent'), tab._onActivate, this, tab);
132             
133             tab.addListener('activationEventChange', function(e) {
134                 if (e.prevValue != e.newValue) {
135                     tab.removeListener(e.prevValue, tab._onActivate);
136                     tab.addListener(e.newValue, tab._onActivate, this, tab);
137                 }
138             });
139         },
140
141         /**
142          * Routes childNode events.
143          * @method DOMEventHandler
144          * @param {event} e The Dom event that is being handled.
145          * @return void
146          */
147         DOMEventHandler: function(e) {
148             var target = Event.getTarget(e),
149                 tabParent = this._tabParent,
150                 tabs = this.get('tabs'),
151                 tab,
152                 tabEl,
153                 contentEl;
154
155             
156             if (Dom.isAncestor(tabParent, target) ) {
157                 for (var i = 0, len = tabs.length; i < len; i++) {
158                     tabEl = tabs[i].get(ELEMENT);
159                     contentEl = tabs[i].get(CONTENT_EL);
160
161                     if ( target == tabEl || Dom.isAncestor(tabEl, target) ) {
162                         tab = tabs[i];
163                         break; // note break
164                     }
165                 } 
166                 
167                 if (tab) {
168                     tab.fireEvent(e.type, e);
169                 }
170             }
171         },
172         
173         /**
174          * Returns the Tab instance at the specified index.
175          * @method getTab
176          * @param {Integer} index The position of the Tab.
177          * @return YAHOO.widget.Tab
178          */
179         getTab: function(index) {
180             return this.get('tabs')[index];
181         },
182         
183         /**
184          * Returns the index of given tab.
185          * @method getTabIndex
186          * @param {YAHOO.widget.Tab} tab The tab whose index will be returned.
187          * @return int
188          */
189         getTabIndex: function(tab) {
190             var index = null,
191                 tabs = this.get('tabs');
192             for (var i = 0, len = tabs.length; i < len; ++i) {
193                 if (tab == tabs[i]) {
194                     index = i;
195                     break;
196                 }
197             }
198             
199             return index;
200         },
201         
202         /**
203          * Removes the specified Tab from the TabView.
204          * @method removeTab
205          * @param {YAHOO.widget.Tab} item The Tab instance to be removed.
206          * @return void
207          */
208         removeTab: function(tab) {
209             var tabCount = this.get('tabs').length,
210                 index = this.getTabIndex(tab);
211
212             if ( tab === this.get(ACTIVE_TAB) ) { 
213                 if (tabCount > 1) { // select another tab
214                     if (index + 1 === tabCount) { // if last, activate previous
215                         this.set(ACTIVE_INDEX, index - 1);
216                     } else { // activate next tab
217                         this.set(ACTIVE_INDEX, index + 1);
218                     }
219                 } else { // no more tabs
220                     this.set(ACTIVE_TAB, null);
221                 }
222             }
223             
224             this._tabParent.removeChild( tab.get(ELEMENT) );
225             this._contentParent.removeChild( tab.get(CONTENT_EL) );
226             this._configs.tabs.value.splice(index, 1);
227
228             tab.fireEvent('remove', { type: 'remove', tabview: this });
229         },
230         
231         /**
232          * Provides a readable name for the TabView instance.
233          * @method toString
234          * @return String
235          */
236         toString: function() {
237             var name = this.get('id') || this.get('tagName');
238             return "TabView " + name; 
239         },
240         
241         /**
242          * The transiton to use when switching between tabs.
243          * @method contentTransition
244          */
245         contentTransition: function(newTab, oldTab) {
246             if (newTab) {
247                 newTab.set('contentVisible', true);
248             }
249             if (oldTab) {
250                 oldTab.set('contentVisible', false);
251             }
252         },
253         
254         /**
255          * setAttributeConfigs TabView specific properties.
256          * @method initAttributes
257          * @param {Object} attr Hash of initial attributes
258          */
259         initAttributes: function(attr) {
260             TabView.superclass.initAttributes.call(this, attr);
261             
262             if (!attr.orientation) {
263                 attr.orientation = 'top';
264             }
265             
266             var el = this.get(ELEMENT);
267
268             if (!Dom.hasClass(el, this.CLASSNAME)) {
269                 Dom.addClass(el, this.CLASSNAME);        
270             }
271             
272             /**
273              * The Tabs belonging to the TabView instance.
274              * @attribute tabs
275              * @type Array
276              */
277             this.setAttributeConfig('tabs', {
278                 value: [],
279                 readOnly: true
280             });
281
282             /**
283              * The container of the tabView's label elements.
284              * @property _tabParent
285              * @private
286              * @type HTMLElement
287              */
288             this._tabParent = 
289                     this.getElementsByClassName(this.TAB_PARENT_CLASSNAME,
290                             'ul' )[0] || this._createTabParent();
291                 
292             /**
293              * The container of the tabView's content elements.
294              * @property _contentParent
295              * @type HTMLElement
296              * @private
297              */
298             this._contentParent = 
299                     this.getElementsByClassName(this.CONTENT_PARENT_CLASSNAME,
300                             'div')[0] ||  this._createContentParent();
301             
302             /**
303              * How the Tabs should be oriented relative to the TabView.
304              * @attribute orientation
305              * @type String
306              * @default "top"
307              */
308             this.setAttributeConfig('orientation', {
309                 value: attr.orientation,
310                 method: function(value) {
311                     var current = this.get('orientation');
312                     this.addClass('yui-navset-' + value);
313                     
314                     if (current != value) {
315                         this.removeClass('yui-navset-' + current);
316                     }
317                     
318                     if (value === 'bottom') {
319                         this.appendChild(this._tabParent);
320                     }
321                 }
322             });
323             
324             /**
325              * The index of the tab currently active.
326              * @attribute activeIndex
327              * @type Int
328              */
329             this.setAttributeConfig(ACTIVE_INDEX, {
330                 value: attr.activeIndex,
331                 method: function(value) {
332                 },
333                 validator: function(value) {
334                     var ret = true;
335                     if (value && this.getTab(value).get('disabled')) { // cannot activate if disabled
336                         ret = false;
337                     }
338                     return ret;
339                 }
340             });
341             
342             /**
343              * The tab currently active.
344              * @attribute activeTab
345              * @type YAHOO.widget.Tab
346              */
347             this.setAttributeConfig(ACTIVE_TAB, {
348                 value: attr.activeTab,
349                 method: function(tab) {
350                     var activeTab = this.get(ACTIVE_TAB);
351                     
352                     if (tab) {
353                         tab.set(ACTIVE, true);
354                     }
355                     
356                     if (activeTab && activeTab !== tab) {
357                         activeTab.set(ACTIVE, false);
358                     }
359                     
360                     if (activeTab && tab !== activeTab) { // no transition if only 1
361                         this.contentTransition(tab, activeTab);
362                     } else if (tab) {
363                         tab.set('contentVisible', true);
364                     }
365                 },
366                 validator: function(value) {
367                     var ret = true;
368                     if (value && value.get('disabled')) { // cannot activate if disabled
369                         ret = false;
370                     }
371                     return ret;
372                 }
373             });
374
375             this.on('activeTabChange', this._onActiveTabChange);
376             this.on('activeIndexChange', this._onActiveIndexChange);
377
378             if ( this._tabParent ) {
379                 this._initTabs();
380             }
381             
382             // Due to delegation we add all DOM_EVENTS to the TabView container
383             // but IE will leak when unsupported events are added, so remove these
384             this.DOM_EVENTS.submit = false;
385             this.DOM_EVENTS.focus = false;
386             this.DOM_EVENTS.blur = false;
387
388             for (var type in this.DOM_EVENTS) {
389                 if ( YAHOO.lang.hasOwnProperty(this.DOM_EVENTS, type) ) {
390                     this.addListener.call(this, type, this.DOMEventHandler);
391                 }
392             }
393         },
394
395         /**
396          * Removes selected state from the given tab if it is the activeTab
397          * @method deselectTab
398          * @param {Int} index The tab index to deselect 
399          */
400         deselectTab: function(index) {
401             if (this.getTab(index) === this.get('activeTab')) {
402                 this.set('activeTab', null);
403             }
404         },
405
406         /**
407          * Makes the tab at the given index the active tab
408          * @method selectTab
409          * @param {Int} index The tab index to be made active
410          */
411         selectTab: function(index) {
412             this.set('activeTab', this.getTab(index));
413         },
414
415         _onActiveTabChange: function(e) {
416             var activeIndex = this.get(ACTIVE_INDEX),
417                 newIndex = this.getTabIndex(e.newValue);
418
419             if (activeIndex !== newIndex) {
420                 if (!(this.set(ACTIVE_INDEX, newIndex)) ) { // NOTE: setting
421                      // revert if activeIndex update fails (cancelled via beforeChange) 
422                     this.set(ACTIVE_TAB, e.prevValue);
423                 }
424             }
425         },
426         
427         _onActiveIndexChange: function(e) {
428             // no set if called from ActiveTabChange event
429             if (e.newValue !== this.getTabIndex(this.get(ACTIVE_TAB))) {
430                 if (!(this.set(ACTIVE_TAB, this.getTab(e.newValue))) ) { // NOTE: setting
431                      // revert if activeTab update fails (cancelled via beforeChange) 
432                     this.set(ACTIVE_INDEX, e.prevValue);
433                 }
434             }
435         },
436
437         /**
438          * Creates Tab instances from a collection of HTMLElements.
439          * @method _initTabs
440          * @private
441          * @return void
442          */
443         _initTabs: function() {
444             var tabs = Dom.getChildren(this._tabParent),
445                 contentElements = Dom.getChildren(this._contentParent),
446                 activeIndex = this.get(ACTIVE_INDEX),
447                 tab,
448                 attr,
449                 active;
450
451             for (var i = 0, len = tabs.length; i < len; ++i) {
452                 attr = {};
453                 
454                 if (contentElements[i]) {
455                     attr.contentEl = contentElements[i];
456                 }
457
458                 tab = new YAHOO.widget.Tab(tabs[i], attr);
459                 this.addTab(tab);
460                 
461                 if (tab.hasClass(tab.ACTIVE_CLASSNAME) ) {
462                     active = tab;
463                 }
464             }
465             if (activeIndex) {
466                 this.set(ACTIVE_TAB, this.getTab(activeIndex));
467             } else {
468                 this._configs.activeTab.value = active; // dont invoke method
469                 this._configs.activeIndex.value = this.getTabIndex(active);
470             }
471         },
472
473         _createTabViewElement: function(attr) {
474             var el = document.createElement('div');
475
476             if ( this.CLASSNAME ) {
477                 el.className = this.CLASSNAME;
478             }
479             
480             return el;
481         },
482
483         _createTabParent: function(attr) {
484             var el = document.createElement('ul');
485
486             if ( this.TAB_PARENT_CLASSNAME ) {
487                 el.className = this.TAB_PARENT_CLASSNAME;
488             }
489             
490             this.get(ELEMENT).appendChild(el);
491             
492             return el;
493         },
494         
495         _createContentParent: function(attr) {
496             var el = document.createElement('div');
497
498             if ( this.CONTENT_PARENT_CLASSNAME ) {
499                 el.className = this.CONTENT_PARENT_CLASSNAME;
500             }
501             
502             this.get(ELEMENT).appendChild(el);
503             
504             return el;
505         }
506     });
507     
508     
509     YAHOO.widget.TabView = TabView;
510 })();
511
512 (function() {
513     var Y = YAHOO.util, 
514         Dom = Y.Dom,
515         Lang = YAHOO.lang,
516     
517
518     // STRING CONSTANTS
519         ACTIVE_TAB = 'activeTab',
520         LABEL = 'label',
521         LABEL_EL = 'labelEl',
522         CONTENT = 'content',
523         CONTENT_EL = 'contentEl',
524         ELEMENT = 'element',
525         CACHE_DATA = 'cacheData',
526         DATA_SRC = 'dataSrc',
527         DATA_LOADED = 'dataLoaded',
528         DATA_TIMEOUT = 'dataTimeout',
529         LOAD_METHOD = 'loadMethod',
530         POST_DATA = 'postData',
531         DISABLED = 'disabled',
532     
533     /**
534      * A representation of a Tab's label and content.
535      * @namespace YAHOO.widget
536      * @class Tab
537      * @extends YAHOO.util.Element
538      * @constructor
539      * @param element {HTMLElement | String} (optional) The html element that 
540      * represents the TabView. An element will be created if none provided.
541      * @param {Object} properties A key map of initial properties
542      */
543     Tab = function(el, attr) {
544         attr = attr || {};
545         if (arguments.length == 1 && !Lang.isString(el) && !el.nodeName) {
546             attr = el;
547             el = attr.element;
548         }
549
550         if (!el && !attr.element) {
551             el = this._createTabElement(attr);
552         }
553
554         this.loadHandler =  {
555             success: function(o) {
556                 this.set(CONTENT, o.responseText);
557             },
558             failure: function(o) {
559             }
560         };
561         
562         Tab.superclass.constructor.call(this, el, attr);
563         
564         this.DOM_EVENTS = {}; // delegating to tabView
565     };
566
567     YAHOO.extend(Tab, YAHOO.util.Element, {
568         /**
569          * The default tag name for a Tab's inner element.
570          * @property LABEL_INNER_TAGNAME
571          * @type String
572          * @default "em"
573          */
574         LABEL_TAGNAME: 'em',
575         
576         /**
577          * The class name applied to active tabs.
578          * @property ACTIVE_CLASSNAME
579          * @type String
580          * @default "selected"
581          */
582         ACTIVE_CLASSNAME: 'selected',
583         
584         /**
585          * The class name applied to active tabs.
586          * @property ACTIVE_CLASSNAME
587          * @type String
588          * @default "selected"
589          */
590         HIDDEN_CLASSNAME: 'yui-hidden',
591         
592         /**
593          * The title applied to active tabs.
594          * @property ACTIVE_TITLE
595          * @type String
596          * @default "active"
597          */
598         ACTIVE_TITLE: 'active',
599
600         /**
601          * The class name applied to disabled tabs.
602          * @property DISABLED_CLASSNAME
603          * @type String
604          * @default "disabled"
605          */
606         DISABLED_CLASSNAME: DISABLED,
607         
608         /**
609          * The class name applied to dynamic tabs while loading.
610          * @property LOADING_CLASSNAME
611          * @type String
612          * @default "disabled"
613          */
614         LOADING_CLASSNAME: 'loading',
615
616         /**
617          * Provides a reference to the connection request object when data is
618          * loaded dynamically.
619          * @property dataConnection
620          * @type Object
621          */
622         dataConnection: null,
623         
624         /**
625          * Object containing success and failure callbacks for loading data.
626          * @property loadHandler
627          * @type object
628          */
629         loadHandler: null,
630
631         _loading: false,
632         
633         /**
634          * Provides a readable name for the tab.
635          * @method toString
636          * @return String
637          */
638         toString: function() {
639             var el = this.get(ELEMENT),
640                 id = el.id || el.tagName;
641             return "Tab " + id; 
642         },
643         
644         /**
645          * setAttributeConfigs TabView specific properties.
646          * @method initAttributes
647          * @param {Object} attr Hash of initial attributes
648          */
649         initAttributes: function(attr) {
650             attr = attr || {};
651             Tab.superclass.initAttributes.call(this, attr);
652             
653             /**
654              * The event that triggers the tab's activation.
655              * @attribute activationEvent
656              * @type String
657              */
658             this.setAttributeConfig('activationEvent', {
659                 value: attr.activationEvent || 'click'
660             });        
661
662             /**
663              * The element that contains the tab's label.
664              * @attribute labelEl
665              * @type HTMLElement
666              */
667             this.setAttributeConfig(LABEL_EL, {
668                 value: attr[LABEL_EL] || this._getLabelEl(),
669                 method: function(value) {
670                     value = Dom.get(value);
671                     var current = this.get(LABEL_EL);
672
673                     if (current) {
674                         if (current == value) {
675                             return false; // already set
676                         }
677                         
678                         current.parentNode.replaceChild(value, current);
679                         this.set(LABEL, value.innerHTML);
680                     }
681                 } 
682             });
683
684             /**
685              * The tab's label text (or innerHTML).
686              * @attribute label
687              * @type String
688              */
689             this.setAttributeConfig(LABEL, {
690                 value: attr.label || this._getLabel(),
691                 method: function(value) {
692                     var labelEl = this.get(LABEL_EL);
693                     if (!labelEl) { // create if needed
694                         this.set(LABEL_EL, this._createLabelEl());
695                     }
696                     
697                     labelEl.innerHTML = value;
698                 }
699             });
700             
701             /**
702              * The HTMLElement that contains the tab's content.
703              * @attribute contentEl
704              * @type HTMLElement
705              */
706             this.setAttributeConfig(CONTENT_EL, {
707                 value: attr[CONTENT_EL] || document.createElement('div'),
708                 method: function(value) {
709                     value = Dom.get(value);
710                     var current = this.get(CONTENT_EL);
711
712                     if (current) {
713                         if (current === value) {
714                             return false; // already set
715                         }
716                         if (!this.get('selected')) {
717                             Dom.addClass(value, 'yui-hidden');
718                         }
719                         current.parentNode.replaceChild(value, current);
720                         this.set(CONTENT, value.innerHTML);
721                     }
722                 }
723             });
724             
725             /**
726              * The tab's content.
727              * @attribute content
728              * @type String
729              */
730             this.setAttributeConfig(CONTENT, {
731                 value: attr[CONTENT],
732                 method: function(value) {
733                     this.get(CONTENT_EL).innerHTML = value;
734                 }
735             });
736
737             /**
738              * The tab's data source, used for loading content dynamically.
739              * @attribute dataSrc
740              * @type String
741              */
742             this.setAttributeConfig(DATA_SRC, {
743                 value: attr.dataSrc
744             });
745             
746             /**
747              * Whether or not content should be reloaded for every view.
748              * @attribute cacheData
749              * @type Boolean
750              * @default false
751              */
752             this.setAttributeConfig(CACHE_DATA, {
753                 value: attr.cacheData || false,
754                 validator: Lang.isBoolean
755             });
756             
757             /**
758              * The method to use for the data request.
759              * @attribute loadMethod
760              * @type String
761              * @default "GET"
762              */
763             this.setAttributeConfig(LOAD_METHOD, {
764                 value: attr.loadMethod || 'GET',
765                 validator: Lang.isString
766             });
767
768             /**
769              * Whether or not any data has been loaded from the server.
770              * @attribute dataLoaded
771              * @type Boolean
772              */        
773             this.setAttributeConfig(DATA_LOADED, {
774                 value: false,
775                 validator: Lang.isBoolean,
776                 writeOnce: true
777             });
778             
779             /**
780              * Number if milliseconds before aborting and calling failure handler.
781              * @attribute dataTimeout
782              * @type Number
783              * @default null
784              */
785             this.setAttributeConfig(DATA_TIMEOUT, {
786                 value: attr.dataTimeout || null,
787                 validator: Lang.isNumber
788             });
789             
790             /**
791              * Arguments to pass when POST method is used 
792              * @attribute postData
793              * @default null
794              */
795             this.setAttributeConfig(POST_DATA, {
796                 value: attr.postData || null
797             });
798
799             /**
800              * Whether or not the tab is currently active.
801              * If a dataSrc is set for the tab, the content will be loaded from
802              * the given source.
803              * @attribute active
804              * @type Boolean
805              */
806             this.setAttributeConfig('active', {
807                 value: attr.active || this.hasClass(this.ACTIVE_CLASSNAME),
808                 method: function(value) {
809                     if (value === true) {
810                         this.addClass(this.ACTIVE_CLASSNAME);
811                         this.set('title', this.ACTIVE_TITLE);
812                     } else {
813                         this.removeClass(this.ACTIVE_CLASSNAME);
814                         this.set('title', '');
815                     }
816                 },
817                 validator: function(value) {
818                     return Lang.isBoolean(value) && !this.get(DISABLED) ;
819                 }
820             });
821             
822             /**
823              * Whether or not the tab is disabled.
824              * @attribute disabled
825              * @type Boolean
826              */
827             this.setAttributeConfig(DISABLED, {
828                 value: attr.disabled || this.hasClass(this.DISABLED_CLASSNAME),
829                 method: function(value) {
830                     if (value === true) {
831                         Dom.addClass(this.get(ELEMENT), this.DISABLED_CLASSNAME);
832                     } else {
833                         Dom.removeClass(this.get(ELEMENT), this.DISABLED_CLASSNAME);
834                     }
835                 },
836                 validator: Lang.isBoolean
837             });
838             
839             /**
840              * The href of the tab's anchor element.
841              * @attribute href
842              * @type String
843              * @default '#'
844              */
845             this.setAttributeConfig('href', {
846                 value: attr.href ||
847                         this.getElementsByTagName('a')[0].getAttribute('href', 2) || '#',
848                 method: function(value) {
849                     this.getElementsByTagName('a')[0].href = value;
850                 },
851                 validator: Lang.isString
852             });
853             
854             /**
855              * The Whether or not the tab's content is visible.
856              * @attribute contentVisible
857              * @type Boolean
858              * @default false
859              */
860             this.setAttributeConfig('contentVisible', {
861                 value: attr.contentVisible,
862                 method: function(value) {
863                     if (value) {
864                         Dom.removeClass(this.get(CONTENT_EL), this.HIDDEN_CLASSNAME);
865                         
866                         if ( this.get(DATA_SRC) ) {
867                          // load dynamic content unless already loading or loaded and caching
868                             if ( !this._loading && !(this.get(DATA_LOADED) && this.get(CACHE_DATA)) ) {
869                                 this._dataConnect();
870                             }
871                         }
872                     } else {
873                         Dom.addClass(this.get(CONTENT_EL), this.HIDDEN_CLASSNAME);
874                     }
875                 },
876                 validator: Lang.isBoolean
877             });
878         },
879         
880         _dataConnect: function() {
881             if (!Y.Connect) {
882                 return false;
883             }
884
885             Dom.addClass(this.get(CONTENT_EL).parentNode, this.LOADING_CLASSNAME);
886             this._loading = true; 
887             this.dataConnection = Y.Connect.asyncRequest(
888                 this.get(LOAD_METHOD),
889                 this.get(DATA_SRC), 
890                 {
891                     success: function(o) {
892                         this.loadHandler.success.call(this, o);
893                         this.set(DATA_LOADED, true);
894                         this.dataConnection = null;
895                         Dom.removeClass(this.get(CONTENT_EL).parentNode,
896                                 this.LOADING_CLASSNAME);
897                         this._loading = false;
898                     },
899                     failure: function(o) {
900                         this.loadHandler.failure.call(this, o);
901                         this.dataConnection = null;
902                         Dom.removeClass(this.get(CONTENT_EL).parentNode,
903                                 this.LOADING_CLASSNAME);
904                         this._loading = false;
905                     },
906                     scope: this,
907                     timeout: this.get(DATA_TIMEOUT)
908                 },
909
910                 this.get(POST_DATA)
911             );
912         },
913         _createTabElement: function(attr) {
914             var el = document.createElement('li'),
915                 a = document.createElement('a'),
916                 label = attr.label || null,
917                 labelEl = attr.labelEl || null;
918             
919             a.href = attr.href || '#'; // TODO: Use Dom.setAttribute?
920             el.appendChild(a);
921             
922             if (labelEl) { // user supplied labelEl
923                 if (!label) { // user supplied label
924                     label = this._getLabel();
925                 }
926             } else {
927                 labelEl = this._createLabelEl();
928             }
929             
930             a.appendChild(labelEl);
931             
932             return el;
933         },
934
935         _getLabelEl: function() {
936             return this.getElementsByTagName(this.LABEL_TAGNAME)[0];
937         },
938
939         _createLabelEl: function() {
940             var el = document.createElement(this.LABEL_TAGNAME);
941             return el;
942         },
943     
944         
945         _getLabel: function() {
946             var el = this.get(LABEL_EL);
947                 
948                 if (!el) {
949                     return undefined;
950                 }
951             
952             return el.innerHTML;
953         },
954
955         _onActivate: function(e, tabview) {
956             var tab = this,
957                 silent = false;
958             
959
960             Y.Event.preventDefault(e);
961             if (tab === tabview.get(ACTIVE_TAB)) {
962                 silent = true; // dont fire activeTabChange if already active
963             }
964             tabview.set(ACTIVE_TAB, tab, silent);
965         }
966     });
967     
968     
969     /**
970      * Fires when a tab is removed from the tabview
971      * @event remove
972      * @type CustomEvent
973      * @param {Event} An event object with fields for "type" ("remove")
974      * and "tabview" (the tabview instance it was removed from) 
975      */
976     
977     YAHOO.widget.Tab = Tab;
978 })();
979
980 YAHOO.register("tabview", YAHOO.widget.TabView, {version: "2.7.0", build: "1799"});