From 85c1a4b5b8ac1b270fa2b38bd44c282d46a4d608 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Mon, 20 Jun 2022 20:48:30 -0300 Subject: [PATCH 1/2] Fix ctx menu closing on the same click it opens Closure Library already handles the difficult work (keeping track of coordinates). This commit changes handleContextMenu so that it accesses the same code paths as normal mouse-ups (where the fix is located in Closure) and provides a supporting override which makes right-clicks "count" as the browser action button in this context. It also provides the mouse event which was responsible for creating the menu directly to the menu, which is required for the Closure Library fix to work. --- core/contextmenu.js | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/core/contextmenu.js b/core/contextmenu.js index 65401747e6..1aa0387bda 100644 --- a/core/contextmenu.js +++ b/core/contextmenu.js @@ -103,9 +103,20 @@ Blockly.ContextMenu.populate_ = function(options, rtl) { if (option.enabled) { goog.events.listen( menuItem, goog.ui.Component.EventType.ACTION, option.callback); - menuItem.handleContextMenu = function(/* e */) { + menuItem.handleContextMenu = function(e) { // Right-clicking on menu option should count as a click. - goog.events.dispatchEvent(this, goog.ui.Component.EventType.ACTION); + // Call handleMouseUp() so the intended code paths for handling a click + // are reached. + this.handleMouseUp(e); + }; + menuItem.handleMouseDown = function(e) { + // Menu options only respond to left clicking (browser action button). + // Override the event to let right clicking work too. + e.isMouseActionButton = function() { + return this.isButton(goog.events.BrowserEvent.MouseButton.LEFT) || + this.isButton(goog.events.BrowserEvent.MouseButton.RIGHT); + }; + goog.ui.MenuItem.base(this, 'handleMouseDown', e); }; } } @@ -139,6 +150,20 @@ Blockly.ContextMenu.position_ = function(menu, e, rtl) { Blockly.utils.uiMenu.adjustBBoxesForRTL(viewportBBox, anchorBBox, menuSize); } + // Closure Library menu code includes a fix for a bug where a menu option + // will respond to the event which was responsible for showing the menu in + // the first place. This fix compares the coordinates of the first mouseup + // event with those of the event which created it (made the menu visible). + // We can only take advantage of the fix if we specifically provide the + // mouse event to the menu, even if we don't otherwise have any reason to + // call setVisible (as the menu defaults to visible anyway). + // See issue #2085. + menu.setVisible( + true, // this menu is visible (this is the default anyway) + true, // "force" the value and don't emit SHOW & AFTER_SHOW events (avoid side effects) + e // provide mouse event so menu.openingCoords gets set (used for the Closure Library fix) + ); + Blockly.WidgetDiv.positionWithAnchor(viewportBBox, anchorBBox, menuSize, rtl); // Calling menuDom.focus() has to wait until after the menu has been placed // correctly. Otherwise it will cause a page scroll to get the misplaced menu From 38b468b9c926c718a3284d954bea8c32574d9c3c Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Tue, 16 Aug 2022 20:12:54 -0300 Subject: [PATCH 2/2] formally subclass goog.ui.MenuItem with desired custom behavior --- core/contextmenu.js | 53 ++++++++++++++++++++------------------------- 1 file changed, 23 insertions(+), 30 deletions(-) diff --git a/core/contextmenu.js b/core/contextmenu.js index 1aa0387bda..9565499087 100644 --- a/core/contextmenu.js +++ b/core/contextmenu.js @@ -30,6 +30,8 @@ */ goog.provide('Blockly.ContextMenu'); +goog.provide('Blockly.ContextMenuItem'); + goog.require('Blockly.Events.BlockCreate'); goog.require('Blockly.scratchBlocksUtils'); goog.require('Blockly.utils'); @@ -96,28 +98,16 @@ Blockly.ContextMenu.populate_ = function(options, rtl) { var menu = new goog.ui.Menu(); menu.setRightToLeft(rtl); for (var i = 0, option; option = options[i]; i++) { - var menuItem = new goog.ui.MenuItem(option.text); + // Use a custom class for the menu item instance. This is a subclass of + // goog.ui.MenuItem and has all the same behavior as usual, with minor + // tweaks for use in Blockly (and Scratch Blocks). + var menuItem = new Blockly.ContextMenuItem(option.text); menuItem.setRightToLeft(rtl); menu.addChild(menuItem, true); menuItem.setEnabled(option.enabled); if (option.enabled) { goog.events.listen( menuItem, goog.ui.Component.EventType.ACTION, option.callback); - menuItem.handleContextMenu = function(e) { - // Right-clicking on menu option should count as a click. - // Call handleMouseUp() so the intended code paths for handling a click - // are reached. - this.handleMouseUp(e); - }; - menuItem.handleMouseDown = function(e) { - // Menu options only respond to left clicking (browser action button). - // Override the event to let right clicking work too. - e.isMouseActionButton = function() { - return this.isButton(goog.events.BrowserEvent.MouseButton.LEFT) || - this.isButton(goog.events.BrowserEvent.MouseButton.RIGHT); - }; - goog.ui.MenuItem.base(this, 'handleMouseDown', e); - }; } } return menu; @@ -150,20 +140,6 @@ Blockly.ContextMenu.position_ = function(menu, e, rtl) { Blockly.utils.uiMenu.adjustBBoxesForRTL(viewportBBox, anchorBBox, menuSize); } - // Closure Library menu code includes a fix for a bug where a menu option - // will respond to the event which was responsible for showing the menu in - // the first place. This fix compares the coordinates of the first mouseup - // event with those of the event which created it (made the menu visible). - // We can only take advantage of the fix if we specifically provide the - // mouse event to the menu, even if we don't otherwise have any reason to - // call setVisible (as the menu defaults to visible anyway). - // See issue #2085. - menu.setVisible( - true, // this menu is visible (this is the default anyway) - true, // "force" the value and don't emit SHOW & AFTER_SHOW events (avoid side effects) - e // provide mouse event so menu.openingCoords gets set (used for the Closure Library fix) - ); - Blockly.WidgetDiv.positionWithAnchor(viewportBBox, anchorBBox, menuSize, rtl); // Calling menuDom.focus() has to wait until after the menu has been placed // correctly. Otherwise it will cause a page scroll to get the misplaced menu @@ -542,3 +518,20 @@ Blockly.ContextMenu.workspaceCommentOption = function(ws, e) { }; // End helper functions for creating context menu options. + + +Blockly.ContextMenuItem = function(content) { + Blockly.ContextMenuItem.superClass_.constructor.call(this, content); +}; +goog.inherits(Blockly.ContextMenuItem, goog.ui.MenuItem); + +Blockly.ContextMenuItem.prototype.handleMouseDown = function(e) { + // Menu options only respond to left clicking (browser action button). + // Override the event to let right clicking work too. + e.isMouseActionButton = function() { + return this.isButton(goog.events.BrowserEvent.MouseButton.LEFT) || + this.isButton(goog.events.BrowserEvent.MouseButton.RIGHT); + }; + + Blockly.ContextMenuItem.superClass_.handleMouseDown.call(this, e); +};