Skip to content
This repository was archived by the owner on Jun 24, 2025. It is now read-only.

Commit 43d1b53

Browse files
authored
Merge pull request #1861 from TriliumNext/content-menu-target
Make it show which node triggered the event when right-clicking on tree
2 parents 307d94a + 6e1dfb8 commit 43d1b53

File tree

3 files changed

+27
-26
lines changed

3 files changed

+27
-26
lines changed

apps/client/src/menus/context_menu.ts

Lines changed: 12 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ interface ContextMenuOptions<T> {
1010
items: MenuItem<T>[];
1111
/** 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. */
1212
forcePositionOnMobile?: boolean;
13+
onHide?: () => void;
1314
}
1415

1516
interface MenuSeparatorItem {
@@ -36,15 +37,13 @@ export type ContextMenuEvent = PointerEvent | MouseEvent | JQuery.ContextMenuEve
3637
class ContextMenu {
3738
private $widget: JQuery<HTMLElement>;
3839
private $cover: JQuery<HTMLElement>;
39-
private dateContextMenuOpenedMs: number;
4040
private options?: ContextMenuOptions<any>;
4141
private isMobile: boolean;
4242

4343
constructor() {
4444
this.$widget = $("#context-menu-container");
4545
this.$cover = $("#context-menu-cover");
4646
this.$widget.addClass("dropend");
47-
this.dateContextMenuOpenedMs = 0;
4847
this.isMobile = utils.isMobile();
4948

5049
if (this.isMobile) {
@@ -76,8 +75,6 @@ class ContextMenu {
7675
keyboardActionService.updateDisplayedShortcuts(this.$widget);
7776

7877
this.positionMenu();
79-
80-
this.dateContextMenuOpenedMs = Date.now();
8178
}
8279

8380
positionMenu() {
@@ -186,8 +183,6 @@ class ContextMenu {
186183
return false;
187184
}
188185

189-
this.hide();
190-
191186
if ("handler" in item && item.handler) {
192187
item.handler(item, e);
193188
}
@@ -197,6 +192,12 @@ class ContextMenu {
197192
// it's important to stop the propagation especially for sub-menus, otherwise the event
198193
// might be handled again by top-level menu
199194
return false;
195+
})
196+
.on("mouseup", (e) =>{
197+
e.stopPropagation();
198+
// Hide the content menu on mouse up to prevent the mouse event from propagating to the elements below.
199+
this.hide();
200+
return false;
200201
});
201202

202203
if ("enabled" in item && item.enabled !== undefined && !item.enabled) {
@@ -220,27 +221,14 @@ class ContextMenu {
220221
}
221222

222223
async hide() {
223-
// this date checking comes from change in FF66 - https://github.com/zadam/trilium/issues/468
224-
// "contextmenu" event also triggers "click" event which depending on the timing can close the just opened context menu
225-
// we might filter out right clicks, but then it's better if even right clicks close the context menu
226-
if (Date.now() - this.dateContextMenuOpenedMs > 300) {
227-
// seems like if we hide the menu immediately, some clicks can get propagated to the underlying component
228-
// see https://github.com/zadam/trilium/pull/3805 for details
229-
await timeout(100);
230-
this.$widget.removeClass("show");
231-
this.$cover.removeClass("show");
232-
$("body").removeClass("context-menu-shown");
233-
this.$widget.hide();
234-
}
224+
this.options?.onHide?.();
225+
this.$widget.removeClass("show");
226+
this.$cover.removeClass("show");
227+
$("body").removeClass("context-menu-shown");
228+
this.$widget.hide();
235229
}
236230
}
237231

238-
function timeout(ms: number) {
239-
return new Promise((accept, reject) => {
240-
setTimeout(accept, ms);
241-
});
242-
}
243-
244232
const contextMenu = new ContextMenu();
245233

246234
export default contextMenu;

apps/client/src/menus/tree_context_menu.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ interface ConvertToAttachmentResponse {
1919
attachment?: FAttachment;
2020
}
2121

22+
let lastTargetNode: HTMLElement | null = null;
23+
2224
// This will include all commands that implement ContextMenuCommandData, but it will not work if it additional options are added via the `|` operator,
2325
// so they need to be added manually.
2426
export type TreeCommandNames = FilteredCommandNames<ContextMenuCommandData> | "openBulkActionsDialog";
@@ -33,12 +35,19 @@ export default class TreeContextMenu implements SelectMenuItemEventListener<Tree
3335
}
3436

3537
async show(e: PointerEvent | JQuery.TouchStartEvent | JQuery.ContextMenuEvent) {
36-
contextMenu.show({
38+
await contextMenu.show({
3739
x: e.pageX ?? 0,
3840
y: e.pageY ?? 0,
3941
items: await this.getMenuItems(),
40-
selectMenuItemHandler: (item, e) => this.selectMenuItemHandler(item)
42+
selectMenuItemHandler: (item, e) => this.selectMenuItemHandler(item),
43+
onHide: () => {
44+
lastTargetNode?.classList.remove('fancytree-menu-target');
45+
}
4146
});
47+
// It's placed after show to ensure the old target is cleared before showing the context menu again on repeated right-clicks.
48+
lastTargetNode?.classList.remove('fancytree-menu-target');
49+
lastTargetNode = this.node.span;
50+
lastTargetNode.classList.add('fancytree-menu-target');
4251
}
4352

4453
async getMenuItems(): Promise<MenuItem<TreeCommandNames>[]> {

apps/client/src/stylesheets/tree.css

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,10 @@ span.fancytree-node:hover {
208208
border: 1px solid var(--main-border-color);
209209
}
210210

211+
span.fancytree-node.fancytree-menu-target {
212+
box-shadow: inset 0 0 0 1px var(--main-border-color);
213+
}
214+
211215
.fancytree-title:hover,
212216
span.fancytree-node:hover .fancytree-title {
213217
border: 0;

0 commit comments

Comments
 (0)