Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Delta Between Two Patch Sets: ext/background.js

Issue 29370947: Issue 3138 - Improve how context menu "block element" handles iframes (Closed)
Left Patch Set: Rebased Created Aug. 9, 2017, 3:27 p.m.
Right Patch Set: Use messaging instead of requiring the info module Created Oct. 19, 2017, 10:52 a.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « composer.postload.js ('k') | lib/filterComposer.js » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
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-present 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()
21 { 20 {
22 let nonEmptyPageMaps = new Set(); 21 let nonEmptyPageMaps = new Set();
23 22
24 let PageMap = ext.PageMap = function() 23 let PageMap = ext.PageMap = function()
25 { 24 {
26 this._map = new Map(); 25 this._map = new Map();
27 }; 26 };
28 PageMap.prototype = { 27 PageMap.prototype = {
29 _delete(id) 28 _delete(id)
30 { 29 {
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
94 let frame = frames.get(0); 93 let frame = frames.get(0);
95 if (frame) 94 if (frame)
96 return frame.url; 95 return frame.url;
97 } 96 }
98 }, 97 },
99 sendMessage(message, responseCallback, frameId) 98 sendMessage(message, responseCallback, frameId)
100 { 99 {
101 let options = {}; 100 let options = {};
102 if (typeof frameId != "undefined") 101 if (typeof frameId != "undefined")
103 options.frameId = frameId; 102 options.frameId = frameId;
104 chrome.tabs.sendMessage(this.id, message, options, responseCallback); 103 browser.tabs.sendMessage(this.id, message, options, responseCallback);
105 } 104 }
106 }; 105 };
107 106
108 ext.getPage = id => new Page({id: parseInt(id, 10)}); 107 ext.getPage = id => new Page({id: parseInt(id, 10)});
109 108
110 function afterTabLoaded(callback) 109 function afterTabLoaded(callback)
111 { 110 {
112 return openedTab => 111 return openedTab =>
113 { 112 {
114 let onUpdated = (tabId, changeInfo, tab) => 113 let onUpdated = (tabId, changeInfo, tab) =>
115 { 114 {
116 if (tabId == openedTab.id && changeInfo.status == "complete") 115 if (tabId == openedTab.id && changeInfo.status == "complete")
117 { 116 {
118 chrome.tabs.onUpdated.removeListener(onUpdated); 117 browser.tabs.onUpdated.removeListener(onUpdated);
119 callback(new Page(openedTab)); 118 callback(new Page(openedTab));
120 } 119 }
121 }; 120 };
122 chrome.tabs.onUpdated.addListener(onUpdated); 121 browser.tabs.onUpdated.addListener(onUpdated);
123 }; 122 };
124 } 123 }
125 124
126 ext.pages = { 125 ext.pages = {
127 open(url, callback)
128 {
129 chrome.tabs.create({url}, callback && afterTabLoaded(callback));
130 },
131 query(info, callback)
132 {
133 let rawInfo = {};
134 for (let property in info)
135 {
136 switch (property)
137 {
138 case "active":
139 case "lastFocusedWindow":
140 rawInfo[property] = info[property];
141 }
142 }
143
144 chrome.tabs.query(rawInfo, tabs =>
145 {
146 callback(tabs.map(tab => new Page(tab)));
147 });
148 },
149 onLoading: new ext._EventTarget(), 126 onLoading: new ext._EventTarget(),
150 onActivated: new ext._EventTarget(), 127 onActivated: new ext._EventTarget(),
151 onRemoved: new ext._EventTarget() 128 onRemoved: new ext._EventTarget()
152 }; 129 };
153 130
154 chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => 131 browser.tabs.onUpdated.addListener((tabId, changeInfo, tab) =>
155 { 132 {
156 if (changeInfo.status == "loading") 133 if (changeInfo.status == "loading")
157 ext.pages.onLoading._dispatch(new Page(tab)); 134 ext.pages.onLoading._dispatch(new Page(tab));
158 }); 135 });
159 136
160 function createFrame(tabId, frameId) 137 function createFrame(tabId, frameId)
161 { 138 {
162 let frames = framesOfTabs.get(tabId); 139 let frames = framesOfTabs.get(tabId);
163 if (!frames) 140 if (!frames)
164 { 141 {
(...skipping 12 matching lines...) Expand all
177 } 154 }
178 155
179 function updatePageFrameStructure(frameId, tabId, url, parentFrameId) 156 function updatePageFrameStructure(frameId, tabId, url, parentFrameId)
180 { 157 {
181 if (frameId == 0) 158 if (frameId == 0)
182 { 159 {
183 let page = new Page({id: tabId, url}); 160 let page = new Page({id: tabId, url});
184 161
185 ext._removeFromAllPageMaps(tabId); 162 ext._removeFromAllPageMaps(tabId);
186 163
187 chrome.tabs.get(tabId, () => 164 browser.tabs.get(tabId, () =>
188 { 165 {
189 // If the tab is prerendered, chrome.tabs.get() sets 166 // If the tab is prerendered, browser.tabs.get() sets
190 // chrome.runtime.lastError and we have to dispatch the onLoading event, 167 // browser.runtime.lastError and we have to dispatch the onLoading
191 // since the onUpdated event isn't dispatched for prerendered tabs. 168 // event, since the onUpdated event isn't dispatched for prerendered
192 // However, we have to keep relying on the unUpdated event for tabs that 169 // tabs. However, we have to keep relying on the onUpdated event for
193 // are already visible. Otherwise browser action changes get overridden 170 // tabs that are already visible. Otherwise browser action changes get
194 // when Chrome automatically resets them on navigation. 171 // overridden when Chrome automatically resets them on navigation.
195 if (chrome.runtime.lastError) 172 if (browser.runtime.lastError)
196 ext.pages.onLoading._dispatch(page); 173 ext.pages.onLoading._dispatch(page);
197 }); 174 });
198 } 175 }
199 176
200 // Update frame URL and parent in frame structure 177 // Update frame URL and parent in frame structure
201 let frame = createFrame(tabId, frameId); 178 let frame = createFrame(tabId, frameId);
202 frame.url = new URL(url); 179 frame.url = new URL(url);
203 180
204 let parentFrame = framesOfTabs.get(tabId).get(parentFrameId); 181 let parentFrame = framesOfTabs.get(tabId).get(parentFrameId);
205 if (parentFrame) 182 if (parentFrame)
206 frame.parent = parentFrame; 183 frame.parent = parentFrame;
207 } 184 }
208 185
209 chrome.webRequest.onHeadersReceived.addListener(details => 186 browser.webRequest.onHeadersReceived.addListener(details =>
210 { 187 {
211 // We have to update the frame structure when switching to a new 188 // We have to update the frame structure when switching to a new
212 // document, so that we process any further requests made by that 189 // document, so that we process any further requests made by that
213 // document in the right context. Unfortunately, we cannot rely 190 // document in the right context. Unfortunately, we cannot rely
214 // on webNavigation.onCommitted since it isn't guaranteed to fire 191 // on webNavigation.onCommitted since it isn't guaranteed to fire
215 // before any subresources start downloading[1]. As an 192 // before any subresources start downloading[1]. As an
216 // alternative we use webRequest.onHeadersReceived for HTTP(S) 193 // alternative we use webRequest.onHeadersReceived for HTTP(S)
217 // URLs, being careful to ignore any responses that won't cause 194 // URLs, being careful to ignore any responses that won't cause
218 // the document to be replaced. 195 // the document to be replaced.
219 // [1] - https://bugs.chromium.org/p/chromium/issues/detail?id=665843 196 // [1] - https://bugs.chromium.org/p/chromium/issues/detail?id=665843
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
277 return; 254 return;
278 } 255 }
279 } 256 }
280 257
281 updatePageFrameStructure(details.frameId, details.tabId, details.url, 258 updatePageFrameStructure(details.frameId, details.tabId, details.url,
282 details.parentFrameId); 259 details.parentFrameId);
283 }, 260 },
284 {types: ["main_frame", "sub_frame"], urls: ["http://*/*", "https://*/*"]}, 261 {types: ["main_frame", "sub_frame"], urls: ["http://*/*", "https://*/*"]},
285 ["responseHeaders"]); 262 ["responseHeaders"]);
286 263
287 chrome.webNavigation.onBeforeNavigate.addListener(details => 264 browser.webNavigation.onBeforeNavigate.addListener(details =>
288 { 265 {
289 // Since we can only listen for HTTP(S) responses using 266 // Since we can only listen for HTTP(S) responses using
290 // webRequest.onHeadersReceived we must update the page structure here for 267 // webRequest.onHeadersReceived we must update the page structure here for
291 // other navigations. 268 // other navigations.
292 let url = new URL(details.url); 269 let url = new URL(details.url);
293 if (url.protocol != "http:" && url.protocol != "https:") 270 if (url.protocol != "http:" && url.protocol != "https:")
294 { 271 {
295 updatePageFrameStructure(details.frameId, details.tabId, details.url, 272 updatePageFrameStructure(details.frameId, details.tabId, details.url,
296 details.parentFrameId); 273 details.parentFrameId);
297 } 274 }
298 }); 275 });
299 276
300 function forgetTab(tabId) 277 function forgetTab(tabId)
301 { 278 {
302 ext.pages.onRemoved._dispatch(tabId); 279 ext.pages.onRemoved._dispatch(tabId);
303 280
304 ext._removeFromAllPageMaps(tabId); 281 ext._removeFromAllPageMaps(tabId);
305 framesOfTabs.delete(tabId); 282 framesOfTabs.delete(tabId);
306 } 283 }
307 284
308 chrome.tabs.onReplaced.addListener((addedTabId, removedTabId) => 285 browser.tabs.onReplaced.addListener((addedTabId, removedTabId) =>
309 { 286 {
310 forgetTab(removedTabId); 287 forgetTab(removedTabId);
311 }); 288 });
312 289
313 chrome.tabs.onRemoved.addListener(forgetTab); 290 browser.tabs.onRemoved.addListener(forgetTab);
314 291
315 chrome.tabs.onActivated.addListener(details => 292 browser.tabs.onActivated.addListener(details =>
316 { 293 {
317 ext.pages.onActivated._dispatch(new Page({id: details.tabId})); 294 ext.pages.onActivated._dispatch(new Page({id: details.tabId}));
318 }); 295 });
319 296
320 297
321 /* Browser actions */ 298 /* Browser actions */
322 299
323 let BrowserAction = function(tabId) 300 let BrowserAction = function(tabId)
324 { 301 {
325 this._tabId = tabId; 302 this._tabId = tabId;
326 this._changes = null; 303 this._changes = null;
327 }; 304 };
328 BrowserAction.prototype = { 305 BrowserAction.prototype = {
329 _applyChanges() 306 _applyChanges()
330 { 307 {
331 if ("iconPath" in this._changes) 308 if ("iconPath" in this._changes)
332 { 309 {
333 chrome.browserAction.setIcon({ 310 // Firefox for Android displays the browser action not as an icon but
334 tabId: this._tabId, 311 // as a menu item. There is no icon, but such an option may be added in
335 path: { 312 // the future.
313 // https://bugzilla.mozilla.org/show_bug.cgi?id=1331746
314 if ("setIcon" in browser.browserAction)
315 {
316 let path = {
336 16: this._changes.iconPath.replace("$size", "16"), 317 16: this._changes.iconPath.replace("$size", "16"),
337 19: this._changes.iconPath.replace("$size", "19"), 318 19: this._changes.iconPath.replace("$size", "19"),
338 20: this._changes.iconPath.replace("$size", "20"), 319 20: this._changes.iconPath.replace("$size", "20"),
339 32: this._changes.iconPath.replace("$size", "32"), 320 32: this._changes.iconPath.replace("$size", "32"),
340 38: this._changes.iconPath.replace("$size", "38"), 321 38: this._changes.iconPath.replace("$size", "38"),
341 40: this._changes.iconPath.replace("$size", "40") 322 40: this._changes.iconPath.replace("$size", "40")
323 };
324 try
325 {
326 browser.browserAction.setIcon({tabId: this._tabId, path});
342 } 327 }
343 }); 328 catch (e)
329 {
330 // Edge throws if passed icon sizes different than 19,20,38,40px.
331 delete path[16];
332 delete path[32];
333 browser.browserAction.setIcon({tabId: this._tabId, path});
334 }
335 }
344 } 336 }
345 337
346 if ("badgeText" in this._changes) 338 if ("badgeText" in this._changes)
347 { 339 {
348 chrome.browserAction.setBadgeText({ 340 // There is no badge on Firefox for Android; the browser action is
349 tabId: this._tabId, 341 // simply a menu item.
350 text: this._changes.badgeText 342 if ("setBadgeText" in browser.browserAction)
351 }); 343 {
344 browser.browserAction.setBadgeText({
345 tabId: this._tabId,
346 text: this._changes.badgeText
347 });
348 }
352 } 349 }
353 350
354 if ("badgeColor" in this._changes) 351 if ("badgeColor" in this._changes)
355 { 352 {
356 chrome.browserAction.setBadgeBackgroundColor({ 353 // There is no badge on Firefox for Android; the browser action is
357 tabId: this._tabId, 354 // simply a menu item.
358 color: this._changes.badgeColor 355 if ("setBadgeBackgroundColor" in browser.browserAction)
359 }); 356 {
357 browser.browserAction.setBadgeBackgroundColor({
358 tabId: this._tabId,
359 color: this._changes.badgeColor
360 });
361 }
360 } 362 }
361 363
362 this._changes = null; 364 this._changes = null;
363 }, 365 },
364 _queueChanges() 366 _queueChanges()
365 { 367 {
366 chrome.tabs.get(this._tabId, () => 368 browser.tabs.get(this._tabId, () =>
367 { 369 {
368 // If the tab is prerendered, chrome.tabs.get() sets 370 // If the tab is prerendered, browser.tabs.get() sets
369 // chrome.runtime.lastError and we have to delay our changes 371 // browser.runtime.lastError and we have to delay our changes
370 // until the currently visible tab is replaced with the 372 // until the currently visible tab is replaced with the
371 // prerendered tab. Otherwise chrome.browserAction.set* fails. 373 // prerendered tab. Otherwise browser.browserAction.set* fails.
372 if (chrome.runtime.lastError) 374 if (browser.runtime.lastError)
373 { 375 {
374 let onReplaced = (addedTabId, removedTabId) => 376 let onReplaced = (addedTabId, removedTabId) =>
375 { 377 {
376 if (addedTabId == this._tabId) 378 if (addedTabId == this._tabId)
377 { 379 {
378 chrome.tabs.onReplaced.removeListener(onReplaced); 380 browser.tabs.onReplaced.removeListener(onReplaced);
379 this._applyChanges(); 381 this._applyChanges();
380 } 382 }
381 }; 383 };
382 chrome.tabs.onReplaced.addListener(onReplaced); 384 browser.tabs.onReplaced.addListener(onReplaced);
383 } 385 }
384 else 386 else
385 { 387 {
386 this._applyChanges(); 388 this._applyChanges();
387 } 389 }
388 }); 390 });
389 }, 391 },
390 _addChange(name, value) 392 _addChange(name, value)
391 { 393 {
392 if (!this._changes) 394 if (!this._changes)
(...skipping 26 matching lines...) Expand all
419 }; 421 };
420 422
421 423
422 /* Context menus */ 424 /* Context menus */
423 425
424 let contextMenuItems = new ext.PageMap(); 426 let contextMenuItems = new ext.PageMap();
425 let contextMenuUpdating = false; 427 let contextMenuUpdating = false;
426 428
427 let updateContextMenu = () => 429 let updateContextMenu = () =>
428 { 430 {
429 if (contextMenuUpdating) 431 // Firefox for Android does not support context menus.
432 // https://bugzilla.mozilla.org/show_bug.cgi?id=1269062
433 if (!("contextMenus" in browser) || contextMenuUpdating)
430 return; 434 return;
431 435
432 contextMenuUpdating = true; 436 contextMenuUpdating = true;
433 437
434 chrome.tabs.query({active: true, lastFocusedWindow: true}, tabs => 438 browser.tabs.query({active: true, lastFocusedWindow: true}, tabs =>
435 { 439 {
436 chrome.contextMenus.removeAll(() => 440 browser.contextMenus.removeAll(() =>
437 { 441 {
438 contextMenuUpdating = false; 442 contextMenuUpdating = false;
439 443
440 if (tabs.length == 0) 444 if (tabs.length == 0)
441 return; 445 return;
442 446
443 let items = contextMenuItems.get({id: tabs[0].id}); 447 let items = contextMenuItems.get({id: tabs[0].id});
444 448
445 if (!items) 449 if (!items)
446 return; 450 return;
447 451
448 items.forEach(item => 452 items.forEach(item =>
449 { 453 {
450 chrome.contextMenus.create({ 454 browser.contextMenus.create({
451 title: item.title, 455 title: item.title,
452 contexts: item.contexts, 456 contexts: item.contexts,
453 onclick(info, tab) 457 onclick(info, tab)
454 { 458 {
455 item.onclick(new Page(tab), info); 459 item.onclick(new Page(tab), info);
456 } 460 }
457 }); 461 });
458 }); 462 });
459 }); 463 });
460 }); 464 });
(...skipping 21 matching lines...) Expand all
482 let index = items.indexOf(item); 486 let index = items.indexOf(item);
483 if (index != -1) 487 if (index != -1)
484 { 488 {
485 items.splice(index, 1); 489 items.splice(index, 1);
486 updateContextMenu(); 490 updateContextMenu();
487 } 491 }
488 } 492 }
489 } 493 }
490 }; 494 };
491 495
492 chrome.tabs.onActivated.addListener(updateContextMenu); 496 browser.tabs.onActivated.addListener(updateContextMenu);
493 497
494 chrome.windows.onFocusChanged.addListener(windowId => 498 if ("windows" in browser)
495 { 499 {
496 if (windowId != chrome.windows.WINDOW_ID_NONE) 500 browser.windows.onFocusChanged.addListener(windowId =>
497 updateContextMenu(); 501 {
498 }); 502 if (windowId != browser.windows.WINDOW_ID_NONE)
503 updateContextMenu();
504 });
505 }
499 506
500 507
501 /* Web requests */ 508 /* Web requests */
502 509
503 let framesOfTabs = new Map(); 510 let framesOfTabs = new Map();
504 511
505 ext.getFrame = (tabId, frameId) => 512 ext.getFrame = (tabId, frameId) =>
506 { 513 {
507 let frames = framesOfTabs.get(tabId); 514 let frames = framesOfTabs.get(tabId);
508 return frames && frames.get(frameId); 515 return frames && frames.get(frameId);
509 }; 516 };
510 517
511 let handlerBehaviorChangedQuota = 518 let handlerBehaviorChangedQuota =
512 chrome.webRequest.MAX_HANDLER_BEHAVIOR_CHANGED_CALLS_PER_10_MINUTES; 519 browser.webRequest.MAX_HANDLER_BEHAVIOR_CHANGED_CALLS_PER_10_MINUTES;
513 520
514 function propagateHandlerBehaviorChange() 521 function propagateHandlerBehaviorChange()
515 { 522 {
516 // Make sure to not call handlerBehaviorChanged() more often than allowed 523 // Make sure to not call handlerBehaviorChanged() more often than allowed
517 // by chrome.webRequest.MAX_HANDLER_BEHAVIOR_CHANGED_CALLS_PER_10_MINUTES. 524 // by browser.webRequest.MAX_HANDLER_BEHAVIOR_CHANGED_CALLS_PER_10_MINUTES.
518 // Otherwise Chrome notifies the user that this extension is causing issues. 525 // Otherwise Chrome notifies the user that this extension is causing issues.
519 if (handlerBehaviorChangedQuota > 0) 526 if (handlerBehaviorChangedQuota > 0)
520 { 527 {
521 chrome.webNavigation.onBeforeNavigate.removeListener( 528 browser.webNavigation.onBeforeNavigate.removeListener(
522 propagateHandlerBehaviorChange 529 propagateHandlerBehaviorChange
523 ); 530 );
524 chrome.webRequest.handlerBehaviorChanged(); 531 browser.webRequest.handlerBehaviorChanged();
525 532
526 handlerBehaviorChangedQuota--; 533 handlerBehaviorChangedQuota--;
527 setTimeout(() => { handlerBehaviorChangedQuota++; }, 600000); 534 setTimeout(() => { handlerBehaviorChangedQuota++; }, 600000);
528 } 535 }
529 } 536 }
530 537
531 ext.webRequest = { 538 ext.webRequest = {
532 onBeforeRequest: new ext._EventTarget(), 539 onBeforeRequest: new ext._EventTarget(),
533 handlerBehaviorChanged() 540 handlerBehaviorChanged()
534 { 541 {
535 // Defer handlerBehaviorChanged() until navigation occurs. 542 // Defer handlerBehaviorChanged() until navigation occurs.
536 // There wouldn't be any visible effect when calling it earlier, 543 // There wouldn't be any visible effect when calling it earlier,
537 // but it's an expensive operation and that way we avoid to call 544 // but it's an expensive operation and that way we avoid to call
538 // it multiple times, if multiple filters are added/removed. 545 // it multiple times, if multiple filters are added/removed.
539 let {onBeforeNavigate} = chrome.webNavigation; 546 let {onBeforeNavigate} = browser.webNavigation;
540 if (!onBeforeNavigate.hasListener(propagateHandlerBehaviorChange)) 547 if (!onBeforeNavigate.hasListener(propagateHandlerBehaviorChange))
541 onBeforeNavigate.addListener(propagateHandlerBehaviorChange); 548 onBeforeNavigate.addListener(propagateHandlerBehaviorChange);
542 } 549 }
543 }; 550 };
544 551
545 chrome.tabs.query({}, tabs => 552 browser.tabs.query({}, tabs =>
546 { 553 {
547 tabs.forEach(tab => 554 tabs.forEach(tab =>
548 { 555 {
549 chrome.webNavigation.getAllFrames({tabId: tab.id}, details => 556 browser.webNavigation.getAllFrames({tabId: tab.id}, details =>
550 { 557 {
551 if (details && details.length > 0) 558 if (details && details.length > 0)
552 { 559 {
553 let frames = new Map(); 560 let frames = new Map();
554 framesOfTabs.set(tab.id, frames); 561 framesOfTabs.set(tab.id, frames);
555 562
556 for (let detail of details) 563 for (let detail of details)
557 { 564 {
558 let frame = {url: new URL(detail.url)}; 565 let frame = {url: new URL(detail.url)};
559 frames.set(detail.frameId, frame); 566 frames.set(detail.frameId, frame);
560 567
561 if (detail.parentFrameId != -1) 568 if (detail.parentFrameId != -1)
562 frame.parent = frames.get(detail.parentFrameId); 569 frame.parent = frames.get(detail.parentFrameId);
563 } 570 }
564 } 571 }
565 }); 572 });
566 }); 573 });
567 }); 574 });
568 575
569 chrome.webRequest.onBeforeRequest.addListener(details => 576 browser.webRequest.onBeforeRequest.addListener(details =>
570 { 577 {
571 // The high-level code isn't interested in requests that aren't 578 // The high-level code isn't interested in requests that aren't
572 // related to a tab or requests loading a top-level document, 579 // related to a tab or requests loading a top-level document,
573 // those should never be blocked. 580 // those should never be blocked.
574 if (details.type == "main_frame") 581 if (details.type == "main_frame")
575 return; 582 return;
576 583
577 // Filter out requests from non web protocols. Ideally, we'd explicitly 584 // Filter out requests from non web protocols. Ideally, we'd explicitly
578 // specify the protocols we are interested in (i.e. http://, https://, 585 // specify the protocols we are interested in (i.e. http://, https://,
579 // ws:// and wss://) with the url patterns, given below, when adding this 586 // ws:// and wss://) with the url patterns, given below, when adding this
(...skipping 23 matching lines...) Expand all
603 } 610 }
604 611
605 if (ext.webRequest.onBeforeRequest._dispatch( 612 if (ext.webRequest.onBeforeRequest._dispatch(
606 url, type, page, frame).includes(false)) 613 url, type, page, frame).includes(false))
607 return {cancel: true}; 614 return {cancel: true};
608 }, {urls: ["<all_urls>"]}, ["blocking"]); 615 }, {urls: ["<all_urls>"]}, ["blocking"]);
609 616
610 617
611 /* Message passing */ 618 /* Message passing */
612 619
613 chrome.runtime.onMessage.addListener((message, rawSender, sendResponse) => 620 browser.runtime.onMessage.addListener((message, rawSender, sendResponse) =>
614 { 621 {
615 let sender = {}; 622 let sender = {};
616 623
617 // Add "page" and "frame" if the message was sent by a content script. 624 // Add "page" and "frame" if the message was sent by a content script.
618 // If sent by popup or the background page itself, there is no "tab". 625 // If sent by popup or the background page itself, there is no "tab".
619 if ("tab" in rawSender) 626 if ("tab" in rawSender)
620 { 627 {
621 sender.page = new Page(rawSender.tab); 628 sender.page = new Page(rawSender.tab);
622 sender.frame = { 629 sender.frame = {
623 id: rawSender.frameId, 630 id: rawSender.frameId,
(...skipping 11 matching lines...) Expand all
635 if (frame) 642 if (frame)
636 return frame.parent || null; 643 return frame.parent || null;
637 644
638 return frames.get(0) || null; 645 return frames.get(0) || null;
639 } 646 }
640 }; 647 };
641 } 648 }
642 649
643 return ext.onMessage._dispatch( 650 return ext.onMessage._dispatch(
644 message, sender, sendResponse 651 message, sender, sendResponse
645 ).indexOf(true) != -1; 652 ).includes(true);
646 }); 653 });
647 654
648 655
649 /* Storage */ 656 /* Storage */
650 657
651 ext.storage = { 658 ext.storage = {
652 get(keys, callback) 659 get(keys, callback)
653 { 660 {
654 chrome.storage.local.get(keys, callback); 661 browser.storage.local.get(keys, callback);
655 }, 662 },
656 set(key, value, callback) 663 set(key, value, callback)
657 { 664 {
658 let items = {}; 665 let items = {};
659 items[key] = value; 666 items[key] = value;
660 chrome.storage.local.set(items, callback); 667 browser.storage.local.set(items, callback);
661 }, 668 },
662 remove(key, callback) 669 remove(key, callback)
663 { 670 {
664 chrome.storage.local.remove(key, callback); 671 browser.storage.local.remove(key, callback);
665 }, 672 },
666 onChanged: chrome.storage.onChanged 673 onChanged: browser.storage.onChanged
667 }; 674 };
668
669 /* Options */
670
671 if ("openOptionsPage" in chrome.runtime)
672 {
673 ext.showOptions = callback =>
674 {
675 if (!callback)
676 {
677 chrome.runtime.openOptionsPage();
678 }
679 else
680 {
681 chrome.runtime.openOptionsPage(() =>
682 {
683 if (chrome.runtime.lastError)
684 return;
685
686 chrome.tabs.query({active: true, lastFocusedWindow: true}, tabs =>
687 {
688 if (tabs.length > 0)
689 {
690 if (tabs[0].status == "complete")
691 callback(new Page(tabs[0]));
692 else
693 afterTabLoaded(callback)(tabs[0]);
694 }
695 });
696 });
697 }
698 };
699 }
700 else
701 {
702 // Edge does not yet support runtime.openOptionsPage (tested version 38)
703 // and so this workaround needs to stay for now.
704 // We are not using extension.getURL to get the absolute path here
705 // because of the Edge issue:
706 // https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/1027 6332/
707 ext.showOptions = callback =>
708 {
709 chrome.windows.getLastFocused(win =>
710 {
711 let optionsUrl = "options.html";
712 let queryInfo = {url: optionsUrl};
713
714 // extension pages can't be accessed in incognito windows. In order to
715 // correctly mimic the way in which Chrome opens extension options,
716 // we have to focus the options page in any other window.
717 if (!win.incognito)
718 queryInfo.windowId = win.id;
719
720 chrome.tabs.query(queryInfo, tabs =>
721 {
722 if (tabs.length > 0)
723 {
724 let tab = tabs[0];
725
726 chrome.windows.update(tab.windowId, {focused: true});
727 chrome.tabs.update(tab.id, {active: true});
728
729 if (callback)
730 callback(new Page(tab));
731 }
732 else
733 {
734 ext.pages.open(optionsUrl, callback);
735 }
736 });
737 });
738 };
739 }
740 675
741 /* Windows */ 676 /* Windows */
742 ext.windows = { 677 ext.windows = {
743 create(createData, callback) 678 create(createData, callback)
744 { 679 {
745 chrome.windows.create(createData, createdWindow => 680 browser.windows.create(createData, createdWindow =>
746 { 681 {
747 afterTabLoaded(callback)(createdWindow.tabs[0]); 682 afterTabLoaded(callback)(createdWindow.tabs[0]);
748 }); 683 });
749 } 684 }
750 }; 685 };
751 }()); 686 }
LEFTRIGHT

Powered by Google App Engine
This is Rietveld