@innovastudio/contentbuilder-interactive-runtime 1.0.9 → 1.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -10754,6 +10754,8 @@ class vn {
|
|
|
10754
10754
|
// Simple on/off for external plugins
|
|
10755
10755
|
trustedDomains: [],
|
|
10756
10756
|
// Optional: whitelist specific domains
|
|
10757
|
+
onReInit: () => {
|
|
10758
|
+
},
|
|
10757
10759
|
...e
|
|
10758
10760
|
}, this.plugins = /* @__PURE__ */ new Map(), this.loadedStyles = /* @__PURE__ */ new Set(), this.components = /* @__PURE__ */ new Map(), this.externalPlugins = /* @__PURE__ */ new Map();
|
|
10759
10761
|
}
|
|
@@ -10846,7 +10848,7 @@ class vn {
|
|
|
10846
10848
|
u.setAttribute("data-edit-id", h);
|
|
10847
10849
|
}), t.hasAttribute("data-cb-original-content") || t.setAttribute("data-cb-original-content", t.innerHTML);
|
|
10848
10850
|
const d = s.mount(t, r);
|
|
10849
|
-
this.components.set(t, d), this.setupInlineEditing(t, r), t.setAttribute("data-cb-loaded", "true");
|
|
10851
|
+
this.components.set(t, d), this.setupInlineEditing(t, r), t.setAttribute("data-cb-loaded", "true"), typeof t.mount == "function" && t.mount();
|
|
10850
10852
|
} catch (r) {
|
|
10851
10853
|
console.error(`[PluginManager] Failed to mount component "${n}":`, r);
|
|
10852
10854
|
}
|
|
@@ -10894,13 +10896,13 @@ class vn {
|
|
|
10894
10896
|
const s = (r, o) => {
|
|
10895
10897
|
const a = e.getAttribute("data-cb-original-content");
|
|
10896
10898
|
if (!a) return;
|
|
10897
|
-
const
|
|
10898
|
-
|
|
10899
|
-
const
|
|
10900
|
-
if (
|
|
10901
|
-
|
|
10902
|
-
const
|
|
10903
|
-
e.setAttribute("data-cb-original-content",
|
|
10899
|
+
const d = document.createElement("template");
|
|
10900
|
+
d.innerHTML = a.trim();
|
|
10901
|
+
const l = d.content.querySelector(`[data-edit-id="${r}"]`);
|
|
10902
|
+
if (l) {
|
|
10903
|
+
l.innerHTML = o;
|
|
10904
|
+
const h = d.innerHTML;
|
|
10905
|
+
e.setAttribute("data-cb-original-content", h);
|
|
10904
10906
|
}
|
|
10905
10907
|
};
|
|
10906
10908
|
i.forEach((r) => {
|
|
@@ -10990,19 +10992,24 @@ class vn {
|
|
|
10990
10992
|
try {
|
|
10991
10993
|
const u = this.parseOptions(o);
|
|
10992
10994
|
let l = o.querySelector(".grid-sortable");
|
|
10993
|
-
l || o.classList.contains("grid-sortable") && (l = o), l && Array.from(l.children).forEach((b, w) => {
|
|
10995
|
+
if (l || o.classList.contains("grid-sortable") && (l = o), l && Array.from(l.children).forEach((b, w) => {
|
|
10994
10996
|
b.nodeType === 1 && b.tagName !== "STYLE" && b.tagName !== "SCRIPT" && b.setAttribute("data-index", w);
|
|
10995
10997
|
}), o.querySelectorAll(".edit").forEach((b, w) => {
|
|
10996
10998
|
const _ = `content-${Date.now()}-${r}-${w}`;
|
|
10997
10999
|
b.setAttribute("data-edit-id", _);
|
|
10998
|
-
}), o.hasAttribute("data-cb-original-content")
|
|
11000
|
+
}), !o.hasAttribute("data-cb-original-content"))
|
|
11001
|
+
o.setAttribute("data-cb-original-content", o.innerHTML);
|
|
11002
|
+
else {
|
|
11003
|
+
let b = document.createRange();
|
|
11004
|
+
o.innerHTML = "", o.appendChild(b.createContextualFragment(o.getAttribute("data-cb-original-content")));
|
|
11005
|
+
}
|
|
10999
11006
|
const p = await d.mount(o, u);
|
|
11000
|
-
this.components.set(o, p), this.setupInlineEditing(o, u), o.setAttribute("data-cb-loaded", "true"), r++;
|
|
11007
|
+
this.components.set(o, p), this.setupInlineEditing(o, u), o.setAttribute("data-cb-loaded", "true"), typeof o.mount == "function" && o.mount(), r++;
|
|
11001
11008
|
} catch (u) {
|
|
11002
11009
|
console.error(`[PluginManager] Failed to mount component "${a}":`, u);
|
|
11003
11010
|
}
|
|
11004
11011
|
}
|
|
11005
|
-
return this.emit("reinitialized", { container: e, count: r }), r;
|
|
11012
|
+
return typeof this.config.onReInit == "function" && this.config.onReInit(), this.emit("reinitialized", { container: e, count: r }), r;
|
|
11006
11013
|
} finally {
|
|
11007
11014
|
this.reinitializeInProgress = !1;
|
|
11008
11015
|
}
|
|
@@ -508,4 +508,4 @@ ${q.data}
|
|
|
508
508
|
`}}this.tokenInput+=y,this.tokenOutput+=k}return!0}catch(l){return l.name==="AbortError"?this.settings.consoleLog&&console.log("Request aborted by user."):console.error("Error:",l),!1}}async assistant(e,t,i,n){this.controller=new AbortController,this.signal=this.controller.signal;let s=.6,r=.9,o=1;n||(n=[]);let a=this.settings.model;n.length>0&&(a=this.settings.model2);const d={assistantId:this.settings.assistantId,question:e,context:t,system:i,functs:n,temperature:s,topP:r,num:o,model:a,customData:this.settings.customData};try{let u={"Content-Type":"application/json",...this.settings.headers},h=await(await fetch(this.settings.assistantUrl,{signal:this.signal,method:"POST",headers:u,body:JSON.stringify(d)})).json();return h.error?(console.log(`Error:
|
|
509
509
|
`+h.error),!1):(h.usage&&(this.tokenInput+=h.usage.prompt_tokens,this.tokenOutput+=h.usage.completion_tokens),h.answer.content[0].text.value)}catch(u){return u.name==="AbortError"?this.settings.consoleLog&&console.log("Request aborted by user."):console.error("Error:",u),!1}}async assistantStream(e,t,i,n,s){this.controller=new AbortController,this.signal=this.controller.signal;let r=.6,o=.9,a=1;n||(n=[]);const d={assistantId:this.settings.assistantId,question:e,context:t,system:i,functs:n,temperature:r,topP:o,num:a,model:this.settings.model,customData:this.settings.customData};try{let u={"Content-Type":"application/json",...this.settings.headers};const l=await fetch(this.settings.assistantStreamUrl,{signal:this.signal,method:"POST",headers:u,body:JSON.stringify(d)});if(!l.ok)return console.error("Error:",l.statusText),!1;const h=l.body.getReader(),p=new TextDecoder;let b="",w=!1;for(;!w;){const{done:_,value:g}=await h.read();if(w=_,w)break;const v=p.decode(g,{stream:!0});b+=v;const f=b.split(`
|
|
510
510
|
`);b="";for(const m of f)if(m.trim()!=="")if(m.startsWith("data:")){const y=m.slice(5).trim();y==="[DONE]"&&this.settings.consoleLog&&console.log("Stream completed.");try{const k=JSON.parse(y);if(k.choices&&k.choices[0].delta&&k.choices[0].delta.content){const x=k.choices[0].delta.content;s&&s(x)}}catch{b+=m+`
|
|
511
|
-
`}}else{const y=JSON.parse(m);this.tokenInput+=y.prompt_tokens,this.tokenOutput+=y.completion_tokens;break}}return!0}catch(u){return u.name==="AbortError"?this.settings.consoleLog&&console.log("Request aborted by user."):console.error("Error:",u),!1}}hexToRgb(e){const t=e.replace("#",""),i=parseInt(t,16),n=i>>16&255,s=i>>8&255,r=i&255;return{red:n,green:s,blue:r}}getId(e="id"){return`${e}-${Math.random().toString(36).substr(2,9)}`}appendHtml(e,t){e&&t&&e.insertAdjacentHTML("beforeend",t)}cleanup(){if(this.element){let e=this.element.querySelectorAll('input[type="text"], input[type="number"], input[type="email"], input[type="tel"], input[type="url"], textarea');e.forEach(t=>{t.removeEventListener("input",this.inputListener)}),e=this.element.querySelectorAll('input[type="date"], input[type="radio"], input[type="checkbox"]'),e.forEach(t=>{t.removeEventListener("change",this.changeListener)}),this.debounceTimeout&&(clearTimeout(this.debounceTimeout),this.debounceTimeout=null)}}destroy(){try{if(this._scrollListener){let e;this.settings.isBuilder?e=document.querySelector(this.settings.previewSelector):e=this.element;const t=e.querySelector(".submit-container"),i=this.getScrollableParent(t);i?i.removeEventListener("scroll",this._scrollListener):window.removeEventListener("scroll",this._scrollListener),window.removeEventListener("resize",this._scrollListener)}}catch{}this.element&&(this.cleanup(),this.element.innerHTML="",this.element=null);for(const e in this.listeners)this.listeners[e].clear();this.listeners={}}out(e){let t=this.settings.lang[e];return t||e}}class mn{constructor(e={}){this.config={plugins:{},autoLoad:!0,pluginBaseUrl:"",allowExternalPlugins:!0,trustedDomains:[],...e},this.plugins=new Map,this.loadedStyles=new Set,this.components=new Map,this.externalPlugins=new Map}async autoLoadPlugins(){const t=this.detectComponentTypes().filter(i=>this.config.plugins[i]&&!this.plugins.has(i));return t.length>0&&await Promise.all(t.map(i=>this.loadPlugin(i))),t}detectComponentTypes(){const e=new Set;return document.querySelectorAll("[data-cb-type]").forEach(t=>{e.add(t.dataset.cbType)}),document.querySelectorAll('[class*="cb-"]').forEach(t=>{t.classList.forEach(i=>{if(i.startsWith("cb-")){const n=i.replace("cb-","");e.add(n)}})}),Array.from(e)}async loadPlugin(e){if(this.plugins.has(e))return this.plugins.get(e);const t=this.config.plugins[e];if(!t)return console.warn(`[PluginManager] Plugin "${e}" not found in registry`),null;try{t.css&&this.loadCSS(this.resolveUrl(t.css));const i=this.resolveUrl(t.url),n=await this.importModule(i),s=n.default||n;return this.plugins.set(e,s),typeof s.init=="function"&&await s.init(this),this.emit("plugin-loaded",{name:e,plugin:s}),s}catch(i){return console.error(`[PluginManager] Failed to load plugin "${e}":`,i),null}}async importModule(e){return import(e)}loadCSS(e){if(this.loadedStyles.has(e))return;const t=document.createElement("link");t.rel="stylesheet",t.href=e,t.onload=()=>{this.emit("css-loaded",{url:e})},t.onerror=()=>{console.error(`[PluginManager] Failed to load CSS: ${e}`)},document.head.appendChild(t),this.loadedStyles.add(e)}resolveUrl(e){return e.startsWith("http://")||e.startsWith("https://")||e.startsWith("//")?e:this.config.pluginBaseUrl+e}initializeComponents(){return document.querySelectorAll("[data-cb-type]").forEach((t,i)=>{const n=t.dataset.cbType,s=this.plugins.get(n);if(s&&typeof s.mount=="function")try{const r=this.parseOptions(t);let o=t.querySelector(".grid-sortable");o||t.classList.contains("grid-sortable")&&(o=t),o&&Array.from(o.children).forEach((u,l)=>{u.nodeType===1&&u.tagName!=="STYLE"&&u.tagName!=="SCRIPT"&&u.setAttribute("data-index",l)}),t.querySelectorAll(".edit").forEach((u,l)=>{const h=`content-${Date.now()}-${i}-${l}`;u.setAttribute("data-edit-id",h)}),t.hasAttribute("data-cb-original-content")||t.setAttribute("data-cb-original-content",t.innerHTML);const d=s.mount(t,r);this.components.set(t,d),this.setupInlineEditing(t,r),t.setAttribute("data-cb-loaded","true")}catch(r){console.error(`[PluginManager] Failed to mount component "${n}":`,r)}}),this.components.size}parseOptions(e){const t={};return Array.from(e.attributes).forEach(i=>{if(i.name.startsWith("data-cb-")){const n=i.name.replace("data-cb-","").replace(/-([a-z])/g,(s,r)=>r.toUpperCase());t[n]=this.parseValue(i.value)}}),t}parseValue(e){if(e==="true")return!0;if(e==="false")return!1;if(!isNaN(e)&&e!=="")return Number(e);try{return JSON.parse(e)}catch{return e}}setupInlineEditing(e,t){if(!e.closest(".data-editor"))return;const i=e.querySelectorAll(".edit[data-edit-id]");if(i.length===0)return;e.querySelectorAll('[contenteditable="true"]').forEach(r=>{r.removeAttribute("contenteditable"),r._cbObserver&&(r._cbObserver.disconnect(),delete r._cbObserver)});const s=(r,o)=>{const a=e.getAttribute("data-cb-original-content");if(!a)return;const l=new DOMParser().parseFromString(a,"text/html").body;if(!l)return;const h=l.querySelector(`[data-edit-id="${r}"]`);if(h){h.innerHTML=o;const p=l.innerHTML;e.setAttribute("data-cb-original-content",p)}};i.forEach(r=>{r.setAttribute("contenteditable","true");const o=new MutationObserver(()=>{const a=r.getAttribute("data-edit-id"),d=r.innerHTML;s(a,d)});o.observe(r,{childList:!0,characterData:!0,subtree:!0,attributes:!0,attributeFilter:["style"]}),r._cbObserver=o})}async use(e){return await this.loadPlugin(e)}getPlugin(e){return this.plugins.get(e)}getAllPlugins(){return Array.from(this.plugins.entries())}hasPlugin(e){return this.plugins.has(e)}getComponent(e){return this.components.get(e)}async reinitialize(e=document){if(this.reinitializeInProgress)return clearTimeout(this.pendingReinitialize),new Promise(t=>{this.pendingReinitialize=setTimeout(async()=>{this.pendingReinitialize=null;const i=await this.reinitialize(e);t(i)},100)});this.reinitializeInProgress=!0;try{const t=[];this.components.forEach((o,a)=>{(e===document||e.contains(a))&&t.push({element:a,instance:o})}),t.forEach(({element:o,instance:a})=>{const d=o.dataset.cbType,u=this.plugins.get(d);u&&typeof u.unmount=="function"&&u.unmount(o,a),this.components.delete(o)});const n=this.detectComponentTypesInContainer(e).filter(o=>this.config.plugins[o]&&!this.plugins.has(o));n.length>0&&await Promise.all(n.map(o=>this.loadPlugin(o)));const s=e.querySelectorAll("[data-cb-type]");let r=0;for(const o of s){const a=o.dataset.cbType,d=this.plugins.get(a);if(d&&typeof d.mount=="function")try{const u=this.parseOptions(o);let l=o.querySelector(".grid-sortable");l||o.classList.contains("grid-sortable")&&(l=o),l&&Array.from(l.children).forEach((b,w)=>{b.nodeType===1&&b.tagName!=="STYLE"&&b.tagName!=="SCRIPT"&&b.setAttribute("data-index",w)}),o.querySelectorAll(".edit").forEach((b,w)=>{const _=`content-${Date.now()}-${r}-${w}`;b.setAttribute("data-edit-id",_)}),o.hasAttribute("data-cb-original-content")?o.innerHTML=o.getAttribute("data-cb-original-content"):o.setAttribute("data-cb-original-content",o.innerHTML);const p=await d.mount(o,u);this.components.set(o,p),this.setupInlineEditing(o,u),o.setAttribute("data-cb-loaded","true"),r++}catch(u){console.error(`[PluginManager] Failed to mount component "${a}":`,u)}}return this.emit("reinitialized",{container:e,count:r}),r}finally{this.reinitializeInProgress=!1}}detectComponentTypesInContainer(e){const t=new Set;return e.querySelectorAll("[data-cb-type]").forEach(n=>{t.add(n.dataset.cbType)}),Array.from(t)}async loadExternalPlugin(e,t){if(!e||typeof e!="string")throw new Error("Plugin ID is required and must be a string");if(!t.url)throw new Error("Plugin URL is required");if(this.plugins.has(e))return console.warn(`[PluginManager] Plugin "${e}" is already loaded`),this.plugins.get(e);const i=this.validatePluginSource(t.url);if(!i.allowed)throw new Error(`Security: ${i.reason}`);i.warning&&(console.warn(`[PluginManager] ${i.warning}`),this.emit("plugin-security-warning",{pluginId:e,url:t.url,warning:i.warning}));try{this.config.plugins[e]={url:t.url,css:t.css||null,source:"external",loadedAt:new Date().toISOString()},this.externalPlugins.set(e,this.config.plugins[e]);const n=await this.loadPlugin(e);return this.emit("external-plugin-loaded",{pluginId:e,url:t.url}),n}catch(n){throw delete this.config.plugins[e],this.externalPlugins.delete(e),console.error(`[PluginManager] Failed to load external plugin "${e}":`,n),n}}validatePluginSource(e){const t=e.includes("localhost")||e.includes("127.0.0.1");if(!e.startsWith("https://")&&!t)return{allowed:!1,reason:"Only HTTPS URLs are allowed (except localhost for development)"};if(!this.config.allowExternalPlugins)return{allowed:!1,reason:"External plugins are disabled. Enable allowExternalPlugins in configuration."};if(this.config.trustedDomains.length>0){const n=new URL(e).hostname;if(!this.config.trustedDomains.some(r=>{if(r.startsWith("*.")){const o=r.slice(2);return n===o||n.endsWith("."+o)}return n===r}))return{allowed:!0,warning:`Loading plugin from external domain: ${n}. Only add plugins from sources you trust.`}}else return{allowed:!0,warning:`Loading external plugin from: ${new URL(e).hostname}. This plugin will have full access to your page.`};return{allowed:!0}}async loadExternalPlugins(e){const t=[];for(const[i,n]of Object.entries(e))try{const s=await this.loadExternalPlugin(i,n);t.push({pluginId:i,success:!0,plugin:s})}catch(s){t.push({pluginId:i,success:!1,error:s.message}),console.error(`[PluginManager] Failed to load external plugin "${i}":`,s)}return t}unregisterPlugin(e){if(!this.externalPlugins.has(e))return console.warn(`[PluginManager] Plugin "${e}" is not an external plugin`),!1;const t=this.plugins.get(e),i=[];return this.components.forEach((n,s)=>{s.dataset.cbType===e&&i.push({element:s,instance:n})}),i.forEach(({element:n,instance:s})=>{t&&typeof t.unmount=="function"&&t.unmount(n,s),this.components.delete(n)}),t&&typeof t.destroy=="function"&&t.destroy(this),this.plugins.delete(e),this.externalPlugins.delete(e),delete this.config.plugins[e],this.emit("plugin-unregistered",{pluginId:e}),!0}getExternalPlugins(){return Array.from(this.externalPlugins.entries()).map(([e,t])=>({id:e,...t}))}isExternalPlugin(e){return this.externalPlugins.has(e)}destroy(){this.components.forEach((t,i)=>{const n=i.dataset.cbType,s=this.plugins.get(n);s&&typeof s.unmount=="function"&&s.unmount(i,t)}),element.querySelectorAll('[contenteditable="true"]').forEach(t=>{t.removeAttribute("contenteditable"),t._cbObserver&&(t._cbObserver.disconnect(),delete t._cbObserver)}),this.plugins.forEach((t,i)=>{typeof t.destroy=="function"&&t.destroy(this)}),this.components.clear(),this.plugins.clear()}emit(e,t){if(this.runtime&&typeof this.runtime.emit=="function")this.runtime.emit(e,t);else{const i=new CustomEvent(`contentbox:${e}`,{detail:t});document.dispatchEvent(i)}}setRuntime(e){this.runtime=e}}class bn{constructor(e={}){const t={skin:"light",plugins:{},autoLoadPlugins:!0,pluginBaseUrl:"",allowExternalPlugins:!0,trustedDomains:[]};this.settings={...t,...e},this.initialized=!1,this.pluginManager=new mn({plugins:this.settings.plugins,autoLoad:this.settings.autoLoadPlugins,pluginBaseUrl:this.settings.pluginBaseUrl,allowExternalPlugins:this.settings.allowExternalPlugins,trustedDomains:this.settings.trustedDomains}),this.pluginManager.setRuntime(this),window.Glide=Rs,window.FormViewer=gn}async use(e){return await this.pluginManager.use(e)}getPlugin(e){return this.pluginManager.getPlugin(e)}getPlugins(){return this.pluginManager.getAllPlugins()}hasPlugin(e){return this.pluginManager.hasPlugin(e)}getComponent(e){return this.pluginManager.getComponent(e)}getComponents(){return this.pluginManager.components}async reinitialize(e){const t=await this.pluginManager.reinitialize(e);return this.initCore(),t}async loadExternalPlugin(e,t){return await this.pluginManager.loadExternalPlugin(e,t)}async loadExternalPlugins(e){return await this.pluginManager.loadExternalPlugins(e)}unregisterPlugin(e){return this.pluginManager.unregisterPlugin(e)}emit(e,t){const i=new CustomEvent(`contentbox:${e}`,{detail:t});document.dispatchEvent(i)}on(e,t){document.addEventListener(`contentbox:${e}`,t)}off(e,t){document.removeEventListener(`contentbox:${e}`,t)}init(){this.initialized||(this.initCore(),this.initPlugins(),this.initialized=!0,this.emit("init"))}async initPlugins(){this.settings.autoLoadPlugins&&await this.pluginManager.autoLoadPlugins(),this.pluginManager.initializeComponents()}initCore(){const e={touchNavigation:!0,selector:".glightbox",loop:!0,autoplayVideos:!0,zoomable:!0,slideEffect:"slide",descPosition:"bottom",skin:this.settings.skin};this.refreshLightbox(e),document.querySelectorAll(".is-lightbox,.block-click").forEach(i=>{const n=s=>{let r=i.getAttribute("href")||i.getAttribute("data-modal-url");this.openLightbox(r,i,e),s.preventDefault(),s.stopImmediatePropagation()};i.addEventListener("click",n),i._lightboxHandler=n})}refreshLightbox(e){this.glightbox&&this.glightbox.destroy(),this.glightbox=new jt(e),window.GLightbox=jt.default}openLightbox(e,t,i){let n=[],s=0;if(t){const o=t.closest("[data-gallery]");let a=[];o?a=o.querySelectorAll(".is-lightbox"):document.querySelectorAll(".is-lightbox,.block-click").forEach(u=>{u.closest("[data-gallery]")||a.push(u)}),a.forEach((d,u)=>{let l=d.getAttribute("href");l||(l=d.getAttribute("data-modal-url")),n.push({href:l}),e===l&&(s=u)})}const r=document.activeElement;r?.blur(),n.length>0?(this.glightbox.setElements(n),this.glightbox.openAt(s)):(this.glightbox.setElements([{href:e}]),this.glightbox.open()),this.glightbox.on("close",()=>{this.refreshLightbox(i),r?.focus()})}destroy(){this.glightbox&&(this.glightbox.destroy(),this.glightbox=null),document.querySelectorAll(".is-lightbox,.block-click").forEach(t=>{t._lightboxHandler&&(t.removeEventListener("click",t._lightboxHandler),delete t._lightboxHandler)}),this.pluginManager.destroy(),this.initialized=!1,this.emit("destroy")}}return bn})();
|
|
511
|
+
`}}else{const y=JSON.parse(m);this.tokenInput+=y.prompt_tokens,this.tokenOutput+=y.completion_tokens;break}}return!0}catch(u){return u.name==="AbortError"?this.settings.consoleLog&&console.log("Request aborted by user."):console.error("Error:",u),!1}}hexToRgb(e){const t=e.replace("#",""),i=parseInt(t,16),n=i>>16&255,s=i>>8&255,r=i&255;return{red:n,green:s,blue:r}}getId(e="id"){return`${e}-${Math.random().toString(36).substr(2,9)}`}appendHtml(e,t){e&&t&&e.insertAdjacentHTML("beforeend",t)}cleanup(){if(this.element){let e=this.element.querySelectorAll('input[type="text"], input[type="number"], input[type="email"], input[type="tel"], input[type="url"], textarea');e.forEach(t=>{t.removeEventListener("input",this.inputListener)}),e=this.element.querySelectorAll('input[type="date"], input[type="radio"], input[type="checkbox"]'),e.forEach(t=>{t.removeEventListener("change",this.changeListener)}),this.debounceTimeout&&(clearTimeout(this.debounceTimeout),this.debounceTimeout=null)}}destroy(){try{if(this._scrollListener){let e;this.settings.isBuilder?e=document.querySelector(this.settings.previewSelector):e=this.element;const t=e.querySelector(".submit-container"),i=this.getScrollableParent(t);i?i.removeEventListener("scroll",this._scrollListener):window.removeEventListener("scroll",this._scrollListener),window.removeEventListener("resize",this._scrollListener)}}catch{}this.element&&(this.cleanup(),this.element.innerHTML="",this.element=null);for(const e in this.listeners)this.listeners[e].clear();this.listeners={}}out(e){let t=this.settings.lang[e];return t||e}}class mn{constructor(e={}){this.config={plugins:{},autoLoad:!0,pluginBaseUrl:"",allowExternalPlugins:!0,trustedDomains:[],onReInit:()=>{},...e},this.plugins=new Map,this.loadedStyles=new Set,this.components=new Map,this.externalPlugins=new Map}async autoLoadPlugins(){const t=this.detectComponentTypes().filter(i=>this.config.plugins[i]&&!this.plugins.has(i));return t.length>0&&await Promise.all(t.map(i=>this.loadPlugin(i))),t}detectComponentTypes(){const e=new Set;return document.querySelectorAll("[data-cb-type]").forEach(t=>{e.add(t.dataset.cbType)}),document.querySelectorAll('[class*="cb-"]').forEach(t=>{t.classList.forEach(i=>{if(i.startsWith("cb-")){const n=i.replace("cb-","");e.add(n)}})}),Array.from(e)}async loadPlugin(e){if(this.plugins.has(e))return this.plugins.get(e);const t=this.config.plugins[e];if(!t)return console.warn(`[PluginManager] Plugin "${e}" not found in registry`),null;try{t.css&&this.loadCSS(this.resolveUrl(t.css));const i=this.resolveUrl(t.url),n=await this.importModule(i),s=n.default||n;return this.plugins.set(e,s),typeof s.init=="function"&&await s.init(this),this.emit("plugin-loaded",{name:e,plugin:s}),s}catch(i){return console.error(`[PluginManager] Failed to load plugin "${e}":`,i),null}}async importModule(e){return import(e)}loadCSS(e){if(this.loadedStyles.has(e))return;const t=document.createElement("link");t.rel="stylesheet",t.href=e,t.onload=()=>{this.emit("css-loaded",{url:e})},t.onerror=()=>{console.error(`[PluginManager] Failed to load CSS: ${e}`)},document.head.appendChild(t),this.loadedStyles.add(e)}resolveUrl(e){return e.startsWith("http://")||e.startsWith("https://")||e.startsWith("//")?e:this.config.pluginBaseUrl+e}initializeComponents(){return document.querySelectorAll("[data-cb-type]").forEach((t,i)=>{const n=t.dataset.cbType,s=this.plugins.get(n);if(s&&typeof s.mount=="function")try{const r=this.parseOptions(t);let o=t.querySelector(".grid-sortable");o||t.classList.contains("grid-sortable")&&(o=t),o&&Array.from(o.children).forEach((u,l)=>{u.nodeType===1&&u.tagName!=="STYLE"&&u.tagName!=="SCRIPT"&&u.setAttribute("data-index",l)}),t.querySelectorAll(".edit").forEach((u,l)=>{const h=`content-${Date.now()}-${i}-${l}`;u.setAttribute("data-edit-id",h)}),t.hasAttribute("data-cb-original-content")||t.setAttribute("data-cb-original-content",t.innerHTML);const d=s.mount(t,r);this.components.set(t,d),this.setupInlineEditing(t,r),t.setAttribute("data-cb-loaded","true"),typeof t.mount=="function"&&t.mount()}catch(r){console.error(`[PluginManager] Failed to mount component "${n}":`,r)}}),this.components.size}parseOptions(e){const t={};return Array.from(e.attributes).forEach(i=>{if(i.name.startsWith("data-cb-")){const n=i.name.replace("data-cb-","").replace(/-([a-z])/g,(s,r)=>r.toUpperCase());t[n]=this.parseValue(i.value)}}),t}parseValue(e){if(e==="true")return!0;if(e==="false")return!1;if(!isNaN(e)&&e!=="")return Number(e);try{return JSON.parse(e)}catch{return e}}setupInlineEditing(e,t){if(!e.closest(".data-editor"))return;const i=e.querySelectorAll(".edit[data-edit-id]");if(i.length===0)return;e.querySelectorAll('[contenteditable="true"]').forEach(r=>{r.removeAttribute("contenteditable"),r._cbObserver&&(r._cbObserver.disconnect(),delete r._cbObserver)});const s=(r,o)=>{const a=e.getAttribute("data-cb-original-content");if(!a)return;const d=document.createElement("template");d.innerHTML=a.trim();const l=d.content.querySelector(`[data-edit-id="${r}"]`);if(l){l.innerHTML=o;const h=d.innerHTML;e.setAttribute("data-cb-original-content",h)}};i.forEach(r=>{r.setAttribute("contenteditable","true");const o=new MutationObserver(()=>{const a=r.getAttribute("data-edit-id"),d=r.innerHTML;s(a,d)});o.observe(r,{childList:!0,characterData:!0,subtree:!0,attributes:!0,attributeFilter:["style"]}),r._cbObserver=o})}async use(e){return await this.loadPlugin(e)}getPlugin(e){return this.plugins.get(e)}getAllPlugins(){return Array.from(this.plugins.entries())}hasPlugin(e){return this.plugins.has(e)}getComponent(e){return this.components.get(e)}async reinitialize(e=document){if(this.reinitializeInProgress)return clearTimeout(this.pendingReinitialize),new Promise(t=>{this.pendingReinitialize=setTimeout(async()=>{this.pendingReinitialize=null;const i=await this.reinitialize(e);t(i)},100)});this.reinitializeInProgress=!0;try{const t=[];this.components.forEach((o,a)=>{(e===document||e.contains(a))&&t.push({element:a,instance:o})}),t.forEach(({element:o,instance:a})=>{const d=o.dataset.cbType,u=this.plugins.get(d);u&&typeof u.unmount=="function"&&u.unmount(o,a),this.components.delete(o)});const n=this.detectComponentTypesInContainer(e).filter(o=>this.config.plugins[o]&&!this.plugins.has(o));n.length>0&&await Promise.all(n.map(o=>this.loadPlugin(o)));const s=e.querySelectorAll("[data-cb-type]");let r=0;for(const o of s){const a=o.dataset.cbType,d=this.plugins.get(a);if(d&&typeof d.mount=="function")try{const u=this.parseOptions(o);let l=o.querySelector(".grid-sortable");if(l||o.classList.contains("grid-sortable")&&(l=o),l&&Array.from(l.children).forEach((b,w)=>{b.nodeType===1&&b.tagName!=="STYLE"&&b.tagName!=="SCRIPT"&&b.setAttribute("data-index",w)}),o.querySelectorAll(".edit").forEach((b,w)=>{const _=`content-${Date.now()}-${r}-${w}`;b.setAttribute("data-edit-id",_)}),!o.hasAttribute("data-cb-original-content"))o.setAttribute("data-cb-original-content",o.innerHTML);else{let b=document.createRange();o.innerHTML="",o.appendChild(b.createContextualFragment(o.getAttribute("data-cb-original-content")))}const p=await d.mount(o,u);this.components.set(o,p),this.setupInlineEditing(o,u),o.setAttribute("data-cb-loaded","true"),typeof o.mount=="function"&&o.mount(),r++}catch(u){console.error(`[PluginManager] Failed to mount component "${a}":`,u)}}return typeof this.config.onReInit=="function"&&this.config.onReInit(),this.emit("reinitialized",{container:e,count:r}),r}finally{this.reinitializeInProgress=!1}}detectComponentTypesInContainer(e){const t=new Set;return e.querySelectorAll("[data-cb-type]").forEach(n=>{t.add(n.dataset.cbType)}),Array.from(t)}async loadExternalPlugin(e,t){if(!e||typeof e!="string")throw new Error("Plugin ID is required and must be a string");if(!t.url)throw new Error("Plugin URL is required");if(this.plugins.has(e))return console.warn(`[PluginManager] Plugin "${e}" is already loaded`),this.plugins.get(e);const i=this.validatePluginSource(t.url);if(!i.allowed)throw new Error(`Security: ${i.reason}`);i.warning&&(console.warn(`[PluginManager] ${i.warning}`),this.emit("plugin-security-warning",{pluginId:e,url:t.url,warning:i.warning}));try{this.config.plugins[e]={url:t.url,css:t.css||null,source:"external",loadedAt:new Date().toISOString()},this.externalPlugins.set(e,this.config.plugins[e]);const n=await this.loadPlugin(e);return this.emit("external-plugin-loaded",{pluginId:e,url:t.url}),n}catch(n){throw delete this.config.plugins[e],this.externalPlugins.delete(e),console.error(`[PluginManager] Failed to load external plugin "${e}":`,n),n}}validatePluginSource(e){const t=e.includes("localhost")||e.includes("127.0.0.1");if(!e.startsWith("https://")&&!t)return{allowed:!1,reason:"Only HTTPS URLs are allowed (except localhost for development)"};if(!this.config.allowExternalPlugins)return{allowed:!1,reason:"External plugins are disabled. Enable allowExternalPlugins in configuration."};if(this.config.trustedDomains.length>0){const n=new URL(e).hostname;if(!this.config.trustedDomains.some(r=>{if(r.startsWith("*.")){const o=r.slice(2);return n===o||n.endsWith("."+o)}return n===r}))return{allowed:!0,warning:`Loading plugin from external domain: ${n}. Only add plugins from sources you trust.`}}else return{allowed:!0,warning:`Loading external plugin from: ${new URL(e).hostname}. This plugin will have full access to your page.`};return{allowed:!0}}async loadExternalPlugins(e){const t=[];for(const[i,n]of Object.entries(e))try{const s=await this.loadExternalPlugin(i,n);t.push({pluginId:i,success:!0,plugin:s})}catch(s){t.push({pluginId:i,success:!1,error:s.message}),console.error(`[PluginManager] Failed to load external plugin "${i}":`,s)}return t}unregisterPlugin(e){if(!this.externalPlugins.has(e))return console.warn(`[PluginManager] Plugin "${e}" is not an external plugin`),!1;const t=this.plugins.get(e),i=[];return this.components.forEach((n,s)=>{s.dataset.cbType===e&&i.push({element:s,instance:n})}),i.forEach(({element:n,instance:s})=>{t&&typeof t.unmount=="function"&&t.unmount(n,s),this.components.delete(n)}),t&&typeof t.destroy=="function"&&t.destroy(this),this.plugins.delete(e),this.externalPlugins.delete(e),delete this.config.plugins[e],this.emit("plugin-unregistered",{pluginId:e}),!0}getExternalPlugins(){return Array.from(this.externalPlugins.entries()).map(([e,t])=>({id:e,...t}))}isExternalPlugin(e){return this.externalPlugins.has(e)}destroy(){this.components.forEach((t,i)=>{const n=i.dataset.cbType,s=this.plugins.get(n);s&&typeof s.unmount=="function"&&s.unmount(i,t)}),element.querySelectorAll('[contenteditable="true"]').forEach(t=>{t.removeAttribute("contenteditable"),t._cbObserver&&(t._cbObserver.disconnect(),delete t._cbObserver)}),this.plugins.forEach((t,i)=>{typeof t.destroy=="function"&&t.destroy(this)}),this.components.clear(),this.plugins.clear()}emit(e,t){if(this.runtime&&typeof this.runtime.emit=="function")this.runtime.emit(e,t);else{const i=new CustomEvent(`contentbox:${e}`,{detail:t});document.dispatchEvent(i)}}setRuntime(e){this.runtime=e}}class bn{constructor(e={}){const t={skin:"light",plugins:{},autoLoadPlugins:!0,pluginBaseUrl:"",allowExternalPlugins:!0,trustedDomains:[]};this.settings={...t,...e},this.initialized=!1,this.pluginManager=new mn({plugins:this.settings.plugins,autoLoad:this.settings.autoLoadPlugins,pluginBaseUrl:this.settings.pluginBaseUrl,allowExternalPlugins:this.settings.allowExternalPlugins,trustedDomains:this.settings.trustedDomains}),this.pluginManager.setRuntime(this),window.Glide=Rs,window.FormViewer=gn}async use(e){return await this.pluginManager.use(e)}getPlugin(e){return this.pluginManager.getPlugin(e)}getPlugins(){return this.pluginManager.getAllPlugins()}hasPlugin(e){return this.pluginManager.hasPlugin(e)}getComponent(e){return this.pluginManager.getComponent(e)}getComponents(){return this.pluginManager.components}async reinitialize(e){const t=await this.pluginManager.reinitialize(e);return this.initCore(),t}async loadExternalPlugin(e,t){return await this.pluginManager.loadExternalPlugin(e,t)}async loadExternalPlugins(e){return await this.pluginManager.loadExternalPlugins(e)}unregisterPlugin(e){return this.pluginManager.unregisterPlugin(e)}emit(e,t){const i=new CustomEvent(`contentbox:${e}`,{detail:t});document.dispatchEvent(i)}on(e,t){document.addEventListener(`contentbox:${e}`,t)}off(e,t){document.removeEventListener(`contentbox:${e}`,t)}init(){this.initialized||(this.initCore(),this.initPlugins(),this.initialized=!0,this.emit("init"))}async initPlugins(){this.settings.autoLoadPlugins&&await this.pluginManager.autoLoadPlugins(),this.pluginManager.initializeComponents()}initCore(){const e={touchNavigation:!0,selector:".glightbox",loop:!0,autoplayVideos:!0,zoomable:!0,slideEffect:"slide",descPosition:"bottom",skin:this.settings.skin};this.refreshLightbox(e),document.querySelectorAll(".is-lightbox,.block-click").forEach(i=>{const n=s=>{let r=i.getAttribute("href")||i.getAttribute("data-modal-url");this.openLightbox(r,i,e),s.preventDefault(),s.stopImmediatePropagation()};i.addEventListener("click",n),i._lightboxHandler=n})}refreshLightbox(e){this.glightbox&&this.glightbox.destroy(),this.glightbox=new jt(e),window.GLightbox=jt.default}openLightbox(e,t,i){let n=[],s=0;if(t){const o=t.closest("[data-gallery]");let a=[];o?a=o.querySelectorAll(".is-lightbox"):document.querySelectorAll(".is-lightbox,.block-click").forEach(u=>{u.closest("[data-gallery]")||a.push(u)}),a.forEach((d,u)=>{let l=d.getAttribute("href");l||(l=d.getAttribute("data-modal-url")),n.push({href:l}),e===l&&(s=u)})}const r=document.activeElement;r?.blur(),n.length>0?(this.glightbox.setElements(n),this.glightbox.openAt(s)):(this.glightbox.setElements([{href:e}]),this.glightbox.open()),this.glightbox.on("close",()=>{this.refreshLightbox(i),r?.focus()})}destroy(){this.glightbox&&(this.glightbox.destroy(),this.glightbox=null),document.querySelectorAll(".is-lightbox,.block-click").forEach(t=>{t._lightboxHandler&&(t.removeEventListener("click",t._lightboxHandler),delete t._lightboxHandler)}),this.pluginManager.destroy(),this.initialized=!1,this.emit("destroy")}}return bn})();
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@innovastudio/contentbuilder-interactive-runtime",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.10",
|
|
5
5
|
"description": "Runtime libraries for ContentBuilder generated content",
|
|
6
6
|
"main": "dist/contentbuilder-interactive-runtime.esm.js",
|
|
7
7
|
"module": "dist/contentbuilder-interactive-runtime.esm.js",
|