rasti 1.1.2 → 2.0.0-alpha.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/README.md CHANGED
@@ -1,13 +1,14 @@
1
1
  # <a href="http://rasti.js.org"><img src="docs/logo.svg" height="80" alt="Rasti" aria-label="rasti.js.org" /></a>
2
2
 
3
- Rasti is a minimalistic JavaScript MV library for building user interfaces.<br />
4
- It gives structure to applications by providing [models](docs/api.md#module_Model) that emit events on properties changes, and [views](docs/api.md#module_View) with declarative DOM events handling to define UI components.<br />
5
- Rasti is inspired by the Backbone.js architecture. It can be considered as an ES6 subset of Backbone.js for modern browsers.<br />
6
- It's ideal for building simple lightweight applications, without the need of configuration or boilerplate. Projects where a resulting small codebase is prioritized over using a complex rendering system.<br />
3
+
4
+ Rasti is a minimalistic, ultra-lightweight JavaScript library designed for efficient user interface development.<br />
5
+ Its goal is to help you create projects with a compact codebase, eliminating the need for boilerplate.<br />
6
+ While offering a low-level Model and View with a Backbone.js-like API, Rasti also introduces a higher-level Component class that enables a more composable and declarative approach to building UI components.<br />
7
+
7
8
  The project is [hosted on GitHub](https://github.com/8tentaculos/rasti), and it's available for use under the [MIT](LICENSE.md) software license.<br />
8
9
  You can report bugs and discuss features on the [GitHub issues page](https://github.com/8tentaculos/rasti/issues).
9
10
 
10
- [![build status](https://img.shields.io/travis/8tentaculos/rasti/master.svg?style=flat-square)](https://travis-ci.org/8tentaculos/rasti)
11
+ [![Build Status](https://app.travis-ci.com/8tentaculos/rasti.svg?branch=master)](https://app.travis-ci.com/8tentaculos/rasti)
11
12
  [![npm version](https://img.shields.io/npm/v/rasti.svg?style=flat-square)](https://www.npmjs.com/package/rasti)
12
13
  [![npm downloads](https://img.shields.io/npm/dm/rasti.svg?style=flat-square)](https://www.npmjs.com/package/rasti)
13
14
 
@@ -20,13 +21,13 @@ $ npm install --save rasti
20
21
  ```
21
22
 
22
23
  ```javascript
23
- import { Model, View } from 'rasti';
24
+ import { Model, Component } from 'rasti';
24
25
  ```
25
26
 
26
27
  #### Using native modules
27
28
 
28
29
  ```javascript
29
- import { Model, View } from 'https://unpkg.com/rasti/es';
30
+ import { Model, Component } from 'https://unpkg.com/rasti/es';
30
31
  ```
31
32
 
32
33
  #### Using `<script>` tag
@@ -36,32 +37,25 @@ import { Model, View } from 'https://unpkg.com/rasti/es';
36
37
  ```
37
38
 
38
39
  ```javascript
39
- const { Model, View } = Rasti;
40
+ const { Model, Component } = Rasti;
40
41
  ```
41
42
 
42
- #### A simple `View`
43
+ #### A simple `Component`
43
44
 
44
45
  ```javascript
45
- class Timer extends View {
46
- constructor(options) {
47
- super(options);
48
- // Create model to store internal state. Set `seconds` attribute into 0.
49
- this.model = new Model({ seconds : 0 });
50
- // Listen to changes in model `seconds` attribute and re render.
51
- this.model.on('change:seconds', this.render.bind(this));
52
- // Increment model `seconds` attribute every 1000 milliseconds.
53
- this.interval = setInterval(() => this.model.seconds++, 1000);
54
- }
55
-
56
- template(model) {
57
- return `Seconds: <span>${model.seconds}</span>`;
58
- }
59
- }
60
- // Render view and append view's element into body.
61
- document.body.appendChild(new Timer().render().el);
46
+ // Create Timer component.
47
+ const Timer = Component.create`
48
+ <div>Seconds: <span>${({ model }) => model.seconds}</span></div>
49
+ `;
50
+ // Create model to store seconds.
51
+ const model = new Model({ seconds: 0 });
52
+ // Mount timer on body.
53
+ Timer.mount({ model }, document.body);
54
+ // Increment `model.seconds` every second.
55
+ setInterval(() => model.seconds++, 1000);
62
56
  ```
63
57
 
64
- [Try it on CodePen](https://codepen.io/8tentaculos/pen/dyXgGMp?editors=0010)
58
+ [Try it on CodePen](https://codepen.io/8tentaculos/pen/gOQxaOE?editors=0010)
65
59
 
66
60
  The [rasti npm package](https://www.npmjs.com/package/rasti) includes precompiled production and development UMD builds in the dist folder. They can be used directly without a bundler and are thus compatible with many popular JavaScript module loaders and environments.<br />
67
61
  The UMD builds make Rasti available as a `window.Rasti` global variable.
package/dist/rasti.js CHANGED
@@ -20,13 +20,23 @@ return /******/ (() => { // webpackBootstrap
20
20
  /******/ "use strict";
21
21
  /******/ var __webpack_modules__ = ({
22
22
 
23
+ /***/ "./src/Component.js":
24
+ /*!**************************!*\
25
+ !*** ./src/Component.js ***!
26
+ \**************************/
27
+ /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
28
+
29
+ eval("\n\nexports.__esModule = true;\nexports[\"default\"] = void 0;\nvar _View2 = _interopRequireDefault(__webpack_require__(/*! ./View */ \"./src/View.js\"));\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { \"default\": obj }; }\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\nfunction _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf(subClass, superClass); }\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n// This options keys will be extended on view instance.\nvar componentOptions = {\n key: true,\n state: true,\n onCreate: true,\n onChange: true,\n onRender: true\n};\n\n/*\n * Helper function. Extract attributes from html tag\n * @param text {string} html text\n * @return {object} Object with keys / values representing attributes.\n */\nvar getAttributes = function getAttributes(text) {\n var attributes = {};\n var re = /([a-z]+)=?(\\S+)?/gi;\n var result;\n while ((result = re.exec(text)) !== null) {\n attributes[result[1]] = result[2] ? result[2].replace(/'|\"/g, '') : true;\n }\n return attributes;\n};\n\n/*\n * Helper function. If expression is a function, call it with context and args.\n */\nvar evalExpression = function evalExpression(expression, context) {\n for (var _len = arguments.length, args = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {\n args[_key - 2] = arguments[_key];\n }\n return typeof expression === 'function' ? expression.apply(context, args) : expression;\n};\n\n/**\n * Components are a special kind of `View` that is designed to be easily composable, \n * making it simple to add child views and build complex user interfaces.<br />\n * Unlike views, which are render-agnostic, components have a specific set of rendering \n * guidelines that allow for a more declarative development style.\n * @module\n * @param {object} options Object containing options. The following keys will be merged to `this`: model, state, key, onDestroy, onRender, onCreate, onChange.\n * @example\n * import { Component, Model } from 'rasti';\n * // Create Timer component.\n * const Timer = Component.create`\n * <div>Seconds: <span>${({ model }) => model.seconds}</span></div>\n * `;\n * // Create model to store seconds.\n * const model = new Model({ seconds: 0 });\n * // Mount timer on body.\n * Timer.mount({ model }, document.body);\n * // Increment `model.seconds` every second.\n * setInterval(() => model.seconds++, 1000);\n */\nvar Component = /*#__PURE__*/function (_View) {\n _inheritsLoose(Component, _View);\n function Component() {\n var _this;\n var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n _this = _View.call(this, options) || this;\n // Extend \"this\" with options, mapping componentOptions keys.\n Object.keys(options).forEach(function (key) {\n if (componentOptions[key]) _this[key] = options[key];\n });\n // Store options by default.\n _this.options = options;\n // Ensure id.\n _this.id = _this.attributes.id ?\n // If id is provided, evaluate it.\n evalExpression(_this.attributes.id, _assertThisInitialized(_this), _assertThisInitialized(_this)) : // Generate a unique id and set it as id attribute.\n \"rasti-component-\" + _this.uid;\n // Bind onChange to this to be used as listener.\n // Store bound version, so it can be removed on onDestroy method.\n _this.onChange = _this.onChange.bind(_assertThisInitialized(_this));\n // Listen to model changes and call onChange.\n if (_this.model) _this.model.on('change', _this.onChange);\n if (_this.state) _this.state.on('change', _this.onChange);\n // Call life cycle method.\n _this.onCreate.apply(_assertThisInitialized(_this), arguments);\n return _this;\n }\n\n /*\n * Override. We don't want to ensure an element on instantiation.\n * We will provide it later.\n */\n var _proto = Component.prototype;\n _proto.ensureElement = function ensureElement() {\n // If el is provided, delegate events.\n if (this.el) this.delegateEvents();\n };\n _proto.findElement = function findElement(parent) {\n return (parent || document).querySelector(\"#\" + this.id);\n }\n\n /*\n * Used internally on the render process. Attach the view to the dom element.\n */;\n _proto.hydrate = function hydrate(parent) {\n var _this2 = this;\n this.el = this.findElement(parent);\n this.delegateEvents();\n this.children.forEach(function (child) {\n return child.hydrate(_this2.el);\n });\n this.onRender.call(this);\n }\n\n /*\n * Override. Add some custom logic to super `destroy` method.\n */;\n _proto.destroy = function destroy(options) {\n _View.prototype.destroy.call(this, options);\n // Stop listening to `change`.\n // Set destroyed flag to prevent a last render after destroyed. TODO: Review\n if (this.model) this.model.off('change', this.onChange);\n if (this.state) this.state.off('change', this.onChange);\n this.destroyed = true;\n }\n\n /**\n * Lifecycle method. Called when the view is created at the end of the constructor.\n * @param options {object} The view options.\n */;\n _proto.onCreate = function onCreate() {}\n\n /**\n * Lifecycle method. Called when model emits `change` event.\n * By default calls render method.\n * This method should be extended with custom logic.\n * Maybe comparing new attributes with previous ones and calling\n * render when needed. Or doing some dom transformation.\n * @param model {Rasti.Model}\n * @param key {string}\n * @param value {any}\n */;\n _proto.onChange = function onChange() {\n this.render();\n }\n\n /**\n * Lifecycle method. Called when the view is rendered.\n */;\n _proto.onRender = function onRender() {}\n\n /**\n * Lifecycle method. Called when the view is destroyed.\n */;\n _proto.onDestroy = function onDestroy() {}\n\n /*\n * Replace expressions.\n */;\n _proto.replaceExpressions = function replaceExpressions(string, parseExpressionResult) {\n var _this3 = this;\n return string.replace(/{(\\d+)}/g, function (match) {\n // Get expression index.\n var idx = match.match(/{(\\d+)}/)[1];\n // Eval expression. Pass view as argument.\n var result = _this3.template.expressions[idx].call(_this3, _this3);\n // Treat all expressions as arrays.\n var results = result instanceof Array ? result : [result];\n // Replace expression with the result of the evaluation.\n return results.reduce(function (out, current) {\n // Concatenate expressions.\n out += parseExpressionResult(current);\n return out;\n }, '');\n })\n // Replace `attribute=\"true\"` with `attribute`\n .replace(/([a-z]+)=[\"|']true[\"|']/g, '$1')\n // Replace `attribute=\"false\"` with ``\n .replace(/([a-z]+)=[\"|']false[\"|']/g, '');\n }\n\n /*\n * Treat the whole view as a HTML string.\n */;\n _proto.toString = function toString() {\n var _this4 = this;\n // Normally there won't be any children, but if there are, destroy them.\n this.destroyChildren();\n // Add id to template including root element (this.el) as part of it.\n var tpl = this.attributes.id ? this.template.outer : this.template.outer.replace(/^<([a-z]+)/, \"<$1 id=\\\"\" + this.id + \"\\\"\");\n // Replace expressions.\n return this.replaceExpressions(tpl, function (result) {\n var out = result;\n // Return empty string if result is null or undefined.\n if (result === null || typeof result === 'undefined') out = '';\n // If result is a view, add it to children array.\n else if (result && typeof result.render === 'function') {\n // Add child component.\n _this4.addChild(result);\n }\n return out;\n });\n }\n\n /*\n * View render method.\n */;\n _proto.render = function render() {\n var _this5 = this;\n // Prevent a last re render if view is already destroyed.\n if (this.destroyed) return this;\n // If \"this.el\" is not present,\n // create a new element according \"this.tag\"\n // and \"this.attributes\".\n if (!this.el) {\n this.el = this.createElement(this.tag);\n this.delegateEvents();\n }\n // Set `this.el` attributes.\n Object.keys(this.attributes).forEach(function (key) {\n // Omit changing id.\n if (key === 'id') return;\n // Evaluate attribute value.\n var value = evalExpression(_this5.attributes[key], _this5, _this5);\n // Transform bool attribute values\n if (value === false) {\n // Remove false attributes.\n _this5.el.removeAttribute(key);\n } else {\n if (value === true) value = '';\n _this5.el.setAttribute(key, value);\n }\n });\n var previousChildren = this.children;\n this.children = [];\n var nextChildren = [];\n var recycledChildren = [];\n\n // Replace expressions.\n // Set html text inside `this.el`. Make it part of the dom.\n this.el.innerHTML = this.replaceExpressions(this.template.inner, function (result) {\n var out = result;\n // Return empty string if result is null or undefined.\n if (result === null || typeof result === 'undefined') out = '';\n\n // If result is a view, add it to children array.\n else if (result && typeof result.render === 'function') {\n var found = result.key && previousChildren.find(function (previousChild) {\n return previousChild.key === result.key;\n });\n if (found) {\n out = \"<\" + found.tag + \" id=\\\"\" + evalExpression(found.id, found, found) + \"\\\"></\" + found.tag + \">\";\n recycledChildren.push(found);\n result.destroy();\n } else {\n nextChildren.push(result);\n }\n }\n return out;\n });\n nextChildren.forEach(function (nextChild) {\n _this5.addChild(nextChild).hydrate(_this5.el);\n });\n recycledChildren.forEach(function (recycledChild) {\n _this5.el.replaceChild(_this5.addChild(recycledChild).el, recycledChild.findElement(_this5.el));\n });\n previousChildren.forEach(function (previousChild) {\n var found = recycledChildren.indexOf(previousChild) > -1;\n if (!found) previousChild.destroy();\n });\n\n // Call onRender lifecycle method.\n this.onRender.call(this);\n // Return this for chaining.\n return this;\n }\n\n /**\n * Helper method used to extend a `Component`, creating a subclass.\n * @static\n * @param {object} object Object containing methods to be added to the new `Component` subclass. Also can be a function that receives the parent prototype and returns an object.\n */;\n Component.extend = function extend(object) {\n var Current = this;\n var Extended = /*#__PURE__*/function (_Current) {\n _inheritsLoose(Extended, _Current);\n function Extended() {\n return _Current.apply(this, arguments) || this;\n }\n return Extended;\n }(Current);\n Object.assign(Extended.prototype, typeof object === 'function' ? object(Current.prototype) : object);\n return Extended;\n }\n\n /**\n * Mount the component into the dom.\n * It instantiate the Component view using options, \n * appends its element into the DOM (if `el` is provided).\n * And returns the view instance.\n * @static\n * @param {object} options The view options.\n * @param {node} el Dom element to append the view element.\n * @param {boolean} hydrate If true, the view will use existing html.\n * @return {Rasti.View}\n */;\n Component.mount = function mount() {\n var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n var el = arguments.length > 1 ? arguments[1] : undefined;\n var hydrate = arguments.length > 2 ? arguments[2] : undefined;\n // Instantiate view.\n var view = new this(options);\n\n // If `el` is passed, mount component.\n if (el) {\n if (hydrate) {\n view.toString();\n } else {\n var fragment = document.createElement('template');\n // Add html text into element inner html.\n fragment.innerHTML = view;\n // Add to dom.\n el.appendChild(fragment.content);\n }\n view.hydrate(el);\n }\n return view;\n }\n /**\n * Tagged template that receives an HTML string, \n * and returns a `Component`.\n * @static\n */;\n Component.create = function create(strings) {\n for (var _len2 = arguments.length, expressions = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {\n expressions[_key2 - 1] = arguments[_key2];\n }\n var parts = [];\n // Replace functions and objects interpolations with `{number}`.\n // Where `number` is the index on expressions array.\n strings.forEach(function (string, i) {\n // Add string part.\n parts.push(string);\n // Add expression placeholder for later or expression eval.\n if (expressions[i]) {\n parts.push(typeof expressions[i] === 'function' || typeof expressions[i] === 'object' ? \"{\" + i + \"}\" : expressions[i]);\n }\n });\n // Create output text for main template.\n var main = parts.join('').trim().replace(/\\n/g, '');\n // Extract outer tag, attributes and inner html.\n var result = main.match(/^<([a-z]+)(.*?)>(.*)<\\/\\1>$/);\n // Remove events listeners.\n var string = main.replace(/on([A-Z]{1}[a-z]+)+=[^>\\s]+/g, '');\n // Parse attributes from html text into an object.\n var attributes = getAttributes(result[2]);\n var events = {};\n // Filter events. Replace placeholders `{number}` with expressions.\n attributes = Object.keys(attributes).reduce(function (out, key) {\n var matchKey = key.match(/on(([A-Z]{1}[a-z]+)+)/); // Is Event?\n var matchValue = attributes[key].match(/{(\\d+)}/); // Is placeholder for function or object?\n // Get expression or value.\n var value = matchValue && matchValue[1] ? expressions[matchValue[1]] : attributes[key];\n // Is event handler.\n if (matchKey && matchKey[1]) {\n var eventType = matchKey[1].toLowerCase();\n Object.keys(value).forEach(function (selector) {\n return events[\"\" + eventType + (selector === '&' ? '' : \" \" + selector)] = value[selector];\n });\n return out;\n }\n // Is function expression.\n out[key] = value;\n return out;\n }, {});\n var Current = this;\n\n // Create subclass for this component.\n return Current.extend({\n // Set events.\n events: events,\n // Set attributes.\n attributes: attributes,\n // Set template data.\n template: {\n // Template including root element (this.el) as part of the template.\n outer: string,\n // Template for innerHTML of root element.\n inner: result[3],\n // Template expressions.\n expressions: expressions\n },\n // Set root element tag.\n tag: result[1]\n });\n };\n return Component;\n}(_View2[\"default\"]);\nexports[\"default\"] = Component;\n\n//# sourceURL=webpack://Rasti/./src/Component.js?");
30
+
31
+ /***/ }),
32
+
23
33
  /***/ "./src/Emitter.js":
24
34
  /*!************************!*\
25
35
  !*** ./src/Emitter.js ***!
26
36
  \************************/
27
37
  /***/ ((__unused_webpack_module, exports) => {
28
38
 
29
- eval("\n\nexports.__esModule = true;\nexports[\"default\"] = void 0;\n/**\n * Emitter is a class that can be extended giving the subclass the ability to emit \n * and bind custom named events. Model and View inherits from it.\n * @module\n * @example\n * import { Emitter } from 'rasti';\n * // Define App class, inherits from Emitter.\n * class App extends Emitter {\n * constructor() {\n * super()\n * // Fetch data and emit `ready` event.\n * fetch('/api/init').then(() => this.emit('ready')); \n * }\n * }\n * // Instantiate App.\n * const app = new App();\n * // Add event listener to ready event.\n * app.on('ready', () => console.log('app is ready!'));\n */\nvar Emitter = /*#__PURE__*/function () {\n function Emitter() {}\n var _proto = Emitter.prototype;\n /**\n * Adds event listener.\n * @param {string} type Type of the event (e.g. `change`).\n * @param {function} listener Callback function to be called when the event is emitted.\n * @example\n * this.model.on('change', this.render.bind(this)); // Re render when model changes.\n */\n _proto.on = function on(type, listener) {\n if (typeof listener !== 'function') {\n throw TypeError('Listener must be a function');\n }\n if (!this.listeners) this.listeners = {};\n if (!this.listeners[type]) this.listeners[type] = [];\n this.listeners[type].push(listener);\n }\n\n /**\n * Adds event listener that executes once.\n * @param {string} type Type of the event (e.g. `change`).\n * @param {function} listener Callback function to be called when the event is emitted.\n * @example\n * this.model.once('change', () => console.log('This will happen once'));\n */;\n _proto.once = function once(type, _listener2) {\n if (typeof _listener2 === 'function') {\n var self = this;\n var _listener = _listener2;\n _listener2 = function listener() {\n _listener.apply(void 0, arguments);\n self.off(type, _listener2);\n };\n }\n this.on(type, _listener2);\n }\n\n /**\n * Removes event listeners.\n * @param {string} [type] Type of the event (e.g. `change`). If is not provided, it removes all listeners.\n * @param {function} [listener] Callback function to be called when the event is emitted. If listener is not provided, it removes all listeners for specified type.\n * @example\n * this.model.off('change'); // Stop listening to changes.\n */;\n _proto.off = function off(type, listener) {\n if (!type) {\n this.listeners = {};\n } else {\n if (!listener) {\n delete this.listeners[type];\n } else {\n var listeners = this.listeners[type];\n if (listeners) {\n var copy = listeners.slice();\n copy.forEach(function (fn, idx) {\n if (fn === listener) listeners.splice(idx, 1);\n });\n if (!listeners.length) {\n delete this.listeners[type];\n }\n }\n }\n }\n }\n\n /**\n * Emits event of specified type. Listeners will receive specified arguments.\n * @param {string} type Type of the event (e.g. `change`).\n * @param {any} [...args] Arguments to be passed to listener.\n * @example\n * this.emit('invalid'); // Emit validation error event.\n */;\n _proto.emit = function emit(type) {\n for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {\n args[_key - 1] = arguments[_key];\n }\n var listeners = this.listeners && this.listeners[type];\n if (!listeners || !listeners.length) return;\n var copy = listeners.slice();\n copy.forEach(function (fn) {\n fn.apply(void 0, args);\n });\n };\n return Emitter;\n}();\nexports[\"default\"] = Emitter;\n\n//# sourceURL=webpack://Rasti/./src/Emitter.js?");
39
+ eval("\n\nexports.__esModule = true;\nexports[\"default\"] = void 0;\n/**\n * `Emitter` is a class that provides an easy way to implement the observer pattern \n * in your applications.<br />\n * It can be extended to create new classes that have the ability to emit and bind custom named events.<br /> \n * Emitter is used by `Model` and `View` classes, which inherit from it to implement \n * event-driven functionality.\n *\n * @module\n * @example\n * import { Emitter } from 'rasti';\n * // Custom cart\n * class ShoppingCart extends Emitter {\n * constructor() {\n * super();\n * this.items = [];\n * }\n *\n * addItem(item) {\n * this.items.push(item);\n * // Emit a custom event called `itemAdded`.\n * // Pass the added item as an argument to the event listener.\n * this.emit('itemAdded', item);\n * }\n * }\n * // Create an instance of ShoppingCart and Logger\n * const cart = new ShoppingCart();\n * // Listen to the `itemAdded` event and log the added item using the logger.\n * cart.on('itemAdded', (item) => {\n * console.log(`Item added to cart: ${item.name} - Price: $${item.price}`);\n * });\n * // Simulate adding items to the cart\n * const item1 = { name : 'Smartphone', price : 1000 };\n * const item2 = { name : 'Headphones', price : 150 };\n *\n * cart.addItem(item1); // Output: \"Item added to cart: Smartphone - Price: $1000\"\n * cart.addItem(item2); // Output: \"Item added to cart: Headphones - Price: $150\"\n */\nvar Emitter = /*#__PURE__*/function () {\n function Emitter() {}\n var _proto = Emitter.prototype;\n /**\n * Adds event listener.\n * @param {string} type Type of the event (e.g. `change`).\n * @param {function} listener Callback function to be called when the event is emitted.\n * @example\n * this.model.on('change', this.render.bind(this)); // Re render when model changes.\n */\n _proto.on = function on(type, listener) {\n if (typeof listener !== 'function') {\n throw TypeError('Listener must be a function');\n }\n if (!this.listeners) this.listeners = {};\n if (!this.listeners[type]) this.listeners[type] = [];\n this.listeners[type].push(listener);\n }\n\n /**\n * Adds event listener that executes once.\n * @param {string} type Type of the event (e.g. `change`).\n * @param {function} listener Callback function to be called when the event is emitted.\n * @example\n * this.model.once('change', () => console.log('This will happen once'));\n */;\n _proto.once = function once(type, _listener2) {\n if (typeof _listener2 === 'function') {\n var self = this;\n var _listener = _listener2;\n _listener2 = function listener() {\n _listener.apply(void 0, arguments);\n self.off(type, _listener2);\n };\n }\n this.on(type, _listener2);\n }\n\n /**\n * Removes event listeners.\n * @param {string} [type] Type of the event (e.g. `change`). If is not provided, it removes all listeners.\n * @param {function} [listener] Callback function to be called when the event is emitted. If listener is not provided, it removes all listeners for specified type.\n * @example\n * this.model.off('change'); // Stop listening to changes.\n */;\n _proto.off = function off(type, listener) {\n if (!type) {\n this.listeners = {};\n } else {\n if (!listener) {\n delete this.listeners[type];\n } else {\n var listeners = this.listeners[type];\n if (listeners) {\n var copy = listeners.slice();\n copy.forEach(function (fn, idx) {\n if (fn === listener) listeners.splice(idx, 1);\n });\n if (!listeners.length) {\n delete this.listeners[type];\n }\n }\n }\n }\n }\n\n /**\n * Emits event of specified type. Listeners will receive specified arguments.\n * @param {string} type Type of the event (e.g. `change`).\n * @param {any} [...args] Arguments to be passed to listener.\n * @example\n * this.emit('invalid'); // Emit validation error event.\n */;\n _proto.emit = function emit(type) {\n for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {\n args[_key - 1] = arguments[_key];\n }\n var listeners = this.listeners && this.listeners[type];\n if (!listeners || !listeners.length) return;\n var copy = listeners.slice();\n copy.forEach(function (fn) {\n fn.apply(void 0, args);\n });\n };\n return Emitter;\n}();\nexports[\"default\"] = Emitter;\n\n//# sourceURL=webpack://Rasti/./src/Emitter.js?");
30
40
 
31
41
  /***/ }),
32
42
 
@@ -36,7 +46,7 @@ eval("\n\nexports.__esModule = true;\nexports[\"default\"] = void 0;\n/**\n * Em
36
46
  \**********************/
37
47
  /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
38
48
 
39
- eval("\n\nexports.__esModule = true;\nexports[\"default\"] = void 0;\nvar _Emitter2 = _interopRequireDefault(__webpack_require__(/*! ./Emitter */ \"./src/Emitter.js\"));\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { \"default\": obj }; }\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\nfunction _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf(subClass, superClass); }\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n/**\n * - Orchestrates data and business logic.\n * - Emits events when data changes.\n * \n * A Model manages an internal table of data attributes, and triggers \"change\" events \n * when any of its data is modified.<br />\n * Models may handle syncing data with a persistence layer.<br />\n * Design your models as the atomic reusable objects containing all of the helpful functions for \n * manipulating their particular bit of data.<br /> \n * Models should be able to be passed around throughout your app, and used anywhere that bit of data is needed.<br />\n * Rasti Models stores its attributes in `this.attributes`, which is extended from `this.defaults` and constructor `attrs` parameter.\n * For every attribute, a getter is generated, which retrieve the model property from `this.attributes`.\n * And a setter, which sets the model property in `this.attributes` and emits `change` and `change:attribute` events.\n * @module\n * @param {object} attrs Object containing model attributes to extend `this.attributes`. Getters and setters are generated for `this.attributtes`, in order to emit `change` events.\n * @example\n * // Todo model\n * class TodoModel extends Rasti.Model {\n * toggle() {\n * // Set completed property. This will call a setter that will set `completed` \n * // in this.attributes, and emit `change` and `change:completed` events.\n * this.completed = !this.completed; \n * }\n * }\n * // Todo model has `title` and `completed` default attributes. `defaults` will extend `this.attributes`. Getters and setters are generated for `this.attributtes`, in order to emit `change` events.\n * TodoModel.prototype.defaults = {\n * title : '',\n * completed : false\n * };\n * // Create todo. Pass `title` attribute as argument.\n * const todo = new TodoModel({ title : 'Learn Rasti' });\n * // Listen to `change:completed` event.\n * todo.on('change:completed', () => console.log('Completed:', todo.completed));\n * // Complete todo.\n * todo.toggle(); // Completed: true\n */\nvar Model = /*#__PURE__*/function (_Emitter) {\n _inheritsLoose(Model, _Emitter);\n function Model() {\n var _this;\n var attrs = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n _this = _Emitter.call(this) || this;\n // Call preinitialize.\n _this.preinitialize.apply(_assertThisInitialized(_this), arguments);\n // attributes object.\n _this.attributes = Object.assign({}, _this.defaults || {}, attrs);\n // Previous attributes.\n _this.previous = {};\n // Generate getters/setters for every attr.\n Object.keys(_this.attributes).forEach(_this.defineAttribute.bind(_assertThisInitialized(_this)));\n return _this;\n }\n\n /**\n * 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.\n * @param {object} attrs Object containing model attributes to extend `this.attributes`.\n */\n var _proto = Model.prototype;\n _proto.preinitialize = function preinitialize() {}\n\n /**\n * Generate getter/setter for the given key. In order to emit `change` events.\n * This method is called internally by the constructor\n * for `this.attributes`.\n * @param {string} key Attribute key.\n */;\n _proto.defineAttribute = function defineAttribute(key) {\n var _this2 = this;\n Object.defineProperty(this, key, {\n get: function get() {\n return _this2.get(key);\n },\n set: function set(value) {\n _this2.set(key, value);\n }\n });\n }\n\n /**\n * Get an attribute from `this.attributes`.\n * This method is called internally by generated getters.\n * @param {string} key Attribute key.\n * @return {any} The attribute value.\n */;\n _proto.get = function get(key) {\n return this.attributes[key];\n }\n\n /**\n * Set an attribute into `this.attributes`.\n * Emit `change` and `change:attribute` if value change.\n * Could be called in two forms, `this.set('key', value)` and\n * `this.set({ key : value })`.\n * This method is called internally by generated setters.\n * @param {string} key Attribute key or object containing keys/values.\n * @param [value] Attribute value.\n * @return {this} This model.\n * @emits change\n * @emits change:attribute\n */;\n _proto.set = function set(key, value) {\n var _ref,\n _this3 = this;\n var attrs = typeof key === 'object' ? key : (_ref = {}, _ref[key] = value, _ref);\n Object.keys(attrs).forEach(function (key) {\n var changed = key in _this3.attributes && attrs[key] !== _this3.attributes[key];\n _this3.previous[key] = _this3.attributes[key];\n _this3.attributes[key] = attrs[key];\n // Emit change events.\n if (changed) {\n _this3.emit('change', _this3, key, attrs[key]);\n _this3.emit(\"change:\" + key, _this3, attrs[key]);\n }\n });\n return this;\n }\n\n /**\n * Return object representation of the model to be used for JSON serialization.\n * By default returns `this.attributes`.\n * @return {object} Object representation of the model to be used for JSON serialization.\n */;\n _proto.toJSON = function toJSON() {\n return this.attributes;\n };\n return Model;\n}(_Emitter2[\"default\"]);\nexports[\"default\"] = Model;\n\n//# sourceURL=webpack://Rasti/./src/Model.js?");
49
+ eval("\n\nexports.__esModule = true;\nexports[\"default\"] = void 0;\nvar _Emitter2 = _interopRequireDefault(__webpack_require__(/*! ./Emitter */ \"./src/Emitter.js\"));\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { \"default\": obj }; }\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\nfunction _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf(subClass, superClass); }\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n/**\n * - Orchestrates data and business logic.\n * - Emits events when data changes.\n * \n * A `Model` manages an internal table of data attributes and triggers change events when any of its data is modified.<br />\n * Models may handle syncing data with a persistence layer. To design your models, create atomic, reusable objects \n * that contain all the necessary functions for manipulating their specific data.<br />\n * Models should be easily passed throughout your app and used anywhere the corresponding data is needed.<br />\n * Rasti models stores its attributes in `this.attributes`, which is extended from `this.defaults` and the \n * constructor `attrs` parameter. For every attribute, a getter is generated to retrieve the model property \n * from `this.attributes`, and a setter is created to set the model property in `this.attributes` and emit `change` \n * and `change:attribute` events.\n * @module\n * @param {object} attrs Object containing model attributes to extend `this.attributes`. Getters and setters are generated for `this.attributtes`, in order to emit `change` events.\n * @example\n * import { Model } from 'rasti';\n * // Product model\n * class ProductModel extends Model {\n * preinitialize() {\n * // The Product model has `name` and `price` default attributes.\n * // `defaults` will extend `this.attributes`.\n * // Getters and setters are generated for `this.attributes`,\n * // in order to emit `change` events.\n * this.defaults = {\n * name: '',\n * price: 0\n * };\n * }\n *\n * setDiscount(discountPercentage) {\n * // Apply a discount to the price property.\n * // This will call a setter that will update `price` in `this.attributes`,\n * // and emit `change` and `change:price` events.\n * const discount = this.price * (discountPercentage / 100);\n * this.price -= discount;\n * }\n * }\n * // Create a product instance with a name and price.\n * const product = new ProductModel({ name: 'Smartphone', price: 1000 });\n * // Listen to the `change:price` event.\n * product.on('change:price', () => console.log('New Price:', product.price));\n * // Apply a 10% discount to the product.\n * product.setDiscount(10); // Output: \"New Price: 900\"\n */\nvar Model = /*#__PURE__*/function (_Emitter) {\n _inheritsLoose(Model, _Emitter);\n function Model() {\n var _this;\n var attrs = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n _this = _Emitter.call(this) || this;\n // Call preinitialize.\n _this.preinitialize.apply(_assertThisInitialized(_this), arguments);\n // attributes object.\n _this.attributes = Object.assign({}, _this.defaults || {}, attrs);\n // Previous attributes.\n _this.previous = {};\n // Generate getters/setters for every attr.\n Object.keys(_this.attributes).forEach(_this.defineAttribute.bind(_assertThisInitialized(_this)));\n return _this;\n }\n\n /**\n * 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.\n * @param {object} attrs Object containing model attributes to extend `this.attributes`.\n */\n var _proto = Model.prototype;\n _proto.preinitialize = function preinitialize() {}\n\n /**\n * Generate getter/setter for the given key. In order to emit `change` events.\n * This method is called internally by the constructor\n * for `this.attributes`.\n * @param {string} key Attribute key.\n */;\n _proto.defineAttribute = function defineAttribute(key) {\n var _this2 = this;\n Object.defineProperty(this, key, {\n get: function get() {\n return _this2.get(key);\n },\n set: function set(value) {\n _this2.set(key, value);\n }\n });\n }\n\n /**\n * Get an attribute from `this.attributes`.\n * This method is called internally by generated getters.\n * @param {string} key Attribute key.\n * @return {any} The attribute value.\n */;\n _proto.get = function get(key) {\n return this.attributes[key];\n }\n\n /**\n * Set an attribute into `this.attributes`.\n * Emit `change` and `change:attribute` if value change.\n * Could be called in two forms, `this.set('key', value)` and\n * `this.set({ key : value })`.\n * This method is called internally by generated setters.\n * @param {string} key Attribute key or object containing keys/values.\n * @param [value] Attribute value.\n * @return {this} This model.\n * @emits change\n * @emits change:attribute\n */;\n _proto.set = function set(key, value) {\n var _ref,\n _this3 = this;\n var attrs = typeof key === 'object' ? key : (_ref = {}, _ref[key] = value, _ref);\n Object.keys(attrs).forEach(function (key) {\n var changed = key in _this3.attributes && attrs[key] !== _this3.attributes[key];\n _this3.previous[key] = _this3.attributes[key];\n _this3.attributes[key] = attrs[key];\n // Emit change events.\n if (changed) {\n _this3.emit('change', _this3, key, attrs[key]);\n _this3.emit(\"change:\" + key, _this3, attrs[key]);\n }\n });\n return this;\n }\n\n /**\n * Return object representation of the model to be used for JSON serialization.\n * By default returns `this.attributes`.\n * @return {object} Object representation of the model to be used for JSON serialization.\n */;\n _proto.toJSON = function toJSON() {\n return this.attributes;\n };\n return Model;\n}(_Emitter2[\"default\"]);\nexports[\"default\"] = Model;\n\n//# sourceURL=webpack://Rasti/./src/Model.js?");
40
50
 
41
51
  /***/ }),
42
52
 
@@ -46,7 +56,7 @@ eval("\n\nexports.__esModule = true;\nexports[\"default\"] = void 0;\nvar _Emitt
46
56
  \*********************/
47
57
  /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
48
58
 
49
- eval("\n\nexports.__esModule = true;\nexports[\"default\"] = void 0;\nvar _Emitter2 = _interopRequireDefault(__webpack_require__(/*! ./Emitter */ \"./src/Emitter.js\"));\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { \"default\": obj }; }\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\nfunction _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf(subClass, superClass); }\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n// This options keys will be extended on view instance.\nvar viewOptions = {\n el: true,\n tag: true,\n attributes: true,\n events: true,\n model: true,\n template: true,\n onDestroy: true\n};\n\n/**\n * - Listens for changes and renders UI.\n * - Handles user input and interactivity.\n * - Sends captured input to the model.\n *\n * A View is an atomic chunk of user interface. It often renders the data from a specific model, \n * or number of models, but views can also be data-less chunks of UI that stand alone.<br /> \n * Models must be unaware of views. Instead, views listen to the model \"change\" events, \n * and react or re-render themselves appropriately.<br />\n * Views has a root element, `this.el`. That element is used for event delegation. Elements lookups are scoped to that element. And render and dom manipulations should be done inside that element. \n * If `this.el` is not present, an element will be created using `this.tag` (or `div` as default), and `this.attributes`.<br />\n * @module\n * @param {object} options Object containing options. The following keys will be merged to `this`: el, tag, attributes, events, model, template, onDestroy.\n * @property {node} el Every view has a root element, `this.el`. If not present it will be created.\n * @property {string} tag If `this.el` is not present, an element will be created using `this.tag`. Default is `div`.\n * @property {object} attributes If `this.el` is not present, an element will be created using `this.attributes`.\n * @property {object} events Object in the format `{'event selector' : 'listener'}`. Used to bind delegated event listeners to root element.\n * @property {object} model A `Rasti.Model` or any object containing data and business logic.\n * @property {function} template A function that receives data and returns a markup string (html for example).\n * @example\n * // Counter view.\n * class CounterView extends View {\n * constructor(options) {\n * super(options);\n * // Bind method to `this`, to be called as listener.\n * this.render = this.render.bind(this);\n * // Listen to model change and re render.\n * this.model.on('change:count', this.render);\n * }\n * onDestroy() {\n * // Unbind events when destroyed.\n * this.model.off('change:count', this.render);\n * }\n * // Listener method. Called when button is clicked.\n * onClickIncrement() {\n * // Increment count on model.\n * this.model.count++;\n * }\n * }\n * Object.assign(CounterView.prototype, {\n * // Set delegated events.\n * // Call `onClickIncrement` when button is clicked.\n * events : {\n * 'click button' : 'onClickIncrement'\n * },\n * // View's template.\n * template : (model) => `\n * <div>The count is: ${model.count}</div>\n * <button>Increment</button>\n * `\n * });\n * // Model.\n * const model = new Model({ count : 0 });\n * // Instantiate CounterView.\n * const counterView = new CounterView({ model });\n * // Add to DOM.\n * document.body.appendChild(counterView.render().el);\n */\nvar View = /*#__PURE__*/function (_Emitter) {\n _inheritsLoose(View, _Emitter);\n function View() {\n var _this;\n var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n _this = _Emitter.call(this) || this;\n // Call preinitialize.\n _this.preinitialize.apply(_assertThisInitialized(_this), arguments);\n // Generate unique id.\n // Useful to generate elements ids.\n _this.uid = \"uid\" + ++View.uid;\n // Store delegated events listeners,\n // so they can be unbinded later.\n _this.delegatedEventListeners = [];\n // Store child views,\n // so they can be destroyed.\n _this.children = [];\n // Extend \"this\" with options, mapping viewOptions keys.\n Object.keys(options).forEach(function (key) {\n if (viewOptions[key]) _this[key] = options[key];\n });\n // Ensure that the view has a root element at `this.el`.\n _this.ensureElement();\n return _this;\n }\n\n /**\n * If you define a preinitialize method, it will be invoked when the view is first created, before any instantiation logic is run.\n * @param {object} attrs Object containing model attributes to extend `this.attributes`.\n */\n var _proto = View.prototype;\n _proto.preinitialize = function preinitialize() {}\n\n /**\n * Returns the first element that match the selector, \n * scoped to DOM elements within the current view's root element (`this.el`).\n * @param {string} selector CSS selector.\n * @return {node} Element matching selector within the view's root element (`this.el`).\n */;\n _proto.$ = function $(selector) {\n return this.el.querySelector(selector);\n }\n\n /**\n * Returns a list of elements that match the selector, \n * scoped to DOM elements within the current view's root element (`this.el`).\n * @param {string} selector CSS selector.\n * @return {node[]} List of elements matching selector within the view's root element (`this.el`).\n */;\n _proto.$$ = function $$(selector) {\n return this.el.querySelectorAll(selector);\n }\n\n /**\n * Destroy the view.\n * Destroy children views if any, undelegate events, stop listening to events, call `onDestroy` lifecycle method.\n * Pass options.remove as true to remove the view's root element (`this.el`) from the DOM.\n * @param {object} options.remove Remove the view's root element (`this.el`) from the DOM.\n */;\n _proto.destroy = function destroy() {\n var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n remove = _ref.remove;\n // Call destroy on children.\n this.destroyChildren();\n // Undelegate `this.el` event listeners\n this.undelegateEvents();\n // Unbind `this` events.\n this.off();\n // Remove `this.el` if \"options.remove\" is true.\n if (remove) this.removeElement();\n // Call onDestroy lifecycle method\n this.onDestroy();\n }\n\n /**\n * `onDestroy` lifecycle method is called after view is destroyed.\n * Override with your code. Useful to stop listening to model's events.\n */;\n _proto.onDestroy = function onDestroy() {}\n\n /**\n * Add a view as a child.\n * Children views are stored at `this.children`, and destroyed when the parent is destroyed.\n * Returns the child for chaining.\n * @param {Rasti.View} child\n * @return {Rasti.View}\n */;\n _proto.addChild = function addChild(child) {\n this.children.push(child);\n return child;\n }\n\n /**\n * Call destroy method on children views.\n */;\n _proto.destroyChildren = function destroyChildren() {\n while (this.children.length) this.children.shift().destroy();\n }\n\n /**\n * Ensure that the view has a root element at `this.el`.\n * You shouldn't call this method directly. It's called from constructor.\n * You may override it if you want to use a different logic or to \n * postpone element creation.\n */;\n _proto.ensureElement = function ensureElement() {\n // If \"this.el\" is not present,\n // create a new element according \"this.tag\"\n // and \"this.attributes\".\n if (!this.el) this.el = this.createElement(this.tag, this.attributes);\n // Delegate events on element.\n this.delegateEvents();\n }\n\n /**\n * Create an element.\n * Called from constructor if `this.el` is undefined, to ensure\n * the view to have a root element.\n * @param {string} tag Tag for the element. Default to `div`\n * @param {object} attrs Attributes for the element.\n * @return {node} The created element.\n */;\n _proto.createElement = function createElement() {\n var tag = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'div';\n var attrs = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n // Create dom element.\n var el = document.createElement(tag);\n // Add element attributes.\n Object.keys(attrs).forEach(function (key) {\n return el.setAttribute(key, attrs[key]);\n });\n return el;\n }\n\n /**\n * Remove `this.el` from DOM.\n */;\n _proto.removeElement = function removeElement() {\n this.el.parentNode.removeChild(this.el);\n }\n\n /**\n * Provide declarative listeners for DOM events within a view. If an events hash is not passed directly, uses `this.events` as the source.<br />\n * 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.\n * Omitting the selector causes the event to be bound to the view's root element (`this.el`).<br />\n * By default, `delegateEvents` is called within the View's constructor, \n * 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 />\n * All attached listeners are bound to the view automatically, so when the listeners are invoked, `this` continues to refer to the view object.<br />\n * When `delegateEvents` is run again, perhaps with a different events hash, all listeners are removed and delegated afresh.\n * @param {object} [events] Object in the format `{'event selector' : 'listener'}`. Used to bind delegated event listeners to root element.\n * @return {Rasti.View} Return `this` for chaining.\n * @example\n * MyView.prototype.events = {\n * 'click button.ok' : 'onClickOkButton',\n * 'click button.cancel' : function() {}\n * };\n */;\n _proto.delegateEvents = function delegateEvents() {\n var _this2 = this;\n var events = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.events;\n if (!events) return this;\n if (this.delegatedEventListeners.length) this.undelegateEvents();\n\n // Store events by type i.e.: \"click\", \"submit\", etc.\n var eventTypes = {};\n Object.keys(events).forEach(function (key) {\n var keyParts = key.split(' '),\n type = keyParts.shift(),\n selector = keyParts.join(' '),\n listener = events[key];\n listener = (typeof listener === 'string' ? _this2[listener] : listener).bind(_this2);\n if (!eventTypes[type]) eventTypes[type] = [];\n eventTypes[type].push({\n selector: selector,\n listener: listener\n });\n });\n var indexOf = Array.prototype.indexOf;\n Object.keys(eventTypes).forEach(function (type) {\n var self = _this2;\n var typeListener = function typeListener(event) {\n eventTypes[type].forEach(function (_ref2) {\n var selector = _ref2.selector,\n listener = _ref2.listener;\n if (indexOf.call(selector ? self.el.querySelectorAll(selector) : [self.el], event.target) > -1) {\n listener(event, self);\n }\n });\n };\n _this2.delegatedEventListeners.push({\n type: type,\n listener: typeListener\n });\n _this2.el.addEventListener(type, typeListener);\n });\n return this;\n }\n\n /**\n * Removes all of the view's delegated events. Useful if you want to disable or remove a view from the DOM temporarily. Called automatically when the view is destroyed.\n * @return {Rasti.View} Return `this` for chaining.\n */;\n _proto.undelegateEvents = function undelegateEvents() {\n var _this3 = this;\n this.delegatedEventListeners.forEach(function (_ref3) {\n var type = _ref3.type,\n listener = _ref3.listener;\n _this3.el.removeEventListener(type, listener);\n });\n this.delegatedEventListeners = [];\n return this;\n }\n\n /**\n * Render the view.\n * This method should be overridden with custom logic.\n * The default implementation sets innerHTML of `this.el` with `this.template`.\n * Conventions are to only manipulate the dom in the scope of `this.el`, \n * and to return `this` for chaining.\n * If you added any child view, you must call `this.destroyChildren`.\n * @return {Rasti.View} Return `this` for chaining.\n */;\n _proto.render = function render() {\n if (this.template) this.el.innerHTML = this.template(this.model);\n return this;\n };\n return View;\n}(_Emitter2[\"default\"]);\n/*\n * Unique Id\n */\nexports[\"default\"] = View;\nView.uid = 0;\n\n//# sourceURL=webpack://Rasti/./src/View.js?");
59
+ eval("\n\nexports.__esModule = true;\nexports[\"default\"] = void 0;\nvar _Emitter2 = _interopRequireDefault(__webpack_require__(/*! ./Emitter */ \"./src/Emitter.js\"));\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { \"default\": obj }; }\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\nfunction _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf(subClass, superClass); }\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n// This options keys will be extended on view instance.\nvar viewOptions = {\n el: true,\n tag: true,\n attributes: true,\n events: true,\n model: true,\n template: true,\n onDestroy: true\n};\n\n/**\n * - Listens for changes and renders UI.\n * - Handles user input and interactivity.\n * - Sends captured input to the model.\n *\n * A `View` is an atomic unit of the user interface that can render the data from a specific model or multiple models.\n * However, views can also be independent and have no associated data.<br />\n * Models must be unaware of views. Views, on the other hand, may render model data and listen to the change events \n * emitted by the models to re-render themselves based on changes.<br />\n * Each `View` has a root element, `this.el`, which is used for event delegation.<br />\n * All element lookups are scoped to this element, and any rendering or DOM manipulations should be done inside it. \n * If `this.el` is not present, an element will be created using `this.tag` (defaulting to div) and `this.attributes`.\n * @module\n * @param {object} options Object containing options. The following keys will be merged to `this`: el, tag, attributes, events, model, template, onDestroy.\n * @property {node} el Every view has a root element, `this.el`. If not present it will be created.\n * @property {string} tag If `this.el` is not present, an element will be created using `this.tag`. Default is `div`.\n * @property {object} attributes If `this.el` is not present, an element will be created using `this.attributes`.\n * @property {object} events Object in the format `{'event selector' : 'listener'}`. Used to bind delegated event listeners to root element.\n * @property {object} model A `Rasti.Model` or any object containing data and business logic.\n * @property {function} template A function that receives data and returns a markup string (html for example).\n * @example\n * import { View } from 'rasti';\n * \n * class Timer extends View {\n * constructor(options) {\n * super(options);\n * // Create model to store internal state. Set `seconds` attribute into 0.\n * this.model = new Model({ seconds : 0 });\n * // Listen to changes in model `seconds` attribute and re render.\n * this.model.on('change:seconds', this.render.bind(this));\n * // Increment model `seconds` attribute every 1000 milliseconds.\n * this.interval = setInterval(() => this.model.seconds++, 1000);\n * }\n *\n * template(model) {\n * return `Seconds: <span>${model.seconds}</span>`;\n * }\n * }\n * // Render view and append view's element into body.\n * document.body.appendChild(new Timer().render().el);\n */\nvar View = /*#__PURE__*/function (_Emitter) {\n _inheritsLoose(View, _Emitter);\n function View() {\n var _this;\n var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n _this = _Emitter.call(this) || this;\n // Call preinitialize.\n _this.preinitialize.apply(_assertThisInitialized(_this), arguments);\n // Generate unique id.\n // Useful to generate elements ids.\n _this.uid = \"uid\" + ++View.uid;\n // Store delegated events listeners,\n // so they can be unbinded later.\n _this.delegatedEventListeners = [];\n // Store child views,\n // so they can be destroyed.\n _this.children = [];\n // Extend \"this\" with options, mapping viewOptions keys.\n Object.keys(options).forEach(function (key) {\n if (viewOptions[key]) _this[key] = options[key];\n });\n // Ensure that the view has a root element at `this.el`.\n _this.ensureElement();\n return _this;\n }\n\n /**\n * If you define a preinitialize method, it will be invoked when the view is first created, before any instantiation logic is run.\n * @param {object} attrs Object containing model attributes to extend `this.attributes`.\n */\n var _proto = View.prototype;\n _proto.preinitialize = function preinitialize() {}\n\n /**\n * Returns the first element that match the selector, \n * scoped to DOM elements within the current view's root element (`this.el`).\n * @param {string} selector CSS selector.\n * @return {node} Element matching selector within the view's root element (`this.el`).\n */;\n _proto.$ = function $(selector) {\n return this.el.querySelector(selector);\n }\n\n /**\n * Returns a list of elements that match the selector, \n * scoped to DOM elements within the current view's root element (`this.el`).\n * @param {string} selector CSS selector.\n * @return {node[]} List of elements matching selector within the view's root element (`this.el`).\n */;\n _proto.$$ = function $$(selector) {\n return this.el.querySelectorAll(selector);\n }\n\n /**\n * Destroy the view.\n * Destroy children views if any, undelegate events, stop listening to events, call `onDestroy` lifecycle method.\n * Pass options.remove as true to remove the view's root element (`this.el`) from the DOM.\n * @param {object} options.remove Remove the view's root element (`this.el`) from the DOM.\n */;\n _proto.destroy = function destroy() {\n var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n remove = _ref.remove;\n // Call destroy on children.\n this.destroyChildren();\n // Undelegate `this.el` event listeners\n this.undelegateEvents();\n // Unbind `this` events.\n this.off();\n // Remove `this.el` if \"options.remove\" is true.\n if (remove) this.removeElement();\n // Call onDestroy lifecycle method\n this.onDestroy.apply(this, arguments);\n }\n\n /**\n * `onDestroy` lifecycle method is called after view is destroyed.\n * Override with your code. Useful to stop listening to model's events.\n */;\n _proto.onDestroy = function onDestroy() {}\n\n /**\n * Add a view as a child.\n * Children views are stored at `this.children`, and destroyed when the parent is destroyed.\n * Returns the child for chaining.\n * @param {Rasti.View} child\n * @return {Rasti.View}\n */;\n _proto.addChild = function addChild(child) {\n this.children.push(child);\n return child;\n }\n\n /**\n * Call destroy method on children views.\n */;\n _proto.destroyChildren = function destroyChildren() {\n while (this.children.length) this.children.shift().destroy();\n }\n\n /**\n * Ensure that the view has a root element at `this.el`.\n * You shouldn't call this method directly. It's called from constructor.\n * You may override it if you want to use a different logic or to \n * postpone element creation.\n */;\n _proto.ensureElement = function ensureElement() {\n // If \"this.el\" is not present,\n // create a new element according \"this.tag\"\n // and \"this.attributes\".\n if (!this.el) this.el = this.createElement(this.tag, this.attributes);\n // Delegate events on element.\n this.delegateEvents();\n }\n\n /**\n * Create an element.\n * Called from constructor if `this.el` is undefined, to ensure\n * the view to have a root element.\n * @param {string} tag Tag for the element. Default to `div`\n * @param {object} attrs Attributes for the element.\n * @return {node} The created element.\n */;\n _proto.createElement = function createElement() {\n var tag = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'div';\n var attrs = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n // Create dom element.\n var el = document.createElement(tag);\n // Add element attributes.\n Object.keys(attrs).forEach(function (key) {\n return el.setAttribute(key, attrs[key]);\n });\n return el;\n }\n\n /**\n * Remove `this.el` from DOM.\n */;\n _proto.removeElement = function removeElement() {\n this.el.parentNode.removeChild(this.el);\n }\n\n /**\n * Provide declarative listeners for DOM events within a view. If an events hash is not passed directly, uses `this.events` as the source.<br />\n * 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.\n * Omitting the selector causes the event to be bound to the view's root element (`this.el`).<br />\n * By default, `delegateEvents` is called within the View's constructor, \n * 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 />\n * All attached listeners are bound to the view automatically, so when the listeners are invoked, `this` continues to refer to the view object.<br />\n * When `delegateEvents` is run again, perhaps with a different events hash, all listeners are removed and delegated afresh.\n * @param {object} [events] Object in the format `{'event selector' : 'listener'}`. Used to bind delegated event listeners to root element.\n * @return {Rasti.View} Return `this` for chaining.\n * @example\n * MyView.prototype.events = {\n * 'click button.ok' : 'onClickOkButton',\n * 'click button.cancel' : function() {}\n * };\n */;\n _proto.delegateEvents = function delegateEvents() {\n var _this2 = this;\n var events = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.events;\n if (!events) return this;\n if (this.delegatedEventListeners.length) this.undelegateEvents();\n\n // Store events by type i.e.: \"click\", \"submit\", etc.\n var eventTypes = {};\n Object.keys(events).forEach(function (key) {\n var keyParts = key.split(' '),\n type = keyParts.shift(),\n selector = keyParts.join(' '),\n listener = events[key];\n listener = (typeof listener === 'string' ? _this2[listener] : listener).bind(_this2);\n if (!eventTypes[type]) eventTypes[type] = [];\n eventTypes[type].push({\n selector: selector,\n listener: listener\n });\n });\n var indexOf = Array.prototype.indexOf;\n Object.keys(eventTypes).forEach(function (type) {\n var self = _this2;\n var typeListener = function typeListener(event) {\n eventTypes[type].forEach(function (_ref2) {\n var selector = _ref2.selector,\n listener = _ref2.listener;\n if (indexOf.call(selector ? self.el.querySelectorAll(selector) : [self.el], event.target) > -1) {\n listener(event, self);\n }\n });\n };\n _this2.delegatedEventListeners.push({\n type: type,\n listener: typeListener\n });\n _this2.el.addEventListener(type, typeListener);\n });\n return this;\n }\n\n /**\n * Removes all of the view's delegated events. Useful if you want to disable or remove a view from the DOM temporarily. Called automatically when the view is destroyed.\n * @return {Rasti.View} Return `this` for chaining.\n */;\n _proto.undelegateEvents = function undelegateEvents() {\n var _this3 = this;\n this.delegatedEventListeners.forEach(function (_ref3) {\n var type = _ref3.type,\n listener = _ref3.listener;\n _this3.el.removeEventListener(type, listener);\n });\n this.delegatedEventListeners = [];\n return this;\n }\n\n /**\n * Render the view.\n * This method should be overridden with custom logic.\n * The default implementation sets innerHTML of `this.el` with `this.template`.\n * Conventions are to only manipulate the dom in the scope of `this.el`, \n * and to return `this` for chaining.\n * If you added any child view, you must call `this.destroyChildren`.\n * @return {Rasti.View} Return `this` for chaining.\n */;\n _proto.render = function render() {\n if (this.template) this.el.innerHTML = this.template(this.model);\n return this;\n };\n return View;\n}(_Emitter2[\"default\"]);\n/*\n * Unique Id\n */\nexports[\"default\"] = View;\nView.uid = 0;\n\n//# sourceURL=webpack://Rasti/./src/View.js?");
50
60
 
51
61
  /***/ }),
52
62
 
@@ -56,7 +66,7 @@ eval("\n\nexports.__esModule = true;\nexports[\"default\"] = void 0;\nvar _Emitt
56
66
  \**********************/
57
67
  /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
58
68
 
59
- eval("\n\nexports.__esModule = true;\nvar _Emitter = _interopRequireDefault(__webpack_require__(/*! ./Emitter */ \"./src/Emitter.js\"));\nexports.Emitter = _Emitter[\"default\"];\nvar _Model = _interopRequireDefault(__webpack_require__(/*! ./Model */ \"./src/Model.js\"));\nexports.Model = _Model[\"default\"];\nvar _View = _interopRequireDefault(__webpack_require__(/*! ./View */ \"./src/View.js\"));\nexports.View = _View[\"default\"];\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { \"default\": obj }; }\n\n//# sourceURL=webpack://Rasti/./src/index.js?");
69
+ eval("\n\nexports.__esModule = true;\nvar _Emitter = _interopRequireDefault(__webpack_require__(/*! ./Emitter */ \"./src/Emitter.js\"));\nexports.Emitter = _Emitter[\"default\"];\nvar _Model = _interopRequireDefault(__webpack_require__(/*! ./Model */ \"./src/Model.js\"));\nexports.Model = _Model[\"default\"];\nvar _View = _interopRequireDefault(__webpack_require__(/*! ./View */ \"./src/View.js\"));\nexports.View = _View[\"default\"];\nvar _Component = _interopRequireDefault(__webpack_require__(/*! ./Component */ \"./src/Component.js\"));\nexports.Component = _Component[\"default\"];\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { \"default\": obj }; }\n\n//# sourceURL=webpack://Rasti/./src/index.js?");
60
70
 
61
71
  /***/ })
62
72
 
package/dist/rasti.min.js CHANGED
@@ -1 +1 @@
1
- !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.Rasti=t():e.Rasti=t()}(self,(()=>(()=>{"use strict";var e={30:(e,t)=>{t.__esModule=!0,t.default=void 0;var n=function(){function e(){}var t=e.prototype;return t.on=function(e,t){if("function"!=typeof t)throw TypeError("Listener must be a function");this.listeners||(this.listeners={}),this.listeners[e]||(this.listeners[e]=[]),this.listeners[e].push(t)},t.once=function(e,t){if("function"==typeof t){var n=this,i=t;t=function(){i.apply(void 0,arguments),n.off(e,t)}}this.on(e,t)},t.off=function(e,t){if(e)if(t){var n=this.listeners[e];n&&(n.slice().forEach((function(e,i){e===t&&n.splice(i,1)})),n.length||delete this.listeners[e])}else delete this.listeners[e];else this.listeners={}},t.emit=function(e){for(var t=arguments.length,n=new Array(t>1?t-1:0),i=1;i<t;i++)n[i-1]=arguments[i];var r=this.listeners&&this.listeners[e];r&&r.length&&r.slice().forEach((function(e){e.apply(void 0,n)}))},e}();t.default=n},289:(e,t,n)=>{var i;function r(e){if(void 0===e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return e}function s(e,t){return s=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(e,t){return e.__proto__=t,e},s(e,t)}t.__esModule=!0,t.default=void 0;var o=function(e){var t,n;function i(){var t,n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return(t=e.call(this)||this).preinitialize.apply(r(t),arguments),t.attributes=Object.assign({},t.defaults||{},n),t.previous={},Object.keys(t.attributes).forEach(t.defineAttribute.bind(r(t))),t}n=e,(t=i).prototype=Object.create(n.prototype),t.prototype.constructor=t,s(t,n);var o=i.prototype;return o.preinitialize=function(){},o.defineAttribute=function(e){var t=this;Object.defineProperty(this,e,{get:function(){return t.get(e)},set:function(n){t.set(e,n)}})},o.get=function(e){return this.attributes[e]},o.set=function(e,t){var n,i=this,r="object"==typeof e?e:((n={})[e]=t,n);return Object.keys(r).forEach((function(e){var t=e in i.attributes&&r[e]!==i.attributes[e];i.previous[e]=i.attributes[e],i.attributes[e]=r[e],t&&(i.emit("change",i,e,r[e]),i.emit("change:"+e,i,r[e]))})),this},o.toJSON=function(){return this.attributes},i}(((i=n(30))&&i.__esModule?i:{default:i}).default);t.default=o},789:(e,t,n)=>{t.__esModule=!0,t.default=void 0;var i,r=(i=n(30))&&i.__esModule?i:{default:i};function s(e,t){return s=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(e,t){return e.__proto__=t,e},s(e,t)}var o={el:!0,tag:!0,attributes:!0,events:!0,model:!0,template:!0,onDestroy:!0},u=function(e){var t,n;function i(){var t,n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return(t=e.call(this)||this).preinitialize.apply(function(e){if(void 0===e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return e}(t),arguments),t.uid="uid"+ ++i.uid,t.delegatedEventListeners=[],t.children=[],Object.keys(n).forEach((function(e){o[e]&&(t[e]=n[e])})),t.ensureElement(),t}n=e,(t=i).prototype=Object.create(n.prototype),t.prototype.constructor=t,s(t,n);var r=i.prototype;return r.preinitialize=function(){},r.$=function(e){return this.el.querySelector(e)},r.$$=function(e){return this.el.querySelectorAll(e)},r.destroy=function(){var e=(arguments.length>0&&void 0!==arguments[0]?arguments[0]:{}).remove;this.destroyChildren(),this.undelegateEvents(),this.off(),e&&this.removeElement(),this.onDestroy()},r.onDestroy=function(){},r.addChild=function(e){return this.children.push(e),e},r.destroyChildren=function(){for(;this.children.length;)this.children.shift().destroy()},r.ensureElement=function(){this.el||(this.el=this.createElement(this.tag,this.attributes)),this.delegateEvents()},r.createElement=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"div",t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=document.createElement(e);return Object.keys(t).forEach((function(e){return n.setAttribute(e,t[e])})),n},r.removeElement=function(){this.el.parentNode.removeChild(this.el)},r.delegateEvents=function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.events;if(!t)return this;this.delegatedEventListeners.length&&this.undelegateEvents();var n={};Object.keys(t).forEach((function(i){var r=i.split(" "),s=r.shift(),o=r.join(" "),u=t[i];u=("string"==typeof u?e[u]:u).bind(e),n[s]||(n[s]=[]),n[s].push({selector:o,listener:u})}));var i=Array.prototype.indexOf;return Object.keys(n).forEach((function(t){var r=e,s=function(e){n[t].forEach((function(t){var n=t.selector,s=t.listener;i.call(n?r.el.querySelectorAll(n):[r.el],e.target)>-1&&s(e,r)}))};e.delegatedEventListeners.push({type:t,listener:s}),e.el.addEventListener(t,s)})),this},r.undelegateEvents=function(){var e=this;return this.delegatedEventListeners.forEach((function(t){var n=t.type,i=t.listener;e.el.removeEventListener(n,i)})),this.delegatedEventListeners=[],this},r.render=function(){return this.template&&(this.el.innerHTML=this.template(this.model)),this},i}(r.default);t.default=u,u.uid=0}},t={};function n(i){var r=t[i];if(void 0!==r)return r.exports;var s=t[i]={exports:{}};return e[i](s,s.exports,n),s.exports}var i={};return(()=>{var e=i;e.__esModule=!0;var t=o(n(30));e.Emitter=t.default;var r=o(n(289));e.Model=r.default;var s=o(n(789));function o(e){return e&&e.__esModule?e:{default:e}}e.View=s.default})(),i})()));
1
+ !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.Rasti=t():e.Rasti=t()}(self,(()=>(()=>{"use strict";var e={252:(e,t,n)=>{t.__esModule=!0,t.default=void 0;var r,i=(r=n(789))&&r.__esModule?r:{default:r};function o(e){if(void 0===e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return e}function s(e,t){e.prototype=Object.create(t.prototype),e.prototype.constructor=e,a(e,t)}function a(e,t){return a=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(e,t){return e.__proto__=t,e},a(e,t)}var u={key:!0,state:!0,onCreate:!0,onChange:!0,onRender:!0},l=function(e,t){for(var n=arguments.length,r=new Array(n>2?n-2:0),i=2;i<n;i++)r[i-2]=arguments[i];return"function"==typeof e?e.apply(t,r):e},c=function(e){function t(){var t,n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return t=e.call(this,n)||this,Object.keys(n).forEach((function(e){u[e]&&(t[e]=n[e])})),t.options=n,t.id=t.attributes.id?l(t.attributes.id,o(t),o(t)):"rasti-component-"+t.uid,t.onChange=t.onChange.bind(o(t)),t.model&&t.model.on("change",t.onChange),t.state&&t.state.on("change",t.onChange),t.onCreate.apply(o(t),arguments),t}s(t,e);var n=t.prototype;return n.ensureElement=function(){this.el&&this.delegateEvents()},n.findElement=function(e){return(e||document).querySelector("#"+this.id)},n.hydrate=function(e){var t=this;this.el=this.findElement(e),this.delegateEvents(),this.children.forEach((function(e){return e.hydrate(t.el)})),this.onRender.call(this)},n.destroy=function(t){e.prototype.destroy.call(this,t),this.model&&this.model.off("change",this.onChange),this.state&&this.state.off("change",this.onChange),this.destroyed=!0},n.onCreate=function(){},n.onChange=function(){this.render()},n.onRender=function(){},n.onDestroy=function(){},n.replaceExpressions=function(e,t){var n=this;return e.replace(/{(\d+)}/g,(function(e){var r=e.match(/{(\d+)}/)[1],i=n.template.expressions[r].call(n,n);return(i instanceof Array?i:[i]).reduce((function(e,n){return e+t(n)}),"")})).replace(/([a-z]+)=["|']true["|']/g,"$1").replace(/([a-z]+)=["|']false["|']/g,"")},n.toString=function(){var e=this;this.destroyChildren();var t=this.attributes.id?this.template.outer:this.template.outer.replace(/^<([a-z]+)/,'<$1 id="'+this.id+'"');return this.replaceExpressions(t,(function(t){var n=t;return null==t?n="":t&&"function"==typeof t.render&&e.addChild(t),n}))},n.render=function(){var e=this;if(this.destroyed)return this;this.el||(this.el=this.createElement(this.tag),this.delegateEvents()),Object.keys(this.attributes).forEach((function(t){if("id"!==t){var n=l(e.attributes[t],e,e);!1===n?e.el.removeAttribute(t):(!0===n&&(n=""),e.el.setAttribute(t,n))}}));var t=this.children;this.children=[];var n=[],r=[];return this.el.innerHTML=this.replaceExpressions(this.template.inner,(function(e){var i=e;if(null==e)i="";else if(e&&"function"==typeof e.render){var o=e.key&&t.find((function(t){return t.key===e.key}));o?(i="<"+o.tag+' id="'+l(o.id,o,o)+'"></'+o.tag+">",r.push(o),e.destroy()):n.push(e)}return i})),n.forEach((function(t){e.addChild(t).hydrate(e.el)})),r.forEach((function(t){e.el.replaceChild(e.addChild(t).el,t.findElement(e.el))})),t.forEach((function(e){r.indexOf(e)>-1||e.destroy()})),this.onRender.call(this),this},t.extend=function(e){var t=function(e){function t(){return e.apply(this,arguments)||this}return s(t,e),t}(this);return Object.assign(t.prototype,"function"==typeof e?e(this.prototype):e),t},t.mount=function(){var e=arguments.length>1?arguments[1]:void 0,t=arguments.length>2?arguments[2]:void 0,n=new this(arguments.length>0&&void 0!==arguments[0]?arguments[0]:{});if(e){if(t)n.toString();else{var r=document.createElement("template");r.innerHTML=n,e.appendChild(r.content)}n.hydrate(e)}return n},t.create=function(e){for(var t=arguments.length,n=new Array(t>1?t-1:0),r=1;r<t;r++)n[r-1]=arguments[r];var i=[];e.forEach((function(e,t){i.push(e),n[t]&&i.push("function"==typeof n[t]||"object"==typeof n[t]?"{"+t+"}":n[t])}));var o=i.join("").trim().replace(/\n/g,""),s=o.match(/^<([a-z]+)(.*?)>(.*)<\/\1>$/),a=o.replace(/on([A-Z]{1}[a-z]+)+=[^>\s]+/g,""),u=function(e){for(var t,n={},r=/([a-z]+)=?(\S+)?/gi;null!==(t=r.exec(e));)n[t[1]]=!t[2]||t[2].replace(/'|"/g,"");return n}(s[2]),l={};return u=Object.keys(u).reduce((function(e,t){var r=t.match(/on(([A-Z]{1}[a-z]+)+)/),i=u[t].match(/{(\d+)}/),o=i&&i[1]?n[i[1]]:u[t];if(r&&r[1]){var s=r[1].toLowerCase();return Object.keys(o).forEach((function(e){return l[s+("&"===e?"":" "+e)]=o[e]})),e}return e[t]=o,e}),{}),this.extend({events:l,attributes:u,template:{outer:a,inner:s[3],expressions:n},tag:s[1]})},t}(i.default);t.default=c},30:(e,t)=>{t.__esModule=!0,t.default=void 0;var n=function(){function e(){}var t=e.prototype;return t.on=function(e,t){if("function"!=typeof t)throw TypeError("Listener must be a function");this.listeners||(this.listeners={}),this.listeners[e]||(this.listeners[e]=[]),this.listeners[e].push(t)},t.once=function(e,t){if("function"==typeof t){var n=this,r=t;t=function(){r.apply(void 0,arguments),n.off(e,t)}}this.on(e,t)},t.off=function(e,t){if(e)if(t){var n=this.listeners[e];n&&(n.slice().forEach((function(e,r){e===t&&n.splice(r,1)})),n.length||delete this.listeners[e])}else delete this.listeners[e];else this.listeners={}},t.emit=function(e){for(var t=arguments.length,n=new Array(t>1?t-1:0),r=1;r<t;r++)n[r-1]=arguments[r];var i=this.listeners&&this.listeners[e];i&&i.length&&i.slice().forEach((function(e){e.apply(void 0,n)}))},e}();t.default=n},289:(e,t,n)=>{var r;function i(e){if(void 0===e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return e}function o(e,t){return o=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(e,t){return e.__proto__=t,e},o(e,t)}t.__esModule=!0,t.default=void 0;var s=function(e){var t,n;function r(){var t,n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return(t=e.call(this)||this).preinitialize.apply(i(t),arguments),t.attributes=Object.assign({},t.defaults||{},n),t.previous={},Object.keys(t.attributes).forEach(t.defineAttribute.bind(i(t))),t}n=e,(t=r).prototype=Object.create(n.prototype),t.prototype.constructor=t,o(t,n);var s=r.prototype;return s.preinitialize=function(){},s.defineAttribute=function(e){var t=this;Object.defineProperty(this,e,{get:function(){return t.get(e)},set:function(n){t.set(e,n)}})},s.get=function(e){return this.attributes[e]},s.set=function(e,t){var n,r=this,i="object"==typeof e?e:((n={})[e]=t,n);return Object.keys(i).forEach((function(e){var t=e in r.attributes&&i[e]!==r.attributes[e];r.previous[e]=r.attributes[e],r.attributes[e]=i[e],t&&(r.emit("change",r,e,i[e]),r.emit("change:"+e,r,i[e]))})),this},s.toJSON=function(){return this.attributes},r}(((r=n(30))&&r.__esModule?r:{default:r}).default);t.default=s},789:(e,t,n)=>{t.__esModule=!0,t.default=void 0;var r,i=(r=n(30))&&r.__esModule?r:{default:r};function o(e,t){return o=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(e,t){return e.__proto__=t,e},o(e,t)}var s={el:!0,tag:!0,attributes:!0,events:!0,model:!0,template:!0,onDestroy:!0},a=function(e){var t,n;function r(){var t,n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return(t=e.call(this)||this).preinitialize.apply(function(e){if(void 0===e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return e}(t),arguments),t.uid="uid"+ ++r.uid,t.delegatedEventListeners=[],t.children=[],Object.keys(n).forEach((function(e){s[e]&&(t[e]=n[e])})),t.ensureElement(),t}n=e,(t=r).prototype=Object.create(n.prototype),t.prototype.constructor=t,o(t,n);var i=r.prototype;return i.preinitialize=function(){},i.$=function(e){return this.el.querySelector(e)},i.$$=function(e){return this.el.querySelectorAll(e)},i.destroy=function(){var e=(arguments.length>0&&void 0!==arguments[0]?arguments[0]:{}).remove;this.destroyChildren(),this.undelegateEvents(),this.off(),e&&this.removeElement(),this.onDestroy.apply(this,arguments)},i.onDestroy=function(){},i.addChild=function(e){return this.children.push(e),e},i.destroyChildren=function(){for(;this.children.length;)this.children.shift().destroy()},i.ensureElement=function(){this.el||(this.el=this.createElement(this.tag,this.attributes)),this.delegateEvents()},i.createElement=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"div",t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=document.createElement(e);return Object.keys(t).forEach((function(e){return n.setAttribute(e,t[e])})),n},i.removeElement=function(){this.el.parentNode.removeChild(this.el)},i.delegateEvents=function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.events;if(!t)return this;this.delegatedEventListeners.length&&this.undelegateEvents();var n={};Object.keys(t).forEach((function(r){var i=r.split(" "),o=i.shift(),s=i.join(" "),a=t[r];a=("string"==typeof a?e[a]:a).bind(e),n[o]||(n[o]=[]),n[o].push({selector:s,listener:a})}));var r=Array.prototype.indexOf;return Object.keys(n).forEach((function(t){var i=e,o=function(e){n[t].forEach((function(t){var n=t.selector,o=t.listener;r.call(n?i.el.querySelectorAll(n):[i.el],e.target)>-1&&o(e,i)}))};e.delegatedEventListeners.push({type:t,listener:o}),e.el.addEventListener(t,o)})),this},i.undelegateEvents=function(){var e=this;return this.delegatedEventListeners.forEach((function(t){var n=t.type,r=t.listener;e.el.removeEventListener(n,r)})),this.delegatedEventListeners=[],this},i.render=function(){return this.template&&(this.el.innerHTML=this.template(this.model)),this},r}(i.default);t.default=a,a.uid=0}},t={};function n(r){var i=t[r];if(void 0!==i)return i.exports;var o=t[r]={exports:{}};return e[r](o,o.exports,n),o.exports}var r={};return(()=>{var e=r;e.__esModule=!0;var t=a(n(30));e.Emitter=t.default;var i=a(n(289));e.Model=i.default;var o=a(n(789));e.View=o.default;var s=a(n(252));function a(e){return e&&e.__esModule?e:{default:e}}e.Component=s.default})(),r})()));