From 541bb378ddece2eab135a8066a16994e94436dea Mon Sep 17 00:00:00 2001 From: Giulio Cesare Solaroli Date: Mon, 03 Oct 2011 16:04:12 +0000 Subject: Merge pull request #1 from gcsolaroli/master First version of the restructured repository --- (limited to 'frontend/beta/js/YUI/tabview.js') diff --git a/frontend/beta/js/YUI/tabview.js b/frontend/beta/js/YUI/tabview.js new file mode 100644 index 0000000..34a09bb --- a/dev/null +++ b/frontend/beta/js/YUI/tabview.js @@ -0,0 +1,1950 @@ +/* +Copyright (c) 2006, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 0.12.0 +*/ +(function() { + + YAHOO.util.Lang = { + isArray: function(val) { // frames lose type, so test constructor string + if (val.constructor && val.constructor.toString().indexOf('Array') > -1) { + return true; + } else { + return YAHOO.util.Lang.isObject(val) && val.constructor == Array; + } + }, + + isBoolean: function(val) { + return typeof val == 'boolean'; + }, + + isFunction: function(val) { + return typeof val == 'function'; + }, + + isNull: function(val) { + return val === null; + }, + + isNumber: function(val) { + return !isNaN(val); + }, + + isObject: function(val) { + return typeof val == 'object' || YAHOO.util.Lang.isFunction(val); + }, + + isString: function(val) { + return typeof val == 'string'; + }, + + isUndefined: function(val) { + return typeof val == 'undefined'; + } + }; +})();/** + * Provides Attribute configurations. + * @namespace YAHOO.util + * @class Attribute + * @constructor + * @param hash {Object} The intial Attribute. + * @param {YAHOO.util.AttributeProvider} The owner of the Attribute instance. + */ + +YAHOO.util.Attribute = function(hash, owner) { + if (owner) { + this.owner = owner; + this.configure(hash, true); + } +}; + +YAHOO.util.Attribute.prototype = { + /** + * The name of the attribute. + * @property name + * @type String + */ + name: undefined, + + /** + * The value of the attribute. + * @property value + * @type String + */ + value: null, + + /** + * The owner of the attribute. + * @property owner + * @type YAHOO.util.AttributeProvider + */ + owner: null, + + /** + * Whether or not the attribute is read only. + * @property readOnly + * @type Boolean + */ + readOnly: false, + + /** + * Whether or not the attribute can only be written once. + * @property writeOnce + * @type Boolean + */ + writeOnce: false, + + /** + * The attribute's initial configuration. + * @private + * @property _initialConfig + * @type Object + */ + _initialConfig: null, + + /** + * Whether or not the attribute's value has been set. + * @private + * @property _written + * @type Boolean + */ + _written: false, + + /** + * The method to use when setting the attribute's value. + * The method recieves the new value as the only argument. + * @property method + * @type Function + */ + method: null, + + /** + * The validator to use when setting the attribute's value. + * @property validator + * @type Function + * @return Boolean + */ + validator: null, + + /** + * Retrieves the current value of the attribute. + * @method getValue + * @return {any} The current value of the attribute. + */ + getValue: function() { + return this.value; + }, + + /** + * Sets the value of the attribute and fires beforeChange and change events. + * @method setValue + * @param {Any} value The value to apply to the attribute. + * @param {Boolean} silent If true the change events will not be fired. + * @return {Boolean} Whether or not the value was set. + */ + setValue: function(value, silent) { + var beforeRetVal; + var owner = this.owner; + var name = this.name; + + var event = { + type: name, + prevValue: this.getValue(), + newValue: value + }; + + if (this.readOnly || ( this.writeOnce && this._written) ) { + return false; // write not allowed + } + + if (this.validator && !this.validator.call(owner, value) ) { + return false; // invalid value + } + + if (!silent) { + beforeRetVal = owner.fireBeforeChangeEvent(event); + if (beforeRetVal === false) { + YAHOO.log('setValue ' + name + + 'cancelled by beforeChange event', 'info', 'Attribute'); + return false; + } + } + + if (this.method) { + this.method.call(owner, value); + } + + this.value = value; + this._written = true; + + event.type = name; + + if (!silent) { + this.owner.fireChangeEvent(event); + } + + return true; + }, + + /** + * Allows for configuring the Attribute's properties. + * @method configure + * @param {Object} map A key-value map of Attribute properties. + * @param {Boolean} init Whether or not this should become the initial config. + */ + configure: function(map, init) { + map = map || {}; + this._written = false; // reset writeOnce + this._initialConfig = this._initialConfig || {}; + + for (var key in map) { + if ( key && map.hasOwnProperty(key) ) { + this[key] = map[key]; + if (init) { + this._initialConfig[key] = map[key]; + } + } + } + }, + + /** + * Resets the value to the initial config value. + * @method resetValue + * @return {Boolean} Whether or not the value was set. + */ + resetValue: function() { + return this.setValue(this._initialConfig.value); + }, + + /** + * Resets the attribute config to the initial config state. + * @method resetConfig + */ + resetConfig: function() { + this.configure(this._initialConfig); + }, + + /** + * Resets the value to the current value. + * Useful when values may have gotten out of sync with actual properties. + * @method refresh + * @return {Boolean} Whether or not the value was set. + */ + refresh: function(silent) { + this.setValue(this.value, silent); + } +};(function() { + var Lang = YAHOO.util.Lang; + + /* + Copyright (c) 2006, Yahoo! Inc. All rights reserved. + Code licensed under the BSD License: + http://developer.yahoo.net/yui/license.txt + */ + + /** + * Provides and manages YAHOO.util.Attribute instances + * @namespace YAHOO.util + * @class AttributeProvider + * @uses YAHOO.util.EventProvider + */ + YAHOO.util.AttributeProvider = function() {}; + + YAHOO.util.AttributeProvider.prototype = { + + /** + * A key-value map of Attribute configurations + * @property _configs + * @protected (may be used by subclasses and augmentors) + * @private + * @type {Object} + */ + _configs: null, + /** + * Returns the current value of the attribute. + * @method get + * @param {String} key The attribute whose value will be returned. + */ + get: function(key){ + var configs = this._configs || {}; + var config = configs[key]; + + if (!config) { + YAHOO.log(key + ' not found', 'error', 'AttributeProvider'); + return undefined; + } + + return config.value; + }, + + /** + * Sets the value of a config. + * @method set + * @param {String} key The name of the attribute + * @param {Any} value The value to apply to the attribute + * @param {Boolean} silent Whether or not to suppress change events + * @return {Boolean} Whether or not the value was set. + */ + set: function(key, value, silent){ + var configs = this._configs || {}; + var config = configs[key]; + + if (!config) { + YAHOO.log('set failed: ' + key + ' not found', + 'error', 'AttributeProvider'); + return false; + } + + return config.setValue(value, silent); + }, + + /** + * Returns an array of attribute names. + * @method getAttributeKeys + * @return {Array} An array of attribute names. + */ + getAttributeKeys: function(){ + var configs = this._configs; + var keys = []; + var config; + for (var key in configs) { + config = configs[key]; + if ( configs.hasOwnProperty(key) && + !Lang.isUndefined(config) ) { + keys[keys.length] = key; + } + } + + return keys; + }, + + /** + * Sets multiple attribute values. + * @method setAttributes + * @param {Object} map A key-value map of attributes + * @param {Boolean} silent Whether or not to suppress change events + */ + setAttributes: function(map, silent){ + for (var key in map) { + if ( map.hasOwnProperty(key) ) { + this.set(key, map[key], silent); + } + } + }, + + /** + * Resets the specified attribute's value to its initial value. + * @method resetValue + * @param {String} key The name of the attribute + * @param {Boolean} silent Whether or not to suppress change events + * @return {Boolean} Whether or not the value was set + */ + resetValue: function(key, silent){ + var configs = this._configs || {}; + if (configs[key]) { + this.set(key, configs[key]._initialConfig.value, silent); + return true; + } + return false; + }, + + /** + * Sets the attribute's value to its current value. + * @method refresh + * @param {String | Array} key The attribute(s) to refresh + * @param {Boolean} silent Whether or not to suppress change events + */ + refresh: function(key, silent){ + var configs = this._configs; + + key = ( ( Lang.isString(key) ) ? [key] : key ) || + this.getAttributeKeys(); + + for (var i = 0, len = key.length; i < len; ++i) { + if ( // only set if there is a value and not null + configs[key[i]] && + ! Lang.isUndefined(configs[key[i]].value) && + ! Lang.isNull(configs[key[i]].value) ) { + configs[key[i]].refresh(silent); + } + } + }, + + /** + * Adds an Attribute to the AttributeProvider instance. + * @method register + * @param {String} key The attribute's name + * @param {Object} map A key-value map containing the + * attribute's properties. + */ + register: function(key, map) { + this._configs = this._configs || {}; + + if (this._configs[key]) { // dont override + return false; + } + + map.name = key; + this._configs[key] = new YAHOO.util.Attribute(map, this); + return true; + }, + + /** + * Returns the attribute's properties. + * @method getAttributeConfig + * @param {String} key The attribute's name + * @private + * @return {object} A key-value map containing all of the + * attribute's properties. + */ + getAttributeConfig: function(key) { + var configs = this._configs || {}; + var config = configs[key] || {}; + var map = {}; // returning a copy to prevent overrides + + for (key in config) { + if ( config.hasOwnProperty(key) ) { + map[key] = config[key]; + } + } + + return map; + }, + + /** + * Sets or updates an Attribute instance's properties. + * @method configureAttribute + * @param {String} key The attribute's name. + * @param {Object} map A key-value map of attribute properties + * @param {Boolean} init Whether or not this should become the intial config. + */ + configureAttribute: function(key, map, init) { + var configs = this._configs || {}; + + if (!configs[key]) { + YAHOO.log('unable to configure, ' + key + ' not found', + 'error', 'AttributeProvider'); + return false; + } + + configs[key].configure(map, init); + }, + + /** + * Resets an attribute to its intial configuration. + * @method resetAttributeConfig + * @param {String} key The attribute's name. + * @private + */ + resetAttributeConfig: function(key){ + var configs = this._configs || {}; + configs[key].resetConfig(); + }, + + /** + * Fires the attribute's beforeChange event. + * @method fireBeforeChangeEvent + * @param {String} key The attribute's name. + * @param {Obj} e The event object to pass to handlers. + */ + fireBeforeChangeEvent: function(e) { + var type = 'before'; + type += e.type.charAt(0).toUpperCase() + e.type.substr(1) + 'Change'; + e.type = type; + return this.fireEvent(e.type, e); + }, + + /** + * Fires the attribute's change event. + * @method fireChangeEvent + * @param {String} key The attribute's name. + * @param {Obj} e The event object to pass to the handlers. + */ + fireChangeEvent: function(e) { + e.type += 'Change'; + return this.fireEvent(e.type, e); + } + }; + + YAHOO.augment(YAHOO.util.AttributeProvider, YAHOO.util.EventProvider); +})();(function() { +// internal shorthand +var Dom = YAHOO.util.Dom, + Lang = YAHOO.util.Lang, + EventPublisher = YAHOO.util.EventPublisher, + AttributeProvider = YAHOO.util.AttributeProvider; + +/** + * Element provides an interface to an HTMLElement's attributes and common + * methods. Other commonly used attributes are added as well. + * @namespace YAHOO.util + * @class Element + * @uses YAHOO.util.AttributeProvider + * @constructor + * @param el {HTMLElement | String} The html element that + * represents the Element. + * @param {Object} map A key-value map of initial config names and values + */ +YAHOO.util.Element = function(el, map) { + if (arguments.length) { + this.init(el, map); + } +}; + +YAHOO.util.Element.prototype = { + /** + * Dom events supported by the Element instance. + * @property DOM_EVENTS + * @type Object + */ + DOM_EVENTS: null, + + /** + * Wrapper for HTMLElement method. + * @method appendChild + * @param {Boolean} deep Whether or not to do a deep clone + */ + appendChild: function(child) { + child = child.get ? child.get('element') : child; + this.get('element').appendChild(child); + }, + + /** + * Wrapper for HTMLElement method. + * @method getElementsByTagName + * @param {String} tag The tagName to collect + */ + getElementsByTagName: function(tag) { + return this.get('element').getElementsByTagName(tag); + }, + + /** + * Wrapper for HTMLElement method. + * @method hasChildNodes + * @return {Boolean} Whether or not the element has childNodes + */ + hasChildNodes: function() { + return this.get('element').hasChildNodes(); + }, + + /** + * Wrapper for HTMLElement method. + * @method insertBefore + * @param {HTMLElement} element The HTMLElement to insert + * @param {HTMLElement} before The HTMLElement to insert + * the element before. + */ + insertBefore: function(element, before) { + element = element.get ? element.get('element') : element; + before = (before && before.get) ? before.get('element') : before; + + this.get('element').insertBefore(element, before); + }, + + /** + * Wrapper for HTMLElement method. + * @method removeChild + * @param {HTMLElement} child The HTMLElement to remove + */ + removeChild: function(child) { + child = child.get ? child.get('element') : child; + this.get('element').removeChild(child); + return true; + }, + + /** + * Wrapper for HTMLElement method. + * @method replaceChild + * @param {HTMLElement} newNode The HTMLElement to insert + * @param {HTMLElement} oldNode The HTMLElement to replace + */ + replaceChild: function(newNode, oldNode) { + newNode = newNode.get ? newNode.get('element') : newNode; + oldNode = oldNode.get ? oldNode.get('element') : oldNode; + return this.get('element').replaceChild(newNode, oldNode); + }, + + + /** + * Registers Element specific attributes. + * @method initAttributes + * @param {Object} map A key-value map of initial attribute configs + */ + initAttributes: function(map) { + map = map || {}; + var element = Dom.get(map.element) || null; + + /** + * The HTMLElement the Element instance refers to. + * @config element + * @type HTMLElement + */ + this.register('element', { + value: element, + readOnly: true + }); + }, + + /** + * Adds a listener for the given event. These may be DOM or + * customEvent listeners. Any event that is fired via fireEvent + * can be listened for. All handlers receive an event object. + * @method addListener + * @param {String} type The name of the event to listen for + * @param {Function} fn The handler to call when the event fires + * @param {Any} obj A variable to pass to the handler + * @param {Object} scope The object to use for the scope of the handler + */ + addListener: function(type, fn, obj, scope) { + var el = this.get('element'); + var scope = scope || this; + + el = this.get('id') || el; + + if (!this._events[type]) { // create on the fly + if ( this.DOM_EVENTS[type] ) { + YAHOO.util.Event.addListener(el, type, function(e) { + if (e.srcElement && !e.target) { // supplement IE with target + e.target = e.srcElement; + } + this.fireEvent(type, e); + }, obj, scope); + } + + this.createEvent(type, this); + this._events[type] = true; + } + + this.subscribe.apply(this, arguments); // notify via customEvent + }, + + + /** + * Alias for addListener + * @method on + * @param {String} type The name of the event to listen for + * @param {Function} fn The function call when the event fires + * @param {Any} obj A variable to pass to the handler + * @param {Object} scope The object to use for the scope of the handler + */ + on: function() { this.addListener.apply(this, arguments); }, + + + /** + * Remove an event listener + * @method removeListener + * @param {String} type The name of the event to listen for + * @param {Function} fn The function call when the event fires + */ + removeListener: function(type, fn) { + this.unsubscribe.apply(this, arguments); + }, + + /** + * Wrapper for Dom method. + * @method addClass + * @param {String} className The className to add + */ + addClass: function(className) { + Dom.addClass(this.get('element'), className); + }, + + /** + * Wrapper for Dom method. + * @method getElementsByClassName + * @param {String} className The className to collect + * @param {String} tag (optional) The tag to use in + * conjunction with class name + * @return {Array} Array of HTMLElements + */ + getElementsByClassName: function(className, tag) { + return Dom.getElementsByClassName(className, tag, + this.get('element') ); + }, + + /** + * Wrapper for Dom method. + * @method hasClass + * @param {String} className The className to add + * @return {Boolean} Whether or not the element has the class name + */ + hasClass: function(className) { + return Dom.hasClass(this.get('element'), className); + }, + + /** + * Wrapper for Dom method. + * @method removeClass + * @param {String} className The className to remove + */ + removeClass: function(className) { + return Dom.removeClass(this.get('element'), className); + }, + + /** + * Wrapper for Dom method. + * @method replaceClass + * @param {String} oldClassName The className to replace + * @param {String} newClassName The className to add + */ + replaceClass: function(oldClassName, newClassName) { + return Dom.replaceClass(this.get('element'), + oldClassName, newClassName); + }, + + /** + * Wrapper for Dom method. + * @method setStyle + * @param {String} property The style property to set + * @param {String} value The value to apply to the style property + */ + setStyle: function(property, value) { + return Dom.setStyle(this.get('element'), property, value); + }, + + /** + * Wrapper for Dom method. + * @method getStyle + * @param {String} property The style property to retrieve + * @return {String} The current value of the property + */ + getStyle: function(property) { + return Dom.getStyle(this.get('element'), property); + }, + + /** + * Apply any queued set calls. + * @method fireQueue + */ + fireQueue: function() { + var queue = this._queue; + for (var i = 0, len = queue.length; i < len; ++i) { + this[queue[i][0]].apply(this, queue[i][1]); + } + }, + + /** + * Appends the HTMLElement into either the supplied parentNode. + * @method appendTo + * @param {HTMLElement | Element} parentNode The node to append to + * @param {HTMLElement | Element} before An optional node to insert before + */ + appendTo: function(parent, before) { + parent = (parent.get) ? parent.get('element') : Dom.get(parent); + + before = (before && before.get) ? + before.get('element') : Dom.get(before); + var element = this.get('element'); + + var newAddition = !Dom.inDocument(element); + + if (!element) { + YAHOO.log('appendTo failed: element not available', + 'error', 'Element'); + return false; + } + + if (!parent) { + YAHOO.log('appendTo failed: parent not available', + 'error', 'Element'); + return false; + } + + if (element.parent != parent) { + if (before) { + parent.insertBefore(element, before); + } else { + parent.appendChild(element); + } + } + + YAHOO.log(element + 'appended to ' + parent); + + if (!newAddition) { + return false; // note return; no refresh if in document + } + + // if a new addition, refresh HTMLElement any applied attributes + var keys = this.getAttributeKeys(); + + for (var key in keys) { // only refresh HTMLElement attributes + if ( !Lang.isUndefined(element[key]) ) { + this.refresh(key); + } + } + }, + + get: function(key) { + var configs = this._configs || {}; + var el = configs.element; // avoid loop due to 'element' + if (el && !configs[key] && !Lang.isUndefined(el.value[key]) ) { + return el.value[key]; + } + + return AttributeProvider.prototype.get.call(this, key); + }, + + set: function(key, value, silent) { + var el = this.get('element'); + if (!el) { + this._queue[key] = ['set', arguments]; + return false; + } + + // set it on the element if not a property + if ( !this._configs[key] && !Lang.isUndefined(el[key]) ) { + _registerHTMLAttr(this, key); + } + + return AttributeProvider.prototype.set.apply(this, arguments); + }, + + register: function(key) { // protect html attributes + var configs = this._configs || {}; + var element = this.get('element') || null; + + if ( element && !Lang.isUndefined(element[key]) ) { + YAHOO.log(key + ' is reserved for ' + element, + 'error', 'Element'); + return false; + } + + return AttributeProvider.prototype.register.apply(this, arguments); + }, + + configureAttribute: function(property, map, init) { // protect html attributes + if (!this._configs[property] && this._configs.element && + !Lang.isUndefined(this._configs.element[property]) ) { + _registerHTMLAttr(this, property, map); + return false; + } + + return AttributeProvider.prototype.configure.apply(this, arguments); + }, + + getAttributeKeys: function() { + var el = this.get('element'); + var keys = AttributeProvider.prototype.getAttributeKeys.call(this); + + //add any unconfigured element keys + for (var key in el) { + if (!this._configs[key]) { + keys[key] = keys[key] || el[key]; + } + } + + return keys; + }, + + init: function(el, attr) { + this._queue = this._queue || []; + this._events = this._events || {}; + this._configs = this._configs || {}; + attr = attr || {}; + attr.element = attr.element || el || null; + + this.DOM_EVENTS = { + 'click': true, + 'keydown': true, + 'keypress': true, + 'keyup': true, + 'mousedown': true, + 'mousemove': true, + 'mouseout': true, + 'mouseover': true, + 'mouseup': true + }; + + var readyHandler = function() { + this.initAttributes(attr); + + this.setAttributes(attr, true); + this.fireQueue(); + this.fireEvent('contentReady', { + type: 'contentReady', + target: attr.element + }); + }; + + if ( Lang.isString(el) ) { + _registerHTMLAttr(this, 'id', { value: el }); + YAHOO.util.Event.onAvailable(el, function() { + attr.element = Dom.get(el); + this.fireEvent('available', { + type: 'available', + target: attr.element + }); + }, this, true); + + YAHOO.util.Event.onContentReady(el, function() { + readyHandler.call(this); + }, this, true); + } else { + readyHandler.call(this); + } + } +}; + +/** + * Sets the value of the property and fires beforeChange and change events. + * @private + * @method _registerHTMLAttr + * @param {YAHOO.util.Element} element The Element instance to + * register the config to. + * @param {String} key The name of the config to register + * @param {Object} map A key-value map of the config's params + */ +var _registerHTMLAttr = function(self, key, map) { + var el = self.get('element'); + map = map || {}; + map.name = key; + map.method = map.method || function(value) { + el[key] = value; + }; + map.value = map.value || el[key]; + self._configs[key] = new YAHOO.util.Attribute(map, self); +}; + +/** + * Fires when the Element's HTMLElement can be retrieved by Id. + *

