From 9f65b5a36e4a34b5d3c3b848a714be07cbe0d29b Mon Sep 17 00:00:00 2001
From: buzz-lightsnack-2007
<73412182+buzz-lightsnack-2007@users.noreply.github.com>
Date: Wed, 22 May 2024 23:04:26 +0800
Subject: [PATCH 01/45] rename "external" to "platform"
The e-commerce platform is external to the extension
---
src/manifest.json | 4 ++--
src/scripts/GUI/entrypoints/manager.js | 2 +-
src/scripts/{external => platform}/background.js | 2 +-
src/scripts/{external => platform}/check.js | 0
src/scripts/{external => platform}/processor.js | 2 +-
src/scripts/{external => platform}/scraper.js | 0
src/scripts/{external => platform}/watch.js | 4 ++--
7 files changed, 7 insertions(+), 7 deletions(-)
rename src/scripts/{external => platform}/background.js (59%)
rename src/scripts/{external => platform}/check.js (100%)
rename src/scripts/{external => platform}/processor.js (98%)
rename src/scripts/{external => platform}/scraper.js (100%)
rename src/scripts/{external => platform}/watch.js (94%)
diff --git a/src/manifest.json b/src/manifest.json
index aa794ae..b058623 100644
--- a/src/manifest.json
+++ b/src/manifest.json
@@ -15,13 +15,13 @@
"content_scripts": [
{
"matches": ["http://*/*", "https://*/*"],
- "js": ["scripts/external/background.js"]
+ "js": ["scripts/platform/background.js"]
}
],
"web_accessible_resources": [
{
"matches": ["http://*/*", "https://*/*"],
- "resources": ["scripts/*.js", "scripts/external/*.js"]
+ "resources": ["scripts/*.js", "scripts/platform/*.js"]
}
],
diff --git a/src/scripts/GUI/entrypoints/manager.js b/src/scripts/GUI/entrypoints/manager.js
index a90e71f..dcd8df7 100644
--- a/src/scripts/GUI/entrypoints/manager.js
+++ b/src/scripts/GUI/entrypoints/manager.js
@@ -3,7 +3,7 @@
import Tabs from "/scripts/GUI/tabs.js";
import Window from "/scripts/GUI/window.js";
import IconIndicator from "./iconindicator.js";
-import check from "/scripts/external/check.js";
+import check from "/scripts/platform/check.js";
import pointer from "/scripts/data/pointer.js";
export default class EntryManager {
diff --git a/src/scripts/external/background.js b/src/scripts/platform/background.js
similarity index 59%
rename from src/scripts/external/background.js
rename to src/scripts/platform/background.js
index 4bd494e..35a4da3 100644
--- a/src/scripts/external/background.js
+++ b/src/scripts/platform/background.js
@@ -7,7 +7,7 @@ The content script
// Import the necessary modules.
(async () => {
// Import the watchman module.
- let watch = (await import(chrome.runtime.getURL("scripts/external/watch.js"))).default;
+ let watch = (await import(chrome.runtime.getURL("scripts/platform/watch.js"))).default;
// Begin the job.
watch.main();
diff --git a/src/scripts/external/check.js b/src/scripts/platform/check.js
similarity index 100%
rename from src/scripts/external/check.js
rename to src/scripts/platform/check.js
diff --git a/src/scripts/external/processor.js b/src/scripts/platform/processor.js
similarity index 98%
rename from src/scripts/external/processor.js
rename to src/scripts/platform/processor.js
index 1ce4cac..2329038 100644
--- a/src/scripts/external/processor.js
+++ b/src/scripts/platform/processor.js
@@ -2,7 +2,7 @@
Process the information on the website and display it on screen.
*/
-import scraper from "/scripts/external/scraper.js";
+import scraper from "/scripts/platform/scraper.js";
import product from "/scripts/data/product.js";
import {global, background} from "/scripts/secretariat.js";
import logging from "/scripts/logging.js";
diff --git a/src/scripts/external/scraper.js b/src/scripts/platform/scraper.js
similarity index 100%
rename from src/scripts/external/scraper.js
rename to src/scripts/platform/scraper.js
diff --git a/src/scripts/external/watch.js b/src/scripts/platform/watch.js
similarity index 94%
rename from src/scripts/external/watch.js
rename to src/scripts/platform/watch.js
index de923cd..f5c16b5 100644
--- a/src/scripts/external/watch.js
+++ b/src/scripts/platform/watch.js
@@ -2,8 +2,8 @@
Be sensitive to changes and update the state.
*/
-import check from "/scripts/external/check.js";
-import processor from "/scripts/external/processor.js";
+import check from "/scripts/platform/check.js";
+import processor from "/scripts/platform/processor.js";
import logging from "/scripts/logging.js";
import texts from "/scripts/mapping/read.js";
import {global} from "/scripts/secretariat.js";
From 27757a5a366123aaac9b130c857e3dcaefa0fa6b Mon Sep 17 00:00:00 2001
From: buzz-lightsnack-2007
<73412182+buzz-lightsnack-2007@users.noreply.github.com>
Date: Wed, 22 May 2024 23:23:20 +0800
Subject: [PATCH 02/45] don't sync external scripts
You have to download yours and name it appropriately!
---
.gitignore | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.gitignore b/.gitignore
index e1985cf..249af4a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,6 @@
.DS_Store
/bin
-/src/styles/external/
+/src/s*s/external/
/src/config/config.json
*.log
*.crx
From a9e60aad2e7aea760b1a1c0ad17d3b471690f749 Mon Sep 17 00:00:00 2001
From: buzz-lightsnack-2007
<73412182+buzz-lightsnack-2007@users.noreply.github.com>
Date: Wed, 22 May 2024 23:24:24 +0800
Subject: [PATCH 03/45] run materialize directly after import
---
src/pages/popup.htm | 1 -
src/pages/popup/error.htm | 1 -
src/pages/popup/hello.htm | 1 -
src/pages/popup/load.htm | 1 -
src/pages/popup/results.htm | 1 -
src/pages/settings.htm | 3 +--
src/pages/settings/filters.htm | 1 -
src/scripts/GUI/builder/windowman.js | 14 ++++++++++++--
src/scripts/pages/page.js | 8 ++------
9 files changed, 15 insertions(+), 16 deletions(-)
diff --git a/src/pages/popup.htm b/src/pages/popup.htm
index 174ad91..a330d0a 100644
--- a/src/pages/popup.htm
+++ b/src/pages/popup.htm
@@ -1,7 +1,6 @@
-
diff --git a/src/pages/popup/error.htm b/src/pages/popup/error.htm
index d071c35..89053ff 100644
--- a/src/pages/popup/error.htm
+++ b/src/pages/popup/error.htm
@@ -1,6 +1,5 @@
-
diff --git a/src/pages/popup/hello.htm b/src/pages/popup/hello.htm
index 9c64806..c9b6fc6 100644
--- a/src/pages/popup/hello.htm
+++ b/src/pages/popup/hello.htm
@@ -2,7 +2,6 @@
-
diff --git a/src/pages/popup/load.htm b/src/pages/popup/load.htm
index 70dd85f..78cc85c 100644
--- a/src/pages/popup/load.htm
+++ b/src/pages/popup/load.htm
@@ -1,6 +1,5 @@
-
diff --git a/src/pages/popup/results.htm b/src/pages/popup/results.htm
index 74827e0..cb25340 100644
--- a/src/pages/popup/results.htm
+++ b/src/pages/popup/results.htm
@@ -1,6 +1,5 @@
-
diff --git a/src/pages/settings.htm b/src/pages/settings.htm
index 806a492..0eb2611 100644
--- a/src/pages/settings.htm
+++ b/src/pages/settings.htm
@@ -1,8 +1,7 @@
-
-
+
diff --git a/src/pages/settings/filters.htm b/src/pages/settings/filters.htm
index e12f574..80cebfc 100644
--- a/src/pages/settings/filters.htm
+++ b/src/pages/settings/filters.htm
@@ -1,7 +1,6 @@
-
diff --git a/src/scripts/GUI/builder/windowman.js b/src/scripts/GUI/builder/windowman.js
index 5dc1d07..30b8e51 100644
--- a/src/scripts/GUI/builder/windowman.js
+++ b/src/scripts/GUI/builder/windowman.js
@@ -6,6 +6,7 @@ import Tabs from "/scripts/GUI/tabs.js";
import {global, background} from "/scripts/secretariat.js";
import {URLs} from "/scripts/utils/URLs.js";
import wait from "/scripts/utils/wait.js";
+import logging from "/scripts/logging.js";
import UI from "/scripts/GUI/builder/windowman.extras.js";
export default class windowman {
@@ -20,8 +21,8 @@ export default class windowman {
function headers (OPTIONS) {
let LOAD_STATE = true;
let UI = {
- "CSS": ["/styles/external/fonts/materialdesignicons.min.css", "/styles/external/materialize/css/materialize.css", "/styles/ui.css"],
- "scripts": ["/styles/external/materialize/js/materialize.js"]
+ "CSS": ["https://cdn.jsdelivr.net/npm/@mdi/font@7.4.47/css/materialdesignicons.min.css", "https://cdn.jsdelivr.net/npm/@materializecss/materialize@2.0.3-alpha/dist/css/materialize.min.css", "/styles/ui.css"],
+ "scripts": ["/scripts/external/materialize.min.js"]
};
// Add additional sources.
@@ -61,6 +62,15 @@ export default class windowman {
ELEMENT.setAttribute(key, METADATA[key]);
});
document.querySelector(`head`).appendChild(ELEMENT);
+
+ if (source.includes(`materialize`) && source.includes(`js`)) {
+ ELEMENT.onload = () => {
+ M.AutoInit();
+ };
+ ELEMENT.onerror = (err) => {
+ logging.error(err);
+ };
+ };
})
: false;
diff --git a/src/scripts/pages/page.js b/src/scripts/pages/page.js
index baf8441..82a1c4d 100644
--- a/src/scripts/pages/page.js
+++ b/src/scripts/pages/page.js
@@ -14,10 +14,6 @@ export default class Page {
this.window.manager.sync();
Object.assign(this.window, this.window[`manager`]);
- }
-
- document.addEventListener("DOMContentLoaded", function () {
- M.AutoInit();
- });
- }
+ };
+ };
};
\ No newline at end of file
From 6ad2b1f93a6be5741dbdf5025a1cc3d22cdda629 Mon Sep 17 00:00:00 2001
From: buzz-lightsnack-2007
<73412182+buzz-lightsnack-2007@users.noreply.github.com>
Date: Wed, 22 May 2024 23:39:58 +0800
Subject: [PATCH 04/45] Scroll to the tab
---
src/scripts/GUI/builder/windowman.tabs.js | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/src/scripts/GUI/builder/windowman.tabs.js b/src/scripts/GUI/builder/windowman.tabs.js
index 840a2d7..39a964e 100644
--- a/src/scripts/GUI/builder/windowman.tabs.js
+++ b/src/scripts/GUI/builder/windowman.tabs.js
@@ -131,6 +131,12 @@ class Tabs {
((nested.dictionary.get(this, [name, `elements`, `tabs`, ID, `header`]) && ((nested.dictionary.get(options, [`automatic`]) != null) ? !options[`automatic`] : true))
? ((this[name][`elements`][`tabs`][ID][`container`].classList.contains(`active`)) ? false : this[name][`elements`][`tabs`][ID][`header`].click())
: false);
+
+ // Scroll to the tab.
+ if (nested.dictionary.get(this, [name, `elements`, `tabs`, ID, `header`])) {
+ // Scroll to the tab.
+ this[name][`elements`][`tabs`][ID][`header`].scrollIntoView({"behavior": "smooth", "block": "start"});
+ };
// Remove the lock.
this[`status`][`opening`] = false;
From e7dd3dbcaa57e932fd6beedf3925d9938fb19aaa Mon Sep 17 00:00:00 2001
From: buzz-lightsnack-2007
<73412182+buzz-lightsnack-2007@users.noreply.github.com>
Date: Wed, 22 May 2024 23:56:04 +0800
Subject: [PATCH 05/45] determine initialization status
---
src/scripts/pages/popup.js | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/scripts/pages/popup.js b/src/scripts/pages/popup.js
index b053739..2dfbf44 100644
--- a/src/scripts/pages/popup.js
+++ b/src/scripts/pages/popup.js
@@ -47,6 +47,7 @@ class Page_Popup extends Page {
: ((this[`status`])
? this[`status`]
: {});
+ this[`status`][`init`] = DATA[`init`];
// Confirm completion by returning the status.
return (this[`status`]);
From 796a7765639f6431e7c814c8fb5a56cf52c60ebb Mon Sep 17 00:00:00 2001
From: buzz-lightsnack-2007
<73412182+buzz-lightsnack-2007@users.noreply.github.com>
Date: Wed, 22 May 2024 23:56:30 +0800
Subject: [PATCH 06/45] load OOBE when not initialized properly
---
src/scripts/pages/popup.js | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/src/scripts/pages/popup.js b/src/scripts/pages/popup.js
index 2dfbf44..6bb98f2 100644
--- a/src/scripts/pages/popup.js
+++ b/src/scripts/pages/popup.js
@@ -71,7 +71,14 @@ class Page_Popup extends Page {
this.update().then(() => {
// Make sure that the website has been selected!
if (this[`ref`]) {
- let PAGE = chrome.runtime.getURL(`pages/popup/`.concat(PAGES[(this[`status`][`done`] <= -1 || this[`status`][`error`]) ? `error` : ((this[`status`][`done`] >= 1) ? `results` : `loading`)]));
+ let SELECTION = this[`status`][`init`]
+ ? (this[`status`][`done`] <= -1 || this[`status`][`error`])
+ ? `error`
+ : ((this[`status`][`done`] >= 1)
+ ? `results`
+ : `loading`)
+ : `OOBE`;
+ let PAGE = chrome.runtime.getURL(`pages/popup/`.concat(PAGES[SELECTION]));
// Replace the iframe src with the new page.
(this.elements[`frame`].src != PAGE) ? this.elements[`frame`].src = PAGE : false;
From d625972726cc92a37ab5d126568c2013c85bbf6e Mon Sep 17 00:00:00 2001
From: buzz-lightsnack-2007
<73412182+buzz-lightsnack-2007@users.noreply.github.com>
Date: Thu, 23 May 2024 15:56:46 +0800
Subject: [PATCH 07/45] set empty-keyed DATA if null
---
src/scripts/utils/nested.js | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/scripts/utils/nested.js b/src/scripts/utils/nested.js
index 846c9c4..62d6e77 100644
--- a/src/scripts/utils/nested.js
+++ b/src/scripts/utils/nested.js
@@ -46,6 +46,7 @@ nested.dictionary = class dictionary {
*/
static set(data, path, value, options = {}) {
let DATA = data, PATH = path, VALUE = value;
+ (DATA == null) ? DATA = {} : false;
// Convert path into an array if not yet set.
PATH = (Array.isArray(PATH)) ? PATH : (PATH && (typeof PATH).includes(`str`)) ? PATH.trim().split(`,`) : [];
From 226a39818c862a1b43e426be39cd067b4e596ad9 Mon Sep 17 00:00:00 2001
From: buzz-lightsnack-2007
<73412182+buzz-lightsnack-2007@users.noreply.github.com>
Date: Thu, 23 May 2024 16:20:14 +0800
Subject: [PATCH 08/45] add message for pop-outs
---
src/_locales/en/messages.json | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/_locales/en/messages.json b/src/_locales/en/messages.json
index 8e4cbff..70ade93 100644
--- a/src/_locales/en/messages.json
+++ b/src/_locales/en/messages.json
@@ -89,6 +89,9 @@
"term_hello": {
"message": "Hello!"
},
+ "term_popout": {
+ "message": "Pop-Out"
+ },
"page_opening": {
"message": "Opening…"
From 80321abfe750651e2f23413a8dbe0c8ac606b43c Mon Sep 17 00:00:00 2001
From: buzz-lightsnack-2007
<73412182+buzz-lightsnack-2007@users.noreply.github.com>
Date: Thu, 23 May 2024 16:21:31 +0800
Subject: [PATCH 09/45] rename windowman modules and references
---
src/scripts/GUI/builder/extras.js | 11 +++++++++++
.../GUI/builder/{windowman.search.js => search.js} | 0
.../GUI/builder/{windowman.tabs.js => tabs.js} | 0
src/scripts/GUI/builder/windowman.extras.js | 9 ---------
src/scripts/GUI/builder/windowman.js | 2 +-
5 files changed, 12 insertions(+), 10 deletions(-)
create mode 100644 src/scripts/GUI/builder/extras.js
rename src/scripts/GUI/builder/{windowman.search.js => search.js} (100%)
rename src/scripts/GUI/builder/{windowman.tabs.js => tabs.js} (100%)
delete mode 100644 src/scripts/GUI/builder/windowman.extras.js
diff --git a/src/scripts/GUI/builder/extras.js b/src/scripts/GUI/builder/extras.js
new file mode 100644
index 0000000..57ddbcc
--- /dev/null
+++ b/src/scripts/GUI/builder/extras.js
@@ -0,0 +1,11 @@
+
+import {Search} from "./search.js";
+import {Tabs} from "./tabs.js";
+import {NavigationBar} from "./navigation.js";
+
+class UI {}
+UI.search = Search;
+UI.tabs = Tabs;
+UI[`navigation bar`] = NavigationBar;
+
+export {UI as default};
\ No newline at end of file
diff --git a/src/scripts/GUI/builder/windowman.search.js b/src/scripts/GUI/builder/search.js
similarity index 100%
rename from src/scripts/GUI/builder/windowman.search.js
rename to src/scripts/GUI/builder/search.js
diff --git a/src/scripts/GUI/builder/windowman.tabs.js b/src/scripts/GUI/builder/tabs.js
similarity index 100%
rename from src/scripts/GUI/builder/windowman.tabs.js
rename to src/scripts/GUI/builder/tabs.js
diff --git a/src/scripts/GUI/builder/windowman.extras.js b/src/scripts/GUI/builder/windowman.extras.js
deleted file mode 100644
index a78a5bc..0000000
--- a/src/scripts/GUI/builder/windowman.extras.js
+++ /dev/null
@@ -1,9 +0,0 @@
-
-import {Search} from "./windowman.search.js";
-import {Tabs} from "./windowman.tabs.js";
-
-class UI {}
-UI.search = Search;
-UI.tabs = Tabs;
-
-export {UI as default};
\ No newline at end of file
diff --git a/src/scripts/GUI/builder/windowman.js b/src/scripts/GUI/builder/windowman.js
index 30b8e51..5e8763e 100644
--- a/src/scripts/GUI/builder/windowman.js
+++ b/src/scripts/GUI/builder/windowman.js
@@ -7,7 +7,7 @@ import {global, background} from "/scripts/secretariat.js";
import {URLs} from "/scripts/utils/URLs.js";
import wait from "/scripts/utils/wait.js";
import logging from "/scripts/logging.js";
-import UI from "/scripts/GUI/builder/windowman.extras.js";
+import UI from "/scripts/GUI/builder/extras.js";
export default class windowman {
elements = {};
From b1ac5bc5458f7bf70b780e86e591888f13763c6e Mon Sep 17 00:00:00 2001
From: buzz-lightsnack-2007
<73412182+buzz-lightsnack-2007@users.noreply.github.com>
Date: Thu, 23 May 2024 16:21:54 +0800
Subject: [PATCH 10/45] add OOBE menu bar
---
src/pages/popup.htm | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/src/pages/popup.htm b/src/pages/popup.htm
index a330d0a..3239aef 100644
--- a/src/pages/popup.htm
+++ b/src/pages/popup.htm
@@ -7,10 +7,14 @@
From 6a415e8aa602d886fcfc731eacae12c049dcac5c Mon Sep 17 00:00:00 2001
From: buzz-lightsnack-2007
<73412182+buzz-lightsnack-2007@users.noreply.github.com>
Date: Thu, 23 May 2024 16:28:22 +0800
Subject: [PATCH 11/45] automatically open API configuration of the OOBE
---
src/scripts/pages/hello.js | 17 ++++++++++++-----
1 file changed, 12 insertions(+), 5 deletions(-)
diff --git a/src/scripts/pages/hello.js b/src/scripts/pages/hello.js
index 3f34531..82f0895 100644
--- a/src/scripts/pages/hello.js
+++ b/src/scripts/pages/hello.js
@@ -21,10 +21,19 @@ class Page_MiniConfig extends Page {
Set the default options.
*/
#set() {
- (!this.window.tabs.OOBE.selected) ? this.window.tabs.open(`OOBE`, `OOBE_Hello`) : false;
+ global.read([`init`]).then((STATE) => {
+ if (!STATE) {
+ this.window.tabs.open(`OOBE`, `OOBE_Hello`);
+
+ // Update the storage to mark that the OOBE page has been viewed.
+ global.write([`init`], true, 1, {"silent": true});
+ } else {
+ global.read([`settings`,`analysis`,`api`,`key`]).then((STATE) => {
+ (!STATE) ? this.window.tabs.open(`OOBE`, `OOBE_APISetup`) : false;
+ });
+ };
+ });
- // Update the storage to mark that the OOBE page has been viewed.
- global.write([`init`], true, 1, {"silent": true});
}
/*
@@ -89,8 +98,6 @@ class Page_MiniConfig extends Page {
Object.keys(ELEMENTS[STEP_NUMBER][`container`]).forEach((PART) => {
ELEMENTS[STEP_NUMBER][`container`][PART].classList.add(`card`.concat(([`container`].includes(PART)) ? `` : `-`.concat(PART)));
});
-
- ELEMENTS[STEP_NUMBER][`container`][`container`].classList.add(`container`);
}
const set_contents = () => {
From 6c62f67f4cfa2e41a2681b9272abae4d2a371f2a Mon Sep 17 00:00:00 2001
From: buzz-lightsnack-2007
<73412182+buzz-lightsnack-2007@users.noreply.github.com>
Date: Thu, 23 May 2024 16:28:40 +0800
Subject: [PATCH 12/45] create navigation bar elements manager
---
src/scripts/GUI/builder/navigation.js | 128 ++++++++++++++++++++++++++
1 file changed, 128 insertions(+)
create mode 100644 src/scripts/GUI/builder/navigation.js
diff --git a/src/scripts/GUI/builder/navigation.js b/src/scripts/GUI/builder/navigation.js
new file mode 100644
index 0000000..f00ba2f
--- /dev/null
+++ b/src/scripts/GUI/builder/navigation.js
@@ -0,0 +1,128 @@
+/*
+
+*/
+
+import nested from "/scripts/utils/nested.js";
+
+class NavigationBar {
+ options = {};
+
+ constructor () {
+ this.#get();
+ };
+
+ #get () {
+ let NAVIGATION_ELEMENTS = document.querySelectorAll(`nav.nav-wrapper`);
+
+ // If there are navigation elements, then proceed.
+ (NAVIGATION_ELEMENTS.length)
+ ? (NAVIGATION_ELEMENTS.forEach((ELEMENT) => {
+ // Set the name, or generate one if it doesn't exist.
+ let NAME = (ELEMENT.getAttribute(`id`) || ELEMENT.getAttribute(`nav-name`) || Object.keys(this).length);
+
+ if (!([`options`].includes(NAME))) {
+ this[NAME] = (this[NAME]) ? this[NAME] : {};
+
+ // Set the elements.
+ this[NAME][`elements`] = nested.dictionary.set(this[NAME][`elements`], `container`, ELEMENT);
+
+ /*
+ Get elements expected to only have one in existence.
+ */
+ const get_constant_elements = () => {
+ // Define the attributes to look for
+ const ELEMENTS_ATTRIBUTES = [`brand-logo`];
+
+ const add_elements = (list_classes) => {
+ list_classes.forEach((CLASS) => {
+ let ELEMENTS = ELEMENT.querySelectorAll(`:scope .${CLASS}`);
+
+ // If the element exists, then proceed.
+ (ELEMENTS.length)
+ ? this[NAME][`elements`][CLASS] = ELEMENTS
+ : false;
+ })
+ };
+ add_elements(ELEMENTS_ATTRIBUTES);
+ }
+
+ const set_elements_groups = () => {
+ let GROUPS = ELEMENT.querySelectorAll(`:scope > ul`);
+
+ (GROUPS.length)
+ ? GROUPS.forEach((GROUP) => {
+ // Get the name.
+ let NAME_GROUP = (GROUP.getAttribute(`nav-group-name`) || GROUP.getAttribute(`id`) || ((this[NAME][`elements`][`groups`] ? Object.keys(this[NAME][`elements`][`groups`]).length + 1 : 0) + 1));
+
+ // Set the elements.
+ this[NAME][`elements`][`groups`] = nested.dictionary.set(this[NAME][`elements`][`groups`], NAME_GROUP, {"container": GROUP, "items": GROUP.querySelectorAll(`:scope > li`)});
+
+ // Set the element properties.
+ this[NAME][`group`] = nested.dictionary.set(this[NAME][`group`], NAME_GROUP, {"hidden": GROUP.hidden});
+
+ // Remove the attributes.
+ GROUP.removeAttribute(`nav-group-name`)
+ })
+ : false;
+ };
+
+ const set_default_properties = () => {
+ this[NAME].hidden = this[NAME][`elements`][`container`].hidden;
+ };
+
+ get_constant_elements();
+ set_elements_groups();
+ };
+
+ // Remove the attributes.
+ ELEMENT.removeAttribute(`nav-name`);
+ }))
+ : false;
+ };
+
+ /*
+ Show the navigation bar or one of its groups.
+
+ @param {string} name the name of the navigation bar
+ @param {string} group the name of the group to show
+ @return {boolean} the operation state
+ */
+ show(name, group) {
+ if ((name && group) ? ((Object.keys(this).includes(name)) ? ((this[name][`group`]) ? Object.keys(this[name][`group`]).includes(group) : false) : false) : false) {
+ this[name][`elements`][`groups`][group][`container`].hidden = false;
+ this[name][`group`][group][`hidden`] = this[name][`elements`][`groups`][group][`container`].hidden;
+
+ return (this[name][`group`][group][`hidden`] == false);
+ } else if (name ? Object.keys(this).includes(name) : false) {
+ this[name][`elements`][`container`].hidden = false;
+ this[name][`elements`][`container`].classList.remove(`hidden`);
+ this[name].hidden = this[name][`elements`][`container`].hidden;
+
+ return (this[name].hidden == false);
+ };
+ };
+
+ /*
+ Hide the navigation bar or one of its groups.
+
+ @param {string} name the name of the navigation bar
+ @param {string} group the name of the group to show
+ @return {boolean} the operation state
+ */
+ hide(name, group) {
+ if ((name && group) ? ((Object.keys(this).includes(name)) ? ((this[name][`group`]) ? Object.keys(this[name][`group`]).includes(group) : false) : false) : false) {
+ this[name][`elements`][`groups`][group][`container`].hidden = true;
+ this[name][`group`][group][`hidden`] = this[name][`elements`][`groups`][group][`container`].hidden;
+
+ return (this[name][`group`][group][`hidden`] == true);
+ } else if (name ? Object.keys(this).includes(name) : false) {
+ this[name][`elements`][`container`].hidden = true;
+ this[name][`elements`][`container`].classList.add(`hidden`);
+ this[name].hidden = this[name][`elements`][`container`].hidden;
+
+ return (this[name].hidden == true);
+ };
+ };
+};
+
+export {NavigationBar};
\ No newline at end of file
From 4309d1ac6bc88f11f36a60db5d1ecb7cb128e270 Mon Sep 17 00:00:00 2001
From: buzz-lightsnack-2007
<73412182+buzz-lightsnack-2007@users.noreply.github.com>
Date: Thu, 23 May 2024 16:29:18 +0800
Subject: [PATCH 13/45] open OOBE when set up is incomplete
Update navigation bar
---
src/scripts/pages/popup.js | 15 +++++++++------
1 file changed, 9 insertions(+), 6 deletions(-)
diff --git a/src/scripts/pages/popup.js b/src/scripts/pages/popup.js
index 6bb98f2..32b8900 100644
--- a/src/scripts/pages/popup.js
+++ b/src/scripts/pages/popup.js
@@ -4,7 +4,6 @@
// Import modules.
import {global, background} from "/scripts/secretariat.js";
-import Window from "/scripts/GUI/window.js";
import Page from "/scripts/pages/page.js";
import Loader from "/scripts/GUI/loader.js";
import Tabs from "/scripts/GUI/tabs.js";
@@ -36,9 +35,9 @@ class Page_Popup extends Page {
if (override || !this[`ref`]) {this[`ref`] = await global.read([`last`])};
// Get all the data to be used here.
- let DATA = {
- "status": await global.read([`sites`, this[`ref`], `status`], -1)
- };
+ let DATA = {};
+ DATA[`status`] = await global.read([`sites`, this[`ref`], `status`], -1);
+ DATA[`init`] = (await global.read([`init`])) && (await global.read([`settings`,`analysis`,`api`,`key`]));
// Update all other data.
this[`status`] = (DATA[`status`] != null)
@@ -83,8 +82,12 @@ class Page_Popup extends Page {
// Replace the iframe src with the new page.
(this.elements[`frame`].src != PAGE) ? this.elements[`frame`].src = PAGE : false;
- // The results page has its own container.
- this.elements[`container`].classList[(PAGE.includes(`results`)) ? `remove` : `add`](`container`);
+ // The results and OOBE pages has its own container.
+ this.elements[`container`].classList[([`results`, `OOBE`].includes(SELECTION)) ? `remove` : `add`](`container`);
+
+ // Set the title bar content.
+ this[`window`][`navigation bar`][([`OOBE`].includes(SELECTION)) ? `hide` : `show`](`header`, `results`);
+ this[`window`][`navigation bar`][([`OOBE`].includes(SELECTION)) ? `show` : `hide`](`header`, `OOBE`);
};
});
}
From 3131b0760a4f099901b1c8c9787cad8839d7c5b4 Mon Sep 17 00:00:00 2001
From: buzz-lightsnack-2007
<73412182+buzz-lightsnack-2007@users.noreply.github.com>
Date: Thu, 23 May 2024 22:08:58 +0800
Subject: [PATCH 14/45] remove trigger textbox
Not in this version
---
src/pages/settings/filters.htm | 4 ----
1 file changed, 4 deletions(-)
diff --git a/src/pages/settings/filters.htm b/src/pages/settings/filters.htm
index 80cebfc..c687c54 100644
--- a/src/pages/settings/filters.htm
+++ b/src/pages/settings/filters.htm
@@ -63,10 +63,6 @@
-
-
-
-
From 174bdd5ee822859dcd89600619af427c3e21038e Mon Sep 17 00:00:00 2001
From: buzz-lightsnack-2007
<73412182+buzz-lightsnack-2007@users.noreply.github.com>
Date: Thu, 23 May 2024 22:11:55 +0800
Subject: [PATCH 15/45] show different groups of navbar elements during
different pages
---
src/pages/popup.htm | 4 +++-
src/scripts/pages/popup.js | 18 ++++++++++++++++--
src/scripts/platform/processor.js | 22 ++++++++++++++--------
3 files changed, 33 insertions(+), 11 deletions(-)
diff --git a/src/pages/popup.htm b/src/pages/popup.htm
index 3239aef..c3c3eed 100644
--- a/src/pages/popup.htm
+++ b/src/pages/popup.htm
@@ -7,12 +7,14 @@
diff --git a/src/scripts/pages/popup.js b/src/scripts/pages/popup.js
index 32b8900..9324db7 100644
--- a/src/scripts/pages/popup.js
+++ b/src/scripts/pages/popup.js
@@ -65,6 +65,13 @@ class Page_Popup extends Page {
"OOBE": "hello.htm",
"error": "error.htm"
};
+ // Set the width and the height.
+ const PAGES_DIMENSIONS = {
+ "loading": {"width": "200pt", "height": "100pt"},
+ "error": {"width": "250pt", "height": "300pt"},
+ "results": {"width": "250pt", "height": "225pt"},
+ "OOBE": {"width": "350pt", "height": "300pt"},
+ };
// Prepare all the necessary data.
this.update().then(() => {
@@ -86,8 +93,15 @@ class Page_Popup extends Page {
this.elements[`container`].classList[([`results`, `OOBE`].includes(SELECTION)) ? `remove` : `add`](`container`);
// Set the title bar content.
- this[`window`][`navigation bar`][([`OOBE`].includes(SELECTION)) ? `hide` : `show`](`header`, `results`);
- this[`window`][`navigation bar`][([`OOBE`].includes(SELECTION)) ? `show` : `hide`](`header`, `OOBE`);
+ this[`window`][`navigation bar`][([`OOBE`, `loading`].includes(SELECTION)) ? `hide` : `show`](`header`, `result`);
+ [`loading`, `OOBE`].forEach((NAME) => {
+ this[`window`][`navigation bar`][(NAME == SELECTION) ? `show` : `hide`](`header`, NAME);
+ });
+
+ // Set the dimensions of the body.
+ Object.keys(PAGES_DIMENSIONS[SELECTION]).forEach((DIMENSION) => {
+ document.body.style[DIMENSION] = PAGES_DIMENSIONS[SELECTION][DIMENSION];
+ });
};
});
}
diff --git a/src/scripts/platform/processor.js b/src/scripts/platform/processor.js
index 2329038..226d6f0 100644
--- a/src/scripts/platform/processor.js
+++ b/src/scripts/platform/processor.js
@@ -13,6 +13,7 @@ import gemini from "/scripts/AI/gemini.js";
export default class processor {
#filter;
#analyzer;
+ status = {};
async scrape (fields, options) {
this.product.details = new scraper (((fields) ? fields : this.targets), options);
@@ -96,12 +97,19 @@ export default class processor {
RUN = true;
} else {
new logging(texts.localized(`AIkey_message_waiting_title`), texts.localized(`AIkey_message_waiting_body`));
- new background(async () => {
- if ((!RUN) ? (await global.read([`settings`,`analysis`,`api`,`key`])) : false) {
- await main();
- RUN = true;
- }
- });
+ if (!this.status.wait) {
+ this.status.background = new background(async () => {
+ this.status.wait = true; // lock the process
+ if ((!RUN) ? (await global.read([`settings`,`analysis`,`api`,`key`])) : false) {
+ await main();
+ RUN = true;
+
+ // Cancel the background process.
+ this.status.background.cancel();
+ this.status.wait = false; // unlock the process
+ }
+ });
+ }
}
}
@@ -155,8 +163,6 @@ export default class processor {
this.product = new product();
this.targets = this.#filter[`data`];
-
- this.status = {};
((((typeof options).includes(`obj`)) ? Object.hasOwn(options, `automatic`) : false) ? options[`automatic`] : true) ? this.run() : false;
}
From 98b01c8380c48ff6ed10219eb088ecf993d2b9ac Mon Sep 17 00:00:00 2001
From: buzz-lightsnack-2007
<73412182+buzz-lightsnack-2007@users.noreply.github.com>
Date: Fri, 24 May 2024 23:58:36 +0800
Subject: [PATCH 16/45] Since filters can be instantiated, rename class as
FilterManager
---
src/scripts/filters.js | 21 ++++++++++-----------
1 file changed, 10 insertions(+), 11 deletions(-)
diff --git a/src/scripts/filters.js b/src/scripts/filters.js
index b175194..2ed9bfb 100644
--- a/src/scripts/filters.js
+++ b/src/scripts/filters.js
@@ -10,13 +10,13 @@ import {Queue} from "/scripts/utils/common.js";
import logging from "/scripts/logging.js"
// const logging = (await import(chrome.runtime.getURL("/scripts/logging.js"))).default;
-export default class filters {
+export default class FilterManager {
constructor() {
this.refresh();
- }
+ };
- /*
- Get all filters.
+ /*
+ Get all filters.
*/
async refresh() {
this.all = await global.read(`filters`);
@@ -34,8 +34,8 @@ export default class filters {
};
if (URL) {
- let SELECTED = await global.search(`filters`, URL, `URL`, 0.5, {"cloud": -1});
-
+ let SELECTED = await global.search(`filters`, URL, [`URL`], {"strictness": 0.5, "cloud": -1});
+
if ((SELECTED && SELECTED != null && (typeof SELECTED).includes(`obj`)) ? (Object.keys(SELECTED)).length : false) {
this.one = (Object.entries(SELECTED))[0][1];
return (this.one);
@@ -54,12 +54,12 @@ export default class filters {
if (location && location != `*`) {
let LOCATIONS = [];
- (Array.isArray(location))
+ (Array.isArray(location))
? location.forEach((LOCATION) => {
URLs.test(LOCATION) ? LOCATIONS.push(LOCATION) : false;
})
: (URLs.test(location)) ? LOCATIONS.push(location) : false;
-
+
(LOCATIONS.length)
? LOCATIONS.forEach((LOCATION) => {
filters.enqueue(LOCATION);
@@ -93,13 +93,13 @@ export default class filters {
if (result) {
// Write the filter to storage.
await global.write(["filters", filter_URL], result, -1, {"silent": true});
-
+
// Add the filter to the sync list.
if ((await global.read(["settings", `filters`])) ? !((Object.keys(await global.read(["settings", `filters`]))).includes(filter_URL)) : true) {
global.write(["settings", `filters`, filter_URL], true, 1, {"silent": true});
};
- // Notify that the update is completed.
+ // Notify that the update is completed.
new logging(texts.localized(`settings_filters_update_status_complete`),filter_URL);
}
})
@@ -131,6 +131,5 @@ export default class filters {
logging.warn(texts.localized(`settings_filters_removal_stop`));
return false;
}
-
}
}
From 88f364137c0eb11a114ffba0273ea72ca9971246 Mon Sep 17 00:00:00 2001
From: buzz-lightsnack-2007
<73412182+buzz-lightsnack-2007@users.noreply.github.com>
Date: Fri, 24 May 2024 23:59:49 +0800
Subject: [PATCH 17/45] rename references of filter class
---
src/scripts/background/check.js | 56 +++++++++++++++++----------------
src/scripts/pages/settings.js | 24 +++++++-------
src/scripts/platform/check.js | 12 +++----
3 files changed, 47 insertions(+), 45 deletions(-)
diff --git a/src/scripts/background/check.js b/src/scripts/background/check.js
index e7a9a4c..8a90503 100644
--- a/src/scripts/background/check.js
+++ b/src/scripts/background/check.js
@@ -5,7 +5,7 @@ Check the tabs in the background, and check the filters.
// Filter importation
import EntryManager from "/scripts/GUI/entrypoints/manager.js"
-import filters from "../filters.js";
+import FilterManager from "../filters.js";
import {background, global} from "/scripts/secretariat.js";
export default class BackgroundCheck {
@@ -19,15 +19,15 @@ export default class BackgroundCheck {
updater() {
global.read([`settings`,`sync`]).then(async (DURATION_PREFERENCES) => {
/*
- Set the default options if they don't exist yet.
+ Set the default options if they don't exist yet.
*/
const setDefaults = async () => {
- // Forcibly create the preference if it doesn't exist. It's required!
+ // Forcibly create the preference if it doesn't exist. It's required!
if (!(typeof DURATION_PREFERENCES).includes(`obj`) || !DURATION_PREFERENCES || Array.isArray(DURATION_PREFERENCES)) {
DURATION_PREFERENCES = {};
DURATION_PREFERENCES[`duration`] = 24;
-
- // Write it.
+
+ // Write it.
return(await global.write([`settings`, `sync`], DURATION_PREFERENCES, -1, {"silent": true}));
} else {return (true)};
};
@@ -35,7 +35,7 @@ export default class BackgroundCheck {
setDefaults().then((result) => {
if (result) {
/*
- Check if it's time to update the filters through comparing the difference of the current time and the last updated time to the expected duration.
+ Check if it's time to update the filters through comparing the difference of the current time and the last updated time to the expected duration.
*/
async function updater_check() {
let TIME = {};
@@ -47,9 +47,9 @@ export default class BackgroundCheck {
};
/*
- Run the update.
+ Run the update.
- @return {Promise} the promise that, once resolved, contains the last update status.
+ @return {Promise} the promise that, once resolved, contains the last update status.
*/
const updater_run = async () => {
filter.update();
@@ -58,60 +58,62 @@ export default class BackgroundCheck {
return(await global.write([`settings`,`sync`,`last`], Date.now(), -1));
};
- // Set the interval.
+ // Set the interval.
let updater_set = () => {
this.update[`checker`] = setInterval(async () => {
- // Update the filters.
+ // Update the filters.
updater_run();
}, DURATION_PREFERENCES[`duration`]);
};
-
+
/*
- Reset the interval.
+ Reset the interval.
*/
const updater_reset = () => {
- // Cancel the interval.
+ // Cancel the interval.
(this.update[`checker`]) ? clearInterval(this.update[`checker`]) : false;
- // Run the updater, if necessary.
+ // Run the updater, if necessary.
(updater_check())
? updater_run()
: false;
-
- // Start the new interval.
+
+ // Start the new interval.
updater_set();
}
-
+
const updater_background = () => {
this.update[`background`] = async () => {
if ((await global.read([`settings`, `sync`, `duration`])) ? (await global.read([`settings`, `sync`, `duration`] * (60 ** 2) * 1000 != DURATION_PREFERENCES[`duration`])) : false) {
- // Get the new time.
- DURATION_PREFERENCES[`duration`] = await global.global.read([`settings`, `sync`, `duration`]) * (60 ** 2) * 1000;
+ if (await global.global.read([`settings`, `sync`, `duration`])) {
+ // Get the new time.
+ DURATION_PREFERENCES[`duration`] = await global.global.read([`settings`, `sync`, `duration`]) * (60 ** 2) * 1000;
- // Reset the updater.
- updater_reset();
+ // Reset the updater.
+ updater_reset();
+ }
};
};
- // Set the background checker.
+ // Set the background checker.
new background(() => {return(this.update.background())});
}
// Convert DURATION_PREFERENCES[`duration`]) from hrs to milliseconds.
DURATION_PREFERENCES[`duration`] = DURATION_PREFERENCES[`duration`] * (60 ** 2) * 1000;
- // Set the filter management.
- let filter = new filters();
-
+ // Set the filter management.
+ let filter = new FilterManager();
+
// When the browser is started, run the updater immediately only when the filters are not updated yet.
(updater_check())
? updater_run()
: false;
- // Run the background.
+ // Run the background.
updater_background();
}
});
})
}
-};
\ No newline at end of file
+};
diff --git a/src/scripts/pages/settings.js b/src/scripts/pages/settings.js
index f6683ae..5455020 100644
--- a/src/scripts/pages/settings.js
+++ b/src/scripts/pages/settings.js
@@ -6,7 +6,7 @@
import {global} from "/scripts/secretariat.js";
import Page from "/scripts/pages/page.js";
import texts from "/scripts/mapping/read.js";
-import filters from "/scripts/filters.js";
+import FilterManager from "/scripts/filters.js";
import logging from "/scripts/logging.js";
import {URLs} from "/scripts/utils/URLs.js";
@@ -25,13 +25,13 @@ class Page_Settings extends Page {
*/
events() {
if ((Object.keys(this.window.elements[`interactive`][`action`])).length) {
- // Instantiate the filters module, since it's needed for some of the actions below.
- this.data.filters = (this.data.filters) ? this.data.filters : new filters();
+ // Instantiate the filters module, since it's needed for some of the actions below.
+ this.data.filters = (this.data.filters) ? this.data.filters : new FilterManager();
- // Bypass the OOBE page since the user opened the settings page.
+ // Bypass the OOBE page since the user opened the settings page.
global.write([`init`], true, 1, {"silent": true});
- // Set the actions.
+ // Set the actions.
let ACTIONS = {};
ACTIONS[`filters,update`] = async () => {this.data.filters.update(`*`);};
ACTIONS[`filters,add,one`] = () => {
@@ -44,7 +44,7 @@ class Page_Settings extends Page {
if (SOURCE ? SOURCE.trim() : false) {
SOURCE = SOURCE.trim().split(`, `);
- // Verify user inputs are valid.
+ // Verify user inputs are valid.
let VALID = true;
// Check if the URL is valid.
@@ -66,18 +66,18 @@ class Page_Settings extends Page {
}
};
ACTIONS[`filters,update,one`] = () => {
- // Update the selected filter.
+ // Update the selected filter.
return((this.window.search.filters.selected) ? this.data.filters.update(this.window.search.filters.selected) : false)
};
ACTIONS[`filters,delete,one`] = () => {
- // Remove the selected filter.
+ // Remove the selected filter.
return((this.window.search.filters.selected) ? this.data.filters.remove(this.window.search.filters.selected) : false)
}
ACTIONS[`storage,clear`] = () => {
return(global.forget(`sites`));
}
-
- // Add the event listeners.
+
+ // Add the event listeners.
(Object.keys(ACTIONS)).forEach((NAME) => {
(this.window.elements[`interactive`][`action`][NAME] ? this.window.elements[`interactive`][`action`][NAME].length : false)
? this.window.elements[`interactive`][`action`][NAME].forEach((ELEMENT) => {
@@ -91,7 +91,7 @@ class Page_Settings extends Page {
(this.window.elements[`linked`][`show`][`settings,general,showApplicable`] ? this.window.elements[`linked`][`show`][`settings,general,showApplicable`].length : false)
? (this.window.elements[`linked`][`show`][`settings,general,showApplicable`]).forEach((ELEMENT) => {
ELEMENT.addEventListener(`change`, () => {
- // The extension icon cache doesn't clear by itself.
+ // The extension icon cache doesn't clear by itself.
ELEMENT.addEventListener(`change`, () => {
!(ELEMENT.checked)
? new logging(texts.localized(`settings_restartToApply`), texts.localized(`settings_restartToApply_iconChange`), true)
@@ -104,4 +104,4 @@ class Page_Settings extends Page {
}
}
-new Page_Settings();
\ No newline at end of file
+new Page_Settings();
diff --git a/src/scripts/platform/check.js b/src/scripts/platform/check.js
index 3f01663..50bac7d 100644
--- a/src/scripts/platform/check.js
+++ b/src/scripts/platform/check.js
@@ -1,19 +1,19 @@
/*
check.js
-Check if a website is supported.
+Check if a website is supported.
*/
-import filters from '/scripts/filters.js';
+import FilterManager from '/scripts/filters.js';
export default class check {
- /*
- Check if an e-commerce platform is supported.
+ /*
+ Check if an e-commerce platform is supported.
@param {string} URL
@returns {object} the support state
*/
static async platform (URL = window.location.href) {
- return (await ((new filters).select(URL)));
+ return (await ((new FilterManager).select(URL)));
}
-}
\ No newline at end of file
+}
From 0d36039ba5caa6179531d68d956896bf4a7d1d00 Mon Sep 17 00:00:00 2001
From: buzz-lightsnack-2007
<73412182+buzz-lightsnack-2007@users.noreply.github.com>
Date: Fri, 24 May 2024 23:59:56 +0800
Subject: [PATCH 18/45] add RegEx tester
---
src/scripts/utils/RegExManager.js | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
create mode 100644 src/scripts/utils/RegExManager.js
diff --git a/src/scripts/utils/RegExManager.js b/src/scripts/utils/RegExManager.js
new file mode 100644
index 0000000..d76c41d
--- /dev/null
+++ b/src/scripts/utils/RegExManager.js
@@ -0,0 +1,26 @@
+/*
+RegEx Manager
+Tests and manages regular expressions
+*/
+
+class RegExManager {
+ /*
+ Tests a regular expression.
+
+ @param {string} expression The regular expression to test.
+ @return {boolean} the state
+ */
+ static test(expression) {
+ let RESULT = {};
+ RESULT[`state`] = false;
+ try {
+ console.log(expression);
+ RESULT[`expression`] = new RegExp(expression);
+ RESULT[`state`] = true;
+ } catch(err) {};
+
+ return (RESULT[`state`]);
+ };
+};
+
+export {RegExManager};
From 0c52ce4d08aefa30d800ab814b8d9dfbd2e2eb2e Mon Sep 17 00:00:00 2001
From: buzz-lightsnack-2007
<73412182+buzz-lightsnack-2007@users.noreply.github.com>
Date: Sat, 25 May 2024 00:00:33 +0800
Subject: [PATCH 19/45] use the ES6 import method for gemini.js
---
src/scripts/AI/gemini.js | 14 ++++++++------
1 file changed, 8 insertions(+), 6 deletions(-)
diff --git a/src/scripts/AI/gemini.js b/src/scripts/AI/gemini.js
index 04a721d..a44c41e 100644
--- a/src/scripts/AI/gemini.js
+++ b/src/scripts/AI/gemini.js
@@ -2,10 +2,10 @@
// Import the file module.
// import file from `./net.js`;
-const texts = (await import(chrome.runtime.getURL("scripts/mapping/read.js"))).default;
+import texts from "/scripts/mapping/read.js";
// Don't forget to set the class as export default.
-export default class gemini {
+class gemini {
#key;
#request;
@@ -65,7 +65,7 @@ export default class gemini {
REQUEST[`contents`] = [];
/*
- Add the blob to a generative part.
+ Add the blob to a generative part.
Function below by Google (https://ai.google.dev/tutorials/get_started_web)
@param {Blob} image the image to add
@@ -80,7 +80,7 @@ export default class gemini {
reader.onloadend = () => resolve(reader.result.split(',')[1]);
reader.readAsDataURL(image[`blob`]);
});
-
+
return {inlineData: { data: image[`base64`], mimeType: image[`type`] }};
};
@@ -98,7 +98,7 @@ export default class gemini {
? PROMPT[REQUEST[`contents`].length][`images`] = [PROMPT[REQUEST[`contents`].length][`images`]]
: false;
- // Add the photos, which are already in the blob format.
+ // Add the photos, which are already in the blob format.
while ((PROMPT[REQUEST[`contents`].length][`images`]) ? (MESSAGE[`parts`].length < PROMPT[REQUEST[`contents`].length][`images`].length) : false) {
let MESSAGE_IMAGE = await fileToGenerativePart(PROMPT[REQUEST[`contents`].length][`images`][MESSAGE[`parts`].length]);
if (MESSAGE_IMAGE) {
@@ -151,7 +151,7 @@ export default class gemini {
let analyze = (RESPONSE_RAW) => {
let RESPONSES = [];
- // Delete previous block state, if any.
+ // Delete previous block state, if any.
delete this.blocked;
while (RESPONSES.length < RESPONSE_RAW[`candidates`].length && !this.blocked) {
@@ -188,3 +188,5 @@ export default class gemini {
return(analyze(this.response));
}
};
+
+export {gemini as default};
From a377d28da83dab899d8db7ae8ca97b5594d6d6ff Mon Sep 17 00:00:00 2001
From: buzz-lightsnack-2007
<73412182+buzz-lightsnack-2007@users.noreply.github.com>
Date: Sat, 25 May 2024 00:01:19 +0800
Subject: [PATCH 20/45] use nested search function for
secretariat.global.search
---
src/scripts/secretariat.js | 231 +++++++++----------------------------
1 file changed, 53 insertions(+), 178 deletions(-)
diff --git a/src/scripts/secretariat.js b/src/scripts/secretariat.js
index 8fee205..c322cd1 100644
--- a/src/scripts/secretariat.js
+++ b/src/scripts/secretariat.js
@@ -12,7 +12,7 @@ Global data storage, which refers to local and synchronized storage
*/
class global {
/* Read all stored data in the browser cache.
-
+
@param {array} name the data name
@param {int} cloud determines cloud reading, which is otherwise set to automatic (0)
@return {object} the data
@@ -31,23 +31,23 @@ class global {
let DATA, DATA_RETURNED;
// Convert the entered prefname to an array if it is not one.
- let NAME = (!Array.isArray(name) && name != null)
+ let NAME = (!Array.isArray(name) && name != null)
? 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 && !(typeof DATA[`sync`]).includes(`undef`)) ? `sync` : `local`;
DATA_RETURNED[`value`] = DATA[DATA_RETURNED[`source`]];
-
- // Override the data with managed data if available.
+
+ // 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`];
@@ -59,7 +59,7 @@ class global {
cloud = (cloud > 0) ? 1 : -1;
DATA = await pull(cloud);
DATA_RETURNED = (NAME) ? nested.dictionary.get(DATA, NAME) : DATA;
-
+
return(DATA_RETURNED);
break;
};
@@ -73,79 +73,13 @@ class global {
@param {object} OPTIONS the options
@return {object} the results
*/
- static async search(SOURCE, TERM, ADDITIONAL_PLACES, STRICT = 0, OPTIONS = {}) {
+ static async search(SOURCE, TERM, ADDITIONAL_PLACES, OPTIONS) {
+ // Set the default options.
+ OPTIONS = Object.assign({}, {"strictness": 0, "criteria": ADDITIONAL_PLACES}, OPTIONS);
+
+ // Initialize the data.
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;
- }
- }
- }
- }
- }
+ let RESULTS = nested.dictionary.search(DATA, TERM, OPTIONS);;
return RESULTS;
};
@@ -167,48 +101,48 @@ class global {
DATA_CHECK[`state`] = await compare([...NAME], DATA);
(!DATA_CHECK[`state`])
- ? logging.error((new texts(`error_msg_save_failed`)).localized, NAME.join(` → `), JSON.stringify(DATA))
+ ? GUI_INFO[`log`] = logging.error((new texts(`error_msg_save_failed`)).localized, NAME.join(` → `), JSON.stringify(DATA))
: ((((typeof OPTIONS).includes(`obj`) && OPTIONS != null) ? (!(!!OPTIONS[`silent`])) : true)
- ? new logging (new texts(`saving_done`).localized)
+ ? GUI_INFO[`log`] = new logging (new texts(`saving_done`).localized)
: false);
-
+
return (DATA_CHECK[`state`]);
}
- let DATA_ALL;
+ let DATA_ALL, GUI_INFO = {};
// Inform the user that saving is in progress.
if (((typeof OPTIONS).includes(`obj`) && OPTIONS != null) ? (!(!!OPTIONS[`silent`])) : true) {
- let LOG = new logging ((new texts(`saving_current`)).localized, (new texts(`saving_current_message`)).localized, false)
+ GUI_INFO[`log`] = new logging ((new texts(`saving_current`)).localized, (new texts(`saving_current_message`)).localized, false)
};
- // Get all data and set a blank value if it doesn't exist yet.
+ // 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 && DATA_ALL != undefined && (typeof DATA_ALL).includes(`obj`)) ? Object.keys(DATA_ALL).length <= 0 : true)
+ DATA_ALL = ((DATA_ALL != null && DATA_ALL != undefined && (typeof DATA_ALL).includes(`obj`)) ? Object.keys(DATA_ALL).length <= 0 : true)
? {}
: DATA_ALL;
- // Set the data name.
+ // Set the data name.
let DATA_NAME = (!(Array.isArray(path)) && path && path != undefined)
? String(path).trim().split(",")
- : ((path != null) ? path : []) // Ensure that path isn't empty.
+ : ((path != null) ? path : []) // Ensure that path isn't empty.
// Merge!
DATA_INJECTED = nested.dictionary.set(DATA_ALL, (DATA_NAME != null) ? [...DATA_NAME] : DATA_NAME, data, OPTIONS);
- // If cloud is not selected, get where the data is already existent.
+ // 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);
- (typeof LOG).includes(`undef`) ? false : LOG.clear();
+ GUI_INFO[`log`] ? GUI_INFO[`log`].clear() : false;
return ((OPTIONS[`verify`] != null ? (OPTIONS[`verify`]) : true) ? verify(DATA_NAME, data) : true);
}
/*
- Removes a particular data.
+ Removes a particular data.
@param {string} preference the preference name to delete
@param {string} subpreference the subpreference name to delete
@@ -222,7 +156,7 @@ class global {
if (CONFIRMATION) {
if (preference) {
/*
- Erase applicable storage from a provider.
+ Erase applicable storage from a provider.
@param {string} name the name of the data
@param {int} cloud the usage of cloud storage
@@ -235,28 +169,28 @@ class global {
@param {int} cloud the usage of cloud storage
*/
function secure(name, cloud) {
- let PATH = name;
- // Check if the value already exists.
+ let PATH = name;
+ // Check if the value already exists.
return(global.read([...PATH], cloud).then(async (DATA) => {
return((DATA != null)
- // Then erase the data.
+ // Then erase the data.
? await global.write(PATH, null, cloud, {"strict": true, "verify": false})
: true);
}));
};
-
+
/*
- Remove the key from existence.
+ Remove the key from existence.
@param {string} name the name of the data
@param {int} cloud the usage of cloud storage
*/
async function eliminate(name, cloud) {
- // Store the variable seperately to avoid overwriting.
+ // Store the variable seperately to avoid overwriting.
let PATH = name;
- // There are two methods to erase the data.
- // The first only occurs when the root is selected and the path is just a direct descendant.
+ // There are two methods to erase the data.
+ // The first only occurs when the root is selected and the path is just a direct descendant.
if (PATH.length == 1) {
chrome.storage[(cloud > 0) ? `sync` : `local`].remove(PATH[0]);
} else {
@@ -266,7 +200,7 @@ class global {
if ((((typeof (DATA[`all`])).includes(`obj`) && !Array.isArray(DATA[`all`]) && DATA[`all`] != null) ? Object.keys(DATA[`all`]) : false) ? Object.hasOwn(DATA[`all`], PATH[PATH.length - 1]) : false) {
DATA[`modified`] = DATA[`all`];
-
+
delete DATA[`modified`][PATH[PATH.length - 1]];
return(global.write(((PATH && Array.isArray(PATH)) ? (PATH.slice(0,-1)) : null), DATA[`modified`], cloud, {"strict": true}));
@@ -274,13 +208,13 @@ class global {
});
}
-
+
};
- // Set the data path.
+ // Set the data path.
let DATA_NAME = (!(Array.isArray(path)) && path && path != undefined)
? String(path).trim().split(",")
- : ((path != null) ? path : []) // Ensure that path isn't empty.
+ : ((path != null) ? path : []) // Ensure that path isn't empty.
await secure([...DATA_NAME], cloud);
eliminate([...DATA_NAME], cloud);
@@ -297,66 +231,7 @@ class global {
return CONFIRMATION;
}
-}
-
-class session {
- /*
- Recall session storage data.
-
- @param {string} path the path to the data
- @return {object} the data
- */
- static async read(path) {
- // Change PATH to array if it isn't.
- let PATH = (!(Array.isArray(path)) && path && path != undefined)
- ? String(path).trim().split(",")
- : ((path != null) ? path : []);
-
- // Prepare data.
- let DATA = {};
- DATA[`all`] = await chrome.storage.session.get(null);
- (DATA[`all`]) ? DATA[`selected`] = nested.dictionary.get(DATA[`all`], [...PATH]) : false;
-
- return (DATA[`selected`]);
- }
-
- /*
- Write the data to a specified path.
-
- @param {string} PATH the path to the data
- @param {object} DATA the data to be written
- */
- static async write(PATH, DATA) {
- async function verify (NAME, DATA) {
- let DATA_CHECK = {};
-
- // Verify the presence of the data.
- DATA_CHECK[`state`] = await compare(null, [await session.read([...NAME]), DATA]);
-
- // Only notify when writing failed.
- (!DATA_CHECK[`state`])
- ? logging.error((new texts(`error_msg_save_failed`)).localized, NAME.join(` → `), JSON.stringify(DATA))
- : true;
-
- return (DATA_CHECK[`state`]);
- }
-
- DATA = {"write": DATA};
- DATA[`all`] = await session.read(null);
- ((DATA[`all`] != null && (typeof DATA[`all`]).includes(`obj`)) ? Object.keys(DATA[`all`]).length <= 0 : true)
- ? DATA[`all`] = {}
- : false;
-
- let TARGET = (!(typeof PATH).includes(`obj`)) ? String(PATH).trim().split(",") : PATH;
-
- // Merge!
- DATA[`inject`] = nested.dictionary.set(DATA[`all`], [...TARGET], DATA[`write`]);
-
- // Write!
- chrome.storage.session.set(DATA[`inject`]);
- return(await verify(TARGET, DATA[`write`]));
- }
-}
+};
/*
Compare a data against the stored data. Useful when comparing dictionaries.
@@ -394,7 +269,7 @@ export async function compare(PATH, DATA) {
class template {
/* Initialize the storage.
-
+
@param {dictionary} data this build's managed data
*/
static set(data) {
@@ -403,16 +278,16 @@ class template {
((typeof data).includes(`obj`) && data != null) ? PREFERENCES[`all`][`build`] = data : false;
- // Read all data.
+ // Read all data.
[`managed`, `local`, `sync`].forEach((SOURCE) => {
chrome.storage[SOURCE].get(null, (DATA) => {
PREFERENCES[`all`][SOURCE] = DATA;
})
});
- // Merge the data.
+ // Merge the data.
// Managed > Synchronized > Imported > Local
- // Set managed preferences.
+ // Set managed preferences.
managed.reinforce();
// Import build data
@@ -453,7 +328,7 @@ managed data functions
*/
class managed {
/*
- Reinforce managed data.
+ Reinforce managed data.
*/
static reinforce() {
chrome.storage.managed.get(null, (DATA_MANAGED) => {
@@ -465,7 +340,7 @@ class managed {
}
/*
- Read for any applicable managed data.
+ Read for any applicable managed data.
@param {string} name the name of the data
@return {boolean} the result
@@ -499,7 +374,7 @@ class managed {
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`]);
}
}
@@ -509,13 +384,13 @@ Background data execution
*/
class background {
/*
- Add or prepare a listener.
+ Add or prepare a listener.
@param {function} callback the function to run
@param {object} options the options
*/
constructor (callback, options) {
- // Set the listener.
+ // Set the listener.
this.callback = callback;
// Run the listener if necessary.
@@ -523,7 +398,7 @@ class background {
};
/*
- Set the listener.
+ Set the listener.
*/
run () {
return(chrome.storage.onChanged.addListener((changes, namespace) => {
@@ -532,10 +407,10 @@ class background {
};
/*
- Cancel the listener.
+ Cancel the listener.
*/
cancel () {
- // Cancel the listener.
+ // Cancel the listener.
return(chrome.storage.onChanged.removeListener((changes, namespace) => {
this.callback({"changes": changes, "namespace": namespace});
}))
@@ -553,4 +428,4 @@ export function observe(callback) {
}));
}
-export {global, session, template, managed, background};
+export {global, template, managed, background};
From eedd53aba41fb7599e32d3bcc24866d102f0d95c Mon Sep 17 00:00:00 2001
From: buzz-lightsnack-2007
<73412182+buzz-lightsnack-2007@users.noreply.github.com>
Date: Sat, 25 May 2024 00:01:58 +0800
Subject: [PATCH 21/45] add specific message for failure to convert to JSON
---
src/scripts/utils/net.js | 22 +++++++++++-----------
1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/src/scripts/utils/net.js b/src/scripts/utils/net.js
index f44aa90..a0d6f46 100644
--- a/src/scripts/utils/net.js
+++ b/src/scripts/utils/net.js
@@ -8,7 +8,7 @@ import logging from "/scripts/logging.js";
export default class net {
/*
Download a file from the network or locally.
-
+
@param {string} URL the URL to download
@param {string} TYPE the expected TYPE of file
@param {boolean} VERIFY_ONLY whether to verify the file only, not return its content
@@ -17,21 +17,21 @@ export default class net {
*/
static async download(URL, TYPE, VERIFY_ONLY = false, STRICT = false) {
let CONNECT, DATA;
- let HEADERS = {};
-
- // If TYPE is used as headers, then the other parts of the header should be taken out for later usage.
+ let HEADERS = {};
+
+ // If TYPE is used as headers, then the other parts of the header should be taken out for later usage.
if (TYPE && (typeof TYPE).includes(`obj`)) {
HEADERS = TYPE;
TYPE = HEADERS[`Content-Type`];
}
-
+
try {
- // Fetch the file. Add headers when defined.
+ // Fetch the file. Add headers when defined.
(Object.keys(HEADERS).length) ? CONNECT = await fetch(URL, {method: `POST`, headers: HEADERS}) : CONNECT = await fetch(URL);
-
+
if (CONNECT.ok && !VERIFY_ONLY) {
DATA = await CONNECT[(TYPE.toLowerCase().includes('blob')) ? `blob` : `text`]();
-
+
if (TYPE
? (TYPE.toLowerCase().includes(`json`) || TYPE.toLowerCase().includes(`dictionary`))
: false) {
@@ -40,9 +40,9 @@ export default class net {
} catch(err) {
// When not in JSON, run this.
if (STRICT) {
- // Should not allow the data to be returned since it's not correct.
+ // Should not allow the data to be returned since it's not correct.
DATA = null;
- throw new TypeError(texts.localized(`error_msg_notJSON`, false));
+ throw err;
} else {
logging.warn(texts.localized(`error_msg_notJSON`, false));
}
@@ -54,7 +54,7 @@ export default class net {
} catch(err) {
throw err;
}
-
+
// Return the filter.
return VERIFY_ONLY ? CONNECT.ok : DATA;
}
From 3e2723d58b83dbdbf7aec8383b27ed34bb14cd63 Mon Sep 17 00:00:00 2001
From: buzz-lightsnack-2007
<73412182+buzz-lightsnack-2007@users.noreply.github.com>
Date: Sat, 25 May 2024 09:15:06 +0800
Subject: [PATCH 22/45] auto-refresh data when updated
Should be evident when the name of the filter has been changed
---
src/scripts/GUI/builder/search.js | 230 ++++++++++++++++--------------
1 file changed, 120 insertions(+), 110 deletions(-)
diff --git a/src/scripts/GUI/builder/search.js b/src/scripts/GUI/builder/search.js
index 88948db..e337f76 100644
--- a/src/scripts/GUI/builder/search.js
+++ b/src/scripts/GUI/builder/search.js
@@ -15,57 +15,57 @@ class Search {
};
/*
- Include all relevant DOM elements into this object.
+ Include all relevant DOM elements into this object.
*/
#get() {
document.querySelectorAll(`[data-result]`).forEach((ELEMENT) => {
let SOURCE = ELEMENT.getAttribute(`data-result`);
-
+
if (SOURCE != `state`) {
this[SOURCE] = (!this[SOURCE])
? {}
: this[SOURCE];
-
+
const elements = () => {
this[SOURCE][`elements`] = (this[SOURCE][`elements`]) ? this[SOURCE][`elements`] : {};
-
- // First, add the search box.
+
+ // First, add the search box.
this[SOURCE][`elements`][`search box`] = (this[SOURCE][`elements`][`search box`])
? this[SOURCE][`elements`][`search box`].push(ELEMENT)
- : [ELEMENT];
-
+ : [ELEMENT];
+
let SOURCES = {
"results list": `[data-results-list="${SOURCE}"]`,
"container": `[data-result-linked="${SOURCE}"]`,
"enable": `[data-result-enable]`
};
-
+
const linked = () => {
let LINKED_SOURCES = {
"content": "data-result-content",
"fields": "data-result-store"
};
-
+
(Object.keys(LINKED_SOURCES)).forEach((COMPONENT) => {
(document.querySelector(SOURCES[`container`].concat(` [`, LINKED_SOURCES[COMPONENT], `]`)))
? (document.querySelectorAll(SOURCES[`container`].concat(` [`, LINKED_SOURCES[COMPONENT], `]`))).forEach((ELEMENT) => {
this[SOURCE][`elements`][COMPONENT] = (this[SOURCE][`elements`][COMPONENT] && !(Array.isArray(this[SOURCE][`elements`][COMPONENT])) && (typeof this[SOURCE][`elements`][COMPONENT]).includes(`obj`)) ? this[SOURCE][`elements`][COMPONENT] : {};
-
- // Get the name of the element.
+
+ // Get the name of the element.
let NAME = ELEMENT.getAttribute(LINKED_SOURCES[COMPONENT]);
(ELEMENT.getAttribute(`data-store-location`))
? ELEMENT[`data store location`] = ELEMENT.getAttribute(`data-store-location`)
: false;
- // Set the element.
+ // Set the element.
this[SOURCE][`elements`][COMPONENT][NAME] = (this[SOURCE][`elements`][COMPONENT][NAME] ? this[SOURCE][`elements`][COMPONENT][NAME].length : false)
? (this[SOURCE][`elements`][COMPONENT][NAME].includes(ELEMENT)
? false
: [...this[SOURCE][`elements`][COMPONENT][NAME], ELEMENT])
: [ELEMENT];
-
-
- // Remove the attribute.
+
+
+ // Remove the attribute.
[LINKED_SOURCES[COMPONENT], `data-store-location`].forEach((ATTRIBUTE) => {
ELEMENT.removeAttribute(ATTRIBUTE);
})
@@ -73,7 +73,7 @@ class Search {
: false;
})
}
-
+
if (SOURCES ? Object.keys(SOURCES) : false) {
(Object.keys(SOURCES)).forEach((COMPONENT) => {
(document.querySelector(SOURCES[COMPONENT]))
@@ -83,23 +83,23 @@ class Search {
linked();
}
}
-
- // Get relevant data.
+
+ // Get relevant data.
const attributes = () => {
- // Accumulate all search criteria where possible.
+ // Accumulate all search criteria where possible.
(ELEMENT.hasAttribute(`data-results-filters`))
? this[SOURCE][`additional criteria`] = (this[SOURCE][`additional criteria`]) ? [...this[SOURCE][`additional criteria`], ...ELEMENT.getAttribute(`data-results-filters`).split(`,`)] : ELEMENT.getAttribute(`data-results-filters`).split(`,`)
: false;
(ELEMENT.hasAttribute(`data-show`))
? this[SOURCE][`preview`] = ELEMENT.getAttribute(`data-show`)
: false;
-
- // Remove attributes only used during construction, simultaneously protecting against edited HTML from the debugger.
+
+ // Remove attributes only used during construction, simultaneously protecting against edited HTML from the debugger.
[`data-result`, `data-results-filters`, `data-show`].forEach((ATTRIBUTE) => {
ELEMENT.removeAttribute(ATTRIBUTE);
});
}
-
+
elements();
attributes();
}
@@ -108,7 +108,7 @@ class Search {
};
/*
- Set the functions of the relevant elements.
+ Set the functions of the relevant elements.
*/
#set() {
(Object.keys(this)).forEach((SOURCE) => {
@@ -117,9 +117,9 @@ class Search {
ELEMENT.addEventListener(`change`, () => {this.run({"name": SOURCE, "element": ELEMENT}, null, {"auto sync": true});});
});
- // Set the state.
+ // Set the state.
this[SOURCE][`scripts`] = {"background": {}};
-
+
// Find the data.
this.run({"name": SOURCE}, `*`, {"auto sync": true});
this.pick(SOURCE, null);
@@ -128,7 +128,7 @@ class Search {
};
/*
- Run a search.
+ Run a search.
@param {object} source the source data
@param {object} data the data to find for
@@ -148,13 +148,15 @@ class Search {
show().then(() => {
if (((typeof options).includes(`obj`) && options) ? options[`auto sync`] : false) {
// Set the refresh function.
- let item = this[source[`name`]][`selected`];
+ let EXISTING_DATA = {};
+ EXISTING_DATA[`item`] = this[source[`name`]][`selected`];
+ EXISTING_DATA[`criteria`] = this[source[`name`]][`criteria`];
this[source[`name`]][`scripts`][`refresh`] = () => {
wait((this[`state`][`read/write`] ? this[`state`][`read/write`] >= 0 : true)).then(
() => {
- if (this[source][`selected`] == item) {
- show()
+ if (this[source[`name`]][`selected`] == EXISTING_DATA[`item`] || EXISTING_DATA[`criteria`] == this[source[`name`]][`criteria`]) {
+ show();
} else if (this[source[`name`]][`scripts`][`background`][`refresh`]) {
this[source[`name`]][`scripts`][`background`][`refresh`].cancel();
};
@@ -162,7 +164,7 @@ class Search {
);
};
- this[source[`name`]][`scripts`][`background`][`refresh`] = new background(() => {this[source[`name`]][`scripts`][`refresh`]});
+ this[source[`name`]][`scripts`][`background`][`refresh`] = new background(() => {this[source[`name`]][`scripts`][`refresh`]()});
};
}).catch((err) => {
logging.error(err);
@@ -170,7 +172,7 @@ class Search {
};
/*
- Find the data.
+ Find the data.
@param {object} source the source data
@param {string} data the data to find for
@@ -181,15 +183,15 @@ class Search {
? source = {"name": source}
: false;
- // Set the primary search criteria.
+ // Set the primary search criteria.
if (data && data != `*`) {
- // Having data filled means an override.
+ // Having data filled means an override.
this[source[`name`]][`criteria`] = ((typeof data).includes(`str`)) ? data.trim() : data;
} else if ((source[`element`]) ? source[`element`].value.trim() : false) {
- // There is an element to use.
+ // There is an element to use.
this[source[`name`]][`criteria`] = source[`element`].value.trim();
} else if (this[source[`name`]][`elements`][`search box`] ? this[source[`name`]][`elements`][`search box`].length : false) {
- // No element defined, look for every box.
+ // No element defined, look for every box.
(this[source[`name`]][`elements`][`search box`]).forEach((ELEMENT) => {
this[source[`name`]][`criteria`] = (ELEMENT.type.includes(`num`) || ELEMENT.type.includes(`range`))
? ((parseFloat(ELEMENT.value.trim()) != parseInt(ELEMENT.value.trim()))
@@ -203,19 +205,19 @@ class Search {
this[source[`name`]][`criteria`] = null;
};
- // Find.
+ // Find.
this[source[`name`]][`results`] = await ((this[source[`name`]][`criteria`] != null)
? ((this[source[`name`]][`additional criteria`] ? this[source[`name`]][`additional criteria`].length : false)
? global.search(source[`name`], this[source[`name`]][`criteria`], this[source[`name`]][`additional criteria`])
: global.search(source[`name`], this[source[`name`]][`criteria`]))
: global.read(source[`name`]));
- // Return the data.
+ // Return the data.
return (this[source[`name`]][`results`]);
}
/*
- Display the search results.
+ Display the search results.
@param {string} source the source data
@param {object} data the data to display
@@ -225,43 +227,43 @@ class Search {
if (source ? (Array.isArray(source) ? source.length : String(source)) : false) {
source = (Array.isArray(source)) ? source.join(`,`) : String(source);
- // Get the data.
+ // Get the data.
data = (data && ((typeof data).includes(`obj`))) ? data : this[source][`results`];
const gui_output = () => {
- // Prepare the elements we will need.
+ // Prepare the elements we will need.
if (this[source][`elements`][`results list`] ? this[source][`elements`][`results list`].length : false) {
- const design = () => {
- // Prepare the access keys.
- let ACCESS_KEYS = {"top": ["1", "2", "3", "4", "5", "6", "7", "8", "9"], "nav": ["<", ">"]};
-
- /*
- Add the selected state.
- */
- const select = (element) => {
- if (element) {
- // Remove all active classes.
- (element.parentElement).parentElement.querySelectorAll(`li`).forEach((ELEMENT) => {
- ELEMENT.classList.remove(`active`);
- });
-
- // Add the active.
- element.parentElement.classList.add(`active`);
-
- return (element);
- };
+ /*
+ Add the selected state.
+ */
+ const select = (element) => {
+ if (element) {
+ // Remove all active classes.
+ (element).parentElement.querySelectorAll(`li:has(a)`).forEach((ELEMENT) => {
+ ELEMENT.classList.remove(`active`);
+ });
+
+ // Add the active.
+ element.classList.add(`active`);
+
+ return (element);
};
-
+ };
+
+ const design = () => {
+ // Prepare the access keys.
+ let ACCESS_KEYS = {"top": ["1", "2", "3", "4", "5", "6", "7", "8", "9"], "nav": ["<", ">"]};
+
/*
- Add the access keys (shortcut).
-
+ Add the access keys (shortcut).
+
@param {string} name the name of the element
@param {object} ELEMENT the element to add the access key to
@param {object} state the current state of the element
*/
const shortcut = (name, element, state) => {
let RESULT_INDEX = (Object.keys(data)).indexOf(name);
-
+
if (RESULT_INDEX >= 0) {
if (state.includes(`config`)) {
((RESULT_INDEX < ACCESS_KEYS[`top`].length) && (RESULT_INDEX >= 0))
@@ -272,54 +274,57 @@ class Search {
} else if (state.includes(`execute`)) {
let ELEMENT = {"selected": element};
ELEMENT[`neighbors`] = (ELEMENT[`selected`].parentElement.parentElement).querySelectorAll(`a`);
-
- // Remove elements with accesskeys in nav.
+
+ // Remove elements with accesskeys in nav.
(ELEMENT[`neighbors`]).forEach((OTHER) => {
(OTHER.getAttribute(`accesskey`) ? (ACCESS_KEYS[`nav`].includes(OTHER.getAttribute(`accesskey`))) : false)
? OTHER.removeAttribute(`accesskey`)
: false;
})
-
+
if ((RESULT_INDEX + 1 >= ACCESS_KEYS[`top`].length) && (RESULT_INDEX + 1 < ELEMENT[`neighbors`].length)) {
ELEMENT[`neighbors`][RESULT_INDEX + 1].setAttribute(`accesskey`, ACCESS_KEYS[`nav`][1])
}
-
+
(RESULT_INDEX > ACCESS_KEYS[`top`].length)
? (ELEMENT[`neighbors`])[RESULT_INDEX - 1].setAttribute(`accesskey`, ACCESS_KEYS[`nav`][0])
: false;
-
+
(RESULT_INDEX >= ACCESS_KEYS[`top`].length)
? ELEMENT[`selected`].setAttribute(`accesskey`, `0`)
: false;
-
+
return (ELEMENT);
}
}
}
-
+
let ELEMENTS = [];
-
+
(data ? Object.keys(data).length : false)
? (Object.keys(data)).forEach((RESULT) => {
let ELEMENTS_RESULT = {}
ELEMENTS_RESULT[`container`] = document.createElement(`li`);
ELEMENTS_RESULT[`title`] = document.createElement(`a`);
-
- // Add the classes.
+
+ // Add the classes.
ELEMENTS_RESULT[`title`].classList.add(`waves-effect`);
ELEMENTS_RESULT[`title`].textContent = String((title && data[RESULT][title]) ? data[RESULT][title] : RESULT);
-
- // Add the action.
+
+ // Add the action.
ELEMENTS_RESULT[`title`].addEventListener(`click`, () => {
- // Set the visual state.
- select(ELEMENTS_RESULT[`title`]);
+ // Set the visual state.
+ select(ELEMENTS_RESULT[`container`]);
shortcut(RESULT, ELEMENTS_RESULT[`title`], `execute`);
-
+
// Pick the data.
this.pick(source, RESULT, data[RESULT]);
});
-
- // Add the shortcut.
+
+ // Add the real linked data name temporarily.
+ ELEMENTS_RESULT[`container`][`linked`] = RESULT;
+
+ // Add the shortcut.
ELEMENTS_RESULT[`title`] = shortcut(RESULT, ELEMENTS_RESULT[`title`], `config`);
// Add the elements to the container.
@@ -327,10 +332,10 @@ class Search {
ELEMENTS.push(ELEMENTS_RESULT[`container`]);
})
: false;
-
+
return (ELEMENTS);
}
-
+
let TEMPLATE = design();
(this[source][`elements`][`results list`]).forEach((ELEMENT_TARGET) => {
// Clear the target element.
@@ -338,6 +343,11 @@ class Search {
(TEMPLATE.length)
? TEMPLATE.forEach((ELEMENT) => {
ELEMENT_TARGET.appendChild(ELEMENT);
+
+ // Preselect the item.
+ if (ELEMENT[`linked`] == nested.dictionary.get(this, [source, `selected`])) {
+ select(ELEMENT);
+ };
})
: this.pick(source, null);
})
@@ -345,7 +355,7 @@ class Search {
}
/*
- Display the search results in the log.
+ Display the search results in the log.
*/
function log (data, title) {
if (Object.keys(data).length) {
@@ -373,7 +383,7 @@ class Search {
@param {string} details the details of the selected item
*/
pick(source, item, details) {
- // Fill in the details if it's missing when the item and source isn't.
+ // Fill in the details if it's missing when the item and source isn't.
if (!details && (source && item)) {
(Object.hasOwn(this[source][`results`], item))
? details = this[source][`results`][item]
@@ -382,7 +392,7 @@ class Search {
const set = () => {
this[source][`selected`] = item;
-
+
// Set the background state.
nested.dictionary.get(this, [source, `scripts`, `background`, `selected`])
? this[source][`scripts`][`background`][`selected`].cancel()
@@ -391,8 +401,8 @@ class Search {
this[source][`scripts`][`reader`] = wait((this[`state`][`read/write`] ? this[`state`][`read/write`] >= 0 : true)).then(
() => {(this[source][`selected`] == item) ? gui_display() : false;}
);
-
- // Reset the background.
+
+ // Reset the background.
this[source][`scripts`][`background`][`selected`] = new background(() => {this[source][`scripts`][`reader`]});
}
}
@@ -433,10 +443,10 @@ class Search {
case `radio`:
ELEMENT.checked = false;
break;
- default:
+ default:
ELEMENT.value = ``;
};
-
+
if ((ELEMENT.nodeName.toLowerCase()).includes(`input`) || (ELEMENT.nodeName.toLowerCase()).includes(`textarea`)) {
// Check if the element has an event listener and remove it.
(ELEMENT.func)
@@ -464,46 +474,46 @@ class Search {
: ((typeof item).includes(`str`)
? item.trim()
: item);
-
+
this[source][`elements`][ELEMENTS][SOURCE].forEach((ELEMENT) => {
if ((ELEMENT.nodeName.toLowerCase()).includes(`input`) || (ELEMENT.nodeName.toLowerCase()).includes(`textarea`) || (ELEMENT.nodeName.toLowerCase()).includes(`progress`)) {
-
+
switch (ELEMENT.type) {
case `checkbox`:
case `radio`:
ELEMENT.checked = (DATA[`value`]);
break;
- default:
+ default:
ELEMENT.value = DATA[`value`];
};
-
+
if ((DATA[`source`] != `*`) && (ELEMENT.nodeName.toLowerCase()).includes(`input`) || (ELEMENT.nodeName.toLowerCase()).includes(`textarea`)) {
- // Remove the existing function.
+ // Remove the existing function.
(ELEMENT.func)
? [`change`, `blur`].forEach((EVENT) => {
ELEMENT.removeEventListener(EVENT, ELEMENT.func)
})
: false;
-
- // Add the new function.
+
+ // Add the new function.
ELEMENT.func = () => {};
switch (ELEMENT.type) {
case `checkbox`:
case `radio`:
ELEMENT.func = () => {
- this[`state`][`read/write`] = -1;
+ this[`state`][`read/write`] = -1;
this[`state`][`last result`] = global.write(DATA[`target`], ELEMENT.checked, (ELEMENT[`data store location`] ? ELEMENT[`data store location`] : -1));
- this[`state`][`read/write`] = 0;
- return(this[`state`][`last result`]);
+ this[`state`][`read/write`] = 0;
+ return(this[`state`][`last result`]);
};
-
+
ELEMENT.checked = (DATA[`value`]);
break;
- default:
+ default:
if ((typeof DATA[`value`]).includes(`obj`) && !Array.isArray(DATA[`value`])) {
ELEMENT.value = JSON.stringify(DATA[`value`]);
-
+
ELEMENT.func = () => {
this[`state`][`read/write`] = -1;
this[`state`][`last result`] = false;
@@ -520,7 +530,7 @@ class Search {
}
} else {
ELEMENT.value = DATA[`value`];
-
+
ELEMENT.func = () => {
this[`state`][`read/write`] = -1;
@@ -530,20 +540,20 @@ class Search {
: parseInt(ELEMENT.value.trim())
)
: ELEMENT.value.trim());
-
+
this[`state`][`last result`] = global.write(DATA[`target`], ELEMENT.val, (ELEMENT[`data store location`] ? ELEMENT[`data store location`] : -1));
this[`state`][`read/write`] = 0;
-
+
delete ELEMENT.val;
return (this[`state`][`last result`]);
}
};
};
-
+
(ELEMENT.nodeName.toLowerCase().includes(`textarea`))
? ELEMENT.addEventListener(`blur`, ELEMENT.func)
: false;
-
+
ELEMENT.addEventListener(`change`, ELEMENT.func);
}
} else {
@@ -551,7 +561,7 @@ class Search {
};
})
}
-
+
}
})
: false;
@@ -559,7 +569,7 @@ class Search {
}
enable();
- fill();
+ fill();
}
@@ -576,4 +586,4 @@ class Search {
}
};
-export { Search };
\ No newline at end of file
+export { Search };
From 98ea6ede65b550b23c339895156bf75f0083a975 Mon Sep 17 00:00:00 2001
From: buzz-lightsnack-2007
<73412182+buzz-lightsnack-2007@users.noreply.github.com>
Date: Sat, 25 May 2024 09:34:10 +0800
Subject: [PATCH 23/45] add nested dictionary search
---
src/scripts/utils/nested.js | 84 ++++++++++++++++++++++++++++++++++---
1 file changed, 79 insertions(+), 5 deletions(-)
diff --git a/src/scripts/utils/nested.js b/src/scripts/utils/nested.js
index 62d6e77..03508f3 100644
--- a/src/scripts/utils/nested.js
+++ b/src/scripts/utils/nested.js
@@ -1,7 +1,8 @@
-class nested {}
+import { RegExManager } from "./RegExManager.js";
+class nested {}
nested.dictionary = class dictionary {
- /*
+ /*
Get the data from the dictionary.
@param {object} data the data to be used
@@ -11,7 +12,7 @@ nested.dictionary = class dictionary {
static get(data, path) {
let DATA = data;
- // Set the path.
+ // Set the path.
let PATH = {};
PATH[`all`] = (Array.isArray(path))
? path
@@ -70,6 +71,79 @@ nested.dictionary = class dictionary {
// Return the value.
return (DATA);
}
-}
-export {nested as default};
\ No newline at end of file
+ /* More enhanced searching.
+
+ @param {object} data the data
+ @param {string} value the value to search
+ @param {object} options the options
+ @return {object} the results
+ */
+ static search(data, value, options) {
+ // Set the default options.
+ let OPTIONS = Object.assign({}, {"strictness": 0}, options);
+ let DATA = data;
+ let TERM = value;
+ let RESULTS;
+
+ if (data && ((typeof data).includes(`obj`) && !Array.isArray(data))) {
+ if (!TERM || ((typeof TERM).includes(`str`) ? !TERM.trim() : false)) {
+ RESULTS = data;
+ } else {
+ RESULTS = {};
+
+ // Sequentially search through the data, first by key.
+ if (OPTIONS[`mode`] != `criteria`) {
+ (Object.keys(DATA)).forEach((DATA_NAME) => {
+ if (OPTIONS[`strictness`] > 1 ? DATA_NAME == TERM : (DATA_NAME.includes(TERM) || TERM.includes(DATA_NAME))) {
+ RESULTS[DATA_NAME] = DATA[DATA_NAME];
+ }
+ });
+ };
+
+ // Get the additional criteria.
+ if ((OPTIONS[`mode`] != `root`) && OPTIONS[`criteria`]) {
+ let ADDITIONAL_PLACES = (!Array.isArray(OPTIONS[`criteria`])) ? OPTIONS[`criteria`].split(`,`) : OPTIONS[`criteria`];
+
+ // Search through the data.
+ if (ADDITIONAL_PLACES) {
+ // Perform a sequential search on the additional criteria.
+ ADDITIONAL_PLACES.forEach((ADDITIONAL_PLACE) => {
+ Object.keys(DATA).forEach((DATA_NAME) => {
+ let VALUE = {};
+ VALUE[`parent`] = DATA[DATA_NAME];
+
+ if (VALUE[`parent`] ? (typeof (VALUE[`parent`])).includes(`obj`) : false) {
+ VALUE[`current`] = nested.dictionary.get(VALUE[`parent`], ADDITIONAL_PLACE);
+
+ console.log(RegExManager.test(VALUE[`current`]) ? (new RegExp(VALUE[`current`])).test(TERM) : `not`);
+
+ if (VALUE[`current`]
+ ? ((OPTIONS[`strictness`] >= 1)
+ ? VALUE[`current`] == TERM
+ : (
+ ((OPTIONS[`strictness`] < 0.5)
+ ? (VALUE[`current`].includes(TERM))
+ : false)
+ || TERM.includes(VALUE[`current`])
+ || (RegExManager.test(VALUE[`current`])
+ ? (new RegExp(VALUE[`current`])).test(TERM)
+ : false)))
+ : false) {
+ RESULTS[DATA_NAME] = DATA[DATA_NAME];
+ };
+ };
+ })
+ })
+ };
+ };
+ };
+
+ };
+
+ // Return the results.
+ return RESULTS;
+ };
+};
+
+export {nested as default};
From b47a641b88dadfa183d8362bdf3c98955cd049fc Mon Sep 17 00:00:00 2001
From: buzz-lightsnack-2007
<73412182+buzz-lightsnack-2007@users.noreply.github.com>
Date: Sat, 25 May 2024 09:36:03 +0800
Subject: [PATCH 24/45] remove role="primary"
It looks annoying
---
src/pages/settings.htm | 4 ++--
src/styles/colors/all.forms.css | 7 +------
2 files changed, 3 insertions(+), 8 deletions(-)
diff --git a/src/pages/settings.htm b/src/pages/settings.htm
index 0eb2611..dc0bfb8 100644
--- a/src/pages/settings.htm
+++ b/src/pages/settings.htm
@@ -1,7 +1,7 @@
-
+
@@ -51,7 +51,7 @@
-
+