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

Unified Diff: options.js

Issue 29333819: Issue 2375 - Implement "Blocking lists" section in new options page (Closed)
Patch Set: Created Jan. 18, 2016, 9:50 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
===================================================================
--- a/options.js
+++ b/options.js
@@ -72,6 +72,7 @@
if (text)
listItem.setAttribute("data-search", text.toLowerCase());
+ updateTimeDate(listItem, item);
var control = listItem.querySelector(".control");
if (control)
{
@@ -81,7 +82,13 @@
this._setEmpty(table, null);
if (table.hasChildNodes())
- table.insertBefore(listItem, table.childNodes[this.items.indexOf(item)]);
+ {
+ var index = this.items.indexOf(item);
+ if (table.firstChild.classList.contains("head"))
+ index++;
+
+ table.insertBefore(listItem, table.childNodes[index]);
+ }
else
table.appendChild(listItem);
}
@@ -96,10 +103,11 @@
return;
this.items.splice(index, 1);
+ var access = (item.url || item.text).replace(/'/g, "\\'");
Thomas Greiner 2016/01/19 11:27:28 I notice the issues with accessing elements by the
saroyanm 2016/01/22 09:55:08 Done, but wouldn't it be simpler to just have a pr
Thomas Greiner 2016/01/25 15:40:28 By returning a function we only create the "access
for (var i = 0; i < this.details.length; i++)
{
var table = E(this.details[i].id);
- var element = table.childNodes[index];
+ var element = table.querySelector("[data-access='" + access + "']");
element.parentElement.removeChild(element);
if (this.items.length == 0)
this._setEmpty(table, this.details[i].emptyText);
@@ -113,12 +121,79 @@
{
var table = E(this.details[i].id);
var template = table.querySelector("template");
+ var staticElements = [];
Thomas Greiner 2016/01/19 11:27:29 This logic is quite complicated. Assuming that you
saroyanm 2016/01/22 09:55:10 Currently we are not using createDocumentFragment
Thomas Greiner 2016/01/25 15:40:27 You could use `Element.nextElementSibling` to avoi
saroyanm 2016/01/26 18:36:15 I assume while you didn't commented under updated
Thomas Greiner 2016/01/27 17:16:56 Thanks for reminding me. I wrote down some parts t
+ var element = table.firstChild;
+ while (element)
+ {
+ if (element.tagName == "TEMPLATE" ||
+ (element.classList && element.classList.contains("static")))
+ staticElements.push(element);
+ element = element.nextSibling
+ }
+
table.innerHTML = "";
- table.appendChild(template);
+ for (var j = 0; j < staticElements.length; j++)
+ table.appendChild(staticElements[j]);
+
this._setEmpty(table, this.details[i].emptyText);
}
};
+ Collection.prototype.getTableIds = function()
Thomas Greiner 2016/01/19 11:27:29 This information is an implementation detail and s
saroyanm 2016/01/22 09:55:09 updated the method to check if the collection has
+ {
+ var ids = [];
+ for (var i = 0; i < this.details.length; i++)
+ ids.push(this.details[i].id)
+
+ return ids;
+ };
+
+ function updateTimeDate(listItem, subscription)
+ {
+ var dateElement = listItem.querySelector(".date");
+ var timeElement = listItem.querySelector(".time");
+
+ if(dateElement && timeElement)
+ {
+ if (subscription.downloadStatus &&
+ subscription.downloadStatus != "synchronize_ok")
+ {
+ var map =
+ {
+ "synchronize_invalid_url": "options_subscription_lastDownload_invalidURL",
+ "synchronize_connection_error": "options_subscription_lastDownload_connectionError",
+ "synchronize_invalid_data": "options_subscription_lastDownload_invalidData",
+ "synchronize_checksum_mismatch": "options_subscription_lastDownload_checksumMismatch"
+ };
+ if (subscription.downloadStatus in map)
+ timeElement.textContent = ext.i18n.getMessage(map[subscription.downloadStatus]);
+ else
+ timeElement.textContent = subscription.downloadStatus;
+ }
+ else if (subscription.lastDownload > 0)
+ {
+ var timedate = i18n_timeDateStrings(subscription.lastDownload * 1000);
Thomas Greiner 2016/01/19 11:27:29 This function returns the localized date-time stri
saroyanm 2016/01/22 09:55:10 I see, I was trying to make it consistent with old
Thomas Greiner 2016/01/25 15:40:28 The mere formatting of the string should be generi
saroyanm 2016/01/26 18:36:15 Done.
+ if (timedate[1])
+ dateElement.textContent = timedate[1].split("/").reverse().join("-");
+ else
+ {
+ var today = new Date();
+ dateElement.textContent = today.getFullYear() + "-" +
+ today.getMonth()+1 + "-" + today.getDate();
+ }
+ var time = timedate[0].split(":");
+ time[2] = time[2].split(" ")[1];
+ if (time[2] == "AM" && time[0] == "12")
+ time[0] = 0;
+ else if (time[2] == "PM")
+ time[0] = parseInt(time[0]) + 12;
+
+ time.pop();
+ timeElement.textContent = time.join(":");
+ }
+ }
+ }
+
function onToggleSubscriptionClick(e)
Thomas Greiner 2016/01/19 11:27:29 I'd suggest renaming this function to "toggleRemov
saroyanm 2016/01/22 09:55:08 Done.
{
e.preventDefault();
@@ -134,6 +209,17 @@
addEnableSubscription(subscriptionUrl);
}
+ function onToggleSubscriptionStateClick(e)
+ {
+ e.preventDefault();
+ var subscriptionUrl = e.target.parentNode.getAttribute("data-access");
Thomas Greiner 2016/01/19 11:27:29 What about reusing `getParentAccessElement()` sinc
saroyanm 2016/01/22 09:55:10 Done.
Thomas Greiner 2016/01/25 15:40:28 I don't see that you changed anything here.
saroyanm 2016/01/26 18:36:15 Now for sure, thanks.
+ ext.backgroundPage.sendMessage(
+ {
+ type: "subscriptions.toggleState",
+ url: subscriptionUrl
+ });
+ }
+
function onAddLanguageSubscriptionClick(e)
{
e.preventDefault();
@@ -207,31 +293,40 @@
emptyText: "options_customFilters_empty"
}
]);
+ collections.blockingLists = new Collection(
+ [
+ {
+ id: "blocking-lists-table",
+ onClick: onToggleSubscriptionStateClick
+ }
+ ]);
- 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()
+ var property = change[i].name;
+ if (property == "disabled")
{
- var access = (subscriptionUrl || subscription.text).replace(/'/g, "\\'");
+ var access = (subscription.url ||
+ subscription.text).replace(/'/g, "\\'");
var elements = document.querySelectorAll("[data-access='" + access + "']");
for (var i = 0; i < elements.length; i++)
{
var element = elements[i];
+ var tableId = element.parentElement ? element.parentElement.id : "";
var control = element.querySelector(".control");
- if (control.localName == "input")
+ if (control && control.localName == "input")
control.checked = subscription.disabled == false;
- if (subscriptionUrl in recommendationsMap)
+ if (subscription.url in recommendationsMap)
{
- var recommendation = recommendationsMap[subscriptionUrl];
- if (recommendation.type == "ads")
+ var recommendation = recommendationsMap[subscription.url];
+ var langids = collections.langs.getTableIds();
+ var allLangIds = collections.allLangs.getTableIds();
+ if (recommendation.type == "ads" &&
+ langids.concat(allLangIds).indexOf(tableId) != -1)
{
if (subscription.disabled == false)
{
@@ -247,33 +342,58 @@
}
}
}
+ else
+ {
+ var blockingListId = collections.blockingLists.details[0].id;
+ var blockingList = document.getElementById(blockingListId);
+ var listItem = blockingList.querySelector("[data-access='" +
+ subscription.url + "']");
+ updateTimeDate(listItem, 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,
- {
- get: function()
- {
- return this["$" + property];
- },
- set: function(value)
- {
- this["$" + property] = value;
- onObjectChanged();
- }
- });
- });
- }
- else
- {
- Object.observe(subscription, onObjectChanged);
- }
+ return this["$" + property];
+ },
+ set: function(value)
+ {
+ this["$" + property] = value;
+ 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)
+ {
+ knownSubscription.disabled = subscription.disabled;
+ knownSubscription.lastDownload = subscription.lastDownload;
+ }
+ else
+ {
+ observeSubscription(subscription);
+ getAcceptableAdsURL(function(acceptableAdsUrl)
+ {
var collection = null;
if (subscriptionUrl in recommendationsMap)
{
@@ -366,6 +486,15 @@
element = element.parentElement;
}
+ function getParentAccessElement()
Thomas Greiner 2016/01/19 11:27:30 Please avoid declaring functions inside other func
saroyanm 2016/01/22 09:55:09 Good point.
+ {
+ var elementCopy = element;
+ while (!elementCopy.dataset.access)
Thomas Greiner 2016/01/19 11:27:29 We can't use `Element.dataset` due to older Safari
saroyanm 2016/01/22 09:55:09 Right, done.
+ elementCopy = elementCopy.parentNode;
+
+ return elementCopy;
+ }
+
var actions = element.getAttribute("data-action").split(",");
for (var i = 0; i < actions.length; i++)
{
@@ -419,18 +548,83 @@
document.body.setAttribute("data-tab",
element.getAttribute("data-tab"));
break;
+ case "update-all-subscriptions":
+ ext.backgroundPage.sendMessage(
+ {
+ type: "subscriptions.updateAll"
+ });
+ break;
+ case "open-context-menu":
Thomas Greiner 2016/01/19 11:27:29 We should improve this mechanism because it requir
saroyanm 2016/01/22 09:55:09 Done, but bit hacky, not sure if it's what you mea
Thomas Greiner 2016/01/27 17:16:56 Better but what about replacing it with "toggle-co
saroyanm 2016/01/28 17:00:10 Done.
+ var listItem = getParentAccessElement();
+ var contextMenu = listItem.querySelector(".content");
+ listItem.classList.add("context");
+
+ function mouseover()
+ {
+ contextMenu.addEventListener("mouseout", mouseout, false);
+ contextMenu.removeEventListener("mouseover", mouseover);
+ }
+ function mouseout(event)
+ {
+ if (event.target.parentElement != contextMenu)
+ {
+ var relatedTarget = event.relatedTarget;
+ if (relatedTarget.parentNode == this || relatedTarget == this)
+ return;
+ listItem.classList.remove("context");
+ contextMenu.removeEventListener("mouseout", mouseout);
+ }
+ }
+
+ contextMenu.addEventListener("mouseover", mouseover, false);
+ break;
+ case "update-now":
+ ext.backgroundPage.sendMessage(
+ {
+ type: "subscriptions.update",
+ url: getParentAccessElement().dataset.access
+ });
+ break;
+ case "website":
+ ext.backgroundPage.sendMessage(
+ {
+ type: "subscriptions.website",
+ url: getParentAccessElement().dataset.access
+ });
+ break;
+ case "source":
+ window.open(getParentAccessElement().dataset.access);
+ break;
+ case "delete":
+ ext.backgroundPage.sendMessage(
+ {
+ type: "subscriptions.remove",
+ url: getParentAccessElement().dataset.access
+ });
+ 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;
+ function updateTemplate(template, selector, messageId)
Thomas Greiner 2016/01/19 11:27:29 This functionality belongs into "i18n.js". If elem
saroyanm 2016/01/22 09:55:08 Done.
+ {
+ template.content.querySelector(selector).
+ textContent = ext.i18n.getMessage(messageId);
+ }
+
+ var template = document.querySelector("#recommend-list-table template");
+ updateTemplate(template, ".popular", "options_popular");
+
+ template = document.querySelector("#all-lang-table template");
+ updateTemplate(template, ".button-add span", "options_button_add");
+
+ template = document.querySelector("#blocking-lists-table template");
+ updateTemplate(template, ".update-now", "options_blockingList_update_now");
+ updateTemplate(template, ".website", "options_blockingList_website");
+ updateTemplate(template, ".source", "options_blockingList_source");
+ updateTemplate(template, ".delete", "options_blockingList_delete");
populateLists();
@@ -705,14 +899,27 @@
switch (action)
{
case "added":
+ updateSubscription(subscription);
+ updateShareLink();
+
+ var knownSubscription = subscriptionsMap[subscription.url];
+ if (knownSubscription)
+ collections.blockingLists.addItems(knownSubscription);
+ else
+ collections.blockingLists.addItems(subscription);
+ break;
case "disabled":
updateSubscription(subscription);
updateShareLink();
break;
+ case "updated":
+ updateSubscription(subscription);
Thomas Greiner 2016/01/19 11:27:29 That's not what "updated" is meant to notify you o
saroyanm 2016/01/22 09:55:10 Ahh right, thanks for pointing that out. Done.
+ break;
case "homepage":
// TODO: NYI
break;
case "removed":
+ var knownSubscription = subscriptionsMap[subscription.url];
getAcceptableAdsURL(function(acceptableAdsUrl)
{
if (subscription.url == acceptableAdsUrl)
@@ -722,7 +929,6 @@
}
else
{
- var knownSubscription = subscriptionsMap[subscription.url];
if (subscription.url in recommendationsMap)
knownSubscription.disabled = true;
else
@@ -733,6 +939,7 @@
}
updateShareLink();
});
+ collections.blockingLists.removeItem(knownSubscription);
break;
case "title":
// TODO: NYI
@@ -821,7 +1028,7 @@
ext.backgroundPage.sendMessage(
{
type: "subscriptions.listen",
- filter: ["added", "disabled", "homepage", "removed", "title"]
+ filter: ["added", "disabled", "updated", "homepage", "removed", "title"]
});
window.addEventListener("DOMContentLoaded", onDOMLoaded, false);

Powered by Google App Engine
This is Rietveld