2 YUI 3.13.0 (build 508226d)
3 Copyright 2013 Yahoo! Inc. All rights reserved.
4 Licensed under the BSD License.
5 http://yuilibrary.com/license/
8 YUI.add('attribute-core', function (Y, NAME) {
11 * The State class maintains state for a collection of named items, with
12 * a varying number of properties defined.
14 * It avoids the need to create a separate class for the item, and separate instances
15 * of these classes for each item, by storing the state in a 2 level hash table,
16 * improving performance when the number of items is likely to be large.
21 Y.State = function() {
32 * Adds a property to an item.
35 * @param name {String} The name of the item.
36 * @param key {String} The name of the property.
37 * @param val {Any} The value of the property.
39 add: function(name, key, val) {
40 var item = this.data[name];
43 item = this.data[name] = {};
50 * Adds multiple properties to an item.
53 * @param name {String} The name of the item.
54 * @param obj {Object} A hash of property/value pairs.
56 addAll: function(name, obj) {
57 var item = this.data[name],
61 item = this.data[name] = {};
65 if (obj.hasOwnProperty(key)) {
72 * Removes a property from an item.
75 * @param name {String} The name of the item.
76 * @param key {String} The property to remove.
78 remove: function(name, key) {
79 var item = this.data[name];
87 * Removes multiple properties from an item, or removes the item completely.
90 * @param name {String} The name of the item.
91 * @param obj {Object|Array} Collection of properties to delete. If not provided, the entire item is removed.
93 removeAll: function(name, obj) {
103 Y.each(obj, function(value, key) {
104 this.remove(name, typeof key === 'string' ? key : value);
110 * For a given item, returns the value of the property requested, or undefined if not found.
113 * @param name {String} The name of the item
114 * @param key {String} Optional. The property value to retrieve.
115 * @return {Any} The value of the supplied property.
117 get: function(name, key) {
118 var item = this.data[name];
126 * For the given item, returns an object with all of the
127 * item's property/value pairs. By default the object returned
128 * is a shallow copy of the stored data, but passing in true
129 * as the second parameter will return a reference to the stored
133 * @param name {String} The name of the item
134 * @param reference {boolean} true, if you want a reference to the stored
136 * @return {Object} An object with property/value pairs for the item.
138 getAll : function(name, reference) {
139 var item = this.data[name],
148 if (item.hasOwnProperty(key)) {
149 obj[key] = item[key];
158 /*jshint maxlen:200*/
161 * The attribute module provides an augmentable Attribute implementation, which
162 * adds configurable attributes and attribute change events to the class being
163 * augmented. It also provides a State class, which is used internally by Attribute,
164 * but can also be used independently to provide a name/property/value data structure to
171 * The attribute-core submodule provides the lightest level of attribute handling support
172 * without Attribute change events, or lesser used methods such as reset(), modifyAttrs(),
176 * @submodule attribute-core
183 // Externally configurable props
186 READ_ONLY = "readOnly",
187 WRITE_ONCE = "writeOnce",
188 INIT_ONLY = "initOnly",
189 VALIDATOR = "validator",
191 VALUE_FN = "valueFn",
192 LAZY_ADD = "lazyAdd",
194 // Used for internal state management
196 BYPASS_PROXY = "_bypassProxy",
197 INIT_VALUE = "initValue",
204 * AttributeCore provides the lightest level of configurable attribute support. It is designed to be
205 * augmented on to a host class, and provides the host with the ability to configure
206 * attributes to store and retrieve state, <strong>but without support for attribute change events</strong>.
208 * <p>For example, attributes added to the host can be configured:</p>
210 * <li>As read only.</li>
211 * <li>As write once.</li>
212 * <li>With a setter function, which can be used to manipulate
213 * values passed to Attribute's <a href="#method_set">set</a> method, before they are stored.</li>
214 * <li>With a getter function, which can be used to manipulate stored values,
215 * before they are returned by Attribute's <a href="#method_get">get</a> method.</li>
216 * <li>With a validator function, to validate values before they are stored.</li>
219 * <p>See the <a href="#method_addAttr">addAttr</a> method, for the complete set of configuration
220 * options available for attributes.</p>
222 * <p>Object/Classes based on AttributeCore can augment <a href="AttributeObservable.html">AttributeObservable</a>
223 * (with true for overwrite) and <a href="AttributeExtras.html">AttributeExtras</a> to add attribute event and
224 * additional, less commonly used attribute methods, such as `modifyAttr`, `removeAttr` and `reset`.</p>
226 * @class AttributeCore
227 * @param attrs {Object} The attributes to add during construction (passed through to <a href="#method_addAttrs">addAttrs</a>).
228 * These can also be defined on the constructor being augmented with Attribute by defining the ATTRS property on the constructor.
229 * @param values {Object} The initial attribute values to apply (passed through to <a href="#method_addAttrs">addAttrs</a>).
230 * These are not merged/cloned. The caller is responsible for isolating user provided values if required.
231 * @param lazy {boolean} Whether or not to add attributes lazily (passed through to <a href="#method_addAttrs">addAttrs</a>).
233 function AttributeCore(attrs, values, lazy) {
234 // HACK: Fix #2531929
235 // Complete hack, to make sure the first clone of a node value in IE doesn't doesn't hurt state - maintains 3.4.1 behavior.
236 // Too late in the release cycle to do anything about the core problem.
237 // The root issue is that cloning a Y.Node instance results in an object which barfs in IE, when you access it's properties (since 3.3.0).
240 this._initAttrHost(attrs, values, lazy);
244 * <p>The value to return from an attribute setter in order to prevent the set from going through.</p>
246 * <p>You can return this value from your setter if you wish to combine validator and setter
247 * functionality into a single setter function, which either returns the massaged value to be stored or
248 * AttributeCore.INVALID_VALUE to prevent invalid values from being stored.</p>
250 * @property INVALID_VALUE
255 AttributeCore.INVALID_VALUE = {};
256 INVALID_VALUE = AttributeCore.INVALID_VALUE;
259 * The list of properties which can be configured for
260 * each attribute (e.g. setter, getter, writeOnce etc.).
262 * This property is used internally as a whitelist for faster
265 * @property _ATTR_CFG
270 AttributeCore._ATTR_CFG = [SETTER, GETTER, VALIDATOR, VALUE, VALUE_FN, WRITE_ONCE, READ_ONLY, LAZY_ADD, BYPASS_PROXY];
273 * Utility method to protect an attribute configuration hash, by merging the
274 * entire object and the individual attr config objects.
276 * @method protectAttrs
278 * @param {Object} attrs A hash of attribute to configuration object pairs.
279 * @return {Object} A protected version of the `attrs` argument.
281 AttributeCore.protectAttrs = function (attrs) {
283 attrs = Y.merge(attrs);
284 for (var attr in attrs) {
285 if (attrs.hasOwnProperty(attr)) {
286 attrs[attr] = Y.merge(attrs[attr]);
294 AttributeCore.prototype = {
297 * Constructor logic for attributes. Initializes the host state, and sets up the inital attributes passed to the
300 * @method _initAttrHost
301 * @param attrs {Object} The attributes to add during construction (passed through to <a href="#method_addAttrs">addAttrs</a>).
302 * These can also be defined on the constructor being augmented with Attribute by defining the ATTRS property on the constructor.
303 * @param values {Object} The initial attribute values to apply (passed through to <a href="#method_addAttrs">addAttrs</a>).
304 * These are not merged/cloned. The caller is responsible for isolating user provided values if required.
305 * @param lazy {boolean} Whether or not to add attributes lazily (passed through to <a href="#method_addAttrs">addAttrs</a>).
308 _initAttrHost : function(attrs, values, lazy) {
309 this._state = new Y.State();
310 this._initAttrs(attrs, values, lazy);
315 * Adds an attribute with the provided configuration to the host object.
318 * The config argument object supports the following properties:
322 * <dt>value <Any></dt>
323 * <dd>The initial value to set on the attribute</dd>
325 * <dt>valueFn <Function | String></dt>
327 * <p>A function, which will return the initial value to set on the attribute. This is useful
328 * for cases where the attribute configuration is defined statically, but needs to
329 * reference the host instance ("this") to obtain an initial value. If both the value and valueFn properties are defined,
330 * the value returned by the valueFn has precedence over the value property, unless it returns undefined, in which
331 * case the value property is used.</p>
333 * <p>valueFn can also be set to a string, representing the name of the instance method to be used to retrieve the value.</p>
336 * <dt>readOnly <boolean></dt>
337 * <dd>Whether or not the attribute is read only. Attributes having readOnly set to true
338 * cannot be modified by invoking the set method.</dd>
340 * <dt>writeOnce <boolean> or <string></dt>
342 * Whether or not the attribute is "write once". Attributes having writeOnce set to true,
343 * can only have their values set once, be it through the default configuration,
344 * constructor configuration arguments, or by invoking set.
345 * <p>The writeOnce attribute can also be set to the string "initOnly",
346 * in which case the attribute can only be set during initialization
347 * (when used with Base, this means it can only be set during construction)</p>
350 * <dt>setter <Function | String></dt>
352 * <p>The setter function used to massage or normalize the value passed to the set method for the attribute.
353 * The value returned by the setter will be the final stored value. Returning
354 * <a href="#property_Attribute.INVALID_VALUE">Attribute.INVALID_VALUE</a>, from the setter will prevent
355 * the value from being stored.
358 * <p>setter can also be set to a string, representing the name of the instance method to be used as the setter function.</p>
361 * <dt>getter <Function | String></dt>
364 * The getter function used to massage or normalize the value returned by the get method for the attribute.
365 * The value returned by the getter function is the value which will be returned to the user when they
369 * <p>getter can also be set to a string, representing the name of the instance method to be used as the getter function.</p>
372 * <dt>validator <Function | String></dt>
375 * The validator function invoked prior to setting the stored value. Returning
376 * false from the validator function will prevent the value from being stored.
379 * <p>validator can also be set to a string, representing the name of the instance method to be used as the validator function.</p>
382 * <dt>lazyAdd <boolean></dt>
383 * <dd>Whether or not to delay initialization of the attribute until the first call to get/set it.
384 * This flag can be used to over-ride lazy initialization on a per attribute basis, when adding multiple attributes through
385 * the <a href="#method_addAttrs">addAttrs</a> method.</dd>
389 * <p>The setter, getter and validator are invoked with the value and name passed in as the first and second arguments, and with
390 * the context ("this") set to the host object.</p>
392 * <p>Configuration properties outside of the list mentioned above are considered private properties used internally by attribute,
393 * and are not intended for public use.</p>
397 * @param {String} name The name of the attribute.
398 * @param {Object} config An object with attribute configuration property/value pairs, specifying the configuration for the attribute.
401 * <strong>NOTE:</strong> The configuration object is modified when adding an attribute, so if you need
402 * to protect the original values, you will need to merge the object.
405 * @param {boolean} lazy (optional) Whether or not to add this attribute lazily (on the first call to get/set).
407 * @return {Object} A reference to the host object.
411 addAttr : function(name, config, lazy) {
414 var host = this, // help compression
421 config = config || {};
423 if (LAZY_ADD in config) {
424 lazy = config[LAZY_ADD];
427 added = state.get(name, ADDED);
429 if (lazy && !added) {
437 if (!added || config.isLazyAdd) {
439 hasValue = (VALUE in config);
444 // We'll go through set, don't want to set value in config directly
446 // PERF TODO: VALIDATE: See if setting this to undefined is sufficient. We use to delete before.
447 // In certain code paths/use cases, undefined may not be the same as not present.
448 // If not, we can set it to some known fixed value (like INVALID_VALUE, say INITIALIZING_VALUE) for performance,
449 // to avoid a delete which seems to help a lot.
451 value = config.value;
452 config.value = undefined;
456 config.initializing = true;
461 // Go through set, so that raw values get normalized/validated
462 host.set(name, value);
465 config.initializing = false;
473 * Checks if the given attribute has been added to the host
476 * @param {String} name The name of the attribute to check.
477 * @return {boolean} true if an attribute with the given name has been added, false if it hasn't.
478 * This method will return true for lazily added attributes.
480 attrAdded: function(name) {
481 return !!(this._state.get(name, ADDED));
485 * Returns the current value of the attribute. If the attribute
486 * has been configured with a 'getter' function, this method will delegate
487 * to the 'getter' to obtain the value of the attribute.
491 * @param {String} name The name of the attribute. If the value of the attribute is an Object,
492 * dot notation can be used to obtain the value of a property of the object (e.g. <code>get("x.y.z")</code>)
494 * @return {Any} The value of the attribute
496 get : function(name) {
497 return this._getAttr(name);
501 * Checks whether or not the attribute is one which has been
502 * added lazily and still requires initialization.
504 * @method _isLazyAttr
506 * @param {String} name The name of the attribute
507 * @return {boolean} true if it's a lazily added attribute, false otherwise.
509 _isLazyAttr: function(name) {
510 return this._state.get(name, LAZY);
514 * Finishes initializing an attribute which has been lazily added.
516 * @method _addLazyAttr
518 * @param {Object} name The name of the attribute
519 * @param {Object} [lazyCfg] Optional config hash for the attribute. This is added for performance
520 * along the critical path, where the calling method has already obtained lazy config from state.
522 _addLazyAttr: function(name, lazyCfg) {
523 var state = this._state;
525 lazyCfg = lazyCfg || state.get(name, LAZY);
529 // PERF TODO: For App's id override, otherwise wouldn't be
530 // needed. It expects to find it in the cfg for it's
531 // addAttr override. Would like to remove, once App override is
533 state.data[name].lazy = undefined;
535 lazyCfg.isLazyAdd = true;
537 this.addAttr(name, lazyCfg);
542 * Sets the value of an attribute.
547 * @param {String} name The name of the attribute. If the
548 * current value of the attribute is an Object, dot notation can be used
549 * to set the value of a property within the object (e.g. <code>set("x.y.z", 5)</code>).
550 * @param {Any} value The value to set the attribute to.
551 * @param {Object} [opts] Optional data providing the circumstances for the change.
552 * @return {Object} A reference to the host object.
554 set : function(name, val, opts) {
555 return this._setAttr(name, val, opts);
559 * Allows setting of readOnly/writeOnce attributes. See <a href="#method_set">set</a> for argument details.
565 * @param {String} name The name of the attribute.
566 * @param {Any} val The value to set the attribute to.
567 * @param {Object} [opts] Optional data providing the circumstances for the change.
568 * @return {Object} A reference to the host object.
570 _set : function(name, val, opts) {
571 return this._setAttr(name, val, opts, true);
575 * Provides the common implementation for the public set and protected _set methods.
577 * See <a href="#method_set">set</a> for argument details.
583 * @param {String} name The name of the attribute.
584 * @param {Any} value The value to set the attribute to.
585 * @param {Object} [opts] Optional data providing the circumstances for the change.
586 * @param {boolean} force If true, allows the caller to set values for
587 * readOnly or writeOnce attributes which have already been set.
589 * @return {Object} A reference to the host object.
591 _setAttr : function(name, val, opts, force) {
594 stateProxy = this._stateProxy,
604 if (name.indexOf(DOT) !== -1) {
607 path = name.split(DOT);
611 // On Demand - Should be rare - handles out of order valueFn, setter, getter references
612 if (tCfgs && tCfgs[name]) {
613 this._addOutOfOrder(name, tCfgs[name]);
616 cfg = state.data[name] || {};
620 this._addLazyAttr(name, cfg);
623 initialSet = (cfg.value === undefined);
625 if (stateProxy && name in stateProxy && !cfg._bypassProxy) {
626 // 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?
630 writeOnce = cfg.writeOnce;
631 initializing = cfg.initializing;
633 if (!initialSet && !force) {
644 if (!initializing && !force && writeOnce === INIT_ONLY) {
649 // Don't need currVal if initialSet (might fail in custom getter if it always expects a non-undefined/non-null value)
651 currVal = this.get(name);
655 val = O.setValue(Y.clone(currVal), path, val);
657 if (val === undefined) {
663 if (!this._fireAttrChange || initializing) {
664 this._setAttrVal(name, strPath, currVal, val, opts, cfg);
666 // HACK - no real reason core needs to know about _fireAttrChange, but
667 // it adds fn hops if we want to break it out. Not sure it's worth it for this critical path
668 this._fireAttrChange(name, strPath, currVal, val, opts, cfg);
677 * Utility method used by get/set to add attributes
678 * encountered out of order when calling addAttrs().
684 * setter: function() {
685 * // make sure this bar is available when foo is added
694 * @method _addOutOfOrder
696 * @param name {String} attribute name
697 * @param cfg {Object} attribute configuration
699 _addOutOfOrder : function(name, cfg) {
704 delete this._tCfgs[name];
706 // TODO: The original code went through addAttrs, so
707 // sticking with it for this pass. Seems like we could
708 // just jump straight to _addAttr() and get some perf
710 this._addAttrs(attrs, this._tVals);
714 * Provides the common implementation for the public get method,
715 * allowing Attribute hosts to over-ride either method.
717 * See <a href="#method_get">get</a> for argument details.
723 * @param {String} name The name of the attribute.
724 * @return {Any} The value of the attribute.
726 _getAttr : function(name) {
734 if (name.indexOf(DOT) !== -1) {
735 path = name.split(DOT);
739 // On Demand - Should be rare - handles out of
740 // order valueFn, setter, getter references
741 if (tCfgs && tCfgs[name]) {
742 this._addOutOfOrder(name, tCfgs[name]);
745 attrCfg = this._state.data[name] || {};
749 attrCfg = attrCfg.lazy;
750 this._addLazyAttr(name, attrCfg);
753 val = this._getStateVal(name, attrCfg);
755 getter = attrCfg.getter;
757 if (getter && !getter.call) {
758 getter = this[getter];
761 val = (getter) ? getter.call(this, val, fullName) : val;
762 val = (path) ? O.getValue(val, path) : val;
768 * Gets the stored value for the attribute, from either the
769 * internal state object, or the state proxy if it exits
771 * @method _getStateVal
773 * @param {String} name The name of the attribute
774 * @param {Object} [cfg] Optional config hash for the attribute. This is added for performance along the critical path,
775 * where the calling method has already obtained the config from state.
777 * @return {Any} The stored value of the attribute
779 _getStateVal : function(name, cfg) {
780 var stateProxy = this._stateProxy;
783 cfg = this._state.getAll(name) || {};
786 return (stateProxy && (name in stateProxy) && !(cfg._bypassProxy)) ? stateProxy[name] : cfg.value;
790 * Sets the stored value for the attribute, in either the
791 * internal state object, or the state proxy if it exits
793 * @method _setStateVal
795 * @param {String} name The name of the attribute
796 * @param {Any} value The value of the attribute
798 _setStateVal : function(name, value) {
799 var stateProxy = this._stateProxy;
800 if (stateProxy && (name in stateProxy) && !this._state.get(name, BYPASS_PROXY)) {
801 stateProxy[name] = value;
803 this._state.add(name, VALUE, value);
808 * Updates the stored value of the attribute in the privately held State object,
809 * if validation and setter passes.
811 * @method _setAttrVal
813 * @param {String} attrName The attribute name.
814 * @param {String} subAttrName The sub-attribute name, if setting a sub-attribute property ("x.y.z").
815 * @param {Any} prevVal The currently stored value of the attribute.
816 * @param {Any} newVal The value which is going to be stored.
817 * @param {Object} [opts] Optional data providing the circumstances for the change.
818 * @param {Object} [attrCfg] Optional config hash for the attribute. This is added for performance along the critical path,
819 * where the calling method has already obtained the config from state.
821 * @return {booolean} true if the new attribute value was stored, false if not.
823 _setAttrVal : function(attrName, subAttrName, prevVal, newVal, opts, attrCfg) {
827 cfg = attrCfg || this._state.data[attrName] || {},
828 validator = cfg.validator,
830 initializing = cfg.initializing,
831 prevRawVal = this._getStateVal(attrName, cfg),
832 name = subAttrName || attrName,
837 if (!validator.call) {
838 // Assume string - trying to keep critical path tight, so avoiding Lang check
839 validator = this[validator];
842 valid = validator.call(host, newVal, name, opts);
844 if (!valid && initializing) {
845 newVal = cfg.defaultValue;
846 valid = true; // Assume it's valid, for perf.
851 if (!validator || valid) {
854 // Assume string - trying to keep critical path tight, so avoiding Lang check
855 setter = this[setter];
858 retVal = setter.call(host, newVal, name, opts);
860 if (retVal === INVALID_VALUE) {
862 newVal = cfg.defaultValue;
866 } else if (retVal !== undefined){
873 if(!subAttrName && (newVal === prevRawVal) && !Lang.isObject(newVal)) {
877 if (!(INIT_VALUE in cfg)) {
878 cfg.initValue = newVal;
880 host._setStateVal(attrName, newVal);
892 * Sets multiple attribute values.
895 * @param {Object} attrs An object with attributes name/value pairs.
896 * @param {Object} [opts] Optional data providing the circumstances for the change.
897 * @return {Object} A reference to the host object.
900 setAttrs : function(attrs, opts) {
901 return this._setAttrs(attrs, opts);
905 * Implementation behind the public setAttrs method, to set multiple attribute values.
909 * @param {Object} attrs An object with attributes name/value pairs.
910 * @param {Object} [opts] Optional data providing the circumstances for the change
911 * @return {Object} A reference to the host object.
914 _setAttrs : function(attrs, opts) {
916 for (attr in attrs) {
917 if ( attrs.hasOwnProperty(attr) ) {
918 this.set(attr, attrs[attr], opts);
925 * Gets multiple attribute values.
928 * @param {Array | boolean} attrs Optional. An array of attribute names. If omitted, all attribute values are
929 * returned. If set to true, all attributes modified from their initial values are returned.
930 * @return {Object} An object with attribute name/value pairs.
932 getAttrs : function(attrs) {
933 return this._getAttrs(attrs);
937 * Implementation behind the public getAttrs method, to get multiple attribute values.
941 * @param {Array | boolean} attrs Optional. An array of attribute names. If omitted, all attribute values are
942 * returned. If set to true, all attributes modified from their initial values are returned.
943 * @return {Object} An object with attribute name/value pairs.
945 _getAttrs : function(attrs) {
948 modifiedOnly = (attrs === true);
950 // TODO - figure out how to get all "added"
951 if (!attrs || modifiedOnly) {
952 attrs = O.keys(this._state.data);
955 for (i = 0, len = attrs.length; i < len; i++) {
958 if (!modifiedOnly || this._getStateVal(attr) != this._state.get(attr, INIT_VALUE)) {
959 // Go through get, to honor cloning/normalization
960 obj[attr] = this.get(attr);
968 * Configures a group of attributes, and sets initial values.
971 * <strong>NOTE:</strong> This method does not isolate the configuration object by merging/cloning.
972 * The caller is responsible for merging/cloning the configuration object if required.
978 * @param {Object} cfgs An object with attribute name/configuration pairs.
979 * @param {Object} values An object with attribute name/value pairs, defining the initial values to apply.
980 * Values defined in the cfgs argument will be over-written by values in this argument unless defined as read only.
981 * @param {boolean} lazy Whether or not to delay the intialization of these attributes until the first call to get/set.
982 * Individual attributes can over-ride this behavior by defining a lazyAdd configuration property in their configuration.
983 * See <a href="#method_addAttr">addAttr</a>.
985 * @return {Object} A reference to the host object.
987 addAttrs : function(cfgs, values, lazy) {
990 this._tVals = (values) ? this._normAttrVals(values) : null;
991 this._addAttrs(cfgs, this._tVals, lazy);
992 this._tCfgs = this._tVals = null;
999 * Implementation behind the public addAttrs method.
1001 * This method is invoked directly by get if it encounters a scenario
1002 * in which an attribute's valueFn attempts to obtain the
1003 * value an attribute in the same group of attributes, which has not yet
1004 * been added (on demand initialization).
1008 * @param {Object} cfgs An object with attribute name/configuration pairs.
1009 * @param {Object} values An object with attribute name/value pairs, defining the initial values to apply.
1010 * Values defined in the cfgs argument will be over-written by values in this argument unless defined as read only.
1011 * @param {boolean} lazy Whether or not to delay the intialization of these attributes until the first call to get/set.
1012 * Individual attributes can over-ride this behavior by defining a lazyAdd configuration property in their configuration.
1013 * See <a href="#method_addAttr">addAttr</a>.
1015 _addAttrs : function(cfgs, values, lazy) {
1016 var tCfgs = this._tCfgs,
1017 tVals = this._tVals,
1022 for (attr in cfgs) {
1023 if (cfgs.hasOwnProperty(attr)) {
1025 // Not Merging. Caller is responsible for isolating configs
1026 attrCfg = cfgs[attr];
1027 attrCfg.defaultValue = attrCfg.value;
1029 // Handle simple, complex and user values, accounting for read-only
1030 value = this._getAttrInitVal(attr, attrCfg, tVals);
1032 if (value !== undefined) {
1033 attrCfg.value = value;
1037 tCfgs[attr] = undefined;
1040 this.addAttr(attr, attrCfg, lazy);
1046 * Utility method to protect an attribute configuration
1047 * hash, by merging the entire object and the individual
1048 * attr config objects.
1050 * @method _protectAttrs
1052 * @param {Object} attrs A hash of attribute to configuration object pairs.
1053 * @return {Object} A protected version of the attrs argument.
1054 * @deprecated Use `AttributeCore.protectAttrs()` or
1055 * `Attribute.protectAttrs()` which are the same static utility method.
1057 _protectAttrs : AttributeCore.protectAttrs,
1060 * Utility method to normalize attribute values. The base implementation
1061 * simply merges the hash to protect the original.
1063 * @method _normAttrVals
1064 * @param {Object} valueHash An object with attribute name/value pairs
1066 * @return {Object} An object literal with 2 properties - "simple" and "complex",
1067 * containing simple and complex attribute values respectively keyed
1068 * by the top level attribute name, or null, if valueHash is falsey.
1072 _normAttrVals : function(valueHash) {
1085 for (k in valueHash) {
1086 if (valueHash.hasOwnProperty(k)) {
1087 if (k.indexOf(DOT) !== -1) {
1088 path = k.split(DOT);
1089 attr = path.shift();
1091 subvals = subvals || {};
1093 v = subvals[attr] = subvals[attr] || [];
1099 vals[k] = valueHash[k];
1104 return { simple:vals, complex:subvals };
1108 * Returns the initial value of the given attribute from
1109 * either the default configuration provided, or the
1110 * over-ridden value if it exists in the set of initValues
1111 * provided and the attribute is not read-only.
1113 * @param {String} attr The name of the attribute
1114 * @param {Object} cfg The attribute configuration object
1115 * @param {Object} initValues The object with simple and complex attribute name/value pairs returned from _normAttrVals
1117 * @return {Any} The initial value of the attribute.
1119 * @method _getAttrInitVal
1122 _getAttrInitVal : function(attr, cfg, initValues) {
1123 var val = cfg.value,
1124 valFn = cfg.valueFn,
1127 readOnly = cfg.readOnly,
1136 if (!readOnly && initValues) {
1137 // Simple Attributes
1138 simple = initValues.simple;
1139 if (simple && simple.hasOwnProperty(attr)) {
1145 if (valFn && !initValSet) {
1147 valFn = this[valFn];
1150 tmpVal = valFn.call(this, attr);
1155 if (!readOnly && initValues) {
1157 // Complex Attributes (complex values applied, after simple, in case both are set)
1158 complex = initValues.complex;
1160 if (complex && complex.hasOwnProperty(attr) && (val !== undefined) && (val !== null)) {
1161 subvals = complex[attr];
1162 for (i = 0, l = subvals.length; i < l; ++i) {
1163 path = subvals[i].path;
1164 subval = subvals[i].value;
1165 O.setValue(val, path, subval);
1174 * Utility method to set up initial attributes defined during construction,
1175 * either through the constructor.ATTRS property, or explicitly passed in.
1177 * @method _initAttrs
1179 * @param attrs {Object} The attributes to add during construction (passed through to <a href="#method_addAttrs">addAttrs</a>).
1180 * These can also be defined on the constructor being augmented with Attribute by defining the ATTRS property on the constructor.
1181 * @param values {Object} The initial attribute values to apply (passed through to <a href="#method_addAttrs">addAttrs</a>).
1182 * These are not merged/cloned. The caller is responsible for isolating user provided values if required.
1183 * @param lazy {boolean} Whether or not to add attributes lazily (passed through to <a href="#method_addAttrs">addAttrs</a>).
1185 _initAttrs : function(attrs, values, lazy) {
1186 // ATTRS support for Node, which is not Base based
1187 attrs = attrs || this.constructor.ATTRS;
1190 BaseCore = Y.BaseCore,
1191 baseInst = (Base && Y.instanceOf(this, Base)),
1192 baseCoreInst = (!baseInst && BaseCore && Y.instanceOf(this, BaseCore));
1194 if (attrs && !baseInst && !baseCoreInst) {
1195 this.addAttrs(Y.AttributeCore.protectAttrs(attrs), values, lazy);
1200 Y.AttributeCore = AttributeCore;
1203 }, '3.13.0', {"requires": ["oop"]});