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 8 Fenster II: Frames
  gp 8.1 Mit Frames arbeiten
  gp 8.2 Auf Daten von Frames zugreifen
  gp 8.3 Ein Warenkorb in JavaScript
  gp 8.4 Diashow
  gp 8.5 Fragen & Aufgaben

Kapitel 8 Fenster II: Frames

Fensterln: nachts zu einem Mädchen ans Fenster gehen
[und durchs Fenster zu ihm ins Zimmer klettern]
– Duden in acht Bänden

Das window-Objekt steht in der Objekthierarchie ganz oben. Dies ist verständlich, da alles, was man mit JavaScript anstellen kann, in irgendeiner Art von Fenster dargestellt wird. Wenn also eine Webseite aus mehreren Frames besteht, wird jeder dieser Frames wie ein Fenster behandelt, zumindest im Sinne von JavaScript. Sie sehen, es gibt viele verschiedene Anwendungen für dieses Objekt. Aus diesem Grund wird das Thema in drei Kapiteln behandelt.

In diesem Kapitel werden Sie erfahren, wie man mit JavaScript auf Frames zugreift und damit beispielsweise seine Navigation flexibler gestalten kann. Außerdem wird Schritt für Schritt eine der JavaScript-Standardanwendungen implementiert: eine Warenkorblösung.


Galileo Computing

8.1 Mit Frames arbeiten  downtop

Unter einem Frame versteht man einen Bereich im Browser-Fenster, der – genau wie das Browser-Fenster selbst – einen eigenen Scroll-Balken haben kann und unabhängig vom Rest der Webseite gescrollt werden kann. Frames tauchten das erste Mal im Netscape Navigator 2 auf und wurden sehr schnell von Webdesignern übernommen, erlaubten Frames doch eine bequeme Navigation. Viele Seiten bestanden zunächst aus zwei Frames: Der eine enthielt die Navigationspunkte, der zweite die eigentlichen Inhalte der Seite. Da sich die Navigation in dem Frame befand, musste sie nicht in die Seiten mit dem eigentlichen Inhalt mit eingeschlossen werden, was den Verwaltungsaufwand bei Änderungen verringerte (nur die Seite mit der Navigation musste angepasst werden, jedoch nicht jede einzelne Inhaltsseite). Der Internet Explorer übernahm Frames in der Version 3, und schon begannen die Webdesigner zu fluchen, da die Implementierung von Frames leicht unterschiedlich war (Stichwort: Abstand des Frame-Inhalts vom Frame-Rand). Mittlerweile geht der Trend zu Seiten ohne Frames zurück, auch in Hinblick auf Handhelds, deren eingeschränkte Browser oft mit Frames nichts anfangen können. Dennoch können Sie in Verbindung mit JavaScript mit Frames erstaunliche Dinge machen – Dinge, die ohne Frames nur mit Schwierigkeiten oder gar nicht realisiert werden könnten.

Mit JavaScript ist es möglich, von einem Frame aus Methoden, Eigenschaften und Variablen eines anderen Frames aufzurufen. Im Folgenden erfahren Sie zunächst etwas über den strukturellen Aufbau von Frames, und dann, wie diese Strukturen in JavaScript nachgebildet worden sind.


Galileo Computing

8.1.1 Frames mit HTML  downtop

Eine Frame-Struktur wird immer mit dem HTML-Tag <FRAMESET> eingeleitet. Es wird genau einer der beiden folgenden Parameter erwartet:

gp  ROWS: Die einzelnen Frames werden untereinander (in Zeilen, engl. rows) angeordnet.
gp  COLS: Die einzelnen Frames werden nebeneinander (in Spalten, engl. columns) angeordnet.

Als Wert für diesen Parameter werden – durch Kommata getrennt – die Höhen (bei ROWS) oder Breiten (bei COLS) der einzelnen Frames erwartet. Dabei haben Sie die Wahl zwischen drei Optionen:

gp  Angabe in Pixeln: Lediglich der numerische Wert wird angegeben.
gp  Angabe in Prozent der Gesamthöhe/-breite des Fensters, welches das <FRAMESET> enthält.
gp  »Rest«: Wird durch einen Stern (*) symbolisiert.

Diese Möglichkeiten können natürlich miteinander kombiniert werden. Da dieses Buch keine HTML-Einführung sein soll, folgen hier nur ein paar kurze Beispiele:

gp  <FRAMESET ROWS="100,200,300">: Drei Frames, untereinander angeordnet. Im Idealfall hat der oberste Frame eine Höhe von 100 Pixeln, der mittlere eine von 200 Pixeln, der untere eine von 300 Pixeln. Das ist deswegen ein Idealfall, da das Browser-Fenster wahrscheinlich nicht exakt 600 Pixel hoch ist.
gp  <FRAMESET COLS="100,50%,*">: Drei Frames, nebeneinander angeordnet. Der mittlere nimmt die halbe Breite ein, der linke ist exakt 100 Pixel breit, und der dritte Frame beansprucht die restliche Breite für sich. Sollte sich also die Breite des Browser-Fensters verändern, ändern gleichzeitig auch der mittlere und rechte Frame ihre Breite, der linke Frame bleibt jedoch in der Größe konstant.

Mit <FRAMESET> wird also die Frame-Struktur festgelegt – über die individuellen Inhalte der Frames wurde damit noch nichts ausgesagt. Hierfür ist der <FRAME>-Tag zuständig, der in seinem SRC-Attribut die URL des Dokuments enthält, das in dem entsprechenden Frame dargestellt werden soll.

Für jeden Frame muss – innerhalb der FRAMESET-Struktur – entweder ein <FRAME>-Tag verwendet werden oder ein weiterer <FRAMESET>-Tag. So können auch mehrere Framesets ineinander verschachtelt werden. In den folgenden Abschnitten wird die folgende Frame-Struktur als Vorbild verwendet:

<HTML>
<HEAD><TITLE>Frames</TITLE></HEAD>
<FRAMESET COLS="150,*">
  <FRAME NAME="A" SRC="a.html">
  <FRAMESET ROWS="100,*">
    <FRAME NAME="B" SRC="b.html">
    <FRAME NAME="C" SRC="c.html">
  </FRAMESET>
</FRAMESET>
<NOFRAMES>
<BODY>Ihr Browser kann mit Frames nichts anfangen!</BODY>
</NOFRAMES>
</HTML>
Abbildung 8.1  Die Beispielseite im Browser
Abbildung

Zur Erläuterung: Das Browser-Fenster wird zunächst vertikal in zwei Bereiche geteilt: Der linke wird mit der Datei a.html gefüllt, der rechte wird horizontal in zwei Frames geteilt, wovon der obere die Datei b.html und der untere die Datei c.html enthält. In Abbildung 8.1 sehen Sie, wie das ganze im Browser aussieht.


Galileo Computing

8.1.2 Frames mit JavaScript füllen  downtop

