Galileo Computing <openbook>
Galileo Computing - Programming the Net
Galileo Computing - Programming the Net


JavaScript von Christian Wenz
Browserübergreifende Lösungen
JavaScript - Zum Katalog
gp Kapitel 15 Events
  gp 15.1 Events mit dem Netscape Navigator
  gp 15.2 Events mit dem Internet Explorer
  gp 15.3 Events mit beiden Browsern
  gp 15.4 Event-Handling im Netscape 6
  gp 15.5 Fragen & Aufgaben

Kapitel 15 Events

Große Ereignisse werfen ihre Dementis voraus.
– Lothar Schmidt

Die Behandlung von Ereignissen, also die Reaktion auf Benutzereingaben oder aktionen, gestaltet sich bis jetzt noch ziemlich überschaubar. Es gibt Event-Handler, die in den entsprechenden HTML-Tags eingesetzt werden und bei Eintreten des entsprechenden Ereignisses eine JavaScript-Aktion ausführen (können). In diesem Kapitel wird dieses Konzept noch einmal behandelt. Es werden Erweiterungen daran in der JavaScript-Version 1.2 und eine alternative Methode vorgestellt, um Event-Handler zu setzen. Dann wird es erst richtig interessant: Sowohl Netscape als auch Microsoft haben für die Version 4 ihrer Browser das Event-Konzept erweitert und bieten ausgefeiltere Möglichkeiten an. Eine praxisnahe Anwendung dafür zu finden, fällt nicht immer leicht, aber beispielsweise können Tastatureingaben abgefangen und zum Teil auch erkannt werden. Im letzten Abschnitt dieses Kapitels werden dann Wege aufgezeigt, wie Sie Ihre Abfragen für beide Browsertypen funktionsfähig machen – aber erst ab Version 4, wohlgemerkt. Ganz am Schluss werfen wir noch einen kurzen Blick auf den brandneuen Netscape 6.


Galileo Computing

15.1 Events mit dem Netscape Navigator  downtop

Im Folgenden wird – der Einfachheit halber – auf Ereignisse mit möglichst simplen Aktionen reagiert, im Normalfall mit window.alert(). Das hat den Vorteil, dass man – bei diesem neuen Stoff – nicht den Überblick innerhalb eines längeren, ausführlicheren Beispiels verliert, sondern sich auf das Wesentliche konzentrieren kann.

Die bisherige Methode, auf ein Ereignis zu reagieren, bestand darin, einen HTML-Event-Handler dementsprechend zu setzen:

<HTML>
<HEAD>
<TITLE>Events</TITLE>
<SCRIPT LANGUAGE="JavaScript"><!--
function hamlet(){
   alert("To be, or not to be")
}

//--></SCRIPT>
</HEAD>
<BODY onLoad="hamlet()">
<H3>Events mit Netscape</H3>
</BODY>
</HTML>

Galileo Computing

15.1.1 Neue Ereignisse  downtop

In JavaScript Version 1.2 wurden neue Ereignisse und dazugehörige Event-Handler eingeführt. Diese betreffen Maus- und Tastatureingaben.

gp  Bei einem Mausklick trat in den älteren Versionen nach dem Drücken und Loslassen der Maustaste das Ereignis click ein, und dann konnte mit dem Event-Handler onClick reagiert werden. Ab Netscape Navigator 4.0 wurde dieses Verfahren etwas verfeinert. Es gibt die zusätzlichen Ereignisse mousedown und mouseup, die eintreten, wenn die Maustaste gedrückt respektive wieder losgelassen wird. Ein Mausklick lässt also drei Ereignisse hintereinander eintreten, und zwar in dieser Reihenfolge:
gp  mousedown
gp  mouseup
gp  click

An folgendem Beispiel können Sie die Reihenfolge ausprobieren. Klicken Sie auf die Formular-Schaltfläche, und beobachten Sie, wie sich die Statuszeile verändert, wenn Sie die Schaltfläche anklicken und dann die Maustaste wieder loslassen.

<HTML>
<HEAD>
<TITLE>Neue Mausereignisse</TITLE>
</HEAD>
<BODY onLoad="window.status=''">
<H3>Neue Mausereignisse</H3>
<FORM>
<INPUT TYPE="BUTTON" VALUE="Klick mich!"
  onMousedown="window.status+='[mousedown]'"
  onMouseup="window.status+='[mouseup]'"
  onClick="window.status+='[click]'">


</FORM>
</BODY>
</HTML>
Abbildung 15.1  Die neuen Mausereignisse
Abbildung

Ein weiteres neues Ereignis ist dblclick, das einen Doppelklick darstellt. Neu ist auch das Ereignis mousemove, das die Bewegungen der Maus erfasst. Wir werden später darauf zurückkommen.

Auch Tastatureingaben können abgefangen werden, dazu erfahren Sie später in diesem Kapitel mehr.


Galileo Computing

15.1.2 Ereignisse als Objekteigenschaften  downtop

Ab JavaScript Version 1.1, also Netscape Navigator 3, konnte man Event-Handler auch ohne HTML-Code besetzen. Kommen wir zu dem Code vom Anfang des Kapitels zurück:

<BODY onLoad="hamlet()">
gp  Dies kann – ab JavaScript 1.1 – auch folgendermaßen ausgedrückt werden:
window.onload=hamlet
gp  Hierbei sind zwei Dinge bemerkenswert. Zum einen fehlen die Klammern hinter hamlet; das liegt daran, dass kein Funktionsaufruf angegeben werden darf, sondern eine Funktionsreferenz, also ein Funktionsname ohne Klammern. Zum anderen erfolgt die Zuweisung anders: Da <BODY onLoad=""> beim Laden des Fensters ausgeführt wird, muss die onload-Eigenschaft des window-Objekts gesetzt werden. Ab Netscape Navigator 4.0 ist man in der Groß- und Kleinschreibung relativ frei, aber Netscape Navigator 3 besteht ausschließlich auf Kleinbuchstaben; deswegen werden und müssen wir uns auf die Kleinschreibung beschränken, können also kein window.ONLOAD oder Ähnliches verwenden.

Durch dieses Vorgehen gewinnt man an Flexibilität, da man den Event-Handler an jeder Stelle im Dokument setzen kann. Ebenso kann – wenn es die Applikation erfordert – der Event-Handler gelöscht werden:

window.onload = null

In diesem Fall ist das eher unsinnig, da das Ereignis load ohnehin nur einmal auftritt, beim Laden der Seite nämlich.

Das oben angeführte Beispiel mit den neuen Mausereignissen kann wie folgt äquivalent umgeschrieben werden:

<HTML>
<HEAD>
<TITLE>Neue Mausereignisse</TITLE>
<SCRIPT LANGUAGE="JavaScript"><!--
function mclick(){window.status += "[click]"}
function mup(){window.status += "[mouseup]"} 
function mdown(){window.status += "[mousedown]"} 
function init(){
   window.status = ''
   with (document.forms[0].elements[0])
      onclick = mclick
      onmouseup = mup
      onmousedown = mdown
}
window.onload = init
//--></SCRIPT>
</HEAD>
<BODY>
<H3>Neue Mausereignisse</H3>
<FORM>
<INPUT TYPE="BUTTON" VALUE="Klick mich!">
</FORM>
</BODY>
</HTML>

Es ist hierbei sehr wichtig, dass die Funktion init() erst beim Eintreten des load-Ereignisses aufgerufen wird. Das Dokument muss vollständig geladen worden sein, denn davor existiert die Schaltfläche noch nicht, ihr können also auch keine Eigenschaften gegeben werden.


Galileo Computing

15.1.3 Ereignisse abfangen  downtop

Wie oben zu sehen, sind ein Ereignis und ein Event-Handler immer einem bestimmten Element zugewiesen. Die Funktion init() ist dem onLoad-Event-Handler des Fensters zugewiesen, die anderen Funktionen den mausbezogenen Event-Handlern der bestimmten Schaltfläche. Rein theoretisch kann es aber ganz geschickt sein, wenn nicht die Schaltfläche die Abarbeitung des Ereignisses übernimmt, sondern vielleicht das Fenster, das das »Oberobjekt« der Schaltfläche ist (die Schaltfläche kann als window.document.forms[0].elements[0] angesprochen werden). Dazu gibt es die Methode captureEvents(), mit der man festlegen kann, dass bestimmte Objekte Ereignisse abfangen, die in deren Unterobjekten auftreten. Als Parameter werden die zu überwachenden Ereignisse übergeben. Mit dem folgenden Befehl fängt das Objekt window alle click-Ereignisse in seinen Unterobjekten ab:

window.captureEvents(Event.CLICK)

Hierbei bezeichnet Event.CLICK das click-Ereignis, die Schreibweise (insbesondere das Ereignis in Großbuchstaben) ist verpflichtend. Das Event-Objekt wird in diesem Kapitel noch etwas ausführlicher behandelt.

Sollen mehrere Ereignisse überwacht werden, so werden diese – durch den |-Operator getrennt – angegeben. Der |-Operator steht für das bitweise Oder, was an dieser Stelle aber nicht sonderlich interessant ist; es kommt vielmehr darauf an, wie dieser Operator für die Ereignisbehandlung eingesetzt wird. Wenn das window-Objekt die Ereignisse click, mousedown und mouseup überprüfen soll, muss der folgende Befehl ausgeführt werden:

window.captureEvents(Event.CLICK | Event.MOUSEDOWN | Event.MOUSEUP)

Alternativ kann man auch mehrere captureEvents()-Aufrufe hintereinander schalten, wenn man sich mit dem |-Operator nicht wohl fühlt (die Verwechslungsgefahr mit || ist recht groß).

Die Methode captureEvents() kann nicht nur beim window-Objekt eingesetzt werden, sondern auch beim document-Objekt und beim layer-Objekt (dieses Objekt wird in den DHTML-Kapiteln noch näher erläutert).

Natürlich kann man das frühe Abfangen von Ereignissen auch wieder ausschalten; hierzu dient die Methode releaseEvents(). Die folgenden Codezeilen heben sich gegenseitig auf:

window.captureEvents(Event.CLICK | Event.MOUSEDOWN | Event.MOUSEUP)
window.releaseEvents(Event.CLICK | Event.MOUSEDOWN | Event.MOUSEUP)

Galileo Computing

15.1.4 Ereignisbehandlung  downtop

Wenn ein übergeordnetes Projekt Ereignisse abfangen soll, so muss man feststellen können, welches Ereignis wo eingetreten ist, um darauf reagieren zu können. Im Folgenden wird so etwas am bekannten Beispiel mit der Schaltfläche exemplarisch vorgeführt. Die Anwendung soll insofern erweitert werden, dass eine zweite Schaltfläche eingeführt wird, die auch mit Event-Handlern bestückt werden soll. Um Schreibarbeit zu sparen, soll die Ereignisbehandlung nicht direkt in dem HTML-Code für die Schaltflächen definiert werden, sondern »von oben« gesteuert werden.

Zunächst einmal muss man mit captureEvents() die Ereignisse an das window-Objekt (zumindest in diesem Beispiel) binden. Sodann muss man für die Ereignisse entsprechende Verarbeitungsfunktionen erstellen und zuweisen. Das Beispiel sieht dann ungefähr folgendermaßen aus:

<HTML>
<HEAD>
<TITLE>Neue Mausereignisse</TITLE>
<SCRIPT LANGUAGE="JavaScript"><!--
function mclick(e) {}
function mup(e) {}
function mdown(e) {}
window.captureEvents(Event.CLICK | Event.MOUSEDOWN | Event.MOUSEUP)
window.onclick = mclick
window.onmousedown = mdown
window.onmouseup = mup
//--></SCRIPT>
</HEAD>
<BODY>
<H3>Neue Mausereignisse</H3>
<FORM>
<INPUT TYPE="BUTTON" NAME="Button1" VALUE="Button1">
<INPUT TYPE="BUTTON" NAME="Button2" VALUE="Button2">
</FORM>
</BODY>
</HTML>

Beachten Sie die leeren Funktionsaufrufe:

function mclick(e) {}
function mup(e) {}
function mdown(e) {}

Anscheinend wird ein Parameter e übergeben, doch woher kommt dieser? Wenn man Event-Handler mittels JavaScript-Eigenschaften setzt, kann man ja keine Parameter übergeben, da die Klammern fehlen. In diesem Fall wird jedoch das Ereignis selbst, eine Instanz des Objekts Event, an die Behandlungsfunktion übergeben. Die Bezeichnung e ist hierbei zwar frei wählbar, das e hat sich aber mittlerweile in Programmiererkreisen durchgesetzt. Solche ungeschriebenen Gesetze haben den Vorteil, dass man fremden Code auch ohne ausreichende Dokumentation recht schnell verstehen kann – unter Umständen.

Das Event-Objekt hat eine ganze Reihe von Eigenschaften, die in der Referenz vollständig vorgestellt werden. Für unsere Zwecke verwenden wir zunächst die Folgenden:

gp  target: Das Ziel des Ereignisses, also das Objekt, für das das Ereignis bestimmt war. Im Gegensatz zu manchen Quellen gibt der Netscape Navigator 4.x eine Objektreferenz zurück und keine Zeichenkette.
gp  type: Die Art des Ereignisses als Zeichenkette

Sie sehen, dass es eigentlich völlig unnötig war, gleich drei Funktionen, mclick(), mdown() und mup(), zu verwenden, da sich der Typ des eingetretenen Ereignisses bestimmen lässt. Zur Übung können Sie diesem Missstand ja einmal beheben.

Die drei Behandlungsfunktionen werden nun so umgeschrieben, dass in der Statuszeile nicht nur der Name des Ereignisses angegeben wird, sondern auch der Name des Objekts, für das dieses Ereignis bestimmt war. Da man mit der Eigenschaft target eben dieses Objekt erhält, kann man mit der Objekteigenschaft name den gewünschten Wert erhalten.

function mclick(e){window.status += "[click@"+e.target.name+"]"}

function mup(e){window.status += "[mouseup@"+e.target.name+"]"}

function mdown(e){window.status += "[mousedown@"+e.target.name+"]"}
Abbildung 15.2  Die geklickte Schaltfläche wird identifiziert.
Abbildung


Galileo Computing

15.1.5 Ereignisse umleiten  downtop

Es ist ab dem Netscape Navigator 4 nicht nur möglich, Ereignisse abzufangen und abzuarbeiten, bevor sie bei dem eigentlichen Zielobjekt eintreffen; man kann die Ereignisse auch auf andere Objekte umleiten. Beispielsweise ist es möglich, ein click-Ereignis einer Schaltfläche auf einen Link umzuleiten. Wenn das click-Ereignis bei einem Link eintrifft, wird dieser Link aktiviert (das muss natürlich noch programmiert werden). Die entsprechende Methode heißt handleEvent(), und als Parameter muss das Ereignis explizit übergeben werden.

Wird im folgenden Code die erste Schaltfläche angeklickt, so wird das Ereignis an die Methode handleEvent() des Links übergeben (alle Links eines Dokuments werden im Array document.links[] gespeichert), und die Website des Galileo Verlags wird aufgerufen. Wird dagegen die zweite Schaltfläche angeklickt, so wird wie gewöhnlich die Statuszeile geändert.

<HTML>
<HEAD>
<TITLE>Neue Mausereignisse</TITLE>
<SCRIPT LANGUAGE="JavaScript"><!--
function mclick(e){
   if (e.target.name=="Button1")
      document.links[0].handleEvent(e)
   else
      window.status += "[click@"+e.target.name+"]" 
}
function mup(e){window.status += "[mouseup@"+e.target.name+"]"}
function mdown(e){window.status += "[mousedown@"+e.target.name+"]"}
window.captureEvents(Event.CLICK | Event.MOUSEDOWN | Event.MOUSEUP)
window.onclick = mclick
window.onmousedown = mdown
window.onmouseup = mup
function galileo(){location.href = "http://www.galileo-press.de"}
function init(){
   document.links[0].onclick = galileo
   window.status = ""
}
window.onload = init
//--></SCRIPT>
</HEAD>
<BODY>
<H3>Neue Mausereignisse</H3>
<FORM>
<INPUT TYPE="BUTTON" NAME="Button1" VALUE="Button1">
<INPUT TYPE="BUTTON" NAME="Button2" VALUE="Button2">
</FORM>
<HR>
<A HREF="http://www.galileo-press.de">Galileo Press</A>
</BODY>
</HTML>

Galileo Computing

15.1.6 Ereignisse durchleiten  downtop

Ein Problem hat das Netscape-System noch. Wenn dem window-Objekt ein Ereignis zugeordnet wird (durch captureEvents()), aber dieses Objekt damit nichts tut, ist das Ereignis verloren oder muss manuell an ein anderes Objekt weitergeleitet werden (mit handleEvent()). Das muss aber noch nicht das Ende der Fahnenstange sein; und in der Tat gibt es noch eine weitere Methode, routeEvent(). Dieser wird auch das Ereignis als Parameter übergeben, aber man kann mit ihr das Ereignis nicht an ein fixes Objekt weitergeben, sondern es in der Hierarchie nach unten durchreichen. Wird also eine Schaltfläche angeklickt, das click-Ereignis vom window-Objekt abgefangen und dann routeEvent(e) aufgerufen, so wird zuerst nachgeschaut, ob das document-Objekt (das Nächste in der Hierarchie) einen Event-Handler für das Ereignis (hier: click) hat. Falls nicht, so wird – in diesem Beispiel – zunächst das Formular überprüft, aber das hat beim Netscape Navigator ja ohnehin kein click-Ereignis. Zuletzt wird die Schaltfläche selbst überprüft.

Dieses Vorgehen hat seine Vorteile. So kann man explizit prüfen, wo ein Ereignis herkommt, und wenn man damit nichts anfangen kann, wird es einfach weitergereicht. Im folgenden Beispiel, der nächsten Erweiterung unseres Codes, wird dieses Verfahren an zwei Stellen eingesetzt.

gp  Wenn der Benutzer irgendwo in das Fenster klickt, tritt auch ein click-Ereignis auf, und wird vom window-Objekt (dank captureEvents()) abgefangen. Mitunter erscheint dann Müll in der Statuszeile. Dies wird verhindert, indem überprüft wird, ob der Name des aufrufenden Objekts mit "Button" anfängt.
gp  Klickt der Benutzer auf den Link, wird auch nichts in die Statuszeile geschrieben, und das Ereignis wird direkt weitergereicht, sodass das Ziel des Links auch angezeigt wird, ohne dass groß mit handleEvent() umgeleitet werden muss.
<HTML>
<HEAD>
<TITLE>Neue Mausereignisse</TITLE>
<SCRIPT LANGUAGE="JavaScript"><!--
function mclick(e){
   if (e.target.name.indexOf("Button")==0)
      window.status += "[click@"+e.target.name+"]" 
   routeEvent(e)
}
function mup(e){window.status += "[mouseup@"+e.target.name+"]"}
function mdown(e){window.status += "[mousedown@"+e.target.name+"]"}
window.captureEvents(Event.CLICK | Event.MOUSEDOWN | Event.MOUSEUP)
window.onclick = mclick
window.onmousedown = mdown
window.onmouseup = mup
function galileo(){location.href = "http://www.galileo-press.de"}
function init(){
   document.links[0].onclick = galileo
   window.status = ""
}
window.onload = init
//--></SCRIPT>
</HEAD>
<BODY>
<H3>Neue Mausereignisse</H3>
<FORM>
<INPUT TYPE="BUTTON" NAME="Button1" VALUE="Button1">
<INPUT TYPE="BUTTON" NAME="Button2" VALUE="Button2">
</FORM>
<HR>
<A HREF="http://www.galileo-press.de" >Galileo Press</A>
</BODY>
</HTML>

Galileo Computing

15.1.7 Tastatureingaben  downtop

Für Tastatureingaben wurden mit JavaScript 1.2 ebenfalls neue Ereignisse eingeführt. Auf einen Tastendruck tritt das Ereignis keypress ein. Wie bei einem Mausklick besteht auch dieser Tastendruck aus zwei Teilen, und zwar keydown (Taste drücken) und keyup (wieder loslassen).

Bei Tastatureingaben gewinnt das Ereignis an besonderer Bedeutung. In der Eigenschaft which steht der ASCII-Code des Zeichens. So kann ein einfaches Ratespiel implementiert werden. Der Benutzer kann in das folgende Texteingabefeld beliebige Buchstaben eingeben. Nach jedem Tastendruck wird der eingegebene Buchstabe mit dem zu erratenden Buchstaben verglichen. Hat der Benutzer richtig geraten, so wird dies ausgegeben. Bei jedem Rateversuch wird ein Zähler um eins erhöht, denn man kann nicht unendlich oft raten, sondern (bei uns) maximal zehnmal. Beachten Sie, wie im folgenden Code die Funktion immer mit return true verlassen wird, außer wenn das Ratespiel zu Ende ist, dann endet die Funktion mit return false. Der Grund ist Folgender: Wie Sie bereits an diversen Beispielen in anderen Kapiteln gesehen haben, wird die weitere Abarbeitung des Ereignisses im Browser abgebrochen, wenn ein Event-Handler mit return false endet. In diesem Fall soll verhindert werden, dass die zusätzlich eingetippten Buchstaben im Eingabefeld erscheinen.

<HTML>
<HEAD>
<TITLE>Tastatureingaben mit dem Netscape Navigator</TITLE>
<SCRIPT LANGUAGE="JavaScript"><!--
var versuche = 0
var geheim = "Q"  //Geheimes Zeichen
function taste(e){
   versuche = 0
   //Umwandlung ASCII-Code in Zeichen
   var zeichen = String.fromCharCode(e.which) 
   if (zeichen.toUpperCase()==geheim){
      alert("Richtig geraten, mit genau " + versuche + " Versuchen")
      versuche = 10
   }
   return (versuche<10)
}
document.captureEvents(Event.KEYPRESS)
document.onkeypress = taste
//--></SCRIPT>
</HEAD>
<BODY>
<FORM>
<INPUT TYPE="TEXT" SIZE=10>
</BODY>
</HTML>

Ein Hinweis noch am Rande: Mit einer einzigen zusätzlichen Zeile kann man zumindest verhindern, dass auf älteren Netscape-Browsern und auf allen Versionen des Microsoft Internet Explorer keine Fehlermeldung ausgegeben wird. Nicht vorhandene Eigenschaften kann man ohne Ärger setzen, die einzige Gefahrenquelle ist die folgende Zeile:

document.captureEvents(Event.KEYPRESS)

Mit einem Trick, der unter anderem schon aus dem Kapitel »Images« bekannt ist, kann man das verhindern:

if (document.captureEvents)
   document.captureEvents(Event.KEYPRESS)

Galileo Computing

15.2 Events mit dem Internet Explorer  downtop

Wie bereits eingangs erwähnt, hat auch der Internet Explorer mit seiner Version 4 ein neues Ereignismodell eingeführt. Leider ist dieses Modell fast vollständig inkompatibel zu der Variante von Netscape, aber gegen Ende dieses Kapitels werden wir uns auch dieses Problems annehmen. Galten alle vorherigen Beispiele in diesem Kapitel nur für den Netscape Navigator 4 oder höher, so funktionieren die folgenden Beispiele nur ab dem Internet Explorer Version 4. Zur Vereinigung dieser beiden Browser gelangen wir wie gesagt später.

Ganz allgemein kann man sagen, dass das DOM (Document Object Model) des Internet Explorer ausgereifter ist als die Netscape-Variante. So kann beispielsweise jeder Tag mit Event-Handlern bestückt werden, beispielsweise auch <P>, <I> und <B>. Um aber am Ende browser-unabhängig zu bleiben, sollte man nur die Elemente mit Event-Handlern bestücken, die auch der Netscape Navigator mit einer Ereignisbehandlung versehen kann.


Galileo Computing

15.2.1 Neue Ereignisse  downtop

Auch der Internet Explorer hat in Version 4 neue Ereignisse eingeführt. Für Mausbewegungen sind das mousedown, mouseup und dblclick; bei der Tastatur handelt es sich um keydown, keyup und keypress. Bei der Bedeutung dieser Ereignisse gibt es keinen Unterschied zu Netscape, sodass die Ereignisse an dieser Stelle nicht noch einmal ausführlich erklärt werden. Der Unterschied liegt in der Behandlung der Maus- und Tastatureingaben, aber dazu später mehr.


Galileo Computing

15.2.2 Ereignisse als Objekteigenschaften  downtop

gp  Auch der Internet Explorer 4 kann wie der Netscape Navigator 4 statt HTML-Event-Handlern JavaScript-Objekteigenschaften benutzen. Das Beispiel von oben kann also unverändert wieder verwendet werden:
<HTML>
<HEAD>
<TITLE>Events</TITLE>
<SCRIPT LANGUAGE="JavaScript"><!--
function hamlet(){
   alert("To be, or not to be")
}
window.onload = hamlet
//--></SCRIPT>
</HEAD>
<BODY>
<H3>Events mit dem Internet Explorer</H3>
</BODY>
</HTML>

Galileo Computing

15.2.3 Spezielle Skripten  downtop

Es gibt beim Internet Explorer eine spezielle Möglichkeit, Event-Handler zu erzeugen. Dazu verwendet man ein gewöhnlichen <SCRIPT>-Tag genommen, und setzt die Parameter EVENT und FOR. Ersterer enthält den Namen des Event-Handlers (beispielsweise onload oder onclick), Letzterer den Identifikator des Objekts oder HTML-Elements, für das der Event-Handler eingesetzt werden soll. In der Praxis sieht das folgendermaßen aus:

<HTML>
<HEAD>
<TITLE>Spezielle Skripten</TITLE>
<SCRIPT LANGUAGE="JavaScript" EVENT="onclick" FOR="Button1"><!--
window.status = "Schaltfläche gedrückt!"
//--></SCRIPT>
</HEAD>
<BODY>
<H3>Spezielle Skripten</H3>
<FORM>
<INPUT TPYE="BUTTON" NAME="Button1" VALUE="Klick mich">
</FORM>
</BODY>
</HTML>

So schön die Idee auch ist, in der Praxis ist dieses Vorgehen völlig verfehlt. Der Internet Explorer 3 sowie alle Netscape-Versionen ignorieren die Parameter EVENT und FOR des <SCRIPT>-Tags und führen die Befehle darin schon beim Laden der Seite aus. Aus diesem Grund werden Sie die obige Methode nur auf schlechten Seiten finden, und auch das nur äußerst selten.


Galileo Computing

15.2.4 Ereignisse abfangen  downtop

Beim Netscape Navigator kann man mit captureEvents() und release Events() Ereignisse abfangen, die in Unterobjekten auftreten. Das liegt daran, dass beim Netscape Navigator Ereignisse in der Regel nur an das Objekt weitergeleitet werden, für das das jeweilige Ereignis bestimmt ist. Beim Internet Explorer funktioniert es etwas anders: Tritt bei einem Objekt ein Ereignis auf und ist dazu kein Ereignis-Handler definiert, so wird zum überordneten Objekt weitergegangen und nachgeschaut, ob zu diesem vielleicht ein Event-Handler definiert ist. Um auf das in diesem Kapitel schon öfter verwendete Formularbeispiel zurückzukommen: Im folgenden Code werden alle Mausklicks in das Dokument abgefangen – also insbesondere auch die Klicks auf eine Schaltfläche:

<HTML>
<HEAD>
<TITLE>Ereignisse mit dem Internet Explorer</TITLE>
<SCRIPT LANGUAGE="JavaScript"><!--
function mclick(){
   window.status += "[Mausklick]"
}
document.onclick = mclick
//--></SCRIPT>
</HEAD>
<BODY onLoad="window.status=''">
<H3>Neue Mausereignisse</H3>
<FORM>
<INPUT TYPE="BUTTON" NAME="Button1" VALUE="Button1">
</FORM>
</BODY>
</HTML>

Auch für die Methode releaseEvents() gibt es eine äquivalente Anweisung – die Objekteigenschaft muss einfach auf null gesetzt werden:

document.onclick = null

Galileo Computing

15.2.5 Bubbling  downtop

Der zuvor skizzierte Ablauf beim Eintreten eines Ereignisses wird nun noch etwas genauer dargestellt. Tritt bei einem Objekt ein Ereignis auf, so wird bei diesem Objekt und dann nacheinander bei allen übergeordneten Objekten nachgeschaut, ob einer der beiden folgenden Fälle eintritt:

gp  Es gibt einen Event-Handler, und dieser wird mit return false abgeschlossen.
gp  Man ist beim obersten Objekt angelangt, dem document-Objekt.

Wenn man das oben dargestellte Programm leicht modifiziert bzw. ergänzt, kann man diesen Effekt sehr gut beobachten:

<HTML>
<HEAD>
<TITLE>Ereignisse mit dem Internet Explorer</TITLE>
<SCRIPT LANGUAGE="JavaScript"><!--
function mclick(){
   window.status += "[Mausklick]"
}
function buttonclick(){
   window.status += "[Buttonclick]"
}
document.onclick = mclick
//--></SCRIPT>
</HEAD>
<BODY onLoad="window.status=''">
<H3>Neue Mausereignisse</H3>
<FORM>
<INPUT TYPE="BUTTON" NAME="Button1" VALUE="Button1" 
onClick="buttonclick()">
</FORM>
</BODY>
</HTML>

Wenn Sie das Skript ausführen, und auf die Schaltfläche klicken, werden sowohl die Funktionen buttonclick() als auch mclick() aufgerufen.

Endet jedoch buttonclick() mit return false, so wird mclick() nicht mehr ausgeführt, wenn auf die Schaltfläche geklickt wird:

<HTML>
<HEAD>
<TITLE>Ereignisse mit dem Internet Explorer</TITLE>
<SCRIPT LANGUAGE="JavaScript"><!--
function mclick(){
   window.status += "[Mausklick]"
}

function buttonclick(){
   window.status += "[Buttonclick]"
   return false
}
document.onclick = mclick
//--></SCRIPT>
</HEAD>
<BODY onLoad="window.status=''">
<H3>Neue Mausereignisse</H3>
<FORM>
<INPUT TYPE="BUTTON" NAME="Button1" VALUE="Button1"
  onClick="buttonclick()">
</FORM>
</BODY>
</HTML>
Abbildung 15.3  Die neuen Mausereignisse
Abbildung

Das hierarchische Vorgehen von unten nach oben nennt man im Englischen »Bubbling«, weil das Ereignis wie eine Blase (bubble) nach oben steigt.


Galileo Computing

15.2.6 Das Event-Objekt  downtop

Schon im Abschnitt über den Netscape Navigator wurde das Event-Objekt vorgestellt. Die gute Nachricht: Beim Internet Explorer verhält sich dieses Objekt recht ähnlich. Die schlechte Nachricht: Es gibt ganz am Anfang einen entscheidenden Unterschied – Kompatibilität adé! Während beim Netscape Navigator das aktuelle Ereignis als Parameter an den Event-Handler übergeben wird, ist das beim Internet Explorer nicht so – es ist nicht einmal nötig. Auf das aktuelle Ereignis kann mit window.event oder einfach nur mit event zugegriffen werden.

Auch hier gibt es wieder die Eigenschaft type, die die Art des Ereignisses als Zeichenkette angibt (z. B. "load" oder "click"). Nur event.target gibt es nicht mehr, beim Internet Explorer heißt diese Eigenschaft srcElement und enthält (wie target beim Netscape Navigator) eine Referenz auf das Objekt, für das das Ereignis bestimmt war.

gp  Beachten Sie auf jeden Fall, dass beim Netscape Navigator Event mit großem E geschrieben wird, beim Internet Explorer mit kleinem e.
Abbildung 15.4  Die geklickte Schaltfläche wird identifiziert.
Abbildung

Im folgenden Beispiel wird der NAME-Parameter derjenigen Schaltfläche angegeben, die geklickt worden ist:

<HTML>
<HEAD>
<TITLE>Ereignisse mit dem Internet Explorer</TITLE>
<SCRIPT LANGUAGE="JavaScript"><!--
function mclick(){
   window.status +=  "["+event.type+"@"+event.srcElement.name+"]"
}
document.onclick = mclick
//--></SCRIPT>
</HEAD>
<BODY onLoad="window.status=''">
<H3>Neue Mausereignisse</H3>
<FORM>
<INPUT TYPE="BUTTON" NAME="Button1" VALUE="Button1"> 
<INPUT TYPE="BUTTON" NAME="Button2" VALUE="Button2">
</FORM>
</BODY>
</HTML>

Das Prinzip des Event-Bubblings kann nicht nur generell abgeschaltet werden – etwa durch ein return false – sondern auch explizit für genau ein Ereignis. Dazu verwenden Sie das folgende Kommando:

event.cancelBubble = true

Galileo Computing

15.3 Events mit beiden Browsern  downtop

Im letzten Abschnitt dieses Kapitels werden noch kurz Strategien vorgestellt, wie Sie Ihre Skripten auf beiden Browsern ohne Fehler benutzen können – vielleicht auf älteren Browsern nicht mit der vollen Funktionalität, aber immerhin ohne Fehlermeldungen. Außerdem werden kurz die Unterschiede bei der Abfrage von gedrückten Tastaturtasten und Maustasten bei den beiden »großen« Browsern beleuchtet.


Galileo Computing

15.3.1 Browser-Unabhängigkeit  downtop

Im Folgenden sollen einige allgemeine Konzepte vorgestellt werden, die bei der fortgeschrittenen, browserunabhängigen Ereignisbehandlung von Nutzen sein können.

Netscape oder nicht?

In Sachen Ereignis fällt es ziemlich leicht, den Netscape Navigator vom Internet Explorer zu unterscheiden. Sie verwenden dazu die Objektüberprüfung, die schon im Kapitel »Images« nützlich war:

if (window.Event)
   //Code für den Netscape Navigator 4
else 
   //Code für den Internet Explorer 4

Ereignisse abfangen

Wie bereits erwähnt, kennt der Internet Explorer die Methode capture Events() nicht; durch das Bubbling-Prinzip ist sie ja auch nicht nötig, da Ereignisse nach oben weitergereicht werden. Soll etwa ein Mausklick abgefangen werden, so kann man sich mit folgendem Code behelfen:

function mclick(){
   window.status += "[Mausklick]"
}
if (window.Event)
   document.captureEvents(Event.MOUSEUP)
document.onclick = mclick

Denken Sie daran, dass der Internet Explorer beim document-Objekt aufhört und nicht mehr weiter nach oben gehen kann; Folgendes wäre also falsch:

if (window.Event)
   window.captureEvents(Event.MOUSEUP)
window.onclick = mclick

Ereigniseigenschaften

Wie bereits angedeutet, gibt es bei der Abfrage von Ereignissen Unterschiede zwischen den beiden Browsern, angefangen von der Übergabe als Parameter bis hin zur Schreibweise. Auch hier kann man sich wieder mit einer Objektüberprüfung behelfen:

function mclick(e){
   var ev = (window.Event) ? e : window.event
   window.status += "["+ev.type+"]"
}

if (window.Event)
   document.captureEvents(Event.MOUSEUP)
document.onclick = mclick

Beim Netscape Navigator wird auf den Parameter e zugegriffen, beim Internet Explorer auf window.event (oder event). Die Eigenschaft type ist bei beiden Browsern identisch, kann also problemlos verwendet werden. Bei dem Ziel des Ereignisses ist das etwas aufwendiger, man benötigt eine eigene Anweisung:

function mclick(e){
   var ev = (window.Event) ? e : window.event
   var ziel = (window.Event) ? ev.target : ev.srcElement
   window.status += "["+ev.type+"@"+ziel.name+"]"
}
if (window.Event)
   document.captureEvents(Event.MOUSEUP)
document.onclick = mclick

Galileo Computing

15.3.2 Benutzereingaben  downtop

In den vorherigen Abschnitten wurden Tastatureingaben und Mausklicks nur eher stiefmütterlich behandelt; beispielsweise wurden Sondertasten wie etwa (Alt) und (Strg) nicht erwähnt. Das soll sich an dieser Stelle ändern. Zwar unterscheiden sich auch hier die beiden Browser, aber inzwischen sollten Sie so abgehärtet sein, dafür eine Lösung zu finden.

Mausklicks

PC-Mäuse haben zwei oder drei Tasten. Da ist es doch interessant herauszufinden, welche dieser Tasten gedrückt worden ist. Bevor Sie sich irrwitzige Anwendungsmöglichkeiten ausdenken, eine kleine Warnung: Beispielsweise ruft die rechte Maustaste ein Kontextmenü auf, das Ereignis tritt (für den Browser) also gar nicht ein. Viele Maustreiber belegen die mittlere Maustaste mit einem Doppelklick, und damit ist die Taste für den differenzierten Einsatz auch nicht sonderlich geeignet.

Beim Netscape Navigator erhält man die Nummer der gedrückten Maustaste aus der which-Eigenschaft des aufgetretenen Ereignisses. Beim Internet Explorer dagegen gibt es hierfür eine gesonderte Eigenschaft, und zwar die Eigenschaft button des Ereignisses.

<HTML>
<HEAD>
<TITLE>Maustasten</TITLE>
<SCRIPT LANGUAGE="JavaScript"><!--
function taste(e){
   if (window.Event)
      var maustaste = e.which
   else 
      var maustaste = e.button
   
   window.status += "[geklickt:" + maustaste + "]"
}
//--></SCRIPT>
</HEAD>
<BODY onLoad="document.forms[0].elements[0].onclick=taste;
  window.status=''">
<H3>Maustasten</H3>
<FORM>
<INPUT TYPE="BUTTON" NAME="Button1" VALUE="Klick mich">
</FORM>
</BODY>
</HTML>

Tasten

Wie Sie bereits gesehen haben, erhält man den ASCII-Code beim Netscape Navigator aus der which-Eigenschaft des Ereignisses; beim Internet Explorer gibt es wieder eine eigene Eigenschaft, nämlich keyCode. Bei verschiedenen Plattformen gibt es hin und wieder Bugs in der Umsetzung, die aber mit der Methode String.fromCharCode() zusammenhängen. Bei manchen Internet Explorer-Versionen für den Macintosh werden einige seltenere Zeichen falsch zurückgegeben. Verlassen Sie sich im Zweifel also auf den ASCII-Code; im Produktionsbetrieb können Sie dennoch immer auf fromCharCode() zurückgreifen.

<HTML>
<HEAD>
<TITLE>Tastatur</TITLE>
<SCRIPT LANGUAGE="JavaScript"><!--
function taste(e){
   if (window.Event)
      var tastatur = e.which
   else 
      var tastatur = e.keyCode
   
   window.status += "[getippt:" +
     String.fromCharCode(tastatur) + "]"

//--></SCRIPT>
</HEAD>
<BODY onLoad="document.forms[0].elements[0].onclick=taste;
  window.status=''">
<H3>Tastatur</H3>
<FORM>
<INPUT TYPE="TEXT" NAME="TEXT1">
</FORM>
</BODY>
</HTML>

Sondertasten

Mit den Sondertasten verhält es sich vom Prinzip her ähnlich wie mit Tastatureingaben und Mausklicks. Während beim Netscape Navigator möglichst viel in eine Eigenschaft oder Variable gepackt worden ist (ressourcensparend), kann man beim Internet Explorer explizit auf eine bestimmte Eigenschaft pro Sondertaste zugreifen (benutzerfreundlich). Eine Einschränkung gibt es jedoch. Beim Netscape Navigator können die Tasten (Alt), (Strg), (Umschalt) und (Meta) (die (Windows)-Taste) abgefragt werden, beim Internet Explorer lediglich (Alt), (Strg) und (ª). Die (Control)-Taste, das Macintosh-Äquivalent zur (Strg)-Taste, kann beim Macintosh-IE 4 ebenfalls nicht abgefragt werden.

Anstelle von langen Erklärungen nachfolgend ein selbsterklärendes Beispiel. Während beim Internet Explorer einzelne Eigenschaften abgefragt werden, muss man beim Netscape Navigator wieder eine bitweise Operation, diesmal UND (&) verwenden.

<HTML>
<HEAD>
<TITLE>Sondertasten</TITLE>
<SCRIPT LANGUAGE="JavaScript"><!--
function taste(e){
   if (window.Event){//Netscape
      window.status += "["
      if (e.modifiers & Event.ALT_MASK)
         window.status += "Alt"
      if (e.modifiers & Event.CONTROL_MASK)
         window.status += "Strg"
      if (e.modifiers & Event.SHIFT_MASK)
         window.status += "Umschalt"
      if (e.modifiers & Event.META_MASK)
         window.status += "Meta"
      window.status += "]"
  } else{//IE
      window.status += "["
      if (event.altKey)
         window.status += "Alt"
      if (event.ctrlKey)
         window.status += "Strg"
      if (event.shiftKey)
         window.status += "Umschalt"
   }
}
//--></SCRIPT>
</HEAD>
<BODY onload="document.forms[0].elements[0].onclick=taste;
  window.status=''">
<H3>Sondertasten</H3>
<FORM>
<INPUT TYPE="BUTTON" NAME="Button1" VALUE="Klick mich!">
</FORM>
</BODY>
</HTML>
Abbildung 15.5  Auch gedrückte Sondertasten können abgefragt werden.
Abbildung

Testen Sie dieses Programm, indem Sie ein paar der Sondertasten gedrückt halten und dann mit der Maus auf die Schaltfläche klicken.


Galileo Computing

15.4 Event-Handling im Netscape 6  downtop

Die Ereignisbehandlung im neuen Netscape 6 ist eine Mischung aus den Konzepten des Netscape Navigator 4.x und des Internet Explorer ab Version 4. Während der Netscape Navigator ein Ereignis nur beim »Eintauchen« in eine Website abfangen kann (mit captureEvent), stößt der Internet Explorer auf dasselbe Ereignis, wie es via Bubbling nach oben steigt. Der Netscape 6 versteht beide Richtungen, die Ansteuerung ist identisch.

An einer Stelle mussten sich die Softwarearchitekten von Netscape jedoch entscheiden: Welches Modell wählen wir für das Ereignis-Objekt? Man entschied sich für die Netscape-Variante: An jeden Ereignis-Handler wird eine Variable übergeben (wird meistens im Funktionskopf mit e bezeichnet), auf deren Eigenschaften (z. B. e.target etc.) im Funktionsrumpf zugegriffen werden kann. Sie sehen also: Wenn Sie das Netscape-Konzept erst einmal begriffen haben, können Sie auch für Netscape 6 programmieren.


Galileo Computing

15.5 Fragen & Aufgaben  toptop

1. Was ist der prinzipielle Unterschied bei der Ereignisbehandlung zwischen Netscape Navigator und dem Microsoft Internet Explorer?
2. Aus welchen Teilereignissen besteht das dblclick-Ereignis? Geben Sie ein Testprogramm an, um genau dies herauszufinden.
3. Was ist der Unterschied zwischen handleEvent() und routeEvent()?
4. Welche drei (!) Möglichkeiten gibt es, um die »Ereignisdurchreichung« (Bubbling) beim Internet Explorer abzubrechen?
5. Erstellen Sie eine HTML-Seite mit drei Schaltflächen. Jede Schaltfläche ist mit einer URL beschriftet. Auf Mausklick soll genau diese URL geladen werden. Der Code darf nur mit Browsern ab Versionsnummer 4 funktionieren, verwenden Sie keine HTML-Event-Handler!
6. Das letzte Beispiel in diesem Kapitel führt beim Netscape Navigator 3 zu einem Fehler. Warum ist das so, und wie kann man das mit minimalem Aufwand beheben (indem man ein paar Zeichen ändert)?





1    Warum haben wir wohl die Statuszeile zur Ausgabe verwendet, und nicht ein Alert–Fenster?

2    Die linke, primäre Maustaste hat die Nummer 1; bei Mäusen für Linkshänder hat die rechte Maustaste die Nummer 1.

  

Webseiten

CSS-Praxis

Kompendium Informations-
technik

Der eigene Webserver

PC-Netzwerke




Copyright © Galileo Press GmbH 2001 - 2002
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken und speichern. Ansonsten unterliegt das <openbook> denselben Bestimmungen wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.
Die Veröffentlichung der Inhalte oder Teilen davon bedarf der ausdrücklichen schriftlichen Genehmigung von Galileo Press. Falls Sie Interesse daran haben sollten, die Inhalte auf Ihrer Website oder einer CD anzubieten, melden Sie sich bitte bei: stefan.krumbiegel@galileo-press.de


[Galileo Computing]

Galileo Press GmbH, Gartenstraße 24, 53229 Bonn, fon: 0228.42150.0, fax 0228.42150.77, info@galileo-press.de