I’ve been working on a small context menu library in Javascript. Basically it lets you register a listener on a DOM element along with a flag specifying which types of clicks should render the context menu. Also, let’s save the discussion of whether creating your own custom right-click menu is a good idea or not for another time.
The menu worked fine in Chrome and Safari, but when I tried it out in Firefox there was an issue. When right-clicking, the menu would appear but when the mouse button was released, the menu disappeared again.
Technically, the library works like this. When a right-click menu is registered, an event listener is added to the specified DOM element for the contextmenu event. The listener shows the menu and adds a new event listener to the document which is responsible for closing the menu whenever the user clicks outside the menu’s boundaries.
The contextmenu event is a non-standard event, but it is implemented by all the major browsers. Firefox, Chrome and Safari all consider this to be a mouse event, though in the draft of HTML 5.1 the contextmenu event is not necessarily considered to be a mouse event.
As I said, Firefox would open the menu and quickly close it again, and given the above description I started looking into which events were fired. I wrote a small test page which registered listeners for mousedown, mouseup, click and contextmenu on a div and the document, in both the capture and bubble phase. This is the event order in Chrome:
- mousedown (capture) on document
- mousedown (capture) on DIV
- mousedown (bubble) on DIV
- mousedown (bubble) on document
- contextmenu (capture) on document
- contextmenu (capture) on DIV
- contextmenu (bubble) on DIV
- contextmenu (bubble) on document
- mouseup (capture) on document
- mouseup (capture) on DIV
- mouseup (bubble) on DIV
- mouseup (bubble) on document
Safari acts the same for the first two events, but never fires a mouseup event. And this is what happens in Firefox:
- mousedown (capture) on document
- mousedown (capture) on DIV
- mousedown (bubble) on DIV
- mousedown (bubble) on document
- contextmenu (capture) on document
- contextmenu (capture) on DIV
- contextmenu (bubble) on DIV
- contextmenu (bubble) on document
- mouseup (capture) on document
- mouseup (capture) on DIV
- mouseup (bubble) on DIV
- mouseup (bubble) on document
- click (capture) on document
- click (bubble) on document
As you can see, there is a slight difference between Chrome and Firefox. Logically, I think it is reasonable to do as Firefox does and fire a click event. But look a little closer on the click event. It only appears two times, both on the document. In other words, it never hits the div on which the click originated, though the target property correctly references the div.
After some googling, I managed to find a bug report on Bugzilla for this issue which was marked as invalid without any real reason other than “there is no specification”. I’ve added a comment on the issue with the hope of getting an explanation, but until then I wanted to share this in case other people run into the same problem.