diff --git a/main.js b/main.js index 7f9760a..ba72013 100644 --- a/main.js +++ b/main.js @@ -27,27 +27,51 @@ const pools = { }; +/** Stear class */ export class Stear{ elem; #childs = {}; + #frames = []; + /** + * Creating a Stear class. It can be used to render "stear" in an Element. + * + * @param {HTMLElement} elem + */ constructor(elem){ this.elem = elem; elem.style.position="relative"; } + /** + * Change the Style of the render Element. + * + * @param {JSON} css + */ style(css){ Object.entries(css).forEach(([k, d]) => { this.elem.style[k] = d; }); } + /** + * An Store for Frames + * + * @param {string} id + * @param {SFrame} elem + */ addElement (id,elem){ if(!(elem instanceof SFrame))throw new TypeError("Cannot add Element not extending from SFrame"); this.#childs[id] = elem; } + /** + * Access an Element from the Frame Store + * + * @param {string} id + * @returns + */ getElement (id) { return this.g(id); } @@ -56,18 +80,69 @@ export class Stear{ return this.#childs[id]; } + /** + * Render an Element gloabal. + * + * @param {SFrame} elem + * @param {*} args + * @param {number} layer + * @returns + */ async call (elem, args, layer = 1){ - return await elem.call(this, args, layer); + return await elem.call(this, args, this.#frames, layer); } + /** + * Render an Element in annother Element. + * + * @param {SFrame} elem + * @param {*} args + * @param {HTMLElement} renderParent + * @param {number} layer + * @returns + */ include(elem, args, renderParent, layer = 1){ - return elem.call(this, args, layer, renderParent); + return elem.call(this, args, this.#frames, layer, renderParent); } + /** + * Rernder everthing. + * + * @param {*} arg + * @returns + */ + rerenderGlobal(arg){ + if(this.#frames.length == 0)return; + return new Promise((res,rej)=>{ + let running = this.#frames.length; + for (let i = 0; i < this.#frames.length; i++) { + const element = this.#frames[i]; + element.globalRenderRequest(arg) + .then(()=>{ + running--; + if(running==0)res(); + }); + } + }); + + } + + /** + * Add raw css Data. + * + * @param {string} text + */ static addGlobalStyleText(text){ globalStyle.innerHTML+="\n"+text; } + /** + * Add a css Animation + * + * @param {object} steps - css like json Syntax + * @param {string} name + * @returns {string} name + */ static addAnimation(steps, name = "stearAnimation_" + counter++){ Stear.addGlobalStyleText(`@keyframes ${name} { ${ @@ -80,6 +155,13 @@ ${Object.entries(d).map(d => " " + toCssAttr(d[0]) + ": " + d[1] + ";").joi return name; } + + /** + * + * @param {object} json - css like json Syntax + * @param {string} name - e.g. .classname + * @returns {string} name + */ static addGlobalStyleJSON(json, name = ".stearClass_" + counter++){ Stear.addGlobalStyleText(` ${name} { @@ -89,6 +171,12 @@ ${Object.entries(json).map(d => " " + toCssAttr(d[0]) + ": " + d[1] + ";").jo return name; } + /** + * Add A Language Pool. E.g. for a subpage. + * + * @param {string} name + * @returns {LanguagePool} + */ static addLanguagePool(name){ if(typeof pools[name] == "undefined"){ pools[name] = new LanguagePool(); @@ -96,19 +184,32 @@ ${Object.entries(json).map(d => " " + toCssAttr(d[0]) + ": " + d[1] + ";").jo return pools[name]; } + /** + * Add a file containing translations. + * + * @param {JSON} data + * @param {string} lang + */ static addLanguageFile(data,lang){ Object.entries(data).forEach(([k,d]) => { if (typeof pools[k] == "undefined") pools[k] = new LanguagePool(); pools[k].addFile(d,lang); }); - } + } + /** + * Used Language + */ static set lang (lang){ Object.entries(pools).forEach(([k, d]) => { d.lang = lang; }); + this.globalRenderRequest(); } + /** + * Generate Language File with defaults + */ static get getLanguageFile(){ var out = {}; Object.entries(pools).forEach(([k, d]) => { @@ -118,20 +219,141 @@ ${Object.entries(json).map(d => " " + toCssAttr(d[0]) + ": " + d[1] + ";").jo } } +//////////////////////////////////////////////////////////////////////// +//utils +/** + * Can be called to close a frame and return a response. + * @async + * @callback utilsResolveCallback + * @param {*} returnValue + * @param {boolean} close + */ + +/** + * Remove this Frame from Screen + * @async + * @callback utilsCloseCallback + */ + +/** + * Rerender the local Content + * @async + * @callback utilsRenderCallback + * @param {...*} args + * @return {objectt} find + */ + +/** + * Open and run another frame with the ability to return data. + * @async + * @callback utilsCallCallback + * @param {SFrame} elem + * @param {*} args + * @return {callPromise} + */ + +/** + * Embet another Frame + * @async + * @callback utilsIncludeCallback + * @param {SFrame} elem + * @param {*} args + * @return {includeFrame} + */ + +///////////////////////////////////////////////////////////////////////// +//eventCallbacks +/** + * Called when Page is fully loaded. + * @callback eventOnLoadedCallback + */ + +/** + * Will be called and awaited bevor resolving. + * @async + * @callback eventOnResolveCallback + */ + +/** + * Will be called and awaited bevor closing. + * @async + * @callback eventOnCloseCallback + */ + +/** + * Will be called and awaited bevor rerendering. + * @async + * @callback eventOnBeforRerenderCallback + * @param {...*} args - any given param + */ + +/** + * Will be called and awaited after rerendering. + * @async + * @callback eventOnAfterRerenderCallback + * @param {...*} args - any given param + */ + +/** + * Will be called when included in another Frame and that Frame rerenders. + * @callback eventOnParentRenderCallback + */ + +/** + * Will be called when included in another Frame and that Frame rerenders. + * @callback eventOnGlobalRenderCallback + */ + +/** + * @typedef callUtils + * @type {Object} + * @property {Object} find - find an element in local tree + * @property {utilsResolveCallback} resolve - Return the Data + * @property {utilsCloseCallback} close - Close the Frame + * @property {utilsRenderCallback} render - Rerender the Frame + * @property {utilsCallCallback} call - Use another Frame + * @property {utilsIncludeCallback} include - Include another Frame + * @property {Object} event - local Events + * @property {eventOnLoadedCallback} event.onloaded + * @property {eventOnResolveCallback} event.onresolve + * @property {eventOnCloseCallback} event.close + * @property {eventOnBeforRerenderCallback} event.onBeforRerender + * @property {eventOnAfterRerenderCallback} event.onAfterRerender + * @property {eventOnParentRenderCallback} event.onParentRender + * @property {eventOnGlobalRenderCallback} event.onGlobalRenderRequest + */ + +/** + * This callback will be called, when a frame should be opened. + * @callback callCallback + * @param {Stear} stear + * @param {callUtils} utils - lots of utils for Frame manipulation + * @param {*} args + */ + +/** + * SFrame class + */ export class SFrame{ #preRender; #call; + /** + * + * @param {Object} args + * @param {callCallback} args.call + * @param {boolean} [args.preRender] + */ constructor({ call, preRender = true }){ this.#preRender = preRender; this.#call = call; } - call(stear, args, layer = 1, renderParent = stear.elem){ + call(stear, args, frames, layer = 1, renderParent = stear.elem){ let lastRender; let renderElem; - let event = { onloaded: () => { }, onclose: ()=>{}, onresolve: () => { }, onBeforRerender: () => { }, onAfterRerender: () => { }, onParentRender:()=>{} }; + let event = { onloaded: () => { }, onclose: ()=>{}, onresolve: () => { }, onBeforRerender: () => { }, onAfterRerender: () => { }, onParentRender:()=>{}, onGlobalRenderRequest:()=>true }; let find = {}; let resolved = false; @@ -155,6 +377,14 @@ export class SFrame{ } const ppp = new callPromise(async (res,rej)=>{ + const globalRegister = { + globalRenderRequest: async (...args)=>{ + const arg = await event.onGlobalRenderRequest(...args); + if(arg===false) return; + await options.render(arg); + } + } + frames.push(globalRegister); const options = { find, render: async (...args) => { @@ -169,6 +399,8 @@ export class SFrame{ resolved = true; await event.onresolve(); if (close && lastRender && [...(renderParent.children)].includes(lastRender._)) renderParent.removeChild(lastRender._); + let i = frames.indexOf(globalRegister); + if(i>-1)frames.splice(i,1); res(r); }, call: (elem, args = {}) => { @@ -176,7 +408,7 @@ export class SFrame{ }, close: async () => { await event.onclose(); - if (close && lastRender && [...(renderParent.children)].includes(lastRender._)) renderParent.removeChild(lastRender._); + if (lastRender && [...(renderParent.children)].includes(lastRender._)) renderParent.removeChild(lastRender._); }, include: (frame, args = {}) => { let iFrame = new includeFrame(stear, frame, layer + 1, args); @@ -199,12 +431,19 @@ export class SFrame{ } +/** Create a SWindow, a Fullscreen Frame. */ export class SWindow extends SFrame{ #Frame; - + + /** + * + * @param {Object} args + * @param {callCallback} args.call + * @param {boolean} [args.preRender] + */ constructor({ call, preRender = true, backgroundColor = "transparent"}){ - var Frame = _({ + /*var Frame = _({ style: { top: "0px", left: "0px", @@ -216,7 +455,7 @@ export class SWindow extends SFrame{ //overflow:"scroll" }, find:"main" - }, []); + }, []);*/ super({ call: async(...args) => _({ style: { @@ -233,11 +472,21 @@ export class SWindow extends SFrame{ }, await call(...args)), preRender }); - this.#Frame = Frame; + //this.#Frame = Frame; } } +/** + * @typedef renderNodeSettings + * @type {Object} + * @property {string}[type] + * @property {string}[find] + * @property {Object}[event] + * @property {Object}[attr] + */ + +/** Create a Render node, */ export class class_ { #elem; #childs; @@ -245,6 +494,13 @@ export class class_ { #find; #doBuild; + /** + * Generate a new Stear render Node. + * + * @param {renderNodeSettings} settings + * @param {(LanguagePoolString|string|class_)[]} childs + * @param {boolean} doBuild + */ constructor(settings,childs,doBuild = true){ this.#elem = document.createElement(settings.type ?? "div"); this.#childs = childs; @@ -272,11 +528,17 @@ export class class_ { this.#doBuild = doBuild; } + /** + * @param {(LanguagePoolString|string|class_)[]} childs + */ set childs(childs){ if (!this.#doBuild) return; this.#childs = Array.isArray(childs) ? childs : [childs]; } + /** + * @param {renderNodeSettings} settings + */ set settings(settings){ var keys = Object.keys(settings); for (let i = 0; i < keys.length; i++) { @@ -293,6 +555,11 @@ export class class_ { } } + /** + * Build Stear Structure + * + * @param {*} args + */ async build (args) { if(!this.#doBuild)return; this.#build = []; @@ -313,6 +580,11 @@ export class class_ { } } + /** + * Genereate HTML Structure + * + * @return {HTMLElement} + */ get render (){ if (!this.#doBuild) return this.#elem; this.#elem.innerHTML = ""; @@ -327,10 +599,18 @@ export class class_ { return this.#elem; } + /** + * @return {HTMLElement} + */ get _ (){ return this.#elem; } + /** + * Returns find Object + * + * @return {Object} find + */ get find (){ var out = {}; if (this.#doBuild){ @@ -342,15 +622,32 @@ export class class_ { return out; } } + +/** + * + * @param {renderNodeSettings} [settings] + * @param {(LanguagePoolString|string|class_)[]} [childs] + * @returns + */ export const _ = (settings = {}, childs = []) => new class_(settings, Array.isArray(childs) ? childs : [childs]); export const s = (type,settings,...childs)=>{ + settings = settings ?? {}; settings.type = type; return new class_(settings,childs); } +/** includeFrame */ class includeFrame{ #elem; #call; + /** + * Call another Frame and generate an includeFrame. + * + * @param {Stear} stear + * @param {SFrame} frame + * @param {number} layer + * @param {*} args + */ constructor(stear,frame,layer, args = {}){ this.#elem = new class_({},[],false); this.#call = stear.include(frame, args, this.#elem._, layer); @@ -362,16 +659,28 @@ class includeFrame{ }); } + /** + * @return {callUtils} utils from included Frame + */ get opts(){ return this.#call.opts; } + /** + * Close the included Frame. + */ close(){ if(this.#call){ this.#call.opts.close(); } } + /** + * Trigger onParentRender event + * + * @param {*} settings + * @returns + */ render(settings={}){ this.#elem.settings = settings; this.#call.opts.event.onParentRender();