Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ Add more context menus #11

Merged
merged 6 commits into from
Nov 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions scripts/unit-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ new App()
.get('/config', (_, res) => void res.send({ shouldWatch }))
.post('/results', (req, res) => {
req.on('data', (chunk: Buffer) => {
// eslint-disable-next-line no-console
console.log(chunk.toString())
})
req.on('close', () => {
Expand Down
13 changes: 13 additions & 0 deletions src/actors/ContextMenu.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,26 @@
// NOTE: This file should only have types imported from it. Its contents will not be
// available at runtime

export interface MediaInfo {
contentType?: string
contentDisposition?: string
}

export interface ContextMenuInfo {
position: {
screenX: number
screenY: number
inputSource: number
}

context: {
principal?: nsIPrincipalType
referrerInfo?: string
}

mediaInfo?: MediaInfo

textSelection?: string
href?: string
imageSrc?: string
}
87 changes: 84 additions & 3 deletions src/actors/ContextMenuChild.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@
/// <reference path="../link.d.ts" />
import { lazyESModuleGetters } from 'resource://app/modules/TypedImportUtils.sys.mjs'

import type { ContextMenuInfo } from './ContextMenu.types'
import type { ContextMenuInfo, MediaInfo } from './ContextMenu.types'

const lazy = lazyESModuleGetters({
SelectionUtils: 'resource://gre/modules/SelectionUtils.sys.mjs',
E10SUtils: 'resource://gre/modules/E10SUtils.sys.mjs',
})

export class ContextMenuChild extends JSWindowActorChild {
Expand All @@ -21,15 +22,83 @@ export class ContextMenuChild extends JSWindowActorChild {
}
}

handleEvent(event: MouseEvent & { inputSource: number }) {
getImageSrcIfExists(target: Node): string | undefined {
if ((target as HTMLImageElement).src) {
return (target as HTMLImageElement).src
}
}

/**
* This code was based on the code from here: https://searchfox.org/mozilla-central/source/browser/actors/ContextMenuChild.sys.mjs#568
*/
getMediaInfo(target: Node & nsIImageLoadingContentType) {
// @ts-expect-error - Ci interfaces are not instanceofable
if (!(target instanceof Ci.nsIImageLoadingContent && target.currentURI)) {
return
}

const mediaInfo: MediaInfo = {}

try {
const imageCache = Cc['@mozilla.org/image/tools;1']
// @ts-expect-error - Cc is not correctly typed yet
.getService(Ci.imgITools)
.getImgCacheForDocument(target.ownerDocument)
// The image cache's notion of where this image is located is
// the currentURI of the image loading content.
const props = imageCache.findEntryProperties(
target.currentURI,
target.ownerDocument,
)

try {
mediaInfo.contentType = props.get('type', Ci.nsISupportsCString).data
} catch (e) {
// Ignore errors
}

try {
mediaInfo.contentDisposition = props.get(
'content-disposition',
Ci.nsISupportsCString,
).data
} catch (e) {
// Ignore errors
}
} catch (e) {
// Ignore errors
}

return mediaInfo
}

getReferrerInfo(target: Element) {
const referrerInfo = Cc['@mozilla.org/referrer-info;1'].createInstance(
Ci.nsIReferrerInfo,
) as nsIReferrerInfoType
referrerInfo.initWithElement(target)
return lazy.E10SUtils.serializeReferrerInfo(referrerInfo)
}

handleEvent(
event: MouseEvent & { inputSource: number; composedTarget?: EventTarget },
) {
const data: {
position: ContextMenuInfo['position']
context: ContextMenuInfo['context']
} & Partial<ContextMenuInfo> = {
position: {
screenX: event.screenX,
screenY: event.screenY,
inputSource: event.inputSource,
},

context: {
principal:
(event.target &&
(event.target as Node).ownerDocument?.nodePrincipal) ||
undefined,
},
}

const selectionInfo = lazy.SelectionUtils.getSelectionDetails(
Expand All @@ -39,7 +108,19 @@ export class ContextMenuChild extends JSWindowActorChild {
data.textSelection = selectionInfo.fullText
}

if (event.target) data.href = this.getHrefIfExists(event.target as Node)
if (
event.composedTarget &&
(event.composedTarget as Node).nodeType === Node.ELEMENT_NODE
) {
const node = event.composedTarget as Node

data.href = this.getHrefIfExists(node)
data.imageSrc = this.getImageSrcIfExists(node)
data.mediaInfo = this.getMediaInfo(
node as Node & nsIImageLoadingContentType,
)
data.context.referrerInfo = this.getReferrerInfo(node as Element)
}

this.sendAsyncMessage('contextmenu', data satisfies ContextMenuInfo)
}
Expand Down
2 changes: 1 addition & 1 deletion src/actors/ContextMenuParent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export class ContextMenuParent extends JSWindowActorParent {
receiveMessage(event: ContextMenuEvent) {
if (event.name == 'contextmenu') {
const win = event.target.browsingContext.embedderElement.ownerGlobal
win.windowApi.showContextMenu(event.data)
win.windowApi.showContextMenu(event.data, this)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,18 @@
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->

<script lang="ts">
import { getMenuItemsDynamicPref, type MenuItem } from '@shared/contextMenus'
import type { MenuItem } from '@shared/contextMenus'
import { browserContextMenuInfo } from '../../lib/globalApi'
import type { ContextMenuInfo } from '../../../../actors/ContextMenu.types'
import { resolverStore } from '@shared/svelteUtils'

const menuItems = getMenuItemsDynamicPref('browser.contextmenus.page')
const contextMenusModule = import('@shared/contextMenus')
const menuItems = resolverStore(
[],
contextMenusModule.then(({ getMenuItemsDynamicPref }) =>
getMenuItemsDynamicPref('browser.contextmenus.page'),
),
)

function shouldHideSeparator(
index: number,
Expand Down
6 changes: 3 additions & 3 deletions src/content/browser/components/tabs/tab.ts
Original file line number Diff line number Diff line change
Expand Up @@ -305,21 +305,21 @@ class TabProgressListener
aStatus: number,
aMessage: string,
): void {
console.log('onStatusChange')
// console.log('onStatusChange')
}
onSecurityChange(
aWebProgress: nsIWebProgressType,
aRequest: nsIRequestType,
aState: number,
): void {
console.log('onSecurityChange')
// console.log('onSecurityChange')
}
onContentBlockingEvent(
aWebProgress: nsIWebProgressType,
aRequest: nsIRequestType,
aEvent: number,
): void {
console.log('onContentBlockingEvent')
// console.log('onContentBlockingEvent')
}

QueryInterface = ChromeUtils.generateQI([
Expand Down
12 changes: 11 additions & 1 deletion src/content/browser/components/toolbar/omnibox/Bookmarks.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
remove,
} from '../../../../shared/ExtBookmarkAPI'
import ToolbarButton from '../ToolbarButton.svelte'
import { onMount } from 'svelte'

export let tab: Tab

Expand Down Expand Up @@ -59,11 +60,20 @@

panel.hidePopup()
}

const OPEN_BOOKMARK_PANEL = () =>
panel.openPopup(bookmarkButton, 'bottomright topright')
onMount(() => {
window.windowApi.windowTriggers.on(
'bookmarkCurrentPage',
OPEN_BOOKMARK_PANEL,
)
})
</script>

<ToolbarButton
bind:button={bookmarkButton}
on:click={() => panel.openPopup(bookmarkButton, 'bottomright topright')}
on:click={OPEN_BOOKMARK_PANEL}
kind="page-icon"
>
<i class={$bookmarkInfo ? 'ri-bookmark-fill' : 'ri-bookmark-line'} />
Expand Down
13 changes: 11 additions & 2 deletions src/content/browser/lib/globalApi.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
/* 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 mitt from 'mitt'
import { writable } from 'svelte/store'

import type { ContextMenuInfo } from '../../../actors/ContextMenu.types'
import { viewableWritable } from '../../shared/svelteUtils'
import { Tab } from '../components/tabs/tab'
import { resource } from './resources'

export let contextMenuParentActor: JSWindowActorParent
export const browserContextMenuInfo = writable<ContextMenuInfo>({
position: { screenX: 0, screenY: 0, inputSource: 0 },
context: {},
})

let internalSelectedTab = -1
Expand Down Expand Up @@ -115,18 +118,24 @@ function insertAndShift<T>(arr: T[], from: number, to: number) {
arr.splice(to, 0, cutOut)
}

export type WindowTriggers = {
bookmarkCurrentPage: undefined
}

export const windowApi = {
windowTriggers: mitt<WindowTriggers>(),
closeTab,
openTab,
setIcon: (browser: XULBrowserElement, iconURL: string) =>
tabs
.readOnce()
.find((tab) => tab.getTabId() == browser.browserId)
?.icon.set(iconURL),
showContextMenu: (menuInfo: ContextMenuInfo) => {
showContextMenu: (menuInfo: ContextMenuInfo, actor: JSWindowActorParent) => {
browserContextMenuInfo.set(menuInfo)
contextMenuParentActor = actor

queueMicrotask(() => {
requestAnimationFrame(() => {
const contextMenu = document.getElementById(
'browser_context_menu',
) as XULMenuPopup
Expand Down
2 changes: 1 addition & 1 deletion src/content/browser/lib/shortcuts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export function initializeShortcuts() {
runOnCurrentTab((tab) => tab.goForward())
break
default:
console.log(event)
console.warn('Unknown event', event)
}
})
}
2 changes: 0 additions & 2 deletions src/content/browser/lib/xul/browser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ const { useRemoteTabs, useRemoteSubframe } = window.docShell.QueryInterface(
Ci.nsILoadContext,
)

console.log(useRemoteTabs, useRemoteSubframe)

const DEFAULT_BROWSER_ATTRIBUTES = {
message: 'true',
messagemanagergroup: 'browsers',
Expand Down
48 changes: 48 additions & 0 deletions src/content/contentAreaUtils.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/* 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/. */

declare function urlSecurityCheck(
url: string | nsIURIType,
principal: nsIPrincipalType,
flags?: number,
): void

declare function saveURL(
url: string | nsIURIType,
originalUrl: string,
fileName: string,
filePickerTitleKey: string,
shouldBypassCache: boolean,
aSkipPrompt: boolean,
aReferrerInfo: nsIReferrerInfoType,
aCookieJarSettings: nsICookieJarSettingsType,
aSourceDocument,
aIsContentWindowPrivate: boolean,
aPrincipal: nsIPrincipalType,
)

declare function saveBrowser(
aBrowser: XULBrowserElement,
aSkipPrompt: boolean,
aBrowsingContext = null,
)

declare function internalSave(
aURL: string,
aOriginalURL: string | null,
aDocument,
aDefaultFileName: string | null,
aContentDisposition: string | null,
aContentType: string | null,
aShouldBypassCache: boolean | null,
aFilePickerTitleKey: string | null,
aChosenData,
aReferrerInfo: nsIReferrerInfoType | null,
aCookieJarSettings: nsICookieJarSettingsType | null,
aInitiatingDocument?,
aSkipPrompt?: boolean | null,
aCacheKey?: string | null,
aIsContentWindowPrivate?: boolean | null,
aPrincipal?: nsIPrincipalType | null,
)
21 changes: 21 additions & 0 deletions src/content/globalOverlay.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/* 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/. */

declare function closeWindow(aClose, aPromptFunction, aSource)

/**
* @depends @mozilla.org/browser/browserglue;1
*/
declare function canQuitApplication(aData, aSource)

/**
* @depends @mozilla.org/browser/browserglue;1
*/
declare function goQuitApplication(event)

declare function goUpdateCommand(aCommand: string)

declare function goDoCommand(aCommand: string)

declare function goSetCommandEnabled(aID, aEnabled)
Loading
Loading