/* Copyright (c) 2010, Yahoo! Inc. All rights reserved. Code licensed under the BSD License: http://developer.yahoo.com/yui/license.html version: 3.3.0 build: 3167 */ 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", INIT_ONLY = "initOnly", 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() { 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 && Y.instanceOf(host, 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 | String>
*
*

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 both the value and valueFn properties are defined, * the value returned by the valueFn has precedence over the value property, unless it returns undefined, in which * case the value property is used.

* *

valueFn can also be set to a string, representing the name of the instance method to be used to retrieve the value.

*
* *
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> or <string>
*
* 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. *

The writeOnce attribute can also be set to the string "initOnly", in which case the attribute can only be set during initialization * (when used with Base, this means it can only be set during construction)

*
* *
setter <Function | String>
*
*

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. *

* *

setter can also be set to a string, representing the name of the instance method to be used as the setter function.

*
* *
getter <Function | String>
*
*

* 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. *

* *

getter can also be set to a string, representing the name of the instance method to be used as the getter function.

*
* *
validator <Function | String>
*
*

* The validator function invoked prior to setting the stored value. Returning * false from the validator function will prevent the value from being stored. *

* *

validator can also be set to a string, representing the name of the instance method to be used as the validator function.

*
* *
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) { 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)) { config = config || {}; hasValue = (VALUE in config); if(hasValue) { // We'll go through set, don't want to set value in config 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); } } } } }, /** * 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); if (getter && !getter.call) { getter = this[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, writeOnce, initializing; 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)) { } else { writeOnce = state.get(name, WRITE_ONCE); initializing = state.get(name, INITIALIZING); if (!initialSet && !force) { if (writeOnce) { allowSet = false; } if (state.get(name, READ_ONLY)) { allowSet = false; } } if (!initializing && !force && writeOnce === INIT_ONLY) { 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) { allowSet = false; } } if (allowSet) { if (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, defaultTargetOnly: true, defaultFn:host._defAttrChangeFn, silent:true, broadcast : state.get(attrName, BROADCAST) }); state.add(attrName, PUBLISHED, true); } facade = (opts) ? Y.merge(opts) : host._ATTR_E_FACADE; // Not using the single object signature for fire({type:..., newVal:...}), since // we don't want to override type. Changed to the fire(type, {newVal:...}) signature. // facade.type = eventName; facade.attrName = attrName; facade.subAttrName = subAttrName; facade.prevVal = currVal; facade.newVal = newVal; // host.fire(facade); host.fire(eventName, 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)) { // Prevent "after" listeners from being invoked since nothing changed. e.stopImmediatePropagation(); } else { e.newVal = this.get(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) { if (!validator.call) { // Assume string - trying to keep critical path tight, so avoiding Lang check validator = this[validator]; } 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) { if (!setter.call) { // Assume string - trying to keep critical path tight, so avoiding Lang check setter = this[setter]; } if (setter) { retVal = setter.call(host, newVal, name); if (retVal === INVALID_VALUE) { allowSet = false; } else if (retVal !== undefined){ newVal = retVal; } } } if (allowSet) { if(!subAttrName && (newVal === prevValRaw) && !Lang.isObject(newVal)) { allowSet = false; } else { // Store value if (state.get(attrName, INIT_VALUE) === undefined) { state.add(attrName, INIT_VALUE, newVal); } host._setStateVal(attrName, newVal); } } } else { 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) { var val, valFn; // init value is provided by the user if it exists, else, provided by the config if (!cfg[READ_ONLY] && initValues && initValues.hasOwnProperty(attr)) { val = initValues[attr]; } else { val = cfg[VALUE]; valFn = cfg[VALUE_FN]; if (valFn) { if (!valFn.call) { valFn = this[valFn]; } if (valFn) { val = valFn.call(this); } } } return val; }, /** * Returns an object with the configuration properties (and value) * for the given attrubute. If attrName is not provided, returns the * configuration properties for all attributes. * * @method _getAttrCfg * @protected * @param {String} name Optional. The attribute name. If not provided, the method will return the configuration for all attributes. * @return {Object} The configuration properties for the given attribute, or all attributes. */ _getAttrCfg : function(name) { var o, data = this._state.data; if (data) { o = {}; Y.each(data, function(cfg, cfgProp) { if (name) { if(name in cfg) { o[cfgProp] = cfg[name]; } } else { Y.each(cfg, function(attrCfg, attr) { o[attr] = o[attr] || {}; o[attr][cfgProp] = attrCfg; }); } }); } return o; } }; // Basic prototype augment - no lazy constructor invocation. Y.mix(Attribute, EventTarget, false, null, 1); Y.Attribute = Attribute; }, '3.3.0' ,{requires:['event-custom']});