From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- .../extensions/parent/ext-webNavigation.js | 276 +++++++++++++++++++++ 1 file changed, 276 insertions(+) create mode 100644 toolkit/components/extensions/parent/ext-webNavigation.js (limited to 'toolkit/components/extensions/parent/ext-webNavigation.js') diff --git a/toolkit/components/extensions/parent/ext-webNavigation.js b/toolkit/components/extensions/parent/ext-webNavigation.js new file mode 100644 index 0000000000..c65b61041b --- /dev/null +++ b/toolkit/components/extensions/parent/ext-webNavigation.js @@ -0,0 +1,276 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +// This file expects tabTracker to be defined in the global scope (e.g. +// by ext-browser.js or ext-android.js). +/* global tabTracker */ + +ChromeUtils.defineESModuleGetters(this, { + MatchURLFilters: "resource://gre/modules/MatchURLFilters.sys.mjs", + PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.sys.mjs", + WebNavigation: "resource://gre/modules/WebNavigation.sys.mjs", + WebNavigationFrames: "resource://gre/modules/WebNavigationFrames.sys.mjs", +}); + +var { ExtensionError } = ExtensionUtils; + +const defaultTransitionTypes = { + topFrame: "link", + subFrame: "auto_subframe", +}; + +const frameTransitions = { + anyFrame: { + qualifiers: ["server_redirect", "client_redirect", "forward_back"], + }, + topFrame: { + types: ["reload", "form_submit"], + }, +}; + +const tabTransitions = { + topFrame: { + qualifiers: ["from_address_bar"], + types: ["auto_bookmark", "typed", "keyword", "generated", "link"], + }, + subFrame: { + types: ["manual_subframe"], + }, +}; + +const isTopLevelFrame = ({ frameId, parentFrameId }) => { + return frameId == 0 && parentFrameId == -1; +}; + +const fillTransitionProperties = (eventName, src, dst) => { + if ( + eventName == "onCommitted" || + eventName == "onHistoryStateUpdated" || + eventName == "onReferenceFragmentUpdated" + ) { + let frameTransitionData = src.frameTransitionData || {}; + let tabTransitionData = src.tabTransitionData || {}; + + let transitionType, + transitionQualifiers = []; + + // Fill transition properties for any frame. + for (let qualifier of frameTransitions.anyFrame.qualifiers) { + if (frameTransitionData[qualifier]) { + transitionQualifiers.push(qualifier); + } + } + + if (isTopLevelFrame(dst)) { + for (let type of frameTransitions.topFrame.types) { + if (frameTransitionData[type]) { + transitionType = type; + } + } + + for (let qualifier of tabTransitions.topFrame.qualifiers) { + if (tabTransitionData[qualifier]) { + transitionQualifiers.push(qualifier); + } + } + + for (let type of tabTransitions.topFrame.types) { + if (tabTransitionData[type]) { + transitionType = type; + } + } + + // If transitionType is not defined, defaults it to "link". + if (!transitionType) { + transitionType = defaultTransitionTypes.topFrame; + } + } else { + // If it is sub-frame, transitionType defaults it to "auto_subframe", + // "manual_subframe" is set only in case of a recent user interaction. + transitionType = tabTransitionData.link + ? "manual_subframe" + : defaultTransitionTypes.subFrame; + } + + // Fill the transition properties in the webNavigation event object. + dst.transitionType = transitionType; + dst.transitionQualifiers = transitionQualifiers; + } +}; + +this.webNavigation = class extends ExtensionAPIPersistent { + makeEventHandler(event) { + let { extension } = this; + let { tabManager } = extension; + return ({ fire }, params) => { + // Don't create a MatchURLFilters instance if the listener does not include any filter. + let [urlFilters] = params; + let filters = urlFilters ? new MatchURLFilters(urlFilters.url) : null; + + let listener = data => { + if (!data.browser) { + return; + } + if ( + !extension.privateBrowsingAllowed && + PrivateBrowsingUtils.isBrowserPrivate(data.browser) + ) { + return; + } + if (filters && !filters.matches(data.url)) { + return; + } + + let data2 = { + url: data.url, + timeStamp: Date.now(), + }; + + if (event == "onErrorOccurred") { + data2.error = data.error; + } + + if (data.frameId != undefined) { + data2.frameId = data.frameId; + data2.parentFrameId = data.parentFrameId; + } + + if (data.sourceFrameId != undefined) { + data2.sourceFrameId = data.sourceFrameId; + } + + // Do not send a webNavigation event when the data.browser is related to a tab from a + // new window opened to adopt an existent tab (See Bug 1443221 for a rationale). + const chromeWin = data.browser.ownerGlobal; + + if ( + chromeWin && + chromeWin.gBrowser && + chromeWin.gBrowserInit && + chromeWin.gBrowserInit.isAdoptingTab() && + chromeWin.gBrowser.selectedBrowser === data.browser + ) { + return; + } + + // Fills in tabId typically. + Object.assign(data2, tabTracker.getBrowserData(data.browser)); + if (data2.tabId < 0) { + return; + } + let tab = tabTracker.getTab(data2.tabId); + if (!tabManager.canAccessTab(tab)) { + return; + } + + if (data.sourceTabBrowser) { + data2.sourceTabId = tabTracker.getBrowserData( + data.sourceTabBrowser + ).tabId; + } + + fillTransitionProperties(event, data, data2); + + fire.async(data2); + }; + + WebNavigation[event].addListener(listener); + return { + unregister() { + WebNavigation[event].removeListener(listener); + }, + convert(_fire) { + fire = _fire; + }, + }; + }; + } + + makeEventManagerAPI(event, context) { + let self = this; + return new EventManager({ + context, + module: "webNavigation", + event, + register(fire, ...params) { + let fn = self.makeEventHandler(event); + return fn({ fire }, params).unregister; + }, + }).api(); + } + + PERSISTENT_EVENTS = { + onBeforeNavigate: this.makeEventHandler("onBeforeNavigate"), + onCommitted: this.makeEventHandler("onCommitted"), + onDOMContentLoaded: this.makeEventHandler("onDOMContentLoaded"), + onCompleted: this.makeEventHandler("onCompleted"), + onErrorOccurred: this.makeEventHandler("onErrorOccurred"), + onReferenceFragmentUpdated: this.makeEventHandler( + "onReferenceFragmentUpdated" + ), + onHistoryStateUpdated: this.makeEventHandler("onHistoryStateUpdated"), + onCreatedNavigationTarget: this.makeEventHandler( + "onCreatedNavigationTarget" + ), + }; + + getAPI(context) { + let { extension } = context; + let { tabManager } = extension; + + return { + webNavigation: { + // onTabReplaced does nothing, it exists for compat. + onTabReplaced: new EventManager({ + context, + name: "webNavigation.onTabReplaced", + register: fire => { + return () => {}; + }, + }).api(), + onBeforeNavigate: this.makeEventManagerAPI("onBeforeNavigate", context), + onCommitted: this.makeEventManagerAPI("onCommitted", context), + onDOMContentLoaded: this.makeEventManagerAPI( + "onDOMContentLoaded", + context + ), + onCompleted: this.makeEventManagerAPI("onCompleted", context), + onErrorOccurred: this.makeEventManagerAPI("onErrorOccurred", context), + onReferenceFragmentUpdated: this.makeEventManagerAPI( + "onReferenceFragmentUpdated", + context + ), + onHistoryStateUpdated: this.makeEventManagerAPI( + "onHistoryStateUpdated", + context + ), + onCreatedNavigationTarget: this.makeEventManagerAPI( + "onCreatedNavigationTarget", + context + ), + getAllFrames({ tabId }) { + let tab = tabManager.get(tabId); + if (tab.discarded) { + return null; + } + let frames = WebNavigationFrames.getAllFrames(tab.browsingContext); + return frames.map(fd => ({ tabId, ...fd })); + }, + getFrame({ tabId, frameId }) { + let tab = tabManager.get(tabId); + if (tab.discarded) { + return null; + } + let fd = WebNavigationFrames.getFrame(tab.browsingContext, frameId); + if (!fd) { + throw new ExtensionError(`No frame found with frameId: ${frameId}`); + } + return { tabId, ...fd }; + }, + }, + }; + } +}; -- cgit v1.2.3