Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge branch 'Satyam-2532810' into dev-master

  • Loading branch information...
commit 353f3174b1e805860ae0a065d5ada977219fc537 2 parents c7facd1 + 9e579f2
@ericf ericf authored
View
38 build/attribute-base/attribute-base-coverage.js
@@ -26,9 +26,9 @@ _yuitest_coverage["build/attribute-base/attribute-base.js"] = {
path: "build/attribute-base/attribute-base.js",
code: []
};
-_yuitest_coverage["build/attribute-base/attribute-base.js"].code=["YUI.add('attribute-base', function (Y, NAME) {",""," /**"," * 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"," */",""," /**"," * <p>"," * 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."," * </p>"," * <p>For example, attributes added to the host can be configured:</p>"," * <ul>"," * <li>As read only.</li>"," * <li>As write once.</li>"," * <li>With a setter function, which can be used to manipulate"," * values passed to Attribute's <a href=\"#method_set\">set</a> method, before they are stored.</li>"," * <li>With a getter function, which can be used to manipulate stored values,"," * before they are returned by Attribute's <a href=\"#method_get\">get</a> method.</li>"," * <li>With a validator function, to validate values before they are stored.</li>"," * </ul>"," *"," * <p>See the <a href=\"#method_addAttr\">addAttr</a> method, for the complete set of configuration"," * options available for attributes.</p>"," *"," * <p><strong>NOTE:</strong> Most implementations will be better off extending the <a href=\"Base.html\">Base</a> 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.</p>"," *"," * @class Attribute"," * @param attrs {Object} The attributes to add during construction (passed through to <a href=\"#method_addAttrs\">addAttrs</a>). These can also be defined on the constructor being augmented with Attribute by defining the ATTRS property on the constructor."," * @param values {Object} The initial attribute values to apply (passed through to <a href=\"#method_addAttrs\">addAttrs</a>). These are not merged/cloned. The caller is responsible for isolating user provided values if required."," * @param lazy {boolean} Whether or not to add attributes lazily (passed through to <a href=\"#method_addAttrs\">addAttrs</a>)."," * @uses AttributeCore"," * @uses AttributeObservable"," * @uses EventTarget"," * @uses AttributeExtras"," */"," function Attribute() {"," Y.AttributeCore.apply(this, arguments);"," Y.AttributeObservable.apply(this, arguments);"," Y.AttributeExtras.apply(this, arguments);"," }",""," Y.mix(Attribute, Y.AttributeCore, false, null, 1);"," Y.mix(Attribute, Y.AttributeExtras, false, null, 1);",""," // Needs to be \"true\", to overwrite methods from AttributeCore"," Y.mix(Attribute, Y.AttributeObservable, true, null, 1);",""," /**"," * <p>The value to return from an attribute setter in order to prevent the set from going through.</p>"," *"," * <p>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"," * AttributeCore.INVALID_VALUE to prevent invalid values from being stored.</p>"," *"," * @property INVALID_VALUE"," * @type Object"," * @static"," * @final"," */"," Attribute.INVALID_VALUE = Y.AttributeCore.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 _ATTR_CFG"," * @type Array"," * @static"," * @protected"," */"," Attribute._ATTR_CFG = Y.AttributeCore._ATTR_CFG.concat(Y.AttributeObservable._ATTR_CFG);",""," /**"," * Utility method to protect an attribute configuration hash, by merging the"," * entire object and the individual attr config objects."," *"," * @method protectAttrs"," * @static"," * @param {Object} attrs A hash of attribute to configuration object pairs."," * @return {Object} A protected version of the `attrs` argument."," */"," Attribute.protectAttrs = Y.AttributeCore.protectAttrs;",""," Y.Attribute = Attribute;","","","}, '@VERSION@', {\"requires\": [\"attribute-core\", \"attribute-observable\", \"attribute-extras\"]});"];
-_yuitest_coverage["build/attribute-base/attribute-base.js"].lines = {"1":0,"54":0,"55":0,"56":0,"57":0,"60":0,"61":0,"64":0,"78":0,"92":0,"103":0,"105":0};
-_yuitest_coverage["build/attribute-base/attribute-base.js"].functions = {"Attribute:54":0,"(anonymous 1):1":0};
+_yuitest_coverage["build/attribute-base/attribute-base.js"].code=["YUI.add('attribute-base', function (Y, NAME) {",""," /**"," * 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"," */",""," /**"," * <p>"," * 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."," * </p>"," * <p>For example, attributes added to the host can be configured:</p>"," * <ul>"," * <li>As read only.</li>"," * <li>As write once.</li>"," * <li>With a setter function, which can be used to manipulate"," * values passed to Attribute's <a href=\"#method_set\">set</a> method, before they are stored.</li>"," * <li>With a getter function, which can be used to manipulate stored values,"," * before they are returned by Attribute's <a href=\"#method_get\">get</a> method.</li>"," * <li>With a validator function, to validate values before they are stored.</li>"," * </ul>"," *"," * <p>See the <a href=\"#method_addAttr\">addAttr</a> method, for the complete set of configuration"," * options available for attributes.</p>"," *"," * <p><strong>NOTE:</strong> Most implementations will be better off extending the <a href=\"Base.html\">Base</a> 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.</p>"," *"," * @class Attribute"," * @param attrs {Object} The attributes to add during construction (passed through to <a href=\"#method_addAttrs\">addAttrs</a>)."," * These can also be defined on the constructor being augmented with Attribute by defining the ATTRS property on the constructor."," * @param values {Object} The initial attribute values to apply (passed through to <a href=\"#method_addAttrs\">addAttrs</a>)."," * These are not merged/cloned. The caller is responsible for isolating user provided values if required."," * @param lazy {boolean} Whether or not to add attributes lazily (passed through to <a href=\"#method_addAttrs\">addAttrs</a>)."," * @uses AttributeCore"," * @uses AttributeObservable"," * @uses EventTarget"," * @uses AttributeExtras"," */"," function Attribute() {"," Y.AttributeCore.apply(this, arguments);"," Y.AttributeObservable.apply(this, arguments);"," Y.AttributeExtras.apply(this, arguments);"," }",""," Y.mix(Attribute, Y.AttributeCore, false, null, 1);"," Y.mix(Attribute, Y.AttributeExtras, false, null, 1);",""," // Needs to be `true`, to overwrite methods from AttributeCore"," Y.mix(Attribute, Y.AttributeObservable, true, null, 1);",""," /**"," * <p>The value to return from an attribute setter in order to prevent the set from going through.</p>"," *"," * <p>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"," * AttributeCore.INVALID_VALUE to prevent invalid values from being stored.</p>"," *"," * @property INVALID_VALUE"," * @type Object"," * @static"," * @final"," */"," Attribute.INVALID_VALUE = Y.AttributeCore.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 _ATTR_CFG"," * @type Array"," * @static"," * @protected"," */"," Attribute._ATTR_CFG = Y.AttributeCore._ATTR_CFG.concat(Y.AttributeObservable._ATTR_CFG);",""," /**"," * Utility method to protect an attribute configuration hash, by merging the"," * entire object and the individual attr config objects."," *"," * @method protectAttrs"," * @static"," * @param {Object} attrs A hash of attribute to configuration object pairs."," * @return {Object} A protected version of the `attrs` argument."," */"," Attribute.protectAttrs = Y.AttributeCore.protectAttrs;",""," Y.Attribute = Attribute;","","","}, '@VERSION@', {\"requires\": [\"attribute-core\", \"attribute-observable\", \"attribute-extras\"]});"];
+_yuitest_coverage["build/attribute-base/attribute-base.js"].lines = {"1":0,"56":0,"57":0,"58":0,"59":0,"62":0,"63":0,"66":0,"80":0,"94":0,"105":0,"107":0};
+_yuitest_coverage["build/attribute-base/attribute-base.js"].functions = {"Attribute:56":0,"(anonymous 1):1":0};
_yuitest_coverage["build/attribute-base/attribute-base.js"].coveredLines = 12;
_yuitest_coverage["build/attribute-base/attribute-base.js"].coveredFunctions = 2;
_yuitest_coverline("build/attribute-base/attribute-base.js", 1);
@@ -77,8 +77,10 @@ YUI.add('attribute-base', function (Y, NAME) {
* of attributes for derived classes, accounting for values passed into the constructor.</p>
*
* @class Attribute
- * @param attrs {Object} The attributes to add during construction (passed through to <a href="#method_addAttrs">addAttrs</a>). These can also be defined on the constructor being augmented with Attribute by defining the ATTRS property on the constructor.
- * @param values {Object} The initial attribute values to apply (passed through to <a href="#method_addAttrs">addAttrs</a>). These are not merged/cloned. The caller is responsible for isolating user provided values if required.
+ * @param attrs {Object} The attributes to add during construction (passed through to <a href="#method_addAttrs">addAttrs</a>).
+ * These can also be defined on the constructor being augmented with Attribute by defining the ATTRS property on the constructor.
+ * @param values {Object} The initial attribute values to apply (passed through to <a href="#method_addAttrs">addAttrs</a>).
+ * These are not merged/cloned. The caller is responsible for isolating user provided values if required.
* @param lazy {boolean} Whether or not to add attributes lazily (passed through to <a href="#method_addAttrs">addAttrs</a>).
* @uses AttributeCore
* @uses AttributeObservable
@@ -86,24 +88,24 @@ YUI.add('attribute-base', function (Y, NAME) {
* @uses AttributeExtras
*/
_yuitest_coverfunc("build/attribute-base/attribute-base.js", "(anonymous 1)", 1);
-_yuitest_coverline("build/attribute-base/attribute-base.js", 54);
+_yuitest_coverline("build/attribute-base/attribute-base.js", 56);
function Attribute() {
- _yuitest_coverfunc("build/attribute-base/attribute-base.js", "Attribute", 54);
-_yuitest_coverline("build/attribute-base/attribute-base.js", 55);
+ _yuitest_coverfunc("build/attribute-base/attribute-base.js", "Attribute", 56);
+_yuitest_coverline("build/attribute-base/attribute-base.js", 57);
Y.AttributeCore.apply(this, arguments);
- _yuitest_coverline("build/attribute-base/attribute-base.js", 56);
+ _yuitest_coverline("build/attribute-base/attribute-base.js", 58);
Y.AttributeObservable.apply(this, arguments);
- _yuitest_coverline("build/attribute-base/attribute-base.js", 57);
+ _yuitest_coverline("build/attribute-base/attribute-base.js", 59);
Y.AttributeExtras.apply(this, arguments);
}
- _yuitest_coverline("build/attribute-base/attribute-base.js", 60);
+ _yuitest_coverline("build/attribute-base/attribute-base.js", 62);
Y.mix(Attribute, Y.AttributeCore, false, null, 1);
- _yuitest_coverline("build/attribute-base/attribute-base.js", 61);
+ _yuitest_coverline("build/attribute-base/attribute-base.js", 63);
Y.mix(Attribute, Y.AttributeExtras, false, null, 1);
- // Needs to be "true", to overwrite methods from AttributeCore
- _yuitest_coverline("build/attribute-base/attribute-base.js", 64);
+ // Needs to be `true`, to overwrite methods from AttributeCore
+ _yuitest_coverline("build/attribute-base/attribute-base.js", 66);
Y.mix(Attribute, Y.AttributeObservable, true, null, 1);
/**
@@ -118,7 +120,7 @@ Y.mix(Attribute, Y.AttributeObservable, true, null, 1);
* @static
* @final
*/
- _yuitest_coverline("build/attribute-base/attribute-base.js", 78);
+ _yuitest_coverline("build/attribute-base/attribute-base.js", 80);
Attribute.INVALID_VALUE = Y.AttributeCore.INVALID_VALUE;
/**
@@ -133,7 +135,7 @@ Attribute.INVALID_VALUE = Y.AttributeCore.INVALID_VALUE;
* @static
* @protected
*/
- _yuitest_coverline("build/attribute-base/attribute-base.js", 92);
+ _yuitest_coverline("build/attribute-base/attribute-base.js", 94);
Attribute._ATTR_CFG = Y.AttributeCore._ATTR_CFG.concat(Y.AttributeObservable._ATTR_CFG);
/**
@@ -145,10 +147,10 @@ Attribute._ATTR_CFG = Y.AttributeCore._ATTR_CFG.concat(Y.AttributeObservable._AT
* @param {Object} attrs A hash of attribute to configuration object pairs.
* @return {Object} A protected version of the `attrs` argument.
*/
- _yuitest_coverline("build/attribute-base/attribute-base.js", 103);
+ _yuitest_coverline("build/attribute-base/attribute-base.js", 105);
Attribute.protectAttrs = Y.AttributeCore.protectAttrs;
- _yuitest_coverline("build/attribute-base/attribute-base.js", 105);
+ _yuitest_coverline("build/attribute-base/attribute-base.js", 107);
Y.Attribute = Attribute;
View
8 build/attribute-base/attribute-base-debug.js
@@ -43,8 +43,10 @@ YUI.add('attribute-base', function (Y, NAME) {
* of attributes for derived classes, accounting for values passed into the constructor.</p>
*
* @class Attribute
- * @param attrs {Object} The attributes to add during construction (passed through to <a href="#method_addAttrs">addAttrs</a>). These can also be defined on the constructor being augmented with Attribute by defining the ATTRS property on the constructor.
- * @param values {Object} The initial attribute values to apply (passed through to <a href="#method_addAttrs">addAttrs</a>). These are not merged/cloned. The caller is responsible for isolating user provided values if required.
+ * @param attrs {Object} The attributes to add during construction (passed through to <a href="#method_addAttrs">addAttrs</a>).
+ * These can also be defined on the constructor being augmented with Attribute by defining the ATTRS property on the constructor.
+ * @param values {Object} The initial attribute values to apply (passed through to <a href="#method_addAttrs">addAttrs</a>).
+ * These are not merged/cloned. The caller is responsible for isolating user provided values if required.
* @param lazy {boolean} Whether or not to add attributes lazily (passed through to <a href="#method_addAttrs">addAttrs</a>).
* @uses AttributeCore
* @uses AttributeObservable
@@ -60,7 +62,7 @@ YUI.add('attribute-base', function (Y, NAME) {
Y.mix(Attribute, Y.AttributeCore, false, null, 1);
Y.mix(Attribute, Y.AttributeExtras, false, null, 1);
- // Needs to be "true", to overwrite methods from AttributeCore
+ // Needs to be `true`, to overwrite methods from AttributeCore
Y.mix(Attribute, Y.AttributeObservable, true, null, 1);
/**
View
8 build/attribute-base/attribute-base.js
@@ -43,8 +43,10 @@ YUI.add('attribute-base', function (Y, NAME) {
* of attributes for derived classes, accounting for values passed into the constructor.</p>
*
* @class Attribute
- * @param attrs {Object} The attributes to add during construction (passed through to <a href="#method_addAttrs">addAttrs</a>). These can also be defined on the constructor being augmented with Attribute by defining the ATTRS property on the constructor.
- * @param values {Object} The initial attribute values to apply (passed through to <a href="#method_addAttrs">addAttrs</a>). These are not merged/cloned. The caller is responsible for isolating user provided values if required.
+ * @param attrs {Object} The attributes to add during construction (passed through to <a href="#method_addAttrs">addAttrs</a>).
+ * These can also be defined on the constructor being augmented with Attribute by defining the ATTRS property on the constructor.
+ * @param values {Object} The initial attribute values to apply (passed through to <a href="#method_addAttrs">addAttrs</a>).
+ * These are not merged/cloned. The caller is responsible for isolating user provided values if required.
* @param lazy {boolean} Whether or not to add attributes lazily (passed through to <a href="#method_addAttrs">addAttrs</a>).
* @uses AttributeCore
* @uses AttributeObservable
@@ -60,7 +62,7 @@ YUI.add('attribute-base', function (Y, NAME) {
Y.mix(Attribute, Y.AttributeCore, false, null, 1);
Y.mix(Attribute, Y.AttributeExtras, false, null, 1);
- // Needs to be "true", to overwrite methods from AttributeCore
+ // Needs to be `true`, to overwrite methods from AttributeCore
Y.mix(Attribute, Y.AttributeObservable, true, null, 1);
/**
View
432 build/attribute-core/attribute-core-coverage.js
218 additions, 214 deletions not shown
View
81 build/attribute-core/attribute-core-debug.js
@@ -216,8 +216,10 @@ YUI.add('attribute-core', function (Y, NAME) {
* additional, less commonly used attribute methods, such as `modifyAttr`, `removeAttr` and `reset`.</p>
*
* @class AttributeCore
- * @param attrs {Object} The attributes to add during construction (passed through to <a href="#method_addAttrs">addAttrs</a>). These can also be defined on the constructor being augmented with Attribute by defining the ATTRS property on the constructor.
- * @param values {Object} The initial attribute values to apply (passed through to <a href="#method_addAttrs">addAttrs</a>). These are not merged/cloned. The caller is responsible for isolating user provided values if required.
+ * @param attrs {Object} The attributes to add during construction (passed through to <a href="#method_addAttrs">addAttrs</a>).
+ * These can also be defined on the constructor being augmented with Attribute by defining the ATTRS property on the constructor.
+ * @param values {Object} The initial attribute values to apply (passed through to <a href="#method_addAttrs">addAttrs</a>).
+ * These are not merged/cloned. The caller is responsible for isolating user provided values if required.
* @param lazy {boolean} Whether or not to add attributes lazily (passed through to <a href="#method_addAttrs">addAttrs</a>).
*/
function AttributeCore(attrs, values, lazy) {
@@ -288,8 +290,10 @@ YUI.add('attribute-core', function (Y, NAME) {
* constructor.
*
* @method _initAttrHost
- * @param attrs {Object} The attributes to add during construction (passed through to <a href="#method_addAttrs">addAttrs</a>). These can also be defined on the constructor being augmented with Attribute by defining the ATTRS property on the constructor.
- * @param values {Object} The initial attribute values to apply (passed through to <a href="#method_addAttrs">addAttrs</a>). These are not merged/cloned. The caller is responsible for isolating user provided values if required.
+ * @param attrs {Object} The attributes to add during construction (passed through to <a href="#method_addAttrs">addAttrs</a>).
+ * These can also be defined on the constructor being augmented with Attribute by defining the ATTRS property on the constructor.
+ * @param values {Object} The initial attribute values to apply (passed through to <a href="#method_addAttrs">addAttrs</a>).
+ * These are not merged/cloned. The caller is responsible for isolating user provided values if required.
* @param lazy {boolean} Whether or not to add attributes lazily (passed through to <a href="#method_addAttrs">addAttrs</a>).
* @private
*/
@@ -330,7 +334,8 @@ YUI.add('attribute-core', function (Y, NAME) {
* 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.
- * <p>The writeOnce attribute can also be set to the string "initOnly", in which case the attribute can only be set during initialization
+ * <p>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)</p>
* </dd>
*
@@ -414,7 +419,7 @@ YUI.add('attribute-core', function (Y, NAME) {
added : true
});
} else {
-
+ /*jshint maxlen:200*/
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)) {
@@ -422,6 +427,7 @@ YUI.add('attribute-core', function (Y, NAME) {
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');}
+ /*jshint maxlen:150*/
if (hasValue) {
// We'll go through set, don't want to set value in config directly
@@ -451,7 +457,8 @@ YUI.add('attribute-core', function (Y, NAME) {
*
* @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.
+ * @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);
@@ -493,7 +500,7 @@ YUI.add('attribute-core', function (Y, NAME) {
* @private
* @param {Object} name The name of the attribute
*/
- _addLazyAttr: function(name, cfg) {
+ _addLazyAttr: function(name) {
var state = this._state,
lazyCfg = state.get(name, LAZY);
@@ -511,13 +518,12 @@ YUI.add('attribute-core', function (Y, NAME) {
* @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. <code>set("x.y.z", 5)</code>).
- *
* @param {Any} value The value to set the attribute to.
- *
+ * @param {Object} [opts] Optional data providing the circumstances for the change.
* @return {Object} A reference to the host object.
*/
- set : function(name, val) {
- return this._setAttr(name, val);
+ set : function(name, val, opts) {
+ return this._setAttr(name, val, opts);
},
/**
@@ -529,10 +535,11 @@ YUI.add('attribute-core', function (Y, NAME) {
*
* @param {String} name The name of the attribute.
* @param {Any} val The value to set the attribute to.
+ * @param {Object} [opts] Optional data providing the circumstances for the change.
* @return {Object} A reference to the host object.
*/
- _set : function(name, val) {
- return this._setAttr(name, val, null, true);
+ _set : function(name, val, opts) {
+ return this._setAttr(name, val, opts, true);
},
/**
@@ -546,22 +553,13 @@ YUI.add('attribute-core', function (Y, NAME) {
*
* @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.
- * This is currently a hack. There's no real need for the AttributeCore implementation
- * to support this parameter, but breaking it out into AttributeObservable, results in
- * additional function hops for the critical path.
+ * @param {Object} [opts] Optional data providing the circumstances for the change.
* @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) {
-
- // HACK - no real reason core needs to know about opts, but
- // it adds fn hops if we want to break it out.
- // Not sure it's worth it for this critical path
-
var allowSet = true,
state = this._state,
stateProxy = this._stateProxy,
@@ -629,8 +627,9 @@ YUI.add('attribute-core', function (Y, NAME) {
}
if (allowSet) {
+ opts = opts || {};
if (!this._fireAttrChange || initializing) {
- this._setAttrVal(name, strPath, currVal, val);
+ this._setAttrVal(name, strPath, currVal, val, opts);
} else {
// HACK - no real reason core needs to know about _fireAttrChange, but
// it adds fn hops if we want to break it out. Not sure it's worth it for this critical path
@@ -738,10 +737,11 @@ YUI.add('attribute-core', function (Y, 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.
+ * @param {Object} [opts] Optional data providing the circumstances for the change.
*
* @return {booolean} true if the new attribute value was stored, false if not.
*/
- _setAttrVal : function(attrName, subAttrName, prevVal, newVal) {
+ _setAttrVal : function(attrName, subAttrName, prevVal, newVal, opts) {
var host = this,
allowSet = true,
@@ -760,7 +760,7 @@ YUI.add('attribute-core', function (Y, NAME) {
validator = this[validator];
}
if (validator) {
- valid = validator.call(host, newVal, name);
+ valid = validator.call(host, newVal, name, opts);
if (!valid && initializing) {
newVal = cfg.defaultValue;
@@ -776,7 +776,7 @@ YUI.add('attribute-core', function (Y, NAME) {
setter = this[setter];
}
if (setter) {
- retVal = setter.call(host, newVal, name);
+ retVal = setter.call(host, newVal, name, opts);
if (retVal === INVALID_VALUE) {
Y.log('Attribute: ' + attrName + ', setter returned Attribute.INVALID_VALUE for value:' + newVal, 'warn', 'attribute');
@@ -814,11 +814,12 @@ YUI.add('attribute-core', function (Y, NAME) {
*
* @method setAttrs
* @param {Object} attrs An object with attributes name/value pairs.
+ * @param {Object} [opts] Optional data providing the circumstances for the change.
* @return {Object} A reference to the host object.
* @chainable
*/
- setAttrs : function(attrs) {
- return this._setAttrs(attrs);
+ setAttrs : function(attrs, opts) {
+ return this._setAttrs(attrs, opts);
},
/**
@@ -827,14 +828,15 @@ YUI.add('attribute-core', function (Y, NAME) {
* @method _setAttrs
* @protected
* @param {Object} attrs An object with attributes name/value pairs.
+ * @param {Object} [opts] Optional data providing the circumstances for the change
* @return {Object} A reference to the host object.
* @chainable
*/
- _setAttrs : function(attrs) {
+ _setAttrs : function(attrs, opts) {
var attr;
for (attr in attrs) {
if ( attrs.hasOwnProperty(attr) ) {
- this.set(attr, attrs[attr]);
+ this.set(attr, attrs[attr], opts);
}
}
return this;
@@ -976,9 +978,8 @@ YUI.add('attribute-core', function (Y, NAME) {
_protectAttrs : AttributeCore.protectAttrs,
/**
- * 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.
+ * 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
@@ -1034,7 +1035,6 @@ YUI.add('attribute-core', function (Y, NAME) {
* @private
*/
_getAttrInitVal : function(attr, cfg, initValues) {
-
var val = cfg.value,
valFn = cfg.valueFn,
tmpVal,
@@ -1085,12 +1085,15 @@ YUI.add('attribute-core', function (Y, NAME) {
},
/**
- * Utility method to set up initial attributes defined during construction, either through the constructor.ATTRS property, or explicitly passed in.
+ * Utility method to set up initial attributes defined during construction,
+ * either through the constructor.ATTRS property, or explicitly passed in.
*
* @method _initAttrs
* @protected
- * @param attrs {Object} The attributes to add during construction (passed through to <a href="#method_addAttrs">addAttrs</a>). These can also be defined on the constructor being augmented with Attribute by defining the ATTRS property on the constructor.
- * @param values {Object} The initial attribute values to apply (passed through to <a href="#method_addAttrs">addAttrs</a>). These are not merged/cloned. The caller is responsible for isolating user provided values if required.
+ * @param attrs {Object} The attributes to add during construction (passed through to <a href="#method_addAttrs">addAttrs</a>).
+ * These can also be defined on the constructor being augmented with Attribute by defining the ATTRS property on the constructor.
+ * @param values {Object} The initial attribute values to apply (passed through to <a href="#method_addAttrs">addAttrs</a>).
+ * These are not merged/cloned. The caller is responsible for isolating user provided values if required.
* @param lazy {boolean} Whether or not to add attributes lazily (passed through to <a href="#method_addAttrs">addAttrs</a>).
*/
_initAttrs : function(attrs, values, lazy) {
View
2  build/attribute-core/attribute-core-min.js
@@ -1 +1 @@
-YUI.add("attribute-core",function(e,t){function E(e,t,n){this._yuievt=null,this._initAttrHost(e,t,n)}e.State=function(){this.data={}},e.State.prototype={add:function(e,t,n){var r=this.data[e];r||(r=this.data[e]={}),r[t]=n},addAll:function(e,t){var n=this.data[e],r;n||(n=this.data[e]={});for(r in t)t.hasOwnProperty(r)&&(n[r]=t[r])},remove:function(e,t){var n=this.data[e];n&&delete n[t]},removeAll:function(t,n){var r;n?e.each(n,function(e,n){this.remove(t,typeof n=="string"?n:e)},this):(r=this.data,t in r&&delete r[t])},get:function(e,t){var n=this.data[e];if(n)return n[t]},getAll:function(e,t){var n=this.data[e],r,i;if(t)i=n;else if(n){i={};for(r in n)n.hasOwnProperty(r)&&(i[r]=n[r])}return i}};var n=e.Object,r=e.Lang,i=".",s="getter",o="setter",u="readOnly",a="writeOnce",f="initOnly",l="validator",c="value",h="valueFn",p="lazyAdd",d="added",v="_bypassProxy",m="initializing",g="initValue",y="lazy",b="isLazyAdd",w;E.INVALID_VALUE={},w=E.INVALID_VALUE,E._ATTR_CFG=[o,s,l,c,h,a,u,p,v],E.protectAttrs=function(t){if(t){t=e.merge(t);for(var n in t)t.hasOwnProperty(n)&&(t[n]=e.merge(t[n]))}return t},E.prototype={_initAttrHost:function(t,n,r){this._state=new e.State,this._initAttrs(t,n,r)},addAttr:function(e,t,n){var r=this,i=r._state,s,o;t=t||{},n=p in t?t[p]:n;if(n&&!r.attrAdded(e))i.addAll(e,{lazy:t,added:!0});else if(!r.attrAdded(e)||i.get(e,b))o=c in t,o&&(s=t.value,delete t.value),t.added=!0,t.initializing=!0,i.addAll(e,t),o&&r.set(e,s),i.remove(e,m);return r},attrAdded:function(e){return!!this._state.get(e,d)},get:function(e){return this._getAttr(e)},_isLazyAttr:function(e){return this._state.get(e,y)},_addLazyAttr:function(e,t){var n=this._state,r=n.get(e,y);n.add(e,b,!0),n.remove(e,y),this.addAttr(e,r)},set:function(e,t){return this._setAttr(e,t)},_set:function(e,t){return this._setAttr(e,t,null,!0)},_setAttr:function(t,r,s,o){var u=!0,a=this._state,l=this._stateProxy,h,p,d,v,m,g,y;return t.indexOf(i)!==-1&&(d=t,v=t.split(i),t=v.shift()),this._isLazyAttr(t)&&this._addLazyAttr(t),h=a.getAll(t,!0)||{},p=!(c in h),l&&t in l&&!h._bypassProxy&&(p=!1),g=h.writeOnce,y=h.initializing,!p&&!o&&(g&&(u=!1),h.readOnly&&(u=!1)),!y&&!o&&g===f&&(u=!1),u&&(p||(m=this.get(t)),v&&(r=n.setValue(e.clone(m),v,r),r===undefined&&(u=!1)),u&&(!this._fireAttrChange||y?this._setAttrVal(t,d,m,r):this._fireAttrChange(t,d,m,r,s))),this},_getAttr:function(e){var t=this,r=e,o=t._state,u,a,f,l;return e.indexOf(i)!==-1&&(u=e.split(i),e=u.shift()),t._tCfgs&&t._tCfgs[e]&&(l={},l[e]=t._tCfgs[e],delete t._tCfgs[e],t._addAttrs(l,t._tVals)),t._isLazyAttr(e)&&t._addLazyAttr(e),f=t._getStateVal(e),a=o.get(e,s),a&&!a.call&&(a=this[a]),f=a?a.call(t,f,r):f,f=u?n.getValue(f,u):f,f},_getStateVal:function(e){var t=this._stateProxy;return t&&e in t&&!this._state.get(e,v)?t[e]:this._state.get(e,c)},_setStateVal:function(e,t){var n=this._stateProxy;n&&e in n&&!this._state.get(e,v)?n[e]=t:this._state.add(e,c,t)},_setAttrVal:function(e,t,n,i){var s=this,o=!0,u=this._state.getAll(e,!0)||{},a=u.validator,f=u.setter,l=u.initializing,c=this._getStateVal(e),h=t||e,p,d;return a&&(a.call||(a=this[a]),a&&(d=a.call(s,i,h),!d&&l&&(i=u.defaultValue,d=!0))),!a||d?(f&&(f.call||(f=this[f]),f&&(p=f.call(s,i,h),p===w?o=!1:p!==undefined&&(i=p))),o&&(!t&&i===c&&!r.isObject(i)?o=!1:(g in u||(u.initValue=i),s._setStateVal(e,i)))):o=!1,o},setAttrs:function(e){return this._setAttrs(e)},_setAttrs:function(e){var t;for(t in e)e.hasOwnProperty(t)&&this.set(t,e[t]);return this},getAttrs:function(e){return this._getAttrs(e)},_getAttrs:function(e){var t={},r,i,s,o=e===!0;if(!e||o)e=n.keys(this._state.data);for(i=0,s=e.length;i<s;i++){r=e[i];if(!o||this._getStateVal(r)!=this._state.get(r,g))t[r]=this.get(r)}return t},addAttrs:function(e,t,n){var r=this;return e&&(r._tCfgs=e,r._tVals=r._normAttrVals(t),r._addAttrs(e,r._tVals,n),r._tCfgs=r._tVals=null),r},_addAttrs:function(e,t,n){var r=this,i,s,o;for(i in e)e.hasOwnProperty(i)&&(s=e[i],s.defaultValue=s.value,o=r._getAttrInitVal(i,s,r._tVals),o!==undefined&&(s.value=o),r._tCfgs[i]&&delete r._tCfgs[i],r.addAttr(i,s,n))},_protectAttrs:E.protectAttrs,_normAttrVals:function(e){var t={},n={},r,s,o,u;if(e){for(u in e)e.hasOwnProperty(u)&&(u.indexOf(i)!==-1?(r=u.split(i),s=r.shift(),o=n[s]=n[s]||[],o[o.length]={path:r,value:e[u]}):t[u]=e[u]);return{simple:t,complex:n}}return null},_getAttrInitVal:function(e,t,r){var i=t.value,s=t.valueFn,o,u=!1,a,f,l,c,h,p,d;!t.readOnly&&r&&(a=r.simple,a&&a.hasOwnProperty(e)&&(i=a[e],u=!0)),s&&!u&&(s.call||(s=this[s]),s&&(o=s.call(this,e),i=o));if(!t.readOnly&&r){f=r.complex;if(f&&f.hasOwnProperty(e)&&i!==undefined&&i!==null){d=f[e];for(l=0,c=d.length;l<c;++l)h=d[l].path,p=d[l].value,n.setValue(i,h,p)}}return i},_initAttrs:function(t,n,r){t=t||this.constructor.ATTRS;var i=e.Base,s=e.BaseCore,o=i&&e.instanceOf(this,i),u=!o&&s&&e.instanceOf(this,s);t&&!o&&!u&&this.addAttrs(e.AttributeCore.protectAttrs(t),n,r)}},e.AttributeCore=E},"@VERSION@",{requires:["oop"]});
+YUI.add("attribute-core",function(e,t){function E(e,t,n){this._yuievt=null,this._initAttrHost(e,t,n)}e.State=function(){this.data={}},e.State.prototype={add:function(e,t,n){var r=this.data[e];r||(r=this.data[e]={}),r[t]=n},addAll:function(e,t){var n=this.data[e],r;n||(n=this.data[e]={});for(r in t)t.hasOwnProperty(r)&&(n[r]=t[r])},remove:function(e,t){var n=this.data[e];n&&delete n[t]},removeAll:function(t,n){var r;n?e.each(n,function(e,n){this.remove(t,typeof n=="string"?n:e)},this):(r=this.data,t in r&&delete r[t])},get:function(e,t){var n=this.data[e];if(n)return n[t]},getAll:function(e,t){var n=this.data[e],r,i;if(t)i=n;else if(n){i={};for(r in n)n.hasOwnProperty(r)&&(i[r]=n[r])}return i}};var n=e.Object,r=e.Lang,i=".",s="getter",o="setter",u="readOnly",a="writeOnce",f="initOnly",l="validator",c="value",h="valueFn",p="lazyAdd",d="added",v="_bypassProxy",m="initializing",g="initValue",y="lazy",b="isLazyAdd",w;E.INVALID_VALUE={},w=E.INVALID_VALUE,E._ATTR_CFG=[o,s,l,c,h,a,u,p,v],E.protectAttrs=function(t){if(t){t=e.merge(t);for(var n in t)t.hasOwnProperty(n)&&(t[n]=e.merge(t[n]))}return t},E.prototype={_initAttrHost:function(t,n,r){this._state=new e.State,this._initAttrs(t,n,r)},addAttr:function(e,t,n){var r=this,i=r._state,s,o;t=t||{},n=p in t?t[p]:n;if(n&&!r.attrAdded(e))i.addAll(e,{lazy:t,added:!0});else if(!r.attrAdded(e)||i.get(e,b))o=c in t,o&&(s=t.value,delete t.value),t.added=!0,t.initializing=!0,i.addAll(e,t),o&&r.set(e,s),i.remove(e,m);return r},attrAdded:function(e){return!!this._state.get(e,d)},get:function(e){return this._getAttr(e)},_isLazyAttr:function(e){return this._state.get(e,y)},_addLazyAttr:function(e){var t=this._state,n=t.get(e,y);t.add(e,b,!0),t.remove(e,y),this.addAttr(e,n)},set:function(e,t,n){return this._setAttr(e,t,n)},_set:function(e,t,n){return this._setAttr(e,t,n,!0)},_setAttr:function(t,r,s,o){var u=!0,a=this._state,l=this._stateProxy,h,p,d,v,m,g,y;return t.indexOf(i)!==-1&&(d=t,v=t.split(i),t=v.shift()),this._isLazyAttr(t)&&this._addLazyAttr(t),h=a.getAll(t,!0)||{},p=!(c in h),l&&t in l&&!h._bypassProxy&&(p=!1),g=h.writeOnce,y=h.initializing,!p&&!o&&(g&&(u=!1),h.readOnly&&(u=!1)),!y&&!o&&g===f&&(u=!1),u&&(p||(m=this.get(t)),v&&(r=n.setValue(e.clone(m),v,r),r===undefined&&(u=!1)),u&&(s=s||{},!this._fireAttrChange||y?this._setAttrVal(t,d,m,r,s):this._fireAttrChange(t,d,m,r,s))),this},_getAttr:function(e){var t=this,r=e,o=t._state,u,a,f,l;return e.indexOf(i)!==-1&&(u=e.split(i),e=u.shift()),t._tCfgs&&t._tCfgs[e]&&(l={},l[e]=t._tCfgs[e],delete t._tCfgs[e],t._addAttrs(l,t._tVals)),t._isLazyAttr(e)&&t._addLazyAttr(e),f=t._getStateVal(e),a=o.get(e,s),a&&!a.call&&(a=this[a]),f=a?a.call(t,f,r):f,f=u?n.getValue(f,u):f,f},_getStateVal:function(e){var t=this._stateProxy;return t&&e in t&&!this._state.get(e,v)?t[e]:this._state.get(e,c)},_setStateVal:function(e,t){var n=this._stateProxy;n&&e in n&&!this._state.get(e,v)?n[e]=t:this._state.add(e,c,t)},_setAttrVal:function(e,t,n,i,s){var o=this,u=!0,a=this._state.getAll(e,!0)||{},f=a.validator,l=a.setter,c=a.initializing,h=this._getStateVal(e),p=t||e,d,v;return f&&(f.call||(f=this[f]),f&&(v=f.call(o,i,p,s),!v&&c&&(i=a.defaultValue,v=!0))),!f||v?(l&&(l.call||(l=this[l]),l&&(d=l.call(o,i,p,s),d===w?u=!1:d!==undefined&&(i=d))),u&&(!t&&i===h&&!r.isObject(i)?u=!1:(g in a||(a.initValue=i),o._setStateVal(e,i)))):u=!1,u},setAttrs:function(e,t){return this._setAttrs(e,t)},_setAttrs:function(e,t){var n;for(n in e)e.hasOwnProperty(n)&&this.set(n,e[n],t);return this},getAttrs:function(e){return this._getAttrs(e)},_getAttrs:function(e){var t={},r,i,s,o=e===!0;if(!e||o)e=n.keys(this._state.data);for(i=0,s=e.length;i<s;i++){r=e[i];if(!o||this._getStateVal(r)!=this._state.get(r,g))t[r]=this.get(r)}return t},addAttrs:function(e,t,n){var r=this;return e&&(r._tCfgs=e,r._tVals=r._normAttrVals(t),r._addAttrs(e,r._tVals,n),r._tCfgs=r._tVals=null),r},_addAttrs:function(e,t,n){var r=this,i,s,o;for(i in e)e.hasOwnProperty(i)&&(s=e[i],s.defaultValue=s.value,o=r._getAttrInitVal(i,s,r._tVals),o!==undefined&&(s.value=o),r._tCfgs[i]&&delete r._tCfgs[i],r.addAttr(i,s,n))},_protectAttrs:E.protectAttrs,_normAttrVals:function(e){var t={},n={},r,s,o,u;if(e){for(u in e)e.hasOwnProperty(u)&&(u.indexOf(i)!==-1?(r=u.split(i),s=r.shift(),o=n[s]=n[s]||[],o[o.length]={path:r,value:e[u]}):t[u]=e[u]);return{simple:t,complex:n}}return null},_getAttrInitVal:function(e,t,r){var i=t.value,s=t.valueFn,o,u=!1,a,f,l,c,h,p,d;!t.readOnly&&r&&(a=r.simple,a&&a.hasOwnProperty(e)&&(i=a[e],u=!0)),s&&!u&&(s.call||(s=this[s]),s&&(o=s.call(this,e),i=o));if(!t.readOnly&&r){f=r.complex;if(f&&f.hasOwnProperty(e)&&i!==undefined&&i!==null){d=f[e];for(l=0,c=d.length;l<c;++l)h=d[l].path,p=d[l].value,n.setValue(i,h,p)}}return i},_initAttrs:function(t,n,r){t=t||this.constructor.ATTRS;var i=e.Base,s=e.BaseCore,o=i&&e.instanceOf(this,i),u=!o&&s&&e.instanceOf(this,s);t&&!o&&!u&&this.addAttrs(e.AttributeCore.protectAttrs(t),n,r)}},e.AttributeCore=E},"@VERSION@",{requires:["oop"]});
View
81 build/attribute-core/attribute-core.js
@@ -216,8 +216,10 @@ YUI.add('attribute-core', function (Y, NAME) {
* additional, less commonly used attribute methods, such as `modifyAttr`, `removeAttr` and `reset`.</p>
*
* @class AttributeCore
- * @param attrs {Object} The attributes to add during construction (passed through to <a href="#method_addAttrs">addAttrs</a>). These can also be defined on the constructor being augmented with Attribute by defining the ATTRS property on the constructor.
- * @param values {Object} The initial attribute values to apply (passed through to <a href="#method_addAttrs">addAttrs</a>). These are not merged/cloned. The caller is responsible for isolating user provided values if required.
+ * @param attrs {Object} The attributes to add during construction (passed through to <a href="#method_addAttrs">addAttrs</a>).
+ * These can also be defined on the constructor being augmented with Attribute by defining the ATTRS property on the constructor.
+ * @param values {Object} The initial attribute values to apply (passed through to <a href="#method_addAttrs">addAttrs</a>).
+ * These are not merged/cloned. The caller is responsible for isolating user provided values if required.
* @param lazy {boolean} Whether or not to add attributes lazily (passed through to <a href="#method_addAttrs">addAttrs</a>).
*/
function AttributeCore(attrs, values, lazy) {
@@ -288,8 +290,10 @@ YUI.add('attribute-core', function (Y, NAME) {
* constructor.
*
* @method _initAttrHost
- * @param attrs {Object} The attributes to add during construction (passed through to <a href="#method_addAttrs">addAttrs</a>). These can also be defined on the constructor being augmented with Attribute by defining the ATTRS property on the constructor.
- * @param values {Object} The initial attribute values to apply (passed through to <a href="#method_addAttrs">addAttrs</a>). These are not merged/cloned. The caller is responsible for isolating user provided values if required.
+ * @param attrs {Object} The attributes to add during construction (passed through to <a href="#method_addAttrs">addAttrs</a>).
+ * These can also be defined on the constructor being augmented with Attribute by defining the ATTRS property on the constructor.
+ * @param values {Object} The initial attribute values to apply (passed through to <a href="#method_addAttrs">addAttrs</a>).
+ * These are not merged/cloned. The caller is responsible for isolating user provided values if required.
* @param lazy {boolean} Whether or not to add attributes lazily (passed through to <a href="#method_addAttrs">addAttrs</a>).
* @private
*/
@@ -330,7 +334,8 @@ YUI.add('attribute-core', function (Y, NAME) {
* 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.
- * <p>The writeOnce attribute can also be set to the string "initOnly", in which case the attribute can only be set during initialization
+ * <p>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)</p>
* </dd>
*
@@ -413,12 +418,13 @@ YUI.add('attribute-core', function (Y, NAME) {
added : true
});
} else {
-
+ /*jshint maxlen:200*/
if (!host.attrAdded(name) || state.get(name, IS_LAZY_ADD)) {
hasValue = (VALUE in config);
+ /*jshint maxlen:150*/
if (hasValue) {
// We'll go through set, don't want to set value in config directly
@@ -448,7 +454,8 @@ YUI.add('attribute-core', function (Y, NAME) {
*
* @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.
+ * @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);
@@ -490,7 +497,7 @@ YUI.add('attribute-core', function (Y, NAME) {
* @private
* @param {Object} name The name of the attribute
*/
- _addLazyAttr: function(name, cfg) {
+ _addLazyAttr: function(name) {
var state = this._state,
lazyCfg = state.get(name, LAZY);
@@ -508,13 +515,12 @@ YUI.add('attribute-core', function (Y, NAME) {
* @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. <code>set("x.y.z", 5)</code>).
- *
* @param {Any} value The value to set the attribute to.
- *
+ * @param {Object} [opts] Optional data providing the circumstances for the change.
* @return {Object} A reference to the host object.
*/
- set : function(name, val) {
- return this._setAttr(name, val);
+ set : function(name, val, opts) {
+ return this._setAttr(name, val, opts);
},
/**
@@ -526,10 +532,11 @@ YUI.add('attribute-core', function (Y, NAME) {
*
* @param {String} name The name of the attribute.
* @param {Any} val The value to set the attribute to.
+ * @param {Object} [opts] Optional data providing the circumstances for the change.
* @return {Object} A reference to the host object.
*/
- _set : function(name, val) {
- return this._setAttr(name, val, null, true);
+ _set : function(name, val, opts) {
+ return this._setAttr(name, val, opts, true);
},
/**
@@ -543,22 +550,13 @@ YUI.add('attribute-core', function (Y, NAME) {
*
* @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.
- * This is currently a hack. There's no real need for the AttributeCore implementation
- * to support this parameter, but breaking it out into AttributeObservable, results in
- * additional function hops for the critical path.
+ * @param {Object} [opts] Optional data providing the circumstances for the change.
* @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) {
-
- // HACK - no real reason core needs to know about opts, but
- // it adds fn hops if we want to break it out.
- // Not sure it's worth it for this critical path
-
var allowSet = true,
state = this._state,
stateProxy = this._stateProxy,
@@ -622,8 +620,9 @@ YUI.add('attribute-core', function (Y, NAME) {
}
if (allowSet) {
+ opts = opts || {};
if (!this._fireAttrChange || initializing) {
- this._setAttrVal(name, strPath, currVal, val);
+ this._setAttrVal(name, strPath, currVal, val, opts);
} else {
// HACK - no real reason core needs to know about _fireAttrChange, but
// it adds fn hops if we want to break it out. Not sure it's worth it for this critical path
@@ -731,10 +730,11 @@ YUI.add('attribute-core', function (Y, 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.
+ * @param {Object} [opts] Optional data providing the circumstances for the change.
*
* @return {booolean} true if the new attribute value was stored, false if not.
*/
- _setAttrVal : function(attrName, subAttrName, prevVal, newVal) {
+ _setAttrVal : function(attrName, subAttrName, prevVal, newVal, opts) {
var host = this,
allowSet = true,
@@ -753,7 +753,7 @@ YUI.add('attribute-core', function (Y, NAME) {
validator = this[validator];
}
if (validator) {
- valid = validator.call(host, newVal, name);
+ valid = validator.call(host, newVal, name, opts);
if (!valid && initializing) {
newVal = cfg.defaultValue;
@@ -769,7 +769,7 @@ YUI.add('attribute-core', function (Y, NAME) {
setter = this[setter];
}
if (setter) {
- retVal = setter.call(host, newVal, name);
+ retVal = setter.call(host, newVal, name, opts);
if (retVal === INVALID_VALUE) {
allowSet = false;
@@ -803,11 +803,12 @@ YUI.add('attribute-core', function (Y, NAME) {
*
* @method setAttrs
* @param {Object} attrs An object with attributes name/value pairs.
+ * @param {Object} [opts] Optional data providing the circumstances for the change.
* @return {Object} A reference to the host object.
* @chainable
*/
- setAttrs : function(attrs) {
- return this._setAttrs(attrs);
+ setAttrs : function(attrs, opts) {
+ return this._setAttrs(attrs, opts);
},
/**
@@ -816,14 +817,15 @@ YUI.add('attribute-core', function (Y, NAME) {
* @method _setAttrs
* @protected
* @param {Object} attrs An object with attributes name/value pairs.
+ * @param {Object} [opts] Optional data providing the circumstances for the change
* @return {Object} A reference to the host object.
* @chainable
*/
- _setAttrs : function(attrs) {
+ _setAttrs : function(attrs, opts) {
var attr;
for (attr in attrs) {
if ( attrs.hasOwnProperty(attr) ) {
- this.set(attr, attrs[attr]);
+ this.set(attr, attrs[attr], opts);
}
}
return this;
@@ -965,9 +967,8 @@ YUI.add('attribute-core', function (Y, NAME) {
_protectAttrs : AttributeCore.protectAttrs,
/**
- * 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.
+ * 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
@@ -1023,7 +1024,6 @@ YUI.add('attribute-core', function (Y, NAME) {
* @private
*/
_getAttrInitVal : function(attr, cfg, initValues) {
-
var val = cfg.value,
valFn = cfg.valueFn,
tmpVal,
@@ -1074,12 +1074,15 @@ YUI.add('attribute-core', function (Y, NAME) {
},
/**
- * Utility method to set up initial attributes defined during construction, either through the constructor.ATTRS property, or explicitly passed in.
+ * Utility method to set up initial attributes defined during construction,
+ * either through the constructor.ATTRS property, or explicitly passed in.
*
* @method _initAttrs
* @protected
- * @param attrs {Object} The attributes to add during construction (passed through to <a href="#method_addAttrs">addAttrs</a>). These can also be defined on the constructor being augmented with Attribute by defining the ATTRS property on the constructor.
- * @param values {Object} The initial attribute values to apply (passed through to <a href="#method_addAttrs">addAttrs</a>). These are not merged/cloned. The caller is responsible for isolating user provided values if required.
+ * @param attrs {Object} The attributes to add during construction (passed through to <a href="#method_addAttrs">addAttrs</a>).
+ * These can also be defined on the constructor being augmented with Attribute by defining the ATTRS property on the constructor.
+ * @param values {Object} The initial attribute values to apply (passed through to <a href="#method_addAttrs">addAttrs</a>).
+ * These are not merged/cloned. The caller is responsible for isolating user provided values if required.
* @param lazy {boolean} Whether or not to add attributes lazily (passed through to <a href="#method_addAttrs">addAttrs</a>).
*/
_initAttrs : function(attrs, values, lazy) {
View
53 build/attribute-extras/attribute-extras-coverage.js
@@ -26,9 +26,9 @@ _yuitest_coverage["build/attribute-extras/attribute-extras.js"] = {
path: "build/attribute-extras/attribute-extras.js",
code: []
};
-_yuitest_coverage["build/attribute-extras/attribute-extras.js"].code=["YUI.add('attribute-extras', function (Y, NAME) {",""," /**"," * 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-extras submodule provides less commonly used attribute methods, and can"," * be augmented/mixed into an implemention which used attribute-core."," *"," * @module attribute"," * @submodule attribute-extras"," */"," var BROADCAST = \"broadcast\","," PUBLISHED = \"published\","," INIT_VALUE = \"initValue\",",""," MODIFIABLE = {"," readOnly:1,"," writeOnce:1,"," getter:1,"," broadcast:1"," };",""," /**"," * A augmentable implementation for AttributeCore, providing less frequently used"," * methods for Attribute management such as modifyAttrs(), removeAttr and reset()"," *"," * @class AttributeExtras"," * @extensionfor AttributeCore"," */"," function AttributeExtras() {}",""," AttributeExtras.prototype = {",""," /**"," * Updates the configuration of an attribute which has already been added."," * <p>"," * 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."," * </p>"," * @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);"," },",""," /**"," * 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",""," if (name) {"," if (host._isLazyAttr(name)) {"," host._addLazyAttr(name);"," }"," host.set(name, host._state.get(name, INIT_VALUE));"," } else {"," Y.each(host._state.data, function(v, n) {"," host.reset(n);"," });"," }"," return host;"," },",""," /**"," * Returns an object with the configuration properties (and value)"," * for the given attribute. 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,"," state = this._state;",""," if (name) {"," o = state.getAll(name) || {};"," } else {"," o = {};"," Y.each(state.data, function(v, n) {"," o[n] = state.getAll(n);"," });"," }",""," return o;"," }"," };",""," Y.AttributeExtras = AttributeExtras;","","","}, '@VERSION@', {\"requires\": [\"oop\"]});"];
-_yuitest_coverage["build/attribute-extras/attribute-extras.js"].lines = {"1":0,"20":0,"38":0,"40":0,"55":0,"58":0,"60":0,"61":0,"64":0,"65":0,"66":0,"67":0,"70":0,"71":0,"86":0,"99":0,"101":0,"102":0,"103":0,"105":0,"107":0,"108":0,"111":0,"125":0,"128":0,"129":0,"131":0,"132":0,"133":0,"137":0,"141":0};
-_yuitest_coverage["build/attribute-extras/attribute-extras.js"].functions = {"AttributeExtras:38":0,"modifyAttr:54":0,"removeAttr:85":0,"(anonymous 2):107":0,"reset:98":0,"(anonymous 3):132":0,"_getAttrCfg:124":0,"(anonymous 1):1":0};
+_yuitest_coverage["build/attribute-extras/attribute-extras.js"].code=["YUI.add('attribute-extras', function (Y, NAME) {",""," /**"," * 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-extras submodule provides less commonly used attribute methods, and can"," * be augmented/mixed into an implemention which used attribute-core."," *"," * @module attribute"," * @submodule attribute-extras"," */"," var BROADCAST = \"broadcast\","," PUBLISHED = \"published\","," INIT_VALUE = \"initValue\",",""," MODIFIABLE = {"," readOnly:1,"," writeOnce:1,"," getter:1,"," broadcast:1"," };",""," /**"," * A augmentable implementation for AttributeCore, providing less frequently used"," * methods for Attribute management such as modifyAttrs(), removeAttr and reset()"," *"," * @class AttributeExtras"," * @extensionfor AttributeCore"," */"," function AttributeExtras() {}",""," AttributeExtras.prototype = {",""," /**"," * Updates the configuration of an attribute which has already been added."," * <p>"," * 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."," * </p>"," * @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);"," }"," }"," }"," }"," /*jshint maxlen:200*/"," /*jshint maxlen:150 */"," },",""," /**"," * 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);"," },",""," /**"," * 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",""," if (name) {"," if (host._isLazyAttr(name)) {"," host._addLazyAttr(name);"," }"," host.set(name, host._state.get(name, INIT_VALUE));"," } else {"," Y.each(host._state.data, function(v, n) {"," host.reset(n);"," });"," }"," return host;"," },",""," /**"," * Returns an object with the configuration properties (and value)"," * for the given attribute. 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,"," state = this._state;",""," if (name) {"," o = state.getAll(name) || {};"," } else {"," o = {};"," Y.each(state.data, function(v, n) {"," o[n] = state.getAll(n);"," });"," }",""," return o;"," }"," };",""," Y.AttributeExtras = AttributeExtras;","","","}, '@VERSION@', {\"requires\": [\"oop\"]});"];
+_yuitest_coverage["build/attribute-extras/attribute-extras.js"].lines = {"1":0,"20":0,"38":0,"40":0,"55":0,"58":0,"60":0,"61":0,"64":0,"65":0,"66":0,"67":0,"70":0,"71":0,"87":0,"100":0,"102":0,"103":0,"104":0,"106":0,"108":0,"109":0,"112":0,"126":0,"129":0,"130":0,"132":0,"133":0,"134":0,"138":0,"142":0};
+_yuitest_coverage["build/attribute-extras/attribute-extras.js"].functions = {"AttributeExtras:38":0,"modifyAttr:54":0,"removeAttr:86":0,"(anonymous 2):108":0,"reset:99":0,"(anonymous 3):133":0,"_getAttrCfg:125":0,"(anonymous 1):1":0};
_yuitest_coverage["build/attribute-extras/attribute-extras.js"].coveredLines = 31;
_yuitest_coverage["build/attribute-extras/attribute-extras.js"].coveredFunctions = 8;
_yuitest_coverline("build/attribute-extras/attribute-extras.js", 1);
@@ -122,7 +122,8 @@ state.remove(name, PUBLISHED);
}
}
}
-
+ /*jshint maxlen:200*/
+ /*jshint maxlen:150 */
},
/**
@@ -132,8 +133,8 @@ state.remove(name, PUBLISHED);
* @param {String} name The name of the attribute to be removed.
*/
removeAttr: function(name) {
- _yuitest_coverfunc("build/attribute-extras/attribute-extras.js", "removeAttr", 85);
-_yuitest_coverline("build/attribute-extras/attribute-extras.js", 86);
+ _yuitest_coverfunc("build/attribute-extras/attribute-extras.js", "removeAttr", 86);
+_yuitest_coverline("build/attribute-extras/attribute-extras.js", 87);
this._state.removeAll(name);
},
@@ -147,28 +148,28 @@ this._state.removeAll(name);
* @chainable
*/
reset : function(name) {
- _yuitest_coverfunc("build/attribute-extras/attribute-extras.js", "reset", 98);
-_yuitest_coverline("build/attribute-extras/attribute-extras.js", 99);
+ _yuitest_coverfunc("build/attribute-extras/attribute-extras.js", "reset", 99);
+_yuitest_coverline("build/attribute-extras/attribute-extras.js", 100);
var host = this; // help compression
- _yuitest_coverline("build/attribute-extras/attribute-extras.js", 101);
+ _yuitest_coverline("build/attribute-extras/attribute-extras.js", 102);
if (name) {
- _yuitest_coverline("build/attribute-extras/attribute-extras.js", 102);
+ _yuitest_coverline("build/attribute-extras/attribute-extras.js", 103);
if (host._isLazyAttr(name)) {
- _yuitest_coverline("build/attribute-extras/attribute-extras.js", 103);
+ _yuitest_coverline("build/attribute-extras/attribute-extras.js", 104);
host._addLazyAttr(name);
}
- _yuitest_coverline("build/attribute-extras/attribute-extras.js", 105);
+ _yuitest_coverline("build/attribute-extras/attribute-extras.js", 106);
host.set(name, host._state.get(name, INIT_VALUE));
} else {
- _yuitest_coverline("build/attribute-extras/attribute-extras.js", 107);
+ _yuitest_coverline("build/attribute-extras/attribute-extras.js", 108);
Y.each(host._state.data, function(v, n) {
- _yuitest_coverfunc("build/attribute-extras/attribute-extras.js", "(anonymous 2)", 107);
-_yuitest_coverline("build/attribute-extras/attribute-extras.js", 108);
+ _yuitest_coverfunc("build/attribute-extras/attribute-extras.js", "(anonymous 2)", 108);
+_yuitest_coverline("build/attribute-extras/attribute-extras.js", 109);
host.reset(n);
});
}
- _yuitest_coverline("build/attribute-extras/attribute-extras.js", 111);
+ _yuitest_coverline("build/attribute-extras/attribute-extras.js", 112);
return host;
},
@@ -183,32 +184,32 @@ return host;
* @return {Object} The configuration properties for the given attribute, or all attributes.
*/
_getAttrCfg : function(name) {
- _yuitest_coverfunc("build/attribute-extras/attribute-extras.js", "_getAttrCfg", 124);
-_yuitest_coverline("build/attribute-extras/attribute-extras.js", 125);
+ _yuitest_coverfunc("build/attribute-extras/attribute-extras.js", "_getAttrCfg", 125);
+_yuitest_coverline("build/attribute-extras/attribute-extras.js", 126);
var o,
state = this._state;
- _yuitest_coverline("build/attribute-extras/attribute-extras.js", 128);
+ _yuitest_coverline("build/attribute-extras/attribute-extras.js", 129);
if (name) {
- _yuitest_coverline("build/attribute-extras/attribute-extras.js", 129);
+ _yuitest_coverline("build/attribute-extras/attribute-extras.js", 130);
o = state.getAll(name) || {};
} else {
- _yuitest_coverline("build/attribute-extras/attribute-extras.js", 131);
-o = {};
_yuitest_coverline("build/attribute-extras/attribute-extras.js", 132);
+o = {};
+ _yuitest_coverline("build/attribute-extras/attribute-extras.js", 133);
Y.each(state.data, function(v, n) {
- _yuitest_coverfunc("build/attribute-extras/attribute-extras.js", "(anonymous 3)", 132);
-_yuitest_coverline("build/attribute-extras/attribute-extras.js", 133);
+ _yuitest_coverfunc("build/attribute-extras/attribute-extras.js", "(anonymous 3)", 133);
+_yuitest_coverline("build/attribute-extras/attribute-extras.js", 134);
o[n] = state.getAll(n);
});
}
- _yuitest_coverline("build/attribute-extras/attribute-extras.js", 137);
+ _yuitest_coverline("build/attribute-extras/attribute-extras.js", 138);
return o;
}
};
- _yuitest_coverline("build/attribute-extras/attribute-extras.js", 141);
+ _yuitest_coverline("build/attribute-extras/attribute-extras.js", 142);
Y.AttributeExtras = AttributeExtras;
View
3  build/attribute-extras/attribute-extras-debug.js
@@ -73,8 +73,9 @@ YUI.add('attribute-extras', function (Y, NAME) {
}
}
}
-
+ /*jshint maxlen:200*/
if (!host.attrAdded(name)) {Y.log('Attribute modifyAttr:' + name + ' has not been added. Use addAttr to add the attribute', 'warn', 'attribute');}
+ /*jshint maxlen:150 */
},
/**
View
3  build/attribute-extras/attribute-extras.js
@@ -73,7 +73,8 @@ YUI.add('attribute-extras', function (Y, NAME) {
}
}
}
-
+ /*jshint maxlen:200*/
+ /*jshint maxlen:150 */
},
/**
View
18 build/attribute-observable/attribute-observable-coverage.js
@@ -26,8 +26,8 @@ _yuitest_coverage["build/attribute-observable/attribute-observable.js"] = {
path: "build/attribute-observable/attribute-observable.js",
code: []
};
-_yuitest_coverage["build/attribute-observable/attribute-observable.js"].code=["YUI.add('attribute-observable', function (Y, NAME) {",""," /**"," * 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-observable` submodule provides augmentable attribute change event support"," * for AttributeCore based implementations."," *"," * @module attribute"," * @submodule attribute-observable"," */"," var EventTarget = Y.EventTarget,",""," CHANGE = \"Change\","," BROADCAST = \"broadcast\","," PUBLISHED = \"published\";",""," /**"," * Provides an augmentable implementation of attribute change events for"," * AttributeCore."," *"," * @class AttributeObservable"," * @extensionfor AttributeCore"," * @uses EventTarget"," */"," function AttributeObservable() {"," // Perf tweak - avoid creating event literals if not required."," this._ATTR_E_FACADE = {};",""," EventTarget.call(this, {emitFacade:true});"," }",""," AttributeObservable._ATTR_CFG = [BROADCAST];",""," AttributeObservable.prototype = {",""," /**"," * 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. <code>set(\"x.y.z\", 5)</code>)."," *"," * @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);"," },",""," /**"," * Allows setting of readOnly/writeOnce attributes. See <a href=\"#method_set\">set</a> 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);"," },",""," /**"," * Sets multiple attribute values."," *"," * @method setAttrs"," * @param {Object} attrs An object with attributes name/value pairs."," * @param {Object} opts Properties to mix into the event payload. These are shared and mixed into each set"," * @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."," * @param {Object} opts Properties to mix into the event payload. These are shared and mixed into each set"," * @return {Object} A reference to the host object."," * @chainable"," */"," _setAttrs : function(attrs, opts) {"," var attr;"," for (attr in attrs) {"," if ( attrs.hasOwnProperty(attr) ) {"," this.set(attr, attrs[attr], 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,"," broadcast,"," evtCfg;",""," if (!state.get(attrName, PUBLISHED)) {",""," evtCfg = {"," queuable:false,"," defaultTargetOnly: true,"," defaultFn:host._defAttrChangeFn,"," silent:true"," };",""," broadcast = state.get(attrName, BROADCAST);"," if (broadcast !== undefined) {"," evtCfg.broadcast = broadcast;"," }",""," host.publish(eventName, evtCfg);",""," 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);"," }"," }"," };",""," // Basic prototype augment - no lazy constructor invocation."," Y.mix(AttributeObservable, EventTarget, false, null, 1);",""," Y.AttributeObservable = AttributeObservable;",""," /**"," The `AttributeEvents` class extension was deprecated in YUI 3.8.0 and is now"," an alias for the `AttributeObservable` class extension. Use that class"," extnesion instead. This alias will be removed in a future version of YUI.",""," @class AttributeEvents"," @uses EventTarget"," @deprecated Use `AttributeObservable` instead."," @see AttributeObservable"," **/"," Y.AttributeEvents = AttributeObservable;","","","}, '@VERSION@', {\"requires\": [\"event-custom\"]});"];
-_yuitest_coverage["build/attribute-observable/attribute-observable.js"].lines = {"1":0,"20":0,"34":0,"36":0,"38":0,"41":0,"43":0,"66":0,"83":0,"96":0,"110":0,"111":0,"112":0,"113":0,"116":0,"132":0,"139":0,"141":0,"148":0,"149":0,"150":0,"153":0,"155":0,"158":0,"164":0,"165":0,"166":0,"167":0,"170":0,"181":0,"183":0,"185":0,"191":0,"193":0,"205":0};
+_yuitest_coverage["build/attribute-observable/attribute-observable.js"].code=["YUI.add('attribute-observable', function (Y, NAME) {",""," /**"," * 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-observable` submodule provides augmentable attribute change event support"," * for AttributeCore based implementations."," *"," * @module attribute"," * @submodule attribute-observable"," */"," var EventTarget = Y.EventTarget,",""," CHANGE = \"Change\","," BROADCAST = \"broadcast\","," PUBLISHED = \"published\";",""," /**"," * Provides an augmentable implementation of attribute change events for"," * AttributeCore."," *"," * @class AttributeObservable"," * @extensionfor AttributeCore"," * @uses EventTarget"," */"," function AttributeObservable() {"," // Perf tweak - avoid creating event literals if not required."," this._ATTR_E_FACADE = {};",""," EventTarget.call(this, {emitFacade:true});"," }",""," AttributeObservable._ATTR_CFG = [BROADCAST];",""," AttributeObservable.prototype = {",""," /**"," * 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. <code>set(\"x.y.z\", 5)</code>)."," *"," * @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);"," },",""," /**"," * Allows setting of readOnly/writeOnce attributes. See <a href=\"#method_set\">set</a> 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);"," },",""," /**"," * Sets multiple attribute values."," *"," * @method setAttrs"," * @param {Object} attrs An object with attributes name/value pairs."," * @param {Object} opts Properties to mix into the event payload. These are shared and mixed into each set"," * @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."," * @param {Object} opts Properties to mix into the event payload. These are shared and mixed into each set"," * @return {Object} A reference to the host object."," * @chainable"," */"," _setAttrs : function(attrs, opts) {"," var attr;"," for (attr in attrs) {"," if ( attrs.hasOwnProperty(attr) ) {"," this.set(attr, attrs[attr], 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,"," broadcast,"," evtCfg;",""," if (!state.get(attrName, PUBLISHED)) {",""," evtCfg = {"," queuable:false,"," defaultTargetOnly: true,"," defaultFn:host._defAttrChangeFn,"," silent:true"," };",""," broadcast = state.get(attrName, BROADCAST);"," if (broadcast !== undefined) {"," evtCfg.broadcast = broadcast;"," }",""," host.publish(eventName, evtCfg);",""," 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, e.opts)) {"," /*jshint maxlen:200*/"," /*jshint maxlen:150*/"," // Prevent \"after\" listeners from being invoked since nothing changed."," e.stopImmediatePropagation();"," } else {"," e.newVal = this.get(e.attrName);"," }"," }"," };",""," // Basic prototype augment - no lazy constructor invocation."," Y.mix(AttributeObservable, EventTarget, false, null, 1);",""," Y.AttributeObservable = AttributeObservable;",""," /**"," The `AttributeEvents` class extension was deprecated in YUI 3.8.0 and is now"," an alias for the `AttributeObservable` class extension. Use that class"," extnesion instead. This alias will be removed in a future version of YUI.",""," @class AttributeEvents"," @uses EventTarget"," @deprecated Use `AttributeObservable` instead."," @see AttributeObservable"," **/"," Y.AttributeEvents = AttributeObservable;","","","}, '@VERSION@', {\"requires\": [\"event-custom\"]});"];
+_yuitest_coverage["build/attribute-observable/attribute-observable.js"].lines = {"1":0,"20":0,"34":0,"36":0,"38":0,"41":0,"43":0,"66":0,"83":0,"96":0,"110":0,"111":0,"112":0,"113":0,"116":0,"132":0,"139":0,"141":0,"148":0,"149":0,"150":0,"153":0,"155":0,"158":0,"164":0,"165":0,"166":0,"167":0,"170":0,"181":0,"185":0,"187":0,"193":0,"195":0,"207":0};
_yuitest_coverage["build/attribute-observable/attribute-observable.js"].functions = {"AttributeObservable:34":0,"set:65":0,"_set:82":0,"setAttrs:95":0,"_setAttrs:109":0,"_fireAttrChange:131":0,"_defAttrChangeFn:180":0,"(anonymous 1):1":0};
_yuitest_coverage["build/attribute-observable/attribute-observable.js"].coveredLines = 35;
_yuitest_coverage["build/attribute-observable/attribute-observable.js"].coveredFunctions = 8;
@@ -249,22 +249,24 @@ host.fire(eventName, facade);
_defAttrChangeFn : function(e) {
_yuitest_coverfunc("build/attribute-observable/attribute-observable.js", "_defAttrChangeFn", 180);
_yuitest_coverline("build/attribute-observable/attribute-observable.js", 181);
-if (!this._setAttrVal(e.attrName, e.subAttrName, e.prevVal, e.newVal)) {
+if (!this._setAttrVal(e.attrName, e.subAttrName, e.prevVal, e.newVal, e.opts)) {
+ /*jshint maxlen:200*/
+ /*jshint maxlen:150*/
// Prevent "after" listeners from being invoked since nothing changed.
- _yuitest_coverline("build/attribute-observable/attribute-observable.js", 183);
+ _yuitest_coverline("build/attribute-observable/attribute-observable.js", 185);
e.stopImmediatePropagation();
} else {
- _yuitest_coverline("build/attribute-observable/attribute-observable.js", 185);
+ _yuitest_coverline("build/attribute-observable/attribute-observable.js", 187);
e.newVal = this.get(e.attrName);
}
}
};
// Basic prototype augment - no lazy constructor invocation.
- _yuitest_coverline("build/attribute-observable/attribute-observable.js", 191);
+ _yuitest_coverline("build/attribute-observable/attribute-observable.js", 193);
Y.mix(AttributeObservable, EventTarget, false, null, 1);
- _yuitest_coverline("build/attribute-observable/attribute-observable.js", 193);
+ _yuitest_coverline("build/attribute-observable/attribute-observable.js", 195);
Y.AttributeObservable = AttributeObservable;
/**
@@ -277,7 +279,7 @@ Y.AttributeObservable = AttributeObservable;
@deprecated Use `AttributeObservable` instead.
@see AttributeObservable
**/
- _yuitest_coverline("build/attribute-observable/attribute-observable.js", 205);
+ _yuitest_coverline("build/attribute-observable/attribute-observable.js", 207);
Y.AttributeEvents = AttributeObservable;
View
4 build/attribute-observable/attribute-observable-debug.js
@@ -178,8 +178,10 @@ YUI.add('attribute-observable', function (Y, NAME) {
* @param {EventFacade} e The event object for attribute change events.
*/
_defAttrChangeFn : function(e) {
- if (!this._setAttrVal(e.attrName, e.subAttrName, e.prevVal, e.newVal)) {
+ if (!this._setAttrVal(e.attrName, e.subAttrName, e.prevVal, e.newVal, e.opts)) {
+ /*jshint maxlen:200*/
Y.log('State not updated and stopImmediatePropagation called for attribute: ' + e.attrName + ' , value:' + e.newVal, 'warn', 'attribute');
+ /*jshint maxlen:150*/
// Prevent "after" listeners from being invoked since nothing changed.
e.stopImmediatePropagation();
} else {
View
2  build/attribute-observable/attribute-observable-min.js
@@ -1 +1 @@
-YUI.add("attribute-observable",function(e,t){function o(){this._ATTR_E_FACADE={},n.call(this,{emitFacade:!0})}var n=e.EventTarget,r="Change",i="broadcast",s="published";o._ATTR_CFG=[i],o.prototype={set:function(e,t,n){return this._setAttr(e,t,n)},_set:function(e,t,n){return this._setAttr(e,t,n,!0)},setAttrs:function(e,t){return this._setAttrs(e,t)},_setAttrs:function(e,t){var n;for(n in e)e.hasOwnProperty(n)&&this.set(n,e[n],t);return this},_fireAttrChange:function(t,n,o,u,a){var f=this,l=t+r,c=f._state,h,p,d;c.get(t,s)||(d={queuable:!1,defaultTargetOnly:!0,defaultFn:f._defAttrChangeFn,silent:!0},p=c.get(t,i),p!==undefined&&(d.broadcast=p),f.publish(l,d),c.add(t,s,!0)),h=a?e.merge(a):f._ATTR_E_FACADE,h.attrName=t,h.subAttrName=n,h.prevVal=o,h.newVal=u,f.fire(l,h)},_defAttrChangeFn:function(e){this._setAttrVal(e.attrName,e.subAttrName,e.prevVal,e.newVal)?e.newVal=this.get(e.attrName):e.stopImmediatePropagation()}},e.mix(o,n,!1,null,1),e.AttributeObservable=o,e.AttributeEvents=o},"@VERSION@",{requires:["event-custom"]});
+YUI.add("attribute-observable",function(e,t){function o(){this._ATTR_E_FACADE={},n.call(this,{emitFacade:!0})}var n=e.EventTarget,r="Change",i="broadcast",s="published";o._ATTR_CFG=[i],o.prototype={set:function(e,t,n){return this._setAttr(e,t,n)},_set:function(e,t,n){return this._setAttr(e,t,n,!0)},setAttrs:function(e,t){return this._setAttrs(e,t)},_setAttrs:function(e,t){var n;for(n in e)e.hasOwnProperty(n)&&this.set(n,e[n],t);return this},_fireAttrChange:function(t,n,o,u,a){var f=this,l=t+r,c=f._state,h,p,d;c.get(t,s)||(d={queuable:!1,defaultTargetOnly:!0,defaultFn:f._defAttrChangeFn,silent:!0},p=c.get(t,i),p!==undefined&&(d.broadcast=p),f.publish(l,d),c.add(t,s,!0)),h=a?e.merge(a):f._ATTR_E_FACADE,h.attrName=t,h.subAttrName=n,h.prevVal=o,h.newVal=u,f.fire(l,h)},_defAttrChangeFn:function(e){this._setAttrVal(e.attrName,e.subAttrName,e.prevVal,e.newVal,e.opts)?e.newVal=this.get(e.attrName):e.stopImmediatePropagation()}},e.mix(o,n,!1,null,1),e.AttributeObservable=o,e.AttributeEvents=o},"@VERSION@",{requires:["event-custom"]});
View
4 build/attribute-observable/attribute-observable.js
@@ -178,7 +178,9 @@ YUI.add('attribute-observable', function (Y, NAME) {
* @param {EventFacade} e The event object for attribute change events.
*/
_defAttrChangeFn : function(e) {
- if (!this._setAttrVal(e.attrName, e.subAttrName, e.prevVal, e.newVal)) {
+ if (!this._setAttrVal(e.attrName, e.subAttrName, e.prevVal, e.newVal, e.opts)) {
+ /*jshint maxlen:200*/
+ /*jshint maxlen:150*/
// Prevent "after" listeners from being invoked since nothing changed.
e.stopImmediatePropagation();
} else {
View
221 src/attribute/docs/index.mustache
@@ -1,6 +1,6 @@
<div class="intro">
- <p>The Attribute utility allows you to add attributes to any class through an augmentable Attribute interface.
- The interface adds `get and `set methods to your class to retrieve and store attribute values, as well as
+ <p>The Attribute utility allows you to add attributes to any class through an augmentable Attribute interface.
+ The interface adds `get and `set methods to your class to retrieve and store attribute values, as well as
support for change events that can be used to listen for changes in attribute values.</p>
<p>In addition, attributes can be configured with custom getters, setters and validators, allowing the developer to
@@ -11,8 +11,8 @@
<h2 id="augment">Augmenting Your Class With Attribute</h2>
-<p>The Attribute class is designed to be augmented to an existing class (we'll refer to this class as the 'host' class) and adds attribute
-management support to it. For example, assuming you have a class constructor, `MyClass, to which you'd like to add attribute support,
+<p>The Attribute class is designed to be augmented to an existing class (we'll refer to this class as the 'host' class) and adds attribute
+management support to it. For example, assuming you have a class constructor, `MyClass, to which you'd like to add attribute support,
you can simply augment your class with Attribute, as shown below:</p>
```
@@ -26,17 +26,17 @@ YUI().use("attribute", function(Y) {
});
```
<p>Instances of your class will now have Attribute methods available, which your class can use to configure attributes for itself, and which users of your
-class can use to get and set attribute values. See the <a href="{{apiDocs}}/Attribute.html">Attribute API documentation</a> for a complete list of
+class can use to get and set attribute values. See the <a href="{{apiDocs}}/Attribute.html">Attribute API documentation</a> for a complete list of
methods which Attribute will add to your class.</p>
-<p>Note that in general, rather than augmenting Attribute directly, most implementations will simply extend <a href="../base/index.html">Base</a>, which
+<p>Note that in general, rather than augmenting Attribute directly, most implementations will simply extend <a href="../base/index.html">Base</a>, which
augments Attribute, and handles attribute setup for you. Base also sets up all attributes to be lazily initialized (initialized on the first call to get or set) by default, improving performance.</p>
<h2 id="adding">Adding Attributes</h2>
-<p>Once augmented with Attribute, your class can either use the `addAttrs` method to setup attributes en mass, or use the
+<p>Once augmented with Attribute, your class can either use the `addAttrs` method to setup attributes en mass, or use the
`addAttr` method, to add them individually. `addAttrs` is tailored towards use by host classes, since in addition
-to being able to initialize multiple attributes in one call, it also accepts an additional name/value hash, which can be used to allow the
+to being able to initialize multiple attributes in one call, it also accepts an additional name/value hash, which can be used to allow the
user to define the initial value of attributes when instantiating Attribute driven classes, as shown below:</p>
```
@@ -45,7 +45,7 @@ function MyClass(userValues) {
// Use addAttrs, to setup default attributes for
// your class, and mixing in user provided initial values.
-
+
var attributeConfig = {
attrA : {
// ... Configuration for attribute "attrA" ...
@@ -53,9 +53,9 @@ function MyClass(userValues) {
attrB : {
// ... Configuration for attribute "attrB" ...
- }
+ }
};
-
+
this.addAttrs(attributeConfig, userValues);
};
@@ -99,11 +99,11 @@ o.set("attrB", "Hello World!");
<td>Function</td>
<td>
- <p>A function, the return value of which is the value for the attribute. This property can be used instead of the
- value property for static configurations, if you need to set default values which require access to instance state
+ <p>A function, the return value of which is the value for the attribute. This property can be used instead of the
+ value property for static configurations, if you need to set default values which require access to instance state
("this.something").</p>
- <p>If both the value and valueFn properties are defined, the value returned by valueFn has precedence over the value property,
+ <p>If both the value and valueFn properties are defined, the value returned by valueFn has precedence over the value property,
unless it returns undefined, in which case the value property is used.</p>
<p>The valueFn is passed the name of the attribute, allowing users to share valueFn implementations across attributes if required.</p>
@@ -117,10 +117,10 @@ o.set("attrB", "Hello World!");
be used to manipulate or normalize the stored value before it is returned to the user.</p>
<p>The function will be passed the currently stored value of the attribute as the first argument and the name
- of the attribute as the second argument. If configured, the value returned by this function will be
+ of the attribute as the second argument. If configured, the value returned by this function will be
the value returned to the user.</p>
-
- <p>Attribute also supports the ability to return sub-attribute values (`get('a.b.c')`). The getter implications for
+
+ <p>Attribute also supports the ability to return sub-attribute values (`get('a.b.c')`). The getter implications for
this are discussed in the <a href="#subattrs-gsv">Getters, Setters, Validators and Sub Attributes</a> section.</p>
</td>
</tr>
@@ -131,36 +131,49 @@ o.set("attrB", "Hello World!");
<p>Custom 'set' handler, which is invoked when the user calls Attribute's `set` method. It can
be used to manipulate the value which is stored for the attribute.</p>
- <p>The function will be passed the value which the user passed to the set method as the first
- argument and the name of the attribute as the second argument. If configured, the value returned by this
- function will be the value stored as the attribute value.</p>
+ <p>The function will be passed the value which the user passed to the set method as the first
+ argument, the name of the attribute as the second argument and the third argument passed to the `set`
+ method as the third argument. If configured, the value returned by this
+ function will be the value stored as the attribute value.</p>
+
+ <p>The setter may return the constant `Y.Attribute.INVALID_VALUE` to reject a value.</p>
- <p>The getter and setter can be used to normalize values on input/output for the user while storing the
+ <p>The getter and setter can be used to normalize values on input/output for the user while storing the
value in a format most effective for internal operation.</p>
-
- <p>Attribute also supports the ability to set sub-attribute values (`set('a.b.c', 10)`). The setter
- implications for this are discussed in the <a href="#subattrs-gsv">Getters, Setters, Validators and Sub Attributes</a>
+
+ <p>Attribute also supports the ability to set sub-attribute values (`set('a.b.c', 10)`). The setter
+ implications for this are discussed in the <a href="#subattrs-gsv">Getters, Setters, Validators and Sub Attributes</a>
section.</p>
+
+ <p>The third argument is optional and it should have been an object. It may be used to give the reason or origin of
+ the change. This allows the setter to manipulate the value in special ways when it comes from certain
+ sources or to decide whether to accept it or not.</p>
+
</td>
</tr>
<tr>
<td>`validator`</td>
<td>Function</td>
<td>
- <p>Validation function, which if defined, is called before the `setter`.
- The validation function is passed the value which the user is trying to set as the first argument and the name of the
- attribute as the second argument.</p>
+ <p>Validation function, which if defined, is called before the `setter`.
+ The validation function is passed the value which the user is trying to set as the first argument, the name of the
+ attribute as the second argument and the third argument passed to the `set` method
+ as the third argument.</p>
- <p>If the function returns `false`, the attribute's stored value is not updated (and the `setter`, if defined, will not be invoked).
+ <p>If the function returns `false`, the attribute's stored value is not updated (and the `setter`, if defined, will not be invoked).
If it returns `true`, the `setter` is invoked if defined, and the attribute's stored value is updated.</p>
<p>If validation is a potentially expensive task and contains code which would be repeated in a `setter` (for example, converting a string to a Node reference),
- you can combine validation into the `setter` function, by returning `Attribute.INVALID_VALUE` from a `setter` if it
+ you can combine validation into the `setter` function, by returning `Attribute.INVALID_VALUE` from a `setter` if it
encounters an invalid value.</p>
-
- <p>Attribute also supports the ability to set sub-attribute values (set('a.b.c', 10)). The 'validator'
- implications for this are discussed in the <a href="#subattrs-gsv">Getters, Setters, Validators and Sub Attributes</a>
+
+ <p>Attribute also supports the ability to set sub-attribute values (set('a.b.c', 10)). The 'validator'
+ implications for this are discussed in the <a href="#subattrs-gsv">Getters, Setters, Validators and Sub Attributes</a>
section.</p>
+
+ <p>The third argument is optional and it should have been an object. It may be used to give the reason or origin of
+ the change. This allows the validator to accept a value when it comes from certain sources
+ while rejecting it in general.</p>
</td>
</tr>
<tr>
@@ -197,15 +210,15 @@ o.set("attrB", "Hello World!");
<td>boolean</td>
<td>
<p>
- 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
+ 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 <a href="{{apiDocs}}/Attribute.html#method_addAttrs">`addAttrs`</a> method.
</p>
<p>When extending Base, all attributes are added lazily, so this flag can be used to over-ride
lazyAdd behavior for specific attributes.</p>
<p><strong>The only reason you should need to disable `lazyAdd` is if your setter is doing more
than normalizing the attribute value</strong>. For example if your setter is storing some other state, in `this._someProp`, which is being used
- by other parts of your component. In this case, since you're not getting or setting the attribute to access `this._someProp`,
+ by other parts of your component. In this case, since you're not getting or setting the attribute to access `this._someProp`,
it won't get set up lazily, until someone actually calls `get` or `set` for the related attribute.</p>
</td>
</tr>
@@ -215,13 +228,13 @@ o.set("attrB", "Hello World!");
<td>
<p>
This configuration value is not actually supported by Attribute natively, but is available when
- working with Base, and defining attribute configurations using Base's static <a href="{{apiDocs}}/Base.html#property_ATTRS">ATTRS</a> property.
+ working with Base, and defining attribute configurations using Base's static <a href="{{apiDocs}}/Base.html#property_ATTRS">ATTRS</a> property.
</p>
<p>
This property controls how the statically defined default `value` field in Base's `ATTRS` attribute configuration is handled,
when setting it up as the value for an instance. By default (if this property is not defined) object literals and arrays are deep cloned, to protect the default value from
- being modified. Setting cloneDefaultValue to `false` will disable cloning. This is useful in cases where you intend to use arrays or
- object literals by reference (e.g. they point to utilities). A shallow clone will be used if cloneDefaultValue is set to `"shallow"` and a
+ being modified. Setting cloneDefaultValue to `false` will disable cloning. This is useful in cases where you intend to use arrays or
+ object literals by reference (e.g. they point to utilities). A shallow clone will be used if cloneDefaultValue is set to `"shallow"` and a
deep clone will be used for `"deep"` or `true`.
</p>
</td>
@@ -231,7 +244,7 @@ o.set("attrB", "Hello World!");
<h4 id="howtoconfig">Configuring Attributes</h4>
-<p>The above attribute properties are set using an object with property name/value pairs, which is passed to either `addAttrs` or `addAttr` as the
+<p>The above attribute properties are set using an object with property name/value pairs, which is passed to either `addAttrs` or `addAttr` as the
configuration argument. For example, expanding on the code snippet above:</p>
```
@@ -243,7 +256,7 @@ var attributeConfig = {
value: 5,
setter: function(val) {
- return Math.min(val, 10);
+ return Math.min(val, 10);
},
validator: function(val) {
@@ -269,7 +282,7 @@ this.addAttr("attrA", {
value: 5,
setter: function(val) {
- return Math.min(val, 10);
+ return Math.min(val, 10);
},
validator: function(val) {
@@ -278,12 +291,60 @@ this.addAttr("attrA", {
});
```
+<h2>Setting and Getting Attributes</h2>
+
+<p>Attribute adds `set` and `get` methods to the object it augments.</p>
+```
+myObject.set("attrA", 6);
+
+Y.log(myObject.get("attrA")); // should log 6
+```
+<p>Several attributes can be set or read at once via the `setAttrs` and `getAttrs`
+methods.</p>
+```
+myObject.setAttrs({
+ age: 6,
+ name: "John"
+});
+
+Y.log(Y.Lang.sub("{name} is {age} years old", myObject.getAttrs()));
+```
+<p>Calling `getAttrs` without any arguments will return all the configured attributes.
+Passing an array of attribute names will return only those. Passing `true`
+will return only those modified from its initially configured value.</p>
+
+<p>A protected `_set` method allows changing the value of attributes configured as `readOnly`
+or past the first write in those configured as `writeOnce`, to allow the
+object to still enforce those rules in the public API while allowing the
+object to change the values internally.</p>
+
+<p>An extra argument can be provided to `set` and `setAttrs` indicating the
+reason or origin of the change. This argument must be an object and it will
+be passed to the `setter` and/or `validator` methods, if any, and it will
+be merged into the event facade of the attribute change events.</p>
+
+```
+myObject.set("attrA", inputNode.get("value"), {src:"UI"});
+
+myObject.setAttrs({
+ attrA: null,
+ attrB: ""
+},{src:"internal"});
+```
+
+<p>This may allow an object to set an attribute to a value otherwise forbidden
+in the public API, to have the `setter` manipulate it in a special way or
+an attribute change event to respond in a particular manner. For example, as shown
+in the sample code above,
+a `setter` may accept and parse a numeric string when the the source of the
+change is the UI while it would reject it otherwise.</p>
+
<h2 id="events">Attribute Change Events</h2>
-<p>The availability of attribute change events are one of the key benefits of using
-attributes to store state for your objects, instead of regular object properties.
-Attribute change events are fired whenever `set` is invoked for an
-attribute, allowing you to execute code in response to a change in the attribute's
+<p>The availability of attribute change events are one of the key benefits of using
+attributes to store state for your objects, instead of regular object properties.
+Attribute change events are fired whenever `set` is invoked for an
+attribute, allowing you to execute code in response to a change in the attribute's
value.</p>
<h4>Listening for Change Events</h4>
@@ -291,7 +352,7 @@ value.</p>
<p>Attribute change events are Custom Events, having the type: "[attributeName]Change", where
[attributeName] is the name of the attribute which you're monitoring for changes.</p>
-<p>For example, if you were interested in listening for changes to an attribute named
+<p>For example, if you were interested in listening for changes to an attribute named
"enabled", you would subscribe to events of type "enabledChange".</p>
```
@@ -301,26 +362,45 @@ o.on("enabledChange", function(event) {
```
-<p><em>NOTE:</em> Context and additional arguments for the listener function can either be
-defined using YUI's `bind` method, or by passing in the context and
+<p><em>NOTE:</em> Context and additional arguments for the listener function can either be
+defined using YUI's `bind` method, or by passing in the context and
additional arguments to the `on` method.</p>
-<p>Attribute change event listeners can be registered using either the `on`
+<p>Attribute change event listeners can be registered using either the `on`
(as shown above) or `after` Attribute methods.</p>
-
+
+<p>Attribute change event listeners may respond differently according to the
+source or reason of the change as specified in the third argument to `set`.
+This argument will be merged into the event facade and can be checked by the
+event listener.</p>
+```
+myObject.after("nameChange", function (event) {
+ if (event.src !== "UI") {
+ inputNode.set("value", event.newVal);
+ }
+});
+```
+<p>The code above listens to changes in the `name` attribute and, if it comes
+from anywhere but the UI, it sets the input box to the new value.</p>
+
<h4>On vs. After</h4>
<h5>On</h5>
-<p>Listeners registered using the `on` method, are notified <strong>before</strong> the stored state of the attribute has been updated.
+<p>Listeners registered using the `on` method, are notified <strong>before</strong> the stored state of the attribute has been updated.
Functions registered as "on" listeners receive an `Event` object as the first argument (actually an
-instance of <a href="{{apiDocs}}/EventFacade.html">`EventFacade`</a>) which contains information
+instance of <a href="{{apiDocs}}/EventFacade.html">`EventFacade`</a>) which contains information
about the attribute being modified.</p>
<p>Since these listeners are invoked before any state change has occurred, they have the ability to
-prevent the change in state from occurring, by invoking `event.preventDefault()` on
+prevent the change in state from occurring, by invoking `event.preventDefault()` on
the event object passed to them, or to modify the value being set, by modifying the `event.newVal` property.</p>
+<p>The value passed to the "on" event listener has not yet been checked via the `validator` or
+normalized by the `setter` method. Since the change may later be rejected or prevented
+by further event listeners attached later, an "on" event listener should not
+produce any secondary effects.</p>
+
```
o.on("enabledChange", function(event) {
@@ -338,12 +418,15 @@ o.on("enabledChange", function(event) {
<h5>After</h5>
-<p>Listeners registered using the `after` method, are notified <strong>after</strong>
-the stored state of the attribute has been updated. As with "on" listeners, the subscribed function
+<p>Listeners registered using the `after` method, are notified <strong>after</strong>
+the stored state of the attribute has been updated. As with "on" listeners, the subscribed function
receives an `Event` object as the first parameter.</p>
-<p>Based on the definition above, "after" listeners are not invoked if state change is prevented,
-for example, due to one of the "on" listeners calling `preventDefault` on the event object.</p>
+<p>Based on the definition above, "after" listeners are not invoked if state change is prevented,
+for example, due to one of the "on" listeners calling `preventDefault` on the event object.
+They are not invoked either if the `validator` or `setter` methods
+rejected the value and they will receive the value already modified by the `setter` thus
+it is safe to produce any secondary effects based on the changed value.</p>
```
o.after("enabledChange", function(event) {
@@ -372,7 +455,7 @@ as well methods used to manage event propagation. These are described below:</p>
<dt>attrName</dt>
<dd>The name of the attribute which is being set</dd>
<dt>subAttrName</dt>
- <dd><p>Attribute also allows you to set individual properties of attributes having values which are objects through the
+ <dd><p>Attribute also allows you to set individual properties of attributes having values which are objects through the
`set` method (e.g. `o.set("X.a.b", 5)`, discussed below). This event property will contain the complete dot notation path for the object property which was changed.</p>
<p>For example, during `o.set("X.a.b", 5);`, `event.subAttrName` will be `"X.a.b"`, the path of the property which was modified, and `event.attrName` will be `"X"`, the attribute name.</p></dd>
<dt>preventDefault()<dt>
@@ -380,10 +463,12 @@ as well methods used to manage event propagation. These are described below:</p>
<dt>stopImmediatePropagation()</dt>
<dd>This method can be called in "on" or "after" listener functions, and will prevent the rest of the listener stack from
being notified, but will not prevent the attribute's value from being updated (viz. will not prevent the default behavior).</dd>
+ <dt>-- Custom properties --</dt>
+ <dd>Any other properties in the object passed as the last argument in a `set` or `setAttrs` call.</dd>
</dl>
<h2 id="attrsetflow">Attribute Set Flow Diagram</h2>
-
+
<p>The diagram below shows the order in which attribute setters, validators and change event subscribers are invoked during the set operation:</p>
<p><a href="setflow.html" title="Click too see full-size image"><img src="{{componentAssets}}/img/attribute-set-flow.png" alt="Flow diagram for the attribute 'set' operation" height="466" width="538"></a></p>
@@ -427,9 +512,9 @@ o.set("strings.messages.intro", "Welcome");
```
-<p>Setting sub attribute values, will fire an attribute change event for the
+<p>Setting sub attribute values, will fire an attribute change event for the
main attribute (`"stringsChange"` in the above example), however the event object passed
-to the listeners with have a "subAttrName" property set to reflect the full path to the
+to the listeners with have a "subAttrName" property set to reflect the full path to the
attribute set (e.g. `event.subAttrName` will be `"strings.ui.accept_label"` for the set call on line 2 in the code snippet above).</p>
<p>You can also retrieve sub attribute values using the same dot notation syntax</p>
@@ -440,13 +525,13 @@ var lbl = o.get("strings.ui.accept_label");
```
-<h3 id="subattrs-gsv">Getters, Setters, Validators and Sub Attributes</h3>
+<h3 id="subattrs-gsv">Getters, Setters, Validators and Sub Attributes</h3>
-<p>Getter, setter and validator attribute configuration functions are only defined for the top level
-attribute (`"strings"` in this case) and will be invoked when getting/setting sub attribute values.
-What this means is that getters and setters should always return the massaged value for the top level
-attribute (e.g. `"strings"`), and not the sub attribute value being set (e.g. `"strings.ui.accept_label"`).
-The sub attribute being set is passed in as the second argument to the getter/setter/validator, so that it
+<p>Getter, setter and validator attribute configuration functions are only defined for the top level
+attribute (`"strings"` in this case) and will be invoked when getting/setting sub attribute values.
+What this means is that getters and setters should always return the massaged value for the top level
+attribute (e.g. `"strings"`), and not the sub attribute value being set (e.g. `"strings.ui.accept_label"`).
+The sub attribute being set is passed in as the second argument to the getter/setter/validator, so that it
can fork for sub attribute handling if required.</p>
<p>For example:</p>
@@ -462,7 +547,7 @@ this.addAttr("strings", {
var path = fullName.split(".");
if (path.length > 1) {
-
+
// Someone's asking for a sub-attribute value
// Maybe we want to do some special normalization just for this use case.
View
8 src/attribute/js/Attribute.js
@@ -41,8 +41,10 @@
* of attributes for derived classes, accounting for values passed into the constructor.</p>
*
* @class Attribute
- * @param attrs {Object} The attributes to add during construction (passed through to <a href="#method_addAttrs">addAttrs</a>). These can also be defined on the constructor being augmented with Attribute by defining the ATTRS property on the constructor.
- * @param values {Object} The initial attribute values to apply (passed through to <a href="#method_addAttrs">addAttrs</a>). These are not merged/cloned. The caller is responsible for isolating user provided values if required.
+ * @param attrs {Object} The attributes to add during construction (passed through to <a href="#method_addAttrs">addAttrs</a>).
+ * These can also be defined on the constructor being augmented with Attribute by defining the ATTRS property on the constructor.
+ * @param values {Object} The initial attribute values to apply (passed through to <a href="#method_addAttrs">addAttrs</a>).
+ * These are not merged/cloned. The caller is responsible for isolating user provided values if required.
* @param lazy {boolean} Whether or not to add attributes lazily (passed through to <a href="#method_addAttrs">addAttrs</a>).
* @uses AttributeCore
* @uses AttributeObservable
@@ -58,7 +60,7 @@
Y.mix(Attribute, Y.AttributeCore, false, null, 1);
Y.mix(Attribute, Y.AttributeExtras, false, null, 1);
- // Needs to be "true", to overwrite methods from AttributeCore
+ // Needs to be `true`, to overwrite methods from AttributeCore
Y.mix(Attribute, Y.AttributeObservable, true, null, 1);
/**
View
81 src/attribute/js/AttributeCore.js
@@ -67,8 +67,10 @@
* additional, less commonly used attribute methods, such as `modifyAttr`, `removeAttr` and `reset`.</p>
*
* @class AttributeCore
- * @param attrs {Object} The attributes to add during construction (passed through to <a href="#method_addAttrs">addAttrs</a>). These can also be defined on the constructor being augmented with Attribute by defining the ATTRS property on the constructor.
- * @param values {Object} The initial attribute values to apply (passed through to <a href="#method_addAttrs">addAttrs</a>). These are not merged/cloned. The caller is responsible for isolating user provided values if required.
+ * @param attrs {Object} The attributes to add during construction (passed through to <a href="#method_addAttrs">addAttrs</a>).
+ * These can also be defined on the constructor being augmented with Attribute by defining the ATTRS property on the constructor.
+ * @param values {Object} The initial attribute values to apply (passed through to <a href="#method_addAttrs">addAttrs</a>).
+ * These are not merged/cloned. The caller is responsible for isolating user provided values if required.
* @param lazy {boolean} Whether or not to add attributes lazily (passed through to <a href="#method_addAttrs">addAttrs</a>).
*/
function AttributeCore(attrs, values, lazy) {
@@ -139,8 +141,10 @@
* constructor.
*
* @method _initAttrHost
- * @param attrs {Object} The attributes to add during construction (passed through to <a href="#method_addAttrs">addAttrs</a>). These can also be defined on the constructor being augmented with Attribute by defining the ATTRS property on the constructor.
- * @param values {Object} The initial attribute values to apply (passed through to <a href="#method_addAttrs">addAttrs</a>). These are not merged/cloned. The caller is responsible for isolating user provided values if required.
+ * @param attrs {Object} The attributes to add during construction (passed through to <a href="#method_addAttrs">addAttrs</a>).
+ * These can also be defined on the constructor being augmented with Attribute by defining the ATTRS property on the constructor.
+ * @param values {Object} The initial attribute values to apply (passed through to <a href="#method_addAttrs">addAttrs</a>).
+ * These are not merged/cloned. The caller is responsible for isolating user provided values if required.
* @param lazy {boolean} Whether or not to add attributes lazily (passed through to <a href="#method_addAttrs">addAttrs</a>).
* @private
*/
@@ -181,7 +185,8 @@
* 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.
- * <p>The writeOnce attribute can also be set to the string "initOnly", in which case the attribute can only be set during initialization
+ * <p>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)</p>
* </dd>
*
@@ -265,7 +270,7 @@
added : true
});
} else {
-
+ /*jshint maxlen:200*/
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)) {
@@ -273,6 +278,7 @@
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');}
+ /*jshint maxlen:150*/
if (hasValue) {
// We'll go through set, don't want to set value in config directly
@@ -302,7 +308,8 @@
*
* @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.
+ * @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);
@@ -344,7 +351,7 @@
* @private
* @param {Object} name The name of the attribute
*/
- _addLazyAttr: function(name, cfg) {
+ _addLazyAttr: function(name) {
var state = this._state,
lazyCfg = state.get(name, LAZY);
@@ -362,13 +369,12 @@
* @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. <code>set("x.y.z", 5)</code>).
- *
* @param {Any} value The value to set the attribute to.
- *
+ * @param {Object} [opts] Optional data providing the circumstances for the change.
* @return {Object} A reference to the host object.
*/
- set : function(name, val) {
- return this._setAttr(name, val);
+ set : function(name, val, opts) {
+ return this._setAttr(name, val, opts);
},
/**
@@ -380,10 +386,11 @@
*
* @param {String} name The name of the attribute.
* @param {Any} val The value to set the attribute to.
+ * @param {Object} [opts] Optional data providing the circumstances for the change.
* @return {Object} A reference to the host object.
*/
- _set : function(name, val) {
- return this._setAttr(name, val, null, true);
+ _set : function(name, val, opts) {
+ return this._setAttr(name, val, opts, true);
},
/**
@@ -397,22 +404,13 @@
*
* @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.
- * This is currently a hack. There's no real need for the AttributeCore implementation
- * to support this parameter, but breaking it out into AttributeObservable, results in
- * additional function hops for the critical path.
+ * @param {Object} [opts] Optional data providing the circumstances for the change.
* @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) {
-
- // HACK - no real reason core needs to know about opts, but
- // it adds fn hops if we want to break it out.
- // Not sure it's worth it for this critical path
-
var allowSet = true,
state = this._state,
stateProxy = this._stateProxy,
@@ -480,8 +478,9 @@
}
if (allowSet) {
+ opts = opts || {};
if (!this._fireAttrChange || initializing) {
- this._setAttrVal(name, strPath, currVal, val);
+ this._setAttrVal(name, strPath, currVal, val, opts);
} else {
// HACK - no real reason core needs to know about _fireAttrChange, but
// it adds fn hops if we want to break it out. Not sure it's worth it for this critical path
@@ -589,10 +588,11 @@
* @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.
+ * @param {Object} [opts] Optional data providing the circumstances for the change.
*
* @return {booolean} true if the new attribute value was stored, false if not.
*/
- _setAttrVal : function(attrName, subAttrName, prevVal, newVal) {
+ _setAttrVal : function(attrName, subAttrName, prevVal, newVal, opts) {
var host = this,
allowSet = true,
@@ -611,7 +611,7 @@
validator = this[validator];
}
if (validator) {
- valid = validator.call(host, newVal, name);
+ valid = validator.call(host, newVal, name, opts);
if (!valid && initializing) {
newVal = cfg.defaultValue;
@@ -627,7 +627,7 @@
setter = this[setter];
}
if (setter) {
- retVal = setter.call(host, newVal, name);
+ retVal = setter.call(host, newVal, name, opts);
if (retVal === INVALID_VALUE) {
Y.log('Attribute: ' + attrName + ', setter returned Attribute.INVALID_VALUE for value:' + newVal, 'warn', 'attribute');
@@ -665,11 +665,12 @@
*
* @method setAttrs
* @param {Object} attrs An object with attributes name/value pairs.
+ * @param {Object} [opts] Optional data providing the circumstances for the change.
* @return {Object} A reference to the host object.
* @chainable
*/
- setAttrs : function(attrs) {
- return this._setAttrs(attrs);
+ setAttrs : function(attrs, opts) {
+ return this._setAttrs(attrs, opts);
},
/**
@@ -678,14 +679,15 @@
* @method _setAttrs
* @protected
* @param {Object} attrs An object with attributes name/value pairs.
+ * @param {Object} [opts] Optional data providing the circumstances for the change
* @return {Object} A reference to the host object.
* @chainable
*/
- _setAttrs : function(attrs) {
+ _setAttrs : function(attrs, opts) {
var attr;
for (attr in attrs) {
if ( attrs.hasOwnProperty(attr) ) {
- this.set(attr, attrs[attr]);
+ this.set(attr, attrs[attr], opts);
}
}
return this;
@@ -827,9 +829,8 @@
_protectAttrs : AttributeCore.protectAttrs,
/**
- * 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.
+ * 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
@@ -885,7 +886,6 @@
* @private
*/
_getAttrInitVal : function(attr, cfg, initValues) {
-
var val = cfg.value,
valFn = cfg.valueFn,
tmpVal,
@@ -936,12 +936,15 @@
},
/**
- * Utility method to set up initial attributes defined during construction, either through the constructor.ATTRS property, or explicitly passed in.
+ * Utility method to set up initial attributes defined during construction,
+ * either through the constructor.ATTRS property, or explicitly passed in.
*
* @method _initAttrs
* @protected
- * @param attrs {Object} The attributes to add during construction (passed through to <a href="#method_addAttrs">addAttrs</a>). These can also be defined on the constructor being augmented with Attribute by defining the ATTRS property on the constructor.
- * @param values {Object} The initial attribute values to apply (passed through to <a href="#method_addAttrs">addAttrs</a>). These are not merged/cloned. The caller is responsible for isolating user provided values if required.
+ * @param attrs {Object} The attributes to add during construction (passed through to <a href="#method_addAttrs">addAttrs</a>).
+ * These can also be defined on the constructor being augmented with Attribute by defining the ATTRS property on the constructor.
+ * @param values {Object} The initial attribute values to apply (passed through to <a href="#method_addAttrs">addAttrs</a>).
+ * These are not merged/cloned. The caller is responsible for isolating user provided values if required.
* @param lazy {boolean} Whether or not to add attributes lazily (passed through to <a href="#method_addAttrs">addAttrs</a>).
*/
_initAttrs : function(attrs, values, lazy) {
View
3  src/attribute/js/AttributeExtras.js
@@ -71,8 +71,9 @@
}
}
}
-
+ /*jshint maxlen:200*/
if (!host.attrAdded(name)) {Y.log('Attribute modifyAttr:' + name + ' has not been added. Use addAttr to add the attribute', 'warn', 'attribute');}
+ /*jshint maxlen:150 */
},
/**
View
4 src/attribute/js/AttributeObservable.js
@@ -176,8 +176,10 @@
* @param {EventFacade} e The event object for attribute change events.
*/
_defAttrChangeFn : function(e) {
- if (!this._setAttrVal(e.attrName, e.subAttrName, e.prevVal, e.newVal)) {
+ if (!this._setAttrVal(e.attrName, e.subAttrName, e.prevVal, e.newVal, e.opts)) {
+ /*jshint maxlen:200*/
Y.log('State not updated and stopImmediatePropagation called for attribute: ' + e.attrName + ' , value:' + e.newVal, 'warn', 'attribute');
+ /*jshint maxlen:150*/
// Prevent "after" listeners from being invoked since nothing changed.
e.stopImmediatePropagation();
} else {
View
35 src/attribute/tests/unit/assets/attribute-core-tests.js
@@ -235,6 +235,41 @@ YUI.add('attribute-core-tests', function(Y) {
Y.Assert.areEqual("TESTADHOCCONFIGURED", h.get("AdHoc"));
},
+ testSetterWithOpts : function() {
+ var h = this.createHost();
+
+
+ h.addAttr("tri", {
+ setter: function(val, name, opts) {
+ opts = opts || {};
+ if (opts.src === 'internal') {
+ if (parseInt(val,10) == val && val >= 0 && val <=2) {
+ return val;
+ } else {
+ return Y.AttributeCore.INVALID_VALUE;
+ }
+ } else {
+ return (val?2:0)
+ }
+ }
+ });
+
+ h.set("tri", "whatever");
+ Y.Assert.areEqual(2, h.get("tri"),"1");
+ h.set("tri", false);
+ Y.Assert.areEqual(0, h.get("tri"),"2");
+ h.set("tri", 1);
+ Y.Assert.areEqual(2, h.get("tri"),"3");
+ h.set("tri", 1, {src: 'internal'});
+ Y.Assert.areEqual(1, h.get("tri"),"4");
+ h.set("tri", "whatever", {src: 'internal'});
+ Y.Assert.areEqual(1, h.get("tri"),"5");
+ h.set("tri", false);
+ Y.Assert.areEqual(0, h.get("tri"),"6");
+
+
+
+ },
testMassSetGet : function() {
var h = this.createHost();
Please sign in to comment.
Something went wrong with that request. Please try again.