diff options
Diffstat (limited to 'html')
-rw-r--r-- | html/display-panel.html | 85 | ||||
-rw-r--r-- | html/display-panel.js | 226 | ||||
-rw-r--r-- | html/options_main.js | 6 |
3 files changed, 309 insertions, 8 deletions
diff --git a/html/display-panel.html b/html/display-panel.html index 5e5580e..9b6d619 100644 --- a/html/display-panel.html +++ b/html/display-panel.html @@ -6,9 +6,90 @@ <html> <head> <meta charset="utf-8"/> - <title>Myext popup</title> + <title>Hachette - page settings</title> + <style> + input[type="radio"], input[type="checkbox"] { + display: none; + } + + body { + width: 300px; + height: 300px; + } + + .show_next:not(:checked)+* { + display: none; + } + + .hide { + display: none; + } + + #possible_patterns_chbx:not(:checked)+label span#triangle:first-child+span, + #possible_patterns_chbx:not(:checked)+label+*, + #possible_patterns_chbx:checked+label span#triangle:first-child { + display: none; + } + + #container_for_injected>#none_injected:not(:last-child) { + display: none; + } + + input#connected_chbx:checked+div+h3 { + display: none; + } + </style> </head> <body> - <button id="settings_but" type="button">Settings</button>_POPUPSCRIPTS_ + <!-- The invisible div below is for elements that will be cloned. --> + <div class="hide"> + <li id="pattern_li_template"> + <span></span> + <button>View in settings</button> + </li> + </div> + + <h2 id="page_url_heading"></h2> + + <input id="show_privileged_notice_chbx" type="checkbox" class="show_next"></input> + <h3>Privileged page</h3> + + <input id="show_page_state_chbx" type="checkbox" class="show_next"></input> + <div> + <input id="possible_patterns_chbx" type="checkbox"></input> + <label for="possible_patterns_chbx"> + <h3> + <span id="triangle">⏵</span><span>⏷</span> + Possible patterns + </h3> + </label> + <ul id="possible_patterns"></ul> + + <input id="connected_chbx" type="checkbox" class="show_next"></input> + <div> + <h3> + Matched pattern: <span id="pattern">...</span> + <button id="view_pattern" class="hide"> + View in settings + </button> + </h3> + <h3> + Blocked: <span id="blocked">...</span> + </h3> + <h3> + Payload: <span id="payload">...</span> + <button id="view_payload" class="hide"> + View in settings + </button> + </h3> + <h3>Injected</h3> + <div id="container_for_injected"> + <span id="none_injected">None</span> + </div> + </div> + <h3>Trying to connect..<input id="loading_chbx" type="checkbox" class="show_next"></input><span>.</span></h3> + </div> + + <button id="settings_but" type="button" style="margin-top: 20px;">Settings</button>_POPUPSCRIPTS_ </body> </html> 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(); diff --git a/html/options_main.js b/html/options_main.js index 9c66a27..f7adf39 100644 --- a/html/options_main.js +++ b/html/options_main.js @@ -12,6 +12,7 @@ * IMPORT TYPE_NAME * IMPORT list_prefixes * IMPORT url_extract_target + * IMPORT nice_name * IMPORTS_END */ @@ -21,11 +22,6 @@ function by_id(id) return document.getElementById(id); } -function nice_name(prefix, name) -{ - return `${name} (${TYPE_NAME[prefix]})`; -} - const item_li_template = by_id("item_li_template"); const bag_component_li_template = by_id("bag_component_li_template"); const chbx_component_li_template = by_id("chbx_component_li_template"); |