| 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 27 matching lines...) Expand all Loading... |
| 115 if (!frame) | 115 if (!frame) |
| 116 frame = frames[frameId] = {}; | 116 frame = frames[frameId] = {}; |
| 117 | 117 |
| 118 return frame; | 118 return frame; |
| 119 } | 119 } |
| 120 | 120 |
| 121 function updatePageFrameStructure(frameId, tabId, url, parentFrameId) | 121 function updatePageFrameStructure(frameId, tabId, url, parentFrameId) |
| 122 { | 122 { |
| 123 if (frameId == 0) | 123 if (frameId == 0) |
| 124 { | 124 { |
| 125 let page = new Page({id: tabId, url: url}); | 125 let page = new Page({id: tabId, url}); |
| 126 | 126 |
| 127 ext._removeFromAllPageMaps(tabId); | 127 ext._removeFromAllPageMaps(tabId); |
| 128 | 128 |
| 129 chrome.tabs.get(tabId, () => | 129 chrome.tabs.get(tabId, () => |
| 130 { | 130 { |
| 131 // If the tab is prerendered, chrome.tabs.get() sets | 131 // If the tab is prerendered, chrome.tabs.get() sets |
| 132 // chrome.runtime.lastError and we have to dispatch the onLoading event, | 132 // chrome.runtime.lastError and we have to dispatch the onLoading event, |
| 133 // since the onUpdated event isn't dispatched for prerendered tabs. | 133 // since the onUpdated event isn't dispatched for prerendered tabs. |
| 134 // However, we have to keep relying on the unUpdated event for tabs that | 134 // However, we have to keep relying on the unUpdated event for tabs that |
| 135 // are already visible. Otherwise browser action changes get overridden | 135 // are already visible. Otherwise browser action changes get overridden |
| 136 // when Chrome automatically resets them on navigation. | 136 // when Chrome automatically resets them on navigation. |
| 137 if (chrome.runtime.lastError) | 137 if (chrome.runtime.lastError) |
| 138 ext.pages.onLoading._dispatch(page); | 138 ext.pages.onLoading._dispatch(page); |
| 139 }); | 139 }); |
| 140 } | 140 } |
| 141 | 141 |
| 142 // Update frame parent and URL in frame structure | 142 // Update frame parent and URL in frame structure |
| 143 let frame = createFrame(tabId, frameId); | 143 let frame = createFrame(tabId, frameId); |
| 144 frame.url = new URL(url); | 144 frame.url = new URL(url); |
| 145 frame.parent = framesOfTabs[tabId][parentFrameId] || null; | 145 frame.parent = framesOfTabs[tabId][parentFrameId] || null; |
| 146 }; | 146 } |
| 147 | 147 |
| 148 chrome.webRequest.onHeadersReceived.addListener(details => | 148 chrome.webRequest.onHeadersReceived.addListener(details => |
| 149 { | 149 { |
| 150 // We have to update the frame structure when switching to a new | 150 // We have to update the frame structure when switching to a new |
| 151 // document, so that we process any further requests made by that | 151 // document, so that we process any further requests made by that |
| 152 // document in the right context. Unfortunately, we cannot rely | 152 // document in the right context. Unfortunately, we cannot rely |
| 153 // on webNavigation.onCommitted since it isn't guaranteed to fire | 153 // on webNavigation.onCommitted since it isn't guaranteed to fire |
| 154 // before any subresources start downloading[1]. As an | 154 // before any subresources start downloading[1]. As an |
| 155 // alternative we use webRequest.onHeadersReceived for HTTP(S) | 155 // alternative we use webRequest.onHeadersReceived for HTTP(S) |
| 156 // URLs, being careful to ignore any responses that won't cause | 156 // URLs, being careful to ignore any responses that won't cause |
| (...skipping 25 matching lines...) Expand all Loading... |
| 182 // "Content-Disposition" with a valid and non-empty value other | 182 // "Content-Disposition" with a valid and non-empty value other |
| 183 // than "inline". | 183 // than "inline". |
| 184 // https://chromium.googlesource.com/chromium/src/+/02d3f50b/content/brows
er/loader/mime_sniffing_resource_handler.cc#534 | 184 // https://chromium.googlesource.com/chromium/src/+/02d3f50b/content/brows
er/loader/mime_sniffing_resource_handler.cc#534 |
| 185 // https://chromium.googlesource.com/chromium/src/+/02d3f50b/net/http/http
_content_disposition.cc#374 | 185 // https://chromium.googlesource.com/chromium/src/+/02d3f50b/net/http/http
_content_disposition.cc#374 |
| 186 // https://chromium.googlesource.com/chromium/src/+/16e2688e/net/http/http
_util.cc#431 | 186 // https://chromium.googlesource.com/chromium/src/+/16e2688e/net/http/http
_util.cc#431 |
| 187 if (headerName == "content-disposition") | 187 if (headerName == "content-disposition") |
| 188 { | 188 { |
| 189 let disposition = header.value.split(";")[0].replace(/[ \t]+$/, ""); | 189 let disposition = header.value.split(";")[0].replace(/[ \t]+$/, ""); |
| 190 if (disposition.toLowerCase() != "inline" && | 190 if (disposition.toLowerCase() != "inline" && |
| 191 /^[\x21-\x7E]+$/.test(disposition) && | 191 /^[\x21-\x7E]+$/.test(disposition) && |
| 192 !/[()<>@,;:\\"/\[\]?={}]/.test(disposition)) | 192 !/[()<>@,;:\\"/[\]?={}]/.test(disposition)) |
| 193 return; | 193 return; |
| 194 } | 194 } |
| 195 | 195 |
| 196 // The value of the "Content-Type" header also determines if Chrome will | 196 // The value of the "Content-Type" header also determines if Chrome will |
| 197 // initiate a download, or otherwise how the response will be rendered. | 197 // initiate a download, or otherwise how the response will be rendered. |
| 198 // We only need to consider responses which will result in a navigation | 198 // We only need to consider responses which will result in a navigation |
| 199 // and be rendered as HTML or similar. | 199 // and be rendered as HTML or similar. |
| 200 // Note: Chrome might render the response as HTML if the "Content-Type" | 200 // Note: Chrome might render the response as HTML if the "Content-Type" |
| 201 // header is missing, invalid or unknown. | 201 // header is missing, invalid or unknown. |
| 202 // https://chromium.googlesource.com/chromium/src/+/99f41af9/net/http/http
_util.cc#66 | 202 // https://chromium.googlesource.com/chromium/src/+/99f41af9/net/http/http
_util.cc#66 |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 295 chrome.browserAction.setBadgeBackgroundColor({ | 295 chrome.browserAction.setBadgeBackgroundColor({ |
| 296 tabId: this._tabId, | 296 tabId: this._tabId, |
| 297 color: this._changes.badgeColor | 297 color: this._changes.badgeColor |
| 298 }); | 298 }); |
| 299 } | 299 } |
| 300 | 300 |
| 301 this._changes = null; | 301 this._changes = null; |
| 302 }, | 302 }, |
| 303 _queueChanges() | 303 _queueChanges() |
| 304 { | 304 { |
| 305 chrome.tabs.get(this._tabId, function() | 305 chrome.tabs.get(this._tabId, () => |
| 306 { | 306 { |
| 307 // If the tab is prerendered, chrome.tabs.get() sets | 307 // If the tab is prerendered, chrome.tabs.get() sets |
| 308 // chrome.runtime.lastError and we have to delay our changes | 308 // chrome.runtime.lastError and we have to delay our changes |
| 309 // until the currently visible tab is replaced with the | 309 // until the currently visible tab is replaced with the |
| 310 // prerendered tab. Otherwise chrome.browserAction.set* fails. | 310 // prerendered tab. Otherwise chrome.browserAction.set* fails. |
| 311 if (chrome.runtime.lastError) | 311 if (chrome.runtime.lastError) |
| 312 { | 312 { |
| 313 let onReplaced = (addedTabId, removedTabId) => | 313 let onReplaced = (addedTabId, removedTabId) => |
| 314 { | 314 { |
| 315 if (addedTabId == this._tabId) | 315 if (addedTabId == this._tabId) |
| 316 { | 316 { |
| 317 chrome.tabs.onReplaced.removeListener(onReplaced); | 317 chrome.tabs.onReplaced.removeListener(onReplaced); |
| 318 this._applyChanges(); | 318 this._applyChanges(); |
| 319 } | 319 } |
| 320 }; | 320 }; |
| 321 chrome.tabs.onReplaced.addListener(onReplaced); | 321 chrome.tabs.onReplaced.addListener(onReplaced); |
| 322 } | 322 } |
| 323 else | 323 else |
| 324 { | |
| 325 this._applyChanges(); | 324 this._applyChanges(); |
| 326 } | 325 }); |
| 327 }.bind(this)); | |
| 328 }, | 326 }, |
| 329 _addChange(name, value) | 327 _addChange(name, value) |
| 330 { | 328 { |
| 331 if (!this._changes) | 329 if (!this._changes) |
| 332 { | 330 { |
| 333 this._changes = {}; | 331 this._changes = {}; |
| 334 this._queueChanges(); | 332 this._queueChanges(); |
| 335 } | 333 } |
| 336 | 334 |
| 337 this._changes[name] = value; | 335 this._changes[name] = value; |
| 338 }, | 336 }, |
| 339 setIcon(path) | 337 setIcon(path) |
| 340 { | 338 { |
| 341 this._addChange("iconPath", path); | 339 this._addChange("iconPath", path); |
| 342 }, | 340 }, |
| 343 setBadge(badge) | 341 setBadge(badge) |
| 344 { | 342 { |
| 345 if (!badge) | 343 if (!badge) |
| 346 { | |
| 347 this._addChange("badgeText", ""); | 344 this._addChange("badgeText", ""); |
| 348 } | |
| 349 else | 345 else |
| 350 { | 346 { |
| 351 if ("number" in badge) | 347 if ("number" in badge) |
| 352 this._addChange("badgeText", badge.number.toString()); | 348 this._addChange("badgeText", badge.number.toString()); |
| 353 | 349 |
| 354 if ("color" in badge) | 350 if ("color" in badge) |
| 355 this._addChange("badgeColor", badge.color); | 351 this._addChange("badgeColor", badge.color); |
| 356 } | 352 } |
| 357 } | 353 } |
| 358 }; | 354 }; |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 439 | 435 |
| 440 /* Web requests */ | 436 /* Web requests */ |
| 441 | 437 |
| 442 let framesOfTabs = Object.create(null); | 438 let framesOfTabs = Object.create(null); |
| 443 | 439 |
| 444 ext.getFrame = (tabId, frameId) => | 440 ext.getFrame = (tabId, frameId) => |
| 445 { | 441 { |
| 446 return (framesOfTabs[tabId] || {})[frameId]; | 442 return (framesOfTabs[tabId] || {})[frameId]; |
| 447 }; | 443 }; |
| 448 | 444 |
| 449 let handlerBehaviorChangedQuota = chrome.webRequest.MAX_HANDLER_BEHAVIOR_CHANG
ED_CALLS_PER_10_MINUTES; | 445 let handlerBehaviorChangedQuota = |
| 446 chrome.webRequest.MAX_HANDLER_BEHAVIOR_CHANGED_CALLS_PER_10_MINUTES; |
| 450 | 447 |
| 451 function propagateHandlerBehaviorChange() | 448 function propagateHandlerBehaviorChange() |
| 452 { | 449 { |
| 453 // Make sure to not call handlerBehaviorChanged() more often than allowed | 450 // Make sure to not call handlerBehaviorChanged() more often than allowed |
| 454 // by chrome.webRequest.MAX_HANDLER_BEHAVIOR_CHANGED_CALLS_PER_10_MINUTES. | 451 // by chrome.webRequest.MAX_HANDLER_BEHAVIOR_CHANGED_CALLS_PER_10_MINUTES. |
| 455 // Otherwise Chrome notifies the user that this extension is causing issues. | 452 // Otherwise Chrome notifies the user that this extension is causing issues. |
| 456 if (handlerBehaviorChangedQuota > 0) | 453 if (handlerBehaviorChangedQuota > 0) |
| 457 { | 454 { |
| 458 chrome.webNavigation.onBeforeNavigate.removeListener(propagateHandlerBehav
iorChange); | 455 chrome.webNavigation.onBeforeNavigate.removeListener( |
| 456 propagateHandlerBehaviorChange |
| 457 ); |
| 459 chrome.webRequest.handlerBehaviorChanged(); | 458 chrome.webRequest.handlerBehaviorChanged(); |
| 460 | 459 |
| 461 handlerBehaviorChangedQuota--; | 460 handlerBehaviorChangedQuota--; |
| 462 setTimeout(() => { handlerBehaviorChangedQuota++; }, 600000); | 461 setTimeout(() => { handlerBehaviorChangedQuota++; }, 600000); |
| 463 } | 462 } |
| 464 } | 463 } |
| 465 | 464 |
| 466 ext.webRequest = { | 465 ext.webRequest = { |
| 467 onBeforeRequest: new ext._EventTarget(), | 466 onBeforeRequest: new ext._EventTarget(), |
| 468 handlerBehaviorChanged() | 467 handlerBehaviorChanged() |
| 469 { | 468 { |
| 470 // Defer handlerBehaviorChanged() until navigation occurs. | 469 // Defer handlerBehaviorChanged() until navigation occurs. |
| 471 // There wouldn't be any visible effect when calling it earlier, | 470 // There wouldn't be any visible effect when calling it earlier, |
| 472 // but it's an expensive operation and that way we avoid to call | 471 // but it's an expensive operation and that way we avoid to call |
| 473 // it multiple times, if multiple filters are added/removed. | 472 // it multiple times, if multiple filters are added/removed. |
| 474 let onBeforeNavigate = chrome.webNavigation.onBeforeNavigate; | 473 let {onBeforeNavigate} = chrome.webNavigation; |
| 475 if (!onBeforeNavigate.hasListener(propagateHandlerBehaviorChange)) | 474 if (!onBeforeNavigate.hasListener(propagateHandlerBehaviorChange)) |
| 476 onBeforeNavigate.addListener(propagateHandlerBehaviorChange); | 475 onBeforeNavigate.addListener(propagateHandlerBehaviorChange); |
| 477 } | 476 } |
| 478 }; | 477 }; |
| 479 | 478 |
| 480 chrome.tabs.query({}, tabs => | 479 chrome.tabs.query({}, tabs => |
| 481 { | 480 { |
| 482 tabs.forEach(tab => | 481 tabs.forEach(tab => |
| 483 { | 482 { |
| 484 chrome.webNavigation.getAllFrames({tabId: tab.id}, details => | 483 chrome.webNavigation.getAllFrames({tabId: tab.id}, details => |
| 485 { | 484 { |
| 486 if (details && details.length > 0) | 485 if (details && details.length > 0) |
| 487 { | 486 { |
| 488 let frames = framesOfTabs[tab.id] = Object.create(null); | 487 let frames = framesOfTabs[tab.id] = Object.create(null); |
| 489 | 488 |
| 490 for (let i = 0; i < details.length; i++) | 489 for (let i = 0; i < details.length; i++) |
| 491 frames[details[i].frameId] = {url: new URL(details[i].url), parent:
null}; | 490 { |
| 491 frames[details[i].frameId] = { |
| 492 url: new URL(details[i].url), |
| 493 parent: null |
| 494 }; |
| 495 } |
| 492 | 496 |
| 493 for (let i = 0; i < details.length; i++) | 497 for (let i = 0; i < details.length; i++) |
| 494 { | 498 { |
| 495 let parentFrameId = details[i].parentFrameId; | 499 let {parentFrameId} = details[i]; |
| 496 | 500 |
| 497 if (parentFrameId != -1) | 501 if (parentFrameId != -1) |
| 498 frames[details[i].frameId].parent = frames[parentFrameId]; | 502 frames[details[i].frameId].parent = frames[parentFrameId]; |
| 499 } | 503 } |
| 500 } | 504 } |
| 501 }); | 505 }); |
| 502 }); | 506 }); |
| 503 }); | 507 }); |
| 504 | 508 |
| 505 chrome.webRequest.onBeforeRequest.addListener(details => | 509 chrome.webRequest.onBeforeRequest.addListener(details => |
| 506 { | 510 { |
| 507 // The high-level code isn't interested in requests that aren't | 511 // The high-level code isn't interested in requests that aren't |
| 508 // related to a tab or requests loading a top-level document, | 512 // related to a tab or requests loading a top-level document, |
| 509 // those should never be blocked. | 513 // those should never be blocked. |
| 510 if (details.tabId == -1 || details.type == "main_frame") | 514 if (details.tabId == -1 || details.type == "main_frame") |
| 511 return; | 515 return; |
| 512 | 516 |
| 513 // We are looking for the frame that contains the element which | 517 // We are looking for the frame that contains the element which |
| 514 // has triggered this request. For most requests (e.g. images) we | 518 // has triggered this request. For most requests (e.g. images) we |
| 515 // can just use the request's frame ID, but for subdocument requests | 519 // can just use the request's frame ID, but for subdocument requests |
| 516 // (e.g. iframes) we must instead use the request's parent frame ID. | 520 // (e.g. iframes) we must instead use the request's parent frame ID. |
| 517 let frameId; | 521 let {frameId, type} = details; |
| 518 let requestType; | 522 if (type == "sub_frame") |
| 519 if (details.type == "sub_frame") | |
| 520 { | 523 { |
| 521 frameId = details.parentFrameId; | 524 frameId = details.parentFrameId; |
| 522 requestType = "SUBDOCUMENT"; | 525 type = "SUBDOCUMENT"; |
| 523 } | |
| 524 else | |
| 525 { | |
| 526 frameId = details.frameId; | |
| 527 requestType = details.type.toUpperCase(); | |
| 528 } | 526 } |
| 529 | 527 |
| 530 let frame = ext.getFrame(details.tabId, frameId); | 528 let frame = ext.getFrame(details.tabId, frameId); |
| 531 if (frame) | 529 if (frame) |
| 532 { | 530 { |
| 533 let results = ext.webRequest.onBeforeRequest._dispatch( | 531 let results = ext.webRequest.onBeforeRequest._dispatch( |
| 534 new URL(details.url), | 532 new URL(details.url), |
| 535 requestType, | 533 type.toUpperCase(), |
| 536 new Page({id: details.tabId}), | 534 new Page({id: details.tabId}), |
| 537 frame | 535 frame |
| 538 ); | 536 ); |
| 539 | 537 |
| 540 if (results.indexOf(false) != -1) | 538 if (results.indexOf(false) != -1) |
| 541 return {cancel: true}; | 539 return {cancel: true}; |
| 542 } | 540 } |
| 543 }, {urls: ["http://*/*", "https://*/*"]}, ["blocking"]); | 541 }, {urls: ["http://*/*", "https://*/*"]}, ["blocking"]); |
| 544 | 542 |
| 545 | 543 |
| (...skipping 19 matching lines...) Expand all Loading... |
| 565 | 563 |
| 566 let frame = frames[rawSender.frameId]; | 564 let frame = frames[rawSender.frameId]; |
| 567 if (frame) | 565 if (frame) |
| 568 return frame.parent; | 566 return frame.parent; |
| 569 | 567 |
| 570 return frames[0]; | 568 return frames[0]; |
| 571 } | 569 } |
| 572 }; | 570 }; |
| 573 } | 571 } |
| 574 | 572 |
| 575 return ext.onMessage._dispatch(message, sender, sendResponse).indexOf(true)
!= -1; | 573 return ext.onMessage._dispatch( |
| 574 message, sender, sendResponse |
| 575 ).indexOf(true) != -1; |
| 576 }); | 576 }); |
| 577 | 577 |
| 578 | 578 |
| 579 /* Storage */ | 579 /* Storage */ |
| 580 | 580 |
| 581 ext.storage = { | 581 ext.storage = { |
| 582 get(keys, callback) | 582 get(keys, callback) |
| 583 { | 583 { |
| 584 chrome.storage.local.get(keys, callback); | 584 chrome.storage.local.get(keys, callback); |
| 585 }, | 585 }, |
| (...skipping 10 matching lines...) Expand all Loading... |
| 596 onChanged: chrome.storage.onChanged | 596 onChanged: chrome.storage.onChanged |
| 597 }; | 597 }; |
| 598 | 598 |
| 599 /* Options */ | 599 /* Options */ |
| 600 | 600 |
| 601 if ("openOptionsPage" in chrome.runtime) | 601 if ("openOptionsPage" in chrome.runtime) |
| 602 { | 602 { |
| 603 ext.showOptions = callback => | 603 ext.showOptions = callback => |
| 604 { | 604 { |
| 605 if (!callback) | 605 if (!callback) |
| 606 { | |
| 607 chrome.runtime.openOptionsPage(); | 606 chrome.runtime.openOptionsPage(); |
| 608 } | |
| 609 else | 607 else |
| 610 { | 608 { |
| 611 chrome.runtime.openOptionsPage(() => | 609 chrome.runtime.openOptionsPage(() => |
| 612 { | 610 { |
| 613 if (chrome.runtime.lastError) | 611 if (chrome.runtime.lastError) |
| 614 return; | 612 return; |
| 615 | 613 |
| 616 chrome.tabs.query({active: true, lastFocusedWindow: true}, tabs => | 614 chrome.tabs.query({active: true, lastFocusedWindow: true}, tabs => |
| 617 { | 615 { |
| 618 if (tabs.length > 0) | 616 if (tabs.length > 0) |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 650 { | 648 { |
| 651 let tab = tabs[0]; | 649 let tab = tabs[0]; |
| 652 | 650 |
| 653 chrome.windows.update(tab.windowId, {focused: true}); | 651 chrome.windows.update(tab.windowId, {focused: true}); |
| 654 chrome.tabs.update(tab.id, {active: true}); | 652 chrome.tabs.update(tab.id, {active: true}); |
| 655 | 653 |
| 656 if (callback) | 654 if (callback) |
| 657 callback(new Page(tab)); | 655 callback(new Page(tab)); |
| 658 } | 656 } |
| 659 else | 657 else |
| 660 { | |
| 661 ext.pages.open(optionsUrl, callback); | 658 ext.pages.open(optionsUrl, callback); |
| 662 } | |
| 663 }); | 659 }); |
| 664 }); | 660 }); |
| 665 }; | 661 }; |
| 666 } | 662 } |
| 667 | 663 |
| 668 /* Windows */ | 664 /* Windows */ |
| 669 ext.windows = { | 665 ext.windows = { |
| 670 create(createData, callback) | 666 create(createData, callback) |
| 671 { | 667 { |
| 672 chrome.windows.create(createData, createdWindow => | 668 chrome.windows.create(createData, createdWindow => |
| 673 { | 669 { |
| 674 afterTabLoaded(callback)(createdWindow.tabs[0]); | 670 afterTabLoaded(callback)(createdWindow.tabs[0]); |
| 675 }); | 671 }); |
| 676 } | 672 } |
| 677 }; | 673 }; |
| 678 } | 674 } |
| OLD | NEW |