diff --git a/gui/scripts/logging.JS b/gui/scripts/logging.JS index f544d76..2e30fb0 100644 --- a/gui/scripts/logging.JS +++ b/gui/scripts/logging.JS @@ -13,7 +13,9 @@ export default class logging { static error(ERROR_CODE, ERROR_MESSAGE, critical = true) { (async () => { // Import the templating. - const texts = await import(chrome.runtime.getURL("gui/scripts/read.js")); + const texts = ( + await import(chrome.runtime.getURL("gui/scripts/read.js")) + )[`texts`]; // Display the error message. console.error(texts.read(`error_msg`, [ERROR_CODE, ERROR_MESSAGE])); diff --git a/gui/scripts/pages/open/popup.JS b/gui/scripts/pages/open/popup.JS index addb39f..bdbf119 100644 --- a/gui/scripts/pages/open/popup.JS +++ b/gui/scripts/pages/open/popup.JS @@ -1,12 +1,11 @@ -import {windowman} from '../../windowman.JS'; +import { windowman } from "../../windowman.JS"; function redirect() { - new windowman(`gui/pages/settings.htm`); + windowman.new(`gui/pages/settings.htm`); window.close(); } - function main() { redirect(); } diff --git a/gui/scripts/pages/open/settings.JS b/gui/scripts/pages/open/settings.JS index 7a94a88..76715f3 100644 --- a/gui/scripts/pages/open/settings.JS +++ b/gui/scripts/pages/open/settings.JS @@ -1,14 +1,13 @@ // Open the settings in a pop-up window. -import {windowman} from '../../windowman.JS'; +import { windowman } from "../../windowman.JS"; function redirect() { - new windowman(`gui/pages/settings.htm`); + windowman.new(`gui/pages/settings.htm`); window.close(); } - function main() { redirect(); } diff --git a/gui/scripts/pages/settings.js b/gui/scripts/pages/settings.js index 85eb06e..1e17ab4 100644 --- a/gui/scripts/pages/settings.js +++ b/gui/scripts/pages/settings.js @@ -1,15 +1,25 @@ /* Settings.js - Build the interface for the settings + Build the interface for the settings */ // Import modules. -import { windowman } from "../windowman.js"; -let secretariat = await import(chrome.runtime.getURL("scripts/secretariat.js")); +//import { windowman } from "../windowman.js"; + +async function build() { + let secretariat = ( + await import(chrome.runtime.getURL("scripts/secretariat.js")) + ).secretariat; + let windowman = ( + await import(chrome.runtime.getURL("gui/scripts/windowman.js")) + ).windowman; + + let window = new windowman(); +} /* - Arrange the interface. - */ -function arrange() { + Arrange the interface. + */ +/*function arrange() { async function openLast() { let last_opened = ( await Promise.all([secretariat.read([`view`, window.location.href], 1)]) @@ -26,17 +36,24 @@ function arrange() { openLast(); } -/* - Define the mapping of each button. - */ -function events() { - windowman.events(); +function main() { + windowman.fill(); + events(); + arrange(); +}*/ + +/* + Define the mapping of each button. + */ +function events() { if (document.querySelector(`[data-action="filters,update"]`)) { document .querySelector(`[data-action="filters,update"]`) .addEventListener(`click`, async () => { - let filters = await import(chrome.runtime.getURL(`scripts/filters.js`)); + let filters = ( + await import(chrome.runtime.getURL(`scripts/filters.js`)) + ).default; filters.update(); }); } @@ -44,19 +61,22 @@ function events() { document .querySelector(`[data-action="storage,clear"]`) .addEventListener(`click`, async () => { - let storage = await import( - chrome.runtime.getURL(`scripts/secretariat.js`) - ); + let storage = ( + await import(chrome.runtime.getURL(`scripts/secretariat.js`)) + )["secretariat"]; storage.forget(`sites`); }); } } -function main() { - windowman.prepare(); - windowman.fill(); +//main(); +function load() { + document.addEventListener("DOMContentLoaded", function () { + M.AutoInit(); + }); + + build(); events(); - arrange(); } -main(); +load(); diff --git a/gui/scripts/windowman.JS b/gui/scripts/windowman.JS index 549e674..5948eec 100644 --- a/gui/scripts/windowman.JS +++ b/gui/scripts/windowman.JS @@ -1,76 +1,144 @@ /* windowman -Window management */ +Window and window content management */ import texts from "./read.js"; class windowman { - /* Initialize the window frame. */ - static prepare() { - try { - let UI = { - library: [ - chrome.runtime.getURL("gui/styles/interface.external.css"), - chrome.runtime.getURL("gui/styles/ui.css"), - ], - script: chrome.runtime.getURL( - "gui/scripts/external/interface.external.js", - ), - }; - - UI.library.forEach((source) => { - $(`head`).append( - ``, - ); - }); - - $(`head`).append(``); - } catch (error) { - console.error(texts.localized(`error_fileNotFound`, [error])); - } - - // Prevent scaling, similar to a real window. - $(`head`).append( - ``, - ); - } - - constructor(URL, height, width) { + static new(URL, height, width) { this.window = chrome.windows.create({ url: chrome.runtime.getURL(URL), type: "popup", - width: width ? parseInt(width) : 400, + width: width ? parseInt(width) : 600, height: height ? parseInt(height) : 600, }); } - static fill() { - function text() { - let text_elements = document.querySelectorAll("[data-text]"); + // Prepare the window with its metadata. + constructor() { + function headers() { + let UI = { + library: [ + chrome.runtime.getURL( + "gui/styles/external/mdi/materialdesignicons.min.css", + ), + chrome.runtime.getURL( + "gui/styles/external/materialize/css/materialize.css", + ), + chrome.runtime.getURL("gui/styles/ui.css"), + ], + }; - text_elements.forEach((text_element) => { - let text_inserted = texts.localized( - text_element.getAttribute(`data-text`), - false, - text_element.hasAttribute(`data-text-parameter`) - ? text_element.getAttribute(`data-text-parameter`).split(",") - : null, - ); - if (!text_inserted) { - text_inserted = texts.localized( - `term_`.concat(text_element.getAttribute(`data-text`)), - ); - } - - if (text_element.tagName.toLowerCase().includes(`input`)) { - text_element.setAttribute(`placholder`, text_inserted); - } else { - text_element.innerText = text_inserted; - } + UI.library.forEach((source) => { + let metadata_element = document.createElement(`link`); + metadata_element.setAttribute(`rel`, `stylesheet`); + metadata_element.setAttribute(`type`, `text/css`); + metadata_element.setAttribute(`href`, source); + document.querySelector(`head`).appendChild(metadata_element); }); } - function storage() { - (async () => { + // Get the window. + this[`metadata`] = chrome.windows.getCurrent(); + + /* + window_metadata[`id`] = window.id; + window_metadata[`focused`] = window.focused; + window_metadata[`state`] = window.state; + window_metadata[`type`] = window.type; + window_metadata[`incognito`] = window.incognito; + window_metadata[`alwaysOnTop`] = window.alwaysOnTop; + window_metadata[`sessionId`] = window.sessionId; + window_metadata[`tabs`] = window.tabs;*/ + + /* Fill in data and events. */ + function appearance() { + function icons() { + let target_elements = document.querySelectorAll(`[data-icon]`); + + target_elements.forEach((element) => { + // Get the content before removing it. + let element_data = {}; + + // Swap the placement of the existing content. + function swap() { + element_data[`content`] = element.innerHTML; + element.innerHTML = ``; + + let element_text = document.createElement(`span`); + element_text.innerHTML = element_data[`content`]; + + element.appendChild(element_text); + } + + // Add the icon. + function iconify() { + // Get the icon. + element_data[`icon`] = element.getAttribute(`data-icon`); + + // Get the icon. + let icon_element = document.createElement(`i`); + icon_element.className = `mdi mdi-`.concat(element_data[`icon`]); + element.prepend(icon_element); + } + + swap(); + iconify(); + }); + } + + function text() { + let text_elements = {}; + text_elements[`content`] = document.querySelectorAll("[for]"); + text_elements[`alt`] = document.querySelectorAll("[alt-for]"); + text_elements[`title`] = document.querySelectorAll("[title-for]"); + + text_elements[`content`].forEach((text_element) => { + let text_inserted = texts.localized( + text_element.getAttribute(`for`), + false, + text_element.hasAttribute(`for-parameter`) + ? text_element.getAttribute(`for-parameter`).split(",") + : null, + ); + if (!text_inserted) { + text_inserted = texts.localized( + `term_`.concat(text_element.getAttribute(`for`)), + ); + } + + if (text_element.tagName.toLowerCase().includes(`input`)) { + text_element.setAttribute(`placholder`, text_inserted); + } else { + text_element.innerText = text_inserted; + } + }); + + delete text_elements[`content`]; + Object.keys(text_elements).forEach((key) => { + if (text_elements[key]) { + text_elements[key].forEach((text_element) => { + let text_inserted = texts.localized( + text_element.getAttribute(key.concat(`-for`)), + false, + text_element.hasAttribute(key.concat(`for-parameter`)) + ? text_element + .getAttribute(key.concat(`for-parameter`)) + .split(",") + : null, + ); + if (!text_inserted) { + text_inserted = texts.localized( + `term_`.concat(text_element.getAttribute(key.concat(`-for`))), + ); + } + + text_element.setAttribute(key, text_inserted); + }); + } + }); + } + + async function storage() { // Import the module. const secretariat = await import( chrome.runtime.getURL("scripts/secretariat.js") @@ -108,18 +176,17 @@ class windowman { } }); }); - })(); + } + + text(); + icons(); + storage(); } - text(); - storage(); - } - - /* Add click events. */ - static events() { - /* Add events related to storage. */ - function storage() { - (async () => { + // Adds events to the window. + function events() { + /* Add events related to storage. */ + async function storage() { // Import the module. const secretariat = await import( chrome.runtime.getURL("scripts/secretariat.js") @@ -160,201 +227,97 @@ class windowman { input_element.addEventListener("change", element[`event`]); }); - })(); - } + } - /* Make it feel more like a native window. */ - function functionality() { - /* Adjust the interface based on events. */ - function changeUI() { - function tabs() { - let menus = document.querySelectorAll("menu[role=tablist]"); + /* Map buttons to their corresponding action buttons. */ + function actions() { + function links() { + let buttons = document.querySelectorAll("button[href]"); - if (menus) { - menus.forEach((menu) => { - let buttons = menu.querySelectorAll("button, a"); + if (buttons) { + buttons.forEach((button) => { + let event = function () { + // Get the data from the button. + let target = {}; + target[`source`] = this.getAttribute(`href`); - if (buttons) { - buttons.forEach((button) => { - let event = function () { - // Prevent selection. - let MENU = this.parentElement; - let BUTTONS = MENU.querySelectorAll("button, a"); + // Get the correct path. + target[`path`] = ( + !target[`source`].includes(`://`) + ? window.location.pathname + .split(`/`) + .slice(0, -1) + .join(`/`) + .concat(`/`) + : `` + ).concat(target[`source`]); - BUTTONS.forEach((BUTTON) => { - BUTTON.setAttribute( - `aria-selected`, - String( - BUTTON.getAttribute(`for`) == - this.getAttribute(`for`), - ), - ); - }); + windowman.new( + target[`path`], + this.getAttribute(`tab-height`) + ? this.getAttribute(`tab-height`) + : null, + this.getAttribute(`tab-width`) + ? this.getAttribute(`tab-width`) + : null, + ); + }; + button.addEventListener("click", event); + }); + } + } - let CONTAINER = document.getElementById( - MENU.getAttribute(`for`), - ); - let SECTIONS = CONTAINER.querySelectorAll( - `#${CONTAINER.id} > section`, - ); + links(); + } - SECTIONS.forEach((SECTION) => { - // SECTION.setAttribute(`hidden`, true); + /* + Update the interface based on the storage data changes. + */ + async function updates() { + // Import the module. + const secretariat = await import( + chrome.runtime.getURL("scripts/secretariat.js") + ); - if (!this.getAttribute(`for`).includes(SECTION.id)) { - SECTION.setAttribute( - `hidden`, - this.getAttribute(`for`).includes(SECTION.id), - ); - } else { - SECTION.removeAttribute(`hidden`); - } - }); + // Get the storage data. + let storage_data = await secretariat.read(); - // Save. - (async () => { - const secretariat = await import( - chrome.runtime.getURL("scripts/secretariat.js") - ); + async function update_interface() { + let input_elements = document.querySelectorAll("[data-enable]"); - // Write the data. - secretariat.write( - [`view`, window.location.href], - parseInt(this.getAttribute(`tab`)), - 1, - ); - })(); - }; - - button.addEventListener("click", event); - }); + if (input_elements) { + input_elements.forEach((input_element) => { + if (input_element.getAttribute("data-enable")) { + (async () => { + input_element.disabled = + (await secretariat.read( + input_element.getAttribute("data-enable"), + )) == null || + (await secretariat.read( + input_element.getAttribute("data-enable"), + )); + })(); } }); } } - tabs(); - } + // Update the input elements. + secretariat.observe((what) => { + update_interface(); + }); - document.addEventListener("contextmenu", (event) => - event.preventDefault(), - ); - - changeUI(); - } - - /* Map buttons to their corresponding action buttons. */ - function actions() { - function links() { - let buttons = document.querySelectorAll("button[href]"); - - if (buttons) { - buttons.forEach((button) => { - let event = function () { - // Get the data from the button. - let file = {}; - file[`target`] = this.getAttribute(`href`); - - // Check if the file exists to only open it when it is the case. - function testUrl(URL) { - // Code from https://stackoverflow.com/questions/3646914/how-do-i-check-if-file-exists-in-jquery-or-pure-javascript - const HTTP = new XMLHttpRequest(); - try { - HTTP.open(`HEAD`, URL, false); - HTTP.send(); - return HTTP.status != 404; - } catch (error) { - return false; - } - } - - if (!file[`target`].includes(`://`)) { - // Get the current path. - file[`path`] = window.location.pathname.split(`/`); - file[`path`] = - file[`path`].slice(0, file[`path`].length - 1).join(`/`) + - `/`; - file[`location`] = file[`path`].concat(file[`target`]); - } else { - file[`location`] = file[`target`]; - } - - let open_combinations = [``, `.htm`, `.html`]; - for ( - let open_combination = 0; - open_combination < open_combinations.length; - open_combination++ - ) { - if ( - testUrl( - file[`location`] + open_combinations[open_combination], - ) - ) { - new windowman( - file[`location`] + open_combinations[open_combination], - this.getAttribute(`tab-height`) - ? this.getAttribute(`tab-height`) - : null, - this.getAttribute(`tab-width`) - ? this.getAttribute(`tab-width`) - : null, - ); - break; - } - } - }; - button.addEventListener("click", event); - }); - } - } - - links(); - } - - /* - Update the interface based on the storage data changes. - */ - async function updates() { - // Import the module. - const secretariat = await import( - chrome.runtime.getURL("scripts/secretariat.js") - ); - - // Get the storage data. - let storage_data = await secretariat.read(); - - async function update_interface() { - let input_elements = document.querySelectorAll("[data-enable]"); - - if (input_elements) { - input_elements.forEach((input_element) => { - if (input_element.getAttribute("data-enable")) { - (async () => { - input_element.disabled = - (await secretariat.read( - input_element.getAttribute("data-enable"), - )) == null || - (await secretariat.read( - input_element.getAttribute("data-enable"), - )); - })(); - } - }); - } - } - - // Update the input elements. - secretariat.observe((what) => { update_interface(); - }); + } - update_interface(); + storage(); + actions(); + updates(); } - storage(); - functionality(); - actions(); - updates(); + headers(); + appearance(); + events(); } } diff --git a/scripts/fc.js b/scripts/fc.js index 3e44f94..7678afc 100644 --- a/scripts/fc.js +++ b/scripts/fc.js @@ -2,7 +2,7 @@ This does not stand for "FamiCom" but instead on Finalization and Completion. This script provides installation run scripts. */ -import { read, write, init } from "./secretariat.js"; +import { init } from "./secretariat.js"; let config = chrome.runtime.getURL("config/config.json"); diff --git a/scripts/filters.js b/scripts/filters.js index c8518f2..4b32e2c 100644 --- a/scripts/filters.js +++ b/scripts/filters.js @@ -2,102 +2,121 @@ Manage filters. */ -/* Select the most appropriate filter based on a URL. - -@param {string} URL the current URL -*/ -export async function select(URL = window.location.href) {} - -/* Update all filters or just one. - -@param {string} URL the URL to update -@return {boolean} the state -*/ -export async function update(URL) { - // Import the updater. - const secretariat = await import( - chrome.runtime.getURL("scripts/secretariat.js") - ); - const net = await import(chrome.runtime.getURL("scripts/net.js")); - const texts = await import(chrome.runtime.getURL("gui/scripts/read.js")); - - // Apparently, JS doesn't have a native queueing system, but it might best work here. - class Queue { - constructor() { - this.elements = []; - } - - enqueue(element) { - this.elements.push(element); - } - - dequeue() { - return this.elements.shift(); - } - - isEmpty() { - return this.elements.length <= 0; - } +export default class filters { + constructor() { + this.all = {}; } - // Create a queue of the filters. - let filters = new Queue(); + /* Select the most appropriate filter based on a URL. - if (URL) { - // Check if the URL is in a valid protocol - if (URL.includes(`://`)) { - // Append that to the queue. - filters.enqueue(URL); - } - } else { - // Add every item to the queue based on what was loaded first. - if ((await Promise.all([secretariat.read(`filters`, -1)]))[0]) { - Object.keys( - (await Promise.all([secretariat.read(`filters`, -1)]))[0], - ).every((filter_URL) => { - if (filter_URL.includes(`://`)) { - filters.enqueue(filter_URL); - } - }); - } + @param {string} URL the current URL + */ + static select(URL = window.location.href) { + this.one = {}; } - if (!filters.isEmpty()) { - while (!filters.isEmpty()) { - let filter_URL = filters.dequeue(); + /* Update all filters or just one. - // Inform the user of download state. - console.log( - texts.read(`settings_filters_update_status`, null, [filter_URL]), + @param {string} URL the URL to update + @return {boolean} the state + */ + static update(URL) { + (async () => { + // Import the updater. + const secretariat = await import( + chrome.runtime.getURL("scripts/secretariat.js") ); + const net = await import(chrome.runtime.getURL("scripts/net.js")); + const texts = (await import(chrome.runtime.getURL("gui/scripts/read.js"))) + .default; + const alerts = ( + await import(chrome.runtime.getURL("gui/scripts/alerts.js")) + ).default; - // Create promise of downloading. - let filter_download = net.download(filter_URL); - filter_download - .then((result) => { - // Only work when the filter is valid. - if (result) { - // Write the filter to storage. - secretariat.write(["filters", filter_URL], result, -1); - console.log( - texts.read(`settings_filters_update_status_complete`, null, [ - filter_URL, - ]), - ); - } - }) - .catch((error) => { - // Inform the user of the download failure. - console.log( - texts.read(`settings_filters_update_status_failure`, null, [ - error, + // Apparently, JS doesn't have a native queueing system, but it might best work here. + class Queue { + constructor() { + this.elements = []; + } + + enqueue(element) { + this.elements.push(element); + } + + dequeue() { + return this.elements.shift(); + } + + isEmpty() { + return this.elements.length <= 0; + } + } + + // Create a queue of the filters. + let filters = new Queue(); + + if (URL) { + // Check if the URL is in a valid protocol + if (URL.includes(`://`)) { + // Append that to the queue. + filters.enqueue(URL); + } + } else { + // Add every item to the queue based on what was loaded first. + if ((await Promise.all([secretariat.read(`filters`, -1)]))[0]) { + Object.keys( + (await Promise.all([secretariat.read(`filters`, -1)]))[0], + ).every((filter_URL) => { + if (filter_URL.includes(`://`)) { + filters.enqueue(filter_URL); + } + }); + } + } + + if (!filters.isEmpty()) { + while (!filters.isEmpty()) { + let filter_URL = filters.dequeue(); + + // Inform the user of download state. + alerts.log( + texts.localized(`settings_filters_update_status`, null, [ filter_URL, ]), ); - }); - } - } else { - // Inform the user of the download being unnecessary. - console.log(texts.read(`settings_filters_update_stop`)); + + // Create promise of downloading. + let filter_download = net.download(filter_URL); + filter_download + .then((result) => { + // Only work when the filter is valid. + if (result) { + // Write the filter to storage. + secretariat.write(["filters", filter_URL], result, -1); + console.log( + texts.localized( + `settings_filters_update_status_complete`, + null, + [filter_URL], + ), + ); + } + }) + .catch((error) => { + // Inform the user of the download failure. + console.log( + texts.localized( + `settings_filters_update_status_failure`, + null, + [error, filter_URL], + ), + ); + }); + } + } else { + // Inform the user of the download being unnecessary. + alerts.warn(texts.localized(`settings_filters_update_stop`)); + } + })(); } } diff --git a/scripts/secretariat.js b/scripts/secretariat.js index 4138774..a939742 100644 --- a/scripts/secretariat.js +++ b/scripts/secretariat.js @@ -27,11 +27,11 @@ export async function read(DATA_NAME, CLOUD = 0, PARAMETER_TEST = null) { } /* - Find the data now. + Get all dataset. - @param {number} SOURCE the data source - */ - function read_database(SOURCE = -1) { + @param {number} SOURCE the data source + */ + async function read_database(SOURCE = -1) { let data = {}; let data_returned; @@ -75,10 +75,10 @@ export async function read(DATA_NAME, CLOUD = 0, PARAMETER_TEST = null) { /* 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 - */ + @param {dictionary} DATA_ALL the data + @param {object} DATA_PATH the path of the data + @return {object} the data + */ function find_data(DATA_ALL, DATA_PATH, PARAMETER_TEST) { // Pull the data out. let DATA_PATH_SELECTED = String(DATA_PATH.shift()).trim(); @@ -185,9 +185,9 @@ export function write(PATH, DATA, CLOUD = -1) { /* Forcibly write the data to chrome database - @param {object} DATA the data - @param {number} CLOUD the storage - */ + @param {object} DATA the data + @param {number} CLOUD the storage + */ function write_database(DATA, CLOUD = 0) { // If CLOUD is set to 0, it should automatically determine where the previous source of data was taken from. @@ -200,11 +200,11 @@ export function write(PATH, DATA, CLOUD = -1) { /* Appropriately nest and merge the data. - @param {object} EXISTING the original data - @param {object} PATH the subpath - @param {object} VALUE the value - @return {object} the updated data - */ + @param {object} EXISTING the original data + @param {object} PATH the subpath + @param {object} VALUE the value + @return {object} the updated data + */ function nest(EXISTING, SUBPATH, VALUE) { let DATABASE = EXISTING; @@ -263,7 +263,9 @@ export function forget(preference, subpreference, CLOUD = 0) { (async () => { // Import alerts module. - let alerts = await import(chrome.runtime.getURL(`gui/scripts/alerts.js`)); + let alerts = (await import(chrome.runtime.getURL(`gui/scripts/alerts.js`)))[ + `alerts` + ]; // Confirm the action. let forget_action = alerts.confirm_action(); @@ -388,7 +390,7 @@ Run a script when the browser storage has been changed. @param {object} reaction the function to run */ -export async function observe(reaction) { +export function observe(reaction) { chrome.storage.onChanged.addListener((changes, namespace) => { reaction(changes, namespace); }); diff --git a/scripts/watchman.js b/scripts/watchman.js index a41eb6c..84b1e27 100644 --- a/scripts/watchman.js +++ b/scripts/watchman.js @@ -7,8 +7,10 @@ Be sensitive to changes and update the state. let secretariat = await import( chrome.runtime.getURL("scripts/secretariat.js") ); - let filters = await import(chrome.runtime.getURL("scripts/filters.js")); - let reader = await import(chrome.runtime.getURL("scripts/reader.js")); + let filters = (await import(chrome.runtime.getURL("scripts/filters.js")))[ + `filters` + ]; + // let reader = await import(chrome.runtime.getURL("scripts/reader.js")); class watchman { /* Check the current URL.