class source: Grid Example 1: E-mail List with Row and Column Navigation


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<html xml:lang="en" xmlns="http://www.w3.org/1999/xhtml"
      xmlns:wairole="http://www.w3.org/2005/01/wai-rdf/GUIRoleTaxonomy#"
      xmlns:aaa="http://www.w3.org/2005/07/aaa">

<head>
  <title>class: Grid Example 1: E-mail List with Row and Column Navigation</title>


<style type="text/css">
body {
  font-size: medium;
  font-family: sans-serif;
  }
  
.warning {
  color: red;
  font-weight: bold;
}

table.email {
  border: gray solid 2px;
}

table.emailfocus {
  border: black solid 2px;
}


tr.selected {
  background-color: #C0A080;
  color: white;
}

tr.highlightcolumn {
  background-color: #A0C0C0;
  color: black;
}

th, td {
  padding: .3em;
}


th {
  text-align: center;
  font-weight: bold;
}  

thead tr {
  background-color:#80A0A0;
  color: #F0F0F0;
}

tr.highlight,
td.highlight,
th.highlight {
  background-color: #C0E0E0;
  color: #202020;
}


.center {
  text-align: center;
}

label.hidden {
  position: absolute;
  left: -200em;
  top: -20em;
  }

h3 {
  margin: 0;
  padding: 0;
  font-weight: normal;
  font-size: medium;
}

code {
   font-size: large;
   font-family: monospace;
   font-weight: bold;
  }

div#config1 {
  display: none;
}
</style>

<script type="text/javascript">

//globals.js

/**
*
* The Globale Variables
*/

if (!window.Node) {
  var Node = {            // If there is no Node object, define one
    ELEMENT_NODE: 1,    // with the following properties and values.
    ATTRIBUTE_NODE: 2,  // Note that these are HTML node types only.
    TEXT_NODE: 3,       // For XML-specific nodes, you need to add
    COMMENT_NODE: 8,    // other constants here.
    DOCUMENT_NODE: 9,
    DOCUMENT_FRAGMENT_NODE: 11
  }
}


var KEY_PAGEUP   = 33;
var KEY_PAGEDOWN = 34;
var KEY_END      = 35;
var KEY_HOME     = 36;

var KEY_LEFT     = 37;
var KEY_UP       = 38;
var KEY_RIGHT    = 39;
var KEY_DOWN     = 40;

var KEY_SPACE    = 32;
var KEY_TAB      = 9;

var KEY_BACKSPACE = 8;
var KEY_DELETE    = 46;
var KEY_ENTER     = 13;
var KEY_INSERT    = 45;
var KEY_ESCAPE    = 27;

var KEY_F1        = 112;
var KEY_F2        = 113;
var KEY_F3        = 114;
var KEY_F4        = 115;
var KEY_F5        = 116;
var KEY_F6        = 117;
var KEY_F7        = 118;
var KEY_F8        = 119;
var KEY_F9        = 120;
var KEY_F10       = 121;

var KEY_M         = 77;

var NS_XHTML = "http://www.w3.org/1999/xhtml"
var NS_STATE = "http://www.w3.org/2005/07/aaa";

// **********************************************
// *
// * Commonly used helper functions
// *
// **********************************************

/**
*
* nextSiblingElement
*
* @contructor
*/

function nextSiblingElement( node ) {

  var next_node = node.nextSibling;

  while( next_node
    && (next_node.nodeType != Node.ELEMENT_NODE) ) {
    next_node = next_node.nextSibling;
  }  // endwhile

  return next_node;
  
}

/**
*
* previousSiblingElement
*
* @param ( node ) node object for which you are looking for the next sibling element node
*
* @return ( node) next sibling or "null"
*/

function previousSiblingElement( node ) {

  var next_node = node.previousSibling;

  while( next_node
    && (next_node.nodeType != Node.ELEMENT_NODE) ) {
    next_node = next_node.previousSibling;
  }  // endwhile

  return next_node;
  
}

/**
*
* firstChildElement
*
* @param ( node ) node object for which you are looking for the first child element node
*
* @return ( node) next sibling or "null"
*/

function firstChildElement( node ) {

  var next_node = node.firstChild;

  while( next_node
    && (next_node.nodeType != Node.ELEMENT_NODE) ) {
    next_node = next_node.nextSibling;
  }  // endwhile


  return next_node;
  
}

/**
*
* getTextContentOfNode
*
* @contructor
*/

function getTextContentOfNode( node ) {

  var next_node = node.firstChild;
  var str = "";

  while( next_node ) {
    
    if( (next_node.nodeType == Node.TEXT_NODE ) &&
      (next_node.length > 0 )
     )
      str += next_node.data;
    
    
    next_node = next_node.nextSibling;
    
  }  // endwhile

  return str;
  
}

/**
*
* setTextContentOfNode
*
* @contructor
*/

function setTextContentOfNode( node, text ) {

   // Generate a new text node with the text value
    var text_node = document.createTextNode(text);
  
    // Remove child nodes to remove text
    while (node.firstChild) {
      node.removeChild(node.firstChild);
    } // while

    // Append new text to the container element
    node.appendChild( text_node );

}
//widgets_class.js

// JavaScript Document


if (!window.Node) {
  var Node = {            // If there is no Node object, define one
    ELEMENT_NODE: 1,    // with the following properties and values.
    ATTRIBUTE_NODE: 2,  // Note that these are HTML node types only.
    TEXT_NODE: 3,       // For XML-specific nodes, you need to add
    COMMENT_NODE: 8,    // other constants here.
    DOCUMENT_NODE: 9,
    DOCUMENT_FRAGMENT_NODE: 11
  }
}

var ARIA_STATE = "aria-";

/**
* Widgets Object is used to initialize a set of controls
* and provide a conveinence fuction to cancel event propagration
* @construtor
*/

function Widgets() {
  this.widgets = new Array();
}

/**
* add is member of the Widgets Object
* and used add a widget ot the list of widgets to be intitialized
* as part of the onload event
* The controls array is the list of controls to initialize
* @member Enable
* @return none
*/

Widgets.prototype.add = function(obj) {
  this.widgets[this.widgets.length] = obj;
}

/**
* init is member of the Widgets Object
* and is called by the onload event to initialize widgets in the web resource
* The controls array is the list of controls to initialize
* @member Enable
* @return none
*/

Widgets.prototype.init = function() {
     
   for(var i = 0; i < this.widgets.length; i++ )
     this.widgets[i].init();
}

//
// convience function for getting the node based on id

function _$( id ) {
  return document.getElementById( id );  
}


//
// WebBrowser object to abstract accessibility API differences between web standards supporting browsers and Internet Explorer 7.0
//
// The state variable keeps track of current state of checkbox
function WebBrowser() {

}

/**
* Mouse capture
*
* @param ( node ) DOM node object
* @return nothing
*/

if ( document.addEventListener ) {

  // If a web standards based browser implement this function

  WebBrowser.prototype.setMouseCapture = function( node, clickHandler, downHandler, moveHandler, upHandler ) {

    if( clickHandler )
      document.addEventListener( "click",     clickHandler, true );
    
    if( downHandler )
      document.addEventListener( "mousedown", downHandler,  true );

    if( moveHandler )
      document.addEventListener( "mousemove", moveHandler,  true );
    
    if( upHandler)
      document.addEventListener( "mouseup",   upHandler,    true );

  }

  WebBrowser.prototype.releaseMouseCapture = function( node, clickHandler, downHandler, moveHandler, upHandler ) {

  if( upHandler)
      document.removeEventListener( "mouseup",   upHandler,    true );
      
    if( moveHandler )
      document.removeEventListener( "mousemove", moveHandler,  true );
    
    if( downHandler )
      document.removeEventListener( "mousedown", downHandler,  true );
      
    if( clickHandler )
      document.removeEventListener( "click",     clickHandler, true );

  }

} else {

  // If a Microsoft IE based browser implement this function

  WebBrowser.prototype.setMouseCapture = function( node, clickHandler, downHandler, moveHandler, upHandler ) {

   node.setCapture();
   if( clickHandler)
     node.attachEvent( "onclick", clickHandler );
    
   if( downHandler)
     node.attachEvent( "onmousedown", downHandler );
    
   if( moveHandler )
     node.attachEvent( "onmousemove", moveHandler );
    
   if( upHandler )
     node.attachEvent( "onmouseup", upHandler );

  } // endif

  WebBrowser.prototype.releaseMouseCapture = function( node, clickHandler, downHandler, moveHandler, upHandler ) {

   if( upHandler )
     node.detachEvent( "onmouseup", upHandler );
    
   if( moveHandler )
     node.detachEvent( "onmousemove", moveHandler );
    
   if( downHandler)
     node.detachEvent( "onmousedown", downHandler );
    
   if( clickHandler)
     node.detachEvent( "onclick", clickHandler );
    
     node.releaseCapture();

  } // endif


}

