@craftile/preview-client-html 0.8.1 → 0.9.0
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/html.cdn.js +1 -1
- package/dist/index.d.ts +9 -0
- package/dist/index.js +151 -0
- package/package.json +3 -3
package/dist/html.cdn.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var Te=Object.defineProperty;var Ne=(S,k,p)=>k in S?Te(S,k,{enumerable:!0,configurable:!0,writable:!0,value:p}):S[k]=p;var N=(S,k,p)=>Ne(S,typeof k!="symbol"?k+"":k,p);var HtmlPreviewClient=(function(){"use strict";var S=Object.defineProperty,k=(o,e,t)=>e in o?S(o,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):o[e]=t,p=(o,e,t)=>k(o,typeof e!="symbol"?e+"":e,t);class ie{constructor(e,t="*"){p(this,"handlers",new Map),p(this,"targetWindow"),p(this,"targetOrigin"),p(this,"fallbackHandler"),this.targetWindow=e,this.targetOrigin=t,window.addEventListener("message",this.handleMessage.bind(this))}handleMessage(e){const t=e.data;if(!t.type)return;const n=this.handlers.get(t.type);n?n.forEach(i=>i(t.payload,e)):this.fallbackHandler&&this.fallbackHandler(e.data,e)}send(e,t){const n={type:e,payload:t};this.targetWindow.postMessage(n,this.targetOrigin)}listen(e,t){return this.handlers.has(e)||this.handlers.set(e,[]),this.handlers.get(e).push(t),()=>{const n=this.handlers.get(e);if(n){const i=n.indexOf(t);i>-1&&n.splice(i,1)}}}registerFallbackHandler(e){this.fallbackHandler=e}}function re(o="*"){if(window.parent===window)throw new Error("Not inside an iframe");return new ie(window.parent,o)}class se{constructor(){p(this,"listeners",new Map)}on(e,t){return this.listeners.has(e)||this.listeners.set(e,new Set),this.listeners.get(e).add(t),()=>{this.off(e,t)}}off(e,t){const n=this.listeners.get(e);n&&(n.delete(t),n.size===0&&this.listeners.delete(e))}once(e,t){const n=i=>{t(i),this.off(e,n)};this.on(e,n)}emit(e,...t){const n=this.listeners.get(e);if(n){const i=t[0];n.forEach(r=>{try{r(i)}catch(s){console.error(`Error in event listener for '${String(e)}':`,s)}})}}removeAllListeners(e){e?this.listeners.delete(e):this.listeners.clear()}}class oe{constructor(e){p(this,"active",!0),p(this,"messenger"),p(this,"currentHoveredBlock",null),p(this,"currentSelectedBlock",null),p(this,"overlayButtonHovered",!1),p(this,"resizeObserver",null),p(this,"mutationObserver",null),this.messenger=e,this.messenger.listen("craftile.inspector.enable",()=>this.enable()),this.messenger.listen("craftile.inspector.disable",()=>this.disable()),this.messenger.listen("craftile.inspector.overlay-button-enter",this.handleOverlayButtonEnter.bind(this)),this.messenger.listen("craftile.inspector.overlay-button-leave",this.handleOverlayButtonLeave.bind(this)),this.messenger.listen("craftile.editor.select-block",this.handleEditorSelectBlock.bind(this)),this.messenger.listen("craftile.editor.deselect-block",this.handleEditorDeselectBlock.bind(this)),window.addEventListener("scroll",this.handleScroll.bind(this),{passive:!0}),this.setupGlobalEventListeners()}updateTrackedElement(e,t){this.currentHoveredBlock?.dataset.block===e&&(this.currentHoveredBlock=t,this.sendHoveredBlockPosition()),this.currentSelectedBlock?.dataset.block===e&&(this.currentSelectedBlock=t,this.sendSelectedBlockPosition(!0),this.trackSelectedBlock())}enable(){this.active=!0,document.body.classList.add("craftile-inspector-active"),this.currentSelectedBlock&&this.trackSelectedBlock()}disable(){this.active=!1,document.body.classList.remove("craftile-inspector-active"),this.currentHoveredBlock=null,this.overlayButtonHovered=!1,this.resizeObserver&&(this.resizeObserver.disconnect(),this.resizeObserver=null),this.mutationObserver&&(this.mutationObserver.disconnect(),this.mutationObserver=null)}handleOverlayButtonEnter(){this.overlayButtonHovered=!0}handleOverlayButtonLeave(e){this.overlayButtonHovered=!1,this.currentHoveredBlock||this.messenger.send("craftile.preview.block-leave")}handleEditorSelectBlock(e){const t=document.querySelector(`[data-block="${e.blockId}"]`);t&&(this.currentSelectedBlock=t,this.sendSelectedBlockPosition(),this.trackSelectedBlock(),t.scrollIntoView({behavior:"smooth",block:"nearest",inline:"nearest"}))}handleEditorDeselectBlock(){this.currentSelectedBlock=null,this.resizeObserver&&(this.resizeObserver.disconnect(),this.resizeObserver=null),this.mutationObserver&&(this.mutationObserver.disconnect(),this.mutationObserver=null)}handleScroll(){this.active&&(this.currentSelectedBlock&&this.sendSelectedBlockPosition(),this.currentHoveredBlock&&this.sendHoveredBlockPosition())}setupGlobalEventListeners(){document.addEventListener("mouseover",this.handleGlobalHover.bind(this)),document.addEventListener("mouseout",this.handleGlobalLeave.bind(this)),document.addEventListener("click",this.handleGlobalClick.bind(this),{capture:!0})}handleGlobalHover(e){if(!this.active)return;const t=e.target.closest("[data-block]");t&&(e.stopPropagation(),this.currentHoveredBlock=t,this.sendHoveredBlockPosition())}handleGlobalLeave(e){!this.active||!e.target.closest("[data-block]")||this.overlayButtonHovered||(this.currentHoveredBlock=null,this.messenger.send("craftile.preview.block-leave"))}handleGlobalClick(e){if(this.messenger.send("craftile.preview.click"),!this.active)return;const t=e.target.closest("[data-block]");if(!t||!t.getAttribute("data-block"))return;this.currentSelectedBlock===t||(e.preventDefault(),e.stopImmediatePropagation(),this.currentSelectedBlock=t,this.sendSelectedBlockPosition(),this.trackSelectedBlock())}sendHoveredBlockPosition(){const e=this.computeElementPositioning(this.currentHoveredBlock);this.messenger.send("craftile.preview.block-hover",{blockRect:e.rect,parentRect:e.parentRect,scrollTop:e.scrollTop,scrollLeft:e.scrollLeft,blockId:this.currentHoveredBlock.dataset.block,parentFlexDirection:e.parentFlexDirection})}sendSelectedBlockPosition(e=!1){if(!this.currentSelectedBlock)return;const t=this.computeElementPositioning(this.currentSelectedBlock);this.messenger.send(e?"craftile.preview.update-selected-block":"craftile.preview.block-select",{blockRect:t.rect,scrollTop:t.scrollTop,scrollLeft:t.scrollLeft,blockId:this.currentSelectedBlock.dataset.block})}trackSelectedBlock(){if(!this.currentSelectedBlock)return;this.resizeObserver&&(this.resizeObserver.disconnect(),this.resizeObserver=null),this.mutationObserver&&(this.mutationObserver.disconnect(),this.mutationObserver=null),this.resizeObserver=new ResizeObserver(()=>{this.active&&this.currentSelectedBlock&&this.sendSelectedBlockPosition(!0)}),this.resizeObserver.observe(this.currentSelectedBlock),this.mutationObserver=new MutationObserver(()=>{this.active&&this.currentSelectedBlock&&this.sendSelectedBlockPosition(!0)}),this.mutationObserver.observe(this.currentSelectedBlock,{attributes:!0,subtree:!1});let e=this.currentSelectedBlock.parentElement;for(;e&&(this.mutationObserver.observe(e,{childList:!0,subtree:!1}),e!==document.body);)e=e.parentElement}computeElementPositioning(e){const t=e.getBoundingClientRect(),n=window.pageYOffset||document.documentElement.scrollTop,i=window.pageXOffset||document.documentElement.scrollLeft,r=this.findEldestParentBlock(e),s=r&&r!==e?r.getBoundingClientRect():void 0,l=this.getElementFlexDirection(e.parentElement);return{rect:t,parentRect:s,scrollTop:n,scrollLeft:i,parentFlexDirection:l}}findEldestParentBlock(e){let t=null,n=e.parentElement;for(;n&&n!==document.body;)n.hasAttribute("data-block")&&(t=n),n=n.parentElement;return t}getElementFlexDirection(e){if(!e)return"column";const t=window.getComputedStyle(e),n=t.display.includes("flex")?t.flexDirection:"column";return n==="row"||n==="row-reverse"?"row":"column"}}class le extends se{constructor(){super(),p(this,"messenger"),p(this,"inspector"),this.messenger=re(window.origin),this.inspector=new oe(this.messenger),this.initialize()}initialize(){window.addEventListener("load",()=>{this.messenger.send("craftile.preview.ready",{}),setTimeout(()=>{this.sendPageData()},0)}),this.messenger.registerFallbackHandler(e=>{const{type:t,payload:n}=e;this.emit(t,n)})}sendPageData(){const e=document.getElementById("page-data");if(e)try{const t=JSON.parse(e.textContent||"{}");this.messenger.send("craftile.preview.page-data",{pageData:t})}catch(t){console.error("Failed to parse page data:",t)}}}var K=11;function ae(o,e){var t=e.attributes,n,i,r,s,l;if(!(e.nodeType===K||o.nodeType===K)){for(var h=t.length-1;h>=0;h--)n=t[h],i=n.name,r=n.namespaceURI,s=n.value,r?(i=n.localName||i,l=o.getAttributeNS(r,i),l!==s&&(n.prefix==="xmlns"&&(i=n.name),o.setAttributeNS(r,i,s))):(l=o.getAttribute(i),l!==s&&o.setAttribute(i,s));for(var u=o.attributes,m=u.length-1;m>=0;m--)n=u[m],i=n.name,r=n.namespaceURI,r?(i=n.localName||i,e.hasAttributeNS(r,i)||o.removeAttributeNS(r,i)):e.hasAttribute(i)||o.removeAttribute(i)}}var A,ce="http://www.w3.org/1999/xhtml",g=typeof document>"u"?void 0:document,de=!!g&&"content"in g.createElement("template"),he=!!g&&g.createRange&&"createContextualFragment"in g.createRange();function fe(o){var e=g.createElement("template");return e.innerHTML=o,e.content.childNodes[0]}function ue(o){A||(A=g.createRange(),A.selectNode(g.body));var e=A.createContextualFragment(o);return e.childNodes[0]}function me(o){var e=g.createElement("body");return e.innerHTML=o,e.childNodes[0]}function ve(o){return o=o.trim(),de?fe(o):he?ue(o):me(o)}function H(o,e){var t=o.nodeName,n=e.nodeName,i,r;return t===n?!0:(i=t.charCodeAt(0),r=n.charCodeAt(0),i<=90&&r>=97?t===n.toUpperCase():r<=90&&i>=97?n===t.toUpperCase():!1)}function pe(o,e){return!e||e===ce?g.createElement(o):g.createElementNS(e,o)}function be(o,e){for(var t=o.firstChild;t;){var n=t.nextSibling;e.appendChild(t),t=n}return e}function _(o,e,t){o[t]!==e[t]&&(o[t]=e[t],o[t]?o.setAttribute(t,""):o.removeAttribute(t))}var q={OPTION:function(o,e){var t=o.parentNode;if(t){var n=t.nodeName.toUpperCase();n==="OPTGROUP"&&(t=t.parentNode,n=t&&t.nodeName.toUpperCase()),n==="SELECT"&&!t.hasAttribute("multiple")&&(o.hasAttribute("selected")&&!e.selected&&(o.setAttribute("selected","selected"),o.removeAttribute("selected")),t.selectedIndex=-1)}_(o,e,"selected")},INPUT:function(o,e){_(o,e,"checked"),_(o,e,"disabled"),o.value!==e.value&&(o.value=e.value),e.hasAttribute("value")||o.removeAttribute("value")},TEXTAREA:function(o,e){var t=e.value;o.value!==t&&(o.value=t);var n=o.firstChild;if(n){var i=n.nodeValue;if(i==t||!t&&i==o.placeholder)return;n.nodeValue=t}},SELECT:function(o,e){if(!e.hasAttribute("multiple")){for(var t=-1,n=0,i=o.firstChild,r,s;i;)if(s=i.nodeName&&i.nodeName.toUpperCase(),s==="OPTGROUP")r=i,i=r.firstChild,i||(i=r.nextSibling,r=null);else{if(s==="OPTION"){if(i.hasAttribute("selected")){t=n;break}n++}i=i.nextSibling,!i&&r&&(i=r.nextSibling,r=null)}o.selectedIndex=t}}},P=1,Y=11,J=3,Q=8;function C(){}function ge(o){if(o)return o.getAttribute&&o.getAttribute("id")||o.id}function ke(o){return function(t,n,i){if(i||(i={}),typeof n=="string")if(t.nodeName==="#document"||t.nodeName==="HTML"||t.nodeName==="BODY"){var r=n;n=g.createElement("html"),n.innerHTML=r}else n=ve(n);else n.nodeType===Y&&(n=n.firstElementChild);var s=i.getNodeKey||ge,l=i.onBeforeNodeAdded||C,h=i.onNodeAdded||C,u=i.onBeforeElUpdated||C,m=i.onElUpdated||C,Ce=i.onBeforeNodeDiscarded||C,M=i.onNodeDiscarded||C,we=i.onBeforeElChildrenUpdated||C,Ee=i.skipFromChildren||C,Z=i.addChild||function(a,c){return a.appendChild(c)},z=i.childrenOnly===!0,O=Object.create(null),x=[];function D(a){x.push(a)}function ee(a,c){if(a.nodeType===P)for(var v=a.firstChild;v;){var d=void 0;c&&(d=s(v))?D(d):(M(v),v.firstChild&&ee(v,c)),v=v.nextSibling}}function I(a,c,v){Ce(a)!==!1&&(c&&c.removeChild(a),M(a),ee(a,v))}function G(a){if(a.nodeType===P||a.nodeType===Y)for(var c=a.firstChild;c;){var v=s(c);v&&(O[v]=c),G(c),c=c.nextSibling}}G(t);function V(a){h(a);for(var c=a.firstChild;c;){var v=c.nextSibling,d=s(c);if(d){var f=O[d];f&&H(c,f)?(c.parentNode.replaceChild(f,c),L(f,c)):V(c)}else V(c);c=v}}function Se(a,c,v){for(;c;){var d=c.nextSibling;(v=s(c))?D(v):I(c,a,!0),c=d}}function L(a,c,v){var d=s(c);if(d&&delete O[d],!v){var f=u(a,c);if(f===!1||(f instanceof HTMLElement&&(a=f,G(a)),o(a,c),m(a),we(a,c)===!1))return}a.nodeName!=="TEXTAREA"?Oe(a,c):q.TEXTAREA(a,c)}function Oe(a,c){var v=Ee(a,c),d=c.firstChild,f=a.firstChild,y,B,T,$,w;e:for(;d;){for($=d.nextSibling,y=s(d);!v&&f;){if(T=f.nextSibling,d.isSameNode&&d.isSameNode(f)){d=$,f=T;continue e}B=s(f);var F=f.nodeType,E=void 0;if(F===d.nodeType&&(F===P?(y?y!==B&&((w=O[y])?T===w?E=!1:(a.insertBefore(w,f),B?D(B):I(f,a,!0),f=w,B=s(f)):E=!1):B&&(E=!1),E=E!==!1&&H(f,d),E&&L(f,d)):(F===J||F==Q)&&(E=!0,f.nodeValue!==d.nodeValue&&(f.nodeValue=d.nodeValue))),E){d=$,f=T;continue e}B?D(B):I(f,a,!0),f=T}if(y&&(w=O[y])&&H(w,d))v||Z(a,w),L(w,d);else{var j=l(d);j!==!1&&(j&&(d=j),d.actualize&&(d=d.actualize(a.ownerDocument||g)),Z(a,d),V(d))}d=$,f=T}Se(a,f,B);var ne=q[a.nodeName];ne&&ne(a,c)}var b=t,R=b.nodeType,te=n.nodeType;if(!z){if(R===P)te===P?H(t,n)||(M(t),b=be(t,pe(n.nodeName,n.namespaceURI))):b=n;else if(R===J||R===Q){if(te===R)return b.nodeValue!==n.nodeValue&&(b.nodeValue=n.nodeValue),b;b=n}}if(b===n)M(t);else{if(n.isSameNode&&n.isSameNode(b))return;if(L(b,n,z),x)for(var W=0,ye=x.length;W<ye;W++){var X=O[x[W]];X&&I(X,X.parentNode,!1)}}return!z&&b!==t&&t.parentNode&&(b.actualize&&(b=b.actualize(t.ownerDocument||g)),t.parentNode.replaceChild(b,t)),b}}var Be=ke(ae);class U{constructor(e,t){N(this,"previewClient");N(this,"morphdomOptions");N(this,"elementCache",new Map);N(this,"regionCommentsCache",new Map);N(this,"childrenCommentsCache",new Map);this.previewClient=e||new le,this.morphdomOptions=t?.morphdom||{},this.previewClient.on("updates.effects",this.handleEffects.bind(this)),this.previewClient.on("craftile.editor.updates",this.handleDirectUpdates.bind(this)),this.cacheRegionComments(),this.cacheChildrenComments()}static init(e,t){return new U(e,t)}getElementCached(e){if(this.elementCache.has(e)){const n=this.elementCache.get(e);if(n.isConnected)return n;this.elementCache.delete(e)}const t=document.querySelector(`[data-block="${e}"]`);return t&&this.elementCache.set(e,t),t}cacheRegionComments(){const e=document.createTreeWalker(document.body,NodeFilter.SHOW_COMMENT,null);let t;const n=new Map;for(;t=e.nextNode();){const i=t.textContent?.trim();if(i){if(i.startsWith("BEGIN region: ")){const r=i.substring(14);n.set(r,t)}else if(i.startsWith("END region: ")){const r=i.substring(12),s=n.get(r);s&&(this.regionCommentsCache.set(r,{begin:s,end:t}),n.delete(r))}}}}cacheChildrenComments(){const e=document.createTreeWalker(document.body,NodeFilter.SHOW_COMMENT,null);let t;const n=new Map;for(;t=e.nextNode();){const i=t.textContent?.trim();if(i){if(i.startsWith("BEGIN children: ")){const r=i.substring(16);n.set(r,t)}else if(i.startsWith("END children: ")){const r=i.substring(14),s=n.get(r);s&&(this.childrenCommentsCache.set(r,{begin:s,end:t}),n.delete(r))}}}}cacheChildrenCommentsForBlock(e){const t=this.getElementCached(e);if(!t)return;this.childrenCommentsCache.delete(e);const n=document.createTreeWalker(t,NodeFilter.SHOW_COMMENT,null);let i,r=null;for(;i=n.nextNode();){const s=i.textContent?.trim();if(s){if(s===`BEGIN children: ${e}`)r=i;else if(s===`END children: ${e}`&&r){this.childrenCommentsCache.set(e,{begin:r,end:i});break}}}}invalidateCache(e){[...e.updated,...e.removed].forEach(t=>{this.elementCache.delete(t),this.childrenCommentsCache.delete(t)})}handleEffects(e){const{effects:t,blocks:n,regions:i,changes:r}=e;t&&(this.invalidateCache(r),t.html&&this.handleHtmlEffects(t.html,{blocks:n,regions:i,changes:r}))}handleDirectUpdates(e){const{changes:t}=e;t.moved&&this.handleMoves(e),t.updated.length>0&&this.handleDisabledBlocks(e),t.removed.length>0&&this.handleRemoves(e)}handleMoves(e){const{blocks:t,changes:n}=e;for(const[i,r]of Object.entries(e.changes.moved)){if(r?.toParent&&n.updated?.includes(r?.toParent))continue;if(!this.isValidMoveInstruction(r)){console.warn(`Invalid move instruction for block ${i}:`,r);continue}const s=t[i];this.moveBlockUsingDOM(s,r)}}handleDisabledBlocks(e){const{blocks:t,changes:n}=e;for(const i of n.updated){const r=t[i];if(!r)continue;const l=!!this.getElementCached(i);r.disabled&&l?this.removeBlock(r.id):r.disabled}}handleRemoves(e){const{changes:t}=e;for(const n of t.removed)this.removeBlock(n)}handleHtmlEffects(e,t){const{blocks:n,regions:i}=t;for(const[r,s]of Object.entries(e)){if(!s)continue;const l=n[r];if(!l){console.warn(`Block data not found for ${r}`);continue}if(l.disabled){console.debug(`Skipping disabled block ${r}`);continue}if(!!this.getElementCached(r))this.updateBlockHtml(l,s);else{const m=this.calculatePosition(l,i,n);this.insertBlock(l,s,m)}}}isValidMoveInstruction(e){const t=!!(e.toParent||e.toRegion),n=e.toIndex===void 0||e.toIndex>=0;return t&&n}removeBlock(e){const t=this.getElementCached(e);t?(this.previewClient.emit("block.remove.before",{blockId:e,element:t}),t.remove(),this.elementCache.delete(e),this.previewClient.emit("block.remove.after",{blockId:e,element:t})):console.warn(`Block ${e} not found for removal`)}moveBlockUsingDOM(e,t){const n=this.getElementCached(e.id),{toParent:i,toRegion:r,toIndex:s}=t;if(!n){console.warn(`Block element ${e.id} not found for move operation`);return}if(this.previewClient.emit("block.move.before",{blockId:e.id,blockType:e.type,block:e,element:n,toParent:i,toRegion:r,toIndex:s}),i){const l=this.getElementCached(i);if(!l){console.error(`Parent element ${i} not found for move operation`);return}this.insertElementInContainer(n,l,e.id,s)}else if(r){const l=this.findRegionInsertionPoint(r,s,void 0,void 0,e.id);if(!l){console.error(`Failed to find insertion point for region: ${r}`);return}l.parent.insertBefore(n,l.before)}this.previewClient.emit("block.move.after",{blockId:e.id,blockType:e.type,block:e,element:n,toParent:i,toRegion:r,toIndex:s})}insertElementInContainer(e,t,n,i){const r=t.getAttribute("data-block"),s=r?this.childrenCommentsCache.get(r):null;if(s){const l=this.findPositionBetweenComments(s.begin,s.end,i,n);l.parent.insertBefore(e,l.before)}else{const h=Array.from(t.children).filter(m=>m.getAttribute("data-block")!==n),u=i!==void 0&&i<h.length?h[i]:null;t.insertBefore(e,u)}}insertBlock(e,t,n){if(this.getElementCached(e.id))return;this.previewClient.emit("block.insert.before",{blockId:e.id,blockType:e.type,block:e,html:t,positionInfo:n});const i=this.parseHtmlElement(t,e.id);if(!i)return;const{parentId:r,regionName:s,position:l,afterId:h,beforeId:u}=n;if(r){const m=this.getElementCached(r);if(!m){console.error(`Parent element ${r} not found for block ${e.id}`);return}this.insertElementByPosition(i,m,l,h,u)}else if(s){const m=this.findRegionInsertionPoint(s,l,h,u);if(!m){console.error(`Failed to find insertion point for region: ${s}`);return}m.parent.insertBefore(i,m.before)}else console.warn(`No parent or region specified for block ${e.id}, inserting into body`),document.body.appendChild(i);this.elementCache.set(e.id,i),this.cacheChildrenCommentsForBlock(e.id),i.scrollIntoView({behavior:"smooth",block:"nearest",inline:"nearest"}),this.previewClient.emit("block.insert.after",{blockId:e.id,blockType:e.type,block:e,html:t,positionInfo:n})}updateBlockHtml(e,t){if(!t){console.warn(`No HTML provided for block ${e.id}`);return}const n=this.getElementCached(e.id);if(!n){console.warn(`Block element ${e.id} not found for HTML update`);return}this.previewClient.emit("block.update.before",{blockId:e.id,blockType:e.type,block:e,element:n,html:t}),Be(n,t,this.morphdomOptions),this.elementCache.delete(e.id);const i=this.getElementCached(e.id);if(!i){console.error(`Block element ${e.id} not found after morphdom update`);return}i!==n&&this.previewClient.inspector.updateTrackedElement(e.id,i),this.cacheChildrenCommentsForBlock(e.id),this.previewClient.emit("block.update.after",{blockId:e.id,blockType:e.type,block:e,element:i,html:t})}insertElementByPosition(e,t,n,i,r){const s=t.getAttribute("data-block"),l=s?this.childrenCommentsCache.get(s):null;if(l){let h=null;if(r)h=this.getElementCached(r);else if(i){const u=this.getElementCached(i);u&&u.nextSibling&&(h=u.nextSibling)}else if(typeof n=="number"){const u=this.findPositionBetweenComments(l.begin,l.end,n);l.begin.parentNode.insertBefore(e,u.before);return}h||(h=l.end),l.begin.parentNode.insertBefore(e,h)}else{let h=null;if(r)h=this.getElementCached(r);else if(i){const u=this.getElementCached(i);u&&(h=u.nextElementSibling)}else typeof n=="number"&&(h=Array.from(t.children)[n]||null);t.insertBefore(e,h)}}findRegionInsertionPoint(e,t,n,i,r){const s=this.regionCommentsCache.get(e);if(!s)return console.error(`Region comments not found for region: ${e}`),null;const{begin:l,end:h}=s;let u=null;if(i){const m=this.getElementCached(i);m&&(u=m)}else if(n){const m=this.getElementCached(n);m&&m.nextSibling&&(u=m.nextSibling)}else typeof t=="number"&&(u=this.findPositionInRegion(l,h,t,r));return u||(u=h),{parent:l.parentNode,before:u}}findPositionInRegion(e,t,n,i){const r=[];let s=e.nextSibling;for(;s&&s!==t;){if(s.nodeType===Node.ELEMENT_NODE&&s.hasAttribute("data-block")){const l=s.getAttribute("data-block");(!i||l!==i)&&r.push(s)}s=s.nextSibling}return n<r.length?r[n]:null}findPositionBetweenComments(e,t,n,i){let r=null;if(typeof n=="number"){const s=[];let l=e.nextSibling;for(;l&&l!==t;){if(l.nodeType===Node.ELEMENT_NODE&&l.hasAttribute("data-block")){const h=l.getAttribute("data-block");(!i||h!==i)&&s.push(l)}l=l.nextSibling}r=n<s.length?s[n]:null}return r||(r=t),{parent:e.parentNode,before:r}}calculatePosition(e,t,n){if(e.parentId){const i=n[e.parentId];i||console.warn(`Block data not found for block ${e.id}`);const r=i.children.indexOf(e.id);if(r===-1)return console.warn(`Block ${e.id} not found in parent ${e.parentId} children`),{parentId:e.parentId};const{afterId:s,beforeId:l}=this.findAdjacentSiblings(i.children,r,n);return{parentId:e.parentId,position:r,afterId:s,beforeId:l}}else{for(const i of t){const r=i.blocks.indexOf(e.id);if(r!==-1){const{afterId:s,beforeId:l}=this.findAdjacentSiblings(i.blocks,r,n);return{regionName:i.name,position:r,afterId:s,beforeId:l}}}return{}}}findAdjacentSiblings(e,t,n){let i,r;for(let s=t-1;s>=0;s--){const l=n[e[s]];if(l&&!l.disabled){i=e[s];break}}for(let s=t+1;s<e.length;s++){const l=n[e[s]];if(l&&!l.disabled){r=e[s];break}}return{afterId:i,beforeId:r}}parseHtmlElement(e,t){if(!e.trim())return console.error(`Empty HTML provided for block ${t}`),null;const n=document.createElement("div");n.innerHTML=e;const i=n.firstElementChild;return i||(console.error(`Invalid HTML for block ${t}: no element found`),null)}}return U})();
|
|
1
|
+
var xe=Object.defineProperty;var Te=(y,C,v)=>C in y?xe(y,C,{enumerable:!0,configurable:!0,writable:!0,value:v}):y[C]=v;var w=(y,C,v)=>Te(y,typeof C!="symbol"?C+"":C,v);var HtmlPreviewClient=(function(){"use strict";var y=Object.defineProperty,C=(o,e,t)=>e in o?y(o,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):o[e]=t,v=(o,e,t)=>C(o,typeof e!="symbol"?e+"":e,t);class ie{constructor(e,t="*"){v(this,"handlers",new Map),v(this,"targetWindow"),v(this,"targetOrigin"),v(this,"fallbackHandler"),this.targetWindow=e,this.targetOrigin=t,window.addEventListener("message",this.handleMessage.bind(this))}handleMessage(e){const t=e.data;if(!t.type)return;const n=this.handlers.get(t.type);n?n.forEach(i=>i(t.payload,e)):this.fallbackHandler&&this.fallbackHandler(e.data,e)}send(e,t){const n={type:e,payload:t};this.targetWindow.postMessage(n,this.targetOrigin)}listen(e,t){return this.handlers.has(e)||this.handlers.set(e,[]),this.handlers.get(e).push(t),()=>{const n=this.handlers.get(e);if(n){const i=n.indexOf(t);i>-1&&n.splice(i,1)}}}registerFallbackHandler(e){this.fallbackHandler=e}}function re(o="*"){if(window.parent===window)throw new Error("Not inside an iframe");return new ie(window.parent,o)}class se{constructor(){v(this,"listeners",new Map)}on(e,t){return this.listeners.has(e)||this.listeners.set(e,new Set),this.listeners.get(e).add(t),()=>{this.off(e,t)}}off(e,t){const n=this.listeners.get(e);n&&(n.delete(t),n.size===0&&this.listeners.delete(e))}once(e,t){const n=i=>{t(i),this.off(e,n)};this.on(e,n)}emit(e,...t){const n=this.listeners.get(e);if(n){const i=t[0];n.forEach(r=>{try{r(i)}catch(s){console.error(`Error in event listener for '${String(e)}':`,s)}})}}removeAllListeners(e){e?this.listeners.delete(e):this.listeners.clear()}}class oe{constructor(e){v(this,"active",!0),v(this,"messenger"),v(this,"currentHoveredBlock",null),v(this,"currentSelectedBlock",null),v(this,"overlayButtonHovered",!1),v(this,"resizeObserver",null),v(this,"mutationObserver",null),this.messenger=e,this.messenger.listen("craftile.inspector.enable",()=>this.enable()),this.messenger.listen("craftile.inspector.disable",()=>this.disable()),this.messenger.listen("craftile.inspector.overlay-button-enter",this.handleOverlayButtonEnter.bind(this)),this.messenger.listen("craftile.inspector.overlay-button-leave",this.handleOverlayButtonLeave.bind(this)),this.messenger.listen("craftile.editor.select-block",this.handleEditorSelectBlock.bind(this)),this.messenger.listen("craftile.editor.deselect-block",this.handleEditorDeselectBlock.bind(this)),window.addEventListener("scroll",this.handleScroll.bind(this),{passive:!0}),this.setupGlobalEventListeners()}updateTrackedElement(e,t){this.currentHoveredBlock?.dataset.block===e&&(this.currentHoveredBlock=t,this.sendHoveredBlockPosition()),this.currentSelectedBlock?.dataset.block===e&&(this.currentSelectedBlock=t,requestAnimationFrame(()=>{this.sendSelectedBlockPosition(!0)}),this.trackSelectedBlock())}enable(){this.active=!0,document.body.classList.add("craftile-inspector-active"),this.currentSelectedBlock&&this.trackSelectedBlock()}disable(){this.active=!1,document.body.classList.remove("craftile-inspector-active"),this.currentHoveredBlock=null,this.overlayButtonHovered=!1,this.resizeObserver&&(this.resizeObserver.disconnect(),this.resizeObserver=null),this.mutationObserver&&(this.mutationObserver.disconnect(),this.mutationObserver=null)}handleOverlayButtonEnter(){this.overlayButtonHovered=!0}handleOverlayButtonLeave(e){this.overlayButtonHovered=!1,this.currentHoveredBlock||this.messenger.send("craftile.preview.block-leave")}handleEditorSelectBlock(e){const t=document.querySelector(`[data-block="${e.blockId}"]`);t&&(this.currentSelectedBlock=t,this.sendSelectedBlockPosition(),this.trackSelectedBlock(),t.scrollIntoView({behavior:"smooth",block:"nearest",inline:"nearest"}))}handleEditorDeselectBlock(){this.currentSelectedBlock=null,this.resizeObserver&&(this.resizeObserver.disconnect(),this.resizeObserver=null),this.mutationObserver&&(this.mutationObserver.disconnect(),this.mutationObserver=null)}handleScroll(){this.active&&(this.currentSelectedBlock&&this.sendSelectedBlockPosition(),this.currentHoveredBlock&&this.sendHoveredBlockPosition())}setupGlobalEventListeners(){document.addEventListener("mouseover",this.handleGlobalHover.bind(this)),document.addEventListener("mouseout",this.handleGlobalLeave.bind(this)),document.addEventListener("click",this.handleGlobalClick.bind(this),{capture:!0})}handleGlobalHover(e){if(!this.active)return;const t=e.target.closest("[data-block]");t&&(e.stopPropagation(),this.currentHoveredBlock=t,this.sendHoveredBlockPosition())}handleGlobalLeave(e){!this.active||!e.target.closest("[data-block]")||this.overlayButtonHovered||(this.currentHoveredBlock=null,this.messenger.send("craftile.preview.block-leave"))}handleGlobalClick(e){if(this.messenger.send("craftile.preview.click"),!this.active)return;const t=e.target.closest("[data-block]");if(!t||!t.getAttribute("data-block"))return;this.currentSelectedBlock===t||(e.preventDefault(),e.stopImmediatePropagation(),this.currentSelectedBlock=t,this.sendSelectedBlockPosition(),this.trackSelectedBlock())}sendHoveredBlockPosition(){const e=this.computeElementPositioning(this.currentHoveredBlock);this.messenger.send("craftile.preview.block-hover",{blockRect:e.rect,parentRect:e.parentRect,scrollTop:e.scrollTop,scrollLeft:e.scrollLeft,blockId:this.currentHoveredBlock.dataset.block,parentFlexDirection:e.parentFlexDirection})}sendSelectedBlockPosition(e=!1){if(!this.currentSelectedBlock)return;const t=this.computeElementPositioning(this.currentSelectedBlock);this.messenger.send(e?"craftile.preview.update-selected-block":"craftile.preview.block-select",{blockRect:t.rect,scrollTop:t.scrollTop,scrollLeft:t.scrollLeft,blockId:this.currentSelectedBlock.dataset.block})}trackSelectedBlock(){if(!this.currentSelectedBlock)return;this.resizeObserver&&(this.resizeObserver.disconnect(),this.resizeObserver=null),this.mutationObserver&&(this.mutationObserver.disconnect(),this.mutationObserver=null),this.resizeObserver=new ResizeObserver(()=>{this.active&&this.currentSelectedBlock&&this.sendSelectedBlockPosition(!0)}),this.resizeObserver.observe(this.currentSelectedBlock),this.mutationObserver=new MutationObserver(()=>{this.active&&this.currentSelectedBlock&&this.sendSelectedBlockPosition(!0)}),this.mutationObserver.observe(this.currentSelectedBlock,{attributes:!0,subtree:!1});let e=this.currentSelectedBlock.parentElement;for(;e&&(this.mutationObserver.observe(e,{childList:!0,subtree:!1}),e!==document.body);)e=e.parentElement}computeElementPositioning(e){const t=e.getBoundingClientRect(),n=window.pageYOffset||document.documentElement.scrollTop,i=window.pageXOffset||document.documentElement.scrollLeft,r=this.findEldestParentBlock(e),s=r&&r!==e?r.getBoundingClientRect():void 0,l=this.getElementFlexDirection(e.parentElement);return{rect:t,parentRect:s,scrollTop:n,scrollLeft:i,parentFlexDirection:l}}findEldestParentBlock(e){let t=null,n=e.parentElement;for(;n&&n!==document.body;)n.hasAttribute("data-block")&&(t=n),n=n.parentElement;return t}getElementFlexDirection(e){if(!e)return"column";const t=window.getComputedStyle(e),n=t.display.includes("flex")?t.flexDirection:"column";return n==="row"||n==="row-reverse"?"row":"column"}}class le extends se{constructor(){super(),v(this,"messenger"),v(this,"inspector"),this.messenger=re(window.origin),this.inspector=new oe(this.messenger),this.initialize()}initialize(){window.addEventListener("load",()=>{this.messenger.send("craftile.preview.ready",{}),setTimeout(()=>{this.sendPageData()},0)}),this.messenger.registerFallbackHandler(e=>{const{type:t,payload:n}=e;this.emit(t,n)})}sendPageData(){const e=document.getElementById("page-data");if(e)try{const t=JSON.parse(e.textContent||"{}");this.messenger.send("craftile.preview.page-data",{pageData:t})}catch(t){console.error("Failed to parse page data:",t)}}}var q=11;function ce(o,e){var t=e.attributes,n,i,r,s,l;if(!(e.nodeType===q||o.nodeType===q)){for(var h=t.length-1;h>=0;h--)n=t[h],i=n.name,r=n.namespaceURI,s=n.value,r?(i=n.localName||i,l=o.getAttributeNS(r,i),l!==s&&(n.prefix==="xmlns"&&(i=n.name),o.setAttributeNS(r,i,s))):(l=o.getAttribute(i),l!==s&&o.setAttribute(i,s));for(var u=o.attributes,m=u.length-1;m>=0;m--)n=u[m],i=n.name,r=n.namespaceURI,r?(i=n.localName||i,e.hasAttributeNS(r,i)||o.removeAttributeNS(r,i)):e.hasAttribute(i)||o.removeAttribute(i)}}var A,ae="http://www.w3.org/1999/xhtml",b=typeof document>"u"?void 0:document,de=!!b&&"content"in b.createElement("template"),he=!!b&&b.createRange&&"createContextualFragment"in b.createRange();function fe(o){var e=b.createElement("template");return e.innerHTML=o,e.content.childNodes[0]}function ue(o){A||(A=b.createRange(),A.selectNode(b.body));var e=A.createContextualFragment(o);return e.childNodes[0]}function me(o){var e=b.createElement("body");return e.innerHTML=o,e.childNodes[0]}function pe(o){return o=o.trim(),de?fe(o):he?ue(o):me(o)}function P(o,e){var t=o.nodeName,n=e.nodeName,i,r;return t===n?!0:(i=t.charCodeAt(0),r=n.charCodeAt(0),i<=90&&r>=97?t===n.toUpperCase():r<=90&&i>=97?n===t.toUpperCase():!1)}function ve(o,e){return!e||e===ae?b.createElement(o):b.createElementNS(e,o)}function ge(o,e){for(var t=o.firstChild;t;){var n=t.nextSibling;e.appendChild(t),t=n}return e}function _(o,e,t){o[t]!==e[t]&&(o[t]=e[t],o[t]?o.setAttribute(t,""):o.removeAttribute(t))}var X={OPTION:function(o,e){var t=o.parentNode;if(t){var n=t.nodeName.toUpperCase();n==="OPTGROUP"&&(t=t.parentNode,n=t&&t.nodeName.toUpperCase()),n==="SELECT"&&!t.hasAttribute("multiple")&&(o.hasAttribute("selected")&&!e.selected&&(o.setAttribute("selected","selected"),o.removeAttribute("selected")),t.selectedIndex=-1)}_(o,e,"selected")},INPUT:function(o,e){_(o,e,"checked"),_(o,e,"disabled"),o.value!==e.value&&(o.value=e.value),e.hasAttribute("value")||o.removeAttribute("value")},TEXTAREA:function(o,e){var t=e.value;o.value!==t&&(o.value=t);var n=o.firstChild;if(n){var i=n.nodeValue;if(i==t||!t&&i==o.placeholder)return;n.nodeValue=t}},SELECT:function(o,e){if(!e.hasAttribute("multiple")){for(var t=-1,n=0,i=o.firstChild,r,s;i;)if(s=i.nodeName&&i.nodeName.toUpperCase(),s==="OPTGROUP")r=i,i=r.firstChild,i||(i=r.nextSibling,r=null);else{if(s==="OPTION"){if(i.hasAttribute("selected")){t=n;break}n++}i=i.nextSibling,!i&&r&&(i=r.nextSibling,r=null)}o.selectedIndex=t}}},N=1,Y=11,J=3,Q=8;function k(){}function be(o){if(o)return o.getAttribute&&o.getAttribute("id")||o.id}function Ce(o){return function(t,n,i){if(i||(i={}),typeof n=="string")if(t.nodeName==="#document"||t.nodeName==="HTML"||t.nodeName==="BODY"){var r=n;n=b.createElement("html"),n.innerHTML=r}else n=pe(n);else n.nodeType===Y&&(n=n.firstElementChild);var s=i.getNodeKey||be,l=i.onBeforeNodeAdded||k,h=i.onNodeAdded||k,u=i.onBeforeElUpdated||k,m=i.onElUpdated||k,ke=i.onBeforeNodeDiscarded||k,L=i.onNodeDiscarded||k,Se=i.onBeforeElChildrenUpdated||k,Be=i.skipFromChildren||k,Z=i.addChild||function(c,a){return c.appendChild(a)},z=i.childrenOnly===!0,O=Object.create(null),H=[];function I(c){H.push(c)}function ee(c,a){if(c.nodeType===N)for(var p=c.firstChild;p;){var d=void 0;a&&(d=s(p))?I(d):(L(p),p.firstChild&&ee(p,a)),p=p.nextSibling}}function M(c,a,p){ke(c)!==!1&&(a&&a.removeChild(c),L(c),ee(c,p))}function G(c){if(c.nodeType===N||c.nodeType===Y)for(var a=c.firstChild;a;){var p=s(a);p&&(O[p]=a),G(a),a=a.nextSibling}}G(t);function V(c){h(c);for(var a=c.firstChild;a;){var p=a.nextSibling,d=s(a);if(d){var f=O[d];f&&P(a,f)?(a.parentNode.replaceChild(f,a),D(f,a)):V(a)}else V(a);a=p}}function we(c,a,p){for(;a;){var d=a.nextSibling;(p=s(a))?I(p):M(a,c,!0),a=d}}function D(c,a,p){var d=s(a);if(d&&delete O[d],!p){var f=u(c,a);if(f===!1||(f instanceof HTMLElement&&(c=f,G(c)),o(c,a),m(c),Se(c,a)===!1))return}c.nodeName!=="TEXTAREA"?ye(c,a):X.TEXTAREA(c,a)}function ye(c,a){var p=Be(c,a),d=a.firstChild,f=c.firstChild,x,E,T,$,S;e:for(;d;){for($=d.nextSibling,x=s(d);!p&&f;){if(T=f.nextSibling,d.isSameNode&&d.isSameNode(f)){d=$,f=T;continue e}E=s(f);var F=f.nodeType,B=void 0;if(F===d.nodeType&&(F===N?(x?x!==E&&((S=O[x])?T===S?B=!1:(c.insertBefore(S,f),E?I(E):M(f,c,!0),f=S,E=s(f)):B=!1):E&&(B=!1),B=B!==!1&&P(f,d),B&&D(f,d)):(F===J||F==Q)&&(B=!0,f.nodeValue!==d.nodeValue&&(f.nodeValue=d.nodeValue))),B){d=$,f=T;continue e}E?I(E):M(f,c,!0),f=T}if(x&&(S=O[x])&&P(S,d))p||Z(c,S),D(S,d);else{var K=l(d);K!==!1&&(K&&(d=K),d.actualize&&(d=d.actualize(c.ownerDocument||b)),Z(c,d),V(d))}d=$,f=T}we(c,f,E);var ne=X[c.nodeName];ne&&ne(c,a)}var g=t,R=g.nodeType,te=n.nodeType;if(!z){if(R===N)te===N?P(t,n)||(L(t),g=ge(t,ve(n.nodeName,n.namespaceURI))):g=n;else if(R===J||R===Q){if(te===R)return g.nodeValue!==n.nodeValue&&(g.nodeValue=n.nodeValue),g;g=n}}if(g===n)L(t);else{if(n.isSameNode&&n.isSameNode(g))return;if(D(g,n,z),H)for(var W=0,Oe=H.length;W<Oe;W++){var j=O[H[W]];j&&M(j,j.parentNode,!1)}}return!z&&g!==t&&t.parentNode&&(g.actualize&&(g=g.actualize(t.ownerDocument||b)),t.parentNode.replaceChild(g,t)),g}}var Ee=Ce(ce);class U{constructor(e,t){w(this,"previewClient");w(this,"morphdomOptions");w(this,"elementCache",new Map);w(this,"regionCommentsCache",new Map);w(this,"childrenCommentsCache",new Map);w(this,"pendingScripts",new Set);w(this,"scriptExecutionCount",{total:0,completed:0,failed:0});this.previewClient=e||new le,this.morphdomOptions=t?.morphdom||{},this.previewClient.on("updates.effects",this.handleEffects.bind(this)),this.previewClient.on("craftile.editor.updates",this.handleDirectUpdates.bind(this)),this.cacheRegionComments(),this.cacheChildrenComments()}static init(e,t){return new U(e,t)}getElementCached(e){if(this.elementCache.has(e)){const n=this.elementCache.get(e);if(n.isConnected)return n;this.elementCache.delete(e)}const t=document.querySelector(`[data-block="${e}"]`);return t&&this.elementCache.set(e,t),t}cacheRegionComments(){const e=document.createTreeWalker(document.body,NodeFilter.SHOW_COMMENT,null);let t;const n=new Map;for(;t=e.nextNode();){const i=t.textContent?.trim();if(i){if(i.startsWith("BEGIN region: ")){const r=i.substring(14);n.set(r,t)}else if(i.startsWith("END region: ")){const r=i.substring(12),s=n.get(r);s&&(this.regionCommentsCache.set(r,{begin:s,end:t}),n.delete(r))}}}}cacheChildrenComments(){const e=document.createTreeWalker(document.body,NodeFilter.SHOW_COMMENT,null);let t;const n=new Map;for(;t=e.nextNode();){const i=t.textContent?.trim();if(i){if(i.startsWith("BEGIN children: ")){const r=i.substring(16);n.set(r,t)}else if(i.startsWith("END children: ")){const r=i.substring(14),s=n.get(r);s&&(this.childrenCommentsCache.set(r,{begin:s,end:t}),n.delete(r))}}}}cacheChildrenCommentsForBlock(e){const t=this.getElementCached(e);if(!t)return;this.childrenCommentsCache.delete(e);const n=document.createTreeWalker(t,NodeFilter.SHOW_COMMENT,null);let i,r=null;for(;i=n.nextNode();){const s=i.textContent?.trim();if(s){if(s===`BEGIN children: ${e}`)r=i;else if(s===`END children: ${e}`&&r){this.childrenCommentsCache.set(e,{begin:r,end:i});break}}}}invalidateCache(e){[...e.updated,...e.removed].forEach(t=>{this.elementCache.delete(t),this.childrenCommentsCache.delete(t)})}handleEffects(e){const{effects:t,blocks:n,regions:i,changes:r}=e;t&&(this.invalidateCache(r),t.html&&this.handleHtmlEffects(t.html,{blocks:n,regions:i,changes:r}),t.css&&this.handleCssEffects(t.css),t.js&&this.handleJsEffects(t.js))}handleCssEffects(e){for(const t of e)this.injectStyleElement(t)}injectStyleElement(e){const t=document.createElement("div");t.innerHTML=e;const n=t.firstElementChild;if(!n||n.tagName!=="STYLE"&&n.tagName!=="LINK"){console.warn("Invalid CSS element provided:",e);return}const i=n.id;if(i){const r=document.getElementById(i);if(r&&(r.tagName==="STYLE"||r.tagName==="LINK")){r.parentNode?.replaceChild(n,r);return}}if(n.tagName==="STYLE"&&!i){const r=n.textContent?.trim();if(r){const s=document.querySelectorAll("style:not([id])");for(const l of s)if(l.textContent?.trim()===r)return}}if(n.tagName==="LINK"&&!i){const r=n.getAttribute("href"),s=n.getAttribute("rel");if(r){const l=document.querySelectorAll("link:not([id])");for(const h of l)if(h.getAttribute("href")===r&&h.getAttribute("rel")===s)return}}document.head.appendChild(n)}handleJsEffects(e){this.pendingScripts.clear(),this.scriptExecutionCount={total:0,completed:0,failed:0};const t=e.filter(n=>n?.trim());if(this.scriptExecutionCount.total=t.length,t.length===0){this.emitScriptExecutionComplete();return}for(const n of t)this.injectScriptElement(n)}injectScriptElement(e){const t=document.createElement("div");t.innerHTML=e;const n=t.firstElementChild;if(!n||n.tagName!=="SCRIPT"){console.warn("Invalid script element provided:",e),this.onScriptCompleted(!1);return}const i=n.id;if(i){const r=document.getElementById(i);if(r&&r.tagName==="SCRIPT"){this.pendingScripts.delete(r),r.parentNode?.replaceChild(n,r),this.trackScriptExecution(n);return}}if(!n.src&&!i){const r=n.textContent?.trim();if(r){const s=document.querySelectorAll("script:not([src]):not([id])");for(const l of s)if(l.textContent?.trim()===r){this.onScriptCompleted(!0);return}}}if(n.src&&!i){const r=n.src,s=document.querySelectorAll("script[src]:not([id])");for(const l of s)if(l.src===r){this.onScriptCompleted(!0);return}}document.head.appendChild(n),this.trackScriptExecution(n)}trackScriptExecution(e){if(e.src){this.pendingScripts.add(e);const t=()=>{this.pendingScripts.delete(e),this.onScriptCompleted(!0),e.removeEventListener("load",t),e.removeEventListener("error",n)},n=()=>{this.pendingScripts.delete(e),this.onScriptCompleted(!1),e.removeEventListener("load",t),e.removeEventListener("error",n)};e.addEventListener("load",t),e.addEventListener("error",n)}else this.onScriptCompleted(!0)}onScriptCompleted(e){e?this.scriptExecutionCount.completed++:this.scriptExecutionCount.failed++,this.scriptExecutionCount.completed+this.scriptExecutionCount.failed>=this.scriptExecutionCount.total&&this.emitScriptExecutionComplete()}emitScriptExecutionComplete(){this.previewClient.emit("scripts.execution.complete",{total:this.scriptExecutionCount.total,completed:this.scriptExecutionCount.completed,failed:this.scriptExecutionCount.failed,success:this.scriptExecutionCount.failed===0})}handleDirectUpdates(e){const{changes:t}=e;t.moved&&this.handleMoves(e),t.updated.length>0&&this.handleDisabledBlocks(e),t.removed.length>0&&this.handleRemoves(e)}handleMoves(e){const{blocks:t,changes:n}=e;for(const[i,r]of Object.entries(e.changes.moved)){if(r?.toParent&&n.updated?.includes(r?.toParent))continue;if(!this.isValidMoveInstruction(r)){console.warn(`Invalid move instruction for block ${i}:`,r);continue}const s=t[i];this.moveBlockUsingDOM(s,r)}}handleDisabledBlocks(e){const{blocks:t,changes:n}=e;for(const i of n.updated){const r=t[i];if(!r)continue;const l=!!this.getElementCached(i);r.disabled&&l?this.removeBlock(r.id):r.disabled}}handleRemoves(e){const{changes:t}=e;for(const n of t.removed)this.removeBlock(n)}handleHtmlEffects(e,t){const{blocks:n,regions:i}=t;for(const[r,s]of Object.entries(e)){if(!s)continue;const l=n[r];if(!l){console.warn(`Block data not found for ${r}`);continue}if(l.disabled){console.debug(`Skipping disabled block ${r}`);continue}if(!!this.getElementCached(r))this.updateBlockHtml(l,s);else{const m=this.calculatePosition(l,i,n);this.insertBlock(l,s,m)}}}isValidMoveInstruction(e){const t=!!(e.toParent||e.toRegion),n=e.toIndex===void 0||e.toIndex>=0;return t&&n}removeBlock(e){const t=this.getElementCached(e);t?(this.previewClient.emit("block.remove.before",{blockId:e,element:t}),t.remove(),this.elementCache.delete(e),this.previewClient.emit("block.remove.after",{blockId:e,element:t})):console.warn(`Block ${e} not found for removal`)}moveBlockUsingDOM(e,t){const n=this.getElementCached(e.id),{toParent:i,toRegion:r,toIndex:s}=t;if(!n){console.warn(`Block element ${e.id} not found for move operation`);return}if(this.previewClient.emit("block.move.before",{blockId:e.id,blockType:e.type,block:e,element:n,toParent:i,toRegion:r,toIndex:s}),i){const l=this.getElementCached(i);if(!l){console.error(`Parent element ${i} not found for move operation`);return}this.insertElementInContainer(n,l,e.id,s)}else if(r){const l=this.findRegionInsertionPoint(r,s,void 0,void 0,e.id);if(!l){console.error(`Failed to find insertion point for region: ${r}`);return}l.parent.insertBefore(n,l.before)}this.previewClient.emit("block.move.after",{blockId:e.id,blockType:e.type,block:e,element:n,toParent:i,toRegion:r,toIndex:s})}insertElementInContainer(e,t,n,i){const r=t.getAttribute("data-block"),s=r?this.childrenCommentsCache.get(r):null;if(s){const l=this.findPositionBetweenComments(s.begin,s.end,i,n);l.parent.insertBefore(e,l.before)}else{const h=Array.from(t.children).filter(m=>m.getAttribute("data-block")!==n),u=i!==void 0&&i<h.length?h[i]:null;t.insertBefore(e,u)}}insertBlock(e,t,n){if(this.getElementCached(e.id))return;this.previewClient.emit("block.insert.before",{blockId:e.id,blockType:e.type,block:e,html:t,positionInfo:n});const i=this.parseHtmlElement(t,e.id);if(!i)return;const{parentId:r,regionName:s,position:l,afterId:h,beforeId:u}=n;if(r){const m=this.getElementCached(r);if(!m){console.error(`Parent element ${r} not found for block ${e.id}`);return}this.insertElementByPosition(i,m,l,h,u)}else if(s){const m=this.findRegionInsertionPoint(s,l,h,u);if(!m){console.error(`Failed to find insertion point for region: ${s}`);return}m.parent.insertBefore(i,m.before)}else console.warn(`No parent or region specified for block ${e.id}, inserting into body`),document.body.appendChild(i);this.elementCache.set(e.id,i),this.cacheChildrenCommentsForBlock(e.id),i.scrollIntoView({behavior:"smooth",block:"nearest",inline:"nearest"}),this.previewClient.emit("block.insert.after",{blockId:e.id,blockType:e.type,block:e,html:t,positionInfo:n})}updateBlockHtml(e,t){if(!t){console.warn(`No HTML provided for block ${e.id}`);return}const n=this.getElementCached(e.id);if(!n){console.warn(`Block element ${e.id} not found for HTML update`);return}this.previewClient.emit("block.update.before",{blockId:e.id,blockType:e.type,block:e,element:n,html:t}),Ee(n,t,this.morphdomOptions),this.elementCache.delete(e.id);const i=this.getElementCached(e.id);if(!i){console.error(`Block element ${e.id} not found after morphdom update`);return}i!==n&&this.previewClient.inspector.updateTrackedElement(e.id,i),this.cacheChildrenCommentsForBlock(e.id),this.previewClient.emit("block.update.after",{blockId:e.id,blockType:e.type,block:e,element:i,html:t})}insertElementByPosition(e,t,n,i,r){const s=t.getAttribute("data-block"),l=s?this.childrenCommentsCache.get(s):null;if(l){let h=null;if(r)h=this.getElementCached(r);else if(i){const u=this.getElementCached(i);u&&u.nextSibling&&(h=u.nextSibling)}else if(typeof n=="number"){const u=this.findPositionBetweenComments(l.begin,l.end,n);l.begin.parentNode.insertBefore(e,u.before);return}h||(h=l.end),l.begin.parentNode.insertBefore(e,h)}else{let h=null;if(r)h=this.getElementCached(r);else if(i){const u=this.getElementCached(i);u&&(h=u.nextElementSibling)}else typeof n=="number"&&(h=Array.from(t.children)[n]||null);t.insertBefore(e,h)}}findRegionInsertionPoint(e,t,n,i,r){const s=this.regionCommentsCache.get(e);if(!s)return console.error(`Region comments not found for region: ${e}`),null;const{begin:l,end:h}=s;let u=null;if(i){const m=this.getElementCached(i);m&&(u=m)}else if(n){const m=this.getElementCached(n);m&&m.nextSibling&&(u=m.nextSibling)}else typeof t=="number"&&(u=this.findPositionInRegion(l,h,t,r));return u||(u=h),{parent:l.parentNode,before:u}}findPositionInRegion(e,t,n,i){const r=[];let s=e.nextSibling;for(;s&&s!==t;){if(s.nodeType===Node.ELEMENT_NODE&&s.hasAttribute("data-block")){const l=s.getAttribute("data-block");(!i||l!==i)&&r.push(s)}s=s.nextSibling}return n<r.length?r[n]:null}findPositionBetweenComments(e,t,n,i){let r=null;if(typeof n=="number"){const s=[];let l=e.nextSibling;for(;l&&l!==t;){if(l.nodeType===Node.ELEMENT_NODE&&l.hasAttribute("data-block")){const h=l.getAttribute("data-block");(!i||h!==i)&&s.push(l)}l=l.nextSibling}r=n<s.length?s[n]:null}return r||(r=t),{parent:e.parentNode,before:r}}calculatePosition(e,t,n){if(e.parentId){const i=n[e.parentId];i||console.warn(`Block data not found for block ${e.id}`);const r=i.children.indexOf(e.id);if(r===-1)return console.warn(`Block ${e.id} not found in parent ${e.parentId} children`),{parentId:e.parentId};const{afterId:s,beforeId:l}=this.findAdjacentSiblings(i.children,r,n);return{parentId:e.parentId,position:r,afterId:s,beforeId:l}}else{for(const i of t){const r=i.blocks.indexOf(e.id);if(r!==-1){const{afterId:s,beforeId:l}=this.findAdjacentSiblings(i.blocks,r,n);return{regionName:i.name,position:r,afterId:s,beforeId:l}}}return{}}}findAdjacentSiblings(e,t,n){let i,r;for(let s=t-1;s>=0;s--){const l=n[e[s]];if(l&&!l.disabled){i=e[s];break}}for(let s=t+1;s<e.length;s++){const l=n[e[s]];if(l&&!l.disabled){r=e[s];break}}return{afterId:i,beforeId:r}}parseHtmlElement(e,t){if(!e.trim())return console.error(`Empty HTML provided for block ${t}`),null;const n=document.createElement("div");n.innerHTML=e;const i=n.firstElementChild;return i||(console.error(`Invalid HTML for block ${t}: no element found`),null)}}return U})();
|
package/dist/index.d.ts
CHANGED
|
@@ -11,6 +11,8 @@ export default class RawHtmlRenderer {
|
|
|
11
11
|
private elementCache;
|
|
12
12
|
private regionCommentsCache;
|
|
13
13
|
private childrenCommentsCache;
|
|
14
|
+
private pendingScripts;
|
|
15
|
+
private scriptExecutionCount;
|
|
14
16
|
constructor(previewClient?: PreviewClient, options?: HtmlPreviewClientOptions);
|
|
15
17
|
static init(previewClient?: PreviewClient, options?: HtmlPreviewClientOptions): RawHtmlRenderer;
|
|
16
18
|
private getElementCached;
|
|
@@ -19,6 +21,13 @@ export default class RawHtmlRenderer {
|
|
|
19
21
|
private cacheChildrenCommentsForBlock;
|
|
20
22
|
private invalidateCache;
|
|
21
23
|
private handleEffects;
|
|
24
|
+
private handleCssEffects;
|
|
25
|
+
private injectStyleElement;
|
|
26
|
+
private handleJsEffects;
|
|
27
|
+
private injectScriptElement;
|
|
28
|
+
private trackScriptExecution;
|
|
29
|
+
private onScriptCompleted;
|
|
30
|
+
private emitScriptExecutionComplete;
|
|
22
31
|
private handleDirectUpdates;
|
|
23
32
|
private handleMoves;
|
|
24
33
|
private handleDisabledBlocks;
|
package/dist/index.js
CHANGED
|
@@ -10,6 +10,8 @@ class RawHtmlRenderer {
|
|
|
10
10
|
__publicField(this, "elementCache", /* @__PURE__ */ new Map());
|
|
11
11
|
__publicField(this, "regionCommentsCache", /* @__PURE__ */ new Map());
|
|
12
12
|
__publicField(this, "childrenCommentsCache", /* @__PURE__ */ new Map());
|
|
13
|
+
__publicField(this, "pendingScripts", /* @__PURE__ */ new Set());
|
|
14
|
+
__publicField(this, "scriptExecutionCount", { total: 0, completed: 0, failed: 0 });
|
|
13
15
|
this.previewClient = previewClient || new PreviewClient();
|
|
14
16
|
this.morphdomOptions = options?.morphdom || {};
|
|
15
17
|
this.previewClient.on("updates.effects", this.handleEffects.bind(this));
|
|
@@ -124,6 +126,155 @@ class RawHtmlRenderer {
|
|
|
124
126
|
if (effects.html) {
|
|
125
127
|
this.handleHtmlEffects(effects.html, { blocks, regions, changes });
|
|
126
128
|
}
|
|
129
|
+
if (effects.css) {
|
|
130
|
+
this.handleCssEffects(effects.css);
|
|
131
|
+
}
|
|
132
|
+
if (effects.js) {
|
|
133
|
+
this.handleJsEffects(effects.js);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
handleCssEffects(cssEffects) {
|
|
137
|
+
for (const styleHtml of cssEffects) {
|
|
138
|
+
this.injectStyleElement(styleHtml);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
injectStyleElement(styleHtml) {
|
|
142
|
+
const temp = document.createElement("div");
|
|
143
|
+
temp.innerHTML = styleHtml;
|
|
144
|
+
const styleElement = temp.firstElementChild;
|
|
145
|
+
if (!styleElement || styleElement.tagName !== "STYLE" && styleElement.tagName !== "LINK") {
|
|
146
|
+
console.warn("Invalid CSS element provided:", styleHtml);
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
const id = styleElement.id;
|
|
150
|
+
if (id) {
|
|
151
|
+
const existing = document.getElementById(id);
|
|
152
|
+
if (existing && (existing.tagName === "STYLE" || existing.tagName === "LINK")) {
|
|
153
|
+
existing.parentNode?.replaceChild(styleElement, existing);
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
if (styleElement.tagName === "STYLE" && !id) {
|
|
158
|
+
const content = styleElement.textContent?.trim();
|
|
159
|
+
if (content) {
|
|
160
|
+
const existingStyles = document.querySelectorAll("style:not([id])");
|
|
161
|
+
for (const existing of existingStyles) {
|
|
162
|
+
if (existing.textContent?.trim() === content) {
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
if (styleElement.tagName === "LINK" && !id) {
|
|
169
|
+
const href = styleElement.getAttribute("href");
|
|
170
|
+
const rel = styleElement.getAttribute("rel");
|
|
171
|
+
if (href) {
|
|
172
|
+
const existingLinks = document.querySelectorAll("link:not([id])");
|
|
173
|
+
for (const existing of existingLinks) {
|
|
174
|
+
if (existing.getAttribute("href") === href && existing.getAttribute("rel") === rel) {
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
document.head.appendChild(styleElement);
|
|
181
|
+
}
|
|
182
|
+
handleJsEffects(jsElements) {
|
|
183
|
+
this.pendingScripts.clear();
|
|
184
|
+
this.scriptExecutionCount = { total: 0, completed: 0, failed: 0 };
|
|
185
|
+
const validScripts = jsElements.filter((jsHtml) => jsHtml?.trim());
|
|
186
|
+
this.scriptExecutionCount.total = validScripts.length;
|
|
187
|
+
if (validScripts.length === 0) {
|
|
188
|
+
this.emitScriptExecutionComplete();
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
for (const jsHtml of validScripts) {
|
|
192
|
+
this.injectScriptElement(jsHtml);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
injectScriptElement(scriptHtml) {
|
|
196
|
+
const temp = document.createElement("div");
|
|
197
|
+
temp.innerHTML = scriptHtml;
|
|
198
|
+
const scriptElement = temp.firstElementChild;
|
|
199
|
+
if (!scriptElement || scriptElement.tagName !== "SCRIPT") {
|
|
200
|
+
console.warn("Invalid script element provided:", scriptHtml);
|
|
201
|
+
this.onScriptCompleted(false);
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
const id = scriptElement.id;
|
|
205
|
+
if (id) {
|
|
206
|
+
const existing = document.getElementById(id);
|
|
207
|
+
if (existing && existing.tagName === "SCRIPT") {
|
|
208
|
+
this.pendingScripts.delete(existing);
|
|
209
|
+
existing.parentNode?.replaceChild(scriptElement, existing);
|
|
210
|
+
this.trackScriptExecution(scriptElement);
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
if (!scriptElement.src && !id) {
|
|
215
|
+
const content = scriptElement.textContent?.trim();
|
|
216
|
+
if (content) {
|
|
217
|
+
const existingScripts = document.querySelectorAll("script:not([src]):not([id])");
|
|
218
|
+
for (const existing of existingScripts) {
|
|
219
|
+
if (existing.textContent?.trim() === content) {
|
|
220
|
+
this.onScriptCompleted(true);
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
if (scriptElement.src && !id) {
|
|
227
|
+
const src = scriptElement.src;
|
|
228
|
+
const existingScripts = document.querySelectorAll("script[src]:not([id])");
|
|
229
|
+
for (const existing of existingScripts) {
|
|
230
|
+
if (existing.src === src) {
|
|
231
|
+
this.onScriptCompleted(true);
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
document.head.appendChild(scriptElement);
|
|
237
|
+
this.trackScriptExecution(scriptElement);
|
|
238
|
+
}
|
|
239
|
+
trackScriptExecution(scriptElement) {
|
|
240
|
+
if (scriptElement.src) {
|
|
241
|
+
this.pendingScripts.add(scriptElement);
|
|
242
|
+
const onLoad = () => {
|
|
243
|
+
this.pendingScripts.delete(scriptElement);
|
|
244
|
+
this.onScriptCompleted(true);
|
|
245
|
+
scriptElement.removeEventListener("load", onLoad);
|
|
246
|
+
scriptElement.removeEventListener("error", onError);
|
|
247
|
+
};
|
|
248
|
+
const onError = () => {
|
|
249
|
+
this.pendingScripts.delete(scriptElement);
|
|
250
|
+
this.onScriptCompleted(false);
|
|
251
|
+
scriptElement.removeEventListener("load", onLoad);
|
|
252
|
+
scriptElement.removeEventListener("error", onError);
|
|
253
|
+
};
|
|
254
|
+
scriptElement.addEventListener("load", onLoad);
|
|
255
|
+
scriptElement.addEventListener("error", onError);
|
|
256
|
+
} else {
|
|
257
|
+
this.onScriptCompleted(true);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
onScriptCompleted(success) {
|
|
261
|
+
if (success) {
|
|
262
|
+
this.scriptExecutionCount.completed++;
|
|
263
|
+
} else {
|
|
264
|
+
this.scriptExecutionCount.failed++;
|
|
265
|
+
}
|
|
266
|
+
const totalProcessed = this.scriptExecutionCount.completed + this.scriptExecutionCount.failed;
|
|
267
|
+
if (totalProcessed >= this.scriptExecutionCount.total) {
|
|
268
|
+
this.emitScriptExecutionComplete();
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
emitScriptExecutionComplete() {
|
|
272
|
+
this.previewClient.emit("scripts.execution.complete", {
|
|
273
|
+
total: this.scriptExecutionCount.total,
|
|
274
|
+
completed: this.scriptExecutionCount.completed,
|
|
275
|
+
failed: this.scriptExecutionCount.failed,
|
|
276
|
+
success: this.scriptExecutionCount.failed === 0
|
|
277
|
+
});
|
|
127
278
|
}
|
|
128
279
|
handleDirectUpdates(data) {
|
|
129
280
|
const { changes } = data;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@craftile/preview-client-html",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "HTML preview client for static block rendering in Craftile",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"craftile",
|
|
@@ -39,8 +39,8 @@
|
|
|
39
39
|
"vite": "^7.0.0",
|
|
40
40
|
"vite-plugin-dts": "^4.5.4",
|
|
41
41
|
"vitest": "^3.2.4",
|
|
42
|
-
"@craftile/preview-client": "0.
|
|
43
|
-
"@craftile/types": "0.
|
|
42
|
+
"@craftile/preview-client": "0.9.0",
|
|
43
|
+
"@craftile/types": "0.9.0"
|
|
44
44
|
},
|
|
45
45
|
"repository": {
|
|
46
46
|
"type": "git",
|