"use strict"; import {Utils} from "../Utils/Utils.ecma.js"; import {Check} from "../Utils/Check.ecma.js"; import {Attributes} from "./Attributes.ecma.js"; import {LicensesComponent} from "../Components/LicensesComponent.ecma.js"; import {FormsComponent} from "../Components/FormsComponent.ecma.js"; import {BaseComponent} from "../Components/BaseComponent.ecma.js"; /** * @typedef {import("./AnP.ecma.js").AnP} AnP * @typedef {import("../Models/ThreadModel.ecma.js").ThreadModel} ThreadModel */ /** * @callback anp_event_callback * @param {!Event} event * @returns {any|null|void} */ /** * @class * @constructor * @param {!AnP} anp * @returns {void} * @access public */ export const Components = (function(){ /** * @constructs Components * @param {!AnP} anp * @returns {void} * @access private */ const Components = function(anp){ /** @type {Components} */ const self = this; /** @type {boolean} */ let started = false, /** @type {ThreadModel|null} */ thread = null; /** * @returns {void} * @access private */ const constructor = () => { [ ["licenses", LicensesComponent], ["base", BaseComponent], ["forms", FormsComponent] ].forEach(([name, Class]) => { if(Class){ self[name + "_component"] = new Class(anp); Check.is_function(self[name + "_component"].build) && (self[name] = self[name + "_component"].build); }; }); }; /** * @param {!ThreadModel} thread * @returns {void} * @access private */ const analyzer = thread => { if(anp.item_self == document) return; anp.item_self.querySelectorAll(".image[data-status=unloaded]").forEach(image => { image.setAttribute("data-status", "loading"); image.querySelector("img").setAttribute("src", Utils.variables_decode(image.getAttribute("data-sources"))[0]); }); }; /** * @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; thread = anp.threads.add(analyzer, { bucle : true, timer : 100 }); Utils.execute_items([ "licenses", "base", "forms" ], (key, next) => { self[key + "_component"].start(ok => { next(); }); }, () => { end(true); }); return true; }; /** * @param {!(Array.)} childs * @returns {Array.|Array.|null>, Array.>|null>>} * @access private */ const set_childs = childs => Check.is_string(childs[0]) ? [childs] : childs; /** * @param {...Array.|Array.|null>, Array.>|null} items * @returns {string} * @access public */ this.set = (...items) => items.reduce((html, [tag, attributes, childs]) => { const subitem = ( self[tag] && (!attributes || !attributes.built) ? self[tag](...Utils.get_array(attributes)) : `<` + tag + anp.attributes.create(attributes, null, "built") + `>` + ( Check.is_array(childs) && childs.length ? self.set(...set_childs(childs)) : Check.is_null_or_undefined(childs) ? "" : "" + childs) + ``); return html + (Check.is_array(subitem) ? self.set(...[subitem]) : subitem); }, ``); /** * @param {!(string|HTMLElement)} item * @param {...Array.|Array.|null>, Array.>|null>} items * @returns {string} * @access public */ this.set_to = (item, ...items) => { anp.preload(item, (item, asynchronous, ok) => { ok && items.forEach(([tag, attributes, childs]) => { if(self[tag] && (!attributes || !attributes.built)){ /** @type {string|Array.|HTMLElement|NodeList} */ const subitem = self[tag](...Utils.get_array(attributes)); if(Check.is_string(subitem)) item.innerHTML += subitem; else if(Check.is_array(subitem)) self.set_to(item, subitem); else if(Check.is_html_items(subitem)) subitem.forEach(subnode => item.appendChild(subnode)); else if(Check.is_html_item(subitem)) item.appendChild(subitem); }else{ /** @type {HTMLElement} */ const subitem = item.appendChild(document.createElement(tag)); anp.attributes.set(subitem, attributes, null, ["built"]); Check.is_array(childs) && childs.length && self.set_to(subitem, ...set_childs(childs)); }; }); }); }; /** * @param {!(Object.|Array.)} inputs * @returns {Array.} * @access public */ this.image = inputs => { /** @type {Object.} */ const attributes = Utils.get_dictionary(Check.is_array_string(inputs) ? {sources : inputs} : inputs), /** @type {Array.} */ source_keys = ["images", "sources", "image", "source", "src"], /** @type {Array.} */ images = Utils.get_strings(Utils.get_value(source_keys, attributes)); Attributes.remove(attributes, source_keys.concat([ "class", "classes", "status", "data_status", "data_i", "data_sources" ])); return ["span", { ...attributes, class : Attributes.join_classes("image", Utils.get_value(["class", "classes"], attributes)), data_status : "unloaded", data_sources : images, data_i : 0 }, [ ["img", { // on_load_execute : item => { // item.setAttribute("src", images[0]); // }, onload : (item, event) => { item.parentNode.setAttribute("data-status", "loaded"); item.parentNode.querySelector("span").style.backgroundImage = "url('" + item.src + "')"; }, onerror : (item, event) => { /** @type {Array.} */ const images = Utils.variables_decode(item.parentNode.getAttribute("data-sources")), /** @type {number} */ i = Number(item.parentNode.getAttribute("data-i")) + 1; if(i < images.length){ item.parentNode.setAttribute("data-i", i); item.setAttribute("src", images[i]); }else item.parentNode.setAttribute("data-status", "error"); }, ...(attributes.title ? {alt : attributes.title} : {}) }], ["span"] ]]; }; /** * @param {!string} name * @param {!string} [tag = "span"] * @param {?(Object.|Array.)} [attributes = null] * @returns {Array.} * @access public */ this.icon = (name, tag = "span", attributes = null) => { /** @type {Array.|string|null} */ const childs = Utils.get_value(["content", "child", "childs"], attributes, null); Attributes.remove(attributes = Utils.get_dictionary(attributes), [ ["content", "child", "childs"] ]); attributes.data_icon = name; return [tag, attributes, childs]; }; /** * @param {?string} base * @param {?(Object.|Array.)} attributes * @returns {Array.} * @access private */ const process_title = (base, attributes) => [ anp.i18n.get([base].concat(Utils.get_strings(Utils.get_value([ "title", "text", "texts", "default_text", "default_texts" ], attributes, []))), attributes), ( !Check.is_null_or_undefined(Utils.get_dictionary(attributes).title) || Utils.get_value(["with_title", "has_title"], attributes, false) ) ]; /** * @param {!string} name * @param {!string} [tag = "span"] * @param {?(Object.|Array.)} [attributes = null] * @returns {Array.} * @access public */ this.i18n = (name, tag = "span", attributes = null) => { /** @type {[string, boolean]} */ const [text, has_title] = process_title(name, attributes); Attributes.remove(attributes = Utils.get_dictionary(attributes), [ "text", "texts", "default_text", "default_texts", "with_title", "has_title" ]); attributes.data_i18n = name; has_title && (attributes.title = text); return [tag, attributes, text]; }; /** * @param {!string} name * @param {?(anp_event_callback|Object.|Array.)} [attributes = null] * @returns {Array.} */ this.button = (name, attributes = null) => { /** @type {[string, boolean]} */ const [text, has_title] = process_title(name, {with_title : true, ...( Check.is_function(attributes) ? attributes = {onclick : attributes} : attributes)}), /** @type {Array.|string>} */ childs = [ self.icon(Utils.get_value(["icon", "data_icon"], attributes, name)), self.i18n(name) ], /** @type {Array.|string|null} */ content = Utils.get_value(["child", "childs", "content"], attributes, null); content && childs.push(content); Attributes.remove(attributes = Utils.get_dictionary(attributes), [ "text", "texts", "default_text", "default_texts", "with_title", "has_title", "icon", "data_icon", "child", "childs", "content" ]); attributes.built = true; attributes.type || (attributes.type = "button"); if(has_title){ attributes.title = text; attributes.data_i18n = name; attributes.data_i18n_without = true; }; return ["button", { ...attributes, }, childs]; }; /** * @param {!Array.|string>} items * @param {?(Object.|Array.)} [attributes = null] * @param {!string} [tag = "div"] * @returns {Array.} * @access public */ this.group = (items, attributes = null, tag = "div") => { /** @type {string} */ const classes = Attributes.join_classes("group", Utils.get_value(["class", "classes"], attributes)); Attributes.remove(attributes = Utils.get_dictionary(attributes), [ "class", "classes" ]); attributes.class = classes; return [tag, attributes, items]; }; /** * @param {!Array.|string>} buttons * @param {?(Object.|Array.)} [attributes = null] * @param {!string} [tag = "div"] * @returns {Array.} * @access public */ this.buttons = (buttons, attributes = null, tag = "div") => self.group(buttons, Utils.get_dictionary([attributes, { class : Attributes.join_classes("buttons", Utils.get_value(["class", "classes"], attributes)) }]), tag); /** * @param {?(Object.)} [attributes = null] * @param {?(Object.)} [own_attributes = null] * @returns {Array.} * @access public */ this.input = (attributes = null, own_attributes = null) => ["input", { ...Utils.get_dictionary(attributes), ...Utils.get_dictionary(own_attributes), built : true }]; /** * @param {?(Object.)} [attributes = null] * @returns {Array.} * @access public * @returns */ this.number = (attributes = null) => { /** @type {string} */ const classes = Attributes.join_classes("input-field input-number", Utils.get_value(["class", "classes"], attributes)); Attributes.remove(attributes = Utils.get_dictionary(attributes), ["class", "classes"]); return ["span", {class : classes}, [ ["input", { ...attributes, type : "number" }] ]]; }; constructor(); }; return Components; })();