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: Rabased and addressed comments Created March 6, 2014, 8:38 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 // But don't interfere the icon animation if active.
145 // In that case the icon animation takes care to update
146 // the icon to its new status with its next frame.
147 if (!iconAnimation.tabs.has(tab))
148 tab.browserAction.setIcon(status.icon);
149 144
150 // show or hide the context menu entry dependent on whether 145 // show or hide the context menu entry dependent on whether
151 // adblocking is active in that tab 146 // adblocking is active on that page
152 if (status.whitelisted || !/^https?:/.test(tab.url)) 147 page.contextMenus.removeAll();
153 ext.contextMenus.hideMenuItems(); 148 if (Prefs.shouldShowBlockElementMenu && !whitelisted && htmlPages.has(page))
154 else 149 page.contextMenus.create(contextMenuItem);
155 ext.contextMenus.showMenuItems(); 150 }
156 } 151
157 152 function refreshIconAndContextMenuForAllPages()
158 /** 153 {
159 * Old versions for Opera stored patterns.ini in the localStorage object, this 154 ext.pages.query({}, function(pages)
160 * will import it into FilterStorage properly. 155 {
161 * @return {Boolean} true if data import is in progress 156 pages.forEach(refreshIconAndContextMenu);
162 */ 157 });
163 function importOldData()
164 {
165 if ("patterns.ini" in localStorage)
166 {
167 FilterStorage.loadFromDisk(localStorage["patterns.ini"]);
168
169 var remove = [];
170 for (var key in localStorage)
171 if (key.indexOf("patterns.ini") == 0 || key.indexOf("patterns-backup") == 0)
172 remove.push(key);
173 for (var i = 0; i < remove.length; i++)
174 delete localStorage[remove[i]];
175
176 return true;
177 }
178 else
179 return false;
180 } 158 }
181 159
182 /** 160 /**
183 * 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
184 * filter subscription if necessary. 162 * filter subscription if necessary.
185 */ 163 */
186 function addSubscription(prevVersion) 164 function addSubscription(prevVersion)
187 { 165 {
188 // Make sure to remove "Recommended filters", no longer necessary 166 // Make sure to remove "Recommended filters", no longer necessary
189 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
225 { 203 {
226 subscription.title = "Allow non-intrusive advertising"; 204 subscription.title = "Allow non-intrusive advertising";
227 FilterStorage.addSubscription(subscription); 205 FilterStorage.addSubscription(subscription);
228 if (subscription instanceof DownloadableSubscription && !subscription.last Download) 206 if (subscription instanceof DownloadableSubscription && !subscription.last Download)
229 Synchronizer.execute(subscription); 207 Synchronizer.execute(subscription);
230 } 208 }
231 else 209 else
232 addAcceptable = false; 210 addAcceptable = false;
233 } 211 }
234 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
235 if (!addSubscription && !addAcceptable) 226 if (!addSubscription && !addAcceptable)
236 return; 227 return;
237 228
238 function notifyUser() 229 function notifyUser()
239 { 230 {
240 ext.windows.getLastFocused(function(win) 231 ext.pages.open(ext.getURL("firstRun.html"));
241 {
242 win.openTab(ext.getURL("firstRun.html"));
243 });
244 } 232 }
245 233
246 if (addSubscription) 234 if (addSubscription)
247 { 235 {
248 // Load subscriptions data 236 // Load subscriptions data
249 var request = new XMLHttpRequest(); 237 var request = new XMLHttpRequest();
250 request.open("GET", "subscriptions.xml"); 238 request.open("GET", "subscriptions.xml");
251 request.addEventListener("load", function() 239 request.addEventListener("load", function()
252 { 240 {
253 var node = Utils.chooseFilterSubscription(request.responseXML.getElementsB yTagName("subscription")); 241 var node = Utils.chooseFilterSubscription(request.responseXML.getElementsB yTagName("subscription"));
254 var subscription = (node ? Subscription.fromURL(node.getAttribute("url")) : null); 242 var subscription = (node ? Subscription.fromURL(node.getAttribute("url")) : null);
255 if (subscription) 243 if (subscription)
256 { 244 {
257 FilterStorage.addSubscription(subscription); 245 FilterStorage.addSubscription(subscription);
258 subscription.disabled = false; 246 subscription.disabled = false;
259 subscription.title = node.getAttribute("title"); 247 subscription.title = node.getAttribute("title");
260 subscription.homepage = node.getAttribute("homepage"); 248 subscription.homepage = node.getAttribute("homepage");
261 if (subscription instanceof DownloadableSubscription && !subscription.la stDownload) 249 if (subscription instanceof DownloadableSubscription && !subscription.la stDownload)
262 Synchronizer.execute(subscription); 250 Synchronizer.execute(subscription);
263 251
264 notifyUser(); 252 notifyUser();
265 } 253 }
266 }, false); 254 }, false);
267 request.send(null); 255 request.send(null);
268 } 256 }
269 else 257 else
270 notifyUser(); 258 notifyUser();
271 } 259 }
272 260
273 function setContextMenu()
274 {
275 if (Prefs.shouldShowBlockElementMenu)
276 {
277 // Register context menu item
278 ext.contextMenus.addMenuItem(ext.i18n.getMessage("block_element"), ["image", "video", "audio"], function(srcUrl, tab)
279 {
280 if (srcUrl)
281 tab.sendMessage({type: "clickhide-new-filter", filter: srcUrl});
282 });
283 }
284 else
285 ext.contextMenus.removeMenuItems();
286 }
287
288 Prefs.addListener(function(name) 261 Prefs.addListener(function(name)
289 { 262 {
290 if (name == "shouldShowBlockElementMenu") 263 if (name == "shouldShowBlockElementMenu")
291 setContextMenu(); 264 refreshIconAndContextMenuForAllPages();
292 }); 265 });
293 setContextMenu();
294
295 /**
296 * Opens options tab or focuses an existing one, within the last focused window .
297 * @param {Function} callback function to be called with the
298 Tab object of the options tab
299 */
300 function openOptions(callback)
301 {
302 ext.windows.getLastFocused(function(win)
303 {
304 win.getAllTabs(function(tabs)
305 {
306 var optionsUrl = ext.getURL("options.html");
307
308 for (var i = 0; i < tabs.length; i++)
309 {
310 if (tabs[i].url == optionsUrl)
311 {
312 tabs[i].activate();
313 if (callback)
314 callback(tabs[i]);
315 return;
316 }
317 }
318
319 win.openTab(optionsUrl, callback && function(tab)
320 {
321 tab.onCompleted.addListener(callback);
322 });
323 });
324 });
325 }
326 266
327 function prepareNotificationIconAndPopup() 267 function prepareNotificationIconAndPopup()
328 { 268 {
269 var animateIcon = (activeNotification.type !== "question");
329 activeNotification.onClicked = function() 270 activeNotification.onClicked = function()
330 { 271 {
331 iconAnimation.stop(); 272 if (animateIcon)
332 activeNotification = null; 273 stopIconAnimation();
274 notificationClosed();
333 }; 275 };
334 iconAnimation.update(activeNotification.severity); 276 if (animateIcon)
335 } 277 startIconAnimation(activeNotification.type);
336 278 }
337 function openNotificationLinks() 279
280 function openNotificationLinks()
338 { 281 {
339 if (activeNotification.links) 282 if (activeNotification.links)
340 { 283 {
341 activeNotification.links.forEach(function(link) 284 activeNotification.links.forEach(function(link)
342 { 285 {
343 ext.windows.getLastFocused(function(win) 286 ext.windows.getLastFocused(function(win)
344 { 287 {
345 win.openTab(Utils.getDocLink(link)); 288 win.openTab(Utils.getDocLink(link));
346 }); 289 });
347 }); 290 });
348 } 291 }
349 } 292 }
350 293
351 function notificationButtonClick(id, index) 294 function notificationButtonClick(buttonIndex)
352 { 295 {
353 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])
354 { 303 {
355 ext.windows.getLastFocused(function(win) 304 ext.windows.getLastFocused(function(win)
356 { 305 {
357 win.openTab(Utils.getDocLink(activeNotification.links[index])); 306 win.openTab(Utils.getDocLink(activeNotification.links[buttonIndex]));
358 }); 307 });
359 } 308 }
360 } 309 }
361 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
362 function showNotification(notification) 356 function showNotification(notification)
363 { 357 {
358 if (activeNotification && activeNotification.id === notification.id)
359 return;
360
364 activeNotification = notification; 361 activeNotification = notification;
365 if (activeNotification.severity === "critical") 362 if (activeNotification.type === "critical" || activeNotification.type === "que stion")
366 { 363 {
367 var hasWebkitNotifications = typeof webkitNotifications !== "undefined"; 364 var texts = NotificationStorage.getLocalizedTexts(notification);
368 if (hasWebkitNotifications && "createHTMLNotification" in webkitNotification s)
369 {
370 var notification = webkitNotifications.createHTMLNotification("notificatio n.html");
371 notification.show();
372 notification.addEventListener("close", prepareNotificationIconAndPopup, fa lse);
373 return;
374 }
375
376 var texts = Notification.getLocalizedTexts(notification);
377 var title = texts.title || ""; 365 var title = texts.title || "";
378 var message = texts.message ? texts.message.replace(/<\/?(a|strong)>/g, "") : ""; 366 var message = texts.message ? texts.message.replace(/<\/?(a|strong)>/g, "") : "";
379 var iconUrl = ext.getURL("icons/abp-128.png"); 367 var iconUrl = ext.getURL("icons/abp-128.png");
380 var hasLinks = activeNotification.links && activeNotification.links.length > 0; 368 var hasLinks = activeNotification.links && activeNotification.links.length > 0;
381 // Chrome on Linux does not fully support chrome.notifications yet 369
382 // https://code.google.com/p/chromium/issues/detail?id=291485 370 if (canUseChromeNotifications)
383 if (require("info").platform == "chromium" &&
384 "notifications" in chrome &&
385 navigator.platform.indexOf("Linux") == -1)
386 { 371 {
387 var opts = { 372 var opts = {
388 type: "basic", 373 type: "basic",
389 title: title, 374 title: title,
390 message: message, 375 message: message,
391 iconUrl: iconUrl, 376 buttons: [],
392 buttons: [] 377 priority: 2 // We use the highest priority to prevent the notification f rom closing automatically
393 }; 378 };
394 var regex = /<a>(.*?)<\/a>/g; 379 if (activeNotification.type === "question")
395 var plainMessage = texts.message || ""; 380 {
396 var match; 381 opts.buttons.push({title: ext.i18n.getMessage("overlay_notification_butt on_yes")});
397 while (match = regex.exec(plainMessage)) 382 opts.buttons.push({title: ext.i18n.getMessage("overlay_notification_butt on_no")});
398 opts.buttons.push({title: match[1]}); 383 }
399 384 else
400 var notification = chrome.notifications; 385 {
401 notification.create("", opts, function() {}); 386 var regex = /<a>(.*?)<\/a>/g;
402 notification.onClosed.addListener(prepareNotificationIconAndPopup); 387 var plainMessage = texts.message || "";
403 notification.onButtonClicked.addListener(notificationButtonClick); 388 var match;
404 } 389 while (match = regex.exec(plainMessage))
405 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")
406 { 400 {
407 if (hasLinks) 401 if (hasLinks)
408 message += " " + ext.i18n.getMessage("notification_without_buttons"); 402 message += " " + ext.i18n.getMessage("notification_without_buttons");
409 403
410 var notification = webkitNotifications.createNotification(iconUrl, title, message); 404 imgToBase64(iconUrl, function(iconData)
411 notification.show(); 405 {
412 notification.addEventListener("close", prepareNotificationIconAndPopup, fa lse); 406 var notification = new Notification(
413 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 });
414 } 419 }
415 else 420 else
416 { 421 {
417 var message = title + "\n" + message; 422 var message = title + "\n" + message;
418 if (hasLinks) 423 if (hasLinks)
419 message += "\n\n" + ext.i18n.getMessage("notification_with_buttons"); 424 message += "\n\n" + ext.i18n.getMessage("notification_with_buttons");
420 425
421 if (confirm(message)) 426 var approved = confirm(message);
427 if (activeNotification.type === "question")
428 notificationButtonClick(approved ? 0 : 1);
429 else if (approved)
422 openNotificationLinks(); 430 openNotificationLinks();
423 prepareNotificationIconAndPopup(); 431 }
424 } 432 }
425 } 433 prepareNotificationIconAndPopup();
426 else 434 }
427 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};
428 } 461 }
429 462
430 ext.onMessage.addListener(function (msg, sender, sendResponse) 463 ext.onMessage.addListener(function (msg, sender, sendResponse)
431 { 464 {
432 switch (msg.type) 465 switch (msg.type)
433 { 466 {
434 case "get-selectors": 467 case "get-selectors":
435 var selectors = null; 468 var selectors = [];
436 469
437 if (!isFrameWhitelisted(sender.tab, sender.frame, "DOCUMENT") && 470 if (!isFrameWhitelisted(sender.page, sender.frame, "DOCUMENT") &&
438 !isFrameWhitelisted(sender.tab, sender.frame, "ELEMHIDE")) 471 !isFrameWhitelisted(sender.page, sender.frame, "ELEMHIDE"))
439 { 472 {
440 var noStyleRules = false; 473 var noStyleRules = false;
441 var host = extractHostFromURL(sender.frame.url); 474 var host = extractHostFromFrame(sender.frame);
442 for (var i = 0; i < noStyleRulesHosts.length; i++) 475 for (var i = 0; i < noStyleRulesHosts.length; i++)
443 { 476 {
444 var noStyleHost = noStyleRulesHosts[i]; 477 var noStyleHost = noStyleRulesHosts[i];
445 if (host == noStyleHost || (host.length > noStyleHost.length && 478 if (host == noStyleHost || (host.length > noStyleHost.length &&
446 host.substr(host.length - noStyleHost.leng th - 1) == "." + noStyleHost)) 479 host.substr(host.length - noStyleHost.leng th - 1) == "." + noStyleHost))
447 { 480 {
448 noStyleRules = true; 481 noStyleRules = true;
449 } 482 }
450 } 483 }
451 selectors = ElemHide.getSelectorsForDomain(host, false); 484 selectors = ElemHide.getSelectorsForDomain(host, false);
452 if (noStyleRules) 485 if (noStyleRules)
453 { 486 {
454 selectors = selectors.filter(function(s) 487 selectors = selectors.filter(function(s)
455 { 488 {
456 return !/\[style[\^\$]?=/.test(s); 489 return !/\[style[\^\$]?=/.test(s);
457 }); 490 });
458 } 491 }
459 } 492 }
460 493
461 sendResponse(selectors); 494 sendResponse(selectors);
462 break; 495 break;
463 case "should-collapse": 496 case "should-collapse":
464 if (isFrameWhitelisted(sender.tab, sender.frame, "DOCUMENT")) 497 if (isFrameWhitelisted(sender.page, sender.frame, "DOCUMENT"))
465 { 498 {
466 sendResponse(false); 499 sendResponse(false);
467 break; 500 break;
468 } 501 }
469 502
470 var requestHost = extractHostFromURL(msg.url); 503 var url = new URL(msg.url);
471 var documentHost = extractHostFromURL(sender.frame.url); 504 var documentHost = extractHostFromFrame(sender.frame);
472 var thirdParty = isThirdParty(requestHost, documentHost); 505 var filter = defaultMatcher.matchesAny(
473 var filter = defaultMatcher.matchesAny(msg.url, msg.mediatype, documentHos t, thirdParty); 506 stringifyURL(url), msg.mediatype,
507 documentHost, isThirdParty(url, documentHost)
508 );
509
474 if (filter instanceof BlockingFilter) 510 if (filter instanceof BlockingFilter)
475 { 511 {
476 var collapse = filter.collapse; 512 var collapse = filter.collapse;
477 if (collapse == null) 513 if (collapse == null)
478 collapse = Prefs.hidePlaceholders; 514 collapse = Prefs.hidePlaceholders;
479 sendResponse(collapse); 515 sendResponse(collapse);
480 } 516 }
481 else 517 else
482 sendResponse(false); 518 sendResponse(false);
483 break; 519 break;
484 case "get-domain-enabled-state": 520 case "get-domain-enabled-state":
485 // Returns whether this domain is in the exclusion list. 521 // Returns whether this domain is in the exclusion list.
486 // The browser action popup asks us this. 522 // The browser action popup asks us this.
487 if(sender.tab) 523 if(sender.page)
488 { 524 {
489 sendResponse({enabled: !isWhitelisted(sender.tab.url)}); 525 sendResponse({enabled: !isPageWhitelisted(sender.page)});
490 return; 526 return;
491 } 527 }
492 break; 528 break;
493 case "add-filters": 529 case "add-filters":
494 if (msg.filters && msg.filters.length) 530 var filters;
495 { 531 try
496 for (var i = 0; i < msg.filters.length; i++) 532 {
497 FilterStorage.addFilter(Filter.fromText(msg.filters[i])); 533 filters = parseFilters(msg.text);
498 } 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"});
499 break; 545 break;
500 case "add-subscription": 546 case "add-subscription":
501 openOptions(function(tab) 547 ext.showOptions(function(page)
502 { 548 {
503 tab.sendMessage(msg); 549 page.sendMessage(msg);
504 }); 550 });
505 break; 551 break;
506 case "add-key-exception": 552 case "add-sitekey":
507 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);
508 break; 558 break;
509 case "forward": 559 case "forward":
510 if (sender.tab) 560 if (sender.page)
511 { 561 {
512 sender.tab.sendMessage(msg.payload, sendResponse); 562 if (msg.expectsResponse)
513 // Return true to indicate that we want to call 563 {
514 // sendResponse asynchronously 564 sender.page.sendMessage(msg.payload, sendResponse);
515 return true; 565 return true;
516 } 566 }
517 break; 567
518 default: 568 sender.page.sendMessage(msg.payload);
519 sendResponse({}); 569 }
520 break; 570 break;
521 } 571 }
522 }); 572 });
523 573
524 // Update icon if a tab changes location 574 // update icon when page changes location
525 ext.tabs.onLoading.addListener(function(tab) 575 ext.pages.onLoading.addListener(function(page)
526 { 576 {
527 tab.sendMessage({type: "clickhide-deactivate"}); 577 page.sendMessage({type: "clickhide-deactivate"});
528 refreshIconAndContextMenu(tab); 578 refreshIconAndContextMenu(page);
529 }); 579 });
530 580
531 setTimeout(function() 581 setTimeout(function()
532 { 582 {
533 var notificationToShow = Notification.getNextToShow(); 583 var notificationToShow = NotificationStorage.getNextToShow();
534 if (notificationToShow) 584 if (notificationToShow)
535 showNotification(notificationToShow); 585 showNotification(notificationToShow);
536 }, 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