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

Delta Between Two Patch Sets: new-options.js

Issue 29478597: Issue 5326 - General tab (HTML, strings and functionality) (Closed)
Left Patch Set: Created July 26, 2017, 8:38 p.m.
Right Patch Set: rebase Created Aug. 23, 2017, 12:36 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-present 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 setLinks, E */ 19 setLinks, 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 acceptableAdsPrivacyUrl = null; 28 let acceptableAdsPrivacyUrl = null;
29 let subscriptionToChange = null;
30 let isCustomFiltersLoaded = false; 29 let isCustomFiltersLoaded = false;
31 let {getMessage} = ext.i18n; 30 let {getMessage} = ext.i18n;
32 let customFilters = []; 31 let customFilters = [];
33 let filterErrors = new Map([ 32 let filterErrors = new Map([
34 ["synchronize_invalid_url", 33 ["synchronize_invalid_url",
35 "options_filterList_lastDownload_invalidURL"], 34 "options_filterList_lastDownload_invalidURL"],
36 ["synchronize_connection_error", 35 ["synchronize_connection_error",
37 "options_filterList_lastDownload_connectionError"], 36 "options_filterList_lastDownload_connectionError"],
38 ["synchronize_invalid_data", 37 ["synchronize_invalid_data",
39 "options_filterList_lastDownload_invalidData"], 38 "options_filterList_lastDownload_invalidData"],
40 ["synchronize_checksum_mismatch", 39 ["synchronize_checksum_mismatch",
41 "options_filterList_lastDownload_checksumMismatch"] 40 "options_filterList_lastDownload_checksumMismatch"]
42 ]); 41 ]);
43 const timestampUI = Symbol(); 42 const timestampUI = Symbol();
44 const whitelistedDomainRegexp = /^@@\|\|([^/:]+)\^\$document$/; 43 const whitelistedDomainRegexp = /^@@\|\|([^/:]+)\^\$document$/;
45 // Period of time in milliseconds 44 // Period of time in milliseconds
46 const minuteInMs = 60000; 45 const minuteInMs = 60000;
47 const hourInMs = 3600000; 46 const hourInMs = 3600000;
48 const fullDayInMs = 86400000; 47 const fullDayInMs = 86400000;
49 const privacySubscriptions = ["privacy", "social"];
50 const moreSubscriptions = ["malware", "anti-adblock"];
51 48
52 function Collection(details) 49 function Collection(details)
53 { 50 {
54 this.details = details; 51 this.details = details;
55 this.items = []; 52 this.items = [];
56 } 53 }
57 54
58 Collection.prototype._setEmpty = function(table, texts) 55 Collection.prototype._setEmpty = function(table, texts)
59 { 56 {
60 let placeholders = table.querySelectorAll(".empty-placeholder"); 57 let placeholders = table.querySelectorAll(".empty-placeholder");
(...skipping 19 matching lines...) Expand all
80 { 77 {
81 let access = (item.url || item.text).replace(/'/g, "\\'"); 78 let access = (item.url || item.text).replace(/'/g, "\\'");
82 return function(container) 79 return function(container)
83 { 80 {
84 return container.querySelector("[data-access='" + access + "']"); 81 return container.querySelector("[data-access='" + access + "']");
85 }; 82 };
86 }; 83 };
87 84
88 Collection.prototype._getItemTitle = function(item, i) 85 Collection.prototype._getItemTitle = function(item, i)
89 { 86 {
90 if (item.url === acceptableAdsUrl)
Thomas Greiner 2017/08/09 18:14:49 Do we even need this special handling of Acceptabl
saroyanm 2017/08/14 14:00:10 I think that we want the title to be translated, a
Thomas Greiner 2017/08/15 17:10:29 What's so bad about showing the original (i.e. unt
saroyanm 2017/08/16 14:17:38 Nevermind I totally agree, I thought that this als
91 return getMessage("options_aa_tracking_label");
Thomas Greiner 2017/08/09 18:14:49 Detail: Let's be consistent with the naming scheme
saroyanm 2017/08/14 14:00:09 Agree, I'll change.
saroyanm 2017/08/16 14:17:38 Done.
92 if (item.url === acceptableAdsPrivacyUrl)
93 return getMessage("options_aa_no_tracking_label");
94 if (this.details[i].useOriginalTitle && item.originalTitle) 87 if (this.details[i].useOriginalTitle && item.originalTitle)
95 return item.originalTitle; 88 return item.originalTitle;
96 return item.title || item.url || item.text; 89 return item.title || item.url || item.text;
97 }; 90 };
98 91
99 Collection.prototype._sortItems = function() 92 Collection.prototype._sortItems = function()
100 { 93 {
101 this.items.sort((a, b) => 94 this.items.sort((a, b) =>
102 { 95 {
103 // Make sure that Acceptable Ads is always last, since it cannot be 96 // Make sure that Acceptable Ads is always last, since it cannot be
104 // disabled, but only be removed. That way it's grouped together with 97 // disabled, but only be removed. That way it's grouped together with
105 // the "Own filter list" which cannot be disabled either at the bottom 98 // the "Own filter list" which cannot be disabled either at the bottom
106 // of the filter lists in the Advanced tab. 99 // of the filter lists in the Advanced tab.
107 if (a.url == acceptableAdsUrl || a.url == acceptableAdsPrivacyUrl) 100 if (isAcceptableAds(a.url))
108 return 1; 101 return 1;
109 if (b.url == acceptableAdsUrl || b.url == acceptableAdsPrivacyUrl) 102 if (isAcceptableAds(b.url))
110 return -1; 103 return -1;
111 104
112 // Make sure that newly added entries always appear on top in descending 105 // Make sure that newly added entries always appear on top in descending
113 // chronological order 106 // chronological order
114 let aTimestamp = a[timestampUI] || 0; 107 let aTimestamp = a[timestampUI] || 0;
115 let bTimestamp = b[timestampUI] || 0; 108 let bTimestamp = b[timestampUI] || 0;
116 if (aTimestamp || bTimestamp) 109 if (aTimestamp || bTimestamp)
117 return bTimestamp - aTimestamp; 110 return bTimestamp - aTimestamp;
118 111
119 let aTitle = this._getItemTitle(a, 0).toLowerCase(); 112 let aTitle = this._getItemTitle(a, 0).toLowerCase();
(...skipping 14 matching lines...) Expand all
134 let detail = this.details[j]; 127 let detail = this.details[j];
135 let table = E(detail.id); 128 let table = E(detail.id);
136 let template = table.querySelector("template"); 129 let template = table.querySelector("template");
137 let listItem = document.createElement("li"); 130 let listItem = document.createElement("li");
138 listItem.appendChild(document.importNode(template.content, true)); 131 listItem.appendChild(document.importNode(template.content, true));
139 listItem.setAttribute("aria-label", this._getItemTitle(item, j)); 132 listItem.setAttribute("aria-label", this._getItemTitle(item, j));
140 listItem.setAttribute("data-access", item.url || item.text); 133 listItem.setAttribute("data-access", item.url || item.text);
141 listItem.setAttribute("role", "section"); 134 listItem.setAttribute("role", "section");
142 135
143 let tooltip = listItem.querySelector("[data-tooltip]"); 136 let tooltip = listItem.querySelector("[data-tooltip]");
144 if (tooltip && tooltip.hasAttribute("data-tooltip")) 137 if (tooltip)
Thomas Greiner 2017/08/09 18:14:48 Detail: The second condition is redundant because
saroyanm 2017/08/14 14:00:10 Well spotted.
saroyanm 2017/08/16 14:17:38 Done.
145 { 138 {
146 if (item.recommended) 139 let tooltipId = tooltip.getAttribute("data-tooltip");
Thomas Greiner 2017/08/09 18:14:48 According to the spec, not all subscriptions that
saroyanm 2017/08/14 14:00:08 I agree, make sense to first check if the string f
saroyanm 2017/08/16 14:17:37 Done.
147 { 140 tooltipId = tooltipId.replace("%value%", item.recommended);
148 let tooltipId = tooltip.getAttribute("data-tooltip"); 141 if (getMessage(tooltipId))
149 tooltipId = tooltipId.replace("%value%", item.recommended); 142 {
150 tooltip.setAttribute("data-tooltip", tooltipId); 143 tooltip.setAttribute("data-tooltip", tooltipId);
151 }
152 else
153 {
154 tooltip.parentNode.removeChild(tooltip);
155 } 144 }
156 } 145 }
157 146
158 for (let control of listItem.querySelectorAll(".control")) 147 for (let control of listItem.querySelectorAll(".control"))
159 { 148 {
160 if (control.hasAttribute("title")) 149 if (control.hasAttribute("title"))
161 { 150 {
162 let titleValue = getMessage(control.getAttribute("title")); 151 let titleValue = getMessage(control.getAttribute("title"));
163 control.setAttribute("title", titleValue); 152 control.setAttribute("title", titleValue);
164 } 153 }
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
220 this._sortItems(); 209 this._sortItems();
221 let access = (item.url || item.text).replace(/'/g, "\\'"); 210 let access = (item.url || item.text).replace(/'/g, "\\'");
222 for (let i = 0; i < this.details.length; i++) 211 for (let i = 0; i < this.details.length; i++)
223 { 212 {
224 let table = E(this.details[i].id); 213 let table = E(this.details[i].id);
225 let element = table.querySelector("[data-access='" + access + "']"); 214 let element = table.querySelector("[data-access='" + access + "']");
226 if (!element) 215 if (!element)
227 continue; 216 continue;
228 217
229 let title = this._getItemTitle(item, i); 218 let title = this._getItemTitle(item, i);
230 element.querySelector(".display").textContent = title; 219 let displays = element.querySelectorAll(".display");
220 for (let j = 0; j < displays.length; j++)
221 displays[j].textContent = title;
222
231 element.setAttribute("aria-label", title); 223 element.setAttribute("aria-label", title);
232 if (this.details[i].searchable) 224 if (this.details[i].searchable)
233 element.setAttribute("data-search", title.toLowerCase()); 225 element.setAttribute("data-search", title.toLowerCase());
234 let control = element.querySelector(".control[role='checkbox']"); 226 let control = element.querySelector(".control[role='checkbox']");
235 if (control) 227 if (control)
236 { 228 {
237 control.setAttribute("aria-checked", item.disabled == false); 229 control.setAttribute("aria-checked", item.disabled == false);
238 if ((item.url == acceptableAdsUrl || 230 if (isAcceptableAds(item.url) && this == collections.filterLists)
239 item.url == acceptableAdsPrivacyUrl) &&
Thomas Greiner 2017/08/09 18:14:50 Detail: This is already the third time that you're
saroyanm 2017/08/14 14:00:10 agree.
saroyanm 2017/08/16 14:17:36 Done.
240 this == collections.filterLists)
241 control.disabled = true; 231 control.disabled = true;
242 } 232 }
243 233
244 let lastUpdateElement = element.querySelector(".last-update"); 234 let lastUpdateElement = element.querySelector(".last-update");
245 if (lastUpdateElement) 235 if (lastUpdateElement)
246 { 236 {
247 let message = element.querySelector(".message"); 237 let message = element.querySelector(".message");
248 if (item.isDownloading) 238 if (item.isDownloading)
249 { 239 {
250 let text = getMessage("options_filterList_lastDownload_inProgress"); 240 let text = getMessage("options_filterList_lastDownload_inProgress");
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
338 index += (index == focusables.length - 1) ? -1 : 1; 328 index += (index == focusables.length - 1) ? -1 : 1;
339 329
340 let nextElement = focusables[index]; 330 let nextElement = focusables[index];
341 if (!nextElement) 331 if (!nextElement)
342 return false; 332 return false;
343 333
344 nextElement.focus(); 334 nextElement.focus();
345 return true; 335 return true;
346 } 336 }
347 337
348 collections.security = new Collection([ 338 collections.protection = new Collection([
349 { 339 {
350 id: "recommend-security-list-table" 340 id: "recommend-protection-list-table"
351 } 341 }
352 ]); 342 ]);
353 collections.langs = new Collection([ 343 collections.langs = new Collection([
354 { 344 {
355 id: "blocking-languages-table", 345 id: "blocking-languages-table",
356 emptyText: ["options_language_empty"], 346 emptyText: ["options_language_empty"]
357 switchSingleEntryControl: true
Thomas Greiner 2017/08/09 18:14:48 Detail: This property appears to be unused.
saroyanm 2017/08/14 14:00:09 right, will remove.
saroyanm 2017/08/16 14:17:38 Done.
358 } 347 }
359 ]); 348 ]);
360 collections.allLangs = new Collection([ 349 collections.allLangs = new Collection([
361 { 350 {
362 id: "all-lang-table-add", 351 id: "all-lang-table-add",
363 emptyText: ["options_dialog_language_other_empty"] 352 emptyText: ["options_dialog_language_other_empty"]
364 },
365 {
366 id: "all-lang-table-change",
367 emptyText: ["options_dialog_language_other_empty"]
368 } 353 }
369 ]); 354 ]);
370 collections.custom = new Collection([ 355 collections.custom = new Collection([
371 { 356 {
372 id: "custom-list-table" 357 id: "custom-list-table"
373 } 358 }
374 ]); 359 ]);
375 collections.whitelist = new Collection([ 360 collections.whitelist = new Collection([
376 { 361 {
377 id: "whitelisting-table", 362 id: "whitelisting-table",
378 emptyText: ["options_whitelist_empty_1", "options_whitelist_empty_2"] 363 emptyText: ["options_whitelist_empty_1", "options_whitelist_empty_2"]
379 } 364 }
380 ]); 365 ]);
381 collections.filterLists = new Collection([ 366 collections.filterLists = new Collection([
382 { 367 {
383 id: "all-filter-lists-table", 368 id: "all-filter-lists-table",
384 useOriginalTitle: true 369 useOriginalTitle: true
385 } 370 }
386 ]); 371 ]);
387 372
388 function toggleShowRecommendation(subscription) 373 function addSubscription(subscription)
389 { 374 {
375 let collection = null;
376 if (subscription.recommended)
377 {
378 if (subscription.recommended == "ads")
379 {
380 if (subscription.disabled == false)
381 collection = collections.langs;
382
383 collections.allLangs.addItem(subscription);
384 }
385 else
386 {
387 collection = collections.protection;
388 }
389 }
390 else if (!isAcceptableAds(subscription.url))
391 {
392 collection = collections.custom;
393 }
394
395 if (collection)
396 collection.addItem(subscription);
397
398 subscriptionsMap[subscription.url] = subscription;
399 updateTooltips();
400 }
401
402 function updateSubscription(subscription)
403 {
404 for (let name in collections)
405 collections[name].updateItem(subscription);
406
390 if (subscription.recommended == "ads") 407 if (subscription.recommended == "ads")
391 { 408 {
392 if (subscription.disabled) 409 if (subscription.disabled)
393 collections.langs.removeItem(subscription); 410 collections.langs.removeItem(subscription);
394 else 411 else
395 collections.langs.addItem(subscription); 412 collections.langs.addItem(subscription);
396 } 413 }
397 414 else if (!subscription.recommended && !isAcceptableAds(subscription.url))
398 if (moreSubscriptions.indexOf(subscription.recommended) >= 0 && 415 {
Thomas Greiner 2017/08/09 18:14:50 This is the opposite of what the spec says: "All f
saroyanm 2017/08/14 14:00:08 Hmmm, good point.. I'll update this.
saroyanm 2017/08/16 14:17:36 Done.
399 subscription.disabled == false) 416 if (subscription.disabled == false)
400 { 417 {
401 collections.custom.addItem(subscription); 418 collections.custom.addItem(subscription);
402 updateTooltips(); 419 updateTooltips();
403 }
404 }
405
406 function addSubscription(subscription)
407 {
408 let collection;
409 if (subscription.recommended)
410 {
411 if (privacySubscriptions.indexOf(subscription.recommended) >= 0)
Thomas Greiner 2017/08/09 18:14:49 Detail: This naming doesn't make sense. You're put
Thomas Greiner 2017/08/09 18:14:50 Detail: You're only using this variable here and w
saroyanm 2017/08/14 14:00:09 Good point.
saroyanm 2017/08/16 14:17:36 Done.
saroyanm 2017/08/16 14:17:36 Not anymore
412 collection = collections.security;
413 else if (subscription.recommended == "ads")
414 {
415 if (subscription.disabled == false)
416 collection = collections.langs;
417 else
418 collection = collections.allLangs;
419 }
420 else if (subscription.disabled == false)
421 {
422 collection = collections.custom;
423 } 420 }
424 else 421 else
425 { 422 {
426 subscriptionsMap[subscription.url] = subscription; 423 collections.custom.removeItem(subscription);
427 return; 424 }
428 } 425 }
429 }
430 else if (subscription.url == acceptableAdsUrl ||
431 subscription.url == acceptableAdsPrivacyUrl)
432 {
433 return;
Thomas Greiner 2017/08/09 18:14:50 Doesn't this mean that neither of the Acceptable A
saroyanm 2017/08/14 14:00:09 I think I tried to be consistent with previous imp
Thomas Greiner 2017/08/15 17:10:29 Ok, thanks.
saroyanm 2017/08/16 14:17:37 I did updated the implementation on how subscripti
434 }
435 else
436 collection = collections.custom;
437
438 collection.addItem(subscription);
439 subscriptionsMap[subscription.url] = subscription;
440 toggleShowRecommendation(subscription);
441 updateTooltips();
442 }
443
444 function updateSubscription(subscription)
445 {
446 for (let name in collections)
447 collections[name].updateItem(subscription);
448
449 toggleShowRecommendation(subscription);
450 } 426 }
451 427
452 function updateFilter(filter) 428 function updateFilter(filter)
453 { 429 {
454 let match = filter.text.match(whitelistedDomainRegexp); 430 let match = filter.text.match(whitelistedDomainRegexp);
455 if (match && !filtersMap[filter.text]) 431 if (match && !filtersMap[filter.text])
456 { 432 {
457 filter.title = match[1]; 433 filter.title = match[1];
458 collections.whitelist.addItem(filter); 434 collections.whitelist.addItem(filter);
459 } 435 }
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after
577 addEnableSubscription(findParentData(element, "access", false)); 553 addEnableSubscription(findParentData(element, "access", false));
578 break; 554 break;
579 case "add-predefined-subscription": { 555 case "add-predefined-subscription": {
580 let dialog = E("dialog-content-predefined"); 556 let dialog = E("dialog-content-predefined");
581 let title = dialog.querySelector("h3").textContent; 557 let title = dialog.querySelector("h3").textContent;
582 let url = dialog.querySelector(".url").textContent; 558 let url = dialog.querySelector(".url").textContent;
583 addEnableSubscription(url, title); 559 addEnableSubscription(url, title);
584 closeDialog(); 560 closeDialog();
585 break; 561 break;
586 } 562 }
587 case "block-all":
588 ext.backgroundPage.sendMessage({
589 type: "subscriptions.remove",
590 url: acceptableAdsPrivacyUrl
591 });
592 ext.backgroundPage.sendMessage({
593 type: "subscriptions.remove",
594 url: acceptableAdsUrl
595 });
596 setDntNotification(false);
Thomas Greiner 2017/08/09 18:14:48 Placing this here may cause inconsistent behavior
saroyanm 2017/08/14 14:00:09 Noted
saroyanm 2017/08/16 14:17:37 Done.
597 break;
598 case "cancel-custom-filters": 563 case "cancel-custom-filters":
599 setCustomFiltersView("read"); 564 setCustomFiltersView("read");
600 break; 565 break;
601 case "change-language-subscription": 566 case "change-language-subscription":
602 ext.backgroundPage.sendMessage({ 567 for (let key in subscriptionsMap)
603 type: "subscriptions.remove", 568 {
604 url: subscriptionToChange 569 let subscription = subscriptionsMap[key];
Thomas Greiner 2017/08/09 18:14:50 This variable seems redundant because you should b
saroyanm 2017/08/14 14:00:09 agree.
saroyanm 2017/08/16 14:17:38 Done.
605 }); 570 let subscriptionType = subscription.recommended;
606 ext.backgroundPage.sendMessage({ 571 if (subscriptionType == "ads" && subscription.disabled == false)
607 type: "subscriptions.add", 572 {
608 url: findParentData(element, "access", false) 573 ext.backgroundPage.sendMessage({
609 }); 574 type: "subscriptions.remove",
575 url: subscription.url
576 });
577 ext.backgroundPage.sendMessage({
578 type: "subscriptions.add",
579 url: findParentData(element, "access", false)
580 });
581 break;
582 }
583 }
610 break; 584 break;
Thomas Greiner 2017/08/09 18:14:49 What if one of those two actions fails? In theory
saroyanm 2017/08/14 14:00:10 We still have a button for adding subscription, I
Thomas Greiner 2017/08/15 17:10:29 That's fine with me as long as we make sure that t
611 case "close-dialog": 585 case "close-dialog":
612 closeDialog(); 586 closeDialog();
613 break; 587 break;
614 case "edit-custom-filters": 588 case "edit-custom-filters":
615 setCustomFiltersView("write"); 589 setCustomFiltersView("write");
616 break;
617 case "enable-aa":
saroyanm 2017/07/26 20:56:50 Adding acceptableAds multiple times, causes the "A
Thomas Greiner 2017/08/09 18:14:48 Acknowledged.
618 ext.backgroundPage.sendMessage({
619 type: "subscriptions.remove",
620 url: acceptableAdsPrivacyUrl
621 });
622 ext.backgroundPage.sendMessage({
623 type: "subscriptions.add",
624 url: acceptableAdsUrl
625 });
626 setDntNotification(false);
627 break;
628 case "enable-privacy-aa":
saroyanm 2017/07/26 20:56:50 The "Acceptable Ads notification" I think will be
Thomas Greiner 2017/08/09 18:14:49 Acknowledged.
629 ext.backgroundPage.sendMessage({
630 type: "subscriptions.remove",
631 url: acceptableAdsUrl
632 });
633 ext.backgroundPage.sendMessage({
634 type: "subscriptions.add",
635 url: acceptableAdsPrivacyUrl
636 });
637 break; 590 break;
638 case "import-subscription": { 591 case "import-subscription": {
639 let url = E("blockingList-textbox").value; 592 let url = E("blockingList-textbox").value;
640 addEnableSubscription(url); 593 addEnableSubscription(url);
641 closeDialog(); 594 closeDialog();
642 break; 595 break;
643 } 596 }
644 case "open-context-menu": { 597 case "open-context-menu": {
645 let listItem = findParentData(element, "access", true); 598 let listItem = findParentData(element, "access", true);
646 if (listItem && !listItem.classList.contains("show-context-menu")) 599 if (listItem && !listItem.classList.contains("show-context-menu"))
(...skipping 14 matching lines...) Expand all
661 ext.backgroundPage.sendMessage({ 614 ext.backgroundPage.sendMessage({
662 type: "filters.remove", 615 type: "filters.remove",
663 text: findParentData(element, "access", false) 616 text: findParentData(element, "access", false)
664 }); 617 });
665 break; 618 break;
666 case "remove-subscription": 619 case "remove-subscription":
667 ext.backgroundPage.sendMessage({ 620 ext.backgroundPage.sendMessage({
668 type: "subscriptions.remove", 621 type: "subscriptions.remove",
669 url: findParentData(element, "access", false) 622 url: findParentData(element, "access", false)
670 }); 623 });
671 break;
672 case "save-change-subscription":
673 subscriptionToChange = findParentData(element, "access", false);
674 break; 624 break;
675 case "save-custom-filters": 625 case "save-custom-filters":
676 sendMessageHandleErrors({ 626 sendMessageHandleErrors({
677 type: "filters.importRaw", 627 type: "filters.importRaw",
678 text: E("custom-filters-raw").value, 628 text: E("custom-filters-raw").value,
679 removeExisting: true 629 removeExisting: true
680 }, 630 },
681 () => 631 () =>
682 { 632 {
683 setCustomFiltersView("read"); 633 setCustomFiltersView("read");
634 });
635 break;
636 case "switch-acceptable-ads":
637 let {value} = element;
638 ext.backgroundPage.sendMessage({
639 type: value == "privacy" ? "subscriptions.add" :
640 "subscriptions.remove",
641 url: acceptableAdsPrivacyUrl
642 });
643 ext.backgroundPage.sendMessage({
644 type: value == "ads" ? "subscriptions.add" : "subscriptions.remove",
645 url: acceptableAdsUrl
684 }); 646 });
685 break; 647 break;
686 case "switch-tab": 648 case "switch-tab":
687 let tabId = findParentData(element, "tab", false); 649 let tabId = findParentData(element, "tab", false);
688 switchTab(tabId); 650 switchTab(tabId);
689 break; 651 break;
690 case "toggle-disable-subscription": 652 case "toggle-disable-subscription":
691 ext.backgroundPage.sendMessage({ 653 ext.backgroundPage.sendMessage({
692 type: "subscriptions.toggle", 654 type: "subscriptions.toggle",
693 keepInstalled: true, 655 keepInstalled: true,
(...skipping 330 matching lines...) Expand 10 before | Expand all | Expand 10 after
1024 986
1025 function closeDialog() 987 function closeDialog()
1026 { 988 {
1027 let dialog = E("dialog"); 989 let dialog = E("dialog");
1028 dialog.setAttribute("aria-hidden", true); 990 dialog.setAttribute("aria-hidden", true);
1029 dialog.removeAttribute("aria-labelledby"); 991 dialog.removeAttribute("aria-labelledby");
1030 document.body.removeAttribute("data-dialog"); 992 document.body.removeAttribute("data-dialog");
1031 focusedBeforeDialog.focus(); 993 focusedBeforeDialog.focus();
1032 } 994 }
1033 995
1034 function setDntNotification(state) 996 function setAcceptableAds()
1035 { 997 {
1036 if (state) 998 let option = "none";
1037 E("acceptable-ads").classList.add("show-dnt-notification"); 999 document.forms["acceptable-ads"].classList.remove("show-dnt-notification");
1038 else 1000 if (acceptableAdsUrl in subscriptionsMap)
1039 E("acceptable-ads").classList.remove("show-dnt-notification"); 1001 {
1002 option = "ads";
1003 }
1004 else if (acceptableAdsPrivacyUrl in subscriptionsMap)
1005 {
1006 option = "privacy";
1007
1008 if (!navigator.doNotTrack)
1009 document.forms["acceptable-ads"].classList.add("show-dnt-notification");
1010 }
1011 document.forms["acceptable-ads"]["acceptable-ads"].value = option;
1012 }
1013
1014 function isAcceptableAds(url)
1015 {
1016 return url == acceptableAdsUrl || url == acceptableAdsPrivacyUrl;
1040 } 1017 }
1041 1018
1042 function populateLists() 1019 function populateLists()
1043 { 1020 {
1044 subscriptionsMap = Object.create(null); 1021 subscriptionsMap = Object.create(null);
1045 filtersMap = Object.create(null); 1022 filtersMap = Object.create(null);
1046 1023
1047 // Empty collections and lists 1024 // Empty collections and lists
1048 for (let property in collections) 1025 for (let property in collections)
1049 collections[property].clearAll(); 1026 collections[property].clearAll();
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
1084 disabled: true 1061 disabled: true
1085 }); 1062 });
1086 1063
1087 ext.backgroundPage.sendMessage({ 1064 ext.backgroundPage.sendMessage({
1088 type: "prefs.get", 1065 type: "prefs.get",
1089 key: "subscriptions_exceptionsurl_privacy" 1066 key: "subscriptions_exceptionsurl_privacy"
1090 }, 1067 },
1091 (urlPrivacy) => 1068 (urlPrivacy) =>
1092 { 1069 {
1093 acceptableAdsPrivacyUrl = urlPrivacy; 1070 acceptableAdsPrivacyUrl = urlPrivacy;
1094 addSubscription({
Thomas Greiner 2017/08/09 18:14:50 This looks odd. The subscription is not installed
saroyanm 2017/08/14 14:00:10 Agree it's odd :) Will fix.
saroyanm 2017/08/16 14:17:37 Done.
1095 url: acceptableAdsPrivacyUrl,
1096 disabled: true
1097 });
1098 1071
1099 // Load user subscriptions 1072 // Load user subscriptions
Thomas Greiner 2017/08/09 18:14:49 This code doesn't depend on the value of `urlPriva
saroyanm 2017/08/14 14:00:09 There are checks involved dependant on acceptableA
Thomas Greiner 2017/08/15 17:10:29 Which checks in particular are you referring to?
saroyanm 2017/08/16 14:17:37 To checks in "onSubscriptionMessage", we do same f
Thomas Greiner 2017/08/16 17:57:08 Ok, makes sense.
1100 ext.backgroundPage.sendMessage({ 1073 ext.backgroundPage.sendMessage({
1101 type: "subscriptions.get", 1074 type: "subscriptions.get",
1102 downloadable: true 1075 downloadable: true
1103 }, 1076 },
1104 (subscriptions) => 1077 (subscriptions) =>
1105 { 1078 {
1106 for (let subscription of subscriptions) 1079 for (let subscription of subscriptions)
1107 onSubscriptionMessage("added", subscription); 1080 onSubscriptionMessage("added", subscription);
1108 }); 1081 });
1109 }); 1082 });
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after
1206 case "lastDownload": 1179 case "lastDownload":
1207 case "title": 1180 case "title":
1208 updateSubscription(subscription); 1181 updateSubscription(subscription);
1209 break; 1182 break;
1210 case "added": 1183 case "added":
1211 if (subscription.url in subscriptionsMap) 1184 if (subscription.url in subscriptionsMap)
1212 updateSubscription(subscription); 1185 updateSubscription(subscription);
1213 else 1186 else
1214 addSubscription(subscription); 1187 addSubscription(subscription);
1215 1188
1216 if (subscription.url == acceptableAdsUrl) 1189 if (isAcceptableAds(subscription.url))
1217 document.querySelector( 1190 setAcceptableAds();
1218 "[name='acceptable-ads'][value='tracking']").checked = true;
Thomas Greiner 2017/08/09 18:14:49 I noticed that you're only changing the value of `
Thomas Greiner 2017/08/09 18:14:49 Coding Style: "When an if statement, an else state
saroyanm 2017/08/14 14:00:10 Agree.
saroyanm 2017/08/16 14:17:37 Done.
1219 if (subscription.url == acceptableAdsPrivacyUrl)
Thomas Greiner 2017/08/09 18:14:48 Detail: This condition will never be `true` if the
saroyanm 2017/08/14 14:00:10 agree.
Thomas Greiner 2017/08/16 17:57:08 Maybe I'm missing something but I can't find the c
1220 {
1221 document.querySelector(
1222 "[name='acceptable-ads'][value='no-tracking']").checked = true;
1223 if (!navigator.doNotTrack)
saroyanm 2017/07/26 20:56:50 I couldn't find way to listen for "do not track" c
Thomas Greiner 2017/08/09 18:14:49 Users need to move away from the options page to c
saroyanm 2017/08/14 14:00:10 This is a good idea, but I think would be better t
Thomas Greiner 2017/08/15 17:10:30 Ok, sounds good.
1224 setDntNotification(true);
1225 }
1226 1191
1227 collections.filterLists.addItem(subscription); 1192 collections.filterLists.addItem(subscription);
1228 break; 1193 break;
1229 case "removed": 1194 case "removed":
1230 if (subscription.url == acceptableAdsUrl || 1195 if (subscription.recommended)
1231 subscription.url == acceptableAdsPrivacyUrl ||
1232 subscription.recommended &&
1233 moreSubscriptions.indexOf(subscription.recommended) == -1)
1234 { 1196 {
1235 subscription.disabled = true; 1197 subscription.disabled = true;
1236 onSubscriptionMessage("disabled", subscription); 1198 onSubscriptionMessage("disabled", subscription);
1237 } 1199 }
1238 else 1200 else
1239 { 1201 {
1240 collections.custom.removeItem(subscription);
1241 delete subscriptionsMap[subscription.url]; 1202 delete subscriptionsMap[subscription.url];
1203 if (isAcceptableAds(subscription.url))
1204 {
1205 setAcceptableAds();
1206 }
1207 else
1208 {
1209 collections.custom.removeItem(subscription);
1210 }
1242 } 1211 }
1243 collections.filterLists.removeItem(subscription); 1212 collections.filterLists.removeItem(subscription);
1244 break; 1213 break;
1245 } 1214 }
1246 1215
1247 updateShareLink(); 1216 updateShareLink();
1248 } 1217 }
1249 1218
1250 function hidePref(key, value) 1219 function hidePref(key, value)
1251 { 1220 {
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
1322 { 1291 {
1323 // Hide the share tab if a script on the share page would be blocked 1292 // Hide the share tab if a script on the share page would be blocked
1324 E("tab-share").hidden = isAnyBlocked; 1293 E("tab-share").hidden = isAnyBlocked;
1325 } 1294 }
1326 } 1295 }
1327 1296
1328 for (let sharedResource of shareResources) 1297 for (let sharedResource of shareResources)
1329 checkShareResource(sharedResource, onResult); 1298 checkShareResource(sharedResource, onResult);
1330 } 1299 }
1331 1300
1332 function getMessages(id)
1333 {
1334 let messages = [];
1335 for (let i = 1; true; i++)
1336 {
1337 let message = ext.i18n.getMessage(id + "_" + i);
1338 if (!message)
1339 break;
1340
1341 messages.push(message);
1342 }
1343 return messages;
1344 }
1345
1346 function updateTooltips() 1301 function updateTooltips()
1347 { 1302 {
1348 let anchors = document.querySelectorAll(":not(.tooltip) > [data-tooltip]"); 1303 let anchors = document.querySelectorAll(":not(.tooltip) > [data-tooltip]");
1349 for (let anchor of anchors) 1304 for (let anchor of anchors)
1350 { 1305 {
1351 let id = anchor.getAttribute("data-tooltip"); 1306 let id = anchor.getAttribute("data-tooltip");
1352 1307
1353 let wrapper = document.createElement("div"); 1308 let wrapper = document.createElement("div");
1354 wrapper.className = "tooltip"; 1309 wrapper.className = "tooltip";
1355 anchor.parentNode.replaceChild(wrapper, anchor); 1310 anchor.parentNode.replaceChild(wrapper, anchor);
1356 wrapper.appendChild(anchor); 1311 wrapper.appendChild(anchor);
1357 1312
1358 let topTexts = getMessages(id);
1359 let bottomTexts = getMessages(id + "_notes");
1360
1361 // We have to use native tooltips to avoid issues when attaching a tooltip
1362 // to an element in a scrollable list or otherwise it might get cut off
1363 if (anchor.hasAttribute("data-tooltip-native"))
1364 {
1365 let title = topTexts.concat(bottomTexts).join("\n\n");
1366 anchor.setAttribute("title", title);
1367 continue;
1368 }
1369
1370 let tooltip = document.createElement("div"); 1313 let tooltip = document.createElement("div");
1371 tooltip.setAttribute("role", "tooltip"); 1314 tooltip.setAttribute("role", "tooltip");
1372 1315
1373 let imageSource = anchor.getAttribute("data-tooltip-image"); 1316 let paragraph = document.createElement("p");
1374 if (imageSource) 1317 paragraph.textContent = getMessage(id);
1375 { 1318 tooltip.appendChild(paragraph);
1376 let image = document.createElement("img");
1377 image.src = imageSource;
1378 image.alt = "";
1379 tooltip.appendChild(image);
1380 }
1381
1382 for (let topText of topTexts)
1383 {
1384 let paragraph = document.createElement("p");
1385 paragraph.innerHTML = topText;
1386 tooltip.appendChild(paragraph);
1387 }
1388 if (bottomTexts.length > 0)
1389 {
1390 let notes = document.createElement("div");
1391 notes.className = "notes";
1392 for (let bottomText of bottomTexts)
1393 {
1394 let paragraph = document.createElement("p");
1395 paragraph.innerHTML = bottomText;
1396 notes.appendChild(paragraph);
1397 }
1398 tooltip.appendChild(notes);
1399 }
1400 1319
1401 wrapper.appendChild(tooltip); 1320 wrapper.appendChild(tooltip);
1402 } 1321 }
1403 } 1322 }
1404 1323
1405 ext.onMessage.addListener((message) => 1324 ext.onMessage.addListener((message) =>
1406 { 1325 {
1407 switch (message.type) 1326 switch (message.type)
1408 { 1327 {
1409 case "app.respond": 1328 case "app.respond":
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
1448 }); 1367 });
1449 ext.backgroundPage.sendMessage({ 1368 ext.backgroundPage.sendMessage({
1450 type: "subscriptions.listen", 1369 type: "subscriptions.listen",
1451 filter: ["added", "disabled", "homepage", "lastDownload", "removed", 1370 filter: ["added", "disabled", "homepage", "lastDownload", "removed",
1452 "title", "downloadStatus", "downloading"] 1371 "title", "downloadStatus", "downloading"]
1453 }); 1372 });
1454 1373
1455 window.addEventListener("DOMContentLoaded", onDOMLoaded, false); 1374 window.addEventListener("DOMContentLoaded", onDOMLoaded, false);
1456 window.addEventListener("hashchange", onHashChange, false); 1375 window.addEventListener("hashchange", onHashChange, false);
1457 } 1376 }
LEFTRIGHT

Powered by Google App Engine
This is Rietveld