This page provides several tests to illustrate how a browser handles the focus and blur events for <div> elements with the button role. Each test in the grid below has uniquely defined properties. The first test is the default button element with no tabindex defined. Each subsequent test specifies a value for tabindex, with the last one being an undefined (i.e. invalid) value.
onfocus and onblur event handlers have been bound to each of the test case controls. If triggered, an event handler will log the event in the Test Results box to the right of the test grid. The focus event handler modifies the styling of the button to illustrate cases where the element has focus but the browser does not provide any visual indication. The event handlers do not consume the event (i.e. they allow propagation). This allows the test to record the event but not affect the browser's default behavior. onclick and keydown event handlers have also been bound for the test controls to briefly apply highlight styling to the div buttons. These handlers consume the events.
<div id="description">
<p>This page provides several tests to illustrate how a browser handles the focus and blur events for <div> elements with the button role. Each test in the grid below has uniquely defined properties. The first test is the default button element with no tabindex defined. Each subsequent test specifies a value for tabindex, with the last one being an undefined (i.e. invalid) value.</p>
<p>onfocus and onblur event handlers have been bound to each of the test case controls. If triggered, an event handler will log the event in the Test Results box to the right of the test grid. The focus event handler modifies the styling of the button to illustrate cases where the element has focus but the browser does not provide any visual indication. The event handlers do not consume the event (i.e. they allow propagation). This allows the test to record the event but not affect the browser's default behavior. onclick and keydown event handlers have also been bound for the test controls to briefly apply highlight styling to the div buttons. These handlers consume the events.</p>
<p>The reset buttons will clear the Test Results.</p>
</div>
// key code definitions
var KEY_ENTER = 13;
var KEY_SPACE = 32;
/*-------------- div button tests ---------------------------*/
// bind the div button test focus handlers
$('#div1, #div2, #div3, #div4').focus(function (e) {
$(this).addClass('focus');
return handleEvent(e, this, 'focus', 'div-results', true, false);
});
// bind the div button test blur handlers
$('#div1, #div2, #div3, #div4').blur(function (e) {
$(this).removeClass('focus');
return handleEvent(e, this, 'blur', 'div-results', true, false);
});
// bind the div button click handlers
$('#div1, #div2, #div3, #div4').click(function (e) {
// Store the object
animID = this;
// Add the highlight class
$(this).addClass('highlight');
// set a timer to remove the highlight class
setTimeout(function() {$(animID).removeClass('highlight');}, 200);
e.preventDefault;
return false;
});
// bind the div button keydown handlers
$('#div1, #div2, #div3, #div4').keydown(function (e) {
switch(e.which) {
case KEY_ENTER:
case KEY_SPACE: {
// Store the object
animID = this;
// Add the highlight class
$(this).addClass('highlight');
// set a timer to remove the highlight class
setTimeout(function() {$(animID).removeClass('highlight');}, 200);
e.preventDefault;
return false;
break;
}
} // end switch
return true;
});
// load the result database
$.getJSON('data/div.json', function(data, rslt) {
if (rslt=='success') {
loadData(data);
makeSortable('#results');
}
});
/*
* function handleEvent() appends a row to the target table. Called by event handlers to process focus events
*
* @param (e object) The browser.event object
*
* @param (id object) The element that fired the event
*
* @param (event string) The name of the event that called the handler
*
* @param (target string) The id of the target table where results will be appended
*
* @param (propagate boolean) true if allowing propagation, false if consuming event
*
* @param (preventDefault boolean) true if preventing default behavior, false otherwise
*
* @return true if propagating, false if consuming event
*/
function handleEvent(e, id, event, target, propagate, preventDefault) {
// append the result row to the target table
$('#' + target + ' > tbody').append('<tr><td class="event">' + event + ':</td><td>' + $(id).attr('id') + '</td></td>');
// if preventDefault is true, set the preventDefault property of the event
if (preventDefault == true) {
e.preventDefault = true;
}
// if propagate is false, set the stopPropagation property of the even and return false
if (propagate == false) {
e.stopPropagation = false;
return false;
}
/*
* function loadData() is a callback for a getJSON call to load the result data from a json file
* and append it to a table in the html page
*
* @param (data array) data is the array of data records loaded from the file
*
* @param (rslt string) rslt is the result of the load operations.
*
* @return N/A
*/
function loadData(data) {
var row;
var invalid = "";
$('#results tbody tr:odd').addClass('odd');
}
// Define a small jQuery extension to alternate table row colors
jQuery.fn.alternateRowColors = function() {
$('tbody tr:odd', this).removeClass('even').addClass('odd');
$('tbody tr:even', this).removeClass('odd').addClass('even');
return this;
};
/*
* function makeSortable() applies properties to a table necessary to allow for alpha-numeric sorting
*
* @param (id object) id is the table object to make sortable
*
* @return N/A
*/
function makeSortable(id) {
// iterate through the table elements
$(id).each(function () {
var $table = $(this);
$table.alternateRowColors();
// iterate through the table header
$('.result-header', $table).each(function(column) {
var $header = $(this);
var findSortKey;
// adjust column to handle the overlapping header rows
// (i.e. don't count Results and Notes header)
// Note: This adjust must be modified if the header format changes.
// Remove it if single-line header
//
if (column > 5) {
column -= 2;
}
// if the cell has the sort-alpha class, find the sort keys
if ($header.is('.sort-alpha')) {
findSortKey = function ($cell) {
return $cell.find('.sort-key').text().toUpperCase()
+ ' ' + $cell.text().toUpperCase();
};
}
if (findSortKey) {
// Define the header highlighting handler
$header.find('.sort-button').addClass('clickable');
$header.hover(function() {
$header.addClass('hover');
}, function() {
$header.removeClass('hover');
});
//
// bind a focus handler to the sort buttons
//
$('.sort-button').focus(function () {
$(this).css('background-color', 'black');
});
//
// bind a blur handler to the sort buttons
//
$('.sort-button').blur(function () {
$(this).css('background-color', 'transparent');
});
// Define the header click handler to perform table
// sorting when the header is clicked
$header.find('.sort-button').click(function(e) {
var sortDirection = 1;
// if the table is sorted in ascending order, reverse
// the sort order flag
if ($header.is('.sorted-asc')) {
sortDirection = -1;
}
// create an array of the table rows
var rows = $table.find('tbody >tr').get();
// iterate through the table rows and store the sort keys for each one
// in an attached expando
$.each(rows, function (index, row) {
var $cell
// The first column is marked as a header row for screen readers
// Need to treat it seperately
if (column == 0) {
$cell = $(row).children('th').eq(column);
}
else {
$cell = $(row).children('td').eq(column - 1);
}
row.sortKey = findSortKey($cell);
});
// sort the rows
rows.sort(function(a, b) {
if (a.sortKey < b.sortKey) {
// move row a before row b
// (according to the sort direction)
return -sortDirection;
}
else if (a.sortKey > b.sortKey) {
// move row a after row b
return sortDirection;
}
// the rows are equal--do nothing
return 0;
});
// iterate through the rows array and reinsert them into the table
// according to the new sort order
$.each(rows, function(index, row) {
// insert the row
$table.children('tbody').append(row);
// remove the expando
row.sortKey = null;
});
// remove the previous sorted class and reset the button images
$table.find('.result-header')
.removeClass('sorted-asc')
.removeClass('sorted-desc')
.not(this).find('img').attr('src', 'images/sortable.png');
// reapply the sorted class
// the first column is th for screen readers
if (column == 0) {
// remove the sorted class from the other columns
$table.find('td').removeClass('sorted')
// apply the class to the browser column
$('.browser-col').addClass('sorted');
}
else {
// remove the class from the browser column
$('.browser-col').removeClass('sorted')
// apply the class to the appropriate column
$table.find('td').removeClass('sorted')
.filter(':nth-child(' + (column + 1) + ')')
.addClass('sorted');
}
// reapply the row striping
$table.alternateRowColors();
e.preventDefault;
return false;
}); // end header click
} // end if
}); // end each
}); // end each
} // end makeSortable();
}); // end document ready
</script>