/**
* OnClick Event Simulator
*
* @param ( node ) DOM node object
* @return nothing
*/

if( document.createEvent ) {

  // If a web standards based browser implement this function

  WebBrowser.prototype.simulateOnClickEvent = function( node ) {
    // W3C DOM Events way to trigger a "click" event
    var e = document.createEvent('MouseEvents');
    e.initEvent( 'click', true, true );

    node.dispatchEvent( e );

  }

} else {

  // If a Microsoft IE based browser implement this function

  WebBrowser.prototype.simulateOnClickEvent = function( node ) {

    var e = document.createEventObject();
    node.fireEvent( "onclick", e );

  } // endif

}

//
// keyCode is a function to get the keycode from a keypress event
//
// @param ( event object) event is an event object
//
// @return ( keycode )

WebBrowser.prototype.keyCode = function( event ) {
  var e = event || window.event;
  
  return e.keyCode;
  
}  

if (typeof document.documentElement.setAttributeNS != 'undefined') {

  WebBrowser.prototype.stopPropagation = function( event ) {
    event.stopPropagation();
    event.preventDefault();
    return false;
  }

  WebBrowser.prototype.target = function( event ) {
  return event.target;
  }
  
  WebBrowser.prototype.charCode = function(event) {
     return event.charCode;
  }

  WebBrowser.prototype.calculateOffsetLeft = function( node ) {
  return node.offsetLeft;    
  }
  
  WebBrowser.prototype.calculateOffsetTop = function( node ) {
  return node.offsetTop;    
  }
  
  WebBrowser.prototype.pageX = function( e ) {
    return e.pageX;    
  }
  
  WebBrowser.prototype.pageY = function( e ) {
    return e.pageY;    
  }

  WebBrowser.prototype.setNodePosition = function(node,left,top) {
    node.style.left = left+"px";
    node.style.top = top+"px";
  }
  
} else {

  WebBrowser.prototype.stopPropagation = function( event ) {
    window.event.cancelBubble = true;
    window.event.returnValue = false;
    return false;
  }

  WebBrowser.prototype.charCode = function(event) {
    return window.browser.keyCode( event );
  }

  WebBrowser.prototype.target = function( event ) {
    return window.event.srcElement;
  }

  WebBrowser.prototype.calculateOffsetLeft = function(node) {
  var offset = 0;
  
  while( node ) {
    offset += node.offsetLeft;
    node = node.offsetParent;
  }
  
  return offset;    
  }
  
  WebBrowser.prototype.calculateOffsetTop = function(node) {
  var offset = 0;
  
  while( node ) {
    offset = offset + node.offsetTop;
    node = node.offsetParent;
  }
  
  return offset;    
  }

  WebBrowser.prototype.pageX = function( e ) {
    return e.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft);    
  }
  
  WebBrowser.prototype.pageY = function( e ) {
    return e.clientY + (document.documentElement.scrollTop || document.body.scrollTop);    
  }
  
  WebBrowser.prototype.setNodePosition = function(node,left,top) {
    var offsetx = 0;
    var offsety = 0;
    var nnode = node.offsetParent
    while( nnode ) {
      offsetx = offsetx + nnode.offsetLeft;
      offsety = offsety + nnode.offsetTop;
      nnode = nnode.offsetParent;
    }
    node.style.left = left-offsetx+"px";
    node.style.top = top-offsety+"px";
  }


};


if (document.addEventListener) {

     // Functions for W3C Standards compliant implementation of adding event handlers

     WebBrowser.prototype.addEvent = function(elmTarget, sEventName, fCallback) {
       elmTarget.addEventListener(sEventName, fCallback, false);
       returnValue = true;
     };

     WebBrowser.prototype.removeEvent = function(elmTarget, sEventName, fCallback) {
       elmTarget.removeEventListener(sEventName, fCallback, false);
       returnValue = true;
     };

     WebBrowser.prototype.addChangeEvent =  function(elmTarget, fCallback) {
      elmTarget.addEventListener("DOMAttrModified", fCallback, false);
      returnValue = true;
    };

} else {

  if(document.attachEvent) {

     // IE Specific Event handler functions
     WebBrowser.prototype.addEvent = function(elmTarget, sEventName, fCallback) {
       returnValue = elmTarget.attachEvent('on' + sEventName, fCallback);
     };

     WebBrowser.prototype.removeEvent = function(elmTarget, sEventName, fCallback) {
       returnValue = elmTarget.detachEvent('on' + sEventName, fCallback);
     };

    WebBrowser.prototype.addChangeEvent =  function(elmTarget, fCallback) {
      returnValue = elmTarget.attachEvent("onpropertychange", fCallback);
    };

  } else {

     // For browsers that do not support W3C or IE event functions
     WebBrowser.prototype.addEvent = function(elmTarget, sEventName, fCallback) {
       return false;
     };

     WebBrowser.prototype.removeEvent = function(elmTarget, sEventName, fCallback) {
       return false;
     };

     WebBrowser.prototype.addChangeEvent =  function(elmTarget, fCallback) {
       return false;
     };

  }

}



//
// ARIA functions to absract the setting and reading of ARIA features
// This is important since the ARIA specification is not completely defined
// This makes it easier to make syntactic changes to examples
//

function ARIA() {

}

ARIA.prototype.setAriaState = function(elmTarget, sStateName, sStateValue) {
  elmTarget.setAttribute(ARIA_STATE + sStateName, sStateValue);
}

ARIA.prototype.setRole = function(elmTarget, sStateValue) {
  elmTarget.setAttribute("role", sStateValue);
}
  
ARIA.prototype.getAriaState = function(elmTarget, sStateName) {
  return elmTarget.getAttribute(ARIA_STATE + sStateName);
}

ARIA.prototype.removeAriaState = function(elmTarget, sStateName) {
  return elmTarget.removeAttribute(ARIA_STATE + sStateName);
}

ARIA.prototype.hasAriaState = function(elmTarget, sStateName) {
  return elmTarget.hasAttribute(ARIA_STATE + sStateName);
}


ARIA.prototype.setRolesAndStates = function(elmAccessible)
{
  var STATE_MACHINE_BEGIN = 0;
  var STATE_MACHINE_IN_ACCESSIBLE = 1;
  var STATE_MACHINE_ROLE_IS_SET = 2;

  var sClass = elmAccessible.className;
  var arClassNames = sClass.split(' ');
  var machineState = STATE_MACHINE_BEGIN;
  var role = "";

  for (j = 0; j < arClassNames.length; j++) {

    // Delete spaces in CNAMEs
    var sClass = arClassNames[j].replace(/ /g, '');

    // alert(sClass + " " + machineState);
    // Test to see if there are any CNAMEs to process, if not exit
    if (!sClass) { continue; }
  
    // Look for CNAMEs assocaited with ARIA markup
    if ( sClass == 'axs' ) {

      /* found "axs" accessible keyword, rest of class will be treated as ARIA roles and states */
      machineState = STATE_MACHINE_IN_ACCESSIBLE;

    } else if (machineState == STATE_MACHINE_IN_ACCESSIBLE) {

//       alert(elmAccessible.id + " " + sClass);

      /* found role, set it and move on */
    if( sClass != 'norole')
        this.setRole(elmAccessible, sClass);

      machineState = STATE_MACHINE_ROLE_IS_SET;
      role = sClass;

    } else if (machineState == STATE_MACHINE_ROLE_IS_SET) {

      /* found state, set it and look for more */
      if (sClass.indexOf('-') != -1) {

        /* state has specific value, parse it out and set it */
        var arValue = sClass.split(/-/);

        // arValue[0] is state name, arValue[1] is value
  //
  // test for tabindex value
  if( arValue[0] != "tabindex" )
    //
    // If not tabindex set the aria property and value
          this.setAriaState(elmAccessible, arValue[0], arValue[1]);
  else {
    //
    // If tabindex use Microsoft IE property to set tabindex value
    if( arValue[1] != "" ) {
      // alert("Tabindex=" + arvalue[1]);
            elmAccessible.tabIndex = arValue[1];      
          } else {
      // if tabindex value is undefined assume it is a negative number and set tabindex=-1
      // alert("Tabindex=-1");
            elmAccessible.tabIndex = -1;            
    }
  }
      } else {
        /* state is simply a name, value is null - make it a string to match other values as strings*/
        this.setAriaState(elmAccessible, sClass, "");
      }
    }
  }
};

