diff -r 000000000000 -r 40c8f766c9b8 src/cm/media/js/lib/yui/yui3.0.0/build/attribute/attribute-debug.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/cm/media/js/lib/yui/yui3.0.0/build/attribute/attribute-debug.js Mon Nov 23 15:14:29 2009 +0100 @@ -0,0 +1,1196 @@ +/* +Copyright (c) 2009, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 3.0.0 +build: 1549 +*/ +YUI.add('attribute-base', function(Y) { + + /** + * The State class maintains state for a collection of named items, with + * a varying number of properties defined. + * + * It avoids the need to create a separate class for the item, and separate instances + * of these classes for each item, by storing the state in a 2 level hash table, + * improving performance when the number of items is likely to be large. + * + * @constructor + * @class State + */ + Y.State = function() { + /** + * Hash of attributes + * @property data + */ + this.data = {}; + }; + + Y.State.prototype = { + + /** + * Adds a property to an item. + * + * @method add + * @param name {String} The name of the item. + * @param key {String} The name of the property. + * @param val {Any} The value of the property. + */ + add : function(name, key, val) { + var d = this.data; + d[key] = d[key] || {}; + d[key][name] = val; + }, + + /** + * Adds multiple properties to an item. + * + * @method addAll + * @param name {String} The name of the item. + * @param o {Object} A hash of property/value pairs. + */ + addAll: function(name, o) { + var key; + for (key in o) { + if (o.hasOwnProperty(key)) { + this.add(name, key, o[key]); + } + } + }, + + /** + * Removes a property from an item. + * + * @method remove + * @param name {String} The name of the item. + * @param key {String} The property to remove. + */ + remove: function(name, key) { + var d = this.data; + if (d[key] && (name in d[key])) { + delete d[key][name]; + } + }, + + /** + * Removes multiple properties from an item, or remove the item completely. + * + * @method removeAll + * @param name {String} The name of the item. + * @param o {Object|Array} Collection of properties to delete. If not provided, the entire item is removed. + */ + removeAll: function(name, o) { + var d = this.data; + + Y.each(o || d, function(v, k) { + if(Y.Lang.isString(k)) { + this.remove(name, k); + } else { + this.remove(name, v); + } + }, this); + }, + + /** + * For a given item, returns the value of the property requested, or undefined if not found. + * + * @method get + * @param name {String} The name of the item + * @param key {String} Optional. The property value to retrieve. + * @return {Any} The value of the supplied property. + */ + get: function(name, key) { + var d = this.data; + return (d[key] && name in d[key]) ? d[key][name] : undefined; + }, + + /** + * For the given item, returns a disposable object with all of the + * item's property/value pairs. + * + * @method getAll + * @param name {String} The name of the item + * @return {Object} An object with property/value pairs for the item. + */ + getAll : function(name) { + var d = this.data, o; + + Y.each(d, function(v, k) { + if (name in d[k]) { + o = o || {}; + o[k] = v[name]; + } + }, this); + + return o; + } + }; + /** + * The attribute module provides an augmentable Attribute implementation, which + * adds configurable attributes and attribute change events to the class being + * augmented. It also provides a State class, which is used internally by Attribute, + * but can also be used independently to provide a name/property/value data structure to + * store state. + * + * @module attribute + */ + + /** + * The attribute-base submodule provides core attribute handling support, with everything + * aside from complex attribute handling in the provider's constructor. + * + * @module attribute + * @submodule attribute-base + */ + var O = Y.Object, + Lang = Y.Lang, + EventTarget = Y.EventTarget, + + DOT = ".", + CHANGE = "Change", + + // Externally configurable props + GETTER = "getter", + SETTER = "setter", + READ_ONLY = "readOnly", + WRITE_ONCE = "writeOnce", + VALIDATOR = "validator", + VALUE = "value", + VALUE_FN = "valueFn", + BROADCAST = "broadcast", + LAZY_ADD = "lazyAdd", + BYPASS_PROXY = "_bypassProxy", + + // Used for internal state management + ADDED = "added", + INITIALIZING = "initializing", + INIT_VALUE = "initValue", + PUBLISHED = "published", + DEF_VALUE = "defaultValue", + LAZY = "lazy", + IS_LAZY_ADD = "isLazyAdd", + + INVALID_VALUE, + MODIFIABLE = {}; + + // Properties which can be changed after the attribute has been added. + MODIFIABLE[READ_ONLY] = 1; + MODIFIABLE[WRITE_ONCE] = 1; + MODIFIABLE[GETTER] = 1; + MODIFIABLE[BROADCAST] = 1; + + /** + *

+ * Attribute provides configurable attribute support along with attribute change events. It is designed to be + * augmented on to a host class, and provides the host with the ability to configure attributes to store and retrieve state, + * along with attribute change events. + *

+ *

For example, attributes added to the host can be configured:

+ * + * + *

See the addAttr method, for the complete set of configuration + * options available for attributes

. + * + *

NOTE: Most implementations will be better off extending the Base class, + * instead of augmenting Attribute directly. Base augments Attribute and will handle the initial configuration + * of attributes for derived classes, accounting for values passed into the constructor.

+ * + * @class Attribute + * @uses EventTarget + */ + function Attribute() { + Y.log('Attribute constructor called', 'info', 'attribute'); + + var host = this, // help compression + attrs = this.constructor.ATTRS, + Base = Y.Base; + + // Perf tweak - avoid creating event literals if not required. + host._ATTR_E_FACADE = {}; + + EventTarget.call(host, {emitFacade:true}); + + // _conf maintained for backwards compat + host._conf = host._state = new Y.State(); + + host._stateProxy = host._stateProxy || null; + host._requireAddAttr = host._requireAddAttr || false; + + // ATTRS support for Node, which is not Base based + if ( attrs && !(Base && host instanceof Base)) { + host.addAttrs(this._protectAttrs(attrs)); + } + } + + /** + *

The value to return from an attribute setter in order to prevent the set from going through.

+ * + *

You can return this value from your setter if you wish to combine validator and setter + * functionality into a single setter function, which either returns the massaged value to be stored or + * Attribute.INVALID_VALUE to prevent invalid values from being stored.

+ * + * @property Attribute.INVALID_VALUE + * @type Object + * @static + * @final + */ + Attribute.INVALID_VALUE = {}; + INVALID_VALUE = Attribute.INVALID_VALUE; + + /** + * The list of properties which can be configured for + * each attribute (e.g. setter, getter, writeOnce etc.). + * + * This property is used internally as a whitelist for faster + * Y.mix operations. + * + * @property Attribute._ATTR_CFG + * @type Array + * @static + * @protected + */ + Attribute._ATTR_CFG = [SETTER, GETTER, VALIDATOR, VALUE, VALUE_FN, WRITE_ONCE, READ_ONLY, LAZY_ADD, BROADCAST, BYPASS_PROXY]; + + Attribute.prototype = { + /** + *

+ * Adds an attribute with the provided configuration to the host object. + *

+ *

+ * The config argument object supports the following properties: + *

+ * + *
+ *
value <Any>
+ *
The initial value to set on the attribute
+ * + *
valueFn <Function>
+ *
A function, which will return the initial value to set on the attribute. This is useful + * for cases where the attribute configuration is defined statically, but needs to + * reference the host instance ("this") to obtain an initial value. + * If defined, this precedence over the value property.
+ * + *
readOnly <boolean>
+ *
Whether or not the attribute is read only. Attributes having readOnly set to true + * cannot be modified by invoking the set method.
+ * + *
writeOnce <boolean>
+ *
Whether or not the attribute is "write once". Attributes having writeOnce set to true, + * can only have their values set once, be it through the default configuration, + * constructor configuration arguments, or by invoking set.
+ * + *
setter <Function>
+ *
The setter function used to massage or normalize the value passed to the set method for the attribute. + * The value returned by the setter will be the final stored value. Returning + * Attribute.INVALID_VALUE, from the setter will prevent + * the value from being stored.
+ * + *
getter <Function>
+ *
The getter function used to massage or normalize the value returned by the get method for the attribute. + * The value returned by the getter function is the value which will be returned to the user when they + * invoke get.
+ * + *
validator <Function>
+ *
The validator function invoked prior to setting the stored value. Returning + * false from the validator function will prevent the value from being stored.
+ * + *
broadcast <int>
+ *
If and how attribute change events for this attribute should be broadcast. See CustomEvent's broadcast property for + * valid values. By default attribute change events are not broadcast.
+ * + *
lazyAdd <boolean>
+ *
Whether or not to delay initialization of the attribute until the first call to get/set it. + * This flag can be used to over-ride lazy initialization on a per attribute basis, when adding multiple attributes through + * the addAttrs method.
+ * + *
+ * + *

The setter, getter and validator are invoked with the value and name passed in as the first and second arguments, and with + * the context ("this") set to the host object.

+ * + *

Configuration properties outside of the list mentioned above are considered private properties used internally by attribute, and are not intended for public use.

+ * + * @method addAttr + * + * @param {String} name The name of the attribute. + * @param {Object} config An object with attribute configuration property/value pairs, specifying the configuration for the attribute. + * + *

+ * NOTE: The configuration object is modified when adding an attribute, so if you need + * to protect the original values, you will need to merge the object. + *

+ * + * @param {boolean} lazy (optional) Whether or not to add this attribute lazily (on the first call to get/set). + * + * @return {Object} A reference to the host object. + * + * @chainable + */ + addAttr: function(name, config, lazy) { + + Y.log('Adding attribute: ' + name, 'info', 'attribute'); + + var host = this, // help compression + state = host._state, + value, + hasValue; + + lazy = (LAZY_ADD in config) ? config[LAZY_ADD] : lazy; + + if (lazy && !host.attrAdded(name)) { + state.add(name, LAZY, config || {}); + state.add(name, ADDED, true); + } else { + + if (host.attrAdded(name) && !state.get(name, IS_LAZY_ADD)) { Y.log('Attribute: ' + name + ' already exists. Cannot add it again without removing it first', 'warn', 'attribute'); } + + if (!host.attrAdded(name) || state.get(name, IS_LAZY_ADD)) { + + config = config || {}; + + hasValue = (VALUE in config); + + if (config.readOnly && !hasValue) { Y.log('readOnly attribute: ' + name + ', added without an initial value. Value will be set on initial call to set', 'warn', 'attribute');} + + if(hasValue) { + // We'll go through set, don't want to set value in _state directly + value = config.value; + delete config.value; + } + + config.added = true; + config.initializing = true; + + state.addAll(name, config); + + if (hasValue) { + // Go through set, so that raw values get normalized/validated + host.set(name, value); + } + + state.remove(name, INITIALIZING); + } + } + + return host; + }, + + /** + * Checks if the given attribute has been added to the host + * + * @method attrAdded + * @param {String} name The name of the attribute to check. + * @return {boolean} true if an attribute with the given name has been added, false if it hasn't. This method will return true for lazily added attributes. + */ + attrAdded: function(name) { + return !!this._state.get(name, ADDED); + }, + + /** + * Updates the configuration of an attribute which has already been added. + *

+ * The properties which can be modified through this interface are limited + * to the following subset of attributes, which can be safely modified + * after a value has already been set on the attribute: readOnly, writeOnce, + * broadcast and getter. + *

+ * @method modifyAttr + * @param {String} name The name of the attribute whose configuration is to be updated. + * @param {Object} config An object with configuration property/value pairs, specifying the configuration properties to modify. + */ + modifyAttr: function(name, config) { + var host = this, // help compression + prop, state; + + if (host.attrAdded(name)) { + + if (host._isLazyAttr(name)) { + host._addLazyAttr(name); + } + + state = host._state; + for (prop in config) { + if (MODIFIABLE[prop] && config.hasOwnProperty(prop)) { + state.add(name, prop, config[prop]); + + // If we reconfigured broadcast, need to republish + if (prop === BROADCAST) { + state.remove(name, PUBLISHED); + } + } + } + } + + if (!host.attrAdded(name)) {Y.log('Attribute modifyAttr:' + name + ' has not been added. Use addAttr to add the attribute', 'warn', 'attribute');} + }, + + /** + * Removes an attribute from the host object + * + * @method removeAttr + * @param {String} name The name of the attribute to be removed. + */ + removeAttr: function(name) { + this._state.removeAll(name); + }, + + /** + * Returns the current value of the attribute. If the attribute + * has been configured with a 'getter' function, this method will delegate + * to the 'getter' to obtain the value of the attribute. + * + * @method get + * + * @param {String} name The name of the attribute. If the value of the attribute is an Object, + * dot notation can be used to obtain the value of a property of the object (e.g. get("x.y.z")) + * + * @return {Any} The value of the attribute + */ + get : function(name) { + return this._getAttr(name); + }, + + /** + * Checks whether or not the attribute is one which has been + * added lazily and still requires initialization. + * + * @method _isLazyAttr + * @private + * @param {String} name The name of the attribute + * @return {boolean} true if it's a lazily added attribute, false otherwise. + */ + _isLazyAttr: function(name) { + return this._state.get(name, LAZY); + }, + + /** + * Finishes initializing an attribute which has been lazily added. + * + * @method _addLazyAttr + * @private + * @param {Object} name The name of the attribute + */ + _addLazyAttr: function(name) { + var state = this._state, + lazyCfg = state.get(name, LAZY); + + state.add(name, IS_LAZY_ADD, true); + state.remove(name, LAZY); + this.addAttr(name, lazyCfg); + }, + + /** + * Sets the value of an attribute. + * + * @method set + * @chainable + * + * @param {String} name The name of the attribute. If the + * current value of the attribute is an Object, dot notation can be used + * to set the value of a property within the object (e.g. set("x.y.z", 5)). + * + * @param {Any} value The value to set the attribute to. + * + * @param {Object} opts (Optional) Optional event data to be mixed into + * the event facade passed to subscribers of the attribute's change event. This + * can be used as a flexible way to identify the source of a call to set, allowing + * the developer to distinguish between set called internally by the host, vs. + * set called externally by the application developer. + * + * @return {Object} A reference to the host object. + */ + set : function(name, val, opts) { + return this._setAttr(name, val, opts); + }, + + /** + * Resets the attribute (or all attributes) to its initial value, as long as + * the attribute is not readOnly, or writeOnce. + * + * @method reset + * @param {String} name Optional. The name of the attribute to reset. If omitted, all attributes are reset. + * @return {Object} A reference to the host object. + * @chainable + */ + reset : function(name) { + var host = this, // help compression + added; + + if (name) { + if (host._isLazyAttr(name)) { + host._addLazyAttr(name); + } + host.set(name, host._state.get(name, INIT_VALUE)); + } else { + added = host._state.data.added; + Y.each(added, function(v, n) { + host.reset(n); + }, host); + } + return host; + }, + + /** + * Allows setting of readOnly/writeOnce attributes. See set for argument details. + * + * @method _set + * @protected + * @chainable + * + * @param {String} name The name of the attribute. + * @param {Any} val The value to set the attribute to. + * @param {Object} opts (Optional) Optional event data to be mixed into + * the event facade passed to subscribers of the attribute's change event. + * @return {Object} A reference to the host object. + */ + _set : function(name, val, opts) { + return this._setAttr(name, val, opts, true); + }, + + /** + * Provides the common implementation for the public get method, + * allowing Attribute hosts to over-ride either method. + * + * See get for argument details. + * + * @method _getAttr + * @protected + * @chainable + * + * @param {String} name The name of the attribute. + * @return {Any} The value of the attribute. + */ + _getAttr : function(name) { + var host = this, // help compression + fullName = name, + state = host._state, + path, + getter, + val, + cfg; + + if (name.indexOf(DOT) !== -1) { + path = name.split(DOT); + name = path.shift(); + } + + // On Demand - Should be rare - handles out of order valueFn references + if (host._tCfgs && host._tCfgs[name]) { + cfg = {}; + cfg[name] = host._tCfgs[name]; + delete host._tCfgs[name]; + host._addAttrs(cfg, host._tVals); + } + + // Lazy Init + if (host._isLazyAttr(name)) { + host._addLazyAttr(name); + } + + val = host._getStateVal(name); + getter = state.get(name, GETTER); + + val = (getter) ? getter.call(host, val, fullName) : val; + val = (path) ? O.getValue(val, path) : val; + + return val; + }, + + /** + * Provides the common implementation for the public set and protected _set methods. + * + * See set for argument details. + * + * @method _setAttr + * @protected + * @chainable + * + * @param {String} name The name of the attribute. + * @param {Any} value The value to set the attribute to. + * @param {Object} opts (Optional) Optional event data to be mixed into + * the event facade passed to subscribers of the attribute's change event. + * @param {boolean} force If true, allows the caller to set values for + * readOnly or writeOnce attributes which have already been set. + * + * @return {Object} A reference to the host object. + */ + _setAttr : function(name, val, opts, force) { + var allowSet = true, + state = this._state, + stateProxy = this._stateProxy, + data = state.data, + initialSet, + strPath, + path, + currVal; + + if (name.indexOf(DOT) !== -1) { + strPath = name; + path = name.split(DOT); + name = path.shift(); + } + + if (this._isLazyAttr(name)) { + this._addLazyAttr(name); + } + + initialSet = (!data.value || !(name in data.value)); + + if (stateProxy && name in stateProxy && !this._state.get(name, BYPASS_PROXY)) { + // TODO: Value is always set for proxy. Can we do any better? Maybe take a snapshot as the initial value for the first call to set? + initialSet = false; + } + + if (this._requireAddAttr && !this.attrAdded(name)) { + Y.log('Set attribute:' + name + ', aborted; Attribute is not configured', 'warn', 'attribute'); + } else { + + if (!initialSet && !force) { + + if (state.get(name, WRITE_ONCE)) { + Y.log('Set attribute:' + name + ', aborted; Attribute is writeOnce', 'warn', 'attribute'); + allowSet = false; + } + + if (state.get(name, READ_ONLY)) { + Y.log('Set attribute:' + name + ', aborted; Attribute is readOnly', 'warn', 'attribute'); + allowSet = false; + } + } + + if (allowSet) { + // Don't need currVal if initialSet (might fail in custom getter if it always expects a non-undefined/non-null value) + if (!initialSet) { + currVal = this.get(name); + } + + if (path) { + val = O.setValue(Y.clone(currVal), path, val); + + if (val === undefined) { + Y.log('Set attribute path:' + strPath + ', aborted; Path is invalid', 'warn', 'attribute'); + allowSet = false; + } + } + + if (allowSet) { + if (state.get(name, INITIALIZING)) { + this._setAttrVal(name, strPath, currVal, val); + } else { + this._fireAttrChange(name, strPath, currVal, val, opts); + } + } + } + } + + return this; + }, + + /** + * Utility method to help setup the event payload and fire the attribute change event. + * + * @method _fireAttrChange + * @private + * @param {String} attrName The name of the attribute + * @param {String} subAttrName The full path of the property being changed, + * if this is a sub-attribute value being change. Otherwise null. + * @param {Any} currVal The current value of the attribute + * @param {Any} newVal The new value of the attribute + * @param {Object} opts Any additional event data to mix into the attribute change event's event facade. + */ + _fireAttrChange : function(attrName, subAttrName, currVal, newVal, opts) { + var host = this, + eventName = attrName + CHANGE, + state = host._state, + facade; + + if (!state.get(attrName, PUBLISHED)) { + host.publish(eventName, { + queuable:false, + defaultFn:host._defAttrChangeFn, + silent:true, + broadcast : state.get(attrName, BROADCAST) + }); + state.add(attrName, PUBLISHED, true); + } + + facade = (opts) ? Y.merge(opts) : host._ATTR_E_FACADE; + + facade.type = eventName; + facade.attrName = attrName; + facade.subAttrName = subAttrName; + facade.prevVal = currVal; + facade.newVal = newVal; + + host.fire(facade); + }, + + /** + * Default function for attribute change events. + * + * @private + * @method _defAttrChangeFn + * @param {EventFacade} e The event object for attribute change events. + */ + _defAttrChangeFn : function(e) { + if (!this._setAttrVal(e.attrName, e.subAttrName, e.prevVal, e.newVal)) { + Y.log('State not updated and stopImmediatePropagation called for attribute: ' + e.attrName + ' , value:' + e.newVal, 'warn', 'attribute'); + // Prevent "after" listeners from being invoked since nothing changed. + e.stopImmediatePropagation(); + } else { + e.newVal = this._getStateVal(e.attrName); + } + }, + + /** + * Gets the stored value for the attribute, from either the + * internal state object, or the state proxy if it exits + * + * @method _getStateVal + * @private + * @param {String} name The name of the attribute + * @return {Any} The stored value of the attribute + */ + _getStateVal : function(name) { + var stateProxy = this._stateProxy; + return stateProxy && (name in stateProxy) && !this._state.get(name, BYPASS_PROXY) ? stateProxy[name] : this._state.get(name, VALUE); + }, + + /** + * Sets the stored value for the attribute, in either the + * internal state object, or the state proxy if it exits + * + * @method _setStateVal + * @private + * @param {String} name The name of the attribute + * @param {Any} value The value of the attribute + */ + _setStateVal : function(name, value) { + var stateProxy = this._stateProxy; + if (stateProxy && (name in stateProxy) && !this._state.get(name, BYPASS_PROXY)) { + stateProxy[name] = value; + } else { + this._state.add(name, VALUE, value); + } + }, + + /** + * Updates the stored value of the attribute in the privately held State object, + * if validation and setter passes. + * + * @method _setAttrVal + * @private + * @param {String} attrName The attribute name. + * @param {String} subAttrName The sub-attribute name, if setting a sub-attribute property ("x.y.z"). + * @param {Any} prevVal The currently stored value of the attribute. + * @param {Any} newVal The value which is going to be stored. + * + * @return {booolean} true if the new attribute value was stored, false if not. + */ + _setAttrVal : function(attrName, subAttrName, prevVal, newVal) { + + var host = this, + allowSet = true, + state = host._state, + + validator = state.get(attrName, VALIDATOR), + setter = state.get(attrName, SETTER), + initializing = state.get(attrName, INITIALIZING), + prevValRaw = this._getStateVal(attrName), + + name = subAttrName || attrName, + retVal, + valid; + + if (validator) { + valid = validator.call(host, newVal, name); + + if (!valid && initializing) { + newVal = state.get(attrName, DEF_VALUE); + valid = true; // Assume it's valid, for perf. + } + } + + if (!validator || valid) { + if (setter) { + retVal = setter.call(host, newVal, name); + + if (retVal === INVALID_VALUE) { + Y.log('Attribute: ' + attrName + ', setter returned Attribute.INVALID_VALUE for value:' + newVal, 'warn', 'attribute'); + allowSet = false; + } else if (retVal !== undefined){ + Y.log('Attribute: ' + attrName + ', raw value: ' + newVal + ' modified by setter to:' + retVal, 'info', 'attribute'); + newVal = retVal; + } + } + + if (allowSet) { + if(!subAttrName && (newVal === prevValRaw) && !Lang.isObject(newVal)) { + Y.log('Attribute: ' + attrName + ', value unchanged:' + newVal, 'warn', 'attribute'); + allowSet = false; + } else { + // Store value + if (state.get(attrName, INIT_VALUE) === undefined) { + state.add(attrName, INIT_VALUE, newVal); + } + host._setStateVal(attrName, newVal); + } + } + + } else { + Y.log('Attribute:' + attrName + ', Validation failed for value:' + newVal, 'warn', 'attribute'); + allowSet = false; + } + + return allowSet; + }, + + /** + * Sets multiple attribute values. + * + * @method setAttrs + * @param {Object} attrs An object with attributes name/value pairs. + * @return {Object} A reference to the host object. + * @chainable + */ + setAttrs : function(attrs, opts) { + return this._setAttrs(attrs, opts); + }, + + /** + * Implementation behind the public setAttrs method, to set multiple attribute values. + * + * @method _setAttrs + * @protected + * @param {Object} attrs An object with attributes name/value pairs. + * @return {Object} A reference to the host object. + * @chainable + */ + _setAttrs : function(attrs, opts) { + for (var attr in attrs) { + if ( attrs.hasOwnProperty(attr) ) { + this.set(attr, attrs[attr]); + } + } + return this; + }, + + /** + * Gets multiple attribute values. + * + * @method getAttrs + * @param {Array | boolean} attrs Optional. An array of attribute names. If omitted, all attribute values are + * returned. If set to true, all attributes modified from their initial values are returned. + * @return {Object} An object with attribute name/value pairs. + */ + getAttrs : function(attrs) { + return this._getAttrs(attrs); + }, + + /** + * Implementation behind the public getAttrs method, to get multiple attribute values. + * + * @method _getAttrs + * @protected + * @param {Array | boolean} attrs Optional. An array of attribute names. If omitted, all attribute values are + * returned. If set to true, all attributes modified from their initial values are returned. + * @return {Object} An object with attribute name/value pairs. + */ + _getAttrs : function(attrs) { + var host = this, + o = {}, + i, l, attr, val, + modifiedOnly = (attrs === true); + + attrs = (attrs && !modifiedOnly) ? attrs : O.keys(host._state.data.added); + + for (i = 0, l = attrs.length; i < l; i++) { + // Go through get, to honor cloning/normalization + attr = attrs[i]; + val = host.get(attr); + + if (!modifiedOnly || host._getStateVal(attr) != host._state.get(attr, INIT_VALUE)) { + o[attr] = host.get(attr); + } + } + + return o; + }, + + /** + * Configures a group of attributes, and sets initial values. + * + *

+ * NOTE: This method does not isolate the configuration object by merging/cloning. + * The caller is responsible for merging/cloning the configuration object if required. + *

+ * + * @method addAttrs + * @chainable + * + * @param {Object} cfgs An object with attribute name/configuration pairs. + * @param {Object} values An object with attribute name/value pairs, defining the initial values to apply. + * Values defined in the cfgs argument will be over-written by values in this argument unless defined as read only. + * @param {boolean} lazy Whether or not to delay the intialization of these attributes until the first call to get/set. + * Individual attributes can over-ride this behavior by defining a lazyAdd configuration property in their configuration. + * See addAttr. + * + * @return {Object} A reference to the host object. + */ + addAttrs : function(cfgs, values, lazy) { + var host = this; // help compression + if (cfgs) { + host._tCfgs = cfgs; + host._tVals = host._normAttrVals(values); + host._addAttrs(cfgs, host._tVals, lazy); + host._tCfgs = host._tVals = null; + } + + return host; + }, + + /** + * Implementation behind the public addAttrs method. + * + * This method is invoked directly by get if it encounters a scenario + * in which an attribute's valueFn attempts to obtain the + * value an attribute in the same group of attributes, which has not yet + * been added (on demand initialization). + * + * @method _addAttrs + * @private + * @param {Object} cfgs An object with attribute name/configuration pairs. + * @param {Object} values An object with attribute name/value pairs, defining the initial values to apply. + * Values defined in the cfgs argument will be over-written by values in this argument unless defined as read only. + * @param {boolean} lazy Whether or not to delay the intialization of these attributes until the first call to get/set. + * Individual attributes can over-ride this behavior by defining a lazyAdd configuration property in their configuration. + * See addAttr. + */ + _addAttrs : function(cfgs, values, lazy) { + var host = this, // help compression + attr, + attrCfg, + value; + + for (attr in cfgs) { + if (cfgs.hasOwnProperty(attr)) { + + // Not Merging. Caller is responsible for isolating configs + attrCfg = cfgs[attr]; + attrCfg.defaultValue = attrCfg.value; + + // Handle simple, complex and user values, accounting for read-only + value = host._getAttrInitVal(attr, attrCfg, host._tVals); + + if (value !== undefined) { + attrCfg.value = value; + } + + if (host._tCfgs[attr]) { + delete host._tCfgs[attr]; + } + + host.addAttr(attr, attrCfg, lazy); + } + } + }, + + /** + * Utility method to protect an attribute configuration + * hash, by merging the entire object and the individual + * attr config objects. + * + * @method _protectAttrs + * @protected + * @param {Object} attrs A hash of attribute to configuration object pairs. + * @return {Object} A protected version of the attrs argument. + */ + _protectAttrs : function(attrs) { + if (attrs) { + attrs = Y.merge(attrs); + for (var attr in attrs) { + if (attrs.hasOwnProperty(attr)) { + attrs[attr] = Y.merge(attrs[attr]); + } + } + } + return attrs; + }, + + /** + * Utility method to normalize attribute values. The base implementation + * simply merges the hash to protect the original. + * + * @method _normAttrVals + * @param {Object} valueHash An object with attribute name/value pairs + * + * @return {Object} + * + * @private + */ + _normAttrVals : function(valueHash) { + return (valueHash) ? Y.merge(valueHash) : null; + }, + + /** + * Returns the initial value of the given attribute from + * either the default configuration provided, or the + * over-ridden value if it exists in the set of initValues + * provided and the attribute is not read-only. + * + * @param {String} attr The name of the attribute + * @param {Object} cfg The attribute configuration object + * @param {Object} initValues The object with simple and complex attribute name/value pairs returned from _normAttrVals + * + * @return {Any} The initial value of the attribute. + * + * @method _getAttrInitVal + * @private + */ + _getAttrInitVal : function(attr, cfg, initValues) { + + // init value is provided by the user if it exists, else, provided by the config + var val = (!cfg[READ_ONLY] && initValues && initValues.hasOwnProperty(attr)) ? + val = initValues[attr] : + (cfg[VALUE_FN]) ? + cfg[VALUE_FN].call(this) : + cfg[VALUE]; + + Y.log('initValue for ' + attr + ':' + val, 'info', 'attribute'); + + return val; + } + }; + + // Basic prototype augment - no lazy constructor invocation. + Y.mix(Attribute, EventTarget, false, null, 1); + + Y.Attribute = Attribute; + + +}, '3.0.0' ,{requires:['event-custom']}); +YUI.add('attribute-complex', function(Y) { + + /** + * Adds support for attribute providers to handle complex attributes in the constructor + * + * @module attribute + * @submodule attribute-complex + * @for Attribute + */ + + var O = Y.Object, + DOT = "."; + + Y.Attribute.Complex = function() {}; + Y.Attribute.Complex.prototype = { + + /** + * Utility method to split out simple attribute name/value pairs ("x") + * from complex attribute name/value pairs ("x.y.z"), so that complex + * attributes can be keyed by the top level attribute name. + * + * @method _normAttrVals + * @param {Object} valueHash An object with attribute name/value pairs + * + * @return {Object} An object literal with 2 properties - "simple" and "complex", + * containing simple and complex attribute values respectively keyed + * by the top level attribute name, or null, if valueHash is falsey. + * + * @private + */ + _normAttrVals : function(valueHash) { + var vals = {}, + subvals = {}, + path, + attr, + v, k; + + if (valueHash) { + for (k in valueHash) { + if (valueHash.hasOwnProperty(k)) { + if (k.indexOf(DOT) !== -1) { + path = k.split(DOT); + attr = path.shift(); + v = subvals[attr] = subvals[attr] || []; + v[v.length] = { + path : path, + value: valueHash[k] + }; + } else { + vals[k] = valueHash[k]; + } + } + } + return { simple:vals, complex:subvals }; + } else { + return null; + } + }, + + /** + * Returns the initial value of the given attribute from + * either the default configuration provided, or the + * over-ridden value if it exists in the set of initValues + * provided and the attribute is not read-only. + * + * @param {String} attr The name of the attribute + * @param {Object} cfg The attribute configuration object + * @param {Object} initValues The object with simple and complex attribute name/value pairs returned from _normAttrVals + * + * @return {Any} The initial value of the attribute. + * + * @method _getAttrInitVal + * @private + */ + _getAttrInitVal : function(attr, cfg, initValues) { + + var val = (cfg.valueFn) ? cfg.valueFn.call(this) : cfg.value, + simple, + complex, + i, + l, + path, + subval, + subvals; + + if (!cfg.readOnly && initValues) { + + // Simple Attributes + simple = initValues.simple; + if (simple && simple.hasOwnProperty(attr)) { + val = simple[attr]; + } + + // Complex Attributes (complex values applied, after simple, incase both are set) + complex = initValues.complex; + if (complex && complex.hasOwnProperty(attr)) { + subvals = complex[attr]; + for (i = 0, l = subvals.length; i < l; ++i) { + path = subvals[i].path; + subval = subvals[i].value; + O.setValue(val, path, subval); + } + } + } + + return val; + } + }; + + Y.mix(Y.Attribute, Y.Attribute.Complex, true, null, 1); + + +}, '3.0.0' ,{requires:['attribute-base']}); + + +YUI.add('attribute', function(Y){}, '3.0.0' ,{use:['attribute-base', 'attribute-complex']}); +