Creating Custom Context Menus for MSHTML

The DEC already has methods available for creating a custom context menu but MSHTML doesn't. This code adds this nice functionality to MSHTML and does it in a way that is quite similar to the DEC samples that come from Microsoft.

The approach to this process was to create an interface that was as close to the standard context menu that appears in the browser as well as the one that appears in the DEC samples from Microsoft.

The demo that I have provided consists of two html documents. The first is contextmenus.html which defines all my methods, properties and initialization code. The second is editor.html which is my default document which loads into the iframe that resides on contextmenus.html.

When you try out the demo, type some text into the editor and then right click anywhere in the editor to display the context menu. You'll notice that what you see are three commands: cut, copy and paste.

The process can be broken down into specific steps:

Attaching the oncontextmenu Event

The oncontextmenu event gets attached to the body of the document which is our editor. That way, when the user right clicks to bring up the context menu, it runs our function instead of the default menu.

Building the Context Menu

To build the context menu, I used the createPopup() method in Internet Explorer because it behaves more like a context menu then a div or dialog box. I define the style of the popup to closely match that of the context menu. Then I add items from an array into the popup. Once they've been added to the popup I'll dispay the popup.

function showContextMenu(event){
    [...]
    var menuStrings = new Array();
    var menuStates = new Array();

    var idx=0;
    ContextMenu.length = 0;
    contextCount = 0;
    for (i=0; i<GeneralContextMenu.length; i++) {
    ContextMenu[idx++] = GeneralContextMenu[i];
    }

    for (i=0; i<ContextMenu.length; i++) {
    addContextItem(ContextMenu[i].string, false);
    }

    /* display the context menu */
    var iHeight = (contextCount * 17) + 5;
    oPopup.show(event.clientX+2, event.clientY+2, 150, iHeight, editor.document.body);
    return false;
}

Adding Items to the Context Menu

The addContextItem() method is used to create each element in the context menu. This is done by creating a new div within the popup that contains the text and then I set all the necessary styles and attach the appropriate events. the onmouseover and onmouseout are attached to a hilite and delite function used to create the menu item rollover feature. This is purely cosmetic. The important one is the onclick function.

    [...]
    el.innerHTML = text;
    el.style.margin = '0px 1px';
    el.style.padding = '2px 20px';
    el.attachEvent('onmouseover',contextHilite);
    el.attachEvent('onmouseout',contextDelite);
    el.attachEvent('onclick',contextOnclick);
    [...]

The onclick event gets attached to contextOnclick which will process whatever function has been selected.

Processing the Selected Item

Once an item is selected, the state is double-checked. If it's disabled then we don't want to do anything. Otherwise, we have a switch statement that processes the result. My example only has a default case but if you had a custom function that you wanted to run instead of the execCommand then you could create a case for that cmdId and process it seperately.


function contextOnclick(event){
if(event.srcElement.state){
    return false; // do nothing
} else {
    /* process the info:
       decide what you want to do based on the
       id passed from event.srcElement.item */
    oPopup.hide();
    switch (ContextMenu[event.srcElement.item].cmdId){
        default:
            editor.document.execCommand(ContextMenu[event.srcElement.item].cmdId);

    }

}
}

And that's all there is to it! Check out the example if you haven't already.

Published July 29, 2002 · Updated September 17, 2005
Categorized as MSHTML and DEC
Short URL: https://snook.ca/s/114

Conversation

2 Comments · RSS feed
max said on November 04, 2004

Is it possible to build multi-level context menu's using this method?

sample use for when right-clicking over a link...
Cut
Copy
Paste
Link >
   Edit Link...
   Remove Link

Jonathan Snook said on November 04, 2004

It would be but would take some work to add events to all items in the context menu to show and hide the submenus.

The way I've handled it is to check if I'm on a certain element and then add new elements to the context menu accordingly. So, if you clicked on a link you'd see something like:

Edit Link...
Remove Link
------------
Cut
Copy
Paste

But if you right-clicked within a table cell you'd see:

Cell Properties
Table Properties
---------------
Cut
Copy
Paste

I hope that helps!

Sorry, comments are closed for this post. If you have any further questions or comments, feel free to send them to me directly.

Want to learn about scaling CSS for large projects?

I'm available for full and half-day workshops on scalable CSS architecture. I can provide on-site training for your team. Interested?
Get in touch.