Version 0.6.1.
Licensed under the MIT-License.
This page describes a technique which uses the keyboard keys to navigate through table rows.
Implemented by Stephan Soller <stephan.soller@helionweb.de> and
extended by Roberto Rambaldi.
Idea by Florian Seefried <florian.seefried@helionweb.de>.
The main idea of Florian Seefried was to make tables more userfriendly by giving them the possibilty to use the arrow keys to navigate thought table rows and using return to “enter” an record. Together with the backspace key this makes fast navigation possible. This behaviour is known from some desktop applications but is not seen very often on web applications. This little script should make it easier for programmers to integrate this behaviour into thier applications.
If you have any questions, want to report a bug or just want to talk about the script you can send me a mail.
Just take a look at the example page. You can also download the example as a zipped archive.
Include jquery.js (jQuery v1.1.1) and jquery.table_navigation.js into your page.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head>
<script src="jquery.js" type="text/javascript"></script>
<script src="jquery.table_navigation.js" type="text/javascript"></script>
Call the jQuery.tableNavigation()
function to initialize the table navigation.
<script type="text/javascript">
jQuery.tableNavigation();
</script>
You can specify some options to change the behaviour or source code interaction of the script. See
the options section for a detailed description. Calling jQuery.tableNavigation()
multiple times will update the options used by the table navigation.
Add the CSS class navigateable
to the table
element which you want to be navigateable
using the keyboard. Also add the CSS class activation
to the a
element of each row
whichs href
attribute should be used if the user presses the return key or double clicks on the
row. This marks the link as the activation link for the corresponding row.
<table class="navigateable">
<thead>
<tr>
<th>Cell 01</th>
<th>Cell 02</th>
<th>Cell 03</th>
</tr>
</thead>
<tbody>
<tr>
<td>Data 01-01</td>
<td><a href="target01.html" class="activation">Link 01</a></td>
</tr>
<tr>
<td>Data 02-01</td>
<td><a href="target02.html" class="activation">Link 02</a></td>
</tr>
</tbody>
</table>
It's important to use the thead
and tbody
tags to seperate the table header from
the body. By default only the rows (tr
elements) in the tbody
element are selectable
and rows in the table header are not. You can change this by modifying the row_selector
option (detailed
information below).
Create a CSS style for tr.selected
which formats the currently selected table row.
<style type="text/css">
tr.selected {background-color: red; color: white;}
</style>
That's all. Much fun. If you find this little script useful, discovered bugs or have ideas to improve it, just leave a comment or drop me a mail.
You can specify some options when calling the jQuery.tableNavigation
function to initialize the
table navigation. To update the used options just call jQuery.tableNavigation
again with the new
options. The function takes these options as a hash:
jQuery.tableNavigation({
table_selector: 'table.navigateable',
row_selector: 'table.navigateable tbody tr',
selected_class: 'selected',
activation_selector: 'a.activation',
bind_key_events_to_links: true,
focus_links_on_select: true,
select_event: 'click',
activate_event: 'dblclick',
activation_element_activate_event: 'click',
scroll_overlap: 20,
cookie_name: 'last_selected_row_index',
focus_tables: true,
focused_table_class: 'focused',
jump_between_tables: true,
disabled: false,
on_activate: null,
on_select: null
});
table_selector
focused_table_class
option. Defaults to table.navigateable
.
row_selector
table.navigateable tbody tr
which will effect all table rows
(tr
elements) inside a tables tbody
element.
This way header tr
elements inside of a thead
element will not be affected. You can use your own selector here but it have to
effect tr
elements. Something like
div.overview tbody tr.viewable_records
will
limit the effected table rows a little bit more.
selected_class
selected
.
activation_selector
a.activation
.
bind_key_events_to_links
true
) or to the document object (false
).
If the events are bound to the document object forms on the same page will not work
properly but the script won't need the focus to work. Default value is true
,
to get pre v0.5.4 behaviour set it to false
.
focus_links_on_select
bind_key_events_to_links
option is set to false
. Defaults to true
but if you want pre v0.5.4 behaviour set it to false
.
select_event
click
) but you can use all event names supported by
jQuery, see jQueries event docs.
activate_event
dblclick
.
activation_element_activate_event
false
or null
to not bind any event to the activation element. Defaults to click
.
scroll_overlap
20
pixels.
This also compensates some browser incompatibilities and a value blow 20
isn't recommended.
cookie_name
null
the script will not use any cookies at all. Then
however if you return to a table you may find the wrong row selected. This is caused by
different browser caching behavior and usually the script can work around the problem using
cookies. The default cookie name is last_selected_row_index
.
disabled
false
(event handlers are enabled).
See the demonstration page for an example.
focus_tables
true
or false
) to toggle the highlighting of the current
table. If set to true
the table of the currently selected row will be marked with the
class specified in the focused_table_class
option. Set to false
if you
just have one table on a page and/or want to increase the performance of the script. Defaults to
true
.
focused_table_class
focused
.
focused_table_class
focused
.
jump_between_tables
true
or false
) which allows you to controll if the script can jump
between multiple tables on one page. If set to true
and the last row of a
table is reached the next row selected will be the first row of the next table. Note that this can confuse users
because the keyborad focus and the view port also jumps to the first row of the next table. Defaults to
true
.
on_select
null
and no user specified code is run. See user specified event handlers
for detailed information and examples.
on_activate
null
and no user specified code is run. See
user specified event handlers for detailed information and examples.
They can be used to inject your own code on certain events like when a row gets selected or activated. A quick example will tell more than 100 words so here's one:
jQuery.tableNavigation({
on_activate: function(row){
var link_destination = jQuery("a", row).attr("href");
var user_wants_to_go = confirm('This link will bring you to "' + link_destination + '".\nDo you really want to go?');
return user_wants_to_go;
}
});
As you can see in the example the event handler is a function assigned to the on_activate
option. This function takes the DOM object of the row affected by the event as a parameter and is called every time a row is activated.
What you want to do with the row is up to you. In the example we grab the value of the first links href
attribute and
ask the user if he wants to go to this location. We then return the users decision. But what is this return user_wants_to_go;
about?
If an event handler returns true
(or anything other than false
) the plugin will continue as usual
after calling our event handler. In case of the on_activate
event it will redirect the browser to the location of the
activation link. However this default action is not always wanted eg. if the user clicks "abort" in our example. In this case an event
handler can return false
to suppress the default action and the user will not be redirected to the new location.
Alternatively to specifying a function you can assign a simple string to the on_activate
option:
jQuery.tableNavigation({
on_activate: "onclick"
});
or
jQuery.tableNavigation({
on_activate: "alert('we love the evil eval()');"
});
If the string you assigned to the on_activate
option starts with "on"
it is
interpreted as an attribute name. When a row gets activated the plugin will look for an attribute of the activation link named like this
and eval its content. Any other string will be evaled directly.
These approaches are usually hard to debug and not really good coding practice. In almost any cases you will be better of by using a function like in the first example.
Everything show here for the on_activate
option also applies to the
on_select
option. The default action of the on_select event is to mark the next row with the
class specified in the selected_class
option and to scroll the page to make the new row visible
if necessary. Again if your handler returns anything but true
these default actions will be skipped.
keypress
event if an arrow key is pressed. However the keydown
, and keyup
events are working. The script now uses the keydown
event if it detects IE.
file://...
) Firefox 2.0 doesn't remember the last activated row correctly. It doesn't store or read the cookie used to save the index of the last activated row.getPos
function of the Interface Elements utility functions or is caused by bad browser support as the results vary on different browsers.Want to help? Know a solution to a bug? Leave a comment or send me a mail.
This script intercepts several keyboard and mouse events and uses them to manipulate the currently selected row of a table.
First of by default the script will only affect tables of the CSS class navigateable
. Within such a table the script considers
only rows (tr
elements) with a tbody
element as selectable. This is necessary to avoide that the table
header row can be selected (tr
elements within the thead
element). The selected row will be marked
with the CSS class selected
. So if you want to define special styles for the selected row you should simply use the CSS
selector tr.selected
.
Several events can be used to manipulate the selected table row:
tr
element that follows the
currently selected tr
element.
tr
element just before the
currently selected tr
element.
When selecting a row the CSS class "selected" is added to this rows tr
tag.
This class gets removed from the previously selected row. Additionaly the activation link of the new row will be
focused and the screen will scroll to the position of the row leaving a certain amount of pixels to the border of the
viewport (default 20 pixels). This ensures that the selected row is visible. If there is no next row to select the
arrow keys will cause the page to scroll just as usual.
Activating a row will also select this row. More important this will read the URL of the first link
(a
tag) in the row of the class activation
. Before following this URL the index of
the currently activated row and the URL of the current page will be stored to a cookie.
So, the user got to the next page... what now? Usually if you entered a record you aren't intrested in you'll use the backspace key to get back to the table and select the next interesting one. It's intuitive to think that the record you just activated is also still selected if you come back to select the next one... Well, this heavily depends on the kind of caching the browser performs. Because every browser has it's own way of caching pages this doesn't work very well and you'll get everything but not the table with the row selected you activated before.
To bypass this limitation the script saved the index of the last activated row and the URL of this page in a cookie.
If the user now returns to the table the script reads the cookie and selects the row stored there which is the row the
user activated just before leaving. This will only be done if the URL stored in the cookie matches the current URL.
In case the user goes on to another page using this script the URLs don't match and the script will select the first
row, not some strange row index from another table. You can disable this workaround by setting the
cookie_name
option to null
.
This little script is build upon jQuery by John Resig and contributors.
It also includes the getPos
and getScroll
functions of the utility functions of Stefan Petres Interface Elements for jQuery.
Cookies are handled by the cookie handling functions form Quirks Mode written by Scott Andrew and edited by Peter-Paul Koch.
Roberto Rambaldi also added some nice things to it (namely the 0.4.0 release).
Much tanks to these guys, without them such a quickly (prototype done in about 4 to 6 hours) and clearly developed
script wouldn't have been possible.
Special thanks to Roberto Rambaldi for contributing the 0.4.0 release.
Also special thanks to Antonio Biondo whos few, simple but genius changes led to the 0.5.4 release.
focused
.focused
.activation_link_class
option (default value activation
) is replaced by the
more common activation_selector
option (default value a.activation
).
href
attribute
(speak: links). This was necessary to not break the behaviour of checkboxes if used as activation elements.
disabled
option to temporarily disable all event handlers of the script (requested by Jeff).jQuery.tableNavigation()
call is done inside an
if
/ then
statement the tagName
property is suddenly undefined. Fixed by
using the nodeName
property instead of the tagName
property. Thanks to Brian Garibaldi for
helping me out with this.
jQuery.tableNavigation()
function will rebind all event handlers if necessary. This can be used to restore the table navigation behavior if another script modified
the elements of the table. You can take a look at a test page to explore this
behavior. Again thanks to HT for his help.
jQuery.tableNavigation()
function was called multiple times. This broke the table navigation
behavior in a somehow funny way. However if you call jQuery.tableNavigation()
multiple times now it'll just update
the settings used by the table navigation. Thanks to HT for reporting the bug.
on_select
and
on_activate
events. This feature is inspired by the on_activate
option contributed by Roberto Rambaldi.
getPos
and getScroll
functions of the utility functions
of Stefan Petres Interface Elements for jQuery directly into the script. Now
iutil.js
is no longer required.
keypress
event again to fix some unwanted scrolling with Opera. If IE is detected the
keydown
event is used.
return_link_name
option to the less confusing name activation_link_name
.cookie_name
option to null
.on_activate
option which specifies what should happen if a row gets activated. You can even use this option to write your own row activation handler.jquery.key_navigation.js
to match the plugin name scheme.jQuery.tableNavigation
namespace.scrollToIfNeccessary
function which makes sure an highlighted row is visible on the viewport. This one needs Stefan Petres Interface utility library.Copyright (c) 2006 Stephan Soller <stephan.soller@helionweb.de>, Florian Seefried <florian.seefried@helionweb.de>.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.