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

Delta Between Two Patch Sets: new-options.js

Issue 29411555: Issue 5169 - Add whitelisted tab to the new options page (Closed)
Left Patch Set: Created April 21, 2017, 11:32 a.m.
Right Patch Set: Fixed the TYPO Created July 3, 2017, 4:10 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 {getMessage} = ext.i18n; 29 let {getMessage} = ext.i18n;
29 let filterErrors = new Map([ 30 let filterErrors = new Map([
30 ["synchronize_invalid_url", 31 ["synchronize_invalid_url",
31 "options_filterList_lastDownload_invalidURL"], 32 "options_filterList_lastDownload_invalidURL"],
32 ["synchronize_connection_error", 33 ["synchronize_connection_error",
33 "options_filterList_lastDownload_connectionError"], 34 "options_filterList_lastDownload_connectionError"],
34 ["synchronize_invalid_data", 35 ["synchronize_invalid_data",
35 "options_filterList_lastDownload_invalidData"], 36 "options_filterList_lastDownload_invalidData"],
36 ["synchronize_checksum_mismatch", 37 ["synchronize_checksum_mismatch",
37 "options_filterList_lastDownload_checksumMismatch"] 38 "options_filterList_lastDownload_checksumMismatch"]
38 ]); 39 ]);
40 const timestampUI = Symbol();
39 41
40 function Collection(details) 42 function Collection(details)
41 { 43 {
42 this.details = details; 44 this.details = details;
43 this.items = []; 45 this.items = [];
44 } 46 }
45 47
46 Collection.prototype._setEmpty = function(table, texts) 48 Collection.prototype._setEmpty = function(table, texts)
47 { 49 {
48 let placeholders = table.querySelectorAll(".empty-placeholder"); 50 let placeholders = table.querySelectorAll(".empty-placeholder");
49 51
50 if (texts && placeholders.length == 0) 52 if (texts && placeholders.length == 0)
51 { 53 {
52 for (let i = 0; i < texts.length; i++) 54 for (let text of texts)
Thomas Greiner 2017/05/09 13:42:56 Detail: You're not using the index so I'd recommen
saroyanm 2017/05/16 20:20:07 Well spotted, done.
53 { 55 {
54 let placeholder = document.createElement("li"); 56 let placeholder = document.createElement("li");
55 placeholder.className = "empty-placeholder"; 57 placeholder.className = "empty-placeholder";
56 placeholder.textContent = getMessage(texts[i]); 58 placeholder.textContent = getMessage(text);
57 table.appendChild(placeholder); 59 table.appendChild(placeholder);
58 } 60 }
59 } 61 }
60 else if (placeholders.length > 0) 62 else if (placeholders.length > 0)
61 { 63 {
62 for (let i = 0; i < placeholders.length; i++) 64 for (let placeholder of placeholders)
63 table.removeChild(placeholders[i]); 65 table.removeChild(placeholder);
64 } 66 }
65 }; 67 };
66 68
67 Collection.prototype._createElementQuery = function(item) 69 Collection.prototype._createElementQuery = function(item)
68 { 70 {
69 let access = (item.url || item.text).replace(/'/g, "\\'"); 71 let access = (item.url || item.text).replace(/'/g, "\\'");
70 return function(container) 72 return function(container)
71 { 73 {
72 return container.querySelector("[data-access='" + access + "']"); 74 return container.querySelector("[data-access='" + access + "']");
73 }; 75 };
74 }; 76 };
75 77
76 Collection.prototype._getItemTitle = function(item, i) 78 Collection.prototype._getItemTitle = function(item, i)
77 { 79 {
78 if (item.url == acceptableAdsUrl) 80 if (item.url == acceptableAdsUrl)
79 return getMessage("options_acceptableAds_description"); 81 return getMessage("options_acceptableAds_description");
80 if (this.details[i].useOriginalTitle && item.originalTitle) 82 if (this.details[i].useOriginalTitle && item.originalTitle)
81 return item.originalTitle; 83 return item.originalTitle;
82 return item.title || item.url || item.text; 84 return item.title || item.url || item.text;
83 }; 85 };
84 86
85 Collection.prototype.addItem = function(item) 87 Collection.prototype._sortItems = function()
86 { 88 {
87 if (this.items.indexOf(item) >= 0)
88 return;
89
90 this.items.push(item);
91 this.items.sort((a, b) => 89 this.items.sort((a, b) =>
92 { 90 {
93 // Make sure that Acceptable Ads is always last, since it cannot be 91 // Make sure that Acceptable Ads is always last, since it cannot be
94 // disabled, but only be removed. That way it's grouped together with 92 // disabled, but only be removed. That way it's grouped together with
95 // the "Own filter list" which cannot be disabled either at the bottom 93 // the "Own filter list" which cannot be disabled either at the bottom
96 // of the filter lists in the Advanced tab. 94 // of the filter lists in the Advanced tab.
97 if (a.url == acceptableAdsUrl) 95 if (a.url == acceptableAdsUrl)
98 return 1; 96 return 1;
99 if (b.url == acceptableAdsUrl) 97 if (b.url == acceptableAdsUrl)
100 return -1; 98 return -1;
101 99
100 // Make sure that newly added entries always appear on top in descending
101 // chronological order
102 let aTimestamp = a[timestampUI] || 0;
103 let bTimestamp = b[timestampUI] || 0;
104 if (aTimestamp || bTimestamp)
105 return bTimestamp - aTimestamp;
106
102 let aTitle = this._getItemTitle(a, 0).toLowerCase(); 107 let aTitle = this._getItemTitle(a, 0).toLowerCase();
103 let bTitle = this._getItemTitle(b, 0).toLowerCase(); 108 let bTitle = this._getItemTitle(b, 0).toLowerCase();
104 return aTitle.localeCompare(bTitle); 109 return aTitle.localeCompare(bTitle);
105 }); 110 });
106 111 };
112
113 Collection.prototype.addItem = function(item)
114 {
115 if (this.items.indexOf(item) >= 0)
116 return;
117
118 this.items.push(item);
119 this._sortItems();
107 for (let j = 0; j < this.details.length; j++) 120 for (let j = 0; j < this.details.length; j++)
108 { 121 {
109 let table = E(this.details[j].id); 122 let table = E(this.details[j].id);
110 let template = table.querySelector("template"); 123 let template = table.querySelector("template");
111 let listItem = document.createElement("li"); 124 let listItem = document.createElement("li");
112 listItem.appendChild(document.importNode(template.content, true)); 125 listItem.appendChild(document.importNode(template.content, true));
113 listItem.setAttribute("aria-label", this._getItemTitle(item, j)); 126 listItem.setAttribute("aria-label", this._getItemTitle(item, j));
114 listItem.setAttribute("data-access", item.url || item.text); 127 listItem.setAttribute("data-access", item.url || item.text);
115 listItem.setAttribute("role", "section"); 128 listItem.setAttribute("role", "section");
116 129
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
178 } 191 }
179 192
180 element.parentElement.removeChild(element); 193 element.parentElement.removeChild(element);
181 if (this.items.length == 0) 194 if (this.items.length == 0)
182 this._setEmpty(table, detail.emptyText); 195 this._setEmpty(table, detail.emptyText);
183 } 196 }
184 }; 197 };
185 198
186 Collection.prototype.updateItem = function(item) 199 Collection.prototype.updateItem = function(item)
187 { 200 {
201 let oldIndex = this.items.indexOf(item);
202 this._sortItems();
188 let access = (item.url || item.text).replace(/'/g, "\\'"); 203 let access = (item.url || item.text).replace(/'/g, "\\'");
189 for (let i = 0; i < this.details.length; i++) 204 for (let i = 0; i < this.details.length; i++)
190 { 205 {
191 let table = E(this.details[i].id); 206 let table = E(this.details[i].id);
192 let element = table.querySelector("[data-access='" + access + "']"); 207 let element = table.querySelector("[data-access='" + access + "']");
193 if (!element) 208 if (!element)
194 continue; 209 continue;
195 210
196 let title = this._getItemTitle(item, i); 211 let title = this._getItemTitle(item, i);
197 element.querySelector(".display").textContent = title; 212 element.querySelector(".display").textContent = title;
198 element.setAttribute("aria-label", title); 213 element.setAttribute("aria-label", title);
199 if (this.details[i].searchable) 214 if (this.details[i].searchable)
200 element.setAttribute("data-search", title.toLowerCase()); 215 element.setAttribute("data-search", title.toLowerCase());
201 let control = element.querySelector(".control[role='checkbox']"); 216 let control = element.querySelector(".control[role='checkbox']");
202 if (control) 217 if (control)
203 { 218 {
204 control.setAttribute("aria-checked", item.disabled == false); 219 control.setAttribute("aria-checked", item.disabled == false);
205 if (item.url == acceptableAdsUrl && this == collections.filterLists) 220 if (item.url == acceptableAdsUrl && this == collections.filterLists)
206 control.setAttribute("disabled", true); 221 control.disabled = true;
207 } 222 }
208 223
209 let dateElement = element.querySelector(".date"); 224 let dateElement = element.querySelector(".date");
210 let timeElement = element.querySelector(".time"); 225 let timeElement = element.querySelector(".time");
211 if (dateElement && timeElement) 226 if (dateElement && timeElement)
212 { 227 {
213 let message = element.querySelector(".message"); 228 let message = element.querySelector(".message");
214 if (item.isDownloading) 229 if (item.isDownloading)
215 { 230 {
216 let text = getMessage("options_filterList_lastDownload_inProgress"); 231 let text = getMessage("options_filterList_lastDownload_inProgress");
(...skipping 23 matching lines...) Expand all
240 { 255 {
241 if (item.homepage) 256 if (item.homepage)
242 websiteElement.setAttribute("href", item.homepage); 257 websiteElement.setAttribute("href", item.homepage);
243 else 258 else
244 websiteElement.setAttribute("aria-hidden", true); 259 websiteElement.setAttribute("aria-hidden", true);
245 } 260 }
246 261
247 let sourceElement = element.querySelector(".context-menu .source"); 262 let sourceElement = element.querySelector(".context-menu .source");
248 if (sourceElement) 263 if (sourceElement)
249 sourceElement.setAttribute("href", item.url); 264 sourceElement.setAttribute("href", item.url);
265
266 let newIndex = this.items.indexOf(item);
267 if (oldIndex != newIndex)
268 table.insertBefore(element, table.childNodes[newIndex]);
250 } 269 }
251 }; 270 };
252 271
253 Collection.prototype.clearAll = function() 272 Collection.prototype.clearAll = function()
254 { 273 {
255 this.items = []; 274 this.items = [];
256 for (let detail of this.details) 275 for (let detail of this.details)
257 { 276 {
258 let table = E(detail.id); 277 let table = E(detail.id);
259 let element = table.firstChild; 278 let element = table.firstChild;
(...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after
473 else 492 else
474 location.href = link; 493 location.href = link;
475 }); 494 });
476 } 495 }
477 496
478 function switchTab(id) 497 function switchTab(id)
479 { 498 {
480 location.hash = id; 499 location.hash = id;
481 } 500 }
482 501
502 function execAction(action, element)
503 {
504 switch (action)
505 {
506 case "add-domain-exception":
507 addWhitelistedDomain();
508 break;
509 case "add-language-subscription":
510 addEnableSubscription(findParentData(element, "access", false));
511 break;
512 case "add-predefined-subscription": {
513 let dialog = E("dialog-content-predefined");
514 let title = dialog.querySelector("h3").textContent;
515 let url = dialog.querySelector(".url").textContent;
516 addEnableSubscription(url, title);
517 closeDialog();
518 break;
519 }
520 case "cancel-custom-filters":
521 E("custom-filters").classList.remove("mode-edit");
522 break;
523 case "close-dialog":
524 closeDialog();
525 break;
526 case "edit-custom-filters":
527 editCustomFilters();
528 break;
529 case "import-subscription": {
530 let url = E("blockingList-textbox").value;
531 addEnableSubscription(url);
532 closeDialog();
533 break;
534 }
535 case "open-context-menu": {
536 let listItem = findParentData(element, "access", true);
537 if (listItem && !listItem.classList.contains("show-context-menu"))
538 listItem.classList.add("show-context-menu");
539 break;
540 }
541 case "open-dialog": {
542 let dialog = findParentData(element, "dialog", false);
543 openDialog(dialog);
544 break;
545 }
546 case "open-doclink": {
547 let doclink = findParentData(element, "doclink", false);
548 openDocLink(doclink);
549 break;
550 }
551 case "remove-filter":
552 ext.backgroundPage.sendMessage({
553 type: "filters.remove",
554 text: findParentData(element, "access", false)
555 });
556 break;
557 case "remove-subscription":
558 ext.backgroundPage.sendMessage({
559 type: "subscriptions.remove",
560 url: findParentData(element, "access", false)
561 });
562 break;
563 case "save-custom-filters":
564 sendMessageHandleErrors({
565 type: "filters.importRaw",
566 text: E("custom-filters-raw").value,
567 removeExisting: true
568 },
569 () =>
570 {
571 E("custom-filters").classList.remove("mode-edit");
572 });
573 break;
574 case "switch-tab":
575 let tabId = findParentData(element, "tab", false);
576 switchTab(tabId);
577 break;
578 case "toggle-disable-subscription":
579 ext.backgroundPage.sendMessage({
580 type: "subscriptions.toggle",
581 keepInstalled: true,
582 url: findParentData(element, "access", false)
583 });
584 break;
585 case "toggle-pref":
586 ext.backgroundPage.sendMessage({
587 type: "prefs.toggle",
588 key: findParentData(element, "pref", false)
589 });
590 break;
591 case "toggle-remove-subscription":
592 let subscriptionUrl = findParentData(element, "access", false);
593 if (element.getAttribute("aria-checked") == "true")
594 {
595 ext.backgroundPage.sendMessage({
596 type: "subscriptions.remove",
597 url: subscriptionUrl
598 });
599 }
600 else
601 addEnableSubscription(subscriptionUrl);
602 break;
603 case "update-all-subscriptions":
604 ext.backgroundPage.sendMessage({
605 type: "subscriptions.update"
606 });
607 break;
608 case "update-subscription":
609 ext.backgroundPage.sendMessage({
610 type: "subscriptions.update",
611 url: findParentData(element, "access", false)
612 });
613 break;
614 }
615 }
616
483 function onClick(e) 617 function onClick(e)
484 { 618 {
485 let context = document.querySelector(".show-context-menu"); 619 let context = document.querySelector(".show-context-menu");
486 if (context) 620 if (context)
487 context.classList.remove("show-context-menu"); 621 context.classList.remove("show-context-menu");
488 622
489 let element = findParentData(e.target, "action", true); 623 let actions = findParentData(e.target, "action", false);
490 if (!element) 624 if (!actions)
491 return; 625 return;
492 626
493 let actions = element.getAttribute("data-action").split(","); 627 actions = actions.split(",");
494 for (let action of actions) 628 for (let action of actions)
495 { 629 {
496 switch (action) 630 execAction(action, e.target);
497 {
498 case "add-domain-exception":
499 addWhitelistedDomain();
500 break;
501 case "add-predefined-subscription": {
502 let dialog = E("dialog-content-predefined");
503 let title = dialog.querySelector("h3").textContent;
504 let url = dialog.querySelector(".url").textContent;
505 addEnableSubscription(url, title);
506 closeDialog();
507 break;
508 }
509 case "cancel-custom-filters":
510 E("custom-filters").classList.remove("mode-edit");
511 break;
512 case "cancel-domain-exception":
513 E("whitelisting-textbox").value = "";
514 document.querySelector("#whitelisting .controls").classList
515 .remove("mode-edit");
516 break;
517 case "close-dialog":
518 closeDialog();
519 break;
520 case "edit-custom-filters":
521 E("custom-filters").classList.add("mode-edit");
522 editCustomFilters();
523 break;
524 case "edit-domain-exception":
525 document.querySelector("#whitelisting .controls").classList
526 .add("mode-edit");
527 E("whitelisting-textbox").focus();
528 break;
529 case "import-subscription": {
530 let url = E("blockingList-textbox").value;
531 addEnableSubscription(url);
532 closeDialog();
533 break;
534 }
535 case "open-dialog": {
536 let dialog = findParentData(element, "dialog", false);
537 openDialog(dialog);
538 break;
539 }
540 case "open-doclink": {
541 let doclink = findParentData(element, "doclink", false);
542 openDocLink(doclink);
543 break;
544 }
545 case "save-custom-filters":
546 sendMessageHandleErrors({
547 type: "filters.importRaw",
548 text: E("custom-filters-raw").value,
549 removeExisting: true
550 },
551 () =>
552 {
553 E("custom-filters").classList.remove("mode-edit");
554 });
555 break;
556 case "switch-tab": {
557 let tabId = findParentData(e.target, "tab", false);
558 switchTab(tabId);
559 break;
560 }
561 case "toggle-pref":
562 ext.backgroundPage.sendMessage({
563 type: "prefs.toggle",
564 key: findParentData(element, "pref", false)
565 });
566 break;
567 case "update-all-subscriptions":
568 ext.backgroundPage.sendMessage({
569 type: "subscriptions.update"
570 });
571 break;
572 case "open-context-menu": {
573 let listItem = findParentData(element, "access", true);
574 if (listItem != context)
575 listItem.classList.add("show-context-menu");
576 break;
577 }
578 case "update-subscription":
579 ext.backgroundPage.sendMessage({
580 type: "subscriptions.update",
581 url: findParentData(element, "access", false)
582 });
583 break;
584 case "remove-subscription":
585 ext.backgroundPage.sendMessage({
586 type: "subscriptions.remove",
587 url: findParentData(element, "access", false)
588 });
589 break;
590 case "toggle-remove-subscription": {
591 let subscriptionUrl = findParentData(element, "access", false);
592 if (element.getAttribute("aria-checked") == "true")
593 {
594 ext.backgroundPage.sendMessage({
595 type: "subscriptions.remove",
596 url: subscriptionUrl
597 });
598 }
599 else
600 addEnableSubscription(subscriptionUrl);
601 break;
602 }
603 case "toggle-disable-subscription":
604 ext.backgroundPage.sendMessage({
605 type: "subscriptions.toggle",
606 keepInstalled: true,
607 url: findParentData(element, "access", false)
608 });
609 break;
610 case "add-language-subscription":
611 addEnableSubscription(findParentData(element, "access", false));
612 break;
613 case "remove-filter":
614 ext.backgroundPage.sendMessage({
615 type: "filters.remove",
616 text: findParentData(element, "access", false)
617 });
618 break;
619 }
620 } 631 }
621 } 632 }
622 633
623 function getKey(e) 634 function getKey(e)
624 { 635 {
625 // e.keyCode has been deprecated so we attempt to use e.key 636 // e.keyCode has been deprecated so we attempt to use e.key
626 if ("key" in e) 637 if ("key" in e)
627 return e.key; 638 return e.key;
628 return getKey.keys[e.keyCode]; 639 return getKey.keys[e.keyCode];
629 } 640 }
(...skipping 15 matching lines...) Expand all
645 return; 656 return;
646 657
647 let container = findParentData(element, "action", true); 658 let container = findParentData(element, "action", true);
648 if (!container || !container.hasAttribute("data-keys")) 659 if (!container || !container.hasAttribute("data-keys"))
649 return; 660 return;
650 661
651 let keys = container.getAttribute("data-keys").split(" "); 662 let keys = container.getAttribute("data-keys").split(" ");
652 if (keys.indexOf(key) < 0) 663 if (keys.indexOf(key) < 0)
653 return; 664 return;
654 665
655 switch (container.getAttribute("data-action")) 666 if (element.getAttribute("role") == "tab")
656 { 667 {
657 case "add-domain-exception": 668 if (key == "ArrowLeft" || key == "ArrowUp")
658 addWhitelistedDomain(); 669 element = element.previousElementSibling || container.lastElementChild;
659 break; 670 else if (key == "ArrowRight" || key == "ArrowDown")
660 case "open-doclink": 671 element = element.nextElementSibling || container.firstElementChild;
661 let doclink = findParentData(element, "doclink", false); 672 }
662 openDocLink(doclink); 673
663 break; 674 let actions = container.getAttribute("data-action").split(",");
664 case "switch-tab": 675 for (let action of actions)
665 if (key == "Enter") 676 {
666 { 677 execAction(action, element);
667 let tabId = findParentData(element, "tab", false);
668 switchTab(tabId);
669 }
670 else if (element.hasAttribute("aria-selected"))
671 {
672 if (key == "ArrowLeft" || key == "ArrowUp")
673 {
674 element = element.previousElementSibling ||
675 container.lastElementChild;
676 }
677 else if (key == "ArrowRight" || key == "ArrowDown")
678 {
679 element = element.nextElementSibling ||
680 container.firstElementChild;
681 }
682
683 let tabId = findParentData(element, "tab", false);
684 switchTab(tabId);
685 }
686 break;
687 } 678 }
688 } 679 }
689 680
690 function selectTabItem(tabId, container, focus) 681 function selectTabItem(tabId, container, focus)
691 { 682 {
692 // Show tab content 683 // Show tab content
693 document.body.setAttribute("data-tab", tabId); 684 document.body.setAttribute("data-tab", tabId);
694 685
695 // Select tab 686 // Select tab
696 let tabList = container.querySelector("[role='tablist']"); 687 let tabList = container.querySelector("[role='tablist']");
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
767 758
768 updateShareLink(); 759 updateShareLink();
769 updateTooltips(); 760 updateTooltips();
770 761
771 // Initialize interactive UI elements 762 // Initialize interactive UI elements
772 document.body.addEventListener("click", onClick, false); 763 document.body.addEventListener("click", onClick, false);
773 document.body.addEventListener("keyup", onKeyUp, false); 764 document.body.addEventListener("keyup", onKeyUp, false);
774 let placeholderValue = getMessage("options_dialog_language_find"); 765 let placeholderValue = getMessage("options_dialog_language_find");
775 E("find-language").setAttribute("placeholder", placeholderValue); 766 E("find-language").setAttribute("placeholder", placeholderValue);
776 E("find-language").addEventListener("keyup", onFindLanguageKeyUp, false); 767 E("find-language").addEventListener("keyup", onFindLanguageKeyUp, false);
777 let exampleValue = getMessage("options_whitelist_placeholder_example"); 768 let exampleValue = getMessage("options_whitelist_placeholder_example",
778 exampleValue += " www.example.com"; 769 ["www.example.com"]);
779 E("whitelisting-textbox").setAttribute("placeholder", exampleValue); 770 E("whitelisting-textbox").setAttribute("placeholder", exampleValue);
780 E("whitelisting-textbox").addEventListener("keyup", (e) => 771 E("whitelisting-textbox").addEventListener("keyup", (e) =>
Thomas Greiner 2017/05/09 13:42:56 I'm not sure it's a good idea to validate the inpu
saroyanm 2017/05/16 20:20:06 It will, that's why I'm using keyUp instead.
saroyanm 2017/05/18 16:21:52 Fine for now because we are checking for only empt
781 { 772 {
782 let addWhitelistButton = E("whitelisting-add-button"); 773 E("whitelisting-add-button").disabled = !e.target.value;
783 let validationElement = E("whitelisting-validation");
784 if (getKey(e) == "Enter")
785 {
786 if (!E("whitelisting-add-button").hasAttribute("disabled"))
787 addWhitelistedDomain();
788 }
789 else
790 {
791 let validIpAddressRegex = "^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25"
saroyanm 2017/04/21 12:03:17 Regular expression to match Hostname and IP addres
Thomas Greiner 2017/05/09 13:42:56 Detail: Those are constants that we can simply com
Thomas Greiner 2017/05/09 13:42:56 I don't think we need to be that specific. Somethi
saroyanm 2017/05/16 20:20:07 I think this is not anymore relevant, while the va
792 + "[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$";
Thomas Greiner 2017/05/09 13:42:56 You need to escape the escape characters since you
793 let validHostnameRegex = "^(([a-zA-Z]|[a-zA-Z][a-zA-Z0-9\-]*[a-zA-Z0-9]"
Thomas Greiner 2017/05/09 13:42:56 Same here. I don't think we need to be that specif
794 +")\.)*([A-Za-z]|[A-Za-z][A-Za-z0-9\-]*[A-Za-z0-9])$";
795
796 let isDuplicate = false;
797 for (let i = 0; i < collections.whitelist.items.length; i++)
798 {
799 if (collections.whitelist.items[i].title == e.target.value)
800 isDuplicate = true;
Thomas Greiner 2017/05/09 13:42:56 Detail: Why do we need this variable? We could jus
801 }
802
803 if (isDuplicate)
804 {
805 addWhitelistButton.setAttribute("disabled", "");
saroyanm 2017/04/21 12:03:17 I think we should use checkValidity() method inste
Thomas Greiner 2017/05/09 13:42:56 Detail: Can't we just do `addWhitelistButton.disab
saroyanm 2017/05/16 20:20:06 done.
806 validationElement.textContent =
807 getMessage("options_whitelist_duplicate");
808 }
809 else if (new RegExp(validIpAddressRegex).test(e.target.value) ||
810 new RegExp(validHostnameRegex).test(e.target.value))
811 {
812 addWhitelistButton.removeAttribute("disabled");
813 validationElement.textContent = "";
814 }
815 else if (!e.target.value)
816 {
817 validationElement.textContent = "";
818 addWhitelistButton.setAttribute("disabled", "");
819 }
820 else
821 {
822 addWhitelistButton.setAttribute("disabled", "");
823 validationElement.textContent =
824 getMessage("options_whitelist_invalid");
825
826 }
827 }
828 }, false); 774 }, false);
829 775
830 // Advanced tab 776 // Advanced tab
831 let tweaks = document.querySelectorAll("#tweaks li[data-pref]"); 777 let tweaks = document.querySelectorAll("#tweaks li[data-pref]");
832 tweaks = Array.prototype.map.call(tweaks, (checkbox) => 778 tweaks = Array.prototype.map.call(tweaks, (checkbox) =>
833 { 779 {
834 return checkbox.getAttribute("data-pref"); 780 return checkbox.getAttribute("data-pref");
835 }); 781 });
836 for (let key of tweaks) 782 for (let key of tweaks)
837 { 783 {
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after
992 for (let subscription of subscriptions) 938 for (let subscription of subscriptions)
993 { 939 {
994 ext.backgroundPage.sendMessage({ 940 ext.backgroundPage.sendMessage({
995 type: "filters.get", 941 type: "filters.get",
996 subscriptionUrl: subscription.url 942 subscriptionUrl: subscription.url
997 }, 943 },
998 (filters) => 944 (filters) =>
999 { 945 {
1000 for (let filter of filters) 946 for (let filter of filters)
1001 updateFilter(filter); 947 updateFilter(filter);
948
949 isCustomFiltersLoaded = true;
1002 }); 950 });
1003 } 951 }
1004 }); 952 });
1005 loadRecommendations(); 953 loadRecommendations();
1006 ext.backgroundPage.sendMessage({ 954 ext.backgroundPage.sendMessage({
1007 type: "prefs.get", 955 type: "prefs.get",
1008 key: "subscriptions_exceptionsurl" 956 key: "subscriptions_exceptionsurl"
1009 }, 957 },
1010 (url) => 958 (url) =>
1011 { 959 {
(...skipping 12 matching lines...) Expand all
1024 { 972 {
1025 for (let subscription of subscriptions) 973 for (let subscription of subscriptions)
1026 onSubscriptionMessage("added", subscription); 974 onSubscriptionMessage("added", subscription);
1027 }); 975 });
1028 }); 976 });
1029 } 977 }
1030 978
1031 function addWhitelistedDomain() 979 function addWhitelistedDomain()
1032 { 980 {
1033 let domain = E("whitelisting-textbox"); 981 let domain = E("whitelisting-textbox");
982 for (let whitelistItem of collections.whitelist.items)
983 {
984 if (whitelistItem.title == domain.value)
985 {
986 whitelistItem[timestampUI] = Date.now();
987 collections.whitelist.updateItem(whitelistItem);
988 domain.value = "";
989 break;
990 }
991 }
1034 if (domain.value) 992 if (domain.value)
1035 { 993 {
1036 sendMessageHandleErrors({ 994 sendMessageHandleErrors({
1037 type: "filters.add", 995 type: "filters.add",
1038 text: "@@||" + domain.value.toLowerCase() + "^$document" 996 text: "@@||" + domain.value.toLowerCase() + "^$document"
1039 }); 997 });
1040 } 998 }
1041 999
1042 domain.value = ""; 1000 domain.value = "";
1043 E("whitelisting-add-button").setAttribute("disabled", ""); 1001 E("whitelisting-add-button").disabled = true;
1044 } 1002 }
1045 1003
1046 function editCustomFilters() 1004 function editCustomFilters()
1047 { 1005 {
1006 if (!isCustomFiltersLoaded)
1007 {
1008 console.error("Custom filters are not loaded");
1009 return;
1010 }
1011
1012 E("custom-filters").classList.add("mode-edit");
1048 let filterTexts = []; 1013 let filterTexts = [];
1049 for (let customFilterItem of collections.customFilters.items) 1014 for (let customFilterItem of collections.customFilters.items)
1050 filterTexts.push(customFilterItem.text); 1015 filterTexts.push(customFilterItem.text);
1051 E("custom-filters-raw").value = filterTexts.join("\n"); 1016 E("custom-filters-raw").value = filterTexts.join("\n");
1052 } 1017 }
1053 1018
1054 function addEnableSubscription(url, title, homepage) 1019 function addEnableSubscription(url, title, homepage)
1055 { 1020 {
1056 let messageType = null; 1021 let messageType = null;
1057 let knownSubscription = subscriptionsMap[url]; 1022 let knownSubscription = subscriptionsMap[url];
(...skipping 12 matching lines...) Expand all
1070 message.homepage = homepage; 1035 message.homepage = homepage;
1071 1036
1072 ext.backgroundPage.sendMessage(message); 1037 ext.backgroundPage.sendMessage(message);
1073 } 1038 }
1074 1039
1075 function onFilterMessage(action, filter) 1040 function onFilterMessage(action, filter)
1076 { 1041 {
1077 switch (action) 1042 switch (action)
1078 { 1043 {
1079 case "added": 1044 case "added":
1045 filter[timestampUI] = Date.now();
1080 updateFilter(filter); 1046 updateFilter(filter);
1081 updateShareLink(); 1047 updateShareLink();
1082 break; 1048 break;
1083 case "loaded": 1049 case "loaded":
1084 populateLists(); 1050 populateLists();
1085 break; 1051 break;
1086 case "removed": 1052 case "removed":
1087 let knownFilter = filtersMap[filter.text]; 1053 let knownFilter = filtersMap[filter.text];
1088 collections.whitelist.removeItem(knownFilter); 1054 collections.whitelist.removeItem(knownFilter);
1089 collections.customFilters.removeItem(knownFilter); 1055 collections.customFilters.removeItem(knownFilter);
(...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after
1350 }); 1316 });
1351 ext.backgroundPage.sendMessage({ 1317 ext.backgroundPage.sendMessage({
1352 type: "subscriptions.listen", 1318 type: "subscriptions.listen",
1353 filter: ["added", "disabled", "homepage", "lastDownload", "removed", 1319 filter: ["added", "disabled", "homepage", "lastDownload", "removed",
1354 "title", "downloadStatus", "downloading"] 1320 "title", "downloadStatus", "downloading"]
1355 }); 1321 });
1356 1322
1357 window.addEventListener("DOMContentLoaded", onDOMLoaded, false); 1323 window.addEventListener("DOMContentLoaded", onDOMLoaded, false);
1358 window.addEventListener("hashchange", onHashChange, false); 1324 window.addEventListener("hashchange", onHashChange, false);
1359 } 1325 }
LEFTRIGHT

Powered by Google App Engine
This is Rietveld