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

Make context element mandatory when showing a context menu. #14982

Merged
merged 2 commits into from
Feb 25, 2025
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
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
## 1.59.0

<a name="breaking_changes_1.59.0">[Breaking Changes:](#breaking_changes_1.59.0)</a>

- [core] A context html element is now mandatory when showing a context menu [#14982](https://github.com/eclipse-theia/theia/pull/14982) - contributed on behalf of STMicroelectronics
- [core] Adjusted the binding of named `ILogger` injections. These no longer have to be bound explicitly.
If you encounter errors such as `Error: Ambiguous match found for serviceIdentifier: Symbol(ILogger)`, remove your bindings for the `ILogger` symbol.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ export class SampleToolbarContribution extends AbstractToolbarContribution
includeAnchorArg: false,
menuPath: ToolbarMenus.SEARCH_WIDGET_DROPDOWN_MENU,
anchor: { x: left, y: bottom },
context: e.currentTarget
});
}
}
Expand Down
1 change: 1 addition & 0 deletions packages/ai-chat-ui/src/browser/chat-input-widget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ export class AIChatInputWidget extends ReactWidget {
this.contextMenuRenderer.render({
menuPath: AIChatInputWidget.CONTEXT_MENU,
anchor: { x: event.posx, y: event.posy },
context: event.target
});
event.preventDefault();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,8 @@ export class CodePartRenderer
this.contextMenuRenderer.render({
menuPath: ChatViewTreeWidget.CONTEXT_MENU,
anchor: { x: event.posx, y: event.posy },
args: [node, { code }]
args: [node, { code }],
context: event.target
});
event.preventDefault();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -435,7 +435,8 @@ export class ChatViewTreeWidget extends TreeWidget {
this.contextMenuRenderer.render({
menuPath: ChatViewTreeWidget.CONTEXT_MENU,
anchor: { x: event.clientX, y: event.clientY },
args: [node]
args: [node],
context: event.currentTarget
});
event.preventDefault();
}
Expand Down
6 changes: 3 additions & 3 deletions packages/core/src/browser/context-menu-renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,10 +110,10 @@ export interface RenderContextMenuOptions {
*/
includeAnchorArg?: boolean;
/**
* A DOM context to use when evaluating any `when` clauses
* of menu items registered for this item.
* A DOM context for the menu to be shown
* Will be used to attach the menu to a window and to evaluate enablement ("when"-clauses)
*/
context?: HTMLElement;
context: HTMLElement;
contextKeyService?: ContextMatcher;
onHide?: () => void;
/**
Expand Down
3 changes: 2 additions & 1 deletion packages/core/src/browser/shell/side-panel-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,8 @@ export class SidePanelHandler {
this.contextMenuRenderer.render({
args: [title.owner],
menuPath: SIDE_PANEL_TOOLBAR_CONTEXT_MENU,
anchor: e
anchor: e,
context: e.currentTarget instanceof HTMLElement ? e.currentTarget : this.tabBar.node
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ export class SidebarBottomMenuWidget extends SidebarMenuWidget {
anchor: {
x: button.left + button.width,
y: button.top + button.height,
}
},
context: e.currentTarget
});
}

Expand Down
1 change: 1 addition & 0 deletions packages/core/src/browser/shell/sidebar-menu-widget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ export class SidebarMenuWidget extends ReactWidget {
x: button.left + button.width,
y: button.top,
},
context: e.currentTarget,
onHide: () => {
this.preservingContext = false;
if (this.preservedContext) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ export class TabBarToolbar extends ReactWidget {
menuPath: TAB_BAR_TOOLBAR_CONTEXT_MENU,
args: [this.current],
anchor,
context: this.current?.node,
context: this.current?.node || this.node,
onHide: () => toDisposeOnHide.dispose(),
skipSingleRootNode: true,
});
Expand Down Expand Up @@ -375,7 +375,7 @@ export class TabBarToolbar extends ReactWidget {
menuPath,
args: [this.current],
anchor,
context: this.current?.node,
context: this.current?.node || this.node,
contextKeyService: contextMatcher,
onHide: () => toDisposeOnHide.dispose()
});
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/browser/shell/tab-bars.ts
Original file line number Diff line number Diff line change
Expand Up @@ -653,6 +653,7 @@ export class TabBarRenderer extends TabBar.Renderer {
menuPath: this.contextMenuPath!,
anchor: event,
args: [event],
context: event.currentTarget,
contextKeyService: contextKeyServiceOverlay,
// We'd like to wait until the command triggered by the context menu has been run, but this should let it get through the preamble, at least.
onHide: () => setTimeout(() => { if (this.selectionService) { this.selectionService.selection = oldSelection; } })
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/browser/tree/tree-widget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1362,6 +1362,7 @@ export class TreeWidget extends ReactWidget implements StatefulWidget {
const args = this.toContextMenuArgs(node);
setTimeout(() => this.contextMenuRenderer.render({
menuPath: contextMenuPath,
context: event.currentTarget,
anchor: { x, y },
args
}), 10);
Expand Down
8 changes: 6 additions & 2 deletions packages/core/src/browser/view-container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,11 @@ export class ViewContainer extends BaseWidget implements StatefulWidget, Applica
if (event.button === 2 && every(this.containerLayout.iter(), part => !!part.isHidden)) {
event.stopPropagation();
event.preventDefault();
contextMenuRenderer.render({ menuPath: this.contextMenuPath, anchor: event });
contextMenuRenderer.render({
menuPath: this.contextMenuPath,
anchor: event,
context: event.currentTarget instanceof HTMLElement ? event.currentTarget : this.node
});
}
}),
commandRegistry.registerCommand({ id: this.globalHideCommandId }, {
Expand Down Expand Up @@ -436,7 +440,7 @@ export class ViewContainer extends BaseWidget implements StatefulWidget, Applica
if (event.button === 2) {
event.preventDefault();
event.stopPropagation();
this.contextMenuRenderer.render({ menuPath: this.contextMenuPath, anchor: event });
this.contextMenuRenderer.render({ menuPath: this.contextMenuPath, anchor: event, context: this.node });
}
}),
newPart.onTitleChanged(() => this.refreshMenu(newPart)),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ export class ElectronTextInputContextMenuContribution implements FrontendApplica
this.contextMenuRenderer.render({
anchor: event,
menuPath: ElectronTextInputContextMenu.MENU_PATH,
context: event.target,
onHide: () => target.focus()
});
}
Expand Down Expand Up @@ -119,7 +120,8 @@ export class ElectronContextMenuRenderer extends BrowserContextMenuRenderer {
const node = (menuAccess as BrowserContextMenuAccess).menu.node;
const topPanelHeight = document.getElementById('theia-top-panel')?.clientHeight ?? 0;
// ensure the context menu is not displayed outside of the main area
if (node.style.top && parseInt(node.style.top.substring(0, node.style.top.length - 2)) < topPanelHeight) {
const menuRect = node.getBoundingClientRect();
if (menuRect.top < topPanelHeight) {
node.style.top = `${topPanelHeight}px`;
node.style.maxHeight = `calc(${node.style.maxHeight} - ${topPanelHeight}px)`;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ export class EditorLineNumberContribution implements FrontendApplicationContribu
this.contextMenuRenderer.render({
menuPath: EDITOR_LINENUMBER_CONTEXT_MENU,
anchor: event.event,
context: editor.node,
args,
contextKeyService
});
Expand Down
3 changes: 2 additions & 1 deletion packages/keymaps/src/browser/keybindings-widget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,8 @@ export class KeybindingWidget extends ReactWidget implements StatefulWidget {
this.contextMenuRenderer.render({
menuPath: KeybindingWidget.CONTEXT_MENU,
anchor: event.nativeEvent,
args: [item, this]
args: [item, this],
context: event.currentTarget
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -605,6 +605,7 @@ export class MemoryTableWidget extends ReactWidget {
menuPath: MemoryTableWidget.CONTEXT_MENU,
anchor: { x: right, y: top },
args: this.getContextMenuArgs(event),
context: target
});
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,7 @@ export class RegisterTableWidget extends MemoryTableWidget {
menuPath: RegisterTableWidget.CONTEXT_MENU,
anchor: event.nativeEvent,
args: this.getContextMenuArgs(event),
context: curTarget
});
}
}
Expand Down
4 changes: 2 additions & 2 deletions packages/monaco/src/browser/monaco-context-menu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,14 @@ export class MonacoContextMenuService implements IContextMenuService {
}
}

private getContext(delegate: IContextMenuDelegate): HTMLElement | undefined {
private getContext(delegate: IContextMenuDelegate): HTMLElement {
const anchor = delegate.getAnchor();
if (anchor instanceof HTMLElement) {
return anchor;
} else if (anchor instanceof StandardMouseEvent) {
return anchor.target;
} else {
return undefined;
return window.document.body; // last resort
}
}
showContextMenu(delegate: IContextMenuDelegate): void {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ export class NotebookCellToolbarFactory {
menuPath,
includeAnchorArg: false,
args: itemOptions.contextMenuArgs?.(),
context: this.notebookContextManager.context
context: this.notebookContextManager.context || (e.currentTarget as HTMLElement)
}) :
() => this.commandRegistry.executeCommand(menuNode.command!, ...(itemOptions.commandArgs?.() ?? [])),
isVisible: () => menuPath ? true : Boolean(this.commandRegistry.getVisibleHandler(menuNode.command!, ...(itemOptions.commandArgs?.() ?? []))),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -929,7 +929,8 @@ export class TreeViewWidget extends TreeViewWelcomeWidget {
menuPath: contextMenuPath,
anchor: { x, y },
args,
contextKeyService
contextKeyService,
context: event.currentTarget
}), 10);
}
}
Expand Down
3 changes: 2 additions & 1 deletion packages/plugin-ext/src/main/browser/webview/webview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,8 @@ export class WebviewWidget extends BaseWidget implements StatefulWidget, Extract
args: [event.context],
anchor: {
x: domRect.x + event.clientX, y: domRect.y + event.clientY
}
},
context: this.node
});
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,7 @@ export abstract class PreferenceLeafNodeRenderer<ValueType extends JSONValue, In
menuPath: PreferenceMenus.PREFERENCE_EDITOR_CONTEXT_MENU,
anchor: { x: domRect.left, y: domRect.bottom },
args: [{ id: this.id, value }],
context: target,
onHide: () => this.hideCog()
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,7 @@ export class PreferencesScopeTabBar extends TabBar<Widget> implements StatefulWi
this.contextMenuRenderer.render({
menuPath: PreferenceMenus.FOLDER_SCOPE_MENU_PATH,
anchor: { x: tabRect.left, y: tabRect.bottom },
context: folderTabNode,
onHide: () => {
setTimeout(() => toDisposeOnHide.dispose());
if (source === 'click') { folderTabNode.blur(); }
Expand Down
3 changes: 2 additions & 1 deletion packages/scm/src/browser/scm-tree-widget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -523,7 +523,8 @@ export abstract class ScmElement<P extends ScmElement.Props = ScmElement.Props>
contextMenuRenderer.render({
menuPath: this.contextMenuPath,
anchor: event.nativeEvent,
args: this.contextMenuArgs
args: this.contextMenuArgs,
context: event.currentTarget
});
});
};
Expand Down
2 changes: 1 addition & 1 deletion packages/terminal/src/browser/terminal-widget-impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ export class TerminalWidgetImpl extends TerminalWidget implements StatefulWidget
const contextMenuListener = (event: MouseEvent) => {
event.preventDefault();
event.stopPropagation();
this.contextMenuRenderer.render({ menuPath: TerminalMenus.TERMINAL_CONTEXT_MENU, anchor: event });
this.contextMenuRenderer.render({ menuPath: TerminalMenus.TERMINAL_CONTEXT_MENU, anchor: event, context: this.node });
};
this.node.addEventListener('contextmenu', contextMenuListener);
this.onDispose(() => this.node.removeEventListener('contextmenu', contextMenuListener));
Expand Down
3 changes: 2 additions & 1 deletion packages/timeline/src/browser/timeline-tree-widget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,8 @@ export class TimelineItemNode extends React.Component<TimelineItemNode.Props> {
contextMenuRenderer.render({
menuPath: TIMELINE_ITEM_CONTEXT_MENU,
anchor: event.nativeEvent,
args: [timelineItem]
args: [timelineItem],
context: event.currentTarget
});
} finally {
contextKeys.timelineItem.set(currentTimelineItem);
Expand Down
1 change: 1 addition & 0 deletions packages/toolbar/src/browser/toolbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ export class ToolbarImpl extends TabBarToolbar {
const { menuPath, anchor } = this.getMenuDetailsForClick(event);
return this.contextMenuRenderer.render({
args: contextMenuArgs,
context: event.currentTarget,
menuPath,
anchor,
});
Expand Down
3 changes: 2 additions & 1 deletion packages/vsx-registry/src/browser/vsx-extension.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,8 @@ export class VSXExtension implements VSXExtensionData, TreeElement {
x: e.clientX,
y: e.clientY,
},
args: [this]
args: [this],
context: e.currentTarget
});
}

Expand Down
Loading