aboutsummaryrefslogtreecommitdiff
path: root/html/display-panel.js
diff options
context:
space:
mode:
Diffstat (limited to 'html/display-panel.js')
-rw-r--r--html/display-panel.js392
1 files changed, 338 insertions, 54 deletions
diff --git a/html/display-panel.js b/html/display-panel.js
index 1693182..b4d9abb 100644
--- a/html/display-panel.js
+++ b/html/display-panel.js
@@ -10,6 +10,11 @@
* IMPORT browser
* IMPORT is_chrome
* IMPORT is_mozilla
+ *** Using remote storage here seems inefficient, we only resort to that
+ *** temporarily, before all storage access gets reworked.
+ * IMPORT get_remote_storage
+ * IMPORT get_import_frame
+ * IMPORT query_all
* IMPORT CONNECTION_TYPE
* IMPORT url_item
* IMPORT is_privileged_url
@@ -17,13 +22,13 @@
* IMPORT nice_name
* IMPORT open_in_settings
* IMPORT for_each_possible_pattern
+ * IMPORT by_id
+ * IMPORT clone_template
* IMPORTS_END
*/
-function by_id(id)
-{
- return document.getElementById(id);
-}
+let storage;
+let tab_url;
const tab_query = {currentWindow: true, active: true};
@@ -55,28 +60,19 @@ async function show_page_activity_info()
return;
}
- const url = url_item(tab.url);
- page_url_heading.textContent = url;
- if (is_privileged_url(url)) {
+ tab_url = url_item(tab.url);
+ page_url_heading.textContent = tab_url;
+ if (is_privileged_url(tab_url)) {
show_privileged_notice_chbx.checked = true;
return;
}
- populate_possible_patterns_list(url);
+ populate_possible_patterns_list(tab_url);
show_page_state_chbx.checked = true;
try_to_connect(tab.id);
}
-function populate_possible_patterns_list(url)
-{
- for_each_possible_pattern(url, add_pattern_to_list);
-
- const port = browser.runtime.connect({name: CONNECTION_TYPE.PAGE_INFO});
- port.onMessage.addListener(handle_page_info);
- port.postMessage(["subscribe", url]);
-}
-
const possible_patterns_ul = by_id("possible_patterns");
const pattern_li_template = by_id("pattern_li_template");
pattern_li_template.removeAttribute("id");
@@ -121,53 +117,55 @@ function set_pattern_li_button_text(li_id, text)
by_id(li_id).firstElementChild.nextElementSibling.textContent = text;
}
-function handle_page_info(message)
+function handle_page_change(change)
{
- const [type, data] = message;
+ const li_id = ensure_pattern_exists(change.item);
+ if (change.old_val === undefined)
+ set_pattern_li_button_text(li_id, "Edit in settings");
+ if (change.new_val === undefined)
+ set_pattern_li_button_text(li_id, "Add setting");
+}
- if (type === "change") {
- const li_id = ensure_pattern_exists(data.item);
- if (data.old_val === undefined)
- set_pattern_li_button_text(li_id, "Edit in settings");
- if (data.new_val === undefined)
- set_pattern_li_button_text(li_id, "Add setting");
- }
+function populate_possible_patterns_list(url)
+{
+ for_each_possible_pattern(url, add_pattern_to_list);
- if (type === "new_url") {
- for (const li_id of known_patterns.values())
- set_pattern_li_button_text(li_id, "Add setting");
- for (const [pattern, settings] of data) {
- set_pattern_li_button_text(ensure_pattern_exists(pattern),
- "Edit in settings")
- }
+ for (const [pattern, settings] of query_all(storage, url)) {
+ set_pattern_li_button_text(ensure_pattern_exists(pattern),
+ "Edit in settings");
}
+
+ storage.add_change_listener(handle_page_change, [TYPE_PREFIX.PAGE]);
}
const connected_chbx = by_id("connected_chbx");
const query_pattern_but = by_id("query_pattern");
+var content_script_port;
+
function try_to_connect(tab_id)
{
/* This won't connect to iframes. We'll add support for them later */
const connect_info = {name: CONNECTION_TYPE.ACTIVITY_INFO, frameId: 0};
- const port = browser.tabs.connect(tab_id, connect_info);
+ content_script_port = browser.tabs.connect(tab_id, connect_info);
- const button_cb = (e) => start_querying_repos(port);
+ const disconnect_cb = () => handle_disconnect(tab_id, start_querying_repos);
+ content_script_port.onDisconnect.addListener(disconnect_cb);
+ content_script_port.onMessage.addListener(handle_activity_report);
- port.onDisconnect.addListener(port => handle_disconnect(tab_id, button_cb));
- port.onMessage.addListener(handle_activity_report);
-
- query_pattern_but.addEventListener("click", button_cb);
+ query_pattern_but.addEventListener("click", start_querying_repos);
if (is_mozilla)
- setTimeout(() => monitor_connecting(port, tab_id), 1000);
+ setTimeout(() => monitor_connecting(tab_id), 1000);
}
const query_started_chbx = by_id("query_started_chbx");
function start_querying_repos(port)
{
- port.postMessage("dummy (trigger repo querying)");
+ const repo_urls = storage.get_all_names(TYPE_PREFIX.REPO);
+ if (content_script_port)
+ content_script_port.postMessage([TYPE_PREFIX.URL, tab_url, repo_urls]);
query_started_chbx.checked = true;
}
@@ -176,6 +174,7 @@ const loading_chbx = by_id("loading_chbx");
function handle_disconnect(tab_id, button_cb)
{
query_pattern_but.removeEventListener("click", button_cb);
+ content_script_port = null;
if (is_chrome && !browser.runtime.lastError)
return;
@@ -188,12 +187,16 @@ function handle_disconnect(tab_id, button_cb)
setTimeout(() => try_to_connect(tab_id), 1000);
}
-function monitor_connecting(port, tab_id)
+function monitor_connecting(tab_id)
{
if (connected_chbx.checked)
return;
- port.disconnect();
+ if (content_script_port)
+ content_script_port.disconnect();
+ else
+ return;
+
loading_chbx.checked = !loading_chbx.checked;
try_to_connect(tab_id);
}
@@ -204,7 +207,8 @@ const blocked_span = by_id("blocked");
const payload_span = by_id("payload");
const view_payload_but = by_id("view_payload");
const container_for_injected = by_id("container_for_injected");
-const container_for_repo_responses = by_id("container_for_repo_responses");
+
+const queried_items = new Map();
function handle_activity_report(message)
{
@@ -213,7 +217,7 @@ function handle_activity_report(message)
const [type, data] = message;
if (type === "settings") {
- let [pattern, settings, repos] = data;
+ let [pattern, settings] = data;
settings = settings || {};
blocked_span.textContent = settings.allow ? "no" : "yes";
@@ -247,20 +251,300 @@ function handle_activity_report(message)
container_for_injected.appendChild(h4);
container_for_injected.appendChild(pre);
}
- if (type === "repo_query_result") {
- const [repo_url, response_text] = data;
+ if (type === "repo_query_action") {
+ query_started_chbx.checked = true;
- const h4 = document.createElement("h4");
- const pre = document.createElement("pre");
- h4.textContent = repo_url;
- pre.textContent = response_text;
+ const key = data.prefix + data.item;
+ const results = queried_items.get(key) || {};
+ Object.assign(results, data.results);
+ queried_items.set(key, results);
+
+ const action = data.prefix === TYPE_PREFIX.URL ?
+ show_query_result : record_fetched_install_dep;
+
+ for (const [repo_url, result] of Object.entries(data.results))
+ action(data.prefix, data.item, repo_url, result);
+ }
+}
+
+const container_for_repo_responses = by_id("container_for_repo_responses");
+
+const results_lists = new Map();
+
+function create_results_list(url)
+{
+ const list_div = document.createElement("div");
+ const list_head = document.createElement("h4");
+ const list = document.createElement("ul");
+
+ list_head.textContent = url;
+ list_div.appendChild(list_head);
+ list_div.appendChild(list);
+ container_for_repo_responses.appendChild(list_div);
+
+ const list_object = {list, by_repo: new Map()};
+
+ results_lists.set(url, list_object);
+
+ return list_object;
+}
+
+function create_result_item(list_object, repo_url, result)
+{
+ const result_li = document.createElement("li");
+ const repo_url_span = document.createElement("span");
+ const result_item = {result_li, appended: null};
+
+ repo_url_span.textContent = repo_url;
+ result_li.appendChild(repo_url_span);
+
+ list_object.list.appendChild(result_li);
+ list_object.by_repo.set(repo_url, result_item);
+
+ return result_item;
+}
+
+function set_appended(result_item, element)
+{
+ if (result_item.appended)
+ result_item.appended.remove();
+ result_item.appended = element;
+ result_item.result_li.appendChild(element);
+}
+
+function show_message(result_item, text)
+{
+ const div = document.createElement("div");
+ div.textContent = text;
+ set_appended(result_item, div);
+}
+
+function showcb(text)
+{
+ return item => show_message(item, text);
+}
+
+function unroll_chbx_first_checked(entry_object)
+{
+ if (!entry_object.chbx.checked)
+ return;
+
+ entry_object.chbx.removeEventListener("change", entry_object.unroll_cb);
+ delete entry_object.unroll_cb;
+
+ entry_object.unroll.textContent = "preview not implemented...";
+}
+
+const show_install_chbx = by_id("show_install_view_chbx");
+
+let import_frame;
+let install_target = null;
+
+function install_abort(error_state)
+{
+ import_frame.show_error(`Error: ${error_state}`);
+ install_target = null;
+}
+
+/*
+ * Translate objects from the format in which they are sent by Hydrilla to the
+ * format in which they are stored in settings.
+ */
- container_for_repo_responses.appendChild(h4);
- container_for_repo_responses.appendChild(pre);
+function translate_script(script_object, repo_url)
+{
+ return {
+ [TYPE_PREFIX.SCRIPT + script_object.name]: {
+ hash: script_object.sha256,
+ url: `${repo_url}/content/${script_object.location}`
+ }
+ };
+}
+
+function translate_bag(bag_object)
+{
+ return {
+ [TYPE_PREFIX.BAG + bag_object.name]: bag_object.components
+ };
+}
+
+const format_translators = {
+ [TYPE_PREFIX.BAG]: translate_bag,
+ [TYPE_PREFIX.SCRIPT]: translate_script
+};
+
+function install_check_ready()
+{
+ if (install_target.to_fetch.size > 0)
+ return;
+
+ const page_key = [TYPE_PREFIX.PAGE + install_target.pattern];
+ const to_install = [{[page_key]: {components: install_target.payload}}];
+
+ for (const key of install_target.fetched) {
+ const old_object =
+ queried_items.get(key)[install_target.repo_url].response;
+ const new_object =
+ format_translators[key[0]](old_object, install_target.repo_url);
+ to_install.push(new_object);
+ }
+
+ import_frame.show_selection(to_install);
+}
+
+const possible_errors = ["connection_error", "parse_error"];
+
+function fetch_install_deps(components)
+{
+ const needed = [...components];
+ const processed = new Set();
+
+ while (needed.length > 0) {
+ const [prefix, item] = needed.pop();
+ const key = prefix + item;
+ processed.add(key);
+ const results = queried_items.get(key);
+ let relevant_result = null;
+
+ if (results)
+ relevant_result = results[install_target.repo_url];
+
+ if (!relevant_result) {
+ content_script_port.postMessage([prefix, item,
+ [install_target.repo_url]]);
+ install_target.to_fetch.add(key);
+ continue;
+ }
+
+ if (possible_errors.includes(relevant_result.state)) {
+ install_abort(relevant_result.state);
+ return false;
+ }
+
+ install_target.fetched.add(key);
+
+ if (prefix !== TYPE_PREFIX.BAG)
+ continue;
+
+ for (const dependency of relevant_result.response.components) {
+ if (processed.has(dependency.join('')))
+ continue;
+ needed.push(dependency);
+ }
}
}
+function record_fetched_install_dep(prefix, item, repo_url, result)
+{
+ const key = prefix + item;
+
+ if (!install_target || repo_url !== install_target.repo_url ||
+ !install_target.to_fetch.has(key))
+ return;
+
+ if (possible_errors.includes(result.state)) {
+ install_abort(result.state);
+ return;
+ }
+
+ if (result.state !== "completed")
+ return;
+
+ install_target.to_fetch.delete(key);
+ install_target.fetched.add(key);
+
+ if (prefix === TYPE_PREFIX.BAG &&
+ fetch_install_deps(result.response.components) === false)
+ return;
+
+ install_check_ready();
+}
+
+function install_clicked(entry_object)
+{
+ show_install_chbx.checked = true;
+ import_frame.show_loading();
+
+ install_target = {
+ repo_url: entry_object.repo_url,
+ pattern: entry_object.match_object.pattern,
+ payload: entry_object.match_object.payload,
+ fetched: new Set(),
+ to_fetch: new Set()
+ };
+
+ fetch_install_deps([install_target.payload]);
+
+ install_check_ready();
+}
+
+var max_query_result_id = 0;
+
+function show_query_successful_result(result_item, repo_url, result)
+{
+ const ul = document.createElement("ul");
+
+ set_appended(result_item, ul);
+
+ for (const match of result) {
+ const entry_object = clone_template("query_match_li_template");
+
+ entry_object.pattern.textContent = match.pattern;
+
+ ul.appendChild(entry_object.li);
+
+ if (!match.payload) {
+ entry_object.payload.textContent = "(none)";
+ for (const key of ["chbx", "br", "triangle", "unroll"])
+ entry_object[key].remove();
+ continue;
+ }
+
+ entry_object.component.textContent = nice_name(...match.payload);
+
+ const install_cb = () => install_clicked(entry_object);
+ entry_object.btn.addEventListener("click", install_cb);
+
+ const chbx_id = `query_result_${max_query_result_id++}`;
+ entry_object.chbx.id = chbx_id;
+ entry_object.lbl.setAttribute("for", chbx_id);
+
+ entry_object.unroll_cb = () => unroll_chbx_first_checked(entry_object);
+ entry_object.chbx.addEventListener("change", entry_object.unroll_cb);
+
+ entry_object.component_object = match.payload;
+ entry_object.match_object = match;
+ entry_object.repo_url = repo_url;
+ }
+}
+
+function show_query_result(url_prefix, url, repo_url, result)
+{
+ const results_list_object = results_lists.get(url) ||
+ create_results_list(url);
+ const result_item = results_list_object.by_repo.get(repo_url) ||
+ create_result_item(results_list_object, repo_url, result);
+
+ const completed_cb =
+ item => show_query_successful_result(item, repo_url, result.response);
+ const possible_actions = {
+ completed: completed_cb,
+ started: showcb("loading..."),
+ connection_error: showcb("Error when querying repository."),
+ parse_error: showcb("Bad data format received.")
+ };
+ possible_actions[result.state](result_item, repo_url);
+}
+
by_id("settings_but")
.addEventListener("click", (e) => browser.runtime.openOptionsPage());
-show_page_activity_info();
+async function main()
+{
+ storage = await get_remote_storage();
+ import_frame = await get_import_frame();
+ import_frame.onclose = () => show_install_chbx.checked = false;
+ show_page_activity_info();
+}
+
+main();