docShell .QueryInterface(Ci.nsIInterfaceRequestor) .getInterface(Ci.nsIWebProgress); webProgress.removeProgressListener(this.#progressListener); } onLocationChange(webProgress, request, location, flags) { // We don't care about inner-frame navigations. if (!webProgress.isTopLevel) { return; } // If this is a new document then the DOMContentLoaded event will trigger // the new interaction instead. if (!(flags & Ci.nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT)) { return; } this.#recordNewPage(); } #recordNewPage() { if (!this.docShell.currentDocumentChannel) { // If there is no document channel, then it is something we're not // interested in, but we do need to know that the previous interaction // has ended. this.sendAsyncMessage("Interactions:PageHide"); return; } let docInfo = this.#getDocumentInfo(); // This may happen when the page calls replaceState or pushState with the // same URL. We'll just consider this to not be a new page. if (docInfo.url == this.#currentURL) { return; } this.#currentURL = docInfo.url; if ( this.docShell.currentDocumentChannel instanceof Ci.nsIHttpChannel && !this.docShell.currentDocumentChannel.requestSucceeded ) { return; } this.sendAsyncMessage("Interactions:PageLoaded", docInfo); } async handleEvent(event) { if (this.isContentWindowPrivate) { // No recording in private browsing mode. return; } switch (event.type) { case "DOMContentLoaded": { this.#recordNewPage(); break; } case "pagehide": { // We generally expect this to be an nsIHttpChannel, if it isn't // then the if statement below will return early anyway. let currentDocumentChannel = /** @type {nsIHttpChannel} */ ( this.docShell.currentDocumentChannel ); if (!currentDocumentChannel) { return; } if (!currentDocumentChannel.requestSucceeded) { return; } this.sendAsyncMessage("Interactions:PageHide"); break; } } } /** * Returns the current document information for sending to the parent process. * * @returns {{ isActive: boolean, url: string, referrer: * }?} */ #getDocumentInfo() { let doc = this.document; let referrer; if (doc.referrer) { referrer = Services.io.newURI(doc.referrer); } return { isActive: this.manager.browsingContext.isActive, url: doc.documentURIObject.specIgnoringRef, referrer: referrer?.specIgnoringRef, }; } } PK