gp  Kleines Quiz: Wie bekommt man eine leere Seite in einen Frame? Netscape-Veteranen erinnern sich vielleicht an die Abkürzung about:blank, die seit Version 1 eine leere Seite erzeugt. Der Internet Explorer 3 mag das jedoch gar nicht und gibt eine Fehlermeldung aus (vgl. Abbildung 8.2).
Abbildung 8.2  Fehlermeldung beim Internet Explorer 3
Abbildung

Mit JavaScript ist es jedoch möglich, den Startinhalt eines Frames direkt in der Seite mit dem Frameset festzulegen. Das ist eigentlich gar nichts Neues. Sie wissen ja schon längst, wie man eine JavaScript-Funktion via URL aufrufen kann: mit dem JavaScript-Protokoll. Ganz nebenbei kann man damit auch noch andere Dinge erzeugen als eine leere Seite. Betrachten Sie folgendes Beispiel:

Abbildung 8.3  Mit JavaScript gefüllte Frames
Abbildung

<HTML>
<HEAD><TITLE>Frames</TITLE>
<SCRIPT LANGUAGE="JavaScript"><!--
function tag(s){
  return "<"+s+">"
}
function leer(){
  html = tag("HTML")+tag("BODY")+tag("/BODY")+tag("/HTML")
  return html
}
function voll(s){
  html = tag("HTML")+tag("BODY")
  html += tag("H3")+s+tag("/H3")
  html += tag("/BODY")+tag("/HTML")
  return html
}
//--></SCRIPT>
</HEAD>
<FRAMESET COLS="150,*">
   <FRAME NAME="A" SRC="javascript:top.voll('linker Frame')">
   <FRAMESET ROWS="100,*">
      <FRAME NAME="B" SRC="javascript:top.leer()">
      <FRAME NAME="C" SRC="javascript:top.voll('rechts unten')">
   </FRAMESET>
</FRAMESET>
<NOFRAMES>
<BODY>Ihr Browser kann mit Frames nichts anfangen!</BODY>
</NOFRAMES>
</HTML>

Im Browser sieht diese Seite dann so ähnlich wie in Abbildung 8.3 aus, vorausgesetzt natürlich, Ihr Browser unterstützt JavaScript! Was übrigens das top. vor dem Funktionsnamen bedeutet, erfahren Sie ein paar Abschnitte später.


Galileo Computing

8.2 Auf Daten von Frames zugreifen  downtop

Wie bereits erwähnt, werden Frames in JavaScript wie Fenster behandelt. Mit den Schlüsselworten this und self erhält man also eine Referenz auf den aktuellen Frame – oder eben das aktuelle Fenster, wenn die Seite keine Frames enthält.

Auf sich selbst zuzugreifen ist aber nicht sonderlich interessant, und erst recht nichts Neues. Viel eher ist es wichtig, wie man von einer Webseite aus auf die Unterframes zugreifen kann, und wie man – von einem Frame aus – auf das in der Hierarchie eine Stufe über einem stehende Element zugreifen kann. Um das anhand eines praktischen Beispiels einmal durchzuführen, wird das Standardbeispiel für diesen Abschnitt leicht verändert:

Das Hauptdokument, es heißt in unserem Beispiel frameset.html, hat folgenden Aufbau:

<HTML>
<HEAD><TITLE>Frames</TITLE></HEAD>
<FRAMESET COLS="150,*">
  <FRAME NAME="A" SRC="a.html">
  <FRAME NAME="B" SRC="b.html">
</FRAMESET>
<NOFRAMES>
<BODY>Ihr Browser kann mit Frames nichts anfangen!</BODY>
</NOFRAMES>
</HTML>

Die Datei b.html enthält wiederum ein Frameset:

<HTML>
<HEAD><TITLE>Noch mehr Frames</TITLE></HEAD>
<FRAMESET ROWS="100,*">
    <FRAME NAME="C" SRC="c.html">
    <FRAME NAME="D" SRC="d.html">
  </FRAMESET>
</HTML>

Abbildung 8.4 veranschaulicht noch einmal den Aufbau: Die Hauptseite enthält zwei Frames – links a.html, rechts b.html, welche sich in die zwei Frames mit Inhalt c.html (oben) und d.html (unten) aufteilt.

Abbildung 8.4  Die Beispielseite im Browser
Abbildung


Galileo Computing

8.2.1 Auf übergeordnete Frames zugreifen  downtop

Wenn Sie in HTML codieren wollen, dass sich das Ziel eines Links nicht im aktuellen Frame öffnet, sondern das gesamte Browser-Fenster für sich beansprucht, machen Sie das für gewöhnlich folgendermaßen:

<A HREF="seite.htm" TARGET="_top">Hier klicken</A>

Bei JavaScript heißt das Schlüsselwort ganz ähnlich: top. Hiermit erhalten Sie eine Referenz auf das oberste Fenster in der gesamten Frame-Hierarchie. Egal, ob Sie sich in a.html, c.html oder gar frameset.html befinden – top.location enthält immer "frameset.html" (sowie den Pfad zu dieser Datei).

Oft ist es jedoch von Nutzen, in der Hierarchie nur eine Stufe nach oben zu gelangen, also in unserem Beispiel etwa von c.html eine Referenz auf den Frame mit b.html zu erhalten. Das Schlüsselwort heißt hier parent (dt. »Elternteil«). Wenn Sie sich also in c.html befinden, enthält parent. location "b.html"; von dieser Datei aus wiederum enthält parent.location "frameset.html".

gp  Mit parent erhält man bildlich betrachtet immer eine Referenz auf das Dokument, die den <FRAMESET>-Tag enthält, der den Frame mit der aufrufenden Datei enthält. Sind in einer Datei also mehrere Framesets ineinander verschachtelt, stehen diese dennoch in der Frame-Hierarchie auf einer Ebene.

Einige Seiten, die ihre Navigation mit Frames erledigen, stellen externe Links in einem ihrer Frames dar, sodass die eigene Navigation immer noch sichtbar bleibt, die fremde Website also in einem Unterframe einer anderen Website dargestellt wird. Das ist zum einen unfreundlich und zum anderen auch schon ein paar Mal erfolgreich an- bzw. abgemahnt worden. Wenn Sie verhindern wollen, dass Ihre Seiten innerhalb eines fremden Framesets dargestellt werden, haben Sie die folgenden Möglichkeiten, die alle auf demselben Prinzip beruhen: Wenn wir uns nicht im obersten Frame in der Hierarchie befinden, dann machen wir uns zum obersten Frame in der Hierarchie!

<SCRIPT LANGUAGE="JavaScript"><!--
if (self != top) top.location = self.location
//--></SCRIPT>

oder

<SCRIPT LANGUAGE="JavaScript"><!--
if (self != parent) top.location = self.location
//--></SCRIPT>

Bauen Sie dieses Skript in all Ihre Webseiten ein, und Sie werden nie wieder von fremden Framesets belästigt werden!

Es gibt jedoch auch noch einen anderen Fall: Ein Besucher Ihrer Webseiten setzt ein Lesezeichen (Bookmark) auf eine Seite in einem Frame. Wenn er jedoch das Lesezeichen wieder aufruft, wird lediglich die eine Seite geladen, nicht jedoch die anderen Frames, die beispielsweise die gesamte Navigation enthalten.

