@plentico/pattr 0.0.5 → 0.0.6
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 +6 -5
- package/package.json +1 -1
- package/pattr.js +19 -2
- package/pattr.min.js +1 -1
package/README.md
CHANGED
|
@@ -72,7 +72,7 @@ For use with wrapped components (e.g., from Pico templating), evaluate visibilit
|
|
|
72
72
|
|
|
73
73
|
```html
|
|
74
74
|
<!-- From Pico: {if age > 10} wraps a component that has p-scope -->
|
|
75
|
-
<div p-show:pre-scope="age > 10" p-scope="double = age * 2"
|
|
75
|
+
<div p-show:pre-scope="age > 10" p-scope="double = age * 2">
|
|
76
76
|
Your doubled age is: <span p-text="double"></span>
|
|
77
77
|
</div>
|
|
78
78
|
```
|
|
@@ -88,7 +88,6 @@ You can combine both for complex scenarios:
|
|
|
88
88
|
p-show:pre-scope="age > 10"
|
|
89
89
|
p-show="double > 30"
|
|
90
90
|
p-scope="double = age * 2"
|
|
91
|
-
p-id="two-show-attr-demo"
|
|
92
91
|
>
|
|
93
92
|
Your doubled age (<span p-text="double"></span>) is greater than 30
|
|
94
93
|
</div>
|
|
@@ -186,7 +185,7 @@ Available events: `click`, `focus`, `blur`, `input`, `change`, `submit`, `keydow
|
|
|
186
185
|
|
|
187
186
|
## Scoped Components
|
|
188
187
|
|
|
189
|
-
Create nested components with isolated reactive state using `p-scope` and `p-id
|
|
188
|
+
Create nested components with isolated reactive state using `p-scope` (and optionally `p-id`):
|
|
190
189
|
|
|
191
190
|
```html
|
|
192
191
|
<div>
|
|
@@ -198,13 +197,15 @@ Create nested components with isolated reactive state using `p-scope` and `p-id`
|
|
|
198
197
|
<div>Child count (×2): <span p-text="count"></span></div>
|
|
199
198
|
<button p-on:click="count++">+</button>
|
|
200
199
|
|
|
201
|
-
<section p-
|
|
200
|
+
<section p-scope="count = count + 1;">
|
|
202
201
|
<div>Grandchild count (+1): <span p-text="count"></span></div>
|
|
203
202
|
<button p-on:click="count++">+</button>
|
|
204
203
|
</section>
|
|
205
204
|
</section>
|
|
206
205
|
```
|
|
207
206
|
|
|
207
|
+
> The `p-id` attribute used to be required to use `p-scope`, now it's optional and can be omitted entirely. It's still available because it could be helpful for debugging purposes, migrating data between elements, or if external tools/scripts need to reference scopes by name.
|
|
208
|
+
|
|
208
209
|
### Scoping Example
|
|
209
210
|
|
|
210
211
|
Components down the chain can diverge from the reactivity provided by their Parent components. However, if a Parent component is updated, it will resync all descendant components.
|
|
@@ -419,7 +420,7 @@ import Pattr from '@plentico/pattr';
|
|
|
419
420
|
</template>
|
|
420
421
|
|
|
421
422
|
<!-- Scoped component -->
|
|
422
|
-
<section p-
|
|
423
|
+
<section p-scope="count = todos.length;">
|
|
423
424
|
<p>Total todos: <span p-text="count"></span></p>
|
|
424
425
|
</section>
|
|
425
426
|
</body>
|
package/package.json
CHANGED
package/pattr.js
CHANGED
|
@@ -203,10 +203,25 @@ window.Pattr = {
|
|
|
203
203
|
this.refreshAllLoops();
|
|
204
204
|
},
|
|
205
205
|
|
|
206
|
+
generateDomPathId(el) {
|
|
207
|
+
const path = [];
|
|
208
|
+
let node = el;
|
|
209
|
+
while (node && node.tagName !== 'HTML') {
|
|
210
|
+
const parent = node.parentElement;
|
|
211
|
+
if (parent) {
|
|
212
|
+
const index = Array.from(parent.children).indexOf(node);
|
|
213
|
+
path.unshift(`${node.tagName}[${index}]`);
|
|
214
|
+
}
|
|
215
|
+
node = parent;
|
|
216
|
+
}
|
|
217
|
+
return path.join('/');
|
|
218
|
+
},
|
|
219
|
+
|
|
206
220
|
buildScopeData(el, parentData) {
|
|
207
221
|
let currentData = parentData;
|
|
208
222
|
if (el.hasAttribute('p-scope')) {
|
|
209
|
-
|
|
223
|
+
// Use explicit p-id if provided, otherwise generate from DOM position
|
|
224
|
+
const dataId = el.getAttribute('p-id') || this.generateDomPathId(el);
|
|
210
225
|
if (!parentData._p_children) {
|
|
211
226
|
parentData._p_children = {};
|
|
212
227
|
}
|
|
@@ -215,6 +230,8 @@ window.Pattr = {
|
|
|
215
230
|
}
|
|
216
231
|
currentData = parentData._p_children[dataId];
|
|
217
232
|
currentData._p_scope = el.getAttribute('p-scope');
|
|
233
|
+
// Store the ID for later use
|
|
234
|
+
currentData._p_id = dataId;
|
|
218
235
|
}
|
|
219
236
|
let child = el.firstElementChild;
|
|
220
237
|
while (child) {
|
|
@@ -257,7 +274,7 @@ window.Pattr = {
|
|
|
257
274
|
* Creates a new scope for an element with p-scope during hydration
|
|
258
275
|
*/
|
|
259
276
|
initScope(el, parentScope) {
|
|
260
|
-
const dataId = el.getAttribute('p-id');
|
|
277
|
+
const dataId = el.getAttribute('p-id') || this.generateDomPathId(el);
|
|
261
278
|
const localRawData = parentScope._p_target._p_children[dataId];
|
|
262
279
|
|
|
263
280
|
// Create new inherited Proxy
|
package/pattr.min.js
CHANGED
|
@@ -4,4 +4,4 @@
|
|
|
4
4
|
* https://github.com/plentico/pattr
|
|
5
5
|
* MIT License
|
|
6
6
|
*/
|
|
7
|
-
window.Pattr={_templateScopeCounter:0,directives:{"p-text":(e,t,r={})=>{let o=String(t);if(r.trim&&r.trim.length>0){const e=parseInt(r.trim[0])||100;o.length>e&&(o=o.substring(0,e)+"...")}e.innerText=o},"p-html":(e,t,r={})=>{let o=t;if(r.allow&&r.allow.length>0){const e=r.allow,t=document.createElement("div");t.innerHTML=o;const a=t=>{if(t.nodeType===Node.ELEMENT_NODE){const r=t.tagName.toLowerCase();if(!e.includes(r))return document.createTextNode(t.textContent);const o=t.cloneNode(!1);return Array.from(t.childNodes).forEach(e=>{const t=a(e);t&&o.appendChild(t)}),o}return t.cloneNode()},s=document.createElement("div");Array.from(t.childNodes).forEach(e=>{const t=a(e);t&&s.appendChild(t)}),o=s.innerHTML}if(r.trim&&r.trim.length>0){const e=parseInt(r.trim[0])||100,t=document.createElement("div");t.innerHTML=o;let a=0,s=!1;const n=t=>{if(s)return null;if(t.nodeType===Node.TEXT_NODE){const r=t.textContent,o=e-a;if(r.length<=o)return a+=r.length,t.cloneNode();{s=!0;const e=r.substring(0,o)+"...";return document.createTextNode(e)}}if(t.nodeType===Node.ELEMENT_NODE){const e=t.cloneNode(!1);for(let r of t.childNodes){const t=n(r);if(t&&e.appendChild(t),s)break}return e}return t.cloneNode()},i=document.createElement("div");for(let e of t.childNodes){const t=n(e);if(t&&i.appendChild(t),s)break}o=i.innerHTML}e.innerHTML=o},"p-show":(e,t)=>{e.style.display=t?"":"none"},"p-style":(e,t)=>{"string"==typeof t?e.style.cssText=t:"object"==typeof t&&null!==t&&Object.assign(e.style,t)},"p-class":(e,t)=>{"string"==typeof t?e.className=t:Array.isArray(t)?e.className=t.join(" "):"object"==typeof t&&null!==t&&(e.className=Object.keys(t).filter(e=>t[e]).join(" "))},"p-model":(e,t)=>{e.value=t},"p-attr":(e,t,r={})=>{const o=Object.keys(r);if(o.length>0){const r=o[0];null==t||!1===t?e.removeAttribute(r):e.setAttribute(r,String(t))}else"object"==typeof t&&null!==t&&Object.keys(t).forEach(r=>{const o=t[r];null==o||!1===o?e.removeAttribute(r):e.setAttribute(r,String(o))})}},parseDirectiveModifiers(e){const t=e.split(":"),r=t[0],o={};for(let e=1;e<t.length;e++){const r=t[e].split("."),a=r[0],s=r.slice(1);o[a]=s}return{directive:r,modifiers:o}},async start(){this.root=document.documentElement;const e=document.getElementById("p-root-data")?.textContent;try{this.rawData=JSON.parse(e||"{}")}catch(e){console.error("Error parsing root data JSON:",e)}this.buildScopeData(this.root,this.rawData),this.data=this.observe(this.rawData),this.walkDom(this.root,this.data,!0),this.refreshAllLoops()},buildScopeData(e,t){let r=t;if(e.hasAttribute("p-scope")){const o=e.getAttribute("p-id")||"missing_p-id";t._p_children||(t._p_children={}),t._p_children[o]||(t._p_children[o]={}),r=t._p_children[o],r._p_scope=e.getAttribute("p-scope")}let o=e.firstElementChild;for(;o;)this.buildScopeData(o,r),o=o.nextElementSibling},observe(e,t){const r=e;let o=r;t&&(o=Object.create(t._p_target||t),Object.assign(o,r));return new Proxy(o,{get:(e,t)=>"_p_target"===t?e:e[t],set:(e,t,r)=>(e[t]=r,this.walkDom(this.root,this.data,!1),!0),has:(e,t)=>t in e})},initScope(e,t){const r=e.getAttribute("p-id"),o=t._p_target._p_children[r],a=this.observe(o,t);this.executePScopeStatements(a,o._p_scope);const s=Object.getPrototypeOf(a._p_target);e._parentSnapshot={};for(let t in s)t.startsWith("_p_")||(e._parentSnapshot[t]=s[t]);const n=a._p_target;e._localSnapshot={};for(let t of Object.keys(n))t.startsWith("_p_")||(e._localSnapshot[t]=n[t]);return a},refreshScope(e,t){let r=e._scope;if(!r)return t;const o=e.getAttribute("p-scope");return o&&r._p_target&&this.updateScopeFromParent(e,r,o),r},executePScopeStatements(scope,pScopeExpr){const statements=pScopeExpr.split(";").map(e=>e.trim()).filter(e=>e),target=scope._p_target,sequentialScope=new Proxy(target,{get:(e,t)=>Object.prototype.hasOwnProperty.call(e,t)?e[t]:scope[t],has:(e,t)=>Object.prototype.hasOwnProperty.call(e,t)||t in scope});for(const stmt of statements){const match=stmt.match(/^(\w+)\s*=\s*(.+)$/);if(match){const[,varName,expr]=match;try{const value=eval(`with (sequentialScope) { (${expr}) }`);target[varName]=value}catch(e){console.error(`Error executing p-scope statement "${stmt}":`,e)}}}},updateScopeFromParent(el,scope,pScopeExpr){const parentProto=Object.getPrototypeOf(scope._p_target),target=scope._p_target,changedParentVars=new Set,changedLocalVars=new Set;el._parentSnapshot||(el._parentSnapshot={});for(let e in parentProto)e.startsWith("_p_")||(el._parentSnapshot[e]!==parentProto[e]&&changedParentVars.add(e),el._parentSnapshot[e]=parentProto[e]);el._localSnapshot||(el._localSnapshot={});for(let e of Object.keys(target))e.startsWith("_p_")||(el._localSnapshot[e]!==target[e]&&changedLocalVars.add(e),el._localSnapshot[e]=target[e]);const allChangedVars=new Set([...changedParentVars,...changedLocalVars]);if(0!==allChangedVars.size)try{const statements=pScopeExpr.split(";").map(e=>e.trim()).filter(e=>e),outputVars=new Set;statements.forEach(e=>{const t=e.match(/^(\w+)\s*=\s*(.+)$/);t&&outputVars.add(t[1])});const setInThisPass=new Set,sequentialScope=new Proxy(target,{get:(e,t)=>"_p_target"===t||"_p_children"===t||"_p_scope"===t||setInThisPass.has(t)?e[t]:changedParentVars.has(t)?parentProto[t]:changedLocalVars.has(t)||Object.prototype.hasOwnProperty.call(e,t)?e[t]:parentProto[t],set:(e,t,r)=>(e[t]=r,!0),has:(e,t)=>setInThisPass.has(t)||Object.prototype.hasOwnProperty.call(e,t)||t in parentProto});statements.forEach(stmt=>{let shouldExecute=!1;const parts=stmt.split("=");if(parts.length<=1)return;const rhs=parts.slice(1).join("=");if(changedParentVars.forEach(e=>{rhs.includes(e)&&(shouldExecute=!0)}),changedLocalVars.forEach(e=>{!outputVars.has(e)&&rhs.includes(e)&&(shouldExecute=!0)}),shouldExecute||setInThisPass.forEach(e=>{rhs.includes(e)&&(shouldExecute=!0)}),shouldExecute){const match=stmt.match(/^(\w+)\s*=\s*(.+)$/);if(match){const[,varName,expr]=match,value=eval(`with (sequentialScope) { (${expr}) }`);target[varName]=value,setInThisPass.add(varName)}}});for(let e of Object.keys(target))e.startsWith("_p_")||(el._localSnapshot[e]=target[e])}catch(e){console.error("Error re-executing p-scope expression:",e)}},registerEventListeners(el){Array.from(el.attributes).forEach(attr=>{if(attr.name.startsWith("p-on:")){const event=attr.name.replace("p-on:","");el.addEventListener(event,()=>{eval(`with (el._scope) { ${attr.value} }`),this.refreshAllLoops()})}})},registerModelBinding(el){const modelAttr=el.getAttribute("p-model");modelAttr&&(el.addEventListener("input",e=>{let value;const type=e.target.type;value="number"===type||"range"===type?""===e.target.value?null:Number(e.target.value):"checkbox"===type?e.target.checked:"radio"===type?e.target.checked?e.target.value:void 0:e.target.value,void 0!==value&&eval(`with (el._scope) { ${modelAttr} = value }`)}),"checkbox"!==el.type&&"radio"!==el.type||el.addEventListener("change",e=>{let value;value="checkbox"===el.type?e.target.checked:e.target.checked?e.target.value:void 0,void 0!==value&&eval(`with (el._scope) { ${modelAttr} = value }`)}))},evaluateDirectives(el,scope){Array.from(el.attributes).forEach(attr=>{const parsed=this.parseDirectiveModifiers(attr.name);if(Object.keys(this.directives).includes(parsed.directive)){const evalScope=el._scope||scope,value=eval(`with (evalScope) { (${attr.value}) }`);this.directives[parsed.directive](el,value,parsed.modifiers)}})},setForTemplateRecursive(e,t){e._forTemplate=t,Array.from(e.children).forEach(e=>{this.setForTemplateRecursive(e,t)})},refreshAllLoops(e=this.root,t=new Set){if("TEMPLATE"===e.tagName&&e.hasAttribute("p-for")){if(t.has(e))return;return t.add(e),void this.handleFor(e,e._scope||this.data,!1)}let r=e.firstElementChild;for(;r;){const e=r.nextElementSibling;this.refreshAllLoops(r,t),r=e}},handleFor(e,t,r){const o=e.getAttribute("p-for"),a=o.match(/^(?:const|let)?\s*(.+?)\s+(of|in)\s+(.+)$/);if(!a)return void console.error(`Invalid p-for expression: ${o}`);const[,s,n,i]=a;r?this.hydrateLoop(e,t,s,i):this.refreshLoop(e,t,s,i)},getTemplateScopePrefix(e){let t="";if(e._forTemplate){const r=e._forTemplate._forData;if(r&&r.scopePrefix){let r=e.previousElementSibling;for(;r;){if(r.hasAttribute&&r.hasAttribute("p-for-key")){t=r.getAttribute("p-for-key")+"-";break}r=r.previousElementSibling}}}if(!t){let r=e.previousElementSibling;for(;r;){if(r.hasAttribute&&r.hasAttribute("p-for-key")&&r._forTemplate===e._forTemplate){t=r.getAttribute("p-for-key")+"-";break}r=r.previousElementSibling}}if(!t){let r=e.parentElement;for(;r;){if(r.hasAttribute&&r.hasAttribute("p-for-key")){t=r.getAttribute("p-for-key")+"-";break}if(r._forTemplate){const e=r._forTemplate._forData;if(e){const o=e.renderedElements.indexOf(r);if(o>=0){t=(e.scopePrefix||"")+o+"-";break}}}r=r.parentElement}}return e._forScopeId||(e._forScopeId="s"+this._templateScopeCounter++),t+e._forScopeId+":"},hydrateLoop(template,parentScope,varPattern,iterableExpr){template._scope=parentScope;try{const iterable=eval(`with (parentScope) { (${iterableExpr}) }`),scopePrefix=this.getTemplateScopePrefix(template);template._forData={varPattern:varPattern,iterableExpr:iterableExpr,renderedElements:[],scopePrefix:scopePrefix};const existingElementsByKey={};let sibling=template.nextElementSibling;for(;sibling&&sibling.hasAttribute("p-for-key");){const e=sibling.getAttribute("p-for-key"),t=e.startsWith(scopePrefix)||!e.includes(":")&&!e.includes("-");if(t){let t;t=e.startsWith(scopePrefix)?e.substring(scopePrefix.length):e,existingElementsByKey[t]||(existingElementsByKey[t]=[]),existingElementsByKey[t].push(sibling)}sibling=sibling.nextElementSibling}let index=0,lastInserted=template;for(const e of iterable){const t=this.createLoopScope(parentScope,varPattern,e);if(existingElementsByKey[String(index)])existingElementsByKey[String(index)].forEach(e=>{e._scope=t,this.setForTemplateRecursive(e,template),"TEMPLATE"!==e.tagName&&e.setAttribute("p-for-key",scopePrefix+index),this.walkDom(e,t,!0),template._forData.renderedElements.push(e),lastInserted=e});else{const e=template.content.cloneNode(!0),r=Array.from(e.children);r.forEach(e=>{e._scope=t,this.setForTemplateRecursive(e,template),"TEMPLATE"!==e.tagName&&e.setAttribute("p-for-key",scopePrefix+index),this.walkDom(e,t,!0)});const o=document.createDocumentFragment();r.forEach(e=>o.appendChild(e)),lastInserted.parentNode.insertBefore(o,lastInserted.nextSibling),template._forData.renderedElements.push(...r),lastInserted=r[r.length-1]||lastInserted}index++}Object.keys(existingElementsByKey).forEach(e=>{parseInt(e)>=index&&existingElementsByKey[e].forEach(e=>e.remove())})}catch(e){console.error(`Error in p-for hydration: ${iterableExpr}`,e)}},removeLoopElements(e){e.forEach(e=>{if(e._forData&&e._forData.renderedElements&&(this.removeLoopElements(e._forData.renderedElements),e._forData.renderedElements=[]),e.querySelectorAll){e.querySelectorAll("template[p-for]").forEach(e=>{e._forData&&e._forData.renderedElements&&(this.removeLoopElements(e._forData.renderedElements),e._forData.renderedElements=[])})}e.remove()})},refreshLoop(template,parentScope,varPattern,iterableExpr){const forData=template._forData;if(forData)try{const iterable=eval(`with (parentScope._p_target || parentScope) { (${iterableExpr}) }`),scopePrefix=forData.scopePrefix||this.getTemplateScopePrefix(template);this.removeLoopElements(forData.renderedElements),forData.renderedElements=[];let lastInsertedElement=template,index=0;for(const e of iterable){const t=template.content.cloneNode(!0),r=this.createLoopScope(parentScope,forData.varPattern,e),o=Array.from(t.children);o.forEach(e=>{e._scope=r,this.setForTemplateRecursive(e,template),"TEMPLATE"!==e.tagName&&e.setAttribute("p-for-key",scopePrefix+index)});const a=document.createDocumentFragment();o.forEach(e=>a.appendChild(e)),lastInsertedElement.parentNode.insertBefore(a,lastInsertedElement.nextSibling),forData.renderedElements.push(...o),o.forEach(e=>{this.walkDom(e,r,!0)});const s=o[o.length-1];s&&(lastInsertedElement=this.findLastRenderedSibling(s)),index++}}catch(e){console.error(`Error in p-for refresh: ${iterableExpr}`,e)}},findLastRenderedSibling(e){if("TEMPLATE"===e.tagName&&e._forData&&e._forData.renderedElements.length>0){const t=e._forData.renderedElements[e._forData.renderedElements.length-1];return this.findLastRenderedSibling(t)}return e},createLoopScope(e,t,r){const o={};if((t=t.trim()).startsWith("[")){const e=t.slice(1,-1).split(",").map(e=>e.trim());Array.isArray(r)?e.forEach((e,t)=>o[e]=r[t]):o[e[0]]=r}else if(t.startsWith("{")){t.slice(1,-1).split(",").map(e=>e.trim()).forEach(e=>{const[t,a]=e.split(":").map(e=>e.trim());o[a||t]=r[t]})}else o[t]=r;if(!e)return console.error("parentScope is undefined in createLoopScope"),new Proxy({},{get:()=>{},set:()=>!1});const a=e._p_target||e;if(!a||"object"!=typeof a)return console.error("Invalid parentTarget:",a),new Proxy(o,{get:(e,t)=>e[t],set:(e,t,r)=>(e[t]=r,!0)});const s=Object.create(a);Object.assign(s,o);const n=new Proxy(s,{get:(e,t)=>e[t],set:(e,t,r)=>(t in o?e[t]=r:a[t]=r,!0)});return n._p_target=s,n},walkDom(el,parentScope,isHydrating=!1){if("TEMPLATE"===el.tagName&&el.hasAttribute("p-for")){if(!isHydrating&&el._forTemplate)return;return void this.handleFor(el,parentScope,isHydrating)}const preScopeShowAttr=Array.from(el.attributes).find(e=>{const t=this.parseDirectiveModifiers(e.name);return"p-show"===t.directive&&t.modifiers["pre-scope"]});if(preScopeShowAttr&&parentScope){const value=eval(`with (parentScope) { (${preScopeShowAttr.value}) }`);this.directives["p-show"](el,value)}let currentScope=parentScope;el.hasAttribute("p-scope")&&(currentScope=isHydrating?this.initScope(el,parentScope):this.refreshScope(el,parentScope)),isHydrating&&(el._scope=currentScope,this.registerEventListeners(el),this.registerModelBinding(el)),currentScope&&Array.from(el.attributes).forEach(attr=>{const parsed=this.parseDirectiveModifiers(attr.name);if(("p-show"!==parsed.directive||!parsed.modifiers["pre-scope"])&&Object.keys(this.directives).includes(parsed.directive)){const evalScope=el._scope||currentScope,value=eval(`with (evalScope) { (${attr.value}) }`);this.directives[parsed.directive](el,value,parsed.modifiers)}});const children=Array.from(el.children);for(const e of children)this.walkDom(e,currentScope,isHydrating)}},window.Pattr.start();
|
|
7
|
+
window.Pattr={_templateScopeCounter:0,directives:{"p-text":(e,t,r={})=>{let o=String(t);if(r.trim&&r.trim.length>0){const e=parseInt(r.trim[0])||100;o.length>e&&(o=o.substring(0,e)+"...")}e.innerText=o},"p-html":(e,t,r={})=>{let o=t;if(r.allow&&r.allow.length>0){const e=r.allow,t=document.createElement("div");t.innerHTML=o;const a=t=>{if(t.nodeType===Node.ELEMENT_NODE){const r=t.tagName.toLowerCase();if(!e.includes(r))return document.createTextNode(t.textContent);const o=t.cloneNode(!1);return Array.from(t.childNodes).forEach(e=>{const t=a(e);t&&o.appendChild(t)}),o}return t.cloneNode()},s=document.createElement("div");Array.from(t.childNodes).forEach(e=>{const t=a(e);t&&s.appendChild(t)}),o=s.innerHTML}if(r.trim&&r.trim.length>0){const e=parseInt(r.trim[0])||100,t=document.createElement("div");t.innerHTML=o;let a=0,s=!1;const n=t=>{if(s)return null;if(t.nodeType===Node.TEXT_NODE){const r=t.textContent,o=e-a;if(r.length<=o)return a+=r.length,t.cloneNode();{s=!0;const e=r.substring(0,o)+"...";return document.createTextNode(e)}}if(t.nodeType===Node.ELEMENT_NODE){const e=t.cloneNode(!1);for(let r of t.childNodes){const t=n(r);if(t&&e.appendChild(t),s)break}return e}return t.cloneNode()},i=document.createElement("div");for(let e of t.childNodes){const t=n(e);if(t&&i.appendChild(t),s)break}o=i.innerHTML}e.innerHTML=o},"p-show":(e,t)=>{e.style.display=t?"":"none"},"p-style":(e,t)=>{"string"==typeof t?e.style.cssText=t:"object"==typeof t&&null!==t&&Object.assign(e.style,t)},"p-class":(e,t)=>{"string"==typeof t?e.className=t:Array.isArray(t)?e.className=t.join(" "):"object"==typeof t&&null!==t&&(e.className=Object.keys(t).filter(e=>t[e]).join(" "))},"p-model":(e,t)=>{e.value=t},"p-attr":(e,t,r={})=>{const o=Object.keys(r);if(o.length>0){const r=o[0];null==t||!1===t?e.removeAttribute(r):e.setAttribute(r,String(t))}else"object"==typeof t&&null!==t&&Object.keys(t).forEach(r=>{const o=t[r];null==o||!1===o?e.removeAttribute(r):e.setAttribute(r,String(o))})}},parseDirectiveModifiers(e){const t=e.split(":"),r=t[0],o={};for(let e=1;e<t.length;e++){const r=t[e].split("."),a=r[0],s=r.slice(1);o[a]=s}return{directive:r,modifiers:o}},async start(){this.root=document.documentElement;const e=document.getElementById("p-root-data")?.textContent;try{this.rawData=JSON.parse(e||"{}")}catch(e){console.error("Error parsing root data JSON:",e)}this.buildScopeData(this.root,this.rawData),this.data=this.observe(this.rawData),this.walkDom(this.root,this.data,!0),this.refreshAllLoops()},generateDomPathId(e){const t=[];let r=e;for(;r&&"HTML"!==r.tagName;){const e=r.parentElement;if(e){const o=Array.from(e.children).indexOf(r);t.unshift(`${r.tagName}[${o}]`)}r=e}return t.join("/")},buildScopeData(e,t){let r=t;if(e.hasAttribute("p-scope")){const o=e.getAttribute("p-id")||this.generateDomPathId(e);t._p_children||(t._p_children={}),t._p_children[o]||(t._p_children[o]={}),r=t._p_children[o],r._p_scope=e.getAttribute("p-scope"),r._p_id=o}let o=e.firstElementChild;for(;o;)this.buildScopeData(o,r),o=o.nextElementSibling},observe(e,t){const r=e;let o=r;t&&(o=Object.create(t._p_target||t),Object.assign(o,r));return new Proxy(o,{get:(e,t)=>"_p_target"===t?e:e[t],set:(e,t,r)=>(e[t]=r,this.walkDom(this.root,this.data,!1),!0),has:(e,t)=>t in e})},initScope(e,t){const r=e.getAttribute("p-id")||this.generateDomPathId(e),o=t._p_target._p_children[r],a=this.observe(o,t);this.executePScopeStatements(a,o._p_scope);const s=Object.getPrototypeOf(a._p_target);e._parentSnapshot={};for(let t in s)t.startsWith("_p_")||(e._parentSnapshot[t]=s[t]);const n=a._p_target;e._localSnapshot={};for(let t of Object.keys(n))t.startsWith("_p_")||(e._localSnapshot[t]=n[t]);return a},refreshScope(e,t){let r=e._scope;if(!r)return t;const o=e.getAttribute("p-scope");return o&&r._p_target&&this.updateScopeFromParent(e,r,o),r},executePScopeStatements(scope,pScopeExpr){const statements=pScopeExpr.split(";").map(e=>e.trim()).filter(e=>e),target=scope._p_target,sequentialScope=new Proxy(target,{get:(e,t)=>Object.prototype.hasOwnProperty.call(e,t)?e[t]:scope[t],has:(e,t)=>Object.prototype.hasOwnProperty.call(e,t)||t in scope});for(const stmt of statements){const match=stmt.match(/^(\w+)\s*=\s*(.+)$/);if(match){const[,varName,expr]=match;try{const value=eval(`with (sequentialScope) { (${expr}) }`);target[varName]=value}catch(e){console.error(`Error executing p-scope statement "${stmt}":`,e)}}}},updateScopeFromParent(el,scope,pScopeExpr){const parentProto=Object.getPrototypeOf(scope._p_target),target=scope._p_target,changedParentVars=new Set,changedLocalVars=new Set;el._parentSnapshot||(el._parentSnapshot={});for(let e in parentProto)e.startsWith("_p_")||(el._parentSnapshot[e]!==parentProto[e]&&changedParentVars.add(e),el._parentSnapshot[e]=parentProto[e]);el._localSnapshot||(el._localSnapshot={});for(let e of Object.keys(target))e.startsWith("_p_")||(el._localSnapshot[e]!==target[e]&&changedLocalVars.add(e),el._localSnapshot[e]=target[e]);const allChangedVars=new Set([...changedParentVars,...changedLocalVars]);if(0!==allChangedVars.size)try{const statements=pScopeExpr.split(";").map(e=>e.trim()).filter(e=>e),outputVars=new Set;statements.forEach(e=>{const t=e.match(/^(\w+)\s*=\s*(.+)$/);t&&outputVars.add(t[1])});const setInThisPass=new Set,sequentialScope=new Proxy(target,{get:(e,t)=>"_p_target"===t||"_p_children"===t||"_p_scope"===t||setInThisPass.has(t)?e[t]:changedParentVars.has(t)?parentProto[t]:changedLocalVars.has(t)||Object.prototype.hasOwnProperty.call(e,t)?e[t]:parentProto[t],set:(e,t,r)=>(e[t]=r,!0),has:(e,t)=>setInThisPass.has(t)||Object.prototype.hasOwnProperty.call(e,t)||t in parentProto});statements.forEach(stmt=>{let shouldExecute=!1;const parts=stmt.split("=");if(parts.length<=1)return;const rhs=parts.slice(1).join("=");if(changedParentVars.forEach(e=>{rhs.includes(e)&&(shouldExecute=!0)}),changedLocalVars.forEach(e=>{!outputVars.has(e)&&rhs.includes(e)&&(shouldExecute=!0)}),shouldExecute||setInThisPass.forEach(e=>{rhs.includes(e)&&(shouldExecute=!0)}),shouldExecute){const match=stmt.match(/^(\w+)\s*=\s*(.+)$/);if(match){const[,varName,expr]=match,value=eval(`with (sequentialScope) { (${expr}) }`);target[varName]=value,setInThisPass.add(varName)}}});for(let e of Object.keys(target))e.startsWith("_p_")||(el._localSnapshot[e]=target[e])}catch(e){console.error("Error re-executing p-scope expression:",e)}},registerEventListeners(el){Array.from(el.attributes).forEach(attr=>{if(attr.name.startsWith("p-on:")){const event=attr.name.replace("p-on:","");el.addEventListener(event,()=>{eval(`with (el._scope) { ${attr.value} }`),this.refreshAllLoops()})}})},registerModelBinding(el){const modelAttr=el.getAttribute("p-model");modelAttr&&(el.addEventListener("input",e=>{let value;const type=e.target.type;value="number"===type||"range"===type?""===e.target.value?null:Number(e.target.value):"checkbox"===type?e.target.checked:"radio"===type?e.target.checked?e.target.value:void 0:e.target.value,void 0!==value&&eval(`with (el._scope) { ${modelAttr} = value }`)}),"checkbox"!==el.type&&"radio"!==el.type||el.addEventListener("change",e=>{let value;value="checkbox"===el.type?e.target.checked:e.target.checked?e.target.value:void 0,void 0!==value&&eval(`with (el._scope) { ${modelAttr} = value }`)}))},evaluateDirectives(el,scope){Array.from(el.attributes).forEach(attr=>{const parsed=this.parseDirectiveModifiers(attr.name);if(Object.keys(this.directives).includes(parsed.directive)){const evalScope=el._scope||scope,value=eval(`with (evalScope) { (${attr.value}) }`);this.directives[parsed.directive](el,value,parsed.modifiers)}})},setForTemplateRecursive(e,t){e._forTemplate=t,Array.from(e.children).forEach(e=>{this.setForTemplateRecursive(e,t)})},refreshAllLoops(e=this.root,t=new Set){if("TEMPLATE"===e.tagName&&e.hasAttribute("p-for")){if(t.has(e))return;return t.add(e),void this.handleFor(e,e._scope||this.data,!1)}let r=e.firstElementChild;for(;r;){const e=r.nextElementSibling;this.refreshAllLoops(r,t),r=e}},handleFor(e,t,r){const o=e.getAttribute("p-for"),a=o.match(/^(?:const|let)?\s*(.+?)\s+(of|in)\s+(.+)$/);if(!a)return void console.error(`Invalid p-for expression: ${o}`);const[,s,n,i]=a;r?this.hydrateLoop(e,t,s,i):this.refreshLoop(e,t,s,i)},getTemplateScopePrefix(e){let t="";if(e._forTemplate){const r=e._forTemplate._forData;if(r&&r.scopePrefix){let r=e.previousElementSibling;for(;r;){if(r.hasAttribute&&r.hasAttribute("p-for-key")){t=r.getAttribute("p-for-key")+"-";break}r=r.previousElementSibling}}}if(!t){let r=e.previousElementSibling;for(;r;){if(r.hasAttribute&&r.hasAttribute("p-for-key")&&r._forTemplate===e._forTemplate){t=r.getAttribute("p-for-key")+"-";break}r=r.previousElementSibling}}if(!t){let r=e.parentElement;for(;r;){if(r.hasAttribute&&r.hasAttribute("p-for-key")){t=r.getAttribute("p-for-key")+"-";break}if(r._forTemplate){const e=r._forTemplate._forData;if(e){const o=e.renderedElements.indexOf(r);if(o>=0){t=(e.scopePrefix||"")+o+"-";break}}}r=r.parentElement}}return e._forScopeId||(e._forScopeId="s"+this._templateScopeCounter++),t+e._forScopeId+":"},hydrateLoop(template,parentScope,varPattern,iterableExpr){template._scope=parentScope;try{const iterable=eval(`with (parentScope) { (${iterableExpr}) }`),scopePrefix=this.getTemplateScopePrefix(template);template._forData={varPattern:varPattern,iterableExpr:iterableExpr,renderedElements:[],scopePrefix:scopePrefix};const existingElementsByKey={};let sibling=template.nextElementSibling;for(;sibling&&sibling.hasAttribute("p-for-key");){const e=sibling.getAttribute("p-for-key"),t=e.startsWith(scopePrefix)||!e.includes(":")&&!e.includes("-");if(t){let t;t=e.startsWith(scopePrefix)?e.substring(scopePrefix.length):e,existingElementsByKey[t]||(existingElementsByKey[t]=[]),existingElementsByKey[t].push(sibling)}sibling=sibling.nextElementSibling}let index=0,lastInserted=template;for(const e of iterable){const t=this.createLoopScope(parentScope,varPattern,e);if(existingElementsByKey[String(index)])existingElementsByKey[String(index)].forEach(e=>{e._scope=t,this.setForTemplateRecursive(e,template),"TEMPLATE"!==e.tagName&&e.setAttribute("p-for-key",scopePrefix+index),this.walkDom(e,t,!0),template._forData.renderedElements.push(e),lastInserted=e});else{const e=template.content.cloneNode(!0),r=Array.from(e.children);r.forEach(e=>{e._scope=t,this.setForTemplateRecursive(e,template),"TEMPLATE"!==e.tagName&&e.setAttribute("p-for-key",scopePrefix+index),this.walkDom(e,t,!0)});const o=document.createDocumentFragment();r.forEach(e=>o.appendChild(e)),lastInserted.parentNode.insertBefore(o,lastInserted.nextSibling),template._forData.renderedElements.push(...r),lastInserted=r[r.length-1]||lastInserted}index++}Object.keys(existingElementsByKey).forEach(e=>{parseInt(e)>=index&&existingElementsByKey[e].forEach(e=>e.remove())})}catch(e){console.error(`Error in p-for hydration: ${iterableExpr}`,e)}},removeLoopElements(e){e.forEach(e=>{if(e._forData&&e._forData.renderedElements&&(this.removeLoopElements(e._forData.renderedElements),e._forData.renderedElements=[]),e.querySelectorAll){e.querySelectorAll("template[p-for]").forEach(e=>{e._forData&&e._forData.renderedElements&&(this.removeLoopElements(e._forData.renderedElements),e._forData.renderedElements=[])})}e.remove()})},refreshLoop(template,parentScope,varPattern,iterableExpr){const forData=template._forData;if(forData)try{const iterable=eval(`with (parentScope._p_target || parentScope) { (${iterableExpr}) }`),scopePrefix=forData.scopePrefix||this.getTemplateScopePrefix(template);this.removeLoopElements(forData.renderedElements),forData.renderedElements=[];let lastInsertedElement=template,index=0;for(const e of iterable){const t=template.content.cloneNode(!0),r=this.createLoopScope(parentScope,forData.varPattern,e),o=Array.from(t.children);o.forEach(e=>{e._scope=r,this.setForTemplateRecursive(e,template),"TEMPLATE"!==e.tagName&&e.setAttribute("p-for-key",scopePrefix+index)});const a=document.createDocumentFragment();o.forEach(e=>a.appendChild(e)),lastInsertedElement.parentNode.insertBefore(a,lastInsertedElement.nextSibling),forData.renderedElements.push(...o),o.forEach(e=>{this.walkDom(e,r,!0)});const s=o[o.length-1];s&&(lastInsertedElement=this.findLastRenderedSibling(s)),index++}}catch(e){console.error(`Error in p-for refresh: ${iterableExpr}`,e)}},findLastRenderedSibling(e){if("TEMPLATE"===e.tagName&&e._forData&&e._forData.renderedElements.length>0){const t=e._forData.renderedElements[e._forData.renderedElements.length-1];return this.findLastRenderedSibling(t)}return e},createLoopScope(e,t,r){const o={};if((t=t.trim()).startsWith("[")){const e=t.slice(1,-1).split(",").map(e=>e.trim());Array.isArray(r)?e.forEach((e,t)=>o[e]=r[t]):o[e[0]]=r}else if(t.startsWith("{")){t.slice(1,-1).split(",").map(e=>e.trim()).forEach(e=>{const[t,a]=e.split(":").map(e=>e.trim());o[a||t]=r[t]})}else o[t]=r;if(!e)return console.error("parentScope is undefined in createLoopScope"),new Proxy({},{get:()=>{},set:()=>!1});const a=e._p_target||e;if(!a||"object"!=typeof a)return console.error("Invalid parentTarget:",a),new Proxy(o,{get:(e,t)=>e[t],set:(e,t,r)=>(e[t]=r,!0)});const s=Object.create(a);Object.assign(s,o);const n=new Proxy(s,{get:(e,t)=>e[t],set:(e,t,r)=>(t in o?e[t]=r:a[t]=r,!0)});return n._p_target=s,n},walkDom(el,parentScope,isHydrating=!1){if("TEMPLATE"===el.tagName&&el.hasAttribute("p-for")){if(!isHydrating&&el._forTemplate)return;return void this.handleFor(el,parentScope,isHydrating)}const preScopeShowAttr=Array.from(el.attributes).find(e=>{const t=this.parseDirectiveModifiers(e.name);return"p-show"===t.directive&&t.modifiers["pre-scope"]});if(preScopeShowAttr&&parentScope){const value=eval(`with (parentScope) { (${preScopeShowAttr.value}) }`);this.directives["p-show"](el,value)}let currentScope=parentScope;el.hasAttribute("p-scope")&&(currentScope=isHydrating?this.initScope(el,parentScope):this.refreshScope(el,parentScope)),isHydrating&&(el._scope=currentScope,this.registerEventListeners(el),this.registerModelBinding(el)),currentScope&&Array.from(el.attributes).forEach(attr=>{const parsed=this.parseDirectiveModifiers(attr.name);if(("p-show"!==parsed.directive||!parsed.modifiers["pre-scope"])&&Object.keys(this.directives).includes(parsed.directive)){const evalScope=el._scope||currentScope,value=eval(`with (evalScope) { (${attr.value}) }`);this.directives[parsed.directive](el,value,parsed.modifiers)}});const children=Array.from(el.children);for(const e of children)this.walkDom(e,currentScope,isHydrating)}},window.Pattr.start();
|