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

Delta Between Two Patch Sets: options.js

Issue 29333819: Issue 2375 - Implement "Blocking lists" section in new options page (Closed)
Left Patch Set: Addressed Thomas comments Created Jan. 22, 2016, 9:53 a.m.
Right Patch Set: Fixed the progress indicator and small fixes Created Feb. 4, 2016, 5:43 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« background.js ('K') | « options.html ('k') | skin/options.css » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 /* 1 /*
2 * This file is part of Adblock Plus <https://adblockplus.org/>, 2 * This file is part of Adblock Plus <https://adblockplus.org/>,
3 * Copyright (C) 2006-2015 Eyeo GmbH 3 * Copyright (C) 2006-2016 Eyeo GmbH
4 * 4 *
5 * Adblock Plus is free software: you can redistribute it and/or modify 5 * Adblock Plus is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 3 as 6 * it under the terms of the GNU General Public License version 3 as
7 * published by the Free Software Foundation. 7 * published by the Free Software Foundation.
8 * 8 *
9 * Adblock Plus is distributed in the hope that it will be useful, 9 * Adblock Plus is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details. 12 * GNU General Public License for more details.
13 * 13 *
14 * You should have received a copy of the GNU General Public License 14 * You should have received a copy of the GNU General Public License
15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. 15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
16 */ 16 */
17 17
18 "use strict"; 18 "use strict";
19 19
20 (function() 20 (function()
21 { 21 {
22 var subscriptionsMap = Object.create(null); 22 var subscriptionsMap = Object.create(null);
23 var recommendationsMap = Object.create(null); 23 var recommendationsMap = Object.create(null);
24 var filtersMap = Object.create(null); 24 var filtersMap = Object.create(null);
25 var collections = Object.create(null); 25 var collections = Object.create(null);
26 var maxLabelId = 0;
27 var getMessage = ext.i18n.getMessage;
28 var filterErrors =
29 {
30 "synchronize_invalid_url": "options_filterList_lastDownload_invalidURL",
31 "synchronize_connection_error": "options_filterList_lastDownload_connectionE rror",
32 "synchronize_invalid_data": "options_filterList_lastDownload_invalidData",
33 "synchronize_checksum_mismatch": "options_filterList_lastDownload_checksumMi smatch"
34 };
26 35
27 function Collection(details) 36 function Collection(details)
28 { 37 {
29 this.details = details; 38 this.details = details;
30 this.items = []; 39 this.items = [];
31 } 40 }
32 41
33 Collection.prototype._setEmpty = function(table, text) 42 Collection.prototype._setEmpty = function(table, text)
34 { 43 {
35 var placeholder = table.querySelector(".empty-placeholder"); 44 var placeholder = table.querySelector(".empty-placeholder");
36 if (text && !placeholder) 45 if (text && !placeholder)
37 { 46 {
38 placeholder = document.createElement("li"); 47 placeholder = document.createElement("li");
39 placeholder.className = "empty-placeholder"; 48 placeholder.className = "empty-placeholder";
40 placeholder.textContent = ext.i18n.getMessage(text); 49 placeholder.textContent = getMessage(text);
41 table.appendChild(placeholder); 50 table.appendChild(placeholder);
42 } 51 }
43 else if (placeholder) 52 else if (placeholder)
44 table.removeChild(placeholder); 53 table.removeChild(placeholder);
45 } 54 }
46 55
47 Collection.prototype._createElementQuery = function(item) 56 Collection.prototype._createElementQuery = function(item)
48 { 57 {
49 var access = (item.url || item.text).replace(/'/g, "\\'"); 58 var access = (item.url || item.text).replace(/'/g, "\\'");
50 return function(container) 59 return function(container)
(...skipping 15 matching lines...) Expand all
66 return aValue.localeCompare(bValue); 75 return aValue.localeCompare(bValue);
67 }); 76 });
68 77
69 for (var j = 0; j < this.details.length; j++) 78 for (var j = 0; j < this.details.length; j++)
70 { 79 {
71 var table = E(this.details[j].id); 80 var table = E(this.details[j].id);
72 var template = table.querySelector("template"); 81 var template = table.querySelector("template");
73 for (var i = 0; i < arguments.length; i++) 82 for (var i = 0; i < arguments.length; i++)
74 { 83 {
75 var item = arguments[i]; 84 var item = arguments[i];
76 var text = item.title || item.url || item.text;
77 var listItem = document.createElement("li"); 85 var listItem = document.createElement("li");
78 listItem.appendChild(document.importNode(template.content, true)); 86 listItem.appendChild(document.importNode(template.content, true));
79 listItem.setAttribute("data-access", item.url || item.text); 87 listItem.setAttribute("data-access", item.url || item.text);
80 listItem.querySelector(".display").textContent = text; 88
81 if (text) 89 var labelId = "label-" + (++maxLabelId);
82 listItem.setAttribute("data-search", text.toLowerCase()); 90 listItem.querySelector(".display").setAttribute("id", labelId);
83
84 updateBlockingList(listItem, item);
Thomas Greiner 2016/01/27 17:16:57 This doesn't belong into Collection since it's spe
saroyanm 2016/01/28 17:00:11 We are calling this method on observer as well, Th
Thomas Greiner 2016/01/29 17:48:08 This code is only relevant for subscriptions. Howe
85 var control = listItem.querySelector(".control"); 91 var control = listItem.querySelector(".control");
86 if (control) 92 if (control)
87 { 93 {
94 // We use aria-labelledby to avoid triggering the control when
95 // interacting with the label
96 control.setAttribute("aria-labelledby", labelId);
88 control.addEventListener("click", this.details[j].onClick, false); 97 control.addEventListener("click", this.details[j].onClick, false);
89 control.checked = item.disabled == false;
90 } 98 }
91 99
92 this._setEmpty(table, null); 100 this._setEmpty(table, null);
93 if (table.hasChildNodes()) 101 if (table.hasChildNodes())
102 {
94 table.insertBefore(listItem, 103 table.insertBefore(listItem,
95 table.childNodes[this.items.indexOf(item)]); 104 table.childNodes[this.items.indexOf(item)]);
Thomas Greiner 2016/01/25 15:40:32 Detail: Please use braces around it if you occupy
saroyanm 2016/01/26 18:36:19 Done.
Thomas Greiner 2016/01/27 17:16:58 Detail: What I meant with "indent using double-spa
saroyanm 2016/01/28 17:00:12 Got it, sorry for that, I was thinking that we nee
105 }
96 else 106 else
97 table.appendChild(listItem); 107 table.appendChild(listItem);
108 this.updateItem(item);
98 } 109 }
99 } 110 }
100 return length; 111 return length;
101 }; 112 };
102 113
103 Collection.prototype.removeItem = function(item) 114 Collection.prototype.removeItem = function(item)
104 { 115 {
105 var index = this.items.indexOf(item); 116 var index = this.items.indexOf(item);
106 if (index == -1) 117 if (index == -1)
107 return; 118 return;
108 119
109 this.items.splice(index, 1); 120 this.items.splice(index, 1);
110 var getListElement = this._createElementQuery(item); 121 var getListElement = this._createElementQuery(item);
111 for (var i = 0; i < this.details.length; i++) 122 for (var i = 0; i < this.details.length; i++)
112 { 123 {
113 var table = E(this.details[i].id); 124 var table = E(this.details[i].id);
114 var element = getListElement(table); 125 var element = getListElement(table);
126
127 // Element gets removed so make sure to handle focus appropriately
128 var control = element.querySelector(".control");
129 if (control && control == document.activeElement)
130 {
131 if (!focusNextElement(element.parentElement, control))
132 {
133 // Fall back to next focusable element within same tab or dialog
134 var focusableElement = element.parentElement;
135 while (focusableElement)
136 {
137 if (focusableElement.classList.contains("tab-content")
138 || focusableElement.classList.contains("dialog-content"))
139 break;
140
141 focusableElement = focusableElement.parentElement;
142 }
143 focusNextElement(focusableElement || document, control);
144 }
145 }
146
115 element.parentElement.removeChild(element); 147 element.parentElement.removeChild(element);
116 if (this.items.length == 0) 148 if (this.items.length == 0)
117 this._setEmpty(table, this.details[i].emptyText); 149 this._setEmpty(table, this.details[i].emptyText);
118 } 150 }
119 }; 151 };
120 152
153 Collection.prototype.updateItem = function(item)
154 {
155 var access = (item.url || item.text).replace(/'/g, "\\'");
156 for (var i = 0; i < this.details.length; i++)
157 {
158 var table = E(this.details[i].id);
159 var element = table.querySelector("[data-access='" + access + "']");
160 if (!element)
161 continue;
162
163 var title = item.title || item.url || item.text;
164 element.querySelector(".display").textContent = title;
165 if (title)
166 element.setAttribute("data-search", title.toLowerCase());
167 var control = element.querySelector(".control[role='checkbox']");
168 if (control)
169 control.setAttribute("aria-checked", item.disabled == false);
170
171 var downloadStatus = item.downloadStatus;
172 var dateElement = element.querySelector(".date");
173 var timeElement = element.querySelector(".time");
174 if(dateElement && timeElement)
175 {
176 var message = element.querySelector(".message");
177 ext.backgroundPage.sendMessage(
178 {
179 type: "subscriptions.isDownloading",
180 url: item.url
181 },
182 function(isDownloading)
183 {
184 if (isDownloading)
185 {
186 var text = getMessage("options_filterList_lastDownload_inProgress");
187 message.textContent = text;
188 element.classList.add("show-message");
189 }
190 else if (downloadStatus && downloadStatus != "synchronize_ok")
191 {
192 if (downloadStatus in filterErrors)
193 message.textContent = getMessage(filterErrors[downloadStatus]);
194 else
195 message.textContent = item.downloadStatus;
196 element.classList.add("show-message");
197 }
198 else if (item.lastDownload > 0)
199 {
200 var dateTime = i18n_formatDateTime(item.lastDownload * 1000);
201 dateElement.textContent = dateTime[0];
202 timeElement.textContent = dateTime[1];
203 element.classList.remove("show-message");
204 }
205 });
206 }
207 var websiteElement = element.querySelector(".context-menu .website");
208 var sourceElement = element.querySelector(".context-menu .source");
209 if (websiteElement && item.homepage)
210 websiteElement.setAttribute("href", item.homepage);
211 if (sourceElement)
212 sourceElement.setAttribute("href", item.url);
213 }
214 };
215
121 Collection.prototype.clearAll = function() 216 Collection.prototype.clearAll = function()
122 { 217 {
123 this.items = []; 218 this.items = [];
124 for (var i = 0; i < this.details.length; i++) 219 for (var i = 0; i < this.details.length; i++)
125 { 220 {
126 var table = E(this.details[i].id); 221 var table = E(this.details[i].id);
127 var template = table.querySelector("template");
128 var staticElements = [];
Thomas Greiner 2016/01/25 15:40:33 The above two variables are no longer used.
saroyanm 2016/01/26 18:36:19 Done.
129 var element = table.firstChild; 222 var element = table.firstChild;
130 while (element) 223 while (element)
131 { 224 {
132 if ((element.tagName == "LI" && !element.classList.contains("static")) | | 225 if (element.tagName == "LI" && !element.classList.contains("static"))
133 element.nodeType == 3)
134 table.removeChild(element); 226 table.removeChild(element);
135 element = element.nextSibling 227 element = element.nextElementSibling;
136 } 228 }
137 229
138 this._setEmpty(table, this.details[i].emptyText); 230 this._setEmpty(table, this.details[i].emptyText);
139 } 231 }
140 }; 232 };
141 233
142 Collection.prototype.hasId = function(id) 234 function focusNextElement(container, currentElement)
143 { 235 {
144 for (var i = 0; i < this.details.length; i++) 236 var focusables = container.querySelectorAll("a, button, input, .control");
145 if (this.details[i].id == id) 237 focusables = Array.prototype.slice.call(focusables);
146 return true; 238 var index = focusables.indexOf(currentElement);
147 239 index += (index == focusables.length - 1) ? -1 : 1;
148 return false; 240
149 }; 241 var nextElement = focusables[index];
150 242 if (!nextElement)
151 function updateBlockingList(listItem, subscription) 243 return false;
152 { 244
153 var dateElement = listItem.querySelector(".date"); 245 nextElement.focus();
154 var timeElement = listItem.querySelector(".time"); 246 return true;
155
156 if(dateElement && timeElement)
157 {
158 if (subscription.downloadStatus &&
159 subscription.downloadStatus != "synchronize_ok")
160 {
161 var map =
162 {
163 "synchronize_invalid_url": "options_subscription_lastDownload_invalidU RL",
164 "synchronize_connection_error": "options_subscription_lastDownload_con nectionError",
165 "synchronize_invalid_data": "options_subscription_lastDownload_invalid Data",
166 "synchronize_checksum_mismatch": "options_subscription_lastDownload_ch ecksumMismatch"
167 };
168 if (subscription.downloadStatus in map)
169 timeElement.textContent = ext.i18n.getMessage(map[subscription.downloa dStatus]);
170 else
171 timeElement.textContent = subscription.downloadStatus;
172 }
173 else if (subscription.lastDownload > 0)
174 {
175 var timedate = i18n_timeDateStrings(subscription.lastDownload * 1000);
176 var date = new Date(subscription.lastDownload * 1000);
177 dateElement.textContent = date.getFullYear() + "-" +
178 date.getMonth()+1 + "-" + date.getDate();
179 timeElement.textContent = date.getHours() + ":" + date.getMinutes();
180 }
181 }
182 var websiteElement = listItem.querySelector(".context-menu .website");
183 var sourceElement = listItem.querySelector(".context-menu .source");
184 if (websiteElement && subscription.homepage)
185 websiteElement.setAttribute("href", subscription.homepage);
186 if (sourceElement)
187 sourceElement.setAttribute("href", subscription.url);
188 } 247 }
189 248
190 function toggleRemoveSubscription(e) 249 function toggleRemoveSubscription(e)
191 { 250 {
192 e.preventDefault(); 251 e.preventDefault();
193 var subscriptionUrl = getParentAccessElement(e.target). 252 var subscriptionUrl = findParentData(e.target, "access", false);
194 getAttribute("data-access"); 253 if (e.target.getAttribute("aria-checked") == "true")
195 if (!e.target.checked)
196 { 254 {
197 ext.backgroundPage.sendMessage({ 255 ext.backgroundPage.sendMessage({
198 type: "subscriptions.remove", 256 type: "subscriptions.remove",
199 url: subscriptionUrl 257 url: subscriptionUrl
200 }); 258 });
201 } 259 }
202 else 260 else
203 addEnableSubscription(subscriptionUrl); 261 addEnableSubscription(subscriptionUrl);
204 } 262 }
205 263
206 function toggleDisableSubscription(e) 264 function toggleDisableSubscription(e)
207 { 265 {
208 e.preventDefault(); 266 e.preventDefault();
209 var subscriptionUrl = e.target.parentNode.getAttribute("data-access"); 267 var subscriptionUrl = findParentData(e.target, "access", false);
210 ext.backgroundPage.sendMessage( 268 ext.backgroundPage.sendMessage(
211 { 269 {
212 type: "subscriptions.toggle", 270 type: "subscriptions.toggle",
213 keepInstalled: true, 271 keepInstalled: true,
214 url: subscriptionUrl 272 url: subscriptionUrl
215 }); 273 });
216 } 274 }
217 275
218 function onAddLanguageSubscriptionClick(e) 276 function onAddLanguageSubscriptionClick(e)
219 { 277 {
220 e.preventDefault(); 278 e.preventDefault();
221 var url = this.parentNode.getAttribute("data-access"); 279 var url = findParentData(this, "access", false);
222 addEnableSubscription(url); 280 addEnableSubscription(url);
223 } 281 }
224 282
225 function onRemoveFilterClick() 283 function onRemoveFilterClick()
226 { 284 {
227 var filter = this.parentNode.getAttribute("data-access"); 285 var filter = findParentData(this, "access", false);
228 ext.backgroundPage.sendMessage( 286 ext.backgroundPage.sendMessage(
229 { 287 {
230 type: "filters.remove", 288 type: "filters.remove",
231 text: filter 289 text: filter
232 }); 290 });
233 } 291 }
234 292
235 collections.popular = new Collection( 293 collections.popular = new Collection(
236 [ 294 [
237 { 295 {
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
281 onClick: onRemoveFilterClick 339 onClick: onRemoveFilterClick
282 } 340 }
283 ]); 341 ]);
284 collections.customFilters = new Collection( 342 collections.customFilters = new Collection(
285 [ 343 [
286 { 344 {
287 id: "custom-filters-table", 345 id: "custom-filters-table",
288 emptyText: "options_customFilters_empty" 346 emptyText: "options_customFilters_empty"
289 } 347 }
290 ]); 348 ]);
291 collections.blockingLists = new Collection( 349 collections.filterLists = new Collection(
292 [ 350 [
293 { 351 {
294 id: "blocking-lists-table", 352 id: "all-filter-lists-table",
295 onClick: toggleDisableSubscription 353 onClick: toggleDisableSubscription
296 } 354 }
297 ]); 355 ]);
298 356
299 function observeSubscription(subscription) 357 function observeSubscription(subscription)
300 { 358 {
301 function onObjectChanged(change) 359 function onObjectChanged(change)
302 { 360 {
303 for (var i = 0; i < change.length; i++) 361 for (var i = 0; i < change.length; i++)
304 { 362 {
305 var property = change[i].name; 363 if (change[i].name == "disabled")
306 if (property == "disabled") 364 {
307 { 365 var recommendation = recommendationsMap[subscription.url];
308 var access = (subscription.url || 366 if (recommendation && recommendation.type == "ads")
309 subscription.text).replace(/'/g, "\\'"); 367 {
310 var elements = document.querySelectorAll("[data-access='" + access + " ']"); 368 if (subscription.disabled == false)
311 for (var i = 0; i < elements.length; i++)
312 {
313 var element = elements[i];
314 var tableId = element.parentElement ? element.parentElement.id : "";
315 var control = element.querySelector(".control");
316 if (control && control.localName == "input")
317 control.checked = subscription.disabled == false;
318 if (subscription.url in recommendationsMap)
319 { 369 {
320 var recommendation = recommendationsMap[subscription.url]; 370 collections.allLangs.removeItem(subscription);
321 if (recommendation.type == "ads" && 371 collections.langs.addItems(subscription);
322 (collections.langs.hasId(tableId) ||
323 collections.allLangs.hasId(tableId)))
Thomas Greiner 2016/01/25 15:40:33 I've been thinking about this again. Wouldn't you
saroyanm 2016/01/26 18:36:18 I assume you are referring to the "Collection.prot
Thomas Greiner 2016/01/27 17:16:57 I guess you're right. We can leave it here for now
saroyanm 2016/01/28 17:00:11 Done, hope now it's more clear.
324 {
325 if (subscription.disabled == false)
326 {
327 collections.allLangs.removeItem(subscription);
328 collections.langs.addItems(subscription);
329 }
330 else
331 {
332 collections.allLangs.addItems(subscription);
333 collections.langs.removeItem(subscription);
334 }
335 }
336 } 372 }
373 else
374 {
375 collections.allLangs.addItems(subscription);
376 collections.langs.removeItem(subscription);
377 }
337 } 378 }
338 } 379 }
339 else 380 for (var i in collections)
340 { 381 collections[i].updateItem(subscription);
341 var blockingListId = collections.blockingLists.details[0].id;
342 var blockingList = document.getElementById(blockingListId);
343 var listItem = blockingList.querySelector("[data-access='" +
344 subscription.url + "']");
345 if (listItem)
346 updateBlockingList(listItem, subscription);
347 }
348 } 382 }
349 } 383 }
350 384
351 if (!Object.observe) 385 if (!Object.observe)
352 { 386 {
353 ["disabled", "lastDownload"].forEach(function(property) 387 ["disabled", "lastDownload"].forEach(function(property)
354 { 388 {
355 subscription["$" + property] = subscription[property]; 389 subscription["$" + property] = subscription[property];
356 Object.defineProperty(subscription, property, 390 Object.defineProperty(subscription, property,
357 { 391 {
358 get: function() 392 get: function()
359 { 393 {
360 return this["$" + property]; 394 return this["$" + property];
361 }, 395 },
362 set: function(value) 396 set: function(newValue)
363 { 397 {
364 this["$" + property] = value; 398 var oldValue = this["$" + property];
365 var change = Object.create(null); 399 if (oldValue != newValue)
366 change.name = property; 400 {
367 onObjectChanged([change]); 401 this["$" + property] = newValue;
402 var change = Object.create(null);
403 change.name = property;
404 onObjectChanged([change]);
405 }
368 } 406 }
369 }); 407 });
370 }); 408 });
371 } 409 }
372 else 410 else
373 { 411 {
374 Object.observe(subscription, onObjectChanged); 412 Object.observe(subscription, onObjectChanged);
375 } 413 }
376 } 414 }
377 415
378 function updateSubscription(subscription) 416 function updateSubscription(subscription)
379 { 417 {
380 var subscriptionUrl = subscription.url; 418 var subscriptionUrl = subscription.url;
381 var knownSubscription = subscriptionsMap[subscriptionUrl]; 419 var knownSubscription = subscriptionsMap[subscriptionUrl];
382 if (knownSubscription) 420 if (knownSubscription)
383 { 421 {
384 for (var param in subscription) 422 for (var property in subscription)
Thomas Greiner 2016/01/25 15:40:31 Detail: It's a property, not a parameter.
saroyanm 2016/01/26 18:36:19 Done.
385 if (param != "title") 423 if (property != "title")
Thomas Greiner 2016/01/25 15:40:31 Why did you specifically exclude the "title" prope
saroyanm 2016/01/26 18:36:19 To use titles specified in Recommendation, so the
Thomas Greiner 2016/01/27 17:16:57 Right, forgot about that case. It's actually tric
saroyanm 2016/01/28 17:00:11 Acknowledged.
386 knownSubscription[param] = subscription[param]; 424 knownSubscription[property] = subscription[property];
387 } 425 }
388 else 426 else
389 { 427 {
390 observeSubscription(subscription); 428 observeSubscription(subscription);
391 getAcceptableAdsURL(function(acceptableAdsUrl) 429 getAcceptableAdsURL(function(acceptableAdsUrl)
392 { 430 {
393 var collection = null; 431 var collection = null;
394 if (subscriptionUrl in recommendationsMap) 432 if (subscriptionUrl in recommendationsMap)
395 { 433 {
396 var recommendation = recommendationsMap[subscriptionUrl]; 434 var recommendation = recommendationsMap[subscriptionUrl];
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
446 subscription.url = element.getAttribute("url"); 484 subscription.url = element.getAttribute("url");
447 subscription.disabled = null; 485 subscription.disabled = null;
448 subscription.downloadStatus = null; 486 subscription.downloadStatus = null;
449 subscription.homepage = null; 487 subscription.homepage = null;
450 var recommendation = Object.create(null); 488 var recommendation = Object.create(null);
451 recommendation.type = element.getAttribute("type"); 489 recommendation.type = element.getAttribute("type");
452 var prefix = element.getAttribute("prefixes"); 490 var prefix = element.getAttribute("prefixes");
453 if (prefix) 491 if (prefix)
454 { 492 {
455 prefix = prefix.replace(/\W/g, "_"); 493 prefix = prefix.replace(/\W/g, "_");
456 subscription.title = ext.i18n.getMessage("options_language_" + prefi x); 494 subscription.title = getMessage("options_language_" + prefix);
457 } 495 }
458 else 496 else
459 { 497 {
460 var type = recommendation.type.replace(/\W/g, "_"); 498 var type = recommendation.type.replace(/\W/g, "_");
461 subscription.title = ext.i18n.getMessage("common_feature_" + type + "_title"); 499 subscription.title = getMessage("common_feature_" + type + "_title") ;
462 } 500 }
463 501
464 recommendationsMap[subscription.url] = recommendation; 502 recommendationsMap[subscription.url] = recommendation;
465 updateSubscription(subscription); 503 updateSubscription(subscription);
466 } 504 }
467 }); 505 });
468 } 506 }
469 507
470 function getParentAccessElement(element) 508 function findParentData(element, dataName, returnElement)
471 { 509 {
472 while (!element.getAttribute("data-access")) 510 while (element)
473 element = element.parentNode; 511 {
Thomas Greiner 2016/01/25 15:40:33 This may cause an exception if there is no parent
saroyanm 2016/01/26 18:36:19 Like it, thanks.
474 512 if (element.hasAttribute("data-" + dataName))
475 return element; 513 return returnElement ? element : element.getAttribute("data-" + dataName );
514
515 element = element.parentElement;
516 }
517 return null;
476 } 518 }
477 519
478 function onClick(e) 520 function onClick(e)
479 { 521 {
522 var context = document.querySelector(".show-context-menu");
523 if (context)
524 context.classList.remove("show-context-menu");
525
480 var element = e.target; 526 var element = e.target;
481 while (true) 527 while (true)
482 { 528 {
483 if (!element) 529 if (!element)
484 {
485 var context = document.querySelector(".context");
486 if (context)
487 context.classList.remove("context");
488 return; 530 return;
489 }
490 531
491 if (element.hasAttribute("data-action")) 532 if (element.hasAttribute("data-action"))
492 break; 533 break;
493 534
494 element = element.parentElement; 535 element = element.parentElement;
495 } 536 }
496 537
497 var actions = element.getAttribute("data-action").split(","); 538 var actions = element.getAttribute("data-action").split(",");
498 for (var i = 0; i < actions.length; i++) 539 for (var i = 0; i < actions.length; i++)
499 { 540 {
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
547 document.body.setAttribute("data-tab", 588 document.body.setAttribute("data-tab",
548 element.getAttribute("data-tab")); 589 element.getAttribute("data-tab"));
549 break; 590 break;
550 case "update-all-subscriptions": 591 case "update-all-subscriptions":
551 ext.backgroundPage.sendMessage( 592 ext.backgroundPage.sendMessage(
552 { 593 {
553 type: "subscriptions.update" 594 type: "subscriptions.update"
554 }); 595 });
555 break; 596 break;
556 case "open-context-menu": 597 case "open-context-menu":
557 var listItem = getParentAccessElement(element); 598 var listItem = findParentData(element, "access", true);
558 var contextMenu = listItem.querySelector(".content"); 599 if (listItem != context)
559 listItem.classList.add("context"); 600 listItem.classList.add("show-context-menu");
560 break; 601 break;
561 case "update-now": 602 case "update-subscription":
562 ext.backgroundPage.sendMessage( 603 ext.backgroundPage.sendMessage(
563 { 604 {
564 type: "subscriptions.update", 605 type: "subscriptions.update",
565 url: getParentAccessElement(element).getAttribute("data-access") 606 url: findParentData(element, "access", false)
566 }); 607 });
567 getParentAccessElement(element).classList.remove("context"); 608 break;
Thomas Greiner 2016/01/25 15:40:33 Why not just add a "close-context-menu" action to
saroyanm 2016/01/26 18:36:19 Done.
568 break; 609 case "remove-subscription":
569 case "website":
570 getParentAccessElement(element).classList.remove("context");
571 break;
572 case "source":
573 getParentAccessElement(element).classList.remove("context");
574 break;
575 case "delete":
Thomas Greiner 2016/01/25 15:40:33 Detail: This message name doesn't describe what it
saroyanm 2016/01/26 18:36:18 Done.
576 ext.backgroundPage.sendMessage( 610 ext.backgroundPage.sendMessage(
577 { 611 {
578 type: "subscriptions.remove", 612 type: "subscriptions.remove",
579 url: getParentAccessElement(element).getAttribute("data-access") 613 url: findParentData(element, "access", false)
580 }); 614 });
581 getParentAccessElement(element).classList.remove("context");
582 break; 615 break;
583 } 616 }
584 } 617 }
585 } 618 }
586 619
587 function onDOMLoaded() 620 function onDOMLoaded()
588 { 621 {
589 populateLists(); 622 populateLists();
590 function onFindLanguageKeyUp() 623 function onFindLanguageKeyUp()
591 { 624 {
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
626 659
627 getDocLink("contribute", function(link) 660 getDocLink("contribute", function(link)
628 { 661 {
629 document.querySelector("#tab-contribute a").setAttribute("href", link); 662 document.querySelector("#tab-contribute a").setAttribute("href", link);
630 }); 663 });
631 664
632 updateShareLink(); 665 updateShareLink();
633 666
634 // Initialize interactive UI elements 667 // Initialize interactive UI elements
635 document.body.addEventListener("click", onClick, false); 668 document.body.addEventListener("click", onClick, false);
636 var placeholderValue = ext.i18n.getMessage("options_dialog_language_find"); 669 var placeholderValue = getMessage("options_dialog_language_find");
637 E("find-language").setAttribute("placeholder", placeholderValue); 670 E("find-language").setAttribute("placeholder", placeholderValue);
638 E("find-language").addEventListener("keyup", onFindLanguageKeyUp, false); 671 E("find-language").addEventListener("keyup", onFindLanguageKeyUp, false);
639 E("whitelisting-textbox").addEventListener("keypress", function(e) 672 E("whitelisting-textbox").addEventListener("keypress", function(e)
640 { 673 {
641 if (getKey(e) == "Enter") 674 if (getKey(e) == "Enter")
642 addWhitelistedDomain(); 675 addWhitelistedDomain();
643 }, false); 676 }, false);
644 677
645 // Advanced tab 678 // Advanced tab
646 var filterTextbox = document.querySelector("#custom-filters-add input"); 679 var filterTextbox = document.querySelector("#custom-filters-add input");
647 placeholderValue = ext.i18n.getMessage("options_customFilters_textbox_placeh older"); 680 placeholderValue = getMessage("options_customFilters_textbox_placeholder");
648 filterTextbox.setAttribute("placeholder", placeholderValue); 681 filterTextbox.setAttribute("placeholder", placeholderValue);
649 function addCustomFilters() 682 function addCustomFilters()
650 { 683 {
651 var filterText = filterTextbox.value; 684 var filterText = filterTextbox.value;
652 ext.backgroundPage.sendMessage( 685 ext.backgroundPage.sendMessage(
653 { 686 {
654 type: "filters.add", 687 type: "filters.add",
655 text: filterText 688 text: filterText
656 }); 689 });
657 filterTextbox.value = ""; 690 filterTextbox.value = "";
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
745 updateFilter(filters[i]); 778 updateFilter(filters[i]);
746 }); 779 });
747 } 780 }
748 }); 781 });
749 loadRecommendations(); 782 loadRecommendations();
750 getAcceptableAdsURL(function(acceptableAdsUrl) 783 getAcceptableAdsURL(function(acceptableAdsUrl)
751 { 784 {
752 var subscription = Object.create(null); 785 var subscription = Object.create(null);
753 subscription.url = acceptableAdsUrl; 786 subscription.url = acceptableAdsUrl;
754 subscription.disabled = true; 787 subscription.disabled = true;
755 subscription.title = ext.i18n.getMessage("options_acceptableAds_descriptio n"); 788 subscription.title = getMessage("options_acceptableAds_description");
756 updateSubscription(subscription); 789 updateSubscription(subscription);
757 790
758 // Load user subscriptions 791 // Load user subscriptions
759 ext.backgroundPage.sendMessage( 792 ext.backgroundPage.sendMessage(
760 { 793 {
761 type: "subscriptions.get", 794 type: "subscriptions.get",
762 downloadable: true 795 downloadable: true
763 }, 796 },
764 function(subscriptions) 797 function(subscriptions)
765 { 798 {
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after
856 function onSubscriptionMessage(action, subscription) 889 function onSubscriptionMessage(action, subscription)
857 { 890 {
858 switch (action) 891 switch (action)
859 { 892 {
860 case "added": 893 case "added":
861 updateSubscription(subscription); 894 updateSubscription(subscription);
862 updateShareLink(); 895 updateShareLink();
863 896
864 var knownSubscription = subscriptionsMap[subscription.url]; 897 var knownSubscription = subscriptionsMap[subscription.url];
865 if (knownSubscription) 898 if (knownSubscription)
866 collections.blockingLists.addItems(knownSubscription); 899 collections.filterLists.addItems(knownSubscription);
867 else 900 else
868 collections.blockingLists.addItems(subscription); 901 collections.filterLists.addItems(subscription);
869 break; 902 break;
870 case "disabled": 903 case "disabled":
871 updateSubscription(subscription); 904 updateSubscription(subscription);
872 updateShareLink(); 905 updateShareLink();
873 break; 906 break;
874 case "lastDownload": 907 case "lastDownload":
875 updateSubscription(subscription); 908 updateSubscription(subscription);
876 break; 909 break;
877 case "homepage": 910 case "homepage":
878 // TODO: NYI 911 // TODO: NYI
(...skipping 11 matching lines...) Expand all
890 { 923 {
891 if (subscription.url in recommendationsMap) 924 if (subscription.url in recommendationsMap)
892 knownSubscription.disabled = true; 925 knownSubscription.disabled = true;
893 else 926 else
894 { 927 {
895 collections.custom.removeItem(knownSubscription); 928 collections.custom.removeItem(knownSubscription);
896 delete subscriptionsMap[subscription.url]; 929 delete subscriptionsMap[subscription.url];
897 } 930 }
898 } 931 }
899 updateShareLink(); 932 updateShareLink();
933 collections.filterLists.removeItem(knownSubscription);
900 }); 934 });
901 collections.blockingLists.removeItem(knownSubscription);
Thomas Greiner 2016/01/25 15:40:38 Detail: Semantically, updating the UI should happe
saroyanm 2016/01/26 18:36:18 Done.
902 break; 935 break;
903 case "title": 936 case "title":
904 // TODO: NYI 937 // TODO: NYI
905 break; 938 break;
906 } 939 }
907 } 940 }
908 941
909 function onShareLinkClick(e) 942 function onShareLinkClick(e)
910 { 943 {
911 e.preventDefault(); 944 e.preventDefault();
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
980 filter: ["addSubscription", "error"] 1013 filter: ["addSubscription", "error"]
981 }); 1014 });
982 ext.backgroundPage.sendMessage( 1015 ext.backgroundPage.sendMessage(
983 { 1016 {
984 type: "filters.listen", 1017 type: "filters.listen",
985 filter: ["added", "loaded", "removed"] 1018 filter: ["added", "loaded", "removed"]
986 }); 1019 });
987 ext.backgroundPage.sendMessage( 1020 ext.backgroundPage.sendMessage(
988 { 1021 {
989 type: "subscriptions.listen", 1022 type: "subscriptions.listen",
990 filter: ["added", "disabled", "homepage", "lastDownload", "removed", "title" , "updated"] 1023 filter: ["added", "disabled", "homepage", "lastDownload", "removed", "title" ]
Thomas Greiner 2016/01/25 15:40:32 Detail: You removed the handling for "updated" so
saroyanm 2016/01/26 18:36:20 Done.
991 }); 1024 });
992 1025
993 window.addEventListener("DOMContentLoaded", onDOMLoaded, false); 1026 window.addEventListener("DOMContentLoaded", onDOMLoaded, false);
994 })(); 1027 })();
LEFTRIGHT

Powered by Google App Engine
This is Rietveld