Opened 10 years ago

Closed 8 years ago

#9826 closed enhancement (wontfix)

Allow menu to operate as a drop down

Reported by: craigm Owned by:
Priority: high Milestone: future
Component: Dijit Version: 1.3.2
Keywords: Menu DropDown drop down DropDownMenu Cc:
Blocked By: Blocking:

Description

At the moment a plain Menu widget's _openMyself() function has 2 methods of determining the x/y coordinates at where it should display itself. A right click will trigger the menu at the cursor, otherwise it appears at 10 pixel offset from the top left position of the target node. I'd like to propose an enhancement to the base Menu widget that allows it to operate as a drop down to its attached node, similar to the functionality of the DropDownButton?, but without the need for the button.

My use case for this particular enhancement is that I have some navigation images at the top of my page and mouse over event for these images triggers the menu which should appear as a drop down. This means that the menu needs to position itself at the bottom left corner of the image that fired the mouse over event. I have already modified the Menu.js file in my project to achieve this but would like to see it added to dojo.

Original code in Menu._openMySelf():

var x,y;
if(dojo.isSafari || this._contextMenuWithMouse){
  x=e.pageX;
  y=e.pageY;
}else{
  // otherwise open near e.target
  var coords = dojo.coords(e.target, true);
  x = coords.x + 10;
  y = coords.y + 10;
}

Modified version:

var x,y;
if (this.openUnderTarget) {
  var coords = dojo.coords(e.target, true);
  var targetHeight = e.target.offsetHeight;    
  x = coords.x;
  y = coords.y + targetHeight;
} else if(dojo.isSafari || this._contextMenuWithMouse){
  x=e.pageX;
  y=e.pageY;
}else{
  // otherwise open near e.target
  var coords = dojo.coords(e.target, true);
  x = coords.x + 10;
  y = coords.y + 10;
}

I'll try to attach a screenshot and patch.

Attachments (2)

example.JPG (10.2 KB) - added by craigm 10 years ago.
Menu opening at bottom left corner of image that was moused over
menu.patch (1.5 KB) - added by craigm 10 years ago.
Patch file, apply directly to Menu.js

Download all attachments as: .zip

Change History (8)

Changed 10 years ago by craigm

Attachment: example.JPG added

Menu opening at bottom left corner of image that was moused over

Changed 10 years ago by craigm

Attachment: menu.patch added

Patch file, apply directly to Menu.js

comment:1 Changed 10 years ago by bill

Dijit tries to keep widgets separate from popup/dropdown functionality. Note how _Calendar is just a plain-old widget but you can use it as a drop down by calling dijit.popup.open().

Menu was a bit of an exception because Menu's can be attached to existing nodes as context menus, but if you want to make thean image spawn a drop down why not just call dijit.popup.open() ?

comment:2 Changed 10 years ago by craigm

Bill,

That did occur to me but I didn't want to duplicate the code for the onExecute and onCancel handlers, in addition to the focus and blur stuff after dijit.popup.open is called.

Maybe a good compromise would be to break this function down into 2 separate functions. Add a new function that returns something like {x: TheXCoord, y: TheYCoord} and functions the same as the current if/else block in the trunk. This function could be called something like _getPopupLocation(). _openMySelf would call this function to find the location of the popup and I can override this function with my own version that attaches it to a DOM node.

_getPopupLocation: function(/*Event*/ e) {
  // summary:
  //    Internal function for determining the x/y coordinate
  //    at which the menu should appear
  // tags:
  //    private

  // Get coordinates.
  // if we are opening the menu with the mouse or on safari open
  // the menu at the mouse cursor
  // (Safari does not have a keyboard command to open the context menu
  // and we don't currently have a reliable way to determine
  // _contextMenuWithMouse on Safari)
  var x,y;        
  if(dojo.isSafari || this._contextMenuWithMouse){
    x=e.pageX;
    y=e.pageY;
  }else{
    // otherwise open near e.target
    var coords = dojo.coords(e.target, true);
    x = coords.x + 10;
    y = coords.y + 10;
  }
  return {x: x, y: y};
},

_openMyself: function(/*Event*/ e){
  // summary:
  //    Internal function for opening myself when the user
  //    does a right-click or something similar
  // tags:
  //    private
    if(this.leftClickToOpen&&e.button>0){
    return;
  }
  dojo.stopEvent(e);
  var popupLoc = this._getPopupLocation(e);

  var self=this;
  var savedFocus = dijit.getFocus(this);
  function closeAndRestoreFocus(){
    // user has clicked on a menu or popup
    dijit.focus(savedFocus);
    dijit.popup.close(self);
  }
  dijit.popup.open({
    popup: this,
    x: popupLoc.x,
    y: popupLoc.y,
    onExecute: closeAndRestoreFocus,
    onCancel: closeAndRestoreFocus,
    orient: this.isLeftToRight() ? 'L' : 'R'
  });
  this.focus();

  this._onBlur = function(){
    this.inherited('_onBlur', arguments);
    // Usually the parent closes the child widget but if this is a context
    // menu then there is no parent
    dijit.popup.close(this);
    // don't try to restore focus; user has clicked another part of the screen
    // and set focus there
  };
},

comment:3 Changed 10 years ago by bill

Milestone: 1.41.5

comment:4 Changed 9 years ago by Adam Peller

Milestone: 1.51.6

comment:5 Changed 8 years ago by bill

Milestone: 1.6future

comment:6 Changed 8 years ago by bill

Resolution: wontfix
Status: newclosed

Sorry, I don't want to add any (more) special code to menu. If dijit.popup.open() is too hard to use maybe the signature could be simplified.

Note: See TracTickets for help on using tickets.