Bug 1310019 - web extension API : chrome.tabs.query doesn’t get tabs title at first call, r?kmag
Add permission to the active tab on mousedown in ext-browserAction.js
MozReview-Commit-ID: H0oXQElppo7
--- a/browser/components/extensions/ext-browserAction.js
+++ b/browser/components/extensions/ext-browserAction.js
@@ -144,16 +144,23 @@ BrowserAction.prototype = {
if (event.button == 0) {
// Begin pre-loading the browser for the popup, so it's more likely to
// be ready by the time we get a complete click.
let tab = window.gBrowser.selectedTab;
let popupURL = this.getProperty(tab, "popup");
let enabled = this.getProperty(tab, "enabled");
if (popupURL && enabled) {
+ // Add permission for the active tab so it will exist for the popup.
+ // Store the tab to revoke the permission during clearPopup.
+ if (!this.pendingPopup && !this.tabManager.hasActiveTabPermission(tab)) {
+ this.tabManager.addActiveTabPermission(tab);
+ this.tabToRevokeDuringClearPopup = tab;
+ }
+
this.pendingPopup = this.getPopup(window, popupURL);
window.addEventListener("mouseup", this, true);
} else {
this.clearPopup();
}
}
break;
@@ -206,16 +213,20 @@ BrowserAction.prototype = {
},
/**
* Clears any pending pre-loaded popup and related timeouts.
*/
clearPopup() {
this.clearPopupTimeout();
if (this.pendingPopup) {
+ if (this.tabToRevokeDuringClearPopup) {
+ this.tabManager.revokeActiveTabPermission(this.tabToRevokeDuringClearPopup);
+ this.tabToRevokeDuringClearPopup = null;
+ }
this.pendingPopup.destroy();
this.pendingPopup = null;
}
},
/**
* Clears any pending timeouts to clear stale, pre-loaded popups.
*/
--- a/browser/components/extensions/ext-utils.js
+++ b/browser/components/extensions/ext-utils.js
@@ -645,16 +645,20 @@ ExtensionTabManager.prototype = {
// Note that, unlike Chrome, we don't currently clear this permission with
// the tab navigates. If the inner window is revived from BFCache before
// we've granted this permission to a new inner window, the extension
// maintains its permissions for it.
this.hasTabPermissionFor.set(tab, tab.linkedBrowser.innerWindowID);
}
},
+ revokeActiveTabPermission(tab = TabManager.activeTab) {
+ this.hasTabPermissionFor.delete(tab);
+ },
+
// Returns true if the extension has the "activeTab" permission for this tab.
// This is somewhat more permissive than the generic "tabs" permission, as
// checked by |hasTabPermission|, in that it also allows programmatic script
// injection without an explicit host permission.
hasActiveTabPermission(tab) {
// This check is redundant with addTabPermission, but cheap.
if (this.extension.hasPermission("activeTab")) {
return (this.hasTabPermissionFor.has(tab) &&
--- a/browser/components/extensions/test/browser/browser_ext_browserAction_popup.js
+++ b/browser/components/extensions/test/browser/browser_ext_browserAction_popup.js
@@ -1,15 +1,15 @@
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
+let scriptPage = url => `<html><head><meta charset="utf-8"><script src="${url}"></script></head><body>${url}</body></html>`;
+
function* testInArea(area) {
- let scriptPage = url => `<html><head><meta charset="utf-8"><script src="${url}"></script></head><body>${url}</body></html>`;
-
let extension = ExtensionTestUtils.loadExtension({
manifest: {
"background": {
"page": "data/background.html",
},
"browser_action": {
"default_popup": "popup-a.html",
"browser_style": true,
@@ -196,45 +196,53 @@ add_task(function* testBrowserActionInPa
add_task(function* testBrowserActionClickCanceled() {
let extension = ExtensionTestUtils.loadExtension({
manifest: {
"browser_action": {
"default_popup": "popup.html",
"browser_style": true,
},
+ "permissions": ["activeTab"],
},
files: {
"popup.html": `<!DOCTYPE html><html><head><meta charset="utf-8"></head></html>`,
},
});
yield extension.startup();
const {GlobalManager, Management: {global: {browserActionFor}}} = Cu.import("resource://gre/modules/Extension.jsm", {});
let ext = GlobalManager.extensionMap.get(extension.id);
let browserAction = browserActionFor(ext);
let widget = getBrowserActionWidget(extension).forWindow(window);
+ let tab = window.gBrowser.selectedTab;
// Test canceled click.
EventUtils.synthesizeMouseAtCenter(widget.node, {type: "mousedown", button: 0}, window);
isnot(browserAction.pendingPopup, null, "Have pending popup");
is(browserAction.pendingPopup.window, window, "Have pending popup for the correct window");
is(browserAction.pendingPopupTimeout, null, "Have no pending popup timeout");
+ is(browserAction.tabToRevokeDuringClearPopup, tab, "Tab to revoke was saved");
+ is(browserAction.tabManager.hasActiveTabPermission(tab), true, "Active tab was granted permission");
+
EventUtils.synthesizeMouseAtCenter(document.documentElement, {type: "mouseup", button: 0}, window);
is(browserAction.pendingPopup, null, "Pending popup was cleared");
is(browserAction.pendingPopupTimeout, null, "Have no pending popup timeout");
+ is(browserAction.tabToRevokeDuringClearPopup, null, "Tab to revoke was removed");
+ is(browserAction.tabManager.hasActiveTabPermission(tab), false, "Permission was revoked from tab");
+
// Test completed click.
EventUtils.synthesizeMouseAtCenter(widget.node, {type: "mousedown", button: 0}, window);
isnot(browserAction.pendingPopup, null, "Have pending popup");
is(browserAction.pendingPopup.window, window, "Have pending popup for the correct window");
is(browserAction.pendingPopupTimeout, null, "Have no pending popup timeout");
@@ -325,8 +333,49 @@ add_task(function* testBrowserActionDisa
is(browserAction.pendingPopupTimeout, null, "Have no pending popup timeout");
// Give the popup a chance to load and trigger a failure, if it was
// erroneously opened.
yield new Promise(resolve => setTimeout(resolve, 250));
yield extension.unload();
});
+
+add_task(function* testBrowserActionTabPopulation() {
+ // Note: This test relates to https://bugzilla.mozilla.org/show_bug.cgi?id=1310019
+ let extension = ExtensionTestUtils.loadExtension({
+ manifest: {
+ "browser_action": {
+ "default_popup": "popup.html",
+ "browser_style": true,
+ },
+ "permissions": ["activeTab"],
+ },
+
+ files: {
+ "popup.html": scriptPage("popup.js"),
+ "popup.js": function() {
+ browser.tabs.query({active: true, currentWindow: true}).then(tabs => {
+ browser.test.assertEq("mochitest index /",
+ tabs[0].title,
+ "Tab has the expected title on first click");
+ browser.test.sendMessage("tabTitle");
+ });
+ },
+ },
+ });
+
+ let win = yield BrowserTestUtils.openNewBrowserWindow();
+ yield BrowserTestUtils.loadURI(win.gBrowser.selectedBrowser, "http://example.com/");
+ yield BrowserTestUtils.browserLoaded(win.gBrowser.selectedBrowser);
+
+ yield extension.startup();
+
+ let widget = getBrowserActionWidget(extension).forWindow(win);
+ EventUtils.synthesizeMouseAtCenter(widget.node, {type: "mousedown", button: 0}, win);
+
+ yield extension.awaitMessage("tabTitle");
+
+ EventUtils.synthesizeMouseAtCenter(widget.node, {type: "mouseup", button: 0}, win);
+
+ yield extension.unload();
+ yield BrowserTestUtils.closeWindow(win);
+});