Rheinwerk Computing < openbook > Rheinwerk Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger.

 <<   zurück
JavaScript und AJAX von Christian Wenz
Das umfassende Handbuch
Buch: JavaScript und AJAX

JavaScript und AJAX
839 S., mit DVD, 39,90 Euro
Rheinwerk Computing
ISBN 3-89842-859-1
gp Kapitel 14 Ereignisbehandlung
  gp 14.1 Events mit dem Netscape Navigator
    gp 14.1.1 Neue Ereignisse
    gp 14.1.2 Ereignisse als Objekteigenschaften
    gp 14.1.3 Ereignisse abfangen
    gp 14.1.4 Ereignisbehandlung
    gp 14.1.5 Ereignisse umleiten
    gp 14.1.6 Ereignisse durchleiten
    gp 14.1.7 Tastatureingaben
  gp 14.2 Events mit dem Internet Explorer
    gp 14.2.1 Neue Ereignisse
    gp 14.2.2 Ereignisse als Objekteigenschaften
    gp 14.2.3 Spezielle Skripten
    gp 14.2.4 Ereignisse abfangen
    gp 14.2.5 Bubbling
    gp 14.2.6 Das Event-Objekt
  gp 14.3 Events mit beiden Browsern
    gp 14.3.1 Browserunabhängigkeit
    gp 14.3.2 Benutzereingaben
  gp 14.4 Andere (und moderne) Browser

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

Kapitel 14 Ereignisbehandlung

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 beim 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 gezeigt, und es wird eine alternative Methode vorgestellt, um Event-Handler zu setzen. Dann wird es erst richtig interessant: Sowohl Netscape als auch Microsoft haben seinerzeit 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 Verfahren aufgezeigt, wie Sie Ihre Abfragen für beide Browsertypen funktionsfähig machen können – ab Version 4, wohlgemerkt. Warum ist das (im Falle) von Netscape überhaupt noch relevant? Ganz einfach: Am Schluss sehen wir uns die aktuellen Mozilla-Browser an, die sich kräftig beim alten Netscape bedient haben.


Rheinwerk Computing

14.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 type="text/javascript"><!--
function hamlet() {
   alert("To be, or not to be");
}

//--></script>
</head>
<body onload="hamlet();">
<h1>Events mit Netscape</h1>
</body>
</html>

Rheinwerk Computing

14.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.

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

Am folgenden 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='';">
<h1>Neue Mausereignisse</h1>
<form>
<input type="button" value="Klick mich!"
  onmousedown="window.status+='[mousedown]';"
  onmouseup="window.status+='[mouseup]';"
  onclick="window.status+='[click]';" />
</form>
</body>
</html>

Abbildung
Hier klicken, um das Bild zu Vergrößern

Abbildung 14.1     Die neuen Mausereignisse

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 in Abschnitt 14.1.7, »Tastatureingaben«, mehr.


Rheinwerk Computing

14.1.2 Ereignisse als Objekteigenschaften  downtop

Event-Handler können auch ohne HTML-Markup besetzt werden. Kommen wir zu dem Code vom Anfang des Kapitels zurück:

<body onload="hamlet();">

Dies kann auch folgendermaßen ausgedrückt werden:

window.onload = hamlet;

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 angegeben wird. 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.

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 natürlich 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 type="text/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>
<h1>Neue Mausereignisse</h1>
<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.

Mit anonymen Funktionen können Sie ein wenig Tipparbeit einsparen. Beim Setzen von window.onload (oder einer anderen Ereignis-Eigenschaft) geben Sie einfach den Funktionscode an, ohne extra eine (benannte) Funktion definieren zu müssen:

<html>
<head>
<title>Neue Mausereignisse</title>
<script type="text/javascript"><!--
window.onload = function() {
   window.status = '';
   with (document.forms[0].elements[0]) {
      onclick =
         function () { window.status += "[click]"; };
      onmouseup =
         function () { window.status += "[mouseup]"; };
      onmousedown =
         function () { window.status += "[mousedown]"; };
  }
};
//--></script>
</head>
<body>
<h1>Neue Mausereignisse</h1>
<form>
<input type="button" value="Klick mich!" />
</form>
</body>
</html>

Rheinwerk Computing

14.1.3 Ereignisse abfangen  downtop

Wie oben zu sehen ist, 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, dass das Ereignis komplett in Großbuchstaben erscheint) ist verpflichtend. Das Event-Objekt wird in diesem Kapitel noch etwas ausführlicher behandelt.

Der Opera-Browser unterstützt window.captureEvents() nicht; hier müssen Sie document.captureEvents() verwenden!

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 wohlfühlt (die Verwechslungsgefahr mit || ist recht groß). Die Methode capture-Events() kann nicht nur beim window-Objekt eingesetzt werden, sondern auch beim document-Objekt. 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);

Rheinwerk Computing

14.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, als 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, sondern »von oben« gesteuert werden.

Zunächst einmal muss man mit captureEvents() die Ereignisse an das window-Objekt binden (zumindest in diesem Beispiel). 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 type="text/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>
<h1>Neue Mausereignisse</h1>
<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 (als Referenz), also das Objekt, für das das Ereignis bestimmt war.
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 diesen »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
Hier klicken, um das Bild zu Vergrößern

Abbildung 14.2     Die angeklickte Schaltfläche wird identifiziert.


Rheinwerk Computing

14.1.5 Ereignisse umleiten  downtop

Es ist 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 von Galileo Press 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 type="text/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>
<h1>Neue Mausereignisse</h1>

<form>
<input type="button" name="Button1" value="Button1" />
<input type="button" name="Button2" value="Button2" />
</form>
<hr />
<a href="https://www.rheinwerk-verlag.de">Galileo Press</a>
</body>
</html>

Rheinwerk Computing

14.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 Methode wird auch das Ereignis als Parameter übergeben, aber man kann mit ihr das Ereignis nicht an ein fixes Objekt weitergeben, sondern muss 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 Objekt in der Hierarchie) einen Event-Handler für das Ereignis (hier: click) hat. Falls nicht, 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. Das können Sie verhindern, indem Sie überprüfen, 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, so dass das Ziel des Links auch angezeigt wird, ohne dass groß mit handleEvent() umgeleitet werden muss.
<html>
<head>
<title>Neue Mausereignisse</title>
<script type="text/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>
<h1>Neue Mausereignisse</h1>
<form>
<input type="button" name="Button1" value="Button1" />
<input type="button" name="Button2" value="Button2" />
</form>
<hr />
<a href="https://www.rheinwerk-verlag.de" >Galileo Press</a>
</body>
</html>

Rheinwerk Computing

14.1.7 Tastatureingaben  toptop

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

Das W3C-DOM Level 2 kennt keine Tastatureingaben. Sprich, die Browserhersteller mussten hier Pionierarbeit leisten – was dazu führt, dass verschiedene Browser einige Unterschiede in der Tastaturhandhabung aufweisen.

Bei Tastatureingaben gewinnt das Ereignis besonders an 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 Mozilla</title>
<script type="text/javascript"><!--
var versuche = 0;
var geheim = "K"  //Geheimes Zeichen
function taste(e) {
   versuche = 0;
   //Umwandlung von 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" />
</form>
</body>
</html>

Ein Hinweis noch am Rande: Mit einer einzigen zusätzlichen Zeile kann man zumindest verhindern, dass auf Nicht-Netscape-Browsern eine Fehlermeldung ausgegeben wird. Nicht vorhandene Eigenschaften kann man ohne Probleme setzen, die einzige Gefahrenquelle ist die folgende Zeile:

document.captureEvents(Event.KEYPRESS);

Mit einem kleinen Trick kann man das verhindern:

if (document.captureEvents) {
   document.captureEvents(Event.KEYPRESS);
}
 <<   zurück
  
  Zum Katalog
Zum Katalog: JavaScript und AJAX
JavaScript und AJAX
bestellen
 Ihre Meinung?
Wie hat Ihnen das <openbook> gefallen?
Ihre Meinung

 Buchtipps
Zum Katalog: JavaScript






 JavaScript


Zum Katalog: jQuery






 jQuery


Zum Katalog: Einstieg in JavaScript






 Einstieg in JavaScript


Zum Katalog: Responsive Webdesign






 Responsive Webdesign


Zum Katalog: Suchmaschinen-Optimierung






 Suchmaschinen-
 Optimierung


 Shopping
Versandkostenfrei bestellen in Deutschland und Österreich
InfoInfo




Copyright © Rheinwerk Verlag GmbH 2007
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. 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.


[Rheinwerk Computing]

Galileo Press, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de