rasti 2.0.0-alpha.9 → 2.0.1

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/es/Component.js CHANGED
@@ -1,4 +1,3 @@
1
- function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
2
1
  function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf(subClass, superClass); }
3
2
  function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
4
3
  import View from './View.js';
@@ -47,9 +46,9 @@ var evalExpression = function evalExpression(expression, context) {
47
46
 
48
47
  /**
49
48
  * 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 />
49
+ * making it simple to add child views and build complex user interfaces.
51
50
  * Unlike views, which are render-agnostic, components have a specific set of rendering
52
- * guidelines that allow for a more declarative development style.<br />
51
+ * guidelines that allow for a more declarative development style.
53
52
  * Components are defined with the `create` static method, which takes a tagged template.
54
53
  * @module
55
54
  * @extends Rasti.View
@@ -73,31 +72,24 @@ var evalExpression = function evalExpression(expression, context) {
73
72
  * setInterval(() => model.seconds++, 1000);
74
73
  */
75
74
  var Component = /*#__PURE__*/function (_View) {
76
- _inheritsLoose(Component, _View);
77
75
  function Component() {
78
76
  var _this;
79
77
  var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
80
- _this = _View.call(this, options) || this;
78
+ _this = _View.apply(this, arguments) || this;
81
79
  // Extend "this" with options, mapping componentOptions keys.
82
80
  Object.keys(options).forEach(function (key) {
83
81
  if (componentOptions[key]) _this[key] = options[key];
84
82
  });
85
83
  // Store options by default.
86
84
  _this.options = options;
87
- // Ensure id.
88
- _this.id = _this.attributes.id ?
89
- // If id is provided, evaluate it.
90
- evalExpression(_this.attributes.id, _assertThisInitialized(_this), _assertThisInitialized(_this)) :
91
- // Generate a unique id and set it as id attribute.
92
- Component.ID_TEMPLATE(_this.uid);
93
85
  // Bind onChange to this to be used as listener.
94
86
  // Store bound version, so it can be removed on onDestroy method.
95
- _this.onChange = _this.onChange.bind(_assertThisInitialized(_this));
87
+ _this.onChange = _this.onChange.bind(_this);
96
88
  // Listen to model changes and call onChange.
97
- if (_this.model) _this.model.on('change', _this.onChange);
98
- if (_this.state) _this.state.on('change', _this.onChange);
89
+ if (_this.model && _this.model.on) _this.model.on('change', _this.onChange);
90
+ if (_this.state && _this.state.on) _this.state.on('change', _this.onChange);
99
91
  // Call life cycle method.
100
- _this.onCreate.apply(_assertThisInitialized(_this), arguments);
92
+ _this.onCreate.apply(_this, arguments);
101
93
  return _this;
102
94
  }
103
95
 
@@ -105,10 +97,22 @@ var Component = /*#__PURE__*/function (_View) {
105
97
  * Override. We don't want to ensure an element on instantiation.
106
98
  * We will provide it later.
107
99
  */
100
+ _inheritsLoose(Component, _View);
108
101
  var _proto = Component.prototype;
109
102
  _proto.ensureElement = function ensureElement() {
110
103
  // If el is provided, delegate events.
111
- if (this.el) this.delegateEvents();
104
+ if (this.el) {
105
+ this.delegateEvents();
106
+ this.id = this.el.id;
107
+ }
108
+ // Ensure id.
109
+ if (!this.id) {
110
+ this.id = this.attributes && this.attributes.id ?
111
+ // If id is provided, evaluate it.
112
+ evalExpression(this.attributes.id, this, this) :
113
+ // Generate a unique id and set it as id attribute.
114
+ Component.ID_TEMPLATE(this.uid);
115
+ }
112
116
  }
113
117
 
114
118
  /*
@@ -123,32 +127,34 @@ var Component = /*#__PURE__*/function (_View) {
123
127
  */;
124
128
  _proto.getAttributes = function getAttributes() {
125
129
  var _this2 = this;
126
- var add = {};
130
+ var add = {
131
+ id: this.id
132
+ };
127
133
  var remove = {};
128
- var attrs = [];
129
- Object.keys(this.attributes).forEach(function (key) {
130
- if (key === 'id') return;
131
- // Evaluate attribute value.
132
- var value = evalExpression(_this2.attributes[key], _this2, _this2);
134
+ var html = ["id=\"" + this.id + "\""];
135
+ if (this.attributes) {
136
+ Object.keys(this.attributes).forEach(function (key) {
137
+ if (key === 'id') return;
138
+ // Evaluate attribute value.
139
+ var value = evalExpression(_this2.attributes[key], _this2, _this2);
133
140
 
134
- // Transform bool attribute values
135
- if (value === false) {
136
- remove[key] = true;
137
- } else if (value === true) {
138
- add[key] = '';
139
- attrs.push(key);
140
- } else {
141
- if (value === null || typeof value === 'undefined') value = '';
142
- add[key] = value;
143
- attrs.push(key + "=\"" + value + "\"");
144
- }
145
- });
146
- add.id = this.id;
147
- attrs.push("id=\"" + this.id + "\"");
141
+ // Transform bool attribute values
142
+ if (value === false) {
143
+ remove[key] = true;
144
+ } else if (value === true) {
145
+ add[key] = '';
146
+ html.push(key);
147
+ } else {
148
+ if (value === null || typeof value === 'undefined') value = '';
149
+ add[key] = value;
150
+ html.push(key + "=\"" + value + "\"");
151
+ }
152
+ });
153
+ }
148
154
  return {
149
155
  add: add,
150
156
  remove: remove,
151
- html: attrs.join(' ')
157
+ html: html.join(' ')
152
158
  };
153
159
  }
154
160
 
@@ -185,10 +191,12 @@ var Component = /*#__PURE__*/function (_View) {
185
191
  _proto.destroy = function destroy() {
186
192
  _View.prototype.destroy.apply(this, arguments);
187
193
  // Stop listening to `change`.
188
- // Set destroyed flag to prevent a last render after destroyed. TODO: Review
189
- if (this.model) this.model.off('change', this.onChange);
190
- if (this.state) this.state.off('change', this.onChange);
194
+ if (this.model && this.model.off) this.model.off('change', this.onChange);
195
+ if (this.state && this.state.off) this.state.off('change', this.onChange);
196
+ // Set destroyed flag to prevent a last render after destroyed.
191
197
  this.destroyed = true;
198
+ // Return `this` for chaining.
199
+ return this;
192
200
  }
193
201
 
194
202
  /**
@@ -204,8 +212,8 @@ var Component = /*#__PURE__*/function (_View) {
204
212
  * Maybe comparing new attributes with previous ones and calling
205
213
  * render when needed. Or doing some dom transformation.
206
214
  * @param model {Rasti.Model} The model that emitted the event.
207
- * @param key {string} The key that changed.
208
- * @param value {any} The new value.
215
+ * @param changed {object} Object containing keys and values that has changed.
216
+ * @param [...args] {any} Any extra arguments passed to set method.
209
217
  */;
210
218
  _proto.onChange = function onChange() {
211
219
  this.render();
@@ -251,12 +259,12 @@ var Component = /*#__PURE__*/function (_View) {
251
259
  return out + parsed;
252
260
  }, '');
253
261
  })
254
- // Replace `attribute="true"` with `attribute`
255
- .replace(new RegExp("([a-z]+)=[\"|']" + Component.TRUE_PLACEHOLDER + "[\"|']", 'g'), '$1')
256
- // Replace `attribute="false"` with empty string.
257
- .replace(new RegExp("([a-z]+)=[\"|']" + Component.FALSE_PLACEHOLDER + "[\"|']", 'g'), '')
258
- // Replace rest of false expressions with empty string.
259
- .replace(new RegExp(Component.FALSE_PLACEHOLDER, 'g'), '');
262
+ // Replace `attribute="true"` with `attribute` and `attribute="false"` with empty string.
263
+ .replace(new RegExp("([\\w|data-]+)=([\"'])?(" + Component.TRUE_PLACEHOLDER + "|" + Component.FALSE_PLACEHOLDER + ")\\2", 'g'), function (match, attribute, quote, placeholder) {
264
+ return placeholder === Component.TRUE_PLACEHOLDER ? attribute : '';
265
+ })
266
+ // Replace rest of true or false expressions with empty string.
267
+ .replace(new RegExp(Component.TRUE_PLACEHOLDER + "|" + Component.FALSE_PLACEHOLDER, 'g'), '');
260
268
  }
261
269
 
262
270
  /*
@@ -266,13 +274,18 @@ var Component = /*#__PURE__*/function (_View) {
266
274
  var _this5 = this;
267
275
  // Normally there won't be any children, but if there are, destroy them.
268
276
  this.destroyChildren();
269
- // Replace expressions.
270
- var inner = this.template.inner && this.replaceExpressions(this.template.inner, function (component) {
277
+ // Get tag name.
278
+ var tag = this.tag || 'div';
279
+ // Get attributes.
280
+ var attributes = this.getAttributes().html;
281
+ // Replace expressions of inner template.
282
+ var close = this.template && this.template.inner;
283
+ var inner = close && this.replaceExpressions(this.template.inner, function (component) {
271
284
  // Add child component.
272
285
  return _this5.addChild(component);
273
286
  });
274
287
  // Generate outer template.
275
- return inner ? "<" + this.tag + " " + this.getAttributes().html + ">" + inner + "</" + this.tag + ">" : "<" + this.tag + " " + this.getAttributes().html + " />";
288
+ return close ? "<" + tag + " " + attributes + ">" + inner + "</" + tag + ">" : "<" + tag + " " + attributes + " />";
276
289
  }
277
290
 
278
291
  /*
@@ -298,7 +311,7 @@ var Component = /*#__PURE__*/function (_View) {
298
311
  _this6.el.setAttribute(key, attributes.add[key]);
299
312
  });
300
313
  // Check for `template.inner` to see if view has innerHTML.
301
- if (this.template.inner) {
314
+ if (this.template && this.template.inner) {
302
315
  var previousChildren = this.children;
303
316
  this.children = [];
304
317
  var nextChildren = [];
@@ -313,8 +326,10 @@ var Component = /*#__PURE__*/function (_View) {
313
326
  return previousChild.key === component.key;
314
327
  });
315
328
  if (found) {
329
+ var tag = found.el.tagName.toLowerCase();
330
+ var id = found.el.id;
316
331
  // If child already exists, replace it html by its root element.
317
- out = "<" + found.tag + " id=\"" + found.id + "\"></" + found.tag + ">";
332
+ out = "<" + tag + " id=\"" + id + "\"></" + tag + ">";
318
333
  // Add child to recycled children.
319
334
  recycledChildren.push(found);
320
335
  // Destroy new child component. Use recycled one instead.
@@ -358,10 +373,10 @@ var Component = /*#__PURE__*/function (_View) {
358
373
  Component.extend = function extend(object) {
359
374
  var Current = this;
360
375
  var Extended = /*#__PURE__*/function (_Current) {
361
- _inheritsLoose(Extended, _Current);
362
376
  function Extended() {
363
377
  return _Current.apply(this, arguments) || this;
364
378
  }
379
+ _inheritsLoose(Extended, _Current);
365
380
  return Extended;
366
381
  }(Current);
367
382
  Object.assign(Extended.prototype, typeof object === 'function' ? object(Current.prototype) : object);
@@ -379,10 +394,7 @@ var Component = /*#__PURE__*/function (_View) {
379
394
  * @param {boolean} hydrate If true, the view will use existing html.
380
395
  * @return {Rasti.Component}
381
396
  */;
382
- Component.mount = function mount() {
383
- var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
384
- var el = arguments.length > 1 ? arguments[1] : undefined;
385
- var hydrate = arguments.length > 2 ? arguments[2] : undefined;
397
+ Component.mount = function mount(options, el, hydrate) {
386
398
  // Instantiate view.
387
399
  var view = new this(options);
388
400
  // If `el` is passed, mount component.
@@ -401,6 +413,7 @@ var Component = /*#__PURE__*/function (_View) {
401
413
  // Return view instance.
402
414
  return view;
403
415
  }
416
+
404
417
  /**
405
418
  * Takes a tagged template containing an HTML string,
406
419
  * and returns a new `Component` class.
@@ -434,7 +447,7 @@ var Component = /*#__PURE__*/function (_View) {
434
447
  // Create output text for main template.
435
448
  var main = parts.join('').trim().replace(/\n/g, '');
436
449
  // Extract outer tag, attributes and inner html.
437
- var result = main.match(/^<([a-z]+)(.*?)>(.*)<\/\1>$/) || main.match(/^<([a-z]+)(.*?)\/>$/);
450
+ var result = main.match(/^<([a-z]+[1-6]?)(.*?)>(.*)<\/\1>$/) || main.match(/^<([a-z]+)(.*?)\/>$/);
438
451
  // Parse attributes from html text into an object.
439
452
  var attributes = extractAttributes(result[2]);
440
453
  // Events to be delegated.
package/es/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/es/Model.js CHANGED
@@ -1,4 +1,3 @@
1
- function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
2
1
  function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf(subClass, superClass); }
3
2
  function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
4
3
  import Emitter from './Emitter.js';
@@ -6,10 +5,10 @@ import Emitter from './Emitter.js';
6
5
  * - Orchestrates data and business logic.
7
6
  * - Emits events when data changes.
8
7
  *
9
- * A `Model` manages an internal table of data attributes and triggers change events when any of its data is modified.<br />
8
+ * A `Model` manages an internal table of data attributes and triggers change events when any of its data is modified.
10
9
  * Models may handle syncing data with a persistence layer. To design your models, create atomic, reusable objects
11
- * that contain all the necessary functions for manipulating their specific data.<br />
12
- * Models should be easily passed throughout your app and used anywhere the corresponding data is needed.<br />
10
+ * that contain all the necessary functions for manipulating their specific data.
11
+ * Models should be easily passed throughout your app and used anywhere the corresponding data is needed.
13
12
  * Rasti models stores its attributes in `this.attributes`, which is extended from `this.defaults` and the
14
13
  * constructor `attrs` parameter. For every attribute, a getter is generated to retrieve the model property
15
14
  * from `this.attributes`, and a setter is created to set the model property in `this.attributes` and emit `change`
@@ -48,19 +47,18 @@ import Emitter from './Emitter.js';
48
47
  * product.setDiscount(10); // Output: "New Price: 900"
49
48
  */
50
49
  var Model = /*#__PURE__*/function (_Emitter) {
51
- _inheritsLoose(Model, _Emitter);
52
50
  function Model() {
53
51
  var _this;
54
52
  var attrs = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
55
53
  _this = _Emitter.call(this) || this;
56
54
  // Call preinitialize.
57
- _this.preinitialize.apply(_assertThisInitialized(_this), arguments);
55
+ _this.preinitialize.apply(_this, arguments);
58
56
  // attributes object.
59
57
  _this.attributes = Object.assign({}, _this.defaults || {}, attrs);
60
58
  // Previous attributes.
61
59
  _this.previous = {};
62
60
  // Generate getters/setters for every attr.
63
- Object.keys(_this.attributes).forEach(_this.defineAttribute.bind(_assertThisInitialized(_this)));
61
+ Object.keys(_this.attributes).forEach(_this.defineAttribute.bind(_this));
64
62
  return _this;
65
63
  }
66
64
 
@@ -68,6 +66,7 @@ var Model = /*#__PURE__*/function (_Emitter) {
68
66
  * 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.
69
67
  * @param {object} attrs Object containing model attributes to extend `this.attributes`.
70
68
  */
69
+ _inheritsLoose(Model, _Emitter);
71
70
  var _proto = Model.prototype;
72
71
  _proto.preinitialize = function preinitialize() {}
73
72
 
@@ -100,11 +99,13 @@ var Model = /*#__PURE__*/function (_Emitter) {
100
99
  }
101
100
 
102
101
  /**
103
- * Set an attribute into `this.attributes`.
104
- * Emit `change` and `change:attribute` if a value change.
102
+ * Set an attribute into `this.attributes`.
103
+ * Emit `change` and `change:attribute` if a value change.
105
104
  * Could be called in two forms, `this.set('key', value)` and
106
- * `this.set({ key : value })`.
107
- * This method is called internally by generated setters.
105
+ * `this.set({ key : value })`.
106
+ * This method is called internally by generated setters.
107
+ * 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.
108
+ * The `change:attribute` event listener will receive the model instance, the new attribute value, and the rest of the arguments passed to `set` method.
108
109
  * @param {string} key Attribute key or object containing keys/values.
109
110
  * @param [value] Attribute value.
110
111
  * @return {this} This model.
package/es/View.js CHANGED
@@ -1,4 +1,3 @@
1
- function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
2
1
  function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf(subClass, superClass); }
3
2
  function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
4
3
  import Emitter from './Emitter.js';
@@ -20,10 +19,10 @@ var viewOptions = {
20
19
  * - Sends captured input to the model.
21
20
  *
22
21
  * A `View` is an atomic unit of the user interface that can render the data from a specific model or multiple models.
23
- * However, views can also be independent and have no associated data.<br />
22
+ * However, views can also be independent and have no associated data.
24
23
  * Models must be unaware of views. Views, on the other hand, may render model data and listen to the change events
25
- * emitted by the models to re-render themselves based on changes.<br />
26
- * Each `View` has a root element, `this.el`, which is used for event delegation.<br />
24
+ * emitted by the models to re-render themselves based on changes.
25
+ * Each `View` has a root element, `this.el`, which is used for event delegation.
27
26
  * All element lookups are scoped to this element, and any rendering or DOM manipulations should be done inside it.
28
27
  * If `this.el` is not present, an element will be created using `this.tag` (defaulting to div) and `this.attributes`.
29
28
  * @module
@@ -57,13 +56,12 @@ var viewOptions = {
57
56
  * document.body.appendChild(new Timer().render().el);
58
57
  */
59
58
  var View = /*#__PURE__*/function (_Emitter) {
60
- _inheritsLoose(View, _Emitter);
61
59
  function View() {
62
60
  var _this;
63
61
  var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
64
62
  _this = _Emitter.call(this) || this;
65
63
  // Call preinitialize.
66
- _this.preinitialize.apply(_assertThisInitialized(_this), arguments);
64
+ _this.preinitialize.apply(_this, arguments);
67
65
  // Generate unique id.
68
66
  // Useful to generate elements ids.
69
67
  _this.uid = "uid" + ++View.uid;
@@ -86,6 +84,7 @@ var View = /*#__PURE__*/function (_Emitter) {
86
84
  * If you define a preinitialize method, it will be invoked when the view is first created, before any instantiation logic is run.
87
85
  * @param {object} attrs Object containing model attributes to extend `this.attributes`.
88
86
  */
87
+ _inheritsLoose(View, _Emitter);
89
88
  var _proto = View.prototype;
90
89
  _proto.preinitialize = function preinitialize() {}
91
90
 
@@ -112,6 +111,7 @@ var View = /*#__PURE__*/function (_Emitter) {
112
111
  /**
113
112
  * Destroy the view.
114
113
  * Destroy children views if any, undelegate events, stop listening to events, call `onDestroy` lifecycle method.
114
+ * @return {Rasti.View} Return `this` for chaining.
115
115
  */;
116
116
  _proto.destroy = function destroy() {
117
117
  // Call destroy on children.
@@ -189,18 +189,21 @@ var View = /*#__PURE__*/function (_Emitter) {
189
189
 
190
190
  /**
191
191
  * Remove `this.el` from DOM.
192
+ * @return {Rasti.View} Return `this` for chaining.
192
193
  */;
193
194
  _proto.removeElement = function removeElement() {
194
195
  this.el.parentNode.removeChild(this.el);
196
+ // Return `this` for chaining.
197
+ return this;
195
198
  }
196
199
 
197
200
  /**
198
- * Provide declarative listeners for DOM events within a view. If an events hash is not passed directly, uses `this.events` as the source.<br />
201
+ * Provide declarative listeners for DOM events within a view. If an events hash is not passed directly, uses `this.events` as the source.
199
202
  * 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.
200
- * Omitting the selector causes the event to be bound to the view's root element (`this.el`).<br />
203
+ * Omitting the selector causes the event to be bound to the view's root element (`this.el`).
201
204
  * By default, `delegateEvents` is called within the View's constructor,
202
- * 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 />
203
- * All attached listeners are bound to the view automatically, so when the listeners are invoked, `this` continues to refer to the view object.<br />
205
+ * 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.
206
+ * All attached listeners are bound to the view automatically, so when the listeners are invoked, `this` continues to refer to the view object.
204
207
  * When `delegateEvents` is run again, perhaps with a different events hash, all listeners are removed and delegated afresh.
205
208
  * @param {object} [events] Object in the format `{'event selector' : 'listener'}`. Used to bind delegated event listeners to root element.
206
209
  * @return {Rasti.View} Return `this` for chaining.