Image Replacement Example
Because image replacement is such a versatile technique we will end our discussion of the Image object with an extended example. Example 16-3 defines a ToggleButton class that uses image replacement to simulate a graphical checkbox. Because this class uses images that we provide, we can use bolder graphics than those plain-old graphics used by the standard HTML Checkbox object. Figure 16-1 shows how these toggle button graphics could appear on a web page. This is a complex, real-world example, and is worth studying carefully.
Figure 16-1: ToggleButtons implemented with image replacement
Example 16-3: Implementing a ToggleButton with Image Replacement
<SCRIPT LANGUAGE="JavaScript1.1"> //This is the constructor function for our new ToggleButton class.//Calling it creates a ToggleButton object and outputs the required//<A> and <IMG> tags into the specified document at the current location.//Therefore, don't call it for the current document from an event handler.//Arguments://document: the Document object the buttons will be created in.//checked: a Boolean that says whether the button is initially checked.//label: an optional string that specifies text to appear after the button.//onclick: an optional function to be called when the toggle button is//clicked. It will be passed a Boolean indicating the new//state of the button. You can also pass a string, which will//be converted to a function which is passed a Boolean argument//named "state".function ToggleButton(document, checked, label, onclick) { //first time called, document will be false. Ignore this call.if (document == null) return; //The first time we are called (and only the first time) we have//to do some special stuff. First, now that the prototype object//is created, we can set up our methods.//Second, we've got to load the images that we'll be using.//Doing this will get the images in the cache for when we need them.if (!ToggleButton.prototype.over) { //Initialize the prototype object to create our methods.ToggleButton.prototype.over = _ToggleButton_over; ToggleButton.prototype.out = _ToggleButton_out; ToggleButton.prototype.click = _ToggleButton_click; //Now create an array of image objects, and assign URLs to them.//The URLs of the images are configurable, and are stored in an//array property of this constructor function itself. They will be//initialized below. Because of a bug in Navigator, we've got//to maintain references to these images, so we store the array//in a property of the constructor rather than using a local variable.ToggleButton.images = new Array(4); for(var i = 0; i < 4; i++) { ToggleButton.images[i] = new Image(ToggleButton.width, ToggleButton.height); ToggleButton.images[i].src = ToggleButton.imagenames[i]; } } //Save some of the arguments we were passed.this.document = document; this.checked = checked; //Remember that the mouse is not currently on top of us.this.highlighted = false; //Save the onclick argument to be called when the button is clicked.//If it is not already a function, attempt to convert it//to a function that is passed a single argument, named state.this.onclick = onclick; if (typeof this.onclick == "string") this.onclick = new Function("state", this.onclick); //Figure out what entry in the document.images[] array the images//for this checkbox will be stored at.var index = document.images.length; //Now output the HTML code for this checkbox. Use <A> and <IMG> tags.//The event handlers we output here are confusing, but crucial to the//operation of this class. The "_tb" property is defined below, as//are the over(), out(), and click() methods.document.write(' <A HREF ="" ' + 'onMouseOver="document.images[' + index + ']._tb.over();return true;" '+ 'onMouseOut="document.images[' + index + ']._tb.out()" '+ 'onClick="document.images[' + index + ']._tb.click(); return false;">'); document.write('<IMG src="' + togglebutton.imagenames[this.checked+0] +'"'+ ' WIDTH=" + togglebutton.width + " HEIGHT=" + togglebutton.height + " BORDER=0 HSPACE=0 VSPACE=0 >'); if (label) document.write(label); document.write('</A>'); //Now that we've output the <IMG> tag, save a reference to the//Image object that it created in the ToggleButton object.this.image = document.images[index]; //And also make a link in the other direction: from the Image object//to this ToggleButton object. Do this by defining a "_tb" property//in the Image object.this.image._tb = this; } //This becomes the over() method.function _ToggleButton_over() { //Change the image, and remember that we're highlighted.this.image.src = ToggleButton.imagenames[this.checked + 2]; this.highlighted = true; } //This becomes the out() method.function _ToggleButton_out() { //Change the image, and remember that we're not highlighted.this.image.src = ToggleButton.imagenames[this.checked + 0]; this.highlighted = false; } //This becomes the click() method.function _ToggleButton_click() { //Toggle the state of the button, change the image, and call the//onclick method, if it was specified for this ToggleButton.this.checked = !this.checked; this.image.src = ToggleButton.imagenames[this.checked+this.highlighted*2]; if (this.onclick) this.onclick(this.checked); } //Initialize static class properties that describe the checkbox images. These//are just defaults. Programs can override them by assigning new values.//But the should only be overridden *before* any ToggleButtons are created.ToggleButton.imagenames = new Array(4); //create an arrayToggleButton.imagenames[0] = "togglebutton0.gif"; //the unchecked boxToggleButton.imagenames[1] = "togglebutton1.gif"; //the box with a check markToggleButton.imagenames[2] = "togglebutton2.gif"; //unchecked but highlightedToggleButton.imagenames[3] = "togglebutton3.gif"; //checked and highlightedToggleButton.width = ToggleButton.height = 25; //size of all images</SCRIPT> <!--Here's how we might use the ToggleButton class.--> Optional extras:<BR> <SCRIPT LANGUAGE="JavaScript1.1"> //Create the buttonsvar tb1 = new ToggleButton(document, true, "28.8K Modem<BR>"); var tb2 = new ToggleButton(document, false, "Laser Printer<BR>"); var tb3 = new ToggleButton(document, false, "Tape Backup Unit<BR>"); </SCRIPT> <!--Here's how we can use the ToggleButton objects from event handlers.--> <FORM> <INPUT TYPE="button" VALUE="Report Button States" > <INPUT TYPE="button" VALUE="Reset Buttons" > </FORM>