summaryrefslogtreecommitdiffstats
path: root/browser/extensions/webcompat/about-compat/aboutCompat.js
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--browser/extensions/webcompat/about-compat/aboutCompat.js283
1 files changed, 283 insertions, 0 deletions
diff --git a/browser/extensions/webcompat/about-compat/aboutCompat.js b/browser/extensions/webcompat/about-compat/aboutCompat.js
new file mode 100644
index 0000000000..e01b853877
--- /dev/null
+++ b/browser/extensions/webcompat/about-compat/aboutCompat.js
@@ -0,0 +1,283 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+/* globals browser */
+
+let availablePatches;
+
+const portToAddon = (function () {
+ let port;
+
+ function connect() {
+ port = browser.runtime.connect({ name: "AboutCompatTab" });
+ port.onMessage.addListener(onMessageFromAddon);
+ port.onDisconnect.addListener(e => {
+ port = undefined;
+ });
+ }
+
+ connect();
+
+ async function send(message) {
+ if (port) {
+ return port.postMessage(message);
+ }
+ return Promise.reject("background script port disconnected");
+ }
+
+ return { send };
+})();
+
+const $ = function (sel) {
+ return document.querySelector(sel);
+};
+
+const DOMContentLoadedPromise = new Promise(resolve => {
+ document.addEventListener(
+ "DOMContentLoaded",
+ () => {
+ resolve();
+ },
+ { once: true }
+ );
+});
+
+Promise.all([
+ browser.runtime.sendMessage("getAllInterventions"),
+ DOMContentLoadedPromise,
+]).then(([info]) => {
+ document.body.addEventListener("click", async evt => {
+ const ele = evt.target;
+ if (ele.nodeName === "BUTTON") {
+ const row = ele.closest("[data-id]");
+ if (row) {
+ evt.preventDefault();
+ ele.disabled = true;
+ const id = row.getAttribute("data-id");
+ try {
+ await browser.runtime.sendMessage({ command: "toggle", id });
+ } catch (_) {
+ ele.disabled = false;
+ }
+ }
+ } else if (ele.classList.contains("tab")) {
+ document.querySelectorAll(".tab").forEach(tab => {
+ tab.classList.remove("active");
+ });
+ ele.classList.add("active");
+ }
+ });
+
+ availablePatches = info;
+ redraw();
+});
+
+function onMessageFromAddon(msg) {
+ const alsoShowHidden = location.hash === "#all";
+
+ if ("interventionsChanged" in msg) {
+ redrawTable($("#interventions"), msg.interventionsChanged, alsoShowHidden);
+ }
+
+ if ("overridesChanged" in msg) {
+ redrawTable($("#overrides"), msg.overridesChanged, alsoShowHidden);
+ }
+
+ if ("shimsChanged" in msg) {
+ updateShimTables(msg.shimsChanged, alsoShowHidden);
+ }
+
+ const id = msg.toggling || msg.toggled;
+ const button = $(`[data-id="${id}"] button`);
+ if (!button) {
+ return;
+ }
+ const active = msg.active;
+ document.l10n.setAttributes(
+ button,
+ active ? "label-disable" : "label-enable"
+ );
+ button.disabled = !!msg.toggling;
+}
+
+function redraw() {
+ if (!availablePatches) {
+ return;
+ }
+ const { overrides, interventions, shims } = availablePatches;
+ const alsoShowHidden = location.hash === "#all";
+ redrawTable($("#overrides"), overrides, alsoShowHidden);
+ redrawTable($("#interventions"), interventions, alsoShowHidden);
+ updateShimTables(shims, alsoShowHidden);
+}
+
+function clearTableAndAddMessage(table, msgId) {
+ table.querySelectorAll("tr").forEach(tr => {
+ tr.remove();
+ });
+
+ const tr = document.createElement("tr");
+ tr.className = "message";
+ tr.id = msgId;
+
+ const td = document.createElement("td");
+ td.setAttribute("colspan", "3");
+ document.l10n.setAttributes(td, msgId);
+ tr.appendChild(td);
+
+ table.appendChild(tr);
+}
+
+function hideMessagesOnTable(table) {
+ table.querySelectorAll("tr.message").forEach(tr => {
+ tr.remove();
+ });
+}
+
+function updateShimTables(shimsChanged, alsoShowHidden) {
+ const tables = document.querySelectorAll("table.shims");
+ if (!tables.length) {
+ return;
+ }
+
+ for (const { bug, disabledReason, hidden, id, name, type } of shimsChanged) {
+ // if any shim is disabled by global pref, all of them are. just show the
+ // "disabled in about:config" message on each shim table in that case.
+ if (disabledReason === "globalPref") {
+ for (const table of tables) {
+ clearTableAndAddMessage(table, "text-disabled-in-about-config");
+ }
+ return;
+ }
+
+ // otherwise, find which table the shim belongs in. if there is none,
+ // ignore the shim (we're not showing it on the UI for whatever reason).
+ const table = document.querySelector(`table.shims#${type}`);
+ if (!table) {
+ continue;
+ }
+
+ // similarly, skip shims hidden from the UI (only for testing, etc).
+ if (!alsoShowHidden && hidden) {
+ continue;
+ }
+
+ // also, hide the shim if it is disabled because it is not meant for this
+ // platform, release (etc) rather than being disabled by pref/about:compat
+ const notApplicable =
+ disabledReason &&
+ disabledReason !== "pref" &&
+ disabledReason !== "session";
+ if (!alsoShowHidden && notApplicable) {
+ continue;
+ }
+
+ // create an updated table-row for the shim
+ const tr = document.createElement("tr");
+ tr.setAttribute("data-id", id);
+
+ let td = document.createElement("td");
+ td.innerText = name;
+ tr.appendChild(td);
+
+ td = document.createElement("td");
+ const a = document.createElement("a");
+ a.href = `https://bugzilla.mozilla.org/show_bug.cgi?id=${bug}`;
+ document.l10n.setAttributes(a, "label-more-information", { bug });
+ a.target = "_blank";
+ td.appendChild(a);
+ tr.appendChild(td);
+
+ td = document.createElement("td");
+ tr.appendChild(td);
+ const button = document.createElement("button");
+ document.l10n.setAttributes(
+ button,
+ disabledReason ? "label-enable" : "label-disable"
+ );
+ td.appendChild(button);
+
+ // is it already in the table?
+ const row = table.querySelector(`tr[data-id="${id}"]`);
+ if (row) {
+ row.replaceWith(tr);
+ } else {
+ table.appendChild(tr);
+ }
+ }
+
+ for (const table of tables) {
+ if (!table.querySelector("tr:not(.message)")) {
+ // no shims? then add a message that none are available for this platform/config
+ clearTableAndAddMessage(table, `text-no-${table.id}`);
+ } else {
+ // otherwise hide any such message, since we have shims on the list
+ hideMessagesOnTable(table);
+ }
+ }
+}
+
+function redrawTable(table, data, alsoShowHidden) {
+ const df = document.createDocumentFragment();
+ table.querySelectorAll("tr").forEach(tr => {
+ tr.remove();
+ });
+
+ let noEntriesMessage;
+ if (data === false) {
+ noEntriesMessage = "text-disabled-in-about-config";
+ } else if (data.length === 0) {
+ noEntriesMessage = `text-no-${table.id}`;
+ }
+
+ if (noEntriesMessage) {
+ const tr = document.createElement("tr");
+ df.appendChild(tr);
+
+ const td = document.createElement("td");
+ td.setAttribute("colspan", "3");
+ document.l10n.setAttributes(td, noEntriesMessage);
+ tr.appendChild(td);
+
+ table.appendChild(df);
+ return;
+ }
+
+ for (const row of data) {
+ if (row.hidden && !alsoShowHidden) {
+ continue;
+ }
+
+ const tr = document.createElement("tr");
+ tr.setAttribute("data-id", row.id);
+ df.appendChild(tr);
+
+ let td = document.createElement("td");
+ td.innerText = row.domain;
+ tr.appendChild(td);
+
+ td = document.createElement("td");
+ const a = document.createElement("a");
+ const bug = row.bug;
+ a.href = `https://bugzilla.mozilla.org/show_bug.cgi?id=${bug}`;
+ document.l10n.setAttributes(a, "label-more-information", { bug });
+ a.target = "_blank";
+ td.appendChild(a);
+ tr.appendChild(td);
+
+ td = document.createElement("td");
+ tr.appendChild(td);
+ const button = document.createElement("button");
+ document.l10n.setAttributes(
+ button,
+ row.active ? "label-disable" : "label-enable"
+ );
+ td.appendChild(button);
+ }
+ table.appendChild(df);
+}
+
+window.onhashchange = redraw;