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"); |
@@ -139,13 +160,56 @@ |
if (!element) |
continue; |
- var text = item.title || item.url || item.text; |
- element.querySelector(".display").textContent = text; |
- if (text) |
- element.setAttribute("data-search", text.toLowerCase()); |
+ var title = item.title || item.url || item.text; |
+ element.querySelector(".display").textContent = title; |
+ if (title) |
+ element.setAttribute("data-search", title.toLowerCase()); |
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) |
+ { |
+ var message = element.querySelector(".message"); |
+ ext.backgroundPage.sendMessage( |
+ { |
+ type: "subscriptions.isDownloading", |
+ url: item.url |
+ }, |
+ function(isDownloading) |
+ { |
+ if (isDownloading) |
+ { |
+ var text = getMessage("options_filterList_lastDownload_inProgress"); |
+ message.textContent = text; |
+ element.classList.add("show-message"); |
+ } |
+ else if (downloadStatus && downloadStatus != "synchronize_ok") |
+ { |
+ if (downloadStatus in filterErrors) |
+ message.textContent = getMessage(filterErrors[downloadStatus]); |
+ else |
+ message.textContent = item.downloadStatus; |
+ element.classList.add("show-message"); |
+ } |
+ else if (item.lastDownload > 0) |
+ { |
+ var dateTime = i18n_formatDateTime(item.lastDownload * 1000); |
+ dateElement.textContent = dateTime[0]; |
+ timeElement.textContent = dateTime[1]; |
+ element.classList.remove("show-message"); |
+ } |
+ }); |
+ } |
+ 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 +219,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 +246,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 +261,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 +294,7 @@ |
[ |
{ |
id: "recommend-list-table", |
- onClick: onToggleSubscriptionClick |
+ onClick: toggleRemoveSubscription |
} |
]); |
collections.langs = new Collection( |
@@ -222,7 +302,7 @@ |
{ |
id: "blocking-languages-table", |
emptyText: "options_dialog_language_added_empty", |
- onClick: onToggleSubscriptionClick |
+ onClick: toggleRemoveSubscription |
}, |
{ |
id: "blocking-languages-dialog-table", |
@@ -241,14 +321,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 +346,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 +377,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]; |
+ if (oldValue != newValue) |
{ |
- get: function() |
- { |
- return this["$" + property]; |
- }, |
- set: function(value) |
- { |
- this["$" + property] = value; |
- onObjectChanged(); |
- } |
- }); |
- }); |
- } |
- else |
- { |
- Object.observe(subscription, onObjectChanged); |
- } |
+ this["$" + property] = newValue; |
+ 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 +485,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 +505,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 +588,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 +666,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 +677,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 +785,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 +891,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 +921,6 @@ |
} |
else |
{ |
- var knownSubscription = subscriptionsMap[subscription.url]; |
if (subscription.url in recommendationsMap) |
knownSubscription.disabled = true; |
else |
@@ -782,6 +930,7 @@ |
} |
} |
updateShareLink(); |
+ collections.filterLists.removeItem(knownSubscription); |
}); |
break; |
case "title": |
@@ -871,7 +1020,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); |