@plentico/pattr 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/pattr.min.js ADDED
@@ -0,0 +1,7 @@
1
+ /*!
2
+ * Pattr v1.0.0
3
+ * A lightweight reactive framework
4
+ * https://github.com/plentico/pattr
5
+ * MIT License
6
+ */
7
+ window.Pattr={_templateScopeCounter:0,directives:{"p-text":(e,t,r={})=>{let o=String(t);if(r.trim&&r.trim.length>0){const e=parseInt(r.trim[0])||100;o.length>e&&(o=o.substring(0,e)+"...")}e.innerText=o},"p-html":(e,t,r={})=>{let o=t;if(r.allow&&r.allow.length>0){const e=r.allow,t=document.createElement("div");t.innerHTML=o;const a=t=>{if(t.nodeType===Node.ELEMENT_NODE){const r=t.tagName.toLowerCase();if(!e.includes(r))return document.createTextNode(t.textContent);const o=t.cloneNode(!1);return Array.from(t.childNodes).forEach(e=>{const t=a(e);t&&o.appendChild(t)}),o}return t.cloneNode()},s=document.createElement("div");Array.from(t.childNodes).forEach(e=>{const t=a(e);t&&s.appendChild(t)}),o=s.innerHTML}if(r.trim&&r.trim.length>0){const e=parseInt(r.trim[0])||100,t=document.createElement("div");t.innerHTML=o;let a=0,s=!1;const n=t=>{if(s)return null;if(t.nodeType===Node.TEXT_NODE){const r=t.textContent,o=e-a;if(r.length<=o)return a+=r.length,t.cloneNode();{s=!0;const e=r.substring(0,o)+"...";return document.createTextNode(e)}}if(t.nodeType===Node.ELEMENT_NODE){const e=t.cloneNode(!1);for(let r of t.childNodes){const t=n(r);if(t&&e.appendChild(t),s)break}return e}return t.cloneNode()},i=document.createElement("div");for(let e of t.childNodes){const t=n(e);if(t&&i.appendChild(t),s)break}o=i.innerHTML}e.innerHTML=o},"p-show":(e,t)=>{e.style.display=t?"":"none"},"p-style":(e,t)=>{"string"==typeof t?e.style.cssText=t:"object"==typeof t&&null!==t&&Object.assign(e.style,t)},"p-class":(e,t)=>{"string"==typeof t?e.className=t:Array.isArray(t)?e.className=t.join(" "):"object"==typeof t&&null!==t&&(e.className=Object.keys(t).filter(e=>t[e]).join(" "))},"p-model":(e,t)=>{e.value=t},"p-attr":(e,t,r={})=>{const o=Object.keys(r);if(o.length>0){const r=o[0];null==t||!1===t?e.removeAttribute(r):e.setAttribute(r,String(t))}else"object"==typeof t&&null!==t&&Object.keys(t).forEach(r=>{const o=t[r];null==o||!1===o?e.removeAttribute(r):e.setAttribute(r,String(o))})}},parseDirectiveModifiers(e){const t=e.split(":"),r=t[0],o={};for(let e=1;e<t.length;e++){const r=t[e].split("."),a=r[0],s=r.slice(1);o[a]=s}return{directive:r,modifiers:o}},async start(){this.root=document.documentElement;const e=document.getElementById("p-root-data")?.textContent;try{this.rawData=JSON.parse(e||"{}")}catch(e){console.error("Error parsing root data JSON:",e)}this.buildScopeData(this.root,this.rawData),this.data=this.observe(this.rawData),this.walkDom(this.root,this.data,!0),this.refreshAllLoops()},buildScopeData(e,t){let r=t;if(e.hasAttribute("p-scope")){const o=e.getAttribute("p-id")||"missing_p-id";t._p_children||(t._p_children={}),t._p_children[o]||(t._p_children[o]={}),r=t._p_children[o],r._p_scope=e.getAttribute("p-scope")}let o=e.firstElementChild;for(;o;)this.buildScopeData(o,r),o=o.nextElementSibling},observe(e,t){const r=e;let o=r;t&&(o=Object.create(t._p_target||t),Object.assign(o,r));return new Proxy(o,{get:(e,t)=>"_p_target"===t?e:e[t],set:(e,t,r)=>(e[t]=r,this.walkDom(this.root,this.data,!1),!0),has:(e,t)=>t in e})},initScope(e,t){const r=e.getAttribute("p-id"),o=t._p_target._p_children[r],a=this.observe(o,t);this.executePScopeStatements(a,o._p_scope);const s=Object.getPrototypeOf(a._p_target);e._parentSnapshot={};for(let t in s)t.startsWith("_p_")||(e._parentSnapshot[t]=s[t]);const n=a._p_target;e._localSnapshot={};for(let t of Object.keys(n))t.startsWith("_p_")||(e._localSnapshot[t]=n[t]);return a},refreshScope(e,t){let r=e._scope;if(!r)return t;const o=e.getAttribute("p-scope");return o&&r._p_target&&this.updateScopeFromParent(e,r,o),r},executePScopeStatements(scope,pScopeExpr){const statements=pScopeExpr.split(";").map(e=>e.trim()).filter(e=>e),target=scope._p_target,sequentialScope=new Proxy(target,{get:(e,t)=>Object.prototype.hasOwnProperty.call(e,t)?e[t]:scope[t],has:(e,t)=>Object.prototype.hasOwnProperty.call(e,t)||t in scope});for(const stmt of statements){const match=stmt.match(/^(\w+)\s*=\s*(.+)$/);if(match){const[,varName,expr]=match;try{const value=eval(`with (sequentialScope) { (${expr}) }`);target[varName]=value}catch(e){console.error(`Error executing p-scope statement "${stmt}":`,e)}}}},updateScopeFromParent(el,scope,pScopeExpr){const parentProto=Object.getPrototypeOf(scope._p_target),target=scope._p_target,changedParentVars=new Set,changedLocalVars=new Set;el._parentSnapshot||(el._parentSnapshot={});for(let e in parentProto)e.startsWith("_p_")||(el._parentSnapshot[e]!==parentProto[e]&&changedParentVars.add(e),el._parentSnapshot[e]=parentProto[e]);el._localSnapshot||(el._localSnapshot={});for(let e of Object.keys(target))e.startsWith("_p_")||(el._localSnapshot[e]!==target[e]&&changedLocalVars.add(e),el._localSnapshot[e]=target[e]);const allChangedVars=new Set([...changedParentVars,...changedLocalVars]);if(0!==allChangedVars.size)try{const statements=pScopeExpr.split(";").map(e=>e.trim()).filter(e=>e),outputVars=new Set;statements.forEach(e=>{const t=e.match(/^(\w+)\s*=\s*(.+)$/);t&&outputVars.add(t[1])});const setInThisPass=new Set,sequentialScope=new Proxy(target,{get:(e,t)=>"_p_target"===t||"_p_children"===t||"_p_scope"===t||setInThisPass.has(t)?e[t]:changedParentVars.has(t)?parentProto[t]:changedLocalVars.has(t)||Object.prototype.hasOwnProperty.call(e,t)?e[t]:parentProto[t],set:(e,t,r)=>(e[t]=r,!0),has:(e,t)=>setInThisPass.has(t)||Object.prototype.hasOwnProperty.call(e,t)||t in parentProto});statements.forEach(stmt=>{let shouldExecute=!1;const parts=stmt.split("=");if(parts.length<=1)return;const rhs=parts.slice(1).join("=");if(changedParentVars.forEach(e=>{rhs.includes(e)&&(shouldExecute=!0)}),changedLocalVars.forEach(e=>{!outputVars.has(e)&&rhs.includes(e)&&(shouldExecute=!0)}),shouldExecute||setInThisPass.forEach(e=>{rhs.includes(e)&&(shouldExecute=!0)}),shouldExecute){const match=stmt.match(/^(\w+)\s*=\s*(.+)$/);if(match){const[,varName,expr]=match,value=eval(`with (sequentialScope) { (${expr}) }`);target[varName]=value,setInThisPass.add(varName)}}});for(let e of Object.keys(target))e.startsWith("_p_")||(el._localSnapshot[e]=target[e])}catch(e){console.error("Error re-executing p-scope expression:",e)}},registerEventListeners(el){Array.from(el.attributes).forEach(attr=>{if(attr.name.startsWith("p-on:")){const event=attr.name.replace("p-on:","");el.addEventListener(event,()=>{eval(`with (el._scope) { ${attr.value} }`),this.refreshAllLoops()})}})},registerModelBinding(el){const modelAttr=el.getAttribute("p-model");modelAttr&&(el.addEventListener("input",e=>{let value;const type=e.target.type;value="number"===type||"range"===type?""===e.target.value?null:Number(e.target.value):"checkbox"===type?e.target.checked:"radio"===type?e.target.checked?e.target.value:void 0:e.target.value,void 0!==value&&eval(`with (el._scope) { ${modelAttr} = value }`)}),"checkbox"!==el.type&&"radio"!==el.type||el.addEventListener("change",e=>{let value;value="checkbox"===el.type?e.target.checked:e.target.checked?e.target.value:void 0,void 0!==value&&eval(`with (el._scope) { ${modelAttr} = value }`)}))},evaluateDirectives(el,scope){Array.from(el.attributes).forEach(attr=>{const parsed=this.parseDirectiveModifiers(attr.name);if(Object.keys(this.directives).includes(parsed.directive)){const evalScope=el._scope||scope,value=eval(`with (evalScope) { (${attr.value}) }`);this.directives[parsed.directive](el,value,parsed.modifiers)}})},setForTemplateRecursive(e,t){e._forTemplate=t,Array.from(e.children).forEach(e=>{this.setForTemplateRecursive(e,t)})},refreshAllLoops(e=this.root,t=new Set){if("TEMPLATE"===e.tagName&&e.hasAttribute("p-for")){if(t.has(e))return;return t.add(e),void this.handleFor(e,e._scope||this.data,!1)}let r=e.firstElementChild;for(;r;){const e=r.nextElementSibling;this.refreshAllLoops(r,t),r=e}},handleFor(e,t,r){const o=e.getAttribute("p-for"),a=o.match(/^(?:const|let)?\s*(.+?)\s+(of|in)\s+(.+)$/);if(!a)return void console.error(`Invalid p-for expression: ${o}`);const[,s,n,i]=a;r?this.hydrateLoop(e,t,s,i):this.refreshLoop(e,t,s,i)},getTemplateScopePrefix(e){let t="";if(e._forTemplate){const r=e._forTemplate._forData;if(r&&r.scopePrefix){let r=e.previousElementSibling;for(;r;){if(r.hasAttribute&&r.hasAttribute("p-for-key")){t=r.getAttribute("p-for-key")+"-";break}r=r.previousElementSibling}}}if(!t){let r=e.previousElementSibling;for(;r;){if(r.hasAttribute&&r.hasAttribute("p-for-key")&&r._forTemplate===e._forTemplate){t=r.getAttribute("p-for-key")+"-";break}r=r.previousElementSibling}}if(!t){let r=e.parentElement;for(;r;){if(r.hasAttribute&&r.hasAttribute("p-for-key")){t=r.getAttribute("p-for-key")+"-";break}if(r._forTemplate){const e=r._forTemplate._forData;if(e){const o=e.renderedElements.indexOf(r);if(o>=0){t=(e.scopePrefix||"")+o+"-";break}}}r=r.parentElement}}return e._forScopeId||(e._forScopeId="s"+this._templateScopeCounter++),t+e._forScopeId+":"},hydrateLoop(template,parentScope,varPattern,iterableExpr){template._scope=parentScope;try{const iterable=eval(`with (parentScope) { (${iterableExpr}) }`),scopePrefix=this.getTemplateScopePrefix(template);template._forData={varPattern:varPattern,iterableExpr:iterableExpr,renderedElements:[],scopePrefix:scopePrefix};const existingElementsByKey={};let sibling=template.nextElementSibling;for(;sibling&&sibling.hasAttribute("p-for-key");){const e=sibling.getAttribute("p-for-key"),t=e.startsWith(scopePrefix)||!e.includes(":")&&!e.includes("-");if(t){let t;t=e.startsWith(scopePrefix)?e.substring(scopePrefix.length):e,existingElementsByKey[t]||(existingElementsByKey[t]=[]),existingElementsByKey[t].push(sibling)}sibling=sibling.nextElementSibling}let index=0,lastInserted=template;for(const e of iterable){const t=this.createLoopScope(parentScope,varPattern,e);if(existingElementsByKey[String(index)])existingElementsByKey[String(index)].forEach(e=>{e._scope=t,this.setForTemplateRecursive(e,template),"TEMPLATE"!==e.tagName&&e.setAttribute("p-for-key",scopePrefix+index),this.walkDom(e,t,!0),template._forData.renderedElements.push(e),lastInserted=e});else{const e=template.content.cloneNode(!0),r=Array.from(e.children);r.forEach(e=>{e._scope=t,this.setForTemplateRecursive(e,template),"TEMPLATE"!==e.tagName&&e.setAttribute("p-for-key",scopePrefix+index),this.walkDom(e,t,!0)});const o=document.createDocumentFragment();r.forEach(e=>o.appendChild(e)),lastInserted.parentNode.insertBefore(o,lastInserted.nextSibling),template._forData.renderedElements.push(...r),lastInserted=r[r.length-1]||lastInserted}index++}Object.keys(existingElementsByKey).forEach(e=>{parseInt(e)>=index&&existingElementsByKey[e].forEach(e=>e.remove())})}catch(e){console.error(`Error in p-for hydration: ${iterableExpr}`,e)}},removeLoopElements(e){e.forEach(e=>{if(e._forData&&e._forData.renderedElements&&(this.removeLoopElements(e._forData.renderedElements),e._forData.renderedElements=[]),e.querySelectorAll){e.querySelectorAll("template[p-for]").forEach(e=>{e._forData&&e._forData.renderedElements&&(this.removeLoopElements(e._forData.renderedElements),e._forData.renderedElements=[])})}e.remove()})},refreshLoop(template,parentScope,varPattern,iterableExpr){const forData=template._forData;if(forData)try{const iterable=eval(`with (parentScope._p_target || parentScope) { (${iterableExpr}) }`),scopePrefix=forData.scopePrefix||this.getTemplateScopePrefix(template);this.removeLoopElements(forData.renderedElements),forData.renderedElements=[];let lastInsertedElement=template,index=0;for(const e of iterable){const t=template.content.cloneNode(!0),r=this.createLoopScope(parentScope,forData.varPattern,e),o=Array.from(t.children);o.forEach(e=>{e._scope=r,this.setForTemplateRecursive(e,template),"TEMPLATE"!==e.tagName&&e.setAttribute("p-for-key",scopePrefix+index)});const a=document.createDocumentFragment();o.forEach(e=>a.appendChild(e)),lastInsertedElement.parentNode.insertBefore(a,lastInsertedElement.nextSibling),forData.renderedElements.push(...o),o.forEach(e=>{this.walkDom(e,r,!0)});const s=o[o.length-1];s&&(lastInsertedElement=this.findLastRenderedSibling(s)),index++}}catch(e){console.error(`Error in p-for refresh: ${iterableExpr}`,e)}},findLastRenderedSibling(e){if("TEMPLATE"===e.tagName&&e._forData&&e._forData.renderedElements.length>0){const t=e._forData.renderedElements[e._forData.renderedElements.length-1];return this.findLastRenderedSibling(t)}return e},createLoopScope(e,t,r){const o={};if((t=t.trim()).startsWith("[")){const e=t.slice(1,-1).split(",").map(e=>e.trim());Array.isArray(r)?e.forEach((e,t)=>o[e]=r[t]):o[e[0]]=r}else if(t.startsWith("{")){t.slice(1,-1).split(",").map(e=>e.trim()).forEach(e=>{const[t,a]=e.split(":").map(e=>e.trim());o[a||t]=r[t]})}else o[t]=r;if(!e)return console.error("parentScope is undefined in createLoopScope"),new Proxy({},{get:()=>{},set:()=>!1});const a=e._p_target||e;if(!a||"object"!=typeof a)return console.error("Invalid parentTarget:",a),new Proxy(o,{get:(e,t)=>e[t],set:(e,t,r)=>(e[t]=r,!0)});const s=Object.create(a);Object.assign(s,o);const n=new Proxy(s,{get:(e,t)=>e[t],set:(e,t,r)=>(t in o?e[t]=r:a[t]=r,!0)});return n._p_target=s,n},walkDom(e,t,r=!1){if("TEMPLATE"===e.tagName&&e.hasAttribute("p-for")){if(!r&&e._forTemplate)return;return void this.handleFor(e,t,r)}let o=t;e.hasAttribute("p-scope")&&(o=r?this.initScope(e,t):this.refreshScope(e,t)),r&&(e._scope=o,this.registerEventListeners(e),this.registerModelBinding(e)),o&&this.evaluateDirectives(e,o);const a=Array.from(e.children);for(const e of a)this.walkDom(e,o,r)}},window.Pattr.start();