CSCI A348/A548

Lecture Notes 11

Fall 1999


Executable content. Client-side JavaScript

Introduction

Lightweight interpeted programming language with rudimentary object-oriented capabilities. Developed by Brendan Eich and his team at Netscape. General-purpose core of the language embedded in Navigator and other web browsers, embellished for web programming with the addition of objects that represent the web browser window and its contents. It allows programmatic control over content of web pages, browser, and HTML forms (through event handlers, pieces of JavaScript code that are executed when a particular event occurs.

Syntactically the core JavaScript language resembles C, C++, and Java. Untyped language, though, which means that variables do not need to have a type specified. Objects in JavaScript are more like Perl's associative arrays than they are like structures in C or objects in C++ or Java. Purely interpreted language.

Simple sample JavaScript program:

<html>
<body bgcolor=white>
<script language="javascript">
document.write("<h2>Table of Factorials</h2>\n"); 
for (i = 0, fact = 1; i < 10; i++, fact *= i) {
  document.write(i + "! = " + fact); 
  document.write("\n</br>"); 
}
</script>
</body>
</html>
Script tags are used to embed JavaScript code within an HTML file. The write method is used to dynamically output HTML text that will be parsed and displayed by the web browser.

Besides allowing programmatic control over the content of web pages, JavaScript also allows programmatic control over the browser and the content of HTML forms that appear in a web page. Not only can JavaScript control the content of HTML forms, it can also control the behaviour of those forms. JavaScript can do that by defining "event handlers" for the form. The code in the event handlers will be executed when a particular event occurs, such as when the user clicks a button.

<html>
<body bgcolor=white>
<form>
<input type="button"
       value="click here!"
       onClick="alert('You clicked the button!')">
</form>
</body>
</html>
The onClick attribute shown in the simple example above is an HTML extension added by Netscape specifically for client-side JavaScript. All JavaScript event handlers are defined with HTML attributes like this one. The value of the onClick attribute is a string of JavaScript code to be executed when the user clicks a button.

The examples above highlight only the simplest features of client-side JavaScript. The real power of JavaScript on the client side is that scripts have access to a hierarchy of objects that are based on the content of the web page. What is exciting about the language is the context in which it is embedded (the web browser). Client JavaScript is essentially a way of programming the web browser remotely.

JavaScript is not Java simplified, similarity of names purely a marketing ploy. It cannot draw graphics, do networking or multithreading (Java does all these). But unlike Java it can control the browser very well and can communicate well and make a good team with Java (with which it has a disjoint set of features). JavaScript can also control the document appearance and content. This allows you to write arbitrary HTML in a document as the document is being parsed by the browser. You can also generate documents entirely from scratch. What this amounts to is the ability to generate dynamic and conditional HTML documents, a technique that works particularly well in multiframe documents. (Indeed, in some cases, dynamic generation of frame contents allows a JavaScript program to entirely replace the use of a traditional CGI script).

Several JavaScript objects allow control over the behaviour of the browser (The Window and History objects). The Document object and the objects it contains allow programs to read and sometimes interact with portions of the document. BY far the most important capability for interacting with document contents is provided by the Form object and by the element objects it can contain: the Button, Checkbox, Hidden, Password, Radio, Reset, Select, Submit allow you to read and write the values of any input element in any form in the document.

HTML forms have been traditionally used with CGI scripts, JavaScript is much more practical circumstances since it can transfer some of the computation to the client workstation (instead of sending the data to the server for calculationbs at every single step in the program, as in the calculator program of your third homework assignment). Another common use for the ability to read user input from form elements is for verification of a form before it is submitted.

To experiment with JavaScript all you need is a browser (no network connection is necessarry).

Client-side program structure.

There are five techniques for including JavaScript code in HTML:

1. The <SCRIPT> tag. Client-side JavaScript scripts are part of an HTML file and are usually coded within <SCRIPT> and </SCRIPT> tags. Between these tags you may place any number of JavaScript statements. A single HTML document may contain more than one pair of (non-overlapping) <SCRIPT> and </SCRIPT> tags. The context that matters is the HTML page, not the script block. The <SCRIPT> tag has an optional LANGUAGE attribute that specifies the scripting languagefor the script.

Here's a simple JavaScript Program in an HTML file:

<html>
<head>
<title> Today's Date </title>
  <script language="JavaScript"> 
  // Define a function for use later on 
  function  print_todays_date() { 
    var d = new Date(); // today's date and time 
    document.write(d.toLocaleString()); 
  }
  </script> 
</head>
<body bgcolor=white>
<hr>The date and time are: <br> <b> 
  <script language="JavaScript">
  // Now call the function we defined above 
  print_todays_date(); 
  </script>
</b> <hr>
</body>
</html>
2. Including JavaScript Files. The <SCRIPT> supports an SRC attribute. The value of the attribute specifies the URL of a file of JavaScript code. It is used like this:
<html>
<head>
<title> Today's Date </title>
  <script src="date.js"></script> 
</head>
<body bgcolor=white>
<hr>The date and time are: <br> <b> 
  <script language="JavaScript">
  // Now call the function we defined above 
  print_todays_date(); 
  </script>
</b> <hr>
</body>
</html>
where the file date.js has the following contents:
// Define a function for use later on 
function  print_todays_date() { 
  var d = new Date(); // today's date and time 
  document.write(d.toLocaleString()); 
}
The program above prints the date, being essentially equivalent to the program in section 1. A JavaScript file typically has a .js extension. It is also a good idea to use the LANGUAGE attribute with the SRC atribute.

3. JavaScript and Events. Web browsers are graphical environments responding to mouse button clicks and keystrokes (input) generated by the user. In order to implement an event-driven program you must write event-handler functions that take appropriate actions in response to user's input. You must also register these event handlers with the system in some way (perhaps just by giving them standard names) so that the system can invoke them at the appropriate times.

In order to allow us to define JavaScript event handlers as part of HTML object definitions, JavaScript extends HTML by adding new attributes to various HTML tags that define objects. A common technique is to define the body of the event handler as a function between <SCRIPT> and </SCRIPT> tags and simply invoke the function from the event handler.

Here's a list of event handlers defined by client-side JavaScript objects:

Area
  • onClick()
  • onMouseOut()
  • onMouseOver()
Button
  • onBlur()
  • onClick()
  • onFocus()
Checkbox
  • onBlur()
  • onClick()
  • onFocus()
FileUpload
  • onBlur()
  • onChange()
  • onFocus()
Form
  • onReset()
  • onSubmit()
Frame
  • onLoad()
  • onUnload()
Image
  • onAbort()
  • onError()
  • onLoad()
Link
  • onClick()
  • onMouseOut()
  • onMouseOver()
Radio
  • onBlur()
  • onClick()
  • onFocus()
Reset
  • onBlur()
  • onClick()
  • onFocus()
Select
  • onBlur()
  • onChange()
  • onFocus()
Submit
  • onBlur()
  • onClick()
  • onFocus()
Text
  • onBlur()
  • onChange()
  • onFocus()
TextArea
  • onBlur()
  • onChange()
  • onFocus()
Window
  • onBlur()
  • onError()
  • onFocus()
  • onLoad()
  • onUnload()

Timer Events. There is another type of event, besides those generated through user interaction. These are events generated when specified periods of time have elapsed: they are known as timer events, or timeouts. Timeouts are important to any JavaScript program that must perform an action on some regular schedule, wvewn when the user is not interacting with the browser. Applications of timeouts include clocks and animation.

Here are two examples:

// call the show_date_time() function 1 second from now
setTimeout("show_date_time();", 1000);
shows the date one second after the statement is executed, and
function animate_status_line_annoyingly() {
  // Set the Window.status property here. 
  // then arange to be called later so we can do it again!
  setTimeout("animate_status_line_annoyingly()", 1000); 
}
when invoked, starts a loop of 1-second delayed animations of the status bar.

4. JavaScript in URLs. Another way in which JavaScript code can be included on the client side is in a URL following the javascript: pseudo-protocol specifier. This special protocol type specifies that the body of the URL is arbitrary JavaScript code to be interpreted by the JavaScript interpreter.

For example:

javascript: var now = new Date(); "<h1>The time is:</h1>" + now;
or
javascript: alert("Hello World!"); 
Try both of these in the Location: box of your browser. The javascript URL can be used anywhere you'd use a regular URL.

5. JavaScript Entities. In Navigator 3.0 and later, Javascript code may appear in one additional location in a web page. This is in a JavaSCript entity within the value of an attribute of an HTML tag. Recall that an HTML entity is a sequence of characters like &lt; that represents a special character like <. A JavaScript entity is similar. It has the following syntax:

&{ JavaScript-statements };
The entity may contain any number of JavaScript statements, which must be separated from one another by semicolons. It must begin with an ampersand and an open curly bracket and end with a close curly bracket and a semicolon. Whenever an entity is encountered in HTML, it is replaced with its value. The value of a JavaScript entity is the value of the last JavaScript statement or expression within the entity, converted to a string.

In general, entities can be used anywhere within HTML code. The JavaScript entity, however, is restricted to appear only within the value of HTML attributes. These entities allow you to, in effect, write conditional HTML. Typical usages might look like these:

<body bgcolor="&{favorite_color();};">
<input type="text" name="lastname" value="&{defaults.lastname};">
Execution of scripts occurs as part of the web browser's HTML parsing process.

Windows and the JavaScript Name Space

In client-side JavaScript the web browser window is represented by a Window object. The Window object is the central, most important object in JavaScript. All other HTML objects in Javascript are accessed as properties of the Window object, or as properties of those properties. This object has methods like alert() and prompt, and properties like location, status and history. There's also another property, self, that is a synonym for the window property. Thus a window can refer back to itself.

A window also defines the name space of a JavaScript program (or script).

Programming with Windows

Essentially this involves using methods such as: alert(), confirm(), and prompt(); knowing how to open or close windows; working with the status line; applying various other techniques such as frame programming techniques etc.

Here's an example of a digital clock in the status line:

<html>
<head>
<script>
// This function displays the time in the status line.
// Invoke it once to activate the clock; it will call 
// itself from then on.
function display_time_in_status_line () {
  var d = new Date();                  // get current time
  var h = d.getHours();                //extract hours: 0 to 23
  var m = d.getMinutes();              // extract minutes: 0 to 59 
  var ampm = ( h >= 12) ? "PM" : "AM"; // is it am or pm? 
  if (h > 12) h -= 12;                 // convert 24hr format to 12hr 
  if (h == 0) h = 12;                  // convert 0 o'clock to midnight 
  if (m < 10) m = "0" + m;             // convert 0 minutes to 00 minutes, etc; 
  var t = h + ":" + m " " + ampm;      // put it all together 

  defaultStatus = t;                   // display it in the status line 

  // arrange to do it all again in 1 minute 
  setTimeout("display_time_in_status_line()", 60000); // milliseconds 
}
</script> 
<title> Clock </title> 
</head>
<!-- Don't bother starting the clock 'till everything is loaded. The
  -- status line will be busy with other messages during loading, anyway --> 
<body bgcolor=white onLoad="display_time_in_status_line();">
</body>
</html>
The Navigator, Location, and History Objects

The Window object contains references to three objects that contain information about the browser or the browser window itself, rather than information about the contents of the window:

Here's a navigation bar that uses these three objects and their properties:

<!-- This file implements a navigation bar, 
     designed to go in a frame at the bottom of a window. Include 
     it in a frameset like the following: 
  
     <frameset rows="*,75">
       <frame src="about:help">
       <frame src="navigation.html">
     </frameset> 

-->      

<script>

              // The function is invoked by the Back button 
              // in our navigation bar. 
function go_back() {
              // First, clear the URL entry field in our form 
  document.navbar.url.value = ""; 
              // Then use the History object of the main frame 
              // to go back 
  parent.frames[0].history.back(); 
              // Wait a second, and then update the URL entry 
              // field in the form from the location.href property 
              // of the main frame. The wait seems to be necessary 
              // to allow the location.href property to get in sync.
  setTimeout(
      "document.navbar.url.value = parent.frames[0].location.href;", 
      1000 
  ); 
}
 
              // This function is invoked by the Forward button in 
              // the navigation bar. It works just like the one above. 
function go_forward() {
  document.navbar.url.value = ""; 
  parent.frames[0].history.forward(); 
  setTimeout(
      "document.navbar.url.value = parent.frames[0].location.href;", 
      1000
  );
} 
              // This function is invoked by the Go button in the 
              // navigation bar, and also when the form is submitted 
              // (when the user hits the Return key). 
function go_to() {
              // Just set the location property of the main frame to 
              // the URL that the user typed in. 
  parent.frames[0].location = document.navbar.url.value; 
}
</script> 
<!-- Here's the form, with event handlers that invoke 
     the functions above --> 
<form name="navbar" onSubmit="go_to(); return false; ">
<input type="button" value="Back"     onClick="go_back();">
<input type="button" value="Forward"  onClick="go_forward();">
URL: <input type="text"   name="url"  size=50>
     <input type="button" value="Go"  onClick="go_to();">
</form> 
The file above is navigation.html and we can access it from a file like this:
<html><head><title>Example</title></head>
  <frameset rows="*,75">
    <frame src="http://www.best.indiana.edu">
    <frame src="navigation.html" name="navbar">
  </frameset> 
</html>
Documents and Their Contents

<SCRIPT>
var _console = null;

function debug(msg) 
{
    // Open a window the first time we are called, or after an existing
    // console window has been closed.
    if ((_console == null) || (_console.closed)) { 
        _console = window.open("","console","width=600,height=300,resizable");
        // Open a document in the window to display plain text.
        _console.document.open("text/plain");
    }

    _console.document.writeln(msg);
}
</SCRIPT>

<!-- Here's an example of using this script. -->
<SCRIPT>var n = 0;</SCRIPT>
<FORM>
<INPUT TYPE="button" VALUE="Push Me"
       onClick="debug('You have pushed me:\t' + ++n + ' times.');">
</FORM>
Special Effects with Images

<html><head><title>Animation Example</title></head>
<img src="http://www.cs.indiana.edu/classes/a202/lectures/last/T1.gif" 
     name="animation"> <script>
images = new Array(10); 
for (var i = 0; i < 10; i++) {
  images[i] = new Image(); 
  images[i].src = 
    "http://www.cs.indiana.edu/classes/a202/lectures/last/T" + 
    (i + 1) + ".gif";
} 
function animate() {
  document.animation.src = images[frame].src;
  frame = (frame + 1) % 10; 
  timeout_id = setTimeout("animate()", 250); 
}
var frame = 0; 
var timeout_id = null; 
</script>
<body bgcolor=white>
<form>
  <input type=button value="Start" 
         onClick="if (timeout_id == null) animate()"> 
  <input type=button value="Stop"
         onClick="if (timeout_id) clearTimeout(timeout_id); timeout_id=null;">
</form>
</body></html> 
Forms and Form Elements

<FORM NAME="everything">  <!-- A one-of-everything HTML form... -->
 <TABLE BORDER CELLPADDING=5>   <!-- ...in a big HTML table. -->
   <TR>
     <TD>Username:<BR>[1]<INPUT TYPE=text NAME="username" SIZE=15></TD>
     <TD>Password:<BR>[2]<INPUT TYPE=password NAME="password" SIZE=15></TD>
     <TD ROWSPAN=4>Input Events[3]<BR>
       <TEXTAREA NAME="textarea" ROWS=20 COLS=28></TEXTAREA></TD>
     <TD ROWSPAN=4 ALIGN=center VALIGN=center>
       [9]<INPUT TYPE=button VALUE="Clear" NAME="clearbutton"><BR>
       [10]<INPUT TYPE=submit NAME="submitbutton" VALUE="Submit"><BR>
       [11]<INPUT TYPE=reset NAME="resetbutton" VALUE="Reset"></TD></TR>
   <TR>
     <TD COLSPAN=2>Filename: [4]<INPUT TYPE=file NAME="file" SIZE=15></TD></TR>
   <TR>
     <TD>My Computer Peripherals:<BR>
       [5]<INPUT TYPE=checkbox NAME="peripherals" VALUE="modem">28.8K Modem<BR>
       [5]<INPUT TYPE=checkbox NAME="peripherals" VALUE="printer">Printer<BR>
       [5]<INPUT TYPE=checkbox NAME="peripherals" VALUE="tape">Tape Backup</TD>
     <TD>My Web Browser:<BR>
       [6]<INPUT TYPE=radio NAME="browser" VALUE="nn">Netscape Navigator<BR>
       [6]<INPUT TYPE=radio NAME="browser" VALUE="ie">Internet Explorer<BR>
       [6]<INPUT TYPE=radio NAME="browser" VALUE="other">Other</TD></TR>
   <TR>
     <TD>My Hobbies:[7]<BR>
       <SELECT multiple NAME="hobbies" SIZE=4>
         <OPTION VALUE="programming">Hacking JavaScript
         <OPTION VALUE="surfing">Surfing the Web
         <OPTION VALUE="caffeine">Drinking Coffee
         <OPTION VALUE="annoying">Annoying my Friends
       </SELECT></TD>
     <TD align=center valign=center>My Favorite Color:<BR>[8]
       <SELECT NAME="color">
         <OPTION VALUE="red">Red        <OPTION VALUE="green">Green
         <OPTION VALUE="blue">Blue      <OPTION VALUE="white">White
         <OPTION VALUE="violet">Violet  <OPTION VALUE="peach">Peach
       </SELECT></TD></TR>
 </TABLE>
</FORM>

<DIV ALIGN=center>        <!-- Another table--the key to the one above. -->
  <TABLE BORDER=4 BGCOLOR=pink CELLSPACING=1 CELLPADDING=4>
    <TR>
      <TD ALIGN=center><B>Form Elements</B></TD>
      <TD>[1] Text</TD>  <TD>[2] Password</TD>  <TD>[3] Textarea</TD>
      <TD>[4] FileUpload</TD> <TD>[5] Checkbox</TD></TR>
    <TR>
      <TD>[6] Radio</TD>  <TD>[7] Select (list)</TD>
      <TD>[8] Select (menu)</TD>  <TD>[9] Button</TD>
      <TD>[10] Submit</TD>  <TD>[11] Reset</TD></TR>
  </TABLE>
</DIV>

<SCRIPT LANGUAGE="JavaScript1.1">
// This generic function appends details of an event to the big Textarea
// element in the form above. It will be called from various event handlers.
function report(element, event) 
{
    var t = element.form.textarea;
    var elmtname = element.name;
    if ((element.type == "select-one") || (element.type == "select-multiple")){
        value = " ";
        for(var i = 0; i < element.options.length; i++)
            if (element.options[i].selected) 
                value += element.options[i].value + " ";
    }
    else if (element.type == "textarea") value = "...";
    else value = element.value;
    var msg = event + ": " + elmtname + ' (' + value + ')\n';
    t.value = t.value + msg;
}

// This function adds a bunch of event handlers to every element in a form.
// It doesn't bother checking to see if the element supports the event handler,
// it just adds them all. Note that the event handlers call report() above.
function addhandlers(f)
{
    var click_handler = new Function("report(this, 'Click')");
    var change_handler = new Function("report(this, 'Change')");
    var focus_handler = new Function("report(this, 'Focus')");
    var blur_handler = new Function("report(this, 'Blur')");
    var select_handler = new Function("report(this, 'Select')");
        
    for(var i = 0; i < f.elements.length; i++) {
        var e = f.elements[i];
        e.onclick = click_handler;
        e.onchange = change_handler;
        e.onfocus = focus_handler;
        e.onblur = blur_handler;
        e.onselect = select_handler;
    }

    // Special case handlers for the buttons:
    f.clearbutton.onclick = 
        new Function("this.form.textarea.value=''; report(this, 'Click');");
    f.submitbutton.onclick = 
        new Function("report(this, 'Click'); return false");
    f.resetbutton.onclick = 
        new Function("this.form.reset(); report(this, 'Click'); return false");
}
// Activate our form by adding all possible event handlers!
addhandlers(document.everything);
</SCRIPT>


Last updated: October 4, 1999 by Adrian German