"use strict"; import {Check} from "./Check.ecma.js"; /** * @callback utils_preload_callback * @param {?HTMLElement} item * @param {!boolean} asynchronous * @param {!boolean} ok * @returns {void} */ /** * @callback utils_execute_callback * @param {...any} [paramenters] * @returns {any|null} */ /** * @class * @constructor * @returns {void} * @access public * @static */ export const Utils = (function(){ /** * @constructs Utils * @returns {void} * @access private * @static */ const Utils = function(){}; /** * @param {!(string|HTMLElement)} selector * @param {!utils_preload_callback} callback * @param {!(Document|HTMLElement)} [root = document] * @param {!number} [timeout = 2000] * @returns {void} * @access public * @static */ Utils.preload = (selector, callback, root = document, timeout = 2000) => { if(!selector) callback(null, false, false); else if(Check.is_html_object(selector)) callback(selector, false, true); else if(Check.is_string(selector) && (selector = selector.trim())){ /** @type {HTMLElement|null} */ let item = null; try{ if(item = root.querySelector(selector)){ callback(item, false, true); return; }; }catch(exception){ callback(null, false, false); return; }; /** @type {number} */ const date = Date.now(); /** @type {number} */ let interval = setInterval(() => { if(item = root.querySelector(selector)){ clearInterval(interval); callback(item, true, true); }else if(Date.now() - date > timeout){ clearInterval(interval); callback(null, false, true); }; }, 100); }else callback(null, false, false); }; /** * @param {!utils_execute_callback} callback * @param {...any} [parameters] * @returns {any|null} * @access public * @static */ Utils.execute = (callback, ...parameters) => Check.is_function(callback) ? callback(...parameters) : null; /** * @param {!(string|HTMLElement)} selector * @param {!Object.} attributes * @param {!(HTMLElement|Document)} [position = document] * @returns {void} * @access public * @static */ Utils.set_attributes = (selector, attributes, position = document) => { (Check.is_string(selector) ? position.querySelectorAll(selector) : [selector]).forEach(item => { for(const key in attributes){ if(/^on_?/i.test(key)) item.addEventListener( key.substring(2).replace(/[^a-z]+/g, "").toLowerCase(), event => Utils.execute(attributes[key], item, event) ); else item.setAttribute(key.replace(/_|([A-Z])/g, (_, character) => { return character ? "-" + character.toLowerCase() : "-"; }), attributes[key]); }; }); }; /** * @param {!(string|HTMLElement|Document)} selector * @param {!Array.<[string, Object.|null, Array.|null]} items * @param {!(HTMLElement|Document)} [position = document] * @returns {Array.} * @access public * @static */ Utils.set_html = (selector, items, position = document) => { Check.is_string(selector) && (selector = position.querySelector(selector)); return items.map(([tag, attributes, childs]) => { /** @type {HTMLElement} */ const item = selector.appendChild(document.createElement(tag)); attributes && Utils.set_attributes(item, attributes); if(!Check.is_null_or_undefined(childs)){ if(Check.is_string(childs)) item.innerHTML = childs; else if(Check.is_array(childs)) Utils.set_html(item, childs); }; return item; }); }; Utils.get_keys = keys => ( Check.is_array(keys) ? keys.reduce((keys, key) => keys.concat(Utils.get_keys(key)), []) : Check.is_key(keys) ? [keys] : []); Utils.get_dictionary = (dictionaries, overwrite = false) => ( Check.is_array(dictionaries) ? dictionaries.reduce((dictionary, item) => (overwrite ? { ...dictionary, ...Utils.get_dictionary(item) } : { ...Utils.get_dictionary(item), ...dictionary }), {}) : Check.is_dictionary(dictionaries) ? dictionaries : {}); Utils.get_value = (keys, inputs, _default = null) => { const l = (keys = Utils.get_keys(keys)).length; if(l && Object.keys(inputs = Utils.get_dictionary(inputs)).length) for(let i = 0; i < l; i ++) if(inputs[keys[i]] !== undefined) return inputs[keys[i]]; return _default; }; Utils.download = (data, mime = "application/octet-stream", name = null) => { console.log(data); const anchor = document.createElement("a"), date = new Date(); Utils.set_attributes(anchor, { download : name || ("RoutesMaker." + ( ("0000" + date.getFullYear()).slice(-4) + ("00" + (date.getMonth() + 1)).slice(-2) + ("00" + date.getDate()).slice(-2) + ("00" + date.getHours()).slice(-2) + ("00" + date.getMinutes()).slice(-2) + ("00" + date.getSeconds()).slice(-2) ) + ".json"), href : "data:" + mime + ";base64," + btoa(Check.is_string(data) ? data : JSON.stringify(data)), target : "_blank" }); anchor.click(); anchor.remove(); }; Utils.upload = callback => { const input = document.createElement("input"); Utils.set_attributes(input, { type : "file", multiple : false, on_change : (item, event) => { let loaded = 0; const data = [], l = event.target.files.length, end = (i, file, string) => { data[i] = { name : file.name, last_modified_date : file.lastModified, size : file.size, mime : file.type, content : string }; if(++ loaded == l){ input.remove(); Utils.execute(callback, ...data); }; }; [...event.target.files].forEach((file, i) => { const reader = new FileReader(); reader.onload = () => { end(i, file, reader.result); }; reader.readAsText(file); }); } }); input.click(); }; Utils.to_kebab = snake => snake.replace(/_/g, "-"); /** * @param {?string} item * @returns {string|null} * @access public * @static */ Utils.to_key = item => Check.is_string(item) && (item = item.trim()) ? item.replace(/[^a-z0-9]+/ig, "_") : null; return Utils; })();