From 453ba03962ececcdff9264bea606b7bc488c1803 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Wed, 1 Sep 2021 11:45:06 +0200 Subject: add styling for popup page\n\nThis does not include styling for contents of the import dialog --- html/DOM_helpers.js | 2 +- html/back_button.css | 50 +++++++ html/base.css | 22 ++- html/display-panel.html | 365 ++++++++++++++++++++++++++++++++++++++---------- html/display-panel.js | 174 ++++++++++++----------- html/import_frame.html | 1 - html/options.html | 95 +++---------- html/options_main.js | 8 +- html/table.css | 46 ++++++ 9 files changed, 528 insertions(+), 235 deletions(-) create mode 100644 html/back_button.css create mode 100644 html/table.css (limited to 'html') diff --git a/html/DOM_helpers.js b/html/DOM_helpers.js index 392299f..01e2be9 100644 --- a/html/DOM_helpers.js +++ b/html/DOM_helpers.js @@ -42,7 +42,7 @@ function clone_template(template_id) result_object[template_key] = element; element.removeAttribute("id"); - element.removeAttribute("template_key"); + element.removeAttribute("data-template"); for (const child of element.children) to_process.push(child); diff --git a/html/back_button.css b/html/back_button.css new file mode 100644 index 0000000..1ddc5da --- /dev/null +++ b/html/back_button.css @@ -0,0 +1,50 @@ +/** + * part of Hachette + * Style for a "back" button with a CSS arrow image. + * + * Copyright (C) 2021 Wojtek Kosior + * Redistribution terms are gathered in the `copyright' file. + */ + +.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/base.css b/html/base.css index 91fd953..0b9c7d3 100644 --- a/html/base.css +++ b/html/base.css @@ -6,8 +6,11 @@ * Redistribution terms are gathered in the `copyright' file. */ -html { +body { font-family: sans-serif; + background-color: #f0f0f0; + color: #555; + overflow: auto; } textarea { @@ -18,6 +21,10 @@ input[type="checkbox"], input[type="radio"], .hide { display: none; } +.camouflage { + visibility: hidden; +} + .show_next:not(:checked)+* { display: none; } @@ -42,6 +49,8 @@ button, .button { margin: 2px 0px; -moz-user-select: none; user-select: none; + cursor: pointer; + font: 400 15px sans-serif; } button.slimbutton, .button.slimbutton { @@ -64,3 +73,14 @@ aside { textarea: { resize: none; } + +.has_bottom_line::after, .has_upper_line::before { + content: ""; + display: block; + height: 8px; + background: linear-gradient(transparent, #555); +} + +.has_bottom_line::after { + background: linear-gradient(#555, transparent); +} diff --git a/html/display-panel.html b/html/display-panel.html index cbd7dc8..4121c30 100644 --- a/html/display-panel.html +++ b/html/display-panel.html @@ -9,117 +9,336 @@ Hachette - page settings + + - +
+

Site modifiers install

-
-
-

- - -

Privileged page

- - -
- - - -
    - - + + +
    +

    Injected scripts

    +
    + None +
    +
    + + +
    +

    Possible patterns for this page

    +
    + +
    +
    - Matched pattern: ... - -
    - Blocked: ... -
    - Payload: ... - -

    Injected

    -
    - None + + + +
    +
    +
    +
    + + +
    +

    Queried from repositories

    +
    +
    +
    + + +
    +

    +

    Privileged page

    + +
    +
    + +
    +
    + +
    + + + + + + + + + + + + + + + + + + +
    Matched pattern:... + +
    Scripts blocked:...
    Injected payload:... + +
    + +
    +
    - -
    -

    Queried from repositories

    +
    +

    + Connecting to content script... +

    +
    -
    -

    Trying to connect...

    - -
    _POPUPSCRIPTS_ + +
    + +
    + + _POPUPSCRIPTS_ diff --git a/html/display-panel.js b/html/display-panel.js index 54b5578..0c89864 100644 --- a/html/display-panel.js +++ b/html/display-panel.js @@ -20,6 +20,7 @@ * IMPORT TYPE_PREFIX * IMPORT nice_name * IMPORT open_in_settings + * IMPORT url_matches * IMPORT each_url_pattern * IMPORT by_id * IMPORT get_template @@ -30,6 +31,16 @@ let storage; let tab_url; +/* Force popup 's reflow on stupid Firefox. */ +if (is_mozilla) { + const reflow_forcer = + () => document.documentElement.style.width = "-moz-fit-content"; + for (const radio of document.querySelectorAll('[name="current_view"]')) + radio.addEventListener("change", reflow_forcer); +} + +const show_queried_view_radio = by_id("show_queried_view_radio"); + const tab_query = {currentWindow: true, active: true}; async function get_current_tab() @@ -48,8 +59,21 @@ async function get_current_tab() } const page_url_heading = by_id("page_url_heading"); -const show_privileged_notice_chbx = by_id("show_privileged_notice_chbx"); -const show_page_state_chbx = by_id("show_page_state_chbx"); +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 '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() { @@ -61,69 +85,65 @@ async function show_page_activity_info() } tab_url = /^([^?#]*)/.exec(tab.url)[1]; - page_url_heading.textContent = tab_url; + to_spans(tab_url).forEach(s => page_url_heading.append(s)); if (is_privileged_url(tab_url)) { - show_privileged_notice_chbx.checked = true; + privileged_notice.classList.remove("hide"); return; } populate_possible_patterns_list(tab_url); - show_page_state_chbx.checked = true; + page_state.classList.remove("hide"); try_to_connect(tab.id); } -const possible_patterns_ul = by_id("possible_patterns"); -const pattern_li_template = get_template("pattern_li"); -pattern_li_template.removeAttribute("id"); +const possible_patterns_list = by_id("possible_patterns"); const known_patterns = new Map(); function add_pattern_to_list(pattern) { - const li = pattern_li_template.cloneNode(true); - li.id = `pattern_li_${known_patterns.size}`; - known_patterns.set(pattern, li.id); + const template = clone_template("pattern_entry"); + template.name.textContent = pattern; - const span = li.firstElementChild; - span.textContent = pattern; - - const button = span.nextElementSibling; const settings_opener = () => open_in_settings(TYPE_PREFIX.PAGE, pattern); - button.addEventListener("click", settings_opener); + template.button.addEventListener("click", settings_opener); - possible_patterns_ul.appendChild(li) + known_patterns.set(pattern, template); + possible_patterns_list.append(template.entry); - return li.id; + return template; } function ensure_pattern_exists(pattern) { - let id = known_patterns.get(pattern); + let entry_object = known_patterns.get(pattern); /* * As long as pattern computation works well, we should never get into this * conditional block. This is just a safety measure. To be removed as part * of a bigger rework when we start taking iframes into account. */ - if (id === undefined) { + if (entry_object === undefined) { console.log(`unknown pattern: ${pattern}`); - id = add_pattern_to_list(pattern); + entry_object = add_pattern_to_list(pattern); } - return id; + return entry_object; } -function set_pattern_li_button_text(li_id, text) +function style_possible_pattern_entry(pattern, exists_in_settings) { - by_id(li_id).firstElementChild.nextElementSibling.textContent = text; + const [text, class_action] = exists_in_settings ? + ["Edit", "add"] : ["Add", "remove"]; + const entry_object = ensure_pattern_exists(pattern); + + entry_object.button.textContent = `${text} setting`; + entry_object.entry.classList[class_action]("matched_pattern"); } function handle_page_change(change) { - const li_id = ensure_pattern_exists(change.item); - if (change.old_val === undefined) - set_pattern_li_button_text(li_id, "Edit in settings"); - if (change.new_val === undefined) - set_pattern_li_button_text(li_id, "Add setting"); + if (url_matches(tab_url, change.item)) + style_possible_pattern_entry(change.item, change.new_val !== undefined); } function populate_possible_patterns_list(url) @@ -131,10 +151,8 @@ 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)) { - set_pattern_li_button_text(ensure_pattern_exists(pattern), - "Edit in settings"); - } + 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]); } @@ -160,17 +178,16 @@ function try_to_connect(tab_id) setTimeout(() => monitor_connecting(tab_id), 1000); } -const query_started_chbx = by_id("query_started_chbx"); - -function start_querying_repos(port) +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]); - query_started_chbx.checked = true; } -const loading_chbx = by_id("loading_chbx"); +const loading_point = by_id("loading_point"); +const reload_notice = by_id("reload_notice"); function handle_disconnect(tab_id, button_cb) { @@ -184,7 +201,9 @@ function handle_disconnect(tab_id, button_cb) if (connected_chbx.checked) return; - loading_chbx.checked = !loading_chbx.checked; + loading_point.classList.toggle("camouflage"); + reload_notice.classList.remove("hide"); + setTimeout(() => try_to_connect(tab_id), 1000); } @@ -198,7 +217,8 @@ function monitor_connecting(tab_id) else return; - loading_chbx.checked = !loading_chbx.checked; + loading_point.classList.toggle("camouflage"); + reload_notice.classList.remove("hide"); try_to_connect(tab_id); } @@ -206,11 +226,15 @@ 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 queried_items = new Map(); +let max_injected_script_id = 0; + function handle_activity_report(message) { connected_chbx.checked = true; @@ -236,25 +260,22 @@ function handle_activity_report(message) const components = settings.components; if (components) { payload_span.textContent = nice_name(...components); + payload_buttons_div.classList.remove("hide"); const settings_opener = () => open_in_settings(...components); - view_payload_but.classList.remove("hide"); view_payload_but.addEventListener("click", settings_opener); } else { payload_span.textContent = "none"; } } if (type === "script") { - const h4 = document.createElement("h4"); - const pre = document.createElement("pre"); - h4.textContent = "script"; - pre.textContent = data; - - container_for_injected.appendChild(h4); - container_for_injected.appendChild(pre); + 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 === "repo_query_action") { - query_started_chbx.checked = true; - const key = data.prefix + data.item; const results = queried_items.get(key) || {}; Object.assign(results, data.results); @@ -274,35 +295,26 @@ const results_lists = new Map(); function create_results_list(url) { - const list_div = document.createElement("div"); - const list_head = document.createElement("h4"); - const list = document.createElement("ul"); + const cloned_template = clone_template("multi_repos_query_result"); + cloned_template.url_span.textContent = url; + container_for_repo_responses.appendChild(cloned_template.div); - list_head.textContent = url; - list_div.appendChild(list_head); - list_div.appendChild(list); - container_for_repo_responses.appendChild(list_div); + cloned_template.by_repo = new Map(); + results_lists.set(url, cloned_template); - const list_object = {list, by_repo: new Map()}; - - results_lists.set(url, list_object); - - return list_object; + return cloned_template; } function create_result_item(list_object, repo_url, result) { - const result_li = document.createElement("li"); - const repo_url_span = document.createElement("span"); - const result_item = {result_li, appended: null}; - - repo_url_span.textContent = repo_url; - result_li.appendChild(repo_url_span); + const cloned_template = clone_template("single_repo_query_result"); + cloned_template.repo_url.textContent = repo_url; + cloned_template.appended = null; - list_object.list.appendChild(result_li); - list_object.by_repo.set(repo_url, result_item); + list_object.ul.appendChild(cloned_template.li); + list_object.by_repo.set(repo_url, cloned_template); - return result_item; + return cloned_template; } function set_appended(result_item, element) @@ -310,7 +322,7 @@ function set_appended(result_item, element) if (result_item.appended) result_item.appended.remove(); result_item.appended = element; - result_item.result_li.appendChild(element); + result_item.li.appendChild(element); } function show_message(result_item, text) @@ -333,11 +345,9 @@ function unroll_chbx_first_checked(entry_object) entry_object.chbx.removeEventListener("change", entry_object.unroll_cb); delete entry_object.unroll_cb; - entry_object.unroll.textContent = "preview not implemented..."; + entry_object.unroll.innerHTML = "preview not implemented...
    (consider contributing)"; } -const show_install_chbx = by_id("show_install_view_chbx"); - let import_frame; let install_target = null; @@ -463,7 +473,6 @@ function record_fetched_install_dep(prefix, item, repo_url, result) function install_clicked(entry_object) { - show_install_chbx.checked = true; import_frame.show_loading(); install_target = { @@ -483,25 +492,24 @@ var max_query_result_id = 0; function show_query_successful_result(result_item, repo_url, result) { - const ul = document.createElement("ul"); - - set_appended(result_item, ul); + 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; - ul.appendChild(entry_object.li); + cloned_ul_template.ul.appendChild(entry_object.li); if (!match.payload) { entry_object.payload.textContent = "(none)"; - for (const key of ["chbx", "br", "triangle", "unroll"]) + for (const key of ["chbx", "triangle", "unroll"]) entry_object[key].remove(); continue; } - entry_object.component.textContent = nice_name(...match.payload); + entry_object.payload.textContent = nice_name(...match.payload); const install_cb = () => install_clicked(entry_object); entry_object.btn.addEventListener("click", install_cb); @@ -544,7 +552,7 @@ async function main() { storage = await get_remote_storage(); import_frame = await get_import_frame(); - import_frame.onclose = () => show_install_chbx.checked = false; + import_frame.onclose = () => show_queried_view_radio.checked = true; show_page_activity_info(); } diff --git a/html/import_frame.html b/html/import_frame.html index 0511e6c..835977d 100644 --- a/html/import_frame.html +++ b/html/import_frame.html @@ -5,7 +5,6 @@ -

    Settings import

    Loading... diff --git a/html/options.html b/html/options.html index e0c3c23..13a8973 100644 --- a/html/options.html +++ b/html/options.html @@ -9,11 +9,9 @@ Hachette options + @@ -239,7 +185,7 @@ -
    +
    @@ -247,7 +193,7 @@
    -
    +
    @@ -270,7 +216,7 @@
    -
    +
    @@ -304,7 +250,7 @@
    -
    +
    @@ -313,7 +259,7 @@
    -
    +
    @@ -341,7 +287,7 @@
    -
    +
    @@ -375,7 +321,7 @@
    @@ -390,7 +336,7 @@
    @@ -411,6 +357,7 @@ diff --git a/html/options_main.js b/html/options_main.js index 8067fe7..03505a5 100644 --- a/html/options_main.js +++ b/html/options_main.js @@ -77,8 +77,12 @@ function add_li(prefix, item, at_the_end=false) break; } } - if (!li.parentElement) - ul.ul.appendChild(li); + 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); } diff --git a/html/table.css b/html/table.css new file mode 100644 index 0000000..6296f83 --- /dev/null +++ b/html/table.css @@ -0,0 +1,46 @@ +.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; + white-space: nowrap; +} + +.tight_table td:first-child { + width: 100%; +} + +td>div.button { + margin-right: 4px; + white-space: nowrap; + float: right; +} -- cgit v1.2.3