221 lines
5.8 KiB
JavaScript
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;
|
|
})(); |