@osaedasia/oresume
Version:
A user-friendly library for generating complete Single Page Applications (SPAs)
2 lines (1 loc) • 3.81 kB
JavaScript
import{DomHelper as t}from"../infrastructure/helpers/DomHelper.js";import{FragmentAttributes as e}from"../domain/attributes/FragmentAttributes.js";import{ParserAttributes as r}from"../domain/attributes/ParserAttributes.js";import{FunctionAttributes as n}from"../domain/attributes/FunctionAttributes.js";import{ObserverAttributes as s}from"../domain/attributes/ObserverAttributes.js";import{RandomUUID as i}from"@osaedasia/std";import{isAnHTMLObject as o}from"../domain/definitions/interfaces/HTMLObject.js";import{ElementNotFoundInFragmentError as a,FragmentRootNotFoundError as m}from"../domain/exceptions/Fragment.js";import{App as c}from"./App.js";class l{_virtualFragment;_fragmentUUID;_fragmentName;_registeredEvents=[];_registeredObservers=[];constructor(t){this._fragmentUUID=i.v4,this._fragmentName=t,this._virtualFragment=this._createHTMLFragment({html:`\n <div style="border: 1px solid; padding: 4px 12px; border-radius: 8px;">\n <h3>Empty fragment.</h3>\n <p>To change the content of "${this._fragmentName}", update the 'content' property !</p>\n </div>\n `,patterns:[]})}set content(t){this.detachAllEvents(),this._registeredEvents=[],this._registeredObservers=[];const e="function"==typeof t?t({navigate:c.navigate}):t;this._virtualFragment=this._createHTMLFragment(e)}get fragment(){return this._preLoadFragment(),this._virtualFragment.cloneNode(!0)}addEventListener(t,e,r){if(!this._getActiveFragmentRoot().querySelector(t))throw new a(`Could not find element '${t}' in fragment.`);this._registeredEvents.push({selector:t,type:e,callback:r})}detachAllEvents(){const t=this._getActiveFragmentRoot();this._iterateListeners(t,((t,e)=>e.removeEventListener(t.type,t.callback)),(t=>{}));for(const t of this._registeredObservers)t.unsub&&(t.unsub(),t.unsub=void 0)}attachAllEvents(){const t=this._getActiveFragmentRoot();this._iterateListeners(t,((t,e)=>e.addEventListener(t.type,t.callback)),(t=>{throw new a(`Could not find element '${t.selector}' in fragment while attaching events.`)}));for(const e of this._registeredObservers){const r=t.querySelector(e.selector);if(!r)throw new a(`Could not find element '${e.selector}' in fragment while subscribing to the observer.`);e.unsub=e.observer.subscribe((t=>{r.innerHTML=this._getObserverStateString(t)}))}}_preLoadFragment(){for(const t of this._registeredObservers){const e=this._virtualFragment.querySelector(t.selector);if(!e)throw new a(`Could not find element '${t.selector}' in fragment while pre-loading the observer.`);e.innerHTML=this._getObserverStateString(t.observer.state)}}_getObserverStateString(t){return o(t)?t.toHtml():String(t)}_iterateListeners(t,e,r){for(const n of this._registeredEvents){const s=t.querySelector(n.selector);s?e(n,s):r(n)}}_createHTMLFragment(o){const a=t.wrapHtmlInSingleDiv(o.html),m=a.firstElementChild;m&&(m.setAttribute(e.ID,this._fragmentUUID),m.setAttribute(e.NAME,this._fragmentName));for(const t of o.patterns){const e=a.querySelector(`[${r.PATTERN}="${t.marker}"]`);if(e){const o=i.v4;if(e.removeAttribute(r.PATTERN),"function"===t.type){e.setAttribute(n.ID,o);const r=t.handler.name.trim();e.setAttribute(n.NAME,r.length<=0?"anonymous":r),this._registeredEvents.push({selector:`[${n.ID}="${o}"]`,type:t.eventType??"click",callback:()=>t.handler()})}"observer"===t.type&&(e.setAttribute(s.ID,o),this._registeredObservers.push({selector:`[${s.ID}="${o}"]`,observer:t.observer}))}}return a.cloneNode(!0)}_getActiveFragmentRoot(){try{return this._findRootElementInDOMByUUID()}catch{return this.fragment}}_findRootElementInDOMByUUID(){const t=document.querySelector(`[${e.ID}="${this._fragmentUUID}"]`);if(!t)throw new m(`Could not find main fragment with ${e.ID}="${this._fragmentUUID}".`);return t}}export{l as Fragment};