YUI-ext grid and context menus

I recently had the opportunity to use YUI-Ext for a little application. I'll focus on the creation of the context menus for the grid. If you're discovering YUI-Ext's layout approach, more information is available from Jack Slockum's blog in Exploring Cross-browser Web 2.0 Layouts with Yahoo! UI and Cross-browser Web 2.0 Layouts (Part 2) and Ajax Feed Viewer 2.0. I'll illustrate what I learned with a little useless app (code is in javascript.js), which lets you rate fries for different countries. As belgian fries can only be good, the context menu will only propose to rate them as good. However, for other countries, you can rate fries as bad. (Yes, this example is that useless...). I'm working with a grid whose data comes from an XML file. This XML file contains a list of countries in this format:

1
Belgium
http://www.belgium.be

Which result in this datamodel definition:
dataModel = new YAHOO.ext.grid.XMLDataModel({
                            tagName: 'item',
                            id: 'id',
                            fields: ['country', 'url']
                            });
and this column model:
var colModel = new YAHOO.ext.grid.DefaultColumnModel([
      {header: "Country", width: 100, sortable: true},
      {header: "URL", width: 250, sortable: true, renderer: formatURL},
]);
The URL column has a renderer set: this is a function which allows you to format the data in the column. Here's the URL renderer:
function formatURL(val) { return ''+val+'';}
A renderer can also be used to display fixed content. Eg, if you want to display the text "Delete" in a column, you can simply use this renderer:
function deleteText(val) { return 'Delete';}
For this example I store the list's items in the file items.xml, so here's how I load the data:
dataModel.load('items.xml');
Now we can create the grid:
var grid = new YAHOO.ext.grid.Grid('my-grid', dataModel, colModel);
I created a function onContextMenu which is set as listener to the "rowcontextmenu" event:
grid.addListener('rowcontextmenu', onContextMenu);
This method prevents the default behaviour:
e.preventDefault();
If you don't, you get the browser's default context menu. Even with this call, Firefox 1.5 displays its own context menu. As the context menu to display depends on the content of the first column, it then extracts this value. The best way I found to do this is:
grid.getSelectedRows()[0].childNodes[0].childNodes[0].innerHTML;
(In my app, I could not base the decision on the row's id, which could be the better choice if possible) According to the value extracted, the context menu to display is retrieved, its position is set, and it is shown:
this.context_menu = this.belgium_menu;
YAHOO.util.Dom.setXY(YAHOO.util.Dom.get('belgiummenu'), e.getXY());
this.context_menu.show();
Both context menus are built similarly, at the start of the onContextMenu function, and stored in a member variable so that the next time is it called, it can reuse the menu built eaarlier. Here's how the menu is defined for rows with 'Belgium' in the first column:
if (!this.belgium_menu)
{
        var aMenuItems = [
                { text: "Rate Belgian Fries as Excellent" },
                { text: "Rate Belgian Fries as Excellent" },
        ];
        this.belgium_menu =new YAHOO.widget.ContextMenu('belgiummenu',
                {
                        itemdata: aMenuItems            
                }
        );
        this.belgium_menu.clickEvent.subscribe(onBelgiumSelect, this.belgium_menu, true);
        this.belgium_menu.render(document.body);
}

The menu is constructed by settings the items it should display, and then we subscribe a method to its click event. In this listener taking 3 arguments, you can simply have a switch statement to act differently depending on which menu entry was clicked:
                  function onMenuChoice(type, args, menu)
                  {
                              switch(args[1].index){
                                        case 0: //First entry
                                                break;
                                        case 1: //Second Entry
                                }
                  }