<!--#include virtual="commontop.html" -->
<title>Web Programming Step by Step, Lecture 15: Events</title>
</head>
<body>
<div class="layout">
<div id="controls"><!-- DO NOT EDIT --></div>
<div id="currentSlide"><!-- DO NOT EDIT --></div>
<div id="header"></div>
<div id="footer">
<h1><em>Web Programming Step by Step</em>, Lecture 15</h1>
<h2>Events</h2>
</div>
</div>
<div class="presentation">
<div class="slide">
<h1><a href="http://www.webstepbook.com/">Web Programming Step by Step</a></h1>
<h3>Lecture 15 <br /> Events</h3>
<h4>Reading: 9.1 - 9.2</h4>
<p class="license">
Except where otherwise noted, the contents of this presentation are Copyright 2010 Marty Stepp and Jessica Miller.
</p>
<div class="w3c">
<a href="http://validator.w3.org/check/referer"><img src="images/w3c-xhtml11.png" alt="Valid XHTML 1.1" /></a>
<a href="http://jigsaw.w3.org/css-validator/check/referer"><img src="images/w3c-css.png" alt="Valid CSS!" /></a>
</div>
</div>
<!-- <div class="slide titleslide">
<h1>9.2: Event-Handling</h1>
<ul>
<li>
8.1: Global DOM Objects
</li>
<li>
<strong>9.2: Event-Handling</strong>
</li>
</ul>
</div> -->
<div class="slide">
<h1>JavaScript events</h1>
<table class="standard">
<tr>
<td>
<code><a href="http://www.w3schools.com/jsref/jsref_onabort.asp">abort</a></code>
</td>
<td>
<code><a href="http://www.w3schools.com/jsref/jsref_onblur.asp">blur</a></code>
</td>
<td>
<code><a href="http://www.w3schools.com/jsref/jsref_onchange.asp">change</a></code>
</td>
<td>
<code><a href="http://www.w3schools.com/jsref/jsref_onclick.asp">click</a></code>
</td>
<td>
<code><a href="http://www.w3schools.com/jsref/jsref_ondblclick.asp">dblclick</a></code>
</td>
<td>
<code><a href="http://www.w3schools.com/jsref/jsref_onerror.asp">error</a></code>
</td>
<td>
<code><a href="http://www.w3schools.com/jsref/jsref_onfocus.asp">focus</a></code>
</td>
</tr>
<tr>
<td>
<code><a href="http://www.w3schools.com/jsref/jsref_onkeydown.asp">keydown</a></code>
</td>
<td>
<code><a href="http://www.w3schools.com/jsref/jsref_onkeypress.asp">keypress</a></code>
</td>
<td>
<code><a href="http://www.w3schools.com/jsref/jsref_onkeyup.asp">keyup</a></code>
</td>
<td>
<code><a href="http://www.w3schools.com/jsref/jsref_onload.asp">load</a></code>
</td>
<td>
<code><a href="http://www.w3schools.com/jsref/jsref_onmousedown.asp">mousedown</a></code>
</td>
<td>
<code><a href="http://www.w3schools.com/jsref/jsref_onmousemove.asp">mousemove</a></code>
</td>
<td>
<code><a href="http://www.w3schools.com/jsref/jsref_onmouseout.asp">mouseout</a></code>
</td>
</tr>
<tr>
<td>
<code><a href="http://www.w3schools.com/jsref/jsref_onmouseover.asp">mouseover</a></code>
</td>
<td>
<code><a href="http://www.w3schools.com/jsref/jsref_onmouseup.asp">mouseup</a></code>
</td>
<td>
<code><a href="http://www.w3schools.com/jsref/jsref_onreset.asp">reset</a></code>
</td>
<td>
<code><a href="http://www.w3schools.com/jsref/jsref_onresize.asp">resize</a></code>
</td>
<td>
<code><a href="http://www.w3schools.com/jsref/jsref_onselect.asp">select</a></code>
</td>
<td>
<code><a href="http://www.w3schools.com/jsref/jsref_onsubmit.asp">submit</a></code>
</td>
<td>
<code><a href="http://www.w3schools.com/jsref/jsref_onunload.asp">unload</a></code>
</td>
</tr>
</table>
<ul>
<li>
the <code>click</code> event (<code>onclick</code>) is just one of many events that can be handled
</li>
<li>
<strong>problem</strong>: events are tricky and have <a href="http://www.quirksmode.org/js/introevents.html">incompatibilities</a> across browsers
<ul>
<li>
reasons: fuzzy W3C event specs; IE disobeying web standards; etc.
</li>
</ul>
</li>
<li>
<strong>solution</strong>: Prototype includes many event-related features and fixes
</li>
</ul>
</div>
<div class="slide">
<h1>Attaching event handlers the Prototype way</h1>
<pre class="syntaxtemplate js">
<del><var>element</var>.on<var>event</var> = <var>function</var></del>;
<var>element</var>.observe("<var>event</var>", <var>function</var>);
</pre>
<pre class="examplecode js">
<span class="comment">// call the playNewGame function when the Play button is clicked</span>
$("play").observe("click", playNewGame);
</pre>
<ul>
<li>
to use Prototype's event features, you must attach the handler using the DOM element object's <code>observe</code> method (added by Prototype)
</li>
<li>
pass the <strong>event name</strong> as a string, and the <strong>function name</strong> to call
</li>
<li>
handlers <em>must</em> be attached this way for Prototype's event features to work
</li>
</ul>
<ul class="aside" style="margin-top: 2em">
<li>
<code>observe</code> substitutes for <a href="http://www.quirksmode.org/js/events_advanced.html"><code>addEventListener</code></a> (not supported by IE)
</li>
</ul>
</div>
<div class="slide">
<h1>Prototype alternative to <code>window.onload</code></h1>
<pre class="syntaxtemplate js">
<del>window.onload = function() {
// ...
};</del>
document.<em>observe</em>(<em>'dom:loaded'</em>, function() {
// ...
});
</pre>
<pre class="examplecode js">
<span class="comment">// attach playNewGame click handler when page has finished loading</span>
document.observe('dom:loaded', function () {
$('play').observe('click', playNewGame);
});
</pre>
<ul>
<li>
allows multiple scripts to run "onload" handlers when the page has finished loading
</li>
</ul>
</div>
<div class="slide">
<h1>Attaching multiple event handlers with <code>$$</code></h1>
<pre class="examplecode js">
<span class="comment">// listen to clicks on all buttons with class "control" that
// are directly inside the section with ID "game"</span>
document.observe('dom:loaded', function() {
var gameButtons = <em>$$("#game > button.control")</em>;
for (var i = 0; i < gameButtons.length; i++) {
<em>gameButtons[i].observe("click", gameButtonClick);</em>
}
});
function gameButtonClick() { ... }
</pre>
<ul>
<li>you can use <code>$$</code> and other DOM walking methods to unobtrusively attach event handlers to a group of related elements in your <code>window.onload</code> code</li>
</ul>
</div>
<div class="slide">
<h1>The <code>event</code> object</h1>
<pre class="syntaxtemplate js">
function <var>name</var>(<em>event</em>) {
<span class="comment">// an event handler function ...</span>
}
</pre>
<ul>
<li>
Event handlers can accept an optional parameter to represent the event that is occurring. Event objects have the following properties / methods:
</li>
</ul>
<table class="standard">
<tr>
<th>
method / property name
</th>
<th>
description
</th>
</tr>
<tr>
<td>
<code>type</code>
</td>
<td>
what kind of event, such as <code>"click"</code> or <code>"mousedown"</code>
</td>
</tr>
<tr>
<td>
<a href="http://prototypejs.org/api/event/element"><code>element()</code></a> *
</td>
<td>
the element on which the event occurred
</td>
</tr>
<tr>
<td>
<a href="http://prototypejs.org/api/event/stop"><code>stop()</code></a> **
</td>
<td>
cancels an event
</td>
</tr>
<tr>
<td>
<a href="http://prototypejs.org/api/event/stopObserving"><code>stopObserving()</code></a>
</td>
<td>
removes an event handler
</td>
</tr>
</table>
<ul class="aside" style="list-style-type: none">
<li>
* replaces non-standard <code>srcElement</code> and <code>which</code> properties
</li>
<li>
** replaces non-standard <code>return false;</code>, <code>stopPropagation</code>, etc.
</li>
</ul>
</div>
<div class="slide">
<h1>
Mouse events
<span class="readingsection">(9.2.2)</span>
</h1>
<table class="standard">
<caption>clicking</caption>
<tr>
<td>
<code><a href="http://www.w3schools.com/jsref/jsref_onclick.asp">click</a></code>
</td>
<td>
user presses/releases mouse button on the element
</td>
</tr>
<tr>
<td>
<code><a href="http://www.w3schools.com/jsref/jsref_ondblclick.asp">dblclick</a></code>
</td>
<td>
user presses/releases mouse button twice on the element
</td>
</tr>
<tr>
<td>
<code><a href="http://www.w3schools.com/jsref/jsref_onmousedown.asp">mousedown</a></code>
</td>
<td>
user presses down mouse button on the element
</td>
</tr>
<tr>
<td>
<code><a href="http://www.w3schools.com/jsref/jsref_onmouseup.asp">mouseup</a></code>
</td>
<td>
user releases mouse button on the element
</td>
</tr>
</table>
<table class="standard">
<caption>movement</caption>
<tr>
<td>
<code><a href="http://www.w3schools.com/jsref/jsref_onmouseover.asp">mouseover</a></code>
</td>
<td>
mouse cursor enters the element's box
</td>
</tr>
<tr>
<td>
<code><a href="http://www.w3schools.com/jsref/jsref_onmouseout.asp">mouseout</a></code>
</td>
<td>
mouse cursor exits the element's box
</td>
</tr>
<tr>
<td>
<code><a href="http://www.w3schools.com/jsref/jsref_onmousemove.asp">mousemove</a></code>
</td>
<td>
mouse cursor moves around within the element's box
</td>
</tr>
</table>
</div>
<div class="slide">
<h1>Mouse event objects</h1>
<p>
The <code>event</code> passed to a mouse handler has these properties:
</p>
<div class="rightfigure" style="width: 30%">
<img src="images/figure_2_mouse_events.png" alt="mouse event" style="width: 100%" />
</div>
<table class="standard">
<tr>
<th>
property/method
</th>
<th>
description
</th>
</tr>
<tr>
<td>
<code>clientX</code>, <code>clientY</code>
</td>
<td>
coordinates in <em>browser window</em>
</td>
</tr>
<tr>
<td>
<code>screenX</code>, <code>screenY</code>
</td>
<td>
coordinates in <em>screen</em>
</td>
</tr>
<tr>
<td>
<code>offsetX</code>, <code>offsetY</code>
</td>
<td>
coordinates in <em>element</em> (non-standard)
</td>
</tr>
<!--
<tr>
<td>
<code>pageX</code>, <code>pageY</code>
</td>
<td>
coordinates in <em>entire web page</em>
</td>
</tr>
-->
<tr>
<td>
<a href="http://prototypejs.org/api/event/pointerX"><code>pointerX()</code></a>, <br />
<a href="http://prototypejs.org/api/event/pointerY"><code>pointerY()</code></a> *
</td>
<td>
coordinates in <em>entire web page</em>
</td>
</tr>
<tr>
<td>
<a href="http://prototypejs.org/api/event/isLeftClick"><code>isLeftClick()</code></a> **
</td>
<td>
<code>true</code> if left button was pressed
</td>
</tr>
</table>
<ul class="aside" style="list-style-type: none">
<li>
* replaces non-standard properties <code>pageX</code> and <code>pageY</code>
</li>
<li>
** replaces non-standard properties <code>button</code> and <code>which</code>
</li>
</ul>
</div>
<div class="slide">
<h1>Mouse event example</h1>
<div class="example">
<pre class="examplecode html">
<pre id="target">Move the mouse over me!</pre>
</pre>
<pre class="examplecode js">
document.observe('dom:loaded', function() {
$("target").observe("mousemove", showCoords);
});
function showCoords(<em>event</em>) {
$("target").innerHTML =
"pointer: (" + <em>event.pointerX()</em> + ", " + <em>event.pointerY()</em> + ")\n"
+ "screen : (" + <em>event.screenX</em> + ", " + <em>event.screenY</em> + ")\n"
+ "client : (" + <em>event.clientX</em> + ", " + <em>event.clientY</em> + ")";
}
</pre>
<div class="exampleoutput">
<pre onmousemove="this.innerHTML = 'pointer: (' + event.pageX + ', ' + event.pageY + ')\n' + 'screen : (' + event.screenX + ', ' + event.screenY + ')\n' + 'client : (' + event.clientX + ', ' + event.clientY + ')';">
Move the mouse over me!</pre>
</div>
</div>
</div>
<div class="slide">
<h1>
The keyword <code>this</code>
<span class="readingsection">(8.1.3)</span>
</h1>
<pre class="syntaxtemplate js">
this.<var>fieldName</var> <span class="comment">// access field</span>
this.<var>fieldName</var> = <var>value</var>; <span class="comment">// modify field</span>
this.<var>methodName</var>(<var>parameters</var>); <span class="comment">// call method</span>
</pre>
<ul>
<li>
all JavaScript code actually runs inside of an object
</li>
<li>
by default, code runs in the global <code>window</code> object (so <code>this</code> === <code>window</code>)
<ul>
<li>
all global variables and functions you declare become part of <code>window</code>
</li>
</ul>
</li>
<li>
the <code>this</code> keyword refers to the current object
</li>
</ul>
</div>
<div class="slide">
<h1>
Event handler binding
</h1>
<div class="example">
<pre class="examplecode js">
document.observe('dom:loaded', function() {
<em>$("textbox").observe("mouseout", booyah);</em> <span class="comment">// bound to text box here</span>
<em>$("submit").observe("click", booyah);</em> <span class="comment">// bound to submit button here</span>
});
function booyah() { <span class="comment">// booyah knows what object it was called on</span>
<em>this</em>.value = "booyah";
}
</pre>
<div class="exampleoutput">
<input id="textbox" onmouseout="this.value = 'booyah';" />
<input type="submit" id="save" value="Save" onclick="this.value = 'booyah';">
</div>
</div>
<ul>
<li>event handlers attached unobtrusively are <span class="term">bound</span> to the element</li>
<li>inside the handler, that element becomes <code>this</code> (rather than the <code>window</code>)
</li>
</ul>
</div>
<div class="slide">
<h1>Fixing redundant code with <code>this</code></h1>
<pre class="examplecode html">
<fieldset>
<label><input type="radio" name="ducks" id="huey" <em>value="Huey"</em> /> Huey</label>
<label><input type="radio" name="ducks" id="dewey" <em>value="Dewey"</em> /> Dewey</label>
<label><input type="radio" name="ducks" id="louie" <em>value="Louie"</em> /> Louie</label>
</fieldset>
</pre>
<pre class="examplecode js">
function processDucks() {
<del class="bad"> if ($("huey").checked) {
alert("Huey is checked!");
} else if ($("dewey").checked) {
alert("Dewey is checked!");
} else {
alert("Louie is checked!");
}</del>
<span class="errorfixed">alert(<em>this.value + </em>" is checked!");</span>
}
</pre>
<ul>
<li>if the same function is assigned to multiple elements, each gets its own bound copy</li>
</ul>
</div>
<div class="slide">
<h1>
Problems with reading/changing styles
</h1>
<div class="example">
<pre class="examplecode html">
<button id="clickme">Click Me</button>
</pre>
<pre class="examplecode examplecode2 js">
document.observe('dom:loaded', function() {
$("clickme").onclick = biggerFont;
});
function biggerFont() {
<em class="bad">var size = parseInt($("clickme").style.fontSize);</em>
size += 4;
$("clickMe").style.fontSize = size + "pt";
}
</pre>
<div class="exampleoutput">
<button>Click Me</button>
</div>
</div>
<ul>
<li><a class="popup" href="http://www.w3schools.com/HTMLDOM/dom_obj_style.asp"><code>style</code></a> property lets you set any CSS style for an element</li>
<li>
problem: you cannot (usually) read existing styles with it
</li>
</ul>
</div>
<div class="slide">
<h1>
Accessing styles in Prototype
<span class="readingsection">(9.1.4)</span>
</h1>
<div class="example">
<pre class="examplecode js">
function biggerFont() {
<span class="comment">// turn text yellow and make it bigger</span>
var size = parseInt($("clickme").<em>getStyle</em>("font-size"));
$("clickme").style.fontSize = (size + 4) + "pt";
}
</pre>
<div class="exampleoutput">
<button style="font-size: 20pt !important;" onclick="var s = parseInt(this.style.fontSize); this.style.setProperty('font-size', s + 4 + 'pt', 'important');">Click Me</button>
</div>
</div>
<ul>
<li><code>getStyle</code> function added to DOM object allows accessing existing styles</li>
<li><code>addClassName</code>, <code>removeClassName</code>, <code>hasClassName</code> manipulate CSS classes</li>
</ul>
</div>
<div class="slide">
<h1>Common bug: incorrect usage of existing styles</h1>
<pre class="examplecode js">
<del>this.style.top = this.getStyle("top") + 100 + "px";</del> <span class="comment">// bad!</span>
</pre>
<ul>
<li>the above example computes e.g.
<code>"200px" + 100 + "px"</code> , <br />
which would evaluate to <code>"200px100px"</code>
</li>
<li>
a corrected version:
</li>
</ul>
<pre class="examplecode js">
this.style.top = <em>parseInt(</em>this.getStyle("top")<em>)</em> + 100 + "px"; <span class="comment">// correct</span>
</pre>
</div>
<div class="slide">
<h1>
Unobtrusive styling
<span class="readingsection">(8.2.3)</span>
</h1>
<pre class="examplecode js">
function okayClick() {
<del>this.style.color = "red";</del>
this.<em>className = "highlighted"</em>;
}
</pre>
<pre class="examplecode css">
.<em>highlighted</em> { color: red; }
</pre>
<ul>
<li>well-written JavaScript code should contain as little CSS as possible</li>
<li>use JS to set CSS classes/IDs on elements</li>
<li>define the styles of those classes/IDs in your CSS file</li>
</ul>
</div>
<div class="slide">
<h1>
Setting CSS classes in Prototype
<span class="readingsection">(9.1.4)</span>
</h1>
<pre class="examplecode js">
function highlightField() {
<span class="comment">// turn text yellow and make it bigger</span>
if (!$("text").<em>hasClassName</em>("invalid")) {
$("text").<em>addClassName</em>("highlight");
}
}
</pre>
<ul>
<li><code>addClassName</code>, <code>removeClassName</code>, <code>hasClassName</code> manipulate CSS classes</li>
<li>
similar to existing <code>className</code> DOM property, but don't have to manually split by spaces
</li>
</ul>
</div>
<!--#include virtual="commonbottom.html" -->