Difference between revisions of "ARIA Menu"

From Level Access Web Labs
Jump to navigation Jump to search
(Created page with "<html lang="en-US"> <head> <title>ARIA Menu Example</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <script src="http://test.cita.illinois.ed...")
 
 
(29 intermediate revisions by 5 users not shown)
Line 1: Line 1:
<html lang="en-US">
+
This example is not working correctly.
<head>
 
<title>ARIA Menu Example</title>
 
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
 
    <script src="http://test.cita.illinois.edu/aria/js/constants.js" type="text/javascript"></script>
 
    <script src="http://test.cita.illinois.edu/aria/js/jquery.js" type="text/javascript"></script>
 
<style type="text/css">
 
/* CSS Document */
 
#st1 {
 
  padding: .5em;
 
  border: 1px solid black;
 
  height: 400px;
 
  width: 70%;
 
  font-size: medium;
 
  font-family: sans-serif;
 
}
 
ul.menubar {
 
  margin: 0;
 
  padding: 0 .25em;
 
  list-style: none;
 
  border: 1px solid black;
 
  height: 1.85em;
 
  width: 20em;
 
  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;
 
  padding: 0;
 
  font-weight: normal;
 
  border: 1px solid black;
 
  background-color: #ccc;
 
  width: auto;
 
}
 
ul.menu li {
 
  float: none;
 
  display: block;
 
  white-space: nowrap;
 
  padding: 2px 1em;
 
  color: black;
 
}
 
  
li.separator {
+
<html lang="en">
  margin: 0;
+
  <head>
   margin-bottom: 4px !important;
+
   <title>
  height: 2px !important;
+
    ARIA menus
   border-bottom: 1px solid black;
+
   </title>
}
+
   <style type="text/css">
 
+
    #l1, #l2 {
li.checked {
+
       float:left;
  font-weight: bold;
+
       width:10em;
  background-image: url('images/dot.png');
+
       background-color:darkblue;
  background-repeat: no-repeat;
+
       color:white;
  background-position: 5px 10px;
+
       padding:.2em;
}
 
 
 
.hover {
 
  background-color: #700 !important;
 
  color: white !important;
 
}
 
 
 
.hover-checked {
 
  background-color: #700 !important;
 
  color: white !important;
 
  background-image: url('images/dot-selected.png') !important;
 
}
 
 
 
.focus {
 
  background-color: black;
 
  font-weight: bold;
 
  color: white !important;
 
}
 
 
 
li.focus-checked {
 
  background-color: black;
 
  font-weight: bold;
 
  color: white !important;
 
  background-image: url('images/dot-selected.png') !important;
 
}
 
 
 
/*
 
* Text area styles
 
*/
 
.italic {
 
  font-style: italic;
 
}
 
.bold {
 
  font-weight: bold;
 
}
 
.underline {
 
  text-decoration: underline;
 
}
 
   </style>
 
<script type="text/javascript">
 
var g_closetimer = undefined; // document timer object for menu close
 
var menuApp = undefined;
 
 
 
$(document).ready(function(event) {
 
 
 
  menuApp = new menubar("mb1");
 
 
 
 
 
}); // end document ready
 
 
 
//
 
// Function keyCodes() is a object which defines keycodes for the application
 
//
 
// @return N/A
 
//
 
function keyCodes() {
 
 
 
  // key code definitions
 
  this.tab  = 9;
 
  this.enter = 13;
 
  this.esc  = 27;
 
  this.space = 32;
 
  this.left  = 37;
 
  this.up    = 38;
 
  this.right = 39;
 
  this.down  = 40;
 
 
 
} // end keyCodes();
 
 
 
 
 
/////////////// 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 menubar widget definition /////////////////////
 
 
 
//
 
// Function menubar() is the constructor of a menubar widget to manipulate a text area.
 
// The widget will bind to the ul passed to it.
 
//
 
// As written, this widget will only handle a single level of menu.
 
//
 
// @param(id string) id is the HTML id of the ul to bind to
 
//
 
// @return N/A
 
//
 
function menubar(id) {
 
 
 
  // define widget properties
 
  this.$id = $('#' + id);
 
  this.$menus = this.$id.children('li'); // jQuery array of top level menus
 
  this.$items = this.$menus.find('li').not('.separator'); // jQuery array of menu items
 
 
 
  this.keys = new keyCodes();
 
  this.timeout = 100; // number of milliseconds to delay before closing a menu
 
 
 
  this.$openMenu = undefined; // current open menu object
 
 
 
  // create the textArea widget
 
  this.textarea = new textArea(this.$id.attr('aria-controls'));
 
 
 
  this.itemFocus = false; // set to true when focus moves from a menu to a menu item (IE fix)
 
 
 
  // do initial styling, etc.
 
  this.init();
 
 
 
  // bind event handlers
 
  this.bindHandlers();
 
};
 
 
 
//
 
// Function init() is a member function to perform initial processing of the widget, such as
 
// applying initial styling to menu items.
 
//
 
// @return N/A
 
//
 
menubar.prototype.init = function() {
 
 
 
  // add the checked class to visually show checked items
 
  this.$items.filter('[aria-checked=true]').addClass('checked');
 
 
 
} // end init()
 
 
 
//
 
// Function closeMenu() is a member function to close an open menu and modify its
 
// aria attributes accordingly. If a menu item has focus, focus is set on the
 
// menu itself
 
//
 
// @param($id object) $id is the jquery object of the menu to close
 
//
 
// @parem(setFocus boolean) setFocus is true if focus should be set on the menu; false if not
 
// @return N/A
 
//
 
menubar.prototype.closeMenu = function($id, setFocus) {
 
 
 
  var $subMenu = $id.children('ul');
 
 
 
  // unbind the mouse delegate handlers. Prevents conflicts during menu close animations.
 
  $subMenu.undelegate('li', 'mouseover');
 
  $subMenu.undelegate('li', 'mouseout');
 
  $subMenu.undelegate('li', 'click');
 
 
 
  if ($id) {
 
    var $menu = $id.children('ul');
 
 
 
    // remove the focus class from the listitems in the menu
 
    $menu.find('li').removeClass('focus focus-checked');
 
   
 
    // Set aria-hidden to true and hide the subMenu
 
    $menu.attr('aria-hidden', 'true').hide();
 
 
 
    if (setFocus == true) {
 
      // need to return focus to the menu to prevent a non-visible
 
      // item having focus
 
      $id.focus();
 
    }
 
  }
 
 
 
  // clear openMenu
 
  this.$openMenu = undefined;
 
 
 
} // end closeMenu()
 
 
 
//
 
// Function showMenu() is a member function to open a menu and modify its
 
// aria attributes accordingly.
 
//
 
// @param($menu object) $menu is the jquery object of the menu to open
 
//
 
// @return N/A
 
//
 
menubar.prototype.showMenu = function($menu) {
 
 
 
  var $subMenu = $menu.children('ul');
 
  var thisObj = this;
 
 
 
  // Bind mouse event delegates. Binding event handlers to the menu
 
  // items only when the menu is shown helps prevent conflicts during
 
  // menu close animations. Using delegates is much faster than
 
  // binding to each menu item.
 
 
 
  // bind a mouseover delegate
 
  $subMenu.delegate('li', 'mouseover', function(e) {
 
    return thisObj.handleItemMouseOver($(this), e);
 
  });
 
 
 
  // bind a mouseout delegate
 
  $subMenu.delegate('li', 'mouseout', function(e) {
 
    return thisObj.handleItemMouseOut($(this), e);
 
  });
 
 
 
  // bind a click delegate
 
  $subMenu.delegate('li', 'click', function(e) {
 
    return thisObj.handleItemClick($(this), e);
 
  });
 
 
 
  // set aria-hidden to false and show the subMenu
 
  $subMenu.attr('aria-hidden', 'false').show();
 
 
 
  // bind the mouseover event delegate
 
  this.$openMenu = $menu;
 
 
 
} // end showMenu()
 
 
 
//
 
// Function findParentMenu() is a member function to find the parent menu
 
// of a menu item.
 
//
 
// @param($item object) $item is the jquery object of the item to find parent of
 
//
 
// @return(object) Returns the jQuery object of the parent menu;
 
//
 
menubar.prototype.findParentMenu = function($item) {
 
 
 
  var $menu = undefined;
 
 
 
  this.$menus.each(function() {
 
    if ($(this).find('li').index($item) != -1) {
 
 
 
      // this is the parent menu, store it
 
      $menu = $(this);
 
 
 
      // break out of the loop
 
      return false;
 
 
     }
 
     }
  });
+
     li {
 
+
      list-style-type:none !important;
  return $menu;
 
 
 
} // end findParentMenu()
 
 
 
//
 
// Function bindHandlers() is a member function to bind event handlers for the widget.
 
//
 
// @return N/A
 
//
 
menubar.prototype.bindHandlers = function() {
 
 
 
  var thisObj = this;
 
 
 
  ///////// bind top level menu event handlers //////////
 
 
 
  // bind a mouseover handler
 
  this.$menus.mouseover(function(e) {
 
     return thisObj.handleMenuMouseOver($(this), e);
 
  });
 
 
 
  // bind a mouseout handler
 
  this.$menus.mouseout(function(e) {
 
    return thisObj.handleMenuMouseOut($(this), e);
 
  });
 
 
 
  // bind a click handler
 
  this.$menus.click(function(e) {
 
    return thisObj.handleMenuClick($(this), e);
 
  });
 
 
 
  // bind a keydown handler
 
  this.$menus.keydown(function(e) {
 
    return thisObj.handleMenuKeyDown($(this), e);
 
  });
 
 
 
  // bind a keypress handler
 
  this.$menus.keypress(function(e) {
 
    return thisObj.handleMenuKeyPress($(this), e);
 
  });
 
 
 
  // bind a focus handler
 
  this.$menus.focus(function(e) {
 
    return thisObj.handleMenuFocus($(this), e);
 
  });
 
 
 
  // bind a blur handler
 
  this.$menus.blur(function(e) {
 
    return thisObj.handleMenuBlur($(this), e);
 
  });
 
 
 
  ///////// bind submenu event handlers //////////
 
 
 
 
 
  // bind a keydown handler
 
  this.$items.keydown(function(e) {
 
    return thisObj.handleItemKeyDown($(this), e);
 
  });
 
 
 
  // bind a keypress handler
 
  this.$items.keypress(function(e) {
 
    return thisObj.handleItemKeyPress($(this), e);
 
  });
 
 
 
  // bind a focus handler
 
  this.$items.focus(function(e) {
 
    return thisObj.handleItemFocus($(this), e);
 
  });
 
 
 
  ///////// bind document handlers //////////
 
 
 
  // bind a click handler to close the menu when user clicks elsewhere
 
  $(document).click(function(e) {
 
    return thisObj.handleDocumentClick(e);
 
  });
 
 
 
} // end bindHandlers()
 
 
 
