commit 90528f3c566353e8aa264ce81abc090af53344a9
parent d9a3929af8ed876781628b19739738e174921d46
Author: Stephen Thompson <sthompson@mozilla.com>
Date: Tue, 9 Dec 2025 15:56:56 +0000
Bug 1998015 - update canonical URL on location change and pageshow r=tabbrowser-reviewers,dao
The canonical URL is currently identified on DOMContentLoaded in a content process. That causes TabNotesController to decide whether to show a tab note icon on the associated tab.
This patch clears the canonical URL and tab note icon on a tab when its associated browser starts navigating to a new location.
In addition to DOMContentLoaded, a content process will also notify about its canonical URL on `pageshow` events.
With these changes, the tab note icon stays in sync with the browser in more cases:
- navigating to a page that's ineligible for tab notes right now (e.g. about: pages)
- using the back/forward buttons
Differential Revision: https://phabricator.services.mozilla.com/D273528
Diffstat:
4 files changed, 40 insertions(+), 0 deletions(-)
diff --git a/browser/components/DesktopActorRegistry.sys.mjs b/browser/components/DesktopActorRegistry.sys.mjs
@@ -286,6 +286,7 @@ let JSWINDOWACTORS = {
esModuleURI: "resource:///actors/CanonicalURLChild.sys.mjs",
events: {
DOMContentLoaded: {},
+ pageshow: {},
},
},
enablePreference: "browser.tabs.notes.enabled",
diff --git a/browser/components/tabnotes/CanonicalURLChild.sys.mjs b/browser/components/tabnotes/CanonicalURLChild.sys.mjs
@@ -21,6 +21,7 @@ export class CanonicalURLChild extends JSWindowActorChild {
handleEvent(event) {
switch (event.type) {
case "DOMContentLoaded":
+ case "pageshow":
this.#discoverCanonicalUrl();
}
}
diff --git a/browser/components/tabnotes/TabNotesController.sys.mjs b/browser/components/tabnotes/TabNotesController.sys.mjs
@@ -68,6 +68,7 @@ class TabNotesControllerClass {
registerWindow(win) {
if (lazy.TAB_NOTES_ENABLED) {
EVENTS.forEach(eventName => win.addEventListener(eventName, this));
+ win.gBrowser.addTabsProgressListener(this);
lazy.logConsole.debug("registerWindow", EVENTS, win);
}
}
@@ -81,6 +82,7 @@ class TabNotesControllerClass {
unregisterWindow(win) {
if (lazy.TAB_NOTES_ENABLED) {
EVENTS.forEach(eventName => win.removeEventListener(eventName, this));
+ win.gBrowser.removeTabsProgressListener(this);
lazy.logConsole.debug("unregisterWindow", EVENTS, win);
}
}
@@ -173,6 +175,34 @@ class TabNotesControllerClass {
break;
}
}
+
+ /**
+ * Invoked by Tabbrowser after we register with `Tabbrowser.addProgressListener`.
+ *
+ * Clears the tab note icon and canonical URL from a tab when navigation starts
+ * within a tab.
+ *
+ * The CanonicalURL actor running in this tab's browser will report the canonical
+ * URL of the new destination in the browser, which will determine whether the
+ * new destination has an associated tab note.
+ *
+ * @type {TabbrowserWebProgressListener<"onLocationChange">}
+ */
+ onLocationChange(aBrowser, aWebProgress, aRequest, aLocation, aFlags) {
+ // Tab notes only apply to the top-level frames loaded in tabs.
+ 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) {
+ return;
+ }
+
+ const tab = aBrowser.ownerGlobal.gBrowser.getTabForBrowser(aBrowser);
+ tab.canonicalUrl = undefined;
+ tab.hasTabNote = false;
+ lazy.logConsole.debug("clear tab note due to location change", tab);
+ }
}
export const TabNotesController = new TabNotesControllerClass();
diff --git a/browser/components/tabnotes/types/tabnotes.ts b/browser/components/tabnotes/types/tabnotes.ts
@@ -12,6 +12,7 @@ interface CanonicalURLIdentifiedEvent {
target: MozBrowser;
detail: {
canonicalUrl: string;
+ canonicalUrlSources: CanonicalURLSource[];
};
}
@@ -21,3 +22,10 @@ interface TabNoteRecord {
created: Temporal.Instant;
text: string;
}
+
+type TabbrowserWebProgressListener<
+ ListenerName extends keyof nsIWebProgressListener,
+ F = nsIWebProgressListener[ListenerName],
+> = F extends (...args: any) => any
+ ? (aBrowser: MozBrowser, ...rest: Parameters<F>) => ReturnType<F>
+ : never;