| Index: options.js |
| =================================================================== |
| --- a/options.js |
| +++ b/options.js |
| @@ -24,6 +24,14 @@ |
| var filtersMap = Object.create(null); |
| var collections = Object.create(null); |
| var maxLabelId = 0; |
| + var getMessage = ext.i18n.getMessage; |
| + var filterErrors = |
| + { |
| + "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" |
| + }; |
| function Collection(details) |
| { |
| @@ -38,13 +46,22 @@ |
| { |
| placeholder = document.createElement("li"); |
| placeholder.className = "empty-placeholder"; |
| - placeholder.textContent = ext.i18n.getMessage(text); |
| + placeholder.textContent = getMessage(text); |
| table.appendChild(placeholder); |
| } |
| else if (placeholder) |
| table.removeChild(placeholder); |
| } |
| + Collection.prototype._createElementQuery = function(item) |
| + { |
| + var access = (item.url || item.text).replace(/'/g, "\\'"); |
| + return function(container) |
| + { |
| + return container.querySelector("[data-access='" + access + "']"); |
| + }; |
| + }; |
| + |
| Collection.prototype.addItems = function() |
| { |
| var length = Array.prototype.push.apply(this.items, arguments); |
| @@ -82,7 +99,10 @@ |
| this._setEmpty(table, null); |
| if (table.hasChildNodes()) |
| - table.insertBefore(listItem, table.childNodes[this.items.indexOf(item)]); |
| + { |
| + table.insertBefore(listItem, |
| + table.childNodes[this.items.indexOf(item)]); |
| + } |
| else |
| table.appendChild(listItem); |
| this.updateItem(item); |
| @@ -98,10 +118,11 @@ |
| return; |
| this.items.splice(index, 1); |
| + var getListElement = this._createElementQuery(item); |
| for (var i = 0; i < this.details.length; i++) |
| { |
| var table = E(this.details[i].id); |
| - var element = table.childNodes[index]; |
| + var element = getListElement(table); |
| // Element gets removed so make sure to handle focus appropriately |
| var control = element.querySelector(".control"); |
| @@ -146,6 +167,36 @@ |
| var control = element.querySelector(".control[role='checkbox']"); |
| if (control) |
| control.setAttribute("aria-checked", item.disabled == false); |
| + |
| + var downloadStatus = item.downloadStatus; |
| + var dateElement = element.querySelector(".date"); |
| + var timeElement = element.querySelector(".time"); |
| + if(dateElement && timeElement) |
| + { |
| + if (downloadStatus && downloadStatus != "synchronize_ok") |
| + { |
| + if (downloadStatus in filterErrors) |
| + timeElement.textContent = getMessage(filterErrors[downloadStatus]); |
| + else |
| + timeElement.textContent = item.downloadStatus; |
| + } |
| + else if (item.lastDownload > 0) |
| + { |
| + var dateTime = i18n_formatDateTime(item.lastDownload * 1000); |
| + dateElement.textContent = dateTime[0]; |
| + timeElement.textContent = dateTime[1]; |
| + } |
| + else |
| + { |
| + timeElement.textContent = getMessage("options_filterList_lastDownload_inProgress"); |
|
Thomas Greiner
2016/02/03 14:50:14
Whenever adding a subscription I see two issues:
saroyanm
2016/02/03 17:43:12
Done.
|
| + } |
| + } |
| + var websiteElement = element.querySelector(".context-menu .website"); |
| + var sourceElement = element.querySelector(".context-menu .source"); |
| + if (websiteElement && item.homepage) |
| + websiteElement.setAttribute("href", item.homepage); |
| + if (sourceElement) |
| + sourceElement.setAttribute("href", item.url); |
| } |
| }; |
| @@ -155,9 +206,14 @@ |
| for (var i = 0; i < this.details.length; i++) |
| { |
| var table = E(this.details[i].id); |
| - var template = table.querySelector("template"); |
| - table.innerHTML = ""; |
| - table.appendChild(template); |
| + var element = table.firstChild; |
| + while (element) |
| + { |
| + if (element.tagName == "LI" && !element.classList.contains("static")) |
| + table.removeChild(element); |
| + element = element.nextElementSibling; |
| + } |
| + |
| this._setEmpty(table, this.details[i].emptyText); |
| } |
| }; |
| @@ -177,12 +233,11 @@ |
| return true; |
| } |
| - function onToggleSubscriptionClick(e) |
| + function toggleRemoveSubscription(e) |
| { |
| e.preventDefault(); |
| - var checkbox = e.target; |
| - var subscriptionUrl = checkbox.parentElement.getAttribute("data-access"); |
| - if (checkbox.getAttribute("aria-checked") == "true") |
| + var subscriptionUrl = findParentData(e.target, "access", false); |
| + if (e.target.getAttribute("aria-checked") == "true") |
| { |
| ext.backgroundPage.sendMessage({ |
| type: "subscriptions.remove", |
| @@ -193,16 +248,28 @@ |
| addEnableSubscription(subscriptionUrl); |
| } |
| + function toggleDisableSubscription(e) |
| + { |
| + e.preventDefault(); |
| + var subscriptionUrl = findParentData(e.target, "access", false); |
| + ext.backgroundPage.sendMessage( |
| + { |
| + type: "subscriptions.toggle", |
| + keepInstalled: true, |
| + url: subscriptionUrl |
| + }); |
| + } |
| + |
| function onAddLanguageSubscriptionClick(e) |
| { |
| e.preventDefault(); |
| - var url = this.parentNode.getAttribute("data-access"); |
| + var url = findParentData(this, "access", false); |
| addEnableSubscription(url); |
| } |
| function onRemoveFilterClick() |
| { |
| - var filter = this.parentNode.getAttribute("data-access"); |
| + var filter = findParentData(this, "access", false); |
| ext.backgroundPage.sendMessage( |
| { |
| type: "filters.remove", |
| @@ -214,7 +281,7 @@ |
| [ |
| { |
| id: "recommend-list-table", |
| - onClick: onToggleSubscriptionClick |
| + onClick: toggleRemoveSubscription |
| } |
| ]); |
| collections.langs = new Collection( |
| @@ -222,7 +289,7 @@ |
| { |
| id: "blocking-languages-table", |
| emptyText: "options_dialog_language_added_empty", |
| - onClick: onToggleSubscriptionClick |
| + onClick: toggleRemoveSubscription |
| }, |
| { |
| id: "blocking-languages-dialog-table", |
| @@ -241,14 +308,14 @@ |
| [ |
| { |
| id: "acceptableads-table", |
| - onClick: onToggleSubscriptionClick |
| + onClick: toggleRemoveSubscription |
| } |
| ]); |
| collections.custom = new Collection( |
| [ |
| { |
| id: "custom-list-table", |
| - onClick: onToggleSubscriptionClick |
| + onClick: toggleRemoveSubscription |
| } |
| ]); |
| collections.whitelist = new Collection( |
| @@ -266,23 +333,23 @@ |
| emptyText: "options_customFilters_empty" |
| } |
| ]); |
| + collections.filterLists = new Collection( |
| + [ |
| + { |
| + id: "all-filter-lists-table", |
| + onClick: toggleDisableSubscription |
| + } |
| + ]); |
| - function updateSubscription(subscription) |
| + function observeSubscription(subscription) |
| { |
| - var subscriptionUrl = subscription.url; |
| - var knownSubscription = subscriptionsMap[subscriptionUrl]; |
| - if (knownSubscription) |
| - knownSubscription.disabled = subscription.disabled; |
| - else |
| + function onObjectChanged(change) |
| { |
| - getAcceptableAdsURL(function(acceptableAdsUrl) |
| + for (var i = 0; i < change.length; i++) |
| { |
| - function onObjectChanged() |
| + if (change[i].name == "disabled") |
| { |
| - for (var i in collections) |
| - collections[i].updateItem(subscription); |
| - |
| - var recommendation = recommendationsMap[subscriptionUrl]; |
| + var recommendation = recommendationsMap[subscription.url]; |
| if (recommendation && recommendation.type == "ads") |
| { |
| if (subscription.disabled == false) |
| @@ -297,33 +364,57 @@ |
| } |
| } |
| } |
| + for (var i in collections) |
| + collections[i].updateItem(subscription); |
| + } |
| + } |
| - if (!Object.observe) |
| + if (!Object.observe) |
| + { |
| + ["disabled", "lastDownload"].forEach(function(property) |
| + { |
| + subscription["$" + property] = subscription[property]; |
| + Object.defineProperty(subscription, property, |
| { |
| - // Currently only "disabled" property of subscription used for observation |
| - // but with Advanced tab implementation we should also add more properties. |
| - ["disabled"].forEach(function(property) |
| + get: function() |
| { |
| - subscription["$" + property] = subscription[property]; |
| - Object.defineProperty(subscription, property, |
| + return this["$" + property]; |
| + }, |
| + set: function(newValue) |
| + { |
| + var oldValue = this["$" + property]; |
| + this["$" + property] = newValue; |
|
Thomas Greiner
2016/02/03 14:50:14
Detail: Shouldn't this only be set whenever the va
saroyanm
2016/02/03 17:43:12
Done.
|
| + if (oldValue != newValue) |
| { |
| - get: function() |
| - { |
| - return this["$" + property]; |
| - }, |
| - set: function(value) |
| - { |
| - this["$" + property] = value; |
| - onObjectChanged(); |
| - } |
| - }); |
| - }); |
| - } |
| - else |
| - { |
| - Object.observe(subscription, onObjectChanged); |
| - } |
| + var change = Object.create(null); |
| + change.name = property; |
| + onObjectChanged([change]); |
| + } |
| + } |
| + }); |
| + }); |
| + } |
| + else |
| + { |
| + Object.observe(subscription, onObjectChanged); |
| + } |
| + } |
| + function updateSubscription(subscription) |
| + { |
| + var subscriptionUrl = subscription.url; |
| + var knownSubscription = subscriptionsMap[subscriptionUrl]; |
| + if (knownSubscription) |
| + { |
| + for (var property in subscription) |
| + if (property != "title") |
| + knownSubscription[property] = subscription[property]; |
| + } |
| + else |
| + { |
| + observeSubscription(subscription); |
| + getAcceptableAdsURL(function(acceptableAdsUrl) |
| + { |
| var collection = null; |
| if (subscriptionUrl in recommendationsMap) |
| { |
| @@ -381,19 +472,18 @@ |
| subscription.disabled = null; |
| subscription.downloadStatus = null; |
| subscription.homepage = null; |
| - subscription.lastSuccess = null; |
| var recommendation = Object.create(null); |
| recommendation.type = element.getAttribute("type"); |
| var prefix = element.getAttribute("prefixes"); |
| if (prefix) |
| { |
| prefix = prefix.replace(/\W/g, "_"); |
| - subscription.title = ext.i18n.getMessage("options_language_" + prefix); |
| + subscription.title = getMessage("options_language_" + prefix); |
| } |
| else |
| { |
| var type = recommendation.type.replace(/\W/g, "_"); |
| - subscription.title = ext.i18n.getMessage("common_feature_" + type + "_title"); |
| + subscription.title = getMessage("common_feature_" + type + "_title"); |
| } |
| recommendationsMap[subscription.url] = recommendation; |
| @@ -402,8 +492,24 @@ |
| }); |
| } |
| + function findParentData(element, dataName, returnElement) |
| + { |
| + while (element) |
| + { |
| + if (element.hasAttribute("data-" + dataName)) |
| + return returnElement ? element : element.getAttribute("data-" + dataName); |
| + |
| + element = element.parentElement; |
| + } |
| + return null; |
| + } |
| + |
| function onClick(e) |
| { |
| + var context = document.querySelector(".show-context-menu"); |
| + if (context) |
| + context.classList.remove("show-context-menu"); |
| + |
| var element = e.target; |
| while (true) |
| { |
| @@ -469,21 +575,38 @@ |
| document.body.setAttribute("data-tab", |
| element.getAttribute("data-tab")); |
| break; |
| + case "update-all-subscriptions": |
| + ext.backgroundPage.sendMessage( |
| + { |
| + type: "subscriptions.update" |
| + }); |
| + break; |
| + case "open-context-menu": |
| + var listItem = findParentData(element, "access", true); |
| + if (listItem != context) |
| + listItem.classList.add("show-context-menu"); |
| + break; |
| + case "update-subscription": |
| + ext.backgroundPage.sendMessage( |
| + { |
| + type: "subscriptions.update", |
| + url: findParentData(element, "access", false) |
| + }); |
| + break; |
| + case "remove-subscription": |
| + ext.backgroundPage.sendMessage( |
| + { |
| + type: "subscriptions.remove", |
| + url: findParentData(element, "access", false) |
| + }); |
| + break; |
| } |
| } |
| } |
| function onDOMLoaded() |
| { |
| - var recommendationTemplate = document.querySelector("#recommend-list-table template"); |
| - var popularText = ext.i18n.getMessage("options_popular"); |
| - recommendationTemplate.content.querySelector(".popular").textContent = popularText; |
| - var languagesTemplate = document.querySelector("#all-lang-table template"); |
| - var buttonText = ext.i18n.getMessage("options_button_add"); |
| - languagesTemplate.content.querySelector(".button-add span").textContent = buttonText; |
| - |
| populateLists(); |
| - |
| function onFindLanguageKeyUp() |
| { |
| var searchStyle = E("search-style"); |
| @@ -530,7 +653,7 @@ |
| // Initialize interactive UI elements |
| document.body.addEventListener("click", onClick, false); |
| - var placeholderValue = ext.i18n.getMessage("options_dialog_language_find"); |
| + var placeholderValue = getMessage("options_dialog_language_find"); |
| E("find-language").setAttribute("placeholder", placeholderValue); |
| E("find-language").addEventListener("keyup", onFindLanguageKeyUp, false); |
| E("whitelisting-textbox").addEventListener("keypress", function(e) |
| @@ -541,7 +664,7 @@ |
| // Advanced tab |
| var filterTextbox = document.querySelector("#custom-filters-add input"); |
| - placeholderValue = ext.i18n.getMessage("options_customFilters_textbox_placeholder"); |
| + placeholderValue = getMessage("options_customFilters_textbox_placeholder"); |
| filterTextbox.setAttribute("placeholder", placeholderValue); |
| function addCustomFilters() |
| { |
| @@ -649,7 +772,7 @@ |
| var subscription = Object.create(null); |
| subscription.url = acceptableAdsUrl; |
| subscription.disabled = true; |
| - subscription.title = ext.i18n.getMessage("options_acceptableAds_description"); |
| + subscription.title = getMessage("options_acceptableAds_description"); |
| updateSubscription(subscription); |
| // Load user subscriptions |
| @@ -755,14 +878,27 @@ |
| switch (action) |
| { |
| case "added": |
| + updateSubscription(subscription); |
| + updateShareLink(); |
| + |
| + var knownSubscription = subscriptionsMap[subscription.url]; |
| + if (knownSubscription) |
| + collections.filterLists.addItems(knownSubscription); |
| + else |
| + collections.filterLists.addItems(subscription); |
| + break; |
| case "disabled": |
| updateSubscription(subscription); |
| updateShareLink(); |
| break; |
| + case "lastDownload": |
| + updateSubscription(subscription); |
| + break; |
| case "homepage": |
| // TODO: NYI |
| break; |
| case "removed": |
| + var knownSubscription = subscriptionsMap[subscription.url]; |
| getAcceptableAdsURL(function(acceptableAdsUrl) |
| { |
| if (subscription.url == acceptableAdsUrl) |
| @@ -772,7 +908,6 @@ |
| } |
| else |
| { |
| - var knownSubscription = subscriptionsMap[subscription.url]; |
| if (subscription.url in recommendationsMap) |
| knownSubscription.disabled = true; |
| else |
| @@ -782,6 +917,7 @@ |
| } |
| } |
| updateShareLink(); |
| + collections.filterLists.removeItem(knownSubscription); |
| }); |
| break; |
| case "title": |
| @@ -871,7 +1007,7 @@ |
| ext.backgroundPage.sendMessage( |
| { |
| type: "subscriptions.listen", |
| - filter: ["added", "disabled", "homepage", "removed", "title"] |
| + filter: ["added", "disabled", "homepage", "lastDownload", "removed", "title"] |
| }); |
| window.addEventListener("DOMContentLoaded", onDOMLoaded, false); |