From c2e1dcc9ac1b53022c047c2df5e4cd6767ee9427 Mon Sep 17 00:00:00 2001 From: trickypr <23250792+trickypr@users.noreply.github.com> Date: Fri, 29 Dec 2023 14:29:10 +1100 Subject: [PATCH] =?UTF-8?q?=F0=9F=9A=B8=20Assorted=20new=20tab=20fixes=20(?= =?UTF-8?q?#43)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/actors/ClickHandlerChild.ts | 37 +++++++++++++++++++ src/actors/ClickHandlerParent.ts | 15 ++++++++ src/actors/link.json | 2 + src/content/browser/lib/window/tab.ts | 9 ++++- .../browser/lib/xul/NSBrowserAccess.ts | 33 +++++++++++++++-- src/modules/BrowserGlue.ts | 12 ++++++ 6 files changed, 102 insertions(+), 6 deletions(-) create mode 100644 src/actors/ClickHandlerChild.ts create mode 100644 src/actors/ClickHandlerParent.ts diff --git a/src/actors/ClickHandlerChild.ts b/src/actors/ClickHandlerChild.ts new file mode 100644 index 0000000..aa368fd --- /dev/null +++ b/src/actors/ClickHandlerChild.ts @@ -0,0 +1,37 @@ +/* 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/. */ + +/// + +export type ClickHandlerMessage = { + name: 'openlink' + data: { href: string } +} & { target: JSWindowActorParent } + +export class ClickHandlerChild extends JSWindowActorChild { + getHrefIfExists(target: Node): string | undefined { + if ((target as HTMLAnchorElement).href) { + return (target as HTMLAnchorElement).href + } + + if (target.parentElement) { + return this.getHrefIfExists(target.parentElement) + } + } + + handleEvent(event: MouseEvent) { + if (event.defaultPrevented || !event.target) return + + const href = this.getHrefIfExists(event.target as Node) + + const ctrlClick = event.button === 0 && event.ctrlKey + const middleClick = event.button === 1 + + const shouldOpenNewTab = href && (ctrlClick || middleClick) + + if (!shouldOpenNewTab) return + + this.sendAsyncMessage('openlink', { href }) + } +} diff --git a/src/actors/ClickHandlerParent.ts b/src/actors/ClickHandlerParent.ts new file mode 100644 index 0000000..fbc003c --- /dev/null +++ b/src/actors/ClickHandlerParent.ts @@ -0,0 +1,15 @@ +/* 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/. */ +/// +import { ClickHandlerMessage } from './ClickHandlerChild' + +export class ClickHandlerParent extends JSWindowActorParent { + receiveMessage(event: ClickHandlerMessage) { + if (event.name == 'openlink') { + const win = event.target.browsingContext.embedderElement.ownerGlobal + const uri = Services.io.newURI(event.data.href) + win.windowApi.tabs.openTab(uri) + } + } +} diff --git a/src/actors/link.json b/src/actors/link.json index 758dc8a..3435b4d 100644 --- a/src/actors/link.json +++ b/src/actors/link.json @@ -1,4 +1,6 @@ [ + "ClickHandlerChild", + "ClickHandlerParent", "ContextMenuChild", "ContextMenuParent", "LinkHandlerChild", diff --git a/src/content/browser/lib/window/tab.ts b/src/content/browser/lib/window/tab.ts index f50f6ae..625675b 100644 --- a/src/content/browser/lib/window/tab.ts +++ b/src/content/browser/lib/window/tab.ts @@ -51,11 +51,12 @@ export class Tab { public hidden = writable(false) constructor(uri: nsIURIType) { - this.uri = viewableWritable(uri) - this.goToUri(uri) this.browserElement = createBrowser({ remoteType: getBrowserRemoteType(uri), }) + + this.uri = viewableWritable(uri) + this.goToUri(uri) this.title.set(uri.asciiHost) this.uri.subscribe(async (uri) => @@ -79,6 +80,10 @@ export class Tab { return this.tabId || 0 } + public getBrowserElement() { + return this.browserElement + } + public getDragRepresentation() { return { windowId: window.windowApi.id, diff --git a/src/content/browser/lib/xul/NSBrowserAccess.ts b/src/content/browser/lib/xul/NSBrowserAccess.ts index 60113aa..201f9e1 100644 --- a/src/content/browser/lib/xul/NSBrowserAccess.ts +++ b/src/content/browser/lib/xul/NSBrowserAccess.ts @@ -4,6 +4,22 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ +export enum OpenWhere { + DefaultWindow = 0, + CurrentWindow = 1, + NewWindow = 2, + NewTab = 3, + PrintBrowser = 4, +} + +export enum OpenFlags { + New = 0x0, + /** Open was triggered by a thirdparty application */ + External = 0x1, + NoOpener = 0x4, + NoReferer = 0x8, +} + export class NSBrowserAccess { createContentWindow( aURI: nsIURIType, @@ -15,15 +31,24 @@ export class NSBrowserAccess { ) { throw new Error('Method not implemented.') } + createContentWindowInFrame( aURI: nsIURIType, params: nsIOpenURIInFrameParamsType, aWhere: number, - aFlags: number, - aName: string, - ): Element { - throw new Error('Method not implemented.') + ): Element | null { + if (aWhere !== OpenWhere.NewTab) { + console.warn('NSBrowserAccess: Only OpenWhere.NewTab is supported') + return null + } + + // TODO: Handle params + // TODO: Handle unhandled arguments (see nsIBrowserDOMWindow) + const tab = window.windowApi.tabs.openTab(aURI) + const browser = tab.getBrowserElement() + return browser } + openURI( aURI: nsIURIType, aOpenWindowInfo: nsIOpenWindowInfoType, diff --git a/src/modules/BrowserGlue.ts b/src/modules/BrowserGlue.ts index e2b3acf..de848ac 100644 --- a/src/modules/BrowserGlue.ts +++ b/src/modules/BrowserGlue.ts @@ -10,6 +10,18 @@ const lazy = lazyESModuleGetters({ const JS_PROCESS_ACTORS = {} const JS_WINDOW_ACTORS = { + ClickHandler: { + parent: { esModuleURI: 'resource://app/actors/ClickHandlerParent.sys.mjs' }, + child: { + esModuleURI: 'resource://app/actors/ClickHandlerChild.sys.mjs', + events: { + chromelinkclick: { capture: true, mozSystemGroup: true }, + }, + }, + + allFrames: true, + }, + ContextMenu: { parent: { esModuleURI: 'resource://app/actors/ContextMenuParent.sys.mjs',