API Docs for: 3.10.3
Show:

File: attribute/js/AttributeObservable.js

  1. /*For log lines*/
  2. /*jshint maxlen:200*/
  3.  
  4.  
  5. /**
  6. * The attribute module provides an augmentable Attribute implementation, which
  7. * adds configurable attributes and attribute change events to the class being
  8. * augmented. It also provides a State class, which is used internally by Attribute,
  9. * but can also be used independently to provide a name/property/value data structure to
  10. * store state.
  11. *
  12. * @module attribute
  13. */
  14.  
  15. /**
  16. * The `attribute-observable` submodule provides augmentable attribute change event support
  17. * for AttributeCore based implementations.
  18. *
  19. * @module attribute
  20. * @submodule attribute-observable
  21. */
  22. var EventTarget = Y.EventTarget,
  23.  
  24. CHANGE = "Change",
  25. BROADCAST = "broadcast";
  26.  
  27. /**
  28. * Provides an augmentable implementation of attribute change events for
  29. * AttributeCore.
  30. *
  31. * @class AttributeObservable
  32. * @extensionfor AttributeCore
  33. * @uses EventTarget
  34. */
  35. function AttributeObservable() {
  36. // Perf tweak - avoid creating event literals if not required.
  37. this._ATTR_E_FACADE = {};
  38.  
  39. EventTarget.call(this, {emitFacade:true});
  40. }
  41.  
  42. AttributeObservable._ATTR_CFG = [BROADCAST];
  43.  
  44. AttributeObservable.prototype = {
  45.  
  46. /**
  47. * Sets the value of an attribute.
  48. *
  49. * @method set
  50. * @chainable
  51. *
  52. * @param {String} name The name of the attribute. If the
  53. * current value of the attribute is an Object, dot notation can be used
  54. * to set the value of a property within the object (e.g. <code>set("x.y.z", 5)</code>).
  55. *
  56. * @param {Any} value The value to set the attribute to.
  57. *
  58. * @param {Object} opts (Optional) Optional event data to be mixed into
  59. * the event facade passed to subscribers of the attribute's change event. This
  60. * can be used as a flexible way to identify the source of a call to set, allowing
  61. * the developer to distinguish between set called internally by the host, vs.
  62. * set called externally by the application developer.
  63. *
  64. * @return {Object} A reference to the host object.
  65. */
  66. set : function(name, val, opts) {
  67. return this._setAttr(name, val, opts);
  68. },
  69.  
  70. /**
  71. * Allows setting of readOnly/writeOnce attributes. See <a href="#method_set">set</a> for argument details.
  72. *
  73. * @method _set
  74. * @protected
  75. * @chainable
  76. *
  77. * @param {String} name The name of the attribute.
  78. * @param {Any} val The value to set the attribute to.
  79. * @param {Object} opts (Optional) Optional event data to be mixed into
  80. * the event facade passed to subscribers of the attribute's change event.
  81. * @return {Object} A reference to the host object.
  82. */
  83. _set : function(name, val, opts) {
  84. return this._setAttr(name, val, opts, true);
  85. },
  86.  
  87. /**
  88. * Sets multiple attribute values.
  89. *
  90. * @method setAttrs
  91. * @param {Object} attrs An object with attributes name/value pairs.
  92. * @param {Object} opts Properties to mix into the event payload. These are shared and mixed into each set
  93. * @return {Object} A reference to the host object.
  94. * @chainable
  95. */
  96. setAttrs : function(attrs, opts) {
  97. return this._setAttrs(attrs, opts);
  98. },
  99.  
  100. /**
  101. * Implementation behind the public setAttrs method, to set multiple attribute values.
  102. *
  103. * @method _setAttrs
  104. * @protected
  105. * @param {Object} attrs An object with attributes name/value pairs.
  106. * @param {Object} opts Properties to mix into the event payload. These are shared and mixed into each set
  107. * @return {Object} A reference to the host object.
  108. * @chainable
  109. */
  110. _setAttrs : function(attrs, opts) {
  111. var attr;
  112. for (attr in attrs) {
  113. if ( attrs.hasOwnProperty(attr) ) {
  114. this.set(attr, attrs[attr], opts);
  115. }
  116. }
  117. return this;
  118. },
  119.  
  120. /**
  121. * Utility method to help setup the event payload and fire the attribute change event.
  122. *
  123. * @method _fireAttrChange
  124. * @private
  125. * @param {String} attrName The name of the attribute
  126. * @param {String} subAttrName The full path of the property being changed,
  127. * if this is a sub-attribute value being change. Otherwise null.
  128. * @param {Any} currVal The current value of the attribute
  129. * @param {Any} newVal The new value of the attribute
  130. * @param {Object} opts Any additional event data to mix into the attribute change event's event facade.
  131. * @param {Object} [cfg] The attribute config stored in State, if already available.
  132. */
  133. _fireAttrChange : function(attrName, subAttrName, currVal, newVal, opts, cfg) {
  134. var host = this,
  135. eventName = this._getFullType(attrName + CHANGE),
  136. state = host._state,
  137. hasOpts = false,
  138. facade,
  139. broadcast,
  140. e;
  141.  
  142. if (!cfg) {
  143. cfg = state.data[attrName] || {};
  144. }
  145.  
  146. if (!cfg.published) {
  147.  
  148. // PERF: Using lower level _publish() for
  149. // critical path performance
  150. e = host._publish(eventName);
  151.  
  152. e.emitFacade = true;
  153. e.defaultTargetOnly = true;
  154. e.defaultFn = host._defAttrChangeFn;
  155.  
  156. broadcast = cfg.broadcast;
  157. if (broadcast !== undefined) {
  158. e.broadcast = broadcast;
  159. }
  160.  
  161. cfg.published = true;
  162. }
  163.  
  164. if (opts) {
  165. facade = Y.merge(opts);
  166. hasOpts = true;
  167. } else {
  168. facade = host._ATTR_E_FACADE;
  169. }
  170.  
  171. // Not using the single object signature for fire({type:..., newVal:...}), since
  172. // we don't want to override type. Changed to the fire(type, {newVal:...}) signature.
  173.  
  174. facade.attrName = attrName;
  175. facade.subAttrName = subAttrName;
  176. facade.prevVal = currVal;
  177. facade.newVal = newVal;
  178.  
  179. if (hasOpts) {
  180. host.fire(eventName, facade, opts);
  181. } else {
  182. host.fire(eventName, facade);
  183. }
  184. },
  185.  
  186. /**
  187. * Default function for attribute change events.
  188. *
  189. * @private
  190. * @method _defAttrChangeFn
  191. * @param {EventFacade} e The event object for attribute change events.
  192. */
  193. _defAttrChangeFn : function(e) {
  194.  
  195. if (!this._setAttrVal(e.attrName, e.subAttrName, e.prevVal, e.newVal, e.details[1])) {
  196. // Prevent "after" listeners from being invoked since nothing changed.
  197. e.stopImmediatePropagation();
  198.  
  199. Y.log('State not updated and stopImmediatePropagation called for attribute: ' + e.attrName + ' , value:' + e.newVal, 'warn', 'attribute');
  200. } else {
  201. e.newVal = this.get(e.attrName);
  202. }
  203. }
  204. };
  205.  
  206. // Basic prototype augment - no lazy constructor invocation.
  207. Y.mix(AttributeObservable, EventTarget, false, null, 1);
  208.  
  209. Y.AttributeObservable = AttributeObservable;
  210.  
  211. /**
  212. The `AttributeEvents` class extension was deprecated in YUI 3.8.0 and is now
  213. an alias for the `AttributeObservable` class extension. Use that class
  214. extnesion instead. This alias will be removed in a future version of YUI.
  215.  
  216. @class AttributeEvents
  217. @uses EventTarget
  218. @deprecated Use `AttributeObservable` instead.
  219. @see AttributeObservable
  220. **/
  221. Y.AttributeEvents = AttributeObservable;
  222.