AnP/Public/ecma/Managers/UniqueKeysManager.ecma.js

221 lines
5.8 KiB
JavaScript

"use strict";
import {Common} from "../Utils/Common.ecma.js";
import {Check} from "../Utils/Checks.ecma.js";
import {RE} from "../Utils/Patterns.ecma.js";
import {UniqueKeyModel} from "../Models/UniqueKeyModel.ecma.js";
/**
* @typedef {import("../Application/AnP.ecma.js").AnP} AnP
*/
/**
* @class UniqueKeysManager
* @constructor
* @param {!AnP} anp
* @return {void}
* @access public
* @static
*/
export const UniqueKeysManager = (function(){
/**
* @callback simple_callback
* @returns {void}
*/
/**
* @callback continue_callback
* @param {!boolean} ok
* @return {boolean}
*/
/**
* @constructs UniqueKeysManager
* @param {!AnP} anp
* @return {void}
* @access private
* @static
*/
const UniqueKeysManager = function(anp){
/** @type {UniqueKeysManager} */
const self = this,
/** @type {Object.<number, UniqueKeyModel>} */
keys = {},
/** @type {Array.<string>} */
alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz".split("");
/** @type {boolean} */
let started = false,
/** @type {number} */
length = 13,
/** @type {number} */
keys_i = 0,
/** @type {number|null} */
thread = null;
/**
* @returns {void}
* @access private
*/
const constructor = () => {};
/**
* @param {?continue_callback} callback
* @returns {boolean}
* @access public
*/
this.update = (callback = null) => {
/** @type {string|Array.<string>} */
const new_alphabet = anp.settings.get("unique_keys_alphabet", null, alphabet);
alphabet.splice(0, keys.length, ...Common.unique(
Check.is_string(new_alphabet) ? new_alphabet.split("") :
Check.is_array(new_alphabet) ? new_alphabet :
alphabet));
length = anp.settings.get("unique_keys_length", null, length);
Common.execute(callback);
};
/**
* @param {?continue_callback} callback
* @returns {boolean}
* @access public
*/
this.reset = (callback = null) => {
keys.splice(0, keys.length);
alphabet.splice(0, keys.length, ..."123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz".split(""));
length = 13;
self.update(callback);
};
/**
* @param {?continue_callback} callback
* @returns {boolean}
* @access public
*/
this.start = (callback = null) => {
/** @type {continue_callback} */
const end = ok => Common.execute(callback, ok);
if(started){
end(false);
return false;
};
started = true;
self.update(() => {
thread = anp.threads.add(thread_method);
end(true);
});
return true;
};
/**
* @param {?continue_callback} callback
* @returns {boolean}
* @access public
*/
this.close = (callback = null) => {
/** @type {continue_callback} */
const end = ok => Common.execute(callback, ok);
if(!started){
end(false);
return false;
};
started = false;
end(true);
return true;
};
/**
* @returns {void}
* @access private
*/
const thread_method = () => {
[...Object.entries(keys)].forEach(([i, model]) => {
if(model.is_html_item){
if(model.loaded){
if(!document.querySelector("#" + model.key + ",." + model.key + ",[name=" + model.key + "]"))
delete keys[i];
}else if(document.querySelector("#" + model.key + ",." + model.key + ",[name=" + model.key + "]"))
model.loaded = true;
};
});
};
/**
* @param {!string} key
* @returns {boolean}
* @access public
*/
this.exists = key => Object.values(keys).some(k => k.key === key);
/**
* @param {!boolean} [is_html_item = false]
* @return {string}
* @access public
*/
this.create = (is_html_item = false) => {
/** @type {string} */
let key;
/** @type {number} */
const l = alphabet.length,
/** @type {number} */
shift = Math.ceil(Math.log2(alphabet.length));
do{
key = "";
do{
/** @type {number} */
let random = (Math.random() * (1 << 28)) | 0;
while(random && (key += alphabet[random % l]).length < length)
random >>= shift;
}while(key.length < length);
}while(
!RE.KEY.test(key) ||
document.querySelector("#" + key + ",." + key + ",[name=" + key + "]") ||
self.exists(key)
);
keys[++ keys_i] = new UniqueKeyModel(key, is_html_item, keys_i);
return key;
};
/**
* @param {!string} key
* @returns {boolean}
* @access public
*/
this.remove = key => {
return [...Object.entries(keys)].some(([i, model]) => {
if(model.key == key){
delete keys[i];
return true;
};
return false;
});
};
constructor();
};
return UniqueKeysManager;
})();