AnP/Public/ecma/AnPLoader.ecma.js

323 lines
10 KiB
JavaScript

"use strict";
/**
* @callback anp_loader_default_callback
* @returns {void}
*/
/**
* @callback anp_loader_execute_callback
* @param {...(any|null)} [parameters]
* @returns {any|null}
*/
/**
* @class
* @constructor
* @param {!(Object.<string, any|null>|Array.<any|null>)} inputs
* @returns {void}
* @access public
*/
export const AnPLoader = (function(){
/**
* @constructs AnPLoader
* @param {!(Object.<string, any|null>|Array.<any|null>)} inputs
* @param {!anp_loader_default_callback} callback
* @returns {void}
* @access private
*/
const AnPLoader = function(inputs, callback){
/** @type {AnPLoader} */
const self = this;
/** @type {string} */
this.domain = /^[^\:]+\:\/{2}[^\/]+\.([lg]ocal|anprm(\.[lg]ocal)?)\/?/i.test(window.location.href) ? "local" : "k3y.pw";
/**
* @returns {void}
* @access private
*/
const constructor = () => {
/** @type {number} */
let i = 0;
/** @type {anp_loader_default_callback} */
const end = () => {
++ i == 2 && AnPLoader.execute(callback, self);
},
/** @type {Object.<string, any|null>} */
options = {
domain : self.domain = AnPLoader.get_value("domain", inputs, self.domain),
name : AnPLoader.get_value("name", inputs, "AnP")
};
AnPLoader.styles_loader(AnPLoader.get_list_strings(AnPLoader.get_value(["style", "styles"], inputs)), end, options);
AnPLoader.scripts_loader(AnPLoader.get_list_strings(AnPLoader.get_value(["script", "scripts"], inputs)), end, options);
};
constructor();
};
/**
* @param {?any} item
* @returns {boolean}
* @access public
* @static
*/
AnPLoader.is_string = item => typeof item == "string";
/**
* @param {?any} item
* @returns {boolean}
* @access public
* @static
*/
AnPLoader.is_key = item => item && AnPLoader.is_string(item) && /^[a-z0-9_]+$/i.test(item);
/**
* @param {?any} item
* @returns {boolean}
* @access public
* @static
*/
AnPLoader.is_array = item => item instanceof Array;
/**
* @param {?any} item
* @returns {boolean}
* @access public
* @static
*/
AnPLoader.is_dictionary = item => item && item.constructor == Object;
/**
* @param {?any} item
* @returns {boolean}
* @access public
* @static
*/
AnPLoader.is_function = item => typeof item == "function";
/**
* @param {?any} item
* @returns {Array.<any|null>}
* @access public
* @static
*/
AnPLoader.get_array = item => AnPLoader.is_array(item) ? item : [item];
/**
* @param {?any} item
* @param {!boolean} [overwrite = false]
* @returns {Object.<string, any|null>}
* @access public
* @static
*/
AnPLoader.get_dictionary = (item, overwrite = false) => AnPLoader.get_array(item).reduce((dictionary, subitem) => {
AnPLoader.is_array(subitem) && (subitem = AnPLoader.get_dictionary(subitem, overwrite));
return AnPLoader.is_dictionary(subitem) ? overwrite ? {...dictionary, ...subitem} : {...subitem, ...dictionary} : dictionary;
}, {});
/**
* @param {!(string|Array.<string>)} keys
* @returns {Array.<string>}
* @access public
* @static
*/
AnPLoader.get_keys = keys => AnPLoader.get_array(keys).filter((key, i, array) => AnPLoader.is_key(key) && array.indexOf(key) == i);
/**
* @param {!(string|Array.<string>)} keys
* @param {!(Object.<string, any|null>|Array.<any|null>)} inputs
* @param {?any} [_default = null]
* @returns {any|null|undefined}
* @access public
* @static
*/
AnPLoader.get_value = (keys, inputs, _default = null) => {
if(AnPLoader.is_array(inputs)){
for(let i = 0, l = inputs.length; i < l; i ++){
/** @type {any|null|undefined} */
const value = AnPLoader.get_value(keys, inputs[i], undefined)
if(value !== undefined)
return value;
};
}else if(AnPLoader.is_dictionary(inputs)){
for(let i = 0, l = (keys = AnPLoader.get_keys(keys)).length; i < l; i ++)
if(inputs[keys[i]] !== undefined)
return inputs[keys[i]];
};
return _default;
};
/**
* @param {!(string|Array.<any|null>)} items
* @returns {Array.<any>}
* @access public
* @static
*/
AnPLoader.get_list_strings = items => {
if(items){
if(AnPLoader.is_string(items))
return [items];
if(AnPLoader.is_array(items))
return items.filter(item => AnPLoader.is_string(item) || AnPLoader.is_array(item)).map(item => AnPLoader.is_array(item) ? AnPLoader.get_list_strings(item) : item);
};
return [];
};
/**
* @param {!anp_loader_execute_callback} callback
* @param {...(any|null)} parameters
* @returns {any|null}
* @access public
* @static
*/
AnPLoader.execute = (callback, ...parameters) => {
return AnPLoader.is_function(callback) ? callback(...parameters) : null;
};
/**
* @param {!Array.<Array.<string>>} scripts
* @param {?anp_loader_default_callback} [callback = null]
* @param {?(Object.<string, any|null>|Array.<any|null>)} [options = null]
* @param {!number} [i = 0]
* @returns {void}
* @access public
* @static
*/
AnPLoader.scripts_loader = (scripts, callback = null, options = null, i = 0) => {
if(i == scripts.length){
AnPLoader.execute(callback);
return;
};
/** @type {number} */
let loaded = 0;
/** @type {number} */
const l = scripts[i].length,
/** @type {anp_loader_default_callback} */
end = () => {
++ loaded == l && AnPLoader.scripts_loader(scripts, callback, options, i + 1);
},
/** @type {HTMLHeadElement} */
head = document.querySelector("head");
AnPLoader.get_array(scripts[i]).forEach(script => {
if(AnPLoader.is_string(script)){
/** @type {HTMLScriptElement} */
const item = head.appendChild(document.createElement("script"));
options && (script = AnPLoader.string_variables(script, options));
["load", "error"].forEach(key => {
item.addEventListener(key, event => {
end();
});
});
item.setAttribute("data-type", "text/javascript;charset=utf-8");
item.setAttribute("data-language", script.slice(-8).toLowerCase() == ".ecma.js" ? "ECMAScript 2015" : "JavaScript 1.8.5");
item.setAttribute("src", script);
item.setAttribute("data-crossorigin", "anonymous");
item.setAttribute("charset", "utf-8");
}else
end();
});
};
/**
* @param {!Array.<Array.<string>>} styles
* @param {?anp_loader_default_callback} [callback = null]
* @param {?(Object.<string, any|null>|Array.<any|null>)} [options = null]
* @param {!number} [i = 0]
* @returns {void}
* @access public
* @static
*/
AnPLoader.styles_loader = (styles, callback = null, options = null, i = 0) => {
if(i == styles.length){
AnPLoader.execute(callback);
return;
};
/** @type {number} */
let loaded = 0;
/** @type {number} */
const l = styles[i].length,
/** @type {anp_loader_default_callback} */
end = () => {
++ loaded == l && AnPLoader.styles_loader(styles, callback, options, i + 1);
},
/** @type {HTMLHeadElement} */
head = document.querySelector("head");
AnPLoader.get_array(styles[i]).forEach(style => {
if(AnPLoader.is_string(style)){
/** @type {HTMLScriptElement} */
const item = head.appendChild(document.createElement("link")),
/** @type {boolean} */
is_sass = style.slice(-5).toLowerCase() == ".scss";
options && (style = AnPLoader.string_variables(style, options));
["load", "error"].forEach(key => {
item.addEventListener(key, event => {
end();
});
});
item.setAttribute("type", "text/css;charset=utf-8");
item.setAttribute("data-language", (is_sass ? "SASS/" : "") + "CSS3");
item.setAttribute("rel", "stylesheet");
if(is_sass){
/** @type {string} */
const css_file = style.substring(0, style.length - 5) + ".css";
item.setAttribute("href", css_file);
item.setAttribute("data-scss", style);
item.setAttribute("data-css-map", css_file + ".map");
}else
item.setAttribute("href", style);
item.setAttribute("data-crossorigin", "anonymous");
item.setAttribute("charset", "utf-8");
}else
end();
});
};
/**
* @param {!string} string
* @param {!(Object.<string, any|null>|Array.<any|null>)} variables
* @param {?any} [_default = null]
* @returns {string}
* @access public
* @static
*/
AnPLoader.string_variables = (string, variables, _default = null) => {
variables = AnPLoader.get_dictionary(variables);
return ("" + string).replace(/\{([a-z0-9_]+)\}/ig, (all, key) => (
variables[key] !== undefined ? variables[key] :
_default !== null && _default !== undefined ? _default :
all));
};
return AnPLoader;
})();