"use strict"; import {Check} from "./Check.ecma.js"; /** * @class Utils * @constructor * @returns {void} * @access public * @static */ export const Utils = (function(){ /** * @callback utils_execute_callback * @param {...(any|null)} inputs * @returns {any|null} */ /** * @callback utils_default_callback * @returns {void} */ /** * @callback utils_execute_array_each_callback * @param {?any} item * @param {!utils_default_callback} callback * @returns {void} */ /** * @constructs Utils * @returns {void} * @access private * @static */ const Utils = function(){}; /** @type {string} */ Utils.BASE64_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; /** @type {string} */ Utils.RANDOM_ALPHABET = "bHMnuamw/RUBk+xNvCXghsPdlSFG12rLoT0O3VZ=5QeWyI8pADqjcEfJ9Kt64i7Yz"; /** * @param {...(any|null)} items * @returns {Array} * @access public * @static */ Utils.get_keys = (...items) => items.reduce((keys, item) => { if(Check.is_key(item)) keys.push(item); else if(Check.is_array(item)) keys.push(...Utils.get_keys(...item)); return keys; }, []); /** * @param {...(any|null)} items * @returns {Array.>} * @access public * @static */ Utils.get_dictionaries = (...items) => items.reduce((dictionaries, item) => { if(Check.is_dictionary(item)) dictionaries.push(item); else if(Check.is_array(item)) dictionaries.push(...Utils.get_dictionaries(...item)); return dictionaries; }, []); /** * @param {?any} items * @param {!boolean} [overwrite = false] * @returns {Object.} * @access public * @static */ Utils.get_dictionary = (items, overwrite = false) => ( Check.is_dictionary ? items : Check.is_array(items) ? items.reduce((dictionary, item) => { if(Check.is_dictionary(item)) dictionary = overwrite ? {...dictionary, ...item} : {...item, ...dictionary}; else if(Check.is_array(item)) dictionary = {...dictionary, ...Utils.get_dictionary(item, overwrite)}; return dictionary; }) : {}); /** * @param {!(string|Array.)} keys * @param {!(Object.|Array.)} inputs * @param {?any} [_default = null] * @returns {any|null} * @access public * @static */ Utils.get_value = (keys, inputs, _default = null) => { /** @type {number} */ const l = (keys = Utils.get_keys(keys)).length; if(l){ /** @type {number} */ const m = (inputs = Utils.get_dictionaries(inputs)).length; for(let i = 0; i < l; i++) for(let j = 0; j < m; j++) if(keys[i] in inputs[j]) return inputs[j][keys[i]]; }; return _default; }; /** * @param {!string} string * @param {!(Object.|Array.)} variables * @param {?any} _default * @returns {string} * @access public * @static */ Utils.string_variables = (string, variables, _default = null) => { variables = Utils.get_dictionary(variables); return ("" + string).replace(/\{([a-z_][a-z0-9_]*)\}/gi, (all, key) => ( key in variables ? variables[key] : _default === null ? all : _default)); }; /** * @param {!string} string * @returns {string} * @access public * @static */ Utils.to_kebab_case = string => ("" + string).replace(/([A-Z]+)|[^a-z0-9]+/g, (_, upper) => ( upper ? "-" + upper.toLowerCase() : "-")); /** * @param {!HTMLElement} item * @param {...Object.} attributes * @returns {void} * @access public * @static */ Utils.attributes = (item, attributes) => { for(const [key, value] of Object.entries(attributes)){ if(/^on[_\-]?/i.test(key) && Check.is_function(value)) item.addEventListener(key.toLowerCase().replace(/^on[_\-]?/, ""), event => { Utils.execute(value, item, event); }); else item.setAttribute(Utils.to_kebab_case(key), value); }; }; /** * @param {!HTMLElement} item * @param {...(string|HTMLElement|[string, Object.|null, string|Array.|null]|null)} structure * @returns {Array.} * @access public * @static */ Utils.html = (item, ...structure) => { /** @type {Array.} */ const items = []; item || (item = document.createDocumentFragment()); for(const node of structure) if(Check.is_string(node)) item.innerHTML += node; else if(Check.is_html_item(node)) items.push(item.appendChild(node)); else if(Check.is_array(node)){ /** @type {[string, Object.|null, Array.|null]} */ const [tag, attributes, children] = node.concat(null, null).slice(0, 3), /** @type {HTMLElement} */ element = document.createElement(tag); attributes && Utils.attributes(element, attributes); if(children && children.length){ if(Check.is_string(children)) element.innerHTML += children; else Utils.html(element, ...children); }; items.push(item.appendChild(element)); }; return items; }; /** * @param {?any} item * @returns {any|null} * @access public * @static */ Utils.unique = item => ( Check.is_array(item) ? item.filter((item, i, array) => array.indexOf(item) == i) : Check.is_string(item) ? item.split("").filter((char, i, array) => array.indexOf(char) == i).join("") : item); /** * @param {?(number|Array.|string)} [from = null] * @param {?number} [to = null] * @returns {any|null} * @access public * @static */ Utils.get_random = (from = null, to = null) => ( Check.is_array(from) || Check.is_string(from) ? from.length ? from[Math.random() * from.length >> 0] : null : Check.is_integer(from) ? ( to === null ? Math.random() * from >> 0 : Check.is_integer(to) ? from + (Math.random() * (to - from + 1) >> 0) : Check.is_number(to) ? from + Math.random() * (to - from) : null) : Check.is_number(from) ? ( to === null ? Math.random() * from : Check.is_number(to) ? from + Math.random() * (to - from) : null) : from === null ? Math.random() : null); /** * @param {?any} data * @returns {string} * @access public * @static */ Utils.encode_data = data => btoa(encodeURIComponent(JSON.stringify(data)).replace(/%([0-9A-F]{2})/g, (_, p1) => String.fromCharCode("0x" + p1))); /** * @param {!string} code * @returns {any|null} * @access public * @static */ Utils.decode_data = code => { /** @type {string} */ const data = decodeURIComponent(atob(code).split("").map(c => "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2)).join("")); try{ return JSON.parse(data) || data; }catch(exception){}; return data; }; /** * @param {!utils_execute_callback} callback * @param {...(any|null)} inputs * @returns {any|null} * @access public * @static */ Utils.execute = (callback, ...inputs) => ( Check.is_function(callback) ? callback(...inputs) : null); /** * @param {!Array.} array * @param {!utils_execute_array_each_callback} each_callback * @param {?utils_default_callback} [end_callback = null] * @param {!number} [i = 0] * @returns {void} * @access public * @static */ Utils.execute_array = (array, each_callback, end_callback = null, i = 0) => { if(i < array.length) Utils.execute(each_callback, array[i], () => { Utils.execute_array(array, each_callback, end_callback, i + 1); }); else Utils.execute(end_callback); }; /** * @param {?any} item * @returns {Array.} * @access public * @static */ Utils.get_array = item => Check.is_array(item) ? item : [item]; /** * @param {!string} string * @returns {string} * @access public * @static */ Utils.randomize_string = string => string.split("").sort(() => Utils.get_random() - 0.5).join(""); /** * @param {?any} data * @returns {string} * @access public * @static */ Utils.encrypt_data = data => Utils.encode_data(data).split("").map(character => Utils.RANDOM_ALPHABET[Utils.BASE64_ALPHABET.indexOf(character)]).join(""); /** * @param {string} data * @returns {any|null} * @access public * @static */ Utils.decrypt_data = data => Utils.decode_data(data.split("").map(character => Utils.BASE64_ALPHABET[Utils.RANDOM_ALPHABET.indexOf(character)]).join("")); return Utils; })();