summaryrefslogtreecommitdiff
path: root/html
diff options
context:
space:
mode:
Diffstat (limited to 'html')
-rw-r--r--html/back_button.css71
-rw-r--r--html/display_panel.html370
-rw-r--r--html/display_panel.js586
-rw-r--r--html/import_frame.html79
-rw-r--r--html/import_frame.js185
-rw-r--r--html/mozilla_scrollbar_fix.css67
-rw-r--r--html/options.html416
-rw-r--r--html/options_main.js781
-rw-r--r--html/popup.html2
-rw-r--r--html/settings.html1
-rw-r--r--html/table.css74
11 files changed, 1 insertions, 2631 deletions
diff --git a/html/back_button.css b/html/back_button.css
deleted file mode 100644
index 38740d7..0000000
--- a/html/back_button.css
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0
- *
- * Style for a "back" button with a CSS arrow image
- *
- * This file is part of Haketilo.
- *
- * Copyright (C) 2021 Wojtek Kosior <koszko@koszko.org>
- *
- * File is dual-licensed. You can choose either GPLv3+, CC BY-SA or both.
- *
- * 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.
- *
- * 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
- * licenses. 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.
- */
-
-.back_button {
- display: block;
- width: auto;
- height: auto;
- background-color: white;
- border: solid #454 0.4em;
- border-left: none;
- border-radius: 0 1.5em 1.5em 0;
- cursor: pointer;
-}
-
-.back_button:hover {
- box-shadow: 0 6px 8px 0 rgba(0,0,0,0.24), 0 17px 50px 0 rgba(0,0,0,0.19);
-}
-
-.back_button>div, .back_arrow {
- width: 2em;
- height: 0.5em;
- background-color: #4CAF50;
- border-radius: 0.3em;
- margin: 1.15em 0.4em;
-}
-
-.back_button>div::after, .back_arrow::after,
-.back_button>div::before, .back_arrow::before {
- content: "";
- display: block;
- position: relative;
- background-color: inherit;
- width: 1.3em;
- height: 0.5em;
- transform: rotate(45deg);
- border-radius: 0.3em;
- top: 0.3em;
- right: 0.2em;
- margin: 0 -1.3em -0.5em 0;
-}
-
-.back_button>div::before, .back_arrow::before {
- transform: rotate(-45deg);
- top: -0.3em;
-}
diff --git a/html/display_panel.html b/html/display_panel.html
deleted file mode 100644
index 1468368..0000000
--- a/html/display_panel.html
+++ /dev/null
@@ -1,370 +0,0 @@
-<!doctype html>
-<!--
- SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0
-
- Extension's popup page
-
- This file is part of Haketilo.
-
- Copyright (C) 2021 Wojtek Kosior <koszko@koszko.org>
-
- File is dual-licensed. You can choose either GPLv3+, CC BY-SA or both.
-
- 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.
-
- 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
- licenses. 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.
- -->
-<html>
- <head>
- <meta charset="utf-8"/>
- <title>Haketilo - page settings</title>
-#LOADCSS html/reset.css
-#LOADCSS html/base.css
-#LOADCSS html/back_button.css
-#LOADCSS html/table.css
-#IF MOZILLA
-#LOADCSS html/mozilla_scrollbar_fix.css
-#ENDIF
- <style>
- body {
- width: max-content;
- width: -moz-fit-content;
- }
-
- .top>h2 {
- padding-left: calc(0.8*3.2em - 8px);
- }
-
- .top {
- line-height: calc(0.8*3.6em - 16px);
- }
-
- #main_view>.top>h2 {
- padding-left: 0;
- max-width: 550px
- }
-
- .unroll_chbx:not(:checked)+div>:not(:first-child) {
- display: none;
- }
-
- .unroll_triangle {
- height: 1em;
- width: 1em;
- display: inline-block;
- }
-
- .unroll_triangle::after {
- content: "";
- width: 0.6em;
- height: 0.6em;
- background: linear-gradient(-45deg, currentColor 50%, transparent 50%);
- display: block;
- position: relative;
- transform: rotate(-45deg);
- top: 0.3em;
- }
-
- .unroll_chbx:checked+div>:first-child .unroll_triangle::after {
- transform: rotate(45deg);
- left: 0.2em;
- top: 0.2em;
- }
-
- .unroll_chbx:checked+div>:first-child .unroll_block {
- display: block;
- }
-
- .unroll_chbx:checked+div>:first-child {
- line-height: 1.4em;
- }
-
- .l2_ul {
- border-left: solid #454 5px;
- }
-
- .l1_li {
- margin-top: 0.3em;
- margin-bottom: 0.3em;
- }
-
- .l1_li>div {
- padding: 0.3em 0.3em 0.3em 0;
- }
-
- .l2_li {
- padding: 0.3em;
- }
-
- #container_for_injected>*:nth-child(odd),
- .l2_li:nth-child(odd) {
- background-color: #e5e5e5;
- }
-
- #container_for_injected>#none_injected:not(:last-child) {
- display: none;
- }
-
- #page_url_heading>span {
- display: inline-block;
- }
-
- .back_button {
- position: fixed;
- z-index: 1;
- top: 0;
- left: 0;
- /* The following scales the entire button. */
- font-size: 80%;
- }
-
- #show_main_view_radio:checked~.back_button {
- margin-left: -3.2em;
- }
-
- #show_main_view_radio:not(:checked)~.back_button {
- transition: all 0.2s ease-out;
- }
-
- pre {
- font-family: monospace;
- background-color: white;
- padding: 1px 5px;
- }
-
- .matched_pattern {
- font-weight: bold;
- }
-
- tr.matched_pattern~tr {
- color: #777;
- font-size: 90%;
- }
-
- .padding_inline {
- padding-left: 5px;
- padding-right: 5px;
- }
-
- .padding_top {
- padding-top: 5px;
- }
-
- .header {
- padding-bottom: 0.3em;
- margin-bottom: 0.5em;
- text-align: center;
- }
-
- .middle {
- margin-top: 0.5em;
- margin-bottom: 0.5em;
- }
-
- .footer {
- padding-top: 0.3em;
- margin-top: 0.5em;
- text-align: center;
- }
-
- .active_setting_table {
- margin-bottom: 0.5em;
- }
-
- .active_setting_table td {
- padding: 5px;
- vertical-align: middle;
- }
- </style>
- </head>
- <body>
- <template>
- <tr id="pattern_entry" class="nowrap" data-template="entry">
- <td data-template="name"></td>
- <td>
- <div class="button" data-template="button">Add setting</div>
- </td>
- </tr>
-
- <li id="query_match_li" class="l2_li" data-template="li">
- <div>
- <span>pattern:</span>
- <span class="bold" data-template="pattern"></span>
- <label class="button slimbutton" for="show_install_view_radio" data-template="btn">
- Install
- </label>
- </div>
- <div id="unrollable_component" data-template="unroll_container">
- <input type="checkbox" class="unroll_chbx" data-template="chbx"></input>
- <div>
- <span>payload:
- <label class="bold unroll_block" data-template="lbl">
- <div data-template="triangle" class="unroll_triangle"></div>
- <span data-template="payload"></span>
- </label>
- </span>
- <div data-template="unroll"></div>
- </div>
- </div>
- </li>
-
- <div id="injected_script" data-template="div">
- <input type="checkbox" class="unroll_chbx" data-template="chbx"></input>
- <div>
- <label data-template="lbl">
- <h3><div class="unroll_triangle"></div> script</h3>
- </label>
- <pre class="has_bottom_thin_line has_upper_thin_line" data-template="script_contents"></pre>
- </div>
- </div>
-
- <div id="multi_repos_query_result" data-template="div">
- Results for <span class="bold" data-template="url_span"></span>
- <ul class="l1_ul" data-template="ul"></ul>
- </div>
-
- <li id="single_repo_query_result" class="l1_li" data-template="li">
- <div>
- From <span class="bold" data-template="repo_url"></span>
- </div>
- </li>
-
- <ul id="result_patterns_list" class="l2_ul" data-template="ul">
- </ul>
- </template>
-
- <input id="show_install_view_radio" type="radio" class="show_next" name="current_view"></input>
- <div id="install_view">
- <div class="top has_bottom_line"><h2> Site modifiers install </h2></div>
- <div class="padding_inline">
-#INCLUDE html/import_frame.html
- </div>
- </div>
-
- <input id="show_injected_view_radio" type="radio" class="show_next" name="current_view"></input>
- <div id="injected_view">
- <div class="top has_bottom_line"><h2>Injected scripts</h2></div>
- <div id="container_for_injected">
- <span id="none_injected">None</span>
- </div>
- </div>
-
- <input id="show_patterns_view_radio" type="radio" class="show_next" name="current_view"></input>
- <div>
- <div class="top has_bottom_line"><h2>Possible patterns for this page</h2></div>
- <div class="padding_inline">
- <aside>
- Patterns higher are more specific and override the ones below.
- </aside>
- </div>
- <div class="table_wrapper firefox_scrollbars_hacky_fix">
- <div>
- <table>
- <tbody id="possible_patterns">
- </tbody>
- </table>
- </div>
- </div>
- <div class="padding_inline padding_top has_upper_thin_line firefox_scrollbars_hacky_fix has_inline_content">
- <span class="nowrap">
-#INCLUDE html/default_blocking_policy.html
- </span>
- </div>
- </div>
-
- <input id="show_queried_view_radio" type="radio" class="show_next" name="current_view"></input>
- <div>
- <div class="top has_bottom_line"><h2>Queried from repositories</h2></div>
- <div id="container_for_repo_responses" class="padding_inline">
- </div>
- </div>
-
- <input id="show_main_view_radio" type="radio" class="show_next" name="current_view" checked></input>
- <div id="main_view">
- <div class="top has_bottom_line"><h2 id="page_url_heading"></h2></div>
- <h3 id="privileged_notice" class="middle hide">Privileged page</h3>
-
- <div id="page_state" class="hide">
- <div class="header padding_inline has_bottom_thin_line">
- <label for="show_patterns_view_radio" class="button">
- Edit settings for this page
- </label>
- </div>
- <div class="middle padding_inline">
- <input id="connected_chbx" type="checkbox" class="show_hide_next2"></input>
- <div>
- <table class="active_setting_table">
- <tbody>
- <tr class="nowrap">
- <td>Matched pattern:</td>
- <td id="pattern" class="bold">...</td>
- <td>
- <button id="view_pattern" class="hide">
- View in settings
- </button>
- </td>
- </tr>
- <tr class="nowrap">
- <td>Scripts blocked:</td>
- <td id="blocked" class="bold">...</td>
- <td></td>
- </tr>
- <tr class="nowrap">
- <td>Injected payload:</td>
- <td id="payload" class="bold">...</td>
- <td id="payload_buttons" class="hide">
- <button id="view_payload"> View in settings </button>
- <br/>
- <label id="view_injected" class="button" for="show_injected_view_radio">
- View injected scripts
- </label>
- </td>
- </tr>
- <tr>
- <td id="content_type" colspan="3" class="hide">
- This is a non-HTML page. Chosen payload will not be injected.
- </td>
- </tr>
- </tbody>
- </table>
- <label id="query_pattern" for="show_queried_view_radio" class="button">
- Install scripts for this page
- </label>
- </div>
- <div>
- <h3>
- Connecting to content script..<span id="loading_point">.</span>
- </h3>
- <aside id="reload_notice">
- Try reloading the page.
- </aside>
- </div>
- </div>
- </div>
-
- <div class="footer padding_inline has_upper_thin_line">
- <button id="settings_but" type="button">
- Open Haketilo settings
- </button>
- </div>
- </div>
-
- <div class="has_upper_line"></div>
-
- <label for="show_main_view_radio" class="back_button"><div></div></label>
-#LOADJS html/display_panel.js
- </body>
-</html>
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();
diff --git a/html/import_frame.html b/html/import_frame.html
deleted file mode 100644
index bac98a8..0000000
--- a/html/import_frame.html
+++ /dev/null
@@ -1,79 +0,0 @@
-<!--
- SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0
-
- Scripts import dialog
-
- This file is part of Haketilo.
-
- Copyright (C) 2021 Wojtek Kosior <koszko@koszko.org>
-
- File is dual-licensed. You can choose either GPLv3+, CC BY-SA or both.
-
- 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.
-
- 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
- licenses. 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.
- -->
-
-<!--
- This is not a standalone page. This file is meant to be imported into other
- HTML code.
- -->
-
-<style>
- .padding_right {
- padding-right: 0.3em;
- }
-</style>
-<template>
- <tr id="import_entry" class="nowrap" data-template="entry">
- <td>
- <input type="checkbox" style="display: inline;" checked data-template="chbx"></input>
- <span data-template="name_span"></span>
- </td>
- <td class="bold padding_right" data-template="warning"></td>
- </tr>
-</template>
-
-<input id="import_loading_radio" type="radio" name="import_window_content" class="show_next"></input>
-<span> Loading... </span>
-
-<input id="import_failed_radio" type="radio" name="import_window_content" class="show_next"></input>
-<div>
- <span id="import_errormsg"></span>
- <input id="import_errordetail_chbx" type="checkbox" class="show_next"></input>
- <pre id="import_errordetail"></pre>
- <button id="import_failok_but"> OK </button>
-</div>
-
-<input id="import_selection_radio" type="radio" name="import_window_content" class="show_next"></input>
-<div>
- <button id="check_all_import_but"> Check all </button>
- <button id="uncheck_all_import_but"> Uncheck all </button>
- <button id="uncheck_colliding_import_but"> Uncheck existing </button>
- <aside id="existing_settings_note">
- Settings that would owerwrite existing ones are marked "!".
- </aside>
- <div id="import_table_wrapper" class="table_wrapper">
- <div>
- <table>
- <tbody id="import_list">
- </tbody>
- </table>
- </div>
- </div>
- <button id="commit_import_but"> OK </button>
- <button id="cancel_import_but"> Cancel </button>
-</div>
diff --git a/html/import_frame.js b/html/import_frame.js
deleted file mode 100644
index 659d420..0000000
--- a/html/import_frame.js
+++ /dev/null
@@ -1,185 +0,0 @@
-/**
- * This file is part of Haketilo.
- *
- * Function: Logic for the settings import frame.
- *
- * 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.
- */
-
-#FROM common/storage_client.js IMPORT get_remote_storage
-#FROM html/DOM_helpers.js IMPORT by_id, clone_template
-#FROM common/misc.js IMPORT nice_name
-#FROM common/once.js IMPORT make_once
-
-let storage;
-
-let import_list = by_id("import_list");
-let import_chbxs_colliding = undefined;
-let entry_objects = undefined;
-let settings_import_map = undefined;
-
-function add_import_entry(prefix, name)
-{
- const cloned_template = clone_template("import_entry");
- Object.assign(cloned_template, {prefix, name});
-
- cloned_template.name_span.textContent = nice_name(prefix, name);
-
- if (storage.get(prefix, name) !== undefined) {
- import_chbxs_colliding.push(cloned_template.chbx);
- cloned_template.warning.textContent = "!";
- }
-
- import_list.appendChild(cloned_template.entry);
-
- return cloned_template;
-}
-
-function check_all_imports()
-{
- for (const entry_object of entry_objects)
- entry_object.chbx.checked = true;
-}
-
-function uncheck_all_imports()
-{
- for (const entry_object of entry_objects)
- entry_object.chbx.checked = false;
-}
-
-function uncheck_colliding_imports()
-{
- for (let chbx of import_chbxs_colliding)
- chbx.checked = false;
-}
-
-function commit_import()
-{
- for (const entry_object of entry_objects) {
- if (!entry_object.chbx.checked)
- continue;
-
- const key = entry_object.prefix + entry_object.name;
- const value = settings_import_map.get(key);
- storage.set(entry_object.prefix, entry_object.name, value);
- }
-
- deactivate();
-}
-
-const import_loading_radio = by_id("import_loading_radio");
-
-function show_loading()
-{
- import_loading_radio.checked = true;
-}
-
-const import_failed_radio = by_id("import_failed_radio");
-const import_errormsg = by_id("import_errormsg");
-const import_errordetail_chbx = by_id("import_errordetail_chbx");
-const import_errordetail = by_id("import_errordetail");
-
-function show_error(errormsg, errordetail)
-{
- import_failed_radio.checked = true;
- import_errormsg.textContent = errormsg;
- import_errordetail_chbx.checked = errordetail;
- import_errordetail.textContent = errordetail;
-}
-
-const import_selection_radio = by_id("import_selection_radio");
-const existing_settings_note = by_id("existing_settings_note");
-
-function show_selection(settings)
-{
- import_selection_radio.checked = true;
-
- let old_children = import_list.children;
- while (old_children[0] !== undefined)
- import_list.removeChild(old_children[0]);
-
- import_chbxs_colliding = [];
- entry_objects = [];
- settings_import_map = new Map();
-
- for (let setting of settings) {
- let [key, value] = Object.entries(setting)[0];
- let prefix = key[0];
- let name = key.substring(1);
- entry_objects.push(add_import_entry(prefix, name));
- settings_import_map.set(key, value);
- }
-
- const op = import_chbxs_colliding.length > 0 ? "remove" : "add";
- existing_settings_note.classList[op]("hide");
-}
-
-function deactivate()
-{
- /* Let GC free some memory */
- import_chbxs_colliding = undefined;
- entry_objects = undefined;
- settings_import_map = undefined;
-
- if (exports.onclose)
- exports.onclose();
-}
-
-const wrapper = by_id("import_table_wrapper");
-const style_table = (...cls) => cls.forEach(c => wrapper.classList.add(c));
-
-const exports =
- {show_loading, show_error, show_selection, deactivate, style_table};
-
-async function init()
-{
- storage = await get_remote_storage();
-
- by_id("commit_import_but").addEventListener("click", commit_import);
- by_id("check_all_import_but").addEventListener("click", check_all_imports);
- by_id("uncheck_all_import_but")
- .addEventListener("click", uncheck_all_imports);
- by_id("uncheck_colliding_import_but")
- .addEventListener("click", uncheck_colliding_imports);
- by_id("cancel_import_but").addEventListener("click", deactivate);
- by_id("import_failok_but").addEventListener("click", deactivate);
-
- return exports;
-}
-
-#EXPORT make_once(init) AS get_import_frame
diff --git a/html/mozilla_scrollbar_fix.css b/html/mozilla_scrollbar_fix.css
deleted file mode 100644
index 08cdc93..0000000
--- a/html/mozilla_scrollbar_fix.css
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0
- *
- * Hacky fix for vertical scrollbar width being included in child's width
- *
- * This file is part of Haketilo.
- *
- * Copyright (C) 2021 Wojtek Kosior <koszko@koszko.org>
- *
- * File is dual-licensed. You can choose either GPLv3+, CC BY-SA or both.
- *
- * 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.
- *
- * 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
- * licenses. 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.
- */
-
-/*
- * Under Mozilla browsers to avoid vertical scrollbar forcing horizontal
- * scrollbar to appear in an element we add the `firefox_scrollbars_hacky_fix'
- * class to an element for which width has to be reserved.
- *
- * This is a bit hacky and relies on some assumed width of Firefox scrollbar, I
- * know. And must be excluded from Chromium builds.
- *
- * I came up with this hack when working on popup. Before that I had the
- * scrollbar issue with tables in the options page and gave up there and made
- * the scrollbal always visible. Now we could try applying this "fix" there,
- * too!
- */
-
-.firefox_scrollbars_hacky_fix {
- font-size: 0;
-}
-
-.firefox_scrollbars_hacky_fix>div {
- display: inline-block;
- width: -moz-available;
-}
-
-.firefox_scrollbars_hacky_fix>*>* {
- font-size: initial;
-}
-
-.firefox_scrollbars_hacky_fix::after {
- content: "";
- display: inline-block;
- visibility: hidden;
- font-size: initial;
- width: 14px;
-}
-
-.firefox_scrollbars_hacky_fix.has_inline_content::after {
- width: calc(14px - 0.3em);
-}
diff --git a/html/options.html b/html/options.html
deleted file mode 100644
index e317032..0000000
--- a/html/options.html
+++ /dev/null
@@ -1,416 +0,0 @@
-<!DOCTYPE html>
-<!--
- SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0
-
- Extension's settings page
-
- This file is part of Haketilo.
-
- Copyright (C) 2021 Wojtek Kosior <koszko@koszko.org>
-
- File is dual-licensed. You can choose either GPLv3+, CC BY-SA or both.
-
- 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.
-
- 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
- licenses. 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.
- -->
-<html>
- <head>
- <meta charset="utf-8"/>
- <title>Haketilo options</title>
-#LOADCSS html/reset.css
-#LOADCSS html/base.css
-#LOADCSS html/table.css
- <style>
- body {
- width: 100%;
- }
-
- /* tabbed view */
- #show_repos:not(:checked) ~ #repos,
- #show_pages:not(:checked) ~ #pages,
- #show_bags:not(:checked) ~ #bags,
- #show_scripts:not(:checked) ~ #scripts {
- display: none;
- }
-
- #show_repos:checked ~ div #repos_lbl,
- #show_pages:checked ~ div #pages_lbl,
- #show_bags:checked ~ div #bags_lbl,
- #show_scripts:checked ~ div #scripts_lbl {
- background: #4CAF50;
- color: white;
- }
-
- #tab_heads>* {
- font-size: 130%;
- padding: 10px;
- display: inline-block;
- cursor: pointer;
- }
-
- #tab_heads {
- -moz-user-select: none;
- user-select: none;
- }
-
- #import_but {
- font: unset;
- font-size: 130%;
- float: right;
- margin: 0;
- border-radius: 0;
- }
-
- div.tab {
- min-width: 50vw;
- width: fit-content;
- padding-left: 6px;
- }
-
- /* popup window with list of selectable components */
- .popup {
- position: fixed;
- width: 100vw;
- height: 100vh;
- left: 0;
- top: 0;
- background-color: rgba(60,60,60,0.4);
- z-index: 1;
- overflow: auto;
- vertical-align: center;
- horizontal-align: center;
- }
-
- .popup_frame {
- background-color: #f0f0f0;
- margin: 5vh auto;
- padding: 15px;
- border: solid #333 4px;
- border-radius: 15px;
- width: -moz-fit-content;
- width: fit-content;
- }
-
- .work_li .table_wrapper::before {
- background: linear-gradient(#e0f0f0, #555);
- }
-
- .work_li .table_wrapper::after {
- background: linear-gradient(#555, #e0f0f0);
- }
-
- .table_wrapper.always_scrollbar>* {
- border-left: solid #454 8px;
- max-height: 80vh;
- overflow-y: scroll;
- }
-
- .table_wrapper .table_wrapper.always_scrollbar>*,
- .popup_frame .table_wrapper.always_scrollbar>* {
- max-height: 60vh;
- }
-
- .popup_frame .table_wrapper table {
- min-width: 30vw;
- }
-
- .popup_frame .table_wrapper {
- margin: 0 auto;
- }
-
- td:first-child {
- max-width: 70vw;
- overflow: hidden;
- }
-
- tr.work_li>td:first-child {
- padding-right: 0;
- max-width: unset;
- }
-
- tr.work_li>td>div {
- background-color: #e0f0f0;
- border-left: solid #454 5px;
- border-right: solid #454 2px;
- padding: 5px 10px;
- }
-
- .form_grid {
- display: grid;
- grid-template-columns: auto auto;
- }
-
- .form_grid>label {
- grid-column: 1 / span 1;
- margin-right: 10px;
- }
-
- .form_grid label {
- line-height: 34px; /* center text vertically */
- }
-
- .form_grid>input, .form_grid>span {
- grid-column: 2 / span 1;
- }
-
- .form_grid>label[for="script_contents_field"],
- .form_grid>* {
- grid-column: 1 / span 2;
- }
-
- .form_grid>textarea {
- min-width: 70vw;
- resize: none;
- }
-
- .form_disabled>* {
- opacity: 0.5;
- pointer-events: none;
- }
-
- .form_disabled_msg {
- display: none;
- font-style: italic;
- }
-
- .form_disabled .form_disabled_msg {
- opacity: initial;
- pointer-events: initial;
- display: initial;
- }
- </style>
- </head>
- <body>
- <template>
- <tr id="item_li" class="nowrap">
- <td></td>
- <td><div class="button"> Edit </div></td>
- <td><div class="button"> Remove </div></td>
- <td><div class="button"> Export </div></td>
- </tr>
- <tr id="bag_component_li" class="nowrap">
- <td></td>
- <td><div class="button"> Remove </div></td>
- </tr>
- <tr id="chbx_component_li" class="nowrap">
- <td>
- <input type="checkbox" style="display: inline;"></input>
- <span></span>
- </td>
- </tr>
- <tr id="radio_component_li" class="nowrap">
- <td>
- <input type="radio" style="display: inline;" name="page_components"></input>
- <span></span>
- </td>
- </tr>
- </template>
-
- <!-- Mind the show_*s ids below - their format is assumed in js code -->
- <input type="radio" name="tabs" id="show_repos"></input>
- <input type="radio" name="tabs" id="show_pages" checked></input>
- <input type="radio" name="tabs" id="show_bags"></input>
- <input type="radio" name="tabs" id="show_scripts"></input>
- <div id="tab_heads" class="has_bottom_line">
- <label for="show_repos" id="repos_lbl"> Repos </label>
- <label for="show_pages" id="pages_lbl"> Pages </label>
- <label for="show_bags" id="bags_lbl"> Bags </label>
- <label for="show_scripts" id="scripts_lbl"> Scripts </label>
- <button id="import_but" style="margin-left: 40px;"> Import </button>
- </div>
- <div id="repos" class="tab">
- <div class="table_wrapper tight_table has_bottom_line has_upper_line">
- <div>
- <table>
- <tbody id="repos_ul">
- <tr id="work_repo_li" class="hide work_li">
- <td colspan="4">
- <div class="form_grid">
- <label for="repo_url_field">URL: </label>
- <input id="repo_url_field"></input>
- <div>
- <button id="save_repo_but" type="button"> Save </button>
- <button id="discard_repo_but" type="button"> Cancel </button>
- </div>
- </div>
- </td>
- </tr>
- </tbody>
- </table>
- </div>
- </div>
- <button id="add_repo_but" type="button"> Add repository </button>
- </div>
- <div id="pages" class="tab">
- <div class="table_wrapper tight_table has_bottom_line has_upper_line">
- <div>
- <table>
- <tbody id="pages_ul">
- <tr id="work_page_li" class="hide work_li">
- <td colspan="4">
- <div class="form_grid">
- <label for="page_url_field">URL: </label>
- <input id="page_url_field"></input>
- <label>Payload: </label>
- <span class="nowrap">
- <span id="page_payload"></span>
- <button id="select_page_components_but">
- Choose payload
- </button>
- </span>
- <div id="allow_native_scripts_container" class="nowrap">
- <input id="page_allow_chbx" type="checkbox" style="display: inline;"></input>
- <label for="page_allow_chbx">Allow native scripts</label>
- <span class="form_disabled_msg">
- (only possible when no payload is used)
- </span>
- </div>
- <div>
- <button id="save_page_but" type="button"> Save </button>
- <button id="discard_page_but" type="button"> Cancel </button>
- </div>
- </div>
- </td>
- </tr>
- </tbody>
- </table>
- </div>
- </div>
- <button id="add_page_but" type="button"> Add page </button>
- <br/>
-#INCLUDE html/default_blocking_policy.html
- </div>
- <div id="bags" class="tab">
- <div class="table_wrapper tight_table has_bottom_line has_upper_line">
- <div>
- <table>
- <tbody id="bags_ul">
- <tr id="work_bag_li" class="hide work_li">
- <td colspan="4">
- <div class="form_grid">
- <label for="bag_name_field"> Name: </label>
- <input id="bag_name_field"></input>
- <div class="table_wrapper tight_table has_bottom_line has_upper_line">
- <div>
- <table>
- <tbody id="bag_components_ul">
- <tr id="empty_bag_component_li" class="hide"></tr>
- </tbody>
- </table>
- </div>
- </div>
- <div>
- <button id="select_bag_components_but">
- Add scripts
- </button>
- </div>
- <div>
- <button id="save_bag_but"> Save </button>
- <button id="discard_bag_but"> Cancel </button>
- </div>
- </div>
- </td>
- </tr>
- </tbody>
- </table>
- </div>
- </div>
- <button id="add_bag_but" type="button"> Add bag </button>
- </div>
- <div id="scripts" class="tab">
- <div class="table_wrapper tight_table has_bottom_line has_upper_line">
- <div>
- <table>
- <tbody id="scripts_ul">
- <tr id="work_script_li" class="hide work_li">
- <td colspan="4">
- <div class="form_grid">
- <label for="script_name_field"> Name: </label>
- <input id="script_name_field"></input>
- <label for="script_url_field"> URL: </label>
- <input id="script_url_field"></input>
- <label for="script_sha256_field"> SHA256: </label>
- <input id="script_sha256_field"></input>
- <aside>
- Note: URL and SHA256 are ignored if script text is provided.
- </aside>
- <label for="script_contents_field"> contents: </label>
- <textarea id="script_contents_field" rows="20" cols="80"></textarea>
- <div>
- <button id="save_script_but"> Save </button>
- <button id="discard_script_but"> Cancel </button>
- </div>
- </div>
- </td>
- </tr>
- </tbody>
- </table>
- </div>
- </div>
- <button id="add_script_but" type="button"> Add script </button>
- </div>
-
- <div id="chbx_components_window" class="hide popup" position="absolute">
- <div class="popup_frame">
- <div class="table_wrapper tight_table has_bottom_line has_upper_line">
- <div>
- <table>
- <tbody id="chbx_components_ul">
- </tbody>
- </table>
- </div>
- </div>
- <button id="commit_bag_components_but"> Add </button>
- <button id="cancel_bag_components_but"> Cancel </button>
- </div>
- </div>
-
- <div id="radio_components_window" class="hide popup" position="absolute">
- <div class="popup_frame">
- <div class="table_wrapper tight_table always_scrollbar has_bottom_line has_upper_line">
- <div>
- <table>
- <tbody id="radio_components_ul">
- <tr id="radio_component_none_li">
- <td>
- <input id="radio_component_none_input" type="radio" style="display: inline;" name="page_components"></input>
- <span>(None)</span>
- </td>
- </tr>
- </tbody>
- </table>
- </div>
- </div>
- <button id="commit_page_components_but"> Choose </button>
- <button id="cancel_page_components_but"> Cancel </button>
- </div>
- </div>
-
- <div id="import_window" class="hide popup" position="absolute">
- <div class="popup_frame">
- <h2> Settings import </h2>
-#INCLUDE html/import_frame.html
- </div>
- </div>
-
- <a id="file_downloader" class="hide"></a>
- <form id="file_opener_form" style="visibility: hidden;">
- <input type="file" id="file_opener"></input>
- </form>
-#LOADJS html/options_main.js
- </body>
-</html>
diff --git a/html/options_main.js b/html/options_main.js
deleted file mode 100644
index 4b828f0..0000000
--- a/html/options_main.js
+++ /dev/null
@@ -1,781 +0,0 @@
-/**
- * This file is part of Haketilo.
- *
- * Function: Settings page 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.
- */
-
-#FROM common/storage_client.js IMPORT get_remote_storage
-#FROM common/stored_types.js IMPORT TYPE_PREFIX, TYPE_NAME, \
- list_prefixes
-#FROM common/misc.js IMPORT nice_name, matchers
-#FROM common/sanitize_JSON.js IMPORT parse_json_with_schema
-#FROM html/DOM_helpers.js IMPORT get_template, by_id
-#FROM html/import_frame.js IMPORT get_import_frame
-
-var storage;
-
-const item_li_template = get_template("item_li");
-const bag_component_li_template = get_template("bag_component_li");
-const chbx_component_li_template = get_template("chbx_component_li");
-const radio_component_li_template = get_template("radio_component_li");
-/* Make sure they are later cloned without id. */
-item_li_template.removeAttribute("id");
-bag_component_li_template.removeAttribute("id");
-chbx_component_li_template.removeAttribute("id");
-radio_component_li_template.removeAttribute("id");
-
-function list_set_scrollbar(list_elem)
-{
- const op = ((list_elem.children.length === 1 &&
- list_elem.children[0].classList.contains("hide")) ||
- list_elem.children.length < 1) ? "remove" : "add";
- while (!list_elem.classList.contains("table_wrapper"))
- list_elem = list_elem.parentElement;
- list_elem.classList[op]("always_scrollbar");
-}
-
-function item_li_id(prefix, item)
-{
- return `li_${prefix}_${item}`;
-}
-
-/* Insert into list of bags/pages/scripts/repos */
-function add_li(prefix, item, at_the_end=false)
-{
- let ul = ul_by_prefix[prefix];
- let li = item_li_template.cloneNode(true);
- li.id = item_li_id(prefix, item);
-
- let span = li.firstElementChild;
- span.textContent = item;
-
- let edit_button = span.nextElementSibling;
- edit_button.addEventListener("click", () => edit_item(prefix, item));
-
- let remove_button = edit_button.nextElementSibling;
- remove_button.addEventListener("click",
- () => storage.remove(prefix, item));
-
- let export_button = remove_button.nextElementSibling;
- export_button.addEventListener("click",
- () => export_item(prefix, item));
- if (prefix === TYPE_PREFIX.REPO)
- export_button.remove();
-
- if (!at_the_end) {
- for (let element of ul.ul.children) {
- if (element.id < li.id || element.id.startsWith("work_"))
- continue;
-
- ul.ul.insertBefore(li, element);
- break;
- }
- }
- if (!li.parentElement) {
- if (ul.work_li !== ul.ul.lastElementChild)
- ul.ul.appendChild(li);
- else
- ul.work_li.before(li);
- }
-
- list_set_scrollbar(ul.ul);
-}
-
-const chbx_components_ul = by_id("chbx_components_ul");
-const radio_components_ul = by_id("radio_components_ul");
-
-function chbx_li_id(prefix, item)
-{
- return `cli_${prefix}_${item}`;
-}
-
-function radio_li_id(prefix, item)
-{
- return `rli_${prefix}_${item}`;
-}
-
-//TODO: refactor the 2 functions below
-
-function add_chbx_li(prefix, name)
-{
- if (![TYPE_PREFIX.BAG, TYPE_PREFIX.SCRIPT].includes(prefix))
- return;
-
- let li = chbx_component_li_template.cloneNode(true);
- li.id = chbx_li_id(prefix, name);
- li.setAttribute("data-prefix", prefix);
- li.setAttribute("data-name", name);
-
- let chbx = li.firstElementChild.firstElementChild;
- let span = chbx.nextElementSibling;
-
- span.textContent = nice_name(prefix, name);
-
- chbx_components_ul.appendChild(li);
- list_set_scrollbar(chbx_components_ul);
-}
-
-var radio_component_none_li = by_id("radio_component_none_li");
-
-function add_radio_li(prefix, name)
-{
- if (![TYPE_PREFIX.BAG, TYPE_PREFIX.SCRIPT].includes(prefix))
- return;
-
- let li = radio_component_li_template.cloneNode(true);
- li.id = radio_li_id(prefix, name);
- li.setAttribute("data-prefix", prefix);
- li.setAttribute("data-name", name);
-
- let radio = li.firstElementChild.firstElementChild;
- let span = radio.nextElementSibling;
-
- span.textContent = nice_name(prefix, name);
-
- radio_component_none_li.before(li);
- list_set_scrollbar(radio_components_ul);
-}
-
-/* Used to reset edited repo. */
-function reset_work_repo_li(ul, item, _)
-{
- ul.work_name_input.value = maybe_string(item);
-}
-
-/* Used to get repo data for saving */
-function work_repo_li_data(ul)
-{
- return [ul.work_name_input.value, {}];
-}
-
-const allow_native_scripts_container = by_id("allow_native_scripts_container");
-const page_payload_span = by_id("page_payload");
-
-function set_page_components(components)
-{
- if (components === undefined) {
- page_payload_span.setAttribute("data-payload", "no");
- page_payload_span.textContent = "(None)";
- allow_native_scripts_container.classList.remove("form_disabled");
- } else {
- page_payload_span.setAttribute("data-payload", "yes");
- let [prefix, name] = components;
- page_payload_span.setAttribute("data-prefix", prefix);
- page_payload_span.setAttribute("data-name", name);
- page_payload_span.textContent = nice_name(prefix, name);
- allow_native_scripts_container.classList.add("form_disabled");
- }
-}
-
-const page_allow_chbx = by_id("page_allow_chbx");
-
-/* Used to reset edited page. */
-function reset_work_page_li(ul, item, settings)
-{
- ul.work_name_input.value = maybe_string(item);
- settings = settings || {allow: false, components: undefined};
- page_allow_chbx.checked = !!settings.allow;
-
- set_page_components(settings.components);
-}
-
-function work_page_li_components()
-{
- if (page_payload_span.getAttribute("data-payload") === "no")
- return undefined;
-
- let prefix = page_payload_span.getAttribute("data-prefix");
- let name = page_payload_span.getAttribute("data-name");
- return [prefix, name];
-}
-
-/* Used to get edited page data for saving. */
-function work_page_li_data(ul)
-{
- let url = ul.work_name_input.value;
- let settings = {
- components : work_page_li_components(),
- allow : !!page_allow_chbx.checked
- };
-
- return [url, settings];
-}
-
-const empty_bag_component_li = by_id("empty_bag_component_li");
-var bag_components_ul = by_id("bag_components_ul");
-
-function remove_bag_component_entry(entry)
-{
- const list = entry.parentElement;
- entry.remove();
- list_set_scrollbar(list);
-}
-
-/* Used to construct and update components list of edited bag. */
-function add_bag_components(components)
-{
- for (let component of components) {
- let [prefix, name] = component;
- let li = bag_component_li_template.cloneNode(true);
- li.setAttribute("data-prefix", prefix);
- li.setAttribute("data-name", name);
-
- let span = li.firstElementChild;
- span.textContent = nice_name(prefix, name);
- let remove_but = span.nextElementSibling;
- remove_but.addEventListener("click",
- () => remove_bag_component_entry(li));
- bag_components_ul.appendChild(li);
- }
-
- bag_components_ul.appendChild(empty_bag_component_li);
- list_set_scrollbar(bag_components_ul);
-}
-
-/* Used to reset edited bag. */
-function reset_work_bag_li(ul, item, components)
-{
- components = components || [];
-
- ul.work_name_input.value = maybe_string(item);
- let old_components_ul = bag_components_ul;
- bag_components_ul = old_components_ul.cloneNode(false);
-
- old_components_ul.replaceWith(bag_components_ul);
-
- add_bag_components(components);
-}
-
-/* Used to get edited bag data for saving. */
-function work_bag_li_data(ul)
-{
- let component_li = bag_components_ul.firstElementChild;
-
- let components = [];
-
- /* Last list element is empty li with id set. */
- while (component_li.id === '') {
- components.push([component_li.getAttribute("data-prefix"),
- component_li.getAttribute("data-name")]);
- component_li = component_li.nextElementSibling;
- }
-
- return [ul.work_name_input.value, components];
-}
-
-const script_url_input = by_id("script_url_field");
-const script_sha256_input = by_id("script_sha256_field");
-const script_contents_field = by_id("script_contents_field");
-
-function maybe_string(maybe_defined)
-{
- return maybe_defined === undefined ? "" : maybe_defined + "";
-}
-
-/* Used to reset edited script. */
-function reset_work_script_li(ul, name, data)
-{
- ul.work_name_input.value = maybe_string(name);
- if (data === undefined)
- data = {};
- script_url_input.value = maybe_string(data.url);
- script_sha256_input.value = maybe_string(data.hash);
- script_contents_field.value = maybe_string(data.text);
-}
-
-/* Used to get edited script data for saving. */
-function work_script_li_data(ul)
-{
- return [ul.work_name_input.value, {
- url : script_url_input.value,
- hash : script_sha256_input.value,
- text : script_contents_field.value
- }];
-}
-
-function cancel_work(prefix)
-{
- let ul = ul_by_prefix[prefix];
-
- if (ul.state === UL_STATE.IDLE)
- return;
-
- if (ul.state === UL_STATE.EDITING_ENTRY) {
- add_li(prefix, ul.edited_item);
- }
-
- ul.work_li.classList.add("hide");
- ul.ul.append(ul.work_li);
- list_set_scrollbar(ul.ul);
- ul.state = UL_STATE.IDLE;
-}
-
-function save_work(prefix)
-{
- let ul = ul_by_prefix[prefix];
-
- if (ul.state === UL_STATE.IDLE)
- return;
-
- let [item, data] = ul.get_work_li_data(ul);
-
- /* Here we fire promises and return without waiting. */
-
- if (ul.state === UL_STATE.EDITING_ENTRY)
- storage.replace(prefix, ul.edited_item, item, data);
- if (ul.state === UL_STATE.ADDING_ENTRY)
- storage.set(prefix, item, data);
-
- cancel_work(prefix);
-}
-
-function edit_item(prefix, item)
-{
- cancel_work(prefix);
-
- let ul = ul_by_prefix[prefix];
- let li = by_id(item_li_id(prefix, item));
-
- if (li === null) {
- add_new_item(prefix, item);
- return;
- }
-
- ul.reset_work_li(ul, item, storage.get(prefix, item));
- ul.ul.insertBefore(ul.work_li, li);
- ul.ul.removeChild(li);
- ul.work_li.classList.remove("hide");
- list_set_scrollbar(ul.ul);
-
- ul.state = UL_STATE.EDITING_ENTRY;
- ul.edited_item = item;
-}
-
-const file_downloader = by_id("file_downloader");
-
-function recursively_export_item(prefix, name, added_items, items_data)
-{
- let key = prefix + name;
-
- if (added_items.has(key))
- return;
-
- let data = storage.get(prefix, name);
- if (data === undefined) {
- console.log(`${TYPE_NAME[prefix]} '${name}' for export not found`);
- return;
- }
-
- if (prefix !== TYPE_PREFIX.SCRIPT) {
- let components = prefix === TYPE_PREFIX.BAG ?
- data : [data.components];
-
- for (let [comp_prefix, comp_name] of components) {
- recursively_export_item(comp_prefix, comp_name,
- added_items, items_data);
- }
- }
-
- items_data.push({[key]: data});
- added_items.add(key);
-}
-
-function export_item(prefix, name)
-{
- let added_items = new Set();
- let items_data = [];
- recursively_export_item(prefix, name, added_items, items_data);
- let file = new Blob([JSON.stringify(items_data)],
- {type: "application/json"});
- let url = URL.createObjectURL(file);
- file_downloader.setAttribute("href", url);
- file_downloader.setAttribute("download", prefix + name + ".json");
- file_downloader.click();
- file_downloader.removeAttribute("href");
- URL.revokeObjectURL(url);
-}
-
-function add_new_item(prefix, name)
-{
- cancel_work(prefix);
-
- let ul = ul_by_prefix[prefix];
- ul.reset_work_li(ul);
- ul.work_li.classList.remove("hide");
- ul.ul.appendChild(ul.work_li);
- list_set_scrollbar(ul.ul);
-
- if (name !== undefined)
- ul.work_name_input.value = name;
- ul.state = UL_STATE.ADDING_ENTRY;
-}
-
-const chbx_components_window = by_id("chbx_components_window");
-
-function bag_components()
-{
- chbx_components_window.classList.remove("hide");
- radio_components_window.classList.add("hide");
-
- for (let li of chbx_components_ul.children) {
- let chbx = li.firstElementChild.firstElementChild;
- chbx.checked = false;
- }
-}
-
-function commit_bag_components()
-{
- let selected = [];
-
- for (let li of chbx_components_ul.children) {
- let chbx = li.firstElementChild.firstElementChild;
- if (!chbx.checked)
- continue;
-
- selected.push([li.getAttribute("data-prefix"),
- li.getAttribute("data-name")]);
- }
-
- add_bag_components(selected);
- cancel_components();
-}
-
-const radio_components_window = by_id("radio_components_window");
-var radio_component_none_input = by_id("radio_component_none_input");
-
-function page_components()
-{
- radio_components_window.classList.remove("hide");
- chbx_components_window.classList.add("hide");
-
- radio_component_none_input.checked = true;
-
- let components = work_page_li_components();
- if (components === undefined)
- return;
-
- let [prefix, item] = components;
- let li = by_id(radio_li_id(prefix, item));
-
- if (li === null)
- radio_component_none_input.checked = false;
- else
- li.firstElementChild.firstElementChild.checked = true;
-}
-
-function commit_page_components()
-{
- let components = null;
-
- for (let li of radio_components_ul.children) {
- let radio = li.firstElementChild.firstElementChild;
- if (!radio.checked)
- continue;
-
- components = [li.getAttribute("data-prefix"),
- li.getAttribute("data-name")];
-
- if (radio.id === "radio_component_none_input")
- components = undefined;
-
- break;
- }
-
- if (components !== null)
- set_page_components(components);
- cancel_components();
-}
-
-function cancel_components()
-{
- chbx_components_window.classList.add("hide");
- radio_components_window.classList.add("hide");
-}
-
-const UL_STATE = {
- EDITING_ENTRY : 0,
- ADDING_ENTRY : 1,
- IDLE : 2
-};
-
-const ul_by_prefix = {
- [TYPE_PREFIX.REPO] : {
- ul : by_id("repos_ul"),
- work_li : by_id("work_repo_li"),
- work_name_input : by_id("repo_url_field"),
- reset_work_li : reset_work_repo_li,
- get_work_li_data : work_repo_li_data,
- state : UL_STATE.IDLE,
- edited_item : undefined,
- },
- [TYPE_PREFIX.PAGE] : {
- ul : by_id("pages_ul"),
- work_li : by_id("work_page_li"),
- work_name_input : by_id("page_url_field"),
- reset_work_li : reset_work_page_li,
- get_work_li_data : work_page_li_data,
- select_components : page_components,
- commit_components : commit_page_components,
- state : UL_STATE.IDLE,
- edited_item : undefined,
- },
- [TYPE_PREFIX.BAG] : {
- ul : by_id("bags_ul"),
- work_li : by_id("work_bag_li"),
- work_name_input : by_id("bag_name_field"),
- reset_work_li : reset_work_bag_li,
- get_work_li_data : work_bag_li_data,
- select_components : bag_components,
- commit_components : commit_bag_components,
- state : UL_STATE.IDLE,
- edited_item : undefined,
- },
- [TYPE_PREFIX.SCRIPT] : {
- ul : by_id("scripts_ul"),
- work_li : by_id("work_script_li"),
- work_name_input : by_id("script_name_field"),
- reset_work_li : reset_work_script_li,
- get_work_li_data : work_script_li_data,
- state : UL_STATE.IDLE,
- edited_item : undefined,
- }
-}
-
-/*
- * Newer browsers could utilise `text' method of File objects.
- * Older ones require FileReader.
- */
-
-function _read_file(file, resolve, reject)
-{
- let reader = new FileReader();
-
- reader.onload = () => resolve(reader.result);
- reader.onerror = () => reject(reader.error);
- reader.readAsText(file);
-}
-
-function read_file(file)
-{
- return new Promise((resolve, reject) =>
- _read_file(file, resolve, reject));
-}
-
-const url_regex = /^[a-z0-9]+:\/\/[^/]+\.[^/]{2,}(\/[^?#]*)?$/;
-const empty_regex = /^$/;
-
-const settings_schema = [
- [{}, "matchentry", "minentries", 1,
- new RegExp(`^${TYPE_PREFIX.SCRIPT}`), {
- /* script data */
- "url": ["optional", url_regex, "or", empty_regex],
- "sha256": ["optional", matchers.sha256, "or", empty_regex],
- "text": ["optional", "string"]
- },
- new RegExp(`^${TYPE_PREFIX.BAG}`), [
- "optional",
- [matchers.component, "repeat"],
- "default", undefined
- ],
- new RegExp(`^${TYPE_PREFIX.PAGE}`), {
- /* page data */
- "components": ["optional", matchers.component]
- }], "repeat"
-];
-
-const import_window = by_id("import_window");
-let import_frame;
-
-async function import_from_file(event)
-{
- let files = event.target.files;
- if (files.length < 1)
- return;
-
- import_window.classList.remove("hide");
- import_frame.show_loading();
-
- try {
- const file = await read_file(files[0]);
- var result = parse_json_with_schema(settings_schema, file);
- } catch(e) {
- import_frame.show_error("Bad file :(", "" + e);
- return;
- }
-
- import_frame.show_selection(result);
-}
-
-const file_opener_form = by_id("file_opener_form");
-
-function hide_import_window()
-{
- import_window.classList.add("hide");
-
- /*
- * Reset file <input>. Without this, a second attempt to import the same
- * file would result in "change" event not happening on <input> element.
- */
- file_opener_form.reset();
-}
-
-async function initialize_import_facility()
-{
- let import_but = by_id("import_but");
- let file_opener = by_id("file_opener");
-
- import_but.addEventListener("click", () => file_opener.click());
- file_opener.addEventListener("change", import_from_file);
-
- import_frame = await get_import_frame();
- import_frame.onclose = hide_import_window;
- import_frame.style_table("has_bottom_line", "always_scrollbar",
- "has_upper_line", "tight_table");
-}
-
-/*
- * If url has a target appended, e.g.
- * chrome-extension://hnhmbnpohhlmhehionjgongbnfdnabdl/html/options.html#smyhax
- * that target will be split into prefix and item name (e.g. "s" and "myhax")
- * and editing of that respective item will be started.
- *
- * We don't need to worry about the state of the page (e.g. some editing being
- * in progress) in jump_to_item() - this function is called at the beginning,
- * together with callbacks being assigned to buttons, so it is safe to assume
- * lists are initialized with items and page is in its virgin state with regard
- * to everything else.
- */
-function jump_to_item(url_with_item)
-{
- const [dummy1, base_url, dummy2, target] =
- /^([^#]*)(#(.*))?$/i.exec(url_with_item);
- if (target === undefined)
- return;
-
- const prefix = target.substring(0, 1);
-
- if (!list_prefixes.includes(prefix)) {
- history.replaceState(null, "", base_url);
- return;
- }
-
- by_id(`show_${TYPE_NAME[prefix]}s`).checked = true;
- edit_item(prefix, decodeURIComponent(target.substring(1)));
-}
-
-async function main()
-{
- storage = await get_remote_storage();
-
- for (let prefix of list_prefixes) {
- for (let item of storage.get_all_names(prefix).sort()) {
- add_li(prefix, item, true);
- add_chbx_li(prefix, item);
- add_radio_li(prefix, item);
- }
-
- let name = TYPE_NAME[prefix];
-
- let add_but = by_id(`add_${name}_but`);
- let discard_but = by_id(`discard_${name}_but`);
- let save_but = by_id(`save_${name}_but`);
-
- add_but.addEventListener("click", () => add_new_item(prefix));
- discard_but.addEventListener("click", () => cancel_work(prefix));
- save_but.addEventListener("click", () => save_work(prefix));
-
- if ([TYPE_PREFIX.REPO, TYPE_PREFIX.SCRIPT].includes(prefix))
- continue;
-
- let ul = ul_by_prefix[prefix];
-
- let commit_components_but = by_id(`commit_${name}_components_but`);
- let cancel_components_but = by_id(`cancel_${name}_components_but`);
- let select_components_but = by_id(`select_${name}_components_but`);
-
- commit_components_but
- .addEventListener("click", ul.commit_components);
- select_components_but
- .addEventListener("click", ul.select_components);
- cancel_components_but.addEventListener("click", cancel_components);
- }
-
- jump_to_item(document.URL);
-
- storage.add_change_listener(handle_change);
-
- await initialize_import_facility();
-}
-
-function handle_change(change)
-{
- if (change.old_val === undefined) {
- add_li(change.prefix, change.item);
- add_chbx_li(change.prefix, change.item);
- add_radio_li(change.prefix, change.item);
-
- return;
- }
-
- if (change.new_val !== undefined)
- return;
-
- let ul = ul_by_prefix[change.prefix];
- if (ul.state === UL_STATE.EDITING_ENTRY &&
- ul.edited_item === change.item) {
- ul.state = UL_STATE.ADDING_ENTRY;
- return;
- }
-
- let uls_creators = [[ul.ul, item_li_id]];
-
- if ([TYPE_PREFIX.BAG, TYPE_PREFIX.SCRIPT].includes(change.prefix)) {
- uls_creators.push([chbx_components_ul, chbx_li_id]);
- uls_creators.push([radio_components_ul, radio_li_id]);
- }
-
- for (let [components_ul, id_creator] of uls_creators) {
- let li = by_id(id_creator(change.prefix, change.item));
- components_ul.removeChild(li);
- list_set_scrollbar(components_ul);
- }
-}
-
-main();
diff --git a/html/popup.html b/html/popup.html
index ad6c258..bb30425 100644
--- a/html/popup.html
+++ b/html/popup.html
@@ -55,10 +55,10 @@
#info_form, #unprivileged_page_info {
display: grid;
grid-template-columns: auto;
- text-align: center;
}
#info_form * {
+ text-align: center;
white-space: nowrap;
text-overflow: ellipsis;
overflow-x: hidden;
diff --git a/html/settings.html b/html/settings.html
index ce19e55..7abb870 100644
--- a/html/settings.html
+++ b/html/settings.html
@@ -33,7 +33,6 @@
<title>Haketilo options</title>
#LOADCSS html/reset.css
#LOADCSS html/base.css
-#LOADCSS html/table.css
#LOADCSS html/grid.css
<style>
/* Style top menu items. */
diff --git a/html/table.css b/html/table.css
deleted file mode 100644
index 48792c1..0000000
--- a/html/table.css
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0
- *
- * Table styling used in some Haketilo internal HTML pages
- *
- * This file is part of Haketilo.
- *
- * Copyright (C) 2021 Wojtek Kosior <koszko@koszko.org>
- *
- * File is dual-licensed. You can choose either GPLv3+, CC BY-SA or both.
- *
- * 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.
- *
- * 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
- * licenses. 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.
- */
-
-.table_wrapper {
- display: block;
- background-color: #f0f0f0;
- margin: 6px 0;
-}
-
-.table_wrapper table {
- border-collapse: unset;
- width: 100%;
-}
-
-.table_wrapper.tight_table,
-.table_wrapper.tight_table>*,
-.table_wrapper.tight_table>*>table {
- width: -moz-min-content;
- width: min-content;
-}
-
-tr:nth-child(odd) {
- background-color: #e5e5e5;
-}
-
-td {
- vertical-align: middle;
- min-width: fit-content;
- min-width: -moz-fit-content;
-}
-
-.tight_table td {
- width: 1%;
-}
-
-td:first-child {
- padding: 3px 10px 6px;
-}
-
-.tight_table td:first-child {
- width: 100%;
-}
-
-td>div.button {
- margin-right: 4px;
- white-space: nowrap;
- float: right;
-}