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.

