Web Programming Step by Step

Chapter 9
Events and the Prototype Library

Except where otherwise noted, the contents of this presentation are Copyright 2009 Marty Stepp and Jessica Miller.

Valid XHTML 1.1 Valid CSS!

9.1: The Prototype JavaScript Library

Problems with JavaScript

JavaScript is a powerful language, but it has many flaws:

Prototype

<script src="http://www.cs.washington.edu/education/courses/cse190m/09sp/prototype.js" 
 type="text/javascript"></script>

<!-- or, -->
<script src="http://prototypejs.org/assets/2008/1/25/prototype-1.6.0.2.js" 
 type="text/javascript"></script>

Prototype's new methods (9.1.2)

Prototype adds new methods to many existing JavaScript types:

Array clear clone compact each first flatten from indexOf
inspect last reduce reverse size toArray uniq without
Number abs ceil floor round succ times toColorPart toPaddedString
Object clone extend inspect isArray isElement isFunction isHash
isNumber isString isUndefined keys toHTML toQueryString values
String blank camelize capitalize dasherize empty endsWith escapeHTML
include inspect interpolate parseQuery scan startsWith strip
sub stripTags toQueryParams times toArray underscore unescapeHTML

The $ function (9.1.3)

$("id")

DOM element methods

absolutize addClassName classNames cleanWhitespace clonePosition
cumulativeOffset cumulativeScrollOffset empty extend firstDescendant
getDimensions getHeight getOffsetParent getStyle getWidth
hasClassName hide identify insert inspect
makeClipping makePositioned match positionedOffset readAttribute
recursivelyCollect relativize remove removeClassName replace
scrollTo select setOpacity setStyle show
toggle toggleClassName undoClipping undoPositioned update
viewportOffset visible wrap writeAttribute

Styles and CSS classes (9.1.4)

function makeFontBigger() {
	// turn text yellow and make it bigger
	if (!$("text").hasClassName("highlight")) {
		$("text").addClassName("highlight");
	}
	var size = parseInt($("text").getStyle("font-size"));
	$("text").style.fontSize = (size + 2) + "pt";
}

Common bug: incorrect usage of existing styles

this.style.top = this.getStyle("top") + 100 + "px";            // bad!
this.style.top = parseInt(this.getStyle("top")) + 100 + "px";  // correct

DOM tree traversal methods

method(s) description
ancestors, up elements above this one
childElements, descendants, down elements below this one (not text nodes)
siblings, next, nextSiblings,
previous, previousSiblings, adjacent
elements with same parent
as this one (not text nodes)
DOM element
// remove elements in "main" that do not contain "Sun"
var sibs = $("main").siblings();
for (var i = 0; i < sibs.length; i++) {
	if (sibs[i].innerHTML.indexOf("Sun") < 0) {
		sibs[i].remove();
	}
}

Methods for selecting elements

Prototype adds methods to the document object (and all DOM element objects) for selecting groups of elements:

getElementsByClassName array of elements that use given class attribute
select array of elements that match given CSS selector, such as "div#sidebar ul.news > li"
var gameButtons = $("game").select("button.control");
for (var i = 0; i < gameButtons.length; i++) {
	gameButtons[i].style.color = "yellow";
}

The $$ function (9.1.5)

var arrayName = $$("CSS selector");
// hide all "announcement" paragraphs in the "news" section
var paragraphs = $$("div#news p.announcement");
for (var i = 0; i < paragraphs.length; i++) {
	paragraphs[i].hide();
}

Common $$ issues

Prototype and forms (9.1.6)

$F("id")
var name = $F("username");
if (name.length < 4) {
	$("username").clear();
	$("login").disable();
}
activate clear disable enable
focus getValue present select

9.2: Event-Handling

More about events

abort blur change click dblclick error focus
keydown keypress keyup load mousedown mousemove mouseout
mouseover mouseup reset resize select submit unload

Attaching event handlers the Prototype way

element.onevent = function;
element.observe("event", "function");
// call the playNewGame function when the Play button is clicked
$("play").observe("click", playNewGame);

Attaching multiple event handlers with $$

// listen to clicks on all buttons with class "control" that
// are directly inside the section with ID "game"
window.observe("load", function() {
	var gameButtons = $$("#game > button.control");
	for (var i = 0; i < gameButtons.length; i++) {
		gameButtons[i].observe("click", gameButtonClick);
	}
});

