No Starch Press The Book Of Java Script, A Practical Guide To Interactive Web Pages 2nd (2007)

User Manual: Pdf

Open the PDF directly: View PDF PDF.
Page Count: 519

DownloadNo Starch Press The Book Of Java Script, A Practical Guide To Interactive Web Pages 2nd (2007)
Open PDF In BrowserView PDF
THE BOOK of

™

JAVASCRIPT
2ND EDITION

A P R A C T I C A L G U I D E T O INTERACTIVE
WEB PAGES

by thau!

®

San Francisco

THE BOOK OF JAVASCRIPT, 2ND EDITION. Copyright © 2007 by Dave Thau.
First edition © 2000 by Dave Thau.
All rights reserved. No part of this work may be reproduced or transmitted in any form or by any means, electronic or
mechanical, including photocopying, recording, or by any information storage or retrieval system, without the prior
written permission of the copyright owner and the publisher.
Printed on recycled paper in the United States of America
10 09 08 07 06

123456789

ISBN-10: 1-59327-106-9
ISBN-13: 978-1-59327-106-0
Publisher: William Pollock
Associate Production Editor: Christina Samuell
Cover and Interior Design: Octopod Studios
Developmental Editors: Jim Compton, William Pollock, and Riley Hoffman
Technical Reviewer: Luke Knowland
Copyeditor: Publication Services, Inc.
Compositors: Riley Hoffman and Megan Dunchak
Proofreader: Stephanie Provines
Indexer: Nancy Guenther
For information on book distributors or translations, please contact No Starch Press, Inc. directly:
No Starch Press, Inc.
555 De Haro Street, Suite 250, San Francisco, CA 94107
phone: 415.863.9900; fax: 415.863.9950; info@nostarch.com; www.nostarch.com
Library of Congress Cataloging-in-Publication Data
Thau.
The book of JavaScript : a practical guide to interactive Web pages / Thau!. -- 2nd ed.
p. cm.
Includes index.
ISBN-13: 978-1-59327-106-0
ISBN-10: 1-59327-106-9
1. JavaScript (Computer program language) I. Title.
QA76.73.J39T37 2006
005.13'3--dc22
2006011786
No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and
company names mentioned herein may be the trademarks of their respective owners. Rather than use a trademark
symbol with every occurrence of a trademarked name, we are using the names only in an editorial fashion and to the
benefit of the trademark owner, with no intention of infringement of the trademark.
The information in this book is distributed on an “As Is” basis, without warranty. While every precaution has been
taken in the preparation of this work, neither the author nor No Starch Press, Inc. 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
information contained in it.

I dedicate this revised edition of The Book of JavaScript to my wonderful
wife Kirsten Menger-Anderson, who never failed to keep a straight
face when I said, “It’s almost done.”

BRIEF CONTENTS

Foreword by Luke Knowland ......................................................................................... xxi
Foreword to the First Edition by Nadav Savio ................................................................ xxiii
Acknowledgments ....................................................................................................... xxv
Introduction .............................................................................................................. xxvii
Chapter 1: Welcome to JavaScript! .................................................................................. 1
Chapter 2: Using Variables and Built-in Functions to
Update Your Web Pages Automatically.................................................................... 15
Chapter 3: Giving the Browsers What They Want............................................................ 33
Chapter 4: Working with Rollovers................................................................................. 51
Chapter 5: Opening and Manipulating Windows ............................................................ 67
Chapter 6: Writing Your Own JavaScript Functions .......................................................... 83
Chapter 7: Providing and Receiving Information with Forms .............................................. 99
Chapter 8: Keeping Track of Information with Arrays and Loops ...................................... 123
Chapter 9: Timing Events ............................................................................................ 147
Chapter 10: Using Frames and Image Maps ................................................................. 169
Chapter 11: Validating Forms, Massaging Strings, and
Working with Server-Side Programs ....................................................................... 191
Chapter 12: Saving Visitor Information with Cookies ...................................................... 215

Chapter 13: Dynamic HTML ........................................................................................ 233
Chapter 14: Ajax Basics ............................................................................................. 261
Chapter 15: XML in JavaScript and Ajax ...................................................................... 279
Chapter 16: Server-Side Ajax ...................................................................................... 299
Chapter 17: Putting It All Together in a Shared To Do List ............................................... 331
Chapter 18: Debugging JavaScript and Ajax ................................................................ 363
Appendix A: Answers to Assignments ........................................................................... 381
Appendix B: Resources ............................................................................................... 405
Appendix C: Reference to JavaScript Objects and Functions............................................ 411
Appendix D: Chapter 15’s Italian Translator and Chapter 17’s To Do List Application ........ 455
Index ........................................................................................................................ 469

viii

Brief Contents

CONTENTS IN DETAIL
FOREWORD by Luke Knowland
FOREWORD TO THE FIRST EDITION by Nadav Savio
ACKNOWLEDGMENTS
INTRODUCTION

xxi
xxiii
xxv
xxvii

How This Book Is Organized .................................................................................. xxvii
Companion Website ...............................................................................................xxx

1
WELCOME TO JAVASCRIPT!

1

Is JavaScript for You?................................................................................................. 1
Is This Book for You? ................................................................................................. 2
The Goals of This Book .............................................................................................. 2
What Can JavaScript Do? .......................................................................................... 3
What Are the Alternatives to JavaScript?...................................................................... 5
CGI Scripting .............................................................................................. 5
VBScript...................................................................................................... 7
Java ........................................................................................................... 7
Flash .......................................................................................................... 7
JavaScript’s Limitations............................................................................................... 7
JavaScript Can’t Talk to Servers ..................................................................... 7
JavaScript Can’t Create Graphics .................................................................. 8
JavaScript Works Differently in Different Browsers ............................................ 8
Getting Started ......................................................................................................... 8
Where JavaScript Goes on Your Web Pages................................................................ 9
Dealing with Older Browsers .................................................................................... 10
Your First JavaScript ................................................................................................ 12
Summary................................................................................................................ 12
Assignment............................................................................................................. 13

2
USING VARIABLES AND BUILT-IN FUNCTIONS TO
UPDATE YOUR WEB PAGES AUTOMATICALLY

15

Variables Store Information ...................................................................................... 16
Syntax of Variables .................................................................................... 16
Naming Variables...................................................................................... 17
Arithmetic with Variables ............................................................................ 18
Write Here Right Now: Displaying Results.................................................................. 19
Line-by-Line Analysis of Figure 2-4 ................................................................ 20
Strings ................................................................................................................... 20
Line-by-Line Analysis of Figure 2-6 ................................................................ 21

More About Functions.............................................................................................. 21
alert()........................................................................................................ 22
Line-by-Line Analysis of Figure 2-9 ................................................................ 23
prompt() .................................................................................................... 24
Parameters ............................................................................................................. 25
Writing the Date to Your Web Page .......................................................................... 26
Built-in Date Functions ................................................................................. 26
Date and Time Methods .............................................................................. 26
Code for Writing the Date and Time............................................................. 27
Line-by-Line Analysis of Figure 2-12 .............................................................. 29
How the European Space Agency Writes the Date to Its Page ...................................... 30
Summary................................................................................................................ 31
Assignment............................................................................................................. 31

3
GIVING THE BROWSERS WHAT THEY WANT

33

A Real-World Example of Browser Detection .............................................................. 34
Browser Detection Methods ...................................................................................... 35
Quick-but-Rough Browser Detection .............................................................. 35
More Accurate Browser Detection ................................................................ 36
Redirecting Visitors to Other Pages ............................................................................ 37
if-then Statements .................................................................................................... 38
Boolean Expressions ................................................................................... 38
Nesting..................................................................................................... 40
if-then-else Statements ................................................................................. 40
if-then-else-if Statements ............................................................................... 41
When and Where to Place Curly Brackets..................................................... 41
OR and AND ......................................................................................................... 42
OR ........................................................................................................... 43
AND ........................................................................................................ 44
Putting It All Together ............................................................................................... 45
A Few More Details About Boolean Expressions.......................................................... 47
How Netscape Provides Browser-Specific Content ....................................................... 48
Summary................................................................................................................ 50
Assignment............................................................................................................. 50

4
W O R K I N G W IT H R O L L O V E R S

51

A Real-World Example of Rollovers ........................................................................... 52
Triggering Events .................................................................................................... 53
Event Types ............................................................................................... 53
Quotes in JavaScript................................................................................... 55
Clicking the Link to Nowhere ....................................................................... 56
More Interesting Actions.............................................................................. 57
Swapping Images ................................................................................................... 58
Working with Multiple Images .................................................................................. 59

x

Contents in D e ta i l

What’s with All the Dots? ........................................................................................ 60
The document Object.................................................................................. 60
Object Properties ....................................................................................... 61
Finally, Rollovers! ....................................................................................... 62
Image Preloading....................................................................................... 62
How the Tin House Rollovers Work............................................................................ 64
Summary................................................................................................................ 65
Assignment............................................................................................................. 65

5
OPENING AND MANIPULATING WINDOWS

67

Real-World Examples of Opening Windows to Further Information................................ 68
Working with Windows as Objects ........................................................................... 69
Opening Windows.................................................................................................. 69
Manipulating the Appearance of New Windows ........................................... 70
Some Browsers and Computers Open Windows Differently ............................. 72
Closing Windows ................................................................................................... 72
Using the Right Name: How Windows See Themselves and Each Other ........................ 73
Moving Windows to the Front or Back of the Screen.................................................... 74
Window Properties.................................................................................................. 74
The status Property ..................................................................................... 74
The opener Property ................................................................................... 75
More Window Methods........................................................................................... 77
Resizing Windows ..................................................................................... 77
Moving Windows ...................................................................................... 77
Summary................................................................................................................ 80
Assignment............................................................................................................. 80

6
WRITING YOUR OWN JAVASCRIPT FUNCTIONS

83

Functions as Shortcuts .............................................................................................. 84
Basic Structure of JavaScript Functions .......................................................... 84
Naming Your Functions............................................................................... 85
Parentheses and Curly Brackets.................................................................... 85
An Example of a Simple Function ................................................................. 85
Writing Flexible Functions ........................................................................................ 86
Using Parameters ....................................................................................... 87
Line-by-Line Analysis of Figure 6-4 ................................................................ 88
Using More Than One Parameter ................................................................. 90
Getting Information from Functions ............................................................................ 91
Line-by-Line Analysis of Figure 6-9 ................................................................ 92
Dealing with Y2K .................................................................................................... 93
Line-by-Line Analysis of Figure 6-12 .............................................................. 94
Defining Variables Properly ...................................................................................... 94
Summary................................................................................................................ 96
Assignment............................................................................................................. 97

Contents in D etai l

xi

7
P R O V ID I N G A N D R E C E I V I N G I N F O R M A T I O N
WITH FORMS

99

Real-World Examples of Forms................................................................................ 100
Form Basics .......................................................................................................... 101
Text Fields ............................................................................................... 102
Buttons, Checkboxes, and Radio Buttons ..................................................... 102
Select Elements ........................................................................................ 104
Textareas ................................................................................................ 106
Final Form Comments ............................................................................... 106
Forms and JavaScript............................................................................................. 107
Naming Form Elements ............................................................................. 107
Naming Radio Buttons .............................................................................. 108
Naming Options ...................................................................................... 108
Reading and Setting Form Elements ......................................................................... 109
Reading Information from Text Fields .......................................................... 109
Setting the Value of a Text Field ................................................................. 110
Textareas ................................................................................................ 111
Checkboxes............................................................................................. 112
Radio Buttons........................................................................................... 114
Pull-Down Menus and Scrollable Lists .......................................................... 115
Handling Events Using Form Elements ...................................................................... 116
Make this a Shortcut .............................................................................................. 117
Using Pull-Down Menus as Navigational Tools .......................................................... 118
One Last Forms Shortcut......................................................................................... 119
How the Doctors Without Borders Pull-Down Navigation Tool Works........................... 120
Summary.............................................................................................................. 120
Assignment........................................................................................................... 121

8
KEEPING TRACK OF INFORMATION WITH
ARRAYS AND LOOPS

123

Real-World Examples of Arrays............................................................................... 123
JavaScript’s Built-In Arrays ...................................................................................... 124
Figuring Out How Many Items an Array Contains ..................................................... 126
Going Through Arrays ........................................................................................... 126
while Loops .......................................................................................................... 128
while Loops and Arrays ............................................................................ 129
Going Off the Deep End ........................................................................... 130
Using array.length in Your Loop................................................................. 131
An Incremental Shortcut ............................................................................ 131
Beware of Infinite Loops ............................................................................ 131
for Loops.............................................................................................................. 132
How AntWeb Checks Off All the Checkboxes .......................................................... 133
Line-by-Line Analysis of Figure 8-11 ............................................................ 133
Creating Your Own Arrays..................................................................................... 134
Line-by-Line Analysis of Figure 8-12 ............................................................ 135
How the Book of JavaScript Tip Box Works .............................................................. 136
Checking for Blank Statements ................................................................... 137
Checking the Last Element in the Array........................................................ 137
xii

C on t e n t s i n D e t a i l

Testing the Limits of Arrays ........................................................................ 137
The startScroll() Function............................................................................ 138
A Streamlined Version .............................................................................. 139
Loops Can Nest .................................................................................................... 140
Creating Arrays As You Go Along .......................................................................... 140
Associative Arrays................................................................................................. 142
Line-by-Line Analysis of Figure 8-18 ............................................................ 144
Summary.............................................................................................................. 144
Assignment........................................................................................................... 145

9
T IM IN G E V E N TS

147

Real-World Examples of Timing Events..................................................................... 147
Setting an Alarm with setTimeout()........................................................................... 148
Canceling an Alarm with clearTimeout()................................................................... 149
Line-by-Line Analysis of Figure 9-3 .............................................................. 150
Repeating Timed Actions........................................................................................ 150
Line-by-Line Analysis of Figure 9-5 .............................................................. 152
Using parseInt() with Form Elements ............................................................ 152
Clearing Out a Time-Out Before You Set a New One ................................... 153
Declaring Variables That Hold Time-Outs Outside Functions .......................... 153
Building a Clock with Timing Loops ......................................................................... 154
Line-by-Line Analysis of Figure 9-7 .............................................................. 155
How the Book of JavaScript Website’s Timer Works .................................................. 155
How Space.com’s Countdown Script Works............................................................. 157
Calculating Times..................................................................................... 160
Global Variables and Constants................................................................. 160
A Timed Slide Show .............................................................................................. 161
Line-by-Line Analysis of Figure 9-11 ............................................................ 162
A Safer Version of rotateImage() ............................................................................. 163
Why Declaring a Variable Outside a Function Is Unsafe ............................... 163
Why You Can’t Put var Inside a Timing Loop ............................................... 163
The Solution ............................................................................................ 164
The Hitch ................................................................................................ 165
The Solution to the Hitch............................................................................ 165
Why image_array Is Declared Outside the rotateImage() Function.................. 166
Summary.............................................................................................................. 167
Assignment........................................................................................................... 167

10
U S IN G FR A M E S A N D I M A G E M A P S

169

A Real-World Example of Frames and Image Maps................................................... 170
Frames................................................................................................................. 170
Frame Basics ........................................................................................... 170
Frames and JavaScript .............................................................................. 172
Frames and Image Swaps ......................................................................... 174
Changing the Contents of Two Frames at Once ........................................... 176
Frames Inside Frames ............................................................................... 177
JavaScript and Frames Inside Frames.......................................................... 179
Contents i n Detail

xiii

Frame Busting .......................................................................................... 179
Using Frames to Store Information .............................................................. 181
Line-by-Line Analysis of Figure 10-15 .......................................................... 183
Image Maps ......................................................................................................... 184
Image Map Basics.................................................................................... 185
Image Maps and JavaScript ...................................................................... 186
How Salon’s Bug-Eating Script Works...................................................................... 186
Salon’s Nested Frames ............................................................................. 188
Salon’s Image Map .................................................................................. 188
The changeMe() Function .......................................................................... 188
Summary.............................................................................................................. 189
Assignment........................................................................................................... 190

11
VALIDATING FORMS, MASSAGING STRINGS,
AND WORKING WITH SERVER-SIDE PROGRAMS

191

A Real-World Example of Form Validation ............................................................... 192
Making Sure a Visitor Has Filled Out a Form Element ................................................ 192
Line-by-Line Analysis of Figure 11-2 ............................................................ 194
String Handling..................................................................................................... 196
Breaking Strings Apart .............................................................................. 196
Matching String Patterns with Regular Expressions........................................ 203
How Dictionary.com’s Form Validators Work ........................................................... 207
Line-by-Line Analysis of Figure 11-11 .......................................................... 210
Summary.............................................................................................................. 213
Assignment........................................................................................................... 214

12
S A V IN G V I S IT O R I N F O RM A TI O N W I TH C O O K IE S

215

A Real-World Example of Cookies........................................................................... 216
What Are Cookies?............................................................................................... 216
What Cookies Can and Can’t Do ........................................................................... 217
Working with Cookies ........................................................................................... 218
Setting Cookies........................................................................................ 218
Reading Cookies...................................................................................... 218
Resetting Cookies ..................................................................................... 219
Setting More Than One Piece of Information................................................ 220
Setting the Duration of a Cookie ................................................................ 222
Who Can Read the Cookie?...................................................................... 224
The Whole Cookie ................................................................................... 224
Setting Multiple Cookies............................................................................ 225
Cookie Libraries.................................................................................................... 225
A Cookie-Based Shopping Cart .............................................................................. 226
Adding an Item to the Cart ........................................................................ 227
The Checkout Page................................................................................... 229
The readTheCookie() Function.................................................................... 230
The checkOut() Function ........................................................................... 231
Summary.............................................................................................................. 232
Assignment........................................................................................................... 232
xiv

Contents in D e ta i l

13
DYNAMIC HTML

233

Real-World Examples of DHTML.............................................................................. 234
CSS Basics ........................................................................................................... 234
The 
Tag ......................................................................................... 235 Positioning a div with CSS......................................................................... 235 Hiding a div ............................................................................................ 237 Layering divs ........................................................................................... 237 JavaScript and DHTML........................................................................................... 238 Making divs Move ................................................................................................ 239 Using setTimeout() and clearTimeout() to Animate a Page ........................................... 239 Line-by-Line Analysis of Figure 13-10 .......................................................... 240 Changing the Contents of a div............................................................................... 241 spans and getElementsByTagName() ....................................................................... 242 Advanced DOM Techniques ................................................................................... 244 W3C DOM Overview .............................................................................. 245 Creating and Adding Elements Using the W3C DOM .................................. 245 Adding Text to an Element......................................................................... 246 Adding Elements in the Middle of a Page and Removing Elements ................. 247 Additional DOM Details............................................................................ 248 Manipulating a Page Using the DOM ......................................................... 250 Fancy Event Handling ............................................................................................ 250 The event Object...................................................................................... 250 Adding Event Handlers Using JavaScript ..................................................... 254 Drop-Down Menus ................................................................................................ 257 Line-by-Line Analysis of Figure 13-23 .......................................................... 259 The Borders ............................................................................................. 259 Summary.............................................................................................................. 259 Assignment........................................................................................................... 260 14 AJAX BASICS 261 A Real-World Example of Ajax ............................................................................... 262 Introduction to Ajax ............................................................................................... 263 Asynchronicity—The A in Ajax................................................................... 264 XML—The X in Ajax ................................................................................. 265 JavaScript—The J in Ajax .......................................................................... 265 Creating and Sending Requests .............................................................................. 265 Creating a Request Object ........................................................................ 265 Telling the Object Where to Send the Request ............................................. 266 What to Do When the Request Is Answered ................................................ 266 Writing JavaScript That Is Called After the Request Has Been Answered ......... 268 Sending the Request ................................................................................. 268 Putting Everything Together........................................................................ 269 Getting the Results .................................................................................... 270 Demonstrating Asynchronicity ................................................................................. 271 Line-by-Line Analysis of Figure 14-6 ............................................................ 273 C on t e n t s i n D e t a i l xv Ajax and Usability ................................................................................................ 274 The Back Button ....................................................................................... 274 URLs and Bookmarking ............................................................................. 274 Poor Design............................................................................................. 274 To Ajax, or Not to Ajax ......................................................................................... 275 Bad: Just Because You Can ....................................................................... 275 Bad: It’s the Hot New Thing....................................................................... 275 Bad: Replacing Something That Works with Something New and Confusing ........................................................... 275 Good: In-Context Data Manipulation .......................................................... 276 Good: Interactive Widgets ........................................................................ 276 Good: Saving State .................................................................................. 276 Summary.............................................................................................................. 276 Assignment........................................................................................................... 277 15 X M L IN J A V A S C R I P T A N D A J A X 279 A Real-World Example of Ajax and XML.................................................................. 280 Google Suggest .................................................................................................... 281 XML—the Extensible Markup Language.................................................................... 282 The Rules of XML ................................................................................................... 283 The XML Header ...................................................................................... 283 XML Elements........................................................................................... 284 XML Attributes.......................................................................................... 284 Illegal XML Characters .............................................................................. 284 XML Documents Have a Single Root Element................................................ 285 Final Comments About the XML Format ....................................................... 285 Processing XML ..................................................................................................... 285 Line-by-Line Analysis of Figure 15-6 ............................................................ 287 Internet Explorer, responseXML, and Client-Side Ajax ................................... 291 Problems with White Space in XML ............................................................ 291 Creating a Suggest Application for Translation ......................................................... 292 Finding the Translations ............................................................................ 294 Displaying the Results ............................................................................... 295 Summary.............................................................................................................. 296 Assignment........................................................................................................... 297 16 SERVER-SIDE AJAX 299 Real-World Examples of Server-Side Ajax ................................................................ 300 The Power of Webservers....................................................................................... 301 A Server-Side Programming Language ..................................................................... 303 PHP Basics ........................................................................................................... 304 Sending Simple Input to PHP with a GET Request ...................................................... 305 Passing Input in a URL............................................................................... 305 Using PHP to Read the Inputs of a GET Request............................................ 306 xvi Contents in D e ta i l Creating a Google Suggest Application with an Ajax GET Request ............................. 308 Contacting Third-Party Webservers with Ajax and PHP ................................. 308 The JavaScript for the Homemade Google Suggest Application ..................... 309 Using PHP to Contact Other Webservers ..................................................... 313 Ajax and the POST Method .................................................................................... 314 An Ajax-Friendly Form .............................................................................. 316 POSTing with Ajax ................................................................................... 316 Sending XML Information from the Browser to a Webserver........................... 318 HEAD Requests: Getting Information About a Server-Side File .................................... 318 Adding Headers to Your Responses............................................................ 319 Headers and XML .................................................................................... 320 The Caching Problem ............................................................................................ 320 File Handling in PHP.............................................................................................. 321 Creating and Adding Contents to a Text File with PHP .................................. 321 Reading Files in PHP................................................................................. 322 When Communication Breaks Down........................................................................ 323 Automatically Updating a Web Page When a Server-Side File Changes ...................... 325 readFileDoFunction()................................................................................. 327 callReadFile() ........................................................................................... 327 callUpdateIfChanged().............................................................................. 328 stopTimer() .............................................................................................. 328 Recap and Breathe................................................................................... 328 The Server-Side PHP Code......................................................................... 328 Summary.............................................................................................................. 329 Assignment........................................................................................................... 330 17 PUTTING IT ALL TOGETHER IN A SHARED TO DO LIST 331 Features of the To Do List Application ...................................................................... 332 To Do List Data Files .............................................................................................. 334 userInfo.xml............................................................................................. 334 To Do List File .......................................................................................... 335 To Do List Server Side ............................................................................................ 336 The To Do List Client Side, Part 1: The HTML............................................................. 337 The To Do List Client Side, Part 2: The JavaScript ...................................................... 338 The Function Road Map ............................................................................ 339 Logging In and Out .................................................................................. 340 Functions Related to Logging In .................................................................. 341 Helper Functions ...................................................................................... 343 Displaying Available Lists .......................................................................... 346 Displaying a Specific List........................................................................... 349 Processing Changes to a List...................................................................... 352 Limitations on Manipulating XML Documents................................................ 356 Adding a New Item.................................................................................. 357 A Few Closing Notes............................................................................................. 359 Client-Side or Server-Side Code?................................................................ 359 Security Issues.......................................................................................... 359 Summary.............................................................................................................. 361 Assignment........................................................................................................... 361 Contents in D etai l xvii 18 D E B U G G I N G J A V A S C R IP T A N D A J A X 363 Good Coding Practices.......................................................................................... 364 Starting with Comments ............................................................................ 364 Filling In the Code .................................................................................... 365 Avoiding Common Mistakes ................................................................................... 365 Use a Consistent Naming Convention......................................................... 365 Avoid Reserved Words ............................................................................. 366 Remember to Use Two Equal Signs in Logical Tests....................................... 366 Use Quotation Marks Correctly .................................................................. 366 Finding Bugs......................................................................................................... 367 Printing Variables with alert() Statements ..................................................... 367 Debugging Beyond Alerts.......................................................................... 369 Using Your Browser’s Bug Detector............................................................. 370 Using JavaScript Debuggers ...................................................................... 370 Debugging Ajax in Firefox 1.5 and 2.0 ...................................................... 374 Other Debugging Resources ...................................................................... 376 Fixing Bugs .......................................................................................................... 376 Back Up Your Program ............................................................................. 377 Fix One Bug at a Time .............................................................................. 377 Avoid Voodoo Coding.............................................................................. 377 Look for Similar Bugs ................................................................................ 378 Clear Your Head...................................................................................... 378 Ask for Help ............................................................................................ 378 Summary.............................................................................................................. 379 A A N S W E R S T O A S S IG N M E N T S Chapter Chapter Chapter Chapter Chapter Chapter Chapter Chapter Chapter Chapter Chapter Chapter xviii 381 2 ............................................................................................................ 381 3 ............................................................................................................ 383 4 ............................................................................................................ 383 5 ............................................................................................................ 384 index.html ............................................................................................... 384 image_page.html ..................................................................................... 384 6 ............................................................................................................ 385 7 ............................................................................................................ 385 8 ............................................................................................................ 387 9 ............................................................................................................ 389 10 .......................................................................................................... 390 index.html ............................................................................................... 390 assignment-nav.html.................................................................................. 390 blank.html ............................................................................................... 391 11 .......................................................................................................... 391 index.html ............................................................................................... 391 assignment-nav.html.................................................................................. 392 blank.html ............................................................................................... 394 12 .......................................................................................................... 394 13 .......................................................................................................... 395 C on t e n t s i n D e t a i l Chapter 14 .......................................................................................................... 397 addressBook.xml...................................................................................... 397 index.html ............................................................................................... 397 Chapter 17 .......................................................................................................... 399 Join Functions .......................................................................................... 400 Giving a User Access to Your To Do List...................................................... 402 B RESOURCES 405 Tutorials ............................................................................................................... 405 HTML Tutorials ......................................................................................... 406 Cascading Style Sheets Tutorials ................................................................ 406 Advanced Topics in JavaScript................................................................... 406 Ajax Tutorials .......................................................................................... 407 Example JavaScript and Ajax Code......................................................................... 407 Good Ajax Websites ............................................................................................. 407 Ajax Frameworks .................................................................................................. 408 JavaScript ............................................................................................... 408 PHP ........................................................................................................ 409 Java ....................................................................................................... 409 .NET....................................................................................................... 410 Ruby....................................................................................................... 410 C REFERENCE TO JAVASCRIPT OBJECTS AND FUNCTIONS 411 alert()................................................................................................................... 413 Anchor ................................................................................................................ 413 Applet ................................................................................................................. 413 Area.................................................................................................................... 414 Array................................................................................................................... 414 Button (Including Submit and Reset Buttons) .............................................................. 416 Checkbox............................................................................................................. 417 clearInterval()........................................................................................................ 417 clearTimeout() ....................................................................................................... 417 confirm() .............................................................................................................. 418 Date .................................................................................................................... 418 Document............................................................................................................. 421 elements[] ............................................................................................................ 423 escape()............................................................................................................... 423 eval() ................................................................................................................... 423 Event ................................................................................................................... 423 FileUpload ........................................................................................................... 424 Form.................................................................................................................... 424 Hidden ................................................................................................................ 426 History ................................................................................................................. 426 HTMLElement........................................................................................................ 427 Image .................................................................................................................. 429 C o n te n t s i n D e t a i l xix isNaN() ............................................................................................................... 430 Link ..................................................................................................................... 431 Location ............................................................................................................... 431 Math ................................................................................................................... 432 Navigator ............................................................................................................ 433 Number ............................................................................................................... 434 Option................................................................................................................. 435 parseInt().............................................................................................................. 436 parseFloat() .......................................................................................................... 436 Password ............................................................................................................. 436 prompt() ............................................................................................................... 438 Radio .................................................................................................................. 438 Reset ................................................................................................................... 439 Screen ................................................................................................................. 439 Select .................................................................................................................. 439 setInterval() ........................................................................................................... 440 setTimeout() .......................................................................................................... 441 String................................................................................................................... 441 Style .................................................................................................................... 445 Submit ................................................................................................................. 446 Text ..................................................................................................................... 446 Textarea............................................................................................................... 447 this ...................................................................................................................... 448 unescape() ........................................................................................................... 448 var ...................................................................................................................... 448 window ............................................................................................................... 448 XMLHttpRequest and ActiveXObject("Microsoft.XMLHTTP") ......................................... 454 D CHAPTER 15’S ITALIAN TRANSLATOR AND CHAPTER 17’S TO DO LIST APPLICATION 455 Chapter 15’s Italian Translator................................................................................ 455 Chapter 17’s To Do List Application ........................................................................ 457 todo.html................................................................................................. 457 readXMLFile.php ...................................................................................... 467 saveXMLFile.php ...................................................................................... 467 INDEX xx Co ntents i n Detail 469 FOREWORD The first JavaScript I remember writing was a routine to change two frames at the same time. I was the production specialist for HotWired, and it was shortly after frames and JavaScript debuted, well before there was documentation for either. Fortunately, it was also well before Internet Explorer 3.0 appeared on the scene, so I only had to make sure my JavaScript worked for Netscape 2.0. Even so, without a reference book to point out where possible pitfalls could be or answer simple questions such as how to set variables that JavaScript would like or how to make different windows talk to each other, it was one hell of a challenge. And it was deeply satisfying when I got it to work correctly. When Dave asked me to do the technical review of the second edition of The Book of JavaScript, I couldn’t have been more pleased or honored. The deep satisfaction I felt when I wrote those first JavaScripts and they worked correctly, and the deeper satisfaction I felt as more and more browsers were released and I figured out how to write cross-browser and cross-platform JavaScript, are the same feelings I got when I read Dave’s explanations and examples. He describes what a piece of code is going to do and how to think about it, then lays out an example of code that makes sense—whether you’re a seasoned programmer or entirely new to JavaScript. On top of all that, he takes a practical approach to programming, he’s able to explain complex problems in a way that doesn’t make them sound daunting, and when you’re done covering each topic, you feel like you’ve earned the knowledge. That’s rare, and it’s really, really refreshing. Since the first edition of this book was published, there have been a few advancements in JavaScript, most notably the advent of Ajax. Ajax is a concept that makes even a few professional programmers’ heads spin, but (not surprisingly) Dave manages to break down what Ajax is and what it isn’t, explains when it makes sense to use it, and shows you how to do it. If you’re new to JavaScript, you win—you couldn’t ask for a better person to teach you how to program. If you’re an old hat at JavaScript and you’re looking for a refresher course or wondering how to take advantage of Ajax, you win too. Happy coding! Luke Knowland Interaction Designer, Six Apart San Francisco xxii F o r e w or d FOREWORD TO THE FIRST EDITION I learned JavaScript completely on my own. There was no one to tell me about “event handlers” or how to set cookies. No one even explained what a variable is, let alone the best ways to name them. Of course I had reference books, but they were intimidating tomes, full of cryptic lists and tables, written by programmers for programmers. David Thau is a remarkable combination of natural teacher and seasoned programmer. As a result, The Book of JavaScript not only teaches JavaScript thoroughly and enjoyably in a friendly, unintimidating tone, but it teaches programming as elegantly as any book I’ve seen. In fact, I’ve always thought of this as Thau’s ulterior motive—he pretends he’s just showing you how to make a rollover or validate the text in an HTML form, but before you know it you’ve learned how to code! Perhaps the most telling thing I can say is that, reading this book, I can’t help but wish I was learning JavaScript for the first time. If you are, then consider yourself lucky to have Thau as a teacher. You couldn’t do better. Happy JavaScripting! Nadav Savio Principal, Giant Ant Design San Francisco ACKNOWLEDGMENTS This second edition of The Book of JavaScript took me much longer to complete than I could have imagined. I’d like to thank the entire No Starch Press staff for putting up with all the delays and surprise extra bits. I would especially like to thank Christina Samuell for moving the process along, William Pollock, Riley Hoffman, Jerome Colburn, and Stephanie Provines for extensive edits, and Luke Knowland for making sure all the code works and offering many excellent suggestions. I’d also like to thank my neighbor, Laurentino Padilla, for sweeping our sidewalk on Thursdays. Without him, this book would have taken even longer to finish. INTRODUCTION You are about to begin a journey through JavaScript— a programming language that adds interactivity and spark to web pages all over the Internet. This book, written primarily for nonprogrammers, provides scripts you can cut and paste for use on your website, but it also explains how they work, so you’ll soon be writing your own scripts. Each chapter focuses on a few important JavaScript features, shows you how professional websites incorporate those features, and gives you examples of how you might add those features to your own web pages. How This Book Is Organized Before you dive in, here is a quick overview of what you’ll learn as you make your way through The Book of JavaScript. Have fun! Chapter 1: Welcome to JavaScript! This chapter lays out the book’s goals, introduces you to JavaScript and compares it to other tools, describes some of the nifty ways in which JavaScript can enhance your web pages, and walks you through writing your first JavaScript. Chapter 2: Using Variables and Built-in Functions to Update Your Web Pages Automatically Did you know that JavaScript can figure out what day it is and write the date to a web page? This chapter will show you how. Along the way you’ll also learn how JavaScript remembers things using variables and performs actions using functions. Chapter 3: Giving the Browsers What They Want In this chapter you’ll learn how to direct someone to a web page specifically designed for his or her browser. You’ll figure out which browser the visitor is using, then you’ll use if-then statements and their kin to point the visitor in the right direction. Chapter 4: Working with Rollovers This chapter covers everyone’s favorite JavaScript trick—the image swap. You’ll also learn how to trigger JavaScript based on a viewer’s actions. Chapter 5: Opening and Manipulating Windows This chapter explains everything you need to know about opening new browser windows—another favorite JavaScript trick. You’ll also learn how JavaScript writes HTML to the new windows, closes them, and moves them around on the screen. Chapter 6: Writing Your Own JavaScript Functions Functions are the major building blocks of any JavaScript program, so learning to write your own is a critical step toward JavaScript mastery. This chapter gives you the tools you’ll need to write your own functions and put them to work. Chapter 7: Providing and Receiving Information with Forms This chapter shows you how JavaScript works with HTML forms to collect all kinds of information from your users and give them fancy ways to navigate your site. Chapter 8: Keeping Track of Information with Arrays and Loops JavaScript calls lists arrays, and they come in very handy. This chapter describes how JavaScript deals with these lists, whether they include all the images on a web page or all the friends in your address book. Chapter 9: Timing Events This chapter discusses setting events to occur at specific times. For example, you can open a window and then close it in five seconds, or you can write a clock that updates every second. Once you know how to do this, you can create games and other interactive applications based on timed events. xxviii I n t ro d u c t i o n Chapter 10: Using Frames and Image Maps How JavaScript works with HTML frames and image maps is the subject of this chapter. It covers topics including changing two or more frames at once and preventing your web page from getting trapped in someone else’s frame set. Chapter 11: Validating Forms, Massaging Strings, and Working with Server-Side Programs This chapter shows you how to make sure people are filling out your HTML forms completely. Along the way, you’ll learn fancy ways to check user input—for example, you’ll learn how to check the formatting of an email address. Chapter 12: Saving Visitor Information with Cookies Cookies are bits of code that let your web pages save information a visitor has provided even after he or she turns off the computer. This allows your site to greet a guest by name whenever he visits (if he tells you his name, of course!). Chapter 13: Dynamic HTML This chapter introduces Dynamic HTML, a feature of newer browsers that lets you animate entire web pages. Chapter 14: Ajax Basics This chapter begins a trilogy of chapters on Ajax, a programming technique that helps you build websites that act like desktop applications. Here you’ll be introduced to Ajax and most of the JavaScript you’ll need to know to create Ajax applications. Chapter 15: XML in JavaScript and Ajax The X in Ajax stands for XML. This chapter describes how to represent information using the XML data-sharing standard and process XML documents using JavaScript. Chapter 16: Server-Side Ajax You’ll wrap up your introduction to Ajax with instructions for writing programs that run on webservers. This chapter touches on the PHP programming language and shows you how PHP programs store files on webservers and contact other webservers for information. Chapter 17: Putting It All Together in a Shared To Do List In this chapter you’ll apply everything you learned in the first 16 chapters and create a collaborative To Do list application. Not much new material will be introduced, but you’ll see how everything we’ve covered so far fits together. Chapter 18: Debugging JavaScript and Ajax This chapter wraps things up by giving you tips for what to do when the JavaScript you’ve written isn’t working correctly. Appendix A: Answers to Assignments Here you’ll find answers to the assignments that end each chapter. I n t r od u ct i o n xxix Appendix B: Resources This appendix provides information about the many JavaScript and Ajax libraries you can use to further enhance your web pages. Appendix C: Reference to JavaScript Objects and Functions This appendix lists all of the objects and functions that comprise JavaScript. Appendix D: Chapter 15’s Italian Translator and Chapter 17’s To Do List Application The last appendix gives a couple of the book’s longest code examples in their entirety. Companion Website The Book of JavaScript website (http://www.bookofjavascript.com) contains the code examples from each chapter, archived copies of many of the websites mentioned, and lots of script libraries and freeware. You’ll find that each chapter has its own directory, complete with the example scripts and relevant images from that chapter, as well as the answer to that chapter’s assignment. Here’s a rundown of the directories. /Chapter01, /Chapter02, and so on Each chapter has its own directory. For example, the code examples from Chapter 1 are available at http://www.bookofjavascript.com/ Chapter01. /Freeware This directory contains free software you may find useful, including: z XAMPP webserver and PHP packages for Windows and Linux z MAMP webserver and PHP packages for Macintosh z Flock social web browser z Venkman JavaScript debugger for Firefox z Firefox 2.0 browser /Libraries This directory contains free JavaScript libraries you can cut and paste into your website, including: z Prototype JavaScript Framework z Webmonkey Cookie Library z Sarissa XML Toolkit /Websites This directory contains HTML (including JavaScript) and images for many of the websites discussed in the book. xxx I n t r o d u c ti o n WELCOME TO JAVASCRIPT! Welcome to The Book of JavaScript. JavaScript is one of the fastest and easiest ways to make your website truly dynamic— that is, interactive. If you want to spruce up tired-looking pages, you’ve got the right book. This book will give you some ready-made JavaScripts you can implement immediately on your website, but, more importantly, it will take you step by step through sample scripts (both hypothetical and real-world examples) so that you understand how JavaScript works. With this understanding you can modify existing scripts to fit your specific needs as well as write scripts from scratch. Your knowledge of JavaScript will grow as you work through the book; each chapter introduces and explores in depth a new JavaScript topic by highlighting its application in real-life situations. Is JavaScript for You? If you want a quick, easy way to add interactivity to your website, if the thought of using complex programming languages intimidates you, or if you’re interested in programming but simply don’t know where to start, JavaScript is for you. JavaScript, a programming language built into your web browser, is one of the best ways to add interactivity to your website because it’s the only crossbrowser language that works directly with web browsers. Other languages such as Java, Perl, PHP, and C don’t have direct access to the images, forms, and windows that make up a web page. JavaScript is also very easy to learn. You don’t need any special hardware or software, you don’t need access to a webserver, and you don’t need a degree in computer science to get things working. All you need is a web browser and a text editor such as SimpleText or Notepad. Finally, JavaScript is a complete programming language, so if you want to learn more about programming, it provides a great introduction. (If you don’t give a hoot about programming, that’s fine too. There are plenty of places— including this book and its companion website—where you can get prefab scripts to cut and paste right into your pages. But you’ll get much more out of the book by using it as a tool for learning JavaScript programming.) Is This Book for You? This book assumes you don’t have any programming background. Even if you have programmed before, you’ll find enough that’s new in JavaScript to keep you entertained. One of the best things about JavaScript is that you don’t have to be a mega-expert to get it working on your web pages right away. You do need a working knowledge of HTML, however. The Goals of This Book The main goal of this book is to get you to the point of writing your own JavaScripts. An important tool in learning to write scripts is the ability to read other people’s scripts. JavaScript is a sprawling language, and you can learn thousands of little tricks from other scripts. In fact, once you’ve finished this book, you’ll find that viewing the source code of web pages that use JavaScript is the best way to increase your knowledge. Each of the following chapters includes JavaScript techniques used in building professional sites. Along the way, I’ll point out sites that use the technique described, and by viewing the source code of such sites you’ll soon see there are many ways to script. Sometimes going through a site’s code reveals interesting aspects of JavaScript that I don’t cover in this book. Beyond learning how to write your own JavaScript and read other people’s scripts, I also want you to learn where to look for additional information on JavaScript. As I’ve noted, the best place to learn new techniques is to view the source code of web pages you find interesting. However, several websites also offer free JavaScripts. I’ll be introducing some of these as we go along, but here are a few good examples to get you started: 2 Chapter 1 z http://www.webmonkey.com/reference/javascript_code_library z http://javascript.internet.com z http://www.scriptsearch.com/JavaScript/Scripts z http://www.javascriptsearch.com Another good place to get information is a JavaScript reference book. The Book of JavaScript is primarily a tutorial for learning basic JavaScript and making your website interactive. It’s not a complete guide to the language, which includes too many details for even a lengthy introduction to cover. If you’re planning to become a true JavaScript master, I suggest picking up JavaScript: The Definitive Guide by David Flanagan (O’Reilly, 2006) after making your way through this book. The last 500 or so pages of Flanagan’s book list every JavaScript command and the browsers in which it works. What Can JavaScript Do? JavaScript can add interactivity to your web pages in a number of ways. This book offers many examples of JavaScript’s broad capabilities. The following are just two examples that illustrate what you can do with JavaScript. The first example (Figure 1-1) is a flashing grid of colored squares (to get the full effect, browse to http://www.bookofjavascript.com/Chapter01/ Fig01-01.html), created by a fellow named Taylor way back in 1996. Flashy, isn’t it? In this example, a JavaScript function changes the color of a randomly chosen square in the grid every second or so. Figure 1-1: A demonstration of JavaScript’s artful abilities W e l co me t o Jav aS c r i p t ! 3 Mousing over one of the five icons below the squares (number, plus sign, square, letter, and horizontal line) tells the page to use a new set of images on the grid. For example, mousing over the number icon tells the JavaScript to start replacing the squares with 1s and 0s. This page illustrates four important JavaScript features you’ll learn about throughout the book: z How to change images on a web page z How to affect web pages over time z How to add randomness to web pages z How to dynamically change what’s happening on a web page based on an action taken by someone viewing the page Although Taylor’s demo is beautiful, it’s not the most practical application of JavaScript. Figure 1-2 (available at http://www.bookofjavascript.com/ Chapter01/Fig01-02.html) shows you a much more practical use of JavaScript that calculates the weight of a fish based on its length. Enter the length and type of fish, and the JavaScript calculates the fish’s weight. This fishy code demonstrates JavaScript’s ability to read what a visitor has entered into a form, perform a mathematical calculation based on the input, and provide feedback by displaying the results in another part of the form. You may not find calculating a fish’s weight a particularly useful application of JavaScript either, but you can use the same skills to calculate a monthly payment on a loan (Chapter 7), score a quiz (Chapter 10), or verify that a visitor has provided a valid email address (Chapter 11). Figure 1-2: How much does my fish weigh? 4 Chapter 1 These are just two examples of the many features JavaScript can add to your websites. Each chapter will cover at least one new application. If you want a preview of what you’ll learn, read the first page or so of each chapter. What Are the Alternatives to JavaScript? Several other programming languages can add interactivity to web pages, but they all differ from JavaScript in important ways. The four main alternatives are CGI scripting, Java, VBScript, and Flash. CGI Scripting Before JavaScript, using CGI scripts was the only way to make web pages do more than hyperlink to other web pages containing fixed text. CGI stands for Common Gateway Interface. It’s a protocol that allows a web browser running on your computer to communicate with programs running on webservers. It is most often used with HTML forms—pages where the user enters information and submits it for processing. For example, the user might see a web page containing places for entering the length and selecting the type of a fish, as well as a Compute button. When the user keys in the length, selects the type, and clicks the button, the information is sent to a CGI script on the server. The CGI script (which is probably written in a programming language like Perl, PHP, or C) receives the information, calculates the weight of the fish, and sends the answer, coded as an HTML page, back to the browser. CGI scripts are very powerful, but because they reside on webservers, they have some drawbacks. The Need for Back-and-Forth Communication First, the connection between your web browser and the webserver limits the speed of your web page’s interactivity. This may not sound like a big problem, but imagine the following scenario: You’re filling out an order form with a dozen entry fields including name, address, and phone number (see Figure 1-3), but you forget to fill out the phone number and address fields. When you click the Submit button to send the information across the Internet to the webserver, the CGI script sees that you didn’t fill out the form completely and sends a message back across the Internet requesting that you finish the job. This cycle could take quite a while over a slow connection. If you fill out the form incorrectly again, you have to wait through another cycle. People find this process tiresome, especially if they’re customers who want their orders processed quickly. With JavaScript, though, the programs you write run in the browser itself. This means that the browser can make sure you’ve filled out the form correctly before sending the form’s contents to the webserver. JavaScript thus reduces the time your information spends traveling between the browser and the server. W e l co me t o Jav aS c r i p t ! 5 Figure 1-3: A simple order form Server Overload by Concurrent Access Another drawback to CGI scripts is that a webserver running a CGI program can get bogged down if too many people call the script simultaneously (for example, if too many fishermen decided to run the weight calculator and click the Compute button at the same time). Serving up HTML pages is pretty easy for a webserver. However, some CGI scripts take a long time to run on a machine, and each time someone calls the script, the server has to start up another copy of it. As more and more people try to run the script, the server slows down progressively. If a thousand people are trying to run the script at once, the server might take so long to respond that either the user or the browser gives up, thinking the server is dead. This problem doesn’t exist in JavaScript because its scripts run on each visitor’s web browser—not on the webserver. Security Restrictions A third problem with CGI scripts is that not everyone has access to the parts of a webserver that can run CGI scripts. Since a CGI script can conceivably crash a webserver or exploit security flaws, system administrators generally guard these areas, only allowing fellow administrators access. If you have Internet access through an Internet service provider (ISP), you may not be allowed to write CGI scripts. If you are designing web pages for a company, you may not be given access to the CGI-enabled areas of the webserver. 6 Chapter 1 JavaScript, on the other hand, goes right into the HTML of a web page. If you can write a web page, you can put JavaScript in the page without permission from recalcitrant administrators. VBScript The language most similar to JavaScript is Microsoft’s proprietary language, VBScript (VB stands for Visual Basic). Like JavaScript, VBScript runs on your web browser and adds interactivity to web pages. However, VBScript works only on computers running Internet Explorer (IE) on Microsoft Windows, so unless you want to restrict your readership to people who use IE on Windows, you should go with JavaScript. Java Although JavaScript and Java have similar names, they aren’t the same. Netscape, now a part of AOL, initially created JavaScript to provide interactivity for web pages, whereas Sun Microsystems wrote Java as a general programming language that works on all kinds of operating systems. Flash Flash is a tool from Macromedia developed to add animation and interactivity to websites. Almost all modern browsers can view Flash animations or can easily download the Flash plug-in. Flash animations look great, and a basic Flash animation requires no programming skills at all. To create Flash animations, however, you must purchase a Flash product from Macromedia. While some people consider Flash and JavaScript to be competitors, that’s not the case. In fact, you can call JavaScript programs from Flash, and you can manipulate Flash animations using JavaScript. Web page designers will often blend the two, using Flash for animations and JavaScript for interactivity that does not involve animations. Flash animations can also be made more interactive using a language called ActionScript, which is almost exactly like JavaScript. JavaScript’s Limitations Yes, JavaScript does have limitations, but these limitations are natural and unavoidable by-products of its main purpose: to add interactivity to your web pages. JavaScript Can’t Talk to Servers One of JavaScript’s drawbacks is also its main strength: It works entirely within the web browser. As we’ve seen, this cuts down on the amount of time your browser spends communicating with a webserver. On the other hand, this also means that JavaScript can’t communicate with other machines and therefore can’t handle some server tasks you may need to do. W e l co me t o Jav aS c r i p t ! 7 For example, JavaScript can’t aggregate information collected from your users. If you want to write a survey that asks your visitors a couple of questions, stores their answers in a database, and sends a thank-you email when they finish, you’ll have to use a program that runs on your webserver. As we’ll see in Chapter 7, JavaScript can make the survey run more smoothly, but once a visitor has finished filling out the questions, JavaScript can’t store the information on the server, because it can’t contact the server. In order to store the survey information, you need to use a program that runs on a webserver. Sending email with JavaScript is also impossible, because to send email JavaScript would have to contact a mail server. Again, you need a server-side program for this job. Although JavaScript can’t directly control programs that run on webservers, it can ask webservers to run programs, and it can send information to those programs. We’ll see examples of that in Chapters 7 and 14, and we’ll get a taste for writing server-side programs in Chapters 15 and 16. JavaScript Can’t Create Graphics Another of JavaScript’s limitations is that it can’t create its own graphics. Whereas more complicated languages can draw pictures, JavaScript can only manipulate existing pictures (that is, GIF or JPEG files). Luckily, because JavaScript can manipulate created images in so many ways, you shouldn’t find this too limiting. JavaScript Works Differently in Different Browsers Perhaps the most annoying problem with JavaScript is that it works somewhat differently in different browsers. JavaScript was introduced in 1996 by Netscape in version 2 of Netscape Navigator. Since then, JavaScript has changed, and every browser implements a slightly different version of it—often adding browser-specific features. Luckily, starting in the late 1990s, the European Computer Manufacturers Association (ECMA) began publishing standards for JavaScript, which they call ECMAScript. About 99 percent of all browsers being used today comply with at least version 3 of the ECMA standard. These include Internet Explorer version 5.5 and later, Netscape version 6 and later, Mozilla, Firefox, all versions of Safari, and Opera version 5 and later. Because almost all browsers currently in use adhere to version 3 of the ECMA standard, I’ll be using that as the standard version of JavaScript in the book. Where incompatibilities between browsers arise, I’ll point them out. Getting Started We’re about ready to begin. To write JavaScripts, you need a web browser and a text editor. Any text editor will do: Notepad or WordPad in Windows and SimpleText on a Macintosh are the simplest choices. Microsoft Word or Corel’s WordPerfect will work as well. You can also use a text editor such as BBEdit or HomeSite, which are designed to work with HTML and JavaScript. Some tools for building websites will actually write JavaScript for you— for example, Adobe’s Dreamweaver and GoLive. These tools work fine when 8 Chapter 1 you want to write JavaScripts for common features such as image rollovers and you know you’ll never want to change them. Unfortunately, the JavaScript often ends up much longer than necessary, and you may find it difficult to understand and change to suit your needs. Unless you want a JavaScript that works exactly like one provided by the package you’ve purchased, you’re often best off writing scripts by hand. Of course, you can also use one of these tools to figure out how you want your page to behave and then go back and rewrite the script to suit your specific needs. NOTE Always save documents as text only, and end their names with .html or .htm. If you’re using Microsoft Word or WordPerfect and you don’t save your documents as text-only HTML or HTM files, both programs will save your documents in formats web browsers can’t read. If you try to open a web page you’ve written and the browser shows a lot of weird characters you didn’t put in your document, go back and make sure you’ve saved it as text only. Where JavaScript Goes on Your Web Pages Now let’s get down to some JavaScript basics. Figure 1-4 shows you the thinnest possible skeleton of an HTML page with JavaScript. JavaScript Skeleton X Figure 1-4: An HTML page with JavaScript In Figure 1-4, you can see the JavaScript between the tags in X and Y. Note that you can also start JavaScript with this tags. Furthermore, you can’t include any HTML between . Between those tags, your browser assumes that everything it sees is JavaScript. If it sees HTML in there, or anything else it can’t interpret as JavaScript, it gets confused and gives you an error message. These JavaScript tags can go in either the head (between and ) or the body (between and ) of your HTML page. It doesn’t matter too much where you put them, although you’re generally best off putting as much JavaScript in the head as possible. That way you don’t have to look for it all over your web pages. One final thing worth mentioning here is that the lines that start with two slashes are JavaScript comments. The browser ignores any text that appears after two slashes. Documenting your work with comments is extremely important, because programming languages aren’t easily understood. The script you’re writing may make perfect sense while you’re writing it, but a few days later, when you want to make a little modification, you might spend hours just figuring out what you wrote the first time. If you comment your code, you’ll have a better chance to save yourself the hassle of remembering what you were thinking when you wrote that bizarre code at 2 AM in the midst of what seemed like an amazingly lucid caffeine haze. Dealing with Older Browsers There’s a slight problem with the JavaScript skeleton in Figure 1-4 (besides the fact that it doesn’t really have any JavaScript in it): Netscape didn’t introduce the Figure 1-6: Hiding JavaScript from browsers that don’t understand it The important symbols are the comments in Y. These weird lines work because in HTML, the are tags that mark the beginning and end of an entire block of comments. Older browsers that don’t recognize the , and people with older browsers will thank you. Wel c o me t o J a v a S cr i pt ! 11 Your First JavaScript It’s time to run your first JavaScript program. I’ll explain the code in Figure 1-7 in the next chapter, so for now, just type the code into your text editor, save it as my_first_program.html, and then run it in your browser. If you don’t want to type it all in, run the example at http://www.bookofjavascript.com/ Chapter01/Fig01-07.html. JavaScript Skeleton Figure 1-7: Your first JavaScript program When a browser reads this file, the JavaScript in X instructs the browser to put up a little window with the words Hello, world! in it. Figure 1-8 shows you what this looks like in a web browser. Traditionally, this is the first script you write in any programming language. It gets you warmed up for the fun to come. Figure 1-8: Window launched by the “Hello, world!” script Summary Congratulations—you’re now on your way to becoming a bona fide JavaScripter! This chapter has given you all the basic tools you need and has shown you how to get a very basic JavaScript program running. If you followed everything here, you now know: 12 Chapter 1 z Some of the great things JavaScript can do z How JavaScript compares to CGI scripting, VBScript, Java, and Flash z JavaScript’s main limitations z Where JavaScript goes on the page z How to write JavaScript older browsers won’t misunderstand Assignment Try typing Figure 1-7 into a text editor and running it in a web browser. You’ll find the next chapter’s assignments hard to do if you can’t get Figure 1-7 to work. If you’re sure you’ve recreated Figure 1-7 exactly and it’s not working, make sure you’re saving the file as text only. You may also find it helpful to peruse Chapter 14, which discusses ways to fix broken code. Although you may not understand everything in that chapter, you may find some helpful tips. If it’s still not working, try running the version of Figure 1-7 at http:// www.bookofjavascript.com/Chapter01/Fig01-07.html. If that doesn’t work, you may be using a browser that doesn’t support JavaScript, or your browser may be set to reject JavaScript. If you’re sure you’re using a browser that supports JavaScript (Netscape 2.0 and later versions, and Internet Explorer 3.0 and later), check your browser’s options and make sure it’s set to run JavaScript. Once you’re comfortable with the concepts covered in this chapter, you’ll be ready to write some code! Wel c o me t o J a v a S cr i pt ! 13 USING VARIABLES AND BUILT-IN FUNCTIONS TO UPDATE YOUR WEB PAGES AUTOMATICALLY With JavaScript you can update the content of your pages automatically—every day, every hour, or every second. In this chapter, I’ll focus on a simple script that automatically changes the date on your web page. Along the way you’ll learn: z How JavaScript uses variables to remember simple items such as names and numbers z How JavaScript keeps track of more complicated items such as dates z How to use JavaScript functions to write information to your web page Before getting into the nuts and bolts of functions and variables, let’s take a look at a couple of examples of web pages that automatically update themselves, starting with the European Space Agency (http://www.esa.int). As you can see in Figure 2-1, the ESA’s home page shows you the current date. Rather than change the home page every day, the ESA uses JavaScript to change the date automatically. Figure 2-1: Using JavaScript to display the current date An even more frequently updated page is the home page of the Book of JavaScript website (http://www.bookofjavascript.com), which updates the time as well as the date (see Figure 2-2). You don’t have to sit in front of your computer, updating the dates and times on your websites. JavaScript can set you free! The ability to write HTML to web pages dynamically is one of JavaScript’s most powerful features. Figure 2-2: Dynamically updating the date and time To understand how to update the date and time on the page, you’ll first have to learn about variables, strings, and functions. Your homework assignment at the end of this chapter will be to figure out how to add seconds to the time. Variables Store Information Think back to those glorious days of algebra class when you learned about variables and equations. For example, if x = 2, y = 3, and z = x + y, then z = 5. In algebra, variables like x, y, and z store or hold the place of numbers. In JavaScript and other programming languages, variables also store other kinds of information. Syntax of Variables The syntax of variables (the set of rules for defining and using variables) is slightly different in JavaScript from what it was in your algebra class. Figure 2-3 illustrates the syntax of variables in JavaScript with a silly script that figures out how many seconds there are in a day. NOTE 16 Chapter 2 Figure 2-3 does not write the results of the JavaScript to the web page—I’ll explain how to do that in Figure 2-4. Seconds in a Day

Know how many seconds are in a day?

I do!

Figure 2-3: Defining and using variables There’s a lot going on here, so let’s take it line by line. Line X is a statement (a statement in JavaScript is like a sentence in English), and it says to JavaScript, “Create a variable called seconds_per_minute and set its value to 60.” Notice that X ends with a semicolon. Semicolons in JavaScript are like periods in English: They mark the end of a statement (for example, one that defines a variable, as above). As you see more and more statements, you’ll get the hang of where to place semicolons. The first word, var, introduces a variable for the first time—you don’t need to use it after the first instance, no matter how many times you employ the variable in the script. NOTE Many people don’t use var in their code. Although most browsers let you get away without it, it’s always a good idea to put var in front of a variable the first time you use it. (You’ll see why when I talk about writing your own functions in Chapter 6.) Naming Variables Notice that the variable name in X is pretty long—unlike algebraic variables, it’s not just a single letter like x, y, or z. When using variables in JavaScript (or any programming language), you should give them names that indicate what piece of information they hold. The variable in X stores the number of seconds in a minute, so I’ve called it seconds_per_minute. If you name your variables descriptively, your code will be easier to understand while you’re writing it, and much easier to understand when you return to it later for revision or enhancement. Also, no matter which programming U s i n g V a r i a b l e s a n d B u i l t - i n F u n ct i on s to U p d a t e Yo u r W e b P a g e s A ut om a t i c a ll y 17 language you use, you’ll spend about 50 percent of your coding time finding and getting rid of your mistakes. This is called debugging—and it’s a lot easier to debug code when the variables have descriptive names. You’ll learn more about debugging in Chapter 14. There are four rules for naming variables in JavaScript: 1. The initial character must be a letter, an underscore, or a dollar sign, but subsequent characters may be numbers as well. 2. No spaces are allowed. 3. Variables are case sensitive, so my_cat is different from My_Cat, which in turn is different from mY_cAt. As far as the computer is concerned, each of these would represent a different variable—even if that’s not what the programmer intended. (You’ll see an example of this in the section “alert()” on page 22.) To avoid any potential problems with capitalization, I use lowercase for all my variables, with underscores (_) where there would be spaces in ordinary English. 4. You can’t use reserved words. Reserved words are terms used by the JavaScript language itself. For instance, you’ve seen that the first time you use a variable, you should precede it with the word var. Because JavaScript uses the word var to introduce variables, you can’t use var as a variable name. Different browsers have different reserved words, so the best thing to do is avoid naming variables with words that seem like terms JavaScript might use. Most reserved words are fairly short, so using longer, descriptive variable names keeps you fairly safe. I often call my variables things like the_cat, or the_date because there are no reserved words that start with the word the. If you have a JavaScript that you’re certain is correct, but it isn’t working for some reason, it might be because you’ve used a reserved word. Arithmetic with Variables Line Y in Figure 2-3 introduces a new variable called seconds_per_day and sets it equal to the product of the other three variables using an asterisk (*), which means multiplication. A plus sign (+) for addition, a minus sign (-) for subtraction, and a slash (/) for division represent the other major arithmetic functions. When the browser finishes its calculations in our example, it reaches the end of the JavaScript in the head (Z) and goes down to the body of the HTML. There it sees two lines of HTML announcing that the page knows how many seconds there are in a day.

Know how many seconds are in a day?

I do!

So now you have a page that knows how many seconds there are in a day. Big deal, right? Wouldn’t it be better if you could tell your visitors what the answer is? Well, you can, and it’s not very hard. 18 Chapter 2 Write Here Right Now: Displaying Results JavaScript uses the write() function to write text to a web page. Figure 2-4 shows how to use write() to let your visitors know how many seconds there are in a day. (The new code is in bold.) Figure 2-5 shows the page this code displays. Seconds in a Day

My calculations show that . . .

Figure 2-4: Using write() to write to a web page Figure 2-5: JavaScript’s calculations U s i n g V a r i a b l e s a n d B u i l t - i n F u n ct i on s to U p d a t e Yo u r W e b P a g e s A ut om a t i c a ll y 19 Line-by-Line Analysis of Figure 2-4 Line X in Figure 2-4 writes the words there are to the web page (only the words between the quotes appear on the page). Don’t worry about all the periods and what window and document really mean right now (I’ll cover these topics in depth in Chapter 4, when we talk about image swaps). For now, just remember that if you want to write something to a web page, use window.document.write("whatever");, placing the text you want written to the page between the quotes. If you don’t use quotes around your text, as in window.document.write(seconds_per_day); then JavaScript interprets the text between the parentheses as a variable and writes whatever is stored in the variable (in this case, seconds_per_day) to the web page (see Figure 2-6). If you accidentally ask JavaScript to write out a variable you haven’t defined, you’ll get a JavaScript error. Be careful not to put quotes around variable names if you want JavaScript to know you’re talking about a variable. If you add quotes around the seconds_per_day variable, like this: window.document.write("seconds_per_day"); then JavaScript will write seconds_per_day to the web page. The way JavaScript knows the difference between variables and regular text is that regular text has quotes around it and a variable doesn’t. Strings Any series of characters between quotes is called a string. (You’ll be seeing lots of strings throughout this book.) Strings are a basic type of information, like numbers—and like numbers, you can assign them to variables. To assign a string to a variable, you’d write something like this: var my_name = "thau!"; The word thau! is the string assigned to the variable my_name. You can stick strings together with a plus sign (+), as shown in the bolded section of Figure 2-6. This code demonstrates how to write output to your page using strings. Seconds in a Day

My calculations show that . . .

Figure 2-6: Putting strings together Line-by-Line Analysis of Figure 2-6 Line X in Figure 2-6, var first_part = "there are "; assigns the string "there are" to the variable first_part. Line Y, var last_part = " seconds in a day."; sets the variable last_part to the string "seconds in a day." Line Z glues together the values stored in first_part, seconds_per_day, and last_part. The end result is that the variable whole_thing includes the whole string you want to print to the page, there are 86400 seconds in a day. The window.document.write() line then writes whole_thing to the web page. NOTE The methods shown in Figures 2-4 and 2-6 are equally acceptable ways of writing there are 86400 seconds in a day. However, there are times when storing strings in variables and then assembling them with the plus sign (+) is clearly the best way to go. We’ll see a case of this when we finally get to putting the date on a page. More About Functions Whereas variables store information, functions process that information. All functions take the form functionName(). Sometimes there’s something in the parentheses and sometimes there isn’t. You’ve already seen one of JavaScript’s many built-in functions, window.document.write(), which U s i n g V a r i a b l e s a n d B u i l t - i n F u n ct i on s to U p d a t e Yo u r W e b P a g e s A ut om a t i c a ll y 21 writes whatever lies between the parentheses to the web page. Before diving into the date functions that you’ll need to write the date to your web page, I’ll talk about two interesting functions, just so you get the hang of how functions work. alert() One handy function is alert(), which puts a string into a little announcement box (also called an alert box). Figure 2-7 demonstrates how to call an alert(), and Figure 2-8 shows what the alert box looks like. An Alert Box Y

To code, perchance to function

Figure 2-7: Creating an alert box The first thing visitors see when they come to the page Figure 2-7 creates is an alert box announcing that I wrote the page (Figure 2-8). The alert box appears because of X, which tells JavaScript to execute its alert() function. While the alert box is on the screen, the browser stops doing any work. Clicking OK in the alert box makes it go away and allows the browser to finish drawing the web page. In this case, that means writing Figure 2-8: The alert box the words To code, perchance to function to the page (Y). The alert() function is useful for troubleshooting when your JavaScript isn’t working correctly. Let’s say you’ve typed in Figure 2-6, but when you run the code, you see that you must have made a typo—it says there are 0 seconds in a day instead of 86400. You can use alert() to find out how the different variables are set before multiplication occurs. The script in Figure 2-9 contains an error that causes the script to say there are “undefined” seconds in a year; and to track down the error, I’ve added alert() function statements that tell you why this problem is occurring. 22 Chapter 2 Seconds in a Day

My calculations show that . . .

Figure 2-9: Using alert() to find out what’s wrong Line-by-Line Analysis of Figure 2-9 The problem with this script is in X. Notice the accidental capitalization of the first letter in Hours_per_day. This is what causes the script to misbehave. Line \ multiplies the other numbers by the variable hours_per_day, but hours_per_day was not set—remember, JavaScript considers it a different variable from Hours_per_day—so JavaScript thinks its value is either 0 or undefined, depending on your browser. Multiplying anything by 0 results in 0, so the script calculates that there are 0 seconds in a day. The same holds true for browsers that think hours_per_day is undefined. Multiplying anything U s i n g V a r i a b l e s a n d B u i l t - i n F u n ct i on s to U p d a t e Yo u r W e b P a g e s A ut om a t i c a ll y 23 by something undefined results in the answer being undefined, so the browser will report that there are undefined seconds in a day. This script is short, making it easy to see the mistake. However, in longer scripts it’s sometimes hard to figure out what’s wrong. I’ve added Y, Z, and [ in this example to help diagnose the problem. Each of these statements puts a variable into an alert box. The alert in Y will say seconds_per_minute is: 60. The alert in [ will say hours_per_day is: 0, or, depending on your browser, the alert won’t appear at all. Either way, you’ll know there’s a problem with the hours_per_day variable. If you can’t figure out the mistake by reading the script, you’ll find this type of information very valuable. Alerts are very useful debugging tools. prompt() Another helpful built-in function is prompt(), which asks your visitor for some information and then sets a variable equal to whatever your visitor types. Figure 2-10 shows how you might use prompt() to write a form letter. A Form Letter Y

Dear ,

Thank you for coming to my web page. Figure 2-10: Using prompt() to write a form letter Notice that prompt() in X has two strings inside the parentheses: "What's your name?" and "put your name here". If you run the code in Figure 2-10, you’ll see a prompt box that resembles Figure 2-11. (I’ve used the Opera browser in 24 Chapter 2 this illustration; prompt boxes will look somewhat different in IE and other browsers.) If you type Rumpelstiltskin and click OK, the page responds with Dear Rumpelstiltskin, Thank you for coming to my web page. Figure 2-11: Starting a form letter with a prompt box The text above the box where your visitors will type their name ("What's your name?") is the first string in the prompt function; the text inside the box ("put your name here") is the second string. If you don’t want anything inside the box, put two quotes ("") right next to each other in place of the second string to keep that space blank: var the_name = prompt("What's your name?", ""); If you look at the JavaScript in the body (starting in Y), you’ll see how to use the variable the_name. First write the beginning of the heading to the page using normal HTML. Then launch into JavaScript and use document.write(the_name) to write whatever name the visitor typed into the prompt box for your page. If your visitor typed yertle the turtle into that box, yertle the turtle gets written to the page. Once the item in the_name is written, you close the JavaScript tag, write a comma and the rest of the heading using regular old HTML, and then continue with the form letter. Nifty, eh? The prompt() function is handy because it enables your visitor to supply the variable information. In this case, after the user types a name into the prompt box in Figure 2-10 (thereby setting the variable the_name), your script can use the supplied information by calling that variable. Parameters The words inside the parentheses of functions are called parameters. The document.write() function requires one parameter: a string to write to your web page. The prompt() function takes two parameters: a string to write above the box and a string to write inside the box. Parameters are the only aspect of a function you can control; they are your means of providing the function with the information it needs to do its job. With a prompt() function, for example, you can’t change the color of the box, how many buttons it has, or anything else; in using a predefined prompt box, you’ve decided that you don’t need to customize the box’s appearance. You can only change the parameters it specifically provides— U s i n g V a r i a b l e s a n d B u i l t - i n F u n ct i on s to U p d a t e Yo u r W e b P a g e s A ut om a t i c a ll y 25 namely, the text and heading of the prompt you want to display. You’ll learn more about controlling what functions do when you write your own functions in Chapter 6. Writing the Date to Your Web Page Now that you know about variables and functions, you can print the date to your web page. To do so, you must first ask JavaScript to check the local time on your visitor’s computer clock: var now = new Date(); The first part of this line, var now =, should look familiar. It sets the variable now to some value. The second part, new Date(), is new; it creates an object. Objects store data that require multiple pieces of information, such as a particular moment in time. For example, in JavaScript you need an object to describe 2:30 PM on Saturday, January 7, 2006, in San Francisco. That’s because it requires many different bits of information: the time, day, month, date, and year, as well as some representation (in relation to Greenwich Mean Time) of the user’s local time. As you can imagine, working with an object is a bit more complicated than working with just a number or a string. Because dates are so rich in information, JavaScript has a built-in Date object to contain those details. When you want the user’s current date and time, you use new Date() to tell JavaScript to create a Date object with all the correct information. NOTE You must capitalize the letter D in Date to tell JavaScript you want to use the built-in Date object. If you don’t capitalize it, JavaScript won’t know what kind of object you’re trying to create, and you’ll get an error message. Built-in Date Functions Now that JavaScript has created your Date object, let’s extract information from it using JavaScript’s built-in date functions. To extract the current year, use the Date object’s getYear() function: var now = new Date(); var the_year = now.getYear(); Date and Time Methods In the code above, the variable now is a Date object, and the function getYear() is a method of the Date object. Methods are simply functions that are built in to objects. For example, the getYear() function is built in to the Date object and gets the object’s year. Because the function is part of the Date object, it is called a method. To use the getYear() method to get the year of the date stored in the variable now, you would write: now.getYear() 26 Chapter 2 Table 2-1 lists commonly used date methods. (You can find a complete list of date methods in Appendix C.) Table 2-1: Commonly Used Date and Time Methods NOTE Name Description getDate() The day of the month as an integer from 1 to 31 getDay() The day of the week as an integer where 0 is Sunday and 1 is Monday getHours() The hour as an integer between 0 and 23 getMinutes() The minutes as an integer between 0 and 59 getMonth() The month as an integer between 0 and 11 where 0 is January and 11 is December getSeconds() The seconds as an integer between 0 and 59 getTime() The current time in milliseconds where 0 is January 1, 1970, 00:00:00 getYear() The year, but this format differs from browser to browser Notice that getMonth() returns a number between 0 and 11; if you want to show the month to your site’s visitors, to be user-friendly you should add 1 to the month after using getMonth(), as shown in Y in Figure 2-12. Internet Explorer and various versions of Netscape deal with years in different and strange ways: z Some versions of Netscape, such as Netscape 4.0 for the Mac, always return the current year minus 1900. So if it’s the year 2010, getYear() returns 110. z Other versions of Netscape return the full four-digit year except when the year is in the twentieth century, in which case they return just the last two digits. z Netscape 2.0 can’t deal with dates before 1970 at all. Any date before January 1, 1970 is stored as December 31, 1969. z In Internet Explorer, getYear() returns the full four-digit year if the year is after 1999 or before 1900. If the year is between 1900 and 1999, it returns the last two digits. You’d figure a language created in 1995 wouldn’t have the Y2K problem, but the ways of software developers are strange. Later in this chapter I’ll show you how to fix this bug. Code for Writing the Date and Time Now let’s put this all together. To get the day, month, and year, we use the getDate(), getMonth(), and getYear() methods. To get the hour and the minutes, we use getHours() and getMinutes(). Figure 2-12 shows you the complete code for writing the date and time (without seconds) to a web page, as seen on the Book of JavaScript home page. U s i n g V a r i a b l e s a n d B u i l t - i n F u n ct i on s to U p d a t e Yo u r W e b P a g e s A ut om a t i c a ll y 27 The Book of JavaScript 28 Chapter 2 _

Welcome to the Book of JavaScript Home Page!

Figure 2-12: Writing the current date and time to a web page Line-by-Line Analysis of Figure 2-12 Here are a few interesting things in this example. Getting the Date and Time The lines from X up until Y get the current date and time from the visitor’s computer clock and then use the appropriate date methods to extract the day, month, year, hours and minutes. Although I’m using a variable name date in X to store the date, I could have used any variable name there: the_date, this_moment, the_present, or any valid variable name. Don’t be fooled into thinking that a variable needs to have the same name as the corresponding JavaScript object; in this case, date just seems like a good name. Making Minor Adjustments Before building the strings we will write to the website, we need to make some little adjustments to the date information just collected. Here’s how it works: z Line Y adds 1 to the month because getMonth() thinks January is month 0. z Line Z fixes the Y2K problem discussed earlier in the chapter, in which the getYear() method returns the wrong thing on some older browsers. If you feed fixY2K() the year returned by date.getYear(), it will return the correct year. The fixY2K() function is not a built-in JavaScript function. I had to write it myself. Don’t worry about how the function works right now. z Line [ fixes a minor formatting issue, using another function that’s not built-in. If the script is called at 6 past the hour, date.getMinutes() returns 6. If you don’t do something special with that 6, your time will look like 11:6 instead of 11:06. So fixTime() sticks a zero in front of a number if that number is less than 10. You can use fixTime() to fix the seconds too, for your homework assignment. Getting the String Right Now that we’ve made a few minor adjustments, it’s time to build the strings. Line \ builds the string for the date. Here’s the wrong way to do it: var date_string = "month / day / year"; U s i n g V a r i a b l e s a n d B u i l t - i n F u n ct i on s to U p d a t e Yo u r W e b P a g e s A ut om a t i c a ll y 29 If you wrote your code this way, you’d get a line that says Today is month / day / year. Why? Remember that JavaScript doesn’t look up variables if they’re inside quotes. So place the variables outside the quote marks and glue everything together using plus signs (+): var date_string = month + "/" + day + "/" + year; This may look a little funny at first, but it’s done so frequently that you’ll soon grow used to it. Line ] creates the string to represent the time. It is very similar to \. Line ^ puts \ and ] together to create the string that will be written to the website. Lines \ through ^ could all have been written as one long line: var date_time_string = "Today is " + month + "/" + day + "/" + year + ". The time is now " + hour + ":" + minutes + "."; However, using three lines makes the code easier for people to read and understand. It’s always best to write your code as if other people are going to read it. What Are Those Other Functions? The JavaScript between ^ and _ defines the fixY2K() and fixTime() functions. Again, don’t worry about these lines for now. We’ll cover how to write your own functions in glorious detail in Chapter 6. JavaScript and HTML Make sure to place your JavaScript and HTML in the proper order. In Figure 2-12, the welcoming HTML in _ precedes the JavaScript that actually writes the date and time in `, since the browser first writes that text and then executes the JavaScript. With JavaScript, as with HTML, browsers read from the top of the page down. I’ve put document.write() in the body so that the actual date information will come after the welcome text. I’ve put the rest of the JavaScript at the head of the page to keep the body HTML cleaner. Why document.write()? Notice that the code in Figure 2-11 uses document.write() instead of window.document.write(). In general, it’s fine to drop the word window and the first dot before the word document. In future chapters I’ll tell you when the word window must be added. How the European Space Agency Writes the Date to Its Page The JavaScript used by the European Space Agency is very much like the code I used for the Book of JavaScript web page. One big difference between the two is that the ESA prints out the month using abbreviations like Jan and Feb for January and February. They do this using arrays, a topic discussed in Chapter 8, so in Figure 2-13 I’ve modified their code a bit to focus on topics covered so far. 30 Chapter 2 Figure 2-13: How the European Space Agency writes the date to its page Everything here should look very familiar to you, except for X and Y, which will make more sense after you’ve read Chapter 3. If anything else in the ESA script seems unclear to you, try doing the homework assignment. In fact, do the homework assignment even if it all seems extremely clear. The only way to really learn JavaScript is to do it. Go ahead, give that homework a shot! And enjoy! Summary This chapter was chock-full of JavaScript goodness. Here’s a review of the most important points for you to understand: z How to declare and use variables (use var the first time and use valid and descriptive variable names) z How to write to web pages with document.write() z How to get the current date from JavaScript with the Date object and its various methods If you got all that, you’re well on your way to becoming a JavaScript superstar. Try the following assignment to test your JavaScript skills. Assignment Change the script in Figure 2-12 so that it writes out the seconds as well as the hour and minutes. If you’re feeling like getting ahead of the game, you can try, for a big chunk of extra credit, to change the time from a 24-hour clock to a 12-hour clock. The getHours() method returns the hour as a number between 0 and 23. See if you can figure out how to adjust that time to be between 1 and 12. You’ll have to use some tricks I haven’t covered in this chapter. If you can’t figure this out now, you’ll be able to do it by the end of the next chapter. U s i n g V a r i a b l e s a n d B u i l t - i n F u n ct i on s to U p d a t e Yo u r W e b P a g e s A ut om a t i c a ll y 31 GIVING THE BROWSERS WHAT THEY WANT Much to the dismay of web developers everywhere, different browsers implement JavaScript and HTML in slightly different ways. Wouldn’t it be great if you could serve each browser exactly the content it could understand? Fortunately, you can use JavaScript to determine which browser a visitor is using. You can then use that information to deliver content suitable for that specific browser, either by redirecting the visitor to a page containing content especially tailored for that browser or by writing your JavaScripts so that the same page does different things depending on the browser looking at it. This chapter covers the three topics you need to understand to deliver browser-specific pages using redirects: z z z How to determine which browser your visitor is using How to redirect the visitor to other pages automatically How to send the visitor to the page you want, depending on which browser he or she is using As in Chapter 2, while learning how to handle an important web authoring task, you’ll also be introduced to fundamental elements of the JavaScript language—in this case, if-then statements and related methods for implementing logical decision making in your scripts. Let’s first talk about determining which browser a visitor is using. A Real-World Example of Browser Detection Before we get into the details of how browser detection works, let’s look at a real-world example. Netscape, the company that brought you the Netscape Navigator browser, has a complicated home page with lots of interesting features. They’ve taken great pains to make their home page look good to most browsers, including early versions of their own browser. If you compare the Netscape home page seen with Netscape Navigator 4 (Figure 3-1) to the page seen using Navigator 8 (Figure 3-2), you’ll notice some subtle differences. Among other things, the news blurb at the bottom of Figure 3-2 has a little navigational element in the lower-right corner. Clicking the numbers in that corner cycles you through different news blurbs. Figure 3-1 does not have these numbers, probably because there isn’t a good way to provide this fancy functionality in the old Netscape Navigator. Figure 3-1: Netscape Navigator 4 view of Netscape home page Figure 3-2: Netscape Navigator 8 view of Netscape home page How does Netscape show the numbers to only those browsers that can provide this feature? There are two steps. First you have to determine which browser your visitor is using. Once you know the browser, you know what JavaScript and HTML features it supports. Then you have to figure out how to control what the person will see based on the known capabilities of the browser. 34 Chapter 3 Browser Detection Methods A browser is identified by its name (Netscape, Firefox, Internet Explorer, and so on) combined with its version number. Your JavaScript needs to determine both of these items. There are two ways to approach this task: a quick but rough method and a slightly less quick but more accurate method. Quick-but-Rough Browser Detection In general, the line var browser_name = navigator.appName; determines who made the browser. If the user is using a Netscape browser, the variable browser_name will be set to the string "Netscape". If it’s a Microsoft Internet Explorer browser, browser_name will be set to "Microsoft Internet Explorer". Every JavaScript-enabled browser must have the variable navigator.appName. If you use Opera, navigator.appName equals "Opera". Unfortunately, some browsers travel incognito. For example, the navigator.appName for Firefox is "Netscape". The JavaScript in Firefox is the same as that for Netscape browsers, so in general, it’s fine to treat Firefox browsers as Netscape browsers. But, as you can see, if you want to be sure about the browser being used, you can’t rely on naviagor.appName. There’s a similar rough method for determining the browser version being used: navigator.appVersion. Unfortunately, navigator.appVersion isn’t just a number but a sometimes cryptic string that varies from browser to browser. For example, the Macintosh browser Safari has this nice, simple navigator.appVersion string: "5.0". By contrast, Internet Explorer 6.0 running under Windows XP has a navigator.appVersion that looks like this: "4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322)". To see the navigator.appVersion string for your browser, type this into the browser’s address box (where you normally enter web addresses): javascript:alert(navigator.appVersion) If you care only about whether a person is using a 4.0 browser or later, you can pick out the version numbers from those navigator.appVersion strings with the parseFloat() command, which looks at the string and grabs the first item that resembles a floating-point number (a number that contains a decimal point). Thus the line var browser_version = parseFloat(navigator.appVersion); sets the variable browser_version to the first number in the navigator.appVersion string. For most browsers, this will be the actual version number. For Internet Explorer, it will be 4.0 for any version of the browser 4.0 or later. You can see why I call this method rough. G i v i n g th e B ro w s e r s W h a t T h e y W an t 35 More Accurate Browser Detection JavaScript has another variable that contains information about the browser being used: navigator.userAgent. This variable identifies both the manufacturer of the browser and its version. As it did with navigator.appVersion, however, the formatting of the string varies from browser to browser. Because the navigator.userAgent strings are different from each other, there is no simple way to extract the information you want. Fortunately, people have already written browser sniffers: bits of JavaScript that will do all the hard work of browser identification for you. You can find brwsniff.js, which I downloaded from http://jsbrwsniff.sourceforge.net, at http:// www.bookofjavascript.com/Chapter03. To use this file, put it in the same folder as the web page containing your JavaScript. Then, put this line in the header of your web page: This tells JavaScript to add the contents of the file named brwsniff.js to your web page. Now you can use the JavaScript stored in that file. To use the JavaScript in brwsniff.js to determine the name and version of the browser being used to view your web page, add these lines of JavaScript: X var browser_info = getBrowser(); Y var browser_name = browserInfo[0]; Z var browser_version = browserInfo[1]; Line X calls a function in brwsniff.js that reads the navigator.userAgent string and compares it to all the different browser version strings it knows. Once it determines the name and version of the browser, the function loads this information into a variable called browser_info. All the variables we’ve seen so far store one piece of information—a string or a number, for example. This browser_info variable is an array, a type of variable designed to hold multiple items of related information. You’ll learn how to work with arrays in Chapter 8. For now it’s enough to know that an array is a variable that can store more than one piece of information. Line Y puts the first bit of information stored in the array into a variable called browser_name. Line Z puts the second piece of information stored in browser_info into a variable named browser_version. Used together, these two variables tell you what kind of browser is viewing the web page. Try the web page in Figure 3-3 on your own browser. NOTE This Figure 3-3: Finding the browser version number with a browser sniffer Redirecting Visitors to Other Pages Now that you understand browser detection, you can tailor your site to provide information specific to each browser. There are two main ways to do this. First, you can use document.write(), which we saw in the last chapter, to display one message on your page if the site visitor is using Netscape Navigator 4, and a different message on the same page for Internet Explorer 6.0. Alternatively, you can redirect your visitors to separate pages specifically tailored to different browsers. To redirect visitors to another page, you’d write something like this: window.location.href = "http://www.mywebsite.com/page_for_netscape4.html"; When JavaScript sees a line like this, it loads the page with the specified URL into the browser. NOTE Are you wondering “What’s with all these periods in commands like window.location.href and navigator.appName?” Never fear. I’ll address these when I discuss image swaps and dot notation in Chapter 4. In general, it’s probably best to use document.write() instead of redirecting the user. Because there are so many browsers, trying to maintain a different page for each one can quickly become burdensome. However, if you just want to redirect someone with an older browser to a page that tells them to upgrade, redirection is probably the best way to go. G i v i n g th e B ro w s e r s W h a t T h e y W an t 37 if-then Statements Now that you know which browser your visitor is using, you need to learn how to tell JavaScript to write different things depending on the browser being used—in other words, how to implement a logical test, choosing between different actions based on specific information. Branching is a fundamental technique in any programming or scripting language. Be sure to read this section if you’re not already familiar with the concept. To alter your web pages based on the browser a visitor is using, you tell JavaScript something like, “If the visitor is using Internet Explorer, then write this IE-tailored content.” An if-then statement in JavaScript looks like this: if (navigator.appName == "Microsoft Internet Explorer") { // write IE-specific content document.write("Welcome, Internet Explorer user!"); } Here’s the basic structure of an if-then statement: if (some test) { statement_1; statement_2; statement_3; ... } NOTE JavaScript is unforgiving: if must be lowercase, and you must put parentheses around the test that follows it. The test that appears between the parentheses must be either true or false. If the variable navigator.appName equals "Microsoft Internet Explorer", the test between the parentheses is true, and the statements located between the curly brackets are executed. If the variable doesn’t equal "Microsoft Internet Explorer", the test between the parentheses is false, and the statements between the curly brackets aren’t executed. Boolean Expressions The test in the parentheses after if is a Boolean expression—an expression that’s either true or false. In JavaScript, a Boolean expression is usually a statement about the values of one or more variables. Table 3-1 lists some of the symbols you’ll be using to form Boolean expressions in JavaScript. NOTE 38 Chapter 3 Boolean expressions are named after George Boole (1815–1864), who invented a way to express logical statements in mathematical form. Table 3-1: Symbols in Boolean Expressions Test Meaning Example (All of These Are True) < Less than 1 < 3 > Greater than 3 > 1 == The same as (equal) "happy" == "happy", 3 == 3 != Different from (not equal) "happy" != "crabby", 3 != 2 <= Less than or equal to 2 <= 3, 2 <= 2 >= Greater than or equal to 3 >= 1, 3 >= 3 Notice in Table 3-1 that you must use two equal signs when you want JavaScript to test for equality in an if-then statement Boolean expression. In fact, accidentally using one equal sign instead of two in an if-then statement is probably the major cause of mind-blowing programming errors. As you learned in Chapter 2, a single equal sign is used to assign a value to a variable. So if you accidentally use only one equal sign, JavaScript thinks you mean to set the variable on the left of the equal sign to the value of whatever is on the right of the equal sign, and it will act as if the test result is always true. Here’s an example of the trauma that this mistake can cause. Say you want to write a JavaScript that puts Happy Birthday, Mom! on your web page when it’s your mother’s birthday. If her birthday were August 6, you might write something like Figure 3-4 (which contains the dreaded error). If you try this script, you’ll see that it always prints Happy Birthday, Mom! to the web page, which is great for Mom, but probably not what you want. Figure 3-4: Mom’s birthday greeting—broken version G i v i n g th e B ro w s e r s W h a t T h e y W an t 39 The script starts off correctly. When JavaScript sees X, it sets the variable month to whatever month it is. If you’re running the script in March, it sets month to 2. The problem arises in the next line, though: if (month = 7) Here JavaScript sees one equal sign and thinks you want to set the variable month to the value 7. The script does what you’re telling it to do, and then acts as if your test is true. Since the result is true, JavaScript moves to the curly brackets, where it finds Z, another if-then statement that incorrectly uses one equal sign instead of two. This line sets the variable day to the value 6 and again results in a true statement. JavaScript then moves to the second set of curly brackets, where it sees that it’s supposed to [ write

Happy Birthday, Mom!

, which it does— every time someone visits the page (see Figure 3-5). Figure 3-5: Mom’s birthday greeting NOTE I remember the difference between one and two equal signs by thinking is the same as instead of equals when I’m doing an if-then test, and remembering that is the same as translates into two equal signs. Nesting Figure 3-4 is the first example I’ve used of nesting—one if-then statement inside another. Although it sometimes makes sense to nest your if-then statements, things get confusing if you start to get three or more levels deep (one if-then statement inside the curly brackets of another if-then statement, which itself is inside the curly brackets of a third if-then statement). Try to write your code so that it doesn’t need more than two levels of nesting. If you find yourself with if-then statements more than two levels deep, it often means that you’re doing something complicated enough to justify writing a new function to handle some of the complexity. (More on that in Chapter 6.) if-then-else Statements There are a couple of fancier versions of the if-then statement. The first is the if-then-else statement: if (navigator.appName == "Microsoft Internet Explorer") { // write IE-specific content 40 Chapter 3 document.write("Welcome, Internet Explorer user!"); } else { // write netscape specific content document.write("Welcome, Netscape user!"); } This reads nicely in English if you read else as otherwise: “If they’re using Internet Explorer, show them IE-specific content, otherwise send them Netscape-specific content.” if-then-else-if Statements The above code assumes that there are only two browser manufacturers in the world, when in fact there are a multitude. We can solve this problem with an if-then-else-if statement that, if a visitor has a browser other than Netscape or Internet Explorer, displays content regarding unknown browsers. if (navigator.appName == "Netscape") { // write netscape-specific content document.write("Welcome, Netscape user!"); } else if (navigator.appName == "Microsoft Internet Explorer") { // write IE-specific content document.write("Welcome, Internet Explorer user!"); } else { // write unknown browser content document.write("Welcome, user of a fancy unknown browser!"); } This code reads in English as: “If they’re using Netscape, send them Netscape-specific content; if they’re using Internet Explorer, send them IEspecific content. Otherwise send them a message about having a mysterious browser.” When and Where to Place Curly Brackets Notice in the examples above that curly brackets (braces) mark the beginning and end of the body of an if-then statement, enclosing the part where you tell JavaScript what action(s) to take. You’ll also notice that I place my beginning and ending curly brackets on their own lines, like this: if (something == something_else) { blah_blah_blah; } G i v i n g th e B ro w s e r s W h a t T h e y W an t 41 This is my style, one that I think makes it easier to align pairs of beginning and ending brackets. Other people prefer this slightly more compact style: if (something == something_else) { blah_blah_blah; } It’s up to you to choose where you put the curly brackets. Many studies have tried to figure out which formatting style is most readable or which avoids bugs. When you get right down to it, just decide what you think looks good and go with that. Sometimes curly brackets are not needed in an if-then statement, such as when the body of the statement has only one line. For example, this is legal: if (something == something_else) alert("they're equal"); else alert("they're different!"); Since each of the “then” parts of the clause is only one line (the alert functions), the curly brackets around these statements are optional. However, it’s always a good idea to include the braces anyway, because you might want to add a second line to that else clause. If you do add a second line to the else clause and forget to put the brackets around the two lines, your script won’t work. With curly brackets, the previous example would look like this: if (something == something_else) { alert("they're equal"); } else { alert("they're different!"); } Or, if you prefer the more compact style: if (something == something_else) { alert("they're equal"); } else { alert("they're different!"); } OR and AND The if-then statements we’ve seen so far are pretty simple. You might, however, want to add more conditions to an if-then statement (for example, “If Joe is in high school and is not doing his homework, then tell him to get to work”). To add more conditions to an if-then statement, use the OR and AND operators. 42 Chapter 3 OR Suppose you want to give different greetings to people who come to your site, depending on who they are. You could, as in Figure 3-6, use a prompt box to ask for a visitor’s name (Figure 3-7) and then use an if-then statement to determine which greeting to give. Figure 3-6: Asking for a visitor’s name with the prompt box Figure 3-7: The prompt box asking for a visitor’s name This example greets thau with “Welcome back, thau! Long time no see!” (Figure 3-8) and everyone else with “Greetings, Name. Good to see you.” Figure 3-8: thau’s greeting To greet others the same way you greet thau, you could use a series of if-then statements as in Figure 3-9. if (the_name == "thau") { document.write("Welcome back, thau! Long time no see!"); } else if (the_name == "dave") { document.write("Welcome back, dave! Long time no see!"); } G i v i n g th e B ro w s e r s W h a t T h e y W an t 43 else if (the_name == "pugsly") { document.write("Welcome back, pugsly! Long time no see!"); } else if (the_name == "gomez") { document.write("Welcome back, gomez! Long time no see!"); } else { document.write("Greetings, " + the_name + ". Good to see you."); } Figure 3-9: Personalized greetings with a series of if-then statements This would work, but there’s a lot of waste here: We repeat basically the same document.write() line four times. What we really want to say is something like: “If the_name is thau, or dave, or pugsly, or gomez, give the ‘Long time no see’ greeting.” JavaScript has a feature called the OR operator, which comes in handy here. Figure 3-10 shows OR in use: if ((the_name == "thau") || (the_name == "dave") || (the_name == "pugsly") || (the_name == "gomez")) { document.write("Welcome back, " + the_name + "! Long time no see!"); } Figure 3-10: The OR operator The OR operator is represented by two vertical lines (||), called bars. You will usually be able to type the bar (|) character as the shifted backslash (\) key on your keyboard. NOTE Although each of the Boolean tests in Figure 3-10 (for example, the_name == "thau") has its own parentheses, these aren’t strictly necessary. However, the set of parentheses around all four Boolean tests is required, and it’s a good idea to include the other parentheses for legibility’s sake. AND AND, another important operator, is represented by two ampersands (&&). Figure 3-11 shows this operator in use. var age = prompt("How old are you?", ""); var drinking = prompt("Are you drinking alcohol (yes or no)?", "yes"); if ((age < 21) && (drinking == "yes")) { document.write("Beat it!"); } else 44 Chapter 3 { document.write("Enjoy the show!"); } Figure 3-11: The AND operator When bars start using robot bouncers that run on JavaScript, this is the kind of code they’ll be running. The script asks a person’s age and whether he or she is drinking alcohol (Figure 3-12). Figure 3-12: The bouncer’s questions If the person is under 21 and is drinking alcohol, the bouncer tells him or her to beat it. Otherwise, the visitor is perfectly legal and is welcome to stay (Figure 3-13). (Never mind the fake IDs for now.) o Figure 3-13: The bouncer’s response Putting It All Together Here’s a script containing most of what’s been presented in the chapter so far. The script in Figure 3-14 redirects users to one page if they’re using an older version of Netscape (version 4 or earlier), another page if they’re using an older version of Internet Explorer (version 5.5 or earlier), a third page for browsers it’s unfamiliar with, and a fourth page for modern browsers it knows about. I’ve broken the code into two blocks of

Unknown Browser

Sorry, but this page only works for browsers Netscape 6.0 and later, and Internet Explorer 5.5 and later. Figure 3-14: Complete redirection code 46 Chapter 3 A Few More Details About Boolean Expressions There are just a few more things you need to know about Boolean expressions before you can call yourself a Boolean master. You already know that you can create an if-then statement using code like this: if (name == "thau") { alert("Hello, thau!"); } This says, “If it is true that the variable name contains the string thau, put up an alert saying Hello, thau! ” What you may not know is that you can store the value true or false in a variable and use it later. So, I could have done this instead: var thisIsThau = (name == "thau"); if (thisIsThau == true) { alert("Hello, thau!"); } The first line tests to see whether the variable name contains the string "thau". If it does, the test is true. This true value is stored in the variable thisIsThau. You can then test to see whether the variable thisIsThau is true, as seen in the subsequent if-then statement. This can be shortened a bit to this: var thisIsThau = (name == "thau"); if (thisIsThau) { alert("Hello, thau!"); } Notice that I’m not explicitly checking to see whether thisIsThau contains the value true. Instead, I’m just putting the variable inside the if-then test parentheses. The if-then rule states, “If the thing inside the parentheses is true, do the action in the curly brackets.” In this case, the variable isThisThau will be true if the variable name contains the value "thau". If you wanted to do something in the case where the string stored in name was something other than "thau" you could do this: var thisIsThau = (name == "thau"); if (thisIsThau == false) { alert("Hello, somebody other than thau!"); } Here, we’re checking to see whether the value stored inside thisIsThau is false, which it will be if the comparison of name and "thau" turned out to be false in the line above (for example, if name equaled "pugsly"). The final shortcut involves using the special character !, which means not. G i v i n g th e B ro w s e r s W h a t T h e y W an t 47 var thisIsThau = (name == "thau"); if (!thisIsThau) { alert("Hello, somebody other than thau!"); } The expression means “if thisIsThau is not true, then do the stuff in the curly brackets.” These Boolean shortcuts are used quite frequently in the scripts I’ve seen on the Web, so you should take some time to get used to them. How Netscape Provides Browser-Specific Content Now we’ve covered just about everything you need to know to understand how Netscape serves up the browser-specific content illustrated at the beginning of the chapter (Figures 3-1 and 3-2). Here is a somewhat simplified and modified version of the JavaScript on Netscape’s home page: Next comes all of the HTML. Inside the HTML, when you want to decide whether or not to write something based on the browser being used, you do something like this: \ The script starts by using the userAgent and appVersion variables to determine the type of browser being used. Notice the use of parseInt() in Y. This function works just like parseFloat(), except that it pulls the first integer out of a string, rather than the first floating-point number. This will set the variable major to a number like 4, 5, or 6. The next line (Z) is jam-packed with information, so take it slow. The first thing to notice is the use of the indexOf() function. We’ll see more of indexOf() in Chapter 11 when we work with strings. The main thing to know here is that indexOf() checks to see whether a string contains another 48 Chapter 3 string. To see if the word mozilla is part of the string stored in agent, we use agent.indexOf('mozilla'). If mozilla is in the agent string, indexOf() will return some number other than 1. If mozilla is not part of the agent string, indexOf() will return 1. This can get a little confusing, so make sure you understand that last rule. Now, looking at Z, we see that there are two main parts. The first part checks to see whether some application of the indexOf() function gives a result different from 1. The next part checks to see if another application of the indexOf() function gives a result that equals 1. If the first part is true, and the second part is also true, then the whole thing is true, and the value true is stored in the variable ns. If either of the comparisons is false, then the whole thing will be false, and the value false will be stored in ns. Remember the bouncer’s test: if ((age < 21) && (drinking == "yes")) If both statements were true—the person was under 21, and the person was drinking—the person got bounced. If either part was not true, then they were okay. With all that in mind, let’s look to see what the two comparisons in Z are. The first one will return the value true if indexOf() finds the string mozilla in the variable agent. Take a long, hard look at the expression: agent.indexOf('mozilla') != -1 Remember, if the string stored in variable agent contains the string mozilla, indexOf() will return a value not equal to 1. So this test will be true if the navigator.userAgent has the word mozilla (upper- or lowercase) in it. The next part makes sure that the navigator.userAgent does not contain the string compatible. This is because many browsers say they are Mozilla compatible, and they’ll have both the words mozilla and compatible in their navigator.userAgent string. Netscape just has the word mozilla in its string. The end result of Z is that the variable ns will be true if the navigator.userAgent contains the string mozilla but not the string compatible. The next lines figure out which version of Netscape this might be. Consider [: var ns4 = (ns && (major == 4)); This line says, “If the variable ns is true, and the variable major has a value of 4, then put the value true in the variable ns4.” If it’s not true both that the variable ns is true and that the variable major is 4, then ns4 will be false. The other lines perform similar tests for Navigator 7 and other browsers. Each one is a little different from the others, so make sure you take some time to understand all of them. G i v i n g th e B ro w s e r s W h a t T h e y W an t 49 Once the browser is known, the decision whether or not to display the browser-specific feature (namely, the page number navigation links) happens later in the code. Right at the place where you either write something to the web page or not, depending on the browser being used, you use a line like \: if (!ns4) document.write('the stuff that puts in the numbers'); This says, “If this is not a Netscape 4 browser, write the code that puts in the navigation element.” The variable ns will be true if the earlier code determined that it was a Netscape 4 browser being used, and false otherwise. Remember that this code must go between tags. Except for the part of the script that determines the type of browser being used, the Netscape code is fairly simple. If you want to avoid the complexities involved in determining the browser being used, use one of the browser sniffer packages available for free on the Web, incorporating the software into your page using JavaScript statements similar to those shown in the section “More Accurate Browser Detection” on page 36. Summary Here are the things you should remember from this chapter: z JavaScript’s tools for identifying a visitor’s browser (navigator.appName, navigator.appVersion, and navigator.userAgent) z How if-then, if-then-else, and if-then-else-if statements work z How Boolean expressions work z How to redirect your visitors to other web pages z How to import JavaScript from another file Did you get all that? If so, here’s an assignment for you. Assignment Write a web page that asks for a visitor’s name. If the visitor is someone you like, send him to your favorite page. If it’s someone you don’t know, send him to a different page. And if it’s someone you don’t like, send him to yet another page. 50 Chapter 3 WORKING WITH ROLLOVERS You’ve seen rollovers a million times. You mouse over an image, and the image changes. You mouse off the image, and the image changes back to its original state. Rollovers are an easy way to make your site more interactive. This chapter will show you how to create a good rollover. This involves: z Telling JavaScript to detect the mouse event that will trigger an image swap z Telling JavaScript which of several images to swap in, based on the mouse event z Replacing the old image with a new one I’ll also teach you a new way to detect which browser a visitor is using. A Real-World Example of Rollovers To begin, let’s take a look at rollovers in action. Tin House (http://www .tinhouse.com), one of my favorite literary journals, has a little house on its home page that helps you navigate the site. When you first come to the page, all the lights in the house are off (Figure 4-1); rolling over different parts of the house lights those areas up (Figure 4-2). It may be a little silly, but I like it. Figure 4-1: Tin House home page before mousing over the house Figure 4-2: Tin House home page with mouse over the house The Book of JavaScript home page also has a relatively straightforward and uncomplicated implementation of an image swap. If you mouse over the graphic that says Turn it over! the image of the front cover of the book will 52 Chapter 4 change to show the back of the book (see Figures 4-3 and 4-4). Mouse off the Turn it over! image again and the book image switches back to the front cover. There are many ways to script a rollover. Because rollovers don’t work in old browsers, or when people turn JavaScript off, creating them also involves browser detection, so in this chapter you’ll learn more ways to tailor JavaScripts to the visitor’s browser. You’ll also learn how quotation marks are handled in JavaScript and how the hierarchical framework of a web page, known as the Document Object Model (DOM), is reflected in JavaScript syntax. Figure 4-3: An image from the Book of JavaScript home page before mouseover Figure 4-4: The same image after mouseover Triggering Events So far all the JavaScript we’ve seen is triggered when a web page loads into a browser. But JavaScript can also be event driven. Event-driven JavaScript waits for your visitor to take a particular action, such as mousing over an image, before it reacts. The key to coding eventdriven JavaScript is to know the names of events and how to use them. Event Types With JavaScript’s help, different parts of your web page can detect different events. For example, a pull-down menu can know when it has changed (see Chapter 7); a window when it has closed (see Chapter 5); and a link when a visitor has clicked on it. In this chapter I’ll focus on link events. A link can detect many kinds of events, all of which involve interactions with the mouse. The link can detect when your mouse moves over it and when your mouse moves off of it. The link knows when you click down on it, and whether, while you’re over the link, you lift your finger back off the button after clicking down. The link also knows whether the mouse moves while over the link. W or k in g w it h R ol l o v e r s 53 Like the other kinds of interactions that we’ll cover in later chapters, all of these events are captured in the same way: using an event handler. onClick Figure 4-5 shows the basic format of a link that calls an alert after a visitor clicks it. Before adding JavaScript: Visit the Book of JavaScript website After adding JavaScript: Visit the Book of JavaScript website Figure 4-5: A link that calls an alert Try putting the link with the onClick into one of your own web pages. When you click the link, an alert box should come up and say Off to the Book of JavaScript! (Figure 4-6). When you click OK in the box, the page should load the Book of JavaScript website. Figure 4-6: The event-driven “Off to the Book of JavaScript!” alert box Notice that, aside from the addition of onClick, this enhanced link is almost exactly like the normal link. The onClick event handler says, “When this link is clicked, pop up an alert.” onMouseOver and onMouseOut Two other link events are onMouseOver and onMouseOut. Moving the mouse over a link triggers onMouseOver, as shown in Figure 4-7. board Figure 4-7: onMouseOver 54 Chapter 4 As you can see, moving the mouse over the link triggers onMouseOver. The code for onMouseOut looks like the onMouseOver code (except for the handler name) and is triggered when the mouse moves off of the link. You can use onMouseOut, onMouseOver, and onClick in the same link, as in Figure 4-8. board Figure 4-8: onMouseOut, onMouseOver, and onClick in the same link Mousing over this link results in an alert box showing the words Mayday! Mouse overboard! (Figure 4-9). Pressing ENTER to get rid of the first alert and moving your mouse off the link results in another alert box that contains the words Hooray! Mouse off of board!! If you click the link instead of moving your mouse off it, nothing will happen, because of the return false; code in the onClick. Figure 4-9: An alert box produced by mousing over a link onMouseMove, onMouseUp, and onMouseDown The onMouseMove, onMouseUp, and onMouseDown event handlers work much like the others. Try them yourself and see. The onMouseMove event handler is called whenever the mouse is moved while it is over the link. The onMouseDown event handler is triggered when a mouse button is pressed down while the mouse is over a link. Similarly, the onMouseUp event handler is triggered when the mouse button is lifted up again. An onClick event handler is triggered whenever an onMouseDown event is followed by an onMouseUp event. Quotes in JavaScript This example also demonstrates a new wrinkle in JavaScript syntax. Inside the double quotes of the onClick (Figure 4-8) is a complete line of JavaScript, semicolon and all. In previous chapters, we’ve placed all of our JavaScript between opening tags. The only exception to W or k in g w it h R ol l o v e r s 55 this rule is when JavaScript is inside the quotes of an event. Your browser will assume that anything within these quotes is JavaScript, so you shouldn’t put tags in there. Also note that the quotes in the alert are single quotes ('). If these were double quotes ("), JavaScript wouldn’t be able to figure out which quotes go with what. For example, if you wrote onClick = "alert("Off to the Book of JavaScript!");" JavaScript would think that the second double quote closed the first one, which would confuse it and result in an error. Make sure that if you have quotes inside quotes, one set is double and the other is single. Apostrophes can also pose problems. For example, let’s say you want the alert in Figure 4-7 to say Here's the Book of JavaScript page. You're gonna love it! You would want the JavaScript to resemble this: onClick = "alert('Here's the Book of JavaScript page. You're gonna love it!');" Unfortunately, JavaScript reads the apostrophes in Here's and You're as single quotes inside single quotes and gets confused. If you really want those apostrophes, escape them with a backslash (\), like this: onClick = "alert('Here\'s the Book of JavaScript page. You\'re gonna love it!');" Putting a backslash before a special character, such as a quote, tells JavaScript to print the item rather than interpret it. Clicking the Link to Nowhere You may have noticed that the links in Figures 4-7 and 4-8 have an unusual form for the href attribute: This hash mark (#) in an href means, “Go to the top of this page.” I’ve included it there because most browsers expect something to be inside the quotes after the href, usually a URL. In Figure 4-5, for example, the tag is In HTML, href is a required attribute of the anchor () tag, or link. href is an abbreviation for hypertext reference, and it’s required because, as far as HTML is concerned, the whole purpose of a link is to send the user 56 Chapter 4 somewhere else when the link is clicked, so the browser needs to be told where to go. Usually that’s another page, but in this case you are not trying to go anywhere. I might have just put nothing inside the quotes (href = ""), but different browsers will do different things in that case, and it’s usually something weird. Give it a try in your favorite browser. To avoid weird behaviors, it’s best to put the # sign inside an href when you don’t want the link to go anywhere when clicked. The link in Figure 4-8 had a second way of ensuring that the link didn’t go anywhere when clicked: onClick = "return false;". Placing return false; in the quotes after an onClick tells JavaScript to prevent the browser from following the URL inside the link’s href. This can be quite useful for dealing with people who have JavaScript turned off in their browsers. For example, if someone with JavaScript turned off clicks the link in Figure 4-10, the browser will ignore the onClick and happily follow the URL inside the href. This URL might go to a web page that describes the wonders of JavaScript and tells the user how to turn JavaScript on. People who already have JavaScript turned on will be treated to the contents of the onClick. They will see an alert box, and then the return false inside the onClick will prevent the browser from following the URL in the href. Although very few people turn JavaScript off (fewer than 1 percent of browsers), it never hurts to take them into consideration. Click me Figure 4-10: Links for people with JavaScript turned off More Interesting Actions You can do more with event handlers than simply triggering alert boxes. Figure 4-11, for instance, uses an event handler to customize a page’s background color. change background Figure 4-11: Customizing background color When you click this link, a prompt box asks whether you want to change the background to red or blue. When you type your response, the background changes to that color. In fact, you can type whatever you want into that prompt box, and your browser will try to guess the color you mean. (You can even do a kind of personality exam by typing your name into the prompt and seeing what color your browser thinks you are. When I type thau into the prompt, the background turns pea green.) W or k in g w it h R ol l o v e r s 57 This example demonstrates two new facts about JavaScript. First, notice that the onClick triggers three separate JavaScript statements. You can put as many lines of JavaScript as you want between the onClick’s quotes, although if you put too much in there, the HTML starts to look messy. Second, notice that you can change the background color of a page by setting window.document.bgColor to the color you desire. To make the background of a page red, you’d type: window.document.bgColor = 'red'; In the example, we’re setting the background color to any color the user enters into the prompt box. I’ll say more about window.document.bgColor soon. Swapping Images Using JavaScript, you can change or swap images on your web pages, making buttons light up, images animate, and features explain themselves. Before you tell JavaScript to swap an image, you have to tell it what image to swap by naming the image. Figure 4-12 shows you how. Before JavaScript: After JavaScript: Figure 4-12: Naming an image In this example, I’ve put an image of a happy face on the page and named it my_image. NOTE You can name an image whatever you like, but the name can’t contain spaces. Once you’ve named an image, it’s easy to tell JavaScript to swap it with a new one. Let’s say you have an image named my_image. To create an image swap, tell JavaScript you want to change the src of that image to another.gif: window.document.my_image.src = "another.gif"; Figure 4-13 shows the code for a very basic page with an image and a link; click the link, and the image changes to happy_face.gif (Figure 4-14). Simple Image Swap
make my day! Figure 4-13: JavaScript for a basic image swap Figure 4-14: Swapping a sad face for a happy one Working with Multiple Images If you have more than one image on a page, you should give each one a different name. Figure 4-15 has two images and two links. The first link tells JavaScript to swap the image called my_first_image (the sad face) with happy_face.gif. The second link tells JavaScript to swap the image called my_second_image (a circle) with square.gif. The result is shown in Figure 4-16. NOTE When using more than one image, you must name your images differently. If you accidentally give two images the same name, the swap won’t work. Two Image Swaps

make my day!
square the circle! Figure 4-15: JavaScript for swapping two images NOTE Image swapping doesn’t work in browsers earlier than Internet Explorer 4.0 or Netscape 3.0. Furthermore, if you’re trying to replace a small image with a bigger one, or a big image with a smaller one, browsers earlier than Netscape 4.61 and Internet Explorer 4.0 will squash or stretch the new image to fit the space the old one occupied. Later versions of these browsers adjust the page to fit the bigger or smaller image. W or k in g w it h R ol l o v e r s 59 Figure 4-16: Swapping two images What’s with All the Dots? You may wonder why JavaScript refers to my_image as window.document.my_image and not just as my_image. You may also wonder why you would use window .document.my_image.src when you want to change the src of that image. In short, what’s with all the dots? The answer has to do with how your browser looks at your web page. Figure 4-17 shows the hierarchical organization of a web page as JavaScript understands it—through the Document Object Model (DOM). At the top of the DOM is the window that contains the web page you’re viewing. That window contains the navigator, document, and location objects. Each of these objects has a lot of information in it, and by changing one you can change what happens on your web page. The dots in a line of JavaScript separate hierarchical levels of objects. When JavaScript sees a series of objects separated by dots, it goes to the last object in the series. So, for example, the phrase window.location tells JavaScript to find the location object inside the current window. Similarly, the line window.document.my_image.src tells JavaScript to find the source file (src) of the image named my_image within the document object in the current window. The current window is the one in which the JavaScript is located. The document Object The document object lists all the images, links, forms, and other stuff on a web page. To code an image swap, we must tell JavaScript to find the document object in the window, then locate the image object we would like to change in the document object’s list, and finally change the image’s src. In JavaScript terms (where happy_face.gif is the image we’re swapping in), this is how it looks: window.document.my_image.src = "happy_face.gif"; 60 Chapter 4 THE CURRENT WINDOW self, window, parent, top various Window objects navigator Navigator object frames[] array of Window objects plugins[] mimeType[] array of Plugin objects MimeType objects array of mimeTypes[] array of MimeType objects forms[] location Location object history History object array of Form objects anchors[] array of Anchor objects document Document object Package JavaPackage object images[] array of Image objects applets[] array of JavaObject objects embeds[] elements[] array of HTML Form element objects: Button Checkbox FileUpload Hidden Password Radio Reset Select Submit Text Textarea options[] array of array of JavaObject objects Option objects Figure 4-17: DOM’s hierarchical organization Object Properties An object’s properties are the bits of information that describe the object, such as its height, width, and src (the name of the file that the image displays). Some properties, such as the src of an image, can be changed, and others can’t. As we’ve seen, changing the src property of an image object changes which file is displayed: window.document.my_image.src = "happy_face.gif"; Other properties, like the image’s height and width, are read-only and cannot be changed. The document object contains the image objects, and it has its own properties. For example, the background color of the document object is called bgColor. That’s why we could change the background color of our document using window.document.bgColor = 'red'. The image and document objects are just two of many objects we’ll be seeing throughout the book. Each JavaScript object has its own set of properties. Appendix C provides a list of many JavaScript objects and their properties. W or k in g w it h R ol l o v e r s 61 Finally, Rollovers! Now that we know how to tell JavaScript how to do an image swap and how to trigger JavaScript based on a user event with onClick, onMouseOver, and onMouseOut, we can create a rollover. Just stick an onMouseOver and onMouseOut inside an image tag, like this: See how that works? When first loaded, the image shows the sad_face.gif because that’s what the image tag calls. tags, it’s not a bad idea to put them in a link surrounding the image: Image Preloading That’s pretty much all there is to your basic image swap. As usual, there’s something that makes the process a little more difficult. When you do an image swap as I’ve described, the image that’s swapped in downloads only 62 Chapter 4 when your visitor mouses over the image. If your network connection is slow or the image is big, there’s a delay between the mouseover and the image swap. The way around this potential download delay is to preload your images—grabbing them all before they’re needed and saving them in the browser’s cache. When the mouse moves over a rollover image, the browser first looks to see whether the swap image is in its cache. If the image is there, the browser doesn’t need to download the image, and the swap occurs quickly. There are hundreds of image preloading scripts, and they’re all basically the same. Rather than write your own, you can download one of the free ones and paste it into your page (Webmonkey has a good one at http://www .hotwired.com/webmonkey/reference/javascript_code_library/wm_pl_img). Let’s go over the basics of how preloads work so you’ll recognize them when you see them. There are two parts to a preload. First, you create a new image object. The line var new_image = new Image(); creates a new image object that has no information. It doesn’t have a GIF or JPEG associated with it, nor does it have a height or width. If you know the height and width of the image, you can do this: var new_image = new Image(width, height); Giving JavaScript information about the size of the image helps the browser allocate memory for the image; it doesn’t have much impact on how users experience your web page. Once you’ve created this new object, new_image.src = "my_good_image.gif"; forces the browser to download an image into its cache by setting the image object’s src. When the image is in the browser’s cache, it can be swapped for another image without any download delays. Figure 4-18 incorporates a preload with the rollover we saw in the last example. Preloaded Rollover W or k in g w it h R ol l o v e r s 63 Figure 4-18: Image preload and rollover How the Tin House Rollovers Work At the beginning of the chapter, I mentioned the home page of Tin House. Its image swap JavaScript is quite simple and will give you an idea of how easy it is to add a little JavaScript to your site. The Tin House rollover involves four images: the top, middle, left, and right parts of the bottom floor of the house. These images are placed in an HTML table to create the complete image of the house. Figure 4-19 shows you the (abbreviated) code for the top floor. X [ General Information: Our history, our glory, and our guidelines. Figure 4-19: Rollover from the Tin House home page This should look very familiar by now. Line [ describes the image. Notice that Tin House puts width, height, border, and alt attributes inside their image tag as well as the name attribute used to do the image swap. The height and width attributes tell web browsers how much space to reserve for the image. The alt attribute does two important things. First, some browsers don’t display images. This might be because the person is on a slow connection and has turned images off in their browser, or because they using are a device that can read web pages to them, or perhaps it’s a search engine visiting your web page, looking for stuff to add to its index. The alt attribute in an image provides information about that image in all of these situations. In addition, the alt attribute is used by some browsers even when images are being displayed. Recent versions of Internet Explorer, for example, will display the alt text in a yellow box when you leave your mouse over an image for more than a second or two. Getting back to the JavaScript, you can see that Tin House has put its onMouseOver (Y) and onMouseOut (Z) inside an HTML link (X). As we’ve seen, the onMouseOver and onMouseOut event handlers can go either in the image itself, or in a link surrounding the image, as Tin House has done. 64 Chapter 4 Summary In this chapter you’ve learned: z How to trigger events, such as onMouseOver and onMouseOut z How to nullify a link with return false inside onClick z How to change the background color of a page z How to swap images z How to preload images so that they’ll swap in more quickly z How the DOM uses dots to separate objects into hierarchies Now that you know the basics of image swapping, you can perform lots of tricks. You can make an image vanish by swapping in one that’s the same color as the page background. You can make images composed of explanatory text and place them next to the feature they describe. There’s no end to the fun you can have with image swaps. As always, we’ll be revisiting many of these points in later chapters, so you’ll become more and more familiar with them. To make sure you understand how they work, try the following assignment. Assignment Figures 4-20 and 4-21 show you a page which does two image swaps simultaneously. Notice that mousing over the text on the bottom of the screen changes the words from turn over to turn back and swaps the book’s front cover with its back cover. The words, like the book covers, are images, and they are swapped using the techniques we’ve learned in this chapter. Your assignment is to write a similar page where mousing over one image causes two images to change. Figure 4-20: The Chapter 4 assignment page before the rollover Figure 4-21: The Chapter 4 assignment page after the rollover W or k in g w it h R ol l o v e r s 65 OPENING AND MANIPULATING WINDOWS JavaScript gives you the ability to open multiple browser windows and control what’s inside them. JavaScript can also change where windows are located on your visitor’s screen. You can use the windows you open to present a slide show or some help information or to build a remote control device for your site. In this chapter, you’ll learn how to: z Open new windows with JavaScript z Make those windows look the way you’d like z Position the windows on your visitor’s screen z Swap images inside windows you’ve opened Real-World Examples of Opening Windows to Further Information Let’s begin with a quick look at two examples of windows linked from home pages. The Network for Good (http://www.networkforgood.org) is one of the best charity resources on the Web. At the top and bottom of its page, it has links to a Help window (Figure 5-1). Click either link, and a window with answers to frequently asked questions pops up. Notice that this window is smaller than the Network for Good home page and has no menu bar across the top. Also notice the familiar close box button in the upper-right corner of the Help window. Clicking that box closes the window. Figure 5-1: Opening a window to further information The Book of JavaScript web page (http://www.bookofjavascript.com) has an About the Author link (Figure 5-2), which acts similarly. Clicking this link opens a smaller window that provides more information about me, the author. At the bottom of the window is a button that closes the window. Help windows like these can vastly improve a visitor’s experience of your site. Rather than clicking to a new web page, waiting for the download, and then having to click back to the original page if she wants to refer to it for a moment, the user will find that these windows display your information very quickly and without browser navigation, and it will be possible for her to see both pages at once and switch quickly between them. 68 Chapter 5 Figure 5-2: A small helper window Working with Windows as Objects Because windows are objects, you manipulate them just as you would any object (see Chapter 2 for a discussion of objects and methods), by using JavaScript’s dot notation to apply one of the available methods to the window object you name: window_name.method_name(); This chapter introduces the methods that JavaScript provides for the most important window operations, along with useful properties you can specify for a window object. Opening Windows To open a window, use the open() method, which opens a window that has the characteristics you specify as parameters inside its parentheses: var window_name = window.open("some_url", "html_name", "feature1,feature2,feature3,..."); In this example, I’ve set up a variable called window_name to refer to the window we’re opening. When I want to use JavaScript to change or manipulate what’s inside the window, I’ll refer to this window as window_name. Here window_name is just a variable—you could use any valid JavaScript variable name, such as fido, in its place if you so desired (see Chapter 2 for variable naming rules). O pe n i n g an d M an i pu lati n g W i n do w s 69 Manipulating the Appearance of New Windows The three parameters of the window.open() command control the new window’s characteristics. The URL Parameter The first parameter is the URL of the page you want to appear inside the window when the window opens. If you’d like to open a window with the Book of JavaScript website, inside the Use the remote control to send various web pages to this window. Figure 5-7: The code for the window that calls the remote control NOTE Some people install pop-up blocking software on their computers or set their browsers to block pop-up windows. Because the JavaScript in Figure 5-7 opens a window automatically (without the user having to click a link), it qualifies as a pop-up window, and computers that block pop-ups will prevent the window from opening. If the above JavaScript doesn’t work on your computer, it may be because you have blocked pop-ups. The code in Figure 5-7 opens a window and loads the web page called the_remote.html, which is shown in Figure 5-8. Figure 5-9 shows you the code for the_remote.html. o Figure 5-8: The page that calls the remote control, and the remote control itself Remote Control X NY Times
76 Chapter 5 Webmonkey
Salon
Figure 5-9: The remote control code Figure 5-9 includes code for a typical link using an onClick (X). When a visitor clicks the New York Times link, JavaScript looks up window.opener (the window that opened the remote control) and then changes its location to http://www.nytimes.com. Then, because of the window.focus(), JavaScript brings the remote control window to the front of the screen. Notice that because this JavaScript is running inside the remote control window, we use window.focus() rather than control_window.focus(). More Window Methods You’ve seen four window methods so far: open(), close(), focus(), and blur(). Let’s look at two more that come in handy from time to time: resizing and moving windows. Resizing Windows Modern browsers provide two different ways your JavaScript can resize a window. The window.resizeTo() method resizes a window to a given width and height. To change a small window into one that’s 500 pixels wide and 200 pixels high, you’d use the following script: window.resizeTo(500,200); Alternatively, you can change the size of a window by a specific amount using window.resizeBy(). The window.resizeBy() method takes two numbers: how much the width of the window should change and how much the height should change. The code window.resizeBy(10, -5); makes a browser 10 pixels wider and 5 pixels shorter. Moving Windows The window.moveTo() method moves a window to an absolute position on the screen. If you want the window in the upper-left corner of the user’s screen, you’d type: window.moveTo(0,0); O pe n i n g an d M an i pu lati n g W i n do w s 77 The first number is the number of pixels from the left border of the screen you want the window’s upper-left corner to appear, and the second number is the number of pixels from the top of the screen. An alternative to window.moveTo() is window.moveBy(). If you want to move a window 5 pixels to the right and 10 pixels down from its current position, you’d type: window.moveBy(5,10); The first number is the number of pixels to the right you want to move the window, and the second is the number of pixels down. If you want to move the window 10 pixels up and 5 to the left, just use negative numbers: window.moveBy(-5,-10); Be careful not to move a window entirely off a user’s screen. To ensure against this possibility, you have to know the size of the user’s screen. The two properties that indicate this are: window.screen.availHeight window.screen.availWidth Figure 5-10 shows how you can use window.screen.availHeight and window.screen.availWidth to move a window to the center of the screen. This script centers the window on any screen, regardless of its size. Center Window

Hi!

Figure 5-10: Code for moving a window to the center of the screen Lines X through Z resize the window to 200 by 200 pixels. Once that’s done, the script uses window.screen.availHeight and window.screen.availWidth to figure out how high and wide the screen is. After determining those values, the script does some calculations to figure out where the upper-left corner of the window should go. Let’s look at the formula to calculate the left-hand position of the window: var left_point = parseInt(width / 2) - parseInt(window_width / 2); The first part of this formula determines the screen’s midpoint by dividing the width of the screen by two (we’ve defined the variable width in [). The parseInt() command ensures that the resulting number is an integer. Knowing the screen’s midpoint isn’t enough to center the window, however, because window.moveTo() sets the left border of the window you’re moving. If you move the left border of the window into the center of the screen, the window will be too far to the right. To get the window to the center of the screen, we have to move it over to the left. The second part of the formula, subtracting parseInt(window_width / 2), figures out how far to move the window to the left: half the window’s width (see Figure 5-11). If you place the left side of the window in the middle of the screen, the window won’t be centered. You have to move it a bit to the left. To center the window, move it ½ of its width to the left. In other words, the left border is: ½ screen width – ½ window width. screen screen window window ½ window width ½ screen width ½ screen width Figure 5-11: Calculating how to center a window O pe n i n g an d M an i pu lati n g W i n do w s 79 Line \ performs a similar calculation to determine where to set the top of the window. Once we’ve determined the window’s correct top and left position, we use the window.moveTo() command to move it (]). NOTE In Internet Explorer, the moveTo() method works only when it is moving the window containing the JavaScript. In other words, if you have opened a window named my_window, you can’t move that window using my_window.moveTo(100,100). You can still use window.moveTo(100,100) to move the window that contains the JavaScript calling the moveTo() method. Summary In this chapter you’ve learned: z How to open new windows with window.open() z How to incorporate various standard browser elements in the new window using the feature parameter z How to close the windows you’ve opened with window_name.close() z How to move windows to the front of the screen with window.focus() z How to send windows to the back of the screen with window.blur() z How to change the message in the window’s status bar by setting window.status z How a window you’ve opened can affect the previous window with window.opener z How to resize windows with window.resizeTo() and window.resizeBy() z How to move windows with window.moveTo() and window.moveBy() Congratulations! Now that you know how to swap images and mess with windows, you can handle about 75 percent of what most web professionals do with JavaScript. The next few chapters will cover some details of JavaScript as a programming language, and then we’ll be ready for the really fancy stuff. Assignment We’ve learned how to change the contents of the status bar of a window we’ve opened using JavaScript: var my_window = window.open("http://www.nostarch.com","my_window"); my_window.status = "I'm in the new window's status bar!"; We can use a similar technique to swap an image in a window we’ve opened using JavaScript. Remember, the code to swap an image looks like this, where the_image is the name of an image on the page: window.document.the_image.src = "new_image.gif" 80 Chapter 5 To swap an image in another window, just replace window in the script with the name of the window containing the image. Your homework assignment is to write a page (let’s call it the main page) that contains two links. Write some JavaScript so that when the main page opens, it also opens a little window containing an image. When clicked, the two links on the main page swap different images into the little window. Figures 5-12 and 5-13 demonstrate what I mean. Figure 5-12: After opening the main window Figure 5-13: After clicking the Really Happy link This assignment is a bit tricky, but give it your best shot before looking at the solution in Appendix A. O pe n i n g an d M an i pu lati n g W i n do w s 81 WRITING YOUR OWN JAVASCRIPT FUNCTIONS In this chapter we’re going to focus on a programming concept—writing your own functions. Knowing how to write your own functions will improve almost any JavaScript you create. In fact, you’ll see how custommade functions can enhance several of the JavaScript tricks you’ve already learned. In this chapter, you’ll learn how to: z Write your own functions z Use homemade functions to improve your code z Write functions you can cut and paste into whatever pages you want We’ll be using homemade functions in every chapter from now on, so pay extra-close attention to what’s going on in this chapter. You’ll be glad you did.. Functions as Shortcuts Functions aren’t anything new. You’ve already seen a number of functions that come built in to JavaScript. The alert() function, for example, takes whatever text you put inside the parentheses and displays an alert box with that text. In its simplest form, function is just a shorthand name for a series of JavaScript instructions. When you call the alert() function, JavaScript understands it as a command to carry out some task, such as opening a window that has an OK button and a close button and putting some text in the window. The functions you create act as shorthand as well. Let’s say you want to write a link that opens a small window and then centers that window on the screen if the visitor is using Netscape 4.0 or above. You could write a link resembling Figure 6-1 (most of the code in it is similar to Figure 5-10). Click me to open a small centered window Figure 6-1: A link that opens a small window and centers it in Netscape 4 and above— this won’t work in Internet Explorer (see note at the end of Chapter 5) However, it is not a good idea to write a link in this way: There’s too much JavaScript embedded in the HTML. This makes HTML hard to follow, even for people who know JavaScript. Furthermore, if you want two or three links on your page, your HTML becomes even uglier and your page’s download time increases. Even more problematic, if you want to change the code to affect window size or centering, you have to make the change everywhere you put the link. The solution to these problems is to give all the JavaScript in Figure 6-1 a name and then simply call that name when you want to open and center a window. That’s exactly what homemade functions are for: They allow you to call a set of JavaScript instructions (the function) just by using its name. Basic Structure of JavaScript Functions Figure 6-2 shows you the skeleton of a homemade function. 84 Chapter 6 function functionName() { a line of JavaScript; another line of JavaScript; more lines of JavaScript; } Figure 6-2: The basic structure of a homemade function A function definition starts with the word function. When JavaScript sees that word, it knows you’re about to define the subsequent bunch of JavaScript as a function. Naming Your Functions Next comes the function’s name. The rules for naming a function are similar to those for naming a variable. The first character must be a letter; the rest of the characters can include letters, numbers, dashes, and underscores. No other characters, including spaces, are allowed. Like variables, function names are case sensitive, so JavaScript will consider a function called feedTheCat() to be different from a function called FeedTheCat(). Make sure you don’t give a function and a variable the same name. If you have a variable called my_cat and a function called my_cat, JavaScript will forget either what the function’s supposed to do or what value you’ve stored in the my_cat variable. Because of this weird behavior, and because function names are case sensitive, it makes sense to have a different convention for naming functions than for naming variables. For variables I use lowercase letters with underscores, and for functions I use what’s called in-caps or camel-caps notation. Names in this notation style consist of strings of words without spaces, in which every word except the first is initial-capitalized, as in openAndCenterTheWindow(), myCat(), and printDate(). In-caps notation is a pretty common convention and should serve you well. Parentheses and Curly Brackets A pair of parentheses follows the function’s name. For now, you won’t be entering anything between them, but they’re still necessary. After the parentheses you need a pair of curly brackets. Between these brackets you’ll write the JavaScript that will run when the function is called. An Example of a Simple Function Figure 6-3 shows you how the window-centering code in Figure 5-10 looks rewritten as a web page containing a function. Notice that the link calling the function (X) has the same form as a link that calls a built-in JavaScript function—the function name appears inside an onClick. W r iting You r O wn Jav aScript Functions 85 Getting Centered X Click me to open a small centered window Figure 6-3: Opening and centering a window using a function Next, notice that I’ve put the JavaScript declaring the function in the head of the page. You can declare functions in either the head or the body of an HTML page, but I like to declare my functions in the head because that way I don’t have to search for them all over the page. Finally, it’s important to remember that the browser reads the page from the top down. When it sees the word function, it remembers the function name and the lines of JavaScript you’ve associated with that name. However, the JavaScript between the curly brackets doesn’t actually execute until the onClick in the link calls the function. When we start putting more than one function on a web page, you’ll see why it’s important to keep this in mind. Writing Flexible Functions The code in Figure 6-3 does a good job of opening and centering a window containing No Starch Press’s home page. But what if you wanted another link to open and center a different window with a different URL in it— Webmonkey’s, for example? 86 Chapter 6 One approach would be to write a second function that looks just like the first one, the only difference being that you’d replace the line var the_window = window.open('http://www.nostarch.com/','the_window','height=200,width=200'); with the line var the_window = window.open('http://www.webmonkey.com/','the_window','height=200,width=200'); This would work fine, but it’s not a good idea to have two functions that do almost exactly the same thing. First of all, it’s wasteful. If you could write one function that worked regardless of the URL, you’d save both typing and download time. Even more important, if you want to change how you’re doing the centering, you’ll have to change two functions instead of just one. Using Parameters Luckily, there’s a way to make your function more flexible. The trick is to add a parameter. Remember, the alert() function takes one parameter—the words you want to appear in the alert box. You can write the openAndCenterWindow() function to take a parameter, too. In this case, the parameter would be the URL of the web page you want to appear in the window. In general, a function’s parameter is whatever item of information the function needs in order to do its job—text to be displayed, a URL to link to, or whatever. Many functions use multiple parameters. The code in Figure 6-4 shows how to add a parameter to your function and how to call the function with this parameter. Getting Centered Functionally Y Click me to put the Webmonkey home page in a small centered window

Click me to put the No Starch Press home page in a small centered window Figure 6-4: Opening and centering a window with a parameter Line-by-Line Analysis of Figure 6-4 The tag for Webmonkey, Click me to put the Webmonkey home page in a small centered window calls the function with the URL for Webmonkey in parentheses (see the result in Figure 6-5). Here Webmonkey’s URL goes into the function just as the words go into the alert() function, but instead of any random string, it’s a URL. Figure 6-5: The Webmonkey site, opened and centered 88 Chapter 6 Similarly, the tag Click me to put the No Starch Press home page in a small centered window calls the function with the URL for No Starch Press. Now let’s look at the function itself. Only two lines differ from those in Figure 6-3. The first line of the function now looks like this: function openAndCenterWindow(the_url) Notice that a word appears inside the parentheses now. This term is a variable, storing whatever value you’ll use when you call the function. So if the line openAndCenterWindow("happy happy!"); calls the function, the variable the_url holds the value "happy happy!". When we call the function in Figure 6-4 as follows, the variable the_url holds the value "http://www.nostarch.com/": Click me to put the No Starch Press home page in a small centered window The second line in the function that differs from Figure 6-3 is Y, which opens the window. In Figure 6-3 we opened the window with a web page: var the_window = window.open('http://www.nostarch.com/', 'the_window', 'height=200,width=200'); In Figure 6-4 we open the window with the variable that was set when the function was called: var the_window = window.open(the_url, 'the_window', 'height=200,width=200'); JavaScript sees the variable the_url and knows it’s a variable because no quotes surround it. If the function has 'http://www.nostarch.com/' inside the parentheses, like this openAndCenterWindow('http://www.nostarch.com/'); the variable the_url has the value http://www.nostarch.com/, so the window opens with the No Starch Press home page. Figure 6-6 shows you graphically what’s going on here. W r iting You r O wn Jav aScript Functions 89 Function Definition function openAndCenterWindow(the_url) { var the_window= window.open(the_url, ", 'height=200,width=200'); } Function Call openAndCenterWindow('http://www.nostarch.com/'); Figure 6-6: Passing parameters Using More Than One Parameter Sometimes you want to change more than one thing each time you call a function. The built-in JavaScript function prompt(), for example, can change two sets of words: the words that appear above the text box and those that appear within it. When we call prompt() as follows, we pass in two parameters, separated by a comma: var the_answer = prompt("What's your favorite color?","yellow?"); The method window.open(), discussed in the last chapter, provides an example of three parameters: the URL you want to open inside the window, the name of the window, and the window’s features. The functions you write can also take more than one parameter. Let’s say you want to write a function to display a web page in a square window. You might write a function that finds the name of the page and the length of one of the sides of a window. Figure 6-7 shows you what this would look like. Square Windows Y Open the Webmonkey home page in a big square window
90 Chapter 6 Open the No Starch Press home page in a small square window
Figure 6-7: Writing functions that take more than one parameter Notice that in X two variables now appear between the parentheses following the function name: the_url and the_length. In Y we’re calling the function as we would call prompt(), with two parameters separated by a comma. Calling the function sets the first variable in the function definition to the first parameter, so in the case of Y, the_url is set to http://www.webmonkey.com/. Similarly, the second variable in the function definition is set to the second parameter in the function call. If we call the function as in Y, the_length is set to 400. Figure 6-8 depicts the results of calling functions with two parameters. Function Definition function openSquareWindow(the_url, the_length) { var the_features = "width=" + the_length + ",height=" + the_length, var the_window = window.open(the_url, "", the_features); } Function Call openSquareWindow('http://www.webmonkey.com/', 400); Figure 6-8: Calling functions with two parameters Getting Information from Functions You can also write functions that give information back to you. Consider the prompt() function: var the_answer = prompt("What's your name?","Ishmael"); When a user types his or her name into the prompt box and clicks OK, the name goes into the variable the_answer. In programming parlance, you’d say that the function prompt() returns the words typed into the prompt box. The functions you write can return values as well. Figure 6-9 shows a very simple example of how to make a function return values. Date Printer Hello! Today is Figure 6-9: A script with a simple function that returns a value Line-by-Line Analysis of Figure 6-9 Most of the function should be familiar by now. The first four lines create a new Date object and carry out a few method calls to get information from that object. Line X takes the information gathered and creates a nicely formatted date. Notice that the line is var the_nice_date = the_month + "/" + the_day + "/" + the_year; and not var the_nice_date = "the_month/the_day/the_year"; The latter won’t work, because JavaScript won’t recognize the_month, the_day, or the_year as variables if they appear inside quotes. The correct version of this line takes the variables out of the quotes and puts them together with slashes using the plus (+) sign. In the incorrect version, the quotation marks stop JavaScript from interpreting the names as variables, so the web page would display Hello! Today is the_month/the_day/ the_year. Line Y tells JavaScript to exit the function and return the value of the_nice_date to whatever variable is waiting for it. In this case, the variable is today in Z. Whenever JavaScript sees the word return in a function, it exits the function and outputs whatever value comes after return. 92 Chapter 6 Line Z calls the function getNiceDate(), which returns a nicely formatted date. The code document.write(today) then puts the date on the web page, as shown in Figure 6-10. Figure 6-10: Returning the date Dealing with Y2K Figure 6-9 works fine, but it has a little problem. Remember our discussion of the Y2K problem in the getYear() method of the Date object (“Writing the Date to Your Web Page” on page 26)? Different browsers deal with years differently. In some versions of Netscape, getYear() returns the year minus 1900. So if it’s the year 2010, getYear() returns 110. Other versions return the full four-digit year if the year is before 1900 or after 1999. Different versions of Internet Explorer give different results for the same date as well. The way to deal with this problem is to see whether the year returned by getYear()is less than 1000. If so, your visitor is using a browser that subtracts 1900 from the date if it’s after 1899. In this case, you can get the correct fourdigit year by adding 1900 to the date. You’ll find a concise form for all this convoluted logic in the JavaScript function Y2K(), shown in Figure 6-11. function Y2K(the_date) { if (the_date < 1000) { the_date = the_date + 1900; } return the_date; } Figure 6-11: Dealing with the Y2K problem This function adds 1900 to the year if it is less than 1000. You can drop the Y2K() function into the script shown in Figure 6-8 to deal with its Y2K problem. Figure 6-12 demonstrates how the two look together. Date Printer Hello! Today is Figure 6-12: The script in Figure 6-9 with the Y2K fix Line-by-Line Analysis of Figure 6-12 Line X in Figure 6-12 uses the getYear() method to get the year, and Y calls the function Y2K() on the year to fix it up. The variable the_fixed_year is set to whatever Y2K() returns. The JavaScript in Figure 6-12 actually defines the function Y2K() after the getNiceDate() function. It might seem strange that getNiceDate() can call Y2K() even though Y2K() is defined after getNiceDate(). Remember, though, that when you define functions, you’re just telling JavaScript their names and what they do, so the order in which you define your functions doesn’t matter as long as you define them all before you call any of them from HTML. Defining Variables Properly The getNiceDate() function in Figure 6-12 calls the year variable the_year. However, when you look at how the Y2K() function appears in Z, you’ll see that it calls whatever passes into it the_date. Since we’re calling Y2K(the_year), JavaScript looks up the value of the_year and then sends that value to the Y2K() function. The Y2K() function stores that value in the variable the_date. In other words, the functions getNiceDate() and Y2K() have two different names for the same value. It’s as if the functions are different countries where people speak different languages. If you try to talk about the_year inside the Y2K() function, it won’t know what you’re saying, and you’ll get an error. Figure 6-13 shows you a graphical representation of how this works. 94 Chapter 6 function getNiceDate() { var now = new Date(); var the_month = now.getMonth()+1; // remember, Jan is month 0 var the_day = now.getDate(); var the_year = now.getYear(); var the_fixed_year = Y2K(the_year); var the_nice_date = the_month + "/" + the_day + "/" + the_fixed_year; return the_nice_date; } function Y2K(the_date) { if(the_date < 1000) { the_date = the_date + 1900; } return the_date; } Let’s say now.getYear() returns 110, meaning that it’s 2010 and your visitor is using IE. This means that the_year = 110 inside the getNiceDate() function. Here we’re passing the_year into the Y2K() function. First, JavaScript figures out that the_year is a variable equal to 110. Then it passes the value 110 to the Y2K() function. Inside the Y2K() function, the variable the_date takes the value 110, because that’s what we passed into the function. Now the_date gets changed to 2010. The value of the_date is returned to the awaiting variable. The awaiting variable is the_fixed_year. So now the_fixed_year has the value 2010. Figure 6-13: How variables work in different functions Why can’t the Y2K() function access the variable the_year in getNiceDate()? Because when you first defined the_year, you put the word var in front of it: var the_year = now.getYear(); The word var tells JavaScript to create the variable only for the function where it’s defined. If you’d omitted var when defining the_year, you could access that variable inside the Y2K() function. You might think that freedom would be a good thing. Why shouldn’t you access the_year anywhere in the program—why hide it inside getNiceDate()? The reason is that if you don’t hide variables inside functions, you will soon drive yourself crazy. Having one function change a variable that was declared in another function is a major cause of difficult-to-debug problems. The idea of protecting variables declared inside functions is such an important programming concept that it gets its own name: encapsulation. Consider the example in Figure 6-14 to see the headaches you’ll avoid if you define your variables with var: Bad Encapsulation Click here for a survey Figure 6-14: The dangers of variables without var If I run this example and input thau when the prompt asks for a name and fido when the prompt asks for a dog’s name, we end up with an alert that says fido has a dog named fido. Somewhere along the line, the program forgot that my name was thau and replaced it with fido. This happened because both getNames() and getDogName() use a variable called the_name. Function getNames() saves the user’s name in the variable the_name. Then function getDogName() saves the dog’s name in the_name. If I had used var when declaring the variable the_name in the getDogName() function, JavaScript would have understood that the variable is specific to that function and would have left alone all the_name variables in other functions. Because I didn’t use var when I set the variable the_name inside the getDogName() function, I unintentionally replaced the contents of the_name with the dog’s name. When getDogName() exits and the alert comes up, we see the dog’s name: alert (the_name + " has a dog named " + dog_name); If I had used var inside the getDogName() function, thau has a dog named fido would have come up. As your JavaScripts get longer, you’re likely to use the same variable in different functions. Without var, it’s very difficult to track down what’s going wrong in these functions, so save yourself the headache with a little preparation. Using var to hide variables inside functions also allows you to write functions that you can cut and paste into other scripts. If you define all your variables with var, you don’t have to worry about whether a function you’ve written will mess up another function when you paste it into a different page. Otherwise you can’t tell whether some variable in a program shares a variable name with your function. Summary There’s an art to figuring out when to use a function and knowing the best way to write one. In general, the best time to use a function is for a simple task you need to execute more than once. For example, patching the Y2K 96 Chapter 6 bug in JavaScript is a task you may have to do repeatedly, so it’s a good idea to create a function to handle it. As we see more complicated examples of JavaScript later in the book, you’ll get a sense for what should go into functions. And, of course, as you view the source code on all the great web pages you see, you’ll notice how various JavaScripters use functions. Almost all complicated JavaScripts use at least one homemade function. In this chapter, you’ve seen how to write simple functions with no parameters and more complicated functions that take parameters and return values. If you found all of this a bit tricky, don’t worry. You’ll have many more opportunities to learn how to use functions in JavaScript. Assignment Write a page with three images on it, each of them a navigational icon leading to another website. Each time the user mouses over a navigational icon, it should do an image swap, and a new window should open with an appropriate URL. For example, the three images could be of an apple, a monkey, and a sun. (See http://www.bookofjavascript.com/Chapter06.) When the user mouses over the sun icon, the image could swap to a happy sun, and a window with the Sun Microsystems home page could open up. Create this effect using a function that takes three parameters: the image to swap, the new image to put in its place, and the URL to open in the new window. For example, if the user mouses over the sun icon, the image should look like this: The first parameter in the function fancySwap() is the location of the image you want to swap. Notice that the image has the name sun. This means JavaScript will refer to this image as window.document.sun. The second parameter is the name of the GIF file to swap into the image called sun. The third parameter is the URL that should open in the new window. The function you write will start as follows: function fancySwap(the_image_tag, the_new_image, the_url) { you fill in here . . . } The lines of code you write will carry out the image swap (using what you learned in Chapter 4) and open a new window with the_url (using what you learned in Chapter 5). NOTE As described in Chapter 5, if the user has a pop-up blocker, the code may not work. Good luck—this is a tough one! W r iting You r O wn Jav aScript Functions 97 PROVIDING AND RECEIVING INFORMATION WITH FORMS So far I’ve shown you a few ways to get information from your visitors. You can ask questions with the prompt() function, and you can use onClick to tell when they click a link or onMouseOver to detect when they move over a link. In this chapter, you’ll learn a plethora of ways to collect and display information using HTML forms and JavaScript. You can rely on forms and JavaScript to create very interactive sites that might include surveys and quizzes, calculators, games, and novel navigational tools. In this chapter you’ll learn how to: z Create HTML forms z Use JavaScript to read a form a visitor has filled out z Use JavaScript to fill out a form automatically z Use forms as navigational tools Real-World Examples of Forms Forms can gather all sorts of input, including demographic information such as age and gender, answers to quizzes and polls, and numbers for tricky equations. The mortgage monthly payment calculator shown in Figure 7-1 offers an example of the latter. The form gives you places for the amount, interest rate, and length of a loan. If you enter all this information and click the submit button (which says calculate monthly payment), JavaScript reads the information off the form, performs a calculation, and displays the results in the monthly payment box. Figure 7-1: This mortgage calculator uses a form that presents input fields. You can also use forms as navigational tools. The home page for Doctors Without Borders (http://www.doctorswithoutborders.org, shown in Figure 7-2) has a pull-down menu that functions as a navigational tool. Click the menu, pull down to highlight the name of the country you’d like information about, and release the mouse—JavaScript tells the browser to take you to the page. Figure 7-2: The Doctors Without Borders home page uses a pull-down menu that acts as a navigational form. 100 Chapter 7 As a third example, the Book of JavaScript home page also has a pull-down menu that functions as a navigational tool (Figure 7-3). Click the menu, pull down to highlight the name of the chapter you’d like to visit, and release the mouse—JavaScript directs your browser to a page of information about that chapter. Figure 7-3 shows the navigation element on the Book of JavaScript home page. Figure 7-3: The Book of JavaScript home page’s navigation element All three examples work in the same general way: HTML draws the forms in Figures 7-1 and 7-3 on the web page, and JavaScript reads the information that the visitor fills in. Most forms that use JavaScript follow this pattern. Let’s look first at how to write forms to your web page with HTML. Form Basics Figure 7-4 shows a simple form displayed in a browser, and Figure 7-5 shows the HTML behind that form. Figure 7-4: A simple HTML form A Very Basic HTML Form X

Y Name:
Z Age:
Provi ding and Receivi ng Information with F orms 101 [
Figure 7-5: HTML code for the basic form shown in Figure 7-4 Text Fields As you can see in Figure 7-4, the HTML in Figure 7-5 draws two text boxes on the screen. A visitor to your site can click inside the text boxes and type a name and age. Notice that the form is constructed of normal HTML. Like most HTML, the form must go between the and tags. The form begins with a
tag and ends with a
tag (X and [). Between the
tags you’ll see the elements of the form (Y and Z), the parts that hold information. In this chapter, you’ll encounter a variety of different form elements, each with special characteristics. The elements in Y and Z are called text fields. These allow the user to type a line of text in a field. Later you’ll learn how JavaScript reads the user’s typed input. The part of Y and Z that tells the browser to draw a text field is the tag: The tag tells the browser to create an input field of type text. You can embellish the text field a bit—for example, you can make the text box bigger by setting its size: The size of the text field is roughly equal to the number of characters that can fit inside the field. You can also tell the browser to place some words in the text box. For example, if you want the words Type your name here to appear inside the text box, enter this: By setting the value of the text box, you determine what goes inside it. Remember the term value—it will come in handy later. Buttons, Checkboxes, and Radio Buttons In addition to text fields, you can put buttons, checkboxes, and radio buttons in your forms. Figure 7-6 shows you what each of these elements looks like, and Figure 7-7 shows you the HTML used to draw Figure 7-6. 102 Chapter 7 Figure 7-6: A checkbox, radio buttons, and a button The Checkbox The code in X of Figure 7-7 shows you the HTML for a single checkbox. If you want the box checked by default in the above example, put the word checked inside the element tag, like this: You’ll encounter the word checked again, so remember it. X Y Z [ \ ] Checkboxes, Radio Buttons, and Buttons

Tell me about your dog

Name:

Would you like your dog to get our daily newsletter?

yes

How old is your dog?
between 0 and 1 years
between 1 and 3 years
between 3 and 7 years
older than 7 years

Figure 7-7: The HTML for a checkbox, radio buttons, and a button Provi ding and Receivi ng Information with F orms 103 The Radio Button The next type of input element is the radio button. Radio buttons differ from checkboxes in that they’re meant to come in groups of mutually exclusive radio buttons. Since a dog cannot be between 0 and 1 and between 1 and 3 years old, a group of radio buttons is a good way to input the dog’s age range. The way to put radio buttons into a group is to give them all the same name attribute. In Figure 7-7 I’ve given the radio buttons the same name (Y through \) so that a visitor can only choose one of them. Because all these buttons share the name age, you can only turn on one at a time. For example, if the visitor chooses the first radio button and then the third one, that action deselects the first radio button. If you want the page to open with a radio button already chosen, use the word checked, just as with checkboxes: The Button The final type of input element demonstrated in Figure 7-7 is the button: input type = "button" This input type creates a rectangular button. If you want some words to appear inside the button, set the button’s value as in ]. Right now the button doesn’t perform any function, but soon we’ll learn how to attach an action to it. Select Elements All the form elements we’ve discussed so far are input elements. The next two elements, pull-down menus and scrolling lists, have a slightly different format. Figure 7-8 shows what these elements look like, and Figure 7-9 shows the HTML used to write that page. Figure 7-8: A pull-down menu and a scrolling list Pull-down menus start with a tag (Z). An The main difference between scrolling lists and pull-down menus is that scrolling lists have size set inside the tag, like this: tags appears inside the textarea when the browser renders the page. You can control the size of the textarea by setting its rows and columns. As with the text box, these numbers roughly reflect the number of characters a visitor can enter in the textarea: The rows number controls the textarea’s height, and cols controls the width. A Textarea
Figure 7-11: The HTML for a textarea Final Form Comments This section has covered much of what you need to know about writing HTML forms for the purpose of this book. You’ll find other details about forms in any good HTML manual. 106 Chapter 7 Forms and JavaScript Once you have a form on your web page, you can use JavaScript to read information from that form and display information in it. The mortgage monthly payment calculator, for example, reads the principal, interest rate, and other information the user types into the form, calculates a monthly payment based on this information, and then writes the result to the form. Naming Form Elements Before you can read from or write to an element of your form, you need to tell JavaScript which form element you’re talking about by naming your form and its elements. The code in Figure 7-12 demonstrates how to name forms (X) and their elements (Y and Z). Notice that you can’t name the Figure 7-27: Using pull-down menus as navigation tools 118 Chapter 7 One Last Forms Shortcut Sometimes you just want to find out whether a given radio button has been selected. As we’ve seen, you can do that with a line like this: if (window.document.radio_button_form.age[0].checked == true) { alert("The first radio button was selected!"); } This line is pretty long. It can be shortened if you add an id attribute to your form elements—like so: 0 to 1
1 to 3
3 to 7
The contents of the id attribute can be whatever you want, as long as you don’t give two elements the same id. Once you’ve given each of your form elements an id, you can refer to an element by its id using the method getElementById(): var myElement = window.document.getElementById("age1"); if (myElement.checked == true) { alert("The first radio button was selected!"); } Or, more concisely: if (document.getElementById("age1").checked == true) { alert("The first radio button was selected!"); } The id attribute can go into any HTML element, not just forms. If an tag has an id, it can be referenced using the same getElementById() method. Some people prefer getElementById() over using the names of the elements, as I’ve been doing in the rest of the book, and there are good reasons to use it. First, you can access a form element without knowing which form the element is in. This can be handy if you have many forms on a page. Second, getElementById() is the only way to manipulate certain parts of HTML. This will come up in Chapter 13, where you’ll learn about Dynamic HTML. I prefer to use element names rather than id attributes because of the frequent need to integrate JavaScript with CGI scripts (see Chapter 11). Websites often send the contents of forms to server-side programs that do things like adding information to a database or sending email to site users. These programs rely on the names of the form elements, rather than their id attributes. To get full functionality from web forms, you need to give the Provi ding and Receivi ng Information with F orms 119 elements names. And since you have to give the elements names anyway, you may as well use the names when manipulating the forms with JavaScript. As you study other people’s JavaScripts, you’ll see both names and ids being used. They are equally valid, and which one you use will depend on the situation and your preferences. How the Doctors Without Borders Pull-Down Navigation Tool Works The Doctors Without Borders pull-down navigation code is very similar to the JavaScript you saw in Figure 7-27. Figure 7-28 shows you their code, modified to save space: Figure 7-28: Code for the Doctors Without Borders pull-down navigation tool The only big difference between the code in Figure 7-27 and the Doctors Without Borders code in Figure 7-28 is the if-then clause starting in X. This extra test is necessary because the first option in their pull-down contains no value—it’s just a header. If a visitor selects an option with no value, the value property of the select is set to "". So X in Figure 7-28 checks to see whether the visitor selected the first option of the list. If so, the function does not send the visitor anywhere. Summary We covered a lot of ground in this chapter. If you missed any item in the following list, go back and take another look. You should now know: 120 Chapter 7 z How to write HTML forms z How to read information entered into a form z How to write your own content to a form z How to trigger functions from all the form elements z How to use the word this as a shortcut z How to use the id attribute and the getElementById() method to access HTML elements Most form hassles involve the various form elements. Take a look at Appendix C for a complete review of what kinds of events the different elements trigger and what information your JavaScript can discover from them. Assignment Write a clock that tells the time in San Francisco, New York, London, and Tokyo. The clock should have a text field for the time, a button to update the clock, and four radio buttons, each for a different time zone. When you click one of the radio buttons, the correct time should appear in the text field. When you click the update button, the clock should update with the time from the zone you’ve selected with the radio buttons. Figure 7-29 shows an example. Figure 7-29: Updating the time for different cities First you’ll need some information about looking up time. Remember from Chapter 2 how to get the current hour: var now = new Date(); var the_hour = now.getHours(); The Date object has a few methods that come in handy for dealing with different time zones. In this case, use getUTCHours(), getUTCMinutes(), and getUTCSeconds(). These methods tell you the hour, minutes, and seconds in Coordinated Universal Time (UTC), which has replaced Greenwich Mean Time as the world standard. London time is the same as UTC time. New York time is five hours behind London time, California time is eight hours behind London time, and Tokyo time is nine hours ahead of London time. As always, the answer is in Appendix A, but you’ll learn a lot more if you give the assignment a good try before looking there. It’s not an easy assignment, so don’t be surprised if it takes longer than an hour to get it exactly right. Provi ding and Receivi ng Information with F orms 121 KEEPING TRACK OF INFORMATION WITH ARRAYS AND LOOPS The last chapter showed you how JavaScript stores radio buttons and pull-down menu options in lists. In programmer’s parlance, lists are called arrays. This chapter will teach you how to create your own arrays and use them to keep track of large amounts of information. In this chapter, you’ll learn how to: z Use JavaScript’s built-in arrays to control your HTML z Create new arrays of your own information z Use loops to search through arrays for information Real-World Examples of Arrays JavaScript’s built-in arrays are useful in a wide variety of applications. One of the sites I work on, http://www.antweb.org, uses JavaScript’s built-in arrays to show users which species of ants live in various counties in the San Francisco Bay Area (see Figure 8-1). At the bottom of the list of counties is a Select All checkbox. Clicking this box causes all the other checkboxes to become checked. This trick is easy to script because the checkboxes are stored in an array, allowing me to use JavaScript to check off each one. Browse to http://www.bookofjavascript.com/Websites/AntWeb to see this in action. Figure 8-1: AntWeb checkboxes Creating your own arrays can be useful as well. The Book of JavaScript website employs arrays to show visitors a series of JavaScript programming tips. In the textarea in Figure 8-2, you’ll see one of a dozen programming tips that rotate through this box. I store these tips in a JavaScript array and rotate through the array to put different tips into the textarea. The same principle applies to making a timed slide show, which we’ll see in the next chapter. Figure 8-2: Rotating programming tips on the Book of JavaScript home page JavaScript’s Built-In Arrays When a web browser reads an HTML page, it automatically creates a number of arrays. In the previous chapter we saw that JavaScript creates an array for each set of radio buttons with the same name. If you create a set of radio buttons named age inside a form named the_form, you can refer to the first radio button in the set like this: window.document.the_form.age[0] 124 Chapter 8 JavaScript also creates an array for the options in each pull-down menu and scrollable list. Here’s how you could access the second option in a pulldown menu named gender: window.document.the_form.gender.options[1] These are just two of JavaScript’s automatically created arrays. Browsers also automatically create an array of all the image objects on a web page, called images. The same holds true for form elements (the array of form elements is called elements). In Figure 8-3 (part of the Document Object Model), you can see which elements (the boxes with the words array of in them) get automatically created arrays. THE CURRENT WINDOW self, window, parent, top various Window objects navigator Navigator object frames[] array of Window objects plugins[] mimeType[] array of Plugin objects MimeType objects array of mimeTypes[] array of MimeType objects forms[] location Location object array of Form objects history History object anchors[] JavaObject objects array of HTML Form element objects: Button Checkbox FileUpload Hidden Password Radio Reset Select Submit Text Textarea embeds[] options[] array of JavaObject objects Option objects array of Anchor objects document Document object Package JavaPackage object elements[] images[] array of Image objects applets[] array of array of Figure 8-3: Part of the DOM showing arrays in the document object Each of these arrays is built based on how the page’s creator has written its HTML. In the images array, for example, the first image on a web page is called images[0], the second is images[1], and so on. If you use the images array, you don’t have to name your images to swap them (as in “Swapping Images” on page 58). For example, you can swap the first image on a web page with an image called happy.gif with this line: window.document.images[0].src = 'happy.gif'; Ke e p i n g T r a c k o f I n f or m a t io n w it h A r ra y s a n d L o o ps 125 Why would you want to use built-in arrays instead of just naming HTML elements? Sometimes you have no choice. As we saw in Chapter 7, because all the radio buttons in a set have the same name, you can access them only using the built-in array. Built-in arrays are also useful when you have many elements on a page. If you have a web page with 100 images, naming them all becomes tedious. Instead, you can just refer to each image by its number (for a set of 100 images, the numbers would be 0 to 99). The best thing about arrays, however, is that a little bit of JavaScript can act on each element in the array—a great time-saving feature if you have a 100-element array. In the AntWeb example, clicking one checkbox (Select All) checks all the individual county checkboxes. It doesn’t matter whether you have a lone checkbox or a thousand of them—the code is the same. To control an entire array as the AntWeb script does, your code needs to determine how many elements the array contains and then go through each element in the array, performing whatever action you want on it. AntWeb, for example, figures out how many checkboxes there are and then checks each one. Figuring Out How Many Items an Array Contains In all modern JavaScript-enabled browsers, an array’s length property contains the number of elements in an array. For example, the script in Figure 8-4 figures out how many images a web page holds. Figure 8-4: How many images a web page contains Drop this JavaScript into the bottom of a web page with images, and you’ll see how it works. The critical line is X, which tells JavaScript to create a variable called num_images and set it to the number of images in the built-in images array. If the page has 10 images, num_images will equal 10. Going Through Arrays Once you know how many elements are in an array, you need to write some code that goes through each element. If you have a list of four checkboxes and want to check them all, you could write a script like Figure 8-5. Checking Four Checkboxes 126 Chapter 8
One
Two
Three
Four
true; true; true; true; = "checkFour();">
Figure 8-5: Checking four checkboxes The checkFour() function in this script goes through each of the four checkboxes and sets its checked property to true (see the result in Figure 8-6). But this code is not the best solution, since it only works for four checkboxes. To work with five checkboxes, you’d have to add another line Figure 8-6: The checkboxes checked to the function. With 1,000 checkboxes the function would end up 1,000 lines long, each line identical to the one before it except for the number between brackets. Writing this would be very tedious. Worse, sometimes, when a page is dynamically generated (see Chapter 13), you don’t know how many checkboxes will appear on a page. In this case, it would be impossible to write a function like the one in Figure 8-5. You can avoid both these problems with a loop. A loop allows you to execute the same JavaScript statements multiple times with slight variations. For example, a loop could execute the following line 1,000 times, changing the number in the brackets each time. window.document.the_form.elements[0].checked = true; Ke e p i n g T r a c k o f I n f or m a t io n w it h A r ra y s a n d L o o ps 127 while Loops One kind of loop is called a while loop. In plain English, this translates to “While such-and-such is true, do the following.” Figure 8-7 shows a while loop that prints the word happy three times. X Y Z [ \ ] ^ I'm Happy and I Know It I'm
and I know it! Figure 8-7: Printing the word happy three times with a while loop Loops are a very common programming technique. They may seem strange the first couple of times you see them, but they are so common that after a while you’ll understand them on sight. The typical while loop starts with a variable set to zero, as in X of Figure 8-7. The variable index is just like any other variable. Once you’ve set this variable, the while loop begins. Line Y reads, “While the variable index is less than three, execute the JavaScript between the curly brackets (Z and ]).” The format of this line is important. The word while must be lowercase, and the Boolean test index < 3 must fall between parentheses. When JavaScript sees Y, it checks whether the variable index has a value less than 3. If so, the script runs the lines between the curly brackets Z and ]. When we start, index is 0, which is less than 3, so the script executes the two lines between Z and ]. Line [ writes the word happy to the web page, and \ adds one to index, changing it from 0 to 1. Once we execute \ and reach the curly bracket in ], JavaScript jumps back to Y to see if index is still less than three. This is the nature of the while loop. Every time JavaScript reaches a loop’s closing curly bracket (]), it jumps back to the beginning of the loop (Y) to see whether the test in the parentheses is still true. Because 1 is less than 3, JavaScript executes [, which prints happy again; it then executes \, adding 1 to index (which now has a value of 2). 128 Chapter 8 Again, because we’re in a while loop, JavaScript jumps from ] to Y and checks to see whether index is still less than 3. It is, so [ and \ execute again. The word happy appears a third time, and the script increments index from 2 to 3. Once again, JavaScript jumps from ] to Y and checks to see whether index is less than 3. This time, however, index is equal to 3, so the test (index < 3) is not true. The while loop stops and JavaScript jumps to ^, the line after the closing curly bracket. Many people have a hard time with looping, so make sure you understand how it works. You may find it helpful to translate Y into plain English: “While index is less than 3, write happy and add 1 to index.” while Loops and Arrays Now that you know how while loops work, you can apply them to arrays. Look back at the function in Figure 8-5, and notice that each of the four lines is more or less the same: window.document.the_form.elements[some_number].checked = true; The only difference is the number between the square brackets. Now think about the variable index in Figure 8-7. Its value increases by 1 each time the script goes through the loop. This feature makes the index variable ideal for accessing each element in an array. Figure 8-8 uses index to create a more flexible version of Figure 8-5. X Y Z [ \ ] ^ Checking Four Checkboxes One
Two
Three
Four

Ke e p i n g T r a c k o f I n f or m a t io n w it h A r ra y s a n d L o o ps 129
Figure 8-8: Using a loop to check four checkboxes The critical line is [, which says, “Set form element number index to true.” The first time through the loop, index is 0, so [ checks the first form element (the first checkbox). Then \ adds 1 to index, changing index from 0 to 1. JavaScript reaches ] and jumps back to Y, executes [ and \ because index is less than 4, and repeats the process until index equals 4. When index equals 4 and JavaScript jumps to Y, the while loop ends (because index is no longer less than 4) and JavaScript jumps to ^, the line after the closing curly bracket. Combining while loops and arrays is extremely common, so make sure you comprehend the process. The advantage of this kind of code is that it works whether you have just a few checkboxes or a few thousand. To get the code to work for, say, 4,000 checkboxes, you would just change the number in Y from 4 to 4,000. The loop will then run 4,000 times, starting with 0 and finally ending when index equals 4,000. Going Off the Deep End The script in Figure 8-8 looks at the values of form elements 0 through 3, which are the four checkboxes at the start of the form. The next form element in the figure is the button. All input elements have a checked value, although it doesn’t really do anything for a button, so window.document.the_form.elements[4].checked will always be false. But what about this: window.document.the_form.elements[5].checked Here, we’re asking JavaScript to look at the checked value of whatever is stored in the sixth spot in the elements array. Sadly, there’s nothing there; there are only five elements in this form, so JavaScript will respond with the special word undefined. Then, when you ask JavaScript to find the checked value of this undefined thing, it gets confused and you get a JavaScript error. You can prevent this kind of error by making sure that the values stored in the array are defined, like this: if (window.document.the_form.elements[5] != undefined) { var checked_value = window.document.the_form.elements[5].checked; } Notice that there are no quotes around the word undefined. It’s a special word like true and false. 130 Chapter 8 Using array.length in Your Loop The code in Figure 8-8 works well, but it could use one improvement. In general, it’s best to have as few literal numbers in your code as possible: Using specific numbers tends to make code apply only in specific situations. In Figure 8-8, for example, Y works only when exactly four checkboxes appear on the page. If you add another checkbox to the web page, you’ll have to remember to change the 4 in Y to 5. Rather than rely on your memory, you should let the computer do the remembering. You can rewrite Y like this: while (index < window.document.the_form.elements.length) The expression window.document.the_form.elements.length always equals the number of form elements on a page, since adding another checkbox automatically increases the length of the elements array. An Incremental Shortcut Lines like \ in Figure 8-8 are used so frequently that programmers have come up with the shorthand index++ to replace index = index + 1. That’s the variable index followed by two plus signs (++), and it saves you the hassle of typing index twice. We’ll be seeing many other shortcuts like this later. Beware of Infinite Loops You should avoid one common loop mistake like the plague. It’s so common that it has a name: the infinite loop. Infinite loops happen when your code enters a loop it can never exit. Figure 8-9 shows you the classic error. var index = 0; while (index < 10) { window.document.write("I am infinite!
"); } Figure 8-9: The classic infinite loop—don’t try this at home Running this script will make you sad, so please don’t try it. If you do run it, the script will endlessly write I am infinite! to the page. To stop the script from running, you’d have to quit the browser, which isn’t always easy when you’re stuck in an infinite loop. This loop is infinite because I forgot to add 1 to index after writing “I am infinite!” The index variable starts at 0 and never changes, so index < 10 is always true. Since the test while (index < 10) is always true, the loop continues until you exit the browser. The only way to avoid accidentally writing an infinite loop is to exercise caution. Whenever you write a loop, make sure the loop will exit at some point. Ke e p i n g T r a c k o f I n f or m a t io n w it h A r ra y s a n d L o o ps 131 for Loops Another type of loop is the for loop. You format while and for loops differently, but they do the same things. Which loop you use is largely a matter of preference. Though for loops look a little more confusing at first, they are more compact. Figure 8-10 compares a while loop and a for loop that perform exactly the same task. // while loop X var index = 0; Y while (index < 10) { window.document.writeln("hello
"); Z index++; } // for loop [ for (var index = 0; index < 10; index++) { window.document.writeln("hello
"); } Figure 8-10: Comparing a while loop and a for loop Both of the loops in Figure 8-10 write the word hello to a web page ten times. The main difference between them is that X, Y, and Z in the while loop collapse into [ in the for loop. The format of a for loop is as follows: for (initializer; test; incrementer) { // some JavaScript } All for loops start with the word for, followed by parentheses containing three pieces of JavaScript, separated by semicolons. The first piece is a statement that is said to initialize the loop. Usually this statement declares an index variable and sets it to the starting number. In [ of Figure 8-10, the initializer of the for loop is var index = 0 (the same as X in the while loop). The second parameter of a for loop is the test, which, if true, means that the loop will execute one more time and then test again. In [ of Figure 8-10, the test is index < 10 (the same as Y in the while loop). The final piece is the incrementer, a statement that changes the condition each time the loop repeats, usually by adding a number to the index variable (like Z in the while loop). Whether you use while loops or for loops is a matter of taste. You can write for loops in fewer lines, but while loops are a bit easier to read. Some people prefer for loops because they lower the risk of accidentally getting into an infinite loop. In a while loop, you can easily neglect to put index++ inside the curly brackets. In a for loop, it’s hard to forget to put this element inside the parentheses because you always have three expressions there. 132 Chapter 8 How AntWeb Checks Off All the Checkboxes Figure 8-11 shows a stripped-down version of how AntWeb uses loops to check off all the checkboxes when a visitor clicks Select All. I’ve taken out AntWeb’s HTML formatting, along with the repetitive code for several of the counties, but the checkAll() function is exactly the same as AntWeb’s. To see the complete AntWeb page in all its formatting glory, browse to http://www.bookofjavascript.com/Websites/AntWeb. X Y Z [ \ ] ^ _ AntWeb's Use of Arrays and Loops
Alameda
Contra Costa
Marin
Select All
} Figure 8-11: AntWeb’s use of arrays and loops Line-by-Line Analysis of Figure 8-11 The first few lines in Figure 8-11 describe the form that contains the checkboxes. Line X names the form bayAreaSearchForm, and Y and the two lines after it describe each of the checkboxes. Line Z describes the checkbox that causes the other checkboxes to become checked. This checkbox is named selectall; clicking it calls the function selectAll(), which starts in [. Notice in Z that when the function is called, the name of the form to act on is passed to the function. In [, that form is named thisForm inside the function. The nice thing about this is that the selectAll function will work on any page, and for any form. You just need to pass the form into the function, as is Ke e p i n g T r a c k o f I n f or m a t io n w it h A r ra y s a n d L o o ps 133 done when the function is called in Z. Line \, the first line in the function’s body, stores the number of elements in the form into a variable named count. There are four elements in this form—the three county checkboxes and the Select All checkbox—so count will be 4. Line ] stores the checked value of the selectall checkbox: either true, if the checkbox was just checked, or false, if it was unchecked. The real fun begins with the loop, starting in ^. The first time through the loop, the variable named loop will have a value of 0, so thisForm.counties[loop] in _ will point to the first element in the bayAreaSearch form—the first checkbox. The second time through the loop, the value of loop will be 1, so thisForm.counties[loop] will point to the second checkbox. The loop occurs four times, once for each checkbox. You may be thinking that testing the fourth checkbox is a bit unnecessary, and you would be correct. The fourth time through the loop, the script is just setting the fourth checkbox to checkVal, which already stores the value of the fourth checkbox. Hence, the script is just setting the value of the fourth checkbox to whatever the value already is. If I wanted to avoid this unnecessary step, I could have changed the loop to this: X for (var loop = 0; loop < count; loop++) { if (thisForm.counties[loop].name != 'selectAll') { thisForm.counties[loop].checked = checkedVal; } } Here, X looks at the name of the checkbox. If it is anything other than 'selectAll', the JavaScript will change the checked value of the checkbox. I decided to leave that out because the unnecessary effort taken by JavaScript to change the checked value of a checkbox is less than the effort that would be required to examine the name of a checkbox and see whether it is selectAll each time through the script. With the types of tasks JavaScript is generally used for, efficiency decisions like this don’t really save very much time. However, if you notice that your script is taking a long time to run, make sure code inside your loops does not take too long. Slow code that runs once in a script isn’t too bad. Slow code that runs 1,000 times because it’s in a loop might slow things down noticeably. Creating Your Own Arrays Arrays are so handy that you’ll often want to create your own. A phone book, for example, is an array of names and phone numbers. You can think of a survey as an array of questions; an array can also store the answers a visitor enters. A slide show is an array of pictures shown in sequence. Happily, JavaScript lets you create your own arrays. If you know what you want to store in the array when you create it, use a line like the following: var rainbow_colors = new Array("red", "orange", "yellow", "green", "blue", "indigo", "violet"); 134 Chapter 8 This line creates a variable called rainbow_colors that stores an array of colors. The words new Array() tell JavaScript to create a new Array object, just as new Date() created a new Date object back in Chapter 2. To put values in your new array, simply list them in the parentheses. Everything you’ve learned about JavaScript’s built-in arrays also applies to arrays you create yourself. Figure 8-12 uses the rainbow_colors array to create a psychedelic strobe effect on a web page. X Y Z [ Strobe
Figure 8-12: A psychedelic strobe effect Line-by-Line Analysis of Figure 8-12 Line X in Figure 8-12 creates the array and Y sets up the loop, saying, “While index is less than the number of items in the array, execute the JavaScript between the curly brackets.” The first time through the loop, index is 0, so when Z looks up rainbow_colors[index], it gets the first item in the array, the value red. Line Z assigns this value to window.document.bgColor, which sets the background color to red. Once the script has set this color, [ adds 1 to index, and the loop begins again. Next time through, index will be 1, so Z will make the background color orange, [ then adds 1 to index, making it 2, and back through the loop we go. If you have a very fast computer, the background may strobe too quickly for you to see it. In this case, add a few more colors to the array in X. Ke e p i n g T r a c k o f I n f or m a t io n w it h A r ra y s a n d L o o ps 135 How the Book of JavaScript Tip Box Works The Book of JavaScript website has a little textarea that shows various programming tips. The script keeps these tips in an array and then uses JavaScript to loop through the array, showing one tip at a time. Each tip stays in the textarea for 3.5 seconds before the next one appears. I should confess that I got the idea for this tip box from something that the search engine Ask.com (http://www.ask.com, formerly known as Ask Jeeves) once had on its home page. In fact, I will present two different versions of the code. The first version, shown in Figure 8-13, is very similar to the code Ask.com originally used. The second version, which you’ll see in Figure 8-14, is a bit simpler (though not necessarily better). The code in Figure 8-13 is similar to code from Ask.com and contains many little tricks that I haven’t yet covered. It starts out simply enough with X, which says, “After the page has loaded, call the function startScroll().” The first line in the JavaScript tags, Y, creates an array called tips and loads it with a bunch of familiar programming adages. Line Z creates a variable called num_tips and sets it equal to the number of tips in the tips array. X Y Z [ \ ] ^ _ ` a 136 Chapter 8 Arrays and Loops a la Ask.com
Figure 8-13: Ask.com-style use of arrays and loops Checking for Blank Statements The next couple of lines exhibit “paranoid” programming style. Paranoid programmers make sure everything is perfect before they execute a line of code that’s going to affect the user experience. Line [ and the line following it, for example, make sure no blank statements (two quotation marks with nothing between them) appear at the end of the tips array. Who knows why that would happen—but just in case, [ checks the last element in the array. If it’s not blank, the loop ends. If it is blank, the line below it executes, reducing num_tips by 1. The loop then checks to see whether the second to last element is blank. If it’s not, the loop ends. If it is, that line runs again, reducing num_tips by 1 once more. Notice that you can subtract one from a variable with the syntax variable_name--. You can also use ++variable_name and --variable_name as shown. Checking the Last Element in the Array You might be wondering how [ checks the last element of the array. Remember, num_tips equals the number of items in the array. If the array has three items, num_tips equals three. However, because the first element in the array is zero, the last element in an array will be two—the length of the array minus one. To look at the last element of an array, use the following line: var last_element = the_array[the_array.length - 1]; If the array contains three elements, the_array.length equals 3, and the_array.length minus 1 equals 2, which is the number JavaScript uses to reference the last element in the array. You may be thinking, “There’s no way I’d ever figure that out!” But don’t worry—this kind of array mathematics becomes second nature after you’ve done it a few times. Testing the Limits of Arrays You may have noticed that before [ checks to see whether the last element in the array is a blank string, it makes sure there is at least one tip in the array. If there are no elements in the array, num_tips will equal 0. If that’s the case, then the second part of the while loop would be checking to see whether tips[0 – 1] == "", or doing the math, tips[-1]. Because arrays start at 0, there will never be a value in position -1, so there’s really no reason to check what’s in that position. When you have two parts to a test that contains and, both parts must be true for the whole thing to be true. JavaScript is smart enough Ke e p i n g T r a c k o f I n f or m a t io n w it h A r ra y s a n d L o o ps 137 to not bother checking the second part of a test with an and if the first part is false. Why bother testing the second part if it already knows the whole thing will be false? The startScroll() Function In the startScroll() function, we find more programming paranoia. Line \ checks to see whether the variable count actually has a setting. If not, its value is the special word null. Line ] exhibits even more paranoia. Ask.com makes sure the form named rotate has been drawn to the page by checking to see whether the form named document.tip_form exists. If it does not exist, document.tip_form is false, and the lines between the brackets of the if-then statement won’t execute. I have never encountered any browsers that support JavaScript but not forms. If they’re out there, however, ] makes sure JavaScript won’t try to write to a form that doesn’t exist. Line ^ looks up a tip in the array and writes it into the textarea. This line tells JavaScript to find the form named tip_form and the form element named tip_box and sets its value to whatever appears on the right side of the equal sign. The latter requires some explanation. Instead of just looking up the value of element index in the text array and then adding 1 to index, as in document.tip_form.tip_box.value = tips[index]; index++; line ^ looks up the value of element index and adds 1 to index right there: document.tip_form.tip_box.value = tips[index++]; This is legal and saves some space, but it’s a little hard to read. Going back to the notation introduced earlier, if Ask.com had done this, document.tip_form.tip_box.value = tips[++index]; putting the plus signs in front of index, the JavaScript would add 1 to index and then look for the value of tips[index]. It’s the same as this line: index++; document.tip_form.tip_box.value = tips[index]; It’s rare to see people messing around with the location of the double plus and minus operators. But if you run into this while looking at source code, you’ll know what’s going on. The next two lines, _ and `, are important for any program that continuously loops through an array. The JavaScript writes a tip in the textarea, then moves on to the next tip in the array, until it runs out of tips. Once that happens, the program should return to the first question in the array and start all over. Lines _ and ` make this happen. Line _ determines whether the last question has appeared. If the variable index is more than num_tips - 1, 138 Chapter 8 we’ve reached the end of the array. Remember, Z set num_tips to the length of the array, so num_tips - 1 is the position of the array’s last element. If index is greater than num_tips - 1, we’ve reached the array’s end, and ` executes. It sets the variable index back to 0, so the next time the script puts tips[index] into the textarea, index will indicate the first question in the array. Finally, a determines how fast the questions change in the textarea. The next chapter will talk more about how the code in a works. For now, you just need to know that it translates as, “In 3.5 seconds, call the function startScroll() again.” Each time the script calls startScroll(), the function puts a new question in the textarea and increments index by 1. A Streamlined Version The code in Figure 8-13 is a bit confusing. Figure 8-14 shows you a streamlined version that still works under most conditions. Although the code in this version is more streamlined, it’s not necessarily better. Paranoia is a good thing in programming. The more checks you put in, the less likely your visitors are to encounter a JavaScript error. Given the choice between the approaches demonstrated in Figures 8-13 and 8-14, I’d recommend the former because it’s more robust. The code in Figure 8-14 is merely easier to understand. Arrays and Loops
Figure 13-18: Demonstrating keyboard events Although the script in Figure 13-18 is simple, there are some subtleties. First, whenever a user types anything while in the text field, the act of pressing the key down creates one event, and the act of releasing the key creates another event. These events are captured by the event handlers in \. In either case, the displayEvent() function is called. This function creates variables for each of the event’s properties, combines them into a string, and then puts the Dynami c HTML 251 resulting string into the textarea with the id of showEvents. The most interesting lines in this function are X, which gets a number representing the character being pressed, and Y, which converts that number into an actual character. After those lines are executed, Z creates a string representing what happened in the event and [ puts that string in the text area if the key being pressed is a letter (letters have character code numbers between 65 and 90). Figure 13-19 shows what happens when a and then A are typed into the text field. Notice that in both cases, the characterCode is 65, and the resulting character is A. In order to determine whether the user has entered a capital or lowercase letter, the shiftKey property of the event must be examined. Figure 13-19: Typing a and A into the Figure 13-18 script Mouse Events Mouse events have their own properties. Unfortunately, some cross-browser differences complicate accessing the position of the mouse and determining which mouse button was clicked. Table 13-3 shows the properties of mouse events, and it gives some details about how to deal with cross-browser differences. Table 13-3: Properties of Mouse Events 252 Chapter 13 Property Description button Equals 2 if it’s a right-click—otherwise, it depends on the browser clientX Internet Explorer’s X position for the mouse clientY Internet Explorer’s Y position for the mouse pageX Most other browsers’ X position for the mouse pageY Most other browsers’ Y position for the mouse As you can see from Table 13-3, all the properties of mouse events are browser dependent. The button property, for example, describes which button was clicked when an onMouseDown or onMouseUp event happened. However, the meaning of the numbers provided by the button property depend on the browser being used. In Internet Explorer, 1 means the left button was clicked, 2 means the right button, and 4 means the middle button. In most other browsers, 0 means the left button, 1 means the middle button, and 2 means the right button. Because 2 means the right button was clicked in both cases and many people don’t have a middle button on their mouse, it is often safe to see if the button property of the event was 2 and call it a left-click if it was not. The position of the mouse is a bit trickier. Browsers other than Internet Explorer generally use an event’s pageX and pageY properties to give a number representing the X and Y positions (in pixels) of the event relative to the top-left corner of the browser window. These two properties take into consideration scrolling a window. If a window is 10,000 pixels long and the user has scrolled down to the very bottom, the pageY property will be around 10,000 at the bottom of the window. Internet Explorer, on the other hand, uses properties named clientX and clientY. These properties do not take scrolling into consideration, so to use them, you should add numbers representing how far down and to the left the browser has been scrolled. Those numbers are available as document.body.scrollTop and document.body.scrollLeft. Figure 13-20 presents a script that determines the X and Y positions of a mouse and puts the results in a textarea. X Y Z [ \ ] ^ Checking Mouse Position
Figure 13-20: Detecting the position of the mouse Dynami c HTML 253 In Figure 13-20, moving inside the div calls the displayEvent() function (]), and moving the mouse onto the div clears the textarea that stores all the mouse information collected (^). The displayEvent() function first checks to see if the browser knows about the pageX property of the event (X). If so it uses pageX to get the x coordinate of the mouse, relative to the top-left corner of the browser window (Y) and pageY to get the y coordinate. If the browser does not know about the pageX property but does know about the clientX property (Z), it uses clientX and clientY. Notice in [ that the amount that the browser has been scrolled to the right or down must be added to the clientX and clientY property to account for scrolled windows. The last line in the function (\) adds the appropriate information to the textarea with the id of results. Adding Event Handlers Using JavaScript Throughout this book, whenever we have wanted to trigger an event based on a user’s behavior, we have put an event handler inside the triggering element. For example, in Chapter 4, when we wanted an alert box to pop up when a user clicked a link, we put an onClick event inside the link: Click me Putting event handlers inside the elements that trigger the events can cause some problems: z Doing so puts JavaScript inside your HTML elements rather than inside ^
_

Figure 13-21: Cross-browser script for attaching functions to event handlers The script in Figure 13-21 creates a set of six checkboxes, each with a different name. Clicking any of these checkboxes results in an alert box providing the name of the checkbox that was just clicked. Notice that the HTML describing the checkboxes contains no onClick handlers (_). This is because the handlers are assigned using JavaScript. The onLoad handler inside the tag (^) triggers the function which assigns the handlers. The function is called by the onLoad handler because an HTML element cannot have a function attached to its handler until the web browser knows about the element. If a piece of JavaScript tries to attach a handler to a form element that has not yet been processed by the browser, an error will result. For this reason, it’s best to wait until all the elements have been loaded before assigning functions to their handlers. The attachHandlers() function has several interesting aspects. First, it uses the DOM methods covered earlier in the chapter to access the checkboxes. These checkboxes are child elements of the form element, and so they are accessible as the childNodes of the form (X). The childNodes property returns an array, which is then looped through. Each time through the loop, the JavaScript checks the next element in the array to see if it is an input element. Notice that both the strings INPUT and input are checked. This is because some 256 Chapter 13 browsers capitalize element names and other browsers don’t. For each input element found, Z attaches the doAlert() function to the element’s onclick handler. Once the handlers have been attached, the page waits until a checkbox is clicked. When that happens, the onclick event is triggered, and the doAlert() function is called. Notice that the definition of doAlert() contains a parameter ([). In Firefox and most other browsers, this parameter will be filled with an event object that contains information about the event that caused the doAlert() function to be called. If that parameter is not filled in, it means the user is most likely using Internet Explorer. In this case, \ is true. The evt variable is set to the Internet Explorer variable event, and thisBox is set to the checkbox that was clicked using Internet Explorer’s srcElement property. If Firefox, or some other browser was used instead, the function’s evt parameter would already contain the event object, and we’d only need to set thisBox to the checkbox that was clicked by accessing the target property (]). One final note about assigning functions to event handlers using JavaScript: If for some reason you want to remove an event handler from an object, simply set the handler’s value to null. Here’s an example: document.getElementById("myDiv").onclick = null; Drop-Down Menus I’ll close this chapter by showing how to build a basic drop-down menu with DHTML. The menu shown in Figure 13-22 has three links: Dogs, Cats, and Birds. Mousing over Cats causes a submenu to drop down with the names of several cat breeds. Clicking one of those links sends the browser to a web page about that kind of cat. Figure 13-23 shows the code that drives this drop-down menu. I’ve already covered everything you must know to understand this code, so take a look at it, and see if you can figure out how it works before reading my Figure 13-22: A drop-down menu explanation. Drop-Down Menus
Figure 13-23: A basic hierarchical menu 258 Chapter 13 Line-by-Line Analysis of Figure 13-23 A drop-down menu has a div for each menu option. The nine divs in Figure 13-23 include one div for each top-level menu element ([), one for each submenu (]), one for the bottom border, and one for the right border. Each time a visitor mouses over one of the main menu options, only the submenu matching the link most recently moused over is shown. If the visitor mouses over Cats, making the list of cat breeds visible, and then mouses over Dogs, the closeAll() function hides the Cats submenu and changeDiv() displays the Dogs submenu. Mousing over the bottom or right border closes all the submenus. The closeAll() Function The closeAll() function loops through the array of divs defined in X. Each time through the loop in Z, closeAll() calls the changeDiv() function to hide one of the divs. The changeDiv() Function The changeDiv() function takes two parameters: the name of a div to change, and whether to make the div hidden or visible. Line Y changes the visibility of the specified div to visible or hidden, depending on the value of the second parameter of changeDiv(). The Borders The menu’s bottom border is a long transparent (and therefore invisible) GIF (\). The code in \ dictates that mousing over this invisible GIF hides all submenus. This GIF and the blank GIFs on the right of the menus make sure the submenu vanishes if the visitor’s mouse leaves the menu area completely. Figure 13-23 offers a basic example of how you might implement a hierarchical menu. For more complete versions, check out the menu and navigation section of Dynamic Drive’s website. Fortune magazine’s website used this one: http://www.dynamicdrive.com/dynamicindex1/dropmenuindex.htm. Summary DHTML is the topic of several excellent books—what we’ve discussed here should just whet your appetite. But you have learned a few DHTML basics, including the following: z How to use divs to create blocks of HTML z How to add styles to divs z How to make divs, along with the HTML they contain, visible or invisible z How to move divs Dynami c HTML 259 z How to animate divs with timed loops z How to use DOM methods to alter HTML documents z How to read keyboard and mouse events z How to create a basic hierarchical menu If you understood all that, you shouldn’t have any problem with the assignment. Assignment Create a DHTML screensaver like the one shown in Figure 13-24. The smiley face in the figure continually bounces around the screen. When it hits one of the walls, it bounces off at a random angle. To make the smiley face move diagonally, change its top and left positions in a timing loop. To get it to bounce off a wall, make it change directions when it hits one side of the screen. Remember, to make the smiley move right, you would add to its left property, and to make it move left, you would subtract from its left property. Figure 13-24: A screensaver created with JavaScript 260 Chapter 13 AJAX BASICS Ajax (Asynchronous JavaScript and XML) helps create web pages that act like desktop applications. By combining DHTML with the ability to download and display information from a webserver while a user is still interacting with a web page, Ajax puts an end to the old submit-and-wait cycle common to most interactive websites. If you’ve used Google Maps (http://maps.google.com), you’ve seen Ajax in action. There are also Ajax versions of word processors, spreadsheets, and other common applications. Like DHTML, Ajax is a complex topic and is the focus of a number of books. However, with the JavaScript you’ve learned so far, and a few other details, you will be well on your way to becoming a master of Ajax. This chapter introduces Ajax, including: z An overview of Ajax and the technologies it encompasses z The A in Ajax—Asynchronicity—and why you need it z The basic JavaScript you’ll need for Ajax z Browser compatibility issues z Potential pitfalls when using Ajax z When to use Ajax and when to avoid it z How to set up a webserver and write server-side programs that communicate with Ajax This chapter tells only part of the Ajax story. In Chapter 15 you’ll learn about the X in Ajax (which stands for the data transfer standard XML), and how to read and navigate XML documents in JavaScript and use them in Ajax applications. A Real-World Example of Ajax The best-known example of Ajax may be Google Maps (maps.google.com). Figure 14-1 shows you the map which results from searching for the office of No Starch Press. The map is very interactive; you can zoom in, zoom out, and pan around without having to reload the page. A smaller map in the bottomright corner of the main map shows you the larger context of the map you’re viewing. A blue box in the smaller map moves around as you pan across the large map. Figure 14-1: Google Maps The map’s interface can mark places you ask about, such as No Starch Press in Figure 14-1, and show directions between two points. For example, Figure 14-2 shows the route between the office and El Metate, one of my favorite Mexican restaurants in San Francisco. All of this interactivity involves frequent trips to Google’s webservers without the user seeing the page reload. 262 Chapter 14 Figure 14-2: Getting directions with Google Maps Introduction to Ajax The term Ajax was coined by Jesse James Garrett1 to describe a general approach to creating web applications. This approach involves the following steps: 1. An event, such as a user moving the mouse or typing into an input field, triggers one or more simultaneous requests to a webserver for more information. 2. While the webserver is processing the requests, the web browser goes about its business as usual, allowing the user to continue interacting with the web page. 3. The result from each request appears once the webserver has processed that request, and it is used to update the web page using the DHTML techniques you learned in Chapter 13. Figure 14-3 shows how Ajax works and how it differs from the traditional style of communication between web browsers and webservers. In the traditional style of browser-server communication, a user clicks a link or submits a form in a web browser. This causes the browser to send a request for information to a webserver: either the web page named in the href attribute of the link, or the results of a program or script named in the action attribute of the
tag. Once the request is sent, the browser sits idly, usually animating an icon in the upper-right corner of the window, and the user waits for the webserver to respond to the request. Eventually the server responds, and the web page reloads, presenting new information. 1 For Garrett’s original essay on Ajax, see http://adaptivepath.com/publications/essays/ archives/000385.php. Ajax B a si cs 263 Before Ajax After Ajax  User submits form to webserver.  Moving off a text field sends the server a secret message. (...)  User waits while webserver thinks. ! (...)  The server thinks. Meanwhile, the user keeps playing with the page. !  Server done; sends answer back.  Server done; sends answer back. User is still uninterrupted.  Browser page reloads; user can continue.  Page is updated, but doesn’t reload. User has not stopped enjoying the page. Figure 14-3: Ajax versus traditional communications between a web browser and a webserver In the Ajax style, on the other hand, the browser makes a request from the webserver without the user knowing about the request. The icon in the browser’s corner doesn’t spin, and the browser can still be used. When the response comes back from the webserver, the information displayed in the web browser is updated without reloading the page. The entire process occurs without causing a pause in the user’s interactions with the web page. Asynchronicity—The A in Ajax The A in Ajax stands for asynchronous, which in this context means something like non-waiting. In asynchronous communication (the After Ajax part of Figure 14-3), the browser sends a request to a webserver and does not wait for the reply. Many asynchronous requests can be made simultaneously, and the browser deals with the responses as they come from the webserver. In contrast, the traditional style of browser-server communication described in the Before Ajax part of Figure 14-3 is synchronous; that is, the browser submits a request to a webserver and then waits for a reply, unable to send any other requests until the server responds. 264 Chapter 14 An example of asynchronicity can be seen when you download a web page and watch images appearing on the page at different times. The images are requested simultaneously, and the browser displays them as it receives them. While this sort of asynchronicity is built in to all but the oldest web browsers, until recently JavaScript programmers couldn’t control asynchronous communications with webservers. This all changed with the addition of a new JavaScript object called the request object. XML—The X in Ajax The X in Ajax stands for XML. Since the publication of the XML standard in 1998, XML has become the format for sharing structured text-based information between computers. As we will see, browsers have built-in ways for dealing with information that has been formatted as XML documents. This, and the ubiquity of XML documents, makes XML a great format for sharing information between web browsers and webservers. JavaScript—The J in Ajax Ajax uses JavaScript to create requests, send them to webservers, parse the XML results, and update web pages accordingly. The rest of the chapter describes how to use JavaScript to create and send requests, and deal with the asynchronous nature of the requests. Creating and Sending Requests The key to implementing the Ajax-style communication described above is the JavaScript request object, which is built into Internet Explorer 6.0 and later, Firefox 0.8 and later, Opera 7.54 and later, and Safari 1.2.2 and later. Your JavaScript can use this request object to query a webserver for information, store the returned information, and update the page when the server has provided the information. There are four steps involved in using JavaScript to make an Ajax request: 1. 2. 3. 4. Creating a request object Telling the request object where to send the request Telling the object what to do when the request is answered Telling the object to make the request Creating a Request Object The first step in making an Ajax request is to create a request object. Sadly, there is a little bit of browser incompatibility involved in creating this object. In Internet Explorer,2 a request object is created like this: var request = new ActiveXObject("Microsoft.XMLHTTP"); 2 It’s possible to get slightly different versions of the request object from different versions of IE. You only need to do this for fancy Ajax tricks that are beyond the scope of this discussion. Ajax B a si cs 265 In browsers other than Internet Explorer, do this: var request = new XMLHttpRequest(); Putting these together gives this: var request = null; if (window.XMLHttpRequest) { request = new XMLHttpRequest(); } else if (window.ActiveXObject) { request = new ActiveXObject("Microsoft.XMLHTTP"); } Once this block of JavaScript has executed, the request variable will contain a request object. Telling the Object Where to Send the Request The request object will request information from some resource. Usually, that resource will be the webserver that served up the web page containing the JavaScript making the request. In this case, the request object needs to know the URL of a program or script that lives on the webserver (known as a server-side program). This server-side program will process the request and respond with the requested information. (Chapter 16 will focus more on server-side Ajax.) If you don’t have access to a webserver, you can instead ask the request object to request a file that lives in the same directory as the file containing the JavaScript making the call. To request a file, the request object simply needs to know the file’s name, such as my_file.txt. Here’s how to tell a request object to request the file named my_file.txt: request.open("GET", "my_file.txt"); The open method of the request object takes two parameters. The first parameter is the type of request you want to make (GET, POST, HEAD, and so on). I’ll discuss the difference between these in Chapter 16; for now, we’ll only use GET. The second parameter is a string that tells the object where to send the request. If the resource is password protected, the username and password can be provided as two additional (optional) parameters, like so: request.open("GET", "my_file.txt", username, password); What to Do When the Request Is Answered As described in the introduction, a key feature of Ajax is asynchronicity. After a request object makes a request, the web browser is free to do whatever it wants, which may involve creating more request objects to make additional requests. Each request object is responsible for tracking the process of making 266 Chapter 14 its request, waiting for a reply, and realizing when all the information provided in response to the request has been completely downloaded. Your task as a JavaScript coder is to tell each request object what it should do when the requested resource has been completely downloaded, using a special property of the request object called its readyState. As the request object moves through its stages, from creation, to being told about where to send the request, to sending the request, and so on, the value of the readyState property changes. The property is called readyState because each stage of a request object is called its state. Table 14-1 lists the values the readyState property can take and what they mean. Table 14-1: Values of a Request Object’s readyState Property Property Value State Name Description 0 Uninitialized The object has been created but not told about the request: open() has not been called. 1 Loading The object knows about the request but has not sent it yet: send() has not been called. 2 Loaded The request has been sent, and basic information about the response is available. 3 Interactive The response is being loaded into the request object. 4 Completed The entire response has been loaded into the request object and is now available. The main trick in Ajax is to write a special function that is called whenever the readyState property changes value. To define this function and make sure it is called when the request object’s readyState property changes, do something like this: request.onreadystatechange = function() { alert("the state has changed!"); } There’s actually a lot happening in the code fragment above, so let’s go slowly. The part of this JavaScript before the period refers to the request object we’ve created. The part following the period, onreadystatechange, is an event handler of the object. We’ve seen plenty of event handlers before: onClick, onMouseOver, and so on. These handlers are part of the objects. For example, a form button () will have an onClick handler, which is triggered whenever a user clicks the button. We’ve used these handlers by referring to them inside the HTML tag. For example, the tag will attach the function myFunction() to the button’s onClick event handler. Just as a button has an onClick handler, the request object has a handler called onreadystatechange, which is called automatically whenever the value of the request object’s readyState property changes. And, just as we can attach a function to the button’s onClick handler, we can attach a function to the onreadystatechange handler. Ajax B a si cs 267 However, in contrast to the button’s handler, we don’t stick the function into an HTML tag. Instead, we set the onreadystatechange handler equal to something called an anonymous function. This function has no name; it is simply called function. By setting this handler equal to this anonymous function we ensure that whenever the request object’s readyState property changes, the function—that is, the code in the braces—is called. It looks weird, but you’ll get used to it. Writing JavaScript That Is Called After the Request Has Been Answered A request object begins life with a readyState of 0. Calling request.open() tells the request object where to send the request, and switches the object’s readyState to 1. Because the readyState has changed, the anonymous function attached to the onreadystatechange handler is called. Usually, you don’t want your JavaScript to do anything special at this point, so the function should not do anything when the readyState has been changed to 1. In fact, the function usually does not do anything until the readyState has changed to 4, which, as you can see in Table 14-1, means that the request has been answered and that all the information sent by the server has been downloaded into the object. Once readyState 4 is reached, the function is ready to do something with the data. Because JavaScripts usually don’t do anything until the request object reaches a readyState of 4, the anonymous function often looks something like this: request.onreadystatechange = function() { if (request.readyState == 4) { alert("Download complete! "); } } In the code above, the alert is called only after the request’s readyState property changes to 4. The anonymous function is actually called when the property changes from 0 to 1, 1 to 2, and 2 to 3, but because of the if-then statement, the alert is called only when the readyState changes to 4. Although this code sample calls an alert, more typically the JavaScript inside the if-then statement will do something with the information that has been downloaded into the request object. We’ll see examples of this soon. Sending the Request Once you’ve told the request object where to send the request and what to do when the request has been answered, it’s time to tell the request object to send the request, like so: request.send(null); 268 Chapter 14 This command sends the request using the request object’s send method. The single parameter of the send method contains information (for example, form information) to send to a webserver when making a POST request. Because the request we’re making is of type GET (remember the first parameter of the request.open() method), the parameter of the send method is set to null, which is a predefined term meaning “no information.” Putting Everything Together Figure 14-4 combines everything covered so far in one function, which includes creating the request object, telling it where to send the request, providing the anonymous function that is to be triggered when the request object changes state, and sending the request. X Y Z [ \ ] ^ _ ` a A Simple Ajax Script
Figure 14-4: A simple Ajax script Ajax B a si cs 269 The action begins when the user clicks the button in `, which calls the doAjaxCall() function (X) and sends it the name of a file to read. NOTE In general, a URL would go in here, but because I’m not assuming you have access to a webserver, we’re just going to read a file that lives in the same directory as the file containing this JavaScript. The doAjaxCall() function creates a new request object (Y), which is either an XMLHttpRequest object or an ActiveXObject object. If the browser reading the JavaScript knows what the XMLHttpRequest object is, it will create a new object of this type; if instead it knows what the ActiveXObject is, it will create a new object of this type. If the browser doesn’t know either of these objects, request will stay equal to null. In Z, we make sure that a request object was created. If not, _ lets the user know that he or she needs a browser upgrade. If a request object was created, [ tells it where to send the request. The function to call when the readyState property of the request object changes is declared in \. This function says, “If the request is in state 4, the request object has sent the request and received an answer; put the All done! message into the div with the id of resultDiv (]).” Finally, the request object makes the request in ^, which begins the process of downloading the requested text file. The request object then goes through its five states, and each state change triggers the anonymous function. Once the request object is in state 4, the anonymous function writes All done! into the div. The magic in all of this is that while the request object is performing the query and getting the results, the browser does not freeze up and the page does not reload. And that is the beauty of Ajax. Getting the Results The code in Figure 14-4 performs the request, retrieves the results, and puts All done! into the div; it doesn’t actually display the retrieved results. It’s as if I asked you what you wanted for dinner and ignored what you said. Usually, once the request object has entered state 4, you will want to look at the information the object has retrieved. This information is stored in one or two properties of the request object: The responseText property of the object always contains a text string with the results, and if the response is an XML document, the responseXML property of the request contains an XML object representing the results (more on this in Chapters 15 and 16). If the response is not an XML document, responseXML will contain the value null. To put the results of the query into the div in a in Figure 14-4, change the body of the if-then statement in ] to document.getElementById("resultDiv").innerHTML = request.responseText; 270 Chapter 14 Demonstrating Asynchronicity Now it’s time to have a deeper look at asynchronicity. Figure 14-5 demonstrates how two request objects can download files asynchronously. Here, clicking the Start Downloading button downloads two files, shortWait and longWait, which take different amounts of time for a webserver to process. The JavaScript behind this figure (shown in Figure 14-6) requests the file that takes the longest to process (longWait) first, and then requests the one that takes less time to process (shortWait). Figure 14-5: Demonstrating asynchronicity Were these files to be downloaded synchronously, the script would download the slowest file—longWait—first, and then the quickest file, shortWait (because that’s the order in which they were requested). However, because these files are loaded asynchronously, all requests happen simultaneously. This means that shortWait will be downloaded before longWait. Each line in the figure shows the name of the file being downloaded and the number of seconds it took to download. What you can’t see in the figure is that each of the lines appeared on the web page as the file is downloaded: the first line 1.2 seconds after the button was clicked, and the next line about 4 seconds later. Now let’s have a look at the code behind Figure 14-5 to see how the magic works. Figure 14-6 reveals the trick. NOTE Before you can try out this example or most of the examples in Chapters 15, 16, and 17, you’ll need to set up a webserver and PHP on your local computer. If you don’t already have a webserver and PHP on your local machine, refer to “Setting Up a Webserver and PHP” on page 273. If you already have a webserver running on your machine, it has PHP installed, and you know where the webserver’s top-level document directory is, you can try running the script in Figure 14-6. To do so, put the files longWait.php, shortWait.php, and Fig14-06.html in a directory named boj, and put that directory in the top-level directory of your webserver. Then browse to http://localhost/boj/Fig14-06.html. If that doesn’t work, try http://127.0.0.1/boj/Fig14-06.html. If that doesn’t work either, you should refer to your webserver’s manual to determine how to connect with your webserver. The files longWait.php, shortWait.php, and Fig14-06.html are available at http://www.bookofjavascript.com/Chapter14. Ajax B a si cs 271 X Y Z [ \ ] ^ Demonstrating Ansynchronicity
Figure 14-6: Asynchronicity in Ajax 272 Chapter 14 SETTING UP A WEBSERVER AND PHP Below you’ll find some resources for setting up the Apache webserver and PHP on your desktop machine. Apache has been the most popular webserver on the Internet for more than 10 years. It is very robust, has loads of features, and works on all modern Windows, Macintosh, and Unix (including the major flavors of Linux) operating systems. In the spirit of full disclosure, I should mention that my cousin, Robert S. Thau, was one of the original authors of Apache. Hooray, Robert! For Windows and Linux If you are using Windows 98, NT, 2000, or XP, or a major version of Linux (Debian, Mandrake, Red Hat, or SuSE), you can install Apache and PHP using one easy package called XAMPP from Apache Friends. The package is available at http://www.apachefriends.org/en/xampp.html and at http:// www.bookofjavascript.com/Freeware/xampp. The useful MySQL database and a few other things are also included. If you want to get up and running quickly, I suggest you use XAMPP. For Macintosh OS X Server If you’re running the Macintosh OS X Server operating system (http://www .apple.com/server/macosx)—which is different from its desktop operating system— you already have Apache and PHP installed. See your OS X Server documentation for details on how to get it operational. For Macintosh OS X Standard If you’re not running OS X Server, there is a simple package for setting up Apache, PHP, and MySQL on the Macintosh. It’s called MAMP, and it’s available at http:// mamp.info and at http://www.bookofjavascript.com/Freeware/mamp. Line-by-Line Analysis of Figure 14-6 The action starts when a user clicks the button in ^, which calls the demoAsync() function in X. This function creates a new Date object that tracks the time when the function was called, and then it calls the downloadFile() function twice (once for each file we want to download). Notice that the function asks for the largest file, longWait, first and the smallest file, shortWait, next. The downloadFile() function that starts in Y looks like a typical Ajax function. It begins by trying to create a new request object, and if that succeeds, it tells the request which resource to access. The anonymous function that is called when the request changes its state is defined in Z. This function says that we should add some information to the contents of the div named resultDiv ([) once the request has completed (that is, when the request object’s readyState property equals 4). The information added is the name of the requested file and the time it took to download. Line \ calls getExpiredTime() to determine how long (in seconds) it took to download the file. Ajax B a si cs 273 Next up, getExpiredTime() (]) is passed a Date object that represents the time when the demoAsync() function was called. The getTime() method of this Date object returns the number of milliseconds between January 1, 1970, and the time represented by the object (getTime() was described in Table 2-1). Next, a Date object that represents the current date and time is created, and getTime() calculates the number of milliseconds between the current time and January 1, 1970; the difference between these two numbers is the time (in milliseconds) that has passed since the demoAsync() function was called and the request object completed its download of the requested file. That number is divided by 1,000 (1,000 milliseconds in a second) to get a time in seconds. Ajax and Usability There are many good examples of Ajax (Google Maps, Flickr, and Google Suggest, to name a few), but it is very easy to create a confusing and difficultto-use Ajax application. Below is a list of some roadblocks that you may encounter along your road to implementing excellent Ajax. The Back Button Web users are accustomed to using their browser’s back button to return to pages they’ve just seen. Unfortunately, unless special care is taken, the back button does not work as expected in Ajax applications. For example, if you click the left side of a Google map and drag it to the right side of the screen, the map will change, but clicking the browser’s back button won’t return the map to its previous state. Instead, because all of an Ajax application happens on a single web page, clicking back will take you off that web page. In the case of Google Maps, this may take you out of Google Maps entirely. You can use many of the Ajax frameworks described in Appendix B to help make the browser’s back button work in ways that will make more sense to your visitors. Dojo (http://www.dojotoolkit.org), Backbase (http://www.backbase.com), and RSH (http://codinginparadise.org/projects/dhtml_history/README.html) are three examples of such libraries. URLs and Bookmarking Web page URLs can be written down, sent to friends, and bookmarked. However, because the URL of a web page for an Ajax application does not change as the contents of the page change (all updates happen on the same page), special care must be taken to create URLs that can be bookmarked and emailed. Again, you’ll find solutions to this problem in the Ajax frameworks in Appendix B. Poor Design People who have been browsing web pages for any length of time are probably all too familiar with the usual submit-wait-reload method of web interaction. In this style of communication, the entire web page updates 274 Chapter 14 when new information is returned from the server, which also signals to the visitor that the whole page is new. When using Ajax, on the other hand, the contents of a web page might change without the visitor noticing any signs of a change. As a web designer, you should be sure to signify important changes to web pages using design techniques, such as changing color or borders. Ajax also offers new types of navigation to the web designer. Pre-Ajax, designers used links and images to help users navigate between web pages. Ajax and dynamic HTML offer much greater flexibility, but this flexibility can also create confusing means of navigation. For example, you could design a website with an interactive knob that visitors would turn to see different pages of your site. Although this interactive knob would be nifty, it might also confuse most web surfers, who are accustomed to navigating websites using hyperlinks. Adding a fancy new navigation style is probably not a good idea unless you are simply trying to show off your elite Ajax skills. For more information about potential problems with Ajax, see Chris McEvoy’s article “Ajax Sucks Most of the Time”3 and Alex Bosworth’s article “Ajax Mistakes.”4 To Ajax, or Not to Ajax Like all technologies, Ajax can be used for good or for evil. Opinions concerning the best times to use Ajax range from “never” to “whenever possible.” I tread the middle ground by keeping in mind the following bad and good uses of Ajax: Bad: Just Because You Can No flashy web technique should be unleashed upon your visitors just because you think it’s cool—unless, of course, your visitors are going to your site expressly to see cool web tricks. Bad: It’s the Hot New Thing Similarly, just because Ajax is new doesn’t mean it solves all problems, and as we’ve seen, it introduces new ones. Resist the urge to add Ajax to your site just because it is the hot new thing. Bad: Replacing Something That Works with Something New and Confusing Hyperlinks do a great job of leading people from one web page to another. Confusing your visitors with new and unnecessary forms of navigation will most likely result in fewer users. 3 See http://www.usabilityviews.com/ajaxsucks.html. Note that this article is a rewriting of an older article by Jakob Neilsen titled “Why Frames Suck (Most of the Time),” which is available at http://www.useit.com/alertbox/9612.html. 4 See http://sourcelabs.com/ajb/archives/2005/05/ajax_mistakes.html. Ajax B a si cs 275 Good: In-Context Data Manipulation Imagine you are the CEO of a big company, and you are presented with a table of information about your employees. This table may include the name, salary, and tenure of each employee. Now, imagine you want to sort that table by name, salary, or tenure. Without Ajax, you would click a button and wait for the whole page to reload. With Ajax, the table can stay on the screen while the data are being rearranged, which is far less disruptive. In this example, the object you are manipulating stays in front of you while you are manipulating it. This is a good use of Ajax. Another example of in-context data manipulation is Google Maps’ use of Ajax. In Google Maps, you can move the map by dragging on it. The rest of the page does not change, and at no point is the screen blank. Mapping applications that do not use Ajax reload the entire web page each time you want to pan a map. Good: Interactive Widgets Interactive widgets are small components of a website that generally appear on the margins of a web page. Items such as news tickers, quick one-question polls (“Do you prefer cats or dogs?”), and login forms fall into this category. In each of these cases, interacting with the widget may produce results that do not require the entire web page to reload. For example, if a visitor tries to log in with an invalid username or password, the error message might as well appear on the current web page, rather than bringing the visitor to an entirely new page that says nothing but Invalid login. Similarly, the current poll results might show up exactly where the poll the user just completed was placed. Good: Saving State Many word processors and other applications have an auto-save function, which stores a user’s work from time to time. The same functionality can be added to a web application using Ajax’s ability to send information to a webserver without alerting or disturbing the user. This kind of behind-thescenes application of asynchronous behavior is a perfect context for Ajax. Summary This chapter has covered the basics of using Ajax, including: 276 Chapter 14 z How client-server communication using Ajax differs from the traditional type of web-based client-server communication z How to create a request object and send requests z How to get results from a request object once the request has been fulfilled z What asynchronicity means, and what it can do for you z What problems may arise z When to use Ajax This is just the first of three chapters on Ajax. The next chapter deals with how to use XML to share information between a web browser and a webserver. Chapter 16 gets you started with writing programs that run on webservers and communicate with the Ajax you learned in this chapter and that you’ll learn in Chapter 15. Assignment The JavaScript in Figure 14-4 used Ajax to read the contents of a file called sample.txt, but it did not display the contents of the file. Your assignment is to write a page that asks for a file to read in, and then displays the contents of that file in a div. Figure 14-7 depicts how a solution might look after a user entered sample.txt into the text field and clicked the Get the File button. Remember, the file that Ajax reads must live in the same directory as one that contains the Ajax code. Figure 14-7: Displaying the contents of a file Ajax B a si cs 277 XML IN JAVASCRIPT AND AJAX Chapter 14 introduced Ajax and showed how it works inside web browsers. Normally, Ajax applications pass information back and forth between a web browser and a webserver. When a user drags a Google map, for example, the browser sends information to the server about how the user is dragging the map. The server then returns map-related information for the browser to interpret and display. Information passed back and forth between a web browser and a webserver can take many forms. This chapter discusses the form used by Ajax: XML. In this chapter you will learn: z What XML is and why it’s useful z How to format information using XML z How to use JavaScript to read XML documents z What browser-compatibility issues relate to processing XML How to use XML in Ajax communications z Once you’ve mastered the intricacies of XML, you’ll be ready for Chapter 16, the final Ajax chapter. There you will learn how to write the server-side code for Ajax communications. A Real-World Example of Ajax and XML The photo-sharing community site Flickr (http://www.flickr.com) provides many fancy web-based tools for uploading, editing, and sharing your photos. Figure 15-1 shows how Flickr looks after I’ve logged in. At the top of the screen is a menu with an Organize button. Clicking that button brings you to a page like the one in Figure 15-2. Here, you can drag your pictures to the canvas, edit their descriptions, change their dates, and perform a variety of other image-organizing tasks. What you don’t see is the behind-the-scenes communication Flickr uses to retrieve your images from its webserver. Using a handy debugging tool called the XmlHttpRequest debugger (which I’ll describe in detail in Chapter 18), I was able to watch a bit of that communication. As the web page in Figure 15-2 opens, the browser sends an Ajax query to the Flickr server, and the server answers with a list of the images I have already uploaded. Figure 15-3 shows part of the webserver’s response. Figure 15-1: Flickr user home page The gobbledygook you see in Figure 15-3 is XML, the standard way of communicating information in Ajax. If you look at it long enough, you’ll see that the response describes three photos. Each photo has a title, a date it was uploaded, a date it was taken, and a bunch of other information. In addition to this information, you’ll see lots of tags that look something like HTML tags. This information is processed by the JavaScript in Flickr’s web page and turned into a nice interface like the one in Figure 15-2. The XML document is a bit hard to understand, but keep in mind that XML is meant for programs, not people. Normal humans are not supposed to see XML in the raw like this. Only programmers like us have that honor. 280 Chapter 15 Figure 15-2: Flickr Organize page Although Flickr is a great example of a site that uses XML in its clientserver communications, the application is a bit too complicated to use as an instructional example. Instead, this chapter will show you how to use XML to create a application much like Google’s enhanced search engine interface, Google Suggest. Figure 15-3: Part of Flickr’s webserver XML response (I removed 29 of the photos) Google Suggest Google Suggest (http://labs.google.com/suggest) is just like the usual Google search engine, but as you type a word into the search field, it presents a list of frequently searched-for terms beginning with the letters you have already typed, along with the number of results you’d get if you searched for each of X M L i n J a v aS c ri p t a n d A j a x 281 those terms. For example, Figure 15-4 shows what happens when I commit the narcissistic act of typing my name into Google’s search field. Each time I type a letter into the search field, Google Suggest gets information from Google’s webserver and updates the page. In typical Ajax fashion, this trip to the server occurs invisibly. Figure 15-4: Finding myself in Google Suggest In this chapter, we will use XML to create an Ajax application much like Google Suggest. XML—the Extensible Markup Language XML is a standard way of representing information that can be stored in a file or shared between machines. Computers have been storing and sharing information since they were first created. In the past, people who wrote software invented their own formats for sharing information. Imagine a language translation program that stores its dictionary in a file. The file will contain words in English and their translations into another language, say, Italian. That file can be formatted any number of ways. For example, it might have each English word and its Italian translation on one line, separated by a colon: a: un, uno, una aardvark: oritteropo Alternatively, the file could have an English word on one line, the Italian translation on the next line, and then a blank line before the next English word: a un, uno, una aardvark oritteropo There are infinitely many ways to format a file for a computer. As long as the computer understands the format of the file, it will be able to do something with the information inside. Unfortunately, all these different file formats 282 Chapter 15 make it difficult to create tools that can work with arbitrary files. How can a program or a tool know that the first file uses one line for each English word and translation, while the second file uses two lines for the English word and its translation? This is where XML comes in. XML is a standard file format ratified by the World Wide Web Consortium in 1998 (http://www.w3.org/XML). Since the standard’s release, XML has become the way to store and share structured text documents. A structured document is one that can be divided up into meaningful components. For example, The Book of JavaScript is structured. It has chapters, each of which has a title at the start and a summary near the end. Each chapter also has a number of large sections indicated by headers in large print, and these sections can be subdivided into shorter parts marked by smaller-print headers. Most text documents designed to be read and processed by computers have some sort of structure; XML is a standard way to describe that structure to a computer. XML has become so popular that all modern web browsers come with built-in methods to read and process XML documents. Similarly, all major programming languages used by webservers also have XMLprocessing facilities. Because both web browsers and webservers understand XML, they can communicate with each other by sending messages that conform to the XML standard. The Rules of XML The rules for XML documents are simple and few. As another example of an XML document, consider the XML-style English-to-Italian dictionary in Figure 15-5. X Y a un, uno, una Z aardvark oritteropo Figure 15-5: A simple XML document The XML Header All XML documents start with an XML header like the one in Figure15-5. XML headers can also include an optional attribute called an encoding, as you can see in the first line of Figure 15-3. This encoding tells an XML processor what kind of characters to expect in the document. X M L i n J a v aS c ri p t a n d A j a x 283 XML Elements XML elements are used to mark up information. For example, to indicate that something is an English word, we might define an XML element called english. Most XML elements have a start and end tag; in this case, the english element has a start tag, , and an end tag . To indicate that aardvark is an English word, we would use the following XML: aardvark (Z). XML elements can nest inside each other. The nesting must be proper— that is, the inner XML element must be closed before the outer XML element is closed. Element names must begin with a letter and should not contain spaces or punctuation other than periods (.), hyphens (-), and underscores (_). If there are no XML elements or text inside the open and close tags of an XML element, that element is called empty. An empty XML element can be shortened from to . It does not have an end tag, but the closing bracket has a slash before it. The document in Figure 15-5 has several XML elements: dictionary, word, english, and translation. A computer program that understands XML could read this document and know that aardvark and a are both considered english things, and that english things and translation things are parts of word things, which are parts of a dictionary thing. Because the document is in XML, we would not have to tell the program that the English and Italian words are separated by a colon or that each line represents an English/Italian pair. XML Attributes Elements can have attributes. An element with an attribute looks like this: No Starch Press This is an XML element named a with an attribute named href. The value of the attribute is quoted. Attribute names follow the same rules as element names: They must begin with a letter and should not contain spaces or punctuation other than periods (.), hyphens (-), or underscores (_). Empty elements can still have attributes: NOTE Did you notice that the XML above is also HTML? HTML is almost a type of XML. The main difference between it and XML is that HTML is more relaxed. For example, the element: is valid HTML, but not valid XML. To be valid XML it would have to look like this: . Notice the slash before the closing bracket. Illegal XML Characters Certain special characters (', ", <, >, and &) are not allowed in an element name, an attribute name, attribute values, or text between the elements. If you need to use one of these characters you must use an encoding known as an entity, which is introduced by an ampersand (&) and terminated with a semicolon (;). Use the entities < and > to represent the angle brackets 284 Chapter 15 < and >, and use ' and " to represent apostrophe and quotation marks. Because it introduces entities, the ampersand itself is a special character. If you need to use an ampersand as itself, you must use the entity &. To ensure maximum cross-browser interoperability, all non-ASCII characters should be encoded using their Unicode decimal numbers. For example, the character á (a with an acute accent) should be encoded as á. (See http://www.unicode.org/charts for the entire set of character entities and http://www.webmonkey.com/webmonkey/reference/special_characters for a less complete, but more usable, list.) XML Documents Have a Single Root Element An XML document must have only one root element. The root element is the first XML element in the document, and all the other elements of the XML document go between its open and close tags. For example, in Figure 15-5 the root element is dictionary (Y). Final Comments About the XML Format As already mentioned, XML has become an incredibly pervasive standard. One feature of XML that makes it particularly useful is that you can invent any element names you desire. This means that organizations can agree upon a set of XML elements that work for them and that can be used to structure all information within their organization or field. Varieties of XML, called XML vocabularies or markup languages, have been invented for many applications, such as SVG for describing two-dimensional graphics, GedML for genealogical information, GML for geographic information, VRML for describing objects in 3D, and SportsML, which the International Press Telecommunications Council uses to publish sports information. Each of these uses the rules of XML and a set of predefined element and attribute names. When using XML, you can either use existing vocabulary or create your own. The format of an XML document is just the tip of the XML iceberg. There are many useful technologies built around XML, including standard ways to search XML documents, ways to convert XML documents into PDFs and HTML, and ways to ensure that XML documents conform to specific vocabularies (such as GML, VRML, and the others described above). Processing XML XML is so popular that web browsers have built-in mechanisms for dealing with XML documents. In fact, all of the methods used to process the DOM (discussed in Chapter 13) can also be used to process XML documents. The script in Figure 15-6 shows how to use some of the methods that we used to process the DOM to create an application that looks up a word in three dictionary files (German, Portuguese, and Italian), which I downloaded from the Internet Dictionary Project (http://www.ilovelanguages.com/IDP). X M L i n J a v aS c ri p t a n d A j a x 285 Reading XML Documents
Portuguese:
Italian:
German:
Figure 15-6: Reading an XML document As you can see in Figure 15-7, entering aardvark into the text box and clicking the Translate! button translates the provided word into the three languages. Figure 15-7: Translating aardvark NOTE Unless the XML dictionary files are served up using a webserver, the script in Figure 15-6 will not work in Internet Explorer. To understand why not, why it doesn’t matter too much, and what you can do about it, see the section “Internet Explorer, responseXML, and Client-Side Ajax” on page 291. Line-by-Line Analysis of Figure 15-6 The script in Figure 15-6 begins when a user clicks the Translate! button or when the user presses ENTER while the cursor is in the text box (thereby submitting the form). In either case, the function getTranslations() is called with the contents of the text box. The getTranslations() function in X simply calls getTranslationsFromFile() for each of the dictionary files. NOTE It’s nice to use an array and a loop here, because if we want to add a new language file, we can just add it to the languages array. X M L i n J a v aS c ri p t a n d A j a x 287 The getTranslationsFromFile() function in Y is called once for each language. It has two parameters: the name of a language and the word to translate. This function is the typical Ajax function we’ve seen, with a few twists. First, in Z notice that the request is getting a file whose name is the name of the language we want to translate, with the extension .xml. Once the request has been answered, [ retrieves the value of the request’s responseXML property. Then \ calls the findTranslation() function and puts its results into an element with an id attribute set to the language. NOTE Notice that the variable passed into the getTranslationsFromFile() function is used to name both the file being read and the element into which the answer should be placed. Using one variable in multiple contexts is a common trick. Also notice that ] puts the string "SEARCHING..." into the element, which will soon hold the result whenever the request object changes into any state other than 4. This is a good way to let your users know that your page is doing something and that there is more information to come. Visualizing the XML Document All of the XML handling is done in the findTranslation() function (^), which is called once the XML document has been fully loaded (after the equal sign in \). To understand better how findTranslation() works, see Figure 15-8, which represents part of the XML document in Figure 15-5 graphically. The root element of the XML document, dictionary, appears as a node at the top of Figure 15-8. dictionary word english word translation english translation Text node Text node Text node Text node nodeValue = a nodeValue = un nodeValue = aardvark nodeValue = oritteropo Figure 15-8: A graphical representation of part of the XML in Figure 15-5 The dictionary node has two child nodes, each named word, which represent the word elements in Figure 15-5. Each word node in Figure 15-8, in turn, has two children, named english and translation, representing the english and translation elements in Figure 15-5. These elements each have some text between their open and close tags: an English word and its translation. The text stored between the tags of an XML element is stored in a text node that is a child of that element. If the only thing between an element’s open and close tags is text, the text node containing that text is the first child of the element. In order actually to get the text from the text node, the node’s nodeValue property must be accessed. We’ll see that working soon. 288 Chapter 15 Navigating the XML Document Now let’s return to the findTranslation() function. The function first sets the translation to "unknown" and, if no other translation is found, this will be the result returned. The first sign of XML handling is in _, which uses the getElementsByTagName() method (discussed in Chapter 13) to return an array of all the elements of the XML document with the name "english". You can see these elements in the XML in Figure 15-5. Once that array of elements is returned, the function loops through the array. Each time through the loop, the variable this_english_element is set to the next english element in the array, and ` extracts the English word between the open and close tags of the element. Line a then extracts the translation of that english element. Extracting Information from XML Elements Lines ` and a are complicated enough to deserve their own figure. Figure 15-9 is a graphic representation of the process of translating the word aardvark. Assume that we’ve retrieved the list of elements named english and have looped past the first english element. We’re now looking at the second english element in the list, which is labeled in the figure with the box containing the words this_english_element. The this_english_element element has a child element that is a text node with a nodeValue of aardvark. dictionary Parent of this_english_element word word Next sibling of this_english_element this_english_element english translation translation english Text node Text node Text node Text node nodeValue = a nodeValue = un nodeValue = aardvark nodeValue = oritteropo Text node of this_english_element Figure 15-9: A graphical representation of getting a word’s translation Line ` extracts the value "aardvark" from this_english_element. Here’s ` again: this_word = this_english_element.firstChild.nodeValue This line looks at the built-in firstChild property of the XML element stored in this_english_element, which is a text node, and then it retrieves the nodeValue of that text node. The line following ` checks to see whether this word is the word we want to translate. If it is, a retrieves the translation of the word. X M L i n J a v aS c ri p t a n d A j a x 289 To understand a, look back at Figure 15-9. Notice that the parent of the node labeled this_english_element is a word node and that it has been labeled Parent of this_english_element. This word node has two children: this_english_element and a translation node. As is true of people, any two XML nodes that share a parent are called siblings. The sibling that comes right after an XML node is called that node’s next sibling. The sibling next to this_english_element is the node labeled Next Sibling of this_english_element. This next sibling can be accessed using the built-in property nextSibling. Now look at a: the_translation = this_english_element.nextSibling.firstChild.nodeValue The code in a gets the translation of this_english_element by looking at this_english_element, finding its next sibling (the translation node), getting that node’s first child (the text node), and then retrieving the nodeValue of that text node. Wrapping Up Before wrapping up Figure 15-6, let’s review. A visitor has entered a word into a text field and clicked the Translate! button. This calls getTranslations(), which loops through a list of languages into which the provided word should be translated. Each time through the loop, getTranslationFromFile() is passed the name of a language and the word to translate. The getTranslationFromFile() function performs an Ajax call that reads in an XML dictionary for that language and then calls findTranslation() to get the translation. The findTranslation() function does all the XML handling just covered and returns the found translation back to the getTranslationFromFile() function. Now we’re ready to wrap up. Once findTranslation() finds and returns the translation of the requested word, \ in getTranslationFromFile() puts the translation into the span with an id equal to the name of the language being processed. This makes the translation appear on the web page and completes the Ajax request for this language. As with all things Ajax, the calls in getTranslationsFromFile() all are satisfied asynchronously. Once the user clicks the Translate! button, the language files are all accessed simultaneously, the translations are retrieved, and the results are placed in the tags at the bottom of the HTML. NOTE I’ve used spans instead of divs to avoid a line break between the text listing the language (e.g., Italian) and the returned translation. This example has shown you the fundamentals of processing XML documents in JavaScript. The rest of the chapter will cover a few niggling details and then take you through another example of using XML in Ajax. 290 Chapter 15 Internet Explorer, responseXML, and Client-Side Ajax I noted in the previous section that the script in Figure 15-6 will not work on Internet Explorer if the XML dictionary files are not served up by a webserver. This is because Internet Explorer fills the responseXML property only if the browser is told that the file being read is an XML file. If the file is being read straight off the hard drive (and not sent by a webserver), Internet Explorer won’t know that this is an XML file rather than an ordinary text file. In general, this is not really a problem. If you are developing a web page that will be available to anyone other than you, you will need to use a webserver to serve it and all the documents relating to it. Therefore, in practice, the XML files will be served by a webserver, and Figure 15-6 should work just as it is. The only time this Internet Explorer “feature” will cause problems is when testing and debugging your Ajax code without using a webserver. Fortunately, there is a simple fix: Replace [ in Figure 15-6 with this: xml_response = new ActiveXObject("Microsoft.XMLDOM"); xml_response.loadXML(request.responseText); These lines use a special Microsoft ActiveXObject to turn the contents of the request’s responseText property into XML. Problems with White Space in XML Some browsers, such as Firefox, like to treat blank spaces in XML documents (including spaces used to indent tags) as text nodes. As you might imagine, these unexpected text nodes can cause problems when using JavaScript to navigate around an XML page. To solve this problem, you can write some JavaScript to remove all text nodes in the XML with nodeValues that contain only spaces, or you can write your JavaScript to simply ignore these blank text nodes (which usually appear between XML elements). For example, if Firefox reads this line of XML a un the XML document stored in request.responseXML will contain a word element with three children: an english element, a text node with the space between the english and translation elements, and the translation element. This means that the nextSibling property of the english element would point to the text node rather than to the translation element. This is bad news for the script in Figure 15-6, which assumes that each english element will be followed by a translation element rather than by a text node containing only a space. A more flexible version of Figure 15-6 would do one of two things. First, the JavaScript could preprocess the XML document, deleting all the text nodes that contain only spaces. Alternatively, the code could leave the X M L i n J a v aS c ri p t a n d A j a x 291 extra text nodes in place but just skip nodes that it doesn’t care about. For example, when looking for the translation of an English word, the code in Figure 15-6 could loop through the children of the parent of the english element, checking the nodeName of each child and stopping when it finds an element named translation. As it is now, the code in Figure 15-6 works fine because the XML files I created do not have a space between the english and translation elements. For our purposes, this works. In the real world, however, you would want to write code that would deal with the possibility that somebody writing an XML dictionary for your application would accidentally put a space between the english and translation elements. Creating a Suggest Application for Translation Let’s apply what we’ve learned so far to another example of using XML with Ajax. Google Suggest is a very fancy web application, with many interesting features that help it react quickly to user queries. As shown in Figure 15-4, Google Suggest provides suggested searches as you type letters into the search box. Although the JavaScript I’ll describe in this section is not nearly as advanced as what you see in Google Suggest, it should help to demonstrate how Google Suggest works. Figure 15-10 shows a simplified suggest application that translates English words into Italian. The figure shows how things look in Internet Explorer after I type bo. On the left side you see a list of the first ten English words in the dictionary that start with the letters bo, and on the right side are their translations. After each keypress, the script reloads the italian.xml file and looks for words that begin with whatever letters are in the text box. As is typical with Ajax, there is no submit button to push; the JavaScript accesses the information it needs and updates the page as I type. Figure 15-10: The translation script with suggestions 292 Chapter 15 NOTE For a full description of how Google Suggest works, see Chris Justice’s excellent analysis at http://serversideguy.blogspot.com/2004/12/google-suggest-dissected.html. The code for this neat little application can be found in Appendix D and is available at http://www.bookofjavascript.com/Chapter15/translator.html. It is a bit long, so I will break it up a bit as I describe it here. NOTE Remember, this code will not work if you are testing it in Internet Explorer unless you serve up the italian.xml file using a webserver. If you don’t have access to a webserver and you want to test the script out, make sure to make the change described in the section “Internet Explorer, responseXML, and Client-Side Ajax” on page 291. Let’s begin with the text entry form:
This form has one text input element and a div into which the results of the script will be placed. The ems you see in the style of the div set the width of the div equal to some multiple of the width of the letter m (em) in the font being used. The size of the em unit will vary with the font being used, in direct proportion to the width of the letter m in that font. As a result, if a user changes the font size on his or her browser, the script will automatically adjust the width of the div. The JavaScript code will automatically change the height of the div as the number of results to be shown changes. Notice that the text input element has an onKeyUp event handler. When a letter is typed (that is, a key is pressed), and then released, the getTranslations() function is called upon the release of the key. This function is almost exactly like the getTranslationFromFile() function shown in Figure 15-6 except for the anonymous function defined after Z, which has been changed to: request.onreadystatechange = function() { if (request.readyState == 4) { xml_response = request.responseXML; displayResults(findTranslations(xml_response, the_word)); } } When the state of the request object changes to 4, it has completely downloaded the requested document. At this point it calls findTranslations() to get the relevant words and translations, and then it sends those results to the displayResults() function. X M L i n J a v aS c ri p t a n d A j a x 293 Finding the Translations The findTranslations() function searches through the XML file for the correct words to display. Figure 15-11 is a slightly abridged version: X Y Z [ \ ] ^ _ function findTranslations(xml_doc, the_word) { // obvious variable declarations and initializations (omitted) var these_translations = new Array(); var english_word_elements = xml_doc.getElementsByTagName("english"); var reg_exp = new RegExp("^" + the_word); while ((loop < english_word_elements.length) && (found == false)) { this_word = english_word_elements[loop].firstChild.nodeValue; if (reg_exp.test(this_word)) { the_translation = english_word_elements[loop].nextSibling.firstChild.nodeValue; found = true; } loop++; } if (found == true) { these_translations.push(this_word + "\t" + the_translation); for (var count = loop; count < (loop + 10); count++) { if (count < english_word_elements.length) { this_word = english_word_elements[count].firstChild.nodeValue; if (reg_exp.test(this_word)) { the_translation = english_word_elements[count].nextSibling.firstChild.nodeValue; these_translations.push(this_word + "\t" + the_translation); } } } } return these_translations; } Figure 15-11: Finding the translations The findTranslations() function shown in Figure 15-11 is similar to the findTranslations() function shown in Figure 15-6, except that instead of getting just one translation for a word, it looks for up to ten words that begin with the letters in the text box, with their translations. If only seven words begin with the letters in the text box, only those seven words will be displayed. The function uses regular expressions (discussed in Chapter 11) to determine whether a word starts with the letters in the box (X). Next, it gets a list of all the XML elements named english and loops through that list until either it runs out of elements or it finds a word that matches the regular expression (Y). Each time through the loop, this_word is set to the English word (Z), and then [ checks to see whether this_word matches the regular expression. If it does, the translation of the word is retrieved from the english element’s sibling, the found variable is set to true, and the loop ends. 294 Chapter 15 At the end of the loop, \ checks to see whether a word has been found that matches the regular expression. If so, ] sticks the word, followed by a tab (\t) and the word’s translation at the end of an array called these_translations. The these_translations array now has one word and its translation, and it will eventually contain all the words and translations to be displayed. NOTE The push() method ( ]) is a handy way to add something to the end of an array; it pushes an element to the end. Once the retrieved word and translation have been added to the array, it’s time to find other words that begin with the letters in the text field. The loop in ^ begins by examining the items in the array of english elements, starting where the previous loop left off. It then looks at the next nine items. Each time through the loop, the code gets the next english element, checks to see whether it matches the regular expression, and if so, adds it and its translation to the these_translations array. The code in _ makes sure the loop ends if there are no more elements in the array of english elements to consider, which may happen, for example, if we are looking at words that begin with the letter z. When the loop in ^ ends, the function exits and returns the these_ translations array, which is then fed into the displayResults() function. Displaying the Results The function displayResults(), which displays the results, is pretty straightforward (as shown in Figure 15-12). The function first creates an HTML table and then inserts that table into the innerHTML of theResultsDiv. The only tricky thing about this script involves changing the size of the div so that its border expands and contracts as the table changes size. X Y Z [ \ function displayResults(the_results) { var display_me = ""; var splitter; var this_result = null; for (var loop = 0; loop < the_results.length; loop++) { this_result = the_results[loop]; if (this_result != null) { splitter = this_result.split("\t"); display_me += "" + splitter[0] + "" + splitter[1] + ""; } } document.getElementById("theResults").style.height = (the_results.length + parseInt(the_results.length / 5) + 1) + "em"; document.getElementById("theResults").innerHTML = "" + display_me + "
"; } Figure 15-12: Displaying the results X M L i n J a v aS c ri p t a n d A j a x 295 The displayResults() function is passed an array of results to display. The code in X loops through this array, setting this_result to the next result each time it goes through the loop. NOTE Remember that each result is an English word, followed by a tab and the word’s translation in Italian (see ] in Figure 15-11). The split() method in Y is a built-in method of String objects. Given a character, or a set of characters, the split() method divides a string into parts and stores those parts in an array. For example, the instance of split() in Y takes the string in the_result and divides it into two parts: the part before the tab (\t) and the part after the tab. These pieces are stored in an array called splitter; splitter[0] contains the part before the tab, and splitter[1] contains the part after the tab. The code in Z then takes these parts, creates a string representing a row in an HTML table, and adds this string to the display_me variable, which will contain all the rows of the table. Once the loop completes, [ changes the height property of the div’s style property, making it roughly as tall as the table that it will contain. The formula in [ gives an approximation of the div’s height; it says that the div’s height should equal the number of rows in the table plus a little bit for the space between the rows. The number of rows in the table, in turn, equals the number of items in the the_results array. Finally, \ puts the beginning and ending table tags on the table and puts the table into the innerHTML of the div. There’s a great deal more to Google Suggest, including choosing an element from the suggestion box, caching results to make the page react more quickly, and filling in a few letters in the text box. With the JavaScript you know now, and a little expertise with cascading style sheets, you should be able to add those features to your own applications. Summary This chapter has covered the basics of using XML with JavaScript and Ajax: z What XML is used for z How to format XML documents z How Ajax applications use XML to share data z How to process XML with JavaScript z How to deal with cross-browser XML issues The chapter has also given you more details about some objects you’ve already encountered: 296 Chapter 15 z How to use the split() method to divide a string into parts z How to use the push() method to add an element to the end of an array z How to use em in a cascading style sheet to make the size of something proportional to the font being used Now that you know how to perform Ajax calls from the browser, and how to format XML documents and process them with JavaScript, it’s time to complete the Ajax cycle and learn about server-side programs. First, however, you should practice your Ajax skills with the following assignment. Assignment Write an Ajax address book like the one shown in Figure 15-13. First, create an XML file that is to be your address book. Each person should have a name, a home address, a phone number, and an email address. When the web page opens, it should get the names of the people in the XML file and then put them into the select field. When a user clicks a name in the select field, Ajax should look up that person in the phone book and display the results in the spans below the select box. Figure 15-13: An Ajax-enabled address book X M L i n J a v aS c ri p t a n d A j a x 297 SERVER-SIDE AJAX In Chapter 15 we saw how Ajax can enhance your user’s experience by making asynchronous requests for information. In that chapter we focused entirely on client-side Ajax. In this chapter we’ll focus on using Ajax to communicate with programs on webservers, which I will also call server-side programs. This chapter explains: z What server-side programs can do for you z Different types of requests z The basics of PHP, a server-side programming language z How to use PHP to read and save files on webservers z What to do if the webserver you are contacting doesn’t respond z How to update the contents of a web browser automatically when a server-side file changes Real-World Examples of Server-Side Ajax Almost all examples of Ajax on the Web involve communications between a web browser and a program running on a webserver. For example, when you search for a restaurant using Google Maps, Google’s webservers provide the maps and determine where the icon showing the restaurant’s location should go. The Ajax-driven To Do list site, http://www.tadalist.com, lets you create To Do lists and then share them so that others (whether in your household or organization) can add tasks, mark completed tasks, and so on. Figure 16-1 shows my Book of JavaScript To Do list. At the top are uncompleted items (don’t tell my publisher!), and below those are finished items. (I’m still waiting to celebrate; any day now, for sure.) Figure 16-1: A Ta-da List To Do list Figure 16-2 shows the screen after I click the Add Another Item link. As you can see, a text field and an Add This Item button appear. When I click the button, the new item appears on the bottom of the To Do list and is saved on the Ta-da List webserver. When I exit the browser and then return to the site, the saved To Do list is read from the Ta-da List webserver and displayed in my browser. When we covered cookies in Chapter 12, we saw examples of how to store a user’s information. For example, when a visitor bought clothing using the shopping cart, the items the visitor bought were stored on the visitor’s hard drive. Then, when it was time to purchase the selected items, the checkout page retrieved this stored information and told the visitor how much was owed. The difference in the To Do list example is that rather than saving the information on the computer of the person using the web page, the application saves the information on the Ta-da List webserver. As you may recall, browsers limit the amount of information you can save in a cookie on a visitor’s 300 Chapter 16 hard drive to about 80 kilobytes. In contrast, the amount of information stored on a webserver’s hard drive is limited only by the amount of space on the hard drive. Another difference between saving information in a cookie on a user’s hard drive and saving it on a webserver’s hard drive is that information on a webserver can be shared by anybody who accesses that server with his or her web browser. Figure 16-2: Adding a new item to the To Do list Notice the Sharing link at the right end of the navigation bar at the top of the list in Figures 16-1 and 16-2. When the link is clicked, it brings up a page that allows you to input an email address for the person you want to set up as a sharer. Ta-da List then emails a code to that address that lets the recipient modify the list you’ve shared. Sharing is made possible because both you (the list owner) and the list sharer are using web browsers to alter information that is shared on a single, remote webserver that anyone with the correct code can access. In this chapter I’ll teach you what you need to know to build your own collaborative To Do list Ajax application. However, since such an application is complex and involves a fair amount of code (which pulls together elements from every chapter of this book), I will cover the application in depth only in Chapter 17. The Power of Webservers Until now, we have focused on JavaScript programs, which run in a web browser. These programs can save information on the local computer and rely on the local computer for their system resources. This chapter will focus on programs that run on webservers—programs that save information to a remote server and rely on that webserver for much of the heavy lifting. Server-Side Aj ax 301 We touched briefly on webserver-based programs in Chapter 7 when we discussed submitting forms to webservers. However, in that chapter, once the information was sent from the web browser to the webserver, we didn’t worry about it. Now we do; it’s time to dig into the details of webserver programs. You can use programs that run on webservers to enhance your JavaScript in two ways. First, when a JavaScript program interacts with a server-side program, every web browser running that JavaScript can access and interact with the same webserver. For example, if 100 (or 10,000) people use that JavaScript, then all can interact with the same webserver. As a result, everyone’s information can be stored in one central spot: the server. In contrast, when we use cookies to store information, the information is stored only on the user’s machine. Because cookies store information locally, we’re prevented from doing useful things such as compiling answers to a survey taken by multiple users. On the other hand, when a server-side program is used to store those answers on a webserver, all of those answers can be collected and analyzed simply by accessing that webserver. You can also use server-side programs to enhance your JavaScript by invoking the “magical” powers of the machines running webservers. For example, although you can’t use JavaScript to send email via a web browser (the browser doesn’t know how to send email), a computer running a webserver may be able to send email, so you may be able to use it to send an email with information submitted via a web browser form. Because a webserver can communicate with other Internet-connected servers, you can also use a webserver to circumvent one of the limitations of the request object that we covered in Chapter 14. Specifically, for security reasons, many web browsers, such as Firefox, will not let JavaScript that comes from one webserver send an Ajax request to another webserver—a limitation that can be quite restrictive. For example, imagine that you want to write some Ajax that requests information from Google Maps and combines the returned information with weather information from weather.com, perhaps marking spots on the map where temperature records have been broken that day. Although some browsers will stop an Ajax script from using a request object to get information directly from weather.com, you can write an Ajax script that contacts a webserver, have the webserver get the information from weather.com, and then send that information back to the browser. Figure 16-3 illustrates this transaction nicely. On the left side of the figure, you see a browser requesting and receiving a page from the No Starch Press website. The returned page contains some Ajax code that tries to use a request object to get information from the weather.com server. (I don’t know; they’re really into the weather in San Francisco.) Unfortunately, this request is illegal, and it triggers a “Permission denied” error in Firefox and other browsers. We circumvent this error by using the technique demonstrated at the right side of Figure 16-3. This time, when the web browser requests a page from NoStarch.com, the Ajax in that page makes another request to NoStarch.com asking a program running on the NoStarch.com webserver to request information from the weather.com server. When the weather.com server answers that 302 Chapter 16 request, the NoStarch.com server-side program passes the information back to the user’s web browser. Because the web browser never directly requests information from the weather.com server, the action is allowed, and you don’t see the “Permission denied” error. This style of communication is possible only with server-side programs. Next, you’ll learn some server-side programming basics. Illegal Ajax NoStarch.com weather.com Legal Ajax NoStarch.com  Browser requests and receives page with Ajax from NoStarch.com. NoStarch.com  Browser requests and receives page with Ajax from NoStarch.com. NoStarch.com weather.com weather.com  Request object asks NoStarch.com to get data from weather.com. NoStarch.com weather.com  NoStarch.com requests and receives data from weather.com. weather.com server  Request object can’t request data from weather.com. NoStarch.com weather.com  NoStarch.com sends data back to web browser. Figure 16-3: Cross-server communication using Ajax A Server-Side Programming Language Webservers can run programs written in many different programming languages, but JavaScript isn’t one of them. Therefore, instead of JavaScript, we’ll use PHP as our server-side programming language. The acronym PHP stands for PHP: Hypertext Preprocessor. (This kind of self-referential naming passes for humor among computer programmers.) PHP is popular because its code can be incorporated directly into HTML pages, it’s free, and it’s cross-platform compatible. NOTE In order to try the examples in this chapter, you’ll need access to a webserver that runs PHP. See “Setting Up a Webserver and PHP” on page 273 for some resources describing how to set one up for Windows, Mac, and Linux computers. Popular alternatives to PHP include Perl, C++, C#, Python, Ruby, and Java (which is different from JavaScript; remember Chapter 1?). The language you use will largely be determined by the languages your webserver will run and what you’re familiar with. (Don’t worry too much about having to learn PHP in order to do Ajax. PHP and JavaScript are very similar in many ways.) Server-Side Aj ax 303 PHP Basics PHP code can sit in its own text file, or it can be integrated into the HTML of a web page. The characters mark the end of the code. Names of files containing PHP code generally have the extension .php rather than .html. Figure 16-4 shows the “Hello, world!” program, which tradition dictates should be your first program in any language. "Hello, world!" in PHP

My First PHP Program

X Figure 16-4: A basic PHP program If you copy the contents of Figure 16-4 into a file, name it something ending in .php, and put the file into a directory accessible by a webserver that understands PHP, you’ll see something like Figure 16-5. NOTE PHP programs must be run by a webserver. This means that you cannot simply “open” a PHP file using your browser. Instead, you need to enter the URL of the PHP program into your browser. If you put the PHP program in Figure 16-4 in the top-level directory of your webserver and name the file hello.php, you can access the file using this URL: http://localhost/hello.php. If that doesn’t work, try http://127.0.0.1/hello.php. If that doesn’t work, check your webserver’s documentation to determine how to connect with your webserver. Figure 16-5: The web page resulting from Figure 16-4 That’s it—your first PHP program. Now let’s see what it does. The code in Figure 16-4 is very simple. First, note that it’s mostly HTML. The PHP starts with the opening characters in X and ends with the closing characters in Z. The only real line of PHP (Y) is the one that uses the PHP function print to put the string “Hello, world!” into the web page. This is like JavaScript’s document.write() function. 304 Chapter 16 NOTE As in JavaScript, strings in PHP are contained in quotation marks. When a PHP-savvy webserver reads in a file with a name ending in .php, it looks for PHP statements between characters and executes them. The result is a new web page that is sent to the web browser—in this case, a page with the string “Hello, world!” inside it. This transformation is similar to what happens when a web browser reads in a page with JavaScript. It looks for code between tags, executes the code, and shows the user the result. A web page can contain both PHP and JavaScript. If it does, the page is transformed twice: First, the page is read by the webserver, which executes the PHP code and sends the result to the web browser. Next, the browser executes the JavaScript code and displays the result to the user. Sending Simple Input to PHP with a GET Request Server-side programs generally take input from a web browser and use that input to determine what to send back to the browser. For example, with Google Maps, the input might be coordinates on a map, and the output of the server-side program would be a new map. With the Ta-da List To Do list, the input might be a new To Do item to save and the output might be a message saying whether or not the new item was successfully saved. Input can be sent to a server-side program as part of a GET request or as part of a POST request. A GET request is used when the input you are sending to a server-side program is fairly short, such as sending a coordinate to Google Maps to be mapped. A POST request is typically used when the input is longer, such as the contents of a new To Do item. Let’s start by focusing on GET requests. Passing Input in a URL We used GET requests when we requested a test file from our hard drive in Chapter 14. Here is an example: request.open("GET", "my_file.txt"); This request has two parameters. The first indicates that we’re making a GET request. The second tells JavaScript what we are requesting, in this case, the file named my_file.txt. However, rather than requesting a local file, a GET request usually goes to a webserver that is running a server-side program. Instead of the name of a file, the request is typically a specially formatted URL that has two parts: one part that indicates where a server-side program is running, and another part containing input to send to the program. It’s easiest to describe the format of this special URL with an example. Here’s the URL used to ask Google Suggest to return a set of search terms that start with the string no starch: http://www.google.com/complete/search?js=true&qu=no%20starch Server-Side Aj ax 305 Type that URL into your browser, and you’ll get results from Google that look like this: sendRPCDone(frameElement, "no starch", new Array("no starch press", "no starch", "no starch diet", "no starch recipes", "no starch publishing", "no starch publisher", "no starch books", "no starch diets", "no starch publications", "no starch vegetables"), new Array("512,000 results", "1,150,000 results", "312,000 results", "162,000 results", "271,000 results", " ", " ", " ", "401,000 results", "237,000 results"), new Array("")); The results may look like nonsense right now, but we’ll soon use them to create a simplified version of Google Suggest. There are a few interesting things about this URL. The part before the question mark (http://www.google.com/complete/search) is just like a normal URL; it points to where the resource lives on the Internet. The question mark (?) indicates that the rest of the URL is input to be sent to the resource. Input sent in a GET follows the form key1=value1&key2=value2&key3=value3 and so on. This example string is composed of three key-value pairs, joined with ampersands (&). The three key-value pairs are key1=value1, key2=value2, and key3=value3. A key-value pair is much like a variable and a value to store in that variable. When this input is sent to the server-side program, the program will access the values value1, value2, and value3 using the keys key1, key2, and key3. We’ll see how to do this in a moment. NOTE Keys don’t need to be named key1, key2 and key3. Like variables, they can be named anything that begins with a letter or an underscore. Turning back to Google Suggest, the input js=true&qu=no%20starch contains two key-value pairs: js=true and qu=no%20starch. The first of these key-value pairs (js=true) tells Google that you want the reply to come back in a single line of JavaScript. The second key-value pair (qu=no%starch) is the actual string you want Google to search for. Notice the %20 in the value? Spaces are not allowed in URLs, so we use the hexadecimal ASCII value for a space instead. Different resources will require different inputs. There are three ways to determine what form the input is supposed to take: One is to read the documentation provided by the resource (or someone else); the second is to code the resource yourself (as we’ll do in this chapter); and the third is to deconstruct the JavaScript used by the resource by viewing the source on the web page that calls the resource. How did I know that Google Suggest needs keys named js and qu, and that the value for js needs to be true? I read it in a good article (at http://serversideguy.blogspot.com/2004/12/google-suggestdissected.html). If you’re writing your own server-side script, you’ll go with the second option—you’ll be coding the resource yourself. Using PHP to Read the Inputs of a GET Request Consider the following URL: http://localhost/myKeys.php?name=dave%20thau&job=slacker 306 Chapter 16 This URL points to a PHP program called myKeys.php. The text file containing the program resides on a webserver running on my local computer, so I can reach it using the domain localhost instead of something like nostarch.com. This URL contains two input keys: name and job. Now the question is, how can the PHP program access and use this input? The answer lies in PHP’s built-in $_REQUEST variable. Figure 16-6 shows the results of running a simple PHP program that reads some keys from a URL like the one above and displays them in a web page. The code for this PHP program is shown in Figure 16-7. Figure 16-6: A web page displaying PHP parameters Reading Keys

Reading Input Keys

X Y The value for key name is
The value for key job is
Figure 16-7: Accessing GET parameters in PHP Like JavaScript, PHP has many built-in variables. One such variable is $_REQUEST, which contains all the keys sent to the PHP script using either GET or POST. To get the value of a GET key, just include that key’s name in quotes between open and close brackets of the $_REQUEST variable. (In contrast to JavaScript, PHP variable names all begin with a $ sign, and they do not have to be declared with var.) Now you should be able to understand the code in Figure 16-7. Line X sets the $name variable to the value of the name key retrieved from the built-in PHP $_REQUEST variable. This value is then inserted into the web page in Y. Server-Side Aj ax 307 Creating a Google Suggest Application with an Ajax GET Request Let’s take what we’ve covered so far and build a useful application with it. Figure 16-8 shows a homemade interface to the Google search engine that works much like Google Suggest. As you can see in the figure, I’ve typed the first few letters of the word javascript, and the application is showing how many results would be returned by searches starting with those letters. Figure 16-8: Searching for javascript in our version of Google Suggest The page you see in Figure 16-8 is very similar to the translator example in Figure 15-10. In that example, we used Ajax to read a file containing English words and their Italian translations and then used the information in that file to show the words that matched specific user input. In Figure 16-8 the information we’re showing comes from Google rather than from a file. In the following sections, I will modify the code in Figures 15-6, 15-11, and 15-12 to create a simple homemade version of Google Suggest that actually retrieves data from Google. Contacting Third-Party Webservers with Ajax and PHP The main challenge when modifying the code in Figures 15-6, 15-11, and 15-12 will be to retrieve information from Google instead of reading a file from the hard drive. Line Z in Figure 15-6 looked like this: request.open("GET", the_file + ".xml"); This line tells JavaScript that we are requesting a file. In the section “Passing Input in a URL” on page 305, we saw how to format a URL with inputs that, when entered into a browser, get you some results from Google. It would be nice if we could simply put this URL in the second parameter of the open() method instead of a filename. Then, instead of requesting a file, we would be requesting information from Google. Unfortunately, because of the Ajax security limitation described by Figure 16-3, we can’t use Ajax to query Google directly for results. Instead, we have to write a PHP script that queries Google for us. 308 Chapter 16 Our solution will require two different files: a client-side file, which will contain the HTML, JavaScript, and Ajax calls, and a server-side PHP file, which will take user input from the web browser and use it to request information from Google. When Google responds to the server-side PHP program’s request, the server-side PHP program sends the information back to the browser, which displays it. This application is a bit complicated, so before getting into the nittygritty of the code, let me sketch out how the code will work. As usual, the action starts when a visitor types something into the text box in Figure 16-8. With each keystroke in that box, the following occurs: 1. A JavaScript function sends an Ajax request to a PHP program (which will be described shortly). The request includes as input the letters typed into the text box. 2. The PHP program sends a request to Google asking about the number of search results for words starting with those letters. 3. Google responds. 4. When the response is received, a JavaScript function called displayResults() parses Google’s response and displays the answer. Let’s start by looking at the JavaScript side of this application. The JavaScript for the Homemade Google Suggest Application Figure 16-9 shows you the client-side code for Figure 16-8. Much of the code in Figure 16-9 is similar to the code in Figures 15-6, 15-11, and 15-12, so I’ll just discuss the changes. Querying Google Suggest
]
Figure 16-9: The client-side Google Suggest code 310 Chapter 16 As is typical of Ajax, most of the action occurs when the user does something. In this case, whenever a user types a character in the box, the code in ] calls getSuggestions() with the box’s contents. This function is much like the typical Ajax functions you’ve seen many times now (e.g., doAjaxCall() in Figure 14-4). It gets a request object, tells the object what request to make and what to do when the response is received, and then sends the request. For example, in Figure 16-9, the request object is told to request information from the URL described in X and Y. Dealing with Spaces in URLs When getSuggestions() is called in ], it is passed the string of characters that appear in the text box. This string may contain spaces or other characters that are not allowed in URLs. Now recall the built-in JavaScript function escape() from Chapter 12. This function converts a string into something that can be legally saved in a cookie, and it encodes strings so that they may be sent in a URL (turning each space into %20, for example). Once the escape() function does its magic, Y creates the full URL of the PHP program used to query Google. This URL points to a document called Fig16-10.php, which is served up by my local webserver. At the end of the URL we see a question mark, the key name word, an equal sign, and then the URL-legal value of the characters the user entered in the text box. Next the request object contacts the PHP program named in the URL and sets as input the letters typed into the text box. The PHP program (which we’ll see in Figure 16-10) uses that input to request information from Google. When the request is sent, and the answer received, the code in Z executes, calling the function displayResults() and sending it whatever text the PHP program returned. The Response from Google The rest of the script displays the information that our PHP program received from Google and passed back to our JavaScript. To make sense of it, let's first see what Google actually sends. Because the PHP program asks Google to send the information back in a JavaScript-friendly form, Google’s response looks like this: sendRPCDone(frameElement, "javascript", new Array("javascript", "javascript tutorial", "javascript reference", "javascripts", "javascript array", "javascript alert", "javascript window.open", "javascript redirect", "javascript substring", "javascript tutorials"), new Array("50,200,000 results", "6,100,000 results", "7,880,000 results", "1,530,000 results", "1,500,000 results", "2,230,000 results", "526,000 results", "557,000 results", "248,000 results", "4,660,000 results"), new Array("")); Although it may not seem obvious, this response is actually a call to a Google-created JavaScript function named sendRPCDone(), which is called with five parameters: frameElement, "javascript", two big arrays, and then an empty array. Server-Side Aj ax 311 The only things we care about are the two big arrays. The first array contains the words that match the input "javascript". The second array contains the numbers of results that each of those words would return if used in a Google search. For example, the first element in the first array, "javascript", will return the number of results stored in the first element of the second array, 50,2000,000 results. The sendRPCDone() function is defined somewhere by Google. It probably does many interesting things with the function’s five parameters and then displays the results on a Google-friendly web page. But we don’t care how Google uses that function. We're going to define our own sendRPCDone() function that will do what we want it to do: format the contents of the function’s second and third parameters and display the formatted information in our web page. Processing the Google Results—The Magic of eval() Recall that Z in Figure 16-9 sends the results returned by Google to a function called displayResults(). The first line of that function is very interesting because it uses a built-in JavaScript function called eval(). The eval() function takes a string and forces JavaScript to evaluate it. For example, if we run the following two lines, we’ll end up with the_solution as 8: var the_add_string = "3 + 5"; var the_solution = eval(the_add_string); Notice that the_add_string is a string. If we printed the_add_string using document.write() or alert() statement, it would print out 3 + 5. The eval() function, however, treats the string 3 + 5 as if it were a JavaScript statement and evaluates it. As just discussed, that big string returned by Google is actually a sendRPCDone() function call with parameters that contain the information we requested. When the Ajax request has been completed, Z passes the string to the displayResults() function, at which point the eval() in [ evaluates and executes it. Because we’re writing the JavaScript, we can write the sendRPCDone() function so that it will transform the two big arrays sent by Google into something that our displayResults() function can handle. Displaying the Results Like the displayResults() function in Figure 15-12, this one displays an array of items in a div. In Figure 15-12, each item in the array was an English word, followed by a tab (\t), followed in turn by an Italian translation of that word. The displayResults() function formatted each item and then put the resulting lines into a div. The displayResults() function in this example does exactly the same thing: It too displays a group of items in an array, where each item is a search term, then a tab, and then the number of results that you’d get if you searched for the term in Google. 312 Chapter 16 The sendRPCDone() function takes the results retrieved from Google and puts them into an array for displayResults() to process. Take a look at sendRPCDone() in Figure 16-9. It takes the two big arrays, loops through them, creates a string of the form search result, tab, number of results, and adds that string to a new array. Finally, it sends that new array back to displayResults(), which puts it into our div, just as displayResults() did in Chapter 15. Using PHP to Contact Other Webservers That does it for the JavaScript side of this example. To recap, a user types something into the text box. Each key press calls the getSuggestions() function, which uses a request object to send a request to our PHP program. The PHP program then passes the request along to Google. Google answers the PHP program with that big sendRPCDone string, and the PHP program sends the string back to the request object. When the request object has received the string, the displayResults() function is called. This function calls eval() on the sendRPCDone string, and this evaluation results in a call to the sencdRPCDone() function we wrote. This function takes the response from Google and returns an array, which displayResults() then uses to update the web page. The piece we need to add is the PHP program that takes the request from the JavaScript, sends it to Google, receives the answer from Google, and then passes the answer back to the JavaScript. You can see that PHP program listed in Figure 16-10. fetchtext($googleURL); ] print $snoopy->results; ?> X Y Z [ Figure 16-10: The Google Suggest server-side program When this PHP program is called, the value of the word key in the URL that is defined in Y in Figure 16-9 is automatically stored in the $_REQUEST["word"] PHP variable. The PHP program uses that value to create a Google URL with two keys, js and qu (as discussed in the section “Passing Input in a URL” on page 305). Setting the first key to true means we want our results to come back as JavaScript—that is, as that long string returned by Google, the one that starts with sendRPCDone. The second key identifies the phrase to search for. Server-Side Aj ax 313 Let’s start at the top of the script. The first line (X) provides access to a PHP library named Snoopy. Just as you can import external JavaScript files into your JavaScript code with a line like

Make Your Dream Unchanging

Your Name:
Your Favorite Dream:

Server-Side Aj ax 317 _
Figure 16-12: Sending an Ajax POST Clicking the button in _ calls the submitMe() function. This function is sent a pointer to the form, and X reads the contents of the form and constructs the string that will be sent to the PHP program. The URL of that program is defined in Y. Notice that the only information in the URL is the location of the program; there is no additional input. In Z we tell the request object about this URL and that we’re going to send a POST-style request. Line [ further specifies that the information we’re sending the server-side program is coming from a form. Finally, ] sends the request and passes the string constructed in X. The PHP program will process this message string and return some results. When the results are fully loaded into the request object, \ will place them into the div that initially contains the form (^). Replacing the contents of the div will replace the form with whatever message has been sent back by the PHP program. Sending XML Information from the Browser to a Webserver Don’t forget that the X in Ajax stands for XML. XML files can be sent to a PHP program just like any other contents. Because XML tends to be lengthy, it’s generally best to send it by using the POST method and putting the XML into the request object’s send() method. HEAD Requests: Getting Information About a Server-Side File The previous sections described how to use GET and POST methods to send information to a server-side program and retrieve the server-side program’s response. Sometimes, in addition to the information returned by the webserver, a response can contain information about the response itself. This kind of information, sometimes called metadata, is stored in a normally invisible part of the response called the response header. A response can have many headers. Headers might include information such as the number of kilobytes in the response, when the response was sent, and when that file was last updated. Here are some of the headers returned by Flickr.com when it answers an Ajax request: Date: Wed, 20 Dec 2006 21:11:46 GMT Server: Apache/2.0.52 Content-Type: text/xml; charset = utf-8 318 Chapter 16 These are just three of the headers Flickr sends back. The first one, named Date, sends back the time the response was sent. The header named Server describes the kind of webserver Flickr uses. The last header, Content-Type, gives you information about the format of the response (it’s XML, sent using the UTF-8 character set). These headers can be very useful. For example, in Chapter 17 we will discuss the details behind developing a multiuser To Do list application. In order to create a sharable To Do list, we will store the To Do list information in a file on a webserver so that it can be modified by many different users. When two people are working on a To Do list at the same time, one user should see the changes made by the other user soon after those changes have been made, without needing to reload the page. In order to have our Ajax program always display the most up-to-date version of the To Do list, we might refresh the file every few seconds. However, if there are many items on the To Do list, the file containing the list might become very large. Rather than repeatedly download a very large file that may not have changed, we can simply look up the last time it was modified and use this information to see whether we need to get a newer version of the file. When a webserver responds to any request, it can include response headers. When you are interested in a header but don’t want to retrieve the entire response, you can use a HEAD request to retrieve just the response headers: request.open("HEAD", the_URL); When the request is answered and the response has been downloaded into the request object (the request object is in readyState 4) you can access the header information with the request object’s getResponseHeader() method. The date and time a file was last modified is usually sent in a header named Last-Modified, which can be retrieved by calling the getResponseHeader() method with the string "Last-Modified": var last_modified = request.getResponseHeader("Last-Modified"); Using the returned value to create a new Date() object makes it easy to access the information. Here is an example: var last_modified_date = new Date(last_modified); (In Figures 16-15 and 16-16 at the end of this chapter, you’ll see an example of using a HEAD request to see whether a file has been updated.) Adding Headers to Your Responses Headers, such as the Last-Modified and Date header just described, are added to a response by the server-side program that sends the response. To add a header to a response sent by PHP, use PHP’s header() function, which takes a string describing the header as a parameter. For example, to set a header named My-Header, use the following: header('My-Header: I am a header'); Server-Side Aj ax 319 The header information is sent as soon as PHP sees this line. The line should appear toward the top of your PHP program, before any print commands. If you try to set a header after using print, PHP will give an error. An example of setting headers will be shown soon in Figure 16-16. Headers and XML In Chapter 14 you saw two different ways to access the information stored in the request object: responseText and responseXML. A string version of all responses is stored in the request object’s responseText property, and if the response is an XML document, an XML version of the response is accessible in the responseXML property. (The XML version is nice because it allows you to navigate the XML document using the XML-handling methods we discussed in Chapter 15.) The request object needs to know that the response is an XML document before it will store the response in the responseXML property. To tell it that your response is XML, set the header information of the PHP response using the header() function. Simply placing the following line in your PHP program before using print to send a response should do the trick: header("Content-Type: text/xml"); This will tell the request object that this response is an XML document. The Caching Problem We have now seen three different kinds of requests: GET, POST, and HEAD. Each of these requests requires a URL pointing to the resource being requested. In some situations, such as the interactive To Do list application we’ll be discussing in Chapter 17, a file may be requested multiple times during the course of a user’s interaction with the application. Although the contents of the file might change, the URL pointing to that file does not. This situation can cause problems for some browsers. Internet Explorer, for example, is notorious for not updating a web page even though the page’s contents have changed. Firefox and most other browsers generally behave as you would expect, updating the web page with the new information. Internet Explorer, however, decides whether or not to update the page based on the URL used in the request. If that URL looks familiar, IE assumes that the new page is just like the old one (it has the same URL after all), and it won’t update. This is bad news for Ajax, because it means that the new information won’t be shown. Happily, there is an easy fix for this problem: Make each URL look different every time. Here is an example: var the_URL = "http://mydomain.com?ignoreMe=" + new Date().getTime(); 320 Chapter 16 Recall from Chapter 2 that the getTime() method of a Date object returns the number of seconds between the time the method is called and January 1, 1970; a number that will differ every second. Setting a parameter such as ignoreMe equal to the results of getTime() makes the URL different every time the URL is used. This will trick Internet Explorer into thinking it’s a new URL, inducing IE to update the page. We’ll see an example of this trick in Figure 16-15. File Handling in PHP PHP programs can read and manipulate files that reside on webservers. With PHP, you can read a text file, create a new text file, and edit the text in a file on the server. Once a file is created on a webserver, it can be accessed by any web browser. When a webserver file is edited, those edits will be seen by anyone looking at the file. Creating and Adding Contents to a Text File with PHP To use PHP to create a new text file, or to change the contents of an existing text file, you must: 1. 2. 3. Open the file and signify that you want to write contents to the file Write text to the file Close the file To open a file for writing, use PHP’s fopen() function. This function takes two parameters: the name of the file you want to open and either a "w" if you want to replace the existing contents of that file with new text, or an "a" if you want to add text to the end of the file. The fopen() function returns a value, which you can use in your PHP program to refer to the file you’ve just opened. For example, to open myFile.txt for writing, use this line: $myFile = fopen("myFile.txt", "w"); NOTE When you open a file with "w" as the second parameter, the old contents of the file are deleted. Therefore, if you want to edit the contents of a file, you should first read the contents of the file into a variable, then edit the contents of the variable, and then write the contents back to the file. We’ll be doing this in Chapter 17. Once a file has been opened, use the PHP function fwrite() to write to it. This function takes the value returned by the fopen() function and the string you want to write to the file. The function returns either TRUE or FALSE, depending on whether or not it succeeded in writing to the file. (Writing may fail for several reasons: the hard drive might be full, or the webserver might not have permissions to write to the file.) For example, to write two lines to the file you opened above, use this line: $success = fwrite($myFile, "line one\nline two"); Server-Side Aj ax 321 The \n puts a line break into the file, which creates a two-line file in this case. If the write is successful, $success will contain the value TRUE; if not, it will contain the value FALSE. Once you’ve written to a file, close it with fclose(): fclose($myFile); Combining these lines gives you the PHP script below: One of the more pernicious problems you’ll encounter when dealing with server-side programming is that of ensuring that your webserver has permission to alter the files you want to alter. Sometimes a PHP program can fail to write to a file because the webserver running it does not have access to that particular file. If this happens, PHP will give an error like this: Warning: fopen(yourFile.txt) [function fopen]: failed to open stream: Permission denied. File permissions work differently on different operating systems. If you get this kind of error, refer to your operating system’s manuals to determine how to inspect and modify file permissions. Reading Files in PHP It’s a bit trickier to read a file using PHP than it is to write to a file. The complication arises because the contents of a file are read line by line, and PHP needs to know when it has reached the end of a file so that it can stop reading. Luckily, the PHP function feof() will tell PHP when it has reached the end of a file. This function takes a variable that points to an open file (such as $myFile) and returns TRUE when the end of the file has been reached. Figure 16-13 shows an example of PHP reading a file. Figure 16-13: Reading a file with PHP In Figure 16-13, X opens the file for reading and puts a pointer to the opened file into the variable $myFile. The most complicated line is Y, which calls the feof() function on $myFile to see whether PHP has reached the end of the file. If not, feof() returns FALSE, and the line inside the while loop is executed. This line uses the function fgets() to read a line from $myFile. It takes that line and attaches it to the end of the $contents variable, so each time through the loop the next line of $myFile is appended to the end of $contents. Eventually, the last line of $myFile will be read and the feof() function will respond with TRUE. When that happens, the loop ends, and the program returns the contents of the file. NOTE Notice how similar PHP and JavaScript are. They have identically structured while loops, they both use two equal signs to see whether two things are the same, and they both use the values TRUE and FALSE (although in JavaScript these values are lowercase). When Communication Breaks Down When a web browser contacts a webserver for information, many things can go wrong. Here are some examples: z The page being requested may not actually be on the server. z The user may not have permission to access the page. z If a server-side program is being called, something might go wrong with that program. z The server might take too long to get back to the web browser, and the browser might stop waiting. When a request object sends a request and then says that the request has been fulfilled (its readyState is 4), all we really know is that the request has been answered in some way. Everything could have gone well, with the server sending the information requested, or something may have gone wrong. To determine how the client-server communication went, we can check the status property of the request object for a status code, as listed in Table 16-1. The most frequent numbers you’ll see are 200, if everything went well; 404, if the URL provided to the request object does not exist on the server; and 500, if the request went to a server-side program, but something went wrong with the program. Somewhat less frequently you may see a 401 or 403 if the page or program you are trying to access is password-protected, 408 if the server took too long to respond, or 503 if the server exists but the serverside program you are sending the request to does not. Server-Side Aj ax 323 Table 16-1: Request Object Status Codes Status Code Meaning 200 OK 204 No Content 400 Bad Request 401 Unauthorized 403 Forbidden 404 Not Found 407 Proxy Authentication Required 408 Request Time-out 411 Length Required 413 Requested Data Entity Too Large 414 Requested URL Too Long 415 Unsupported Media Type 500 Internal Server Error 503 Service Unavailable 504 Gateway Time-out Typically, you should make sure that the request was satisfied and everything went well (status code 200). To do so, add an if-then statement to JavaScript functions that make Ajax calls, as shown in Figure 16-14. request.open("GET", some_url); request.onreadystatechange = function() { X if (request.readyState == 4) { Y if (request.status == 200) { doSomething(); } else if (request.status == 404) { Z document.getElementById("errorDiv").innerHTML = 'Sorry, the page you are accessing could not be found.'; } else if (request.status == 500) document.getElementById("errorDiv").innerHTML = 'Sorry, there was a problem with the server.'; } else { document.getElementById("errorDiv").innerHTML = 'Sorry, communication breakdown. Please try again.'; } } } Figure 16-14: Adding a status check to an Ajax call In this code sample, once the request object has reached readyState == 4 (X), we check its status. If the status is 200 (Y), then we do whatever it is that we want to do when the request has been answered. If not, then we want to tell the user that something went wrong—in this example, by putting a message into a div with the id of errorDiv (Z). 324 Chapter 16 Automatically Updating a Web Page When a Server-Side File Changes Figures 16-15 and 16-16 demonstrate how to use HEAD calls, server-side file reading, and the cache-tricking technique to read a file from a webserver, display its contents, and update the contents whenever the file on the server changes. This type of application is useful whenever more than one person can update a file on a webserver—for example, if two people have access to the same To Do list. Automatically Updating Display of a Changed File
Figure 16-15: Client-side checking for updated server-side file Figure 16-15 lists the client-side portion of the application. Clicking the Read the File button in the form at the bottom calls the callReadFile() function and sends it the name of a file to read. The callReadFile() function does only one thing—it calls a function named readFileDoFunction(), which does the actual work of getting the file. We’ll take a look at readFileDoFunction() first and then turn back to callReadFile(). 326 Chapter 16 readFileDoFunction() The readFileDoFunction() function is a very generic function that deals with situations where you want to use Ajax to read a file and then execute some function. In all the Ajax examples up until now, functions that made Ajax calls had a couple of lines like this: request.open("GET", some_url); request.onreadystatechange = function() { if (request.readyState == 4) { doSomething(); } } As you know, this tells a request object where a request should be sent and what to do when the request has been satisfied. The readFileDoFunction() function does the same thing, but it’s a bit more flexible. The function is sent three parameters: the name of a file to read, the way to read it (use a GET or a HEAD call), and the function to execute when the readyState changes. Line Z in the function takes the first parameter, the name of the file, and creates a URL with it. NOTE Notice that the URL has "&t=" + new Date().getTime() at the end. This makes the URL look different every second and overcomes Internet Explorer’s overzealous caching by tricking it into thinking that you’re requesting something you haven’t requested before. Lines [ and \ are the new versions of the typical Ajax lines mentioned above. Line [ tells the request object the kind of call to make (GET or HEAD) and where to send the request. Line \ assigns the function that should be called when the request object’s readyState changes. Normally, an anonymous function would go after the equal sign, but in this case we put a variable which holds the anonymous function there. callReadFile() Now let’s look back at the callReadFile() function to see what it’s doing. Line X calls the readFileDoFunction() function just described. This function takes three parameters, the first two of which are the name of the file, which was sent to callReadFile(), and the type of call we want to make, which is a GET call. The third parameter, which starts in Y, is an entire anonymous function. We’re taking the function that we normally would have put after the equal sign in \ and passing it as a parameter to readFileDoFunction(). This technique is nice because it means that we can use readFileDoFunction() whenever we want to use Ajax to read in some file and execute some function once the file is read. In the case of callReadFile(), which is called when a user clicks the Read the File button, we want to read in the file whose name was passed into callReadFile(), numbers.txt; then, when the file has been completely read, Server-Side Aj ax 327 we want to get the Last-Modified header of the file that was read and then call the displayResults() function, which will display what was retrieved from the file. The displayResults() function takes three parameters: the contents of the file we have just read, the name of the file we’ve read, and the number of seconds between January 1, 1970 and the time the file was last modified (from now on, let’s just call that the last modified time). The function first displays the contents of the file by putting them into the div with the id of contents. Then ] sets up a time-out that will call the callUpdateIfChanged() function in five seconds. Once five seconds have passed, this function does a HEAD call to read the Last-Modified header of the file. If at some point during the last five seconds the file has changed, the new Last-Modified header will differ from the one we retrieved when we first read the file. If the new Last-Modified value is different, the new version of the file will be read, the web page will be updated, and the last modified time will be updated to reflect the fact that the file changed. callUpdateIfChanged() Like callReadFile(), callUpdateIfChanged() does just one thing—it calls readFileDoFunction(). In this case, however, we’re doing a HEAD call and sending a different anonymous function to be called when the request object’s readyState changes. This anonymous function gets the value of the new Last-Modified header, checks to see whether the time is different from when we read the file the first time, and, if it is, makes another call to callReadFile(). Just as before, callReadFile() reads in the file and sets the last modified time. Lastly, callUpdateIfChanged() creates another time-out to call callUpdateIfChanged() again in five seconds. stopTimer() The only function left to describe is stopTimer(), which simply cancels the most recently set time-out. This function is called when the user clicks the Stop Checking button. Recap and Breathe Summarizing to this point, the interesting elements in Figure 16-15 include passing an anonymous function as a parameter to another function, using a HEAD call to retrieve the last modified time of a file, and attaching a new Date().getTime() to a URL to trick Internet Explorer into thinking you’re making a request that is different from one you made earlier. The Server-Side PHP Code Now let’s turn to Figure 16-16, which lists readTextFile.php, the server-side program called in Z. 328 Chapter 16 Figure 16-16: The readTextFile.php called in Z of Figure 16-15 The PHP code in Figure 16-16 is fairly straightforward. After getting the name of the file to read from PHP’s built-in $_REQUEST variable, the code in X sends the Last-Modified header to the browser. The tricky part of X involves using built-in PHP functions to create a date and time that JavaScript can understand. The code uses two PHP functions: gmdate() formats the string, and filemtime() returns the time when the file named by $fileName was last modified. Next, the code checks to see whether this is a HEAD request, using the code in Y. This code looks at the built-in PHP variable $_SERVER["REQUEST_ METHOD"], which will store the value "GET", "POST", or "HEAD". If it is "HEAD", then all the PHP script should do is send the header information in X. If it is not a HEAD request, then the body of the if-then clause reads the contents of the file into the $contents variable, and Z sends that information to the browser. Summary Phew. Here’s a rundown of everything covered in this chapter: z How server-side programs let you store information from many users in one place and let you use facilities available to machines running webservers z How the server-side language PHP uses variables, if-then clauses, and loops, much like JavaScript does z How to use URLs and web forms to send information to server-side PHP programs z How to send GET, POST, and HEAD requests to a server-side program Server-Side Aj ax 329 z How to use PHP and the Snoopy library to contact other webservers z How to use PHP to save and read files on webservers z How to trick Internet Explorer into not caching your web pages z How to share XML information between client-side and server-side programs Congratulations! You have now learned practically all the JavaScript this book has to teach. The next chapter contains only a small amount of new information; it mostly applies all the JavaScript you’ve learned so far to the task of creating a multiuser Ajax-driven To Do list application. So sit back, take a break, and bask in your new JavaScript knowledge. Assignment If you didn’t complete the steps described in “Setting Up a Webserver and PHP” on page 273, do so now. 330 Chapter 16 PUTTING IT ALL TOGETHER IN A SHARED TO DO LIST This is it! The last big script of The Book of JavaScript! This is where we combine everything that we’ve learned so far to create a shared To Do list. This application draws from every chapter in this book. It uses the basic structure of JavaScript tags from Chapter 1, variables from Chapter 2, if-then clauses from Chapter 3, events from Chapter 4, window manipulation from Chapters 5 and 10, functions from Chapter 6, forms from Chapter 7, loops and arrays from Chapter 8, time-outs from Chapter 9, string handling from Chapter 11, cookies from Chapter 12, dynamic HTML from Chapter 13, client-side Ajax from Chapter 14, XML from Chapter 15, and server-side Ajax from Chapter 16. I’ll only cover part of the application here; your homework will be to complete it. Features of the To Do List Application Our shared To Do list application will have a membership base. New users can join the site, and once they’ve joined, can log in to and out of the site. When someone joins the site, that user starts with a blank To Do list, and I will call that user the owner of that list. The owner of a list can add items to the list and mark items as completed or not. A list owner can also designate other users as subscribers to the list. Subscribers can modify the To Do list just as an owner can. I’ll use the word editor to describe the list’s owner or one of the list’s subscribers. To review, the application will provide the following features: z New users will be able to sign up and create their own To Do lists z Current users can log in to and out of the site z Someone who has created a To Do list can allow other users to edit her list z List editors can add new items to a To Do list z List editors can mark items as completed z List editors can mark completed items as uncompleted In the scenarios that follow, two people, Nestor and Odysseus, have signed up for the To Do list service. Each has built his own To Do list and added items to it. Nestor has allowed Odysseus to see and modify his list, but Odysseus is keeping his own list private. Figures 17-1 through 17-6 show you the major features of the partial application. But first, a caveat. Although the design and user interface of this application are functional, they are also hideous. Apologies to those with delicate design sensibilities. Figures 17-1 through 17-3 show the process of clicking the login button and logging in. Notice at the bottom of Figure 17-3 that Odysseus can choose to see either his own list or Nestor’s list. If Nestor had logged in, he would see only his own list because Odysseus hasn’t shared his list with Nestor. Notice also that Odysseus can log out. Figure 17-4 shows the screen after Odysseus has chosen to see his own list. He has two uncompleted tasks on his To Do list. Figure 17-1: The view when first coming to the site 332 Chapter 17 Figure 17-2: After clicking the login link Figure 17-3: After Odysseus logs in Figure 17-4: Viewing Odysseus’s list Figure 17-5 shows the screen after he clicks the checkbox next to the first task in the Still Pending list, signaling that he has completed it. If Odysseus has made a mistake and didn’t really finish that task, he can click the checkbox next to the task in the Completed list and move it back to the Still Pending section. Finally, Figure 17-6 shows the screen after Odysseus has added a new item to his list. Figure 17-5: After marking the first task as completed Putting It A ll Together in a S hared To Do Li st 333 Figure 17-6: After adding a new item to the list The application uses the automatic updating trick from Chapter 16. If Nestor is looking at his To Do list, and Odysseus adds something to Nestor’s list, Nestor will automatically see his list update. The same is true for the To Do lists each person can see. If someone new, say Achilles, decides to let Odysseus have access to his list, and Odysseus is logged in, Odysseus’s page will automatically update to let him know that he now has access to Achilles’s list. There are three different types of files that make this application work: an HTML file with some JavaScript in it, which works in the browser; a serverside program, which runs on the webserver (a PHP program in this case); and some data files (XML), which store the information used by the application. Let’s turn first to the data files. To Do List Data Files The To Do list application uses two different types of XML files: One file, userInfo.xml, describes all users with access to the application. The second type of file represents a To Do list. Each user will have one To Do list file. userInfo.xml userInfo.xml contains the name, password, and profiles of all the users who have signed up to use the To Do list application. It also contains information about who can edit which lists. Figure 17-7 shows an example of userInfo.xml. 334 Chapter 17 X Y Z nestor cup King of Pylos, fought the centaurs nestor Z odysseus horsie Hero of the Iliad and Odyssey odysseus nestor Figure 17-7: XML representing information about users Let’s walk through this file. As with all valid XML files, the first line (X) declares that this is an XML file. Line Y declares the one root element in the file, users. The usernames odysseus and nestor follow in Z, inside the beginning and ending tags; these are the two users who have signed up for our application so far. Each username is followed with some specific information about that user including (but not limited to) a name, a password, a profile, and the lists to which that user has access. This XML file is updated whenever the user information changes; for example, if a new user joins, or if one user permits another to see his or her list. NOTE This partial version of the application does not have a “join” feature; adding one will be part of your homework. If it had such a feature, the file would update with information related to new users when they create an account in our application. To Do List File The second type of XML file contains information about a user’s To Do list. Each user owns one file, the name of which is based on the username. For example, Figure 17-8 shows the contents of odysseus.xml, which contains all the To Do list information shown in Figure 17-4. odysseus X Putting It A ll Together in a S hared To Do Li st 335 Y Z 1 Go with Nestor and Ajax to convince.... [ 2 Play with big wooden horse \ Figure 17-8: XML representing Odysseus’s To Do list, stored in odysseus.xml The root element in this XML file, list, contains three elements: the name of the list, a list of pending items (openitems), and a list of completed items (doneitems). As you can see in Figure 17-8, Odysseus has two tasks to complete (X and [), and has no completed tasks (there’s nothing between the tags in \). Each task in the list has two elements: a number (Y), which makes it easy to identify the item, and the item itself (Z). When Odysseus adds or changes an item’s status, the XML file odysseus.xml is updated. NOTE I invented the XML tags for both userInfo.xml and the To Do list file. If there was some generally accepted XML standard for To Do lists, I could have used that instead. To Do List Server Side This example uses only two straightforward PHP programs. The first, readXMLFile.php, reads in an XML file; it is almost a copy of the code in Figure 16-16. If a HEAD request was sent, readXMLFile.php returns only the lastmodified date of the file. If a GET request is sent, readXMLFile.php reads the requested file from the webserver and passes it to the browser. The only difference between Figure 16-16 and readXMLFile.php is that readXMLFile.php sends an additional header when responding to a GET request: header("Content-Type: text/xml"); The second server-side program, saveXMLFile.php, saves an XML file. Figure 17-9 shows the PHP code. As I hope you’ll see, it’s very similar to the program we used to write out a text file in “Creating and Adding Contents to a Text File with PHP” on page 321. Figure 17-9: PHP program for saving a string to a file Let’s take this program apart. This program receives a POST from the browser whenever a file needs to be saved. It is passed two keys: the name of the file to be saved and the contents of the file. These keys are accessed in PHP using X and Y. Line Z opens the file for writing, and [ writes the contents to the file. Before actually writing the contents to the file, [ calls the built-in PHP function stripslashes(). This function is particularly important because some versions of PHP add backslashes to quotes inside text sent for parsing, and we want to remove those backslashes. For example, because we’re sending XML information, the first line of the file we want to save is But when this is sent to some versions of PHP, it will be turned into The stripslashes() function removes those inserted backslashes. The To Do List Client Side, Part 1: The HTML Most of the power of our To Do list application is in the client-side code. The client-side code is quite long, so I’ll describe it section by section. For a listing of the entire client side, see Appendix D. Let’s first look at the body of the HTML file as shown in Figure 17-10. X Y

Login Section

Z

Content Section

[
Welcome! Please sign in to see your To Do lists. Putting It A ll Together in a S hared To Do Li st 337

To Do Lists You Can Access

\
Figure 17-10: The application’s HTML The body of the page is divided into four sections. The first section (Y) is reserved for error messages. Whenever anything goes wrong in the application (for example, if someone logs in with an incorrect password or if something goes wrong with the server when trying to read a file), a message is put into the innerHTML of the div with the id of errorDiv. The error message will be displayed in red because of the style attribute inside the div. Below that section, in Z, is a div with the id of loginArea. When the page is first read in, this div will contain the login link. When that link is clicked, the contents of this area are replaced by a form that lets a user enter a username and password. Once the user logs in, the form is replaced with a greeting and the ability to log out. The div in [ is reserved for displaying the contents of the list being viewed. It initially holds a greeting message. Finally, \ marks the div that will contain information about which To Do lists a person can view. By keeping the contents of the list being viewed in a div that is separate from all other lists, we make it easy to update one list without updating any others. Finally, notice that X the tag calls the checkIfLoggedIn() function when the page is loaded. This function ensures that if a logged-in user reloads the web page, or visits another page and returns to this one, the page recognizes that the user has already logged in and shows the user the appropriate information. The To Do List Client Side, Part 2: The JavaScript Now let’s turn to the JavaScript code. Imagine you are assigned the task of developing the JavaScript for this To Do list application. Where would you start? Even though this application is simple when compared to something like Google Maps, it is still complicated enough to make the task of writing the code seem overwhelming. When faced with a large problem, it is often helpful to apply a problem solving technique called divide and conquer. To solve a large problem, divide the large task into smaller ones, and then conquer the smaller projects one at a time. For example, the code in the To Do list application can be divided into several different feature sets: z z z z 338 Chapter 17 Logging in and out Displaying available lists Displaying a specific list Processing changes to a list Applying the divide and conquer technique means that you write the JavaScript to deal with all the features for logging in and out, then you write the JavaScript for displaying available lists, and so on. If any of these smaller tasks still seems overwhelming, apply divide and conquer again to break it up into smaller tasks that are easier to tackle. The rest of the chapter will describe the code for each of the feature sets just listed. As usual, we will write our own functions to complete the tasks. Although there are only four general feature sets, each will require many functions. But before getting into the code itself, let’s look at a road map for how the functions I will describe relate to each other. The Function Road Map Figure 17-11 shows each of the 27 functions I will describe. An arrow leading from one function to another means the first function calls the second function. The functions at the top of the figure are called by a user interacting with the web page in some way. As you can see, almost every function calls at least two other functions. readyMarkUndone readyMarkDone markUndone markDone addNewItem doLogin checkIfLoggedIn processLogin readyDisplayList displayLogin logout getNameFromCookie displayHomeInformation displayLegalLists addNewToFile displayList displayLists getUser updateTodoIfChanged getHighValue readFileDoFunction getItems updateUserIfChanged saveAndReload saveFileDoFunction getItemString getFirstValue Figure 17-11: Functions and their dependencies Functions with many arrows going into them are used by many others. For example, the getFirstValue() function is called by seven other functions, and the readFileDoFunction() function is called by six others. Putting the code of getFirstValue() in its own function means that the code can live in one place, rather than being repeated seven different times. If you had not yet been convinced of the magic of functions before seeing this application, you should be by now. (Don’t let the complexity of this diagram bother you; the descriptions in this chapter should make everything crystal clear.) Putting It A ll Together in a S hared To Do Li st 339 Let’s now turn to the first set of features: those that involve logging in to and logging out of the application. Logging In and Out The login process begins when a user clicks the link in the loginArea div (Z in Figure 17-10), which calls the displayLogin() function shown here: function displayLogin() { var theForm = "
Name:
" + "Password: " + "
" document.getElementById("loginArea").innerHTML = theForm; } This function simply puts a form into the innerHTML of the loginArea div. When the user fills out the form and clicks the submit button, the JavaScript calls the doLogin() function. The doLogin() function contains our first bit of Ajax. The form completed by the user is sent to it, and it calls the readFileDoFunction(), shown next. function doLogin(my_form) { readFileDoFunction("userInfo.xml", "GET", function() { if (request.readyState == 4) { if (request.status == 200) { processLogin(request.responseXML, my_form); } else { document.getElementById("errorDiv").innerHTML = "Sorry, there was a problem with the server."; } } } ); } Notice that readFileDoFunction() is sent "userInfo.xml" as the name of the file to read, and processLogin() is the function to call once the file has been read. Notice too that if something goes wrong with reading the file, an error is put into the div with the id of errorDiv. The readFileDoFunction() function performs the Ajax call. This function is shown next, and, as you can see, it looks very much like the function described in Figure 16-15. 340 Chapter 17 function readFileDoFunction(file_name, request_type, the_function) { if (window.XMLHttpRequest) { request = new XMLHttpRequest(); } else { request = new ActiveXObject("Microsoft.XMLHTTP"); } var theURL = "http://localhost/boj/ch17/readXMLFile.php?fileName=" + file_name + "&t=" + new Date().getTime(); if (request) { request.open(request_type, theURL); request.onreadystatechange = the_function; request.send(null); } else { document.getElementById("errorDiv").innerHTML = "Sorry, you must update your browser before seeing Ajax in " " action."; } + } However, unlike the function in Figure 16-15, which called the server-side program readTextFile.php, this function calls a server-side program called readXMLFile.php. If the browser doesn’t understand Ajax, readFileDoFunction() puts the error message in the errorDiv div. As before, readFileDoFunction() executes the passed-in function whenever the readyState of the request object changes. In this case, when the readyState of the request object is 4, and the request is satisfied correctly (status is 200), the passed-in function calls processLogin(), which does the actual work of logging in. Functions Related to Logging In Figure 17-12 lists processLogin() and some of the helper functions it calls. function processLogin(user_info, my_form) { X var var var var var Y var this_user = getUser(user_info, user_name); if (this_user != null) { this_password = getFirstValue(this_user, "password"); if (user_password == this_password) { success = true; } } Z user_name = my_form.elements["name"].value; user_password = my_form.elements["password"].value; success = true; this_password_node; this_password; Putting It A ll Together in a S hared To Do Li st 341 if (success == true) { document.cookie = "user=" + user_name; displayHomeInformation(user_name); document.getElementById("contentArea").innerHTML = ""; } else { document.getElementById("errorDiv").innerHTML += "
Login error; please try again.
"; } [ } \ function getUser(user_info, user_name) { var users = user_info.getElementsByTagName("user"); var count = 0; var found_user = null; var this_user; while ((count < users.length) && (found_user == null)) { this_user = users[count]; this_name = getFirstValue(this_user, "name"); if (this_name == user_name) { found_user = this_user; } count++; } return found_user; } ] function getFirstValue(my_element, child) { ^ return my_element.getElementsByTagName(child)[0].firstChild.nodeValue; } _ function displayHomeInformation(user_name) { document.getElementById("loginArea").innerHTML = "Welcome " + user_name + ". " + " logout "; displayLegalLists(user_name); } Figure 17-12: Functions related to logging in The processLogin() function is passed two files, the first of which is the XML document retrieved by readFileDoFunction(). This is the userInfo.xml file described in the section “To Do List Data Files” on page 334. The processLogin() function is also passed in the form that was filled out by the user. The processLogin() function first extracts the values submitted with the form (starting in X). Then, after declaring some variables, in Y the function calls getUser() which takes the XML document and the username entered into the form and returns a pointer to the XML element that represents that user. More on getUser() will be found in the next section. Next, we want to see whether the password typed into the form is the same as the user’s password stored in userInfo.xml. If you look at the userInfo.xml file, you’ll see that each user element has four child elements: name, password, profile, and lists. Once getUser() returns a pointer to the correct user 342 Chapter 17 element, Z calls getFirstValue() to get the value of the user element’s password child element. The getFirstValue() function (defined in ]) takes as parameters a pointer to an element, and a string holding the name of the child of that element whose value you want to return. In this case, we want to return the value of the password child of the user element. (There are more details on getFirstValue() coming in the next section.) If the user and password match, then the success variable will have been set to true, and three things will happen. First, a cookie is set with the username ([), which will be used whenever the page is reloaded, to check whether a user has logged in. This cookie will be deleted either when the user logs out or when the user closes the browser. Once the cookie is set, the function displayHomeInformation() is called (defined in _). This function updates the page to reflect that the user successfully logged in. Finally, the message currently in the contentArea div is erased. If something goes wrong with the login (the username doesn’t exist, the password doesn’t match, or there was a server error), a message is put into the errorDiv. Helper Functions Now let’s turn to the helper functions just mentioned: getFirstValue(), getUser(), and displayHomeInformation(). Because getFirstValue() is used by many functions, we’ll discuss it first. getFirstValue() The processLogin() function calls getFirstValue() in Z in order to get the password of a given user. The getFirstValue() function is passed a user element and the string "password". The single line of getFirstValue() in ^ gets the password of that user. The first part of ^ calls the getElementsByTagName() function on the user element that is being passed in: my_element.getElementsByTagName(child) Because the child parameter is the string "password", this line returns an array of the password elements of the user element. Because we control the XML stored in userInfo.xml, we know that each user element will have only one password. Therefore, we know that the array returned by getElementsByTagName() will have only one element. The [0] in ^ refers to the first password element, which we know is the only password element. Just as we can use my_array[0] to refer to the first element in my_array, we can use getElementsByTagName("password")[0] to refer to the first (and only) element in the array returned by getElementsByTagName(). We now have the user element’s child password element thanks to my_element.getElementsByTagName(child)[0]. Because that password element has one child (which is the text node containing the password string), we can use the firstChild property to access that text node. Once we have accessed the Putting It A ll Together in a S hared To Do Li st 343 text node, we can get its value from its nodeValue. To make getFirstValue() more clear, it could have been written like this: function getFirstValue(my_element, child) { var child_array = my_element.getElementsByTagName(child); var first_child_element = child_array[0]; var child_text_node = first_child_element.firstChild; var child_value = child_text_node.nodeValue; return child_value; } You can see that the longer version is easier to understand but takes up much more space. getUser() The getUser() function (defined in \) takes two parameters: the XML document representing the userInfo.xml file, which was read by readFileDoFunction(), and the username. getUser() returns a pointer to an XML user element that represents the user. getUser() calls getElementsByTagName(), which returns an array of all the user elements of the XML document. It then loops through the array and uses getFirstValue() to determine the value of the name child of each user element. If the name child is the same as the name entered into the form, we have found the user element that matches that name, and this user element is returned. displayHomeInformation() The function displayHomeInformation() (defined in _) does two things. First, it changes the contents of the loginArea div so that it shows a welcome message and a logout link instead of the login form. Next, it calls displayLegalLists(), which determines which lists this user is allowed to see, and puts links to these lists into the listArea div. Logging Out and Checking If Logged In When displayHomeInformation() changes the contents of the loginArea div, it inserts a logout link into the web page. Logging out is handled by the function logout() and its helper function, getNameFromCookie(). The getNameFromCookie() function is also called by checkIfLoggedIn(), which is called whenever the To Do list application is visited (see X in Figure 17-10). Each of these functions are shown in Figure 17-13. Let’s see how they get the job done. function logout() { var the_date = new Date("December 31, 1900"); var the_cookie_date = the_date.toGMTString(); X var user_name = getNameFromCookie(); document.cookie = "user=" + escape(user_name) + ";expires=" + the_cookie_date; Y Z 344 Chapter 17 clearTimeout(user_list_timeout); clearTimeout(current_list_timeout); window.location.reload(); } [ function getNameFromCookie() { var cookieParts = null; var user_name = null; if (document.cookie != null) { \ user_name = document.cookie.split("=")[1]; } return user_name; } ] function checkIfLoggedIn() { var user_name = getNameFromCookie(); if (user_name != null) { displayHomeInformation(user_name); } } Figure 17-13: Checking for logged-in user and logging out logout() The logout() function is called when a user clicks on the logout link shown in Figure 17-3. The logout() function deletes the cookie that is storing the username, clears any time-outs that have been set, and resets the application to the pre-logged-in state showing in Figure 17-1. First, logout() deletes the cookie which is storing the username by changing its date value to a prior date (as discussed in the section “Setting the Duration of a Cookie” on page 222). It uses these two lines: var the_date = new Date("December 31, 1900"); var the_cookie_date = the_date.toGMTString(); Next, X calls getNameFromCookie(), which reads the cookie and returns a string with the username. Then document.cookie is set with this expired cookie, effectively deleting it. A couple of time-outs are cleared in Y (more on these soon). Finally, logout() calls the reload() method of the window’s location object, which reloads the page. Because the cookie has been deleted, the user is no longer logged in, and when the page is reloaded it returns to its pre-logged-in state, as shown in Figure 17-1. getNameFromCookie() getNameFromCookie() in [ retrieves the username from the cookie created upon login by extracting it in \ with user_name = document.cookie.split("=")[1]; This line splits whatever is stored in document.cookie into parts, using = as a delimiter. Our To Do list application stores only one cookie, which, if the user is logged in, will equal something like username=odysseus. The split() method splits this string into two parts and puts those parts into an array; [1] returns the second element of the array. Putting It A ll Together in a S hared To Do Li st 345 checkIfLoggedIn() If a logged-in user clicks the reload button on his or her browser, the To Do list application should redisplay his or her information when the page is reloaded. The checkIfLoggedIn() function, defined in ], inspects the application’s cookie, which contains a username, and displays the user’s To Do list information using the displayHomeInformation() function. Displaying Available Lists Once a user has logged in, the line after [ in Figure 17-12 calls the displayHomeInformation() function (_ in Figure 17-12). This function updates the loginArea div with a welcome message and a logout link and then calls displayLegalLists(), which (together with the functions described below) determines which To Do lists a user can see and modify. The collection of available lists is placed inside listArea div. If a second user decides to give the logged-in user access to his or her list, the available lists section for that logged-in user needs to be updated. We use a setTimeout to regularly check to see whether this kind of updating will be necessary. Figure 17-14 lists the functions that display and update a user’s list of available To Do lists. function displayLegalLists(user_name) { readFileDoFunction("userInfo.xml", "GET", function() { if (request.readyState == 4) { if (request.status == 200) { var last_modified = request.getResponseHeader("Last-Modified"); var last_modified_date = new Date(last_modified); displayLists(request.responseXML, user_name, last_modified_date.getTime()); } else { document.getElementById("errorDiv").innerHTML = "Sorry, your lists could not be displayed due to a " + "problem with the server."; } } } ); X Y } Z [ \ ] 346 Chapter 17 function displayLists(user_info, user_name, last_modified_date) { var this_user = getUser(user_info, user_name); var display_info = ""; var this_link; var this_list; if (this_user != null) { var lists_element = this_user.getElementsByTagName("lists")[0]; var lists = lists_element.getElementsByTagName("list"); for (var loop=0; loop < lists.length; loop++) { this_list = lists[loop].firstChild.nodeValue; this_link = "" + this_list + ""; display_info += this_link + "
"; } document.getElementById("listArea").innerHTML = display_info; user_list_timeout = setTimeout("updateUserIfChanged(" + last_modified_date + ",'" + user_name + "')", 60000); ^ } } _ function updateUserIfChanged(current_last_modified, user_name) { readFileDoFunction("userInfo.xml", "HEAD", function() { if (request.readyState == 4) { if (request.status == 200) { var last_modified = request.getResponseHeader("Last-Modified"); var last_modified_date = new Date(last_modified).getTime(); if (last_modified_date != current_last_modified) { displayLegalLists(user_name); } user_list_timeout = setTimeout("updateUserIfChanged(" + last_modified_date + ",'" + user_name + "')", 60000); } else { document.getElementById("errorDiv").innerHTML = "Problem updating user " + request.status; } } } ); ` a } Figure 17-14: Functions to display and update a user’s To Do list The displayLegalLists() function starts by using readFileDoFunction() to trigger an Ajax call. readFileDoFunction("userInfo.xml", "GET", function() {...}) This call reads in the userInfo.xml file and executes the provided anonymous function, function() {...}. Most of the anonymous function is executed when the Ajax request object reaches readyState 4, and the server returns a 200 message, signifying that the request was properly satisfied. When these conditions are met, the anonymous function in X reads the Last-Modified field of the request object’s response header and turns it into a Date object. Next, the anonymous function calls displayLists() in Y and sends it three parameters: the XML retrieved from the request, the name of the logged-in user, and the time the userInfo.xml file was last updated. NOTE The value passed to displayLists() is not the Date object itself. Instead, the Date’s getTime() method is called to return the number of seconds between the last time the file was updated and January 1, 1970. Putting It A ll Together in a S hared To Do Li st 347 displayLists() The displayLists() function does most of the real work. It first calls getUser() to get the appropriate user element from the userInfo.xml file. Then, in Z, it gets the first child element of the user element, named lists. Because there is only one element named lists for each user element, we know that we want the first one. Once we have the lists element, getElementsByTagName() is called again in [ to return an array filled with the set of list elements that are nested in the lists element. Once we have our array, we loop through it to create a string to display each list element. The code in \ gets the name of the each list element in the loop. For example, the user Odysseus has two available lists: his and Nestor’s. The array created in [ contains each of these lists. The first time through the loop, \ pulls out odysseus; the next time through, it pulls nestor. Once \ determines the name of the list, ] creates the string to be displayed in the web browser, which will look something like this: odysseus The body of the link is the name of the available list (shown here as odysseus). An onClick inside the link calls readyDisplayList() when clicked, which pulls the name of the list. Once the loop completes, display_info will hold the string with all of the available To Do lists. This string is then put into the innerHTML of the listArea div. Finally, ^ sets the time-out that will be used to check whether the userInfo.xml file has been changed. Line ^ calls updateUserIfChanged() (defined in _) after one minute and passes it the date userInfo.xml was last modified and the name of the logged-in user. T H E IM P O R T A N C E O F F U N C T I O N P A R A M E T E R S Many functions in the To Do list application, including displayLists() and displayLegalLists(), take the name of the logged-in user as a parameter. Because the user is logged in, that name is also available by inspecting document.cookie. You may ask yourself, why bother passing the username as a parameter to a function if it’s available in the cookie? For stylistic reasons, I like to pass in as parameters all the variables that impact the behavior of a function. This makes it easier to adapt the functions to new situations where, perhaps, the username is not stored in a cookie. Think of a function as a black box. Input is sent into the box, something happens inside the box, and out comes some output. We know what goes into the function by looking at its parameters, and we know what comes out of the function by looking at the return values. This style of coding makes it easier to see what a function does and to reuse functions in other scripts. If a function relies on values that are not passed into it as parameters, a person reading the function will have to read the whole thing to understand what information the function needs in order to work correctly. 348 Chapter 17 updateUserIfChanged() Now the updateUserIfChanged() function does a HEAD call to check whether the last modified date of the userInfo.xml file differs from the one that was passed into the function. If the last modified date of userInfo.xml is different, the file has been updated, and ` calls displayLegalLists() again to reload the user’s legal list information. Finally, updateUserIfChanged() creates a new time-out to call updateUserIfChanged() again in one minute (a). This time-out loop, in which updateUserIfChanged() is called and then a time-out is set to call updateUserIfChanged() again in a minute, keeps going until the user logs out, clearing the time-out. Displaying a Specific List Now the list of available To Do lists is displayed to the user with the name of each list as a link. Clicking on a link calls the function readyDisplayList(), which begins the process of displaying the contents of a given To Do list. Figure 17-15 lists readyDisplayList(). function readyDisplayList(list_name) { X var file_name = list_name + ".xml"; Y readFileDoFunction(file_name, "GET", function() { if (request.readyState == 4) { if (request.status == 200) { var last_modified = request.getResponseHeader("Last-Modified"); var last_modified_date = new Date(last_modified); Z displayList(request.responseXML, last_modified_date.getTime()); } else { document.getElementById("errorDiv").innerHTML = "Sorry, could not display To Do list " + list_name + " due to a problem with the server."; } } } ); } Figure 17-15: Function to display a To Do list Figure 17-16 lists the associated functions of readyDisplayList(). function displayList(the_list, last_modified_date) { var list_name = getFirstValue(the_list, "name"); var intro_text = "

Looking at list: " + list_name + "

"; var pending_display = "Still Pending:
    "; Y var open_item_element = the_list.getElementsByTagName("openitems")[0]; X Putting It A ll Together in a S hared To Do Li st 349 var open_items = open_item_element.getElementsByTagName("item"); for (var loop=0; loop < open_items.length; loop++) { this_item = open_items[loop]; this_contents = getFirstValue(this_item, "contents"); this_number = getFirstValue(this_item, "number"); pending_display += "
  • " + this_contents; } pending_display += "
"; Z var done_display = "Completed:
    "; var open_item_element = the_list.getElementsByTagName("doneitems")[0]; var open_items = open_item_element.getElementsByTagName("item"); for (var loop=0; loop < open_items.length; loop++) { this_item = open_items[loop]; this_contents = getFirstValue(this_item, "contents"); this_number = getFirstValue(this_item, "number"); done_display += "
  • " + this_contents; } done_display += "
"; [ document.getElementById("contentArea").innerHTML = intro_text + pending_display + done_display; \ document.getElementById("contentArea").innerHTML += "

Add New Item: "+ "

"; ] todo_list_timeout = setTimeout("updateTodoIfChanged(" + last_modified_date + ",'" + list_name + "')", 5000); } function updateTodoIfChanged(current_last_modified, list_name) { readFileDoFunction(list_name + ".xml", "HEAD", function() { if (request.readyState == 4) { if (request.status == 200) { var last_modified = request.getResponseHeader("Last-Modified"); var last_modified_date = new Date(last_modified).getTime(); if (last_modified_date != current_last_modified) { _ readyDisplayList(list_name); } ` todo_list_timeout = setTimeout("updateTodoIfChanged(" + ^ 350 Chapter 17 last_modified_date + ",'" + list_name + "')", seconds_between_todo_list_update); } else { document.getElementById("errorDiv").innerHTML = "Problem updating To Do list " + request.status; } } } ); } Figure 17-16: The supporting functions for displaying a To Do list readyDisplayList() readyDisplayList()is very similar to displayLegalLists(), shown in Figure 17-14. Like displayLegalLists(), it takes the name of a list to read (for example, odysseus) and calls the Ajax function readFileDoFunction(), which reads the file containing the list and then calls another function. The code in X in Figure 17-15 sets the name of the file equal to the name of the list, concatenated with the string ".xml". If the user wants to see the odysseus list, the code in Y will read the file odysseus.xml. The anonymous function sent to readFileDoFunction() calls displayList() once the file has been completely loaded (Z). Finally, the displayList() function is sent an XML document read from the file and the file’s last modification time. displayList() The displayList() function in Figure 17-16 does most of the work involved in displaying a To Do list. Its first line (X) calls getFirstValue() to retrieve the name of the list from the XML document. In Figure 17-8, you’ll see that the name element is a child of the root of the XML file. The getFirstValue() function reads the string inside the first (and only) name element inside the list element. The next couple of lines start the strings that we will use to display the To Do list. To Do List Strings The To Do list is represented by two strings: one listing the set of items to complete (pending items), the other listing the set of items which have already been completed. These two strings are, in turn, constructed in two loops. The first loop adds the pending items to one string, and the second adds the completed items to the other string. The first loop starts in Y, where it accesses the first openitem element that is a child of the list element. This openitem element has a set of item elements inside. Each element is a task to complete. The loop iterates through each of these items, creating a string that is added to the pending_display string. (You should already be familiar will all the lines in that loop.) Each line in the loop gets a value of the item, either its contents or its identification number. Putting It A ll Together in a S hared To Do Li st 351 Line Z creates the string for each item, which looks like this:
  • Beat Troy As you can see, each item gets a checkbox that, when clicked, calls the function readyMarkDone(). This function marks an item completed, moving it from the pending to the completed list. The function has two parameters: the name of the list to update and the item to be updated. Once the loop describing the pending items completes, the loop that lists the completed item kicks in. This loop is just like the previous one, except that it iterates through all the items inside the doneitems element and prints out a checkbox with an onClick that calls the function readyMarkUndone(), which moves an item from the completed list back to the pending list. Adding the Content to the Web Page Once both loops have run their course, [ puts the introductory text, the list of pending items, and the list of done items into the contentArea div. Line \ adds a form to that div (with an input box and a button) that calls addNewItem() to add new items to the To Do list once the add button has been clicked. Finally, ] starts a time-out that works just like the time-out in a of Figure 17-14, except that it calls updateTodoIfChanged() instead of updateUserIfChanged(). updateTodoIfChanged() The updateTodoIfChanged() function is like updateUserIfChanged() (shown in _ in Figure 17-14). There are three key differences between these functions. First, updateTodoIfChanged() and updateUserIfChanged() read different XML files. updateUserIfChanged() reads the userInfo.xml file, and as you can see in ^ of Figure 17-16, updateTodoIfChanged() reads in the XML file storing the requested To Do list (for example, odysseus.xml). Second, the functions updateTodoIfChanged() and updateUserIfChanged() call different functions after reading their requested files. The updateUserIfChanged() function calls displayLegalLists() to display the list of To Do lists a user may edit. In contrast, the updateTodoIfChanged() function calls readyDisplayList() to display the requested To Do list once it has finished reading the requested To Do list file (_). The final difference between updateTodoIfChanged() and updateUserIfChanged() is the time-out set in `, which sets a time-out to call updateTodoIfChanged() instead of calling updateUserIfChanged(), as occurs in updateUserIfChanged. Processing Changes to a List A user may change a To Do list by moving an item between the pending and completed lists or by adding a new item to the To Do list. Let’s turn first to Figure 17-17, which covers the functions needed to change the status of an existing item. 352 Chapter 17 X function readyMarkDone(list_name, the_item) { var file_name = list_name + ".xml"; readFileDoFunction(file_name, "GET", function() { if (request.readyState == 4) { if (request.status == 200) { Z markDone(request.responseXML, the_item, list_name); } else { document.getElementById("errorDiv").innerHTML = "Sorry, this item could not be marked done due to a " + "problem with the server."; } } } ); } Y [ function markDone(the_document, the_item, list_name, last_modified_date) { \ var open_items = getItems(the_document,"openitems"); var done_items = getItems(the_document,"doneitems"); var this_number; var found_item = null; var count = 0; while ((count < open_items.length) && (found_item == null)) { this_number = getFirstValue(open_items[count], "number"); if (this_number == the_item) { found_item = open_items[count]; } else { count++; } } if (found_item != null) { open_items.splice(count, 1); done_items.push(found_item); saveAndReload(open_items, done_items, list_name); } ] ^ _ ` a } Figure 17-17: Changing the status of a task Figure 17-17 shows the two main functions involved in changing an item from pending to done: readyMarkDone() and markDone(). readyMarkDone() The readyMarkDone() function in X is called whenever someone clicks a checkbox next to a pending item in the To Do list. This function is passed the name of the list to edit and the number of the task to be moved from pending to done. The function then calls readFileDoFunction() in Y and passes it the name of the To Do list file to load, as well as an anonymous function to execute when the request object changes its readyState. Putting It A ll Together in a S hared To Do Li st 353 The anonymous function executes the markDone() function once the To Do file has been completely loaded. The markDone() function takes four parameters: the name of the requested XML file, the identification number of the item that is changing its status, the name of the requested list, and the list’s last modification date. markDone() When called, markDone() in [ creates two arrays: open_items (\) contains all the pending tasks in the To Do list, and done_items contains all the done tasks. (These arrays are created by getItems(), which we’ll discuss shortly.) Once these arrays have been created, ] loops through the open_items array, looking for the item identified by the number passed into markDone()’s second parameter. If it finds the item, three things happen, beginning in ^: 1. 2. 3. markDone() removes the item from the open_items array using the built-in array method splice(). (This method takes two parameters: an item in the array to remove and the number of items to remove, including the one in the first parameter.) The splice() method in _ removes just the found item from the open_items array, and the item is put at the end of the done_items array, using the array method push() in `. In a saveAndReload() turns the arrays into a new XML file, sends the XML back to the webserver for saving, and then updates the To Do list. getItems() and saveAndReload() The markDone() function in Figure 17-17 relied on some helper functions: getItems() and saveAndReload(). The getItems() function is passed an XML document and the name of an XML element, and it returns an array of all XML elements from the document with the given name. The saveAndReload() function saves an XML document to the webserver and updates the To Do list seen in the web browser. These helper functions are shown in Figure 17-18. X function getItems(the_document, the_item_type) { var the_items_array = new Array(); var item_elements = the_document.getElementsByTagName(the_item_type)[0]; var items = item_elements.getElementsByTagName("item"); for (var loop=0; loop < items.length; loop++) { the_items_array[loop] = items[loop]; } return the_items_array; } Y function saveAndReload(open_items, done_items, list_name) { Z var the_string = ""; the_string += ""; the_string += "" + list_name + ""; [ the_string += getItemString("openitems", open_items); the_string += getItemString("doneitems", done_items); the_string += ""; 354 Chapter 17 var file_name = list_name + ".xml"; saveFileDoFunction(file_name, the_string, function() { if (request.readyState == 4) { if ((request.responseText == "success") && (request.status == 200)) { readyDisplayList(list_name); } else { document.getElementById("errorDiv").innerHTML = "Sorry, there was an error saving your list. "; } } } ); \ } ] function getItemString(item_list_name, item_list) { var the_string = "<" + item_list_name + ">"; for (var loop = 0; loop < item_list.length; loop++) { the_string += ""; the_string += "" + getFirstValue(item_list[loop], "number") + ""; the_string += "" + getFirstValue(item_list[loop], "contents") + ""; the_string += ""; } the_string += ""; return the_string; } ^ function saveFileDoFunction(file_name, the_contents, the_function) { if (window.XMLHttpRequest) { request = new XMLHttpRequest(); } else { request = new ActiveXObject("Microsoft.XMLHTTP"); } _ var the_url = "http://localhost/boj/ch17/saveXMLFile.php?t=" + new Date().getTime(); var the_message = "fileName=" + file_name + "&contents=" + the_contents; if (request) { request.open("POST", the_url); request.setRequestHeader("Content-type", "application/x-www-form-urlencoded; charset=UTF-8"); request.onreadystatechange = the_function; request.send(the_message); } else { document.getElementById("errorDiv").innerHTML = "Sorry, you must update your browser before seeing Ajax in action."; ` a } } Figure 17-18: More functions involved in changing a task’s status Putting It A ll Together in a S hared To Do Li st 355 getItems() The function getItems() in Figure 17-18 (X) retrieves an array of tasks that are either openitems or doneitems. The function getItems() is called with an XML document and a type of item to get: either items inside an openitems element or items inside a doneitems element. getItems() calls getElementsByTagName() to get an array of elements of the given type and then it loops through this array, loading each item into a new array called the_items_array. Limitations on Manipulating XML Documents Ordinarily, there’s no reason to loop through one array just to add all of its elements to a new array as I’m doing in getItems(). But here’s why I’m doing that. When getItems() uses getElementsByTagName() to retrieve an array of elements, that array comes from the XML document. You may recall that the markDone() function alters the array returned by getItems(), calling splice() to remove elements from the array and push() to add elements. Unfortunately, most browsers won’t allow changes to arrays retrieved from the XML document. Therefore, getItems() creates its own JavaScript array and copies the items out of the array returned by getElementsByTagName() into the new array called the_items_array. saveAndReload() The next helper function, saveAndReload(), is defined in Y. It creates a string containing an XML document, which is based on the information in the open_items and done_items arrays created by markDone() and markUndone(), and then it sets up the Ajax call that saves this string to the webserver. Line Z begins the creation of a string that holds the XML document. The next few lines add the name of the To Do list and the opening list element tag. The next two lines (starting with [) call getItemString() to create strings that contain the information stored in the open_items and done_items arrays. getItemString() The getItemString() function, declared in ], loops through the provided array and creates a string representing each item. (You should find the code in getItemString() easy to follow by now.) The lines after [ add the closing list tag, then set up the Ajax call that will save the altered To Do list to the webserver and call the functions used to display the To Do list. This Ajax call, performed by saveFileDoFunction(), is similar to readFileDoFunction() (discussed in “Logging In and Out” on page 340), except that it saves a file instead of reading it. saveAndReload() The function saveAndReload() calls saveFileDoFunction() in \ and passes it the name of a file to save, the string to be saved into the file, and an anonymous function that is called when the Ajax request object changes its readyState. 356 Chapter 17 In this case, once the file has been saved to the server, the anonymous function calls readyDisplayList(), which, if you remember from Figures 17-15 and 17-16, sets up an Ajax call that reads the file that was just saved and displays the results. saveFileDoFunction() The contents of saveFileDoFunction(), which start in ^ in Figure 17-18, should look very familiar to you. Line _ defines the URL that points to the server-side program being called (saveXMLFile.php). Line ` creates the message to send with the POST, which includes the name of the file to be saved and the file’s contents. (Because the contents are sent via POST, rather than GET, I don’t need to use escape() here, as I did when sending information in a GET in Figure 16-9.) Finally, a and the subsequent lines send the POST request. NOTE It would be a good idea to remove all of the characters that are illegal XML, however, such as quotation marks and less than and greater than symbols. To do that, replace each with its HTML encoding: ", <, and >. For brevity’s sake, I’ll leave that as an exercise for the reader. Adding a New Item The final section of code in the application adds a new item to a To Do list when a user fills in the Add New Item text box in Figure 17-4. Clicking the add button calls addNewItem() and sends it the form and the name of the list being edited. Figure 17-19 shows you the addNewItem() function and the functions it relies on. X function addNewItem(the_form, list_name) { var file_name = list_name + ".xml"; readFileDoFunction(file_name, "GET", function() { if (request.readyState == 4) { if (request.status == 200) { addNewToFile(request.responseXML, the_form.newItem.value, list_name); } else { document.getElementById("errorDiv").innerHTML = "Sorry, new item could not be added to To Do list for" + list_name + " due to a problem with the server."; } } } ); Y } Z function addNewToFile(the_document, new_contents, list_name) { [ var open_items = getItems(the_document,"openitems"); var done_items = getItems(the_document,"doneitems"); Putting It A ll Together in a S hared To Do Li st 357 \ var high_number = getHighValue(the_document); var new_number = high_number + 1; var new_item = document.createElement("item"); var new_item_number = document.createElement("number"); var new_item_content = document.createElement("contents"); new_item_number.appendChild(document.createTextNode(new_number)); new_item_content.appendChild(document.createTextNode(new_contents)); new_item.appendChild(new_item_number); new_item.appendChild(new_item_content); open_items.push(new_item); saveAndReload(open_items, done_items, list_name); ] ^ _ } ` function getHighValue(the_document) { var high_number = 0; var this_number = 0; var items = the_document.getElementsByTagName("item"); for (var loop=0; loop < items.length; loop++) { this_number = parseInt(getFirstValue(items[loop], "number")); if (this_number > high_number) { high_number = this_number; } } return high_number; } Figure 17-19: Adding new items Function addNewItem() in X is a now-familiar Ajax setup function. It calls readFileDoFunction(), tells it to read the appropriate To Do list, and defines an anonymous function that calls addNewToFile() in Y, once the request list has been read. The addNewToFile() function in Z is passed an XML document representing the To Do list, new information to add to that list, and the name of the list. Line [ uses the getItems() function described in Figure 17-18 to get all pending items in the To Do list, and the following line gets all the completed items. The rest of addNewToFile() creates the item to add to the list, each of which has an identifier number, which the various functions use to refer to each item. These identifiers are assigned in order, so each new item gets a number one higher than the highest-numbered item in the To Do list. Line \ calls getHighValue() to determine the highest numbered item on the To Do list; the following line adds one to that value to set a new identifier number. The lines beginning in ] and ending in ^ use XML methods to create a new item. Once they complete, new_item will be an XML element that looks like this: 6 This is a new item 358 Chapter 17 Line ^ adds this new item to the array of open items retrieved in [. Finally, _ calls saveAndReload() (introduced in Figure 17-18) to save the two item arrays. getHighValue() Believe it or not, we are almost done. The only function left to describe, getHighValue() (`), loops through all the items in a list, retrieves their identifier numbers, and returns the highest number among them. And that, dear reader, is the entirety of the application so far. A Few Closing Notes This application combines elements from every chapter of this book. If you’ve understood everything here, you can consider yourself well versed in JavaScript lore. However, before closing, I have two final issues to raise about the application: how to decide whether code should run in the client side versus the server side, and considerations about the security of the application. Client-Side or Server-Side Code? Most of the code in this application was written in JavaScript and therefore appeared on the client side. I designed the application this way because this is The Book of JavaScript, not The Book of PHP (which may be in the works). Nevertheless, some of the code would have been better placed on the server side. For example, displayLegalLists() in Figure 17-14 displays a user’s list of available To Do lists. However, even though the application cares only about changes to the logged-in user’s information, displayLegalLists() actually retrieves the entire userInfo.xml file. The entire file must be read, because all the code for extracting the information specific to the logged-in user from userInfo.xml appears in the JavaScript. In contrast, when information about the user is extracted on the server side instead, the PHP can send only the part of userInfo.xml that we care about. This sends less information across the network and gives the JavaScript less to deal with. When one million people have signed up for your shared To Do list service, the difference between a few lines of XML and millions of lines of XML is enormous. Sending information across the Internet is often the biggest bottleneck in any client-server application, so do what you can to minimize the amount of information that clients and servers pass back and forth. Security Issues When writing server-side applications, you must pay attention to security issues. Many servers are hacked because of poorly written server-side code. The application described here is insecure in two ways. First, user passwords are sent from the web browser to the webserver without encryption. Second, the application does not do enough to ensure that a user has successfully logged in before giving the user access to To Do lists. Putting It A ll Together in a S hared To Do Li st 359 Password Encryption Information does not pass directly from a web browser to a webserver; it is routed around the Internet, passing from one server to another until it reaches its destination. Any server along the way can spy on you, looking for passwords, and if those passwords are sent without encryption (also called a cleartext), the spy’s job is made even easier. One solution might be to write a JavaScript function to encrypt the password before it is sent to the webserver, and then decrypt it on the server side. This is a bad solution, because anyone can view the JavaScript on your web page and figure out how your encryption function works. The solution is to use a secure webserver that understands the HTTPS protocol (that is, secure HTTP). HTTPS works just like HTTP except that it adds an additional encryption/authentication layer between HTTP and TCP. Okay, that’s enough of that mumbo jumbo for now. To send a message to a secure HTTPS server, use https:// instead of http:// at the beginning of your URL. When https:// is used, the web browser and webserver act together to encrypt and decrypt information securely. To send information securely within your application (assuming that you have access to a secure server), use an https:// URL in your Ajax calls and the username and password parameters in the request.open() method (see “Telling the Object Where to Send the Request” on page 266). NOTE All commonly used brands of webservers have a secure mode, so if you are running your own webserver, check that server’s documentation. If you are not running your own webserver, ask your server’s system administrator whether your server supports secure transactions. Using Server-Side Sessions Our application uses a cookie to determine if a user has logged in. This poses another security problem. Because cookies live on the client side of the application, they can be faked by clever users. A malicious user could create his own username=odysseus cookie, put it on his hard drive, and get access to Odysseus’s account. To avoid this potential problem, you should have your server track users who have logged in properly. When a user logs in properly with the login function, the server records that. Then, whenever a user wants to get information from the webserver, the server checks to see whether this user has properly logged in. If not, the server doesn’t give the user access to restricted information or services. The traditional way to track logged in users is with a session. When a user logs in, the server starts a session, which tracks the user. All server-side languages, including PHP, provide some way of creating sessions. NOTE 360 Chapter 17 To learn more about sessions in PHP, pick up a PHP book or search the Internet. In addition, many of the toolkits described in Appendix B, such as Sajax, help you handle sessions. Summary The primary point of this chapter has been to show how you can integrate everything in this book to create a useful and practical web application. If you’ve lost track of how all the functions described work together, see the road map in Figure 17-11, and then check the JavaScript again to see where the dependencies arise. Although most of the application used JavaScript learned earlier in the book, there were a few new tidbits of information. We discussed: z Using splice() to delete elements from arrays (Figure 17-17) z Dealing with browsers that won’t let you edit XML documents (see “Limitations on Manipulating XML Documents” on page 356) z Using https:// and the open() method of the request object to send information securely z Applying the divide and conquer problem-solving technique when faced with an overwhelming task Congratulations on making it this far! You are now ready to start writing very complex JavaScript applications. Be warned, however! As your JavaScript gets more complex, bugs get trickier to detect and weed out. The next chapter discusses the very important topic of debugging and introduces you to a number of tools and techniques that will help you find and stomp out those bothersome bugs. Assignment Your assignment is to add these critical features to the application discussed in this chapter: z Allow new users to join the service z Allow a user to permit another user to access his or her To Do list How you add these features and what they look like is completely up to you. You’re the expert now! Putting It A ll Together in a S hared To Do Li st 361 DEBUGGING JAVASCRIPT AND AJAX Now that you’ve mastered the basics of JavaScript, it’s time to start writing some complicated scripts of your own. This chapter will help you solve the problems that inevitably arise in writing even simple scripts. The key point is to think before you code. Having a clear idea of how your script will work before you write it will cut down tremendously on your rewriting and bug fixing. Of course, you can’t avoid bugs altogether, so you’ll need to learn how to decrease the number of bugs in your scripts and figure out why a program isn’t doing what you want. This chapter covers some common debugging tips and techniques, including how to: z z z z Write clear and relatively bug-free code Avoid common mistakes Print out variables and log messages in various ways Use and interpret your browser’s JavaScript bug detector z Use a more complete JavaScript debugger Debug Ajax z Fix bugs without creating new ones z Good Coding Practices Two keys to good programming are to write programs for people, not for computers, and to think before you code. Writing programs for people means using comments to guide readers through your code, using meaningful variable names, and writing code that’s easy to understand rather than clever. Clever coding is cute, but the clever coder gets the bug. Sketching out your code using comments is a good way to wind up with commented and well thought-out code. Programmers often think that they will have time to “clean up” the code after they have everything working. Unfortunately, once one bit of code works, there will always be more to write, so people rarely have time to go back and comment their code. Commenting first ensures that the comments will be there when you are done. It also forces you to figure out how your JavaScript will work before you dive in and start coding. Thinking before you code means that you will be less likely to pursue a path that will not work. Writing comments first also means that you will have a feeling for how much work lies before you. As you write the JavaScript that performs the tasks described by your comments, you will be able to keep track of what you have accomplished and how much remains. Starting with Comments Here’s an example of writing the comments for a function before writing the function itself: //function beKind() // beKind asks for a user's name, chooses a random affirmation, // and returns an alert box with the name and the kind words function beKind() { // first construct a list of affirmations // // next get the user's name // // then choose a random affirmation // // finally return the personalized kindness // } 364 Chapter 18 Filling In the Code Now that you have your JavaScript plotted out in comments, you can fill in the code itself, step by step. //function beKind() // beKind asks for a user's name, chooses a random affirmation, // and returns an alert box with the name and the affirmation function beKind() { // first construct a list of affirmations // var the_affirmation_list = new Array(); the_affirmation_list[0] = "You are a great coder!"; the_affirmation_list[1] = "Your JavaScript is powerful!"; the_affirmation_list[2] = "You finished the whole book!"; // next get the user's name // var the_name = prompt("What's your name?", ""); // then choose a random affirmation // var the_number = Math.floor(Math.random() * 5); var the_affirmation = the_affirmation_list[the_number]; // finally return the personalized kindness // alert("Congratulations, " + the_name + ". " + the_affirmation); } Commenting not only forces you to think before you code; it also makes the task of coding seem a lot easier. Instead of facing one huge task, you’ve already broken it down into easily coded sections. Avoiding Common Mistakes Most beginning programmers make simple syntactic mistakes. It takes a long time to stop forgetting to close quotes, curly brackets, and parentheses, but luckily modern browsers have JavaScript bug detectors that detect such errors for you. Those bug detectors will be described later in the chapter. This section covers techniques for avoiding a few common mistakes that many browser bug detectors won’t catch. Use a Consistent Naming Convention The JavaScript bug detector often misses incorrect capitalization and pluralization of variable and function names, a common and annoying error. You’ll greatly reduce the occurrence of such mistakes if you stick to one convention for naming variables and functions. For instance, I name my variables in all lowercase and with underscores replacing spaces (my_variable, the_date, D e b u g gi n g J a v a S cr i p t a n d A j a x 365 an_example_variable, and so on), and I use in-caps notation for functions (addThreeNumbers(), writeError(), and so on). See the section “Naming Your Functions” on page 85 for more information. I avoid pluralizing anything because it’s easy to forget which variables you’ve made plural. Avoid Reserved Words You can’t use words reserved for JavaScript as variables. For example, you can’t name a variable if, because JavaScript uses if. Though it’s not likely you’d name a variable if, you might want to use a variable called, for example, document. Unfortunately, document is a JavaScript object, so using it as a variable would wreak all kinds of havoc. Even more unfortunately, different browsers reserve different words, so there’s no complete list of words to eschew. The safest course of action is to avoid words used in JavaScript and in HTML. If you’re having problems with a variable and you can’t figure out what’s wrong, you may be running into such a problem—try renaming the variable. Remember to Use Two Equal Signs in Logical Tests Some browsers catch the equal-sign error; some don’t. This very common mistake is extremely difficult to detect if the browser doesn’t find it for you. Here’s an example: var the_name = prompt("What's your name?", ""); if (the_name = "thau") { alert("Hello, thau!"); } else { alert("Hello, stranger."); } This code shows you the Hello, thau! alert box regardless of what you type in the prompt, because only one equal sign appears in the if-then statement. The equal sign sets the_name equal to "thau" and returns a value of true. This extremely insidious bug will drive you batty. For your own sanity’s sake, concentrate on not making mistakes like this. Your psychiatrist will thank you. I avoid this mistake by thinking about two equals signs as is the same as, and one equal sign as equals. When I code, I say to myself, “If the_name is the same as "thau", then. . . .” Thinking about the code this way helps me remember the difference between one and two equal signs. Use Quotation Marks Correctly This one gets me time and time again. The only way JavaScript knows the difference between a variable and a string is that strings have quotes around them and variables don’t. Here’s an obvious error: var the_name = 'Ishmael'; alert("the_name is very happy"); 366 Chapter 18 The above code yields an alert box that says the_name is very happy even though the_name is a variable. Once JavaScript sees quotes around something, it simply treats it like a string. Putting the_name in quotes stops JavaScript from looking up the_name in its memory. Here’s a less obvious variation of this bug, which we saw in Chapter 9: function wakeMeIn3() { var the_message = "Wake up! Hey! Hey! WAKE UP!!!!"; setTimeout("alert(the_message);", 3000); } The problem is that you’re telling JavaScript to execute alert(the_message) in three seconds—but three seconds from now the_message won’t exist because you’ve exited the wakeMeIn3() function (the function itself defines the_message variable). Here’s the solution to this problem: function wakeMeIn3() { var the_message = "Wake up!"; setTimeout("alert('" + the_message + "');", 3000); } When you pull the_message out of the quotes, the setTimeout() schedules the command alert("Wake up!");—which is the result you want. Finding Bugs Much of the debugging process involves discovering where the bug is in the first place. Unfortunately, finding the little pests isn’t always easy. You can look for bugs in lots of different ways. This section covers some of your major options, from writing alerts into your code to using your browser’s bug detector and other debugging tools. Printing Variables with alert() Statements The most tried-and-true debugging method is to use alert() statements to print out what’s going on in your script. Figure 18-1 lists two functions. In one, if you enter random names in the prompt boxes, you’ll see the greeting Ahoy, polloi! If you enter Dave in the first prompt box and Thau in the second one, you’re supposed to get the message Howdy, partner! However, running the functions won’t work because one of them contains an error. Running theGreeting() doesn’t result in any JavaScript syntax errors, but the function works incorrectly. In this simple example, you may discover the error easily just by looking at the JavaScript. However, as your scripts get more complicated, you’ll find it harder to locate errors by eyeballing your code. D e b u g gi n g J a v a S cr i p t a n d A j a x 367 function getName() { var first_name = prompt("What's your first name?",""); var last_name = prompt("What's your last name?",""); var the_name = first_name + " " + last_name; } function theGreeting() { var the_name = getName(); if (the_name == "Dave Thau") { alert("Howdy, partner!"); } else { alert("Ahoy, polloi!"); } } Figure 18-1: Find the error If JavaScript doesn’t catch your error and you can’t figure it out by looking at the script, try printing out the variables. The easiest way to do this is to use an alert() to print out a variable, as in Figure 18-2: function getName() { var first_name = prompt("What's your first name?",""); var last_name = prompt("What's your last name?",""); var the_name = first_name + " " + last_name; X alert("in getName, the_name is: " + the_name); } function theGreeting() { var the_name = getName(); Y alert("after getName, the_name = " + the_name); if (the_name == "Dave Thau") { alert("Howdy, partner!"); } else { alert("Ahoy, polloi!"); } } Figure 18-2: Using alert() to print out variables After you enter the names Dave and Thau at the prompts in getName(), the alert in X says “in getName, the_name is Dave Thau.” That looks fine, so you can be pretty sure nothing’s wrong up to the point of X. However, the alert in Y says “after getName, the_name = undefined.” That means the script has a problem somewhere between X and Y—the_name is correct just before getName() exits, but it’s wrong after theGreeting(). Because getName() gets the right answer but theGreeting() fails to receive that answer from getName(), the problem probably lies in the way the script passes the answer from getName() to theGreeting(). 368 Chapter 18 Sure enough, that’s the problem. The getName() function figures out the name but never returns it. We need to put return the_name at the end of the function. Debugging Beyond Alerts Putting alert boxes in your code is a good debugging tool, but when you need to examine variables at many places in a JavaScript it can be annoying to have to press the OK button every other line. One trick that can make your debugging experience more pleasant involves using a variable to set different levels of debugging, such as brief, extreme, and none. The brief level might use alert() statements to print a few debugging messages along the way, while the extreme level might print a ton of debugging messages into another window or a textarea inside a form. The third option, none, won’t print any messages at all. Figure 18-3 lists some code that uses a variable to determine what kind of debugging you want to do. X var debug = "none"; function getName() { var first_name = prompt("What's your first name?",""); var last_name = prompt("What's your last name?",""); var the_name = first_name + " " + last_name; Y doError("in getName, the_name is: " + the_name); } function theGreeting() { var the_name = getName(); doError("after getName, the_name = " + the_name); if (the_name == "Dave Thau") { alert("Howdy, partner!"); } else { alert("Ahoy, polloi!"); } } function doError(the_message) { if (debug == "brief") { Z alert(the_message); } else if (debug == "extreme") { [ window.document.the_form.the_text.value += the_message + "\n"; } } Figure 18-3: Using a debug variable D e b u g gi n g J a v a S cr i p t a n d A j a x 369 Figure 18-3 uses a function called doError() to handle its debugging. For example, Y passes a debugging message to doError(); the doError() function then decides what to do with this message based on how X sets the debug variable. If it sets debug to "brief", Z puts the debugging message in an alert box. Using alerts is handy when you want to check variables in just a few places and you don’t mind pressing OK in each alert box. However, if you want to look at a lot of debugging messages simultaneously, it’s more helpful to set the debug variable to "extreme" ([). Finally, when you’re ready to show your code to the world, just set debug to "none" to prevent the debugging messages from appearing at all. Setting a debug variable like the one in Figure 18-3 saves you the hassle of having to find and remove multiple debugging statements. Depending on how you set debug, you can even use document.write() to show or hide the textarea you’re using to display the debug message. That way, you can show the textarea while debugging the script and then hide it when you’re ready to let visitors see your JavaScript. A number of people have written logging libraries that you can add to your JavaScripts if you don’t feel like writing something like Figure 18-3. Two good examples are Andre’s JSLog, available at http://earthcode.com/blog/ 2005/12/jslog.html, and Log4Ajax by Eric Spiegelberg, available at http:// today.java.net/pub/a/today/2005/12/13/log4ajax.html. Using Your Browser’s Bug Detector If you’ve been trying the examples and doing the assignments as we’ve gone along, you’ve no doubt encountered your browser’s bug detector. When you’ve made a coding mistake, running your code in the browser often results in a window that describes the error. Some browsers, such as Internet Explorer 5.0 and up, warn you by putting an error icon at the bottom-left corner of the window. Clicking the error icon opens a window that describes the error. Other browsers, such as Firefox, may not show errors at all but instead have a console that displays errors. To see the console, type javascript: in the location box of your browser. Sometimes you may find the JavaScript error messages helpful; other times they may seem confusing. For serious debugging, you may have to move up to a full-fledged JavaScript debugger. Using JavaScript Debuggers If you use Firefox or Mozilla, you can download the handy JavaScript debugger named Venkman at https://addons.mozilla.org/firefox/216. Once you have installed the extension, a new JavaScript Debugger option appears under Firefox’s Tools menu, as shown in Figure 18-4. Selecting this option brings up the Venkman debugger, which looks like Figure 18-5. There are many little windows in Venkman, and like any debugger, Venkman is a complicated application. For our purposes, the most important window is the middle one on the left, named Local Variables. 370 Chapter 18 Figure 18-4: Selecting the Venkman JavaScript debugger extension in Firefox As long as the debugging window is open, the debugger can be invoked at any point in your JavaScript program by adding the line: debugger; at the point where you want the debugger to start. Figure 18-5: The Venkman JavaScript debugger D e b u g gi n g J a v a S cr i p t a n d A j a x 371 Consider the code in Figure 18-6. function getName() { var first_name = prompt("What's your first name?",""); var last_name = prompt("What's your last name?",""); var the_name = first_name + " " + last_name; } X function theGreeting() { debugger; var the_name = getName(); if (the_name == "Dave Thau") { alert("Howdy, partner!"); } else { alert("Ahoy, polloi!"); } } Figure 18-6: Starting the debugger As before, we suspect that something funny is going on with getName(). In this case, rather than putting in an alert or using logging, we invoke the JavaScript debugger in X. This stops the JavaScript program and makes the JavaScript debugger window look like Figure 18-7. The debugger; line appeared within theGreeting(), so the Local Variables section of the debugger shows you what it knows about the function. Initially, it knows that there is one variable, the_name, and that it has no value (the value is void). Figure 18-7: After X has been executed 372 Chapter 18 After I click the Step Into button a couple of times to get into getName(), then fill in some prompts, the debugger in Figure 18-8 shows that first_name and last_name are set correctly. Figure 18-8: Examining variables; first_name and last_name look correct I click the Step Into button a few more times until I’ve exited getName(), and I see in Figure 18-9 that for some reason the_name is still void. From this I can deduce that the value is not getting passed out of the getName() function. Figure 18-9: Examining variables; the_name looks incorrect D e b u g gi n g J a v a S cr i p t a n d A j a x 373 In this simple example, the complexity of a full-blown debugger such as Venkman is unnecessary. However, with complicated functions, being able to step through the JavaScript one line at a time, and see the values of the variables at every step, can cut down debugging time immensely. If you’d like to learn more about how to use Venkman, you can find an excellent tutorial at http://www.svendtofte.com/code/learning_venkman. The Venkman debugger is by far the easiest JavaScript debugger to use and is itself a reason to download Firefox. If you are trying to debug a problem that occurs only in Internet Explorer, you will need a debugger that works for Internet Explorer. The best option here is the Microsoft Script Editor,1 which comes packaged with Microsoft Office. Debugging Ajax in Firefox 1.5 and 2.0 Debugging Ajax is much like debugging JavaScript. However, the client-server communication that goes on in debugging Ajax adds a bit of complexity. An extension for Firefox 1.5 and 2.0 called Greasemonkey,2 combined with a script called the XMLHttpRequest Debugging Script,3 can give you a window into how your web browser and a webserver are communicating. Once you have downloaded and installed Greasemonkey and the XMLHttpRequest Debugging script, you can monitor requests sent and received by Firefox request objects. The XmlHttpRequestDebugging script maintains a list of JavaScripts that might have request objects that need to be monitored. To add JavaScripts that run on your desktop computer to that list, choose ToolsManage User Scripts from the Firefox menu, and add http://localhost/* to the Included Pages list, as seen in Figure 18-10. Once you have done so, a div is added to any web page on this list that makes an Ajax-style request. For example, Figure 18-11 shows the debugging window after Odysseus has logged into the To Do list application from Chapter 17. The figure shows two Ajax calls. The first line of a call tells you the type of call it was, in this case a GET. The next line tells you where the request was sent. The third line lets you see what message was sent with the request when the request.send() method was invoked. In the case of a GET, the message is null. With POST, the message will be the string sent. On the third line is also an [edit&replay] button, which gives you a window like Figure 18-12. In this window you can change the message sent in the request and then resend the request to see what happens. The fourth line of the window in Figure 18-11 gives you the status of the webserver’s response. Clicking [export] opens a window with the complete response from the webserver (Figure 18-13). As you can gather, this tool is extremely useful for debugging client-server communications in Ajax. 1 A good tutorial is available at http://www.jonathanboutelle.com/mt/archives/2006/01/ howto_debug_jav.html. 374 Chapter 18 2 See http://greasemonkey.mozdev.org. 3 See http://blog.monstuff.com/archives/images/XMLHttpRequestDebugging.v1.2.user.js. Figure 18-10: Adding JavaScripts that run on your desktop machine to the list of scripts to monitor NOTE Only you (and other users who have added Greasemonkey and the XMLHttpRequest Debugging script and have added your web page to their watch list) will see the XmlHttpRequest debugging window. Don’t worry about anyone else being affected by it. Figure 18-11: XmlHttpRequest debugger showing client-server traffic D e b u g gi n g J a v a S cr i p t a n d A j a x 375 Figure 18-12: Using the XmlHttpRequest debugger to examine and edit an Ajax message Other Debugging Resources Before closing this section on debugging, I should mention two other debugging tools. Firebug4 is a relatively new and popular debugger for Firefox 1.5 that combines logging, a JavaScript debugger, and the ability to watch Ajax requests. Microsoft’s Visual Web Developer Express Edition5 is a free website development environment that includes a JavaScript debugger and can also watch Ajax requests. Fixing Bugs Once you’ve found where your bugs are, you need to fix them—and you have multiple options for this, both good and bad. This section covers a few things you should do when getting rid of bugs. 376 Chapter 18 4 See http://www.joehewitt.com/software/firebug. 5 See http://msdn.microsoft.com/vstudio/express/vwd. Figure 18-13: A detailed look at the client-server communication Back Up Your Program Some bugs are really hard to get rid of. In fact, sometimes in the process of eradicating a little bug that’s driving you nuts, you end up destroying your entire program. This happens a lot, so saving a backup of your program before you start to debug is the best way to ensure that a bug doesn’t get the best of you. Fix One Bug at a Time If you have multiple bugs, fix one and test your fix before moving to the next bug. Fixing a lot of bugs at once increases the risk of adding even more bugs. Avoid Voodoo Coding Sometimes you know a bug exists, but you don’t really know why. Let’s say you have a variable called index and for some reason index is always 1 less than you think it should be. At this point you can do two things. You can sit there for a while and figure out why index is 1 less than it should be, or you D e b u g gi n g J a v a S cr i p t a n d A j a x 377 can just shrug, add 1 to index before using it, and move on. The latter method is called voodoo programming. When you start thinking, “What the hell? Why is index 2 instead of 3 here? Well . . . I’ll just add 1 for now and fix it later,” you’re engaging in voodoo programming. Voodoo programming may work in the short term, but eventually it will doom you. It’s like sweeping dust under a rug. The problem resurfaces— either you get yet another weird error you can’t figure out, or the next poor soul cursed to look at your code will find it extremely hard to understand. Don’t practice voodoo coding. Look for Similar Bugs In some ways, the ability to cut and paste code is the worst thing that ever happened to programmers. Often you’ll write some JavaScript in one function, then cut and paste it into another function. If the first function had a problem, you have now created problems in two functions. I’m not saying you shouldn’t cut and paste code—but keep in mind that bugs have a way of multiplying, so if you find one bug, look for similar bugs elsewhere in your code. One bug that typically crops up several times in every JavaScript is misspelled variable names. If you misspell the_name as teh_name in one place, chances are you’ve done it someplace else too. Clear Your Head You’re sitting there staring at a bug, and you just can’t figure out what’s going on or how to fix it. Or maybe you can’t even find the bug in the first place. The best thing to do is walk away from your computer. Go read a book and take a stroll around the corner. Get a tasty beverage. Do something— anything—but don’t think about the program or the problem. This technique is called incubation, and it works amazingly well. After you’ve had a little break and relaxed a bit, try finding the bug again. Often you’ll approach the problem in a new, more fruitful way. Incubation works because it breaks you out of a dysfunctional mindset. Ask for Help Sometimes you get stuck in your own contorted thought patterns, and you need someone who hasn’t thought about the problem to find the hole in your logic. In structured coding environments, programmers periodically review each other’s code. Code review not only helps iron out bugs but also results in better code. Don’t be afraid to show other people your JavaScripts. You’ll become a better JavaScripter. 378 Chapter 18 Summary Programming is a skill that improves dramatically over time, and learning how to debug efficiently is one of the biggest components of that process. Whenever you program, you will need to debug. A completely bug-free program is almost never written in one draft. The best you can do is to try to minimize the bugs and to write your programs in a way that makes it easy to detect and fix the bugs that slip in. The tools and techniques covered in this chapter should help make your debugging experience as pleasant as possible. Congratulations! You now know everything you need to start a career as an official JavaScripter. All that remains is lots and lots of practice. View source on every page that catches your fancy, and check out the free JavaScript resources listed in Appendix B. If you’ve made it this far, you’ve learned a lot of JavaScript, but this book hasn’t by any means covered every detail of this huge subject—so leaf through Appendix C to get a feel for the other JavaScript functions and objects at your disposal. If you’re going to do a lot of JavaScripting, get a good JavaScript reference book, like David Flanagan’s JavaScript: The Definitive Guide (O’Reilly, 2006). But most importantly, experiment freely and push the boundaries of what you’ve learned here. Now go forth and code! D e b u g gi n g J a v a S cr i p t a n d A j a x 379 ANSWERS TO ASSIGNMENTS Here are solutions to the assignments I’ve given at the end of each chapter. The scripts and images used in the solutions may be found on this book’s companion website (http://www .bookofjavascript.com). The JavaScript in this appendix contains comments where I think explanation is necessary. If your solution works and is not much longer than mine, you’ve done a good job. There is no assignment for Chapter 1, so we’ll start with Chapter 2. Chapter 2 The Chapter 2 assignment asks you to change Figure 2-12 so that seconds are displayed along with minutes and hours. Use the Date object’s getSeconds() method to get the number of seconds and the fixTime() function to fix the formatting of the seconds. Chapter 2 Assignment Right now it's: 382 Appendix A Chapter 3 In this assignment, you are asked to send people you like to one page, people you don’t like to another page, and everyone else to a third page. This should exercise your new understanding of if-then-else-if statements. Chapter 3 Assignment Chapter 4 This assignment asks you to create an image swap that changes two images at once. Do this by putting two image swap statements inside the event handlers. Chapter 4 Assignment

    Welcome to the Book of JavaScript Website!

    Chapter 5 This assignment asks you to write a web page that contains two links. When the web page opens, it should also open a little window containing an image. When clicked, the two links on the main page should swap different images into the little window. Make sure that index.html and image_page.html are in the same directory. index.html The index.html file opens the little window. Chapter 5 Assignment

    Play with a little window

    Make him sad
    Make him happy
    image_page.html The image_page.html file specifies the content of the little window. Little Window 384 Appendix A Chapter 6 This assignment asks you to create a function that swaps one image with another and opens a new window to a given URL. The function takes three parameters: the name of an image to swap, the URL of a new image to put in its place, and a URL to open in the new window. Chapter 6 Assignment Chapter 7 This assignment asks you to write a script for a clock that tells the time in San Francisco, New York, London, and Tokyo. The clock should have a text field for the time, a button to update the clock, and four radio buttons, one for each of those time zones. When you click on one of the radio buttons, A n s w e rs to A s s i gn me n ts 385 the correct time should appear in the text field. When you click on the update button, the clock should update with the time from the zone you’ve selected with the radio buttons. This solution has two main functions: updateClock() is called when the update button is clicked, and updateReadout() is called when one of the time zone radio buttons is clicked. Chapter 7 Assignment

    San Francisco
    New York
    London
    Tokyo
    Chapter 8 This assignment uses arrays and loops to draw a chart based on user input. One function, getNumbers(), creates an array that stores the values to the chart. After collecting these values from the user, getNumbers() then loops through the array, calling drawSquares() to draw each line of the chart. A n s w e rs to A s s i gn me n ts 387 Chapter 8 Assignment Draw the histogram 388 Appendix A Chapter 9 This assignment asks you to alter Figure 9-11 so that mousing over the image stops the slide show, and mousing off the image starts it again. The solution is very much like Figure 9-11. The only addition is the link around the image that clears the time-out when it is moused over and restarts the slideshow when the mouse moves off of it. Chapter 9 Assignment
    A n s w e rs to A s s i gn me n ts 389 Chapter 10 This assignment asks you to create a page with at least two frames. The first frame should contain a submit button and a text box into which a visitor should type a URL. After the submit button is clicked, the second frame shows the web page called by the URL in the text box. In addition to providing a location box, the browser page in the solution uses Salon’s image map to show various URLs in the display frame. Because it uses frames, this assignment requires three HTML files: index.html, assignment-nav.html, and blank.html. index.html The first page, index.html, lays out the frameset. Chapter 10 Assignment assignment-nav.html The second page, assignment-nav.html, contains the image map and the form. Clicking on an area in the image map or submitting the form loads a URL into the lower frame. Notice the use of this in the form’s onSubmit. nav
    Type a URL below, or
    click on an area of the map.
    390 Appendix A blank.html The third page, blank.html, is just a blank page which appears in the lower frame. blank Chapter 11 This assignment extends Chapter 10’s assignment by adding string validation to make sure the URLs entered in the browser’s location bar are valid web addresses. This means the URL should start with http:// or https://, have no spaces, and have at least two words with a period between them. The solution begins with the code from Chapter 10’s assignment and adds a function named domainCheckAndGo() that performs the string validation. Like the Chapter 10 assignment, this assignment requires three HTML files because it uses frames. index.html The first page, index.html, lays out the frameset. Chapter 11 Assignment A n s w e rs to A s s i gn me n ts 391 assignment-nav.html The second page, assignment-nav.html, contains the contents of the top frame, including the JavaScript. nav
    Type a URL below, or
    click on an area of the map.
    A n s w e rs to A s s i gn me n ts 393 blank.html The third page, blank.html, is just a blank page which appears in the lower frame. blank Chapter 12 This assignment asks you to use cookies to keep track of whether or not a user has visited a web page. The solution below uses Webmonkey’s cookie library to set and read a cookie named was_here. Chapter 12 Assignment

    My Page

    Don't you just love this page? Chapter 13 This assignment asks you to create a bouncing smiley face screen saver using Dynamic HTML. The script below uses two variables, x_motion and y_motion, to keep track of the horizontal and vertical directions in which the smiley face is moving. These variables will either hold the value "plus" or "minus". A "plus" value calls for a number to be added to the current position. If the variable is x_motion, adding a value will move the smiley face to the right. If the variable is y_motion, adding a value will move the smiley face down. Chapter 13 Assignment
    396 Appendix A Chapter 14 This assignment asks you to create an address book using Ajax. The address information should be stored in an XML file. Each entry should have a name, a home address, a phone number, and an email address. The solution requires two files: addressBook.xml, which stores the address information, and index.html, which contains the Ajax code. addressBook.xml The first file is an XML file storing information in the address book. Herman Munster
    1313 Mockingbird Lane, Transylvania
    (415) 555-1212 herman@munster.com
    Nicholas Nickleby
    index.html The second file is the HTML page that contains the JavaScript and Ajax calls to read in and display the file. Chapter 14 Assignment
    Name:
    Address:
    Phone:
    Email:
    Chapter 17 This is your final exam. If you got this working, take yourself out to dinner. If you gave it a good shot, take yourself out to dinner. Heck, if you’ve read to this point in the book, take yourself out to dinner. The assignment was to add these critical features to the To Do list application described in the chapter: z z Allow new users to join the service Allow a user to permit another user to access his or her To Do list Only the HTML file containing the JavaScript needs to be changed here. First, you needed to make a change to the HTML at the bottom of the page to add the “join” link to the login section:

    Login
    Section

    "loginArea"> "#" onClick = "displayLogin(); return false;">login or "#" onClick = "displayJoin(); return false;">join Then there are a number of new functions. First, I’ll cover the functions necessary to provide the ability to join, then the functions necessary to allow someone to give another user access to his or her list. A n s w e rs to A s s i gn me n ts 399 Join Functions Seven functions work together to create a new user: displayJoin() Displays the form that will collect new user information doJoin() Called when the join link is clicked; reads in userInfo.xml and calls processJoin() processJoin() Creates a new user and adds it to userInfo.xml createUserFileAndLogin() addUser() Creates an empty To Do list for a new user Actually creates a new userInfo.xml file makeNewUser() Makes a new user element makeUserInfoDoc() Converts the userInfo.xml file into a string to save to a file // puts a join form into the loginArea function displayJoin() { var theForm = "
    Name:
    " + "Password:
    " + "Password again:
    " + "Profile:
    " + "
    "; document.getElementById("loginArea").innerHTML = theForm; } // reads in the userInfo.xml file and calls processJoin function doJoin(my_form) { readFileDoFunction("userInfo.xml", "GET", function() { if (request.readyState == 4) { if (request.status == 200) { processJoin(request.responseXML, my_form); } else { document.getElementById("errorDiv").innerHTML = "Sorry, there was a problem with the server."; } } } ); } // creates a new user and adds it to the userInfo.xml file function processJoin(user_info, my_form) { var user_name = my_form.elements["name"].value; var user_password = my_form.elements["password"].value; var user_password_2 = my_form.elements["password2"].value; var profile = my_form.elements["profile"].value; var error = "no error"; var this_user = getUser(user_info, user_name); if (this_user != null) { error = "A user with this name already exists."; } else if (user_password != user_password_2) { error = "The two provided passwords don't match."; } if (error == "no error") { var new_user_doc = addUser(user_name, user_password, profile, user_info); 400 Appendix A saveFileDoFunction("userInfo.xml", new_user_doc, function() { if (request.readyState == 4) { if ((request.responseText == "success")&&(request.status == 200)) { createUserFileAndLogin(user_name); } else { document.getElementById("errorDiv").innerHTML = "Sorry, there was an error saving the user information. "; } } } ); } else { document.getElementById("errorDiv").innerHTML += "
    Sorry, " + error + "
    "; } } // creates an empty To Do list for a new user and then logs the user in function createUserFileAndLogin(the_user) { var the_file = "" + "" + the_user + "" + ""; saveFileDoFunction(the_user + ".xml", the_file, function() { if (request.readyState == 4) { if (request.status == 200) { document.cookie = "user="+the_user; displayHomeInformation(the_user); document.getElementById("contentArea").innerHTML = ""; } else { document.getElementById("errorDiv").innerHTML = "Sorry, there was a problem saving the To Do list for " + the_user; } } } ); } // creates a new userInfo.xml document with the new user function addUser(the_name, the_password, profile, user_info) { var users_array = user_info.getElementsByTagName("user"); var new_users_array = new Array(); for (var loop = 0; loop < users_array.length; loop++) { new_users_array[loop] = users_array[loop]; } new_users_array[loop] = makeNewUser(the_name, the_password, profile, new Array(the_name)); var new_document = makeUserInfoDoc(new_users_array); return new_document; } // makes a new user element function makeNewUser(the_name, the_password, profile, list_array) { var new_user = document.createElement("user"); var new_name = document.createElement("name"); new_name.appendChild(document.createTextNode(the_name)); var new_password = document.createElement("password"); A n s w e rs to A s s i gn me n ts 401 new_password.appendChild(document.createTextNode(the_password)); var new_profile = document.createElement("profile"); new_profile.appendChild(document.createTextNode(profile)); var new_lists = document.createElement("lists"); var new_list; for (var loop = 0; loop < list_array.length; loop++) { new_list = document.createElement("list"); new_list.appendChild(document.createTextNode(list_array[loop])); new_lists.appendChild(new_list); } new_user.appendChild(new_name); new_user.appendChild(new_password); new_user.appendChild(new_profile); new_user.appendChild(new_lists); return new_user; } // builds the new XML string for the userInfo.xml file function makeUserInfoDoc(user_array) { var the_doc = ""; var this_user; the_doc += ""; for (var loop = 0; loop < user_array.length; loop++) { this_user = user_array[loop]; the_doc += ""; the_doc += "" + getFirstValue(this_user, "name") + ""; the_doc += "" + getFirstValue(this_user, "password") + ""; the_doc += "" + getFirstValue(this_user, "profile") + ""; the_doc += ""; this_lists = this_user.getElementsByTagName("lists")[0]; var these_lists = this_lists.getElementsByTagName("list"); for (var list_loop = 0; list_loop < these_lists.length; list_loop++) { the_doc += "" + these_lists[list_loop].firstChild.nodeValue + ""; } the_doc += ""; the_doc += ""; } the_doc += ""; return the_doc; } Giving a User Access to Your To Do List These seven functions allow a user to share his or her To Do list with another user. I’ll use the word owner to refer to the user who owns the To Do list, and the word collaborator to refer to the user being given access to the owner’s To Do list. displayHomeInformation() Just like the one in Chapter 16, but adds an additional link that calls giveAccess() giveAccess() Reads in all the system’s users and calls listAllUsers() listAllUsers() Creates a form with a radio button for each potential collaborator, so one may be chosen 402 Appendix A readyAddAvailableUser() addAvailableUser() Reads in the userInfo.xml list and calls addAvailableUser() Adds the newly chosen collaborator to the owner’s lists section in the userInfo.xml file Returns a new user element with the collaborator’s name added to the owner’s lists element addNewAvailableToUserElement() // add a "Give another user access" link to the loginArea after a person has // logged in by changing displayHomeInformation() function displayHomeInformation(user_name) { document.getElementById("loginArea").innerHTML = "Welcome " + user_name + ". " + " logout " + " give another user access "; displayLegalLists(user_name); } // get userInfo.xml and list all the users function giveAccess(the_user) { readFileDoFunction("userInfo.xml", "GET", function() { if (request.readyState == 4) { if (request.status == 200) { listAllUsers(request.responseXML, the_user); } else { document.getElementById("errorDiv").innerHTML = "Sorry, could not get a list of the users."; } } } ); } // create the form showing all the users function listAllUsers(user_info, current_user) { var display = "
    "; var all_users = user_info.getElementsByTagName("user"); var this_user; var this_name; for (var loop = 0; loop < all_users.length; loop++) { this_user = all_users[loop]; this_name = getFirstValue(this_user,"name"); if (this_name != current_user) { display += "" + this_name + "
    "; } } display += "
    "; document.getElementById("contentArea").innerHTML = display; } // get userInfo.xml and add a new available user function readyAddAvailableUser(user_to_add, this_user) { readFileDoFunction("userInfo.xml", "GET", function() { if (request.readyState == 4) { if (request.status == 200) { A n s w e rs to A s s i gn me n ts 403 addAvailableUser(request.responseXML, user_to_add, this_user); } else { document.getElementById("errorDiv").innerHTML = "Sorry, there was a problem getting the list of users."; } } } ); } // add the new user to the user's available list, then // create a new userInfo.xml document and save it function addAvailableUser(user_info, user_to_add, current_user) { var new_user_array = new Array(); var curr_user_array = user_info.getElementsByTagName("user"); var count = 0; for (var loop = 0; loop < curr_user_array.length; loop++) { this_user = curr_user_array[loop]; this_name = getFirstValue(this_user, "name"); if (this_name == current_user) { add_to_array = addNewAvailableToUserElement(this_user, user_to_add); } else { add_to_array = this_user; } new_user_array[loop] = add_to_array; } var new_user_doc = makeUserInfoDoc(new_user_array); saveFileDoFunction("userInfo.xml", new_user_doc, function() { if (request.readyState == 4) { if ((request.responseText == "success")&&(request.status == 200)) { document.getElementById("contentArea").innerHTML = ""; displayLegalLists(current_user); } else { document.getElementById("errorDiv").innerHTML = "Sorry, there was an error saving the user information. "; } } } ); } // return a new user element with the new user added to the available list function addNewAvailableToUserElement(this_user, user_to_add) { var lists = this_user.getElementsByTagName("lists")[0]; var the_name = getFirstValue(this_user, "name"); var profile = getFirstValue(this_user, "profile"); var the_password = getFirstValue(this_user,"password"); var lists_array = lists.getElementsByTagName("list"); var new_lists_array = new Array(); for (var loop = 0; loop < lists_array.length; loop++) { new_lists_array[loop] = lists_array[loop].firstChild.nodeValue; } new_lists_array[loop] = user_to_add; var new_user = makeNewUser(the_name, the_password, profile, new_lists_array); return new_user; } 404 Appendix A RESOURCES You are not alone. There are plenty of JavaScript and Ajax resources to guide and support you along the path to JavaScript mastery. This book is just the beginning of your journey. In this appendix you’ll find tutorials, libraries, frameworks, and blogs that will give you more information than you could possibly process. Tutorials This book covered all of the basics of JavaScript and Ajax, and many advanced topics as well. Here are tutorials that will help you fill in the details not covered in this book. HTML Tutorials HTML is the backbone of any web page. The following sites provide in-depth HTML details: Webmonkey http://www.webmonkey.com/webmonkey/authoring W3 Schools http://www.w3schools.com/html Cascading Style Sheets Tutorials Cascading Style Sheets (CSS) and the JavaScript style object were used throughout the book to add formatting to HTML elements. CSS is a big topic all on its own. Webmonkey stylesheets http://www.webmonkey.com/webmonkey/authoring/ W3 Schools http://www.w3schools.com/css/default.asp Westciv http://www.westciv.com/style_master/academy/css_tutorial Advanced Topics in JavaScript There aren’t many aspects of JavaScript not covered in this book. You might want to learn even more about object-oriented programming in JavaScript, how events work in different browsers, and handling errors. Object-Oriented Programming Object-oriented programming (OOP) is a programming style that simplifies many aspects of programming. The following tutorials at WebReference.com describe OOP in detail and discuss how to use this style of coding with JavaScript: http://www.webreference.com/js/column79 http://www.webreference.com/js/column80 Advanced Event Handling Chapters 2 and 13 covered many details about how to handle events in JavaScript. Believe it or not, there is a bit more to learn on the topic. A series of articles at the bottom of this QuirksMode.org page give an excellent indepth discussion of advanced event handling: http://www.quirksmode.org/js/contents.html Exception Handling JavaScript has some fancy ways of responding to errors in your code. The following tutorial at Dev Shed discusses how to use the JavaScript commands try and catch to capture errors and respond to them. http://www.devshed.com/c/a/JavaScript/JavaScript-Exception-Handling 406 Appendix B Ajax Tutorials Because Ajax is a complex topic, there are many tutorials about it. For tutorials that focus on Ajax frameworks, see “Ajax Frameworks” on page 408. For general Ajax tutorials, a regularly updated list of Ajax tutorials may be found at http://www.maxkiesler.com/index.php. Especially helpful will be the “Round-up of 30 AJAX Tutorials” (March 15, 2006) and “60 More AJAX Tutorials” (May 8, 2006). Example JavaScript and Ajax Code The following sites contain many examples of JavaScript and Ajax code that you can cut and paste into your web pages. dhtmlgoodies.com http://www.dhtmlgoodies.com A nicely laid-out site from Alf Magne Kalleland The JavaScript Source http://javascript.internet.com EarthWeb’s JavaScript resource, with over two thousand scripts and counting Dynamic Drive http://www.dynamicdrive.com Another very nicely laid-out site, with a CSS library as well JS Made Easy.com http://www.jsmadeeasy.com Code examples, tutorials, and JavaScript cheat sheets Webmonkey http://www.webmonkey.com/webmonkey/reference/ javascript_code_library An oldie but a goodie, close to my heart Good Ajax Websites These sites provide news and tips for Ajax programmers. ajaxian http://ajaxian.com My favorite site for Ajax news Ajax Goals http://ajaxgoals.com Another good Ajax news site AjaxPatterns http://ajaxpatterns.org An Ajax wiki with a great deal of information about advanced Ajax topics AJAX Magazine http://ajax.phpmagazine.net Not updated as frequently as the rest, but that can be a good thing R e so u r c es 407 Ajax Frameworks As you’ve seen, the code for Ajax applications can get complicated and long. However, there is a fair amount of code that is common to many Ajax applications. Creating a request object, for example, occurs in every Ajax application. Ajax frameworks do a great deal of the work for you. Frameworks exist for handling XML, achieving common interface effects such as drag and drop, and working with numerous server-side languages. Here is a list of some of the most commonly used frameworks, separated into categories based on the server-side languages they work with. All the frameworks are free, or have a free version, unless otherwise specified. This is just a sample of available frameworks. See http://ajaxpatterns.org/Ajax_Frameworks for a more exhaustive list. JavaScript The following sites provide numerous JavaScript widgets and libraries used by many professional sites to ease their JavaScript coding. Dojo http://dojotoolkit.org Lots of navigation and page layout tools, such as drag and drop, slide shows, collapsible trees, rich text editors, and more Lightbox http://www.huddletogether.com/projects/lightbox2 Nice library for displaying and managing images using Prototype and Scriptaculous, which are available from sites in this list Mochikit http://mochikit.com Hundreds of JavaScript functions, covering areas including string formatting, date and time handling, logging, CSS manipulation, and all sorts of visual effects Prototype http://prototype.conio.net A JavaScript programming framework that promotes good object-oriented programming and includes Ajax support, higher-order programming constructs, and easy DOM manipulation (lots of other toolkits use this, so most likely you will too) Rico http://openrico.org A very popular user interface client that uses Prototype Simple Ajax Code Kit (SACK) http://twilightuniverse.com/resources/ code/sack Gives you a fancy way to deal with the standard request object Sarissa http://sarissa.sf.net An excellent toolkit to support XML manipulation, including good ways to query XML documents and easy calls to turn XML documents into strings 408 Appendix B Scriptaculous http://script.aculo.us This very popular framework gives you lots of visual effects, using Prototype Spry http://labs.adobe.com/technologies/spry A framework from Adobe intended to give web designers access to the powers of Ajax without having to know very much JavaScript PHP The following sites provide tools for developing Ajax applications using PHP. CakePHP http://cakephp.org A popular rapid development framework for PHP that integrates well with the Prototype JavaScript library Ajax Task List http://grahambird.co.uk/cake/tutorials/ajax.php A good tutorial for CakePHP, also based on a To Do list application Simple Ajax Toolkit (Sajax) http://www.modernmethod.com/sajax Lets you call PHP code from within your JavaScript and makes it easier to do PHP calls without having to bother with sending information to the webserver via a request object Java Fans of the Java programming language can find useful tools for Ajax programming in the following list. AjaxTags http://ajaxtags.sourceforge.net Tags for Java Server Pages to provide common Ajax techniques such as form validation, text box auto-complete, and content highlighting Direct Web Remoting (DWR) http://getahead.ltd.uk/dwr A very popular framework that allows you to embed Java calls inside your JavaScript, much like the PHP framework Sajax Echo2 http://www.nextapp.com/platform/echo2/echo A Java servlet that generates the JavaScript for you to create and run an entire Ajax application in Java Google Web Toolkit (GWT) http://code.google.com/webtoolkit A Java-to-JavaScript translator that enables you to code your Ajax in Java, then convert it to JavaScript; similar to Echo2, except in GWT all the code runs on the client side Comparing the Google Web Toolkit to Echo2 http://www.theserverside.com/news/thread.tss?thread_id=40804 A thorough comparison of Echo2 and GWT (written by the author of Echo2) R e so u r c es 409 .NET Coders who prefer to use Microsoft’s .NET technology will find Ajax support at the following sites. Atlas http://atlas.asp.net Free web development framework from Microsoft, marketed as integrating “cross-browser client script libraries with the ASP.NET 2.0 serverbased development framework” ComfortASP.NET http://www.comfortasp.de A framework that enables you to add many Ajax features to sites in the Active Server Pages (ASP) environment without needing to know how to program; features include timers, prevention of multiple form submits, and handling the Ajax calls Ruby Ruby is not a new programming language, but it has recently become very popular among web developers. Ruby on Rails http://www.rubyonrails.org A framework for developing database-backed web applications that has Ajax support and a cultlike following (some of my friends swear by it) 410 Appendix B REFERENCE TO JAVASCRIPT OBJECTS AND FUNCTIONS This reference covers all objects and functions currently part of JavaScript in Firefox and various versions of Internet Explorer. Each entry appears with the earliest version of Internet Explorer that supports it and whether or not Firefox supports it. For example, an entry listed with FF, IE 5 will work in Firefox 1.0, Internet Explorer 5, and later versions of those browsers. In the summer of 2006, according to a variety of sites (including W3 Schools,1 Counter.com,2 and the Browser News3), approximately 70 percent of users were using some version of Internet Explorer (mostly IE 6), and 1 See http://www.w3schools.com/browsers/browsers_stats.asp. 2 See http://www.thecounter.com/stats/2006/August/browser.php. 3 See http://www.upsdell.com/BrowserNews/stat.htm. 18 percent of users were using some version of Firefox. An additional 4 percent were using a browser that executes JavaScript much as Firefox does (such as Netscape, Opera, or Safari). The remaining 8 percent represent a hodgepodge of earlier browsers, Internet spiders (like Google’s) that crawl around the Internet adding websites to their databases, and later browsers that may or may not support JavaScript but, if they do, probably support the same objects and methods as Firefox. If you want the flashiest web pages, writing JavaScript for IE 5.5 and Firefox will allow at least 92 percent of web browsers to see your pages. To expand that by another 1 percent or so, you could go through the extra effort of writing special code for IE 4 and Netscape 4 browsers. In that case, I recommend you buy the latest version of The JavaScript Bible by Danny Goodman (Wiley, 2004). If I have used an entry in this book or consider it an important function, I define it here and illustrate it with an example. For the less common JavaScript functions and objects, I provide brief descriptions and list the browsers that support them. This reference capitalizes object entries and lists them with their methods, properties, and handlers (properties come first, in alphabetical order, followed by methods, and then handlers). Because certain browsers support some but not all of an object’s properties, methods, and handlers, I list each item with the earliest browser versions that support it. Object properties can be read-only or read-write. If a property is read-write, JavaScript can look up and change its value. However, JavaScript can’t change a read-only property—JavaScript can only look up the value of that property. For example, JavaScript changes (writes to) the src property of an image in an image swap: window.document.my_image.src = "happy.gif"; JavaScript can also look it up (read it): var the_gif_showing = window.document.my_image.src; On the other hand, JavaScript can only look up the firstChild property of a DOM node: var my_child = window.document.getElementById('something').firstChild; In Firefox and other similar browsers, some properties can be written to only if the script is “signed.” See http://www.mozilla.org/projects/security/ components/signed-scripts.html for more information on signed scripts. Unless stated otherwise, the properties in this appendix are read-write. Although this reference tries to cover all the objects and methods you are likely to need when writing JavaScript, browsers have literally hundreds of browser-specific methods and properties, and new ones are added with each new browser version. Get the most complete references straight from the horses’ mouths: Internet Explorer http://www.microsoft.com/technet/prodtechnol/IE Firefox 412 Appendix C http://developer.mozilla.org alert() [FF, IE 3] Displays a dialog box with one button labeled OK and a message specified by the function’s parameter. For example: alert("Hello, world!"); creates a dialog box with the words Hello, world! and an OK button. The browser window is frozen until the user clicks the OK button. Anchor All anchors on a page are stored in the document’s anchor array: window.document.anchors[]. Example: Properties hash FF, IE 3 Contents of an anchor after the # character host FF, IE 3 Hostname and the port of a link hostname FF, IE 3 Hostname of an anchor href FF, IE 3 href of the anchor name FF, IE 4 Anchor tag’s name pathname FF, IE 3 Part of an anchor after the host port FF, IE 3 Port of an anchor (usually null) protocol FF, IE 3 Protocol of an anchor (http and ftp are the most common) rel, rev FF, IE 3 Additional attribute, called rel or rev, used in some anchors to add more information about the link search FF, IE 3 Part of an anchor following the ? character target FF, IE 3 HTML target of an anchor Applet Refers to a Java applet. All applets on a page are stored in the JavaScript array window.document.applets[]. Properties code FF, IE 4 Read-only: URL string of the applet’s Java class file codeBase FF, IE 4 Read-only: Path to the applet, not including the class file name height, width FF, IE 4 Size of the applet display section hspace, vspace FF, IE 4 Padding around the applet display, in pixels name FF, IE 4 Read-only: Applet’s name Re f e r e n c e to J a v a S c r i p t O b j e ct s a nd F un c ti o ns 413 Methods start() FF, IE 3 Starts a Java applet stop() FF, IE 3 Stops a Java applet For example: window.document.applets[0].start(); tells the first Java applet on a web page to start, while window.document.applets[0].stop(); tells the first Java applet on a web page to stop. Area [FF, IE 3] An HTML tag that describes a clickable region inside a client-side image map. Area tags are stored in the JavaScript array window.document.links[]; an area is treated just like a link object (see “Link” on page 431 for more information). Array [FF, IE 3] A list of information. There are two ways to create an array: var the_array = new Array(); var the_array = new Array(element_one, element_two, element_three...); You can look up or change elements in an array using their position numbers (numbering starts with 0): the_array[0] = "thau!"; window.document.writeln(the_array[0] + " wrote this book."); Properties length FF, IE 3 Number of elements in an array Example: var my_array = new Array("eenie", "meenie", "miney", "moe"); var number_of_things = my_array.length; The variable number_of_things holds the value 4, because there are four elements in the array. prototype 414 Appendix C FF, IE3 Adds properties and methods to all objects of an array. See the tutorials in “Object-Oriented Programming” on page 406. Methods join() FF, IE 3 Creates a string from an array. Each element in the array will be listed in the string and separated by a space from the previous and following ele-ments, unless some other delimiter is listed as a parameter to join(). Example: var my_array = new Array("eenie", "meenie", "miney", "moe"); var my_string = my_array.join(":"); The variable my_string contains eenie:meenie:miney:moe. reverse() FF, IE 3 Returns a copy of an array with the elements reversed Example: var my_array = new Array("eenie", "meenie", "miney", "moe"); var new_array = my_array.reverse(); The variable new_array contains an array with the elements moe, miney, meenie, and eenie, in that order. sort() FF, IE 4 Returns an array with the elements of another array sorted in alphabetical order. If the name of a function is listed as a parameter to sort(), that function will define the order of two elements passed to it as follows: z If the function returns a value less than 0, the first element is smaller than the second. z If the function returns a value greater than 0, the second element is smaller than the first. z If the function returns 0, do not change the order of the elements. Examples: var my_array = new Array("eenie", "moe", "miney", "meenie"); var sorted_array = my_array.sort(); The variable sorted_array contains the elements eenie, meenie, miney, and moe in that order. var my_array = new Array(1, 12, 2); var sorted_array = my_array.sort(numericalSorter); function numericalSorter(element_one, element_two) { return element_one - element_two; } The variable sorted_array contains the elements 1, 2, and 12, in that order. Re f e r e n c e to J a v a S c r i p t O b j e ct s a nd F un c ti o ns 415 Less Common Methods concat() FF, IE 4 Concatenates many elements into one array pop() FF, IE 5.5 Returns the last element of an array and deletes that element from the array push() FF, IE 5.5 Appends a value to the end of an array shift() FF, IE 5.5 Returns the first element of an array and shifts the other elements to replace it slice() FF, IE 4 Creates a new array by taking a piece out of this array splice() FF, IE 5.5 Replaces or deletes parts of an array or puts something in the middle toString() FF, IE 3 Converts an array into a comma-separated string unShift() FF, IE 5.5 Appends a value to the start of an array Button (Including Submit and Reset Buttons) The button, submit, and reset form elements. Properties form FF, IE 3 Read-only: Form containing the button name FF, IE 3 Name of a button. Note that name is not the text that shows up in the button on the web page (see the value property). type FF, IE 3 Read-only: Type of button: button, submit, or reset value FF, IE 3 String shown on the button onClick FF, IE 3 Triggered when a visitor clicks on the button onMouseDown FF, IE 4 Triggered when the mouse is clicked on the button onMouseUp FF, IE 4 Triggered when the mouse is released after clicking Handlers Example: When the user clicks this button, the words on the button change from Click me to Stop clicking me! Methods click() 416 Appendix C FF, IE 3 Simulates the act of clicking the button Checkbox The checkbox form element. Properties checked FF, IE 3 true if a visitor has selected the checkbox, false otherwise. Setting the property to true will cause the checkbox to act as if a visitor had selected the box. form FF, IE 3 Read-only: Form containing the checkbox name FF, IE 3 Name of a checkbox type FF, IE 3 Read-only: Set to 'checkbox' value FF, IE 3 Value of the checkbox Example: if (window.document.my_form.the_checkbox.checked == true) { alert("Thanks for clicking the checkbox!"); } Handlers onClick FF, IE 3 Triggered when a visitor clicks the checkbox FF, IE 3 Simulates the act of clicking the checkbox Methods click() clearInterval() [FF, IE 4] Cancels an interval set by setInterval(). JavaScript commands may execute repeatedly every n milliseconds. See “setInterval()” on page 440 for more information. clearTimeout() [FF, IE 3] Cancels a time-out set by setTimeout(). See “setTimeout()” on page 441 and Chapter 9 for more information on time-outs. For example: clearTimeout(my_timeout); cancels a time-out named my_timeout. Re f e r e n c e to J a v a S c r i p t O b j e ct s a nd F un c ti o ns 417 confirm() [FF, IE 3] Creates a dialog box with two buttons, OK and Cancel, and text specified by the function’s parameter. Clicking OK results in the function returning a value of true, and clicking Cancel results in a false value. Example: if (confirm("Are you feeling happy?")) { alert("Clap your hands!"); } else { alert("Don't worry!"); } This example calls up a dialog box with the text Are you feeling happy? along with an OK button and a Cancel button. Clicking the OK button causes the function to return true, executing the first part of the if-then-else statement with an alert box showing the words Clap your hands! Clicking Cancel causes the function to return false, triggering the else clause of the if-then-else statement and calling an alert box showing the words Don’t worry! Date This object represents dates; you can create it in several ways: var var var var var the_date the_date the_date the_date the_date = = = = = new new new new new Date(); Date("month dd, yyyy"); Date("month dd, yyyy hh:mm:ss"); Date(yy, mm, dd); Date(milliseconds); Here month is the name of the month (January, February, and so on), dd is a two-digit day (01 to 31), yyyy is a four-digit year (0000 to 9999), and so on. If you create a Date object without anything in the parentheses, JavaScript will assume you mean the current date and time according to the computer that’s running the JavaScript. The Date object has numerous methods for getting and setting the date. Except where noted, the methods work for all JavaScript-enabled browsers. Methods for Getting the Date and Time Supported by FF and IE 3 except where noted. 418 Appendix C getDate() Returns the day of the month as an integer from 1 to 31 getDay() Returns the day of the week as an integer, where 0 is Sunday and 1 is Monday getFullYear() Returns the year as a four-digit number (only in FF, IE 4) getHours() Returns the hour as an integer between 0 and 23 getMinutes() Returns the minutes as an integer between 0 and 59 getMonth() Returns the month as an integer between 0 and 11, where 0 is January and 11 is December getSeconds() Returns the seconds as an integer between 0 and 59 getTime() Returns the current time in milliseconds, where 0 is January 1, 1970, 00:00:00 Example: var the_date = new Date(); var the_hours = the_date.getHours(); If the clock on the computer running the JavaScript thinks it’s 8 PM, the_hours contains the number 20. Methods for Getting the UTC Date and Time The following methods (FF, IE 4) return dates and times in UTC time (Universal Time Coordinate, measured somewhat differently from Greenwich Mean Time, which it replaced as the world standard). getUTCDate() Returns the day of the month as an integer from 1 to 31 getUTCDay() Returns the day of the week as an integer, where 0 is Sunday and 1 is Monday getUTCFullYear() Returns the year as a four-digit number getUTCHours() Returns the hour as an integer between 0 and 23 getUTCMinutes() Returns the minutes as an integer between 0 and 59 getUTCMonth() Returns the month as an integer between 0 and 11, where 0 is January and 11 is December getUTCSeconds() Returns the seconds as an integer between 0 and 59 The Problematic getYear() Method The getYear() method should return the number of years since 1900, but its behavior differs from browser to browser. Some browsers perform as advertised—for example, returning 110 if the year is 2010. Others, however, equate getYear() with getFullYear(), returning 2010 if the year is 2010. Because of these cross-browser discrepancies, it’s best to adjust the date provided by getYear() as follows: var the_date var the_year if (the_year { the_year } = new Date(); = the_date.getYear(); < 1000) = the_year + 1900; This code always results in the_year containing the correct four-digit year. Re f e r e n c e to J a v a S c r i p t O b j e ct s a nd F un c ti o ns 419 Methods for Setting the Date and Time The following methods change the contents of a Date object (FF, IE 3, except where noted): setDate() Sets the day of the month as an integer from 1 to 31 setFullYear() Sets the year as a four-digit number (only in FF and IE 4) setHours() Sets the hour as an integer between 0 and 23 setMinutes() Sets the minutes as an integer between 0 and 59 setMonth() Sets the month as an integer between 0 and 11, where 0 is January and 11 is December setSeconds() Sets the seconds as an integer between 0 and 59 setTime() Sets the current time in milliseconds, where 0 is January 1, 1970, 00:00:00 setYear() Sets the year—uses two digits if the year is between 1900 and 1999, four digits otherwise Example: var the_date = new Date(); the_date.setHours(22); the_date.setYear(2012); The Date object called the_date thinks it’s 10 PM in the year 2012. Methods for Setting the UTC Date and Time The following methods (FF, IE 4) are like the ones just described, except the dates and times set by the methods are adjusted to reflect UTC time, the replacement for Greenwich Mean Time. setUTCDate() Sets day of the month as an integer from 1 to 31 setUTCFullYear() Sets the year as a four-digit number setUTCHours() Sets the hour as an integer between 0 and 23 setUTCMinutes() Sets the minutes as an integer between 0 and 59 setUTCMonth() Sets the month as an integer between 0 and 11, where 0 is January and 11 is December setUTCSeconds() Sets the seconds as an integer between 0 and 59 Example: var the_date = new Date(); the_date.setUTCHours(10); If the computer is one time zone to the west of Greenwich, England, the_date will now think it’s 9 AM UTC. 420 Appendix C Methods for Converting Dates to Strings These methods turn the date stored in a Date object into a string. toGMTString() FF, IE3 Returns the date adjusted to reflect Greenwich Mean Time, the former world standard toUTCString() FF, IE4 Suggested method for later browsers Document The document of a window holds all the HTML elements of the web page in that window. Properties alinkColor FF, IE 3 Color of a link when you click it anchors[] FF, IE 3 Read-only: Array of anchor objects. See “Anchor” on page 413 for more information. applets[] FF, IE 3 Read-only: Array storing the applets in the document. See “Applet” on page 413 for more information. bgColor FF, IE 3 Background color of a page. The value can be the name of a color or a hexadecimal triplet. Example: window.document.bgColor = "#000000"; This line makes the background of a page black. body FF, IE 4 Body element of a web page cookie FF, IE 3 HTML cookie associated with this document. See Chapter 12 for more information on cookies. documentElement FF, IE 5 Read-only: Root element of an XML file domain FF, IE 4 Domain of a web page (e.g., nostarch.com) embeds[] FF, IE 4 Read-only: Array of embeds[] fgColor FF, IE 3 Default font color forms[] FF, IE 3 Array that stores all of a document’s forms. See “Form” on page 424 for more information. images[] FF, IE 3 Array that stores all of a document’s images. See “Image” on page 429 for more information. lastModified FF, IE 3 Read-only string that stores the date on which a user most recently changed the document Example: window.document.writeln("last changed on: " + window.document.lastModified); This line writes the date of the last time the page was modified. Re f e r e n c e to J a v a S c r i p t O b j e ct s a nd F un c ti o ns 421 linkColor FF, IE 3 Default color of a link links[] FF, IE 3 Array storing all of a document’s hyperlinks. See “Link” on page 431 for more information. referrer FF, IE 3 Read-only string containing the domain name of the hyperlink that led to this page For example: window.document.writeln("Thanks for coming from " + window.document.referrer); writes Thanks for coming from www.nostarch.com if a hyperlink from the No Starch Press website led to the page. styleSheets[] FF, IE 4 Read-only: Array of all style elements title FF, IE 3 Contains the document’s title For example: window.document.title = "Presto Chango"; changes the title of the page to Presto Chango. URL FF, IE 4 URL of the document vlinkColor FF, IE 3 Color of visited links; can’t be changed once you write the link Methods 422 Appendix C close() FF, IE 3 Use close() when you’ve finished writing to the document (optional). Sometimes, because of browser bugs, writing to a web page using document.write() won’t actually complete that action unless you execute document.close() after executing document.write(). createAttribute() FF, IE 6 Given a string, creates an XML attribute named that string createElement() FF, IE 4 Given a string, creates an XML element named that string createTextNode() FF, IE 5 Given a string, creates a text node with a nodeValue equal to the string getElementById() FF, IE 5 Returns the element in a document that has the id equal to a provided string getElementsByName() FF, IE 5 Returns an array of elements that have a name attribute set to a given string getElementsByTagName() FF, IE 5 Returns an array of elements which have a given name, such as
    or open() FF, IE 3 Use open() if you want to clear the contents of a web page before writing to it using write() or writeln(). If you use document.open(), use document.close() when you’re done writing to the page. write(), writeln() FF, IE 3 Writes to a web page. The only difference between these two methods is that writeln() appends a line break at the end of whatever is written. elements[] [FF, IE 3] An array in the form object that stores all the elements (buttons, checkboxes, radio buttons, and so on) of a form. See “Form” on page 424 for more information. escape() [FF, IE 3] Formats a string so that it conforms to URL encoding. Generally used for setting cookies (Chapter 12) and sending information to servers (Chapters 15 and 16). Example: var encoded_string = escape("a string safe for cookies"); The variable encoded_string now holds a%20string%20safe%20for%20cookies because the escape function replaces spaces with %20. See “unescape()” on page 448 for more information. eval() [FF, IE 3] Evaluates a string. Example: var the_sum = eval("2 + 3"); The variable the_sum will equal 5 because eval() forces JavaScript to evaluate the string "2 + 3". Event The event object describes an event that just happened: a mouse click, a cursor movement, and so on. See Chapter 13 for more details. Properties altKey FF, IE 4 true if the ALT key is held down button FF, IE 4 If the event involves a click, this says what kind. A 2 means the right button was clicked. Some other number probably means the left button. See Chapter 13 for more information. clientX IE 4 x coordinate of an event in a window clientY IE 4 y coordinate of an event in a window ctrlKey FF, IE 4 true if the CTRL key is held down keyCode FF, IE 4 ASCII value of the key that was pressed pageX FF x coordinate of an event in a window pageY FF y coordinate of an event in a window screenX FF, IE 4 x coordinate of an event on the screen screenY FF, IE 4 y coordinate of an event on the screen shiftKey FF, IE 4 true if the SHIFT key is held down srcElement IE 4 Element that received the event Re f e r e n c e to J a v a S c r i p t O b j e ct s a nd F un c ti o ns 423 target FF Element that received the event type FF, IE 4 Type of event FileUpload The FileUpload form element lets a visitor choose a file on the computer to submit to a CGI script along with the form. Use the syntax . Properties name FF, IE 3 Name of the FileUpload field value FF, IE 4 Read-only: Filename selected Methods blur() FF, IE 3 Removes the cursor from the FileUpload element focus() FF, IE 3 Moves the cursor to the FileUpload element select() FF, IE 3 Selects the text inside the FileUpload element onBlur FF, IE 3 Called when the user removes the cursor from the field onChange FF, IE 3 Triggered when a visitor changes the contents of the field onFocus FF, IE 3 Called when the user puts the cursor into the field Handlers Form Every form on a web page has a form object. The window.document.forms[] array stores all of a web page’s form objects. Properties Each type of Form element—button, checkbox, FileUpload, hidden, password, radio, reset, select, submit, text, and textarea—has its own object listing in this appendix. See each individual object for more information. action FF, IE 4; read-only in IE 3 Triggers a specified CGI script when a user submits the form Example: if (user == "expert") { window.document.the_form.action = "expert_script.cgi"; } else { window.document.the_form.action = "basic_script.cgi"; } If the user is considered an expert, the form is set to run expert_script.cgi when the user submits the form. 424 Appendix C elements[] FF, IE 3 Array of the elements of this form For example: window.document.form_name.elements[0].checked = true; will set the checked value of the first element of the form named form_name to true. encoding FF, IE 4; read-only in IE 3 How the information in the form is encoded when it’s sent to a CGI script. It’s almost always "application/x-www-form-urlencoded" and there’s almost never a reason to change it. length FF, IE 3 Number of elements in a form Example: var number_elements = window.document.the_form.length; method FF, IE 4; read-only in IE 3 Specifies how a form sends information (via either POST or GET) to the CGI script listed in the action tag Example: window.document.the_form.method = "GET"; FF, IE 3 name Looks for a form by name if you need to locate it For example: window.document.form_name indicates the form named form_name. target FF, IE 3; read-only in IE 3 Window in which the form is to write the results of the form’s CGI script. If the target specifies a window that does not exist, a new window opens. Example: var target_window = window.open("blank.html","my_target"); window.document.the_form.target = "my_target"; The first line opens a window with the name my_target. The second line tells the form named the_form that the CGI script it runs should return its results to the window named my_target. Re f e r e n c e to J a v a S c r i p t O b j e ct s a nd F un c ti o ns 425 Methods FF, IE 4 reset() Resets the elements of a form, as if a visitor clicked a reset button Example: window.document.the_form.reset(); FF, IE 3 Submits the form, as if a visitor clicked a submit button, except that the onSubmit handler is not called when the submit() method is invoked onReset FF, IE 3 Triggered when a form is reset onSubmit FF, IE 3 Triggered when a form is submitted. Executing return false inside a submit handler stops submission of the form to the CGI script. submit() Handlers Example:
    This calls the function formNotDone() on the form. If the function returns true, the if-then statement returns false and the form is not submitted. Note that formNotDone() is not a built-in JavaScript function. See Chapter 11 for more information on form validation. Hidden An invisible form element that can store values on a web page without the visitor seeing them; useful for sending secret information to a CGI script. Properties name FF, IE 3 Name of a hidden element value FF, IE 3 Value of a hidden element For example: window.document.the_form.my_hidden.value = "a nice person"; will set the value of the hidden element named my_hidden to a nice person. If the form is subsequently sent to a CGI script, the value will be passed along. History The history of URLs visited by the visitor’s browser. 426 Appendix C Properties FF, IE 4 length Number of URLs in the history list Methods FF, IE 3 back() Returns to the previous page (like clicking the browser’s back button) Example: history.back(); FF, IE 3 forward() Advances to the next page (like clicking the browser’s forward button) Example: history.forward(); FF, IE 3 go() Takes one parameter: the number of URLs to advance (positive values) or go back (negative values). In IE 3, the parameter can be only 1, 0, or 1. Example: history.go(-2); HTMLElement [FF, IE 4] All HTML elements (images, links, forms, and form elements) are considered objects. Properties all[] FF, IE 4 Read-only: Array holding all the elements the element contains attributes[] FF, IE 5 Read-only: Array holding all the attributes of an element childNodes[] FF, IE 4 Read-only: Array of child nodes className FF, IE 4 CSS identifier for the element dir FF, IE 5 Contents of an HTML element’s dir attribute disabled FF, IE 4 If set to true, dims the element so that it looks inactive document FF, IE 4 Read-only: Reference to the element’s document firstChild, lastChild FF, IE 5 Read-only: First or last child node of an element height, width FF, IE 5 Height and width of an element id FF, IE 4 id attribute of an element innerHTML FF, IE 4 HTML text inside the element, not including the start and end tags lang FF, IE 4 Element’s lang attribute, used by Internet Explorer to determine how to display language-specific characters Re f e r e n c e to J a v a S c r i p t O b j e ct s a nd F un c ti o ns 427 nextSibling, previousSibling FF, IE 5 Read-only: Next or previous sibling of an element or node. See Chapter 14 for details. nodeName FF, IE 5 Read only: Name of a node or element nodeType FF, IE 5 Read only: Type of node or element. 1 = element, 2 = attribute, 3 = text node, 8 = comment, 9 = document node nodeValue FF, IE 5 Value of a textNode, or null offsetHeight, offsetWidth FF, IE 4 Read-only: Element’s height and width offsetLeft, offsetTop FF, IE 4 Read-only: Horizontal or vertical position of the element in pixels, relative to the containing element offsetParent FF, IE 4 Read-only: Reference to the element that contains this element parentNode FF, IE 5 Read-only: Parent node of this node or element scrollHeight, scrollWidth FF, IE 4 Read-only: Measurements of an element regardless of how much is visible scrollLeft, scrollTop FF, IE 4 Read-only: Amount an object is scrolled, in pixels style FF, IE 4 Element’s CSS style information tabIndex FF, IE 4 Position of this element in the traversal order (the order in which elements are selected successively by pressing the TAB key) tagName FF, IE 4 HTML tag name of the element Methods 428 Appendix C addEventListener(), removeEventListener() FF Advanced event handling for Firefox. See “Advanced Event Handling” on page 406. appendChild() FF, IE 5 Append a node to the end of another node’s array of child elements attachEvent(), detatchEvent() IE 5 Advanced event handling for Internet Explorer. See “Advanced Event Handling” on page 406. blur() FF, IE 3 Moves focus off an element click() FF, IE 3 Simulates a click on an element cloneNode() FF, IE 5 Makes a copy of a node. If true is passed as a parameter, the node and all its children (and their children . . . ) are also copied. dispatchEvent() FF Advanced event handling for Firefox. See “Advanced Event Handling” on page 406. fireEvent() IE 5.5 Advanced event handling for Internet Explorer. See “Advanced Event Handling” on page 406. getAttribute() FF, IE 4 Given a string with an attribute name, returns the value of the attribute of this element focus() FF, IE 3 Moves focus onto an element getAttributeNode() FF, IE 6 Given a string with an attribute name, gets a node representing the attribute of this element getElementsByTagName() FF, IE 5 Given a string with the name of an HTML or XML element, returns an array with all the elements with that tag name hasChildNodes() FF, IE 5 Returns true if this element has child elements insertBefore() FF, IE 5 Given a new child node and a reference child node, inserts the new child node into this element’s list of children before the reference child node item() FF, IE 5 Given a number, returns the child of this node with that index number (the first child is item 0) releaseCapture(), setCapture() IE 5 Advanced event handling for Internet Explorer. See “Advanced Event Handling” on page 406. removeAttribute() FF, IE 4 Given the name of an attribute, removes it from this element removeAttributeNode() FF, IE 6 Given an attribute node, removes it from this element removeChild() FF, IE 5 Given a node, removes it from the children list of this element replaceChild() FF, IE 5 Given a new child node and an old child node, replaces the old child node with the new one setAttribute() FF, IE 6 Adds an attribute node to this element Handlers [FF, IE 4] onBlur onDblclick onHelp onKeyPress onMouseDown onMouseOut onMouseUp onClick onFocus onKeyDown onKeyUp onMouseOver onMouseOver onResize Image JavaScript stores images in the images array of the document object. A user may create a new image object as follows: var new_image = new Image(); This statement creates a new image and sets its src property to a GIF or JPEG, then preloads that file. See Chapter 4 for more information about images and preloading. Properties align FF, IE 4 Orientation of an image relative to the surrounding text. Values can be: absbottom, absmiddle, baseline, bottom, left, middle, right, texttop, top alt FF, IE 4 alt text of an image border FF, IE 4 Size of the border around the image Example: var the_border_size = window.document.my_image.border; complete FF, IE 4 Read-only: true if the image has completely downloaded and false otherwise Re f e r e n c e to J a v a S c r i p t O b j e ct s a nd F un c ti o ns 429 Example: if (window.document.pretty_bird.complete) { alert("you should now see a pretty bird"); } height, width FF, IE 4 Height of an image in pixels hspace, vspace FF, IE 4 Number of transparent pixels around an image isMap FF, IE 4 If set to true, the x and y coordinate of the image is sent to whatever server-side program appears in an anchor link around the image lowsrc FF, IE 4 Image to show on a low-resolution monitor Example: window.document.the_image.lowsrc = "small_image.gif"; name FF, IE 4 Name of an image; JavaScript can use this to identify the image Example: If this appears on your web page, the following JavaScript swaps sad.gif with happy.gif: window.document.my_image.src = "happy.gif"; The name of the image, my_image, identifies which image to swap. src FF, IE 4 Name of the file containing the image to show For example: window.document.my_image.src = "happy.gif"; swaps the image contained in the file happy.gif into the image named my_image. isNaN() [FF, IE 4] Returns true if the parameter is not a number, false otherwise. Example: var zip_code = "none of your business"; if (isNaN(zip_code)) { alert("Please provide something that at least looks like a zip code!"); } Since zip_code contains a string, isNaN() returns true, triggering the alert. 430 Appendix C Link The hypertext link object: . See “Anchor” on page 413 for more information. Location The location object controls the URL shown in the browser window. Properties hash FF, IE 3 Part of the URL following a hash mark Example: window.location.hash = "where_to_go"; This will cause the browser to jump to the position of the current page that has the anchor . host FF, IE 3 Hostname and port of a URL For example, if the URL is http://www.feedmag.com:80/index.html, the host is www.feedmag.com:80. hostname FF, IE 3 Domain of the URL shown in the browser Example: if (window.location.hostname == "www.nostarch.com") { alert("welcome to No Starch Press"); } href FF, IE 3 Full path of the page shown. Changing href causes the browser to load the specified page. For example: window.location.href = "http://www.nostarch.com/index.html"; loads the page index.html from the No Starch Press website. pathname FF, IE 3 Path and filename shown in the browser window (the URL minus the domain information) Example: var the_path = window.location.pathname; The variable the_path will hold "index.html" if the window is currently showing http://www.nostarch.com/index.html. Re f e r e n c e to J a v a S c r i p t O b j e ct s a nd F un c ti o ns 431 FF, IE 3 port URL’s port If the URL is http://www.feedmag.com:80/index.html, the port will be 80. FF, IE 3 protocol URL’s protocol If the URL is http://www.feedmag.com:80/index.html, the protocol will be "http". search FF, IE 3 Part of a URL following a question mark If the URL is http://www.webmonkey.com/index.html?hello_there, var the_search = window.location.search; the variable the_search will contain "hello_there". Methods reload() FF, IE 4 Reloads the page For example: window.location.reload(); will act as if a visitor clicked the reload or refresh button in the browser. replace() FF, IE 4 Loads the page specified by the URL passed as a parameter into the browser window. The page shown when replace() is called is removed from the browser’s history and replaced with the new page. This means that clicking the back button after the new page has replaced the currently shown page won’t result in revisiting the current page. It’s as if you’re telling the browser to forget the currently shown page. Example: window.location.replace("http://www.npr.com"); 0 Math [FF, IE 3] The math object contains numerous properties and methods. Except where noted, all of these properties and methods work in Firefox, IE 3, and more recent browsers, and all the properties are read-only. Because most of the methods and properties are self-explanatory, I will give few examples. I’ll round all numbers to the sixth decimal point. 432 Appendix C Properties E e, Euler’s constant, the base of natural logarithms (2.718282) LN2 Natural log of 2 (0.693147) LN10 Natural log of 10 (2.302585) LOG2E Base 2 log of e (1.442695) LOG10E Base 10 log of e (0.434294) PI Pi (3.141593) SQRT2 Square root of 2 (1.414214) Methods abs() Absolute value of the argument, for example, var ab_value = Math.abs(-10); sets ab_value to 10 acos() Arc cosine of the argument in radians asin() Arc sine of the argument in radians atan() Arc tangent of the argument in radians ceil() Integer greater than or equal to the number passed, for example, var the_ceiling = Math.ceil(9.5); sets the_ceiling to 10 cos() Cosine of the number of radians passed as the argument exp() Value of e raised to the power passed as the argument floor() Integer lower than or equal to the number passed as the argument log() Natural log of the argument max() Higher of the two numbers passed as arguments, for example, var the_higher = Math.max(10,11); sets the_higher to 11 min() Lower of the two numbers passed as arguments pow() First argument raised to the power passed as the second argument, for example, two_cubed = Math.pow(2,3); sets two_cubed to 8 (2 to the third power) random() Random number between 0 and 1 round() Argument rounded up if its decimal value is greater than or equal to 0.5 and rounded down otherwise sin() Sine of the number of radians passed as the argument sqrt() Square root of the argument tan() Tangent of the number of radians passed as the argument Navigator The navigator object lets JavaScript know what type of web browser your visitor is using. Properties appName FF, IE 3 Manufacturer of the browser (Netscape, Internet Explorer, Opera, and so on) Re f e r e n c e to J a v a S c r i p t O b j e ct s a nd F un c ti o ns 433 Example: if (navigator.appName == "Netscape") { window.location = "netscape_index.html"; } This code sends a visitor to a page called netscape_index.html if the visitor is using Netscape. FF, IE 3 appVersion String representing the version of the browser. It’s not useful unless interpreted with the parseFloat() function. Example: if (parseFloat(navigator.appVersion) < 2) { alert("Isn't it time to upgrade?"); } Less Common Properties appCodeName FF, IE 3 Read-only: Browser’s code name browserLanguage IE 4 Read-only: Language in which the browser’s interface is displayed, for example, "en-us" for U.S. English or "ar-iq" for Iraqi Arabic cookieEnabled FF, IE 4 Read-only: true if the browser can take cookies language FF Read-only: Language of the browser online FF, IE 4 Read-only: true if the browser is online platform FF, IE 4 Read-only: Browser’s operating system systemLanguage IE 4 Language in which the operating system’s interface is displayed userAgent FF, IE 3 Generally a string composed of appCodeName and appVersion Methods FF, IE 4 javaEnabled Read-only: true if Java is on Number The Number object has some helpful read-only properties. Properties 434 Appendix C MAX_VALUE FF, IE 4 Read-only: Highest integer possible given the configuration of the browser and the computer it’s on MIN_VALUE FF, IE 4 Read-only: Lowest integer possible given the configuration of the browser and the computer it’s on NaN FF, IE 4 Read-only: Not a number, the result if a mathematical operation fails (Math.sqrt(-1), for example); can be tested with the isNaN() function Example: if (isNaN(Math.sqrt(-1))) { alert("Get real! You can't take the square root of -1!"); } NEGATIVE_INFINITY FF, IE 4 Read-only: Value smaller than Number.MIN_VALUE. You know no number will ever be less than this value. POSITIVE_INFINITY FF, IE 4 Read-only: Value bigger than Number.MAX_VALUE. No number will ever exceed this value. Methods FF, IE 5.5 toExponential() Displays the number in exponential notation. An integer parameter specifies the number of digits to the right of the decimal point. Example: var the_answer = 4321; alert(the_answer.exponential(2)); The alert contains the string 4.32e+3. toFixed() FF, IE 5.5 Sets the number of digits following a decimal point. The number is rounded up if it has more trailing digits than n, and "0"s are used after the decimal point if needed to create the desired decimal length. toPrecision() FF, IE 5.5 Formats any number so it is of length n, where n is an integer passed as a parameter. Also called significant digits. A decimal point and "0"s are used if needed to create the desired length. toString() FF, IE 3 Turns a number into a string Option The option object refers to an option in a select element of a form—either a pull-down menu or scrollable list. All the options of a select element are stored in the options[] array of that element. Properties Form FF, IE 3 Form containing the option selected FF, IE 3 true if the option has been selected and false otherwise Example: if (window.document.the_form.the_pulldown.options[0].selected == true) { var the_option_text = window.document.the_form.the_pulldown.option[0].text; alert("thanks for picking " + the_option_text); } Re f e r e n c e to J a v a S c r i p t O b j e ct s a nd F un c ti o ns 435 text FF, IE 3 Text associated with an option (see the preceding example) value FF, IE 3 Value of the option parseInt() [FF, IE 3] Converts a string to an integer as long as the first character is a number. If the first character is not a number, parseInt() returns NaN (not a number). If the string is a number followed by letters, parseInt() grabs the first set of digits in the string. Example: var the_string = "123abc456"; var the_numbers = parseInt(the_string); The variable the_numbers contains 123. parseFloat() [FF, IE 3] Converts a string to a floating-point number as long as the first character is a number. If the first character is not a number, parseFloat() returns NaN (not a number). If the string is a number followed by letters, parseFloat() grabs the first set of numbers in the string. Example: var the_string = "3.14etc"; var the_numbers = parseFloat(the_string); The variable the_numbers contains 3.14. Password The password form element, like the text form element, allows a visitor to type a line of text into a form. In a password element, however, asterisks or bullets replace the letters to hide the contents from view. The element is represented like this in HTML: . Properties 436 Appendix C defaultValue FF, IE 3 Read-only: Browser-set default value for the element Form FF, IE 3 Read-only: Form containing the element maxLength FF, IE 4 Maximum number of characters allowed in the field name FF, IE 3 Name of the password field readOnly FF, IE 4 true if users can’t enter data into the field size FF, IE 4 Width of the field type FF, IE 4 Read-only: Set to 'PASSWORD' value FF, IE 3 Text that appears in the password field Example: When a visitor enters a password into this field and presses ENTER, whatever the visitor typed gets sent to the alert() function. Methods blur() FF, IE 3 Removes the cursor from the password element Example: window.document.my_form.the_password.blur(); focus() FF, IE 3 Moves the cursor to the password element Example: window.document.my_form.the_password.focus(); This line puts the cursor inside the password element named the_password. Unless the focus is changed, the next characters typed go into the_password. FF, IE 3 select() Selects the text inside the password element Example: window.document.my_form.the_password.select(); Handlers onBlur FF, IE 3 Called when a visitor removes the cursor from the password element Example: onChange FF, IE 3 Triggered when a visitor changes the contents of the field and then clicks out of the field or presses ENTER Example: Re f e r e n c e to J a v a S c r i p t O b j e ct s a nd F un c ti o ns 437 onFocus FF, IE 3 Called when the cursor is put into the password field Example: This method opens a window when a visitor clicks inside the password field. prompt() A dialog box that has OK and Cancel buttons, a place for a message to the visitor, and a box into which the visitor may type a reply. The prompt() function returns the visitor’s reply and takes two parameters: a message that appears above the input area and a default value to put in the input area. If the visitor clicks Cancel, prompt() returns the value null. Example: var the_name = prompt("What's your name?", "your name here"); if (the_name == null) { the_name = prompt("Come on! What's your name?","Please..."); } This calls up a prompt box asking visitors for their names. The words your name here appear as default text in the input area. If a visitor clicks Cancel, the if-then statement asks for the name one more time. Radio The radio button form element. Radio buttons given the same name are considered a set and are stored in an array with the set’s name. A visitor can select only one radio button of the set at any given time. If a web page has five radio buttons named favorite_color, the second radio button in the set is referred to as: window.document.the_form.favorite_color[1] Properties checked FF, IE 3 true if a visitor has selected the radio button and false otherwise. Setting the property to true causes the radio button to act as if a visitor selected the button. Example: if (window.document.the_form.favorite_color[3].checked == true) { alert("I like that color too!"); } 438 Appendix C This if-then statement calls an alert box if a visitor selects the fourth radio button named favorite_color. defaultValue FF, IE 3 Read-only: Browser-set default value for the element length FF, IE 3 Read-only: Number of elements in a group of radio buttons with the same name name FF, IE 3 Radio button’s name type FF, IE 3 Read-only: Identifies element as a radio button value FF, IE 3 Value of a radio button Methods click() FF, IE 3 Simulates a click on the element Handlers onClick FF, IE 3 Triggered when a visitor clicks the radio button Reset See “Button (Including Submit and Reset Buttons)” on page 416. Screen The screen object contains a number of read-only properties that provide information about the computer screen used to view a web page. Properties availHeight, availWidth FF, IE 4 Read-only: Available height and width of the screen, in pixels. Excludes the taskbar in Windows systems and any other permanent screen elements. Example: var screen_height = screen.availHeight; height, width FF, IE 4 Read-only: Height and width of the screen in pixels colorDepth FF, IE 4 Read-only: Number of colors on the screen (bits per pixel in IE, natural log in FF) pixelDepth FF, IE 4 Read-only: Bits per pixel Select The select form element can either be a pull-down menu or a scrollable list. The items in it are called the options of the select and are stored in the select element’s options[] array. Re f e r e n c e to J a v a S c r i p t O b j e ct s a nd F un c ti o ns 439 Properties length FF, IE 3 Number of options in the select multiple FF, IE 4 If true, accept multiple selections in select box name FF, IE 3 select object’s name options[] FF, IE 3 Read-only: Array containing the select’s options. See “Option” on page 435 for more information. selectedIndex FF, IE 3 Contains the selected option’s array position in a select element. If no item has been selected, selectedIndex is 1. If more than one option has been selected, selectedIndex contains the position of the first option. To determine all the options selected, use a loop to look at the selected property of each option object. See “Option” on page 435 for more information. Example: var option_number = window.document.the_form.the_select.selectedIndex; if (selected_option_number != -1) { var option_text = window.document.the_form.the_select.options[option_number].text; alert("Thanks for choosing " + option_text); } This code determines which option (if any) has been selected, and it presents an alert box with the selected option’s text. Handlers onChange FF, IE 3 Triggered when a visitor selects or deselects an option Example: Selecting Cat or Dog triggers the select’s onChange, resulting in an alert box commending the visitor on his or her choice. setInterval() [FF, IE 4] Executes JavaScript statements at repeated time intervals, given two parameters: the JavaScript statements to execute and the number of milliseconds between each execution. The function returns a reference to the interval so that clearInterval() may cancel it. For example: var the_interval = setInterval("alert('Stop procrastinating!');", 10000); creates an interval that calls up an alert box every 10 seconds. 440 Appendix C setTimeout() [FF, IE 3] Executes JavaScript statements once after a specified amount of time, given two parameters: the JavaScript statements to execute and the number of milliseconds in the future to execute the statements. The function returns a reference to the time-out so that clearTimeout() may cancel it. For example: var the_timeout = setTimeout("alert('Stop procrastinating!');", 10000); creates a time-out that calls up an alert box in 10 seconds. String Strings are sets of characters between quotes. See Chapter 11 for more information on strings. Properties FF, IE 3 length Read-only: Number of characters in a string Example: var the_string = "hello"; var the_length = the_string.length; This code sets the_length to 5. Methods anchor() FF, IE 3 Takes a name as a parameter and returns an anchor tag with the string as the text of the link For example: var the_string = "Information About Fish"; var the_anchor = the_string.anchor("fish_info"); window.document.writeln(the_anchor); writes Information About Fish to a web page. big() FF, IE 3 Puts the string between and tags For example: var the_string = "something really important"; window.document.writeln(the_string.big()); writes something really important to a web page. Re f e r e n c e to J a v a S c r i p t O b j e ct s a nd F un c ti o ns 441 bold() FF, IE 3 Puts the string between and tags For example: var the_string = "something really important"; window.document.writeln(the_string.bold()); writes something really important to a web page. charAt() FF, IE 3 Takes a number as a parameter and returns the character in that position of the string. Returns null if there is no character. For example: var the_string = "rabbit"; var the_first_char = the_string.charAt(0); sets the_first_char to r because r is in position 0 of the string. charCodeAt() FF, IE 4 Takes a number as a parameter and returns the ASCII code of the character in that position of the string. Returns null if there is no character. concat() FF, IE 4 Given a string, adds it to the end of this string For example: var the_string = "Hi"; window.document.writeln(the_string.concat(" there")); writes "Hi there" to a web page. fixed() FF, IE 3 Puts the string between and tags fontcolor() FF, IE 3 Takes the name of a color or a hexadecimal triplet as a parameter and encloses the string between and tags For example: var the_string = "pretty"; window.document.writeln(the_string.fontcolor("pink")); writes pretty to a web page. fontsize() FF, IE 3 Takes an integer as a parameter and encloses the string between and tags For example: var the_string = "cheese"; window.document.writeln(the_string.fontsize(48)); writes cheese to a web page. 442 Appendix C String.fromCharCode() FF, IE 4 Constructs a string from ASCII codes For example: alert(String.fromCharCode(72, 73)); puts up an alert with the string "HI". indexOf() FF, IE 3 Searches within the string for the substring specified by the first parameter. The optional second parameter is an integer that dictates where in the string to start searching. If the string contains the substring, indexOf() returns the position of the substring within the string. If the string does not contain the substring, indexOf() returns 1. For example: var the_string = "The Waldorf Astoria"; var wheres = the_string.indexOf("Waldo"); sets wheres to 4 because the W in Waldo is in position 4 in the string. italics() FF, IE 3 Puts the string between and tags For example: var the_string = "tower"; window.document.writeln(the_string.italics()); writes tower to a web page. lastIndexOf() FF, IE 3 Returns the position of the last occurrence of a substring in a string. Like indexOf(), it can take one or two parameters. The first is the substring to search for, and the second is where in the string to start searching. For example: var the_string = "The last word."; var last_space = the_string.lastIndexOf(" "); sets last_space to 8. link() FF, IE 3 Takes a URL as a parameter and creates a hyperlink with the string as the text of the link and the URL as the contents of the HREF attribute For example: var the_string = "News For Geeks"; window.document.writeln(the_string.link("http://www.slashdot.org")); writes News for Geeks to a web page. Re f e r e n c e to J a v a S c r i p t O b j e ct s a nd F un c ti o ns 443 split() FF, IE 4 Splits a string into an array along a substring passed as a parameter Example: var the_string = "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec"; var the_months = the_string.split(","); This code creates an array called the_months, which has "Jan" in position 0, "Feb" in position 1, and so on. localeCompare() FF, IE 5.5 Compares Unicode versions of this string and the string passed as a parameter. Returns zero if they are the same, 1 if this string sorts after the parameter, and 1 if this string sorts before the parameter. For example: the_string = "Apple"; alert(the_string.localeCompare("\u0041pple")) returns zero. match() FF, IE 4 Takes a regular expression as the parameter. Returns true if the string matches the regular expression. See Chapter 11 for more information. replace() FF, IE 4 Takes a regular expression and a string as parameters. Replaces the match for the regular expression with the string. Example: var the_string = "Happy"; alert(the_string.replace(/p/, "r")); alert(the_string.replace(/p/g, "r")); The first alert will say Harpy and the second will say Harry. 444 Appendix C search() FF, IE 4 Takes a regular expression as a parameter and returns the position in the string that matches the expression, or 1 if the regular expression does not match slice() FF, IE 4 Returns a substring of a string. Takes a start position and an end position of the substring. If end position is not included, returns from start position to the end of the string. small() FF, IE 3 Puts the string between and tags sub() FF, IE 3 Puts the string between and tags substr() FF, IE 4 Extracts a substring from a string. Takes two parameters: the position of the first character of the substring and the length of the substring. Similar to the substring() method. Example: var the_string = "core"; var the_extract = the_string.substr(1, 2); This code sets the_extract to "or" because "o" is in position 1 in the string and is 2 letters long. substring() FF, IE 3 Extracts a substring from a string. Takes two parameters: the position of the first character of the substring and the position of the character after the last character in the substring. Similar to the substr() method, except it works in more browsers and takes a different second parameter. Example: var the_string = "core"; var the_extract = the_string.substr(1, 3); This code example sets the_extract to "or" because "o" is in position 1 of the string and "e", the letter after the last character in "or", is in position 3. sup() FF, IE 3 Puts the string between and tags toLocaleLowerCase(), toLocaleUpperCase() FF, IE 5.5 Converts a string to lowercase or upper case. Can handle Unicode characters. Example: var the_string = "\u0041pple"; window.document.writeln(the_string.toLocaleLowerCase()); This code writes apple to a web page. toLowerCase(), toUpperCase() FF, IE 3 Converts a string to lowercase or uppercase. Doesn’t know Unicode. Style [FF, IE 4] The object that represents a Cascading Style Sheet (CSS). As discussed in Chapter 13, you can use CSS in combination with JavaScript to animate a web page in many ways. Style sheets are often attached to
    HTML tags as follows:
    Here's a style sheet!
    This code gives div an id of "mystyle" and positions the text between the
    and
    tags 100 pixels from the left and 100 pixels from the top of the screen. Re f e r e n c e to J a v a S c r i p t O b j e ct s a nd F un c ti o ns 445 The style object is available for all HTML elements. The following line accesses the style object for the div in the preceding example: var the_style = document.getElementById("mystyle").style; All the properties of a style object are read-write. There are many, many properties for the style object. The ones compatible with both Firefox and Internet Explorer 5 and above are listed in the following table. For more information about those properties, pick up a good book on CSS or Dynamic HTML. Properties [FF, IE 5] background borderRightWidth fontVarient paddingTop backgroundAttachment borderStyle fontWeight pageBreakAfter backgroundColor borderTop height pageBreakBefore backgroundImage borderTopColor left position backgroundPosition borderTopStyle letterSpacing right backgroundRepeat borderTopWidth lineHeight tableLayout border borderWidth listStyleImage textAlign borderBottom bottom listStylePosition textDecoration borderBottomColor clear listStyleType textIndent borderBottomStyle clip margin textIndex borderBottomWidth color marginBottom textTransform borderColor cssText marginLeft top borderLeft cursor marginRight unicodeBidi borderLeftColor direction marginTop verticalAlign borderLeftStyle display overflow visibility borderLeftWidth font padding whiteSpace borderRight fontFamily paddingBottom width borderRightColor fontSize paddingLeft wordSpacing borderRightStyle fontStyle paddingRight zIndex Submit The submit button sends an onSubmit event to the form that contains it. See “Button (Including Submit and Reset Buttons)” on page 416 for more information. Text The text form element allows a visitor to type a line of text into a form. See “Password” on page 436 for more information. 446 Appendix C Textarea A textarea is a multiline box into which text can be typed. Its HTML looks like this: . Properties cols FF, IE 4 Number of columns of the textarea defaultValue FF, IE 3 Read-only: Browser-set default value for the element form FF, IE 3 Read-only: Form containing the element maxLength FF, IE 4 Maximum number of characters allowed in the field name FF, IE 3 Name of the textarea field readOnly FF, IE 4 true if users can’t enter data into the field rows FF, IE 4 Number of rows of this textarea type FF, IE 4 Read-only: Set to "TEXTAREA" value FF, IE 3 Text that appears in the textarea Methods blur() FF, IE 3 Removes the cursor from the textarea Example: window.document.my_form.the_area.blur(); focus() FF, IE 3 Moves the cursor to the textarea Example: window.document.my_form.the_area.focus(); This line puts the cursor inside the password element named the_password. Unless the focus is changed, the next characters typed go into the_password. select() FF, IE 3 Selects the text inside the textarea Example: window.document.my_form.the_area.select(); Handlers onBlur FF, IE 3 Called when a visitor removes the cursor from the textarea onChange FF, IE 3 Triggered when a visitor changes the contents of the field and then clicks outside the field or presses ENTER onFocus FF, IE 3 Called when the cursor is put into the password field Re f e r e n c e to J a v a S c r i p t O b j e ct s a nd F un c ti o ns 447 this [FF, IE 3] A term that refers to the object in which it appears. Example: Here, this refers to the checkbox named riddle_me because that’s where this appears. The alert box will have the text riddle_me inside. unescape() [FF, IE 3] Decodes a string encoded with escape(). Example: var decoded_string = unescape("a%20string%20safe%20for%20cookies"); The variable decoded_string now holds the string "safe for cookies" because the unescape function replaces each %20 with a space. See “escape()” on page 436 for more information. var [FF, IE 3] A term used the first time a variable is named. Example: var a_new_variable = "I feel good!"; window The window object is either a browser window or a frame. Many methods of the window object have been listed in this appendix already. Those are left out of the description of the window object. Properties closed FF, IE 4 Read-only: true if a window has been closed and false if it is still open. The window referenced is generally created using the window.open() method. Example: if (my_window.closed == false) { my_window.location = "http://www.hits.org"; } This example makes sure the window named my_window has not been closed before sending a visitor to http://www.hits.org. 448 Appendix C defaultStatus FF, IE 3 Read-only: Browser’s default message in the status area of the window document FF, IE 3 Read-only: document object of the window. See “Document” on page 421 for more information. frames[] FF, IE 3 Read-only: Array of frames stored in a window. Each frame is considered another window object. Example: window.frames[0].document.writeln("Hello!"); This line writes the word Hello! into the document of the first frame in the window’s frame set. history FF, IE 3 Read-only: History object of a window. See “History” on page 426 for more information. innerHeight FF Height of the display area of the web page (only signed scripts can make this smaller than 100 pixels) innerWidth FF Width of the display area of the web page (only signed scripts can make this smaller than 100 pixels) name FF, IE 3 Name of a frame or window. The frame set provides the name of a frame. The name of a window is the second parameter in the window.open() method. navigator FF, IE 4 Read-only: navigator object of the window Example: var first_frame_name = window.frames[0].name; onerror FF, IE 4 The name of a function to trigger when there’s a JavaScript error. The function must take three parameters: the error message, the URL of the document in which the error occurred, and the line of the error. Example: function alertError(the_message, the_url, the_line) { var the_string = "Warning, Will Robinson! " + the_message; the_string += " occurred on line " + the_line " of " + the_url; } window.onerror = window.alertError; Now, whenever there is a JavaScript error, an alert will pop up with the contents of that error. Re f e r e n c e to J a v a S c r i p t O b j e ct s a nd F un c ti o ns 449 offscreenBuffering IE 4 Setting this to true may reduce flicker in DHTML animations opener FF, IE 3 Reference back to the window or frame that opened the current window Example: window.opener.location = "http://www.nostarch.com"; This example changes the URL shown in the window that opened the current window. outerHeight FF Height of the window (only signed scripts can make this smaller than 100 pixels) outerWidth FF Width of the window (only signed scripts can make this smaller than 100 pixels) pageXOffset FF Read-only: How far to the right the screen has scrolled in pixels pageYOffset FF Read-only: How far down the screen has scrolled in pixels parent FF, IE 3 Read-only: Parent of this window (used in the context of frames) Example: parent.frames[1].location = "http://www.aclu.org"; This line changes the URL of the second frame in a frame set when called by another frame in the same frame set. screen FF, IE 4 Read-only: Window’s screen object screenLeft IE 5 Read-only: Horizontal coordinate (in pixels) of the left border of the browser window’s content area relative to the upper left corner of the screen. The content area is where the web page resides. screenTop IE 5 Read-only: Vertical coordinate (in pixels) of the top border of the browser window’s content area relative to the upper left corner of the screen. The content area is where the web page resides. screenX FF Horizontal coordinate of the left side of the window screenY FF Vertical coordinate of the top of the window scrollX FF Read-only: Horizontal scrolling of the browser window scrollY FF Read-only: Vertical scrolling of the browser window self FF, IE 3 Read-only: Reference to the current window or frame, the same as window Example: self.location = "http://www.npr.org"; status FF, IE 3 Contents of the window’s status bar Example: window.status = "Don't forget to smile!"; 450 Appendix C top FF, IE 3 Read-only: Topmost window in a window hierarchy. Helpful when your JavaScript is in a deeply nested frame and you want it to affect the whole web page. Example: window.location = "http://www.theonion.com"; top.location = "http://www.theonion.com"; When executed inside a frame, the first line changes the URL of the frame to www.theonion.com, and the second line changes the URL of the entire web page. Methods blur() FF, IE 4 Sends a window behind all the other windows on the screen Example: window.blur(); close() FF, IE 3 Closes a window open() FF, IE 3 Opens a new window and returns a reference to it. Takes three parameters: the URL of the window to open, the target name of the window, and a comma-delimited list of features the window should have. Some of the features, such as width and height, must have values assigned to them. If the third parameter is left out, the new window contains the same features as the window that opened it. Example: var little_window = window.open("http://www.ebay.com", "little_window", "height=50,width=50,resizable"); The above code opens up a small resizable window holding eBay’s website. Features The following list contains all the features a window may have and which browsers allow which features. The first list contains the window features that work in Netscape 2, Internet Explorer 3, and more recent versions of these browsers. copyhistory Copies the history of the current window to the window being opened (that is, it enables the use of the back button in the new window) directories Directory buttons height Height of the new window location Location bar (where URLs may be typed) Re f e r e n c e to J a v a S c r i p t O b j e ct s a nd F un c ti o ns 451 menubar Menu bar (File, Edit, and so on); always present on a Macintosh resizable Makes the window resizable (Macintosh windows are always resizable) scrollbars Provides scrollbars when the content of the window exceeds the window size status Shows the status bar toolbar Toolbar (back, forward, and so on) width Width of the window The following list contains features that only work in Firefox and similar browsers. Certain features, noted by an asterisk, require that Firefox sign your script. alwaysLowered* Always puts this window behind others on the screen alwaysRaised* Always puts this window above others on the screen dependent Closes the new window when the opening window closes hotkeys Disables keyboard shortcuts except Quit innerHeight Height of the window’s content region innerWidth Width of the window’s content region outerHeight Total height of the window outerWidth Total width of the window screenX How far from the left side of the screen the window appears screenY How far from the top of the screen the window appears titlebar* Set titlebar = no to hide the title bar z-lock* Puts the window below all other browser windows Methods scroll() FF, IE 4 Takes two parameters: a number of pixels to scroll horizontally and a number to scroll vertically Example: window.scroll(100,500); This line moves the scroll bars so that the part of the screen 100 pixels from the left border and 500 pixels from the top of the screen appears at the upper left corner of the screen. scrollBy() FF, IE 4 Takes two parameters: the number of pixels to scroll the window horizontally and vertically (use negative numbers to move the scroll bars to the left or up) Example: window.scrollBy(50,-100); This line scrolls the window 50 pixels to right and 100 pixels up. 452 Appendix C Less Common Methods back() FF Goes back a page (like clicking the browser’s back button) find() FF Searches in the document for the string passed as the parameter forward() FF Goes forward a page (like clicking the browser’s forward button) home() FF Goes to the home page (like clicking the browser’s home button) moveBy() FF, IE 4 Moves the window a specified number of pixels horizontally and vertically. Firefox script must be signed to move the window off the screen. moveTo() FF, IE 4 Moves the window to a certain x, y position relative to the upper left corner of the browser window. Firefox script must be signed to move the window off the screen. print() FF, IE 5 Prints the current web page (like clicking the browser’s print button) resizeBy() FF, IE 4 Takes two parameters: an amount in pixels to resize the window horizontally and an amount to resize it vertically resizeTo() FF, IE 4 Takes two parameters: a width in pixels and a height in pixels. Resizes the window to these dimensions. scrollTo() FF, IE 4 Just like window.scroll() stop() FF Stops loading the web page (like clicking the browser’s stop button) Handlers Window handlers go inside the tag of the web page. onBlur FF, IE 4 Triggered when the window is no longer topmost on the screen Example: This window closes itself if the user selects another window. onError FF, IE 4 Triggered when a JavaScript error occurs Example: onFocus FF, IE 4 Triggered when the user selects the window Example: onLoad FF, IE 3 Triggered when the page, including all its images, has completely loaded For example: calls the function startThauScript() when the page has fully loaded. Re f e r e n c e to J a v a S c r i p t O b j e ct s a nd F un c ti o ns 453 FF, IE 4 onResize Triggered when the visitor has resized the page Example: FF, IE 3 onUnload Triggered when a visitor is about to leave the page. This occurs even when the browser holding the page is closed, when the visitor clicks a link, or when the visitor reloads the page. Example: XMLHttpRequest [FF] and ActiveXObject("Microsoft.XMLHTTP") [IE 5.5] These objects are used extensively in Ajax, as described in Chapters 14, 15, 16, and 17. Properties readyState State of the request responseText String containing the response to the request responseXML If the response is an XML document, it is stored here status Response status from the server Methods abort() Cancels the request open() Tells the request object where the request should go and what kind of request it is. See Chapter 14 for more information. send() Sends the request. If this is a POST-type request, the information to send to the server is sent as a parameter. Otherwise, the parameter is null. Handlers onReadyStateChange 454 Appendix C Triggered when the request object’s readyState property changes CHAPTER 15’S ITALIAN TRANSLATOR AND CHAPTER 17’S TO DO L I S T A P P L I C A T I O N The examples given in this appendix were too long to list in their entirety in Chapters 15 and 17. For more information about how each works, please refer to the appropriate chapter. Chapter 15’s Italian Translator Translator Suggestion Script
    Chapter 17’s To Do List Application The To Do list application used one HTML file and two PHP files. todo.html To Do

    Login Section

    Content Section

    Welcome! Please sign in to see your To Do lists.

    To Do Lists You Can Access

    466 Appendix D readXMLFile.php saveXMLFile.php C h a p t e r 1 5 ’ s I t a l i a n T r a n s la t i on S cr i p t a n d C h a p t e r 1 7 ’ s To D o Li s t A p p l i c a t i o n 467 INDEX Symbols & Numbers & (ampersand), in XML entities, 284 && (AND) operator, 198 in if-then statements, 44–45 <> (angle brackets), entities in XML for, 284 for HTML comments, 11 and tag, 10 vs. HTML elements for JavaScript, 254
  • Navigation menu