| 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 | 
|---|