OpoTests/Public/ecma/Utils/Utils.ecma.js

329 lines
9.5 KiB
JavaScript

"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<string>}
* @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.<Object.<string, any|null>>}
* @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.<string, any|null>}
* @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.<string>)} keys
* @param {!(Object.<string, any|null>|Array.<any|null>)} 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.<string, any|null>|Array.<any|null>)} 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.<string, any|null>} 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.<string, any|null>|null, string|Array.<string>|null]|null)} structure
* @returns {Array.<HTMLElement>}
* @access public
* @static
*/
Utils.html = (item, ...structure) => {
/** @type {Array.<HTMLElement>} */
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.<string, any|null>|null, Array.<any|null>|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.<any|null>|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.<any|null>} 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.<any|null>}
* @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;
})();