Friday, November 6, 2009

Javascript/Firefox: context menu popup


The context menu of Firefox behaves differently between the Windows and Linux platforms. On Linux, the context menu pops up as soon as you press down the right button of the mouse; While on Windows, it shows when you press down and release the right button.

The Linux style behavior makes it difficult for an extension to capture and hack the mousedown event. We can do a little hack to emulate the Windows style behavior on the Linux platform.

The idea is that we capture the mousedown event and suppress the context menu. When the user release the mouse button, we capture the mouseup event and fire a fake contextmenu event.

Here is the demo source code.


1. Capture the mousedown event and suppress the context menu.

1.1 Capture the mousedown event
addEventListener("mousedown", myMouseDown, true);

function myMouseDown(event)
{
   if (2 == event.button)    // right-click
   {
      if (navigator.platform != "Win32")   // No need for Windows
      {
         // Capture the contextmenu event.
         addEventListener("contextmenu", myNoContextMenu, true);

         // remove the listener right after to avoid mess up the other
         // contextmenu events.
         setTimeout(function(){ removeEventListener("contextmenu", myNoContextMenu, true); }, 0);
      }
   }
}

1.2 Suppress the context menu
function myNoContextMenu(event)
{
   // Prevent the default action, i.e. context menu poping up
   event.preventDefault();
   event.stopPropagation();
}


2. Capture the mouseup event and pop up the context menu.

1.1 Capture the mouseup event
addEventListener("mouseup", myMouseUp, true);

function myMouseUp(event)
{
   if (2 == event.button)   // right-click
   {
      myShowContextMenu(event);
   }
}


1.2 Pop up the context menu
function myShowContextMenu(event)
{
   if (navigator.platform == "Win32")
      return;  // on Window context menu is already shown on mouseup.

   // create a contextmenu event.
   var newEv = event.view.document.createEvent("MouseEvents");
   newEv.initMouseEvent("contextmenu", true, true, event.view, 1,
             event.screenX, event.screenY, event.clientX, event.clientY,
             false, false, false, false, 2, null);

   // fire the new event.
   event.originalTarget.dispatchEvent(newEv);
}

2 comments:

Tom said...

I'm noticing that in IE7, when the context menu is showing, none of the mouseover/mouseout events fire when I move around the screen. But in Firefox, the context menu is showing yet the underlying elements respond to mouseover and mouseout. In my case, I don't want the underlying elements to react when I have a context menu showing. Ideas? Gracias fellas!

Pil said...

As far es I see this code should display the browsers default context menu.
I noticed that no context menu would be displayed in no browser on three platforms (Linux, Mac, and Windows), although the contextmenu event would be fired.

 
Get This <