At times it is convenient to
execute code that we have bound to an event, even if the normal
circumstances of the event are not occurring. For example, suppose we
wanted our style switcher to begin in its collapsed state. We could
accomplish this by hiding buttons from within the stylesheet, or by
calling the .hide() method from a $(document).ready()
handler. Another way would be to simulate a click on the style switcher
so that the toggling mechanism we've already established is triggered.
The .trigger() method allows us to do just this:
$(document).ready(function() {
$('#switcher').trigger('click');
});
Now right when the page
loads the switcher is collapsed, just as if it had been clicked. If we
were hiding content that we wanted people without JavaScript enabled to
see, this would be a reasonable way to implement graceful degradation.
The .trigger() method provides the same set of shortcuts that .bind() does. When these shortcuts are used with no arguments, the behavior is to trigger the action rather than bind it:
$(document).ready(function() {
.trigger() methodshortcuts$('#switcher').click();
});
Keyboard events
As another example, we can add
keyboard shortcuts to our style switcher. When the user types the first
letter of one of the display styles, we will have the page behave as if
the corresponding button were clicked. To implement this feature, we
will need to explore keyboard events, that behave a bit differently from mouse events.
There are two types of keyboard events: those that react to the keyboard directly (keyup and keydown) and those that react to text input (keypress). A single character entry event could correspond to several keys, for example when the Shift key in combination with the X key creates the capital letter X.
While the specifics of implementation differ from one browser to the
next (unsurprisingly), a safe rule of thumb is as follows: if you want
to know what key the user pushed, you should observe the keyup or keydown event; if you want to know what character ended up on the screen as a result, you should observe the keypress event. For this feature, we just want to know when the user presses the D, N, or L key, so we will use keyup.
Next, we need to determine
which element should watch for the event. This is a little less obvious
than with mouse events, where we have an obvious mouse cursor to tell us
about the event's target. Instead, the target of a keyboard event is
the element that currently has the keyboard focus. The element with focus can be changed in several ways, including mouse clicks and presses of the Tab
key. Not every element can get the focus, either; only items that have
default keyboard-driven behaviors such as form fields, links, and
elements with a .tabIndex property are candidates.
In this case, we don't really
care what element has the focus; we want our switcher to work whenever
the user presses one of the keys. Event bubbling will once again come in
handy, as we can bind our keyup event to the document element and have assurance that eventually, any key event will bubble up to us.
Finally, we will need to know which key was pressed when our keyup handler gets triggered. We can inspect the event object for this. The .keyCode
property of the event contains an identifier for the key that was
pressed, and for alphabetic keys, this identifier is the ASCII value of
the uppercase letter. So we can switch on this value and trigger the
appropriate button click:
$(document).ready(function() {
keyboard events, style switcher.keyCode property$(document).keyup(function(event) {
switch (String.fromCharCode(event.keyCode)) {
case 'D':
$('#switcher-default').click();
break;
case 'N':
$('#switcher-narrow').click();
break;
case 'L':
$('#switcher-large').click();
break;
}
});
});
Presses of these three keys
now simulate mouse clicks on the buttons—provided that the key event is
not interrupted by features such as Firefox's "search for text when I
start typing."
As an alternative to using .trigger()
to simulate this click, let's explore how to factor out code into a
function so that more than one handler can call it—in this case, both click and keyup. While not necessary in this case, this technique can be useful in eliminating code redundancy.
$(document).ready(function() {
// Enable hover effect on the style switcher buttons.
$('#switcher .button').hover(function() {
$(this).addClass('hover');
}, function() {
$(this).removeClass('hover');
});
// Allow the style switcher to expand and collapse.
var toggleStyleSwitcher = function(event) {
if (!$(event.target).is('.button')) {
$('#switcher .button').toggleClass('hidden');
}
};
$('#switcher').click(toggleStyleSwitcher);
// Simulate a click so we start in a collaped state.
$('#switcher').click();
// The setBodyClass() function changes the page style.
// The style switcher state is also updated.
var setBodyClass = function(className) {
$('body').removeClass();
$('body').addClass(className);
$('#switcher .button').removeClass('selected');
$('#switcher-' + className).addClass('selected');
if (className == 'default') {
$('#switcher').click(toggleStyleSwitcher);
}
else {
$('#switcher').unbind('click', toggleStyleSwitcher);
$('#switcher .button').removeClass('hidden');
}
};
// Invoke setBodyClass() when a button is clicked.
$('#switcher').click(function(event) {
if ($(event.target).is('.button')) {
if (event.target.id == 'switcher-default') {
setBodyClass('default');
}
if (event.target.id == 'switcher-narrow') {
setBodyClass('narrow');
}
else if (event.target.id == 'switcher-large') {
setBodyClass('large');
}
}
keyboard events, style switcheradding});
// Invoke setBodyClass() when a key is pressed.
$(document).keyup(function(event) {
switch (String.fromCharCode(event.keyCode)) {
case 'D':
setBodyClass('default');
break;
case 'N':
setBodyClass('narrow');
break;
case 'L':
setBodyClass('large');
break;
}
});
});