trilium/src/public/app/services/context_menu.js

124 lines
3.9 KiB
JavaScript
Raw Normal View History

import keyboardActionService from './keyboard_actions.js';
2020-02-29 18:28:30 +08:00
class ContextMenu {
constructor() {
this.$widget = $("#context-menu-container");
this.dateContextMenuOpenedMs = 0;
2020-02-29 18:28:30 +08:00
$(document).on('click', () => this.hide());
}
2020-07-15 05:29:37 +08:00
2020-02-29 18:28:30 +08:00
async show(options) {
this.options = options;
2020-07-15 05:29:37 +08:00
2020-02-29 18:28:30 +08:00
this.$widget.empty();
this.addItems(this.$widget, options.items);
keyboardActionService.updateDisplayedShortcuts(this.$widget);
this.positionMenu();
this.dateContextMenuOpenedMs = Date.now();
}
positionMenu() {
// code below tries to detect when dropdown would overflow from page
// in such case we'll position it above click coordinates so it will fit into client
const clientHeight = document.documentElement.clientHeight;
const contextMenuHeight = this.$widget.outerHeight() + 30;
2020-07-15 05:29:37 +08:00
let top, left;
2020-02-29 18:28:30 +08:00
if (this.options.y + contextMenuHeight > clientHeight) {
top = clientHeight - contextMenuHeight - 10;
} else {
top = this.options.y - 10;
}
2020-07-15 05:29:37 +08:00
if (this.options.orientation === 'left') {
left = this.options.x - this.$widget.outerWidth() + 20;
}
else {
left = this.options.x - 20;
}
2020-02-29 18:28:30 +08:00
this.$widget.css({
display: "block",
top: top,
2020-07-15 05:29:37 +08:00
left: left
2020-02-29 18:28:30 +08:00
}).addClass("show");
}
addItems($parent, items) {
2019-03-17 18:38:27 +08:00
for (const item of items) {
if (item.title === '----') {
$parent.append($("<div>").addClass("dropdown-divider"));
} else {
2019-03-17 18:38:27 +08:00
const $icon = $("<span>");
2019-03-17 18:38:27 +08:00
if (item.uiIcon) {
$icon.addClass("bx bx-" + item.uiIcon);
2019-03-17 18:38:27 +08:00
} else {
$icon.append("&nbsp;");
}
const $link = $("<span>")
2019-03-17 18:38:27 +08:00
.append($icon)
.append(" &nbsp; ") // some space between icon and text
.append(item.title);
const $item = $("<li>")
.addClass("dropdown-item")
.append($link)
2020-02-29 18:28:30 +08:00
// important to use mousedown instead of click since the former does not change focus
// (especially important for focused text for spell check)
.on('mousedown', (e) => {
e.stopPropagation();
2019-03-17 18:38:27 +08:00
2020-02-29 18:28:30 +08:00
this.hide();
2019-03-17 18:38:27 +08:00
2020-02-29 18:28:30 +08:00
if (item.handler) {
item.handler(item, e);
}
this.options.selectMenuItemHandler(item, e);
2019-05-04 03:50:14 +08:00
// it's important to stop the propagation especially for sub-menus, otherwise the event
// might be handled again by top-level menu
return false;
});
if (item.enabled !== undefined && !item.enabled) {
$item.addClass("disabled");
}
2018-11-10 05:18:51 +08:00
2019-03-17 18:38:27 +08:00
if (item.items) {
$item.addClass("dropdown-submenu");
$link.addClass("dropdown-toggle");
2019-03-17 18:38:27 +08:00
const $subMenu = $("<ul>").addClass("dropdown-menu");
2020-02-29 18:28:30 +08:00
this.addItems($subMenu, item.items);
2019-03-17 18:38:27 +08:00
$item.append($subMenu);
}
$parent.append($item);
}
}
}
2020-02-29 18:28:30 +08:00
hide() {
// this date checking comes from change in FF66 - https://github.com/zadam/trilium/issues/468
// "contextmenu" event also triggers "click" event which depending on the timing can close 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) {
this.$widget.hide();
}
}
}
2020-02-29 18:28:30 +08:00
const contextMenu = new ContextMenu();
2020-07-15 05:29:37 +08:00
export default contextMenu;