import keyboardActionService from './keyboard_actions.js'; const $contextMenuContainer = $("#context-menu-container"); let dateContextMenuOpenedMs = 0; /** * @param event - originating click event (used to get coordinates to display menu at position) * @param {object} contextMenu - needs to have getContextMenuItems() and selectContextMenuItem(e, cmd) */ async function initContextMenu(event, contextMenu) { event.stopPropagation(); $contextMenuContainer.empty(); function addItems($parent, items) { for (const item of items) { if (item.title === '----') { $parent.append($("
").addClass("dropdown-divider")); } else { const $icon = $(""); if (item.uiIcon) { $icon.addClass("bx bx-" + item.uiIcon); } else { $icon.append(" "); } const $link = $("") .append($icon) .append("   ") // some space between icon and text .append(item.title); const $item = $("
  • ") .addClass("dropdown-item") .append($link) .attr("data-cmd", item.cmd) .on('click', function (e) { const cmd = $(e.target).closest(".dropdown-item").attr("data-cmd"); e.originalTarget = event.target; contextMenu.selectContextMenuItem(e, cmd); hideContextMenu(); // 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"); } if (item.items) { $item.addClass("dropdown-submenu"); $link.addClass("dropdown-toggle"); const $subMenu = $("
      ").addClass("dropdown-menu"); addItems($subMenu, item.items); $item.append($subMenu); } $parent.append($item); } } } addItems($contextMenuContainer, await contextMenu.getContextMenuItems()); keyboardActionService.updateDisplayedShortcuts($contextMenuContainer); // 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 clickPosition = event.pageY; const clientHeight = document.documentElement.clientHeight; const contextMenuHeight = $contextMenuContainer.outerHeight() + 30; let top; if (clickPosition + contextMenuHeight > clientHeight) { top = clientHeight - contextMenuHeight - 10; } else { top = event.pageY - 10; } dateContextMenuOpenedMs = Date.now(); $contextMenuContainer.css({ display: "block", top: top, left: event.pageX - 20 }).addClass("show"); } $(document).on('click', () => hideContextMenu()); function hideContextMenu() { // 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() - dateContextMenuOpenedMs > 300) { $contextMenuContainer.hide(); } } export default { initContextMenu, hideContextMenu }