673 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
			
		
		
	
	
			673 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
| <html>
 | |
| <head>
 | |
| <style type="text/css">
 | |
| ul.tree { 
 | |
|   width: 10em; 
 | |
| } 
 | |
| ul.tree, ul.tree ul { 
 | |
|   list-style: none; 
 | |
|   margin: 0; 
 | |
|   padding-left: 20px; 
 | |
|   font-weight: normal; 
 | |
|   background-color: white; 
 | |
|   color: black; 
 | |
| } 
 | |
| 
 | |
| ul.tree li { 
 | |
|   margin-left: 17px; 
 | |
| } 
 | |
| 
 | |
| ul.tree li.groupHeader { 
 | |
|   font-weight: bold; 
 | |
|   margin-left: 0px; 
 | |
| } 
 | |
| 
 | |
| img.headerImg { 
 | |
|   margin-right: 5px; 
 | |
| } 
 | |
| 
 | |
| li.focus { 
 | |
|   color: white; 
 | |
|   background: black; 
 | |
| } 
 | |
| </style>
 | |
| <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
 | |
| <script type="text/javascript">
 | |
| var g_focusHandled = false; // set to true if focus is handled 
 | |
| 
 | |
| // 
 | |
| // Function resetFocusFlag() is a callback to reset the focusHandled flag. This is 
 | |
| // called by the timer set in the treeview focus handler 
 | |
| // 
 | |
| function resetFocusFlag() { 
 | |
|   g_focusHandled = false; 
 | |
| } 
 | |
| 
 | |
| $(document).ready(function() { 
 | |
| 
 | |
|   var treeviewApp = new treeview('tree1'); 
 | |
| 
 | |
| }); // end ready 
 | |
| 
 | |
| // 
 | |
| // Function keyCodes() is an object to define keycodes for the application 
 | |
| // 
 | |
| function keyCodes() { 
 | |
| 
 | |
|   this.enter      = 13; 
 | |
|   this.space      = 32; 
 | |
| 
 | |
|   this.pageup     = 33; 
 | |
|   this.pagedown   = 34; 
 | |
|   this.end        = 35; 
 | |
|   this.home       = 36; 
 | |
|   this.left       = 37; 
 | |
|   this.up         = 38; 
 | |
|   this.right      = 39; 
 | |
|   this.down       = 40; 
 | |
|   this.asterisk   = 106; 
 | |
| 
 | |
| } // end keyCodes() 
 | |
| 
 | |
| // 
 | |
| // Function treeview() is a class constructor for a treeview widget. The widget binds to an 
 | |
| // unordered list. The top-level <ul> must have role='tree'. All list items must have role='treeitem'. 
 | |
| // 
 | |
| // Tree groups must be embedded lists within the listitem that heads the group. the top <ul> of a group 
 | |
| // must have role='group'. aria-expanded is used to indicate whether a group is expanded or collapsed. This 
 | |
| // property must be set on the listitem the encapsulates the group. 
 | |
| // 
 | |
| // @param (treeID string) treeID is the html id of the top-level <ul> of the list to bind the widget to 
 | |
| // 
 | |
| // @return N/A 
 | |
| // 
 | |
| function treeview(treeID) { 
 | |
| 
 | |
|   // define the object properties 
 | |
|   this.$id = $('#' + treeID); 
 | |
|   this.$listitems = this.$id.find('li'); // an array of list items 
 | |
|   this.$groups = undefined; // an array of the listitems that function as group headers 
 | |
|   this.$visibleItems = undefined; // an array of currently visible listitems (including headers) 
 | |
|   this.focusHandled = false; // Set to true when a focus event is handled and reset after a small delay 
 | |
| 
 | |
|   this.keys = new keyCodes(); 
 | |
| 
 | |
|   // initialize the treeview 
 | |
|   this.init(); 
 | |
| 
 | |
|   // bind event handlers 
 | |
|   this.bindHandlers(); 
 | |
| 
 | |
| } // end treeview() constructor 
 | |
