Test Start
Animal, Mineral, or Vegetable
Animals
Cats
Dogs
Small Breeds
Medium Breeds
Large Breeds
Minerals
Gold
Vegetables
Test End
Rule References
| Rule | Pass IDs | Fail IDs |
|---|---|---|
| Rule 84 |
|
none |
| Rule 85 |
|
none |
| Rule 86 |
|
none |
| Rule 87 |
|
none |
| Rule 88 |
|
none |
| Rule 89 |
|
none |
| Rule 92 |
|
none |
| Rule 93 |
|
none |
| Rule 94 |
|
none |
| Rule 95 |
|
none |
| Rule 97 |
|
none |
| Rule 98 |
|
none |
Calculations
No calculations for test 140
Test Description
- This test implements a simple tooltip widget using aria-owns
Keyboard shortcuts (based on recommended shortcuts specified by the DHTML Style Guide Working Group):
* Up: Select the previous visible tree item.
* Down: Select next visible tree item.
* Left: Collapse the currently selected parent node if it is expanded. Move to the previous parent node (if possible) when the current parent node is collapsed.
* Right: Expand the currently selected parent node and move to the first child list item.
* Enter: Toggle the expanded or collapsed state of the selected parent node.
* Home: Select the root parent node of the tree.
* End: Select the last visible node of the tree.
* Tab: Navigate away from tree.
* * (asterisk on the numpad): Expand all group nodes.
* Double-clicking on a parent node will toggle its expanded or collapsed state.
Test Markup
- ARIA 1.0: [aria-expanded]
- ARIA 1.0: [aria-hidden]
- ARIA 1.0: [aria-labelledby]
- ARIA 1.0: [role="application"]
- ARIA 1.0: [role="group"]
- ARIA 1.0: [role="tree"]
- ARIA 1.0: [role="treeitem"]
User Agent Implementation
No user agent implementation information.
HTML Source Code
<div id="application" role="application">
<h2 id="label_1">Animal, Mineral, or Vegetable</h2>
<div id="tree1" class="tree root-level" role="tree" aria-labelledby="label_1" tabindex="-1">
<div id="animals" class="tree-parent" role="treeitem" aria-owns="animalGroup" aria-expanded="true" tabindex="0">
<img class="parentImg" role="treeitem" src="http://www.oaa-acessibility.org/media/testsuite/images/expanded.gif" alt="Group expanded"/>
<span>Animals</span>
</div>
<div id="animalGroup" class="group" role="group">
<div id="birds" class="tree-item" role="treeitem" tabindex="-1">Birds</div>
<div id="cats" class="tree-parent" role="treeitem" aria-owns="catGroup" aria-expanded="false" tabindex="-1">
<img class="parentImg" role="treeitem" tabindex="-1" src="http://www.oaa-acessibility.org/media/testsuite/images/contracted.gif" alt="Group collapsed"/>
<span>Cats</span>
</div>
<div id="catGroup" class="group" role="group">
<div id="siamese" class="tree-item" role="treeitem" tabindex="-1">Siamese</div>
<div id="tabby" class="tree-item" role="treeitem" tabindex="-1">Tabby</div>
</div>
<div id="dogs" class="tree-parent" role="treeitem" aria-owns="dogGroup" aria-expanded="true" tabindex="-1">
<img class="parentImg" role="treeitem" tabindex="-1" src="http://www.oaa-acessibility.org/media/testsuite/images/expanded.gif" alt="Group expanded"/>
<span>Dogs</span>
</div>
<div id="dogGroup" class="group" role="group">
<div id="smallBreeds" class="tree-parent" role="treeitem" aria-owns="smallBreedGroup" aria-expanded="true" tabindex="-1">
<img class="parentImg" role="treeitem" tabindex="-1" src="http://www.oaa-acessibility.org/media/testsuite/images/expanded.gif" alt="Group expanded"/>
<span>Small Breeds</span>
</div>
<div id="smallBreedGroup" class="group" role="group">
<div id="chihuahua" class="tree-item" role="treeitem" tabindex="-1">Chihuahua</div>
<div id="italian_greyhound" class="tree-item" role="treeitem" tabindex="-1">Italian Greyhound</div>
<div id="Japanese_chin" class="tree-item" role="treeitem" tabindex="-1">Japanese Chin</div>
</div>
<div id="mediumBreeds" class="tree-parent" role="treeitem" aria-owns="mediumBreedGroup" aria-expanded="false" tabindex="-1">
<img class="parentImg" role="treeitem" tabindex="-1" src="http://www.oaa-acessibility.org/media/testsuite/images/contracted.gif" alt="Group collapsed"/>
<span>Medium Breeds</span>
</div>
<div id="mediumBreedGroup" class="group" role="group">
<div id="beagle" class="tree-item" role="treeitem" tabindex="-1">Beagle</div>
<div id="cocker_spaniel" class="tree-item" role="treeitem" tabindex="-1">Cocker Spaniel</div>
<div id="pit_bull" class="tree-item" role="treeitem" tabindex="-1">Pit Bull</div>
</div>
<div id="largeBreeds" class="tree-parent" role="treeitem" aria-owns="largeBreedGroup" aria-expanded="false" tabindex="-1">
<img class="parentImg" role="treeitem" tabindex="-1" src="http://www.oaa-acessibility.org/media/testsuite/images/contracted.gif" alt="Group collapsed"/>
<span>Large Breeds</span>
</div>
<div id="largeBreedGroup" class="group" role="group">
<div id="afghan" class="tree-item" role="treeitem", tabindex="-1">Afghan</div>
<div id="great_dane" class="tree-item" role="treeitem" tabindex="-1">Great Dane</div>
<div id="mastiff" class="tree-item" role="treeitem" tabindex="-1">Mastiff</div>
</div>
</div>
</div>
<div id="minerals" class="tree-parent" role="treeitem" aria-owns="mineralGroup" aria-expanded="true" tabindex="-1">
<img class="parentImg" role="treeitem" tabindex="-1" src="http://www.oaa-acessibility.org/media/testsuite/images/expanded.gif" alt="Group expanded"/>
<span>Minerals</span>
</div>
<div id="mineralGroup" class="group" role="group">
<div id="zinc" class="tree-item" role="treeitem" tabindex="-1">Zinc</div>
<div id="gold" class="tree-parent" role="treeitem" aria-owns="goldGroup" aria-expanded="false" tabindex="-1">
<img class="parentImg" role="treeitem" tabindex="-1" src="http://www.oaa-acessibility.org/media/testsuite/images/contracted.gif" alt="Group collapsed"/>
<span>Gold</span>
</div>
<div id="goldGroup" class="group" role="group">
<div id="yellow_gold" class="tree-item" role="treeitem" tabindex="-1">Yellow Gold</div>
<div id="white_gold" class="tree-item" role="treeitem" tabindex="-1">White Gold</div>
</div>
<div id="silver" class="tree-item" role="treeitem" tabindex="-1">Silver</div>
</div>
<div id="vegetables" class="tree-parent" role="treeitem" aria-owns="vegetableGroup" aria-expanded="true" tabindex="-1">
<img class="parentImg" role="treeitem" tabindex="-1" src="http://www.oaa-acessibility.org/media/testsuite/images/expanded.gif" alt="Group expanded"/>
<span>Vegetables</span>
</div>
<div id="vegetableGroup" class="group" role="group">
<div id="carrot" class="tree-item" role="treeitem" tabindex="-1">Carrot</div>
<div id="tomato" class="tree-item" role="treeitem" tabindex="-1">Tomato</div>
<div id="lettuce" class="tree-item" role="treeitem" tabindex="-1">Lettuce</div>
</div>
</div>
</div>
CSS Code
h2#label_1 {
margin: .5em 0 !important;
padding: 0 !important;
font-size: 1.6em !important;
}
div.tree {
margin-left: 20px;
padding: 0;
width: 15em;
}
div.group {
padding-left: 22px;
}
div.tree-item {
padding-left: 22px;
}
div.tree-parent {
font-weight: bold;
}
img.parentImg {
margin-right: 5px;
}
div.tree-focus {
color: white;
background: black;
}
Javascript Source Code
$(document).ready(function() {
var treeviewApp = new treeview('tree1');
}); // end ready
//
// 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 tree 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('div').not('.group'); // an array of tree items
this.$parents = this.$id.find('.tree-parent'); // an array of the parent items
this.$visibleItems = undefined; // an array of currently visible tree Items (including parents)
this.$activeItem = null; // holds the jQuery object of the active tree item
this.keys = {
tab: 9,
enter: 13,
space: 32,
pageup: 33,
pagedown: 34,
end: 35,
home: 36,
left: 37,
up: 38,
right: 39,
down: 40,
asterisk: 106
};
// 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 styling to the tree parents
this.$parents.each (function(index) {
var $group = $('#' + $(this).attr('aria-owns'));
// If the aria-expanded is false, hide the group and display the collapsed state image
if ($(this).attr('aria-expanded') == 'false') {
$group.hide().attr('aria-hidden', 'true');
$(this).find('img').attr('src', 'http://www.oaa-acessibility.org/media/testsuite/images/contracted.gif').attr('alt', 'Group collapsed');
}
});
// create the initial visible item array
this.$visibleItems = this.$listItems.filter(':visible');
} // end init()
//
// Function expandGroup() is a member function to expand a collapsed group
//
// @param($item object) $item is the jquery id of the parent item of the group to expand
//
// @param(hasFocus boolean) focus is true if the parent item has focus, false otherwise
//
// @return N/A
//
treeview.prototype.expandGroup = function($item, hasFocus) {
var $group = $('#' + $item.attr('aria-owns'));
// expand the group
$group.show().attr('aria-hidden', 'false');
$item.attr('aria-expanded', 'true');
if (hasFocus == true) {
$item.children('img').attr('src', 'http://www.oaa-acessibility.org/media/testsuite/images/expanded-focus.gif').attr('alt', 'Group expanded');
}
else {
$item.children('img').attr('src', 'http://www.oaa-acessibility.org/media/testsuite/images/expanded.gif').attr('alt', 'Group expanded');
}
// refresh the list of visible items
this.$visibleItems = this.$listItems.filter(':visible');
} // end expandGroup()
//
// Function collapseGroup() is a member function to collapse an expanded group
//
// @param($item object) $item is the jquery id of the parent item of the group to collapse
//
// @param(hasFocus boolean) focus is true if the parent item has focus, false otherwise
//
// @return N/A
//
treeview.prototype.collapseGroup = function($item, hasFocus) {
var $group = $('#' + $item.attr('aria-owns'));
// collapse the group
$group.hide().attr('aria-hidden', 'true');
$item.attr('aria-expanded', 'false');
if (hasFocus == true) {
$item.children('img').attr('src', 'http://www.oaa-acessibility.org/media/testsuite/images/contracted-focus.gif').attr('alt', 'Group collapsed');
}
else {
$item.children('img').attr('src', 'http://www.oaa-acessibility.org/media/testsuite/images/contracted.gif').attr('alt', 'Group collapsed');
}
// refresh the list of visible items
this.$visibleItems = this.$listItems.filter(':visible');
} // end collapseGroup()
//
// Function toggleGroup() is a member function to toggle the display state of a group
//
// @param($item object) $item is the jquery id of the parent item of the group to toggle
//
// @param(hasFocus boolean) hasFocus is true if the parent item has focus, false otherwise
//
// @return N/A
//
treeview.prototype.toggleGroup = function($item, hasFocus) {
if ($item.attr('aria-expanded') == 'true') {
// collapse the group
this.collapseGroup($item, hasFocus);
}
else {
// expand the group
this.expandGroup($item, hasFocus);
}
} // 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 parent items
this.$parents.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);
});
// bind a document click handler
$(document).click(function(e) {
if (thisObj.$activeItem != null) {
// remove the focus styling
thisObj.$activeItem.removeClass('tree-focus');
if (thisObj.$activeItem.hasClass('tree-parent') == true) {
// this is a parent item, remove the focus image
if (thisObj.$activeItem.attr('aria-expanded') == 'true') {
thisObj.$activeItem.children('img').attr('src', 'http://www.oaa-acessibility.org/media/testsuite/images/expanded.gif');
}
else {
thisObj.$activeItem.children('img').attr('src', 'http://www.oaa-acessibility.org/media/testsuite/images/contracted.gif');
}
}
// set activeItem to null
thisObj.$activeItem = null;
}
return true;
});
} // end bindHandlers()
//
// Function updateStyling() is a member function to update the styling for the tree items
//
// @param ($item object) $item is the jQuery object of the item to highlight
//
// @return N/A
//
treeview.prototype.updateStyling = function($item) {
// remove the focus highlighting from the treeview items
// and remove them from the tab order.
this.$listItems.removeClass('tree-focus').attr('tabindex', '-1');
// remove the focus image from parent items
this.$parents.each(function() {
// add the focus image
if ($(this).attr('aria-expanded') == 'true') {
$(this).children('img').attr('src', 'http://www.oaa-acessibility.org/media/testsuite/images/expanded.gif');
}
else {
$(this).children('img').attr('src', 'http://www.oaa-acessibility.org/media/testsuite/images/contracted.gif');
}
});
if ($item.hasClass('tree-parent') == true) {
// add the focus image
if ($item.attr('aria-expanded') == 'true') {
$item.children('img').attr('src', 'http://www.oaa-acessibility.org/media/testsuite/images/expanded-focus.gif');
}
else {
$item.children('img').attr('src', 'http://www.oaa-acessibility.org/media/testsuite/images/contracted-focus.gif');
}
}
// apply the focus highlighting and place the element in the tab order
$item.addClass('tree-focus').attr('tabindex', '0');
} // end updateStyling()
//
// Function handleKeyDown() is a member function to process keydown events for the treeview items
//
// @param ($item object) $item is the jQuery id of the parent item 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($item, e) {
var $itemGroup = $item.parent();
var curNdx = this.$visibleItems.index($item);
if ((e.altKey || e.ctrlKey)
|| (e.shiftKey && e.keyCode != this.keys.tab)) {
// do nothing
return true;
}
switch (e.keyCode) {
case this.keys.tab: {
// set activeItem to null
this.$activeItem = null;
// remove the focus styling
$item.removeClass('tree-focus');
if ($item.hasClass('tree-parent') == true) {
// this is a parent item, remove the focus image
if ($item.attr('aria-expanded') == 'true') {
$item.children('img').attr('src', 'http://www.oaa-acessibility.org/media/testsuite/images/expanded.gif');
}
else {
$item.children('img').attr('src', 'http://www.oaa-acessibility.org/media/testsuite/images/contracted.gif');
}
}
return true;
}
case this.keys.home: {
// store the active item
this.$activeItem = this.$parents.first();
// set focus on the active item
this.$activeItem.focus();
e.stopPropagation();
return false;
}
case this.keys.end: {
// store the active item
this.$activeItem = this.$visibleItems.last();
// set focus on the active item
this.$activeItem.focus();
e.stopPropagation();
return false;
}
case this.keys.enter:
case this.keys.space: {
if ($item.hasClass('tree-parent') == false) {
// do nothing
}
else {
// toggle the display of the child group
this.toggleGroup($item, true);
}
e.stopPropagation();
return false;
}
case this.keys.left: {
if ($item.hasClass('tree-parent') == true
&& $item.attr('aria-expanded') == 'true') {
this.collapseGroup($item, true);
}
else {
// move up to the parent
var groupID = $itemGroup.attr('id');
// set the parent tree item as the active item
this.$activeItem = this.$parents.filter('[aria-owns=' + groupID + ']');
// set focus on the active item
this.$activeItem.focus();
}
e.stopPropagation();
return false;
}
case this.keys.right: {
if ($item.hasClass('tree-parent') == false) {
// do nothing
}
else if ($item.attr('aria-expanded') == 'false') {
this.expandGroup($item, true);
}
else {
var $childGroup = $('#' + $item.attr('aria-owns'));
// move to the first item in the child group
this.$activeItem = $childGroup.children('div').not('group').first();
// set focus on the active item
this.$activeItem.focus();
}
e.stopPropagation();
return false;
}
case this.keys.up: {
if (curNdx > 0) {
var $prev = this.$visibleItems.eq(curNdx - 1);
// stroe the new active item
this.$activeItem = $prev;
// set focus
$prev.focus();
}
e.stopPropagation();
return false;
}
case this.keys.down: {
if (curNdx < this.$visibleItems.length - 1) {
var $next = this.$visibleItems.eq(curNdx + 1);
// stroe the new active item
this.$activeItem = $next;
$next.focus();
}
e.stopPropagation();
return false;
}
case this.keys.asterisk: {
// expand all groups
var thisObj = this;
this.$parents.each(function() {
if (thisObj.$activeItem[0] == $(this)[0]) {
thisObj.expandGroup($(this), true);
}
else {
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 ($item object) $item is the jQuery id of the parent item 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($item, e) {
if (e.altKey || e.ctrlKey || e.shiftKey) {
// do nothing
return true;
}
switch (e.keyCode) {
case this.keys.tab: {
return true;
}
case this.keys.enter:
case this.keys.space:
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;
}
default : {
var chr = String.fromCharCode(e.which);
var bMatch = false;
var itemNdx = this.$visibleItems.index($item);
var itemCnt = this.$visibleItems.length;
var curNdx = itemNdx + 1;
// check if the active item was the last one on the list
if (curNdx == itemCnt) {
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 != itemNdx) {
var $curItem = this.$visibleItems.eq(curNdx);
var titleChr = $curItem.text().charAt(0);
if ($curItem.is('.tree-parent')) {
titleChr = $curItem.find('span').text().charAt(0);
}
if (titleChr.toLowerCase() == chr) {
bMatch = true;
break;
}
curNdx = curNdx+1;
if (curNdx == itemCnt) {
// reached the end of the list, start again at the beginning
curNdx = 0;
}
}
if (bMatch == true) {
this.$activeItem = this.$visibleItems.eq(curNdx);
this.$activeItem.focus();
}
e.stopPropagation();
return false;
}
}
return true;
} // end handleKeyPress
//
// Function handleDblClick() is a member function to process double-click events for parent items.
// Double-click expands or collapses a group.
//
// @param ($id object) $id is the jQuery id of the parent item 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;
}
// update the active item
this.$activeItem = $id;
// apply the focus highlighting
this.updateStyling($id);
// 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 ($item object) $item is the jQuery id of the parent item 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($item, e) {
if (e.altKey || e.ctrlKey || e.shiftKey) {
// do nothing
return true;
}
// update the active item
this.$activeItem = $item;
// apply the focus highlighting
this.updateStyling($item);
e.stopPropagation();
return false;
} // end handleClick
//
// Function handleFocus() is a member function to process focus events.
//
// @param ($item object) $item is the jQuery id of the parent item firing event
//
// @param (e object) e is the associated event object
//
// @return (boolean) returns true
//
treeview.prototype.handleFocus = function($item, e) {
if (this.$activeItem == null) {
this.$activeItem = $item;
}
this.updateStyling(this.$activeItem);
return true;
} // end handleFocus
//
// Function handleBlur() is a member function to process blur events.
//
// @param ($id object) $id is the jQuery id of the parent item firing event
//
// @param (e object) e is the associated event object
//
// @return (boolean) returns true
//
treeview.prototype.handleBlur = function($id, e) {
return true;
} // end handleBlur