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

Side by Side Diff: new-options.js

Issue 29445590: Issue 5255 - Advanced tab (HTML, strings and functionality) (Closed)
Patch Set: Addressed Thomas comments Created July 12, 2017, 1:03 p.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
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details. 12 * GNU General Public License for more details.
13 * 13 *
14 * You should have received a copy of the GNU General Public License 14 * You should have received a copy of the GNU General Public License
15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. 15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
16 */ 16 */
17 17
18 /* globals checkShareResource, getDocLink, i18nFormatDateTime, openSharePopup, 18 /* globals checkShareResource, getDocLink, i18nFormatDateTime, openSharePopup,
19 E */ 19 E */
20 20
21 "use strict"; 21 "use strict";
22 22
23 { 23 {
24 let subscriptionsMap = Object.create(null); 24 let subscriptionsMap = Object.create(null);
25 let filtersMap = Object.create(null); 25 let filtersMap = Object.create(null);
26 let collections = Object.create(null); 26 let collections = Object.create(null);
27 let acceptableAdsUrl = null; 27 let acceptableAdsUrl = null;
28 let isCustomFiltersLoaded = false; 28 let isCustomFiltersLoaded = false;
29 let {getMessage} = ext.i18n; 29 let {getMessage} = ext.i18n;
30 let customFiltersArray = [];
Thomas Greiner 2017/07/14 12:26:13 Detail: I'd recommend not to include the value typ
saroyanm 2017/07/14 16:17:25 Acknowledged.
saroyanm 2017/07/14 17:11:06 Done.
30 let filterErrors = new Map([ 31 let filterErrors = new Map([
31 ["synchronize_invalid_url", 32 ["synchronize_invalid_url",
32 "options_filterList_lastDownload_invalidURL"], 33 "options_filterList_lastDownload_invalidURL"],
33 ["synchronize_connection_error", 34 ["synchronize_connection_error",
34 "options_filterList_lastDownload_connectionError"], 35 "options_filterList_lastDownload_connectionError"],
35 ["synchronize_invalid_data", 36 ["synchronize_invalid_data",
36 "options_filterList_lastDownload_invalidData"], 37 "options_filterList_lastDownload_invalidData"],
37 ["synchronize_checksum_mismatch", 38 ["synchronize_checksum_mismatch",
38 "options_filterList_lastDownload_checksumMismatch"] 39 "options_filterList_lastDownload_checksumMismatch"]
39 ]); 40 ]);
40 41
42 const whitelistedDomainRegexp = /^@@\|\|([^/:]+)\^\$document$/;
43 // Period of time in milliseconds
44 const minuteInMs = 60000;
45 const hourInMs = 3600000;
46 const fullDayInMs = 86400000;
47
41 function Collection(details) 48 function Collection(details)
42 { 49 {
43 this.details = details; 50 this.details = details;
44 this.items = []; 51 this.items = [];
45 } 52 }
46 53
47 Collection.prototype._setEmpty = function(table, text) 54 Collection.prototype._setEmpty = function(table, text)
48 { 55 {
49 let placeholder = table.querySelector(".empty-placeholder"); 56 let placeholder = table.querySelector(".empty-placeholder");
50 if (text && !placeholder) 57 if (text && !placeholder)
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
93 if (b.url == acceptableAdsUrl) 100 if (b.url == acceptableAdsUrl)
94 return -1; 101 return -1;
95 102
96 let aTitle = this._getItemTitle(a, 0).toLowerCase(); 103 let aTitle = this._getItemTitle(a, 0).toLowerCase();
97 let bTitle = this._getItemTitle(b, 0).toLowerCase(); 104 let bTitle = this._getItemTitle(b, 0).toLowerCase();
98 return aTitle.localeCompare(bTitle); 105 return aTitle.localeCompare(bTitle);
99 }); 106 });
100 107
101 for (let j = 0; j < this.details.length; j++) 108 for (let j = 0; j < this.details.length; j++)
102 { 109 {
103 let table = E(this.details[j].id); 110 let detail = this.details[j];
111 let table = E(detail.id);
104 let template = table.querySelector("template"); 112 let template = table.querySelector("template");
105 let listItem = document.createElement("li"); 113 let listItem = document.createElement("li");
106 listItem.appendChild(document.importNode(template.content, true)); 114 listItem.appendChild(document.importNode(template.content, true));
107 listItem.setAttribute("aria-label", this._getItemTitle(item, j)); 115 listItem.setAttribute("aria-label", this._getItemTitle(item, j));
108 listItem.setAttribute("data-access", item.url || item.text); 116 listItem.setAttribute("data-access", item.url || item.text);
109 listItem.setAttribute("role", "section"); 117 listItem.setAttribute("role", "section");
110 118
111 let label = listItem.querySelector(".display"); 119 let label = listItem.querySelector(".display");
112 if (item.recommended && label.hasAttribute("data-tooltip")) 120 if (item.recommended && label.hasAttribute("data-tooltip"))
113 { 121 {
114 let tooltipId = label.getAttribute("data-tooltip"); 122 let tooltipId = label.getAttribute("data-tooltip");
115 tooltipId = tooltipId.replace("%value%", item.recommended); 123 tooltipId = tooltipId.replace("%value%", item.recommended);
116 label.setAttribute("data-tooltip", tooltipId); 124 label.setAttribute("data-tooltip", tooltipId);
117 } 125 }
118 126
119 for (let control of listItem.querySelectorAll(".control")) 127 for (let control of listItem.querySelectorAll(".control"))
120 { 128 {
121 if (control.hasAttribute("title")) 129 if (control.hasAttribute("title"))
122 { 130 {
123 let titleValue = getMessage(control.getAttribute("title")); 131 let titleValue = getMessage(control.getAttribute("title"));
124 control.setAttribute("title", titleValue); 132 control.setAttribute("title", titleValue);
125 } 133 }
126 } 134 }
127 135
128 this._setEmpty(table, null); 136 this._setEmpty(table, null);
129 if (table.hasChildNodes()) 137 if (table.children.length > 0)
130 { 138 table.insertBefore(listItem, table.children[this.items.indexOf(item)]);
131 table.insertBefore(listItem,
132 table.childNodes[this.items.indexOf(item)]);
133 }
134 else 139 else
135 table.appendChild(listItem); 140 table.appendChild(listItem);
141
136 this.updateItem(item); 142 this.updateItem(item);
137 } 143 }
138 return length; 144 return length;
139 }; 145 };
140 146
141 Collection.prototype.removeItem = function(item) 147 Collection.prototype.removeItem = function(item)
142 { 148 {
143 let index = this.items.indexOf(item); 149 let index = this.items.indexOf(item);
144 if (index == -1) 150 if (index == -1)
145 return; 151 return;
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
193 if (this.details[i].searchable) 199 if (this.details[i].searchable)
194 element.setAttribute("data-search", title.toLowerCase()); 200 element.setAttribute("data-search", title.toLowerCase());
195 let control = element.querySelector(".control[role='checkbox']"); 201 let control = element.querySelector(".control[role='checkbox']");
196 if (control) 202 if (control)
197 { 203 {
198 control.setAttribute("aria-checked", item.disabled == false); 204 control.setAttribute("aria-checked", item.disabled == false);
199 if (item.url == acceptableAdsUrl && this == collections.filterLists) 205 if (item.url == acceptableAdsUrl && this == collections.filterLists)
200 control.setAttribute("disabled", true); 206 control.setAttribute("disabled", true);
201 } 207 }
202 208
203 let dateElement = element.querySelector(".date"); 209 let lastUpdateElement = element.querySelector(".last-update");
204 let timeElement = element.querySelector(".time"); 210 if (lastUpdateElement)
205 if (dateElement && timeElement)
206 { 211 {
207 let message = element.querySelector(".message"); 212 let message = element.querySelector(".message");
208 if (item.isDownloading) 213 if (item.isDownloading)
209 { 214 {
210 let text = getMessage("options_filterList_lastDownload_inProgress"); 215 let text = getMessage("options_filterList_lastDownload_inProgress");
211 message.textContent = text; 216 message.textContent = text;
212 element.classList.add("show-message"); 217 element.classList.add("show-message");
213 } 218 }
214 else if (item.downloadStatus != "synchronize_ok") 219 else if (item.downloadStatus != "synchronize_ok")
215 { 220 {
216 let error = filterErrors.get(item.downloadStatus); 221 let error = filterErrors.get(item.downloadStatus);
217 if (error) 222 if (error)
218 message.textContent = getMessage(error); 223 message.textContent = getMessage(error);
219 else 224 else
220 message.textContent = item.downloadStatus; 225 message.textContent = item.downloadStatus;
221 element.classList.add("show-message"); 226 element.classList.add("show-message");
222 } 227 }
223 else if (item.lastDownload > 0) 228 else if (item.lastDownload > 0)
224 { 229 {
225 let dateTime = i18nFormatDateTime(item.lastDownload * 1000); 230 let lastUpdate = item.lastDownload * 1000;
226 dateElement.textContent = dateTime[0]; 231 let lastUpdateLive = function()
227 timeElement.textContent = dateTime[1]; 232 {
233 let sinceUpdate = Date.now() - lastUpdate;
234 if (sinceUpdate > fullDayInMs)
235 {
236 let lastUpdateDate = new Date(item.lastDownload * 1000);
237 let monthName = lastUpdateDate.toLocaleString(undefined,
238 {month: "short"});
239 let day = lastUpdateDate.getDate();
240 day = day < 10 ? "0" + day : day;
241 lastUpdateElement.textContent = day + " " + monthName + " " +
242 lastUpdateDate.getFullYear();
243 }
244 else if (sinceUpdate > hourInMs)
245 {
246 let placeholder = [Math.round(sinceUpdate / hourInMs)];
247 lastUpdateElement.textContent =
248 getMessage("options_filterList_hours", placeholder);
Thomas Greiner 2017/07/14 12:26:12 This placeholder isn't defined in new-options.json
saroyanm 2017/07/14 16:17:24 Well spotted, will remove it.
saroyanm 2017/07/14 17:11:06 Done.
249 }
250 else if (sinceUpdate > minuteInMs)
251 {
252 let placeholder = [Math.round(sinceUpdate / minuteInMs)];
253 lastUpdateElement.textContent =
254 getMessage("options_filterList_minutes", placeholder);
255 }
256 else
257 {
258 lastUpdateElement.textContent =
259 getMessage("options_filterList_now");
260 }
261 };
262 lastUpdateLive();
228 element.classList.remove("show-message"); 263 element.classList.remove("show-message");
229 } 264 }
230 } 265 }
231 266
232 let websiteElement = element.querySelector(".context-menu .website"); 267 let websiteElement = element.querySelector(".context-menu .website");
233 if (websiteElement) 268 if (websiteElement)
234 { 269 {
235 if (item.homepage) 270 if (item.homepage)
236 websiteElement.setAttribute("href", item.homepage); 271 websiteElement.setAttribute("href", item.homepage);
237 else 272 else
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
308 { 343 {
309 id: "custom-list-table" 344 id: "custom-list-table"
310 } 345 }
311 ]); 346 ]);
312 collections.whitelist = new Collection([ 347 collections.whitelist = new Collection([
313 { 348 {
314 id: "whitelisting-table", 349 id: "whitelisting-table",
315 emptyText: "options_whitelisted_empty" 350 emptyText: "options_whitelisted_empty"
316 } 351 }
317 ]); 352 ]);
318 collections.customFilters = new Collection([
319 {
320 id: "custom-filters-table",
321 emptyText: "options_customFilters_empty"
322 }
323 ]);
324 collections.filterLists = new Collection([ 353 collections.filterLists = new Collection([
325 { 354 {
326 id: "all-filter-lists-table", 355 id: "all-filter-lists-table",
327 useOriginalTitle: true 356 useOriginalTitle: true
328 } 357 }
329 ]); 358 ]);
330 359
331 function toggleShowLanguage(subscription) 360 function toggleShowLanguage(subscription)
332 { 361 {
333 if (subscription.recommended == "ads") 362 if (subscription.recommended == "ads")
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
371 function updateSubscription(subscription) 400 function updateSubscription(subscription)
372 { 401 {
373 for (let name in collections) 402 for (let name in collections)
374 collections[name].updateItem(subscription); 403 collections[name].updateItem(subscription);
375 404
376 toggleShowLanguage(subscription); 405 toggleShowLanguage(subscription);
377 } 406 }
378 407
379 function updateFilter(filter) 408 function updateFilter(filter)
380 { 409 {
381 let match = filter.text.match(/^@@\|\|([^/:]+)\^\$document$/); 410 let match = filter.text.match(whitelistedDomainRegexp);
382 if (match && !filtersMap[filter.text]) 411 if (match && !filtersMap[filter.text])
383 { 412 {
384 filter.title = match[1]; 413 filter.title = match[1];
385 collections.whitelist.addItem(filter); 414 collections.whitelist.addItem(filter);
386 } 415 }
387 else 416 else
388 collections.customFilters.addItem(filter); 417 {
418 customFiltersArray.push(filter.text);
419 if (isCustomFiltersLoaded)
Thomas Greiner 2017/07/14 12:26:12 Detail: What is this check for? It seems that `upd
saroyanm 2017/07/14 16:17:25 Shouldn't we wait only for the time when all filte
Thomas Greiner 2017/07/14 16:37:42 Right, I remember and I see that this has actually
saroyanm 2017/07/14 16:41:34 I agree, I'll create a separate issue for that, wh
420 updateCustomFiltersUi();
421 }
389 422
390 filtersMap[filter.text] = filter; 423 filtersMap[filter.text] = filter;
391 } 424 }
392 425
426 function removeCustomFilter(text)
427 {
428 let index = customFiltersArray.indexOf(text);
429 if (index >= 0)
430 customFiltersArray.splice(index, 1);
Thomas Greiner 2017/07/14 12:26:12 What if there are multiple instances of the same f
saroyanm 2017/07/14 16:17:25 There shouldn't be multiple instances of same filt
Thomas Greiner 2017/07/14 16:37:42 My thinking was that a pre-existing filter could a
saroyanm 2017/07/14 16:41:34 Acknowledged.
431
432 updateCustomFiltersUi();
433 }
434
435 function updateCustomFiltersUi()
436 {
437 let customFiltersListElement = E("custom-filters-raw");
438 customFiltersListElement.value = "";
Thomas Greiner 2017/07/14 12:26:12 Detail: This is redundant because the line below w
saroyanm 2017/07/14 16:17:24 Thanks for noticing. Will update.
saroyanm 2017/07/14 17:11:06 Done.
439 customFiltersListElement.value = customFiltersArray.join("\n");
440 }
441
393 function loadRecommendations() 442 function loadRecommendations()
394 { 443 {
395 fetch("subscriptions.xml") 444 fetch("subscriptions.xml")
396 .then((response) => 445 .then((response) =>
397 { 446 {
398 return response.text(); 447 return response.text();
399 }) 448 })
400 .then((text) => 449 .then((text) =>
401 { 450 {
402 let doc = new DOMParser().parseFromString(text, "application/xml"); 451 let doc = new DOMParser().parseFromString(text, "application/xml");
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
467 else 516 else
468 location.href = link; 517 location.href = link;
469 }); 518 });
470 } 519 }
471 520
472 function switchTab(id) 521 function switchTab(id)
473 { 522 {
474 location.hash = id; 523 location.hash = id;
475 } 524 }
476 525
477 function execAction(action, element) 526 function execAction(action, element, event)
478 { 527 {
479 switch (action) 528 switch (action)
480 { 529 {
481 case "add-domain-exception": 530 case "add-domain-exception":
482 addWhitelistedDomain(); 531 addWhitelistedDomain();
483 break; 532 break;
484 case "add-language-subscription": 533 case "add-language-subscription":
485 addEnableSubscription(findParentData(element, "access", false)); 534 addEnableSubscription(findParentData(element, "access", false));
486 break; 535 break;
487 case "add-predefined-subscription": { 536 case "add-predefined-subscription": {
488 let dialog = E("dialog-content-predefined"); 537 let dialog = E("dialog-content-predefined");
489 let title = dialog.querySelector("h3").textContent; 538 let title = dialog.querySelector("h3").textContent;
490 let url = dialog.querySelector(".url").textContent; 539 let url = dialog.querySelector(".url").textContent;
491 addEnableSubscription(url, title); 540 addEnableSubscription(url, title);
492 closeDialog(); 541 closeDialog();
493 break; 542 break;
494 } 543 }
495 case "cancel-custom-filters": 544 case "cancel-custom-filters":
496 E("custom-filters").classList.remove("mode-edit"); 545 updateCustomFiltersUi();
546 setCustomFiltersView("read");
497 break; 547 break;
498 case "cancel-domain-exception": 548 case "cancel-domain-exception":
499 E("whitelisting-textbox").value = ""; 549 E("whitelisting-textbox").value = "";
500 document.querySelector("#whitelisting .controls").classList 550 document.querySelector("#whitelisting .controls").classList
501 .remove("mode-edit"); 551 .remove("mode-edit");
502 break; 552 break;
503 case "close-dialog": 553 case "close-dialog":
504 closeDialog(); 554 closeDialog();
505 break; 555 break;
506 case "edit-custom-filters": 556 case "edit-custom-filters":
507 editCustomFilters(); 557 setCustomFiltersView("write");
508 break; 558 break;
509 case "edit-domain-exception": 559 case "edit-domain-exception":
510 document.querySelector("#whitelisting .controls").classList 560 document.querySelector("#whitelisting .controls").classList
511 .add("mode-edit"); 561 .add("mode-edit");
512 E("whitelisting-textbox").focus(); 562 E("whitelisting-textbox").focus();
513 break; 563 break;
514 case "import-subscription": { 564 case "import-subscription": {
515 let url = E("blockingList-textbox").value; 565 let url = E("blockingList-textbox").value;
516 addEnableSubscription(url); 566 addEnableSubscription(url);
517 closeDialog(); 567 closeDialog();
(...skipping 28 matching lines...) Expand all
546 }); 596 });
547 break; 597 break;
548 case "save-custom-filters": 598 case "save-custom-filters":
549 sendMessageHandleErrors({ 599 sendMessageHandleErrors({
550 type: "filters.importRaw", 600 type: "filters.importRaw",
551 text: E("custom-filters-raw").value, 601 text: E("custom-filters-raw").value,
552 removeExisting: true 602 removeExisting: true
553 }, 603 },
554 () => 604 () =>
555 { 605 {
556 E("custom-filters").classList.remove("mode-edit"); 606 setCustomFiltersView("read");
557 }); 607 });
558 break; 608 break;
559 case "switch-tab": 609 case "switch-tab":
560 let tabId = findParentData(element, "tab", false); 610 let tabId = findParentData(element, "tab", false);
561 switchTab(tabId); 611 switchTab(tabId);
562 break; 612 break;
563 case "toggle-disable-subscription": 613 case "toggle-disable-subscription":
564 ext.backgroundPage.sendMessage({ 614 ext.backgroundPage.sendMessage({
565 type: "subscriptions.toggle", 615 type: "subscriptions.toggle",
566 keepInstalled: true, 616 keepInstalled: true,
(...skipping 25 matching lines...) Expand all
592 break; 642 break;
593 case "update-subscription": 643 case "update-subscription":
594 ext.backgroundPage.sendMessage({ 644 ext.backgroundPage.sendMessage({
595 type: "subscriptions.update", 645 type: "subscriptions.update",
596 url: findParentData(element, "access", false) 646 url: findParentData(element, "access", false)
597 }); 647 });
598 break; 648 break;
599 } 649 }
600 } 650 }
601 651
652 function setCustomFiltersView(mode)
653 {
654 let customFilters = E("custom-filters");
655 let customFiltersListElement = E("custom-filters-raw");
656 if (mode == "read")
657 {
658 customFiltersListElement.disabled = true;
659 if (!customFiltersListElement.value)
660 {
661 setCustomFiltersView("empty");
662 return;
663 }
664 }
665 else if (mode == "write")
666 {
667 updateCustomFiltersUi();
Thomas Greiner 2017/07/14 12:26:13 Interesting that you're calling `updateCustomFilte
saroyanm 2017/07/14 16:17:25 You are right, I'm not sure why I did this.. I'll
saroyanm 2017/07/14 17:11:06 Done.
668 customFiltersListElement.disabled = false;
669 }
670
671 customFilters.dataset.mode = mode;
672 }
673
602 function onClick(e) 674 function onClick(e)
603 { 675 {
604 let context = document.querySelector(".show-context-menu"); 676 let context = document.querySelector(".show-context-menu");
605 if (context) 677 if (context)
606 context.classList.remove("show-context-menu"); 678 context.classList.remove("show-context-menu");
607 679
608 let actions = findParentData(e.target, "action", false); 680 let actions = findParentData(e.target, "action", false);
609 if (!actions) 681 if (!actions)
610 return; 682 return;
611 683
612 actions = actions.split(","); 684 actions = actions.split(",");
613 for (let action of actions) 685 for (let action of actions)
614 { 686 {
615 execAction(action, e.target); 687 execAction(action, e.target, e);
616 } 688 }
617 } 689 }
618 690
619 function getKey(e) 691 function getKey(e)
620 { 692 {
621 // e.keyCode has been deprecated so we attempt to use e.key 693 // e.keyCode has been deprecated so we attempt to use e.key
622 if ("key" in e) 694 if ("key" in e)
623 return e.key; 695 return e.key;
624 return getKey.keys[e.keyCode]; 696 return getKey.keys[e.keyCode];
625 } 697 }
(...skipping 26 matching lines...) Expand all
652 { 724 {
653 if (key == "ArrowLeft" || key == "ArrowUp") 725 if (key == "ArrowLeft" || key == "ArrowUp")
654 element = element.previousElementSibling || container.lastElementChild; 726 element = element.previousElementSibling || container.lastElementChild;
655 else if (key == "ArrowRight" || key == "ArrowDown") 727 else if (key == "ArrowRight" || key == "ArrowDown")
656 element = element.nextElementSibling || container.firstElementChild; 728 element = element.nextElementSibling || container.firstElementChild;
657 } 729 }
658 730
659 let actions = container.getAttribute("data-action").split(","); 731 let actions = container.getAttribute("data-action").split(",");
660 for (let action of actions) 732 for (let action of actions)
661 { 733 {
662 execAction(action, element); 734 execAction(action, element, e);
663 } 735 }
664 } 736 }
665 737
666 function selectTabItem(tabId, container, focus) 738 function selectTabItem(tabId, container, focus)
667 { 739 {
668 // Show tab content 740 // Show tab content
669 document.body.setAttribute("data-tab", tabId); 741 document.body.setAttribute("data-tab", tabId);
670 742
671 // Select tab 743 // Select tab
672 let tabList = container.querySelector("[role='tablist']"); 744 let tabList = container.querySelector("[role='tablist']");
673 if (!tabList) 745 if (!tabList)
674 return null; 746 return null;
675 747
676 let previousTab = tabList.querySelector("[aria-selected]"); 748 let previousTab = tabList.querySelector("[aria-selected]");
677 previousTab.removeAttribute("aria-selected"); 749 previousTab.removeAttribute("aria-selected");
678 previousTab.setAttribute("tabindex", -1); 750 previousTab.setAttribute("tabindex", -1);
679 751
680 let tab = tabList.querySelector("li[data-tab='" + tabId + "']"); 752 let tab = tabList.querySelector("li[data-tab='" + tabId + "']");
681 tab.setAttribute("aria-selected", true); 753 tab.setAttribute("aria-selected", true);
682 tab.setAttribute("tabindex", 0); 754 tab.setAttribute("tabindex", 0);
683 755
684 let tabContentId = tab.getAttribute("aria-controls"); 756 let tabContentId = tab.getAttribute("aria-controls");
685 let tabContent = document.getElementById(tabContentId); 757 let tabContent = document.getElementById(tabContentId);
686 758
687 // Select sub tabs
688 if (tab.hasAttribute("data-subtab"))
689 selectTabItem(tab.getAttribute("data-subtab"), tabContent, false);
690
691 if (tab && focus) 759 if (tab && focus)
692 tab.focus(); 760 tab.focus();
693 761
694 return tabContent; 762 return tabContent;
695 } 763 }
696 764
697 function onHashChange() 765 function onHashChange()
698 { 766 {
699 let hash = location.hash.substr(1); 767 let hash = location.hash.substr(1);
700 if (!hash) 768 if (!hash)
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
750 let placeholderValue = getMessage("options_dialog_language_find"); 818 let placeholderValue = getMessage("options_dialog_language_find");
751 E("find-language").setAttribute("placeholder", placeholderValue); 819 E("find-language").setAttribute("placeholder", placeholderValue);
752 E("find-language").addEventListener("keyup", onFindLanguageKeyUp, false); 820 E("find-language").addEventListener("keyup", onFindLanguageKeyUp, false);
753 E("whitelisting-textbox").addEventListener("keypress", (e) => 821 E("whitelisting-textbox").addEventListener("keypress", (e) =>
754 { 822 {
755 if (getKey(e) == "Enter") 823 if (getKey(e) == "Enter")
756 addWhitelistedDomain(); 824 addWhitelistedDomain();
757 }, false); 825 }, false);
758 826
759 // Advanced tab 827 // Advanced tab
760 let tweaks = document.querySelectorAll("#tweaks li[data-pref]"); 828 let customize = document.querySelectorAll("#customize li[data-pref]");
761 tweaks = Array.prototype.map.call(tweaks, (checkbox) => 829 customize = Array.prototype.map.call(customize, (checkbox) =>
762 { 830 {
763 return checkbox.getAttribute("data-pref"); 831 return checkbox.getAttribute("data-pref");
764 }); 832 });
765 for (let key of tweaks) 833 for (let key of customize)
766 { 834 {
767 getPref(key, (value) => 835 getPref(key, (value) =>
768 { 836 {
769 onPrefMessage(key, value, true); 837 onPrefMessage(key, value, true);
770 }); 838 });
771 } 839 }
772 ext.backgroundPage.sendMessage({ 840 ext.backgroundPage.sendMessage({
773 type: "app.get", 841 type: "app.get",
774 what: "features" 842 what: "features"
775 }, 843 },
776 (features) => 844 (features) =>
777 { 845 {
778 hidePref("show_devtools_panel", !features.devToolsPanel); 846 hidePref("show_devtools_panel", !features.devToolsPanel);
779 }); 847 });
780 848
781 let filterTextbox = document.querySelector("#custom-filters-add input"); 849 getDocLink("filterdoc", (link) =>
782 placeholderValue = getMessage("options_customFilters_textbox_placeholder");
783 filterTextbox.setAttribute("placeholder", placeholderValue);
784 function addCustomFilters()
785 { 850 {
786 let filterText = filterTextbox.value; 851 E("link-filters").setAttribute("href", link);
787 sendMessageHandleErrors({ 852 });
788 type: "filters.add", 853
789 text: filterText 854 getDocLink("subscriptions", (link) =>
790 },
791 () =>
792 {
793 filterTextbox.value = "";
794 });
795 }
796 E("custom-filters-add").addEventListener("submit", (e) =>
797 { 855 {
798 e.preventDefault(); 856 setLinks("filter-lists-description", link);
799 addCustomFilters(); 857 });
800 }, false); 858
859 E("custom-filters-raw").setAttribute("placeholder",
860 getMessage("options_customFilters_edit_placeholder", ["/ads/track/*"]));
801 861
802 // Help tab 862 // Help tab
803 getDocLink("faq", (link) => 863 getDocLink("faq", (link) =>
804 { 864 {
805 E("link-faq").setAttribute("href", link); 865 E("link-faq").setAttribute("href", link);
806 }); 866 });
807 getDocLink("social_twitter", (link) => 867 getDocLink("social_twitter", (link) =>
808 { 868 {
809 E("link-twitter").setAttribute("href", link); 869 E("link-twitter").setAttribute("href", link);
810 }); 870 });
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after
923 ext.backgroundPage.sendMessage({ 983 ext.backgroundPage.sendMessage({
924 type: "filters.get", 984 type: "filters.get",
925 subscriptionUrl: subscription.url 985 subscriptionUrl: subscription.url
926 }, 986 },
927 (filters) => 987 (filters) =>
928 { 988 {
929 for (let filter of filters) 989 for (let filter of filters)
930 updateFilter(filter); 990 updateFilter(filter);
931 991
932 isCustomFiltersLoaded = true; 992 isCustomFiltersLoaded = true;
993 updateCustomFiltersUi();
994 setCustomFiltersView("read");
933 }); 995 });
934 } 996 }
935 }); 997 });
936 loadRecommendations(); 998 loadRecommendations();
937 ext.backgroundPage.sendMessage({ 999 ext.backgroundPage.sendMessage({
938 type: "prefs.get", 1000 type: "prefs.get",
939 key: "subscriptions_exceptionsurl" 1001 key: "subscriptions_exceptionsurl"
940 }, 1002 },
941 (url) => 1003 (url) =>
942 { 1004 {
(...skipping 25 matching lines...) Expand all
968 type: "filters.add", 1030 type: "filters.add",
969 text: "@@||" + domain.value.toLowerCase() + "^$document" 1031 text: "@@||" + domain.value.toLowerCase() + "^$document"
970 }); 1032 });
971 } 1033 }
972 1034
973 domain.value = ""; 1035 domain.value = "";
974 document.querySelector("#whitelisting .controls") 1036 document.querySelector("#whitelisting .controls")
975 .classList.remove("mode-edit"); 1037 .classList.remove("mode-edit");
976 } 1038 }
977 1039
978 function editCustomFilters()
979 {
980 if (!isCustomFiltersLoaded)
981 {
982 console.error("Custom filters are not loaded");
983 return;
984 }
985
986 E("custom-filters").classList.add("mode-edit");
987 let filterTexts = [];
988 for (let customFilterItem of collections.customFilters.items)
989 filterTexts.push(customFilterItem.text);
990 E("custom-filters-raw").value = filterTexts.join("\n");
991 }
992
993 function addEnableSubscription(url, title, homepage) 1040 function addEnableSubscription(url, title, homepage)
994 { 1041 {
995 let messageType = null; 1042 let messageType = null;
996 let knownSubscription = subscriptionsMap[url]; 1043 let knownSubscription = subscriptionsMap[url];
997 if (knownSubscription && knownSubscription.disabled == true) 1044 if (knownSubscription && knownSubscription.disabled == true)
998 messageType = "subscriptions.toggle"; 1045 messageType = "subscriptions.toggle";
999 else 1046 else
1000 messageType = "subscriptions.add"; 1047 messageType = "subscriptions.add";
1001 1048
1002 let message = { 1049 let message = {
(...skipping 14 matching lines...) Expand all
1017 { 1064 {
1018 case "added": 1065 case "added":
1019 updateFilter(filter); 1066 updateFilter(filter);
1020 updateShareLink(); 1067 updateShareLink();
1021 break; 1068 break;
1022 case "loaded": 1069 case "loaded":
1023 populateLists(); 1070 populateLists();
1024 break; 1071 break;
1025 case "removed": 1072 case "removed":
1026 let knownFilter = filtersMap[filter.text]; 1073 let knownFilter = filtersMap[filter.text];
1027 collections.whitelist.removeItem(knownFilter); 1074 if (whitelistedDomainRegexp.test(knownFilter.text))
1028 collections.customFilters.removeItem(knownFilter); 1075 collections.whitelist.removeItem(knownFilter);
1076 else
1077 removeCustomFilter(filter.text);
1078
1029 delete filtersMap[filter.text]; 1079 delete filtersMap[filter.text];
1030 updateShareLink(); 1080 updateShareLink();
1031 break; 1081 break;
1032 } 1082 }
1033 } 1083 }
1034 1084
1035 function onSubscriptionMessage(action, subscription) 1085 function onSubscriptionMessage(action, subscription)
1036 { 1086 {
1037 if (subscription.url in subscriptionsMap) 1087 if (subscription.url in subscriptionsMap)
1038 { 1088 {
(...skipping 250 matching lines...) Expand 10 before | Expand all | Expand 10 after
1289 }); 1339 });
1290 ext.backgroundPage.sendMessage({ 1340 ext.backgroundPage.sendMessage({
1291 type: "subscriptions.listen", 1341 type: "subscriptions.listen",
1292 filter: ["added", "disabled", "homepage", "lastDownload", "removed", 1342 filter: ["added", "disabled", "homepage", "lastDownload", "removed",
1293 "title", "downloadStatus", "downloading"] 1343 "title", "downloadStatus", "downloading"]
1294 }); 1344 });
1295 1345
1296 window.addEventListener("DOMContentLoaded", onDOMLoaded, false); 1346 window.addEventListener("DOMContentLoaded", onDOMLoaded, false);
1297 window.addEventListener("hashchange", onHashChange, false); 1347 window.addEventListener("hashchange", onHashChange, false);
1298 } 1348 }
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