//
 
// Function handleMenuMouseOver() is a member function to process mouseover
 
// events for the top menus.
 
//
 
// @param($menu object) $menu is the jquery object of the menu firing the event
 
//
 
// @param(e object) e is the associated event object
 
//
 
// @return(boolean) Returns false;
 
//
 
menubar.prototype.handleMenuMouseOver = function($menu, e) {
 
 
 
  // cancel the close timer if it is set
 
  if (g_closetimer) {
 
    window.clearTimeout(g_closetimer);
 
    g_closetimer = undefined;
 
  }
 
 
 
  // if there is an open menu, remove the highlight style from menu items
 
  // and close it
 
  if (this.$openMenu) {
 
 
 
    // if the open menu is not the one being processed, hide it
 
    if ($menu.get(0) != this.$openMenu.get(0)) {
 
      this.closeMenu(this.$openMenu, true);
 
 
     }
 
     }
 
+
     #label1 {
     // open the current menu
 
    this.showMenu($menu);
 
   
 
    // remove styling from all menus
 
    this.removeStyling(this.$menus);
 
 
 
    // if the current menu was not given focus, set focus.
 
    if ($menu.hasClass('.focus') == false) {
 
      $menu.focus();
 
 
     }
 
     }
 
+
     #u1, #u2 {
  }
+
      display:none;
  else {
 
    // Add hover style
 
    $menu.addClass('hover');
 
  }
 
 
 
  e.stopPropagation();
 
  return false;
 
 
 
} // end handleMenuMouseOver()
 
 
 
//
 
// Function handleMenuMouseOut() is a member function to process mouseout
 
// events for the top menus.
 
//
 
// @param($menu object) $menu is the jquery object of the menu firing the event
 
//
 
// @param(e object) e is the associated event object
 
//
 
// @return(boolean) Returns false;
 
//
 
menubar.prototype.handleMenuMouseOut = function($menu, e) {
 
 
 
  // set the close timer to call closeMenu
 
  g_closetimer = window.setTimeout(function() { menuApp.closeMenu($menu, false); }, this.timeout);
 
 
 
  // Remover hover style
 
  $menu.removeClass('hover');
 
 
 
  e.stopPropagation();
 
  return false;
 
 
 
} // end handleMenuMouseOut()
 
 
 
//
 
// Function handleMenuClick() is a member function to process click events
 
// for the top menus.
 
//
 
// @param($menu object) $menu is the jquery object of the menu firing the event
 
//
 
// @param(e object) e is the associated event object
 
//
 
// @return(boolean) Returns false;
 
//
 
menubar.prototype.handleMenuClick = function($menu, e) {
 
 
 
  // If a menu is open, close it
 
  if (this.$openMenu) {
 
    this.closeMenu(this.$openMenu, true);
 
  }
 
  else {
 
    this.showMenu($menu);
 
  }
 
 
 
  // remove styling from other menus
 
  this.removeStyling(this.$menus);
 
 
 
  // set focus on this menu
 
  $menu.focus();
 
 
 
  e.stopPropagation();
 
  return false;
 
 
 
} // end handleMenuClick()
 
 
 
//
 
// Function handleMenuFocus() is a member function to process focus events
 
// for the top menus.
 
//
 
// @param($menu object) $menu is the jquery object of the menu firing the event
 
//
 
// @param(e object) e is the associated event object
 
//
 
// @return(boolean) Returns true;
 
//
 
menubar.prototype.handleMenuFocus = function($menu, e) {
 
 
 
  $menu.addClass('focus');
 
 
 
  return true;
 
 
 
} // end handleMenuFocus()
 
 
 
//
 
// Function handleMenuBlur() is a member function to process blur events
 
// for the top menus.
 
//
 
// @param($menu object) $menu is the jquery object of the menu firing the event
 
//
 
// @param(e object) e is the associated event object
 
//
 
// @return(boolean) Returns true;
 
//
 
menubar.prototype.handleMenuBlur = function($menu, e) {
 
 
 
  if (this.itemFocus == false) {
 
    // remove the focus and hover classes
 
     this.removeStyling($menu);
 
  }
 
  else {
 
    this.itemFocus = false;
 
  }
 
 
 
  return true;
 
 
 
} // end handleMenuBlur()
 
 
 
//
 
// Function handleMenuKeyDown() is a member function to process keydown events
 
// for the top menus.
 
//
 
// @param($menu object) $menu is the jquery object of the menu firing the event
 
//
 
// @param(e object) e is the associated event object
 
//
 
// @return(boolean) Returns false if consuming; true if propagating
 
//
 
menubar.prototype.handleMenuKeyDown = function($menu, e) {
 
 
 
  if (e.altKey || e.ctrlKey || e.shiftKey) {
 
        // Modifier key pressed: Do not process
 
        return true;
 
 
     }
 
     }
 
