@innovastudio/contentbuilder-interactive-runtime 1.0.11 → 1.0.13
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.
|
@@ -10916,7 +10916,7 @@ class vn {
|
|
|
10916
10916
|
if ((u.ctrlKey || u.metaKey) && u.which === 65) {
|
|
10917
10917
|
let l;
|
|
10918
10918
|
try {
|
|
10919
|
-
window.getSelection ? l = window.getSelection().getRangeAt(0).commonAncestorContainer.parentNode : document.selection && (l = document.selection.createRange().parentElement()), o(l), u.preventDefault();
|
|
10919
|
+
window.getSelection ? l = window.getSelection().getRangeAt(0).commonAncestorContainer.parentNode : document.selection && (l = document.selection.createRange().parentElement()), o(l), u.preventDefault(), u.stopImmediatePropagation();
|
|
10920
10920
|
} catch {
|
|
10921
10921
|
}
|
|
10922
10922
|
}
|
|
@@ -10933,10 +10933,9 @@ class vn {
|
|
|
10933
10933
|
// Text content changes
|
|
10934
10934
|
subtree: !0,
|
|
10935
10935
|
// Watch all descendants
|
|
10936
|
-
attributes: !0
|
|
10936
|
+
attributes: !0
|
|
10937
10937
|
// Attribute changes
|
|
10938
|
-
attributeFilter: [
|
|
10939
|
-
// Specifically watch style (color picker)
|
|
10938
|
+
// attributeFilter: ['style'] // Specifically watch style (color picker)
|
|
10940
10939
|
}), r._cbObserver = d;
|
|
10941
10940
|
});
|
|
10942
10941
|
}
|
|
@@ -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,s){this.controller=new AbortController,this.signal=this.controller.signal;let n=.6,r=.9,o=1;s||(s=[]);let a=this.settings.model;s.length>0&&(a=this.settings.model2);const d={assistantId:this.settings.assistantId,question:e,context:t,system:i,functs:s,temperature:n,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,s,n){this.controller=new AbortController,this.signal=this.controller.signal;let r=.6,o=.9,a=1;s||(s=[]);const d={assistantId:this.settings.assistantId,question:e,context:t,system:i,functs:s,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;n&&n(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),s=i>>16&255,n=i>>8&255,r=i&255;return{red:s,green:n,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 s=i.replace("cb-","");e.add(s)}})}),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),s=await this.importModule(i),n=s.default||s;return this.plugins.set(e,n),typeof n.init=="function"&&await n.init(this),this.emit("plugin-loaded",{name:e,plugin:n}),n}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 s=t.dataset.cbType,n=this.plugins.get(s);if(n&&typeof n.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=n.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 "${s}":`,r)}}),this.components.size}parseOptions(e){const t={};return Array.from(e.attributes).forEach(i=>{if(i.name.startsWith("data-cb-")){const s=i.name.replace("data-cb-","").replace(/-([a-z])/g,(n,r)=>r.toUpperCase());t[s]=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('.edit[contenteditable="true"]').forEach(r=>{r.removeAttribute("contenteditable"),r._cbObserver&&(r._cbObserver.disconnect(),delete r._cbObserver),r._cbKeydownHandler&&(r.removeEventListener("keydown",r._cbKeydownHandler),delete r._cbKeydownHandler)});const n=(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=u=>{var l=document.createRange();l.selectNodeContents(u);var h=window.getSelection();h.removeAllRanges(),h.addRange(l)},a=u=>{if((u.ctrlKey||u.metaKey)&&u.which===65){let l;try{window.getSelection?l=window.getSelection().getRangeAt(0).commonAncestorContainer.parentNode:document.selection&&(l=document.selection.createRange().parentElement()),o(l),u.preventDefault()}catch{}}};r.addEventListener("keydown",a),r._cbKeydownHandler=a;const d=new MutationObserver(()=>{const u=r.getAttribute("data-edit-id"),l=r.innerHTML;n(u,l)});d.observe(r,{childList:!0,characterData:!0,subtree:!0,attributes:!0,attributeFilter:["style"]}),r._cbObserver=d})}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 s=this.detectComponentTypesInContainer(e).filter(o=>this.config.plugins[o]&&!this.plugins.has(o));s.length>0&&await Promise.all(s.map(o=>this.loadPlugin(o)));const n=e.querySelectorAll("[data-cb-type]");let r=0;for(const o of n){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(s=>{t.add(s.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 s=await this.loadPlugin(e);return this.emit("external-plugin-loaded",{pluginId:e,url:t.url}),s}catch(s){throw delete this.config.plugins[e],this.externalPlugins.delete(e),console.error(`[PluginManager] Failed to load external plugin "${e}":`,s),s}}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 s=new URL(e).hostname;if(!this.config.trustedDomains.some(r=>{if(r.startsWith("*.")){const o=r.slice(2);return s===o||s.endsWith("."+o)}return s===r}))return{allowed:!0,warning:`Loading plugin from external domain: ${s}. 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,s]of Object.entries(e))try{const n=await this.loadExternalPlugin(i,s);t.push({pluginId:i,success:!0,plugin:n})}catch(n){t.push({pluginId:i,success:!1,error:n.message}),console.error(`[PluginManager] Failed to load external plugin "${i}":`,n)}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((s,n)=>{n.dataset.cbType===e&&i.push({element:n,instance:s})}),i.forEach(({element:s,instance:n})=>{t&&typeof t.unmount=="function"&&t.unmount(s,n),this.components.delete(s)}),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((e,t)=>{const i=t.dataset.cbType,s=this.plugins.get(i);s&&typeof s.unmount=="function"&&s.unmount(t,e)}),this.components.forEach((e,t)=>{t.querySelectorAll('.edit[contenteditable="true"]').forEach(s=>{s.removeAttribute("contenteditable"),s._cbObserver&&(s._cbObserver.disconnect(),delete s._cbObserver),s._cbKeydownHandler&&(s.removeEventListener("keydown",s._cbKeydownHandler),delete s._cbKeydownHandler)})}),this.plugins.forEach((e,t)=>{typeof e.destroy=="function"&&e.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 s=n=>{let r=i.getAttribute("href")||i.getAttribute("data-modal-url");this.openLightbox(r,i,e),n.preventDefault(),n.stopImmediatePropagation()};i.addEventListener("click",s),i._lightboxHandler=s})}refreshLightbox(e){this.glightbox&&this.glightbox.destroy(),this.glightbox=new jt(e),window.GLightbox=jt.default}openLightbox(e,t,i){let s=[],n=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")),s.push({href:l}),e===l&&(n=u)})}const r=document.activeElement;r?.blur(),s.length>0?(this.glightbox.setElements(s),this.glightbox.openAt(n)):(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),s=i>>16&255,n=i>>8&255,r=i&255;return{red:s,green:n,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 s=i.replace("cb-","");e.add(s)}})}),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),s=await this.importModule(i),n=s.default||s;return this.plugins.set(e,n),typeof n.init=="function"&&await n.init(this),this.emit("plugin-loaded",{name:e,plugin:n}),n}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 s=t.dataset.cbType,n=this.plugins.get(s);if(n&&typeof n.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=n.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 "${s}":`,r)}}),this.components.size}parseOptions(e){const t={};return Array.from(e.attributes).forEach(i=>{if(i.name.startsWith("data-cb-")){const s=i.name.replace("data-cb-","").replace(/-([a-z])/g,(n,r)=>r.toUpperCase());t[s]=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('.edit[contenteditable="true"]').forEach(r=>{r.removeAttribute("contenteditable"),r._cbObserver&&(r._cbObserver.disconnect(),delete r._cbObserver),r._cbKeydownHandler&&(r.removeEventListener("keydown",r._cbKeydownHandler),delete r._cbKeydownHandler)});const n=(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=u=>{var l=document.createRange();l.selectNodeContents(u);var h=window.getSelection();h.removeAllRanges(),h.addRange(l)},a=u=>{if((u.ctrlKey||u.metaKey)&&u.which===65){let l;try{window.getSelection?l=window.getSelection().getRangeAt(0).commonAncestorContainer.parentNode:document.selection&&(l=document.selection.createRange().parentElement()),o(l),u.preventDefault(),u.stopImmediatePropagation()}catch{}}};r.addEventListener("keydown",a),r._cbKeydownHandler=a;const d=new MutationObserver(()=>{const u=r.getAttribute("data-edit-id"),l=r.innerHTML;n(u,l)});d.observe(r,{childList:!0,characterData:!0,subtree:!0,attributes:!0}),r._cbObserver=d})}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 s=this.detectComponentTypesInContainer(e).filter(o=>this.config.plugins[o]&&!this.plugins.has(o));s.length>0&&await Promise.all(s.map(o=>this.loadPlugin(o)));const n=e.querySelectorAll("[data-cb-type]");let r=0;for(const o of n){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(s=>{t.add(s.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 s=await this.loadPlugin(e);return this.emit("external-plugin-loaded",{pluginId:e,url:t.url}),s}catch(s){throw delete this.config.plugins[e],this.externalPlugins.delete(e),console.error(`[PluginManager] Failed to load external plugin "${e}":`,s),s}}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 s=new URL(e).hostname;if(!this.config.trustedDomains.some(r=>{if(r.startsWith("*.")){const o=r.slice(2);return s===o||s.endsWith("."+o)}return s===r}))return{allowed:!0,warning:`Loading plugin from external domain: ${s}. 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,s]of Object.entries(e))try{const n=await this.loadExternalPlugin(i,s);t.push({pluginId:i,success:!0,plugin:n})}catch(n){t.push({pluginId:i,success:!1,error:n.message}),console.error(`[PluginManager] Failed to load external plugin "${i}":`,n)}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((s,n)=>{n.dataset.cbType===e&&i.push({element:n,instance:s})}),i.forEach(({element:s,instance:n})=>{t&&typeof t.unmount=="function"&&t.unmount(s,n),this.components.delete(s)}),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((e,t)=>{const i=t.dataset.cbType,s=this.plugins.get(i);s&&typeof s.unmount=="function"&&s.unmount(t,e)}),this.components.forEach((e,t)=>{t.querySelectorAll('.edit[contenteditable="true"]').forEach(s=>{s.removeAttribute("contenteditable"),s._cbObserver&&(s._cbObserver.disconnect(),delete s._cbObserver),s._cbKeydownHandler&&(s.removeEventListener("keydown",s._cbKeydownHandler),delete s._cbKeydownHandler)})}),this.plugins.forEach((e,t)=>{typeof e.destroy=="function"&&e.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 s=n=>{let r=i.getAttribute("href")||i.getAttribute("data-modal-url");this.openLightbox(r,i,e),n.preventDefault(),n.stopImmediatePropagation()};i.addEventListener("click",s),i._lightboxHandler=s})}refreshLightbox(e){this.glightbox&&this.glightbox.destroy(),this.glightbox=new jt(e),window.GLightbox=jt.default}openLightbox(e,t,i){let s=[],n=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")),s.push({href:l}),e===l&&(n=u)})}const r=document.activeElement;r?.blur(),s.length>0?(this.glightbox.setElements(s),this.glightbox.openAt(n)):(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.13",
|
|
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",
|