@plentico/pattr 0.0.8 → 0.0.10
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 +45 -0
- package/package.json +1 -1
- package/pattr.js +152 -9
- package/pattr.min.js +1 -1
package/README.md
CHANGED
|
@@ -127,6 +127,51 @@ You can combine both for complex scenarios:
|
|
|
127
127
|
<div p-class="{ active: isActive, disabled: !isEnabled }"></div>
|
|
128
128
|
```
|
|
129
129
|
|
|
130
|
+
#### Static Class Merging
|
|
131
|
+
|
|
132
|
+
By default, `p-class` preserves static classes defined in your HTML and merges them with dynamic classes:
|
|
133
|
+
|
|
134
|
+
```html
|
|
135
|
+
<div class="card animate" p-class="{ 'highlight': isActive }">
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
- `card` and `animate` are preserved (static classes not in p-class)
|
|
139
|
+
- `highlight` is added/removed based on `isActive`
|
|
140
|
+
- Result: `"card animate"` or `"card animate highlight"`
|
|
141
|
+
|
|
142
|
+
#### Class Collision Handling
|
|
143
|
+
|
|
144
|
+
If a static class has the same name as a dynamic class, `p-class` takes precedence and manages it:
|
|
145
|
+
|
|
146
|
+
```html
|
|
147
|
+
<div class="item collapsed" p-class="{ 'collapsed': !isExpanded }">
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
- `item` is preserved (no collision)
|
|
151
|
+
- `collapsed` is managed by `p-class` (collision - p-class wins)
|
|
152
|
+
- When `isExpanded=true`: class is `"item"` (collapsed removed)
|
|
153
|
+
- When `isExpanded=false`: class is `"item collapsed"`
|
|
154
|
+
|
|
155
|
+
#### `p-class:replace` - Replace All Classes
|
|
156
|
+
|
|
157
|
+
Use the `:replace` modifier to completely replace all classes (old behavior):
|
|
158
|
+
|
|
159
|
+
```html
|
|
160
|
+
<!-- Without :replace - merges with static classes -->
|
|
161
|
+
<div class="static-class" p-class="themeClass">
|
|
162
|
+
<!-- Result: "static-class dark-theme" -->
|
|
163
|
+
|
|
164
|
+
<!-- With :replace - replaces all classes -->
|
|
165
|
+
<div class="static-class" p-class:replace="themeClass">
|
|
166
|
+
<!-- Result: "dark-theme" (static-class removed) -->
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
This is useful when you want `p-class` to have complete control over the element's classes:
|
|
170
|
+
|
|
171
|
+
```html
|
|
172
|
+
<div class="old-theme" p-class:replace="{ 'light-theme': isLight, 'dark-theme': !isLight }">
|
|
173
|
+
```
|
|
174
|
+
|
|
130
175
|
### `p-attr` - Set Attributes
|
|
131
176
|
|
|
132
177
|
**Single attributes**
|
package/package.json
CHANGED
package/pattr.js
CHANGED
|
@@ -126,17 +126,76 @@ window.Pattr = {
|
|
|
126
126
|
Object.assign(el.style, value);
|
|
127
127
|
}
|
|
128
128
|
},
|
|
129
|
-
'p-class': (el, value) => {
|
|
130
|
-
|
|
131
|
-
|
|
129
|
+
'p-class': (el, value, modifiers = {}) => {
|
|
130
|
+
// Check for .replace modifier - completely replaces all classes
|
|
131
|
+
const shouldReplace = modifiers.replace !== undefined;
|
|
132
|
+
|
|
133
|
+
if (shouldReplace) {
|
|
134
|
+
// Replace mode: p-class.replace completely controls the className
|
|
135
|
+
if (typeof value === 'string') {
|
|
136
|
+
el.className = value;
|
|
137
|
+
} else if (Array.isArray(value)) {
|
|
138
|
+
el.className = value.join(' ');
|
|
139
|
+
} else if (typeof value === 'object' && value !== null) {
|
|
140
|
+
el.className = Object.keys(value)
|
|
141
|
+
.filter(key => value[key])
|
|
142
|
+
.join(' ');
|
|
143
|
+
}
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Merge mode: preserve static classes, add/remove dynamic ones
|
|
148
|
+
|
|
149
|
+
// Calculate new dynamic classes from the value FIRST
|
|
150
|
+
let newDynamicClasses = new Set();
|
|
151
|
+
// Track ALL potential dynamic class names (for collision detection with object format)
|
|
152
|
+
let allPotentialDynamicClasses = new Set();
|
|
153
|
+
|
|
154
|
+
if (typeof value === 'string' && value) {
|
|
155
|
+
value.split(' ').forEach(c => {
|
|
156
|
+
if (c) {
|
|
157
|
+
newDynamicClasses.add(c);
|
|
158
|
+
allPotentialDynamicClasses.add(c);
|
|
159
|
+
}
|
|
160
|
+
});
|
|
132
161
|
} else if (Array.isArray(value)) {
|
|
133
|
-
|
|
162
|
+
value.forEach(c => {
|
|
163
|
+
if (c) {
|
|
164
|
+
newDynamicClasses.add(c);
|
|
165
|
+
allPotentialDynamicClasses.add(c);
|
|
166
|
+
}
|
|
167
|
+
});
|
|
134
168
|
} else if (typeof value === 'object' && value !== null) {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
.
|
|
138
|
-
|
|
169
|
+
Object.keys(value).forEach(key => {
|
|
170
|
+
// All keys are potential dynamic classes (for collision detection)
|
|
171
|
+
allPotentialDynamicClasses.add(key);
|
|
172
|
+
// Only add to active dynamic classes if value is truthy
|
|
173
|
+
if (value[key]) newDynamicClasses.add(key);
|
|
174
|
+
});
|
|
139
175
|
}
|
|
176
|
+
|
|
177
|
+
// Initialize static classes tracking on first run
|
|
178
|
+
// IMPORTANT: Exclude any classes that are potential dynamic classes (collisions)
|
|
179
|
+
if (!el._p_staticClasses) {
|
|
180
|
+
const currentClasses = el.className ? el.className.split(' ').filter(c => c) : [];
|
|
181
|
+
// Exclude ALL potential dynamic class names (not just currently active ones)
|
|
182
|
+
// This ensures that for object format like {collapsed: false}, 'collapsed'
|
|
183
|
+
// is still excluded from static classes even though it's not currently active
|
|
184
|
+
el._p_staticClasses = currentClasses.filter(c => !allPotentialDynamicClasses.has(c));
|
|
185
|
+
}
|
|
186
|
+
if (!el._p_dynamicClasses) {
|
|
187
|
+
el._p_dynamicClasses = new Set();
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Update tracked dynamic classes
|
|
191
|
+
el._p_dynamicClasses = newDynamicClasses;
|
|
192
|
+
|
|
193
|
+
// Build final class list:
|
|
194
|
+
// 1. Start with static classes (already excludes collisions from first run)
|
|
195
|
+
// 2. Add all current dynamic classes
|
|
196
|
+
const finalClasses = [...el._p_staticClasses, ...el._p_dynamicClasses];
|
|
197
|
+
|
|
198
|
+
el.className = finalClasses.join(' ');
|
|
140
199
|
},
|
|
141
200
|
'p-model': (el, value) => {
|
|
142
201
|
// If value is an array, join with commas for display
|
|
@@ -358,6 +417,43 @@ window.Pattr = {
|
|
|
358
417
|
});
|
|
359
418
|
|
|
360
419
|
for (const stmt of statements) {
|
|
420
|
+
// Check for array destructuring: [a, b] = expr
|
|
421
|
+
const arrayDestructMatch = stmt.match(/^\[([^\]]+)\]\s*=\s*(.+)$/);
|
|
422
|
+
if (arrayDestructMatch) {
|
|
423
|
+
const [, vars, expr] = arrayDestructMatch;
|
|
424
|
+
const varNames = vars.split(',').map(v => v.trim());
|
|
425
|
+
try {
|
|
426
|
+
const value = eval(`with (sequentialScope) { (${expr}) }`);
|
|
427
|
+
if (Array.isArray(value)) {
|
|
428
|
+
varNames.forEach((varName, i) => {
|
|
429
|
+
target[varName] = value[i];
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
} catch (e) {
|
|
433
|
+
console.error(`Error executing p-scope array destructuring "${stmt}":`, e);
|
|
434
|
+
}
|
|
435
|
+
continue;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
// Check for object destructuring: {a, b} = expr
|
|
439
|
+
const objDestructMatch = stmt.match(/^\{([^}]+)\}\s*=\s*(.+)$/);
|
|
440
|
+
if (objDestructMatch) {
|
|
441
|
+
const [, vars, expr] = objDestructMatch;
|
|
442
|
+
const varNames = vars.split(',').map(v => v.trim());
|
|
443
|
+
try {
|
|
444
|
+
const value = eval(`with (sequentialScope) { (${expr}) }`);
|
|
445
|
+
if (typeof value === 'object' && value !== null) {
|
|
446
|
+
varNames.forEach(varName => {
|
|
447
|
+
target[varName] = value[varName];
|
|
448
|
+
});
|
|
449
|
+
}
|
|
450
|
+
} catch (e) {
|
|
451
|
+
console.error(`Error executing p-scope object destructuring "${stmt}":`, e);
|
|
452
|
+
}
|
|
453
|
+
continue;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
// Regular variable assignment
|
|
361
457
|
const match = stmt.match(/^(\w+)\s*=\s*(.+)$/);
|
|
362
458
|
if (match) {
|
|
363
459
|
const [, varName, expr] = match;
|
|
@@ -421,6 +517,23 @@ window.Pattr = {
|
|
|
421
517
|
// Local changes to these should NOT trigger re-execution
|
|
422
518
|
const outputVars = new Set();
|
|
423
519
|
statements.forEach(stmt => {
|
|
520
|
+
// Handle array destructuring: [a, b] = expr
|
|
521
|
+
const arrayMatch = stmt.match(/^\[([^\]]+)\]\s*=\s*(.+)$/);
|
|
522
|
+
if (arrayMatch) {
|
|
523
|
+
const vars = arrayMatch[1].split(',').map(v => v.trim());
|
|
524
|
+
vars.forEach(v => outputVars.add(v));
|
|
525
|
+
return;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
// Handle object destructuring: {a, b} = expr
|
|
529
|
+
const objMatch = stmt.match(/^\{([^}]+)\}\s*=\s*(.+)$/);
|
|
530
|
+
if (objMatch) {
|
|
531
|
+
const vars = objMatch[1].split(',').map(v => v.trim());
|
|
532
|
+
vars.forEach(v => outputVars.add(v));
|
|
533
|
+
return;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
// Regular variable
|
|
424
537
|
const match = stmt.match(/^(\w+)\s*=\s*(.+)$/);
|
|
425
538
|
if (match) {
|
|
426
539
|
outputVars.add(match[1]);
|
|
@@ -498,6 +611,37 @@ window.Pattr = {
|
|
|
498
611
|
}
|
|
499
612
|
|
|
500
613
|
if (shouldExecute) {
|
|
614
|
+
// Handle array destructuring: [a, b] = expr
|
|
615
|
+
const arrayMatch = stmt.match(/^\[([^\]]+)\]\s*=\s*(.+)$/);
|
|
616
|
+
if (arrayMatch) {
|
|
617
|
+
const [, vars, expr] = arrayMatch;
|
|
618
|
+
const varNames = vars.split(',').map(v => v.trim());
|
|
619
|
+
const value = eval(`with (sequentialScope) { (${expr}) }`);
|
|
620
|
+
if (Array.isArray(value)) {
|
|
621
|
+
varNames.forEach((varName, i) => {
|
|
622
|
+
target[varName] = value[i];
|
|
623
|
+
setInThisPass.add(varName);
|
|
624
|
+
});
|
|
625
|
+
}
|
|
626
|
+
return;
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
// Handle object destructuring: {a, b} = expr
|
|
630
|
+
const objMatch = stmt.match(/^\{([^}]+)\}\s*=\s*(.+)$/);
|
|
631
|
+
if (objMatch) {
|
|
632
|
+
const [, vars, expr] = objMatch;
|
|
633
|
+
const varNames = vars.split(',').map(v => v.trim());
|
|
634
|
+
const value = eval(`with (sequentialScope) { (${expr}) }`);
|
|
635
|
+
if (typeof value === 'object' && value !== null) {
|
|
636
|
+
varNames.forEach(varName => {
|
|
637
|
+
target[varName] = value[varName];
|
|
638
|
+
setInThisPass.add(varName);
|
|
639
|
+
});
|
|
640
|
+
}
|
|
641
|
+
return;
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
// Regular variable assignment
|
|
501
645
|
const match = stmt.match(/^(\w+)\s*=\s*(.+)$/);
|
|
502
646
|
if (match) {
|
|
503
647
|
const [, varName, expr] = match;
|
|
@@ -1049,4 +1193,3 @@ window.Pattr = {
|
|
|
1049
1193
|
}
|
|
1050
1194
|
|
|
1051
1195
|
window.Pattr.start()
|
|
1052
|
-
|
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 o=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=o(t);r&&e.appendChild(r)}),e}const a=t.cloneNode(!1);return Array.from(t.childNodes).forEach(e=>{const t=o(e);t&&a.appendChild(t)}),a}return t.cloneNode()},s=document.createElement("div");Array.from(t.childNodes).forEach(e=>{const t=o(e);t&&s.appendChild(t)}),a=s.innerHTML}if(r.trim&&r.trim.length>0){const e=parseInt(r.trim[0])||100,t=document.createElement("div");t.innerHTML=a;let o=0,s=!1;const n=t=>{if(s)return null;if(t.nodeType===Node.TEXT_NODE){const r=t.textContent,a=e-o;if(r.length<=a)return o+=r.length,t.cloneNode();{s=!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),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}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)=>{"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)=>{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("."),o=r[0],s=r.slice(1);a[o]=s}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;if(e.hasAttribute("p-scope")){const a=e.getAttribute("p-id")||this.generateDomPathId(e);t._p_children||(t._p_children={}),t._p_children[a]||(t._p_children[a]={}),r=t._p_children[a],r._p_scope=e.getAttribute("p-scope"),r._p_id=a}let a=e.firstElementChild;for(;a;)this.buildScopeData(a,r),a=a.nextElementSibling},observe(e,t){const r=e;let a=r;t&&(a=Object.create(t._p_target||t),Object.assign(a,r));return new Proxy(a,{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),a=t._p_target._p_children[r],o=this.observe(a,t);this.executePScopeStatements(o,a._p_scope);const s=Object.getPrototypeOf(o._p_target);e._parentSnapshot={};for(let t in s)t.startsWith("_p_")||(e._parentSnapshot[t]=s[t]);const n=o._p_target;e._localSnapshot={};for(let t of Object.keys(n))t.startsWith("_p_")||(e._localSnapshot[t]=n[t]);return o},refreshScope(e,t){let r=e._scope;if(!r)return t;const a=e.getAttribute("p-scope");return a&&r._p_target&&this.updateScopeFromParent(e,r,a),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;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}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 a=e.getAttribute("p-for"),o=a.match(/^(?:const|let)?\s*(.+?)\s+(of|in)\s+(.+)$/);if(!o)return void console.error(`Invalid p-for expression: ${a}`);const[,s,n,i]=o;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 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 o=document.createDocumentFragment();a.forEach(e=>o.appendChild(e)),lastInsertedElement.parentNode.insertBefore(o,lastInsertedElement.nextSibling),forData.renderedElements.push(...a),a.forEach(e=>{this.walkDom(e,r,!0)});const s=a[a.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 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,o]=e.split(":").map(e=>e.trim());a[o||t]=r[t]})}else a[t]=r;if(!e)return console.error("parentScope is undefined in createLoopScope"),new Proxy({},{get:()=>{},set:()=>!1});const o=e._p_target||e;if(!o||"object"!=typeof o)return console.error("Invalid parentTarget:",o),new Proxy(a,{get:(e,t)=>e[t],set:(e,t,r)=>(e[t]=r,!0)});const s=Object.create(o);Object.assign(s,a);const n=new Proxy(s,{get:(e,t)=>e[t],set:(e,t,r)=>(t in a?e[t]=r:o[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 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;if(e.hasAttribute("p-scope")){const a=e.getAttribute("p-id")||this.generateDomPathId(e);t._p_children||(t._p_children={}),t._p_children[a]||(t._p_children[a]={}),r=t._p_children[a],r._p_scope=e.getAttribute("p-scope"),r._p_id=a}let a=e.firstElementChild;for(;a;)this.buildScopeData(a,r),a=a.nextElementSibling},observe(e,t){const r=e;let a=r;t&&(a=Object.create(t._p_target||t),Object.assign(a,r));return new Proxy(a,{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),a=t._p_target._p_children[r],s=this.observe(a,t);this.executePScopeStatements(s,a._p_scope);const o=Object.getPrototypeOf(s._p_target);e._parentSnapshot={};for(let t in o)t.startsWith("_p_")||(e._parentSnapshot[t]=o[t]);const n=s._p_target;e._localSnapshot={};for(let t of Object.keys(n))t.startsWith("_p_")||(e._localSnapshot[t]=n[t]);return s},refreshScope(e,t){let r=e._scope;if(!r)return t;const a=e.getAttribute("p-scope");return a&&r._p_target&&this.updateScopeFromParent(e,r,a),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 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=pScopeExpr.split(";").map(e=>e.trim()).filter(e=>e),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.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}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 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="";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;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();
|