| 
 | |
| // 
 | |
| // Function init() is a member function to initialize the treeview widget. It traverses the tree, identifying 
 | |
| // which listitems are headers for groups and applying initial collapsed are expanded styling 
 | |
| // 
 | |
| // @return N/A 
 | |
| // 
 | |
| treeview.prototype.init = function() { 
 | |
| 
 | |
|   var thisObj = this; 
 | |
| 
 | |
|   // iterate through the tree and apply the groupHeader class and styling to the group headers 
 | |
|   this.$id.find('li').each (function(index) { 
 | |
| 
 | |
|     var $group = $(this).children('ul'); 
 | |
| 
 | |
|     if ($group.length > 0) { 
 | |
|       // this listitem is a group header 
 | |
| 
 | |
|       // Apply the group header styling 
 | |
|       $(this).addClass('groupHeader'); 
 | |
| 
 | |
|       // insert the header image. Note: this method allows the widget to degrade gracefully 
 | |
|       // if javascript is disabled or there is some other error. 
 | |
|       $(this).prepend('<img class="headerImg" src="treeExpanded.gif" />'); 
 | |
| 
 | |
|       // If the aria-expanded is false, hide the group and display the collapsed state image 
 | |
|       if ($(this).attr('aria-expanded') == 'false') { 
 | |
|         $group.hide(); 
 | |
|         $(this).find('img').attr('src', 'treeContracted.gif'); 
 | |
|       } 
 | |
|     } 
 | |
|   }); 
 | |
| 
 | |
|   // create the group and initial visible item array 
 | |
|   this.$groups = $('li.groupHeader'); 
 | |
|   this.$visibleItems = this.$id.find('li:visible'); 
 | |
| 
 | |
| } // end init() 
 | |
| 
 | |
| // 
 | |
| // Function expandGroup() is a member function to expand a collapsed group 
 | |
| // 
 | |
| // @param($id object) $id is the jquery id of the group header of the group to expand 
 | |
| // 
 | |
| // @param(focus boolean) focus is true if the group header has focus, false otherwise 
 | |
| // 
 | |
| // @return N/A 
 | |
| // 
 | |
| treeview.prototype.expandGroup = function($id, focus) { 
 | |
| 
 | |
|   var $group = $id.children('ul'); 
 | |
| 
 | |
|   // expand the group 
 | |
|   $group.show(); 
 | |
| 
 | |
|   $id.attr('aria-expanded', 'true'); 
 | |
| 
 | |
|   if (focus == true) { 
 | |
|     $id.children('img').attr('src', 'treeExpandedFocus.gif'); 
 | |
|   } 
 | |
|   else { 
 | |
|     $id.children('img').attr('src', 'treeExpanded.gif'); 
 | |
|   } 
 | |
| 
 | |
|   // refresh the list of visible items 
 | |
|   this.$visibleItems = this.$id.find('li:visible'); 
 | |
| 
 | |
| } // end expandGroup() 
 | |
| 
 | |
| // 
 | |
| // Function collapseGroup() is a member function to collapse an expanded group 
 | |
| // 
 | |
| // @param($id object) $id is the jquery id of the group header of the group to collapse 
 | |
| // 
 | |
| // @param(focus boolean) focus is true if the group header has focus, false otherwise 
 | |
| // 
 | |
| // @return N/A 
 | |
| // 
 | |
| treeview.prototype.collapseGroup = function($id, focus) { 
 | |
| 
 | |
|   var $group = $id.children('ul'); 
 | |
| 
 | |
|   // collapse the group 
 | |
|   $group.hide(); 
 | |
| 
 | |
|   $id.attr('aria-expanded', 'false'); 
 | |
| 
 | |
|   if (focus == true) { 
 | |
|     $id.children('img').attr('src', 'treeContractedFocus.gif'); 
 | |
|   } 
 | |
|   else { 
 | |
|     $id.children('img').attr('src', 'treeContracted.gif'); 
 | |
|   } 
 | |
| 
 | |
|   // refresh the list of visible items 
 | |
|   this.$visibleItems = this.$id.find('li:visible'); 
 | |
| 
 | |
| } // end collapseGroup() 
 | |