+
    .focus {
  switch(e.keyCode) {
+
    outline: dotted;
    case this.keys.tab: {
 
      // close the open menu (if applicable)
 
      this.closeMenu(this.$openMenu, false);
 
 
 
      // allow tab event to propagate;
 
      return true;
 
 
     }
 
     }
    case this.keys.esc: {
+
  </style>
      // close the open menu (if applicable)
+
  <script type="text/javascript">
       this.closeMenu(this.$openMenu, true);
+
    function showHide(evt) {
 +
       var e = window.event ? window.event : evt;
  
      e.stopPropagation();
+
            obj = e.target;
      return false;
+
            toggle(obj,1);
 
     }
 
     }
    case this.keys.enter:
 
    case this.keys.space:
 
    case this.keys.up:
 
    case this.keys.down: {
 
 
      // open the menu
 
      this.showMenu($menu);
 
 
      // set focus on the first menu item
 
      $menu.find('li:first').focus();
 
  
      // set itemFocus flag to prevent blur from processing (IE fix).
+
        function visible(obj) {
      this.itemFocus = true;
+
            if (window.getComputedStyle(obj,null).display == "none")
   
+
                return false;
      e.stopPropagation();
+
            else
      return false;
+
              return true;
    }
+
        }
    case this.keys.left: {
 
      // select the previous menu (rotate to
 
      // last menu if this is the first one).
 
  
      var curNdx = this.$menus.index($menu);
+
        // set force to 1 to force only that one to be displayed
      var $prev;
+
    function toggle(obj, force) {
     
 
      // find the menu to move to
 
      if (curNdx > 0) {
 
        $prev = this.$menus.eq(curNdx - 1);
 
      }
 
      else {
 
        $prev = this.$menus.last();
 
      }
 
  
      // open the new menu
+
                if (obj.tagName == "SPAN")
      this.showMenu($prev);
+
                  obj = obj.parentNode;
  
      // set focus on the menu's first item
+
            if (obj.id == "l1" || obj.id == "l2") {
      $prev.find('li:first').focus();
+
                obj = obj.children[1]
 +
          }
  
      // close this menu if it is open
+
          if (obj.tagName == "UL") {
      this.closeMenu($menu, false);
+
                if (force) {
 +
                        var o = document.getElementsByClassName('menu')
 +
                        for (var i=0; i < o.length; i++) {
  
      // Remove the focus styling
+
                          o[i].style.display = "none";
      this.removeStyling($menu);
+
                        }
 
+
                  obj.style.display = "block";
      e.stopPropagation();
+
            }
      return false;
+
                else if (!visible(obj)) {
    }
+
                  obj.style.display = "block";
 
+
                  obj.setAttribute("aria-expanded","true");
    case this.keys.right: {
+
                  obj.querySelector("li").focus();
      // select the next menu (rotate to
+
                }
      // first menu if this is the last one).
+
                else
 
+
                    obj.style.display = "none";
      var curNdx = this.$menus.index($menu);
+
          }
      var $next;
+
          else if (obj.tagName == "LI") {
     
+
            obj.onclick();
      if (curNdx < this.$menus.length - 1) {
+
          }
        $next = this.$menus.eq(curNdx + 1);
 
      }
 
      else {
 
        $next = this.$menus.first();
 
      }
 
 
 
      // open the new menu
 
      this.showMenu($next);
 
 
 
      // set focus on the menu's first item
 
      $next.find('li:first').focus();
 
 
 
      // close this menu if it is open
 
      this.closeMenu($menu, false);
 
 
 
      // Remove the focus styling
 
      this.removeStyling($menu);
 
 
 
      e.stopPropagation();
 
      return false;
 
    }
 
 
 
  } // end switch
 
 
 
  return true;
 
 
 
} // end handleMenuKeyDown()
 
 
 
//
 
// Function handleMenuKeyPress() is a member function to process keydown events
 
// for the top 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($menu object) $menu is the jquery object of the menu firing the event
 
//
 
// @param(e object) e is the associated event object
 
//
 
// @return(boolean) Returns false if consuming; true if propagating
 
//
 
menubar.prototype.handleMenuKeyPress = function($menu, e) {
 
 
 
  if (e.altKey || e.ctrlKey || e.shiftKey) {
 
      // Modifier key pressed: Do not process
 
      return true;
 
  }
 
 
 
  switch(e.keyCode) {
 
    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;
 
 
     }
 
     }
  
  } // end switch
