Applied jQuery DEVELOP AND DESIGN
Jay Blanchard
Applied jQuery: Develop and Design Jay Blanchard
Peachpit Press 1249 Eighth Street Berkeley, CA 94710 510/524-2178 510/524-2221 (fax) Find us on the Web at: www.peachpit.com To report errors, please send a note to:
[email protected] Peachpit Press is a division of Pearson Education. Copyright © 2012 by Jay Blanchard Editor: Rebecca Gulick Development and Copy Editor: Anne Marie Walker Technical Reviewer: Jesse R. Castro Production Coordinator: Myrna Vladic Compositor: Danielle Foster Proofreader: Patricia Pane Indexer: Valerie Haynes-Perry Cover design: Aren Straiger Interior design: Mimi Heft
Notice of Rights All rights reserved. No part of this book may be reproduced or transmitted in any form by any means, electronic, mechanical, photocopying, recording, or otherwise, without the prior written permission of the publisher. For information on getting permission for reprints and excerpts, contact
[email protected].
Notice of Liability The information in this book is distributed on an “As Is” basis, without warranty. While every precaution has been taken in the preparation of the book, neither the author nor Peachpit Press shall have any liability to any person or entity with respect to any loss or damage caused or alleged to be caused directly or indirectly by the instructions contained in this book or by the computer software and hardware products described in it.
Trademarks Many of the designations used by manufacturers and sellers to distinguish their products are claimed as trademarks. Where those designations appear in this book, and Peachpit was aware of a trademark claim, the designations appear as requested by the owner of the trademark. All other product names and services identified throughout this book are used in editorial fashion only and for the benefit of such companies with no intention of infringement of the trademark. No such use, or the use of any trade name, is intended to convey endorsement or other affiliation with this book. ISBN 13: 978-0-321-77256-5 ISBN 10: 0-321-77256-3 987654321 Printed and bound in the United States of America
To Mom, who taught me there was magic in books, and to Dad, who taught me there was magic in me.
ACKNOWLEDGMENTS
Projects like this are not possible without the support and understanding of a lot of people, something I really didn’t understand when first embarking on the journey to create a book. Saying “thank you” isn’t nearly enough, but I hope that you all understand how much I appreciate you! Even with the blender of life roaring around us, Connie Kay, Kaitlyn, Brittany, Zach, Karla, and Morgan provided more love and support than you can imagine. I love you all! To Rebecca Gulick, thank you for believing in me and helping a dream to come true! To Anne Marie Walker, enough cannot be said about your gentle firmness, guidance, and subtle humor. I am eternally grateful to you! To Jesse Castro, thanks for keeping me on the straight and narrow. Your insight, technical abilities, and encouragement blow me away! To Larry Ullman, thanks for being the Ford Prefect to my Arthur Dent and guiding me through the galaxy! I kept my towel on my desk the whole time! To Francis Govers, the twists and turns in my life are made all the more bearable by knowing that you are just a phone call or an e-mail away. Best friends don’t get any better! To the folks who have made up the teams of developers that I have worked with day in and day out, thank you for making me a better programmer and a better person! Your willingness to look over my shoulder and teach me something new is treasured beyond measure. To the jQuery community, you are an amazing group of people, and I am honored to share electrons with you!
IV
APPLIED jQUERY: DEVELOP AND DESIGN
CONTENTS
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . viii Welcome to jQuery . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xi CHAPTER 1
INTRODUCING JQUERY . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . XIV Making jQuery Work . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 Working with the DOM. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 Learning a Few jQuery Tips . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 Selecting Elements Specifically . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 Making Quick Work of DOM Traversal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 Troubleshooting with Firebug . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 Packing Up Your Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 Using Return False . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .15 Fiddling with jQuery Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 Combining jQuery with Other Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 Starting with HTML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .18 Styling Web Pages with CSS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .18 Using PHP and MySQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .18 Progressive Enhancement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 Planning Design and Interaction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 Wrapping Up . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
CHAPTER 2
WORKING WITH EVENTS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24 Using the Photographer’s Exchange Web site . . . . . . . . . . . . . . . . . . . . . . . . .26 Making Navigation Graceful . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 Creating and Calling Modal Windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 Binding Events to Other Elements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 Building an Image Carousel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 Creating Sprite-based Navigation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50 Wrapping Up . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
CHAPTER 3
MAKING FORMS POP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58 Leveraging Form Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60 Focusing on a Form Input . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60 Validating Email Addresses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62 Making Sure an Input Is Complete . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66 Tackling Uploads . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .69 Performing Client-side Validation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
CONTENTS
V
Developing Server-side Validation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72 Uploading Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .74 Wrapping Up . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89 CHAPTER 4
BEING EFFECTIVE WITH AJAX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90 Using AJAX for Validation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92 Building the PHP Registration and Validation File . . . . . . . . . . . . . . . . . . . . 92 Setting Up the jQuery Validation and Registration Functions . . . . . . . 100 Logging in the User . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105 Using AJAX to Update Content . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108 Getting Content Based on the Current User . . . . . . . . . . . . . . . . . . . . . . . . . . 108 Loading Content Based on Request . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110 Loading Scripts Dynamically . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112 Using jQuery’s AJAX Extras . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116 Using JSON . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126 Securing AJAX Requests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134 Preventing Form Submission . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135 Using Cookies to Identify Users . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139 Cleansing User-supplied Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141 Transmitting Data Securely . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144 Wrapping Up . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145
CHAPTER 5
APPLYING JQUERY WIDGETS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146 Using the jQuery UI Widgets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .148 Customizing the jQuery UI. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148 Including jQuery UI Widgets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152 Using jQuery Plugins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171 Beefing Up Your Apps with Plugins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172 Pumping Up Your Sites . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188 Rolling Your Own Plugins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200 Wrapping Up . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203
CHAPTER 6
CREATING APPLICATION INTERFACES . . . . . . . . . . . . . . . . . . . . . . . . 204 Establishing the Foundation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 206 Creating the HTML. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 207 Applying the CSS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209 Making the Interface Resizable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 214
VI
APPLIED jQUERY: DEVELOP AND DESIGN
Improving the Application Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217 Creating Better Sprites . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217 Loading Content with AJAX. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 226 Configuring Additional Enhancements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235 Wrapping up . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 247 Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 248
CONTENTS
VII
INTRODUCTION
As Web designers, you are painstakingly compelled to grab Web surfers’ attention as quickly as possible and then keep them on your site to absorb the content. In addition to the product, service, or information that you are providing, the site must be visually attractive and offer stimulating (and valuable) interaction. The jQuery library is the main ingredient for providing the icing on your Web-site cake. If applied well, the effects of jQuery will convince visitors and application users to click around and sample all of your content. The trick is learning how to combine jQuery with other markup and languages effectively. You must gain knowledge in a wide range of disciplines, like HTML (HyperText Markup Language) and CSS (Cascading Style Sheets), to know how to properly mix in the right amount of jQuery. The goal of this book is to give you the knowledge to bring the HTML, CSS, and jQuery ingredients together to create compelling interactivity to your Web sites and applications. Throughout the book, I’ll also show you ways to use PHP, a popular serverside scripting language, and MySQL, a relational database product, to enhance your overall development and supercharge your applications. Both technologies translate easily to other Web development languages.
WHAT IS JQUERY? Announced in 2006 by its creator, John Resig, jQuery quickly gained popularity and support as a new way to use JavaScript to interact with HTML and CSS. jQuery’s simple selectors mimicked CSS selectors, making the library familiar and easy to learn for designers and developers alike. The jQuery library erased the worry that Web developers had suffered through when trying to create interactive sites across a wide range of browsers by handling most browser compatibility issues behind the scenes. Topping off those two features is the shortened syntax used by jQuery. The following example shows how you would select an element based on its id attribute using jQuery: $(‘#foo’);
VIII
APPLIED jQUERY: DEVELOP AND DESIGN
The jQuery selector is much shorter as opposed to the same example in oldschool JavaScript: document.getElementByID(‘foo’);
It’s no wonder that the Web-development community embraced jQuery’s “write less, do more” mantra. Couple the simplicity of jQuery with its ability to support complex animations and achieve stupendous effects, and you get a JavaScript library that is flexible and capable of empowering you to provide your Web site visitors with an outstanding interactive experience.
WHO THIS BOOK IS FOR This book is aimed at beginning to intermediate Web developers, but it doesn’t matter where you are in your journey as a designer or developer. You should find examples in this book that will help you to bring your Web pages and applications to life with jQuery. It helps if you have a basic knowledge of HTML, CSS, JavaScript, and jQuery, but it is not necessary because the examples are fully baked and ready to go.
WHAT I USED As of this writing, jQuery 1.5 had been released and is used for all of the examples in the book. You can download it at www.jquery.com. It is also available on the book’s Web site atwww.appliedjquery.com. HTML, CSS, and JavaScript files are all plain-text files that you can create and edit in any plain-text editor. Examples were all tested in Firefox 3 and Internet Explorer 8, with an occasional peek in Safari and Google Chrome.
WHERE TO FIND THE CODE All of the code examples for the book are available from the Applied jQuery Web site at www.appliedjquery.com/downloads. There you can download a Zip file containing all of the examples, graphics, and other collateral needed to follow along. The examples are arranged by chapter within the Zip file and include all of the necessary jQuery files to make the examples work right out of the box.
INTRODUCTION
IX
However, even though all of the files are available for download, I encourage you to type out each example as you progress through the book. Taking a hands-on approach will help you to learn how all of the technologies fit together and will reinforce the concepts in your brain.
LET’S GET STARTED It’s time for you to jump right in and get started learning how to use jQuery. In the first chapter I’ll give you some good rules and tools to get you headed in the right direction for sweetening your Web development efforts with jQuery.
X
APPLIED jQUERY: DEVELOP AND DESIGN
i WELCOME TO jQUERY
WELCOME TO jQUERY jQuery is one of the most popular JavaScript libraries in use today because it lets you build JavaScript Web pages and Web applications quickly and easily, accomplishing in a single line of code something that would have required dozens of lines of JavaScript code. Grab yourself a computer and the handful of tools outlined below, and then dig into the following six chapters.
XII
jQUERY
jQUERY UI
TEXT EDITOR
jQuery, which is free to download and use, comes in the form of a single .js file that you link to from your Web page, and your code accesses the library by calling various jQuery functions. Go to jquery. com and download the jQuery library.
Next, you’ll want to download the jQuery UI library from jQueryUI.com. This will equip you with some core interaction plugins as well as many UI widgets that I’ll discuss later in the book.
You’ll be doing some scripting, so get yourself a good text editor. Windows users typically opt for Microsoft Notepad or Notepad++, while Mac users often rely on BBEdit from Bare Bones Software.
APPLIED jQUERY: DEVELOP AND DESIGN
BROWSER
TROUBLESHOOTER
Chances are you’ve already got a standardscompliant browser installed. Popular options are the latest versions of Microsoft Internet Explorer, Mozilla Firefox, Apple Safari, Google Chrome, and Opera.
I rely heavily on the Firebug Web development tool for troubleshooting. Go to http://getfirebug. com and get a version that’s specific to your browser. It’s 100% free and open source, and you’ll be grateful you’ve got it installed when something goes wrong.
TESTING ENVIRONMENT Rather than using an actual hosted Web site to test your jQuery creations, use a testing environment that’s local on your own computer. I use XAMPP, which you can download from http://apachefriends.org.
WELCOME TO jQUERY
XIII
1 INTRODUCING jQUERY
Rich, interactive Web sites that use semantic markup and unobtrusive technologies like Cascading Style Sheets (CSS) and JavaScript are becoming the de facto standard in Web development. Designers and developers are looking for new and better ways to bring their creations to life, and libraries like jQuery make this goal easily attainable. To get started properly with jQuery, you need to equip yourself with the appropriate tools and concepts. So, I’ve gathered those tools for you and will help you to learn how to use them. This chapter will give you a firm grasp of the basics of jQuery and the tools that will make working with jQuery straightforward. Also included are some tips for getting the most out of jQuery. But first things first; let’s start with a “Hello World” example jQuery style.
MAKING jQUERY WORK
The strength of the jQuery library is its ability to interact with elements in your Web pages that you are already familiar with. Markup tags, class declarations, and attribute information in your Web pages can be easily connected to jQuery by using the simple concept of selectors. A jQuery selector will wrap an element or set of elements into an object. Once you have created the jQuery object, you can effectively apply a multitude of jQuery methods to that object to create animations, send information to and from the server, or perform object manipulation. No book on programming is worth its salt if it doesn’t have a “Hello World!” example. To illustrate the power and flexibility of jQuery’s selectors, let’s create a “Hello World!” example. NOTE: The Hello World code is the only code example not available in the download from the book’s Web site. The reason is that I think it is very important that you type this one in yourself. Comments are also included in the example.
1. Start by establishing the basic markup for the HTML page: <meta charset=”utf-8” /> Hello World - jQuery Style
2. Be sure to include the jQuery source file. Without this file none of the jQuery code will operate: <script type=”text/javascript” p src=”jquery-1.5.min.js”>
3. Open a script tag to give the jQuery code a place to live within the page: <script type=”text/javascript”>
2
CHAPTER 1
INTRODUCING jQUERY
4. The jQuery functions that you are creating need to be available to run after the Web page has finished loading all of its elements. To accomplish this, you wrap the jQuery code in a document ready function. Just as it implies, the code wrapped in the function becomes available to run when the Web document is ready: $(document).ready(function() {
5. Create the first selector. This selector will get the markup element in the page having an id attribute equal to first. All id attributes are selected in jQuery (and CSS) by prepending the hash (#) sign to the information contained within the id attribute. You’ll follow the selector with jQuery’s html method by chaining the html method to the selector. This method will place the markup Hello World! into the selected element: /* write ‘Hello World! to the first div */ $(‘#first’).html(‘Hello World!’);
Chaining is the term used to describe applying one or more methods to jQuery objects. Chaining gives you a wide variety of possibilities to combine methods to create unique interactions for your Web-site visitors. 6. For this example, you’ll create one additional method that connects, or binds, an event handler to a selector to create an action. The event handler will accept an action and perform additional jQuery functions to other selected elements. Start this portion of the example by binding jQuery’s click handler to an element with an id of link: /* a clickable ‘Hello World!’ example */ $(‘#link’).click(function() {
The click method exposes a handler function that allows you to build a string of actions that will be triggered by the click method. 7. Set up a selector for the element with an id of greeting and apply the html method to it: $(‘#greeting’).html(‘Hello Again!’);
MAKING jQUERY WORK
3
8. Close out the jQuery code with the proper braces, brackets, and script tags: }); });
Pay close attention to braces and brackets when you create jQuery code. It is critically important that each opening bracket or brace have a matching closing bracket or brace. 9. Finish up the head section of the markup and open the body of the Web page:
10. Create an HTML div with an id of first. The initial jQuery selector that you created previously will interact with this element, adding the HTML markup that was specified between the div tags:
11. Create another HTML div with an id of second. You did not write any selectors for this element; it is just being used as a container for other elements:
12. Create an anchor tag and give it an id of link. You wrote jQuery code earlier that will handle the link when it is clicked by a user: Click Me!
13. Create a span element with an id of greeting. When the link is clicked, the selector for greeting will apply the HTML markup you specified between the span tags: <span id=”greeting”>
14. Complete the page by closing out the markup tags properly:
4
CHAPTER 1
INTRODUCING jQUERY
FIGURE 1.1 The “Hello World!” message appears when the page loads, and the “Hello Again!” message appears when the link is clicked.
15. Save the file as hello_world.html and load it into your Web browser. If you have been diligent with your typing, you will be rewarded with a Web page identical to the one shown in Figure 1.1. This example is just a small taste of how you can connect jQuery to elements in your Web pages to provide information and interactivity. The example also demonstrates how you can add elements to your Web pages using jQuery. To work with jQuery effectively, you need to know how to work with all of the elements in a Web page and how they are assembled into a document. A document? That is absolutely correct: Web pages are documents that are intended for display in Web browsers. Because Web pages are documents, they follow some of the same rules that paper documents follow, and those rules are provided by the master document—the Document Object Model (DOM).
MAKING jQUERY WORK
5
WORKING WITH THE DOM
FIGURE 1.2 Examining the DOM using Firebug with Firefox.
6
CHAPTER 1
At the heart of all of your Web pages is an API (Application Programming Interface) that describes everything on the page. It is the DOM. The DOM provides information for each element on the page, including styles associated with elements. The information in the DOM is stored in a tree-like structure. Several DOM inspector applications are available either as stand-alone applications or as add-ins to many popular Web browsers. Figure 1.2 shows the DOM inspector available with Firebug.
INTRODUCING jQUERY
FIGURE 1.3 An outline of the relationships between the elements in the list.
The DOM API is what allows languages like JavaScript and libraries like jQuery to interact with elements in your Web pages. You can use libraries like jQuery to virtually climb up and down the DOM tree to locate, add, remove, and modify elements. Because you’ll be using jQuery to interact with the DOM, including adding and removing elements from it, you need to become familiar with how the DOM is constructed. You don’t need to become an expert on the DOM, but you should know enough about the DOM to recognize what is going on when you manipulate it with jQuery. Knowing the DOM becomes critically important when you start working with jQuery’s parent and child type selectors. You must understand the relationship between the elements in the DOM so that you can effectively manipulate those elements. Consider the following HTML markup:
To know how to travel up and down the DOM tree, you must know what the relationships are between the elements. Figure 1.3 shows how those relationships are defined.
WORKING WITH THE DOM
7
LINE BREAKS AND COMMENTS Because JavaScript allows you to continue code through line breaks, jQuery will, too. This means that you can spread chained jQuery methods over several lines. Spreading lengthy chains over multiple lines makes the jQuery methods visually easier to follow and troubleshoot. Quite often you’ll see jQuery chains similar to the following example:
var nextImage = $(‘img[src=”bar.jpg”]’) // define the p starting point .closest(‘li’) // travel up to the closest list item .next() // move to the next list item .find(‘img’) // find the image tag in the next list item .attr(‘src’); // grab the source attribute of the found p image tag I cannot stress enough the importance of commenting your code well. Although I won’t be commenting a lot of the code in the book for space reasons, you can expect to see a lot of commentary within the code samples on the Web site. My personal style is to use the double slash at the end of a line when the comment is quick and use larger comment blocks (beginning with /* and ending with */) when I need to be more descriptive.
// is a short comment /* this comment may span multiple lines and can be very p descriptive */
Armed with this knowledge, you can traverse the DOM elements for this list. Given that you know the image source in the first list item, you can retrieve the source attribute from the second image in the list easily, like this: var nextImage = $(‘img[src=”bar.jpg”]’) // define the starting point .closest(‘li’) // travel up to the closest list item .next() // move to the next list item .find(‘img’) // find the image tag in the next list item .attr(‘src’); // grab the sounrce attribute of the found p image tag
The variable nextImage now contains the value murkle.jpg. 8
CHAPTER 1
INTRODUCING jQUERY
LEARNING A FEW jQUERY TIPS
As I use and continue to learn more about the jQuery library, I’ve accumulated some good rules of thumb, including being specific about jQuery selectors, caching selectors, and packing up code to make it more efficient. These and other tips provided here will make your code more effective, provide you with some good tools, and shorten your development time.
SELECTING ELEMENTS SPECIFICALLY To find the elements that you want to act on, jQuery has to traverse the DOM tree. Depending on the length and complexity of a page, the DOM can be quite large. Using grossly formed selectors can slow performance and lead to frustration. jQuery reads selectors right to left, so if you have a selector like this: $(“div ul li a”);
jQuery will gather all the anchors first, determine if they are within list items, and then find out if the list item is contained within an unordered list that is contained within a . Whew! It would be better to give one group of these items a class or an id attribute that will allow you to more directly identify one or more of the elements involved. For instance, the anchor tags in this group can be navigation elements and given a class of navigation (). That will allow you to shorten the selector to $(“.navigation”). As an added bonus, the element can be more easily referred to and styled in CSS!
TIP: Thanks go out to the very supportive jQuery community for the tips included in this section. You can learn a lot by participating in the jQuery forums at http://forum.jquery.com. Forum participants are always willing to lend a hand to help you solve your jQuery and JavaScript problems.
LEARNING A FEW jQUERY TIPS
9
MAKING QUICK WORK OF DOM TRAVERSAL Sometimes, you might need to upgrade a poorly planned older site or application that was developed by someone else. The selector mentioned in the previous section, $(“div ul li a”), might have to be used repeatedly to achieve the results that you are trying to apply with jQuery. If that is the case, you should cache the selector so that you only need to traverse the DOM once for that selector: var myNavLinks = $(“div ul li a”); // perform the traversal and p stores it $(myNavLinks) // the new selector doesn’t have to traverse the p tree again
Caching becomes a valuable performance tool when you want to manipulate dozens or maybe even hundreds of table rows and cells.
TROUBLESHOOTING WITH FIREBUG Available for nearly every browser, Firebug is the leading tool for debugging and profiling JavaScript. It should definitely be in your Web development toolbox. Firebug allows you to carry out several tasks, including watching your code “in action” to see how it behaves when events are triggered on your Web pages. For instance, in Figure 1.4 a link has been clicked. If you look closely, you can see that several lines of HTML have been highlighted in yellow. Those lines are the portion of the HTML affected by the clicked link. One of Firebug’s handier features is its ability to identify JavaScript (and therefore jQuery) errors accurately, allowing you to quickly troubleshoot and correct problems. I’ll use some of Firebug’s features throughout the book. To talk about and demonstrate all the features Firebug has to offer would take an entire book!
TIP: Firebug is a free download from http://getfirebug.com.
10
CHAPTER 1
INTRODUCING jQUERY
PACKING UP YOUR CODE
FIGURE 1.4 Using Firebug, you can examine jQuery’s actions.
While you are working on writing your code, it helps to use lots of white space and comments. All of the comments and white space take up room, so it is best to pack up your code when you get ready to move your code into production. You may have noticed that the official jQuery site, as well as plugin developers, offer scripts in two versions: a normal version and a minified version. The minified version strips out most of the white space and comments. This ensures that your Web site is delivered more efficiently. Several tools are available for packing up your code. One of my favorites is a freebie provided by Google, the Google Closure Compiler (http://code.google.com/ closure/compiler). Google’s Closure Compiler provides a quick method for minifying your code and offers some additional advantages like checking for illegal JavaScript. LEARNING A FEW jQUERY TIPS
11
For fun, let’s pack some code in the file spritenav.js, which you will use later in the book. With white space and comments, the code looks like this: /* * NAME: SpriteNav(jQuery) * AUTHOR: Jay Blanchard * DATE: 2011-01-10 * BUSINESS RULE:
* * REVISION:
a20110110jb
* STATUS:
open
* USAGE:
call from web interface page
* * REVISION HISTORY * * a20110110jb
- create CSS and XHTML for initial testing layout
* */ $(document).ready(function() {
$(function() { /* set original values */ $(“#spriteNav span”).css(“opacity”, “0”); $(“#spriteNav span.selected”).css(“opacity”, “1”);
/* how do we hover? let me count the ways... */ $(“#spriteNav span”).hover(function() { if($(this).attr(“class”).length == 0) { $(this).stop().animate({
12
CHAPTER 1
INTRODUCING jQUERY
opacity: 1 }, 75); // end mousein } else { $(this).css(“opacity”, “1”); // end mousein }; //end if }, function(){ if($(this).attr(“class”).length == 0) { $(this).stop().animate({ opacity: 0 }, 250); // end mouseout } else { $(this).css(“opacity”, “1”); // end mouseout }; //end if }); // end hover function
/* click me! click me! */ $(“#spriteNav span”).click(function() { /* we clicked, so remove the selected class from all */ $(“#spriteNav span”).removeClass(“selected”); /* then add it to the selected one */ $(this).addClass(“selected”); /* then fade out the previously selected item */ /* be specific about the ones to be faded out */ $(“#spriteNav span:not(.selected)”).stop().animate({ opacity: 0 }, 500); }); // end click function }); // end function }); // end document ready function
LEARNING A FEW jQUERY TIPS
13
FIGURE 1.5 The code before and then after packing, which also reveals warnings and errors that are encountered by the Closure Compiler.
14
CHAPTER 1
In Figure 1.5 you can see the side-by-side comparison of the code before and after packing. After packing the code with the Google Closure Compiler, it becomes: $(document).ready(function(){$(function(){$(“#spriteNav span”).css p (“opacity”,”0”);$(“#spriteNav span.selected”).css(“opacity”, p ”1”);$(“#spriteNav span”).hover(function(){if($(this).attr p (“class”).length==0){$(this).stop().animate({opacity:1},75)} p else{$(this).css(“opacity”,”1”)}},function(){if($(this). p attr(“class”).length==0){$(this).stop().animate({opacity:0}, p 250)}else{$(this).css(“opacity”,”1”)}});$(“#spriteNav span”). p click(function(){$(“#spriteNav span”).removeClass(“selected”); p $(this).addClass(“selected”);$(“#spriteNav span:not(.selected)”). p stop().animate({opacity:0},500)})})});
INTRODUCING jQUERY
Reduced to 40 percent of its original size (1360 bytes originally; 567 bytes after minifying), the code is very compact. Although this is a good example of the gains to be made while minifying jQuery code, you really don’t need to minify small files. If you are using a number of small files, it is best to combine them and then run them through the reduction process. If you plan to minify your files, be sure to keep one copy that you use for editing with all the white space and comments intact, and then minify when you are ready to use the file on a production Web site or application.
USING RETURN FALSE Anyone who has done any amount of JavaScript programming, including programming with jQuery, has run into return false;. For the most part, many have used it improperly. Let’s look at an example, an HTML anchor tag link: Click Here!
Typically, you might apply something similar to the following jQuery to handle the anchor tag: $(“div a”).click(function() { var link = $(this).attr(“href”); $(“#content”).load(link); return false; });
In this example you want to be able to click the link and have that link not perform as it normally would; you want it to just load the information from the link into the element with an id of content. So, you insert return false; into the function. It works! But do you really know how? Because return false works so well, you may not realize when it trips you up later on. The return false function first calls preventDefault(); and then it calls stopPropogation(). The function stopPropogation() stops the click event in this case from bubbling up the DOM, which may prevent subsequent click events from working on the ancestors you may add later. You’ll end up scratching your head a lot when your seemingly perfect code fails to do what you ask of it with no errors lurking about to give you a clue as to what happened.
LEARNING A FEW jQUERY TIPS
15
More often than not what you should use is preventDefault(), as shown in the following highlighted code: $(“div a”).click(function(e) { var link = $(this).attr(“href”); $(“#content”).load(link); e.preventDefault(); });
Take a few minutes to become familiar with the other related functions, stopPropogation() and stopImmediatePropogation(), because you may find
them handy and revealing!
FIDDLING WITH jQUERY CODE One of the most useful and coolest tools I’ve seen in many years is a Web application called jsFiddle (http://jsFiddle.net). Developed by Piotr Zalewa as “a playground for Web developers,” jsFiddle is a great Web site where you can combine HTML and CSS while experimenting on that code with jQuery (Figure 1.6). The tool supports several different versions of jQuery and is an excellent troubleshooting tool. Using the jsFiddle Web site is a great way to share code with other developers for discussion, troubleshooting, or bragging rights. The Web site also allows you to include the latest jQuery UI (user interface) code in your experiments.
16
CHAPTER 1
INTRODUCING jQUERY
FIGURE 1.6 Using jsFiddle, you can test a jQuery code snippet.
LEARNING A FEW jQUERY TIPS
17
COMBINING jQUERY WITH OTHER CODE
Throughout the book, you’ll be using several technologies to bring your Web applications to life. To start, you’ll use HTML, CSS, and JavaScript, and then mix in PHP and MySQL to support further interaction.
STARTING WITH HTML HTML is what you’ll use to start all of your Web pages. Use of the latest version of HTML, HTML5, is on the rise, and examples in the book use it where appropriate. Because HTML5 is still in development, browser support is limited. I recommend plenty of cross-browser testing when using HTML5. jQuery can select HTML DOM elements easily. For instance, if you have a form input element:
you can use the jQuery selector $(‘input[name=”username”]’) to interact with the element.
STYLING WEB PAGES WITH CSS CSS can be tricky territory because different browsers provide different levels of support for the properties that CSS has to offer. Cross-browser testing is still required to make sure that what displays in one also displays in another. It is very important to understand that it is OK if your sites do not look exactly the same from browser to browser. jQuery will support the latest and greatest CSS version, CSS3, and all of its properties, but make sure that you test in many browsers because that is the only way you can determine if what you see is acceptable to you.
USING PHP AND MYSQL As one of the most popular server-side languages on the Web, PHP has made its mark on the technology you know and use every day. For the examples and projects in this book, you’ll be using PHP not only for supporting asynchronous data requests to the server (AJAX), but also for shortening your development time with jQuery. You will couple PHP with the MySQL database to support and enhance your jQuery projects. Keep in mind that you can use any number of languages and database products with jQuery in the ways that I will present in the book—the choice is totally up to you. 18
CHAPTER 1
INTRODUCING jQUERY
PROGRESSIVE ENHANCEMENT
In 2003, Steve Champeon, speaking at the very popular SXSW Interactive conference in Austin, Texas, coined the term progressive enhancement. The concept arrived at just about the same time as some earlier JavaScript libraries. The process behind progressive enhancement is to first develop your markup, then add style to that markup (CSS), and finally bring into play enhanced interaction via JavaScript. In the good old days of Web development, designers and coders were stuck with a paradigm called graceful degradation. Everyone designed their sites for the latest browsers using the latest technologies and then “fixed” their pages by inserting hacks or removing JavaScript functionality so that they would gracefully degrade and be usable by older, less-capable browsers or in situations where the user might have JavaScript disabled. Developers attempted to perform browser detection using JavaScript so that they could deliver flashy interaction in every browser available. It was tiresome and frustrating. Steve Champeon’s concept changed all of that. There is a better way to describe progressive enhancement. In his 2008 article, “Understanding Progressive Enhancement” (www.alistapart.com/articles/ understandingprogressiveenhancement), on the A List Apart Web site, Aaron Gustafson painted my favorite picture of what progressive enhancement is when he wrote, “If you’re a candy fan, think of it as a Peanut M&M: Start with your content peanut, marked up in rich, semantic (X)HTML. Coat that content with a layer of rich, creamy CSS. Finally, add JavaScript as the hard candy shell to make a wonderfully tasty treat (and keep it from melting in your hands).” Let’s examine a quick example of progressive enhancement. Here is a portion of 1-1.html (available in the code download atwww.appliedjquery.com in the folder chap1/1-1.html): Progressive Enhancement Example New Content
Google PROGRESSIVE ENHANCEMENT
19
FIGURE 1.7 The basic progressive enhancement page with HTML and CSS only. FIGURE 1.8 The result of clicking the New Content link in 1-2.html.
The markup is pretty standard. Adding some basic CSS produces what you see in Figure 1.7. I’ve also produced the HTML and CSS for a second page called 1-2.html, which is in the folder chap1/1-2.html. If you click the link for New Content, that page will load normally (Figure 1.8). The only change made, other than adding some content for this example, is in the CSS that causes the content to be displayed in a burnt orange box: #rightContent { width: 75%; margin-left: 20px; padding-top: 10px; padding-left: 10px; background-color: #FFCC66; vertical-align: top; float: left; }
20
CHAPTER 1
INTRODUCING jQUERY
The site works perfectly, even though it is rather bland. Let’s add just a bit of jQuery without touching any of the current markup. 1. Include the jQuery library by placing a tag in the section of 1-1.html: <meta http-equiv=”Content-Type” content=”text/html; p charset=ISO-8859-1” /> Progressive Enhancement Example 1-1 <script type=”text/javascript” src=”../inc/jQuery/8 jquery-1.5.min.js">
2. Add a code block also within the tags, although it is not necessary to do so, as you will see in later examples: <script type=”text/javascript”> $(document).ready(function(e) { $(“#anchor”).click(function() { $(“#rightContent”).load(“1-2.html #rightContent > p”); e.preventDefault(); }); });
Basically, the code specifies, Anytime the element identified as anchor is clicked, load the paragraphs from 1-2.html file’s rightContent area into 1-1. html file’s content area.
PROGRESSIVE ENHANCEMENT
21
FIGURE 1.9 The content from the second page appears without the distracting background color.
Now when you click the New Content link, the page does not reload and the content appears as you expect, without the yucky background color (Figure 1.9). Adding jQuery without using inline JavaScript tags is known as unobtrusive JavaScript and adheres to the principles of progressive enhancement. None of the HTML tags had to be changed, and if JavaScript is disabled, the pages will continue to work as designed. No more embedding JavaScript calls within the HTML tags! In addition, the CSS here is unobtrusive, too. There are no style attributes as part of the HTML tags, but jQuery does give you the ability to change styling on the fly by giving you ways to add and remove classes and directly manipulate the CSS of every element on the page. You’ll be using these functions frequently throughout the book.
22
CHAPTER 1
INTRODUCING jQUERY
PLANNING DESIGN AND INTERACTION
Any good Web application begins on paper, perhaps with a few basic sketches. By the end of the book, you’ll have the ability to greatly enhance your sites with jQuery, so planning is especially important. You don’t want to just throw jQuery code willy-nilly into your Web pages without a plan, or soon you’ll have interaction overload. So many page elements will change and move on the screen that you’ll get your visitor’s attention, but not in the ways that you want to gain that attention. Creating a storyboard is a great way to plan how you will guide the visitor through your site. Drawing a storyboard doesn’t require any special skill. You can use sticky notes, sketches, flowcharts, or even the UML (Unified Modeling Language) to show how potential interactions behave and pages connect to each other. Be sure to ask lots of “what ifs.” What if the viewer clicks here? What if the mouse scrolls over this section of the page? What if the total is over $100? What if you put your spinning, flaming logo right in the center of the page? Asking questions like these and creating a basic layout of the site will open your eyes to how your visitors will see and interact with your Web pages. It will also give you some ideas for how you can build more jQuery widgets that add value to your sites.
WRAPPING UP In this chapter, you learned about the jQuery JavaScript library, how to write the proper syntax for jQuery, and how jQuery selectors are like CSS selectors. You learned how jQuery interacts with the DOM and how you can use jQuery to traverse the DOM. You gained knowledge of tools like Firebug, jsFiddle, and the Google Closure Compiler to help you troubleshoot, test, and make your jQuery scripts ready for use on live Web sites and applications. Finally, you learned how to combine jQuery with HTML, CSS, and other languages using Progressive Enhancement techniques to keep all of your code and scripts compartmentalized for easy maintenance and to let site visitors with less-capable browsers use your content with restriction. Now that you are armed with some good tools and an understanding of the jQuery basics, it is time to jump right in. To learn how jQuery can interact with the browser and events associated with the browser, just turn the page!
WRAPPING UP
23
2 WORKING WITH EVENTS
The bread and butter of jQuery is its ability to interact with all kinds of browser and physical events, including mouse movement, form interaction, and keyboard events. You can take control of these events using jQuery to provide your Web-site visitors with a much richer interactive experience. By binding events such as a mouse click or a keypress to text, links, images, and other DOM elements, you can call into action myriad functions from animation to AJAX. Functions can be combined to create complex chain reactions, a very cool thing. In this chapter I’ll show you how to gain control over many of these events while creating a fictional Web site called Photographer’s Exchange. You will combine the events to create effects that will make your Web audience sit up and take notice. Other events are very subtle and will add flavor to your Web applications.
USING THE PHOTOGRAPHER’S EXCHANGE WEB SITE
FIGURE 2.1 The front page of Photographer’s Exchange. The text is used as a placeholder for development you will add later.
You will design the Photographer’s Exchange Web site to allow photographers to show off their pictures and techniques. Users will be able to upload pictures and edit information about those pictures. Additionally, users will be able to submit articles about photography. Visitors will be able to search the site using different criteria. The front page of the site will showcase featured photographs and articles from photographers. Figure 2.1 shows the basic layout of the site ready for editing.
NOTE: All of the code in this book is available as a download from the book’s Web site at www.appliedjquery.com/download.
26
CHAPTER 2
WORKING WITH EVENTS
MAKING NAVIGATION GRACEFUL
If you want to apply the principles of progressive enhancement—as discussed in Chapter 1—to your site, you need to make your navigation as graceful as possible. The easiest way to do this is to fully form your links as if JavaScript, and therefore jQuery, is not available for your visitors. Open the chap2/2-1.php file. You’ll find an unordered HTML list containing three links: <span>Search <span>Register <span>Login
Each link works properly in the absence of JavaScript. Clicking on any of them causes the respective page to be loaded into the browser. NOTE: To save time and space in this book, I did not create the additional Web pages. The content for each modal window, which is contained in 1-1.php, can be placed in separate pages if you are concerned that users will not have JavaScript available.
This set of links will be used to call modal windows into the browser.
CREATING AND CALLING MODAL WINDOWS Modal windows are a clever way for users to interact with Web sites and applications. They provide smooth transitions by placing content “above” the current Web page and can give users information, as well as receive information from users either in forms or a confirmation dialog. Once the modal window is closed, users return to the same content in the Web browser that they were viewing previously. Each modal window is used to perform a specific action in the site: search, register, or login. You do not have to make any modifications to the HTML for the links; all you have to do is add the proper jQuery. 1. Create a jQuery statement that selects all of the anchor tags that have a class of modal: $(‘a.modal’).click(function() {
MAKING NAVIGATION GRACEFUL
27
You have now handed over control of the click event to jQuery or have bound jQuery’s click event to the anchor tag. This binding allows jQuery to handle the click event and any functions assigned to that event. The remainder of the function decides which modal window to open, where to place the window, and how to close the modal window. Additionally, the function places a semitransparent “shade” over the entire site to make the modal window stand out. You can find the complete code in chap2/inc/jqpe.js under the section commented /* modal windows */. 2. Store the value of the rel attribute from the currently clicked item in a variable that will be used later in the function: var modalID = $(this).attr(‘rel’);
3. Fade in the modal window that you selected and add a link that allows you to close the modal window. A graphic element (close_button.png) is used to make the close button look nice: $(‘#’ + modalID).fadeIn().prepend(‘');
In the file chap2/inc/modal.css, the margins and padding were defined for each of the modal windows. To get them to center on the screen, you need to account for the extra space created by the padding and margins so that the proper offset can be applied. In this case there is a 20-pixel margin and 20 pixels of padding surrounding each modal window. That means that you must add 80 pixels to the height and width. With the height and width set, you then divide by 2 to get the proper margin. 4. Assign the horizontal and vertical margin calculated values to the variables modalMarginTop and modalMarginLeft: var modalMarginTop = ($(‘#’ + modalID).height() + 80) / 2; var modalMarginLeft = ($(‘#’ + modalID).width() + 80) / 2;
28
CHAPTER 2
WORKING WITH EVENTS
FIGURE 2.2 The modal window box, including padding and margins. The top-left corner of the modal window is located at 50 percent of the window height and width to begin. Setting the top and left margins with negative numbers moves the modal box to the center of the browser window.
move -240 pixels 0, 0
move -290 pixels
500 x 400 modal div with 20 pixels of padding and 20 pixels of margin. Overall, the modal box is 580 pixels by 480 pixels.
5. Now add the margin information to the modal window’s CSS to center it: $(‘#’ + modalID).css({ ‘margin-top’ : -modalMarginTop, ‘margin-left’ : -modalMarginLeft });
Figure 2.2 shows a model of the modal box and how much it must be offset to the top and left of the browser window to center the box. If you don’t calculate where the center of the box should go, the upperleft corner of the box will be centered in the browser window, as shown in Figure 2.3.
MAKING NAVIGATION GRACEFUL
29
FIGURE 2.3 The modal box without calculating where the center of the box should go. The top-left corner of the modal box is at 0, 0 for the browser window’s 50 percent height and width.
SIZING UP ANIMATIONS When creating the modal window, you invoked the very first animation using the jQuery method fadeIn(). jQuery has a number of built-in animation methods, including fadeIn and slideDown as well as the animate method that allows you to create custom animations. What is an animation? In jQuery an animation is the act of moving an element from one CSS state to another CSS state smoothly. Animation can only be used on CSS rules that have numerical properties. jQuery uses a set of algorithms to calculate each of the points from the start of one state to the end of another state. A simple example is opacity. If an element is invisible, its opacity is 0. To make the element fully visible, you set its opacity to 1. Depending on the length of time assigned to the transition, jQuery will calculate discrete steps needed to make the element appear to fade in (or out), moving opacity from 0 to 1 or vice versa. jQuery also supports queues so that you can combine animations to create complex movements and changes. The jQuery user interface (UI) extends jQuery basic animation events and adds several additional effect methods, including color animations.
30
CHAPTER 2
WORKING WITH EVENTS
FIGURE 2.4 The modal window for registration is opened and is properly centered with the shaded, see-through background.
CREATING A SHADED BACKGROUND
The last order of business for opening the modal window is creating a shaded background. The shade is actually a semitransparent div through which you can still see the Web site. It is a very cool effect and helps users to understand that they are still on your site but that their attention should be focused on the content highlighted for them. You’ll use a similar version of the see-through div for other widgets in the Web site. 1. Append a new div to the body to make the shade: $(‘body’).append(‘’);
2. Animate the shaded background to partial opacity to make it somewhat transparent: $(‘#modalShade’).css(‘opacity’, 0.7).fadeIn();
3. Close the click function with the return false; method to keep the link from trying to load another page into the browser. return false; });
Once complete, the jQuery code opens the modal window in the center of the browser window with a shaded background that allows users to see the Web page beneath it (Figure 2.4).
MAKING NAVIGATION GRACEFUL
31
CONTROLLING THE FUTURE WITH LIVE( ) AND DELEGATE( ) jQuery provides two methods for binding events to elements created now or in the future: live and delegate. Both save you the additional work of adding new event bindings as you add new elements dynamically. The primary difference between the two is that live does not support DOM traversal, whereas delegate will support binding of events to specific DOM elements. To use live, you must use it immediately after a selector to bind to an event, just as you did in the code for closing the modal window:
$(‘a.close, #modalShade’).live(‘click’, function() {... On the other hand, delegate can be used as follows:
$(‘ul#myList’).delegate(‘li’, ‘click’, function() {... This binds the click event to each of the list items (
) now and in the future. If you append more list items to the unordered list, they will all have the click function bound to them.
Don’t worry about handling form information or processing that information right now. I’ll cover form handling and processing in Chapter 3, “Making Forms Pop” and Chapter 4, “Being Effective with AJAX.” CLOSING THE MODAL WINDOW
Users must be able to close the window and get rid of the shade, so you need to give users a way to get back to the Web site. 1. Start the close function by binding the close graphic and modal shade to a jQuery click method: $(‘a.close, #modalShade’).live(‘click’, function() {
Neither of these elements existed in the DOM (see Chapter 1 for a short discussion of the DOM) originally, so you have to use a special jQuery function, live, to bind the click to these elements.
32
CHAPTER 2
WORKING WITH EVENTS
2. Determine which modal window to close by getting the id of the parent of a.close: var thisModalID = $(‘a.close’).parent().attr(‘id’);
3. Now fade out the modal window and the shade. When the fade-out is complete, use the callback function fadeOut provides to remove the div that held the shade and the link that was prepended to the modal window: $(‘#modalShade, #’+thisModalID).fadeOut(function() { $(‘#modalShade, a.close’).remove(); }); return false; });
In simple terms a callback is a block of executable code that is passed as an argument to another function. The block of code in the callback will run when the original function is complete. You issue a callback to the fadeOut function as highlighted: $(‘#modalShade, #’+thisModalID).fadeOut(function() { $(‘#modalShade, a.close’).remove(); });
The fade-out completes before issuing the callback to remove the #modalShade and a.close element from the DOM. Combining multiple jQuery methods in this way makes a click on a link a pretty powerful event. Can you bind the click event, or any other event, to elements that are not links? Of course you can, and you already have. Look at the following line again: $(‘a.close, #modalShade’).live(‘click’, function() {
The highlighted value is the id for the div that held the shade, which is also bound to the live click function. This allows users to click anywhere on the shade to fade out the modal window and perform the other items in the function. Binding to nonlink-type elements is common when using jQuery.
MAKING NAVIGATION GRACEFUL
33
BINDING EVENTS TO OTHER ELEMENTS
jQuery gives you the flexibility to bind events to any element available in the DOM. This gives you the capability to set up highly interactive user interfaces. Creating a truly fun and intuitive user experience is easier than ever because you are not limiting your users to just clicking a link or a button on your Web site. The Photographer’s Exchange Web site needs a way to feature members’ photographs. A simple photo carousel will provide an excellent method of showcasing the members’ talents while allowing you, as the developer, to flex your creative muscles.
BUILDING AN IMAGE CAROUSEL Let’s add a simple version of a photo carousel to the site now. The concept for the carousel is very simple and is based on an unordered list of thumbnail images. You can see this list added to the site in chap2/2-2.php:
34
CHAPTER 2
WORKING WITH EVENTS
Now that you have a list of images, you need to add the following carousel features: 䊏
Automatic scrolling.
䊏
Scrolling that stops when a mouse cursor hovers over any portion of the carousel.
䊏
Scrolling that continues when the mouse cursor is not hovering over any portion of the carousel.
䊏
Highlighting an image when the mouse cursor hovers over a thumbnail of that image.
䊏
Controlling manual scrolling.
䊏
Displaying a larger version of a picture when its respective thumbnail is clicked.
Before you can start adding these features, you need to create the container for the carousel using CSS. Let’s cover that first. SETTING UP THE CAROUSEL CSS
To make the carousel effect work well, it must have a solid container. The container will be defined by the CSS along with the markup that you created earlier. 1. Set up the #carouselInner rule to allow only a certain number of thumbnails to be visible at any one time: #carouselInner { float: left; width: 510px; overflow: hidden; background: #000000; }
The #carouselInner rule sets up a visible area of 510 pixels. Anything outside of the element assigned to this rule will not be visible. The 510-pixel area is calculated by adding the widths of three thumbnails (160 pixels each) plus 10 pixels for each thumbnail. The additional pixels allow for padding around each image.
BINDING EVENTS TO OTHER ELEMENTS
35
2. Create a left margin that allows two images to be hidden off to the left of the carousel. Setting this margin is the most important part of the #carouselUL rule. Having two images to the left of the carousel ensures that the scrolling will happen smoothly. Make sure that the whole carousel is wide enough to hold the number of thumbnails you plan to display. In this case #carouselUL is designed to hold a maximum of 50 thumbnails: #carouselUL { position: relative; list-style-type: none; left: -340px; margin: 0px; padding: 0px; width: 8500px; padding-bottom: 10px; }
3. Now set the height and width of the list items: #carouselUL li{ float: left; width: 160px; height: 128px; padding: 0px; background: #000000; margin-top: 10px; margin-bottom: 10px; margin-left: 5px; margin-right: 5px; text-align: center; }
36
CHAPTER 2
WORKING WITH EVENTS
Visible Portion
Scroll Direction
Invisible
Invisible
Figure 2.5 gives you an idea of how list items will be moved. As the carousel scrolls to the left, the first list item is moved to the end of the list while the item is invisible. The reverse happens (the last list item is moved to the first spot) when the carousel scrolls to the right. The user gets the impression that the images are on a carousel going around and around. Once the style information has been defined, you can begin working on adding the features to the carousel using jQuery.
FIGURE 2.5 The visible and invisible portions of the carousel. You can also see how the images will move to make the carousel “infinite.” The thumbnails will start over at the beginning of the list when the last one is displayed.
NOTE: There is much more to the CSS (chap4/css/carousel.css) for the carousel, but it is mostly decorative or setting up space for the arrows that will be used for manual control of the carousel. Additionally, the style information for the modal window to display the larger pictures is defined.
ADDING AUTOMATIC SCROLLING
It is time for you to start adding the features defined for the carousel. You’ll first create a function that automatically scrolls the carousel. Create a file called carousel. js and save it in the chap2/inc folder. 1. Create the function using the function keyword and call the function autoCarousel. Then set the variable itemWidth equal to the width of one of the list items in the carousel and add 10 to it to make space for the padding: function autoCarousel() { var itemWidth = $(‘#carouselUL li’).outerWidth() + 10;
BINDING EVENTS TO OTHER ELEMENTS
37
2. Determine how far to the left the carousel needs to move. Recall that the left margin of the CSS was set to -340 originally, so the moveFactor will be -510. Assign the results of that calculation to the variable moveFactor: var moveFactor = parseInt($(‘#carouselUL’).css(‘left’)) p - itemWidth;
3. Now the fun really begins! Bind the animate method to the unordered list identified by #carouselUL. Then the list of images is moved to the left so that the images’ left margins are the same as the moveFactor. Add the duration of slow and easing transition of linear for tighter control of the animation: $(‘#carouselUL’).animate( {‘left’ : moveFactor}, ‘slow’, ‘linear’, p function(){
4. Move the first list item to the end of the list, after the last list item. This line of code, contained in the animation’s callback function, contains the secret to making the carousel infinite: $(“#carouselUL li:last”).after($(“#carouselUL p li:first”));
By moving the list item and changing the order of the HTML list as a whole, you can make the pictures appear to keep going around the carousel. TIP: Easing, in jQuery terms, tells an animation how fast to move at different points during the animation’s progress. jQuery includes two default easing methods: linear and swing. Linear moves the animation steadily from point A to point B with no speed change. Swing moves the animation slowly at first, faster near its midpoint, and then slows down as it reaches its end. Both of these easing methods will help to smooth animations, making them less jerky. You can create some cool effects by using George Smith’s jQuery Easing Plugin. The plugin makes dozens of additional easing types available to use in your jQuery applications. The plugin is available from the GSGD Web site at http://gsgd.co.uk/sandbox/jquery/easing.
38
CHAPTER 2
WORKING WITH EVENTS
5. Close out the function by resetting the left margin back to its original value and closing all of the brackets and braces: $(‘#carouselUL’).css({‘left’ : ‘-340px’}); }); };
If you don’t reset the left margin, the carousel will continue to scroll to the left, and eventually the pictures will be out of sight. 6. Call the autoCarousel function by placing it in a setInterval function. Give the setInterval method an identifier by assigning it to a variable. Set the interval to 2000 milliseconds (2 seconds): var moveCarousel = setInterval(autoCarousel, 2000);
Now you can load the page. You’ll see that the carousel starts automatically and pauses for 2 seconds between each animation. 7. Use the very next line of code to make all the thumbnails and the arrow graphics appear to be faded: $(‘.carThumb, #scrollLeft, #scrollRight’).css({opacity: 0.5});
You’ll take advantage of the opacity being set to a faded state when you create the hover functions. ADDING THE HOVER FUNCTIONS
You’ll bind the hover function to the thumbnail images identified by the class of carThumb as well as the divs containing the arrows that will be used to manually control the scrolling of the carousel. Three actions are required for the hover function: 䊏
Stop the scrolling when a mouse cursor hovers over any portion of the carousel.
䊏
Highlight the image when the mouse cursor hovers over a thumbnail.
䊏
Continue scrolling when the mouse cursor is not hovering over any portion of the carousel.
BINDING EVENTS TO OTHER ELEMENTS
39
FIGURE 2.6 The mouse cursor over one of the images in the carousel. The image has been faded to full opacity, and the carousel has stopped scrolling.
1. Bind the hover function to the class carThumb and elements with an id of scrollLeft and scrollRight: $(‘.carThumb, #scrollLeft, #scrollRight’).hover(function() {
The hover function consists of two sections, one for mouseover and one for mouseout. The jQuery hover method combines this functionality to give you a tremendous amount of flexibility. 2. Bind the jQuery stop and animate methods for the mouseover portion of the function to elements represented by $(this). The stop makes sure that the current animation will quit when you move the mouse away or perform some other action. Without stop, the animations would continue to queue up and run, and that is not desirable for the hover function: $(this).stop().animate({ opacity: 1 }, 75);
The animation makes the image fade to full opacity very quickly (75 milliseconds). This gives the appearance of the image being highlighted and fulfills one of the requirements. The cursor is hovered over a thumbnail in Figure 2.6, making it appear to be brighter than the thumbnails adjacent to it.
40
CHAPTER 2
WORKING WITH EVENTS
3. Stop the scrolling animation of the carousel by clearing the setInterval function. Identify the interval to be cleared by passing the identifier moveCarousel to the clearInterval function: clearInterval(moveCarousel);
4. Add the code to fade the image in the mouseout portion of the hover function: }, function() { $(this).stop().animate({ opacity: 0.5 }, 250);
The mouseout side of the jQuery hover function reverses the fade of the opacity and does so more slowly (250 milliseconds) just for effect. Note that you did not apply any easing to either side of the hover function. Easing will work here, but the times for the movement to either full or half opacity are so fast that most easing methods would hardly be noticed. 5. Restart the carousel’s automatic scrolling by calling the setInterval function in the last line of the mouseout side of the hover function: moveCarousel = setInterval(autoCarousel, 2000); });
The requirements for the carousel are being met pretty quickly. Next, you’ll give the Web-site visitors a way to control the scrolling of the carousel manually. CONTROLLING MANUAL SCROLLING
Web-site visitors need the ability to manually scroll the carousel so they can look for specific images. Adding manual control is fairly simple, even though the movement of the carousel may seem backwards compared to the image that is clicked. In other words, clicking the right arrow moves the carousel to the left, and clicking the left arrow moves the carousel to the right.
BINDING EVENTS TO OTHER ELEMENTS
41
A portion of the functionality for manual control was completed for the automatic scroll function autoCarousel (the following highlighted code). All that you need to do is wrap the code in a function that binds a click function to the element identified as scrollRight: $(‘#scrollRight’).click(function(){ var itemWidth = $(‘#carouselUL li’).outerWidth() + 10; var moveFactor = parseInt($(‘#carouselUL’).css(‘left’)) - itemWidth; $(‘#carouselUL’).animate( {‘left’ : moveFactor}, ‘slow’, ‘linear’, function(){ $(“#carouselUL li:last”).after($(“#carouselUL li:first”)); $(‘#carouselUL’).css({‘left’ : ‘-340px’}); }); });
If you’ve been really observant, you’ll notice that this click event is bound to an arrow image that points to the right but moves the carousel to the left. As mentioned earlier, the movement might seem a little backwards for these functions, but there is a very good reason. Visitors to Web sites have been conditioned by actions that they have performed for most of their lives. One of the most prominent of these conditions is turning the page of a book or a newspaper. This action requires you to grasp a section of the page on your right and move it to the left. It seems quite natural that this movement will reveal new content the way you expect it to. The same goes for the carousel. Clicking on the right moves the carousel to the left and feels very natural. You can test this by making a couple of changes to the function. Moving the carousel to the right requires only a couple of changes. 1. Make a copy of the function that was used to set up manual control when clicking on the right arrow, and paste the newly copied code below that function.
42
CHAPTER 2
WORKING WITH EVENTS
2. Change the first line of the function to bind the click function to the scrollLeft selector: $(‘#scrollLeft’).click(function(){
3. Change the calculation assigned to the moveFactor variable to add the itemWidth instead of subtracting it: var itemWidth = $(‘#carouselUL li’).outerWidth() + 10; var moveFactor = parseInt($(‘#carouselUL’).css(‘left’)) + p itemWidth;
The distance moved by the carousel is the same as it was before; it is just moving in a different direction. This difference in direction is accomplished by animating the move from -340 pixels left to -170 pixels left (the carousel moves from -340 pixels left to -510 pixels left when animating to the left): 4. Create the function that binds the animate method to the carousel: $(‘#carouselUL’).animate( {‘left’ : moveFactor}, ‘slow’, ‘linear’, function(){
5. Move the last list item to a place before the first list item: $(“#carouselUL li:first”).before($(“#carouselUL p li:last”));
Making this move is the opposite of the action that was performed before to reorder the image list and makes the carousel “infinite” in the opposite direction if the user continues to manually select the scrollLeft option. 6. Reset the left margin to its original location with the last line of code to complete the requirement for manual control of the carousel: $(‘#carouselUL’).css({‘left’ : ‘-340px’}); }); });
BINDING EVENTS TO OTHER ELEMENTS
43
typical left margin of the carousel -340 pixels FIGURE 2.7 The relationship between the standard left margin for the carousel, -340 pixels left, and the margins that get set temporarily to support the animation.
margin gets set to -510 pixels to give the animation a place to move to when scrolling to the left
margin gets set to -170 pixels, giving the animation a place to move to when scrolling to the right
To understand the movement, Figure 2.7 illustrates the normal left margin of the carousel at -340 pixels. The margin gets moved to the right or left temporarily as needed by the carousel click functions. This gives the animation method a “go-to” location. NOTE: The style rule for the container that holds the arrows is included in chap2/css/carousel.css. You need to add one more requirement to complete the carousel, and it is a huge one (excuse the pun). The carousel needs a method to display larger images. ZOOMING IN ON LARGER IMAGES
When site visitors spot a thumbnail that they would like to get a better look at, you do not want them to just squint at the thumbnails and try to imagine them as larger images. By applying some CSS and jQuery, it is easy to give users a way to view larger pictures by clicking a thumbnail. 1. Using a technique similar to the creation of modal windows with form elements, create a div just before the closing body tag in chap2/2-2.php:
44
CHAPTER 2
WORKING WITH EVENTS
2. Add the style rules for photoModal to chap2/css/carousel.css: .photoModal { display: none; background: #FFFFFF; color: #000000; border: 20px solid #FFFFFF; float: left; font-size: 1.2em; position: fixed; width: auto; height: auto; top: 50%; left: 50%; z-index: 200; }
It is important that you include a height and width property (highlighted) in the rule because these properties ensure that the image loaded into the div will fill the div properly and support the calculation that centers the picture within the browser window. Next, you’ll add the additional functions to handle the large images to the file you created earlier, chap2/inc/carousel.js. The first addition should be a function that loads all of the larger images into hidden divs having a class of photoHolder. It is necessary to load the images this way because jQuery cannot measure the height and width of something that is not yet loaded. Without the facility to measure elements not yet in the DOM, loading each image when the thumbnail is clicked may give you erratic results. 1. Bind the thumbnails with a class of carThumb to the each method to begin the function: $(‘.carThumb’).each(function(){
BINDING EVENTS TO OTHER ELEMENTS
45
2. Extract the image’s path and name information based on the source of the thumbnail. For example, the first line assigns photos/thumb_ka1.jpg to the variable photoInfo: var photoInfo = $(this).attr(“src”);
3. Split the thumbnail path information apart at the forward slash: var photoPathArr = photoInfo.split(‘/’);
The split creates an array called photoPathArr. This array contains two pieces of information; photos contained in photoPathArr[0] and thumb_ka1.jpg in photoPathArr[1]. 4. Concatenate a forward slash to photos (contained in photoPathArr[0]). The forward slash is needed to truly represent the path for the images: var photoPath = photoPathArr[0]+’/’;
5. Perform another split to get the actual name of the full-sized image: var photoInfoArr = photoInfo.split(‘_’);
The name of the full-sized image will be contained in photoInfoArr[1]. 6. Reassemble the two pieces to provide the path to the full-sized image like photos/ka1.jpg: var photoSrc = photoPath+photoInfoArr[1];
Note that manipulating text as you just did occurs frequently in jQuery (and other programming languages). As a matter of fact, you’ll see similar text manipulation later in this function when you bind the click event to the thumbnails. As your skills grow, you’ll be able to write functions that will process text manipulations like this quickly, and more important, as snippets of code that are reusable. 7. Define the images by creating a new image with the $(‘’) selector and bind the image to the load function: $(‘’).load(function(){
46
CHAPTER 2
WORKING WITH EVENTS
8. Append a div to the body of the HTML document to hold the full-sized image: $(‘body’).append(‘
108
CHAPTER 4
BEING EFFECTIVE WITH AJAX
3. Open the function by making sure that the document (the current Web page DOM information) is completely loaded: $(document).ready(function() {
4. The first critical step in making sure that you get the right information from the database is to assign the value of the cookie set during login to a variable that can be used by jQuery. The information in the cookie is the user’s name: var cookieUser = ‘’;
5. As stated earlier, the get method relies on name=value pairs to do its work properly. Make sure that the get request sends the cookie data to the server as a name=value pair: $.get(‘inc/userPhoto.php’, {photoUser: cookieUser}, p function(data){
6. Load the information returned into the div with an id of myPhotos: $(‘#myPhotos’).html(data);
7. Close the get function with the data type that is expected to be returned from the PHP script. Once closed, set the closing tag (the tag is shown only for reference): }, ‘html’); });
8. Before you can get the photos from the database, you need to create the photo table. So, run the pephoto.sql file located in the chap4/sql folder of the code download. The SQL file will also insert default data for the photos located in the chap4/photos folder. In the PHP file chap4/inc/userPhoto.php, the SQL query uses the information contained in the photoUser variable: $getImg = “SELECT `imgName`,`imgThumb` “; $getImg .= “FROM `photoex`.`pephoto` “; $getImg .= “WHERE `username` = ‘”.$_GET[‘photoUser’].”’ “; USING AJAX TO UPDATE CONTENT
109
FIGURE 4.6 The user’s photographs in tabular form.
The user’s photographs are retrieved and placed into a table for viewing. The results are illustrated in Figure 4.6. Combining user data with the get method is very effective for pages where data unique to the user must be displayed. What about content that is not unique to the user? The get method has a cool little brother called load.
LOADING CONTENT BASED ON REQUEST Of the jQuery AJAX shorthand methods, load is the simplest and easiest method for retrieving information from the server. It is especially useful if you want to call on new information that does not need data passed to it like you would do with the get or post methods. The syntax for load is short and sweet as well: $(‘a[href=”writeNew”]’).click(function(e){ e.preventDefault(); $(‘#newArticle’).load(‘inc/userWrite.php’); });
110
CHAPTER 4
BEING EFFECTIVE WITH AJAX
FIGURE 4.7 The form has been loaded into the page so that the user can write a new article.
Clicking on the Write link (Figure 4.7) invokes the load function, causing chap4/ inc/userWrite.php to be loaded into the div with an id of newArticle. There is one other really neat feature that load offers: You can use it to bring in just portions of other pages. For instance, to bring in a div with an id of part1 from another page, the syntax is as follows: $(‘#newArticle’).load(‘inc/anotherPage.html #part1’);
Having the option of loading page portions can give you a great deal of design and organizational flexibility. NOTE: In Chapter 6, “Creating Application Interfaces,” you’ll use an example in which several widgets will be contained in one file that will be called by load as needed to complete the interface.
Not every Web site can use every AJAX feature that jQuery offers, so you’ll leave the Photographer’s Exchange Web site behind at this point. You’ll develop standalone examples to demonstrate some of the other features and events available in jQuery’s AJAX library.
USING AJAX TO UPDATE CONTENT
111
LOADING SCRIPTS DYNAMICALLY There are some cases in which you will need to load JavaScript or jQuery scripts just for one-time use in your Web pages and applications. jQuery provides a special AJAX shorthand method to do just that, getScript. For this example, you’ll use the code contained in chap3/dvdCollection, which is a small personal Web site designed to be used as a catalog of all the DVD and Blu-ray Discs that you own. From time to time, you’ll want to know just how many DVD and Blu-ray Discs you have, but it isn’t really necessary to load the script that performs the counts and displays the result every time you use the site. jQuery’s getScript method is the perfect remedy for loading scripts that you’ll use infrequently. 1. Set up a script called dvdcount.js and place it in the inc directory of the DVD collection site. This is the script that getScript will load when called upon to do so. 2. Include the document ready functionality: $(document).ready(function(){
3. Each movie is contained in a div with a class of dvd. Assign the count of those div’s to the variable totalCount: var totalCount = $(‘.dvd’).length;
4. Use jQuery’s :contains selector to help count the types of discs in the collection. The :contains selector is very handy for finding elements containing a specific string. Here it is used to find the text “DVD” or “Bluray” in the h3 element: var dvdCount = $(‘h3:contains(“DVD”)’).length; var brCount = $(‘h3:contains(“Blu-ray”)’).length;
5. Set up the modal window to show the user the information. This is the same technique used in Chapter 2 and Chapter 3, so I won’t cover each step in detail: var movieModal = ‘Total Movies: p '+totalCount+'
DVD: '+dvdCount+'
Blu-ray: p '+brCount+'';
112
CHAPTER 4
BEING EFFECTIVE WITH AJAX
$('body').append(movieModal); var modalMarginTop = ($('.movieModal').height() + 40) / 2; var modalMarginLeft = ($('.movieModal').width() + 40) / 2; $('.movieModal').css({ 'margin-top' : -modalMarginTop, 'margin-left' : -modalMarginLeft });
The modal will only pop up for a moment before fading out: $(‘.movieModal’).fadeIn(‘slow’, function(){ $(this).fadeOut(2500, function() { $(this).remove(); }); }); });
The main page for the DVD catalog site is chap4/dvdCollection/4-5.php. Let’s take a moment to set it up. 1. Enter the information for the header: <meta charset=”utf-8”> DVD Collection Catalog
USING AJAX TO UPDATE CONTENT
113
2. Include the jQuery file so that all of the interactions will run properly: <script type=”text/javascript” p src=”inc/jquery-1.5.min.js">
3. Set up the body next: DVD Collection Catalog
4. Set up the menu section carefully, because you’ll use these elements to call other scripts:
5. Set up the div that will house the content of the page:
6. Create the section containing the jQuery scripts you’ll use to load information into the page along with the function that loads chap4/dvdCollection/ inc/getdvd.php. The PHP is called by the jQuery load method to get the information about the DVD collection: <script type=”text/javascript”> $(document).ready(function(){ $(‘.content’).load(‘inc/getdvd.php’);
114
CHAPTER 4
BEING EFFECTIVE WITH AJAX
FIGURE 4.8 Clicking on the Summary element loads and runs the dvdcount.js script.
7. Bind the click method to the list item with an id of summary. This will call getScript to run the jQuery script created earlier, dvdcount.js: $(‘#summary’).click(function() { $.getScript(‘inc/dvdcount.js’); }); });
8. Close out the HTML:
Clicking the Summary element on the Web page causes the dvdcount.js script to be loaded and run, showing the modal window complete with counts (Figure 4.8). The modal window then slowly fades away.
USING AJAX TO UPDATE CONTENT
115
You will find many cases where loading and running scripts on the fly will enhance your Web sites and applications. Next, you’ll turn your attention to many of jQuery’s AJAX extras and learn how to apply them practically.
USING JQUERY’S AJAX EXTRAS In addition to the shorthand methods, jQuery provides many useful methods and helpers to give you ways to use AJAX efficiently. These methods range from lowlevel interfaces to global event handlers, all of which, when applied properly, will make your programs and Web sites more effective. Let’s look at these extras, starting with the low-level interfaces. WORKING WITH LOW-LEVEL INTERFACES
jQuery’s low-level AJAX interfaces provide the most detailed approach to AJAX functions. This kind of detail makes the low-level interfaces quite flexible but introduces additional complexity due to all of the options available. One way to combat the complexity of having an extensive choice of options is to use a method to set up options that do not change frequently. Take a look at the simplest of the low-level interfaces, ajaxSetup: $.ajaxSetup({ url: ajaxProcessing.php, type: ‘POST’ });
The ajaxSetup method allows you to provide options that will be used with every AJAX request. You can set all of the AJAX options available (over 25 of them!) using ajaxSetup. This is very convenient if you need to make repeated AJAX requests to the same URL or use the same password each time you make a request. In many cases, developers will put all of their server-side AJAX handlers in the same file on the server. Using ajaxSetup shortens their AJAX calls, including the shorthand methods. Given the current example of ajaxSetup, your post method could be configured like this: $.post({ data: formData });
116
CHAPTER 4
BEING EFFECTIVE WITH AJAX
The only thing you need to supply to the post function is the data to be handled by ajaxProcessing.php. One advantage of using the ajaxSetup method is that you can override any of the ajaxSetup options in the individual AJAX calls that you make. The low-level interface that you will see in use most is the straight ajax method. It is the function that is wrapped by the shorthand methods and is at the very heart of all of jQuery’s AJAX calls. The ajax method is capable of accepting all of the options that can be used with jQuery’s AJAX requests. Perhaps the best way to understand the low-level AJAX method is to compare it to one of the shorthand methods you used earlier. Here is the post method that you used to check to make sure the user name was available: $.post(‘inc/peRegister.php’, { formName: ‘register’, penewuser: newName }, function(data){ var usernameCount = data; if(1 == usernameCount){ $(‘#penewuser’).next(‘.error’).css(‘display’, ‘inline’); } else { $(‘#penewuser’).next(‘.error’).css(‘display’, ‘none’); } }, ‘html’);
Here is the same request using jQuery’s low-level ajax method: $.ajax({ type: ‘POST’, url: ‘inc/peRegister.php’, data: ‘formName=register&penewuser=’+newName+’’, success: function(data){ var usernameCount = data; if(1 == usernameCount){
USING AJAX TO UPDATE CONTENT
117
$(‘#penewuser’).next(‘.error’).css(‘display’, ‘inline’); } else { $(‘#penewuser’).next(‘.error’).css(‘display’, ‘none’); } }, dataType: ‘html’ });
The differences are fairly obvious, such as declaring the method that AJAX should use to convey the information to the server (type: ‘POST’), specifying the way that raw data is formatted (data: ‘formName=register&penewuser= ’+newName+’’, ) and ensuring that the success method is implicitly defined (success: function(data){…). Take a tour of jQuery’s ajax API at http://api.jquery.com/jQuery.ajax to see all of the options available for use with this method. Now that you can send information to the server and receive information back from your server-side processes, you need to make sure that your users are informed that an AJAX action is taking place. jQuery provides several helper functions that make it easy for you to do just that. TRIGGERING EVENTS BEFORE AND AFTER THE AJAX CALL
In many cases, your jQuery AJAX functions will happen so quickly that users may not even know that their actions achieved the desired result. In other cases, the AJAX process may be lengthy and require that users wait for results. jQuery provides four methods that you can use to keep users informed: ajaxStart, ajaxSend, ajaxComplete, and ajaxStop. It is important to understand that there is an order to these four functions. You can call any number of AJAX processes during any given event. For this reason, you may want to know not only when the first AJAX function starts, but also when each subsequent AJAX method gets called and completes. Then you may want to register that all of the AJAX calls have completed. If you imagine jQuery AJAX events as a stack of items as in Figure 4.9, you’ll see how the jQuery AJAX engine defines the order of the events and their calls.
118
CHAPTER 4
BEING EFFECTIVE WITH AJAX
jQuery AJAX Start
FIGURE 4.9 The initial jQuery events are stacked up by the developer and then ordered and processed by jQuery’s AJAX engine.
jQuery AJAX Send jQuery AJAX Request
jQuery AJAX Start jQuery AJAX Request jQuery AJAX Request jQuery AJAX Request jQuery AJAX Stop jQuery AJAX Request jQuery AJAX Complete
A J A X CO N T R O L L E R
jQuery AJAX Complete jQuery AJAX Send
jQuery AJAX Send jQuery AJAX Request jQuery AJAX Complete jQuery AJAX Send jQuery AJAX Request jQuery AJAX Complete jQuery AJAX Send jQuery AJAX Request jQuery AJAX Complete jQuery AJAX Stop
Let’s take a close look at how to use the ajaxStart and ajaxStop methods by giving users a visual queue during a data- and file-submission event in the DVD Collection Catalog. 1. Open chap4/4-6.php. In 4-6.php you will see a form (Figure 4.10 on the next page) that accepts user input and provides a method for uploading a file. This combination is not unusual, but it will require that you pay careful attention when writing the PHP and jQuery to handle the data transfer and file upload.
USING AJAX TO UPDATE CONTENT
119
FIGURE 4.10 The form that users will fill out to add movies to their personal database.
Two PHP scripts will handle the data supplied in the form: one for the movie cover art upload (not really AJAX, remember?) and one for the data input into the form. 2. Create a file called chap4/dvdCollection/inc/dvdcover.php to set up the image upload first. 3. Set up the path for the cover art: $coverPath = “../cover_art/”;
4. Make sure that the file is submitted properly and has no errors: if ($_FILES[“movieCover”][“error”] == UPLOAD_ERR_OK) {
5. Set up the variables to hold the information about the uploaded file (this is the same technique that you used for file uploads in Chapter 3): $tmpName = $_FILES[“movieCover”][“tmp_name”]; $coverName = $_FILES[“movieCover”][“name”];
6. Create the regular expression used to check the file extension of the uploaded file: $regexFileExt = “/\.(jpg|jpeg|png)$/i”;
120
CHAPTER 4
BEING EFFECTIVE WITH AJAX
7. Test the file extension to see if it matches one allowed by the regular expression: if(preg_match($regexFileExt, $coverName)){
8. Check the file again by making sure it really is the right kind of file according to its first few bytes: $arrEXIFType = array(IMAGETYPE_JPEG, IMAGETYPE_PNG); if(in_array(exif_imagetype($tmpName), $arrEXIFType)){
9. Set up the file’s new name and path, and place them into the variable $newCover: $newCover = $coverPath.$coverName;
10. Move the properly named file to its permanent directory: move_uploaded_file($tmpName, $newCover); } } }
Now that you’ve completed the PHP script for the file upload, you can create the PHP script that will be called by the jQuery AJAX post method to update the database. 1. Create a file called postdvd.php and store it in the chap4/dvdCollection/ inc folder. Only two actions are contained in postdvd.php: one to connect to the database and one to run the query that will perform the database update. 2. Set up the database connection first (be sure to use the user name and password that you have set up for your database): if(!$dbc = mysql_connect(‘localhost’, ‘username’, ‘password’)){ echo mysql_error() . “\n”; exit(); }
USING AJAX TO UPDATE CONTENT
121
3. Introduce a little sleep timer to slow down the process. This will allow the animated loading graphic to be displayed by ajaxStart in the jQuery function that will be created (typically, the database operation is very fast—so fast that the user may not realize that something has occurred.): sleep(2);
4. Create the SQL query that will accept the values from the AJAX post method to update the database with: $insertMovie = “INSERT INTO `dvdcollection`.`dvd` “; $insertMovie .= “(`name`,`genre`,`format`,`description`, p `cover`) “; $insertMovie .= “VALUES(“; $insertMovie .= “’”.$_POST[‘movieName’].”’,”; $insertMovie .= “’”.$_POST[‘movieGenre’].”’,”; $insertMovie .= “’”.$_POST[‘movieFormat’].”’,”; $insertMovie .= “’”.$_POST[‘movieDescription’].”’,”; $insertMovie .= “’cover_art/”.$_POST[‘movieCover’].”’ “; $insertMovie .= “)”;
NOTE: Make sure that you run the SQL chap4/dvdCollection/sql/ create_collection_table.sql script in your database platform to set up and populate the table for the DVD collection. 5. Call the mysql_query function to run the SQL query: if(!($movieInfo = mysql_query($insertMovie, $dbc))){ echo mysql_error(); echo mysql_errno(); exit(); }
122
CHAPTER 4
BEING EFFECTIVE WITH AJAX
With the PHP scripts complete, you can now turn your attention to the jQuery functions. All of the jQuery functions will be placed into the file inc/movieUp.js. 1. Start the file by defining the ajaxStart method: $(‘body’).ajaxStart(function(){
The ajaxStart function will be called as soon as an AJAX request is made. The method can be bound to any element available in the DOM and is bound to the body element for use here. You can define any processes that you want within the ajaxStart method. 2. For this file and data upload, create a modal pop-up window to give the users a visual clue that something is occurring: var waitingModal = ‘ p '; $('body').append(waitingModal); var modalMarginTop = ($(‘.waitingModal’).height() + 40) / 2; var modalMarginLeft = ($(‘.waitingModal’).width() + 40) / 2; $(‘.waitingModal’).css({ ‘margin-top’ : -modalMarginTop, ‘margin-left’ : -modalMarginLeft }); $(‘.waitingModal’).fadeIn(‘slow’); });
The technique used to create the modal window is no different than what you have used previously in the book. 3. Bind the ajaxStop method to the body element (remember that methods like ajaxStart and ajaxStop can be bound to any element). When the AJAX request is complete, you’ll want to clear the form and remove the modal from view so that the user knows the process is finished: $(‘body’).ajaxStop(function(){
USING AJAX TO UPDATE CONTENT
123
4. Clear the form elements so that the user can use the form to add another movie. Just like using ajaxStart, you can define any process within the ajaxStop function: $(‘#addMovie input[name*=”movie”]’).val(‘’); $(‘#addMovie textarea’).val(‘’);
Be very specific with your jQuery selectors when choosing which form elements to clear. For example, using just $(‘#addMovie input’) will also clear the form’s buttons, and that would confuse the user. 5. Fade away the modal indicator and remove it from the DOM. This is the last part of the process defined in the ajaxStop method: $(‘.waitingModal’).fadeOut(‘slow’, function(){ $(this).remove(); }); });
6. Begin the form handler by binding the form addMovie to the submit method: $(‘#addMovie’).submit(function(){
7. Upload the image using the iframe method that was defined in Chapter 3: var iframeName = (‘iframeUpload’); var iframeTemp = $(‘<iframe name=”’+iframeName+’” p src=”about:blank” />'); iframeTemp.css('display', 'none'); $('body').append(iframeTemp); $(this).attr({ action: ‘inc/dvdcover.php’, method: ‘post’, enctype: ‘multipart/form-data’, encoding: ‘multipart/form-data’, target: iframeName });
124
CHAPTER 4
BEING EFFECTIVE WITH AJAX
8. Once the image upload is complete, remove the iframe from the DOM: setTimeout(function(){ iframeTemp.remove(); }, 1000);
9. Prepare the data to be used in the post method. Because information in a textarea cannot be serialized with normal jQuery methods, create a text string that sets up the textarea value as if it were serialized by making the information a name=value pair:
FIGURE 4.11 The ajaxStart method has called the waiting indicator.
var coverData = ‘&movieCover=’ + p $(‘input[name=”movieCover”]’).val();
10. Serialize the remainder of the form data: var formData = $(this).serialize();
11. Once the form data has been processed by the serialize function, concatenate the two strings together in the uploadData variable: var uploadData = formData + coverData;
12. Call the jQuery AJAX shorthand method post to upload the data: $.post(‘inc/postdvd.php’, uploadData); });
When the movie data form is submitted, the jQuery AJAX engine will see that there is a post occurring during the process, triggering the ajaxStart method. Figure 4.11 shows the modal loading indicator called by ajaxStart. Once the post process has completed, the ajaxStop method is triggered, causing the modal waiting indicator to fade out. Now that you have learned to handle AJAX calls and the data they return, you need to learn how to handle one of the Web’s fastest-growing data types, JSON. TIP: If you need animated graphics to indicate to your users that something is occurring in the background, check out www.ajaxload.info. There you can generate several different animated graphics in a wide array of colors.
USING AJAX TO UPDATE CONTENT
125
USING JSON JSON (JavaScript Object Notation) has become a popular and lightweight way to transmit data packages for various uses over the Internet. In many ways, JSON is more popular than XML for delivering data quickly and efficiently. JSON data can be easily used with the jQuery AJAX shorthand method especially designed to handle the JSON data type, getJSON. So what exactly is JSON? To understand JSON, you need a little lesson in JavaScript’s object literal notation. Object literal notation is an explicit way of creating an object and is the most robust way of setting up a JavaScript object. Here is an example: var person = { name: “Jay”, occupation: “developer”, stats: [“blonde”, “blue”, “fair”], walk: function (){alert(this.name+ ‘is walking’);} };
The person object has been literally defined as name: value pairs, including a nested array (stats) and a method to make the object walk. It is a very tidy way to describe an object. The following commands interact with the person object: person.walk(); //alerts ‘Jay is walking’ alert(person.stats[1]); // alerts ‘blue’
JSON is a subset of the object literal notation, essentially the name: value pairs that describe an object. A JSON array can contain multiple objects. The key to being successful with JSON is making sure that it is well-formed. JSON must have matching numbers of opening and closing brackets and curly braces (the braces must be in the correct order); the names and values in the name : value pairs must be quoted properly; and commas must separate each name: value pair.
126
CHAPTER 4
BEING EFFECTIVE WITH AJAX
To illustrate this, look at the JSON for the person object: var myJSONobject = {“person”:[{ “name”:”Jay”, “occupation”:”developer”, “stats”:[{ “hair”:”blonde”, “eyes”:”blue”, “skin”:”fair” }] }] };
It’s important to note that the JSON object does not contain any methods or functions that can be executed. JSON specifically excludes these from the notation because JSON is only meant to be a vehicle for transmitting data. SETTING UP A JSON REQUEST
Twitter has undoubtedly become one of the most popular social media outlets since the dawn of the Internet. Twitter has made an API available for those who want to extend the use of Twitter to their own Web pages and applications. One of the most popular uses of the Twitter API is to include recent tweets in personal Web sites and blogs. Taking advantage of the API can be as simple or as complex as you want it to be. Let’s build a simple widget to obtain your last ten tweets for inclusion in a Web page. The tweet data is returned from Twitter in the JSONP format. JSONP is known as “JSON with Padding.” Under normal circumstances, you cannot make AJAX requests outside of the domain the request originates from (Figure 4.12 on the next page). JSONP relies on a JavaScript quirk: <script> elements are allowed to make those cross-domain requests.
USING AJAX TO UPDATE CONTENT
127
Typical AJAX Request (not allowed cross-domain)
JSONP AJAX Request (allowed cross-domain)
FIGURE 4.12 The only way you can make a cross-domain request is with JSONP.
To make this work, the JSON must be returned in a function. Using the JSON object created earlier, the JSONP would look like this: myJSONfunction({“person”:[{“name”:”Jay”, “occupation”:”developer”, p "stats":[{"hair":"blonde","eyes":"blue","skin":"fair"}]}]});
If it looks like gibberish to you now, don’t worry; as you walk through the function being built to get JSON data from Twitter, it will become much clearer. Let’s build the entire file, including CSS, from scratch.
128
CHAPTER 4
BEING EFFECTIVE WITH AJAX
1. Create a file called 4-7.php in the chap4 folder. 2. Set up the DOCTYPE and include the basic head, title, and character set declarations: <meta http-equiv=”Content-Type” content=”text/html; p charset=utf-8” /> Twitter Widget
3. Provide a reference to the jQuery source that you will be using. Make sure that the path is correct; in this case the path is inc/jquery-1.5.2.min.js: <script type=”text/javascript” p src=”inc/jquery-1.5.min.js”>
4. Create the style information for the Twitter widget: <style type=”text/css”> body { background-color: #FFFFCC; } #tw { position: relative; width: 350px; left: 50%; margin-left: -175px; } .tweet { font-family: “Lucida Grande”,”Arial Unicode MS”, p sans-serif; width: 350px;
USING AJAX TO UPDATE CONTENT
129
background-color: #99FFCC; padding: 5px; border-right: 2px solid #66CC99; border-bottom: 3px solid #66CC99; margin-bottom: 2px; }
5. Close out the head section of the page:
The body section for the widget is very simple: Add a div with an id of tw to which the tweets will be appended:
The jQuery script to get the tweets is very short but requires that you pay attention to detail. You will make the names and hash tags clickable so that they have the same functionality they have on the Twitter Web site. Any links included in a tweet will also be clickable, opening a new browser window to show the information. 1. Start the jQuery function by opening a script tag and inserting the documentready function: <script type=”text/javascript”> $(document).ready(function() {
2. Create the URL to access Twitter and store the URL in the variable twitterURL: var twitterURL ='http://twitter.com/statuses/ p user_timeline.json?screen_name= p YOUR_TWITTER_USER_NAME&count=10&callback=?';
Be sure to replace YOUR_TWITTER_USER_NAME with your actual Twitter user name. It is very important to make sure that the URL is formatted with the query string (name=value pairs) that will be used by getJSON during
130
CHAPTER 4
BEING EFFECTIVE WITH AJAX
the request. Send three options to Twitter: your Twitter screen_name, the count of the number of tweets to return, and most important, the callback. It is the callback option that lets Twitter know that you expect the return data to be JSONP. 3. Once the URL is formed, open the getJSON request method by sending the URL and defining the getJSON callback option: $.getJSON(twitterURL, function(data){
NOTE: The callback option for the query string is not the same as the callback for the getJSON request.
4. The JSONP has been returned from Twitter at this point. Set up a loop through the data contained in the function. Treat the data as members of an array called item: $.each(data, function(i, item){
5. Contain the tweet in a name: value pair with the name of text. Assign this item to the variable tweetText: var tweetText = item.text;
6. Use regular expressions to locate URLs, @ tags, and hash(#) tags in the tweet so that you can give each the proper treatment. Look for URL’s first: tweetText = tweetText.replace p (/http:\/\/\S+/g, ‘$&');
The regular expression /http:\/\/\S+/g matches text beginning with http:// and ending in a space, which would typically indicate a URL. The /g (global) says to match all URLs in the string contained in tweetText. The URLs are turned into links by replacing the URL with an anchor tag containing the URL as both the href and the text of the link. In JavaScript the $& property contains the last item matched by a regular expression. Because the URL was the last item matched, it can be replaced into an anchor tag by using the $& property.
USING AJAX TO UPDATE CONTENT
131
7. Twitter prefixes user names with the @ symbol. So, search tweetText for words beginning with the @ symbol: tweetText = tweetText.replace(/(@)(\w+)/g, p ‘ $1$2');
Here, the regular expression /(@)(\w+)/g indicates that all words beginning with the @ symbol are replaced by the appropriate anchor tag to open a browser window for users’ tweets. The $1 and $2 contain the information matched in each parenthesis, which is used to include those matches in the replacement text. 8. Turn your attention to the hash tags now and use a technique similar to the one you used for replacing the @ symbol: tweetText = tweetText.replace(/(#)(\w+)/g, p ‘ $1$2 p ');
9. Once the tweetText has been completely manipulated to insert all of the anchor tags, place it into a div. Then append the new div to the existing div (id=”tw”) that was set up as part of the original content for the page: $(“#tw”).append(‘ p '+tweetText+'');
10. Close out the jQuery function and HTML tags for the page: }); }); });
132
CHAPTER 4
BEING EFFECTIVE WITH AJAX
FIGURE 4.13 The Twitter widget retrieves the last few posts that you made.
11. Upload the page to a server, and load the page into a browser. You should achieve the results that you see in Figure 4.13. With all of the data traveling back and forth between clients and servers, including servers not under your control, it is only natural to be concerned about the security of the information that you and your Web-site visitors send in AJAX requests. Let’s address those concerns next.
USING AJAX TO UPDATE CONTENT
133
SECURING AJAX REQUESTS
One of the vexing problems with Web sites and applications is that users will either inadvertently or purposely submit data through your Web site that can cause harm to your databases and servers. It is important that you take as many steps as possible to guard against the input and transmission of bad or malformed data. Several of these steps have been covered already, including using regular expressions to guide the user to input the right kind of data and making sure that cookies are set uniquely for each Web visitor. As an older, and much wiser, mentor said to me, “Locking the gate in this way only keeps the honest people from climbing the fence.” Even with regular expressions in place for form fields, you cannot stop the transmission of the data because the form can still be submitted. So, what are some of the measures you can take to prevent users from submitting potentially harmful data? 䊏
Prevent form submission by “graying” out the Submit button on forms until all of the regular expression rules for each form field have been met.
䊏
Use cookies to uniquely identify the user (more precisely, the user’s computer) based on registration information and check cookie data against a database during transmission of user-supplied data.
䊏
Clean user-supplied data when it arrives at the back-end process to make sure the data doesn’t contain harmful statements or characters.
䊏
Transmit the data over a secure connection (HTTPS [HyperText Transfer Protocol Secure]) to prevent outsiders from “sniffing” information traveling from and to the Web browser.
NOTE: For more information on HTTPS, visit the Electronic Frontier Foundation’s Web site at www.eff.org/https-everywhere. These techniques should be used in conjunction with each other to present the safest experience for the user and the Web-site owner. Let’s walk through some of these techniques.
134
CHAPTER 4
BEING EFFECTIVE WITH AJAX
PREVENTING FORM SUBMISSION Let’s return to the Photographer’s Exchange Web site and make some changes to the HTML file containing the registration form as well as the jQuery script that supports the form. 1. Open chap4/4-2.php and locate the section of the script where jQuery scripts are included. You’ll find these include declarations between the head tags. 2. Change the following highlighted line to point to the updated jqpe.js file: <script type=”text/javascript” p src=”inc/jquery-1.5.min.js”> <script type=”text/javascript” p src=”inc/jquery.ez-bg-resize.js”> <script type=”text/javascript” p src=”inc/spritenav.js”> <script type=”text/javascript” p src=”inc/carousel.js”> <script type=”text/javascript” p src=”inc/jqpe.js”> <script type=”text/javascript” p src=”inc/peAjax.js”>
After the change, the line will look like this: <script type=”text/javascript” p src=”inc/jqpeUpdated.js”>
3. Save the file as chap4/4-8.php. 4. Open chap4/inc/jqpe.js and save it as chap4/inc/jqpeUpdated.js. Add the code for the error count function. Start by initializing the $submitErrors variable: var submitErrors = 0;
5. Declare a function called errorCount: function errorCount(errors) {
SECURING AJAX REQUESTS
135
6. Set the argument variable errors to be equal to the submitErrors variable: errors = submitErrors;
7. If the error count is zero, you want to enable the submit button. So, remove the disabled attribute from the button. Use the jQuery attribute selectors to select the proper button: if(0 == errors){ $(‘input[type=”submit”][value=”Register”]’). p removeAttr('disabled');
8. If the error count is not zero, the submit button will be disabled. Use the same selector syntax and add the disabled attribute to the button: } else { $(‘input[type=”submit”][value=”Register”]’). p attr('disabled','disabled'); }
9. Close out the function : }
Once the function is in place, you’ll need to make some changes to the password and email validation functions that were created previously. 1. In jqpeUpdated.js locate the password validation function that begins with the comment /*make sure password is not blank */. Insert the two new lines of code highlighted here: /* make sure that password is not blank */ $(function() { var passwordLength = $(‘#penewpass’).val().length; if(passwordLength == 0){ $(‘#penewpass’).next(‘.error’).css(‘display’, p ‘inline’); errorCount(submitErrors++); $(‘#penewpass’).change(function() {
136
CHAPTER 4
BEING EFFECTIVE WITH AJAX
$(this).next(‘.error’).css(‘display’, ‘none’); errorCount(submitErrors--); }); } });
If the password is blank (having a length of zero), the errorCount function is called and the submitErrors variable is incremented by a count of one. errorCount(submitErrors++);
After a password has been entered, the error is cleared and the error count can be reduced by decrementing submitErrors: errorCount(submitErrors--);
2. Locate the email validation function. It begins with the comment /* validate e-mail address in register form */. Add the same calls to the errorCount function where indicated by the following highlights: /* validate e-mail address in register form */ $(function(){ var emailLength = $(‘#email’).val().length; if(emailLength == 0){ $(‘#email’).next(‘.error’).css(‘display’, p ‘inline’); errorCount(submitErrors++); $(‘#email’).change(function() { var regexEmail = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+ p \.[a-zA-Z]{2,4}$/; var inputEmail = $(this).val(); var resultEmail = regexEmail.test(inputEmail); if(resultEmail){ $(this).next('.error').css('display', 'none'); errorCount(submitErrors--);
SECURING AJAX REQUESTS
137
FIGURE 4.14 The Register button is grayed out. It is not available to the user until all errors are cleared.
} }); } });
When the page first loads, submitErrors gets incremented twice—once by each of the validation functions. The total error count prior to the form being filled out is two. Because the submitErrors has a value of two, the submit button is disabled, as illustrated in Figure 4.14. As each function is cleared of its error, the submitErrors variable is decremented until it finally attains a value of zero. When the value of submitErrors is zero, the errorCount function removes the disabled attribute from the submit button and the form can be submitted normally. This technique can be applied to any number of form fields that you need to validate, but it really isn’t enough to prevent malicious users from trying to hack your site. Let’s take a look at another technique you can add to your Web-site application model, giving each user cookies.
138
CHAPTER 4
BEING EFFECTIVE WITH AJAX
USING COOKIES TO IDENTIFY USERS Giving users cookies sounds very pleasant. But it really means that you want to identify users to make sure they are allowed to use the forms and data on your Web site. What you don’t want to do is put sensitive information into cookies. Cookies can be stolen, read, and used. Personally, I’m not a big fan of “remember me cookies” because the longer it takes a cookie to expire, the longer the potentially malicious user has to grab and use information in the cookie. I’d rather cookies expire when the user closes the browser. This would reduce the chance that someone could log in to the user’s computer and visit the same sites to gain information or copy the cookies to another location. What should you store in the cookie? One technique that you can employ that is very effective is storing a unique token in the cookie that can be matched to the user during the user’s current session. Let’s modify the Photographer’s Exchange login process to store a token in the user’s database record. The token will be changed each time the user logs in to the site, and you will use the token to retrieve other data about the user as needed. 1. Open chap4/inc/peRegister.php and locate the section that starts with the comment /* if the login is good */. You will insert new code to create and save the token into the newly created database column. 2. The first line that you need to add creates a unique value to tokenize. Concatenate the user name contained in $_POST[‘pename’] with a time stamp from PHP’s time function. PHP’s time function returns the time in seconds since January 1, 1970. Store that in the variable $tokenValue, as shown in the following highlighted line: /* if the login is good */ if(1 == $loginCount){ if(isset($_POST[‘remember’])){ $tokenValue = $_POST[‘pename’].time(“now”);
3. Modify the information to be stored in $peCookieValue by hashing the $tokenValue with an MD5 (Message Digest Algorithm) hash: $peCookieValue = hash(‘md5’, $tokenValue); $peCookieExpire = time()+(60*60*24*365);
SECURING AJAX REQUESTS
139
$domain = ($_SERVER[‘HTTP_HOST’] != ‘localhost’) ? p $_SERVER['HTTP_HOST'] : false; setcookie('photoex', $peCookieValue, $peCookieExpire, '/', p $domain, false); echo $loginCount; } else {
The MD5 hash algorithm is a cryptographic hash that takes a string and converts it to a 32-bit hexadecimal number. The hexadecimal number is typically very unique and is made more so here by the use of the time function combined with the user’s name. 4. Make the same modifications in the section of the code where no “remember me” value is set: $tokenValue = $_POST[‘pename’].time(“now”); $peCookieValue = hash(‘md5’, $tokenValue); $peCookieExpire = 0; $domain = ($_SERVER[‘HTTP_HOST’] != ‘localhost’) ? p $_SERVER['HTTP_HOST'] : false; setcookie('photoex', $peCookieValue, $peCookieExpire, '/', p $domain, false); echo $loginCount;
5. Add the code that will update the database with the new value: $updateUser = “UPDATE `photoex`.`peuser` “; $updateUser .= “SET `token` = ‘”.$peCookieValue.”’ “; $updateUser .= “WHERE `username` = ‘”.$_POST[‘pename’].”’ “; if(!($updateData = mysql_query($updateUser, $dbc))){ echo mysql_errno(); exit(); }
140
CHAPTER 4
BEING EFFECTIVE WITH AJAX
FIGURE 4.15 The content of the cookie is circled and would-be cookie thieves are foiled!
6. Open chap4/4-8.php and log in to the site with a known good user name and password. The cookie will be set with the token, and the token information will be set in the database. You can use your browser’s built-in cookie viewer (for Figure 4.15, I used Tools > Page Info > Security > View Cookies in the Firefox browser) to examine the value stored in the cookie. Using the value of the token, you can retrieve needed information about the user so that the data can be entered into forms or the appropriate photographs can be displayed. Next, let’s take a look at cleaning up user-supplied data.
CLEANSING USER-SUPPLIED DATA One additional step that you can take to make sure that user-supplied data is safe once it reaches the server is to use your client-side scripting language to ensure that the data is handled safely and securely. A less than savory visitor may visit your site and copy your visible Web pages and functions. Once copied, modifications can be made to your jQuery scripts to remove some of the controls (regular expressions for instance) that you have placed around data. Your first line of defense against that is to replicate those controls in your server-side scripts. 1. Using email validations as an example, open peRegister.php (chap4/inc/ peRegister.php) to modify it.
SECURING AJAX REQUESTS
141
2. Locate the section of the code that begins with the comment /* if the registration form has a valid username & password insert the data */ and supply this regular expression: $regexEmail = ‘/^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/’;
This is the same regular expression used in the jQuery function to validate email addresses into the registration form. 3. Test the value posted against the regular expression with PHP’s preg_match function: preg_match($regexEmail, $_POST[‘email’], $match);
4. The test result, a 1 if there is a match or a 0 if there isn’t a match, is placed into the variable $match that is declared in the preg_match function. Use this result to modify the $_POST[‘email’] variable: if(1 == $match){ $_POST[‘email’] = $_POST[‘email’]; } else { $_POST[‘email’] = ‘E-MAIL ADDRESS NOT VALID’; }
The data from the $_POST[‘email’] variable is used in the SQL query that inserts the data into the database. Many languages, such as PHP, include specific functions for data cleansing. Let’s take a look at two PHP functions that you can use to clean up data before it is entered into a database: htmlspecialchars() and mysql_real_escape_string(). Cleaning up information submitted in HTML format is a simple matter of wrapping the data in PHP’s htmlspecialchars function. Given a form like this: Search For:
142
CHAPTER 4
BEING EFFECTIVE WITH AJAX
The PHP htmlspecialchars function replaces certain characters and returns: Search For:
< p /label>
The following characters have been changed: 䊏
Ampersand (&) becomes ‘&’
䊏
Double quote (“) becomes ‘"’
䊏
Single quote (‘) becomes ‘'’
䊏
The less than bracket (’
Using PHP’s htmlspecialchars function makes user-supplied HTML data much safer to use in your Web sites and databases. PHP does provide a function to reverse the effect, which is htmlspecialchars_decode(). Also just as simple is preventing possible SQL injection attacks by using PHP’s mysql_real_escape_string function. This function works by escaping certain characters in any string. A malicious visitor may try to enter a SQL query into a form field in hopes that it will be executed. Look at the following example in which the visitor is trying to attempt to gain admin rights to the database by changing the database admin password. The hacker has also assumed some common words to try to determine table names: UPDATE `user` SET `pwd`=’gotcha!’ WHERE `uid`=’’ OR `uid` LIKE p ‘%admin%’; --
SECURING AJAX REQUESTS
143
If this SQL query was entered into the user name field, you could keep it from running by using mysql_real_escape_string: $_POST[‘username’] = mysql_real_escape_string($_POST[‘username’]);
This sets the value of $_POST[‘username’] to: UPDATE `user` SET `pwd`=\’gotcha!\’ WHERE `uid`=\’\’ or `uid` like p \’%admin%\’; --
Because the query is properly handled and certain characters are escaped, it is inserted into the database and will do no harm. One other technique that you can use is securing the transmission of data between the client and the server. Let’s focus on that next.
TRANSMITTING DATA SECURELY Another option that you can consider is getting a security certificate for your site or application and then putting your site into an HTTPS security protocol. This is very useful because data traveling between the client and server cannot be read by potential attackers as easily, but it can be costly. All of the Web site data is encrypted according to keys provided by the security certificate. The Web-site information is transmitted back and forth in a Secure Sockets Layer (SSL). The SSL is a cryptographic communications protocol for the Web. Once the data reaches either end of the transmission, it is decrypted properly for use. If you have used a Web site where the URL begins with https:// or you have seen the lock icon on your Web browser, you have used a Web site protected in this manner. Many financial institutions and business Web sites use HTTPS to ensure that their data travels securely. TIP: You can learn more about HTTPS and SSL at the Electronic Frontier Foundation’s Web site atwww.eff.org/https-everywhere.
144
CHAPTER 4
BEING EFFECTIVE WITH AJAX
WRAPPING UP
In this chapter, you learned how to combine jQuery AJAX shorthand methods like .get( ), .post( ) and .load( ) with server-side scripting to add responsiveness to your HTML forms. Included in this chapter were methods for getting a response back from the server that you could process with jQuery to change page content or provide meaningful messages to your Web site visitors. You were also introduced to the jQuery low-level AJAX methods that are used for more complex interactions with Web servers. Finally, you learned about JavaScript Object Notation (JSON) and how jQuery’s JSON methods can be used to retrieve data from services like Twitter or Flickr for use on the Web sites that you will build. If the first taste of a jQuery widget has left you hungry for more, you’re in luck! Chapter 5, “Applying jQuery Widgets,” explores widgets of all shapes and sizes, including several from the jQuery UI project. In addition to widgets from the jQuery UI project, you’ll also learn about using plugins that others have developed and how to roll (and publish) your own plugins to share with others. Read on, Macduff!
WRAPPING UP
145
5 APPLYING jQUERY WIDGETS
jQuery is so easily extended with functionality that jQuery designers and developers have written hundreds of extensions (plugins) ranging from the incredibly simple and useful to the extremely complex and specialized. The jQuery UI (User Interface) library, a group of core plugins for interaction, widgets, and visual effects, continues to be developed as a separate branch of jQuery. Using the jQuery UI library will make your programming life much easier and provide you with the tools to add advanced features to your Web sites and applications effectively. In this chapter, you’ll learn about some very useful widgets from the jQuery UI, as well as some of the most effective and cool plugins made popular by the designer and developer community. In addition, I’ll walk you through the steps to create your own plugins.
USING THE jQUERY UI WIDGETS
FIGURE 5.1 A portion of the ThemeRoller options available for configuring a custom style sheet to use with the jQuery UI widgets.
The jQuery UI is a complete library package to make interactive widgets come to life. A widget is a stand-alone package or tool that adds certain functionality—such as tabs or calendars from which you can pick dates—to your Web interfaces.
NOTE: Widgets are the components of the jQuery UI, whereas plugins is the term for developer-created and maintained widgets. As an added bonus, you can download preconfigured styles, complete with images and icons, from the jQuery UI Web-site gallery (www.jqueryui.com). You can also roll your own CSS with the jQuery UI ThemeRoller, as shown in Figure 5.1.
CUSTOMIZING THE JQUERY UI The jQuery UI ThemeRoller (available at http://jqueryui.com/themeroller) gives you the option of setting the CSS rules for the style sheet that will be downloaded with the jQuery UI library. The CSS rules set in the ThemeRoller are used to give the jQuery UI widgets the information they need to be visually integrated with your Web site.
148
CHAPTER 5
APPLYING jQUERY WIDGETS
Once you have picked a color palette for your Web site or application, it is easy to transfer that color palette and style information to the jQuery UI ThemeRoller (Figure 5.2). You can provide rules for the font settings, colors, and many of the individual elements that make up a jQuery UI widget. As you make the changes to each of the style rules in the ThemeRoller, the elements on the ThemeRoller page are updated automatically so that you can see the results of those changes immediately. Once you have all of your style information set, you need to download the customized theme. When you click the Download theme button, you can select the jQuery UI widgets you want to include in your download. Some of the widgets that you can choose include: 䊏
Accordion. Provides a widget with sliding content areas and is designed to provide a lot of content in a fixed space.
䊏
Autocomplete. Attempts to predict words or phrases based on the input by a user.
䊏
Dialog. Gives the developer a way to create interactive dialog boxes.
䊏
Tabs. Provides a way to transform content containers into an interface resembling tabbed folders.
FIGURE 5.2 The jQuery UI ThemeRoller changes the styles of the elements as the information is entered into the ThemeRoller widget.
USING THE jQUERY UI WIDGETS
149
FIGURE 5.3 The location of the jQuery files and how they are referenced in the HTML files.
Be sure to take the time to read about and familiarize yourself with all of the widgets available from the jQuery UI Web site. For now, download all of the widgets included in the jQuery UI library. In the future you can select just the widgets that you need for a particular project. Once you have configured the CSS theme to your liking, click Download. Your customized jQuery UI package will be presented to you as a compressed archive file in the ZIP format. Save the archive file to your hard drive. Let’s look at how to include the jQuery UI library in your HTML files next. REFERENCING JQUERY UI FILES IN HTML FILES
When the archive file is safely on your hard drive, you can extract the files. It is important to note that the jQuery UI library contains lots of extra files that are not needed for your Web site, so do not transfer them to your Web server. Figure 5.3 shows how I organize files for the most basic Web sites; highlighted are the files that you’ll need from the jQuery UI download. For the version of jQuery UI used in the Web site that will be developed in this chapter, I copied the images directory of the jQuery UI library download (and everything in it) and the jQuery UI CSS file jquery-ui-1.8.12.custom.css and then pasted them into the chap5/css/ui folder. The jQuery UI JavaScript file jquery-ui-1.8.12.custom.min.js is copied and pasted into the chap5/inc/jQuery folder. This will make the jQuery UI library files available to the Web site. The jQuery UI files are then referenced properly in the HTML files that will use the jQuery UI widgets. Let’s take it step by step and create a baseline file that will be added to as the chapter progresses. 1. Create a file called 5-0.php and save it in the chap5 folder.
150
CHAPTER 5
APPLYING jQUERY WIDGETS
2. Create the basic HTML layout for the site:
3. Create the opening head tag and include the basic character type and title of the page: <meta http-equiv=”Content-Type” p content=”text/html; charset=UTF-8” /> The Lodge at Mystic Forrest
4. Reference the Web site’s CSS and jQuery UI CSS files first: <script type="text/javascript" p src="inc/jQuery/jquery-ui-1.8.12.custom.min.js"> p
6. Provide a set of script tags and the document ready wrapper. You will include other jQuery calls in this wrapper: <script type=”text/javascript”> $(document).ready(function() {
});
USING THE jQUERY UI WIDGETS
151
7. Provide the remainder of the tags to complete the basic HTML layout.
With the jQuery UI in place, you can start adding some of the cool widgets that the jQuery UI provides for your Web site.
INCLUDING JQUERY UI WIDGETS The jQuery UI widgets are well designed and easy to configure. In fact, the widgets are so well-designed that in some cases there is very little jQuery code to apply to your interfaces. Typically, you only have to call the widget and add the options required for your site. It is more important that you apply the correct HTML markup when using the jQuery UI widgets. A good example of applying the proper markup is when you decide to build a tabbed interface. So, you’ll do that next. CREATING TABBED INTERFACES
One of the easiest ways to present content or multipart forms to Web-site visitors is with a tabbed interface. People are familiar with the concept of tabs as file folders, so navigating a Web site using tabs seems very natural. Web designers have been creating tabbed interfaces for years using complex CSS and JavaScript. The jQuery UI Tabs widget removes the complexity and adds some extremely flexible features for creating tabbed interfaces. 1. Open the basic file chap5/5-0.php and save it as chap5/5-1.php to set up the markup for the tabbed interface. In the body tag add a div for the header:
2. Set up a div for the content area of the page:
152
CHAPTER 5
APPLYING jQUERY WIDGETS
The tabs are defined by an unordered list. It is important that the anchor tags be preceded with a hash mark (highlighted) because the links will be used to reference any div added later: - Welcome to the p lodge...
- Play with us...
- Stay with us...
3. Set up a div for each tab and make sure that the id for each div matches the text entered into the anchor tags from the previous unordered list: Mystic Forrest welcomes you... Things to do... Make a reservation...
You can place almost any content that you want to in each div, as you will see when other jQuery UI widgets are added to the site. 4. Close out the div tags:
All that is left to do is add a bit of jQuery to turn your markup into tabs.
USING THE jQUERY UI WIDGETS
153
BEFORE
AFTER
FIGURE 5.4 The browser window before and after the addition of the jQuery UI Tabs widget.
5. In the head section of your markup add the highlighted code in the document ready wrapper: <script type=”text/javascript”> $(document).ready(function() { $(‘#contentTabs’).tabs(); });
The jQuery UI takes care of manipulating the CSS for markup and browser events, turning your ordinary unordered list into a tabbed interface (Figure 5.4). By just following a few simple steps, the jQuery UI library eliminates hours of complex and tedious work. That’s it. One line of jQuery code with the proper supporting files and markup has transformed your ordinary Web site into an interactive masterpiece, and it was all made possible by the jQuery UI package. 154
CHAPTER 5
APPLYING jQUERY WIDGETS
The Tabs widget has many options available, including the ability to load content via AJAX. With the proper options set, you can even allow site visitors to rearrange the order of the tabs to suit their preferences. Let’s spice things up by giving users a way to select dates in forms. ADDING CALENDARS TO FORMS
Instead of relying on site visitors to input dates correctly or having to write complex algorithms to parse dates entered by site visitors, it would be much easier if you had a tool that would allow users to select the dates they need to enter into forms. The jQuery UI provides just such a tool—the Datepicker. Let’s add a simple form to the “Stay with us” tab on the site that you are working on. This form gathers just enough information for the Web-site’s owner to respond to site visitors about possible reservations at the site owner’s small hotel. 1. Save a copy of the file you just completed, chap5/5-1.php as chap5/5-2.php. 2. Locate the div with an id of stay. Insert the following markup for a simple form: Arrival Date: p
Departure p Date:
Visitor Name: p
Phone Number: p
Request Reservation
Reset Form
USING THE jQUERY UI WIDGETS
155
The jQuery code to handle both dates (arrivalDate and departureDate) is slightly more complex than the jQuery code for the tabs. Because the owner of the hotel only wants people to inquire about dates today or in the future, you need to set up the Datepicker with its minDate option. Then you’ll need to employ Datepicker’s onSelect option to set up the departure calendar so that only dates beyond the arrival date are available for selection. 3. Start the Datepicker function by binding the Datepicker to the form element that has an id of arrivalDate: $(‘#arrivalDate’).datepicker({
In many cases, options are passed to jQuery UI widgets and the plugins that you will learn about later in the form of an object. As you learned in Chapter 4, JavaScript objects are specified in object literal notation, in other words name: value pairs. 4. You do not want dates in the past to be available for the user to select. So, set the minDate option to 0 to set the earliest selectable date to today (Figure 5.5): minDate: 0,
Once a date has been selected for the arrival, you can use the onSelect option of the Datepicker to create a date value that occurs beyond the arrival date. The site owner does not want the visitor to be able to select a departure date that occurs before the arrival date. 5. Open the onSelect option and pass the selected date in the dateText variable: onSelect: function(dateText) {
6. Begin the calculation of a proper departure date by converting the dateText variable to a real date with JavaScript’s Date function: var depart = new Date(dateText);
7. Set the date contained in the depart variable to one day greater than the value it currently holds (which happens to be the arrival date despite what it is called): depart.setDate(depart.getDate()+1);
156
CHAPTER 5
APPLYING jQUERY WIDGETS
FIGURE 5.5 Users cannot click a date earlier than today, provided that today is July 19, 2011, in this case. FIGURE 5.6 The Datepicker’s minimum departure date is one day greater than the arrival date.
8. Bind the datepicker to the form input element with an id of departureDate and set the minDate option to the new potential departure date: $(‘#departureDate’).datepicker({ minDate: depart });
9. Close up the function with the appropriate braces and parentheses: } });
Once complete, the departure date is set to be a minimum date of the day after the arrival date (Figure 5.6). As with other jQuery UI widgets, the Datepicker provides a wide array of options for customizing the widget, including animations, the ability to show multiple months at once, and the capability to localize the calendar to certain regions with the proper language choice in place. After the Datepicker is added to the form and configured with the options that you desire, you can submit the form using AJAX. Let’s set that up next and use the jQuery UI Dialog widget to give site visitors a chance to confirm their submission.
USING THE jQUERY UI WIDGETS
157
ESTABLISHING A “DIALOG” WITH VISITORS
Part of the interaction that you can establish with users of your Web site or application is provided in the form of dialog boxes. You can use dialog boxes to inform or warn your users. You can also use them to gather additional information from users, even if that information is as simple as confirming a form submission. The jQuery UI Dialog widget is very flexible and offers a number of options for customization. Let’s set up a dialog box to confirm submission of the reservation request. There are several pieces to setting up even a simple dialog box; they include HTML, PHP, and jQuery. To provide the interaction, you’ll set up each of the pieces, beginning with the HTML, next. 1. Open chap5/5-2.php and save a copy of it as chap5/5-3.php. 2. Prior to the closing body tag in the HTML, add the following lines of markup to establish the markup for the dialog box: Are you sure you wish to inquire about these dates?
Because this will be a simple confirmation dialog box, the HTML is very simple. The title attribute in the div tag will be used for the title of the dialog box, whereas the content of the div will be used in the body of the dialog box. 3. Run the SQL file chap5/sql/lodge.sql (available in the code download) on your database package to set up the database and create the table that will hold the reservation requests. Now that the HTML markup is complete and the database table is established, you can turn your attention to creating the PHP code for handling the reservation inquiry.
158
CHAPTER 5
APPLYING jQUERY WIDGETS
4. Create chap5/inc/reserve.php and set up the connection to the database. Be sure to use the correct user name and password for the database connection: if(!$dbc = mysql_connect(‘localhost’, ‘username’, ‘password’)){ echo ‘error connecting to the database(‘.mysql_errno().’): p '.mysql_error() . "\n"; exit(); }
5. Add a sleep function to the process. The sleep function will cause the program to hesitate for the defined time before performing the next line of code (the requirement of adding a sleep statement will become clear in the section “Informing users with a Progressbar”). Set it up for 2 seconds: sleep(2);
6. Create the SQL statement that will be used to place the information from an AJAX post request into the reserverequests table: $reserveIN = “INSERT INTO `lamf`.`reserverequests` “; $reserveIN .= “(`arrival`, `departure`, `guest`, `phone`) “; $reserveIN .= “VALUES (“; $reserveIN .= “’”.mysql_real_escape_string($_POST p [‘arrivalDate’]).”’, “; $reserveIN .= “’”.mysql_real_escape_string($_POST p [‘departureDate’]).”’, “; $reserveIN .= “’”.mysql_real_escape_string($_POST p [‘visitorName’]).”’, “; $reserveIN .= “’”.mysql_real_escape_string($_POST p [‘phoneArea’]).’-’.mysql_real_escape_string($_POST p [‘phoneExchange’]).’-’.mysql_real_escape_string($_POST p [‘phoneNumber’]).”’ “; $reserveIN .= “)”;
USING THE jQUERY UI WIDGETS
159
7. Run the SQL statement on the database and report any errors: if(!($reservation = mysql_query($reserveIN, $dbc))){ echo mysql_errno(); exit(); }
For this form, the AJAX process does not need or expect any return from the database, so no information is returned from the query other than any error that may occur. This completes the PHP, leaving you free to move on to the jQuery script. The jQuery script has two functions, one bound to the form’s Submit button that will call the dialog function and the dialog function itself. 1. Open chap5/5-3.php and locate the document ready function in the head section of the HTML. 2. Start the dialog process by binding a submit method to the reservation form: $(‘#reservationForm’).submit(function(e){
3. Call the jQuery UI Dialog open method on the HTML markup you created earlier in this exercise: $(‘#dialog’).dialog(‘open’);
4. Apply the preventDefault method to the submit event and close the function: e.preventDefault(); });
5. For usage in this site, add one other dialog method bound to the div element you created in the HTML earlier: $(‘#dialog’).dialog({
6. Add the autoOpen option first. By setting this option to false, you keep the dialog box from opening until the dialog open method is called: autoOpen: false,
160
CHAPTER 5
APPLYING jQUERY WIDGETS
7. Set the width of the dialog box: width: 325,
8. Set the modal option to true if you want the dialog box to have the properties that a modal window has (a shaded background through which you can see other content but helps the user to focus on the interaction at hand): modal: true,
9. Set the resizable option to false. For the dialog box to be used in this situation there is no need to make it resizable: resizable: false,
Next, you need to create the buttons for the dialog box. In the dialog box the question, “Are you sure you wish to inquire about these dates?” is presented to the user. The possible answers are YES or NO. Each button will fire its own functions. 10. Create the first button, the YES button: buttons: { “YES”: function() {
11. The jQuery UI Dialog buttons have callback functions available to them. So, within the callback, serialize the form and use jQuery’s AJAX post method to send the serialized data to the PHP handler script chap5/inc/ reserve.php that you created earlier: var formData = $(‘#reservationForm’).serialize(); $.post(‘inc/reserve.php’, formData);
Because there is no data to be returned from the post method, there is no callback assigned to the AJAX function. 12. Clear the text inputs of the form to give users an indication that something has happened: $(‘#reservationForm input[type=”text”]’).val(‘’);
USING THE jQUERY UI WIDGETS
161
FIGURE 5.7 The jQuery UI dialog box is set up to act as a confirmation interaction.
13. Call the dialog close method on the dialog box after the YES button has been clicked and the AJAX call has been performed: $(this).dialog(“close”);
14. For the NO button on the dialog box, there isn’t any functionality required, so close the dialog box: }, “NO”: function() { $(this).dialog(“close”); }
15. Add the closing brackets for the dialog function: } });
16. Navigate to the “Stay with us” tab, fill out the form, and then click Submit. The jQuery UI Dialog widget box pops up and offers you the option of submitting the dates (Figure 5.7). The interaction provided by the jQuery UI Dialog widget works well, but it could leave users wondering if anything occurred. The data was removed from the form very abruptly, and the dialog box disappeared. Users might be more comforted if they see and perceive that an action is taking place. And that sounds like a perfect job for the jQuery UI Progressbar!
162
CHAPTER 5
APPLYING jQUERY WIDGETS
INFORMING USERS WITH A PROGRESSBAR
Using a jQuery UI Progressbar widget to give users a visual cue that a process is occurring can be as simple or as complex as you want to make it. In some cases, you can simply just display an animated Progressbar to indicate to users that an action is occurring. In other instances, you can set up a complex interaction with the jQuery UI Progressbar widget that will allow it to accept incremental information from certain operations that you can then use to move the bar from left to right. AJAX requests do not return the kind of incremental information that you would need to perform this movement, because AJAX requests are asynchronous. You can either guess at the incremental values (not recommended), or you can find other ways to use the jQuery UI Progressbar widget to get the desired result. NOTE: AJAX does not typically return any information to the browser until the XMLHttpRequest is complete (refer to Chapter 4). You can force the browser to return incremental information via the AJAX request, but it is a very complex process and in some cases may cause the user’s browser to “lock up” until the request is complete.
One way to use the jQuery UI Progressbar widget is having it display an animated image to indicate action. That is the method you’ll use here. You’ll show the jQuery UI Progressbar in a modal window using techniques that you learned earlier. Once confirmation about submitting the date information is received, the Progressbar will be invoked in the ajaxStart function. After the AJAX request has completed, the Progressbar will fade out and then disappear. 1. To configure the CSS for the jQuery UI Progressbar and modal window, open chap5/css/lamf.css and insert the shade property: #progressShade {
2. Hide the shade initially by setting its display property to none: display: none;
USING THE jQUERY UI WIDGETS
163
3. Set the color and position of the shade: background: #323232; position: fixed; left: 0; top: 0;
4. Configure the height and width along with the z-index of the shade: width: 100%; height: 100%; z-index: 100; }
5. Set up the CSS rules for the element that will hold the jQuery UI Progressbar widget: #progressbar {
6. Hide the Progressbar until it is needed: display: none;
7. Configure the position, height, and width: position: fixed; height: 12px; width: 200px;
8. Set the correct margin and position data to center the jQuery UI Progressbar widget on the browser window: margin: auto; top: 50%; left: 50%;
9. Set the z-index to a number high enough to ensure that it will appear on top of every other element: z-index: 200; }
164
CHAPTER 5
APPLYING jQUERY WIDGETS
Now you need to prepare the jQuery to display the jQuery UI Progressbar widget. 1. Save a copy of chap5/5-3.php as chap5/5-4.php. 2. Bind ajaxStart to the body: $(‘body’).ajaxStart(function() {
3. Using the same techniques demonstrated earlier in the book for setting up modal windows, add the modal window code into the ajaxStart function. $(‘body’).append(‘ p '); var modalMarginTop = ($('#progressbar').height()) / 2; var modalMarginLeft = ($('#progressbar').width()) / 2; $('#progressbar').css({ 'margin-top' : -modalMarginTop, 'margin-left' : -modalMarginLeft }); $('#progressShade').css('opacity', '0.4');
4. Call the jQuery UI Progressbar widget within the ajaxStart function: $( “#progressbar” ).progressbar({
5. Initialize the Progressbar’s value option to 100. This means that the bar will be fully extended from left to right in the space that it occupies on the Web page: value: 100 });
6. Fade in the Progressbar with the animated image, giving the appearance that an action is occurring: $(‘#progressbar, #progressShade’).fadeIn(250); });
USING THE jQUERY UI WIDGETS
165
FIGURE 5.8 The jQuery UI Progressbar widget indicates to users that a process is running.
7. Remove the jQuery UI Progressbar widget during the ajaxStop function after the AJAX request is completed: $(‘body’).ajaxStop(function() { $(‘#progressbar, #progressShade’).fadeOut(400, function(){ $(‘#progressbar, #progressShade’).remove(); }); });
Under normal circumstances, the AJAX request and response cycle that drives the appearance and removal of the jQuery UI Progressbar widget in the Web site would happen so quickly that the Progressbar would barely have time to appear before it faded away. This is the reason the sleep function was placed into the PHP file in the section “Establishing a ‘dialog’ with visitors.” The sleep function pads the request with a small amount of time that gives the Progressbar a longer screen life. Figure 5.8 shows the Progressbar in action. Giving users visual clues in the manner that the jQuery UI Progressbar widget does is a valuable method for keeping Web-site visitors engaged. Web application
166
CHAPTER 5
APPLYING jQUERY WIDGETS
users appreciate knowing that they have some amount of control over their interaction with the application. Another method that you can use to keep users engaged is the jQuery UI Autocomplete widget. Let’s look at a way to use that widget next. COMPLETING FIELDS AUTOMATICALLY
Blind searches where the user enters information into a form and clicks a button to await the results are nearly history on the Internet today. Many Web sites, including large sites like Google, are opting to provide users with immediate suggestions based on what users type into an input field. The jQuery UI Autocomplete widget gives you the power to accomplish immediate suggestion functionality easily. Let’s add this widget to the Web site next. 1. Open chap5/5-4.php and save a copy of it as chap5/5-5.php. Locate the HTML markup for the second tab. That markup is in the div with an id of play. 2. Set up the only markup needed to support the jQuery UI Autocomplete widget, a form input box: Things to do... Attractions:
3. Set up a div to hold the results of the search:
You’ll create the jQuery script for the Autocomplete widget in a separate file called chap5/inc/jQuery/attractions.js. 4. Make sure you include the following line to reference that file in the head section of 5-5.php: <script type=”text/javascript” p src=”inc/jQuery/attractions.js”>
USING THE jQUERY UI WIDGETS
167
5. To configure the jQuery script file, chap5/inc/jQuery/attractions.js, build an array of attractions: $(function(){ var attractions = [ “Admiral Nimitz Museum - Fredericksburg”, “Aquarena Springs Nature Center - San Marcos”, “Canyon Lake - Sattler”, “Dinosaur Flats - Startzville”, “Enchanted Rock - Fredericksburg”, “Gruene Hall - New Braunfels”, “Guadalupe River State Park - Spring Branch”, “Live Oak Disc Golf Course - Live Oak”, “Longhorn Caverns - Boerne”, “Lost Maples State Park - Vanderpool”, “National Museum of the Pacific War - Fredericksburg”, “Wonder World - San Marcos” ];
6. Bind the autocomplete method to the input text box that was created earlier: $(‘#attractions’).autocomplete({
7. Provide the Autocomplete widget with a reference to the source of the data to be used to perform the job of presenting immediate suggestions to the user. The source here is the array that was completed, called attractions: source: attractions,
8. Place the text for the selected item, returned in ui.item, into the variable selectedAttraction: select: function(event, ui) { var selectedAttraction = ui.item.value;
168
CHAPTER 5
APPLYING jQUERY WIDGETS
9. Split the selectedAttraction variable into an array using the JavaScript split method. The first word of the array, arrayAttractName, is used to identify the element in chap5/inc/attractionInfo.php that will be retrieved:
FIGURE 5.9 As a user starts to type in a search term, the suggested search terms are returned by Autocomplete.
var arrayAttractionName = p selectedAttraction.split(‘ ‘);
10. Load the information about the attraction into the element having the id of attractionInfo: $(‘#attractionInfo’).load(‘inc/attractionInfo.php p #'+arrayAttractionName[0]); } }); });
The progression of the jQuery UI Autocomplete widget is shown in Figure 5.9.
USING THE jQUERY UI WIDGETS
169
The core widgets of the jQuery UI library really do provide a lot of additional functionality in a small and easily usable package. However, these widgets only scratch the surface of what is available to you as a designer or developer for adding interaction via jQuery to your Web applications. Let’s continue to examine widgets that you can add to your sites that are available from other developers just like you. NOTE: The file containing the information about the attractions, chap5/inc/attractionInfo.php, was created with only a couple of attractions for demonstration purposes.
170
CHAPTER 5
APPLYING jQUERY WIDGETS
USING jQUERY PLUGINS
As mentioned previously, the development community embraced and extended jQuery by adding, and continuing to add, hundreds of plugins. Members of the community make these plugins available for other designers and developers in the community to use in their own sites and applications, and the plugins are usually free of any charges or royalties. The jQuery team acknowledges this effort and has included space on its Web site at http://plugins.jquery.com to feature these plugins. On the Web site you can find listings for plugins from AJAX to widgets. Sorting through these plugins to determine some of the most useful was quite a trick due to the sheer volume of plugins available. In the end, I chose several plugins that you’ll be able to put to work quickly and easily in your Web applications and on your Web sites: 䊏
Tablesorter. Gives you the capability to add sorting functions to any ordinary HTML table.
䊏
TinyTips. A tool tip generator that allows you to add further information to almost any element.
䊏
gMap. Makes interacting with Google’s map API straightforward and provides you with a wide range of options to give you the ability to deliver extensive information to your Web-site visitors via maps.
䊏
jqPlot. A powerful plugin that will give you the power to present complex data to your visitors in plot and graph form. NOTE: Developers who provide plugins put a lot of hard work and time into making their products easy to use and free of charge for the Web-site designer and developer community. To support the developers and the continued development of their plugins, I encourage you to donate to these people who help to simplify your job, and mine. (Many plugin Web sites have links on them that allow you to donate to the developer.)
USING JQUERY jQUERY PLUGINS
171
BEEFING UP YOUR APPS WITH PLUGINS When developing Web sites and applications, you’ll turn to certain tools over and over again to accomplish specific effects or provide particular kinds of content. The jQuery plugins discussed in the following sections fit that bill. In addition to providing easy access to certain kinds of content, these jQuery plugins are simple to use and add value to the content that you present to your Web-site visitors. One of the actions that computer users have always appreciated is the ability to sort a data-filled table by one or more columns. Sorting tables helps users to make sense of the data and provides them a way to mine the data for trends. You can extend this action to your Web-based tables by adding the jQuery Tablesorter plugin. SORTING TABLE RECORDS
Christian Bach’s Tablesorter plugin (available fromhttp://tablesorter.com/docs) is the most efficient plugin available for adding sort capabilities to any HTML table. So, let’s incorporate it into the lodge Web site. In the lodge example, the owner wants to see and respond to all of the reservation requests. Because these requests come in with different dates that might not be in order, the lodge owner needs to be able to sort the records and respond to the requests that will come up first. 1. Open chap5/5-5.php and save a copy of it as chap5/5-6.php. 2. Start writing the PHP that will get the list of reservation requests, beginning with the database connection (make sure you use the username and password you have set up for your database):
The PHP will retrieve all of the reservation requests records from the database. 4. Create the HTML section of the page, including the Tablesorter CSS file. Make sure that the Tablesorter plugin script is included after the basic jQuery file: <meta http-equiv=”Content-Type” content=”text/html; p charset=UTF-8” /> The Lodge at Mystic Forrest <script type=”text/javascript” p src=”inc/jQuery/jquery-ui-1.8.12.custom.min.js"> p <script type=”text/javascript” p src="inc/jQuery/jquery.tablesorter.min.js"> p
USING jQUERY PLUGINS
173
5. Bind the Tablesorter method to a table with an id of requests: <script type=”text/javascript”> $(document).ready(function() { $(‘#requests’).tablesorter({
The jQuery Tablesorter plugin has a number of options available, but only one is called here. The Responded column in the table doesn’t need to be sortable. Columns are counted left to right beginning with zero; the Responded column is number four. 6. Set the Responded column’s sorter property to false: headers: {4:{sorter: false}} });
7. Close out the script. });
The function is now ready to perform. 8. Create the body of the HTML markup. Call a PHP script from within the HTML to set up the table to be sorted: Reservation Requests
9. Create a conditional check in the PHP section to test if there is data in the table; if not, the PHP code will return a message that there is no data available so that the user doesn’t perceive that there might be something wrong with this application:
15. Put the rest of the HTML tags into place. Figure 5.10 shows the completed table.
The records are sorted in the order in which they were input into the database. In this table four columns, Arrival Date, Departure Date, Guest Name, and Guest Phone, are sortable. Figure 5.11 shows the sorting action that occurs when you click on the header for Arrival Date. NOTE: I purposely omitted how users can remove a record from being displayed in the table by selecting the check box in the column Responded. A good exercise would be to add the jQuery change event to the check boxes and use jQuery’s AJAX functionality to mark that record as responded to. Then users will only have to view the records they need to respond to.
No matter how simple or complex your tables may be, the Tablesorter plugin will provide you with many options to ensure that your Web-site users can sort data to their heart’s content. Another way of providing additional information is supplying a tool tip when the mouse hovers over an element in your HTML page. Let’s add a tool-tip plugin to the site that will provide additional information about the tabs.
176
CHAPTER 5
APPLYING jQUERY WIDGETS
FIGURE 5.10 The freshly loaded table with the data unsorted.
FIGURE 5.11 The first column is ordered from earliest arrival date to latest arrival date.
USING jQUERY PLUGINS
177
FIGURE 5.12 A TinyTip provides more information about a tab on the lodge’s Web site.
PROVIDING BITE-SIZED INFORMATION
Tool tips, such as the one shown in Figure 5.12, can be a great way to present your Web-site visitors with additional information about a link or a word on a Web page. The jQuery TinyTips plugin (available at www.mikemerritt.me/blog/jqueryplugin-tinytips-1-1 and authored by Mike Merritt ) is a small, easy-to-use, and extremely flexible plugin that will give you the option of presenting pictures as well as text in pop-up style tool tips. Let’s try it! 1. Open chap5/5-6.php and save a copy of it as chap5/5-7.php. Insert the source references for the TinyTips CSS and jQuery script files in the head section (highlighted): <script type="text/javascript" p src="inc/jQuery/jquery-ui-1.8.12.custom.min.js">
178
CHAPTER 5
APPLYING jQUERY WIDGETS
<script type="text/javascript" p src="inc/jQuery/attractions.js"> <script type=”text/javascript” p src="inc/jQuery/jquery.tinyTips.js">
2. Locate the $(document).ready(function() {… section of the code between the head tags and include the following jQuery to set up the TinyTips: $(‘a.tinyTip’).tinyTips(‘yellow’, ‘title’);
You are binding the anchor tags with a class of tinyTip to the tinyTips method. The properties in the tinyTips method are (in order) the CSS styles to use and the element attribute that will be displayed in the tool tip. 3. To create TinyTips on a couple of the tabs on the lodge’s Web site, include the class tinyTip and add a title attribute to the HTML markup for the tabs: - p Welcome to the lodge...
- Play with us...
3. Add the following style rules and properties in your CSS file chap5/css/ lamf.css. These properties will be used to define the container for the map: #lodgeMap { position: relative;
4. Define a height and width for the element used to hold the map: width: 700px; height: 450px;
180
CHAPTER 5
APPLYING jQUERY WIDGETS
5. Center the element that holds the map on the screen: margin-left: -350px; left: 50%; }
6. Add the jQuery code for the gMap plugin to the document ready wrapper in the head section of the HTML file, chap5/5-8.php. Bind the gMap plugin to the element that will hold the map: <script type=”text/javascript”> $(document).ready(function(){ $(‘#lodgeMap’).gMap({
7. Set your gMap options. Place a marker at a certain latitude and longitude: markers: [{ latitude: 29.871266, longitude: -98.237708 }],
8. Pass the type of map and zoom level to the gMap plugin: maptype: G_PHYSICAL_MAP, zoom: 12 }); });
USING jQUERY PLUGINS
181
FIGURE 5.13 The marker created by the gMap plugin shows the lodge’s location on an island.
The maptype: G_PHYSICAL_MAP option provides a terrain view on the map (Figure 5.13). 9. Add the element to hold the map somewhere in the HTML body:
10. Load the page. The jQuery gMap plugin presents the map centered on the location entered complete with a marker and zoomed in at such a level as to provide some detail about the terrain to users. Again, be sure to check the gMap Web site for many more options that were not demonstrated here. Plotting points on a map and plotting information in a chart are easy when using jQuery plugins. To make data reporting more intuitive, it is often desirable to present that information graphically as bar or pie charts, or along plot and trend lines. The next plugin, jqPlot, provides a thorough library for providing these types of charts to your Web-application users.
182
CHAPTER 5
APPLYING jQUERY WIDGETS
PLOTTING AND CHARTING DATA
Up to this point, the plugins have been fairly simple to use. Chris Leonello’s jqPlot plugin is no different (available at www.jqplot.com) in its simplicity. What is different is the volume of options available to you for creating and customizing many types of graphs and charts. This kind of flexibility comes at a price: You must be meticulous in how you set up the display and data details when using this plugin. In this example, you’ll create a bar chart (Figure 5.14) to show the lodge owner the number of reservation requests per month that come through the Web site. You’ll add the chart to the page where the lodge owner sees the reservation requests that need to be processed. Start the exercise by modifying the site’s CSS file.
FIGURE 5.14 jqPlot is used to set up a horizontal bar chart of reservation requests per month.
1. Open chap5/css/lamf.css and add a height and width property to the CSS selector requestChart. This selector will be connected to the element in the HTML where the chart is to be displayed: #requestChart { width: 800px; height: 350px; } USING jQUERY PLUGINS
183
To retrieve the data from the database and format the data properly for use by the jQuery jqPlot plugin, the PHP must be crafted very carefully. jqPlot expects a label (in the form of a numerical index value) and a value to be plotted on the chart in pairs using JavaScript Object Notation (JSON): [0,1],[0,2],[0,3],[0,4],[6,5],[2,6],[3,7],[0,8],[1,9],[0,10], p [0,11],[1,12]
The first number in each pair represents the value to be plotted. The second value is the plot index (in this case matched to a month of the year). TIP: Many jQuery plugins use data configured as JSON based on its being a subset of JavaScript’s object literal notation. This helps to keep notation consistent from plugin to plugin and helps the developer avoid having to learn different formats for passing information to plugins. The PHP request to the MySQL database will use the same connection that was created earlier; let’s look at the code you’ll add to the PHP section of the page. 2. Save a copy of chap5/5-8.php as chap5/5-9.php. This is the file you will add the additional PHP and jQuery code to for displaying the bar graph. 3. Declare a variable in the PHP section of 5-9.php that will hold the plot data from the database immediately after the database query is done: $ra = ‘’;
4. Create an array called requestArray that will be used to index the database request: $requestArray = array(1,2,3,4,5,6,7,8,9,10,11,12);
5. Loop through the $requestArray and start making requests to the database based on the $requestArray: for($i = 0; $i < count($requestArray); $i++){ $getReservationsByMonth = “SELECT count(*) as reqCount p FROM `lamf`.`reserverequests` WHERE SUBSTRING p (`arrival`, 1, 2) = ".$requestArray[$i];
184
CHAPTER 5
APPLYING jQUERY WIDGETS
6. Run the query. The query returns any errors that occur: if(!($requestsMonth = p mysql_query($getReservationsByMonth, $dbc))){ echo mysql_errno(); exit(); }
7. To make sure that the JSON array string is formatted properly, insert a comma between each bracketed pair of values. If the value of $i is less than 11 (December), insert the comma (highlighted): if($i < 11){ $ra .= ‘[‘. mysql_result($requestsMonth, 0) p .’,’. ($i+1) . '],’;
PHP’s mysql_result returns the first item (the count of requests made in the given month) from the query $requestsMonth. Because the index of the $requestArray is actually one less than the actual numerical index of the month (remember that PHP array indexes start with zero), you add 1 to that value to make sure the months line up properly. 8. Eliminate the possibility of putting a comma after the pair if the month is December ($i == 11): } else { $ra .= ‘[‘. mysql_result($requestsMonth, 0) p .’,’. ($i+1) . ']'; } }
Now that the PHP is outputting the proper data format, you can focus your attention on inserting the right files to be referenced in the head section of the HTML. The jqPlot plugin has several optional add-ons, and depending on the chart you expect to display, you may have to include any number of these add-ons.
USING jQUERY PLUGINS
185
9. Make sure that you reference jqPlot’s CSS style sheet: