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

Delta Between Two Patch Sets: options.js

Issue 29333819: Issue 2375 - Implement "Blocking lists" section in new options page (Closed)
Left Patch Set: Rebase to d12b18c2a168 Created Jan. 28, 2016, 1:38 p.m.
Right Patch Set: Fixed the progress indicator and small fixes Created Feb. 4, 2016, 5:43 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
« background.js ('K') | « 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-2016 Eyeo GmbH 3 * Copyright (C) 2006-2016 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 "use strict"; 18 "use strict";
19 19
20 (function() 20 (function()
21 { 21 {
22 var subscriptionsMap = Object.create(null); 22 var subscriptionsMap = Object.create(null);
23 var recommendationsMap = Object.create(null); 23 var recommendationsMap = Object.create(null);
24 var filtersMap = Object.create(null); 24 var filtersMap = Object.create(null);
25 var collections = Object.create(null); 25 var collections = Object.create(null);
26 var maxLabelId = 0; 26 var maxLabelId = 0;
27 var getMessage = ext.i18n.getMessage;
28 var filterErrors =
29 {
30 "synchronize_invalid_url": "options_filterList_lastDownload_invalidURL",
31 "synchronize_connection_error": "options_filterList_lastDownload_connectionE rror",
32 "synchronize_invalid_data": "options_filterList_lastDownload_invalidData",
33 "synchronize_checksum_mismatch": "options_filterList_lastDownload_checksumMi smatch"
34 };
27 35
28 function Collection(details) 36 function Collection(details)
29 { 37 {
30 this.details = details; 38 this.details = details;
31 this.items = []; 39 this.items = [];
32 } 40 }
33 41
34 Collection.prototype._setEmpty = function(table, text) 42 Collection.prototype._setEmpty = function(table, text)
35 { 43 {
36 var placeholder = table.querySelector(".empty-placeholder"); 44 var placeholder = table.querySelector(".empty-placeholder");
37 if (text && !placeholder) 45 if (text && !placeholder)
38 { 46 {
39 placeholder = document.createElement("li"); 47 placeholder = document.createElement("li");
40 placeholder.className = "empty-placeholder"; 48 placeholder.className = "empty-placeholder";
41 placeholder.textContent = ext.i18n.getMessage(text); 49 placeholder.textContent = getMessage(text);
42 table.appendChild(placeholder); 50 table.appendChild(placeholder);
43 } 51 }
44 else if (placeholder) 52 else if (placeholder)
45 table.removeChild(placeholder); 53 table.removeChild(placeholder);
46 } 54 }
47 55
48 Collection.prototype._createElementQuery = function(item) 56 Collection.prototype._createElementQuery = function(item)
49 { 57 {
50 var access = (item.url || item.text).replace(/'/g, "\\'"); 58 var access = (item.url || item.text).replace(/'/g, "\\'");
51 return function(container) 59 return function(container)
(...skipping 21 matching lines...) Expand all
73 var template = table.querySelector("template"); 81 var template = table.querySelector("template");
74 for (var i = 0; i < arguments.length; i++) 82 for (var i = 0; i < arguments.length; i++)
75 { 83 {
76 var item = arguments[i]; 84 var item = arguments[i];
77 var listItem = document.createElement("li"); 85 var listItem = document.createElement("li");
78 listItem.appendChild(document.importNode(template.content, true)); 86 listItem.appendChild(document.importNode(template.content, true));
79 listItem.setAttribute("data-access", item.url || item.text); 87 listItem.setAttribute("data-access", item.url || item.text);
80 88
81 var labelId = "label-" + (++maxLabelId); 89 var labelId = "label-" + (++maxLabelId);
82 listItem.querySelector(".display").setAttribute("id", labelId); 90 listItem.querySelector(".display").setAttribute("id", labelId);
83 updateBlockingList(listItem, item);
Thomas Greiner 2016/01/28 14:09:58 Detail: Don't use `\t` for whitespaces.
84 var control = listItem.querySelector(".control"); 91 var control = listItem.querySelector(".control");
85 if (control) 92 if (control)
86 { 93 {
87 // We use aria-labelledby to avoid triggering the control when 94 // We use aria-labelledby to avoid triggering the control when
88 // interacting with the label 95 // interacting with the label
89 control.setAttribute("aria-labelledby", labelId); 96 control.setAttribute("aria-labelledby", labelId);
90 control.addEventListener("click", this.details[j].onClick, false); 97 control.addEventListener("click", this.details[j].onClick, false);
91 } 98 }
92 99
93 this._setEmpty(table, null); 100 this._setEmpty(table, null);
94 if (table.hasChildNodes()) 101 if (table.hasChildNodes())
95 { 102 {
96 table.insertBefore(listItem, 103 table.insertBefore(listItem,
97 table.childNodes[this.items.indexOf(item)]); 104 table.childNodes[this.items.indexOf(item)]);
98 } 105 }
99 else 106 else
100 table.appendChild(listItem); 107 table.appendChild(listItem);
101 this.updateItem(item); 108 this.updateItem(item);
102 } 109 }
103 } 110 }
104 return length; 111 return length;
105 }; 112 };
106 113
107 Collection.prototype.removeItem = function(item) 114 Collection.prototype.removeItem = function(item)
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
146 Collection.prototype.updateItem = function(item) 153 Collection.prototype.updateItem = function(item)
147 { 154 {
148 var access = (item.url || item.text).replace(/'/g, "\\'"); 155 var access = (item.url || item.text).replace(/'/g, "\\'");
149 for (var i = 0; i < this.details.length; i++) 156 for (var i = 0; i < this.details.length; i++)
150 { 157 {
151 var table = E(this.details[i].id); 158 var table = E(this.details[i].id);
152 var element = table.querySelector("[data-access='" + access + "']"); 159 var element = table.querySelector("[data-access='" + access + "']");
153 if (!element) 160 if (!element)
154 continue; 161 continue;
155 162
156 var text = item.title || item.url || item.text; 163 var title = item.title || item.url || item.text;
157 element.querySelector(".display").textContent = text; 164 element.querySelector(".display").textContent = title;
158 if (text) 165 if (title)
159 element.setAttribute("data-search", text.toLowerCase()); 166 element.setAttribute("data-search", title.toLowerCase());
160 var control = element.querySelector(".control[role='checkbox']"); 167 var control = element.querySelector(".control[role='checkbox']");
161 if (control) 168 if (control)
162 control.setAttribute("aria-checked", item.disabled == false); 169 control.setAttribute("aria-checked", item.disabled == false);
170
171 var downloadStatus = item.downloadStatus;
172 var dateElement = element.querySelector(".date");
173 var timeElement = element.querySelector(".time");
174 if(dateElement && timeElement)
175 {
176 var message = element.querySelector(".message");
177 ext.backgroundPage.sendMessage(
178 {
179 type: "subscriptions.isDownloading",
180 url: item.url
181 },
182 function(isDownloading)
183 {
184 if (isDownloading)
185 {
186 var text = getMessage("options_filterList_lastDownload_inProgress");
187 message.textContent = text;
188 element.classList.add("show-message");
189 }
190 else if (downloadStatus && downloadStatus != "synchronize_ok")
191 {
192 if (downloadStatus in filterErrors)
193 message.textContent = getMessage(filterErrors[downloadStatus]);
194 else
195 message.textContent = item.downloadStatus;
196 element.classList.add("show-message");
197 }
198 else if (item.lastDownload > 0)
199 {
200 var dateTime = i18n_formatDateTime(item.lastDownload * 1000);
201 dateElement.textContent = dateTime[0];
202 timeElement.textContent = dateTime[1];
203 element.classList.remove("show-message");
204 }
205 });
206 }
207 var websiteElement = element.querySelector(".context-menu .website");
208 var sourceElement = element.querySelector(".context-menu .source");
209 if (websiteElement && item.homepage)
210 websiteElement.setAttribute("href", item.homepage);
211 if (sourceElement)
212 sourceElement.setAttribute("href", item.url);
163 } 213 }
164 }; 214 };
165 215
166 Collection.prototype.clearAll = function() 216 Collection.prototype.clearAll = function()
167 { 217 {
168 this.items = []; 218 this.items = [];
169 for (var i = 0; i < this.details.length; i++) 219 for (var i = 0; i < this.details.length; i++)
170 { 220 {
171 var table = E(this.details[i].id); 221 var table = E(this.details[i].id);
172 var element = table.firstChild; 222 var element = table.firstChild;
173 while (element) 223 while (element)
174 { 224 {
175 if ((element.tagName == "LI" && !element.classList.contains("static")) | | 225 if (element.tagName == "LI" && !element.classList.contains("static"))
176 element.nodeType == 3)
177 table.removeChild(element); 226 table.removeChild(element);
178 element = element.nextSibling 227 element = element.nextElementSibling;
179 } 228 }
180 229
181 this._setEmpty(table, this.details[i].emptyText); 230 this._setEmpty(table, this.details[i].emptyText);
182 } 231 }
183 }; 232 };
184
185 function updateBlockingList(listItem, subscription)
186 {
187 var dateElement = listItem.querySelector(".date");
188 var timeElement = listItem.querySelector(".time");
189
190 if(dateElement && timeElement)
191 {
192 if (subscription.downloadStatus &&
193 subscription.downloadStatus != "synchronize_ok")
194 {
195 var map =
196 {
197 "synchronize_invalid_url": "options_subscription_lastDownload_invalidU RL",
198 "synchronize_connection_error": "options_subscription_lastDownload_con nectionError",
199 "synchronize_invalid_data": "options_subscription_lastDownload_invalid Data",
200 "synchronize_checksum_mismatch": "options_subscription_lastDownload_ch ecksumMismatch"
201 };
202 if (subscription.downloadStatus in map)
203 timeElement.textContent = ext.i18n.getMessage(map[subscription.downloa dStatus]);
204 else
205 timeElement.textContent = subscription.downloadStatus;
206 }
207 else if (subscription.lastDownload > 0)
208 {
209 var dateTime = i18n_formatDateTime(subscription.lastDownload * 1000);
210 dateElement.textContent = dateTime[0];
211 timeElement.textContent = dateTime[1];
212 }
213 }
214 var websiteElement = listItem.querySelector(".context-menu .website");
215 var sourceElement = listItem.querySelector(".context-menu .source");
216 if (websiteElement && subscription.homepage)
217 websiteElement.setAttribute("href", subscription.homepage);
218 if (sourceElement)
219 sourceElement.setAttribute("href", subscription.url);
220 }
221 233
222 function focusNextElement(container, currentElement) 234 function focusNextElement(container, currentElement)
223 { 235 {
224 var focusables = container.querySelectorAll("a, button, input, .control"); 236 var focusables = container.querySelectorAll("a, button, input, .control");
225 focusables = Array.prototype.slice.call(focusables); 237 focusables = Array.prototype.slice.call(focusables);
226 var index = focusables.indexOf(currentElement); 238 var index = focusables.indexOf(currentElement);
227 index += (index == focusables.length - 1) ? -1 : 1; 239 index += (index == focusables.length - 1) ? -1 : 1;
228 240
229 var nextElement = focusables[index]; 241 var nextElement = focusables[index];
230 if (!nextElement) 242 if (!nextElement)
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after
343 ]); 355 ]);
344 356
345 function observeSubscription(subscription) 357 function observeSubscription(subscription)
346 { 358 {
347 function onObjectChanged(change) 359 function onObjectChanged(change)
348 { 360 {
349 for (var i = 0; i < change.length; i++) 361 for (var i = 0; i < change.length; i++)
350 { 362 {
351 if (change[i].name == "disabled") 363 if (change[i].name == "disabled")
352 { 364 {
353 for (var i in collections)
354 collections[i].updateItem(subscription);
355
356 var recommendation = recommendationsMap[subscription.url]; 365 var recommendation = recommendationsMap[subscription.url];
357 if (recommendation && recommendation.type == "ads") 366 if (recommendation && recommendation.type == "ads")
358 { 367 {
359 if (subscription.disabled == false) 368 if (subscription.disabled == false)
360 { 369 {
361 collections.allLangs.removeItem(subscription); 370 collections.allLangs.removeItem(subscription);
362 collections.langs.addItems(subscription); 371 collections.langs.addItems(subscription);
363 } 372 }
364 else 373 else
365 { 374 {
366 collections.allLangs.addItems(subscription); 375 collections.allLangs.addItems(subscription);
367 collections.langs.removeItem(subscription); 376 collections.langs.removeItem(subscription);
368 } 377 }
369 } 378 }
370 } 379 }
371 else 380 for (var i in collections)
372 { 381 collections[i].updateItem(subscription);
373 var blockingListId = collections.filterLists.details[0].id;
374 var blockingList = document.getElementById(blockingListId);
375 var listItem = blockingList.querySelector("[data-access='" +
376 subscription.url + "']");
377 if (listItem)
378 updateBlockingList(listItem, subscription);
379 }
380 } 382 }
381 } 383 }
382 384
383 if (!Object.observe) 385 if (!Object.observe)
384 { 386 {
385 ["disabled", "lastDownload"].forEach(function(property) 387 ["disabled", "lastDownload"].forEach(function(property)
386 { 388 {
387 subscription["$" + property] = subscription[property]; 389 subscription["$" + property] = subscription[property];
388 Object.defineProperty(subscription, property, 390 Object.defineProperty(subscription, property,
389 { 391 {
390 get: function() 392 get: function()
391 { 393 {
392 return this["$" + property]; 394 return this["$" + property];
393 }, 395 },
394 set: function(value) 396 set: function(newValue)
395 { 397 {
396 this["$" + property] = value; 398 var oldValue = this["$" + property];
397 var change = Object.create(null); 399 if (oldValue != newValue)
398 change.name = property; 400 {
399 onObjectChanged([change]); 401 this["$" + property] = newValue;
402 var change = Object.create(null);
403 change.name = property;
404 onObjectChanged([change]);
405 }
400 } 406 }
401 }); 407 });
402 }); 408 });
403 } 409 }
404 else 410 else
405 { 411 {
406 Object.observe(subscription, onObjectChanged); 412 Object.observe(subscription, onObjectChanged);
407 } 413 }
408 } 414 }
409 415
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
478 subscription.url = element.getAttribute("url"); 484 subscription.url = element.getAttribute("url");
479 subscription.disabled = null; 485 subscription.disabled = null;
480 subscription.downloadStatus = null; 486 subscription.downloadStatus = null;
481 subscription.homepage = null; 487 subscription.homepage = null;
482 var recommendation = Object.create(null); 488 var recommendation = Object.create(null);
483 recommendation.type = element.getAttribute("type"); 489 recommendation.type = element.getAttribute("type");
484 var prefix = element.getAttribute("prefixes"); 490 var prefix = element.getAttribute("prefixes");
485 if (prefix) 491 if (prefix)
486 { 492 {
487 prefix = prefix.replace(/\W/g, "_"); 493 prefix = prefix.replace(/\W/g, "_");
488 subscription.title = ext.i18n.getMessage("options_language_" + prefi x); 494 subscription.title = getMessage("options_language_" + prefix);
489 } 495 }
490 else 496 else
491 { 497 {
492 var type = recommendation.type.replace(/\W/g, "_"); 498 var type = recommendation.type.replace(/\W/g, "_");
493 subscription.title = ext.i18n.getMessage("common_feature_" + type + "_title"); 499 subscription.title = getMessage("common_feature_" + type + "_title") ;
494 } 500 }
495 501
496 recommendationsMap[subscription.url] = recommendation; 502 recommendationsMap[subscription.url] = recommendation;
497 updateSubscription(subscription); 503 updateSubscription(subscription);
498 } 504 }
499 }); 505 });
500 } 506 }
501 507
502 function findParentData(element, dataName, returnElement) 508 function findParentData(element, dataName, returnElement)
503 { 509 {
504 while (element) 510 while (element)
505 { 511 {
506 if (element.hasAttribute("data-" + dataName)) 512 if (element.hasAttribute("data-" + dataName))
507 return returnElement ? element : element.getAttribute("data-" + dataName ); 513 return returnElement ? element : element.getAttribute("data-" + dataName );
508 514
509 element = element.parentElement; 515 element = element.parentElement;
510 } 516 }
511 return null; 517 return null;
512 } 518 }
513 519
514 function onClick(e) 520 function onClick(e)
515 { 521 {
522 var context = document.querySelector(".show-context-menu");
523 if (context)
524 context.classList.remove("show-context-menu");
525
516 var element = e.target; 526 var element = e.target;
517 while (true) 527 while (true)
518 { 528 {
519 if (!element) 529 if (!element)
520 {
521 var context = document.querySelector(".context");
522 if (context)
523 context.classList.remove("context");
524 return; 530 return;
525 }
526 531
527 if (element.hasAttribute("data-action")) 532 if (element.hasAttribute("data-action"))
528 break; 533 break;
529 534
530 element = element.parentElement; 535 element = element.parentElement;
531 } 536 }
532 537
533 var actions = element.getAttribute("data-action").split(","); 538 var actions = element.getAttribute("data-action").split(",");
534 for (var i = 0; i < actions.length; i++) 539 for (var i = 0; i < actions.length; i++)
535 { 540 {
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
584 element.getAttribute("data-tab")); 589 element.getAttribute("data-tab"));
585 break; 590 break;
586 case "update-all-subscriptions": 591 case "update-all-subscriptions":
587 ext.backgroundPage.sendMessage( 592 ext.backgroundPage.sendMessage(
588 { 593 {
589 type: "subscriptions.update" 594 type: "subscriptions.update"
590 }); 595 });
591 break; 596 break;
592 case "open-context-menu": 597 case "open-context-menu":
593 var listItem = findParentData(element, "access", true); 598 var listItem = findParentData(element, "access", true);
594 var contextMenu = listItem.querySelector(".content"); 599 if (listItem != context)
595 listItem.classList.add("context"); 600 listItem.classList.add("show-context-menu");
596 break; 601 break;
597 case "update-now": 602 case "update-subscription":
598 ext.backgroundPage.sendMessage( 603 ext.backgroundPage.sendMessage(
599 { 604 {
600 type: "subscriptions.update", 605 type: "subscriptions.update",
601 url: findParentData(element, "access") 606 url: findParentData(element, "access", false)
602 }); 607 });
603 break; 608 break;
604 case "remove-subscription": 609 case "remove-subscription":
605 ext.backgroundPage.sendMessage( 610 ext.backgroundPage.sendMessage(
606 { 611 {
607 type: "subscriptions.remove", 612 type: "subscriptions.remove",
608 url: findParentData(element, "access") 613 url: findParentData(element, "access", false)
609 }); 614 });
610 break;
611 case "close-context-menu":
612 var access = findParentData(element, "access", true);
613 if (access)
614 access.classList.remove("context");
615 break; 615 break;
616 } 616 }
617 } 617 }
618 } 618 }
619 619
620 function onDOMLoaded() 620 function onDOMLoaded()
621 { 621 {
622 populateLists(); 622 populateLists();
623 function onFindLanguageKeyUp() 623 function onFindLanguageKeyUp()
624 { 624 {
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
659 659
660 getDocLink("contribute", function(link) 660 getDocLink("contribute", function(link)
661 { 661 {
662 document.querySelector("#tab-contribute a").setAttribute("href", link); 662 document.querySelector("#tab-contribute a").setAttribute("href", link);
663 }); 663 });
664 664
665 updateShareLink(); 665 updateShareLink();
666 666
667 // Initialize interactive UI elements 667 // Initialize interactive UI elements
668 document.body.addEventListener("click", onClick, false); 668 document.body.addEventListener("click", onClick, false);
669 var placeholderValue = ext.i18n.getMessage("options_dialog_language_find"); 669 var placeholderValue = getMessage("options_dialog_language_find");
670 E("find-language").setAttribute("placeholder", placeholderValue); 670 E("find-language").setAttribute("placeholder", placeholderValue);
671 E("find-language").addEventListener("keyup", onFindLanguageKeyUp, false); 671 E("find-language").addEventListener("keyup", onFindLanguageKeyUp, false);
672 E("whitelisting-textbox").addEventListener("keypress", function(e) 672 E("whitelisting-textbox").addEventListener("keypress", function(e)
673 { 673 {
674 if (getKey(e) == "Enter") 674 if (getKey(e) == "Enter")
675 addWhitelistedDomain(); 675 addWhitelistedDomain();
676 }, false); 676 }, false);
677 677
678 // Advanced tab 678 // Advanced tab
679 var filterTextbox = document.querySelector("#custom-filters-add input"); 679 var filterTextbox = document.querySelector("#custom-filters-add input");
680 placeholderValue = ext.i18n.getMessage("options_customFilters_textbox_placeh older"); 680 placeholderValue = getMessage("options_customFilters_textbox_placeholder");
681 filterTextbox.setAttribute("placeholder", placeholderValue); 681 filterTextbox.setAttribute("placeholder", placeholderValue);
682 function addCustomFilters() 682 function addCustomFilters()
683 { 683 {
684 var filterText = filterTextbox.value; 684 var filterText = filterTextbox.value;
685 ext.backgroundPage.sendMessage( 685 ext.backgroundPage.sendMessage(
686 { 686 {
687 type: "filters.add", 687 type: "filters.add",
688 text: filterText 688 text: filterText
689 }); 689 });
690 filterTextbox.value = ""; 690 filterTextbox.value = "";
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
778 updateFilter(filters[i]); 778 updateFilter(filters[i]);
779 }); 779 });
780 } 780 }
781 }); 781 });
782 loadRecommendations(); 782 loadRecommendations();
783 getAcceptableAdsURL(function(acceptableAdsUrl) 783 getAcceptableAdsURL(function(acceptableAdsUrl)
784 { 784 {
785 var subscription = Object.create(null); 785 var subscription = Object.create(null);
786 subscription.url = acceptableAdsUrl; 786 subscription.url = acceptableAdsUrl;
787 subscription.disabled = true; 787 subscription.disabled = true;
788 subscription.title = ext.i18n.getMessage("options_acceptableAds_descriptio n"); 788 subscription.title = getMessage("options_acceptableAds_description");
789 updateSubscription(subscription); 789 updateSubscription(subscription);
790 790
791 // Load user subscriptions 791 // Load user subscriptions
792 ext.backgroundPage.sendMessage( 792 ext.backgroundPage.sendMessage(
793 { 793 {
794 type: "subscriptions.get", 794 type: "subscriptions.get",
795 downloadable: true 795 downloadable: true
796 }, 796 },
797 function(subscriptions) 797 function(subscriptions)
798 { 798 {
(...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after
1018 filter: ["added", "loaded", "removed"] 1018 filter: ["added", "loaded", "removed"]
1019 }); 1019 });
1020 ext.backgroundPage.sendMessage( 1020 ext.backgroundPage.sendMessage(
1021 { 1021 {
1022 type: "subscriptions.listen", 1022 type: "subscriptions.listen",
1023 filter: ["added", "disabled", "homepage", "lastDownload", "removed", "title" ] 1023 filter: ["added", "disabled", "homepage", "lastDownload", "removed", "title" ]
1024 }); 1024 });
1025 1025
1026 window.addEventListener("DOMContentLoaded", onDOMLoaded, false); 1026 window.addEventListener("DOMContentLoaded", onDOMLoaded, false);
1027 })(); 1027 })();
LEFTRIGHT

Powered by Google App Engine
This is Rietveld