@livetemplate/client 0.8.41 → 0.8.42
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/dist/livetemplate-client.browser.js +1 -1
- package/dist/livetemplate-client.browser.js.map +2 -2
- package/dist/livetemplate-client.d.ts.map +1 -1
- package/dist/livetemplate-client.js +18 -14
- package/dist/livetemplate-client.js.map +1 -1
- package/dist/tests/navigation.test.js +27 -0
- package/dist/tests/navigation.test.js.map +1 -1
- package/package.json +1 -1
|
@@ -28,5 +28,5 @@
|
|
|
28
28
|
}
|
|
29
29
|
`,document.head.appendChild(t)}document.body.insertBefore(e,document.body.firstChild),this.bar=e}hide(){this.bar&&(this.bar.parentNode&&this.bar.parentNode.removeChild(this.bar),this.bar=null)}};var me=class{disable(e){if(!e)return;e.querySelectorAll("form").forEach(n=>{n.querySelectorAll("input, textarea, select, button").forEach(i=>{i.disabled=!0})})}enable(e){if(!e)return;e.querySelectorAll("form").forEach(n=>{n.querySelectorAll("input, textarea, select, button").forEach(i=>{i.disabled=!1})})}};var Et=!1;function un(s){let e=s.target;if(!e||!(e instanceof Element))return;let t=e.closest("button[commandfor]");if(!t||t.disabled)return;let n=t.getAttribute("commandfor");if(!n)return;let r=t.getAttribute("command"),i=document.getElementById(n);i&&(i instanceof HTMLDialogElement?r==="show-modal"&&!i.open?i.showModal():r==="close"&&i.open&&i.close():i instanceof HTMLElement&&i.hasAttribute("popover")&&(r==="show-popover"&&typeof i.showPopover=="function"?i.showPopover():r==="hide-popover"&&typeof i.hidePopover=="function"?i.hidePopover():r==="toggle-popover"&&typeof i.togglePopover=="function"&&i.togglePopover()))}function wt(){"commandForElement"in HTMLButtonElement.prototype||Et||(Et=!0,document.addEventListener("click",un))}var X="__lvt_scroll_away",U=[];function pn(){for(let s=U.length-1;s>=0;s--){let e=U[s];e.trigger.isConnected||(e.target.removeEventListener("scroll",e.handler),delete e.trigger[X],U.splice(s,1))}}function Tt(s){pn();let e=t=>{let n=t.getAttribute("lvt-scroll-away");if(!n)return;if(n!=="bottom"&&n!=="top"){console.warn(`Unknown lvt-scroll-away edge: ${n}`);return}let r=B(t);if(!r||r===t){let u=t[X];u&&(u.target.removeEventListener("scroll",u.handler),At(u),delete t[X]),console.warn("lvt-scroll-away requires data-lvt-target pointing to a scrollable container");return}let i=t[X];if(i){if(i.target===r)return;i.target.removeEventListener("scroll",i.handler),At(i)}let a=parseInt(getComputedStyle(t).getPropertyValue("--lvt-scroll-threshold").trim(),10),o=isNaN(a)?200:a,c=!1,l=()=>{c||(c=!0,requestAnimationFrame(()=>{c=!1,(n==="top"?r.scrollTop:r.scrollHeight-r.scrollTop-r.clientHeight)>o?t.classList.add("visible"):t.classList.remove("visible")}))};r.addEventListener("scroll",l,{passive:!0}),l();let d={trigger:t,target:r,handler:l};t[X]=d,U.push(d)};e(s),s.querySelectorAll("[lvt-scroll-away]").forEach(e)}function At(s){let e=U.indexOf(s);e!==-1&&U.splice(e,1)}function St(s){for(let e=U.length-1;e>=0;e--){let t=U[e];s&&t.trigger.isConnected&&!s.contains(t.trigger)||(t.target.removeEventListener("scroll",t.handler),t.trigger.classList.remove("visible"),delete t.trigger[X],U.splice(e,1))}}function Lt(s){return typeof structuredClone=="function"?structuredClone(s):JSON.parse(JSON.stringify(s))}function fn(s){return s!=null&&typeof s=="object"&&Array.isArray(s.d)&&Array.isArray(s.s)}function Ie(s,e=0){if(e>50||s==null||typeof s!="object"||Array.isArray(s))return!1;if(fn(s))return!0;for(let n of Object.keys(s))if(/^\d+$/.test(n)){let r=s[n];if(r!=null&&typeof r=="object"&&!Array.isArray(r)&&Ie(r,e+1))return!0}return!1}function gn(s,e){if(!e.s||!Array.isArray(e.s))return!1;if(Ie(s)&&!Ie(e))return!0;for(let t of Object.keys(s))if(/^\d+$/.test(t)&&!(t in e))return!0;return!1}var ve=class{constructor(e){this.logger=e;this.treeState={};this.rangeState={};this.rangeIdKeys={}}applyUpdate(e,t){var c,l;let n=!1,r=[],i=new Set;for(let[d,u]of Object.entries(e))if(Array.isArray(u)&&u.length>0&&Array.isArray(u[0])&&typeof u[0][0]=="string"){let f=this.treeState[d];f&&typeof f=="object"&&!Array.isArray(f)&&Array.isArray(f.d)&&Array.isArray(f.s)?((c=t==null?void 0:t.canApplyTargeted)==null?void 0:c.call(t,f,d))===!0?(this.applyDifferentialOpsToRange(f,u,d),r.push({rangePath:d,ops:u,statics:f.s,idKey:(l=f.m)==null?void 0:l.idKey}),i.add(d)):(this.treeState[d]=Lt(f),this.applyDifferentialOpsToRange(this.treeState[d],u,d)):this.treeState[d]=u,n=!0}else{let f=this.treeState[d],g=typeof u=="object"&&u!==null&&!Array.isArray(u)?this.deepMergeTreeNodes(f,u,d):u;JSON.stringify(f)!==JSON.stringify(g)&&(this.treeState[d]=g,n=!0)}let o={html:this.reconstructFromTree(this.treeState,"",i.size>0?i:void 0),changed:n};return r.length>0&&(o.targetedOps=r),o}reset(){this.treeState={},this.rangeState={},this.rangeIdKeys={}}getTreeState(){return{...this.treeState}}getStaticStructure(){return this.treeState.s||null}renderState(){return this.reconstructFromTree(this.treeState,"")}deepMergeTreeNodes(e,t,n=""){var i;if(typeof t!="object"||t===null||Array.isArray(t)||typeof e!="object"||e===null||Array.isArray(e))return t;if(gn(e,t))return this.logger.debug(`[deepMerge] Structure transition at path ${n}, replacing instead of merging`),t;let r={...e};for(let[a,o]of Object.entries(t)){let c=n?`${n}.${a}`:a,l=Array.isArray(o)&&o.length>0&&Array.isArray(o[0])&&typeof o[0][0]=="string",d=r[a]&&typeof r[a]=="object"&&!Array.isArray(r[a])&&Array.isArray(r[a].d)&&Array.isArray(r[a].s);l&&d?(r[a]=Lt(r[a]),this.logger.debug(`[deepMerge] Applying diff ops at path ${c}`,{ops:o,rangeItems:(i=r[a].d)==null?void 0:i.length}),this.applyDifferentialOpsToRange(r[a],o,c)):typeof o=="object"&&o!==null&&!Array.isArray(o)&&typeof r[a]=="object"&&r[a]!==null&&!Array.isArray(r[a])?r[a]=this.deepMergeTreeNodes(r[a],o,c):r[a]=o}return r}applyDifferentialOpsToRange(e,t,n){if(!e||typeof e!="object"||!Array.isArray(e.d)||!Array.isArray(e.s)){this.logger.error(`[applyDiffOpsToRange] Invalid rangeStructure at path ${n}`,{rangeStructure:e});return}let r=e.d;this.rangeState[n]||(this.rangeState[n]={items:r,statics:e.s}),e.m&&typeof e.m=="object"&&typeof e.m.idKey=="string"&&(this.rangeIdKeys[n]=e.m.idKey),this.logger.debug(`[applyDiffOpsToRange] path=${n}, idKey=${this.rangeIdKeys[n]}, items=${r.length}, ops=${t.length}`);for(let i of t){if(!Array.isArray(i)||i.length<2)continue;switch(i[0]){case"r":{let o=i[1],c=this.findItemIndexByKey(r,o,e.s,n);this.logger.debug(`[applyDiffOpsToRange] Remove: key=${o}, index=${c}, total=${r.length}`),c>=0?(r.splice(c,1),this.logger.debug(`[applyDiffOpsToRange] After removal: ${r.length} items`)):this.logger.debug(`[applyDiffOpsToRange] Remove failed: key ${o} not found`);break}case"u":{let o=this.findItemIndexByKey(r,i[1],e.s,n),c=i[2];o>=0&&c&&(r[o]=this.mergeRangeItem(r[o],c,n));break}case"a":{let o=Array.isArray(i[1])?i[1]:[i[1]];i[2]&&(e.s=i[2]),r.push(...o),i[3]&&typeof i[3]=="object"&&i[3].idKey&&(this.rangeIdKeys[n]=i[3].idKey);break}case"p":{let o=Array.isArray(i[1])?i[1]:[i[1]];i[2]&&(e.s=i[2]),r.unshift(...o);break}case"i":{let o=this.findItemIndexByKey(r,i[1],e.s,n);if(o>=0){let c=Array.isArray(i[2])?i[2]:[i[2]];r.splice(o+1,0,...c)}break}case"o":{let o=i[1],c=[],l=new Map;for(let d of r){let u=this.getItemKey(d,e.s,n);u&&l.set(u,d)}for(let d of o){let u=l.get(d);u&&c.push(u)}r.length=0,r.push(...c);break}default:break}}this.rangeState[n]={items:r,statics:e.s}}reconstructFromTree(e,t,n){if(e.s&&Array.isArray(e.s)){let r="";for(let i=0;i<e.s.length;i++){let a=e.s[i];if(r+=a,i<e.s.length-1){let o=i.toString();if(e[o]!==void 0){let c=t?`${t}.${o}`:o;if(n&&n.has(c)){r+=`<!--lvt-targeted-skip:${c}-->`;continue}r+=this.renderValue(e[o],o,c)}}}return r=r.replace(/<root>/g,"").replace(/<\/root>/g,""),r}return this.renderValue(e,"",t)}renderValue(e,t,n){if(e==null||typeof e=="string"&&e.startsWith("{{")&&e.endsWith("}}"))return"";if(typeof e=="object"&&!Array.isArray(e)){if(e.d&&Array.isArray(e.d)&&e.s&&Array.isArray(e.s)){let a=n||t||"";return a&&(this.rangeState[a]={items:e.d,statics:e.s},e.m&&typeof e.m=="object"&&typeof e.m.idKey=="string"&&(this.rangeIdKeys[a]=e.m.idKey)),this.renderRangeStructure(e,t,n)}if("s"in e&&Array.isArray(e.s))return this.reconstructFromTree(e,n||"");let r=Object.keys(e),i=r.filter(a=>/^\d+$/.test(a)).sort((a,o)=>parseInt(a)-parseInt(o));if(i.length>0&&i.length===r.length)return i.map(a=>{let o=n?`${n}.${a}`:a;return this.renderValue(e[a],a,o)}).join("")}return Array.isArray(e)?e.length>0&&Array.isArray(e[0])&&typeof e[0][0]=="string"?this.applyDifferentialOperations(e,n):e.map((r,i)=>{let a=i.toString(),o=n?`${n}.${a}`:a;return typeof r=="object"&&r&&r.s?this.reconstructFromTree(r,o):this.renderValue(r,a,o)}).join(""):typeof e=="object"?(this.logger.debug("Skipping plain object value (not a tree node) - this is normal for state-only data"),""):String(e)}renderRangeStructure(e,t,n){let{d:r,s:i}=e;if(!r||!Array.isArray(r))return"";if(r.length===0){if(e.else){let a="else",o=n?`${n}.else`:"else";return this.renderValue(e.else,a,o)}return""}return i&&Array.isArray(i)?r.map((a,o)=>this.renderRangeItem(a,o,i,n)).join(""):r.map((a,o)=>{let c=o.toString(),l=n?`${n}.${c}`:c;return this.renderValue(a,c,l)}).join("")}renderRangeItem(e,t,n,r){let i=n,a="";for(let o=0;o<i.length;o++)if(a+=i[o],o<i.length-1){let c=o.toString();if(e[c]!==void 0){let l=r?`${r}.${t}.${c}`:`${t}.${c}`;a+=this.renderValue(e[c],c,l)}}return a}applyDifferentialOperations(e,t){if(!t||!this.rangeState[t])return"";let n=this.rangeState[t],r=[...n.items],i=n.statics;for(let o of e){if(!Array.isArray(o)||o.length<2)continue;switch(o[0]){case"r":{let l=this.findItemIndexByKey(r,o[1],i,t);l>=0&&r.splice(l,1);break}case"u":{let l=this.findItemIndexByKey(r,o[1],i,t),d=o[2];l>=0&&d&&(r[l]=this.mergeRangeItem(r[l],d,t||""));break}case"a":{this.addItemsToRange(r,o[1],o[2],n,!1),o[3]&&typeof o[3]=="object"&&o[3].idKey&&(this.rangeIdKeys[t||""]=o[3].idKey);break}case"p":{this.addItemsToRange(r,o[1],o[2],n,!0);break}case"i":{let l=this.findItemIndexByKey(r,o[1],i,t);if(l>=0){let d=Array.isArray(o[2])?o[2]:[o[2]];r.splice(l+1,0,...d)}break}case"o":{let l=o[1],d=[],u=new Map;for(let p of r){let f=this.getItemKey(p,i,t);f&&u.set(f,p)}for(let p of l){let f=u.get(p);f&&d.push(f)}r.length=0,r.push(...d);break}default:break}}this.rangeState[t]={items:r,statics:n.statics},this.treeState[t]={d:r,s:n.statics};let a=this.getCurrentRangeStructure(t);return a&&a.s?this.renderItemsWithStatics(r,a.s,t):r.map(o=>this.renderValue(o)).join("")}getCurrentRangeStructure(e){if(this.rangeState[e])return{d:this.rangeState[e].items,s:this.rangeState[e].statics};let t=this.treeState[e];return t&&typeof t=="object"&&t.s?t:null}renderItemsWithStatics(e,t,n){let r=e.map((i,a)=>this.renderRangeItem(i,a,t,n)).join("");return this.logger.isDebugEnabled()&&(this.logger.debug("[renderItemsWithStatics] statics:",t),this.logger.debug("[renderItemsWithStatics] items count:",e.length),this.logger.debug("[renderItemsWithStatics] result snippet:",r.substring(0,200))),r}addItemsToRange(e,t,n,r,i){if(n&&(r.statics=n),!t)return;let a=Array.isArray(t)?t:[t];i?e.unshift(...a):e.push(...a)}getItemKey(e,t,n){if(e._k&&typeof e._k=="string")return e._k;if(!n||!this.rangeIdKeys[n])return null;let r=this.rangeIdKeys[n];return e[r]||null}findItemIndexByKey(e,t,n,r){return e.findIndex(i=>this.getItemKey(i,n,r)===t)}mergeRangeItem(e,t,n){return this.deepMergeTreeNodes(e,t,`${n}.item`)}};var Fe=["data-key","data-lvt-key"],hn=Fe.map(s=>new RegExp(`(?:^|[\\s<])${s}\\s*=`)),j="data-lvt-targeted-applied",q="data-lvt-targeted-skip",ye=class{constructor(e){this.ctx=e;this.containerCache=new Map}invalidate(){this.containerCache.clear()}invalidatePath(e){this.containerCache.delete(e)}findContainer(e,t,n){let r=this.containerCache.get(t);if(r&&r.isConnected&&e.contains(r))return r;if(r&&this.containerCache.delete(t),n===void 0)return null;let i=this.findItemByKey(e,n);if(!i||!i.parentElement)return null;let a=i.parentElement;return this.containerCache.set(t,a),a}canApplyTargeted(e,t,n){if(!t||typeof t!="object")return{ok:!1,reason:"no range structure"};if(!Array.isArray(t.s)||t.s.length===0)return{ok:!1,reason:"no statics"};let r=[t.s];if(t.sm&&typeof t.sm=="object")for(let d of Object.values(t.sm))Array.isArray(d)&&r.push(d);if(!r.some(d=>this.staticsContainKeyAttribute(d)))return{ok:!1,reason:"no data-key attribute in statics"};let a=t.d;if(Array.isArray(a)){for(let d of a)if(this.itemHasNestedRange(d))return{ok:!1,reason:"nested-range item"}}let o=this.extractItemKey(a==null?void 0:a[0],t),c=this.findContainer(e,n,o);if(!c)return{ok:!1,reason:"container not found in DOM"};let l=c;for(;l;){if(l.hasAttribute("lvt-ignore"))return{ok:!1,reason:"lvt-ignore ancestor"};if(l===e)break;l=l.parentElement}return{ok:!0,container:c,containerKey:o}}apply(e,t,n){let{rangePath:r,ops:i,statics:a}=t,o=this.firstKnownKey(i),c=this.findContainer(e,r,o);if(!c)return this.ctx.logger.debug(`[RangeDomApplier] container not found for range ${r}; cannot apply`),null;let l=!0;for(let d of i){if(!Array.isArray(d)||d.length<1)continue;let u=d[0];try{let p=!0;switch(u){case"r":p=this.applyRemove(c,d[1]);break;case"u":p=this.applyUpdateRow(c,d[1],a,r,n);break;case"i":p=this.applyInsertAfter(c,d[1],d[2],a,r);break;case"a":p=this.applyAppend(c,d[1],a,r);break;case"p":p=this.applyPrepend(c,d[1],a,r);break;case"o":p=this.applyReorder(c,d[1]);break;default:this.ctx.logger.warn(`[RangeDomApplier] unknown op type ${u}; falling back`),p=!1}p||(l=!1)}catch(p){return this.ctx.logger.error(`[RangeDomApplier] op ${u} failed for range ${r}`,p),null}}return l?(typeof window!="undefined"&&"__lvtTargetedHits"in window&&window.__lvtTargetedHits++,c):null}cleanupMarkers(e){e.querySelectorAll(`[${j}]`).forEach(r=>r.removeAttribute(j)),e.hasAttribute(j)&&e.removeAttribute(j),e.querySelectorAll(`[${q}]`).forEach(r=>r.removeAttribute(q)),e.hasAttribute(q)&&e.removeAttribute(q)}applyRemove(e,t){let n=this.findItemByKey(e,t);return n?(this.fireHookOnSubtree(n,"lvt-destroyed"),n.remove(),!0):(this.ctx.logger.debug(`[RangeDomApplier] r: row with key ${t} not found (idempotent no-op)`),!0)}applyUpdateRow(e,t,n,r,i){var u,p;let a=this.findItemByKey(e,t);if(!a)return this.ctx.logger.debug(`[RangeDomApplier] u: row with key ${t} not found in DOM; falling back`),!1;let o=this.indexOfChild(e,a),c=this.lookupCurrentItem(r,t);if(!c)return this.ctx.logger.debug(`[RangeDomApplier] u: item state for key ${t} not available; falling back`),!1;let l=this.ctx.renderItem(c,o,n,r),d=this.parseSingleRow(l);return d?(i?se(a,d,{...i,childrenOnly:!1}):(this.fireHookOnSubtree(a,"lvt-destroyed"),a.replaceWith(d),(p=(u=this.ctx).onNodeAdded)==null||p.call(u,d),this.fireHookOnSubtree(d,"lvt-mounted")),!0):(this.ctx.logger.warn("[RangeDomApplier] u: failed to parse rendered row HTML; falling back"),!1)}applyInsertAfter(e,t,n,r,i){let a=this.findItemByKey(e,t);return a?this.renderItemsAtomic(n,r,i,this.indexOfChild(e,a)+1,o=>e.insertBefore(o,a.nextSibling)):(this.ctx.logger.debug(`[RangeDomApplier] i: anchor key ${t} not found; falling back`),!1)}applyAppend(e,t,n,r){return this.renderItemsAtomic(t,n,r,e.children.length,i=>e.appendChild(i))}applyPrepend(e,t,n,r){return this.renderItemsAtomic(t,n,r,0,i=>e.insertBefore(i,e.firstChild))}renderItemsAtomic(e,t,n,r,i){var l,d;let a=Array.isArray(e)?e:[e],o=document.createDocumentFragment(),c=[];for(let u=0;u<a.length;u++){let p=this.renderAndParse(a[u],r+u,t,n);if(!p)return!1;o.appendChild(p),c.push(p)}i(o);for(let u of c)(d=(l=this.ctx).onNodeAdded)==null||d.call(l,u),this.fireHookOnSubtree(u,"lvt-mounted");return!0}applyReorder(e,t){if(!Array.isArray(t))return!1;let n=new Map;Array.from(e.children).forEach(a=>{for(let o of Fe){let c=a.getAttribute(o);if(c!==null){n.set(c,a);break}}});let r=document.createDocumentFragment(),i=new Set(t);for(let a of t){let o=n.get(a);o&&r.appendChild(o)}if(i.size<n.size){this.ctx.logger.warn(`[RangeDomApplier] o: newKeyOrder (${i.size}) shorter than existing children (${n.size}); ${n.size-i.size} children will be dropped`);for(let[a,o]of n)i.has(a)||this.fireHookOnSubtree(o,"lvt-destroyed")}return e.replaceChildren(r),!0}renderAndParse(e,t,n,r){let i=this.ctx.renderItem(e,t,n,r);return this.parseSingleRow(i)}parseSingleRow(e){let t=document.createElement("template");t.innerHTML=e.trim();let n=t.content.firstElementChild;return n!=null?n:null}findItemByKey(e,t){let n;typeof CSS!="undefined"&&typeof CSS.escape=="function"?n=CSS.escape(t):(/[\[\]():.#>~+*=^$|! \t\n\r]/.test(t)&&this.ctx.logger.warn(`[RangeDomApplier] CSS.escape unavailable; key "${t}" contains characters that need escaping. Lookup may miss the row.`),n=t.replace(/(["\\])/g,"\\$1"));for(let r of Fe){let i=e.querySelector(`[${r}="${n}"]`);if(i)return i}return null}indexOfChild(e,t){let n=0,r=e.firstElementChild;for(;r;){if(r===t)return n;n++,r=r.nextElementSibling}return-1}firstKnownKey(e){for(let t of e){if(!Array.isArray(t)||t.length<2)continue;let n=t[0];if(n==="r"||n==="u"||n==="i")return typeof t[1]=="string"?t[1]:void 0;if(n==="o"&&Array.isArray(t[1])&&t[1].length>0)return typeof t[1][0]=="string"?t[1][0]:void 0;if(n==="a"||n==="p"){let r=Array.isArray(t[1])?t[1]:[t[1]];for(let i of r)if(i&&typeof i=="object"&&i._k!==void 0)return String(i._k)}}}staticsContainKeyAttribute(e){for(let t of e)if(typeof t=="string"){for(let n of hn)if(n.test(t))return!0}return!1}itemHasNestedRange(e){if(!e||typeof e!="object")return!1;for(let[t,n]of Object.entries(e))if(!t.startsWith("_")&&n&&typeof n=="object"&&!Array.isArray(n)){let r=n;if(Array.isArray(r.d)&&Array.isArray(r.s)||this.itemHasNestedRange(r))return!0}return!1}extractItemKey(e,t){var r;if(!e||typeof e!="object")return;if(e._k!==void 0)return String(e._k);let n=(r=t==null?void 0:t.m)==null?void 0:r.idKey;if(n&&e[n]!==void 0)return String(e[n])}lookupCurrentItem(e,t){return this.ctx.itemLookup(e,t)}fireHookOnSubtree(e,t){e.hasAttribute(t)&&this.ctx.executeLifecycleHook(e,t),e.querySelectorAll(`[${t}]`).forEach(r=>this.ctx.executeLifecycleHook(r,t))}};var be=class{constructor(){this.activeForm=null;this.activeButton=null;this.originalButtonText=null}setActiveSubmission(e,t,n){if(this.activeForm=e,this.activeButton=t,this.originalButtonText=n,e){e.setAttribute("aria-busy","true");let r=e.querySelector("fieldset");r&&(r.disabled=!0)}}handleResponse(e){this.activeForm&&this.activeForm.dispatchEvent(new CustomEvent("lvt:done",{detail:e})),e.success?this.handleSuccess(e):this.handleError(e),this.restoreFormState()}reset(){this.restoreFormState()}handleSuccess(e){if(!this.activeForm)return;this.activeForm.dispatchEvent(new CustomEvent("lvt:success",{detail:e}));let t=this.activeForm.closest("dialog");t&&t.open&&t.close(),this.activeForm.hasAttribute("lvt-form:preserve")||this.activeForm.reset()}handleError(e){this.activeForm&&this.activeForm.dispatchEvent(new CustomEvent("lvt:error",{detail:e}))}restoreFormState(){if(this.activeForm){this.activeForm.removeAttribute("aria-busy");let e=this.activeForm.querySelector("fieldset");e&&(e.disabled=!1)}this.activeButton&&this.originalButtonText!==null&&(this.activeButton.disabled=!1,this.activeButton.textContent=this.originalButtonText),this.activeForm=null,this.activeButton=null,this.originalButtonText=null}};var Ee=class{constructor(e,t){this.context=e;this.logger=t;this.boundFields=new Map;this.enabled=!1;this.wiredElements=new Set;this.elementCleanups=new Map}setCapabilities(e){this.enabled=e.includes("change"),this.logger.debug("Capabilities received, change auto-wiring:",this.enabled?"enabled":"disabled")}analyzeStatics(e){let t=this.boundFields.size;this.walkTree(e),this.boundFields.size>t&&this.logger.debug(`Detected ${this.boundFields.size} bound field(s):`,Array.from(this.boundFields.keys()))}wireElements(){if(!this.enabled)return;let e=this.context.getWrapperElement();if(!e)return;for(let n of this.elementCleanups.keys())n.isConnected||(this.elementCleanups.get(n)(),this.elementCleanups.delete(n),this.wiredElements.delete(n));for(let[n,r]of this.boundFields){let i=this.escapeCSSSelector(n),a=e.querySelectorAll(`[name="${i}"]`);for(let o of a){if(this.wiredElements.has(o)||o.hasAttribute("lvt-input")||o.hasAttribute("lvt-change"))continue;let c=o.closest("form");c&&(c.hasAttribute("lvt-change")||Y(c,"lvt-form:no-intercept",this.logger))||o instanceof HTMLInputElement&&(o.type==="hidden"||o.type==="submit"||o.type==="button")||o instanceof HTMLButtonElement||(this.attachListener(o,n,r),this.wiredElements.add(o))}}let t=e.querySelectorAll("select[name]");for(let n of t){if(this.wiredElements.has(n)||n.hasAttribute("lvt-input")||n.hasAttribute("lvt-change"))continue;let r=n.closest("form");if(r&&(r.hasAttribute("lvt-change")||r.hasAttribute("lvt-form:no-intercept")))continue;let i=n.getAttribute("name");i&&(this.attachListener(n,i,"value"),this.wiredElements.add(n))}}teardown(){for(let e of this.elementCleanups.values())e();this.elementCleanups.clear(),this.wiredElements.clear(),this.boundFields.clear(),this.enabled=!1}getBoundFields(){return this.boundFields}isEnabled(){return this.enabled}walkTree(e){if(!(!e||typeof e!="object"||Array.isArray(e))){e.s&&Array.isArray(e.s)&&this.analyzeStaticsArray(e.s);for(let t of Object.keys(e))if(/^\d+$/.test(t)){let n=e[t];n&&typeof n=="object"&&!Array.isArray(n)&&this.walkTree(n)}if(e.d&&Array.isArray(e.d))for(let t of e.d)t&&typeof t=="object"&&!Array.isArray(t)&&this.walkTree(t)}}analyzeStaticsArray(e){for(let t=0;t<e.length-1;t++){let n=e[t],r=e[t+1],i=this.detectBinding(n,r);i&&!this.boundFields.has(i.fieldName)&&this.boundFields.set(i.fieldName,i.bindingType)}}detectBinding(e,t){let n=this.detectValueBinding(e);return n?{fieldName:n,bindingType:"value"}:(n=this.detectTextareaBinding(e,t),n?{fieldName:n,bindingType:"content"}:(n=this.detectAttributeBinding(e,t),n?{fieldName:n,bindingType:"attribute"}:null))}escapeCSSSelector(e){return typeof CSS!="undefined"&&typeof CSS.escape=="function"?CSS.escape(e):e.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}extractUnclosedTag(e){let t=e.lastIndexOf("<"),n=e.lastIndexOf(">");return t===-1||t<=n?null:e.substring(t)}extractNameFromTag(e){let t=e.match(/\sname="([^"]+)"/);return t?t[1]:null}detectValueBinding(e){if(!e.endsWith('value="'))return null;let t=this.extractUnclosedTag(e);return t?this.extractNameFromTag(t):null}detectTextareaBinding(e,t){if(!t.startsWith("</textarea"))return null;let n=e.match(/<textarea[^>]*\sname="([^"]+)"[^>]*>$/);return n?n[1]:null}detectAttributeBinding(e,t){if(!e.endsWith(" ")||!/^[a-zA-Z>/\s]/.test(t))return null;let n=this.extractUnclosedTag(e);if(!n||!/^<input\s/i.test(n))return null;let r=n.match(/\stype="([^"]+)"/i);if(!r)return null;let i=r[1].toLowerCase();return i!=="checkbox"&&i!=="radio"?null:this.extractNameFromTag(n)}attachListener(e,t,n){let r=e.getAttribute("lvt-debounce"),i=r?parseInt(r,10):NaN,a=Number.isNaN(i)||i<0?300:i,c=Z(()=>{if(!this.enabled)return;let d=n==="attribute"&&e.type==="checkbox"?e.checked:e.value;this.context.send({action:"change",data:{[t]:d}})},a),l=n==="attribute"||e instanceof HTMLSelectElement?"change":"input";e.addEventListener(l,c),this.elementCleanups.set(e,()=>{e.removeEventListener(l,c)}),this.logger.debug(`Auto-wired ${l} listener on [name="${t}"] (debounce: ${a}ms)`)}};var Ne=class{constructor(e){this.options=e;this.socket=null;this.reconnectTimer=null;this.manuallyClosed=!1;this.reconnectAttempts=0}connect(){this.manuallyClosed=!1,this.clearReconnectTimer(),this.socket=new WebSocket(this.options.url);let e=this.socket;e.onopen=()=>{var t,n;this.reconnectAttempts=0,(n=(t=this.options).onOpen)==null||n.call(t,e)},e.onmessage=t=>{var n,r;(r=(n=this.options).onMessage)==null||r.call(n,t)},e.onclose=t=>{var n,r;(r=(n=this.options).onClose)==null||r.call(n,t),!this.manuallyClosed&&this.options.autoReconnect&&this.scheduleReconnect()},e.onerror=t=>{var n,r;(r=(n=this.options).onError)==null||r.call(n,t)}}send(e){this.socket&&this.socket.readyState===WebSocket.OPEN&&this.socket.send(e)}disconnect(){var e,t;this.manuallyClosed=!0,this.clearReconnectTimer(),this.socket&&(this.socket.readyState!==WebSocket.CLOSED&&((t=(e=this.options).onClose)==null||t.call(e,new CloseEvent("close",{code:1e3,reason:"",wasClean:this.socket.readyState===WebSocket.OPEN}))),this.socket.onopen=null,this.socket.onmessage=null,this.socket.onclose=null,this.socket.onerror=null,this.socket.close(),this.socket=null)}getSocket(){return this.socket}scheduleReconnect(){var o,c,l,d,u;this.clearReconnectTimer();let e=(o=this.options.maxReconnectAttempts)!=null?o:10;if(e>0&&this.reconnectAttempts>=e){(l=(c=this.options).onReconnectFailed)==null||l.call(c);return}this.reconnectAttempts++;let t=(d=this.options.reconnectDelay)!=null?d:1e3,n=(u=this.options.maxReconnectDelay)!=null?u:16e3,r=t*Math.pow(2,this.reconnectAttempts-1),i=Math.random()*1e3,a=Math.min(r+i,n);this.reconnectTimer=window.setTimeout(()=>{var p,f;(f=(p=this.options).onReconnectAttempt)==null||f.call(p,this.reconnectAttempts,a),this.connect()},a)}clearReconnectTimer(){this.reconnectTimer!==null&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=null)}},we=class{constructor(e){this.config=e;this.transport=null;this.liveUrlOverride=null}setLiveUrl(e){this.liveUrlOverride=e}async connect(){var d;let e=this.getLiveUrl();if(!await vn(e,this.config.logger))return{usingWebSocket:!1,initialState:await kt(e,this.config.logger)};let n,r,i=new Promise((u,p)=>{n=u,r=p}),a=!1,o=!1,c=null,l=u=>{a||(a=!0,c!==null&&(clearTimeout(c),c=null),u?r(u):n({usingWebSocket:!0}))};c=setTimeout(()=>{l(new Error("WebSocket open timed out after 10s"))},1e4),this.transport=new Ne({url:this.getWebSocketUrl(),autoReconnect:this.config.options.autoReconnect,reconnectDelay:this.config.options.reconnectDelay,maxReconnectDelay:16e3,maxReconnectAttempts:10,onOpen:()=>{o=!0,this.config.onConnected(),l()},onMessage:u=>{try{let p=JSON.parse(u.data);this.config.onMessage(p,u)}catch(p){this.config.logger.error("Failed to parse WebSocket message:",p)}},onClose:()=>{o?this.config.onDisconnected():l(new Error("WebSocket closed before it opened"))},onReconnectAttempt:(u,p)=>{var f,g;(g=(f=this.config).onReconnectAttempt)==null||g.call(f,u,p)},onReconnectFailed:()=>{var u,p;(p=(u=this.config).onReconnectFailed)==null||p.call(u)},onError:u=>{var p,f;(f=(p=this.config).onError)==null||f.call(p,u),l(new Error("WebSocket errored before it opened"))}}),this.transport.connect();try{return await i}catch(u){return this.config.logger.warn("WebSocket open failed, falling back to HTTP",u),(d=this.transport)==null||d.disconnect(),this.transport=null,{usingWebSocket:!1,initialState:await kt(e,this.config.logger)}}}disconnect(){var e;(e=this.transport)==null||e.disconnect(),this.transport=null}send(e){var t;(t=this.transport)==null||t.send(e)}getReadyState(){var e,t;return(t=(e=this.transport)==null?void 0:e.getSocket())==null?void 0:t.readyState}getSocket(){var e,t;return(t=(e=this.transport)==null?void 0:e.getSocket())!=null?t:null}getWebSocketUrl(){let e=this.liveUrlOverride||this.config.options.liveUrl||"/live",t=this.config.options.wsUrl;return t||`${window.location.protocol==="https:"?"wss:":"ws:"}//${window.location.host}${e}`}getLiveUrl(){return this.liveUrlOverride||this.config.options.liveUrl||window.location.pathname+window.location.search}};async function vn(s,e){try{let n=(await fetch(s,{method:"HEAD"})).headers.get("X-LiveTemplate-WebSocket");return n?n==="enabled":!0}catch(t){return e==null||e.warn("Failed to check WebSocket availability:",t),!0}}async function kt(s,e){try{let t=await fetch(s,{method:"GET",credentials:"include",headers:{Accept:"application/json"}});if(!t.ok)throw new Error(`Failed to fetch initial state: ${t.status}`);return await t.json()}catch(t){return e==null||e.warn("Failed to fetch initial state:",t),null}}var Ae=class{async upload(e,t,n){let{file:r}=e;e.abortController=new AbortController;try{let i=new XMLHttpRequest;i.upload.addEventListener("progress",o=>{o.lengthComputable&&(e.bytesUploaded=o.loaded,e.progress=Math.round(o.loaded/o.total*100),n&&n(e))}),e.abortController.signal.addEventListener("abort",()=>{i.abort()});let a=new Promise((o,c)=>{i.addEventListener("load",()=>{i.status>=200&&i.status<300?(e.done=!0,e.progress=100,o()):c(new Error(`S3 upload failed with status ${i.status}: ${i.statusText}`))}),i.addEventListener("error",()=>{c(new Error("S3 upload failed: Network error"))}),i.addEventListener("abort",()=>{c(new Error("S3 upload cancelled"))})});if(i.open("PUT",t.url),t.headers)for(let[o,c]of Object.entries(t.headers))i.setRequestHeader(o,c);i.send(r),await a}catch(i){throw e.error=i instanceof Error?i.message:String(i),i}}};var Te=class{constructor(e,t={}){this.sendMessage=e;this.entries=new Map;this.pendingFiles=new Map;this.autoUploadConfig=new Map;this.uploaders=new Map;this.inputHandlers=new WeakMap;this.chunkSize=t.chunkSize||256*1024,this.onProgress=t.onProgress,this.onComplete=t.onComplete,this.onError=t.onError,this.uploaders.set("s3",new Ae)}initializeFileInputs(e){e.querySelectorAll('input[type="file"][lvt-upload]').forEach(n=>{let r=n.getAttribute("lvt-upload");if(!r)return;let i=this.inputHandlers.get(n);i&&n.removeEventListener("change",i);let a=o=>{let c=o.target.files;!c||c.length===0||this.startUpload(r,Array.from(c))};n.addEventListener("change",a),this.inputHandlers.set(n,a)})}async startUpload(e,t){this.pendingFiles.set(e,t);let n=t.map(i=>({name:i.name,type:i.type||"application/octet-stream",size:i.size})),r={action:"upload_start",upload_name:e,files:n};this.sendMessage(r)}async handleUploadStartResponse(e){let{upload_name:t,entries:n}=e;n.length>0&&this.autoUploadConfig.set(t,n[0].auto_upload);let r=this.pendingFiles.get(t);if(!r){console.error(`No pending files found for upload: ${t}`);return}this.pendingFiles.delete(t);let i=new Map;for(let o of r)i.set(o.name,o);let a=[];for(let o of n){let c=i.get(o.client_name);if(!c){console.warn(`No file found for entry ${o.entry_id} (client_name: ${o.client_name})`);continue}let l={id:o.entry_id,file:c,uploadName:t,progress:0,bytesUploaded:0,valid:o.valid,done:!1,error:o.error,external:o.external};if(this.entries.set(l.id,l),a.push(l),!o.valid){this.onError&&o.error&&this.onError(l,o.error);continue}o.auto_upload&&(o.external?this.uploadExternal(l,o.external):this.uploadChunked(l))}}async uploadExternal(e,t){try{let n=this.uploaders.get(t.uploader);if(!n)throw new Error(`Unknown uploader: ${t.uploader}`);await n.upload(e,t,this.onProgress);let r={action:"upload_complete",upload_name:e.uploadName,entry_ids:[e.id]};this.sendMessage(r),this.onComplete&&this.onComplete(e.uploadName,[e]),this.clearFileInput(e.uploadName),this.cleanupEntries(e.uploadName)}catch(n){let r=n instanceof Error?n.message:String(n);e.error=r,this.onError&&this.onError(e,r),this.cleanupEntries(e.uploadName)}}async uploadChunked(e){let{file:t,id:n}=e,r=0;e.abortController=new AbortController;try{for(;r<t.size;){if(e.abortController.signal.aborted)throw new Error("Upload cancelled");let a=Math.min(r+this.chunkSize,t.size),o=t.slice(r,a),c=await this.fileToBase64(o),l={action:"upload_chunk",entry_id:n,chunk_base64:c,offset:r,total:t.size};this.sendMessage(l),r=a,e.bytesUploaded=r,e.progress=Math.round(r/t.size*100),this.onProgress&&this.onProgress(e)}e.done=!0;let i={action:"upload_complete",upload_name:e.uploadName,entry_ids:[n]};this.sendMessage(i),this.onComplete&&this.onComplete(e.uploadName,[e]),this.clearFileInput(e.uploadName),this.cleanupEntries(e.uploadName)}catch(i){let a=i instanceof Error?i.message:String(i);e.error=a,this.onError&&this.onError(e,a),this.cleanupEntries(e.uploadName)}}handleProgressMessage(e){let t=this.entries.get(e.entry_id);t&&(t.progress=e.progress,t.bytesUploaded=e.bytes_recv,this.onProgress&&this.onProgress(t))}cancelUpload(e){let t=this.entries.get(e);t&&(t.abortController&&t.abortController.abort(),this.sendMessage({action:"cancel_upload",entry_id:e}),this.entries.delete(e))}getEntries(e){let t=[];for(let n of this.entries.values())n.uploadName===e&&t.push(n);return t}triggerPendingUploads(e){let t=[];for(let n of this.entries.values())n.uploadName===e&&n.progress===0&&!n.done&&!n.error&&t.push(n);for(let n of t)n.external?this.uploadExternal(n,n.external):this.uploadChunked(n)}registerUploader(e,t){this.uploaders.set(e,t)}clearFileInput(e){document.querySelectorAll(`input[type="file"][lvt-upload="${e}"]`).forEach(n=>{n.value=""})}cleanupEntries(e,t=5e3){setTimeout(()=>{let n=[];for(let[r,i]of this.entries)e&&i.uploadName!==e||(i.done||i.error)&&n.push(r);for(let r of n)this.entries.delete(r)},t)}fileToBase64(e){return new Promise((t,n)=>{let r=new FileReader;r.onload=()=>{let a=r.result.split(",")[1];t(a)},r.onerror=n,r.readAsDataURL(e)})}};var Mt={silent:0,error:1,warn:2,info:3,debug:4},xt="LiveTemplate",Ue=class s{constructor(e,t=[],n=console){this.state=e;this.scope=t;this.sink=n}setLevel(e){this.state.level=e}getLevel(){return this.state.level}child(e){return new s(this.state,[...this.scope,e],this.sink)}isDebugEnabled(){return this.shouldLog("debug")}error(...e){this.log("error","error",e)}warn(...e){this.log("warn","warn",e)}info(...e){this.log("info","info",e)}debug(...e){this.log("debug","debug",e)}log(e,t,n){if(!this.shouldLog(e))return;(this.sink[t]||console[t]||console.log).apply(this.sink,[this.formatPrefix(),...n])}shouldLog(e){return Mt[e]<=Mt[this.state.level]}formatPrefix(){return this.scope.length===0?`[${xt}]`:`[${xt}:${this.scope.join(":")}]`}};function $e(s={}){var n,r;let e={level:(n=s.level)!=null?n:"info"},t=Array.isArray(s.scope)?s.scope:s.scope?[s.scope]:[];return new Ue(e,t,(r=s.sink)!=null?r:console)}async function Ct(s,e){try{let t=globalThis==null?void 0:globalThis.require;if(typeof t=="function"){let i=t("fs"),a=JSON.parse(i.readFileSync(e,"utf8"));return s.applyUpdate(a)}let r=await(await fetch(e)).json();return s.applyUpdate(r)}catch(t){throw new Error(`Failed to load update from ${e}: ${t}`)}}function Ht(s,e){let t=[],n=l=>l.replace(/\s+/g," ").replace(/>\s+</g,"><").trim(),r=n(s),i=n(e);if(r===i)return{match:!0,differences:[]};let a=r.split(`
|
|
30
30
|
`),o=i.split(`
|
|
31
|
-
`),c=Math.max(a.length,o.length);for(let l=0;l<c;l++){let d=a[l]||"",u=o[l]||"";d!==u&&(t.push(`Line ${l+1}:`),t.push(` Expected: ${d}`),t.push(` Actual: ${u}`))}return{match:!1,differences:t}}var Se=class s{constructor(e={}){this.nodesAddedThisRender=0;this.directiveTouchedThisRender=!1;this.lvtId=null;this.ws=null;this.wrapperElement=null;this.useHTTP=!1;this.sessionCookie=null;this.rateLimitedHandlers=new WeakMap;this.isInitialized=!1;this.messageCount=0;this.navigationEpoch=0;this.liveUrlOverride=null;this.visibilityHandlerAttached=!1;this.hiddenAt=0;this.reconnecting=!1;this.visibilityHandler=null;this.pageshowHandler=null;this.visibilityReconnectTimer=null;let{logger:t,logLevel:n,debug:r,...i}=e,a=n!=null?n:r?"debug":"info",o=t!=null?t:$e({level:a});t?n?t.setLevel(n):r&&t.setLevel("debug"):o.setLevel(a),this.logger=o.child("Client"),this.options={autoReconnect:!1,reconnectDelay:1e3,liveUrl:window.location.pathname+window.location.search,...i},this.treeRenderer=new ve(this.logger.child("TreeRenderer")),this.rangeDomApplier=new ye({logger:this.logger.child("RangeDomApplier"),renderItem:(c,l,d,u)=>this.treeRenderer.renderRangeItem(c,l,d,u),executeLifecycleHook:(c,l)=>this.executeLifecycleHook(c,l),itemLookup:(c,l)=>{var p;let d=this.treeRenderer.getTreeState()[c];if(!d||!Array.isArray(d.d))return null;let u=(p=d.m)==null?void 0:p.idKey;for(let f of d.d)if(!(!f||typeof f!="object")&&(f._k===l||u&&f[u]!==void 0&&String(f[u])===l))return f;return null},onNodeAdded:()=>{this.nodesAddedThisRender++}}),this.focusManager=new oe(this.logger.child("FocusManager")),this.formLifecycleManager=new be,this.loadingIndicator=new he,this.formDisabler=new me,this.uploadHandler=new Te(c=>this.send(c),{chunkSize:256*1024,onProgress:c=>{this.wrapperElement&&this.wrapperElement.dispatchEvent(new CustomEvent("lvt:upload:progress",{detail:{entry:c}}))},onComplete:(c,l)=>{this.logger.info(`Upload complete: ${c}`,l),this.wrapperElement&&this.wrapperElement.dispatchEvent(new CustomEvent("lvt:upload:complete",{detail:{uploadName:c,entries:l}}))},onError:(c,l)=>{this.logger.error(`Upload error for ${c.id}:`,l),this.wrapperElement&&this.wrapperElement.dispatchEvent(new CustomEvent("lvt:upload:error",{detail:{entry:c,error:l}}))}}),this.eventDelegator=new ue({getWrapperElement:()=>this.wrapperElement,getRateLimitedHandlers:()=>this.rateLimitedHandlers,parseValue:c=>this.parseValue(c),send:c=>this.send(c),sendHTTPMultipart:(c,l,d)=>this.sendHTTPMultipart(c,l,d),setActiveSubmission:(c,l,d)=>this.formLifecycleManager.setActiveSubmission(c,l,d),getWebSocketReadyState:()=>this.webSocketManager.getReadyState(),triggerPendingUploads:c=>this.uploadHandler.triggerPendingUploads(c)},this.logger.child("EventDelegator")),this.linkInterceptor=new fe({getWrapperElement:()=>this.wrapperElement,handleNavigationResponse:(c,l)=>this.handleNavigationResponse(c,l),sendNavigate:c=>this.sendNavigate(c),canSendNavigate:()=>!this.useHTTP&&this.webSocketManager.getReadyState()===1},this.logger.child("LinkInterceptor")),this.observerManager=new ge({getWrapperElement:()=>this.wrapperElement,send:c=>this.send(c)},this.logger.child("ObserverManager")),this.changeAutoWirer=new Ee({getWrapperElement:()=>this.wrapperElement,send:c=>this.send(c)},this.logger.child("ChangeAutoWirer")),this.webSocketManager=new we({options:this.options,logger:this.logger.child("Transport"),onConnected:()=>{var c,l,d;this.ws=this.webSocketManager.getSocket(),this.logger.info("WebSocket connected"),this.clearFlashQueryParams(),(l=(c=this.options).onConnect)==null||l.call(c),(d=this.wrapperElement)==null||d.dispatchEvent(new Event("lvt:connected"))},onDisconnected:()=>{var c,l,d;this.ws=null,this.logger.info("WebSocket disconnected"),(l=(c=this.options).onDisconnect)==null||l.call(c),(d=this.wrapperElement)==null||d.dispatchEvent(new Event("lvt:disconnected"))},onMessage:(c,l)=>{this.handleWebSocketPayload(c,l)},onReconnectAttempt:()=>{this.logger.info("Attempting to reconnect...")},onError:c=>{var l,d;this.logger.error("WebSocket error:",c),(d=(l=this.options).onError)==null||d.call(l,c)}})}static autoInit(){let e=$e({scope:"Client:autoInit"}),t=()=>{let n=document.querySelector("[data-lvt-id]");if(n){let r=new s;r.wrapperElement=n,n.getAttribute("data-lvt-loading")==="true"&&(r.loadingIndicator.show(),r.formDisabler.disable(r.wrapperElement)),r.connect().catch(a=>{e.error("Auto-initialization connect failed:",a)}),window.liveTemplateClient=r}};document.readyState==="loading"?document.addEventListener("DOMContentLoaded",t):t()}handleWebSocketPayload(e,t){var r,i,a;let n=e;if(n.type==="upload_progress"){this.uploadHandler.handleProgressMessage(n);return}if(n.upload_name&&n.entries){let o=n;try{this.handleUploadStartResponse(o)}catch(c){this.logger.error("Error handling upload start response:",c)}return}if(n.upload_name&&n.hasOwnProperty("success")){n.success?this.logger.info(`Upload complete: ${n.upload_name}`):this.logger.error(`Upload failed: ${n.upload_name}`,n.error);return}this.isInitialized||(this.loadingIndicator.hide(),this.formDisabler.enable(this.wrapperElement),this.wrapperElement&&this.wrapperElement.hasAttribute("data-lvt-loading")&&this.wrapperElement.removeAttribute("data-lvt-loading"),this.isInitialized=!0,_e()),this.wrapperElement&&((r=e.meta)!=null&&r.capabilities&&this.changeAutoWirer.setCapabilities(e.meta.capabilities),this.changeAutoWirer.analyzeStatics(e.tree),this.updateDOM(this.wrapperElement,e.tree,e.meta),this.messageCount++,this.wrapperElement.dispatchEvent(new CustomEvent("lvt:updated",{detail:{messageCount:this.messageCount,action:(i=e.meta)==null?void 0:i.action,success:(a=e.meta)==null?void 0:a.success}})))}async connect(e="[data-lvt-id]"){var n,r;if(this.wrapperElement=document.querySelector(e),!this.wrapperElement)throw new Error(`LiveTemplate wrapper not found with selector: ${e}`);this.webSocketManager.disconnect();let t=await this.webSocketManager.connect();this.useHTTP=!t.usingWebSocket,this.useHTTP&&(this.ws=null,this.logger.info("WebSocket not available, using HTTP mode"),(r=(n=this.options).onConnect)==null||r.call(n),t.initialState&&this.wrapperElement&&this.handleWebSocketPayload(t.initialState)),this.eventDelegator.setupEventDelegation(),this.eventDelegator.setupWindowEventDelegation(),this.eventDelegator.setupClickAwayDelegation(),this.eventDelegator.setupDOMEventTriggerDelegation(),at(),this.eventDelegator.setupFocusTrapDelegation(),this.eventDelegator.setupAutofocusDelegation(),this.linkInterceptor.setup(this.wrapperElement),de(),wt(),yt(),tt(this.wrapperElement),this.focusManager.attach(this.wrapperElement),this.observerManager.setupInfiniteScrollObserver(),this.observerManager.setupInfiniteScrollMutationObserver(),this.setupVisibilityReconnect()}disconnect(){this.webSocketManager.disconnect(),this.ws=null,this.useHTTP=!1,this.hiddenAt=0,this.reconnecting=!1,this.teardownVisibilityReconnect(),this.eventDelegator.teardownDOMEventTriggerDelegation(),bt(),this.wrapperElement&&(et(this.wrapperElement),nt(this.wrapperElement),St(this.wrapperElement)),this.resetSessionState()}resetSessionState(){this.treeRenderer.reset(),this.rangeDomApplier.invalidate(),this.focusManager.reset(),this.observerManager.teardown(),this.changeAutoWirer.teardown(),this.formLifecycleManager.reset(),this.loadingIndicator.hide(),this.formDisabler.enable(this.wrapperElement),this.lvtId=null,this.isInitialized=!1}setupVisibilityReconnect(){this.visibilityHandlerAttached||typeof document=="undefined"||(this.visibilityHandlerAttached=!0,this.visibilityHandler=()=>{if(document.hidden){!this.useHTTP&&this.webSocketManager.getReadyState()===1&&(this.hiddenAt=Date.now());return}if(this.hiddenAt===0)return;let e=Date.now()-this.hiddenAt;this.hiddenAt=0,!(e<3e3)&&this.scheduleVisibilityReconnect()},this.pageshowHandler=e=>{e.persisted&&this.scheduleVisibilityReconnect()},document.addEventListener("visibilitychange",this.visibilityHandler),window.addEventListener("pageshow",this.pageshowHandler))}teardownVisibilityReconnect(){this.visibilityReconnectTimer!==null&&(clearTimeout(this.visibilityReconnectTimer),this.visibilityReconnectTimer=null),!(!this.visibilityHandlerAttached||typeof document=="undefined")&&(this.visibilityHandler&&(document.removeEventListener("visibilitychange",this.visibilityHandler),this.visibilityHandler=null),this.pageshowHandler&&(window.removeEventListener("pageshow",this.pageshowHandler),this.pageshowHandler=null),this.visibilityHandlerAttached=!1)}scheduleVisibilityReconnect(){this.visibilityReconnectTimer!==null&&clearTimeout(this.visibilityReconnectTimer),this.visibilityReconnectTimer=setTimeout(()=>{this.visibilityReconnectTimer=null,this.wrapperElement&&!this.useHTTP&&!this.reconnecting&&this.webSocketManager.getReadyState()!==void 0&&this.performVisibilityReconnect()},500)}async performVisibilityReconnect(){var e;if(!this.reconnecting){this.reconnecting=!0;try{this.logger.info("Reconnecting after visibility change"),this.webSocketManager.disconnect(),this.ws=null,this.resetSessionState();let t=await this.webSocketManager.connect();if(!this.reconnecting)return;this.useHTTP=!t.usingWebSocket,this.useHTTP&&(this.ws=null,t.initialState&&this.wrapperElement&&this.handleWebSocketPayload(t.initialState)),(e=this.wrapperElement)==null||e.dispatchEvent(new Event("lvt:reconnected"))}catch(t){this.logger.error("Visibility reconnect failed:",t)}finally{this.reconnecting=!1}}}clearFlashQueryParams(){let e=new URL(window.location.href),t=["error","success"],n=!1;for(let r of t)e.searchParams.has(r)&&(e.searchParams.delete(r),n=!0);n&&(this.logger.debug("Clearing flash query params from URL"),window.history.replaceState(null,"",e.toString()))}isReady(){let e=this.wrapperElement;return!e||e.hasAttribute("data-lvt-loading")?!1:this.useHTTP?!0:this.webSocketManager.getReadyState()===1}send(e){let t=this.webSocketManager.getReadyState();this.logger.isDebugEnabled()&&this.logger.debug("send() invoked",{message:e,useHTTP:this.useHTTP,hasWebSocket:t!==void 0,readyState:t}),this.useHTTP?(this.logger.debug("Using HTTP mode for send"),this.sendHTTP(e)):t===1?(this.logger.debug("Sending via WebSocket"),this.webSocketManager.send(JSON.stringify(e))):t!==void 0?(this.logger.warn(`WebSocket not ready (state: ${t}), using HTTP fallback`),this.sendHTTP(e)):this.logger.error("No transport available")}getLiveUrl(){return this.liveUrlOverride||this.options.liveUrl||"/live"}sendNavigate(e){let t=new URL(e,window.location.origin),n={},r=new Set;t.searchParams.forEach((a,o)=>{r.has(o)&&this.logger.warn("sendNavigate: duplicate query param key \u2014 last value wins; server may receive incomplete data",{key:o,href:e}),r.add(o),n[o]=a});let i=t.pathname+t.search;if(this.webSocketManager.getReadyState()!==1){let a=this.webSocketManager.getReadyState();return a===3?this.logger.error("sendNavigate: WebSocket is CLOSED and autoReconnect may be disabled; navigate message dropped. Reload or re-enable autoReconnect.",{href:e}):this.options.autoReconnect?this.logger.warn("sendNavigate: WS not open; browser URL is ahead of server state until reconnect",{href:e,readyState:a}):this.logger.error("sendNavigate: WS not open and autoReconnect is disabled; navigate may be permanently lost",{href:e,readyState:a}),!1}return this.liveUrlOverride=i,this.webSocketManager.setLiveUrl(i),this.logger.debug("sendNavigate",{href:e,data:n}),this.send({action:"__navigate__",data:n}),!0}async sendHTTP(e){try{let t=this.getLiveUrl(),n=await fetch(t,{method:"POST",credentials:"include",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify(e)});if(!n.ok)throw new Error(`HTTP request failed: ${n.status}`);let r=await n.json();this.wrapperElement&&this.updateDOM(this.wrapperElement,r.tree,r.meta)}catch(t){this.logger.error("Failed to send HTTP request:",t)}}sendHTTPMultipart(e,t,n){this.doSendHTTPMultipart(e,t,n)}async doSendHTTPMultipart(e,t,n){try{let r=this.getLiveUrl(),i=await fetch(r,{method:"POST",credentials:"include",headers:{Accept:"application/json"},body:n});if(!i.ok)throw new Error(`HTTP multipart request failed: ${i.status}`);let a=await i.json();this.wrapperElement&&this.updateDOM(this.wrapperElement,a.tree,a.meta)}catch(r){this.logger.error("Failed to send HTTP multipart request:",r)}}stylesheetsDiffer(e,t){let n=document.querySelectorAll('link[rel~="stylesheet"][href]'),r=new Set;n.forEach(c=>{let l=c.href;l&&r.add(l)});let i=e.querySelectorAll('link[rel~="stylesheet"][href]'),a=new Set;if(i.forEach(c=>{let l=c.getAttribute("href");if(l)try{a.add(new URL(l,t).href)}catch(d){a.add(l)}}),r.size!==a.size)return!0;let o=!1;return r.forEach(c=>{a.has(c)||(o=!0)}),o}performFullNavigation(e){window.location.href=e}handleNavigationResponse(e,t){var l;if(!this.wrapperElement)return;let r=new DOMParser().parseFromString(e,"text/html"),i=this.wrapperElement.getAttribute("data-lvt-id"),a=(l=r.querySelector("title"))==null?void 0:l.textContent;a&&(document.title=a);let o=r.querySelector("[data-lvt-id]");if(o){let d=o.getAttribute("data-lvt-id");if(!d){this.logger.warn("Cross-handler navigation: new wrapper has empty data-lvt-id"),window.location.reload();return}if(this.stylesheetsDiffer(r,t)){this.logger.info('Cross-app navigation detected (different <link rel="stylesheet"> set in fetched HTML); falling back to full navigation'),this.performFullNavigation(t);return}this.linkInterceptor.teardownForWrapper(i),this.eventDelegator.teardownForWrapper(i);let u=++this.navigationEpoch;this.disconnect(),this.wrapperElement.setAttribute("data-lvt-id",d),this.wrapperElement.replaceChildren(...Array.from(o.childNodes).map(f=>f.cloneNode(!0))),this.eventDelegator.setupEventDelegation(),this.linkInterceptor.setup(this.wrapperElement),window.scrollTo(0,0);let p=window.location.pathname+window.location.search;if(this.liveUrlOverride=p,this.webSocketManager.setLiveUrl(p),!this.useHTTP){let g=`[data-lvt-id="${d.replace(/[\\"]/g,"\\$&")}"]`;this.connect(g).catch(H=>{u===this.navigationEpoch&&(this.logger.error("Cross-handler reconnect failed:",H),window.location.reload())})}return}this.linkInterceptor.teardownForWrapper(i),this.eventDelegator.teardownForWrapper(i),this.disconnect();let c=r.querySelector("body");c&&this.wrapperElement.replaceChildren(...Array.from(c.childNodes).map(d=>d.cloneNode(!0))),this.eventDelegator.setupEventDelegation(),this.linkInterceptor.setup(this.wrapperElement)}parseValue(e){let t=e.trim(),n=parseFloat(t);if(!isNaN(n)){if(Number.isInteger(n)&&Math.abs(n)>Number.MAX_SAFE_INTEGER)return t;if(t===n.toString())return n}return e==="true"?!0:e==="false"?!1:e}applyUpdate(e){return this.treeRenderer.applyUpdate(e)}applyUpdateToHTML(e,t){let n=this.applyUpdate(t);if(!this.lvtId){let l=e.match(/data-lvt-id="([^"]+)"/);l&&(this.lvtId=l[1])}let r=n.html;if(!e.match(/<body>([\s\S]*?)<\/body>/))return e;let c=`<div data-lvt-id="${this.lvtId||"lvt-unknown"}">`+r+"</div>";return e.replace(/<body>[\s\S]*?<\/body>/,`<body>${c}</body>`)}updateDOM(e,t,n){this.nodesAddedThisRender=0,this.directiveTouchedThisRender=!1;let r=this.treeRenderer.applyUpdate(t,{canApplyTargeted:(l,d)=>this.rangeDomApplier.canApplyTargeted(e,l,d).ok}),i=l=>!l||typeof l!="object"?!1:l.s&&Array.isArray(l.s)?!0:Object.values(l).some(d=>i(d));if(!r.changed&&!i(t))return;let a=document.createElement(e.tagName);if(this.logger.isDebugEnabled()&&(this.logger.debug("[updateDOM] element.tagName:",e.tagName),this.logger.debug("[updateDOM] result.html (first 500 chars):",r.html.substring(0,500)),this.logger.debug("[updateDOM] Has <table> tag:",r.html.includes("<table>")),this.logger.debug("[updateDOM] Has <tbody> tag:",r.html.includes("<tbody>")),this.logger.debug("[updateDOM] Has <tr> tag:",r.html.includes("<tr"))),/<script[\s>]/i.test(r.html)){let l=e.tagName.toLowerCase(),d=l==="body"||l==="html"?"div":l,p=new DOMParser().parseFromString(`<${d}>${r.html}</${d}>`,"text/html"),f=p.body.firstElementChild;f?a.replaceChildren(...Array.from(f.childNodes)):(this.logger.warn("[updateDOM] DOMParser: no wrapper root element; using doc.body children"),a.replaceChildren(...Array.from(p.body.childNodes)))}else a.innerHTML=r.html;this.logger.isDebugEnabled()&&(this.logger.debug("[updateDOM] tempWrapper.innerHTML (first 500 chars):",a.innerHTML.substring(0,500)),this.logger.debug("[updateDOM] tempWrapper has <table>:",a.innerHTML.includes("<table>")),this.logger.debug("[updateDOM] tempWrapper has <tbody>:",a.innerHTML.includes("<tbody>")),this.logger.debug("[updateDOM] tempWrapper has <tr>:",a.innerHTML.includes("<tr")));let o=document.activeElement;if(o instanceof HTMLInputElement&&o.list instanceof HTMLDataListElement&&!a.querySelector("[data-lvt-force-update]")){this.logger.debug("[updateDOM] deferred: datalist input focused"),this.focusManager.restoreFocusedElement();return}let c={childrenOnly:!0,getNodeKey:l=>{if(l.nodeType===1)return l.getAttribute("data-key")||l.getAttribute("data-lvt-key")||void 0},onBeforeElUpdated:(l,d)=>{if(d.nodeType===Node.ELEMENT_NODE&&d.hasAttribute(q))return!1;if(d.nodeType===Node.ELEMENT_NODE&&l.nodeType===Node.ELEMENT_NODE){let u=d.attributes,p=l;for(let f=0;f<u.length;f++){let g=u[f].name;if(g.length>4&&g.charCodeAt(0)===108&&g.charCodeAt(1)===118&&g.charCodeAt(2)===116&&g.charCodeAt(3)===45&&!p.hasAttribute(g)){this.directiveTouchedThisRender=!0;break}}}if(l.nodeType===Node.ELEMENT_NODE&&l.hasAttribute("lvt-ignore")&&!d.hasAttribute("data-lvt-force-update"))return!1;if(l.nodeType===Node.ELEMENT_NODE&&l.hasAttribute("lvt-ignore-attrs")&&!d.hasAttribute("data-lvt-force-update")&&d.nodeType===Node.ELEMENT_NODE){let u=l.attributes,p=d;for(let f=0;f<u.length;f++){let g=u[f];p.hasAttributeNS(g.namespaceURI,g.localName)||p.setAttributeNS(g.namespaceURI,g.name,g.value)}}if(l instanceof HTMLDataListElement&&!d.hasAttribute("data-lvt-force-update")){let u=document.activeElement;if(u instanceof HTMLInputElement&&u.list===l)return!1}return l instanceof HTMLDialogElement&&l.hasAttribute("open")&&!d.hasAttribute("data-lvt-force-update")&&d.setAttribute("open",""),!d.hasAttribute("data-lvt-force-update")&&l instanceof HTMLElement&&l.hasAttribute("popover")&&Oe(l)||(l instanceof HTMLInputElement&&d instanceof HTMLInputElement&&(l.type==="checkbox"||l.type==="radio")&&(d.hasAttribute("data-lvt-force-update")?(l.checked=d.checked,l.type==="checkbox"&&(l.indeterminate=d.indeterminate),l.removeAttribute("data-lvt-force-update")):(d.checked=l.checked,l.checked?d.setAttribute("checked",""):d.removeAttribute("checked"),l.type==="checkbox"&&(d.indeterminate=l.indeterminate))),this.focusManager.shouldSkipUpdate(l))?!1:l.isEqualNode(d)?!(!d.hasAttribute("data-lvt-force-update")&&(d.children.length===0||d.querySelector("[data-lvt-force-update]")===null)):(this.executeLifecycleHook(l,"lvt-updated"),!0)},onElUpdated:l=>{var d;l instanceof HTMLTextAreaElement&&(l.value=(d=l.textContent)!=null?d:""),l instanceof HTMLElement&&l.hasAttribute("data-lvt-force-update")&&l.removeAttribute("data-lvt-force-update")},onNodeAdded:l=>{var d;l instanceof HTMLTextAreaElement&&(l.value=(d=l.textContent)!=null?d:""),l instanceof HTMLElement&&l.hasAttribute("data-lvt-force-update")&&l.removeAttribute("data-lvt-force-update"),l.nodeType===Node.ELEMENT_NODE&&(this.executeLifecycleHook(l,"lvt-mounted"),this.nodesAddedThisRender++)},onBeforeNodeDiscarded:l=>(l.nodeType===Node.ELEMENT_NODE&&this.executeLifecycleHook(l,"lvt-destroyed"),!0)};if(r.targetedOps&&r.targetedOps.length>0){let l=[],d=!1;for(let u of r.targetedOps){let p=this.rangeDomApplier.apply(e,u,c);p?(p.setAttribute(j,""),l.push(p)):d=!0}if(d){this.logger.warn("[updateDOM] one or more targeted DOM ops failed; rebuilding tempWrapper from treeState for a full morphdom sync");for(let p of l)p.removeAttribute(j);let u=this.treeRenderer.renderState();a.innerHTML=u}else this.replaceTargetedSkipPlaceholders(a)}try{se(e,a,c)}finally{this.rangeDomApplier.cleanupMarkers(e)}this.focusManager.restoreFocusedElement(),rt(e),it(e),st(e),ot(e),Tt(e),(this.nodesAddedThisRender>0||this.directiveTouchedThisRender)&&(Ze(e,this.wrapperElement||void 0),this.eventDelegator.setupDOMEventTriggerDelegation(e),this.uploadHandler.initializeFileInputs(e)),this.changeAutoWirer.wireElements(),n&&this.formLifecycleManager.handleResponse(n)}handleUploadStartResponse(e){this.uploadHandler.handleUploadStartResponse(e)}replaceTargetedSkipPlaceholders(e){let t=document.createTreeWalker(e,NodeFilter.SHOW_COMMENT),n=[],r;for(;r=t.nextNode();){let i=r;i.nodeValue&&/^lvt-targeted-skip:.+$/.test(i.nodeValue)&&n.push(i)}for(let i of n){let a=i.nodeValue.match(/^lvt-targeted-skip:(.+)$/),o=a?a[1]:"",c=i.parentElement;c&&c.setAttribute(q,o),i.remove()}}executeLifecycleHook(e,t){let n=e.getAttribute(t);if(n)try{new Function("element",n).call(e,e)}catch(r){this.logger.error(`Error executing ${t} hook:`,r)}}reset(){this.resetSessionState()}getTreeState(){return this.treeRenderer.getTreeState()}getStaticStructure(){return this.treeRenderer.getStaticStructure()}};typeof window!="undefined"&&Se.autoInit();return Ft(yn);})();
|
|
31
|
+
`),c=Math.max(a.length,o.length);for(let l=0;l<c;l++){let d=a[l]||"",u=o[l]||"";d!==u&&(t.push(`Line ${l+1}:`),t.push(` Expected: ${d}`),t.push(` Actual: ${u}`))}return{match:!1,differences:t}}var Se=class s{constructor(e={}){this.nodesAddedThisRender=0;this.directiveTouchedThisRender=!1;this.lvtId=null;this.ws=null;this.wrapperElement=null;this.useHTTP=!1;this.sessionCookie=null;this.rateLimitedHandlers=new WeakMap;this.isInitialized=!1;this.messageCount=0;this.navigationEpoch=0;this.liveUrlOverride=null;this.visibilityHandlerAttached=!1;this.hiddenAt=0;this.reconnecting=!1;this.visibilityHandler=null;this.pageshowHandler=null;this.visibilityReconnectTimer=null;let{logger:t,logLevel:n,debug:r,...i}=e,a=n!=null?n:r?"debug":"info",o=t!=null?t:$e({level:a});t?n?t.setLevel(n):r&&t.setLevel("debug"):o.setLevel(a),this.logger=o.child("Client"),this.options={autoReconnect:!1,reconnectDelay:1e3,liveUrl:window.location.pathname+window.location.search,...i},this.treeRenderer=new ve(this.logger.child("TreeRenderer")),this.rangeDomApplier=new ye({logger:this.logger.child("RangeDomApplier"),renderItem:(c,l,d,u)=>this.treeRenderer.renderRangeItem(c,l,d,u),executeLifecycleHook:(c,l)=>this.executeLifecycleHook(c,l),itemLookup:(c,l)=>{var p;let d=this.treeRenderer.getTreeState()[c];if(!d||!Array.isArray(d.d))return null;let u=(p=d.m)==null?void 0:p.idKey;for(let f of d.d)if(!(!f||typeof f!="object")&&(f._k===l||u&&f[u]!==void 0&&String(f[u])===l))return f;return null},onNodeAdded:()=>{this.nodesAddedThisRender++}}),this.focusManager=new oe(this.logger.child("FocusManager")),this.formLifecycleManager=new be,this.loadingIndicator=new he,this.formDisabler=new me,this.uploadHandler=new Te(c=>this.send(c),{chunkSize:256*1024,onProgress:c=>{this.wrapperElement&&this.wrapperElement.dispatchEvent(new CustomEvent("lvt:upload:progress",{detail:{entry:c}}))},onComplete:(c,l)=>{this.logger.info(`Upload complete: ${c}`,l),this.wrapperElement&&this.wrapperElement.dispatchEvent(new CustomEvent("lvt:upload:complete",{detail:{uploadName:c,entries:l}}))},onError:(c,l)=>{this.logger.error(`Upload error for ${c.id}:`,l),this.wrapperElement&&this.wrapperElement.dispatchEvent(new CustomEvent("lvt:upload:error",{detail:{entry:c,error:l}}))}}),this.eventDelegator=new ue({getWrapperElement:()=>this.wrapperElement,getRateLimitedHandlers:()=>this.rateLimitedHandlers,parseValue:c=>this.parseValue(c),send:c=>this.send(c),sendHTTPMultipart:(c,l,d)=>this.sendHTTPMultipart(c,l,d),setActiveSubmission:(c,l,d)=>this.formLifecycleManager.setActiveSubmission(c,l,d),getWebSocketReadyState:()=>this.webSocketManager.getReadyState(),triggerPendingUploads:c=>this.uploadHandler.triggerPendingUploads(c)},this.logger.child("EventDelegator")),this.linkInterceptor=new fe({getWrapperElement:()=>this.wrapperElement,handleNavigationResponse:(c,l)=>this.handleNavigationResponse(c,l),sendNavigate:c=>this.sendNavigate(c),canSendNavigate:()=>!this.useHTTP&&this.webSocketManager.getReadyState()===1},this.logger.child("LinkInterceptor")),this.observerManager=new ge({getWrapperElement:()=>this.wrapperElement,send:c=>this.send(c)},this.logger.child("ObserverManager")),this.changeAutoWirer=new Ee({getWrapperElement:()=>this.wrapperElement,send:c=>this.send(c)},this.logger.child("ChangeAutoWirer")),this.webSocketManager=new we({options:this.options,logger:this.logger.child("Transport"),onConnected:()=>{var c,l,d;this.ws=this.webSocketManager.getSocket(),this.logger.info("WebSocket connected"),this.clearFlashQueryParams(),(l=(c=this.options).onConnect)==null||l.call(c),(d=this.wrapperElement)==null||d.dispatchEvent(new Event("lvt:connected"))},onDisconnected:()=>{var c,l,d;this.ws=null,this.logger.info("WebSocket disconnected"),(l=(c=this.options).onDisconnect)==null||l.call(c),(d=this.wrapperElement)==null||d.dispatchEvent(new Event("lvt:disconnected"))},onMessage:(c,l)=>{this.handleWebSocketPayload(c,l)},onReconnectAttempt:()=>{this.logger.info("Attempting to reconnect...")},onError:c=>{var l,d;this.logger.error("WebSocket error:",c),(d=(l=this.options).onError)==null||d.call(l,c)}})}static autoInit(){let e=$e({scope:"Client:autoInit"}),t=()=>{let n=document.querySelector("[data-lvt-id]");if(n){let r=new s;r.wrapperElement=n,n.getAttribute("data-lvt-loading")==="true"&&(r.loadingIndicator.show(),r.formDisabler.disable(r.wrapperElement)),r.connect().catch(a=>{e.error("Auto-initialization connect failed:",a)}),window.liveTemplateClient=r}};document.readyState==="loading"?document.addEventListener("DOMContentLoaded",t):t()}handleWebSocketPayload(e,t){var r,i,a;let n=e;if(n.type==="upload_progress"){this.uploadHandler.handleProgressMessage(n);return}if(n.upload_name&&n.entries){let o=n;try{this.handleUploadStartResponse(o)}catch(c){this.logger.error("Error handling upload start response:",c)}return}if(n.upload_name&&n.hasOwnProperty("success")){n.success?this.logger.info(`Upload complete: ${n.upload_name}`):this.logger.error(`Upload failed: ${n.upload_name}`,n.error);return}this.isInitialized||(this.loadingIndicator.hide(),this.formDisabler.enable(this.wrapperElement),this.wrapperElement&&this.wrapperElement.hasAttribute("data-lvt-loading")&&this.wrapperElement.removeAttribute("data-lvt-loading"),this.isInitialized=!0,_e()),this.wrapperElement&&((r=e.meta)!=null&&r.capabilities&&this.changeAutoWirer.setCapabilities(e.meta.capabilities),this.changeAutoWirer.analyzeStatics(e.tree),this.updateDOM(this.wrapperElement,e.tree,e.meta),this.messageCount++,this.wrapperElement.dispatchEvent(new CustomEvent("lvt:updated",{detail:{messageCount:this.messageCount,action:(i=e.meta)==null?void 0:i.action,success:(a=e.meta)==null?void 0:a.success}})))}async connect(e="[data-lvt-id]"){var n,r;if(this.wrapperElement=document.querySelector(e),!this.wrapperElement)throw new Error(`LiveTemplate wrapper not found with selector: ${e}`);this.webSocketManager.disconnect();let t=await this.webSocketManager.connect();this.useHTTP=!t.usingWebSocket,this.useHTTP&&(this.ws=null,this.logger.info("WebSocket not available, using HTTP mode"),(r=(n=this.options).onConnect)==null||r.call(n),t.initialState&&this.wrapperElement&&this.handleWebSocketPayload(t.initialState)),this.eventDelegator.setupEventDelegation(),this.eventDelegator.setupWindowEventDelegation(),this.eventDelegator.setupClickAwayDelegation(),this.eventDelegator.setupDOMEventTriggerDelegation(),at(),this.eventDelegator.setupFocusTrapDelegation(),this.eventDelegator.setupAutofocusDelegation(),this.linkInterceptor.setup(this.wrapperElement),de(),wt(),yt(),tt(this.wrapperElement),this.focusManager.attach(this.wrapperElement),this.observerManager.setupInfiniteScrollObserver(),this.observerManager.setupInfiniteScrollMutationObserver(),this.setupVisibilityReconnect()}disconnect(){this.webSocketManager.disconnect(),this.ws=null,this.useHTTP=!1,this.hiddenAt=0,this.reconnecting=!1,this.teardownVisibilityReconnect(),this.eventDelegator.teardownDOMEventTriggerDelegation(),bt(),this.wrapperElement&&(et(this.wrapperElement),nt(this.wrapperElement),St(this.wrapperElement)),this.resetSessionState()}resetSessionState(){this.treeRenderer.reset(),this.rangeDomApplier.invalidate(),this.focusManager.reset(),this.observerManager.teardown(),this.changeAutoWirer.teardown(),this.formLifecycleManager.reset(),this.loadingIndicator.hide(),this.formDisabler.enable(this.wrapperElement),this.lvtId=null,this.isInitialized=!1}setupVisibilityReconnect(){this.visibilityHandlerAttached||typeof document=="undefined"||(this.visibilityHandlerAttached=!0,this.visibilityHandler=()=>{if(document.hidden){!this.useHTTP&&this.webSocketManager.getReadyState()===1&&(this.hiddenAt=Date.now());return}if(this.hiddenAt===0)return;let e=Date.now()-this.hiddenAt;this.hiddenAt=0,!(e<3e3)&&this.scheduleVisibilityReconnect()},this.pageshowHandler=e=>{e.persisted&&this.scheduleVisibilityReconnect()},document.addEventListener("visibilitychange",this.visibilityHandler),window.addEventListener("pageshow",this.pageshowHandler))}teardownVisibilityReconnect(){this.visibilityReconnectTimer!==null&&(clearTimeout(this.visibilityReconnectTimer),this.visibilityReconnectTimer=null),!(!this.visibilityHandlerAttached||typeof document=="undefined")&&(this.visibilityHandler&&(document.removeEventListener("visibilitychange",this.visibilityHandler),this.visibilityHandler=null),this.pageshowHandler&&(window.removeEventListener("pageshow",this.pageshowHandler),this.pageshowHandler=null),this.visibilityHandlerAttached=!1)}scheduleVisibilityReconnect(){this.visibilityReconnectTimer!==null&&clearTimeout(this.visibilityReconnectTimer),this.visibilityReconnectTimer=setTimeout(()=>{this.visibilityReconnectTimer=null,this.wrapperElement&&!this.useHTTP&&!this.reconnecting&&this.webSocketManager.getReadyState()!==void 0&&this.performVisibilityReconnect()},500)}async performVisibilityReconnect(){var e;if(!this.reconnecting){this.reconnecting=!0;try{this.logger.info("Reconnecting after visibility change"),this.webSocketManager.disconnect(),this.ws=null,this.resetSessionState();let t=await this.webSocketManager.connect();if(!this.reconnecting)return;this.useHTTP=!t.usingWebSocket,this.useHTTP&&(this.ws=null,t.initialState&&this.wrapperElement&&this.handleWebSocketPayload(t.initialState)),(e=this.wrapperElement)==null||e.dispatchEvent(new Event("lvt:reconnected"))}catch(t){this.logger.error("Visibility reconnect failed:",t)}finally{this.reconnecting=!1}}}clearFlashQueryParams(){let e=new URL(window.location.href),t=["error","success"],n=!1;for(let r of t)e.searchParams.has(r)&&(e.searchParams.delete(r),n=!0);n&&(this.logger.debug("Clearing flash query params from URL"),window.history.replaceState(null,"",e.toString()))}isReady(){let e=this.wrapperElement;return!e||e.hasAttribute("data-lvt-loading")?!1:this.useHTTP?!0:this.webSocketManager.getReadyState()===1}send(e){let t=this.webSocketManager.getReadyState();this.logger.isDebugEnabled()&&this.logger.debug("send() invoked",{message:e,useHTTP:this.useHTTP,hasWebSocket:t!==void 0,readyState:t}),this.useHTTP?(this.logger.debug("Using HTTP mode for send"),this.sendHTTP(e)):t===1?(this.logger.debug("Sending via WebSocket"),this.webSocketManager.send(JSON.stringify(e))):t!==void 0?(this.logger.warn(`WebSocket not ready (state: ${t}), using HTTP fallback`),this.sendHTTP(e)):this.logger.error("No transport available")}getLiveUrl(){return this.liveUrlOverride||this.options.liveUrl||"/live"}sendNavigate(e){let t=new URL(e,window.location.origin),n={},r=new Set;t.searchParams.forEach((a,o)=>{r.has(o)&&this.logger.warn("sendNavigate: duplicate query param key \u2014 last value wins; server may receive incomplete data",{key:o,href:e}),r.add(o),n[o]=a});let i=t.pathname+t.search;if(this.webSocketManager.getReadyState()!==1){let a=this.webSocketManager.getReadyState();return a===3?this.logger.error("sendNavigate: WebSocket is CLOSED and autoReconnect may be disabled; navigate message dropped. Reload or re-enable autoReconnect.",{href:e}):this.options.autoReconnect?this.logger.warn("sendNavigate: WS not open; browser URL is ahead of server state until reconnect",{href:e,readyState:a}):this.logger.error("sendNavigate: WS not open and autoReconnect is disabled; navigate may be permanently lost",{href:e,readyState:a}),!1}return this.liveUrlOverride=i,this.webSocketManager.setLiveUrl(i),this.logger.debug("sendNavigate",{href:e,data:n}),this.send({action:"__navigate__",data:n}),!0}async sendHTTP(e){try{let t=this.getLiveUrl(),n=await fetch(t,{method:"POST",credentials:"include",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify(e)});if(!n.ok)throw new Error(`HTTP request failed: ${n.status}`);let r=await n.json();this.wrapperElement&&this.updateDOM(this.wrapperElement,r.tree,r.meta)}catch(t){this.logger.error("Failed to send HTTP request:",t)}}sendHTTPMultipart(e,t,n){this.doSendHTTPMultipart(e,t,n)}async doSendHTTPMultipart(e,t,n){try{let r=this.getLiveUrl(),i=await fetch(r,{method:"POST",credentials:"include",headers:{Accept:"application/json"},body:n});if(!i.ok)throw new Error(`HTTP multipart request failed: ${i.status}`);let a=await i.json();this.wrapperElement&&this.updateDOM(this.wrapperElement,a.tree,a.meta)}catch(r){this.logger.error("Failed to send HTTP multipart request:",r)}}stylesheetsDiffer(e,t){let n=document.querySelectorAll('link[rel~="stylesheet"][href]'),r=new Set;n.forEach(c=>{let l=c.href;l&&r.add(l)});let i=e.querySelectorAll('link[rel~="stylesheet"][href]'),a=new Set;if(i.forEach(c=>{let l=c.getAttribute("href");if(l)try{a.add(new URL(l,t).href)}catch(d){a.add(l)}}),r.size!==a.size)return!0;let o=!1;return r.forEach(c=>{a.has(c)||(o=!0)}),o}performFullNavigation(e){window.location.href=e}handleNavigationResponse(e,t){var l;if(!this.wrapperElement)return;let r=new DOMParser().parseFromString(e,"text/html"),i=this.wrapperElement.getAttribute("data-lvt-id"),a=(l=r.querySelector("title"))==null?void 0:l.textContent;if(a&&(document.title=a),this.stylesheetsDiffer(r,t)){this.logger.info('Cross-app navigation detected (different <link rel="stylesheet"> set in fetched HTML); falling back to full navigation'),this.performFullNavigation(t);return}let o=r.querySelector("[data-lvt-id]");if(o){let d=o.getAttribute("data-lvt-id");if(!d){this.logger.warn("Cross-handler navigation: new wrapper has empty data-lvt-id"),window.location.reload();return}this.linkInterceptor.teardownForWrapper(i),this.eventDelegator.teardownForWrapper(i);let u=++this.navigationEpoch;this.disconnect(),this.wrapperElement.setAttribute("data-lvt-id",d),this.wrapperElement.replaceChildren(...Array.from(o.childNodes).map(f=>f.cloneNode(!0))),this.eventDelegator.setupEventDelegation(),this.linkInterceptor.setup(this.wrapperElement),window.scrollTo(0,0);let p=window.location.pathname+window.location.search;if(this.liveUrlOverride=p,this.webSocketManager.setLiveUrl(p),!this.useHTTP){let g=`[data-lvt-id="${d.replace(/[\\"]/g,"\\$&")}"]`;this.connect(g).catch(H=>{u===this.navigationEpoch&&(this.logger.error("Cross-handler reconnect failed:",H),window.location.reload())})}return}this.linkInterceptor.teardownForWrapper(i),this.eventDelegator.teardownForWrapper(i),this.disconnect();let c=r.querySelector("body");c&&this.wrapperElement.replaceChildren(...Array.from(c.childNodes).map(d=>d.cloneNode(!0))),this.eventDelegator.setupEventDelegation(),this.linkInterceptor.setup(this.wrapperElement)}parseValue(e){let t=e.trim(),n=parseFloat(t);if(!isNaN(n)){if(Number.isInteger(n)&&Math.abs(n)>Number.MAX_SAFE_INTEGER)return t;if(t===n.toString())return n}return e==="true"?!0:e==="false"?!1:e}applyUpdate(e){return this.treeRenderer.applyUpdate(e)}applyUpdateToHTML(e,t){let n=this.applyUpdate(t);if(!this.lvtId){let l=e.match(/data-lvt-id="([^"]+)"/);l&&(this.lvtId=l[1])}let r=n.html;if(!e.match(/<body>([\s\S]*?)<\/body>/))return e;let c=`<div data-lvt-id="${this.lvtId||"lvt-unknown"}">`+r+"</div>";return e.replace(/<body>[\s\S]*?<\/body>/,`<body>${c}</body>`)}updateDOM(e,t,n){this.nodesAddedThisRender=0,this.directiveTouchedThisRender=!1;let r=this.treeRenderer.applyUpdate(t,{canApplyTargeted:(l,d)=>this.rangeDomApplier.canApplyTargeted(e,l,d).ok}),i=l=>!l||typeof l!="object"?!1:l.s&&Array.isArray(l.s)?!0:Object.values(l).some(d=>i(d));if(!r.changed&&!i(t))return;let a=document.createElement(e.tagName);if(this.logger.isDebugEnabled()&&(this.logger.debug("[updateDOM] element.tagName:",e.tagName),this.logger.debug("[updateDOM] result.html (first 500 chars):",r.html.substring(0,500)),this.logger.debug("[updateDOM] Has <table> tag:",r.html.includes("<table>")),this.logger.debug("[updateDOM] Has <tbody> tag:",r.html.includes("<tbody>")),this.logger.debug("[updateDOM] Has <tr> tag:",r.html.includes("<tr"))),/<script[\s>]/i.test(r.html)){let l=e.tagName.toLowerCase(),d=l==="body"||l==="html"?"div":l,p=new DOMParser().parseFromString(`<${d}>${r.html}</${d}>`,"text/html"),f=p.body.firstElementChild;f?a.replaceChildren(...Array.from(f.childNodes)):(this.logger.warn("[updateDOM] DOMParser: no wrapper root element; using doc.body children"),a.replaceChildren(...Array.from(p.body.childNodes)))}else a.innerHTML=r.html;this.logger.isDebugEnabled()&&(this.logger.debug("[updateDOM] tempWrapper.innerHTML (first 500 chars):",a.innerHTML.substring(0,500)),this.logger.debug("[updateDOM] tempWrapper has <table>:",a.innerHTML.includes("<table>")),this.logger.debug("[updateDOM] tempWrapper has <tbody>:",a.innerHTML.includes("<tbody>")),this.logger.debug("[updateDOM] tempWrapper has <tr>:",a.innerHTML.includes("<tr")));let o=document.activeElement;if(o instanceof HTMLInputElement&&o.list instanceof HTMLDataListElement&&!a.querySelector("[data-lvt-force-update]")){this.logger.debug("[updateDOM] deferred: datalist input focused"),this.focusManager.restoreFocusedElement();return}let c={childrenOnly:!0,getNodeKey:l=>{if(l.nodeType===1)return l.getAttribute("data-key")||l.getAttribute("data-lvt-key")||void 0},onBeforeElUpdated:(l,d)=>{if(d.nodeType===Node.ELEMENT_NODE&&d.hasAttribute(q))return!1;if(d.nodeType===Node.ELEMENT_NODE&&l.nodeType===Node.ELEMENT_NODE){let u=d.attributes,p=l;for(let f=0;f<u.length;f++){let g=u[f].name;if(g.length>4&&g.charCodeAt(0)===108&&g.charCodeAt(1)===118&&g.charCodeAt(2)===116&&g.charCodeAt(3)===45&&!p.hasAttribute(g)){this.directiveTouchedThisRender=!0;break}}}if(l.nodeType===Node.ELEMENT_NODE&&l.hasAttribute("lvt-ignore")&&!d.hasAttribute("data-lvt-force-update"))return!1;if(l.nodeType===Node.ELEMENT_NODE&&l.hasAttribute("lvt-ignore-attrs")&&!d.hasAttribute("data-lvt-force-update")&&d.nodeType===Node.ELEMENT_NODE){let u=l.attributes,p=d;for(let f=0;f<u.length;f++){let g=u[f];p.hasAttributeNS(g.namespaceURI,g.localName)||p.setAttributeNS(g.namespaceURI,g.name,g.value)}}if(l instanceof HTMLDataListElement&&!d.hasAttribute("data-lvt-force-update")){let u=document.activeElement;if(u instanceof HTMLInputElement&&u.list===l)return!1}return l instanceof HTMLDialogElement&&l.hasAttribute("open")&&!d.hasAttribute("data-lvt-force-update")&&d.setAttribute("open",""),!d.hasAttribute("data-lvt-force-update")&&l instanceof HTMLElement&&l.hasAttribute("popover")&&Oe(l)||(l instanceof HTMLInputElement&&d instanceof HTMLInputElement&&(l.type==="checkbox"||l.type==="radio")&&(d.hasAttribute("data-lvt-force-update")?(l.checked=d.checked,l.type==="checkbox"&&(l.indeterminate=d.indeterminate),l.removeAttribute("data-lvt-force-update")):(d.checked=l.checked,l.checked?d.setAttribute("checked",""):d.removeAttribute("checked"),l.type==="checkbox"&&(d.indeterminate=l.indeterminate))),this.focusManager.shouldSkipUpdate(l))?!1:l.isEqualNode(d)?!(!d.hasAttribute("data-lvt-force-update")&&(d.children.length===0||d.querySelector("[data-lvt-force-update]")===null)):(this.executeLifecycleHook(l,"lvt-updated"),!0)},onElUpdated:l=>{var d;l instanceof HTMLTextAreaElement&&(l.value=(d=l.textContent)!=null?d:""),l instanceof HTMLElement&&l.hasAttribute("data-lvt-force-update")&&l.removeAttribute("data-lvt-force-update")},onNodeAdded:l=>{var d;l instanceof HTMLTextAreaElement&&(l.value=(d=l.textContent)!=null?d:""),l instanceof HTMLElement&&l.hasAttribute("data-lvt-force-update")&&l.removeAttribute("data-lvt-force-update"),l.nodeType===Node.ELEMENT_NODE&&(this.executeLifecycleHook(l,"lvt-mounted"),this.nodesAddedThisRender++)},onBeforeNodeDiscarded:l=>(l.nodeType===Node.ELEMENT_NODE&&this.executeLifecycleHook(l,"lvt-destroyed"),!0)};if(r.targetedOps&&r.targetedOps.length>0){let l=[],d=!1;for(let u of r.targetedOps){let p=this.rangeDomApplier.apply(e,u,c);p?(p.setAttribute(j,""),l.push(p)):d=!0}if(d){this.logger.warn("[updateDOM] one or more targeted DOM ops failed; rebuilding tempWrapper from treeState for a full morphdom sync");for(let p of l)p.removeAttribute(j);let u=this.treeRenderer.renderState();a.innerHTML=u}else this.replaceTargetedSkipPlaceholders(a)}try{se(e,a,c)}finally{this.rangeDomApplier.cleanupMarkers(e)}this.focusManager.restoreFocusedElement(),rt(e),it(e),st(e),ot(e),Tt(e),(this.nodesAddedThisRender>0||this.directiveTouchedThisRender)&&(Ze(e,this.wrapperElement||void 0),this.eventDelegator.setupDOMEventTriggerDelegation(e),this.uploadHandler.initializeFileInputs(e)),this.changeAutoWirer.wireElements(),n&&this.formLifecycleManager.handleResponse(n)}handleUploadStartResponse(e){this.uploadHandler.handleUploadStartResponse(e)}replaceTargetedSkipPlaceholders(e){let t=document.createTreeWalker(e,NodeFilter.SHOW_COMMENT),n=[],r;for(;r=t.nextNode();){let i=r;i.nodeValue&&/^lvt-targeted-skip:.+$/.test(i.nodeValue)&&n.push(i)}for(let i of n){let a=i.nodeValue.match(/^lvt-targeted-skip:(.+)$/),o=a?a[1]:"",c=i.parentElement;c&&c.setAttribute(q,o),i.remove()}}executeLifecycleHook(e,t){let n=e.getAttribute(t);if(n)try{new Function("element",n).call(e,e)}catch(r){this.logger.error(`Error executing ${t} hook:`,r)}}reset(){this.resetSessionState()}getTreeState(){return this.treeRenderer.getTreeState()}getStaticStructure(){return this.treeRenderer.getStaticStructure()}};typeof window!="undefined"&&Se.autoInit();return Ft(yn);})();
|
|
32
32
|
//# sourceMappingURL=livetemplate-client.browser.js.map
|