Um das ganze ein wenig anschaulicher zu machen, folgt hier eine Konkretisierung der Aufgabenstellung. Ihre Website besteht aus zwei Frames: Der linke enthält die Navigation, der rechte den Inhalt. Ihre index.html-Datei sieht folgendermaßen aus:

<HTML>
<HEAD><TITLE>Homepage mit Frames</TITLE></HEAD>
<FRAMESET COLS="150,*">
  <FRAME SRC="navigation.html" NAME="Navi">
  <FRAME SRC="inhalt.html" NAME="Inhalt">
</FRAMESET>
<NOFRAMES>
<BODY>Ihr Browser kann mit Frames nichts anfangen!</BODY>
</NOFRAMES>
</HTML>

In allen Unterseiten sollte nun überprüft werden, ob ein Frameset existiert; wenn nicht, soll das Frameset aufgebaut werden. Dies geschieht mit ein wenig JavaScript: Die URL der aktuellen Seite wird über die Kommandozeile an eine Datei frameset.html übergeben, die die Framestruktur erzeugt.

Der folgende Code gehört in alle Unterseiten:

<SCRIPT LANGUAGE="JavaScript"><!--
if (self == top) location.href = "frameset.html?" + location.href
//--></SCRIPT>

Die Datei frameset.html wertet die Kommandozeile aus und baut – mittels document.write() – die Frame-Struktur auf. Beachten Sie, dass Sie das gesamte Frameset mit JavaScript erzeugen müssen, eine Mischung ist nicht möglich (zwar syntaktisch prinzipiell korrekt, die Browser kommen damit aber nicht zurecht).

<HTML>
<HEAD><TITLE>Homepage mit Frame</TITLE></HEAD>
<SCRIPT>
function tag(s) { document.write("<" + s + ">") }
tag('FRAMESET COLS="150,*"')
tag('FRAME SRC="navigation.html" NAME="Navi"')
seite = location.search.substring(1, location.search.length) 
   //beginnt mit "?" !
tag("FRAME SRC='" + seite + "' NAME='Inhalt'")
tag("/FRAMESET")
</SCRIPT>
</HTML>
gp  Denken Sie daran, dass location.search mit einem Fragezeichen beginnt; Sie dürfen daher die Zeichenkette erst ab dem zweiten Zeichen (hat den Index 1) auswerten.

Die mit JavaScript generierten Framesets lassen sich noch weiter verfeinern. Wenn Sie eine größere Website haben, wird sich im (fiktiven) linken Frame nicht immer dieselbe Navigation befinden. Sie können mehrere Frameset-Dateien erstellen und – je nach aufgerufener Unterseite – einen Link auf eine bestimmte dieser Frameset-Seiten setzen. Stellen Sie sich folgende Zuordnungstabelle vor (Tabelle 8.1):

Tabelle 8.1  URLs und zugehörige Frameset-Dateien
URL-Format Zugehöriger Frameset
/produkte/... frameset1.html
/investorrelations/... frameset2.html
Sonstige frameset3.html

 Der Code könnte hier folgendermaßen aussehen:

<SCRIPT LANGUAGE="JavaScript"><!--
if (self == top) {
if location.href.indexOf("/produkte")>=0
   location.href = "frameset1.htm?" + location.href
if location.href.indexOf("/investorrelations")>=0
   location.href = "frameset2.htm?" + location.href
location.href = "frameset3.htm?" + location.href
}
//--></SCRIPT>
gp  Bei einem Schreibzugriff auf location.href wird sofort die neue Seite geladen; dahinter folgender JavaScript-Code wird nicht mehr ausgeführt. Sauberer wäre es natürlich, mit else zu arbeiten.
gp  Der Netscape Navigator 4 hat einen Bug, der dazu führen könnte, dass Seiten nicht mehr korrekt ausgedruckt werden, wenn Sie mit JavaScript auf eine Frameset-Seite umleiten, wenn kein Frameset vorhanden ist. Die Ursache liegt darin, dass der Netscape-Browser vor dem Drucken das Dokument manchmal neu lädt, und zwar unabhängig von anderen Frames. Die JavaScript-Routinen werden ausgeführt, stellen keine Frames fest und wollen daher auf eine andere Seite umleiten – das führt zu Fehlern beim Druck. Sollte dieses Phänomen bei Ihnen auftreten, bieten Sie Ihren Besuchern wenigstens eine druckbare Version Ihrer Seiten an (eine Version der jeweiligen Seite ohne JavaScript).

Galileo Computing

8.2.2 Auf Daten von Unterframes zugreifen  downtop

Referenzen auf die Unterframes eines Fensters werden in dem Array frames[] (um genau zu sein, unter window.frames[] oder self.frames[] oder this.frames[]) gespeichert. Wenn Sie in der Datei frameset.html auf den linken Frame zugreifen wollen, haben Sie folgende Möglichkeiten:

gp  window.A
gp  window.frames[0]
gp  window.frames["A"]

Aber immer der Reihe nach:

gp  window.A: A ist der Wert des NAME-Attributs des entsprechenden Frames. Zwei Dinge sollten Ihnen hier deutlich werden: Geben Sie jedem Frame einen einprägsamen Namen, und verwenden Sie keine JavaScript-Begriffe (beispielsweise sollten Sie den Frame nicht "location" nennen, Sie können auf ihn dann nicht mit window.location zugreifen).
gp  window.frames[0]: Wie bereits erwähnt, werden Referenzen auf alle Frames in der jeweiligen HTML-Seite in dem Array frames[] abgespeichert. Wie bei allen JavaScript-Arrays beginnt der Index bei 0, frames[0] bezeichnet also den ersten Frame. Die Frames werden dabei nach dem Vorkommen im HTML-Dokument nummeriert. Mit frames[1] erhält man also eine Referenz auf den zweiten Frame in der Beispielseite (b.html).
gp  window.frames["A"]: Eine Mischung aus beiden Varianten. Hier kann man auch auf Frames mit speziellen Namen wie etwa "location" zugreifen. Diese Methode bedeutet jedoch recht viel Tipparbeit, und Sie werden sie sehr selten sehen. Je nachdem, wie einprägsam Ihre Frame-Namen sind, sollten Sie eine der beiden ersten Methoden verwenden.

Abbildung 8.5 verdeutlicht die Zugriffsmöglichkeiten auf andere Frames noch einmal.

Abbildung 8.5  Zugriffsmöglichkeiten auf andere Frames
Abbildung

gp  Mit diesem Wissen können Sie fremden Frames auch noch auf die folgenden Weisen entkommen. Denken Sie daran: Wenn Sie sich im obersten Frame in der Hierarchie befinden, zeigen parent und top auf das aktuelle Fenster:
<SCRIPT LANGUAGE="JavaScript"><!--
if (top.frames.length>0) top.location = self.location
//--></SCRIPT>

oder

<SCRIPT LANGUAGE="JavaScript"><!--
if (parent.frames.length>0) top.location = self.location
//--></SCRIPT>

Sie sehen hieran schon, wie man die beiden Methoden – top und parent bzw. frames[] – miteinander kombinieren kann: Will man auf einen Frame zugreifen, der sich in derselben Hierarchie-Ebene befindet, so greift man mit top oder (ggfs. mehrfacher Anwendung von) parent auf den nächsten gemeinsamen Vorfahren der beiden Frames zu und geht dann über frames[] in der Hierarchie wieder hinab. Um im Beispiel von oben von dem Frame mit der Datei c.html zu dem Frame mit der Datei d.html zu gelangen, gibt es folgende Möglichkeiten:

gp  parent.D
gp  top.B.frames[1]
gp  parent.parent.B.D

Wenn Sie Zugriff auf den Frame haben, können Sie damit auch auf alle Eigenschaften des Frames oder seiner Unterobjekte zugreifen, beispielsweise document, location, oder auch auf globale Variablen im JavaScript-Code des Frames.


Galileo Computing

8.2.3 Mehrere Frames gleichzeitig ändern  downtop

Eine der Fragen, die in Newsgroups am häufigsten gestellt werden, lautet: »Wie kann ich den Inhalt mehrerer Frames gleichzeitig ändern?« Dies ist eine Problemstellung, die tatsächlich häufig vorkommt. Denken Sie an eine der Standardanwendungen für Frames: die Navigation. Wenn Sie einen Punkt in der Navigation auswählen, wird (in einem anderen Frame) die entsprechende Inhaltsseite geladen. Jedoch kann es auch vorkommen, dass sich das Aussehen der Navigation selbst ändern soll (beispielsweise soll der gerade ausgewählte Navigationspunkt hervorgehoben werden, damit der Benutzer weiß, wo er sich befindet).

Dieser Effekt ist sehr einfach umzusetzen. Auf die oben aufgezeigte Art und Weise wird auf die entsprechenden Frames zugegriffen und die Eigenschaft location.href entsprechend verändert. Hier lohnt es sich, eine eigene Funktion zu schreiben, die Sie wieder verwenden können. Als Parameter werden Referenzen auf die Frames sowie die zu ladenden URLs übergeben:

<SCRIPT LANGUAGE="JavaScript"><!--
function ZweiFrames(frame1, url1, frame2, url2){
  frame1.location.href = url1
  frame2.location.href = url2
}
//--></SCRIPT>

Stellen Sie sich vor, im vorherigen Beispiel befinden Sie sich im Frame A und wollen via Link in Frame C die Seite cc.html sowie in Frame D die Seite dd.html laden. Sie können das folgendermaßen tun:

<A HREF="javascript:ZweiFrames(parent.B.C, 'cc.html',
  parent.B.D, 'dd.html')">hier klicken</A>

Sie sollten jedoch immer eine Alternative bereithaben, wenn der Browser des Benutzers kein JavaScript unterstützt. In diesem Fall ist das relativ einfach: Wenn Sie sich die Beispielseite noch einmal anschauen, sehen Sie, dass die Frames C und D in der Datei b.html definiert werden. Sie könnten also alternativ eine Datei bb.html erstellen, die folgendermaßen aussieht:

<HTML>
<HEAD><TITLE>Noch mehr Frames</TITLE></HEAD>
<FRAMESET ROWS="100,*">
    <FRAMESET NAME="C" SRC="cc.html">
    <FRAMESET NAME="D" SRC="dd.html">
  </FRAMESET>
</HTML>

Der Link vereinfacht sich dann zu Folgendem puren HTML:

<A HREF="bb.html" TARGET="B">hier klicken</A>

Überlegen Sie also immer, ob Sie die Aufgabenstellung auch ohne JavaScript lösen können. Sie vergrößern damit das mögliche Publikum für Ihre Webseite.


Galileo Computing

8.2.4 Gefährliche Fallen  downtop

Wenn Sie eine größere Website mit Frames aufgebaut haben und recht viel JavaScript verwenden, lohnt es sich natürlich, oft benutzte Befehle in Funktionen auszulagern und diese Funktionen auf irgendeine Seite in einem der Frames zu schreiben. Mittels top, parent und frames[] kann dann auf diese Funktion zugegriffen werden. Ein nahe liegender Ansatz ist es, die Funktionen in der obersten Seite der Hierarchie, also der Seite mit dem Haupt-Frameset abzulegen. Die Funktionen können dann mit top.funktionsname() aufgerufen werden.

gp  Dieses Vorgehen hat jedoch einen großen Haken: Manche ältere Versionen des Microsoft Internet Explorer, insbesondere die 16-Bit-Version 3.x, liefern eine Fehlermeldung, wenn Sie versuchen, auf eine JavaScript-Funktion im Hauptdokument zuzugreifen.
gp  Ein weiterer Bug tritt in alten Versionen des Netscape Navigator (um genau zu sein: Version 2) auf. Wenn Sie von einem Unterframe aus eine Variable im Hauptdokument ändern und das Dokument im Unterframe verschwindet (indem zum Beispiel ein anderes Dokument in diesen Frame geladen wird), passiert es mitunter, dass die Variable ihren Wert unkontrollierbar ändert oder ganz verschwindet.

All diese Effekte lassen sich größtenteils vermeiden, wenn alle JavaScript-Funktionen und globalen Variablen in einem Frame abgelegt werden; idealerweise in einem Frame, der sich nie ändert (beispielsweise ein Navigationsframe). Alternativ dazu können Sie auch auf einen alten HTML-Trick zurückgreifen und einen unsichtbaren Frame verwenden. Der folgende Code erzeugt zwei Frames, wovon der zweite jedoch nicht sichtbar ist, da er nur einen Pixel hoch ist. In diesem Frame lassen sich bequem Funktionen und Variablen ablegen.

<HTML>
<HEAD><TITLE>Unsichtbarer Frame</TITLE></HEAD>
<FRAMESET ROWS="*,1" BORDER=0 CELLSPACING=0 FRAMEBORDER=0>
  <FRAME NAME="sichtbar" SRC="inhalt.htm">
  <FRAME NAME="unsichtbar" SRC="skript.htm">
</FRAMESET>
<NOFRAMES>
<BODY>Ihr Browser kann mit Frames nichts anfangen!</BODY>
</NOFRAMES>
</HTML>

Galileo Computing

8.3 Ein Warenkorb in JavaScript  downtop

E-Commerce ist ein ganz heißes Thema im Web. Anhand von Diskussionen über Hype und Wahrheit in der Fachpresse kann man die Materie wie folgt zusammenfassen: Verkaufen über das Web ist ›in‹. Viele kleinere Firmen haben jedoch ein Problem damit: Sofern man dem Kunden etwas mehr bieten will als ein ordinäres Bestellformular (wobei auch darin ziemlich viel Technik stecken kann, wie Sie bereits gelesen haben), braucht man ein Warenkorbsystem. Die meisten der erhältlichen Systeme sind jedoch serverseitige Lösungen und in Sprachen wie Perl programmiert – was die meisten Hoster nur in ihren teureren Paketen unterstützen. Mit JavaScript ist es jedoch ohne größeren Aufwand möglich, sich selbst eine Warenkorblösung zu bauen. Es existieren im World Wide Web sogar kommerzielle Lösungen, die vollständig oder zum größten Teil in JavaScript programmiert worden sind.

Im Rahmen dieses Kapitels kann nur eine kleinere Lösung entwickelt werden. Für viele Ansprüche genügt diese bereits, und Erweiterungen sind – nach der Lektüre dieses Buchs – kaum Grenzen gesetzt.

Die einfache Lösung, die in den nächsten Abschnitten entwickelt wird, soll Folgendes leisten:

gp  Speicherung von Anzahl, Preis und Beschreibung der einzelnen Waren
gp  Ausgabe des Warenkorbs nebst Berechnung der Gesamtsumme
gp  Änderungen am Warenkorb

Diese drei Punkte werden nacheinander abgearbeitet.


Galileo Computing

8.3.1 Daten in den Warenkorb eintragen  downtop

Die allererste Frage, die man sich stellen sollte, lautet: »Wie speichere ich die Daten?« Es gibt hier mehrere Möglichkeiten:

gp  Für Anzahl, Preis und Beschreibung wird jeweils ein Array angelegt und bei jedem neuen Artikel, der in den Warenkorb gelegt wird, wird ein neuer Eintrag angefügt. Wie Sie schon erfahren haben, ist das Array-Objekt bei älteren Browser-Versionen nur ungenügend implementiert, weshalb diese Lösung – im Hinblick auf ein möglichst großes Publikum – leider ausscheidet.
gp  Für Anzahl, Preis und Beschreibung gibt es je eine Variable. Wenn ein weiterer Artikel in den Warenkorb gelegt wird, werden die entsprechenden Werte, durch ein Seperatorzeichen (z. B. »|«) getrennt, an die jeweiligen Variablen angehängt. Wenn Sie also zwei Artikel haben, die 10 beziehungsweise 20 Euro kosten, und Sie davon 3 beziehungsweise 4 Stück in den Warenkorb legen, hat die Anzahlvariable den Wert "3|4|", die Preisvariable "10|20|" und die Beschreibungsvariable sieht ungefähr so aus: "Beschreibung 1|Beschreibung 2|".
gp  Jeder Wert von Anzahl, Preis und Beschreibung wird in einer eigenen Variablen gespeichert. Diese Methode ist nicht sehr effizient und erfordert den häufigen Einsatz von eval().

Im Folgenden wird die zweite Methode eingesetzt. Der einzige Fallstrick hierbei: Wählen Sie ein Trennzeichen, das auf keinen Fall in der Artikelbeschreibung vorkommt, ansonsten wird es schwierig, am Ende die verschiedenen Daten wieder »auseinander zu fieseln«.

Wir beginnen wird mit dem HTML-Gerüst für die Warenkorbapplikation. Es wird ein unsichtbarer Frame verwendet, der zur Speicherung von Variablen und wichtigen Funktionen benötigt wird:

<HTML>
<HEAD><TITLE>Warenkorb</TITLE></HEAD>
<FRAMESET ROWS="*,1" BORDER=0 CELLSPACING=0 FRAMEBORDER=0>
  <FRAME NAME="inhalt" SRC="inhalt.html">
  <FRAME NAME="korb" SRC="korb.html">
</FRAMESET>
<NOFRAMES>
<BODY>Ihr Browser kann mit Frames nichts anfangen!</BODY>
</NOFRAMES>
</HTML>

Der Plan ist nun Folgender: Wir erstellen eine Funktion einfuegen() und übergeben dieser als Parameter Anzahl, Preis und Beschreibung des betreffenden Artikels. Wie die Funktion dann von einer Seite aus aufgerufen wird, kümmert uns erst später; zunächst kümmern wir uns um die Funktion. Beachten Sie, dass die Variablen für Anzahl, Preis und Beschreibung unbedingt außerhalb der Funktion definiert werden müssen – ansonsten ist die Variable nur lokal gültig, und der Wert geht nach Beendigung der Funktion verloren.

Folgender Code muss also in der Datei korb.html stehen:

<HTML>
<HEAD><TITLE>Warenkorb</TITLE>
<SCRIPT LANGUAGE="JavaScript"><!--
function istZahl(n){
  s = ""+n
  var ziffern = "0123456789"
  for (var i=0; i<s.length; i++)
    if (ziffern.indexOf(s.charAt(i))<0) return false
  return true
}

var anzahl = ""
var preis = ""
var beschreibung = ""
function einfuegen(a, p, b){
  var anz = (istZahl(a) ? a : "0")
  anzahl += anz + "|"
  preis += p + "|"
  beschreibung += b + "|"
}
//--></SCRIPT>
</HEAD>
<BODY></BODY>
</HTML>

In dem oben abgedruckten Code passiert gar nicht so viel: Die drei Variablen anzahl, preis und beschreibung werden in der Funktion einfuegen() einfach die übergebenen Parameter sowie um das Trennzeichen "|" ergänzt. Als einzige Besonderheit wird überprüft, ob die angegebene Anzahl eine natürliche Zahl ist. Das liegt daran, dass Preis und Beschreibung für jeden Artikel fest sind, die Anzahl aber von Hand eingegeben werden soll, sodass auch unsinnige Werte übergeben werden könnten.

Viel interessanter ist es jedoch, wie diese Werte an die Funktion übergeben werden. Dazu stellen Sie sich bitte Folgendes vor: Sie haben mehrere Seiten, auf denen Sie Ihre Produkte vorstellen. Auf jeder dieser Seiten sollte der Benutzer die Möglichkeit haben, den entsprechenden Titel in den Warenkorb einzufügen, und zwar in jeder beliebigen Anzahl. Es bietet sich hier ein kleines Formular an:

<HTML>
<HEAD><TITLE>Beispielartikel für den Warenkorb</TITLE></HEAD>
<BODY>
<H3>M. Proust I</H3>
Das 1. Werk des französischen Autors; 20,55 Euro
<FORM>
<INPUT TYPE="TEXT" NAME="Anzahl" SIZE=2 VALUE="1"> Stück
<INPUT TYPE="BUTTON" VALUE="In den Warenkorb" onClick="">
</FORM>
</BODY>
</HTML>
Abbildung 8.6  Die Warenkorbanwendung
Abbildung

Im Browser sieht das ungefähr so wie in Abbildung 8.6 aus. Fehlt nur noch ein Punkt: Wie muss der onClick-Parameter der Schaltfläche gesetzt werden? Die Funktion einfuegen() muss aufgerufen werden, und als Parameter werden ihr Anzahl, Preis und Beschreibung des Artikels (in dieser Reihenfolge) übergeben. Beachten Sie bitte, dass in JavaScript Dezimalstellen nicht durch ein Komma abgetrennt werden, sondern durch einen Punkt; aus diesem Grund sollte der Preis des Artikels gleich in diesem Format übergeben werden, damit später nicht erst umständlich umgewandelt werden muss. Der onClick-Parameter kann also folgendermaßen gesetzt werden:

onClick="top.korb.einfuegen(this.form.Anzahl.value, '20.55', 
'Proust I.')"

Sie können nun mehrere Seiten mit Artikeln erstellen. Wenn Sie in all diese Seiten das Formular von oben einfügen (natürlich angepasst mit den entsprechenden Preisen und Beschreibungen), haben Sie schon einen wunderbar funktionierenden Warenkorb – nur können Sie bis jetzt nur Waren hineinlegen, aber noch nicht nachschauen, was sich denn überhaupt im Warenkorb befindet.


Galileo Computing

8.3.2 Daten aus dem Warenkorb auslesen  downtop

gp  Für die Anzeige des Warenkorbs müssen die Variablen für Anzahl, Preis und Beschreibung in die Daten für die einzelnen Posten aufgespalten werden. Ab JavaScript 1.1 gibt es die bequeme Methode split() - aber der Warenkorb soll auch unter JavaScript 1.0 laufen, also muss die Methode von Hand programmiert werden.

Im folgenden Programmcode wird in dieser Reihenfolge vorgegangen:

1. Das nächste Trennzeichen (»|«) wird gesucht; alle Zeichen bis dort hin werden in einer Variablen gespeichert (diese Variable enthält dann also entweder die Anzahl, den Preis oder die Beschreibung des aktuellen Produkts).
2. Alle Zeichen bis einschließlich des ersten Trennzeichens werden abgeschnitten.
3. Die Werte, die zuvor in Variablen gespeichert worden sind, werden verwertet (zunächst werden sie lediglich ausgegeben und die Summen addiert).
4. Wenn die Variable für Anzahl, Preis bzw. Beschreibung noch Zeichen enthält, wird wieder zu Schritt 1 gesprungen.

Die Funktionsweise dieses Algorithmus soll am folgenden Beispiel kurz erklärt werden.

Ausgegangen wird von der Zeichenkette "10|20|", welche die Preise der verschiedenen Posten im Warenkorb darstellt.

1. Das erste Trennzeichen wird gesucht; die Zeichen davor ("10") in einer Variablen gespeichert.
2. Alle Zeichen bis einschließlich zum Trennzeichen werden abgeschnitten; übrig bleibt "20|".
3. Der vorher ermittelte Wert – in diesem Falle "20" – wird ausgegeben.
4. Die Variable mit den Preisen enthält noch Zeichen, nämlich "20|", es wird also wieder zu Schritt 1 zurückgesprungen. Dort wird dann "20" in einer Variablen gespeichert, alle Zeichen bis zum Trennzeichen werden abgeschnitten, wonach die Preisvariable eine leere Zeichenkette ist und das Programm abgebrochen wird.

Damit der Quellcode etwas übersichtlicher wird, wurden diejenigen Programmstücke, die nach dem nächsten Trennzeichen suchen und die Ausgangsvariablen verkürzen, in Funktionen ausgelagert.

Zuerst schreiben wir die Ausgabeseite, die den Warenkorb anzeigt:

<HTML>
<HEAD><TITLE>Ausgabe des Warenkorbs</TITLE></HEAD>
<BODY>
<H3>Inhalt des Warenkorbs</H3>
<SCRIPT LANGUAGE="JavaScript"><!--
function tag(s){ document.write("<"+s+">") }
tag("TABLE BORDER=1");
tag("TR");
tag("TD"); document.write("Anzahl"); tag("/TD")
tag("TD"); document.write("Beschreibung"); tag("/TD")
tag("TD"); document.write("Einzelpreis"); tag("/TD")
tag("TD"); document.write("Gesamtpreis"); tag("/TD")
tag("/TR")
anzahl="0"
while (anzahl!=""){
  var anzahl = top.korb.naechste_anzahl()
  var preis = top.korb.naechster_preis()
  var beschreibung = top.korb.naechste_beschreibung()
  if (anzahl!=""){
    tag("TR")
    tag("TD"); document.write(anzahl); tag("/TD")
    tag("TD"); document.write(beschreibung); tag("/TD")
    tag("TD"); document.write(preis); tag("/TD")
    tag("TD"); document.write(anzahl*preis); tag("/TD")
    tag("/TR")
  }
}
tag("/TABLE")
//--></SCRIPT>
</BODY>
</HTML>

Folgende Funktionen müssen noch in die Datei korb.html eingefügt werden:

function naechste_anzahl(){
  if (anzahl.indexOf("|")==-1) return ""
  var anz = anzahl.substring(0, anzahl.indexOf("|"))
  anzahl = anzahl.substring(anzahl.indexOf("|")+1)
  return anz
}
function naechster_preis(){
  if (preis.indexOf("|")==-1) return ""
  var pr = preis.substring(0, preis.indexOf("|"))
  preis = preis.substring(preis.indexOf("|")+1)
  return pr
}
function naechste_beschreibung(){
  if (beschreibung.indexOf("|")==-1) return ""
  var bes = beschreibung.substring(0, beschreibung.indexOf("|"))
  beschreibung = beschreibung.substring(beschreibung.indexOf("|")+1)
  return bes
}

Im Browser sieht die Seite dann wie in Abbildung 8.7 aus.

Abbildung 8.7  Die Ausgabeseite der Warenkorbanwendung
Abbildung


Galileo Computing

8.3.3 Den Warenkorb verändern  downtop

Wenn Sie schon einmal online bei Amazon oder ähnlichen Anbietern eingekauft haben, wissen Sie es sicherlich zu schätzen, bei Betrachtung des Warenkorbs die Anzahl der unterschiedlichen Posten ändern zu können und Artikel komplett zu entfernen. Diese Funktionalität soll auch in den einfachen Warenkorb eingebaut werden. Dazu soll Folgendes implementiert werden:

gp  Wird die Anzahl auf einen Wert ungleich 0 geändert, soll sie auch so im Warenkorb geändert werden.
gp  Wird die Anzahl jedoch auf den Wert 0 geändert, so wird der Posten aus dem Warenkorb entfernt.

Hierzu müssen zwei Dinge implementiert werden:

gp  Die Anzahl neben jedem Warenkorbeintrag muss in einem Texteingabefeld stehen.
gp  Eine Funktion, die am besten im unsichtbaren Frame abgelegt wird, muss die Variablen für Anzahl, Wert und Beschreibung aktualisieren.

Der erste Punkt ist relativ schnell erledigt. Damit die Texteingabefelder später leichter zu identifizieren sind, bekommen sie als Namen "anzahl" sowie die laufende Nummer des Warenkorbpostens, also "anzahl1", "anzahl2" und so weiter. Analog werden der Preis und die Beschreibung in den (unsichtbaren) Feldern "preis1", "preis2" usw. beziehungsweise "beschreibung1", "beschreibung2" usw. festgehalten. Außerdem wird in einem versteckten Formularfeld gespeichert, wie viele Posten der Warenkorb enthält. Das vereinfacht später die Aktualisierung.

