@quietsapa/qsl 0.1.2 → 0.1.4
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/CHANGELOG.md +46 -3
- package/README.md +5 -13
- package/dist/qsl.min.js +1 -1
- package/dist/qsl.min.js.map +1 -1
- package/dist/qsl.mjs +15 -15
- package/dist/qsl.mjs.map +1 -1
- package/dist/qsl.slim.min.js +1 -1
- package/dist/qsl.slim.min.js.map +1 -1
- package/package.json +1 -1
- package/src/core.js +7 -1
- package/src/plugins/events.js +36 -14
- package/src/presets/full.js +2 -0
package/dist/qsl.slim.min.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
!function(){"use strict";const e={VERSION:"0.1.2",PREFIX:"qsl-",FLOW_TYPE:{DEFAULT:"default",ORDERED:"ordered"},FLOW_STATE:{READY:"READY",RUNNING:"RUNNING",COMPLETED:"COMPLETED"},FLOW_OPTIONS:{delay:0,priority:0,between:null,trigger:null,condition:null,beforeStart:null,onComplete:null,group:null,paused:!1,preload:!1,fireEvents:!0,depends:[]},EVENTS:{STARTED:"QSL:started",COMPLETED:"QSL:completed",ERROR:"QSL:error",FLOW_STARTED:"QSL:flow:started",FLOW_COMPLETED:"QSL:flow:completed",ALL_COMPLETED:"QSL:all:completed",SKIPPED:"QSL:skipped",DOMREADY:"QSL:domready",LOADED:"QSL:loaded"},LIFECYCLE:{DOMREADY:"interactive"===document.readyState||"complete"===document.readyState,LOADED:!1},CALLBACK:"QSLReady",types:new Map,flows:new Map,flowOptions:new Map,flowGroups:new Map,currentProcessPerFlow:new Map,pendingFlows:new Set,pendingProcesses:new Set,completedProcesses:new Set,loadActions:new Set,initActions:new Set,addProcessFilters:new Set,completedFlowsActions:new Set,flowIdFilters:new Set,conditionHandlers:new Set,triggerHandlers:new Set,processCompleteActions:new Set,allCompleteActions:new Set,resetActions:new Set,handlerCallbacksFilters:new Set,onAllComplete:null,globalResolve:null,logger:null,hasStarted:!1,eventsEnabled:!1,initialized:!1,completing:!1,autoReset:!0,globalBetween:0,async init(){if(this.initialized)return this;const e=document.currentScript;if(window.__QSL__=window.__QSL__||this,"interactive"===document.readyState||"complete"===document.readyState?this.LIFECYCLE.DOMREADY=!0:document.addEventListener("DOMContentLoaded",()=>this.LIFECYCLE.DOMREADY=!0,{once:!0}),"complete"===document.readyState?this.LIFECYCLE.LOADED=!0:window.addEventListener("load",()=>this.LIFECYCLE.LOADED=!0,{once:!0}),this.registerType("console",e=>new Promise(t=>{var s;null==(s=e.onBeforeStart)||s.call(e),setTimeout(()=>{var s;e.message&&this.log(e.message,{timestamp:Date.now()}),null==(s=e.onComplete)||s.call(e),t()},e.delay||0)})),window.addEventListener("QSL:log",e=>this.log(e.detail.type,e.detail.config.id)),window.addEventListener("QSL:error",e=>this.error(e.detail.type,e.detail.error,e.detail.config.id)),this.initActions.size)for(const i of this.initActions)"function"==typeof i&&await i.call(this);this.initialized=!0;const t=e&&e.src?new URL(e.src,document.baseURI):null;if(!t||"true"!==t.searchParams.get("async"))return this;const s=t.searchParams.get("callback")||this.CALLBACK;return"function"==typeof window[s]&&window[s](),this},use(e,...t){return"function"==typeof e&&e(this,...t),this},add(e,t=null){if(!e||"object"!=typeof e)return this;if(e.id=e.id?this.PREFIX+e.id:this.PREFIX+Math.random().toString(36).slice(2),e.skipped=!1,e.type||(e.type="console"),Array.isArray(e.depends)&&(e.depends=[...new Set(e.depends)]),this.addProcessFilters.size)for(const i of this.addProcessFilters)"function"==typeof i&&([t,e]=i.call(this,t,e));const s=this.normalizeFlowId(t);return e.flowId=s,this.getOrCreateFlow(s).push(e),this},async load({between:e=!1}={}){if(!this.hasStarted){this.hasStarted=!0,this.globalBetween=e;for(const e of this.loadActions)"function"==typeof e&&e.call(this);return new Promise(e=>{if(!this.flows.size)return this.reset(),e();this.globalResolve=e,this.processFlows()})}},reset(){if(this.resetActions.size)for(const e of this.resetActions)"function"==typeof e&&e.call(this);return this.flows.clear(),this.flowOptions.clear(),this.flowGroups.clear(),this.pendingFlows.clear(),this.pendingProcesses.clear(),this.completedProcesses.clear(),this.currentProcessPerFlow.clear(),this.onAllComplete=null,this.globalResolve=null,this.hasStarted=!1,this.globalBetween=0,this.log("RESET"),this},destroy(){return this.reset(),this.types.clear(),this.initActions.clear(),this.loadActions.clear(),this.addProcessFilters.clear(),this.completedFlowsActions.clear(),this.flowIdFilters.clear(),this.conditionHandlers.clear(),this.triggerHandlers.clear(),this.processCompleteActions.clear(),this.allCompleteActions.clear(),this.resetActions.clear(),this.handlerCallbacksFilters.clear(),this.logger=null,this.eventsEnabled=!1,this.initialized=!1,this},setLogger(e){return!e||"function"!=typeof e&&"object"!=typeof e||(this.logger=e),this},setOnAllComplete(e){return this.onAllComplete="function"==typeof e?e:null,this},useEvents(){return this.eventsEnabled=!0,this},log(e,...t){this.logger&&"function"==typeof this.logger.log&&this.logger.log(e,...t)},error(e,...t){this.logger&&"function"==typeof this.logger.error&&this.logger.error(e,...t)},fire(e,t){this.eventsEnabled&&this.EVENTS[e]&&window.dispatchEvent(new CustomEvent(this.EVENTS[e],{detail:t}))},normalizeFlowId(e){return!0===e?e=this.FLOW_TYPE.ORDERED:"string"!=typeof e&&(e=this.FLOW_TYPE.DEFAULT),e},registerType(e,t){return"string"!=typeof e||"function"!=typeof t||this.types.set(e,t),this},registerTypes(e){if(!e||"object"!=typeof e)return this;const t=Array.isArray(e)?e:Object.entries(e).map(([e,t])=>"function"==typeof t?{type:e,handler:t}:t);for(const s of t)s&&this.registerType(s.type,s.handler);return this},pauseGroup(e){const t=this.flowGroups.get(e);if(!t)return this;for(const s of t)this.setFlowOptions({paused:!0},s);return this},runGroup(e){const t=this.flowGroups.get(e);if(!t)return this;for(const s of t)this.setFlowOptions({paused:!1},s),this.runFlow(s);return this},runFlow(e,t=!1){const s=this.flows.get(e),i=this.flowOptions.get(e);return s&&i&&i.status===this.FLOW_STATE.READY?(this.processFlows(e,t),this):this},getOrCreateFlow(e){return this.flows.has(e)||(this.flows.set(e,[]),this.flowOptions.set(e,{...this.FLOW_OPTIONS,ordered:e===this.FLOW_TYPE.ORDERED,status:this.FLOW_STATE.READY})),this.flows.get(e)},setFlowOptions(e={},t=null){if(t=this.normalizeFlowId(t),this.getOrCreateFlow(t),!e||"object"!=typeof e)return this;const s=this.flowOptions.get(t);return Array.isArray(e.depends)&&e.depends.length&&(e.depends=[...new Set(e.depends)],e.paused=!0,this.pendingFlows.add(t)),e.group&&(this.flowGroups.has(e.group)||this.flowGroups.set(e.group,new Set),this.flowGroups.get(e.group).add(t)),this.flowOptions.set(t,{...s,...e}),this},checkPendingFlows(){if(this.pendingFlows.size)for(const e of this.pendingFlows){const t=this.flowOptions.get(e);t&&t.depends&&t.depends.every(e=>{const t=this.flowOptions.get(this.normalizeFlowId(e));return t&&t.status===this.FLOW_STATE.COMPLETED})&&(this.setFlowOptions({paused:!1},e),this.pendingFlows.delete(e),this.runFlow(e))}},checkPendingProcesses(){if(this.pendingProcesses.size)for(const e of this.pendingProcesses){const t=e.depends.filter(e=>{const t=Array.from(this.flows.values()).some(t=>t.some(t=>t.id===this.PREFIX+e));return!this.completedProcesses.has(this.PREFIX+e)&&!t});if(t.length){this.pendingProcesses.delete(e),this.log("DEP_NOT_FOUND",e.id,`${t.join(", ")}`),e._depsResolved=!0,e._triggered=!0,e._waitResolve&&e._waitResolve();continue}e.depends.every(e=>this.completedProcesses.has(this.PREFIX+e))&&(this.pendingProcesses.delete(e),e._depsResolved=!0,e._triggered&&e._waitResolve&&e._waitResolve())}},async maybeComplete(){var e;if(!this.hasStarted)return;if(this.pendingFlows.size)for(const i of this.pendingFlows){const e=this.flowOptions.get(i);e&&e.depends&&e.depends.some(e=>!this.flowOptions.has(this.normalizeFlowId(e)))&&(this.setFlowOptions({status:this.FLOW_STATE.COMPLETED},i),this.pendingFlows.delete(i),this.log("FLOW_DEP_SKIPPED",{flow:i,depends:`${e.depends.filter(e=>!this.flowOptions.has(this.normalizeFlowId(e))).join(", ")}`}))}let t=!!this.flowOptions.size&&Array.from(this.flowOptions.values()).every(e=>e.status===this.FLOW_STATE.COMPLETED),s=t;if(this.flows.size&&this.completedFlowsActions.size)for(const i of this.completedFlowsActions)s=i.call(this,t,this.flows,this.flowOptions);if(s&&!this.completing){if(this.completing=!0,this.log("ALL_COMPLETED"),this.fire("ALL_COMPLETED"),null==(e=this.onAllComplete)||e.call(this),null!==this.globalResolve&&this.globalResolve(),this.allCompleteActions.size)for(const e of this.allCompleteActions)"function"==typeof e&&e.call(this);this.autoReset&&this.reset(),this.completing=!1}},processFlows(e=null,t=!1){if(!this.flows.size)return;let s=e?[e]:Array.from(this.flows.keys());if(s.length&&this.flowIdFilters.size)for(const i of this.flowIdFilters)"function"==typeof i&&(s=i.call(this,s));s.sort((e,t)=>{const s=this.flowOptions.get(e),i=this.flowOptions.get(t),o=null!=(null==s?void 0:s.trigger),n=null!=(null==i?void 0:i.trigger);if(o&&!n)return 1;if(!o&&n)return-1;const r=(null==s?void 0:s.priority)||0;return((null==i?void 0:i.priority)||0)-r});for(const i of s){const s=this.flowOptions.get(i);if(s&&s.status!==this.FLOW_STATE.COMPLETED)if(this.getConditionStatus(s.condition))this.setFlowOptions({status:this.FLOW_STATE.COMPLETED},i);else if(!s.paused){if((null===e||e&&!t)&&null!=s.trigger){const e=this.getTriggerFunction(s.trigger,s);if(e){this.setFlowOptions({paused:!0},i);let t=!1;e(()=>{t||(t=!0,this.setFlowOptions({paused:!1},i),this.runFlow(i,!0))});continue}}this.setFlowOptions({status:this.FLOW_STATE.RUNNING},i),(async()=>{var e,t;null==(e=s.beforeStart)||e.call(s),s.delay&&s.delay>0&&await new Promise(e=>setTimeout(e,s.delay));const o=(this.flows.get(i)||[]).slice();if(o.sort((e,t)=>(t.priority||0)-(e.priority||0)),(s.preload||s.prefetch)&&!s.trigger)for(const i of o)if(!i.trigger&&("script"===i.type&&i.src||"style"===i.type&&i.href))try{const e=document.createElement("link");e.rel=s.preload?"preload":"prefetch",e.href=i.src||i.href,e.as="script"===i.type?"script":"style",i.crossOrigin&&(e.crossOrigin=i.crossOrigin),document.head.appendChild(e)}catch(r){this.error("PRELOAD_ERROR",r,i.id)}const n=void 0!==s.between&&null!==s.between?s.between:this.globalBetween;if(s.ordered){let e=Promise.resolve();o.forEach((t,s)=>{e=e.then(async()=>{s>0&&n&&await new Promise(e=>setTimeout(e,n)),await this.run(t)})}),await e}else{const e=o.map(async(e,t)=>(t>0&&n&&await new Promise(e=>setTimeout(e,n)),this.run(e)));await Promise.all(e)}this.setFlowOptions({status:this.FLOW_STATE.COMPLETED},i),null==(t=s.onComplete)||t.call(s),this.checkPendingFlows(),this.maybeComplete()})()}}this.checkPendingFlows(),this.maybeComplete()},async run(e){if(!e._running&&!this.getConditionStatus(e.condition)){if(e._running=!0,e._waitPromise||(e._triggered=!1,e._depsResolved=!1,e._waitPromise=new Promise(t=>e._waitResolve=t)),null!=e.trigger){const t=this.getTriggerFunction(e.trigger,e);t?t(()=>{e._triggered=!0,e._depsResolved&&e._waitResolve()}):e._triggered=!0}else e._triggered=!0;if(Array.isArray(e.depends)&&e.depends.length){const t=e.depends.filter(e=>{const t=Array.from(this.flows.values()).some(t=>t.some(t=>t.id===this.PREFIX+e));return!this.completedProcesses.has(this.PREFIX+e)&&!t});if(t.length)this.log("DEP_NOT_FOUND",e.id,`${t.join(", ")}`),e._depsResolved=!0,e._triggered=!0,e._waitResolve&&e._waitResolve();else{e.depends.every(e=>this.completedProcesses.has(this.PREFIX+e))?(e._depsResolved=!0,e._triggered&&e._waitResolve()):this.pendingProcesses.add(e)}}else e._depsResolved=!0,e._triggered&&e._waitResolve();return await e._waitPromise,this.execute(e)}},getConditionStatus(e){if(null==e)return!1;if(Array.isArray(e))return e.some(e=>this.getConditionStatus(e));if("object"==typeof e&&e.operator){const{operator:t,conditions:s}=e;return!!Array.isArray(s)&&("or"===t?s.every(e=>this.getConditionStatus(e)):"and"===t&&s.some(e=>this.getConditionStatus(e)))}if("function"==typeof e&&!e())return!0;if("boolean"==typeof e&&!e)return!0;if(this.conditionHandlers.size)for(const t of this.conditionHandlers)if("function"==typeof t){const s=t.call(this,e);if(!0===s||!1===s)return s}return!1},getTriggerFunction(e,t){if(null==e)return null;if("function"==typeof e)return t=>e(t);if(Array.isArray(e))return s=>{const i=e.map(e=>this.getTriggerFunction(e,t)).filter(e=>e);if(0===i.length)return void s();let o=0;const n=()=>{++o===i.length&&s()};i.forEach(e=>e(n))};if("object"==typeof e&&e.operator){const{operator:s,triggers:i}=e;return Array.isArray(i)?"or"===s?e=>{const s=i.map(e=>this.getTriggerFunction(e,t)).filter(e=>e);if(0===s.length)return void e();let o=!1;const n=()=>{o||(o=!0,e())};s.forEach(e=>e(n))}:"and"===s?e=>{const s=i.map(e=>this.getTriggerFunction(e,t)).filter(e=>e);if(0===s.length)return void e();let o=0;const n=()=>{++o===s.length&&e()};s.forEach(e=>e(n))}:null:null}if(this.triggerHandlers.size)for(const s of this.triggerHandlers)if("function"==typeof s){const i=s.call(this,e,t);if(i&&"function"==typeof i)return i}return!0===e||"interaction"===e?e=>this.waitForInteraction(e):null},waitForInteraction(e){["click","keydown","wheel","mousedown","mousemove","touchstart"].forEach(t=>window.addEventListener(t,()=>e(),{once:!0,passive:!0}))},async execute(e){const t=async()=>{if(this.processCompleteActions.size)for(const t of this.processCompleteActions)"function"==typeof t&&t.call(this,e);this.completedProcesses.add(e.id),e._running=!1,this.checkPendingProcesses()};if(e.skipped)return this.fire("SKIPPED",{...e,id:e.id}),void t();const s=this.types.get(e.type);if(!s)return this.log("UNKNOWN_TYPE",e.type,e.id),void t();this.fire("STARTED",{...e,id:e.id});const i={};if(this.handlerCallbacksFilters.size)for(const o of this.handlerCallbacksFilters)if("function"==typeof o){const t=o.call(this,e);t&&"object"==typeof t&&Object.assign(i,t)}return s(e,i).then(()=>{this.fire("COMPLETED",{...e,id:e.id}),t()}).catch(()=>{this.fire("ERROR",{...e,id:e.id}),t()})}},t=e=>{window.dispatchEvent(new CustomEvent("QSL:log",{detail:e}))},s=e=>{window.dispatchEvent(new CustomEvent("QSL:error",{detail:e}))},i={type:"script",handler:(e,i)=>((e,i={})=>new Promise(async o=>{var n;const{flowId:r,tag:l,id:a,delay:c,data:d,onBeforeStart:h,onComplete:p,onError:f,footer:u,dom:g,onElement:w,onCustomResolve:E}=e;if(r&&l&&a)try{h&&await h(e),t({tag:l,type:"PROCESS_STARTED",config:e}),c&&await new Promise(e=>setTimeout(e,c));let r=document.createElement(l);if(null==w||w(r,e),null==(n=i.registerProcessElement)||n.call(i,r,e),d&&"object"==typeof d)for(const[e,t]of Object.entries(d))r.setAttribute(`data-${e.replace(/([A-Z])/g,"-$1").toLowerCase().replace(/[^a-z0-9_-]/g,"").replace(/^-/,"")}`,String(t));E||(r.onload=()=>{t({tag:l,type:"PROCESS_COMPLETED",config:e}),null==p||p(),o()}),r.onerror=t=>{s({tag:l,type:"PROCESS_FAILED",config:e}),null==f||f(t),o(t)},g&&(u?document.body:document.head).appendChild(r),null==E||E({el:r,config:e,resolve:o})}catch(y){s({tag:l,type:"PROCESS_FAILED",config:e,error:y}),null==f||f(y),o(y)}else o()}))({...e,tag:"script",dom:!0,onElement:(e,{src:t,module:s,async:i,defer:o,crossOrigin:n,integrity:r,bypassCache:l})=>{s&&(e.type="module"),i&&(e.async=i),o&&(e.defer=o),n&&(e.crossOrigin=n),r&&(e.integrity=r),t&&(e.src=t+((e,t)=>t?(e.includes("?")?"&":"?")+Date.now():"")(t,l))}},i)};e.registerTypes([i]).init()}();
|
|
1
|
+
!function(){"use strict";const e={VERSION:"0.1.4",PREFIX:"qsl-",FLOW_TYPE:{DEFAULT:"default",ORDERED:"ordered"},FLOW_STATE:{READY:"READY",RUNNING:"RUNNING",COMPLETED:"COMPLETED"},FLOW_OPTIONS:{delay:0,priority:0,between:null,trigger:null,condition:null,beforeStart:null,onComplete:null,group:null,paused:!1,preload:!1,fireEvents:!0,depends:[]},EVENTS:{STARTED:"QSL:started",COMPLETED:"QSL:completed",ERROR:"QSL:error",FLOW_STARTED:"QSL:flow:started",FLOW_COMPLETED:"QSL:flow:completed",ALL_COMPLETED:"QSL:all:completed",SKIPPED:"QSL:skipped",DOMREADY:"QSL:domready",LOADED:"QSL:loaded"},LIFECYCLE:{DOMREADY:"interactive"===document.readyState||"complete"===document.readyState,LOADED:!1},CALLBACK:"QSLReady",types:new Map,flows:new Map,flowOptions:new Map,flowGroups:new Map,currentProcessPerFlow:new Map,pendingFlows:new Set,pendingProcesses:new Set,completedProcesses:new Set,loadActions:new Set,initActions:new Set,addProcessFilters:new Set,completedFlowsActions:new Set,flowIdFilters:new Set,conditionHandlers:new Set,triggerHandlers:new Set,processCompleteActions:new Set,allCompleteActions:new Set,resetActions:new Set,handlerCallbacksFilters:new Set,onAllComplete:null,globalResolve:null,logger:null,hasStarted:!1,eventsEnabled:!1,initialized:!1,completing:!1,autoReset:!0,globalBetween:0,async init(){if(this.initialized)return this;const e=document.currentScript;if(window.__QSL__=window.__QSL__||this,"interactive"===document.readyState||"complete"===document.readyState?this.LIFECYCLE.DOMREADY=!0:document.addEventListener("DOMContentLoaded",()=>this.LIFECYCLE.DOMREADY=!0,{once:!0}),"complete"===document.readyState?this.LIFECYCLE.LOADED=!0:window.addEventListener("load",()=>this.LIFECYCLE.LOADED=!0,{once:!0}),this.registerType("console",e=>new Promise(t=>{var s;null==(s=e.onBeforeStart)||s.call(e),setTimeout(()=>{var s;e.message&&this.log(e.message,{timestamp:Date.now()}),null==(s=e.onComplete)||s.call(e),t()},e.delay||0)})),window.addEventListener("QSL:log",e=>this.log(e.detail.type,e.detail.config.id)),window.addEventListener("QSL:error",e=>this.error(e.detail.type,e.detail.error,e.detail.config.id)),this.initActions.size)for(const i of this.initActions)"function"==typeof i&&await i.call(this);this.initialized=!0;const t=e&&e.src?new URL(e.src,document.baseURI):null;if(!t||"true"!==t.searchParams.get("async"))return this;const s=t.searchParams.get("callback")||this.CALLBACK;return"function"==typeof window[s]&&window[s](),this},use(e,...t){return"function"==typeof e&&e(this,...t),this},add(e,t=null){if(!e||"object"!=typeof e)return this;if(e.id=e.id?this.PREFIX+e.id:this.PREFIX+Math.random().toString(36).slice(2),e.skipped=!1,e.type||(e.type="console"),Array.isArray(e.depends)&&(e.depends=[...new Set(e.depends)]),this.addProcessFilters.size)for(const i of this.addProcessFilters)"function"==typeof i&&([t,e]=i.call(this,t,e));const s=this.normalizeFlowId(t);return e.flowId=s,this.getOrCreateFlow(s).push(e),this},async load({between:e=!1}={}){if(!this.hasStarted){this.hasStarted=!0,this.globalBetween=e;for(const e of this.loadActions)"function"==typeof e&&e.call(this);return new Promise(e=>{if(!this.flows.size)return this.reset(),e();this.globalResolve=e,this.processFlows()})}},reset(){if(this.resetActions.size)for(const e of this.resetActions)"function"==typeof e&&e.call(this);return this.flows.clear(),this.flowOptions.clear(),this.flowGroups.clear(),this.pendingFlows.clear(),this.pendingProcesses.clear(),this.completedProcesses.clear(),this.currentProcessPerFlow.clear(),this.onAllComplete=null,this.globalResolve=null,this.hasStarted=!1,this.globalBetween=0,this.log("RESET"),this},destroy(){return this.reset(),this.types.clear(),this.initActions.clear(),this.loadActions.clear(),this.addProcessFilters.clear(),this.completedFlowsActions.clear(),this.flowIdFilters.clear(),this.conditionHandlers.clear(),this.triggerHandlers.clear(),this.processCompleteActions.clear(),this.allCompleteActions.clear(),this.resetActions.clear(),this.handlerCallbacksFilters.clear(),this.logger=null,this.eventsEnabled=!1,this.initialized=!1,this},setLogger(e){return!e||"function"!=typeof e&&"object"!=typeof e||(this.logger=e),this},setOnAllComplete(e){return this.onAllComplete="function"==typeof e?e:null,this},useEvents(){return this.eventsEnabled=!0,this},log(e,...t){this.logger&&"function"==typeof this.logger.log&&this.logger.log(e,...t)},error(e,...t){this.logger&&"function"==typeof this.logger.error&&this.logger.error(e,...t)},fire(e,t){this.eventsEnabled&&this.EVENTS[e]&&window.dispatchEvent(new CustomEvent(this.EVENTS[e],{detail:t}))},normalizeFlowId(e){return!0===e?e=this.FLOW_TYPE.ORDERED:"string"!=typeof e&&(e=this.FLOW_TYPE.DEFAULT),e},registerType(e,t){return"string"!=typeof e||"function"!=typeof t||this.types.set(e,t),this},registerTypes(e){if(!e||"object"!=typeof e)return this;const t=Array.isArray(e)?e:Object.entries(e).map(([e,t])=>"function"==typeof t?{type:e,handler:t}:t);for(const s of t)s&&this.registerType(s.type,s.handler);return this},pauseGroup(e){const t=this.flowGroups.get(e);if(!t)return this;for(const s of t)this.setFlowOptions({paused:!0},s);return this},runGroup(e){const t=this.flowGroups.get(e);if(!t)return this;for(const s of t)this.setFlowOptions({paused:!1},s),this.runFlow(s);return this},runFlow(e,t=!1){const s=this.flows.get(e),i=this.flowOptions.get(e);return s&&i&&i.status===this.FLOW_STATE.READY?(this.processFlows(e,t),this):this},getOrCreateFlow(e){return this.flows.has(e)||(this.flows.set(e,[]),this.flowOptions.set(e,{...this.FLOW_OPTIONS,ordered:e===this.FLOW_TYPE.ORDERED,status:this.FLOW_STATE.READY})),this.flows.get(e)},setFlowOptions(e={},t=null){if(t=this.normalizeFlowId(t),this.getOrCreateFlow(t),!e||"object"!=typeof e)return this;const s=this.flowOptions.get(t);return Array.isArray(e.depends)&&e.depends.length&&(e.depends=[...new Set(e.depends)],e.paused=!0,this.pendingFlows.add(t)),e.group&&(this.flowGroups.has(e.group)||this.flowGroups.set(e.group,new Set),this.flowGroups.get(e.group).add(t)),this.flowOptions.set(t,{...s,...e}),this},checkPendingFlows(){if(this.pendingFlows.size)for(const e of this.pendingFlows){const t=this.flowOptions.get(e);t&&t.depends&&t.depends.every(e=>{const t=this.flowOptions.get(this.normalizeFlowId(e));return t&&t.status===this.FLOW_STATE.COMPLETED})&&(this.setFlowOptions({paused:!1},e),this.pendingFlows.delete(e),this.runFlow(e))}},checkPendingProcesses(){if(this.pendingProcesses.size)for(const e of this.pendingProcesses){const t=e.depends.filter(e=>{const t=Array.from(this.flows.values()).some(t=>t.some(t=>t.id===this.PREFIX+e));return!this.completedProcesses.has(this.PREFIX+e)&&!t});if(t.length){this.pendingProcesses.delete(e),this.log("DEP_NOT_FOUND",e.id,`${t.join(", ")}`),e._depsResolved=!0,e._triggered=!0,e._waitResolve&&e._waitResolve();continue}e.depends.every(e=>this.completedProcesses.has(this.PREFIX+e))&&(this.pendingProcesses.delete(e),e._depsResolved=!0,e._triggered&&e._waitResolve&&e._waitResolve())}},async maybeComplete(){var e;if(!this.hasStarted)return;if(this.pendingFlows.size)for(const i of this.pendingFlows){const e=this.flowOptions.get(i);e&&e.depends&&e.depends.some(e=>!this.flowOptions.has(this.normalizeFlowId(e)))&&(this.setFlowOptions({status:this.FLOW_STATE.COMPLETED},i),this.pendingFlows.delete(i),this.log("FLOW_DEP_SKIPPED",{flow:i,depends:`${e.depends.filter(e=>!this.flowOptions.has(this.normalizeFlowId(e))).join(", ")}`}))}let t=!!this.flowOptions.size&&Array.from(this.flowOptions.values()).every(e=>e.status===this.FLOW_STATE.COMPLETED),s=t;if(this.flows.size&&this.completedFlowsActions.size)for(const i of this.completedFlowsActions)s=i.call(this,t,this.flows,this.flowOptions);if(s&&!this.completing){if(this.completing=!0,this.log("ALL_COMPLETED"),this.fire("ALL_COMPLETED"),null==(e=this.onAllComplete)||e.call(this),null!==this.globalResolve&&this.globalResolve(),this.allCompleteActions.size)for(const e of this.allCompleteActions)"function"==typeof e&&e.call(this);this.autoReset&&this.reset(),this.completing=!1}},processFlows(e=null,t=!1){if(!this.flows.size)return;let s=e?[e]:Array.from(this.flows.keys());if(s.length&&this.flowIdFilters.size)for(const i of this.flowIdFilters)"function"==typeof i&&(s=i.call(this,s));s.sort((e,t)=>{const s=this.flowOptions.get(e),i=this.flowOptions.get(t),o=null!=(null==s?void 0:s.trigger),n=null!=(null==i?void 0:i.trigger);if(o&&!n)return 1;if(!o&&n)return-1;const r=(null==s?void 0:s.priority)||0;return((null==i?void 0:i.priority)||0)-r});for(const i of s){const s=this.flowOptions.get(i);if(s&&s.status!==this.FLOW_STATE.COMPLETED)if(this.getConditionStatus(s.condition))this.setFlowOptions({status:this.FLOW_STATE.COMPLETED},i);else if(!s.paused){if((null===e||e&&!t)&&null!=s.trigger){const e=this.getTriggerFunction(s.trigger,s);if(e){this.setFlowOptions({paused:!0},i);let t=!1;e(()=>{t||(t=!0,this.setFlowOptions({paused:!1},i),this.runFlow(i,!0))});continue}}this.setFlowOptions({status:this.FLOW_STATE.RUNNING},i),(async()=>{var e,t;null==(e=s.beforeStart)||e.call(s),s.delay&&s.delay>0&&await new Promise(e=>setTimeout(e,s.delay));const o=(this.flows.get(i)||[]).slice();if(o.sort((e,t)=>(t.priority||0)-(e.priority||0)),(s.preload||s.prefetch)&&!s.trigger)for(const i of o)if(!i.trigger&&("script"===i.type&&i.src||"style"===i.type&&i.href))try{const e=document.createElement("link");e.rel=s.preload?"preload":"prefetch",e.href=i.src||i.href,e.as="script"===i.type?"script":"style",i.crossOrigin&&(e.crossOrigin=i.crossOrigin),document.head.appendChild(e)}catch(r){this.error("PRELOAD_ERROR",r,i.id)}const n=void 0!==s.between&&null!==s.between?s.between:this.globalBetween;if(s.ordered){let e=Promise.resolve();o.forEach((t,s)=>{e=e.then(async()=>{s>0&&n&&await new Promise(e=>setTimeout(e,n)),await this.run(t)})}),await e}else{const e=o.map(async(e,t)=>(t>0&&n&&await new Promise(e=>setTimeout(e,n)),this.run(e)));await Promise.all(e)}this.setFlowOptions({status:this.FLOW_STATE.COMPLETED},i),null==(t=s.onComplete)||t.call(s),this.checkPendingFlows(),this.maybeComplete()})()}}this.checkPendingFlows(),this.maybeComplete()},async run(e){if(!e._running&&!this.getConditionStatus(e.condition)){if(e._running=!0,e._waitPromise||(e._triggered=!1,e._depsResolved=!1,e._waitPromise=new Promise(t=>e._waitResolve=t)),null!=e.trigger){const t=this.getTriggerFunction(e.trigger,e);t?t(()=>{e._triggered=!0,e._depsResolved&&e._waitResolve()}):e._triggered=!0}else e._triggered=!0;if(Array.isArray(e.depends)&&e.depends.length){const t=e.depends.filter(e=>{const t=Array.from(this.flows.values()).some(t=>t.some(t=>t.id===this.PREFIX+e));return!this.completedProcesses.has(this.PREFIX+e)&&!t});if(t.length)this.log("DEP_NOT_FOUND",e.id,`${t.join(", ")}`),e._depsResolved=!0,e._triggered=!0,e._waitResolve&&e._waitResolve();else{e.depends.every(e=>this.completedProcesses.has(this.PREFIX+e))?(e._depsResolved=!0,e._triggered&&e._waitResolve()):this.pendingProcesses.add(e)}}else e._depsResolved=!0,e._triggered&&e._waitResolve();return await e._waitPromise,this.execute(e)}},getConditionStatus(e){if(null==e)return!1;if(Array.isArray(e))return e.some(e=>this.getConditionStatus(e));if("object"==typeof e&&e.operator){const{operator:t,conditions:s}=e;return!!Array.isArray(s)&&("or"===t?s.every(e=>this.getConditionStatus(e)):"and"===t&&s.some(e=>this.getConditionStatus(e)))}if("function"==typeof e&&!e())return!0;if("boolean"==typeof e&&!e)return!0;if(this.conditionHandlers.size)for(const t of this.conditionHandlers)if("function"==typeof t){const s=t.call(this,e);if(!0===s||!1===s)return s}return!1},getTriggerFunction(e,t){if(null==e)return null;if("function"==typeof e)return t=>e(t);if(Array.isArray(e))return s=>{const i=e.map(e=>this.getTriggerFunction(e,t)).filter(e=>e);if(0===i.length)return void s();let o=0;const n=()=>{++o===i.length&&s()};i.forEach(e=>e(n))};if("object"==typeof e&&e.operator){const{operator:s,triggers:i}=e;return Array.isArray(i)?"or"===s?e=>{const s=i.map(e=>this.getTriggerFunction(e,t)).filter(e=>e);if(0===s.length)return void e();let o=!1;const n=()=>{o||(o=!0,e())};s.forEach(e=>e(n))}:"and"===s?e=>{const s=i.map(e=>this.getTriggerFunction(e,t)).filter(e=>e);if(0===s.length)return void e();let o=0;const n=()=>{++o===s.length&&e()};s.forEach(e=>e(n))}:null:null}if(this.triggerHandlers.size)for(const s of this.triggerHandlers)if("function"==typeof s){const i=s.call(this,e,t);if(i&&"function"==typeof i)return i}return!0===e||"interaction"===e?e=>this.waitForInteraction(e):null},waitForInteraction(e){["click","keydown","wheel","mousedown","mousemove","touchstart"].forEach(t=>window.addEventListener(t,()=>e(),{once:!0,passive:!0}))},async execute(e){const t=async()=>{if(this.processCompleteActions.size)for(const t of this.processCompleteActions)"function"==typeof t&&t.call(this,e);this.completedProcesses.add(e.id),e._running=!1,this.checkPendingProcesses()};if(e.skipped)return this.fire("SKIPPED",{...e,id:e.id}),void t();const s=this.types.get(e.type);if(!s)return this.log("UNKNOWN_TYPE",e.type,e.id),void t();this.fire("STARTED",{...e,id:e.id});const i={};if(this.handlerCallbacksFilters.size)for(const o of this.handlerCallbacksFilters)if("function"==typeof o){const t=o.call(this,e);t&&"object"==typeof t&&Object.assign(i,t)}return s(e,i).then(()=>{this.fire("COMPLETED",{...e,id:e.id}),t()}).catch(()=>{this.fire("ERROR",{...e,id:e.id}),t()})}},t=e=>{window.dispatchEvent(new CustomEvent("QSL:log",{detail:e}))},s=e=>{window.dispatchEvent(new CustomEvent("QSL:error",{detail:e}))},i={type:"script",handler:(e,i)=>((e,i={})=>new Promise(async o=>{var n;const{flowId:r,tag:l,id:a,delay:c,data:d,onBeforeStart:h,onComplete:p,onError:f,footer:u,dom:g,onElement:w,onCustomResolve:E}=e;if(r&&l&&a)try{h&&await h(e),t({tag:l,type:"PROCESS_STARTED",config:e}),c&&await new Promise(e=>setTimeout(e,c));let r=document.createElement(l);if(null==w||w(r,e),null==(n=i.registerProcessElement)||n.call(i,r,e),d&&"object"==typeof d)for(const[e,t]of Object.entries(d))r.setAttribute(`data-${e.replace(/([A-Z])/g,"-$1").toLowerCase().replace(/[^a-z0-9_-]/g,"").replace(/^-/,"")}`,String(t));E||(r.onload=()=>{t({tag:l,type:"PROCESS_COMPLETED",config:e}),null==p||p(),o()}),r.onerror=t=>{s({tag:l,type:"PROCESS_FAILED",config:e}),null==f||f(t),o(t)},g&&(u?document.body:document.head).appendChild(r),null==E||E({el:r,config:e,resolve:o})}catch(y){s({tag:l,type:"PROCESS_FAILED",config:e,error:y}),null==f||f(y),o(y)}else o()}))({...e,tag:"script",dom:!0,onElement:(e,{src:t,module:s,async:i,defer:o,crossOrigin:n,integrity:r,bypassCache:l})=>{s&&(e.type="module"),i&&(e.async=i),o&&(e.defer=o),n&&(e.crossOrigin=n),r&&(e.integrity=r),t&&(e.src=t+((e,t)=>t?(e.includes("?")?"&":"?")+Date.now():"")(t,l))}},i)};e.registerTypes([i]).init()}();
|
|
2
2
|
//# sourceMappingURL=qsl.slim.min.js.map
|
package/dist/qsl.slim.min.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"qsl.slim.min.js","sources":["../src/core.js","../src/types.js","../src/presets/default.js"],"sourcesContent":["export default {\n /**\n * Constants\n */\n VERSION: '0.1.2',\n PREFIX: 'qsl-',\n FLOW_TYPE: {\n DEFAULT: 'default',\n ORDERED: 'ordered',\n },\n FLOW_STATE: { \n READY: 'READY',\n RUNNING: 'RUNNING',\n COMPLETED: 'COMPLETED'\n },\n FLOW_OPTIONS: {\n delay: 0,\n priority: 0,\n between: null,\n trigger: null,\n condition: null,\n beforeStart: null,\n onComplete: null,\n group: null,\n paused: false,\n preload: false,\n fireEvents: true,\n depends: []\n },\n EVENTS: {\n STARTED: 'QSL:started',\n COMPLETED: 'QSL:completed',\n ERROR: 'QSL:error',\n FLOW_STARTED: 'QSL:flow:started',\n FLOW_COMPLETED: 'QSL:flow:completed',\n ALL_COMPLETED: 'QSL:all:completed',\n SKIPPED: 'QSL:skipped',\n DOMREADY: 'QSL:domready',\n LOADED: 'QSL:loaded',\n },\n LIFECYCLE: {\n DOMREADY: document.readyState === 'interactive' || document.readyState === 'complete',\n LOADED: false,\n },\n CALLBACK: 'QSLReady',\n /**\n * Properties\n */\n types: new Map(), // Map to store custom resource types\n flows: new Map(), // Map to store flows\n flowOptions: new Map(), // Map to store flow options\n flowGroups: new Map(), // Map to store flow groups\n currentProcessPerFlow: new Map(), // Map to store current process per flow (flowId -> processId)\n\n pendingFlows: new Set(), // Set to store pending flows\n pendingProcesses: new Set(), // Set to store pending processes\n completedProcesses: new Set(), // Set to store completed processes\n loadActions: new Set(), // Set to store before load triggers\n initActions: new Set(), // Set to store init triggers\n addProcessFilters: new Set(), // Set to store add triggers\n completedFlowsActions: new Set(), // Set to store completed flows actions\n flowIdFilters: new Set(), // Set to store flowId filters\n conditionHandlers: new Set(), // Set to store condition handlers\n triggerHandlers: new Set(), // Set to store trigger handlers\n processCompleteActions: new Set(), // Set to store process completion actions\n allCompleteActions: new Set(), // Set to store all flows completion actions\n resetActions: new Set(), // Set to store reset actions\n handlerCallbacksFilters: new Set(), // Set to store handler callbacks filters\n\n onAllComplete: null, // Callback for all flows completion\n globalResolve: null, // Global resolve function\n logger: null, // Logger instance\n\n hasStarted: false, // Flag to check if QSL has started,\n eventsEnabled: false, // Flag to check if events are enabled\n initialized: false, // Flag to check if QSL is initialized\n completing: false, // Flag to check if QSL is completing\n autoReset: true, // Whether reset() runs automatically once every flow completes\n\n globalBetween: 0, // Global delay between processes\n\n /**\n * Initialize the QSL library.\n * @returns {Promise<this>}\n */\n async init() {\n if (this.initialized) return this;\n\n const loaderScript = document.currentScript;\n\n /* Check if QSL is already initialized */\n window.__QSL__ = window.__QSL__ || this;\n\n /* Check DOMContentLoaded state */\n if (document.readyState === 'interactive' || document.readyState === 'complete') {\n this.LIFECYCLE.DOMREADY = true;\n } else {\n document.addEventListener('DOMContentLoaded', () => this.LIFECYCLE.DOMREADY = true, { once: true });\n }\n\n /* Check window load state */\n if (document.readyState === 'complete') {\n this.LIFECYCLE.LOADED = true;\n } else {\n window.addEventListener('load', () => this.LIFECYCLE.LOADED = true, { once: true });\n }\n\n /* Register default type: console */\n this.registerType('console', (process) => {\n return new Promise((resolve) => {\n process.onBeforeStart?.();\n setTimeout(() => {\n if ( process.message ) this.log( process.message, { timestamp: Date.now() } );\n process.onComplete?.();\n resolve();\n }, process.delay || 0);\n });\n });\n\n /**\n * Custom event listeners for logging and error handling\n */\n window.addEventListener('QSL:log', (e) => this.log(e.detail.type, e.detail.config.id));\n window.addEventListener('QSL:error', (e) => this.error(e.detail.type, e.detail.error, e.detail.config.id));\n\n /**\n * Load init triggers\n */\n if ( this.initActions.size ) {\n for ( const cb of this.initActions ) {\n if ( typeof cb === 'function' ) await cb.call(this);\n }\n }\n \n this.initialized = true;\n\n /**\n * Check if async loading is enabled\n */\n const url = loaderScript && loaderScript.src ? new URL(loaderScript.src, document.baseURI) : null;\n if (!url || url.searchParams.get('async') !== 'true') return this;\n\n /**\n * Callback on async loading with default callback name\n */\n const callback = url.searchParams.get('callback') || this.CALLBACK;\n if (typeof window[callback] === 'function') window[callback]();\n\n /**\n * Return QSL instance for chaining\n */\n return this;\n \n },\n \n /**\n * Register a plugin to QSL.\n *\n * @param {Function} plugin - The plugin function to register.\n * @param {...any} args - Additional arguments passed to the plugin.\n * @returns {this}\n */\n use(plugin, ...args) {\n if (typeof plugin === 'function') plugin(this, ...args);\n return this;\n },\n\n /**\n * Add a process config to a flow.\n * Handles process-level dependencies separately from flow-level logic.\n *\n * @param {Object} config - The process configuration object.\n * @param {string|boolean|null} [flowId=null] - The flow ID or true for ordered, or null for default.\n * @returns {this}\n */\n add(config, flowId = null) {\n if (!config || typeof config !== 'object') return this;\n\n /* Generate ID and default to process state */\n config.id = config.id ? this.PREFIX + config.id : this.PREFIX + Math.random().toString(36).slice(2);\n config.skipped = false;\n\n /* Sanitize config and set default type */\n if (!config.type) config.type = 'console';\n\n /* Register process-level dependencies */\n if (Array.isArray(config.depends)) config.depends = [...new Set(config.depends)];\n\n /* Filter flowId and config by addProcessFilters */\n if ( this.addProcessFilters.size ) {\n for ( const cb of this.addProcessFilters ) {\n if ( typeof cb === 'function' ) [flowId, config] = cb.call(this, flowId, config);\n }\n }\n\n /* Store flowId on process for quick lookup */\n const normalizedFlowId = this.normalizeFlowId(flowId);\n config.flowId = normalizedFlowId;\n\n /* Add to flow for flow-level execution */\n this.getOrCreateFlow(normalizedFlowId).push(config);\n\n /**\n * Return QSL instance for chaining\n */\n return this;\n },\n\n /**\n * Start loading all flows.\n *\n * @param {Object} [options={}]\n * @param {number|boolean} [options.between=false] - Global delay between processes.\n * @returns {Promise<this>}\n */\n async load({ between = false } = {}) {\n if (this.hasStarted) return;\n this.hasStarted = true;\n \n /**\n * Set global between\n */\n this.globalBetween = between;\n\n /**\n * Call load actions\n */\n for ( const cb of this.loadActions ) {\n if (typeof cb === 'function') cb.call(this);\n }\n\n /**\n * Return global promise\n */\n return new Promise((resolve) => {\n if (!this.flows.size) {\n this.reset();\n return resolve();\n }\n\n this.globalResolve = resolve;\n this.processFlows();\n });\n \n },\n\n /**\n * Reset all internal state and clear all flows/options.\n * \n * @returns {void}\n */\n reset() {\n /**\n * Call reset actions before clearing\n */\n if (this.resetActions.size) {\n for (const action of this.resetActions) {\n if (typeof action === 'function') action.call(this);\n }\n }\n\n /**\n * Clear run state only. Plugin registrations (types, condition and\n * trigger handlers, lifecycle hooks) survive, so processes added after\n * a completed run still behave the same way. Use destroy() to tear the\n * whole instance down.\n */\n this.flows.clear();\n this.flowOptions.clear();\n this.flowGroups.clear();\n this.pendingFlows.clear();\n this.pendingProcesses.clear();\n this.completedProcesses.clear();\n this.currentProcessPerFlow.clear();\n this.onAllComplete = null;\n this.globalResolve = null;\n this.hasStarted = false;\n this.globalBetween = 0;\n\n this.log('RESET');\n\n /**\n * Return QSL instance for chaining\n */\n return this;\n },\n\n /**\n * Tear the instance down completely: run state, plugin registrations and\n * registered types. After this, init() has to run again.\n *\n * @returns {this}\n */\n destroy() {\n this.reset();\n\n this.types.clear();\n this.initActions.clear();\n this.loadActions.clear();\n this.addProcessFilters.clear();\n this.completedFlowsActions.clear();\n this.flowIdFilters.clear();\n this.conditionHandlers.clear();\n this.triggerHandlers.clear();\n this.processCompleteActions.clear();\n this.allCompleteActions.clear();\n this.resetActions.clear();\n this.handlerCallbacksFilters.clear();\n\n this.logger = null;\n this.eventsEnabled = false;\n this.initialized = false;\n\n /**\n * Return QSL instance for chaining\n */\n return this;\n },\n\n /**\n * Set the logger instance.\n *\n * @param {Object|Function} logger - Logger instance or function.\n * @returns {this}\n */\n setLogger(logger) {\n if (logger && ( typeof logger === 'function' || typeof logger === 'object' ) ) this.logger = logger;\n\n /**\n * Return QSL instance for chaining\n */\n return this;\n },\n\n /**\n * Set a callback to run when all flows/processes are complete.\n *\n * @param {Function} callback - The callback function.\n * @returns {this}\n */\n setOnAllComplete(callback) {\n this.onAllComplete = typeof callback === 'function' ? callback : null;\n\n /**\n * Return QSL instance for chaining\n */\n return this;\n },\n\n /**\n * Enable DOM events for process/flow lifecycle.\n * @returns {this}\n */\n useEvents() {\n this.eventsEnabled = true;\n\n /**\n * Return QSL instance for chaining\n */\n return this;\n },\n\n /**\n * Log a message using the custom logger if set.\n *\n * @param {string} type - Log type.\n * @param {...any} args - Additional log arguments.\n */\n log(type, ...args) {\n if (this.logger && typeof this.logger.log === 'function') this.logger.log(type, ...args);\n },\n\n /**\n * Log an error using the custom logger if set.\n * \n * @param {string} type - Error type.\n * @param {...any} args - Additional error arguments.\n */\n error(type, ...args) {\n if (this.logger && typeof this.logger.error === 'function') this.logger.error(type, ...args);\n },\n\n /**\n * Fire a DOM event if events are enabled.\n * \n * @param {string} event - Event name.\n * @param {Object} detail - Event detail object.\n */\n fire(event, detail) {\n if (this.eventsEnabled && this.EVENTS[event]) {\n window.dispatchEvent(new CustomEvent(this.EVENTS[event], { detail }));\n }\n },\n\n /**\n * Normalize the flow ID.\n * \n * @param {string|boolean|null} flowId - The flow ID or true for ordered, or null for default.\n * @returns {string} Normalized flow ID.\n */\n normalizeFlowId(flowId) {\n if (flowId === true) {\n flowId = this.FLOW_TYPE.ORDERED;\n } else if (typeof flowId !== 'string') {\n flowId = this.FLOW_TYPE.DEFAULT;\n }\n return flowId;\n },\n\n /**\n * Register a custom resource type handler.\n *\n * @param {string} type - Resource type name.\n * @param {Function} handler - Handler function for the type.\n * @returns {this}\n */\n registerType(type, handler) {\n if (typeof type !== 'string' || typeof handler !== 'function') return this;\n this.types.set(type, handler);\n\n /**\n * Return QSL instance for chaining\n */\n return this;\n },\n\n /**\n * Register multiple custom resource types.\n *\n * @param {Array<{type: string, handler: Function}>|Object} types - Array or object of type definitions.\n * @returns {this}\n */\n registerTypes(types) {\n if (!types || typeof types !== 'object') return this;\n\n /* Accept both [{ type, handler }] and { name: handler } */\n const list = Array.isArray(types)\n ? types\n : Object.entries(types).map(([type, handler]) => (\n typeof handler === 'function' ? { type, handler } : handler\n ));\n\n for (const type of list) {\n if (type) this.registerType(type.type, type.handler);\n }\n\n /**\n * Return QSL instance for chaining\n */\n return this;\n },\n\n /**\n * Pause all flows in a group.\n * \n * @param {string} group - Group name.\n * @returns {this}\n */\n pauseGroup(group) {\n const flowGroup = this.flowGroups.get(group);\n if (!flowGroup) return this;\n for (const flowId of flowGroup) {\n this.setFlowOptions({ paused: true }, flowId);\n }\n\n /**\n * Return QSL instance for chaining\n */\n return this;\n },\n\n /**\n * Run all flows in a group.\n * \n * @param {string} group - Group name.\n * @returns {this}\n */\n runGroup(group) {\n const flowGroup = this.flowGroups.get(group);\n if (!flowGroup) return this;\n for (const flowId of flowGroup) {\n this.setFlowOptions({ paused: false }, flowId);\n this.runFlow(flowId);\n }\n\n /**\n * Return QSL instance for chaining\n */\n return this;\n },\n\n /**\n * Run a specific flow by id.\n *\n * @param {string} flowId - Flow ID.\n * @param {boolean} [withTrigger=false] - Whether to run with trigger logic.\n * @returns {this}\n */\n runFlow(flowId, withTrigger = false) {\n const processes = this.flows.get(flowId);\n const options = this.flowOptions.get(flowId);\n if (!processes || !options || options.status !== this.FLOW_STATE.READY) return this;\n this.processFlows(flowId, withTrigger);\n\n /**\n * Return QSL instance for chaining\n */\n return this;\n },\n\n /**\n * Get or create a flow.\n * \n * @param {string} flowId - Flow ID.\n * @returns {Array} The flow's process array.\n */\n getOrCreateFlow(flowId) {\n if (!this.flows.has(flowId)) {\n this.flows.set(flowId, []);\n this.flowOptions.set(flowId, { \n ...this.FLOW_OPTIONS, \n ordered: flowId === this.FLOW_TYPE.ORDERED, \n status: this.FLOW_STATE.READY \n });\n }\n return this.flows.get(flowId);\n },\n\n /**\n * Set or update options for a flow.\n * If depends is set, pauses the flow until dependencies are resolved.\n * \n * @param {Object} options - Flow options.\n * @param {string|boolean|null} [flowId=null] - Flow ID.\n * @returns {this}\n */\n setFlowOptions(options = {}, flowId = null) {\n /**\n * Normalize flow ID\n */\n flowId = this.normalizeFlowId(flowId);\n\n /**\n * Get or create flow\n */\n this.getOrCreateFlow(flowId);\n\n if (!options || typeof options !== 'object') return this;\n const prevOptions = this.flowOptions.get(flowId);\n\n /**\n * Pause flow if it has dependencies\n */\n if (Array.isArray(options.depends) && options.depends.length) {\n options.depends = [...new Set(options.depends)];\n options.paused = true;\n this.pendingFlows.add(flowId);\n }\n\n /**\n * Grouping flows\n */\n if (options.group) {\n if (!this.flowGroups.has(options.group)) this.flowGroups.set(options.group, new Set());\n this.flowGroups.get(options.group).add(flowId);\n }\n \n /**\n * Update options partially with fallbacks to previous state\n */\n this.flowOptions.set(flowId, { ...prevOptions, ...options });\n\n /**\n * Return QSL instance for chaining\n */\n return this;\n },\n\n /**\n * Check all pending flows and run those whose dependencies are now resolved.\n * \n * @returns {void}\n */\n checkPendingFlows() {\n if (!this.pendingFlows.size) return;\n for (const pendingFlowId of this.pendingFlows) {\n const pendingOptions = this.flowOptions.get(pendingFlowId);\n if (\n pendingOptions &&\n pendingOptions.depends &&\n pendingOptions.depends.every(depId => {\n const depOpt = this.flowOptions.get(this.normalizeFlowId(depId));\n return depOpt && depOpt.status === this.FLOW_STATE.COMPLETED;\n })\n ) {\n this.setFlowOptions({ paused: false }, pendingFlowId);\n this.pendingFlows.delete(pendingFlowId);\n this.runFlow(pendingFlowId);\n }\n }\n },\n\n /**\n * Check all pending processes and run those whose dependencies are now resolved.\n * \n * @returns {void}\n */\n checkPendingProcesses() {\n if (!this.pendingProcesses.size) return;\n for (const process of this.pendingProcesses) {\n const missingDeps = process.depends.filter(depId => {\n const hasProcess = Array.from(this.flows.values()).some(flow =>\n flow.some(p => p.id === this.PREFIX + depId)\n );\n return !this.completedProcesses.has(this.PREFIX + depId) && !hasProcess;\n });\n if (missingDeps.length) {\n this.pendingProcesses.delete(process);\n this.log('DEP_NOT_FOUND', process.id, `${missingDeps.join(', ')}`);\n process._depsResolved = true;\n process._triggered = true;\n if (process._waitResolve) process._waitResolve();\n continue;\n }\n const allDepsCompleted = process.depends.every(depId => this.completedProcesses.has(this.PREFIX + depId));\n if (allDepsCompleted) {\n this.pendingProcesses.delete(process);\n process._depsResolved = true;\n if (process._triggered && process._waitResolve) process._waitResolve();\n }\n }\n },\n\n /**\n * Check if all flows/processes are complete and resolve global promise if so.\n * \n * @returns {Promise<void>}\n */\n async maybeComplete() {\n if ( ! this.hasStarted ) return;\n\n /**\n * Check for pending flows missed dependencies \n */\n if ( this.pendingFlows.size ) {\n for (const pendingFlowId of this.pendingFlows) {\n const pendingOptions = this.flowOptions.get(pendingFlowId);\n if (\n pendingOptions &&\n pendingOptions.depends &&\n pendingOptions.depends.some(depId => !this.flowOptions.has(this.normalizeFlowId(depId)))\n ) {\n this.setFlowOptions({ status: this.FLOW_STATE.COMPLETED }, pendingFlowId);\n this.pendingFlows.delete(pendingFlowId);\n this.log('FLOW_DEP_SKIPPED', { flow: pendingFlowId, depends: `${pendingOptions.depends.filter(depId => !this.flowOptions.has(this.normalizeFlowId(depId))).join(', ')}` });\n }\n }\n }\n \n /**\n * Check completed flows\n */\n let flowsDone = this.flowOptions.size ? Array.from(this.flowOptions.values()).every(opt => opt.status === this.FLOW_STATE.COMPLETED) : false;\n\n /**\n * Completion hooks run even when some flow is still outstanding, so a\n * plugin can hold work back and release it here. With no hooks\n * registered this is exactly the old behaviour: done when every flow\n * is done.\n */\n let maybeComplete = flowsDone;\n\n /*\n * Filter maybeComplete by completedFlowsActions\n */\n if ( this.flows.size && this.completedFlowsActions.size ) {\n for ( const cb of this.completedFlowsActions ) {\n maybeComplete = cb.call(this, flowsDone, this.flows, this.flowOptions);\n }\n }\n\n if ( ! maybeComplete ) return;\n\n if (this.completing) return;\n this.completing = true;\n\n this.log('ALL_COMPLETED');\n this.fire('ALL_COMPLETED');\n\n this.onAllComplete?.();\n if (this.globalResolve !== null) this.globalResolve();\n\n /**\n * Call all flows completion actions\n */\n if (this.allCompleteActions.size) {\n for (const action of this.allCompleteActions) {\n if (typeof action === 'function') action.call(this);\n }\n }\n\n /**\n * Reset run state unless the caller opted out (e.g. for debugging)\n */\n if (this.autoReset) this.reset();\n this.completing = false;\n },\n\n /**\n * Process all flows and their dependencies.\n * \n * @param {string|null} [flowId=null] - Specific flow ID or null for all.\n * @param {boolean} [withTrigger=false] - Whether to run with trigger logic.\n * @returns {this}\n */\n processFlows(flowId = null, withTrigger = false) {\n if (!this.flows.size) return;\n\n /**\n * Run all flows if no specific flowId is provided\n */\n let flowIds = flowId ? [flowId] : Array.from(this.flows.keys());\n\n /**\n * Filter flowIds by flowIdFilters\n */\n if ( flowIds.length && this.flowIdFilters.size ) {\n for ( const cb of this.flowIdFilters ) {\n if ( typeof cb === 'function' ) flowIds = cb.call(this, flowIds);\n }\n }\n\n /**\n * Sort flows: flows without triggers first, then by priority\n */\n flowIds.sort((a, b) => {\n const aOpts = this.flowOptions.get(a);\n const bOpts = this.flowOptions.get(b);\n const aHasTrigger = aOpts?.trigger != null;\n const bHasTrigger = bOpts?.trigger != null;\n \n if (aHasTrigger && !bHasTrigger) return 1;\n if (!aHasTrigger && bHasTrigger) return -1;\n \n const aPriority = aOpts?.priority || 0;\n const bPriority = bOpts?.priority || 0;\n return bPriority - aPriority;\n });\n\n for (const fid of flowIds) {\n const options = this.flowOptions.get(fid);\n\n /**\n * Skip if missed options or flow is already completed\n */\n if (!options || options.status === this.FLOW_STATE.COMPLETED) continue;\n\n /**\n * Flow-level conditions\n */\n if ( this.getConditionStatus(options.condition) ) {\n this.setFlowOptions({ status: this.FLOW_STATE.COMPLETED }, fid);\n continue;\n }\n\n /**\n * Only process if not paused\n */\n if (options.paused) continue;\n\n /**\n * Logic for trigger on flow level\n */\n if ( flowId === null || ( flowId && ! withTrigger ) ) {\n if (options.trigger != null) {\n const trigger = this.getTriggerFunction(options.trigger, options);\n if (trigger) {\n this.setFlowOptions({ paused: true }, fid);\n let triggered = false;\n trigger(() => {\n if (triggered) return;\n triggered = true;\n this.setFlowOptions({ paused: false }, fid);\n this.runFlow(fid, true);\n });\n continue;\n }\n }\n }\n\n /**\n * Set flow to running state\n */\n this.setFlowOptions({ status: this.FLOW_STATE.RUNNING }, fid);\n\n /**\n * Run flows in parallel\n */\n (async () => {\n\n options.beforeStart?.();\n\n /**\n * Delay per flow\n */\n if (options.delay && options.delay > 0) {\n await new Promise(res => setTimeout(res, options.delay));\n }\n\n /**\n * Sort processes by priority\n */\n const processes = (this.flows.get(fid) || []).slice();\n processes.sort((a, b) => (b.priority || 0) - (a.priority || 0));\n\n /**\n * Preload scripts / styles\n */\n if ( (options.preload || options.prefetch ) && ! options.trigger ) {\n for (const p of processes) {\n if (p.trigger) continue;\n if ((p.type === 'script' && p.src) || (p.type === 'style' && p.href)) {\n try {\n const link = document.createElement('link');\n link.rel = options.preload ? 'preload' : 'prefetch';\n link.href = p.src || p.href;\n link.as = p.type === 'script' ? 'script' : 'style';\n if (p.crossOrigin) link.crossOrigin = p.crossOrigin;\n document.head.appendChild(link);\n } catch (e) {\n this.error('PRELOAD_ERROR', e, p.id);\n }\n }\n }\n }\n\n const between = (options.between !== undefined && options.between !== null)\n ? options.between\n : this.globalBetween;\n \n if (options.ordered) {\n /**\n * Ordered: await previous process\n */\n let prev = Promise.resolve();\n processes.forEach((process, idx) => {\n prev = prev.then(async () => {\n if (idx > 0 && between) await new Promise(res => setTimeout(res, between));\n await this.run(process);\n });\n });\n await prev;\n } else {\n /**\n * Unordered: run all processes in parallel\n */\n const promises = processes.map(async (process, idx) => {\n if (idx > 0 && between) await new Promise(res => setTimeout(res, between));\n return this.run(process);\n });\n await Promise.all(promises);\n }\n\n /**\n * Set flow to completed state\n */\n this.setFlowOptions({ status: this.FLOW_STATE.COMPLETED }, fid);\n options.onComplete?.();\n\n /**\n * Check for pending flows\n */\n this.checkPendingFlows();\n\n /**\n * Maybe complete the loading\n */\n this.maybeComplete();\n\n })();\n }\n\n /**\n * Cover skipped/empty batches that never start an async flow.\n */\n this.checkPendingFlows();\n this.maybeComplete();\n },\n\n /**\n * Execute a process based on its type.\n * \n * @param {Object} process - The process object.\n * @returns {Promise<any>}\n */\n async run(process) {\n /**\n * Skip if already running or completed\n */\n if (process._running || this.getConditionStatus(process.condition)) return;\n process._running = true;\n\n /**\n * Setup state\n */\n if (!process._waitPromise) {\n process._triggered = false;\n process._depsResolved = false;\n process._waitPromise = new Promise(res => process._waitResolve = res);\n }\n\n /**\n * Trigger logic for process\n */\n if (process.trigger != null) {\n const trigger = this.getTriggerFunction(process.trigger, process);\n if (trigger) {\n trigger(() => {\n process._triggered = true;\n if (process._depsResolved) process._waitResolve();\n });\n } else {\n process._triggered = true;\n }\n } else {\n process._triggered = true;\n }\n\n /**\n * Check dependencies\n */\n if (Array.isArray(process.depends) && process.depends.length) {\n const missingDeps = process.depends.filter(depId => {\n const hasProcess = Array.from(this.flows.values()).some(flow =>\n flow.some(p => p.id === this.PREFIX + depId)\n );\n return !this.completedProcesses.has(this.PREFIX + depId) && !hasProcess;\n });\n if (missingDeps.length) {\n this.log('DEP_NOT_FOUND', process.id, `${missingDeps.join(', ')}`);\n process._depsResolved = true;\n process._triggered = true;\n if (process._waitResolve) process._waitResolve();\n } else {\n const allDepsCompleted = process.depends.every(depId => this.completedProcesses.has(this.PREFIX + depId));\n if (!allDepsCompleted) {\n this.pendingProcesses.add(process);\n } else {\n process._depsResolved = true;\n if (process._triggered) process._waitResolve();\n }\n }\n } else {\n process._depsResolved = true;\n if (process._triggered) process._waitResolve();\n }\n\n /**\n * Wait for both trigger and dependencies to be resolved\n */\n await process._waitPromise;\n\n return this.execute(process);\n },\n\n /**\n * Check the condition option and return true if the condition fails.\n * \n * @param {string|Function|boolean} conditionOption - The condition option.\n * @returns {boolean} True if the condition fails, false otherwise.\n */\n getConditionStatus(opt) {\n if (opt == null) return false;\n \n if (Array.isArray(opt)) {\n return opt.some(c => this.getConditionStatus(c));\n }\n \n if (typeof opt === 'object' && opt.operator) {\n const { operator, conditions } = opt;\n if (!Array.isArray(conditions)) return false;\n \n if (operator === 'or') {\n return conditions.every(c => this.getConditionStatus(c));\n } else if (operator === 'and') {\n return conditions.some(c => this.getConditionStatus(c));\n }\n return false;\n }\n \n if (typeof opt === 'function' && !opt()) return true;\n if (typeof opt === 'boolean' && !opt) return true;\n\n if (this.conditionHandlers.size) {\n for (const h of this.conditionHandlers) {\n if (typeof h === 'function') {\n const r = h.call(this, opt);\n if (r === true || r === false) return r;\n }\n }\n }\n\n return false;\n },\n\n /**\n * Parse and return a trigger function based on the trigger option.\n * \n * @param {string|Function|boolean} opt - The trigger option.\n * @param {Object} o - The associated process or flow object.\n * @returns {Function|null} The trigger function or null if no trigger function is found.\n */\n getTriggerFunction(opt, o) {\n if (opt == null) return null;\n \n if (typeof opt === 'function') {\n return (cb) => opt(cb);\n }\n \n /**\n * Return trigger function for array of triggers\n */\n if (Array.isArray(opt)) {\n return (cb) => {\n const vd = opt.map(t => this.getTriggerFunction(t, o)).filter(tF => tF);\n if (vd.length === 0) {\n cb();\n return;\n }\n let f = 0;\n const fCb = () => { if (++f === vd.length) cb(); };\n vd.forEach(tF => tF(fCb));\n };\n }\n \n /**\n * Return trigger function for object with operator and triggers\n */\n if (typeof opt === 'object' && opt.operator) {\n const { operator, triggers } = opt;\n if (!Array.isArray(triggers)) return null;\n \n if (operator === 'or') {\n return (cb) => {\n const vd = triggers.map(t => this.getTriggerFunction(t, o)).filter(tF => tF);\n if (vd.length === 0) {\n cb();\n return;\n }\n let f = false;\n const fCb = () => { if (!f) { f = true; cb(); } };\n vd.forEach(tF => tF(fCb));\n };\n } else if (operator === 'and') {\n return (cb) => {\n const vd = triggers.map(t => this.getTriggerFunction(t, o)).filter(tF => tF);\n if (vd.length === 0) {\n cb();\n return;\n }\n let f = 0;\n const fCb = () => { if (++f === vd.length) cb(); };\n vd.forEach(tF => tF(fCb));\n };\n }\n return null;\n }\n\n /**\n * Return trigger function from trigger handlers\n */\n if (this.triggerHandlers.size) {\n for (const h of this.triggerHandlers) {\n if (typeof h === 'function') {\n const r = h.call(this, opt, o);\n if (r && typeof r === 'function') return r;\n }\n }\n }\n \n /**\n * Return interaction trigger function if opt is true or 'interaction'\n */\n if (opt === true || opt === 'interaction') {\n return (cb) => this.waitForInteraction(cb);\n }\n \n return null;\n },\n\n /**\n * Wait for user interaction before running a callback (for interaction phase).\n * This is the default fallback trigger.\n * \n * @param {Function} cb - The callback to run after user interaction.\n * @returns {void}\n */\n waitForInteraction(cb) {\n ['click', 'keydown', 'wheel', 'mousedown', 'mousemove', 'touchstart'].forEach(e => window.addEventListener(e, () => cb(), { once: true, passive: true }));\n },\n\n /**\n * Execute the process based on its type.\n * \n * @param {Object} process - The process object.\n * @returns {Promise<any>}\n */\n async execute(process) {\n const finishProcess = async () => {\n /**\n * Call process completion actions\n */\n if (this.processCompleteActions.size) {\n for (const action of this.processCompleteActions) {\n if (typeof action === 'function') action.call(this, process);\n }\n }\n this.completedProcesses.add(process.id);\n process._running = false;\n this.checkPendingProcesses();\n };\n if (process.skipped) {\n this.fire('SKIPPED', { ...process, id: process.id });\n finishProcess();\n return;\n }\n const handler = this.types.get(process.type);\n if (!handler) {\n this.log('UNKNOWN_TYPE', process.type, process.id);\n finishProcess();\n return;\n }\n this.fire('STARTED', { ...process, id: process.id });\n \n /**\n * Build handler callbacks from filters\n */\n const callbacks = {};\n if (this.handlerCallbacksFilters.size) {\n for (const filter of this.handlerCallbacksFilters) {\n if (typeof filter === 'function') {\n const pluginCallbacks = filter.call(this, process);\n if (pluginCallbacks && typeof pluginCallbacks === 'object') {\n Object.assign(callbacks, pluginCallbacks);\n }\n }\n }\n }\n \n /**\n * Execute handler and handle completion or error\n */\n return handler(process, callbacks)\n .then(() => {\n this.fire('COMPLETED', { ...process, id: process.id });\n finishProcess();\n })\n .catch(() => {\n this.fire('ERROR', { ...process, id: process.id });\n finishProcess();\n });\n }\n};","/**\n * Get cache-bypass suffix for a URL.\n */\nconst bypassSuffix = (source, bypassCache) =>{\n return bypassCache ? ( ( source.includes('?') ? '&' : '?') + Date.now() ) : '';\n}\n\n/**\n * Log a message.\n */\nconst log = (detail) => {\n window.dispatchEvent(new CustomEvent('QSL:log', { detail }));\n}\n\n/**\n * Log an error.\n */\nconst error = (detail) => {\n window.dispatchEvent(new CustomEvent('QSL:error', { detail }));\n}\n\n/**\n * Render an element.\n */\nconst render = (config, callbacks = {}) => {\n return new Promise(async (resolve) => {\n const { flowId, tag, id, delay, data, onBeforeStart, onComplete, onError, footer, dom, onElement, onCustomResolve } = config;\n if (!flowId || !tag || !id) {\n resolve();\n return;\n }\n try {\n if (onBeforeStart) await onBeforeStart(config);\n log({ tag, type: 'PROCESS_STARTED', config });\n if (delay) await new Promise(res => setTimeout(res, delay));\n let el = document.createElement(tag);\n onElement?.(el, config);\n\n callbacks.registerProcessElement?.(el, config);\n\n if (data && typeof data === 'object') {\n for (const [key, value] of Object.entries(data)) {\n el.setAttribute(`data-${key.replace(/([A-Z])/g, '-$1').toLowerCase().replace(/[^a-z0-9_-]/g, '').replace(/^-/, '')}`, String(value));\n }\n }\n\n if (!onCustomResolve) {\n el.onload = () => {\n log({ tag, type: 'PROCESS_COMPLETED', config });\n onComplete?.();\n resolve();\n };\n }\n el.onerror = (e) => {\n error({ tag, type: 'PROCESS_FAILED', config });\n onError?.(e);\n resolve(e);\n };\n if (dom) {\n (footer ? document.body : document.head).appendChild(el);\n }\n onCustomResolve?.({ el, config, resolve });\n } catch (e) {\n error({ tag, type: 'PROCESS_FAILED', config, error: e });\n onError?.(e);\n resolve(e);\n }\n });\n}\n\n/**\n * Render an inline script.\n */\nconst InlineScript = {\n type: 'inline-script',\n handler: (config, callbacks) => { \n let storedResolve = null;\n let alreadyFired = false;\n const eventName = `QSL:inline-script:completed:${config.id}`;\n const resolveProcess = () => {\n log({ tag: 'inline-script', type: 'INLINE_SCRIPT_SUCCESS', config });\n log({ tag: 'inline-script', type: 'PROCESS_COMPLETED', config });\n config?.onComplete?.();\n storedResolve?.();\n };\n const normalizedConfig = {\n ...config,\n code: config.code?.replace(/<script.*?>|<\\/script>/gi, '')\n };\n return render({\n ...normalizedConfig,\n tag: 'script',\n dom: true,\n onElement: (el, config) => {\n const { code, module, id, flowId } = config;\n if (code) el.textContent = code;\n if (module) {\n el.type = 'module';\n const originalCode = el.textContent;\n const fid = JSON.stringify(String(flowId));\n const pid = JSON.stringify(String(id));\n const evt = JSON.stringify(String(eventName));\n const wrappedCode = `(function(){window.__QSL__.currentProcessPerFlow.set(${fid},${pid});try{${originalCode}}finally{window.__QSL__.currentProcessPerFlow.delete(${fid});window.dispatchEvent(new Event(${evt}));}})();`;\n el.textContent = wrappedCode;\n const handler = () => {\n window.removeEventListener(eventName, handler);\n if (storedResolve) {\n resolveProcess();\n } else { \n alreadyFired = true;\n }\n };\n window.addEventListener(eventName, handler);\n }\n },\n onCustomResolve: ({ el, config, resolve }) => {\n const { module } = config;\n storedResolve = resolve;\n if (module && alreadyFired) {\n resolveProcess();\n } else if (!module) {\n queueMicrotask(() => {\n if (storedResolve === resolve) resolveProcess();\n });\n }\n }\n }, callbacks);\n }\n};\n\n/**\n * Render a script element.\n */\nconst Script = {\n type: 'script',\n handler: (config, callbacks) => { \n return render({\n ...config,\n tag: 'script',\n dom: true,\n onElement: (el, { src, module, async, defer, crossOrigin, integrity, bypassCache }) => {\n if (module) el.type = 'module';\n if (async) el.async = async;\n if (defer) el.defer = defer;\n if (crossOrigin) el.crossOrigin = crossOrigin;\n if (integrity) el.integrity = integrity;\n if (src) el.src = src + bypassSuffix(src, bypassCache);\n }\n }, callbacks);\n }\n};\n\n/**\n * Render an inline style.\n */\nconst InlineStyle = {\n type: 'style',\n handler: (config, callbacks) => {\n const normalizedConfig = {\n ...config,\n code: config.code?.replace(/<style.*?>|<\\/style>/gi, '')\n };\n return render({\n ...normalizedConfig,\n tag: 'style',\n dom: true,\n onElement: (el, { code }) => {\n if (code) el.textContent = code;\n },\n onCustomResolve: ({ el, config, resolve }) => {\n const { tag, onComplete } = config;\n log({ tag, type: 'INLINE_STYLE_SUCCESS', config });\n log({ tag, type: 'PROCESS_COMPLETED', config });\n onComplete?.();\n resolve();\n }\n }, callbacks);\n }\n};\n\n/**\n * Render a stylesheet.\n */\nconst Stylesheet = {\n type: 'stylesheet',\n handler: (config, callbacks) => {\n return render({\n ...config,\n tag: 'link',\n dom: true,\n onElement: (el, { href, crossOrigin, bypassCache }) => {\n el.rel = 'stylesheet';\n if (crossOrigin) el.crossOrigin = crossOrigin;\n el.href = href + bypassSuffix(href, bypassCache);\n }\n }, callbacks);\n }\n};\n\n/**\n * Render a pixel.\n */\nconst Pixel = {\n type: 'pixel',\n handler: (config, callbacks) => {\n return render({\n ...config,\n tag: 'img',\n dom: true,\n onElement: (el, { style = { display: 'none' }, dom, src, bypassCache }) => {\n if ( ! dom ) el = new window.Image();\n el.src = src + bypassSuffix(src, bypassCache);\n el.width = 1;\n el.height = 1;\n if ( style && typeof style === 'object' ) {\n for (const [key, value] of Object.entries(style)) {\n el.style.setProperty(key, value);\n }\n }\n },\n onCustomResolve: ({ el, config, resolve }) => {\n const { tag, dom, onComplete } = config;\n const resolver = () => {\n log({ tag, type: 'IMAGE_LOADED', config });\n log({ tag, type: 'PROCESS_COMPLETED', config });\n onComplete?.();\n resolve();\n };\n ! dom ? resolver() : el.onload = () => resolver();\n }\n }, callbacks);\n }\n};\n\n/**\n * Render a custom element.\n */\nconst Shadow = {\n type: 'shadow',\n handler: (config, callbacks) => {\n return render({\n ...config,\n onBeforeStart: async ({ tag }) => await window.customElements.whenDefined(tag),\n onElement: (el, { shadowData }) => {\n el.data = shadowData || {};\n if (shadowData?.hidden) el.setAttribute('hidden', ''); \n },\n onCustomResolve: ({ el, config, resolve }) => {\n const { tag, shadowData, onComplete, onError } = config;\n const resolver = () => {\n const selector = shadowData?.container;\n let container = null;\n if (selector === 'body') {\n container = document.body;\n } else if (typeof selector === 'string' && selector) {\n try {\n container = document.querySelector(selector);\n } catch (e) {\n container = null;\n }\n }\n if (!container) {\n const err = new Error(`Container not found: ${selector}`);\n error({ tag, type: 'SHADOW_FAILED', config, error: err });\n onError?.(err);\n resolve(err);\n return;\n }\n shadowData?.position === 'top' ? container.insertBefore(el, container.firstChild) : container.appendChild(el);\n log({ tag, type: 'SHADOW_SUCCESS', config });\n log({ tag, type: 'PROCESS_COMPLETED', config });\n onComplete?.();\n resolve();\n };\n if (document.readyState === 'interactive' || document.readyState === 'complete') {\n resolver();\n } else {\n document.addEventListener('DOMContentLoaded', resolver, { once: true });\n }\n }\n }, callbacks);\n }\n}\n\n/**\n * Render an HTML element.\n */\nconst HTML = {\n type: 'html',\n handler: (config, callbacks) => {\n return render({\n ...config,\n dom: true,\n onElement: (el, { html = '', id = '', className = '', style = {} }) => {\n if (html) el.innerHTML = html;\n if (id) el.id = id;\n if (className) el.className = Array.isArray(className) ? className.join(' ') : className;\n if ( style && typeof style === 'object' ) {\n for (const [key, value] of Object.entries(style)) {\n el.style.setProperty(key, value);\n }\n }\n },\n onCustomResolve: ({ el, config, resolve }) => {\n const { tag, onComplete } = config;\n log({ tag, type: 'HTML_SUCCESS', config });\n log({ tag, type: 'PROCESS_COMPLETED', config });\n onComplete?.();\n resolve();\n }\n }, callbacks);\n }\n};\n\n/**\n * Default types for QSL.\n */\nexport { Script, Stylesheet, InlineScript, InlineStyle, Pixel, Shadow, HTML };","import core from '../core.js';\n\nimport { Script } from '../types.js';\n\ncore\n .registerTypes([Script])\n .init();"],"names":["core","VERSION","PREFIX","FLOW_TYPE","DEFAULT","ORDERED","FLOW_STATE","READY","RUNNING","COMPLETED","FLOW_OPTIONS","delay","priority","between","trigger","condition","beforeStart","onComplete","group","paused","preload","fireEvents","depends","EVENTS","STARTED","ERROR","FLOW_STARTED","FLOW_COMPLETED","ALL_COMPLETED","SKIPPED","DOMREADY","LOADED","LIFECYCLE","document","readyState","CALLBACK","types","Map","flows","flowOptions","flowGroups","currentProcessPerFlow","pendingFlows","Set","pendingProcesses","completedProcesses","loadActions","initActions","addProcessFilters","completedFlowsActions","flowIdFilters","conditionHandlers","triggerHandlers","processCompleteActions","allCompleteActions","resetActions","handlerCallbacksFilters","onAllComplete","globalResolve","logger","hasStarted","eventsEnabled","initialized","completing","autoReset","globalBetween","init","this","loaderScript","currentScript","window","__QSL__","addEventListener","once","registerType","process","Promise","resolve","_a","onBeforeStart","call","setTimeout","message","log","timestamp","Date","now","e","detail","type","config","id","error","size","cb","url","src","URL","baseURI","searchParams","get","callback","use","plugin","args","add","flowId","Math","random","toString","slice","skipped","Array","isArray","normalizedFlowId","normalizeFlowId","getOrCreateFlow","push","load","reset","processFlows","action","clear","destroy","setLogger","setOnAllComplete","useEvents","fire","event","dispatchEvent","CustomEvent","handler","set","registerTypes","list","Object","entries","map","pauseGroup","flowGroup","setFlowOptions","runGroup","runFlow","withTrigger","processes","options","status","has","ordered","prevOptions","length","checkPendingFlows","pendingFlowId","pendingOptions","every","depId","depOpt","delete","checkPendingProcesses","missingDeps","filter","hasProcess","from","values","some","flow","p","join","_depsResolved","_triggered","_waitResolve","maybeComplete","flowsDone","opt","flowIds","keys","sort","a","b","aOpts","bOpts","aHasTrigger","bHasTrigger","aPriority","fid","getConditionStatus","getTriggerFunction","triggered","res","prefetch","href","link","createElement","rel","as","crossOrigin","head","appendChild","prev","forEach","idx","then","async","run","promises","all","_b","_running","_waitPromise","execute","c","operator","conditions","h","r","o","vd","t","tF","f","fCb","triggers","waitForInteraction","passive","finishProcess","callbacks","pluginCallbacks","assign","catch","Script","tag","data","onError","footer","dom","onElement","onCustomResolve","el","registerProcessElement","key","value","setAttribute","replace","toLowerCase","String","onload","onerror","body","render","module","defer","integrity","bypassCache","source","includes","bypassSuffix"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"qsl.slim.min.js","sources":["../src/core.js","../src/types.js","../src/presets/default.js"],"sourcesContent":["export default {\n /**\n * Constants\n */\n VERSION: '0.1.4',\n PREFIX: 'qsl-',\n FLOW_TYPE: {\n DEFAULT: 'default',\n ORDERED: 'ordered',\n },\n FLOW_STATE: { \n READY: 'READY',\n RUNNING: 'RUNNING',\n COMPLETED: 'COMPLETED'\n },\n FLOW_OPTIONS: {\n delay: 0,\n priority: 0,\n between: null,\n trigger: null,\n condition: null,\n beforeStart: null,\n onComplete: null,\n group: null,\n paused: false,\n preload: false,\n fireEvents: true,\n depends: []\n },\n EVENTS: {\n STARTED: 'QSL:started',\n COMPLETED: 'QSL:completed',\n ERROR: 'QSL:error',\n FLOW_STARTED: 'QSL:flow:started',\n FLOW_COMPLETED: 'QSL:flow:completed',\n ALL_COMPLETED: 'QSL:all:completed',\n SKIPPED: 'QSL:skipped',\n DOMREADY: 'QSL:domready',\n LOADED: 'QSL:loaded',\n },\n LIFECYCLE: {\n DOMREADY: document.readyState === 'interactive' || document.readyState === 'complete',\n LOADED: false,\n },\n CALLBACK: 'QSLReady',\n /**\n * Properties\n */\n types: new Map(), // Map to store custom resource types\n flows: new Map(), // Map to store flows\n flowOptions: new Map(), // Map to store flow options\n flowGroups: new Map(), // Map to store flow groups\n currentProcessPerFlow: new Map(), // Map to store current process per flow (flowId -> processId)\n\n pendingFlows: new Set(), // Set to store pending flows\n pendingProcesses: new Set(), // Set to store pending processes\n completedProcesses: new Set(), // Set to store completed processes\n loadActions: new Set(), // Set to store before load triggers\n initActions: new Set(), // Set to store init triggers\n addProcessFilters: new Set(), // Set to store add triggers\n completedFlowsActions: new Set(), // Set to store completed flows actions\n flowIdFilters: new Set(), // Set to store flowId filters\n conditionHandlers: new Set(), // Set to store condition handlers\n triggerHandlers: new Set(), // Set to store trigger handlers\n processCompleteActions: new Set(), // Set to store process completion actions\n allCompleteActions: new Set(), // Set to store all flows completion actions\n resetActions: new Set(), // Set to store reset actions\n handlerCallbacksFilters: new Set(), // Set to store handler callbacks filters\n\n onAllComplete: null, // Callback for all flows completion\n globalResolve: null, // Global resolve function\n logger: null, // Logger instance\n\n hasStarted: false, // Flag to check if QSL has started,\n eventsEnabled: false, // Flag to check if events are enabled\n initialized: false, // Flag to check if QSL is initialized\n completing: false, // Flag to check if QSL is completing\n autoReset: true, // Whether reset() runs automatically once every flow completes\n\n globalBetween: 0, // Global delay between processes\n\n /**\n * Initialize the QSL library.\n * @returns {Promise<this>}\n */\n async init() {\n if (this.initialized) return this;\n\n /**\n * document.currentScript is only set while this script is running\n * synchronously. Capture it before the first await below: an init\n * action that waits on anything real would otherwise leave it null,\n * and the async ready callback would silently never fire.\n */\n const loaderScript = document.currentScript;\n\n /* Check if QSL is already initialized */\n window.__QSL__ = window.__QSL__ || this;\n\n /* Check DOMContentLoaded state */\n if (document.readyState === 'interactive' || document.readyState === 'complete') {\n this.LIFECYCLE.DOMREADY = true;\n } else {\n document.addEventListener('DOMContentLoaded', () => this.LIFECYCLE.DOMREADY = true, { once: true });\n }\n\n /* Check window load state */\n if (document.readyState === 'complete') {\n this.LIFECYCLE.LOADED = true;\n } else {\n window.addEventListener('load', () => this.LIFECYCLE.LOADED = true, { once: true });\n }\n\n /* Register default type: console */\n this.registerType('console', (process) => {\n return new Promise((resolve) => {\n process.onBeforeStart?.();\n setTimeout(() => {\n if ( process.message ) this.log( process.message, { timestamp: Date.now() } );\n process.onComplete?.();\n resolve();\n }, process.delay || 0);\n });\n });\n\n /**\n * Custom event listeners for logging and error handling\n */\n window.addEventListener('QSL:log', (e) => this.log(e.detail.type, e.detail.config.id));\n window.addEventListener('QSL:error', (e) => this.error(e.detail.type, e.detail.error, e.detail.config.id));\n\n /**\n * Load init triggers\n */\n if ( this.initActions.size ) {\n for ( const cb of this.initActions ) {\n if ( typeof cb === 'function' ) await cb.call(this);\n }\n }\n \n this.initialized = true;\n\n /**\n * Check if async loading is enabled\n */\n const url = loaderScript && loaderScript.src ? new URL(loaderScript.src, document.baseURI) : null;\n if (!url || url.searchParams.get('async') !== 'true') return this;\n\n /**\n * Callback on async loading with default callback name\n */\n const callback = url.searchParams.get('callback') || this.CALLBACK;\n if (typeof window[callback] === 'function') window[callback]();\n\n /**\n * Return QSL instance for chaining\n */\n return this;\n \n },\n \n /**\n * Register a plugin to QSL.\n *\n * @param {Function} plugin - The plugin function to register.\n * @param {...any} args - Additional arguments passed to the plugin.\n * @returns {this}\n */\n use(plugin, ...args) {\n if (typeof plugin === 'function') plugin(this, ...args);\n return this;\n },\n\n /**\n * Add a process config to a flow.\n * Handles process-level dependencies separately from flow-level logic.\n *\n * @param {Object} config - The process configuration object.\n * @param {string|boolean|null} [flowId=null] - The flow ID or true for ordered, or null for default.\n * @returns {this}\n */\n add(config, flowId = null) {\n if (!config || typeof config !== 'object') return this;\n\n /* Generate ID and default to process state */\n config.id = config.id ? this.PREFIX + config.id : this.PREFIX + Math.random().toString(36).slice(2);\n config.skipped = false;\n\n /* Sanitize config and set default type */\n if (!config.type) config.type = 'console';\n\n /* Register process-level dependencies */\n if (Array.isArray(config.depends)) config.depends = [...new Set(config.depends)];\n\n /* Filter flowId and config by addProcessFilters */\n if ( this.addProcessFilters.size ) {\n for ( const cb of this.addProcessFilters ) {\n if ( typeof cb === 'function' ) [flowId, config] = cb.call(this, flowId, config);\n }\n }\n\n /* Store flowId on process for quick lookup */\n const normalizedFlowId = this.normalizeFlowId(flowId);\n config.flowId = normalizedFlowId;\n\n /* Add to flow for flow-level execution */\n this.getOrCreateFlow(normalizedFlowId).push(config);\n\n /**\n * Return QSL instance for chaining\n */\n return this;\n },\n\n /**\n * Start loading all flows.\n *\n * @param {Object} [options={}]\n * @param {number|boolean} [options.between=false] - Global delay between processes.\n * @returns {Promise<this>}\n */\n async load({ between = false } = {}) {\n if (this.hasStarted) return;\n this.hasStarted = true;\n \n /**\n * Set global between\n */\n this.globalBetween = between;\n\n /**\n * Call load actions\n */\n for ( const cb of this.loadActions ) {\n if (typeof cb === 'function') cb.call(this);\n }\n\n /**\n * Return global promise\n */\n return new Promise((resolve) => {\n if (!this.flows.size) {\n this.reset();\n return resolve();\n }\n\n this.globalResolve = resolve;\n this.processFlows();\n });\n \n },\n\n /**\n * Reset all internal state and clear all flows/options.\n * \n * @returns {void}\n */\n reset() {\n /**\n * Call reset actions before clearing\n */\n if (this.resetActions.size) {\n for (const action of this.resetActions) {\n if (typeof action === 'function') action.call(this);\n }\n }\n\n /**\n * Clear run state only. Plugin registrations (types, condition and\n * trigger handlers, lifecycle hooks) survive, so processes added after\n * a completed run still behave the same way. Use destroy() to tear the\n * whole instance down.\n */\n this.flows.clear();\n this.flowOptions.clear();\n this.flowGroups.clear();\n this.pendingFlows.clear();\n this.pendingProcesses.clear();\n this.completedProcesses.clear();\n this.currentProcessPerFlow.clear();\n this.onAllComplete = null;\n this.globalResolve = null;\n this.hasStarted = false;\n this.globalBetween = 0;\n\n this.log('RESET');\n\n /**\n * Return QSL instance for chaining\n */\n return this;\n },\n\n /**\n * Tear the instance down completely: run state, plugin registrations and\n * registered types. After this, init() has to run again.\n *\n * @returns {this}\n */\n destroy() {\n this.reset();\n\n this.types.clear();\n this.initActions.clear();\n this.loadActions.clear();\n this.addProcessFilters.clear();\n this.completedFlowsActions.clear();\n this.flowIdFilters.clear();\n this.conditionHandlers.clear();\n this.triggerHandlers.clear();\n this.processCompleteActions.clear();\n this.allCompleteActions.clear();\n this.resetActions.clear();\n this.handlerCallbacksFilters.clear();\n\n this.logger = null;\n this.eventsEnabled = false;\n this.initialized = false;\n\n /**\n * Return QSL instance for chaining\n */\n return this;\n },\n\n /**\n * Set the logger instance.\n *\n * @param {Object|Function} logger - Logger instance or function.\n * @returns {this}\n */\n setLogger(logger) {\n if (logger && ( typeof logger === 'function' || typeof logger === 'object' ) ) this.logger = logger;\n\n /**\n * Return QSL instance for chaining\n */\n return this;\n },\n\n /**\n * Set a callback to run when all flows/processes are complete.\n *\n * @param {Function} callback - The callback function.\n * @returns {this}\n */\n setOnAllComplete(callback) {\n this.onAllComplete = typeof callback === 'function' ? callback : null;\n\n /**\n * Return QSL instance for chaining\n */\n return this;\n },\n\n /**\n * Enable DOM events for process/flow lifecycle.\n * @returns {this}\n */\n useEvents() {\n this.eventsEnabled = true;\n\n /**\n * Return QSL instance for chaining\n */\n return this;\n },\n\n /**\n * Log a message using the custom logger if set.\n *\n * @param {string} type - Log type.\n * @param {...any} args - Additional log arguments.\n */\n log(type, ...args) {\n if (this.logger && typeof this.logger.log === 'function') this.logger.log(type, ...args);\n },\n\n /**\n * Log an error using the custom logger if set.\n * \n * @param {string} type - Error type.\n * @param {...any} args - Additional error arguments.\n */\n error(type, ...args) {\n if (this.logger && typeof this.logger.error === 'function') this.logger.error(type, ...args);\n },\n\n /**\n * Fire a DOM event if events are enabled.\n * \n * @param {string} event - Event name.\n * @param {Object} detail - Event detail object.\n */\n fire(event, detail) {\n if (this.eventsEnabled && this.EVENTS[event]) {\n window.dispatchEvent(new CustomEvent(this.EVENTS[event], { detail }));\n }\n },\n\n /**\n * Normalize the flow ID.\n * \n * @param {string|boolean|null} flowId - The flow ID or true for ordered, or null for default.\n * @returns {string} Normalized flow ID.\n */\n normalizeFlowId(flowId) {\n if (flowId === true) {\n flowId = this.FLOW_TYPE.ORDERED;\n } else if (typeof flowId !== 'string') {\n flowId = this.FLOW_TYPE.DEFAULT;\n }\n return flowId;\n },\n\n /**\n * Register a custom resource type handler.\n *\n * @param {string} type - Resource type name.\n * @param {Function} handler - Handler function for the type.\n * @returns {this}\n */\n registerType(type, handler) {\n if (typeof type !== 'string' || typeof handler !== 'function') return this;\n this.types.set(type, handler);\n\n /**\n * Return QSL instance for chaining\n */\n return this;\n },\n\n /**\n * Register multiple custom resource types.\n *\n * @param {Array<{type: string, handler: Function}>|Object} types - Array or object of type definitions.\n * @returns {this}\n */\n registerTypes(types) {\n if (!types || typeof types !== 'object') return this;\n\n /* Accept both [{ type, handler }] and { name: handler } */\n const list = Array.isArray(types)\n ? types\n : Object.entries(types).map(([type, handler]) => (\n typeof handler === 'function' ? { type, handler } : handler\n ));\n\n for (const type of list) {\n if (type) this.registerType(type.type, type.handler);\n }\n\n /**\n * Return QSL instance for chaining\n */\n return this;\n },\n\n /**\n * Pause all flows in a group.\n * \n * @param {string} group - Group name.\n * @returns {this}\n */\n pauseGroup(group) {\n const flowGroup = this.flowGroups.get(group);\n if (!flowGroup) return this;\n for (const flowId of flowGroup) {\n this.setFlowOptions({ paused: true }, flowId);\n }\n\n /**\n * Return QSL instance for chaining\n */\n return this;\n },\n\n /**\n * Run all flows in a group.\n * \n * @param {string} group - Group name.\n * @returns {this}\n */\n runGroup(group) {\n const flowGroup = this.flowGroups.get(group);\n if (!flowGroup) return this;\n for (const flowId of flowGroup) {\n this.setFlowOptions({ paused: false }, flowId);\n this.runFlow(flowId);\n }\n\n /**\n * Return QSL instance for chaining\n */\n return this;\n },\n\n /**\n * Run a specific flow by id.\n *\n * @param {string} flowId - Flow ID.\n * @param {boolean} [withTrigger=false] - Whether to run with trigger logic.\n * @returns {this}\n */\n runFlow(flowId, withTrigger = false) {\n const processes = this.flows.get(flowId);\n const options = this.flowOptions.get(flowId);\n if (!processes || !options || options.status !== this.FLOW_STATE.READY) return this;\n this.processFlows(flowId, withTrigger);\n\n /**\n * Return QSL instance for chaining\n */\n return this;\n },\n\n /**\n * Get or create a flow.\n * \n * @param {string} flowId - Flow ID.\n * @returns {Array} The flow's process array.\n */\n getOrCreateFlow(flowId) {\n if (!this.flows.has(flowId)) {\n this.flows.set(flowId, []);\n this.flowOptions.set(flowId, { \n ...this.FLOW_OPTIONS, \n ordered: flowId === this.FLOW_TYPE.ORDERED, \n status: this.FLOW_STATE.READY \n });\n }\n return this.flows.get(flowId);\n },\n\n /**\n * Set or update options for a flow.\n * If depends is set, pauses the flow until dependencies are resolved.\n * \n * @param {Object} options - Flow options.\n * @param {string|boolean|null} [flowId=null] - Flow ID.\n * @returns {this}\n */\n setFlowOptions(options = {}, flowId = null) {\n /**\n * Normalize flow ID\n */\n flowId = this.normalizeFlowId(flowId);\n\n /**\n * Get or create flow\n */\n this.getOrCreateFlow(flowId);\n\n if (!options || typeof options !== 'object') return this;\n const prevOptions = this.flowOptions.get(flowId);\n\n /**\n * Pause flow if it has dependencies\n */\n if (Array.isArray(options.depends) && options.depends.length) {\n options.depends = [...new Set(options.depends)];\n options.paused = true;\n this.pendingFlows.add(flowId);\n }\n\n /**\n * Grouping flows\n */\n if (options.group) {\n if (!this.flowGroups.has(options.group)) this.flowGroups.set(options.group, new Set());\n this.flowGroups.get(options.group).add(flowId);\n }\n \n /**\n * Update options partially with fallbacks to previous state\n */\n this.flowOptions.set(flowId, { ...prevOptions, ...options });\n\n /**\n * Return QSL instance for chaining\n */\n return this;\n },\n\n /**\n * Check all pending flows and run those whose dependencies are now resolved.\n * \n * @returns {void}\n */\n checkPendingFlows() {\n if (!this.pendingFlows.size) return;\n for (const pendingFlowId of this.pendingFlows) {\n const pendingOptions = this.flowOptions.get(pendingFlowId);\n if (\n pendingOptions &&\n pendingOptions.depends &&\n pendingOptions.depends.every(depId => {\n const depOpt = this.flowOptions.get(this.normalizeFlowId(depId));\n return depOpt && depOpt.status === this.FLOW_STATE.COMPLETED;\n })\n ) {\n this.setFlowOptions({ paused: false }, pendingFlowId);\n this.pendingFlows.delete(pendingFlowId);\n this.runFlow(pendingFlowId);\n }\n }\n },\n\n /**\n * Check all pending processes and run those whose dependencies are now resolved.\n * \n * @returns {void}\n */\n checkPendingProcesses() {\n if (!this.pendingProcesses.size) return;\n for (const process of this.pendingProcesses) {\n const missingDeps = process.depends.filter(depId => {\n const hasProcess = Array.from(this.flows.values()).some(flow =>\n flow.some(p => p.id === this.PREFIX + depId)\n );\n return !this.completedProcesses.has(this.PREFIX + depId) && !hasProcess;\n });\n if (missingDeps.length) {\n this.pendingProcesses.delete(process);\n this.log('DEP_NOT_FOUND', process.id, `${missingDeps.join(', ')}`);\n process._depsResolved = true;\n process._triggered = true;\n if (process._waitResolve) process._waitResolve();\n continue;\n }\n const allDepsCompleted = process.depends.every(depId => this.completedProcesses.has(this.PREFIX + depId));\n if (allDepsCompleted) {\n this.pendingProcesses.delete(process);\n process._depsResolved = true;\n if (process._triggered && process._waitResolve) process._waitResolve();\n }\n }\n },\n\n /**\n * Check if all flows/processes are complete and resolve global promise if so.\n * \n * @returns {Promise<void>}\n */\n async maybeComplete() {\n if ( ! this.hasStarted ) return;\n\n /**\n * Check for pending flows missed dependencies \n */\n if ( this.pendingFlows.size ) {\n for (const pendingFlowId of this.pendingFlows) {\n const pendingOptions = this.flowOptions.get(pendingFlowId);\n if (\n pendingOptions &&\n pendingOptions.depends &&\n pendingOptions.depends.some(depId => !this.flowOptions.has(this.normalizeFlowId(depId)))\n ) {\n this.setFlowOptions({ status: this.FLOW_STATE.COMPLETED }, pendingFlowId);\n this.pendingFlows.delete(pendingFlowId);\n this.log('FLOW_DEP_SKIPPED', { flow: pendingFlowId, depends: `${pendingOptions.depends.filter(depId => !this.flowOptions.has(this.normalizeFlowId(depId))).join(', ')}` });\n }\n }\n }\n \n /**\n * Check completed flows\n */\n let flowsDone = this.flowOptions.size ? Array.from(this.flowOptions.values()).every(opt => opt.status === this.FLOW_STATE.COMPLETED) : false;\n\n /**\n * Completion hooks run even when some flow is still outstanding, so a\n * plugin can hold work back and release it here. With no hooks\n * registered this is exactly the old behaviour: done when every flow\n * is done.\n */\n let maybeComplete = flowsDone;\n\n /*\n * Filter maybeComplete by completedFlowsActions\n */\n if ( this.flows.size && this.completedFlowsActions.size ) {\n for ( const cb of this.completedFlowsActions ) {\n maybeComplete = cb.call(this, flowsDone, this.flows, this.flowOptions);\n }\n }\n\n if ( ! maybeComplete ) return;\n\n if (this.completing) return;\n this.completing = true;\n\n this.log('ALL_COMPLETED');\n this.fire('ALL_COMPLETED');\n\n this.onAllComplete?.();\n if (this.globalResolve !== null) this.globalResolve();\n\n /**\n * Call all flows completion actions\n */\n if (this.allCompleteActions.size) {\n for (const action of this.allCompleteActions) {\n if (typeof action === 'function') action.call(this);\n }\n }\n\n /**\n * Reset run state unless the caller opted out (e.g. for debugging)\n */\n if (this.autoReset) this.reset();\n this.completing = false;\n },\n\n /**\n * Process all flows and their dependencies.\n * \n * @param {string|null} [flowId=null] - Specific flow ID or null for all.\n * @param {boolean} [withTrigger=false] - Whether to run with trigger logic.\n * @returns {this}\n */\n processFlows(flowId = null, withTrigger = false) {\n if (!this.flows.size) return;\n\n /**\n * Run all flows if no specific flowId is provided\n */\n let flowIds = flowId ? [flowId] : Array.from(this.flows.keys());\n\n /**\n * Filter flowIds by flowIdFilters\n */\n if ( flowIds.length && this.flowIdFilters.size ) {\n for ( const cb of this.flowIdFilters ) {\n if ( typeof cb === 'function' ) flowIds = cb.call(this, flowIds);\n }\n }\n\n /**\n * Sort flows: flows without triggers first, then by priority\n */\n flowIds.sort((a, b) => {\n const aOpts = this.flowOptions.get(a);\n const bOpts = this.flowOptions.get(b);\n const aHasTrigger = aOpts?.trigger != null;\n const bHasTrigger = bOpts?.trigger != null;\n \n if (aHasTrigger && !bHasTrigger) return 1;\n if (!aHasTrigger && bHasTrigger) return -1;\n \n const aPriority = aOpts?.priority || 0;\n const bPriority = bOpts?.priority || 0;\n return bPriority - aPriority;\n });\n\n for (const fid of flowIds) {\n const options = this.flowOptions.get(fid);\n\n /**\n * Skip if missed options or flow is already completed\n */\n if (!options || options.status === this.FLOW_STATE.COMPLETED) continue;\n\n /**\n * Flow-level conditions\n */\n if ( this.getConditionStatus(options.condition) ) {\n this.setFlowOptions({ status: this.FLOW_STATE.COMPLETED }, fid);\n continue;\n }\n\n /**\n * Only process if not paused\n */\n if (options.paused) continue;\n\n /**\n * Logic for trigger on flow level\n */\n if ( flowId === null || ( flowId && ! withTrigger ) ) {\n if (options.trigger != null) {\n const trigger = this.getTriggerFunction(options.trigger, options);\n if (trigger) {\n this.setFlowOptions({ paused: true }, fid);\n let triggered = false;\n trigger(() => {\n if (triggered) return;\n triggered = true;\n this.setFlowOptions({ paused: false }, fid);\n this.runFlow(fid, true);\n });\n continue;\n }\n }\n }\n\n /**\n * Set flow to running state\n */\n this.setFlowOptions({ status: this.FLOW_STATE.RUNNING }, fid);\n\n /**\n * Run flows in parallel\n */\n (async () => {\n\n options.beforeStart?.();\n\n /**\n * Delay per flow\n */\n if (options.delay && options.delay > 0) {\n await new Promise(res => setTimeout(res, options.delay));\n }\n\n /**\n * Sort processes by priority\n */\n const processes = (this.flows.get(fid) || []).slice();\n processes.sort((a, b) => (b.priority || 0) - (a.priority || 0));\n\n /**\n * Preload scripts / styles\n */\n if ( (options.preload || options.prefetch ) && ! options.trigger ) {\n for (const p of processes) {\n if (p.trigger) continue;\n if ((p.type === 'script' && p.src) || (p.type === 'style' && p.href)) {\n try {\n const link = document.createElement('link');\n link.rel = options.preload ? 'preload' : 'prefetch';\n link.href = p.src || p.href;\n link.as = p.type === 'script' ? 'script' : 'style';\n if (p.crossOrigin) link.crossOrigin = p.crossOrigin;\n document.head.appendChild(link);\n } catch (e) {\n this.error('PRELOAD_ERROR', e, p.id);\n }\n }\n }\n }\n\n const between = (options.between !== undefined && options.between !== null)\n ? options.between\n : this.globalBetween;\n \n if (options.ordered) {\n /**\n * Ordered: await previous process\n */\n let prev = Promise.resolve();\n processes.forEach((process, idx) => {\n prev = prev.then(async () => {\n if (idx > 0 && between) await new Promise(res => setTimeout(res, between));\n await this.run(process);\n });\n });\n await prev;\n } else {\n /**\n * Unordered: run all processes in parallel\n */\n const promises = processes.map(async (process, idx) => {\n if (idx > 0 && between) await new Promise(res => setTimeout(res, between));\n return this.run(process);\n });\n await Promise.all(promises);\n }\n\n /**\n * Set flow to completed state\n */\n this.setFlowOptions({ status: this.FLOW_STATE.COMPLETED }, fid);\n options.onComplete?.();\n\n /**\n * Check for pending flows\n */\n this.checkPendingFlows();\n\n /**\n * Maybe complete the loading\n */\n this.maybeComplete();\n\n })();\n }\n\n /**\n * Cover skipped/empty batches that never start an async flow.\n */\n this.checkPendingFlows();\n this.maybeComplete();\n },\n\n /**\n * Execute a process based on its type.\n * \n * @param {Object} process - The process object.\n * @returns {Promise<any>}\n */\n async run(process) {\n /**\n * Skip if already running or completed\n */\n if (process._running || this.getConditionStatus(process.condition)) return;\n process._running = true;\n\n /**\n * Setup state\n */\n if (!process._waitPromise) {\n process._triggered = false;\n process._depsResolved = false;\n process._waitPromise = new Promise(res => process._waitResolve = res);\n }\n\n /**\n * Trigger logic for process\n */\n if (process.trigger != null) {\n const trigger = this.getTriggerFunction(process.trigger, process);\n if (trigger) {\n trigger(() => {\n process._triggered = true;\n if (process._depsResolved) process._waitResolve();\n });\n } else {\n process._triggered = true;\n }\n } else {\n process._triggered = true;\n }\n\n /**\n * Check dependencies\n */\n if (Array.isArray(process.depends) && process.depends.length) {\n const missingDeps = process.depends.filter(depId => {\n const hasProcess = Array.from(this.flows.values()).some(flow =>\n flow.some(p => p.id === this.PREFIX + depId)\n );\n return !this.completedProcesses.has(this.PREFIX + depId) && !hasProcess;\n });\n if (missingDeps.length) {\n this.log('DEP_NOT_FOUND', process.id, `${missingDeps.join(', ')}`);\n process._depsResolved = true;\n process._triggered = true;\n if (process._waitResolve) process._waitResolve();\n } else {\n const allDepsCompleted = process.depends.every(depId => this.completedProcesses.has(this.PREFIX + depId));\n if (!allDepsCompleted) {\n this.pendingProcesses.add(process);\n } else {\n process._depsResolved = true;\n if (process._triggered) process._waitResolve();\n }\n }\n } else {\n process._depsResolved = true;\n if (process._triggered) process._waitResolve();\n }\n\n /**\n * Wait for both trigger and dependencies to be resolved\n */\n await process._waitPromise;\n\n return this.execute(process);\n },\n\n /**\n * Check the condition option and return true if the condition fails.\n * \n * @param {string|Function|boolean} conditionOption - The condition option.\n * @returns {boolean} True if the condition fails, false otherwise.\n */\n getConditionStatus(opt) {\n if (opt == null) return false;\n \n if (Array.isArray(opt)) {\n return opt.some(c => this.getConditionStatus(c));\n }\n \n if (typeof opt === 'object' && opt.operator) {\n const { operator, conditions } = opt;\n if (!Array.isArray(conditions)) return false;\n \n if (operator === 'or') {\n return conditions.every(c => this.getConditionStatus(c));\n } else if (operator === 'and') {\n return conditions.some(c => this.getConditionStatus(c));\n }\n return false;\n }\n \n if (typeof opt === 'function' && !opt()) return true;\n if (typeof opt === 'boolean' && !opt) return true;\n\n if (this.conditionHandlers.size) {\n for (const h of this.conditionHandlers) {\n if (typeof h === 'function') {\n const r = h.call(this, opt);\n if (r === true || r === false) return r;\n }\n }\n }\n\n return false;\n },\n\n /**\n * Parse and return a trigger function based on the trigger option.\n * \n * @param {string|Function|boolean} opt - The trigger option.\n * @param {Object} o - The associated process or flow object.\n * @returns {Function|null} The trigger function or null if no trigger function is found.\n */\n getTriggerFunction(opt, o) {\n if (opt == null) return null;\n \n if (typeof opt === 'function') {\n return (cb) => opt(cb);\n }\n \n /**\n * Return trigger function for array of triggers\n */\n if (Array.isArray(opt)) {\n return (cb) => {\n const vd = opt.map(t => this.getTriggerFunction(t, o)).filter(tF => tF);\n if (vd.length === 0) {\n cb();\n return;\n }\n let f = 0;\n const fCb = () => { if (++f === vd.length) cb(); };\n vd.forEach(tF => tF(fCb));\n };\n }\n \n /**\n * Return trigger function for object with operator and triggers\n */\n if (typeof opt === 'object' && opt.operator) {\n const { operator, triggers } = opt;\n if (!Array.isArray(triggers)) return null;\n \n if (operator === 'or') {\n return (cb) => {\n const vd = triggers.map(t => this.getTriggerFunction(t, o)).filter(tF => tF);\n if (vd.length === 0) {\n cb();\n return;\n }\n let f = false;\n const fCb = () => { if (!f) { f = true; cb(); } };\n vd.forEach(tF => tF(fCb));\n };\n } else if (operator === 'and') {\n return (cb) => {\n const vd = triggers.map(t => this.getTriggerFunction(t, o)).filter(tF => tF);\n if (vd.length === 0) {\n cb();\n return;\n }\n let f = 0;\n const fCb = () => { if (++f === vd.length) cb(); };\n vd.forEach(tF => tF(fCb));\n };\n }\n return null;\n }\n\n /**\n * Return trigger function from trigger handlers\n */\n if (this.triggerHandlers.size) {\n for (const h of this.triggerHandlers) {\n if (typeof h === 'function') {\n const r = h.call(this, opt, o);\n if (r && typeof r === 'function') return r;\n }\n }\n }\n \n /**\n * Return interaction trigger function if opt is true or 'interaction'\n */\n if (opt === true || opt === 'interaction') {\n return (cb) => this.waitForInteraction(cb);\n }\n \n return null;\n },\n\n /**\n * Wait for user interaction before running a callback (for interaction phase).\n * This is the default fallback trigger.\n * \n * @param {Function} cb - The callback to run after user interaction.\n * @returns {void}\n */\n waitForInteraction(cb) {\n ['click', 'keydown', 'wheel', 'mousedown', 'mousemove', 'touchstart'].forEach(e => window.addEventListener(e, () => cb(), { once: true, passive: true }));\n },\n\n /**\n * Execute the process based on its type.\n * \n * @param {Object} process - The process object.\n * @returns {Promise<any>}\n */\n async execute(process) {\n const finishProcess = async () => {\n /**\n * Call process completion actions\n */\n if (this.processCompleteActions.size) {\n for (const action of this.processCompleteActions) {\n if (typeof action === 'function') action.call(this, process);\n }\n }\n this.completedProcesses.add(process.id);\n process._running = false;\n this.checkPendingProcesses();\n };\n if (process.skipped) {\n this.fire('SKIPPED', { ...process, id: process.id });\n finishProcess();\n return;\n }\n const handler = this.types.get(process.type);\n if (!handler) {\n this.log('UNKNOWN_TYPE', process.type, process.id);\n finishProcess();\n return;\n }\n this.fire('STARTED', { ...process, id: process.id });\n \n /**\n * Build handler callbacks from filters\n */\n const callbacks = {};\n if (this.handlerCallbacksFilters.size) {\n for (const filter of this.handlerCallbacksFilters) {\n if (typeof filter === 'function') {\n const pluginCallbacks = filter.call(this, process);\n if (pluginCallbacks && typeof pluginCallbacks === 'object') {\n Object.assign(callbacks, pluginCallbacks);\n }\n }\n }\n }\n \n /**\n * Execute handler and handle completion or error\n */\n return handler(process, callbacks)\n .then(() => {\n this.fire('COMPLETED', { ...process, id: process.id });\n finishProcess();\n })\n .catch(() => {\n this.fire('ERROR', { ...process, id: process.id });\n finishProcess();\n });\n }\n};","/**\n * Get cache-bypass suffix for a URL.\n */\nconst bypassSuffix = (source, bypassCache) =>{\n return bypassCache ? ( ( source.includes('?') ? '&' : '?') + Date.now() ) : '';\n}\n\n/**\n * Log a message.\n */\nconst log = (detail) => {\n window.dispatchEvent(new CustomEvent('QSL:log', { detail }));\n}\n\n/**\n * Log an error.\n */\nconst error = (detail) => {\n window.dispatchEvent(new CustomEvent('QSL:error', { detail }));\n}\n\n/**\n * Render an element.\n */\nconst render = (config, callbacks = {}) => {\n return new Promise(async (resolve) => {\n const { flowId, tag, id, delay, data, onBeforeStart, onComplete, onError, footer, dom, onElement, onCustomResolve } = config;\n if (!flowId || !tag || !id) {\n resolve();\n return;\n }\n try {\n if (onBeforeStart) await onBeforeStart(config);\n log({ tag, type: 'PROCESS_STARTED', config });\n if (delay) await new Promise(res => setTimeout(res, delay));\n let el = document.createElement(tag);\n onElement?.(el, config);\n\n callbacks.registerProcessElement?.(el, config);\n\n if (data && typeof data === 'object') {\n for (const [key, value] of Object.entries(data)) {\n el.setAttribute(`data-${key.replace(/([A-Z])/g, '-$1').toLowerCase().replace(/[^a-z0-9_-]/g, '').replace(/^-/, '')}`, String(value));\n }\n }\n\n if (!onCustomResolve) {\n el.onload = () => {\n log({ tag, type: 'PROCESS_COMPLETED', config });\n onComplete?.();\n resolve();\n };\n }\n el.onerror = (e) => {\n error({ tag, type: 'PROCESS_FAILED', config });\n onError?.(e);\n resolve(e);\n };\n if (dom) {\n (footer ? document.body : document.head).appendChild(el);\n }\n onCustomResolve?.({ el, config, resolve });\n } catch (e) {\n error({ tag, type: 'PROCESS_FAILED', config, error: e });\n onError?.(e);\n resolve(e);\n }\n });\n}\n\n/**\n * Render an inline script.\n */\nconst InlineScript = {\n type: 'inline-script',\n handler: (config, callbacks) => { \n let storedResolve = null;\n let alreadyFired = false;\n const eventName = `QSL:inline-script:completed:${config.id}`;\n const resolveProcess = () => {\n log({ tag: 'inline-script', type: 'INLINE_SCRIPT_SUCCESS', config });\n log({ tag: 'inline-script', type: 'PROCESS_COMPLETED', config });\n config?.onComplete?.();\n storedResolve?.();\n };\n const normalizedConfig = {\n ...config,\n code: config.code?.replace(/<script.*?>|<\\/script>/gi, '')\n };\n return render({\n ...normalizedConfig,\n tag: 'script',\n dom: true,\n onElement: (el, config) => {\n const { code, module, id, flowId } = config;\n if (code) el.textContent = code;\n if (module) {\n el.type = 'module';\n const originalCode = el.textContent;\n const fid = JSON.stringify(String(flowId));\n const pid = JSON.stringify(String(id));\n const evt = JSON.stringify(String(eventName));\n const wrappedCode = `(function(){window.__QSL__.currentProcessPerFlow.set(${fid},${pid});try{${originalCode}}finally{window.__QSL__.currentProcessPerFlow.delete(${fid});window.dispatchEvent(new Event(${evt}));}})();`;\n el.textContent = wrappedCode;\n const handler = () => {\n window.removeEventListener(eventName, handler);\n if (storedResolve) {\n resolveProcess();\n } else { \n alreadyFired = true;\n }\n };\n window.addEventListener(eventName, handler);\n }\n },\n onCustomResolve: ({ el, config, resolve }) => {\n const { module } = config;\n storedResolve = resolve;\n if (module && alreadyFired) {\n resolveProcess();\n } else if (!module) {\n queueMicrotask(() => {\n if (storedResolve === resolve) resolveProcess();\n });\n }\n }\n }, callbacks);\n }\n};\n\n/**\n * Render a script element.\n */\nconst Script = {\n type: 'script',\n handler: (config, callbacks) => { \n return render({\n ...config,\n tag: 'script',\n dom: true,\n onElement: (el, { src, module, async, defer, crossOrigin, integrity, bypassCache }) => {\n if (module) el.type = 'module';\n if (async) el.async = async;\n if (defer) el.defer = defer;\n if (crossOrigin) el.crossOrigin = crossOrigin;\n if (integrity) el.integrity = integrity;\n if (src) el.src = src + bypassSuffix(src, bypassCache);\n }\n }, callbacks);\n }\n};\n\n/**\n * Render an inline style.\n */\nconst InlineStyle = {\n type: 'style',\n handler: (config, callbacks) => {\n const normalizedConfig = {\n ...config,\n code: config.code?.replace(/<style.*?>|<\\/style>/gi, '')\n };\n return render({\n ...normalizedConfig,\n tag: 'style',\n dom: true,\n onElement: (el, { code }) => {\n if (code) el.textContent = code;\n },\n onCustomResolve: ({ el, config, resolve }) => {\n const { tag, onComplete } = config;\n log({ tag, type: 'INLINE_STYLE_SUCCESS', config });\n log({ tag, type: 'PROCESS_COMPLETED', config });\n onComplete?.();\n resolve();\n }\n }, callbacks);\n }\n};\n\n/**\n * Render a stylesheet.\n */\nconst Stylesheet = {\n type: 'stylesheet',\n handler: (config, callbacks) => {\n return render({\n ...config,\n tag: 'link',\n dom: true,\n onElement: (el, { href, crossOrigin, bypassCache }) => {\n el.rel = 'stylesheet';\n if (crossOrigin) el.crossOrigin = crossOrigin;\n el.href = href + bypassSuffix(href, bypassCache);\n }\n }, callbacks);\n }\n};\n\n/**\n * Render a pixel.\n */\nconst Pixel = {\n type: 'pixel',\n handler: (config, callbacks) => {\n return render({\n ...config,\n tag: 'img',\n dom: true,\n onElement: (el, { style = { display: 'none' }, dom, src, bypassCache }) => {\n if ( ! dom ) el = new window.Image();\n el.src = src + bypassSuffix(src, bypassCache);\n el.width = 1;\n el.height = 1;\n if ( style && typeof style === 'object' ) {\n for (const [key, value] of Object.entries(style)) {\n el.style.setProperty(key, value);\n }\n }\n },\n onCustomResolve: ({ el, config, resolve }) => {\n const { tag, dom, onComplete } = config;\n const resolver = () => {\n log({ tag, type: 'IMAGE_LOADED', config });\n log({ tag, type: 'PROCESS_COMPLETED', config });\n onComplete?.();\n resolve();\n };\n ! dom ? resolver() : el.onload = () => resolver();\n }\n }, callbacks);\n }\n};\n\n/**\n * Render a custom element.\n */\nconst Shadow = {\n type: 'shadow',\n handler: (config, callbacks) => {\n return render({\n ...config,\n onBeforeStart: async ({ tag }) => await window.customElements.whenDefined(tag),\n onElement: (el, { shadowData }) => {\n el.data = shadowData || {};\n if (shadowData?.hidden) el.setAttribute('hidden', ''); \n },\n onCustomResolve: ({ el, config, resolve }) => {\n const { tag, shadowData, onComplete, onError } = config;\n const resolver = () => {\n const selector = shadowData?.container;\n let container = null;\n if (selector === 'body') {\n container = document.body;\n } else if (typeof selector === 'string' && selector) {\n try {\n container = document.querySelector(selector);\n } catch (e) {\n container = null;\n }\n }\n if (!container) {\n const err = new Error(`Container not found: ${selector}`);\n error({ tag, type: 'SHADOW_FAILED', config, error: err });\n onError?.(err);\n resolve(err);\n return;\n }\n shadowData?.position === 'top' ? container.insertBefore(el, container.firstChild) : container.appendChild(el);\n log({ tag, type: 'SHADOW_SUCCESS', config });\n log({ tag, type: 'PROCESS_COMPLETED', config });\n onComplete?.();\n resolve();\n };\n if (document.readyState === 'interactive' || document.readyState === 'complete') {\n resolver();\n } else {\n document.addEventListener('DOMContentLoaded', resolver, { once: true });\n }\n }\n }, callbacks);\n }\n}\n\n/**\n * Render an HTML element.\n */\nconst HTML = {\n type: 'html',\n handler: (config, callbacks) => {\n return render({\n ...config,\n dom: true,\n onElement: (el, { html = '', id = '', className = '', style = {} }) => {\n if (html) el.innerHTML = html;\n if (id) el.id = id;\n if (className) el.className = Array.isArray(className) ? className.join(' ') : className;\n if ( style && typeof style === 'object' ) {\n for (const [key, value] of Object.entries(style)) {\n el.style.setProperty(key, value);\n }\n }\n },\n onCustomResolve: ({ el, config, resolve }) => {\n const { tag, onComplete } = config;\n log({ tag, type: 'HTML_SUCCESS', config });\n log({ tag, type: 'PROCESS_COMPLETED', config });\n onComplete?.();\n resolve();\n }\n }, callbacks);\n }\n};\n\n/**\n * Default types for QSL.\n */\nexport { Script, Stylesheet, InlineScript, InlineStyle, Pixel, Shadow, HTML };","import core from '../core.js';\n\nimport { Script } from '../types.js';\n\ncore\n .registerTypes([Script])\n .init();"],"names":["core","VERSION","PREFIX","FLOW_TYPE","DEFAULT","ORDERED","FLOW_STATE","READY","RUNNING","COMPLETED","FLOW_OPTIONS","delay","priority","between","trigger","condition","beforeStart","onComplete","group","paused","preload","fireEvents","depends","EVENTS","STARTED","ERROR","FLOW_STARTED","FLOW_COMPLETED","ALL_COMPLETED","SKIPPED","DOMREADY","LOADED","LIFECYCLE","document","readyState","CALLBACK","types","Map","flows","flowOptions","flowGroups","currentProcessPerFlow","pendingFlows","Set","pendingProcesses","completedProcesses","loadActions","initActions","addProcessFilters","completedFlowsActions","flowIdFilters","conditionHandlers","triggerHandlers","processCompleteActions","allCompleteActions","resetActions","handlerCallbacksFilters","onAllComplete","globalResolve","logger","hasStarted","eventsEnabled","initialized","completing","autoReset","globalBetween","init","this","loaderScript","currentScript","window","__QSL__","addEventListener","once","registerType","process","Promise","resolve","_a","onBeforeStart","call","setTimeout","message","log","timestamp","Date","now","e","detail","type","config","id","error","size","cb","url","src","URL","baseURI","searchParams","get","callback","use","plugin","args","add","flowId","Math","random","toString","slice","skipped","Array","isArray","normalizedFlowId","normalizeFlowId","getOrCreateFlow","push","load","reset","processFlows","action","clear","destroy","setLogger","setOnAllComplete","useEvents","fire","event","dispatchEvent","CustomEvent","handler","set","registerTypes","list","Object","entries","map","pauseGroup","flowGroup","setFlowOptions","runGroup","runFlow","withTrigger","processes","options","status","has","ordered","prevOptions","length","checkPendingFlows","pendingFlowId","pendingOptions","every","depId","depOpt","delete","checkPendingProcesses","missingDeps","filter","hasProcess","from","values","some","flow","p","join","_depsResolved","_triggered","_waitResolve","maybeComplete","flowsDone","opt","flowIds","keys","sort","a","b","aOpts","bOpts","aHasTrigger","bHasTrigger","aPriority","fid","getConditionStatus","getTriggerFunction","triggered","res","prefetch","href","link","createElement","rel","as","crossOrigin","head","appendChild","prev","forEach","idx","then","async","run","promises","all","_b","_running","_waitPromise","execute","c","operator","conditions","h","r","o","vd","t","tF","f","fCb","triggers","waitForInteraction","passive","finishProcess","callbacks","pluginCallbacks","assign","catch","Script","tag","data","onError","footer","dom","onElement","onCustomResolve","el","registerProcessElement","key","value","setAttribute","replace","toLowerCase","String","onload","onerror","body","render","module","defer","integrity","bypassCache","source","includes","bypassSuffix"],"mappings":"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"}
|
package/package.json
CHANGED
package/src/core.js
CHANGED
|
@@ -2,7 +2,7 @@ export default {
|
|
|
2
2
|
/**
|
|
3
3
|
* Constants
|
|
4
4
|
*/
|
|
5
|
-
VERSION: '0.1.
|
|
5
|
+
VERSION: '0.1.4',
|
|
6
6
|
PREFIX: 'qsl-',
|
|
7
7
|
FLOW_TYPE: {
|
|
8
8
|
DEFAULT: 'default',
|
|
@@ -86,6 +86,12 @@ export default {
|
|
|
86
86
|
async init() {
|
|
87
87
|
if (this.initialized) return this;
|
|
88
88
|
|
|
89
|
+
/**
|
|
90
|
+
* document.currentScript is only set while this script is running
|
|
91
|
+
* synchronously. Capture it before the first await below: an init
|
|
92
|
+
* action that waits on anything real would otherwise leave it null,
|
|
93
|
+
* and the async ready callback would silently never fire.
|
|
94
|
+
*/
|
|
89
95
|
const loaderScript = document.currentScript;
|
|
90
96
|
|
|
91
97
|
/* Check if QSL is already initialized */
|
package/src/plugins/events.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
export default function(QSL) {
|
|
6
6
|
const customEvents = new Map();
|
|
7
7
|
const processElementMap = new WeakMap();
|
|
8
|
+
let processCounter = 0;
|
|
8
9
|
let documentListener = null;
|
|
9
10
|
let windowListener = null;
|
|
10
11
|
let isIntercepting = false;
|
|
@@ -23,6 +24,26 @@ export default function(QSL) {
|
|
|
23
24
|
}
|
|
24
25
|
};
|
|
25
26
|
|
|
27
|
+
/**
|
|
28
|
+
* A key that is unique to this process OBJECT, not to its id.
|
|
29
|
+
*
|
|
30
|
+
* Ids are not unique: the same explicit id can be used by a process in a
|
|
31
|
+
* later load() cycle, or by a late add that the dynamic plugin puts in its
|
|
32
|
+
* own flow. Keying the private event name on the id alone means the second
|
|
33
|
+
* process dispatches an event the first process's listener is still bound
|
|
34
|
+
* to, and that listener runs again. Every listener from one process shares
|
|
35
|
+
* this key, so one dispatch still serves all of them.
|
|
36
|
+
*
|
|
37
|
+
* @param {Object} process
|
|
38
|
+
* @returns {string}
|
|
39
|
+
*/
|
|
40
|
+
const processKey = (process) => {
|
|
41
|
+
if (!process._eventKey) {
|
|
42
|
+
process._eventKey = process.id + '#' + (++processCounter);
|
|
43
|
+
}
|
|
44
|
+
return process._eventKey;
|
|
45
|
+
};
|
|
46
|
+
|
|
26
47
|
/**
|
|
27
48
|
* Initialize event interception when QSL loads.
|
|
28
49
|
*/
|
|
@@ -124,9 +145,10 @@ export default function(QSL) {
|
|
|
124
145
|
if (process) {
|
|
125
146
|
const shouldFireEvents = process.fireEvents !== false && (this.flowOptions.get(targetFlowId)?.fireEvents !== false);
|
|
126
147
|
if (shouldFireEvents) {
|
|
127
|
-
const
|
|
128
|
-
|
|
129
|
-
|
|
148
|
+
const key = processKey(process);
|
|
149
|
+
const eventName = `${type}:${key}`;
|
|
150
|
+
if (!customEvents.has(key)) customEvents.set(key, []);
|
|
151
|
+
const events = customEvents.get(key);
|
|
130
152
|
if (!events.some(e => e.name === eventName)) events.push({ type: eventType, name: eventName });
|
|
131
153
|
if (changeEventName) type = eventName;
|
|
132
154
|
}
|
|
@@ -137,22 +159,22 @@ export default function(QSL) {
|
|
|
137
159
|
|
|
138
160
|
document.addEventListener = (type, listener, opts) => {
|
|
139
161
|
if (type === 'DOMContentLoaded' && this.LIFECYCLE.DOMREADY) {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
162
|
+
/**
|
|
163
|
+
* Only rename here. The renamed event is dispatched once, when
|
|
164
|
+
* the process completes (see processCompleteActions below).
|
|
165
|
+
* Dispatching here as well would deliver it twice, and a vendor
|
|
166
|
+
* that registers two listeners would see every one of them fire
|
|
167
|
+
* once per registration on top of that.
|
|
168
|
+
*/
|
|
169
|
+
type = iterator.call(this, type, this.EVENTS.DOMREADY, true);
|
|
145
170
|
}
|
|
146
171
|
return documentListener.call(document, type, listener, opts);
|
|
147
172
|
};
|
|
148
173
|
|
|
149
174
|
window.addEventListener = (type, listener, opts) => {
|
|
150
175
|
if (type === 'load' && this.LIFECYCLE.LOADED) {
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
type = trackedType;
|
|
154
|
-
queueMicrotask(() => window.dispatchEvent(new Event(trackedType)));
|
|
155
|
-
}
|
|
176
|
+
/* Same as above: rename now, dispatch once on completion. */
|
|
177
|
+
type = iterator.call(this, type, this.EVENTS.LOADED, true);
|
|
156
178
|
}
|
|
157
179
|
return windowListener.call(window, type, listener, opts);
|
|
158
180
|
};
|
|
@@ -175,7 +197,7 @@ export default function(QSL) {
|
|
|
175
197
|
* Use processCompleteActions instead of patching execute.
|
|
176
198
|
*/
|
|
177
199
|
QSL.processCompleteActions.add(function(process) {
|
|
178
|
-
const events = customEvents.get(process.
|
|
200
|
+
const events = customEvents.get(process._eventKey);
|
|
179
201
|
if (events && Array.isArray(events)) {
|
|
180
202
|
for (const event of events) {
|
|
181
203
|
if (event.type === this.EVENTS.DOMREADY) {
|
package/src/presets/full.js
CHANGED
|
@@ -8,6 +8,7 @@ import { loadTrigger, idleTrigger, domReadyTrigger, delayTrigger, hoverTrigger,
|
|
|
8
8
|
import logger from '../plugins/logger.js';
|
|
9
9
|
import events from '../plugins/events.js';
|
|
10
10
|
import circ from '../plugins/circ.js';
|
|
11
|
+
import dynamic from '../plugins/dynamic.js';
|
|
11
12
|
|
|
12
13
|
core
|
|
13
14
|
.registerTypes([Script, InlineScript, InlineStyle, Stylesheet, Pixel, Shadow, HTML])
|
|
@@ -15,6 +16,7 @@ core
|
|
|
15
16
|
.use(logger)
|
|
16
17
|
.use(events)
|
|
17
18
|
.use(circ)
|
|
19
|
+
.use(dynamic)
|
|
18
20
|
|
|
19
21
|
.use(mediaQueryCondition)
|
|
20
22
|
.use(languageCondition)
|