/** * This file is part of the jps-like-websites lib * URL: https://git.labos.goip.de/chris/jpc-like-websites * @copyright by its creator Christian Martin */ /** * @todo Potentially class implementation could be removed entirely. * Since it (at the time being) is only working as a singleton anyway. * Further maybe rename to 'AppBuilder' instead of 'PageBuilder', * page might later become part of a navigation setup. * * * The class provides overreaching options for building the website. * @extends ScriptAndStyleContext */ class PageBuilder extends ScriptAndStyleContext { /** * @type {Array} */ #autoRegisteredComponents; /** * @type {Array} */ #registeredComponents; /** * @type {boolean} */ #showFrameworkConsole; /** * @type {Array} */ _extensions; /** * @type {Map} */ _groups; constructor() { super(); this.#showFrameworkConsole = false; this.#autoRegisteredComponents = []; this.#registeredComponents = []; this._extensions = []; this._groups = new Map(); } /** * * @param {*|Array<*>} groups * @param {Component} component */ subscribeComponentToGroup(groups, component) { if (groups instanceof Array && !(groups instanceof String)) { for (let i = 0; i < groups.length; i++) { this.subscribeComponentToGroup(groups[i], component); } } else { if (!this._groups.has(groups)) { this._groups.set(groups, []); } this._groups.get(groups).push(component); } } autoRegisterComponent() { let compName = 'comp-el-' + this.#autoRegisteredComponents.length; this.#autoRegisteredComponents.push(compName); return compName; } registerComponent(compName) { this.#registeredComponents.push(compName); return compName; } /** * Inserts the given element according to the extStore into the page/document. * The refElement is a reference element for the case * that extStore._position defines "before" or "segment_begin", * which will then look for the refElement as the corresponding insert reference. * * @param {HTMLElement|Component} element * @param {ExtStorage} extStore * @param {HTMLElement|Component} refElement */ addElementToPage(element, extStore = ExtStoreType.CENTRALIZED_DOC_HEAD) { let { insertCallEl, relativePositioning } = {}; relativePositioning = extStore.getRelativePositioning(); insertCallEl = extStore.getRefElement(element); insertCallEl.insertAdjacentElement( relativePositioning, element ); } /** * Determines that the jpc-like-websites libs shouldn't be part of the resulting page. * Therefore the generate() methods will package/generate finalized js, css and html elements * into the final html page in the end. * Especially tricky are reusable elements and functions that use such. * * @todo This method/feature will have to have a logic implemented for state altering components * that then can be "packaged" into a single page. * @todo This method/feature will work only, if an automatic reuse logic for elements/components is implemented within the jpc lib. * @ATTENTION DO NOT USE */ enableFrameworkConsole() { this.#showFrameworkConsole = true; return this; } /** * Little helper function. * If a single page application is in development. * This method sets an autoreload interval for the page. * Default is 20 (sec). * @param {number} relaunchSeconds timeinterval for page to reload (changes) */ inDev(relaunchSeconds = 20) { let head = document.querySelector("head"); let meta = document.createElement("meta"); meta.setAttribute("http-equiv", "refresh"); meta.setAttribute("content", `${relaunchSeconds}`); let devScript = document.createElement('script'); devScript.setAttribute("data-label", "devScript"); devScript.innerText = ` let ts = new Date(); console.log("Page is in Dev-Mode (through 'inDev()' call of PageBuilder."); console.log("Refreshed at: ", ts.getHours()+':'+ts.getMinutes()+':'+ts.getSeconds(), "Intervall ${relaunchSeconds}s"); `; head.appendChild(devScript); head.insertAdjacentElement("beforeend", meta); } /** * * @param {CompelExtension} extension */ addExtension(extension) { if (extension instanceof CompelExtension) { this._extensions.push(extension); extension.install(); } } setPageTitle(title) { this._apptitle = title; } generate() { super.generate(); let docBody = document.querySelector('body'); if (this._apptitle) { document.querySelector("title") .innerText = this._apptitle; } if (this.#showFrameworkConsole) { let pageContextControlPanel = frameworkControlPanel(this._extensions); pageContextControlPanel = pageContextControlPanel.generate(); docBody.insertAdjacentElement( "afterbegin", pageContextControlPanel.html ); } } compelgroups = this._groups; } } const CommonCompelGroups = Object.freeze({ AUTO_REGISTRATED: "auto_registrated", REUSABLE_COMPEL: "reusable", HIGHER_COMPEL: "higher_compel", OVERFLOWING: "overflowing", HIDDEN_ON_START: "hidden_on_start", IS_CONTEXT_MENU: "is_contextmenu", HAS_CONTEXT_MENU: "has_contextmenu", DRAGGABLE: "draggable", HAS_DRAG_EVENT: "has_drag", DROP_TARGET: "droptarget", }); const Page = new PageBuilder();