Using AVA Cript: Special Edition
Using AVA Cript: Special Edition
Using
JAVASCRIPT
Mark C. Reynolds, et. al.
C O N T E N T S
Introduction
Who Should Use This Book? o How This Book Is Organized How to Use This Book Conventions Used in This Book
19
Live Content on the WWW o Forms Explode with Information o Look and Feel Is An Option o Multiple Windows and Frames o Interact with Other Live Objects Role of Scripting o PC Macros Become Scripts o Scripting in Macintosh Applications o Perl Started as a UNIX Scripting Language Extend the Capabilities of the HTML Page o JavaScript Pages Work Differently o JavaScript Meets the HTML Page o Limited by Objects in the Browser JavaScript and Java o JavaScript and Java Work in the Same Environment o JavaScript Is NOT Java o Java and JavaScript Working Together
2
o
35
JavaScript Syntax Variables and Values o Implicit Data Types in JavaScript o Type Conversion Statements and Operators o The Structure of JavaScript Statements o Operators o Comments in JavaScript Code Control Structures o The if Statement o The while Statement o The for Statement Functions and Objects o Functions o Objects
66
Events and Actions o Navigation Actions and Events o Forms Input and Events o Actions That Are Not Events JavaScript Code in HTML o The SCRIPT Tag o Declaring JavaScript Event Handlers Using JavaScript Event Handlers o Document Level Event Handlers o Submit Event Handlers in the FORM Tag o Event Handlers in FORM Elements
Objects, Properties, and Methods in JavaScript o Object-Oriented Programming Concepts o Defining Your Own Objects: The new Statement o Objects as Arrays o Using Variable Length Arrays and Extended Instances o The forin Statement o Method Functions and this
Nested Objects The with Statement Functions with a Variable Number of Arguments Built-In Objects o String Objects o The Math Object o The Date Object o Built-In Functions Browser and HTML Objects o Browser Objects o HTML Objects
o o o
120
143
Customizing User Interaction Using JavaScript Review of HTML Forms o <FORM>...</FORM> o <INPUT> o <SELECT></SELECT> o <OPTION> o <TEXTAREA></TEXTAREA>
HTML Objects in JavaScript o Buttons, Checkboxes, and Radio Buttons o Manipulating Text Fields o Validating and Submitting a Form
Link In with JavaScript o Additions to the LINK Syntax o Properties of the LINK Object o The NAME Attribute has New Significance o LINK Events: onMouseOver and onClick o Change Link URLs, Not the Displayed Text o Display Documents in Frames and Windows Creating and Using Anchors o Your HTML Elements o Anchor Any Text or Element Selection or Scrolling-Your Option o Syntax in Review o onChange, onBlur, and onFocus Events for SELECT o Dynamically Change the Selection, Not the Text Example: An Application Using Advanced Navigation o Expand the View with Frames o Objects for Tri-Eye o Dynamic Links o Anchors to Complete the Story o Other Possible Improvements to and Uses of Internet Tri-Eye Example: Tri-Eye FTP Auto Dialer
JavaScript Object Hierarchy o Browser Windows o Dynamic Window Creation o Window Status o The Location Object o The History Object o Security Aspects of JavaScript Objects o The Document Object Dynamic Documents o Restrictions on document.write o Using Nascent Documents o A Page Generated Entirely by JavaScript o Dynamically Rewriting Your Page o The openNote() Script Revisited
2
o
Global and Local Variables o Parameter Checking More on JavaScript Functions o Storing Your Functions o Functions on the Fly o The eval Function JavaScript's Associative Arrays o Using Associative Pairs o Arrays of Arrays Some JavaScript HTML Objects o Objects Revisited o Images as Objects o The Text Object
Plug-Ins versus Helper Apps Plug-Ins and MIME Types Using Plug-Ins with HTML Plug-In Considerations o Sound Players o Text Readers o VRML and 3-D Viewers o Graphic Formats Viewers o Multimedia Players Considerations in Using Plug-In Based Formats Plug-In Examples o Macromedia Shockwave o Adobe Acrobat o Microsoft Word Viewer o Virtual Reality Modeling Language Plug-Ins and JavaScript
The Java Language o Java and JavaScript Compared o Data Types in Java o Java Classes as Structured Data Types o Java Statements
Developing Java Applets o The Java Development Cycle o Java Compilers and the JDK o The APPLET Tag o A Simple Applet o Anatomy of an Applet An Accounting Applet in Java o The init Method o The start Method o The do1trans Method o The paint Method o Executing the Account Example Applet
The Java Class Hierarchy o Classes and Subclasses o Packages in Java A Pop-Up Document Viewer Applet o Initializing the SD Applet o Event Handling in the SD Applet o Opening a New Document with the SD Applet An Image Viewer Applet o Initializing the Simple Image Viewer o Running the Simple Image Applet
Language Overview o Data Types o Variables o VBScript Constants o VBScript Operators o Control Flow in VBScript o Visual Basic Script Procedures o Syntax Summary Visual Basic Script in HTML Visual Basic Script and OLE Automation VBScript and Forms VBScript Is Growing
Even the First Page Can Come Alive First Page as a Control Panel JavaScript Enhanced Pages as an Application Storing Control Panel Information Good Design Text Properties and Color Values o Text Properties o Color Values o Practical Uses of Text Properties o Overriding fgColor Fonts and Font Methods o Description of Font Methods o Using Font Methods Design of JavaScript Message Editor o How the Message Editor Works o Layout Decision o Framing the Message Editor o Framesets Nest, Frames Objects Don't o HTML Code for a Layout Program Structure or Coding the Events o Font Methods o The About and Help Features o The Preview
o o o o o
Creating Dynamic Framesets o The javascript: Protocol o Empty Frames o Content Variables versus Functions A Simple Color Alternator A Better Color Alternator o Color Objects o The Alternator Object o Events and the Event Queue o Scheduling Multiple Events A Color Fader A Scrolling Marquee The Static Object Animating Images Generating Images o The XBM Format o Representing an XBM Image o XBM Drawing Methods o Displaying Generated Images
Creating Dynamic Output Generating Random Numbers A Random Phrase Generator o Random Words o The Phrasemaker o Colors, Fonts, and All o Adding and Sorting Words An Online Bookstore o Parsing Free-Form User Input o Building an Index o Defining Book and Catalog Objects o The Bookstore o Improved Indexing and Searching
An Overview of LiveWire Live Objects and Properties o Request Object o Client Object o Project Objects o Server Objects External Process Communications: JavaScript and CGIs o Steps to Building a LiveWire Application o Browsing into a LiveWire Application o LiveWire Source Files o The JavaScript Balancing Act o Exchanging Information between the Browser and Server External Files and Databases with JavaScript o Create the New File Object o Open the File o File Positioning o Writing with the File Object o Reading with the File Object o Converting Data o Error Checking and Getting Information o Example Using the File Object
A JavaScript Starter Kit Navigator and Navigator Gold 2.0 o HTML Editing Tools o Graphics Tools o A Simple Template LiveWire Pro Building a JavaScript Site from Ground Up o Overall Structure o Creating the Frame Interface o The Table of Contents o Status Bar Control Articles The Cover Page
Parameter Specification and Data Storage o Storing Parameters and Other Data o Command-Line Parameters o Storing Persistent Data in Cookies Frames and JavaScript o Specifying Frames in HTML o Building a Frameset o Frames within Frames o Examples of Interframe Communication o Writing a New Document into a Frame o Building a JavaScript Function Library in a Frameholder A Bug Database in JavaScript o The Top-Level Structure of the Bug Database o The Bug Object Defined o Entering a New Bug into the Database o Retrieving a Bug o Editing a Bug o Deleting a Bug o Other Buttons
Stefan Raab of Cue Systems, LLC The Collapsing and Expanding Outline Getting up to Speed o The First Attempt: Forms o onClicks and anchors
Those Persistent Objects Losing Automatic Outline Building Simple Idea-Broad Application
o
Chapter 21 Learning from the Pros: Adding Frames and Controlling Navigation
Matthew Fusfield of CyberExplorer The One-Way-Out Web Site New Web Site Formats = Old-Fashioned Organization o To Mirror or Replace Creating Entrance to a Controlled Site Finding a Use for Frames
David Nagy-Farkas of LiveWeb Books Galore! Portability by Design Working with Databases Determining Variable Types Will It Work for a Candy Store?
The World Wide Web o JavaScript Index o The Unofficial JavaScript Resource Center o Voodoo JavaScript Tutorial o Danny Goodman's JavaScript Pages o Gordon McComb's JavaScript Pages o The Complete Idiot's Guide to JavaScript Homesite o Gamelan o Netscape o Netscape World o JavaWorld o Borland's JavaWorld o TeamJava o Symantec o Dimension X o The Java Developer o Sun Microsystems UseNet Newsgroups o comp.lang.javascript
comp.lang.hotjava comp.lang.java comp.infosystems.www.authoring E-Mail Mailing Lists o [email protected] o [email protected] o [email protected] Search Engines o Alta Vista o Yahoo! o Lycos o WebCrawler General Web Sites o The Consummate Winsock Software List o TUCOWS o Shareware.com Netscape Navigator Plug-Ins: Live Object Support o Shockwave for Director by Macromedia o RealAudio by Progressive Networks o Live3D by Netscape o ToolVox by VoxWare o OLE Control by NCompass o PreVU by InterVU o VDOLive by VDOnet o ViewMovie by Ivn Cavero Belande Macintosh and PowerPC (Mac OS) o Netscape Navigator 2.01 o Symantec Caffeine o Talker by MVP Solutions o Roaster o CodeWarrior
o o o
Color Values
Bugs in JavaScript Permanent Limitations New Features in JavaScript o Netscape Navigator 2.1 o Netscape Navigator 3.0 o Communicating with Other Elements in the Navigator The Future
Copyright 1996 by Que Corporation. All rights reserved. Printed in the United States of America. No part of this book may be used or reproduced in any form or by any means, or stored in a database or retrieval system, without prior written permission of the publisher except in the case of brief quotations embodied in critical articles and reviews. Making copies of any part of this book for any purpose other than your own personal use is a violation of United States copyright laws. For information, address Que Corporation, 201 W. 103rd Street, Indianapolis, IN, 46290. You may reach Que's direct sales line by calling 1-800-428-5331. ISBN: 0-7897-0789-6 President Roland Elgey Publishing Director Jim Minatel Managing Editor Sandy Doell Publisher Editorial Services Director Director of Marketing Acquisitions Editor Production Editors Joseph B. Wikert Elizabeth Keaffaber Lynn E. Zingraf Doshia Stewart Kelli M. Brooks, Jeff Riley Kim Margolius
Senior Series Editor Chris Nelson Product Director Mark Cierzniak Editors
Tom Cirtin, Chuck Assistant Product Hutchinson, Theresa Marketing Manager Mathias Software Specialists Dr. Donald Doherty, Technical Editors Dr. Donald Doherty, Oran J. Sands Stephen Feather, Faisal Jawdat, Chris Means, Joe Risse, Doug Welch, Martin Wyatt Technical Specialist Nadeem Muhammad Operations Patricia J. Brooks Coordinator Editorial Assistant Andrea Duvall Acquisitions Jane K. Brownlow,
Indexer
Andrea Duvall, Lisa Farley Ruth Harvey Cover Designers Dan Armstrong, Ruth Harvey Brian Buschkill, Chad Dressler, Trey Frank, Jason Hand, Sonja Hart, Damon Jordan, Daryl Kessler, Stephanie Layton, Michelle Lee, Clint Lahnen, Julie Quinn, Kaylene Riemen, Laura Robbins, Bobbi Satterfield Tim Griffin
Assistants
Bill Dortch has developed software professionally for nearly 20 years. In 1995 he founded hIdaho Design, a Web site design company focused on highly interactive, multimedia site development. Prior to starting hD, Bill was Principal Software Architect at Frye Computer Systems, a leading supplier of network management software. Bill's products have been both commercially and critically successful, and have won many awards, including LAN Magazine's Product of the Year, Editor's Choice from PC Magazine, Infoworld, and PC Week, and many others. A former Boston resident, Bill now lives in Northern Idaho with his cat, Lucky. He can be reached at http://www.hidaho.com or [email protected]. Mona Everett, Ph.D., is a biochemist turned programmer. She works as a senior scientific software development specialist for Computer Data Systems, Inc., and is currently working on developing front-end access for a large medical epidemiological database. She is expert in Window's Delphi and Visual Basic as well as Mac's HyperCard. JavaScript is the most recent addition to her programming repertoire. In addition, she can program in C or Pascal for either platform. Because she has taught for many years, she is particularly interested in educational and other software that enables people to use computers and communicate comfortably. You can contact her at [email protected] or check out her Morphic Molecules pages at http://www.txdirect.net/users/everett. Scott J. Walter "cut his teeth" in computers on an Apple II (no plus) when he was in the seventh grade. By the time he reached senior high, he was working as an assistant to the computer science teacher and programming in BASIC, FORTRAN, Pascal, and assembly language. He was hired by a Minnesota-based software publisher in 1986, and has been developing retail software ever since. In that time, he has built and directed research and development departments at two companies; taught Pascal, C, C++, Windows, and Macintosh programming at the individual and small-business levels; co-authored (and continues to host the Web site for) The Complete Idiot's Guide to JavaScript; and had the time to invent a recipe for "Cajun-Italian Spaghetti Sauce" with his brother, Matthew. Scott's current penchants are for Java, JavaScript, VBScript, ActiveX, UNIX, Windows, C++, Delphi, and other budding development technologies. He is currently a "consultant at large" in the Minneapolis area, and invites you to contact him via e-mail at [email protected] or through his home page at http://www.winternet.com/~sjwalter/. Andrew Wooldridge is assistant Webmaster at Wells Fargo Bank, a pioneer in online banking and Internet services since 1989. Prior to joining Wells Fargo, he was Webmaster of Global Village Communications. Andrew started the HTML Writer's Guild, and has created the popular JavaScript Index at http://www.c2.org/~andreww/javascript/, which receives 40,000 hits per month.
Acknowledgments
The people at Que deserve a large measure of praise for their patience, perseverance, and hard work. I would especially like to thank Doshia Stewart and Kelli Brooks for their ongoing support, guidance, and impressive organizational skills. Many other people at Que have also worked very hard on this book, and are to be congratulated on the outcome. This book would not have been possible without the strenuous efforts and prodigious technical knowledge of the entire writing team. I am very grateful for their individual contributions, each of which was indispensable. Mark C. Reynolds
Introduction
Five years ago the Internet was mostly the province of academics and programmers, and the World Wide Web was an obscure idea in the minds of a few researchers. Today both are experiencing explosive growth and unparalleled interest. Web pages are being created at an astonishing rate. The fundamental challenge of Web page development is that while it is easy to create a Web page, it is more difficult to create an attractive and exciting one. HTML, the markup language that describes the appearance of a page, is easy to learn, and requires no background in programming. HTML has undergone several revisions in order to meet the expanding needs of Web page authors. However, there are limits to what can be achieved inside HTML. The Java programming language was introduced to dramatically extend the Web developer's set of tools, but is still more complex than HTML. Java is very easy to learn; however, like most programming languages, it isn't easy to master. JavaScript bridges this gap. JavaScript offers the Web page author a new level of sophistication without requiring him to become a programmer. JavaScript brings dynamic and powerful capabilities to Web pages, yet JavaScript is no more difficult to learn than HTML. JavaScript can be used to solve common problems, such as validating forms input, and can also be used to create dramatic and visually appealing content, which would be impossible with HTML. The goal of this book is to completely explore JavaScript, from the mundane to the extraordinary. It is designed as an introduction, a reference, and a continuous source of ideas, so that you may continually improve the Web pages that you create.
Part I, "JavaScript the Language," introduces the JavaScript language. The complete syntax and semantics of the language are thoroughly described, with particular attention paid to the close correspondence between HTML elements and JavaScript objects. Chapter 1, "What Is JavaScript?" discusses JavaScript's overall role in the development of Web pages. Chapter 2 "JavaScript: The Language," gives the syntax of JavaScript. This leads directly into a description of the relationship between events on a Web page and JavaScript, in chapter 3, "Events and JavaScript." This is followed by an introduction to the all-important topic of JavaScript objects in chapter 4, "JavaScript Objects." Part II, "JavaScript Objects," is a greatly expanded presentation of the JavaScript object model that begins in chapter 4 of part I. JavaScript objects can be classified as built-in objects or HTML objects. Built-in objects are thoroughly described in chapter 5, "Built-In JavaScript Objects," while chapters 6 through 8 focus on HTML objects. Validation of HTML forms is the subject of chapter 6; each form element is also a JavaScript object. Navigation objects, such as links and anchors, are then described in chapter 7, while chapter 8 presents the top-level objects associated with the Web browser itself. Part II concludes with a thorough treatment of user-defined objects in chapter 9. One of the tremendous advantages of a scripting language such as JavaScript is its capability to integrate diverse technologies on a single Web page. Part III is devoted to examining such technologies. Chapter 10 deals with plug-ins, which are becoming increasingly abundant and useful on the World Wide Web. The Java programming language has received massive attention, and is quite similar to JavaScript in structure. Chapter 11 provides a thorough introduction to Java, while chapter 12 focuses on the critical topic of Web page animation using Java. Finally, chapter 13 presents the Visual Basic scripting language in brief, and also looks at its plug-in technology, OLE controls. Part IV brings the user the most advanced material available on creating special effects using JavaScript. Controlling Web page appearance, producing spectacular visual effects, and finetuning user interaction are the subjects of in-depth treatment in chapters 14 through 16. Each chapter contains at least one fully worked example that can be used immediately. JavaScript server technology is reviewed in chapter 17, while various development tools for JavaScript are covered in chapter 18. Part IV concludes with an in-depth look at Web page development using the innovative frames technology in chapter 19. The fifth part of this book is devoted to Learning from the Pros. This part contains advanced solutions to common, yet difficult problems. Several innovative techniques are described here, as well as pointers on how to enliven any JavaScript Web page. Chapters 20 through 22 describe site outlines in JavaScript, conversion from standard HTML to frames, and a JavaScript online order system. The book concludes with a series of reference appendixes that summarize critical information presented in the main body of the text. A glossary of common JavaScript terms is given, along with a capsule description of all major JavaScript resources. A language summary is provided, as well as a list of known bugs in the current implementation of JavaScript (version 2.0.1). Future enhancements are also discussed in brief.
is used to introduce new terms. Screen messages, code listings, and command samples appear in monospace type. Code that you are instructed to type appears in monospace bold type.
Italic type
TIP Tips present short advice on a quick or often overlooked procedures. These include shortcuts. NOTE Notes present interesting or useful information that isn't necessarily essential to the discussion. A note provides additional information that may help you avoid problems or offers advice that relates to the topic. CAUTION Cautions look like this and warn you about potential problems that a procedure may cause, unexpected results, or mistakes to avoid.
Live Content on the WWW o Forms Explode with Information o Look and Feel Is An Option o Multiple Windows and Frames o Interact with Other Live Objects Role of Scripting o PC Macros Become Scripts o Scripting in Macintosh Applications o Perl Started as a UNIX Scripting Language Extend the Capabilities of the HTML Page o JavaScript Pages Work Differently o JavaScript Meets the HTML Page o Limited by Objects in the Browser JavaScript and Java o JavaScript and Java Work in the Same Environment o JavaScript Is NOT Java o Java and JavaScript Working Together o JavaScript and Other Live Content Tools
Remember the thrill of visiting your first Web page and clicking your first hyperlink to another site? The excitement of surfing from California to Maine, from Australia to Finland? This interactive nature of the Web attracts millions of people to the Web every day. With JavaScript, new dynamic elements let you go beyond the simple click and wait. Users will not just read your pages but also interact with them. Your pages come alive for any user, even with the slowest Internet connection. Users will get quick responses because the interaction does not need to involve the server but can take place in their browser. This interaction can change your pages into an application. Put together a few buttons, a text box, and some code to produce a calculator. Or an editor. Or a game. Or the "killer" JavaScript application that everyone wants. Users will save your JavaScript enhanced pages to use your application again and again. JavaScript is a programming language that allows scripting of events, objects, and actions to create Internet applications.
Calculators-Where is that calculator when you need it? On your page (see fig. 1.1). Beyond simple arithmetic, you can do conversions in hexadecimal, calories, metric, and more. Expand the form and you have the unlimited world of spreadsheets-for example, simple tax forms, grade-point averages, and survey analysis. Figure 1.1 : Calculator built in to a Web page with JavaScript. Display time. What time is it? It's easy to show in a basic text box (see fig. 1.2). Or how about the time anywhere in the world? Add in a little math and show users the elapsed time. Different math produces a countdown time. A little different code and you have a population explosion or national debt counter. Figure 1.2 : JavaScript time displays usually show you the local time. Feedback status. As you build JavaScript applications, there will be a lot going on. Your code will have loops, increment variables, and track user inputs. Let the users in on what's going on. Provide feedback with a numeric counter (see fig. 1.3). Say it "graphically" with a bar graph made of ASCII characters and show a status literally. Figure 1.3 : Text boxes can feed back status of applications to users numerically, with ASCII graphics, or verbally, in text boxes. Verification. With user input, you usually want to verify the validity of the response. For example, if you want the response to be a number between 1 and 10, JavaScript can verify that the user's response falls in that range. If not, the code can notify the user and ask again for the input (see fig. 1.4). Once verified, the result is submitted to the server. Figure 1.4 : Provide your users with instant feedback without waiting for a response from the server. Entertainment. Everyone wants to have fun-even when learning. You can convey your information as an interactive game or even as a joke (see figs. 1.5 and 1.6). The source code is very simple (see listing 1.1).
Figure 1.5 : Punchline: now you see the joke without the punchline revealed. Figure 1.6 : Here's the punchline, hidden until you are ready to see it. The source code in listing 1.1 is easy to modify to tell your own jokes on the Web without giving away the punchline.
Change colors. Ever get to a page where the colors nearly make you go blind? Give your users a choice of several color combinations of backgrounds and text colors. As your application displays documents, use your users' colors (see fig. 1.7). Figure 1.7 : Sample of menu where you can change the background color. TIP There are too many colors for a user to choose. Don't make them experiment; let them select from some good combinations you have already tested. Change links. Normally, users click hyperlinks and off they go to the site you specified as the URL for the hyperlink. With JavaScript, this link can change based on user responses.
If a user indicates a preference to baseball over football, your code can change the hyperlink to point to the Yankees instead of the Cowboys. Reformat Pages. Since JavaScript can examine all of the elements of a document, you can read a document in one frame and completely reformat it in another.
An example is HTML Analysis (see fig. 1.8). In the control panel at the bottom of the window, you specify a URL that is displayed in the left frame. The right panel is generated from the code activated by the REDO button. This code reads the HTML code of the left document and creates an entirely new document that lists all of the hyperlinks. This new document is displayed in the right frame. Figure 1.8 : The URL specified in the top frame is displayed in the second frame. The third frame shows only the links from that page. Such tools are a great way to make certain pages on your site meet your standards. Listing 1.2 shows the frames for HTML Analysis.
2
</BODY> </HTML>
CAUTION The HTML Analysis application is not stable on all platforms. Make sure the URL is completely loaded prior to doing the analysis. TIP You can reformat pages for dramatic results. Instead of showing the entire document in a large frame, bring the source document into an extremely small frame. Then display your reformatted document in the much larger frame. If the frame with your source is small enough, your users won't even know what the original looked like.
Tools for analysis. Analyzing tools are a very interesting derivative of reformatting documents. Instead of displaying a reformatted document, analyzing tools provide an analysis of a document. Tools could check such simple things as word counts, link counts, or other statistics. Code could even be written to show the tree structure of all of the objects in a document. Or you could write code to verify that pages meet the criteria for your corporate site.
Alert, confirm, and prompt dialog boxes. JavaScript has its own built-in dialog boxes you can use in your design. Alert users to take caution (see fig. 1.9), confirm an action with an okay or cancel response (see fig. 1.10), or prompt for a text input (see fig. 1.11). Figure 1.9 : Alert box notifies the user, but provide no choices. Figure 1.10: Confirm box notifies the user and allows him to cancel the action. Figure 1.11: Prompt box lets the user type a response to your code. Control windows. Beyond the built-in dialog boxes, you can create your own controls with custom windows. Populate them with buttons, text boxes, or icons to control the results in your other windows. Navigation windows. Have two, three, or more windows all opened simultaneously. As the user navigates from one, the others display various screens of information. For example, each window might pull in a live image from a different point around the globe as selected by the user. Internet Tri-Eye provides live views from around the world (see fig. 1.12). Figure 1.12: Internet Tri-Eye is an example of a multi-window application and a control panel. Selections in one frame produce results in other frames.
Netscape's LiveWire. LiveWire is a visual development environment for creating Internet applications. This new product provides enhancements to a server including JavaScript. The same language that you use to make your pages come alive on the browser can be used to respond to requests at the server. Instead of writing CGI scripts in Perl, C, or some other language, use JavaScript. Plug-ins. Plug-ins are software that work with Netscape's Navigator. Third-party publishers such as Adobe, MacroMedia, Borland, and many others produce these applications. This software will allow viewing of other file formats, multimedia presentations, and specialized functions.
The number of plug-ins for browsers is expected to grow astronomically. As these applications become more sophisticated, they are expected to use JavaScript as their scripting language. In addition, many of these publishers will allow JavaScript in the browser to interact with their plug-ins. The objects in this software will be available or exposed to JavaScript.
Microsoft is actively promoting its scripting language VBScript. The primary function of this language is to interact with and create external applications. Because this language is a subset of Microsoft's Visual Basic and works with ActiveX controls, it is expected to have a substantial impact.
Netscape Navigator 2.0 supports a new functionality-enhancing feature that provides inline support for a huge range of Live Objects. With Live Objects, developers can deliver rich multimedia content through Internet sites, allowing users to seamlessly view that content with plug-ins such as Adobe Acrobat, Apple QuickTime, and Macromedia Shockwave for Director in the client window-all without launching any external helper applications. New Internet Products. Given the scope of the companies behind JavaScript, you can expect to see some very specialized Internet products. Many of these products will use JavaScript for customizing.
Role of Scripting
There is no definitive definition of a scripting language. Sometimes the term is used to make a distinction from compiled languages. However, some languages like C or C++ can be used for scripting as well as full applications. The term scripting is also used because a language will react to, control, or "script" a series of events. Even macro languages built into PC applications like spreadsheets, databases, word processors, and multimedia applications are now often called scripting languages. The purpose of most scripting languages is to extend the capabilities of applications. Just as the authors of this book cannot imagine every creative use you will make of JavaScript, software authors cannot imagine every possible use of their applications. To make their products more versatile, they add a scripting language. With JavaScript you have a scripting language to use your imagination on the Web. Current uses of scripting languages may give you an insight of the potential for JavaScript. You probably know that macros are built in to many PC applications. Apple's HyperCard contains a very powerful scripting feature. Perl is a scripting language used in many CGI scripts you use on the Web.
Not only is the same language used in each application, the script language helps the applications work together. Microsoft expanded the role of Visual Basic to work with Microsoft Access and Excel. Lotus has developed LiveBasic for its product suite. With the PC environment, the role of scripting languages is serious business. It's the subject of college courses and often used to build nontrivial applications. NOTE Historically, scripting has made several "killer applications." These are applications, that define a whole new category of software, significantly expand the market, and provide a primary reason for people to use a computer. The first successful spreadsheet was VisiCalc, which disappeared with the success of Lotus 1-2-3. The latter had scripting. There were many different database applications on the market before Ashton-Tate's dBase, but this product was programmable with a scripting language. Scripting gave these applications a competitive edge. First, it was a feature that could be used to sell the product. Second, people actually started to use the feature and create significant new capabilities for these products. Third, these scripts created a whole new market with magazine articles, books, third-party software publishers, and training. Fourth, the continuing use of these scripts became an investment by the user in these products. Existing scripts often prevented users from switching to competitive products. And finally, even when a competitive product was introduced with new features, someone would introduce scripts that attempted to add these features into the existing products. Scripts allowed both the publisher and users to advance.
Perl is an interpreted language. While you should be able to find a version of Perl for almost any computer platform, it was created for UNIX systems. It is now platform independent. The vast majority of Perl scripts will run without modification on any system. Take a script written on UNIX and it will run perfectly well on DOS. A CGI script is a type of script that responds to events. In this case, the event is a user submitting data from an HTML form. The attributes of a <FORM> include ACTION, which defines the script to process the data when it is submitted. For example,
<FORM ACTION="\cgi-bin\guestbook.pl">
will process the data from the form in a script called guestbook.pl. More than likely this routine would store the data in a file and return an HTML page to the browser as feedback. It would probably say something like, "Thanks for your entry into our guestbook." Perl is freely distributed on the Internet, but please see its license for more detail. You should be able to find a version for your system using any of the Internet search services. Larry Wall is the sole maintainer. Perl's strength as a language is in manipulating files and text to produce reports. This capability along with its associative arrays make it a natural fit for creating CGI scripts. In a few lines you can process data and return an HTML document in response to an HTML form. If you are a Perl programmer, you can rather quickly learn JavaScript. Both have a similar control structure and both are interpreted languages. Unlike Perl, JavaScript is object-based but it is not nearly as complex. You might miss the text processing capabilities of Perl, but you will find JavaScript a delightful new language to learn. There are some cases where JavaScript is not the appropriate solution, but using Perl for a CGI script would fit the requirement. Generally, if you need to store information, you are going to have to do that on the server and Perl would be a good choice.
new file. This information is almost always a new page, though it might be a multimedia file like an audio clip or an animation. With JavaScript-enhanced pages, there is JavaScript code embedded in the HTML code. The JavaScript can instantly provide you information without waiting on the server or your Internet connection (see fig. 1.13). This information can come from user input, code "hidden" with the document, or other documents in frames or other windows. Figure 1.13: With standard HTML pages, a Web site serves each page to the browser. With JavaScript-enhanced pages, the source for a page can be the existing page. This JavaScript-enhanced page makes this new information visible by updating the contents of a form or by generating an entirely new document. In a JavaScript calculator (refer to fig. 1.1), the form is updated when numbers are entered. In the Punchline script (refer to fig. 1.5), the user clicks the button and a new document is created from the hidden punchline of the joke.
NOTE Like most any other computer language, JavaScript allows you to place comments within your code. Single-line and multiple-line comments are possible. A multiple line starts with the two characters /*. It ends with the two characters */. Consider the following example:
/* This is the start of multiple lines of comments. This is the end */
NOTE To make a comment at the end of a line or on a single line, just use the characters // and everything after that mark until the end of the line will be considered a comment. Between SCRIPT tags you can write two types of code: direct statements and functions. Direct statements are executed by the browser as they are loaded. For example, objects are initialized in direct statements. Functions are blocks of code that are executed only by other code or events.
For example, mouse-click events usually trigger functions. Most of your programs will use both direct statements and functions. Many existing HTML tags now have additional attributes to support JavaScript. For example, all elements of a form can now be identified with the NAME element. You should be familiar with the NAME attribute because it has long been used in creating anchors. Using NAME to identify objects in your documents will generally simplify your coding and debugging. The final addition to HTML is recognizing events like mouse clicks, changes in text boxes, and the loading or unloading of pages. This is how the document recognizes the user interaction. These events are used to trigger JavaScript actions. The code can be quite straightforward, as in the following:
<FORM> <P>Click inside the box and then out to see change. <INPUT TYPE="text" NAME="sample" onChange = "sample.value = a"> <!-- ...after any change in this text box, but the value of a in </FORM>
The JavaScript code that is triggered by an event can be simple or complex. With simple actions, the entire code can be placed in the event element. This is shown in the previous example with sample.value = a. Throughout this book you will see more typical examples of where functions are called by events.
supports JavaScript. This feature is not supported in version 2.0, but is planned for version 2.1 of Netscape Navigator.
Java Displays Are Limited to a Graphic Area To display information on a Web page, Java is limited to painting its text and graphics within a defined area. Just like images on a page are drawn within a defined area of the page, so it is with Java programs. Within these areas the Java applets can create animations, paint, and use various fonts. However, an applet cannot affect anything outside its area. JavaScript gives you access to the entire Web page. You can modify properties of the page or any element of the page. You can create new documents or update parts of a form. Unlike Java, JavaScript lets you change the appearance of any part of your Web documents, not just a limited area. NOTE The hype on Java is that it is flexible enough to do anything. Currently, it cannot affect anything in a Web page outside of the area to which it is assigned. If you want your HTML document to interact with Java, forget it. The only way for Java to control everything on the screen is to write a program from scratch and re-create the entire screen. You basically have to rewrite some browser functions. To access browser objects, Java is expected to work more closely with JavaScript in future editions. This should enhance the capabilities of both languages. Directly related to this is Sun's work on a new version of HotJava, its Web browser. Apparently the new version's primary goal is to make available general-purpose browser routines for Java programmers. It is not clear at this time how this will play out, but the development of HotJava is worth watching. Java Applications Can Stand Alone Java is a general-purpose language that can create standalone applications. Unlike the Java applets that run in Web pages, these applications may not even connect to the Internet but perform business functions like accounting. This is an important aspect of Java that has excited many people. JavaScript, like most other scripting languages, works only with an application. Currently it works with Netscape's Navigator browser and the LiveWire server environment. In the near future it will also work with plug-ins. But JavaScript applications will not function independently. CAUTION HotJava (not to be confused with Java or JavaScript) is Sun's own Web browser written in Java. It has shown that Java applications can stand alone. This browser's purpose was to demonstrate the early applets written with the alpha version of Java. With the official release of Java version 1, the original HotJava is no longer a viable browser. It will not run applets written in Java version 1. A new version of HotJava, which will support both Java 1.0 applets and JavaScript, is apparently in the works .
Java is a Compiled Language With Java you write your code, compile it, and then run it. The person using your Java applet from a Web page cannot look at the source code. For many programmers, there is a sense of security here that you are not giving away your code. JavaScript is interpreted. The code you write in JavaScript is the code that the browser executes. There is no intermediate step of creating executable code from the source code. People can look at the source code of the HTML page and read your JavaScript code and your comments. JavaScript and Java Development Tools The first generation of development tools for these languages are just being introduced. Since JavaScript and Java are very new languages, this is not surprising. However, looking at the nature of the products, some general distinctions between the development tools can be made. Java is very much like the C++ language. It is object oriented, uses many of the same statements, uses libraries, and is compiled. Several companies that have strong C++ programming environments are developing similar environments for Java. This will allow the development of large-scale Java applications, but you will have to learn these programming environments. JavaScript is tied to the HTML page. The code is embedded in it and it operates on HTML elements. Since the code is interpreted by a browser, it is anticipated that HTML editors will add features for creating JavaScript code. JavaScript and Java have Different Audiences Java requires a multi-tasking, multi-threaded environment. So anyone operating on the Unix platform, OS/2, Windows NT and 95, or Macintosh will be able to run Java applications and applets. This is a substantial part of the Internet audience. JavaScript works in any version of Netscape Navigator 2.0 and above, as well as any version of Microsoft Internet Explorer and above. Given the many platforms these browsers support, this is also a substantial part of the Internet audience. There are some big differences between these audiences. The biggest difference is that millions of people running Windows 3.1 can run Netscape Navigator and thus enjoy JavaScript-enhanced pages. These same people cannot run Java applets or applications. It appears that more Internet browsers will support Java than JavaScript, though this is not certain. So while you might have a computer that runs JavaScript, your browser might not support it. But those that do not support JavaScript should be a minority with Microsoft and Netscape supporting both languages. So in the near future it appears that JavaScript has a wider audience due to the Windows 3.1 users. However, as these people upgrade and as new Java-compatible browsers become available, it seems Java will develop a larger audience. Because JavaScript is an interpreted language, there is a huge audience of potential JavaScript authors. All it takes to write a JavaScript program is a JavaScript-compatible browser like
Netscape 2.0 and a text editor. Most HTML editors can also be used to write JavaScript code. So, millions of people now have all the tools they need to create JavaScript applications. In a matter of a few days Netscape was able to distribute probably millions of JavaScript interpreters. It took Microsoft years to distribute nearly as many copies of Microsoft Basic into computers. Learning JavaScript is almost easy. By typing in just a few lines, you can be running a JavaScript application. As you read through this book you will quickly be incorporating many scripts into your pages. But just as anyone can plant a seed, it does take some patience and skill to create a garden.
JavaScript Syntax Variables and Values o Implicit Data Types in JavaScript o Type Conversion Statements and Operators o The Structure of JavaScript Statements o Operators o Comments in JavaScript Code Control Structures o The if Statement o The while Statement o The for Statement Functions and Objects o Functions o Objects
There are many, many different computer programming languages in use today. Each has its own set of special features, which are highly praised by its fans and vigorously panned by its detractors. If you have worked in more than one language then you are aware that there is a continuum of language styles, ranging from highly structured languages such as Ada to more free-wheeling ones such as Lisp. Many are associated with specific settings or applications. Ada, for example, is often found in military projects, while Lisp is often associated with artificial intelligence. Some languages, such as HTML, the language used to describe the layout of World Wide Web pages, have a well-defined organizational structure, but have very little in the way of traditional program structure (there are no data types, for example). In trying to understand a new language it is not only important to master its syntax, it is also vital to appreciate its style-the way in which that language can be used to accomplish specific goals. We have already reviewed the basic goals of JavaScript in chapter 1, "What Is JavaScript?" as well as contrasted it to the more structured Java language. This chapter describes the JavaScript language from both perspectives. A thorough description of its syntax is given, and some initial concepts on how to structure a JavaScript program are also introduced. Anyone who has programming in almost any modern declarative language, such as C, C++ or Pascal, will feel
immediately at home. In addition, HTML authors who have never programmed will be able to rapidly acquire JavaScript proficiency.
JavaScript Syntax
JavaScript is based on an action-oriented model of the World Wide Web. Elements of a Web page, such as a button or checkbox, may trigger actions or events. When one of these events occurs, a corresponding piece of JavaScript code, usually a JavaScript function, is executed. That function, in turn, is composed of various statements which perform calculations, examine or modify the contents of the Web page, or perform other tasks in order to respond in some way to that event. For example, pressing the SUBMIT button on an online order form might invoke a JavaScript function that validates the contents of that form to ensure that the user entered all the required information. In this section, we examine the syntax of JavaScript from the bottom up. We begin with the most basic concepts of how to write a JavaScript statement, and what that statement does, and progress upward through more complex and powerful structures in subsequent sections, culminating in a detailed discussion of JavaScript functions and related concepts. Chapter 3 "Events and JavaScript," explores in greater detail how these elements are tied into Web pages through events. In general, the elements of a JavaScript program can be divided into five categories, as follows:
Variables and their values Expressions, which manipulate those values Control structures, which modify how statements are performed Functions, which execute a block of statements Objects and arrays, which are ways of grouping related pieces of data together
This set of categories is very similar to many other languages. As we examine each of these elements in subsequent sections we will discover that JavaScript is somewhat minimalist in its approach. Many familiar elements, such as explicit data types (int, String, REAL), are missing or have been substantially simplified. However, JavaScript also provides a number of powerful object-oriented constructs which greatly simplify program organization. In this way, JavaScript has the ex-pressive power of languages such as C or Java, while also having fewer rules to remember.
All JavaScript variables are declared using the keyword var. A variable may be initialized, meaning that it is given a value when it is declared, or it may be uninitialized. In addition, multiple variables can be declared on the same line by separating their names with commas. For example, the statements
var x = 7 var y,z = "19" var lk = "lucky"
declare a variable named x with initial value 7, an uninitialized variable y and variables named z and lk whose initial values are "19" and "lucky," respectively. It might seem that x is an integer, z and lk are strings, and y is some undefined quantity. In fact, the real story is a little more complicated than this. The value of each variable depends on the context in which it is used. This context is related to the order in which the variables are seen. As you might guess, the expressions
5 + x lk + z
evaluate to 12 and "lucky19," seemingly confirming our suspicions about what they really are. However, it is also possible to form the expressions
lk + x x + z
which evaluates to "lucky7" and 26, respectively. In the first expression, x has been interpreted as a string, while in the second, z has been interpreted as an integer. TIP JavaScript often attempts to treat all variables within a statement as if they had the same type as the first variable in the statement. These examples illustrate two critically important points about the JavaScript language. First, while JavaScript does not have explicit data types, it does have implicit data types. Second, JavaScript has a set of conversion rules that allow it to decide how to treat a value based on the context in which it is used. The context is established by reading the expression from left to right. In the expression x + z, for example, x is implicitly a numerical value, so that JavaScript also attempts to view z as a number and perform the sum numerically. It succeeds, and the expected 26 results. What would have happened if we had tried x + lk? The x variable occurs first on the left, and is really a number at heart. JavaScript thus tries to interpret the variable lk as a number, too. This is extremely unlucky, in fact, because "lucky" cannot be converted to a number (while z, the string "19," could). JavaScript reports an error if asked to evaluate x + lk. To understand JavaScript variables and values, therefore, it is necessary to understand its set of implicit types and how they may be converted to one another.
Before we enter into these details, let us consider one final example. In all the preceding cases, the uninitialized variable y was never used. What would be the value of an expression such as
x = z + y
Of course, as in all other programming languages, the result of using an uninitialized variable is never good. Since y has never been given a value, there is no way this expression can be evaluated. It may result in something seemingly innocent, such as x being assigned the value of z, as if y were zero. It may also result in something much more serious, such as the value of x becoming something strange, or, more likely, a JavaScript error occurring. This leads to the following common sense rule. TIP Initialize all JavaScript variables to meaningful default values. If a variable has no meaningful default, initialize it to null.
A number, such as -5, 0, or 3.3333 A string, such as "Click Here" or "JavaScript" One of the logical values true or false A "non-atomic" JavaScript element, such as a function or object The special value null
Actually, it would be more correct to say that there are five categories of data type, since it is possible to distinguish two different types of numbers (integers and floating-point numbers), and many different types of JavaScript objects, functions, and other structured types. In fact, part II of this book, "JavaScript Objects," is entirely devoted to explaining the many different JavaScript objects. Variables and Variable Names It is very important to distinguish between variables and their values. The statement x = 10 contains two components: the variable x and the literal value 10. A literal refers to anything that is referred to directly, by its actual value. A variable is just an abstraction that provides a way of giving names to values. Thus the statement x = 10 says, "I am going to refer to the concrete (literal) quantity 10 by the abstract (variable) name x," just as you might say, "I am going to call this lumpy thing I'm sitting on a chair." This also leads to the following important piece of advice. CAUTION It is bad practice to change the implicit data type of a variable. If a variable is initialized to have a certain type (such as string) it should always have that type.
Thus, since we have started out with x = 10 we should make sure that x always has some numeric value. There is no rule that prohibits us from later saying x = "Fortran", but this will generally lead to confusion or programming errors in most cases. No one will stop you from calling that lumpy thing you are sitting on "bacon and eggs" but many of your guests may become confused if you do so. One final rule about variable names: a valid JavaScript variable name must begin with a letter or with the underscore character (_). Case is important, so that norl, NoRl, NORL, and _NORL are all valid JavaScript variable names that refer to different variables. Numerical Values There are two numeric types in JavaScript: integers and floating-point numbers. The rules for specifying both types are almost identical to those of C or C++ or Java. Integers may be specified in base 10 (decimal), base 8 (octal), or base 16 (hexadecimal) formats. The three forms are distinguished as follows, based on the first one or two characters:
1-9 followed by any set of digits is a decimal integer. 0 followed by any set of the digits 0-7 is an octal integer. 0x or 0X followed by any of 0-9, a-f, or A-F is a hexadecimal integer.
Any of the three forms can also start with a + or - sign. Thus, -45 is a decimal integer, 017 is an octal integer, and 0x12EF5 is a hexadecimal integer. The minimum and maximum integers that can be used are implementation dependent, but at least 32 bits should be expected. Floating-point numbers can be specified in either the standard decimal point (.) format or the engineering E-notation. Typical floating-point numbers should contain a decimal point or an exponent, which may begin with either e or E. A floating-point number may also have a + or sign. 0.0, -1.4e12, and 3.14159 are all valid floating-point numbers. The range of valid floats is again implementation dependent, but you should expect that any valid short floating-point number, as defined by the IEEE standard, is acceptable. (The IEEE is the Institute of Electrical and Electronics Engineers, a professional and standards-making organization.) Note that the original LiveScript language attempted to treat all the numeric types the same. Since it has become JavaScript there has been a convergence toward the numerical types of the Java language, and the distinction between integer values, such as 5, and floating-point (or real) values, such as 3.3333, has increased. CAUTION LiveScript is now completely obsolete. It has been replaced by its descendant, JavaScript. Avoid any code you encounter labeled LiveScript as it will almost certainly not work correctly. NOTE Watch out for changes in the way JavaScript handles numeric types. In the future, the distinction between integers, single precision floating-point types (floats), and double precision floating-point types (doubles) may become much sharper.
Strings In JavaScript, strings may be specified using either single quotes ('stuff') or double quotes ("otherstuff"). If you begin a string with one type of quote you must end it with that same form of quote-for example, "badstuff' is not a legal string in JavaScript. Strings may also be nested by alternating the types of quotes used. In fact, you must alternate single and double quotes if you wish to put one string inside another. Here is an example of several nested strings (with apologies to Rudyard Kipling): "Oh, it's 'Tommy this' and 'Tommy that' and 'throw im out, the brute'" As in C and Java, JavaScript strings may contain special combinations of characters, known as escape sequences, to denote certain special characters. The rules for this are still emerging, but it is probably safe to assume that all the escape sequences defined in C will be supported. Since you will almost always be using formatting directives of HTML (such as <BR> for a line break) you will probably not use these directives very often. At the moment, the following sequences are supported:. \t \r \n \f \b tab line feed return form feed (vertical tab) backspace
The special string "" or '' represents the zero length string. This is a perfectly valid string whose length is zero. This is the shortest JavaScript string; the length of the longest is, as usual, implementation dependent. It is reasonable to expect that most JavaScript environments will permit very long sonnets (or very short legislative measures) to be represented as single strings. Logical Values The logical, or boolean, values true and false are typically used in expressions that test some condition to determine how to proceed. If that condition is met then one set of statements is executed; if it is not then another set is used instead. The first corresponds to the true condition, while the second represents the false condition. Not surprisingly, such expressions are known as conditional expressions. As you will see in the "Operators" section there are several comparison operators, such as the equality test (==), which result in logical values. It is possible to think of true as 1 and false as 0. In fact, JavaScript converts these logical values into 1 and 0, respectively. JavaScript also accepts any non-zero integer in place of true, for example, so that 5 and -3 can both be used as stand-ins for true. Many different programming languages follow this same convention. It should be avoided in JavaScript, as it can lead to type confusion. The Value null The value null has a very special role in the JavaScript language. It is the value of last resort, so to speak, for every variable. For the beginning JavaScript programmer, its primary role will be in initializing variables that do not have any more meaningful initial value.
For example, in the set of variable declarations given in the earlier "Variables and Values" section, to initialize y to some value, we should have actually written
var y = null
This prevents JavaScript errors that arise when an uninitialized variable is accidentally used in an expression that requires a value. It is important to realize that the value null does not give the variable y any implicit data type. null also has the property that it may be converted to a benign form of all the other types. When it is converted to a number it becomes 0, when it is converted to a string it becomes the empty string "", and when it is converted to a boolean value it becomes false. This is the one case where is it permissible to change the implicit data type of a variable after it is declared. Therefore, statements such as
var lk2 = lk + y var w = x + y
result in lk2 having the value "lucky" (the same as lk) and w having the value 10 (the same as x). This is why the value null is an excellent way of initializing variables-it is guaranteed to be harmless.
Type Conversion
Several of the examples in the previous section use the + operator to combine different types of things. You may recall that when a string is combined with a number in the form
stringthing + numberthing
the number is converted to a string and the + operator then glues the two strings together (concatenation). However, if they are combined in the opposite order
numberthing + stringthing
then JavaScript attempts to convert the stringthing to a number and add it, numerically, to numberthing. If the stringthing can be converted to a string, such as "-14," then all goes well; if it cannot then an error results. This illustrates the concept of implicit conversion in JavaScript. We have already seen that some examples of implicit conversion are completely safe. false can be converted to 0, "5" can be converted to 5, and null can be converted to just about anything. However, some conversions are obviously invalid, and others might be questionable. Questions such as, "May the string '3.0' be legitimately converted to the integer 3?" are actually very difficult to answer with complete generality. There are two approaches to handling this complex issue: use explicit conversion whenever possible, and use implicit conversion with great care. Both approaches should be used. A
detailed study of explicit conversion is in chapter 5, "Built-In JavaScript Objects," beginning with the section "The String Object." For the moment we will use the following rules of thumb. CAUTON Use implicit conversion only when converting to a string form. Never use it to convert to numerical form. This is because attempts to convert a nonnumerical quantity to a numeric form cause serious JavaScript errors, while conversion to string form generally does not. You have probably already noticed that conversion to a string is always safe, at least for the data types we have encountered so far. In fact, this type of implicit conversion is a boon to the JavaScript programmer, since it avoids the tedious formatting directives that are necessary in many languages such as C. In JavaScript we can say
"This page has been accessed " + cnt + " times today"
without having to worry about the data type of the variable cnt. This construction will always give a valid string, and never an error. The preceding Caution is also based on standard principles of defensive programming. There are many things that cannot be sensibly converted to a numerical form, so the prudent approach is to never try to implicitly convert anything to a number. There are several more robust approaches that can be used in case we have a string that we want to convert to numerical form. These are described in chapter 5. We will also see other exceptions to this rule as our mastery of JavaScript deepens.
JavaScript programs, as mentioned at the beginning of this chapter, are collections of statements, typically organized into functions, which manipulate variables and the HTML environment in which the script itself works, in order to achieve some goal.
2
y = x + 5
This statement contains three parts: the result y, the operator = and the expression x + 5. The result always occurs in the left side, since JavaScript always operates from left to right, and is often called the lvalue. The result must always be something that can be modified. It would be erroneous to write null = x + 5, for example, because null is a built-in, unchangeable component of JavaScript itself-it cannot be modified, so it can never appear as a result. The operator = is the assignment operator, of course. It causes the expression on the right to be evaluated and its value given (assigned) to the result. The expression x + 5 contains another operator, the + operator, which acts to combine x and 5 in some context-specific way. Since x is a number in this case, the + operator performs ordinary addition, and y gets the value 15. As we have already seen, if x had been a string, such as "bleh," then + would have acted as a string concatenation operator and y would be given the value "bleh5" instead. This is an example of operator overloading-the + operator can do different things in different situations. Many JavaScript operators are overloaded. There is one final point to be made about this statement and about the structure of JavaScript programs in general. JavaScript has adopted a line-oriented approach to program flow. This means that it knows that a statement has ended when it reaches the end of a line. It is also possible to explicitly terminate a statement with a semicolon character (;). The statement y = x + 5; is identical in effect to the statement y = x + 5. This also means that you can, in fact, put multiple statements on a single line by separating each of them with a semicolon. For those just starting out in JavaScript it is often a good idea to terminate each statement with a semicolon, and to also put only a single statement on each line. This might seem both redundant and extraneous, but it is well justified. The end of a line is often a purely visual concept. Anyone who has ever used a word processor has undoubtedly encountered the situation where a very long line looks like two lines. Different platforms (Macintosh, PC, UNIX) also have their own unique ideas as to what the proper end-of-line characters are. It is much safer to put in the extra semicolon character and be explicit about the end of the statement than it is to rely on one's eyesight.
Operators
The set of operators that JavaScript uses is, once again, very similar to that of the C, C++, and Java languages. It provides a number of different ways of combining different values, both literals and variables, into expressions. Some operators require two elements to participate in the operation, and are referred to as binary operators. The + operator is a binary operator. Other operators require only a single participant (operand), and are known as unary operators. The ++ operator, which adds 1 to its operand, is a unary operator. Operators may also join forces to form aggregate operators, as we shall see next. JavaScript operators may be classified into the following groups:
Computational operators
This grouping is purely functional, and is based on what the operators actually do. The next four subsections examine each type of operator in more detail. Table 2.1 summarizes the operators in each category and how they are used. Table 2.1 A Summary of JavaScript Operations Computational Operators + Addition, String Concatenation Subtraction, Unary Negation * Multiplication / Division % Modulus ++ Preincrement, Postincrement -Predecrement, Postdecrement Logical Operators ==, != Equality, Inequality <,<=,=>,> Arithmetic and String Comparison ! Logical NOT &&,|| Logical AND, Logical OR ? Conditional Selection (trinary) , Logical Concatenation Bitwise Operators &,| Bitwise AND, Bitwise OR ^ Bitwise eXclusive OR (XOR) ~ Bitwise NOT_ <<,>>,>>> Shift Left, Shift Right, Unsigned Shift Right Assignment Operators = Assignment OP= Aggregate Assignment (+,-,*,/, %,&,|,^,~,<<,>>,>>>) Computational Operators The computational operators are addition (+), sub-traction and negation (-), division (/), multiplication (*), modulus (%), increment (++), and decrement (--). These operators are often used in performing arithmetic computations, but do not forget that the + operator is overloaded; it also has the extremely important role of string concatenation.
The first five computational operators have their standard mathematical meanings. They add, subtract, divide, or multiply two numeric quantities. By combining two quantities using one of these operators the result is made as precise as possible. If an integer is added to a floating-point number, the result is a floating-point number. The following four statements illustrate the use of these operators:
x y z w = = = = 4 + y; 5.5 - z; 10 / w; 1.4e5 * v;
Note that division of integer quantities result in an integer result, so that if w had the value 4 in the third statement, z would get the value 2, not 2.5. Note also that the - operator may also be used as a unary operator to compute the negative of a numeric quantity:
n = -m;
This has exactly the same effect as if we had multiplied m by -1. The modulus operator (%) is used to compute the remainder from a division. Although it can be used with floating-point numbers, it is typically used with integers, so that 21 % 4 evaluates to 1. The modulus operator always gives a remainder that has the same sign as the corresponding quotient, so that -21 % 4 evaluates to -1, not 3. The increment and decrement operators are conveniences created to simplify the very common operations of adding or subtracting one from a number. Both these operators are unary and come in two forms: prefix and postfix. The expression ++x is the preincrement form of the ++ operator, while x++ is the postincrement form. This leads to a subtle and often misunderstood point about the increment and decrement operators. Supposing that x has its usual value 10, consider the two statements
y = ++x; z = x++;
These look very similar, but are in fact very different. After both of these statements have been executed, x has the value 11. However, y ends up with the value 11 while z has the value 10. Why? The reason has to do with the complex issue of what order the operators ++ and = are evaluated in these two statements. In the first statement, the ++ is evaluated first, so that x attains the value 11, and then the assignment = is evaluated, so that this value is passed on to y. In the second statement, the assignment operator = is applied first, so that z becomes 10, the current value of x, and then the ++ is applied to x, so that it advances to 11. The same rule applies to the decrement operator (--). This might seem like it is a violation of the rule of left-to-right evaluation, and it is. Even though the equal sign is to the left of the preincrement operator (++) in the first statement, the ++ operator takes effect first. This is an example of operator precedence, the order in which
multiple operators are applied. This complex topic is discussed in more detail in the "Order of Evaluation" section later in the chapter. Logical Operators Logical operators in JavaScript are used either to carry out some form of test, or to combine the results of more than one such test. They are often referred to as conditional operators. The logical operators that perform a test of some sort are the equality/inequality operator (== and !=), the comparison operators (<, <=, >, and =>), and the logical negation operator (!). The operators that combine logical values are logical AND (&&) and logical OR (||). Finally, the conditional operator (?) and the comma operator (,) are also combining operators, although they are only vaguely logical operators. Equality Operators The binary equality (==) and inequality (!=) operators are used to test if two quantities are the same or different. These operators are overloaded. On integers, they test for strict equality or inequality. On floating-point numbers, they test to see if the two quantities are equal within the precision of the underlying floating-point type. On strings, they test for exact equality-recall that case is significant in JavaScript strings. These operators all return a boolean value, either true or false. For example, if x has the value 10, y has the value 3.0, and z has the value "barney," then x == 10 is true, y != -5.0 is also true, and z == "fred" is false. Unfortunately, even operators as simple as these can be a source of error. It is regrettable that the logical operator == looks so much like the assignment operator =. Consider the following incorrect code fragment:
if ( x = 3 ) { stuff
The purpose of this code is almost certainly to test the value of the variable x against the constant 3, and execute the stuff if that test succeeded. This code fails to realize that purpose in two very dramatic ways, just by inappropriately using = instead of ==. First of all, x = 3 always gives x the value 3, no matter what its previous value was. Instead of testing x using ==, we have altered it with =. Second, the value of the expression x = 3 is the value of its left side, namely 3. Even though 3 is not a true logical value, it is treated as true by the if statement (if is described in greater detail in the section, "Control Structure," later in this chapter). This means that stuff will always be executed, rather than only being executed when x has the prior value 3. This type of error occurs in every programming language in which similar operators are used for very different purposes. In this case, we could have adopted another rule of defensive programming and said
if ( 3 = x ) { stuff
In this case, our typing mistake (= instead of ==) leads to an error, rather than resulting in a subtle programming flaw. Since 3 is a constant, it can never appear on the left side of an assignment, but it is quite capable of appearing on the left side of a logical test. Said another way, since x ==
and 3 == x are completely equivalent, the form 3 == x is preferable. If it is mistyped as an assignment statement (3 = x) it leads to an immediate error rather than one which might take hours of debugging to uncover. This leads to the following advice.
3
TIP When testing for equality always put constants on the left, especially null. There is another subtle evil about the (in)equality operators when they are used with floatingpoint numbers. It is very tricky to make floating-point arithmetic completely independent of the underlying machine. This means that z == 3.0 might be true on one machine but false on another. It can also lead to seemingly absurd results such as 3. != 3.00 being false while 3.0 == 2.9999999 is true. A remedy for this problem is presented at the end of this section. Comparison Operators The comparison operators (<, <=, > and >=) also operate on both numbers and strings. When they act on numbers they perform the usual arithmetic comparisons, yielding boolean values, as with the equality operators. When they act on strings they perform comparisons based on dictionary order, also known as lexicographic order. If a string str1 occurs earlier in the dictionary than a second string str2 then the comparison str1 < str2 (and also str1 <= str2 ) will be true. For example, "barney" < "fred" is true, while "Franklin" < "Delano" is false.
The Negation Operator The logical negation operator (!) is used to reverse the sense of a logical test. It converts true to false and false to true. If x < 15 is true then !(x < 15) is false, and vice versa. Note that ! may also be used with integer values, so that !0 is true, while !5 is false. As in other cases, this use of the ! operator violates type boundaries, and should be
avoided. The logical AND (&&) and OR (||) operators are among the most powerful operators in JavaScript. Both may be used to combine two or more conditions into a composite test. The logical AND of a set of con-ditions is true only if all of its component conditions are true. The logical OR of a set of conditions is true if any of its component conditions are true. Thus
Boolean Logical Operators ( x < 17 ) && buttonPressed && ( z == "Meta" )
is true precisely when x is less than 17 and the boolean variable buttonPressed is true and z is exactly equal to the string "Meta." Similarly,
( x < 17 ) || buttonPressed || ( z == "Meta" )
with
JavaScript stops trying to evaluate the expression as soon as its value is known.
To see how this works, suppose that x has the value 20, buttonPressed is true, and z is the string "Hyper". Since ( x < 17 ) is false the second and third conditions in the logical AND statement are never evaluated. This is because false && anything is always false, so the value of the first expression must be false. Similarly, the second statement stops as soon as buttonPressed is evaluated. Since true || anything is always true, the second expression must be true. Lazy evaluation can be both a boon and a curse. Suppose that "digofpi(1000000000)" is a function that computes the billionth digit of pi. The expression
( x < 25 ) || ( digofpi(1000000000) == 3 )
does not actually try to compute the billionth digit of pi if x is 20, because the expression is already known to be true, and digofpi() is never called. As an additional example, consider the following expression:
( x < 25 ) && beaupage()
Suppose that beaupage() is a function that displays a beautiful Web page. If x is 30 this page will never be seen, because the first part of expression ( x < 25 ) is already known to be false. As a result the function beaupage() is never called. We revisit this phenomenon in the "Functions and Objects" section at the end of this chapter. For the moment, it is wise to be aware of lazy evaluation. The logical AND and OR operators also provide us with one solution to the problem of floating-point comparison. While it may not be possible to ever determine if x is exactly equal to the constant 3.0, you can be certain that it is close using a combined test such as
Fuzzy Comparison ( x - 3.0 ) < epsilon || ( 3.0 - x ) < epsilon
where epsilon is some suitably small value, such as 0.001. This form of test is often referred to as a fuzzy comparison. CAUTION Floating-point arithmetic is not an exact science. Avoid exact comparison tests such as == and !=; use fuzzy comparisons instead.
The Comma and Question Mark Operators The final two operators in the logical category are the conditional operator (?), often called the question mark operator, and the comma operator (,). These two operators are only vaguely logical, but they don't readily fall into any of the other
categories either.
The conditional operator is the only trinary (3 operand) operator in JavaScript. It is used to select one of two possible alternatives based on a conditional test. The syntax for this operator is
( conditionthing ? truealt : falsealt
If the conditionthing is true then the value of this expression is truealt; otherwise it is falsealt. Note that the colon (:) separating the true alternative from the false alternative is mandatory. This can be used to select an appropriate alternative and simplify code, as in this example:
printme = ( errorcode == 0 ? "OK" : "error" );
This expression makes the variable printme have the string value "OK" in case the variable errorcode is 0; otherwise, it is set to "error". The question mark operator is often a fast way to select one of two choices when a control structure would be unnecessarily cumbersome. Finally, the lowly comma operator can be used to force the evaluation of a set of expressions. All intermediate results are discarded, and the value of the very last expression on the right is returned. For example, the expression
b = (d = digofpi(1000000000)), beaupage(), (x < 17);
always computes the billionth digit of pi and assigns it to the variable d, always displays the beautiful page, always compares x against 17, and only returns the result of that comparison since x < 17 is the rightmost expression. The result of that comparison is assigned to the boolean variable b. This might seem like a clever way to outwit JavaScript's lazy evaluation, but it would be clearer to simply write
d = digofpi(1000000000); beaupage(); b = ( x < 17 );
In general, the comma operator is only useful when it is inside a for loop (see "Control Structures," later in this chapter), and should otherwise be ignored. Bitwise Operators In many situations you do not need to know, nor do you wish to know, the precise binary representation of values in your program. There are some situations, however, in which it is absolutely essential to operate at the lowest possible level and deal with the individual bits of a particular value. This often arises in mathematical applications, for example, or when precisely manipulating color values. The bitwise operators are used for this purpose. Table 2.2 shows JavaScript's bitwise operators. Note that all are binary, except for bitwise NOT, which is unary. Each operates on its operands one bit at a time. Table 2.2 JavaScript's Bitwise Operators Operator Name Symbol & Bitwise AND
Bitwise OR Bitwise XOR Bitwise Left Shift Bitwise Signed Right Shift Bitwise Unsigned Right Shift Bitwise NOT
Bitwise AND (&) examines each bit position in each of its operands. If both operands have a 1 bit in a given position, then that bit will also be set to 1 in the result. In all other cases, the output bit position is zero. For example, suppose x = 0x00001234 and y = 0x8000ABCD. Then z = x & y will have the value 0x00000204. You can see this more easily by writing x and y in base 2 (binary) notation, and looking for those positions in which both x and y are 1, as shown in the first part of figure 2.1. Figure 2.1 : JavaScript's bitwise operators operate on each bit separately. Note that x and y only have the same bits set in highlighted positions, so that those are the only bits set in their logical AND z. In this way, bitwise AND is the bit level analog of the logical AND. Bitwise OR (|) is similar. If either bit is 1 in any bit position, then that bit will be 1 in the result. Thus the value of w = x | y will be 0x8000BBFD, as you see in the middle part of figure 2.1. Each bit is set in w if either or both of the corresponding bits in x and y is set. The bitwise XOR (exclusive OR) (^) operator is a variation on the bitwise OR operator. It sets a bit in the result if either bit in the operand is set, but not both. The value of v = x ^ y is 0x8000B9F9, as shown at the bottom of figure 2.1. These three operators may also take more than two operands, so that it is possible to write a very long expression such as
n = ( a & b & c & d & e );
which operates from left to right, as usual. This expression takes the bitwise AND of a and b, ANDs that result with c, ANDs that result with d, and finally ANDs that result with e. The final result is saved in the variable n. CAUTION The bitwise AND (&) and OR (|) operators bear a shocking similarity to their logical counterparts && and ||. This can lead to painfully undetectable errors. The same care that is exercised with = and == should also be used with these operators.
The unary bitwise NOT operator (~) changes each 0 bit in its operand to a 1 bit, and each 1 bit in its operand to a 0 bit. The bitwise NOT of x will have the value 0xFFFFEDCB: x ~x 0000 0000 0000 0000 0001 0010 0011 0100 1111 1111 1111 1111 1110 1101 1100 1011
While &, |, ^ and ~ operate on bits in place, the shift operators <<, >>, and >>> are used to move bits around. The left shift operator (<<) shifts a set of bits to the left by a specified number of positions, while both >> and >>> moves that set of bits to the right in two potentially different ways. For example, let us evaluate these three expressions:
xleft = x << 5; ysright = y >> 3; yusright = y >>> 3;
The first of these shifts each bit in x to the left five positions. Zero bits are tacked on at the right, while the bits that are shifted out at the left are lost when they exceed the overall 32-bit length. So the value of xleft must be 0x00024680. The signed right shift operator acts in almost the same way. Each bit of y is shifted to the right three positions. Bits on the right edge of y are lost as they are shifted out. However, rather than shifting in zeros at the left side of y, the most significant bit of y, which happens to be 1 in this case, is shifted in. The resulting value of ysright is 0xF0001579. This might seem counterintuitive, but it makes good mathematical sense, since it preserves the sign of the operand. If y is negative (most significant bit set, as in our example) then any signed right shifted version of y will also be negative. Similarly, if y had been positive (most significant bit equal to 0) then any right shifted version of y would have been positive. The unsigned right shift operator (>>>) does not preserve the sign of its operand; it always shifts 0 bits in at the left edge. The value of yusright is therefore 0x10001579. The shift processes used to compute xleft, ysright, and yusright are shown in figure 2.2. Figure 2.2 : JavaScript's shift operators move bits to the right or left, and are equivalent to multiplication or division by a power of two. Since all the bitwise operators act at the bit level, chaos can result if they are applied to a variable that is not an integer. Floating-point numbers are particularly sensitive, since an arbitrary bit pattern need not correspond to a valid floating-point number. CAUTION Never perform bitwise operations on floating-point numbers. Your code will be unportable, and floating-point exceptions may result. Assignment and Aggregate Operators Our tour of JavaScript operators concludes with the assignment operator and its aggregates. You have already seen many examples of that most fundamental of all operators, the assignment operator (=). You are well aware that it is used to
assign the result of an expression or value on the right side of the = sign to the variable or lvalue on the left side of the = sign. In JavaScript, as in C, C++, and Java, you can also combine the assignment operator with any of the binary computational and logical operators. The expression
Left
OP= Right ;
OP Right ;
where OP is any of the operators +, -, /, *, %, &, |, ^, <<, >>, or >>>. So, to add 7 to x, multiply y by 19.5, OR z with 0xAA7700, and perform an unsigned right shift of 10 bits on w you can write
x y z w += 7; *= 19.5; |= 0xAA7700; >>>= 10;
These compact expressions replace the wordier versions x = x + 7; y = y * 19.5, and so forth. Order of Evaluation In elementary school math you were probably confronted with questions such as, "What is the value of 3 + 4 * 5? Is it 23 or is it 35?" This was your first exposure to the concept of order of evaluation, or operator precedence. You probably remember that multiplication has a higher precedence than addition, so that the correct answer is 23. The same issue arises in almost every program-ming language with the concept of operators-which comes first? There are two approaches to this issue. The first involves learning, or attempting to learn, the operator precedence table. The more operators there are, the more rules there must be in this table. The second approach is to simply ignore the issue completely and explicitly group your expressions using parentheses. Never write 3 + 4 * 5. Always write 3 + ( 4 * 5 ) or even ( 3 + 4 ) * 5 if that is what you want. This recommendation is very much like several others in this chapter. It trades the effort (and perhaps some readability) of using the explicit parenthesized form against the promise that the order of evaluation will always be exactly as you wrote it. Incorrect order of evaluation is almost certainly the second most common source of programming error in JavaScript (confusing = and == is the first). For the daring, figure 2.3 shows the operator precedence table for JavaScript. For everyone else, the following rule of thumb is recommended. Figure 2.3 : Use the operator precedence table to determine the order of evaluation. TIP
Use parentheses to explicitly specify the order of evaluation in expressions containing more than one operator There is one case in which no amount of parentheses will help. When using the increment (++) and decrement (--) unary operators you must simply know that preincrements and predecrements always happen before anything else.
*/
By contrast, C++ style comments are most suitable for short, pithy descriptions which will fit on a single line. A C++ style comment begins with // and ends at the end of the current line. Critical variables, for example, might merit a Java style comment indicating how they will be used, as follows:
var done = false; // set to true when we are all done
Both comment styles may be mixed freely in the same JavaScript program. However, such comments should never be nested, as this can lead to confusion. Also, the temptation to use HTML style comments (<!- and ->) should be strongly resisted, for reasons which will become clear in the next chapter. TROUBLESHOOTING I have just written my first JavaScript program. Everything looks fine, but the code does nothing. What is wrong? Here is the code:
/* My first JavaScript program *? ...many lines of code not shown /* End of my first JavaScript program */
Your comments are well thought out and informative. Unfortunately, your very first comment begins with /* but does not end with */. You have inadvertently typed *? instead of */, so that the comment does not end until
very far down in your program. When you use C style comments always make sure that they match.
Control Structures
At this point, you have had just enough of the JavaScript language to declare variables, perform assignments, and do various types of arithmetic, string, and logical calculations. You are not yet able to write any meaningful code because you do not have any higher level constructions. In this section, we will consider various methods of controlling the way in which statements are executed. The next section will expose the highest level of JavaScript-its functions and objects. There are three types of control structure in JavaScript, as follows:
if while for
These three control structures are very similar. Each is introduced by a keyword (while, for, and if, respectively) and each manipulates a block of JavaScript statements. A block is introduced by a left brace ({) and terminated with a right brace (}). There can be as many JavaScript statements between { and } as you wish, or as few. A block of code can even be empty, with nothing between the braces. In many ways, a block of statements is like a single gigantic statement. In particular, block structured constructs are often all or nothing-either the entire contents of the block are executed, or none of it is. Since blocks behave like single statements, it is also possible to put blocks inside other blocks, in a nested fashion. As you will see, each of the three control structures has its own specific format and its own special uses, although it is often possible to achieve the same results using any of the three types, with varying degrees of elegance.
The if Statement
The if statement is used to conditionally execute a single block of code. It has two forms, the simple if statement and the ifelse statement. The simple if statement consists of a conditional expression, known as the if test, and a block of code which is executed if that expression evaluates to a boolean true. An example of an if statement follows:
if ( condstmt ) { zero or more statements }
The block of code within the braces is often called the if block. The conditional statement condstmt can be any expression that yields a logical value. Note that numerical expressions may also be used; 0 is construed as false and all other values are taken to be true. As stated earlier, an if statement should be considered a single statement. Code blocks are not traditionally
terminated with a semicolon, although there is no harm in doing so. Listing 2.1 shows an example of a simple if statement.
In this example, the value of x is tested to see if it is less than 10 and also greater than -10. If the result of this test is true then the variable y is set equal to the expression x * x * x, known mathematically as the cube of x, in statement 1 (labeled 1:). The variable ystr is then set to a string that expresses this cubic relationship between x and y, in statement 2. If x fails either of the two tests in the if test then neither of the two statements in the if block are executed. It is easy to see even in this simple example that it is often desirable to have a contingency plan in case the if test is false. This leads to the second form of the if statement, the ifelse control structure. In this form, one block of code is executed if the if test passes, and a second block is executed if it fails. The format of this type of if statement is as follows:
if ( condstmt ) { ifblock of statements } else { elseblock of statements }
NOTE In the current version of JavaScript, the placement of the braces is important. The opening brace ({) should be on the same line as the if keyword. If an else clause is present, the closing brace (}) of the if and the opening brace ({) of the else should both be on the same line as the else keyword. Other placements of the braces are allowed, but may not be understood. In this form of the if statement, the if block is still executed if condstmt is true. However, in this case, the block of code following the else is executed if condstmt is false. Listing 2.2 shows an enhanced version of the code from listing 2.1 using the if...else form.
2
ystr = "Cannot compute the cube of " + x; // 4: explain the failure
In this example, statements 1 and 2 are still executed if x meets both tests in the if test. If either test fails then statements 3 and 4 in the else block are executed instead. Statement 3 is another example of defensive programming. The variable y is given a value, albeit a meaningless value. This is done so that if y is used later it will be guaranteed to have some value (even if we forgot to initialize) regardless of whether the code flowed through the true part of the if (the if block) or the false part of the if (the else block). Observe that ystr also gets a value no matter which of the two blocks is used. In the true case it has the informative string documenting the cube of x; in the false case it has a string indicating that the cube of x could not be computed. Since ystr will presumably be displayed to the user at some point, it is worthwhile to provide an error message. This is an example of parallel code design. Each conditional path modifies the same set of variables. For a simple case, such as listing 2.2, it is easy to ensure that this happens. There are only two variables, y and ystr, and we can see exactly where they are set in every case. For more complicated, nested conditional expressions, it can become almost impossible to observe every variable in every case. Parallel code design is a good goal to strive for nonetheless.
The condition clause condstmt is evaluated as a logical expression. If it is true then the block of statements between the braces is executed. The flow of control then loops back to the top of the while statement, and condstmt is evaluated again. This process continues until the condstmt becomes false, or until some statement within the block forces it to terminate. Each pass through the block of code is called an iteration. Figure 2.4 illustrates the basic structure of a while statement. Figure 2.4 : JavaScript's while control structure executes a block of statements conditionally. The first fundamental difference between a while statement and an if statement is that the while block may be executed many times, while the if or else blocks are executed once at most. You might well wonder how a while statement ever terminates. The code shown in listing 2.3 illustrates a simple situation in which the while block eventually leads to the condstmt becoming false.
2
var x = 1; var xsum = 0; while ( x <= 10 ) { xsum += x; x++; } // loop until x is greater than 10 // add x to the running sum xsum // increment x
This code accumulates the sum of all the integers between 1 and 10, inclusive, in a variable called xsum. x starts out as 1, so that xsum initially becomes 1 as well. x is then incremented to 2 by the x++ statement. That value is then added to xsum, so that it becomes 1 + 2 = 3. This process continues until x finally becomes 11 and the x <= 10 condition is false. xsum at this point has the value 1 + 2 ++ 9 + 10 = 55. Thus, the loop terminates. Note that it is critically important to initialize xsum to 0. If xsum is not initialized at all then the statement xsum += x, which is just shorthand for xsum = xsum + x, gives an error. If xsum is initialized to something other than 0, the final result contains that initial value, and is not just the sum of the integers from 1 through 10. Listing 2.3 shows one way in which a while loop can terminate. Statements within the block may cause the conditional statement to become false. It could also happen that the conditional statement at the top of the while was never true, so that the statements within the block are not executed even once. If x had started with the value 20 in this example then the while test would have been immediately false, and the statements xsum += x and x++ would have never been executed. In this event, xsum would retain its initial value of 0. Using the break Statement There is a third way for a while loop to terminate. If the special statement break is encountered inside the while block, the loop is forced to terminate immediately. No further statements are executed and the condstmt is not retested. Execution continues with the first statement after the end of the while block. Listing 2.4 gives an example of the use of the break statement.
while ( true ) { // 1: loop forever (well, almost) xtmp = xoddsum + x; // 2: compute a trial sum if ( xtmp > 100 ) // 3: if it is too large, then... break; // 4: we are done xoddsum += x; // 5: add x to the running sum xoddsum x += 2; // 6: increment x by 2 } lastx = x; // 7: save the final value of x in the variable lastx
The test clause of this while (statement 1) is true, which, you might well suspect, is always true. This means that there is no way for this loop to terminate unless it is forced to do so by a break statement. In statement 2 a temporary sum is formed in the variable xtmp. This sum is tested against the limit 100 in statement 3; if xtmp exceeds it then statement 4, the break statement, is executed, and the loop terminates. If the test fails (xtmp is still less than 100) then the real sum is formed in statement 5. (Note that it would have been equivalent, and slightly more efficient, if we had written statement 5 as xoddsum = xtmp.) In statement 6, x is incremented by 2. What does this while loop do? It keeps adding up numbers, odd numbers in fact, until the sum is less than 100. When the next sum would have exceeded 100, the if test succeeds, the break is executed, and the flow of control of the program reaches the first statement after the entire while block, namely statement 7. This statement saves the last value of x in a different variable, lastx. So this construction computes the largest sequence of odd numbers that can be added without having the sum exceed 100. You can easily determine for yourself that the value of lastx must be 21, since 1 + 3 + + 21 = 100 exactly, while 1 + 3 + + 21 + 23 = 123 > 100. The Perils of Infinite Loops Listing 2.4 not only illustrates the use of break, it also shows two other elements worth noting. First, listing 2.4 contains a nested conditional: there is an if statement inside the while block. This sort of construct is extremely common, and many levels of nesting are not at all unusual. Second, this example has another very common but somewhat troublesome feature. Since the while test is always true, there is no way for the while to terminate unless the break statement is executed. In the preceding example, it was terminated quite quickly. Suppose, however, that statement 6 had been incorrectly entered as x -= 2. In this case, xoddsum would be getting constantly smaller and xtmp would never exceed 100. This type of error is known as an infinite loop. Listing 2.3 is not immune either, even though it has a conditional test rather than a blanket true. If the final statement of that example had been mistyped as x-, it would never terminate either. Naturally, infinite loops must be vigorously avoided. They will only terminate when some kind of internal error happens (such as an arithmetic overflow when something becomes too large) or as a result of user intervention. Unfortunately, there is no foolproof way to write a while statement (or a for statement, as we shall see shortly) that is guaranteed to be correct. JavaScript is no different than any other programming language in this respect. However, the following general principles will reduce the opportunity for error:
Avoid while ( true ) whenever possible Have at least one way of exiting the loop body
If the while ( true ) construction is used, then the logic that exercises the break statement must be correct. If this logic isn't correct then the loop will never terminate. If you restrict your use of while ( true ) you will have fewer infinite loops. The second suggestion is based on the observation that the more chances there are to exit the loop, the less likely it is that the loop will last forever. Listing 2.5 shows a modified version of listing 2.4 in which we have moved the test on the sum to the while clause itself, and have also added a very paranoid test on the number of times through the loop (the variable loopcount).
while ( ( xoddsum + x ) < 100 ) { xoddsum += x; x += 2; if ( ++loopcount > 1000 ) break; } lastx = x;
This version satisfies both rules. Of course, the test in statement 4 is completely unnecessary. The code is simple enough that we can reassure ourselves that it is correct and will not go into an infinite loop. Once you are writing slightly more complicated while loops, you will find that there are usually multiple possible error conditions that arise. Every time you test for an error you should consider using a break statement. You will often see while ( true ) written as while ( 1 ). These are equivalent, since true has the numerical value 1, but the latter form is sloppy. The conditional portion of a while, if, or for statement should always be a true logical expression. Using the continue Statement There is another special statement that may be used inside while loops: the continue statement. The continue statement is used to force the flow of control back to the top of the while loop. When a continue statement is seen, all statements between it and the end of the while block are skipped, and execution continues at the top of the while. Listing 2.6 shows a simple use for the continue statement.
This example adds up every number between 1 and 100 that is not divisible by 5. The numbers that are divisible by 5 are skipped by virtue of statements 3 and 4. Statement 3 computes the
remainder when x is divided by 5. If that remainder is 0 then x must be evenly divisible by 5. In that case, the conditional in statement 3 is true, and statement 4 is executed. The continue statement causes execution to continue back to the top of the loop at statement 1. This means that statement 5 is not executed, so the sum always misses those values of x which are divisible by 5, and only those values. Many programmers would write line 3 as if ( ! ( x%5 ) ). While this style is very common, it is also confusing and a potential source of error. One problem with this form is that it confuses JavaScript types by using the numerical value x%5 as if it were a logical value. This form also hides the explicit test for zero of listing 2.6. While this ! form is more compact, it is also more error prone, and should be avoided. One striking difference between this listing and previous ones is that x is initialized to 0, not 1, and x is incremented at the top of the loop, not at the bottom. If the x++ were at the bottom, what would happen? The values 1, 2, 3, and 4 would all be gleefully added into xsum. When x reached 5, however, statement 3 would be true, the continue in statement 4 would be executed, and both xsum += x and x++ would be skipped. x would stay equal to 5 forever! Since the x++ statement is critical to the correct functioning of the loop, it must occur before the continue. If it occurs after the continue it will be skipped. CAUTION Any statement that must be executed on every pass through a loop must be placed before any continue statements.
The for clause, as shown, has three parts, separated by two mandatory semicolons. The initstmt is typically used to initialize a variable, although any valid statement may be used in this position. The initstmt is always executed exactly once, when the for statement is first encountered. The condstmt is a conditional test, and serves exactly the same function as in the while statement. It is tested at the top of each loop. The for statement terminates when this condition evaluates to false. The updstmt is executed at the bottom of each loop, as if it were placed immediately after the last statement in the for block. It is typically used to update the variable that is initialized by the initstmt. Listing 2.7 shows a simple example of a for statement. In fact, the code in this listing accomplishes exactly the same task as the code in listing 2.3. Note that this code does not bother
to initialize x when it is declared. This is because the initstmt part of the for loop sets it equal to 1 immediately.
In many ways, the for statement is very much like a fancy version of the while statement. Many of the observations that were made for while also hold true for the for statement. In particular, it is possible to use the break and continue statements within a for loop. One of the advantages of a for loop is that its update statement is executed on every pass through the loop, even those passes that are cut short by a continue. The continue skips every statement in the block, but it does not cause the update statement to be skipped. The for statement may also be used unwisely, just like the while statement. If the condstmt portion of the for clause is omitted, it is as if a true conditional had been used, so that something within the for block must force looping to terminate. You will occasionally see the construction for(;;), which is identical in meaning to while ( true ). The two semicolons are mandatory. The for statement also has some unique features that are not shared by while. The first is that variables may actually be declared and initialized within the initstmt portion. In listing 2.7 we could have dispensed with the external declaration of x, and put var x = 1; as the initialization portion of the for loop. This is often very convenient, since the loop variable (x in this case) is often used only within the loop itself, often making an external declaration pointless. NOTE If a variable is only used inside a block of statements it should be declared at the top of that block. This clarifies your code, since it shows which sections of code use which variables (known as variable scope). A second useful feature of the for statement is that both the initialization portion and the update portion of the for clause may contain multiple statements separated by the comma operator (,). Listing 2.8 shows another version of the code in listing 2.6, rewritten so that both x and lcnt become loop variables.
Listing 2.8 A for Loop with Multiple Initialization and Update Statements
var xsum = 0; for ( var x = 1, lcnt = 0; lcnt < 100; x++, lcnt++ ) { if ( ( x % 5 ) == 0 ) // if x is divisible by 5
2
continue; xsum += x; } // skip it // otherwise, add x to xsum
This usage underlines the fact that both x and lcnt are used only within the body of the for loop. It is also much more compact than its counterpart in listing 2.6. In this example, we need not worry about the logical effect of the continue; we know that both x++ and lcnt++ will always be executed. This is also the most common and useful way to use the comma operator. Finally, there is another form of the for statement that is used exclusively with objects and arrays in JavaScript: the forin statement. We will see how this is used in chapter 4, "JavaScript Objects." Figure 2.5 shows the basic structure of the for, while, and if statements, and the use of the break and continue statements within them. Figure 2.5 : Control statements determine the flow of execution in JavaScript.
Functions
A function is a block of code that has a name. Whenever that name is used the function is called, which means that the code within that function is executed. Functions may also be called with values, known as parameters, which may be used inside the body of the function. Functions serve two purposes. A function is an organizational tool, in the sense that it permits you to perform the same operation without simply copying the same code. The syntax for a function statement in JavaScript is as follows:
function Name ( listofparams ) { body }
The function's Name is given immediately after the function keyword. All function names should be unique, and also should not conflict with any of the statement names which JavaScript itself uses (known as the reserved words). You cannot have a function named while, for
example, and you should not have two functions both named UserHelp. The listofparams is a comma-separated list of the values that are passed into the function. These are referred to as the function's parameters, or arguments. This list may be empty, indicating that the function does not use any arguments (often called a void function). The function's body is the set of statements that make up the function. Listing 2.9 shows a function that adds up all the integers starting at 1 and ending at a value given as the sole argument.
This function does the same task that came up in the discussions of the while and for statements earlier in this chapter. Now that it has been written as a function, this code never needs to be repeated again. Any time you wish to form the sum 1 + 2 + + N, you can simply call the function, as summation(N), and it will perform the task. Notice that the endval parameter is used as the argument to the function. When the function is called, as summation(14) for example, the actual value 14 is used for endval within the function. The function then executes the for statement, with iter < 14 as its termination condition, adding in each successive value into the variable thesum. When the for loop is done, the function executes the return statement. This causes the function to give the value inside the return statement back to the caller. This means that if we write
var sum14; sum14 = summation(14);
the variable sum14 is set to the value returned by the summation function when endval is given the value 14, namely 105. Functions can return any type of value, and are not restricted to returning integers. There are several things to notice about this example. First of all, the variables thesum and iter, which are declared within the body of this function, are local variables. This means that they are only known within the body of this function, and are therefore completely unknown outside it. It is quite possible, even likely, that there are many functions, all of which have a local variable named iter. All these various iters are unrelated. Changing the value of one of these iters would not affect any of the others. This is why the return statement is necessary; it is the only way to communicate the work of the function back to the caller. This same restriction applies to the parameter endval as well. The arguments to a function may not be changed within that function. We could well have written endval = 15 just before the
statement in listing 2.9. This statement would do nothing; it certainly would not change the caller's 14 into a 15. It might seem like every function would always have a return statement. This is not the case, however, since it is possible for a function to have side effects without actually returning a value. This happens by referencing external objects, which are our next topic.
return
Objects
Functions are used to provide a uniform method for organizing code. Objects serve the same purpose for data. Up to this point, the only data items we have seen are simple variables declared with var. Each of these typeless quantities can only hold a single value of some sort at a time. Objects provide the ability to hold multiple values, so that a group of related data elements can be associated with one another. What JavaScript calls an object is called a data structure (or class) in many other languages. As with JavaScript functions, there are two aspects to JavaScript objects: creating them and using them. For the moment, we will defer the question of how to create objects and concentrate on how they are used. We will also see that a JavaScript capable browser will provide a number of its own, built-in objects. A JavaScript object is made up of a set of component parts, which are called its properties, or members. Suppose you have an object named appt which you are using to organize your appointments. The appointment object might have properties that specify the date and time of the appointment, as well as the name of the person with whom the appointment will take place. It might also have a general description field to remind you of the purpose of this meeting. Thus, you can imagine that the appt object will have the following properties:
day month time who why
Each of the properties of the appt object are referenced using the dot operator (.). Thus, appt.month refers to the month property and appt.why gives us the reason for the appointment. These references may appear on both the right and left sides of an expression; we may get their values and also set them. Listing 2.10 shows a code fragment that tests the value of appt and displays a message about a current appointment.
This example assumes that the variable Today has somehow been initialized with today's date, so that the equality test with appt.day is only true for today's appointments. If the test does succeed then the three statements in the if block are executed. Each of these references document.write. The document object is a built-in object of the Netscape Navigator browser. This object has a member known as write, which is actually a function. Functional members of JavaScript objects are known as methods. This particular method takes a string and displays it on the current Web page. Each of the three strings that are passed to document.write are constructed using + as a string concatenation operator. Each of them references one or more properties of the appt object in order to provide meaningful messages to the user. Each also includes <BR>, the HTML construction for a line break. This ability to directly issue HTML directives is one of the most powerful aspects of JavaScript, as it allows the programmer to dynamically modify the contents of Web pages using JavaScript functions and objects. Once you learn more about the Date object, in "The Date Object" section of chapter 5, you will be able to construct a much more satisfying version of this example. Even at this stage, however, the advantage of object-based programming should be apparent. Rather than carrying about many variables, you can use objects instead. Each object can contain all the variables of interest to a particular idea. It can also contain method functions that perform related work. Objects can even contain other objects, so that you can organize your data in a hierarchical structure. Subsequent chapters explore these ideas in much greater detail.
Events and Actions o Navigation Actions and Events o Forms Input and Events o Actions That Are Not Events JavaScript Code in HTML o The SCRIPT Tag o Declaring JavaScript Event Handlers Using JavaScript Event Handlers o Document Level Event Handlers o Submit Event Handlers in the FORM Tag o Event Handlers in FORM Elements
Although HTML pages can be difficult to develop, they are usually very simple to use. The number of things you can do with an HTML page is quite limited. For the most part you simply look at it-read its text, admire its graphics, and, perhaps, listen to the sounds it can play. For many, the Web experience consists of visiting a series of pages without interacting with them. The only interaction occurs when the user selects a link or clicks an imagemap. HTML forms have gradually changed that model to increase the level of interaction. A form can have a variety of ways of accepting input, including text fields, buttons, checkboxes, and multiple choice selections. In this way, HTML forms are a lot like paper forms. The user fills in the form, perhaps to purchase some item, and then submits the form. This submission process also mimics real life. It is difficult to tell if the form has been properly filled in, and the time taken for processing the form is often quite lengthy. In the case of HTML, this processing delay occurs because the contents of the form must be sent across the network to some URL, processed there, and then returned to the user. Even the slightest error causes the form to be rejected, so that the form entry must be repeated. One of the primary goals of JavaScript is to localize most of this process and perform the form validation within the user's browser. It won't be possible to actually submit an order locally, but it will be possible to make sure that the form is properly filled out locally, and thereby avoid forcing the user to redo the form. JavaScript realizes this goal through event handlers. Event handlers are JavaScript statements (usually functions) that are called whenever something
happens. JavaScript functions can be called when a form is submitted, or they can be called whenever the user does anything to the form. If your form requires that a certain field correspond to a number between 2 and 10, for example, you can write a JavaScript function that will validate that field when the user changes it, and complain if the value is out of range. This chapter describes event handling in JavaScript. We discuss all the events that can be handled, as well as the contexts in which these events may arise. In addition, you learn how JavaScript can be included within Web pages, and how JavaScript functions are connected with different components of that page.
Selecting a hypertext link Moving forward or backward in the history list Opening a new URL (possibly in a new window) Quitting the browser
In most of these cases the current page will be unloaded, which means it will no longer be visible in any browser window. In several of these cases a new page will be loaded, which means its contents will be displayed in a browser window, perhaps a new one created specifically to display this particular page. Anyone who has used the World Wide Web realizes that selecting a hypertext link may not successfully take you to another. The machine to which that link points may be down, or simply inaccessible. The link may even be dead, meaning that it does not point to a valid destination. Selecting a dead link often unloads the current page, but doesn't load a new page. Most browsers display a blank page or post an error message. You may or may not be left on the current page, depending on the type of error and the browser being used. A sample error alert from Netscape is shown in fig-ure 3.1.
Figure 3.1 : Attempting to access a non-existent URL results in an error message on some browsers. These events, loading and unloading a page, are the two document level events that can be handled by JavaScript. This means that it is possible to write JavaScript code, contained within the HTML definition of a page, that will be executed whenever that page is loaded. You can also have code that is executed whenever that page is unloaded. The dead link example illustrates the important fact that loading and unloading are two separate, unrelated events. When you attempt to activate a dead link, the current page is unloaded, but nothing is loaded in its place. In order to return to the last valid Web page you must use one of your browser's navigation controls. For example, if you select Back in Netscape the last page you visited is reloaded. There are two additional events that are vaguely related to navigation. These events are the following:
mouseover statechange
When you move the mouse over a hypertext link, a mouseover event is generated. This event is not associated with clicking the link, it is associated with being poised to click it. This event can be used to give the user feedback, such as changing the color of the link or flashing it. The final event is the statechange event. This event has been proposed by Microsoft as part of their planned implementation of an open scripting architecture that will include Visual Basic Script as well as JavaScript. The purpose of this event is to provide staged notifications when a timeconsuming operation is taking place. For example, if a movie player plug-in is being loaded, the statechange event might be issued to indicate the plug-in is ready to accept some user interaction, but cannot yet display its movie.
Simple buttons Yes/No checkboxes Radio buttons Submit buttons Reset buttons
Simple buttons are defined using the HTML <INPUT TYPE="button">. Checkboxes define options, which are either off (not checked) or on (checked). These are created using an <INPUT TYPE="checkbox"> directive. Radio buttons use the <INPUT TYPE="radio"> directive, and permit the user to select exactly one of a set of choices. Submit buttons and reset buttons are very special. Submit buttons, created by <INPUT TYPE="submit">, are used to end input operations on a form. When the submit button is pressed the contents of the form are packaged and sent to the URL target specified in the ACTION attribute of the <FORM> definition. Reset buttons bring the form back to its initial state, wiping out any input the user has performed; they are specified as <INPUT TYPE="reset">. Figure 3.2 shows a simple HTML form with all five button types; it was generated by the HTML file allbut.htm. Figure 3.2 : All five types of HTML buttons have corresponding JavaScript events. TIP Hidden fields on HTML forms do not generate JavaScript events. The one thing the five types of buttons have in common is that you click the button to achieve its effect. Because this is an extremely common action, the JavaScript event model defines click as one of its HTML form events. This event is generated by each of the five button types. In addition, when a form is actually submitted, a submit event is generated. The submit event is really owned by the form being submitted, and not the submit button that causes it. Text Elements in Forms There are three types of text items possible within an HTML form, as follows:
Single line text fields are created with an <INPUT TYPE="text"> directive. Any text you type in a text field is displayed as you type it. This behavior is known as echoing the input. Single line text fields that are created using <INPUT TYPE="password"> do not echo their input. Multi-line text fields are created with the TEXTAREA tag, and are usually called textareas. An HTML form showing all three types of text elements is shown in figure 3.3, created from the file alltxt.htm on the CD-ROM. Interacting with text is more complex than interacting with a button. There are more things you can do with text. You can click in the text field, enter text, edit text, select text, and decide you are finished with the text and move on. Figure 3.3 : HTML text elements generate several different JavaScript events. What are the events JavaScript generates in response to these various actions? JavaScript uses a text manipulation model which will be familiar to anyone who has ever used a windowing system. It defines four events that are associated with text fields and textareas, but not passwords fields-change, select, focus, and blur. The first two should be self-explanatory. The change event is generated whenever any text is changed, and the select event is generated whenever
text is selected. Selecting text is more than simply clicking in the editable text field or textarea. It means actually highlighting a portion of the text with the mouse. NOTE Password fields do not generate JavaScript events. This was a conscious design decision to prevent malicious script code from diverting password text. and blur are a little more involved. A text field or textarea is said to have focus when it is currently accepting input typed at the keyboard. Clicking anywhere inside a text item is certain to give it focus, and simply moving the mouse over the text field may do so as well. blur is the opposite of focus. Blur occurs when the text item no longer has focus. This may happen because some other item now has the focus, or because the focus has simply been lost. You will notice that if you position the mouse over a graphic (other than an imagemap), you can type until your fingers are sore, but nothing happens. This is a case where nothing has focus.
focus
Selection Elements in Forms Selection lists are defined by the SELECT tag; their options are enumerated using the OPTION tag. They operate almost the same as text items; they are capable of generating focus, blur, and change events. Paradoxically, selection lists do not generate select events. You might well wonder why four event types are needed for text and three for lists. This is clarified later in this chapter. Figure 3.4 summarizes the events understood by JavaScript and the HTML elements that generate them. Figure 3.4 : JavaScript events model different types of user interaction with a Web page.
So far we have talked about JavaScript as a language, and we have talked a bit about HTML, but we have not talked about how JavaScript is used in HTML. Event handlers are the glue that link HTML elements with JavaScript code, but how is it done? This section addresses this question. The answer has two parts: how JavaScript is included or referenced in a Web page, and how event handlers are attached to HTML items.
The element LangName gives the language that is used in the subsequent script code; this should be JavaScript. Strictly speaking, the LANGUAGE attribute is not required; at present, Netscape Navigator is the only browser that is widely available and understands any scripting language. Of course, the language it understands is JavaScript. This will certainly change very quickly, so it is a good idea to always include the LANGUAGE attribute. If the SRC attribute is specified then it should reference a URL containing code in the script language. For JavaScript, this should be a valid URL for a file containing the JavaScript code. The filename should have the suffix .js. If the SRC attribute is given then the <SCRIPT> can be immediately terminated by a </SCRIPT> directive. A <SCRIPT> block that loads JavaScript code from a filename click.js in a directory jscode relative to the document base would look like this:
<SCRIPT LANGUAGE="JavaScript" SRC="jscode/click.js"> </SCRIPT>
NOTE
Netscape Navigator 2.0 does not yet support the SRC attribute. This feature has been promised for version 2.1. If the SRC attribute is not given then it is expected that all the code between <SCRIPT> and </SCRIPT> is the script source itself. In the glorious future, when the overwhelming majority of browsers understand the SCRIPT tag, or at least benignly ignore it, the JavaScript source may be given literally. Until then it is recommended that source included between <SCRIPT> and </SCRIPT> be enclosed within the HTML comment delimiters <!-- and -->. A simple example showing a single JavaScript function is shown in listing 3.1. CAUTION Use the C-style comments // and /* */ inside JavaScript code. Never use HTML comments inside JavaScript. Listing 3.1 A JavaScript <SCRIPT> with a Single Function
<SCRIPT LANGUAGE="JavaScript"> <!-function dontclickme() { // an ominous button click alert("I told you not to click me"); return( false ); } <!-- end script --> </SCRIPT>
Use of HTML Comments The function in listing 3.1 does not do much; it merely uses the alert() function to pop up a warning dialog box with its argument as the message. Presumably this function is the click event handler for a button you don't want the user to press. The important thing to notice about this simple example is the paradoxical, but important, use of HTML comments. The entire script body is enclosed with a comment, and the comment close --> is also paired with a second, seemingly redundant, comment start <!-- on the last line. At present, you should structure your script according to the following rules:
Place the comment start (<!--) on a line of its own Follow it with your JavaScript code Terminate the code with <!-- and --> on its own line
You should use this magic incantation not because it makes sense, but because it works. Note that JavaScript code referenced through a SRC URL should also follow these rules, as if it had literally been included in the <SCRIPT> block. Note also that you may have both a JavaScript SRC URL, and literal JavaScript between <SCRIPT> and </SCRIPT>. In this case, the URL referenced by the SRC attribute is read and processed before the literal JavaScript. CAUTION HTML comments are one of the least conforming areas of HTML. Most
browsers deviate a little from the HTML standards, and some deviate a lot. The preceding comment rules may change in the future, and may be implemented differently on different browsers. Processing <SCRIPT> Code There are two important aspects to JavaScript code defined by or within a SCRIPT block. The first important principle is that this JavaScript code is not executed-it is merely read and checked for syntax errors. When the browser sees the code shown in listing 3.1, it does not execute the dontclickme() function, it merely recognizes that this function is a JavaScript function, and saves the definition of that function for later use. This is precisely the opposite behavior of normal HTML. When you say <HR> in an HTML document, you get a horizontal rule. You don't get it immediately, but you do get it when the browser has finished laying out the page (assuming that there are no HTML errors, of course). This is the way that most interpreted languages work, however. If you create a Sub in BASIC, a defun in lisp, or a proc in Tcl, it is not executed when it is read. Instead, the interpreter parses it, which means that it scans through the function looking for obvious syntax errors, such as unbalanced parentheses, and records the function's definition for later use. The function is only used when it is called. In JavaScript, functions can only be called by events. Binding in JavaScript Another critically important aspect of JavaScript is that it carries out dynamic binding. Binding refers to the way in which names of things, such as variable names, function names, and object names, are associated with the things themselves. If you call the function dontclickme from listing 3.1 by saying dontclickme(), you are not actually referring to the function itself, you are referring to the name of the function. "The Song of the Volga Boatmen" is really the name of that song, it is not the song itself. If you want the sheet music, you go to you favorite music store and ask for it by name; most people do not go in and begin singing "Eh-eh uxhnyot." There are two general approaches to binding: static binding and dynamic binding. Many languages, particularly compiled languages like C, C++, and Java, often insist on static binding. This means they require that they be able to find all named references when a program is compiled. (Of course, with the advent of dynamically loaded libraries this rule is relaxed a bit.) JavaScript uses the more liberal form, dynamic binding. JavaScript only attempts to resolve names when they are used. Dynamic binding has several consequences. In the first place, if the function dontclickme() is never called, then it can contain all but the most hideous syntax errors and they will never be found. If dontclickme is the event handler for a button, and no one ever presses the button, its problems are never exposed. Even if dontclickme() is absolutely perfect, but the event handler is erroneously declared to be a function named noclickme(), this mismatch will not be detected until someone finally chooses to press the button. JavaScript will only then try to find a function named noclickme(). It will fail, and an error will result. Dynamic binding is often called runtime binding or late binding because the binding process only takes place when the JavaScript interpreter attempts to run the code.
TIP Always check meticulously to ensure that the function, object, and variable names used in HTML match those in the JavaScript code. Dynamic binding has its advantages and disadvantages. Dynamic binding is used by many interpreters because it simplifies the language, and makes it very easy to add in new functions. Since there is no brooding and melancholy compiler to satisfy, it is possible to build up a complex JavaScript application incrementally. Even if you really need an event handler for every possible event, you can start out with one or two handlers, make them work, and then gradually add more complexity. The disadvantage of dynamic binding should be clear from the previous discussion. There is very little error checking. When the JavaScript interpreter is read-ing all the code in the SRC URL, or processing the code between <SCRIPT> and </SCRIPT>, it is performing some checking but it is by no means performing an exhaustive analysis of the code. Errors, particularly mismatched names, are not found until the erroneous code is executed. To see a more complete example of this, look at the HTML page defined in listing 3.2.
If you copy this code, found in ex32.htm in the js directory on the CD-ROM, into a local file, change the e-mail address in the form's ACTION to your own e-mail address, and then read that file into your browser, everything will be fine. Notice that the click event handler for the button is declared using the HTML attribute onClick="dontclickme()", which tells JavaScript that when this button is pressed the function dontclickme should be called. (The exact syntax for declaring event handlers is discussed in the next section.) If you now click that button you should see something like figure 3.5. Figure 3.5 : Clicking an HTML button invokes a JavaScript event handler that displays an alert.
So far so good. The name of the event handler in the HTML statement that created the button matched the name of a JavaScript function in the SCRIPT block. Now try the following experiment. Change the handler declaration from
onClick="dontclickme()"
to
onClick="noclickme()"
and then read that file into your browser. You will notice that the initial appearance of the HTML page is exactly as before. No errors have been reported. If you attempt to click the button labeled HA!, your browser reports an error, and the alert dialog box shown in figure 3.5 does not appear. This is dynamic binding at work. JavaScript did not know that the function named noclickme did not correspond to any currently defined function until the user action forced it to try to find one. Technically, the function name noclickme is said to be unbound. It might seem like dynamic binding is a great potential source of error, without providing many benefits as compensation. As you will see when we discuss objects in chapter 4, "JavaScript Objects," objects may be defined and even modified on-the-fly. Dynamic binding allows you to refer to things that do not yet exist, but that will exist when the event handler which uses them is actually called. Dynamic binding, like the loose typing provided by JavaScript's var, is a twoedged sword. It must be used with care, but is very powerful. Let's summarize these two critical points about JavaScript parsing and execution, since they will dominate our thinking for several chapters to come:
JavaScript code is parsed when it is seen in a SCRIPT block; it is only executed when an event occurs. JavaScript names are resolved when they are executed, not when they are parsed.
Attribute names are not case-sensitive, following the usual HTML convention. It is good practice, however, to use the coding style shown in the preceding line of code, with on in lowercase and the event name with an initial capital. This helps to distinguish it from other attributes, which are often fully capitalized. The value of the attribute is a set of JavaScript code. The code may be included literally (known as inline JavaScript), or it may reference a JavaScript function. We can completely remove the dontclickme() function of listing 3.2 and write the button statement as
<INPUT TYPE="button" NAME="mycheck" VALUE="HA!" onClick="alert('I told you not to click me');">
This has two disadvantages. First, it tends to lead to very long HTML statements. There is very little you can accomplish in only a few characters. If you have hundreds of characters between the opening (<) and the closing (>) of an HTML statement it will almost certainly be very hard to read, and, if it is too long, may cause your browser to choke. It is also not modular. As you add event handlers for different HTML elements, you may well find that there is a lot of common code. Each of the button handlers might use a variation on the same code. Such common code should always be encapsulated in a JavaScript function, rather than being repeated in several places. TIP Declare all event handlers as JavaScript functions. Avoid inline JavaScript code. One thing to notice about this example is the fact that the value of the onClick attribute is a quoted string. This follows standard HTML convention. Therefore, to include a string within the value of the attribute we must alternate single quotes (') with double quotes ("). This follows the JavaScript standard for strings, as we learned in the "Implicit Data Types in JavaScript" section of chapter 2. If you modify the dontclickme function to accept a string argument then you must carefully use quotes when passing in literal strings. Listing 3.3 shows a modified version of dontclickme, called donteventme, and the HTML event handler declarations which reference it. It can be found in the file ex33.htm on the CD-ROM.
Listing 3.3 ex33.htm A JavaScript Function Can Be Shared by Several Event Handlers
<HTML> <HEAD> <TITLE>An Uncooperative JavaScript Page</TITLE> <SCRIPT LANGUAGE="JavaScript"> <!-function donteventme( str ) { // generic diffident handler alert("I told you not to " + str + " me"); } <!-- end script --> </SCRIPT> </HEAD>
2
<BODY> <FORM METHOD="post" ACTION="mailto:[email protected]"> <BR>No<INPUT TYPE="checkbox" NAME="mycheck" VALUE="HA!" onClick="donteventme('click')"> <SELECT NAME="mysel" onChange="donteventme('change')"> <OPTION SELECTED>Nope</OPTION> <OPTION>Not Me</OPTION> <OPTION>No Way</OPTION> </SELECT> </FORM> </BODY> </HTML>
In this example, the function donteventme is called whenever the checkbox is checked or any selection is made on the selection list. The alert function within the donteventme constructs an uncooperative message based on the function's string argument str. Although this example accomplishes no useful work, it is a perfect template for a JavaScript page. In general, a JavaScript page has the following three components:
JavaScript functions inside a SCRIPT block within the <HEAD> of the document Non-interactive HTML within the document's <BODY> Interactive HTML with event handler attributes whose values are JavaScript functions
You now know how to declare event handlers in general. The next section shows exactly which handlers can be associated with specific HTML tags, and gives various examples of how these event handlers are used. CAUTION Netscape Navigator 2.0 has a bug that can prevent JavaScript event handler code from being triggered. This occurs most often if an IMG directive is given without corresponding WIDTH and HEIGHT attributes. Make certain that you include these attributes if you are using images together with JavaScript.
the page. The BODY tag can contain two event handler declarations using the onLoad and onUnload attributes. A JavaScript page might have a BODY declaration that looks like
<BODY onLoad="loadfunc()" onUnload="unloadfunc()">
The onLoad="loadfunc()" attribute declares a JavaScript handler that will handle the load event. The load event is generated after the entire contents of the page, namely the HTML between <BODY> and </BODY>, has been read, but before it has been displayed. The onLoad event handler is an excellent place to perform any one time initialization. It can also be used to display a splash screen containing company, product, or copyright information. It can even launch a security dialog box which permits only authorized users, with an appropriate password or key, from completely loading the page. The onUnload="unloadfunc()" attribute declares an event handler that is invoked whenever the page is unloaded. This happens when the user executes any action that brings up a new page in the same browser window. An unload event does not occur if a new page is opened in a new window. Even if a new page is not successfully loaded, the current page is still unloaded, and the unloadfunc is called in that case. An onUnload event handler can be used to ensure that there are no loose ends, and to perform any cleanup necessary. For example, if the user has filled out a form, but has failed to press the Submit button, the onUnload handler should inform the user of that fact. It could even submit the form itself based on the user's response. Note that both the onLoad and onUnload handlers are optional. There is one final document level event handler, although it is not associated with the BODY tag. Any HTML link can declare an event handler for the mouseOver event, which occurs when the user places the mouse over the HREF of that link. This can be used to achieve a visual effect, or to perform some special processing before the user actually tries to access the link. Listing 3.4 shows a slightly fanciful example. This code can be found in the file ex34.htm on the CD-ROM. CAUTION In the current implementation of JavaScript, links have event handlers, but anchors do not. This means that you must catch navigation events by attaching event handlers to links. If any of your links point to anchors in the same document, the event must be handled at the link, not at the anchor. Listing 3.4 ex34.htm Using the mouseOver Event to Mediate Access
<HTML> <HEAD> <TITLE>A Nationalist JavaScript Page</TITLE> <SCRIPT LANGUAGE="JavaScript"> <!function warnthem( lnk ) { // mouseOver event handler var theirhost = lnk.hostname; // 2; get hostname of link var domain = "", lastdot = 0, len = 0; len = theirhost.length; // 4; string length of hostname lastdot = theirhost.lastIndexOf("."); // 5; find last dot
2
domain = theirhost.substring(lastdot+1, len); // 6; last part of hostname if ( domain == "zz" ) { // 7; warn about country "zz" alert("Country zz only has 1200 baud modems"); }
} <!- end script -> </SCRIPT> </HEAD> <BODY> <HR> Check out the new links to <A HREF="http://home.std.zz" onMouseOver="warnthem(this)">Zzland</A> and its neighbor <A HREF="http://home.xyzzy.xy" onMouseOver="warnthem(this)">XYville</A> <HR> </BODY> </HTML>
This HTML creates a page with two elements-links to the fictitious home pages of the countries Zzland and XYville, and sets up a mouseOver event handler for those links. Note that the event handler function warnthem is called with an argument this. The special keyword this is used to refer to the current object. When the warnthem function is called, its parameter lnk is filled in with the object that represents the link over which the mouse just moved. Statement 2 extracts the hostname part of that object, which in this example could be either home.std.zz or home.xyzzy.xy, depending on where the mouse is located. The next three statements use some of the string object functions (see "String Content Methods," in chapter 4) to tear off the last part of this fully qualified hostname, namely zz or xy, and save it in the variable domain. This variable is then tested against zz in statement 7. If the test passes then an alert is put up to warn the user that the connection to the zz home page will take longer due to slow modems. Links can also have click event handlers, so this code can be modified not only to warn the user, but also to abort the connection, if necessary. The result of placing the mouse over the Zzland link is shown in figure 3.6. Figure 3.6 : JavaScript event handlers can be used with any hypertext links.
TIP Put event handler attributes last on the attribute list of an HTML tag. This
makes them easy to find and modify during debugging. The onSubmit handler is invoked when the form's contents are about to be submitted. This is a top level action that applies to the entire form. It is also possible to specify an onClick action on the Submit button in a form, as you shall see later in the section, "Button Click Events." The natural use of an onSubmit handler is to validate the contents of a form. The submission proceeds if the contents are valid, and is canceled if they are not. CAUTION If you return false in an onSubmit event handler using UNIX version 2.0 of Netscape Navigator, it does not cancel the submit. Listing 3.5 (file ex35.htm on the CD-ROM) shows a very simple form with a single element, an editable text field. The value of the field is supposed to be a number between 1 and 9. The submit handler function checkit is called when the form is submitted. It validates the userentered quantity and acts accordingly.
Listing 3.5 ex34.htm Form Content Can Be Validated Using an onSubmit Handler
<HTML> <HEAD> <TITLE>A Simple Form Validation Example</TITLE> <SCRIPT LANGUAGE="JavaScript"> <!-function checkit() { // submit validation function var strval = document.myform.mytext.value; // 2; input text value var intval = parseInt(strval); // 3; convert to integer if ( 0 < intval && intval < 10 ) { // 4; input ok return( true ); // 5; allow submit } else { // 6; input bad - tell user alert("Input value " + strval + " is out of range"); return( false ); // 8; forbid submit } } <!-- end script --> </SCRIPT> </HEAD> <BODY> <HR> <FORM NAME="myform" METHOD="post" ACTION="mailto:[email protected]" onSubmit="checkit()"> <P>Enter a number between 1 and 9: <INPUT TYPE="text" NAME="mytext" VALUE="1" SIZE="10"></P> <BR><INPUT TYPE="submit"> </FORM> <HR> </BODY> </HTML>
It is worthwhile to examine this example in some detail, as it exposes a number of points that are more thoroughly discussed later in this chapter. Let us consider the HTML in the <BODY> first. The FORM statement creates a form named myform with a fictitious mailto: destination. It also contains an onSubmit attribute that specifies checkit() as the JavaScript function to call when the form is about to be submitted. Like all of our previous event handlers, this one takes no arguments. You will see very shortly that it is not only possible to pass in arguments, but it can also be very beneficial. For a document this simple, however, it is not necessary. The first INPUT tag establishes an editable text field named mytext which can hold up to 10 characters, and which will be initialized to the string "1". The second INPUT tag puts a Submit button just below the input text field. Neither of these INPUT statements have any handler attributes, although they could. What happens next? If the user types in any text, or does anything except press the Submit button, then nothing special happens. This example does not process any events other than the submit event, so changes in the text field or navigation actions do not result in any JavaScript code being executed. If the user does press the Submit button, then the myform form tries to submit itself. This triggers the submit action, which results in its event handler, checkit(), being called. The checkit function does two somewhat obscure things. In statement 2, it sets the local variable strval equal to the value of document.myform.mytext.value. We know from the "Functions and Objects" section of chapter 2 that the right side of this expression must be an object reference-in fact, a reference to an object within an object within an object. It is reasonable and correct to assume that the myform subobject corresponds to the HTML form named myform within the current document, and that the mytext subobject corresponds to the HTML editable text field named mytext inside myform. This windy construct transfers the value of that text field into the local variable strval. In statement 3, an attempt is made to convert this string to an integer using the built-in function parseInt. The putative integer is stored in intval. In statement 4, our validation test is performed. If the string in the text field did represent an integer between 1 and 9 inclusive then this if test passes and the checkit function returns true, in statement 5. This is a message from JavaScript to the browser that the submission may complete. If the text field was out of range then the else pathway in statement 6 is taken. Note that parseInt returns 0 if its argument cannot be parsed as an integer. This means that if the user entered "five" in the text field rather than "5" the value of intval will be 0, and the else clause will be taken. Statement 7 puts up an alert dialog box telling the user that the value was out of range. It contains the string representation of the value. This is useful since the alert dialog box may be inadvertently positioned over the text input field. Finally, statement 8 returns false, indicating that the submit operation should not complete. The outcome of entering a value that is out of bounds is shown in figure 3.7. Figure 3.7 : JavaScript submit handlers are often used to validate form input.
In this particular case it is important to give the mytext text field an initial value of 1. This ensures that if the user clicks the Submit button without altering that text field it will have an acceptable value, and the form will be submitted. In many cases, just the opposite is true. The whole point of a catalog order form is to persuade the user to enter critical information, such as his name and e-mail address. In this case, it's a good idea to initialize the text field with a deliberately invalid value, so that if the user hits Submit without typing anything the form is not submitted. Chapters 6, "Interactive HTML Objects," and 16, "Creative User Interaction," provide several more sophisticated examples of customized user interaction using JavaScript. NOTE Always give the user meaningful feedback on inappropriate input or other error conditions. Indicate why and where the error occurred, not just that an error occurred. Be brief, but specific. N
standard HTML there is no way to perform input validation of this kind without actually submitting the form and asking the ACTION URL if that particular combination is acceptable. JavaScript event handlers are ideal for this kind of validation. As you learn in chapter 4, every HTML form element is also a JavaScript object. You have already seen some examples of this in listings 3.4 and 3.5. Listing 3.6 shows two radio buttons working together with a checkbox using a JavaScript onClick event handler. The code for this listing can be found in file ex36.htm on the CD-ROM. The initial appearance of this form is shown in figure 3.8. Figure 3.8 : JavaScript onClick handlers can be used to exclude invalid user input.
Listing 3.6 ex36.htm Values of Different Form Elements Can Be Accessed in JavaScript
<HTML> <HEAD> <TITLE>Two Choices Work as One</TITLE> <SCRIPT LANGUAGE="JavaScript"> <!-function insok() { // make sure payment & ins choices are compatible var isgold = document.myform.payment[1].checked; // 2; gold checked var isins = document.myform.insurance.checked; // 3; insurance elected? var ok = null; // 5; if paying in gold without insurance then.. if ( isgold == true && isins != true ) { ok = confirm("Do you want insurance?"); // 6; ask for insurance if ( ok == true ) { // 7; yes, get insurance document.myform.insurance.checked = true; // 8; check it } } <!-- end script --> </SCRIPT> </HEAD> <BODY> <HR> <FORM NAME="myform" METHOD="POST" ACTION="mailto:[email protected]"> <STRONG>Payment Options</STRONG><BR> <HR> <INPUT TYPE="radio" NAME="payment" VALUE="1" CHECKED onClick="insok()"> Personal Check <INPUT TYPE="radio" NAME="payment" VALUE="2" onClick="insok()"> Gold Bullion <HR> <INPUT TYPE="checkbox" NAME="insurance" VALUE="Ins"> Insurance? </FORM> <HR> </BODY> </HTML>
The <BODY> of this page sets up a two-choice radio button named payment, and a checkbox named insurance. The first button is selected, and the checkbox starts off unchecked. The radio
button group has the function insok as its click event handler. Whenever either of the buttons is clicked the insok function is called. In statements 2 and 3 insok fetches the current value of the second radio button named payment. Note that payment actually denotes the entire group of buttons, not any single radio button, so that you must use the array reference payment[1] in order to refer to the second button (0 based indexing is used). That value is stored in the boolean variable isgold. The variable insok gets the state of the insurance checkbox, which is also true if it is checked and false if it is not. A compatibility test is now performed in statement 5. If the radio button group indicates payment in gold bullion, but the insurance button is not checked, then a confirmation dialog box is put up using the confirm() function in statement 6. The confirmation dialog box has OK and Cancel buttons. If the user presses OK, the function returns true; otherwise it returns false. The return value is tested in statement 7. If it was true, then the user does want insurance, and the method function value of the checked property of the myform.insurance object is set to true. Without worrying too much about what methods and properties really mean just yet, it is easy to infer that this assignment statement has the same effect as a click of the insurance button. That checkbox is now checked. TROUBLESHOOTING I modified the code shown in listing 3.6. I added another group of radio buttons to collect information about the user's income level, with its own event handler doinc(). I would like to force the insok() function to be called from the new event handler. Inside doinc() I have a statement
myform.insurance.click();
This click() function is supposed to cause the insurance checkbox to be checked, but the doins() handler is never called. Why? JavaScript has many functions like click() that emulate user actions. These emulated actions do not generate events, however, so the corresponding event handler functions are never called. There is nothing mystical about the event handler function insok()-it is an ordinary JavaScript function that happens to be linked to an HTML event. If you want to call insok() in your doinc() event handler, just do the following:
insok();
Text Edit and Selection Events HTML text <INPUT> fields with a TYPE attribute of "text" may declare event handlers for any combination of the four text events: focus, blur, change, and select. Multi-line text input items created with a TEXTAREA tag may also have these handlers. Selection lists created with <SELECT> can generate all these events except select. The focus event is generated when the text item of a list element gets the input focus, usually as a result of a mouse click. Tabbing through form fields also moves the input focus. The blur event is generated when an item which had focus looses it. The change event is generated whenever something changes. In a text item this results when any new text is entered or existing text is deleted. In a selection list it happens whenever a new selection is made, even in a list that
permits MULTIPLE selections. The select event is generated when the user selects some text, usually by click-and-drag or double-click operations with the mouse. The select event is almost always accompanied by a visual cue, usually by the selected text becoming highlighted or changing color. These events can be used to obtain very fine control over the content of text or selection list items. The most common application is to use the change or blur events to ensure that a text field has an appropriate value. If you ask the user to enter her birthdate, for example, and provide separate fields for the month, day, and year, you will almost certainly want to make sure that the value of the day field is a number between 1 and 31. You might even go to greater lengths, and limit the day field's value based on the value of the month field. In any case, you want to avoid erroneous input such as "bleen." Text events can also be used to coordinate the values coming from multiple form elements, as we saw in listing 3.6. Listing 3.7 (file ex37.htm on the CD-ROM) shows a linguistic application of the blur event for a TEXTAREA. The user is inspired to enter a sentence without a single instance of the letter e. If the user tries and fails he is chided for his lack of creativity. Note that the blur event handler is only called if the user makes an attempt, since blur is only generated when focus is lost. If the user never clicks or types in the TEXTAREA no blur event occurs. Parts II and IV of this book provide many more detailed examples of all the JavaScript events.
2
<HR> <FORM NAME="myform" METHOD="POST" ACTION="mailto:[email protected]"> <TEXTAREA NAME="mytarea" ROWS="5" COLUMNS="80" onBlur="hasE()"> </TEXTAREA> </FORM> <HR> </BODY> </HTML>
The modulus operandi of this example should be becoming familiar to you now. If the user types or clicks in the textarea nothing happens. When he leaves the textarea and clicks elsewhere a blur event is generated and the handler function hasE invoked. This function gets the contents of the textarea into a local variable named thestr (in statement 2) and then uses one of the string functions to convert it to lowercase (statement 3). This saves a little time, as the function won't have to test for the presence of both e and E. The new lowercase string uthestr is tested against the empty string in statement 4. If there is no text the function returns without complaint. If there is some text, but it has an e the user is reprimanded in statement 8. If there is no e but the text has less than 20 characters the user is encouraged to try a more ambitious work in statement 11. If the text is long enough and has no e then the user is praised in statement 13. Of course, there is nothing preventing the user from entering gibberish such as zzzzzzzzzzzzzzzzzzzzzzzzz and being congratulated anyway. Much more sophisticated checking would be necessary to ensure that the input was actually a sentence.
Objects, Properties, and Methods in JavaScript o Object-Oriented Programming Concepts o Defining Your Own Objects: The new Statement o Objects as Arrays o Using Variable Length Arrays and Extended Instances o The forin Statement o Method Functions and this o Nested Objects o The with Statement o Functions with a Variable Number of Arguments Built-In Objects o String Objects o The Math Object o The Date Object o Built-In Functions Browser and HTML Objects o Browser Objects o HTML Objects
The idea of object-oriented programming is not a new one. It actually dates back over 30 years, and has gone through several phases of popularity in that time. Currently, object-oriented programming is considered by many to be an established concept that should be part of all modern programming languages. There are several different conflicting definitions of objectoriented programming. Fortunately, there are some key concepts that are shared by (almost) all versions of objected-oriented programming. At its most basic level, object-oriented programming is a style of programming in which related concepts are grouped together. If you have five data elements and three functions that manipulate those elements, then you group those elements and functions together into a generic container known as an object. This is the common ground shared by (almost) all object-oriented programming languages. Differences arise in the details of how such containers are organized, and in how their contents can be accessed and modified.
An analogy can be made between home ownership and object-oriented programming. Everyone's house has a kitchen, some bedrooms and bathrooms, stairs, flooring, and so forth. Some homes have spiral staircases, Art Deco ironwork, and a gazebo in the back yard. Others have a completely utilitarian layout based on a linear architecture with not a rounded corner in sight. When talking about your home, you describe both the basic aspects ("yes, of course we have a basement") and also the embellishments ("the basement has a painfully hard cement floor"). When talking about what an object means in JavaScript, it's necessary to also talk of two levels. The basic aspects of the way JavaScript handles objects is known as its object model. The embellishments constitute the extensive set of features of the predefined objects in JavaScript, as well as those aspects of the language that can be used to create and use new, user-defined objects.
and an instance of an object is the same as the relationship between a data type and a variable of that data type. In the typeless language such as JavaScript, this distinction is blurred but is still present. Another way to think of this distinction is to think of an object as a set of shelves, some of which may be occupied while others are not. You convert that object into an instance when you completely fill in all the empty shelves. While the object Date is an abstract thing that does refer to any specific date, an instance of the Date object must refer to some specific date. Its empty slots, which specify the actual day, month, year, and so forth, have all been assigned specific values.
To define an object to hold this information, we write the function shown in listing 4.1. Note that this function makes use of the extremely important keyword this, which always refers to the current object. In this case it refers to the current object we are creating.
There are several things to notice about this object definition. First of all, the name of the function is the name of the object: house. Second, this function does not return anything. When functions were first introduced in chapter 2, it might have seemed mysterious how a function could actually do useful work without a return statement, since everything inside a function is local. Using a function to create an object works by modifying this, so that it need not return anything. You can also have the function return(this). Using this explicit return statement has the same effect as the code shown in listing 4.1.
This example shows how a house object is defined. It does not create a specific house instance. The house object has four slots to hold the four properties rooms, style, yearbuilt, and hasgarage. A specific house instance will fill those slots with actual values. Instances are created using the new statement combined with a function call. The keyword new is required, since it tells JavaScript that we are creating an instance rather than just calling a function. We could create an instance of house, named myhouse, as follows:
var myhouse = new house( 10, "Colonial", 1989, true );
Note that the instance myhouse is treated just like any other variable. It must be declared using var. Now that myhouse has been created we can refer to its properties using the dot operator (.). myhouse.rooms has the value 10, myhouse.style is the string "Colonial," myhouse.yearbuilt is 1989, and myhouse.hasgarage is the boolean value true. The fact that rooms and yearbuilt are integers, style is a string, and hasgarage is a boolean is only implicit, of course. There is nothing stopping us from creating a house instance in which the hasgarage property has the string value "yes" rather than a boolean value. Care must be taken to avoid this kind of type confusion. NOTE Object properties are typeless, just like all other variables in JavaScript. The new operator does not protect you against inadvertently assigning an inappropriate value to a property.
Objects as Arrays
Many programming languages support array data types. An array is an indexed collection of items all of which have the same underlying type. In C or Java, for example, we can say int iarr[10]; which defines a collection of 10 integers. These integers are referred to as iarr[0] through iarr[9]. These two languages use zero-based indexing, which means that the first element of the array is at location 0 and the last element of the array is at one less than the length of the array-9 in this case. Other languages have one-based indexing, in which the elements range from 1 up to the length of the array. This might seem more intuitive, but zerobased indexing is actually the more common form. JavaScript also has arrays that use zero-based indexing. In JavaScript, however, arrays and objects are really two views on the same concept. Every object is an array of its property values, and every array is also an object. Our myhouse instance, for example, is an array with the following four elements:
myhouse[0] myhouse[1] myhouse[2] myhouse[3] = = = = 10; "Colonial"; 1989; true; // rooms // style // yearbuilt // hasgarage
There might not seem to be a lot of advantage to referring to objects in this more numeric and less informative manner. You have to remember which index corresponds to which property.
However, this alternate form of access makes it possible to access the properties sequentially, rather than by name, which is sometimes very useful. If we know that house objects always have four members then we can write the function shown in listing 4.2 to display the property values.
If we call this function as showhouse( myhouse ) the four properties of the myhouse instance are displayed. This function must be called with an instance, not an object. It would be an error to try showhouse( house ). Since there are several alternative ways of writing it, we will revisit this function when we have learned more about methods and the forin statement. One deficiency of the showhouse function should strike you immediately. It relies on the implicit knowledge that every house instance has exactly four properties. If we were to augment the definition of a house object by adding a property known as taxrate (a floating-point number describing the current real estate taxation rate on the house), then the showhouse function would need to be modified to increase the loop count in the for statement from 4 to 5. If we neglect to do so then the showhouse function would only print the first four properties, and would never print the taxrate. An even more disastrous error would occur if we defined the house object to have only three properties, but forgot to drop the loop count to 3; then the reference to somehouse[3] would refer to a nonexistent array member. This type of error is known as an out of bounds error, since it refers to an array element that was not within the boundaries of the array. There is a very simple way to avoid this problem and write the showhouse function in a more general manner. TIP Define all objects with a length property, which gives the number of properties in the object. Make the length property the first property. Using the preceding tip, we can rewrite the definition of the house object to include a length property as the first property, and then generalize the showhouse function to be completely independent of any prior knowledge of the house object. This code for the new house object and showhouse function is shown in listing 4.3. This code can be found in the file house1.js on the CD-ROM.
Listing 4.3 house1.js A Better house Object That Knows Its Own Length
2
/*
This function creates a house instance whose first property, at array index 0, contains the number of properties in the house instance.
*/ function house ( rms, stl, yr, garp ) { this.length = 5; // four informative properties, and this.rooms = rms; // rooms this.style = stl; // architecture style this.yearbuilt = yr; // year constructed this.hasgarge = garp; // does it have a garage? } /* */ This function displays a house instance using its length property to determine how many other properties to display length
function showhouse( somehouse ) { // display properties of a house instance var nprops = somehouse.length; // number of properties for( var iter = 1; iter < nprops; iter++) {//iterate over all properties except length document.write("<BR>Property " + iter + " is " + somehouse[iter]); } document.write("<BR>"); }
This house object function takes four parameters, as before. It sets its length property to this number plus 1, since there are four meaningful properties (rooms, style, yearbuilt, and hasgarage) and the length property itself. Each of the meaningful properties have moved up 1, so that if we say myhouse = new house( 10, "Colonial", 1989, true) the array representation of myhouse becomes
myhouse[0] myhouse[1] myhouse[2] myhouse[3] myhouse[4] = = = = = 5; 10; "Colonial"; 1989; true; // total # of properties // rooms // style // yearbuilt // hasgarage
The showhouse function starts by looking at the length property and uses that to set the termination condition for the for loop. The constant 4 of listing 4.2 has been replaced by the variable nprops which holds the length of the myhouse array. This version of showhouse only prints the properties of interest; it does not print the length property. This is why the for loop begins at 1 rather than at 0. The property myhouse[0] is the length property. This use of the length property is a typical example of the true nature of object-oriented programming. One of the fundamental ideas in object-oriented programming is the idea of encapsulation, which is a long-winded way of saying keeping related things in the same place. In the previous definitions of house and showhouse (see listings 4.1 and 4.2), the length of the house object was present in two places. It was implicitly present in the definition of house itself,
and it was also present explicitly, as the upper limit in the for loop. The doctrine of encapsulation says that this is bad. The length of an object should only be stored in one place-in the object itself. By the same token it might be argued that the showhouse function should really be part of the house object, too. The "Method Functions and this" section later in this chapter describes how to do this. Despite the power of this technique, it might still seem less than obvious to refer to properties by index rather than by property name. JavaScript provides a third technique, which is a hybrid of the dot style (.) and the array style ([]). Object properties may be referred to not only as indexed array elements but also as named array elements. This type of array is known as an associative array. The set of properties of the myhouse instance could also be listed as
myhouse["length"] = 5; myhouse["rooms"] = 10; myhouse["style"] = "Colonial"; myhouse["yearbuilt"] = 1989; myhouse["hasgarage"] = true;
CAUTION JavaScript arrays can be accessed by integer index or by property names. Property names are case-sensitive. Integer indices are limited by the length of the array. If you refer to non-existent array elements, by name or by index, it either generates a JavaScript error or gives you an invalid value.
and yourhouse are both instances of the house object. Both result from filling in the four slots in the house template with four specific pieces of information that define myhouse and yourhouse (as well as the fifth, hidden piece of information, the length). It is possible to dynamically extend an instance by simply tacking on a new property. If you feel the need to also record the fact that your house has two tool sheds and a gazebo you can write
myhouse yourhouse.sheds = 2; yourhouse.hasgazebo = true;
These two statements add two new properties to the end of the yourhouse array. The sheds (integer) property is yourhouse[5] and the hasgazebo (boolean) property is yourhouse[6]. Dynamic extensions only apply to specific instances. The myhouse instance is not affected, nor is the house object changed in any way. If we execute showhouse( myhouse ) it prints out exactly the same as it did before. If we create a third house named pizza
2
pizza = new house( 3, "Restaurant", 1993, false );
it will not have either a sheds property or a hasgazebo property. Figure 4.1 illustrates the relationship between the house object and its various instances. Figure 4.1 : Instances inherit their structure from the underlying object, but can also be extended. NOTE Dynamic extensions are completely local to a particular instance. The underlying object and all other instances-past, present, and future-are not affected. There are some situations in which dynamic extensions are absolutely essential, and dramatically simplify programming. For the most part, however, dynamic extensions should be used with great care, as they can be the source of numerous errors. In fact, we have already made one such error, which shows itself if we attempt to execute the function showhouse( yourhouse ). Since the length element of the yourhouse instance has not been modified, it still has the value 5, so that only array elements 1 through 4 (properties "name" through "hasgarage") are displayed. The two new properties will not be displayed. When we added sheds and hasgazebo, we should have also said
yourhouse.length += 2;
to account for the two new properties in this instance. This is precisely the type of error that is easy to make. In general, it would be much better for the house object to always have sheds and hasgazebo properties, which are seldom used, than to randomly glue them on. The most efficient way to do this is discussed later in the "Functions with a Variable Number of Arguments" section of this chapter. The one common case where dynamic extension is extremely useful is in variable length arrays. Since object properties are just array elements, and since these elements can be referred to using a numerical index, it is easy to write an object creation function that creates an array of arbitrary size and content. The function in listing 4.4 can be used to define an object that is an array of strings. The number of strings in the array is the first argument, and the initial value for each element is the second argument.
it creates an instance with 101 properties. The first, at index 0, is the all-important length property. The next 100, at indices 1 through 100 inclusive, are initialized to the string "spoon." Presumably at some point in the future these 100 strings will be set to some other, less uniform values. It is important to initialize all the properties values to something (the empty string "" would do in this case). If we later find that we need more than 100 strings we do not need to create a new, even longer, stringarr instance. Instead we can dynamically extend the array to include these new strings. It is essential that the length property be updated in this case, as there is no other way of determining how many elements are in the array, short of counting them with a for...in loop (see the following section). The following statements add three new strings and update the length:
mystringarr[101] = mystringarr[102] = mystringarr[103] = mystringarr.length "I'm"; "doing"; "laundry"; += 3;
In the for...in statement varname is the name of a variable that takes on the successive property names of the object objname. This form of the for statement also permits the varname to contain a var declaration. Using the for...in statement we can write yet another form of the showhouse function, which does not rely on the presence of a length property. This function is shown in listing 4.5. This version actually works on any instance or object, not just on instances of house, so it has been renamed showany. This function can be found in the file showany.js on the CD-ROM.
Listing 4.5 showany.js A Function That Displays the Properties of Any Object
function showany(anyobj) { or object for( var iter in anyobj ){ // display properties of an instance // iterate over all properties
2
document.write("<BR>Property " + iter + " is " + } document.write("<BR>"); anyobj[iter]);
This version of the instance creation function house not only has the usual four pieces of house information (rooms, style, yearbuilt, and hasgarage) and the length property, which gives the number of properties, it also has a final property named show, which is set equal to the function mshowhouse (it has been given a new name to emphasize that it is now a method function). Note that we did not count this method in the length of the property array (although we could have). The method version of the showhouse function is shown next. It does not have any arguments. Instead, it refers to its enclosing object as this. The usual for loop works as before. Since we have deliberately shortened the length property by one, only the properties with indices 1
through 4 are displayed. We have used both a dot style (.) reference and an array style ([]) reference with this, which acts just like any normal instance. If we execute the show method on the myhouse object, a display something like figure 4.2 appears. Figure 4.2 : Method functions can be used to display the properties of their instances. Since this function takes no arguments, you might wonder how it is used. The answer is that since the show method is a property just like any other property it may be accessed in the same way. The statements
myhouse.show(); yourhouse.show(); pizza.show();
This particular method function took no arguments, and was also void; it does not return any value. Method functions can take as many arguments as you wish, and can also return values. Listing 4.7 shows a very simple method function that takes the current year and an argument, and returns the age of the house as its value. It checks the argument for validity and returns -1 if the current year is actually earlier than the yearbuilt property.
This method must be added to the object defining function house in order for it to work, of course. This function would be called by a standard property reference such as
myhouseage = myhouse.howold( 1996 );
This type of function call is no different than a standard function call such as showhouse( myhouse ). The only difference between method functions and other functions is that method functions may use this as an indirect way of naming the object that contains them. TIP If you have special purpose functions that only operate on instances of an object, then those functions should be methods of that object.
Nested Objects
Object properties are typeless quantities. They may be ordinary variables of any implicit type. Our house object contains properties that are implicitly integers, strings, and booleans. It also contains functional members (methods). In a very real sense, every new object is a new data type, and every instance of that object is a new variable with its object as the underlying, implicit type of that instance. Since JavaScript is typeless, does this mean that objects can contain other objects? In a word, yes. Suppose we create a new object called desc that holds some common pieces of information about various items. In particular, the desc object has properties for length, width, height, and color, and a method for computing the volume. The definition of this object and its volume method are shown in listing 4.8. This code can be found in the file descob.js on the CD-ROM.
*/ function desc( ln, wd, ht, col) { // describe something this.length = 5; // four properties and length of the array this.len = ln; // length of the thing; prop [1] this.width = wd; // width of the thing; prop [2] this.height = ht; // height of the thing; prop [3] this.color = col; // color; prop [4] this.findvolume = findvolume; // volume computation method } /* The volume computation method. If the ismetric argument is true then the metric volume will be returned; otherwise the volume in cubic feet will be returned */ function findvolume ( ismetric ) { var mylen, mywid, myht; var conv = ( 39.37 / 12.0 ); // conversion from metric to English if ( ismetric == true ) { mylen = this.len; // metric by default mywid = this.width; // ditto myht = this.height; // ditto } else { mylen = this.len * conv; // convert mywid = this.width * conv; myht = this.height * conv; } return( mylen * mywid * myht ); // return volume }
We can now add a desc object as a property of the house object. We could simply add length, width, height, and color properties directly to the definition of house, but this would go against another fundamental principle of object-oriented programming: object reuse. The desc object is very general. It can be used to describe a house, a car, a boat, or a tea cozy. It makes good sense to encapsulate these common properties in the desc object and then reuse that object's definition over and over by including it with the house, car, boat, and tea cozy objects. It would be serviceable, but wasteful, to repeat the same information in all these object definitions. Listing 4.9 (part of the CD-ROM file house3.js) shows the latest version of house object creation function.
In order to properly create a house instance we must first create a desc instance, and pass it as the fifth argument to house. It would be an error to pass in a desc object. A house instance, even one with a sub-object, must have all its slots filled in; this is what makes it an instance. This means that all the slots in the desc property of house must be filled in, as well, so that it, too, must be an instance. Once this has been done, it is possible to use all the properties and methods of the desc of the house. Listing 4.10 shows code that creates a desc instance, creates a house instance with that description, and then displays the color, age, and volume of the house using the properties and methods of the desc (and myhouse itself). This type of structure, in which objects and instances can be contained within one another, is referred to as an object hierarchy. Listing 4.10 is also found in the CD-ROM file house3.js. When this code is executed we obtain a page that looks like figure 4.3. Figure 4.3 : Objects can contain one another in an object hierarchy.
2
var myhouse; var mycol, myvol; mydesc = new desc( 20, 18, 15, "beige" ); // fairly big; ugly color myhouse = new house( 10, "Colonial", 1989, true, mydesc ); // mine, though /* Display the colorvolume and age of the house using a reference to the desc properties of myhouse. */ mycol = myhouse.descr.color; // property of property myvol = myhouse.descr.findvolume(true); // submethod document.write("<BR>My house is " + mycol); document.write("<BR>Its " + myhouse.howold( 1996 ) + " years old"); document.write("<BR>My house occupies " + myvol + " cubic meters"); document.write("<BR>");
an object or instance. Inside the with block any reference to properties they had been prefixed with objname and the dot operator (.). Listing 4.11 shows an expanded version of the second part of listing 4.10, in which various aspects of myhouse are displayed. The mshowhouse method should now be extended to not only display the properties of its instance, but to also call a similar show method within the desc object (which will also need to be created).
*/ var mycol, myvol, myage; with ( myhouse ) { mycol = descr.color; // 1: ref to myhouse.descr.color myvol = descr.findvolume(true); // 2: ref to
2
myhouse.descr.findvolume myage = yearbuilt; // 3: reference to myhouse.yearbuilt document.write("<BR>My house is " + mycol); // 4 document.write("<BR>My house occupies " + myvol + " cubic meters"); // 6: explicit reference to another instance if ( myage > yourhouse.yearbuilt ) { document.write("<BR>Its newer than yours!"); // 7 } document.write("<BR>"); }
// 5
Each of the statements labeled 1, 2, and 3 makes an implicit reference to the myhouse object, which was established as the default object to use in the with statement. Note that not every statement within the with block needs to refer to myhouse. Statements 4, 5, and 7 make absolutely no reference to any house object. Also, statement 6 makes an explicit reference to a different house instance, namely yourhouse. Statement 6 exposes one of the weaknesses of the with statement. When JavaScript careens through this with block, it must decide many times when the implicit myhouse is to be used, and when it is to be skipped. It must examine every reference, in fact. So, for mycol it must decide if you meant the local variable mycol or if there is some property of myhouse named myhouse.mycol. Fortunately, there is an unambiguous choice in every case. There is no mycol property of the house object. Statement 6 uses an explicit reference to yourhouse. If statement 6 had been written as
if ( myage > yearbuilt ) {
JavaScript would have misinterpreted your intentions as to the meaning of yearbuilt, and would have implicitly translated this statement to
if ( myage > myhouse.yearbuilt ) {
since there is a yearbuilt property of myhouse. This type of error is both common and pernicious. Since JavaScript is an interpreted language, there is no way to see that this inappropriate translation has taken place. There is no compiled output that can be examined. Such errors are very hard to debug. Even though with is very useful, its use should be strictly circumscribed. CAUTION with blocks should be as short as possible. Check all statements within the with block to ensure that there are no ambiguous references to local variables or to properties of other objects.
Our discussion of the object foundations of JavaScript is almost complete. We have learned that functions are used to define objects and create instances using the new operator. We have also learned that objects, indexed arrays, and associative arrays are really all the same. In fact, the unity between all these concepts goes even deeper. JavaScript functions themselves have properties that can be used to fine- tune their behavior. This aspect of JavaScript is still evolving at the time of this writing. However, we can say for certain that all JavaScript functions will have at least the following two properties:
caller arguments
The caller property is the name of whoever called the function. The arguments property is an array of all the arguments that are not on the argument list of the function. The caller property permits a function to identify and respond to the environment in which it is called. The arguments property allows us to write functions that take a variable number of arguments. The arguments in the function's argument list are mandatory, while those in the arguments property are optional. Listing 4.12 shows a function that takes one mandatory argument and a potentially unlimited number of option arguments. It returns a string describing its invocation. This function is contained in the CD-ROM file optarg.js.
To see how this works, suppose that this function is called from within another function named test1, with the following invocation:
var str = addem( "there", 1, 3, 5, 7 );
What happens? The mandatory argument "there" is assigned to the parameter str1 of the function addem. The complete argument list is also assigned to the variable length array addem.arguments. This has a length property (as do all well behaved arrays), which has the
value 5 since there are five arguments all together-one mandatory argument and four optional arguments. This means that the local variable nopt is 5. Unlike the examples we have used, the length property is not at index 0 of the arguments array. The arguments begin at addem.arguments[0] and continue up to addem.arguments[4] (five elements total). This means that the optional arguments begin at addem.arguments[1]. The for loop in addem adds the optional arguments together, and arrives at 1 + 3 + 5 + 7 = 16, which is assigned to the local variable sum. Finally, strres is constructed by concatenating various strings, among them the mandatory parameter str1, which is "there", and the value of the sum. The concatenated string is returned, and assigned to str; its value is the string "Hello there, sum is 16." Notice that both the mandatory argument str1 and the optional arguments are part of the argument list addem.arguments. Notice also that there need not be any optional arguments. The function call
var str = addem( "on a stick" );
Built-In Objects
Now that we have covered the foundations of object-oriented programming in JavaScript we can begin to look at the actual objects that JavaScript itself provides. These objects can be put into the following three categories:
Built-in objects include string objects, the Date object, and the Math object. They are referred to as built-in because they really do not have anything to do with Web pages, HTML, URLs, the current browser environment, or anything visual. HTML objects, in turn, are directly associated with elements of Web pages. Every link and anchor is a JavaScript object. Every form, and every element within a form, is an HTML object. The hierarchical organization of display elements on a Web page is reflected almost exactly in a hierarchical set of nested HTML objects. You've already gotten a taste of this hierarchy in the event processing examples of chapter 3. Browser objects are at the top of JavaScript's object hierarchy. These objects represent large scale elements of the browser's current environment, and include objects such as window (the current window), history (the list of previously visited pages), and location (the URL of the current page). The rest of this section briefly describes the built-in objects of JavaScript. The next two sections give overviews of the HTML and browser objects. Each of these three categories is quite rich, and chapters 5, "Built-In JavaScript Objects," through 7, "Advanced HTML Objects and Navigation," provide more in-depth information on each of the three categories.
String Objects
String objects are the most built-in of all the built-in JavaScript objects. You do not even use new when creating a string object. Any variable whose value is a string is actually a string object. Literal strings such as "HelloWorld" are also string objects. String objects have one property, length, and many methods. The length property gives the length of the string. The methods fall into three categories: methods that manipulate the contents of the string, methods that manipulate the appearance of the string, and methods that convert the string into an HTML element. String Content Methods The following methods can be used on string objects to access, control, or modify their content:
charAt( idx ) indexOf( chr ) lastIndexOf( chr ) substring( fromidx, toidx ) toLowerCase() toUpperCase()
The toLowerCase and toUpperCase methods convert the contents of the string entirely to lowerand uppercase, respectively. So if we define the string variable
var mystr = "Look At This"
then its length property, mystr.length, will have the value 12, since there are 12 characters in the string. In addition, we can apply the two case conversion methods and get
mystr.toLowerCase() = "look at this" mystr.toUpperCase() = "LOOK AT THIS"
These two functions do nothing to characters that have no case, so the two spaces in this string are unchanged. We could have also applied the methods directly to the literal form of this string object, so "Look At This".toLowerCase is also equal to "look at this". The methods charAt and substring are used to extract either a single character from a string, at position idx, or to extract a range of characters, from position fromidx up to but not including position toidx. Character positions are zero-based, as are all JavaScript arrays, so that all indices must fall between 0 and one less than the length of the array. For example, using mystr, we have
mystr.charAt(5) = "A" mystr.substring(5,7) = "At"
Like the method functions toUpperCase() and toLowerCase() these methods both return strings. Care should be take to give these methods valid indices that are actually within the
string. The substring method will forgive you if you accidentally specify a toidx which is <= the corresponding fromidx-it will return the empty string "". Finally, both the indexOf and lastIndexOf methods are used to search for chr with a string. indexOf searches from the beginning (left side) of the string and lastIndexOf searches from the end (right side). Both return an integer index if they find the character, and -1 if they do not. Using mystr again, we can search for the character o from both sides:
mystr.indexOf("o") = 1 mystr.lastIndexOf("o") = 2
The first search finds the first o of the word "Look" at position 1 (second character), and the second search finds the second o of "Look" since that is the first o when searching from right to left. Both of these methods also take an optional second argument that specifies an initial index at which to start the search. String Appearance Methods The string appearance methods are used to control how a string appears when displayed on a Web page. If you are creating a page with standard HTML tags you would achieve the same effects by using various tags. For example, to make the string "help" appear in italics you would write <I>help</I>. The string appearance methods allow you to obtain the same effects in JavaScript without using the corresponding HTML elements. The string appearance methods are as follows:
big() blink() bold() fixed() fontcolor( colr ) fontsize( sz ) italics() small() strike() sub() sup()
Most of these methods should be self-explanatory. The italics method, for example, performs exactly the same function as the I tag in HTML. The only two that take arguments are the fontcolor and fontsize methods. The fontcolor method changes the font color of the string, as if the <FONT COLOR=colr> attribute had been size. Similarly, the fontsize method changes the size of the font used for displaying a string as if the <FONT SIZE=sz> attribute had been given. colr should be a string; sz may be a number or a string. If it's a number then this specifies an absolute font size; if it's a string such as "+2" it specifies an increment relative to the current font size. Listing 4.13 shows several examples using the string appearance methods. The output of this code is shown in figure 4.4. Figure 4.4 : Many HTML style tags have equivalent JavaScript methods.
NOTE Not all HTML style tags have corresponding string appearance methods. You can always directly embed an HTML tag in the string itself if there is no method with the same functionality. Listing 4.13 String Methods Can Be Used to Change How Strings Are Displayed
var bstr = "big"; var sstr = "small"; /* This displays strings with both big and small text. */ document.write("<BR>This is " + bstr.big() + " text"); document.write("<BR>This is " + sstr.small() + "text"); /* The following two strings contain directly embedded HTML tags. They have exactly the same result as the two method calls above */ document.write("<BR>This is <BIG>big</BIG> text"); document.write("<BR>This is <SMALL>small</SMALL> text"); /* If your favorite tag does not have a method, just embed it */ document.write("<BR>This is <STRONG>strong</STRONG> text"); document.write("<BR>");
HTML String Methods JavaScript provides two string methods for converting strings into hypertext entities. These methods should be clearly distinguished from the HTML objects, such as forms, which are discussed in the section "Browser and HTML Objects" later in this chapter. These methods are used to create HTML, while the HTML objects already are HTML. The two methods in this category are as follows:
anchor( namestr ) link( hrefstr )
Both these methods are used to create some form of the anchor (<A>) HTML attribute. The difference between them is that the anchor method is used to create an anchor with namestr as the value of the NAME attribute, while link is used to create an anchor with the HREF attribute set to hrefstr. Said another way, anchor creates an anchor that is a target, while link creates an anchor that is a link. Both methods convert the string on which they operate into the text portion of that anchor. namestr may be any valid string which may be a NAME, so it should not have any embedded white space. hrefstr should be a valid URL, since the user is being invited to click it. Listing 4.14 uses these methods and shows a simple example that sets up an anchor target and then links to it.
NOTE The anchor() string method uses the older but more common HTML NAME attribute rather than the newer ID tag. Listing 4.14 String Methods Can Be Used to Create HTML Anchors and Links
var sum4str = "Summary of Chapter 4"; var sum4tar = "Summary4"; /* Create a summary target and a link to it. The following two statements are completely equivalent to this HTML: <A NAME="Summary4">Summary of Chapter 4</A><HR> Click here for a <A HREF="#Summary4">Summary of Chapter 4</A> */ document.write(sum4str.anchor(sum4tar)); document.write("<HR>"); document.write("Click here for a " + sum4str.link(location + "#" + document.write("<BR>");
sum4tar));
2
asin( num ) atan( num ) ceil( num ) cos( ang ) exp( num ) floor( num ) log( num ) max( num1, num2 ) max( num1, num2 ) pow( num1, num2 ) random() round( num ) sin( ang ) sqrt( num ) tan( ang)
These are all the functions and constants you find on any decent calculator. Remember that JavaScript is case-sensitive, so you must write Math.PI exactly to get the value of pi. The constants stand for the base of the natural logarithm (Napier's constant, or about 2.71828), the natural log of 10 (about 2.30259), the natural log of 2 (about 0.69315), everyone's favorite pi (about 3.141592653589793), the square root of 1/2 (about 0.7071), and the square root of 2 (about 1.4142). The methods of the Math object include the common trigonometric functions, including the sine (sin), cosine (cos), tangent (tan), and their inverses, the arcsin (asin), arccos (acos), and arctan (atan). Each of the trig functions takes an angle in radians and produces a floating-point number. The values should be between -1 and 1 for the sin and cos methods. Each of the inverse trig functions takes a number, which should be between -1 and 1 for the asin and acos methods, and returns an angle in radians. The ceil, floor, and round methods all take floating-point numbers as inputs, and return integers as outputs. The ceil method gives the smallest integer that is greater than or equal to its argument, while floor returns the largest integer that is less than or equal to its argument. The round method gives the nearest integer. The exp, log, pow, and sqrt methods all deal with exponentiation or its inverse. The exp method raises Math.E to the power given by its argument, and is the inverse of the log method, which returns the natural logarithm of its argument, which should be positive. The pow method raises num1, its first argument, to the power num2, its second argument. The sqrt returns the square root of its argument. If you inadvertently give sqrt a negative number it forgives you and returns 0. Finally, the abs, min, max, and random methods perform various useful operations. The abs method returns the absolute value of its argument. min and max give the minimum and maximum value of their two arguments, respectively. The random method takes no arguments. It returns a
random, floating-point number between 0 and 1. For some obscure reason the random method is only available in the UNIX releases of Netscape Navigator 2.0. Listing 4.15 presents some simple uses of the Math object. This example can be found in the CD-ROM file mathex.js.
Listing 4.15 mathex.js Three Useful Functions Using the Math Object
/* Compute the area of a circle given its diameter */ function areaofcir(diam) { var radius = diam / 2; return( Math.PI * radius * radius ); // pi times r squared } /* Given the coordinates of a point on a circle, determine how far around the circle we must rotate in order to reach that point. Return the angle in radians. */ function angoncircum( x, y ) { var epsilon = 0.00001; // a very small number if ( Math.abs(x) < epsilon ) { // if x is very close to zero if ( y > 0 ) { // positive x axis return(0.0); // 0 degrees = 0 radians } else { // negative x axis return( Math.PI ); // 180 degrees = pi radians } // end of inner if-else } // end of outer if // division by zero avoided by the "if" test above return( Math.atan( y / x ) ); } /* Given the diagonal size of a television, compute its width assuming that the screen is square */ function tvsize( diag ) { return( diag / Math.SQRT2 ); }
often called "The Epoch," since it is shortly after UNIX was first unleashed on an unsuspecting world. CAUTION The current version of JavaScript does not permit you to manipulate dates earlier than The Epoch. Attempting to do so gives unexpected and incorrect results. The Date object has no properties, but many methods. In order to use the Date object you must first understand how to construct instances of it. There are three basic methods of creating a Date instance, as follows:
new Date() new Date( datestring ) new Date( yr, mon, day )
The first form constructs a Date instance that represents the current date and time. This should be accurate to within a second, and also include information about your time zone and any corrections to it currently in effect (such as Daylight Savings Time). The second form takes a string of the form "Month Day, Year" such as "November 23, 1990" and converts it to a Date instance. This string may optionally have a time of the form HH:MM:SS at the end, which is used to set the time to HH hours, MM minutes, and SS seconds. Hours should be specified using a 24-hour clock, also known as military time, so that 10:15 PM is represented as 22:15:00. The third form takes three integers representing the year, month, and day. Note that the month is always indexed from zero, so that November is month 10. The year can also be offset by 1900, so that you can use either of these two forms
var ndat = new Date(90, 10, 23); var ndat = new Date(1990, 10, 23);
to create a Date instance named ndat for November 23, 1990. Note that for the year 2000 and beyond you must use the second form. This form may optionally take an additional three integer arguments for the time, so that 1:05 PM on November 23, 1990 is
var ndat2 = new Date(90, 10, 23, 13, 5, 0);
The Date object has a large set of methods for getting and setting the components of a date. These methods are as follows:
getDate() getDay() getHours() getMinutes() getMonth() getSeconds() getTime()
2
getTimeZoneOffset() getYear() setDate() setHours() setMinutes() setMonth() setSeconds() setTime() setYear()
Most of these methods perform the obvious operation on their Date instance. nvar.getMonth() returns 10, representing November. It is 10, rather than 11, because months are zero-indexed, so that the value of getMonth() is always between 0 and 11, inclusive. The confusingly named getDate, getDay, and getTime are worth a slightly closer look. The getDate method returns the day of the month (1-31), the getDay method returns the day of the week (0-6), and the getTime method returns JavaScript's internal representation of the date, namely the number of milliseconds since The Epoch. This last method might seem to be of dubious utility, but it is useful for comparing two dates to see which is later. The set methods are, of course, used to set the various components of a Date instance. Listing 4.16 shows two simple date manipulation functions. This code can be found in the CD-ROM file datex.js.
Listing 4.16 datex.js Two Useful Functions Using the Date Object
/* Given a date as a string, return the day of the week as an integer between 1 and 7. Note Sunday = 1. */ function dayofweek( datestr ) { var dati; dati = new Date( datestr ); // make datestr into a Date instance return( 1 + dati.getDay() ); // get the day of the week and add 1 } // since getDay() returns a number between 0 and 6 /* Compute the number of days to your birthday. Your birthday is specified as the day and month. */ function tobday( dayi, moni ) { var today, todayy, todayms; var you, youms; var tdiff; today = new Date(); // today's date todayy = today.getYear(); // current year you = new Date(todayy, moni-1, dayi); // your birthday this // need to subtract 1 because months are zero-indexed todayms = today.getTime(); // convert today to ms since The Epoch youms = you.getTime(); // convert your birthday to ms since The Epoch
2
if ( youms < todayms ) { // if your birthday has already passed.. you.setYear(1 + todayy); // look forward to next year youms = you.getTime(); // recompute ms since The Epoch } tdiff = youms - todayms; // number of milliseconds until your next birthday tdiff /= 1000; // convert to seconds tdiff /= 60; // minutes tdiff /= 60; // hours tdiff /= 24; // convert to days return( Math.round( tdiff ) ); // round to nearest integer }
In addition to the get and set methods, the Date object also has methods for converting a Date instance to a string, and two static methods for parsing dates. These methods are as follows:
toGMTString() toLocaleString() toString() parse( datestr ) UTC( datestr )
The first three of these methods convert a date instance into a string representing the date and time relative to Greenwich Mean Time (GMT, also called UTC for Universal Coordinated Time), relative to the current date formatting conventions (which vary between Europe and the U.S., for example), and as just a plain, ordinary string, respectively. The last two methods are used for converting date strings in local time (parse method) or in UTC time (UTC method) into the number of milliseconds since The Epoch. These methods must be referenced as Date.parse() and Date.UTC() since they are static; they may not be used with Date instances. Since they return the internal representation of dates, these values are often simply passed to setTime. TROUBLESHOOTING I have modified your function tobday in listing 4.16. My version accepts an arbitrary string as the input birthday. It works perfectly for my birthday, but it fails horribly for my father's birthday. What is wrong? The code looks like:
function tobday2( bdaystr ) { var bdayint = new Date( bdaystr ); ... many lines of code not shown
Since your father was undoubtedly born before January 1, 1970, the very first line attempts to create a Date instance corresponding to a date before The Epoch. This is not currently permitted. Since it seems that you were born after The Epoch, the code will work fine for your birthday. Until this restriction is lifted you must convert the year to one after 1970 before you construct a Date instance.
Built-In Functions
You have now had your first exposure to the built-in String, Math, and Date objects. Some of these objects are more built-in than others. While Date acts like an actual object, with the exception of its two static methods, the String object is almost invisible. All normal JavaScript programs manipulate strings as if they are a separate data type. The essence of a string is part of the JavaScript language. There is also a small set of functions built in to JavaScript itself. They are not methods, and are never applied to an instance using the dot operator (.). They are on the same plane as functions that you create using the function keyword. At present, there are five such built-in functions; they are as follows:
escape( str ) eval( str ) parseFloat( str ) parseInt( str, radix ) unEscape( str )
The escape and unEscape functions are used to convert to and from the escape code convention used by HTML. In HTML a number of special characters, such as the HTML delimiters < and >, must be represented in a special way to include them in ordinary text. For example, if you have written any HTML at all then you know that you sometimes need to write %20 to represent a space character. The escape built-in function takes a string representing one of these special characters and returns its escape code in the form %xx, where xx is a two-digit number. Thus, escape(" ") returns %20, the code for a space character. The unEscape function is the inverse of the escape function. It takes an escape code and returns the char-acter which that code represents. Thus unEscape("%20") returns the string " " (a single space character). The parseFloat built-in function attempts to parse its string argument as a floating-point number. It only continues parsing the str until it encounters a character that could not possibly be part of a valid floating-point number, such as g. The parseInt built-in function performs a similar operation. It attempts to parse its str argument as an integer in base radix. Thus we would obtain the following values:
parseFloat("+3.14williamtell5") = 3.14 parseInt(10111, 2) = 23
Note that everything after the first w is ignored, since w cannot possibly be part of a floatingpoint number. The second value is obtained because 23 in binary (base 2) notation is 10111. Finally, the eval function attempts to evaluate its string argument as a JavaScript expression and return its value. All the normal rules for evaluating expressions, including variable substitution, are performed by the eval function. This function is extremely powerful simply because it evaluates any JavaScript expression, no matter what that expression does. You will see a lot more of this function in several subsequent chapters. For the moment, we briefly look at a simple
example in which we ask eval to do some arithmetic for us. If x is a var with the value of 10 then the following two expressions assign 146 to both y and z:
y = ( x * 14 ) - ( x / 2 ) + 11; z = eval("( x * 14 ) - ( x / 2 ) + 11");
Browser Objects
The primary browser objects, in rough order of significance, are as follows:
window document location history
The window object, as figure 4.5 shows, is the top object in the JavaScript object hierarchy. Every browser window that is currently open will have a corresponding window object. All the other objects are children of one of the window objects. In particular, every window is associated with a particular Web page, and the HTML structure of this page is reflected in the window's document object. Every window corresponds to some URL; that URL is reflected in the location object. Every window has a history of the previous pages that have been displayed in that window, which are represented by the various properties of the history object. JavaScript maintains an idea of the current window, so that almost all references to sub-objects of the current window do not need to refer to it explicitly. This is why all of our output has been done using document.write() rather than window.document.write(). window objects have the following interesting methods (among others):
alert( msgstr )
All these methods are used to manipulate the window state of the browser itself. The alert and confirm methods are used to display their msgstr argument in a dialog box. The alert method is used to alert the user to something about which the user can do nothing. An alert dialog box contains a single OK button. The confirm dialog box is more flexible, and displays its message with both an OK and a Cancel button. If the user selects OK then the confirm method returns true, otherwise it returns false. The prompt method is used to solicit user input, in the form of a string. It displays a dialog box with the msgstr and an editable text field. This method also accepts a second optional argument that can be used to set a default value in the input field. This method returns whatever the user typed as a string. You use the open method of the window object when you wish to open a new browser window. The urlstr argument is a string representing the URL that will be loaded into that window. The wname argument is a string that gives the new window its name. This method returns an instance of the window object representing the new window created. This method also accepts a third argument that can be used to specify a wide variety of display options for the new window (such as whether or not it should display its toolbar). When the close method is invoked from a window instance the underlying window is closed and the URL in it is unloaded. The document Object Every window is associated with a document object. The document object contains properties for every anchor, link, and form on that page, as well as all of the sub-elements of those elements. It also contains properties for its title (the content of the <TITLE> field of the page), its foreground color (the fgColor property), its background color (the bgColor property), its various link colors, and other attributes of the page itself. The document object has the following methods:
2
clear()
The clear method is used to completely erase a document window. The entire contents are wiped out, regardless of how they got there. The clear method is particularly useful if you are constructing a Web page entirely within JavaScript, and want to make sure it is empty before you start. The open and close methods are used to start and stop buffered output. If you call the open method, perform a series of writes and/or writelns, and then call the close method, the results of your write operations are layed out and appear on the page. CAUTION Do not confuse the open and close methods of the document object with the window methods of the same names. They perform very different functions, and are not interchangeable. Use an explicit reference-document.open() or window.open()-to obtain the appropriate one. Of course we are intimately familiar with the write method by now. The write method is used to write any string expression, including one containing embedded HTML, to the current document. Note that the write method actually takes a variable number of arguments, rather than just one. If more than one argument is given, each of the arguments is interpreted as a string and written in turn. The writeln method is identical to the write method, except that it outputs a carriage return after it has completed writing its argument(s). Note that this carriage return will be ignored by HTML, which really does not like embedded white space, unless the writeln is inside preformatted text (within PRE>...</PRE tags). The history and location Objects The history object is used to refer to the history list of previously visited URLs. The history object has a property known as length, which indicates how many URLs are stored on the history list at present. It also has the following three methods:
back()
The go method is used to navigate the history list. The where argument can be a number or a string. If the where argument is a number then it indicates how far we wish to move in the history list. A positive number means that we wish to move that many documents forward in this history list, while a negative number is used to move backward. Thus, go(5) has the same effect as using the Forward button five times, while go(-1) would be the same as clicking the Back button once. If where is a string representing a URL then that URL is loaded, and becomes the current document.
The location object describes the URL of a document. It has properties representing the various components of the URL, including its protocol part, its hostname part, its pathname part, and its port number part, among other properties. Unfortunately, these properties are often null, at least in the UNIX version of Netscape Navigator 2.0. It also has a toString method which can be used to convert it to a string. We can use the following code to display a formatted message giving the current URL:
var loc = document.location; document.write("<BR>URL is " + loc.toString()); document.write("<BR>");
HTML Objects
To understand how HTML objects work in JavaScript, let us consider a simple piece of HTML that creates an anchor, a small form, and a link to that anchor. This is not intended to be the HTML for a meaningful Web page, but it will nevertheless illustrate the correspondence between HTML elements and JavaScript HTML objects. Our elementary HTML code is given in listing 4.17. This code can be found in simple.htm on the CD-ROM.
Listing 4.17 simple.htm HTML Code for a Page with a Form, Anchor, and Link
<HTML> <HEAD> <TITLE>A very simple HTML page</TITLE> </HEAD> <BODY> <A NAME="top">This is the top of the page</A> <HR> <FORM METHOD="post" ACTION="mailto:[email protected]"> <P>Enter your name: <INPUT TYPE="text" NAME="me" SIZE="70"> </P> <INPUT TYPE="reset" VALUE="Oops"> <INPUT TYPE="submit" VALUE="OK"> </FORM> <HR> Click here to go to the <A HREF="#top">top</A> of the page </BODY> </HTML>
This code creates an HTML page with an anchor at the top of the page and a link to that anchor at the bottom. In between is a simple form that allows the user to enter his name. There is a submit button if he gets it right, and a reset button if he doesn't. If the user is successful the form's contents are submitted via a post action to the fictitious e-mail address [email protected]. We can also access the other HTML elements of this document using the following properties:
anchors forms
2
links
These properties of the document object are arrays representing every HTML element that is an anchor, form, or link on the page. In our particular example there is only one of each, so we would refer to the anchor at the top of the page as document.anchors[0], the link at the bottom of the page as document.links[0], and the form in the middle of the page as document.forms[0]. These are the top-level HTML objects represented by this document. Each of these elements, in turn, has properties and methods that can be used to describe and manipulate it. In particular, the form object corresponding to forms[0] has sub-objects for each of the three form elements (the reset button, the submit button, and the text input field), as well as properties for the submit method and the submit target. forms[0].elements[0] corresponds to the text input field. forms[0].elements[0].name is the name of that field, as specified by the NAME field, which is "me" in this case. Figure 4.6 recapitulates this HTML code and shows how each element in the page is associated with an HTML object. We will have many more examples of this in subsequent chapters.
JavaScript is designed to be easy to learn and convenient to use by almost anyone who seeks to create dynamic Web pages and client-side checking of input forms (as well as many other uses discussed in this book). Because the authors of JavaScript have had this in mind, they have provided you, the programmer, with many built-in objects that you will probably use quite often. These built-in objects are available through both the client-side JavaScript (inside the Netscape Navigator on your desktop) and through LiveWire (Netscape's server-side application). In addition, JavaScript has three functions that you can use throughout your scripts without having to declare them. The three built-in objects are: the String object, the Math object, and the Date object. Each of these provides great functionality, and together they give JavaScript its power as a scripting
language. These built-in objects are discussed in depth in this chapter and you will find many examples for use in your own projects.
This line of code returns "This is some text", as displayed by your Web browser. Table 5.1 shows the various methods that you can call with the string object to alter its HTML formatting. Table 5.1 String Object Methods for HTML Formatting Method Example Returned Value Name
anchor big blink bold fixed fontcolor fontsize italics link small strike sub sup "foo".anchor("anchortext") <A NAME="anchortext">foo</A> "foo".big() "foo".blink() "foo".bold() "foo".fixed() "foo".fontcolor("green") "foo".fontsize(-1) "foo".italics() "foo".link("linktext") "foo".small() "foo".strike() "foo".sub() "foo".sup() <BIG>foo</BIG> <BLINK>foo</BLINK> <B>foo</B> <TT>foo</TT> <FONT COLOR="green">foo</ <FONT SIZE="-1">foo</FONT> <I>foo</I> <A HREF="linktext">foo</A> <SMALL>foo</SMALL> <STRIKE>foo</STRIKE> <SUB>foo</SUB> <SUP>foo</SUP> uppercase UPPERCASE
Figure 5.1 shows how the string "foo" would be rendered in your browser if you used each of the methods listed in table 5.1. Figure 5.1 : String methods as rendered by Netscape Navigator.
Text without any modifications (denoted as Normal Text) is placed between some lines to help you see how each method changes the appearance of the text. Figure 5.2 shows you the source script that was used to create figure 5.1. Note that all of the strings were called as literals-that is, not as variables as you might normally see them. Figure 5.2 : Source code for figure 5.1.
Chaining Methods
Not only can you change the formatting of the text in one way at a time, you can "chain" the various methods together to mimic the behavior of nesting HTML tags around a piece of text. This can be particularly useful if you generate HTML automatically via a script. For example, the following displays a blinking "FOO" on the page:
document.write("foo".blink().toUpperCase().bold())
Remember to include the parentheses after each of the methods even though they do not take any arguments. The preceding code appears to the browser as the following:
<B><BLINK>FOO</BLINK></B>
You can see that the BLINK tag is nested inside the B tag, since the blink method was called first. (JavaScript reads code from left to right and from top to bottom.) If you wish to have a desired effect with nesting tags, remember that the order of nesting is the leftmost string method nested inside the next method called to the right. The reason you can nest these methods is that they all accept and return a string object so it appears to the next method as a simple string-as if you had typed it in. Nesting Methods Versus Chaining Methods There are usually two ways you will see methods called in scripts you encounter. You might see something like this:
foo().bar().baz() "Chaining"
foo(bar(baz()))) "Nesting"
The difference here can be subtle. With foo().bar().baz(), JavaScript will determine the result value of foo(), then treat that value as if it were the object called with .bar(). You must make sure that the value returned by the leftmost method is valid in order to have the second method "appended" to it, to continue calculations. It is valid here if foo() and bar() return strings, since string literals (what each of these methods return) can subsequently have other string methods. foo(bar(baz())) is different in that evaluation is conducted in right-to-left order. baz() is evaluated first and then is passed as a parameter to bar(). bar() must be able to accept a parameter of this type in order for this to work. For some methods, this difference in evaluation has no effect, but for others, you might get incorrect values.
Links are used in a similar fashion. Only in this case, instead of giving an anchor a name, you are giving a link a URL. For example, to display a link to Yahoo, you would write the code in listing 5.1.
TIP
You can quickly create long strings from short ones by using the plus concatenator (+). The expression "Cat Fish" + " Sandwich" yields "Cat Fish Sandwich". Also, you can use the += operator (called the "plusequal" concatenator) to tack a string on the end of another. If string1 = "hello", then string1+=" there" would become "hello there". In addition to changing the formatting of a string object in HTML, you can also return parts of the string without having to know the actual contents of that string. This is extremely useful for parsing out different keywords or commands within some given input string by the user of your script. Table 5.2 lists the methods of the string object that pertain to displaying subsets of the strings contents. Table 5.2 String Object Methods for Displaying Subsets of Strings Method Name Example(s) Returned Value charAt "netscape n navigator".charAt(0) a "netscape navigator"
.charAt(10) indexOf "netscape navigator" .indexOf("scape") "netscape navigator" .indexOf("n",2) "netscape navigator" .lastIndexOf("a") "netscape navigator" .lastIndexOf("a", 12) "netscape navigator" .substring(0,7) "netscape navigator" .substring(7,0) "netscape navigator" .substring(0,50) "netscape navigator" .length "netscape navigator" .substring(0,7).length
lastIndexOf
substring
length
18 7
Note that length is a property of a string and receives its value indirectly based on the number of characters in a string. You cannot directly assign a value to the length property.
charAt
The method charAt returns the character at the index specified. Characters are numbered from 0 to the length of the string minus 1. Its syntax is:
2
stringName.charAt(index)
This method can be used to search down a string (from left to right) until it finds a string fragment matching the specified value. It returns the index of the first character of the matching string. You can use this information with the method substring (mentioned later in this section) to find keywords in a given string. This is useful when you allow the user to input some information and you wish to place parts of that information into different variables. For example, the following returns 9:
thisstring = "Internet World" thisstring.indexOf("World")
This method is identical to indexOf except that the method searches from right to left down the string to find the given keyword. It also returns the index value of the first character of the found keyword. For example, the following returns 5:
"Internet World".lastIndexOf("n") substring
completes the suite of subset text methods. This method returns a substring given beginning and ending index values. Note that the values do not have to be in numerical order. The string returned from substring(1,9) is identical to the one returned from substring(9,1). Also, if you leave off the second index integer, substring assumes you want it to return everything from the first index to the end of the string. And leaving off both indices returns the entire string. For example, listing 5.2, which can be found on the CD-ROM as list 52.txt, returns "World":
substring
2
Length
The length property appears in many types of objects across JavaScript, and pertains to a different value based on the context in which it is used. In strings, this value is an integer based on the number of characters in a string (counting whitespace, etc). For a null string, this value is zero. You cannot directly alter this value except by adding or removing characters from a string. Since the value returned by "foo".length is a number, you can perform mathematical operations on it like any other number. For instance, the following returns 7:
"Hi There".length - 1
or
Math.methodname(parameters)
Table 5.3 summarizes the various methods and properties. Table 5.3 Math Object Methods and Properties Example Returned Value
Math.abs(-79) Math.acos(.5) Math.asin(1) Math.atan(.5) Math.ceil(7.6) Math.cos(.4) Math.exp(8) Math.floor(8.9) Math.log(5) Math.max(1 , 700) Math .min(1 , 700)
Method Name
abs acos asin atan ceil cos exp floor log max min
2
pow random round sin sqrt tan Math Math.pow(6,2) Math.random() Math.round(.567) Math.sin(Math.PI) Math.sqrt(9801) Math.tan(1.5*Math.PI)
Methods
Although most of the methods used by Math are self-evident-such as using Math.sin to calculate the sine function of a number-they are summarized in the following sections, with examples for your reference. abs abs returns the absolute value of its numeric argument. For example, the following returns 1:
Math.abs(-1) acos, asin, atan, cos, sin, tan These return The a is short for arc, as in atan = arctangent.
Returns the smallest integer greater than or equal to the argument passed to it. This is equivalent to always rounding up to the nearest integer.
ceil
See also floor. Returns e to the power of its argument. Where if x is the argument, exp returns ex . (e is Euler's constant-the base of natural logarithms.)
exp
Returns the greatest integer less than or equal to the value passed to it. This is equivalent to always rounding down to the nearest integer.
floor
Returns the natural log of the argument passed to it. The base is e.
For example, the following returns the log to the base e of pi, which is 1.144729885849400164:
pie = Math.PI; pielog = Math.log(pie); document.write("The log to the base e of PI is: " + pielog + "."); max, min
Given two numbers, max returns the greater of the two, and min returns the lesser of the
Given a base and an exponent number, this returns the base to the exponent power.
Available only to UNIX platforms (Solaris, specifically) as of this writing, this returns a pseudorandom number between 0 and 1.
random
This method returns the argument rounded to the nearest integer. It rounds up if the number contains an integer of .5 or greater, and down otherwise.
round
2
with(Math) { java = round(1.4999999999); document.write(java); }
Returns the square root of its argument. Note: the argument must be non-negative, otherwise the sqrt returns 0.
sqrt
An Example Sine Plotter In figure 5.3, we see a Web site that has implemented a script that quickly generates a sine curve. Figure 5.3 : A Web site using math methods.
Math
Properties
The Math object provides you with a few constants that you can use for various scientific and algebraic functions. Note that these properties are constants and cannot be changed by JavaScript. The following is a list of each property and its approximate values:
E-Euler's constant, the base of natural algorithms. Approximately 2.718. LN2-The natural log of 2. Approximately 0.693. LN10-The natural log of 10. Approximately 2.302. PI-The ratio of the circumference of a circle to its diameter. Approximately 3.1415. SQRT1_2-The square root of .5 (one half) or one over the square root of 2. Approximately
0.707.
SQRT2-The
Table 5.4 sumarizes the Math object properties and gives examples. Table 5.4 Math Object Properties Summary Property Name Example Returned Value E Math.E*5 13.59140914229522501
(2.718281828459045091) LN10 Math.LN10/6 (2.302585092994045901) LN2 (0.69314718055994529) PI SQRT2 Math.LN2-Math.E
0.3837641821656743168 -2.025134647899099694
Using the Math object is essentially identical to using other objects in JavaScript with a few exceptions. If you use several Math constants and methods together in a block of code, you can use the with statement to avoid having to retype Math. over and over again. For example, the following:
beta = Math.E * 62; gamma = Math.PI / 4; delta = x * Math.sin(theta);
becomes
with (Math) { beta = E * 62; gamma = PI / 4; delta = x * sin(theta); }
To create a new Date object, you use the new operator. The Date object is pre-defined in JavaScript, and will build this instance filling in the current date and time from the client's system clock. Here is the syntax:
variableName = new Date(parameters)
For example,
today = new Date();
You have several optional parameters that you may send to the Date object, as follows:
variableName variableName variableName variableName = = = = new new new new Date() Date("month day, year hours:minutes:seconds") Date(year, month, day) Date(year, month, day, hours, minutes, seconds)
TIP Each of these forms has a few conventions you should be aware of. The first form, in which you omit all parameters, automatically sets the current date and time in the standard format of:
Day Month Date Hours:Minutes:Seconds Year
For example,
Sat Feb 24 14:43:13 1996
If you use the second or fourth form and omit the hours, minutes, or seconds, JavaScript automatically sets them to 0.
For example,
today.setHours(7);
There are two exceptions to this rule with the Date object: The UTC and parse methods are "static" methods and are always called with just the generic Date object name. For example,
Date.UTC(parameters)
2
Date.parse(parameters)
Table 5.5 summarizes the different Date methods. Table 5.5 Date Object Methods Method Example Returns getDate today.getDate() 5 getDay yesterday.getDay() 2 getHours today.getHours() 5 getMinutes today.getMinutes() 30 getMonth year.getMonth() 6 getSeconds time.getSeconds() 13 getTime now.getTime() ***** getTimeZoneoffset today.getTimeZoneoffset ****** getYear now.getYear 96 (the years since 1900) parse Date.parse(July 1, 1996) ***** setDate now.setDate(6) setHours now.setHours(14) setMinutes now.setMinutes(50) setMonth today.setMonth(7) setSeconds today.setSeconds(7) setTime today.setTime (yesterday.getTime()) today.setYear(88) setYear toGMTString toLocaleString UTC
yesterday.toGMTString() Sat, Feb 24 1996 14:28:15 GMT today.toLocaleString() 2/25/96 14:28:15 Date.UTC(96,11,3,0,0,0) -
Using all these methods' strings and numbers may look like a daunting task, but if you approach the Date object with a few concepts in mind, it makes working with this object much easier. First, all of the methods can be grouped into four categories: get, set, to, and parse. get methods simply return an integer corresponding to the attribute you requested. set methods allow you to change an existing attribute in a Date object-again by passing an integer-only this time you are sending a number instead of receiving it. to methods take the date and convert it into a string-which then allows you to use any of the string methods to further convert the string into a useful form. parse methods (parse and UTC) simply parse-or interpret-date strings.
Secondly, Date attibutes like month, day, or hours are all zero-based numbers. That is, the first month is 0, the second 1, and so on. The same goes for days, where Sunday is 0, Monday is 1, and so on. The reason why numbering starts at 0 instead of 1 is that JavaScript closely mirrors Java in many respects-like always starting an array of "things" with 0. This is a convention followed by many languages and is considered a good programming practice. Table 5.6 lists the numeric conventions. Table 5.6 Date Object Number Conventions Date Attribute Numeric Range
seconds, minutes hours day date year
0 - 59 0 - 23 0-6
Thirdly, when a Date object is created, it takes the information from the Netscape Navigator's environment-usually right as the Web page is being loaded or sometime shortly after.(The Navigator gets information about its environment from the operating system. Other examples of environment variables are the number of other programs running, the current RAM used, and so on, although these may not be accessible by JavaScript.) In the following sections, each Date method is described with a brief example.
get
Methods
These methods allow you to retrieve information from the current Date object. This information can be the seconds, minutes, hours, day of the month, day of the week, months, or years. Notice that there is a getDay method that will give you the day of the week, but you cannot set this value, since the day of the week is dependent on the month, day, and year. See figure 5.4 for examples of the get methods. Figure 5.4 : get method examples.
getDate
Given a date object, this returns the date as an integer between 1 and 31.
2
today = new Date("February 24, 1996") (today.getDay == 0) {document.write("Today (today.getDay == 1) {document.write("Today (today.getDay == 2) {document.write("Today (today.getDay == 3) {document.write("Today (today.getDay == 4) {document.write("Today (today.getDay == 5) {document.write("Today (today.getDay == 6) {document.write("Today
if if if if if if if getHours
is is is is is is is
For example, the following returns, "It's been 16 hours since our party last night!":
today = new Date(); document.write("It's been "+ today.getHours + " since our party last night!"); getMonth
For example, the following displays a different image about 50 percent of the time the user loads this page:
now = newDate(); if (now.getSeconds >30) {document.write("<img src = 'randimage1.gif'>")} if (now.getSeconds <=30) {document.write("<img src = 'randimage3.gif'>")}
Returns the number of milliseconds since January 1, 1970. This is useful in setting the time of another Date object.
getTime
For example,
thisDay = new Date("September 25, 1969"); myBirthday = new Date(); myBirthday.setTime(thisDay.getTime());
Gives you the difference between the local time and GMT (Greenwich
Mean Time).
For example,
now = new Date() timeDifference = now.getTimeZoneoffset; getYear Returns an integer representing the year of the
If the year is 1996, this returns "Hi!" If it is 1997, it returns "Hi! and Happy New Year!"
set
Methods
These methods allow you to add or change attributes of the Date object. You can change the date, month, year, hours, minutes, and seconds of the Date object (see fig. 5.5). All of these methods require integers. Although you will probably use the get methods more often, these methods are handy when you want to quickly create a date and time-perhaps for displaying on a page with a modification date. Figure 5.5 : setmethod examples.
setDate
For example, the following sets the hours attribute ahead 3 hours:
today = new Date() today.setHours=(today.getHours() + 3); setMinutes
This sets the minutes of the given time object (a number between 0 and 59).
For example, the following returns the current Date object (now) with the minutes set for 45:
now = new Date() now.setMinutes(45)
2
setMonth
For example, the following returns today (with the month now May):
today = newDate() today.setMonth(4) setSeconds
For example, the following returns now (with the seconds set ahead 5 seconds):
now = new Date() now.setSeconds(now.getSeconds()+5) setTime
Sets the time value using an integer representing the number of seconds since January
returns:
Sat Sep 04 08:06:40 1982
TIP Instead of using a large integer as a parameter, you could pass a getTime() from another date, such as:
thisDay.setime(thatDay.getTime())
For example, the following returns now (with the year now 1997):
nowYear = new Date() nowYear.setYear(97) to
Methods
These methods convert date information into another format. You can convert a date into a string (based on some set of conventions-as explained later). Once you have converted the date into a string, it can be treated just like any other string for HTML formatting, etc. (see fig. 5.6).
Note that the original date object is not affected. These methods simply parse the date object and return a string based on the information it found. Figure 5.6 : Using to methods.
toGMTString
This method converts the date to a string using the GMT convention.
For example,
today = new Date() document.write((today.toGMTString).bold)
This returns <B>Sat, 24 Feb 1996 17:55:33 GMT</B>. This is also rendered to the Netscape Navigator in bold text. Note that the bold method appended the <B> and the </B> to the string, and is not a default action of toGMTString method. This illustrates how you can compact your code based on the assumption that a method returns a known type that you can then use with other methods. This method converts a date to a string using the locale conventions. Locale conventions are specific to each area that will view this site-meaning that toLocaleString might return a different string in Europe than in the U.S., since in Europe the day is presented before the month. So 09/03/96 might mean September 3rd to the U.S., whereas in Europe, it would mean March 9th.
toLocaleString
would return the following in the U.S., if the date was October 4th, 1996:
09/04/96 08:06:40
Methods
methods take strings and convert them to a resulting date object. These methods complement the to methods, in that they perform the converse of taking a date and coverting it into a string. parse methods are handy in rapidly creating a Date object or simplifying the process of passing a new value to a setTime() method (see fig. 5.7). Figure 5.7 : Examples of parse methods. This method returns the number of milliseconds since January 1, 1970 00:00:00. It takes a string such as Feb 25, 1996 and is useful for setting date objects that already exist. It is
parse
acceptable to use the IETF standard date syntax, such as Sat, 24 Feb 1996 18:15:11 GMT. It understands U.S. time zone abbreviations, but Netscape recommends you use a time zone offset (thus, the use for the getTimeZoneoffset method). Note: The parse function is a static method of Date, so it is always called using Date.parse(), not with the name of the specific date object instance. For example,
netTime = new Date() timeString="Jul 10, 1908" netTime.setTime(Date.parse(timeString));
This returns the current Date object netTime with the changed month, day, and year.
UTC UTC stands for Universal Time Coordinated and is equivalent to GMT. This method for Date, and is always called via Date.UTC. It is called using the following syntax: Date.UTC(year, month, day)
is static
or
Date.UTC(year, month, day, hours, minutes, seconds)
Remember that JavaScript is case-sensitive, so always use uppercase UTC. Also, remember that you use the same integer conventions listed in table 5.6. For example,
theDate = new Date(Date.UTC(96 , 1 , 24 , 12 , 45 , 22));
2
<HEAD> <TITLE>JavaScript Clock</TITLE> <script Language="JavaScript"> <!- Hide me from other browsers // Netscapes Clock - Start // this code was taken from Netscapes JavaScript documentation at // www.netscape.com on Jan.25.96 var timerID = null; var timerRunning = false; function stopclock (){ if(timerRunning) clearTimeout(timerID); timerRunning = false; } function startclock () { // Make sure the clock is stopped stopclock(); showtime(); } function showtime () { var now = new Date(); var hours = now.getHours(); var minutes = now.getMinutes(); var seconds = now.getSeconds() var timeValue = "" + ((hours >12) ? hours -12 :hours) timeValue += ((minutes < 10) ? ":0" : ":") + minutes timeValue += ((seconds < 10) ? ":0" : ":") + seconds timeValue += (hours >= 12) ? " P.M." : " A.M." document.clock.face.value = timeValue; // you could replace the above with this // and have a clock on the status bar: // window.status = timeValue; timerID = setTimeout("showtime()",1000); timerRunning = true; } // Netscapes Clock - Stop -> </script> </HEAD> <BODY bgcolor="#ffffff" text="#000000" link="#0000ff" alink="#008000" vlink="800080" onLoad="startclock()"> <form name="clock" onSubmit="0"> <div align=right> <input type="text" name="face" size=12 value=""> </div> </form> <H1>Now you can add a clock to your pages!</H1> </BODY> </HTML>
Figure 5.8 shows how this would appear on your page. Figure 5.8 : A simple clock example. The heart of this script is the function showtime(). This function creates a Date object called now and pulls out (via getHours, getMinutes, and getSeconds) the hour, minutes, and seconds
values. It then creates a variable called timeValue and assigns the hour to it as a string. timeValue is interpreted by JavaScript as a string even though hours is a number because the first value assigned to timeValue was the empty quotes (""). Notice that if the hours value is greater than 12 it is reduced by 12 to account for conventional 12-hour time notation. Notice also that if the number of seconds or minutes is less than 10, the function appends a "0" before that number to keep the number of digits the same space, and to avoid confusion between 03 and 30. This script runs the function showtime() every 1000 milliseconds (once a second) to display the current time in a format that is easy for the user to interpret. One of the most useful aspects of JavaScript is that it uses an object-oriented approach to programming. What this means is that you (the scripter) can easily take functions that you worked so hard to perfect in one script and adapt them quickly to another script-often with little or no modifications. You can see in the comments of listing 5.2 that if you want, you can direct the output of the function showtime() to the status bar on the bottom of your browser, instead of displaying it in the textbox field on the page. You would do this by commenting out or deleting the following line:
document.clock.face.value = timeValue;
You would also need to remove the comments (the // ) from the following line:
// window.status = timeValue;
Using the status line has the advantage in that the text is less likely to flicker when it updates, as many rapidly updated form fields tend to do. Also, you can easily modify this code-instead of displaying the current time on the screen-to send it to another function. This function might then use that changing information to reload a clockface image (or almost anything your imagination comes up with). Pseudorandom Generator Listing 5.3 shows how you can simulate a seemingly random event. This is currently one of the few ways to work around the fact that the math.random() function is not enabled in all versions of Netscape Navigator (across platforms). The background behind this script is this: I wanted to find a way to generate a short three-word sentence based on a list of verbs, adjectives, and objects. These words came together to create a "Magic Talent," which simu-lates what happens to a number of fictional characters in various fantasy novel series. As someone enters the page, the date is sampled and used as a "seed" number to select one word from each list. These words are then concatenated together on-the-fly and displayed on the page. Essentially, it takes advantage of the fact that someone is unlikely to visit the page at exactly the same hour, minute, and second each day, so it appears to the page visitor that the selection is truly "random." The illusion disappears, though, if he repeatedly reloads this page-since the sentence will change only slightly.
2
objec[6] objec[7] objec[8] objec[9] function = 'swords' = 'castles' = 'trees' = 'pies' getVerb (){ currentdate = new Date() core = currentdate.getSeconds() adcore = Math.floor(core/6) core=adcore theverb = verb[core] return (theverb)
} function getAdj (){ currentdate = new Date() core = currentdate.getMinutes() adcore = Math.floor(core/6) core=adcore theadj = adj[core] return (theadj) } function getObjec (){ currentdate = new Date() core1 = currentdate.getSeconds() core2 = currentdate.getMinutes() core3 = core1 + core2 adcore = Math.floor(core3/12) core = adcore theobjec = objec[core] return (theobjec) } // main program document.write("Random Talent Generator".fontsize(6) + "<p>") document.write(description + spacer + "<p>" + getVerb() + spacer + getAdj()+ spacer + getObjec()) document.write("<p>") // -> </script> <p> If you dont see anything above this line, you dont have Netscape 2.0.<br> </BODY> </HTML>
Figure 5.9 illustrates how this page would appear. Figure 5.9 : The Random Talent Generator. When the user loads this page, the script creates three string arrays and fills them in with the strings I provided. It then uses the getVerb(), getAdj(), and getObjec() to get one of the strings in the array based on the number of seconds, minutes, or the average of the two. This is done by taking the number of seconds in the currentdate.getSeconds, dividing it by 6, and then using the Math.floor method to return an integer between 0 and 9.
Since there is no real way to know when someone will visit this page, and the seconds change rapidly, there is a good chance that it will be difficult for someone visiting only once or twice a day to discern that the "Talents" aren't actually random. You also see an example of using the string method fontsize(). The method fontsize() allows you to replace the "<FONT SIZE=''>...</FONT> tags with just a number passed to the fontsize() method. Usually this will be a negative or postive 1. Note that it works fine with the string literal "Magic Talent Generator". We could just as easily have assigned that string to a variable, say titleString, and then used
titleString.fontsize(6)
TIP You may find yourself using many of the same functions over and over in many different scripts. It's good practice to keep a personal library of useful functions so you can find them (and use them!) over and over again.
Customizing User Interaction Using JavaScript Review of HTML Forms o <FORM>...</FORM> o <INPUT> o <SELECT></SELECT> o <OPTION> o <TEXTAREA></TEXTAREA> HTML Objects in JavaScript o Buttons, Checkboxes, and Radio Buttons o Manipulating Text Fields o Validating and Submitting a Form
If you have been reading this book through to this point, you have proven that you have more than just a casual interest in JavaScript (unless, of course, you've happened to open the book to this page while you are in the book store!). This chapter continues with the "object" theme of this part of the book and introduces you to interactive HTML objects. They are interactive in that they allow you to respond in some way to input from someone who visits your site. When you finish this chapter, you should be well on your way to building your first set of JavaScript scripts for your site. Most of the sites that you find today were built using many of the concepts in this chapter. The ability to use forms to lay out input and output areas; buttons to accept questions, replies, or other input; and "back end" JavaScript to interpret that input, you have the beginnings of a full-fledged application. The ability to use the Web browser's GUI (Graphical User Interface) to create small programs very quickly is quite compelling. What you should take from this chapter is the knowledge of building forms, as well as having a new view of forms. Before JavaScript, the form was basically just for typing in responses to questions, or making a selection among some choices. Now, the form can be a template that instantly responds to some action on your Web site vistor's part.
JavaScript is one of the first scripting languages that applies an object-oriented approach (via its roots in Java) to writing and modifying Web pages. JavaScript takes expressions in HTML, such as
<A HREF="http://www.yahoo.com">Yahoo!</A>
and creates an object with methods and properties similar to the ones you read about in chapter 5, "Built-In JavaScript Objects." This chapter and the next take you through the objects in JavaScript that are created and used when you write HTML code-specifically those related to working with HTML forms. Forms provide a key way for you to build a user interface with which you can create miniature "applettes." An example of this is to use HTML forms buttons and text boxes to allow a user to click buttons on a calculator and see the results immediately (see fig. 6.1). (I use the term applettes as an alternative to Java's applet-which is a small program that runs on your browser. JavaScript scripts are smaller, yet might perform many of the same tasks you see in Java. Thus, you can think of them as mini-applets.) Figure 6.1 : A Web site using a calculator in JavaScript. Another example might be for you to create an order form that checks that all of the order fields are filled in correctly and even calculates a running total of the cost of the items ordered (see fig. 6.2). Figure 6.2 : Another Web site, with an order form that automatically calculates your total order. Before JavaScript, the process of creating and validating information that a user entered via a form depended heavily on sending and receiving information from a server-side CGI script. A CGI was possibly used for creating the actual form (generating HTML), validating the information (such as checking that all of the fields were filled in correctly), and sending a response back to the user confirming that the information had been sent successfully. Using JavaScript, you can place much of the work on the client-side, which can reduce dramatically the connection times between the client (the Navigator) and the server (your Web server). In terms of validating form information, you do this by allowing the script to inspect the contents of each field that the user has entered and present an alert to the user if the information does not meet some specific requirements-like too many characters or if the field is empty.
Tag
<FORM ACTION="URL" METHOD="GET"></FORM> <FORM ENCTYPE="multipart/formdata"></FORM> <INPUT TYPE="TEXT"> <INPUT NAME="somename"> <INPUT VALUE="somevalue"> <INPUT CHECKED> <INPUT SIZE=6> <INPUT MAXLENGTH="100"> <SELECT></SELECT> <SELECT NAME="somename"> <SELECT SIZE="6"> <SELECT MULTIPLE> <OPTION>sometext <OPTION SELECTED> <TEXTAREA ROWS="5" COLS="5">...</TEXTAREA> <TEXTAREA NAME="somename">...</TEXTAREA> <TEXTAREA WRAP=OFF>
Meaning Defines a form Uploads a file via a form Input field Field name Field value Checked Field size (in characters) Maximum length of field Selection list Selection list name Number of options in list Multiple selections (more than one) Option Default Option Text area input box size Text area name Wraps the text
<FORM>...</FORM>
These tags must begin and end your form. The following are attributes of the FORM and /FORM tags:
is the location where you want this form to go. is the way in which you send this information. The METHOD is usually POST, but sometimes you can use GET. ENCTYPE is the MIME type of the information you upload to a server. (At this time, ENCTYPE and file uploads are only available with Netscape.)
ACTION METHOD
<INPUT>
This tag creates various input fields. For example, the following:
<INPUT NAME="Address">
allows you to establish an input field for addresses within the form. Pairing this tag with the following attributes allows you to manipulate specific field designations:
NAME is the name of this field. VALUE is the string or numeric value that is sent with this field. CHECKED applies to checkboxes and radio boxes and defines if they
load. determines which type of input this field is. The types are as follows (you can also see some of these types in figure 6.3 and the corresponding HTML code in figure 6.4): o TEXT-A plain text box. o PASSWORD-A text box that echos bullets when you type into it. The bullets hide the typed text. o CHECKBOX-Renders a small box that indicates whether it is selected. Usually for Yes or No questions. They are commonly referred to as checkboxes. o RADIO-Renders a small circle that allows you to choose one among many options. They are commonly referred to as radio buttons. o IMAGE-Returns the coordinates of the image selected here (with x=num, y=num as the parameters returned). This is very similar to imagemaps, but is useful if you want to just return the xy value that someone clicks. The following is an example:
TYPE o o o <INPUT NAME="thisimage" TYPE="IMAGE" SRC="foo.gif" ALIGN="TOP"> (This use of IMAGE doesn't require you to have a resulting map file on your server,
and could be directly sent to a script for interpretation.) HIDDEN-Is not displayed by the browser. Useful for storing special information for the CGI. o SUBMIT-When this is clicked, it submits the form. o RESET-Clears all input fields and resets to the defaults. o SIZE-The size of the input field (in number of characters) for text or password types. MAXLENGTH sets the maximum number of characters to be allowed within a field of a text or password type.
Figure 6.3 : Different input fields-examples of text, password, checkbox, radio button, submit, and reset (and hidden, too). Figure 6.4 : HTML source code of the input fields in figure 6.3.
<SELECT></SELECT>
These tags present either a scrolling list of choices or a pop-up menu. <SELECT> is generated in different ways, based on your choice of options. You can generate a single window that "pops open" to reveal all of the options-from which you can then select one-or you can see a scrolling list of options with up and down arrows much like a regular window-which allows you to see many choices at once. Pull-down windows are best for times when you want someone to choose one option, and it saves screen space. It's best when the number of options are fewer than five or
so. If you have more than five, you should set the SIZE attribute to show the first five (or less) and allow the user to scroll through the rest. The following lists the attributes you use with <SELECT>. Try out many variations on a test Web page to see how changing the attributes changes the way the list is shown:
is the name of the data (required). determines how many choices to show. If set to 1 or omitted, it renders a pop-up menu. If set to 2 or more it is a scrolling list. MULTIPLE allows you to select multiple options and always renders a scrolling list.
NAME SIZE
TIP An often underutilized way to use this form element is to place a caption to an image just under the image with <SELECT SIZE=1> and the caption text insideone line to an <OPTION>. The result is a nice "pop-open" caption that allows you to use that saved space in other ways. Note though that the bar will be as wide as your longest line in the <OPTION> list.
<OPTION>
Contained within the SELECT and /SELECT tags, this tag designates a selectable item. The following list describes the attributes an <OPTION> might have:
VALUE is the value returned when the form is submitted if this option was selected. SELECTED means when the page is loaded, this option is selected by default.
<TEXTAREA></TEXTAREA>
These tags provide an area for a user to enter multiple lines of text. This defaults to four rows in length, with each row 40 characters wide. The following list describes each attribute you might use in a TEXTAREA tag:
defines the name for the information (required). is the number of rows in this field. is the number of characters wide this field is. determines how text flows inside a text area. You have three options for this attribute (you can see examples of WRAP in figure 6.5 and the corresponding HTML code in figure 6.6): o OFF-No text wrap. o VIRTUAL-Text flows to right border then wraps to next line. It will be submitted as one line, without new lines. So although the text appears to wrap, it will be one line when sent to the server (or script). o PHYSICAL-Text flows beyond right border beyond the text area window. When it is submitted, the text will be wrapped based on any new lines.
NAME ROWS COLS WRAP
Figure 6.5 : Two examples of select fields of different sizes. Figure 6.6 : HTML source code for figure 6.5.
The new attributes you might notice are TARGET and onSubmit. TARGET specifies the window that the responses go to. The event handler onSubmit is optional. The text listed in the handlerText is evaluated when you submit this form via the SUBMIT button or use the submit method in another part of your script. Once you have created this object, you can address its properties and methods in the following way:
2
formName.propertyName formName.methodName(parameters) forms[index].propertyName forms[index].methodName(parameters)
JavaScript places each form it finds in a page in an array called forms. You can access each form by either its index in this array (with the first form at 0, the next at 1, and so on) or by its name. For example,
<form name="thisform"> <input type=text name="input1" value="hi there!"> </form>
By doing this you create an object called thisform which also exists as document.forms[0]. Figure 6.7 illustrates a review of the object hierarchy to display where a form object lies in relation to the other objects generated by JavaScript. Figure 6.7 : The JavaScript object hierarchy, showing the relationship between each object and its "container" (higher level objects). You can access individual fields in this form-where you can either read that field directly or send a new value to that field-which might (depending on the type of input field) dynamically change on the screen. To access information about this form, use the following naming conventions:
formName.action-From the ACTION argument formName.elements-To get to the input (etc.) fields formName.encoding-From the ENCTYPE argument formName.method-From the METHOD argument formName.target-From the TARGET argument
The button Object The button object is a new type of INPUT tag that allows you to create general purpose buttons in a form. You can use these buttons to activate any function, or to open a new URL, or perform any other action that JavaScript can initiate. To define a button object use the following syntax:
<INPUT TYPE = "button" NAME =" nameInside" VALUE = "nameOnButton" [onClick = "handlerText"]>
This is an extremely useful object, and you will probably find yourself using this often to create buttons to run scripts, open new windows, or even cause the browser to leave your Web site altogether! You must use this inside a set of FORM.../FORM tags. You access a button's properties and methods in the following way:
buttonName.propertyName buttonName.methodName(parameters) formName.elements[index].propertyName formName.elements[index].methodName(parameters)
For example, listing 6.3 creates a page that looks like figure 6.8. Upon clicking the button, you will see an Alert dialog box that looks like figure 6.9. Figure 6.8 : Web page with alert button example. Figure 6.9 : Here's the alert!.
You can access the properties of the button object in listing 6.3 by using one of the following:
document.forms[0].elements[0].name
or
alertbutton.name
If you want to retrieve the name of the button as a string object, you could use either of the examples below, which would return "Click Me!":
document.forms[0].elements[0].value
or
alertbutton.value
NOTE Once you have created a button object you can change its value, but the text on the button does not change to reflect this. This is because the button was written to the screen when the page was loaded and cannot be changed unless the page is reloaded. And reloading the page alone does not implement the change, since the button reverts to its default value in the HTML code when it is reloaded. The only way to change this value is to set the value equal to some variable that can persist across page reloading. For more information on how to do this, see chapter 12, "More About Java." The checkbox Object The checkbox object is created inside a form and appears as a small box with or without a mark (usually an x) inside it. Think of a checkbox as an On/Off switch. A user can flip this switch on or off by clicking his mouse inside this box. Clicking here can also trigger an onClick event in your script. You create a checkbox via the syntax in listing 6.4.
Accessing the properties of this object is very similar to accessing the properties of the button object. The properties are as follows:
2
CHECKED indicates true or false to specify if the checkbox is checked. DEFAULTCHECKED indicates whether or not the checkbox was marked checked
upon page
load.
NAME indicates the name of the checkbox. VALUE indicates the value that is returned by
defaults to On.) Listing 6.5 is an example of using the checkbox object in a script (see fig. 6.10). Figure 6.10: Web page with checkbox.
When you click the checkbox so that it is checked, you will see something like what is shown in figure 6.11. If you then "uncheck" it, you will see an alert box like that shown in figure 6.12. Figure 6.11: Once the checkbox is checked, you see this alert. Figure 6.12: Clicking the checkbox off will give you this alert. The radio Object This object allows a user to make a choice of a single selection from many. Usually this is a list of related items from which you wish the user to pick only one choice. The radio object is very similar to the checkbox object, except that a series of radio objects with the same NAME attribute toggle all of the radio buttons off except for the one that was picked. In other words, when you click one radio button in a group of related buttons, all of them will be off except for the one you clicked. You create a radio object using the syntax in listing 6.6.
2
<INPUT TYPE="radio" NAME = "radioName" [CHECKED] [onClick = "handlerText"]> textToDisplay
Accessing information from the radio object is slightly different than from the checkbox object. Since all of the radio buttons of a given group have the same NAME attribute, you access individual radio buttons by adding an index value to the NAME. The format for doing this is as follows:
radioName[index1].propertyName radioName[index1].methodName formname.elements[index2].propertyName formname.elements[index2].methodName
You can click a specific radio button in JavaScript by using the following:
radioName[index1].click
Listing 6.7 is an example of using radio buttons with JavaScript. The result is shown in figure 6.13. Figure 6.13: Web page example of using radio buttons to constrain user input.
This piece of code allows a user to pick one of the three choices-rock, paper, or scissors-which then shows up in the text field box. If the user wants to choose a fourth alternative, say bomb, then she just has to type it in to the box. This is a quick way for you to offer both a series of preset choices, as well as allow a user to place her own customized choice.
This section gives you experience working with the text-based input fields in an HTML form, and shows how you can use JavaScript to enhance these input fields' usefulness to you as a script writer. The hidden Object Often when you create an interactive form, you want to keep some information hidden, yet still pass this information on to the server when the form is submitted. This is often information about the user-perhaps when he last accessed your page, or some preference that he had set in the previous form that generated this one. You can keep track of this information with hidden fields. This field is often used in place of Netscape's "cookies" for compatability to browsers that do not support the cookie specification. Hidden fields contain text information and are not displayed on the screen with the rest of the form. Netscape cookies are small strings of text stored in your cookies.txt file. They are often used to store information about you or your computer that is used by various sites to "remember" some bit of information about you between visits to that Web site. The server writes this code to your machine and will reread it when you visit again. Although this feature is very useful, there are still debates as to its security and validity of use. To create a hidden object, use the following syntax:
<INPUT TYPE="hidden" NAME="hiddenName" [VALUE = "textValue"]>
You can access the properties of this object by using the following:
hiddenName.propertyName formName.elements[index].propertyName
When you use hidden fields, it adds a sense of "state" to the Web. What this means is that usually a Web site has no real way of knowing if a visitor to that Web site had just been there moments ago, or if he is visiting for the first time. Using the hidden field, you can place a hidden reminder to yourself (you as the Web site) on the page he receives-such as a timestamp-and retrieve that reminder whenever he submits that form to you for more information. This is very similar to the process one might go through to enter a parking lot, pick up a tag, then return that tag when you leave. Your server can read that hidden field into a CGI script and respond to the user of the page with something like "Welcome Back! Here's what's changed since you were here last!" Another use might be that of a hidden field in a Web-based game which stores the current score, location, and state of a player. This information is sent back to the game engine every time the player moves to a new location.
The password Object The password input field in a form is very useful for those times when you need to create a logon screen and keep the password of that logon hidden from view or from being printed by some malicious user who sees the login screen. Any time you want the information hidden from sight as a user types that information on the screen, use the password input field. To create this as an object in JavaScript, use the following syntax:
<INPUT TYPE="password" NAME = "passwordName" SIZE=integer [VALUE = "textValue"]>
Accessing the properties and methods of this object once it is created is identical to previous examples and is as follows:
passwordName.propertyName passwordName.methodName(parameters) formname.elements[index].propertyname formname.elements[index].methodname(parameters)
The password object uses the focus, blur, and select event handlers as methods. Let's say you want to check the validity of a password before a user actually sends it back to the server for a login. You can create a function that checks the password and notifies the user if he entered an invalid password. See listing 6.8 for an example.
Try again.")
NOTE Don't confuse the password object with the hidden object. The password object conceals what a user types in to a text entry field, while a hidden object simply hides the whole field. Both input types in some way hide information. The text Object The text input field in an HTML document is your workhorse for inputting many types of information. Most other types of input in forms are derivations of this kind of input.
The text input field is simply a small box of a set size that contains a cursor when you click it. It allows a user using the form to type in information such as a name, a date, or any other kind of information. If the text a user types is too long for the box, it scrolls to the left to accomodate the additional text. In JavaScript, this field serves a new and exciting purpose. Not only can a user using the form enter information into this field, but the script itself can enter information as well. In chapter 5 you saw a script that used this field to display a constantly changing digital clock. You create a JavaScript text object using the syntax in listing 6.9.
The text object properties reflect the information you provide in the tag when you create the object. Table 6.2 is a listing of those properties with an example of how you would access them. Table 6.2 text Object Properties Example Description myText.defaultValue The value of the input tag at page load time myText.name The NAME argument
formName.elements[0].value
Property
defaultValue name value
You can act on this object in a number of ways, either indirectly by another function, or directly by using the event handlers contained in the object. Tables 6.3 and 6.4 list the methods and event handlers associated with the text object. Table 6.3 text Object Methods Example Description
Method
Equivalent to clicking this field blur myText.blur() Equivalent to clicking another field after using this one select myText.select() Equivalent to dragging the mouse across all the text in this field-selecting it Table 6.4 text Object Event Handlers Event Handler Example Description onBlur <input type=text Runs "alert()" when onBlur="alert('blur!')"> focus leaves this field onChange <input type=text Runs "alert()" if the text onChange="alert('changed')"> has changed whenfocus leaves this field onFocus <input type=text Runs "alert()"when user onFocus="alert('start clicks in (or other-wise typing!')"> gives focus to)this field. onSelect <input type=text Runs "alert()" once "alert('text selected!')"> onSelect =some text in this field is selected The script in listing 6.10 places information about a link in a text field below a series of links when a user passes the mouse over each link. This illustrates how you can use other event handlers to pass information to a text field (see fig. 6.14). Figure 6.14: Using onMouseOver, you can display different text in a text field.
focus
myText.focus()
As you pass your mouse over each link-one, two, or three-you see that the text in the text field changes as well. You can easily modify this code to display helpful information about links on your own page beyond the URL that displays at the bottom left of the Netscape Navigator (which is called the status area). The textarea Object When you need a user to input more than just one line of text in a form you use the textarea input type. This is the case if you are providing to the user an e-mail feedback form and want to allow space for the user to type in a lengthy note. To create a textarea object in JavaScript, use the syntax shown in listing 6.11.
A textarea object uses essentially the same attibutes, methods, and properties as does the text object (see tables 6.2, 6.3, and 6.4). You can provide default text to display in this field by adding text between the TEXTAREA.../TEXTAREA tags. Long Example: Foobar the Bazbarian I use the textarea input field in a game I wrote called Foobar the Bazbarian. In this game, the user can click buttons to go north, south, east, and west, and pick up various objects along the way to eventually win the game. The game itself is very simple in its concept, and is long in implementation only because of the many pieces of text input that can be displayed in the textarea window. In a way, this completely turns around the concept of a textarea from one in which you require a user to input long lines of text to displaying something like a miniature computer terminal. Listing 6.12 shows this program's code and figure 6.15 provides a sample display of how it might look on a Web page. Figure 6.15: Web page view of Foobar the Bazbarian.
2
//variable declarations var location="0" var locDesc= new StringArray(16) var zero=0 var bonus="10" locDesc[0]='You are standing at the edge of a small island. Palm trees sprout everywhere and obscure your view to the East and South. The beach is bordered on the North and West' locDesc[1]='The beach is to the West. You see the remains of your wrecked ship here. The forest is to the East and the beach goes North and South.' locDesc[2]='The beach is West of you. At the edge of the forest stands a silver cage with a beautiful princess who becons for you to unlock the cage.' locDesc[3]='The beach lapps at you from the West and South. The palm trees to the North and East sway in the wind. You hear screaming to the North.' locDesc[4]='The ocean borders the North. On the beach you see empty coke cans and various other washed up trash. ' locDesc[5]='You are surrounded by palm trees. A monkey waves a you. You hear screaming to the South.' locDesc[6]='In a clearing, you see a golden cage with a georgeous princess waving at you. She begs you to find the key and let her free.' locDesc[7]='The beach borders to the South. There are graves here with names of other warriors like yourself who failed...' locDesc[8]='The beach borders the North end of the island. The wind blows fiercer here.' locDesc[9]='You are in the midst of palms. Footprints dot the sand in all directions.' locDesc[10]='A woman screams to the West. Sharp rocks hurt your bare feet as you wander...' locDesc[11]='The beach borders the Southern end of the island. You hear a strange sound to the East, like a storm in the distance.' locDesc[12]='You see a chest full of gold, jewels and many other things. Your search reveals....' locDesc[13]='The beach stops you short to East. There are the remains of a campfire here.' locDesc[14]='Bones litter the beach to the East. They look human. You hear a sound like rushing wind to the South. Palms trees obscure your view.' locDesc[15]='A large green Dragon turns to look at you as you enter the clearing. Its growl is like a Mac Truck stuck in high gear.' // functions function StringArray (n) { this.length = n; for (var i = 1; i <= n; i++) { this[i] = '' } return this } function initgame(){ var intro = "Welcome to Foobar the Bazbarian! \r\nClick on buttons to navigate\r\nClick RESET to start over\r"
2
document.forms[0].dialogbox.value=intro+locDesc[0] document.forms[5].score.value=zero document.forms[5].itemhere.value="None" document.forms[5].your1.value="Empty" document.forms[5].your2.value="Empty" document.forms[5].your3.value="Empty" document.forms[5].your4.value="Empty" location=0 } function upscore(addscore){ oldscore=document.forms[5].score.value; num1=parseFloat(addscore); num2=parseFloat(oldscore); newscore=num1 + num2; document.forms[5].score.value=newscore } function changeLocation(index){ force=parseFloat(location) + parseFloat(index); location=force; if (location==0){ document.forms[0].dialogbox.value=locDesc[0]; document.forms[5].itemhere.value="None"; } if (location==1){ document.forms[0].dialogbox.value=locDesc[1]; document.forms[5].itemhere.value="None"; } if (location==2){ document.forms[0].dialogbox.value=locDesc[2]; document.forms[5].itemhere.value="None"; } if (location==3){ document.forms[0].dialogbox.value=locDesc[3]; document.forms[5].itemhere.value="None"; } if (location==10){ document.forms[0].dialogbox.value=locDesc[4]; document.forms[5].itemhere.value="None"; } if (location==11){ document.forms[0].dialogbox.value=locDesc[5]; document.forms[5].itemhere.value="None"; } if (location==12){ document.forms[0].dialogbox.value=locDesc[6]; document.forms[5].itemhere.value="None"; } if (location==13){ document.forms[0].dialogbox.value=locDesc[7]; document.forms[5].itemhere.value="None"; } if (location==20){ document.forms[0].dialogbox.value=locDesc[8]; document.forms[5].itemhere.value="None"; } if (location==21){ document.forms[0].dialogbox.value=locDesc[9];
2
document.forms[5].itemhere.value="None"; } if (location==22){ document.forms[0].dialogbox.value=locDesc[10]; document.forms[5].itemhere.value="None"; } if (location==23){ document.forms[0].dialogbox.value=locDesc[11]; document.forms[5].itemhere.value="None"; } if (location==30){ document.forms[0].dialogbox.value=locDesc[12]; document.forms[5].itemhere.value="Key"; } if (location==31){ document.forms[0].dialogbox.value=locDesc[13]; document.forms[5].itemhere.value="None"; } if (location==32){ document.forms[0].dialogbox.value=locDesc[14]; document.forms[5].itemhere.value="None"; } if (location==33){ document.forms[0].dialogbox.value=locDesc[15]; document.forms[5].itemhere.value="None"; pit(); } if (location != 0 && location != 1 && location != 2 && location != 3 && location !=10 && location !=11 && location !=12 && location !=13 && location !=20 && location !=21 && location !=22 && location !=23 && location !=30 && location !=31 && location !=32 && location !=33 ) { alert ("You cant go there! The water blocks your way."); location=parseFloat(location) - parseFloat(index); } //alert(force + " and location" + location); } function takeItem(){ if (document.forms[5].itemhere.value != "None") { document.forms[5].your1.value=document.forms[5].itemhere.value; upscore(bonus); } else { alert("There's nothing here!") } } function useItem(itemtouse) { if (itemtouse == "Key" && location == 2) { document.forms[0].dialogbox.value="You Win! The Princess gives you a big Kiss, and Hillary reluctantly returns you to the land of Bat....\rYAY!" upscore(1000); } else { if (itemtouse == "Key" && location == 12) { document.forms[0].dialogbox.value="You picked the
2
wrong Princess. The Witch cackles as bolt of flame at your head. You Die!" document.forms[5].score.value=zero } else{ alert ("I cannot use that here"); }} } function pit() { document.forms[0].dialogbox.value= document.forms[0].dialogbox.value + "\rDid I forget to mention the Dragon? Oops. This huge monster thunders up and takes a big bite out of your face. You die." document.forms[5].score.value=zero } // end Functions // end The Engine --></script> <h1 align=center>Foobar the Bazbarian!</h1> <table border align=left><tr><td colspan=2><form><!-- form 0 --> <textarea rows="10" cols="50" name="dialogbox" wrap="virtual"> </textarea></form><tr><td><h4 align="center">Movement</h4> <table border ><tr><td></td><td><form><!-- form 1 --> <input type="button" Value="North" Name="GoNorth" onClick="changeLocation(1)"> </form></td><td></td><tr><td><form><!-- form 2 --> <input type="button" Value="West" Name="GoWest" onClick="changeLocation(10)"> </form></td><td align=center><B>GO</B></td><td><form><!-- form 3 --> <input type="button" Value="East" Name="GoEast" onClick="changeLocation(10)"> </form></td><tr><td><tr><td></td><td><form><!-- form 4 --> <input type="button" Value="South" Name="GoSouth" onClick="changeLocation(1)"> </form></td><td></td></table> <td valign=top><form><!-- form 5 -->Your Score: <input type="text" name="score"><br> Items Here: <input type="text" name="itemhere"><br> Your Items:<br> <input type="text" name="your1"><input type="button" Value="USE" Name="use1" onClick="useItem(document.forms[5].your1.value)"><br> <input type="text" name="your2"><input type="button" Value="USE" Name="use2" onClick="useItem(document.forms[5].your2.value)"><br> <input type="text" name="your3"><input type="button" Value="USE" Name="use3" onClick="useItem(document.forms[5].your3.value)"><br> <input type="text" name="your4"><input type="button" Value="USE" Name="use4" onClick="useItem(document.forms[5].your4.value)"><br> <input type="button" Value="TAKE ITEM" name="takeme" onClick="takeItem()"> <input type="button" Value="QUIT" name="quitme" onClick="history.go(- 1)"> <input type="button" Value="RESET" name="resetme" onClick="initgame()">
she shoots a
2
</form></table><p><font size="-1">Created and copyright Andrew Wooldridge</font><p> <hr align="50%"> You are FOOBAR, the Bazbarian from the land of Bat. You and the Princess of Zfoeps have been kidnapped by the Wicked Witch Hillary. As a challenge, Hillary has imprisoned herself and the Princess in two cages. You must search this small island to free the Princess! Search around and find the key to unlock her cage. If you let out the wrong girl you die! If you free the Princess you win! Click RESET to Start. <br clear=left> Email me if you find a bug. <a href="mailto:[email protected]">[email protected]</a> </BODY> </HTML>
You access this object's properties and methods by the following syntax:
submitName.propertyName
When you click a submit button, it always loads a new page-even if that page is the same page you were already on. This is useful in that you can use a form to change attributes of the current page and see them change when you submit the form. The submit object uses the onClick event handler and can be clicked by using the submitName.click method.
The reset Object The reset button allows a user to completely reset a form's input fields to their defaults. You create a reset object in JavaScript by using the following syntax:
<INPUT TYPE="reset" NAME="resetName" VALUE="buttonText" [onClick ="handlerText"]>
To access its methods and properties, you use the same familiar syntax, as follows:
resetName.propertyName
The reset button uses the same onClick event handler and click method as the submit object. A Simple Form Validation Example Listing 6.13 is a simple script that checks all of your input to see that you have placed the correct information inside each field. It then submits the form.
From the example in listing 6.13, you can see how an input of type button was used in place of an input of type submit. In a real-world script, you could either use a button input type with an onClick event handler which would then run a check on that specific field, or you could keep the submit button and use an onSubmit event handler to run checks on all of the input fields at once. The difference here is that when you use onClick and the button, you can be more specific as to which area you are checking; whereas, using the more general onSubmit, you can check all the fields at once without asking the visitor to check them.
Link In with JavaScript o Additions to the LINK Syntax o Properties of the LINK Object o The NAME Attribute has New Significance o LINK Events: onMouseOver and onClick o Change Link URLs, Not the Displayed Text o Display Documents in Frames and Windows Creating and Using Anchors o Your HTML Elements o Anchor Any Text or Element Selection or Scrolling-Your Option o Syntax in Review o onChange, onBlur, and onFocus Events for SELECT o Dynamically Change the Selection, Not the Text Example: An Application Using Advanced Navigation o Expand the View with Frames o Objects for Tri-Eye o Dynamic Links o Anchors to Complete the Story o Other Possible Improvements to and Uses of Internet Tri-Eye Example: Tri-Eye FTP Auto Dialer
Your users will demand quicker response time as you add more interactivity to your pages. Before JavaScript, most interactive features required your Web page to invoke a CGI script on the server. The more interactivity, the more the users have to wait on the server to deliver new documents. The response time improves dramatically as JavaScript handles interactivity on the browser side instead of waiting on CGI scripts. To meet this increasing demand for better response time, you will increase the size of your Web documents with JavaScript. This is because your pages are more like applications and less like plain reading material. As your document gets larger, you will incorporate more navigational aids. You will create dynamic elements with JavaScript to let users quickly see the
material they want and skip irrelevant information. And you will do this without waiting on the server. Controlling the flow of user interaction is critical to good design. You can confuse your users with the multiple windows and frames possible in the new browsers. The dynamic capability of JavaScript allows you to create new documents in response to your users' preferences. For example, if the viewer selects a favorite sport, the hyperlink named "Last Year's Champion" could vary based on the viewer's selection. With JavaScript features, you can transform the browser from static displays to interactive applications. There are a variety of examples in this chapter which let you try out the new dynamics of hyperlinks, anchors, and selection lists. The chapter concludes with a much larger application that shows you the possibilities of the new browser.
Your browser would display "Click here" as a hyperlink. The reference of a LINK is a URL or a location. You know the World Wide Web protocol, which is http:// as you see in the preceding example. You could also have used the MailTo protocol (for example, mailto:[email protected]). There are formats for FTP, Gopher, and File. JavaScript makes two additional protocols available: javascript: and about.
javascript: protocol A new URL type is now defined in JavaScript for the LINK tag. The protocol is simply javascript:. For example, you could specify javascript: history.go(1) as the URL. When used as the URL for a LINK, the browser executes the statement following the colon. In the following example it executes: history.go(-1). As a useful example, try adding the following line to any page:
<A HREF="javascript: history.go(-1)">Go back to previous page</A>
This is particularly useful on documents displayed in browser windows where you have disabled the toolbar. When you click this hyperlink, the browser takes you back to the previous page in your history list. If you want to test this, open your browser and load your default home page. Then load the page in listing 7.1 called history.htm on the CD-ROM. Clicking the hyperlink returns you to your default home page.
Hyperlinks can also behave like buttons in forms. Instead of placing a function in an onClick event, place the function behind the javascript: protocol. Clicking the hyperlink will have the same effect as clicking a button. In other words, replace the following code for a button in a form:
<INPUT TYPE="botton" VALUE="click here" onClick="myfunction()">
Now let's take this a step further and replace the grey, rectangular JavaScript button with your own colorful icons. Again, use the javascript: protocol, but this time use it with the IMG tag. Here's some sample code:
<A HREF="javascript: myfunction()"><IMG SRC="youricon.gif"></A>
This gives you the ability to make your own shape, size, and color buttons! Imagine how bright and colorful a simple calculator can now appear. The code for creating a button, a text link, and an icon is in listing 7.2. Pressing any one of these items produces the same result.
You can take this concept one step further by using imagemaps. Imagemaps are graphics with active areas. Click one area and you link to one site, click another part of the image and you link to another. Geographical maps and directories are common uses of imagemaps. When coding an imagemap you use URLs to instruct the browser. By substituting in the javascript: protocol, you can now create imagemaps that execute various JavaScript functions instead of jumping to another location. Prior to Netscape Navigator 2.0, all imagemaps were executed on the server. Now you can create client-side imagemaps where the browser does not need to wait on results from the server. Click an image and the browser immediately executes the instruction. Coding an imagemap requires that URLs be specified for various regions of the image. With client-side imagemaps, you can substitute the javascript: protocol. Clicking the imagemap can now execute JavaScript functions as well as jump to locations specified in URLs. NOTE To enable client-side imagemaps, Netscape introduced a new attribute to the IMG element called USEMAP (see http://home.netscape.com/assist/net_sites/html_extensions_3.html). It is added to the IMG tag to tell the browser to invoke client-side imagemapping by reading information from a MAP element. The syntax is:
<IMG SRC="yourimage.gif" USEMAP="yourfile.html#mapname">
NOTE where mapname is the name of a MAP element in the document called yourfile.html. The MAP element must have a name in order to be referenced by the USEMAP
attribute. Contained within the MAP element are AREA tags. A MAP element usually contains more than one AREA tag, one for each different region of the imagemap. The syntax is:
<AREA [SHAPE="shape"] COORDS="x,y,..." [HREF="reference"] [NOHREF]>
NOTE where shape can be RECT (retangles), POLY (polygons), CIRCLE (circle), and DEFAULT (default). COORDS specifies the points that define the shape. You then have the option to specify an action using the HREF attribute. Or you can specify no action using NOHREF. In JavaScript, you can specify the reference to use the javascript: protocol. For example, this code defines a rectangular area where the browser loads the previous page from the history list:
<AREA SHAPE="rect" COORDS="0,0,100,50" HREF="javascript:history.go(-
You can have the browser take you to new locations, execute a JavaScript statement, or a JavaScript function. Your Web pages are more alive than ever now. Listing 7.3 shows a script for creating a client-side imagemap with the javascript: protocol.
CAUTION A javascript:xxx() call replaces a URL. The browser tries to interpret any return from a function call as if it were a URL. If the browser does not understand the return value, it reloads the current page. When that occurs, any window globals that you set during the xxx() function call will be lost. The other new protocol is the about: protocol. When used as a location for a link, it provides Navigator information (see listing 7.4, which can also be found in the about.htm file on the CD-
ROM). In its basic format without any arguments, it is the same as selecting About Netscape from the Help menu. When used with the plug-ins argument, the page displayed is the same as About Plugs from the Help window. The last usage is with the argument cache which is supposed to display the disk cache statistics. NOTE On Windows NT, this features does not work. N Listing 7.4 about.htm Demo of about: Protocol
<HTML><HEAD><TITLE>about.htm by Ray Daly</TITLE> </HEAD><BODY> <P>Demo of the <I>about:</I> protocol: <UL><LI><A HREF="about:">about:</A></LI> <LI><A HREF="about:cache">about:cache</A></LI> <LI><A HREF="about:plug-ins">about:plug-ins</A></LI> </UL><P> </BODY></HTML>
2
document.write( "<BR>target = " + document.links[0].target) document.write( "<P>>The LINK[0] has no hash. ") document.write("Howver the LINK[1] has:<BR>") document.write( "hash = " + document.links[1].hash) document.write("<BR><BR>The numbr of links is the length = ") document.write( document.links.length) </SCRIPT></BODY></HTML>
In using this format, you need to know the index number. The index number is assigned to each LINK object in sequence as it is loaded by the browser. The first link loaded has the index of 0, the second is 1, and so on. So you need to keep track of the order in which the LINK objects are loaded. This is the default method of accessing properties. Often, a simpler means is to name the elements that are referenced by your JavaScript code. Therefore, using our first example, add the NAME attribute:
<A NAME="myname" HREF="http://www.yoursite.com">Click here</A>
Now your JavaScript code can access the properties of this object without having to know the index number. Simply use the following format:
document.name.propertyName
Using the NAME attribute is probably familiar to you if you have used anchors in your HTML documents. It is the identical format and is still how you create anchors. So whenever you use the NAME attribute for your JavaScript code, you are also adding a new anchor.
statement return true. The format is the same as for other events. Use our example, as follows:
<A NAME="myname" HREF="http://www.yoursite.com" onMouseOver="window.status='Please visit my site.'; return true"> Click here</A>
This places the message Please visit my site. in the status bar when the viewer places the mouse pointer over the hyperlink. This overrides most browsers that would display the URL in the status bar in this event. You can use this feature to change the look and feel of your pages. Instead of showing the URL, which is geek talk to many, change your links to verbally tell people where the links take them. So instead of displaying something like
http://www.cris.com/~raydaly/sponsors.html
you can display an easier to understand message in the status bar, such as
Hyperlink to "Sponsor of the Day"
The onClick event uses the same format. Also, the example application for this chapter makes frequent use of the onClick event. The following is a short example:
<A NAME="mymessage" HREF="http://www.newsite.com" onClick="alert('Thanks for visiting. Enjoy the new site.')"> Visit Newsite</A>
This code displays an alert dialog box prior to jumping to the new site (see fig. 7.2). Only after the user clicks OK in the dialog box does the browser hyperlink to www.newsite.com. Figure 7.2 : You can display a dialog box prior to hyperlinking to a new site. CAUTION The onMouseOver event is trapped at each boundary of a link. This results in an event occuring twice as the point enters and leaves the link. If you use the onMouseOver event to write to the status bar, you find that if you move your mouse too quickly you miss the status write. This is because it is rapidly replaced by the browser's own response to the event. When you exit, the status written stays there until you encounter another link. If you want to use the content of your link in a function called from an onMouseOver handler, you can pass the function the keyword this. Links are treated like any other JavaScript object. CAUTION
You might confuse your users by changing the HREF using onClick. Users often look to the status bar to see the URL that the hyperlink will take them to. When you assign the HREF attribute of the LINK, it is displayed in the status bar. When using the onClick event you can set the HREF to a different URL. By reading the status bar the user may assume he is going to the first URL, but instead your JavaScript code takes him to the URL specified by the onClick statement. In the following example, the status bar makes it appear that the link is to Yahoo's site, but the code takes you to Infoseek. It goes to show that you cannot even trust links anymore.
<A NAME="searchme" HREF="http://www.yahoo.com" onClick="this.href='http://www.infoseek.com'"> Search Internet for a Topic</A> To avoid such a deception in the status bar, just add onMouseOver
to change the contents of status bar. For the preceding example, just insert the following as the second line:
onMouseOver="window.status='Will take you to a search engine.'; return true"
2
//...all other times use test mode yahooURL = "http://www.yahoo.com/text/" //...result of function is a URL } </SCRIPT></HEAD> <BODY> <A NAME="yahooLink" HREF="" onClick="this.href=timeText()" //...get the right URL onMouseOver="window.status='Hyperlink to Yahoo!'; return true"> Yahoo!</A> </BODY></HTML> } return yahooURL
The URLs are not just for the Web. For example, suppose you have a fairly lengthy form to be completed by a customer, and one of the first entries asks about the customer's location. Based on that entry, you might dynamically change the mailto address. Then any e-mail the customer might send is directed to the proper salesperson. Listing 7.5 asks the user where he is located. (This code is included on the CD-ROM as atlmail2.htm.) Based on his selection, e-mail goes to a different address. Figure 7.3 shows the result of listing 7.7. Figure 7.3 : Depending on the selection, e-mail goes to a different address. Remember to include a default address or use a dialog box to ask the user to make a choice before trying to send e-mail.
A frame is the other possible target for your link. Frames divide your browser window into two or more areas. Inside these frames you can display standard Web pages or create your own documents. The applications constructed in this chapter use frames. The following code displays the Yahoo! page in the frame labeled "three."
<A HREF=" "onClick="this.href=http://www.yahoo.com" " picture Tri</A> TARGET="three">Show
Windows and frames are often a vital part of a design with dynamic links. Using JavaScript code behind a link, you can build new types of browsers. You can also build new tools. For example, you might bring a page into a frame, analyze it, and display the results in another frame. One area of a frame is often like a control panel that can control the display in another. For example, researchers constantly use different search engines on the Web, and these sites are bookmarked. But it would be handier if these sites were always available like the Directory buttons in Netscape Navigator. Listings 7.8, 7.9, and 7.10, (called searchdr.htm, display.htm, and search.htm on the CD-ROM), show how the top frame contains one line with hyperlinks to eight different search engines. This frame is like a control panel with the documents targeted at the lower frame. Figure 7.4 shows the result. Figure 7.4 : SearchDr puts any of the listed search engines in the frame marked Display. When you create frames, let the default frames provide instructions to the new users.
2
<A HREF="http://www.mckinley.com/" TARGET="display">Magellan</A> -<A HREF="http://www.nlightn.com/" TARGET="display">NlightN</A> -<A HREF="http://www.opentext.com:8080/" TARGET="display">Open Text</A> <A HREF="http://www.webcrawler.com" TARGET="display">WebCrawler</A> -<A HREF="http://www.yahoo.com" TARGET="display">Yahoo!</A> </BODY> </HTML>
For a more substantial example, we will construct an application in this chapter called Internet Tri-Eye. It will truly give you a different view of the world. In listing 7.11 and its corresponding figure 7.5, you see the frames used in creating Internet Tri-Eye. This code can be found in the file trieye.htm on the CD-ROM. Figure 7.5 : The frames used to create Internet Tri-Eye will contain the control panel at the bottom and display Internet camera pictures from around the world. The contents of frames can be .GIF and .JPEG files as well as HTML documents. Although this will be displayed using your browser, it is not the same old browser anymore. Frames and dynamic hyperlinks let you reshape the browser.
take them right to the information instead of being required to scroll through your page. Anchors help you deliver your information more directly.
Note that the name does not have to be the same as the text. In this example the name is jumphere, and the text displayed by the browser is "Part Two." To create the hyperlink to this section, use the following code:
2
<A HREF="#jumphere"> Go To Part Two</A>
This is useful not only within the current document, but also when pulling up information within frames or in other windows. For example, take the case of a form in which you are verifying the input. You would probably use a dialog box to notify the viewer that the input is out of range; then use an anchor at the description of the text box, and link the browser to it with hypertext. Now the text box is right at the top of the screen awaiting a new input. NOTE You can use the anchor to scroll the page to the place you want. The FOCUS and the SELECT methods can do the same with form elements. However, if your form elements have labels, these methods will move the element to the top of the screen cutting off your label. If you want your users to be able to read the labels, anchor the labels and jump to them For comparison, both techniques are used in the code formname.htm on the CD-ROM (see listing 7.12 and fig. 7.7). n Anchors can also provide you with a new way to control the flow in completing a form, as shown in listing 7.12 and figure 7.7. Many times in completing paper forms, you see such instruction as "If you answered NO to question 6, skip to question 9." With JavaScript and anchors, you can look at the response to a question, then-depending on the answer-automatically jump to the anchor for the next appropriate question. Figure 7.7 : You will see a visual difference in comparing the use of anchors to control the flow or the use of the FOCUS and SELECT methods.
2
FREE Overnite shipping when ordering 12 or more.<BR> <INPUT NAME="q1" TYPE="Text" onBlur="skip2(this.form)"><BR> <a NAME="a2"> <B>2.) How do you want it shipped?</B><BR> <INPUT NAME="q2" TYPE="Text" ><BR> <BR><BR><BR><BR><BR><BR> <I>(more questions are listed here) <BR><BR><BR><BR><BR><BR> <BR><BR><BR><BR><BR><BR> <B>12.) What color do you want?</B><BR> <A NAME="a12"><INPUT NAME="q12" TYPE="Text" ><BR> <BR><BR><BR><BR><BR><BR> <I>(more questions are listed here) <BR><BR><BR><BR><BR><BR> <BR><BR><BR><BR><BR><BR> </FORM> </BODY></HTML>
TIP When debugging your JavaScript, check your quotes. Although double quotes and single quotes work the same, you cannot start with a double quote and end with a single quote, or vice versa. Your quotes must match or you will end up with errors several lines later.
Syntax in Review
Although using the SELECT element makes it easier for your viewer, you have to do more work. Remember, SELECT is an element within a form, so it must be between the <FORM></FORM> tags. The syntax of SELECT is one of the most complicated of all the HTML elements. You should be familiar with most of this specification. To support JavaScript you can optionally include event handlers of onBlur, onChange, and onFocus (see listing 7.13).
Listing 7.13 Using onBlur, onChange, and onFocus with the SELECT Element
2
<SELECT NAME="selectName" [SIZE="integer"] [MULTIPLE] [onBlur="handlerText"] [onChange="handlerText"] [onFocus="handlerText"]> <OPTION VALUE="optionValue" [SELECTED]> textToDisplay [ ... <OPTION> textToDisplay] </SELECT>
The SELECT tag has one required attribute: NAME. This name and a value associated with the selected OPTION element are sent to the server when a form is submitted. The NAME attribute can also be used as an anchor. An optional attribute is SIZE, which tells the browser how many options to display. is an optional attribute of SELECT, which changes the list so that one or multiple items can be selected by the user. This type of list is called a scrolling list.
MULTIPLE
The SELECT tag always contains two or more OPTION elements. This is where you list the items for the user to select. Each OPTION has a text property that is displayed in the select box. There is also an associated VALUE property that is sent to the server when the form is submitted along with the name of the SELECT tag. The last attribute of OPTION is itself optional. The SELECTED attribute is a means to have one of the items in your selection list be the default when the page is displayed. The only additions to this specification for JavaScript are the events discussed in the next section.
2
<HTML><HEAD><TITLE>money.htm by Ray Daly</TITLE> <SCRIPT LANGUAGE="JavaScript"> function changeCurrency(form) { form.currency.value=form.country.options[form.country.selectedIndex].va lue } </SCRIPT></HEAD> <BODY><FORM> <P>Demonstrates <I>onChange</I> event. After you make a country selec the currency does not change until you click somewhere else.</P> <B>Select your country</B><BR> <SELECT NAME="country" onChange="changeCurrency(this.form)"> <OPTION VALUE="US Dollars">USA <OPTION VALUE="Canadian Dollars">Canada <OPTION VALUE="Peso">Mexico </SELECT> <P><B>Prices are displayed in:</B><BR> <INPUT TYPE="text" NAME="currency"> </FORM></BODY> </HTML>
onBlur onBlur is a good way to verify proper selections. This event looks for when the focus is no longer on the SELECT object. In other words, it looks for when you click somewhere other than the current element. When the event is triggered, you could execute a verification function. Although you can use the onChange event to verify selections, using onBlur might ensure the viewer's choice. This is because the onBlur event triggers JavaScript code even if a change has not occurred. Verification is not always simply an either/or choice. For example, you might have a selection with some uncommon, but acceptable answers. This might be an unusual color for a piece of merchandise. For this circumstance, you might verify that this is indeed the correct selection, even if the user made no change in his selection. In listing 7.15, the user is simply notified with an alert dialog box if he wants to buy less than a dozen eggs (see fig. 7.9). Figure 7.9 : The event onBlur works almost exactly like onChange, except the JavaScript code is executed even if the selection does not change.
2
<B>How many eggs do you want:</B><BR> <SELECT NAME="quantity" onBlur="checkEggs(this.form)"> <OPTION VALUE="6">Half dozen <OPTION VALUE="12">Dozen <OPTION VALUE="24">Two dozen </SELECT> <P><B>We are holding this many eggs for you:</B><BR> <INPUT TYPE="text" NAME="eggs"> </FORM></BODY> </HTML>
onFocus onFocus is an excellent way to assist the viewer in completing your form. It looks for the viewer moving the cursor to the SELECT element and then triggers code prior to any entry by the viewer. For example, each question in your form can include particular instructions that assist the viewer in making a proper selection. When onFocus is triggered, your code could display in a separate window or frame the instructions related to that question. Or if you require a numeric answer to be calculated, why not pop up a calculator in a new window? That's what happens in the math word problem presented in listing 7.16 (see fig. 7.10). Figure 7.10: When you design your JavaScript applications, remember that you can call up other people's applications like calculators. TIP It is possible to create an endless loop using the onBlur event. To avoid this trap, create a flag variable. Initially set it to zero. Every time you call the routine, check the value of the flag. If the flag is zero, then execute the rest of the routine and set the flag to one. If the flag is not zero, then the routine has already been executed once so you don't need to execute it again. Listing 7.16 wordprob.htm Tricky Math Word Problem Using onFocus
<HTML><HEAD><TITLE>wordprob.htm by Dr. Ray Daly III </TITLE> <SCRIPT LANGUAGE="JavaScript"> function giveAnswer(form) { if (form.answer.selectedIndex==2) { alert ('People usually forget trains run on two tracks.') } } already=0 function callCalculator(form) { if (already==0) { already = 1 //...only need to open this window once newWindow=window.open("http://www.netscape.com/comprod/products/ navigator/version_2.0/script/calc.html") } } </SCRIPT></HEAD> <BODY><FORM>
2
<P>Demonstrates <I>onFocus</I> event. As soon as you put click on the SELECT element, then a calculator pops up.</P> <P><B>Railroad track is ordered for three sections of track. The first is 15 miles long. The second is 23 miles long and the third is 6 miles long. How many miles of track needs to be ordered to complete construction? </B></P> <P><B>What is your answer:</B><BR> <SELECT NAME="answer" onFocus="callCalculator(this.form)" onBlur="giveAnswer(this.form)"> <OPTION VALUE="21">21 <OPTION VALUE="29">29 <OPTION VALUE="88">88 </SELECT> </FORM></BODY> </HTML>
2
<OPTION VALUE="$20">Extra Veggies Pizza </SELECT> </FORM></BODY> </HTML>
CAUTION With text boxes, the information displayed in the box is the value property. With select, the value property is not displayed. This is like radio buttons and checkboxes. So don't change the value property of select and expect the display to change.
2
<HTML><HEAD><TITLE>Internet Tri-Eye</TITLE></HEAD> <FRAMESET ROWS="*,200"> <FRAMESET COLS="33%,34%, 33%"> <FRAME SRC="one.htm" NAME="one"> <FRAME SRC="two.htm" NAME="two"> <FRAME SRC="three.htm" NAME="three"> </FRAMESET> <FRAME SRC="guide.htm" NAME="guide"> <NOFRAMES> <H1>Internet Tri-Eye</H1> <P><B>Internet Tri-Eye</B> is a demonstration of several features of JavaScript. To view and use this program you need a Javascript compatible browser like Netscape 2.0. </NOFRAMES> </FRAMESET> </HTML>
The content of the top three frames, the eyes, are files one.htm, two.htm, and three.htm (see listings 7.19, 7.20, and 7.21). These are extremely small files that are only used when the application is first loaded.
Files two.htm and three.htm are identical to the file one.htm except that the headline is changed to "Eye Two" and "Eye Three," respectively. The guts of Tri-Eye and all of the JavaScript code is found in the file guide.htm. This file contains the contents of the lower frame. As we progress in building the application, all of the changes are made to this file. So far, the four files, trieye.htm, one.htm, two.htm and three.htm, are complete. TIP Most people find it easier to write JavaScript after doing the layout. Do your frames, your tables, your controls, and even some windows; then write the
Next, for each camera a new object is established. In this example, there are nine different cameras, so create nine different objects labeled cam1 to cam9 (see listing 7.23). You can add more if you like.
Listing 7.23 guide.htm Setting Properties for Cam Objects for Tri-Eye
cam1 = new cam ("Hollywood, CA", "#Hollywood", " http:// hollywood.bhi.hollywood.ca.us:8000/pictures/image01.gif") cam2 = new cam ("Pikes Pike, CO", "#Pikes", "http://www.softronics.com/peak_cam/cam.jpg") cam3 = new cam ("New York City, NY", "#New York City", "http://www.metaverse.com/gate/images/empire.jpg") cam4 = new cam ("Zandvoort, NE", "#Zandvoort", "http://www.dataplace.nl//images/zandv-gr.jpg") cam5 = new cam ("Hong Kong", "#Hong Kong", "http://www.hkstar.com/images/capture1.jpg") cam6 = new cam (" Australian Antarctic", "#Antartic", "http://www.antdiv.gov.au/aad/exop/sfo/mawson/video.gif") cam7 = new cam ("Fishcam", "#Fishcam", "http://www.netscape.com/fishcam/fishcam.gif") cam8 = new cam ("Mojo - Cat", "#Mojo", "http://www.lowcomdom.com/mojo.gif") cam9 = new cam ("Steve's Ant Farm", "#Ant Farm", "http://sec.dgsys.com/images/zANTPIX/Untitled.jpeg")
We now have nine different objects. In order to make it easier to reference these objects, create another object called camset (see listing 7.24). From this object, an object called camindex is
created. The first property in camindex is cam1, the second is cam2, etc. Thus, to get the contents of cam5, you reference the fifth element in camindex.
Listing 7.24 guide.htm Putting Nine Objects into One for Tri-Eye
function camset (eye1, eye2, eye3, eye4, eye5, eye6, eye7, eye8, eye9 ) { this.eye1 = eye1 this.eye2 = eye2 this.eye3 = eye3 this.eye4 = eye4 this.eye5 = eye5 this.eye6 = eye6 this.eye7 = eye7 this.eye8 = eye8 this.eye9 = eye9 } camindex = new camset (cam1, cam2, cam3, cam4, cam5, cam6, cam7, cam8,
We do not need to create so many different objects, but this method seems more straightforward than the other options. If you are good with objects, have fun minimizing. The final two lines of the JavaScript for this section initialize two variables to one, as follows:
var setnumber=1 var camnumber=1 //--> </SCRIPT> </HEAD>
Controls To make anything happen with Internet Tri-Eye, controls need to be added. So far, all we have in guide.htm is the JavaScript defining the objects. Now the HTML code is added for the controls (see listing 7.25). To hold the controls, there is a table of three rows and three columns. Across the entire first row is a button and a select element. The button is very simple and labeled About. When you click it, an alert dialog box tells you about Internet Tri-Eye. The next element in the top row is a SELECT box. Here you select which set of cameras you want to look at. The first three cameras are locations in the United States, the next three are international, and the last three are pets. When you make a selection, it sets the variable setnumber to 1 or 2 or 3.
Listing 7.25 guide.htm Laying Out the Control Table for Tri-Eye
<BODY><FORM> <TABLE BORDER="1" WIDTH="100%">
2
<TR> <TD ALIGN=CENTER COLSPAN=3> <A NAME="top"> <INPUT TYPE="button" NAME="aboutTE" VALUE="About Tri-Eye" onClick="alert('Tri-Eye is a demo from the book: JavaScript Special Edition')"> <SELECT NAME="setselect" onBlur="setnumber=setselect.selectedIndex+1"> <OPTION VALUE="US" SELECTED> U.S. <OPTION VALUE="World">World <OPTION VALUE="Pets">Pets </SELECT> </TD> </TR><TR> <TD ALIGN=CENTER VALIGN=TOP WIDTH="33%"> <A HREF=" "onClick="this.href=findHREF(1)" " TARGET="one">Show picture One </A> </TD> <TD ALIGN=CENTER VALIGN=TOP WIDTH="34%"> <A HREF=" "onClick="this.href=findHREF(2)" " TARGET="two">Show picture Two</A> </TD> <TD ALIGN=CENTER VALIGN=TOP WIDTH="33%"> <A HREF=" "onClick="this.href=findHREF(3)" " TARGET="three">Show picture Tri</A> </TD> </TR><TR> <TD ALIGN=CENTER> <A HREF=" "onClick="this.href=findHASH(1)" " NAME="Info1">-- Info </TD> <TD ALIGN=CENTER> <A HREF=" "onClick="this.href=findHASH(2)" " NAME="Info1">-- Info </TD> <TD ALIGN=CENTER> <A HREF=" "onClick="this.href=findHASH(2)" " NAME="Info1">-- Info </TD></TR> </TABLE>
The final two rows of controls are for demonstrating dynamic links and anchors.
Dynamic Links
The middle row of controls is for the dynamic links. When you press on these links, one picture from one camera is displayed. There is one control for each of the "eyes." The code we need pulls in the proper URL, given "eye" 1, 2, or 3, and is based on the set chosen with the SELECT box (see listing 7.26). These variables are camnumber and setnumber.
2
indexnumber = (eye-1) +( 3 * (setnumber -1) //the value of indexnumber is between 0 and 8 return camindex[indexnumber].url //returns the url of the camera
This code is added between the SCRIPT tags in the header section. In most cases you will want to place functions in the header so they are loaded prior to the page be displayed. Once you have the URL, the code is fairly simple. When the hyperlink is clicked, the findHREF function is called. It returns the URL, and the href property is changed. The target for the URL is the appropriate "eye" frame. Change the href property to the URL. For "eye" 3, the code is:
<A HREF=" "onClick="this.href=findHREF(3)" " TARGET="three">Show Tri</A> picture
For simplicity, the hyperlink text is "Show picture one" or "two" or "tri." To polish up the application, an icon could be used here.
Anchors to Take You Back Once you read the information on the picture, you probably want to go back to the controls. Notice that the title of each description is followed by a hyperlink labeled (top). What you may not have noticed is that there is no anchor with the name (top). Instead, (top) is the name of the About button. So press on (top), and the About button is at the top of the page.
2
<A HREF="#top">(top)</A>
NOTE This code completes the guide.htm file (see listing 7.27). All five files that make up this application are found on the CD-ROM. You start the application by loading trieye.htm. n Listing 7.27 guide.htm Anchor Section for Tri-Eye
<CENTER><H1>Tri-Eye Guide</H1></CENTER><DL><DT> <A NAME="Hollywood">Hollywood, CA</A> <I> <A HREF="#top">(top)</A></I></DT><DD> Not your typical American street corner, this is <A HREF="http://www.geocities.com/cgi-bin/main/BHI/look.html">Hollywood and Vine from GeoCities</A>. Just remember that "nobody walks in L.A."</DD><DT><A NAME="Pikes">Pikes Pike, CO</A><I> <A HREF="#top">(top)</A> </I></DT><DD> One of America's most famous mountains. <A HREF="http://www.softronics.com/peak_cam.html">Pikes Peak Cam from Softronics</A> gives you the view from Colorado Springs.</DD> <DT><A NAME="NYC">New York City, NY</A><I><A HREF="#top">(top)</A> </I></DT> <DD>New York City's most famous building. <A HREF="http://www.metaverse.com/empire.html">Empire Cam from Metaverse</A> has a view across part of the skyline. Check the weather.</DD> <DT><A NAME="Zandvoort">Zandvoort, the Netherlands</A> <I><A HREF="#top">(top)</A></I></DT> <DD>No close ups of the people on the beach. This <A HREF="http://www.dataplace.nl/dp/pages/foto.htm">Livecam from Dataplace</A> points northwest across a traffic circle and up the beach.</DD> <DT><A NAME="Hong">Hong Kong</A><I><A HREF="#top">(top)</A></I></DT> <DD>Street scene that is colorful almost anytime. The <A HREF="http://www.hkstar.com/starcam.html">STARcam from HK Star Internet Ltd.</A> shows more cars than people.</DD> <DT><A NAME="Antartic">Australian Antarctic</A> | <I><A HREF="#top">(top)</A></I></DT> <DD>While often black, some previous pictures are available. The <A HREF="http://www.antdiv.gov.au/aad/exop/sfo/mawson/video.html"> camera at Mawson Station</A> captures the pictures and though a variety of technology gets it to your desk.</DD> <DT><A NAME="Fishcam">Fishcam</A> <I><A HREF="#top">(top)</A></I></DT> <DD>Perhaps the most famous fish in the world. <A HREF="http://www.netscape.com/fishcam/fishcam.html"> Fishcam from Netscape</A>now has multiple cameras and formats. Who ever imagined an aquarium as a revenue source?</DD> <DT><A NAME="Mojo">Mojo</A><I> <A HREF="#top">(top)</A></I></DT> <DD>You won't believe the technology used to bring you these images. <A HREF="http://www.lowcomdom.com/mojo_cam.html">Mojo-Cam</A> isn't from a fixed view so it worth following.</DD> <DT><A NAME="Ant">Ant Farm</A><I> <A HREF="#top">(top)</A></I></DT>
2
<DD>Some people won't even think that this is a safe distance away. <A HREF="http://sec.dgsys.com/AntFarm.html">Steve's Ant Farm</A> also has a movie available.</DD></DL></FORM></BODY></HTML>
When you press -Info-, the control scrolls off the frame. Add one frame just for the table of controls. Show the information in another frame. Don't use any frames, but put everything in its own window. Press the control to show a picture, and it pops up as a new window. Then every "eye" can be free floating. Replace the text links with icons. Although -Info- is easy to explain in a book, the page will look better with graphics. Add more cameras. People are hooking up cameras all of the time: some silly, some beautiful, and some scenic. Grab your favorite, and create some more objects. Instead of doing cameras, do eZines or other publications. Take a collection of eZines and put them in as objects. This would obviously work much better with windows instead of frames.
2
ftp://ftp2.netscape.com/2.0/windows/n32e20.exe
Do the same for each FTP location by just changing the host from ftp2 to ftp3, and so on; the last one is ftp10. The function looks nearly the same; only the contents of the properties have changed (see listing 7.28).
Listing 7.28 guide.htm Redefined cam Object for Tri-Eye FTP Auto Dialer
function cam (name, anchor, url) { this.name = name this.anchor = anchor this.url = url } cam1 = new cam ("FTP2", "#Netscape FTP", "ftp://ftp2.netscape.com/2.0/ windows/n32e20.exe") cam2 = new cam ("FTP3", "#Netscape FTP", "ftp://ftp3.netscape.com/2.0/ windows/n32e20.exe") cam3 = new cam ("FTP4", "#Netscape FTP", "ftp://ftp4.netscape.com/2.0/ windows/n32e20.exe") cam4 = new cam ("FTP5", "#Netscape FTP", "ftp://ftp5.netscape.com/2.0/ windows/n32e20.exe") cam5 = new cam ("FTP6", "#Netscape FTP"," ftp://ftp6.netscape.com/2.0/ windows/n32e20.exe") cam6 = new cam ("FTP7", "#Netscape FTP", "ftp://ftp7.netscape.com/2.0/ windows/n32e20.exe") cam7 = new cam ("FTP8", "#Netscape FTP", "ftp://ftp8.netscape.com/2.0/ windows/n32e20.exe") cam8 = new cam ("FTP9", "#Netscape FTP", "ftp://ftp9.netscape.com/2.0/ windows/n32e20.exe") cam9 = new cam ("FTP10", "#Netscape FTP","ftp://ftp10.netscape.com/2.0/ windows/n32e20.exe")
JavaScript Object Hierarchy o Browser Windows o Dynamic Window Creation o Window Status o The Location Object o The History Object o Security Aspects of JavaScript Objects o The Document Object Dynamic Documents o Restrictions on document.write o Using Nascent Documents o A Page Generated Entirely by JavaScript o Dynamically Rewriting Your Page o The openNote() Script Revisited o Writing a Text Graph
This chapter describes the creation of dynamic documents and windows as well as the interaction between windows and their components. This chapter presumes that you now have a working knowledge of JavaScript syntax; the material covered is somewhat more complex than in earlier chapters (see chapter 4, "JavaScript Objects"). The first theme of the chapter is the creation of pop-up windows. The entire content of those windows is defined by a creation function, rather than a URL. We will examine various examples, including pop-ups with text, pop-ups with buttons, and editable pop-ups. We will next examine the history, status, and location objects. You will see how to hurl the user to a specific URL on the history list, how to examine the various parts of the location object, and how to store and retrieve information using the search property of the location object. Finally, you will learn how to create dynamic documents. In fact, you will create a page entirely from JavaScript. You will also learn how to rewrite pages on-the-fly.
You have already learned a lot about objects in JavaScript. In fact, the previous four chapters have been devoted to exploring the various JavaScript objects and their uses. You have already been exposed to the various built-in objects and HTML objects that JavaScript provides. To go further and explore dynamic HTML creation, we must first take a closer look at the hierarchy of objects in JavaScript. If you are familiar with any object-oriented languages, you expect an object hierarchy to begin with a generic object from which all other objects are descendants or children. Unfortunately, the JavaScript object hierarchy does not really follow this model. It might be best described as a system of ownership, and, even then, the analogy is not really exact. For example, a window that creates another window could be thought of as the parent of the new window. However, if you try to refer to the original window from the child by saying parent.someobject, it will not work. On the other hand, frames within a frameset have a parent-child relationship with the original window, and asking for parent.someobject will likely yield the object. Other ownership relationships are not characterized by a parent-child relationship at all. For example, form elements belong to a form, but to obtain the form, you use this.form-not this.parent. With these disconcerting thoughts in mind, let's attempt to sort out the dependencies among Netscape Navigator objects. The Navigator is, in a way, the parent of all other JavaScript objects. It is the executable that runs the browser. The Navigator is responsible for the creation of all browser windows. It is also responsible for responding to general window events. The Navigator is not a visual object. You cannot see it. You only interact with it through its visual construct: its windows.
Browser Windows
Most Navigator window components can only be manipulated in a yes/no fashion at the time of window creation. These include the menu, button bar, location display, status display, history list display, and scroll bars. At the time of window creation, you can determine whether the window can be resized as well as find its dimensions. This might seem like a significant restriction. By rewriting the document, however, you can change the contents of a window. This technique enables you to change the values of form elements, the content of the status bar, the position of the pointer in the history list, and the location (the URL that the window contains) at any time. Table 8.1 lists these various elements, when they can be modified, and how they can be modified. Note that the last two items in this table are not really window elements; they control what is displayed, but are not explicitly displayed themselves. Table 8.1 Modification Rules for JavaScript Controls Object When How Rewrite? Button bar Window creation Yes/No NA Menu Window creation Yes/No NA
Location display Status bar History Document Many form Status bar content Location History list
Window creation Window creation Window creation During rewrite Any time Any time Any time Any time
The function used in this example is the openNote() function, the source for which is given in listing 8.2. Before we plunge into this code, it is worthwhile to notice that the border has explicitly been set to zero. This is the only way you can keep Navigator from drawing a border around your image if it is within a reference statement. Listing 8.2 contains the HTML for the base window with the Image button. It includes the openNotes() function in a header script. Once you open a note window, make sure you close it before it gets lost. Navigator will not open a second window by the same name: it just updates the first one. When this code is executed by pressing the Make Note button you will see something like figure 8.1. Figure 8.1 : A dynamically created window may be tied to button events in JavaScript.
2
</SCRIPT> </HEAD> <BODY> <H3><BR><HR><BR></H3> <CENTER> <FONT SIZE=5 COLOR='darkred'><B>Example 1</B></FONT>: <FONT SIZE=5 COLOR='darkblue'><B>Opening a New Window</B></FONT> <FORM NAME='noteForm'> <INPUT TYPE='button' NAME='makeBtn' VALUE='Make Note' onclick='openNote("JoAnn Murphy at 7:00; bring salad")'> <INPUT TYPE='button' NAME='closeBtn' VALUE='Close note' onclick='closeNote()'> </FORM> </CENTER> <H3><BR><HR><BR></H3> </BODY> </HTML>
CAUTION In a windows.open statement, there are three things to bear in mind, as follows:
1. You only need the first two parameters (the URL, which can be empty,
and the window name) to open a window. If you do not include the third parameter, the window attributes list, then the window will have all of its window attributes set to yes (present). 2. If you specify any of the windows attributes, then you must include the whole list of attributes. Otherwise, the results will be unpredictable. 3. Enclose the attributes list in quotation marks, separate the items with commas, and do not leave spaces. This small script illustrates several points. First, you can set a window global by defining it outside of any function and preceding it with var. Here we set the window global aNoteWin with var aNoteWin. This variable is global so that you could use it to refer to aNoteWin in other functions. Although we did not do so here, you might want to save a number of notes in an array. Second, when you create a window de novo via a script and no URL is specified, the window document is still open and you can write to it. Here we wrote the note topic and then closed the document. A window that you create can be as simple as the note window. However, you can also make this window quite complex. In order to do so, you must write everything to the document, including form elements, images, and JavaScript functions, before you close it. Listing 8.3 shows a second version of the openNote() function. This more elaborate version furnishes the note window with two buttons, including onClick handlers, the topic text, a warning message, and two JavaScript functions. It may be found in the file c8-1.htm on the CD-ROM. Note that the save function is stubbed. The topic of data storage is discussed in chapter 19. All the display elements are neatly wrapped in a table.
Window Status
Netscape Navigator keeps you appraised of which link or button your mouse pointer is over via its status bar. Occasionally, it sends you other messages via that method, too. Perhaps you have seen it busily scrolling text to catch your attention. The status (not the status bar itself) is a property of a window and is accessible to you as self.status = Some message. When you change the status, Navigator immediately displays it in the status bar. You can also set a property called defaultStatus, which is the default message displayed in the status bar. Listing 8.4 illustrates the use of the status property in Netscape Navigator. This code can be found in the file c8-2.htm on the CD-ROM.
2
<!-- fixup forces redraw of window after everything, including images, has loaded. The redraw is necessary to enforce correct drawing of table overlays. --> <BODY onLoad='fixup()'> <H3><BR><HR><BR></H3> <CENTER> <FONT SIZE=5 COLOR='darkred'><B>Example : </B></FONT> <FONT SIZE=5 COLOR='darkblue'><B>Setting the Contents of the Status Bar</B></FONT> <H3><BR><HR><BR></H3> <H3><BR></H3> </CENTER> <CENTER> <FORM NAME='statForm'> <TABLE WIDTH=520 ALIGN=CENTER BORDER><TR ALIGN=CENTER><TD> <TABLE WIDTH=500 ALIGN=CENTER > <TR ALIGN=CENTER> <TD WIDTH=35 ALIGN=CENTER> <IMG WIDTH=485 HEIGHT=50 VSPACE=2 HSPACE= 2 ALIGN=CENTER SRC="Images/gotray.gif"> </TD> <TD> <!-- <INPUT TYPE=button VALUE='Make Status Window' onClick='openStatus("Status is GO!", document.statForm.statMsg.value)'> --> <A HREF='javascript: openStatus("Status is GO!", document.statForm.statMsg.value)'> <IMG WIDTH=23 HEIGHT=22 VSPACE=2 HSPACE=2 ALIGN=absMiddle SRC="Images/gobtn1.gif" BORDER=0> Open Status Window</A> </TD> <TD ALIGN=LEFT > <A HREF='javascript: setStatus()'> <IMG WIDTH=23 HEIGHT=22 VSPACE=2 HSPACE=2 ALIGN=absMiddle SRC="Images/gobtn2.gif" BORDER=0> Set Status</A> </TD> <TD ALIGN=CENTER > <A HREF= 'javascript: close()'> <IMG WIDTH=31 HEIGHT=30 VSPACE=2 HSPACE= 2 ALIGN=absMiddle BORDER=0 SRC="Imagesokbtn.gif"> Close Status </A> </TD> </TR> <TR ALIGN=CENTER> <TD ALIGN=CENTER COLSPAN=4> Msg <INPUT TYPE=text NAME='statMsg' VALUE='Howdy!' SIZE= 50 MAXLENGTH=80> </TD> </TR> </TABLE> </TD></TR></TABLE> </FORM> </CENTER> <H3><BR></H3> </BODY>
2
</HTML>
This example builds a window with a status bar included. Just to make things interesting, we will set the content of the status bar from the parent window. In addition, this script provides an example of the advanced HTML concept of table overlays, and an onLoad() handler, which provides a work-around for Netscape's unpredictable order of drawing images. We will say a little more about table overlays later, when we discuss the fixup() function. The status window is created with a javascript: openStatus(defMsg,msg) link attached to an image. This function, openStatus(defMsg, msg), performs the following tasks:
It creates a new window with everything turned off but the status bar. It also sizes the window so that only the status bar is showing. It checks that the window was actually created by examining aStatWin for a null value. It is important to perform this, since attempts to access objects in a nonexistent window will result in errors. The usual reason why a window will fail to be created is lack of memory. This routine aborts with a message if the window was not created. It places a dummy button in aStatWin. This button is just used as an object to set the focus, so that we can bring the window to the front. Otherwise, small windows can get lost. It sets the initial and default status. Netscape immediately makes its presence known by writing to your status bar.
We will set the status of the status window with a call to setStatus(). This call is made from a javascript: setStatus(document.statForm.statMsg.value) link attached to an image. The setStatus() function also checks to see if aStatWin exists before it tries to address one of its objects. If aStatWin does exist, setStatus changes the content of its status bar. setStatus() then sets the focus on the dummy button in aStatWin to bring the window to the front. This is done by a call to the setFocus() method. The resulting window is shown in figure 8.2. When you are done with the window you can close it using an image button linked with a call to close(). The close() function simply closes aStatWin and makes sure that its value is reset to null. Figure 8.2 : A status bar window may be created dynamically by the parent window. The function fixup() is worth looking at in more detail. The order in which Netscape Navigator draws images depends upon where the images are coming from, whether they are in the cache, and whether their height and width are given explicitly. It can also depend on the size of the images. Extremely attractive presentations can be made by overlaying text and graphics on other graphics via the overlay feature of Netscape tables. However, Netscape will invariably draw your bottom image last when the page first loads. Scrolling the screen causes the correct redraw, but you cannot expect or require your users to do that. One way to force the redraw is to open and quickly close another window over your page. You need to do this after all of the page elements have been loaded. When this occurs, Navigator
sends an onLoad event, which you can capture in the BODY tag. The fixup() function ensures that all of the image buttons are visible. Although this is far from an ideal solution, it is effective. TIP Always check that a newly created window exists before you try to address its properties or methods. Do this by checking to see if the window is null. If it is null, use an alert to inform the user.
remote server. They contain the domain name/IP address of the server and the server port, respectively. They are not usually a visible part of a URL. The Web port is a number denoting the type of service, and is usually 80 for http. The pathname is the path to the file that the browser displays. Search includes any post parameters that are compiled when a form is submitted. Hash is usually a link to a local anchor. The location object also has a host property, which consists of the combination of hostname and port. The location object also has an extremely important property, known as href, which contains the entire URL. Finding Out Where You Are This next example is a page that has no body. It is written entirely by the header script. As the page is written, it dissects the location object and lists all of its properties in a table. To see a non-empty location.search, you have to submit the little form included after the table. To see a non-empty location.search, click the dummy link and then Netscape's Reload button. The host, port, and hostname properties will be non-empty only if you have loaded some page from a server. Listing 8.5 shows the code for the Location Display script. This code is in the file c8-3.htm on the CD-ROM.
2
<SCRIPT> var aline = '<H3><BR></H3><HR><H3><BR></H3>' var skip='<H3><BR></H3>' document.write('<CENTER>') document.write('<FONT SIZE=5 COLOR="darkred"><B>Example : </B></FONT> <FONT SIZE=5 COLOR="darkblue"> <B>What\'s in the Location Object?</B></FONT>') document.write('<BR>') document.write('<BLOCKQUOTE><BLOCKQUOTE>If you are viewing this document from your hard disk, host, hostname, and port will be empty.</BLOCKQUOTE></BLOCKQUOTE>') document.write('<BR>') document.write('<CENTER><TABLE ALIGN= CENTER BORDER CELLPADDING=3>') document.write('<TR><TD><B>Property</B></TD><TD ALIGN=CENTER> <B>Value</B></TD></TR>') document.write('<TR><TD>href</TD><TD>' + location.href + '</TD></TR>') document.write('<TR><TD>protocol</TD><TD>' + location.protocol + '</TD></TR>') document.write('<TR><TD>hostname</TD><TD>' + location.hostname + '</TD></TR>') document.write('<TR><TD>host</TD><TD>' + location.host + '</TD></TR>') document.write('<TR><TD>port</TD><TD>' + location.port + '</TD></TR>') document.write('<TR><TD>pathname</TD><TD>' + location.pathname + '</TD></TR>') document.write('<TR><TD>search</TD><TD>' + location.search + '</TD></TR>') document.write('<TR><TD>hash</TD><TD>' + location.hash + '</TD></TR>') document.write('</TABLE></CENTER>') document.write(aline) document.write('<CENTER>') document.write('<FORM NAME="nameForm" >') document.write('Your name\: <INPUT TYPE=text NAME="yourName" VALUE="John Smith" WIDTH=30 MAXLENGTH=30>') document.write('<INPUT TYPE=submit VALUE="Click Me to Add a Search Parameter!" >') document.write('</FORM>') document.write('<A HREF=' + location.href + '#myAnchor >Click on me and then RELOAD to enter a hash parameter!</A>') document.write(aline) </SCRIPT> </HEAD> </HTML>
Sending the User Elsewhere Not only can you obtain useful information by examining the location object, you can also modify it and send the user else-where. This is useful if you should want to dynamically generate a URL or a reference to an anchor. The example shown in listing 8.6 builds a URL dynamically and sends the current browser to that URL. This code implements a "Message Center," which retrieves messages from URLs created via button clicks. Five users have been created to demonstrate this aspect of the location object. The CD-ROM file c8-4.htm contains this message center code.
2
<HEAD> <!-- Created 08 Feb 1996 a4:08 PM 04:08 PM --> <TITLE>Message Center</TITLE> <SCRIPT> function getMessage(who) { loc = self.location document.forms[0].translate.value = loc loc = document.forms[0].translate.value k = loc.lastIndexOf('/') loc = loc.substring(0,k+1) nloc = loc.substring(0,k+1)+ who.value + '.htm' self.location=nloc } </SCRIPT> </HEAD> <BODY> <CENTER><HR> <FONT SIZE=5 COLOR='darkred'><B>Example 4</B></FONT>: <FONT SIZE=5 COLOR='darkblue'><B>Moving Around Dynamically</B></FONT><BR> <HR><FONT SIZE=6 COLOR='darkslateblue'><B>Message Center</B></FONT><BR> </CENTER> <CENTER> <FORM> <TABLE BORDER ALIGN=CENTER><TR><TD> <INPUT TYPE=radio NAME='getMsgR' VALUE='John' onClick='getMessage(this)'>John <INPUT TYPE=radio NAME='getMsgR' VALUE='George' onClick='getMessage(this)'>George <INPUT TYPE=radio NAME='getMsgR' VALUE='Barbara' onClick='getMessage(this)'>Barbara <INPUT TYPE=radio NAME='getMsgR' VALUE='Ken' onClick='getMessage(this)'>Ken <INPUT TYPE=radio NAME='getMsgR' VALUE='Julie' onClick='getMessage(this)'>Julie <INPUT TYPE=hidden NAME='translate' VALUE='' > </TD></TR></TABLE> </FORM> </CENTER> <H3><BR><HR><BR></H3> <H3><BR><HR SIZE=5 WIDTH=80%><BR></H3> </BODY> </HTML>
The script works by first obtaining the current location. It then strips off the filename and replaces it with the value of the radio button clicked. It also makes sure to tack on the suffix, .htm. This presumes that the message HTML files are in the same directory as the current page. However, it would be easy enough to build in a subdirectory name just for the messages or even have a separate subdirectory for each person. The location object is then set to the newly constructed URL. Setting the location object retrieves the file at that location. In our example, this file represents the set of messages for the particular user whose button was pressed. TIP
You can force a page to be reloaded by setting the location object to the URL corresponding to that page. Using the Search Property When you submit a form, all the values of the various form elements are retrieved, parsed, and concatenated with the location object; they are placed after the path and preceded by question marks (?). The value of location.search is precisely that string, including the question mark (?). This string is not just a simple list of element contents, however. Each element value is placed in the string in the form elementName=elementValue and followed by an ampersand (&). Any nonalphanumeric characters are coded or escaped. The ASCII value of any such character is changed into a two-digit hex number preceded by a percent sign (%). If text field or textarea elements have multiple words, these words are separated by a plus sign (+). Consequently, when you get the location.search string, you have to decode it to get the various form elements that it contains. You can place your own form element values, or anything else, in the location's search property. As long as you precede it with a question mark (?), location.search will retrieve it. However, not all non-alphanumeric characters can be placed in the string or retrieved intact. If you are going to concoct a home-grown search string, you may either need to encode the parameters yourself or not allow non-alphanumeric characters. Listing 8.7 is a simple page that shows you how to manipulate location.search.
2
<CENTER><FONT SIZE=6 COLOR="blue"><B>Forcing a Reload with Location</B></FONT></CENTER> <H3><BR><HR><BR></H3> <CENTER> <FORM NAME=nameForm> <INPUT TYPE=text NAME=myName VALUE='abracadabra&#^$()'> <INPUT TYPE=button NAME=reloadBtn VALUE='Reload Page' onClick='reloadMe()'> <INPUT TYPE=button NAME=submitBtn VALUE= 'Submit Form' onClick='this.form.submit()'> <INPUT TYPE=button NAME=clearBtn VALUE= 'Clear' onClick='clearUp()'> <INPUT TYPE=hidden NAME=hideFld > </FORM> </CENTER> <H3><BR><HR><BR></H3> <H3><BR><HR SIZE=5 WIDTH=80%><BR></H3> </BODY> </HTML>
A script in the <HEAD> part of an HTML document can pick up the command-line parameters with location.search and write something to the document being loaded based on what it finds. This example just reads the parameter string and writes it for you at the head of the page. Note that this write is guarded by a test to see if location.search is null or empty. If location.search is not a valid string and you attempt to parse it into variables that are used later, you will encounter error after error. Always test for a null string or an empty string. The code in listing 8.7 has two useful functions. ClearUp() simply strips the search string from the location by setting the location object to location.path. The reloadMe() function takes the value from the text box and adds it to location.path. It then sets the location to that result.
2
<HEAD> <!-- Created 08 Feb 1996 a9:21 PM 09:21 PM --> <TITLE>Running through the History List</TITLE> <SCRIPT> var aNoteWin var myDummyVar = 'Apples, peaches, pumpkin pie...' function openNote(topic) { aPopUp= window.open('','Note','toolbar=no,location=no, directories=no,status=no,scrollbars=yes,resizable=yes, copyhistory=no,width=110,height=150') ndoc= aPopUp.document ndoc.close() ndoc.open() astr ='<HTML><HEAD><BR><TITLE>' + topic + '</TITLE>' astr +='<SCRIPT>' astr +='function closeNote(aName){' astr +='self.close()' astr +='}\n' astr +='function saveNote(aName){' astr +='}\n' astr +='function goNext(){' astr +='creator.history.forward()\n' astr +='}\n' astr +='function goBack(){' astr +='creator.history.back()\n' astr +='}\n' astr +='function goStart(){' astr += 'creator.history.go(-5)\n' astr +='}\n' astr +='function goEnd(){' astr +='creator.history.go(5)\n' astr +='}\n' astr +='<\/SCRIPT>' astr +='</HEAD>' ndoc.write(astr) astr ='<BODY>' astr +='<FORM NAME="popForm">' astr +='<TABLE ALIGN=LEFT BORDER>' astr +='</TR><TR ALIGN=CENTER><TD>' astr +='\<INPUT TYPE=button NAME=closeBtn VALUE="Close" ONCLICK="closeNote()" \>' astr +='</TD>' astr +='</TR>' astr +='<TR><TD>' astr +='<INPUT TYPE="button" NAME="startBtn" VALUE=<< onclick="goStart()">' astr +='<INPUT TYPE="button" NAME="backBtn" VALUE=< onclick="goBack()">' astr +='<INPUT TYPE="button" NAME="nextBtn" VALUE=> onclick="goNext()">' astr +='<INPUT TYPE="button" NAME="endBtn" VALUE=>> onclick="goEnd()">' astr +='</TD></TR>' astr +='<TR><TD>' astr +='<INPUT TYPE="hidden" NAME="IAm" VALUE="0">'
2
astr +='</TD></TR>' astr +='</TABLE>' astr +='</FORM>' astr +='<BR CLEAR=ALL><H3><BR></H3>' astr +='</BODY></HTML>' ndoc.write(astr) ndoc.close() self.aNoteWin = aPopUp self.aNoteWin.creator = self aNoteWin.document.popForm.startBtn.focus() } function closeNote(which) { self.aNoteWin.close() } </SCRIPT> </HEAD> <BODY > <CENTER> <FONT SIZE=5 COLOR='darkred'><B>Example 6</B></FONT>: <FONT SIZE=5 COLOR='darkblue'><B>Running through the History List </B></FONT> </CENTER> <H3><BR><HR><BR></H3> <BODY> <H3><BR><HR><BR></H3> <CENTER> <FORM NAME='noteForm'> <INPUT TYPE='button' NAME='makeBtn' VALUE='Make Popup' onclick='openNote("JoAnn Murphy at 7:00; bring salad.")'> <INPUT TYPE='button' NAME='closeBtn' VALUE='Close Popup' onclick='closeNote()'> </FORM> </CENTER> <H3><BR><HR><BR></H3> <H3><BR><HR><BR></H3> <H3><BR><HR SIZE=5 WIDTH=80%><BR></H3> </BODY> </HTML>
This pop-up is a variation on our old friend, aNoteWin. It can access its parent's variables through an artificial property of aNoteWin, the creator property. At the end of the openNote() function, which creates and draws the window, aNoteWin.creator is set to self. This automatically creates a new property of the aNoteWin. This enables you to have ready access to the parent window's variables, functions, and objects.
You may have wondered why there is no windows array. This also does not exist in JavaScript for security reasons. If it did, a script from one window mig