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

Delta Between Two Patch Sets: background.js

Issue 5196306347720704: Issue 1965 - Simplified and fixed missing image for icon animation (Closed)
Left Patch Set: Created March 7, 2014, 5:28 p.m.
Right Patch Set: Rebased and addressed comment Created Feb. 12, 2015, 11:15 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 | lib/icon.js » ('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 <http://adblockplus.org/>, 2 * This file is part of Adblock Plus <https://adblockplus.org/>,
3 * Copyright (C) 2006-2013 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.RegExpFilter = RegExpFilter; 21 this.RegExpFilter = RegExpFilter;
22 this.BlockingFilter = BlockingFilter; 22 this.BlockingFilter = BlockingFilter;
23 this.WhitelistFilter = WhitelistFilter; 23 this.WhitelistFilter = WhitelistFilter;
24 } 24 }
25 with(require("subscriptionClasses")) 25 with(require("subscriptionClasses"))
26 { 26 {
27 this.Subscription = Subscription; 27 this.Subscription = Subscription;
28 this.DownloadableSubscription = DownloadableSubscription; 28 this.DownloadableSubscription = DownloadableSubscription;
29 this.SpecialSubscription = SpecialSubscription;
29 } 30 }
30 with(require("whitelisting")) 31 with(require("whitelisting"))
31 { 32 {
32 this.isWhitelisted = isWhitelisted; 33 this.isPageWhitelisted = isPageWhitelisted;
33 this.isFrameWhitelisted = isFrameWhitelisted; 34 this.isFrameWhitelisted = isFrameWhitelisted;
34 this.processKeyException = processKeyException; 35 this.processKey = processKey;
36 this.getKey = getKey;
37 }
38 with(require("url"))
39 {
40 this.stringifyURL = stringifyURL;
41 this.isThirdParty = isThirdParty;
42 this.extractHostFromFrame = extractHostFromFrame;
43 }
44 with(require("icon"))
45 {
46 this.updateIcon = updateIcon;
47 this.startIconAnimation = startIconAnimation;
48 this.stopIconAnimation = stopIconAnimation;
35 } 49 }
36 var FilterStorage = require("filterStorage").FilterStorage; 50 var FilterStorage = require("filterStorage").FilterStorage;
37 var ElemHide = require("elemHide").ElemHide; 51 var ElemHide = require("elemHide").ElemHide;
38 var defaultMatcher = require("matcher").defaultMatcher; 52 var defaultMatcher = require("matcher").defaultMatcher;
39 var Prefs = require("prefs").Prefs; 53 var Prefs = require("prefs").Prefs;
40 var Synchronizer = require("synchronizer").Synchronizer; 54 var Synchronizer = require("synchronizer").Synchronizer;
41 var Utils = require("utils").Utils; 55 var Utils = require("utils").Utils;
42 var Notification = require("notification").Notification; 56 var NotificationStorage = require("notification").Notification;
57 var initAntiAdblockNotification = require("antiadblockInit").initAntiAdblockNoti fication;
58 var parseFilters = require("filterValidation").parseFilters;
43 59
44 // Some types cannot be distinguished 60 // Some types cannot be distinguished
45 RegExpFilter.typeMap.OBJECT_SUBREQUEST = RegExpFilter.typeMap.OBJECT; 61 RegExpFilter.typeMap.OBJECT_SUBREQUEST = RegExpFilter.typeMap.OBJECT;
46 RegExpFilter.typeMap.MEDIA = RegExpFilter.typeMap.FONT = RegExpFilter.typeMap.OT HER; 62 RegExpFilter.typeMap.MEDIA = RegExpFilter.typeMap.FONT = RegExpFilter.typeMap.OT HER;
47 63
48 var isFirstRun = false; 64 // Chrome on Linux does not fully support chrome.notifications until version 35
65 // https://code.google.com/p/chromium/issues/detail?id=291485
66 var canUseChromeNotifications = require("info").platform == "chromium"
67 && "notifications" in chrome
68 && (navigator.platform.indexOf("Linux") == -1 || parseInt(require("info").appl icationVersion, 10) > 34);
69
49 var seenDataCorruption = false; 70 var seenDataCorruption = false;
71 var filterlistsReinitialized = false;
50 require("filterNotifier").FilterNotifier.addListener(function(action) 72 require("filterNotifier").FilterNotifier.addListener(function(action)
51 { 73 {
52 if (action == "load") 74 if (action == "load")
53 { 75 {
54 var importingOldData = importOldData();
55
56 var addonVersion = require("info").addonVersion; 76 var addonVersion = require("info").addonVersion;
57 var prevVersion = localStorage.currentVersion; 77 var prevVersion = ext.storage.currentVersion;
58 if (prevVersion != addonVersion) 78
59 { 79 // There are no filters stored so we need to reinitialize all filterlists
60 isFirstRun = !prevVersion; 80 if (!FilterStorage.firstRun && FilterStorage.subscriptions.length === 0)
61 localStorage.currentVersion = addonVersion; 81 {
62 if (!importingOldData) 82 filterlistsReinitialized = true;
63 addSubscription(prevVersion); 83 prevVersion = null;
64 } 84 }
85
86 if (prevVersion != addonVersion || FilterStorage.firstRun)
87 {
88 seenDataCorruption = prevVersion && FilterStorage.firstRun;
89 ext.storage.currentVersion = addonVersion;
90 addSubscription(prevVersion);
91 }
92
93 if (canUseChromeNotifications)
94 initChromeNotifications();
95 initAntiAdblockNotification();
96
97 // The "Hide placeholders" option has been removed from the UI in 1.8.8.1285
98 // So we reset the option for users updating from older versions.
99 if (prevVersion && Services.vc.compare(prevVersion, "1.8.8.1285") < 0)
100 Prefs.hidePlaceholders = true;
65 } 101 }
66 102
67 // update browser actions when whitelisting might have changed, 103 // update browser actions when whitelisting might have changed,
68 // due to loading filters or saving filter changes 104 // due to loading filters or saving filter changes
69 if (action == "load" || action == "save") 105 if (action == "load" || action == "save")
70 { 106 refreshIconAndContextMenuForAllPages();
71 ext.windows.getAll(function(windows)
72 {
73 for (var i = 0; i < windows.length; i++)
74 {
75 windows[i].getAllTabs(function(tabs)
76 {
77 tabs.forEach(refreshIconAndContextMenu);
78 });
79 }
80 });
81 }
82 }); 107 });
83 108
84 // Special-case domains for which we cannot use style-based hiding rules. 109 // Special-case domains for which we cannot use style-based hiding rules.
85 // See http://crbug.com/68705. 110 // See http://crbug.com/68705.
86 var noStyleRulesHosts = ["mail.google.com", "mail.yahoo.com", "www.google.com"]; 111 var noStyleRulesHosts = ["mail.google.com", "mail.yahoo.com", "www.google.com"];
87 112
113 var htmlPages = new ext.PageMap();
114
88 function removeDeprecatedOptions() 115 function removeDeprecatedOptions()
89 { 116 {
90 var deprecatedOptions = ["specialCaseYouTube", "experimental", "disableInlineT extAds"]; 117 var deprecatedOptions = ["specialCaseYouTube", "experimental", "disableInlineT extAds"];
91 deprecatedOptions.forEach(function(option) 118 deprecatedOptions.forEach(function(option)
92 { 119 {
93 if (option in localStorage) 120 if (option in ext.storage)
94 delete localStorage[option]; 121 delete ext.storage[option];
95 }); 122 });
96 } 123 }
97 124
98 // Remove deprecated options before we do anything else. 125 // Remove deprecated options before we do anything else.
99 removeDeprecatedOptions(); 126 removeDeprecatedOptions();
100 127
101 var activeNotification = null; 128 var activeNotification = null;
102 129
103 function getTabStatus(tab) 130 var contextMenuItem = {
104 { 131 title: ext.i18n.getMessage("block_element"),
105 var whitelisted = isWhitelisted(tab.url); 132 contexts: ["image", "video", "audio"],
106 var animated = iconAnimation.tabs.has(tab); 133 onclick: function(page)
107 134 {
108 var icon; 135 page.sendMessage({type: "clickhide-new-filter"});
109 if (require("info").platform == "safari") 136 }
110 // pick an icon with approtiate size for Safari. However since 137 };
111 // toolbar item icons can't use different colors, we don't have 138
112 // different versions indicating whether the page is whitelisted 139 // Adds or removes browser action icon according to options.
113 icon = "icons/abp-16"; 140 function refreshIconAndContextMenu(page)
114 else 141 {
115 { 142 var whitelisted = isPageWhitelisted(page);
116 // pick an icon with the approtiate size for Chrome/Opera 143 updateIcon(page, whitelisted);
117 // that indicates whether the page is whitelisted
118 if (whitelisted && (!animated || iconAnimation.step < 10))
119 icon = "icons/abp-19-whitelisted";
120 else
121 icon = "icons/abp-19";
122 }
123
124 // pick the current frame if the icon is currently animating
125 // in order to indicate a pending notification
126 if (animated && iconAnimation.step > 0)
127 {
128 icon += "-notification-" + iconAnimation.severity;
129
130 if (iconAnimation.step < 10)
131 icon += "-" + iconAnimation.step;
132 }
133
134 icon += ".png";
135
136 return {icon: icon, whitelisted: whitelisted};
137 }
138
139 function refreshIconAndContextMenu(tab)
140 {
141 var status = getTabStatus(tab);
142
143 // update icon indicating whether the page is whitelisted.
144 tab.browserAction.setIcon(status.icon);
145 144
146 // show or hide the context menu entry dependent on whether 145 // show or hide the context menu entry dependent on whether
147 // adblocking is active in that tab 146 // adblocking is active on that page
148 if (status.whitelisted || !/^https?:/.test(tab.url)) 147 page.contextMenus.removeAll();
149 ext.contextMenus.hideMenuItems(); 148 if (Prefs.shouldShowBlockElementMenu && !whitelisted && htmlPages.has(page))
150 else 149 page.contextMenus.create(contextMenuItem);
151 ext.contextMenus.showMenuItems(); 150 }
152 } 151
153 152 function refreshIconAndContextMenuForAllPages()
154 /** 153 {
155 * Old versions for Opera stored patterns.ini in the localStorage object, this 154 ext.pages.query({}, function(pages)
156 * will import it into FilterStorage properly. 155 {
157 * @return {Boolean} true if data import is in progress 156 pages.forEach(refreshIconAndContextMenu);
158 */ 157 });
159 function importOldData()
160 {
161 if ("patterns.ini" in localStorage)
162 {
163 FilterStorage.loadFromDisk(localStorage["patterns.ini"]);
164
165 var remove = [];
166 for (var key in localStorage)
167 if (key.indexOf("patterns.ini") == 0 || key.indexOf("patterns-backup") == 0)
168 remove.push(key);
169 for (var i = 0; i < remove.length; i++)
170 delete localStorage[remove[i]];
171
172 return true;
173 }
174 else
175 return false;
176 } 158 }
177 159
178 /** 160 /**
179 * This function is called on an extension update. It will add the default 161 * This function is called on an extension update. It will add the default
180 * filter subscription if necessary. 162 * filter subscription if necessary.
181 */ 163 */
182 function addSubscription(prevVersion) 164 function addSubscription(prevVersion)
183 { 165 {
184 // Make sure to remove "Recommended filters", no longer necessary 166 // Make sure to remove "Recommended filters", no longer necessary
185 var toRemove = "https://easylist-downloads.adblockplus.org/chrome_supplement.t xt"; 167 var toRemove = "https://easylist-downloads.adblockplus.org/chrome_supplement.t xt";
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
221 { 203 {
222 subscription.title = "Allow non-intrusive advertising"; 204 subscription.title = "Allow non-intrusive advertising";
223 FilterStorage.addSubscription(subscription); 205 FilterStorage.addSubscription(subscription);
224 if (subscription instanceof DownloadableSubscription && !subscription.last Download) 206 if (subscription instanceof DownloadableSubscription && !subscription.last Download)
225 Synchronizer.execute(subscription); 207 Synchronizer.execute(subscription);
226 } 208 }
227 else 209 else
228 addAcceptable = false; 210 addAcceptable = false;
229 } 211 }
230 212
213 // Add "anti-adblock messages" subscription for new users and users updating f rom old ABP versions
214 if (!prevVersion || Services.vc.compare(prevVersion, "1.8") < 0)
215 {
216 var subscription = Subscription.fromURL(Prefs.subscriptions_antiadblockurl);
217 if (subscription && !(subscription.url in FilterStorage.knownSubscriptions))
218 {
219 subscription.disabled = true;
220 FilterStorage.addSubscription(subscription);
221 if (subscription instanceof DownloadableSubscription && !subscription.last Download)
222 Synchronizer.execute(subscription);
223 }
224 }
225
231 if (!addSubscription && !addAcceptable) 226 if (!addSubscription && !addAcceptable)
232 return; 227 return;
233 228
234 function notifyUser() 229 function notifyUser()
235 { 230 {
236 ext.windows.getLastFocused(function(win) 231 ext.pages.open(ext.getURL("firstRun.html"));
237 {
238 win.openTab(ext.getURL("firstRun.html"));
239 });
240 } 232 }
241 233
242 if (addSubscription) 234 if (addSubscription)
243 { 235 {
244 // Load subscriptions data 236 // Load subscriptions data
245 var request = new XMLHttpRequest(); 237 var request = new XMLHttpRequest();
246 request.open("GET", "subscriptions.xml"); 238 request.open("GET", "subscriptions.xml");
247 request.addEventListener("load", function() 239 request.addEventListener("load", function()
248 { 240 {
249 var node = Utils.chooseFilterSubscription(request.responseXML.getElementsB yTagName("subscription")); 241 var node = Utils.chooseFilterSubscription(request.responseXML.getElementsB yTagName("subscription"));
250 var subscription = (node ? Subscription.fromURL(node.getAttribute("url")) : null); 242 var subscription = (node ? Subscription.fromURL(node.getAttribute("url")) : null);
251 if (subscription) 243 if (subscription)
252 { 244 {
253 FilterStorage.addSubscription(subscription); 245 FilterStorage.addSubscription(subscription);
254 subscription.disabled = false; 246 subscription.disabled = false;
255 subscription.title = node.getAttribute("title"); 247 subscription.title = node.getAttribute("title");
256 subscription.homepage = node.getAttribute("homepage"); 248 subscription.homepage = node.getAttribute("homepage");
257 if (subscription instanceof DownloadableSubscription && !subscription.la stDownload) 249 if (subscription instanceof DownloadableSubscription && !subscription.la stDownload)
258 Synchronizer.execute(subscription); 250 Synchronizer.execute(subscription);
259 251
260 notifyUser(); 252 notifyUser();
261 } 253 }
262 }, false); 254 }, false);
263 request.send(null); 255 request.send(null);
264 } 256 }
265 else 257 else
266 notifyUser(); 258 notifyUser();
267 } 259 }
268 260
269 function setContextMenu()
270 {
271 if (Prefs.shouldShowBlockElementMenu)
272 {
273 // Register context menu item
274 ext.contextMenus.addMenuItem(ext.i18n.getMessage("block_element"), ["image", "video", "audio"], function(srcUrl, tab)
275 {
276 if (srcUrl)
277 tab.sendMessage({type: "clickhide-new-filter", filter: srcUrl});
278 });
279 }
280 else
281 ext.contextMenus.removeMenuItems();
282 }
283
284 Prefs.addListener(function(name) 261 Prefs.addListener(function(name)
285 { 262 {
286 if (name == "shouldShowBlockElementMenu") 263 if (name == "shouldShowBlockElementMenu")
287 setContextMenu(); 264 refreshIconAndContextMenuForAllPages();
288 }); 265 });
289 setContextMenu();
290
291 /**
292 * Opens options tab or focuses an existing one, within the last focused window .
293 * @param {Function} callback function to be called with the
294 Tab object of the options tab
295 */
296 function openOptions(callback)
297 {
298 ext.windows.getLastFocused(function(win)
299 {
300 win.getAllTabs(function(tabs)
301 {
302 var optionsUrl = ext.getURL("options.html");
303
304 for (var i = 0; i < tabs.length; i++)
305 {
306 if (tabs[i].url == optionsUrl)
307 {
308 tabs[i].activate();
309 if (callback)
310 callback(tabs[i]);
311 return;
312 }
313 }
314
315 win.openTab(optionsUrl, callback && function(tab)
316 {
317 tab.onCompleted.addListener(callback);
318 });
319 });
320 });
321 }
322 266
323 function prepareNotificationIconAndPopup() 267 function prepareNotificationIconAndPopup()
324 { 268 {
269 var animateIcon = (activeNotification.type !== "question");
325 activeNotification.onClicked = function() 270 activeNotification.onClicked = function()
326 { 271 {
327 iconAnimation.stop(); 272 if (animateIcon)
328 activeNotification = null; 273 stopIconAnimation();
274 notificationClosed();
329 }; 275 };
330 iconAnimation.update(activeNotification.severity); 276 if (animateIcon)
331 } 277 startIconAnimation(activeNotification.type);
332 278 }
333 function openNotificationLinks() 279
280 function openNotificationLinks()
334 { 281 {
335 if (activeNotification.links) 282 if (activeNotification.links)
336 { 283 {
337 activeNotification.links.forEach(function(link) 284 activeNotification.links.forEach(function(link)
338 { 285 {
339 ext.windows.getLastFocused(function(win) 286 ext.windows.getLastFocused(function(win)
340 { 287 {
341 win.openTab(Utils.getDocLink(link)); 288 win.openTab(Utils.getDocLink(link));
342 }); 289 });
343 }); 290 });
344 } 291 }
345 } 292 }
346 293
347 function notificationButtonClick(id, index) 294 function notificationButtonClick(buttonIndex)
348 { 295 {
349 if (activeNotification.links && activeNotification.links[index]) 296 if (activeNotification.type === "question")
297 {
298 NotificationStorage.triggerQuestionListeners(activeNotification.id, buttonIn dex === 0);
299 NotificationStorage.markAsShown(activeNotification.id);
300 activeNotification.onClicked();
301 }
302 else if (activeNotification.links && activeNotification.links[buttonIndex])
350 { 303 {
351 ext.windows.getLastFocused(function(win) 304 ext.windows.getLastFocused(function(win)
352 { 305 {
353 win.openTab(Utils.getDocLink(activeNotification.links[index])); 306 win.openTab(Utils.getDocLink(activeNotification.links[buttonIndex]));
354 }); 307 });
355 } 308 }
356 } 309 }
357 310
311 function notificationClosed()
312 {
313 activeNotification = null;
314 }
315
316 function imgToBase64(url, callback)
317 {
318 var canvas = document.createElement("canvas"),
319 ctx = canvas.getContext("2d"),
320 img = new Image;
321 img.src = url;
322 img.onload = function()
323 {
324 canvas.height = img.height;
325 canvas.width = img.width;
326 ctx.drawImage(img, 0, 0);
327 callback(canvas.toDataURL("image/png"));
328 canvas = null;
329 };
330 }
331
332 function initChromeNotifications()
333 {
334 // Chrome hides notifications in notification center when clicked so we need t o clear them
335 function clearActiveNotification(notificationId)
336 {
337 if (activeNotification && activeNotification.type != "question" && !("links" in activeNotification))
338 return;
339
340 chrome.notifications.clear(notificationId, function(wasCleared)
341 {
342 if (wasCleared)
343 notificationClosed();
344 });
345 }
346
347 chrome.notifications.onButtonClicked.addListener(function(notificationId, butt onIndex)
348 {
349 notificationButtonClick(buttonIndex);
350 clearActiveNotification(notificationId);
351 });
352 chrome.notifications.onClicked.addListener(clearActiveNotification);
353 chrome.notifications.onClosed.addListener(notificationClosed);
354 }
355
358 function showNotification(notification) 356 function showNotification(notification)
359 { 357 {
358 if (activeNotification && activeNotification.id === notification.id)
359 return;
360
360 activeNotification = notification; 361 activeNotification = notification;
361 if (activeNotification.severity === "critical") 362 if (activeNotification.type === "critical" || activeNotification.type === "que stion")
362 { 363 {
363 var hasWebkitNotifications = typeof webkitNotifications !== "undefined"; 364 var texts = NotificationStorage.getLocalizedTexts(notification);
364 if (hasWebkitNotifications && "createHTMLNotification" in webkitNotification s)
365 {
366 var notification = webkitNotifications.createHTMLNotification("notificatio n.html");
367 notification.show();
368 notification.addEventListener("close", prepareNotificationIconAndPopup, fa lse);
369 return;
370 }
371
372 var texts = Notification.getLocalizedTexts(notification);
373 var title = texts.title || ""; 365 var title = texts.title || "";
374 var message = texts.message ? texts.message.replace(/<\/?(a|strong)>/g, "") : ""; 366 var message = texts.message ? texts.message.replace(/<\/?(a|strong)>/g, "") : "";
375 var iconUrl = ext.getURL("icons/abp-128.png"); 367 var iconUrl = ext.getURL("icons/abp-128.png");
376 var hasLinks = activeNotification.links && activeNotification.links.length > 0; 368 var hasLinks = activeNotification.links && activeNotification.links.length > 0;
377 // Chrome on Linux does not fully support chrome.notifications yet 369
378 // https://code.google.com/p/chromium/issues/detail?id=291485 370 if (canUseChromeNotifications)
379 if (require("info").platform == "chromium" &&
380 "notifications" in chrome &&
381 navigator.platform.indexOf("Linux") == -1)
382 { 371 {
383 var opts = { 372 var opts = {
384 type: "basic", 373 type: "basic",
385 title: title, 374 title: title,
386 message: message, 375 message: message,
387 iconUrl: iconUrl, 376 buttons: [],
388 buttons: [] 377 priority: 2 // We use the highest priority to prevent the notification f rom closing automatically
389 }; 378 };
390 var regex = /<a>(.*?)<\/a>/g; 379 if (activeNotification.type === "question")
391 var plainMessage = texts.message || ""; 380 {
392 var match; 381 opts.buttons.push({title: ext.i18n.getMessage("overlay_notification_butt on_yes")});
393 while (match = regex.exec(plainMessage)) 382 opts.buttons.push({title: ext.i18n.getMessage("overlay_notification_butt on_no")});
394 opts.buttons.push({title: match[1]}); 383 }
395 384 else
396 var notification = chrome.notifications; 385 {
397 notification.create("", opts, function() {}); 386 var regex = /<a>(.*?)<\/a>/g;
398 notification.onClosed.addListener(prepareNotificationIconAndPopup); 387 var plainMessage = texts.message || "";
399 notification.onButtonClicked.addListener(notificationButtonClick); 388 var match;
400 } 389 while (match = regex.exec(plainMessage))
401 else if (hasWebkitNotifications && "createNotification" in webkitNotificatio ns) 390 opts.buttons.push({title: match[1]});
391 }
392
393 imgToBase64(iconUrl, function(iconData)
394 {
395 opts["iconUrl"] = iconData;
396 chrome.notifications.create("", opts, function() {});
397 });
398 }
399 else if ("Notification" in window && activeNotification.type !== "question")
402 { 400 {
403 if (hasLinks) 401 if (hasLinks)
404 message += " " + ext.i18n.getMessage("notification_without_buttons"); 402 message += " " + ext.i18n.getMessage("notification_without_buttons");
405 403
406 var notification = webkitNotifications.createNotification(iconUrl, title, message); 404 imgToBase64(iconUrl, function(iconData)
407 notification.show(); 405 {
408 notification.addEventListener("close", prepareNotificationIconAndPopup, fa lse); 406 var notification = new Notification(
409 notification.addEventListener("click", openNotificationLinks, false); 407 title,
408 {
409 lang: Utils.appLocale,
410 dir: ext.i18n.getMessage("@@bidi_dir"),
411 body: message,
412 icon: iconData
413 }
414 );
415
416 notification.addEventListener("click", openNotificationLinks);
417 notification.addEventListener("close", notificationClosed);
418 });
410 } 419 }
411 else 420 else
412 { 421 {
413 var message = title + "\n" + message; 422 var message = title + "\n" + message;
414 if (hasLinks) 423 if (hasLinks)
415 message += "\n\n" + ext.i18n.getMessage("notification_with_buttons"); 424 message += "\n\n" + ext.i18n.getMessage("notification_with_buttons");
416 425
417 if (confirm(message)) 426 var approved = confirm(message);
427 if (activeNotification.type === "question")
428 notificationButtonClick(approved ? 0 : 1);
429 else if (approved)
418 openNotificationLinks(); 430 openNotificationLinks();
419 prepareNotificationIconAndPopup(); 431 }
420 } 432 }
421 } 433 prepareNotificationIconAndPopup();
422 else 434 }
423 prepareNotificationIconAndPopup(); 435
436 // This is a hack to speedup loading of the options page on Safari.
437 // Once we replaced the background page proxy with message passing
438 // this global function should removed.
439 function getUserFilters()
440 {
441 var filters = [];
442 var exceptions = [];
443
444 for (var i = 0; i < FilterStorage.subscriptions.length; i++)
445 {
446 var subscription = FilterStorage.subscriptions[i];
447 if (!(subscription instanceof SpecialSubscription))
448 continue;
449
450 for (var j = 0; j < subscription.filters.length; j++)
451 {
452 var filter = subscription.filters[j];
453 if (filter instanceof WhitelistFilter && /^@@\|\|([^\/:]+)\^\$document$/. test(filter.text))
454 exceptions.push(RegExp.$1);
455 else
456 filters.push(filter.text);
457 }
458 }
459
460 return {filters: filters, exceptions: exceptions};
424 } 461 }
425 462
426 ext.onMessage.addListener(function (msg, sender, sendResponse) 463 ext.onMessage.addListener(function (msg, sender, sendResponse)
427 { 464 {
428 switch (msg.type) 465 switch (msg.type)
429 { 466 {
430 case "get-selectors": 467 case "get-selectors":
431 var selectors = null; 468 var selectors = [];
432 469
433 if (!isFrameWhitelisted(sender.tab, sender.frame, "DOCUMENT") && 470 if (!isFrameWhitelisted(sender.page, sender.frame, "DOCUMENT") &&
434 !isFrameWhitelisted(sender.tab, sender.frame, "ELEMHIDE")) 471 !isFrameWhitelisted(sender.page, sender.frame, "ELEMHIDE"))
435 { 472 {
436 var noStyleRules = false; 473 var noStyleRules = false;
437 var host = extractHostFromURL(sender.frame.url); 474 var host = extractHostFromFrame(sender.frame);
438 for (var i = 0; i < noStyleRulesHosts.length; i++) 475 for (var i = 0; i < noStyleRulesHosts.length; i++)
439 { 476 {
440 var noStyleHost = noStyleRulesHosts[i]; 477 var noStyleHost = noStyleRulesHosts[i];
441 if (host == noStyleHost || (host.length > noStyleHost.length && 478 if (host == noStyleHost || (host.length > noStyleHost.length &&
442 host.substr(host.length - noStyleHost.leng th - 1) == "." + noStyleHost)) 479 host.substr(host.length - noStyleHost.leng th - 1) == "." + noStyleHost))
443 { 480 {
444 noStyleRules = true; 481 noStyleRules = true;
445 } 482 }
446 } 483 }
447 selectors = ElemHide.getSelectorsForDomain(host, false); 484 selectors = ElemHide.getSelectorsForDomain(host, false);
448 if (noStyleRules) 485 if (noStyleRules)
449 { 486 {
450 selectors = selectors.filter(function(s) 487 selectors = selectors.filter(function(s)
451 { 488 {
452 return !/\[style[\^\$]?=/.test(s); 489 return !/\[style[\^\$]?=/.test(s);
453 }); 490 });
454 } 491 }
455 } 492 }
456 493
457 sendResponse(selectors); 494 sendResponse(selectors);
458 break; 495 break;
459 case "should-collapse": 496 case "should-collapse":
460 if (isFrameWhitelisted(sender.tab, sender.frame, "DOCUMENT")) 497 if (isFrameWhitelisted(sender.page, sender.frame, "DOCUMENT"))
461 { 498 {
462 sendResponse(false); 499 sendResponse(false);
463 break; 500 break;
464 } 501 }
465 502
466 var requestHost = extractHostFromURL(msg.url); 503 var url = new URL(msg.url);
467 var documentHost = extractHostFromURL(sender.frame.url); 504 var documentHost = extractHostFromFrame(sender.frame);
468 var thirdParty = isThirdParty(requestHost, documentHost); 505 var filter = defaultMatcher.matchesAny(
469 var filter = defaultMatcher.matchesAny(msg.url, msg.mediatype, documentHos t, thirdParty); 506 stringifyURL(url), msg.mediatype,
507 documentHost, isThirdParty(url, documentHost)
508 );
509
470 if (filter instanceof BlockingFilter) 510 if (filter instanceof BlockingFilter)
471 { 511 {
472 var collapse = filter.collapse; 512 var collapse = filter.collapse;
473 if (collapse == null) 513 if (collapse == null)
474 collapse = Prefs.hidePlaceholders; 514 collapse = Prefs.hidePlaceholders;
475 sendResponse(collapse); 515 sendResponse(collapse);
476 } 516 }
477 else 517 else
478 sendResponse(false); 518 sendResponse(false);
479 break; 519 break;
480 case "get-domain-enabled-state": 520 case "get-domain-enabled-state":
481 // Returns whether this domain is in the exclusion list. 521 // Returns whether this domain is in the exclusion list.
482 // The browser action popup asks us this. 522 // The browser action popup asks us this.
483 if(sender.tab) 523 if(sender.page)
484 { 524 {
485 sendResponse({enabled: !isWhitelisted(sender.tab.url)}); 525 sendResponse({enabled: !isPageWhitelisted(sender.page)});
486 return; 526 return;
487 } 527 }
488 break; 528 break;
489 case "add-filters": 529 case "add-filters":
490 if (msg.filters && msg.filters.length) 530 var filters;
491 { 531 try
492 for (var i = 0; i < msg.filters.length; i++) 532 {
493 FilterStorage.addFilter(Filter.fromText(msg.filters[i])); 533 filters = parseFilters(msg.text);
494 } 534 }
535 catch (error)
536 {
537 sendResponse({status: "invalid", error: error});
538 break;
539 }
540
541 for (var i = 0; i < filters.length; i++)
542 FilterStorage.addFilter(filters[i]);
543
544 sendResponse({status: "ok"});
495 break; 545 break;
496 case "add-subscription": 546 case "add-subscription":
497 openOptions(function(tab) 547 ext.showOptions(function(page)
498 { 548 {
499 tab.sendMessage(msg); 549 page.sendMessage(msg);
500 }); 550 });
501 break; 551 break;
502 case "add-key-exception": 552 case "add-sitekey":
503 processKeyException(msg.token, sender.tab, sender.frame); 553 processKey(msg.token, sender.page, sender.frame);
554 break;
555 case "report-html-page":
556 htmlPages.set(sender.page, null);
557 refreshIconAndContextMenu(sender.page);
504 break; 558 break;
505 case "forward": 559 case "forward":
506 if (sender.tab) 560 if (sender.page)
507 { 561 {
508 sender.tab.sendMessage(msg.payload, sendResponse); 562 if (msg.expectsResponse)
509 // Return true to indicate that we want to call 563 {
510 // sendResponse asynchronously 564 sender.page.sendMessage(msg.payload, sendResponse);
511 return true; 565 return true;
512 } 566 }
513 break; 567
514 default: 568 sender.page.sendMessage(msg.payload);
515 sendResponse({}); 569 }
516 break; 570 break;
517 } 571 }
518 }); 572 });
519 573
520 // Update icon if a tab changes location 574 // update icon when page changes location
521 ext.tabs.onLoading.addListener(function(tab) 575 ext.pages.onLoading.addListener(function(page)
522 { 576 {
523 tab.sendMessage({type: "clickhide-deactivate"}); 577 page.sendMessage({type: "clickhide-deactivate"});
524 refreshIconAndContextMenu(tab); 578 refreshIconAndContextMenu(page);
525 }); 579 });
526 580
527 setTimeout(function() 581 setTimeout(function()
528 { 582 {
529 var notificationToShow = Notification.getNextToShow(); 583 var notificationToShow = NotificationStorage.getNextToShow();
530 if (notificationToShow) 584 if (notificationToShow)
531 showNotification(notificationToShow); 585 showNotification(notificationToShow);
532 }, 3 * 60 * 1000); 586 }, 3 * 60 * 1000);
LEFTRIGHT
« no previous file | lib/icon.js » ('j') | Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Toggle Comments ('s')

Powered by Google App Engine
This is Rietveld