rasti 2.0.0-alpha.9 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/Model.js CHANGED
@@ -4,17 +4,16 @@ exports.__esModule = true;
4
4
  exports["default"] = void 0;
5
5
  var _Emitter2 = _interopRequireDefault(require("./Emitter.js"));
6
6
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
7
- function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
8
7
  function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf(subClass, superClass); }
9
8
  function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
10
9
  /**
11
10
  * - Orchestrates data and business logic.
12
11
  * - Emits events when data changes.
13
12
  *
14
- * A `Model` manages an internal table of data attributes and triggers change events when any of its data is modified.<br />
13
+ * A `Model` manages an internal table of data attributes and triggers change events when any of its data is modified.
15
14
  * Models may handle syncing data with a persistence layer. To design your models, create atomic, reusable objects
16
- * that contain all the necessary functions for manipulating their specific data.<br />
17
- * Models should be easily passed throughout your app and used anywhere the corresponding data is needed.<br />
15
+ * that contain all the necessary functions for manipulating their specific data.
16
+ * Models should be easily passed throughout your app and used anywhere the corresponding data is needed.
18
17
  * Rasti models stores its attributes in `this.attributes`, which is extended from `this.defaults` and the
19
18
  * constructor `attrs` parameter. For every attribute, a getter is generated to retrieve the model property
20
19
  * from `this.attributes`, and a setter is created to set the model property in `this.attributes` and emit `change`
@@ -53,19 +52,18 @@ function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf ? Objec
53
52
  * product.setDiscount(10); // Output: "New Price: 900"
54
53
  */
