Index: openacs-4/packages/ajaxhelper/www/resources/yui/tabview/tabview.js =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/ajaxhelper/www/resources/yui/tabview/tabview.js,v diff -u -r1.2 -r1.3 --- openacs-4/packages/ajaxhelper/www/resources/yui/tabview/tabview.js 8 Sep 2007 14:22:08 -0000 1.2 +++ openacs-4/packages/ajaxhelper/www/resources/yui/tabview/tabview.js 9 Apr 2009 23:15:50 -0000 1.3 @@ -1,8 +1,8 @@ /* -Copyright (c) 2007, Yahoo! Inc. All rights reserved. +Copyright (c) 2009, Yahoo! Inc. All rights reserved. Code licensed under the BSD License: http://developer.yahoo.net/yui/license.txt -version: 2.3.0 +version: 2.7.0 */ (function() { @@ -12,6 +12,19 @@ * @requires yahoo, dom, event, element * */ + + var Y = YAHOO.util, + Dom = Y.Dom, + Event = Y.Event, + document = window.document, + + // STRING CONSTANTS + ACTIVE = 'active', + ACTIVE_INDEX = 'activeIndex', + ACTIVE_TAB = 'activeTab', + CONTENT_EL = 'contentEl', + ELEMENT = 'element', + /** * A widget to control tabbed views. * @namespace YAHOO.widget @@ -24,515 +37,499 @@ * @param {Object} attr (optional) A key map of the tabView's * initial attributes. Ignored if first arg is attributes object. */ - YAHOO.widget.TabView = function(el, attr) { + TabView = function(el, attr) { attr = attr || {}; if (arguments.length == 1 && !YAHOO.lang.isString(el) && !el.nodeName) { attr = el; // treat first arg as attr object el = attr.element || null; } if (!el && !attr.element) { // create if we dont have one - el = _createTabViewElement.call(this, attr); + el = this._createTabViewElement(attr); } - YAHOO.widget.TabView.superclass.constructor.call(this, el, attr); + TabView.superclass.constructor.call(this, el, attr); }; - YAHOO.extend(YAHOO.widget.TabView, YAHOO.util.Element); - - var proto = YAHOO.widget.TabView.prototype; - var Dom = YAHOO.util.Dom; - var Event = YAHOO.util.Event; - var Tab = YAHOO.widget.Tab; - - - /** - * The className to add when building from scratch. - * @property CLASSNAME - * @default "navset" - */ - proto.CLASSNAME = 'yui-navset'; - - /** - * The className of the HTMLElement containing the TabView's tab elements - * to look for when building from existing markup, or to add when building - * from scratch. - * All childNodes of the tab container are treated as Tabs when building - * from existing markup. - * @property TAB_PARENT_CLASSNAME - * @default "nav" - */ - proto.TAB_PARENT_CLASSNAME = 'yui-nav'; - - /** - * The className of the HTMLElement containing the TabView's label elements - * to look for when building from existing markup, or to add when building - * from scratch. - * All childNodes of the content container are treated as content elements when - * building from existing markup. - * @property CONTENT_PARENT_CLASSNAME - * @default "nav-content" - */ - proto.CONTENT_PARENT_CLASSNAME = 'yui-content'; - - proto._tabParent = null; - proto._contentParent = null; - - /** - * Adds a Tab to the TabView instance. - * If no index is specified, the tab is added to the end of the tab list. - * @method addTab - * @param {YAHOO.widget.Tab} tab A Tab instance to add. - * @param {Integer} index The position to add the tab. - * @return void - */ - proto.addTab = function(tab, index) { - var tabs = this.get('tabs'); - if (!tabs) { // not ready yet - this._queue[this._queue.length] = ['addTab', arguments]; - return false; - } + YAHOO.extend(TabView, Y.Element, { + /** + * The className to add when building from scratch. + * @property CLASSNAME + * @default "navset" + */ + CLASSNAME: 'yui-navset', - index = (index === undefined) ? tabs.length : index; + /** + * The className of the HTMLElement containing the TabView's tab elements + * to look for when building from existing markup, or to add when building + * from scratch. + * All childNodes of the tab container are treated as Tabs when building + * from existing markup. + * @property TAB_PARENT_CLASSNAME + * @default "nav" + */ + TAB_PARENT_CLASSNAME: 'yui-nav', - var before = this.getTab(index); + /** + * The className of the HTMLElement containing the TabView's label elements + * to look for when building from existing markup, or to add when building + * from scratch. + * All childNodes of the content container are treated as content elements when + * building from existing markup. + * @property CONTENT_PARENT_CLASSNAME + * @default "nav-content" + */ + CONTENT_PARENT_CLASSNAME: 'yui-content', - var self = this; - var el = this.get('element'); - var tabParent = this._tabParent; - var contentParent = this._contentParent; - - var tabElement = tab.get('element'); - var contentEl = tab.get('contentEl'); - - if ( before ) { - tabParent.insertBefore(tabElement, before.get('element')); - } else { - tabParent.appendChild(tabElement); - } - - if ( contentEl && !Dom.isAncestor(contentParent, contentEl) ) { - contentParent.appendChild(contentEl); - } + _tabParent: null, + _contentParent: null, - if ( !tab.get('active') ) { - tab.set('contentVisible', false, true); /* hide if not active */ - } else { - this.set('activeTab', tab, true); + /** + * Adds a Tab to the TabView instance. + * If no index is specified, the tab is added to the end of the tab list. + * @method addTab + * @param {YAHOO.widget.Tab} tab A Tab instance to add. + * @param {Integer} index The position to add the tab. + * @return void + */ + addTab: function(tab, index) { + var tabs = this.get('tabs'), + before = this.getTab(index), + tabParent = this._tabParent, + contentParent = this._contentParent, + tabElement = tab.get(ELEMENT), + contentEl = tab.get(CONTENT_EL); + + if (!tabs) { // not ready yet + this._queue[this._queue.length] = ['addTab', arguments]; + return false; + } - } + index = (index === undefined) ? tabs.length : index; + + if ( before ) { + tabParent.insertBefore(tabElement, before.get(ELEMENT)); + } else { + tabParent.appendChild(tabElement); + } - var activate = function(e) { - YAHOO.util.Event.preventDefault(e); - var silent = false; - - if (this == self.get('activeTab')) { - silent = true; // dont fire activeTabChange if already active + if ( contentEl && !Dom.isAncestor(contentParent, contentEl) ) { + contentParent.appendChild(contentEl); } - self.set('activeTab', this, silent); - }; - - tab.addListener( tab.get('activationEvent'), activate); - - tab.addListener('activationEventChange', function(e) { - if (e.prevValue != e.newValue) { - tab.removeListener(e.prevValue, activate); - tab.addListener(e.newValue, activate); + + if ( !tab.get(ACTIVE) ) { + tab.set('contentVisible', false, true); /* hide if not active */ + } else { + this.set(ACTIVE_TAB, tab, true); + } - }); - - tabs.splice(index, 0, tab); - }; - /** - * Routes childNode events. - * @method DOMEventHandler - * @param {event} e The Dom event that is being handled. - * @return void - */ - proto.DOMEventHandler = function(e) { - var el = this.get('element'); - var target = YAHOO.util.Event.getTarget(e); - var tabParent = this._tabParent; - - if (Dom.isAncestor(tabParent, target) ) { - var tabEl; - var tab = null; - var contentEl; - var tabs = this.get('tabs'); + this._initTabEvents(tab); + tabs.splice(index, 0, tab); + }, - for (var i = 0, len = tabs.length; i < len; i++) { - tabEl = tabs[i].get('element'); - contentEl = tabs[i].get('contentEl'); - - if ( target == tabEl || Dom.isAncestor(tabEl, target) ) { - tab = tabs[i]; - break; // note break + _initTabEvents: function(tab) { + tab.addListener( tab.get('activationEvent'), tab._onActivate, this, tab); + + tab.addListener('activationEventChange', function(e) { + if (e.prevValue != e.newValue) { + tab.removeListener(e.prevValue, tab._onActivate); + tab.addListener(e.newValue, tab._onActivate, this, tab); } - } + }); + }, + + /** + * Routes childNode events. + * @method DOMEventHandler + * @param {event} e The Dom event that is being handled. + * @return void + */ + DOMEventHandler: function(e) { + var target = Event.getTarget(e), + tabParent = this._tabParent, + tabs = this.get('tabs'), + tab, + tabEl, + contentEl; + - if (tab) { - tab.fireEvent(e.type, e); - } - } - }; - - /** - * Returns the Tab instance at the specified index. - * @method getTab - * @param {Integer} index The position of the Tab. - * @return YAHOO.widget.Tab - */ - proto.getTab = function(index) { - return this.get('tabs')[index]; - }; - - /** - * Returns the index of given tab. - * @method getTabIndex - * @param {YAHOO.widget.Tab} tab The tab whose index will be returned. - * @return int - */ - proto.getTabIndex = function(tab) { - var index = null; - var tabs = this.get('tabs'); - for (var i = 0, len = tabs.length; i < len; ++i) { - if (tab == tabs[i]) { - index = i; - break; - } - } - - return index; - }; - - /** - * Removes the specified Tab from the TabView. - * @method removeTab - * @param {YAHOO.widget.Tab} item The Tab instance to be removed. - * @return void - */ - proto.removeTab = function(tab) { - var tabCount = this.get('tabs').length; + if (Dom.isAncestor(tabParent, target) ) { + for (var i = 0, len = tabs.length; i < len; i++) { + tabEl = tabs[i].get(ELEMENT); + contentEl = tabs[i].get(CONTENT_EL); - var index = this.getTabIndex(tab); - var nextIndex = index + 1; - if ( tab == this.get('activeTab') ) { // select next tab - if (tabCount > 1) { - if (index + 1 == tabCount) { - this.set('activeIndex', index - 1); - } else { - this.set('activeIndex', index + 1); + if ( target == tabEl || Dom.isAncestor(tabEl, target) ) { + tab = tabs[i]; + break; // note break + } + } + + if (tab) { + tab.fireEvent(e.type, e); } } - } + }, - this._tabParent.removeChild( tab.get('element') ); - this._contentParent.removeChild( tab.get('contentEl') ); - this._configs.tabs.value.splice(index, 1); - - }; - - /** - * Provides a readable name for the TabView instance. - * @method toString - * @return String - */ - proto.toString = function() { - var name = this.get('id') || this.get('tagName'); - return "TabView " + name; - }; - - /** - * The transiton to use when switching between tabs. - * @method contentTransition - */ - proto.contentTransition = function(newTab, oldTab) { - newTab.set('contentVisible', true); - oldTab.set('contentVisible', false); - }; - - /** - * setAttributeConfigs TabView specific properties. - * @method initAttributes - * @param {Object} attr Hash of initial attributes - */ - proto.initAttributes = function(attr) { - YAHOO.widget.TabView.superclass.initAttributes.call(this, attr); + /** + * Returns the Tab instance at the specified index. + * @method getTab + * @param {Integer} index The position of the Tab. + * @return YAHOO.widget.Tab + */ + getTab: function(index) { + return this.get('tabs')[index]; + }, - if (!attr.orientation) { - attr.orientation = 'top'; - } + /** + * Returns the index of given tab. + * @method getTabIndex + * @param {YAHOO.widget.Tab} tab The tab whose index will be returned. + * @return int + */ + getTabIndex: function(tab) { + var index = null, + tabs = this.get('tabs'); + for (var i = 0, len = tabs.length; i < len; ++i) { + if (tab == tabs[i]) { + index = i; + break; + } + } + + return index; + }, - var el = this.get('element'); - - if (!YAHOO.util.Dom.hasClass(el, this.CLASSNAME)) { - YAHOO.util.Dom.addClass(el, this.CLASSNAME); - } - /** - * The Tabs belonging to the TabView instance. - * @config tabs - * @type Array + * Removes the specified Tab from the TabView. + * @method removeTab + * @param {YAHOO.widget.Tab} item The Tab instance to be removed. + * @return void */ - this.setAttributeConfig('tabs', { - value: [], - readOnly: true - }); + removeTab: function(tab) { + var tabCount = this.get('tabs').length, + index = this.getTabIndex(tab); + if ( tab === this.get(ACTIVE_TAB) ) { + if (tabCount > 1) { // select another tab + if (index + 1 === tabCount) { // if last, activate previous + this.set(ACTIVE_INDEX, index - 1); + } else { // activate next tab + this.set(ACTIVE_INDEX, index + 1); + } + } else { // no more tabs + this.set(ACTIVE_TAB, null); + } + } + + this._tabParent.removeChild( tab.get(ELEMENT) ); + this._contentParent.removeChild( tab.get(CONTENT_EL) ); + this._configs.tabs.value.splice(index, 1); + + tab.fireEvent('remove', { type: 'remove', tabview: this }); + }, + /** - * The container of the tabView's label elements. - * @property _tabParent - * @private - * @type HTMLElement + * Provides a readable name for the TabView instance. + * @method toString + * @return String */ - this._tabParent = - this.getElementsByClassName(this.TAB_PARENT_CLASSNAME, - 'ul' )[0] || _createTabParent.call(this); - + toString: function() { + var name = this.get('id') || this.get('tagName'); + return "TabView " + name; + }, + /** - * The container of the tabView's content elements. - * @property _contentParent - * @type HTMLElement - * @private + * The transiton to use when switching between tabs. + * @method contentTransition */ - this._contentParent = - this.getElementsByClassName(this.CONTENT_PARENT_CLASSNAME, - 'div')[0] || _createContentParent.call(this); + contentTransition: function(newTab, oldTab) { + if (newTab) { + newTab.set('contentVisible', true); + } + if (oldTab) { + oldTab.set('contentVisible', false); + } + }, /** - * How the Tabs should be oriented relative to the TabView. - * @config orientation - * @type String - * @default "top" + * setAttributeConfigs TabView specific properties. + * @method initAttributes + * @param {Object} attr Hash of initial attributes */ - this.setAttributeConfig('orientation', { - value: attr.orientation, - method: function(value) { - var current = this.get('orientation'); - this.addClass('yui-navset-' + value); + initAttributes: function(attr) { + TabView.superclass.initAttributes.call(this, attr); + + if (!attr.orientation) { + attr.orientation = 'top'; + } + + var el = this.get(ELEMENT); + + if (!Dom.hasClass(el, this.CLASSNAME)) { + Dom.addClass(el, this.CLASSNAME); + } + + /** + * The Tabs belonging to the TabView instance. + * @attribute tabs + * @type Array + */ + this.setAttributeConfig('tabs', { + value: [], + readOnly: true + }); + + /** + * The container of the tabView's label elements. + * @property _tabParent + * @private + * @type HTMLElement + */ + this._tabParent = + this.getElementsByClassName(this.TAB_PARENT_CLASSNAME, + 'ul' )[0] || this._createTabParent(); - if (current != value) { - this.removeClass('yui-navset-' + current); + /** + * The container of the tabView's content elements. + * @property _contentParent + * @type HTMLElement + * @private + */ + this._contentParent = + this.getElementsByClassName(this.CONTENT_PARENT_CLASSNAME, + 'div')[0] || this._createContentParent(); + + /** + * How the Tabs should be oriented relative to the TabView. + * @attribute orientation + * @type String + * @default "top" + */ + this.setAttributeConfig('orientation', { + value: attr.orientation, + method: function(value) { + var current = this.get('orientation'); + this.addClass('yui-navset-' + value); + + if (current != value) { + this.removeClass('yui-navset-' + current); + } + + if (value === 'bottom') { + this.appendChild(this._tabParent); + } } - - switch(value) { - case 'bottom': - this.appendChild(this._tabParent); - break; + }); + + /** + * The index of the tab currently active. + * @attribute activeIndex + * @type Int + */ + this.setAttributeConfig(ACTIVE_INDEX, { + value: attr.activeIndex, + method: function(value) { + }, + validator: function(value) { + var ret = true; + if (value && this.getTab(value).get('disabled')) { // cannot activate if disabled + ret = false; + } + return ret; } + }); + + /** + * The tab currently active. + * @attribute activeTab + * @type YAHOO.widget.Tab + */ + this.setAttributeConfig(ACTIVE_TAB, { + value: attr.activeTab, + method: function(tab) { + var activeTab = this.get(ACTIVE_TAB); + + if (tab) { + tab.set(ACTIVE, true); + } + + if (activeTab && activeTab !== tab) { + activeTab.set(ACTIVE, false); + } + + if (activeTab && tab !== activeTab) { // no transition if only 1 + this.contentTransition(tab, activeTab); + } else if (tab) { + tab.set('contentVisible', true); + } + }, + validator: function(value) { + var ret = true; + if (value && value.get('disabled')) { // cannot activate if disabled + ret = false; + } + return ret; + } + }); + + this.on('activeTabChange', this._onActiveTabChange); + this.on('activeIndexChange', this._onActiveIndexChange); + + if ( this._tabParent ) { + this._initTabs(); } - }); - + + // Due to delegation we add all DOM_EVENTS to the TabView container + // but IE will leak when unsupported events are added, so remove these + this.DOM_EVENTS.submit = false; + this.DOM_EVENTS.focus = false; + this.DOM_EVENTS.blur = false; + + for (var type in this.DOM_EVENTS) { + if ( YAHOO.lang.hasOwnProperty(this.DOM_EVENTS, type) ) { + this.addListener.call(this, type, this.DOMEventHandler); + } + } + }, + /** - * The index of the tab currently active. - * @config activeIndex - * @type Int + * Removes selected state from the given tab if it is the activeTab + * @method deselectTab + * @param {Int} index The tab index to deselect */ - this.setAttributeConfig('activeIndex', { - value: attr.activeIndex, - method: function(value) { - this.set('activeTab', this.getTab(value)); - }, - validator: function(value) { - return !this.getTab(value).get('disabled'); // cannot activate if disabled + deselectTab: function(index) { + if (this.getTab(index) === this.get('activeTab')) { + this.set('activeTab', null); } - }); + }, + + /** + * Makes the tab at the given index the active tab + * @method selectTab + * @param {Int} index The tab index to be made active + */ + selectTab: function(index) { + this.set('activeTab', this.getTab(index)); + }, + + _onActiveTabChange: function(e) { + var activeIndex = this.get(ACTIVE_INDEX), + newIndex = this.getTabIndex(e.newValue); + + if (activeIndex !== newIndex) { + if (!(this.set(ACTIVE_INDEX, newIndex)) ) { // NOTE: setting + // revert if activeIndex update fails (cancelled via beforeChange) + this.set(ACTIVE_TAB, e.prevValue); + } + } + }, + _onActiveIndexChange: function(e) { + // no set if called from ActiveTabChange event + if (e.newValue !== this.getTabIndex(this.get(ACTIVE_TAB))) { + if (!(this.set(ACTIVE_TAB, this.getTab(e.newValue))) ) { // NOTE: setting + // revert if activeTab update fails (cancelled via beforeChange) + this.set(ACTIVE_INDEX, e.prevValue); + } + } + }, + /** - * The tab currently active. - * @config activeTab - * @type YAHOO.widget.Tab + * Creates Tab instances from a collection of HTMLElements. + * @method _initTabs + * @private + * @return void */ - this.setAttributeConfig('activeTab', { - value: attr.activeTab, - method: function(tab) { - var activeTab = this.get('activeTab'); + _initTabs: function() { + var tabs = Dom.getChildren(this._tabParent), + contentElements = Dom.getChildren(this._contentParent), + activeIndex = this.get(ACTIVE_INDEX), + tab, + attr, + active; + + for (var i = 0, len = tabs.length; i < len; ++i) { + attr = {}; - if (tab) { - tab.set('active', true); - this._configs['activeIndex'].value = this.getTabIndex(tab); // keep in sync + if (contentElements[i]) { + attr.contentEl = contentElements[i]; } + + tab = new YAHOO.widget.Tab(tabs[i], attr); + this.addTab(tab); - if (activeTab && activeTab != tab) { - activeTab.set('active', false); + if (tab.hasClass(tab.ACTIVE_CLASSNAME) ) { + active = tab; } - - if (activeTab && tab != activeTab) { // no transition if only 1 - this.contentTransition(tab, activeTab); - } else if (tab) { - tab.set('contentVisible', true); - } - }, - validator: function(value) { - return !value.get('disabled'); // cannot activate if disabled } - }); + if (activeIndex) { + this.set(ACTIVE_TAB, this.getTab(activeIndex)); + } else { + this._configs.activeTab.value = active; // dont invoke method + this._configs.activeIndex.value = this.getTabIndex(active); + } + }, - if ( this._tabParent ) { - _initTabs.call(this); - } - - // Due to delegation we add all DOM_EVENTS to the TabView container - // but IE will leak when unsupported events are added, so remove these - this.DOM_EVENTS.submit = false; - this.DOM_EVENTS.focus = false; - this.DOM_EVENTS.blur = false; + _createTabViewElement: function(attr) { + var el = document.createElement('div'); - for (var type in this.DOM_EVENTS) { - if ( YAHOO.lang.hasOwnProperty(this.DOM_EVENTS, type) ) { - this.addListener.call(this, type, this.DOMEventHandler); + if ( this.CLASSNAME ) { + el.className = this.CLASSNAME; } - } - }; - - /** - * Creates Tab instances from a collection of HTMLElements. - * @method initTabs - * @private - * @return void - */ - var _initTabs = function() { - var tab, - attr, - contentEl; - var el = this.get('element'); - var tabs = _getChildNodes(this._tabParent); - var contentElements = _getChildNodes(this._contentParent); + return el; + }, - for (var i = 0, len = tabs.length; i < len; ++i) { - attr = {}; - - if (contentElements[i]) { - attr.contentEl = contentElements[i]; - } + _createTabParent: function(attr) { + var el = document.createElement('ul'); - tab = new YAHOO.widget.Tab(tabs[i], attr); - this.addTab(tab); - - if (tab.hasClass(tab.ACTIVE_CLASSNAME) ) { - this._configs.activeTab.value = tab; // dont invoke method - this._configs.activeIndex.value = this.getTabIndex(tab); + if ( this.TAB_PARENT_CLASSNAME ) { + el.className = this.TAB_PARENT_CLASSNAME; } - } - }; - - var _createTabViewElement = function(attr) { - var el = document.createElement('div'); - - if ( this.CLASSNAME ) { - el.className = this.CLASSNAME; - } + + this.get(ELEMENT).appendChild(el); + + return el; + }, - return el; - }; - - var _createTabParent = function(attr) { - var el = document.createElement('ul'); + _createContentParent: function(attr) { + var el = document.createElement('div'); - if ( this.TAB_PARENT_CLASSNAME ) { - el.className = this.TAB_PARENT_CLASSNAME; - } - - this.get('element').appendChild(el); - - return el; - }; - - var _createContentParent = function(attr) { - var el = document.createElement('div'); - - if ( this.CONTENT_PARENT_CLASSNAME ) { - el.className = this.CONTENT_PARENT_CLASSNAME; - } - - this.get('element').appendChild(el); - - return el; - }; - - var _getChildNodes = function(el) { - var nodes = []; - var childNodes = el.childNodes; - - for (var i = 0, len = childNodes.length; i < len; ++i) { - if (childNodes[i].nodeType == 1) { - nodes[nodes.length] = childNodes[i]; + if ( this.CONTENT_PARENT_CLASSNAME ) { + el.className = this.CONTENT_PARENT_CLASSNAME; } + + this.get(ELEMENT).appendChild(el); + + return el; } - - return nodes; - }; - -/** - * Fires before the activeTab is changed. - *

See: Element.addListener

- *

If handler returns false, the change will be cancelled, and the value will not - * be set.

- *

Event fields:
- * <String> type beforeActiveTabChange
- * <YAHOO.widget.Tab> - * prevValue the currently active tab
- * <YAHOO.widget.Tab> - * newValue the tab to be made active

- *

Usage:
- * var handler = function(e) {var previous = e.prevValue};
- * myTabs.addListener('beforeActiveTabChange', handler);

- * @event beforeActiveTabChange - */ + }); -/** - * Fires after the activeTab is changed. - *

See: Element.addListener

- *

Event fields:
- * <String> type activeTabChange
- * <YAHOO.widget.Tab> - * prevValue the formerly active tab
- * <YAHOO.widget.Tab> - * newValue the new active tab

- *

Usage:
- * var handler = function(e) {var previous = e.prevValue};
- * myTabs.addListener('activeTabChange', handler);

- * @event activeTabChange - */ - -/** - * Fires before the orientation is changed. - *

See: Element.addListener

- *

If handler returns false, the change will be cancelled, and the value will not - * be set.

- *

Event fields:
- * <String> type beforeOrientationChange
- * <String> - * prevValue the current orientation
- * <String> - * newValue the new orientation to be applied

- *

Usage:
- * var handler = function(e) {var previous = e.prevValue};
- * myTabs.addListener('beforeOrientationChange', handler);

- * @event beforeOrientationChange - */ -/** - * Fires after the orientation is changed. - *

See: Element.addListener

- *

Event fields:
- * <String> type orientationChange
- * <String> - * prevValue the former orientation
- * <String> - * newValue the new orientation

- *

Usage:
- * var handler = function(e) {var previous = e.prevValue};
- * myTabs.addListener('orientationChange', handler);

- * @event orientationChange - */ + YAHOO.widget.TabView = TabView; })(); (function() { - var Dom = YAHOO.util.Dom, - Event = YAHOO.util.Event; + var Y = YAHOO.util, + Dom = Y.Dom, + Lang = YAHOO.lang, + + // STRING CONSTANTS + ACTIVE_TAB = 'activeTab', + LABEL = 'label', + LABEL_EL = 'labelEl', + CONTENT = 'content', + CONTENT_EL = 'contentEl', + ELEMENT = 'element', + CACHE_DATA = 'cacheData', + DATA_SRC = 'dataSrc', + DATA_LOADED = 'dataLoaded', + DATA_TIMEOUT = 'dataTimeout', + LOAD_METHOD = 'loadMethod', + POST_DATA = 'postData', + DISABLED = 'disabled', + /** * A representation of a Tab's label and content. * @namespace YAHOO.widget @@ -543,20 +540,20 @@ * represents the TabView. An element will be created if none provided. * @param {Object} properties A key map of initial properties */ - var Tab = function(el, attr) { + Tab = function(el, attr) { attr = attr || {}; - if (arguments.length == 1 && !YAHOO.lang.isString(el) && !el.nodeName) { + if (arguments.length == 1 && !Lang.isString(el) && !el.nodeName) { attr = el; el = attr.element; } if (!el && !attr.element) { - el = _createTabElement.call(this, attr); + el = this._createTabElement(attr); } this.loadHandler = { success: function(o) { - this.set('content', o.responseText); + this.set(CONTENT, o.responseText); }, failure: function(o) { } @@ -567,475 +564,417 @@ this.DOM_EVENTS = {}; // delegating to tabView }; - YAHOO.extend(Tab, YAHOO.util.Element); - var proto = Tab.prototype; - - /** - * The default tag name for a Tab's inner element. - * @property LABEL_INNER_TAGNAME - * @type String - * @default "em" - */ - proto.LABEL_TAGNAME = 'em'; - - /** - * The class name applied to active tabs. - * @property ACTIVE_CLASSNAME - * @type String - * @default "on" - */ - proto.ACTIVE_CLASSNAME = 'selected'; - - /** - * The class name applied to disabled tabs. - * @property DISABLED_CLASSNAME - * @type String - * @default "disabled" - */ - proto.DISABLED_CLASSNAME = 'disabled'; - - /** - * The class name applied to dynamic tabs while loading. - * @property LOADING_CLASSNAME - * @type String - * @default "disabled" - */ - proto.LOADING_CLASSNAME = 'loading'; - - /** - * Provides a reference to the connection request object when data is - * loaded dynamically. - * @property dataConnection - * @type Object - */ - proto.dataConnection = null; - - /** - * Object containing success and failure callbacks for loading data. - * @property loadHandler - * @type object - */ - proto.loadHandler = null; - - proto._loading = false; - - /** - * Provides a readable name for the tab. - * @method toString - * @return String - */ - proto.toString = function() { - var el = this.get('element'); - var id = el.id || el.tagName; - return "Tab " + id; - }; - - /** - * setAttributeConfigs TabView specific properties. - * @method initAttributes - * @param {Object} attr Hash of initial attributes - */ - proto.initAttributes = function(attr) { - attr = attr || {}; - Tab.superclass.initAttributes.call(this, attr); - - var el = this.get('element'); - + YAHOO.extend(Tab, YAHOO.util.Element, { /** - * The event that triggers the tab's activation. - * @config activationEvent + * The default tag name for a Tab's inner element. + * @property LABEL_INNER_TAGNAME * @type String + * @default "em" */ - this.setAttributeConfig('activationEvent', { - value: attr.activationEvent || 'click' - }); - + LABEL_TAGNAME: 'em', + /** - * The element that contains the tab's label. - * @config labelEl - * @type HTMLElement - */ - this.setAttributeConfig('labelEl', { - value: attr.labelEl || _getlabelEl.call(this), - method: function(value) { - var current = this.get('labelEl'); - - if (current) { - if (current == value) { - return false; // already set - } - - this.replaceChild(value, current); - } else if (el.firstChild) { // ensure label is firstChild by default - this.insertBefore(value, el.firstChild); - } else { - this.appendChild(value); - } - } - }); - - /** - * The tab's label text (or innerHTML). - * @config label + * The class name applied to active tabs. + * @property ACTIVE_CLASSNAME * @type String + * @default "selected" */ - this.setAttributeConfig('label', { - value: attr.label || _getLabel.call(this), - method: function(value) { - var labelEl = this.get('labelEl'); - if (!labelEl) { // create if needed - this.set('labelEl', _createlabelEl.call(this)); - } - - _setLabel.call(this, value); - } - }); + ACTIVE_CLASSNAME: 'selected', /** - * The HTMLElement that contains the tab's content. - * @config contentEl - * @type HTMLElement + * The class name applied to active tabs. + * @property ACTIVE_CLASSNAME + * @type String + * @default "selected" */ - this.setAttributeConfig('contentEl', { - value: attr.contentEl || document.createElement('div'), - method: function(value) { - var current = this.get('contentEl'); - - if (current) { - if (current == value) { - return false; // already set - } - this.replaceChild(value, current); - } - } - }); + HIDDEN_CLASSNAME: 'yui-hidden', /** - * The tab's content. - * @config content + * The title applied to active tabs. + * @property ACTIVE_TITLE * @type String + * @default "active" */ - this.setAttributeConfig('content', { - value: attr.content, - method: function(value) { - this.get('contentEl').innerHTML = value; - } - }); + ACTIVE_TITLE: 'active', - var _dataLoaded = false; - /** - * The tab's data source, used for loading content dynamically. - * @config dataSrc + * The class name applied to disabled tabs. + * @property DISABLED_CLASSNAME * @type String + * @default "disabled" */ - this.setAttributeConfig('dataSrc', { - value: attr.dataSrc - }); + DISABLED_CLASSNAME: DISABLED, /** - * Whether or not content should be reloaded for every view. - * @config cacheData - * @type Boolean - * @default false - */ - this.setAttributeConfig('cacheData', { - value: attr.cacheData || false, - validator: YAHOO.lang.isBoolean - }); - - /** - * The method to use for the data request. - * @config loadMethod + * The class name applied to dynamic tabs while loading. + * @property LOADING_CLASSNAME * @type String - * @default "GET" + * @default "disabled" */ - this.setAttributeConfig('loadMethod', { - value: attr.loadMethod || 'GET', - validator: YAHOO.lang.isString - }); + LOADING_CLASSNAME: 'loading', /** - * Whether or not any data has been loaded from the server. - * @config dataLoaded - * @type Boolean - */ - this.setAttributeConfig('dataLoaded', { - value: false, - validator: YAHOO.lang.isBoolean, - writeOnce: true - }); - - /** - * Number if milliseconds before aborting and calling failure handler. - * @config dataTimeout - * @type Number - * @default null + * Provides a reference to the connection request object when data is + * loaded dynamically. + * @property dataConnection + * @type Object */ - this.setAttributeConfig('dataTimeout', { - value: attr.dataTimeout || null, - validator: YAHOO.lang.isNumber - }); + dataConnection: null, /** - * Whether or not the tab is currently active. - * If a dataSrc is set for the tab, the content will be loaded from - * the given source. - * @config active - * @type Boolean + * Object containing success and failure callbacks for loading data. + * @property loadHandler + * @type object */ - this.setAttributeConfig('active', { - value: attr.active || this.hasClass(this.ACTIVE_CLASSNAME), - method: function(value) { - if (value === true) { - this.addClass(this.ACTIVE_CLASSNAME); - this.set('title', 'active'); - } else { - this.removeClass(this.ACTIVE_CLASSNAME); - this.set('title', ''); - } - }, - validator: function(value) { - return YAHOO.lang.isBoolean(value) && !this.get('disabled') ; - } - }); + loadHandler: null, + + _loading: false, /** - * Whether or not the tab is disabled. - * @config disabled - * @type Boolean + * Provides a readable name for the tab. + * @method toString + * @return String */ - this.setAttributeConfig('disabled', { - value: attr.disabled || this.hasClass(this.DISABLED_CLASSNAME), - method: function(value) { - if (value === true) { - Dom.addClass(this.get('element'), this.DISABLED_CLASSNAME); - } else { - Dom.removeClass(this.get('element'), this.DISABLED_CLASSNAME); - } - }, - validator: YAHOO.lang.isBoolean - }); + toString: function() { + var el = this.get(ELEMENT), + id = el.id || el.tagName; + return "Tab " + id; + }, /** - * The href of the tab's anchor element. - * @config href - * @type String - * @default '#' + * setAttributeConfigs TabView specific properties. + * @method initAttributes + * @param {Object} attr Hash of initial attributes */ - this.setAttributeConfig('href', { - value: attr.href || - this.getElementsByTagName('a')[0].getAttribute('href', 2) || '#', - method: function(value) { - this.getElementsByTagName('a')[0].href = value; - }, - validator: YAHOO.lang.isString - }); - - /** - * The Whether or not the tab's content is visible. - * @config contentVisible - * @type Boolean - * @default false - */ - this.setAttributeConfig('contentVisible', { - value: attr.contentVisible, - method: function(value) { - if (value) { - this.get('contentEl').style.display = 'block'; + initAttributes: function(attr) { + attr = attr || {}; + Tab.superclass.initAttributes.call(this, attr); + + /** + * The event that triggers the tab's activation. + * @attribute activationEvent + * @type String + */ + this.setAttributeConfig('activationEvent', { + value: attr.activationEvent || 'click' + }); + + /** + * The element that contains the tab's label. + * @attribute labelEl + * @type HTMLElement + */ + this.setAttributeConfig(LABEL_EL, { + value: attr[LABEL_EL] || this._getLabelEl(), + method: function(value) { + value = Dom.get(value); + var current = this.get(LABEL_EL); + + if (current) { + if (current == value) { + return false; // already set + } + + current.parentNode.replaceChild(value, current); + this.set(LABEL, value.innerHTML); + } + } + }); + + /** + * The tab's label text (or innerHTML). + * @attribute label + * @type String + */ + this.setAttributeConfig(LABEL, { + value: attr.label || this._getLabel(), + method: function(value) { + var labelEl = this.get(LABEL_EL); + if (!labelEl) { // create if needed + this.set(LABEL_EL, this._createLabelEl()); + } - if ( this.get('dataSrc') ) { - // load dynamic content unless already loading or loaded and caching - if ( !this._loading && !(this.get('dataLoaded') && this.get('cacheData')) ) { - _dataConnect.call(this); + labelEl.innerHTML = value; + } + }); + + /** + * The HTMLElement that contains the tab's content. + * @attribute contentEl + * @type HTMLElement + */ + this.setAttributeConfig(CONTENT_EL, { + value: attr[CONTENT_EL] || document.createElement('div'), + method: function(value) { + value = Dom.get(value); + var current = this.get(CONTENT_EL); + + if (current) { + if (current === value) { + return false; // already set } + if (!this.get('selected')) { + Dom.addClass(value, 'yui-hidden'); + } + current.parentNode.replaceChild(value, current); + this.set(CONTENT, value.innerHTML); } - } else { - this.get('contentEl').style.display = 'none'; } - }, - validator: YAHOO.lang.isBoolean - }); - }; - - var _createTabElement = function(attr) { - var el = document.createElement('li'); - var a = document.createElement('a'); + }); + + /** + * The tab's content. + * @attribute content + * @type String + */ + this.setAttributeConfig(CONTENT, { + value: attr[CONTENT], + method: function(value) { + this.get(CONTENT_EL).innerHTML = value; + } + }); + + /** + * The tab's data source, used for loading content dynamically. + * @attribute dataSrc + * @type String + */ + this.setAttributeConfig(DATA_SRC, { + value: attr.dataSrc + }); + + /** + * Whether or not content should be reloaded for every view. + * @attribute cacheData + * @type Boolean + * @default false + */ + this.setAttributeConfig(CACHE_DATA, { + value: attr.cacheData || false, + validator: Lang.isBoolean + }); + + /** + * The method to use for the data request. + * @attribute loadMethod + * @type String + * @default "GET" + */ + this.setAttributeConfig(LOAD_METHOD, { + value: attr.loadMethod || 'GET', + validator: Lang.isString + }); + + /** + * Whether or not any data has been loaded from the server. + * @attribute dataLoaded + * @type Boolean + */ + this.setAttributeConfig(DATA_LOADED, { + value: false, + validator: Lang.isBoolean, + writeOnce: true + }); + + /** + * Number if milliseconds before aborting and calling failure handler. + * @attribute dataTimeout + * @type Number + * @default null + */ + this.setAttributeConfig(DATA_TIMEOUT, { + value: attr.dataTimeout || null, + validator: Lang.isNumber + }); + + /** + * Arguments to pass when POST method is used + * @attribute postData + * @default null + */ + this.setAttributeConfig(POST_DATA, { + value: attr.postData || null + }); + + /** + * Whether or not the tab is currently active. + * If a dataSrc is set for the tab, the content will be loaded from + * the given source. + * @attribute active + * @type Boolean + */ + this.setAttributeConfig('active', { + value: attr.active || this.hasClass(this.ACTIVE_CLASSNAME), + method: function(value) { + if (value === true) { + this.addClass(this.ACTIVE_CLASSNAME); + this.set('title', this.ACTIVE_TITLE); + } else { + this.removeClass(this.ACTIVE_CLASSNAME); + this.set('title', ''); + } + }, + validator: function(value) { + return Lang.isBoolean(value) && !this.get(DISABLED) ; + } + }); + + /** + * Whether or not the tab is disabled. + * @attribute disabled + * @type Boolean + */ + this.setAttributeConfig(DISABLED, { + value: attr.disabled || this.hasClass(this.DISABLED_CLASSNAME), + method: function(value) { + if (value === true) { + Dom.addClass(this.get(ELEMENT), this.DISABLED_CLASSNAME); + } else { + Dom.removeClass(this.get(ELEMENT), this.DISABLED_CLASSNAME); + } + }, + validator: Lang.isBoolean + }); + + /** + * The href of the tab's anchor element. + * @attribute href + * @type String + * @default '#' + */ + this.setAttributeConfig('href', { + value: attr.href || + this.getElementsByTagName('a')[0].getAttribute('href', 2) || '#', + method: function(value) { + this.getElementsByTagName('a')[0].href = value; + }, + validator: Lang.isString + }); + + /** + * The Whether or not the tab's content is visible. + * @attribute contentVisible + * @type Boolean + * @default false + */ + this.setAttributeConfig('contentVisible', { + value: attr.contentVisible, + method: function(value) { + if (value) { + Dom.removeClass(this.get(CONTENT_EL), this.HIDDEN_CLASSNAME); + + if ( this.get(DATA_SRC) ) { + // load dynamic content unless already loading or loaded and caching + if ( !this._loading && !(this.get(DATA_LOADED) && this.get(CACHE_DATA)) ) { + this._dataConnect(); + } + } + } else { + Dom.addClass(this.get(CONTENT_EL), this.HIDDEN_CLASSNAME); + } + }, + validator: Lang.isBoolean + }); + }, - a.href = attr.href || '#'; - - el.appendChild(a); - - var label = attr.label || null; - var labelEl = attr.labelEl || null; - - if (labelEl) { // user supplied labelEl - if (!label) { // user supplied label - label = _getLabel.call(this, labelEl); + _dataConnect: function() { + if (!Y.Connect) { + return false; } - } else { - labelEl = _createlabelEl.call(this); - } - - a.appendChild(labelEl); - - return el; - }; - - var _getlabelEl = function() { - return this.getElementsByTagName(this.LABEL_TAGNAME)[0]; - }; - - var _createlabelEl = function() { - var el = document.createElement(this.LABEL_TAGNAME); - return el; - }; - - var _setLabel = function(label) { - var el = this.get('labelEl'); - el.innerHTML = label; - }; - - var _getLabel = function() { - var label, - el = this.get('labelEl'); + + Dom.addClass(this.get(CONTENT_EL).parentNode, this.LOADING_CLASSNAME); + this._loading = true; + this.dataConnection = Y.Connect.asyncRequest( + this.get(LOAD_METHOD), + this.get(DATA_SRC), + { + success: function(o) { + this.loadHandler.success.call(this, o); + this.set(DATA_LOADED, true); + this.dataConnection = null; + Dom.removeClass(this.get(CONTENT_EL).parentNode, + this.LOADING_CLASSNAME); + this._loading = false; + }, + failure: function(o) { + this.loadHandler.failure.call(this, o); + this.dataConnection = null; + Dom.removeClass(this.get(CONTENT_EL).parentNode, + this.LOADING_CLASSNAME); + this._loading = false; + }, + scope: this, + timeout: this.get(DATA_TIMEOUT) + }, + + this.get(POST_DATA) + ); + }, + _createTabElement: function(attr) { + var el = document.createElement('li'), + a = document.createElement('a'), + label = attr.label || null, + labelEl = attr.labelEl || null; - if (!el) { - return undefined; + a.href = attr.href || '#'; // TODO: Use Dom.setAttribute? + el.appendChild(a); + + if (labelEl) { // user supplied labelEl + if (!label) { // user supplied label + label = this._getLabel(); + } + } else { + labelEl = this._createLabelEl(); } - - return el.innerHTML; - }; + + a.appendChild(labelEl); + + return el; + }, + + _getLabelEl: function() { + return this.getElementsByTagName(this.LABEL_TAGNAME)[0]; + }, + + _createLabelEl: function() { + var el = document.createElement(this.LABEL_TAGNAME); + return el; + }, - var _dataConnect = function() { - if (!YAHOO.util.Connect) { - return false; - } + + _getLabel: function() { + var el = this.get(LABEL_EL); + + if (!el) { + return undefined; + } + + return el.innerHTML; + }, - Dom.addClass(this.get('contentEl').parentNode, this.LOADING_CLASSNAME); - this._loading = true; - this.dataConnection = YAHOO.util.Connect.asyncRequest( - this.get('loadMethod'), - this.get('dataSrc'), - { - success: function(o) { - this.loadHandler.success.call(this, o); - this.set('dataLoaded', true); - this.dataConnection = null; - Dom.removeClass(this.get('contentEl').parentNode, - this.LOADING_CLASSNAME); - this._loading = false; - }, - failure: function(o) { - this.loadHandler.failure.call(this, o); - this.dataConnection = null; - Dom.removeClass(this.get('contentEl').parentNode, - this.LOADING_CLASSNAME); - this._loading = false; - }, - scope: this, - timeout: this.get('dataTimeout') + _onActivate: function(e, tabview) { + var tab = this, + silent = false; + + + Y.Event.preventDefault(e); + if (tab === tabview.get(ACTIVE_TAB)) { + silent = true; // dont fire activeTabChange if already active } - ); - }; + tabview.set(ACTIVE_TAB, tab, silent); + } + }); - YAHOO.widget.Tab = Tab; /** - * Fires before the active state is changed. - *

See: Element.addListener

- *

If handler returns false, the change will be cancelled, and the value will not - * be set.

- *

Event fields:
- * <String> type beforeActiveChange
- * <Boolean> - * prevValue the current value
- * <Boolean> - * newValue the new value

- *

Usage:
- * var handler = function(e) {var previous = e.prevValue};
- * myTabs.addListener('beforeActiveChange', handler);

- * @event beforeActiveChange + * Fires when a tab is removed from the tabview + * @event remove + * @type CustomEvent + * @param {Event} An event object with fields for "type" ("remove") + * and "tabview" (the tabview instance it was removed from) */ - - /** - * Fires after the active state is changed. - *

See: Element.addListener

- *

Event fields:
- * <String> type activeChange
- * <Boolean> - * prevValue the previous value
- * <Boolean> - * newValue the updated value

- *

Usage:
- * var handler = function(e) {var previous = e.prevValue};
- * myTabs.addListener('activeChange', handler);

- * @event activeChange - */ - - /** - * Fires before the tab label is changed. - *

See: Element.addListener

- *

If handler returns false, the change will be cancelled, and the value will not - * be set.

- *

Event fields:
- * <String> type beforeLabelChange
- * <String> - * prevValue the current value
- * <String> - * newValue the new value

- *

Usage:
- * var handler = function(e) {var previous = e.prevValue};
- * myTabs.addListener('beforeLabelChange', handler);

- * @event beforeLabelChange - */ - - /** - * Fires after the tab label is changed. - *

See: Element.addListener

- *

Event fields:
- * <String> type labelChange
- * <String> - * prevValue the previous value
- * <String> - * newValue the updated value

- *

Usage:
- * var handler = function(e) {var previous = e.prevValue};
- * myTabs.addListener('labelChange', handler);

- * @event labelChange - */ - - /** - * Fires before the tab content is changed. - *

See: Element.addListener

- *

If handler returns false, the change will be cancelled, and the value will not - * be set.

- *

Event fields:
- * <String> type beforeContentChange
- * <String> - * prevValue the current value
- * <String> - * newValue the new value

- *

Usage:
- * var handler = function(e) {var previous = e.prevValue};
- * myTabs.addListener('beforeContentChange', handler);

- * @event beforeContentChange - */ - - /** - * Fires after the tab content is changed. - *

See: Element.addListener

- *

Event fields:
- * <String> type contentChange
- * <String> - * prevValue the previous value
- * <Boolean> - * newValue the updated value

- *

Usage:
- * var handler = function(e) {var previous = e.prevValue};
- * myTabs.addListener('contentChange', handler);

- * @event contentChange - */ + + YAHOO.widget.Tab = Tab; })(); -YAHOO.register("tabview", YAHOO.widget.TabView, {version: "2.3.0", build: "442"}); +YAHOO.register("tabview", YAHOO.widget.TabView, {version: "2.7.0", build: "1799"});