Die Ausgabeseite wird folgendermaßen geändert (neuer oder aktualisierter Code ist fett dargestellt).

<HTML>
<HEAD><TITLE>Ausgabe des Warenkorbs</TITLE></HEAD>
<BODY>
<H3>Inhalt des Warenkorbs</H3>
<FORM>
<SCRIPT LANGUAGE="JavaScript"><!-- function tag(s){ document.write("<"+s+">") } tag("TABLE BORDER=1"); tag("TR"); tag("TD"); document.write("Anzahl"); tag("/TD") tag("TD"); document.write("Beschreibung"); tag("/TD") tag("TD"); document.write("Einzelpreis"); tag("/TD") tag("TD"); document.write("Gesamtpreis"); tag("/TD") tag("/TR") posten = 0
anzahl="0" while (anzahl!=""){   var anzahl = top.korb.naechste_anzahl()   var preis = top.korb.naechster_preis()   var beschreibung = top.korb.naechste_beschreibung()   if (anzahl!=""){     posten++
    tag("TR")     tag("TD");      tag("INPUT TYPE='TEXT' NAME='anzahl"+posten+"' SIZE=2 VALUE='"
      +anzahl+"'")
   tag("INPUT TYPE='HIDDEN' NAME='preis"+posten+"' VALUE='" +
     preis+"'")
   tag("INPUT TYPE='HIDDEN' NAME='beschreibung"+posten+"' VALUE='" +
     beschreibung+"'")
    tag("/TD")     tag("TD"); document.write(beschreibung); tag("/TD")     tag("TD"); document.write(preis); tag("/TD")     tag("TD"); document.write(anzahl*preis); tag("/TD")     tag("/TR")   } } tag("/TABLE") tag("INPUT TYPE='HIDDEN' NAME='posten' VALUE=" + posten)
//--></SCRIPT> <INPUT TYPE="BUTTON" onClick="top.korb.update(this.form)" VALUE=
  "Aktualisieren">
</FORM>
</BODY> </HTML>
Abbildung 8.8  Der Inhalt des Warenkorbs kann jetzt auch geändert werden.
Abbildung

Beachten Sie, dass an die Funktion update() – die noch erstellt werden muss – eine Referenz auf das aktuelle Formular übergeben wird; das vereinfacht den Zugriff auf die Formularwerte.

Die Funktion, die den Warenkorb aktualisiert, muss nacheinander Folgendes erledigen:

gp  Einlesen aller Warenkorbposten
gp  Sofern die Anzahl eine natürliche Zahl und damit größer als 0 ist, wird der Posten verarbeitet, ansonsten wird er übergangen.
gp  Aktualisierung der durch "|" getrennten Zeichenketten für Anzahl, Preise und Beschreibungen
gp  Neudarstellung des Warenkorbs

Die Hauptschwierigkeit ist wohl der erste Punkt, das Einlesen aller Warenkorbposten. Hat man jedoch einmal das Verfahren verstanden, geht der Rest wie von selbst. Die Anzahl der Posten wird aus dem Formular eingelesen; dann werden innerhalb einer Schleife die Felder "anzahl1" bis ("anzahl"+posten) ausgelesen. Wenn f das Warenkorb-Formular bezeichnet, würde man so alle Mengen einlesen:

for (var i=1; i<=1*f.posten.value; i++){
  a = eval("f.anzahl"+i+".value")
  // Code für die Verarbeitung hier einfügen...
}
gp  Beachten Sie, dass die Anzahl der Posten, die als Formularwert eine Zeichenkette ist, zur Sicherheit durch eine Multiplikation mit 1 in eine natürliche Zahl umgewandelt wird. Alternativ kann auch parseInt() verwendet werden.
gp  Die Aktualisierung der Zeichenketten für Anzahl, Preise und Beschreibungen erfolgt nach dem Muster von oben; die Funktion einfuegen() kann wieder verwendet werden. Fehlt nur noch die Neuanzeige des Warenkorbs. Leider kann location.reload() nicht verwendet werden – diesen Befehl gibt es erst seit der JavaScript-Version 1.1 – aber ein einfaches location.href=location.href reicht prinzipiell völlig aus (ein history.go(0) würde es auch tun). Denken Sie hierbei daran, dass die Funktion update() selbst im Frame mit den JavaScript-Versionen steht. Obwohl sie vom Frame mit dem Warenkorb ausgeführt wird, liefert ein Aufruf von location.href die URL des unsichtbaren Frames zurück, nicht die des aufrufenden Frames!
function update(f){
  //Warenkorb zurücksetzen
  anzahl=""; preis=""; beschreibung=""
  for (var i=1; i<=1*f.posten.value; i++){
    a = eval("f.anzahl"+i+".value")
    p = eval("f.preis"+i+".value")
    b = eval("f.beschreibung"+i+".value")
    einfuegen(a, p, b)
  }
  parent.inhalt.location.href = parent.inhalt.location.href
}

Galileo Computing

8.4 Diashow  downtop

Als letzte Anwendung dieses Kapitels soll eine Diashow entwickelt werden. Ihre Firma hat eine Firmenpräsentation erstellt. Diese soll nun auch in die Website integriert werden. Da die Präsentation mit einem mittelmäßigen Präsentationsprogramm erstellt worden ist, liegen Ihnen lediglich zehn HTML-Seiten vor, die aber nicht miteinander verlinkt sind. Ziel soll es nun sein, diese zehn HTML-Seiten nacheinander anzuzeigen; alle zehn Sekunden soll die nächste Seite geladen werden. Um dem Besucher der Webseiten wenigstens ein bisschen Interaktivität vorzugaukeln, soll er die Animation anhalten, aber auch eine Seite vor- oder zurückspringen können. Das ist Ihr Pech und mein Glück, denn ohne diese Zusatzbedingung könnte man diese Aufgabe auch mit normalen (HTML-)Mitteln lösen.


Galileo Computing

8.4.1 Vorbereitungen  downtop

Beginnen wir mit der Grundstruktur der Präsentation: Das folgende Frameset teilt das Browser-Fenster in die Präsentationsfläche (oben) und den Navigationsbereich (unten) auf:

<HTML>
<HEAD>
<TITLE>Firmenpräsentation</TITLE>
</HEAD>
<FRAMESET ROWS="*,80">
   <FRAME SRC="tour.html" NAME="Tour">
   <FRAME SRC="nav.html" NAME="Nav">
</FRAMESET>
<NOFRAMES>
<BODY>Ihr Browser kann mit Frames nichts anfangen!</BODY>
</NOFRAMES>
</HTML>
Abbildung 8.9  Die Startseite der Diashow
Abbildung

In der Abbildung sehen Sie, wie die Navigationsleiste ungefähr aussehen soll. Als Optionen soll es Start, Stop, Vor, Zurück und Verlassen geben. Wir werden JavaScript-Funkionen mit denselben Namen schreiben. Dazu brauchen wir noch eine Funktion, die die nächste Seite der Animation in den oberen Frame lädt. Außerdem benötigen wir noch globale Variablen. Unter anderem muss jederzeit bekannt sein, welche Seite der Diashow gerade angezeigt wird und ob die Animation gerade läuft oder pausiert.

