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

Delta Between Two Patch Sets: new-options.js

Issue 29445590: Issue 5255 - Advanced tab (HTML, strings and functionality) (Closed)
Left Patch Set: Addressed Thomas comments Created July 12, 2017, 1:03 p.m.
Right Patch Set: Fixed nits Created July 14, 2017, 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
« no previous file with change/comment | « new-options.html ('k') | skin/new-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-2017 eyeo GmbH 3 * Copyright (C) 2006-2017 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 /* globals checkShareResource, getDocLink, i18nFormatDateTime, openSharePopup, 18 /* globals checkShareResource, getDocLink, i18nFormatDateTime, openSharePopup,
19 E */ 19 E */
20 20
21 "use strict"; 21 "use strict";
22 22
23 { 23 {
24 let subscriptionsMap = Object.create(null); 24 let subscriptionsMap = Object.create(null);
25 let filtersMap = Object.create(null); 25 let filtersMap = Object.create(null);
26 let collections = Object.create(null); 26 let collections = Object.create(null);
27 let acceptableAdsUrl = null; 27 let acceptableAdsUrl = null;
28 let isCustomFiltersLoaded = false; 28 let isCustomFiltersLoaded = false;
29 let {getMessage} = ext.i18n; 29 let {getMessage} = ext.i18n;
30 let customFiltersArray = []; 30 let customFilters = [];
Thomas Greiner 2017/07/14 12:26:13 Detail: I'd recommend not to include the value typ
saroyanm 2017/07/14 16:17:25 Acknowledged.
saroyanm 2017/07/14 17:11:06 Done.
31 let filterErrors = new Map([ 31 let filterErrors = new Map([
32 ["synchronize_invalid_url", 32 ["synchronize_invalid_url",
33 "options_filterList_lastDownload_invalidURL"], 33 "options_filterList_lastDownload_invalidURL"],
34 ["synchronize_connection_error", 34 ["synchronize_connection_error",
35 "options_filterList_lastDownload_connectionError"], 35 "options_filterList_lastDownload_connectionError"],
36 ["synchronize_invalid_data", 36 ["synchronize_invalid_data",
37 "options_filterList_lastDownload_invalidData"], 37 "options_filterList_lastDownload_invalidData"],
38 ["synchronize_checksum_mismatch", 38 ["synchronize_checksum_mismatch",
39 "options_filterList_lastDownload_checksumMismatch"] 39 "options_filterList_lastDownload_checksumMismatch"]
40 ]); 40 ]);
41 41 const timestampUI = Symbol();
42 const whitelistedDomainRegexp = /^@@\|\|([^/:]+)\^\$document$/; 42 const whitelistedDomainRegexp = /^@@\|\|([^/:]+)\^\$document$/;
43 // Period of time in milliseconds 43 // Period of time in milliseconds
44 const minuteInMs = 60000; 44 const minuteInMs = 60000;
45 const hourInMs = 3600000; 45 const hourInMs = 3600000;
46 const fullDayInMs = 86400000; 46 const fullDayInMs = 86400000;
47 47
48 function Collection(details) 48 function Collection(details)
49 { 49 {
50 this.details = details; 50 this.details = details;
51 this.items = []; 51 this.items = [];
52 } 52 }
53 53
54 Collection.prototype._setEmpty = function(table, text) 54 Collection.prototype._setEmpty = function(table, texts)
55 { 55 {
56 let placeholder = table.querySelector(".empty-placeholder"); 56 let placeholders = table.querySelectorAll(".empty-placeholder");
57 if (text && !placeholder) 57
58 { 58 if (texts && placeholders.length == 0)
59 placeholder = document.createElement("li"); 59 {
60 placeholder.className = "empty-placeholder"; 60 for (let text of texts)
61 placeholder.textContent = getMessage(text); 61 {
62 table.appendChild(placeholder); 62 let placeholder = document.createElement("li");
63 } 63 placeholder.className = "empty-placeholder";
64 else if (placeholder) 64 placeholder.textContent = getMessage(text);
65 table.removeChild(placeholder); 65 table.appendChild(placeholder);
66 }
67 }
68 else if (placeholders.length > 0)
69 {
70 for (let placeholder of placeholders)
71 table.removeChild(placeholder);
72 }
66 }; 73 };
67 74
68 Collection.prototype._createElementQuery = function(item) 75 Collection.prototype._createElementQuery = function(item)
69 { 76 {
70 let access = (item.url || item.text).replace(/'/g, "\\'"); 77 let access = (item.url || item.text).replace(/'/g, "\\'");
71 return function(container) 78 return function(container)
72 { 79 {
73 return container.querySelector("[data-access='" + access + "']"); 80 return container.querySelector("[data-access='" + access + "']");
74 }; 81 };
75 }; 82 };
76 83
77 Collection.prototype._getItemTitle = function(item, i) 84 Collection.prototype._getItemTitle = function(item, i)
78 { 85 {
79 if (item.url == acceptableAdsUrl) 86 if (item.url == acceptableAdsUrl)
80 return getMessage("options_acceptableAds_description"); 87 return getMessage("options_acceptableAds_description");
81 if (this.details[i].useOriginalTitle && item.originalTitle) 88 if (this.details[i].useOriginalTitle && item.originalTitle)
82 return item.originalTitle; 89 return item.originalTitle;
83 return item.title || item.url || item.text; 90 return item.title || item.url || item.text;
84 }; 91 };
85 92
86 Collection.prototype.addItem = function(item) 93 Collection.prototype._sortItems = function()
87 { 94 {
88 if (this.items.indexOf(item) >= 0)
89 return;
90
91 this.items.push(item);
92 this.items.sort((a, b) => 95 this.items.sort((a, b) =>
93 { 96 {
94 // Make sure that Acceptable Ads is always last, since it cannot be 97 // Make sure that Acceptable Ads is always last, since it cannot be
95 // disabled, but only be removed. That way it's grouped together with 98 // disabled, but only be removed. That way it's grouped together with
96 // the "Own filter list" which cannot be disabled either at the bottom 99 // the "Own filter list" which cannot be disabled either at the bottom
97 // of the filter lists in the Advanced tab. 100 // of the filter lists in the Advanced tab.
98 if (a.url == acceptableAdsUrl) 101 if (a.url == acceptableAdsUrl)
99 return 1; 102 return 1;
100 if (b.url == acceptableAdsUrl) 103 if (b.url == acceptableAdsUrl)
101 return -1; 104 return -1;
102 105
106 // Make sure that newly added entries always appear on top in descending
107 // chronological order
108 let aTimestamp = a[timestampUI] || 0;
109 let bTimestamp = b[timestampUI] || 0;
110 if (aTimestamp || bTimestamp)
111 return bTimestamp - aTimestamp;
112
103 let aTitle = this._getItemTitle(a, 0).toLowerCase(); 113 let aTitle = this._getItemTitle(a, 0).toLowerCase();
104 let bTitle = this._getItemTitle(b, 0).toLowerCase(); 114 let bTitle = this._getItemTitle(b, 0).toLowerCase();
105 return aTitle.localeCompare(bTitle); 115 return aTitle.localeCompare(bTitle);
106 }); 116 });
107 117 };
118
119 Collection.prototype.addItem = function(item)
120 {
121 if (this.items.indexOf(item) >= 0)
122 return;
123
124 this.items.push(item);
125 this._sortItems();
108 for (let j = 0; j < this.details.length; j++) 126 for (let j = 0; j < this.details.length; j++)
109 { 127 {
110 let detail = this.details[j]; 128 let detail = this.details[j];
111 let table = E(detail.id); 129 let table = E(detail.id);
112 let template = table.querySelector("template"); 130 let template = table.querySelector("template");
113 let listItem = document.createElement("li"); 131 let listItem = document.createElement("li");
114 listItem.appendChild(document.importNode(template.content, true)); 132 listItem.appendChild(document.importNode(template.content, true));
115 listItem.setAttribute("aria-label", this._getItemTitle(item, j)); 133 listItem.setAttribute("aria-label", this._getItemTitle(item, j));
116 listItem.setAttribute("data-access", item.url || item.text); 134 listItem.setAttribute("data-access", item.url || item.text);
117 listItem.setAttribute("role", "section"); 135 listItem.setAttribute("role", "section");
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
178 } 196 }
179 197
180 element.parentElement.removeChild(element); 198 element.parentElement.removeChild(element);
181 if (this.items.length == 0) 199 if (this.items.length == 0)
182 this._setEmpty(table, detail.emptyText); 200 this._setEmpty(table, detail.emptyText);
183 } 201 }
184 }; 202 };
185 203
186 Collection.prototype.updateItem = function(item) 204 Collection.prototype.updateItem = function(item)
187 { 205 {
206 let oldIndex = this.items.indexOf(item);
207 this._sortItems();
188 let access = (item.url || item.text).replace(/'/g, "\\'"); 208 let access = (item.url || item.text).replace(/'/g, "\\'");
189 for (let i = 0; i < this.details.length; i++) 209 for (let i = 0; i < this.details.length; i++)
190 { 210 {
191 let table = E(this.details[i].id); 211 let table = E(this.details[i].id);
192 let element = table.querySelector("[data-access='" + access + "']"); 212 let element = table.querySelector("[data-access='" + access + "']");
193 if (!element) 213 if (!element)
194 continue; 214 continue;
195 215
196 let title = this._getItemTitle(item, i); 216 let title = this._getItemTitle(item, i);
197 element.querySelector(".display").textContent = title; 217 element.querySelector(".display").textContent = title;
198 element.setAttribute("aria-label", title); 218 element.setAttribute("aria-label", title);
199 if (this.details[i].searchable) 219 if (this.details[i].searchable)
200 element.setAttribute("data-search", title.toLowerCase()); 220 element.setAttribute("data-search", title.toLowerCase());
201 let control = element.querySelector(".control[role='checkbox']"); 221 let control = element.querySelector(".control[role='checkbox']");
202 if (control) 222 if (control)
203 { 223 {
204 control.setAttribute("aria-checked", item.disabled == false); 224 control.setAttribute("aria-checked", item.disabled == false);
205 if (item.url == acceptableAdsUrl && this == collections.filterLists) 225 if (item.url == acceptableAdsUrl && this == collections.filterLists)
206 control.setAttribute("disabled", true); 226 control.disabled = true;
207 } 227 }
208 228
209 let lastUpdateElement = element.querySelector(".last-update"); 229 let lastUpdateElement = element.querySelector(".last-update");
210 if (lastUpdateElement) 230 if (lastUpdateElement)
211 { 231 {
212 let message = element.querySelector(".message"); 232 let message = element.querySelector(".message");
213 if (item.isDownloading) 233 if (item.isDownloading)
214 { 234 {
215 let text = getMessage("options_filterList_lastDownload_inProgress"); 235 let text = getMessage("options_filterList_lastDownload_inProgress");
216 message.textContent = text; 236 message.textContent = text;
217 element.classList.add("show-message"); 237 element.classList.add("show-message");
218 } 238 }
219 else if (item.downloadStatus != "synchronize_ok") 239 else if (item.downloadStatus != "synchronize_ok")
220 { 240 {
221 let error = filterErrors.get(item.downloadStatus); 241 let error = filterErrors.get(item.downloadStatus);
222 if (error) 242 if (error)
223 message.textContent = getMessage(error); 243 message.textContent = getMessage(error);
224 else 244 else
225 message.textContent = item.downloadStatus; 245 message.textContent = item.downloadStatus;
226 element.classList.add("show-message"); 246 element.classList.add("show-message");
227 } 247 }
228 else if (item.lastDownload > 0) 248 else if (item.lastDownload > 0)
229 { 249 {
230 let lastUpdate = item.lastDownload * 1000; 250 let lastUpdate = item.lastDownload * 1000;
231 let lastUpdateLive = function() 251 let sinceUpdate = Date.now() - lastUpdate;
252 if (sinceUpdate > fullDayInMs)
232 { 253 {
233 let sinceUpdate = Date.now() - lastUpdate; 254 let lastUpdateDate = new Date(item.lastDownload * 1000);
234 if (sinceUpdate > fullDayInMs) 255 let monthName = lastUpdateDate.toLocaleString(undefined,
235 { 256 {month: "short"});
236 let lastUpdateDate = new Date(item.lastDownload * 1000); 257 let day = lastUpdateDate.getDate();
237 let monthName = lastUpdateDate.toLocaleString(undefined, 258 day = day < 10 ? "0" + day : day;
238 {month: "short"}); 259 lastUpdateElement.textContent = day + " " + monthName + " " +
239 let day = lastUpdateDate.getDate(); 260 lastUpdateDate.getFullYear();
240 day = day < 10 ? "0" + day : day; 261 }
241 lastUpdateElement.textContent = day + " " + monthName + " " + 262 else if (sinceUpdate > hourInMs)
242 lastUpdateDate.getFullYear(); 263 {
243 } 264 lastUpdateElement.textContent =
244 else if (sinceUpdate > hourInMs) 265 getMessage("options_filterList_hours");
245 { 266 }
246 let placeholder = [Math.round(sinceUpdate / hourInMs)]; 267 else if (sinceUpdate > minuteInMs)
247 lastUpdateElement.textContent = 268 {
248 getMessage("options_filterList_hours", placeholder); 269 lastUpdateElement.textContent =
Thomas Greiner 2017/07/14 12:26:12 This placeholder isn't defined in new-options.json
saroyanm 2017/07/14 16:17:24 Well spotted, will remove it.
saroyanm 2017/07/14 17:11:06 Done.
249 } 270 getMessage("options_filterList_minutes");
250 else if (sinceUpdate > minuteInMs) 271 }
251 { 272 else
252 let placeholder = [Math.round(sinceUpdate / minuteInMs)]; 273 {
253 lastUpdateElement.textContent = 274 lastUpdateElement.textContent =
254 getMessage("options_filterList_minutes", placeholder); 275 getMessage("options_filterList_now");
255 } 276 }
256 else
257 {
258 lastUpdateElement.textContent =
259 getMessage("options_filterList_now");
260 }
261 };
262 lastUpdateLive();
263 element.classList.remove("show-message"); 277 element.classList.remove("show-message");
264 } 278 }
265 } 279 }
266 280
267 let websiteElement = element.querySelector(".context-menu .website"); 281 let websiteElement = element.querySelector(".context-menu .website");
268 if (websiteElement) 282 if (websiteElement)
269 { 283 {
270 if (item.homepage) 284 if (item.homepage)
271 websiteElement.setAttribute("href", item.homepage); 285 websiteElement.setAttribute("href", item.homepage);
272 else 286 else
273 websiteElement.setAttribute("aria-hidden", true); 287 websiteElement.setAttribute("aria-hidden", true);
274 } 288 }
275 289
276 let sourceElement = element.querySelector(".context-menu .source"); 290 let sourceElement = element.querySelector(".context-menu .source");
277 if (sourceElement) 291 if (sourceElement)
278 sourceElement.setAttribute("href", item.url); 292 sourceElement.setAttribute("href", item.url);
293
294 let newIndex = this.items.indexOf(item);
295 if (oldIndex != newIndex)
296 table.insertBefore(element, table.childNodes[newIndex]);
279 } 297 }
280 }; 298 };
281 299
282 Collection.prototype.clearAll = function() 300 Collection.prototype.clearAll = function()
283 { 301 {
284 this.items = []; 302 this.items = [];
285 for (let detail of this.details) 303 for (let detail of this.details)
286 { 304 {
287 let table = E(detail.id); 305 let table = E(detail.id);
288 let element = table.firstChild; 306 let element = table.firstChild;
(...skipping 24 matching lines...) Expand all
313 } 331 }
314 332
315 collections.popular = new Collection([ 333 collections.popular = new Collection([
316 { 334 {
317 id: "recommend-list-table" 335 id: "recommend-list-table"
318 } 336 }
319 ]); 337 ]);
320 collections.langs = new Collection([ 338 collections.langs = new Collection([
321 { 339 {
322 id: "blocking-languages-table", 340 id: "blocking-languages-table",
323 emptyText: "options_dialog_language_added_empty" 341 emptyText: ["options_dialog_language_added_empty"]
324 }, 342 },
325 { 343 {
326 id: "blocking-languages-dialog-table", 344 id: "blocking-languages-dialog-table",
327 emptyText: "options_dialog_language_added_empty" 345 emptyText: ["options_dialog_language_added_empty"]
328 } 346 }
329 ]); 347 ]);
330 collections.allLangs = new Collection([ 348 collections.allLangs = new Collection([
331 { 349 {
332 id: "all-lang-table", 350 id: "all-lang-table",
333 emptyText: "options_dialog_language_other_empty", 351 emptyText: ["options_dialog_language_other_empty"],
334 searchable: true 352 searchable: true
335 } 353 }
336 ]); 354 ]);
337 collections.acceptableAds = new Collection([ 355 collections.acceptableAds = new Collection([
338 { 356 {
339 id: "acceptableads-table" 357 id: "acceptableads-table"
340 } 358 }
341 ]); 359 ]);
342 collections.custom = new Collection([ 360 collections.custom = new Collection([
343 { 361 {
344 id: "custom-list-table" 362 id: "custom-list-table"
345 } 363 }
346 ]); 364 ]);
347 collections.whitelist = new Collection([ 365 collections.whitelist = new Collection([
348 { 366 {
349 id: "whitelisting-table", 367 id: "whitelisting-table",
350 emptyText: "options_whitelisted_empty" 368 emptyText: ["options_whitelist_empty_1", "options_whitelist_empty_2"]
351 } 369 }
352 ]); 370 ]);
353 collections.filterLists = new Collection([ 371 collections.filterLists = new Collection([
354 { 372 {
355 id: "all-filter-lists-table", 373 id: "all-filter-lists-table",
356 useOriginalTitle: true 374 useOriginalTitle: true
357 } 375 }
358 ]); 376 ]);
359 377
360 function toggleShowLanguage(subscription) 378 function toggleShowLanguage(subscription)
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
408 function updateFilter(filter) 426 function updateFilter(filter)
409 { 427 {
410 let match = filter.text.match(whitelistedDomainRegexp); 428 let match = filter.text.match(whitelistedDomainRegexp);
411 if (match && !filtersMap[filter.text]) 429 if (match && !filtersMap[filter.text])
412 { 430 {
413 filter.title = match[1]; 431 filter.title = match[1];
414 collections.whitelist.addItem(filter); 432 collections.whitelist.addItem(filter);
415 } 433 }
416 else 434 else
417 { 435 {
418 customFiltersArray.push(filter.text); 436 customFilters.push(filter.text);
419 if (isCustomFiltersLoaded) 437 if (isCustomFiltersLoaded)
Thomas Greiner 2017/07/14 12:26:12 Detail: What is this check for? It seems that `upd
saroyanm 2017/07/14 16:17:25 Shouldn't we wait only for the time when all filte
Thomas Greiner 2017/07/14 16:37:42 Right, I remember and I see that this has actually
saroyanm 2017/07/14 16:41:34 I agree, I'll create a separate issue for that, wh
420 updateCustomFiltersUi(); 438 updateCustomFiltersUi();
421 } 439 }
422 440
423 filtersMap[filter.text] = filter; 441 filtersMap[filter.text] = filter;
424 } 442 }
425 443
426 function removeCustomFilter(text) 444 function removeCustomFilter(text)
427 { 445 {
428 let index = customFiltersArray.indexOf(text); 446 let index = customFilters.indexOf(text);
429 if (index >= 0) 447 if (index >= 0)
430 customFiltersArray.splice(index, 1); 448 customFilters.splice(index, 1);
Thomas Greiner 2017/07/14 12:26:12 What if there are multiple instances of the same f
saroyanm 2017/07/14 16:17:25 There shouldn't be multiple instances of same filt
Thomas Greiner 2017/07/14 16:37:42 My thinking was that a pre-existing filter could a
saroyanm 2017/07/14 16:41:34 Acknowledged.
431 449
432 updateCustomFiltersUi(); 450 updateCustomFiltersUi();
433 } 451 }
434 452
435 function updateCustomFiltersUi() 453 function updateCustomFiltersUi()
436 { 454 {
437 let customFiltersListElement = E("custom-filters-raw"); 455 let customFiltersListElement = E("custom-filters-raw");
438 customFiltersListElement.value = ""; 456 customFiltersListElement.value = customFilters.join("\n");
Thomas Greiner 2017/07/14 12:26:12 Detail: This is redundant because the line below w
saroyanm 2017/07/14 16:17:24 Thanks for noticing. Will update.
saroyanm 2017/07/14 17:11:06 Done.
439 customFiltersListElement.value = customFiltersArray.join("\n");
440 } 457 }
441 458
442 function loadRecommendations() 459 function loadRecommendations()
443 { 460 {
444 fetch("subscriptions.xml") 461 fetch("subscriptions.xml")
445 .then((response) => 462 .then((response) =>
446 { 463 {
447 return response.text(); 464 return response.text();
448 }) 465 })
449 .then((text) => 466 .then((text) =>
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
516 else 533 else
517 location.href = link; 534 location.href = link;
518 }); 535 });
519 } 536 }
520 537
521 function switchTab(id) 538 function switchTab(id)
522 { 539 {
523 location.hash = id; 540 location.hash = id;
524 } 541 }
525 542
526 function execAction(action, element, event) 543 function execAction(action, element)
527 { 544 {
528 switch (action) 545 switch (action)
529 { 546 {
530 case "add-domain-exception": 547 case "add-domain-exception":
531 addWhitelistedDomain(); 548 addWhitelistedDomain();
532 break; 549 break;
533 case "add-language-subscription": 550 case "add-language-subscription":
534 addEnableSubscription(findParentData(element, "access", false)); 551 addEnableSubscription(findParentData(element, "access", false));
535 break; 552 break;
536 case "add-predefined-subscription": { 553 case "add-predefined-subscription": {
537 let dialog = E("dialog-content-predefined"); 554 let dialog = E("dialog-content-predefined");
538 let title = dialog.querySelector("h3").textContent; 555 let title = dialog.querySelector("h3").textContent;
539 let url = dialog.querySelector(".url").textContent; 556 let url = dialog.querySelector(".url").textContent;
540 addEnableSubscription(url, title); 557 addEnableSubscription(url, title);
541 closeDialog(); 558 closeDialog();
542 break; 559 break;
543 } 560 }
544 case "cancel-custom-filters": 561 case "cancel-custom-filters":
545 updateCustomFiltersUi();
546 setCustomFiltersView("read"); 562 setCustomFiltersView("read");
547 break;
548 case "cancel-domain-exception":
549 E("whitelisting-textbox").value = "";
550 document.querySelector("#whitelisting .controls").classList
551 .remove("mode-edit");
552 break; 563 break;
553 case "close-dialog": 564 case "close-dialog":
554 closeDialog(); 565 closeDialog();
555 break; 566 break;
556 case "edit-custom-filters": 567 case "edit-custom-filters":
557 setCustomFiltersView("write"); 568 setCustomFiltersView("write");
558 break;
559 case "edit-domain-exception":
560 document.querySelector("#whitelisting .controls").classList
561 .add("mode-edit");
562 E("whitelisting-textbox").focus();
563 break; 569 break;
564 case "import-subscription": { 570 case "import-subscription": {
565 let url = E("blockingList-textbox").value; 571 let url = E("blockingList-textbox").value;
566 addEnableSubscription(url); 572 addEnableSubscription(url);
567 closeDialog(); 573 closeDialog();
568 break; 574 break;
569 } 575 }
570 case "open-context-menu": { 576 case "open-context-menu": {
571 let listItem = findParentData(element, "access", true); 577 let listItem = findParentData(element, "access", true);
572 if (listItem && !listItem.classList.contains("show-context-menu")) 578 if (listItem && !listItem.classList.contains("show-context-menu"))
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
644 ext.backgroundPage.sendMessage({ 650 ext.backgroundPage.sendMessage({
645 type: "subscriptions.update", 651 type: "subscriptions.update",
646 url: findParentData(element, "access", false) 652 url: findParentData(element, "access", false)
647 }); 653 });
648 break; 654 break;
649 } 655 }
650 } 656 }
651 657
652 function setCustomFiltersView(mode) 658 function setCustomFiltersView(mode)
653 { 659 {
654 let customFilters = E("custom-filters"); 660 let customFiltersElement = E("custom-filters-raw");
655 let customFiltersListElement = E("custom-filters-raw"); 661 updateCustomFiltersUi();
656 if (mode == "read") 662 if (mode == "read")
657 { 663 {
658 customFiltersListElement.disabled = true; 664 customFiltersElement.disabled = true;
659 if (!customFiltersListElement.value) 665 if (!customFiltersElement.value)
660 { 666 {
661 setCustomFiltersView("empty"); 667 setCustomFiltersView("empty");
662 return; 668 return;
663 } 669 }
664 } 670 }
665 else if (mode == "write") 671 else if (mode == "write")
666 { 672 {
667 updateCustomFiltersUi(); 673 customFiltersElement.disabled = false;
Thomas Greiner 2017/07/14 12:26:13 Interesting that you're calling `updateCustomFilte
saroyanm 2017/07/14 16:17:25 You are right, I'm not sure why I did this.. I'll
saroyanm 2017/07/14 17:11:06 Done.
668 customFiltersListElement.disabled = false; 674 }
669 } 675
670 676 E("custom-filters").dataset.mode = mode;
671 customFilters.dataset.mode = mode;
672 } 677 }
673 678
674 function onClick(e) 679 function onClick(e)
675 { 680 {
676 let context = document.querySelector(".show-context-menu"); 681 let context = document.querySelector(".show-context-menu");
677 if (context) 682 if (context)
678 context.classList.remove("show-context-menu"); 683 context.classList.remove("show-context-menu");
679 684
680 let actions = findParentData(e.target, "action", false); 685 let actions = findParentData(e.target, "action", false);
681 if (!actions) 686 if (!actions)
682 return; 687 return;
683 688
684 actions = actions.split(","); 689 actions = actions.split(",");
685 for (let action of actions) 690 for (let action of actions)
686 { 691 {
687 execAction(action, e.target, e); 692 execAction(action, e.target);
688 } 693 }
689 } 694 }
690 695
691 function getKey(e) 696 function getKey(e)
692 { 697 {
693 // e.keyCode has been deprecated so we attempt to use e.key 698 // e.keyCode has been deprecated so we attempt to use e.key
694 if ("key" in e) 699 if ("key" in e)
695 return e.key; 700 return e.key;
696 return getKey.keys[e.keyCode]; 701 return getKey.keys[e.keyCode];
697 } 702 }
(...skipping 26 matching lines...) Expand all
724 { 729 {
725 if (key == "ArrowLeft" || key == "ArrowUp") 730 if (key == "ArrowLeft" || key == "ArrowUp")
726 element = element.previousElementSibling || container.lastElementChild; 731 element = element.previousElementSibling || container.lastElementChild;
727 else if (key == "ArrowRight" || key == "ArrowDown") 732 else if (key == "ArrowRight" || key == "ArrowDown")
728 element = element.nextElementSibling || container.firstElementChild; 733 element = element.nextElementSibling || container.firstElementChild;
729 } 734 }
730 735
731 let actions = container.getAttribute("data-action").split(","); 736 let actions = container.getAttribute("data-action").split(",");
732 for (let action of actions) 737 for (let action of actions)
733 { 738 {
734 execAction(action, element, e); 739 execAction(action, element);
735 } 740 }
736 } 741 }
737 742
738 function selectTabItem(tabId, container, focus) 743 function selectTabItem(tabId, container, focus)
739 { 744 {
740 // Show tab content 745 // Show tab content
741 document.body.setAttribute("data-tab", tabId); 746 document.body.setAttribute("data-tab", tabId);
742 747
743 // Select tab 748 // Select tab
744 let tabList = container.querySelector("[role='tablist']"); 749 let tabList = container.querySelector("[role='tablist']");
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
811 816
812 updateShareLink(); 817 updateShareLink();
813 updateTooltips(); 818 updateTooltips();
814 819
815 // Initialize interactive UI elements 820 // Initialize interactive UI elements
816 document.body.addEventListener("click", onClick, false); 821 document.body.addEventListener("click", onClick, false);
817 document.body.addEventListener("keyup", onKeyUp, false); 822 document.body.addEventListener("keyup", onKeyUp, false);
818 let placeholderValue = getMessage("options_dialog_language_find"); 823 let placeholderValue = getMessage("options_dialog_language_find");
819 E("find-language").setAttribute("placeholder", placeholderValue); 824 E("find-language").setAttribute("placeholder", placeholderValue);
820 E("find-language").addEventListener("keyup", onFindLanguageKeyUp, false); 825 E("find-language").addEventListener("keyup", onFindLanguageKeyUp, false);
821 E("whitelisting-textbox").addEventListener("keypress", (e) => 826 let exampleValue = getMessage("options_whitelist_placeholder_example",
822 { 827 ["www.example.com"]);
823 if (getKey(e) == "Enter") 828 E("whitelisting-textbox").setAttribute("placeholder", exampleValue);
824 addWhitelistedDomain(); 829 E("whitelisting-textbox").addEventListener("keyup", (e) =>
830 {
831 E("whitelisting-add-button").disabled = !e.target.value;
825 }, false); 832 }, false);
826 833
827 // Advanced tab 834 // Advanced tab
828 let customize = document.querySelectorAll("#customize li[data-pref]"); 835 let customize = document.querySelectorAll("#customize li[data-pref]");
829 customize = Array.prototype.map.call(customize, (checkbox) => 836 customize = Array.prototype.map.call(customize, (checkbox) =>
830 { 837 {
831 return checkbox.getAttribute("data-pref"); 838 return checkbox.getAttribute("data-pref");
832 }); 839 });
833 for (let key of customize) 840 for (let key of customize)
834 { 841 {
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after
983 ext.backgroundPage.sendMessage({ 990 ext.backgroundPage.sendMessage({
984 type: "filters.get", 991 type: "filters.get",
985 subscriptionUrl: subscription.url 992 subscriptionUrl: subscription.url
986 }, 993 },
987 (filters) => 994 (filters) =>
988 { 995 {
989 for (let filter of filters) 996 for (let filter of filters)
990 updateFilter(filter); 997 updateFilter(filter);
991 998
992 isCustomFiltersLoaded = true; 999 isCustomFiltersLoaded = true;
993 updateCustomFiltersUi();
994 setCustomFiltersView("read"); 1000 setCustomFiltersView("read");
995 }); 1001 });
996 } 1002 }
997 }); 1003 });
998 loadRecommendations(); 1004 loadRecommendations();
999 ext.backgroundPage.sendMessage({ 1005 ext.backgroundPage.sendMessage({
1000 type: "prefs.get", 1006 type: "prefs.get",
1001 key: "subscriptions_exceptionsurl" 1007 key: "subscriptions_exceptionsurl"
1002 }, 1008 },
1003 (url) => 1009 (url) =>
(...skipping 13 matching lines...) Expand all
1017 { 1023 {
1018 for (let subscription of subscriptions) 1024 for (let subscription of subscriptions)
1019 onSubscriptionMessage("added", subscription); 1025 onSubscriptionMessage("added", subscription);
1020 }); 1026 });
1021 }); 1027 });
1022 } 1028 }
1023 1029
1024 function addWhitelistedDomain() 1030 function addWhitelistedDomain()
1025 { 1031 {
1026 let domain = E("whitelisting-textbox"); 1032 let domain = E("whitelisting-textbox");
1033 for (let whitelistItem of collections.whitelist.items)
1034 {
1035 if (whitelistItem.title == domain.value)
1036 {
1037 whitelistItem[timestampUI] = Date.now();
1038 collections.whitelist.updateItem(whitelistItem);
1039 domain.value = "";
1040 break;
1041 }
1042 }
1027 if (domain.value) 1043 if (domain.value)
1028 { 1044 {
1029 sendMessageHandleErrors({ 1045 sendMessageHandleErrors({
1030 type: "filters.add", 1046 type: "filters.add",
1031 text: "@@||" + domain.value.toLowerCase() + "^$document" 1047 text: "@@||" + domain.value.toLowerCase() + "^$document"
1032 }); 1048 });
1033 } 1049 }
1034 1050
1035 domain.value = ""; 1051 domain.value = "";
1036 document.querySelector("#whitelisting .controls") 1052 E("whitelisting-add-button").disabled = true;
1037 .classList.remove("mode-edit");
1038 } 1053 }
1039 1054
1040 function addEnableSubscription(url, title, homepage) 1055 function addEnableSubscription(url, title, homepage)
1041 { 1056 {
1042 let messageType = null; 1057 let messageType = null;
1043 let knownSubscription = subscriptionsMap[url]; 1058 let knownSubscription = subscriptionsMap[url];
1044 if (knownSubscription && knownSubscription.disabled == true) 1059 if (knownSubscription && knownSubscription.disabled == true)
1045 messageType = "subscriptions.toggle"; 1060 messageType = "subscriptions.toggle";
1046 else 1061 else
1047 messageType = "subscriptions.add"; 1062 messageType = "subscriptions.add";
1048 1063
1049 let message = { 1064 let message = {
1050 type: messageType, 1065 type: messageType,
1051 url 1066 url
1052 }; 1067 };
1053 if (title) 1068 if (title)
1054 message.title = title; 1069 message.title = title;
1055 if (homepage) 1070 if (homepage)
1056 message.homepage = homepage; 1071 message.homepage = homepage;
1057 1072
1058 ext.backgroundPage.sendMessage(message); 1073 ext.backgroundPage.sendMessage(message);
1059 } 1074 }
1060 1075
1061 function onFilterMessage(action, filter) 1076 function onFilterMessage(action, filter)
1062 { 1077 {
1063 switch (action) 1078 switch (action)
1064 { 1079 {
1065 case "added": 1080 case "added":
1081 filter[timestampUI] = Date.now();
1066 updateFilter(filter); 1082 updateFilter(filter);
1067 updateShareLink(); 1083 updateShareLink();
1068 break; 1084 break;
1069 case "loaded": 1085 case "loaded":
1070 populateLists(); 1086 populateLists();
1071 break; 1087 break;
1072 case "removed": 1088 case "removed":
1073 let knownFilter = filtersMap[filter.text]; 1089 let knownFilter = filtersMap[filter.text];
1074 if (whitelistedDomainRegexp.test(knownFilter.text)) 1090 if (whitelistedDomainRegexp.test(knownFilter.text))
1075 collections.whitelist.removeItem(knownFilter); 1091 collections.whitelist.removeItem(knownFilter);
(...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after
1339 }); 1355 });
1340 ext.backgroundPage.sendMessage({ 1356 ext.backgroundPage.sendMessage({
1341 type: "subscriptions.listen", 1357 type: "subscriptions.listen",
1342 filter: ["added", "disabled", "homepage", "lastDownload", "removed", 1358 filter: ["added", "disabled", "homepage", "lastDownload", "removed",
1343 "title", "downloadStatus", "downloading"] 1359 "title", "downloadStatus", "downloading"]
1344 }); 1360 });
1345 1361
1346 window.addEventListener("DOMContentLoaded", onDOMLoaded, false); 1362 window.addEventListener("DOMContentLoaded", onDOMLoaded, false);
1347 window.addEventListener("hashchange", onHashChange, false); 1363 window.addEventListener("hashchange", onHashChange, false);
1348 } 1364 }
LEFTRIGHT

Powered by Google App Engine
This is Rietveld