| 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-2017 eyeo GmbH | 3  * Copyright (C) 2006-2017 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 "use strict"; | 18 "use strict"; | 
| 19 | 19 | 
|  | 20 (function() | 
| 20 { | 21 { | 
| 21   /* Pages */ | 22   /* Pages */ | 
| 22 | 23 | 
| 23   let Page = ext.Page = function(tab) | 24   let Page = ext.Page = function(tab) | 
| 24   { | 25   { | 
| 25     this.id = tab.id; | 26     this.id = tab.id; | 
| 26     this._url = tab.url && new URL(tab.url); | 27     this._url = tab.url && new URL(tab.url); | 
| 27 | 28 | 
| 28     this.browserAction = new BrowserAction(tab.id); | 29     this.browserAction = new BrowserAction(tab.id); | 
| 29     this.contextMenus = new ContextMenus(this); | 30     this.contextMenus = new ContextMenus(this); | 
| (...skipping 20 matching lines...) Expand all  Loading... | 
| 50     sendMessage(message, responseCallback) | 51     sendMessage(message, responseCallback) | 
| 51     { | 52     { | 
| 52       chrome.tabs.sendMessage(this.id, message, responseCallback); | 53       chrome.tabs.sendMessage(this.id, message, responseCallback); | 
| 53     } | 54     } | 
| 54   }; | 55   }; | 
| 55 | 56 | 
| 56   ext.getPage = id => new Page({id: parseInt(id, 10)}); | 57   ext.getPage = id => new Page({id: parseInt(id, 10)}); | 
| 57 | 58 | 
| 58   function afterTabLoaded(callback) | 59   function afterTabLoaded(callback) | 
| 59   { | 60   { | 
| 60      return openedTab => | 61     return openedTab => | 
| 61      { | 62     { | 
| 62        let onUpdated = (tabId, changeInfo, tab) => | 63       let onUpdated = (tabId, changeInfo, tab) => | 
| 63        { | 64       { | 
| 64          if (tabId == openedTab.id && changeInfo.status == "complete") | 65         if (tabId == openedTab.id && changeInfo.status == "complete") | 
| 65          { | 66         { | 
| 66            chrome.tabs.onUpdated.removeListener(onUpdated); | 67           chrome.tabs.onUpdated.removeListener(onUpdated); | 
| 67            callback(new Page(openedTab)); | 68           callback(new Page(openedTab)); | 
| 68          } | 69         } | 
| 69        }; | 70       }; | 
| 70        chrome.tabs.onUpdated.addListener(onUpdated); | 71       chrome.tabs.onUpdated.addListener(onUpdated); | 
| 71      }; | 72     }; | 
| 72   } | 73   } | 
| 73 | 74 | 
| 74   ext.pages = { | 75   ext.pages = { | 
| 75     open(url, callback) | 76     open(url, callback) | 
| 76     { | 77     { | 
| 77       chrome.tabs.create({url: url}, callback && afterTabLoaded(callback)); | 78       chrome.tabs.create({url}, callback && afterTabLoaded(callback)); | 
| 78     }, | 79     }, | 
| 79     query(info, callback) | 80     query(info, callback) | 
| 80     { | 81     { | 
| 81       let rawInfo = {}; | 82       let rawInfo = {}; | 
| 82       for (let property in info) | 83       for (let property in info) | 
| 83       { | 84       { | 
| 84         switch (property) | 85         switch (property) | 
| 85         { | 86         { | 
| 86           case "active": | 87           case "active": | 
| 87           case "lastFocusedWindow": | 88           case "lastFocusedWindow": | 
| (...skipping 27 matching lines...) Expand all  Loading... | 
| 115     if (!frame) | 116     if (!frame) | 
| 116       frame = frames[frameId] = {}; | 117       frame = frames[frameId] = {}; | 
| 117 | 118 | 
| 118     return frame; | 119     return frame; | 
| 119   } | 120   } | 
| 120 | 121 | 
| 121   function updatePageFrameStructure(frameId, tabId, url, parentFrameId) | 122   function updatePageFrameStructure(frameId, tabId, url, parentFrameId) | 
| 122   { | 123   { | 
| 123     if (frameId == 0) | 124     if (frameId == 0) | 
| 124     { | 125     { | 
| 125       let page = new Page({id: tabId, url: url}); | 126       let page = new Page({id: tabId, url}); | 
| 126 | 127 | 
| 127       ext._removeFromAllPageMaps(tabId); | 128       ext._removeFromAllPageMaps(tabId); | 
| 128 | 129 | 
| 129       chrome.tabs.get(tabId, () => | 130       chrome.tabs.get(tabId, () => | 
| 130       { | 131       { | 
| 131         // If the tab is prerendered, chrome.tabs.get() sets | 132         // If the tab is prerendered, chrome.tabs.get() sets | 
| 132         // chrome.runtime.lastError and we have to dispatch the onLoading event, | 133         // chrome.runtime.lastError and we have to dispatch the onLoading event, | 
| 133         // since the onUpdated event isn't dispatched for prerendered tabs. | 134         // since the onUpdated event isn't dispatched for prerendered tabs. | 
| 134         // However, we have to keep relying on the unUpdated event for tabs that | 135         // However, we have to keep relying on the unUpdated event for tabs that | 
| 135         // are already visible. Otherwise browser action changes get overridden | 136         // are already visible. Otherwise browser action changes get overridden | 
| 136         // when Chrome automatically resets them on navigation. | 137         // when Chrome automatically resets them on navigation. | 
| 137         if (chrome.runtime.lastError) | 138         if (chrome.runtime.lastError) | 
| 138           ext.pages.onLoading._dispatch(page); | 139           ext.pages.onLoading._dispatch(page); | 
| 139       }); | 140       }); | 
| 140     } | 141     } | 
| 141 | 142 | 
| 142     // Update frame parent and URL in frame structure | 143     // Update frame parent and URL in frame structure | 
| 143     let frame = createFrame(tabId, frameId); | 144     let frame = createFrame(tabId, frameId); | 
| 144     frame.url = new URL(url); | 145     frame.url = new URL(url); | 
| 145     frame.parent = framesOfTabs[tabId][parentFrameId] || null; | 146     frame.parent = framesOfTabs[tabId][parentFrameId] || null; | 
| 146   }; | 147   } | 
| 147 | 148 | 
| 148   chrome.webRequest.onHeadersReceived.addListener(details => | 149   chrome.webRequest.onHeadersReceived.addListener(details => | 
| 149   { | 150   { | 
| 150     // We have to update the frame structure when switching to a new | 151     // We have to update the frame structure when switching to a new | 
| 151     // document, so that we process any further requests made by that | 152     // document, so that we process any further requests made by that | 
| 152     // document in the right context. Unfortunately, we cannot rely | 153     // document in the right context. Unfortunately, we cannot rely | 
| 153     // on webNavigation.onCommitted since it isn't guaranteed to fire | 154     // on webNavigation.onCommitted since it isn't guaranteed to fire | 
| 154     // before any subresources start downloading[1]. As an | 155     // before any subresources start downloading[1]. As an | 
| 155     // alternative we use webRequest.onHeadersReceived for HTTP(S) | 156     // alternative we use webRequest.onHeadersReceived for HTTP(S) | 
| 156     // URLs, being careful to ignore any responses that won't cause | 157     // 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 | 183       // "Content-Disposition" with a valid and non-empty value other | 
| 183       // than "inline". | 184       // than "inline". | 
| 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/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 | 186       // 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 | 187       // https://chromium.googlesource.com/chromium/src/+/16e2688e/net/http/http
     _util.cc#431 | 
| 187       if (headerName == "content-disposition") | 188       if (headerName == "content-disposition") | 
| 188       { | 189       { | 
| 189         let disposition = header.value.split(";")[0].replace(/[ \t]+$/, ""); | 190         let disposition = header.value.split(";")[0].replace(/[ \t]+$/, ""); | 
| 190         if (disposition.toLowerCase() != "inline" && | 191         if (disposition.toLowerCase() != "inline" && | 
| 191             /^[\x21-\x7E]+$/.test(disposition) && | 192             /^[\x21-\x7E]+$/.test(disposition) && | 
| 192             !/[()<>@,;:\\"/\[\]?={}]/.test(disposition)) | 193             !/[()<>@,;:\\"/[\]?={}]/.test(disposition)) | 
| 193           return; | 194           return; | 
| 194       } | 195       } | 
| 195 | 196 | 
| 196       // The value of the "Content-Type" header also determines if Chrome will | 197       // The value of the "Content-Type" header also determines if Chrome will | 
| 197       // initiate a download, or otherwise how the response will be rendered. | 198       // initiate a download, or otherwise how the response will be rendered. | 
| 198       // We only need to consider responses which will result in a navigation | 199       // We only need to consider responses which will result in a navigation | 
| 199       // and be rendered as HTML or similar. | 200       // and be rendered as HTML or similar. | 
| 200       // Note: Chrome might render the response as HTML if the "Content-Type" | 201       // Note: Chrome might render the response as HTML if the "Content-Type" | 
| 201       // header is missing, invalid or unknown. | 202       // header is missing, invalid or unknown. | 
| 202       // https://chromium.googlesource.com/chromium/src/+/99f41af9/net/http/http
     _util.cc#66 | 203       // 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({ | 296         chrome.browserAction.setBadgeBackgroundColor({ | 
| 296           tabId: this._tabId, | 297           tabId: this._tabId, | 
| 297           color: this._changes.badgeColor | 298           color: this._changes.badgeColor | 
| 298         }); | 299         }); | 
| 299       } | 300       } | 
| 300 | 301 | 
| 301       this._changes = null; | 302       this._changes = null; | 
| 302     }, | 303     }, | 
| 303     _queueChanges() | 304     _queueChanges() | 
| 304     { | 305     { | 
| 305       chrome.tabs.get(this._tabId, function() | 306       chrome.tabs.get(this._tabId, () => | 
| 306       { | 307       { | 
| 307         // If the tab is prerendered, chrome.tabs.get() sets | 308         // If the tab is prerendered, chrome.tabs.get() sets | 
| 308         // chrome.runtime.lastError and we have to delay our changes | 309         // chrome.runtime.lastError and we have to delay our changes | 
| 309         // until the currently visible tab is replaced with the | 310         // until the currently visible tab is replaced with the | 
| 310         // prerendered tab. Otherwise chrome.browserAction.set* fails. | 311         // prerendered tab. Otherwise chrome.browserAction.set* fails. | 
| 311         if (chrome.runtime.lastError) | 312         if (chrome.runtime.lastError) | 
| 312         { | 313         { | 
| 313           let onReplaced = (addedTabId, removedTabId) => | 314           let onReplaced = (addedTabId, removedTabId) => | 
| 314           { | 315           { | 
| 315             if (addedTabId == this._tabId) | 316             if (addedTabId == this._tabId) | 
| 316             { | 317             { | 
| 317               chrome.tabs.onReplaced.removeListener(onReplaced); | 318               chrome.tabs.onReplaced.removeListener(onReplaced); | 
| 318               this._applyChanges(); | 319               this._applyChanges(); | 
| 319             } | 320             } | 
| 320           }; | 321           }; | 
| 321           chrome.tabs.onReplaced.addListener(onReplaced); | 322           chrome.tabs.onReplaced.addListener(onReplaced); | 
| 322         } | 323         } | 
| 323         else | 324         else | 
| 324         { | 325         { | 
| 325           this._applyChanges(); | 326           this._applyChanges(); | 
| 326         } | 327         } | 
| 327       }.bind(this)); | 328       }); | 
| 328     }, | 329     }, | 
| 329     _addChange(name, value) | 330     _addChange(name, value) | 
| 330     { | 331     { | 
| 331       if (!this._changes) | 332       if (!this._changes) | 
| 332       { | 333       { | 
| 333         this._changes = {}; | 334         this._changes = {}; | 
| 334         this._queueChanges(); | 335         this._queueChanges(); | 
| 335       } | 336       } | 
| 336 | 337 | 
| 337       this._changes[name] = value; | 338       this._changes[name] = value; | 
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 439 | 440 | 
| 440   /* Web requests */ | 441   /* Web requests */ | 
| 441 | 442 | 
| 442   let framesOfTabs = Object.create(null); | 443   let framesOfTabs = Object.create(null); | 
| 443 | 444 | 
| 444   ext.getFrame = (tabId, frameId) => | 445   ext.getFrame = (tabId, frameId) => | 
| 445   { | 446   { | 
| 446     return (framesOfTabs[tabId] || {})[frameId]; | 447     return (framesOfTabs[tabId] || {})[frameId]; | 
| 447   }; | 448   }; | 
| 448 | 449 | 
| 449   let handlerBehaviorChangedQuota = chrome.webRequest.MAX_HANDLER_BEHAVIOR_CHANG
     ED_CALLS_PER_10_MINUTES; | 450   let handlerBehaviorChangedQuota = | 
|  | 451     chrome.webRequest.MAX_HANDLER_BEHAVIOR_CHANGED_CALLS_PER_10_MINUTES; | 
| 450 | 452 | 
| 451   function propagateHandlerBehaviorChange() | 453   function propagateHandlerBehaviorChange() | 
| 452   { | 454   { | 
| 453     // Make sure to not call handlerBehaviorChanged() more often than allowed | 455     // Make sure to not call handlerBehaviorChanged() more often than allowed | 
| 454     // by chrome.webRequest.MAX_HANDLER_BEHAVIOR_CHANGED_CALLS_PER_10_MINUTES. | 456     // by chrome.webRequest.MAX_HANDLER_BEHAVIOR_CHANGED_CALLS_PER_10_MINUTES. | 
| 455     // Otherwise Chrome notifies the user that this extension is causing issues. | 457     // Otherwise Chrome notifies the user that this extension is causing issues. | 
| 456     if (handlerBehaviorChangedQuota > 0) | 458     if (handlerBehaviorChangedQuota > 0) | 
| 457     { | 459     { | 
| 458       chrome.webNavigation.onBeforeNavigate.removeListener(propagateHandlerBehav
     iorChange); | 460       chrome.webNavigation.onBeforeNavigate.removeListener( | 
|  | 461         propagateHandlerBehaviorChange | 
|  | 462       ); | 
| 459       chrome.webRequest.handlerBehaviorChanged(); | 463       chrome.webRequest.handlerBehaviorChanged(); | 
| 460 | 464 | 
| 461       handlerBehaviorChangedQuota--; | 465       handlerBehaviorChangedQuota--; | 
| 462       setTimeout(() => { handlerBehaviorChangedQuota++; }, 600000); | 466       setTimeout(() => { handlerBehaviorChangedQuota++; }, 600000); | 
| 463     } | 467     } | 
| 464   } | 468   } | 
| 465 | 469 | 
| 466   ext.webRequest = { | 470   ext.webRequest = { | 
| 467     onBeforeRequest: new ext._EventTarget(), | 471     onBeforeRequest: new ext._EventTarget(), | 
| 468     handlerBehaviorChanged() | 472     handlerBehaviorChanged() | 
| 469     { | 473     { | 
| 470       // Defer handlerBehaviorChanged() until navigation occurs. | 474       // Defer handlerBehaviorChanged() until navigation occurs. | 
| 471       // There wouldn't be any visible effect when calling it earlier, | 475       // 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 | 476       // but it's an expensive operation and that way we avoid to call | 
| 473       // it multiple times, if multiple filters are added/removed. | 477       // it multiple times, if multiple filters are added/removed. | 
| 474       let onBeforeNavigate = chrome.webNavigation.onBeforeNavigate; | 478       let {onBeforeNavigate} = chrome.webNavigation; | 
| 475       if (!onBeforeNavigate.hasListener(propagateHandlerBehaviorChange)) | 479       if (!onBeforeNavigate.hasListener(propagateHandlerBehaviorChange)) | 
| 476         onBeforeNavigate.addListener(propagateHandlerBehaviorChange); | 480         onBeforeNavigate.addListener(propagateHandlerBehaviorChange); | 
| 477     } | 481     } | 
| 478   }; | 482   }; | 
| 479 | 483 | 
| 480   chrome.tabs.query({}, tabs => | 484   chrome.tabs.query({}, tabs => | 
| 481   { | 485   { | 
| 482     tabs.forEach(tab => | 486     tabs.forEach(tab => | 
| 483     { | 487     { | 
| 484       chrome.webNavigation.getAllFrames({tabId: tab.id}, details => | 488       chrome.webNavigation.getAllFrames({tabId: tab.id}, details => | 
| 485       { | 489       { | 
| 486         if (details && details.length > 0) | 490         if (details && details.length > 0) | 
| 487         { | 491         { | 
| 488           let frames = framesOfTabs[tab.id] = Object.create(null); | 492           let frames = framesOfTabs[tab.id] = Object.create(null); | 
| 489 | 493 | 
| 490           for (let i = 0; i < details.length; i++) | 494           for (let i = 0; i < details.length; i++) | 
| 491             frames[details[i].frameId] = {url: new URL(details[i].url), parent: 
     null}; | 495           { | 
|  | 496             frames[details[i].frameId] = { | 
|  | 497               url: new URL(details[i].url), | 
|  | 498               parent: null | 
|  | 499             }; | 
|  | 500           } | 
| 492 | 501 | 
| 493           for (let i = 0; i < details.length; i++) | 502           for (let i = 0; i < details.length; i++) | 
| 494           { | 503           { | 
| 495             let parentFrameId = details[i].parentFrameId; | 504             let {parentFrameId} = details[i]; | 
| 496 | 505 | 
| 497             if (parentFrameId != -1) | 506             if (parentFrameId != -1) | 
| 498               frames[details[i].frameId].parent = frames[parentFrameId]; | 507               frames[details[i].frameId].parent = frames[parentFrameId]; | 
| 499           } | 508           } | 
| 500         } | 509         } | 
| 501       }); | 510       }); | 
| 502     }); | 511     }); | 
| 503   }); | 512   }); | 
| 504 | 513 | 
| 505   chrome.webRequest.onBeforeRequest.addListener(details => | 514   chrome.webRequest.onBeforeRequest.addListener(details => | 
| 506   { | 515   { | 
| 507     // The high-level code isn't interested in requests that aren't | 516     // The high-level code isn't interested in requests that aren't | 
| 508     // related to a tab or requests loading a top-level document, | 517     // related to a tab or requests loading a top-level document, | 
| 509     // those should never be blocked. | 518     // those should never be blocked. | 
| 510     if (details.tabId == -1 || details.type == "main_frame") | 519     if (details.tabId == -1 || details.type == "main_frame") | 
| 511       return; | 520       return; | 
| 512 | 521 | 
| 513     // We are looking for the frame that contains the element which | 522     // We are looking for the frame that contains the element which | 
| 514     // has triggered this request. For most requests (e.g. images) we | 523     // has triggered this request. For most requests (e.g. images) we | 
| 515     // can just use the request's frame ID, but for subdocument requests | 524     // 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. | 525     // (e.g. iframes) we must instead use the request's parent frame ID. | 
| 517     let frameId; | 526     let {frameId, type} = details; | 
| 518     let requestType; | 527     if (type == "sub_frame") | 
| 519     if (details.type == "sub_frame") |  | 
| 520     { | 528     { | 
| 521       frameId = details.parentFrameId; | 529       frameId = details.parentFrameId; | 
| 522       requestType = "SUBDOCUMENT"; | 530       type = "SUBDOCUMENT"; | 
| 523     } |  | 
| 524     else |  | 
| 525     { |  | 
| 526       frameId = details.frameId; |  | 
| 527       requestType = details.type.toUpperCase(); |  | 
| 528     } | 531     } | 
| 529 | 532 | 
| 530     let frame = ext.getFrame(details.tabId, frameId); | 533     let frame = ext.getFrame(details.tabId, frameId); | 
| 531     if (frame) | 534     if (frame) | 
| 532     { | 535     { | 
| 533       let results = ext.webRequest.onBeforeRequest._dispatch( | 536       let results = ext.webRequest.onBeforeRequest._dispatch( | 
| 534         new URL(details.url), | 537         new URL(details.url), | 
| 535         requestType, | 538         type.toUpperCase(), | 
| 536         new Page({id: details.tabId}), | 539         new Page({id: details.tabId}), | 
| 537         frame | 540         frame | 
| 538       ); | 541       ); | 
| 539 | 542 | 
| 540       if (results.indexOf(false) != -1) | 543       if (results.indexOf(false) != -1) | 
| 541         return {cancel: true}; | 544         return {cancel: true}; | 
| 542     } | 545     } | 
| 543   }, {urls: ["<all_urls>"]}, ["blocking"]); | 546   }, {urls: ["<all_urls>"]}, ["blocking"]); | 
| 544 | 547 | 
| 545 | 548 | 
| (...skipping 19 matching lines...) Expand all  Loading... | 
| 565 | 568 | 
| 566           let frame = frames[rawSender.frameId]; | 569           let frame = frames[rawSender.frameId]; | 
| 567           if (frame) | 570           if (frame) | 
| 568             return frame.parent; | 571             return frame.parent; | 
| 569 | 572 | 
| 570           return frames[0]; | 573           return frames[0]; | 
| 571         } | 574         } | 
| 572       }; | 575       }; | 
| 573     } | 576     } | 
| 574 | 577 | 
| 575     return ext.onMessage._dispatch(message, sender, sendResponse).indexOf(true) 
     != -1; | 578     return ext.onMessage._dispatch( | 
|  | 579       message, sender, sendResponse | 
|  | 580     ).indexOf(true) != -1; | 
| 576   }); | 581   }); | 
| 577 | 582 | 
| 578 | 583 | 
| 579   /* Storage */ | 584   /* Storage */ | 
| 580 | 585 | 
| 581   ext.storage = { | 586   ext.storage = { | 
| 582     get(keys, callback) | 587     get(keys, callback) | 
| 583     { | 588     { | 
| 584       chrome.storage.local.get(keys, callback); | 589       chrome.storage.local.get(keys, callback); | 
| 585     }, | 590     }, | 
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 668   /* Windows */ | 673   /* Windows */ | 
| 669   ext.windows = { | 674   ext.windows = { | 
| 670     create(createData, callback) | 675     create(createData, callback) | 
| 671     { | 676     { | 
| 672       chrome.windows.create(createData, createdWindow => | 677       chrome.windows.create(createData, createdWindow => | 
| 673       { | 678       { | 
| 674         afterTabLoaded(callback)(createdWindow.tabs[0]); | 679         afterTabLoaded(callback)(createdWindow.tabs[0]); | 
| 675       }); | 680       }); | 
| 676     } | 681     } | 
| 677   }; | 682   }; | 
| 678 } | 683 }()); | 
| OLD | NEW | 
|---|