Neben einigen weiteren Angaben (wie viele Seiten? welche Verzögerung zwischen den Seiten?) benötigen wir noch eine weitere Variable. Da mit setTimeout() gearbeitet werden muss, sollte die zurückgegebene ID in einer Variablen abgespeichert werden.

Im Folgenden sehen Sie das Grundgerüst für die Datei nav.html; in den folgenden Abschnitten werden die Funktionen mit Inhalt gefüllt.

<HTML>
<HEAD>
<SCRIPT LANGUAGE="JavaScript"><!--
//globale Variablen
var seiten = 10 //Anzahl der Seiten tourX.htm
var stat = "stop" //Status der Animation:
                  //"stop" oder "start"
var akt = 1 //aktuell angezeigte Seite tourX.htm
var ID = 0 //ID des letzten Timeouts
var delay = 10000 //Verzögerung in Millisekunden

//Funktionen
function start(){
   //Funktion zum Starten/Fortfahren der Diashow
}
function stop(){
   //Funktion zum Anhalten/Pausieren der Diashow
}
function vor(){
   //Funktion zum Vorspringen in der Animation
}
function zurueck(){
   //Funktion zum Zurückspringen in der Animation
}
function verlassen(){
   //Funktion zum Verlassen der Animation
}
//--></SCRIPT>
</HEAD>
<BODY onLoad="start()">
<FORM onSubmit="return false">
<CENTER>
<TABLE BORDER=0 CELLPADDING=10><TR>
<TD><A HREF="javascript:start()">Start</A></TD>
<TD><A HREF="javascript:stop()">Stop</A></TD>
<TD><A HREF="javascript:zurueck()">Zurück</A></TD>
<TD><A HREF="javascript:vor()">Vor</A></TD>
<TD><A HREF="javascript:verlassen()">Verlassen</A></TD>
</TR></TABLE>
</CENTER>
</BODY>
</HTML>

Galileo Computing

8.4.2 Diashow starten  downtop

Wenn der Benutzer auf Start klickt, muss zuerst überprüft werden, ob die Diashow nicht etwa schon läuft (über die Statusvariable stat). Falls doch, muss keine Aktion erfolgen; andernfalls muss der Status geändert und die neue Seite nach Ablauf von zehn Sekunden geladen werden. Das Laden der weiteren Seiten geschieht dann in der Funktion lade(), die sich – mittels Timeout – immer wieder selbst aufruft. Ein besonderer Fall liegt noch vor, wenn die letzte Seite der Diashow angezeigt wird: Dann darf auch keine Aktion erfolgen.

function start(){
   if (stat=="stop"&&akt<seiten){
      stat = "start"
      ID = setTimeout("lade(akt+1)", delay)
   }
}
function lade(nummer){
   parent.Tour.location.href="tour"+nummer+".html"
   akt = nummer
   if (stat=="start"&&akt<seiten)
      ID = setTimeout("lade(akt+1)", delay)
   else if (akt == seiten)
      stat = "stop"
}

Galileo Computing

8.4.3 Diashow anhalten  downtop

Auch das Anhalten der Diashow gestaltet sich nicht weiter schwierig: Die Statusvariable muss angepasst werden, und das Laden der nächsten Seite muss mit clearTimeout() unterbunden werden:

function stop(){
   stat = "stop"
   clearTimeout(ID)
}

Galileo Computing

8.4.4 Vorwärts und rückwärts springen  downtop

Der Wechsel zur vorherigen oder zur nächsten Seite der Diashow ist relativ ähnlich. Zuerst wird überprüft, ob man sich auf der ersten bzw. letzten Seite befindet (dann geschieht nichts); dann wird clearTimeout() und danach lade() aufgerufen. Beachten Sie, dass die vorherige oder nächste Seite sofort aufgerufen werden soll, also wird setTimeout() nicht verwendet.

function vor(){
   if (akt<seiten){
      clearTimeout(ID)
      lade(akt+1)
   }
}
function zurueck(){
if (akt>0){
      clearTimeout(ID)
      lade(akt-1)
   }
}

Galileo Computing

8.4.5 Diashow verlassen  downtop

Der letzte Punkt auf der Aufgabenliste, das Verlassen der Diashow, verdient eigentlich keine eigene Überschrift. Es wird einfach eine andere Seite geladen; als sauberer Programmierer löschen Sie außerdem noch alle Timeouts.

function verlassen(){
   clearTimeout(ID)
   top.location.href="andereseite.html"
}

Beachten Sie, dass in obigem Code die neue URL auf der obersten Ebene der Framehierarchie aufgerufen wird; Sie rufen ja das JavaScript-Kommando in einem Unterframe auf!


Galileo Computing

8.5 Fragen & Aufgaben  toptop

1. Betrachten Sie folgendes HTML-Dokument:
<HTML>
<FRAMESET ROWS="100,200,*">
   <FRAMESET COLS="200,*,100">
      <FRAME SRC="a.html">
      <FRAME SRC="b.html">
      <FRAMESET ROWS="50,50">
         <FRAME SRC="c.html">
         <FRAME SRC="d.html">
      </FRAMESET>
   </FRAMESET>
   <FRAMESET COLS="200,200">
      <FRAMESET ROWS="50%,50%">
         <FRAME SRC="e.html">
         <FRAME SRC="f.html">
      </FRAMESET>
      <FRAMESET ROWS="33%,67%">
         <FRAME SRC="g.html">
         <FRAME SRC="h.html">
      </FRAMESET>
   </FRAMESET>
   <FRAME SRC="i.html">
</FRAMESET>
</HTML>
Gehen Sie davon aus, dass auf dem Webserver für jeden <FRAMESET>-Tag eine entsprechende Datei liegt, die das Frameset enthält (die obige Auflistung ist also nur eine Zusammenfassung). Die Hauptseite wird im Webbrowser aufgerufen, mitunter auch in einem Unterframe. Ihre Aufgabe soll es nun sein, von einem Unterframe auf einen anderen zuzugreifen. Wie lautet der entsprechende JavaScript-Code?
    gp  Vom Frame mit c.html auf den Frame mit h.html und umgekehrt
    gp  Vom Frame mit a.html auf i.html
2. Schreiben Sie eine Funktion subframes(frameref), die die Anzahl der Unterframes des Frames mit der Referenz frameref ermittelt. Als Unterframes zählen hierbei jedoch nur Frames, die ein Dokument ohne weiteres Frameset enthalten.
3. Wenn die Diashow nach drei Sekunden angehalten und dann wieder gestartet wird, sollte die nächste Seite eigentlich nach sieben Sekunden angezeigt werden. Sie erscheint aber erst nach zehn Sekunden. Korrigieren Sie das Skript dementsprechend. (Tipp: Sie benötigen eine weitere Timeout-ID und eine Funktion, die die Sekunden herunterzählt.)
  

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