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

Unified Diff: options.js

Issue 6088024630755328: issue 1526 - Implement new options page design for Chrome/Opera/Safari (Closed)
Patch Set: Created Feb. 13, 2015, 10:52 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
Index: options.js
===================================================================
new file mode 100644
--- /dev/null
+++ b/options.js
@@ -0,0 +1,651 @@
+/*
+ * This file is part of Adblock Plus <https://adblockplus.org/>,
+ * Copyright (C) 2006-2015 Eyeo GmbH
+ *
+ * Adblock Plus is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * Adblock Plus is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+"use strict";
+
+(function()
+{
+ var acceptableAdsUrl = null;
+
+ var optionObj =
+ {
+ collections:
+ {
+ push: function()
+ {
+ var length = Array.prototype.push.apply(this, arguments);
+ this.sort(function(a, b)
+ {
+ var aValue = (a.title || a.url || a.text).toLowerCase();
+ var bValue = (b.title || b.url || a.text).toLowerCase();
+ if (aValue < bValue)
+ return -1;
+ if (aValue > bValue)
+ return 1;
+ return 0;
+ });
+ for (var i=0; i < arguments.length; i++)
+ {
+ for (var j=0; j < this.table.length; j++)
+ {
+ var object = arguments[i];
+ var text = object.title || object.text;
+ var access = object.url || object.text;
+ var index = this.indexOf(object);
+ var table = E(this.table[j].id);
+ var template = this.table[j].template;
+ var listener = this.table[j].listener;
+
+ var list = document.createElement("li");
+ list.innerHTML = template;
+ list.dataset.access = access;
+ list.getElementsByClassName("display")[0].textContent = text;
+ if (object.isAdsType)
+ list.dataset.value = text.toLowerCase();
+
+ var control = list.getElementsByClassName("control")[0];
+ if (control)
+ {
+ control.addEventListener("click", listener, false);
+ control.checked = !object.disabled;
+ }
+ if (table.hasChildNodes)
+ table.insertBefore(list, table.childNodes[index]);
+ else
+ table.appendChild(list);
+ }
+ }
+ return length;
+ },
+ remove: function(obj)
+ {
+ var index = this.indexOf(obj);
+ this.splice(index, 1);
+ var access = obj.url || obj.text;
+ for (var i=0; i < this.table.length; i++)
+ {
+ var table = E(this.table[i].id);
+ var element = table.querySelector("[data-access='"+access+"']");
+ element.parentElement.removeChild(element);
+ }
+ }
+ },
+ subscriptions: {
+ getArray: function(subscription)
+ {
+ var collArray = null;
+ if (subscription.isPopular)
+ collArray = collections.popular;
+ else if (subscription.isAdsType && subscription.disabled)
+ collArray = collections.allLangs;
+ else if (subscription.isAdsType && !subscription.disabled)
+ collArray = collections.langs;
+ else if (subscription.url == acceptableAdsUrl)
+ collArray = collections.acceptableAds;
+ else
+ collArray = collections.custom;
+ return collArray;
+ },
+ update: function(subscription)
+ {
+ var optionSubscription = this[subscription.url];
+ if (optionSubscription)
+ optionSubscription.disabled = subscription.disabled;
+ else
+ {
+ var collArray = this.getArray(subscription);
+ optionObj.observe(subscription, ["disabled"]);
+ collArray.push = collections.push;
+ collArray.push(subscription);
+ this[subscription.url] = subscription;
+ }
+ },
+ remove: function(subscription)
+ {
+ var optionSubscription = this[subscription.url];
+
+ if (optionSubscription.isAdsType)
+ {
+ collections.langs.remove(optionSubscription);
+ collections.allLangs.push(optionSubscription);
+ }
+ else if(optionSubscription.isPopular)
+ {
+ optionSubscription.disabled = true;
+ }
+ else
+ {
+ collections.custom.remove(optionSubscription);
+ }
+ },
+ chboxListener: function(e)
+ {
+ e.preventDefault();
+ var target = e.target;
+ var isChecked = target.checked;
+ var url = e.target.parentNode.dataset.access;
+ if (!isChecked)
+ SendMessage.removeSubscription(url);
+ else
+ SendMessage.addSubscription(url);
+ },
+ acceptableAdsListener: function(e)
+ {
+ e.preventDefault();
+ var target = e.target;
+ var isChecked = target.checked;
+ var url = e.target.parentNode.dataset.access;
+
+ if (isChecked)
+ SendMessage.addSubscription(url);
+ else
+ SendMessage.removeSubscription(url);
+ },
+ addBtnListener: function(e)
+ {
+ e.preventDefault();
+ var url = this.parentNode.dataset.access;
+ SendMessage.addSubscription(url);
+ }
+ },
+ filters:
+ {
+ update: function(filter)
+ {
+ var optionFilter = this[filter.text];
+ var match = filter.text.match(/^@@\|\|([^\/:]+)\^\$document$/);
+ if (match && !optionFilter)
+ {
+ filter.title = match[1];
+ collections.whitelist.push(filter);
+ this[filter.text] = filter;
+ }
+ else
+ {
+ // TODO: add `filters[i].text` to list of custom filters
+ }
+ },
+ remove: function(filter)
+ {
+ collections.whitelist.remove(filter);
+ },
+ deleteBtnClick: function()
+ {
+ var filter = this.parentNode.dataset.access;
+ SendMessage.removeFilter(filter);
+ }
+ },
+ observe: function(obj, props)
+ {
+ props.forEach(function(property)
+ {
+ obj["__"+property] = obj[property];
+ Object.defineProperty(obj, property,
+ {
+ get: function()
+ {
+ return this["__"+property];
+ },
+ set: function(value)
+ {
+ this["__"+property] = value;
+ var access = obj.url || obj.text;
+ var elements = document.querySelectorAll("[data-access='" + access + "']");
+ for (var i=0; i < elements.length; i++)
+ {
+ var elem = elements[i];
+ var control = elem.getElementsByClassName("control")[0];
+ if (control.tagName == "INPUT")
+ control.checked = !obj.disabled;
+ if (obj.isAdsType)
+ {
+ collections.allLangs.remove(obj);
+ collections.langs.push(obj);
+ }
+ }
+ }
+ });
+ });
+ }
+ };
+
+ function createCollArray(tables)
+ {
+ var array = [];
+ array.push = optionObj.collections.push;
+ array.remove = optionObj.collections.remove;
+ array.table = tables;
+ return array;
+ }
+
+ var collections = optionObj.collections;
+ collections.popular = createCollArray([
+ {
+ id: "recommend-list-table",
+ template: "<input type='checkbox' class='control' /><span class='display'></span><span class='popular'>popular</span>",
+ listener: optionObj.subscriptions.chboxListener
+ }
+ ]);
+ collections.langs = createCollArray([
+ {
+ id: "blocking-languages-table",
+ template: "<input type='checkbox' class='control' /><span class='display'></span>",
+ listener: optionObj.subscriptions.chboxListener
+ },
+ {
+ id: "blocking-languages-modal-table",
+ template: "<span class='display'></span>"
+ }
+ ]);
+ collections.allLangs = createCollArray([
+ {
+ id: "all-lang-table",
+ template: "<button class='button-add control'><span>+add</span></button><span class='display'></span>",
+ listener: optionObj.subscriptions.addBtnListener
+ }
+ ]);
+ collections.acceptableAds = createCollArray([
+ {
+ id: "acceptableads-table",
+ template: "<input type='checkbox' class='control' /><span class='display'></span>",
+ listener: optionObj.subscriptions.acceptableAdsListener
+ }
+ ]);
+ collections.custom = createCollArray([
+ {
+ id: "custom-list-table",
+ template: "<input type='checkbox' class='control' /><span class='display'></span>",
+ listener: optionObj.subscriptions.chboxListener
+ }
+ ]);
+ collections.whitelist = createCollArray([
+ {
+ id: "whitelisting-table",
+ template: "<button class='delete control'></button><span class='display'></span>",
+ listener: optionObj.filters.deleteBtnClick
+ }
+ ]);
+
+ var Recommendations =
+ {
+ load: function()
+ {
+ var request = new XMLHttpRequest();
+ request.open("GET", "subscriptions.xml", false);
+ request.onload = function()
+ {
+ var list = document.getElementById("subscriptionSelector");
+ var docElem = request.responseXML.documentElement;
+ var elements = docElem.getElementsByTagName("subscription");
+ for (var i = 0; i < elements.length; i++)
+ {
+ var element = elements[i];
+ var subscription = Object.create(null);
+ subscription.title = element.getAttribute("title");
+ subscription.url = element.getAttribute("url");
+ subscription.disabled = true;
+ var prefix = element.getAttribute("prefixes");
+ if (prefix)
+ {
+ subscription.isAdsType = true;
+ var prefix = element.getAttribute("prefixes").replace(/,/g, '_');
+ subscription.title = ext.i18n.getMessage("options_language_" + prefix);
+ }
+ else
+ subscription.title = element.getAttribute("specialization");
+
+ if (element.getAttribute("popular"))
+ subscription.isPopular = true;
+ optionObj.subscriptions.update(subscription);
+ }
+ }.bind(this);
+ request.send();
+ }
+ };
+
+ function onDOMLoaded()
+ {
+ updateShareLink();
+ populateLists();
+
+ var tabList = document.querySelectorAll("#main-navigation-tabs li");
+ for (var i = 0; i < tabList.length; ++i)
+ {
+ tabList[i].addEventListener("click", function(ev)
+ {
+ document.body.dataset.tab = this.id.substr(4);
+ }, false);
+ }
+
+ var searchLanguage = function()
+ {
+ var searchStyle = document.getElementById('search_style');
Thomas Greiner 2015/02/18 17:19:27 You're using `document.getElementById()` here but
+ var searchVal = this.value;
+ if (!searchVal)
+ searchStyle.innerHTML = "";
+ else
+ searchStyle.innerHTML = "#all-lang-table li:not([data-value*=\"" + this.value.toLowerCase() + "\"]) { display: none; }";
+ };
+
+ // Update version number in navigation sidebar
+ ext.backgroundPage.sendMessage({
+ method: "app.get",
+ what: "addonVersion"
+ }, function(addonVersion)
+ {
+ E("abp-version").textContent = addonVersion;
+ });
+
+ var whitelistDomainBtnClick = function()
+ {
+ var domain = E("whitelisting-textbox").value;
+ if (domain)
+ SendMessage.addWhitelistedDomain(domain);
+ E("whitelisting-textbox").value = "";
+ };
+
+ var placeholderValue = ext.i18n.getMessage("options_modal_language_find");
+ E("find-language").setAttribute("placeholder", placeholderValue);
+ setLinks("block-element-explanation", "#");
+
+ E("add-blocking-list").addEventListener("click", function()
+ {
+ openModal("customlist");
+ }, false);
+ E("add-website-language").addEventListener("click", function()
+ {
+ openModal("language");
+ }, false);
+ E("modal-close").addEventListener("click", function()
+ {
+ delete document.body.dataset.modal;
+ }, false);
+ E("edit-ownBlockingList-btn").addEventListener("click", editOwnRulsBtnClick, false);
+ E("find-language").addEventListener("keyup", searchLanguage, false);
+ E("whitelisting-add-icon").addEventListener("click", whitelistDomainBtnClick, false);
+ E("whitelisting-add-btn").addEventListener("click", whitelistDomainBtnClick, false);
+ E("whitelisting-enter-icon").addEventListener("click", whitelistDomainBtnClick, false);
+ E("whitelisting-textbox").addEventListener("keypress", function(e)
+ {
+ if (e.keyCode == 13)
+ whitelistDomainBtnClick();
+ }, false);
+ E("whitelisting-cancel-btn").addEventListener("click", function()
+ {
+ E("whitelisting-textbox").value = "";
+ }, false);
+ E("import-blockingList-btn").addEventListener("click", function()
+ {
+ var url = E("blockingList-textbox").value;
+ SendMessage.addSubscription(url);
+ delete document.body.dataset.modal;
+ }, false);
+ }
+
+ function openModal(name)
+ {
+ document.body.dataset.modal = name;
+ var title = "options_modal_" + name + "_title";
+ E("modal-title").textContent = ext.i18n.getMessage(title);
+ }
+
+ function populateLists()
+ {
+ ext.backgroundPage.sendMessage(
+ {
+ type: "subscriptions.get",
+ special: true
+ }, function(subscriptions)
+ {
+ // Load filters
+ for (var i = 0; i < subscriptions.length; i++)
+ {
+ ext.backgroundPage.sendMessage(
+ {
+ type: "filters.get",
+ subscriptionUrl: subscriptions[i].url
+ }, function(filters)
+ {
+ for (var i = 0; i < filters.length; i++)
+ optionObj.filters.update(filters[i]);
+ });
+ }
+ });
+ Recommendations.load();
+ SendMessage.getAcceptableAdsURL(function(url)
+ {
+ acceptableAdsUrl = url;
+ var subscription = Object.create(null);
+ subscription.url = acceptableAdsUrl;
+ subscription.disabled = true;
+ subscription.title = ext.i18n.getMessage("options_acceptableAds_description");
+ optionObj.subscriptions.update(subscription);
+
+ // Load user subscriptions
+ ext.backgroundPage.sendMessage(
+ {
+ type: "subscriptions.get",
+ downloadable: true
+ }, function(subscriptions)
+ {
+ for (var i = 0; i < subscriptions.length; i++)
+ MessageListeners.onSubscriptionMessage("added", subscriptions[i]);
+ });
+ });
+ }
+
+ function editOwnRulsBtnClick()
+ {
+
+ }
+
+ var SendMessage =
+ {
+ getAcceptableAdsURL: function(callback)
+ {
+ ext.backgroundPage.sendMessage(
+ {
+ type: "prefs.get",
+ key: "subscriptions_exceptionsurl"
+ }, function(value)
+ {
+ SendMessage.getAcceptableAdsURL = function(callback)
+ {
+ callback(value);
+ }
+ SendMessage.getAcceptableAdsURL(callback);
+ });
+ },
+ addSubscription: function(url, title, homepage)
+ {
+ var message = {
+ type: "subscriptions.add",
+ url: url
+ };
+ if (title)
+ message.title = title;
+ if (homepage)
+ message.homepage = homepage;
+
+ ext.backgroundPage.sendMessage(message);
+ },
+ removeSubscription: function(url)
+ {
+ ext.backgroundPage.sendMessage(
+ {
+ type: "subscriptions.remove",
+ url: url
+ });
+ },
+ addWhitelistedDomain: function(domain)
+ {
+ ext.backgroundPage.sendMessage(
+ {
+ type: "filters.add",
+ text: "@@||" + domain.toLowerCase() + "^$document"
+ });
+ },
+ removeFilter: function(filter)
+ {
+ ext.backgroundPage.sendMessage(
+ {
+ type: "filters.remove",
+ text: filter
+ });
+ }
+ };
+
+ var MessageListeners =
+ {
+ onFilterMessage: function(action, filter)
+ {
+ switch (action)
+ {
+ case "added":
+ optionObj.filters.update(filter);
+ break;
+ case "loaded":
+ populateLists();
+ break;
+ case "removed":
+ optionObj.filters.remove(filter);
+ break;
+ }
+ },
+ onSubscriptionMessage: function(action, subscription)
+ {
+ switch (action)
+ {
+ case "added":
+ optionObj.subscriptions.update(subscription);
+ break;
+ case "disabled":
+ break;
+ case "homepage":
+ // TODO: NYI
+ break;
+ case "removed":
+ if (subscription.url == acceptableAdsUrl)
+ {
+ subscription.disabled = true;
+ optionObj.subscriptions.update(subscription);
+ }
+ else
+ optionObj.subscriptions.remove(subscription);
+ break;
+ case "title":
+ // TODO: NYI
+ break;
+ }
+ },
+ showAddSubscriptionDialog: function(subscription)
+ {
+ E("blockingList-textbox").value = subscription.url;
+ openModal("customlist");
+ }
+ };
+
+ function updateShareLink()
+ {
+ ext.backgroundPage.sendMessage(
+ {
+ type: "filters.blocked",
+ url: "https://platform.twitter.com/widgets/",
+ requestType: "SCRIPT",
+ docDomain: "adblockplus.org",
+ thirdParty: true
+ }, function(blocked)
+ {
+ // TODO: modify "share" link accordingly
+ });
+ }
+
+ function getDocLink(link, callback)
+ {
+ ext.backgroundPage.sendMessage(
+ {
+ type: "app.get",
+ what: "doclink",
+ link: link
+ }, callback);
+ }
+
+ function setLinks(id)
+ {
+ var element = E(id);
+ if (!element)
+ {
+ return;
+ }
+
+ var links = element.getElementsByTagName("a");
+
+ for (var i = 0; i < links.length; i++)
+ {
+ if (typeof arguments[i + 1] == "string")
+ {
+ links[i].href = arguments[i + 1];
+ links[i].setAttribute("target", "_blank");
+ }
+ else if (typeof arguments[i + 1] == "function")
+ {
+ links[i].href = "javascript:void(0);";
+ links[i].addEventListener("click", arguments[i + 1], false);
+ }
+ }
+ }
+
+ function E(id)
+ {
+ return document.getElementById(id);
+ }
+
+ ext.onMessage.addListener(function(message)
+ {
+ switch (message.type)
+ {
+ case "app.listen":
+ if (message.action == "addSubscription")
+ MessageListeners.showAddSubscriptionDialog(message.args[0]);
+ break;
+ case "filters.listen":
+ MessageListeners.onFilterMessage(message.action, message.args[0]);
+ break;
+ case "subscriptions.listen":
+ MessageListeners.onSubscriptionMessage(message.action, message.args[0]);
+ break;
+ }
+ });
+
+ ext.backgroundPage.sendMessage(
+ {
+ type: "app.listen",
+ filter: ["addSubscription"]
+ });
+ ext.backgroundPage.sendMessage(
+ {
+ type: "filters.listen",
+ filter: ["added", "loaded", "removed"]
+ });
+ ext.backgroundPage.sendMessage(
+ {
+ type: "subscriptions.listen",
+ filter: ["added", "disabled", "homepage", "removed", "title"]
+ });
+
+ window.addEventListener("DOMContentLoaded", onDOMLoaded, false);
+})();

Powered by Google App Engine
This is Rietveld