senangwebs-story
Version:
Lightweight, dependency-free JavaScript library for creating interactive, visual novel-style story experiences.
1 lines • 6.84 kB
JavaScript
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.SWS=t():e.SWS=t()}(this,()=>(()=>{"use strict";var e={d:(t,s)=>{for(var n in s)e.o(s,n)&&!e.o(t,n)&&Object.defineProperty(t,n,{enumerable:!0,get:s[n]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t)},t={};e.d(t,{default:()=>n});class s{constructor(e,t){this.element=e,this.config=t,this.storyId=null,this.scenes=[],this.currentSceneIndex=0,this.currentDialogIndex=0,this.typewriterTimeout=null,this.isTypewriterRunning=!1,this.dialogSpeed=50,this.config?this._initFromJSON():this._initFromHTML(),this._setupUI(),this._updateUI(),this._attachEventListeners()}_initFromHTML(){if(this.storyId=this.element.dataset.swsId,this.element.dataset.swsDialogSpeed){const e=parseInt(this.element.dataset.swsDialogSpeed,10);!isNaN(e)&&e>0&&(this.dialogSpeed=e)}Array.from(this.element.querySelectorAll("[data-sws-scene-1], [data-sws-scene-2], [data-sws-scene-3], [data-sws-scene-4], [data-sws-scene-5], [data-sws-scene-6], [data-sws-scene-7], [data-sws-scene-8], [data-sws-scene-9]")).forEach((e,t)=>{const s={element:e,sceneStart:e.dataset.swsSceneStart||null,background:e.querySelector("[data-sws-background] img")?.src,subjects:[],dialogs:[]},n=Array.from(e.querySelectorAll("[data-sws-subject-id]"));s.subjects=n.map(e=>({id:e.dataset.swsSubjectId,name:e.dataset.swsSubjectName,element:e})),Array.from(e.querySelectorAll("[data-sws-dialog-1], [data-sws-dialog-2], [data-sws-dialog-3], [data-sws-dialog-4], [data-sws-dialog-5], [data-sws-dialog-6], [data-sws-dialog-7], [data-sws-dialog-8], [data-sws-dialog-9]")).forEach((e,t)=>{s.dialogs.push({element:e,text:e.querySelector("p").innerHTML.trim(),subjectId:e.dataset.swsSubject||null,dialogStart:e.dataset.swsDialogStart||null})}),this.scenes.push(s)})}_initFromJSON(){if(this.storyId=this.config.id,this.config.dialogSpeed){const e=parseInt(this.config.dialogSpeed,10);!isNaN(e)&&e>0&&(this.dialogSpeed=e)}this.element.dataset.sws=!0,this.element.dataset.swsId=this.storyId,this.element.innerHTML="",this.config.scenes.forEach((e,t)=>{const s=document.createElement("div");s.setAttribute(`data-sws-scene-${t+1}`,""),e.sceneStart&&(s.dataset.swsSceneStart=e.sceneStart),t>0&&(s.style.display="none");const n=document.createElement("div");n.dataset.swsBackground="";const a=document.createElement("img");a.src=e.background,a.alt=`Scene Background ${t+1}`,n.appendChild(a),s.appendChild(n);const i=document.createElement("div");i.dataset.swsSubjects="";const c=[];e.subjects.forEach(e=>{const t=document.createElement("img");t.src=e.src,t.dataset.swsSubjectId=e.id,t.dataset.swsSubjectName=e.name,t.alt=e.name,i.appendChild(t),c.push({id:e.id,name:e.name,element:t})}),s.appendChild(i);const d=document.createElement("div");d.dataset.swsDialogBox="";const r=document.createElement("h4");r.dataset.swsActiveSubjectName="",d.appendChild(r);const o=[];e.dialogs.forEach((e,t)=>{const s=document.createElement("div");s.dataset.swsDialog=t+1,s.setAttribute(`data-sws-dialog-${t+1}`,""),e.subjectId&&(s.dataset.swsSubject=e.subjectId),e.dialogStart&&(s.dataset.swsDialogStart=e.dialogStart);const n=document.createElement("p");n.innerHTML=e.text,s.appendChild(n),d.appendChild(s),o.push({element:s,text:e.text,subjectId:e.subjectId||null,dialogStart:e.dialogStart||null})}),s.appendChild(d),this.element.appendChild(s);const l={element:s,sceneStart:e.sceneStart||null,background:e.background,subjects:c,dialogs:o};this.scenes.push(l)});const e=document.createElement("div");e.dataset.swsActions="";const t=document.createElement("button");t.dataset.swsButton="back",t.textContent="Back";const s=document.createElement("button");s.dataset.swsButton="next",s.textContent="Next",e.appendChild(t),e.appendChild(s),this.element.appendChild(e)}_setupUI(){this.scenes.forEach((e,t)=>{e.element.style.display=0===t?"":"none",e.dialogs.forEach((e,t)=>{e.element&&(e.element.style.display="none")})})}_attachEventListeners(){const e=this.element.querySelector('[data-sws-button="next"]'),t=this.element.querySelector('[data-sws-button="back"]');e&&e.addEventListener("click",()=>this.next()),t&&t.addEventListener("click",()=>this.back())}next(){if(this.isTypewriterRunning)return void this._completeTypewriter();const e=this.scenes[this.currentSceneIndex];this.currentDialogIndex<e.dialogs.length-1?(this.currentDialogIndex++,this._updateUI()):this.currentSceneIndex<this.scenes.length-1&&(this.currentSceneIndex++,this.currentDialogIndex=0,this._updateUI(!0))}back(){this._completeTypewriter(),this.currentDialogIndex>0?(this.currentDialogIndex--,this._updateUI()):this.currentSceneIndex>0&&(this.currentSceneIndex--,this.currentDialogIndex=this.scenes[this.currentSceneIndex].dialogs.length-1,this._updateUI(!0))}_updateUI(e=!1){e&&(this.scenes.forEach((e,t)=>{e.element.style.display=t===this.currentSceneIndex?"":"none"}),this._executeCallback(this.scenes[this.currentSceneIndex].sceneStart));const t=this.scenes[this.currentSceneIndex];if(!t||!t.dialogs||this.currentDialogIndex>=t.dialogs.length)return void console.error("Scene or dialog not found",{sceneIndex:this.currentSceneIndex,dialogIndex:this.currentDialogIndex,totalScenes:this.scenes.length,scene:t});const s=t.dialogs[this.currentDialogIndex];t.dialogs.forEach((e,t)=>{e.element&&(e.element.style.display="none")});const n=t.element.querySelector(`[data-sws-dialog-${this.currentDialogIndex+1}]`),a=t.element.querySelector("[data-sws-active-subject-name]"),i=t.subjects.find(e=>e.id===s.subjectId);t.subjects.forEach(e=>e.element?.classList.remove("active")),i?(a.textContent=i.name,i.element?.classList.add("active")):a.textContent="",n?(this._typewriter(s.text,n.querySelector("p")),this._executeCallback(s.dialogStart)):console.error("Active dialog element not found",{sceneIndex:this.currentSceneIndex,dialogIndex:this.currentDialogIndex,selector:`[data-sws-dialog-${this.currentDialogIndex+1}]`,sceneElement:t.element})}_typewriter(e,t){if(!t)return;t.parentElement.style.display="",t.textContent="",this.isTypewriterRunning=!0;let s=0;const n=()=>{s<e.length?(t.textContent+=e.charAt(s),s++,this.typewriterTimeout=setTimeout(n,this.dialogSpeed)):this.isTypewriterRunning=!1};n()}_completeTypewriter(){if(this.typewriterTimeout){clearTimeout(this.typewriterTimeout),this.typewriterTimeout=null,this.isTypewriterRunning=!1;const e=this.scenes[this.currentSceneIndex],t=e.dialogs[this.currentDialogIndex],s=e.element.querySelector(`[data-sws-dialog-${this.currentDialogIndex+1}]`);s&&(s.querySelector("p").textContent=t.text)}}_executeCallback(e){if(e)try{new Function(e)()}catch(e){console.error("Error executing callback:",e)}}}document.addEventListener("DOMContentLoaded",()=>{document.querySelectorAll("[data-sws]").forEach(e=>new s(e))});const n=s;return t.default})());