From 1ac49197fb124eed85e36465883e5843fb7b07d5 Mon Sep 17 00:00:00 2001 From: Speedphoenix Date: Thu, 22 Jul 2021 11:39:26 +0200 Subject: [PATCH] Make the contextmenu let click events passthrough With useModal set to false, uses document.addeventlistener in capture mode rather than an invisible layer. Note that this probably breaks on older browsers, and some features or options might not work anymore. useModal is set to true by default, and should behave just like before. --- src/jquery.contextMenu.js | 48 +++++++++++++++++++++++++++++++-------- 1 file changed, 38 insertions(+), 10 deletions(-) diff --git a/src/jquery.contextMenu.js b/src/jquery.contextMenu.js index ace46e63..709386dc 100644 --- a/src/jquery.contextMenu.js +++ b/src/jquery.contextMenu.js @@ -121,6 +121,9 @@ // This overrides the reposition option. hideOnSecondTrigger: false, + // use a modal layer for closing the menu rather than a captured event on document + useModal: true, + //ability to select submenu selectableSubMenu: false, @@ -430,9 +433,9 @@ hoveract.timer = null; }, // click on layer to hide contextMenu - layerClick: function (e) { + layerClick: function (e, opt, onhide) { var $this = $(this), - root = $this.data('contextMenuRoot'), + root = (opt !== undefined) ? opt : $this.data('contextMenuRoot'), button = e.button, x = e.pageX, y = e.pageY, @@ -440,16 +443,28 @@ target, offset; + // If the click is not real, things break: https://github.com/swisnl/jQuery-contextMenu/issues/132 + if(fakeClick){ + if (root !== null && typeof root !== 'undefined' && root.$menu !== null && typeof root.$menu !== 'undefined') { + root.$menu.trigger('contextmenu:hide'); + } + return; + } + + // if the click closing is done through windwow event listener rather than a transparent layer + if (!root.$layer) { + target = document.elementFromPoint(x - $win.scrollLeft(), y - $win.scrollTop()); + if (root.$menu === null || typeof root.$menu === 'undefined' || !root.$menu[0].contains(target)) { + + root.$menu.trigger('contextmenu:hide'); + if (typeof onhide !== 'undefined') + onhide(); + } + return; + } e.preventDefault(); setTimeout(function () { - // If the click is not real, things break: https://github.com/swisnl/jQuery-contextMenu/issues/132 - if(fakeClick){ - if (root !== null && typeof root !== 'undefined' && root.$menu !== null && typeof root.$menu !== 'undefined') { - root.$menu.trigger('contextmenu:hide'); - } - return; - } var $window; var triggerAction = ((root.trigger === 'left' && button === 0) || (root.trigger === 'right' && button === 2)); @@ -967,7 +982,10 @@ css = {}; // hide any open menus - $('#context-menu-layer').trigger('mousedown'); + if ($('#context-menu-layer').length > 0) + $('#context-menu-layer').trigger('mousedown'); + else + $(document).trigger('contextmenu:hide'); // backreference for callbacks opt.$trigger = $trigger; @@ -1497,6 +1515,16 @@ return hasVisibleItems; }, layer: function (opt, zIndex) { + if (!opt.useModal) { + var listener = function (ev) { + handle.layerClick(ev, opt, () => { + document.removeEventListener('mousedown', listener, true); + }); + }; + document.addEventListener('mousedown', listener, true); + return; + } + // add transparent layer for click area // filter and background for Internet Explorer, Issue #23 var $layer = opt.$layer = $('
')