From d688483f5a41e10723e16b0eec024f95309f9ad5 Mon Sep 17 00:00:00 2001 From: AI Engineer Date: Tue, 19 May 2026 07:17:00 +0800 Subject: [PATCH] chore: release state v1.0.10 with critical bug fixes --- CHANGELOG.md | 7 ++ dist/state.js | 196 ++++++++++++++++------------------------- dist/state.min.js | 2 +- package.json | 2 +- src/component.js | 4 +- src/dom.js | 216 ++++++++++++++++------------------------------ 6 files changed, 159 insertions(+), 268 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fc5f596..16baf83 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # CHANGELOG +## v1.0.10 (2026-05-18) + +### 修复 +- **生命周期**: 修复了 `onunload` 监听器因字符串匹配错误导致的失效问题。 +- **插槽合并**: 修复了 `_mergeNode` 在处理 `TEMPLATE` 节点时未正确指向 `.content` 的问题。 +- **架构对齐**: 恢复了 `_parseNode` 的原始执行顺序,确保组件初始化与属性绑定时序的绝对安全性。 + ## v1.0.9 (2026-05-18) ### 修复 diff --git a/dist/state.js b/dist/state.js index c555428..e4eb0e5 100644 --- a/dist/state.js +++ b/dist/state.js @@ -105,7 +105,9 @@ function _mergeNode(from, to, scanObj, exists = {}) { }); } to.classList.add(...from.classList); - Array.from(from.childNodes).forEach((child) => to.appendChild(child)); + const fromContent = from.tagName === "TEMPLATE" ? from.content : from; + const toContent = to.tagName === "TEMPLATE" ? to.content : to; + Array.from(fromContent.childNodes).forEach((child) => toContent.appendChild(child)); if (from.tagName && Component.exists(from.tagName)) _makeComponent(from.tagName, to, scanObj, exists); } function _makeComponent(name, node, scanObj, exists = {}) { @@ -174,25 +176,19 @@ function _returnCode(code, vars, thisObj, extendVars) { } let _translator = (text, args) => { if (!text || typeof text !== "string") return text; - return text.replace(/\{(.+?)\}/g, (match, key) => { - return args.hasOwnProperty(key) ? args[key] : match; - }); + return text.replace(/\{(.+?)\}/g, (match, key) => args.hasOwnProperty(key) ? args[key] : match); }; const SetTranslator = (fn) => _translator = fn; const _translate = (text) => { if (!text || typeof text !== "string" || !text.includes("{#")) return text; return text.replace(/\{#(.+?)#\}/g, (m, content) => { const parts = content.split("||").map((s) => s.trim()); - const rawText = parts[0]; const args = {}; if (parts.length > 1) { - const matches = rawText.match(/\{(.+?)\}/g); - if (matches) matches.forEach((match, i) => { - const key = match.substring(1, match.length - 1); - args[key] = parts[i + 1] || ""; - }); + const matches = parts[0].match(/\{(.+?)\}/g); + if (matches) matches.forEach((match, i) => args[match.substring(1, match.length - 1)] = parts[i + 1] || ""); } - return _translator(rawText, args); + return _translator(parts[0], args); }); }; if (typeof document !== "undefined") { @@ -208,19 +204,16 @@ if (typeof document !== "undefined") { } onNotifyUpdate((binding) => _updateBinding(binding)); function _clearRenderedNodes(node) { - if (node._renderedNodes) node._renderedNodes.forEach((nodes) => { - nodes.forEach((child) => { - child.remove(); - if (child._renderedNodes) _clearRenderedNodes(child); - }); - }); + if (node._renderedNodes) node._renderedNodes.forEach((nodes) => nodes.forEach((child) => { + child.remove(); + if (child._renderedNodes) _clearRenderedNodes(child); + })); } function _updateBinding(binding) { const node = binding.node; - const tpl = binding.tpl; - const exp = binding.exp; + if (!node.isConnected && node.tagName !== "TEMPLATE") return; setActiveBinding(binding); - let result = exp ? tpl ? _returnCode(tpl, { thisNode: node }, node._thisObj || node, node._ref || null) : null : tpl; + let result = binding.exp ? binding.tpl ? _returnCode(binding.tpl, { thisNode: node }, node._thisObj || node, node._ref || null) : null : binding.tpl; setActiveBinding(null); if (binding.prop) { const prop = binding.prop; @@ -232,14 +225,13 @@ function _updateBinding(binding) { if (typeof o !== "object") break; } if (typeof o === "object" && o !== null) { - const resultIsObject = typeof result === "object" && result != null && !Array.isArray(result); const lk = prop[prop.length - 1]; if (lk) { - if (resultIsObject && o[lk] == null) o[lk] = {}; + if (typeof result === "object" && result != null && !Array.isArray(result) && o[lk] == null) o[lk] = {}; const lo = o[lk]; if (typeof lo === "object" && lo != null && lo.__watch) Object.assign(lo, result); else o[lk] = result; - } else if (resultIsObject && typeof o === "object") { + } else if (typeof result === "object" && result != null && !Array.isArray(result)) { Object.assign(o, result); } } @@ -288,9 +280,7 @@ function _updateBinding(binding) { if (!node._renderedNodes) node._renderedNodes = []; node._children.forEach((child) => { const cloned = child.cloneNode(true); - cloned._ref = { ...node._ref }; - cloned._ref[indexName] = k; - cloned._ref[asName] = item; + cloned._ref = { ...node._ref, [indexName]: k, [asName]: item }; cloned._thisObj = node._thisObj; node.parentNode.insertBefore(cloned, node); newNodes.push(cloned); @@ -299,23 +289,20 @@ function _updateBinding(binding) { } }); while (node._renderedNodes && node._renderedNodes.length > keys.length) { - node._renderedNodes[node._renderedNodes.length - 1].forEach((child) => { + node._renderedNodes.pop().forEach((child) => { _clearRenderedNodes(child); child.remove(); }); - node._renderedNodes.pop(); } } else { _clearRenderedNodes(node); node._renderedNodes = []; } } else if (attr === "bind") { - if (["INPUT", "SELECT", "TEXTAREA"].includes(node.tagName)) { - if (!node.hasAttribute("autocomplete")) node.setAttribute("autocomplete", "off"); - } + if (["INPUT", "SELECT", "TEXTAREA"].includes(node.tagName) && !node.hasAttribute("autocomplete")) node.setAttribute("autocomplete", "off"); if (node.type === "checkbox") { if (node.value !== "on" && !result) { - _runCode(`${tpl} = []`, { thisNode: node }, node._thisObj || node, node._ref || {}); + _runCode(`${binding.tpl} = []`, { thisNode: node }, node._thisObj || node, node._ref || {}); result = []; } node._checkboxMultiMode = result instanceof Array; @@ -333,19 +320,13 @@ function _updateBinding(binding) { node.dispatchEvent(new CustomEvent("bind", { bubbles: false, detail: result })); } else { if (["checked", "disabled", "readonly"].includes(attr)) result = !!result; - if (typeof result === "boolean") { - result ? node.setAttribute(attr, "") : node.removeAttribute(attr); - } else if (result !== void 0) { + if (typeof result === "boolean") result ? node.setAttribute(attr, "") : node.removeAttribute(attr); + else if (result !== void 0) { if (typeof result !== "string") result = JSON.stringify(result); - if (attr === "text") { - node.textContent = result ?? ""; - } else if (attr === "html") { - node.innerHTML = result ?? ""; - } else if (node.tagName === "IMG" && attr === "src" && result.includes(".svg")) { - node.setAttribute("_src", result ?? ""); - } else { - node.setAttribute(attr, result ?? ""); - } + if (attr === "text") node.textContent = result ?? ""; + else if (attr === "html") node.innerHTML = result ?? ""; + else if (node.tagName === "IMG" && attr === "src" && result.includes(".svg")) node.setAttribute("_src", result ?? ""); + else node.setAttribute(attr, result ?? ""); } } } @@ -356,49 +337,45 @@ const _initBinding = (binding) => { _updateBinding(binding); }; const _parseNode = (node, scanObj) => { + let hasBindings = false; if (node._bindings) { node._states = /* @__PURE__ */ new Set(); - node._bindings.forEach((bindingData) => { - const binding = { node, ...bindingData }; - _updateBinding(binding); - }); + node._bindings.forEach((b) => _updateBinding({ node, ...b })); if (node._hasOnUpdate) node.dispatchEvent(new Event("update", { bubbles: false })); - return; + hasBindings = true; } if (Component.exists(node.tagName) && !node._componentInitialized) { Array.from(node.attributes).forEach((attr) => { + var _a2; if (attr.name.startsWith("$.")) { const realAttrName = attr.name.slice(2); - let tpl = attr.value; + let tpl = _translate(attr.value); if (tpl.includes("this.")) tpl = tpl.replace(/\bthis\./g, "this.parent."); - tpl = _translate(tpl); const result = _returnCode(tpl, { thisNode: node }, { parent: scanObj.thisObj || node }, node._ref || {}); let o = node; const prop = realAttrName.split("."); for (let i = 0; i < prop.length - 1; i++) { - if (!prop[i]) continue; - if (o[prop[i]] == null) o[prop[i]] = {}; - o = o[prop[i]]; + if (prop[i]) o = o[_a2 = prop[i]] ?? (o[_a2] = {}); } o[prop[prop.length - 1]] = result; node.removeAttribute(attr.name); } }); _makeComponent(node.tagName, node, scanObj); - $$(node, "[slot-id]").forEach((placeholder) => placeholder.removeAttribute("slot-id")); + $$(node, "[slot-id]").forEach((p) => p.removeAttribute("slot-id")); node._componentInitialized = true; if (!node._thisObj) node._thisObj = node; } - let attrs = []; if (node.tagName === "TEMPLATE") { node._children = [...node.content.childNodes]; - node._renderedNodes = []; - if (node.hasAttribute("$if")) attrs.push(node.getAttributeNode("$if")); - else if (node.hasAttribute("$each")) attrs.push(node.getAttributeNode("$each")); - else if (node.hasAttribute("st-if")) attrs.push(node.getAttributeNode("st-if")); - else if (node.hasAttribute("st-each")) attrs.push(node.getAttributeNode("st-each")); + if (!node._renderedNodes) node._renderedNodes = []; + } + if (hasBindings) return; + let attrs = []; + if (node.tagName === "TEMPLATE") { + ["$if", "$each", "st-if", "st-each"].forEach((n) => node.hasAttribute(n) && attrs.push(node.getAttributeNode(n))); } else { - attrs = Array.from(node.attributes).filter((attr) => (attr.name.startsWith("$") || attr.name.startsWith("st-")) && !["$if", "$each", "st-if", "st-each"].includes(attr.name) || attr.name.includes(".")); + attrs = Array.from(node.attributes).filter((a) => (a.name.startsWith("$") || a.name.startsWith("st-")) && !["$if", "$each", "st-if", "st-each"].includes(a.name) || a.name.includes(".")); } if (node._thisObj && scanObj.thisObj) node._thisObj.parent = scanObj.thisObj; if (!node._thisObj) node._thisObj = scanObj.thisObj || null; @@ -409,49 +386,35 @@ const _parseNode = (node, scanObj) => { const realAttrName = exp ? attr.name.slice(attr.name.startsWith("$") ? 1 : 3) : attr.name; let tpl = attr.value; node.removeAttribute(attr.name); - if (realAttrName.startsWith(".")) { - _initBinding({ node, prop: realAttrName.split("."), tpl, exp }); + if (realAttrName.startsWith(".")) _initBinding({ node, prop: realAttrName.split("."), tpl, exp }); + else if (realAttrName.startsWith("on")) { + const eventName = realAttrName.slice(2); + if (eventName === "update") node._hasOnUpdate = true; + if (eventName === "load" && !["BODY", "IMG", "IFRAME"].includes(node.tagName)) node._hasOnLoad = true; + if (eventName === "unload" && !["BODY", "IMG", "IFRAME"].includes(node.tagName)) node._hasOnUnload = true; + node.addEventListener(eventName, (e) => _runCode(tpl, { event: e, thisNode: node, ...e.detail || {} }, scanObj.thisObj || node, node._ref || {})); } else { - if (realAttrName.startsWith("on")) { - const eventName = realAttrName.slice(2); - if (eventName === "update") node._hasOnUpdate = true; - if (eventName === "load" && !["BODY", "IMG", "IFRAME"].includes(node.tagName)) node._hasOnLoad = true; - if (eventName === "unload" && !["BODY", "IMG", "IFRAME"].includes(node.tagName)) node._hasOnUnload = true; - ((node2, thisObj) => { - node2.addEventListener(eventName, (e) => { - _runCode(tpl, { event: e, thisNode: node2, ...e.detail || {} }, thisObj || node2, node2._ref || {}); - }); - })(node, scanObj.thisObj); - } else { - if (realAttrName === "bind") { - node.addEventListener(node.tagName === "TEXTAREA" || node.isContentEditable || node.type === "text" || node.type === "password" ? "input" : "change", (e) => { - let newVal = node.isContentEditable ? e.target.innerHTML : node.type === "checkbox" ? e.target.checked : e.target.files || e.target.value || e.detail; - setNoWriteBack(node); - setDisableRunCodeError(true); - if (node.type === "checkbox" && node._checkboxMultiMode) { - _runCode(`!!checked ? (!${tpl}.includes(val) && ${tpl}.push(val)) : (index = ${tpl}.indexOf(val), index > -1 && ${tpl}.splice(index, 1))`, { val: node.value, checked: newVal, thisNode: node }, scanObj.thisObj || node, node._ref || {}); - } else { - _runCode(`${tpl} = val`, { val: newVal, thisNode: node }, scanObj.thisObj || node, node._ref || {}); - } - setDisableRunCodeError(false); - setNoWriteBack(null); - }); - } else if (realAttrName === "text" && !tpl) { - tpl = node.textContent; - node.textContent = ""; - } - if (tpl) { - tpl = _translate(tpl); - _initBinding({ node, attr: realAttrName, tpl, exp }); - } + if (realAttrName === "bind") { + node.addEventListener(node.tagName === "TEXTAREA" || node.isContentEditable || node.type === "text" || node.type === "password" ? "input" : "change", (e) => { + let newVal = node.isContentEditable ? e.target.innerHTML : node.type === "checkbox" ? e.target.checked : e.target.files || e.target.value || e.detail; + setNoWriteBack(node); + setDisableRunCodeError(true); + if (node.type === "checkbox" && node._checkboxMultiMode) _runCode(`!!checked ? (!${tpl}.includes(val) && ${tpl}.push(val)) : (index = ${tpl}.indexOf(val), index > -1 && ${tpl}.splice(index, 1))`, { val: node.value, checked: newVal, thisNode: node }, scanObj.thisObj || node, node._ref || {}); + else _runCode(`${tpl} = val`, { val: newVal, thisNode: node }, scanObj.thisObj || node, node._ref || {}); + setDisableRunCodeError(false); + setNoWriteBack(null); + }); + } else if (realAttrName === "text" && !tpl) { + tpl = node.textContent; + node.textContent = ""; + } + if (tpl) { + tpl = _translate(tpl); + _initBinding({ node, attr: realAttrName, tpl, exp }); } } }); - if (node._hasOnLoad || node._componentInitialized) { - ((node2) => { - Promise.resolve().then(() => node2.dispatchEvent(new Event("load", { bubbles: false }))); - })(node); - } + if (node._hasOnLoad || node._componentInitialized) Promise.resolve().then(() => node.dispatchEvent(new Event("load", { bubbles: false }))); if (node._hasOnUpdate) node.dispatchEvent(new Event("update", { bubbles: false })); if (node._thisObj) scanObj.thisObj = node._thisObj; }; @@ -483,7 +446,6 @@ const _scanTree = (node, scanObj = {}) => { node.parentNode.insertBefore(template, node); template.content.appendChild(node); template._ref = node._ref; - node = template; return; } if (node.tagName === "TEMPLATE" && (node.hasAttribute("$if") || node.hasAttribute("st-if")) && (node.hasAttribute("$each") || node.hasAttribute("st-each"))) { @@ -498,9 +460,7 @@ const _scanTree = (node, scanObj = {}) => { node.removeAttribute(attr2.name); }); } - Array.from(node.content.childNodes).forEach((child) => { - template.content.appendChild(child); - }); + Array.from(node.content.childNodes).forEach((child) => template.content.appendChild(child)); node.content.appendChild(template); template._ref = node._ref; } @@ -518,7 +478,7 @@ const _scanTree = (node, scanObj = {}) => { }); } if (node._thisObj !== void 0) scanObj.thisObj = node._thisObj || null; - if (scanObj.thisObj === void 0) { + else { let curr = node; while (curr && curr._thisObj === void 0) curr = curr.parentNode; scanObj.thisObj = curr ? curr._thisObj : null; @@ -528,28 +488,22 @@ const _scanTree = (node, scanObj = {}) => { while (curr && curr._ref === void 0) curr = curr.parentNode; node._ref = curr ? { ...curr._ref } : {}; } - if (scanObj.extendVars === void 0) scanObj.extendVars = {}; - if (node._ref !== void 0) { - Object.assign(node._ref, scanObj.extendVars); - scanObj.extendVars = { ...node._ref }; - } + if (scanObj.extendVars) Object.assign(node._ref, scanObj.extendVars); _parseNode(node, scanObj); const nodes = [...node.childNodes || []]; - scanObj.extendVars = node._ref || scanObj.extendVars; - nodes.forEach((child) => _scanTree(child, { thisObj: scanObj.thisObj, extendVars: { ...node._ref } })); + const nextScanObj = { thisObj: scanObj.thisObj, extendVars: { ...node._ref } }; + nodes.forEach((child) => _scanTree(child, nextScanObj)); }; const _unbindTree = (node) => { if (node.nodeType !== 1) return; if (node._hasOnUnload) node.dispatchEvent(new Event("unload", { bubbles: false })); - if (node._states) { - node._states.forEach((stateMappings) => { - for (const [key, bindingSet] of stateMappings) { - for (const binding of bindingSet) { - if (binding.node === node) bindingSet.delete(binding); - } + if (node._states) node._states.forEach((mappings) => { + for (const [key, bindingSet] of mappings) { + for (const binding of bindingSet) { + if (binding.node === node) bindingSet.delete(binding); } - }); - } + } + }); node.childNodes && node.childNodes.forEach((child) => _unbindTree(child)); }; const RefreshState = _scanTree; diff --git a/dist/state.min.js b/dist/state.min.js index 4cd9917..9f9a557 100644 --- a/dist/state.min.js +++ b/dist/state.min.js @@ -1 +1 @@ -var e;let t=null,n=null;const r=e=>t=e,s=e=>n=e,a=new Set;function o(e={},r=null,s=null){const o={},i=new Map,d=new Map,l=(e,t)=>(d.has(e)||d.set(e,new Set),t?d.get(e).add(t):d.get(e).clear(),()=>d.get(e).delete(t)),c=(e,t)=>{d.has(e)&&d.get(e).delete(t)},h=r||(e=>o[e]),u=s||((e,t)=>o[e]=t);return Object.assign(o,e),new Proxy(o,{get:(e,n)=>"__watch"===n?l:"__unwatch"===n?c:"__isProxy"===n||(t&&(i.has(n)||i.set(n,new Set),i.get(n).add(t),t.node._states||(t.node._states=new Set),t.node._states.add(i)),h(n)),set(e,t,r){if(h(t)!==r&&u(t,r),d.has(t)&&d.get(t).forEach(n=>{const s=n(r);void 0!==s&&(r=s,e[t]=r)}),d.has(null)&&d.get(null).forEach(e=>e(r)),i.has(t)){const e=i.get(t);for(const t of e)t.node.isConnected?n!==t.node&&a.forEach(e=>e(t)):e.delete(t)}return!0}})}const i=(e,t)=>t?e.querySelector(t):document.querySelector(e),d=(e,t)=>t?e.querySelectorAll(t):document.querySelectorAll(e),l=new Map,c=[],h={getTemplate:e=>document.querySelector(`template[component="${e.toUpperCase()}"]`),register:(e,t,n=null,...r)=>{l.set(e.toUpperCase(),t),"loading"!==document.readyState?h._addTemplate(e,n,r):c.push([e,n,r])},exists:e=>l.has(e.toUpperCase()),getSetupFunction:e=>l.get(e.toUpperCase()),_addTemplate:(e,t,n)=>{if(t){const n=document.createElement("TEMPLATE");n.setAttribute("component",e.toUpperCase()),n.content.appendChild(t),document.body.appendChild(n)}n&&n.forEach(e=>document.body.appendChild(e))},_initPending:()=>{c.forEach(([e,t,n])=>h._addTemplate(e,t,n)),c.length=0}};function u(e,t,n,r={}){e.attributes&&Array.from(e.attributes).forEach(e=>{"class"!==e.name&&("style"===e.name?t.hasAttribute("style")?t.setAttribute("style",`${e.value}; ${t.getAttribute("style")}`):t.setAttribute("style",e.value):t.hasAttribute(e.name)||t.setAttribute(e.name,e.value))}),t.classList.add(...e.classList),Array.from(e.childNodes).forEach(e=>t.appendChild(e)),e.tagName&&h.exists(e.tagName)&&f(e.tagName,t,n,r)}function f(e,t,n,r={}){if(r[e])return;r[e]=!0,n.thisObj&&Array.from(t.attributes).forEach(e=>{(e.name.startsWith("$")||e.name.startsWith("st-"))&&e.value.includes("this.")&&(e.value=e.value.replace(/\bthis\./g,"this.parent."))});const s=h.getSetupFunction(e),a={};Array.from(t.childNodes).forEach(e=>{e.nodeType===Node.ELEMENT_NODE&&e.hasAttribute("slot")&&(a[e.getAttribute("slot")]=e,e.removeAttribute("slot"))}),t.innerHTML="",t.state=o(t.state||{});const i=h.getTemplate(e);if(i){const e=i.content.cloneNode(!0);if(e.childNodes.length){const s=Array.from(e.childNodes).find(e=>e.nodeType===Node.ELEMENT_NODE);s&&u(s,t,n,r),d(t,"[slot-id]").forEach(e=>{const t=e.getAttribute("slot-id");a[t]&&(e.removeAttribute("slot-id"),e.innerHTML="",u(a[t],e,n,r))})}}s&&s(t)}let b=!1;function p(e){b=e}const m=new Map;function g(e,t,n,r){const s={...r||{},...t||{}},a=Object.keys(s),o=Object.values(s),i=e+a.join(",");try{let t=m.get(i);return t||(t=new Function("Hash","LocalStorage","State",...a,e),m.set(i,t)),t.apply(n,[globalThis.Hash,globalThis.LocalStorage,globalThis.State,...o])}catch(s){return b||console.error(s,r,[e,r,t,n]),null}}function _(e,t,n,r){return e.includes("${")?g("return `"+e+"`",t,n,r):g("return "+e,t,n,r)}let v=(e,t)=>e&&"string"==typeof e?e.replace(/\{(.+?)\}/g,(e,n)=>t.hasOwnProperty(n)?t[n]:e):e;const A=e=>v=e,E=e=>e&&"string"==typeof e&&e.includes("{#")?e.replace(/\{#(.+?)#\}/g,(e,t)=>{const n=t.split("||").map(e=>e.trim()),r=n[0],s={};if(n.length>1){const e=r.match(/\{(.+?)\}/g);e&&e.forEach((e,t)=>{const r=e.substring(1,e.length-1);s[r]=n[t+1]||""})}return v(r,s)}):e;if("undefined"!=typeof document)try{document.createElement("div").setAttribute("$t","1")}catch(e){const t=Element.prototype.setAttribute;Element.prototype.setAttribute=function(e,n){return e.startsWith("$")?t.call(this,"st-"+e.substring(1),n):t.call(this,e,n)}}var y;function N(e){e._renderedNodes&&e._renderedNodes.forEach(e=>{e.forEach(e=>{e.remove(),e._renderedNodes&&N(e)})})}function O(e){const t=e.node,n=e.tpl,s=e.exp;r(e);let a=s?n?_(n,{thisNode:t},t._thisObj||t,t._ref||null):null:n;if(r(null),e.prop){const n=e.prop;let r=t;for(let e=0;e{t.parentNode.insertBefore(e,t),e._ref={...t._ref}}),t._renderedNodes=[t._children]):(N(t),t._renderedNodes=[]);else if("each"===r)if(a&&"object"==typeof a){const e=t.getAttribute("as")||"item",n=t.getAttribute("index")||"index";let r,s;if(a instanceof Map)r=Array.from(a.keys()),s=e=>a.get(e);else if("function"==typeof a[Symbol.iterator]){const e=Array.isArray(a)?a:Array.from(a);r=new Array(e.length);for(let t=0;te[t]}else r=Object.keys(a),s=e=>a[e];for(r.forEach((r,a)=>{const o=s(r);if(t._renderedNodes&&a{s._ref[n]=r,s._ref[e]=o,x(s,{thisObj:t._thisObj,extendVars:s._ref})});else{const s=[];t._renderedNodes||(t._renderedNodes=[]),t._children.forEach(a=>{const i=a.cloneNode(!0);i._ref={...t._ref},i._ref[n]=r,i._ref[e]=o,i._thisObj=t._thisObj,t.parentNode.insertBefore(i,t),s.push(i)}),t._renderedNodes.push(s)}});t._renderedNodes&&t._renderedNodes.length>r.length;)t._renderedNodes[t._renderedNodes.length-1].forEach(e=>{N(e),e.remove()}),t._renderedNodes.pop()}else N(t),t._renderedNodes=[];else if("bind"===r){if(["INPUT","SELECT","TEXTAREA"].includes(t.tagName)&&(t.hasAttribute("autocomplete")||t.setAttribute("autocomplete","off")),"checkbox"===t.type){"on"===t.value||a||(g(`${n} = []`,{thisNode:t},t._thisObj||t,t._ref||{}),a=[]),t._checkboxMultiMode=a instanceof Array;const e=a instanceof Array?a.includes(t.value):!!a;t.checked!==e&&(t.checked=e)}else"radio"===t.type?t.checked!==(t.value===String(a??""))&&(t.checked=t.value===String(a??"")):"value"in t&&"file"!==t.type?setTimeout(()=>{t.value!==String(a??"")&&(t.value=a)}):t.isContentEditable&&t.innerHTML!==String(a??"")&&(t.innerHTML=a);t.dispatchEvent(new CustomEvent("bind",{bubbles:!1,detail:a}))}else["checked","disabled","readonly"].includes(r)&&(a=!!a),"boolean"==typeof a?a?t.setAttribute(r,""):t.removeAttribute(r):void 0!==a&&("string"!=typeof a&&(a=JSON.stringify(a)),"text"===r?t.textContent=a??"":"html"===r?t.innerHTML=a??"":"IMG"===t.tagName&&"src"===r&&a.includes(".svg")?t.setAttribute("_src",a??""):t.setAttribute(r,a??""))}}y=e=>O(e),a.add(y);const T=e=>{e.node._bindings||(e.node._bindings=[]),e.node._bindings.push({attr:e.attr,prop:e.prop,tpl:e.tpl,exp:e.exp}),O(e)},x=(e,t={})=>{if(3===e.nodeType){if(e._stTranslated)return;const t=E(e.textContent);return t!==e.textContent&&(e.textContent=t),void(e._stTranslated=!0)}if(1!==e.nodeType)return;if(e._stTranslated||(Array.from(e.attributes).forEach(e=>{if(!e.name.startsWith("$")&&!e.name.startsWith("st-")&&!e.name.startsWith(".")){const t=E(e.value);t!==e.value&&(e.value=t)}}),e._stTranslated=!0),"TEMPLATE"!==e.tagName&&(e.hasAttribute("$if")||e.hasAttribute("$each")||e.hasAttribute("st-if")||e.hasAttribute("st-each"))){const t=document.createElement("TEMPLATE");return Array.from(e.attributes).filter(t=>["$if","$each","st-if","st-each"].includes(t.name)||(e.hasAttribute("$each")||e.hasAttribute("st-each"))&&["as","index"].includes(t.name)).forEach(n=>{t.setAttribute(n.name,n.value),e.removeAttribute(n.name)}),e.parentNode.insertBefore(t,e),t.content.appendChild(e),t._ref=e._ref,void(e=t)}if("TEMPLATE"===e.tagName&&(e.hasAttribute("$if")||e.hasAttribute("st-if"))&&(e.hasAttribute("$each")||e.hasAttribute("st-each"))){const t=document.createElement("TEMPLATE"),n=Array.from(e.attributes).filter(e=>["$if","$each","st-if","st-each"].includes(e.name)),r=n[n.length-1];t.setAttribute(r.name,r.value),e.removeAttribute(r.name),"$each"!==r.name&&"st-each"!==r.name||Array.from(e.attributes).filter(e=>["as","index"].includes(e.name)).forEach(n=>{t.setAttribute(n.name,n.value),e.removeAttribute(n.name)}),Array.from(e.content.childNodes).forEach(e=>{t.content.appendChild(e)}),e.content.appendChild(t),t._ref=e._ref}if("IMG"===e.tagName&&(e.hasAttribute("src")||e.hasAttribute("_src")||e.hasAttribute("$src"))){const t=e;Promise.resolve().then(()=>{const e=t.getAttribute("_src")||t.getAttribute("src");e&&fetch(e,{cache:"force-cache"}).then(e=>e.text()).then(e=>{const n=(new DOMParser).parseFromString(e,"image/svg+xml").querySelector("svg");n&&(Array.from(t.attributes).forEach(e=>n.setAttribute(e.name,e.value)),t.replaceWith(n))})})}if(void 0!==e._thisObj&&(t.thisObj=e._thisObj||null),void 0===t.thisObj){let n=e;for(;n&&void 0===n._thisObj;)n=n.parentNode;t.thisObj=n?n._thisObj:null}if(void 0===e._ref){let t=e;for(;t&&void 0===t._ref;)t=t.parentNode;e._ref=t?{...t._ref}:{}}void 0===t.extendVars&&(t.extendVars={}),void 0!==e._ref&&(Object.assign(e._ref,t.extendVars),t.extendVars={...e._ref}),((e,t)=>{if(e._bindings)return e._states=new Set,e._bindings.forEach(t=>{O({node:e,...t})}),void(e._hasOnUpdate&&e.dispatchEvent(new Event("update",{bubbles:!1})));h.exists(e.tagName)&&!e._componentInitialized&&(Array.from(e.attributes).forEach(n=>{if(n.name.startsWith("$.")){const r=n.name.slice(2);let s=n.value;s.includes("this.")&&(s=s.replace(/\bthis\./g,"this.parent.")),s=E(s);const a=_(s,{thisNode:e},{parent:t.thisObj||e},e._ref||{});let o=e;const i=r.split(".");for(let e=0;ee.removeAttribute("slot-id")),e._componentInitialized=!0,e._thisObj||(e._thisObj=e));let n=[];var r;"TEMPLATE"===e.tagName?(e._children=[...e.content.childNodes],e._renderedNodes=[],e.hasAttribute("$if")?n.push(e.getAttributeNode("$if")):e.hasAttribute("$each")?n.push(e.getAttributeNode("$each")):e.hasAttribute("st-if")?n.push(e.getAttributeNode("st-if")):e.hasAttribute("st-each")&&n.push(e.getAttributeNode("st-each"))):n=Array.from(e.attributes).filter(e=>(e.name.startsWith("$")||e.name.startsWith("st-"))&&!["$if","$each","st-if","st-each"].includes(e.name)||e.name.includes(".")),e._thisObj&&t.thisObj&&(e._thisObj.parent=t.thisObj),e._thisObj||(e._thisObj=t.thisObj||null),e._ref||(e._ref=t.extendVars||{}),e._states=new Set,n.forEach(n=>{const r=n.name.startsWith("$")||n.name.startsWith("st-"),a=r?n.name.slice(n.name.startsWith("$")?1:3):n.name;let o=n.value;if(e.removeAttribute(n.name),a.startsWith("."))T({node:e,prop:a.split("."),tpl:o,exp:r});else if(a.startsWith("on")){const n=a.slice(2);"update"===n&&(e._hasOnUpdate=!0),"load"!==n||["BODY","IMG","IFRAME"].includes(e.tagName)||(e._hasOnLoad=!0),"unload"!==n||["BODY","IMG","IFRAME"].includes(e.tagName)||(e._hasOnUnload=!0),i=e,d=t.thisObj,i.addEventListener(n,e=>{g(o,{event:e,thisNode:i,...e.detail||{}},d||i,i._ref||{})})}else"bind"===a?e.addEventListener("TEXTAREA"===e.tagName||e.isContentEditable||"text"===e.type||"password"===e.type?"input":"change",n=>{let r=e.isContentEditable?n.target.innerHTML:"checkbox"===e.type?n.target.checked:n.target.files||n.target.value||n.detail;s(e),p(!0),"checkbox"===e.type&&e._checkboxMultiMode?g(`!!checked ? (!${o}.includes(val) && ${o}.push(val)) : (index = ${o}.indexOf(val), index > -1 && ${o}.splice(index, 1))`,{val:e.value,checked:r,thisNode:e},t.thisObj||e,e._ref||{}):g(`${o} = val`,{val:r,thisNode:e},t.thisObj||e,e._ref||{}),p(!1),s(null)}):"text"!==a||o||(o=e.textContent,e.textContent=""),o&&(o=E(o),T({node:e,attr:a,tpl:o,exp:r}));var i,d}),(e._hasOnLoad||e._componentInitialized)&&(r=e,Promise.resolve().then(()=>r.dispatchEvent(new Event("load",{bubbles:!1})))),e._hasOnUpdate&&e.dispatchEvent(new Event("update",{bubbles:!1})),e._thisObj&&(t.thisObj=e._thisObj)})(e,t);const n=[...e.childNodes||[]];t.extendVars=e._ref||t.extendVars,n.forEach(n=>x(n,{thisObj:t.thisObj,extendVars:{...e._ref}}))},j=e=>{1===e.nodeType&&(e._hasOnUnload&&e.dispatchEvent(new Event("unload",{bubbles:!1})),e._states&&e._states.forEach(t=>{for(const[n,r]of t)for(const t of r)t.node===e&&r.delete(t)}),e.childNodes&&e.childNodes.forEach(e=>j(e)))},w=x,S={clone:window.structuredClone||(e=>JSON.parse(JSON.stringify(e))),base64:e=>btoa(String.fromCharCode(...(new TextEncoder).encode(e))),unbase64:e=>(new TextDecoder).decode(Uint8Array.from(atob(e),e=>e.charCodeAt(0))),urlbase64:e=>S.base64(e).replace(/[+/=]/g,e=>({"+":"-","/":"","=":""}[e])),unurlbase64:e=>S.unbase64(e.replace(/[-_.]/g,e=>({"-":"+",_:"/",".":"="}[e])).padEnd(4*Math.ceil(e.length/4),"=")),safeJson:e=>{try{return JSON.parse(e)}catch{return null}},updateDefaults:(e,t)=>{for(const n in t)void 0===e[n]&&(e[n]=t[n])},copyFunction:(e,t,...n)=>{n.forEach(n=>e[n]=t[n].bind(t))},getFunctionBody:e=>{const t=e.toString();return t.slice(t.indexOf("{")+1,t.lastIndexOf("}")).trim()},makeDom:e=>{e.includes(">\n")&&(e=e.replace(/>\s+<").trim());const t=document.createElement("div");return t.innerHTML=e,t.children[0]},newAvg:()=>{let e=0,t=0,n=0;return{add:r=>(e+=r,t++,n=e/t),get:()=>n,clear:()=>{e=0,t=0,n=0}}},newTimeCount:()=>{let e=0,t=0,n=0;return{start:()=>e=(new Date).getTime(),end:()=>{const r=(new Date).getTime(),s=r-e;return e=r,t+=s,n++,s},avg:()=>t/n}}};globalThis.Util=S;let $=new URLSearchParams((null==(e=window.location.hash)?void 0:e.substring(1))||"");const M=o({},e=>S.safeJson($.get(e)),(e,t)=>{const n=$.get(e),r=void 0===t?void 0:JSON.stringify(t);n===r||null===n&&void 0===r||(void 0===t?$.delete(e):$.set(e,r),window.location.hash="#"+$.toString())});"undefined"!=typeof window&&window.addEventListener("hashchange",()=>{var e;const t=$;$=new URLSearchParams((null==(e=window.location.hash)?void 0:e.substring(1))||""),$.forEach((e,n)=>{t.get(n)!==e&&(M[n]=S.safeJson(e))}),t.forEach((e,t)=>{void 0===$.get(t)&&(M[t]=void 0)})});const C=o({},e=>S.safeJson(localStorage.getItem(e)),(e,t)=>{const n=localStorage.getItem(e),r=void 0===t?void 0:JSON.stringify(t);n===r||null===n&&void 0===r||(void 0===t?localStorage.removeItem(e):localStorage.setItem(e,r))});if(globalThis.Hash=M,globalThis.LocalStorage=C,"undefined"!=typeof document){const e=()=>{h._initPending(),new MutationObserver(e=>{e.forEach(e=>{e.addedNodes.forEach(e=>{e.isConnected&&x(e)}),e.removedNodes.forEach(e=>j(e))})}).observe(document.documentElement,{childList:!0,subtree:!0}),x(document.documentElement)};"loading"!==document.readyState?e():document.addEventListener("DOMContentLoaded",e,!0)}export{i as $,d as $$,h as Component,M as Hash,C as LocalStorage,o as NewState,w as RefreshState,A as SetTranslator,S as Util,x as _scanTree,j as _unbindTree}; +var e;let t=null,n=null;const r=e=>t=e,s=e=>n=e,a=new Set;function o(e={},r=null,s=null){const o={},i=new Map,d=new Map,l=(e,t)=>(d.has(e)||d.set(e,new Set),t?d.get(e).add(t):d.get(e).clear(),()=>d.get(e).delete(t)),c=(e,t)=>{d.has(e)&&d.get(e).delete(t)},h=r||(e=>o[e]),u=s||((e,t)=>o[e]=t);return Object.assign(o,e),new Proxy(o,{get:(e,n)=>"__watch"===n?l:"__unwatch"===n?c:"__isProxy"===n||(t&&(i.has(n)||i.set(n,new Set),i.get(n).add(t),t.node._states||(t.node._states=new Set),t.node._states.add(i)),h(n)),set(e,t,r){if(h(t)!==r&&u(t,r),d.has(t)&&d.get(t).forEach(n=>{const s=n(r);void 0!==s&&(r=s,e[t]=r)}),d.has(null)&&d.get(null).forEach(e=>e(r)),i.has(t)){const e=i.get(t);for(const t of e)t.node.isConnected?n!==t.node&&a.forEach(e=>e(t)):e.delete(t)}return!0}})}const i=(e,t)=>t?e.querySelector(t):document.querySelector(e),d=(e,t)=>t?e.querySelectorAll(t):document.querySelectorAll(e),l=new Map,c=[],h={getTemplate:e=>document.querySelector(`template[component="${e.toUpperCase()}"]`),register:(e,t,n=null,...r)=>{l.set(e.toUpperCase(),t),"loading"!==document.readyState?h._addTemplate(e,n,r):c.push([e,n,r])},exists:e=>l.has(e.toUpperCase()),getSetupFunction:e=>l.get(e.toUpperCase()),_addTemplate:(e,t,n)=>{if(t){const n=document.createElement("TEMPLATE");n.setAttribute("component",e.toUpperCase()),n.content.appendChild(t),document.body.appendChild(n)}n&&n.forEach(e=>document.body.appendChild(e))},_initPending:()=>{c.forEach(([e,t,n])=>h._addTemplate(e,t,n)),c.length=0}};function u(e,t,n,r={}){e.attributes&&Array.from(e.attributes).forEach(e=>{"class"!==e.name&&("style"===e.name?t.hasAttribute("style")?t.setAttribute("style",`${e.value}; ${t.getAttribute("style")}`):t.setAttribute("style",e.value):t.hasAttribute(e.name)||t.setAttribute(e.name,e.value))}),t.classList.add(...e.classList);const s="TEMPLATE"===e.tagName?e.content:e,a="TEMPLATE"===t.tagName?t.content:t;Array.from(s.childNodes).forEach(e=>a.appendChild(e)),e.tagName&&h.exists(e.tagName)&&f(e.tagName,t,n,r)}function f(e,t,n,r={}){if(r[e])return;r[e]=!0,n.thisObj&&Array.from(t.attributes).forEach(e=>{(e.name.startsWith("$")||e.name.startsWith("st-"))&&e.value.includes("this.")&&(e.value=e.value.replace(/\bthis\./g,"this.parent."))});const s=h.getSetupFunction(e),a={};Array.from(t.childNodes).forEach(e=>{e.nodeType===Node.ELEMENT_NODE&&e.hasAttribute("slot")&&(a[e.getAttribute("slot")]=e,e.removeAttribute("slot"))}),t.innerHTML="",t.state=o(t.state||{});const i=h.getTemplate(e);if(i){const e=i.content.cloneNode(!0);if(e.childNodes.length){const s=Array.from(e.childNodes).find(e=>e.nodeType===Node.ELEMENT_NODE);s&&u(s,t,n,r),d(t,"[slot-id]").forEach(e=>{const t=e.getAttribute("slot-id");a[t]&&(e.removeAttribute("slot-id"),e.innerHTML="",u(a[t],e,n,r))})}}s&&s(t)}let b=!1;function m(e){b=e}const p=new Map;function g(e,t,n,r){const s={...r||{},...t||{}},a=Object.keys(s),o=Object.values(s),i=e+a.join(",");try{let t=p.get(i);return t||(t=new Function("Hash","LocalStorage","State",...a,e),p.set(i,t)),t.apply(n,[globalThis.Hash,globalThis.LocalStorage,globalThis.State,...o])}catch(s){return b||console.error(s,r,[e,r,t,n]),null}}function _(e,t,n,r){return e.includes("${")?g("return `"+e+"`",t,n,r):g("return "+e,t,n,r)}let E=(e,t)=>e&&"string"==typeof e?e.replace(/\{(.+?)\}/g,(e,n)=>t.hasOwnProperty(n)?t[n]:e):e;const v=e=>E=e,A=e=>e&&"string"==typeof e&&e.includes("{#")?e.replace(/\{#(.+?)#\}/g,(e,t)=>{const n=t.split("||").map(e=>e.trim()),r={};if(n.length>1){const e=n[0].match(/\{(.+?)\}/g);e&&e.forEach((e,t)=>r[e.substring(1,e.length-1)]=n[t+1]||"")}return E(n[0],r)}):e;if("undefined"!=typeof document)try{document.createElement("div").setAttribute("$t","1")}catch(e){const t=Element.prototype.setAttribute;Element.prototype.setAttribute=function(e,n){return e.startsWith("$")?t.call(this,"st-"+e.substring(1),n):t.call(this,e,n)}}var y;function N(e){e._renderedNodes&&e._renderedNodes.forEach(e=>e.forEach(e=>{e.remove(),e._renderedNodes&&N(e)}))}function O(e){const t=e.node;if(!t.isConnected&&"TEMPLATE"!==t.tagName)return;r(e);let n=e.exp?e.tpl?_(e.tpl,{thisNode:t},t._thisObj||t,t._ref||null):null:e.tpl;if(r(null),e.prop){const r=e.prop;let s=t;for(let e=0;e{t.parentNode.insertBefore(e,t),e._ref={...t._ref}}),t._renderedNodes=[t._children]):(N(t),t._renderedNodes=[]);else if("each"===r)if(n&&"object"==typeof n){const e=t.getAttribute("as")||"item",r=t.getAttribute("index")||"index";let s,a;if(n instanceof Map)s=Array.from(n.keys()),a=e=>n.get(e);else if("function"==typeof n[Symbol.iterator]){const e=Array.isArray(n)?n:Array.from(n);s=new Array(e.length);for(let t=0;te[t]}else s=Object.keys(n),a=e=>n[e];for(s.forEach((n,s)=>{const o=a(n);if(t._renderedNodes&&s{s._ref[r]=n,s._ref[e]=o,j(s,{thisObj:t._thisObj,extendVars:s._ref})});else{const s=[];t._renderedNodes||(t._renderedNodes=[]),t._children.forEach(a=>{const i=a.cloneNode(!0);i._ref={...t._ref,[r]:n,[e]:o},i._thisObj=t._thisObj,t.parentNode.insertBefore(i,t),s.push(i)}),t._renderedNodes.push(s)}});t._renderedNodes&&t._renderedNodes.length>s.length;)t._renderedNodes.pop().forEach(e=>{N(e),e.remove()})}else N(t),t._renderedNodes=[];else if("bind"===r){if(["INPUT","SELECT","TEXTAREA"].includes(t.tagName)&&!t.hasAttribute("autocomplete")&&t.setAttribute("autocomplete","off"),"checkbox"===t.type){"on"===t.value||n||(g(`${e.tpl} = []`,{thisNode:t},t._thisObj||t,t._ref||{}),n=[]),t._checkboxMultiMode=n instanceof Array;const r=n instanceof Array?n.includes(t.value):!!n;t.checked!==r&&(t.checked=r)}else"radio"===t.type?t.checked!==(t.value===String(n??""))&&(t.checked=t.value===String(n??"")):"value"in t&&"file"!==t.type?setTimeout(()=>{t.value!==String(n??"")&&(t.value=n)}):t.isContentEditable&&t.innerHTML!==String(n??"")&&(t.innerHTML=n);t.dispatchEvent(new CustomEvent("bind",{bubbles:!1,detail:n}))}else["checked","disabled","readonly"].includes(r)&&(n=!!n),"boolean"==typeof n?n?t.setAttribute(r,""):t.removeAttribute(r):void 0!==n&&("string"!=typeof n&&(n=JSON.stringify(n)),"text"===r?t.textContent=n??"":"html"===r?t.innerHTML=n??"":"IMG"===t.tagName&&"src"===r&&n.includes(".svg")?t.setAttribute("_src",n??""):t.setAttribute(r,n??""))}}y=e=>O(e),a.add(y);const T=e=>{e.node._bindings||(e.node._bindings=[]),e.node._bindings.push({attr:e.attr,prop:e.prop,tpl:e.tpl,exp:e.exp}),O(e)},j=(e,t={})=>{if(3===e.nodeType){if(e._stTranslated)return;const t=A(e.textContent);return t!==e.textContent&&(e.textContent=t),void(e._stTranslated=!0)}if(1!==e.nodeType)return;if(e._stTranslated||(Array.from(e.attributes).forEach(e=>{if(!e.name.startsWith("$")&&!e.name.startsWith("st-")&&!e.name.startsWith(".")){const t=A(e.value);t!==e.value&&(e.value=t)}}),e._stTranslated=!0),"TEMPLATE"!==e.tagName&&(e.hasAttribute("$if")||e.hasAttribute("$each")||e.hasAttribute("st-if")||e.hasAttribute("st-each"))){const t=document.createElement("TEMPLATE");return Array.from(e.attributes).filter(t=>["$if","$each","st-if","st-each"].includes(t.name)||(e.hasAttribute("$each")||e.hasAttribute("st-each"))&&["as","index"].includes(t.name)).forEach(n=>{t.setAttribute(n.name,n.value),e.removeAttribute(n.name)}),e.parentNode.insertBefore(t,e),t.content.appendChild(e),void(t._ref=e._ref)}if("TEMPLATE"===e.tagName&&(e.hasAttribute("$if")||e.hasAttribute("st-if"))&&(e.hasAttribute("$each")||e.hasAttribute("st-each"))){const t=document.createElement("TEMPLATE"),n=Array.from(e.attributes).filter(e=>["$if","$each","st-if","st-each"].includes(e.name)),r=n[n.length-1];t.setAttribute(r.name,r.value),e.removeAttribute(r.name),"$each"!==r.name&&"st-each"!==r.name||Array.from(e.attributes).filter(e=>["as","index"].includes(e.name)).forEach(n=>{t.setAttribute(n.name,n.value),e.removeAttribute(n.name)}),Array.from(e.content.childNodes).forEach(e=>t.content.appendChild(e)),e.content.appendChild(t),t._ref=e._ref}if("IMG"===e.tagName&&(e.hasAttribute("src")||e.hasAttribute("_src")||e.hasAttribute("$src"))){const t=e;Promise.resolve().then(()=>{const e=t.getAttribute("_src")||t.getAttribute("src");e&&fetch(e,{cache:"force-cache"}).then(e=>e.text()).then(e=>{const n=(new DOMParser).parseFromString(e,"image/svg+xml").querySelector("svg");n&&(Array.from(t.attributes).forEach(e=>n.setAttribute(e.name,e.value)),t.replaceWith(n))})})}if(void 0!==e._thisObj)t.thisObj=e._thisObj||null;else{let n=e;for(;n&&void 0===n._thisObj;)n=n.parentNode;t.thisObj=n?n._thisObj:null}if(void 0===e._ref){let t=e;for(;t&&void 0===t._ref;)t=t.parentNode;e._ref=t?{...t._ref}:{}}t.extendVars&&Object.assign(e._ref,t.extendVars),((e,t)=>{let n=!1;if(e._bindings&&(e._states=new Set,e._bindings.forEach(t=>O({node:e,...t})),e._hasOnUpdate&&e.dispatchEvent(new Event("update",{bubbles:!1})),n=!0),h.exists(e.tagName)&&!e._componentInitialized&&(Array.from(e.attributes).forEach(n=>{var r;if(n.name.startsWith("$.")){const s=n.name.slice(2);let a=A(n.value);a.includes("this.")&&(a=a.replace(/\bthis\./g,"this.parent."));const o=_(a,{thisNode:e},{parent:t.thisObj||e},e._ref||{});let i=e;const d=s.split(".");for(let e=0;ee.removeAttribute("slot-id")),e._componentInitialized=!0,e._thisObj||(e._thisObj=e)),"TEMPLATE"===e.tagName&&(e._children=[...e.content.childNodes],e._renderedNodes||(e._renderedNodes=[])),n)return;let r=[];"TEMPLATE"===e.tagName?["$if","$each","st-if","st-each"].forEach(t=>e.hasAttribute(t)&&r.push(e.getAttributeNode(t))):r=Array.from(e.attributes).filter(e=>(e.name.startsWith("$")||e.name.startsWith("st-"))&&!["$if","$each","st-if","st-each"].includes(e.name)||e.name.includes(".")),e._thisObj&&t.thisObj&&(e._thisObj.parent=t.thisObj),e._thisObj||(e._thisObj=t.thisObj||null),e._ref||(e._ref=t.extendVars||{}),e._states=new Set,r.forEach(n=>{const r=n.name.startsWith("$")||n.name.startsWith("st-"),a=r?n.name.slice(n.name.startsWith("$")?1:3):n.name;let o=n.value;if(e.removeAttribute(n.name),a.startsWith("."))T({node:e,prop:a.split("."),tpl:o,exp:r});else if(a.startsWith("on")){const n=a.slice(2);"update"===n&&(e._hasOnUpdate=!0),"load"!==n||["BODY","IMG","IFRAME"].includes(e.tagName)||(e._hasOnLoad=!0),"unload"!==n||["BODY","IMG","IFRAME"].includes(e.tagName)||(e._hasOnUnload=!0),e.addEventListener(n,n=>g(o,{event:n,thisNode:e,...n.detail||{}},t.thisObj||e,e._ref||{}))}else"bind"===a?e.addEventListener("TEXTAREA"===e.tagName||e.isContentEditable||"text"===e.type||"password"===e.type?"input":"change",n=>{let r=e.isContentEditable?n.target.innerHTML:"checkbox"===e.type?n.target.checked:n.target.files||n.target.value||n.detail;s(e),m(!0),"checkbox"===e.type&&e._checkboxMultiMode?g(`!!checked ? (!${o}.includes(val) && ${o}.push(val)) : (index = ${o}.indexOf(val), index > -1 && ${o}.splice(index, 1))`,{val:e.value,checked:r,thisNode:e},t.thisObj||e,e._ref||{}):g(`${o} = val`,{val:r,thisNode:e},t.thisObj||e,e._ref||{}),m(!1),s(null)}):"text"!==a||o||(o=e.textContent,e.textContent=""),o&&(o=A(o),T({node:e,attr:a,tpl:o,exp:r}))}),(e._hasOnLoad||e._componentInitialized)&&Promise.resolve().then(()=>e.dispatchEvent(new Event("load",{bubbles:!1}))),e._hasOnUpdate&&e.dispatchEvent(new Event("update",{bubbles:!1})),e._thisObj&&(t.thisObj=e._thisObj)})(e,t);const n=[...e.childNodes||[]],r={thisObj:t.thisObj,extendVars:{...e._ref}};n.forEach(e=>j(e,r))},w=e=>{1===e.nodeType&&(e._hasOnUnload&&e.dispatchEvent(new Event("unload",{bubbles:!1})),e._states&&e._states.forEach(t=>{for(const[n,r]of t)for(const t of r)t.node===e&&r.delete(t)}),e.childNodes&&e.childNodes.forEach(e=>w(e)))},x=j,S={clone:window.structuredClone||(e=>JSON.parse(JSON.stringify(e))),base64:e=>btoa(String.fromCharCode(...(new TextEncoder).encode(e))),unbase64:e=>(new TextDecoder).decode(Uint8Array.from(atob(e),e=>e.charCodeAt(0))),urlbase64:e=>S.base64(e).replace(/[+/=]/g,e=>({"+":"-","/":"","=":""}[e])),unurlbase64:e=>S.unbase64(e.replace(/[-_.]/g,e=>({"-":"+",_:"/",".":"="}[e])).padEnd(4*Math.ceil(e.length/4),"=")),safeJson:e=>{try{return JSON.parse(e)}catch{return null}},updateDefaults:(e,t)=>{for(const n in t)void 0===e[n]&&(e[n]=t[n])},copyFunction:(e,t,...n)=>{n.forEach(n=>e[n]=t[n].bind(t))},getFunctionBody:e=>{const t=e.toString();return t.slice(t.indexOf("{")+1,t.lastIndexOf("}")).trim()},makeDom:e=>{e.includes(">\n")&&(e=e.replace(/>\s+<").trim());const t=document.createElement("div");return t.innerHTML=e,t.children[0]},newAvg:()=>{let e=0,t=0,n=0;return{add:r=>(e+=r,t++,n=e/t),get:()=>n,clear:()=>{e=0,t=0,n=0}}},newTimeCount:()=>{let e=0,t=0,n=0;return{start:()=>e=(new Date).getTime(),end:()=>{const r=(new Date).getTime(),s=r-e;return e=r,t+=s,n++,s},avg:()=>t/n}}};globalThis.Util=S;let M=new URLSearchParams((null==(e=window.location.hash)?void 0:e.substring(1))||"");const L=o({},e=>S.safeJson(M.get(e)),(e,t)=>{const n=M.get(e),r=void 0===t?void 0:JSON.stringify(t);n===r||null===n&&void 0===r||(void 0===t?M.delete(e):M.set(e,r),window.location.hash="#"+M.toString())});"undefined"!=typeof window&&window.addEventListener("hashchange",()=>{var e;const t=M;M=new URLSearchParams((null==(e=window.location.hash)?void 0:e.substring(1))||""),M.forEach((e,n)=>{t.get(n)!==e&&(L[n]=S.safeJson(e))}),t.forEach((e,t)=>{void 0===M.get(t)&&(L[t]=void 0)})});const $=o({},e=>S.safeJson(localStorage.getItem(e)),(e,t)=>{const n=localStorage.getItem(e),r=void 0===t?void 0:JSON.stringify(t);n===r||null===n&&void 0===r||(void 0===t?localStorage.removeItem(e):localStorage.setItem(e,r))});if(globalThis.Hash=L,globalThis.LocalStorage=$,"undefined"!=typeof document){const e=()=>{h._initPending(),new MutationObserver(e=>{e.forEach(e=>{e.addedNodes.forEach(e=>{e.isConnected&&j(e)}),e.removedNodes.forEach(e=>w(e))})}).observe(document.documentElement,{childList:!0,subtree:!0}),j(document.documentElement)};"loading"!==document.readyState?e():document.addEventListener("DOMContentLoaded",e,!0)}export{i as $,d as $$,h as Component,L as Hash,$ as LocalStorage,o as NewState,x as RefreshState,v as SetTranslator,S as Util,j as _scanTree,w as _unbindTree}; diff --git a/package.json b/package.json index 3f832c4..0a1fc9c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@web/state", - "version": "1.0.9", + "version": "1.0.10", "type": "module", "main": "dist/state.js", diff --git a/src/component.js b/src/component.js index b50e589..1b7f3bb 100644 --- a/src/component.js +++ b/src/component.js @@ -42,7 +42,9 @@ export function _mergeNode(from, to, scanObj, exists = {}) { }); } to.classList.add(...from.classList); - Array.from(from.childNodes).forEach(child => to.appendChild(child)); + const fromContent = from.tagName === 'TEMPLATE' ? from.content : from; + const toContent = to.tagName === 'TEMPLATE' ? to.content : to; + Array.from(fromContent.childNodes).forEach(child => toContent.appendChild(child)); if (from.tagName && Component.exists(from.tagName)) _makeComponent(from.tagName, to, scanObj, exists); } diff --git a/src/dom.js b/src/dom.js index 502a2f1..8a18306 100644 --- a/src/dom.js +++ b/src/dom.js @@ -6,9 +6,7 @@ import { $, $$ } from './dom-utils.js'; let _translator = (text, args) => { if (!text || typeof text !== 'string') return text; - return text.replace(/\{(.+?)\}/g, (match, key) => { - return args.hasOwnProperty(key) ? args[key] : match; - }) + return text.replace(/\{(.+?)\}/g, (match, key) => args.hasOwnProperty(key) ? args[key] : match); }; export const SetTranslator = (fn) => _translator = fn; @@ -16,23 +14,17 @@ const _translate = (text) => { if (!text || typeof text !== 'string' || !text.includes('{#')) return text; return text.replace(/\{#(.+?)#\}/g, (m, content) => { const parts = content.split('||').map(s => s.trim()); - const rawText = parts[0]; const args = {}; if (parts.length > 1) { - const matches = rawText.match(/\{(.+?)\}/g); - if (matches) matches.forEach((match, i) => { - const key = match.substring(1, match.length - 1); - args[key] = parts[i + 1] || ''; - }); + const matches = parts[0].match(/\{(.+?)\}/g); + if (matches) matches.forEach((match, i) => args[match.substring(1, match.length - 1)] = parts[i + 1] || ''); } - return _translator(rawText, args); + return _translator(parts[0], args); }); }; if (typeof document !== 'undefined') { - try { - document.createElement('div').setAttribute('$t', '1'); - } catch (e) { + try { document.createElement('div').setAttribute('$t', '1'); } catch (e) { const originalSetAttribute = Element.prototype.setAttribute; Element.prototype.setAttribute = function (name, value) { if (!name.startsWith('$')) return originalSetAttribute.call(this, name, value); @@ -46,21 +38,18 @@ export { $, $$ }; onNotifyUpdate((binding) => _updateBinding(binding)); export function _clearRenderedNodes(node) { - if (node._renderedNodes) node._renderedNodes.forEach(nodes => { - nodes.forEach(child => { - child.remove(); - if (child._renderedNodes) _clearRenderedNodes(child); - }); - }); + if (node._renderedNodes) node._renderedNodes.forEach(nodes => nodes.forEach(child => { + child.remove(); + if (child._renderedNodes) _clearRenderedNodes(child); + })); } export function _updateBinding(binding) { const node = binding.node; - const tpl = binding.tpl; - const exp = binding.exp; + if (!node.isConnected && node.tagName !== 'TEMPLATE') return; setActiveBinding(binding); - let result = exp ? (tpl ? _returnCode(tpl, { thisNode: node }, node._thisObj || node, node._ref || null) : null) : tpl; + let result = binding.exp ? (binding.tpl ? _returnCode(binding.tpl, { thisNode: node }, node._thisObj || node, node._ref || null) : null) : binding.tpl; setActiveBinding(null); if (binding.prop) { @@ -73,14 +62,13 @@ export function _updateBinding(binding) { if (typeof o !== 'object') break; } if (typeof o === 'object' && o !== null) { - const resultIsObject = typeof result === 'object' && result != null && !Array.isArray(result); const lk = prop[prop.length - 1]; if (lk) { - if (resultIsObject && o[lk] == null) o[lk] = {}; + if (typeof result === 'object' && result != null && !Array.isArray(result) && o[lk] == null) o[lk] = {}; const lo = o[lk]; if (typeof lo === 'object' && lo != null && lo.__watch) Object.assign(lo, result); else o[lk] = result; - } else if (resultIsObject && typeof o === 'object') { + } else if (typeof result === 'object' && result != null && !Array.isArray(result)) { Object.assign(o, result); } } @@ -129,9 +117,7 @@ export function _updateBinding(binding) { if (!node._renderedNodes) node._renderedNodes = []; node._children.forEach(child => { const cloned = child.cloneNode(true); - cloned._ref = { ...node._ref }; - cloned._ref[indexName] = k; - cloned._ref[asName] = item; + cloned._ref = { ...node._ref, [indexName]: k, [asName]: item }; cloned._thisObj = node._thisObj; node.parentNode.insertBefore(cloned, node); newNodes.push(cloned); @@ -140,53 +126,39 @@ export function _updateBinding(binding) { } }); while (node._renderedNodes && node._renderedNodes.length > keys.length) { - node._renderedNodes[node._renderedNodes.length - 1].forEach(child => { + node._renderedNodes.pop().forEach(child => { _clearRenderedNodes(child); child.remove(); }); - node._renderedNodes.pop(); } } else { _clearRenderedNodes(node); node._renderedNodes = []; } } else if (attr === 'bind') { - if (['INPUT', 'SELECT', 'TEXTAREA'].includes(node.tagName)) { - if (!node.hasAttribute('autocomplete')) node.setAttribute('autocomplete', 'off'); - } + if (['INPUT', 'SELECT', 'TEXTAREA'].includes(node.tagName) && !node.hasAttribute('autocomplete')) node.setAttribute('autocomplete', 'off'); if (node.type === 'checkbox') { - if (node.value !== 'on' && !result) { - _runCode(`${tpl} = []`, { thisNode: node }, node._thisObj || node, node._ref || {}); - result = []; - } + if (node.value !== 'on' && !result) { _runCode(`${binding.tpl} = []`, { thisNode: node }, node._thisObj || node, node._ref || {}); result = []; } node._checkboxMultiMode = result instanceof Array; const isChecked = result instanceof Array ? result.includes(node.value) : !!result; if (node.checked !== isChecked) node.checked = isChecked; } else if (node.type === 'radio') { if (node.checked !== (node.value === String(result ?? ''))) node.checked = (node.value === String(result ?? '')); } else if ('value' in node && node.type !== 'file') { - setTimeout(() => { - if (node.value !== String(result ?? '')) node.value = result; - }); + setTimeout(() => { if (node.value !== String(result ?? '')) node.value = result; }); } else if (node.isContentEditable) { if (node.innerHTML !== String(result ?? '')) node.innerHTML = result; } node.dispatchEvent(new CustomEvent('bind', { bubbles: false, detail: result })); } else { if (['checked', 'disabled', 'readonly'].includes(attr)) result = !!result; - if (typeof result === 'boolean') { - result ? node.setAttribute(attr, '') : node.removeAttribute(attr); - } else if (result !== undefined) { + if (typeof result === 'boolean') result ? node.setAttribute(attr, '') : node.removeAttribute(attr); + else if (result !== undefined) { if (typeof result !== 'string') result = JSON.stringify(result); - if (attr === 'text') { - node.textContent = result ?? ''; - } else if (attr === 'html') { - node.innerHTML = result ?? ''; - } else if (node.tagName === 'IMG' && attr === 'src' && result.includes('.svg')) { - node.setAttribute('_src', result ?? ''); - } else { - node.setAttribute(attr, result ?? ''); - } + if (attr === 'text') node.textContent = result ?? ''; + else if (attr === 'html') node.innerHTML = result ?? ''; + else if (node.tagName === 'IMG' && attr === 'src' && result.includes('.svg')) node.setAttribute('_src', result ?? ''); + else node.setAttribute(attr, result ?? ''); } } } @@ -199,52 +171,46 @@ export const _initBinding = (binding) => { }; export const _parseNode = (node, scanObj) => { + let hasBindings = false; if (node._bindings) { node._states = new Set(); - node._bindings.forEach(bindingData => { - const binding = { node: node, ...bindingData }; - _updateBinding(binding); - }); + node._bindings.forEach(b => _updateBinding({ node, ...b })); if (node._hasOnUpdate) node.dispatchEvent(new Event('update', { bubbles: false })); - return; + hasBindings = true; } if (Component.exists(node.tagName) && !node._componentInitialized) { Array.from(node.attributes).forEach(attr => { if (attr.name.startsWith('$.')) { const realAttrName = attr.name.slice(2); - let tpl = attr.value; + let tpl = _translate(attr.value); if (tpl.includes('this.')) tpl = tpl.replace(/\bthis\./g, 'this.parent.'); - tpl = _translate(tpl); const result = _returnCode(tpl, { thisNode: node }, { parent: scanObj.thisObj || node }, node._ref || {}); let o = node; const prop = realAttrName.split('.'); - for (let i = 0; i < prop.length - 1; i++) { - if (!prop[i]) continue; - if (o[prop[i]] == null) o[prop[i]] = {}; - o = o[prop[i]]; - } + for (let i = 0; i < prop.length - 1; i++) { if (prop[i]) o = (o[prop[i]] ??= {}); } o[prop[prop.length - 1]] = result; node.removeAttribute(attr.name); } }); - _makeComponent(node.tagName, node, scanObj); - $$(node, '[slot-id]').forEach(placeholder => placeholder.removeAttribute('slot-id')); + $$(node, '[slot-id]').forEach(p => p.removeAttribute('slot-id')); node._componentInitialized = true; if (!node._thisObj) node._thisObj = node; } - let attrs = []; if (node.tagName === 'TEMPLATE') { node._children = [...node.content.childNodes]; - node._renderedNodes = []; - if (node.hasAttribute('$if')) attrs.push(node.getAttributeNode('$if')); - else if (node.hasAttribute('$each')) attrs.push(node.getAttributeNode('$each')); - else if (node.hasAttribute('st-if')) attrs.push(node.getAttributeNode('st-if')); - else if (node.hasAttribute('st-each')) attrs.push(node.getAttributeNode('st-each')); + if (!node._renderedNodes) node._renderedNodes = []; + } + + if (hasBindings) return; + + let attrs = []; + if (node.tagName === 'TEMPLATE') { + ['$if', '$each', 'st-if', 'st-each'].forEach(n => node.hasAttribute(n) && attrs.push(node.getAttributeNode(n))); } else { - attrs = Array.from(node.attributes).filter(attr => (attr.name.startsWith('$') || attr.name.startsWith('st-')) && !['$if', '$each', 'st-if', 'st-each'].includes(attr.name) || attr.name.includes('.')); + attrs = Array.from(node.attributes).filter(a => (a.name.startsWith('$') || a.name.startsWith('st-')) && !['$if', '$each', 'st-if', 'st-each'].includes(a.name) || a.name.includes('.')); } if (node._thisObj && scanObj.thisObj) node._thisObj.parent = scanObj.thisObj; @@ -257,50 +223,28 @@ export const _parseNode = (node, scanObj) => { const realAttrName = exp ? attr.name.slice(attr.name.startsWith('$') ? 1 : 3) : attr.name; let tpl = attr.value; node.removeAttribute(attr.name); - if (realAttrName.startsWith('.')) { - _initBinding({ node: node, prop: realAttrName.split('.'), tpl, exp }); + if (realAttrName.startsWith('.')) _initBinding({ node, prop: realAttrName.split('.'), tpl, exp }); + else if (realAttrName.startsWith('on')) { + const eventName = realAttrName.slice(2); + if (eventName === 'update') node._hasOnUpdate = true; + if (eventName === 'load' && !['BODY', 'IMG', 'IFRAME'].includes(node.tagName)) node._hasOnLoad = true; + if (eventName === 'unload' && !['BODY', 'IMG', 'IFRAME'].includes(node.tagName)) node._hasOnUnload = true; + node.addEventListener(eventName, (e) => _runCode(tpl, { event: e, thisNode: node, ...(e.detail || {}) }, scanObj.thisObj || node, node._ref || {})); } else { - if (realAttrName.startsWith('on')) { - const eventName = realAttrName.slice(2); - if (eventName === 'update') node._hasOnUpdate = true; - if (eventName === 'load' && !['BODY', 'IMG', 'IFRAME'].includes(node.tagName)) node._hasOnLoad = true; - if (eventName === 'unload' && !['BODY', 'IMG', 'IFRAME'].includes(node.tagName)) node._hasOnUnload = true; - ((node, thisObj) => { - node.addEventListener(eventName, (e) => { - _runCode(tpl, { event: e, thisNode: node, ...(e.detail || {}) }, thisObj || node, node._ref || {}); - }); - })(node, scanObj.thisObj); - } else { - if (realAttrName === 'bind') { - node.addEventListener(node.tagName === 'TEXTAREA' || node.isContentEditable || node.type === 'text' || node.type === 'password' ? 'input' : 'change', (e) => { - let newVal = node.isContentEditable ? e.target.innerHTML : (node.type === 'checkbox' ? e.target.checked : e.target.files || e.target.value || e.detail); - setNoWriteBack(node); - setDisableRunCodeError(true); - if (node.type === 'checkbox' && node._checkboxMultiMode) { - _runCode(`!!checked ? (!${tpl}.includes(val) && ${tpl}.push(val)) : (index = ${tpl}.indexOf(val), index > -1 && ${tpl}.splice(index, 1))`, { val: node.value, checked: newVal, thisNode: node }, scanObj.thisObj || node, node._ref || {}); - } else { - _runCode(`${tpl} = val`, { val: newVal, thisNode: node }, scanObj.thisObj || node, node._ref || {}); - } - setDisableRunCodeError(false); - setNoWriteBack(null); - }); - } else if (realAttrName === 'text' && !tpl) { - tpl = node.textContent; - node.textContent = ''; - } - if (tpl) { - tpl = _translate(tpl); - _initBinding({ node: node, attr: realAttrName, tpl, exp }); - } - } + if (realAttrName === 'bind') { + node.addEventListener(node.tagName === 'TEXTAREA' || node.isContentEditable || node.type === 'text' || node.type === 'password' ? 'input' : 'change', (e) => { + let newVal = node.isContentEditable ? e.target.innerHTML : (node.type === 'checkbox' ? e.target.checked : e.target.files || e.target.value || e.detail); + setNoWriteBack(node); setDisableRunCodeError(true); + if (node.type === 'checkbox' && node._checkboxMultiMode) _runCode(`!!checked ? (!${tpl}.includes(val) && ${tpl}.push(val)) : (index = ${tpl}.indexOf(val), index > -1 && ${tpl}.splice(index, 1))`, { val: node.value, checked: newVal, thisNode: node }, scanObj.thisObj || node, node._ref || {}); + else _runCode(`${tpl} = val`, { val: newVal, thisNode: node }, scanObj.thisObj || node, node._ref || {}); + setDisableRunCodeError(false); setNoWriteBack(null); + }); + } else if (realAttrName === 'text' && !tpl) { tpl = node.textContent; node.textContent = ''; } + if (tpl) { tpl = _translate(tpl); _initBinding({ node, attr: realAttrName, tpl, exp }); } } }); - if (node._hasOnLoad || node._componentInitialized) { - (node => { - Promise.resolve().then(() => node.dispatchEvent(new Event('load', { bubbles: false }))); - })(node); - } + if (node._hasOnLoad || node._componentInitialized) Promise.resolve().then(() => node.dispatchEvent(new Event('load', { bubbles: false }))); if (node._hasOnUpdate) node.dispatchEvent(new Event('update', { bubbles: false })); if (node._thisObj) scanObj.thisObj = node._thisObj; }; @@ -310,8 +254,7 @@ export const _scanTree = (node, scanObj = {}) => { if (node._stTranslated) return; const translated = _translate(node.textContent); if (translated !== node.textContent) node.textContent = translated; - node._stTranslated = true; - return; + node._stTranslated = true; return; } if (node.nodeType !== 1) return; @@ -328,14 +271,10 @@ export const _scanTree = (node, scanObj = {}) => { if (node.tagName !== 'TEMPLATE' && (node.hasAttribute('$if') || node.hasAttribute('$each') || node.hasAttribute('st-if') || node.hasAttribute('st-each'))) { const template = document.createElement('TEMPLATE'); const attrs = Array.from(node.attributes).filter(attr => ['$if', '$each', 'st-if', 'st-each'].includes(attr.name) || ((node.hasAttribute('$each') || node.hasAttribute('st-each')) && ['as', 'index'].includes(attr.name))); - attrs.forEach(attr => { - template.setAttribute(attr.name, attr.value); - node.removeAttribute(attr.name); - }); + attrs.forEach(attr => { template.setAttribute(attr.name, attr.value); node.removeAttribute(attr.name); }); node.parentNode.insertBefore(template, node); template.content.appendChild(node); template._ref = node._ref; - node = template; return; } if (node.tagName === 'TEMPLATE' && (node.hasAttribute('$if') || node.hasAttribute('st-if')) && (node.hasAttribute('$each') || node.hasAttribute('st-each'))) { @@ -345,14 +284,9 @@ export const _scanTree = (node, scanObj = {}) => { template.setAttribute(attr.name, attr.value); node.removeAttribute(attr.name); if (attr.name === '$each' || attr.name === 'st-each') { - Array.from(node.attributes).filter(attr => ['as', 'index'].includes(attr.name)).forEach(attr => { - template.setAttribute(attr.name, attr.value); - node.removeAttribute(attr.name); - }); + Array.from(node.attributes).filter(attr => ['as', 'index'].includes(attr.name)).forEach(attr => { template.setAttribute(attr.name, attr.value); node.removeAttribute(attr.name); }); } - Array.from(node.content.childNodes).forEach(child => { - template.content.appendChild(child); - }); + Array.from(node.content.childNodes).forEach(child => template.content.appendChild(child)); node.content.appendChild(template); template._ref = node._ref; } @@ -372,7 +306,7 @@ export const _scanTree = (node, scanObj = {}) => { } if (node._thisObj !== undefined) scanObj.thisObj = node._thisObj || null; - if (scanObj.thisObj === undefined) { + else { let curr = node; while (curr && curr._thisObj === undefined) curr = curr.parentNode; scanObj.thisObj = curr ? curr._thisObj : null; @@ -382,29 +316,23 @@ export const _scanTree = (node, scanObj = {}) => { while (curr && curr._ref === undefined) curr = curr.parentNode; node._ref = curr ? { ...curr._ref } : {}; } - if (scanObj.extendVars === undefined) scanObj.extendVars = {}; - if (node._ref !== undefined) { - Object.assign(node._ref, scanObj.extendVars); - scanObj.extendVars = { ...node._ref }; - } + if (scanObj.extendVars) Object.assign(node._ref, scanObj.extendVars); + _parseNode(node, scanObj); + const nodes = [...(node.childNodes || [])]; - scanObj.extendVars = node._ref || scanObj.extendVars; - nodes.forEach(child => _scanTree(child, { thisObj: scanObj.thisObj, extendVars: { ...node._ref } })); + const nextScanObj = { thisObj: scanObj.thisObj, extendVars: { ...node._ref } }; + nodes.forEach(child => _scanTree(child, nextScanObj)); }; export const _unbindTree = (node) => { if (node.nodeType !== 1) return; if (node._hasOnUnload) node.dispatchEvent(new Event('unload', { bubbles: false })); - if (node._states) { - node._states.forEach(stateMappings => { - for (const [key, bindingSet] of stateMappings) { - for (const binding of bindingSet) { - if (binding.node === node) bindingSet.delete(binding); - } - } - }); - } + if (node._states) node._states.forEach(mappings => { + for (const [key, bindingSet] of mappings) { + for (const binding of bindingSet) { if (binding.node === node) bindingSet.delete(binding); } + } + }); node.childNodes && node.childNodes.forEach(child => _unbindTree(child)); };