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.js586
1 files changed, 0 insertions, 586 deletions
diff --git a/html/display_panel.js b/html/display_panel.js
deleted file mode 100644
index 1cd77e6..0000000
--- a/html/display_panel.js
+++ /dev/null
@@ -1,586 +0,0 @@
-/**
- * This file is part of Haketilo.
- *
- * Function: Popup logic.
- *
- * Copyright (C) 2021 Wojtek Kosior
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * As additional permission under GNU GPL version 3 section 7, you
- * may distribute forms of that code without the copy of the GNU
- * GPL normally required by section 4, provided you include this
- * license notice and, in case of non-source distribution, a URL
- * through which recipients can access the Corresponding Source.
- * If you modify file(s) with this exception, you may extend this
- * exception to your version of the file(s), but you are not
- * obligated to do so. If you do not wish to do so, delete this
- * exception statement from your version.
- *
- * As a special exception to the GPL, any HTML file which merely
- * makes function calls to this code, and for that purpose
- * includes it by reference shall be deemed a separate work for
- * copyright law purposes. If you modify this code, you may extend
- * this exception to your version of the code, but you are not
- * obligated to do so. If you do not wish to do so, delete this
- * exception statement from your version.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * I, Wojtek Kosior, thereby promise not to sue for violation of this file's
- * license. Although I request that you do not make use of this code in a
- * proprietary program, I am not going to enforce this in court.
- */
-
-#IMPORT common/connection_types.js AS CONNECTION_TYPE
-
-#FROM common/browser.js IMPORT browser
-/*
- * Using remote storage here seems inefficient, we only resort to that
- * temporarily, before all storage access gets reworked.
- */
-#FROM common/storage_client.js IMPORT get_remote_storage
-#FROM html/import_frame.js IMPORT get_import_frame
-#FROM common/settings_query.js IMPORT query_all
-#FROM common/misc.js IMPORT is_privileged_url, nice_name, \
- open_in_settings
-#FROM common/stored_types.js IMPORT TYPE_PREFIX
-#FROM common/patterns.js IMPORT each_url_pattern
-#FROM html/DOM_helpers.js IMPORT by_id, clone_template
-
-let storage;
-let tab_url;
-
-#IF MOZILLA
-/* Force popup <html>'s reflow on stupid Firefox. */
-const reflow_forcer =
- () => document.documentElement.style.width = "-moz-fit-content";
-for (const radio of document.querySelectorAll('[name="current_view"]'))
- radio.addEventListener("change", reflow_forcer);
-#ENDIF
-
-const show_queried_view_radio = by_id("show_queried_view_radio");
-
-const tab_query = {currentWindow: true, active: true};
-
-async function get_current_tab()
-{
-#IF CHROMIUM
- const callback = (cb) => browser.tabs.query(tab_query, tab => cb(tab));
- const promise = new Promise(callback);
-#ELIF MOZILLA
- const promise = browser.tabs.query(tab_query);
-#ENDIF
-
- try {
- return (await promise)[0];
- } catch(e) {
- console.log(e);
- }
-}
-
-const page_url_heading = by_id("page_url_heading");
-const privileged_notice = by_id("privileged_notice");
-const page_state = by_id("page_state");
-
-/* Helper functions to convert string into a list of one-letter <span>'s. */
-function char_to_span(char, doc)
-{
- const span = document.createElement("span");
- span.textContent = char;
- return span;
-}
-
-function to_spans(string, doc=document)
-{
- return string.split("").map(c => char_to_span(c, doc));
-}
-
-async function show_page_activity_info()
-{
- const tab = await get_current_tab();
-
- if (tab === undefined) {
- page_url_heading.textContent = "unknown page";
- return;
- }
-
- tab_url = /^([^?#]*)/.exec(tab.url)[1];
- to_spans(tab_url).forEach(s => page_url_heading.append(s));
- if (is_privileged_url(tab_url)) {
- privileged_notice.classList.remove("hide");
- return;
- }
-
- populate_possible_patterns_list(tab_url);
- page_state.classList.remove("hide");
-
- try_to_connect(tab.id);
-}
-
-const possible_patterns_list = by_id("possible_patterns");
-const known_patterns = new Map();
-
-function add_pattern_to_list(pattern)
-{
- const template = clone_template("pattern_entry");
- template.name.textContent = pattern;
-
- const settings_opener = () => open_in_settings(TYPE_PREFIX.PAGE, pattern);
- template.button.addEventListener("click", settings_opener);
-
- known_patterns.set(pattern, template);
- possible_patterns_list.append(template.entry);
-
- return template;
-}
-
-function style_possible_pattern_entry(pattern, exists_in_settings)
-{
- const [text, class_action] = exists_in_settings ?
- ["Edit", "add"] : ["Add", "remove"];
- const entry_object = known_patterns.get(pattern);
-
- if (entry_object) {
- entry_object.button.textContent = `${text} setting`;
- entry_object.entry.classList[class_action]("matched_pattern");
- }
-}
-
-function handle_page_change(change)
-{
- style_possible_pattern_entry(change.item, change.new_val !== undefined);
-}
-
-function populate_possible_patterns_list(url)
-{
- for (const pattern of each_url_pattern(url))
- add_pattern_to_list(pattern);
-
- for (const [pattern, settings] of query_all(storage, url))
- style_possible_pattern_entry(pattern, true);
-
- 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};
- content_script_port = browser.tabs.connect(tab_id, connect_info);
-
- 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);
-
- query_pattern_but.addEventListener("click", start_querying_repos);
-
-#IF MOZILLA
- setTimeout(() => monitor_connecting(tab_id), 1000);
-#ENDIF
-}
-
-function start_querying_repos()
-{
- query_pattern_but.removeEventListener("click", start_querying_repos);
- 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]);
-}
-
-const loading_point = by_id("loading_point");
-const reload_notice = by_id("reload_notice");
-
-function handle_disconnect(tab_id, button_cb)
-{
- query_pattern_but.removeEventListener("click", button_cb);
- content_script_port = null;
-
-#IF CHROMIUM
- if (!browser.runtime.lastError)
- return;
-#ENDIF
-
- /* return if error was not during connection initialization */
- if (connected_chbx.checked)
- return;
-
- loading_point.classList.toggle("camouflage");
- reload_notice.classList.remove("hide");
-
- setTimeout(() => try_to_connect(tab_id), 1000);
-}
-
-function monitor_connecting(tab_id)
-{
- if (connected_chbx.checked)
- return;
-
- if (content_script_port)
- content_script_port.disconnect();
- else
- return;
-
- loading_point.classList.toggle("camouflage");
- reload_notice.classList.remove("hide");
- try_to_connect(tab_id);
-}
-
-const pattern_span = by_id("pattern");
-const view_pattern_but = by_id("view_pattern");
-const blocked_span = by_id("blocked");
-const payload_span = by_id("payload");
-const payload_buttons_div = by_id("payload_buttons");
-const view_payload_but = by_id("view_payload");
-const view_injected_but = by_id("view_injected");
-const container_for_injected = by_id("container_for_injected");
-const content_type_cell = by_id("content_type");
-
-const queried_items = new Map();
-
-let max_injected_script_id = 0;
-
-function handle_activity_report(message)
-{
- connected_chbx.checked = true;
-
- const [type, data] = message;
-
- if (type === "settings") {
- const settings = data;
-
- blocked_span.textContent = settings.allow ? "no" : "yes";
-
- if (settings.pattern) {
- pattern_span.textContent = settings.pattern;
- const settings_opener =
- () => open_in_settings(TYPE_PREFIX.PAGE, settings.pattern);
- view_pattern_but.classList.remove("hide");
- view_pattern_but.addEventListener("click", settings_opener);
- } else {
- pattern_span.textContent = "none";
- blocked_span.textContent = blocked_span.textContent + " (default)";
- }
-
- if (settings.payload) {
- payload_span.textContent = nice_name(...settings.payload);
- payload_buttons_div.classList.remove("hide");
- const settings_opener = () => open_in_settings(...settings.payload);
- view_payload_but.addEventListener("click", settings_opener);
- } else {
- payload_span.textContent = "none";
- }
- }
- if (type === "script") {
- const template = clone_template("injected_script");
- const chbx_id = `injected_script_${max_injected_script_id++}`;
- template.chbx.id = chbx_id;
- template.lbl.setAttribute("for", chbx_id);
- template.script_contents.textContent = data;
- container_for_injected.appendChild(template.div);
- }
- if (type === "is_html") {
- if (!data)
- content_type_cell.classList.remove("hide");
- }
- if (type === "repo_query_action") {
- 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 cloned_template = clone_template("multi_repos_query_result");
- cloned_template.url_span.textContent = url;
- container_for_repo_responses.appendChild(cloned_template.div);
-
- cloned_template.by_repo = new Map();
- results_lists.set(url, cloned_template);
-
- return cloned_template;
-}
-
-function create_result_item(list_object, repo_url, result)
-{
- const cloned_template = clone_template("single_repo_query_result");
- cloned_template.repo_url.textContent = repo_url;
- cloned_template.appended = null;
-
- list_object.ul.appendChild(cloned_template.li);
- list_object.by_repo.set(repo_url, cloned_template);
-
- return cloned_template;
-}
-
-function set_appended(result_item, element)
-{
- if (result_item.appended)
- result_item.appended.remove();
- result_item.appended = element;
- result_item.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.innerHTML = "preview not implemented...<br />(consider contributing)";
-}
-
-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.
- */
-
-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)
-{
- 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)
-{
- if (result.length === 0) {
- show_message(result_item, "No results :(");
- return;
- }
-
- const cloned_ul_template = clone_template("result_patterns_list");
- set_appended(result_item, cloned_ul_template.ul);
-
- for (const match of result) {
- const entry_object = clone_template("query_match_li");
-
- entry_object.pattern.textContent = match.pattern;
-
- cloned_ul_template.ul.appendChild(entry_object.li);
-
- if (!match.payload) {
- entry_object.payload.textContent = "(none)";
- for (const key of ["chbx", "triangle", "unroll"])
- entry_object[key].remove();
- continue;
- }
-
- entry_object.payload.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());
-
-async function main()
-{
- storage = await get_remote_storage();
- import_frame = await get_import_frame();
- import_frame.onclose = () => show_queried_view_radio.checked = true;
- show_page_activity_info();
-}
-
-main();