Advertisement
Guest User

Untitled

a guest
Apr 30th, 2016
75
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.75 KB | None | 0 0
  1. /**
  2. * A model base class that extends Backbone.Model to provide both
  3. * common functionality and common model properties.
  4. *
  5. * Common properties are defined by property configuration data objects returned
  6. * by the propConfig getter.
  7. *
  8. * Common functionality determined by propConfig includes:
  9. * - defaults
  10. * - server data parsing
  11. */
  12. class ABaseModel extends Backbone.Model {
  13.  
  14. /**
  15. * Returns an array of objects that are used to generate properties and
  16. * default values for the model class. Subclasses that override this should
  17. * concat additional prop objects to the results of super, e.g.:
  18. * return super.propConfig.concat([{...}]);
  19. * so that properties defined in ABaseModel or other parent classes aren't lost.
  20. *
  21. * Each prop object can have the following values:
  22. * - prop {string}: the name of the property to be defined.
  23. * Required.
  24. * - attr {string}: the name of the Backbone model attribute. Useful if
  25. * the server returns an attribute like `_xzserver_full_name` that would
  26. * read better in the frontend as `fullName`.
  27. * Defaults to `prop` value.
  28. * - get {func}: the getter function.
  29. * Defaults to `Backbone.Model.get(attr)`.
  30. * - set {func}: the setter function. If this is present but undefined,
  31. * no setter will be created for the property, resulting in a read-only prop.
  32. * Defaults to `Backbone.Model.set(attr, value)`
  33. * - configurable {bool}: `true` if and only if the type of this property
  34. * descriptor may be changed and if the property may be deleted from
  35. * the corresponding object.
  36. * Defaults to `false`.
  37. * - enumerable {bool}: `true` if and only if this property shows up during
  38. * enumeration of the properties on the corresponding object.
  39. * Defaults to `true`.
  40. *
  41. * - default {* | func}: default value for the property, as returned by
  42. * Backbone.Model.defaults. If a function, called with `this` set to
  43. * the model instance. A function should be used to return all
  44. * object defaults (i.e. non-primitives), e.g.:
  45. * {prop: 'data', default: function() {return {};}}
  46. * since otherwise all model instances would share the same single object.
  47. *
  48. * - mapping {string}: if set, `parse` will map server values to frontend values.
  49. * Options:
  50. * 'date': passes the value (which should be a string in a format
  51. * recognized by the `Date.parse()`` method) to a new `Date` constructor,
  52. * and stores the date object in the model instance.
  53. * 'relation': passes the value (which should be an object or an array
  54. * of objects with model attributes) to a model constructor,
  55. * as specified by the `class` property, and stores the new
  56. * model instance or a model collection in the owning model instance.
  57. * Uses a new Backbone.Collection if the server value is an array.
  58. * - class {class}: the class to construct for relation mappings.
  59. * Required if mapping == 'relation'.
  60. *
  61. * Examples:
  62. *
  63. * // Simple prop
  64. * {prop: 'name'}
  65. *
  66. * // Prop with different server attribute name
  67. * {prop: 'firstName', attr: 'first_name'}
  68. *
  69. * // Un-modifiable prop
  70. * {prop: 'emailConfirmed', set: undefined}
  71. *
  72. * // Un-enumerable prop
  73. * {prop: 'syncId', enumerable: false}
  74. *
  75. * // Primitive default value
  76. * {prop: 'active', default: true}
  77. *
  78. * // Object default value
  79. * {prop: 'extraData', default: function() { return {}; }}
  80. *
  81. * // Date default value
  82. * {prop: 'created', default: function() { return new Date(); }}
  83. *
  84. * // Uses date parsing
  85. * {prop: 'lastModified', mapping: 'date'}
  86. *
  87. * // Uses relationship parsing
  88. * {prop: 'address', mapping: 'relation', class: AAddress}
  89. *
  90. * @returns {array}
  91. */
  92. static get propConfig() {
  93. return [];
  94. }
  95.  
  96. /**
  97. * Configures properties on the model class based on the results of propConfig.
  98. * Should be called on each subclass of ABaseModel.
  99. */
  100. static configureProps() {
  101. for (const propData of this.propConfig) {
  102. const prop = propData.prop;
  103. // attr is optional, defaults to prop
  104. const attr = propData.attr || propData.prop;
  105. const descriptor = propData;
  106.  
  107. Object.defineProperty(this.prototype, prop, Object.assign({
  108. get: function() {
  109. return this.get(attr);
  110. },
  111. set: function(value) {
  112. this.set(attr, value);
  113. },
  114. enumerable: true,
  115. }, descriptor));
  116. }
  117. }
  118.  
  119. /**
  120. * `Backbone.Model.defaults` override gets defaults from propConfig.
  121. * Called automatically by Backbone.Model.constructor.
  122. */
  123. get defaults() {
  124. const defaults = {};
  125.  
  126. this.constructor.propConfig.forEach((propData) => {
  127. const attr = propData.attr || propData.prop;
  128.  
  129. let def = propData.default;
  130.  
  131. if ('function' === typeof def)
  132. {
  133. def = propData.default.call(this)
  134. }
  135.  
  136. defaults[attr] = def;
  137. })
  138.  
  139. return defaults;
  140. }
  141.  
  142. /**
  143. * Returns `propConfig` array, filtered by properties that have a `mapping` value.
  144. * @returns {array}
  145. */
  146. get mappings() {
  147. return this.constructor.propConfig.filter((propData) => {
  148. return !!propData.mapping;
  149. });
  150. }
  151.  
  152. /**
  153. * Override `Backbone.Model.parse` to map API values to model values based on
  154. * propConfig. `parse` is called automatically whenever a model's data is
  155. * returned by the server, in `fetch`, and `save`.
  156. */
  157. parse(response) {
  158. for (const propData of this.mappings) {
  159. const attr = propData.attr || propData.prop;
  160. const mapping = propData.mapping;
  161. const val = response[attr];
  162.  
  163. if (null !== val && undefined !== val) {
  164. switch (mapping) {
  165. case 'date':
  166. response[attr] = new Date(val);
  167. break;
  168. case 'relation':
  169. if (val instanceof Array)
  170. {
  171. const collection = new Backbone.Collection();
  172. collection.model = propData.class;
  173.  
  174. collection.add(val, {parse: true});
  175.  
  176. response[attr] = collection;
  177. }
  178. else
  179. {
  180. response[attr] = new propData.class(val, {parse: true});
  181. }
  182. break;
  183. default:
  184. throw new Error(`Unknown mapping type ${mapping} for prop ${attr}`);
  185. }
  186. }
  187. }
  188.  
  189. return response;
  190. }
  191. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement