"use strict"; import {RE} from "../Utils/Patterns.ecma.js"; import {Common} from "../Utils/Common.ecma.js"; import {Check} from "../Utils/Checks.ecma.js"; import { Div, Span, A, Img, Header, Footer, Main, H1, Nav, UL, LI } from "../Utils/HTMLDSL.ecma.js"; /** * @typedef {import("../Application/AnP.ecma.js").AnP} AnP */ /** * @class BaseComponent * @constructor * @param {!AnP} anp * @return {void} * @access public * @static */ export const BaseComponent = (function(){ /** * @constructs BaseComponent * @param {!AnP} anp * @return {void} * @access private * @static */ const BaseComponent = function(anp){ /** @type {BaseComponent} */ const self = this, /** @type {Object.>} */ caches = {}; /** @type {integer|null} */ let thread = null, /** @type {Array.} */ zooms = [.25, .5, .75, 1.0, 1.5, 2.0]; /** * @returns {void} * @access private */ const constructor = () => { thread = anp.threads.add(thread_method, { autostart : true, bucle : true }); }; /** * @returns {void} * @access private */ const thread_method = () => { Object.entries(caches).forEach(([i, cache]) => { /** @type {HTMLDivElement} */ const base = document.querySelector(".anp[data-i='" + i + "']"), date = Date.now(); if(!base){ delete caches[i]; return; }; /** @type {number} */ const cells = Number(base.getAttribute("data-cells")), /** @type {number} */ zoom = Number(base.getAttribute("data-zoom")); if( cache.x != base.offsetWidth || cache.y != base.offsetHeight || cache.cells != cells || cache.zoom != zoom || false){ cache.x = base.offsetWidth; cache.y = base.offsetHeight; cache.cells = cells; cache.zoom = zoom; base.style.fontSize = ((cache.x < cache.y ? cache.x : cache.y) / (cells / zoom)) + "px"; }; if(date - cache.last_time > 2000){ /** @type {string} */ const gui_mode = Check.is_dark_mode() ? "dark" : "light", /** @type {boolean} */ is_mobile = Check.is_mobile(); cache.last_time = date; if(cache.gui_mode != gui_mode || cache.mobile != is_mobile){ cache.gui_mode = gui_mode; cache.mobile = is_mobile; base.setAttribute("data-gui-mode", gui_mode); base.setAttribute("data-is-mobile", is_mobile); }; }; }); }; /** * @param {?(Object.|Array.)} [inputs = null] * @return {Array.} * @access public */ this.build = (inputs = null) => { /** @type {string} */ const name = anp.settings.get(["application_name", "name"], inputs, "AnP"), /** @type {string} */ link = anp.settings.get(["application_link", "link"], inputs, "https://anp.k3y.pw/"), /** @type {string} */ git = anp.settings.get(["application_git", "git"], inputs, "https://git.k3y.pw/KyMAN/AnP/"), /** @type {string} */ logo = anp.settings.get(["application_logo", "logo"], inputs, "images/logo.webp"), /** @type {string} */ id = anp.unique_keys.create(), /** @type {string} */ gui_mode = Check.is_dark_mode() ? "dark" : "light", /** @type {boolean} */ is_mobile = Check.is_mobile(); /** @type {number} */ let i; while(caches[i = Math.random() * (1 << 28) | 0]); caches[i] = { x : 0, y : 0, cells : anp.settings.get(["application_cells", "cells"], inputs, 40), zoom : anp.settings.get(["application_zoom", "zoom"], inputs, 1.0), gui_mode : gui_mode, mobile : is_mobile, last_time : Date.now() }; return Div({ id : id, class : Common.unique(["anp", id].concat(anp.settings.get([ "application_class", "class" ], inputs, "").split(RE.WHITE_SPACES))).join(" ").trim(), data_hash : id, data_i : i, data_cells : caches[i].cells, data_zoom : caches[i].zoom, data_forced_gui_mode : anp.settings.get(["application_gui_mode", "gui_mode"], inputs, "default"), // default, light, dark data_gui_mode : gui_mode, // default, light, dark data_is_mobile : is_mobile, data_name : name, data_link : link, data_git : git, data_logo : logo }, [ Header(null, [ H1({title : name}, [ A({href : link, target : "_blank"}, [ anp.components.image({sources : [logo], alt : name}), Span({class : "text"}, name) ]) ]), Nav({class : "top-menu"}, [ UL(null, anp.settings.get("main_menu", inputs, [ ["home", "#"], ["git", git, "_blank"] ]).map(([name, link, target]) => LI({ data_i18n : name, data_i18n_without : true, title : anp.i18n.get(name, inputs) }, [ A({ href : link, target : target || "_self" }, [ anp.components.icon(name), anp.components.i18n(name) ]) ]))) ]), anp.components.session_mini.build() ]), Main(null, [ anp.components.aichat.build(inputs) ]), Footer(null, [ anp.components.buttons([ ["zoom", change_zoom], ["reset_zoom", reset_zoom], ["gui_mode", change_gui_mode] ], {class : "gui-controls"}), anp.components.licenses.build(anp.settings.get(["application_licenses", "licenses"], inputs, { copyright : [[2019, 2027], "KyMAN"], cc_by_nc_sa_4 : [] })), anp.components.i18n_selector.build() ]), Div({class : "preloader"}) ]); }; /** * @param {!HTMLElement} item * @returns {HTMLDivElement|null} * @access public */ this.get_from = item => { if(item) while( !item.classList.contains("anp") && (item = item.parentElement) ); return item; }; /** * @param {!HTMLElement} item * @param {!Event} event * @return {void} * @access private */ const change_zoom = (item, event) => { /** @type {HTMLDivElement} */ const base = self.get_from(item), /** @type {number} */ i = zooms.indexOf(Number(base.getAttribute("data-zoom"))); if(isNaN(i)) base.setAttribute("data-zoom", 1.0); else base.setAttribute("data-zoom", zooms[(i + 1) % zooms.length]); }; /** * @param {!HTMLElement} item * @param {!Event} event * @return {void} * @access private */ const reset_zoom = (item, event) => { self.get_from(item).setAttribute("data-zoom", 1.0); }; /** * @param {!HTMLElement} item * @param {!Event} event * @return {void} * @access private */ const change_gui_mode = (item, event) => { /** @type {HTMLDivElement} */ const base = self.get_from(item); base.setAttribute("data-forced-gui-mode", { default : "light", light : "dark", dark : "default" }[base.getAttribute("data-forced-gui-mode")]); }; constructor(); }; return BaseComponent; })();