Skip to content

Commit

Permalink
Added support for webview/context menu contributions (#13166)
Browse files Browse the repository at this point in the history
* added support for webview/context menu contributions

Signed-off-by: Jonah Iden <[email protected]>

* removed unneccessary log

Signed-off-by: Jonah Iden <[email protected]>

---------

Signed-off-by: Jonah Iden <[email protected]>
  • Loading branch information
jonah-iden authored Dec 13, 2023
1 parent 469bd74 commit ad2e106
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ export class PluginMenuCommandAdapter implements MenuCommandAdapter {
['timeline/item/context', (...args) => this.toTimelineArgs(...args)],
['view/item/context', (...args) => this.toTreeArgs(...args)],
['view/title', noArgs],
['webview/context', noArgs]
]).forEach(([contributionPoint, adapter]) => {
if (adapter) {
const paths = codeToTheiaMappings.get(contributionPoint);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import { ScmTreeWidget } from '@theia/scm/lib/browser/scm-tree-widget';
import { TIMELINE_ITEM_CONTEXT_MENU } from '@theia/timeline/lib/browser/timeline-tree-widget';
import { COMMENT_CONTEXT, COMMENT_THREAD_CONTEXT, COMMENT_TITLE } from '../comments/comment-thread-widget';
import { VIEW_ITEM_CONTEXT_MENU } from '../view/tree-view-widget';
import { WebviewWidget } from '../webview/webview';
import { WEBVIEW_CONTEXT_MENU, WebviewWidget } from '../webview/webview';
import { EDITOR_LINENUMBER_CONTEXT_MENU } from '@theia/editor/lib/browser/editor-linenumber-contribution';
import { TEST_VIEW_CONTEXT_MENU } from '@theia/test/lib/browser/view/test-view-contribution';

Expand Down Expand Up @@ -58,7 +58,8 @@ export const implementedVSCodeContributionPoints = [
'timeline/item/context',
'testing/item/context',
'view/item/context',
'view/title'
'view/title',
'webview/context'
] as const;

export type ContributionPoint = (typeof implementedVSCodeContributionPoints)[number];
Expand All @@ -85,6 +86,7 @@ export const codeToTheiaMappings = new Map<ContributionPoint, MenuPath[]>([
['timeline/item/context', [TIMELINE_ITEM_CONTEXT_MENU]],
['view/item/context', [VIEW_ITEM_CONTEXT_MENU]],
['view/title', [PLUGIN_VIEW_TITLE_MENU]],
['webview/context', [WEBVIEW_CONTEXT_MENU]]
]);

type CodeEditorWidget = EditorWidget | WebviewWidget;
Expand Down
29 changes: 27 additions & 2 deletions packages/plugin-ext/src/main/browser/webview/pre/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -339,10 +339,35 @@ delete window.frameElement;
clientY: e.clientY,
ctrlKey: e.ctrlKey,
metaKey: e.metaKey,
shiftKey: e.shiftKey
shiftKey: e.shiftKey,
// @ts-ignore the dataset should exist if the target is an element
});
};

const handleContextMenu = (e) => {
if (e.defaultPrevented) {
return;
}

e.preventDefault();

host.postMessage('did-context-menu', {
clientX: e.clientX,
clientY: e.clientY,
context: findVscodeContext(e.target)
});
};

function findVscodeContext(node) {
if (node) {
if (node.dataset?.vscodeContext) {
return JSON.parse(node.dataset.vscodeContext);
}
return findVscodeContext(node.parentElement);
}
return {};
}

function preventDefaultBrowserHotkeys(e) {
var isOSX = navigator.platform.toUpperCase().indexOf('MAC') >= 0;

Expand Down Expand Up @@ -602,7 +627,7 @@ delete window.frameElement;
newFrame.contentWindow.addEventListener('keydown', handleInnerKeydown);
newFrame.contentWindow.addEventListener('mousedown', handleInnerMousedown);
newFrame.contentWindow.addEventListener('mouseup', handleInnerMouseup);
newFrame.contentWindow.addEventListener('contextmenu', e => e.preventDefault());
newFrame.contentWindow.addEventListener('contextmenu', handleContextMenu);

if (host.onIframeLoaded) {
host.onIframeLoaded(newFrame);
Expand Down
33 changes: 32 additions & 1 deletion packages/plugin-ext/src/main/browser/webview/webview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,16 @@ import { BinaryBufferReadableStream } from '@theia/core/lib/common/buffer';
import { ViewColumn } from '../../../plugin/types-impl';
import { ExtractableWidget } from '@theia/core/lib/browser/widgets/extractable-widget';
import { BadgeWidget } from '@theia/core/lib/browser/view-container';
import { MenuPath } from '@theia/core';
import { ContextMenuRenderer } from '@theia/core/lib/browser';
import { ContextKeyService } from '@theia/core/lib/browser/context-key-service';
import { PluginViewWidget } from '../view/plugin-view-widget';

// Style from core
const TRANSPARENT_OVERLAY_STYLE = 'theia-transparent-overlay';

export const WEBVIEW_CONTEXT_MENU: MenuPath = ['webview-context-menu'];

/* eslint-disable @typescript-eslint/no-explicit-any */

export const enum WebviewMessageChannels {
Expand All @@ -70,7 +76,8 @@ export const enum WebviewMessageChannels {
didKeydown = 'did-keydown',
didMouseDown = 'did-mousedown',
didMouseUp = 'did-mouseup',
onconsole = 'onconsole'
onconsole = 'onconsole',
didcontextmenu = 'did-context-menu'
}

export interface WebviewContentOptions {
Expand Down Expand Up @@ -152,6 +159,12 @@ export class WebviewWidget extends BaseWidget implements StatefulWidget, Extract
@inject(WebviewResourceCache)
protected readonly resourceCache: WebviewResourceCache;

@inject(ContextMenuRenderer)
protected readonly contextMenuRenderer: ContextMenuRenderer;

@inject(ContextKeyService)
protected readonly contextKeyService: ContextKeyService;

viewState: WebviewPanelViewState = {
visible: false,
active: false,
Expand Down Expand Up @@ -357,6 +370,10 @@ export class WebviewWidget extends BaseWidget implements StatefulWidget, Extract
this.dispatchMouseEvent('mouseup', data);
}));

this.toHide.push(this.on(WebviewMessageChannels.didcontextmenu, (event: { clientX: number, clientY: number, context: any }) => {
this.handleContextMenu(event);
}));

this.style();
this.toHide.push(this.themeDataProvider.onDidChangeThemeData(() => this.style()));

Expand All @@ -380,6 +397,20 @@ export class WebviewWidget extends BaseWidget implements StatefulWidget, Extract
}));
}

handleContextMenu(event: { clientX: number, clientY: number, context: any }): void {
const domRect = this.node.getBoundingClientRect();
this.contextKeyService.with(this.parent instanceof PluginViewWidget ?
{ webviewId: this.parent.options.viewId, ...event.context } : {},
() => {
this.contextMenuRenderer.render({
menuPath: WEBVIEW_CONTEXT_MENU,
anchor: {
x: domRect.x + event.clientX, y: domRect.y + event.clientY
}
});
});
}

protected async getRedirect(url: string): Promise<string | undefined> {
const uri = new URI(url);
const localhost = this.externalUriService.parseLocalhost(uri);
Expand Down

0 comments on commit ad2e106

Please sign in to comment.