e and should therefore display a tab // notes icon. const browser = event.target; const { canonicalUrl } = event.detail; const gBrowser = browser.getTabBrowser(); const tab = gBrowser.getTabForBrowser(browser); tab.canonicalUrl = canonicalUrl; lazy.TabNotes.has(tab).then(hasTabNote => { tab.hasTabNote = hasTabNote; }); lazy.logConsole.debug("CanonicalURL:Identified", tab, canonicalUrl); } break; case "TabNote:Created": { const { telemetrySource } = event.detail; if (telemetrySource) { Glean.tabNotes.added.record({ source: telemetrySource, }); } // A new tab note was created for a specific canonical URL. Ensure that // all tabs with the same canonical URL also indicate that there is a // tab note. const { canonicalUrl } = event.target; for (const win of lazy.BrowserWindowTracker.orderedWindows) { for (const tab of win.gBrowser.tabs) { if (tab.canonicalUrl == canonicalUrl) { tab.hasTabNote = true; } } } lazy.logConsole.debug("TabNote:Created", canonicalUrl); } break; case "TabNote:Edited": { const { canonicalUrl } = event.target; const { telemetrySource } = event.detail; if (telemetrySource) { Glean.tabNotes.edited.record({ source: telemetrySource, }); } lazy.logConsole.debug("TabNote:Edited", canonicalUrl); } break; case "TabNote:Removed": { const { telemetrySource, note } = event.detail; const now = Temporal.Now.instant(); const noteAgeHours = Math.round( now.since(note.created).total("hours") ); if (telemetrySource) { Glean.tabNotes.deleted.record({ source: telemetrySource, note_age_hours: noteAgeHours, }); } // A new tab note was removed from a specific canonical URL. Ensure that // all tabs with the same canonical URL also indicate that there is no // longer a tab note. const { canonicalUrl } = event.target; for (const win of lazy.BrowserWindowTracker.orderedWindows) { for (const tab of win.gBrowser.tabs) { if (tab.canonicalUrl == canonicalUrl) { tab.hasTabNote = false; } } } lazy.logConsole.debug("TabNote:Removed", canonicalUrl); } 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 (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.getExistingActor( "CanonicalURL" ); if (parent) { 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; lazy.logConsole.debug("clear tab note due to location change", tab); } } export const TabNotesController = new TabNotesControllerClass(); PK