rasti 4.0.0-alpha.2 → 4.0.0-alpha.4

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
@@ -838,7 +838,7 @@
838
838
  * You shouldn't call this method directly. It's called from the constructor.
839
839
  * You may override it if you want to use a different logic or to
840
840
  * postpone element creation.
841
- */
841
+ */
842
842
  ensureElement() {
843
843
  // Element is already present.
844
844
  if (this.el) {
@@ -1494,7 +1494,7 @@
1494
1494
  const endComment = findComment(parent, this.getEnd(), this.isComponent, startComment);
1495
1495
 
1496
1496
  this.ref = [
1497
- startComment,
1497
+ startComment,
1498
1498
  endComment
1499
1499
  ];
1500
1500
  }
@@ -1596,7 +1596,7 @@
1596
1596
  * @return {boolean} True if the element is a component root element.
1597
1597
  * @private
1598
1598
  */
1599
- const isComponent = (el) => !!el.dataset[Component.DATASET_ELEMENT] && el.dataset[Component.DATASET_ELEMENT].endsWith('-1');
1599
+ const isComponent = (el) => !!(el && el.dataset && el.dataset[Component.DATASET_ELEMENT] && el.dataset[Component.DATASET_ELEMENT].endsWith('-1'));
1600
1600
 
1601
1601
  /**
1602
1602
  * Check if an element has the Rasti data attribute.
@@ -1605,7 +1605,7 @@
1605
1605
  * @return {boolean} True if the element has the data attribute.
1606
1606
  * @private
1607
1607
  */
1608
- const isElement = (el) => !!el.dataset[Component.DATASET_ELEMENT];
1608
+ const isElement = (el) => !!(el && el.dataset && el.dataset[Component.DATASET_ELEMENT]);
1609
1609
 
1610
1610
  /**
1611
1611
  * Generate string with placeholders for interpolated expressions.
@@ -1614,7 +1614,7 @@
1614
1614
  * @return {string} String with placeholders.
1615
1615
  * @private
1616
1616
  */
1617
- const addPlaceholders = (strings, expressions) =>
1617
+ const addPlaceholders = (strings, expressions) =>
1618
1618
  strings.reduce((out, string, i) => {
1619
1619
  // Add string part.
1620
1620
  out.push(string);
@@ -1684,10 +1684,11 @@
1684
1684
  * Expand events.
1685
1685
  * @param {object} attributes Attributes object.
1686
1686
  * @param {EventsManager} eventsManager Events manager.
1687
+ * @param {Function} getDataAttribute Function to get data attribute name with uid.
1687
1688
  * @return {object} Attributes object.
1688
1689
  * @private
1689
1690
  */
1690
- const expandEvents = (attributes, eventsManager) => {
1691
+ const expandEvents = (attributes, eventsManager, getDataAttribute) => {
1691
1692
  const out = {};
1692
1693
  Object.keys(attributes).forEach(key => {
1693
1694
  // Check if key is an event listener.
@@ -1699,7 +1700,7 @@
1699
1700
  if (listener) {
1700
1701
  const index = eventsManager.addListener(listener, type);
1701
1702
  // Add event listener index.
1702
- out[Component.ATTRIBUTE_EVENT(type)] = index;
1703
+ out[getDataAttribute(type)] = index;
1703
1704
  }
1704
1705
  } else {
1705
1706
  // Add attribute.
@@ -1839,7 +1840,8 @@
1839
1840
  // Expand attributes and events.
1840
1841
  const attributes = expandEvents(
1841
1842
  expandAttributes(parsedAttributes, value => getExpressionResult(value, this)),
1842
- this.eventsManager
1843
+ this.eventsManager,
1844
+ type => Component.ATTRIBUTE_EVENT(type, this.uid)
1843
1845
  );
1844
1846
  // Extend template attributes with `options.attributes`.
1845
1847
  if (isRoot && this.attributes) {
@@ -1893,7 +1895,8 @@
1893
1895
  const getAttributes = function() {
1894
1896
  const attributes = expandEvents(
1895
1897
  expandAttributes(parsedAttributes, value => getExpressionResult(value, this)),
1896
- this.eventsManager
1898
+ this.eventsManager,
1899
+ type => Component.ATTRIBUTE_EVENT(type, this.uid)
1897
1900
  );
1898
1901
 
1899
1902
  return attributes;
@@ -2038,7 +2041,7 @@
2038
2041
  const events = {};
2039
2042
  // Create events object.
2040
2043
  this.eventsManager.types.forEach(type => {
2041
- const dataAttribute = Component.ATTRIBUTE_EVENT(type);
2044
+ const dataAttribute = Component.ATTRIBUTE_EVENT(type, this.uid);
2042
2045
  // Create a listener function that gets the listener index from the data attribute and calls the listener.
2043
2046
  const listener = function(event, component, matched) {
2044
2047
  // Get the listener index from the data attribute.
@@ -2135,7 +2138,7 @@
2135
2138
  this.el = this.children[0].el;
2136
2139
  } else {
2137
2140
  // Search for every element in template using getSelector
2138
- this.template.elements.forEach((element, index) => {
2141
+ this.template.elements.forEach((element, index) => {
2139
2142
  if (index === 0) {
2140
2143
  element.hydrate(parent);
2141
2144
  if (this.el) element.ref = this.el;
@@ -2726,7 +2729,7 @@
2726
2729
  * Attributes used to identify elements and events.
2727
2730
  */
2728
2731
  Component.ATTRIBUTE_ELEMENT = 'data-rasti-el';
2729
- Component.ATTRIBUTE_EVENT = (type) => `data-rasti-on-${type}`;
2732
+ Component.ATTRIBUTE_EVENT = (type, uid) => `data-rasti-on-${type}-${uid}`;
2730
2733
 
2731
2734
  /*
2732
2735
  * Dataset attribute used to identify elements.
package/dist/rasti.min.js CHANGED
@@ -1 +1 @@
1
- !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).Rasti={})}(this,(function(t){"use strict";function e(t){if("function"!=typeof t)throw new TypeError("Listener must be a function")}class s{on(t,s){return e(s),this.listeners||(this.listeners={}),this.listeners[t]||(this.listeners[t]=[]),this.listeners[t].push(s),()=>this.off(t,s)}once(t,s){e(s);const i=(...e)=>{s(...e),this.off(t,i)};return this.on(t,i)}off(t,e){this.listeners&&(t?this.listeners[t]&&(e?(this.listeners[t]=this.listeners[t].filter((t=>t!==e)),this.listeners[t].length||delete this.listeners[t]):delete this.listeners[t],Object.keys(this.listeners).length||delete this.listeners):delete this.listeners)}emit(t,...e){this.listeners&&this.listeners[t]&&this.listeners[t].slice().forEach((t=>t(...e)))}listenTo(t,e,s){return t.on(e,s),this.listeningTo||(this.listeningTo=[]),this.listeningTo.push({emitter:t,type:e,listener:s}),()=>this.stopListening(t,e,s)}listenToOnce(t,s,i){e(i);const n=(...e)=>{i(...e),this.stopListening(t,s,n)};return this.listenTo(t,s,n)}stopListening(t,e,s){this.listeningTo&&(this.listeningTo=this.listeningTo.filter((i=>!(!t||t===i.emitter&&!e||t===i.emitter&&e===i.type&&!s||t===i.emitter&&e===i.type&&s===i.listener)||(i.emitter.off(i.type,i.listener),!1))),this.listeningTo.length||delete this.listeningTo)}}const i=(t,e,...s)=>"function"!=typeof t?t:t.apply(e,s);class n extends s{constructor(){super(),this.preinitialize.apply(this,arguments),this.attributes=Object.assign({},i(this.defaults,this),this.parse.apply(this,arguments)),this.previous={},Object.keys(this.attributes).forEach(this.defineAttribute.bind(this))}preinitialize(){}defineAttribute(t){Object.defineProperty(this,`${this.constructor.attributePrefix}${t}`,{get:()=>this.get(t),set:e=>{this.set(t,e)}})}get(t){return this.attributes[t]}set(t,e,...s){let i,n;"object"==typeof t?(i=t,n=[e,...s]):(i={[t]:e},n=s);const r=this._changing;this._changing=!0;const h={};r||(this.previous=Object.assign({},this.attributes)),Object.keys(i).forEach((t=>{i[t]!==this.attributes[t]&&(h[t]=i[t],this.attributes[t]=i[t])}));const o=Object.keys(h);if(o.length&&(this._pending=["change",this,h,...n]),o.forEach((t=>{this.emit(`change:${t}`,this,i[t],...n)})),r)return this;for(;this._pending;){const t=this._pending;this._pending=null,this.emit.apply(this,t)}return this._pending=null,this._changing=!1,this}parse(t){return t}toJSON(){return Object.assign({},this.attributes)}}n.attributePrefix="";const r=["el","tag","attributes","events","model","template","onDestroy"];class h extends s{constructor(t={}){super(),this.preinitialize.apply(this,arguments),this.delegatedEventListeners=[],this.children=[],this.destroyQueue=[],this.viewOptions=[],r.forEach((e=>{e in t&&(this[e]=t[e],this.viewOptions.push(e))})),this.ensureUid(),this.ensureElement()}preinitialize(){}$(t){return this.el.querySelector(t)}$$(t){return this.el.querySelectorAll(t)}destroy(){return this.destroyChildren(),this.undelegateEvents(),this.stopListening(),this.off(),this.destroyQueue.forEach((t=>t())),this.destroyQueue=[],this.onDestroy.apply(this,arguments),this.destroyed=!0,this}onDestroy(){}addChild(t){return this.children.push(t),t}destroyChildren(){this.children.forEach((t=>t.destroy())),this.children=[]}ensureUid(){this.uid||(this.uid="r-"+ ++h.uid)}ensureElement(){if(this.el)this.el=i(this.el,this);else{const t=i(this.tag,this),e=i(this.attributes,this);this.el=this.createElement(t,e)}this.delegateEvents()}createElement(t="div",e={}){let s=document.createElement(t);return Object.keys(e).forEach((t=>s.setAttribute(t,e[t]))),s}removeElement(){return this.el.parentNode.removeChild(this.el),this}delegateEvents(t){if(t||(t=i(this.events,this)),!t)return this;this.delegatedEventListeners.length&&this.undelegateEvents();let s={};return Object.keys(t).forEach((i=>{const n=i.split(" "),r=n.shift(),h=n.join(" ");let o=t[i];"string"==typeof o&&(o=this[o]),e(o),s[r]||(s[r]=[]),s[r].push({selector:h,listener:o})})),Object.keys(s).forEach((t=>{const e=e=>{s[t].forEach((({selector:t,listener:s})=>{if(!t)return void s.call(this,e,this,this.el);let i=e.target;for(;i&&i!==this.el;)i.matches&&i.matches(t)&&s.call(this,e,this,i),i=i.parentElement}))};this.delegatedEventListeners.push({type:t,listener:e}),this.el.addEventListener(t,e)})),this}undelegateEvents(){return this.delegatedEventListeners.forEach((({type:t,listener:e})=>{this.el.removeEventListener(t,e)})),this.delegatedEventListeners=[],this}render(){return this.template&&(this.el.innerHTML=this.template(this.model)),this}static sanitize(t){return`${t}`.replace(/[&<>"']/g,(t=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#039;"}[t])))}}h.uid=0;class o{constructor(t){this.value=t}toString(){return this.value}}class a{constructor(t){this.items=t}}class l{constructor(t,e){this.interpolationUid=t,this.result=e}}class c{constructor(){this.listeners=[],this.types=new Set,this.previousSize=0}addListener(t,e){return this.types.add(e),this.listeners.push(t),this.listeners.length-1}reset(){this.listeners=[],this.previousSize=this.types.size}hasPendingTypes(){return this.types.size>this.previousSize}}class u{constructor(){}reset(){this.paused=0,this.previous=this.tracked||new Map,this.tracked=new Map,this.positionStack=[0]}push(){this.positionStack.push(0)}pop(){this.positionStack.pop()}increment(){this.positionStack[this.positionStack.length-1]++}pause(){this.paused++}resume(){this.paused--}getPath(){return this.positionStack.join("-")}track(t){return 0===this.paused&&this.tracked.set(this.getPath(),t),t}findRecyclable(t){const e=this.previous.get(this.getPath());return e&&e.constructor===t&&!e.key?e:null}}const d=["value","checked","selected"];class p{constructor(t){this.getSelector=t.getSelector,this.getAttributes=t.getAttributes,this.previousAttributes={}}hydrate(t){this.ref=t.querySelector(this.getSelector())}update(){const t=this.getAttributes(),{remove:e,add:s}=function(t,e={}){const s={},i=[];return Object.keys(t).forEach((i=>{let n=t[i];n!==e[i]&&(!0===n?s[i]="":!1!==n&&(null==n&&(n=""),s[i]=n))})),Object.keys(e).forEach((s=>{(!(s in t)||e[s]!==t[s]&&!1===t[s])&&i.push(s)})),{add:s,remove:i}}(t,this.previousAttributes);this.previousAttributes=t,e.forEach((t=>{this.ref.removeAttribute(t),d.includes(t)&&t in this.ref&&(this.ref[t]="value"===t&&"")})),Object.keys(s).forEach((t=>{const e=s[t];this.ref.setAttribute(t,e),d.includes(t)&&t in this.ref&&(this.ref[t]="value"===t?e:!1!==e&&"false"!==e)}))}}const f=["value","checked","selected"];function g(t,e){t.nodeType===e.nodeType?t.nodeType!==Node.TEXT_NODE?t.tagName===e.tagName?(((t,e)=>{const s=e.attributes,i=t.attributes,n=new Set;for(let e=0,i=s.length;e<i;e++){const{name:i,value:r}=s[e];n.add(i),t.getAttribute(i)!==r&&t.setAttribute(i,r)}for(let e=i.length-1;e>=0;e--){const{name:s}=i[e];n.has(s)||t.removeAttribute(s)}for(let s=0,i=f.length;s<i;s++){const i=f[s];i in t&&t[i]!==e[i]&&(t[i]=e[i])}})(t,e),((t,e)=>{const s=t.childNodes,i=e.childNodes,n=s.length;if(n!==i.length)return!1;for(let t=0;t<n;t++)if(!s[t].isEqualNode(i[t]))return!1;return!0})(t,e)||((t,e)=>{const s=Array.from(e.childNodes);t.replaceChildren(...s)})(t,e)):t.replaceWith(e):t.nodeValue!==e.nodeValue&&(t.nodeValue=e.nodeValue):t.replaceWith(e)}function E(t,e,s=(()=>!1),i){let n=i||t.firstChild;for(;n;){if(n.nodeType===Node.COMMENT_NODE&&n.data.trim()===e)return n;if(n.nodeType!==Node.ELEMENT_NODE||s(n)||!n.firstChild){for(;n&&!n.nextSibling;)if(n=n.parentNode,!n||n===t)return null;n&&(n=n.nextSibling)}else n=n.firstChild}return null}class m{constructor(t){this.getStart=t.getStart,this.getEnd=t.getEnd,this.expression=t.expression,this.isComponent=t.isComponent,this.isElement=t.isElement}hydrate(t){const e=E(t,this.getStart(),this.isComponent),s=E(t,this.getEnd(),this.isComponent,e);this.ref=[e,s]}update(t){const[e,s]=this.ref,i=e.nextSibling,n=i.nextSibling===s,r=i==s,h=t.children;if(n&&1===h.length&&!this.isElement(i))g(i,h[0]);else if(r)s.parentNode.insertBefore(t,s);else{const i=document.createRange();i.setStartAfter(e),i.setEndBefore(s),i.deleteContents(),i.insertNode(t)}}}const y=t=>t.reduce(((t,e)=>(Array.isArray(e)?t.push(...y(e)):t.push(e),t)),[]);function T(t){const e=document.createElement("template");return e.innerHTML=`${t}`.trim(),e.content}function b(t){const e=[];return Object.keys(t).forEach((s=>{let i=t[s];!0===i?e.push(s):!1!==i&&(null==i&&(i=""),e.push(`${s}="${i}"`))})),e.join(" ")}const A=(t,e)=>i(t,e,e),v=t=>!!t.dataset[j.DATASET_ELEMENT]&&t.dataset[j.DATASET_ELEMENT].endsWith("-1"),R=t=>!!t.dataset[j.DATASET_ELEMENT],M=(t,e)=>t.reduce(((t,s,i)=>(t.push(s),void 0!==e[i]&&t.push(j.PLACEHOLDER(i)),t)),[]).join(""),L=(t,e)=>{const s=j.PLACEHOLDER("(\\d+)"),i=new RegExp(`${s}`,"g"),n=[];let r,h=0;for(;null!==(r=i.exec(t));){const s=t.slice(h,r.index);n.push(j.markAsSafeHTML(s),e[r[1]]),h=r.index+r[0].length}return n.push(j.markAsSafeHTML(t.slice(h))),n},C=(t,e)=>t.reduce(((t,s)=>{const i=e(s[0]);if(1===s.length)"object"==typeof i?t=Object.assign(t,i):"string"==typeof i&&(t[i]=!0);else{const n=s[2]?e(s[1]):s[1];t[i]=n}return t}),{}),S=(t,e)=>{const s={};return Object.keys(t).forEach((i=>{const n=i.match(/on(([A-Z]{1}[a-z]+)+)/);if(n&&n[1]){const r=n[1].toLowerCase(),h=t[i];if(h){const t=e.addListener(h,r);s[j.ATTRIBUTE_EVENT(r)]=t}}else s[i]=t[i]})),s},$=(t,e,s=!1)=>{const i=j.PLACEHOLDER("(\\d+)"),n=new Map;return s||(t=t.replace(new RegExp(i,"g"),((t,s)=>{const i=e[s];if(i&&i.prototype instanceof j){if(n.has(i))return n.get(i);n.set(i,t)}return t}))),t.replace(new RegExp(`<(${i})([^>]*)>([\\s\\S]*?)</\\1>|<(${i})([^>]*)/>`,"g"),((t,s,i,n,r,h,o,l)=>{let c,u,d;if(s?(c=e[i],u=n):(c=void 0!==o?e[o]:h,u=l),!(c.prototype instanceof j))return t;if(s){const t=$(r,e,!0),s=k(t,e);d=L(s,e)}const p=w(u,e);return e.push((function(){const t=C(p,(t=>A(t,this)));return d&&(t.renderChildren=()=>new a(d.map((t=>A(t,this))))),c.mount(t)})),j.PLACEHOLDER(e.length-1)}))},O=(t,e)=>{const s=j.PLACEHOLDER("(?:\\d+)");return t.replace(new RegExp(`<(${s}|[a-z]+[1-6]?)(?:\\s*)((?:"[^"]*"|'[^']*'|[^>])*)(/?>)`,"gi"),e)},x=(t,e,s)=>{const n=j.PLACEHOLDER("(?:\\d+)");if(t.match(new RegExp(`^\\s*${n}\\s*$`)))return t;if(!t.match(new RegExp(`^\\s*<([a-z]+[1-6]?|${n})([^>]*)>([\\s\\S]*?)</(\\1|${n})>\\s*$|^\\s*<([a-z]+[1-6]?|${n})([^>]*)/>\\s*$`)))throw new SyntaxError(`Template must have a single root element or be a container component: "${t.trim()}"`);let r=0;return O(t,((t,h,o,a)=>{const l=0===r,c=++r;if(!l&&!o.match(new RegExp(n)))return t;const u=w(o,e),d=t=>`${t}-${c}`,p=function(){const t=S(C(u,(t=>A(t,this))),this.eventsManager);return l&&this.attributes&&Object.assign(t,i(this.attributes,this)),t[j.ATTRIBUTE_ELEMENT]=d(this.uid),t};s.push({getSelector:function(){return`[${j.ATTRIBUTE_ELEMENT}="${d(this.uid)}"]`},getAttributes:p}),e.push((function(){const t=p.call(this);return j.markAsSafeHTML(b(t))}));return`<${h} ${j.PLACEHOLDER(e.length-1)}${a}`}))},k=(t,e)=>{const s=j.PLACEHOLDER("(?:\\d+)");return O(t,((t,i,n,r)=>{if(!n.match(new RegExp(s)))return t;const h=w(n,e),o=function(){return S(C(h,(t=>A(t,this))),this.eventsManager)};e.push((function(){const t=o.call(this);return j.markAsSafeHTML(b(t))}));return`<${i} ${j.PLACEHOLDER(e.length-1)}${r}`}))},N=(t,e,s)=>{const i=j.PLACEHOLDER("(\\d+)");let n=0;return t.replace(new RegExp(i,"g"),(function(i,r,h){const o=t.substring(0,h);if(o.lastIndexOf("<")>o.lastIndexOf(">"))return i;const a=++n;return s.push({getStart:function(){return j.MARKER_START(`${this.uid}-${a}`)},getEnd:function(){return j.MARKER_END(`${this.uid}-${a}`)},expression:e[r]}),e.push((function(){const t=A(e[r],this),s=`${this.uid}-${a}`;return new l(s,t)})),j.PLACEHOLDER(e.length-1)}))},w=(t,e)=>{const s=j.PLACEHOLDER("(\\d+)"),i=[],n=new RegExp(`(${s}|[\\w-]+)(?:=(["']?)(?:${s}|((?:.?(?!["']?\\s+(?:\\S+)=|\\s*/?[>"']))+.))\\3)?`,"g");let r;for(;null!==(r=n.exec(t));){const[,t,s,n,h,o]=r,a=void 0!==s?e[parseInt(s,10)]:t,l=void 0!==h?e[parseInt(h,10)]:o;void 0!==l?i.push([a,l,!!n]):i.push([a])}return i},_=["key","state","onCreate","onChange","onHydrate","onMount","onRecycle","onUpdate"];class j extends h{constructor(t={}){super(...arguments),this.componentOptions=[],_.forEach((e=>{e in t&&(this[e]=t[e],this.componentOptions.push(e))}));const e={};Object.keys(t).forEach((s=>{this.viewOptions.includes(s)||this.componentOptions.includes(s)||(e[s]=t[s])})),this.props=new n(e),this.options=t,this.partial=this.partial.bind(this),this.onChange=this.onChange.bind(this),this.onCreate.apply(this,arguments)}events(){const t={};return this.eventsManager.types.forEach((s=>{const i=j.ATTRIBUTE_EVENT(s),n=function(t,s,n){const r=n.getAttribute(i);if(r){let i=this.eventsManager.listeners[parseInt(r,10)];"string"==typeof i&&(i=this[i]),e(i),i.call(this,t,s,n)}};t[`${s} [${i}]`]=n,t[s]=n})),t}ensureElement(){this.eventsManager=new c,this.pathManager=new u,this.template=i(this.template,this),this.el&&(this.el=i(this.el,this),this.toString(),this.hydrate(this.el.parentNode))}isContainer(){return 0===this.template.elements.length&&1===this.template.interpolations.length}subscribe(t,e="change",s=this.onChange){return t.on&&this.listenTo(t,e,s),this}hydrate(t){return["model","state","props"].forEach((t=>{this[t]&&this.subscribe(this[t])})),this.isContainer()?(this.template.interpolations[0].hydrate(t),this.children[0].hydrate(t),this.el=this.children[0].el):(this.template.elements.forEach(((e,s)=>{0===s?(e.hydrate(t),this.el?e.ref=this.el:this.el=e.ref):e.hydrate(this.el)})),this.delegateEvents(),this.template.interpolations.forEach((t=>t.hydrate(this.el))),this.children.forEach((t=>t.hydrate(this.el)))),this.onHydrate.call(this),this}recycle(t){return E(t,j.MARKER_RECYCLED(this.uid),v).replaceWith(...this.getNodes()),this.onRecycle.call(this),this}getRecycledMarker(){return`\x3c!--${j.MARKER_RECYCLED(this.uid)}--\x3e`}getNodes(){return this.isContainer()?[this.template.interpolations[0].ref[0],...this.children[0].getNodes(),this.template.interpolations[0].ref[1]]:[this.el]}callOnMount(){return this.children.forEach((t=>t.callOnMount())),this.onMount.call(this),this}partial(t,...e){const s=L(k($(M(t,e),e),e),e).map((t=>A(t,this)));return new a(s)}renderTemplatePart(t,e){const s=A(t,this),i=t=>{if(null!=t&&!1!==t&&!0!==t){if(t instanceof o)return t;if(t instanceof j)return e(t);if(t instanceof a){this.pathManager.push();const e=t.items.map((t=>(this.pathManager.increment(),i(t)))).join("");return this.pathManager.pop(),e}if(Array.isArray(t)){this.pathManager.pause();const e=y(t).map(i).join("");return this.pathManager.resume(),e}if(t instanceof l){this.pathManager.increment();const e=`\x3c!--${j.MARKER_START(t.interpolationUid)}--\x3e`,s=`\x3c!--${j.MARKER_END(t.interpolationUid)}--\x3e`;return`${e}${i(t.result)}${s}`}return j.sanitize(t)}return""};return`${i(s)}`}toString(){this.destroyChildren(),this.eventsManager.reset(),this.pathManager.reset();const t=t=>(this.pathManager.track(t),this.addChild(t));return this.template.parts.map((e=>this.renderTemplatePart(e,t))).join("")}render(){if(this.destroyed)return this;if(!this.el){const t=T(this);return this.hydrate(t),this}this.eventsManager.reset(),this.pathManager.reset();const t=this.isContainer()?null:document.activeElement;this.template.elements.forEach((t=>t.update()));const e=this.children;return this.children=[],this.template.interpolations.forEach((t=>{const s=[],i=[];this.pathManager.increment();const n=T(this.renderTemplatePart(t.expression,(t=>{let n=t,r=null;return r=t.key?e.find((e=>e.key===t.key)):this.pathManager.findRecyclable(t.constructor),r?(n=r.getRecycledMarker(),i.push([r,t]),r.key||this.pathManager.track(r)):(s.push(t),this.pathManager.track(t)),n})));i.forEach((([t,e])=>{this.addChild(t).recycle(n),t.props.set(e.props.toJSON()),e.destroy()})),s.forEach((t=>this.addChild(t).hydrate(n))),t.update(n)})),this.children.forEach((t=>t.callOnMount())),e.forEach((t=>{this.children.indexOf(t)<0&&t.destroy()})),this.isContainer()?this.el=this.children[0].el:this.eventsManager.hasPendingTypes()&&this.delegateEvents(),t&&this.el.contains(t)&&t.focus(),this.onUpdate.call(this),this}onCreate(){}onChange(){this.render()}onHydrate(){}onMount(){}onRecycle(){}onUpdate(){}onDestroy(){}static markAsSafeHTML(t){return new o(t)}static extend(t){const e=this;class s extends e{}return Object.assign(s.prototype,"function"==typeof t?t(e.prototype):t),s}static mount(t,e,s){const i=new this(t);return e&&(s?(i.toString(),i.hydrate(e)):e.append(...i.render().getNodes()),i.callOnMount()),i}static create(t,...e){"function"==typeof t&&(e=[t],t=["",""]);const s=[],i=[],n=L(N(x($(M(t,e).trim(),e),e,s),e,i),e);return this.extend({template(){return{elements:s.map((t=>new p({getSelector:t.getSelector.bind(this),getAttributes:t.getAttributes.bind(this)}))),interpolations:i.map((t=>new m({getStart:t.getStart.bind(this),getEnd:t.getEnd.bind(this),expression:t.expression,isComponent:v,isElement:R}))),parts:n}}})}}j.ATTRIBUTE_ELEMENT="data-rasti-el",j.ATTRIBUTE_EVENT=t=>`data-rasti-on-${t}`,j.DATASET_ELEMENT="rastiEl",j.PLACEHOLDER=t=>`__RASTI-${t}__`,j.MARKER_RECYCLED=t=>`rasti-recycled-${t}`,j.MARKER_START=t=>`rasti-start-${t}`,j.MARKER_END=t=>`rasti-end-${t}`;var D=j.create`<div></div>`;t.Component=D,t.Emitter=s,t.Model=n,t.View=h}));
1
+ !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).Rasti={})}(this,(function(t){"use strict";function e(t){if("function"!=typeof t)throw new TypeError("Listener must be a function")}class s{on(t,s){return e(s),this.listeners||(this.listeners={}),this.listeners[t]||(this.listeners[t]=[]),this.listeners[t].push(s),()=>this.off(t,s)}once(t,s){e(s);const i=(...e)=>{s(...e),this.off(t,i)};return this.on(t,i)}off(t,e){this.listeners&&(t?this.listeners[t]&&(e?(this.listeners[t]=this.listeners[t].filter((t=>t!==e)),this.listeners[t].length||delete this.listeners[t]):delete this.listeners[t],Object.keys(this.listeners).length||delete this.listeners):delete this.listeners)}emit(t,...e){this.listeners&&this.listeners[t]&&this.listeners[t].slice().forEach((t=>t(...e)))}listenTo(t,e,s){return t.on(e,s),this.listeningTo||(this.listeningTo=[]),this.listeningTo.push({emitter:t,type:e,listener:s}),()=>this.stopListening(t,e,s)}listenToOnce(t,s,i){e(i);const n=(...e)=>{i(...e),this.stopListening(t,s,n)};return this.listenTo(t,s,n)}stopListening(t,e,s){this.listeningTo&&(this.listeningTo=this.listeningTo.filter((i=>!(!t||t===i.emitter&&!e||t===i.emitter&&e===i.type&&!s||t===i.emitter&&e===i.type&&s===i.listener)||(i.emitter.off(i.type,i.listener),!1))),this.listeningTo.length||delete this.listeningTo)}}const i=(t,e,...s)=>"function"!=typeof t?t:t.apply(e,s);class n extends s{constructor(){super(),this.preinitialize.apply(this,arguments),this.attributes=Object.assign({},i(this.defaults,this),this.parse.apply(this,arguments)),this.previous={},Object.keys(this.attributes).forEach(this.defineAttribute.bind(this))}preinitialize(){}defineAttribute(t){Object.defineProperty(this,`${this.constructor.attributePrefix}${t}`,{get:()=>this.get(t),set:e=>{this.set(t,e)}})}get(t){return this.attributes[t]}set(t,e,...s){let i,n;"object"==typeof t?(i=t,n=[e,...s]):(i={[t]:e},n=s);const r=this._changing;this._changing=!0;const h={};r||(this.previous=Object.assign({},this.attributes)),Object.keys(i).forEach((t=>{i[t]!==this.attributes[t]&&(h[t]=i[t],this.attributes[t]=i[t])}));const o=Object.keys(h);if(o.length&&(this._pending=["change",this,h,...n]),o.forEach((t=>{this.emit(`change:${t}`,this,i[t],...n)})),r)return this;for(;this._pending;){const t=this._pending;this._pending=null,this.emit.apply(this,t)}return this._pending=null,this._changing=!1,this}parse(t){return t}toJSON(){return Object.assign({},this.attributes)}}n.attributePrefix="";const r=["el","tag","attributes","events","model","template","onDestroy"];class h extends s{constructor(t={}){super(),this.preinitialize.apply(this,arguments),this.delegatedEventListeners=[],this.children=[],this.destroyQueue=[],this.viewOptions=[],r.forEach((e=>{e in t&&(this[e]=t[e],this.viewOptions.push(e))})),this.ensureUid(),this.ensureElement()}preinitialize(){}$(t){return this.el.querySelector(t)}$$(t){return this.el.querySelectorAll(t)}destroy(){return this.destroyChildren(),this.undelegateEvents(),this.stopListening(),this.off(),this.destroyQueue.forEach((t=>t())),this.destroyQueue=[],this.onDestroy.apply(this,arguments),this.destroyed=!0,this}onDestroy(){}addChild(t){return this.children.push(t),t}destroyChildren(){this.children.forEach((t=>t.destroy())),this.children=[]}ensureUid(){this.uid||(this.uid="r-"+ ++h.uid)}ensureElement(){if(this.el)this.el=i(this.el,this);else{const t=i(this.tag,this),e=i(this.attributes,this);this.el=this.createElement(t,e)}this.delegateEvents()}createElement(t="div",e={}){let s=document.createElement(t);return Object.keys(e).forEach((t=>s.setAttribute(t,e[t]))),s}removeElement(){return this.el.parentNode.removeChild(this.el),this}delegateEvents(t){if(t||(t=i(this.events,this)),!t)return this;this.delegatedEventListeners.length&&this.undelegateEvents();let s={};return Object.keys(t).forEach((i=>{const n=i.split(" "),r=n.shift(),h=n.join(" ");let o=t[i];"string"==typeof o&&(o=this[o]),e(o),s[r]||(s[r]=[]),s[r].push({selector:h,listener:o})})),Object.keys(s).forEach((t=>{const e=e=>{s[t].forEach((({selector:t,listener:s})=>{if(!t)return void s.call(this,e,this,this.el);let i=e.target;for(;i&&i!==this.el;)i.matches&&i.matches(t)&&s.call(this,e,this,i),i=i.parentElement}))};this.delegatedEventListeners.push({type:t,listener:e}),this.el.addEventListener(t,e)})),this}undelegateEvents(){return this.delegatedEventListeners.forEach((({type:t,listener:e})=>{this.el.removeEventListener(t,e)})),this.delegatedEventListeners=[],this}render(){return this.template&&(this.el.innerHTML=this.template(this.model)),this}static sanitize(t){return`${t}`.replace(/[&<>"']/g,(t=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#039;"}[t])))}}h.uid=0;class o{constructor(t){this.value=t}toString(){return this.value}}class a{constructor(t){this.items=t}}class l{constructor(t,e){this.interpolationUid=t,this.result=e}}class c{constructor(){this.listeners=[],this.types=new Set,this.previousSize=0}addListener(t,e){return this.types.add(e),this.listeners.push(t),this.listeners.length-1}reset(){this.listeners=[],this.previousSize=this.types.size}hasPendingTypes(){return this.types.size>this.previousSize}}class u{constructor(){}reset(){this.paused=0,this.previous=this.tracked||new Map,this.tracked=new Map,this.positionStack=[0]}push(){this.positionStack.push(0)}pop(){this.positionStack.pop()}increment(){this.positionStack[this.positionStack.length-1]++}pause(){this.paused++}resume(){this.paused--}getPath(){return this.positionStack.join("-")}track(t){return 0===this.paused&&this.tracked.set(this.getPath(),t),t}findRecyclable(t){const e=this.previous.get(this.getPath());return e&&e.constructor===t&&!e.key?e:null}}const d=["value","checked","selected"];class p{constructor(t){this.getSelector=t.getSelector,this.getAttributes=t.getAttributes,this.previousAttributes={}}hydrate(t){this.ref=t.querySelector(this.getSelector())}update(){const t=this.getAttributes(),{remove:e,add:s}=function(t,e={}){const s={},i=[];return Object.keys(t).forEach((i=>{let n=t[i];n!==e[i]&&(!0===n?s[i]="":!1!==n&&(null==n&&(n=""),s[i]=n))})),Object.keys(e).forEach((s=>{(!(s in t)||e[s]!==t[s]&&!1===t[s])&&i.push(s)})),{add:s,remove:i}}(t,this.previousAttributes);this.previousAttributes=t,e.forEach((t=>{this.ref.removeAttribute(t),d.includes(t)&&t in this.ref&&(this.ref[t]="value"===t&&"")})),Object.keys(s).forEach((t=>{const e=s[t];this.ref.setAttribute(t,e),d.includes(t)&&t in this.ref&&(this.ref[t]="value"===t?e:!1!==e&&"false"!==e)}))}}const f=["value","checked","selected"];function E(t,e){t.nodeType===e.nodeType?t.nodeType!==Node.TEXT_NODE?t.tagName===e.tagName?(((t,e)=>{const s=e.attributes,i=t.attributes,n=new Set;for(let e=0,i=s.length;e<i;e++){const{name:i,value:r}=s[e];n.add(i),t.getAttribute(i)!==r&&t.setAttribute(i,r)}for(let e=i.length-1;e>=0;e--){const{name:s}=i[e];n.has(s)||t.removeAttribute(s)}for(let s=0,i=f.length;s<i;s++){const i=f[s];i in t&&t[i]!==e[i]&&(t[i]=e[i])}})(t,e),((t,e)=>{const s=t.childNodes,i=e.childNodes,n=s.length;if(n!==i.length)return!1;for(let t=0;t<n;t++)if(!s[t].isEqualNode(i[t]))return!1;return!0})(t,e)||((t,e)=>{const s=Array.from(e.childNodes);t.replaceChildren(...s)})(t,e)):t.replaceWith(e):t.nodeValue!==e.nodeValue&&(t.nodeValue=e.nodeValue):t.replaceWith(e)}function g(t,e,s=(()=>!1),i){let n=i||t.firstChild;for(;n;){if(n.nodeType===Node.COMMENT_NODE&&n.data.trim()===e)return n;if(n.nodeType!==Node.ELEMENT_NODE||s(n)||!n.firstChild){for(;n&&!n.nextSibling;)if(n=n.parentNode,!n||n===t)return null;n&&(n=n.nextSibling)}else n=n.firstChild}return null}class m{constructor(t){this.getStart=t.getStart,this.getEnd=t.getEnd,this.expression=t.expression,this.isComponent=t.isComponent,this.isElement=t.isElement}hydrate(t){const e=g(t,this.getStart(),this.isComponent),s=g(t,this.getEnd(),this.isComponent,e);this.ref=[e,s]}update(t){const[e,s]=this.ref,i=e.nextSibling,n=i.nextSibling===s,r=i==s,h=t.children;if(n&&1===h.length&&!this.isElement(i))E(i,h[0]);else if(r)s.parentNode.insertBefore(t,s);else{const i=document.createRange();i.setStartAfter(e),i.setEndBefore(s),i.deleteContents(),i.insertNode(t)}}}const y=t=>t.reduce(((t,e)=>(Array.isArray(e)?t.push(...y(e)):t.push(e),t)),[]);function T(t){const e=document.createElement("template");return e.innerHTML=`${t}`.trim(),e.content}function b(t){const e=[];return Object.keys(t).forEach((s=>{let i=t[s];!0===i?e.push(s):!1!==i&&(null==i&&(i=""),e.push(`${s}="${i}"`))})),e.join(" ")}const A=(t,e)=>i(t,e,e),v=t=>!!(t&&t.dataset&&t.dataset[j.DATASET_ELEMENT]&&t.dataset[j.DATASET_ELEMENT].endsWith("-1")),R=t=>!!(t&&t.dataset&&t.dataset[j.DATASET_ELEMENT]),M=(t,e)=>t.reduce(((t,s,i)=>(t.push(s),void 0!==e[i]&&t.push(j.PLACEHOLDER(i)),t)),[]).join(""),L=(t,e)=>{const s=j.PLACEHOLDER("(\\d+)"),i=new RegExp(`${s}`,"g"),n=[];let r,h=0;for(;null!==(r=i.exec(t));){const s=t.slice(h,r.index);n.push(j.markAsSafeHTML(s),e[r[1]]),h=r.index+r[0].length}return n.push(j.markAsSafeHTML(t.slice(h))),n},$=(t,e)=>t.reduce(((t,s)=>{const i=e(s[0]);if(1===s.length)"object"==typeof i?t=Object.assign(t,i):"string"==typeof i&&(t[i]=!0);else{const n=s[2]?e(s[1]):s[1];t[i]=n}return t}),{}),C=(t,e,s)=>{const i={};return Object.keys(t).forEach((n=>{const r=n.match(/on(([A-Z]{1}[a-z]+)+)/);if(r&&r[1]){const h=r[1].toLowerCase(),o=t[n];if(o){const t=e.addListener(o,h);i[s(h)]=t}}else i[n]=t[n]})),i},S=(t,e,s=!1)=>{const i=j.PLACEHOLDER("(\\d+)"),n=new Map;return s||(t=t.replace(new RegExp(i,"g"),((t,s)=>{const i=e[s];if(i&&i.prototype instanceof j){if(n.has(i))return n.get(i);n.set(i,t)}return t}))),t.replace(new RegExp(`<(${i})([^>]*)>([\\s\\S]*?)</\\1>|<(${i})([^>]*)/>`,"g"),((t,s,i,n,r,h,o,l)=>{let c,u,d;if(s?(c=e[i],u=n):(c=void 0!==o?e[o]:h,u=l),!(c.prototype instanceof j))return t;if(s){const t=S(r,e,!0),s=k(t,e);d=L(s,e)}const p=w(u,e);return e.push((function(){const t=$(p,(t=>A(t,this)));return d&&(t.renderChildren=()=>new a(d.map((t=>A(t,this))))),c.mount(t)})),j.PLACEHOLDER(e.length-1)}))},O=(t,e)=>{const s=j.PLACEHOLDER("(?:\\d+)");return t.replace(new RegExp(`<(${s}|[a-z]+[1-6]?)(?:\\s*)((?:"[^"]*"|'[^']*'|[^>])*)(/?>)`,"gi"),e)},x=(t,e,s)=>{const n=j.PLACEHOLDER("(?:\\d+)");if(t.match(new RegExp(`^\\s*${n}\\s*$`)))return t;if(!t.match(new RegExp(`^\\s*<([a-z]+[1-6]?|${n})([^>]*)>([\\s\\S]*?)</(\\1|${n})>\\s*$|^\\s*<([a-z]+[1-6]?|${n})([^>]*)/>\\s*$`)))throw new SyntaxError(`Template must have a single root element or be a container component: "${t.trim()}"`);let r=0;return O(t,((t,h,o,a)=>{const l=0===r,c=++r;if(!l&&!o.match(new RegExp(n)))return t;const u=w(o,e),d=t=>`${t}-${c}`,p=function(){const t=C($(u,(t=>A(t,this))),this.eventsManager,(t=>j.ATTRIBUTE_EVENT(t,this.uid)));return l&&this.attributes&&Object.assign(t,i(this.attributes,this)),t[j.ATTRIBUTE_ELEMENT]=d(this.uid),t};s.push({getSelector:function(){return`[${j.ATTRIBUTE_ELEMENT}="${d(this.uid)}"]`},getAttributes:p}),e.push((function(){const t=p.call(this);return j.markAsSafeHTML(b(t))}));return`<${h} ${j.PLACEHOLDER(e.length-1)}${a}`}))},k=(t,e)=>{const s=j.PLACEHOLDER("(?:\\d+)");return O(t,((t,i,n,r)=>{if(!n.match(new RegExp(s)))return t;const h=w(n,e),o=function(){return C($(h,(t=>A(t,this))),this.eventsManager,(t=>j.ATTRIBUTE_EVENT(t,this.uid)))};e.push((function(){const t=o.call(this);return j.markAsSafeHTML(b(t))}));return`<${i} ${j.PLACEHOLDER(e.length-1)}${r}`}))},N=(t,e,s)=>{const i=j.PLACEHOLDER("(\\d+)");let n=0;return t.replace(new RegExp(i,"g"),(function(i,r,h){const o=t.substring(0,h);if(o.lastIndexOf("<")>o.lastIndexOf(">"))return i;const a=++n;return s.push({getStart:function(){return j.MARKER_START(`${this.uid}-${a}`)},getEnd:function(){return j.MARKER_END(`${this.uid}-${a}`)},expression:e[r]}),e.push((function(){const t=A(e[r],this),s=`${this.uid}-${a}`;return new l(s,t)})),j.PLACEHOLDER(e.length-1)}))},w=(t,e)=>{const s=j.PLACEHOLDER("(\\d+)"),i=[],n=new RegExp(`(${s}|[\\w-]+)(?:=(["']?)(?:${s}|((?:.?(?!["']?\\s+(?:\\S+)=|\\s*/?[>"']))+.))\\3)?`,"g");let r;for(;null!==(r=n.exec(t));){const[,t,s,n,h,o]=r,a=void 0!==s?e[parseInt(s,10)]:t,l=void 0!==h?e[parseInt(h,10)]:o;void 0!==l?i.push([a,l,!!n]):i.push([a])}return i},_=["key","state","onCreate","onChange","onHydrate","onMount","onRecycle","onUpdate"];class j extends h{constructor(t={}){super(...arguments),this.componentOptions=[],_.forEach((e=>{e in t&&(this[e]=t[e],this.componentOptions.push(e))}));const e={};Object.keys(t).forEach((s=>{this.viewOptions.includes(s)||this.componentOptions.includes(s)||(e[s]=t[s])})),this.props=new n(e),this.options=t,this.partial=this.partial.bind(this),this.onChange=this.onChange.bind(this),this.onCreate.apply(this,arguments)}events(){const t={};return this.eventsManager.types.forEach((s=>{const i=j.ATTRIBUTE_EVENT(s,this.uid),n=function(t,s,n){const r=n.getAttribute(i);if(r){let i=this.eventsManager.listeners[parseInt(r,10)];"string"==typeof i&&(i=this[i]),e(i),i.call(this,t,s,n)}};t[`${s} [${i}]`]=n,t[s]=n})),t}ensureElement(){this.eventsManager=new c,this.pathManager=new u,this.template=i(this.template,this),this.el&&(this.el=i(this.el,this),this.toString(),this.hydrate(this.el.parentNode))}isContainer(){return 0===this.template.elements.length&&1===this.template.interpolations.length}subscribe(t,e="change",s=this.onChange){return t.on&&this.listenTo(t,e,s),this}hydrate(t){return["model","state","props"].forEach((t=>{this[t]&&this.subscribe(this[t])})),this.isContainer()?(this.template.interpolations[0].hydrate(t),this.children[0].hydrate(t),this.el=this.children[0].el):(this.template.elements.forEach(((e,s)=>{0===s?(e.hydrate(t),this.el?e.ref=this.el:this.el=e.ref):e.hydrate(this.el)})),this.delegateEvents(),this.template.interpolations.forEach((t=>t.hydrate(this.el))),this.children.forEach((t=>t.hydrate(this.el)))),this.onHydrate.call(this),this}recycle(t){return g(t,j.MARKER_RECYCLED(this.uid),v).replaceWith(...this.getNodes()),this.onRecycle.call(this),this}getRecycledMarker(){return`\x3c!--${j.MARKER_RECYCLED(this.uid)}--\x3e`}getNodes(){return this.isContainer()?[this.template.interpolations[0].ref[0],...this.children[0].getNodes(),this.template.interpolations[0].ref[1]]:[this.el]}callOnMount(){return this.children.forEach((t=>t.callOnMount())),this.onMount.call(this),this}partial(t,...e){const s=L(k(S(M(t,e),e),e),e).map((t=>A(t,this)));return new a(s)}renderTemplatePart(t,e){const s=A(t,this),i=t=>{if(null!=t&&!1!==t&&!0!==t){if(t instanceof o)return t;if(t instanceof j)return e(t);if(t instanceof a){this.pathManager.push();const e=t.items.map((t=>(this.pathManager.increment(),i(t)))).join("");return this.pathManager.pop(),e}if(Array.isArray(t)){this.pathManager.pause();const e=y(t).map(i).join("");return this.pathManager.resume(),e}if(t instanceof l){this.pathManager.increment();const e=`\x3c!--${j.MARKER_START(t.interpolationUid)}--\x3e`,s=`\x3c!--${j.MARKER_END(t.interpolationUid)}--\x3e`;return`${e}${i(t.result)}${s}`}return j.sanitize(t)}return""};return`${i(s)}`}toString(){this.destroyChildren(),this.eventsManager.reset(),this.pathManager.reset();const t=t=>(this.pathManager.track(t),this.addChild(t));return this.template.parts.map((e=>this.renderTemplatePart(e,t))).join("")}render(){if(this.destroyed)return this;if(!this.el){const t=T(this);return this.hydrate(t),this}this.eventsManager.reset(),this.pathManager.reset();const t=this.isContainer()?null:document.activeElement;this.template.elements.forEach((t=>t.update()));const e=this.children;return this.children=[],this.template.interpolations.forEach((t=>{const s=[],i=[];this.pathManager.increment();const n=T(this.renderTemplatePart(t.expression,(t=>{let n=t,r=null;return r=t.key?e.find((e=>e.key===t.key)):this.pathManager.findRecyclable(t.constructor),r?(n=r.getRecycledMarker(),i.push([r,t]),r.key||this.pathManager.track(r)):(s.push(t),this.pathManager.track(t)),n})));i.forEach((([t,e])=>{this.addChild(t).recycle(n),t.props.set(e.props.toJSON()),e.destroy()})),s.forEach((t=>this.addChild(t).hydrate(n))),t.update(n)})),this.children.forEach((t=>t.callOnMount())),e.forEach((t=>{this.children.indexOf(t)<0&&t.destroy()})),this.isContainer()?this.el=this.children[0].el:this.eventsManager.hasPendingTypes()&&this.delegateEvents(),t&&this.el.contains(t)&&t.focus(),this.onUpdate.call(this),this}onCreate(){}onChange(){this.render()}onHydrate(){}onMount(){}onRecycle(){}onUpdate(){}onDestroy(){}static markAsSafeHTML(t){return new o(t)}static extend(t){const e=this;class s extends e{}return Object.assign(s.prototype,"function"==typeof t?t(e.prototype):t),s}static mount(t,e,s){const i=new this(t);return e&&(s?(i.toString(),i.hydrate(e)):e.append(...i.render().getNodes()),i.callOnMount()),i}static create(t,...e){"function"==typeof t&&(e=[t],t=["",""]);const s=[],i=[],n=L(N(x(S(M(t,e).trim(),e),e,s),e,i),e);return this.extend({template(){return{elements:s.map((t=>new p({getSelector:t.getSelector.bind(this),getAttributes:t.getAttributes.bind(this)}))),interpolations:i.map((t=>new m({getStart:t.getStart.bind(this),getEnd:t.getEnd.bind(this),expression:t.expression,isComponent:v,isElement:R}))),parts:n}}})}}j.ATTRIBUTE_ELEMENT="data-rasti-el",j.ATTRIBUTE_EVENT=(t,e)=>`data-rasti-on-${t}-${e}`,j.DATASET_ELEMENT="rastiEl",j.PLACEHOLDER=t=>`__RASTI-${t}__`,j.MARKER_RECYCLED=t=>`rasti-recycled-${t}`,j.MARKER_START=t=>`rasti-start-${t}`,j.MARKER_END=t=>`rasti-end-${t}`;var D=j.create`<div></div>`;t.Component=D,t.Emitter=s,t.Model=n,t.View=h}));
package/es/Component.js CHANGED
@@ -34,7 +34,7 @@ const getExpressionResult = (expression, context) => getResult(expression, conte
34
34
  * @return {boolean} True if the element is a component root element.
35
35
  * @private
36
36
  */
37
- const isComponent = (el) => !!el.dataset[Component.DATASET_ELEMENT] && el.dataset[Component.DATASET_ELEMENT].endsWith('-1');
37
+ const isComponent = (el) => !!(el && el.dataset && el.dataset[Component.DATASET_ELEMENT] && el.dataset[Component.DATASET_ELEMENT].endsWith('-1'));
38
38
 
39
39
  /**
40
40
  * Check if an element has the Rasti data attribute.
@@ -43,7 +43,7 @@ const isComponent = (el) => !!el.dataset[Component.DATASET_ELEMENT] && el.datase
43
43
  * @return {boolean} True if the element has the data attribute.
44
44
  * @private
45
45
  */
46
- const isElement = (el) => !!el.dataset[Component.DATASET_ELEMENT];
46
+ const isElement = (el) => !!(el && el.dataset && el.dataset[Component.DATASET_ELEMENT]);
47
47
 
48
48
  /**
49
49
  * Generate string with placeholders for interpolated expressions.
@@ -52,7 +52,7 @@ const isElement = (el) => !!el.dataset[Component.DATASET_ELEMENT];
52
52
  * @return {string} String with placeholders.
53
53
  * @private
54
54
  */
55
- const addPlaceholders = (strings, expressions) =>
55
+ const addPlaceholders = (strings, expressions) =>
56
56
  strings.reduce((out, string, i) => {
57
57
  // Add string part.
58
58
  out.push(string);
@@ -122,10 +122,11 @@ const expandAttributes = (attributes, getExpressionResult) => attributes.reduce(
122
122
  * Expand events.
123
123
  * @param {object} attributes Attributes object.
124
124
  * @param {EventsManager} eventsManager Events manager.
125
+ * @param {Function} getDataAttribute Function to get data attribute name with uid.
125
126
  * @return {object} Attributes object.
126
127
  * @private
127
128
  */
128
- const expandEvents = (attributes, eventsManager) => {
129
+ const expandEvents = (attributes, eventsManager, getDataAttribute) => {
129
130
  const out = {};
130
131
  Object.keys(attributes).forEach(key => {
131
132
  // Check if key is an event listener.
@@ -137,7 +138,7 @@ const expandEvents = (attributes, eventsManager) => {
137
138
  if (listener) {
138
139
  const index = eventsManager.addListener(listener, type);
139
140
  // Add event listener index.
140
- out[Component.ATTRIBUTE_EVENT(type)] = index;
141
+ out[getDataAttribute(type)] = index;
141
142
  }
142
143
  } else {
143
144
  // Add attribute.
@@ -277,7 +278,8 @@ const parseElements = (template, expressions, elements) => {
277
278
  // Expand attributes and events.
278
279
  const attributes = expandEvents(
279
280
  expandAttributes(parsedAttributes, value => getExpressionResult(value, this)),
280
- this.eventsManager
281
+ this.eventsManager,
282
+ type => Component.ATTRIBUTE_EVENT(type, this.uid)
281
283
  );
282
284
  // Extend template attributes with `options.attributes`.
283
285
  if (isRoot && this.attributes) {
@@ -331,7 +333,8 @@ const parsePartialElements = (template, expressions) => {
331
333
  const getAttributes = function() {
332
334
  const attributes = expandEvents(
333
335
  expandAttributes(parsedAttributes, value => getExpressionResult(value, this)),
334
- this.eventsManager
336
+ this.eventsManager,
337
+ type => Component.ATTRIBUTE_EVENT(type, this.uid)
335
338
  );
336
339
 
337
340
  return attributes;
@@ -476,7 +479,7 @@ class Component extends View {
476
479
  const events = {};
477
480
  // Create events object.
478
481
  this.eventsManager.types.forEach(type => {
479
- const dataAttribute = Component.ATTRIBUTE_EVENT(type);
482
+ const dataAttribute = Component.ATTRIBUTE_EVENT(type, this.uid);
480
483
  // Create a listener function that gets the listener index from the data attribute and calls the listener.
481
484
  const listener = function(event, component, matched) {
482
485
  // Get the listener index from the data attribute.
@@ -573,7 +576,7 @@ class Component extends View {
573
576
  this.el = this.children[0].el;
574
577
  } else {
575
578
  // Search for every element in template using getSelector
576
- this.template.elements.forEach((element, index) => {
579
+ this.template.elements.forEach((element, index) => {
577
580
  if (index === 0) {
578
581
  element.hydrate(parent);
579
582
  if (this.el) element.ref = this.el;
@@ -1164,7 +1167,7 @@ class Component extends View {
1164
1167
  * Attributes used to identify elements and events.
1165
1168
  */
1166
1169
  Component.ATTRIBUTE_ELEMENT = 'data-rasti-el';
1167
- Component.ATTRIBUTE_EVENT = (type) => `data-rasti-on-${type}`;
1170
+ Component.ATTRIBUTE_EVENT = (type, uid) => `data-rasti-on-${type}-${uid}`;
1168
1171
 
1169
1172
  /*
1170
1173
  * Dataset attribute used to identify elements.
package/es/View.js CHANGED
@@ -168,7 +168,7 @@ class View extends Emitter {
168
168
  * You shouldn't call this method directly. It's called from the constructor.
169
169
  * You may override it if you want to use a different logic or to
170
170
  * postpone element creation.
171
- */
171
+ */
172
172
  ensureElement() {
173
173
  // Element is already present.
174
174
  if (this.el) {
@@ -32,7 +32,7 @@ class Interpolation {
32
32
  const endComment = findComment(parent, this.getEnd(), this.isComponent, startComment);
33
33
 
34
34
  this.ref = [
35
- startComment,
35
+ startComment,
36
36
  endComment
37
37
  ];
38
38
  }
package/lib/Component.cjs CHANGED
@@ -36,7 +36,7 @@ const getExpressionResult = (expression, context) => utils_getResult(expression,
36
36
  * @return {boolean} True if the element is a component root element.
37
37
  * @private
38
38
  */
39
- const isComponent = (el) => !!el.dataset[Component.DATASET_ELEMENT] && el.dataset[Component.DATASET_ELEMENT].endsWith('-1');
39
+ const isComponent = (el) => !!(el && el.dataset && el.dataset[Component.DATASET_ELEMENT] && el.dataset[Component.DATASET_ELEMENT].endsWith('-1'));
40
40
 
41
41
  /**
42
42
  * Check if an element has the Rasti data attribute.
@@ -45,7 +45,7 @@ const isComponent = (el) => !!el.dataset[Component.DATASET_ELEMENT] && el.datase
45
45
  * @return {boolean} True if the element has the data attribute.
46
46
  * @private
47
47
  */
48
- const isElement = (el) => !!el.dataset[Component.DATASET_ELEMENT];
48
+ const isElement = (el) => !!(el && el.dataset && el.dataset[Component.DATASET_ELEMENT]);
49
49
 
50
50
  /**
51
51
  * Generate string with placeholders for interpolated expressions.
@@ -54,7 +54,7 @@ const isElement = (el) => !!el.dataset[Component.DATASET_ELEMENT];
54
54
  * @return {string} String with placeholders.
55
55
  * @private
56
56
  */
57
- const addPlaceholders = (strings, expressions) =>
57
+ const addPlaceholders = (strings, expressions) =>
58
58
  strings.reduce((out, string, i) => {
59
59
  // Add string part.
60
60
  out.push(string);
@@ -124,10 +124,11 @@ const expandAttributes = (attributes, getExpressionResult) => attributes.reduce(
124
124
  * Expand events.
125
125
  * @param {object} attributes Attributes object.
126
126
  * @param {EventsManager} eventsManager Events manager.
127
+ * @param {Function} getDataAttribute Function to get data attribute name with uid.
127
128
  * @return {object} Attributes object.
128
129
  * @private
129
130
  */
130
- const expandEvents = (attributes, eventsManager) => {
131
+ const expandEvents = (attributes, eventsManager, getDataAttribute) => {
131
132
  const out = {};
132
133
  Object.keys(attributes).forEach(key => {
133
134
  // Check if key is an event listener.
@@ -139,7 +140,7 @@ const expandEvents = (attributes, eventsManager) => {
139
140
  if (listener) {
140
141
  const index = eventsManager.addListener(listener, type);
141
142
  // Add event listener index.
142
- out[Component.ATTRIBUTE_EVENT(type)] = index;
143
+ out[getDataAttribute(type)] = index;
143
144
  }
144
145
  } else {
145
146
  // Add attribute.
@@ -279,7 +280,8 @@ const parseElements = (template, expressions, elements) => {
279
280
  // Expand attributes and events.
280
281
  const attributes = expandEvents(
281
282
  expandAttributes(parsedAttributes, value => getExpressionResult(value, this)),
282
- this.eventsManager
283
+ this.eventsManager,
284
+ type => Component.ATTRIBUTE_EVENT(type, this.uid)
283
285
  );
284
286
  // Extend template attributes with `options.attributes`.
285
287
  if (isRoot && this.attributes) {
@@ -333,7 +335,8 @@ const parsePartialElements = (template, expressions) => {
333
335
  const getAttributes = function() {
334
336
  const attributes = expandEvents(
335
337
  expandAttributes(parsedAttributes, value => getExpressionResult(value, this)),
336
- this.eventsManager
338
+ this.eventsManager,
339
+ type => Component.ATTRIBUTE_EVENT(type, this.uid)
337
340
  );
338
341
 
339
342
  return attributes;
@@ -478,7 +481,7 @@ class Component extends View {
478
481
  const events = {};
479
482
  // Create events object.
480
483
  this.eventsManager.types.forEach(type => {
481
- const dataAttribute = Component.ATTRIBUTE_EVENT(type);
484
+ const dataAttribute = Component.ATTRIBUTE_EVENT(type, this.uid);
482
485
  // Create a listener function that gets the listener index from the data attribute and calls the listener.
483
486
  const listener = function(event, component, matched) {
484
487
  // Get the listener index from the data attribute.
@@ -575,7 +578,7 @@ class Component extends View {
575
578
  this.el = this.children[0].el;
576
579
  } else {
577
580
  // Search for every element in template using getSelector
578
- this.template.elements.forEach((element, index) => {
581
+ this.template.elements.forEach((element, index) => {
579
582
  if (index === 0) {
580
583
  element.hydrate(parent);
581
584
  if (this.el) element.ref = this.el;
@@ -1166,7 +1169,7 @@ class Component extends View {
1166
1169
  * Attributes used to identify elements and events.
1167
1170
  */
1168
1171
  Component.ATTRIBUTE_ELEMENT = 'data-rasti-el';
1169
- Component.ATTRIBUTE_EVENT = (type) => `data-rasti-on-${type}`;
1172
+ Component.ATTRIBUTE_EVENT = (type, uid) => `data-rasti-on-${type}-${uid}`;
1170
1173
 
1171
1174
  /*
1172
1175
  * Dataset attribute used to identify elements.
package/lib/View.cjs CHANGED
@@ -170,7 +170,7 @@ class View extends Emitter {
170
170
  * You shouldn't call this method directly. It's called from the constructor.
171
171
  * You may override it if you want to use a different logic or to
172
172
  * postpone element creation.
173
- */
173
+ */
174
174
  ensureElement() {
175
175
  // Element is already present.
176
176
  if (this.el) {
@@ -34,7 +34,7 @@ class Interpolation {
34
34
  const endComment = utils_findComment(parent, this.getEnd(), this.isComponent, startComment);
35
35
 
36
36
  this.ref = [
37
- startComment,
37
+ startComment,
38
38
  endComment
39
39
  ];
40
40
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rasti",
3
- "version": "4.0.0-alpha.2",
3
+ "version": "4.0.0-alpha.4",
4
4
  "description": "Modern MVC for building user interfaces",
5
5
  "type": "module",
6
6
  "main": "lib/index.cjs",
package/src/Component.js CHANGED
@@ -31,7 +31,7 @@ const getExpressionResult = (expression, context) => getResult(expression, conte
31
31
  * @return {boolean} True if the element is a component root element.
32
32
  * @private
33
33
  */
34
- const isComponent = (el) => !!el.dataset[Component.DATASET_ELEMENT] && el.dataset[Component.DATASET_ELEMENT].endsWith('-1');
34
+ const isComponent = (el) => !!(el && el.dataset && el.dataset[Component.DATASET_ELEMENT] && el.dataset[Component.DATASET_ELEMENT].endsWith('-1'));
35
35
 
36
36
  /**
37
37
  * Check if an element has the Rasti data attribute.
@@ -40,7 +40,7 @@ const isComponent = (el) => !!el.dataset[Component.DATASET_ELEMENT] && el.datase
40
40
  * @return {boolean} True if the element has the data attribute.
41
41
  * @private
42
42
  */
43
- const isElement = (el) => !!el.dataset[Component.DATASET_ELEMENT];
43
+ const isElement = (el) => !!(el && el.dataset && el.dataset[Component.DATASET_ELEMENT]);
44
44
 
45
45
  /**
46
46
  * Generate string with placeholders for interpolated expressions.
@@ -49,7 +49,7 @@ const isElement = (el) => !!el.dataset[Component.DATASET_ELEMENT];
49
49
  * @return {string} String with placeholders.
50
50
  * @private
51
51
  */
52
- const addPlaceholders = (strings, expressions) =>
52
+ const addPlaceholders = (strings, expressions) =>
53
53
  strings.reduce((out, string, i) => {
54
54
  // Add string part.
55
55
  out.push(string);
@@ -119,10 +119,11 @@ const expandAttributes = (attributes, getExpressionResult) => attributes.reduce(
119
119
  * Expand events.
120
120
  * @param {object} attributes Attributes object.
121
121
  * @param {EventsManager} eventsManager Events manager.
122
+ * @param {Function} getDataAttribute Function to get data attribute name with uid.
122
123
  * @return {object} Attributes object.
123
124
  * @private
124
125
  */
125
- const expandEvents = (attributes, eventsManager) => {
126
+ const expandEvents = (attributes, eventsManager, getDataAttribute) => {
126
127
  const out = {};
127
128
  Object.keys(attributes).forEach(key => {
128
129
  // Check if key is an event listener.
@@ -134,7 +135,7 @@ const expandEvents = (attributes, eventsManager) => {
134
135
  if (listener) {
135
136
  const index = eventsManager.addListener(listener, type);
136
137
  // Add event listener index.
137
- out[Component.ATTRIBUTE_EVENT(type)] = index;
138
+ out[getDataAttribute(type)] = index;
138
139
  }
139
140
  } else {
140
141
  // Add attribute.
@@ -274,7 +275,8 @@ const parseElements = (template, expressions, elements) => {
274
275
  // Expand attributes and events.
275
276
  const attributes = expandEvents(
276
277
  expandAttributes(parsedAttributes, value => getExpressionResult(value, this)),
277
- this.eventsManager
278
+ this.eventsManager,
279
+ type => Component.ATTRIBUTE_EVENT(type, this.uid)
278
280
  );
279
281
  // Extend template attributes with `options.attributes`.
280
282
  if (isRoot && this.attributes) {
@@ -328,7 +330,8 @@ const parsePartialElements = (template, expressions) => {
328
330
  const getAttributes = function() {
329
331
  const attributes = expandEvents(
330
332
  expandAttributes(parsedAttributes, value => getExpressionResult(value, this)),
331
- this.eventsManager
333
+ this.eventsManager,
334
+ type => Component.ATTRIBUTE_EVENT(type, this.uid)
332
335
  );
333
336
 
334
337
  return attributes;
@@ -473,7 +476,7 @@ class Component extends View {
473
476
  const events = {};
474
477
  // Create events object.
475
478
  this.eventsManager.types.forEach(type => {
476
- const dataAttribute = Component.ATTRIBUTE_EVENT(type);
479
+ const dataAttribute = Component.ATTRIBUTE_EVENT(type, this.uid);
477
480
  // Create a listener function that gets the listener index from the data attribute and calls the listener.
478
481
  const listener = function(event, component, matched) {
479
482
  // Get the listener index from the data attribute.
@@ -570,7 +573,7 @@ class Component extends View {
570
573
  this.el = this.children[0].el;
571
574
  } else {
572
575
  // Search for every element in template using getSelector
573
- this.template.elements.forEach((element, index) => {
576
+ this.template.elements.forEach((element, index) => {
574
577
  if (index === 0) {
575
578
  element.hydrate(parent);
576
579
  if (this.el) element.ref = this.el;
@@ -1161,7 +1164,7 @@ class Component extends View {
1161
1164
  * Attributes used to identify elements and events.
1162
1165
  */
1163
1166
  Component.ATTRIBUTE_ELEMENT = 'data-rasti-el';
1164
- Component.ATTRIBUTE_EVENT = (type) => `data-rasti-on-${type}`;
1167
+ Component.ATTRIBUTE_EVENT = (type, uid) => `data-rasti-on-${type}-${uid}`;
1165
1168
 
1166
1169
  /*
1167
1170
  * Dataset attribute used to identify elements.
package/src/View.js CHANGED
@@ -168,7 +168,7 @@ export default class View extends Emitter {
168
168
  * You shouldn't call this method directly. It's called from the constructor.
169
169
  * You may override it if you want to use a different logic or to
170
170
  * postpone element creation.
171
- */
171
+ */
172
172
  ensureElement() {
173
173
  // Element is already present.
174
174
  if (this.el) {
@@ -32,7 +32,7 @@ class Interpolation {
32
32
  const endComment = findComment(parent, this.getEnd(), this.isComponent, startComment);
33
33
 
34
34
  this.ref = [
35
- startComment,
35
+ startComment,
36
36
  endComment
37
37
  ];
38
38
  }
package/src/index.js CHANGED
@@ -2,4 +2,3 @@ export { default as Emitter } from './Emitter.js';
2
2
  export { default as Model } from './Model.js';
3
3
  export { default as View } from './View.js';
4
4
  export { default as Component } from './Component.js';
5
-