@plentico/pattr 0.0.18 → 0.0.20
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/package.json +1 -1
- package/pattr.js +107 -24
- package/pattr.min.js +1 -1
package/package.json
CHANGED
package/pattr.js
CHANGED
|
@@ -954,17 +954,20 @@ window.Pattr = {
|
|
|
954
954
|
// This handles cases like content[key] where content is inherited
|
|
955
955
|
const scope = el._scope;
|
|
956
956
|
|
|
957
|
-
// For bracket notation like content[key]
|
|
957
|
+
// For bracket notation like content[key] or nested content[key][i],
|
|
958
|
+
// split at the LAST bracket pair: evaluate the container object and the key
|
|
959
|
+
// separately through the scope chain, then set directly on the container.
|
|
960
|
+
// This handles arbitrary nesting depth AND avoids a subtle `with`-statement
|
|
961
|
+
// variable-shadowing bug: if the loop uses `for [key, value] of ...` then
|
|
962
|
+
// `value` is a scope property, so `eval('with (scope) { expr = value }')` would
|
|
963
|
+
// assign the loop variable back to itself instead of the new input value.
|
|
958
964
|
if (modelAttr.includes('[')) {
|
|
959
|
-
|
|
960
|
-
const
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
} else {
|
|
966
|
-
eval(`with (scope) { ${modelAttr} = value }`);
|
|
967
|
-
}
|
|
965
|
+
const lastBracket = modelAttr.lastIndexOf('[');
|
|
966
|
+
const containerExpr = modelAttr.substring(0, lastBracket);
|
|
967
|
+
const keyExpr = modelAttr.substring(lastBracket + 1, modelAttr.length - 1);
|
|
968
|
+
const container = eval(`with (scope) { (${containerExpr}) }`);
|
|
969
|
+
const key = eval(`with (scope) { (${keyExpr}) }`);
|
|
970
|
+
container[key] = value;
|
|
968
971
|
} else if (modelAttr.includes('.')) {
|
|
969
972
|
// Handle dot notation like content.path
|
|
970
973
|
const parts = modelAttr.split('.');
|
|
@@ -1025,23 +1028,16 @@ window.Pattr = {
|
|
|
1025
1028
|
value = e.target.checked ? e.target.value : undefined;
|
|
1026
1029
|
}
|
|
1027
1030
|
if (value !== undefined) {
|
|
1028
|
-
// Set on the scope (Proxy) to trigger reactive updates
|
|
1029
|
-
// This handles cases like content[key] where content is inherited
|
|
1030
1031
|
const scope = el._scope;
|
|
1031
|
-
|
|
1032
|
-
// For bracket notation like content[key], we need to evaluate key first
|
|
1033
1032
|
if (modelAttr.includes('[')) {
|
|
1034
|
-
|
|
1035
|
-
const
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
} else {
|
|
1041
|
-
eval(`with (scope) { ${modelAttr} = value }`);
|
|
1042
|
-
}
|
|
1033
|
+
const lastBracket = modelAttr.lastIndexOf('[');
|
|
1034
|
+
const containerExpr = modelAttr.substring(0, lastBracket);
|
|
1035
|
+
const keyExpr = modelAttr.substring(lastBracket + 1, modelAttr.length - 1);
|
|
1036
|
+
const container = eval(`with (scope) { (${containerExpr}) }`);
|
|
1037
|
+
const key = eval(`with (scope) { (${keyExpr}) }`);
|
|
1038
|
+
container[key] = value;
|
|
1043
1039
|
} else {
|
|
1044
|
-
scope[modelAttr] = value;
|
|
1040
|
+
scope[modelAttr] = value;
|
|
1045
1041
|
}
|
|
1046
1042
|
}
|
|
1047
1043
|
});
|
|
@@ -1207,6 +1203,50 @@ window.Pattr = {
|
|
|
1207
1203
|
return ancestorKey + template._forScopeId + ':';
|
|
1208
1204
|
},
|
|
1209
1205
|
|
|
1206
|
+
/**
|
|
1207
|
+
* Recursively enriches a template content element with nested p-for templates
|
|
1208
|
+
* found in SSR-rendered elements but missing from the outer template's static content.
|
|
1209
|
+
*
|
|
1210
|
+
* When a template generator (e.g. Pico) emits a nested {for} loop only inside the
|
|
1211
|
+
* SSR-rendered siblings—but NOT inside the outer <template p-for> content—refreshLoop
|
|
1212
|
+
* will re-render from template.content and lose the inner template entirely.
|
|
1213
|
+
* Calling this once per hydrateLoop pass "teaches" the outer template about the inner
|
|
1214
|
+
* template so all future refreshLoop calls reproduce it correctly.
|
|
1215
|
+
*/
|
|
1216
|
+
enrichTemplateContent(templateEl, ssrEl) {
|
|
1217
|
+
// Filter out SSR-rendered loop elements (those with p-for-key)
|
|
1218
|
+
const ssrChildren = Array.from(ssrEl.children).filter(
|
|
1219
|
+
c => !c.hasAttribute('p-for-key')
|
|
1220
|
+
);
|
|
1221
|
+
const tplChildren = Array.from(templateEl.children);
|
|
1222
|
+
let ti = 0;
|
|
1223
|
+
|
|
1224
|
+
for (const ssrChild of ssrChildren) {
|
|
1225
|
+
if (ssrChild.tagName === 'TEMPLATE' && ssrChild.hasAttribute('p-for')) {
|
|
1226
|
+
// Check whether the template content already has a matching inner template here
|
|
1227
|
+
const tplChild = tplChildren[ti];
|
|
1228
|
+
const alreadyPresent =
|
|
1229
|
+
tplChild &&
|
|
1230
|
+
tplChild.tagName === 'TEMPLATE' &&
|
|
1231
|
+
tplChild.getAttribute('p-for') === ssrChild.getAttribute('p-for');
|
|
1232
|
+
|
|
1233
|
+
if (!alreadyPresent) {
|
|
1234
|
+
// Insert a clone of the SSR inner template into the outer template content.
|
|
1235
|
+
// cloneNode(true) copies the <template> element and its .content fragment
|
|
1236
|
+
// but does NOT copy the SSR-rendered siblings (p-for-key elements).
|
|
1237
|
+
const clonedInnerTemplate = ssrChild.cloneNode(true);
|
|
1238
|
+
templateEl.insertBefore(clonedInnerTemplate, tplChild || null);
|
|
1239
|
+
tplChildren.splice(ti, 0, clonedInnerTemplate);
|
|
1240
|
+
}
|
|
1241
|
+
ti++;
|
|
1242
|
+
} else if (ti < tplChildren.length && tplChildren[ti].tagName === ssrChild.tagName) {
|
|
1243
|
+
// Structurally matching element — recurse into children
|
|
1244
|
+
this.enrichTemplateContent(tplChildren[ti], ssrChild);
|
|
1245
|
+
ti++;
|
|
1246
|
+
}
|
|
1247
|
+
}
|
|
1248
|
+
},
|
|
1249
|
+
|
|
1210
1250
|
hydrateLoop(template, parentScope, varPattern, iterableExpr) {
|
|
1211
1251
|
template._scope = parentScope;
|
|
1212
1252
|
|
|
@@ -1250,6 +1290,20 @@ window.Pattr = {
|
|
|
1250
1290
|
}
|
|
1251
1291
|
sibling = sibling.nextElementSibling;
|
|
1252
1292
|
}
|
|
1293
|
+
|
|
1294
|
+
// Enrich the outer template's content with any inner p-for templates found in
|
|
1295
|
+
// SSR-rendered siblings but absent from template.content. Without this,
|
|
1296
|
+
// refreshLoop re-renders from template.content and loses the inner template.
|
|
1297
|
+
const templateRoot = template.content.firstElementChild;
|
|
1298
|
+
if (templateRoot) {
|
|
1299
|
+
for (const elements of Object.values(existingElementsByKey)) {
|
|
1300
|
+
for (const el of elements) {
|
|
1301
|
+
if (el.querySelector && el.querySelector('template[p-for]')) {
|
|
1302
|
+
this.enrichTemplateContent(templateRoot, el);
|
|
1303
|
+
}
|
|
1304
|
+
}
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1253
1307
|
|
|
1254
1308
|
let index = 0;
|
|
1255
1309
|
let lastInserted = template;
|
|
@@ -1267,6 +1321,10 @@ window.Pattr = {
|
|
|
1267
1321
|
el.setAttribute('p-for-key', scopePrefix + index);
|
|
1268
1322
|
}
|
|
1269
1323
|
this.walkDom(el, loopScope, true);
|
|
1324
|
+
// Mark AFTER walkDom so that the parent walkDom (which may still be
|
|
1325
|
+
// iterating over children that include this element) knows to skip it
|
|
1326
|
+
// and avoid re-evaluating its directives with the wrong outer scope.
|
|
1327
|
+
el._p_loopHydrated = true;
|
|
1270
1328
|
template._forData.renderedElements.push(el);
|
|
1271
1329
|
lastInserted = el;
|
|
1272
1330
|
});
|
|
@@ -1466,6 +1524,13 @@ window.Pattr = {
|
|
|
1466
1524
|
* Walks the DOM tree, processing scopes, event handlers, and directives
|
|
1467
1525
|
*/
|
|
1468
1526
|
walkDom(el, parentScope, isHydrating = false) {
|
|
1527
|
+
// Skip elements already fully hydrated by hydrateLoop during this hydration pass.
|
|
1528
|
+
// This prevents the parent walkDom from re-evaluating inner SSR elements with the
|
|
1529
|
+
// wrong (outer-loop) scope when those elements live inside an outer SSR element.
|
|
1530
|
+
if (isHydrating && el._p_loopHydrated) {
|
|
1531
|
+
return;
|
|
1532
|
+
}
|
|
1533
|
+
|
|
1469
1534
|
// Handle p-for templates separately
|
|
1470
1535
|
if (el.tagName === 'TEMPLATE' && el.hasAttribute('p-for')) {
|
|
1471
1536
|
// Skip nested templates during refresh (non-hydrating) - they will be
|
|
@@ -1524,6 +1589,24 @@ window.Pattr = {
|
|
|
1524
1589
|
});
|
|
1525
1590
|
}
|
|
1526
1591
|
|
|
1592
|
+
// During hydration, don't recurse into children of a hidden element.
|
|
1593
|
+
// This prevents nested <template p-for> directives from being evaluated with
|
|
1594
|
+
// undefined loop variables when their containing p-show element is false
|
|
1595
|
+
// (e.g. the inner array loop inside an array-container that is hidden for scalar values).
|
|
1596
|
+
if (isHydrating && currentScope) {
|
|
1597
|
+
for (const attr of el.attributes) {
|
|
1598
|
+
const parsed = this.parseDirectiveModifiers(attr.name);
|
|
1599
|
+
if (parsed.directive === 'p-show' && !parsed.modifiers['pre-scope']) {
|
|
1600
|
+
try {
|
|
1601
|
+
if (!eval(`with (currentScope) { (${attr.value}) }`)) {
|
|
1602
|
+
return;
|
|
1603
|
+
}
|
|
1604
|
+
} catch (e) { /* ignore evaluation errors, proceed with children */ }
|
|
1605
|
+
break;
|
|
1606
|
+
}
|
|
1607
|
+
}
|
|
1608
|
+
}
|
|
1609
|
+
|
|
1527
1610
|
// Recurse to children
|
|
1528
1611
|
// Use Array.from to capture a snapshot of children, avoiding issues where
|
|
1529
1612
|
// p-for templates insert new elements during the walk
|
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 a=String(t);if(r.trim&&r.trim.length>0){const e=parseInt(r.trim[0])||100;a.length>e&&(a=a.substring(0,e)+"...")}e.innerText=a},"p-html":(e,t,r={})=>{let a=t;if(r.allow&&r.allow.length>0){const e=r.allow,t=document.createElement("div");t.innerHTML=a;const s=t=>{if(t.nodeType===Node.ELEMENT_NODE){const r=t.tagName.toLowerCase();if(!e.includes(r)){const e=document.createDocumentFragment();return Array.from(t.childNodes).forEach(t=>{const r=s(t);r&&e.appendChild(r)}),e}const a=t.cloneNode(!1);return Array.from(t.childNodes).forEach(e=>{const t=s(e);t&&a.appendChild(t)}),a}return t.cloneNode()},o=document.createElement("div");Array.from(t.childNodes).forEach(e=>{const t=s(e);t&&o.appendChild(t)}),a=o.innerHTML}if(r.trim&&r.trim.length>0){const e=parseInt(r.trim[0])||100,t=document.createElement("div");t.innerHTML=a;let s=0,o=!1;const n=t=>{if(o)return null;if(t.nodeType===Node.TEXT_NODE){const r=t.textContent,a=e-s;if(r.length<=a)return s+=r.length,t.cloneNode();{o=!0;const e=r.substring(0,a)+"...";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),o)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),o)break}a=i.innerHTML}e.innerHTML=a},"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,r={})=>{if(void 0!==r.replace)return void("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(" ")));let a=new Set,s=new Set;if("string"==typeof t&&t?t.split(" ").forEach(e=>{e&&(a.add(e),s.add(e))}):Array.isArray(t)?t.forEach(e=>{e&&(a.add(e),s.add(e))}):"object"==typeof t&&null!==t&&Object.keys(t).forEach(e=>{s.add(e),t[e]&&a.add(e)}),!e._p_staticClasses){const t=e.className?e.className.split(" ").filter(e=>e):[];e._p_staticClasses=t.filter(e=>!s.has(e))}e._p_dynamicClasses||(e._p_dynamicClasses=new Set),e._p_dynamicClasses=a;const o=[...e._p_staticClasses,...e._p_dynamicClasses];e.className=o.join(" ")},"p-model":(e,t)=>{Array.isArray(t)?e.value=t.join(", "):e.value=t},"p-attr":(e,t,r={})=>{const a=Object.keys(r);if(a.length>0){const r=a[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 a=t[r];null==a||!1===a?e.removeAttribute(r):e.setAttribute(r,String(a))})}},parseDirectiveModifiers(e){const t=e.split(":"),r=t[0],a={};for(let e=1;e<t.length;e++){const r=t[e].split("."),s=r[0],o=r.slice(1);a[s]=o}return{directive:r,modifiers:a}},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 a=Array.from(e.children).indexOf(r);t.unshift(`${r.tagName}[${a}]`)}r=e}return t.join("/")},buildScopeData(e,t){let r=t;const a=Array.from(e.attributes).find(e=>e.name.startsWith("p-scope"));if(a){const s=e.getAttribute("p-id")||this.generateDomPathId(e);t._p_children||(t._p_children={}),t._p_children[s]||(t._p_children[s]={}),r=t._p_children[s],r._p_scope=e.getAttribute(a.name),r._p_id=s}let s=e.firstElementChild;for(;s;)this.buildScopeData(s,r),s=s.nextElementSibling},observe(e,t,r=[]){const a=e;let s=a;t&&(s=Object.create(t._p_target||t),Object.assign(s,a));const o=new Set(r),n=t?._p_target||t,i=new WeakSet,c=(e,t=!1,r=null)=>{if(null===e||"object"!=typeof e)return e;if(i.has(e))return e;if(e instanceof Date||e instanceof RegExp||e instanceof Map||e instanceof Set)return e;const a=new Proxy(e,{get:(e,a)=>{if("_p_target"===a)return e;if("_p_syncParent"===a)return n;if("_p_syncKey"===a)return r;const s=e[a];return t&&null!==s&&"object"==typeof s?c(s,!0,r):s},set:(e,a,s)=>{if(null!==s&&"object"==typeof s&&(s=c(s,t,r)),e[a]=s,t&&n&&r){const e=n[r];e&&"object"==typeof e&&(null===s||"object"!=typeof s||e[a]._p_isProxy?e[a]=s:e[a]=c(s,t,r))}return this.walkDom(this.root,this.data,!1),!0},has:(e,t)=>t in e});return i.add(e),a};if(n)for(const e of o){if(e in s){const t=s[e];null!==t&&"object"==typeof t&&(s[e]=c(t,!0))}if(e in n){const t=n[e];null!==t&&"object"==typeof t&&(n[e]=c(t,!0))}}return new Proxy(s,{get:(e,t)=>"_p_target"===t?e:e[t],set:(e,t,r)=>(o.has(t)&&null!==r&&"object"==typeof r&&(r=c(r,!0,t)),e[t]=r,o.has(t)&&n&&t in n&&(n[t]=r),this.walkDom(this.root,this.data,!1),!0),has:(e,t)=>t in e})},splitPScopeStatements(e){const t=[];let r="",a=0,s=0,o=!1,n=null;for(let i=0;i<e.length;i++){const c=e[i],l=i>0?e[i-1]:null;'"'!==c&&"'"!==c&&"`"!==c||"\\"===l||(o?n===c&&(o=!1,n=null):(o=!0,n=c)),o||("{"===c?a++:"}"===c?a--:"("===c?s++:")"===c&&s--),";"!==c||o||0!==a||0!==s?r+=c:(r.trim()&&t.push(r.trim()),r="")}return r.trim()&&t.push(r.trim()),t},getPScopeOutputVars(e){const t=[];return this.splitPScopeStatements(e).forEach(e=>{const r=e.match(/^\[([^\]]+)\]\s*=\s*(.+)$/);if(r){const e=r[1].split(",").map(e=>e.trim());return void t.push(...e)}const a=e.match(/^\{([^}]+)\}\s*=\s*(.+)$/);if(a){const e=a[1].split(",").map(e=>e.trim());return void t.push(...e)}const s=e.match(/^(\w+)\s*=\s*(.+)$/);s&&t.push(s[1])}),t},initScope(e,t){const r=e.getAttribute("p-id")||this.generateDomPathId(e),a=t._p_target._p_children[r],s=e.getAttribute("p-scope"),o=Array.from(e.attributes).find(e=>e.name.startsWith("p-scope")&&e.name.includes("sync"));let n=[],i=[];if(s&&n.push(s),o){const t=e.getAttribute(o.name);n.push(t),i=this.getPScopeOutputVars(t)}const c=n.join("; "),l=this.observe(a,t,i);i.length>0&&(e._p_syncVars=new Set(i)),this.executePScopeStatements(l,c);const p=Object.getPrototypeOf(l._p_target);e._parentSnapshot={};for(let t in p)t.startsWith("_p_")||(e._parentSnapshot[t]=p[t]);const h=l._p_target;e._localSnapshot={};for(let t of Object.keys(h))t.startsWith("_p_")||(e._localSnapshot[t]=h[t]);return l},refreshScope(e,t){let r=e._scope;if(!r)return t;const a=e.getAttribute("p-scope"),s=Array.from(e.attributes).find(e=>e.name.startsWith("p-scope")&&e.name.includes("sync"));let o=[];a&&o.push(a),s&&o.push(e.getAttribute(s.name));const n=o.join("; ");return n&&r._p_target&&this.updateScopeFromParent(e,r,n),r},executePScopeStatements(scope,pScopeExpr){const statements=this.splitPScopeStatements(pScopeExpr),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 arrayDestructMatch=stmt.match(/^\[([^\]]+)\]\s*=\s*(.+)$/);if(arrayDestructMatch){const[,vars,expr]=arrayDestructMatch,varNames=vars.split(",").map(e=>e.trim());try{const value=eval(`with (sequentialScope) { (${expr}) }`);Array.isArray(value)&&varNames.forEach((e,t)=>{target[e]=value[t]})}catch(e){console.error(`Error executing p-scope array destructuring "${stmt}":`,e)}continue}const objDestructMatch=stmt.match(/^\{([^}]+)\}\s*=\s*(.+)$/);if(objDestructMatch){const[,vars,expr]=objDestructMatch,varNames=vars.split(",").map(e=>e.trim());try{const value=eval(`with (sequentialScope) { (${expr}) }`);"object"==typeof value&&null!==value&&varNames.forEach(e=>{target[e]=value[e]})}catch(e){console.error(`Error executing p-scope object destructuring "${stmt}":`,e)}continue}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=this.splitPScopeStatements(pScopeExpr),outputVars=new Set;statements.forEach(e=>{const t=e.match(/^\[([^\]]+)\]\s*=\s*(.+)$/);if(t){return void t[1].split(",").map(e=>e.trim()).forEach(e=>outputVars.add(e))}const r=e.match(/^\{([^}]+)\}\s*=\s*(.+)$/);if(r){return void r[1].split(",").map(e=>e.trim()).forEach(e=>outputVars.add(e))}const a=e.match(/^(\w+)\s*=\s*(.+)$/);a&&outputVars.add(a[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 arrayMatch=stmt.match(/^\[([^\]]+)\]\s*=\s*(.+)$/);if(arrayMatch){const[,vars,expr]=arrayMatch,varNames=vars.split(",").map(e=>e.trim()),value=eval(`with (sequentialScope) { (${expr}) }`);return void(Array.isArray(value)&&varNames.forEach((e,t)=>{target[e]=value[t],setInThisPass.add(e)}))}const objMatch=stmt.match(/^\{([^}]+)\}\s*=\s*(.+)$/);if(objMatch){const[,vars,expr]=objMatch,varNames=vars.split(",").map(e=>e.trim()),value=eval(`with (sequentialScope) { (${expr}) }`);return void("object"==typeof value&&null!==value&&varNames.forEach(e=>{target[e]=value[e],setInThisPass.add(e)}))}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.walkDom(this.root,this.data,!1),this.refreshAllLoops()})}})},registerModelBinding(el){const modelAttr=el.getAttribute("p-model");modelAttr&&(el.addEventListener("input",e=>{let value;const type=e.target.type;if("number"===type||"range"===type)value=""===e.target.value?null:Number(e.target.value);else if("checkbox"===type)value=e.target.checked;else if("radio"===type)value=e.target.checked?e.target.value:void 0;else{const currentValue=eval(`with (el._scope) { ${modelAttr} }`);value=Array.isArray(currentValue)?e.target.value.split(",").map(e=>e.trim()).filter(e=>e):e.target.value}if(void 0!==value){const scope=el._scope;if(modelAttr.includes("[")){const match=modelAttr.match(/^(.+)\[(.+)\]$/);if(match){const[,objName,keyExpr]=match,key=eval(`with (scope) { ${keyExpr} }`);scope[objName][key]=value}else eval(`with (scope) { ${modelAttr} = value }`)}else if(modelAttr.includes(".")){const e=modelAttr.split(".");let t=scope;for(let r=0;r<e.length-1;r++)t=t[e[r]];t[e[e.length-1]]=value}else scope[modelAttr]=value;let pForKey=el.getAttribute("p-for-key"),container=el;if(!pForKey)for(container=el.parentElement;container&&!pForKey;)pForKey=container.getAttribute("p-for-key"),pForKey||(container=container.parentElement);const modelAttrValue=el.getAttribute("p-model"),inputTagName=el.tagName,inputType=el.type;this.walkDom(this.root,this.data,!1),pForKey&&modelAttrValue&&requestAnimationFrame(()=>{const e=document.querySelector(`[p-for-key="${pForKey}"]`);if(e){const t=e.querySelector(`${inputTagName.toLowerCase()}[p-model="${modelAttrValue}"]`);t&&t.focus()}})}}),"checkbox"!==el.type&&"radio"!==el.type||el.addEventListener("change",e=>{let value;if(value="checkbox"===el.type?e.target.checked:e.target.checked?e.target.value:void 0,void 0!==value){const scope=el._scope;if(modelAttr.includes("[")){const match=modelAttr.match(/^(.+)\[(.+)\]$/);if(match){const[,objName,keyExpr]=match,key=eval(`with (scope) { ${keyExpr} }`);scope[objName][key]=value}else eval(`with (scope) { ${modelAttr} = value }`)}else 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 a=e.getAttribute("p-for"),s=a.match(/^(?:const|let)?\s*(.+?)\s+(of|in)\s+(.+)$/);if(!s)return void console.error(`Invalid p-for expression: ${a}`);const[,o,n,i]=s;r?this.hydrateLoop(e,t,o,i):this.refreshLoop(e,t,o,i)},getTemplateScopePrefix(e){let t="",r=e.nextElementSibling;if(r&&r.hasAttribute&&r.hasAttribute("p-for-key")){const a=r.getAttribute("p-for-key"),s=a.lastIndexOf(":");if(s>0){const r=a.substring(0,s+1),o=r.lastIndexOf("-");if(o>=0){t=r.substring(0,o+1);const a=r.substring(o+1,r.length-1);e._forScopeId=a}else e._forScopeId=r.substring(0,r.length-1);return r}}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 a=e.renderedElements.indexOf(r);if(a>=0){t=(e.scopePrefix||"")+a+"-";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 a=document.createDocumentFragment();r.forEach(e=>a.appendChild(e)),lastInserted.parentNode.insertBefore(a,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),a=Array.from(t.children);a.forEach(e=>{e._scope=r,this.setForTemplateRecursive(e,template),"TEMPLATE"!==e.tagName&&e.setAttribute("p-for-key",scopePrefix+index)});const s=document.createDocumentFragment();a.forEach(e=>s.appendChild(e)),lastInsertedElement.parentNode.insertBefore(s,lastInsertedElement.nextSibling),forData.renderedElements.push(...a),a.forEach(e=>{this.walkDom(e,r,!0)});const o=a[a.length-1];o&&(lastInsertedElement=this.findLastRenderedSibling(o)),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 a={};if((t=t.trim()).startsWith("[")){const e=t.slice(1,-1).split(",").map(e=>e.trim());Array.isArray(r)?e.forEach((e,t)=>a[e]=r[t]):a[e[0]]=r}else if(t.startsWith("{")){t.slice(1,-1).split(",").map(e=>e.trim()).forEach(e=>{const[t,s]=e.split(":").map(e=>e.trim());a[s||t]=r[t]})}else a[t]=r;if(!e)return console.error("parentScope is undefined in createLoopScope"),new Proxy({},{get:()=>{},set:()=>!1});const s=e._p_target||e;if(!s||"object"!=typeof s)return console.error("Invalid parentTarget:",s),new Proxy(a,{get:(e,t)=>e[t],set:(e,t,r)=>(e[t]=r,!0)});const o=Object.create(s);Object.assign(o,a);const n=new Proxy(o,{get:(e,t)=>e[t],set:(e,t,r)=>(t in a?e[t]=r:s[t]=r,!0)});return n._p_target=o,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;const hasPScope=Array.from(el.attributes).some(e=>e.name.startsWith("p-scope"));hasPScope&&(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 a=String(t);if(r.trim&&r.trim.length>0){const e=parseInt(r.trim[0])||100;a.length>e&&(a=a.substring(0,e)+"...")}e.innerText=a},"p-html":(e,t,r={})=>{let a=t;if(r.allow&&r.allow.length>0){const e=r.allow,t=document.createElement("div");t.innerHTML=a;const s=t=>{if(t.nodeType===Node.ELEMENT_NODE){const r=t.tagName.toLowerCase();if(!e.includes(r)){const e=document.createDocumentFragment();return Array.from(t.childNodes).forEach(t=>{const r=s(t);r&&e.appendChild(r)}),e}const a=t.cloneNode(!1);return Array.from(t.childNodes).forEach(e=>{const t=s(e);t&&a.appendChild(t)}),a}return t.cloneNode()},o=document.createElement("div");Array.from(t.childNodes).forEach(e=>{const t=s(e);t&&o.appendChild(t)}),a=o.innerHTML}if(r.trim&&r.trim.length>0){const e=parseInt(r.trim[0])||100,t=document.createElement("div");t.innerHTML=a;let s=0,o=!1;const n=t=>{if(o)return null;if(t.nodeType===Node.TEXT_NODE){const r=t.textContent,a=e-s;if(r.length<=a)return s+=r.length,t.cloneNode();{o=!0;const e=r.substring(0,a)+"...";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),o)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),o)break}a=i.innerHTML}e.innerHTML=a},"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,r={})=>{if(void 0!==r.replace)return void("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(" ")));let a=new Set,s=new Set;if("string"==typeof t&&t?t.split(" ").forEach(e=>{e&&(a.add(e),s.add(e))}):Array.isArray(t)?t.forEach(e=>{e&&(a.add(e),s.add(e))}):"object"==typeof t&&null!==t&&Object.keys(t).forEach(e=>{s.add(e),t[e]&&a.add(e)}),!e._p_staticClasses){const t=e.className?e.className.split(" ").filter(e=>e):[];e._p_staticClasses=t.filter(e=>!s.has(e))}e._p_dynamicClasses||(e._p_dynamicClasses=new Set),e._p_dynamicClasses=a;const o=[...e._p_staticClasses,...e._p_dynamicClasses];e.className=o.join(" ")},"p-model":(e,t)=>{Array.isArray(t)?e.value=t.join(", "):e.value=t},"p-attr":(e,t,r={})=>{const a=Object.keys(r);if(a.length>0){const r=a[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 a=t[r];null==a||!1===a?e.removeAttribute(r):e.setAttribute(r,String(a))})}},parseDirectiveModifiers(e){const t=e.split(":"),r=t[0],a={};for(let e=1;e<t.length;e++){const r=t[e].split("."),s=r[0],o=r.slice(1);a[s]=o}return{directive:r,modifiers:a}},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 a=Array.from(e.children).indexOf(r);t.unshift(`${r.tagName}[${a}]`)}r=e}return t.join("/")},buildScopeData(e,t){let r=t;const a=Array.from(e.attributes).find(e=>e.name.startsWith("p-scope"));if(a){const s=e.getAttribute("p-id")||this.generateDomPathId(e);t._p_children||(t._p_children={}),t._p_children[s]||(t._p_children[s]={}),r=t._p_children[s],r._p_scope=e.getAttribute(a.name),r._p_id=s}let s=e.firstElementChild;for(;s;)this.buildScopeData(s,r),s=s.nextElementSibling},observe(e,t,r=[]){const a=e;let s=a;t&&(s=Object.create(t._p_target||t),Object.assign(s,a));const o=new Set(r),n=t?._p_target||t,i=new WeakSet,c=(e,t=!1,r=null)=>{if(null===e||"object"!=typeof e)return e;if(i.has(e))return e;if(e instanceof Date||e instanceof RegExp||e instanceof Map||e instanceof Set)return e;const a=new Proxy(e,{get:(e,a)=>{if("_p_target"===a)return e;if("_p_syncParent"===a)return n;if("_p_syncKey"===a)return r;const s=e[a];return t&&null!==s&&"object"==typeof s?c(s,!0,r):s},set:(e,a,s)=>{if(null!==s&&"object"==typeof s&&(s=c(s,t,r)),e[a]=s,t&&n&&r){const e=n[r];e&&"object"==typeof e&&(null===s||"object"!=typeof s||e[a]._p_isProxy?e[a]=s:e[a]=c(s,t,r))}return this.walkDom(this.root,this.data,!1),!0},has:(e,t)=>t in e});return i.add(e),a};if(n)for(const e of o){if(e in s){const t=s[e];null!==t&&"object"==typeof t&&(s[e]=c(t,!0))}if(e in n){const t=n[e];null!==t&&"object"==typeof t&&(n[e]=c(t,!0))}}return new Proxy(s,{get:(e,t)=>"_p_target"===t?e:e[t],set:(e,t,r)=>(o.has(t)&&null!==r&&"object"==typeof r&&(r=c(r,!0,t)),e[t]=r,o.has(t)&&n&&t in n&&(n[t]=r),this.walkDom(this.root,this.data,!1),!0),has:(e,t)=>t in e})},splitPScopeStatements(e){const t=[];let r="",a=0,s=0,o=!1,n=null;for(let i=0;i<e.length;i++){const c=e[i],l=i>0?e[i-1]:null;'"'!==c&&"'"!==c&&"`"!==c||"\\"===l||(o?n===c&&(o=!1,n=null):(o=!0,n=c)),o||("{"===c?a++:"}"===c?a--:"("===c?s++:")"===c&&s--),";"!==c||o||0!==a||0!==s?r+=c:(r.trim()&&t.push(r.trim()),r="")}return r.trim()&&t.push(r.trim()),t},getPScopeOutputVars(e){const t=[];return this.splitPScopeStatements(e).forEach(e=>{const r=e.match(/^\[([^\]]+)\]\s*=\s*(.+)$/);if(r){const e=r[1].split(",").map(e=>e.trim());return void t.push(...e)}const a=e.match(/^\{([^}]+)\}\s*=\s*(.+)$/);if(a){const e=a[1].split(",").map(e=>e.trim());return void t.push(...e)}const s=e.match(/^(\w+)\s*=\s*(.+)$/);s&&t.push(s[1])}),t},initScope(e,t){const r=e.getAttribute("p-id")||this.generateDomPathId(e),a=t._p_target._p_children[r],s=e.getAttribute("p-scope"),o=Array.from(e.attributes).find(e=>e.name.startsWith("p-scope")&&e.name.includes("sync"));let n=[],i=[];if(s&&n.push(s),o){const t=e.getAttribute(o.name);n.push(t),i=this.getPScopeOutputVars(t)}const c=n.join("; "),l=this.observe(a,t,i);i.length>0&&(e._p_syncVars=new Set(i)),this.executePScopeStatements(l,c);const p=Object.getPrototypeOf(l._p_target);e._parentSnapshot={};for(let t in p)t.startsWith("_p_")||(e._parentSnapshot[t]=p[t]);const h=l._p_target;e._localSnapshot={};for(let t of Object.keys(h))t.startsWith("_p_")||(e._localSnapshot[t]=h[t]);return l},refreshScope(e,t){let r=e._scope;if(!r)return t;const a=e.getAttribute("p-scope"),s=Array.from(e.attributes).find(e=>e.name.startsWith("p-scope")&&e.name.includes("sync"));let o=[];a&&o.push(a),s&&o.push(e.getAttribute(s.name));const n=o.join("; ");return n&&r._p_target&&this.updateScopeFromParent(e,r,n),r},executePScopeStatements(scope,pScopeExpr){const statements=this.splitPScopeStatements(pScopeExpr),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 arrayDestructMatch=stmt.match(/^\[([^\]]+)\]\s*=\s*(.+)$/);if(arrayDestructMatch){const[,vars,expr]=arrayDestructMatch,varNames=vars.split(",").map(e=>e.trim());try{const value=eval(`with (sequentialScope) { (${expr}) }`);Array.isArray(value)&&varNames.forEach((e,t)=>{target[e]=value[t]})}catch(e){console.error(`Error executing p-scope array destructuring "${stmt}":`,e)}continue}const objDestructMatch=stmt.match(/^\{([^}]+)\}\s*=\s*(.+)$/);if(objDestructMatch){const[,vars,expr]=objDestructMatch,varNames=vars.split(",").map(e=>e.trim());try{const value=eval(`with (sequentialScope) { (${expr}) }`);"object"==typeof value&&null!==value&&varNames.forEach(e=>{target[e]=value[e]})}catch(e){console.error(`Error executing p-scope object destructuring "${stmt}":`,e)}continue}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=this.splitPScopeStatements(pScopeExpr),outputVars=new Set;statements.forEach(e=>{const t=e.match(/^\[([^\]]+)\]\s*=\s*(.+)$/);if(t){return void t[1].split(",").map(e=>e.trim()).forEach(e=>outputVars.add(e))}const r=e.match(/^\{([^}]+)\}\s*=\s*(.+)$/);if(r){return void r[1].split(",").map(e=>e.trim()).forEach(e=>outputVars.add(e))}const a=e.match(/^(\w+)\s*=\s*(.+)$/);a&&outputVars.add(a[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 arrayMatch=stmt.match(/^\[([^\]]+)\]\s*=\s*(.+)$/);if(arrayMatch){const[,vars,expr]=arrayMatch,varNames=vars.split(",").map(e=>e.trim()),value=eval(`with (sequentialScope) { (${expr}) }`);return void(Array.isArray(value)&&varNames.forEach((e,t)=>{target[e]=value[t],setInThisPass.add(e)}))}const objMatch=stmt.match(/^\{([^}]+)\}\s*=\s*(.+)$/);if(objMatch){const[,vars,expr]=objMatch,varNames=vars.split(",").map(e=>e.trim()),value=eval(`with (sequentialScope) { (${expr}) }`);return void("object"==typeof value&&null!==value&&varNames.forEach(e=>{target[e]=value[e],setInThisPass.add(e)}))}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.walkDom(this.root,this.data,!1),this.refreshAllLoops()})}})},registerModelBinding(el){const modelAttr=el.getAttribute("p-model");modelAttr&&(el.addEventListener("input",e=>{let value;const type=e.target.type;if("number"===type||"range"===type)value=""===e.target.value?null:Number(e.target.value);else if("checkbox"===type)value=e.target.checked;else if("radio"===type)value=e.target.checked?e.target.value:void 0;else{const currentValue=eval(`with (el._scope) { ${modelAttr} }`);value=Array.isArray(currentValue)?e.target.value.split(",").map(e=>e.trim()).filter(e=>e):e.target.value}if(void 0!==value){const scope=el._scope;if(modelAttr.includes("[")){const lastBracket=modelAttr.lastIndexOf("["),containerExpr=modelAttr.substring(0,lastBracket),keyExpr=modelAttr.substring(lastBracket+1,modelAttr.length-1),container=eval(`with (scope) { (${containerExpr}) }`),key=eval(`with (scope) { (${keyExpr}) }`);container[key]=value}else if(modelAttr.includes(".")){const e=modelAttr.split(".");let t=scope;for(let r=0;r<e.length-1;r++)t=t[e[r]];t[e[e.length-1]]=value}else scope[modelAttr]=value;let pForKey=el.getAttribute("p-for-key"),container=el;if(!pForKey)for(container=el.parentElement;container&&!pForKey;)pForKey=container.getAttribute("p-for-key"),pForKey||(container=container.parentElement);const modelAttrValue=el.getAttribute("p-model"),inputTagName=el.tagName,inputType=el.type;this.walkDom(this.root,this.data,!1),pForKey&&modelAttrValue&&requestAnimationFrame(()=>{const e=document.querySelector(`[p-for-key="${pForKey}"]`);if(e){const t=e.querySelector(`${inputTagName.toLowerCase()}[p-model="${modelAttrValue}"]`);t&&t.focus()}})}}),"checkbox"!==el.type&&"radio"!==el.type||el.addEventListener("change",e=>{let value;if(value="checkbox"===el.type?e.target.checked:e.target.checked?e.target.value:void 0,void 0!==value){const scope=el._scope;if(modelAttr.includes("[")){const lastBracket=modelAttr.lastIndexOf("["),containerExpr=modelAttr.substring(0,lastBracket),keyExpr=modelAttr.substring(lastBracket+1,modelAttr.length-1),container=eval(`with (scope) { (${containerExpr}) }`),key=eval(`with (scope) { (${keyExpr}) }`);container[key]=value}else 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 a=e.getAttribute("p-for"),s=a.match(/^(?:const|let)?\s*(.+?)\s+(of|in)\s+(.+)$/);if(!s)return void console.error(`Invalid p-for expression: ${a}`);const[,o,n,i]=s;r?this.hydrateLoop(e,t,o,i):this.refreshLoop(e,t,o,i)},getTemplateScopePrefix(e){let t="",r=e.nextElementSibling;if(r&&r.hasAttribute&&r.hasAttribute("p-for-key")){const a=r.getAttribute("p-for-key"),s=a.lastIndexOf(":");if(s>0){const r=a.substring(0,s+1),o=r.lastIndexOf("-");if(o>=0){t=r.substring(0,o+1);const a=r.substring(o+1,r.length-1);e._forScopeId=a}else e._forScopeId=r.substring(0,r.length-1);return r}}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 a=e.renderedElements.indexOf(r);if(a>=0){t=(e.scopePrefix||"")+a+"-";break}}}r=r.parentElement}}return e._forScopeId||(e._forScopeId="s"+this._templateScopeCounter++),t+e._forScopeId+":"},enrichTemplateContent(e,t){const r=Array.from(t.children).filter(e=>!e.hasAttribute("p-for-key")),a=Array.from(e.children);let s=0;for(const t of r)if("TEMPLATE"===t.tagName&&t.hasAttribute("p-for")){const r=a[s];if(!(r&&"TEMPLATE"===r.tagName&&r.getAttribute("p-for")===t.getAttribute("p-for"))){const o=t.cloneNode(!0);e.insertBefore(o,r||null),a.splice(s,0,o)}s++}else s<a.length&&a[s].tagName===t.tagName&&(this.enrichTemplateContent(a[s],t),s++)},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}const templateRoot=template.content.firstElementChild;if(templateRoot)for(const e of Object.values(existingElementsByKey))for(const t of e)t.querySelector&&t.querySelector("template[p-for]")&&this.enrichTemplateContent(templateRoot,t);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),e._p_loopHydrated=!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 a=document.createDocumentFragment();r.forEach(e=>a.appendChild(e)),lastInserted.parentNode.insertBefore(a,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),a=Array.from(t.children);a.forEach(e=>{e._scope=r,this.setForTemplateRecursive(e,template),"TEMPLATE"!==e.tagName&&e.setAttribute("p-for-key",scopePrefix+index)});const s=document.createDocumentFragment();a.forEach(e=>s.appendChild(e)),lastInsertedElement.parentNode.insertBefore(s,lastInsertedElement.nextSibling),forData.renderedElements.push(...a),a.forEach(e=>{this.walkDom(e,r,!0)});const o=a[a.length-1];o&&(lastInsertedElement=this.findLastRenderedSibling(o)),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 a={};if((t=t.trim()).startsWith("[")){const e=t.slice(1,-1).split(",").map(e=>e.trim());Array.isArray(r)?e.forEach((e,t)=>a[e]=r[t]):a[e[0]]=r}else if(t.startsWith("{")){t.slice(1,-1).split(",").map(e=>e.trim()).forEach(e=>{const[t,s]=e.split(":").map(e=>e.trim());a[s||t]=r[t]})}else a[t]=r;if(!e)return console.error("parentScope is undefined in createLoopScope"),new Proxy({},{get:()=>{},set:()=>!1});const s=e._p_target||e;if(!s||"object"!=typeof s)return console.error("Invalid parentTarget:",s),new Proxy(a,{get:(e,t)=>e[t],set:(e,t,r)=>(e[t]=r,!0)});const o=Object.create(s);Object.assign(o,a);const n=new Proxy(o,{get:(e,t)=>e[t],set:(e,t,r)=>(t in a?e[t]=r:s[t]=r,!0)});return n._p_target=o,n},walkDom(el,parentScope,isHydrating=!1){if(isHydrating&&el._p_loopHydrated)return;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;const hasPScope=Array.from(el.attributes).some(e=>e.name.startsWith("p-scope"));if(hasPScope&&(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)}}),isHydrating&¤tScope)for(const attr of el.attributes){const parsed=this.parseDirectiveModifiers(attr.name);if("p-show"===parsed.directive&&!parsed.modifiers["pre-scope"]){try{if(!eval(`with (currentScope) { (${attr.value}) }`))return}catch(e){}break}}const children=Array.from(el.children);for(const e of children)this.walkDom(e,currentScope,isHydrating)}},window.Pattr.start();
|