+
    function drawFocus() {
 +
      removeFocus();
  
  return true;
+
      var id = document.getElementById('m1').getAttribute('aria-activedescendant');
 +
      var obj = document.getElementById(id);
  
} // end handleMenuKeyPress()
+
      if (!visible(obj)) {
 
+
            toggle(obj,0);
//
 
// Function handleItemMouseOver() is a member function to process mouseover
 
// events for the menu items.
 
//
 
// @param($item object) $item is the jquery object of the menu item firing the event
 
//
 
// @param(e object) e is the associated event object
 
//
 
// @return(boolean) Returns false;
 
//
 
menubar.prototype.handleItemMouseOver = function($item, e) {
 
 
 
  // cancel the close timer if it is set
 
  if (g_closetimer) {
 
    window.clearTimeout(g_closetimer);
 
    g_closetimer = undefined;
 
  }
 
 
 
  // add the hover class to the current item
 
  if ($item.attr('aria-checked') == 'true') {
 
    $item.addClass('hover-checked');
 
  }
 
  else {
 
    $item.addClass('hover');
 
  }
 
 
 
  e.stopPropagation();
 
  return false;
 
 
 
} // end handleItemMouseOver()
 
 
 
//
 
// Function handleItemMouseOut() is a member function to process mouseout
 
// events for the menu items.
 
//
 
// @param($item object) $item is the jquery object of the menu item firing the event
 
//
 
// @param(e object) e is the associated event object
 
//
 
// @return(boolean) Returns false;
 
//
 
menubar.prototype.handleItemMouseOut = function($item, e) {
 
 
 
  // find the parent menu for this item
 
  var $menu = this.findParentMenu($item);
 
 
 
  // set the close timer to call closeMenu
 
  g_closetimer = window.setTimeout(function() { menuApp.closeMenu($menu, true); }, this.timeout);
 
 
 
  // remove the hover class from the menu item
 
  if ($item.attr('aria-checked') == 'true') {
 
    $item.removeClass('hover-checked');
 
  }
 
  else {
 
    $item.removeClass('hover');
 
  }
 
 
 
  e.stopPropagation();
 
  return false;
 
 
 
} // end handleItemMouseOut()
 
 
 
//
 
// Function handleItemClick() is a member function to process click events
 
// for the menu items.
 
//
 
// @param($item object) $item is the jquery object of the menu item firing the event
 
//
 
// @param(e object) e is the associated event object
 
//
 
// @return(boolean) Returns false;
 
//
 
menubar.prototype.handleItemClick = function($item, e) {
 
 
 
  var $menu = this.findParentMenu($item);
 
  var thisObj = this;
 
 
 
  // remove the focus style from the item
 
  this.removeStyling($item);
 
 
 
  // proces the click
 
  this.processMenuChoice($item);
 
 
 
  // close the menu
 
  this.closeMenu($menu, false);
 
 
 
  // remove the focus styling from the menu
 
  this.removeStyling($menu);
 
 
 
  // set focus on the text area
 
  this.textarea.$id.focus();
 
 
 
  e.stopPropagation();
 
  return false;
 
 
 
} // end handleItemClick()
 
 
 
//
 
// Function handleItemFocus() is a member function to process focus events
 
// for the menu items.
 
//
 
// @param($item object) $item is the jquery object of the menu item firing the event
 
//
 
// @param(e object) e is the associated event object
 
//
 
// @return(boolean) Returns true;
 
//
 
menubar.prototype.handleItemFocus = function($item, e) {
 
 
 
  // apply the focus class
 
  if ($item.attr('aria-checked') == 'true') {
 
    $item.addClass('focus-checked');
 
  }
 
  else {
 
    $item.addClass('focus');
 
  }
 
 
 
  return true;
 
 
 
} // end handleItemFocus()
 
 
 
//
 
// Function removeStyling() is a member function to remove the focus styling
 
// for the menu items. This is necessary because browsers do not reliably fire the blur
 
// event for non-input elements.
 
//
 
// @param($item object) $item is the jquery object of the item to manipulate
 
//
 
// @return N/A
 
//
 
menubar.prototype.removeStyling = function($item) {
 
 
 
  // remove the focus class
 
  if ($item.attr('aria-checked') == 'true') {
 
    $item.removeClass('focus-checked hover-checked');
 
  }
 
  else {
 
    $item.removeClass('focus hover');
 
  }
 
 
 
} // end removeStyling()
 
 
 
//
 
// Function handleItemKeyDown() is a member function to process keydown events
 
// for the menu items.
 
//
 
// @param($item object) $menu is the jquery object of the menu item firing the event
 
//
 
// @param(e object) e is the associated event object
 
//
 
// @return(boolean) Returns false if consuming; true if propagating
 
//
 
menubar.prototype.handleItemKeyDown = function($item, e) {
 
 
 
  var $menu = this.findParentMenu($item);
 
 
 
  if (e.altKey || e.ctrlKey) {
 
        // Modifier key pressed: Do not process
 
        return true;
 
  }
 
  if (e.shiftKey) {
 
    if (e.keyCode == this.keys.tab) {
 
      // do nothing
 
      e.stopPropagation();
 
      return false;
 
    }
 
 
 
    // do not process
 
    return true;
 
  }
 
 
 
  switch(e.keyCode) {
 
    case this.keys.tab: {
 
 
 
      // close the open menu
 
      this.closeMenu($menu, false);
 
 
 
      // remove the focus style
 
      this.removeStyling($menu);
 
 
 
      // allow tab event to propagate;
 
      return true;
 
    }
 
    case this.keys.esc: {
 
 
 
      // close the open menu (if applicable)
 
      this.closeMenu($menu, true);
 
 
 
      e.stopPropagation();
 
      return false;
 
    }
 
    case this.keys.enter:
 
    case this.keys.space: {
 
 
 
      // remove the focus style from the item
 
      this.removeStyling($item);
 
 
 
      // process the choice
 
      this.processMenuChoice($item);
 
 
 
      // close the menu
 
      this.closeMenu($menu, false);
 
 
 
      // remove the focus styling from the menu
 
      this.removeStyling($menu);
 
 
 
      // set focus on the text area
 
      this.textarea.$id.focus();
 
 
 
      e.stopPropagation();
 
      return false;
 
    }
 
    case this.keys.left: {
 
      // select the previous menu (rotate to
 
      // last menu if this is the first one).
 
 
 
      var curNdx = this.$menus.index($menu);
 
      var $prev;
 
     
 
      // find the menu to move to
 
      if (curNdx > 0) {
 
        $prev = this.$menus.eq(curNdx - 1);
 
 
       }
 
       }
       else {
+
       if (!visible(obj.parentNode)) {
        $prev = this.$menus.last();
+
            toggle(obj.parentNode,0);
 
       }
 
       }
 
+
       if (document.getElementById(id).className)
       // open the new menu
+
        document.getElementById(id).className += " focus";
      this.showMenu($prev);
+
       else
 
+
         document.getElementById(id).className = "focus";
      // set focus on the menu's first item
 
      $prev.find('li:first').focus();
 
 
 
      // close this menu
 
      this.closeMenu($menu, false);
 
 
 
      // remove the focus style
 
      this.removeStyling($menu);
 
 
 
      e.stopPropagation();
 
      return false;
 
    }
 
    case this.keys.right: {
 
      // select the next menu (rotate to
 
      // first menu if this is the last one).
 
 
 
      var curNdx = this.$menus.index($menu);
 
      var $next;
 
     
 
      if (curNdx < this.$menus.length - 1) {
 
        $next = this.$menus.eq(curNdx + 1);
 
      }
 
      else {
 
        $next = this.$menus.first();
 
      }
 
 
 
      // open the new menu
 
      this.showMenu($next);
 
 
 
      // set focus on the menu's first item
 
      $next.find('li:first').focus();
 
 
 
      // close this menu
 
      this.closeMenu($menu, false);
 
 
 
      // remove the focus style
 
      this.removeStyling($menu);
 
 
 
      e.stopPropagation();
 
      return false;
 
    }
 
    case this.keys.up: {
 
      // select the previous menu item (rotate to
 
      // last item if this is the first one).
 
 
 
      var $listItems = $item.siblings().andSelf().not('.separator');
 
      var curNdx = $listItems.index($item);
 
      var $prev;
 
 
 
      // find the new item to select
 
      if (curNdx > 0) {
 
        $prev = $listItems.eq(curNdx - 1);
 
      }
 
       else {
 
         $prev = $listItems.last();
 
      }
 
 
 
      // remove highlighting from the menu item
 
      this.removeStyling($item);
 
 
 
      // set focus on the new item;
 
      $prev.focus();
 
 
 
      e.stopPropagation();
 
      return false;
 
    }
 
    case this.keys.down: {
 
      // select the next menu item (rotate to
 
      // first item if this is the first one).
 
 
 
      var $listItems = $item.siblings().andSelf().not('.separator');
 
      var curNdx = $listItems.index($item);
 
      var $next;
 
 
 
      // find the new item to select
 
      if (curNdx < $listItems.length - 1) {
 
        $next = $listItems.eq(curNdx + 1);
 
      }
 
      else {
 
        $next = $listItems.first();
 
      }
 
 
 
      // remove highlighting from the menu item
 
      this.removeStyling($item);
 
 
 
      // set focus on the new item;
 
      $next.focus();
 
 
 
      e.stopPropagation();
 
      return false;
 
    }
 
 
 
  } // end switch
 
 
 
  return true;
 
 
 
} // end handleItemKeyDown()
 
 
 
