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

Delta Between Two Patch Sets: new-options.js

Issue 29502647: Issue 5482 - Sidebar and about ABP dialog (Closed)
Left Patch Set: Created Aug. 18, 2017, 12:39 p.m.
Right Patch Set: Fixed nit Created Aug. 28, 2017, 11:38 a.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/abp-logo.svg » ('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)
91 return getMessage("options_aa_tracking_label");
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)
145 { 138 {
146 if (item.recommended) 139 let tooltipId = tooltip.getAttribute("data-tooltip");
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) &&
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
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 {
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)
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;
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);
435 if (isCustomFiltersLoaded)
436 {
437 let text = getMessage("options_whitelist_notification", [filter.title]);
438 showNotification(text);
439 }
459 } 440 }
460 else 441 else
461 { 442 {
462 customFilters.push(filter.text); 443 customFilters.push(filter.text);
463 if (isCustomFiltersLoaded) 444 if (isCustomFiltersLoaded)
464 updateCustomFiltersUi(); 445 updateCustomFiltersUi();
465 } 446 }
466 447
467 filtersMap[filter.text] = filter; 448 filtersMap[filter.text] = filter;
468 } 449 }
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
566 addEnableSubscription(findParentData(element, "access", false)); 547 addEnableSubscription(findParentData(element, "access", false));
567 break; 548 break;
568 case "add-predefined-subscription": { 549 case "add-predefined-subscription": {
569 let dialog = E("dialog-content-predefined"); 550 let dialog = E("dialog-content-predefined");
570 let title = dialog.querySelector("h3").textContent; 551 let title = dialog.querySelector("h3").textContent;
571 let url = dialog.querySelector(".url").textContent; 552 let url = dialog.querySelector(".url").textContent;
572 addEnableSubscription(url, title); 553 addEnableSubscription(url, title);
573 closeDialog(); 554 closeDialog();
574 break; 555 break;
575 } 556 }
576 case "block-all":
577 ext.backgroundPage.sendMessage({
578 type: "subscriptions.remove",
579 url: acceptableAdsPrivacyUrl
580 });
581 ext.backgroundPage.sendMessage({
582 type: "subscriptions.remove",
583 url: acceptableAdsUrl
584 });
585 setDntNotification(false);
586 break;
587 case "cancel-custom-filters": 557 case "cancel-custom-filters":
588 setCustomFiltersView("read"); 558 setCustomFiltersView("read");
589 break; 559 break;
590 case "change-language-subscription": 560 case "change-language-subscription":
591 ext.backgroundPage.sendMessage({ 561 for (let key in subscriptionsMap)
592 type: "subscriptions.remove", 562 {
593 url: subscriptionToChange 563 let subscription = subscriptionsMap[key];
594 }); 564 let subscriptionType = subscription.recommended;
595 ext.backgroundPage.sendMessage({ 565 if (subscriptionType == "ads" && subscription.disabled == false)
596 type: "subscriptions.add", 566 {
597 url: findParentData(element, "access", false) 567 ext.backgroundPage.sendMessage({
598 }); 568 type: "subscriptions.remove",
569 url: subscription.url
570 });
571 ext.backgroundPage.sendMessage({
572 type: "subscriptions.add",
573 url: findParentData(element, "access", false)
574 });
575 break;
576 }
577 }
599 break; 578 break;
600 case "close-dialog": 579 case "close-dialog":
601 closeDialog(); 580 closeDialog();
602 break; 581 break;
603 case "edit-custom-filters": 582 case "edit-custom-filters":
604 setCustomFiltersView("write"); 583 setCustomFiltersView("write");
605 break; 584 break;
606 case "enable-aa": 585 case "hide-notification":
607 ext.backgroundPage.sendMessage({ 586 hideNotification();
608 type: "subscriptions.remove",
609 url: acceptableAdsPrivacyUrl
610 });
611 ext.backgroundPage.sendMessage({
612 type: "subscriptions.add",
613 url: acceptableAdsUrl
614 });
615 setDntNotification(false);
616 break;
617 case "enable-privacy-aa":
618 ext.backgroundPage.sendMessage({
619 type: "subscriptions.remove",
620 url: acceptableAdsUrl
621 });
622 ext.backgroundPage.sendMessage({
623 type: "subscriptions.add",
624 url: acceptableAdsPrivacyUrl
625 });
626 break; 587 break;
627 case "import-subscription": { 588 case "import-subscription": {
628 let url = E("blockingList-textbox").value; 589 let url = E("blockingList-textbox").value;
629 addEnableSubscription(url); 590 addEnableSubscription(url);
630 closeDialog(); 591 closeDialog();
631 break; 592 break;
632 } 593 }
633 case "open-context-menu": { 594 case "open-context-menu": {
634 let listItem = findParentData(element, "access", true); 595 let listItem = findParentData(element, "access", true);
635 if (listItem && !listItem.classList.contains("show-context-menu")) 596 if (listItem && !listItem.classList.contains("show-context-menu"))
636 listItem.classList.add("show-context-menu"); 597 listItem.classList.add("show-context-menu");
637 break; 598 break;
638 } 599 }
639 case "open-dialog": { 600 case "open-dialog": {
640 let dialog = findParentData(element, "dialog", false); 601 let dialog = findParentData(element, "dialog", false);
641 openDialog(dialog); 602 openDialog(dialog);
642 break; 603 break;
643 } 604 }
644 case "remove-filter": 605 case "remove-filter":
645 ext.backgroundPage.sendMessage({ 606 ext.backgroundPage.sendMessage({
646 type: "filters.remove", 607 type: "filters.remove",
647 text: findParentData(element, "access", false) 608 text: findParentData(element, "access", false)
648 }); 609 });
649 break; 610 break;
650 case "remove-subscription": 611 case "remove-subscription":
651 ext.backgroundPage.sendMessage({ 612 ext.backgroundPage.sendMessage({
652 type: "subscriptions.remove", 613 type: "subscriptions.remove",
653 url: findParentData(element, "access", false) 614 url: findParentData(element, "access", false)
654 }); 615 });
655 break;
656 case "save-change-subscription":
657 subscriptionToChange = findParentData(element, "access", false);
658 break; 616 break;
659 case "save-custom-filters": 617 case "save-custom-filters":
660 sendMessageHandleErrors({ 618 sendMessageHandleErrors({
661 type: "filters.importRaw", 619 type: "filters.importRaw",
662 text: E("custom-filters-raw").value, 620 text: E("custom-filters-raw").value,
663 removeExisting: true 621 removeExisting: true
664 }, 622 },
665 () => 623 () =>
666 { 624 {
667 setCustomFiltersView("read"); 625 setCustomFiltersView("read");
668 }); 626 });
669 break; 627 break;
628 case "switch-acceptable-ads":
629 let {value} = element;
630 ext.backgroundPage.sendMessage({
631 type: value == "privacy" ? "subscriptions.add" :
632 "subscriptions.remove",
633 url: acceptableAdsPrivacyUrl
634 });
635 ext.backgroundPage.sendMessage({
636 type: value == "ads" ? "subscriptions.add" : "subscriptions.remove",
637 url: acceptableAdsUrl
638 });
639 break;
670 case "switch-tab": 640 case "switch-tab":
671 let tabId = findParentData(element, "tab", false); 641 switchTab(element.getAttribute("href").substr(1));
672 switchTab(tabId);
673 break; 642 break;
674 case "toggle-disable-subscription": 643 case "toggle-disable-subscription":
675 ext.backgroundPage.sendMessage({ 644 ext.backgroundPage.sendMessage({
676 type: "subscriptions.toggle", 645 type: "subscriptions.toggle",
677 keepInstalled: true, 646 keepInstalled: true,
678 url: findParentData(element, "access", false) 647 url: findParentData(element, "access", false)
679 }); 648 });
680 break; 649 break;
681 case "toggle-pref": 650 case "toggle-pref":
682 ext.backgroundPage.sendMessage({ 651 ext.backgroundPage.sendMessage({
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
775 let container = findParentData(element, "action", true); 744 let container = findParentData(element, "action", true);
776 if (!container || !container.hasAttribute("data-keys")) 745 if (!container || !container.hasAttribute("data-keys"))
777 return; 746 return;
778 747
779 let keys = container.getAttribute("data-keys").split(" "); 748 let keys = container.getAttribute("data-keys").split(" ");
780 if (keys.indexOf(key) < 0) 749 if (keys.indexOf(key) < 0)
781 return; 750 return;
782 751
783 if (element.getAttribute("role") == "tab") 752 if (element.getAttribute("role") == "tab")
784 { 753 {
754 let parent = element.parentElement;
785 if (key == "ArrowLeft" || key == "ArrowUp") 755 if (key == "ArrowLeft" || key == "ArrowUp")
786 element = element.previousElementSibling || container.lastElementChild; 756 parent = parent.previousElementSibling || container.lastElementChild;
787 else if (key == "ArrowRight" || key == "ArrowDown") 757 else if (key == "ArrowRight" || key == "ArrowDown")
788 element = element.nextElementSibling || container.firstElementChild; 758 parent = parent.nextElementSibling || container.firstElementChild;
759 element = parent.firstElementChild;
789 } 760 }
790 761
791 let actions = container.getAttribute("data-action").split(","); 762 let actions = container.getAttribute("data-action").split(",");
792 for (let action of actions) 763 for (let action of actions)
793 { 764 {
794 execAction(action, element); 765 execAction(action, element);
795 } 766 }
796 }
797
798 function updateTabLinks()
juliandoucette 2017/08/21 14:10:34 NIT: Why not add these HREFs directly to new-optio
saroyanm 2017/08/21 15:20:22 To avoid duplications, we do specify the target in
juliandoucette 2017/08/21 16:07:24 NIT: You could *just* set a.href then and: tabLis
saroyanm 2017/08/21 16:46:12 I agree with you, I'll change this.
saroyanm 2017/08/23 13:35:45 I've updated the tabs implementation.
799 {
800 let tabs = document.querySelectorAll("[role='tab']");
juliandoucette 2017/08/21 14:10:34 NIT: Isn't this asking for trouble? e.g. if we add
saroyanm 2017/08/21 15:20:22 Why is this trouble ? No, this logic I think shoul
juliandoucette 2017/08/21 16:07:24 Acknowledged. Assuming that you want this to happ
801 for (let i = 0; i < tabs.length; i++)
802 tabs[i].querySelector("a").href = "#" + tabs[i].dataset.tab;
803 } 767 }
804 768
805 function selectTabItem(tabId, container, focus) 769 function selectTabItem(tabId, container, focus)
806 { 770 {
807 // Show tab content 771 // Show tab content
808 document.body.setAttribute("data-tab", tabId); 772 document.body.setAttribute("data-tab", tabId);
809 773
810 // Select tab 774 // Select tab
811 let tabList = container.querySelector("[role='tablist']"); 775 let tabList = container.querySelector("[role='tablist']");
812 if (!tabList) 776 if (!tabList)
813 return null; 777 return null;
814 778
815 let previousTab = tabList.querySelector("[aria-selected]"); 779 let previousTab = tabList.querySelector("[aria-selected]");
816 previousTab.removeAttribute("aria-selected"); 780 previousTab.removeAttribute("aria-selected");
817 previousTab.setAttribute("tabindex", -1); 781 previousTab.setAttribute("tabindex", -1);
818 782
819 let tab = tabList.querySelector("li[data-tab='" + tabId + "']"); 783 let tab = tabList.querySelector("a[href='#" + tabId + "']");
820 tab.setAttribute("aria-selected", true); 784 tab.setAttribute("aria-selected", true);
821 tab.setAttribute("tabindex", 0); 785 tab.setAttribute("tabindex", 0);
822 786
823 let tabContentId = tab.getAttribute("aria-controls"); 787 let tabContentId = tab.getAttribute("aria-controls");
824 let tabContent = document.getElementById(tabContentId); 788 let tabContent = document.getElementById(tabContentId);
825 789
826 if (tab && focus) 790 if (tab && focus)
827 tab.focus(); 791 tab.focus();
828 792
829 return tabContent; 793 return tabContent;
(...skipping 26 matching lines...) Expand all
856 type: "app.get", 820 type: "app.get",
857 what: "addonVersion" 821 what: "addonVersion"
858 }, 822 },
859 (addonVersion) => 823 (addonVersion) =>
860 { 824 {
861 E("abp-version").textContent = getMessage("options_dialog_about_version", 825 E("abp-version").textContent = getMessage("options_dialog_about_version",
862 [addonVersion]); 826 [addonVersion]);
863 }); 827 });
864 828
865 updateTooltips(); 829 updateTooltips();
866 updateTabLinks();
867 830
868 // Initialize interactive UI elements 831 // Initialize interactive UI elements
869 document.body.addEventListener("click", onClick, false); 832 document.body.addEventListener("click", onClick, false);
870 document.body.addEventListener("keyup", onKeyUp, false); 833 document.body.addEventListener("keyup", onKeyUp, false);
871 let exampleValue = getMessage("options_whitelist_placeholder_example", 834 let exampleValue = getMessage("options_whitelist_placeholder_example",
872 ["www.example.com"]); 835 ["www.example.com"]);
873 E("whitelisting-textbox").setAttribute("placeholder", exampleValue); 836 E("whitelisting-textbox").setAttribute("placeholder", exampleValue);
874 E("whitelisting-textbox").addEventListener("keyup", (e) => 837 E("whitelisting-textbox").addEventListener("keyup", (e) =>
875 { 838 {
876 E("whitelisting-add-button").disabled = !e.target.value; 839 E("whitelisting-add-button").disabled = !e.target.value;
877 }, false); 840 }, false);
878 841
879 842
880 getDocLink("contribute", (link) => 843 getDocLink("contribute", (link) =>
juliandoucette 2017/08/21 14:10:34 NIT: It seems like these should be batched somewhe
saroyanm 2017/08/21 15:20:22 Yes it's a plan for future. We might also have a t
juliandoucette 2017/08/21 16:07:25 Acknowledged. Will you check this?
saroyanm 2017/08/21 16:46:13 https://issues.adblockplus.org/ticket/4856
juliandoucette 2017/08/22 10:10:44 Acknowledged.
881 { 844 {
882 E("contribute").href = link; 845 E("contribute").href = link;
883 }); 846 });
884 getDocLink("acceptable_ads_criteria", (link) => 847 getDocLink("acceptable_ads_criteria", (link) =>
885 { 848 {
886 setLinks("enable-aa-description", link); 849 setLinks("enable-aa-description", link);
887 }); 850 });
888 851
889 // Advanced tab 852 // Advanced tab
890 let customize = document.querySelectorAll("#customize li[data-pref]"); 853 let customize = document.querySelectorAll("#customize li[data-pref]");
(...skipping 24 matching lines...) Expand all
915 878
916 getDocLink("subscriptions", (link) => 879 getDocLink("subscriptions", (link) =>
917 { 880 {
918 setLinks("filter-lists-description", link); 881 setLinks("filter-lists-description", link);
919 }); 882 });
920 883
921 E("custom-filters-raw").setAttribute("placeholder", 884 E("custom-filters-raw").setAttribute("placeholder",
922 getMessage("options_customFilters_edit_placeholder", ["/ads/track/*"])); 885 getMessage("options_customFilters_edit_placeholder", ["/ads/track/*"]));
923 886
924 // Help tab 887 // Help tab
925 getDocLink("faq", (link) => 888 getDocLink("adblock_plus_report_issue", (link) =>
926 { 889 {
927 E("link-faq").setAttribute("href", link); 890 setLinks("report-issue", link);
891 });
892 getDocLink("adblock_plus_report_ad", (link) =>
893 {
894 setLinks("report-ad", link);
895 });
896 getDocLink("adblock_plus_report_bug", (link) =>
897 {
898 setLinks("report-bug", link);
899 });
900 getDocLink("reporter_other_link", (link) =>
901 {
902 setLinks("report-forum", link);
928 }); 903 });
929 getDocLink("social_twitter", (link) => 904 getDocLink("social_twitter", (link) =>
930 { 905 {
931 E("link-twitter").setAttribute("href", link); 906 E("twitter").setAttribute("href", link);
932 }); 907 });
933 getDocLink("social_facebook", (link) => 908 getDocLink("social_facebook", (link) =>
934 { 909 {
935 E("link-facebook").setAttribute("href", link); 910 E("facebook").setAttribute("href", link);
936 }); 911 });
937 getDocLink("social_gplus", (link) => 912 getDocLink("social_gplus", (link) =>
938 { 913 {
939 E("link-gplus").setAttribute("href", link); 914 E("google-plus").setAttribute("href", link);
940 });
941 getDocLink("social_renren", (link) =>
942 {
943 E("link-renren").setAttribute("href", link);
944 }); 915 });
945 getDocLink("social_weibo", (link) => 916 getDocLink("social_weibo", (link) =>
946 { 917 {
947 E("link-weibo").setAttribute("href", link); 918 E("weibo").setAttribute("href", link);
948 });
949
950 // Set forum link
951 ext.backgroundPage.sendMessage({
952 type: "app.get",
953 what: "platform"
954 },
955 (platform) =>
956 {
957 ext.backgroundPage.sendMessage({
958 type: "app.get",
959 what: "application"
960 },
961 (application) =>
962 {
963 if (platform == "chromium" && application != "opera")
964 application = "chrome";
965
966 getDocLink(application + "_support", (link) =>
967 {
968 E("link-forum").setAttribute("href", link);
969 });
970 });
971 }); 919 });
972 920
973 E("dialog").addEventListener("keydown", function(e) 921 E("dialog").addEventListener("keydown", function(e)
974 { 922 {
975 switch (getKey(e)) 923 switch (getKey(e))
976 { 924 {
977 case "Escape": 925 case "Escape":
978 closeDialog(); 926 closeDialog();
979 break; 927 break;
980 case "Tab": 928 case "Tab":
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
1017 965
1018 function closeDialog() 966 function closeDialog()
1019 { 967 {
1020 let dialog = E("dialog"); 968 let dialog = E("dialog");
1021 dialog.setAttribute("aria-hidden", true); 969 dialog.setAttribute("aria-hidden", true);
1022 dialog.removeAttribute("aria-labelledby"); 970 dialog.removeAttribute("aria-labelledby");
1023 document.body.removeAttribute("data-dialog"); 971 document.body.removeAttribute("data-dialog");
1024 focusedBeforeDialog.focus(); 972 focusedBeforeDialog.focus();
1025 } 973 }
1026 974
1027 function setDntNotification(state) 975 function showNotification(text)
1028 { 976 {
1029 if (state) 977 E("notification").setAttribute("aria-hidden", false);
1030 E("acceptable-ads").classList.add("show-dnt-notification"); 978 E("notification-text").textContent = text;
1031 else 979 setTimeout(hideNotification, 3000);
1032 E("acceptable-ads").classList.remove("show-dnt-notification"); 980 }
981
982 function hideNotification()
983 {
984 E("notification").setAttribute("aria-hidden", true);
985 E("notification-text").textContent = "";
986 }
987
988 function setAcceptableAds()
989 {
990 let option = "none";
991 document.forms["acceptable-ads"].classList.remove("show-dnt-notification");
992 if (acceptableAdsUrl in subscriptionsMap)
993 {
994 option = "ads";
995 }
996 else if (acceptableAdsPrivacyUrl in subscriptionsMap)
997 {
998 option = "privacy";
999
1000 if (!navigator.doNotTrack)
1001 document.forms["acceptable-ads"].classList.add("show-dnt-notification");
1002 }
1003 document.forms["acceptable-ads"]["acceptable-ads"].value = option;
1004 }
1005
1006 function isAcceptableAds(url)
1007 {
1008 return url == acceptableAdsUrl || url == acceptableAdsPrivacyUrl;
1033 } 1009 }
1034 1010
1035 function populateLists() 1011 function populateLists()
1036 { 1012 {
1037 subscriptionsMap = Object.create(null); 1013 subscriptionsMap = Object.create(null);
1038 filtersMap = Object.create(null); 1014 filtersMap = Object.create(null);
1039 1015
1040 // Empty collections and lists 1016 // Empty collections and lists
1041 for (let property in collections) 1017 for (let property in collections)
1042 collections[property].clearAll(); 1018 collections[property].clearAll();
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
1077 disabled: true 1053 disabled: true
1078 }); 1054 });
1079 1055
1080 ext.backgroundPage.sendMessage({ 1056 ext.backgroundPage.sendMessage({
1081 type: "prefs.get", 1057 type: "prefs.get",
1082 key: "subscriptions_exceptionsurl_privacy" 1058 key: "subscriptions_exceptionsurl_privacy"
1083 }, 1059 },
1084 (urlPrivacy) => 1060 (urlPrivacy) =>
1085 { 1061 {
1086 acceptableAdsPrivacyUrl = urlPrivacy; 1062 acceptableAdsPrivacyUrl = urlPrivacy;
1087 addSubscription({
1088 url: acceptableAdsPrivacyUrl,
1089 disabled: true
1090 });
1091 1063
1092 // Load user subscriptions 1064 // Load user subscriptions
1093 ext.backgroundPage.sendMessage({ 1065 ext.backgroundPage.sendMessage({
1094 type: "subscriptions.get", 1066 type: "subscriptions.get",
1095 downloadable: true 1067 downloadable: true
1096 }, 1068 },
1097 (subscriptions) => 1069 (subscriptions) =>
1098 { 1070 {
1099 for (let subscription of subscriptions) 1071 for (let subscription of subscriptions)
1100 onSubscriptionMessage("added", subscription); 1072 onSubscriptionMessage("added", subscription);
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after
1197 case "lastDownload": 1169 case "lastDownload":
1198 case "title": 1170 case "title":
1199 updateSubscription(subscription); 1171 updateSubscription(subscription);
1200 break; 1172 break;
1201 case "added": 1173 case "added":
1202 if (subscription.url in subscriptionsMap) 1174 if (subscription.url in subscriptionsMap)
1203 updateSubscription(subscription); 1175 updateSubscription(subscription);
1204 else 1176 else
1205 addSubscription(subscription); 1177 addSubscription(subscription);
1206 1178
1207 if (subscription.url == acceptableAdsUrl) 1179 if (isAcceptableAds(subscription.url))
1208 document.querySelector( 1180 setAcceptableAds();
1209 "[name='acceptable-ads'][value='tracking']").checked = true;
1210 if (subscription.url == acceptableAdsPrivacyUrl)
1211 {
1212 document.querySelector(
1213 "[name='acceptable-ads'][value='no-tracking']").checked = true;
1214 if (!navigator.doNotTrack)
1215 setDntNotification(true);
1216 }
1217 1181
1218 collections.filterLists.addItem(subscription); 1182 collections.filterLists.addItem(subscription);
1219 break; 1183 break;
1220 case "removed": 1184 case "removed":
1221 if (subscription.url == acceptableAdsUrl || 1185 if (subscription.recommended)
1222 subscription.url == acceptableAdsPrivacyUrl ||
1223 subscription.recommended &&
1224 moreSubscriptions.indexOf(subscription.recommended) == -1)
1225 { 1186 {
1226 subscription.disabled = true; 1187 subscription.disabled = true;
1227 onSubscriptionMessage("disabled", subscription); 1188 onSubscriptionMessage("disabled", subscription);
1228 } 1189 }
1229 else 1190 else
1230 { 1191 {
1231 collections.custom.removeItem(subscription);
1232 delete subscriptionsMap[subscription.url]; 1192 delete subscriptionsMap[subscription.url];
1193 if (isAcceptableAds(subscription.url))
1194 {
1195 setAcceptableAds();
1196 }
1197 else
1198 {
1199 collections.custom.removeItem(subscription);
1200 }
1233 } 1201 }
1234 collections.filterLists.removeItem(subscription); 1202 collections.filterLists.removeItem(subscription);
1235 break; 1203 break;
1236 } 1204 }
1237 1205
1238 } 1206 }
1239 1207
1240 function hidePref(key, value) 1208 function hidePref(key, value)
1241 { 1209 {
1242 let element = document.querySelector("[data-pref='" + key + "']"); 1210 let element = document.querySelector("[data-pref='" + key + "']");
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
1288 break; 1256 break;
1289 } 1257 }
1290 1258
1291 let checkbox = document.querySelector( 1259 let checkbox = document.querySelector(
1292 "[data-pref='" + key + "'] button[role='checkbox']" 1260 "[data-pref='" + key + "'] button[role='checkbox']"
1293 ); 1261 );
1294 if (checkbox) 1262 if (checkbox)
1295 checkbox.setAttribute("aria-checked", value); 1263 checkbox.setAttribute("aria-checked", value);
1296 } 1264 }
1297 1265
1298 function getMessages(id)
1299 {
1300 let messages = [];
1301 for (let i = 1; true; i++)
1302 {
1303 let message = ext.i18n.getMessage(id + "_" + i);
1304 if (!message)
1305 break;
1306
1307 messages.push(message);
1308 }
1309 return messages;
1310 }
1311
1312 function updateTooltips() 1266 function updateTooltips()
1313 { 1267 {
1314 let anchors = document.querySelectorAll(":not(.tooltip) > [data-tooltip]"); 1268 let anchors = document.querySelectorAll(":not(.tooltip) > [data-tooltip]");
1315 for (let anchor of anchors) 1269 for (let anchor of anchors)
1316 { 1270 {
1317 let id = anchor.getAttribute("data-tooltip"); 1271 let id = anchor.getAttribute("data-tooltip");
1318 1272
1319 let wrapper = document.createElement("div"); 1273 let wrapper = document.createElement("div");
1320 wrapper.className = "tooltip"; 1274 wrapper.className = "tooltip";
1321 anchor.parentNode.replaceChild(wrapper, anchor); 1275 anchor.parentNode.replaceChild(wrapper, anchor);
1322 wrapper.appendChild(anchor); 1276 wrapper.appendChild(anchor);
1323 1277
1324 let topTexts = getMessages(id);
1325 let bottomTexts = getMessages(id + "_notes");
1326
1327 // We have to use native tooltips to avoid issues when attaching a tooltip
1328 // to an element in a scrollable list or otherwise it might get cut off
1329 if (anchor.hasAttribute("data-tooltip-native"))
1330 {
1331 let title = topTexts.concat(bottomTexts).join("\n\n");
1332 anchor.setAttribute("title", title);
1333 continue;
1334 }
1335
1336 let tooltip = document.createElement("div"); 1278 let tooltip = document.createElement("div");
1337 tooltip.setAttribute("role", "tooltip"); 1279 tooltip.setAttribute("role", "tooltip");
1338 1280
1339 let imageSource = anchor.getAttribute("data-tooltip-image"); 1281 let paragraph = document.createElement("p");
1340 if (imageSource) 1282 paragraph.textContent = getMessage(id);
1341 { 1283 tooltip.appendChild(paragraph);
1342 let image = document.createElement("img");
1343 image.src = imageSource;
1344 image.alt = "";
1345 tooltip.appendChild(image);
1346 }
1347
1348 for (let topText of topTexts)
1349 {
1350 let paragraph = document.createElement("p");
1351 paragraph.innerHTML = topText;
1352 tooltip.appendChild(paragraph);
1353 }
1354 if (bottomTexts.length > 0)
1355 {
1356 let notes = document.createElement("div");
1357 notes.className = "notes";
1358 for (let bottomText of bottomTexts)
1359 {
1360 let paragraph = document.createElement("p");
1361 paragraph.innerHTML = bottomText;
1362 notes.appendChild(paragraph);
1363 }
1364 tooltip.appendChild(notes);
1365 }
1366 1284
1367 wrapper.appendChild(tooltip); 1285 wrapper.appendChild(tooltip);
1368 } 1286 }
1369 } 1287 }
1370 1288
1371 ext.onMessage.addListener((message) => 1289 ext.onMessage.addListener((message) =>
1372 { 1290 {
1373 switch (message.type) 1291 switch (message.type)
1374 { 1292 {
1375 case "app.respond": 1293 case "app.respond":
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
1414 }); 1332 });
1415 ext.backgroundPage.sendMessage({ 1333 ext.backgroundPage.sendMessage({
1416 type: "subscriptions.listen", 1334 type: "subscriptions.listen",
1417 filter: ["added", "disabled", "homepage", "lastDownload", "removed", 1335 filter: ["added", "disabled", "homepage", "lastDownload", "removed",
1418 "title", "downloadStatus", "downloading"] 1336 "title", "downloadStatus", "downloading"]
1419 }); 1337 });
1420 1338
1421 window.addEventListener("DOMContentLoaded", onDOMLoaded, false); 1339 window.addEventListener("DOMContentLoaded", onDOMLoaded, false);
1422 window.addEventListener("hashchange", onHashChange, false); 1340 window.addEventListener("hashchange", onHashChange, false);
1423 } 1341 }
LEFTRIGHT

Powered by Google App Engine
This is Rietveld