See: Element.addListener

+ *

Event fields:
+ * <String> type available
+ * <HTMLElement> + * target the HTMLElement bound to this Element instance
+ *

Usage:
+ * var handler = function(e) {var target = e.target};
+ * myTabs.addListener('available', handler);

+ * @event available + */ + +/** + * Fires when the Element's HTMLElement subtree is rendered. + *

See: Element.addListener

+ *

Event fields:
+ * <String> type contentReady
+ * <HTMLElement> + * target the HTMLElement bound to this Element instance
+ *

Usage:
+ * var handler = function(e) {var target = e.target};
+ * myTabs.addListener('contentReady', handler);

+ * @event contentReady + */ + +YAHOO.augment(YAHOO.util.Element, AttributeProvider); +})();(function() { + var Dom = YAHOO.util.Dom, + Event = YAHOO.util.Event, + Lang = YAHOO.util.Lang; + + /** + * A representation of a Tab's label and content. + * @namespace YAHOO.widget + * @class Tab + * @extends YAHOO.util.Element + * @constructor + * @param element {HTMLElement | String} (optional) The html element that + * represents the TabView. An element will be created if none provided. + * @param {Object} properties A key map of initial properties + */ + Tab = function(el, attr) { + attr = attr || {}; + if (arguments.length == 1 && !Lang.isString(el) && !el.nodeName) { + attr = el; + el = attr.element; + } + + if (!el && !attr.element) { + el = _createTabElement.call(this, attr); + } + + this.loadHandler = { + success: function(o) { + this.set('content', o.responseText); + }, + failure: function(o) { + YAHOO.log('loading failed: ' + o.statusText, + 'error', 'Tab'); + } + }; + + Tab.superclass.constructor.call(this, el, attr); + + 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; + + /** + * 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; + }; + + /** + * Registers 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'); + + /** + * The event that triggers the tab's activation. + * @config activationEvent + * @type String + */ + this.register('activationEvent', { + value: attr.activationEvent || 'click' + }); + + /** + * The element that contains the tab's label. + * @config labelEl + * @type HTMLElement + */ + this.register('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 + * @type String + */ + this.register('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); + } + }); + + /** + * The HTMLElement that contains the tab's content. + * @config contentEl + * @type HTMLElement + */ + this.register('contentEl', { // TODO: apply className? + 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); + } + } + }); + + /** + * The tab's content. + * @config content + * @type String + */ + this.register('content', { + value: attr.content, // TODO: what about existing? + method: function(value) { + this.get('contentEl').innerHTML = value; + } + }); + + var _dataLoaded = false; + + /** + * The tab's data source, used for loading content dynamically. + * @config dataSrc + * @type String + */ + this.register('dataSrc', { + value: attr.dataSrc + }); + + /** + * Whether or not content should be reloaded for every view. + * @config cacheData + * @type Boolean + * @default false + */ + this.register('cacheData', { + value: attr.cacheData || false, + validator: Lang.isBoolean + }); + + /** + * The method to use for the data request. + * @config loadMethod + * @type String + * @default "GET" + */ + this.register('loadMethod', { + value: attr.loadMethod || 'GET', + validator: Lang.isString + }); + + /** + * Whether or not any data has been loaded from the server. + * @config dataLoaded + * @type Boolean + */ + this.register('dataLoaded', { + value: false, + validator: Lang.isBoolean, + writeOnce: true + }); + + /** + * Number if milliseconds before aborting and calling failure handler. + * @config dataTimeout + * @type Number + * @default null + */ + this.register('dataTimeout', { + value: attr.dataTimeout || null, + validator: Lang.isNumber + }); + + /** + * 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 + */ + this.register('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 Lang.isBoolean(value) && !this.get('disabled') ; + } + }); + + /** + * Whether or not the tab is disabled. + * @config disabled + * @type Boolean + */ + this.register('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. + * @config href + * @type String + * @default '#' + */ + this.register('href', { + value: attr.href || '#', + method: function(value) { + this.getElementsByTagName('a')[0].href = value; + }, + validator: Lang.isString + }); + + /** + * The Whether or not the tab's content is visible. + * @config contentVisible + * @type Boolean + * @default false + */ + this.register('contentVisible', { + value: attr.contentVisible, + method: function(value) { + if (value == true) { + this.get('contentEl').style.display = 'block'; + + if ( this.get('dataSrc') ) { + // load dynamic content unless already loaded and caching + if ( !this.get('dataLoaded') || !this.get('cacheData') ) { + _dataConnect.call(this); + } + } + } else { + this.get('contentEl').style.display = 'none'; + } + }, + validator: Lang.isBoolean + }); + }; + + var _createTabElement = function(attr) { + var el = document.createElement('li'); + var a = document.createElement('a'); + + 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); + } + } 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'); + + if (!el) { + return undefined; + } + + return el.innerHTML; + }; + + var _dataConnect = function() { + if (!YAHOO.util.Connect) { + YAHOO.log('YAHOO.util.Connect dependency not met', + 'error', 'Tab'); + return false; + } + + Dom.addClass(this.get('contentEl').parentNode, this.LOADING_CLASSNAME); + + 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); + }, + failure: function(o) { + this.loadHandler.failure.call(this, o); + this.dataConnection = null; + Dom.removeClass(this.get('contentEl').parentNode, + this.LOADING_CLASSNAME); + }, + scope: this, + timeout: this.get('dataTimeout') + } + ); + }; + + 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 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 + */ +})();(function() { + + /** + * The tabview module provides a widget for managing content bound to tabs. + * @module tabview + * + */ + /** + * A widget to control tabbed views. + * @namespace YAHOO.widget + * @class TabView + * @extends YAHOO.util.Element + * @constructor + * @param {HTMLElement | String | Object} el(optional) The html + * element that represents the TabView, or the attribute object to use. + * An element will be created if none provided. + * @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) { + attr = attr || {}; + if (arguments.length == 1 && !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); + } + YAHOO.widget.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 Lang = YAHOO.util.Lang; + 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; + } + + index = (index === undefined) ? tabs.length : index; + + var before = this.getTab(index); + + 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); + } + + if ( !tab.get('active') ) { + tab.set('contentVisible', false, true); /* hide if not active */ + } else { + this.set('activeTab', tab, true); + + } + + var activate = function(e) { + YAHOO.util.Event.preventDefault(e); + self.set('activeTab', this); + }; + + 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); + } + }); + + 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'); + + 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 + } + } + + 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; + + 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); + } + } + } + + 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); + }; + + /** + * Registers TabView specific properties. + * @method initAttributes + * @param {Object} attr Hash of initial attributes + */ + proto.initAttributes = function(attr) { + YAHOO.widget.TabView.superclass.initAttributes.call(this, attr); + + if (!attr.orientation) { + attr.orientation = 'top'; + } + + var el = this.get('element'); + + /** + * The Tabs belonging to the TabView instance. + * @config tabs + * @type Array + */ + this.register('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] || _createTabParent.call(this); + + /** + * The container of the tabView's content elements. + * @property _contentParent + * @type HTMLElement + * @private + */ + this._contentParent = + this.getElementsByClassName(this.CONTENT_PARENT_CLASSNAME, + 'div')[0] || _createContentParent.call(this); + + /** + * How the Tabs should be oriented relative to the TabView. + * @config orientation + * @type String + * @default "top" + */ + this.register('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); + } + + switch(value) { + case 'bottom': + this.appendChild(this._tabParent); + break; + } + } + }); + + /** + * The index of the tab currently active. + * @config activeIndex + * @type Int + */ + this.register('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 + } + }); + + /** + * The tab currently active. + * @config activeTab + * @type YAHOO.widget.Tab + */ + this.register('activeTab', { + value: attr.activeTab, + method: function(tab) { + var activeTab = this.get('activeTab'); + + 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) { + return !value.get('disabled'); // cannot activate if disabled + } + }); + + if ( this._tabParent ) { + _initTabs.call(this); + } + + for (var type in this.DOM_EVENTS) { + if ( this.DOM_EVENTS.hasOwnProperty(type) ) { + this.addListener.call(this, type, this.DOMEventHandler); + } + } + }; + + /** + * Creates Tab instances from a collection of HTMLElements. + * @method createTabs + * @private + * @param {Array|HTMLCollection} elements The elements to use for Tabs. + * @return void + */ + var _initTabs = function() { + var tab, + attr, + contentEl; + + var el = this.get('element'); + var tabs = _getChildNodes(this._tabParent); + var contentElements = _getChildNodes(this._contentParent); + + for (var i = 0, len = tabs.length; i < len; ++i) { + attr = {}; + + if (contentElements[i]) { + attr.contentEl = contentElements[i]; + } + + 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 + } + } + }; + + var _createTabViewElement = function(attr) { + var el = document.createElement('div'); + + if ( this.CLASSNAME ) { + el.className = this.CLASSNAME; + } + + return el; + }; + + var _createTabParent = function(attr) { + var el = document.createElement('ul'); + + 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]; + } + } + + 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 + */ +})(); \ No newline at end of file -- cgit v0.9.0.2