rasti 4.0.0-alpha.0 → 4.0.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/README.md +0 -10
- package/dist/rasti.js +27 -13
- package/dist/rasti.min.js +1 -1
- package/es/Component.js +27 -13
- package/lib/Component.cjs +27 -13
- package/package.json +1 -1
- package/src/Component.js +27 -13
package/README.md
CHANGED
|
@@ -187,16 +187,6 @@ For detailed information on how to use **Rasti**, refer to the [API documentatio
|
|
|
187
187
|
- **[v2.0.0](https://github.com/8tentaculos/rasti/releases/tag/v2.0.0)** - Introduced **Components**
|
|
188
188
|
- **[v1.0.0](https://github.com/8tentaculos/rasti/releases/tag/v1.0.0)** - Initial release
|
|
189
189
|
|
|
190
|
-
## Powered by **Rasti**
|
|
191
|
-
|
|
192
|
-
### [Crypto Babylon](https://cryptobabylon.net)
|
|
193
|
-
|
|
194
|
-
A market analytics platform efficiently rendering over 1000 dynamic rows, updated in real-time with thousands of messages per second via multiple WebSocket connections.
|
|
195
|
-
|
|
196
|
-
### [jsPacman](https://pacman.js.org)
|
|
197
|
-
|
|
198
|
-
A DOM-based remake of the classic Ms. Pac-Man game. **Rasti** powers its custom game engine.
|
|
199
|
-
|
|
200
190
|
## License
|
|
201
191
|
|
|
202
192
|
**Rasti** is open-source and available under the [MIT License](LICENSE).
|
package/dist/rasti.js
CHANGED
|
@@ -1715,21 +1715,39 @@
|
|
|
1715
1715
|
* modifies the expressions array adding the mount functions.
|
|
1716
1716
|
* @param main {string} The main template.
|
|
1717
1717
|
* @param {Array<any>} expressions Array of expressions.
|
|
1718
|
+
* @param {boolean} skipNormalization Skip placeholder normalization (for recursive calls).
|
|
1718
1719
|
* @return {string} The template with components tags replaced by expressions
|
|
1719
1720
|
* placeholders.
|
|
1720
1721
|
* @private
|
|
1721
1722
|
*/
|
|
1722
|
-
const expandComponents = (main, expressions) => {
|
|
1723
|
+
const expandComponents = (main, expressions, skipNormalization = false) => {
|
|
1723
1724
|
const PH = Component.PLACEHOLDER('(\\d+)');
|
|
1724
|
-
|
|
1725
|
+
const componentRefMap = new Map();
|
|
1726
|
+
// Normalize component references to use first placeholder index.
|
|
1727
|
+
// Only on first call, not on recursive calls.
|
|
1728
|
+
if (!skipNormalization) {
|
|
1729
|
+
main = main.replace(
|
|
1730
|
+
new RegExp(PH, 'g'),
|
|
1731
|
+
(match, idx) => {
|
|
1732
|
+
const expression = expressions[idx];
|
|
1733
|
+
if (expression && expression.prototype instanceof Component) {
|
|
1734
|
+
if (componentRefMap.has(expression)) {
|
|
1735
|
+
return componentRefMap.get(expression);
|
|
1736
|
+
}
|
|
1737
|
+
componentRefMap.set(expression, match);
|
|
1738
|
+
}
|
|
1739
|
+
return match;
|
|
1740
|
+
}
|
|
1741
|
+
);
|
|
1742
|
+
}
|
|
1743
|
+
// Match component tags with backreference to ensure correct pairing.
|
|
1725
1744
|
return main.replace(
|
|
1726
|
-
new RegExp(`<(${PH})([^>]*)>([\\s\\S]*?)
|
|
1727
|
-
(match, openTag, openIdx, nonVoidAttrs, inner,
|
|
1728
|
-
let tag,
|
|
1745
|
+
new RegExp(`<(${PH})([^>]*)>([\\s\\S]*?)</\\1>|<(${PH})([^>]*)/>`,'g'),
|
|
1746
|
+
(match, openTag, openIdx, nonVoidAttrs, inner, selfClosingTag, selfClosingIdx, selfClosingAttrs) => {
|
|
1747
|
+
let tag, attributesStr, innerList;
|
|
1729
1748
|
|
|
1730
1749
|
if (openTag) {
|
|
1731
|
-
tag =
|
|
1732
|
-
close = typeof closeIdx !== 'undefined' ? expressions[closeIdx] : closeTag;
|
|
1750
|
+
tag = expressions[openIdx];
|
|
1733
1751
|
attributesStr = nonVoidAttrs;
|
|
1734
1752
|
} else {
|
|
1735
1753
|
tag = typeof selfClosingIdx !== 'undefined' ? expressions[selfClosingIdx] : selfClosingTag;
|
|
@@ -1737,15 +1755,11 @@
|
|
|
1737
1755
|
}
|
|
1738
1756
|
// No component found.
|
|
1739
1757
|
if (!(tag.prototype instanceof Component)) return match;
|
|
1740
|
-
|
|
1741
|
-
let innerList;
|
|
1742
1758
|
// Non void component.
|
|
1743
|
-
if (
|
|
1744
|
-
// Close component tag must match open component tag.
|
|
1745
|
-
if (tag !== close) return match;
|
|
1759
|
+
if (openTag) {
|
|
1746
1760
|
// Process inner content same way as partial().
|
|
1747
1761
|
// Recursively expand inner components.
|
|
1748
|
-
const innerTemplate = expandComponents(inner, expressions);
|
|
1762
|
+
const innerTemplate = expandComponents(inner, expressions, true);
|
|
1749
1763
|
// Parse partial elements to handle dynamic attributes and events.
|
|
1750
1764
|
const parsedInner = parsePartialElements(innerTemplate, expressions);
|
|
1751
1765
|
// Split into items.
|
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=>({"&":"&","<":"<",">":">",'"':""","'":"'"}[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((e=>{let i=t[e];!0===i?s[e]="":!1!==i&&(null==i&&(i=""),s[e]=i)})),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 b(t){const e=document.createElement("template");return e.innerHTML=`${t}`.trim(),e.content}function T(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.hasAttribute(j.ATTRIBUTE_ELEMENT)&&t.getAttribute(j.ATTRIBUTE_ELEMENT).endsWith("-1"),R=t=>t.hasAttribute(j.ATTRIBUTE_ELEMENT),L=(t,e)=>t.reduce(((t,s,i)=>(t.push(s),void 0!==e[i]&&t.push(j.PLACEHOLDER(i)),t)),[]).join(""),$=(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}),{}),M=(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},S=(t,e)=>{const s=j.PLACEHOLDER("(\\d+)");return t.replace(new RegExp(`<(${s})([^>]*)>([\\s\\S]*?)</(${s})>|<(${s})([^>]*)/>`,"g"),((t,s,i,n,r,h,o,l,c,u)=>{let d,p,f,g;if(s?(d=void 0!==i?e[i]:s,p=void 0!==o?e[o]:h,f=n):(d=void 0!==c?e[c]:l,f=u),!(d.prototype instanceof j))return t;if(p){if(d!==p)return t;const s=S(r,e),i=k(s,e);g=$(i,e)}const E=w(f,e);return e.push((function(){const t=C(E,(t=>A(t,this)));return g&&(t.renderChildren=()=>new a(g.map((t=>A(t,this))))),d.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=M(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(T(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 M(C(h,(t=>A(t,this))),this.eventsManager)};e.push((function(){const t=o.call(this);return j.markAsSafeHTML(T(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","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}subscribe(t,e="change",s=this.onChange){return t.on&&this.listenTo(t,e,s),this}isContainer(){return 0===this.template.elements.length&&1===this.template.interpolations.length}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))}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}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]}recycle(t){return E(t,j.MARKER_RECYCLED(this.uid),v).replaceWith(...this.getNodes()),this.onRecycle.call(this),this}onCreate(){}onChange(){this.render()}onHydrate(){}onRecycle(){}onUpdate(){}onDestroy(){}partial(t,...e){const s=$(k(S(L(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=b(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=b(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)})),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}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}static create(t,...e){"function"==typeof t&&(e=[t],t=["",""]);const s=[],i=[],n=$(N(x(S(L(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.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=>({"&":"&","<":"<",">":">",'"':""","'":"'"}[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 p=["value","checked","selected"];class d{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((e=>{let i=t[e];!0===i?s[e]="":!1!==i&&(null==i&&(i=""),s[e]=i)})),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),p.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),p.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 b(t){const e=document.createElement("template");return e.innerHTML=`${t}`.trim(),e.content}function T(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),R=t=>t.hasAttribute(j.ATTRIBUTE_ELEMENT)&&t.getAttribute(j.ATTRIBUTE_ELEMENT).endsWith("-1"),v=t=>t.hasAttribute(j.ATTRIBUTE_ELEMENT),L=(t,e)=>t.reduce(((t,s,i)=>(t.push(s),void 0!==e[i]&&t.push(j.PLACEHOLDER(i)),t)),[]).join(""),C=(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}),{}),M=(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},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,p;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);p=C(s,e)}const d=w(u,e);return e.push((function(){const t=$(d,(t=>A(t,this)));return p&&(t.renderChildren=()=>new a(p.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),p=t=>`${t}-${c}`,d=function(){const t=M($(u,(t=>A(t,this))),this.eventsManager);return l&&this.attributes&&Object.assign(t,i(this.attributes,this)),t[j.ATTRIBUTE_ELEMENT]=p(this.uid),t};s.push({getSelector:function(){return`[${j.ATTRIBUTE_ELEMENT}="${p(this.uid)}"]`},getAttributes:d}),e.push((function(){const t=d.call(this);return j.markAsSafeHTML(T(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 M($(h,(t=>A(t,this))),this.eventsManager)};e.push((function(){const t=o.call(this);return j.markAsSafeHTML(T(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","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}subscribe(t,e="change",s=this.onChange){return t.on&&this.listenTo(t,e,s),this}isContainer(){return 0===this.template.elements.length&&1===this.template.interpolations.length}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))}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}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]}recycle(t){return E(t,j.MARKER_RECYCLED(this.uid),R).replaceWith(...this.getNodes()),this.onRecycle.call(this),this}onCreate(){}onChange(){this.render()}onHydrate(){}onRecycle(){}onUpdate(){}onDestroy(){}partial(t,...e){const s=C(k(S(L(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=b(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=b(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)})),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}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}static create(t,...e){"function"==typeof t&&(e=[t],t=["",""]);const s=[],i=[],n=C(N(x(S(L(t,e).trim(),e),e,s),e,i),e);return this.extend({template(){return{elements:s.map((t=>new d({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:R,isElement:v}))),parts:n}}})}}j.ATTRIBUTE_ELEMENT="data-rasti-el",j.ATTRIBUTE_EVENT=t=>`data-rasti-on-${t}`,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
|
@@ -155,21 +155,39 @@ const expandEvents = (attributes, eventsManager) => {
|
|
|
155
155
|
* modifies the expressions array adding the mount functions.
|
|
156
156
|
* @param main {string} The main template.
|
|
157
157
|
* @param {Array<any>} expressions Array of expressions.
|
|
158
|
+
* @param {boolean} skipNormalization Skip placeholder normalization (for recursive calls).
|
|
158
159
|
* @return {string} The template with components tags replaced by expressions
|
|
159
160
|
* placeholders.
|
|
160
161
|
* @private
|
|
161
162
|
*/
|
|
162
|
-
const expandComponents = (main, expressions) => {
|
|
163
|
+
const expandComponents = (main, expressions, skipNormalization = false) => {
|
|
163
164
|
const PH = Component.PLACEHOLDER('(\\d+)');
|
|
164
|
-
|
|
165
|
+
const componentRefMap = new Map();
|
|
166
|
+
// Normalize component references to use first placeholder index.
|
|
167
|
+
// Only on first call, not on recursive calls.
|
|
168
|
+
if (!skipNormalization) {
|
|
169
|
+
main = main.replace(
|
|
170
|
+
new RegExp(PH, 'g'),
|
|
171
|
+
(match, idx) => {
|
|
172
|
+
const expression = expressions[idx];
|
|
173
|
+
if (expression && expression.prototype instanceof Component) {
|
|
174
|
+
if (componentRefMap.has(expression)) {
|
|
175
|
+
return componentRefMap.get(expression);
|
|
176
|
+
}
|
|
177
|
+
componentRefMap.set(expression, match);
|
|
178
|
+
}
|
|
179
|
+
return match;
|
|
180
|
+
}
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
// Match component tags with backreference to ensure correct pairing.
|
|
165
184
|
return main.replace(
|
|
166
|
-
new RegExp(`<(${PH})([^>]*)>([\\s\\S]*?)
|
|
167
|
-
(match, openTag, openIdx, nonVoidAttrs, inner,
|
|
168
|
-
let tag,
|
|
185
|
+
new RegExp(`<(${PH})([^>]*)>([\\s\\S]*?)</\\1>|<(${PH})([^>]*)/>`,'g'),
|
|
186
|
+
(match, openTag, openIdx, nonVoidAttrs, inner, selfClosingTag, selfClosingIdx, selfClosingAttrs) => {
|
|
187
|
+
let tag, attributesStr, innerList;
|
|
169
188
|
|
|
170
189
|
if (openTag) {
|
|
171
|
-
tag =
|
|
172
|
-
close = typeof closeIdx !== 'undefined' ? expressions[closeIdx] : closeTag;
|
|
190
|
+
tag = expressions[openIdx];
|
|
173
191
|
attributesStr = nonVoidAttrs;
|
|
174
192
|
} else {
|
|
175
193
|
tag = typeof selfClosingIdx !== 'undefined' ? expressions[selfClosingIdx] : selfClosingTag;
|
|
@@ -177,15 +195,11 @@ const expandComponents = (main, expressions) => {
|
|
|
177
195
|
}
|
|
178
196
|
// No component found.
|
|
179
197
|
if (!(tag.prototype instanceof Component)) return match;
|
|
180
|
-
|
|
181
|
-
let innerList;
|
|
182
198
|
// Non void component.
|
|
183
|
-
if (
|
|
184
|
-
// Close component tag must match open component tag.
|
|
185
|
-
if (tag !== close) return match;
|
|
199
|
+
if (openTag) {
|
|
186
200
|
// Process inner content same way as partial().
|
|
187
201
|
// Recursively expand inner components.
|
|
188
|
-
const innerTemplate = expandComponents(inner, expressions);
|
|
202
|
+
const innerTemplate = expandComponents(inner, expressions, true);
|
|
189
203
|
// Parse partial elements to handle dynamic attributes and events.
|
|
190
204
|
const parsedInner = parsePartialElements(innerTemplate, expressions);
|
|
191
205
|
// Split into items.
|
package/lib/Component.cjs
CHANGED
|
@@ -157,21 +157,39 @@ const expandEvents = (attributes, eventsManager) => {
|
|
|
157
157
|
* modifies the expressions array adding the mount functions.
|
|
158
158
|
* @param main {string} The main template.
|
|
159
159
|
* @param {Array<any>} expressions Array of expressions.
|
|
160
|
+
* @param {boolean} skipNormalization Skip placeholder normalization (for recursive calls).
|
|
160
161
|
* @return {string} The template with components tags replaced by expressions
|
|
161
162
|
* placeholders.
|
|
162
163
|
* @private
|
|
163
164
|
*/
|
|
164
|
-
const expandComponents = (main, expressions) => {
|
|
165
|
+
const expandComponents = (main, expressions, skipNormalization = false) => {
|
|
165
166
|
const PH = Component.PLACEHOLDER('(\\d+)');
|
|
166
|
-
|
|
167
|
+
const componentRefMap = new Map();
|
|
168
|
+
// Normalize component references to use first placeholder index.
|
|
169
|
+
// Only on first call, not on recursive calls.
|
|
170
|
+
if (!skipNormalization) {
|
|
171
|
+
main = main.replace(
|
|
172
|
+
new RegExp(PH, 'g'),
|
|
173
|
+
(match, idx) => {
|
|
174
|
+
const expression = expressions[idx];
|
|
175
|
+
if (expression && expression.prototype instanceof Component) {
|
|
176
|
+
if (componentRefMap.has(expression)) {
|
|
177
|
+
return componentRefMap.get(expression);
|
|
178
|
+
}
|
|
179
|
+
componentRefMap.set(expression, match);
|
|
180
|
+
}
|
|
181
|
+
return match;
|
|
182
|
+
}
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
// Match component tags with backreference to ensure correct pairing.
|
|
167
186
|
return main.replace(
|
|
168
|
-
new RegExp(`<(${PH})([^>]*)>([\\s\\S]*?)
|
|
169
|
-
(match, openTag, openIdx, nonVoidAttrs, inner,
|
|
170
|
-
let tag,
|
|
187
|
+
new RegExp(`<(${PH})([^>]*)>([\\s\\S]*?)</\\1>|<(${PH})([^>]*)/>`,'g'),
|
|
188
|
+
(match, openTag, openIdx, nonVoidAttrs, inner, selfClosingTag, selfClosingIdx, selfClosingAttrs) => {
|
|
189
|
+
let tag, attributesStr, innerList;
|
|
171
190
|
|
|
172
191
|
if (openTag) {
|
|
173
|
-
tag =
|
|
174
|
-
close = typeof closeIdx !== 'undefined' ? expressions[closeIdx] : closeTag;
|
|
192
|
+
tag = expressions[openIdx];
|
|
175
193
|
attributesStr = nonVoidAttrs;
|
|
176
194
|
} else {
|
|
177
195
|
tag = typeof selfClosingIdx !== 'undefined' ? expressions[selfClosingIdx] : selfClosingTag;
|
|
@@ -179,15 +197,11 @@ const expandComponents = (main, expressions) => {
|
|
|
179
197
|
}
|
|
180
198
|
// No component found.
|
|
181
199
|
if (!(tag.prototype instanceof Component)) return match;
|
|
182
|
-
|
|
183
|
-
let innerList;
|
|
184
200
|
// Non void component.
|
|
185
|
-
if (
|
|
186
|
-
// Close component tag must match open component tag.
|
|
187
|
-
if (tag !== close) return match;
|
|
201
|
+
if (openTag) {
|
|
188
202
|
// Process inner content same way as partial().
|
|
189
203
|
// Recursively expand inner components.
|
|
190
|
-
const innerTemplate = expandComponents(inner, expressions);
|
|
204
|
+
const innerTemplate = expandComponents(inner, expressions, true);
|
|
191
205
|
// Parse partial elements to handle dynamic attributes and events.
|
|
192
206
|
const parsedInner = parsePartialElements(innerTemplate, expressions);
|
|
193
207
|
// Split into items.
|
package/package.json
CHANGED
package/src/Component.js
CHANGED
|
@@ -152,21 +152,39 @@ const expandEvents = (attributes, eventsManager) => {
|
|
|
152
152
|
* modifies the expressions array adding the mount functions.
|
|
153
153
|
* @param main {string} The main template.
|
|
154
154
|
* @param {Array<any>} expressions Array of expressions.
|
|
155
|
+
* @param {boolean} skipNormalization Skip placeholder normalization (for recursive calls).
|
|
155
156
|
* @return {string} The template with components tags replaced by expressions
|
|
156
157
|
* placeholders.
|
|
157
158
|
* @private
|
|
158
159
|
*/
|
|
159
|
-
const expandComponents = (main, expressions) => {
|
|
160
|
+
const expandComponents = (main, expressions, skipNormalization = false) => {
|
|
160
161
|
const PH = Component.PLACEHOLDER('(\\d+)');
|
|
161
|
-
|
|
162
|
+
const componentRefMap = new Map();
|
|
163
|
+
// Normalize component references to use first placeholder index.
|
|
164
|
+
// Only on first call, not on recursive calls.
|
|
165
|
+
if (!skipNormalization) {
|
|
166
|
+
main = main.replace(
|
|
167
|
+
new RegExp(PH, 'g'),
|
|
168
|
+
(match, idx) => {
|
|
169
|
+
const expression = expressions[idx];
|
|
170
|
+
if (expression && expression.prototype instanceof Component) {
|
|
171
|
+
if (componentRefMap.has(expression)) {
|
|
172
|
+
return componentRefMap.get(expression);
|
|
173
|
+
}
|
|
174
|
+
componentRefMap.set(expression, match);
|
|
175
|
+
}
|
|
176
|
+
return match;
|
|
177
|
+
}
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
// Match component tags with backreference to ensure correct pairing.
|
|
162
181
|
return main.replace(
|
|
163
|
-
new RegExp(`<(${PH})([^>]*)>([\\s\\S]*?)
|
|
164
|
-
(match, openTag, openIdx, nonVoidAttrs, inner,
|
|
165
|
-
let tag,
|
|
182
|
+
new RegExp(`<(${PH})([^>]*)>([\\s\\S]*?)</\\1>|<(${PH})([^>]*)/>`,'g'),
|
|
183
|
+
(match, openTag, openIdx, nonVoidAttrs, inner, selfClosingTag, selfClosingIdx, selfClosingAttrs) => {
|
|
184
|
+
let tag, attributesStr, innerList;
|
|
166
185
|
|
|
167
186
|
if (openTag) {
|
|
168
|
-
tag =
|
|
169
|
-
close = typeof closeIdx !== 'undefined' ? expressions[closeIdx] : closeTag;
|
|
187
|
+
tag = expressions[openIdx];
|
|
170
188
|
attributesStr = nonVoidAttrs;
|
|
171
189
|
} else {
|
|
172
190
|
tag = typeof selfClosingIdx !== 'undefined' ? expressions[selfClosingIdx] : selfClosingTag;
|
|
@@ -174,15 +192,11 @@ const expandComponents = (main, expressions) => {
|
|
|
174
192
|
}
|
|
175
193
|
// No component found.
|
|
176
194
|
if (!(tag.prototype instanceof Component)) return match;
|
|
177
|
-
|
|
178
|
-
let innerList;
|
|
179
195
|
// Non void component.
|
|
180
|
-
if (
|
|
181
|
-
// Close component tag must match open component tag.
|
|
182
|
-
if (tag !== close) return match;
|
|
196
|
+
if (openTag) {
|
|
183
197
|
// Process inner content same way as partial().
|
|
184
198
|
// Recursively expand inner components.
|
|
185
|
-
const innerTemplate = expandComponents(inner, expressions);
|
|
199
|
+
const innerTemplate = expandComponents(inner, expressions, true);
|
|
186
200
|
// Parse partial elements to handle dynamic attributes and events.
|
|
187
201
|
const parsedInner = parsePartialElements(innerTemplate, expressions);
|
|
188
202
|
// Split into items.
|