will also work. 3. Add jQuery’s $(document).ready() function to your page: $(document).ready(function() { }); // end ready 4. Use jQuery to select the
A jQuery UI Dialog Box
Are you sure you want to destroy the robot?

A paragraph
and add Yes, I am a paragraph. as a title:A paragraph
You can add a title to any element in the body of a web page. (You can also get more creative with these titles if you wish.) 3. Locate the image tag


Tabbed Panels
. In theTabbed Panels
- ) tag just below the opening
- Tab 1
- Tab 2
- Tab 3 These are named anchor links—links that point to other sections of the page that are identified with the matching ID. In other words, the first
- tag will
link to the for the first panel, the second
- tag to the second panel, and so on. In order to make these links work, you need to add the matching IDs to the panel divs. 4. Locate the
below the- tag you just edited (an HTML comment above the
- tag. For
example, here’s the HTML for a menu with three top-level menus and a submenu
that appears when you mouse over the last menu item:
When this HTML is converted into a menu, visitors can mouse over the Products
menu item, and a submenu with the three product options will pop into view. As
with other jQuery UI widgets, it’s good to provide an ID to the widget’s containing
element. In this case, it’s the first
- tag because that’s the container for all of the
menu items and submenus.
TIP If you want to visually organize the options in your menus, you can add a divider to separate submenu
buttons. Just insert a
- tag with no link and a dash in it like this:
- - jQuery UI will draw a line (instead of adding a button) to the menu. Using the menu widget is easy: 1. Attach the jQuery UI CSS file, jQuery JavaScript file, and the jQuery UI JavaScript file. These are the same basic steps for using any jQuery UI widget as described on page 104. 2. Insert an unordered list of links, with additional unordered lists for submenus as described above. It’s a good idea to make sure your top-level menu items link to pages on your site. 3. Add CSS to limit the size of the menu buttons and submenus. The out-of-the-box CSS for jQuery UI menus doesn’t limit the width of the menu buttons, so you can end up with extraordinarily wide buttons on your main navigation menu. To set a size for the main menu buttons, create a .ui-menu style with a width property, like this: 344 JAVASCRIPT & JQUERY: THE MISSING MANUAL ADDING MENUS TO A PAGE .ui-menu { width: 10em; } The ui-menu class is applied automatically by jQuery UI when it creates a menu widget. That class is applied to each
- tags that are a direct descendant of an element with the ID of mainMenu. (This assumes that you gave
the containing
- tag that ID name as in the example code on page 344. If
you use a different ID for that tag, then use that instead.) The > part is a child
selector and only selects
- tags that are directly children of the main
-
tags, so all the
- tags in submenus ignore this rule.
The style sets each menu button to a set width, and then floats them side by
side. Then you need to set the width of the submenus.
3. Add another CSS style:
.ui-menu .ui-menu {
width: 10em;
}
This style sets the width of the submenus. jQuery UI gives each menu—
-
tag—the class of .ui-menu, so this selector—.ui-menu .ui-menu—selects only
those
- tags that are inside another
- tag. In other words, the style only
applies to nested menus and sets the width of those submenus.
4. Finally, add one last style to fix a problem with the main menu:
#mainMenu {
float: left;
}
This style fixes what’s called an escaping float—a situation where a parent element’s height collapses when its child elements are floated. In plain English, it
just means that the border and background of the main menu don’t look right
when all the buttons are floated. This is one technique for fixing the problem;
just float the parent element.
With the CSS out of the way, you can add the JavaScript.
348
JAVASCRIPT & JQUERY: THE MISSING MANUAL
5. Call the menu() function as described on page 346, but add a few options
to control the placement of the submenu and icon used on the main menu:
ADDING MENUS
TO A PAGE
$('#menu').menu({
position: {
my: 'center top',
at: 'center bottom'
},
icons: {
submenu: 'ui-icon-triangle-1-s'
}
});
The position option (described on page 346) controls the placement of the
submenu. In this case, it puts the menu directly below the menu button that
opens it. In addition, the menu widget normally shows a right-pointing arrow
icon on menu buttons that have submenus. However, because the menu bar is
now horizontal, and the submenu opens up below the main menu bar, you must
use a down-pointing arrow ('ui-icon-triangle-1-s').
Chapter 9: Expanding Your Interface
349
CHAPTER
Forms Revisited
10
F
orms are the original interactive web element, and they’re a part of most web
applications in one form or another. Forms can get input from visitors, let
shoppers buy goods, let community members post their thoughts, and so on.
Chapter 8 looked at ways to make web forms smarter and easier to use. jQuery UI
lets you do even more with your forms and provides a consistent design to make
your form elements look and function in similar ways.
This chapter will show you how to use four jQuery UI widgets—Datepicker, Autocomplete, Selectmenu, and Button—that can really make your forms look great and
work well.
Picking Dates with Style
Many forms require date input. Forms for adding an event to a calendar, booking
a plane flight, and making a dinner reservation all require you to specify a date for
an activity. Many forms provide instructions, like “Type a date, like 12/10/2014,” but
simply asking visitors to type a date into a field can generate a wide variety of results.
First of all, you’re relying on your visitors never to make typos. In addition, because
people often write dates in different ways (in the United States, for example, dates
are specified in the order month, day, year, but many other places the order is day,
month, year), hand-typed dates may be misleading or inaccurate.
Fortunately, jQuery UI’s Datepicker widget makes selecting a date straightforward.
Instead of typing a date, visitors just click a form field, and then use a visual calendar
to pick the desired date (Figure 10-1). This widget is simple to use and customize.
351
PICKING DATES
WITH STYLE
FIGURE 10-1
jQuery UI’s Datepicker widget
provides a simple method to
accurately specify dates in a
web form.
As with most jQuery UI widgets, Datepicker is extremely easy to use:
1. Follow the steps on page 304 to attach jQuery UI’s CSS and JavaScript files
to your web page.
You’ll need to attach the jQuery file as well, so that whenever you use a jQuery
UI widget, you’ll have the jQuery UI CSS, jQuery JavaScript, and jQuery UI
JavaScript files attached to your page (in that order, too).
2. Add a form to a page, and include a text field for capturing a date.
Provide a way to identify that input field, so you can select it with jQuery. For
example, you might give it an ID like this:
Or, if the form has several fields for capturing dates (like fields for arrival and
departure) you might use a class name to identify all fields that should use the
datepicker widget like this:
3. Add jQuery’s $(document).ready() function to your page:
$(document).ready(function() {
}); // end ready
352
JAVASCRIPT & JQUERY: THE MISSING MANUAL
4. Use jQuery to select the input element(s) and call the datepicker() function:
PICKING DATES
WITH STYLE
$(document).ready(function() {
$('#birthdate').datepicker();
}); // end ready
Or, if you’ve used a class to identify more than one input like in the example in
step 2, you could write this:
$(document).ready(function() {
$('.date').datepicker();
}); // end ready
These are the only steps you need to create a date picker like the one you can see
in Figure 10-1. And if that’s all the Datepicker widget did, it’d be good enough. But
the Datepicker widget provides many different options for customizing its display
and how it works.
NOTE HTML5 includes a special date field that’s intended to provide some of the functionality that Datepicker provides, but without any JavaScript. However, it’s not supported that well on all browsers, and doesn’t
provide any way to customize the look of the pop-up calendar. In addition, jQuery UI’s Datepicker provides many
additional features that you won’t get if you use the HTML5 date field.
Setting Date Picker Properties
You can set properties of the Datepicker widget—like the date format jQuery UI
will use when writing the date into the form field—by passing an object to the datepicker() function. This object literal contains datepicker options and values to
control those options.
For example, one option—numberOfMonths—lets you specify how many months
should appear when the date picker opens. Normally that’s just 1 as pictured in
Figure 10-1, but it’s possible to display three months at a time, as shown in Figure
10-2, by setting this value to 3:
$('.date').datepicker({
numberOfMonths : 3
});
Here are some of the most useful options:
• changeMonth. Normally, visitors can change the month displayed by the Datepicker pop-up calendar by clicking either the left or right arrows in the top of
the calendar (Figure 10-1). These buttons display either the previous (left) or
next (right) month. However, this is a tedious way to select a date that’s nine
months away. Set the changeMonth option to true, and a drop-down menu appears in the calendar, letting visitors quickly choose a new month (Figure 10-2).
changeMonth : true
Chapter 10: Forms Revisited
353
PICKING DATES
WITH STYLE
FIGURE 10-2
jQuery UI’s Datepicker
widget is highly customizable. You can change
the number of months
visible at a time, place
the year before the
month name, and supply
different names for
months to match different
languages.
• changeYear. Like changeMonth, this option, when set to true, tells jQuery UI
to display a drop-down menu for selecting a new year for the calendar. You’ll
frequently use this option with the yearRange option (page 346) to set the
number of years to display in the drop-down menu.
changeYear : true
• dateFormat. Lets you supply a string that defines the format you want jQuery
UI to use when writing the selected date to the input field. You use predefined
codes to define different outputs. For example, dd is used to indicate day of the
month, mm the month of the year, and yy the year. You can also insert characters
like space, /, or - as part of the string. For example, say someone selects January
27, 2015 from the pop-up calendar, and you want this to appear in the actual
form as 01-27-2015. You’d set the dateFormat option like this:
dateFormat : 'mm-dd-yy'
jQuery UI supplies many different codes for formatting the date. For some
useful examples, see Table 10-1. You can find a complete list of formats jQuery
UI’s Datepicker widget accepts for the dateFormat option at http://api.jqueryui.
com/datepicker/#utility-formatDate.
NOTE
There are other options, events, and methods for jQuery UI’s datepicker widget. To see them all, visit
http://api.jqueryui.com/datepicker/.
• monthNames. Provide an array of 12 strings to use names other than English
months. For example, to make datepicker display French names of the month,
you’d add this to the object literal passed to datepicker() function:
monthNames: [ "Janvier", "Février", "Mars", "Avril", "Mai", "Juin",
"Juillet", "Août", "Septembre", "Octobre", "Novembre", "Décembre" ]
354
JAVASCRIPT & JQUERY: THE MISSING MANUAL
• numberOfMonths. Assign a number to this option to determine the number
of months visible in the pop-up date picker. Normally it’s a single month, but
you can specify whether you want to display more months. If you go beyond
three months (pictured in Figure 10-2), the datepicker pop up begins to be a
bit unwieldy. The months always appear side by side, so if there are more than
three or four, you’ll have to scroll sideways to see the other months and make
a selection in them. Stick to 1, 2, or 3.
PICKING DATES
WITH STYLE
• maxDate. Sets the latest date that a visitor can select from the datepicker popup calendar. For example, you could use this for a hotel reservation system.
Many hotels don’t let you reserve a room more than one year in advance, so
you could limit the datepicker to no further than one year from the current
date. One way is to assign a number specifying a number of days in the future.
For example, to limit a visitor from picking a day that’s later than 30 days in the
future, you could set the maxDate option like this:
maxDate : 30
Alternatively, you can give this option a string containing special characters
that indicate amounts of time—y for years, m for months, w for weeks, and d for
days. For example, to limit a selection to one year out or less, set the maxDate
option like this:
maxDate : '+1y'
Separate each time character by a space. So, for example, if you want to limit
the date selection to three months, two weeks, and five days into the future,
you’d do this:
maxDate : '+3m +2w +5d'
You’ll find an example of the maxDate option in action in the tutorial on page 359.
• minDate. The opposite of the maxDate option. It sets the earliest selectable date
from the datepicker. This setting is very useful for a scheduling form—after all
there’s no point in letting a visitor schedule a reservation that’s before today
(unless time travel has been discovered since this book was written). You use the
same characters as maxDate to specify the earliest date. For example, to prevent
people from selecting a date earlier than today, set this option to 0, like this:
minDate : 0
Positive values for this option mean the visitor has to select a day in the future.
For example, if the hotel is booked for the next three weeks, you can prevent
a visitor from selecting a date in that time like this:
minDate : '+3w'
Chapter 10: Forms Revisited
355
PICKING DATES
WITH STYLE
Use negative values to set the earliest selectable date in the past. For example,
say you’ve created a form for searching your company’s database of archived
email. To keep the database from bursting at the seams, your company only
stores the past two years’ worth of email records, so there’s not point in letting
people search three, four, or five years in the past—those emails were erased a
long time ago. Here’s how to limit the search to just the past two years:
minDate : '-2y'
You can combine dates, months, and years as well. For example, here’s how to
specify a date that’s one year, two months, and three days in the past:
minDate : '-1y -2m -3d'
NOTE
The minDate and maxDate options also accept a JavaScript date object as an acceptable value.
For example, say your company started business on March 13, 2010. You could set the minimum selectable date
for a datepicker calendar to that date like this:
minDate : new Date(2010, 2, 13)
See page 568 to learn how to create date objects using JavaScript.
• yearRange. This option is used with the changeYear option (page 354), and
determines how many years are displayed in the drop-down year menu. For
example, say you want to collect someone’s date of birth. You set the changeYear
option to true so it’s easy for a visitor to jump back 20, 30, or 50 years. Normally, the changeYear option forces that drop-down menu to show 10 years in
the past and 10 years in the future. It would be better to list a lot of years in the
past and no years in the future (unless, again, time travel has been perfected).
To do that, you give the yearRange option a positive or negative number, followed by a colon, followed by another positive or negative number. The first
number represents the first year listed in the menu, and the second number is
the last year in the menu.
Back to the birth year example, you’d want to be able to list perhaps 120 years
back, but no years in the future. Here’s how:
yearRange : '-120:0'
This setting tells jQuery UI to display a drop-down menu to select a year, with
the first year on the list 100 years before this year and the last year on the list
the current year. If you’re getting confused, check out the tutorial on page 359
for an example.
356
JAVASCRIPT & JQUERY: THE MISSING MANUAL
TABLE 10-1 Useful strings for supplying to the dateFormat option.
EXAMPLE
WHAT IT MEANS
EXAMPLE OUTPUT
'yy-mm-dd'
Complete year, dash, 2 digit
month, dash, 2 digit day. This
is the format used for a date
in MySQL databases.
2015-02-05
'm/d/y'
1 or 2 digit month, forward
slash, 1 or 2 digit day, forward slash, 2 digit year
2/5/15
'D, M d, yy'
Abbreviated day-of-theweek name, comma, space,
abbreviated month name,
space, 1 or 2 digit day,
comma, space, complete
year.
Thu, Feb 5, 2015
'DD, MM dd, yy'
Full day-of-the-week name,
comma, space, full month
name, space, 1 or 2 digit day,
comma, space, complete
year.
Thursday, February 5, 2015
'@'
Unix timestamp. The
number of milliseconds since
midnight on January 1, 1970
(see page 570).
1423123200000
PICKING DATES
WITH STYLE
Tutorial: Adding a Birthdate Picker
It’s time to try out the Datepicker widget. In this tutorial, you’ll turn a text field into
an intelligent device for easily selecting a person’s birthdate.
NOTE
See the note on page 12 for information on how to download the tutorial files.
1. In your text editor, open the file birthdate.html in the chapter10 folder.
This file already contains a link to all of the jQuery and jQuery UI files and the
$(document).ready() function (page 160). The first step is selecting the input
element.
2. Inside the $(document).ready() function, type:
$('#dob')
If you look at the HTML for this page, you’ll see an input element for collecting
a birthdate: . It has an ID of
dob, so this code selects that form field. Now you need to apply the Datepicker
widget.
Chapter 10: Forms Revisited
357
PICKING DATES
WITH STYLE
3. Type a period, followed by datepicker(); so the code now looks like this:
$('#dob').datepicker();
That’s all there is to it!
4. Save the file and preview it in a web browser. Click the input field.
A calendar pops up like magic. This calendar uses jQuery UI’s UI Lightness theme,
but you’ll learn how to change the widget’s appearance in the next chapter.
If you try to select your birthdate, you’ll see it’s kind of a pain. You have to hit
the left arrow button at the top of the calendar 12 times just to go back one year!
So you’ll make it easier to select an older date by adding drop-down menus for
the month and year.
5. Return to your text editor, and in the datepicker() function, add an object
literal, like this:
$('#dob').datepicker({
});
To change options, you pass the datepicker() function an object—{ }—filled with
options, names, and values. First, add a drop-down menu for selecting months.
6. Add changeMonth : true to the object:
$('#dob').datepicker({
changeMonth : true
});
If you save the page now, preview it in a web browser, and click inside the form
field, you should see a drop-down menu in the calendar’s header that lets you
select any of the 12 months of the year. This menu provides a much faster way
to select a date that happened 9 months ago.
Next you’ll create a drop-down for the year.
7. Type a comma after the line you just typed, hit Return, and type changeYear
: true:
$('#dob').datepicker({
changeMonth : true,
changeYear : true
});
This adds another drop-down menu to the calendar. Unfortunately, that menu
only goes back 10 years and also includes the next 10 years, which isn’t what
you want. Unless your visitor is younger than 10 or owns a time machine, the
choices in this drop-down menu aren’t going to be of much use. Fortunately,
you can change the range of years that appear in the menu.
358
JAVASCRIPT & JQUERY: THE MISSING MANUAL
8. Type a comma after the line you just typed, hit return and type yearRange
: '-120:+0':
PICKING DATES
WITH STYLE
$('#dob').datepicker({
changeMonth : true,
changeYear : true,
yearRange : '-120:+0'
});
This changes the years displayed in the year drop-down menu. It now goes
back 120 years and doesn’t display any years after the current one. Much better. However, if you give this latest change a try, you’ll notice that it is possible
to select tomorrow, or a date next week or next month. At the very least, you
want to limit this form to babies that were born today.
9. Type another comma after the line you just typed, hit return and type
maxDate : 0 like this:
$('#dob').datepicker({
changeMonth : true,
changeYear : true,
yearRange : '-120:+0',
maxDate : 0
});
Now you can’t pick a date beyond the current one. Finally, you’ll change the
format of the date, so birthdates are written like this: 1-27-2015.
10. Type another comma after the line you just typed, hit Return, and type
dateFormat : 'm-dd-yy' like this:
$('#dob').datepicker({
changeMonth : true,
changeYear : true,
yearRange : '-120:+0',
maxDate : 0,
dateFormat : 'm-dd-yy'
});
Now you have a highly customized date picker, perfect for selecting birthdates.
11. Save the file and preview it in a web browser.
When you click in the input field the final date picker appears (see Figure 10-3).
You can find a complete version of this tutorial in the complete-birthdate.html
file in the chapter10 folder.
Chapter 10: Forms Revisited
359
STYLISH
SELECT MENUS
FIGURE 10-3
jQuery UI’s Datepicker
widget is a must-have for
any form that requires
inputting a date. You can
customize it in almost
infinite ways to select
dates in the future, or
limit a selection to just
dates in the past. In this
case, any date after July
12, 2014 is grayed-out and
therefore not selectable,
but drop-down menus
make it easy to select a
year long in the past and
a month far from July on
the calendar.
Stylish Select Menus
jQuery UI’s themes let you add a unified design to your user interface elements. For
example, the date picker looks similar to tabbed panels, which look similar to dialog
boxes. Select menus—those form elements that let you pick an option from a dropdown menu—are notoriously hard to style with CSS. Each browser has its own way of
displaying select menus—which is often dictated by the operating system (Windows,
Mac, Linux)—and browsers don’t let you apply every CSS property to select menus.
Fortunately, jQuery UI provides a handy Selectmenu widget which takes a regular
HTML select menu and converts it into a much more attractive menu that matches
the look of other jQuery UI widgets (see Figure 10-4). The Selectmenu widget literally
re-creates the select menu as an unordered list and a series of tags, which
360
JAVASCRIPT & JQUERY: THE MISSING MANUAL
are more accepting of CSS styling. Using clever JavaScript programming, this widget
hides the real menu, while letting visitors select an option from a JavaScript-powered
drop-down menu. The visitor’s selection is mirrored by the real form element, so
when the visitor submits the form, the visitor’s selection is correctly passed to the
web server.
STYLISH
SELECT MENUS
Behind the scenes, jQuery UI is performing some sophisticated programming magic,
but for you, turning a select menu into a jQuery UI select menu couldn’t be simpler:
1. Follow the steps on page 304 to attach jQuery UI’s CSS and JavaScript files
to your web page.
You’ll need to attach the jQuery file as well, so whenever you use a jQuery
UI widget, you’ll have the jQuery UI CSS, jQuery JavaScript, and jQuery UI
JavaScript files attached to your page (in that order, too).
2. Add a form to a page, and include a select menu: that’s a
- tags in submenus ignore this rule.
The style sets each menu button to a set width, and then floats them side by
side. Then you need to set the width of the submenus.
3. Add another CSS style:
.ui-menu .ui-menu {
width: 10em;
}
This style sets the width of the submenus. jQuery UI gives each menu—
- tags that are directly children of the main
- tag within the menu—the main menu
and any submenus.
You can use any measure you’d like—em, px, %—but be careful using percentage.
A submenu takes its percentage value from its parent, so each submenu will get
progressively thinner. To get around this, set the submenu (which is actually an
- inside an
- ) to a 100% width (to match the parent menu). For example:
.ui-menu {
width: 25%;
}
.ui-menu .ui-menu {
width: 100%;
}
Add this CSS to your site’s custom CSS file—not to the jQuery UI CSS file. If
you decide to change the theme, or update jQuery UI to a newer version, any
changes you make to the jQuery UI CSS file will be wiped out by the update.
You’ll learn more about styling jQuery UI widgets in Chapter 11.
FIGURE 9-12
jQuery UI’s menu widget
makes it easy to create
a multi-level menu that
matches the look and
feel of the other jQuery
UI widgets. It’s great for
adding a menu to a web
application to make the
application feel more like
desktop software.
Chapter 9: Expanding Your Interface
345
ADDING MENUS
TO A PAGE
4. Select the outer
- tag and apply the menu() function:
$('#mainMenu').menu();
NOTE
You’ll find an example of the menu widget in the complete_menu.html file in the chapter09 folder.
As with other jQuery UI widgets, the menu widget includes several options for customizing its behavior and appearance. Pass an object literal to the menu() function
to control it:
• icons. As you can see in Figure 9-12, jQuery UI attaches small icons on the right
side of any menu button that has an attached submenu. The icon indicates to
visitors that there’s another menu hidden away in that button. jQuery UI includes
a large selection of icons as part of each theme (see http://api.jqueryui.com/
theming/icons/ for a complete list). You can swap in new icons by supplying an
icons option and a value that includes an object literal, like this:
icons : {
submenu: "ui-icon-circle-triangle-e"
}
Unfortunately, you can only specify one icon, so the icon used for buttons on
the main menu bar is also shared by submenus buttons that have their own
submenus.
• position. The position option controls where submenus are placed in relation
to their parent. Normally submenus are placed directly to the right of their parent
button, but you can change this using the jQuery UI position object discussed
on page 318. For example, if you want to place the submenu directly below the
button that opens it, you could set the option like this:
position : {
my: "center top",
at: "center bottom"
}
This translates to place “my” (the submenu) center and top, and “at” center
and bottom of my parent menu button. This technique is useful for creating
drop-down menus in a horizontal navigation bar as described on page 349.
Creating a Horizontal Navigation Bar
The jQuery UI menus weren’t intended to create a classical navigation bar like the
ones you see at the top of most websites. If that’s what you’re after, the SmartMenus
plug-in discussed on page 241 is probably a better bet. However, you can coax the
menu widget into a horizontal menu with a single drop-down menu with a little CSS
like the one shown in the top image in Figure 9-13.
346
JAVASCRIPT & JQUERY: THE MISSING MANUAL
ADDING MENUS
TO A PAGE
FIGURE 9-13
If you want to keep your
site’s user interface
looking consistent by
using jQuery UI’s CSS
and widgets throughout
your site, you can get a
fully functional horizontal
jQuery UI menu if you’re
willing to settle for only
one level of drop-down
menus (top). jQuery
UI’s Selectmenu widget
doesn’t work very well
if you’re interested in
a multilevel horizontal
menu (bot-tom). Because
all submenus are placed
in the same relationship
to their parent, you end
up with overlapping
submenus. You can see
examples of both types of
menus in the chapter09
folder: complete_
horiz_menus.html and
bad_horiz_menu_multilevel.html.
Multi-level drop-down menus don’t work well because the jQuery UI menu widget
places all submenus in the same position relative to their parents. With a vertical
menu (Figure 9-12), that works well: the submenus pop out to the right of their parent menu button. But with a horizontal menu bar, the first submenu usually appears
below its parent button (Figure 9-13, top) and sub-submenus appear to the right
of their parent. Unfortunately, with jQuery UI, if you place one submenu below its
parent all submenus are placed that way, so you end up with a confusing overlapping
mess of submenus, as pictured in the bottom image in Figure 9-13:
Chapter 9: Expanding Your Interface
347
ADDING MENUS
TO A PAGE
1. To create a horizontal menu, start with an unordered list of links, but add
only one level of nested unordered lists (the HTML example on page 344,
for instance).
Next, you need to add some CSS to make the main nav buttons sit horizontally.
You should put this CSS in the main style sheet for your site and not in the
jQuery UI CSS file.
2. Add CSS to float the top-level menu buttons so they appear side by side in
a horizontal bar:
#mainMenu > li {
width: 10em;
float: left;
}
This CSS selector—#mainMenu > li—selects all
makes it easier to identify. Add id="panel1" to the div, like this:You need to do this for the other panels as well. 5. Repeat step 4 for the last two panel divs (they are identified with HTML comments as well). Make sure you give each div an ID that matches the link from step 3. For example, the second panel’s div should be. Now let’s turn them into tabbed panels. 6. Inside the $(document).ready() function select the container and call the tabs() function: $(document).ready(function() { $('#tabContainer').tabs(); }); // end ready Save the file and preview it in a web browser. The page should look like Figure 9-10. If it doesn’t, check your browser’s console (page 18) and see if there are any JavaScript errors. If you don’t see any, check whether you typed the correct ID names for the container div and panels. Next, you’ll add some effects to the panel transitions by making them fade into view when they open and fade out when they close. 332 JAVASCRIPT & JQUERY: THE MISSING MANUAL 7. Add the following object literal (in bold) to the tabs() function: ADDING TABBED PANELS document).ready(function() { $('#tabContainer').tabs({ show: 'fadeIn', hide: 'fadeOut' }); }); // end ready This applies an effect to the panel transitions. You can try other effects like 'slideDown' and 'slideUp'. Save the page and preview it in a web browser. The tabbed panels work well, but there’s one problem with tabbed panels: the page always opens to either the first tab or one you specify using the active property (page 330). But what if you wanted to e-mail a link to the page and have a particular tab open from that link? For example, imagine you’re in customer service and a customer asks about the technical specs for a product your company sells. There’s a page for that product with the technical specs in a tabbed panel; the problem is that the “About this Product” panel appears whenever that page loads. What if you could just email a link like http://mycompany.com/productA. html#specs, and the tab with the technical specs opens when that link is followed. Well, you can, if you add a little JavaScript magic. The secret is pulling out that #specs from the URL and using it to trigger the panel. 8. After the tabs() function, add a new line and type var hash = location.hash;. The browser window provides what’s called a location object. This object holds lots of information about the URL of the current page, including the hostname (location.hostname), the entire URL (location.href), and other properties (visit https://developer.mozilla.org/en-US/docs/Web/API/Location for a complete list). The location.hash property returns just the part of the URL that includes the # part. For example, say you visited http://mycompany.com/productA.html#specs. The location.hash property for this URL is #specs. You’ll use the hash property to load a panel with a matching hash value. 9. After the code you just added, add a conditional statement, so your final code looks like this: $(document).ready(function() { $('#tabContainer').tabs({ show: 'fadeIn', hide: 'fadeOut' }); var hash = location.hash; if (hash) { $('#tabContainer').tabs('load', hash) } }); // end ready Chapter 9: Expanding Your Interface 333 ADDING TABBED PANELS This code first checks to see if a hash value exists—for example, if the visitor simply just visits the tabs.html page, there isn’t any hash value, so you can skip the rest of the code and just let the first panel load normally. However, if there is a hash value like #panel1, then the next bit of code runs. It simply selects the container again ($('#tabContainer')), calls the tabs() function, and passes two arguments. The first, load, is a command built into the jQuery UI program that tells the tabs function to load a panel. The second argument—hash—is the panel that should be loaded, either #panel1, #panel2, or #panel3 in this example. 10. Save the page and preview it in a web browser. The first panel should open. In the location bar, add #panel3 at the end of the URL (after the tabs.html). Then reload the page. The third panel should display. (If it doesn’t, try copying the URL in the location bar, opening a new tab or browser window and pasting it in.) A finished version of the file—complete_tabs.html—can be found in the chapter09 folder. FIGURE 9-10 The final web page showing the three tabbed panels. 334 JAVASCRIPT & JQUERY: THE MISSING MANUAL ADDING TABBED PANELS POWER USERS’ CLINIC jQuery UI’s Custom Events You learned about browser events like click, mouseover, focus, and resize on pages 148-152. These events are built into browsers and triggered when visitors take certain actions on a page, like click a link or submit a form. Events are useful because they let you write programs that respond to things that are happening on the page. $('#tabContainer').tabs({ beforeActivate: function(evt) { location.hash=$(evt.currentTarget). attr('href'); } }); jQuery UI widgets are programmed with their own custom events—they’re not exactly like the kinds of browser events you’re used to, however. Widget events are simply moments during the creation, execution, or completion of a widget component. There’s a lot going on here, but in a nutshell, you find the href attribute of the tab the visitor clicked (#panel, #panel2, or #panel3) and store it to the location’s hash property (see step 8 on page 333 for more on the hash property). You can find a working copy of this code in a file named complete_tabs_with_custom_event.html in the chapter09 folder. For example, the tabs widget provides a beforeActivate event that lets you run some code right before jQuery UI makes a hidden panel visible. This would come in handy if you wanted to trigger some other action each time a tab is clicked. For example, you could use the beforeActivate custom event to update the URL in the browser’s location bar each time a tab is clicked, so the URL would add the # of the proper panel to the filename—tabs.html#panel3, for instance. Used in conjunction with a conditional statement like the one added in step 9 on page 333, you can provide a way for users to bookmark a custom URL that would display the proper panel each time that bookmark was loaded. To do that, you’d add the beforeActivate property to the tabs() function with a function as a value, like this: Like the tabs widget, each jQuery UI widget gives you lots of ways to do things as the widget is being created, modified, or destroyed. Programmers call these hooks because they let you attach your own programming to the programming already existing in jQuery UI. This is a complex topic, but fun to explore. The best way to learn about these custom events is to visit the API page for each widget (API stands for application programming interface and represents all the properties and functions that you can access as a programmer). At the top of each page there’s a QuickNav box that lists all the custom events the widget supports. For example, the dialog widget’s API page ( http://api.jqueryui.com/dialog/ ) lists 11 different events you can hook into! Tabs with Remote Panel Content jQuery UI even lets you pull in content for tabbed panels from other web pages. In other words, instead of creating an unordered list of links which link to divs within the page, you can create an unordered list of links that point to other pages (or to content that’s generated by a web server). You might want to take this approach if the content in each tab is constantly changing (stock prices, reviews, forum posts). By linking to dynamically created content—for example, information drawn from a frequently updated database using a technology like PHP, .NET, or Ruby On Rails— you can be assured that the content inside the panel is up-to-date. To load panel content from other pages or web server requests, simply create a containing div, an unordered list with links to other pages, and call the tabs() function. For example, say you wanted each panel to include content from a separate Chapter 9: Expanding Your Interface 335 ADDING TABBED PANELS web page. Those pages are named panel1.html, panel2.html, and panel3.html. You’d add this HTML to your page: If you’re linking to dynamic data, you might not be pointing to a web page, but to content generated by a server-side language like PHP: When linking to external web pages, you don’t need to include the panel divs as in step 3 on page 332. jQuery UI will automatically create those divs when the tabbed panels are created. To create the tabbed panels, simply select the container div and call the tabs() function: $('#tabContainer').tabs(); When this code runs, jQuery UI will fetch the HTML from the web page that’s linked to the first visible panel. For example, given the code on above, when the page loads, jQuery UI will load the HTML from the panel1.html file and display it in a panel below the tabs. When someone clicks the second tab, jQuery UI will request the HTML from the second link and create a new panel to place that HTML into. In most cases, you can even link to an external website like Google, Wikipedia, or a server other than the one the tabbed panel page comes from. However, sites can block this process, and then content like web fonts, images, and videos won’t load. There’s another problem with this approach: all of the content of the linked to the page will appear in the panel. So if you link to a complete HTML file with a, tag, and links to CSS and JavaScript files, all of that will be loaded as well. You end up with a page within a page. If all you want is a chunk of HTML content in a panel, there are two solutions. The easiest way is to create page fragments—HTML files that contain only the HTML you wish to appear in the panel. You can easily make a fragment if you’re loading data dynamically from the server—your server-side script only needs to spit out the content that should appear in the panel (and not all the other stuff like the tag required by a full web page). 336 JAVASCRIPT & JQUERY: THE MISSING MANUAL Alternatively, you can let the panel load a full web page and extract only the content you want to appear in the panel using a custom event (see the box on page 335). Here’s how it works: jQuery UI tabbed panels include an event called load. This event lets you run a function immediately after jQuery UI loads content from a remote source. You can use jQuery to find just the content you want, extract it, and place it inside the panel. This method is a little complex, but it doesn’t require a lot of code. ADDING TABBED PANELS First, you need to make sure there’s a way to select specific content from the remote page. An easy way to do this is to wrap the content you want in the panel in a tag with an ID—, for example. With that in place, you now have a way to select just that content and not unnecessary HTML like the ortags. Then, you need to pass a load option to the tabs() function. The load option is the custom event, and you supply an anonymous function (page 138) that tells jQuery UI what to do when it’s received content from the remote page and placed it into a panel. When the load event is triggered, jQuery UI has already created a new tab and inserted the HTML from the remote page into it. At this point, the new panel has all the extra HTML you don’t want. However, you can use jQuery to quickly remove that new HTML and replace it with the stripped-down HTML. It happens so fast, this quick change of content isn’t even displayed in the browser. Here’s an example: $('#tabContainer').tabs({ load: function(evt,ui) { var newHTML = ui.panel.find('#panelContent').html(); ui.panel.html(newHTML); } }) Lines 2-5 are the load option. jQuery UI provides two pieces of information to its custom events (those are evt and ui in line 2). The first, evt, is a regular jQuery event object (page 164). You can use any of the event properties and methods discussed on pages 165-167. In this case, you’re interested in the second argument passed to the load event’s anonymous function: ui. The ui object represents the currently updated user interface element. For tabbed panels, there’s a ui.panel object and ui.tab object. The ui.panel object represents the newly created panel (the that jQuery UI creates when it loads the external web page). In line 3, you create a new variable—newHTML—to hold the final panel content (without the extra HTML like ). When jQuery UI creates the new panel, it loads the entire HTML content from the requested page, so you can look inside that panel and get just the HTML you’re after. The ui.panel.find('#panelContent') part gets the new panel HTML and looks inside it for an element with the ID of panelContent (jQuery’s find() method is described on page 531). Then, the html() method (page 119) kicks in and extracts the HTML from just that one part of the page. In other words, you’ve just collected the small amount of HTML you’re interested in and stored it into a variable named newHTML. Chapter 9: Expanding Your Interface 337 SAVING SPACE WITH ACCORDIONS NOTE You can find an example of using separate web pages for panel content in the remote_tabs.html file located in the chapter09 folder. The file also uses the load custom event to strip out unwanted HTML. In line 4, you simply replace the HTML in the panel (that’s the old HTML, complete with ,, and other unwanted tags) with the new HTML (only the HTML you need for the new panel). This code runs so quickly that the browser never even displays the full web page inside the panel—the visitor will only see the lean, stripped-down HTML you’re after. Saving Space with Accordions jQuery UI accordions, like tabbed panels, are another space-saving user interface device. See the bottom image in Figure 9-11 for an example. But instead of being controlled by a line of tabs along the top, each accordion panel has a clickable headline used to hide and close the accordion panel. The accordion headlines open the panel directly below it and close any currently opened panel. In other words, only one accordion panel is opened at a time. In general, accordions work much the same way as tabs. Most of the options are the same and work the same way as tabs, but the HTML structure is very different. With accordions, you need just three components: • Enclosing that holds the accordion. You need to select the div with jQuery, so add an ID or class to the div so you can select it and apply the Accordion widget to it. • Headline containing text. This headline is the clickable control that opens and closes accordion panels (for example, the blue headline “What does the robot say” in Figure 9-11). It doesn’t matter which level of headline you use—,
, and so on. Just use the same one for each accordion group. (Technically you don’t even have to use a headline tag—any block level tag works—but headlines are the most commonly used.) • Block-level element immediately following the headline. Usually this is a
tag filled with the content you wish to show and hide. This div must go directly after the headline. 338 JAVASCRIPT & JQUERY: THE MISSING MANUAL SAVING SPACE WITH ACCORDIONS FIGURE 9-11 Now you see it, now you don’t. jQuery UI can transform a simple collection of headlines andtags (top) into an interactive presentation of collapsible panels (bottom). Chapter 9: Expanding Your Interface 339 SAVING SPACE WITH ACCORDIONS The headline and following div element represent one part of an accordion. To add more accordion elements, add more headline/div pairs. For example, the basic HTML structure of a three-panel accordion looks like this:Trigger for first accordion panel
Trigger for second accordion panel
Trigger for third accordion panel
tag. Notice that there’s a
tag—that’s a container element that holds the items for the accordion. Inside that div you’ll see antag followed by a
tag. Therepresents the accordion label and the
, the accordion panel. In the HTML for this page, there are three of these/
pairs, so once you add the programming, you’ll have three accordion panels. First, you need to give jQuery a “hook” for selecting the accordion container. 3. Locate thetag below thetag and add an ID:
This is all the HTML you need to add accordions to the page. Now it’s time to add the programming. 4. Inside the $(document).ready() function, select the container and call the accordion() function: $(document).ready(function() { $('#accordion).accordion(); }); // end ready Save the file and preview it in a web browser. The page should look like the bottom image in Figure 9-11. See why it’s called a “mini” tutorial? jQuery UI makes it that simple. But you’re not done yet. You want to make it so that all of the accordion panels are closed when the page loads. 5. Add the following object literal (in bold) to the tabs function: $(document).ready(function() { $('#accordion').accordion({ 342 JAVASCRIPT & JQUERY: THE MISSING MANUAL ADDING MENUS TO A PAGE active: false, collapsible: true }); }); // end ready Preview the page in a browser, and you’ll see that all of the accordion panels begin in the closed position. Click one of the headers to open a panel; click that same header again to close the panel. Accordion panels only close when their associated headline is clicked if the collapsible option is set to true. Let’s choose some different icons from jQuery UI’s large selection of icon elements (http://api.jqueryui.com/theming/icons/). 6. Add an icons property to the accordion options object. The value of this option will be another object literal with two properties: $('#accordion').accordion({ active: false, collapsible: true, icons : { header: 'ui-icon-circle-plus', activeHeader: 'ui-icon-circle-minus' } }); Don’t forget to add a comma after true on line 3. As you can see, JavaScript lets you nest object literals inside of other object literals. Sometimes this kind of code can get a little hard to read, but keep in mind that you can just treat an object literal like any other object—a variable, number or string, for example— and use it as a single value for a variable or object property. 7. Save the page and preview it in a web browser. The page should look like the bottom image in Figure 9-11. If it doesn’t, doublecheck your code against what’s printed in step 4 above. A finished version of the tutorial—complete_accordion.html—is located in the chapter09 folder. Adding Menus to a Page jQuery UI also includes a Selectmenu widget that makes it very easy to convert an unordered, nested list of links into a menu with fly-out submenus. It’s intended to present a vertical menu bar, with menu items listed on top of each other, and submenus appearing to the right (Figure 9-12). However, if you’ll settle for a single set of submenus, it’s possible to coax the Selectmenu widget to a horizontal orientation for the menu’s top level. As with all of the jQuery UI widgets, menus are really simple to use. The hardest part is structuring your HTML, and even that isn’t hard. In fact, you’ve already seen the same structure in the SmartMenus plug-in on page 241. You start with a simple Chapter 9: Expanding Your Interface 343 ADDING MENUS TO A PAGE unordered list of links—these are your top-level menu buttons, the ones that you see when the page loads. If you want to add a pop-out menu to one of those buttons, simply nest another unordered list inside the top-level button’s - tag to the second panel, and so on. In order to make these links work, you need to add the matching IDs to the panel divs. 4. Locate the