//
 
// Function handleItemKeyPress() is a member function to process keydown events
 
// for the menu items.
 
//
 
// 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) $item is the jquery object of the menu item firing the event
 
//
 
// @param(e object) e is the associated event object
 
//
 
// @return(boolean) Returns false if consuming; true if propagating
 
//
 
menubar.prototype.handleItemKeyPress = function($item, e) {
 
 
 
  if (e.altKey || e.ctrlKey || e.shiftKey) {
 
      // Modifier key pressed: Do not process
 
      return true;
 
  }
 
 
 
  switch(e.keyCode) {
 
    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;
 
 
     }
 
     }
  
  } // end switch
+
    function removeFocus() {
 +
            var o = document.getElementsByClassName('focus')
  
  return true;
+
            for(var i = 0; i < o.length; i++) {
 +
                o[i].className = o[i].className.replace( /(?:^|\s)focus(?!\S)/g,'');
 +
            }
  
} // end handleItemKeyPress()
 
 
//
 
// 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 menubar
 
//
 
// @param(e object) e is the associated event object
 
//
 
// @return(boolean) Returns true;
 
//
 
menubar.prototype.handleDocumentClick = function(e) {
 
 
  var $menu = this.$openMenu;
 
 
  if (this.$openMenu) {
 
    // set the close timer to call closeMenu
 
    g_closetimer = window.setTimeout(function() { menuApp.closeMenu($menu, false); }, this.timeout);
 
 
    // Remover styling
 
    this.removeStyling(this.$openMenu);
 
 
  }
 
 
  // 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 $menu = this.findParentMenu($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': {
+
     function keystroke(evt) {
       this.textarea.setStyle(choice);
+
       var e = window.event ? window.event : evt;
 +
            var activeID = document.getElementById('m1').getAttribute('aria-activedescendant');
  
      // reverse the aria-checked state and update styling
+
            if (e.which == 13) { // enter
      if ($item.attr('aria-checked') == 'true') {
+
                toggle(document.getElementById(activeID),0);
        $item.attr('aria-checked', 'false').removeClass('checked');
+
            }
      }
+
            else if (e.which == 40) { // down arrow
      else {
+
          document.getElementById('m1').setAttribute('aria-activedescendant',document.getElementById(activeID).getAttribute('data-next'));
        $item.attr('aria-checked', 'true').addClass('checked');
+
          drawFocus();
      }
+
            }
 
+
            else if (e.which == 38) { // up arrow
      break;
+
          document.getElementById('m1').setAttribute('aria-activedescendant',document.getElementById(activeID).getAttribute('data-previous'));
    }
+
          drawFocus();
    case 'justificationMenu': {
+
            }
      this.textarea.setAlignment(choice);
+
            else if (e.which == 39) {            // right arrow
 
+
                    if (activeID.indexOf("l1") > -1) {
      // update the aria-checked state of the menu items and apply
+
              toggle(document.getElementById('l2'),1);
      // appropriate styling
+
            document.getElementById('m1').setAttribute('aria-activedescendant',"l2");
      $item.attr('aria-checked', 'true').addClass('checked');
+
          }
      $item.siblings().attr('aria-checked', 'false').removeClass('checked');
+
          else {
 
+
              toggle(document.getElementById('l1'),1);
      break;
+
            document.getElementById('m1').setAttribute('aria-activedescendant',"l1");
    }
+
          }
    case 'sizeMenu': {
+
          drawFocus();
      var $menuItems = $item.siblings().andSelf();
+
            }
      var $curItem;
+
            else if (e.which == 37) {            // left arrow
 
+
                    if (activeID.indexOf("l1") > -1) {
      this.textarea.setSize(choice);
+
              toggle(document.getElementById('l2'),1);
 
+
            document.getElementById('m1').setAttribute('aria-activedescendant',"l2");
      ////////////////////////
+
          }
      // update the aria-checked state by first setting all items to false
+
          else {
      // and then setting the item that matches the currently selected font
+
                toggle(document.getElementById('l1'),1);
      // size.
+
            document.getElementById('m1').setAttribute('aria-activedescendant',"l1");
     
+
          }
      // set aria-checked to false and removed checked styling
+
          drawFocus();
      $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 menubar widget definition /////////////////////
 
 
   </script>
 
   </script>
</head>
+
  </head>
 
<body>
 
<body>
<div role="application">
 
  
<ul id="mb1" class="menubar" role="menubar" title="Styling Menu" aria-controls="st1">
+
<h2>Menubar with menu items that contain menus with other menu items</h2>
  <li id="mb1_menu1" role="menuitem" tabindex="0" aria-haspopup="true">
+
<div>
    Font
+
<ul tabindex="0" onclick="showHide(event);" onkeyup="keystroke(event);" id="m1" onfocus="drawFocus();" onblur="removeFocus();" role="menubar" aria-activedescendant="l1" >
    <ul id="fontMenu" class="menu" role="menu">
+
  <li id="l1" role="menuitem" aria-haspopup="true" aria-labelledby="label1" data-next="l1a" data-previous="l1c"><span id="label1" aria-expanded="false" >File &#9660;</span>
      <li id="sans-serif"
+
    <ul role="menu" id="u1" class="menu" >
        role="menuitemradio"
+
      <li tabindex="-1" id="l1a" data-next="l1b" data-previous="l1" onclick="alert('Saving file');" role="menuitem">Save</li>
        tabindex="-1"
+
      <li tabindex="-1" id="l1b" data-next="l1c" data-previous="l1a" onclick="alert('Saving file as ...');" role="menuitem">Save as ...</li>
        aria-controls="st1"
+
      <li tabindex="-1" id="l1c" data-next="l1" data-previous="l1b" onclick="alert('Printing file');" role="menuitem">Print</li>
        aria-checked="true">
+
    </ul>
          Sans-serif
+
  </li>
      </li>
+
  <li id="l2" tabindex="-1" role="menuitem" aria-haspopup="true" aria-labeleldby="label2" data-next="l2a" data-previous="l2c"><span id="label2" aria-expanded="false">Review</span>
      <li id="serif"
+
    <ul role="menu" id="u2" class="menu" >
        role="menuitemradio"
+
      <li id="l2a" data-next="l2b" data-previous="l2" tabindex="-1" onclick="alert('Checking spelling');" role="menuitem">Spelling</li>
        tabindex="-1"
+
      <li id="l2b" data-next="l2c" data-previous="l2a" tabindex="-1" onclick="alert('Opening thesaurus');" role="menuitem">Thesaurus</li>
        aria-controls="st1"
+
      <li id="l2c" data-next="l2" data-previous="l2b" tabindex="-1" onclick="alert('Checking Accessibility');" role="menuitem">Accessibility</li>
        aria-checked="false">
+
    </ul>
          Serif
+
  </li>
      </li>
+
</ul>
      <li id="monospace"
 
        role="menuitemradio"
 
        tabindex="-1"
 
        aria-controls="st1"
 
        aria-checked="false">
 
          Monospace
 
      </li>
 
      <li id="fantasy"
 
        role="menuitemradio"
 
        tabindex="-1"
 
        aria-controls="st1"
 
        aria-checked="false">
 
          Fantasy
 
      </li>
 
    </ul>
 
  </li>
 
  <li id="mb1_menu2" role="menuitem" tabindex="-1" aria-haspopup="true">
 
    Style
 
    <ul id="styleMenu" class="menu" role="menu">
 
      <li id="italic"
 
        role="menuitemcheckbox"
 
        aria-controls="st1"
 
  aria-checked="false"
 
        tabindex="-1">
 
          Italics
 
      </li>
 
      <li id="bold"
 
        role="menuitemcheckbox"
 
        aria-controls="st1"
 
  aria-checked="false"
 
        tabindex="-1">
 
          Bold
 
      </li>
 
      <li id="underline"
 
        role="menuitemcheckbox"
 
        aria-controls="st1"
 
  aria-checked="false"
 
        tabindex="-1">
 
          Underlined
 
      </li>
 
    </ul>
 
  </li>
 
  <li id="mb1_menu3" role="menuitem" tabindex="-1" aria-haspopup="true">
 
    Justification
 
    <ul id="justificationMenu" class="menu" role="menu" title="Justication">
 
      <li id="left"
 
        role="menuitemradio"
 
        tabindex="-1"
 
        aria-controls="st1"
 
        aria-checked="true">
 
          Left
 
      </li>
 
      <li id="center"
 
        role="menuitemradio"
 
        tabindex="-1"
 
        aria-controls="st1"
 
        aria-checked="false">
 
          Centered
 
      </li>
 
      <li id="right"
 
        role="menuitemradio"
 
        tabindex="-1"
 
        aria-controls="st1"
 
        aria-checked="false">
 
          Right
 
      </li>
 
      <li id="justify"
 
        role="menuitemradio"
 
        tabindex="-1"
 
        aria-controls="st1"
 
        aria-checked="false">
 
          Justify
 
      </li>
 
    </ul>
 
  </li>
 
  <li id="mb1_menu4" role="menuitem" tabindex="-1" aria-haspopup="true">
 
    Size
 
    <ul id="sizeMenu" class="menu" role="menu" title="Size">
 
      <li id="larger"
 
        role="menuitem"
 
        aria-controls="st1"
 
        tabindex="-1">
 
          Larger
 
      </li>
 
      <li id="smaller"
 
        role="menuitem"
 
        aria-controls="st1"
 
        tabindex="-1">
 
          Smaller
 
      </li>
 
      <li id="fs_separator"
 
        class="separator"
 
        role="separator"
 
        tabindex="-1">
 
      </li>
 
      <li id="x-small"
 
        role="menuitemradio"
 
        tabindex="-1"
 
        aria-controls="st1"
 
        aria-checked="false">
 
          X-Small
 
      </li>
 
      <li id="small"
 
        role="menuitemradio"
 
        tabindex="-1"
 
        aria-controls="st1"
 
        aria-checked="false">
 
          Small
 
      </li>
 
      <li id="medium"
 
        role="menuitemradio"
 
        tabindex="-1"
 
        aria-controls="st1"
 
        aria-checked="true">
 
          Medium
 
      </li>
 
      <li id="large"
 
        role="menuitemradio"
 
        tabindex="-1"
 
        aria-controls="st1"
 
        aria-checked="false">
 
          Large
 
      </li>
 
      <li id="x-large"
 
        role="menuitemradio"
 
        tabindex="-1"
 
        aria-controls="st1"
 
        aria-checked="false">
 
          X-Large
 
      </li>
 
    </ul>
 
  </li>
 
</ul>
 
  
<textarea id="st1" name="st1">
+
</div>
Four score and seven years ago our fathers brought forth on this continent a new nation, conceived in Liberty, and dedicated to the proposition that all men are created equal.
 
  
Now we are engaged in a great civil war, testing whether that nation, or any nation, so conceived and so dedicated, can long endure. We are met on a great battle-field of that war. We have come to dedicate a portion of that field, as a final resting place for those who here gave their lives that that nation might live. It is altogether fitting and proper that we should do this.
+
<div style="clear:both; padding-top:4em;">&nbsp;</div>
 
+
</html>
But, in a larger sense, we can not dedicate, we can not consecrate, we can not hallow, this ground. The brave men, living and dead, who struggled here, have consecrated it, far above our poor power to add or detract. The world will little note, nor long remember what we say here, but it can never forget what they did here. It is for us the living, rather, to be dedicated here to the unfinished work which they who fought here have thus far so nobly advanced. It is rather for us to be here dedicated to the great task remaining before us, that from these honored dead we take increased devotion to that cause for which they gave the last full measure of devotion, that we here highly resolve that these dead shall not have died in vain, that this nation, under God, shall have a new birth of freedom, and that government of the people, by the people, for the people, shall not perish from the earth.
 
</textarea>
 
  
<p><a href="http://en.wikipedia.org/wiki/Gettysburg,_Pennsylvania">More information on Gettysburg Address</a></p>
+
[[category:ARIA]]
</div>
 
</body>
 
</html>
 
[[Category:ARIA]]
 

Latest revision as of 15:09, 7 March 2018

This example is not working correctly.

ARIA menus

Menubar with menu items that contain menus with other menu items