Bug 1438274 - Fix browser and page actions clearance when navigating
MozReview-Commit-ID: Jb43H65LmFB
--- a/browser/components/extensions/ext-browser.js
+++ b/browser/components/extensions/ext-browser.js
@@ -109,17 +109,16 @@ global.makeWidgetId = id => {
global.TabContext = class extends EventEmitter {
constructor(getDefaults, extension) {
super();
this.extension = extension;
this.getDefaults = getDefaults;
this.tabData = new WeakMap();
- this.lastLocation = new WeakMap();
windowTracker.addListener("progress", this);
windowTracker.addListener("TabSelect", this);
}
get(nativeTab) {
if (!this.tabData.has(nativeTab)) {
this.tabData.set(nativeTab, this.getDefaults(nativeTab));
@@ -135,34 +134,24 @@ global.TabContext = class extends EventE
handleEvent(event) {
if (event.type == "TabSelect") {
let nativeTab = event.target;
this.emit("tab-select", nativeTab);
this.emit("location-change", nativeTab);
}
}
- onStateChange(browser, webProgress, request, stateFlags, statusCode) {
- let flags = Ci.nsIWebProgressListener;
-
- if (!(~stateFlags & (flags.STATE_IS_WINDOW | flags.STATE_START) ||
- this.lastLocation.has(browser))) {
- this.lastLocation.set(browser, request.URI);
- }
- }
-
onLocationChange(browser, webProgress, request, locationURI, flags) {
let gBrowser = browser.ownerGlobal.gBrowser;
- let lastLocation = this.lastLocation.get(browser);
- if (browser === gBrowser.selectedBrowser &&
- !(lastLocation && lastLocation.equalsExceptRef(browser.currentURI))) {
- let nativeTab = gBrowser.getTabForBrowser(browser);
- this.emit("location-change", nativeTab, true);
+ if (browser === gBrowser.selectedBrowser) {
+ let tab = gBrowser.getTabForBrowser(browser);
+ // fromBrowse will be false in case of e.g. a hash change or history.pushState
+ let fromBrowse = !(flags & Ci.nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT);
+ this.emit("location-change", tab, fromBrowse);
}
- this.lastLocation.set(browser, browser.currentURI);
}
shutdown() {
windowTracker.removeListener("progress", this);
windowTracker.removeListener("TabSelect", this);
}
};
--- a/browser/components/extensions/test/browser/browser_ext_browserAction_context.js
+++ b/browser/components/extensions/test/browser/browser_ext_browserAction_context.js
@@ -221,16 +221,27 @@ add_task(async function testTabSwitchCon
{"icon": browser.runtime.getURL("default-2.png"),
"popup": browser.runtime.getURL("default-2.html"),
"title": "Default Title 2",
"badge": "d2",
"badgeBackgroundColor": [0, 0xff, 0, 0xff],
"disabled": false},
];
+ let promiseTabLoad = details => {
+ return new Promise(resolve => {
+ browser.tabs.onUpdated.addListener(function listener(tabId, changed) {
+ if (tabId == details.id && changed.url == details.url) {
+ browser.tabs.onUpdated.removeListener(listener);
+ resolve();
+ }
+ });
+ });
+ };
+
return [
async expect => {
browser.test.log("Initial state, expect default properties.");
await expectDefaults(details[0]);
expect(details[0]);
},
async expect => {
@@ -240,16 +251,23 @@ add_task(async function testTabSwitchCon
await expectDefaults(details[0]);
expect(details[1]);
},
async expect => {
browser.test.log("Create a new tab. Expect default properties.");
let tab = await browser.tabs.create({active: true, url: "about:blank?0"});
tabs.push(tab.id);
+ browser.test.log("Await tab load.");
+ let promise = promiseTabLoad({id: tabs[1], url: "about:blank?0"});
+ let {url} = await browser.tabs.get(tabs[1]);
+ if (url === "about:blank") {
+ await promise;
+ }
+
await expectDefaults(details[0]);
expect(details[0]);
},
async expect => {
browser.test.log("Change properties. Expect new properties.");
let tabId = tabs[1];
browser.browserAction.setIcon({tabId, path: "2.png"});
browser.browserAction.setPopup({tabId, popup: "2.html"});
--- a/browser/components/extensions/test/browser/browser_ext_pageAction_context.js
+++ b/browser/components/extensions/test/browser/browser_ext_pageAction_context.js
@@ -95,18 +95,23 @@ add_task(async function testTabSwitchCon
expect(details[1]);
},
async expect => {
browser.test.log("Create a new tab. No icon visible.");
let tab = await browser.tabs.create({active: true, url: "about:blank?0"});
tabs.push(tab.id);
expect(null);
},
- expect => {
+ async expect => {
browser.test.log("Await tab load. No icon visible.");
+ let promise = promiseTabLoad({id: tabs[1], url: "about:blank?0"});
+ let {url} = await browser.tabs.get(tabs[1]);
+ if (url === "about:blank") {
+ await promise;
+ }
expect(null);
},
async expect => {
browser.test.log("Change properties. Expect new properties.");
let tabId = tabs[1];
await browser.pageAction.show(tabId);
browser.pageAction.setIcon({tabId, path: "2.png"});
@@ -188,8 +193,101 @@ add_task(async function testTabSwitchCon
"unable to set popup to about:addons");
expect(null);
},
];
},
});
});
+
+add_task(async function testNavigationClearsData() {
+ let url = "http://example.com/";
+ let default_title = "Default title";
+ let tab_title = "Tab title";
+
+ let {Management: {global: {tabTracker}}} = ChromeUtils.import("resource://gre/modules/Extension.jsm", {});
+ let extension, tab, tabId, tabs = [];
+ async function addTab(...args) {
+ tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, ...args);
+ tabId = tabTracker.getId(tab);
+ tabs.push(tab);
+ }
+ async function locationChange(url, task) {
+ let locationChanged = BrowserTestUtils.waitForLocationChange(gBrowser, url);
+ await ContentTask.spawn(tab.linkedBrowser, url, task);
+ await locationChanged;
+ }
+ function setUrl(url) {
+ return locationChange(url, (url) => { content.location.href = url; });
+ }
+ function historyPushState(url) {
+ return locationChange(url, (url) => { content.history.pushState(null, null, url); });
+ }
+ async function sendMessage(method, param, expect, msg) {
+ extension.sendMessage({method, param, expect, msg});
+ await extension.awaitMessage("done");
+ }
+ async function expectTabSpecificData(msg) {
+ await sendMessage("isShown", {tabId}, true, msg);
+ await sendMessage("getTitle", {tabId}, tab_title, msg);
+ }
+ async function expectDefaultData(msg) {
+ await sendMessage("isShown", {tabId}, false, msg);
+ await sendMessage("getTitle", {tabId}, default_title, msg);
+ }
+ async function setTabSpecificData() {
+ await expectDefaultData("Expect default data before setting tab-specific data.");
+ await sendMessage("show", tabId);
+ await sendMessage("setTitle", {tabId, title: tab_title});
+ await expectTabSpecificData("Expect tab-specific data after setting it.");
+ }
+
+ info("Load a tab before installing the extension");
+ await addTab(url, true, true);
+
+ extension = ExtensionTestUtils.loadExtension({
+ manifest: {
+ page_action: {default_title},
+ },
+ background: function() {
+ browser.test.onMessage.addListener(async ({method, param, expect, msg}) => {
+ let result = await browser.pageAction[method](param);
+ if (expect !== undefined) {
+ browser.test.assertEq(expect, result, msg);
+ }
+ browser.test.sendMessage("done");
+ });
+ },
+ });
+ await extension.startup();
+
+ info("Set tab-specific data to the existing tab.");
+ await setTabSpecificData();
+
+ info("Add a hash. Does not cause navigation.");
+ await setUrl(url + "#hash");
+ await expectTabSpecificData("Adding a hash does not clear tab-specific data");
+
+ info("Remove the hash. Causes navigation.");
+ await setUrl(url);
+ await expectDefaultData("Removing hash clears tab-specific data");
+
+ info("Open a new tab, set tab-specific data to it.");
+ await addTab("about:newtab", false, false);
+ await setTabSpecificData();
+
+ info("Load a page in that tab.");
+ await setUrl(url);
+ await expectDefaultData("Loading a page clears tab-specific data.");
+
+ info("Set tab-specific data.");
+ await setTabSpecificData();
+
+ info("Push history state. Does not cause navigation.");
+ await historyPushState(url + "/path");
+ await expectTabSpecificData("history.pushState() does not clear tab-specific data");
+
+ for (let tab of tabs) {
+ await BrowserTestUtils.removeTab(tab);
+ }
+ await extension.unload();
+});
--- a/browser/components/extensions/test/browser/browser_ext_pageAction_title.js
+++ b/browser/components/extensions/test/browser/browser_ext_pageAction_title.js
@@ -96,18 +96,23 @@ add_task(async function testTabSwitchCon
expect(details[1]);
},
async expect => {
browser.test.log("Create a new tab. No icon visible.");
let tab = await browser.tabs.create({active: true, url: "about:blank?0"});
tabs.push(tab.id);
expect(null);
},
- expect => {
+ async expect => {
browser.test.log("Await tab load. No icon visible.");
+ let promise = promiseTabLoad({id: tabs[1], url: "about:blank?0"});
+ let {url} = await browser.tabs.get(tabs[1]);
+ if (url === "about:blank") {
+ await promise;
+ }
expect(null);
},
async expect => {
browser.test.log("Change properties. Expect new properties.");
let tabId = tabs[1];
await browser.pageAction.show(tabId);
browser.pageAction.setIcon({tabId, path: "2.png"});