rasti 2.1.0-alpha.0 → 2.1.0-alpha.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/dist/rasti.js CHANGED
@@ -26,7 +26,7 @@ return /******/ (() => { // webpackBootstrap
26
26
  \**************************/
27
27
  /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
28
28
 
29
- eval("\n\nexports.__esModule = true;\nexports[\"default\"] = void 0;\nvar _View2 = _interopRequireDefault(__webpack_require__(/*! ./View.js */ \"./src/View.js\"));\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { \"default\": obj }; }\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 extractAttributes = function extractAttributes(text) {\n var attributes = {};\n var re = /([\\w|data-]+)(?:=[\"']?((?:.(?![\"']?\\s+(?:\\S+)=|\\s*\\/?[>\"']))+.)[\"']?)?/g;\n var result;\n while ((result = re.exec(text)) !== null) {\n attributes[result[1]] = typeof result[2] === 'undefined' ? true : result[2];\n }\n return attributes;\n};\n\n/*\n * Helper function. If first arg is a placeholder for an expression, return the expression.\n */\nvar getExpression = function getExpression(placeholder, expressions) {\n var match = placeholder && placeholder.match && placeholder.match(new RegExp(Component.EXPRESSION_PLACEHOLDER_TEMPLATE('(\\\\d+)')));\n return match && match[1] ? expressions[match[1]] : placeholder;\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. \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 * Components are defined with the `create` static method, which takes a tagged template.\n * @module\n * @extends Rasti.View\n * @param {object} options Object containing options. The following keys will be merged to `this`: model, state, key, onDestroy, onRender, onCreate, onChange.\n * @property {string} key A unique key to identify the component. Used to recycle child components.\n * @property {object} model A `Rasti.Model` or any emitter object containing data and business logic.\n * @property {object} state A `Rasti.Model` or any emitter object containing data and business logic, to be used as internal state.\n * @example\n * import { Component, Model } from 'rasti';\n * // Create Timer component.\n * const Timer = Component.create`\n * <div>\n * Seconds: <span>${({ model }) => model.seconds}</span>\n * </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 = exports[\"default\"] = /*#__PURE__*/function (_View) {\n function Component() {\n var _this;\n var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n _this = _View.apply(this, arguments) || 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 // 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(_this);\n // Listen to model changes and call onChange.\n if (_this.model && _this.model.on) _this.model.on('change', _this.onChange);\n if (_this.state && _this.state.on) _this.state.on('change', _this.onChange);\n // Call life cycle method.\n _this.onCreate.apply(_this, arguments);\n return _this;\n }\n\n /*\n * Tell if component is a container.\n * In which case, it will not have an element by itself.\n * It will render a single expression which is expected to return a single component as child.\n * `this.el` will be a reference to that child component's element.\n * @return {boolean}\n */\n _inheritsLoose(Component, _View);\n var _proto = Component.prototype;\n _proto.isContainer = function isContainer() {\n return !!(!this.tag && this.template && this.template.inner && this.template.expressions && this.template.expressions.length === 1);\n }\n\n /*\n * Override. We don't want to ensure an element on instantiation.\n * We will provide it later.\n */;\n _proto.ensureElement = function ensureElement() {\n // If el is provided, delegate events.\n if (this.el) {\n this.delegateEvents();\n this.id = this.el.id;\n }\n // Ensure id.\n if (!this.isContainer() && !this.id) {\n this.id = this.attributes && this.attributes.id ?\n // If id is provided, evaluate it.\n evalExpression(this.attributes.id, this, this) :\n // Generate a unique id and set it as id attribute.\n Component.ID_TEMPLATE(this.uid);\n }\n }\n\n /*\n * Find view's element on parent node, using id.\n * @param parent {node} The parent node.\n * @return {node} The component's element.\n */;\n _proto.findElement = function findElement(parent) {\n return (parent || document).querySelector(\"#\" + this.id);\n }\n\n /*\n * Eval attributes expressions.\n * @return {object} Object containing add, remove and html properties.\n */;\n _proto.getAttributes = function getAttributes() {\n var _this2 = this;\n var add = {\n id: this.id\n };\n var remove = {};\n var html = [\"id=\\\"\" + this.id + \"\\\"\"];\n if (this.attributes) {\n Object.keys(this.attributes).forEach(function (key) {\n if (key === 'id') return;\n // Evaluate attribute value.\n var value = evalExpression(_this2.attributes[key], _this2, _this2);\n\n // Transform bool attribute values\n if (value === false) {\n remove[key] = true;\n } else if (value === true) {\n add[key] = '';\n html.push(key);\n } else {\n if (value === null || typeof value === 'undefined') value = '';\n add[key] = value;\n html.push(key + \"=\\\"\" + value + \"\\\"\");\n }\n });\n }\n return {\n add: add,\n remove: remove,\n html: html.join(' ')\n };\n }\n\n /*\n * Used internally on the render process.\n * Attach the view to the dom element.\n * @param parent {node} The parent node.\n * @return {Rasti.Component} The component instance.\n */;\n _proto.hydrate = function hydrate(parent) {\n var _this3 = this;\n if (!this.isContainer()) {\n this.el = this.findElement(parent);\n this.delegateEvents();\n this.children.forEach(function (child) {\n return child.hydrate(_this3.el);\n });\n } else {\n this.children[0].hydrate(parent);\n this.el = this.children[0].el;\n }\n // Call `onRender` lifecycle method.\n this.onRender.call(this, 'hydrate');\n // Return `this` for chaining.\n return this;\n }\n\n /*\n * Used internally on the render process.\n * Reuse a view that has `key` when its parent is rendered.\n * @param parent {node} The parent node.\n * @return {Rasti.Component} The component instance.\n */;\n _proto.recycle = function recycle(parent) {\n // Find element to be replaced. It has same id.\n var toBeReplaced = (this.isContainer() ? this.children[0] : this).findElement(parent);\n // Replace it with this.el.\n toBeReplaced.replaceWith(this.el);\n // Call `onRender` lifecycle method.\n this.onRender.call(this, 'recycle');\n // Return `this` for chaining.\n return this;\n }\n\n /*\n * Override. Add some custom logic to super `destroy` method.\n * @param {object} options Options object or any arguments passed to `destroy` method will be passed to `onDestroy` method.\n */;\n _proto.destroy = function destroy() {\n _View.prototype.destroy.apply(this, arguments);\n // Stop listening to `change`.\n if (this.model && this.model.off) this.model.off('change', this.onChange);\n if (this.state && this.state.off) this.state.off('change', this.onChange);\n // Set destroyed flag to prevent a last render after destroyed.\n this.destroyed = true;\n // Return `this` for chaining.\n return this;\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} The model that emitted the event.\n * @param changed {object} Object containing keys and values that has changed.\n * @param [...args] {any} Any extra arguments passed to set method.\n */;\n _proto.onChange = function onChange() {\n this.render();\n }\n\n /**\n * Lifecycle method. Called when the view is rendered.\n * @param type {string} The render type. Can be `render`, `hydrate` or `recycle`.\n */;\n _proto.onRender = function onRender() {}\n\n /**\n * Lifecycle method. Called when the view is destroyed.\n * @param {object} options Options object or any arguments passed to `destroy` method.\n */;\n _proto.onDestroy = function onDestroy() {}\n\n /*\n * Replace expressions.\n */;\n _proto.replaceExpressions = function replaceExpressions(string, addChild) {\n var _this4 = this;\n return string.replace(new RegExp(Component.EXPRESSION_PLACEHOLDER_TEMPLATE('(\\\\d+)'), 'g'), function (match) {\n var expression = getExpression(match, _this4.template.expressions);\n // Eval expression. Pass view as argument.\n var result = evalExpression(expression, _this4, _this4);\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, result) {\n var parsed;\n // If result is true, replace it with a placeholder.\n if (result === true) parsed = Component.TRUE_PLACEHOLDER;\n // If result is false, replace it with a placeholder.\n else if (result === false) parsed = Component.FALSE_PLACEHOLDER;\n // Replace null or undefined with empty string.\n else if (result === null || typeof result === 'undefined') parsed = '';\n // If result is a view, call addChild callback.\n else if (result && typeof result.render === 'function') parsed = addChild(result);\n // Return expression itself.\n else parsed = result;\n // Concatenate expressions.\n return out + parsed;\n }, '');\n })\n // Replace `attribute=\"true\"` with `attribute` and `attribute=\"false\"` with empty string.\n .replace(new RegExp(\"([\\\\w|data-]+)=([\\\"'])?(\" + Component.TRUE_PLACEHOLDER + \"|\" + Component.FALSE_PLACEHOLDER + \")\\\\2\", 'g'), function (match, attribute, quote, placeholder) {\n return placeholder === Component.TRUE_PLACEHOLDER ? attribute : '';\n })\n // Replace rest of true or false expressions with empty string.\n .replace(new RegExp(Component.TRUE_PLACEHOLDER + \"|\" + Component.FALSE_PLACEHOLDER, 'g'), '');\n }\n\n /*\n * Treat the whole view as a HTML string.\n */;\n _proto.toString = function toString() {\n var _this5 = this;\n // Normally there won't be any children, but if there are, destroy them.\n this.destroyChildren();\n // Replace expressions of inner template.\n var close = this.template && this.template.inner;\n var inner = close && this.replaceExpressions(this.template.inner, function (component) {\n // Add child component.\n return _this5.addChild(component);\n });\n // If component is a container, return inner which will be an expression thats return a single component.\n if (this.isContainer()) return inner;\n // Get tag name.\n var tag = this.tag || 'div';\n // Get attributes.\n var attributes = this.getAttributes().html;\n // Generate outer template.\n return close ? \"<\" + tag + \" \" + attributes + \">\" + inner + \"</\" + tag + \">\" : \"<\" + tag + \" \" + attributes + \" />\";\n }\n\n /*\n * View render method.\n */;\n _proto.render = function render() {\n var _this6 = this;\n // Prevent a last re render if view is already destroyed.\n if (this.destroyed) return this;\n if (!this.isContainer()) {\n // If `this.el` is not present, create a new `this.tag` element.\n if (!this.el) {\n this.el = this.createElement(this.tag);\n this.delegateEvents();\n }\n // Set `this.el` attributes.\n var attributes = this.getAttributes();\n // Remove attributes.\n Object.keys(attributes.remove).forEach(function (key) {\n _this6.el.removeAttribute(key);\n });\n // Add attributes.\n Object.keys(attributes.add).forEach(function (key) {\n _this6.el.setAttribute(key, attributes.add[key]);\n });\n }\n // Check for `template.inner` to see if view has innerHTML.\n if (this.template && this.template.inner) {\n // Store active element.\n var activeElement = document.activeElement;\n var nextChildren = [];\n var recycledChildren = [];\n var previousChildren = this.children;\n this.children = [];\n // Replace expressions. Set html inside of `this.el`.\n var inner = this.replaceExpressions(this.template.inner, function (component) {\n var out = component;\n // Check if child already exists.\n var found = component.key && previousChildren.find(function (previousChild) {\n return previousChild.key === component.key;\n });\n if (found) {\n var tag = found.el.tagName.toLowerCase();\n var id = found.el.id;\n // If child already exists, replace it html by its root element.\n out = \"<\" + tag + \" id=\\\"\" + id + \"\\\"></\" + tag + \">\";\n // Add child to recycled children.\n recycledChildren.push(found);\n // Destroy new child component. Use recycled one instead.\n component.destroy();\n } else {\n // Not found. Add new child component.\n nextChildren.push(component);\n }\n // Component html.\n return out;\n });\n if (this.isContainer()) {\n if (nextChildren[0]) {\n var fragment = this.createElement('template');\n fragment.innerHTML = inner;\n // Add new child to dom fragment and hydrate it.\n this.addChild(nextChildren[0]).hydrate(fragment.content);\n // Get next child element.\n var nextEl = fragment.content.children[0];\n // If `this.el` is present, replace it with nextEl.\n if (this.el) this.el.replaceWith(nextEl);\n // Set `this.el` to nextEl.\n this.el = nextEl;\n } else if (recycledChildren[0]) {\n this.addChild(recycledChildren[0]);\n }\n } else {\n this.el.innerHTML = inner;\n // Add new children. Hydrate them.\n nextChildren.forEach(function (nextChild) {\n _this6.addChild(nextChild).hydrate(_this6.el);\n });\n // Replace children root elements with recycled components.\n recycledChildren.forEach(function (recycledChild) {\n _this6.addChild(recycledChild).recycle(_this6.el);\n });\n }\n // Destroy unused children.\n previousChildren.forEach(function (previousChild) {\n var found = recycledChildren.indexOf(previousChild) > -1;\n if (!found) previousChild.destroy();\n });\n // Restore focus.\n if (this.el.contains(activeElement)) {\n activeElement.focus();\n }\n }\n // Call onRender lifecycle method.\n this.onRender.call(this, 'render');\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 function Extended() {\n return _Current.apply(this, arguments) || this;\n }\n _inheritsLoose(Extended, _Current);\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.Component}\n */;\n Component.mount = function mount(options, el, hydrate) {\n // Instantiate view.\n var view = new this(options);\n // If `el` is passed, mount component.\n if (el) {\n if (hydrate) {\n view.toString();\n } else {\n var fragment = this.prototype.createElement('template');\n // Add html text into element inner html.\n fragment.innerHTML = view;\n // Add to dom.\n el.appendChild(fragment.content.children[0]);\n }\n view.hydrate(el);\n }\n // Return view instance.\n return view;\n }\n\n /**\n * Takes a tagged template containing an HTML string, \n * and returns a new `Component` class.\n * - The template outer tag and attributes will be used to create the view's root element.\n * - Boolean attributes should be passed in the form of `attribute=\"${() => true}\"`.\n * - Event handlers should be passed, at the root element, in the form of `onEventName=${{'selector' : listener }}`. Where `selector` is a css selector. The event will be delegated to the view's root element.\n * - The template inner HTML will be used as the view's template.\n * - Template interpolations that are functions will be evaluated on the render process. Receiving the view instance as argument. And being bound to it.\n * - If the function returns `null`, `undefined`, `false` or empty string, the interpolation won't render any content.\n * - If the function returns a component instance, it will be added as a child component.\n * - If the function returns an array, each item will be evaluated as above.\n * @static\n * @param {string} HTML template for the component. Or a function that mounts a sub component.\n * @return {Rasti.Component}\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 // Containers can be created using create as a functions instead of a tagged template.\n if (typeof strings === 'function') {\n expressions = [strings];\n strings = ['', ''];\n }\n var tag, attributes, inner, events;\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' ? Component.EXPRESSION_PLACEHOLDER_TEMPLATE(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-6]?)(.*?)>(.*)<\\/\\1>$/) || main.match(/^<([a-z]+)(.*?)\\/>$/);\n if (result) {\n tag = result[1];\n inner = result[3];\n // Parse attributes from html text into an object.\n attributes = extractAttributes(result[2]);\n // Events to be delegated.\n events = {};\n // Filter events. To generate events object.\n // Generate attributes object, replace placeholders with expressions.\n attributes = Object.keys(attributes).reduce(function (out, key) {\n // Is Event?\n var matchKey = key.match(/on(([A-Z]{1}[a-z]+)+)/);\n // Is placeholder for function or object?\n // Get expression or value.\n var value = getExpression(attributes[key], expressions);\n // Is event handler. Add to events object.\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 attribute. Add to attributes object.\n out[key] = value;\n return out;\n }, {});\n } else inner = main;\n var Current = this;\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.\n template: {\n // Template for innerHTML of root element.\n inner: inner,\n // Template expressions.\n expressions: expressions\n },\n // Set root element tag.\n tag: tag\n });\n };\n return Component;\n}(_View2[\"default\"]);\nComponent.ID_TEMPLATE = function (uid) {\n return \"rasti-component-\" + uid;\n};\nComponent.EXPRESSION_PLACEHOLDER_TEMPLATE = function (idx) {\n return \"__RASTI_EXPRESSION{\" + idx + \"}\";\n};\nComponent.TRUE_PLACEHOLDER = '__RASTI_TRUE';\nComponent.FALSE_PLACEHOLDER = '__RASTI_FALSE';\n\n//# sourceURL=webpack://Rasti/./src/Component.js?");
29
+ eval("\n\nexports.__esModule = true;\nexports[\"default\"] = void 0;\nvar _View2 = _interopRequireDefault(__webpack_require__(/*! ./View.js */ \"./src/View.js\"));\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { \"default\": obj }; }\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 extractAttributes = function extractAttributes(text) {\n var attributes = {};\n var re = /([\\w|data-]+)(?:=[\"']?((?:.(?![\"']?\\s+(?:\\S+)=|\\s*\\/?[>\"']))+.)[\"']?)?/g;\n var result;\n while ((result = re.exec(text)) !== null) {\n attributes[result[1]] = typeof result[2] === 'undefined' ? true : result[2];\n }\n return attributes;\n};\n\n/*\n * Helper function. If first arg is a placeholder for an expression, return the expression.\n */\nvar getExpression = function getExpression(placeholder, expressions) {\n var match = placeholder && placeholder.match && placeholder.match(new RegExp(Component.EXPRESSION_PLACEHOLDER_TEMPLATE('(\\\\d+)')));\n return match && match[1] ? expressions[match[1]] : placeholder;\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. \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 * Components are defined with the `create` static method, which takes a tagged template.\n * @module\n * @extends Rasti.View\n * @param {object} options Object containing options. The following keys will be merged to `this`: model, state, key, onDestroy, onRender, onCreate, onChange.\n * @property {string} key A unique key to identify the component. Used to recycle child components.\n * @property {object} model A `Rasti.Model` or any emitter object containing data and business logic.\n * @property {object} state A `Rasti.Model` or any emitter object containing data and business logic, to be used as internal state.\n * @example\n * import { Component, Model } from 'rasti';\n * // Create Timer component.\n * const Timer = Component.create`\n * <div>\n * Seconds: <span>${({ model }) => model.seconds}</span>\n * </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 = exports[\"default\"] = /*#__PURE__*/function (_View) {\n function Component() {\n var _this;\n var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n _this = _View.apply(this, arguments) || 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 // 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(_this);\n // Listen to model changes and call onChange.\n if (_this.model && _this.model.on) _this.model.on('change', _this.onChange);\n if (_this.state && _this.state.on) _this.state.on('change', _this.onChange);\n // Call life cycle method.\n _this.onCreate.apply(_this, arguments);\n return _this;\n }\n\n /*\n * Tell if component is a container.\n * In which case, it will not have an element by itself.\n * It will render a single expression which is expected to return a single component as child.\n * `this.el` will be a reference to that child component's element.\n * @return {boolean}\n */\n _inheritsLoose(Component, _View);\n var _proto = Component.prototype;\n _proto.isContainer = function isContainer() {\n return !!(!this.tag && this.template && this.template.inner && this.template.expressions && this.template.expressions.length === 1);\n }\n\n /*\n * Override. We don't want to ensure an element on instantiation.\n * We will provide it later.\n */;\n _proto.ensureElement = function ensureElement() {\n // If el is provided, delegate events.\n if (this.el) {\n this.delegateEvents();\n this.id = this.el.id;\n }\n // Ensure id.\n if (!this.isContainer() && !this.id) {\n this.id = this.attributes && this.attributes.id ?\n // If id is provided, evaluate it.\n evalExpression(this.attributes.id, this, this) :\n // Generate a unique id and set it as id attribute.\n Component.ID_TEMPLATE(this.uid);\n }\n }\n\n /*\n * Find view's element on parent node, using id.\n * @param parent {node} The parent node.\n * @return {node} The component's element.\n */;\n _proto.findElement = function findElement(parent) {\n return (parent || document).querySelector(\"#\" + this.id);\n }\n\n /*\n * Eval attributes expressions.\n * @return {object} Object containing add, remove and html properties.\n */;\n _proto.getAttributes = function getAttributes() {\n var _this2 = this;\n var add = {\n id: this.id\n };\n var remove = {};\n var html = [\"id=\\\"\" + this.id + \"\\\"\"];\n if (this.attributes) {\n Object.keys(this.attributes).forEach(function (key) {\n if (key === 'id') return;\n // Evaluate attribute value.\n var value = evalExpression(_this2.attributes[key], _this2, _this2);\n\n // Transform bool attribute values\n if (value === false) {\n remove[key] = true;\n } else if (value === true) {\n add[key] = '';\n html.push(key);\n } else {\n if (value === null || typeof value === 'undefined') value = '';\n add[key] = value;\n html.push(key + \"=\\\"\" + value + \"\\\"\");\n }\n });\n }\n return {\n add: add,\n remove: remove,\n html: html.join(' ')\n };\n }\n\n /*\n * Used internally on the render process.\n * Attach the view to the dom element.\n * @param parent {node} The parent node.\n * @return {Rasti.Component} The component instance.\n */;\n _proto.hydrate = function hydrate(parent) {\n var _this3 = this;\n if (!this.isContainer()) {\n this.el = this.findElement(parent);\n this.delegateEvents();\n this.children.forEach(function (child) {\n return child.hydrate(_this3.el);\n });\n } else {\n this.children[0].hydrate(parent);\n this.el = this.children[0].el;\n }\n // Call `onRender` lifecycle method.\n this.onRender.call(this, 'hydrate');\n // Return `this` for chaining.\n return this;\n }\n\n /*\n * Used internally on the render process.\n * Reuse a view that has `key` when its parent is rendered.\n * @param parent {node} The parent node.\n * @return {Rasti.Component} The component instance.\n */;\n _proto.recycle = function recycle(parent) {\n // Find element to be replaced. It has same id.\n var toBeReplaced = (this.isContainer() ? this.children[0] : this).findElement(parent);\n // Replace it with this.el.\n toBeReplaced.replaceWith(this.el);\n // Call `onRender` lifecycle method.\n this.onRender.call(this, 'recycle');\n // Return `this` for chaining.\n return this;\n }\n\n /*\n * Override. Add some custom logic to super `destroy` method.\n * @param {object} options Options object or any arguments passed to `destroy` method will be passed to `onDestroy` method.\n */;\n _proto.destroy = function destroy() {\n _View.prototype.destroy.apply(this, arguments);\n // Stop listening to `change`.\n if (this.model && this.model.off) this.model.off('change', this.onChange);\n if (this.state && this.state.off) this.state.off('change', this.onChange);\n // Set destroyed flag to prevent a last render after destroyed.\n this.destroyed = true;\n // Return `this` for chaining.\n return this;\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} The model that emitted the event.\n * @param changed {object} Object containing keys and values that has changed.\n * @param [...args] {any} Any extra arguments passed to set method.\n */;\n _proto.onChange = function onChange() {\n this.render();\n }\n\n /**\n * Lifecycle method. Called when the view is rendered.\n * @param type {string} The render type. Can be `render`, `hydrate` or `recycle`.\n */;\n _proto.onRender = function onRender() {}\n\n /**\n * Lifecycle method. Called when the view is destroyed.\n * @param {object} options Options object or any arguments passed to `destroy` method.\n */;\n _proto.onDestroy = function onDestroy() {}\n\n /*\n * Replace expressions.\n */;\n _proto.replaceExpressions = function replaceExpressions(string, addChild) {\n var _this4 = this;\n return string.replace(new RegExp(Component.EXPRESSION_PLACEHOLDER_TEMPLATE('(\\\\d+)'), 'g'), function (match) {\n var expression = getExpression(match, _this4.template.expressions);\n // Eval expression. Pass view as argument.\n var result = evalExpression(expression, _this4, _this4);\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, result) {\n var parsed;\n // If result is true, replace it with a placeholder.\n if (result === true) parsed = Component.TRUE_PLACEHOLDER;\n // If result is false, replace it with a placeholder.\n else if (result === false) parsed = Component.FALSE_PLACEHOLDER;\n // Replace null or undefined with empty string.\n else if (result === null || typeof result === 'undefined') parsed = '';\n // If result is a view, call addChild callback.\n else if (result && typeof result.render === 'function') parsed = addChild(result);\n // Return expression itself.\n else parsed = result;\n // Concatenate expressions.\n return out + parsed;\n }, '');\n })\n // Replace `attribute=\"true\"` with `attribute` and `attribute=\"false\"` with empty string.\n .replace(new RegExp(\"([\\\\w|data-]+)=([\\\"'])?(\" + Component.TRUE_PLACEHOLDER + \"|\" + Component.FALSE_PLACEHOLDER + \")\\\\2\", 'g'), function (match, attribute, quote, placeholder) {\n return placeholder === Component.TRUE_PLACEHOLDER ? attribute : '';\n })\n // Replace rest of true or false expressions with empty string.\n .replace(new RegExp(Component.TRUE_PLACEHOLDER + \"|\" + Component.FALSE_PLACEHOLDER, 'g'), '');\n }\n\n /*\n * Treat the whole view as a HTML string.\n */;\n _proto.toString = function toString() {\n var _this5 = this;\n // Normally there won't be any children, but if there are, destroy them.\n this.destroyChildren();\n // Replace expressions of inner template.\n var close = this.template && this.template.inner;\n var inner = close && this.replaceExpressions(this.template.inner, function (component) {\n // Add child component.\n return _this5.addChild(component);\n });\n // If component is a container, return inner which will be an expression thats return a single component.\n if (this.isContainer()) return inner;\n // Get tag name.\n var tag = this.tag || 'div';\n // Get attributes.\n var attributes = this.getAttributes().html;\n // Generate outer template.\n return close ? \"<\" + tag + \" \" + attributes + \">\" + inner + \"</\" + tag + \">\" : \"<\" + tag + \" \" + attributes + \" />\";\n }\n\n /*\n * View render method.\n */;\n _proto.render = function render() {\n var _this6 = this;\n // Prevent a last re render if view is already destroyed.\n if (this.destroyed) return this;\n if (!this.isContainer()) {\n // If `this.el` is not present, create a new `this.tag` element.\n if (!this.el) {\n this.el = this.createElement(this.tag);\n this.delegateEvents();\n }\n // Set `this.el` attributes.\n var attributes = this.getAttributes();\n // Remove attributes.\n Object.keys(attributes.remove).forEach(function (key) {\n _this6.el.removeAttribute(key);\n });\n // Add attributes.\n Object.keys(attributes.add).forEach(function (key) {\n _this6.el.setAttribute(key, attributes.add[key]);\n });\n }\n // Check for `template.inner` to see if view has innerHTML.\n if (this.template && this.template.inner) {\n // Store active element.\n var activeElement = document.activeElement;\n var nextChildren = [];\n var recycledChildren = [];\n var previousChildren = this.children;\n this.children = [];\n // Replace expressions. Set html inside of `this.el`.\n var inner = this.replaceExpressions(this.template.inner, function (component) {\n var out = component;\n // Check if child already exists.\n var found = component.key && previousChildren.find(function (previousChild) {\n return previousChild.key === component.key;\n });\n if (found) {\n var tag = found.el.tagName.toLowerCase();\n var id = found.el.id;\n // If child already exists, replace it html by its root element.\n out = \"<\" + tag + \" id=\\\"\" + id + \"\\\"></\" + tag + \">\";\n // Add child to recycled children.\n recycledChildren.push(found);\n // Destroy new child component. Use recycled one instead.\n component.destroy();\n } else {\n // Not found. Add new child component.\n nextChildren.push(component);\n }\n // Component html.\n return out;\n });\n if (this.isContainer()) {\n if (nextChildren[0]) {\n var fragment = this.createElement('template');\n fragment.innerHTML = inner;\n // Add new child to dom fragment and hydrate it.\n this.addChild(nextChildren[0]).hydrate(fragment.content);\n // Get next child element.\n var nextEl = fragment.content.children[0];\n // If `this.el` is present, replace it with nextEl.\n if (this.el) this.el.replaceWith(nextEl);\n // Set `this.el` to nextEl.\n this.el = nextEl;\n } else if (recycledChildren[0]) {\n this.addChild(recycledChildren[0]);\n }\n } else {\n this.el.innerHTML = inner;\n // Add new children. Hydrate them.\n nextChildren.forEach(function (nextChild) {\n _this6.addChild(nextChild).hydrate(_this6.el);\n });\n // Replace children root elements with recycled components.\n recycledChildren.forEach(function (recycledChild) {\n _this6.addChild(recycledChild).recycle(_this6.el);\n });\n }\n // Destroy unused children.\n previousChildren.forEach(function (previousChild) {\n var found = recycledChildren.indexOf(previousChild) > -1;\n if (!found) previousChild.destroy();\n });\n // Restore focus.\n if (this.el.contains(activeElement)) {\n activeElement.focus();\n }\n }\n // Call onRender lifecycle method.\n this.onRender.call(this, 'render');\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 function Extended() {\n return _Current.apply(this, arguments) || this;\n }\n _inheritsLoose(Extended, _Current);\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.Component}\n */;\n Component.mount = function mount(options, el, hydrate) {\n // Instantiate view.\n var view = new this(options);\n // If `el` is passed, mount component.\n if (el) {\n if (hydrate) {\n view.toString();\n } else {\n var fragment = this.prototype.createElement('template');\n // Add html text into element inner html.\n fragment.innerHTML = view;\n // Add to dom.\n el.appendChild(fragment.content.children[0]);\n }\n view.hydrate(el);\n }\n // Return view instance.\n return view;\n }\n\n /**\n * Takes a tagged template containing an HTML string, \n * and returns a new `Component` class.\n * - The template outer tag and attributes will be used to create the view's root element.\n * - Boolean attributes should be passed in the form of `attribute=\"${() => true}\"`.\n * - Event handlers should be passed, at the root element, in the form of `onEventName=${{'selector' : listener }}`. Where `selector` is a css selector. The event will be delegated to the view's root element.\n * - The template inner HTML will be used as the view's template.\n * - Template interpolations that are functions will be evaluated on the render process. Receiving the view instance as argument. And being bound to it.\n * - If the function returns `null`, `undefined`, `false` or empty string, the interpolation won't render any content.\n * - If the function returns a component instance, it will be added as a child component.\n * - If the function returns an array, each item will be evaluated as above.\n * @static\n * @param {string} HTML template for the component. Or a function that mounts a sub component.\n * @return {Rasti.Component}\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 // Containers can be created using create as a functions instead of a tagged template.\n if (typeof strings === 'function') {\n expressions = [strings];\n strings = ['', ''];\n }\n var tag, attributes, inner, events;\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' ? Component.EXPRESSION_PLACEHOLDER_TEMPLATE(i) : expressions[i]);\n }\n });\n // Create output string for main template. Add placeholders for new lines.\n var main = parts.join('').trim().replace(/\\n/g, Component.NEW_LINE_PLACEHOLDER);\n // Extract outer tag, attributes and inner html.\n var result = main.match(/^<([a-z]+[1-6]?)(.*?)>(.*)<\\/\\1>$/) || main.match(/^<([a-z]+)(.*?)\\/>$/);\n if (result) {\n // Get tag, attributes.\n tag = result[1];\n // Get inner html. Restore new lines.\n inner = result[3] && result[3].replace(new RegExp(Component.NEW_LINE_PLACEHOLDER, 'g'), '\\n');\n // Parse attributes from html string into an object. Remove new lines.\n attributes = extractAttributes(result[2].replace(new RegExp(Component.NEW_LINE_PLACEHOLDER, 'g'), ''));\n // Events to be delegated.\n events = {};\n // Filter events. To generate events object.\n // Generate attributes object, replace placeholders with expressions.\n attributes = Object.keys(attributes).reduce(function (out, key) {\n // Is Event?\n var matchKey = key.match(/on(([A-Z]{1}[a-z]+)+)/);\n // Is placeholder for function or object?\n // Get expression or value.\n var value = getExpression(attributes[key], expressions);\n // Is event handler. Add to events object.\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 attribute. Add to attributes object.\n out[key] = value;\n return out;\n }, {});\n } else inner = main;\n var Current = this;\n // Create subclass for this component.\n return Current.extend({\n // Set root element tag.\n tag: tag,\n // Set attributes.\n attributes: attributes,\n // Set events.\n events: events,\n // Set template.\n template: {\n // Template for innerHTML of root element.\n inner: inner,\n // Template expressions.\n expressions: expressions\n }\n });\n };\n return Component;\n}(_View2[\"default\"]);\nComponent.ID_TEMPLATE = function (uid) {\n return \"rasti-component-\" + uid;\n};\nComponent.EXPRESSION_PLACEHOLDER_TEMPLATE = function (idx) {\n return \"__RASTI_EXPRESSION_{\" + idx + \"}__\";\n};\nComponent.TRUE_PLACEHOLDER = '__RASTI_TRUE__';\nComponent.FALSE_PLACEHOLDER = '__RASTI_FALSE__';\nComponent.NEW_LINE_PLACEHOLDER = '__RASTI_NEW_LINE__';\n\n//# sourceURL=webpack://Rasti/./src/Component.js?");
30
30
 
31
31
  /***/ }),