| 
 | |
| // 
 | |
| // Function toggleGroup() is a member function to toggle the display state of a group 
 | |
| // 
 | |
| // @param($id object) $id is the jquery id of the group header of the group to toggle 
 | |
| // 
 | |
| // @param(focus boolean) focus is true if the group header has focus, false otherwise 
 | |
| // 
 | |
| // @return N/A 
 | |
| // 
 | |
| treeview.prototype.toggleGroup = function($id, focus) { 
 | |
| 
 | |
|   var $group = $id.children('ul'); 
 | |
| 
 | |
|   if ($id.attr('aria-expanded') == 'true') { 
 | |
|     // collapse the group 
 | |
|     this.collapseGroup($id, focus); 
 | |
|   } 
 | |
|   else { 
 | |
|     // expand the group 
 | |
|     this.expandGroup($id, focus); 
 | |
|   } 
 | |
| 
 | |
| } // end toggleGroup() 
 | |
| 
 | |
| // 
 | |
| // Function bindHandlers() is a member function to bind event handlers to the listitems 
 | |
| // 
 | |
| // return N/A 
 | |
| // 
 | |
| treeview.prototype.bindHandlers = function() { 
 | |
| 
 | |
|   var thisObj = this; 
 | |
| 
 | |
|   // bind a dblclick handler to the group headers 
 | |
|   this.$groups.dblclick(function(e) { 
 | |
|     return thisObj.handleDblClick($(this), e); 
 | |
|   }); 
 | |
| 
 | |
|   // bind a click handler 
 | |
|   this.$listitems.click(function(e) { 
 | |
|     return thisObj.handleClick($(this), e); 
 | |
|   }); 
 | |
| 
 | |
|   // bind a keydown handler 
 | |
|   this.$listitems.keydown(function(e) { 
 | |
|     return thisObj.handleKeyDown($(this), e); 
 | |
|   }); 
 | |
| 
 | |
|   // bind a keypress handler 
 | |
|   this.$listitems.keypress(function(e) { 
 | |
|     return thisObj.handleKeyPress($(this), e); 
 | |
|   }); 
 | |
| 
 | |
|   // bind a focus handler 
 | |
|   this.$listitems.focus(function(e) { 
 | |
|     return thisObj.handleFocus($(this), e); 
 | |
|   }); 
 | |
| 
 | |
|   // bind a blur handler 
 | |
|   this.$listitems.blur(function(e) { 
 | |
|     return thisObj.handleBlur($(this), e); 
 | |
|   }); 
 | |
| 
 | |
| } // end bindHandlers() 
 | |
| 
 | |
| // 
 | |
| // Function doHighlight() is a member function to remove the highlighting from 
 | |
| // other treeview items and apply it to the passed element 
 | |
| // 
 | |
| // @param ($id object) $id is the jQuery object of the element to highlight 
 | |
| // 
 | |
| // @param (isHeader boolean) isHeader is true if $id points to a group header 
 | |
| // 
 | |
| // @return N/A 
 | |
| // 
 | |
| treeview.prototype.doHighlight = function($id, isHeader) { 
 | |
| 
 | |
|   // remove the focus highlighting from the treeview items 
 | |
|   // and remove them from the tab order. 
 | |
|   this.$listitems.removeClass('focus').attr('tabindex', '-1'); 
 | |
| 
 | |
|   // remove the focus image from group headers 
 | |
|   this.$groups.each(function() { 
 | |
|     // add the focus image 
 | |
|     if ($(this).attr('aria-expanded') == 'true') { 
 | |
|       $(this).children('img').attr('src', 'treeExpanded.gif'); 
 | |
|     } 
 | |
|     else { 
 | |
|       $(this).children('img').attr('src', 'treeContracted.gif'); 
 | |
|     } 
 | |
|   }); 
 | |
| 
 | |
|   if (isHeader == true) { 
 | |
|     // add the focus image 
 | |
|     if ($id.attr('aria-expanded') == 'true') { 
 | |
|       $id.children('img').attr('src', 'treeExpandedFocus.gif'); 
 | |
|     } 
 | |
|     else { 
 | |
|       $id.children('img').attr('src', 'treeContractedFocus.gif'); 
 | |
|     } 
 | |
|   } 
 | |
| 
 | |
| 
 | |
|   // apply the focus highlighting and place the element in the tab order 
 | |
|   $id.addClass('focus').attr('tabindex', '0'); 
 | |
| 
 | |
| } // end doHighlight() 
 | |
