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

Delta Between Two Patch Sets: options.js

Issue 29321198: Issue 2376 - Implement custom filters in new options page (Closed)
Left Patch Set: Created June 29, 2015, 11:21 a.m.
Right Patch Set: Nit fixes Created July 15, 2015, 2:35 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 | « options.html ('k') | skin/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-2015 Eyeo GmbH 3 * Copyright (C) 2006-2015 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 18 matching lines...) Expand all
29 this.details = details; 29 this.details = details;
30 this.items = []; 30 this.items = [];
31 } 31 }
32 32
33 Collection.prototype.addItems = function() 33 Collection.prototype.addItems = function()
34 { 34 {
35 var length = Array.prototype.push.apply(this.items, arguments); 35 var length = Array.prototype.push.apply(this.items, arguments);
36 if (length == 0) 36 if (length == 0)
37 return; 37 return;
38 38
39 this.items.sort(function(a, b) 39 this.items.sort(function(a, b)
Thomas Greiner 2015/06/30 09:23:29 You need to first filter out all empty lines befor
saroyanm 2015/07/08 18:25:42 I do wander why we even need to submit the empty s
Thomas Greiner 2015/07/09 11:07:54 Yep, the earlier we can filter those out the bette
saroyanm 2015/07/09 16:31:39 Done.
40 { 40 {
41 var aValue = (a.title || a.text || a.url).toLowerCase(); 41 var aValue = (a.title || a.text || a.url).toLowerCase();
42 var bValue = (b.title || b.text || a.url).toLowerCase(); 42 var bValue = (b.title || b.text || b.url).toLowerCase();
Thomas Greiner 2015/06/30 09:23:27 Be careful: It's `b.url`, not `a.url`
saroyanm 2015/07/08 18:25:41 Done.
43 return aValue.localeCompare(bValue); 43 return aValue.localeCompare(bValue);
44 }); 44 });
45 45
46 for (var j = 0; j < this.details.length; j++) 46 for (var j = 0; j < this.details.length; j++)
47 { 47 {
48 var table = E(this.details[j].id); 48 var table = E(this.details[j].id);
49 var template = table.querySelector("template"); 49 var template = table.querySelector("template");
50 for (var i = 0; i < arguments.length; i++) 50 for (var i = 0; i < arguments.length; i++)
51 { 51 {
52 var item = arguments[i]; 52 var item = arguments[i];
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
100 table.appendChild(template); 100 table.appendChild(template);
101 } 101 }
102 this.items.length = 0; 102 this.items.length = 0;
103 }; 103 };
104 104
105 function onToggleSubscriptionClick(e) 105 function onToggleSubscriptionClick(e)
106 { 106 {
107 e.preventDefault(); 107 e.preventDefault();
108 var subscriptionUrl = e.target.parentNode.dataset.access; 108 var subscriptionUrl = e.target.parentNode.dataset.access;
109 if (!e.target.checked) 109 if (!e.target.checked)
110 removeSubscription(subscriptionUrl); 110 {
111 ext.backgroundPage.sendMessage(
112 {
113 type: "subscriptions.remove",
114 url: subscriptionUrl
115 });
116 }
111 else 117 else
112 addEnableSubscription(subscriptionUrl); 118 addEnableSubscription(subscriptionUrl);
113 } 119 }
114 120
115 function onAddLanguageSubscriptionClick(e) 121 function onAddLanguageSubscriptionClick(e)
116 { 122 {
117 e.preventDefault(); 123 e.preventDefault();
118 var url = this.parentNode.dataset.access; 124 var url = this.parentNode.dataset.access;
119 addEnableSubscription(url); 125 addEnableSubscription(url);
120 } 126 }
121 127
122 function onRemoveFilterClick() 128 function onRemoveFilterClick()
123 { 129 {
124 var filter = this.parentNode.dataset.access; 130 var filter = this.parentNode.dataset.access;
125 removeFilter(filter); 131 ext.backgroundPage.sendMessage(
132 {
133 type: "filters.remove",
134 text: filter
135 });
126 } 136 }
127 137
128 collections.popular = new Collection( 138 collections.popular = new Collection(
129 [ 139 [
130 { 140 {
131 id: "recommend-list-table", 141 id: "recommend-list-table",
132 onClick: onToggleSubscriptionClick 142 onClick: onToggleSubscriptionClick
133 } 143 }
134 ]); 144 ]);
135 collections.langs = new Collection( 145 collections.langs = new Collection(
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after
265 } 275 }
266 } 276 }
267 277
268 function updateFilter(filter) 278 function updateFilter(filter)
269 { 279 {
270 var match = filter.text.match(/^@@\|\|([^\/:]+)\^\$document$/); 280 var match = filter.text.match(/^@@\|\|([^\/:]+)\^\$document$/);
271 if (match && !filtersMap[filter.text]) 281 if (match && !filtersMap[filter.text])
272 { 282 {
273 filter.title = match[1]; 283 filter.title = match[1];
274 collections.whitelist.addItems(filter); 284 collections.whitelist.addItems(filter);
275 filtersMap[filter.text] = filter;
276 } 285 }
277 else 286 else
278 {
279 // TODO: add `filters[i].text` to list of custom filters
Thomas Greiner 2015/06/30 09:23:28 Remove this comment
saroyanm 2015/07/08 18:25:42 Done.
280 collections.customFilters.addItems(filter); 287 collections.customFilters.addItems(filter);
281 filtersMap[filter.text] = filter; 288
Thomas Greiner 2015/06/30 09:23:28 This line is shared across both branches of the if
saroyanm 2015/07/08 18:25:41 Done.
282 } 289 filtersMap[filter.text] = filter;
283 } 290 }
284 291
285 function loadRecommendations() 292 function loadRecommendations()
286 { 293 {
287 var request = new XMLHttpRequest(); 294 var request = new XMLHttpRequest();
288 request.open("GET", "subscriptions.xml", false); 295 request.open("GET", "subscriptions.xml", false);
289 request.addEventListener("load", function() 296 request.addEventListener("load", function()
290 { 297 {
291 var list = document.getElementById("subscriptionSelector"); 298 var list = document.getElementById("subscriptionSelector");
292 var docElem = request.responseXML.documentElement; 299 var docElem = request.responseXML.documentElement;
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
326 333
327 function onDOMLoaded() 334 function onDOMLoaded()
328 { 335 {
329 var recommendationTemplate = document.querySelector("#recommend-list-table t emplate"); 336 var recommendationTemplate = document.querySelector("#recommend-list-table t emplate");
330 var popularText = ext.i18n.getMessage("options_popular"); 337 var popularText = ext.i18n.getMessage("options_popular");
331 recommendationTemplate.content.querySelector(".popular").textContent = popul arText; 338 recommendationTemplate.content.querySelector(".popular").textContent = popul arText;
332 var languagesTemplate = document.querySelector("#all-lang-table template"); 339 var languagesTemplate = document.querySelector("#all-lang-table template");
333 var buttonText = ext.i18n.getMessage("options_button_add"); 340 var buttonText = ext.i18n.getMessage("options_button_add");
334 languagesTemplate.content.querySelector(".button-add span").textContent = bu ttonText; 341 languagesTemplate.content.querySelector(".button-add span").textContent = bu ttonText;
335 342
336 updateShareLink();
337 populateLists(); 343 populateLists();
338 344
339 var tabList = document.querySelectorAll("#main-navigation-tabs li"); 345 var tabList = document.querySelectorAll("#main-navigation-tabs li");
340 for (var i = 0; i < tabList.length; i++) 346 for (var i = 0; i < tabList.length; i++)
341 { 347 {
342 tabList[i].addEventListener("click", function(e) 348 tabList[i].addEventListener("click", function(e)
343 { 349 {
344 document.body.dataset.tab = e.currentTarget.dataset.show; 350 document.body.dataset.tab = e.currentTarget.dataset.show;
345 }, false); 351 }, false);
346 } 352 }
347 353
348 function onFindLanguageKeyUp() 354 function onFindLanguageKeyUp()
349 { 355 {
350 var searchStyle = E("search-style"); 356 var searchStyle = E("search-style");
351 if (!this.value) 357 if (!this.value)
352 searchStyle.innerHTML = ""; 358 searchStyle.innerHTML = "";
353 else 359 else
354 searchStyle.innerHTML = "#all-lang-table li:not([data-search*=\"" + this .value.toLowerCase() + "\"]) { display: none; }"; 360 searchStyle.innerHTML = "#all-lang-table li:not([data-search*=\"" + this .value.toLowerCase() + "\"]) { display: none; }";
355 } 361 }
356 362
357 function isEnterPressed(e) 363 function isEnterPressed(e)
358 { 364 {
359 // e.keyCode has been deprecated so we attempt to use e.key 365 // e.keyCode has been deprecated so we attempt to use e.key
360 // keyCode "13" corresponds to "Enter" 366 if ("key" in e)
361 if ((e.key && e.key == "Enter") || (!e.key && e.keyCode == 13)) 367 return e.key == "Enter";
362 return true; 368 return e.keyCode == 13; // keyCode "13" corresponds to "Enter"
363 return false; 369 }
Thomas Greiner 2015/06/30 09:23:28 Detail: You could reduce that to one line: return
saroyanm 2015/07/08 18:25:41 Done. Please note that this function most probably
364 } 370
365 371 // Initialize navigation sidebar
366 // Update version number in navigation sidebar
367 ext.backgroundPage.sendMessage( 372 ext.backgroundPage.sendMessage(
368 { 373 {
369 method: "app.get", 374 type: "app.get",
370 what: "addonVersion" 375 what: "addonVersion"
371 }, 376 },
372 function(addonVersion) 377 function(addonVersion)
373 { 378 {
374 E("abp-version").textContent = addonVersion; 379 E("abp-version").textContent = addonVersion;
375 }); 380 });
376 381 getDocLink("releases", function(link)
382 {
383 E("link-version").setAttribute("href", link);
384 });
385
386 getDocLink("contribute", function(link)
387 {
388 document.querySelector("#tab-contribute a").setAttribute("href", link);
389 });
390
391 updateShareLink();
392
393 // Initialize interactive UI elements
377 var placeholderValue = ext.i18n.getMessage("options_dialog_language_find"); 394 var placeholderValue = ext.i18n.getMessage("options_dialog_language_find");
378 E("find-language").setAttribute("placeholder", placeholderValue); 395 E("find-language").setAttribute("placeholder", placeholderValue);
379 E("add-blocking-list").addEventListener("click", function() 396 E("add-blocking-list").addEventListener("click", function()
380 { 397 {
381 openDialog("customlist"); 398 openDialog("customlist");
382 }, false); 399 }, false);
383 E("add-website-language").addEventListener("click", function() 400 E("add-website-language").addEventListener("click", function()
384 { 401 {
385 openDialog("language"); 402 openDialog("language");
386 }, false); 403 }, false);
(...skipping 18 matching lines...) Expand all
405 addWhitelistedDomain(); 422 addWhitelistedDomain();
406 }, false); 423 }, false);
407 E("import-blockingList-button").addEventListener("click", function() 424 E("import-blockingList-button").addEventListener("click", function()
408 { 425 {
409 var url = E("blockingList-textbox").value; 426 var url = E("blockingList-textbox").value;
410 addEnableSubscription(url); 427 addEnableSubscription(url);
411 delete document.body.dataset.dialog; 428 delete document.body.dataset.dialog;
412 }, false); 429 }, false);
413 430
414 // Advanced tab 431 // Advanced tab
415 E("custom-filters-add-textbox").setAttribute("placeholder", ext.i18n.getMess age("options_customFilters_textbox_placeholder")); 432 var filterTextbox = document.querySelector("#custom-filters-add input");
Thomas Greiner 2015/06/30 09:23:28 Split this up into two lines to avoid exceeding th
saroyanm 2015/07/08 18:25:41 Done.
416 function addCustomFilter() 433 placeholderValue = ext.i18n.getMessage("options_customFilters_textbox_placeh older");
Thomas Greiner 2015/06/30 09:23:28 "addCustomFilters" please
saroyanm 2015/07/08 18:25:41 Done.
417 { 434 filterTextbox.setAttribute("placeholder", placeholderValue);
418 var filterTextbox = E("custom-filters-add-textbox"); 435 function addCustomFilters()
436 {
437 var filterText = filterTextbox.value;
419 ext.backgroundPage.sendMessage( 438 ext.backgroundPage.sendMessage(
420 { 439 {
421 type: "parse.filter", 440 type: "filters.add",
422 text: filterTextbox.value 441 text: filterText
423 },
424 function(result)
425 {
426 if (result.error)
427 {
428 alert(result.error);
429 return;
430 }
431 if (result.filter)
432 addFilter(result.filter.text);
433
434 filterTextbox.value = "";
435 }); 442 });
436 } 443 filterTextbox.value = "";
437 E("custom-filters-add-btn").addEventListener("click", addCustomFilter, false ); 444 }
438 E("custom-filters-add-textbox").addEventListener("keypress", function(e) 445 E("custom-filters-add").addEventListener("submit", function(e)
439 { 446 {
440 if (isEnterPressed(e)) 447 e.preventDefault();
441 addCustomFilter(); 448 addCustomFilters();
442 }, false); 449 }, false);
443 var customFilterEditButtons = document.querySelectorAll("#custom-filters-edi t-wrapper button"); 450 var customFilterEditButtons = document.querySelectorAll("#custom-filters-edi t-wrapper button");
Thomas Greiner 2015/06/30 09:23:28 Please avoid setting event listeners individually
saroyanm 2015/07/08 18:25:40 Done.
444 for (var i = 0; i < customFilterEditButtons.length; i++) 451 E("custom-filters-edit-wrapper").addEventListener("click", function(e)
445 { 452 {
446 customFilterEditButtons[i].addEventListener("click", function(e) 453 var target = null;
447 { 454 if (e.target.localName == "button")
448 E("custom-filters").dataset.view = e.currentTarget.dataset.show; 455 target = e.target;
Thomas Greiner 2015/06/30 09:23:28 This can be achieved more performantly by toggling
saroyanm 2015/07/08 18:25:41 Done.
449 var id = e.currentTarget.id; 456 else if (e.target.parentElement.localName == "button")
450 if (id == "custom-filters-edit-btn") 457 target = e.target.parentElement;
451 editCustomFilters(); 458 else
452 else if (id == "custom-filters-save-btn") 459 return;
453 { 460
454 ext.backgroundPage.sendMessage( 461 var id = target.id;
455 { 462 E("custom-filters").classList.toggle("mode-edit");
456 type: "filters.importRaw", 463 if (id == "custom-filters-show-edit")
457 text: E("custom-filters-textarea").value 464 editCustomFilters();
458 }); 465 else if (id == "custom-filters-raw-save")
459 } 466 {
460 }, false); 467 ext.backgroundPage.sendMessage(
461 } 468 {
469 type: "filters.importRaw",
470 text: E("custom-filters-raw").value
471 });
472 }
473 }, false);
462 } 474 }
463 475
464 function openDialog(name) 476 function openDialog(name)
465 { 477 {
466 document.body.dataset.dialog = name; 478 document.body.dataset.dialog = name;
467 } 479 }
468 480
469 function populateLists() 481 function populateLists()
470 { 482 {
471 subscriptionsMap = Object.create(null); 483 subscriptionsMap = Object.create(null);
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
532 text: "@@||" + domain.value.toLowerCase() + "^$document" 544 text: "@@||" + domain.value.toLowerCase() + "^$document"
533 }); 545 });
534 } 546 }
535 547
536 domain.value = ""; 548 domain.value = "";
537 } 549 }
538 550
539 function editCustomFilters() 551 function editCustomFilters()
540 { 552 {
541 var customFilterItems = collections.customFilters.items; 553 var customFilterItems = collections.customFilters.items;
542 var text = ""; 554 var filterTexts = [];
543 for (var i = 0; i < customFilterItems.length; i++) 555 for (var i = 0; i < customFilterItems.length; i++)
544 text += customFilterItems[i].text + "\n"; 556 filterTexts.push(customFilterItems[i].text);
545 E("custom-filters-textarea").value = text; 557 E("custom-filters-raw").value = filterTexts.join("\n");
Thomas Greiner 2015/06/30 09:23:28 This loop is potentially creating a lot of strings
saroyanm 2015/07/08 18:25:41 Done.
546 } 558 }
547 559
548 function getAcceptableAdsURL(callback) 560 function getAcceptableAdsURL(callback)
549 { 561 {
550 ext.backgroundPage.sendMessage( 562 ext.backgroundPage.sendMessage(
551 { 563 {
552 type: "prefs.get", 564 type: "prefs.get",
553 key: "subscriptions_exceptionsurl" 565 key: "subscriptions_exceptionsurl"
554 }, 566 },
555 function(value) 567 function(value)
(...skipping 18 matching lines...) Expand all
574 var message = { 586 var message = {
575 type: messageType, 587 type: messageType,
576 url: url 588 url: url
577 }; 589 };
578 if (title) 590 if (title)
579 message.title = title; 591 message.title = title;
580 if (homepage) 592 if (homepage)
581 message.homepage = homepage; 593 message.homepage = homepage;
582 594
583 ext.backgroundPage.sendMessage(message); 595 ext.backgroundPage.sendMessage(message);
584 }
585
586 function removeSubscription(url)
587 {
588 ext.backgroundPage.sendMessage(
589 {
590 type: "subscriptions.remove",
591 url: url
592 });
593 }
594
595 function removeFilter(filter)
596 {
597 ext.backgroundPage.sendMessage(
598 {
599 type: "filters.remove",
600 text: filter
601 });
602 }
603
604 function addFilter(filter)
Thomas Greiner 2015/06/30 09:23:29 There's no need to create a function for that beca
saroyanm 2015/07/08 18:25:41 Done. Please note that we still have similar metho
Thomas Greiner 2015/07/09 11:07:54 Good point, feel free to include that in this revi
saroyanm 2015/07/09 16:31:39 Done.
605 {
606 ext.backgroundPage.sendMessage(
607 {
608 type: "filters.add",
609 text: filter
610 });
611 } 596 }
612 597
613 function onFilterMessage(action, filter) 598 function onFilterMessage(action, filter)
614 { 599 {
615 switch (action) 600 switch (action)
616 { 601 {
617 case "added": 602 case "added":
618 updateFilter(filter); 603 updateFilter(filter);
619 updateShareLink(); 604 updateShareLink();
620 break; 605 break;
621 case "loaded": 606 case "loaded":
622 populateLists(); 607 populateLists();
623 break; 608 break;
624 case "removed": 609 case "removed":
625 var knownFilter = filtersMap[filter.text]; 610 var knownFilter = filtersMap[filter.text];
626 collections.whitelist.removeItem(knownFilter); 611 collections.whitelist.removeItem(knownFilter);
627 collections.customFilters.removeItem(knownFilter); 612 collections.customFilters.removeItem(knownFilter);
Thomas Greiner 2015/06/30 09:23:28 Note that when I click on "edit view" and right af
saroyanm 2015/07/08 18:25:41 The problem is that in "filters.importRaw" we were
628 delete filtersMap[filter.text]; 613 delete filtersMap[filter.text];
629 updateShareLink(); 614 updateShareLink();
630 break; 615 break;
631 } 616 }
632 } 617 }
633 618
634 function onSubscriptionMessage(action, subscription) 619 function onSubscriptionMessage(action, subscription)
635 { 620 {
636 switch (action) 621 switch (action)
637 { 622 {
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
691 { 676 {
692 // TODO: modify "share" link accordingly 677 // TODO: modify "share" link accordingly
693 }); 678 });
694 } 679 }
695 680
696 function E(id) 681 function E(id)
697 { 682 {
698 return document.getElementById(id); 683 return document.getElementById(id);
699 } 684 }
700 685
686 function getDocLink(link, callback)
687 {
688 ext.backgroundPage.sendMessage(
689 {
690 type: "app.get",
691 what: "doclink",
692 link: link
693 }, callback);
694 }
695
701 ext.onMessage.addListener(function(message) 696 ext.onMessage.addListener(function(message)
702 { 697 {
703 switch (message.type) 698 switch (message.type)
704 { 699 {
705 case "app.listen": 700 case "app.listen":
706 if (message.action == "addSubscription") 701 if (message.action == "addSubscription")
707 showAddSubscriptionDialog(message.args[0]); 702 {
703 E("blockingList-textbox").value = message.args[0].url;
704 openDialog("customlist");
705 }
706 else if (message.action == "error")
707 {
708 alert(message.args.join("\n"));
709 }
708 break; 710 break;
709 case "filters.listen": 711 case "filters.listen":
710 onFilterMessage(message.action, message.args[0]); 712 onFilterMessage(message.action, message.args[0]);
711 break; 713 break;
712 case "subscriptions.listen": 714 case "subscriptions.listen":
713 onSubscriptionMessage(message.action, message.args[0]); 715 onSubscriptionMessage(message.action, message.args[0]);
714 break; 716 break;
715 } 717 }
716 }); 718 });
717 719
718 ext.backgroundPage.sendMessage( 720 ext.backgroundPage.sendMessage(
719 { 721 {
720 type: "app.listen", 722 type: "app.listen",
721 filter: ["addSubscription"] 723 filter: ["addSubscription", "error"]
722 }); 724 });
723 ext.backgroundPage.sendMessage( 725 ext.backgroundPage.sendMessage(
724 { 726 {
725 type: "filters.listen", 727 type: "filters.listen",
726 filter: ["added", "loaded", "removed"] 728 filter: ["added", "loaded", "removed"]
727 }); 729 });
728 ext.backgroundPage.sendMessage( 730 ext.backgroundPage.sendMessage(
729 { 731 {
730 type: "subscriptions.listen", 732 type: "subscriptions.listen",
731 filter: ["added", "disabled", "homepage", "removed", "title"] 733 filter: ["added", "disabled", "homepage", "removed", "title"]
732 }); 734 });
733 735
734 window.addEventListener("DOMContentLoaded", onDOMLoaded, false); 736 window.addEventListener("DOMContentLoaded", onDOMLoaded, false);
735 })(); 737 })();
LEFTRIGHT

Powered by Google App Engine
This is Rietveld