Jonathan Snook.ca

 

Creating Custom Context Menus

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.