- Interrupting the User
- Building the Dialog Box
- Capturing the Mouse Interactions
- Capturing Keyboard Events
- Summary
Capturing Keyboard Events
A truly modal dialog box should stop all user interaction with the parent window, including all keyboard interactions. (Most web developers tend to overlook the keyboard, as casual web users primarily use the mouse to move around web pages.) After we’ve stopped all mouse interactions, it’s quite easy to capture the keyboard events as well:
- The focus is moved to the first button in the dialog box.
- The keyboard event handler is defined for the container modalDialog DIV.
- The keyboard event handler acts on the few keystrokes that are recognized by the dialog box (Tab, Shift+Tab, Esc, Enter) and blocks all the others by using the xStopPropagation and xPreventDefault functions (described in my article "Adding Keyboard Shortcuts to a Web User Interface").
The keyboard handler definition is a bit obscure, as it’s defined as a property of the Modal object, but has to act within the scope of the modalDialog DIV and still retain the access to its parent object as well as to the DIV object. I’ve solved this problem by declaring a me local variable, which is set to the this value in context of the messageBox function. (Thus, me is equal to Modal.) The keyboard handler is then attached to the dialog DIV with the xAddEventListener function call:
var me = this; me.dialog = dialog; xAddEventListener(dialog,"keydown", function (evt) { me.keyboardHandler(evt,me) });
The keyboard event handler does the following:
- Retrieves the event-related properties into a browser-independent xEvent object
- Stops event propagation and disables default browser processing
- Checks whether the currently focused element is one of the button links, and selects the first button link otherwise
- Retrieves the parent button of the current link
- Acts on the key that the user has pressed
The framework of the event handler is shown in the following listing:
function keyboardHandler(evt,me) { var e = new xEvent(evt); xStopPropagation(evt); xPreventDefault(evt); var el = e.target; if (el.className != "modalButtonLink") { me.firstButtonLink.focus(); return; } var btn = el.parentNode; switch (e.keyCode) { ... handle individual keystrokes ... } }
The code to handle the Esc and Enter keys is straightforward: Both keys close the dialog box and call the callback function. The Esc key returns the Modal.CANCEL value, and the Enter key returns the value of the currently selected button.
switch (e.keyCode) { case 13: if (el.clickFunction) el.clickFunction(); break; case 27: me.finishDialogBox(me.CANCEL); break; ... }
The code that handles the Tab and the Shift+Tab keys is a bit more difficult to understand:
- The Tab key moves the focus to the link (the firstChild of a button) of the next button (the nextSibling of the current button), or to the first button (the firstChild of the parent DIV) if no next sibling exists.
- The Shift+Tab key moves the focus to the previous button (the previousSibling of the current button) or the last button (the lastChild of the parent DIV), if no previous sibling exists.
switch (e.keyCode) { ... case 9: if (e.shiftKey) { if (btn.previousSibling) { btn.previousSibling.firstChild.focus(); } else { btn.parentNode.lastChild.firstChild.focus(); } } else { if (btn.nextSibling) { btn.nextSibling.firstChild.focus(); } else { btn.parentNode.firstChild.firstChild.focus(); } } break; ... }
You can view the complete keyboard event handler on my web site.