471 lines
14 KiB
JavaScript
471 lines
14 KiB
JavaScript
"use strict";
|
|
|
|
import {Check} from "./Checks.ecma.js";
|
|
import {RE} from "./Patterns.ecma.js";
|
|
|
|
/**
|
|
* @class Common
|
|
* @constructor
|
|
* @returns {void}
|
|
* @access private
|
|
* @static
|
|
*/
|
|
export const Common = (function(){
|
|
|
|
/**
|
|
* @callback execute_callback
|
|
* @param {...(any|null)} parameters
|
|
* @returns {any|null}
|
|
*/
|
|
|
|
/**
|
|
* @callback simple_callback
|
|
* @returns {void}
|
|
*/
|
|
|
|
/**
|
|
* @callback each_item_callback
|
|
* @param {?any} item
|
|
* @param {!simple_callback} next
|
|
* @return {void}
|
|
*/
|
|
|
|
/**
|
|
* @callback preload_callback
|
|
* @param {?HTMLElement} item
|
|
* @param {!boolean} asynchronous
|
|
* @param {!boolean} ok
|
|
* @return {void}
|
|
*/
|
|
|
|
/**
|
|
* @constructs Common
|
|
* @returns {void}
|
|
* @access private
|
|
* @static
|
|
*/
|
|
const Common = function(){};
|
|
|
|
/** @type {Object.<string, Object.<string, string>>} */
|
|
Common.REGULAR_EXPRESSION = {
|
|
TO : {
|
|
"\n" : "n",
|
|
"\r" : "r",
|
|
"\t" : "t"
|
|
},
|
|
FROM : {
|
|
n : "\n",
|
|
r : "\r",
|
|
t : "\t"
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @param {...(any|null)} items
|
|
* @returns {Array.<string>}
|
|
* @access public
|
|
* @static
|
|
*/
|
|
Common.get_keys = (...items) => items.reduce((keys, item) => {
|
|
|
|
if(Check.is_key(item))
|
|
keys.includes(item) || keys.push(item);
|
|
else if(Check.is_array(item))
|
|
keys.push(...Common.get_keys(...item).filter(key => !keys.includes(key)));
|
|
|
|
return keys;
|
|
}, []);
|
|
|
|
/**
|
|
* @param {...(any|null)} items
|
|
* @returns {Array.<string>}
|
|
* @access public
|
|
* @static
|
|
*/
|
|
Common.get_texts = (...items) => items.reduce((texts, item) => {
|
|
|
|
if(Check.is_string(item))
|
|
texts.includes(item) || texts.push(item);
|
|
else if(Check.is_array(item))
|
|
texts.push(...Common.get_texts(...item));
|
|
|
|
return texts;
|
|
}, []);
|
|
|
|
/**
|
|
* @param {...(any|null)} items
|
|
* @returns {Array.<Object.<string, any|null>>}
|
|
* @access public
|
|
* @static
|
|
*/
|
|
Common.get_dictionaries = (...items) => items.reduce((dictionaries, item) => {
|
|
|
|
if(Check.is_dictionary(item))
|
|
dictionaries.push(item);
|
|
else if(Check.is_array(item))
|
|
dictionaries.push(...Common.get_dictionaries(...item));
|
|
|
|
return dictionaries;
|
|
}, []);
|
|
|
|
/**
|
|
* @param {any|null} items
|
|
* @param {!boolean} [overwrite = false]
|
|
* @param {!Array.<string>} [except = []]
|
|
* @returns {Object.<string, any|null>}
|
|
* @access public
|
|
* @static
|
|
*/
|
|
Common.get_dictionary = (items, overwrite = false, except = []) => {
|
|
if(Check.is_dictionary(items))
|
|
return Object.entries(items).filter(([key, _]) => !except.includes(key)).reduce((dictionary, [key, value]) => {
|
|
dictionary[key] = value;
|
|
return dictionary;
|
|
}, {});
|
|
if(Check.is_array(items))
|
|
return items.reduce((dictionary, item) => {
|
|
|
|
if(Check.is_dictionary(item))
|
|
Object.keys(item).filter(key => (
|
|
overwrite || dictionary[key] === undefined
|
|
) && !except.includes(key)).forEach(key => {
|
|
dictionary[key] = item[key];
|
|
});
|
|
else if(Check.is_array(item))
|
|
Object.entries(Common.get_dictionary(item, overwrite, except)).filter(([key, _]) => (
|
|
overwrite || dictionary[key] === undefined
|
|
) && !except.includes(key)).forEach(([key, value]) => {
|
|
dictionary[key] = value;
|
|
});
|
|
|
|
return dictionary;
|
|
}, {});
|
|
return {};
|
|
};
|
|
|
|
/**
|
|
* @param {?any} items
|
|
* @returns {Array.<any|null>}
|
|
* @access public
|
|
* @static
|
|
*/
|
|
Common.get_array = items => Check.is_array(items) ? items : [items];
|
|
|
|
/**
|
|
* @param {!(string|Array.<string>)} keys
|
|
* @param {!(Object.<string, any|null>|Array<any|null>)} inputs
|
|
* @param {?any} [_default = null]
|
|
* @returns {any|null}
|
|
* @access public
|
|
* @static
|
|
*/
|
|
Common.get_value = (keys, inputs, _default = null) => {
|
|
if((keys = Common.get_keys(keys)).length)
|
|
for(let subinputs of Common.get_dictionaries(inputs))
|
|
for(let key of keys)
|
|
if(subinputs[key] !== undefined)
|
|
return subinputs[key];
|
|
return _default;
|
|
};
|
|
|
|
/**
|
|
* @param {!string} string
|
|
* @param {!(Object.<string, any|null>|Array<any|null>)} inputs
|
|
* @param {?any} [_default = null]
|
|
* @returns {string}
|
|
* @access public
|
|
* @static
|
|
*/
|
|
Common.string_variables = (string, inputs, _default = null) => {
|
|
|
|
inputs = Common.get_dictionary(inputs);
|
|
|
|
return ("" + string).replace(RE.STRING_VARIABLES, (all, key) => (
|
|
inputs[key] !== undefined ? inputs[key] :
|
|
_default !== null ? _default :
|
|
all));
|
|
};
|
|
|
|
/**
|
|
* @param {!execute_callback} callback
|
|
* @param {...(any|null)} parameters
|
|
* @returns {any|null}
|
|
* @access public
|
|
* @static
|
|
*/
|
|
Common.execute = (callback, ...parameters) => Check.is_function(callback) ? callback(...parameters) : null;
|
|
|
|
/**
|
|
* @param {!Array.<any|null>} array
|
|
* @param {!each_item_callback} each_callback
|
|
* @param {?simple_callback} end_callback
|
|
* @param {!number} [i = null]
|
|
* @returns {void}
|
|
* @access private
|
|
* @static
|
|
*/
|
|
const execute_array_ordered = (array, each_callback, end_callback, i = 0) => {
|
|
if(i == array.length)
|
|
Common.execute(end_callback);
|
|
else
|
|
Common.execute(each_callback, array[i], () => {
|
|
execute_array_ordered(array, each_callback, end_callback, i + 1);
|
|
});
|
|
};
|
|
|
|
/**
|
|
* @param {!Array.<any|null>} array
|
|
* @param {!each_item_callback} each_callback
|
|
* @param {?simple_callback} end_callback
|
|
* @returns {void}
|
|
* @access private
|
|
* @static
|
|
*/
|
|
const execute_array_unordered = (array, each_callback, end_callback) => {
|
|
|
|
/** @type {number} */
|
|
const l = array.length;
|
|
/** @type {number} */
|
|
let i = 0;
|
|
|
|
if(array.length){
|
|
for(let item of array)
|
|
Common.execute(each_callback, item, () => {
|
|
++ i == l && Common.execute(end_callback);
|
|
});
|
|
}else
|
|
Common.execute(end_callback);
|
|
|
|
};
|
|
|
|
/**
|
|
* @param {!Array.<any|null>} array
|
|
* @param {!each_item_callback} each_callback
|
|
* @param {?simple_callback} end_callback
|
|
* @param {!boolean} [ordered = false]
|
|
* @returns {void}
|
|
* @access public
|
|
* @static
|
|
*/
|
|
Common.execute_array = (array, each_callback, end_callback = null, ordered = false) => {
|
|
if(ordered)
|
|
execute_array_ordered(array, each_callback, end_callback);
|
|
else
|
|
execute_array_unordered(array, each_callback, end_callback);
|
|
};
|
|
|
|
/**
|
|
* @param {!Object.<string, any|null>} dictionary
|
|
* @returns {void}
|
|
* @access public
|
|
* @static
|
|
*/
|
|
Common.clear_dictionary = dictionary => {
|
|
[...Object.keys(dictionary)].forEach(key => {
|
|
delete dictionary[key];
|
|
});
|
|
};
|
|
|
|
/**
|
|
* @param {!string} string
|
|
* @returns {string}
|
|
* @access public
|
|
* @static
|
|
*/
|
|
Common.to_kebab = string => string.replace(RE.TO_KEBAB, (_, capital, rest, special) => (
|
|
capital ? "-" + (capital + rest).toLowerCase() :
|
|
special ? "-" :
|
|
"")).toLowerCase();
|
|
|
|
/**
|
|
* @param {!(string|HTMLElement)} selector
|
|
* @param {!preload_callback} callback
|
|
* @param {!number} [timeout = 2000]
|
|
* @param {!number} [fps = 10]
|
|
* @returns {void}
|
|
* @access public
|
|
* @static
|
|
*/
|
|
Common.preload = (selector, callback, timeout = 2000, fps = 10) => {
|
|
if(!Check.is_function(callback))
|
|
return;
|
|
if(Check.is_html_item(selector))
|
|
return callback(selector, false, true);
|
|
if(!Check.is_string(selector))
|
|
return callback(null, false, false);
|
|
|
|
/** @type {HTMLElement|null} */
|
|
let item;
|
|
|
|
try{
|
|
if(item = document.querySelector(selector))
|
|
try{
|
|
return callback(item, false, true);
|
|
}catch(exception){
|
|
console.error(exception);
|
|
};
|
|
}catch(exception){
|
|
return callback(null, false, false);
|
|
};
|
|
|
|
/** @type {number} */
|
|
const date = Date.now(),
|
|
/** @type {number} */
|
|
interval = setInterval(() => {
|
|
if(item = document.querySelector(selector)){
|
|
clearInterval(interval);
|
|
return callback(item, true, true);
|
|
};
|
|
if(Date.now() - date > timeout){
|
|
clearInterval(interval);
|
|
return callback(null, true, false);
|
|
};
|
|
}, 1000 / fps);
|
|
|
|
};
|
|
|
|
/**
|
|
* @param {...(HTMLElement|string|Array.<any|null>)} inputs
|
|
* @returns {Array.<HTMLElement>}
|
|
* @access public
|
|
* @static
|
|
*/
|
|
Common.HTML = (...inputs) => {
|
|
|
|
/** @type {DocumentFragment} */
|
|
const fragment = new DocumentFragment(),
|
|
/** @type {HTMLElement|null} */
|
|
master = (
|
|
Check.is_html_item(inputs[0]) ? inputs[0] :
|
|
Check.is_string(inputs[0]) ? document.querySelector(inputs[0]) :
|
|
null);
|
|
|
|
(master ? inputs.slice(1) : inputs).forEach(subinputs => {
|
|
if(Check.is_html_item(subinputs))
|
|
fragment.appendChild(subinputs);
|
|
else if(Check.is_string(subinputs))
|
|
fragment.appendChild(document.createTextNode(subinputs));
|
|
else if(Check.is_array(subinputs)){
|
|
|
|
/** @type {[string, Object.<string, any|null>|null, any|null]} */
|
|
const [tag, attributes, children] = subinputs.concat([null, null]).slice(0, 3),
|
|
/** @type {HTMLElement} */
|
|
item = document.createElement(tag);
|
|
|
|
Check.is_dictionary(attributes) && Object.entries(attributes).forEach(([key, value]) => {
|
|
if(RE.ON_ATTRIBUTE.test(key) && Check.is_function(value))
|
|
item.addEventListener(key.replace(RE.ON_ATTRIBUTE, "").replace(RE.SPECIAL_HTML_EVENT_CHARACTERS, "").toLowerCase(), event => {
|
|
value(item, event);
|
|
});
|
|
else if(value !== null)
|
|
item.setAttribute(Common.to_kebab(key), value);
|
|
});
|
|
|
|
if(Check.is_array(children))
|
|
Common.HTML(...children).forEach(child => item.appendChild(child));
|
|
else if(Check.is_string(children))
|
|
item.innerHTML += children;
|
|
|
|
fragment.appendChild(item);
|
|
|
|
};
|
|
});
|
|
|
|
master && master.appendChild(fragment);
|
|
|
|
return [...fragment.childNodes];
|
|
};
|
|
|
|
/**
|
|
* @param {?any} value
|
|
* @returns {any|null}
|
|
* @access public
|
|
* @static
|
|
*/
|
|
Common.unique = value => (
|
|
Check.is_string(value) ? value.split("").filter((char, i, array) => array.indexOf(char) == i).join("") :
|
|
Check.is_array(value) ? value.filter((item, i, array) => array.indexOf(item) == i) :
|
|
value);
|
|
|
|
/**
|
|
* @param {?any} value
|
|
* @return {string|null}
|
|
* @access public
|
|
* @static
|
|
*/
|
|
Common.json_encode = value => {
|
|
try{
|
|
return JSON.stringify(value);
|
|
}catch(exception){};
|
|
return null;
|
|
};
|
|
|
|
/**
|
|
* @param {?any} value
|
|
* @returns {Object.<string, any|null>|Array.<any|null>|null}
|
|
* @access public
|
|
* @static
|
|
*/
|
|
Common.json_decode = value => {
|
|
try{
|
|
return JSON.parse(value);
|
|
}catch(exception){};
|
|
return null;
|
|
};
|
|
|
|
/**
|
|
* @param {?any} value
|
|
* @returns {string|null}
|
|
* @access public
|
|
* @static
|
|
*/
|
|
Common.base64_encode = value => {
|
|
if(Check.is_json_item(value))
|
|
return btoa(JSON.stringify(value));
|
|
try{
|
|
return btoa(value);
|
|
}catch(exception){};
|
|
return null;
|
|
};
|
|
|
|
/**
|
|
* @param {?any} value
|
|
* @returns {string|null}
|
|
* @access public
|
|
* @static
|
|
*/
|
|
Common.base64_decode = value => {
|
|
try{
|
|
return atob(value);
|
|
}catch(exception){};
|
|
return null;
|
|
};
|
|
|
|
/**
|
|
* @param {!(Object.<string, any|null>|Array.<any|null>)} data
|
|
* @returns {string}
|
|
* @access public
|
|
* @static
|
|
*/
|
|
Common.data_encode = data => Common.base64_encode(Common.json_encode(data));
|
|
|
|
/**
|
|
* @param {!string} data
|
|
* @returns {(Object.<string, any|null>|Array.<any|null>)}
|
|
* @access public
|
|
* @static
|
|
*/
|
|
Common.data_decode = data => Common.json_decode(Common.base64_decode(data));
|
|
|
|
/**
|
|
* @param {!string} string
|
|
* @returns {string}
|
|
* @access public
|
|
* @static
|
|
*/
|
|
Common.to_regular_expression = string => string.replace(RE.TO_REGULAR_EXPRESSION, character => (
|
|
"\\" + (Common.REGULAR_EXPRESSION.FROM[character] || character)
|
|
));
|
|
|
|
return Common;
|
|
})(); |