[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
1 /* 2 YUI 3.17.2 (build 9c3c78e) 3 Copyright 2014 Yahoo! Inc. All rights reserved. 4 Licensed under the BSD License. 5 http://yuilibrary.com/license/ 6 */ 7 8 YUI.add('attribute-core', function (Y, NAME) { 9 10 /** 11 * The State class maintains state for a collection of named items, with 12 * a varying number of properties defined. 13 * 14 * It avoids the need to create a separate class for the item, and separate instances 15 * of these classes for each item, by storing the state in a 2 level hash table, 16 * improving performance when the number of items is likely to be large. 17 * 18 * @constructor 19 * @class State 20 */ 21 Y.State = function() { 22 /** 23 * Hash of attributes 24 * @property data 25 */ 26 this.data = {}; 27 }; 28 29 Y.State.prototype = { 30 31 /** 32 * Adds a property to an item. 33 * 34 * @method add 35 * @param name {String} The name of the item. 36 * @param key {String} The name of the property. 37 * @param val {Any} The value of the property. 38 */ 39 add: function(name, key, val) { 40 var item = this.data[name]; 41 42 if (!item) { 43 item = this.data[name] = {}; 44 } 45 46 item[key] = val; 47 }, 48 49 /** 50 * Adds multiple properties to an item. 51 * 52 * @method addAll 53 * @param name {String} The name of the item. 54 * @param obj {Object} A hash of property/value pairs. 55 */ 56 addAll: function(name, obj) { 57 var item = this.data[name], 58 key; 59 60 if (!item) { 61 item = this.data[name] = {}; 62 } 63 64 for (key in obj) { 65 if (obj.hasOwnProperty(key)) { 66 item[key] = obj[key]; 67 } 68 } 69 }, 70 71 /** 72 * Removes a property from an item. 73 * 74 * @method remove 75 * @param name {String} The name of the item. 76 * @param key {String} The property to remove. 77 */ 78 remove: function(name, key) { 79 var item = this.data[name]; 80 81 if (item) { 82 delete item[key]; 83 } 84 }, 85 86 /** 87 * Removes multiple properties from an item, or removes the item completely. 88 * 89 * @method removeAll 90 * @param name {String} The name of the item. 91 * @param obj {Object|Array} Collection of properties to delete. If not provided, the entire item is removed. 92 */ 93 removeAll: function(name, obj) { 94 var data; 95 96 if (!obj) { 97 data = this.data; 98 99 if (name in data) { 100 delete data[name]; 101 } 102 } else { 103 Y.each(obj, function(value, key) { 104 this.remove(name, typeof key === 'string' ? key : value); 105 }, this); 106 } 107 }, 108 109 /** 110 * For a given item, returns the value of the property requested, or undefined if not found. 111 * 112 * @method get 113 * @param name {String} The name of the item 114 * @param key {String} Optional. The property value to retrieve. 115 * @return {Any} The value of the supplied property. 116 */ 117 get: function(name, key) { 118 var item = this.data[name]; 119 120 if (item) { 121 return item[key]; 122 } 123 }, 124 125 /** 126 * For the given item, returns an object with all of the 127 * item's property/value pairs. By default the object returned 128 * is a shallow copy of the stored data, but passing in true 129 * as the second parameter will return a reference to the stored 130 * data. 131 * 132 * @method getAll 133 * @param name {String} The name of the item 134 * @param reference {boolean} true, if you want a reference to the stored 135 * object 136 * @return {Object} An object with property/value pairs for the item. 137 */ 138 getAll : function(name, reference) { 139 var item = this.data[name], 140 key, obj; 141 142 if (reference) { 143 obj = item; 144 } else if (item) { 145 obj = {}; 146 147 for (key in item) { 148 if (item.hasOwnProperty(key)) { 149 obj[key] = item[key]; 150 } 151 } 152 } 153 154 return obj; 155 } 156 }; 157 /*For log lines*/ 158 /*jshint maxlen:200*/ 159 160 /** 161 * The attribute module provides an augmentable Attribute implementation, which 162 * adds configurable attributes and attribute change events to the class being 163 * augmented. It also provides a State class, which is used internally by Attribute, 164 * but can also be used independently to provide a name/property/value data structure to 165 * store state. 166 * 167 * @module attribute 168 */ 169 170 /** 171 * The attribute-core submodule provides the lightest level of attribute handling support 172 * without Attribute change events, or lesser used methods such as reset(), modifyAttrs(), 173 * and removeAttr(). 174 * 175 * @module attribute 176 * @submodule attribute-core 177 */ 178 var O = Y.Object, 179 Lang = Y.Lang, 180 181 DOT = ".", 182 183 // Externally configurable props 184 GETTER = "getter", 185 SETTER = "setter", 186 READ_ONLY = "readOnly", 187 WRITE_ONCE = "writeOnce", 188 INIT_ONLY = "initOnly", 189 VALIDATOR = "validator", 190 VALUE = "value", 191 VALUE_FN = "valueFn", 192 LAZY_ADD = "lazyAdd", 193 194 // Used for internal state management 195 ADDED = "added", 196 BYPASS_PROXY = "_bypassProxy", 197 INIT_VALUE = "initValue", 198 LAZY = "lazy", 199 200 INVALID_VALUE; 201 202 /** 203 * <p> 204 * AttributeCore provides the lightest level of configurable attribute support. It is designed to be 205 * augmented on to a host class, and provides the host with the ability to configure 206 * attributes to store and retrieve state, <strong>but without support for attribute change events</strong>. 207 * </p> 208 * <p>For example, attributes added to the host can be configured:</p> 209 * <ul> 210 * <li>As read only.</li> 211 * <li>As write once.</li> 212 * <li>With a setter function, which can be used to manipulate 213 * values passed to Attribute's <a href="#method_set">set</a> method, before they are stored.</li> 214 * <li>With a getter function, which can be used to manipulate stored values, 215 * before they are returned by Attribute's <a href="#method_get">get</a> method.</li> 216 * <li>With a validator function, to validate values before they are stored.</li> 217 * </ul> 218 * 219 * <p>See the <a href="#method_addAttr">addAttr</a> method, for the complete set of configuration 220 * options available for attributes.</p> 221 * 222 * <p>Object/Classes based on AttributeCore can augment <a href="AttributeObservable.html">AttributeObservable</a> 223 * (with true for overwrite) and <a href="AttributeExtras.html">AttributeExtras</a> to add attribute event and 224 * additional, less commonly used attribute methods, such as `modifyAttr`, `removeAttr` and `reset`.</p> 225 * 226 * @class AttributeCore 227 * @param attrs {Object} The attributes to add during construction (passed through to <a href="#method_addAttrs">addAttrs</a>). 228 * These can also be defined on the constructor being augmented with Attribute by defining the ATTRS property on the constructor. 229 * @param values {Object} The initial attribute values to apply (passed through to <a href="#method_addAttrs">addAttrs</a>). 230 * These are not merged/cloned. The caller is responsible for isolating user provided values if required. 231 * @param lazy {boolean} Whether or not to add attributes lazily (passed through to <a href="#method_addAttrs">addAttrs</a>). 232 */ 233 function AttributeCore(attrs, values, lazy) { 234 // HACK: Fix #2531929 235 // Complete hack, to make sure the first clone of a node value in IE doesn't doesn't hurt state - maintains 3.4.1 behavior. 236 // Too late in the release cycle to do anything about the core problem. 237 // The root issue is that cloning a Y.Node instance results in an object which barfs in IE, when you access it's properties (since 3.3.0). 238 this._yuievt = null; 239 240 this._initAttrHost(attrs, values, lazy); 241 } 242 243 /** 244 * <p>The value to return from an attribute setter in order to prevent the set from going through.</p> 245 * 246 * <p>You can return this value from your setter if you wish to combine validator and setter 247 * functionality into a single setter function, which either returns the massaged value to be stored or 248 * AttributeCore.INVALID_VALUE to prevent invalid values from being stored.</p> 249 * 250 * @property INVALID_VALUE 251 * @type Object 252 * @static 253 * @final 254 */ 255 AttributeCore.INVALID_VALUE = {}; 256 INVALID_VALUE = AttributeCore.INVALID_VALUE; 257 258 /** 259 * The list of properties which can be configured for 260 * each attribute (e.g. setter, getter, writeOnce etc.). 261 * 262 * This property is used internally as a whitelist for faster 263 * Y.mix operations. 264 * 265 * @property _ATTR_CFG 266 * @type Array 267 * @static 268 * @protected 269 */ 270 AttributeCore._ATTR_CFG = [SETTER, GETTER, VALIDATOR, VALUE, VALUE_FN, WRITE_ONCE, READ_ONLY, LAZY_ADD, BYPASS_PROXY]; 271 272 /** 273 * Utility method to protect an attribute configuration hash, by merging the 274 * entire object and the individual attr config objects. 275 * 276 * @method protectAttrs 277 * @static 278 * @param {Object} attrs A hash of attribute to configuration object pairs. 279 * @return {Object} A protected version of the `attrs` argument. 280 */ 281 AttributeCore.protectAttrs = function (attrs) { 282 if (attrs) { 283 attrs = Y.merge(attrs); 284 for (var attr in attrs) { 285 if (attrs.hasOwnProperty(attr)) { 286 attrs[attr] = Y.merge(attrs[attr]); 287 } 288 } 289 } 290 291 return attrs; 292 }; 293 294 AttributeCore.prototype = { 295 296 /** 297 * Constructor logic for attributes. Initializes the host state, and sets up the inital attributes passed to the 298 * constructor. 299 * 300 * @method _initAttrHost 301 * @param attrs {Object} The attributes to add during construction (passed through to <a href="#method_addAttrs">addAttrs</a>). 302 * These can also be defined on the constructor being augmented with Attribute by defining the ATTRS property on the constructor. 303 * @param values {Object} The initial attribute values to apply (passed through to <a href="#method_addAttrs">addAttrs</a>). 304 * These are not merged/cloned. The caller is responsible for isolating user provided values if required. 305 * @param lazy {boolean} Whether or not to add attributes lazily (passed through to <a href="#method_addAttrs">addAttrs</a>). 306 * @private 307 */ 308 _initAttrHost : function(attrs, values, lazy) { 309 this._state = new Y.State(); 310 this._initAttrs(attrs, values, lazy); 311 }, 312 313 /** 314 * <p> 315 * Adds an attribute with the provided configuration to the host object. 316 * </p> 317 * <p> 318 * The config argument object supports the following properties: 319 * </p> 320 * 321 * <dl> 322 * <dt>value <Any></dt> 323 * <dd>The initial value to set on the attribute</dd> 324 * 325 * <dt>valueFn <Function | String></dt> 326 * <dd> 327 * <p>A function, which will return the initial value to set on the attribute. This is useful 328 * for cases where the attribute configuration is defined statically, but needs to 329 * reference the host instance ("this") to obtain an initial value. If both the value and valueFn properties are defined, 330 * the value returned by the valueFn has precedence over the value property, unless it returns undefined, in which 331 * case the value property is used.</p> 332 * 333 * <p>valueFn can also be set to a string, representing the name of the instance method to be used to retrieve the value.</p> 334 * </dd> 335 * 336 * <dt>readOnly <boolean></dt> 337 * <dd>Whether or not the attribute is read only. Attributes having readOnly set to true 338 * cannot be modified by invoking the set method.</dd> 339 * 340 * <dt>writeOnce <boolean> or <string></dt> 341 * <dd> 342 * Whether or not the attribute is "write once". Attributes having writeOnce set to true, 343 * can only have their values set once, be it through the default configuration, 344 * constructor configuration arguments, or by invoking set. 345 * <p>The writeOnce attribute can also be set to the string "initOnly", 346 * in which case the attribute can only be set during initialization 347 * (when used with Base, this means it can only be set during construction)</p> 348 * </dd> 349 * 350 * <dt>setter <Function | String></dt> 351 * <dd> 352 * <p>The setter function used to massage or normalize the value passed to the set method for the attribute. 353 * The value returned by the setter will be the final stored value. Returning 354 * <a href="#property_Attribute.INVALID_VALUE">Attribute.INVALID_VALUE</a>, from the setter will prevent 355 * the value from being stored. 356 * </p> 357 * 358 * <p>setter can also be set to a string, representing the name of the instance method to be used as the setter function.</p> 359 * </dd> 360 * 361 * <dt>getter <Function | String></dt> 362 * <dd> 363 * <p> 364 * The getter function used to massage or normalize the value returned by the get method for the attribute. 365 * The value returned by the getter function is the value which will be returned to the user when they 366 * invoke get. 367 * </p> 368 * 369 * <p>getter can also be set to a string, representing the name of the instance method to be used as the getter function.</p> 370 * </dd> 371 * 372 * <dt>validator <Function | String></dt> 373 * <dd> 374 * <p> 375 * The validator function invoked prior to setting the stored value. Returning 376 * false from the validator function will prevent the value from being stored. 377 * </p> 378 * 379 * <p>validator can also be set to a string, representing the name of the instance method to be used as the validator function.</p> 380 * </dd> 381 * 382 * <dt>lazyAdd <boolean></dt> 383 * <dd>Whether or not to delay initialization of the attribute until the first call to get/set it. 384 * This flag can be used to over-ride lazy initialization on a per attribute basis, when adding multiple attributes through 385 * the <a href="#method_addAttrs">addAttrs</a> method.</dd> 386 * 387 * </dl> 388 * 389 * <p>The setter, getter and validator are invoked with the value and name passed in as the first and second arguments, and with 390 * the context ("this") set to the host object.</p> 391 * 392 * <p>Configuration properties outside of the list mentioned above are considered private properties used internally by attribute, 393 * and are not intended for public use.</p> 394 * 395 * @method addAttr 396 * 397 * @param {String} name The name of the attribute. 398 * @param {Object} config An object with attribute configuration property/value pairs, specifying the configuration for the attribute. 399 * 400 * <p> 401 * <strong>NOTE:</strong> The configuration object is modified when adding an attribute, so if you need 402 * to protect the original values, you will need to merge the object. 403 * </p> 404 * 405 * @param {boolean} lazy (optional) Whether or not to add this attribute lazily (on the first call to get/set). 406 * 407 * @return {Object} A reference to the host object. 408 * 409 * @chainable 410 */ 411 addAttr : function(name, config, lazy) { 412 413 414 var host = this, // help compression 415 state = host._state, 416 data = state.data, 417 value, 418 added, 419 hasValue; 420 421 config = config || {}; 422 423 if (LAZY_ADD in config) { 424 lazy = config[LAZY_ADD]; 425 } 426 427 added = state.get(name, ADDED); 428 429 if (lazy && !added) { 430 state.data[name] = { 431 lazy : config, 432 added : true 433 }; 434 } else { 435 436 437 if (!added || config.isLazyAdd) { 438 439 hasValue = (VALUE in config); 440 441 442 if (hasValue) { 443 444 // We'll go through set, don't want to set value in config directly 445 446 // PERF TODO: VALIDATE: See if setting this to undefined is sufficient. We use to delete before. 447 // In certain code paths/use cases, undefined may not be the same as not present. 448 // If not, we can set it to some known fixed value (like INVALID_VALUE, say INITIALIZING_VALUE) for performance, 449 // to avoid a delete which seems to help a lot. 450 451 value = config.value; 452 config.value = undefined; 453 } 454 455 config.added = true; 456 config.initializing = true; 457 458 data[name] = config; 459 460 if (hasValue) { 461 // Go through set, so that raw values get normalized/validated 462 host.set(name, value); 463 } 464 465 config.initializing = false; 466 } 467 } 468 469 return host; 470 }, 471 472 /** 473 * Checks if the given attribute has been added to the host 474 * 475 * @method attrAdded 476 * @param {String} name The name of the attribute to check. 477 * @return {boolean} true if an attribute with the given name has been added, false if it hasn't. 478 * This method will return true for lazily added attributes. 479 */ 480 attrAdded: function(name) { 481 return !!(this._state.get(name, ADDED)); 482 }, 483 484 /** 485 * Returns the current value of the attribute. If the attribute 486 * has been configured with a 'getter' function, this method will delegate 487 * to the 'getter' to obtain the value of the attribute. 488 * 489 * @method get 490 * 491 * @param {String} name The name of the attribute. If the value of the attribute is an Object, 492 * dot notation can be used to obtain the value of a property of the object (e.g. <code>get("x.y.z")</code>) 493 * 494 * @return {Any} The value of the attribute 495 */ 496 get : function(name) { 497 return this._getAttr(name); 498 }, 499 500 /** 501 * Checks whether or not the attribute is one which has been 502 * added lazily and still requires initialization. 503 * 504 * @method _isLazyAttr 505 * @private 506 * @param {String} name The name of the attribute 507 * @return {boolean} true if it's a lazily added attribute, false otherwise. 508 */ 509 _isLazyAttr: function(name) { 510 return this._state.get(name, LAZY); 511 }, 512 513 /** 514 * Finishes initializing an attribute which has been lazily added. 515 * 516 * @method _addLazyAttr 517 * @private 518 * @param {Object} name The name of the attribute 519 * @param {Object} [lazyCfg] Optional config hash for the attribute. This is added for performance 520 * along the critical path, where the calling method has already obtained lazy config from state. 521 */ 522 _addLazyAttr: function(name, lazyCfg) { 523 var state = this._state; 524 525 lazyCfg = lazyCfg || state.get(name, LAZY); 526 527 if (lazyCfg) { 528 529 // PERF TODO: For App's id override, otherwise wouldn't be 530 // needed. It expects to find it in the cfg for it's 531 // addAttr override. Would like to remove, once App override is 532 // removed. 533 state.data[name].lazy = undefined; 534 535 lazyCfg.isLazyAdd = true; 536 537 this.addAttr(name, lazyCfg); 538 } 539 }, 540 541 /** 542 * Sets the value of an attribute. 543 * 544 * @method set 545 * @chainable 546 * 547 * @param {String} name The name of the attribute. If the 548 * current value of the attribute is an Object, dot notation can be used 549 * to set the value of a property within the object (e.g. <code>set("x.y.z", 5)</code>). 550 * @param {Any} value The value to set the attribute to. 551 * @param {Object} [opts] Optional data providing the circumstances for the change. 552 * @return {Object} A reference to the host object. 553 */ 554 set : function(name, val, opts) { 555 return this._setAttr(name, val, opts); 556 }, 557 558 /** 559 * Allows setting of readOnly/writeOnce attributes. See <a href="#method_set">set</a> for argument details. 560 * 561 * @method _set 562 * @protected 563 * @chainable 564 * 565 * @param {String} name The name of the attribute. 566 * @param {Any} val The value to set the attribute to. 567 * @param {Object} [opts] Optional data providing the circumstances for the change. 568 * @return {Object} A reference to the host object. 569 */ 570 _set : function(name, val, opts) { 571 return this._setAttr(name, val, opts, true); 572 }, 573 574 /** 575 * Provides the common implementation for the public set and protected _set methods. 576 * 577 * See <a href="#method_set">set</a> for argument details. 578 * 579 * @method _setAttr 580 * @protected 581 * @chainable 582 * 583 * @param {String} name The name of the attribute. 584 * @param {Any} value The value to set the attribute to. 585 * @param {Object} [opts] Optional data providing the circumstances for the change. 586 * @param {boolean} force If true, allows the caller to set values for 587 * readOnly or writeOnce attributes which have already been set. 588 * 589 * @return {Object} A reference to the host object. 590 */ 591 _setAttr : function(name, val, opts, force) { 592 var allowSet = true, 593 state = this._state, 594 stateProxy = this._stateProxy, 595 tCfgs = this._tCfgs, 596 cfg, 597 initialSet, 598 strPath, 599 path, 600 currVal, 601 writeOnce, 602 initializing; 603 604 if (name.indexOf(DOT) !== -1) { 605 strPath = name; 606 607 path = name.split(DOT); 608 name = path.shift(); 609 } 610 611 // On Demand - Should be rare - handles out of order valueFn, setter, getter references 612 if (tCfgs && tCfgs[name]) { 613 this._addOutOfOrder(name, tCfgs[name]); 614 } 615 616 cfg = state.data[name] || {}; 617 618 if (cfg.lazy) { 619 cfg = cfg.lazy; 620 this._addLazyAttr(name, cfg); 621 } 622 623 initialSet = (cfg.value === undefined); 624 625 if (stateProxy && name in stateProxy && !cfg._bypassProxy) { 626 // TODO: Value is always set for proxy. Can we do any better? Maybe take a snapshot as the initial value for the first call to set? 627 initialSet = false; 628 } 629 630 writeOnce = cfg.writeOnce; 631 initializing = cfg.initializing; 632 633 if (!initialSet && !force) { 634 635 if (writeOnce) { 636 allowSet = false; 637 } 638 639 if (cfg.readOnly) { 640 allowSet = false; 641 } 642 } 643 644 if (!initializing && !force && writeOnce === INIT_ONLY) { 645 allowSet = false; 646 } 647 648 if (allowSet) { 649 // Don't need currVal if initialSet (might fail in custom getter if it always expects a non-undefined/non-null value) 650 if (!initialSet) { 651 currVal = this.get(name); 652 } 653 654 if (path) { 655 val = O.setValue(Y.clone(currVal), path, val); 656 657 if (val === undefined) { 658 allowSet = false; 659 } 660 } 661 662 if (allowSet) { 663 if (!this._fireAttrChange || initializing) { 664 this._setAttrVal(name, strPath, currVal, val, opts, cfg); 665 } else { 666 // HACK - no real reason core needs to know about _fireAttrChange, but 667 // it adds fn hops if we want to break it out. Not sure it's worth it for this critical path 668 this._fireAttrChange(name, strPath, currVal, val, opts, cfg); 669 } 670 } 671 } 672 673 return this; 674 }, 675 676 /** 677 * Utility method used by get/set to add attributes 678 * encountered out of order when calling addAttrs(). 679 * 680 * For example, if: 681 * 682 * this.addAttrs({ 683 * foo: { 684 * setter: function() { 685 * // make sure this bar is available when foo is added 686 * this.get("bar"); 687 * } 688 * }, 689 * bar: { 690 * value: ... 691 * } 692 * }); 693 * 694 * @method _addOutOfOrder 695 * @private 696 * @param name {String} attribute name 697 * @param cfg {Object} attribute configuration 698 */ 699 _addOutOfOrder : function(name, cfg) { 700 701 var attrs = {}; 702 attrs[name] = cfg; 703 704 delete this._tCfgs[name]; 705 706 // TODO: The original code went through addAttrs, so 707 // sticking with it for this pass. Seems like we could 708 // just jump straight to _addAttr() and get some perf 709 // improvement. 710 this._addAttrs(attrs, this._tVals); 711 }, 712 713 /** 714 * Provides the common implementation for the public get method, 715 * allowing Attribute hosts to over-ride either method. 716 * 717 * See <a href="#method_get">get</a> for argument details. 718 * 719 * @method _getAttr 720 * @protected 721 * @chainable 722 * 723 * @param {String} name The name of the attribute. 724 * @return {Any} The value of the attribute. 725 */ 726 _getAttr : function(name) { 727 var fullName = name, 728 tCfgs = this._tCfgs, 729 path, 730 getter, 731 val, 732 attrCfg; 733 734 if (name.indexOf(DOT) !== -1) { 735 path = name.split(DOT); 736 name = path.shift(); 737 } 738 739 // On Demand - Should be rare - handles out of 740 // order valueFn, setter, getter references 741 if (tCfgs && tCfgs[name]) { 742 this._addOutOfOrder(name, tCfgs[name]); 743 } 744 745 attrCfg = this._state.data[name] || {}; 746 747 // Lazy Init 748 if (attrCfg.lazy) { 749 attrCfg = attrCfg.lazy; 750 this._addLazyAttr(name, attrCfg); 751 } 752 753 val = this._getStateVal(name, attrCfg); 754 755 getter = attrCfg.getter; 756 757 if (getter && !getter.call) { 758 getter = this[getter]; 759 } 760 761 val = (getter) ? getter.call(this, val, fullName) : val; 762 val = (path) ? O.getValue(val, path) : val; 763 764 return val; 765 }, 766 767 /** 768 * Gets the stored value for the attribute, from either the 769 * internal state object, or the state proxy if it exits 770 * 771 * @method _getStateVal 772 * @private 773 * @param {String} name The name of the attribute 774 * @param {Object} [cfg] Optional config hash for the attribute. This is added for performance along the critical path, 775 * where the calling method has already obtained the config from state. 776 * 777 * @return {Any} The stored value of the attribute 778 */ 779 _getStateVal : function(name, cfg) { 780 var stateProxy = this._stateProxy; 781 782 if (!cfg) { 783 cfg = this._state.getAll(name) || {}; 784 } 785 786 return (stateProxy && (name in stateProxy) && !(cfg._bypassProxy)) ? stateProxy[name] : cfg.value; 787 }, 788 789 /** 790 * Sets the stored value for the attribute, in either the 791 * internal state object, or the state proxy if it exits 792 * 793 * @method _setStateVal 794 * @private 795 * @param {String} name The name of the attribute 796 * @param {Any} value The value of the attribute 797 */ 798 _setStateVal : function(name, value) { 799 var stateProxy = this._stateProxy; 800 if (stateProxy && (name in stateProxy) && !this._state.get(name, BYPASS_PROXY)) { 801 stateProxy[name] = value; 802 } else { 803 this._state.add(name, VALUE, value); 804 } 805 }, 806 807 /** 808 * Updates the stored value of the attribute in the privately held State object, 809 * if validation and setter passes. 810 * 811 * @method _setAttrVal 812 * @private 813 * @param {String} attrName The attribute name. 814 * @param {String} subAttrName The sub-attribute name, if setting a sub-attribute property ("x.y.z"). 815 * @param {Any} prevVal The currently stored value of the attribute. 816 * @param {Any} newVal The value which is going to be stored. 817 * @param {Object} [opts] Optional data providing the circumstances for the change. 818 * @param {Object} [attrCfg] Optional config hash for the attribute. This is added for performance along the critical path, 819 * where the calling method has already obtained the config from state. 820 * 821 * @return {Boolean} true if the new attribute value was stored, false if not. 822 */ 823 _setAttrVal : function(attrName, subAttrName, prevVal, newVal, opts, attrCfg) { 824 825 var host = this, 826 allowSet = true, 827 cfg = attrCfg || this._state.data[attrName] || {}, 828 validator = cfg.validator, 829 setter = cfg.setter, 830 initializing = cfg.initializing, 831 prevRawVal = this._getStateVal(attrName, cfg), 832 name = subAttrName || attrName, 833 retVal, 834 valid; 835 836 if (validator) { 837 if (!validator.call) { 838 // Assume string - trying to keep critical path tight, so avoiding Lang check 839 validator = this[validator]; 840 } 841 if (validator) { 842 valid = validator.call(host, newVal, name, opts); 843 844 if (!valid && initializing) { 845 newVal = cfg.defaultValue; 846 valid = true; // Assume it's valid, for perf. 847 } 848 } 849 } 850 851 if (!validator || valid) { 852 if (setter) { 853 if (!setter.call) { 854 // Assume string - trying to keep critical path tight, so avoiding Lang check 855 setter = this[setter]; 856 } 857 if (setter) { 858 retVal = setter.call(host, newVal, name, opts); 859 860 if (retVal === INVALID_VALUE) { 861 if (initializing) { 862 newVal = cfg.defaultValue; 863 } else { 864 allowSet = false; 865 } 866 } else if (retVal !== undefined){ 867 newVal = retVal; 868 } 869 } 870 } 871 872 if (allowSet) { 873 if(!subAttrName && (newVal === prevRawVal) && !Lang.isObject(newVal)) { 874 allowSet = false; 875 } else { 876 // Store value 877 if (!(INIT_VALUE in cfg)) { 878 cfg.initValue = newVal; 879 } 880 host._setStateVal(attrName, newVal); 881 } 882 } 883 884 } else { 885 allowSet = false; 886 } 887 888 return allowSet; 889 }, 890 891 /** 892 * Sets multiple attribute values. 893 * 894 * @method setAttrs 895 * @param {Object} attrs An object with attributes name/value pairs. 896 * @param {Object} [opts] Optional data providing the circumstances for the change. 897 * @return {Object} A reference to the host object. 898 * @chainable 899 */ 900 setAttrs : function(attrs, opts) { 901 return this._setAttrs(attrs, opts); 902 }, 903 904 /** 905 * Implementation behind the public setAttrs method, to set multiple attribute values. 906 * 907 * @method _setAttrs 908 * @protected 909 * @param {Object} attrs An object with attributes name/value pairs. 910 * @param {Object} [opts] Optional data providing the circumstances for the change 911 * @return {Object} A reference to the host object. 912 * @chainable 913 */ 914 _setAttrs : function(attrs, opts) { 915 var attr; 916 for (attr in attrs) { 917 if ( attrs.hasOwnProperty(attr) ) { 918 this.set(attr, attrs[attr], opts); 919 } 920 } 921 return this; 922 }, 923 924 /** 925 * Gets multiple attribute values. 926 * 927 * @method getAttrs 928 * @param {String[]|Boolean} attrs Optional. An array of attribute names. If omitted, all attribute values are 929 * returned. If set to true, all attributes modified from their initial values are returned. 930 * @return {Object} An object with attribute name/value pairs. 931 */ 932 getAttrs : function(attrs) { 933 return this._getAttrs(attrs); 934 }, 935 936 /** 937 * Implementation behind the public getAttrs method, to get multiple attribute values. 938 * 939 * @method _getAttrs 940 * @protected 941 * @param {String[]|Boolean} attrs Optional. An array of attribute names. If omitted, all attribute values are 942 * returned. If set to true, all attributes modified from their initial values are returned. 943 * @return {Object} An object with attribute name/value pairs. 944 */ 945 _getAttrs : function(attrs) { 946 var obj = {}, 947 attr, i, len, 948 modifiedOnly = (attrs === true); 949 950 // TODO - figure out how to get all "added" 951 if (!attrs || modifiedOnly) { 952 attrs = O.keys(this._state.data); 953 } 954 955 for (i = 0, len = attrs.length; i < len; i++) { 956 attr = attrs[i]; 957 958 if (!modifiedOnly || this._getStateVal(attr) != this._state.get(attr, INIT_VALUE)) { 959 // Go through get, to honor cloning/normalization 960 obj[attr] = this.get(attr); 961 } 962 } 963 964 return obj; 965 }, 966 967 /** 968 * Configures a group of attributes, and sets initial values. 969 * 970 * <p> 971 * <strong>NOTE:</strong> This method does not isolate the configuration object by merging/cloning. 972 * The caller is responsible for merging/cloning the configuration object if required. 973 * </p> 974 * 975 * @method addAttrs 976 * @chainable 977 * 978 * @param {Object} cfgs An object with attribute name/configuration pairs. 979 * @param {Object} values An object with attribute name/value pairs, defining the initial values to apply. 980 * Values defined in the cfgs argument will be over-written by values in this argument unless defined as read only. 981 * @param {boolean} lazy Whether or not to delay the intialization of these attributes until the first call to get/set. 982 * Individual attributes can over-ride this behavior by defining a lazyAdd configuration property in their configuration. 983 * See <a href="#method_addAttr">addAttr</a>. 984 * 985 * @return {Object} A reference to the host object. 986 */ 987 addAttrs : function(cfgs, values, lazy) { 988 if (cfgs) { 989 this._tCfgs = cfgs; 990 this._tVals = (values) ? this._normAttrVals(values) : null; 991 this._addAttrs(cfgs, this._tVals, lazy); 992 this._tCfgs = this._tVals = null; 993 } 994 995 return this; 996 }, 997 998 /** 999 * Implementation behind the public addAttrs method. 1000 * 1001 * This method is invoked directly by get if it encounters a scenario 1002 * in which an attribute's valueFn attempts to obtain the 1003 * value an attribute in the same group of attributes, which has not yet 1004 * been added (on demand initialization). 1005 * 1006 * @method _addAttrs 1007 * @private 1008 * @param {Object} cfgs An object with attribute name/configuration pairs. 1009 * @param {Object} values An object with attribute name/value pairs, defining the initial values to apply. 1010 * Values defined in the cfgs argument will be over-written by values in this argument unless defined as read only. 1011 * @param {boolean} lazy Whether or not to delay the intialization of these attributes until the first call to get/set. 1012 * Individual attributes can over-ride this behavior by defining a lazyAdd configuration property in their configuration. 1013 * See <a href="#method_addAttr">addAttr</a>. 1014 */ 1015 _addAttrs : function(cfgs, values, lazy) { 1016 var tCfgs = this._tCfgs, 1017 tVals = this._tVals, 1018 attr, 1019 attrCfg, 1020 value; 1021 1022 for (attr in cfgs) { 1023 if (cfgs.hasOwnProperty(attr)) { 1024 1025 // Not Merging. Caller is responsible for isolating configs 1026 attrCfg = cfgs[attr]; 1027 attrCfg.defaultValue = attrCfg.value; 1028 1029 // Handle simple, complex and user values, accounting for read-only 1030 value = this._getAttrInitVal(attr, attrCfg, tVals); 1031 1032 if (value !== undefined) { 1033 attrCfg.value = value; 1034 } 1035 1036 if (tCfgs[attr]) { 1037 tCfgs[attr] = undefined; 1038 } 1039 1040 this.addAttr(attr, attrCfg, lazy); 1041 } 1042 } 1043 }, 1044 1045 /** 1046 * Utility method to protect an attribute configuration 1047 * hash, by merging the entire object and the individual 1048 * attr config objects. 1049 * 1050 * @method _protectAttrs 1051 * @protected 1052 * @param {Object} attrs A hash of attribute to configuration object pairs. 1053 * @return {Object} A protected version of the attrs argument. 1054 * @deprecated Use `AttributeCore.protectAttrs()` or 1055 * `Attribute.protectAttrs()` which are the same static utility method. 1056 */ 1057 _protectAttrs : AttributeCore.protectAttrs, 1058 1059 /** 1060 * Utility method to normalize attribute values. The base implementation 1061 * simply merges the hash to protect the original. 1062 * 1063 * @method _normAttrVals 1064 * @param {Object} valueHash An object with attribute name/value pairs 1065 * 1066 * @return {Object} An object literal with 2 properties - "simple" and "complex", 1067 * containing simple and complex attribute values respectively keyed 1068 * by the top level attribute name, or null, if valueHash is falsey. 1069 * 1070 * @private 1071 */ 1072 _normAttrVals : function(valueHash) { 1073 var vals, 1074 subvals, 1075 path, 1076 attr, 1077 v, k; 1078 1079 if (!valueHash) { 1080 return null; 1081 } 1082 1083 vals = {}; 1084 1085 for (k in valueHash) { 1086 if (valueHash.hasOwnProperty(k)) { 1087 if (k.indexOf(DOT) !== -1) { 1088 path = k.split(DOT); 1089 attr = path.shift(); 1090 1091 subvals = subvals || {}; 1092 1093 v = subvals[attr] = subvals[attr] || []; 1094 v[v.length] = { 1095 path : path, 1096 value: valueHash[k] 1097 }; 1098 } else { 1099 vals[k] = valueHash[k]; 1100 } 1101 } 1102 } 1103 1104 return { simple:vals, complex:subvals }; 1105 }, 1106 1107 /** 1108 * Returns the initial value of the given attribute from 1109 * either the default configuration provided, or the 1110 * over-ridden value if it exists in the set of initValues 1111 * provided and the attribute is not read-only. 1112 * 1113 * @param {String} attr The name of the attribute 1114 * @param {Object} cfg The attribute configuration object 1115 * @param {Object} initValues The object with simple and complex attribute name/value pairs returned from _normAttrVals 1116 * 1117 * @return {Any} The initial value of the attribute. 1118 * 1119 * @method _getAttrInitVal 1120 * @private 1121 */ 1122 _getAttrInitVal : function(attr, cfg, initValues) { 1123 var val = cfg.value, 1124 valFn = cfg.valueFn, 1125 tmpVal, 1126 initValSet = false, 1127 readOnly = cfg.readOnly, 1128 simple, 1129 complex, 1130 i, 1131 l, 1132 path, 1133 subval, 1134 subvals; 1135 1136 if (!readOnly && initValues) { 1137 // Simple Attributes 1138 simple = initValues.simple; 1139 if (simple && simple.hasOwnProperty(attr)) { 1140 val = simple[attr]; 1141 initValSet = true; 1142 } 1143 } 1144 1145 if (valFn && !initValSet) { 1146 if (!valFn.call) { 1147 valFn = this[valFn]; 1148 } 1149 if (valFn) { 1150 tmpVal = valFn.call(this, attr); 1151 val = tmpVal; 1152 } 1153 } 1154 1155 if (!readOnly && initValues) { 1156 1157 // Complex Attributes (complex values applied, after simple, in case both are set) 1158 complex = initValues.complex; 1159 1160 if (complex && complex.hasOwnProperty(attr) && (val !== undefined) && (val !== null)) { 1161 subvals = complex[attr]; 1162 for (i = 0, l = subvals.length; i < l; ++i) { 1163 path = subvals[i].path; 1164 subval = subvals[i].value; 1165 O.setValue(val, path, subval); 1166 } 1167 } 1168 } 1169 1170 return val; 1171 }, 1172 1173 /** 1174 * Utility method to set up initial attributes defined during construction, 1175 * either through the constructor.ATTRS property, or explicitly passed in. 1176 * 1177 * @method _initAttrs 1178 * @protected 1179 * @param attrs {Object} The attributes to add during construction (passed through to <a href="#method_addAttrs">addAttrs</a>). 1180 * These can also be defined on the constructor being augmented with Attribute by defining the ATTRS property on the constructor. 1181 * @param values {Object} The initial attribute values to apply (passed through to <a href="#method_addAttrs">addAttrs</a>). 1182 * These are not merged/cloned. The caller is responsible for isolating user provided values if required. 1183 * @param lazy {boolean} Whether or not to add attributes lazily (passed through to <a href="#method_addAttrs">addAttrs</a>). 1184 */ 1185 _initAttrs : function(attrs, values, lazy) { 1186 // ATTRS support for Node, which is not Base based 1187 attrs = attrs || this.constructor.ATTRS; 1188 1189 var Base = Y.Base, 1190 BaseCore = Y.BaseCore, 1191 baseInst = (Base && Y.instanceOf(this, Base)), 1192 baseCoreInst = (!baseInst && BaseCore && Y.instanceOf(this, BaseCore)); 1193 1194 if (attrs && !baseInst && !baseCoreInst) { 1195 this.addAttrs(Y.AttributeCore.protectAttrs(attrs), values, lazy); 1196 } 1197 } 1198 }; 1199 1200 Y.AttributeCore = AttributeCore; 1201 1202 1203 }, '3.17.2', {"requires": ["oop"]});
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Aug 11 10:00:09 2016 | Cross-referenced by PHPXref 0.7.1 |