| 
 | |
| // 
 | |
| // Function handleKeyDown() is a member function to process keydown events for the treeview items 
 | |
| // 
 | |
| // @param ($id object) $id is the jQuery id of the group header firing event 
 | |
| // 
 | |
| // @param (e object) e is the associated event object 
 | |
| // 
 | |
| // @return (boolean) returns false if consuming event; true if not 
 | |
| // 
 | |
| treeview.prototype.handleKeyDown = function($id, e) { 
 | |
| 
 | |
|   var curNdx = this.$visibleItems.index($id); 
 | |
|   var isHeader = false; 
 | |
| 
 | |
|   // determine if this is a group header 
 | |
|   if (this.$groups.index($prev) != -1) { 
 | |
|     isHeader = true; 
 | |
|   } 
 | |
| 
 | |
|   if (e.altKey || e.ctrlKey || e.shiftKey) { 
 | |
|     // do nothing 
 | |
|     return true; 
 | |
|   } 
 | |
| 
 | |
|   switch (e.keyCode) { 
 | |
|     case this.keys.home: { 
 | |
|       this.$groups.first().focus(); 
 | |
| 
 | |
|       e.stopPropagation(); 
 | |
|       return false; 
 | |
|     } 
 | |
|     case this.keys.end: { 
 | |
|       this.$visibleItems.last().focus(); 
 | |
| 
 | |
|       e.stopPropagation(); 
 | |
|       return false; 
 | |
|     } 
 | |
|     case this.keys.enter: { 
 | |
| 
 | |
|       if (isHeader == false) { 
 | |
|         // do nothing 
 | |
|         return true; 
 | |
|       } 
 | |
| 
 | |
|       this.toggleGroup($id, true); 
 | |
| 
 | |
|       e.stopPropagation(); 
 | |
|       return false; 
 | |
|     } 
 | |
|     case this.keys.left: { 
 | |
|        
 | |
|       if (isHeader == false) { 
 | |
|         // do nothing 
 | |
|         return true; 
 | |
|       } 
 | |
| 
 | |
|       if ($id.attr('aria-expanded') == 'true') { 
 | |
|         this.collapseGroup($id, true); 
 | |
|       } 
 | |
|       else { 
 | |
|         // move to previous group header 
 | |
|         var prevNdx = this.$groups.index($id) - 1; 
 | |
| 
 | |
|         if (prevNdx >= 0) { 
 | |
|           var $prev = this.$groups.eq(prevNdx); 
 | |
|           var parentFound = false; 
 | |
| 
 | |
|           while (parentFound == false) { 
 | |
|             if ($prev.find('#' + $id.attr('id')).length > 0) { 
 | |
|               parentFound = true; 
 | |
|               $prev.focus(); 
 | |
|               break; 
 | |
|             } 
 | |
|             else { 
 | |
|               // decrement prevNdx to reference the previous 
 | |
|               // group header in the $groups array 
 | |
|               prevNdx--; 
 | |
| 
 | |
|               $prev = this.$groups.eq(prevNdx); 
 | |
| 
 | |
|               if (prevNdx < 0) { 
 | |
|                 // no parent group header 
 | |
|                 break; 
 | |
|               } 
 | |
|             } 
 | |
| 
 | |
|           } // end while 
 | |
|         } 
 | |
|       } 
 | |
| 
 | |
|       e.stopPropagation(); 
 | |
|       return false; 
 | |
|     } 
 | |
|     case this.keys.right: { 
 | |
|        
 | |
|       if (isHeader == false) { 
 | |
|         // do nothing 
 | |
|         return true; 
 | |
|       } 
 | |
| 
 | |
|       if ($id.attr('aria-expanded') == 'false') { 
 | |
|         this.expandGroup($id, true); 
 | |
|       } 
 | |
| 
 | |
|       e.stopPropagation(); 
 | |
|       return false; 
 | |
|     } 
 | |
|     case this.keys.up: { 
 | |
| 
 | |
|       if (curNdx > 0) { 
 | |
|         var $prev = this.$visibleItems.eq(curNdx - 1); 
 | |
| 
 | |
|         $prev.focus(); 
 | |
|       } 
 | |
| 
 | |
|       e.stopPropagation(); 
 | |
|       return false; 
 | |
|     } 
 | |
|     case this.keys.down: { 
 | |
| 
 | |
|       if (curNdx < this.$visibleItems.length - 1) { 
 | |
|         var $next = this.$visibleItems.eq(curNdx + 1); 
 | |
| 
 | |
|         $next.focus(); 
 | |
|       } 
 | |
|       e.stopPropagation(); 
 | |
|       return false; 
 | |
|     } 
 | |
|     case this.keys.asterisk: { 
 | |
|       // expand all groups 
 | |
| 
 | |
|       var thisObj = this; 
 | |
| 
 | |
|       this.$groups.each(function() { 
 | |
|         thisObj.expandGroup($(this), false); 
 | |
|       }); 
 | |
| 
 | |
|       e.stopPropagation(); 
 | |
|       return false; 
 | |
|     } 
 | |
|   } 
 | |
| 
 | |
|   return true; 
 | |
| 
 | |
| } // end handleKeyDown 
 | |
| 
 | |
| // 
 | |
| // Function handleKeyPress() is a member function to process keypress events for the treeview items 
 | |
| // This function is needed for browsers, such as Opera, that perform window manipulation on kepress events 
 | |
| // rather than keydown. The function simply consumes the event. 
 | |
| // 
 | |
| // @param ($id object) $id is the jQuery id of the group header firing event 
 | |
| // 
 | |
| // @param (e object) e is the associated event object 
 | |
| // 
 | |
| // @return (boolean) returns false if consuming event; true if not 
 | |
| // 
 | |
| treeview.prototype.handleKeyPress = function($id, e) { 
 | |
| 
 | |
|   if (e.altKey || e.ctrlKey || e.shiftKey) { 
 | |
|     // do nothing 
 | |
|     return true; 
 | |
|   } 
 | |
| 
 | |
|   switch (e.keyCode) { 
 | |
|     case this.keys.enter: 
 | |
|     case this.keys.home: 
 | |
|     case this.keys.end: 
 | |
|     case this.keys.left: 
 | |
|     case this.keys.right: 
 | |
|     case this.keys.up: 
 | |
|     case this.keys.down: { 
 | |
|       e.stopPropagation(); 
 | |
|       return false; 
 | |
|     } 
 | |
|   } 
 | |
| 
 | |
|   return true; 
 | |
| 
 | |
| } // end handleKeyPress 
 | |
| 
 | |
| // 
 | |
| // Function handleDblClick() is a member function to process double-click events for group headers. 
 | |
| // Double-click expands or collapses a group. 
 | |
| // 
 | |
| // @param ($id object) $id is the jQuery id of the group header firing event 
 | |
| // 
 | |
| // @param (e object) e is the associated event object 
 | |
| // 
 | |
| // @return (boolean) returns false if consuming event; true if not 
 | |
| // 
 | |
| treeview.prototype.handleDblClick = function($id, e) { 
 | |
| 
 | |
|   if (e.altKey || e.ctrlKey || e.shiftKey) { 
 | |
|     // do nothing 
 | |
|     return true; 
 | |
|   } 
 | |
| 
 | |
|   // apply the focus highlighting 
 | |
|   this.doHighlight($id, true); 
 | |
| 
 | |
|   // expand or collapse the group 
 | |
|   this.toggleGroup($id, true); 
 | |
| 
 | |
|   e.stopPropagation(); 
 | |
|   return false; 
 | |
| 
 | |
| } // end handleDblClick 
 | |
| 
 | |
| // 
 | |
| // Function handleClick() is a member function to process click events. 
 | |
| // 
 | |
| // @param ($id object) $id is the jQuery id of the group header firing event 
 | |
| // 
 | |
| // @param (e object) e is the associated event object 
 | |
| // 
 | |
| // @return (boolean) returns false if consuming event; true if not 
 | |
| // 
 | |
| treeview.prototype.handleClick = function($id, e) { 
 | |
| 
 | |
|   if (e.altKey || e.ctrlKey || e.shiftKey) { 
 | |
|     // do nothing 
 | |
|     return true; 
 | |
|   } 
 | |
| 
 | |
|   if (this.$groups.index($id) == -1) { 
 | |
|     // this is a list item 
 | |
| 
 | |
|     // apply the focus highlighting 
 | |
|     this.doHighlight($id, false); 
 | |
|   } 
 | |
|   else { 
 | |
|     // this is a group header 
 | |
| 
 | |
|     // apply the focus highlighting 
 | |
|     this.doHighlight($id, true); 
 | |
|   } 
 | |
| 
 | |
|   e.stopPropagation(); 
 | |
|   return false; 
 | |
| 
 | |
| } // end handleClick 
 | |
| 
 | |
| // 
 | |
| // Function handleFocus() is a member function to process focus events. 
 | |
| // 
 | |
| // @param ($id object) $id is the jQuery id of the group header firing event 
 | |
| // 
 | |
| // @param (e object) e is the associated event object 
 | |
| // 
 | |
| // @return (boolean) returns true 
 | |
| // 
 | |
| treeview.prototype.handleFocus = function($id, e) { 
 | |
| 
 | |
|   // only process the event if the focusHandled flag is false 
 | |
|   if (g_focusHandled == false) { 
 | |
| 
 | |
|     // prevent encapsulating group headers from responding to 
 | |
|     // the focus event. 
 | |
|     g_focusHandled = true; 
 | |
|    
 | |
|     if (this.$groups.index($id) == -1) { 
 | |
|       this.doHighlight($id, false); 
 | |
|     } 
 | |
|     else { 
 | |
|       // this is a group header 
 | |
|       this.doHighlight($id, true); 
 | |
|     } 
 | |
| 
 | |
|     window.setTimeout(resetFocusFlag, 10); 
 | |
|   } 
 | |
| 
 | |
|   return true; 
 | |
| 
 | |
| } // end handleFocus 
 | |
| 
 | |
| // 
 | |
| // Function handleBlur() is a member function to process blur events. 
 | |
| // 
 | |
| // @param ($id object) $id is the jQuery id of the group header firing event 
 | |
| // 
 | |
| // @param (e object) e is the associated event object 
 | |
| // 
 | |
| // @return (boolean) returns true 
 | |
| // 
 | |
| treeview.prototype.handleBlur = function($id, e) { 
 | |
| 
 | |
|   if (this.$groups.index($id) != -1) { 
 | |
|     // this is a group header 
 | |
| 
 | |
|     // remove the focus image 
 | |
|     if ($id.attr('aria-expanded') == 'true') { 
 | |
|       $id.children('img').attr('src', 'treeExpanded.gif'); 
 | |
|     } 
 | |
|     else { 
 | |
|       $id.children('img').attr('src', 'treeContracted.gif'); 
 | |
|     } 
 | |
|   } 
 | |
| 
 | |
|   // remove the focus highlighting 
 | |
|   $id.removeClass('focus'); 
 | |
| 
 | |
|   return true; 
 | |
| 
 | |
| } // end handleBlur 
 | |
| </script>
 | |
