test104a.html
authorRichard Schwerdtfeger <schwer@us.ibm.com>
Mon, 11 Nov 2013 11:35:31 -0600
changeset 413 8f5b4c80fb9e
parent 411 fcfd7d399bf9 (current diff)
parent 412 806564d2a54a (diff)
child 414 008b88ba265c
test104a.html
ARIA-UAIG/1.0/tests/test-files/test104a.html
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ARIA-UAIG/1.0/tests/test-files/test104a.html	Mon Nov 11 11:35:31 2013 -0600
@@ -0,0 +1,1456 @@
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" >
+  <head id="head">
+    
+    <title id="header_title">Example 25 - Menubar</title>
+    
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+    
+    <link rel="stylesheet" href="http://www.oaa-accessibility.org/media/css/openajax-example-print.css"   type="text/css" media="print" />
+    <link rel="stylesheet" href="http://www.oaa-accessibility.org/media/css/openajax-example-screen.css"  type="text/css" media="screen" title="screen" />
+
+    <script type="text/javascript">
+      var $URL_SITE = "http://www.oaa-accessibility.org/media//";
+    </script>
+
+<style type="text/css">
+body {
+     background: white;
+     }
+
+#st1 {
+	padding: .5em;
+	border: 1px solid black;
+	height: 400px;
+	width: 70%;
+	font-size: medium;
+	font-family: sans-serif;
+}
+ul.menubar {
+	margin: 0 !important;
+	padding: 0 .25em !important;
+	list-style: none !important;
+   font-size: 100% !important;
+	height: 1.85em;
+	width: 20em;
+	border: 1px solid black;
+	background: #ccc;
+}
+ul.menubar li {
+	float: left;
+	display: inline; position: relative;
+	margin: 0;
+	padding: .25em .35em;
+	height: 1.25em;
+}
+ul.menu {
+	position: absolute;
+	left: 0;
+	top: 1.75em;
+	display: none;
+	list-style: none;
+	margin: 0 !important;
+	padding: 0 !important;
+	font-weight: normal !important;
+   font-size: 100% !important;
+	border: 1px solid black;
+	background-color: #ccc;
+	width: 8.5em;
+}
+ul.menu li {
+	float: none;
+	display: block;
+	white-space: nowrap;
+	padding: 2px 1em;
+	color: black;
+}
+
+li.separator {
+	margin: 0;
+	margin-bottom: 4px !important;
+	height: 2px !important;
+	border-bottom: 1px solid black;
+}
+
+li.checked {
+	font-weight: bold;
+	background-image: url('http://www.oaa-accessibility.org/media/examples/images/dot.png');
+	background-repeat: no-repeat;
+	background-position: 5px 10px;
+}
+
+.menu-hover {
+	background-color: #700 !important;
+	color: white !important;
+}
+
+.menu-hover-checked {
+	background-color: #700 !important;
+	color: white !important;
+	background-image: url('http://www.oaa-accessibility.org/media/examples/images/dot-selected.png') !important;
+}
+
+.menu-focus {
+	background-color: black;
+	font-weight: bold;
+	color: white !important;
+}
+
+li.menu-focus-checked {
+	background-color: black;
+	font-weight: bold;
+	color: white !important;
+	background-image: url('http://www.oaa-accessibility.org/media/examples/images/dot-selected.png') !important;
+}
+.hidden {
+   position: absolute;
+   left: -200em;
+   top: -20em;
+}
+
+
+/*
+ * Text area styles
+ */
+.italic {
+	font-style: italic;
+}
+.bold {
+	font-weight: bold;
+}
+.underline {
+	text-decoration: underline;
+}
+
+</style>
+
+
+
+
+
+    
+
+
+<script type="text/javascript" src="http://www.oaa-accessibility.org/media/examples/js/jquery-1.4.2.min.js"></script>
+
+
+
+<script type="text/javascript">
+
+$(document).ready(function() {
+      var menu1 = new menubar('mb1', false);
+
+}); // end ready()
+
+/////////////// begin textArea widget definition ////////////////////////
+
+//
+// Function textArea() is the constructor of a widget to manipulate the
+// properties of a text area.
+//
+// @param(id string) id is the HTML id of the text area to bind to
+//
+// @return N/A
+//
+function textArea(id) {
+
+	// define widget properties
+	this.$id = $('#' + id);
+
+	this.fontSizes = new Array('x-small', 'small', 'medium', 'large', 'x-large');
+	this.sizeNdx = 2; // index of current size setting
+
+} // end textArea() constructor
+
+//
+// setFont() is a member function to set the font family of the text area.
+//
+// @param ( fontFamily string ) name of family to set
+//
+// @return N/A
+//
+textArea.prototype.setFont = function(fontFamily) {
+
+	this.$id.css('font-family', fontFamily);
+
+} // end setFont()
+
+//
+// setStyle() is a member function to set the font style of the text area.
+//
+// @param ( style string ) name of style to set
+//
+// @return N/A
+//
+textArea.prototype.setStyle = function(style) {
+
+	this.$id.toggleClass(style);
+
+} // end setStyle()
+
+//
+// setAlignment() is a member function to set the text alignment of the text area
+//
+// @param ( justification string ) name of style to set
+//
+// @return N/A
+//
+textArea.prototype.setAlignment = function(justification) {
+
+	this.$id.css('text-align', justification);
+
+} // end setAlignment()
+
+//
+// Function getSize() returns the size of text in the text area.
+//
+// @return N/A
+// 
+textArea.prototype.getSize = function() {
+
+	return this.fontSizes[this.sizeNdx];
+
+} // end getSize()
+
+//
+// Function setSize() sets the size of text in the text area.
+//
+// @param ( size string ) size of text to set
+//
+// @return N/A
+// 
+textArea.prototype.setSize = function(size) {
+
+	switch (size) {
+	    case 'larger': {
+	        this.sizeNdx += 1;
+	        if (this.sizeNdx > 4) {
+	            this.sizeNdx = 4;
+	        }
+	        break;
+	    }
+	    case 'smaller': {
+	        this.sizeNdx -= 1;
+	        if (this.sizeNdx < 0) {
+	            this.sizeNdx = 0;
+	        }
+	        break;
+	    }
+	    case 'x-small': {
+	        this.sizeNdx = 0;
+	        break;
+	    }
+	    case 'small': {
+	        this.sizeNdx = 1;
+	        break;
+	    }
+	    case 'medium': {
+	        this.sizeNdx = 2;
+	        break;
+	    }
+	    case 'large': {
+	        this.sizeNdx = 3;
+	        break;
+	    }
+	    case 'x-large': {
+	        this.sizeNdx = 4;
+	        break;
+	    }
+	} // end switch
+
+	// set the new size
+	this.$id.css('font-size', this.fontSizes[this.sizeNdx]);
+
+} // end setSize();
+
+/////////////// end textArea widget definition ////////////////////////
+
+/////////////// begin menu widget definition /////////////////////
+//
+// Function menubar() is the constructor of a menu widget
+// The widget will bind to the ul passed to it.
+//
+// @param(id string) id is the HTML id of the ul to bind to
+//
+// @param(vmenu boolean) vmenu is true if menu is vertical; false if horizontal
+//
+// @return N/A
+//
+function menubar(id, vmenu) {
+
+   // define widget properties
+   this.$id = $('#' + id);
+
+   this.$rootItems = this.$id.children('li'); // jQuerry array of all root-level menu items
+
+   this.$items = this.$id.find('.menu-item').not('.separator'); // jQuery array of menu items
+   this.$parents = this.$id.find('.menu-parent'); // jQuery array of menu items
+   this.$allItems = this.$parents.add(this.$items); // jQuery array of all menu items
+   this.$activeItem = null; // jQuery object of the menu item with focus
+
+   this.vmenu = vmenu;
+   this.bChildOpen = false; // true if child menu is open
+
+   this.keys = {
+            tab:    9,
+            enter:  13,
+            esc:    27,
+            space:  32,
+            left:   37,
+            up:     38,
+            right:  39,
+            down:   40 
+   };
+
+   // bind event handlers
+   this.bindHandlers();
+
+   // associate the menu with the textArea it controls
+   this.textarea = new textArea(this.$id.attr('aria-controls'));
+};
+
+//
+// Function bindHandlers() is a member function to bind event handlers for the widget.
+//
+// @return N/A
+//
+menubar.prototype.bindHandlers = function() {
+
+   var thisObj = this;
+
+   ///////// bind mouse event handlers //////////
+
+   // bind a mouseenter handler for the menu items
+   this.$items.mouseenter(function(e) {
+      if ($(this).is('.checked')) {
+         $(this).addClass('menu-hover-checked');
+      }
+      else {
+         $(this).addClass('menu-hover');
+      }
+      return true;
+   });
+
+   // bind a mouseout handler for the menu items
+   this.$items.mouseout(function(e) {
+      $(this).removeClass('menu-hover menu-hover-checked');
+      return true;
+   });
+
+   // bind a mouseenter handler for the menu parents
+   this.$parents.mouseenter(function(e) {
+      return thisObj.handleMouseEnter($(this), e);
+   });
+
+   // bind a mouseleave handler
+   this.$parents.mouseleave(function(e) {
+      return thisObj.handleMouseLeave($(this), e);
+   });
+
+   // bind a click handler
+   this.$allItems.click(function(e) {
+      return thisObj.handleClick($(this), e);
+   });
+
+   //////////// bind key event handlers //////////////////
+  
+   // bind a keydown handler
+   this.$allItems.keydown(function(e) {
+      return thisObj.handleKeyDown($(this), e);
+   });
+
+   // bind a keypress handler
+   this.$allItems.keypress(function(e) {
+      return thisObj.handleKeyPress($(this), e);
+   });
+
+   // bind a focus handler
+   this.$allItems.focus(function(e) {
+      return thisObj.handleFocus($(this), e);
+   });
+
+   // bind a blur handler
+   this.$allItems.blur(function(e) {
+      return thisObj.handleBlur($(this), e);
+   });
+
+   // bind a document click handler
+   $(document).click(function(e) {
+         return thisObj.handleDocumentClick(e);
+   });
+
+} // end bindHandlers()
+
+//
+// Function handleMouseEnter() is a member function to process mouseover
+// events for the top menus.
+//
+// @param($item object) $item is the jquery object of the item firing the event
+//
+// @param(e object) e is the associated event object
+//
+// @return(boolean) Returns false;
+//
+menubar.prototype.handleMouseEnter = function($item, e) {
+
+   // add hover style
+   if ($item.is('.checked')) {
+      $item.addClass('menu-hover-checked');
+   }
+   else {
+      $item.addClass('menu-hover');
+   }
+
+   // expand the first level submenu
+   if ($item.attr('aria-haspopup') == 'true') {
+      $item.children('ul').show().attr('aria-hidden', 'false');
+      this.bChildOpen = true;
+   }
+   //e.stopPropagation();
+   return true;
+
+} // end handleMouseEnter()
+
+//
+// Function handleMouseOut() is a member function to process mouseout
+// events for the top menus.
+//
+// @param($item object) $item is the jquery object of the item firing the event
+//
+// @param(e object) e is the associated event object
+//
+// @return(boolean) Returns false;
+//
+menubar.prototype.handleMouseOut = function($item, e) {
+
+   // Remover hover styles
+   $item.removeClass('menu-hover menu-hover-checked');
+
+   //e.stopPropagation();
+   return true;
+
+} // end handleMouseOut()
+
+//
+// Function handleMouseLeave() is a member function to process mouseout
+// events for the top menus.
+//
+// @param($menu object) $menu is the jquery object of the item firing the event
+//
+// @param(e object) e is the associated event object
+//
+// @return(boolean) Returns false;
+//
+menubar.prototype.handleMouseLeave = function($menu, e) {
+
+   var $active = $menu.find('.menu-focus-checked');
+
+   $active = $active.add($menu.find('.menu-focus'));
+
+   // Remove hover style
+   $menu.removeClass('menu-hover menu-hover-checked');
+
+   // if any item in the child menu has focus, move focus to the root item
+   if ($active.length > 0) {
+
+      this.bChildOpen = false;
+
+      // remove the focus style from the active item
+      $active.removeClass('menu-focus menu-focus-checked'); 
+
+      // store the active item
+      this.$activeItem = $menu;
+ 
+      // cannot hide items with focus -- move focus to root item
+      $menu.focus();
+   }
+
+   // hide the child menu
+   $menu.children('ul').hide().attr('aria-hidden', 'true');
+
+   //e.stopPropagation();
+   return true;
+
+} // end handleMouseLeave()
+
+//
+// Function handleClick() is a member function to process click events
+// for the top menus.
+//
+// @param($item object) $item is the jquery object of the item firing the event
+//
+// @param(e object) e is the associated event object
+//
+// @return(boolean) Returns false;
+//
+menubar.prototype.handleClick = function($item, e) {
+
+   var $parentUL = $item.parent();
+
+   if ($parentUL.is('.root-level')) {
+         // open the child menu if it is closed
+         $item.children('ul').first().show().attr('aria-hidden', 'false');
+         this.bChildOpen = true;
+   }
+   else {
+      // process the menu choice
+      this.processMenuChoice($item);
+
+      // remove hover and focus styling
+      this.$allItems.removeClass('menu-hover menu-hover-checked menu-focus menu-focus-checked');
+
+      // close the menu
+      this.$id.find('ul').not('.root-level').hide().attr('aria-hidden','true');
+
+      // move focus to the text area
+      this.textarea.$id.focus();
+   }
+
+   e.stopPropagation();
+   return false;
+
+} // end handleClick()
+
+//
+// Function handleFocus() is a member function to process focus events
+// for the menu.
+//
+// @param($item object) $item is the jquery object of the item firing the event
+//
+// @param(e object) e is the associated event object
+//
+// @return(boolean) Returns true;
+//
+menubar.prototype.handleFocus = function($item, e) {
+
+   // if activeItem is null, we are getting focus from outside the menu. Store
+   // the item that triggered the event
+   if (this.$activeItem == null) {
+      this.$activeItem = $item;
+   }
+   else if ($item[0] != this.$activeItem[0]) {
+      return true;
+   }
+   
+   // get the set of jquery objects for all the parent items of the active item
+   var $parentItems = this.$activeItem.parentsUntil('div').filter('li');
+
+   // remove focus styling from all other menu items
+   this.$allItems.removeClass('menu-focus menu-focus-checked');
+
+   // add styling to the active item
+   if (this.$activeItem.is('.checked')) {
+      this.$activeItem.addClass('menu-focus-checked');
+   }
+   else {
+      this.$activeItem.addClass('menu-focus');
+   }
+
+   // add styling to all parent items.
+   // This assumes that parent items do not have a checked state
+   $parentItems.addClass('menu-focus');
+
+   if (this.vmenu == true) {
+      // if the bChildOpen is true, open the active item's child menu (if applicable)
+      if (this.bChildOpen == true) {
+
+         var $itemUL = $item.parent();
+
+         // if the itemUL is a root-level menu and item is a parent item,
+         // show the child menu.
+         if ($itemUL.is('.root-level') && ($item.attr('aria-haspopup') == 'true')) {
+            $item.children('ul').show().attr('aria-hidden', 'false');
+         }
+      }
+      else {
+         this.vmenu = false;
+      }
+   }
+
+   return true;
+
+} // end handleFocus()
+
+//
+// Function handleBlur() is a member function to process blur events
+// for the menu.
+//
+// @param($item object) $item is the jquery object of the item firing the event
+//
+// @param(e object) e is the associated event object
+//
+// @return(boolean) Returns true;
+//
+menubar.prototype.handleBlur = function($item, e) {
+
+   $item.removeClass('menu-focus menu-focus-checked');
+
+   return true;
+
+} // end handleBlur()
+
+//
+// Function handleKeyDown() is a member function to process keydown events
+// for the menus.
+//
+// @param($item object) $item is the jquery object of the item firing the event
+//
+// @param(e object) e is the associated event object
+//
+// @return(boolean) Returns false if consuming; true if propagating
+//
+menubar.prototype.handleKeyDown = function($item, e) {
+
+   if (e.altKey || e.ctrlKey) {
+       // Modifier key pressed: Do not process
+       return true;
+   }
+
+   switch(e.keyCode) {
+      case this.keys.tab: {
+
+         // hide all menu items and update their aria attributes
+         this.$id.find('ul').hide().attr('aria-hidden', 'true');
+
+         // remove focus styling from all menu items
+         this.$allItems.removeClass('menu-focus');
+
+         this.$activeItem = null;
+         this.bChildOpen == false;
+
+         break;
+      }
+      case this.keys.esc: {
+         var $itemUL = $item.parent();
+
+         if ($itemUL.is('.root-level')) {
+            // hide the child menu and update the aria attributes
+            $item.children('ul').first().hide().attr('aria-hidden', 'true');
+         }
+         else {
+
+            // move up one level
+            this.$activeItem = $itemUL.parent();
+
+            // reset the childOpen flag
+            this.bChildOpen = false;
+
+            // set focus on the new item
+            this.$activeItem.focus();
+
+            // hide the active menu and update the aria attributes
+            $itemUL.hide().attr('aria-hidden', 'true');
+         }
+
+         e.stopPropagation();
+         return false;
+      }
+      case this.keys.enter:
+      case this.keys.space: {
+
+         var $parentUL = $item.parent();
+
+         if ($parentUL.is('.root-level')) {
+            // open the child menu if it is closed
+            $item.children('ul').first().show().attr('aria-hidden', 'false');
+            this.bChildOpen = true;
+         }
+         else {
+            // process the menu choice
+            this.processMenuChoice($item);
+
+            // remove hover styling
+            this.$allItems.removeClass('menu-hover menu-hover-checked');
+            this.$allItems.removeClass('menu-focus menu-focus-checked');
+
+            // close the menu
+            this.$id.find('ul').not('.root-level').hide().attr('aria-hidden','true');
+
+
+            // clear the active item
+            this.$activeItem = null;
+
+            // move focus to the text area
+            this.textarea.$id.focus();
+         }
+
+         e.stopPropagation();
+         return false;
+      }
+
+      case this.keys.left: {
+
+         if (this.vmenu == true && $itemUL.is('.root-level')) {
+            // If this is a vertical menu and the root-level is active, move
+            // to the previous item in the menu
+            this.$activeItem = this.moveUp($item); 
+         }
+         else {
+            this.$activeItem = this.moveToPrevious($item); 
+         }
+
+         this.$activeItem.focus();
+
+         e.stopPropagation();
+         return false;
+      }
+      case this.keys.right: {
+
+         if (this.vmenu == true && $itemUL.is('.root-level')) {
+            // If this is a vertical menu and the root-level is active, move
+            // to the next item in the menu
+            this.$activeItem = this.moveDown($item); 
+         }
+         else {
+            this.$activeItem = this.moveToNext($item);
+         }
+
+         this.$activeItem.focus();
+
+         e.stopPropagation();
+         return false;
+      }
+      case this.keys.up: {
+
+         if (this.vmenu == true && $itemUL.is('.root-level')) {
+            // If this is a vertical menu and the root-level is active, move
+            // to the previous root-level menu
+            this.$activeItem = this.moveToPrevious($item); 
+         }
+         else {
+            this.$activeItem = this.moveUp($item); 
+         }
+
+         this.$activeItem.focus();
+
+         e.stopPropagation();
+         return false;
+      }
+      case this.keys.down: {
+
+         if (this.vmenu == true && $itemUL.is('.root-level')) {
+            // If this is a vertical menu and the root-level is active, move
+            // to the next root-level menu
+            this.$activeItem = this.moveToNext($item); 
+         }
+         else {
+            this.$activeItem = this.moveDown($item); 
+         }
+
+         this.$activeItem.focus();
+
+         e.stopPropagation();
+         return false;
+      }
+   } // end switch
+
+   return true;
+
+} // end handleMenuKeyDown()
+
+//
+// Function moveToNext() is a member function to move to the next menu level.
+// This will be either the next root-level menu or the child of a menu parent. If
+// at the root level and the active item is the last in the menu, this function will loop
+// to the first menu item.
+//
+// If the menu is a horizontal menu, the first child element of the newly selected menu will
+// be selected
+//
+// @param($item object) $item is the active menu item
+//
+// @return (object) Returns the item to move to. Returns $item is no move is possible
+//
+menubar.prototype.moveToNext = function($item) {
+
+   var $itemUL = $item.parent(); // $item's containing menu 
+   var $menuItems = $itemUL.children('li'); // the items in the currently active menu
+   var menuNum = $menuItems.length; // the number of items in the active menu
+   var menuIndex = $menuItems.index($item); // the items index in its menu
+   var $newItem = null;
+   var $newItemUL = null;
+
+   if ($itemUL.is('.root-level')) {
+      // this is the root level move to next sibling. This will require closing
+      // the current child menu and opening the new one.
+ 
+      if (menuIndex < menuNum-1) { // not the last root menu
+         $newItem = $item.next();
+      }
+      else { // wrap to first item
+         $newItem = $menuItems.first();
+      }
+
+      // close the current child menu (if applicable)
+      if ($item.attr('aria-haspopup') == 'true') {
+
+         var $childMenu = $item.children('ul').first();
+
+         if ($childMenu.attr('aria-hidden') == 'false') {
+            // hide the child and update aria attributes accordingly
+            $childMenu.hide().attr('aria-hidden', 'true');
+            this.bChildOpen = true;
+         }
+      }
+
+      // remove the focus styling from the current menu
+      $item.removeClass('menu-focus');
+
+      // open the new child menu (if applicable)
+      if (($newItem.attr('aria-haspopup') == 'true') && (this.bChildOpen == true)) {
+
+         var $childMenu = $newItem.children('ul').first();
+
+         // open the child and update aria attributes accordingly
+         $childMenu.show().attr('aria-hidden', 'false');
+
+         /*
+          * Uncomment this section if the first item in the child menu should be
+          * automatically selected
+          *
+         if (!this.vmenu) {
+            // select the first item in the child menu
+            $newItem = $childMenu.children('li').first();
+         }
+         */
+
+      }
+   }
+   else {
+      // this is not the root level. If there is a child menu to be moved into, do that;
+      // otherwise, move to the next root-level menu if there is one
+      if ($item.attr('aria-haspopup') == 'true') {
+         
+         var $childMenu = $item.children('ul').first();
+
+         $newItem = $childMenu.children('li').first();
+
+         // show the child menu and update its aria attributes
+         $childMenu.show().attr('aria-hidden', 'false');
+         this.bChildOpen = true;
+      }
+      else {
+         // at deepest level, move to the next root-level menu
+ 
+         if (this.vmenu == true) {
+            // do nothing
+            return $item;
+         }
+
+         var $parentMenus = null;
+         var $rootItem = null;
+
+         // get list of all parent menus for item, up to the root level
+         $parentMenus = $item.parentsUntil('div').filter('ul').not('.root-level');
+
+         // hide the current menu and update its aria attributes accordingly
+         $parentMenus.hide().attr('aria-hidden', 'true');
+
+         // remove the focus styling from the active menu
+         $parentMenus.find('li').removeClass('menu-focus');
+         $parentMenus.last().parent().removeClass('menu-focus');
+
+         $rootItem = $parentMenus.last().parent(); // the containing root for the menu
+
+         menuIndex = this.$rootItems.index($rootItem);
+
+         // if this is not the last root menu item, move to the next one
+         if (menuIndex < this.$rootItems.length-1) {
+            $newItem = $rootItem.next();
+         }
+         else { // loop
+            $newItem = this.$rootItems.first();
+         }
+
+         if ($newItem.attr('aria-haspopup') == 'true') {
+            var $childMenu = $newItem.children('ul').first();
+
+            $newItem = $childMenu.children('li').first();
+
+            // show the child menu and update it's aria attributes
+            $childMenu.show().attr('aria-hidden', 'false');
+            this.bChildOpen = true;
+         }
+      }
+   }
+
+   return $newItem;
+}
+
+//
+// Function moveToPrevious() is a member function to move to the previous menu level.
+// This will be either the previous root-level menu or the child of a menu parent. If
+// at the root level and the active item is the first in the menu, this function will loop
+// to the last menu item.
+//
+// If the menu is a horizontal menu, the first child element of the newly selected menu will
+// be selected
+//
+// @param($item object) $item is the active menu item
+//
+// @return (object) Returns the item to move to. Returns $item is no move is possible
+//
+menubar.prototype.moveToPrevious = function($item) {
+
+   var $itemUL = $item.parent(); // $item's containing menu 
+   var $menuItems = $itemUL.children('li'); // the items in the currently active menu
+   var menuNum = $menuItems.length; // the number of items in the active menu
+   var menuIndex = $menuItems.index($item); // the items index in its menu
+   var $newItem = null;
+   var $newItemUL = null;
+
+   if ($itemUL.is('.root-level')) {
+      // this is the root level move to previous sibling. This will require closing
+      // the current child menu and opening the new one.
+ 
+      if (menuIndex > 0) { // not the first root menu
+         $newItem = $item.prev();
+      }
+      else { // wrap to last item
+         $newItem = $menuItems.last();
+      }
+
+      // close the current child menu (if applicable)
+      if ($item.attr('aria-haspopup') == 'true') {
+
+         var $childMenu = $item.children('ul').first();
+
+         if ($childMenu.attr('aria-hidden') == 'false') {
+            // hide the child and update aria attributes accordingly
+            $childMenu.hide().attr('aria-hidden', 'true');
+            this.bChildOpen = true;
+         }
+      }
+
+      // remove the focus styling from the current menu
+      $item.removeClass('menu-focus');
+
+      // open the new child menu (if applicable)
+      if (($newItem.attr('aria-haspopup') == 'true') && this.bChildOpen == true) {
+
+         var $childMenu = $newItem.children('ul').first();
+
+         // open the child and update aria attributes accordingly
+         $childMenu.show().attr('aria-hidden', 'false');
+
+         /*
+          * Uncomment this section if the first item in the child menu should be
+          * automatically selected
+          *
+         if (!this.vmenu) {
+            // select the first item in the child menu
+            $newItem = $childMenu.children('li').first();
+         }
+         */
+
+      }
+   }
+   else {
+      // this is not the root level. If there is a parent menu that is not the
+      // root menu, move up one level; otherwise, move to first item of the previous
+      // root menu.
+ 
+      var $parentLI = $itemUL.parent();
+      var $parentUL = $parentLI.parent();
+
+      var $parentMenus = null;
+      var $rootItem = null;
+
+      // if this is a vertical menu or is not the first child menu
+      // of the root-level menu, move up one level.
+      if (this.vmenu == true || !$parentUL.is('.root-level')) {
+
+         $newItem = $itemUL.parent();
+
+         // hide the active menu and update aria-hidden
+         $itemUL.hide().attr('aria-hidden', 'true');
+
+         // remove the focus highlight from the $item
+         $item.removeClass('menu-focus');
+
+         if (this.vmenu == true) {
+            // set a flag so the focus handler does't reopen the menu
+            this.bChildOpen = false;
+         }
+
+      }
+      else { // move to previous root-level menu
+
+         // hide the current menu and update the aria attributes accordingly
+         $itemUL.hide().attr('aria-hidden', 'true');
+
+         // remove the focus styling from the active menu
+         $item.removeClass('menu-focus');
+         $parentLI.removeClass('menu-focus');
+
+         menuIndex = this.$rootItems.index($parentLI);
+
+         if (menuIndex > 0) {
+            // move to the previous root-level menu
+            $newItem = $parentLI.prev();
+         }
+         else { // loop to last root-level menu
+            $newItem = this.$rootItems.last();
+         }
+
+         // add the focus styling to the new menu
+         $newItem.addClass('menu-focus');
+
+         if ($newItem.attr('aria-haspopup') == 'true') {
+            var $childMenu = $newItem.children('ul').first();
+
+            // show the child menu and update it's aria attributes
+            $childMenu.show().attr('aria-hidden', 'false');
+            this.bChildOpen = true;
+
+            $newItem = $childMenu.children('li').first();
+         }
+      }
+   }
+
+   return $newItem;
+}
+
+//
+// Function moveDown() is a member function to select the next item in a menu.
+// If the active item is the last in the menu, this function will loop to the
+// first menu item.
+//
+// @param($item object) $item is the active menu item
+//
+// @param(startChr char) [optional] startChr is the character to attempt to match against the beginning of the
+// menu item titles. If found, focus moves to the next menu item beginning with that character.
+//
+// @return (object) Returns the item to move to. Returns $item is no move is possible
+//
+menubar.prototype.moveDown = function($item, startChr) {
+
+   var $itemUL = $item.parent(); // $item's containing menu 
+   var $menuItems = $itemUL.children('li').not('.separator'); // the items in the currently active menu
+   var menuNum = $menuItems.length; // the number of items in the active menu
+   var menuIndex = $menuItems.index($item); // the items index in its menu
+   var $newItem = null;
+   var $newItemUL = null;
+
+   if ($itemUL.is('.root-level')) { // this is the root level menu
+
+      if ($item.attr('aria-haspopup') != 'true') {
+         // No child menu to move to
+         return $item;
+      }
+
+      // Move to the first item in the child menu
+      $newItemUL = $item.children('ul').first();
+      $newItem = $newItemUL.children('li').first();
+
+      // make sure the child menu is visible
+      $newItemUL.show().attr('aria-hidden', 'false');
+      this.bChildOpen = true;
+
+      return $newItem;
+   }
+
+   // if $item is not the last item in its menu, move to the next item. If startChr is specified, move
+   // to the next item with a title that begins with that character.
+   //
+   if (startChr) {
+      var bMatch = false;
+      var curNdx = menuIndex+1;
+
+      // check if the active item was the last one on the list
+      if (curNdx == menuNum) {
+         curNdx = 0;
+      }
+
+      // Iterate through the menu items (starting from the current item and wrapping) until a match is found
+      // or the loop returns to the current menu item 
+      while (curNdx != menuIndex)  {
+
+         var titleChr = $menuItems.eq(curNdx).html().charAt(0);
+
+         if (titleChr.toLowerCase() == startChr) {
+            bMatch = true;
+            break;
+         }
+
+         curNdx = curNdx+1;
+
+         if (curNdx == menuNum) {
+            // reached the end of the list, start again at the beginning
+            curNdx = 0;
+         }
+      }
+
+      if (bMatch == true) {
+         $newItem = $menuItems.eq(curNdx);
+
+         // remove the focus styling from the current item
+         $item.removeClass('menu-focus menu-focus-checked');
+
+         return $newItem
+      }
+      else {
+         return $item;
+      }
+   }
+   else {
+      if (menuIndex < menuNum-1) {
+         $newItem = $menuItems.eq(menuIndex+1);
+      }
+      else {
+         $newItem = $menuItems.first();
+      }
+   }
+
+   // remove the focus styling from the current item
+   $item.removeClass('menu-focus menu-focus-checked');
+
+   return $newItem;
+}
+
+//
+// Function moveUp() is a member function to select the previous item in a menu.
+// If the active item is the first in the menu, this function will loop to the
+// last menu item.
+//
+// @param($item object) $item is the active menu item
+//
+// @return (object) Returns the item to move to. Returns $item is no move is possible
+//
+menubar.prototype.moveUp = function($item) {
+
+   var $itemUL = $item.parent(); // $item's containing menu 
+   var $menuItems = $itemUL.children('li').not('.separator'); // the items in the currently active menu
+   var menuNum = $menuItems.length; // the number of items in the active menu
+   var menuIndex = $menuItems.index($item); // the items index in its menu
+   var $newItem = null;
+   var $newItemUL = null;
+
+   if ($itemUL.is('.root-level')) { // this is the root level menu
+
+      // nothing to do
+      return $item;
+   }
+
+   // if $item is not the first item in its menu, move to the previous item
+   if (menuIndex > 0) {
+
+      $newItem = $menuItems.eq(menuIndex-1);
+   }
+   else {
+      // loop to top of menu
+      $newItem = $menuItems.last();
+   }
+
+   // remove the focus styling from the current item
+   $item.removeClass('menu-focus menu-focus-checked');
+
+   return $newItem;
+}
+
+//
+// Function handleKeyPress() is a member function to process keydown events
+// for the menus.
+//
+// The Opera browser performs some window commands from the keypress event,
+// not keydown like Firefox, Safari, and IE. This event handler consumes
+// keypresses for relevant keys so that Opera behaves when the user is
+// manipulating the menu with the keyboard.
+//
+// @param($item object) $menu is the jquery object of the item firing the event
+//
+// @param(e object) e is the associated event object
+//
+// @return(boolean) Returns false if consuming; true if propagating
+//
+menubar.prototype.handleKeyPress = function($item, e) {
+
+   if (e.altKey || e.ctrlKey || e.shiftKey) {
+       // Modifier key pressed: Do not process
+       return true;
+   }
+
+   switch(e.keyCode) {
+      case this.keys.tab: {
+         return true;
+      }
+      case this.keys.esc:
+      case this.keys.enter:
+      case this.keys.space:
+      case this.keys.up:
+      case this.keys.down:
+      case this.keys.left:
+      case this.keys.right: {
+
+         e.stopPropagation();
+         return false;
+      }
+      default : {
+         var chr = String.fromCharCode(e.which);
+
+         this.$activeItem = this.moveDown($item, chr);
+         this.$activeItem.focus();
+
+         e.stopPropagation();
+         return false;
+      }
+
+   } // end switch
+
+   return true;
+
+} // end handleKeyPress()
+
+//
+// Function handleDocumentClick() is a member function to process click events on the document. Needed
+// to close an open menu if a user clicks outside the menu
+//
+// @param(e object) e is the associated event object
+//
+// @return(boolean) Returns true;
+//
+menubar.prototype.handleDocumentClick = function(e) {
+
+   // get a list of all child menus
+   var $childMenus = this.$id.find('ul').not('.root-level');
+
+   // hide the child menus
+   $childMenus.hide().attr('aria-hidden', 'true');
+
+   this.$allItems.removeClass('menu-focus menu-focus-checked');
+
+   this.$activeItem = null;
+
+   // allow the event to propagate
+   return true;
+
+} // end handleDocumentClick()
+
+//
+// Function processMenuChoice() is a member function to process the user's menu item
+// choice. Since the menu will close after this, highlight styling is simply removed.
+//
+// @param($item object) $item is the jquery object of the menu item firing the event
+//
+// @return N/A
+//
+menubar.prototype.processMenuChoice = function($item) {
+
+	// find the parent menu for this item
+	var menuName = $item.parent().attr('id');
+	var choice = $item.attr('id');
+
+	// call the appropriate textarea function
+	switch(menuName) {
+		case 'fontMenu': {
+			this.textarea.setFont(choice);
+
+			// update the aria-checked state of the menu items and apply
+			// appropriate styling
+			$item.attr('aria-checked', 'true').addClass('checked');
+			$item.siblings().attr('aria-checked', 'false').removeClass('checked');
+
+			break;
+		}
+		case 'styleMenu': {
+			this.textarea.setStyle(choice);
+
+			// reverse the aria-checked state and update styling
+			if ($item.attr('aria-checked') == 'true') {
+				$item.attr('aria-checked', 'false').removeClass('checked');
+			}
+			else {
+				$item.attr('aria-checked', 'true').addClass('checked');
+			}
+
+			break;
+		}
+		case 'justificationMenu': {
+			this.textarea.setAlignment(choice);
+
+			// update the aria-checked state of the menu items and apply
+			// appropriate styling
+			$item.attr('aria-checked', 'true').addClass('checked');
+			$item.siblings().attr('aria-checked', 'false').removeClass('checked');
+
+			break;
+		}
+		case 'sizeMenu': {
+			var $menuItems = $item.siblings().andSelf();
+			var $curItem;
+
+			this.textarea.setSize(choice);
+
+			////////////////////////
+			// update the aria-checked state by first setting all items to false
+			// and then setting the item that matches the currently selected font
+			// size.
+			
+			// set aria-checked to false and removed checked styling
+			$menuItems.attr('aria-checked', 'false').removeClass('checked');
+
+			// determine which menu item matches the current font size
+			$curItem = $menuItems.filter('[id=' + this.textarea.getSize() + ']');
+
+			// Set aria-checked for the matching item and apply the checked styling
+			$curItem.attr('aria-checked', 'true').addClass('checked');
+
+			break;
+		}
+	} // end switch
+
+} // end processMenuChoice()
+
+/////////////// end menu widget definition /////////////////////
+
+</script>
+</head>
+  
+<body>
+
+<div role="application">
+
+<ul id="mb1" class="menubar root-level" role="menubar" title="Styling Menu" aria-controls="st1">
+  <li id="mb1_menu1" class="menu-parent" role="menuitem" tabindex="0" aria-haspopup="true">
+    Font
+    <ul id="fontMenu" class="menu" role="menu" aria-hidden="true">
+      <li id="sans-serif"
+        class="menu-item checked"
+        role="menuitemradio"
+        tabindex="-1"
+        aria-controls="st1"
+        aria-checked="true">Sans-serif</li>
+      <li id="serif"
+        class="menu-item"
+        role="menuitemradio"
+        tabindex="-1"
+        aria-controls="st1"
+        aria-checked="false">Serif</li>
+      <li id="monospace"
+        class="menu-item"
+        role="menuitemradio"
+        tabindex="-1"
+        aria-controls="st1"
+        aria-checked="false">Monospace</li>
+      <li id="fantasy"
+        class="menu-item"
+        role="menuitemradio"
+        tabindex="-1"
+        aria-controls="st1"
+        aria-checked="false">Fantasy</li>
+    </ul>
+  </li>
+  <li id="mb1_menu2" class="menu-parent" role="menuitem" tabindex="-1" aria-haspopup="true">
+    Style
+    <ul id="styleMenu" class="menu" role="menu" aria-hidden="true">
+      <li id="italic"
+        class="menu-item"
+        role="menuitemcheckbox"
+        aria-controls="st1"
+        aria-checked="false"
+        tabindex="-1">Italics</li>
+      <li id="bold"
+        class="menu-item"
+        role="menuitemcheckbox"
+        aria-controls="st1"
+        aria-checked="false"
+        tabindex="-1">Bold</li>
+      <li id="underline"
+        class="menu-item"
+        role="menuitemcheckbox"
+        aria-controls="st1"
+        aria-checked="false"
+        tabindex="-1">Underlined</li>
+    </ul>
+  </li>
+  <li id="mb1_menu3" class="menu-parent" role="menuitem" tabindex="-1" aria-haspopup="true">
+    Justification
+    <ul id="justificationMenu" class="menu" role="menu" title="Justication" aria-hidden="true">
+      <li id="left"
+        class="menu-item checked"
+        role="menuitemradio"
+        tabindex="-1"
+        aria-controls="st1"
+        aria-checked="true">Left</li>
+      <li id="center"
+        class="menu-item"
+        role="menuitemradio"
+        tabindex="-1"
+        aria-controls="st1"
+        aria-checked="false">Centered</li>
+      <li id="right"
+        class="menu-item"
+        role="menuitemradio"
+        tabindex="-1"
+        aria-controls="st1"
+        aria-checked="false">Right</li>
+      <li id="justify"
+        class="menu-item"
+        role="menuitemradio"
+        tabindex="-1"
+        aria-controls="st1"
+        aria-checked="false">Justify</li>
+    </ul>
+  </li>
+  <li id="mb1_menu4" class="menu-parent" role="menuitem" tabindex="-1" aria-haspopup="true">
+    Size
+    <ul id="sizeMenu" class="menu" role="menu" title="Size" aria-hidden="true">
+      <li id="larger"
+        class="menu-item"
+        role="menuitem"
+        aria-controls="st1"
+        tabindex="-1">Larger</li>
+      <li id="smaller"
+        class="menu-item"
+        role="menuitem"
+        aria-controls="st1"
+        tabindex="-1">Smaller</li>
+      <li id="fs_separator"
+        class="menu-item separator"
+        role="separator"
+        tabindex="-1"></li>
+      <li id="x-small"
+        class="menu-item"
+        role="menuitemradio"
+        tabindex="-1"
+        aria-controls="st1"
+        aria-checked="false">X-Small</li>
+      <li id="small"
+        class="menu-item"
+        role="menuitemradio"
+        tabindex="-1"
+        aria-controls="st1"
+        aria-checked="false">Small</li>
+      <li id="medium"
+        class="menu-item checked"
+        role="menuitemradio"
+        tabindex="-1"
+        aria-controls="st1"
+        aria-checked="true">Medium</li>
+      <li id="large"
+        class="menu-item"
+        role="menuitemradio"
+        tabindex="-1"
+        aria-controls="st1"
+        aria-checked="false">Large</li>
+      <li id="x-large"
+        class="menu-item"
+        role="menuitemradio"
+        tabindex="-1"
+        aria-controls="st1"
+        aria-checked="false">X-Large</li>
+    </ul>
+  </li>
+</ul>
+
+<label for="st1" class="hidden">Text Sample 1</label>
+<textarea id="st1" name="st1">
+This is the a text area.
+</textarea>
+
+</div>
+
+</body>
+</html>
+
+