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

Side by Side Diff: new-options.js

Issue 29411555: Issue 5169 - Add whitelisted tab to the new options page (Closed)
Patch Set: Addressed comments Created May 31, 2017, 8:27 a.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
OLDNEW
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
(...skipping 19 matching lines...) Expand all
30 let filterErrors = new Map([ 30 let filterErrors = new Map([
31 ["synchronize_invalid_url", 31 ["synchronize_invalid_url",
32 "options_filterList_lastDownload_invalidURL"], 32 "options_filterList_lastDownload_invalidURL"],
33 ["synchronize_connection_error", 33 ["synchronize_connection_error",
34 "options_filterList_lastDownload_connectionError"], 34 "options_filterList_lastDownload_connectionError"],
35 ["synchronize_invalid_data", 35 ["synchronize_invalid_data",
36 "options_filterList_lastDownload_invalidData"], 36 "options_filterList_lastDownload_invalidData"],
37 ["synchronize_checksum_mismatch", 37 ["synchronize_checksum_mismatch",
38 "options_filterList_lastDownload_checksumMismatch"] 38 "options_filterList_lastDownload_checksumMismatch"]
39 ]); 39 ]);
40 const timestampUI = Symbol();
40 41
41 function Collection(details) 42 function Collection(details)
42 { 43 {
43 this.details = details; 44 this.details = details;
44 this.items = []; 45 this.items = [];
45 } 46 }
46 47
47 Collection.prototype._setEmpty = function(table, text) 48 Collection.prototype._setEmpty = function(table, texts)
48 { 49 {
49 let placeholder = table.querySelector(".empty-placeholder"); 50 let placeholders = table.querySelectorAll(".empty-placeholder");
50 if (text && !placeholder) 51
52 if (texts && placeholders.length == 0)
51 { 53 {
52 placeholder = document.createElement("li"); 54 for (let text of texts)
53 placeholder.className = "empty-placeholder"; 55 {
54 placeholder.textContent = getMessage(text); 56 let placeholder = document.createElement("li");
55 table.appendChild(placeholder); 57 placeholder.className = "empty-placeholder";
58 placeholder.textContent = getMessage(text);
59 table.appendChild(placeholder);
60 }
56 } 61 }
57 else if (placeholder) 62 else if (placeholders.length > 0)
58 table.removeChild(placeholder); 63 {
64 for (let placeholder of placeholders)
65 table.removeChild(placeholder);
66 }
59 }; 67 };
60 68
61 Collection.prototype._createElementQuery = function(item) 69 Collection.prototype._createElementQuery = function(item)
62 { 70 {
63 let access = (item.url || item.text).replace(/'/g, "\\'"); 71 let access = (item.url || item.text).replace(/'/g, "\\'");
64 return function(container) 72 return function(container)
65 { 73 {
66 return container.querySelector("[data-access='" + access + "']"); 74 return container.querySelector("[data-access='" + access + "']");
67 }; 75 };
68 }; 76 };
69 77
70 Collection.prototype._getItemTitle = function(item, i) 78 Collection.prototype._getItemTitle = function(item, i)
71 { 79 {
72 if (item.url == acceptableAdsUrl) 80 if (item.url == acceptableAdsUrl)
73 return getMessage("options_acceptableAds_description"); 81 return getMessage("options_acceptableAds_description");
74 if (this.details[i].useOriginalTitle && item.originalTitle) 82 if (this.details[i].useOriginalTitle && item.originalTitle)
75 return item.originalTitle; 83 return item.originalTitle;
76 return item.title || item.url || item.text; 84 return item.title || item.url || item.text;
77 }; 85 };
78 86
79 Collection.prototype.addItem = function(item) 87 Collection.prototype._sortItems = function()
80 { 88 {
81 if (this.items.indexOf(item) >= 0)
82 return;
83
84 this.items.push(item);
85 this.items.sort((a, b) => 89 this.items.sort((a, b) =>
86 { 90 {
87 // 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
88 // 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
89 // 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
90 // of the filter lists in the Advanced tab. 94 // of the filter lists in the Advanced tab.
91 if (a.url == acceptableAdsUrl) 95 if (a.url == acceptableAdsUrl)
92 return 1; 96 return 1;
93 if (b.url == acceptableAdsUrl) 97 if (b.url == acceptableAdsUrl)
94 return -1; 98 return -1;
95 99
100 // Make sure that duplicated whitelist entries are always being moved to
Thomas Greiner 2017/06/16 10:35:45 Detail: This is not about handling duplicated entr
saroyanm 2017/06/16 11:13:54 That's a very good question, I didn't know about t
saroyanm 2017/06/16 13:05:11 The mentioned behavior was confirmed, so I'll upda
saroyanm 2017/06/16 16:44:07 Done.
101 // the top of the list
102 let aTimestamp = a[timestampUI] || 0;
103 let bTimestamp = b[timestampUI] || 0;
104 if (aTimestamp || bTimestamp)
105 return bTimestamp - aTimestamp;
106
96 let aTitle = this._getItemTitle(a, 0).toLowerCase(); 107 let aTitle = this._getItemTitle(a, 0).toLowerCase();
97 let bTitle = this._getItemTitle(b, 0).toLowerCase(); 108 let bTitle = this._getItemTitle(b, 0).toLowerCase();
98 return aTitle.localeCompare(bTitle); 109 return aTitle.localeCompare(bTitle);
99 }); 110 });
111 };
100 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();
101 for (let j = 0; j < this.details.length; j++) 120 for (let j = 0; j < this.details.length; j++)
102 { 121 {
103 let table = E(this.details[j].id); 122 let table = E(this.details[j].id);
104 let template = table.querySelector("template"); 123 let template = table.querySelector("template");
105 let listItem = document.createElement("li"); 124 let listItem = document.createElement("li");
106 listItem.appendChild(document.importNode(template.content, true)); 125 listItem.appendChild(document.importNode(template.content, true));
107 listItem.setAttribute("aria-label", this._getItemTitle(item, j)); 126 listItem.setAttribute("aria-label", this._getItemTitle(item, j));
108 listItem.setAttribute("data-access", item.url || item.text); 127 listItem.setAttribute("data-access", item.url || item.text);
109 listItem.setAttribute("role", "section"); 128 listItem.setAttribute("role", "section");
110 129
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
172 } 191 }
173 192
174 element.parentElement.removeChild(element); 193 element.parentElement.removeChild(element);
175 if (this.items.length == 0) 194 if (this.items.length == 0)
176 this._setEmpty(table, detail.emptyText); 195 this._setEmpty(table, detail.emptyText);
177 } 196 }
178 }; 197 };
179 198
180 Collection.prototype.updateItem = function(item) 199 Collection.prototype.updateItem = function(item)
181 { 200 {
201 var oldIndex = this.items.indexOf(item);
202 this._sortItems();
182 let access = (item.url || item.text).replace(/'/g, "\\'"); 203 let access = (item.url || item.text).replace(/'/g, "\\'");
183 for (let i = 0; i < this.details.length; i++) 204 for (let i = 0; i < this.details.length; i++)
184 { 205 {
185 let table = E(this.details[i].id); 206 let table = E(this.details[i].id);
186 let element = table.querySelector("[data-access='" + access + "']"); 207 let element = table.querySelector("[data-access='" + access + "']");
187 if (!element) 208 if (!element)
188 continue; 209 continue;
189 210
190 let title = this._getItemTitle(item, i); 211 let title = this._getItemTitle(item, i);
191 element.querySelector(".display").textContent = title; 212 element.querySelector(".display").textContent = title;
192 element.setAttribute("aria-label", title); 213 element.setAttribute("aria-label", title);
193 if (this.details[i].searchable) 214 if (this.details[i].searchable)
194 element.setAttribute("data-search", title.toLowerCase()); 215 element.setAttribute("data-search", title.toLowerCase());
195 let control = element.querySelector(".control[role='checkbox']"); 216 let control = element.querySelector(".control[role='checkbox']");
196 if (control) 217 if (control)
197 { 218 {
198 control.setAttribute("aria-checked", item.disabled == false); 219 control.setAttribute("aria-checked", item.disabled == false);
199 if (item.url == acceptableAdsUrl && this == collections.filterLists) 220 if (item.url == acceptableAdsUrl && this == collections.filterLists)
200 control.setAttribute("disabled", true); 221 control.disabled = true;
201 } 222 }
202 223
203 let dateElement = element.querySelector(".date"); 224 let dateElement = element.querySelector(".date");
204 let timeElement = element.querySelector(".time"); 225 let timeElement = element.querySelector(".time");
205 if (dateElement && timeElement) 226 if (dateElement && timeElement)
206 { 227 {
207 let message = element.querySelector(".message"); 228 let message = element.querySelector(".message");
208 if (item.isDownloading) 229 if (item.isDownloading)
209 { 230 {
210 let text = getMessage("options_filterList_lastDownload_inProgress"); 231 let text = getMessage("options_filterList_lastDownload_inProgress");
(...skipping 23 matching lines...) Expand all
234 { 255 {
235 if (item.homepage) 256 if (item.homepage)
236 websiteElement.setAttribute("href", item.homepage); 257 websiteElement.setAttribute("href", item.homepage);
237 else 258 else
238 websiteElement.setAttribute("aria-hidden", true); 259 websiteElement.setAttribute("aria-hidden", true);
239 } 260 }
240 261
241 let sourceElement = element.querySelector(".context-menu .source"); 262 let sourceElement = element.querySelector(".context-menu .source");
242 if (sourceElement) 263 if (sourceElement)
243 sourceElement.setAttribute("href", item.url); 264 sourceElement.setAttribute("href", item.url);
265
266 if (oldIndex != this.items.indexOf(item))
Thomas Greiner 2017/06/16 10:35:46 Detail: `this.items.indexOf(item)` is duplicated s
saroyanm 2017/06/16 16:44:06 Done.
267 table.insertBefore(element, table.childNodes[this.items.indexOf(item)]);
244 } 268 }
245 }; 269 };
246 270
247 Collection.prototype.clearAll = function() 271 Collection.prototype.clearAll = function()
248 { 272 {
249 this.items = []; 273 this.items = [];
250 for (let detail of this.details) 274 for (let detail of this.details)
251 { 275 {
252 let table = E(detail.id); 276 let table = E(detail.id);
253 let element = table.firstChild; 277 let element = table.firstChild;
(...skipping 24 matching lines...) Expand all
278 } 302 }
279 303
280 collections.popular = new Collection([ 304 collections.popular = new Collection([
281 { 305 {
282 id: "recommend-list-table" 306 id: "recommend-list-table"
283 } 307 }
284 ]); 308 ]);
285 collections.langs = new Collection([ 309 collections.langs = new Collection([
286 { 310 {
287 id: "blocking-languages-table", 311 id: "blocking-languages-table",
288 emptyText: "options_dialog_language_added_empty" 312 emptyText: ["options_dialog_language_added_empty"]
289 }, 313 },
290 { 314 {
291 id: "blocking-languages-dialog-table", 315 id: "blocking-languages-dialog-table",
292 emptyText: "options_dialog_language_added_empty" 316 emptyText: ["options_dialog_language_added_empty"]
293 } 317 }
294 ]); 318 ]);
295 collections.allLangs = new Collection([ 319 collections.allLangs = new Collection([
296 { 320 {
297 id: "all-lang-table", 321 id: "all-lang-table",
298 emptyText: "options_dialog_language_other_empty", 322 emptyText: ["options_dialog_language_other_empty"],
299 searchable: true 323 searchable: true
300 } 324 }
301 ]); 325 ]);
302 collections.acceptableAds = new Collection([ 326 collections.acceptableAds = new Collection([
303 { 327 {
304 id: "acceptableads-table" 328 id: "acceptableads-table"
305 } 329 }
306 ]); 330 ]);
307 collections.custom = new Collection([ 331 collections.custom = new Collection([
308 { 332 {
309 id: "custom-list-table" 333 id: "custom-list-table"
310 } 334 }
311 ]); 335 ]);
312 collections.whitelist = new Collection([ 336 collections.whitelist = new Collection([
313 { 337 {
314 id: "whitelisting-table", 338 id: "whitelisting-table",
315 emptyText: "options_whitelisted_empty" 339 emptyText: ["options_whitelist_empty_1", "options_whitelist_empty_2"]
316 } 340 }
317 ]); 341 ]);
318 collections.customFilters = new Collection([ 342 collections.customFilters = new Collection([
319 { 343 {
320 id: "custom-filters-table", 344 id: "custom-filters-table",
321 emptyText: "options_customFilters_empty" 345 emptyText: ["options_customFilters_empty"]
322 } 346 }
323 ]); 347 ]);
324 collections.filterLists = new Collection([ 348 collections.filterLists = new Collection([
325 { 349 {
326 id: "all-filter-lists-table", 350 id: "all-filter-lists-table",
327 useOriginalTitle: true 351 useOriginalTitle: true
328 } 352 }
329 ]); 353 ]);
330 354
331 function toggleShowLanguage(subscription) 355 function toggleShowLanguage(subscription)
(...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after
488 let dialog = E("dialog-content-predefined"); 512 let dialog = E("dialog-content-predefined");
489 let title = dialog.querySelector("h3").textContent; 513 let title = dialog.querySelector("h3").textContent;
490 let url = dialog.querySelector(".url").textContent; 514 let url = dialog.querySelector(".url").textContent;
491 addEnableSubscription(url, title); 515 addEnableSubscription(url, title);
492 closeDialog(); 516 closeDialog();
493 break; 517 break;
494 } 518 }
495 case "cancel-custom-filters": 519 case "cancel-custom-filters":
496 E("custom-filters").classList.remove("mode-edit"); 520 E("custom-filters").classList.remove("mode-edit");
497 break; 521 break;
498 case "cancel-domain-exception":
499 E("whitelisting-textbox").value = "";
500 document.querySelector("#whitelisting .controls").classList
501 .remove("mode-edit");
502 break;
503 case "close-dialog": 522 case "close-dialog":
504 closeDialog(); 523 closeDialog();
505 break; 524 break;
506 case "edit-custom-filters": 525 case "edit-custom-filters":
507 editCustomFilters(); 526 editCustomFilters();
508 break; 527 break;
509 case "edit-domain-exception":
510 document.querySelector("#whitelisting .controls").classList
511 .add("mode-edit");
512 E("whitelisting-textbox").focus();
513 break;
514 case "import-subscription": { 528 case "import-subscription": {
515 let url = E("blockingList-textbox").value; 529 let url = E("blockingList-textbox").value;
516 addEnableSubscription(url); 530 addEnableSubscription(url);
517 closeDialog(); 531 closeDialog();
518 break; 532 break;
519 } 533 }
520 case "open-context-menu": { 534 case "open-context-menu": {
521 let listItem = findParentData(element, "access", true); 535 let listItem = findParentData(element, "access", true);
522 if (listItem && !listItem.classList.contains("show-context-menu")) 536 if (listItem && !listItem.classList.contains("show-context-menu"))
523 listItem.classList.add("show-context-menu"); 537 listItem.classList.add("show-context-menu");
(...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after
743 757
744 updateShareLink(); 758 updateShareLink();
745 updateTooltips(); 759 updateTooltips();
746 760
747 // Initialize interactive UI elements 761 // Initialize interactive UI elements
748 document.body.addEventListener("click", onClick, false); 762 document.body.addEventListener("click", onClick, false);
749 document.body.addEventListener("keyup", onKeyUp, false); 763 document.body.addEventListener("keyup", onKeyUp, false);
750 let placeholderValue = getMessage("options_dialog_language_find"); 764 let placeholderValue = getMessage("options_dialog_language_find");
751 E("find-language").setAttribute("placeholder", placeholderValue); 765 E("find-language").setAttribute("placeholder", placeholderValue);
752 E("find-language").addEventListener("keyup", onFindLanguageKeyUp, false); 766 E("find-language").addEventListener("keyup", onFindLanguageKeyUp, false);
753 E("whitelisting-textbox").addEventListener("keypress", (e) => 767 let exampleValue = getMessages("options_whitelist_placeholder_example",
saroyanm 2017/06/14 11:51:22 Nit: This should be getMessage(...)
Thomas Greiner 2017/06/16 10:35:46 Indeed.
saroyanm 2017/06/16 16:43:07 Done.
768 ["www.example.com"]);
769 E("whitelisting-textbox").setAttribute("placeholder", exampleValue);
770 E("whitelisting-textbox").addEventListener("keyup", (e) =>
754 { 771 {
772 let addWhitelistButton = E("whitelisting-add-button");
773 addWhitelistButton.disabled = false;
755 if (getKey(e) == "Enter") 774 if (getKey(e) == "Enter")
756 addWhitelistedDomain(); 775 {
776 if (!addWhitelistButton.disabled)
777 addWhitelistedDomain();
Thomas Greiner 2017/06/16 10:35:46 This will clear the input field so the whitelist b
saroyanm 2017/06/16 15:53:45 We do need: ` domain.value = ""; E("whitelisting-a
saroyanm 2017/06/16 16:43:07 Done.
778 }
779 else
780 {
781 addWhitelistButton.disabled = !e.target.value;
782 }
757 }, false); 783 }, false);
758 784
759 // Advanced tab 785 // Advanced tab
760 let tweaks = document.querySelectorAll("#tweaks li[data-pref]"); 786 let tweaks = document.querySelectorAll("#tweaks li[data-pref]");
761 tweaks = Array.prototype.map.call(tweaks, (checkbox) => 787 tweaks = Array.prototype.map.call(tweaks, (checkbox) =>
762 { 788 {
763 return checkbox.getAttribute("data-pref"); 789 return checkbox.getAttribute("data-pref");
764 }); 790 });
765 for (let key of tweaks) 791 for (let key of tweaks)
766 { 792 {
(...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after
955 { 981 {
956 for (let subscription of subscriptions) 982 for (let subscription of subscriptions)
957 onSubscriptionMessage("added", subscription); 983 onSubscriptionMessage("added", subscription);
958 }); 984 });
959 }); 985 });
960 } 986 }
961 987
962 function addWhitelistedDomain() 988 function addWhitelistedDomain()
963 { 989 {
964 let domain = E("whitelisting-textbox"); 990 let domain = E("whitelisting-textbox");
991 for (let whitelistItem of collections.whitelist.items)
992 {
993 if (whitelistItem.title == domain.value)
994 {
995 whitelistItem[timestampUI] = Date.now();
996 collections.whitelist.updateItem(whitelistItem);
997 domain.value = "";
998 break;
999 }
1000 }
965 if (domain.value) 1001 if (domain.value)
966 { 1002 {
967 sendMessageHandleErrors({ 1003 sendMessageHandleErrors({
968 type: "filters.add", 1004 type: "filters.add",
969 text: "@@||" + domain.value.toLowerCase() + "^$document" 1005 text: "@@||" + domain.value.toLowerCase() + "^$document"
970 }); 1006 });
971 } 1007 }
972 1008
973 domain.value = ""; 1009 domain.value = "";
974 document.querySelector("#whitelisting .controls") 1010 E("whitelisting-add-button").disabled = true;
975 .classList.remove("mode-edit");
976 } 1011 }
977 1012
978 function editCustomFilters() 1013 function editCustomFilters()
979 { 1014 {
980 if (!isCustomFiltersLoaded) 1015 if (!isCustomFiltersLoaded)
981 { 1016 {
982 console.error("Custom filters are not loaded"); 1017 console.error("Custom filters are not loaded");
983 return; 1018 return;
984 } 1019 }
985 1020
(...skipping 303 matching lines...) Expand 10 before | Expand all | Expand 10 after
1289 }); 1324 });
1290 ext.backgroundPage.sendMessage({ 1325 ext.backgroundPage.sendMessage({
1291 type: "subscriptions.listen", 1326 type: "subscriptions.listen",
1292 filter: ["added", "disabled", "homepage", "lastDownload", "removed", 1327 filter: ["added", "disabled", "homepage", "lastDownload", "removed",
1293 "title", "downloadStatus", "downloading"] 1328 "title", "downloadStatus", "downloading"]
1294 }); 1329 });
1295 1330
1296 window.addEventListener("DOMContentLoaded", onDOMLoaded, false); 1331 window.addEventListener("DOMContentLoaded", onDOMLoaded, false);
1297 window.addEventListener("hashchange", onHashChange, false); 1332 window.addEventListener("hashchange", onHashChange, false);
1298 } 1333 }
OLDNEW
« locale/en-US/new-options.json ('K') | « new-options.html ('k') | skin/new-options.css » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld