Summary
Access keys are a contentious area of accessibility, as they can sometimes clash with the shortcut keys used by user agents. One method to get around this problem is to allow users to define their own access keys. This post suggests a PHP class that allows users to define their own access keys.
Author: Gez Lemon
Contents
The AccessKey Class
Update: There is also an ASP version of this article.
Rich Pedley and I have been looking into ways of allowing users to define their own access keys. The AccessKey
class allows users to define their own access keys. Access keys are a contentious area of accessibility, as the way they have been implemented in some user agents mean that they clash with the shortcut keys of the browser. The class provides various methods to help developers provide their own customisation form, along with methods to use them in their markup.
The file ak.zip contains the class and a sample file illustrating how to use the class.
I've set up a demonstration of the class in use. Any access key assignments will be enabled throughout the website. The following is an example of the markup to create the user-defined access key form.
<?php
require_once("ak.class.php");
$arBind = array("Home"=>array("/index.php", "1"),
"Search Criteria"=>array("searchcriteria", "4"),
"Quality Assurance"=>"/services.php",
"Articles Archive"=>"/articles.php");
$objAK = new AccessKeys($arBind);
if ($_POST)
{
if ($_POST["default"])
{
$objAK->useDefaults();
header("Location: $PHP_SELF");
}
else if ($objAK->setCookies())
header("Location: $PHP_SELF");
}
?>
<!DOCTYPE HTML PUBLIC
"-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html lang="en-gb">
<head>
<title>User-Defined Access Keys</title>
<meta http-equiv="Content-Type"
content="text/html; charset=ISO-8859-1">
</head>
<body>
<h1>User-Defined Access Keys</h1>
<?php
$objAK->displayOptions("accessnav");
if (!$objAK->isValid())
echo $objAK->getErrors();
?>
<form id="accesskeysetup" action="ak.php" method="post">
<?php $objAK->generateForm(); ?>
<p>
<input type="submit" name="submit"
value="Assign Accesskey Bindings">
<input type="submit" name="default"
value="Assign Default Bindings">
</p>
</form>
</body>
</html>
Class Constructor
The constructor for the AccessKey
class takes an optional array to help set up the class. The array may contain names and values, or names and an array that includes the value and a suggested access key, or a mixture of the two. The value may either be a URI, or an idref
used with the label
element. For example, the following defines an array of name value pairs (search
contains an idref
, intended to be used with a label
):
$arBind = array("Home"=>"/index.php",
"Skip Navigation"=>"#maincontent",
"Search"=>"search",
"Accessibility Statement"=>"/access.php");
$objAK = new AccessKeys($arBind);
The next example provides the value as an array that includes a suggested accesskey
value.
$arBind = array("Home"=>array("/index.php", "1"),
"Skip Navigation"=>array("#maincontent", "2"),
"Search"=>array("search", "4"),
"Accessibility Statement"=>array("/access.php", "0"));
$objAK = new AccessKeys($arBind);
The final example uses a mixture of name/value pairs, and a name with arrays that
contain the suggested accesskey
value.
$arBind = array("Home"=>array("/index.php", "1"),
"Skip Navigation"=>array("#maincontent", "2"),
"Search"=>array("search", "4"),
"Quality Assurance"=>"/services.php",
"Accessibility Statement"=>array("/access.php", "0"));
$objAK = new AccessKeys($arBind);
AccessKey Methods
The following lists the methods that can be used with the AccessKeys
Class.
addAccessitem Method
The addAccessitem
method allows a single item to be added to the collection of items that may be assigned an accesskey
.
- @parameter String
$strItem
(The name of the item to be added to the collection) - @parameter String
$strValue
(The value - may also be an array)
Examples
$objAK->addAccessitem("Meat", "meat.php");
$objAK->addAccessitem("Fish", array("fish.php", "9"));
removeAccessItem Method
The removeAccessitem
method removes an item from the collection of items that may be assigned an accesskey
.
- @parameter String
$strItem
(The name of the item to be removed from the collection)
Example
$objAK->removeAccessitem("Meat");
isValid Method
The isValid
method returns a Boolean value indicating whether or not the values assigned were valid.
- @parameter none
Example
if (!$objAK->isValid())
echo $objAK->getErrors();
getErrors Method
The getErrors
method returns a string containing errors from form submissions, or an empty string if there are no errors. The getErrors
method should be used with the isValid
method.
- @parameter none
Example
if (!$objAK->isValid())
echo $objAK->getErrors();
setCookies Method
The setCookies
method returns a Boolean value indicating whether or not the values were valid accesskey
values. If the values are inappropriate, isValid
returns false
, and getErrors
can be used to retrieve the errors. Cookies must be set in the head of the document, and the current document must be reloaded before the values are effective. The return value from the setCookies
method can be used to determine whether or not to reload the current page.
- @parameter none
Example
if ($objAK->setCookies())
header("Location: $PHP_SELF");
removeAllBindings Method
The removeAllBindings
method removes all access keys defined for the collection.
- @parameter none
Example
$objAK->removeAllBindings();
displayOptions Method
The displayOptions
method displays a definition list where the definition terms are the names in the collection, and the definitions contain the assigned key, and suggested key if available.
- @parameter String
$strID
(optional parameter to assign an id attribute to the definition list)
Examples
Display options without specifying an id
.
$objAK->displayOptions();
Display options with an id
.
$objAK->displayOptions("someid");
generateForm Method
The generateForm
method generates form sections based on the names provided in the collection. The method takes an optional value to indicate whether the generated markup is XHTML (by default, the value is false
).
- @parameter Boolean
$bXHTML
(optional parameter to determine markup format)
Examples
The following generates the form markup for HTML:
$objAK->generateForm();
The next example generates the form markup for XHTML:
$objAK->generateForm(true);
useDefaults Method
The useDefaults
method assigns all of the values that have been suggested as default keys by the author, if any have been provided.
- @parameter none
Example
$objAK->useDefaults();
header("Location: $PHP_SELF");
getAccessitem Method
The getAccessitem
method returns the markup for a particular item, including the accesskey
if one has been defined. If the item doesn't exist in the collection, the method returns an empty string. The accesskey can be ignored using the $bKey
parameter, in which case, just the markup will be returned. As access keys may be assigned to links, labels, or form controls, an optional parameter allows the markup to return label
tags. By default, the markup returns anchor tags.
- @parameter String
$strItem
(The item to be returned) - @parameter Boolean
$bKey
(Indicates whether the accesskey value should be included) - @parameter String
$strElement
(Element to be returned. Default: "link
", optional "label
")
Examples
An example of how this might be used in a navigation list
<ul id="navigation">
<li>
<?php echo $objAK->getAccessitem("Home", true); ?>
</li>
<li>
<?php echo $objAK->getAccessitem("Contact Us", true); ?>
</li>
</ul>
An example of how this might be used with a form element.
<?php echo $objAK->getAccessitem("Search", true, "label"); ?>
<input type="text" id="search" name="search" size="10">
The following retrieves a link without the access key assignment.
<?php echo $objAK->getAccessitem("Contact Us", false); ?>
Category: Accessibility.
[user-defined-accesskeys.php#comment1]
Very cool! Have you looked at classes in PHP 5? It has far better OO capabilities and allows the attributes to be defined as private or protected for true encapsulation.
Posted by Doug on
[user-defined-accesskeys.php#comment2]
We use PHP 5 at work, but most shared servers are on version 4.
Posted by Gez on
[user-defined-accesskeys.php#comment3]
Could this technique be ported to classic asp? I know .net has classes but a classic asp version would be good.
Posted by Tom K on
[user-defined-accesskeys.php#comment4]
Classic ASP supports the class construct. It doesn't support parameterised class constructors, but has a Class_Initialize event handler that can be used as a constructor without parameters, and also has a Class_Terminate event handler which acts as a class destructor, which isn't supported in PHP 4. ASP's class construct also supports private and public access to class members, so is more powerful in terms of encapsulation than PHP 4, but not as powerful as classes in PHP 5.
I'll put together a basic version of this class in ASP, and post it later on.
Posted by Gez on
[user-defined-accesskeys.php#comment5]
I've put together an ASP version of this class.
Posted by Gez on
[user-defined-accesskeys.php#comment6]
If I understand correctly, this only works with <a href="" accesskey=""> and <label for="" accesskey=""> elements (not the full set permitted to carry an accesskey attribute) and it does not allow for the presence of any attributes (class, title, ...) other than the ones listed?
Posted by Jacques Distler on
[user-defined-accesskeys.php#comment7]
Hi Jacques,
Yes, that's correct. Maybe a better approach would have been to amend existing markup with an identifier, in which case it would be applicable to all elements that are able to have an access key assigned with their original attributes in tact. The structure is all in place, and it wouldn't take much effort for someone to amend it to work that way.
It would also be relatively simple to extend the class to include elements that can have an access key assigned that wouldn't necessarily have a label, such as a submit button. Similarly, the methods of the class could be extended to cater for attributes the author wants included. What's presented here is pretty basic, but as the functionality is encapsulated in a class, it's a straight forward process to extend it for more complex scenarios.
Posted by Gez on
[user-defined-accesskeys.php#comment8]
Hi Gez,
Was there a reason for you not using the DOM functions in PHP to perform this task?
Posted by Gaz on
[user-defined-accesskeys.php#comment9]
Hi Gaz,
I don't think the DOM functions would be appropriate in this case. PHP's DOM functions only work with XML (it would need to work with HTML as well as XHTML), are different between version 4 and 5 of PHP, and needs to be compiled into PHP, which isn't an option for people on a shared server.
Posted by Gez on