Refactor secretariat.js to specify data source origin
global.forget() is currently broken in this commit.
This commit is contained in:
parent
9ade82ccbe
commit
50d02b8c06
1 changed files with 379 additions and 378 deletions
|
@ -6,287 +6,313 @@ import logging from "/scripts/logging.js";
|
||||||
import texts from "/scripts/mapping/read.js";
|
import texts from "/scripts/mapping/read.js";
|
||||||
import hash from "/scripts/utils/hash.js";
|
import hash from "/scripts/utils/hash.js";
|
||||||
|
|
||||||
/* Read all stored data in the browser cache.
|
/*
|
||||||
|
Global data storage, which refers to local and synchronized storage
|
||||||
@param {array} DATA_NAME the data name
|
|
||||||
@param {int} CLOUD determine cloud reading, which is otherwise set to automatic (0)
|
|
||||||
@param {string} PARAMETER_CHECK Determine which parameter to check via regular expressions.
|
|
||||||
@return {object} the data
|
|
||||||
*/
|
*/
|
||||||
export async function read(DATA_NAME, CLOUD = 0) {
|
class global {
|
||||||
// Initialize the selected pref data.
|
/* Read all stored data in the browser cache.
|
||||||
let DATA, DATA_RETURNED;
|
|
||||||
|
@param {array} name the data name
|
||||||
/*
|
@param {int} cloud determines cloud reading, which is otherwise set to automatic (0)
|
||||||
Get all storage values.
|
|
||||||
|
|
||||||
@param {number} SOURCE the data source
|
|
||||||
*/
|
|
||||||
async function read_database(SOURCE = -1) {
|
|
||||||
let data, data_returned;
|
|
||||||
|
|
||||||
async function read_database_local() {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
chrome.storage.local.get(null, function (result) {
|
|
||||||
if (chrome.runtime.lastError) {
|
|
||||||
// Something went wrong
|
|
||||||
reject(new Error(chrome.runtime.lastError));
|
|
||||||
} else {
|
|
||||||
// If the key exists, return the value
|
|
||||||
resolve(result);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async function read_database_sync() {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
chrome.storage.sync.get(null, function (result) {
|
|
||||||
if (chrome.runtime.lastError) {
|
|
||||||
// Something went wrong
|
|
||||||
reject(new Error(chrome.runtime.lastError));
|
|
||||||
} else {
|
|
||||||
// If the key exists, return the value
|
|
||||||
resolve(result);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the data.
|
|
||||||
data_returned = (SOURCE > 0) ? read_database_sync() : read_database_local();
|
|
||||||
return data_returned;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Recursively find through each data, returning either that value or null when the object is not found.
|
|
||||||
|
|
||||||
@param {dictionary} DATA_ALL the data
|
|
||||||
@param {object} DATA_PATH the path of the data
|
|
||||||
@return {object} the data
|
@return {object} the data
|
||||||
*/
|
*/
|
||||||
function find_data(DATA_ALL, DATA_PATH) {
|
static async read(name, cloud = 0) {
|
||||||
let DATA = DATA_ALL;
|
/*
|
||||||
|
Get all storage values.
|
||||||
|
|
||||||
// Pull the data out.
|
@param {number} SOURCE the data source
|
||||||
if (DATA_ALL != null && (Array.isArray(DATA_PATH) && DATA_PATH != null) ? DATA_PATH.length > 0 : false) {
|
*/
|
||||||
let DATA_PATH_SELECTED = String(DATA_PATH.shift()).trim();
|
function pull(SOURCE = -1) {
|
||||||
|
return (chrome.storage[(SOURCE > 0) ? `sync` : `local`].get(null));
|
||||||
// Get the selected data.
|
|
||||||
DATA = DATA_ALL[DATA_PATH_SELECTED];
|
|
||||||
|
|
||||||
// must run if there is actually a parameter to test
|
|
||||||
if (DATA_PATH.length > 0) {
|
|
||||||
// Recursively run to make use of the existing data.
|
|
||||||
DATA = find_data(DATA, DATA_PATH);
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now return the data.
|
/*
|
||||||
return DATA;
|
Find a data given its path.
|
||||||
}
|
|
||||||
|
|
||||||
// Convert the entered prefname to an array if it is not one.
|
@param {object} DATA_ALL the data
|
||||||
if (!Array.isArray(DATA_NAME) && DATA_NAME != null) {
|
@param {object} DATA_PATH the path of the data
|
||||||
// Syntax of splitting is by commas.
|
*/
|
||||||
DATA_NAME = String(DATA_NAME).trim().split(",");
|
function find(DATA_ALL, DATA_PATH) {
|
||||||
}
|
let DATA = DATA_ALL;
|
||||||
|
|
||||||
switch (CLOUD) {
|
// Pull the data out.
|
||||||
case 0:
|
if (DATA_ALL != null && (Array.isArray(DATA_PATH) && DATA_PATH != null) ? DATA_PATH.length > 0 : false) {
|
||||||
DATA = {}; DATA_RETURNED = {};
|
let DATA_PATH_SELECTED = String(DATA_PATH.shift()).trim();
|
||||||
|
|
||||||
DATA[`sync`] = await read((DATA_NAME) ? [...DATA_NAME] : null, 1);
|
// Get the selected data.
|
||||||
DATA[`local`] = await read((DATA_NAME) ? [...DATA_NAME] : null, -1);
|
DATA = DATA_ALL[DATA_PATH_SELECTED];
|
||||||
|
|
||||||
// Now return the data.
|
// must run if there is actually a parameter to test
|
||||||
DATA_RETURNED[`source`] = (DATA[`sync`] != null) ? `sync` : `local`;
|
if (DATA_PATH.length > 0) {
|
||||||
DATA_RETURNED[`value`] = DATA[DATA_RETURNED[`source`]];
|
// Recursively run to make use of the existing data.
|
||||||
|
DATA = find(DATA, DATA_PATH);
|
||||||
return DATA_RETURNED[`value`];
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
CLOUD = (CLOUD > 0) ? 1 : -1;
|
|
||||||
DATA = await read_database(CLOUD);
|
|
||||||
DATA_RETURNED = (DATA_NAME) ? find_data(DATA, DATA_NAME) : DATA;
|
|
||||||
|
|
||||||
return(DATA_RETURNED);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* More enhanced searching.
|
|
||||||
|
|
||||||
@param {Array} SOURCE the source of the data
|
|
||||||
@param {string} TERM the term to search
|
|
||||||
@param {Array} ADDITIONAL_PLACES additional places to search
|
|
||||||
@param {object} OPTIONS the options
|
|
||||||
@return {Array} the results
|
|
||||||
*/
|
|
||||||
export async function search(SOURCE, TERM, ADDITIONAL_PLACES, STRICT = 0, OPTIONS = {}) {
|
|
||||||
let DATA = await read(SOURCE, (OPTIONS[`cloud`] != null) ? OPTIONS[`cloud`] : 0);
|
|
||||||
let RESULTS;
|
|
||||||
|
|
||||||
if (DATA) {
|
|
||||||
RESULTS = {};
|
|
||||||
|
|
||||||
if (TERM && (!(typeof ADDITIONAL_PLACES).includes(`str`) || !ADDITIONAL_PLACES)) {
|
|
||||||
// Sequentially search through the data, first by key.
|
|
||||||
(Object.keys(DATA)).forEach((DATA_NAME) => {
|
|
||||||
if (STRICT ? DATA_NAME == TERM : (DATA_NAME.includes(TERM) || TERM.includes(DATA_NAME))) {
|
|
||||||
RESULTS[DATA_NAME] = DATA[DATA_NAME];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Then, get the additional places.
|
|
||||||
if ((ADDITIONAL_PLACES != null ? Array.isArray(ADDITIONAL_PLACES) : false) ? ADDITIONAL_PLACES.length > 0 : false) {
|
|
||||||
for (let PARAMETER_PRIORITY_NUMBER = 0; PARAMETER_PRIORITY_NUMBER < ADDITIONAL_PLACES.length; PARAMETER_PRIORITY_NUMBER++) {
|
|
||||||
// Recursively search
|
|
||||||
RESULTS = Object.assign({}, RESULTS, search(SOURCE, TERM, ADDITIONAL_PLACES[PARAMETER_PRIORITY_NUMBER], STRICT));
|
|
||||||
};
|
|
||||||
}
|
|
||||||
} else if (((typeof ADDITIONAL_PLACES).includes(`str`) && (ADDITIONAL_PLACES)) ? ADDITIONAL_PLACES.trim() : false) {
|
|
||||||
// Perform a sequential search on the data.
|
|
||||||
if ((typeof DATA).includes(`obj`) && !Array.isArray(DATA) && SOURCE != null) {
|
|
||||||
let VALUE = {};
|
|
||||||
|
|
||||||
for (let DICTIONARY_INDEX = 0; DICTIONARY_INDEX < (Object.keys(DATA)).length; DICTIONARY_INDEX++) {
|
|
||||||
VALUE[`parent`] = DATA[(Object.keys(DATA))[DICTIONARY_INDEX]];
|
|
||||||
|
|
||||||
/* Test for a valid RegEx.
|
|
||||||
|
|
||||||
@param {string} item the item to test
|
|
||||||
*/
|
|
||||||
function isRegEx(item) {
|
|
||||||
let RESULT = {};
|
|
||||||
RESULT[`state`] = false;
|
|
||||||
try {
|
|
||||||
RESULT[`expression`] = new RegExp(item);
|
|
||||||
RESULT[`state`] = true;
|
|
||||||
} catch(err) {};
|
|
||||||
|
|
||||||
return (RESULT[`state`]);
|
|
||||||
};
|
|
||||||
|
|
||||||
if (((typeof VALUE[`parent`]).includes(`obj`) && !Array.isArray(VALUE[`parent`]) && VALUE[`parent`] != null) ? (Object.keys(VALUE[`parent`])).length > 0 : false) {
|
|
||||||
VALUE[`current`] = VALUE[`parent`][ADDITIONAL_PLACES];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (VALUE[`current`] ? ((STRICT >= 1) ? VALUE[`current`] == TERM : (((STRICT < 0.5) ? (VALUE[`current`].includes(TERM)) : false) || TERM.includes(VALUE[`current`]) || (isRegEx(VALUE[`current`]) ? (new RegExp(VALUE[`current`])).test(TERM) : false))) : false) {
|
|
||||||
// Add the data.
|
|
||||||
RESULTS[(Object.keys(DATA))[DICTIONARY_INDEX]] = (Object.entries(DATA))[DICTIONARY_INDEX][1];
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
for (let ELEMENT_INDEX = 0; ELEMENT_INDEX < DATA.length; ELEMENT_INDEX++) {
|
return null;
|
||||||
if (
|
}
|
||||||
((STRICT || (typeof DATA[ELEMENT_INDEX]).includes(`num`)) && DATA[ELEMENT_INDEX] == TERM) ||
|
|
||||||
((!STRICT && !((typeof DATA[ELEMENT_INDEX]).includes(`num`)))
|
// Now return the data.
|
||||||
? (TERM.includes(DATA[ELEMENT_INDEX]) || DATA[ELEMENT_INDEX].includes(TERM) ||
|
return DATA;
|
||||||
(typeof(DATA[ELEMENT_INDEX])).includes(`str`)
|
};
|
||||||
? new RegExp(DATA[ELEMENT_INDEX]).test(TERM)
|
|
||||||
: false
|
// Initialize the selected pref data.
|
||||||
) : false
|
let DATA, DATA_RETURNED;
|
||||||
)
|
|
||||||
) {
|
// Convert the entered prefname to an array if it is not one.
|
||||||
RESULTS[SOURCE] = DATA;
|
let NAME = (!Array.isArray(name) && name != null)
|
||||||
break;
|
? String(name).trim().split(`,`)
|
||||||
|
: name;
|
||||||
|
|
||||||
|
|
||||||
|
switch (cloud) {
|
||||||
|
case 0:
|
||||||
|
DATA = {}; DATA_RETURNED = {};
|
||||||
|
|
||||||
|
DATA[`sync`] = await global.read((NAME) ? [...NAME] : null, 1);
|
||||||
|
DATA[`local`] = await global.read((NAME) ? [...NAME] : null, -1);
|
||||||
|
|
||||||
|
// Now return the data.
|
||||||
|
DATA_RETURNED[`source`] = (DATA[`sync`] != null) ? `sync` : `local`;
|
||||||
|
DATA_RETURNED[`value`] = DATA[DATA_RETURNED[`source`]];
|
||||||
|
|
||||||
|
// Override the data with managed data if available.
|
||||||
|
if ((NAME != null) ? NAME.length : false) {
|
||||||
|
DATA[`managed`] = await managed.read((NAME) ? [...NAME] : null);
|
||||||
|
DATA_RETURNED[`value`] = (DATA[`managed`] != null) ? DATA[`managed`] : DATA_RETURNED[`value`];
|
||||||
|
};
|
||||||
|
|
||||||
|
return DATA_RETURNED[`value`];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
cloud = (cloud > 0) ? 1 : -1;
|
||||||
|
DATA = await pull(cloud);
|
||||||
|
DATA_RETURNED = (NAME) ? find(DATA, NAME) : DATA;
|
||||||
|
|
||||||
|
return(DATA_RETURNED);
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/* More enhanced searching.
|
||||||
|
|
||||||
|
@param {Array} SOURCE the source of the data
|
||||||
|
@param {string} TERM the term to search
|
||||||
|
@param {Array} ADDITIONAL_PLACES additional places to search
|
||||||
|
@param {object} OPTIONS the options
|
||||||
|
@return {Array} the results
|
||||||
|
*/
|
||||||
|
static async search(SOURCE, TERM, ADDITIONAL_PLACES, STRICT = 0, OPTIONS = {}) {
|
||||||
|
let DATA = await global.read(SOURCE, (OPTIONS[`cloud`] != null) ? OPTIONS[`cloud`] : 0);
|
||||||
|
let RESULTS;
|
||||||
|
|
||||||
|
if (DATA) {
|
||||||
|
RESULTS = {};
|
||||||
|
|
||||||
|
if (TERM && (!(typeof ADDITIONAL_PLACES).includes(`str`) || !ADDITIONAL_PLACES)) {
|
||||||
|
// Sequentially search through the data, first by key.
|
||||||
|
(Object.keys(DATA)).forEach((DATA_NAME) => {
|
||||||
|
if (STRICT ? DATA_NAME == TERM : (DATA_NAME.includes(TERM) || TERM.includes(DATA_NAME))) {
|
||||||
|
RESULTS[DATA_NAME] = DATA[DATA_NAME];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Then, get the additional places.
|
||||||
|
if ((ADDITIONAL_PLACES != null ? Array.isArray(ADDITIONAL_PLACES) : false) ? ADDITIONAL_PLACES.length > 0 : false) {
|
||||||
|
ADDITIONAL_PLACES.forEach((ADDITIONAL_PLACE) => {
|
||||||
|
// Recursively search
|
||||||
|
RESULTS = Object.assign({}, RESULTS, global.search(SOURCE, TERM, ADDITIONAL_PLACE, STRICT));
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else if (((typeof ADDITIONAL_PLACES).includes(`str`) && (ADDITIONAL_PLACES)) ? ADDITIONAL_PLACES.trim() : false) {
|
||||||
|
// Perform a sequential search on the data.
|
||||||
|
if ((typeof DATA).includes(`obj`) && !Array.isArray(DATA) && SOURCE != null) {
|
||||||
|
let VALUE = {};
|
||||||
|
|
||||||
|
for (let DICTIONARY_INDEX = 0; DICTIONARY_INDEX < (Object.keys(DATA)).length; DICTIONARY_INDEX++) {
|
||||||
|
VALUE[`parent`] = DATA[(Object.keys(DATA))[DICTIONARY_INDEX]];
|
||||||
|
|
||||||
|
/* Test for a valid RegEx.
|
||||||
|
|
||||||
|
@param {string} item the item to test
|
||||||
|
*/
|
||||||
|
function isRegEx(item) {
|
||||||
|
let RESULT = {};
|
||||||
|
RESULT[`state`] = false;
|
||||||
|
try {
|
||||||
|
RESULT[`expression`] = new RegExp(item);
|
||||||
|
RESULT[`state`] = true;
|
||||||
|
} catch(err) {};
|
||||||
|
|
||||||
|
return (RESULT[`state`]);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (((typeof VALUE[`parent`]).includes(`obj`) && !Array.isArray(VALUE[`parent`]) && VALUE[`parent`] != null) ? (Object.keys(VALUE[`parent`])).length > 0 : false) {
|
||||||
|
VALUE[`current`] = VALUE[`parent`][ADDITIONAL_PLACES];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (VALUE[`current`] ? ((STRICT >= 1) ? VALUE[`current`] == TERM : (((STRICT < 0.5) ? (VALUE[`current`].includes(TERM)) : false) || TERM.includes(VALUE[`current`]) || (isRegEx(VALUE[`current`]) ? (new RegExp(VALUE[`current`])).test(TERM) : false))) : false) {
|
||||||
|
// Add the data.
|
||||||
|
RESULTS[(Object.keys(DATA))[DICTIONARY_INDEX]] = (Object.entries(DATA))[DICTIONARY_INDEX][1];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
for (let ELEMENT_INDEX = 0; ELEMENT_INDEX < DATA.length; ELEMENT_INDEX++) {
|
||||||
|
if (
|
||||||
|
((STRICT || (typeof DATA[ELEMENT_INDEX]).includes(`num`)) && DATA[ELEMENT_INDEX] == TERM) ||
|
||||||
|
((!STRICT && !((typeof DATA[ELEMENT_INDEX]).includes(`num`)))
|
||||||
|
? (TERM.includes(DATA[ELEMENT_INDEX]) || DATA[ELEMENT_INDEX].includes(TERM) ||
|
||||||
|
(typeof(DATA[ELEMENT_INDEX])).includes(`str`)
|
||||||
|
? new RegExp(DATA[ELEMENT_INDEX]).test(TERM)
|
||||||
|
: false
|
||||||
|
) : false
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
RESULTS[SOURCE] = DATA;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return RESULTS;
|
return RESULTS;
|
||||||
}
|
|
||||||
|
|
||||||
/* Write the data on the selected prefname.
|
|
||||||
|
|
||||||
@param {string} PATH the preference name
|
|
||||||
@param {object} DATA the new data to be written
|
|
||||||
@param {int} CLOUD store in the cloud; otherwise set to automatic
|
|
||||||
@param {object} OPTIONS the options
|
|
||||||
*/
|
|
||||||
export async function write(PATH, DATA, CLOUD = -1, OPTIONS = {}) {
|
|
||||||
let DATA_INJECTED = {};
|
|
||||||
|
|
||||||
// Inform the user that saving is in progress.
|
|
||||||
if (((typeof OPTIONS).includes(`obj`) && OPTIONS != null) ? (!(!!OPTIONS[`silent`])) : true) {
|
|
||||||
new logging ((new texts(`saving_current`)).localized, (new texts(`saving_current_message`)).localized, false)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Forcibly write the data to chrome database
|
/* Write the data on the selected prefname.
|
||||||
|
|
||||||
@param {object} DATA the data
|
@param {string} path the preference name
|
||||||
@param {number} CLOUD the storage
|
@param {object} data the new data to be written
|
||||||
|
@param {int} CLOUD store in the cloud; otherwise set to automatic
|
||||||
|
@param {object} OPTIONS the options
|
||||||
*/
|
*/
|
||||||
const store = async (DATA, CLOUD = 0) => {
|
static async write(path, data, CLOUD = -1, OPTIONS = {}) {
|
||||||
// If CLOUD is set to 0, it should automatically determine where the previous source of data was taken from.
|
let DATA_INJECTED = {};
|
||||||
return((CLOUD > 0) ? chrome.storage.sync.set(DATA) : chrome.storage.local.set(DATA));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Appropriately nest and merge the data.
|
// Inform the user that saving is in progress.
|
||||||
|
(((typeof OPTIONS).includes(`obj`) && OPTIONS != null) ? (!(!!OPTIONS[`silent`])) : true)
|
||||||
|
? new logging ((new texts(`saving_current`)).localized, (new texts(`saving_current_message`)).localized, false)
|
||||||
|
: false;
|
||||||
|
|
||||||
@param {object} EXISTING the original data
|
/* Appropriately nest and merge the data.
|
||||||
@param {object} PATH the subpath
|
|
||||||
@param {object} VALUE the value
|
|
||||||
@return {object} the updated data
|
|
||||||
*/
|
|
||||||
function nest(EXISTING, SUBPATH, VALUE) {
|
|
||||||
let DATABASE = EXISTING;
|
|
||||||
|
|
||||||
// Get the current path.
|
@param {object} EXISTING the original data
|
||||||
let PATH = {};
|
@param {object} PATH the subpath
|
||||||
PATH[`current`] = String(SUBPATH.shift()).trim();
|
@param {object} VALUE the value
|
||||||
PATH[`target`] = SUBPATH;
|
@param {boolean} STRICT determines whether data is to be overridden or merged
|
||||||
|
@return {object} the updated data
|
||||||
|
*/
|
||||||
|
function nest(EXISTING, SUBPATH, VALUE, STRICT = false) {
|
||||||
|
let DATABASE = EXISTING;
|
||||||
|
|
||||||
if (PATH[`target`].length > 0) {
|
// Get the current path.
|
||||||
if (DATABASE[PATH[`current`]] == null) {
|
let PATH = {};
|
||||||
DATABASE[PATH[`current`]] = {};
|
PATH[`current`] = String(SUBPATH.shift()).trim();
|
||||||
|
PATH[`target`] = SUBPATH;
|
||||||
|
|
||||||
|
if (PATH[`target`].length > 0) {
|
||||||
|
DATABASE[PATH[`current`]] = (DATABASE[PATH[`current`]] == null)
|
||||||
|
? {}
|
||||||
|
: DATABASE[PATH[`current`]];
|
||||||
|
DATABASE[PATH[`current`]] = nest(DATABASE[PATH[`current`]], PATH[`target`], VALUE, STRICT);
|
||||||
|
} else {
|
||||||
|
// If not strict and the data selected is a dictionary, then merge them.
|
||||||
|
DATABASE[PATH[`current`]] = (((DATABASE[PATH[`current`]]) ? ((typeof DATABASE[PATH[`current`]]).includes(`obj`) && !Array.isArray(DATABASE[PATH[`current`]])) : false) && !STRICT)
|
||||||
|
? Object.assign(DATABASE[PATH[`current`]], VALUE)
|
||||||
|
: VALUE;
|
||||||
}
|
}
|
||||||
DATABASE[PATH[`current`]] = nest(DATABASE[PATH[`current`]], PATH[`target`], VALUE);
|
|
||||||
} else {
|
// Return the value.
|
||||||
DATABASE[PATH[`current`]] = VALUE;
|
return DATABASE;
|
||||||
}
|
}
|
||||||
// Return the value.
|
|
||||||
return DATABASE;
|
async function verify (NAME, DATA) {
|
||||||
|
let DATA_CHECK = {};
|
||||||
|
|
||||||
|
// Verify the presence of the data.
|
||||||
|
DATA_CHECK[`state`] = await compare(NAME, DATA);
|
||||||
|
|
||||||
|
(!DATA_CHECK[`state`])
|
||||||
|
? logging.error((new texts(`error_msg_save_failed`)).localized, String(path), JSON.stringify(DATA))
|
||||||
|
: ((((typeof OPTIONS).includes(`obj`) && OPTIONS != null) ? (!(!!OPTIONS[`silent`])) : true)
|
||||||
|
? new logging (new texts(`saving_done`).localized)
|
||||||
|
: false);
|
||||||
|
|
||||||
|
return (DATA_CHECK[`state`]);
|
||||||
|
}
|
||||||
|
|
||||||
|
let DATA_ALL;
|
||||||
|
|
||||||
|
// Get all data and set a blank value if it doesn't exist yet.
|
||||||
|
DATA_ALL = await global.read(null, CLOUD);
|
||||||
|
DATA_ALL = ((DATA_ALL != null && (typeof DATA_ALL).includes(`obj`)) ? Object.keys(DATA_ALL).length <= 0 : true)
|
||||||
|
? {}
|
||||||
|
: DATA_ALL;
|
||||||
|
|
||||||
|
// Set the data name.
|
||||||
|
let DATA_NAME = (!(Array.isArray(path)) && path)
|
||||||
|
? String(path).trim().split(",")
|
||||||
|
: path;
|
||||||
|
|
||||||
|
// Merge!
|
||||||
|
DATA_INJECTED = nest(DATA_ALL, [...DATA_NAME], data, (OPTIONS[`strict`] != null) ? OPTIONS[`strict`] : false);
|
||||||
|
|
||||||
|
// If cloud is not selected, get where the data is already existent.
|
||||||
|
(CLOUD == 0 || CLOUD == null)
|
||||||
|
? (CLOUD = (DATA_ALL[`local`] != null) ? -1 : 1)
|
||||||
|
: false;
|
||||||
|
|
||||||
|
// Write!
|
||||||
|
chrome.storage[(CLOUD > 0) ? `sync` : `local`].set(DATA_INJECTED);
|
||||||
|
return (verify(DATA_NAME, data));
|
||||||
}
|
}
|
||||||
|
|
||||||
async function verify (NAME, DATA) {
|
/*
|
||||||
let DATA_CHECK = {};
|
Dangerous: Resets a particular data.
|
||||||
|
|
||||||
// Verify the presence of the data.
|
@param {string} preference the preference name to delete
|
||||||
DATA_CHECK[`state`] = await compare(NAME, DATA);
|
@param {string} subpreference the subpreference name to delete
|
||||||
|
@param {int} CLOUD the storage of the data
|
||||||
|
@return {boolean} the user's confirmation
|
||||||
|
*/
|
||||||
|
static async forget(preference, CLOUD = 0, override = false) {
|
||||||
|
// Confirm the action.
|
||||||
|
let CONFIRMATION = override ? override : await logging.confirm();
|
||||||
|
|
||||||
(!DATA_CHECK[`state`])
|
if (CONFIRMATION) {
|
||||||
? logging.error((new texts(`error_msg_save_failed`)).localized, String(PATH), JSON.stringify(DATA))
|
if (preference) {
|
||||||
: ((((typeof OPTIONS).includes(`obj`) && OPTIONS != null) ? (!(!!OPTIONS[`silent`])) : true)
|
/*
|
||||||
? new logging (new texts(`saving_done`).localized)
|
Erase applicable storage from a provider.
|
||||||
: false);
|
|
||||||
|
@param {string} name the name of the data
|
||||||
return (DATA_CHECK[`state`]);
|
@param {int} cloud the usage of cloud storage
|
||||||
|
*/
|
||||||
|
async function erase(name, cloud) {
|
||||||
|
let DATA_NAME = (!(Array.isArray(name))) ? String(name).trim().split(",") : name;
|
||||||
|
|
||||||
|
console.log(DATA_NAME, cloud, [...DATA_NAME.slice(0,-1)]);
|
||||||
|
|
||||||
|
let DATA = await global.read((DATA_NAME.length > 1) ? [...DATA_NAME.slice(0,-1)] : null, cloud);
|
||||||
|
|
||||||
|
console.log(DATA, DATA_NAME, cloud, [...DATA_NAME.slice(0,-1)]);
|
||||||
|
|
||||||
|
(((((typeof (DATA)).includes(`obj`) && !Array.isArray(DATA) && DATA != null) ? Object.keys(DATA) : false) ? Object.keys(DATA).includes(DATA_NAME[DATA_NAME.length - 1]) : false))
|
||||||
|
? delete DATA[DATA_NAME[DATA_NAME.length - 1]]
|
||||||
|
: false;
|
||||||
|
|
||||||
|
await global.write(DATA_NAME.slice(0,-1), DATA, CLOUD, {"strict": true});
|
||||||
|
}
|
||||||
|
|
||||||
|
(CLOUD >= 0) ? await erase(preference, 1) : false;
|
||||||
|
(CLOUD <= 0) ? await erase(preference, -1) : false;
|
||||||
|
} else {
|
||||||
|
// Clear the data storage.
|
||||||
|
(CLOUD >= 0) ? chrome.storage.sync.clear() : false;
|
||||||
|
(CLOUD <= 0) ? chrome.storage.local.clear() : false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return CONFIRMATION;
|
||||||
}
|
}
|
||||||
|
|
||||||
let DATA_ALL = await read(null, CLOUD);
|
|
||||||
if ((DATA_ALL != null && (typeof DATA_ALL).includes(`obj`)) ? Object.keys(DATA_ALL).length <= 0 : true) {
|
|
||||||
DATA_ALL = {};
|
|
||||||
};
|
|
||||||
|
|
||||||
let DATA_NAME = PATH;
|
|
||||||
|
|
||||||
// Convert the entered prefname to an array if it is not one.
|
|
||||||
if (!(typeof SUBPATH).includes(`object`)) {
|
|
||||||
// Split what is not an object.
|
|
||||||
DATA_NAME = String(PATH).trim().split(",");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Merge!
|
|
||||||
DATA_INJECTED = nest(DATA_ALL, [...DATA_NAME], DATA);
|
|
||||||
|
|
||||||
// Write!
|
|
||||||
store(DATA_INJECTED, CLOUD);
|
|
||||||
return (verify(DATA_NAME, DATA));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class session {
|
class session {
|
||||||
|
@ -376,33 +402,6 @@ class session {
|
||||||
// Write!
|
// Write!
|
||||||
store(DATA[`inject`]);
|
store(DATA[`inject`]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Compare a data against the stored data. Useful when comparing dictionaries.
|
|
||||||
|
|
||||||
@param {string} PATH the name
|
|
||||||
@param {object} DATA the data to compare to
|
|
||||||
@return {boolean} the result: true is when the data is the same, false otherwise
|
|
||||||
*/
|
|
||||||
static async compare(PATH, DATA) {
|
|
||||||
/* The actual comparison of data. */
|
|
||||||
async function comparison(DATA_ONE, DATA_TWO) {
|
|
||||||
let RESULT = true;
|
|
||||||
|
|
||||||
// The first round of checking is on the data type.
|
|
||||||
RESULT = ((typeof DATA_ONE == typeof DATA_TWO) ? ((Array.isArray(DATA_TWO) == Array.isArray(DATA_ONE)) && !((DATA_ONE == null && DATA_TWO != null) || (DATA_ONE != null && DATA_TWO == null))) : false) ? ((typeof DATA_ONE).includes(`obj`) ? (await hash.digest(DATA_ONE, {"output": "Number"}) == await hash.digest(DATA_TWO, {"output": "Number"})) : DATA_ONE == DATA_TWO) : false;
|
|
||||||
|
|
||||||
return (RESULT);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
let COMPARISON = {};
|
|
||||||
COMPARISON[`test`] = (PATH) ? DATA : DATA[1];
|
|
||||||
COMPARISON[`against`] = (PATH) ? (await session.read((Array.isArray(PATH)) ? [...PATH] : PATH)) : DATA[0];
|
|
||||||
COMPARISON[`result`] = comparison(COMPARISON[`against`], COMPARISON[`test`]);
|
|
||||||
|
|
||||||
// Return the result.
|
|
||||||
return (COMPARISON[`result`]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -432,129 +431,131 @@ export async function compare(PATH, DATA) {
|
||||||
|
|
||||||
let COMPARISON = {};
|
let COMPARISON = {};
|
||||||
COMPARISON[`test`] = (PATH) ? DATA : DATA[1];
|
COMPARISON[`test`] = (PATH) ? DATA : DATA[1];
|
||||||
COMPARISON[`against`] = (PATH) ? (await read((Array.isArray(PATH)) ? [...PATH] : PATH)) : DATA[0];
|
COMPARISON[`against`] = (PATH) ? (await global.read((Array.isArray(PATH)) ? [...PATH] : PATH)) : DATA[0];
|
||||||
COMPARISON[`result`] = comparison(COMPARISON[`against`], COMPARISON[`test`]);
|
COMPARISON[`result`] = comparison(COMPARISON[`against`], COMPARISON[`test`]);
|
||||||
|
|
||||||
// Return the result.
|
// Return the result.
|
||||||
return (COMPARISON[`result`]);
|
return (COMPARISON[`result`]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Dangerous: Resets all data or a domain's data.
|
class template {
|
||||||
|
/* Initialize the storage.
|
||||||
|
|
||||||
|
@param {dictionary} data this build's managed data
|
||||||
|
*/
|
||||||
|
static set(data) {
|
||||||
|
let PREFERENCES = {};
|
||||||
|
PREFERENCES[`all`] = {};
|
||||||
|
|
||||||
@param {string} preference the preference name to delete
|
((typeof data).includes(`obj`) && data != null) ? PREFERENCES[`all`][`build`] = data : false;
|
||||||
@param {string} subpreference the subpreference name to delete
|
|
||||||
@param {int} CLOUD the storage of the data
|
|
||||||
@return {boolean} the user's confirmation
|
|
||||||
*/
|
|
||||||
export async function forget(preference, CLOUD = 0, override = false) {
|
|
||||||
// Confirm the action.
|
|
||||||
let forget_action = override ? override : await logging.confirm();
|
|
||||||
|
|
||||||
if (forget_action) {
|
// Read all data.
|
||||||
if (preference) {
|
[`managed`, `local`, `sync`].forEach((SOURCE) => {
|
||||||
let erase = async (CLOUD) => {
|
chrome.storage[SOURCE].get(null, (DATA) => {
|
||||||
if (!(Array.isArray(preference))) {
|
PREFERENCES[`all`][SOURCE] = DATA;
|
||||||
preference = String(preference).trim().split(",");
|
})
|
||||||
};
|
});
|
||||||
|
|
||||||
let DATA = await read((preference.length > 1) ? [...preference.slice(0,-1)] : null, CLOUD);
|
// Merge the data.
|
||||||
|
// Managed > Synchronized > Imported > Local
|
||||||
|
managed.reinforce();
|
||||||
|
|
||||||
if (((((typeof (DATA)).includes(`obj`) && !Array.isArray(DATA) && DATA != null) ? Object.keys(DATA) : false) ? Object.keys(DATA).includes((preference.slice(-1))[0]) : false)) {
|
// Set the managed preferences.
|
||||||
delete DATA[preference.slice(-1)];
|
if ((PREFERENCES[`all`][`managed`] && (typeof PREFERENCES[`all`][`managed`]).includes(`obj`) && !Array.isArray(PREFERENCES[`all`][`managed`])) ? Object.keys(PREFERENCES[`all`][`managed`]).length > 0 : false) {
|
||||||
};
|
Object.keys(PREFERENCES[`all`][`managed`]).forEach((item) => {
|
||||||
|
let PREFERENCE = {};
|
||||||
|
PREFERENCE[`name`] = item;
|
||||||
|
|
||||||
await write(preference.slice(0,-1), DATA, CLOUD);
|
// Get if the data already exists.
|
||||||
};
|
PREFERENCE[`existing`] = (PREFERENCES[`all`][`sync`] && (typeof PREFERENCES[`all`][`sync`]).includes(`obj`))
|
||||||
|
? PREFERENCES[`all`][`sync`].hasOwnProperty(PREFERENCE[`name`])
|
||||||
|
: false;
|
||||||
|
|
||||||
if (CLOUD >= 0) {
|
if (!PREFERENCE[`existing`]) {
|
||||||
erase(1);
|
// Do not allow synchronized data to interfere with managed data.
|
||||||
};
|
global.forget(PREFERENCE[`name`], 0, true);
|
||||||
if (CLOUD <= 0) {
|
global.write(PREFERENCE[`name`], PREFERENCES_ALL[`managed`][PREFERENCE[`name`]]);
|
||||||
erase(-1);
|
}
|
||||||
};
|
});
|
||||||
} else {
|
};
|
||||||
// Clear the data storage.
|
|
||||||
if (CLOUD >= 0) {
|
// Import build data
|
||||||
chrome.storage.sync.clear();
|
if (PREFERENCES[`all`][`build`]) {
|
||||||
}
|
Object.keys(PREFERENCES[`all`][`build`]).forEach((item) => {
|
||||||
if (CLOUD <= 0) {
|
let PREFERENCE = { name: item, existing: false };
|
||||||
chrome.storage.local.clear();
|
|
||||||
}
|
PREFERENCE[`existing`] =
|
||||||
|
(PREFERENCES[`all`][`sync`]
|
||||||
|
? PREFERENCES[`all`][`sync`].hasOwnProperty(PREFERENCE[`name`])
|
||||||
|
: false) ||
|
||||||
|
(PREFERENCES[`all`][`managed`]
|
||||||
|
? PREFERENCES[`all`][`managed`].hasOwnProperty(PREFERENCE[`name`])
|
||||||
|
: false) ||
|
||||||
|
(PREFERENCES[`all`][`local`]
|
||||||
|
? PREFERENCES[`all`][`local`].hasOwnProperty(PREFERENCE[`local`])
|
||||||
|
: false);
|
||||||
|
|
||||||
|
(!PREFERENCE[`existing`])
|
||||||
|
? global.write(PREFERENCE[`name`], PREFERENCES[`all`][`build`][PREFERENCE[`name`]], -1)
|
||||||
|
: false;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
return forget_action;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initialize the storage.
|
/*
|
||||||
|
managed data functions
|
||||||
@param {dictionary} data this build's managed data
|
|
||||||
*/
|
*/
|
||||||
export function init(data) {
|
class managed {
|
||||||
let PREFERENCES_ALL = {};
|
/*
|
||||||
PREFERENCES_ALL[`build`] = data;
|
Reinforce managed data.
|
||||||
|
*/
|
||||||
// Read all data.
|
static reinforce() {
|
||||||
chrome.storage.managed.get(null, function (DATA_MANAGED) {
|
chrome.storage.managed.get(null, (DATA_MANAGED) => {
|
||||||
PREFERENCES_ALL[`managed`] = DATA_MANAGED;
|
// Saving the data asynchronously
|
||||||
});
|
(Object.keys(DATA_MANAGED)).forEach(async (SOURCE) => {
|
||||||
|
await write(SOURCE, DATA_MANAGED[SOURCE], -1, {"strict": false});
|
||||||
chrome.storage.local.get(null, function (DATA_LOCAL) {
|
});
|
||||||
PREFERENCES_ALL[`local`] = DATA_LOCAL;
|
|
||||||
});
|
|
||||||
|
|
||||||
chrome.storage.sync.get(null, function (DATA_SYNC) {
|
|
||||||
PREFERENCES_ALL[`sync`] = DATA_SYNC;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Merge data.
|
|
||||||
// Managed > Synchronized > Imported > Local
|
|
||||||
|
|
||||||
if (PREFERENCES_ALL[`managed`]) {
|
|
||||||
Object.keys(PREFERENCES_ALL[`managed`]).forEach((item) => {
|
|
||||||
let PREFERENCE = { name: item, existing: false };
|
|
||||||
|
|
||||||
if (PREFERENCES_ALL[`sync`]) {
|
|
||||||
PREFERENCE[`existing`] = PREFERENCES_ALL[`sync`].hasOwnProperty(
|
|
||||||
PREFERENCE[`name`],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!PREFERENCE[`existing`]) {
|
|
||||||
// Do not allow synchronized data to interfere with managed data.
|
|
||||||
forget(PREFERENCE[`name`]);
|
|
||||||
write(
|
|
||||||
PREFERENCE[`name`],
|
|
||||||
PREFERENCES_ALL[`managed`][PREFERENCE[`name`]],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Import build data
|
/*
|
||||||
if (PREFERENCES_ALL[`build`]) {
|
Read for any applicable managed data.
|
||||||
Object.keys(PREFERENCES_ALL[`build`]).forEach((item) => {
|
|
||||||
let PREFERENCE = { name: item, existing: false };
|
|
||||||
|
|
||||||
PREFERENCE[`existing`] =
|
@param {string} name the name of the data
|
||||||
(PREFERENCES_ALL[`sync`]
|
@return {boolean} the result
|
||||||
? PREFERENCES_ALL[`sync`].hasOwnProperty(PREFERENCE[`name`])
|
*/
|
||||||
: false) ||
|
static async read(name) {
|
||||||
(PREFERENCES_ALL[`managed`]
|
function find(DATA_ALL, DATA_PATH) {
|
||||||
? PREFERENCES_ALL[`managed`].hasOwnProperty(PREFERENCE[`name`])
|
let DATA = DATA_ALL;
|
||||||
: false) ||
|
|
||||||
(PREFERENCES_ALL[`local`]
|
|
||||||
? PREFERENCES_ALL[`local`].hasOwnProperty(PREFERENCE[`local`])
|
|
||||||
: false);
|
|
||||||
|
|
||||||
if (!PREFERENCE[`existing`]) {
|
// Pull the data out.
|
||||||
write(
|
if (DATA_ALL != null && (Array.isArray(DATA_PATH) && DATA_PATH != null) ? DATA_PATH.length > 0 : false) {
|
||||||
PREFERENCE[`name`],
|
let DATA_PATH_SELECTED = String(DATA_PATH.shift()).trim();
|
||||||
PREFERENCES_ALL[`build`][PREFERENCE[`name`]],
|
|
||||||
-1,
|
// Get the selected data.
|
||||||
);
|
DATA = DATA_ALL[DATA_PATH_SELECTED];
|
||||||
|
|
||||||
|
// must run if there is actually a parameter to test
|
||||||
|
if (DATA_PATH.length > 0) {
|
||||||
|
// Recursively run to make use of the existing data.
|
||||||
|
DATA = find(DATA, DATA_PATH);
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
// Now return the data.
|
||||||
|
return DATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
let DATA = {};
|
||||||
|
DATA[`all`] = await chrome.storage.managed.get(null);
|
||||||
|
DATA[`selected`] = ((DATA[`all`] && (typeof DATA[`all`]).includes(`obj`) && !Array.isArray(DATA[`all`])) ? Object.keys(DATA[`all`]).length : false)
|
||||||
|
? find(DATA[`all`], name)
|
||||||
|
: null;
|
||||||
|
|
||||||
|
return (DATA[`selected`]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -569,4 +570,4 @@ export function observe(reaction) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export {session}
|
export {global, session, template, managed};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue