Left: | ||
Right: |
LEFT | RIGHT |
---|---|
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, animation) | 130 var contextMenuItem = { |
104 { | 131 title: ext.i18n.getMessage("block_element"), |
105 var whitelisted = isWhitelisted(tab.url); | 132 contexts: ["image", "video", "audio"], |
106 | 133 onclick: function(page) |
107 var icon; | 134 { |
108 if (require("info").platform == "safari") | 135 page.sendMessage({type: "clickhide-new-filter"}); |
109 // pick an icon with approtiate size for Safari. However since | 136 } |
110 // toolbar item icons can't use different colors, we don't have | 137 }; |
111 // different versions indicating whether the page is whitelisted | 138 |
112 icon = "icons/abp-16"; | 139 // Adds or removes browser action icon according to options. |
113 else | 140 function refreshIconAndContextMenu(page) |
114 { | 141 { |
115 // pick an icon with the approtiate size for Chrome/Opera | 142 var whitelisted = isPageWhitelisted(page); |
116 // that indicates whether the page is whitelisted | 143 updateIcon(page, whitelisted); |
117 if (whitelisted && (!animation || animation.step < 10)) | |
Felix Dahlke
2014/02/27 22:02:05
So we will use the red ABP icon if the animation s
Sebastian Noack
2014/02/28 08:35:16
We are neither going to use the red default nor th
| |
118 icon = "icons/abp-19-whitelisted"; | |
119 else | |
120 icon = "icons/abp-19"; | |
121 } | |
122 | |
123 // pick the current frame if the icon is currently animating | |
124 // in order to indicate a pending notification | |
125 if (animation && animation.step > 0) | |
126 { | |
127 icon += "-notification-"; | |
128 icon += animation.severity; | |
Wladimir Palant
2014/03/06 14:31:35
Nit: why split this to two statements? This seems
Sebastian Noack
2014/03/06 20:41:13
I found it slightly more readable to have one oper
| |
129 | |
130 if (animation.step < 10) | |
131 { | |
132 icon += "-"; | |
133 icon += animation.step; | |
134 } | |
135 } | |
136 | |
137 icon += ".png"; | |
138 | |
139 return {icon: icon, whitelisted: whitelisted}; | |
140 } | |
141 | |
142 function refreshIconAndContextMenu(tab) | |
143 { | |
144 var status = getTabStatus(tab); | |
145 | |
146 // update icon indicating whether the page is whitelisted. | |
147 // But don't interfere the icon animation if active. | |
Felix Dahlke
2014/02/27 22:02:05
s/interfere/interrupt/?
Sebastian Noack
2014/02/28 08:35:16
Don't know. It wouldn't just pause the animation,
Wladimir Palant
2014/03/06 14:31:35
If we now have a generic function to calculate the
Wladimir Palant
2014/03/06 14:34:33
In fact, this isn't even necessary. If iconAnimati
Sebastian Noack
2014/03/06 20:41:13
Done.
On 2014/03/06 14:34:33, Wladimir Palant wro
Wladimir Palant
2014/03/06 20:49:44
Isn't that exactly the issue that registerTab() wa
Sebastian Noack
2014/03/07 17:26:11
Now it is addressed within getTabStatus() as you s
Wladimir Palant
2014/03/07 22:13:29
Still missing something that would start the anima
Sebastian Noack
2014/03/08 11:36:39
Considering that the animation is interrupted anyw
Wladimir Palant
2014/03/21 14:10:11
Why interrupted? The animation step doesn't change
Sebastian Noack
2014/03/31 13:20:32
Since the icon is set per tab, when the active tab
| |
148 // In that case the icon animation takes care to update | |
149 // the icon to its new status with its next frame. | |
150 if (!iconAnimation.tabs.has(tab)) | |
151 tab.browserAction.setIcon(status.icon); | |
152 | 144 |
153 // show or hide the context menu entry dependent on whether | 145 // show or hide the context menu entry dependent on whether |
154 // adblocking is active in the tab | 146 // adblocking is active on that page |
155 if (status.whitelisted || !/^https?:/.test(tab.url)) | 147 page.contextMenus.removeAll(); |
156 ext.contextMenus.hideMenuItems(); | 148 if (Prefs.shouldShowBlockElementMenu && !whitelisted && htmlPages.has(page)) |
157 else | 149 page.contextMenus.create(contextMenuItem); |
158 ext.contextMenus.showMenuItems(); | 150 } |
159 } | 151 |
160 | 152 function refreshIconAndContextMenuForAllPages() |
161 /** | 153 { |
162 * Old versions for Opera stored patterns.ini in the localStorage object, this | 154 ext.pages.query({}, function(pages) |
163 * will import it into FilterStorage properly. | 155 { |
164 * @return {Boolean} true if data import is in progress | 156 pages.forEach(refreshIconAndContextMenu); |
165 */ | 157 }); |
166 function importOldData() | |
167 { | |
168 if ("patterns.ini" in localStorage) | |
169 { | |
170 FilterStorage.loadFromDisk(localStorage["patterns.ini"]); | |
171 | |
172 var remove = []; | |
173 for (var key in localStorage) | |
174 if (key.indexOf("patterns.ini") == 0 || key.indexOf("patterns-backup") == 0) | |
175 remove.push(key); | |
176 for (var i = 0; i < remove.length; i++) | |
177 delete localStorage[remove[i]]; | |
178 | |
179 return true; | |
180 } | |
181 else | |
182 return false; | |
183 } | 158 } |
184 | 159 |
185 /** | 160 /** |
186 * 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 |
187 * filter subscription if necessary. | 162 * filter subscription if necessary. |
188 */ | 163 */ |
189 function addSubscription(prevVersion) | 164 function addSubscription(prevVersion) |
190 { | 165 { |
191 // Make sure to remove "Recommended filters", no longer necessary | 166 // Make sure to remove "Recommended filters", no longer necessary |
192 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 Loading... | |
228 { | 203 { |
229 subscription.title = "Allow non-intrusive advertising"; | 204 subscription.title = "Allow non-intrusive advertising"; |
230 FilterStorage.addSubscription(subscription); | 205 FilterStorage.addSubscription(subscription); |
231 if (subscription instanceof DownloadableSubscription && !subscription.last Download) | 206 if (subscription instanceof DownloadableSubscription && !subscription.last Download) |
232 Synchronizer.execute(subscription); | 207 Synchronizer.execute(subscription); |
233 } | 208 } |
234 else | 209 else |
235 addAcceptable = false; | 210 addAcceptable = false; |
236 } | 211 } |
237 | 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 | |
238 if (!addSubscription && !addAcceptable) | 226 if (!addSubscription && !addAcceptable) |
239 return; | 227 return; |
240 | 228 |
241 function notifyUser() | 229 function notifyUser() |
242 { | 230 { |
243 ext.windows.getLastFocused(function(win) | 231 ext.pages.open(ext.getURL("firstRun.html")); |
244 { | |
245 win.openTab(ext.getURL("firstRun.html")); | |
246 }); | |
247 } | 232 } |
248 | 233 |
249 if (addSubscription) | 234 if (addSubscription) |
250 { | 235 { |
251 // Load subscriptions data | 236 // Load subscriptions data |
252 var request = new XMLHttpRequest(); | 237 var request = new XMLHttpRequest(); |
253 request.open("GET", "subscriptions.xml"); | 238 request.open("GET", "subscriptions.xml"); |
254 request.addEventListener("load", function() | 239 request.addEventListener("load", function() |
255 { | 240 { |
256 var node = Utils.chooseFilterSubscription(request.responseXML.getElementsB yTagName("subscription")); | 241 var node = Utils.chooseFilterSubscription(request.responseXML.getElementsB yTagName("subscription")); |
257 var subscription = (node ? Subscription.fromURL(node.getAttribute("url")) : null); | 242 var subscription = (node ? Subscription.fromURL(node.getAttribute("url")) : null); |
258 if (subscription) | 243 if (subscription) |
259 { | 244 { |
260 FilterStorage.addSubscription(subscription); | 245 FilterStorage.addSubscription(subscription); |
261 subscription.disabled = false; | 246 subscription.disabled = false; |
262 subscription.title = node.getAttribute("title"); | 247 subscription.title = node.getAttribute("title"); |
263 subscription.homepage = node.getAttribute("homepage"); | 248 subscription.homepage = node.getAttribute("homepage"); |
264 if (subscription instanceof DownloadableSubscription && !subscription.la stDownload) | 249 if (subscription instanceof DownloadableSubscription && !subscription.la stDownload) |
265 Synchronizer.execute(subscription); | 250 Synchronizer.execute(subscription); |
266 | 251 |
267 notifyUser(); | 252 notifyUser(); |
268 } | 253 } |
269 }, false); | 254 }, false); |
270 request.send(null); | 255 request.send(null); |
271 } | 256 } |
272 else | 257 else |
273 notifyUser(); | 258 notifyUser(); |
274 } | 259 } |
275 | 260 |
276 function setContextMenu() | |
277 { | |
278 if (Prefs.shouldShowBlockElementMenu) | |
279 { | |
280 // Register context menu item | |
281 ext.contextMenus.addMenuItem(ext.i18n.getMessage("block_element"), ["image", "video", "audio"], function(srcUrl, tab) | |
282 { | |
283 if (srcUrl) | |
284 tab.sendMessage({type: "clickhide-new-filter", filter: srcUrl}); | |
285 }); | |
286 } | |
287 else | |
288 ext.contextMenus.removeMenuItems(); | |
289 } | |
290 | |
291 Prefs.addListener(function(name) | 261 Prefs.addListener(function(name) |
292 { | 262 { |
293 if (name == "shouldShowBlockElementMenu") | 263 if (name == "shouldShowBlockElementMenu") |
294 setContextMenu(); | 264 refreshIconAndContextMenuForAllPages(); |
295 }); | 265 }); |
296 setContextMenu(); | 266 |
297 | 267 function prepareNotificationIconAndPopup() |
298 /** | 268 { |
299 * Opens options tab or focuses an existing one, within the last focused window . | 269 var animateIcon = (activeNotification.type !== "question"); |
300 * @param {Function} callback function to be called with the | 270 activeNotification.onClicked = function() |
301 Tab object of the options tab | 271 { |
302 */ | 272 if (animateIcon) |
303 function openOptions(callback) | 273 stopIconAnimation(); |
304 { | 274 notificationClosed(); |
305 ext.windows.getLastFocused(function(win) | 275 }; |
306 { | 276 if (animateIcon) |
307 win.getAllTabs(function(tabs) | 277 startIconAnimation(activeNotification.type); |
308 { | 278 } |
309 var optionsUrl = ext.getURL("options.html"); | 279 |
310 | 280 function openNotificationLinks() |
311 for (var i = 0; i < tabs.length; i++) | 281 { |
312 { | 282 if (activeNotification.links) |
313 if (tabs[i].url == optionsUrl) | 283 { |
314 { | 284 activeNotification.links.forEach(function(link) |
315 tabs[i].activate(); | 285 { |
316 if (callback) | 286 ext.windows.getLastFocused(function(win) |
317 callback(tabs[i]); | 287 { |
318 return; | 288 win.openTab(Utils.getDocLink(link)); |
319 } | |
320 } | |
321 | |
322 win.openTab(optionsUrl, callback && function(tab) | |
323 { | |
324 tab.onCompleted.addListener(callback); | |
325 }); | 289 }); |
326 }); | 290 }); |
291 } | |
292 } | |
293 | |
294 function notificationButtonClick(buttonIndex) | |
295 { | |
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]) | |
303 { | |
304 ext.windows.getLastFocused(function(win) | |
305 { | |
306 win.openTab(Utils.getDocLink(activeNotification.links[buttonIndex])); | |
307 }); | |
308 } | |
309 } | |
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); | |
327 }); | 351 }); |
328 } | 352 chrome.notifications.onClicked.addListener(clearActiveNotification); |
329 | 353 chrome.notifications.onClosed.addListener(notificationClosed); |
330 function prepareNotificationIconAndPopup() | |
331 { | |
332 activeNotification.onClicked = function() | |
333 { | |
334 iconAnimation.stop(); | |
335 activeNotification = null; | |
336 }; | |
337 | |
338 iconAnimation.update(activeNotification.severity); | |
339 } | 354 } |
340 | 355 |
341 function showNotification(notification) | 356 function showNotification(notification) |
342 { | 357 { |
358 if (activeNotification && activeNotification.id === notification.id) | |
359 return; | |
360 | |
343 activeNotification = notification; | 361 activeNotification = notification; |
344 | 362 if (activeNotification.type === "critical" || activeNotification.type === "que stion") |
345 if (activeNotification.severity === "critical" | 363 { |
346 && typeof webkitNotifications !== "undefined") | 364 var texts = NotificationStorage.getLocalizedTexts(notification); |
347 { | 365 var title = texts.title || ""; |
348 var notification = webkitNotifications.createHTMLNotification("notification. html"); | 366 var message = texts.message ? texts.message.replace(/<\/?(a|strong)>/g, "") : ""; |
349 notification.show(); | 367 var iconUrl = ext.getURL("icons/abp-128.png"); |
350 notification.addEventListener("close", prepareNotificationIconAndPopup); | 368 var hasLinks = activeNotification.links && activeNotification.links.length > 0; |
351 } | 369 |
352 else | 370 if (canUseChromeNotifications) |
353 prepareNotificationIconAndPopup(); | 371 { |
372 var opts = { | |
373 type: "basic", | |
374 title: title, | |
375 message: message, | |
376 buttons: [], | |
377 priority: 2 // We use the highest priority to prevent the notification f rom closing automatically | |
378 }; | |
379 if (activeNotification.type === "question") | |
380 { | |
381 opts.buttons.push({title: ext.i18n.getMessage("overlay_notification_butt on_yes")}); | |
382 opts.buttons.push({title: ext.i18n.getMessage("overlay_notification_butt on_no")}); | |
383 } | |
384 else | |
385 { | |
386 var regex = /<a>(.*?)<\/a>/g; | |
387 var plainMessage = texts.message || ""; | |
388 var match; | |
389 while (match = regex.exec(plainMessage)) | |
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") | |
400 { | |
401 if (hasLinks) | |
402 message += " " + ext.i18n.getMessage("notification_without_buttons"); | |
403 | |
404 imgToBase64(iconUrl, function(iconData) | |
405 { | |
406 var notification = new Notification( | |
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 }); | |
419 } | |
420 else | |
421 { | |
422 var message = title + "\n" + message; | |
423 if (hasLinks) | |
424 message += "\n\n" + ext.i18n.getMessage("notification_with_buttons"); | |
425 | |
426 var approved = confirm(message); | |
427 if (activeNotification.type === "question") | |
428 notificationButtonClick(approved ? 0 : 1); | |
429 else if (approved) | |
430 openNotificationLinks(); | |
431 } | |
432 } | |
433 prepareNotificationIconAndPopup(); | |
434 } | |
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}; | |
354 } | 461 } |
355 | 462 |
356 ext.onMessage.addListener(function (msg, sender, sendResponse) | 463 ext.onMessage.addListener(function (msg, sender, sendResponse) |
357 { | 464 { |
358 switch (msg.type) | 465 switch (msg.type) |
359 { | 466 { |
360 case "get-selectors": | 467 case "get-selectors": |
361 var selectors = null; | 468 var selectors = []; |
362 | 469 |
363 if (!isFrameWhitelisted(sender.tab, sender.frame, "DOCUMENT") && | 470 if (!isFrameWhitelisted(sender.page, sender.frame, "DOCUMENT") && |
364 !isFrameWhitelisted(sender.tab, sender.frame, "ELEMHIDE")) | 471 !isFrameWhitelisted(sender.page, sender.frame, "ELEMHIDE")) |
365 { | 472 { |
366 var noStyleRules = false; | 473 var noStyleRules = false; |
367 var host = extractHostFromURL(sender.frame.url); | 474 var host = extractHostFromFrame(sender.frame); |
368 for (var i = 0; i < noStyleRulesHosts.length; i++) | 475 for (var i = 0; i < noStyleRulesHosts.length; i++) |
369 { | 476 { |
370 var noStyleHost = noStyleRulesHosts[i]; | 477 var noStyleHost = noStyleRulesHosts[i]; |
371 if (host == noStyleHost || (host.length > noStyleHost.length && | 478 if (host == noStyleHost || (host.length > noStyleHost.length && |
372 host.substr(host.length - noStyleHost.leng th - 1) == "." + noStyleHost)) | 479 host.substr(host.length - noStyleHost.leng th - 1) == "." + noStyleHost)) |
373 { | 480 { |
374 noStyleRules = true; | 481 noStyleRules = true; |
375 } | 482 } |
376 } | 483 } |
377 selectors = ElemHide.getSelectorsForDomain(host, false); | 484 selectors = ElemHide.getSelectorsForDomain(host, false); |
378 if (noStyleRules) | 485 if (noStyleRules) |
379 { | 486 { |
380 selectors = selectors.filter(function(s) | 487 selectors = selectors.filter(function(s) |
381 { | 488 { |
382 return !/\[style[\^\$]?=/.test(s); | 489 return !/\[style[\^\$]?=/.test(s); |
383 }); | 490 }); |
384 } | 491 } |
385 } | 492 } |
386 | 493 |
387 sendResponse(selectors); | 494 sendResponse(selectors); |
388 break; | 495 break; |
389 case "should-collapse": | 496 case "should-collapse": |
390 if (isFrameWhitelisted(sender.tab, sender.frame, "DOCUMENT")) | 497 if (isFrameWhitelisted(sender.page, sender.frame, "DOCUMENT")) |
391 { | 498 { |
392 sendResponse(false); | 499 sendResponse(false); |
393 break; | 500 break; |
394 } | 501 } |
395 | 502 |
396 var requestHost = extractHostFromURL(msg.url); | 503 var url = new URL(msg.url); |
397 var documentHost = extractHostFromURL(sender.frame.url); | 504 var documentHost = extractHostFromFrame(sender.frame); |
398 var thirdParty = isThirdParty(requestHost, documentHost); | 505 var filter = defaultMatcher.matchesAny( |
399 var filter = defaultMatcher.matchesAny(msg.url, msg.mediatype, documentHos t, thirdParty); | 506 stringifyURL(url), msg.mediatype, |
507 documentHost, isThirdParty(url, documentHost) | |
508 ); | |
509 | |
400 if (filter instanceof BlockingFilter) | 510 if (filter instanceof BlockingFilter) |
401 { | 511 { |
402 var collapse = filter.collapse; | 512 var collapse = filter.collapse; |
403 if (collapse == null) | 513 if (collapse == null) |
404 collapse = Prefs.hidePlaceholders; | 514 collapse = Prefs.hidePlaceholders; |
405 sendResponse(collapse); | 515 sendResponse(collapse); |
406 } | 516 } |
407 else | 517 else |
408 sendResponse(false); | 518 sendResponse(false); |
409 break; | 519 break; |
410 case "get-domain-enabled-state": | 520 case "get-domain-enabled-state": |
411 // Returns whether this domain is in the exclusion list. | 521 // Returns whether this domain is in the exclusion list. |
412 // The browser action popup asks us this. | 522 // The browser action popup asks us this. |
413 if(sender.tab) | 523 if(sender.page) |
414 { | 524 { |
415 sendResponse({enabled: !isWhitelisted(sender.tab.url)}); | 525 sendResponse({enabled: !isPageWhitelisted(sender.page)}); |
416 return; | 526 return; |
417 } | 527 } |
418 break; | 528 break; |
419 case "add-filters": | 529 case "add-filters": |
420 if (msg.filters && msg.filters.length) | 530 var filters; |
421 { | 531 try |
422 for (var i = 0; i < msg.filters.length; i++) | 532 { |
423 FilterStorage.addFilter(Filter.fromText(msg.filters[i])); | 533 filters = parseFilters(msg.text); |
424 } | 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"}); | |
425 break; | 545 break; |
426 case "add-subscription": | 546 case "add-subscription": |
427 openOptions(function(tab) | 547 ext.showOptions(function(page) |
428 { | 548 { |
429 tab.sendMessage(msg); | 549 page.sendMessage(msg); |
430 }); | 550 }); |
431 break; | 551 break; |
432 case "add-key-exception": | 552 case "add-sitekey": |
433 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); | |
434 break; | 558 break; |
435 case "forward": | 559 case "forward": |
436 if (sender.tab) | 560 if (sender.page) |
437 { | 561 { |
438 sender.tab.sendMessage(msg.payload, sendResponse); | 562 if (msg.expectsResponse) |
439 // Return true to indicate that we want to call | 563 { |
440 // sendResponse asynchronously | 564 sender.page.sendMessage(msg.payload, sendResponse); |
441 return true; | 565 return true; |
442 } | 566 } |
443 break; | 567 |
444 default: | 568 sender.page.sendMessage(msg.payload); |
445 sendResponse({}); | 569 } |
446 break; | 570 break; |
447 } | 571 } |
448 }); | 572 }); |
449 | 573 |
450 // Update icon if a tab changes location | 574 // update icon when page changes location |
451 ext.tabs.onLoading.addListener(function(tab) | 575 ext.pages.onLoading.addListener(function(page) |
452 { | 576 { |
453 tab.sendMessage({type: "clickhide-deactivate"}); | 577 page.sendMessage({type: "clickhide-deactivate"}); |
454 refreshIconAndContextMenu(tab); | 578 refreshIconAndContextMenu(page); |
455 }); | 579 }); |
456 | 580 |
457 setTimeout(function() | 581 setTimeout(function() |
458 { | 582 { |
459 var notificationToShow = Notification.getNextToShow(); | 583 var notificationToShow = NotificationStorage.getNextToShow(); |
460 if (notificationToShow) | 584 if (notificationToShow) |
461 showNotification(notificationToShow); | 585 showNotification(notificationToShow); |
462 }, 3 * 60 * 1000); | 586 }, 3 * 60 * 1000); |
LEFT | RIGHT |