commit 6f18fa3f98d2a9370ba9843b93f94efacd85ae93
parent 70d833b7b5bb7bd25bc575326d19b9d8ee004933
Author: Stephen Thompson <sthompson@mozilla.com>
Date: Mon, 29 Dec 2025 15:52:18 +0000
Bug 2005598 - update canonical URL on pushState r=dwalker,tabbrowser-reviewers
When TabNotesController.onLocationChange detects a tab navigating due to `history.pushState()`, it will request that the CanonicalURL actor re-detect the canonical URL in that tab. This allows the tab note state to change appropriately when navigating within a web site that uses `history.pushState()`.
Differential Revision: https://phabricator.services.mozilla.com/D276085
Diffstat:
2 files changed, 62 insertions(+), 1 deletion(-)
diff --git a/browser/components/tabnotes/CanonicalURLChild.sys.mjs b/browser/components/tabnotes/CanonicalURLChild.sys.mjs
@@ -27,6 +27,19 @@ export class CanonicalURLChild extends JSWindowActorChild {
}
/**
+ * Called when a message is received from the parent process.
+ *
+ * @param {ReceiveMessageArgument} msg
+ */
+ receiveMessage(msg) {
+ switch (msg.name) {
+ case "CanonicalURL:Detect":
+ this.#discoverCanonicalUrl();
+ break;
+ }
+ }
+
+ /**
* Find a canonical URL in the document and tell the parent about it.
*/
#discoverCanonicalUrl() {
diff --git a/browser/components/tabnotes/TabNotesController.sys.mjs b/browser/components/tabnotes/TabNotesController.sys.mjs
@@ -5,6 +5,8 @@
*/
import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";
+/** @import { CanonicalURLParent } from "./CanonicalURLParent.sys.mjs" */
+
const lazy = {};
ChromeUtils.defineESModuleGetters(lazy, {
BrowserWindowTracker: "resource:///modules/BrowserWindowTracker.sys.mjs",
@@ -174,11 +176,57 @@ class TabNotesControllerClass {
if (!aWebProgress.isTopLevel) {
return;
}
- // If we're still on the same page, the tab note indicator does not need to change.
+
if (aFlags & Ci.nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT) {
+ if (
+ aWebProgress.loadType & Ci.nsIDocShell.LOAD_CMD_RELOAD ||
+ aWebProgress.loadType & Ci.nsIDocShell.LOAD_CMD_HISTORY
+ ) {
+ // User is reloading/returning to the same document via history. We
+ // can count on CanonicalURLChild to listen for `pageshow` and tell us
+ // about the canonical URL at the new location.
+ lazy.logConsole.debug(
+ "reload/history navigation, waiting for pageshow",
+ aLocation.spec
+ );
+ return;
+ }
+
+ if (aFlags & Ci.nsIWebProgressListener.LOCATION_CHANGE_HASHCHANGE) {
+ // The web site modified the hash/fragment identifier part of the URL
+ // directly. TODO: determine how and whether to handle `hashchange`.
+ lazy.logConsole.debug("fragment identifier changed", aLocation.spec);
+ return;
+ }
+
+ if (aWebProgress.loadType & Ci.nsIDocShell.LOAD_CMD_PUSHSTATE) {
+ // Web page is using `history.pushState()` to change URLs. There isn't
+ // a way for CanonicalURLChild to detect this in the content process,
+ // so we need to ask it to recalculate canonical URLs to see if they
+ // changed.
+ /** @type {CanonicalURLParent|undefined} */
+ let parent =
+ aBrowser.browsingContext?.currentWindowGlobal.getActor(
+ "CanonicalURL"
+ );
+
+ parent?.sendAsyncMessage("CanonicalURL:Detect");
+ lazy.logConsole.debug(
+ "requesting CanonicalURL:Detect due to history.pushState",
+ aLocation.spec
+ );
+ return;
+ }
+
+ // General same document case: we are navigating in the same document,
+ // so the tab note indicator does not need to change.
return;
}
+ // General case: we are doing normal navigation to another URL, so we
+ // clear the canonical URL/tab note state on the tab and wait for
+ // `CanonicalURL:Identified` to tell us whether the new location has
+ // a tab note.
const tab = aBrowser.ownerGlobal.gBrowser.getTabForBrowser(aBrowser);
tab.canonicalUrl = undefined;
tab.hasTabNote = false;