32
32
 
package/dist/rasti.min.js CHANGED
@@ -1 +1 @@
1
- !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.Rasti=e():t.Rasti=e()}(self,(()=>(()=>{"use strict";var t={818:(t,e,n)=>{e.__esModule=!0,e.default=void 0;var i,r=(i=n(944))&&i.__esModule?i:{default:i};function s(t,e){t.prototype=Object.create(e.prototype),t.prototype.constructor=t,o(t,e)}function o(t,e){return o=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(t,e){return t.__proto__=e,t},o(t,e)}var a={key:!0,state:!0,onCreate:!0,onChange:!0,onRender:!0},h=function(t,e){var n=t&&t.match&&t.match(new RegExp(c.EXPRESSION_PLACEHOLDER_TEMPLATE("(\\d+)")));return n&&n[1]?e[n[1]]:t},u=function(t,e){for(var n=arguments.length,i=new Array(n>2?n-2:0),r=2;r<n;r++)i[r-2]=arguments[r];return"function"==typeof t?t.apply(e,i):t},c=e.default=function(t){function e(){var e,n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return e=t.apply(this,arguments)||this,Object.keys(n).forEach((function(t){a[t]&&(e[t]=n[t])})),e.options=n,e.onChange=e.onChange.bind(e),e.model&&e.model.on&&e.model.on("change",e.onChange),e.state&&e.state.on&&e.state.on("change",e.onChange),e.onCreate.apply(e,arguments),e}s(e,t);var n=e.prototype;return n.isContainer=function(){return!(this.tag||!this.template||!this.template.inner||!this.template.expressions||1!==this.template.expressions.length)},n.ensureElement=function(){this.el&&(this.delegateEvents(),this.id=this.el.id),this.isContainer()||this.id||(this.id=this.attributes&&this.attributes.id?u(this.attributes.id,this,this):e.ID_TEMPLATE(this.uid))},n.findElement=function(t){return(t||document).querySelector("#"+this.id)},n.getAttributes=function(){var t=this,e={id:this.id},n={},i=['id="'+this.id+'"'];return this.attributes&&Object.keys(this.attributes).forEach((function(r){if("id"!==r){var s=u(t.attributes[r],t,t);!1===s?n[r]=!0:!0===s?(e[r]="",i.push(r)):(null==s&&(s=""),e[r]=s,i.push(r+'="'+s+'"'))}})),{add:e,remove:n,html:i.join(" ")}},n.hydrate=function(t){var e=this;return this.isContainer()?(this.children[0].hydrate(t),this.el=this.children[0].el):(this.el=this.findElement(t),this.delegateEvents(),this.children.forEach((function(t){return t.hydrate(e.el)}))),this.onRender.call(this,"hydrate"),this},n.recycle=function(t){return(this.isContainer()?this.children[0]:this).findElement(t).replaceWith(this.el),this.onRender.call(this,"recycle"),this},n.destroy=function(){return t.prototype.destroy.apply(this,arguments),this.model&&this.model.off&&this.model.off("change",this.onChange),this.state&&this.state.off&&this.state.off("change",this.onChange),this.destroyed=!0,this},n.onCreate=function(){},n.onChange=function(){this.render()},n.onRender=function(){},n.onDestroy=function(){},n.replaceExpressions=function(t,n){var i=this;return t.replace(new RegExp(e.EXPRESSION_PLACEHOLDER_TEMPLATE("(\\d+)"),"g"),(function(t){var r=h(t,i.template.expressions),s=u(r,i,i);return(s instanceof Array?s:[s]).reduce((function(t,i){return t+(!0===i?e.TRUE_PLACEHOLDER:!1===i?e.FALSE_PLACEHOLDER:null==i?"":i&&"function"==typeof i.render?n(i):i)}),"")})).replace(new RegExp("([\\w|data-]+)=([\"'])?("+e.TRUE_PLACEHOLDER+"|"+e.FALSE_PLACEHOLDER+")\\2","g"),(function(t,n,i,r){return r===e.TRUE_PLACEHOLDER?n:""})).replace(new RegExp(e.TRUE_PLACEHOLDER+"|"+e.FALSE_PLACEHOLDER,"g"),"")},n.toString=function(){var t=this;this.destroyChildren();var e=this.template&&this.template.inner,n=e&&this.replaceExpressions(this.template.inner,(function(e){return t.addChild(e)}));if(this.isContainer())return n;var i=this.tag||"div",r=this.getAttributes().html;return e?"<"+i+" "+r+">"+n+"</"+i+">":"<"+i+" "+r+" />"},n.render=function(){var t=this;if(this.destroyed)return this;if(!this.isContainer()){this.el||(this.el=this.createElement(this.tag),this.delegateEvents());var e=this.getAttributes();Object.keys(e.remove).forEach((function(e){t.el.removeAttribute(e)})),Object.keys(e.add).forEach((function(n){t.el.setAttribute(n,e.add[n])}))}if(this.template&&this.template.inner){var n=document.activeElement,i=[],r=[],s=this.children;this.children=[];var o=this.replaceExpressions(this.template.inner,(function(t){var e=t,n=t.key&&s.find((function(e){return e.key===t.key}));if(n){var o=n.el.tagName.toLowerCase();e="<"+o+' id="'+n.el.id+'"></'+o+">",r.push(n),t.destroy()}else i.push(t);return e}));if(this.isContainer())if(i[0]){var a=this.createElement("template");a.innerHTML=o,this.addChild(i[0]).hydrate(a.content);var h=a.content.children[0];this.el&&this.el.replaceWith(h),this.el=h}else r[0]&&this.addChild(r[0]);else this.el.innerHTML=o,i.forEach((function(e){t.addChild(e).hydrate(t.el)})),r.forEach((function(e){t.addChild(e).recycle(t.el)}));s.forEach((function(t){r.indexOf(t)>-1||t.destroy()})),this.el.contains(n)&&n.focus()}return this.onRender.call(this,"render"),this},e.extend=function(t){var e=function(t){function e(){return t.apply(this,arguments)||this}return s(e,t),e}(this);return Object.assign(e.prototype,"function"==typeof t?t(this.prototype):t),e},e.mount=function(t,e,n){var i=new this(t);if(e){if(n)i.toString();else{var r=this.prototype.createElement("template");r.innerHTML=i,e.appendChild(r.content.children[0])}i.hydrate(e)}return i},e.create=function(t){for(var n=arguments.length,i=new Array(n>1?n-1:0),r=1;r<n;r++)i[r-1]=arguments[r];var s,o,a,u;"function"==typeof t&&(i=[t],t=["",""]);var c=[];t.forEach((function(t,n){c.push(t),i[n]&&c.push("function"==typeof i[n]||"object"==typeof i[n]?e.EXPRESSION_PLACEHOLDER_TEMPLATE(n):i[n])}));var l=c.join("").trim().replace(/\n/g,""),f=l.match(/^<([a-z]+[1-6]?)(.*?)>(.*)<\/\1>$/)||l.match(/^<([a-z]+)(.*?)\/>$/);return f?(s=f[1],a=f[3],o=function(t){for(var e,n={},i=/([\w|data-]+)(?:=["']?((?:.(?!["']?\s+(?:\S+)=|\s*\/?[>"']))+.)["']?)?/g;null!==(e=i.exec(t));)n[e[1]]=void 0===e[2]||e[2];return n}(f[2]),u={},o=Object.keys(o).reduce((function(t,e){var n=e.match(/on(([A-Z]{1}[a-z]+)+)/),r=h(o[e],i);if(n&&n[1]){var s=n[1].toLowerCase();return Object.keys(r).forEach((function(t){return u[s+("&"===t?"":" "+t)]=r[t]})),t}return t[e]=r,t}),{})):a=l,this.extend({events:u,attributes:o,template:{inner:a,expressions:i},tag:s})},e}(r.default);c.ID_TEMPLATE=function(t){return"rasti-component-"+t},c.EXPRESSION_PLACEHOLDER_TEMPLATE=function(t){return"__RASTI_EXPRESSION{"+t+"}"},c.TRUE_PLACEHOLDER="__RASTI_TRUE",c.FALSE_PLACEHOLDER="__RASTI_FALSE"},527:(t,e)=>{e.__esModule=!0,e.default=void 0,e.default=function(){function t(){}var e=t.prototype;return e.on=function(t,e){if("function"!=typeof e)throw TypeError("Listener must be a function");this.listeners||(this.listeners={}),this.listeners[t]||(this.listeners[t]=[]),this.listeners[t].push(e)},e.once=function(t,e){if("function"==typeof e){var n=this,i=e;e=function(){i.apply(void 0,arguments),n.off(t,e)}}this.on(t,e)},e.off=function(t,e){if(t)if(e){var n=this.listeners[t];n&&(n.slice().forEach((function(t,i){t===e&&n.splice(i,1)})),n.length||delete this.listeners[t])}else delete this.listeners[t];else this.listeners={}},e.emit=function(t){for(var e=arguments.length,n=new Array(e>1?e-1:0),i=1;i<e;i++)n[i-1]=arguments[i];var r=this.listeners&&this.listeners[t];r&&r.length&&r.slice().forEach((function(t){t.apply(void 0,n)}))},t}()},4:(t,e,n)=>{e.__esModule=!0,e.default=void 0;var i,r=(i=n(527))&&i.__esModule?i:{default:i};function s(t,e){return s=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(t,e){return t.__proto__=e,t},s(t,e)}e.default=function(t){function e(){var e,n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return(e=t.call(this)||this).preinitialize.apply(e,arguments),e.attributes=Object.assign({},e.defaults||{},n),e.previous={},Object.keys(e.attributes).forEach(e.defineAttribute.bind(e)),e}var n,i;i=t,(n=e).prototype=Object.create(i.prototype),n.prototype.constructor=n,s(n,i);var r=e.prototype;return r.preinitialize=function(){},r.defineAttribute=function(t){var e=this;Object.defineProperty(this,t,{get:function(){return e.get(t)},set:function(n){e.set(t,n)}})},r.get=function(t){return this.attributes[t]},r.set=function(t,e){for(var n,i,r,s=this,o=arguments.length,a=new Array(o>2?o-2:0),h=2;h<o;h++)a[h-2]=arguments[h];"object"==typeof t?(n=t,i=[e].concat(a)):((r={})[t]=e,n=r,i=a);var u=this._changing;this._changing=!0;var c={};u||(this.previous=Object.assign({},this.attributes)),Object.keys(n).forEach((function(t){n[t]!==s.attributes[t]&&(c[t]=n[t],s.attributes[t]=n[t])}));var l=Object.keys(c);if(l.length&&(this._pending=["change",this,c].concat(i)),l.forEach((function(t){s.emit.apply(s,["change:"+t,s,n[t]].concat(i))})),u)return this;for(;this._pending;){var f=this._pending;this._pending=null,this.emit.apply(this,f)}return this._pending=null,this._changing=!1,this},r.toJSON=function(){return this.attributes},e}(r.default)},944:(t,e,n)=>{e.__esModule=!0,e.default=void 0;var i,r=(i=n(527))&&i.__esModule?i:{default:i};function s(t,e){return s=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(t,e){return t.__proto__=e,t},s(t,e)}var o={el:!0,tag:!0,attributes:!0,events:!0,model:!0,template:!0,onDestroy:!0};(e.default=function(t){function e(){var n,i=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return(n=t.call(this)||this).preinitialize.apply(n,arguments),n.uid="uid"+ ++e.uid,n.delegatedEventListeners=[],n.children=[],Object.keys(i).forEach((function(t){o[t]&&(n[t]=i[t])})),n.ensureElement(),n}var n,i;i=t,(n=e).prototype=Object.create(i.prototype),n.prototype.constructor=n,s(n,i);var r=e.prototype;return r.preinitialize=function(){},r.$=function(t){return this.el.querySelector(t)},r.$$=function(t){return this.el.querySelectorAll(t)},r.destroy=function(){return this.destroyChildren(),this.undelegateEvents(),this.off(),this.onDestroy.apply(this,arguments),this},r.onDestroy=function(){},r.addChild=function(t){return this.children.push(t),t},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 t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"div",e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=document.createElement(t);return Object.keys(e).forEach((function(t){return n.setAttribute(t,e[t])})),n},r.removeElement=function(){return this.el.parentNode.removeChild(this.el),this},r.delegateEvents=function(){var t=this,e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.events;if(!e)return this;this.delegatedEventListeners.length&&this.undelegateEvents();var n={};return Object.keys(e).forEach((function(i){var r=i.split(" "),s=r.shift(),o=r.join(" "),a=e[i];a=("string"==typeof a?t[a]:a).bind(t),n[s]||(n[s]=[]),n[s].push({selector:o,listener:a})})),Object.keys(n).forEach((function(e){var i=function(i){n[e].forEach((function(e){var n=e.selector,r=e.listener;n&&!i.target.closest(n)||r(i,t)}))};t.delegatedEventListeners.push({type:e,listener:i}),t.el.addEventListener(e,i)})),this},r.undelegateEvents=function(){var t=this;return this.delegatedEventListeners.forEach((function(e){var n=e.type,i=e.listener;t.el.removeEventListener(n,i)})),this.delegatedEventListeners=[],this},r.render=function(){return this.template&&(this.el.innerHTML=this.template(this.model)),this},e}(r.default)).uid=0}},e={};function n(i){var r=e[i];if(void 0!==r)return r.exports;var s=e[i]={exports:{}};return t[i](s,s.exports,n),s.exports}var i={};return(()=>{var t=i;t.__esModule=!0;var e=a(n(527));t.Emitter=e.default;var r=a(n(4));t.Model=r.default;var s=a(n(944));t.View=s.default;var o=a(n(818));function a(t){return t&&t.__esModule?t:{default:t}}t.Component=o.default})(),i})()));
1
+ !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.Rasti=e():t.Rasti=e()}(self,(()=>(()=>{"use strict";var t={818:(t,e,n)=>{e.__esModule=!0,e.default=void 0;var i,r=(i=n(944))&&i.__esModule?i:{default:i};function s(t,e){t.prototype=Object.create(e.prototype),t.prototype.constructor=t,o(t,e)}function o(t,e){return o=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(t,e){return t.__proto__=e,t},o(t,e)}var a={key:!0,state:!0,onCreate:!0,onChange:!0,onRender:!0},h=function(t,e){var n=t&&t.match&&t.match(new RegExp(c.EXPRESSION_PLACEHOLDER_TEMPLATE("(\\d+)")));return n&&n[1]?e[n[1]]:t},u=function(t,e){for(var n=arguments.length,i=new Array(n>2?n-2:0),r=2;r<n;r++)i[r-2]=arguments[r];return"function"==typeof t?t.apply(e,i):t},c=e.default=function(t){function e(){var e,n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return e=t.apply(this,arguments)||this,Object.keys(n).forEach((function(t){a[t]&&(e[t]=n[t])})),e.options=n,e.onChange=e.onChange.bind(e),e.model&&e.model.on&&e.model.on("change",e.onChange),e.state&&e.state.on&&e.state.on("change",e.onChange),e.onCreate.apply(e,arguments),e}s(e,t);var n=e.prototype;return n.isContainer=function(){return!(this.tag||!this.template||!this.template.inner||!this.template.expressions||1!==this.template.expressions.length)},n.ensureElement=function(){this.el&&(this.delegateEvents(),this.id=this.el.id),this.isContainer()||this.id||(this.id=this.attributes&&this.attributes.id?u(this.attributes.id,this,this):e.ID_TEMPLATE(this.uid))},n.findElement=function(t){return(t||document).querySelector("#"+this.id)},n.getAttributes=function(){var t=this,e={id:this.id},n={},i=['id="'+this.id+'"'];return this.attributes&&Object.keys(this.attributes).forEach((function(r){if("id"!==r){var s=u(t.attributes[r],t,t);!1===s?n[r]=!0:!0===s?(e[r]="",i.push(r)):(null==s&&(s=""),e[r]=s,i.push(r+'="'+s+'"'))}})),{add:e,remove:n,html:i.join(" ")}},n.hydrate=function(t){var e=this;return this.isContainer()?(this.children[0].hydrate(t),this.el=this.children[0].el):(this.el=this.findElement(t),this.delegateEvents(),this.children.forEach((function(t){return t.hydrate(e.el)}))),this.onRender.call(this,"hydrate"),this},n.recycle=function(t){return(this.isContainer()?this.children[0]:this).findElement(t).replaceWith(this.el),this.onRender.call(this,"recycle"),this},n.destroy=function(){return t.prototype.destroy.apply(this,arguments),this.model&&this.model.off&&this.model.off("change",this.onChange),this.state&&this.state.off&&this.state.off("change",this.onChange),this.destroyed=!0,this},n.onCreate=function(){},n.onChange=function(){this.render()},n.onRender=function(){},n.onDestroy=function(){},n.replaceExpressions=function(t,n){var i=this;return t.replace(new RegExp(e.EXPRESSION_PLACEHOLDER_TEMPLATE("(\\d+)"),"g"),(function(t){var r=h(t,i.template.expressions),s=u(r,i,i);return(s instanceof Array?s:[s]).reduce((function(t,i){return t+(!0===i?e.TRUE_PLACEHOLDER:!1===i?e.FALSE_PLACEHOLDER:null==i?"":i&&"function"==typeof i.render?n(i):i)}),"")})).replace(new RegExp("([\\w|data-]+)=([\"'])?("+e.TRUE_PLACEHOLDER+"|"+e.FALSE_PLACEHOLDER+")\\2","g"),(function(t,n,i,r){return r===e.TRUE_PLACEHOLDER?n:""})).replace(new RegExp(e.TRUE_PLACEHOLDER+"|"+e.FALSE_PLACEHOLDER,"g"),"")},n.toString=function(){var t=this;this.destroyChildren();var e=this.template&&this.template.inner,n=e&&this.replaceExpressions(this.template.inner,(function(e){return t.addChild(e)}));if(this.isContainer())return n;var i=this.tag||"div",r=this.getAttributes().html;return e?"<"+i+" "+r+">"+n+"</"+i+">":"<"+i+" "+r+" />"},n.render=function(){var t=this;if(this.destroyed)return this;if(!this.isContainer()){this.el||(this.el=this.createElement(this.tag),this.delegateEvents());var e=this.getAttributes();Object.keys(e.remove).forEach((function(e){t.el.removeAttribute(e)})),Object.keys(e.add).forEach((function(n){t.el.setAttribute(n,e.add[n])}))}if(this.template&&this.template.inner){var n=document.activeElement,i=[],r=[],s=this.children;this.children=[];var o=this.replaceExpressions(this.template.inner,(function(t){var e=t,n=t.key&&s.find((function(e){return e.key===t.key}));if(n){var o=n.el.tagName.toLowerCase();e="<"+o+' id="'+n.el.id+'"></'+o+">",r.push(n),t.destroy()}else i.push(t);return e}));if(this.isContainer())if(i[0]){var a=this.createElement("template");a.innerHTML=o,this.addChild(i[0]).hydrate(a.content);var h=a.content.children[0];this.el&&this.el.replaceWith(h),this.el=h}else r[0]&&this.addChild(r[0]);else this.el.innerHTML=o,i.forEach((function(e){t.addChild(e).hydrate(t.el)})),r.forEach((function(e){t.addChild(e).recycle(t.el)}));s.forEach((function(t){r.indexOf(t)>-1||t.destroy()})),this.el.contains(n)&&n.focus()}return this.onRender.call(this,"render"),this},e.extend=function(t){var e=function(t){function e(){return t.apply(this,arguments)||this}return s(e,t),e}(this);return Object.assign(e.prototype,"function"==typeof t?t(this.prototype):t),e},e.mount=function(t,e,n){var i=new this(t);if(e){if(n)i.toString();else{var r=this.prototype.createElement("template");r.innerHTML=i,e.appendChild(r.content.children[0])}i.hydrate(e)}return i},e.create=function(t){for(var n=arguments.length,i=new Array(n>1?n-1:0),r=1;r<n;r++)i[r-1]=arguments[r];var s,o,a,u;"function"==typeof t&&(i=[t],t=["",""]);var c=[];t.forEach((function(t,n){c.push(t),i[n]&&c.push("function"==typeof i[n]||"object"==typeof i[n]?e.EXPRESSION_PLACEHOLDER_TEMPLATE(n):i[n])}));var l=c.join("").trim().replace(/\n/g,e.NEW_LINE_PLACEHOLDER),f=l.match(/^<([a-z]+[1-6]?)(.*?)>(.*)<\/\1>$/)||l.match(/^<([a-z]+)(.*?)\/>$/);return f?(s=f[1],a=f[3]&&f[3].replace(new RegExp(e.NEW_LINE_PLACEHOLDER,"g"),"\n"),o=function(t){for(var e,n={},i=/([\w|data-]+)(?:=["']?((?:.(?!["']?\s+(?:\S+)=|\s*\/?[>"']))+.)["']?)?/g;null!==(e=i.exec(t));)n[e[1]]=void 0===e[2]||e[2];return n}(f[2].replace(new RegExp(e.NEW_LINE_PLACEHOLDER,"g"),"")),u={},o=Object.keys(o).reduce((function(t,e){var n=e.match(/on(([A-Z]{1}[a-z]+)+)/),r=h(o[e],i);if(n&&n[1]){var s=n[1].toLowerCase();return Object.keys(r).forEach((function(t){return u[s+("&"===t?"":" "+t)]=r[t]})),t}return t[e]=r,t}),{})):a=l,this.extend({tag:s,attributes:o,events:u,template:{inner:a,expressions:i}})},e}(r.default);c.ID_TEMPLATE=function(t){return"rasti-component-"+t},c.EXPRESSION_PLACEHOLDER_TEMPLATE=function(t){return"__RASTI_EXPRESSION_{"+t+"}__"},c.TRUE_PLACEHOLDER="__RASTI_TRUE__",c.FALSE_PLACEHOLDER="__RASTI_FALSE__",c.NEW_LINE_PLACEHOLDER="__RASTI_NEW_LINE__"},527:(t,e)=>{e.__esModule=!0,e.default=void 0,e.default=function(){function t(){}var e=t.prototype;return e.on=function(t,e){if("function"!=typeof e)throw TypeError("Listener must be a function");this.listeners||(this.listeners={}),this.listeners[t]||(this.listeners[t]=[]),this.listeners[t].push(e)},e.once=function(t,e){if("function"==typeof e){var n=this,i=e;e=function(){i.apply(void 0,arguments),n.off(t,e)}}this.on(t,e)},e.off=function(t,e){if(t)if(e){var n=this.listeners[t];n&&(n.slice().forEach((function(t,i){t===e&&n.splice(i,1)})),n.length||delete this.listeners[t])}else delete this.listeners[t];else this.listeners={}},e.emit=function(t){for(var e=arguments.length,n=new Array(e>1?e-1:0),i=1;i<e;i++)n[i-1]=arguments[i];var r=this.listeners&&this.listeners[t];r&&r.length&&r.slice().forEach((function(t){t.apply(void 0,n)}))},t}()},4:(t,e,n)=>{e.__esModule=!0,e.default=void 0;var i,r=(i=n(527))&&i.__esModule?i:{default:i};function s(t,e){return s=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(t,e){return t.__proto__=e,t},s(t,e)}e.default=function(t){function e(){var e,n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return(e=t.call(this)||this).preinitialize.apply(e,arguments),e.attributes=Object.assign({},e.defaults||{},n),e.previous={},Object.keys(e.attributes).forEach(e.defineAttribute.bind(e)),e}var n,i;i=t,(n=e).prototype=Object.create(i.prototype),n.prototype.constructor=n,s(n,i);var r=e.prototype;return r.preinitialize=function(){},r.defineAttribute=function(t){var e=this;Object.defineProperty(this,t,{get:function(){return e.get(t)},set:function(n){e.set(t,n)}})},r.get=function(t){return this.attributes[t]},r.set=function(t,e){for(var n,i,r,s=this,o=arguments.length,a=new Array(o>2?o-2:0),h=2;h<o;h++)a[h-2]=arguments[h];"object"==typeof t?(n=t,i=[e].concat(a)):((r={})[t]=e,n=r,i=a);var u=this._changing;this._changing=!0;var c={};u||(this.previous=Object.assign({},this.attributes)),Object.keys(n).forEach((function(t){n[t]!==s.attributes[t]&&(c[t]=n[t],s.attributes[t]=n[t])}));var l=Object.keys(c);if(l.length&&(this._pending=["change",this,c].concat(i)),l.forEach((function(t){s.emit.apply(s,["change:"+t,s,n[t]].concat(i))})),u)return this;for(;this._pending;){var f=this._pending;this._pending=null,this.emit.apply(this,f)}return this._pending=null,this._changing=!1,this},r.toJSON=function(){return this.attributes},e}(r.default)},944:(t,e,n)=>{e.__esModule=!0,e.default=void 0;var i,r=(i=n(527))&&i.__esModule?i:{default:i};function s(t,e){return s=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(t,e){return t.__proto__=e,t},s(t,e)}var o={el:!0,tag:!0,attributes:!0,events:!0,model:!0,template:!0,onDestroy:!0};(e.default=function(t){function e(){var n,i=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return(n=t.call(this)||this).preinitialize.apply(n,arguments),n.uid="uid"+ ++e.uid,n.delegatedEventListeners=[],n.children=[],Object.keys(i).forEach((function(t){o[t]&&(n[t]=i[t])})),n.ensureElement(),n}var n,i;i=t,(n=e).prototype=Object.create(i.prototype),n.prototype.constructor=n,s(n,i);var r=e.prototype;return r.preinitialize=function(){},r.$=function(t){return this.el.querySelector(t)},r.$$=function(t){return this.el.querySelectorAll(t)},r.destroy=function(){return this.destroyChildren(),this.undelegateEvents(),this.off(),this.onDestroy.apply(this,arguments),this},r.onDestroy=function(){},r.addChild=function(t){return this.children.push(t),t},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 t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"div",e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=document.createElement(t);return Object.keys(e).forEach((function(t){return n.setAttribute(t,e[t])})),n},r.removeElement=function(){return this.el.parentNode.removeChild(this.el),this},r.delegateEvents=function(){var t=this,e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.events;if(!e)return this;this.delegatedEventListeners.length&&this.undelegateEvents();var n={};return Object.keys(e).forEach((function(i){var r=i.split(" "),s=r.shift(),o=r.join(" "),a=e[i];a=("string"==typeof a?t[a]:a).bind(t),n[s]||(n[s]=[]),n[s].push({selector:o,listener:a})})),Object.keys(n).forEach((function(e){var i=function(i){n[e].forEach((function(e){var n=e.selector,r=e.listener;n&&!i.target.closest(n)||r(i,t)}))};t.delegatedEventListeners.push({type:e,listener:i}),t.el.addEventListener(e,i)})),this},r.undelegateEvents=function(){var t=this;return this.delegatedEventListeners.forEach((function(e){var n=e.type,i=e.listener;t.el.removeEventListener(n,i)})),this.delegatedEventListeners=[],this},r.render=function(){return this.template&&(this.el.innerHTML=this.template(this.model)),this},e}(r.default)).uid=0}},e={};function n(i){var r=e[i];if(void 0!==r)return r.exports;var s=e[i]={exports:{}};return t[i](s,s.exports,n),s.exports}var i={};return(()=>{var t=i;t.__esModule=!0;var e=a(n(527));t.Emitter=e.default;var r=a(n(4));t.Model=r.default;var s=a(n(944));t.View=s.default;var o=a(n(818));function a(t){return t&&t.__esModule?t:{default:t}}t.Component=o.default})(),i})()));
package/es/Component.js CHANGED
@@ -501,15 +501,17 @@ var Component = /*#__PURE__*/function (_View) {
501
501
  parts.push(typeof expressions[i] === 'function' || typeof expressions[i] === 'object' ? Component.EXPRESSION_PLACEHOLDER_TEMPLATE(i) : expressions[i]);
502
502
  }
503
503
  });
504
- // Create output text for main template.
505
- var main = parts.join('').trim().replace(/\n/g, '');
504
+ // Create output string for main template. Add placeholders for new lines.
505
+ var main = parts.join('').trim().replace(/\n/g, Component.NEW_LINE_PLACEHOLDER);
506
506
  // Extract outer tag, attributes and inner html.
507
507
  var result = main.match(/^<([a-z]+[1-6]?)(.*?)>(.*)<\/\1>$/) || main.match(/^<([a-z]+)(.*?)\/>$/);
508
508
  if (result) {
509
+ // Get tag, attributes.
509
510
  tag = result[1];
510
- inner = result[3];
511
- // Parse attributes from html text into an object.
512
- attributes = extractAttributes(result[2]);
511
+ // Get inner html. Restore new lines.
512
+ inner = result[3] && result[3].replace(new RegExp(Component.NEW_LINE_PLACEHOLDER, 'g'), '\n');
513
+ // Parse attributes from html string into an object. Remove new lines.
514
+ attributes = extractAttributes(result[2].replace(new RegExp(Component.NEW_LINE_PLACEHOLDER, 'g'), ''));
513
515
  // Events to be delegated.
514
516
  events = {};
515
517
  // Filter events. To generate events object.
@@ -536,19 +538,19 @@ var Component = /*#__PURE__*/function (_View) {
536
538
  var Current = this;
537
539
  // Create subclass for this component.
538
540
  return Current.extend({
539
- // Set events.
540
- events: events,
541
+ // Set root element tag.
542
+ tag: tag,
541
543
  // Set attributes.
542
544
  attributes: attributes,
545
+ // Set events.
546
+ events: events,
543
547
  // Set template.
544
548
  template: {
545
549
  // Template for innerHTML of root element.
546
550
  inner: inner,
547
551
  // Template expressions.
548
552
  expressions: expressions
549
- },
550
- // Set root element tag.
551
- tag: tag
553
+ }
552
554
  });
553
555
  };
554
556
  return Component;
@@ -558,7 +560,8 @@ Component.ID_TEMPLATE = function (uid) {
558
560
  return "rasti-component-" + uid;
559
561
  };
560
562
  Component.EXPRESSION_PLACEHOLDER_TEMPLATE = function (idx) {
561
- return "__RASTI_EXPRESSION{" + idx + "}";
563
+ return "__RASTI_EXPRESSION_{" + idx + "}__";
562
564
  };
563
- Component.TRUE_PLACEHOLDER = '__RASTI_TRUE';
564
- Component.FALSE_PLACEHOLDER = '__RASTI_FALSE';
565
+ Component.TRUE_PLACEHOLDER = '__RASTI_TRUE__';
566
+ Component.FALSE_PLACEHOLDER = '__RASTI_FALSE__';
567
+ Component.NEW_LINE_PLACEHOLDER = '__RASTI_NEW_LINE__';
package/lib/Component.js CHANGED
@@ -505,15 +505,17 @@ var Component = exports["default"] = /*#__PURE__*/function (_View) {
505
505
  parts.push(typeof expressions[i] === 'function' || typeof expressions[i] === 'object' ? Component.EXPRESSION_PLACEHOLDER_TEMPLATE(i) : expressions[i]);
506
506
  }
507
507
  });
508
- // Create output text for main template.
509
- var main = parts.join('').trim().replace(/\n/g, '');
508
+ // Create output string for main template. Add placeholders for new lines.
509
+ var main = parts.join('').trim().replace(/\n/g, Component.NEW_LINE_PLACEHOLDER);
510
510
  // Extract outer tag, attributes and inner html.
511
511
  var result = main.match(/^<([a-z]+[1-6]?)(.*?)>(.*)<\/\1>$/) || main.match(/^<([a-z]+)(.*?)\/>$/);
512
512
  if (result) {
513
+ // Get tag, attributes.
513
514
  tag = result[1];
514
- inner = result[3];
515
- // Parse attributes from html text into an object.
516
- attributes = extractAttributes(result[2]);
515
+ // Get inner html. Restore new lines.
516
+ inner = result[3] && result[3].replace(new RegExp(Component.NEW_LINE_PLACEHOLDER, 'g'), '\n');
517
+ // Parse attributes from html string into an object. Remove new lines.
518
+ attributes = extractAttributes(result[2].replace(new RegExp(Component.NEW_LINE_PLACEHOLDER, 'g'), ''));
517
519
  // Events to be delegated.
518
520
  events = {};
519
521
  // Filter events. To generate events object.
@@ -540,19 +542,19 @@ var Component = exports["default"] = /*#__PURE__*/function (_View) {
540
542
  var Current = this;
541
543
  // Create subclass for this component.
542
544
  return Current.extend({
543
- // Set events.
544
- events: events,
545
+ // Set root element tag.
546
+ tag: tag,
545
547
  // Set attributes.
546
548
  attributes: attributes,
549
+ // Set events.
550
+ events: events,
547
551
  // Set template.
548
552
  template: {
549
553
  // Template for innerHTML of root element.
550
554
  inner: inner,
551
555
  // Template expressions.
552
556
  expressions: expressions
553
- },
554
- // Set root element tag.
555
- tag: tag
557
+ }
556
558
  });
557
559
  };
558
560
  return Component;
@@ -561,7 +563,8 @@ Component.ID_TEMPLATE = function (uid) {
561
563
  return "rasti-component-" + uid;
562
564
  };
563
565
  Component.EXPRESSION_PLACEHOLDER_TEMPLATE = function (idx) {
564
- return "__RASTI_EXPRESSION{" + idx + "}";
566
+ return "__RASTI_EXPRESSION_{" + idx + "}__";
565
567
  };
566
- Component.TRUE_PLACEHOLDER = '__RASTI_TRUE';
567
- Component.FALSE_PLACEHOLDER = '__RASTI_FALSE';
568
+ Component.TRUE_PLACEHOLDER = '__RASTI_TRUE__';
569
+ Component.FALSE_PLACEHOLDER = '__RASTI_FALSE__';
570
+ Component.NEW_LINE_PLACEHOLDER = '__RASTI_NEW_LINE__';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rasti",
3
- "version": "2.1.0-alpha.0",
3
+ "version": "2.1.0-alpha.1",
4
4
  "description": "Rasti is a minimalistic JavaScript library for building user interfaces.",
5
5
  "main": "lib/index.js",
6
6
  "jsnext:main": "es/index.js",
package/src/Component.js CHANGED
@@ -507,16 +507,18 @@ export default class Component extends View {
507
507
  );
508
508
  }
509
509
  });
510
- // Create output text for main template.
511
- const main = parts.join('').trim().replace(/\n/g, '');
510
+ // Create output string for main template. Add placeholders for new lines.
511
+ const main = parts.join('').trim().replace(/\n/g, Component.NEW_LINE_PLACEHOLDER);
512
512
  // Extract outer tag, attributes and inner html.
513
513
  const result = main.match(/^<([a-z]+[1-6]?)(.*?)>(.*)<\/\1>$/) || main.match(/^<([a-z]+)(.*?)\/>$/);
514
514
 
515
515
  if (result) {
516
+ // Get tag, attributes.
516
517
  tag = result[1];
517
- inner = result[3];
518
- // Parse attributes from html text into an object.
519
- attributes = extractAttributes(result[2]);
518
+ // Get inner html. Restore new lines.
519
+ inner = result[3] && result[3].replace(new RegExp(Component.NEW_LINE_PLACEHOLDER, 'g'), '\n');
520
+ // Parse attributes from html string into an object. Remove new lines.
521
+ attributes = extractAttributes(result[2].replace(new RegExp(Component.NEW_LINE_PLACEHOLDER, 'g'), ''));
520
522
  // Events to be delegated.
521
523
  events = {};
522
524
  // Filter events. To generate events object.
@@ -545,24 +547,25 @@ export default class Component extends View {
545
547
  const Current = this;
546
548
  // Create subclass for this component.
547
549
  return Current.extend({
548
- // Set events.
549
- events,
550
+ // Set root element tag.
551
+ tag,
550
552
  // Set attributes.
551
553
  attributes,
554
+ // Set events.
555
+ events,
552
556
  // Set template.
553
557
  template : {
554
558
  // Template for innerHTML of root element.
555
559
  inner,
556
560
  // Template expressions.
557
- expressions,
558
- },
559
- // Set root element tag.
560
- tag
561
+ expressions
562
+ }
561
563
  });
562
564
  }
563
565
  }
564
566
 
565
567
  Component.ID_TEMPLATE = (uid) => `rasti-component-${uid}`;
566
- Component.EXPRESSION_PLACEHOLDER_TEMPLATE = (idx) => `__RASTI_EXPRESSION{${idx}}`;
567
- Component.TRUE_PLACEHOLDER = '__RASTI_TRUE';
568
- Component.FALSE_PLACEHOLDER = '__RASTI_FALSE';
568
+ Component.EXPRESSION_PLACEHOLDER_TEMPLATE = (idx) => `__RASTI_EXPRESSION_{${idx}}__`;
569
+ Component.TRUE_PLACEHOLDER = '__RASTI_TRUE__';
570
+ Component.FALSE_PLACEHOLDER = '__RASTI_FALSE__';
571
+ Component.NEW_LINE_PLACEHOLDER = '__RASTI_NEW_LINE__';