ChunkySoup.netServing hearty nuggets since 2001

Intro to Object Oriented JavaScript

Part 4: Custom Objects, in code

Didn't I promise there would be code?

I expect that you are already familiar with the JavaScript syntax used below, so I won't go into too much detail. You will notice the regular use of the reference this. When you have used it previously it may have refererred to the document or a form element when working with event handlers like onchange. In its use here it is referring to the object that we are creating.

If you peeked at the source code of the finished example you will notice that I've put each object that was created into its own source file, this is also how I broke it down here. This is done not only because it results in a clean final document, but because it encourages reuse of the objects in other projects. All I have to do is link the object I want to use from another document and it is available.

csnPhotoNavObject.js

// object constructor
function csnPhotoNavObject(csnPhoto) {
	// define object's properties
	this.photo = csnPhoto;

	// attach object's methods
	this.handleMouseOver = csnPhotoNavObjectShowThumb;
	this.handleMouseOut = csnPhotoNavObjectHideThumb;
	this.handleClick = csnPhotoNavObjectHandleClick;
}

// define object's methods

function csnPhotoNavObjectShowThumb() {
	// simply hand off this off to the photo object
	this.photo.showThumb();

}

function csnPhotoNavObjectHideThumb() {
	// simply hand off this off to the photo object
	this.photo.hideThumb();
}

function  csnPhotoNavObjectHandleClick() {
	// our other events were a bit simpler, here we want to return
	// false in addition to showing the full photo
	this.photo.showFull(); // first hand the display of the image off
	return false; // then return false
}

csnPhotoObject.js

// object constructor
function csnPhotoObject(thumbID,thumbOffURI,thumbOnURI,fullID,fullURI) {
	// define object's properties
	this.thumbDOMRef = document.getElementById(thumbID);
	this.fullDOMRef = document.getElementById(fullID);
	this.thumbOffImg = new csnSmartImageObject(thumbOffURI,true);
	this.thumbOnImg = new csnSmartImageObject(thumbOnURI,true);
	// we don't want to load the full image until its needed
	this.fullImg = new csnSmartImageObject(fullURI,false);

	// attach object's methods
	this.showThumb = csnPhotoObjectShowThumb;
	this.hideThumb = csnPhotoObjectHideThumb;
	this.showFull = csnPhotoObjectShowFull;

}

// define object's methods
function csnPhotoObjectShowThumb() {
	this.thumbDOMRef.src = this.thumbOnImg.getImage(); }
function csnPhotoObjectHideThumb() {
	this.thumbDOMRef.src = this.thumbOffImg.getImage(); }
function csnPhotoObjectShowFull() {
	this.fullDOMRef.src = this.fullImg.getImage(); }

csnSmartImageObject.js

// object constructor
function csnSmartImageObject(imgURI,preload) {
  // define local properties
  this.URI = imgURI;
  // we don't need this image until we are ready to load
  this.imageobj = null;

  // attach object's methods
  this.load = csnSmartImageObjectLoad; //  force the loading of the image
  this.getImage = csnSmartImageObjectGetImage; /* this function will
    retrieve the source of the image from this object for use by other
    javscript objects */

  // complete constuctor
  if (preload) { // if preload is true load the image up right away
    this.load();
  }
}

// define object's methods
function csnSmartImageObjectLoad() {
  this.imageobj = new Image(); // create the image object
  this.imageobj.src = this.URI;
}

function csnSmartImageObjectGetImage() {
  if (this.imageobj) { // if we already have it, send the src along
    return this.imageobj.src;
  } else { // if not send the URI to the source back
    /* note, it may be better form to load() and then return the full
        source when its done loading, but this is a much easier way to
        code it and works because the image.src is "overloaded" and can
        handle either case */
    this.load();
    return this.URI;
  }
}

prototype.html

I have always found it easier to work first with prototypes. It allows me to work on the graphic production issues separately from the interactive and scripting issues. It is also very convienient for completely scrapping if you find that you've gone down the wrong direction. For this particular project I worked up a small functional prototype to help in building the above javascript objects.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html lang="en">
<head>
<title>Object Oriented JavaScript - Photo Interface Example</title>

<script type="text/javascript" src="csnSmartImageObject.js"></script>
<script type="text/javascript" src="csnPhotoObject.js"></script>

<script type="text/javascript" src="csnPhotoNavObject.js"></script>

<script type="text/javascript">
<!--

var elements = new Array();
var thumbnailID = "thumbnail"; // this is universal for the page
var emptyimg = "empty.gif"; // this is universal for the page
var photoID = "bigimage"; // this is universal for the page

function initpage() {
  elements[0] =
    new csnPhotoNavObject(new csnPhotoObject(thumbnailID,emptyimg,
      "photo1_tn.gif",photoID,"photo1.gif"))
}
// -->
</script>
<style type="text/css">
<!--
body { color:black; background-color:white; }
img { border:1px red solid; }
a { color:blue; font-size:20px; }
a:hover { color:red; }
a:active { color:purple; }
-->
</style>
</head>
<body onload="initpage()">
<div>
<a href="#" id="navthing"
  onmouseover="elements[0].handleMouseOver()"
  onmouseout="elements[0].handleMouseOut()"
  onclick="return elements[0].handleClick()">1</a><br>

<img id="thumbnail" src="empty.gif" height="60" width="40" alt="thumbnail">
<img id="bigimage" src="empty.gif" height="300" width="200" alt="photo">
</div>

</body>
</html>

finishedgallery.html

Once all the scripting above was finished and working in the prototype I went ahead and put together the finished gallery. I've done a small amount of cleanup in the HTML code (e.g. adding other content; accounting for lack of javascript). I've also added a good deal of CSS to achieve the layout I wanted. The important thing, is that the JavaScript portions of the gallery are, aside from some variable assignments, identical to the prototype.