initApp = function(elmRoot) {
  
  if (document.isInitialized) {
    return;  // Avoid second initialization -- we inited early because of DOMContentLoaded
  }
  
  document.isInitialized = true;
  
  // If elmRoot is undefined start with the BODY element
  
  if ((!elmRoot) || (!elmRoot.getElementsByTagName)) {
    elmRoot = document.body;
  }

  // Check elmRoot node for information in the CLASS attribute to convert to ARIA markup
  
  if (/axs /.test(elmRoot.className)) {
    aria.setRolesAndStates(elmRoot);  // First do root element
  }

  //
  // Check for W3C Standards compliant implementation of XPATH evaluation
  if (document.evaluate) {
    
  // Get ARIA Roles and States  
    var snapAccessibleElements = document.evaluate(".//*[contains(@class, 'axs ')]", elmRoot, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
    for (var i = snapAccessibleElements.snapshotLength - 1; i >= 0; i--) {
      aria.setRolesAndStates(snapAccessibleElements.snapshotItem(i), "wairole:");
    }

  //
  // Otherwise use Micrsoft IE technique for identifying nodes
  } else {
  var axsElements = new Array();
  var axsElementCount = 0;

  var arElements = (typeof elmRoot.all != 'undefined') ? elmRoot.all : elmRoot.getElementsByTagName('*');
  var iElementCount = arElements.length;

  //
  // Find elements with ARIA markup and save their IDs
    for (var i = 0; i < iElementCount; i++) {
      if (/axs /.test(arElements[i].className)) {
        aria.setRolesAndStates(arElements[i]);
      } // endif
    } // endfor
  
}  // endif

  // Initialize widgets
  
  widgets.init();

};

// Initialize global variables used to initial widgets and provide browser independence for handling events and lack of namespace support in IE DOM functions

widgets_flag = true;
var widgets = new Widgets();
var browser = new WebBrowser();
var aria = new ARIA();
//grid1.js

// JavaScript Document

var STATUS_UNREAD = 0;
var STATUS_READ   = 1;

var PRIORITY_LOWEST  = 1;
var PRIORITY_LOW     = 2;
var PRIORITY_NORMAL  = 3;
var PRIORITY_HIGH    = 4;
var PRIORITY_HIGHEST = 5;

var MESSAGE_SELECTED   = 0;
var MESSAGE_ID         = 1;
var MESSAGE_STATUS     = 2;
var MESSAGE_ATTACHMENT = 3;
var MESSAGE_PRIORITY   = 4;
var MESSAGE_FROM       = 5;
var MESSAGE_SUBJECT    = 6;
var MESSAGE_DATE       = 7;
var MESSAGE_SIZE       = 8;
var MESSAGE_HIGHLIGHT  = 9;

// This arrray used for calaculating ids and labels to give id somewhoat huan readable ids

var type_label = new Array();
type_label[MESSAGE_SELECTED]   = "sel";
type_label[MESSAGE_ID]         = "id";
type_label[MESSAGE_STATUS]     = "read";
type_label[MESSAGE_ATTACHMENT] = "attch";
type_label[MESSAGE_PRIORITY]   = "prior";
type_label[MESSAGE_FROM]       = "from";
type_label[MESSAGE_SUBJECT]    = "subj";
type_label[MESSAGE_DATE]       = "date";
type_label[MESSAGE_SIZE]       = "size";

// This array is used to detemine which columns to render and in what order

var message_order = new Array(MESSAGE_SELECTED,
                              MESSAGE_ID,
                              MESSAGE_STATUS,
                              MESSAGE_ATTACHMENT,
                              MESSAGE_PRIORITY,
                              MESSAGE_FROM,
                              MESSAGE_SUBJECT,
                              MESSAGE_DATE,
                              MESSAGE_SIZE);

/**
*
* checkLabelledbyConfiguration
* test to see if any of the configuration checkboxes are checked
*
* @return ( boolean ) flag indicates whether one or more of the labelledby checkboxes is checked
*
*/

function checkLabelledbyConfiguration() {
  
  var flag = document.getElementById("selected_l").checked ||
               document.getElementById("message_l").checked ||
               document.getElementById("status_l").checked ||
               document.getElementById("attachment_l").checked ||
               document.getElementById("priority_l").checked ||
               document.getElementById("from_l").checked ||
               document.getElementById("subject_l").checked ||
               document.getElementById("date_l").checked ||
               document.getElementById("size_l").checked;
        
  return flag;  
}

/**
*
* getlablledbyForMessage
* Generate a list of ids for the labelledby of a messafe
*
* @param ( simpleEmailGrid object ) grid is s grid
* @param ( integer ) message the index of the image in the list
*
* @return ( string ) a list of ids separated by spaces
*/

function getLablledbyForMessage( grid, message ) {

    var idrefs = "";
  
  if( document.getElementById("selected_l").checked)
     idrefs += calcGridcellId( grid, message, MESSAGE_SELECTED ) + " ";

  if( document.getElementById("message_l").checked)
     idrefs += calcGridcellId( grid, message, MESSAGE_ID ) + " ";

  if( document.getElementById("status_l").checked)
     idrefs += calcGridcellId( grid, message, MESSAGE_STATUS ) + " ";

  if( document.getElementById("attachment_l").checked)
     idrefs += calcGridcellId( grid, message, MESSAGE_ATTACHMENT ) + " ";

  if( document.getElementById("priority_l").checked)
     idrefs += calcGridcellId( grid, message, MESSAGE_PRIORITY ) + " ";

  if( document.getElementById("from_l").checked) {
     idrefs += calcHeaderCellId( grid, MESSAGE_FROM ) + " ";
     idrefs += calcGridcellId( grid, message, MESSAGE_FROM ) + " ";
        } // endif

  if( document.getElementById("subject_l").checked) {
     idrefs += calcHeaderCellId( grid, MESSAGE_SUBJECT ) + " ";
     idrefs += calcGridcellId( grid, message, MESSAGE_SUBJECT ) + " ";
        }

  if( document.getElementById("date_l").checked) {
     idrefs += calcHeaderCellId( grid, MESSAGE_DATE ) + " ";
     idrefs += calcGridcellId( grid, message, MESSAGE_DATE ) + " ";
        }  // endif

  if( document.getElementById("size_l").checked) {
     idrefs += calcHeaderCellId( grid, MESSAGE_SIZE ) + " ";
     idrefs += calcGridcellId( grid, message, MESSAGE_SIZE );
        } // endif

    return idrefs;

}

/**
*
* checkDescribedbyConfiguration
* test to see if any of the configuration checkboxes are checked
*
* @return ( boolean ) flag indicates whether one or more of the labelledby checkboxes is checked
*
*/

function checkDescribedbyConfiguration() {
  
  var flag = document.getElementById("selected_d").checked ||
               document.getElementById("message_d").checked ||
               document.getElementById("status_d").checked ||
               document.getElementById("attachment_d").checked ||
               document.getElementById("priority_d").checked ||
               document.getElementById("from_d").checked ||
               document.getElementById("subject_d").checked ||
               document.getElementById("date_d").checked ||
               document.getElementById("size_d").checked;
        
  return flag;  
}

/**
*
* getDescribedbyForMessage
* Generate a list of ids for the describedby
*
* @param ( simpleEmailGrid object ) grid is s grid
* @param ( integer ) message the index of the image in the list
*
* @return ( string ) a list of ids separated by spaces
*/

function getDescribedbyForMessage( grid, message ) {

    var idrefs = "";
  
  if( document.getElementById("selected_d").checked)
     idrefs += calcGridcellId( grid, message, MESSAGE_SELECTED ) + " ";

  if( document.getElementById("message_d").checked)
     idrefs += calcGridcellId( grid, message, MESSAGE_ID ) + " ";

  if( document.getElementById("status_d").checked)
     idrefs += calcGridcellId( grid, message, MESSAGE_STATUS ) + " ";

  if( document.getElementById("attachment_d").checked)
     idrefs += calcGridcellId( grid, message, MESSAGE_ATTACHMENT ) + " ";

  if( document.getElementById("priority_d").checked)
     idrefs += calcGridcellId( grid, message, MESSAGE_PRIORITY ) + " ";

  if( document.getElementById("from_d").checked)
     idrefs += calcGridcellId( grid, message, MESSAGE_FROM ) + " ";

  if( document.getElementById("subject_d").checked)
     idrefs += calcGridcellId( grid, message, MESSAGE_SUBJECT ) + " ";

  if( document.getElementById("date_d").checked)
     idrefs += calcGridcellId( grid, message, MESSAGE_DATE ) + " ";

  if( document.getElementById("size_d").checked)
     idrefs += calcGridcellId( grid, message, MESSAGE_SIZE );
    
    return idrefs;
  
}

/**
*
* The calcGridcellId
*
* @param ( SimpleEmailGrid Object ) grid object contraining the messages
* @param ( integer ) message index of the message list
*
* @return ( string ) the unique id for a message container (TR element)
*/

function calcMessageId( grid, message ) {
  
   return grid.id + "_message" + message;
  
}

/**
*
* The calcHeaderRowId
*
* @param ( SimpleEmailGrid Object ) grid object contraining the messages
*
* @return ( string ) the unique id for a message container (TR element)
*/

function calcHeaderRowId( grid ) {
  
   return grid.id + "_header";
  
}

/**
*
* The calcGridcellId
* Create a table cell node for the grid cell
*
* @param ( SimpleEmailGrid Object ) grid object contraining the messages
* @param ( integer ) message_num is the current message number
* @param ( integer ) data_type itentifies the type of message data in the cell
*
* @retuen ( string ) the return value is the id for the cell
*/

function calcGridcellId( grid, message_num, data_type  ) {
  
   return grid.id + "_message" + message_num + "_" + type_label[data_type];
  
}

/**
*
* The calcHeaderCellId
*
* @param ( SimpleEmailGrid Object ) grid object contraining the messages
* @param ( integer ) data_type itentifies the type of message data
*
* @retuen ( string ) the return value is the id for the cell
*/

function calcHeaderCellId( grid, data_type  ) {
  
   return grid.id + "_" + type_label[data_type];
  
}

/**
*
* The simpleEmailHeader
* Create a table header cell node for the column heading
*
* @param ( SimpleEmailGrid Object ) grid object contraining the messages
* @param ( string ) text for the heade cell
* @param ( string ) css_style will be used to style content using CSS
*
* @return ( node ) return DOM node with the header cell
*/

function simpleEmailHeader( email_grid, type, text, abbr, css_style ) {
  
   var node_th = document.createElement("th");
   browser.addEvent( node_th, "focus", function(event) {handleSimpleEmailGridFocusEvent(event, email_grid);}, true);
   browser.addEvent( node_th, "blur", function(event)  {handleSimpleEmailGridBlurEvent(event, email_grid);},  true);
   node_th.tabIndex = -1;

   node_th.id  = calcHeaderCellId( email_grid, type );
   if( css_style != "" )
     node_th.className = css_style;
    
   if( abbr ) {

     var node_text = document.createTextNode(text);
     var node_abbr = document.createElement("abbr");
     node_abbr.setAttribute("title", abbr );
     node_abbr.appendChild( node_text );
     node_th.appendChild( node_abbr );


   } else {
  
     var node_text = document.createTextNode(text);
  
     node_th.appendChild( node_text );
    
   }
  
   return node_th;

}


/**
*
* The SimpleEmailHeaders object contains information about the current e-mail message
* and methods to render the headers
*
* @contructor
*/

function SimpleEmailHeaders() {
  
  this.cellMarkup = new Array();

  this.cellMarkup[MESSAGE_SELECTED]   = function( grid ) {
                                   return simpleEmailHeader( grid, MESSAGE_SELECTED, "Sel", "Selected", "" );
                                  } // end function

  this.cellMarkup[MESSAGE_ID]         = function( grid ) {
                                   return simpleEmailHeader( grid, MESSAGE_ID, "Mes", "Message", "" );
                                  } // end function

  this.cellMarkup[MESSAGE_STATUS]       = function( grid ) {
                                   return simpleEmailHeader( grid, MESSAGE_STATUS, "Status", "", "" );
                                  } // end function

  this.cellMarkup[MESSAGE_ATTACHMENT] = function( grid ) {
                                   return simpleEmailHeader( grid, MESSAGE_ATTACHMENT, "Att", "Attchment", "" );
                                  } // end function

  this.cellMarkup[MESSAGE_PRIORITY]  = function( grid ) {
                                   return simpleEmailHeader( grid, MESSAGE_PRIORITY, "Pri", "Priority", "" );
                                  } // end function

  this.cellMarkup[MESSAGE_FROM]      = function( grid ) {
                                   return simpleEmailHeader( grid, MESSAGE_FROM, "From", "", "" );
                                  } // end function

  this.cellMarkup[MESSAGE_SUBJECT]   = function( grid ) {
                                   return simpleEmailHeader( grid, MESSAGE_SUBJECT, "Subject", "", "" );
                                  } // end function

  this.cellMarkup[MESSAGE_DATE]   = function( grid ) {
                                   return simpleEmailHeader( grid, MESSAGE_DATE, "Date", "", "" );
                                  } // end function

  this.cellMarkup[MESSAGE_SIZE]   = function( grid ) {
                                   return simpleEmailHeader( grid, MESSAGE_SIZE, "Size", "", "" );
                                  } // end function
}


/**
*
* The SimpleEmailMessageText
* Create a table cell node for the grid cell
*
* @param ( SimpleEmailGrid Object ) emil_grid object contraining the messages
* @param ( integer ) message is the number of the message
* @param ( integer ) type is the type of message data in this cell
* @param ( string ) text for the text node
* @param ( string ) css_style is the class name for the td element
*
* @return ( node ) DOM node for grid cell
*/

function simpleEmailMessageText( email_grid, message, type, text, css_style ) {
  
   var node_td = document.createElement("td");
   node_td.id  = calcGridcellId( email_grid, message, type );
  
   node_td.className = css_style;

   // Add event handlers to update visual styling when grid cell receives and looses focus
   browser.addEvent( node_td, "focus", function(event) {handleSimpleEmailGridFocusEvent(event, email_grid);}, true);
   browser.addEvent( node_td, "blur", function(event)  {handleSimpleEmailGridBlurEvent(event, email_grid);},  true);
  
   // Set ARIA Properties
   node_td.setAttribute("role", "gridcell");
   node_td.tabIndex = -1;
   node_td.setAttribute("aria-labelledby", calcHeaderCellId(email_grid, type ) + " " + node_td.id );
  
   var node_text = document.createTextNode(text);
  
   node_td.appendChild( node_text );
  
   return node_td;

}


/**
*
* The SimpleEmailMessageImage
* Create a table cell node for the grid cell
*
* @param ( SimpleEmailGrid Object ) grid object contraining the messages
* @param ( integer ) message is the number of the message
* @param ( integer ) type is the type of message data in this cell
* @param ( src ) uri the uri to the image
* @param ( text ) alt is a text equivalent for the image
* @param ( string ) css_style will be used to style content using CSS
*
* @return ( node ) DOM node for grid cell
*/

function simpleEmailMessageImage( email_grid, message, type, src, alt, css_style ) {
  
   var node_td = document.createElement("td");
   node_td.id  = calcGridcellId( email_grid, message, type );
   node_td.className = css_style;

   // Add event handlers to update visual styling when grid cell receives and looses focus
   browser.addEvent( node_td, "focus", function(event) {handleSimpleEmailGridFocusEvent(event, email_grid);}, true);
   browser.addEvent( node_td, "blur", function(event)  {handleSimpleEmailGridBlurEvent(event, email_grid);},  true);
  
   // Add ARIA information
   node_td.setAttribute("role", "gridcell");
   node_td.tabIndex = -1;
   node_td.setAttribute("aria-labelledby", calcHeaderCellId(email_grid, type ) + " " + node_td.id );
  
   var node_img = document.createElement("img");
   node_img.setAttribute( "src", src );
   node_img.setAttribute( "alt", alt );
  
   node_td.appendChild( node_img );
  
   return node_td;
  
}

/**
*
* The SimpleEmailMessageCheckbox
* Create a table cell node for the grid cell
*
* @param ( SimpleEmailGrid Object ) grid object contraining the messages
* @param ( integer ) message is the number of the message
* @param ( integer ) type is the type of message data in this cell
* @param ( boolean ) flag indicates if the message is selected
* @param ( string ) label for the checkbox form control
* @param ( string ) css_style will be used to style content using CSS
*/

function simpleEmailMessageCheckbox( email_grid, message, type, flag, label, css_style ) {
  
   var node_td = document.createElement("td");
   node_td.id  = calcGridcellId( email_grid, message, type );
   node_td.className = css_style;

   // Add event handlers to update visual styling when grid cell receives and looses focus
   browser.addEvent( node_td, "focus", function(event) {handleSimpleEmailGridFocusEvent(event, email_grid);}, true);
   browser.addEvent( node_td, "blur", function(event)  {handleSimpleEmailGridBlurEvent(event, email_grid);},  true);
  
   // Add ARIA information
   node_td.setAttribute("role", "gridcell");
   node_td.tabIndex = -1;
   node_td.setAttribute("aria-labelledby", calcHeaderCellId(email_grid, type ) + " " + node_td.id );
  
   var node_input = document.createElement("input");
   node_input.setAttribute("type", "checkbox");
   node_input.setAttribute("name", "selected_" + message );
   node_input.setAttribute("title", label);
  
   // Removed checkbox from TAB order
   node_input.tabIndex = -1;
   node_input.checked = flag;
    
   node_td.appendChild( node_input );
  
   return node_td;
  
}



/**
*
* The SimpleEmailMessage object contains information about the current e-mail message
* and methods to render the message
*
* @contructor
*/

function SimpleEmailMessage() {
  this.data = new Array();
  this.cellMarkup = new Array();
  this.id = null;
  this.highlight = false;
  this.selected = false;
  
  // function to update checkbox when the item is selected
  
  this.checkboxId = null;
  
  // id
  this.data[MESSAGE_ID]         = null;
  // add fuction for creating markup for rendering id
  this.cellMarkup[MESSAGE_ID]   = function( grid, message ) {
                                  return simpleEmailMessageText( grid, message, MESSAGE_ID, grid.messages[message].data[MESSAGE_ID], "center");
                                  } // end function
  
  // Selected state information
  this.data[MESSAGE_SELECTED]   = false;
  // add fuction for creating markup for rendering selected infotmation
  this.cellMarkup[MESSAGE_SELECTED]   = function( grid, message) {
    
                                   grid.messages[message].checkboxId = calcGridcellId( grid, message, MESSAGE_SELECTED );
                                   return simpleEmailMessageCheckbox( grid, message, MESSAGE_SELECTED, grid.messages[message].data[MESSAGE_SELECTED], "Email " + message + " Selected","");
                                  } // end function
  
  // Status of being read
  this.data[MESSAGE_STATUS]       = STATUS_UNREAD;
  // add fuction for creating markup for rendering information about a message being read
  this.cellMarkup[MESSAGE_STATUS]   = function( grid, message) {
                                  if( grid.messages[message].data[MESSAGE_STATUS] )
                                     return simpleEmailMessageImage( grid, message, MESSAGE_STATUS, "images/read.gif", "Read message" ,"center");
                  else    
                                     return simpleEmailMessageImage( grid, message, MESSAGE_STATUS, "images/unread.gif", "New message" ,"center");
                                  } // end function              
  
  // Attachment
  this.data[MESSAGE_ATTACHMENT] = false;
  // add fuction for creating markup for rendering information about a message being read
  this.cellMarkup[MESSAGE_ATTACHMENT] = function( grid, message) {
                                  if( grid.messages[message].data[MESSAGE_ATTACHMENT] )                   
                                     return simpleEmailMessageImage( grid, message, MESSAGE_ATTACHMENT, "images/attach.gif", "Attachment" ,"center");
                  else
                                     return simpleEmailMessageImage( grid, message, MESSAGE_ATTACHMENT, "images/noattach.gif", "None" ,"center");
                                  } // end function
    
  // Email priority
  this.data[MESSAGE_PRIORITY]   = PRIORITY_NORMAL;
  // add fuction for creating markup for rendering information about a message being read
  this.cellMarkup[MESSAGE_PRIORITY]  = function( grid, message) {
                                  switch( grid.messages[message].data[MESSAGE_PRIORITY] ) {
                    
                                       case PRIORITY_LOWEST:
                                        return simpleEmailMessageImage( grid, message, MESSAGE_PRIORITY, "images/priority_lowest.gif", "Lowest priority" ,"center");
                      break;
                    
                                       case PRIORITY_LOW:
                                        return simpleEmailMessageImage( grid, message, MESSAGE_PRIORITY, "images/priority_low.gif", "Low priority" ,"center");
                      break;
                    
                                       case PRIORITY_HIGH:
                                        return simpleEmailMessageImage( grid, message, MESSAGE_PRIORITY, "images/priority_high.gif", "High priority" ,"center");
                      break;

                                       case PRIORITY_HIGHEST:
                                        return simpleEmailMessageImage( grid, message, MESSAGE_PRIORITY, "images/priority_highest.gif", "Highest priority" ,"center");
                      break;
                    
                                       default:
                                        return simpleEmailMessageImage( grid, message, MESSAGE_PRIORITY, "images/priority_none.gif", "" ,"center");
                      break;
                      
                  } // end switch
                  
                                  } // end function
  
  // Email From
  this.data[MESSAGE_FROM]       = "Unkown";
  // add fuction for creating markup for rendering the message is from
  this.cellMarkup[MESSAGE_FROM]        = function( grid, message) {
                                  return simpleEmailMessageText( grid, message, MESSAGE_FROM, grid.messages[message].data[MESSAGE_FROM], "");
                                  } // end function
    
  // Email Subject
  this.data[MESSAGE_SUBJECT]    = "No subject";
  // add fuction for creating markup for rendering the subject of the message
  this.cellMarkup[MESSAGE_SUBJECT]   = function( grid, message) {
                                  return simpleEmailMessageText( grid, message, MESSAGE_SUBJECT, grid.messages[message].data[MESSAGE_SUBJECT], "");
                                  } // end function
    
    // Email Date
  this.data[MESSAGE_DATE]       = "No date";
  // add fuction for creating markup for rendering the subject of the message
  this.cellMarkup[MESSAGE_DATE]      = function( grid, message ) {
                                  return simpleEmailMessageText( grid, message, MESSAGE_DATE, grid.messages[message].data[MESSAGE_DATE], "");
                                  } // end function
      
  // Email Size
  this.data[MESSAGE_SIZE]       = "No size";
  // add fuction for creating markup for rendering who the size of the message
  this.cellMarkup[MESSAGE_SIZE]   = function( grid, message) {
                                  return simpleEmailMessageText( grid, message, MESSAGE_SIZE, grid.messages[message].data[MESSAGE_SIZE], "");
                                  } // end function

}

/**
*
* The SimpleEmailGrid object is used to maintain information about a e-mail list widget
*
* @contructor
*/

function SimpleEmailGrid( id ) {

  this.id = id;
  
  this.in_headers = false;
  this.current_message = -1;
  this.current_column = -1;
  
  this.last_node = null;

  this.messages = new Array();

}

/**
* init is a subclass of SimpleEmailGrid and is used to initialize data
* the event handlers and for SimpleEmailGrid
*
* @member SimpleEmailGrid
*
* @return nothing
*/

SimpleEmailGrid.prototype.init = function() {

  this.node = document.getElementById( this.id );
  
  // Initialize data model for the grid

  // TBODY contains the information on all the current e-mail messages
  var message_data = this.node.getElementsByTagName("tbody")[0];
  
  // if there is a TBODY element extract e-mail data
  if( message_data ) {
  
  var message_rows = message_data.getElementsByTagName("tr");
  
  for(var row = 0; row < message_rows.length; row++ ) {
  
     var message_data = message_rows[row].getElementsByTagName("td");
    
     // see if message data is complete
     if( message_data.length == 9) {
      
     var message = new SimpleEmailMessage( row );
      
     // Get selected
     message.data[MESSAGE_SELECTED]   = message_data[0].getElementsByTagName("input")[0].checked;
        
         // Get message id
     message.data[MESSAGE_ID]         = getTextContentOfNode(message_data[1]);
    
         // Has message been read?
         message.data[MESSAGE_STATUS]       = getTextContentOfNode(message_data[2]).match(/true/) >= 0;
    
         // Attachment
         message.data[MESSAGE_ATTACHMENT] = getTextContentOfNode(message_data[3]).match(/true/) >= 0;

         // Email priority
         message.data[MESSAGE_PRIORITY]   = parseInt(getTextContentOfNode(message_data[4]));
    
     // From
         message.data[MESSAGE_FROM]       = getTextContentOfNode(message_data[5]);
    
     // Subject
         message.data[MESSAGE_SUBJECT]    = getTextContentOfNode(message_data[6]);
    
     // Date
         message.data[MESSAGE_DATE]       = getTextContentOfNode(message_data[7]);
    
     // Size
         message.data[MESSAGE_SIZE]       = getTextContentOfNode(message_data[8]);;
    
     // Highlight
         message.data[MESSAGE_HIGHLIGHT]  = false;
    
     // Add the message to the list
     this.messages[this.messages.length] = message;
    
     } // endif
    
  }  // endfor
    
  } // endif
  
  // Render E-mail headers using javascript
  
  this.headers = new SimpleEmailHeaders();
  
  simpleEmailGridRenderHeaders( this );

  // Render E-mail data using javascript
  
  simpleEmailGridRenderMessages( this );

  var obj = this;
  
  // Add event handlers for selecting a email grid
  browser.addEvent(this.node, "keydown", function(event) {handleSimpleEmailGridKeyDownEvent(event, obj);}, true);
  browser.addEvent(this.node, "focus", function(event) {handleSimpleEmailGridTableFocusEvent(event, obj);}, true);
  browser.addEvent(this.node, "click", function(event) {handleSimpleEmailGridClickEvent(event, obj );}, true);

  // event.addEvent(this.node, "click", function(event) {handleRadioGroupClickEvent(event, obj);}, false);

}

/**
* simpleEmailGridSetHeaderFocus
*
* @param ( SimpleEmailGrid object )  email_grid is the SimpleEmailGrid object to render
* @param ( integer ) column of the column to highlight
*
* @return nothing
*/

function simpleEmailGridSetHeaderFocus( email_grid, column ) {

  if( column >= message_order.length )
    column = message_order.length - 1;
    
  if( ( column >= 0 ) &&
      ( column < message_order.length ) )
     {
     // do this if one of the columns is selected
    
    email_grid.current_column = column;
    email_grid.last_node = document.getElementById(calcHeaderCellId(email_grid, message_order[column]));
  
  } else {
    //  
    // do this if no column is selected  
    
    email_grid.last_node = document.getElementById(calcHeaderRowId( email_grid ));

  } // endif
  
  email_grid.last_node.focus();

}


/**
* simpleEmailGridSetFocus
*
* @param ( SimpleEmailGrid object )  email_grid is the SimpleEmailGrid object to render
* @param ( integer ) message of the message to highlight
* @param ( integer ) column of the column to highlight
*
* @return nothing
*/

function simpleEmailGridSetFocus( email_grid, message, column ) {

  if( column >= message_order.length )
    column = message_order.length - 1;
    
  if( (message >= 0 ) &&
    (message < email_grid.messages.length)
    ) {

    if( ( column >= 0 ) &&
        ( column < message_order.length ) )
       {
      // do this if one of the columns is selected
    
      email_grid.current_message = message;
      email_grid.current_column = column;
    email_grid.last_node = document.getElementById(calcGridcellId(email_grid, message, message_order[column]));

    } else {
      //  
      // do this if no column is selected  
    
      email_grid.current_message = message;
      email_grid.last_node = document.getElementById(email_grid.messages[message].id);
  
    } // endif
  
    email_grid.last_node.focus();

  }  // endif

}

/**
* simpleEmailGridSelected
*
* @param ( SimpleEmailGrid object )  email_grid is the SimpleEmailGrid object to render
* @param ( integer ) message of the message to highlight
* @param ( boolean ) boolean value on whether to highlight or to remove
*
* @return nothing
*/

function simpleEmailGridSetSelected( email_grid, message, flag ) {

  if( (message >= 0 ) && ( message < email_grid.messages.length ) ) {
    email_grid.messages[message].selected = flag;  
    document.getElementById(email_grid.messages[message].checkboxId).getElementsByTagName("input")[0].checked = flag;

    var node = document.getElementById(email_grid.messages[message].id);

    // set ARIA flags
    if( flag ) {
      node.setAttribute("aria-selected", "true");    
    
      if( node.className.search(/selected/i) < 0) {
         node.className += " selected";
    }

  } else {
    node.setAttribute("aria-selected", "false");    
  
   // remove selected from current node
   node.className = email_grid.last_node.className.replace(/selected/i,"");

  }  // endif

  } // endif
  
}

/**
* simpleEmailGridToggledSelected
*
* @param ( SimpleEmailGrid object )  email_grid is the SimpleEmailGrid object to render
*
* @return nothing
*/

function simpleEmailGridToggleSelected( email_grid ) {

    if( email_grid.messages[email_grid.current_message].selected )
      simpleEmailGridSetSelected( email_grid, email_grid.current_message, false );
    else
      simpleEmailGridSetSelected( email_grid, email_grid.current_message, true );
  
}

/**
* simpleEmailGridRenderHeaders
* creates a dom node with renderable HTML mark up of current header cells  
*
* @param ( SimpleEmailGrid object )  email_grid is the SimpleEmailGrid object to render
*
* @return nothing
*/

function simpleEmailGridRenderHeaders( email_grid ) {

   var node_new_header = document.createElement("thead");
  
   var node_headings = document.createElement("tr");
   browser.addEvent( node_headings, "focus", function(event) {handleSimpleEmailGridFocusEvent(event, email_grid);}, true);
   browser.addEvent( node_headings, "blur", function(event)  {handleSimpleEmailGridBlurEvent(event, email_grid);},  true);
    
   // Make the row keyboard focusable using tabindex attribute
   node_headings.tabIndex = -1;
  
   // Add a id
   node_headings.id = calcHeaderRowId( email_grid );
  
   // Set the role of the role to grid cell
   node_headings.setAttribute("role","group");

   // add new table row markup
   node_new_header.appendChild( node_headings );
  
   for(var j = 0; j < message_order.length; j++ ) {

      var node = email_grid.headers.cellMarkup[message_order[j]]( email_grid );
      node_headings.appendChild( node);
      
   } // endfor
    
   var node_data = email_grid.node.getElementsByTagName("thead")[0];

   // remove current grid information on messages
   email_grid.node.removeChild( node_data );
  
   // add updated rendering information on about messages
   email_grid.node.appendChild( node_new_header );
  
}

/**
* simpleEmailGridRenderMessages
* creates a dom node with renderable HTML mark up for current messages
*
* @param ( SimpleEmailGrid object )  email_grid is the SimpleEmailGrid object to render
*
* @return nothing
*/

function simpleEmailGridRenderMessages( email_grid ) {

   var node_new_data = document.createElement("tbody");
  
   for(var i = 0; i < email_grid.messages.length; i++ ) {
    
     var node_message = document.createElement("tr");
    
     // Focus and blur events update visual styling of the node with focus
       browser.addEvent( node_message, "focus", function(event) {handleSimpleEmailGridFocusEvent(event, email_grid);}, true);
       browser.addEvent( node_message, "blur", function(event)  {handleSimpleEmailGridBlurEvent(event, email_grid);},  true);

       // Make the row keyboard focusable using tabindex attribute
     node_message.tabIndex = -1;

     // Set the role of the role to grid cell
     node_message.setAttribute("role","group");

     // Set the labelledby of message if any of the confurgation controls is set
     if( checkLabelledbyConfiguration() )
        node_message.setAttribute("aria-labelledby", getLablledbyForMessage( email_grid, i ));

     // Set the labelledby of message if any of the confurgation controls is set
     if( checkDescribedbyConfiguration() )
        node_message.setAttribute("aria-describedby", getDescribedbyForMessage( email_grid, i ));

     // set the id of the grid cell
     node_message.id = calcMessageId( email_grid, i );

     // save the id as part of the message data
     email_grid.messages[i].id = node_message.id;

     for( var j = 0; j < message_order.length; j++ ) {

       var node = email_grid.messages[i].cellMarkup[message_order[j]]( email_grid, i );
       node_message.appendChild( node);
      
     } // endfor
    
     node_new_data.appendChild( node_message );
      
   }  // endfor
  
   var node_data = email_grid.node.getElementsByTagName("tbody")[0];

   // remove current grid information on messages
   email_grid.node.removeChild( node_data );
  
   // add updated rendering information on about messages
   email_grid.node.appendChild( node_new_data );
  
}

/**
* simpleEmailGridUpdateMessageLabels
*
* @param ( SimpleEmailGrid object )  email_grid is the SimpleEmailGrid object to update labeling
*/

function simpleEmailGridUpdateMessageLabels( email_grid ) {

   for(var i = 0; i < email_grid.messages.length; i++ ) {
    
     // Set the labelledby of message if any of the confurgation controls is set
     if( checkLabelledbyConfiguration() )
       document.getElementById(email_grid.messages[i].id).setAttribute("aria-labelledby", getLablledbyForMessage( email_grid, i ));
     else
       document.getElementById(email_grid.messages[i].id).setAttribute("aria-labelledby", "");
  

     // Set the labelledby of message if any of the confurgation controls is set
     if( checkDescribedbyConfiguration() )
       document.getElementById(email_grid.messages[i].id).setAttribute("aria-describedby", getDescribedbyForMessage( email_grid, i ));
     else
       document.getElementById(email_grid.messages[i].id).setAttribute("aria-describedby", "");


   }  // endfor
  
}


/**
* handleSimpleEmailGridKeyDownEvent processes keys associated with a radio button group
*
* @param ( event ) event is the event handler for the event
* @param ( SimpleEmailGrid object )  email_grid is the SimpleEmailGrid object that is the target of the keyboard event
*
* @return false if keyboard event was used by the Email grid, else true
*/

function handleSimpleEmailGridKeyDownEvent( event, email_grid ) {
  
  var e = event || windows.event;

  switch( e.keyCode ) {
  
    case KEY_DOWN:

         simpleEmailGridSetFocus( email_grid, email_grid.current_message + 1, email_grid.current_column);

         return browser.stopPropagation(event);
         break;
  
    case KEY_UP:
    
         simpleEmailGridSetFocus( email_grid, email_grid.current_message - 1,  email_grid.current_column);
        
         return browser.stopPropagation(event);
         break;
    
    case KEY_LEFT:
    
  
         if( email_grid.current_column > 0 )
           simpleEmailGridSetFocus( email_grid, email_grid.current_message, email_grid.current_column - 1 );
         else
           simpleEmailGridSetFocus( email_grid, email_grid.current_message, 0 );
            
        
         return browser.stopPropagation(event);
         break;
  
    case KEY_RIGHT:

         if( email_grid.current_column >= 0 )
             simpleEmailGridSetFocus( email_grid, email_grid.current_message, email_grid.current_column + 1 );
         else
             simpleEmailGridSetFocus( email_grid, email_grid.current_message, 0 );
          
         return browser.stopPropagation(event);
         break;
    
    case KEY_SPACE:
    
         if( e.ctrlKey ) {
           email_grid.current_column = -1;
           simpleEmailGridSetFocus( email_grid, email_grid.current_message, -1 );      
         } else {
           simpleEmailGridToggleSelected( email_grid );
         } // endif
        
         return browser.stopPropagation(event);
         break;  
  }
  
  return true;

}

/**
* handleSimpleEmailGridTableFocusEvent
*
* @param ( event ) event is the event handler for the event
* @param ( SimpleEmailGrid object ) email_grid is the SimpleEmailGrid object that is the target of the pointer event
*
* @return false if poiner event was used by radio group, else true
*/

function handleSimpleEmailGridTableFocusEvent( event, email_grid ) {
  
  var node = browser.target( event );
  
  if( node.id == email_grid.node.id ) {
    
     email_grid.node.className = "emailfocus";
     email_grid.node.tabIndex = -1;
  
   if( email_grid.last_node == null )
     simpleEmailGridSetFocus( email_grid, 0, -1 );
   else
     simpleEmailGridSetFocus( email_grid, email_grid.current_message, email_grid.current_column );
  
  } // endif

}

/**
* handleSimpleEmailGridFocusEvent
*
* @param ( event ) event is the event handler for the event
* @param ( SimpleEmailGrid object ) email_grid is the SimpleEmailGrid object that is the target of the pointer event
* @return false if poiner event was used by radio group, else true
*/

function handleSimpleEmailGridFocusEvent( event, email_grid ) {
  
   var node = browser.target( event );
  
   email_grid.node.className = "emailfocus";
  
   if( node.id != email_grid.node.id ) {
    
     // if highlight is already set don't set again
     if( node.className.search(/highlight/i) < 0)
         node.className += " highlight";

     node.tabIndex = 0;

   } // endif

}

/**
* handleSimpleEmailGridBlurEvent
*
* @param ( event ) event is the event handler for the event
* @param ( SimpleEmailGrid object ) email_grid is the SimpleEmailGrid object that is the target of the pointer event
*
* @return nothing
*/

function handleSimpleEmailGridBlurEvent( event, email_grid ) {

   var node = browser.target( event );
  
   email_grid.node.className = "email";
  
   if( node != email_grid.node ) {
    
     // remove highlight from current node
     node.className = node.className.replace(/highlight/i,"");
   node.tabIndex = -1;
   email_grid.node.tabIndex = 0;
  
   } // endif

}


/**
* handleSimpleEmailGridClickEvent processes pointer click events with in the SimpleEmailGrid widget
*
* @param ( event ) event is the event handler for the event
* @param ( SimpleEmailGrid object ) email_grid is the SimpleEmailGrid object that is the target of the pointer event
*
* @return false if poiner event was used by radio group, else true
*/

function handleSimpleEmailGridClickEvent( event, email_grid ) {

  var node = browser.target( event );
  
  while( node &&
     ( node.tagName.search(/tr/i) < 0 )
     )
     node = node.parentNode;

  if( node ) {

    // find message number
    var result = node.id.match(/(message)([d])/);
  
  if( result && result[2] ) {
  
    var message = new Number(result[2]);
  
      email_grid.in_headers = false;
      simpleEmailGridSetFocus( email_grid, message, -1 );
      simpleEmailGridToggleSelected( email_grid );
    
  } else {

      email_grid.current_message = -1;
      email_grid.in_headers = true;
          
    simpleEmailGridSetHeaderFocus( email_grid, -1);
    
  } // endif
  
  
  } // endif

}

/**
* handleConfigurationToggleClickEvent
* Show and hide configuration information
*
* @param ( event ) event is the event handler for the event
* @param ( id ) id of the content to show or hide
*
* @return false to prevent event bubbling
*/

function handleConfigurationToggleClickEvent( event, id ) {

  if( document.getElementById( id ).style.display == "block" ) {
    document.getElementById( id ).style.display = "none";  
    event.target.value = "Show Labelledby and Describedby settings for messages";  
  } else {
    document.getElementById( id ).style.display = "block";
    event.target.value = "Hide Labelledby and Describedby settings for messages";  
  } // endif

  return false;
}

/**
* handleSimpleEmailGridApplyClickEvent
* Show and hide configuration information
*
* @param ( event ) event is the event handler for the event
* @param ( grid object ) id of the content to show or hide
*
* @return false to prevent event bubbling
*/

function handleSimpleEmailGridApplyClickEvent( event, email_grid ) {

  // Render E-mail data using javascript
  
  simpleEmailGridUpdateMessageLabels( email_grid );

  return false;

}

</script>
</head>
<body onload="widgets.init()">
<div role="application">
<script type="text/javascript">
  var grid1 = new SimpleEmailGrid("grid1");
  widgets.add(grid1);
</script>


<table id="grid1"
       class="email"
       role="grid"
       tabindex="0"
       aria-labelledby="grid1_label"
       border="2px"
       cellpadding="2px"
     >
  <caption id="grid1_label">E-mail List Sorted by Date</caption>
  
  <thead>
    <tr>
      <th id="sel"><abbr title="Selected">Sel</abbr></th>
      <th id="msg"><abbr title="Message Number">Msg</abbr></th>
      <th id="sta">Status</th>
      <th id="att"><abbr title="Abbreviation">Att</abbr></th>
      <th id="pri"><abbr title="Priority">Pri</abbr></th>
      <th id="fro">From</th>
      <th id="sub">Subject</th>
      <th id="dat">Date</th>
      <th id="siz">Size</th>
  </tr>
  </thead>
  
  <tbody>
    <tr id="email_01"
        role="gridcell"
        tabindex="-1">
    <td headers="sel"><input name="email_01" type="checkbox"/></td>
    <td headers="msg">1</td>
    <td headers="sta">false</td>
    <td headers="att">false</td>
    <td headers="pri">1</td>
    <td headers="fro">John Smith</td>
    <td headers="sub">Trip to Florida</td>
    <td headers="dat">2007-10-03</td>
    <td headers="siz">2K</td>    
  </tr>

    <tr id="email_02"
        role="gridcell"
        tabindex="-1">
    <td headers="sel"><input name="email_02" type="checkbox"/></td>
    <td headers="msg">2</td>
    <td headers="sta">true</td>
    <td headers="att">false</td>
    <td headers="pri">2</td>
    <td headers="fro">Fred Jones</td>
    <td headers="sub">Lunch on Friday</td>
    <td headers="dat">2007-12-03</td>
    <td headers="siz">1K</td>    
  </tr>

    <tr id="email_03"
        role="gridcell"
        tabindex="-1">
    <td headers="sel"><input name="email_03" type="checkbox"/></td>
    <td headers="msg">3</td>
    <td headers="sta">true</td>
    <td headers="att">true</td>
    <td headers="pri">3</td>
    <td headers="fro">Jane Johnson</td>
    <td headers="sub">Proposal for you to review</td>
    <td headers="dat">2007-16-03</td>
    <td headers="siz">12K</td>    
  </tr>

    <tr id="email_04"
        role="gridcell"
        tabindex="-1">
    <td headers="sel"><input name="email_03" type="checkbox"/></td>
    <td headers="msg">4</td>
    <td headers="sta">false</td>
    <td headers="att">true</td>
    <td headers="pri">4</td>
    <td headers="fro">Bill Smith</td>
    <td headers="sub">Information on weekend</td>
    <td headers="dat">2007-19-03</td>
    <td headers="siz">122K</td>    
  </tr>

    <tr id="email_05"
        role="gridcell"
        tabindex="-1">
    <td headers="sel"><input name="email_03" type="checkbox"/></td>
    <td headers="msg">5</td>
    <td headers="sta">true</td>
    <td headers="att">false</td>
    <td headers="pri">5</td>
    <td headers="fro">Skip Roland</td>
    <td headers="sub">Opportunity to participate</td>
    <td headers="dat">2007-20-03</td>
    <td headers="siz">4K</td>    
  </tr>



  </tbody>
  
</table>


<p>
  <input type="button" onclick="handleConfigurationToggleClickEvent(event, 'config1')" value="Show Labelledby and Describedby settings for messages"/>
  <input type="button" onclick="handleSimpleEmailGridApplyClickEvent( event, grid1 )" value="Apply new Labelledby and Describedby settings"/>
</p>

<div id="config1">
<fieldset>
<legend>Configure ARIA <code>labelledby</code> attribute for messages</legend>

<ul style="list-style: none">
  <li><label><input id="selected_l"   type="checkbox" checked=""/>Selected</label></li>
  <li><label><input id="message_l"    type="checkbox" checked=""/>Message Number</label></li>
  <li><label><input id="status_l"     type="checkbox" checked=""/>Read/Unread</label></li>
  <li><label><input id="attachment_l" type="checkbox" checked=""/>Attchement</label></li>
  <li><label><input id="priority_l"   type="checkbox" checked=""/>Priority</label></li>
  <li><label><input id="from_l"       type="checkbox" checked=""/>From</label></li>
  <li><label><input id="subject_l"    type="checkbox" checked=""/>Subject</label></li>
  <li><label><input id="date_l"       type="checkbox"/>Date</label></li>
  <li><label><input id="size_l"       type="checkbox"/>Size</label></li>
</ul>

</fieldset>

<fieldset>
<legend>Configure ARIA <code>describedby</code> attribute for messages</legend>

<ul style="list-style: none">
  <li><label><input id="selected_d"   type="checkbox" checked=""/>Selected</label></li>
  <li><label><input id="message_d"    type="checkbox" checked=""/>Message Number</label></li>
  <li><label><input id="status_d"     type="checkbox" checked=""/>Read/Unread</label></li>
  <li><label><input id="attachment_d" type="checkbox" checked=""/>Attchement</label></li>
  <li><label><input id="priority_d"   type="checkbox" checked=""/>Priority</label></li>
  <li><label><input id="from_d"       type="checkbox" checked=""/>From</label></li>
  <li><label><input id="subject_d"    type="checkbox" checked=""/>Subject</label></li>
  <li><label><input id="date_d"       type="checkbox"/>Date</label></li>
  <li><label><input id="size_d"       type="checkbox"/>Size</label></li>
</ul>

</fieldset>



</div>
</div></body>
</html>