Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Unified Diff: js/desktop-options.js

Issue 29705690: Issue 6310 - Start using JavaScript modularization tool (Closed)
Patch Set: Created Feb. 23, 2018, 9:24 a.m.
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « README.md ('k') | package.json » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: js/desktop-options.js
===================================================================
rename from desktop-options.js
rename to js/desktop-options.js
--- a/desktop-options.js
+++ b/js/desktop-options.js
@@ -15,1462 +15,1460 @@
* along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
*/
/* globals checkShareResource, getDocLink, i18nFormatDateTime, openSharePopup,
setLinks, E */
"use strict";
+let subscriptionsMap = Object.create(null);
+let filtersMap = Object.create(null);
+let collections = Object.create(null);
+let acceptableAdsUrl = null;
+let acceptableAdsPrivacyUrl = null;
+let isCustomFiltersLoaded = false;
+let {getMessage} = browser.i18n;
+let {setElementText} = ext.i18n;
+let customFilters = [];
+let filterErrors = new Map([
+ ["synchronize_invalid_url",
+ "options_filterList_lastDownload_invalidURL"],
+ ["synchronize_connection_error",
+ "options_filterList_lastDownload_connectionError"],
+ ["synchronize_invalid_data",
+ "options_filterList_lastDownload_invalidData"],
+ ["synchronize_checksum_mismatch",
+ "options_filterList_lastDownload_checksumMismatch"]
+]);
+const timestampUI = Symbol();
+const whitelistedDomainRegexp = /^@@\|\|([^/:]+)\^\$document$/;
+// Period of time in milliseconds
+const minuteInMs = 60000;
+const hourInMs = 3600000;
+const fullDayInMs = 86400000;
+
+function Collection(details)
{
- let subscriptionsMap = Object.create(null);
- let filtersMap = Object.create(null);
- let collections = Object.create(null);
- let acceptableAdsUrl = null;
- let acceptableAdsPrivacyUrl = null;
- let isCustomFiltersLoaded = false;
- let {getMessage} = browser.i18n;
- let {setElementText} = ext.i18n;
- let customFilters = [];
- let filterErrors = new Map([
- ["synchronize_invalid_url",
- "options_filterList_lastDownload_invalidURL"],
- ["synchronize_connection_error",
- "options_filterList_lastDownload_connectionError"],
- ["synchronize_invalid_data",
- "options_filterList_lastDownload_invalidData"],
- ["synchronize_checksum_mismatch",
- "options_filterList_lastDownload_checksumMismatch"]
- ]);
- const timestampUI = Symbol();
- const whitelistedDomainRegexp = /^@@\|\|([^/:]+)\^\$document$/;
- // Period of time in milliseconds
- const minuteInMs = 60000;
- const hourInMs = 3600000;
- const fullDayInMs = 86400000;
+ this.details = details;
+ this.items = [];
+}
+
+Collection.prototype._setEmpty = function(table, detail, removeEmpty)
+{
+ if (removeEmpty)
+ {
+ let placeholders = table.querySelectorAll(".empty-placeholder");
+ for (let placeholder of placeholders)
+ table.removeChild(placeholder);
+
+ execAction(detail.removeEmptyAction, table);
+ }
+ else
+ {
+ let {emptyTexts = []} = detail;
+ for (let text of emptyTexts)
+ {
+ let placeholder = document.createElement("li");
+ placeholder.className = "empty-placeholder";
+ placeholder.textContent = getMessage(text);
+ table.appendChild(placeholder);
+ }
+
+ execAction(detail.setEmptyAction, table);
+ }
+};
+
+Collection.prototype._createElementQuery = function(item)
+{
+ let access = (item.url || item.text).replace(/'/g, "\\'");
+ return function(container)
+ {
+ return container.querySelector("[data-access='" + access + "']");
+ };
+};
+
+Collection.prototype._getItemTitle = function(item, i)
+{
+ if (this.details[i].getTitleFunction)
+ return this.details[i].getTitleFunction(item);
+ return item.title || item.url || item.text;
+};
+
+Collection.prototype._sortItems = function()
+{
+ this.items.sort((a, b) =>
+ {
+ // Make sure that Acceptable Ads is always last, since it cannot be
+ // disabled, but only be removed. That way it's grouped together with
+ // the "Own filter list" which cannot be disabled either at the bottom
+ // of the filter lists in the Advanced tab.
+ if (isAcceptableAds(a.url))
+ return 1;
+ if (isAcceptableAds(b.url))
+ return -1;
+
+ // Make sure that newly added entries always appear on top in descending
+ // chronological order
+ let aTimestamp = a[timestampUI] || 0;
+ let bTimestamp = b[timestampUI] || 0;
+ if (aTimestamp || bTimestamp)
+ return bTimestamp - aTimestamp;
+
+ let aTitle = this._getItemTitle(a, 0).toLowerCase();
+ let bTitle = this._getItemTitle(b, 0).toLowerCase();
+ return aTitle.localeCompare(bTitle);
+ });
+};
+
+Collection.prototype.addItem = function(item)
+{
+ if (this.items.indexOf(item) >= 0)
+ return;
+
+ this.items.push(item);
+ this._sortItems();
+ for (let j = 0; j < this.details.length; j++)
+ {
+ let detail = this.details[j];
+ let table = E(detail.id);
+ let template = table.querySelector("template");
+ let listItem = document.createElement("li");
+ listItem.appendChild(document.importNode(template.content, true));
+ listItem.setAttribute("aria-label", this._getItemTitle(item, j));
+ listItem.setAttribute("data-access", item.url || item.text);
+ listItem.setAttribute("role", "section");
+
+ let tooltip = listItem.querySelector("[data-tooltip]");
+ if (tooltip)
+ {
+ let tooltipId = tooltip.getAttribute("data-tooltip");
+ tooltipId = tooltipId.replace("%value%", item.recommended);
+ if (getMessage(tooltipId))
+ {
+ tooltip.setAttribute("data-tooltip", tooltipId);
+ }
+ }
+
+ for (let control of listItem.querySelectorAll(".control"))
+ {
+ if (control.hasAttribute("title"))
+ {
+ let titleValue = getMessage(control.getAttribute("title"));
+ control.setAttribute("title", titleValue);
+ }
+ }
+
+ this._setEmpty(table, detail, true);
+ if (table.children.length > 0)
+ table.insertBefore(listItem, table.children[this.items.indexOf(item)]);
+ else
+ table.appendChild(listItem);
+
+ this.updateItem(item);
+ }
+ return length;
+};
+
+Collection.prototype.removeItem = function(item)
+{
+ let index = this.items.indexOf(item);
+ if (index == -1)
+ return;
+
+ this.items.splice(index, 1);
+ let getListElement = this._createElementQuery(item);
+ for (let detail of this.details)
+ {
+ let table = E(detail.id);
+ let element = getListElement(table);
+
+ // Element gets removed so make sure to handle focus appropriately
+ let control = element.querySelector(".control");
+ if (control && control == document.activeElement)
+ {
+ if (!focusNextElement(element.parentElement, control))
+ {
+ // Fall back to next focusable element within same tab or dialog
+ let focusableElement = element.parentElement;
+ while (focusableElement)
+ {
+ if (focusableElement.classList.contains("tab-content") ||
+ focusableElement.classList.contains("dialog-content"))
+ break;
+
+ focusableElement = focusableElement.parentElement;
+ }
+ focusNextElement(focusableElement || document, control);
+ }
+ }
+
+ element.parentElement.removeChild(element);
+ if (this.items.length == 0)
+ this._setEmpty(table, detail);
+ }
+};
+
+Collection.prototype.updateItem = function(item)
+{
+ let oldIndex = this.items.indexOf(item);
+ this._sortItems();
+ let access = (item.url || item.text).replace(/'/g, "\\'");
+ for (let i = 0; i < this.details.length; i++)
+ {
+ let table = E(this.details[i].id);
+ let element = table.querySelector("[data-access='" + access + "']");
+ if (!element)
+ continue;
- function Collection(details)
+ let title = this._getItemTitle(item, i);
+ let displays = element.querySelectorAll("[data-display]");
+ for (let j = 0; j < displays.length; j++)
+ {
+ if (item[displays[j].dataset.display])
+ displays[j].textContent = item[displays[j].dataset.display];
+ else
+ displays[j].textContent = title;
+ }
+
+ element.setAttribute("aria-label", title);
+ if (this.details[i].searchable)
+ element.setAttribute("data-search", title.toLowerCase());
+ let controls = element.querySelectorAll(".control[role='checkbox']");
+ for (let control of controls)
+ {
+ control.setAttribute("aria-checked", item.disabled == false);
+ if (isAcceptableAds(item.url) && this == collections.filterLists)
+ control.disabled = true;
+ }
+
+ let lastUpdateElement = element.querySelector(".last-update");
+ if (lastUpdateElement)
+ {
+ let message = element.querySelector(".message");
+ if (item.isDownloading)
+ {
+ let text = getMessage("options_filterList_lastDownload_inProgress");
+ message.textContent = text;
+ element.classList.add("show-message");
+ }
+ else if (item.downloadStatus != "synchronize_ok")
+ {
+ let error = filterErrors.get(item.downloadStatus);
+ if (error)
+ message.textContent = getMessage(error);
+ else
+ message.textContent = item.downloadStatus;
+ element.classList.add("show-message");
+ }
+ else if (item.lastDownload > 0)
+ {
+ let lastUpdate = item.lastDownload * 1000;
+ let sinceUpdate = Date.now() - lastUpdate;
+ if (sinceUpdate > fullDayInMs)
+ {
+ let lastUpdateDate = new Date(item.lastDownload * 1000);
+ let monthName = lastUpdateDate.toLocaleString(undefined,
+ {month: "short"});
+ let day = lastUpdateDate.getDate();
+ day = day < 10 ? "0" + day : day;
+ lastUpdateElement.textContent = day + " " + monthName + " " +
+ lastUpdateDate.getFullYear();
+ }
+ else if (sinceUpdate > hourInMs)
+ {
+ lastUpdateElement.textContent =
+ getMessage("options_filterList_hours");
+ }
+ else if (sinceUpdate > minuteInMs)
+ {
+ lastUpdateElement.textContent =
+ getMessage("options_filterList_minutes");
+ }
+ else
+ {
+ lastUpdateElement.textContent =
+ getMessage("options_filterList_now");
+ }
+ element.classList.remove("show-message");
+ }
+ }
+
+ let websiteElement = element.querySelector(".context-menu .website");
+ if (websiteElement)
+ {
+ if (item.homepage)
+ websiteElement.setAttribute("href", item.homepage);
+ else
+ websiteElement.setAttribute("aria-hidden", true);
+ }
+
+ let sourceElement = element.querySelector(".context-menu .source");
+ if (sourceElement)
+ sourceElement.setAttribute("href", item.url);
+
+ let newIndex = this.items.indexOf(item);
+ if (oldIndex != newIndex)
+ table.insertBefore(element, table.childNodes[newIndex]);
+ }
+};
+
+Collection.prototype.clearAll = function()
+{
+ this.items = [];
+ for (let detail of this.details)
{
- this.details = details;
- this.items = [];
+ let table = E(detail.id);
+ let element = table.firstChild;
+ while (element)
+ {
+ if (element.tagName == "LI" && !element.classList.contains("static"))
+ table.removeChild(element);
+ element = element.nextElementSibling;
+ }
+
+ this._setEmpty(table, detail);
+ }
+};
+
+function focusNextElement(container, currentElement)
+{
+ let focusables = container.querySelectorAll("a, button, input, .control");
+ focusables = Array.prototype.slice.call(focusables);
+ let index = focusables.indexOf(currentElement);
+ index += (index == focusables.length - 1) ? -1 : 1;
+
+ let nextElement = focusables[index];
+ if (!nextElement)
+ return false;
+
+ nextElement.focus();
+ return true;
+}
+
+collections.protection = new Collection([
+ {
+ id: "recommend-protection-list-table"
+ }
+]);
+collections.langs = new Collection([
+ {
+ id: "blocking-languages-table",
+ emptyTexts: ["options_language_empty"],
+ getTitleFunction: getLanguageTitle
+ }
+]);
+collections.allLangs = new Collection([
+ {
+ id: "all-lang-table-add",
+ emptyTexts: ["options_dialog_language_other_empty"],
+ getTitleFunction: getLanguageTitle
+ }
+]);
+collections.more = new Collection([
+ {
+ id: "more-list-table",
+ setEmptyAction: "hide-more-filters-section",
+ removeEmptyAction: "show-more-filters-section"
+ }
+]);
+collections.whitelist = new Collection([
+ {
+ id: "whitelisting-table",
+ emptyTexts: ["options_whitelist_empty_1", "options_whitelist_empty_2"]
+ }
+]);
+collections.filterLists = new Collection([
+ {
+ id: "all-filter-lists-table",
+ emptyTexts: ["options_filterList_empty"]
+ }
+]);
+
+function addSubscription(subscription)
+{
+ let {disabled} = subscription;
+ let collection = null;
+ if (subscription.recommended)
+ {
+ if (subscription.recommended == "ads")
+ {
+ if (disabled == false)
+ collection = collections.langs;
+
+ collections.allLangs.addItem(subscription);
+ }
+ else
+ {
+ collection = collections.protection;
+ }
+ }
+ else if (!isAcceptableAds(subscription.url) && disabled == false)
+ {
+ collection = collections.more;
}
- Collection.prototype._setEmpty = function(table, detail, removeEmpty)
+ if (collection)
+ collection.addItem(subscription);
+
+ subscriptionsMap[subscription.url] = subscription;
+ updateTooltips();
+}
+
+function updateSubscription(subscription)
+{
+ for (let name in collections)
+ collections[name].updateItem(subscription);
+
+ if (subscription.recommended == "ads")
{
- if (removeEmpty)
+ if (subscription.disabled)
+ collections.langs.removeItem(subscription);
+ else
+ collections.langs.addItem(subscription);
+ }
+ else if (!subscription.recommended && !isAcceptableAds(subscription.url))
+ {
+ if (subscription.disabled == false)
{
- let placeholders = table.querySelectorAll(".empty-placeholder");
- for (let placeholder of placeholders)
- table.removeChild(placeholder);
-
- execAction(detail.removeEmptyAction, table);
+ collections.more.addItem(subscription);
+ updateTooltips();
}
else
{
- let {emptyTexts = []} = detail;
- for (let text of emptyTexts)
- {
- let placeholder = document.createElement("li");
- placeholder.className = "empty-placeholder";
- placeholder.textContent = getMessage(text);
- table.appendChild(placeholder);
- }
+ collections.more.removeItem(subscription);
+ }
+ }
+}
- execAction(detail.setEmptyAction, table);
+function updateFilter(filter)
+{
+ let match = filter.text.match(whitelistedDomainRegexp);
+ if (match && !filtersMap[filter.text])
+ {
+ filter.title = match[1];
+ collections.whitelist.addItem(filter);
+ if (isCustomFiltersLoaded)
+ {
+ let text = getMessage("options_whitelist_notification", [filter.title]);
+ showNotification(text);
}
- };
-
- Collection.prototype._createElementQuery = function(item)
+ }
+ else
{
- let access = (item.url || item.text).replace(/'/g, "\\'");
- return function(container)
- {
- return container.querySelector("[data-access='" + access + "']");
- };
- };
+ customFilters.push(filter.text);
+ if (isCustomFiltersLoaded)
+ updateCustomFiltersUi();
+ }
+
+ filtersMap[filter.text] = filter;
+}
+
+function loadCustomFilters(filters)
+{
+ for (let filter of filters)
+ updateFilter(filter);
+
+ setCustomFiltersView("read");
+ isCustomFiltersLoaded = true;
+}
+
+function removeCustomFilter(text)
+{
+ let index = customFilters.indexOf(text);
+ if (index >= 0)
+ customFilters.splice(index, 1);
- Collection.prototype._getItemTitle = function(item, i)
- {
- if (this.details[i].getTitleFunction)
- return this.details[i].getTitleFunction(item);
- return item.title || item.url || item.text;
- };
+ updateCustomFiltersUi();
+}
+
+function updateCustomFiltersUi()
+{
+ let customFiltersListElement = E("custom-filters-raw");
+ customFiltersListElement.value = customFilters.join("\n");
+}
- Collection.prototype._sortItems = function()
- {
- this.items.sort((a, b) =>
+function getLanguageTitle(item)
+{
+ let title = item.specialization;
+ if (item.originalTitle && item.originalTitle.indexOf("+EasyList") > -1)
+ title += " + " + getMessage("options_english");
+ return title;
+}
+
+function loadRecommendations()
+{
+ fetch("subscriptions.xml")
+ .then((response) =>
+ {
+ return response.text();
+ })
+ .then((text) =>
{
- // Make sure that Acceptable Ads is always last, since it cannot be
- // disabled, but only be removed. That way it's grouped together with
- // the "Own filter list" which cannot be disabled either at the bottom
- // of the filter lists in the Advanced tab.
- if (isAcceptableAds(a.url))
- return 1;
- if (isAcceptableAds(b.url))
- return -1;
+ let doc = new DOMParser().parseFromString(text, "application/xml");
+ let elements = doc.documentElement.getElementsByTagName("subscription");
+ for (let element of elements)
+ {
+ let type = element.getAttribute("type");
+ let subscription = {
+ disabled: true,
+ downloadStatus: null,
+ homepage: null,
+ specialization: element.getAttribute("specialization"),
+ originalTitle: element.getAttribute("title"),
+ recommended: type,
+ url: element.getAttribute("url")
+ };
- // Make sure that newly added entries always appear on top in descending
- // chronological order
- let aTimestamp = a[timestampUI] || 0;
- let bTimestamp = b[timestampUI] || 0;
- if (aTimestamp || bTimestamp)
- return bTimestamp - aTimestamp;
+ if (subscription.recommended != "ads")
+ {
+ type = type.replace(/\W/g, "_");
+ subscription.title = getMessage("common_feature_" +
+ type + "_title");
+ }
+
+ addSubscription(subscription);
+ }
+ });
+}
- let aTitle = this._getItemTitle(a, 0).toLowerCase();
- let bTitle = this._getItemTitle(b, 0).toLowerCase();
- return aTitle.localeCompare(bTitle);
- });
- };
+function findParentData(element, dataName, returnElement)
+{
+ element = element.closest(`[data-${dataName}]`);
+ if (!element)
+ return null;
+ if (returnElement)
+ return element;
+ return element.getAttribute(`data-${dataName}`);
+}
- Collection.prototype.addItem = function(item)
+function sendMessageHandleErrors(message, onSuccess)
+{
+ browser.runtime.sendMessage(message, (errors) =>
{
- if (this.items.indexOf(item) >= 0)
- return;
+ if (errors.length > 0)
+ alert(errors.join("\n"));
+ else if (onSuccess)
+ onSuccess();
+ });
+}
+
+function switchTab(id)
+{
+ location.hash = id;
+}
+
+function execAction(action, element)
+{
+ if (element.getAttribute("aria-disabled") == "true")
+ return;
- this.items.push(item);
- this._sortItems();
- for (let j = 0; j < this.details.length; j++)
- {
- let detail = this.details[j];
- let table = E(detail.id);
- let template = table.querySelector("template");
- let listItem = document.createElement("li");
- listItem.appendChild(document.importNode(template.content, true));
- listItem.setAttribute("aria-label", this._getItemTitle(item, j));
- listItem.setAttribute("data-access", item.url || item.text);
- listItem.setAttribute("role", "section");
-
- let tooltip = listItem.querySelector("[data-tooltip]");
- if (tooltip)
+ switch (action)
+ {
+ case "add-domain-exception":
+ addWhitelistedDomain();
+ break;
+ case "add-language-subscription":
+ addEnableSubscription(findParentData(element, "access", false));
+ break;
+ case "add-predefined-subscription": {
+ let dialog = E("dialog-content-predefined");
+ let title = dialog.querySelector("h3").textContent;
+ let url = dialog.querySelector(".url").textContent;
+ addEnableSubscription(url, title);
+ closeDialog();
+ break;
+ }
+ case "cancel-custom-filters":
+ setCustomFiltersView("read");
+ break;
+ case "change-language-subscription":
+ for (let key in subscriptionsMap)
{
- let tooltipId = tooltip.getAttribute("data-tooltip");
- tooltipId = tooltipId.replace("%value%", item.recommended);
- if (getMessage(tooltipId))
+ let subscription = subscriptionsMap[key];
+ let subscriptionType = subscription.recommended;
+ if (subscriptionType == "ads" && subscription.disabled == false)
{
- tooltip.setAttribute("data-tooltip", tooltipId);
+ browser.runtime.sendMessage({
+ type: "subscriptions.remove",
+ url: subscription.url
+ });
+ browser.runtime.sendMessage({
+ type: "subscriptions.add",
+ url: findParentData(element, "access", false)
+ });
+ break;
}
}
-
- for (let control of listItem.querySelectorAll(".control"))
- {
- if (control.hasAttribute("title"))
- {
- let titleValue = getMessage(control.getAttribute("title"));
- control.setAttribute("title", titleValue);
- }
- }
-
- this._setEmpty(table, detail, true);
- if (table.children.length > 0)
- table.insertBefore(listItem, table.children[this.items.indexOf(item)]);
- else
- table.appendChild(listItem);
-
- this.updateItem(item);
+ break;
+ case "close-dialog":
+ closeDialog();
+ break;
+ case "edit-custom-filters":
+ setCustomFiltersView("write");
+ break;
+ case "hide-more-filters-section":
+ E("more-filters").setAttribute("aria-hidden", true);
+ break;
+ case "hide-notification":
+ hideNotification();
+ break;
+ case "import-subscription": {
+ let url = E("blockingList-textbox").value;
+ addEnableSubscription(url);
+ closeDialog();
+ break;
+ }
+ case "open-context-menu": {
+ let listItem = findParentData(element, "access", true);
+ if (listItem && !listItem.classList.contains("show-context-menu"))
+ listItem.classList.add("show-context-menu");
+ break;
}
- return length;
- };
-
- Collection.prototype.removeItem = function(item)
- {
- let index = this.items.indexOf(item);
- if (index == -1)
- return;
-
- this.items.splice(index, 1);
- let getListElement = this._createElementQuery(item);
- for (let detail of this.details)
- {
- let table = E(detail.id);
- let element = getListElement(table);
-
- // Element gets removed so make sure to handle focus appropriately
- let control = element.querySelector(".control");
- if (control && control == document.activeElement)
+ case "open-dialog": {
+ let dialog = findParentData(element, "dialog", false);
+ openDialog(dialog);
+ break;
+ }
+ case "remove-filter":
+ browser.runtime.sendMessage({
+ type: "filters.remove",
+ text: findParentData(element, "access", false)
+ });
+ break;
+ case "remove-subscription":
+ browser.runtime.sendMessage({
+ type: "subscriptions.remove",
+ url: findParentData(element, "access", false)
+ });
+ break;
+ case "save-custom-filters":
+ sendMessageHandleErrors({
+ type: "filters.importRaw",
+ text: E("custom-filters-raw").value,
+ removeExisting: true
+ },
+ () =>
{
- if (!focusNextElement(element.parentElement, control))
- {
- // Fall back to next focusable element within same tab or dialog
- let focusableElement = element.parentElement;
- while (focusableElement)
- {
- if (focusableElement.classList.contains("tab-content") ||
- focusableElement.classList.contains("dialog-content"))
- break;
-
- focusableElement = focusableElement.parentElement;
- }
- focusNextElement(focusableElement || document, control);
- }
+ setCustomFiltersView("read");
+ });
+ break;
+ case "show-more-filters-section":
+ E("more-filters").setAttribute("aria-hidden", false);
+ break;
+ case "switch-acceptable-ads":
+ let value = element.value || element.dataset.value;
+ // User check the checkbox
+ let shouldCheck = element.getAttribute("aria-checked") != "true";
+ let installAcceptableAds = false;
+ let installAcceptableAdsPrivacy = false;
+ // Acceptable Ads checkbox clicked
+ if (value == "ads")
+ {
+ installAcceptableAds = shouldCheck;
}
-
- element.parentElement.removeChild(element);
- if (this.items.length == 0)
- this._setEmpty(table, detail);
- }
- };
-
- Collection.prototype.updateItem = function(item)
- {
- let oldIndex = this.items.indexOf(item);
- this._sortItems();
- let access = (item.url || item.text).replace(/'/g, "\\'");
- for (let i = 0; i < this.details.length; i++)
- {
- let table = E(this.details[i].id);
- let element = table.querySelector("[data-access='" + access + "']");
- if (!element)
- continue;
-
- let title = this._getItemTitle(item, i);
- let displays = element.querySelectorAll("[data-display]");
- for (let j = 0; j < displays.length; j++)
+ // Privacy Friendly Acceptable Ads checkbox clicked
+ else
{
- if (item[displays[j].dataset.display])
- displays[j].textContent = item[displays[j].dataset.display];
- else
- displays[j].textContent = title;
+ installAcceptableAdsPrivacy = shouldCheck;
+ installAcceptableAds = !shouldCheck;
}
- element.setAttribute("aria-label", title);
- if (this.details[i].searchable)
- element.setAttribute("data-search", title.toLowerCase());
- let controls = element.querySelectorAll(".control[role='checkbox']");
- for (let control of controls)
- {
- control.setAttribute("aria-checked", item.disabled == false);
- if (isAcceptableAds(item.url) && this == collections.filterLists)
- control.disabled = true;
- }
-
- let lastUpdateElement = element.querySelector(".last-update");
- if (lastUpdateElement)
+ browser.runtime.sendMessage({
+ type: installAcceptableAds ? "subscriptions.add" :
+ "subscriptions.remove",
+ url: acceptableAdsUrl
+ });
+ browser.runtime.sendMessage({
+ type: installAcceptableAdsPrivacy ? "subscriptions.add" :
+ "subscriptions.remove",
+ url: acceptableAdsPrivacyUrl
+ });
+ break;
+ case "switch-tab":
+ switchTab(element.getAttribute("href").substr(1));
+ break;
+ case "toggle-disable-subscription":
+ browser.runtime.sendMessage({
+ type: "subscriptions.toggle",
+ keepInstalled: true,
+ url: findParentData(element, "access", false)
+ });
+ break;
+ case "toggle-pref":
+ browser.runtime.sendMessage({
+ type: "prefs.toggle",
+ key: findParentData(element, "pref", false)
+ });
+ break;
+ case "toggle-remove-subscription":
+ let subscriptionUrl = findParentData(element, "access", false);
+ if (element.getAttribute("aria-checked") == "true")
{
- let message = element.querySelector(".message");
- if (item.isDownloading)
- {
- let text = getMessage("options_filterList_lastDownload_inProgress");
- message.textContent = text;
- element.classList.add("show-message");
- }
- else if (item.downloadStatus != "synchronize_ok")
- {
- let error = filterErrors.get(item.downloadStatus);
- if (error)
- message.textContent = getMessage(error);
- else
- message.textContent = item.downloadStatus;
- element.classList.add("show-message");
- }
- else if (item.lastDownload > 0)
- {
- let lastUpdate = item.lastDownload * 1000;
- let sinceUpdate = Date.now() - lastUpdate;
- if (sinceUpdate > fullDayInMs)
- {
- let lastUpdateDate = new Date(item.lastDownload * 1000);
- let monthName = lastUpdateDate.toLocaleString(undefined,
- {month: "short"});
- let day = lastUpdateDate.getDate();
- day = day < 10 ? "0" + day : day;
- lastUpdateElement.textContent = day + " " + monthName + " " +
- lastUpdateDate.getFullYear();
- }
- else if (sinceUpdate > hourInMs)
- {
- lastUpdateElement.textContent =
- getMessage("options_filterList_hours");
- }
- else if (sinceUpdate > minuteInMs)
- {
- lastUpdateElement.textContent =
- getMessage("options_filterList_minutes");
- }
- else
- {
- lastUpdateElement.textContent =
- getMessage("options_filterList_now");
- }
- element.classList.remove("show-message");
- }
+ browser.runtime.sendMessage({
+ type: "subscriptions.remove",
+ url: subscriptionUrl
+ });
}
-
- let websiteElement = element.querySelector(".context-menu .website");
- if (websiteElement)
- {
- if (item.homepage)
- websiteElement.setAttribute("href", item.homepage);
- else
- websiteElement.setAttribute("aria-hidden", true);
- }
-
- let sourceElement = element.querySelector(".context-menu .source");
- if (sourceElement)
- sourceElement.setAttribute("href", item.url);
-
- let newIndex = this.items.indexOf(item);
- if (oldIndex != newIndex)
- table.insertBefore(element, table.childNodes[newIndex]);
- }
- };
+ else
+ addEnableSubscription(subscriptionUrl);
+ break;
+ case "update-all-subscriptions":
+ browser.runtime.sendMessage({
+ type: "subscriptions.update"
+ });
+ break;
+ case "update-subscription":
+ browser.runtime.sendMessage({
+ type: "subscriptions.update",
+ url: findParentData(element, "access", false)
+ });
+ break;
+ case "validate-import-subscription":
+ let form = findParentData(element, "validation", true);
+ if (!form)
+ return;
- Collection.prototype.clearAll = function()
- {
- this.items = [];
- for (let detail of this.details)
- {
- let table = E(detail.id);
- let element = table.firstChild;
- while (element)
+ if (form.checkValidity())
{
- if (element.tagName == "LI" && !element.classList.contains("static"))
- table.removeChild(element);
- element = element.nextElementSibling;
- }
-
- this._setEmpty(table, detail);
- }
- };
-
- function focusNextElement(container, currentElement)
- {
- let focusables = container.querySelectorAll("a, button, input, .control");
- focusables = Array.prototype.slice.call(focusables);
- let index = focusables.indexOf(currentElement);
- index += (index == focusables.length - 1) ? -1 : 1;
-
- let nextElement = focusables[index];
- if (!nextElement)
- return false;
-
- nextElement.focus();
- return true;
- }
-
- collections.protection = new Collection([
- {
- id: "recommend-protection-list-table"
- }
- ]);
- collections.langs = new Collection([
- {
- id: "blocking-languages-table",
- emptyTexts: ["options_language_empty"],
- getTitleFunction: getLanguageTitle
- }
- ]);
- collections.allLangs = new Collection([
- {
- id: "all-lang-table-add",
- emptyTexts: ["options_dialog_language_other_empty"],
- getTitleFunction: getLanguageTitle
- }
- ]);
- collections.more = new Collection([
- {
- id: "more-list-table",
- setEmptyAction: "hide-more-filters-section",
- removeEmptyAction: "show-more-filters-section"
- }
- ]);
- collections.whitelist = new Collection([
- {
- id: "whitelisting-table",
- emptyTexts: ["options_whitelist_empty_1", "options_whitelist_empty_2"]
- }
- ]);
- collections.filterLists = new Collection([
- {
- id: "all-filter-lists-table",
- emptyTexts: ["options_filterList_empty"]
- }
- ]);
-
- function addSubscription(subscription)
- {
- let {disabled} = subscription;
- let collection = null;
- if (subscription.recommended)
- {
- if (subscription.recommended == "ads")
- {
- if (disabled == false)
- collection = collections.langs;
-
- collections.allLangs.addItem(subscription);
+ addEnableSubscription(E("import-list-url").value,
+ E("import-list-title").value);
+ form.reset();
+ closeDialog();
}
else
{
- collection = collections.protection;
+ form.querySelector(":invalid").focus();
}
- }
- else if (!isAcceptableAds(subscription.url) && disabled == false)
- {
- collection = collections.more;
- }
+ break;
+ }
+}
- if (collection)
- collection.addItem(subscription);
-
- subscriptionsMap[subscription.url] = subscription;
- updateTooltips();
- }
-
- function updateSubscription(subscription)
+function setCustomFiltersView(mode)
+{
+ let customFiltersElement = E("custom-filters-raw");
+ updateCustomFiltersUi();
+ if (mode == "read")
{
- for (let name in collections)
- collections[name].updateItem(subscription);
-
- if (subscription.recommended == "ads")
+ customFiltersElement.disabled = true;
+ if (!customFiltersElement.value)
{
- if (subscription.disabled)
- collections.langs.removeItem(subscription);
- else
- collections.langs.addItem(subscription);
- }
- else if (!subscription.recommended && !isAcceptableAds(subscription.url))
- {
- if (subscription.disabled == false)
- {
- collections.more.addItem(subscription);
- updateTooltips();
- }
- else
- {
- collections.more.removeItem(subscription);
- }
+ setCustomFiltersView("empty");
+ return;
}
}
-
- function updateFilter(filter)
+ else if (mode == "write")
{
- let match = filter.text.match(whitelistedDomainRegexp);
- if (match && !filtersMap[filter.text])
- {
- filter.title = match[1];
- collections.whitelist.addItem(filter);
- if (isCustomFiltersLoaded)
- {
- let text = getMessage("options_whitelist_notification", [filter.title]);
- showNotification(text);
- }
- }
- else
- {
- customFilters.push(filter.text);
- if (isCustomFiltersLoaded)
- updateCustomFiltersUi();
- }
-
- filtersMap[filter.text] = filter;
- }
-
- function loadCustomFilters(filters)
- {
- for (let filter of filters)
- updateFilter(filter);
-
- setCustomFiltersView("read");
- isCustomFiltersLoaded = true;
+ customFiltersElement.disabled = false;
}
- function removeCustomFilter(text)
- {
- let index = customFilters.indexOf(text);
- if (index >= 0)
- customFilters.splice(index, 1);
-
- updateCustomFiltersUi();
- }
+ E("custom-filters").dataset.mode = mode;
+}
- function updateCustomFiltersUi()
- {
- let customFiltersListElement = E("custom-filters-raw");
- customFiltersListElement.value = customFilters.join("\n");
- }
+function onClick(e)
+{
+ let context = document.querySelector(".show-context-menu");
+ if (context)
+ context.classList.remove("show-context-menu");
- function getLanguageTitle(item)
- {
- let title = item.specialization;
- if (item.originalTitle && item.originalTitle.indexOf("+EasyList") > -1)
- title += " + " + getMessage("options_english");
- return title;
- }
+ let actions = findParentData(e.target, "action", false);
+ if (!actions)
+ return;
- function loadRecommendations()
+ actions = actions.split(",");
+ for (let action of actions)
{
- fetch("subscriptions.xml")
- .then((response) =>
- {
- return response.text();
- })
- .then((text) =>
- {
- let doc = new DOMParser().parseFromString(text, "application/xml");
- let elements = doc.documentElement.getElementsByTagName("subscription");
- for (let element of elements)
- {
- let type = element.getAttribute("type");
- let subscription = {
- disabled: true,
- downloadStatus: null,
- homepage: null,
- specialization: element.getAttribute("specialization"),
- originalTitle: element.getAttribute("title"),
- recommended: type,
- url: element.getAttribute("url")
- };
+ execAction(action, e.target);
+ }
+}
- if (subscription.recommended != "ads")
- {
- type = type.replace(/\W/g, "_");
- subscription.title = getMessage("common_feature_" +
- type + "_title");
- }
+function getKey(e)
+{
+ // e.keyCode has been deprecated so we attempt to use e.key
+ if ("key" in e)
+ return e.key;
+ return getKey.keys[e.keyCode];
+}
+getKey.keys = {
+ 9: "Tab",
+ 13: "Enter",
+ 27: "Escape",
+ 37: "ArrowLeft",
+ 38: "ArrowUp",
+ 39: "ArrowRight",
+ 40: "ArrowDown"
+};
- addSubscription(subscription);
- }
- });
- }
+function onKeyUp(e)
+{
+ let key = getKey(e);
+ let element = document.activeElement;
+ if (!key || !element)
+ return;
- function findParentData(element, dataName, returnElement)
- {
- element = element.closest(`[data-${dataName}]`);
- if (!element)
- return null;
- if (returnElement)
- return element;
- return element.getAttribute(`data-${dataName}`);
- }
+ let container = findParentData(element, "action", true);
+ if (!container || !container.hasAttribute("data-keys"))
+ return;
- function sendMessageHandleErrors(message, onSuccess)
+ let keys = container.getAttribute("data-keys").split(" ");
+ if (keys.indexOf(key) < 0)
+ return;
+
+ if (element.getAttribute("role") == "tab")
{
- browser.runtime.sendMessage(message, (errors) =>
- {
- if (errors.length > 0)
- alert(errors.join("\n"));
- else if (onSuccess)
- onSuccess();
- });
- }
-
- function switchTab(id)
- {
- location.hash = id;
+ let parent = element.parentElement;
+ if (key == "ArrowLeft" || key == "ArrowUp")
+ parent = parent.previousElementSibling || container.lastElementChild;
+ else if (key == "ArrowRight" || key == "ArrowDown")
+ parent = parent.nextElementSibling || container.firstElementChild;
+ element = parent.firstElementChild;
}
- function execAction(action, element)
+ let actions = container.getAttribute("data-action").split(",");
+ for (let action of actions)
+ {
+ execAction(action, element);
+ }
+}
+
+function selectTabItem(tabId, container, focus)
+{
+ // Show tab content
+ document.body.setAttribute("data-tab", tabId);
+
+ // Select tab
+ let tabList = container.querySelector("[role='tablist']");
+ if (!tabList)
+ return null;
+
+ let previousTab = tabList.querySelector("[aria-selected]");
+ previousTab.removeAttribute("aria-selected");
+ previousTab.setAttribute("tabindex", -1);
+
+ let tab = tabList.querySelector("a[href='#" + tabId + "']");
+ tab.setAttribute("aria-selected", true);
+ tab.setAttribute("tabindex", 0);
+
+ let tabContentId = tab.getAttribute("aria-controls");
+ let tabContent = document.getElementById(tabContentId);
+
+ if (tab && focus)
+ tab.focus();
+
+ return tabContent;
+}
+
+function onHashChange()
+{
+ let hash = location.hash.substr(1);
+ if (!hash)
+ return;
+
+ // Select tab and parent tabs
+ let tabIds = hash.split("-");
+ let tabContent = document.body;
+ for (let i = 0; i < tabIds.length; i++)
{
- if (element.getAttribute("aria-disabled") == "true")
- return;
+ let tabId = tabIds.slice(0, i + 1).join("-");
+ tabContent = selectTabItem(tabId, tabContent, true);
+ if (!tabContent)
+ break;
+ }
+}
+
+function onDOMLoaded()
+{
+ populateLists();
+
+ // Initialize navigation sidebar
+ browser.runtime.sendMessage({
+ type: "app.get",
+ what: "addonVersion"
+ },
+ (addonVersion) =>
+ {
+ E("abp-version").textContent = getMessage("options_dialog_about_version",
+ [addonVersion]);
+ });
+
+ updateTooltips();
+
+ // Initialize interactive UI elements
+ document.body.addEventListener("click", onClick, false);
+ document.body.addEventListener("keyup", onKeyUp, false);
+ let exampleValue = getMessage("options_whitelist_placeholder_example",
+ ["www.example.com"]);
+ E("whitelisting-textbox").setAttribute("placeholder", exampleValue);
+ E("whitelisting-textbox").addEventListener("keyup", (e) =>
+ {
+ E("whitelisting-add-button").disabled = !e.target.value;
+ }, false);
- switch (action)
+ // General tab
+ getDocLink("contribute", (link) =>
+ {
+ E("contribute").href = link;
+ });
+ getDocLink("acceptable_ads_criteria", (link) =>
+ {
+ setLinks("enable-acceptable-ads-description", link);
+ });
+ setElementText(E("tracking-warning-1"), "options_tracking_warning_1",
+ [getMessage("common_feature_privacy_title"),
+ getMessage("options_acceptableAds_ads_label")]);
+ setElementText(E("tracking-warning-3"), "options_tracking_warning_3",
+ [getMessage("options_acceptableAds_privacy_label")]);
+
+ getDocLink("privacy_friendly_ads", (link) =>
+ {
+ E("enable-acceptable-ads-privacy-description").href = link;
+ });
+ getDocLink("adblock_plus_{browser}_dnt", url =>
+ {
+ setLinks("dnt", url);
+ });
+
+ // Whitelisted tab
+ getDocLink("whitelist", (link) =>
+ {
+ E("whitelist-learn-more").href = link;
+ });
+
+ // Advanced tab
+ let customize = document.querySelectorAll("#customize li[data-pref]");
+ customize = Array.prototype.map.call(customize, (checkbox) =>
+ {
+ return checkbox.getAttribute("data-pref");
+ });
+ for (let key of customize)
+ {
+ getPref(key, (value) =>
{
- case "add-domain-exception":
- addWhitelistedDomain();
- break;
- case "add-language-subscription":
- addEnableSubscription(findParentData(element, "access", false));
- break;
- case "add-predefined-subscription": {
- let dialog = E("dialog-content-predefined");
- let title = dialog.querySelector("h3").textContent;
- let url = dialog.querySelector(".url").textContent;
- addEnableSubscription(url, title);
- closeDialog();
- break;
- }
- case "cancel-custom-filters":
- setCustomFiltersView("read");
- break;
- case "change-language-subscription":
- for (let key in subscriptionsMap)
- {
- let subscription = subscriptionsMap[key];
- let subscriptionType = subscription.recommended;
- if (subscriptionType == "ads" && subscription.disabled == false)
- {
- browser.runtime.sendMessage({
- type: "subscriptions.remove",
- url: subscription.url
- });
- browser.runtime.sendMessage({
- type: "subscriptions.add",
- url: findParentData(element, "access", false)
- });
- break;
- }
- }
- break;
- case "close-dialog":
- closeDialog();
- break;
- case "edit-custom-filters":
- setCustomFiltersView("write");
- break;
- case "hide-more-filters-section":
- E("more-filters").setAttribute("aria-hidden", true);
- break;
- case "hide-notification":
- hideNotification();
- break;
- case "import-subscription": {
- let url = E("blockingList-textbox").value;
- addEnableSubscription(url);
+ onPrefMessage(key, value, true);
+ });
+ }
+ browser.runtime.sendMessage({
+ type: "app.get",
+ what: "features"
+ },
+ (features) =>
+ {
+ hidePref("show_devtools_panel", !features.devToolsPanel);
+ });
+
+ getDocLink("filterdoc", (link) =>
+ {
+ E("link-filters").setAttribute("href", link);
+ });
+
+ getDocLink("subscriptions", (link) =>
+ {
+ E("filter-lists-learn-more").setAttribute("href", link);
+ });
+
+ E("custom-filters-raw").setAttribute("placeholder",
+ getMessage("options_customFilters_edit_placeholder", ["/ads/track/*"]));
+
+ // Help tab
+ getDocLink("adblock_plus_report_bug", (link) =>
+ {
+ setLinks("report-bug", link);
+ });
+ getDocLink("{browser}_support", url =>
+ {
+ setLinks("visit-forum", url);
+ });
+ getDocLink("social_twitter", (link) =>
+ {
+ E("twitter").setAttribute("href", link);
+ });
+ getDocLink("social_facebook", (link) =>
+ {
+ E("facebook").setAttribute("href", link);
+ });
+ getDocLink("social_gplus", (link) =>
+ {
+ E("google-plus").setAttribute("href", link);
+ });
+ getDocLink("social_weibo", (link) =>
+ {
+ E("weibo").setAttribute("href", link);
+ });
+
+ E("dialog").addEventListener("keydown", function(e)
+ {
+ switch (getKey(e))
+ {
+ case "Escape":
closeDialog();
break;
- }
- case "open-context-menu": {
- let listItem = findParentData(element, "access", true);
- if (listItem && !listItem.classList.contains("show-context-menu"))
- listItem.classList.add("show-context-menu");
- break;
- }
- case "open-dialog": {
- let dialog = findParentData(element, "dialog", false);
- openDialog(dialog);
- break;
- }
- case "remove-filter":
- browser.runtime.sendMessage({
- type: "filters.remove",
- text: findParentData(element, "access", false)
- });
- break;
- case "remove-subscription":
- browser.runtime.sendMessage({
- type: "subscriptions.remove",
- url: findParentData(element, "access", false)
- });
- break;
- case "save-custom-filters":
- sendMessageHandleErrors({
- type: "filters.importRaw",
- text: E("custom-filters-raw").value,
- removeExisting: true
- },
- () =>
+ case "Tab":
+ if (e.shiftKey)
{
- setCustomFiltersView("read");
- });
- break;
- case "show-more-filters-section":
- E("more-filters").setAttribute("aria-hidden", false);
- break;
- case "switch-acceptable-ads":
- let value = element.value || element.dataset.value;
- // User check the checkbox
- let shouldCheck = element.getAttribute("aria-checked") != "true";
- let installAcceptableAds = false;
- let installAcceptableAdsPrivacy = false;
- // Acceptable Ads checkbox clicked
- if (value == "ads")
- {
- installAcceptableAds = shouldCheck;
- }
- // Privacy Friendly Acceptable Ads checkbox clicked
- else
- {
- installAcceptableAdsPrivacy = shouldCheck;
- installAcceptableAds = !shouldCheck;
+ if (e.target.classList.contains("focus-first"))
+ {
+ e.preventDefault();
+ this.querySelector(".focus-last").focus();
+ }
}
-
- browser.runtime.sendMessage({
- type: installAcceptableAds ? "subscriptions.add" :
- "subscriptions.remove",
- url: acceptableAdsUrl
- });
- browser.runtime.sendMessage({
- type: installAcceptableAdsPrivacy ? "subscriptions.add" :
- "subscriptions.remove",
- url: acceptableAdsPrivacyUrl
- });
- break;
- case "switch-tab":
- switchTab(element.getAttribute("href").substr(1));
- break;
- case "toggle-disable-subscription":
- browser.runtime.sendMessage({
- type: "subscriptions.toggle",
- keepInstalled: true,
- url: findParentData(element, "access", false)
- });
- break;
- case "toggle-pref":
- browser.runtime.sendMessage({
- type: "prefs.toggle",
- key: findParentData(element, "pref", false)
- });
- break;
- case "toggle-remove-subscription":
- let subscriptionUrl = findParentData(element, "access", false);
- if (element.getAttribute("aria-checked") == "true")
+ else if (e.target.classList.contains("focus-last"))
{
- browser.runtime.sendMessage({
- type: "subscriptions.remove",
- url: subscriptionUrl
- });
- }
- else
- addEnableSubscription(subscriptionUrl);
- break;
- case "update-all-subscriptions":
- browser.runtime.sendMessage({
- type: "subscriptions.update"
- });
- break;
- case "update-subscription":
- browser.runtime.sendMessage({
- type: "subscriptions.update",
- url: findParentData(element, "access", false)
- });
- break;
- case "validate-import-subscription":
- let form = findParentData(element, "validation", true);
- if (!form)
- return;
-
- if (form.checkValidity())
- {
- addEnableSubscription(E("import-list-url").value,
- E("import-list-title").value);
- form.reset();
- closeDialog();
- }
- else
- {
- form.querySelector(":invalid").focus();
+ e.preventDefault();
+ this.querySelector(".focus-first").focus();
}
break;
}
- }
+ }, false);
+
+ onHashChange();
+}
- function setCustomFiltersView(mode)
- {
- let customFiltersElement = E("custom-filters-raw");
- updateCustomFiltersUi();
- if (mode == "read")
- {
- customFiltersElement.disabled = true;
- if (!customFiltersElement.value)
- {
- setCustomFiltersView("empty");
- return;
- }
- }
- else if (mode == "write")
- {
- customFiltersElement.disabled = false;
- }
+let focusedBeforeDialog = null;
+function openDialog(name)
+{
+ let dialog = E("dialog");
+ dialog.setAttribute("aria-hidden", false);
+ dialog.setAttribute("aria-labelledby", "dialog-title-" + name);
+ document.body.setAttribute("data-dialog", name);
+
+ let defaultFocus = document.querySelector(
+ "#dialog-content-" + name + " .default-focus"
+ );
+ if (!defaultFocus)
+ defaultFocus = dialog.querySelector(".focus-first");
+ focusedBeforeDialog = document.activeElement;
+ defaultFocus.focus();
+}
- E("custom-filters").dataset.mode = mode;
- }
+function closeDialog()
+{
+ let dialog = E("dialog");
+ dialog.setAttribute("aria-hidden", true);
+ dialog.removeAttribute("aria-labelledby");
+ document.body.removeAttribute("data-dialog");
+ focusedBeforeDialog.focus();
+}
- function onClick(e)
- {
- let context = document.querySelector(".show-context-menu");
- if (context)
- context.classList.remove("show-context-menu");
+function showNotification(text)
+{
+ E("notification").setAttribute("aria-hidden", false);
+ E("notification-text").textContent = text;
+ setTimeout(hideNotification, 3000);
+}
- let actions = findParentData(e.target, "action", false);
- if (!actions)
- return;
+function hideNotification()
+{
+ E("notification").setAttribute("aria-hidden", true);
+ E("notification-text").textContent = "";
+}
- actions = actions.split(",");
- for (let action of actions)
- {
- execAction(action, e.target);
- }
- }
-
- function getKey(e)
+function setAcceptableAds()
+{
+ let acceptableAdsForm = E("acceptable-ads");
+ let acceptableAds = E("acceptable-ads-allow");
+ let acceptableAdsPrivacy = E("acceptable-ads-privacy-allow");
+ acceptableAdsForm.classList.remove("show-dnt-notification");
+ acceptableAds.setAttribute("aria-checked", false);
+ acceptableAdsPrivacy.setAttribute("aria-checked", false);
+ acceptableAdsPrivacy.setAttribute("tabindex", 0);
+ if (acceptableAdsUrl in subscriptionsMap)
{
- // e.keyCode has been deprecated so we attempt to use e.key
- if ("key" in e)
- return e.key;
- return getKey.keys[e.keyCode];
+ acceptableAds.setAttribute("aria-checked", true);
+ acceptableAdsPrivacy.setAttribute("aria-disabled", false);
}
- getKey.keys = {
- 9: "Tab",
- 13: "Enter",
- 27: "Escape",
- 37: "ArrowLeft",
- 38: "ArrowUp",
- 39: "ArrowRight",
- 40: "ArrowDown"
- };
-
- function onKeyUp(e)
+ else if (acceptableAdsPrivacyUrl in subscriptionsMap)
{
- let key = getKey(e);
- let element = document.activeElement;
- if (!key || !element)
- return;
+ acceptableAds.setAttribute("aria-checked", true);
+ acceptableAdsPrivacy.setAttribute("aria-checked", true);
+ acceptableAdsPrivacy.setAttribute("aria-disabled", false);
- let container = findParentData(element, "action", true);
- if (!container || !container.hasAttribute("data-keys"))
- return;
+ // Edge uses window instead of navigator.
+ // Prefer navigator first since it's the standard.
+ if ((navigator.doNotTrack || window.doNotTrack) != 1)
+ acceptableAdsForm.classList.add("show-dnt-notification");
+ }
+ else
+ {
+ // Using aria-disabled in order to keep the focus
+ acceptableAdsPrivacy.setAttribute("aria-disabled", true);
+ acceptableAdsPrivacy.setAttribute("tabindex", -1);
+ }
+}
- let keys = container.getAttribute("data-keys").split(" ");
- if (keys.indexOf(key) < 0)
- return;
+function isAcceptableAds(url)
+{
+ return url == acceptableAdsUrl || url == acceptableAdsPrivacyUrl;
+}
- if (element.getAttribute("role") == "tab")
+function hasPrivacyConflict()
+{
+ let acceptableAdsList = subscriptionsMap[acceptableAdsUrl];
+ let privacyList = null;
+ for (let url in subscriptionsMap)
+ {
+ let subscription = subscriptionsMap[url];
+ if (subscription.recommended == "privacy")
{
- let parent = element.parentElement;
- if (key == "ArrowLeft" || key == "ArrowUp")
- parent = parent.previousElementSibling || container.lastElementChild;
- else if (key == "ArrowRight" || key == "ArrowDown")
- parent = parent.nextElementSibling || container.firstElementChild;
- element = parent.firstElementChild;
- }
-
- let actions = container.getAttribute("data-action").split(",");
- for (let action of actions)
- {
- execAction(action, element);
+ privacyList = subscription;
+ break;
}
}
-
- function selectTabItem(tabId, container, focus)
- {
- // Show tab content
- document.body.setAttribute("data-tab", tabId);
-
- // Select tab
- let tabList = container.querySelector("[role='tablist']");
- if (!tabList)
- return null;
-
- let previousTab = tabList.querySelector("[aria-selected]");
- previousTab.removeAttribute("aria-selected");
- previousTab.setAttribute("tabindex", -1);
-
- let tab = tabList.querySelector("a[href='#" + tabId + "']");
- tab.setAttribute("aria-selected", true);
- tab.setAttribute("tabindex", 0);
-
- let tabContentId = tab.getAttribute("aria-controls");
- let tabContent = document.getElementById(tabContentId);
-
- if (tab && focus)
- tab.focus();
-
- return tabContent;
- }
+ return acceptableAdsList && acceptableAdsList.disabled == false &&
+ privacyList && privacyList.disabled == false;
+}
- function onHashChange()
+function setPrivacyConflict()
+{
+ let acceptableAdsForm = E("acceptable-ads");
+ if (hasPrivacyConflict())
{
- let hash = location.hash.substr(1);
- if (!hash)
- return;
-
- // Select tab and parent tabs
- let tabIds = hash.split("-");
- let tabContent = document.body;
- for (let i = 0; i < tabIds.length; i++)
- {
- let tabId = tabIds.slice(0, i + 1).join("-");
- tabContent = selectTabItem(tabId, tabContent, true);
- if (!tabContent)
- break;
- }
- }
-
- function onDOMLoaded()
- {
- populateLists();
-
- // Initialize navigation sidebar
- browser.runtime.sendMessage({
- type: "app.get",
- what: "addonVersion"
- },
- (addonVersion) =>
+ getPref("ui_warn_tracking", (showTrackingWarning) =>
{
- E("abp-version").textContent = getMessage("options_dialog_about_version",
- [addonVersion]);
- });
-
- updateTooltips();
-
- // Initialize interactive UI elements
- document.body.addEventListener("click", onClick, false);
- document.body.addEventListener("keyup", onKeyUp, false);
- let exampleValue = getMessage("options_whitelist_placeholder_example",
- ["www.example.com"]);
- E("whitelisting-textbox").setAttribute("placeholder", exampleValue);
- E("whitelisting-textbox").addEventListener("keyup", (e) =>
- {
- E("whitelisting-add-button").disabled = !e.target.value;
- }, false);
-
- // General tab
- getDocLink("contribute", (link) =>
- {
- E("contribute").href = link;
- });
- getDocLink("acceptable_ads_criteria", (link) =>
- {
- setLinks("enable-acceptable-ads-description", link);
+ acceptableAdsForm.classList.toggle("show-warning", showTrackingWarning);
});
- setElementText(E("tracking-warning-1"), "options_tracking_warning_1",
- [getMessage("common_feature_privacy_title"),
- getMessage("options_acceptableAds_ads_label")]);
- setElementText(E("tracking-warning-3"), "options_tracking_warning_3",
- [getMessage("options_acceptableAds_privacy_label")]);
+ }
+ else
+ {
+ acceptableAdsForm.classList.remove("show-warning");
+ }
+}
- getDocLink("privacy_friendly_ads", (link) =>
- {
- E("enable-acceptable-ads-privacy-description").href = link;
- });
- getDocLink("adblock_plus_{browser}_dnt", url =>
- {
- setLinks("dnt", url);
- });
+function populateLists()
+{
+ subscriptionsMap = Object.create(null);
+ filtersMap = Object.create(null);
+
+ // Empty collections and lists
+ for (let property in collections)
+ collections[property].clearAll();
- // Whitelisted tab
- getDocLink("whitelist", (link) =>
+ setCustomFiltersView("empty");
+ browser.runtime.sendMessage({
+ type: "subscriptions.get",
+ special: true
+ },
+ (subscriptions) =>
+ {
+ // Load filters
+ for (let subscription of subscriptions)
{
- E("whitelist-learn-more").href = link;
- });
-
- // Advanced tab
- let customize = document.querySelectorAll("#customize li[data-pref]");
- customize = Array.prototype.map.call(customize, (checkbox) =>
- {
- return checkbox.getAttribute("data-pref");
- });
- for (let key of customize)
- {
- getPref(key, (value) =>
+ browser.runtime.sendMessage({
+ type: "filters.get",
+ subscriptionUrl: subscription.url
+ },
+ (filters) =>
{
- onPrefMessage(key, value, true);
+ loadCustomFilters(filters);
});
}
- browser.runtime.sendMessage({
- type: "app.get",
- what: "features"
- },
- (features) =>
- {
- hidePref("show_devtools_panel", !features.devToolsPanel);
- });
-
- getDocLink("filterdoc", (link) =>
- {
- E("link-filters").setAttribute("href", link);
- });
+ });
+ loadRecommendations();
+ browser.runtime.sendMessage({
+ type: "prefs.get",
+ key: "subscriptions_exceptionsurl"
+ },
+ (url) =>
+ {
+ acceptableAdsUrl = url;
- getDocLink("subscriptions", (link) =>
- {
- E("filter-lists-learn-more").setAttribute("href", link);
- });
-
- E("custom-filters-raw").setAttribute("placeholder",
- getMessage("options_customFilters_edit_placeholder", ["/ads/track/*"]));
-
- // Help tab
- getDocLink("adblock_plus_report_bug", (link) =>
- {
- setLinks("report-bug", link);
- });
- getDocLink("{browser}_support", url =>
- {
- setLinks("visit-forum", url);
- });
- getDocLink("social_twitter", (link) =>
+ browser.runtime.sendMessage({
+ type: "prefs.get",
+ key: "subscriptions_exceptionsurl_privacy"
+ },
+ (urlPrivacy) =>
{
- E("twitter").setAttribute("href", link);
- });
- getDocLink("social_facebook", (link) =>
- {
- E("facebook").setAttribute("href", link);
- });
- getDocLink("social_gplus", (link) =>
- {
- E("google-plus").setAttribute("href", link);
- });
- getDocLink("social_weibo", (link) =>
- {
- E("weibo").setAttribute("href", link);
- });
-
- E("dialog").addEventListener("keydown", function(e)
- {
- switch (getKey(e))
- {
- case "Escape":
- closeDialog();
- break;
- case "Tab":
- if (e.shiftKey)
- {
- if (e.target.classList.contains("focus-first"))
- {
- e.preventDefault();
- this.querySelector(".focus-last").focus();
- }
- }
- else if (e.target.classList.contains("focus-last"))
- {
- e.preventDefault();
- this.querySelector(".focus-first").focus();
- }
- break;
- }
- }, false);
+ acceptableAdsPrivacyUrl = urlPrivacy;
- onHashChange();
- }
-
- let focusedBeforeDialog = null;
- function openDialog(name)
- {
- let dialog = E("dialog");
- dialog.setAttribute("aria-hidden", false);
- dialog.setAttribute("aria-labelledby", "dialog-title-" + name);
- document.body.setAttribute("data-dialog", name);
-
- let defaultFocus = document.querySelector(
- "#dialog-content-" + name + " .default-focus"
- );
- if (!defaultFocus)
- defaultFocus = dialog.querySelector(".focus-first");
- focusedBeforeDialog = document.activeElement;
- defaultFocus.focus();
- }
-
- function closeDialog()
- {
- let dialog = E("dialog");
- dialog.setAttribute("aria-hidden", true);
- dialog.removeAttribute("aria-labelledby");
- document.body.removeAttribute("data-dialog");
- focusedBeforeDialog.focus();
- }
-
- function showNotification(text)
- {
- E("notification").setAttribute("aria-hidden", false);
- E("notification-text").textContent = text;
- setTimeout(hideNotification, 3000);
- }
+ // Load user subscriptions
+ browser.runtime.sendMessage({
+ type: "subscriptions.get",
+ downloadable: true
+ },
+ (subscriptions) =>
+ {
+ for (let subscription of subscriptions)
+ onSubscriptionMessage("added", subscription);
- function hideNotification()
- {
- E("notification").setAttribute("aria-hidden", true);
- E("notification-text").textContent = "";
- }
+ setAcceptableAds();
+ });
+ });
+ });
+}
- function setAcceptableAds()
+function addWhitelistedDomain()
+{
+ let domain = E("whitelisting-textbox");
+ for (let whitelistItem of collections.whitelist.items)
{
- let acceptableAdsForm = E("acceptable-ads");
- let acceptableAds = E("acceptable-ads-allow");
- let acceptableAdsPrivacy = E("acceptable-ads-privacy-allow");
- acceptableAdsForm.classList.remove("show-dnt-notification");
- acceptableAds.setAttribute("aria-checked", false);
- acceptableAdsPrivacy.setAttribute("aria-checked", false);
- acceptableAdsPrivacy.setAttribute("tabindex", 0);
- if (acceptableAdsUrl in subscriptionsMap)
+ if (whitelistItem.title == domain.value)
{
- acceptableAds.setAttribute("aria-checked", true);
- acceptableAdsPrivacy.setAttribute("aria-disabled", false);
- }
- else if (acceptableAdsPrivacyUrl in subscriptionsMap)
- {
- acceptableAds.setAttribute("aria-checked", true);
- acceptableAdsPrivacy.setAttribute("aria-checked", true);
- acceptableAdsPrivacy.setAttribute("aria-disabled", false);
-
- // Edge uses window instead of navigator.
- // Prefer navigator first since it's the standard.
- if ((navigator.doNotTrack || window.doNotTrack) != 1)
- acceptableAdsForm.classList.add("show-dnt-notification");
- }
- else
- {
- // Using aria-disabled in order to keep the focus
- acceptableAdsPrivacy.setAttribute("aria-disabled", true);
- acceptableAdsPrivacy.setAttribute("tabindex", -1);
+ whitelistItem[timestampUI] = Date.now();
+ collections.whitelist.updateItem(whitelistItem);
+ domain.value = "";
+ break;
}
}
-
- function isAcceptableAds(url)
- {
- return url == acceptableAdsUrl || url == acceptableAdsPrivacyUrl;
- }
-
- function hasPrivacyConflict()
- {
- let acceptableAdsList = subscriptionsMap[acceptableAdsUrl];
- let privacyList = null;
- for (let url in subscriptionsMap)
- {
- let subscription = subscriptionsMap[url];
- if (subscription.recommended == "privacy")
- {
- privacyList = subscription;
- break;
- }
- }
- return acceptableAdsList && acceptableAdsList.disabled == false &&
- privacyList && privacyList.disabled == false;
- }
-
- function setPrivacyConflict()
- {
- let acceptableAdsForm = E("acceptable-ads");
- if (hasPrivacyConflict())
- {
- getPref("ui_warn_tracking", (showTrackingWarning) =>
- {
- acceptableAdsForm.classList.toggle("show-warning", showTrackingWarning);
- });
- }
- else
- {
- acceptableAdsForm.classList.remove("show-warning");
- }
- }
-
- function populateLists()
+ const value = domain.value.trim();
+ if (value)
{
- subscriptionsMap = Object.create(null);
- filtersMap = Object.create(null);
-
- // Empty collections and lists
- for (let property in collections)
- collections[property].clearAll();
-
- setCustomFiltersView("empty");
- browser.runtime.sendMessage({
- type: "subscriptions.get",
- special: true
- },
- (subscriptions) =>
- {
- // Load filters
- for (let subscription of subscriptions)
- {
- browser.runtime.sendMessage({
- type: "filters.get",
- subscriptionUrl: subscription.url
- },
- (filters) =>
- {
- loadCustomFilters(filters);
- });
- }
- });
- loadRecommendations();
- browser.runtime.sendMessage({
- type: "prefs.get",
- key: "subscriptions_exceptionsurl"
- },
- (url) =>
- {
- acceptableAdsUrl = url;
-
- browser.runtime.sendMessage({
- type: "prefs.get",
- key: "subscriptions_exceptionsurl_privacy"
- },
- (urlPrivacy) =>
- {
- acceptableAdsPrivacyUrl = urlPrivacy;
-
- // Load user subscriptions
- browser.runtime.sendMessage({
- type: "subscriptions.get",
- downloadable: true
- },
- (subscriptions) =>
- {
- for (let subscription of subscriptions)
- onSubscriptionMessage("added", subscription);
-
- setAcceptableAds();
- });
- });
+ const host = /^https?:\/\//i.test(value) ? new URL(value).host : value;
+ sendMessageHandleErrors({
+ type: "filters.add",
+ text: "@@||" + host.toLowerCase() + "^$document"
});
}
- function addWhitelistedDomain()
+ domain.value = "";
+ E("whitelisting-add-button").disabled = true;
+}
+
+function addEnableSubscription(url, title, homepage)
+{
+ let messageType = null;
+ let knownSubscription = subscriptionsMap[url];
+ if (knownSubscription && knownSubscription.disabled == true)
+ messageType = "subscriptions.toggle";
+ else
+ messageType = "subscriptions.add";
+
+ let message = {
+ type: messageType,
+ url
+ };
+ if (title)
+ message.title = title;
+ if (homepage)
+ message.homepage = homepage;
+
+ browser.runtime.sendMessage(message);
+}
+
+function onFilterMessage(action, filter)
+{
+ switch (action)
{
- let domain = E("whitelisting-textbox");
- for (let whitelistItem of collections.whitelist.items)
- {
- if (whitelistItem.title == domain.value)
- {
- whitelistItem[timestampUI] = Date.now();
- collections.whitelist.updateItem(whitelistItem);
- domain.value = "";
- break;
- }
- }
- const value = domain.value.trim();
- if (value)
- {
- const host = /^https?:\/\//i.test(value) ? new URL(value).host : value;
- sendMessageHandleErrors({
- type: "filters.add",
- text: "@@||" + host.toLowerCase() + "^$document"
- });
- }
+ case "added":
+ filter[timestampUI] = Date.now();
+ updateFilter(filter);
+ break;
+ case "loaded":
+ populateLists();
+ break;
+ case "removed":
+ let knownFilter = filtersMap[filter.text];
+ if (whitelistedDomainRegexp.test(knownFilter.text))
+ collections.whitelist.removeItem(knownFilter);
+ else
+ removeCustomFilter(filter.text);
- domain.value = "";
- E("whitelisting-add-button").disabled = true;
+ delete filtersMap[filter.text];
+ break;
}
-
- function addEnableSubscription(url, title, homepage)
- {
- let messageType = null;
- let knownSubscription = subscriptionsMap[url];
- if (knownSubscription && knownSubscription.disabled == true)
- messageType = "subscriptions.toggle";
- else
- messageType = "subscriptions.add";
+}
- let message = {
- type: messageType,
- url
- };
- if (title)
- message.title = title;
- if (homepage)
- message.homepage = homepage;
-
- browser.runtime.sendMessage(message);
- }
-
- function onFilterMessage(action, filter)
+function onSubscriptionMessage(action, subscription)
+{
+ if (subscription.url in subscriptionsMap)
{
- switch (action)
+ let knownSubscription = subscriptionsMap[subscription.url];
+ for (let property in subscription)
{
- case "added":
- filter[timestampUI] = Date.now();
- updateFilter(filter);
- break;
- case "loaded":
- populateLists();
- break;
- case "removed":
- let knownFilter = filtersMap[filter.text];
- if (whitelistedDomainRegexp.test(knownFilter.text))
- collections.whitelist.removeItem(knownFilter);
- else
- removeCustomFilter(filter.text);
-
- delete filtersMap[filter.text];
- break;
- }
- }
-
- function onSubscriptionMessage(action, subscription)
- {
- if (subscription.url in subscriptionsMap)
- {
- let knownSubscription = subscriptionsMap[subscription.url];
- for (let property in subscription)
- {
- if (property == "title" && knownSubscription.recommended)
- knownSubscription.originalTitle = subscription.title;
- else
- knownSubscription[property] = subscription[property];
- }
- subscription = knownSubscription;
+ if (property == "title" && knownSubscription.recommended)
+ knownSubscription.originalTitle = subscription.title;
+ else
+ knownSubscription[property] = subscription[property];
}
- switch (action)
- {
- case "disabled":
+ subscription = knownSubscription;
+ }
+ switch (action)
+ {
+ case "disabled":
+ updateSubscription(subscription);
+ setPrivacyConflict();
+ break;
+ case "downloading":
+ case "downloadStatus":
+ case "homepage":
+ case "lastDownload":
+ case "title":
+ updateSubscription(subscription);
+ break;
+ case "added":
+ let {url} = subscription;
+ // Handle custom subscription
+ if (/^~user/.test(url))
+ {
+ loadCustomFilters(subscription.filters);
+ return;
+ }
+ else if (url in subscriptionsMap)
updateSubscription(subscription);
- setPrivacyConflict();
- break;
- case "downloading":
- case "downloadStatus":
- case "homepage":
- case "lastDownload":
- case "title":
- updateSubscription(subscription);
- break;
- case "added":
- let {url} = subscription;
- // Handle custom subscription
- if (/^~user/.test(url))
+ else
+ addSubscription(subscription);
+
+ if (isAcceptableAds(url))
+ setAcceptableAds();
+
+ collections.filterLists.addItem(subscription);
+ setPrivacyConflict();
+ break;
+ case "removed":
+ if (subscription.recommended)
+ {
+ subscription.disabled = true;
+ onSubscriptionMessage("disabled", subscription);
+ }
+ else
+ {
+ delete subscriptionsMap[subscription.url];
+ if (isAcceptableAds(subscription.url))
{
- loadCustomFilters(subscription.filters);
- return;
- }
- else if (url in subscriptionsMap)
- updateSubscription(subscription);
- else
- addSubscription(subscription);
-
- if (isAcceptableAds(url))
setAcceptableAds();
-
- collections.filterLists.addItem(subscription);
- setPrivacyConflict();
- break;
- case "removed":
- if (subscription.recommended)
- {
- subscription.disabled = true;
- onSubscriptionMessage("disabled", subscription);
}
else
{
- delete subscriptionsMap[subscription.url];
- if (isAcceptableAds(subscription.url))
- {
- setAcceptableAds();
- }
- else
- {
- collections.more.removeItem(subscription);
- }
+ collections.more.removeItem(subscription);
}
-
- collections.filterLists.removeItem(subscription);
- setPrivacyConflict();
- break;
- }
- }
-
- function hidePref(key, value)
- {
- let element = document.querySelector("[data-pref='" + key + "']");
- if (element)
- element.setAttribute("aria-hidden", value);
- }
-
- function getPref(key, callback)
- {
- let checkPref = getPref.checks[key] || getPref.checkNone;
- checkPref((isActive) =>
- {
- if (!isActive)
- {
- hidePref(key, !isActive);
- return;
}
- browser.runtime.sendMessage({
- type: "prefs.get",
- key
- }, callback);
- });
+ collections.filterLists.removeItem(subscription);
+ setPrivacyConflict();
+ break;
}
+}
- getPref.checkNone = function(callback)
+function hidePref(key, value)
+{
+ let element = document.querySelector("[data-pref='" + key + "']");
+ if (element)
+ element.setAttribute("aria-hidden", value);
+}
+
+function getPref(key, callback)
+{
+ let checkPref = getPref.checks[key] || getPref.checkNone;
+ checkPref((isActive) =>
{
- callback(true);
- };
-
- getPref.checks =
- {
- notifications_ignoredcategories(callback)
+ if (!isActive)
{
- getPref("notifications_showui", callback);
- }
- };
-
- function onPrefMessage(key, value, initial)
- {
- switch (key)
- {
- case "notifications_ignoredcategories":
- value = value.indexOf("*") == -1;
- break;
-
- case "notifications_showui":
- hidePref("notifications_ignoredcategories", !value);
- break;
- case "ui_warn_tracking":
- setPrivacyConflict();
- break;
+ hidePref(key, !isActive);
+ return;
}
- let checkbox = document.querySelector(
- "[data-pref='" + key + "'] button[role='checkbox']"
- );
- if (checkbox)
- checkbox.setAttribute("aria-checked", value);
+ browser.runtime.sendMessage({
+ type: "prefs.get",
+ key
+ }, callback);
+ });
+}
+
+getPref.checkNone = function(callback)
+{
+ callback(true);
+};
+
+getPref.checks =
+{
+ notifications_ignoredcategories(callback)
+ {
+ getPref("notifications_showui", callback);
+ }
+};
+
+function onPrefMessage(key, value, initial)
+{
+ switch (key)
+ {
+ case "notifications_ignoredcategories":
+ value = value.indexOf("*") == -1;
+ break;
+
+ case "notifications_showui":
+ hidePref("notifications_ignoredcategories", !value);
+ break;
+ case "ui_warn_tracking":
+ setPrivacyConflict();
+ break;
}
- function updateTooltips()
+ let checkbox = document.querySelector(
+ "[data-pref='" + key + "'] button[role='checkbox']"
+ );
+ if (checkbox)
+ checkbox.setAttribute("aria-checked", value);
+}
+
+function updateTooltips()
+{
+ let anchors = document.querySelectorAll(":not(.tooltip) > [data-tooltip]");
+ for (let anchor of anchors)
{
- let anchors = document.querySelectorAll(":not(.tooltip) > [data-tooltip]");
- for (let anchor of anchors)
- {
- let id = anchor.getAttribute("data-tooltip");
-
- let wrapper = document.createElement("div");
- wrapper.className = "icon tooltip";
- anchor.parentNode.replaceChild(wrapper, anchor);
- wrapper.appendChild(anchor);
+ let id = anchor.getAttribute("data-tooltip");
- let tooltip = document.createElement("div");
- tooltip.setAttribute("role", "tooltip");
+ let wrapper = document.createElement("div");
+ wrapper.className = "icon tooltip";
+ anchor.parentNode.replaceChild(wrapper, anchor);
+ wrapper.appendChild(anchor);
+
+ let tooltip = document.createElement("div");
+ tooltip.setAttribute("role", "tooltip");
- let paragraph = document.createElement("p");
- paragraph.textContent = getMessage(id);
- tooltip.appendChild(paragraph);
+ let paragraph = document.createElement("p");
+ paragraph.textContent = getMessage(id);
+ tooltip.appendChild(paragraph);
- wrapper.appendChild(tooltip);
- }
+ wrapper.appendChild(tooltip);
}
+}
- ext.onMessage.addListener((message) =>
+ext.onMessage.addListener((message) =>
+{
+ switch (message.type)
{
- switch (message.type)
- {
- case "app.respond":
- switch (message.action)
- {
- case "addSubscription":
- let subscription = message.args[0];
- let dialog = E("dialog-content-predefined");
- dialog.querySelector("h3").textContent = subscription.title || "";
- dialog.querySelector(".url").textContent = subscription.url;
- openDialog("predefined");
- break;
- case "focusSection":
- document.body.setAttribute("data-tab", message.args[0]);
- break;
- }
- break;
- case "filters.respond":
- onFilterMessage(message.action, message.args[0]);
- break;
- case "prefs.respond":
- onPrefMessage(message.action, message.args[0], false);
- break;
- case "subscriptions.respond":
- onSubscriptionMessage(message.action, message.args[0]);
- break;
- }
- });
+ case "app.respond":
+ switch (message.action)
+ {
+ case "addSubscription":
+ let subscription = message.args[0];
+ let dialog = E("dialog-content-predefined");
+ dialog.querySelector("h3").textContent = subscription.title || "";
+ dialog.querySelector(".url").textContent = subscription.url;
+ openDialog("predefined");
+ break;
+ case "focusSection":
+ document.body.setAttribute("data-tab", message.args[0]);
+ break;
+ }
+ break;
+ case "filters.respond":
+ onFilterMessage(message.action, message.args[0]);
+ break;
+ case "prefs.respond":
+ onPrefMessage(message.action, message.args[0], false);
+ break;
+ case "subscriptions.respond":
+ onSubscriptionMessage(message.action, message.args[0]);
+ break;
+ }
+});
- browser.runtime.sendMessage({
- type: "app.listen",
- filter: ["addSubscription", "focusSection"]
- });
- browser.runtime.sendMessage({
- type: "filters.listen",
- filter: ["added", "loaded", "removed"]
- });
- browser.runtime.sendMessage({
- type: "prefs.listen",
- filter: ["notifications_ignoredcategories", "notifications_showui",
- "show_devtools_panel", "shouldShowBlockElementMenu",
- "ui_warn_tracking"]
- });
- browser.runtime.sendMessage({
- type: "subscriptions.listen",
- filter: ["added", "disabled", "homepage", "lastDownload", "removed",
- "title", "downloadStatus", "downloading"]
- });
+browser.runtime.sendMessage({
+ type: "app.listen",
+ filter: ["addSubscription", "focusSection"]
+});
+browser.runtime.sendMessage({
+ type: "filters.listen",
+ filter: ["added", "loaded", "removed"]
+});
+browser.runtime.sendMessage({
+ type: "prefs.listen",
+ filter: ["notifications_ignoredcategories", "notifications_showui",
+ "show_devtools_panel", "shouldShowBlockElementMenu",
+ "ui_warn_tracking"]
+});
+browser.runtime.sendMessage({
+ type: "subscriptions.listen",
+ filter: ["added", "disabled", "homepage", "lastDownload", "removed",
+ "title", "downloadStatus", "downloading"]
+});
- window.addEventListener("DOMContentLoaded", onDOMLoaded, false);
- window.addEventListener("hashchange", onHashChange, false);
-}
+window.addEventListener("DOMContentLoaded", onDOMLoaded, false);
+window.addEventListener("hashchange", onHashChange, false);
« no previous file with comments | « README.md ('k') | package.json » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld