Message from discussion
JavaScript Events - Part 3 - An Event Library
Received: by 10.11.53.63 with SMTP id b63mr3145168cwa;
Tue, 13 Sep 2005 00:44:12 -0700 (PDT)
Return-Path: <pa...@askowl.com.au>
Received: from blogger.com (ftpout.blogger.com [66.102.15.83])
by mx.googlegroups.com with ESMTP id v11si4014572cwb.2005.09.13.00.43.41;
Tue, 13 Sep 2005 00:43:47 -0700 (PDT)
Received-SPF: neutral (googlegroups.com: 66.102.15.83 is neither permitted nor denied by best guess record for domain of pa...@askowl.com.au)
Received: from bla53.prod.google.com (unknown [10.20.1.242])
by blogger.com (Postfix) with ESMTP id 5D6BB19717
for <adeptreaders@googlegroups.com>; Mon, 12 Sep 2005 23:54:18 -0700 (PDT)
Message-ID: <2673745.1126594458376.JavaMail.root@bla53.prod.google.com>
From: Paul Marrington <pa...@askowl.com.au>
To: adeptreaders@googlegroups.com
Subject: [Adept Software Development] JavaScript Events - Part 3 - An Event Library
Mime-Version: 1.0
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: 7bit
Date: Mon, 12 Sep 2005 23:54:18 -0700 (PDT)
<html><head><base href="http://marringtons.com/Adept/blog/Software.Development/"></head><body bgcolor="white" text="black">
My first attempt at an event library allowed a single event to be attached to multiple elements, as well as multiple event methods to a single event on a single element. This is very useful when you want to track the mouse since you need to register the same even for multiple windows or frames. However, it did require the creation of a special event object and then to have that object attached. Consequently - except for the special mouse tracking case - most of my events were set in the time honoured way:
<pre style="FONT-STYLE: italic; FONT-FAMILY: monospace; font-size: small;">
element.onclick = function( evt)
{
evt = evt || event;
if (! evt.target)
evt.target = evt.srcElement;
alert( "clicking " + evt.target
}
</pre><p> </p>
The problems grew:
<ol>
<li>Every event function had to have the first two lines to ensure basic data conformity between browsers.
<li>If more than one piece of independent code wanted to set the same event, they had to know about each other or the event call was lost.
<li>The <i>target</i> field pointed to the element that triggered the event, not necessarily the element that owned the event. The latter isn't available from the event object for IE.
</ol>
I wanted to create a library that:
<ol>
<li>Could be called to set for an element event that already had others functions attached - either by HTML or due to earlier calls. Events needed to be called from most recent to oldest set.
<li>Would provide an event object already normalised for browser differences.
<li>Would provide an owner field that worked across all browsers.
<li>Could ease coding by setting multiple events for a single element, and multiple elements with the same event.
</ol>
<h4>Usage</h4>
The core method is called, surprisingly enough, Events.add(). It requires a reference to the element, the event name and a function to run when the event is triggered.
<ul>
<li>The event name, as with the DOM equivalent, does not start with "on". In other words, use "click", not "onclick".
<li>It will call multiple action methods for a single event.
<li>If the HTML had an event set, this event will be added as well.
<li>The action function has a normalised event object as its one parameter.
<li>It includes valid <i>target</i> and <I>owner</I> fields.
</ul>
<pre style="FONT-STYLE: italic; FONT-FAMILY: monospace; font-size: small;">
Events.add( menu, "click",
function( event)
{
Panel.menuHover = false;
menu.style.display = "none";
Panel.hideShield( menu.panel);
return true;
});
</pre><p> </p>
This can still cause a tedious amount of coding when a lot of events need to be set for a single element. I use an <i>addEvents()</i> method for these cases. It still sets events on a single element, but now it picks up these events from the methods of an object called <i>events</i>. This makes for some clear self-documenting code.
<pre style="FONT-STYLE: italic; FONT-FAMILY: monospace; font-size: small;">
Events.addEvents( tabBarTextNode, Panel.tabActions);
...
Panel.tabActions = {events : {}};
Panel.tabActions.events.click =
function( evt)
{
var panel
= Elements.getPanel( evt.target).panel;
Panel.setFocus( panel);
}
Panel.tabActions.events.contextmenu =
function( evt)
{
var panel = Elements.getPanel(
evt.target).panel;
var menu = Panel._contextMenu(
panel, Mouse.location( evt));
menu.style.top =
Panel.frame.height - menu.offsetHeight;
return false;
}
</pre><p> </p>
Less common - but just as important - are the situations where the same event and action need to be set on many elements. This following method has to use the parameters in a different order with the elements at the end, so that we can add as much as is needed.
<pre style="FONT-STYLE: italic; FONT-FAMILY: monospace; font-size: small;">
Events.addSameEvent( "contextmenu",
function() {alert('not allowed');},
panel.titleBar, panel.resizeBox,
panel.shadowRight, panel.shadowBottom);
</pre><p> </p>
This last method is going to take some describing - as is always the case when objects are used. It's used if you need to add an event to multiple elements that can be used to call multiple actions. None of the methods above will do the job. We can add multiple events to a single element, but we can't add a new event and have it be available to more than one element. The object <i>newList</i> resolves this deficiency: it creates a method that's also an object, so it can have state as well as function. The state is used to point to a list of events, rather than attach them to the element as we do above.
<pre style="FONT-STYLE: italic; FONT-FAMILY: monospace; font-size: small;">
// Called once to create event function objects.
Mouse.events = {};
Mouse.events.mousemove
= Events.newList( "mousemove");
Mouse.events.mouseup
= Events.newList( "mouseup");
Mouse.events.blur
= Events.newList( "blur");
...
// Called for each object we want
// to trigger the event list for.
// Note that the events added are
// function object, not just functions.
Mouse.initialise = function( w)
{ Events.addEvents( w, Mouse); }
...
// Elsewhere we add new events that will be
// called for each registered element
Mouse.events.mousemove.add( Panel.onmousemove);
Mouse.events.mouseup.add( Panel.onmouseup);
</pre><p> </p>
The mouse object here is the only occasion so far when I've used this more complex structure. Every window registers itself for Mouse events by calling <i>Mouse.initialise()</i>. Other modules that need to do something special on these actions register themselves with the action function objects using add(). To put it simply, <i>Panel.onmousemove()</i> will be called for each registered window.
<p>
Now, I suppose you want the library code. Well you can't have it yet. This article is already too long. I'll release it next week, so nyah. <br /><br />--<br><font color="gray" size="2">Posted by Paul Marrington to <a href="http://marringtons.com/Adept/blog/Software.Development/2005/09/javascript-events-part-3-event-library.html">Adept Software Development</a> at 9/13/2005 04:53:00 PM</font></body></html>