OLD | NEW |
1 /* | 1 /* |
2 * This file is part of Adblock Plus <https://adblockplus.org/>, | 2 * This file is part of Adblock Plus <https://adblockplus.org/>, |
3 * Copyright (C) 2006-2016 Eyeo GmbH | 3 * Copyright (C) 2006-2016 Eyeo GmbH |
4 * | 4 * |
5 * Adblock Plus is free software: you can redistribute it and/or modify | 5 * Adblock Plus is free software: you can redistribute it and/or modify |
6 * it under the terms of the GNU General Public License version 3 as | 6 * it under the terms of the GNU General Public License version 3 as |
7 * published by the Free Software Foundation. | 7 * published by the Free Software Foundation. |
8 * | 8 * |
9 * Adblock Plus is distributed in the hope that it will be useful, | 9 * Adblock Plus is distributed in the hope that it will be useful, |
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
50 sendMessage(message, responseCallback) | 50 sendMessage(message, responseCallback) |
51 { | 51 { |
52 chrome.tabs.sendMessage(this.id, message, responseCallback); | 52 chrome.tabs.sendMessage(this.id, message, responseCallback); |
53 } | 53 } |
54 }; | 54 }; |
55 | 55 |
56 ext.getPage = id => new Page({id: parseInt(id, 10)}); | 56 ext.getPage = id => new Page({id: parseInt(id, 10)}); |
57 | 57 |
58 function afterTabLoaded(callback) | 58 function afterTabLoaded(callback) |
59 { | 59 { |
60 return openedTab => | 60 return openedTab => |
61 { | 61 { |
62 let onUpdated = (tabId, changeInfo, tab) => | 62 let onUpdated = (tabId, changeInfo, tab) => |
63 { | 63 { |
64 if (tabId == openedTab.id && changeInfo.status == "complete") | 64 if (tabId == openedTab.id && changeInfo.status == "complete") |
65 { | 65 { |
66 chrome.tabs.onUpdated.removeListener(onUpdated); | 66 chrome.tabs.onUpdated.removeListener(onUpdated); |
67 callback(new Page(openedTab)); | 67 callback(new Page(openedTab)); |
68 } | 68 } |
69 }; | 69 }; |
70 chrome.tabs.onUpdated.addListener(onUpdated); | 70 chrome.tabs.onUpdated.addListener(onUpdated); |
71 }; | 71 }; |
72 } | 72 } |
73 | 73 |
74 ext.pages = { | 74 ext.pages = { |
75 open(url, callback) | 75 open(url, callback) |
76 { | 76 { |
77 chrome.tabs.create({url: url}, callback && afterTabLoaded(callback)); | 77 chrome.tabs.create({url}, callback && afterTabLoaded(callback)); |
78 }, | 78 }, |
79 query(info, callback) | 79 query(info, callback) |
80 { | 80 { |
81 let rawInfo = {}; | 81 let rawInfo = {}; |
82 for (let property in info) | 82 for (let property in info) |
83 { | 83 { |
84 switch (property) | 84 switch (property) |
85 { | 85 { |
86 case "active": | 86 case "active": |
87 case "lastFocusedWindow": | 87 case "lastFocusedWindow": |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
124 let frame = createFrame(details.tabId, details.frameId); | 124 let frame = createFrame(details.tabId, details.frameId); |
125 frame.parent = framesOfTabs[details.tabId][details.parentFrameId] || null; | 125 frame.parent = framesOfTabs[details.tabId][details.parentFrameId] || null; |
126 }); | 126 }); |
127 | 127 |
128 let eagerlyUpdatedPages = new ext.PageMap(); | 128 let eagerlyUpdatedPages = new ext.PageMap(); |
129 | 129 |
130 ext._updatePageFrameStructure = (frameId, tabId, url, eager) => | 130 ext._updatePageFrameStructure = (frameId, tabId, url, eager) => |
131 { | 131 { |
132 if (frameId == 0) | 132 if (frameId == 0) |
133 { | 133 { |
134 let page = new Page({id: tabId, url: url}); | 134 let page = new Page({id: tabId, url}); |
135 | 135 |
136 if (eagerlyUpdatedPages.get(page) != url) | 136 if (eagerlyUpdatedPages.get(page) != url) |
137 { | 137 { |
138 ext._removeFromAllPageMaps(tabId); | 138 ext._removeFromAllPageMaps(tabId); |
139 | 139 |
140 // When a sitekey header is received we must immediately update the page | 140 // When a sitekey header is received we must immediately update the page |
141 // structure in order to record and use the key. We want to avoid | 141 // structure in order to record and use the key. We want to avoid |
142 // trashing the page structure if the onCommitted event is then fired | 142 // trashing the page structure if the onCommitted event is then fired |
143 // for the page. | 143 // for the page. |
144 if (eager) | 144 if (eager) |
145 eagerlyUpdatedPages.set(page, url); | 145 eagerlyUpdatedPages.set(page, url); |
146 | 146 |
147 chrome.tabs.get(tabId, () => | 147 chrome.tabs.get(tabId, () => |
148 { | 148 { |
149 // If the tab is prerendered, chrome.tabs.get() sets | 149 // If the tab is prerendered, chrome.tabs.get() sets |
150 // chrome.runtime.lastError and we have to dispatch the onLoading even
t, | 150 // chrome.runtime.lastError and we have to dispatch the |
151 // since the onUpdated event isn't dispatched for prerendered tabs. | 151 // onLoading event, since the onUpdated event isn't |
152 // However, we have to keep relying on the unUpdated event for tabs th
at | 152 // dispatched for prerendered tabs. However, we have to |
153 // are already visible. Otherwise browser action changes get overridde
n | 153 // keep relying on the unUpdated event for tabs that are |
154 // when Chrome automatically resets them on navigation. | 154 // already visible. Otherwise browser action changes get |
| 155 // overridden when Chrome automatically resets them on |
| 156 // navigation. |
155 if (chrome.runtime.lastError) | 157 if (chrome.runtime.lastError) |
156 ext.pages.onLoading._dispatch(page); | 158 ext.pages.onLoading._dispatch(page); |
157 }); | 159 }); |
158 } | 160 } |
159 } | 161 } |
160 | 162 |
161 // Update frame URL in frame structure | 163 // Update frame URL in frame structure |
162 let frame = createFrame(tabId, frameId); | 164 let frame = createFrame(tabId, frameId); |
163 frame.url = new URL(url); | 165 frame.url = new URL(url); |
164 }; | 166 }; |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
227 chrome.browserAction.setBadgeBackgroundColor({ | 229 chrome.browserAction.setBadgeBackgroundColor({ |
228 tabId: this._tabId, | 230 tabId: this._tabId, |
229 color: this._changes.badgeColor | 231 color: this._changes.badgeColor |
230 }); | 232 }); |
231 } | 233 } |
232 | 234 |
233 this._changes = null; | 235 this._changes = null; |
234 }, | 236 }, |
235 _queueChanges() | 237 _queueChanges() |
236 { | 238 { |
237 chrome.tabs.get(this._tabId, function() | 239 chrome.tabs.get(this._tabId, () => |
238 { | 240 { |
239 // If the tab is prerendered, chrome.tabs.get() sets | 241 // If the tab is prerendered, chrome.tabs.get() sets |
240 // chrome.runtime.lastError and we have to delay our changes | 242 // chrome.runtime.lastError and we have to delay our changes |
241 // until the currently visible tab is replaced with the | 243 // until the currently visible tab is replaced with the |
242 // prerendered tab. Otherwise chrome.browserAction.set* fails. | 244 // prerendered tab. Otherwise chrome.browserAction.set* fails. |
243 if (chrome.runtime.lastError) | 245 if (chrome.runtime.lastError) |
244 { | 246 { |
245 let onReplaced = (addedTabId, removedTabId) => | 247 let onReplaced = (addedTabId, removedTabId) => |
246 { | 248 { |
247 if (addedTabId == this._tabId) | 249 if (addedTabId == this._tabId) |
248 { | 250 { |
249 chrome.tabs.onReplaced.removeListener(onReplaced); | 251 chrome.tabs.onReplaced.removeListener(onReplaced); |
250 this._applyChanges(); | 252 this._applyChanges(); |
251 } | 253 } |
252 }; | 254 }; |
253 chrome.tabs.onReplaced.addListener(onReplaced); | 255 chrome.tabs.onReplaced.addListener(onReplaced); |
254 } | 256 } |
255 else | 257 else |
256 { | |
257 this._applyChanges(); | 258 this._applyChanges(); |
258 } | 259 }); |
259 }.bind(this)); | |
260 }, | 260 }, |
261 _addChange(name, value) | 261 _addChange(name, value) |
262 { | 262 { |
263 if (!this._changes) | 263 if (!this._changes) |
264 { | 264 { |
265 this._changes = {}; | 265 this._changes = {}; |
266 this._queueChanges(); | 266 this._queueChanges(); |
267 } | 267 } |
268 | 268 |
269 this._changes[name] = value; | 269 this._changes[name] = value; |
270 }, | 270 }, |
271 setIcon(path) | 271 setIcon(path) |
272 { | 272 { |
273 this._addChange("iconPath", path); | 273 this._addChange("iconPath", path); |
274 }, | 274 }, |
275 setBadge(badge) | 275 setBadge(badge) |
276 { | 276 { |
277 if (!badge) | 277 if (!badge) |
278 { | |
279 this._addChange("badgeText", ""); | 278 this._addChange("badgeText", ""); |
280 } | |
281 else | 279 else |
282 { | 280 { |
283 if ("number" in badge) | 281 if ("number" in badge) |
284 this._addChange("badgeText", badge.number.toString()); | 282 this._addChange("badgeText", badge.number.toString()); |
285 | 283 |
286 if ("color" in badge) | 284 if ("color" in badge) |
287 this._addChange("badgeColor", badge.color); | 285 this._addChange("badgeColor", badge.color); |
288 } | 286 } |
289 } | 287 } |
290 }; | 288 }; |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
371 | 369 |
372 /* Web requests */ | 370 /* Web requests */ |
373 | 371 |
374 let framesOfTabs = Object.create(null); | 372 let framesOfTabs = Object.create(null); |
375 | 373 |
376 ext.getFrame = (tabId, frameId) => | 374 ext.getFrame = (tabId, frameId) => |
377 { | 375 { |
378 return (framesOfTabs[tabId] || {})[frameId]; | 376 return (framesOfTabs[tabId] || {})[frameId]; |
379 }; | 377 }; |
380 | 378 |
381 let handlerBehaviorChangedQuota = chrome.webRequest.MAX_HANDLER_BEHAVIOR_CHANG
ED_CALLS_PER_10_MINUTES; | 379 let handlerBehaviorChangedQuota = |
| 380 chrome.webRequest.MAX_HANDLER_BEHAVIOR_CHANGED_CALLS_PER_10_MINUTES; |
382 | 381 |
383 function propagateHandlerBehaviorChange() | 382 function propagateHandlerBehaviorChange() |
384 { | 383 { |
385 // Make sure to not call handlerBehaviorChanged() more often than allowed | 384 // Make sure to not call handlerBehaviorChanged() more often than allowed |
386 // by chrome.webRequest.MAX_HANDLER_BEHAVIOR_CHANGED_CALLS_PER_10_MINUTES. | 385 // by chrome.webRequest.MAX_HANDLER_BEHAVIOR_CHANGED_CALLS_PER_10_MINUTES. |
387 // Otherwise Chrome notifies the user that this extension is causing issues. | 386 // Otherwise Chrome notifies the user that this extension is causing issues. |
388 if (handlerBehaviorChangedQuota > 0) | 387 if (handlerBehaviorChangedQuota > 0) |
389 { | 388 { |
390 chrome.webNavigation.onBeforeNavigate.removeListener(propagateHandlerBehav
iorChange); | 389 chrome.webNavigation.onBeforeNavigate.removeListener( |
| 390 propagateHandlerBehaviorChange |
| 391 ); |
391 chrome.webRequest.handlerBehaviorChanged(); | 392 chrome.webRequest.handlerBehaviorChanged(); |
392 | 393 |
393 handlerBehaviorChangedQuota--; | 394 handlerBehaviorChangedQuota--; |
394 setTimeout(() => { handlerBehaviorChangedQuota++; }, 600000); | 395 setTimeout(() => { handlerBehaviorChangedQuota++; }, 600000); |
395 } | 396 } |
396 } | 397 } |
397 | 398 |
398 ext.webRequest = { | 399 ext.webRequest = { |
399 onBeforeRequest: new ext._EventTarget(), | 400 onBeforeRequest: new ext._EventTarget(), |
400 handlerBehaviorChanged() | 401 handlerBehaviorChanged() |
401 { | 402 { |
402 // Defer handlerBehaviorChanged() until navigation occurs. | 403 // Defer handlerBehaviorChanged() until navigation occurs. |
403 // There wouldn't be any visible effect when calling it earlier, | 404 // There wouldn't be any visible effect when calling it earlier, |
404 // but it's an expensive operation and that way we avoid to call | 405 // but it's an expensive operation and that way we avoid to call |
405 // it multiple times, if multiple filters are added/removed. | 406 // it multiple times, if multiple filters are added/removed. |
406 let onBeforeNavigate = chrome.webNavigation.onBeforeNavigate; | 407 let {onBeforeNavigate} = chrome.webNavigation; |
407 if (!onBeforeNavigate.hasListener(propagateHandlerBehaviorChange)) | 408 if (!onBeforeNavigate.hasListener(propagateHandlerBehaviorChange)) |
408 onBeforeNavigate.addListener(propagateHandlerBehaviorChange); | 409 onBeforeNavigate.addListener(propagateHandlerBehaviorChange); |
409 } | 410 } |
410 }; | 411 }; |
411 | 412 |
412 chrome.tabs.query({}, tabs => | 413 chrome.tabs.query({}, tabs => |
413 { | 414 { |
414 tabs.forEach(tab => | 415 tabs.forEach(tab => |
415 { | 416 { |
416 chrome.webNavigation.getAllFrames({tabId: tab.id}, details => | 417 chrome.webNavigation.getAllFrames({tabId: tab.id}, details => |
417 { | 418 { |
418 if (details && details.length > 0) | 419 if (details && details.length > 0) |
419 { | 420 { |
420 let frames = framesOfTabs[tab.id] = Object.create(null); | 421 let frames = framesOfTabs[tab.id] = Object.create(null); |
421 | 422 |
422 for (let i = 0; i < details.length; i++) | 423 for (let i = 0; i < details.length; i++) |
423 frames[details[i].frameId] = {url: new URL(details[i].url), parent:
null}; | 424 { |
| 425 frames[details[i].frameId] = { |
| 426 url: new URL(details[i].url), |
| 427 parent: null |
| 428 }; |
| 429 } |
424 | 430 |
425 for (let i = 0; i < details.length; i++) | 431 for (let i = 0; i < details.length; i++) |
426 { | 432 { |
427 let parentFrameId = details[i].parentFrameId; | 433 let {parentFrameId} = details[i]; |
428 | 434 |
429 if (parentFrameId != -1) | 435 if (parentFrameId != -1) |
430 frames[details[i].frameId].parent = frames[parentFrameId]; | 436 frames[details[i].frameId].parent = frames[parentFrameId]; |
431 } | 437 } |
432 } | 438 } |
433 }); | 439 }); |
434 }); | 440 }); |
435 }); | 441 }); |
436 | 442 |
437 chrome.webRequest.onBeforeRequest.addListener(details => | 443 chrome.webRequest.onBeforeRequest.addListener(details => |
438 { | 444 { |
439 // The high-level code isn't interested in requests that aren't | 445 // The high-level code isn't interested in requests that aren't |
440 // related to a tab or requests loading a top-level document, | 446 // related to a tab or requests loading a top-level document, |
441 // those should never be blocked. | 447 // those should never be blocked. |
442 if (details.tabId == -1 || details.type == "main_frame") | 448 if (details.tabId == -1 || details.type == "main_frame") |
443 return; | 449 return; |
444 | 450 |
445 // We are looking for the frame that contains the element which | 451 // We are looking for the frame that contains the element which |
446 // has triggered this request. For most requests (e.g. images) we | 452 // has triggered this request. For most requests (e.g. images) we |
447 // can just use the request's frame ID, but for subdocument requests | 453 // can just use the request's frame ID, but for subdocument requests |
448 // (e.g. iframes) we must instead use the request's parent frame ID. | 454 // (e.g. iframes) we must instead use the request's parent frame ID. |
449 let frameId; | 455 let {frameId, type} = details; |
450 let requestType; | 456 if (type == "sub_frame") |
451 if (details.type == "sub_frame") | |
452 { | 457 { |
453 frameId = details.parentFrameId; | 458 frameId = details.parentFrameId; |
454 requestType = "SUBDOCUMENT"; | 459 type = "SUBDOCUMENT"; |
455 } | |
456 else | |
457 { | |
458 frameId = details.frameId; | |
459 requestType = details.type.toUpperCase(); | |
460 } | 460 } |
461 | 461 |
462 let frame = ext.getFrame(details.tabId, frameId); | 462 let frame = ext.getFrame(details.tabId, frameId); |
463 if (frame) | 463 if (frame) |
464 { | 464 { |
465 let results = ext.webRequest.onBeforeRequest._dispatch( | 465 let results = ext.webRequest.onBeforeRequest._dispatch( |
466 new URL(details.url), | 466 new URL(details.url), |
467 requestType, | 467 type.toUpperCase(), |
468 new Page({id: details.tabId}), | 468 new Page({id: details.tabId}), |
469 frame | 469 frame |
470 ); | 470 ); |
471 | 471 |
472 if (results.indexOf(false) != -1) | 472 if (results.indexOf(false) != -1) |
473 return {cancel: true}; | 473 return {cancel: true}; |
474 } | 474 } |
475 }, {urls: ["http://*/*", "https://*/*"]}, ["blocking"]); | 475 }, {urls: ["http://*/*", "https://*/*"]}, ["blocking"]); |
476 | 476 |
477 | 477 |
(...skipping 19 matching lines...) Expand all Loading... |
497 | 497 |
498 let frame = frames[rawSender.frameId]; | 498 let frame = frames[rawSender.frameId]; |
499 if (frame) | 499 if (frame) |
500 return frame.parent; | 500 return frame.parent; |
501 | 501 |
502 return frames[0]; | 502 return frames[0]; |
503 } | 503 } |
504 }; | 504 }; |
505 } | 505 } |
506 | 506 |
507 return ext.onMessage._dispatch(message, sender, sendResponse).indexOf(true)
!= -1; | 507 return ext.onMessage._dispatch( |
| 508 message, sender, sendResponse |
| 509 ).indexOf(true) != -1; |
508 }); | 510 }); |
509 | 511 |
510 | 512 |
511 /* Storage */ | 513 /* Storage */ |
512 | 514 |
513 ext.storage = { | 515 ext.storage = { |
514 get(keys, callback) | 516 get(keys, callback) |
515 { | 517 { |
516 chrome.storage.local.get(keys, callback); | 518 chrome.storage.local.get(keys, callback); |
517 }, | 519 }, |
(...skipping 10 matching lines...) Expand all Loading... |
528 onChanged: chrome.storage.onChanged | 530 onChanged: chrome.storage.onChanged |
529 }; | 531 }; |
530 | 532 |
531 /* Options */ | 533 /* Options */ |
532 | 534 |
533 if ("openOptionsPage" in chrome.runtime) | 535 if ("openOptionsPage" in chrome.runtime) |
534 { | 536 { |
535 ext.showOptions = callback => | 537 ext.showOptions = callback => |
536 { | 538 { |
537 if (!callback) | 539 if (!callback) |
538 { | |
539 chrome.runtime.openOptionsPage(); | 540 chrome.runtime.openOptionsPage(); |
540 } | |
541 else | 541 else |
542 { | 542 { |
543 chrome.runtime.openOptionsPage(() => | 543 chrome.runtime.openOptionsPage(() => |
544 { | 544 { |
545 if (chrome.runtime.lastError) | 545 if (chrome.runtime.lastError) |
546 return; | 546 return; |
547 | 547 |
548 chrome.tabs.query({active: true, lastFocusedWindow: true}, tabs => | 548 chrome.tabs.query({active: true, lastFocusedWindow: true}, tabs => |
549 { | 549 { |
550 if (tabs.length > 0) | 550 if (tabs.length > 0) |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
582 { | 582 { |
583 let tab = tabs[0]; | 583 let tab = tabs[0]; |
584 | 584 |
585 chrome.windows.update(tab.windowId, {focused: true}); | 585 chrome.windows.update(tab.windowId, {focused: true}); |
586 chrome.tabs.update(tab.id, {active: true}); | 586 chrome.tabs.update(tab.id, {active: true}); |
587 | 587 |
588 if (callback) | 588 if (callback) |
589 callback(new Page(tab)); | 589 callback(new Page(tab)); |
590 } | 590 } |
591 else | 591 else |
592 { | |
593 ext.pages.open(optionsUrl, callback); | 592 ext.pages.open(optionsUrl, callback); |
594 } | |
595 }); | 593 }); |
596 }); | 594 }); |
597 }; | 595 }; |
598 } | 596 } |
599 | 597 |
600 /* Windows */ | 598 /* Windows */ |
601 ext.windows = { | 599 ext.windows = { |
602 create(createData, callback) | 600 create(createData, callback) |
603 { | 601 { |
604 chrome.windows.create(createData, createdWindow => | 602 chrome.windows.create(createData, createdWindow => |
605 { | 603 { |
606 afterTabLoaded(callback)(createdWindow.tabs[0]); | 604 afterTabLoaded(callback)(createdWindow.tabs[0]); |
607 }); | 605 }); |
608 } | 606 } |
609 }; | 607 }; |
610 } | 608 } |
OLD | NEW |