aboutsummaryrefslogtreecommitdiff
path: root/html/display-panel.js
diff options
context:
space:
mode:
Diffstat (limited to 'html/display-panel.js')
-rw-r--r--html/display-panel.js226
1 files changed, 225 insertions, 1 deletions
diff --git a/html/display-panel.js b/html/display-panel.js
index 4a4cdcd..9ae35fd 100644
--- a/html/display-panel.js
+++ b/html/display-panel.js
@@ -8,8 +8,232 @@
/*
* IMPORTS_START
* IMPORT browser
+ * IMPORT is_chrome
+ * IMPORT is_mozilla
+ * IMPORT CONNECTION_TYPE
+ * IMPORT url_item
+ * IMPORT is_privileged_url
+ * IMPORT TYPE_PREFIX
+ * IMPORT nice_name
+ * IMPORT open_in_settings
+ * IMPORT for_each_possible_pattern
* IMPORTS_END
*/
-document.getElementById("settings_but")
+function by_id(id)
+{
+ return document.getElementById(id);
+}
+
+const tab_query = {currentWindow: true, active: true};
+
+async function get_current_tab()
+{
+ /* Fix for fact that Chrome does not use promises here */
+ const promise = is_chrome ?
+ new Promise((resolve, reject) =>
+ browser.tabs.query(tab_query, tab => resolve(tab))) :
+ browser.tabs.query(tab_query);
+
+ try {
+ return (await promise)[0];
+ } catch(e) {
+ console.log(e);
+ }
+}
+
+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");
+
+async function show_page_activity_info()
+{
+ const tab = await get_current_tab();
+
+ if (tab === undefined) {
+ page_url_heading.textContent = "unknown page";
+ return;
+ }
+
+ const url = url_item(tab.url);
+ page_url_heading.textContent = url;
+ if (is_privileged_url(url)) {
+ show_privileged_notice_chbx.checked = true;
+ return;
+ }
+
+ populate_possible_patterns_list(url);
+ show_page_state_chbx.checked = true;
+
+ try_to_connect(tab.id);
+}
+
+function populate_possible_patterns_list(url)
+{
+ for_each_possible_pattern(url, add_pattern_to_list);
+
+ const port = browser.runtime.connect({name: CONNECTION_TYPE.PAGE_INFO});
+ port.onMessage.addListener(handle_page_info);
+ port.postMessage(["subscribe", url]);
+}
+
+const possible_patterns_ul = by_id("possible_patterns");
+const pattern_li_template = by_id("pattern_li_template");
+pattern_li_template.removeAttribute("id");
+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 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);
+
+ possible_patterns_ul.appendChild(li)
+
+ return li.id;
+}
+
+function ensure_pattern_exists(pattern)
+{
+ let id = 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) {
+ console.log(`unknown pattern: ${pattern}`);
+ id = add_pattern_to_list(pattern);
+ }
+
+ return id;
+}
+
+function set_pattern_li_button_text(li_id, text)
+{
+ by_id(li_id).firstElementChild.nextElementSibling.textContent = text;
+}
+
+function handle_page_info(message)
+{
+ const [type, data] = message;
+
+ if (type === "change") {
+ const li_id = ensure_pattern_exists(data.item);
+ if (data.old_val === undefined)
+ set_pattern_li_button_text(li_id, "Edit in settings");
+ if (data.new_val === undefined)
+ set_pattern_li_button_text(li_id, "Add setting");
+ }
+
+ if (type === "new_url") {
+ for (const li_id of known_patterns.values())
+ set_pattern_li_button_text(li_id, "Add setting");
+ for (const [pattern, settings] of data) {
+ set_pattern_li_button_text(ensure_pattern_exists(pattern),
+ "Edit in settings")
+ }
+ }
+}
+
+const connected_chbx = by_id("connected_chbx");
+
+function try_to_connect(tab_id)
+{
+ /* This won't connect to iframes. We'll add support for them later */
+ const connect_info = {name: CONNECTION_TYPE.ACTIVITY_INFO, frameId: 0};
+ const port = browser.tabs.connect(tab_id, connect_info);
+
+ port.onDisconnect.addListener(port => handle_disconnect(tab_id));
+ port.onMessage.addListener(handle_activity_report);
+
+ if (is_mozilla)
+ setTimeout(() => monitor_connecting(port, tab_id), 1000);
+}
+
+const loading_chbx = by_id("loading_chbx");
+
+function handle_disconnect(tab_id)
+{
+ if (is_chrome && !browser.runtime.lastError)
+ return;
+
+ /* return if there was no connection initialization failure */
+ if (connected_chbx.checked)
+ return;
+
+ loading_chbx.checked = !loading_chbx.checked;
+ setTimeout(() => try_to_connect(tab_id), 1000);
+}
+
+function monitor_connecting(port, tab_id)
+{
+ if (connected_chbx.checked)
+ return;
+
+ port.disconnect();
+ loading_chbx.checked = !loading_chbx.checked;
+ 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 view_payload_but = by_id("view_payload");
+const container_for_injected = by_id("container_for_injected");
+
+function handle_activity_report(message)
+{
+ connected_chbx.checked = true;
+
+ const [type, data] = message;
+
+ if (type === "settings") {
+ let [pattern, settings] = data;
+
+ settings = settings || {};
+ blocked_span.textContent = settings.allow ? "no" : "yes";
+
+ if (pattern) {
+ pattern_span.textContent = pattern;
+ const settings_opener =
+ () => open_in_settings(TYPE_PREFIX.PAGE, pattern);
+ view_pattern_but.classList.remove("hide");
+ view_pattern_but.addEventListener("click", settings_opener);
+ } else {
+ pattern_span.textContent = "none";
+ }
+
+ const components = settings.components;
+ if (components) {
+ payload_span.textContent = nice_name(...components);
+ 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);
+ }
+}
+
+by_id("settings_but")
.addEventListener("click", (e) => browser.runtime.openOptionsPage());
+
+show_page_activity_info();