55
54
  var Model = exports["default"] = /*#__PURE__*/function (_Emitter) {
56
- _inheritsLoose(Model, _Emitter);
57
55
  function Model() {
58
56
  var _this;
59
57
  var attrs = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
60
58
  _this = _Emitter.call(this) || this;
61
59
  // Call preinitialize.
62
- _this.preinitialize.apply(_assertThisInitialized(_this), arguments);
60
+ _this.preinitialize.apply(_this, arguments);
63
61
  // attributes object.
64
62
  _this.attributes = Object.assign({}, _this.defaults || {}, attrs);
65
63
  // Previous attributes.
66
64
  _this.previous = {};
67
65
  // Generate getters/setters for every attr.
68
- Object.keys(_this.attributes).forEach(_this.defineAttribute.bind(_assertThisInitialized(_this)));
66
+ Object.keys(_this.attributes).forEach(_this.defineAttribute.bind(_this));
69
67
  return _this;
70
68
  }
71
69
 
@@ -73,6 +71,7 @@ var Model = exports["default"] = /*#__PURE__*/function (_Emitter) {
73
71
  * If you define a preinitialize method, it will be invoked when the Model is first created, before any instantiation logic is run for the Model.
74
72
  * @param {object} attrs Object containing model attributes to extend `this.attributes`.
75
73
  */
74
+ _inheritsLoose(Model, _Emitter);
76
75
  var _proto = Model.prototype;
77
76
  _proto.preinitialize = function preinitialize() {}
78
77
 
@@ -105,11 +104,13 @@ var Model = exports["default"] = /*#__PURE__*/function (_Emitter) {
105
104
  }
106
105
 
107
106
  /**
108
- * Set an attribute into `this.attributes`.
109
- * Emit `change` and `change:attribute` if a value change.
107
+ * Set an attribute into `this.attributes`.
108
+ * Emit `change` and `change:attribute` if a value change.
110
109
  * Could be called in two forms, `this.set('key', value)` and
111
- * `this.set({ key : value })`.
112
- * This method is called internally by generated setters.
110
+ * `this.set({ key : value })`.
111
+ * This method is called internally by generated setters.
112
+ * The `change` event listener will receive the model instance, an object containing the changed attributes, and the rest of the arguments passed to `set` method.
113
+ * The `change:attribute` event listener will receive the model instance, the new attribute value, and the rest of the arguments passed to `set` method.
113
114
  * @param {string} key Attribute key or object containing keys/values.
114
115
  * @param [value] Attribute value.
115
116
  * @return {this} This model.
package/lib/View.js CHANGED
@@ -4,7 +4,6 @@ exports.__esModule = true;
4
4
  exports["default"] = void 0;
5
5
  var _Emitter2 = _interopRequireDefault(require("./Emitter.js"));
6
6
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
7
- function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
8
7
  function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf(subClass, superClass); }
9
8
  function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
10
9
  // This options keys will be extended on view instance.
@@ -24,10 +23,10 @@ var viewOptions = {
24
23
  * - Sends captured input to the model.
25
24
  *
26
25
  * A `View` is an atomic unit of the user interface that can render the data from a specific model or multiple models.
27
- * However, views can also be independent and have no associated data.<br />
26
+ * However, views can also be independent and have no associated data.
28
27
  * Models must be unaware of views. Views, on the other hand, may render model data and listen to the change events
29
- * emitted by the models to re-render themselves based on changes.<br />
30
- * Each `View` has a root element, `this.el`, which is used for event delegation.<br />
28
+ * emitted by the models to re-render themselves based on changes.
29
+ * Each `View` has a root element, `this.el`, which is used for event delegation.
31
30
  * All element lookups are scoped to this element, and any rendering or DOM manipulations should be done inside it.
32
31
  * If `this.el` is not present, an element will be created using `this.tag` (defaulting to div) and `this.attributes`.
33
32
  * @module
@@ -61,13 +60,12 @@ var viewOptions = {
61
60
  * document.body.appendChild(new Timer().render().el);
62
61
  */
63
62
  var View = exports["default"] = /*#__PURE__*/function (_Emitter) {
64
- _inheritsLoose(View, _Emitter);
65
63
  function View() {
66
64
  var _this;
67
65
  var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
68
66
  _this = _Emitter.call(this) || this;
69
67
  // Call preinitialize.
70
- _this.preinitialize.apply(_assertThisInitialized(_this), arguments);
68
+ _this.preinitialize.apply(_this, arguments);
71
69
  // Generate unique id.
72
70
  // Useful to generate elements ids.
73
71
  _this.uid = "uid" + ++View.uid;
@@ -90,6 +88,7 @@ var View = exports["default"] = /*#__PURE__*/function (_Emitter) {
90
88
  * If you define a preinitialize method, it will be invoked when the view is first created, before any instantiation logic is run.
91
89
  * @param {object} attrs Object containing model attributes to extend `this.attributes`.
92
90
  */
91
+ _inheritsLoose(View, _Emitter);
93
92
  var _proto = View.prototype;
94
93
  _proto.preinitialize = function preinitialize() {}
95
94
 
@@ -116,6 +115,7 @@ var View = exports["default"] = /*#__PURE__*/function (_Emitter) {
116
115
  /**
117
116
  * Destroy the view.
118
117
  * Destroy children views if any, undelegate events, stop listening to events, call `onDestroy` lifecycle method.
118
+ * @return {Rasti.View} Return `this` for chaining.
119
119
  */;
120
120
  _proto.destroy = function destroy() {
121
121
  // Call destroy on children.
@@ -193,18 +193,21 @@ var View = exports["default"] = /*#__PURE__*/function (_Emitter) {
193
193
 
194
194
  /**
195
195
  * Remove `this.el` from DOM.
196
+ * @return {Rasti.View} Return `this` for chaining.
196
197
  */;
197
198
  _proto.removeElement = function removeElement() {
198
199
  this.el.parentNode.removeChild(this.el);
200
+ // Return `this` for chaining.
201
+ return this;
199
202
  }
200
203
 
201
204
  /**
202
- * Provide declarative listeners for DOM events within a view. If an events hash is not passed directly, uses `this.events` as the source.<br />
205
+ * Provide declarative listeners for DOM events within a view. If an events hash is not passed directly, uses `this.events` as the source.
203
206
  * Events are written in the format `{'event selector' : 'listener'}`. The listener may be either the name of a method on the view, or a direct function body.
204
- * Omitting the selector causes the event to be bound to the view's root element (`this.el`).<br />
207
+ * Omitting the selector causes the event to be bound to the view's root element (`this.el`).
205
208
  * By default, `delegateEvents` is called within the View's constructor,
206
- * so if you have a simple events hash, all of your DOM events will always already be connected, and you will never have to call this function yourself. <br />
207
- * All attached listeners are bound to the view automatically, so when the listeners are invoked, `this` continues to refer to the view object.<br />
209
+ * so if you have a simple events hash, all of your DOM events will always already be connected, and you will never have to call this function yourself.
210
+ * All attached listeners are bound to the view automatically, so when the listeners are invoked, `this` continues to refer to the view object.
208
211
  * When `delegateEvents` is run again, perhaps with a different events hash, all listeners are removed and delegated afresh.
209
212
  * @param {object} [events] Object in the format `{'event selector' : 'listener'}`. Used to bind delegated event listeners to root element.
210
213
  * @return {Rasti.View} Return `this` for chaining.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "rasti",
3
- "version": "2.0.0-alpha.9",
4
- "description": "Minimalistic, ultra-lightweight JavaScript library for building user interfaces.",
3
+ "version": "2.0.0",
4
+ "description": "Rasti is a minimalistic JavaScript library for building user interfaces.",
5
5
  "main": "lib/index.js",
6
6
  "jsnext:main": "es/index.js",
7
7
  "files": [
@@ -39,39 +39,39 @@
39
39
  "author": "Alberto Masuelli <alberto.masuelli@gmail.com> (https://github.com/8tentaculos)",
40
40
  "license": "MIT",
41
41
  "devDependencies": {
42
- "@babel/cli": "^7.22.5",
43
- "@babel/core": "^7.22.5",
44
- "@babel/eslint-parser": "^7.22.5",
45
- "@babel/plugin-transform-arrow-functions": "^7.22.5",
46
- "@babel/plugin-transform-block-scoped-functions": "^7.22.5",
47
- "@babel/plugin-transform-block-scoping": "^7.22.5",
48
- "@babel/plugin-transform-classes": "^7.22.5",
49
- "@babel/plugin-transform-computed-properties": "^7.22.5",
50
- "@babel/plugin-transform-destructuring": "^7.22.5",
51
- "@babel/plugin-transform-for-of": "^7.22.5",
52
- "@babel/plugin-transform-function-name": "^7.22.5",
53
- "@babel/plugin-transform-literals": "^7.22.5",
54
- "@babel/plugin-transform-member-expression-literals": "^7.22.5",
55
- "@babel/plugin-transform-modules-commonjs": "^7.22.5",
56
- "@babel/plugin-transform-object-super": "^7.22.5",
57
- "@babel/plugin-transform-parameters": "^7.22.5",
58
- "@babel/plugin-transform-property-literals": "^7.22.5",
59
- "@babel/plugin-transform-shorthand-properties": "^7.22.5",
60
- "@babel/plugin-transform-spread": "^7.22.5",
61
- "@babel/plugin-transform-sticky-regex": "^7.22.5",
62
- "@babel/plugin-transform-template-literals": "^7.22.5",
63
- "@babel/plugin-transform-unicode-regex": "^7.22.5",
64
- "@babel/register": "^7.22.5",
65
- "babel-loader": "^9.1.2",
66
- "chai": "^4.3.7",
67
- "cross-env": "^5.2.1",
68
- "eslint": "^8.43.0",
69
- "jsdoc-to-markdown": "^8.0.0",
70
- "jsdom": "^22.1.0",
42
+ "@babel/cli": "^7.24.1",
43
+ "@babel/core": "^7.24.3",
44
+ "@babel/eslint-parser": "^7.24.1",
45
+ "@babel/plugin-transform-arrow-functions": "^7.24.1",
46
+ "@babel/plugin-transform-block-scoped-functions": "^7.24.1",
47
+ "@babel/plugin-transform-block-scoping": "^7.24.1",
48
+ "@babel/plugin-transform-classes": "^7.24.1",
49
+ "@babel/plugin-transform-computed-properties": "^7.24.1",
50
+ "@babel/plugin-transform-destructuring": "^7.24.1",
51
+ "@babel/plugin-transform-for-of": "^7.24.1",
52
+ "@babel/plugin-transform-function-name": "^7.24.1",
53
+ "@babel/plugin-transform-literals": "^7.24.1",
54
+ "@babel/plugin-transform-member-expression-literals": "^7.24.1",
55
+ "@babel/plugin-transform-modules-commonjs": "^7.24.1",
56
+ "@babel/plugin-transform-object-super": "^7.24.1",
57
+ "@babel/plugin-transform-parameters": "^7.24.1",
58
+ "@babel/plugin-transform-property-literals": "^7.24.1",
59
+ "@babel/plugin-transform-shorthand-properties": "^7.24.1",
60
+ "@babel/plugin-transform-spread": "^7.24.1",
61
+ "@babel/plugin-transform-sticky-regex": "^7.24.1",
62
+ "@babel/plugin-transform-template-literals": "^7.24.1",
63
+ "@babel/plugin-transform-unicode-regex": "^7.24.1",
64
+ "@babel/register": "^7.23.7",
65
+ "babel-loader": "^9.1.3",
66
+ "chai": "^4.4.1",
67
+ "cross-env": "^7.0.3",
68
+ "eslint": "^8.57.0",
69
+ "jsdoc-to-markdown": "^8.0.1",
70
+ "jsdom": "^24.0.0",
71
71
  "jsdom-global": "3.0.2",
72
- "mocha": "^10.2.0",
73
- "rimraf": "^5.0.1",
74
- "webpack": "^5.88.1",
72
+ "mocha": "^10.4.0",
73
+ "rimraf": "^5.0.5",
74
+ "webpack": "^5.91.0",
75
75
  "webpack-cli": "^5.1.4"
76
76
  },
77
77
  "directories": {
package/src/Component.js CHANGED
@@ -47,9 +47,9 @@ const evalExpression = (expression, context, ...args) =>
47
47
 
48
48
  /**
49
49
  * Components are a special kind of `View` that is designed to be easily composable,
50
- * making it simple to add child views and build complex user interfaces.<br />
50
+ * making it simple to add child views and build complex user interfaces.
51
51
  * Unlike views, which are render-agnostic, components have a specific set of rendering
52
- * guidelines that allow for a more declarative development style.<br />
52
+ * guidelines that allow for a more declarative development style.
53
53
  * Components are defined with the `create` static method, which takes a tagged template.
54
54
  * @module
55
55
  * @extends Rasti.View
@@ -74,25 +74,19 @@ const evalExpression = (expression, context, ...args) =>
74
74
  */
75
75
  export default class Component extends View {
76
76
  constructor(options = {}) {
77
- super(options);
77
+ super(...arguments);
78
78
  // Extend "this" with options, mapping componentOptions keys.
79
79
  Object.keys(options).forEach(key => {
80
80
  if (componentOptions[key]) this[key] = options[key];
81
81
  });
82
82
  // Store options by default.
83
83
  this.options = options;
84
- // Ensure id.
85
- this.id = this.attributes.id ?
86
- // If id is provided, evaluate it.
87
- evalExpression(this.attributes.id, this, this) :
88
- // Generate a unique id and set it as id attribute.
89
- Component.ID_TEMPLATE(this.uid);
90
84
  // Bind onChange to this to be used as listener.
91
85
  // Store bound version, so it can be removed on onDestroy method.
92
86
  this.onChange = this.onChange.bind(this);
93
87
  // Listen to model changes and call onChange.
94
- if (this.model) this.model.on('change', this.onChange);
95
- if (this.state) this.state.on('change', this.onChange);
88
+ if (this.model && this.model.on) this.model.on('change', this.onChange);
89
+ if (this.state && this.state.on) this.state.on('change', this.onChange);
96
90
  // Call life cycle method.
97
91
  this.onCreate.apply(this, arguments);
98
92
  }
@@ -103,7 +97,18 @@ export default class Component extends View {
103
97
  */
104
98
  ensureElement() {
105
99
  // If el is provided, delegate events.
106
- if (this.el) this.delegateEvents();
100
+ if (this.el) {
101
+ this.delegateEvents();
102
+ this.id = this.el.id;
103
+ }
104
+ // Ensure id.
105
+ if (!this.id) {
106
+ this.id = this.attributes && this.attributes.id ?
107
+ // If id is provided, evaluate it.
108
+ evalExpression(this.attributes.id, this, this) :
109
+ // Generate a unique id and set it as id attribute.
110
+ Component.ID_TEMPLATE(this.uid);
111
+ }
107
112
  }
108
113
 
109
114
  /*
@@ -117,33 +122,32 @@ export default class Component extends View {
117
122
  * Eval attributes expressions.
118
123
  */
119
124
  getAttributes() {
120
- const add = {};
125
+ const add = { id : this.id };
121
126
  const remove = {};
122
- const attrs = [];
123
-
124
- Object.keys(this.attributes).forEach(key => {
125
- if (key === 'id') return;
126
- // Evaluate attribute value.
127
- let value = evalExpression(this.attributes[key], this, this);
128
-
129
- // Transform bool attribute values
130
- if (value === false) {
131
- remove[key] = true;
132
- } else if (value === true) {
133
- add[key] = '';
134
- attrs.push(key);
135
- } else {
136
- if (value === null || typeof value === 'undefined') value = '';
137
-
138
- add[key] = value;
139
- attrs.push(`${key}="${value}"`);
140
- }
141
- });
127
+ const html = [`id="${this.id}"`];
128
+
129
+ if (this.attributes) {
130
+ Object.keys(this.attributes).forEach(key => {
131
+ if (key === 'id') return;
132
+ // Evaluate attribute value.
133
+ let value = evalExpression(this.attributes[key], this, this);
134
+
135
+ // Transform bool attribute values
136
+ if (value === false) {
137
+ remove[key] = true;
138
+ } else if (value === true) {
139
+ add[key] = '';
140
+ html.push(key);
141
+ } else {
142
+ if (value === null || typeof value === 'undefined') value = '';
142
143
 
143
- add.id = this.id;
144
- attrs.push(`id="${this.id}"`);
144
+ add[key] = value;
145
+ html.push(`${key}="${value}"`);
146
+ }
147
+ });
148
+ }
145
149
 
146
- return { add, remove, html : attrs.join(' ') };
150
+ return { add, remove, html : html.join(' ') };
147
151
  }
148
152
 
149
153
  /*
@@ -177,8 +181,8 @@ export default class Component extends View {
177
181
  super.destroy.apply(this, arguments);
178
182
  // Stop listening to `change`.
179
183
  // Set destroyed flag to prevent a last render after destroyed. TODO: Review
180
- if (this.model) this.model.off('change', this.onChange);
181
- if (this.state) this.state.off('change', this.onChange);
184
+ if (this.model && this.model.off) this.model.off('change', this.onChange);
185
+ if (this.state && this.state.off) this.state.off('change', this.onChange);
182
186
  this.destroyed = true;
183
187
  }
184
188
 
@@ -195,8 +199,8 @@ export default class Component extends View {
195
199
  * Maybe comparing new attributes with previous ones and calling
196
200
  * render when needed. Or doing some dom transformation.
197
201
  * @param model {Rasti.Model} The model that emitted the event.
198
- * @param key {string} The key that changed.
199
- * @param value {any} The new value.
202
+ * @param changed {object} Object containing keys and values that has changed.
203
+ * @param [...args] {any} Any extra arguments passed to set method.
200
204
  */
201
205
  onChange() {
202
206
  this.render();
@@ -257,15 +261,21 @@ export default class Component extends View {
257
261
  toString() {
258
262
  // Normally there won't be any children, but if there are, destroy them.
259
263
  this.destroyChildren();
260
- // Replace expressions.
261
- const inner = this.template.inner && this.replaceExpressions(this.template.inner, (component) => {
262
- // Add child component.
263
- return this.addChild(component);
264
- });
264
+ // Get tag name.
265
+ const tag = this.tag || 'div';
266
+ // Get attributes.
267
+ const attributes = this.getAttributes().html;
268
+ // Replace expressions of inner template.
269
+ const inner = this.template &&
270
+ this.template.inner &&
271
+ this.replaceExpressions(this.template.inner, (component) => {
272
+ // Add child component.
273
+ return this.addChild(component);
274
+ });
265
275
  // Generate outer template.
266
276
  return inner ?
267
- `<${this.tag} ${this.getAttributes().html}>${inner}</${this.tag}>` :
268
- `<${this.tag} ${this.getAttributes().html} />`;
277
+ `<${tag} ${attributes}>${inner}</${tag}>` :
278
+ `<${tag} ${attributes} />`;
269
279
  }
270
280
 
271
281
  /*
@@ -290,7 +300,7 @@ export default class Component extends View {
290
300
  this.el.setAttribute(key, attributes.add[key]);
291
301
  });
292
302
  // Check for `template.inner` to see if view has innerHTML.
293
- if (this.template.inner) {
303
+ if (this.template && this.template.inner) {
294
304
  const previousChildren = this.children;
295
305
 
296
306
  this.children = [];
@@ -308,8 +318,10 @@ export default class Component extends View {
308
318
  );
309
319
 
310
320
  if (found) {
321
+ const tag = found.el.tagName.toLowerCase();
322
+ const id = found.el.id;
311
323
  // If child already exists, replace it html by its root element.
312
- out = `<${found.tag} id="${found.id}"></${found.tag}>`;
324
+ out = `<${tag} id="${id}"></${tag}>`;
313
325
  // Add child to recycled children.
314
326
  recycledChildren.push(found);
315
327
  // Destroy new child component. Use recycled one instead.
@@ -374,7 +386,7 @@ export default class Component extends View {
374
386
  * @param {boolean} hydrate If true, the view will use existing html.
375
387
  * @return {Rasti.Component}
376
388
  */
377
- static mount(options = {}, el, hydrate) {
389
+ static mount(options, el, hydrate) {
378
390
  // Instantiate view.
379
391
  const view = new this(options);
380
392
  // If `el` is passed, mount component.
@@ -393,6 +405,7 @@ export default class Component extends View {
393
405
  // Return view instance.
394
406
  return view;
395
407
  }
408
+
396
409
  /**
397
410
  * Takes a tagged template containing an HTML string,
398
411
  * and returns a new `Component` class.
package/src/Emitter.js CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * `Emitter` is a class that provides an easy way to implement the observer pattern
3
- * in your applications.<br />
4
- * It can be extended to create new classes that have the ability to emit and bind custom named events.<br />
3
+ * in your applications.
4
+ * It can be extended to create new classes that have the ability to emit and bind custom named events.
5
5
  * Emitter is used by `Model` and `View` classes, which inherit from it to implement
6
6
  * event-driven functionality.
7
7
  *
package/src/Model.js CHANGED
@@ -3,10 +3,10 @@ import Emitter from './Emitter.js';
3
3
  * - Orchestrates data and business logic.
4
4
  * - Emits events when data changes.
5
5
  *
6
- * A `Model` manages an internal table of data attributes and triggers change events when any of its data is modified.<br />
6
+ * A `Model` manages an internal table of data attributes and triggers change events when any of its data is modified.
7
7
  * Models may handle syncing data with a persistence layer. To design your models, create atomic, reusable objects
8
- * that contain all the necessary functions for manipulating their specific data.<br />
9
- * Models should be easily passed throughout your app and used anywhere the corresponding data is needed.<br />
8
+ * that contain all the necessary functions for manipulating their specific data.
9
+ * Models should be easily passed throughout your app and used anywhere the corresponding data is needed.
10
10
  * Rasti models stores its attributes in `this.attributes`, which is extended from `this.defaults` and the
11
11
  * constructor `attrs` parameter. For every attribute, a getter is generated to retrieve the model property
12
12
  * from `this.attributes`, and a setter is created to set the model property in `this.attributes` and emit `change`
@@ -90,11 +90,13 @@ export default class Model extends Emitter {
90
90
  }
91
91
 
92
92
  /**
93
- * Set an attribute into `this.attributes`.
94
- * Emit `change` and `change:attribute` if a value change.
93
+ * Set an attribute into `this.attributes`.
94
+ * Emit `change` and `change:attribute` if a value change.
95
95
  * Could be called in two forms, `this.set('key', value)` and
96
- * `this.set({ key : value })`.
97
- * This method is called internally by generated setters.
96
+ * `this.set({ key : value })`.
97
+ * This method is called internally by generated setters.
98
+ * The `change` event listener will receive the model instance, an object containing the changed attributes, and the rest of the arguments passed to `set` method.
99
+ * The `change:attribute` event listener will receive the model instance, the new attribute value, and the rest of the arguments passed to `set` method.
98
100
  * @param {string} key Attribute key or object containing keys/values.
99
101
  * @param [value] Attribute value.
100
102
  * @return {this} This model.
package/src/View.js CHANGED
@@ -17,10 +17,10 @@ const viewOptions = {
17
17
  * - Sends captured input to the model.
18
18
  *
19
19
  * A `View` is an atomic unit of the user interface that can render the data from a specific model or multiple models.
20
- * However, views can also be independent and have no associated data.<br />
20
+ * However, views can also be independent and have no associated data.
21
21
  * Models must be unaware of views. Views, on the other hand, may render model data and listen to the change events
22
- * emitted by the models to re-render themselves based on changes.<br />
23
- * Each `View` has a root element, `this.el`, which is used for event delegation.<br />
22
+ * emitted by the models to re-render themselves based on changes.
23
+ * Each `View` has a root element, `this.el`, which is used for event delegation.
24
24
  * All element lookups are scoped to this element, and any rendering or DOM manipulations should be done inside it.
25
25
  * If `this.el` is not present, an element will be created using `this.tag` (defaulting to div) and `this.attributes`.
26
26
  * @module
@@ -104,6 +104,7 @@ export default class View extends Emitter {
104
104
  /**
105
105
  * Destroy the view.
106
106
  * Destroy children views if any, undelegate events, stop listening to events, call `onDestroy` lifecycle method.
107
+ * @return {Rasti.View} Return `this` for chaining.
107
108
  */
108
109
  destroy() {
109
110
  // Call destroy on children.
@@ -180,18 +181,21 @@ export default class View extends Emitter {
180
181
 
181
182
  /**
182
183
  * Remove `this.el` from DOM.
184
+ * @return {Rasti.View} Return `this` for chaining.
183
185
  */
184
186
  removeElement() {
185
187
  this.el.parentNode.removeChild(this.el);
188
+ // Return `this` for chaining.
189
+ return this;
186
190
  }
187
191
 
188
192
  /**
189
- * Provide declarative listeners for DOM events within a view. If an events hash is not passed directly, uses `this.events` as the source.<br />
193
+ * Provide declarative listeners for DOM events within a view. If an events hash is not passed directly, uses `this.events` as the source.
190
194
  * Events are written in the format `{'event selector' : 'listener'}`. The listener may be either the name of a method on the view, or a direct function body.
191
- * Omitting the selector causes the event to be bound to the view's root element (`this.el`).<br />
195
+ * Omitting the selector causes the event to be bound to the view's root element (`this.el`).
192
196
  * By default, `delegateEvents` is called within the View's constructor,
193
- * so if you have a simple events hash, all of your DOM events will always already be connected, and you will never have to call this function yourself. <br />
194
- * All attached listeners are bound to the view automatically, so when the listeners are invoked, `this` continues to refer to the view object.<br />
197
+ * so if you have a simple events hash, all of your DOM events will always already be connected, and you will never have to call this function yourself.
198
+ * All attached listeners are bound to the view automatically, so when the listeners are invoked, `this` continues to refer to the view object.
195
199
  * When `delegateEvents` is run again, perhaps with a different events hash, all listeners are removed and delegated afresh.
196
200
  * @param {object} [events] Object in the format `{'event selector' : 'listener'}`. Used to bind delegated event listeners to root element.
197
201
  * @return {Rasti.View} Return `this` for chaining.