function gameButtonClick() { ... }

The Event object

function name(event) {
	// an event handler function ...
}
method / property name description
type what kind of event, such as "click" or "mousedown"
element() * the element on which the event occurred
stop() ** cancels an event
stopObserving() removes an event handler

Mouse events (9.2.2)

clicking
click user presses/releases mouse button on this element
dblclick user presses/releases mouse button twice on this element
mousedown user presses down mouse button on this element
mouseup user releases mouse button on this element
movement
mouseover mouse cursor enters this element's box
mouseout mouse cursor exits this element's box
mousemove mouse cursor moves around within this element's box

Mouse event objects

The event parameter passed to a mouse event handler has the following properties:

mouse event
property/method description
clientX, clientY coordinates in browser window
screenX, screenY coordinates in screen
offsetX, offsetY coordinates in element
pointerX(),
pointerY() *
coordinates in entire web page
isLeftClick() ** true if left button was pressed

Mouse event example

<pre id="target">Move the mouse over me!</pre>
window.observe("load", function() {
	$("target").observe("mousemove", showCoords);
});

function showCoords(event) {
	this.innerHTML = 
		  "pointer: (" + event.pointerX() + ", " + event.pointerY() + ")\n"
		+ "screen : (" + event.screenX + ", " + event.screenY + ")\n"
		+ "client : (" + event.clientX + ", " + event.clientY + ")";
}
Move the mouse over me!

Keyboard/text events (9.2.3)

name description
keydown user presses a key while this element has keyboard focus
keyup user releases a key while this element has keyboard focus
keypress user presses and releases a key while this element has keyboard focus
focus this element gains keyboard focus
blur this element loses keyboard focus
select this element's text is selected or deselected)

Key event objects

property name description
keyCode ASCII integer value of key that was pressed
(convert to char with String.fromCharCode)
altKey, ctrlKey, shiftKey true if Shift key is being held
Prototype's key code constants
Event.KEY_BACKSPACE Event.KEY_DELETE Event.KEY_DOWN Event.KEY_END
Event.KEY_ESC Event.KEY_HOME Event.KEY_LEFT Event.KEY_PAGEDOWN
Event.KEY_PAGEUP Event.KEY_RETURN Event.KEY_RIGHT Event.KEY_TAB
Event.KEY_UP

Form events (9.2.4)

event name description
submit form is being submitted
reset form is being reset
change the text or state of a form control has changed
window.observe("load", function() {
	$("orderform").observe("submit", verify);
});

function verify(event) {
	if ($F("zipcode").length < 5) {
		event.stop();       // cancel form submission unless
	}                     // zip code is 5 chars long
}

Page/window events (9.2.5)

namedescription
load the browser loads the page
unload the browser exits the page
resize the browser window is resized
contextmenu the user right-clicks to pop up a context menu
error an error occurs when loading a document or an image
// best way to attach event handlers on page load
window.observe("load", function() {
document.observe("dom:loaded", function() {
	$("orderform").observe("submit", verify);
});

Timer events (9.2.6)

timer
method description
setTimeout(functiondelayMS); arranges to call given function after given delay in ms
setInterval(functiondelayMS); arranges to call given function repeatedly, every delayMS ms
clearTimeout(timerID);
clearInterval(timerID);
stops the given timer object so it will not call its function any more

setTimeout example

<button id="clickme">Click me!</button>
<span id="output"></span>
document.observe("dom:loaded", function() {
	$("clickme").observe("click", delayMsg);
});

function delayMsg() {
	setTimeout(booyah, 5000);
	$("output").innerHTML = "Wait for it...";
}

function booyah() {   // called when the timer goes off
	$("output").innerHTML = "BOOYAH!";
}

setInterval example

var timer = null;  // stores ID of interval timer

document.observe("dom:loaded", function() {
	$("clickme").observe("click", delayMsg2);
});

function delayMsg2() {
	if (timer == null) {
		timer = setInterval(rudy, 1000);
	} else {
		clearInterval(timer);
		timer = null;
	}
}

function rudy() {   // called each time the timer goes off
	$("output").innerHTML += " Rudy!";
}

Passing parameters to timers

function delayedMultiply() {
	// 6 and 7 are passed to multiply when timer goes off
	setTimeout(multiply, 2000, 6, 7);
}
function multiply(a, b) {
	alert(a * b);
}

Common timer errors