Make it show which node triggered the event when right-clicking on the tree.

This commit is contained in:
SiriusXT 2025-05-06 14:55:17 +08:00
parent f0c735e4fc
commit 647a5c948c
3 changed files with 24 additions and 18 deletions

View File

@ -10,6 +10,7 @@ interface ContextMenuOptions<T> {
items: MenuItem<T>[]; items: MenuItem<T>[];
/** On mobile, if set to `true` then the context menu is shown near the element. If `false` (default), then the context menu is shown at the bottom of the screen. */ /** On mobile, if set to `true` then the context menu is shown near the element. If `false` (default), then the context menu is shown at the bottom of the screen. */
forcePositionOnMobile?: boolean; forcePositionOnMobile?: boolean;
onHide?: () => void;
} }
interface MenuSeparatorItem { interface MenuSeparatorItem {
@ -36,7 +37,6 @@ export type ContextMenuEvent = PointerEvent | MouseEvent | JQuery.ContextMenuEve
class ContextMenu { class ContextMenu {
private $widget: JQuery<HTMLElement>; private $widget: JQuery<HTMLElement>;
private $cover: JQuery<HTMLElement>; private $cover: JQuery<HTMLElement>;
private dateContextMenuOpenedMs: number;
private options?: ContextMenuOptions<any>; private options?: ContextMenuOptions<any>;
private isMobile: boolean; private isMobile: boolean;
@ -44,7 +44,6 @@ class ContextMenu {
this.$widget = $("#context-menu-container"); this.$widget = $("#context-menu-container");
this.$cover = $("#context-menu-cover"); this.$cover = $("#context-menu-cover");
this.$widget.addClass("dropend"); this.$widget.addClass("dropend");
this.dateContextMenuOpenedMs = 0;
this.isMobile = utils.isMobile(); this.isMobile = utils.isMobile();
if (this.isMobile) { if (this.isMobile) {
@ -76,8 +75,6 @@ class ContextMenu {
keyboardActionService.updateDisplayedShortcuts(this.$widget); keyboardActionService.updateDisplayedShortcuts(this.$widget);
this.positionMenu(); this.positionMenu();
this.dateContextMenuOpenedMs = Date.now();
} }
positionMenu() { positionMenu() {
@ -220,10 +217,7 @@ class ContextMenu {
} }
async hide() { async hide() {
// this date checking comes from change in FF66 - https://github.com/zadam/trilium/issues/468 this.options?.onHide?.();
// "contextmenu" event also triggers "click" event which depending on the timing can close the just opened context menu
// we might filter out right clicks, but then it's better if even right clicks close the context menu
if (Date.now() - this.dateContextMenuOpenedMs > 300) {
// seems like if we hide the menu immediately, some clicks can get propagated to the underlying component // seems like if we hide the menu immediately, some clicks can get propagated to the underlying component
// see https://github.com/zadam/trilium/pull/3805 for details // see https://github.com/zadam/trilium/pull/3805 for details
await timeout(100); await timeout(100);
@ -232,7 +226,6 @@ class ContextMenu {
$("body").removeClass("context-menu-shown"); $("body").removeClass("context-menu-shown");
this.$widget.hide(); this.$widget.hide();
} }
}
} }
function timeout(ms: number) { function timeout(ms: number) {

View File

@ -19,6 +19,8 @@ interface ConvertToAttachmentResponse {
attachment?: FAttachment; attachment?: FAttachment;
} }
let lastTargetNode: HTMLElement | null = null;
// This will include all commands that implement ContextMenuCommandData, but it will not work if it additional options are added via the `|` operator, // This will include all commands that implement ContextMenuCommandData, but it will not work if it additional options are added via the `|` operator,
// so they need to be added manually. // so they need to be added manually.
export type TreeCommandNames = FilteredCommandNames<ContextMenuCommandData> | "openBulkActionsDialog"; export type TreeCommandNames = FilteredCommandNames<ContextMenuCommandData> | "openBulkActionsDialog";
@ -33,12 +35,19 @@ export default class TreeContextMenu implements SelectMenuItemEventListener<Tree
} }
async show(e: PointerEvent | JQuery.TouchStartEvent | JQuery.ContextMenuEvent) { async show(e: PointerEvent | JQuery.TouchStartEvent | JQuery.ContextMenuEvent) {
contextMenu.show({ await contextMenu.show({
x: e.pageX ?? 0, x: e.pageX ?? 0,
y: e.pageY ?? 0, y: e.pageY ?? 0,
items: await this.getMenuItems(), items: await this.getMenuItems(),
selectMenuItemHandler: (item, e) => this.selectMenuItemHandler(item) selectMenuItemHandler: (item, e) => this.selectMenuItemHandler(item),
onHide: () => {
lastTargetNode?.classList.remove('fancytree-menu-target');
}
}); });
// It's placed after show to ensure the old target is cleared before showing the context menu again on repeated right-clicks.
lastTargetNode?.classList.remove('fancytree-menu-target');
lastTargetNode = this.node.span;
lastTargetNode.classList.add('fancytree-menu-target');
} }
async getMenuItems(): Promise<MenuItem<TreeCommandNames>[]> { async getMenuItems(): Promise<MenuItem<TreeCommandNames>[]> {

View File

@ -208,6 +208,10 @@ span.fancytree-node:hover {
border: 1px solid var(--main-border-color); border: 1px solid var(--main-border-color);
} }
span.fancytree-node.fancytree-menu-target {
box-shadow: inset 0 0 0 1px var(--main-border-color);
}
.fancytree-title:hover, .fancytree-title:hover,
span.fancytree-node:hover .fancytree-title { span.fancytree-node:hover .fancytree-title {
border: 0; border: 0;