"use strict"; import {Attributes} from "../Application/Attributes.ecma.js"; import {Utils} from "../Utils/Utils.ecma.js"; import {Check} from "../Utils/Check.ecma.js"; /** * @typedef {import("../Application/AnP.ecma.js").AnP} AnP * @typedef {import("../Models/ThreadModel.ecma.js").ThreadModel} ThreadModel */ /** * @class * @constructor * @param {!AnP} anp * @returns {void} * @access public */ export const BaseComponent = (function(){ /** * @constructs BaseComponent * @param {!AnP} anp * @returns {void} * @access private */ const BaseComponent = function(anp){ /** @type {BaseComponent} */ const self = this, /** @type {Array.>>} */ identifiers = []; /** @type {boolean} */ let started = false, /** @type {ThreadModel|null} */ thread = null; /** * @returns {void} * @access private */ const constructor = () => {}; /** * @param {!ThreadModel} thread * @returns {void} * @access private */ const analyzer = thread => { /** @type {Array.} */ const for_delete = []; identifiers.forEach((cache, i) => { if(!cache.item && !(cache.item = document.querySelector("#" + cache.id))){ for_delete.push(i); return; }; /** @type {number} */ const zoom = Number(cache.item.getAttribute("data-zoom")) / 100; if( cache.x != cache.item.offsetWidth || cache.y != cache.item.offsetHeight || cache.zoom != zoom ){ cache.x = cache.item.offsetWidth; cache.y = cache.item.offsetHeight; cache.zoom = zoom; /** @type {number} */ const cells = Number(cache.item.getAttribute("data-cells")), /** @type {number} */ minimum_size = Number(cache.item.getAttribute("data-minimum-size")), /** @type {number} */ size = zoom * (cache.x < cache.y ? cache.x : cache.y) / cells; cache.item.style.fontSize = (size > minimum_size ? size : minimum_size) + "px"; cache.item.querySelectorAll("[data-maximum-zoom]").forEach(item => { /** @type {number} */ const maximum_zoom = Number(item.getAttribute("data-maximum-zoom")) / 100, /** @type {number} */ maximum_size = maximum_zoom * (cache.x < cache.y ? cache.x : cache.y) / cells; item.style.fontSize = size > maximum_size ? maximum_size + "px" : "inherit"; }); }; }); if(for_delete.length){ for_delete.reverse(); for_delete.forEach(i => { identifiers.splice(i, 1); }); }; }; /** * @param {?(Object.|Array.)} [inputs = null] * @returns {Object.} * @access private */ const get_attributes = (inputs = null) => { /** @type {string} */ const id = anp.random_chain(), /** @type {Object.} */ attributes = Utils.get_dictionary(inputs), /** @type {anp_attributes_load_callback|null} */ on_load_execute = attributes.on_load_execute; Attributes.remove(attributes, [ "class", "classes", "id", "data_hash", "hash", "cells", "minimum_size", "zoom", "data_cells", "data_minimum_size", "data_zoom", "on_load_execute", "data_dark_mode", "data_mobile", "dark_mode", "mobile" ]); return { ...attributes, on_load_execute : item => { identifiers.push({id : id}); Utils.execute(on_load_execute, item); }, class : Attributes.join_classes(Utils.get_value(["class", "classes"], inputs, []), ["anp", id]), id : id, data_hash : id, data_cells : anp.settings.get(["base_cells", "data_cells", "cells"], inputs, 40), data_minimum_size : anp.settings.get(["base_minimum_size", "data_minimum_size", "minimum_size"], inputs, 12), data_zoom : anp.settings.get(["base_zoom", "data_zoom", "zoom"], inputs, 100), data_gui_mode : anp.settings.get(["base_gui_mode", "data_gui_mode", "gui_mode"], inputs, "default"), data_dark_mode : anp.is_dark_mode(), data_mobile : anp.is_mobile() }; }; /** * @param {?anp_start_callback} callback * @returns {boolean} * @access public */ this.start = (callback = null) => { /** @type {!anp_start_callback} */ const end = ok => { Utils.execute(callback, ok); return ok; }; if(started) return end(false); started = true; /** @type {string|HTMLElement|null} */ const position = anp.settings.get("position"); thread = anp.threads.add(analyzer, { timer : 100, bucle : true }); if(position) anp.preload(position, (position, asyncrhonous, ok) => { if(ok){ /** @type {Object.} */ const attributes = { on_load_execute : item => { anp.item_self = item; anp.hash_self = item.getAttribute("id"); end(true); } }; ["name", "git", "link", "since", "version"].forEach(key => { const value = anp.settings.get("application_" + key); Check.is_null_or_undefined(value) || (attributes["data_" + key] = value); }); if(position.classList.contains("anp")){ /** @type {HTMLElement} */ const footer = position.querySelector("footer"), /** @type {HTMLFieldSetElement} */ gui_controls = footer.insertBefore(document.createElement("fieldset"), footer.childNodes[0]); anp.components.set_to(gui_controls, ...self.build_view_menu()); gui_controls.setAttribute("class", "gui-controls"); anp.attributes.set(position, get_attributes(attributes)); }else{ try{ position.innerHTML = self.build(attributes); }catch(exception){ console.error(exception); }; }; }else end(false); }); else end(true); return true; }; /** * @param {!(Object.|Array.)} inputs * @returns {string} * @access public */ this.build = inputs => { /** @type {Array.} */ const licenses = anp.settings.get(["application_licenses", "application_license", "licenses", "license"], inputs, []), /** @type {Object.} */ attributes = get_attributes(inputs); return anp.components.set(["div", attributes, [ ["header", null, [ ["h1", {class : "logo", title : "AnP"}, [ ["a", {href : "https://anp.k3y.pw/", target : "_blank"}, [ ["image", {sources : "/images/AnP.png", title : "AnP"}], ["span", {class : "text"}, "AnP"] ]] ]] ]], ["main"], ["footer", { "data_maximum_zoom" : anp.settings.get(["base_footer_maximum_zoom", "footer_maximum_zoom"], inputs, 100) }, [].concat( [["fieldset", {class : "gui-controls"}, self.build_view_menu()]], (licenses ? [["licenses", licenses]] : []) )] ]]); }; /** * @returns {Array.} * @access public */ this.build_view_menu = (inputs = null) => [ ["legend", {data_i18n : "gui_controls"}, anp.i18n.get("gui_controls")], ["button", ["less_zoom", set_less_zoom]], ["number", { name : "zoom", min : anp.settings.get("zoom_minimum", inputs, 1), max : anp.settings.get("zoom_maximum", inputs, 200), value : anp.settings.get(["default_zoom", "base_zoom", "zoom"], inputs, 100), step : anp.settings.get("zoom_step", inputs, 1), onchange : change_zoom }], ["button", ["reset_zoom", reset_zoom]], ["button", ["zoom_mode", { onclick : change_zoom_mode, data_modes : anp.settings.get("zoom_modes", inputs, [50, 75, 100, 125, 150]) }]], ["button", ["more_zoom", set_more_zoom]], ["button", ["gui_mode", change_gui_mode]], ["button", ["more_options", { onclick : show_more_options, disabled : true }]] ]; /** * @param {!HTMLElement} item * @param {!number} value * @returns {void} * @access public */ this.change_zoom = (item, value) => { /** @type {HTMLInputElement} */ const number_field = (item = BaseComponent.get(item)).querySelector("footer .gui-controls [type=number]"); item.setAttribute("data-zoom", value); Number(number_field.value) != value && (number_field.value = value); }; /** * @param {!HTMLElement} button * @param {!number} value * @returns {void} * @access private */ const set_zoom = (button, value) => { if(Check.is_number(value)){ /** @type {HTMLInputElement} */ const number_field = button.parentNode.querySelector("[type=number]"); if(value){ value += Number(number_field.value) || 0; if(value < 0){ /** @type {number} */ const minimum = Number(number_field.getAttribute("min")); !isNaN(minimum) && minimum > value && (value = minimum); }else{ /** @type {number} */ const maximum = Number(number_field.getAttribute("max")); !isNaN(maximum) && maximum < value && (value = maximum); }; number_field.value = value; }else number_field.value = value = 100; self.change_zoom(button, value); }; }; /** * @param {!HTMLElement} item * @param {?Event} [event = null] * @returns {void} * @access private */ const set_less_zoom = (item, event = null) => { set_zoom(item, -BaseComponent.get_input_gui_step(item)); }; /** * @param {!HTMLElement} item * @param {?Event} [event = null] * @returns {void} * @access private */ const change_zoom_mode = (item, event = null) => { /** @type {number} */ const current_zoom = Number(item.parentNode.querySelector("[type=number]").value), /** @type {Array.} */ modes = Utils.variables_decode(item.getAttribute("data-modes")); modes.some((value, i) => { if(current_zoom < value){ self.change_zoom(item, value); return true; }; }) || self.change_zoom(item, modes[0]); }; /** * @param {!HTMLElement} item * @param {?Event} [event = null] * @returns {void} * @access private */ const reset_zoom = (item, event = null) => { set_zoom(item, 0); }; /** * @param {!HTMLElement} item * @param {?Event} [event = null] * @returns {void} * @access private */ const set_more_zoom = (item, event = null) => { set_zoom(item, BaseComponent.get_input_gui_step(item)); }; /** * @param {!HTMLElement} item * @param {?Event} [event = null] * @returns {void} * @access private */ const change_gui_mode = (item, event = null) => { (item = BaseComponent.get(item)).setAttribute("data-gui-mode", { "default" : "dark", "dark" : "light", "light" : "default" }[item.getAttribute("data-gui-mode")] || "default"); }; /** * @param {!HTMLElement} item * @param {?Event} [event = null] * @returns {void} * @access private */ const show_more_options = (item, event = null) => { console.log("PASA"); }; /** * @param {!HTMLElement} item * @param {?Event} [event = null] * @returns {void} * @access private */ const change_zoom = (item, event = null) => { self.change_zoom(item, Number(item.value)); }; constructor(); }; /** * @param {!HTMLElement} item * @returns {HTMLElement} * @access public * @static */ BaseComponent.get = item => { if(item) while(true){ if(!item.classList) return null; if(item.classList.contains("anp") || !(item = item.parentNode)) break; }; return item || null; }; /** * @param {!HTMLElement} item * @returns {number} * @access public * @static */ BaseComponent.get_input_gui_step = item => Number(item.parentNode.querySelector("[type=number]").getAttribute("step")); return BaseComponent; })();