452 lines
15 KiB
JavaScript
452 lines
15 KiB
JavaScript
"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.<Array.<Object.<string, any|null>>>} */
|
|
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.<number>} */
|
|
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.<string, any|null>|Array.<any|null>)} [inputs = null]
|
|
* @returns {Object.<string, any|null>}
|
|
* @access private
|
|
*/
|
|
const get_attributes = (inputs = null) => {
|
|
|
|
/** @type {string} */
|
|
const id = anp.random_chain(),
|
|
/** @type {Object.<string, any|null>} */
|
|
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.<string, any|null>} */
|
|
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.<string, any|null>|Array.<any|null>)} inputs
|
|
* @returns {string}
|
|
* @access public
|
|
*/
|
|
this.build = inputs => {
|
|
|
|
/** @type {Array.<any|null>} */
|
|
const licenses = anp.settings.get(["application_licenses", "application_license", "licenses", "license"], inputs, []),
|
|
/** @type {Object.<string, any|null>} */
|
|
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.<any|null>}
|
|
* @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.<number>} */
|
|
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;
|
|
})(); |