| </head> 
 | |
| <body>
 | |
| <div role="application"> 
 | |
| <h2 id="label_1">Foods</h2> 
 | |
| <ul id="tree1" class="tree" role="tree" aria-labelledby="label_1"> 
 | |
|   <li id="fruits" role="treeitem" tabindex="0" aria-expanded="true">Fruits 
 | |
|     <ul role="group"> 
 | |
|       <li id="oranges" role="treeitem" tabindex="-1">Oranges</li> 
 | |
|       <li id="pinapples" role="treeitem" tabindex="-1">Pineapples</li> 
 | |
|       <li id="apples" role="treeitem" tabindex="-1" aria-expanded="false">Apples 
 | |
|         <ul role="group"> 
 | |
|           <li id="macintosh" role="treeitem" tabindex="-1">Macintosh</li> 
 | |
|           <li id="granny_smith" role="treeitem" tabindex="-1" aria-expanded="false">Granny Smith 
 | |
|             <ul role="group"> 
 | |
|               <li id="Washington" role="treeitem" tabindex="-1">Washington State</li> 
 | |
|               <li id="Michigan" role="treeitem" tabindex="-1">Michigan</li> 
 | |
|               <li id="New_York" role="treeitem" tabindex="-1">New York</li> 
 | |
|             </ul> 
 | |
|           </li> 
 | |
|           <li id="fuji" role="treeitem" tabindex="-1">Fuji</li> 
 | |
|         </ul> 
 | |
|       </li> 
 | |
|       <li id="bananas" role="treeitem" tabindex="-1">Bananas</li>     
 | |
|       <li id="pears" role="treeitem" tabindex="-1">Pears</li>     
 | |
|     </ul> 
 | |
|   </li> 
 | |
|   <li id="vegetables" role="treeitem" tabindex="-1" aria-expanded="true">Vegetables 
 | |
|     <ul role="group"> 
 | |
|       <li id="broccoli" role="treeitem" tabindex="-1">Broccoli</li> 
 | |
|       <li id="carrots" role="treeitem" tabindex="-1">Carrots</li> 
 | |
|       <li id="lettuce" role="treeitem" tabindex="-1" aria-expanded="false">Lettuce 
 | |
|       <ul role="group"> 
 | |
|           <li id="romaine" role="treeitem" tabindex="-1">Romaine</li> 
 | |
|           <li id="iceberg" role="treeitem" tabindex="-1">Iceberg</li> 
 | |
|           <li id="butterhead" role="treeitem" tabindex="-1">Butterhead</li> 
 | |
|       </ul> 
 | |
|       </li> 
 | |
|       <li id="spinach" role="treeitem" tabindex="-1">Spinach</li>     
 | |
|       <li id="squash" role="treeitem" tabindex="-1" aria-expanded="true">Squash 
 | |
|         <ul role="group" > 
 | |
|           <li id="acorn" role="treeitem" tabindex="-1">Acorn</li> 
 | |
|           <li id="ambercup" role="treeitem" tabindex="-1">Ambercup</li> 
 | |
|           <li id="autumn_cup" role="treeitem" tabindex="-1">Autumn Cup</li> 
 | |
|           <li id="hubbard" role="treeitem" tabindex="-1">Hubbard</li> 
 | |
|           <li id="kobacha" role="treeitem" tabindex="-1">Kabocha</li> 
 | |
|           <li id="butternut" role="treeitem" tabindex="-1">Butternut</li> 
 | |
|           <li id="spaghetti" role="treeitem" tabindex="-1">Spaghetti</li> 
 | |
|           <li id="sweet_dumpling" role="treeitem" tabindex="-1">Sweet Dumpling</li> 
 | |
|           <li id="turban" role="treeitem" tabindex="-1">Turban</li> 
 | |
|         </ul> 
 | |
|       </li> 
 | |
|     </ul> 
 | |
|   </li> 
 | |
| </ul> 
 | |
| </div> 
 | |
| </body>
 | |
| </html>
 |