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

Delta Between Two Patch Sets: background.js

Issue 5138680696012800: Issue 616 - Enforce $generichide and $genericblock in Chrome (Closed)
Left Patch Set: Rebased. Created March 12, 2015, 8:35 p.m.
Right Patch Set: Updated adblockplustests dependency Created Oct. 5, 2015, 9:52 a.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 | « no previous file | dependencies » ('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
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 with(require("filterClasses")) 18 with(require("filterClasses"))
19 { 19 {
20 this.Filter = Filter; 20 this.Filter = Filter;
21 this.BlockingFilter = BlockingFilter; 21 this.BlockingFilter = BlockingFilter;
22 this.WhitelistFilter = WhitelistFilter; 22 this.WhitelistFilter = WhitelistFilter;
23 this.RegExpFilter = RegExpFilter;
23 } 24 }
24 with(require("subscriptionClasses")) 25 with(require("subscriptionClasses"))
25 { 26 {
26 this.Subscription = Subscription; 27 this.Subscription = Subscription;
27 this.DownloadableSubscription = DownloadableSubscription; 28 this.DownloadableSubscription = DownloadableSubscription;
28 this.SpecialSubscription = SpecialSubscription; 29 this.SpecialSubscription = SpecialSubscription;
29 } 30 }
30 with(require("whitelisting")) 31 with(require("whitelisting"))
31 { 32 {
32 this.isPageWhitelisted = isPageWhitelisted; 33 this.isPageWhitelisted = isPageWhitelisted;
33 this.isFrameWhitelisted = isFrameWhitelisted; 34 this.isFrameWhitelisted = isFrameWhitelisted;
34 this.processKey = processKey; 35 this.processKey = processKey;
35 this.getKey = getKey; 36 this.getKey = getKey;
36 } 37 }
37 with(require("url")) 38 with(require("url"))
38 { 39 {
39 this.stringifyURL = stringifyURL; 40 this.stringifyURL = stringifyURL;
40 this.isThirdParty = isThirdParty; 41 this.isThirdParty = isThirdParty;
41 this.extractHostFromFrame = extractHostFromFrame; 42 this.extractHostFromFrame = extractHostFromFrame;
42 } 43 }
43 with(require("icon"))
44 {
45 this.updateIcon = updateIcon;
46 this.startIconAnimation = startIconAnimation;
47 this.stopIconAnimation = stopIconAnimation;
48 }
49 var FilterStorage = require("filterStorage").FilterStorage; 44 var FilterStorage = require("filterStorage").FilterStorage;
45 var FilterNotifier = require("filterNotifier").FilterNotifier;
50 var ElemHide = require("elemHide").ElemHide; 46 var ElemHide = require("elemHide").ElemHide;
51 var defaultMatcher = require("matcher").defaultMatcher; 47 var defaultMatcher = require("matcher").defaultMatcher;
52 var Prefs = require("prefs").Prefs; 48 var Prefs = require("prefs").Prefs;
53 var Synchronizer = require("synchronizer").Synchronizer; 49 var Synchronizer = require("synchronizer").Synchronizer;
54 var Utils = require("utils").Utils; 50 var Utils = require("utils").Utils;
55 var NotificationStorage = require("notification").Notification;
56 var initAntiAdblockNotification = require("antiadblockInit").initAntiAdblockNoti fication;
57 var parseFilters = require("filterValidation").parseFilters; 51 var parseFilters = require("filterValidation").parseFilters;
58 var composeFilters = require("filterComposer").composeFilters; 52 var composeFilters = require("filterComposer").composeFilters;
59 53 var updateIcon = require("icon").updateIcon;
60 // Chrome on Linux does not fully support chrome.notifications until version 35 54 var initNotifications = require("notificationHelper").initNotifications;
61 // https://code.google.com/p/chromium/issues/detail?id=291485
62 var canUseChromeNotifications = require("info").platform == "chromium"
63 && "notifications" in chrome
64 && (navigator.platform.indexOf("Linux") == -1 || parseInt(require("info").appl icationVersion, 10) > 34);
65 55
66 var seenDataCorruption = false; 56 var seenDataCorruption = false;
67 var filterlistsReinitialized = false; 57 var filterlistsReinitialized = false;
68 require("filterNotifier").FilterNotifier.addListener(function(action) 58
69 { 59 function init()
70 if (action == "load") 60 {
71 { 61 var filtersLoaded = false;
72 var addonVersion = require("info").addonVersion; 62 var prefsLoaded = false;
73 var prevVersion = ext.storage.currentVersion; 63
64 var checkLoaded = function()
65 {
66 if (!filtersLoaded || !prefsLoaded)
67 return;
68
69 var info = require("info");
70 var previousVersion = Prefs.currentVersion;
74 71
75 // There are no filters stored so we need to reinitialize all filterlists 72 // There are no filters stored so we need to reinitialize all filterlists
76 if (!FilterStorage.firstRun && FilterStorage.subscriptions.length === 0) 73 if (!FilterStorage.firstRun && FilterStorage.subscriptions.length === 0)
77 { 74 {
78 filterlistsReinitialized = true; 75 filterlistsReinitialized = true;
79 prevVersion = null; 76 previousVersion = null;
80 } 77 }
81 78
82 if (prevVersion != addonVersion || FilterStorage.firstRun) 79 if (previousVersion != info.addonVersion || FilterStorage.firstRun)
83 { 80 {
84 seenDataCorruption = prevVersion && FilterStorage.firstRun; 81 seenDataCorruption = previousVersion && FilterStorage.firstRun;
85 ext.storage.currentVersion = addonVersion; 82 Prefs.currentVersion = info.addonVersion;
86 addSubscription(prevVersion); 83 addSubscription(previousVersion);
87 } 84 }
88
89 if (canUseChromeNotifications)
90 initChromeNotifications();
91 initAntiAdblockNotification();
92 85
93 // The "Hide placeholders" option has been removed from the UI in 1.8.8.1285 86 // The "Hide placeholders" option has been removed from the UI in 1.8.8.1285
94 // So we reset the option for users updating from older versions. 87 // So we reset the option for users updating from older versions.
95 if (prevVersion && Services.vc.compare(prevVersion, "1.8.8.1285") < 0) 88 if (previousVersion && Services.vc.compare(previousVersion, "1.8.8.1285") < 0)
96 Prefs.hidePlaceholders = true; 89 Prefs.hidePlaceholders = true;
97 } 90
98 91 initNotifications();
99 // update browser actions when whitelisting might have changed, 92
100 // due to loading filters or saving filter changes 93 // Update browser actions and context menus when whitelisting might have
101 if (action == "load" || action == "save") 94 // changed. That is now when initally loading the filters and later when
95 // importing backups or saving filter changes.
96 FilterNotifier.addListener(function(action)
97 {
98 if (action == "load" || action == "save")
99 refreshIconAndContextMenuForAllPages();
100 });
102 refreshIconAndContextMenuForAllPages(); 101 refreshIconAndContextMenuForAllPages();
103 }); 102 };
103
104 var onFilterAction = function(action)
105 {
106 if (action == "load")
107 {
108 FilterNotifier.removeListener(onFilterAction);
109 filtersLoaded = true;
110 checkLoaded();
111 }
112 };
113
114 var onPrefsLoaded = function()
115 {
116 Prefs.onLoaded.removeListener(onPrefsLoaded);
117 prefsLoaded = true;
118 checkLoaded();
119 };
120
121 FilterNotifier.addListener(onFilterAction);
122 Prefs.onLoaded.addListener(onPrefsLoaded);
123 }
124 init();
104 125
105 // Special-case domains for which we cannot use style-based hiding rules. 126 // Special-case domains for which we cannot use style-based hiding rules.
106 // See http://crbug.com/68705. 127 // See http://crbug.com/68705.
107 var noStyleRulesHosts = ["mail.google.com", "mail.yahoo.com", "www.google.com"]; 128 var noStyleRulesHosts = ["mail.google.com", "mail.yahoo.com", "www.google.com"];
108 129
109 var htmlPages = new ext.PageMap(); 130 var htmlPages = new ext.PageMap();
110
111 function removeDeprecatedOptions()
112 {
113 var deprecatedOptions = ["specialCaseYouTube", "experimental", "disableInlineT extAds"];
114 deprecatedOptions.forEach(function(option)
115 {
116 if (option in ext.storage)
117 delete ext.storage[option];
118 });
119 }
120
121 // Remove deprecated options before we do anything else.
122 removeDeprecatedOptions();
123
124 var activeNotification = null;
125 131
126 var contextMenuItem = { 132 var contextMenuItem = {
127 title: ext.i18n.getMessage("block_element"), 133 title: ext.i18n.getMessage("block_element"),
128 contexts: ["image", "video", "audio"], 134 contexts: ["image", "video", "audio"],
129 onclick: function(page) 135 onclick: function(page)
130 { 136 {
131 page.sendMessage({type: "clickhide-new-filter"}); 137 page.sendMessage({type: "clickhide-new-filter"});
132 } 138 }
133 }; 139 };
134 140
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
217 if (subscription instanceof DownloadableSubscription && !subscription.last Download) 223 if (subscription instanceof DownloadableSubscription && !subscription.last Download)
218 Synchronizer.execute(subscription); 224 Synchronizer.execute(subscription);
219 } 225 }
220 } 226 }
221 227
222 if (!addSubscription && !addAcceptable) 228 if (!addSubscription && !addAcceptable)
223 return; 229 return;
224 230
225 function notifyUser() 231 function notifyUser()
226 { 232 {
227 ext.pages.open(ext.getURL("firstRun.html")); 233 if (!Prefs.suppress_first_run_page)
234 ext.pages.open(ext.getURL("firstRun.html"));
228 } 235 }
229 236
230 if (addSubscription) 237 if (addSubscription)
231 { 238 {
232 // Load subscriptions data 239 // Load subscriptions data
233 var request = new XMLHttpRequest(); 240 var request = new XMLHttpRequest();
234 request.open("GET", "subscriptions.xml"); 241 request.open("GET", "subscriptions.xml");
235 request.addEventListener("load", function() 242 request.addEventListener("load", function()
236 { 243 {
237 var node = Utils.chooseFilterSubscription(request.responseXML.getElementsB yTagName("subscription")); 244 var node = Utils.chooseFilterSubscription(request.responseXML.getElementsB yTagName("subscription"));
238 var subscription = (node ? Subscription.fromURL(node.getAttribute("url")) : null); 245 var subscription = (node ? Subscription.fromURL(node.getAttribute("url")) : null);
239 if (subscription) 246 if (subscription)
240 { 247 {
241 FilterStorage.addSubscription(subscription); 248 FilterStorage.addSubscription(subscription);
242 subscription.disabled = false; 249 subscription.disabled = false;
243 subscription.title = node.getAttribute("title"); 250 subscription.title = node.getAttribute("title");
244 subscription.homepage = node.getAttribute("homepage"); 251 subscription.homepage = node.getAttribute("homepage");
245 if (subscription instanceof DownloadableSubscription && !subscription.la stDownload) 252 if (subscription instanceof DownloadableSubscription && !subscription.la stDownload)
246 Synchronizer.execute(subscription); 253 Synchronizer.execute(subscription);
247 254
248 notifyUser(); 255 notifyUser();
249 } 256 }
250 }, false); 257 }, false);
251 request.send(null); 258 request.send(null);
252 } 259 }
253 else 260 else
254 notifyUser(); 261 notifyUser();
255 } 262 }
256 263
257 Prefs.addListener(function(name) 264 Prefs.onChanged.addListener(function(name)
258 { 265 {
259 if (name == "shouldShowBlockElementMenu") 266 if (name == "shouldShowBlockElementMenu")
260 refreshIconAndContextMenuForAllPages(); 267 refreshIconAndContextMenuForAllPages();
261 }); 268 });
262
263 function prepareNotificationIconAndPopup()
264 {
265 var animateIcon = (activeNotification.type !== "question");
266 activeNotification.onClicked = function()
267 {
268 if (animateIcon)
269 stopIconAnimation();
270 notificationClosed();
271 };
272 if (animateIcon)
273 startIconAnimation(activeNotification.type);
274 }
275
276 function openNotificationLinks()
277 {
278 if (activeNotification.links)
279 {
280 activeNotification.links.forEach(function(link)
281 {
282 ext.windows.getLastFocused(function(win)
283 {
284 win.openTab(Utils.getDocLink(link));
285 });
286 });
287 }
288 }
289
290 function notificationButtonClick(buttonIndex)
291 {
292 if (activeNotification.type === "question")
293 {
294 NotificationStorage.triggerQuestionListeners(activeNotification.id, buttonIn dex === 0);
295 NotificationStorage.markAsShown(activeNotification.id);
296 activeNotification.onClicked();
297 }
298 else if (activeNotification.links && activeNotification.links[buttonIndex])
299 {
300 ext.windows.getLastFocused(function(win)
301 {
302 win.openTab(Utils.getDocLink(activeNotification.links[buttonIndex]));
303 });
304 }
305 }
306
307 function notificationClosed()
308 {
309 activeNotification = null;
310 }
311
312 function imgToBase64(url, callback)
313 {
314 var canvas = document.createElement("canvas"),
315 ctx = canvas.getContext("2d"),
316 img = new Image;
317 img.src = url;
318 img.onload = function()
319 {
320 canvas.height = img.height;
321 canvas.width = img.width;
322 ctx.drawImage(img, 0, 0);
323 callback(canvas.toDataURL("image/png"));
324 canvas = null;
325 };
326 }
327
328 function initChromeNotifications()
329 {
330 // Chrome hides notifications in notification center when clicked so we need t o clear them
331 function clearActiveNotification(notificationId)
332 {
333 if (activeNotification && activeNotification.type != "question" && !("links" in activeNotification))
334 return;
335
336 chrome.notifications.clear(notificationId, function(wasCleared)
337 {
338 if (wasCleared)
339 notificationClosed();
340 });
341 }
342
343 chrome.notifications.onButtonClicked.addListener(function(notificationId, butt onIndex)
344 {
345 notificationButtonClick(buttonIndex);
346 clearActiveNotification(notificationId);
347 });
348 chrome.notifications.onClicked.addListener(clearActiveNotification);
349 chrome.notifications.onClosed.addListener(notificationClosed);
350 }
351
352 function showNotification(notification)
353 {
354 if (activeNotification && activeNotification.id === notification.id)
355 return;
356
357 activeNotification = notification;
358 if (activeNotification.type === "critical" || activeNotification.type === "que stion")
359 {
360 var texts = NotificationStorage.getLocalizedTexts(notification);
361 var title = texts.title || "";
362 var message = texts.message ? texts.message.replace(/<\/?(a|strong)>/g, "") : "";
363 var iconUrl = ext.getURL("icons/detailed/abp-128.png");
364 var hasLinks = activeNotification.links && activeNotification.links.length > 0;
365
366 if (canUseChromeNotifications)
367 {
368 var opts = {
369 type: "basic",
370 title: title,
371 message: message,
372 buttons: [],
373 priority: 2 // We use the highest priority to prevent the notification f rom closing automatically
374 };
375 if (activeNotification.type === "question")
376 {
377 opts.buttons.push({title: ext.i18n.getMessage("overlay_notification_butt on_yes")});
378 opts.buttons.push({title: ext.i18n.getMessage("overlay_notification_butt on_no")});
379 }
380 else
381 {
382 var regex = /<a>(.*?)<\/a>/g;
383 var plainMessage = texts.message || "";
384 var match;
385 while (match = regex.exec(plainMessage))
386 opts.buttons.push({title: match[1]});
387 }
388
389 imgToBase64(iconUrl, function(iconData)
390 {
391 opts["iconUrl"] = iconData;
392 chrome.notifications.create("", opts, function() {});
393 });
394 }
395 else if ("Notification" in window && activeNotification.type !== "question")
396 {
397 if (hasLinks)
398 message += " " + ext.i18n.getMessage("notification_without_buttons");
399
400 imgToBase64(iconUrl, function(iconData)
401 {
402 var notification = new Notification(
403 title,
404 {
405 lang: Utils.appLocale,
406 dir: ext.i18n.getMessage("@@bidi_dir"),
407 body: message,
408 icon: iconData
409 }
410 );
411
412 notification.addEventListener("click", openNotificationLinks);
413 notification.addEventListener("close", notificationClosed);
414 });
415 }
416 else
417 {
418 var message = title + "\n" + message;
419 if (hasLinks)
420 message += "\n\n" + ext.i18n.getMessage("notification_with_buttons");
421
422 var approved = confirm(message);
423 if (activeNotification.type === "question")
424 notificationButtonClick(approved ? 0 : 1);
425 else if (approved)
426 openNotificationLinks();
427 }
428 }
429 prepareNotificationIconAndPopup();
430 }
431 269
432 // This is a hack to speedup loading of the options page on Safari. 270 // This is a hack to speedup loading of the options page on Safari.
433 // Once we replaced the background page proxy with message passing 271 // Once we replaced the background page proxy with message passing
434 // this global function should removed. 272 // this global function should removed.
435 function getUserFilters() 273 function getUserFilters()
436 { 274 {
437 var filters = []; 275 var filters = [];
438 var exceptions = []; 276 var exceptions = [];
439 277
440 for (var i = 0; i < FilterStorage.subscriptions.length; i++) 278 for (var i = 0; i < FilterStorage.subscriptions.length; i++)
(...skipping 15 matching lines...) Expand all
456 return {filters: filters, exceptions: exceptions}; 294 return {filters: filters, exceptions: exceptions};
457 } 295 }
458 296
459 ext.onMessage.addListener(function (msg, sender, sendResponse) 297 ext.onMessage.addListener(function (msg, sender, sendResponse)
460 { 298 {
461 switch (msg.type) 299 switch (msg.type)
462 { 300 {
463 case "get-selectors": 301 case "get-selectors":
464 var selectors = []; 302 var selectors = [];
465 303
466 if (!isFrameWhitelisted(sender.page, sender.frame, "DOCUMENT") && 304 if (!isFrameWhitelisted(sender.page, sender.frame,
467 !isFrameWhitelisted(sender.page, sender.frame, "ELEMHIDE")) 305 RegExpFilter.typeMap.DOCUMENT | RegExpFilter.typeM ap.ELEMHIDE))
468 { 306 {
469 var noStyleRules = false; 307 var noStyleRules = false;
470 var specificOnly = isFrameWhitelisted(sender.page, sender.frame, "GENERI CHIDE"); 308 var specificOnly = isFrameWhitelisted(sender.page, sender.frame,
309 RegExpFilter.typeMap.GENERICHIDE);
471 var host = extractHostFromFrame(sender.frame); 310 var host = extractHostFromFrame(sender.frame);
472 311
473 for (var i = 0; i < noStyleRulesHosts.length; i++) 312 for (var i = 0; i < noStyleRulesHosts.length; i++)
474 { 313 {
475 var noStyleHost = noStyleRulesHosts[i]; 314 var noStyleHost = noStyleRulesHosts[i];
476 if (host == noStyleHost || (host.length > noStyleHost.length && 315 if (host == noStyleHost || (host.length > noStyleHost.length &&
477 host.substr(host.length - noStyleHost.leng th - 1) == "." + noStyleHost)) 316 host.substr(host.length - noStyleHost.leng th - 1) == "." + noStyleHost))
478 { 317 {
479 noStyleRules = true; 318 noStyleRules = true;
480 } 319 }
481 } 320 }
482 selectors = ElemHide.getSelectorsForDomain(host, specificOnly); 321 selectors = ElemHide.getSelectorsForDomain(host, specificOnly);
483 if (noStyleRules) 322 if (noStyleRules)
484 { 323 {
485 selectors = selectors.filter(function(s) 324 selectors = selectors.filter(function(s)
486 { 325 {
487 return !/\[style[\^\$]?=/.test(s); 326 return !/\[style[\^\$]?=/.test(s);
488 }); 327 });
489 } 328 }
490 } 329 }
491 330
492 sendResponse(selectors); 331 sendResponse(selectors);
493 break; 332 break;
494 case "should-collapse": 333 case "should-collapse":
495 if (isFrameWhitelisted(sender.page, sender.frame, "DOCUMENT")) 334 if (isFrameWhitelisted(sender.page, sender.frame, RegExpFilter.typeMap.DOC UMENT))
496 { 335 {
497 sendResponse(false); 336 sendResponse(false);
498 break; 337 break;
499 } 338 }
500 339
501 var url = new URL(msg.url); 340 var typeMask = RegExpFilter.typeMap[msg.mediatype];
502 var documentHost = extractHostFromFrame(sender.frame); 341 var documentHost = extractHostFromFrame(sender.frame);
503 var filter = defaultMatcher.matchesAny( 342 var blocked = false;
504 stringifyURL(url), msg.mediatype, 343
505 documentHost, isThirdParty(url, documentHost) 344 for (var i = 0; i < msg.urls.length; i++)
506 ); 345 {
507 346 var url = new URL(msg.urls[i], msg.baseURL);
508 if (filter instanceof BlockingFilter) 347 var filter = defaultMatcher.matchesAny(
509 { 348 stringifyURL(url), typeMask,
510 var collapse = filter.collapse; 349 documentHost, isThirdParty(url, documentHost)
511 if (collapse == null) 350 );
512 collapse = Prefs.hidePlaceholders; 351
513 sendResponse(collapse); 352 if (filter instanceof BlockingFilter)
514 } 353 {
515 else 354 if (filter.collapse != null)
516 sendResponse(false); 355 {
356 sendResponse(filter.collapse);
357 return;
358 }
359
360 blocked = true;
361 }
362 }
363
364 sendResponse(blocked && Prefs.hidePlaceholders);
517 break; 365 break;
518 case "get-domain-enabled-state": 366 case "get-domain-enabled-state":
519 // Returns whether this domain is in the exclusion list. 367 // Returns whether this domain is in the exclusion list.
520 // The browser action popup asks us this. 368 // The browser action popup asks us this.
521 if(sender.page) 369 if(sender.page)
522 { 370 {
523 sendResponse({enabled: !isPageWhitelisted(sender.page)}); 371 sendResponse({enabled: !isPageWhitelisted(sender.page)});
524 return; 372 return;
525 } 373 }
526 break; 374 break;
527 case "add-filters": 375 case "add-filters":
528 var filters; 376 var result = parseFilters(msg.text);
529 try 377
530 { 378 if (result.errors.length > 0)
531 filters = parseFilters(msg.text); 379 {
532 } 380 sendResponse({status: "invalid", error: result.errors.join("\n")});
533 catch (error)
534 {
535 sendResponse({status: "invalid", error: error});
536 break; 381 break;
537 } 382 }
538 383
539 for (var i = 0; i < filters.length; i++) 384 for (var i = 0; i < result.filters.length; i++)
540 FilterStorage.addFilter(filters[i]); 385 FilterStorage.addFilter(result.filters[i]);
541 386
542 sendResponse({status: "ok"}); 387 sendResponse({status: "ok"});
543 break; 388 break;
544 case "add-subscription": 389 case "add-subscription":
545 ext.showOptions(function(page) 390 ext.showOptions(function(page)
546 { 391 {
547 page.sendMessage(msg); 392 page.sendMessage(msg);
548 }); 393 });
549 break; 394 break;
550 case "add-sitekey": 395 case "add-sitekey":
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
582 break; 427 break;
583 } 428 }
584 }); 429 });
585 430
586 // update icon when page changes location 431 // update icon when page changes location
587 ext.pages.onLoading.addListener(function(page) 432 ext.pages.onLoading.addListener(function(page)
588 { 433 {
589 page.sendMessage({type: "clickhide-deactivate"}); 434 page.sendMessage({type: "clickhide-deactivate"});
590 refreshIconAndContextMenu(page); 435 refreshIconAndContextMenu(page);
591 }); 436 });
592
593 setTimeout(function()
594 {
595 var notificationToShow = NotificationStorage.getNextToShow();
596 if (notificationToShow)
597 showNotification(notificationToShow);
598 }, 3 * 60 * 1000);
LEFTRIGHT
« no previous file | dependencies » ('j') | Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Toggle Comments ('s')

Powered by Google App Engine
This is Rietveld