Skip to content

Commit

Permalink
✨ Add more context menus (#11)
Browse files Browse the repository at this point in the history
  • Loading branch information
trickypr authored Nov 18, 2023
1 parent 332413a commit 17133a8
Show file tree
Hide file tree
Showing 26 changed files with 464 additions and 84 deletions.
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

0 comments on commit 17133a8

Please sign in to comment.