32.2 Mit unsichtbaren Frames arbeiten  
Unsichtbare Frames haben den Vorteil, dass ein Teil der Website nie geändert wird. Sie können also in dem Frame Variablen speichern, und der Benutzer bekommt es (fast) nicht mit.
Schlecht sieht es jedoch aus, wenn die Frame-Struktur verlassen wird – beispielsweise, wenn der Benutzer einen Link in einem neuen Fenster öffnet. Sie sollten dann auf jeden Fall eine Warnmeldung ausgeben:
if (self == top) {
alert("Bitte keine Frames im neuen Fenster öffnen!");
window.close();
}
Zwar erscheint beim Schließen des Fensters eine Warnmeldung, aber hier ist nur wichtig, dass der Benutzer im Hauptfenster bleibt.
In der vorgestellten Lösung verwenden wir drei Frames:
|
Einer der Frames ist der Hauptframe. Dies ist der Platz für die eigentlichen Inhalte: die Artikel, die Kategorien und den Warenkorb. |
|
Der zweite Frame gibt aus, wie viele Artikel sich im Warenkorb befinden und wie viel sie zusammen kosten. Zusätzlich wird ein Link angeboten, über den direkt auf den Warenkorb zugegriffen werden kann. Damit wird dann die Bestellung generiert. |
|
Der dritte Frame ist nicht sichtbar und enthält den gesamten JavaScript-Code. Dort wird auch der Inhalt des Warenkorbs abgespeichert. |
Der HTML-Code dafür sieht folgendermaßen aus:
<html>
<head>
<title>Online-Shop</title>
</head>
<frameset rows="*, 50, 1" border="0" frameborder="0">
<frame src="kategorien_frames.html" name="Inhalt" />
<frame src="uebersicht_frames.html" name="Uebersicht" />
<frame src="code_frames.html" name="Code" scrolling="no" />
</frameset>
</body>
</html>
Die Datei code_frames.html ist am schnellsten erstellt:
<html>
<head>
<script type="text/javascript" src="warenkorb.js"></script>
<script type="text/javascript" src="artikel.js"></script>
</head>
<body onload="if (top.frames['Inhalt']) top.frames['Inhalt'].location.reload();">
</body>
</html>
Sie sehen also: Es ist gar nicht viel los. Das ist aber auch verständlich, da die Hauptarbeit in den zwei eingegliederten JavaScript-Dateien erledigt wird:
|
warenkorb.js enthält die Hilfsfunktionen für unseren JavaScript-Shop. |
|
artikel.js enthält nach dem oben skizzierten Muster alle Artikel, nach Kategorien unterteilt. |
Die einzige Besonderheit besteht darin, dass nach dem vollständigen Laden des Dokuments (inklusive aller Artikel) der Inhaltsframe neu geladen wird. In der Regel ist es nämlich so, dass der Inhaltsframe weniger lange zum Laden braucht als der Codeframe und dass deswegen erst nach dem Laden des Codeframes auf die Variablen im Codeframe zugegriffen werden darf.
Die Datei warenkorb.js werden wir im Laufe dieses Abschnitts schrittweise erweitern, so dass Ihnen am Ende eine funktionsfähige Applikation zur Verfügung steht.
32.2.1 Warenkorb füllen  
Um den Warenkorb zu füllen, schreiben wir eine Funktion, die zwei Parameter erwartet:
|
die Bestellnummer des Artikels, der hinzugefügt werden soll |
|
die Angabe, wie viel Stück des betreffenden Artikels in den Warenkorb gelegt werden sollen |
Wie Sie in der Funktion warenkorb_artikel() gesehen haben, wird die Anzahl der Artikel in der Eigenschaft anzahl gespeichert. Sie müssen also nur auf diese Eigenschaft zugreifen.
function warenkorb_hinzufuegen_frames(nr, stueck) {
if (top.frames["Code"]) {
c = top.frames["Code"];
for (var i=0; i<c.kategorie.length; i++) {
for (var j=0; j<c.kategorie[i].artikel.length; j++) {
if (c.kategorie[i].artikel[j].nr == nr) {
c.kategorie[i].artikel[j].anzahl += stueck;
}
}
}
}
}
Zunächst wird überprüft, ob top.frames["Code"] existiert (aufgrund von Browserunterschieden müssen Sie so umständlich auf die Variablen zugreifen, die im selben Frame definiert worden sind). Dann wird derjenige Artikel gesucht, der die gewünschte Bestellnummer hat.
Um also ein Exemplar der dritten JavaScript-Auflage in den Warenkorb zu legen, muss die Funktion folgendermaßen aufgerufen werden:
warenkorb_hinzufuegen_frames("3–89842–132–5", 1);
Alternativ dazu wird noch eine Funktion angeboten, die die Anzahl für einen Artikel im Warenkorb auf eine bestimmte Stückzahl setzt, sie also nicht stupide erhöht. Somit ist es später auch möglich, Artikel aus dem Warenkorb zu entfernen.
function warenkorb_editieren_frames(nr, stueck) {
if (top.frames["Code"]) {
c = top.frames["Code"];
for (var i=0; i<c.kategorie.length; i++) {
for (var j=0; j<c.kategorie[i].artikel.length; j++) {
if (c.kategorie[i].artikel[j].nr == nr) {
c.kategorie[i].artikel[j].anzahl = stueck;
}
}
}
}
}
Der Unterschied zwischen den beiden Funktionen besteht also tatsächlich nur im Zuweisungsoperator: warenkorb_hinzufuegen_frames() verwendet +=, warenkorb_editieren_frames() verwendet dagegen =.
32.2.2 Artikel anzeigen  
Die Artikel sind in Kategorien unterteilt. Sie benötigen also drei verschiedene Seiten:
|
eine Seite, auf der alle Kategorien angezeigt werden: kategorien_frames.html |
|
eine Seite, auf der alle Artikel innerhalb einer Kategorie angezeigt werden: artikel_gesamt_frames.html |
|
eine Seite, auf der ein Artikel en detail angezeigt wird: artikel_einzeln_frames.html |
Beginnen wir zunächst mit der Datei kategorien_frames.html. In dieser Datei wird das Array artikel aus dem Frame namens Code durchlaufen, und es werden die Namen aller Kategorien angezeigt. Diese stehen in der Eigenschaft name der jeweiligen Kategorie.
Die Namen der Kategorien sollen gleichzeitig Links auf die Übersichtsseite sein. Dazu muss die Seite artikel_gesamt_frames.html aufgerufen werden. Als Parameter wird der Name der Kategorie übergeben, also beispielsweise artikel_gesamt_frames.html?Galileo%20Computing.
Sie sehen hierbei, dass der Name der Kategorie in ein URL-fähiges Format umgewandelt worden ist. Dazu steht unter JavaScript die Funktion escape() zur Verfügung. Die Rückverwandlung kann mit unescape() erreicht werden.
In Abbildung 32.1 sehen Sie die folgende HTML-Seite, die alle Kategorien ausgibt:
Die Datei artikel_gesamt_frames.html zeigt dann alle Artikel innerhalb der angegebenen Kategorie an (siehe Abbildung 32.2). Der Code ist hier sehr ähnlich:
|
Zunächst wird die entsprechende Kategorie gesucht. |
|
In einer Schleife werden alle Artikel innerhalb dieser Kategorie ausgelesen und ausgegeben. |
|
Jeder Artikel wird verlinkt, und zwar mit der Datei artikel_einzeln_ frames.html. Als Parameter wird die Bestellnummer des gewählten Artikels angehängt, beispielsweise artikel_einzeln_frames.html? 3-89842-132-5. |
 Hier klicken, um das Bild zu Vergrößern
Abbildung 32.1 Die Kategorienübersicht
Hier sehen Sie die Datei artikel_gesamt_frames.html:
<html>
<head>
<title>Online-Shop</title>
</head>
<body>
<h1>Willkommen im Online-Buch-Shop</h1>
<p>Bitte wählen Sie einen Artikel!
<ul>
<script type="text/javascript"><!--
if (top.frames["Code"] && location.search.length > 1) {
var name = location.search.substring(1,
location.search.length);
name = unescape(name);
c = top.frames["Code"];
for (var i=0; i<c.kategorie.length; i++) {
if (c.kategorie[i].name == name) {
for (var j=0; j<c.kategorie[i].artikel.length; j++) {
var a = c.kategorie[i].artikel[j];
document.write("<li\>");
document.write("<a href=\
"artikel_einzeln_frames.html?");
document.write(escape(a.nr));
document.write("\"\>");
document.write(a.name);
document.write("</a\></li\>");
}
}
}
}
//--></script>
</ul>
</p>
<p><a href="kategorien_frames.html">Zurück zur
Übersicht</a></p>
</body>
</html>
 Hier klicken, um das Bild zu Vergrößern
Abbildung 32.2 Alle Artikel in einer Kategorie
Nun fehlt nur noch die Datei artikel_einzeln_frames.html. In dieser muss der einzelne Artikel mit allen Informationen (z. B. Name, Kurzbeschreibung und ausführliche Beschreibung sowie Grafik) ausgegeben werden.
Bevor Sie sich aber an der Programmierung nach obigem Muster versuchen, sollten Sie sich in Erinnerung rufen, was auf der Seite noch geschehen soll. In der Artikel-Einzelansicht soll dem Benutzer die Möglichkeit geboten werden, den Artikel auch in den Warenkorb zu legen. Sie benötigen dazu die folgenden Elemente:
|
ein Texteingabefeld für die Stückzahl, die von dem Artikel in den Warenkorb gelegt werden soll |
|
eine Schaltfläche, die auf Knopfdruck dann warenkorb_hinzu-fuegen_frames() mit den richtigen Parametern aufruft |
In reinem HTML sieht das ungefähr folgendermaßen aus:
<input type="text" name="anzahl3–89842–132–5" size="2"
value="1" /> Wenz: JavaScript
<input type="button" value="In den Warenkorb"
onclick="javascript:hinzu(this.form, "3–89842–132–5")" />
<br />
Beachten Sie Folgendes:
|
Das name-Attribut des Feldes für die Stückzahl setzt sich aus dem Wort "anzahl" und der Bestellnummer des gewünschten Artikels zusammen. |
|
Die JavaScript-Schaltfläche ruft eine (noch zu schreibende Funktion) hinzu() auf. Als Parameter werden eine Referenz auf das aktuelle Formular sowie die Bestellnummer übergeben. |
Die Funktion hinzu() muss dann
|
die Anzahl aus dem Formular auslesen, |
|
die Funktion warenkorb_hinzufuegen_frames() aufrufen, |
|
eine entsprechende Meldung ausgeben und |
|
den Übersichtsframe neu laden. |
function hinzu(f, nr) {
if (top.frames["Code"]) {
var c = top.frames["Code"];
if (f.elements["anzahl" + nr]) {
var anzahl = f.elements["anzahl" + nr].value;
anzahl = parseInt(anzahl); //Umwandlung in Int
if (isNaN(anzahl)) {
anzahl = 0;
}
c.warenkorb_hinzufuegen_frames(nr, anzahl);
alert("Artikel hinzugefügt!");
if (top.frames["Uebersicht"]) {
top.frames["Uebersicht"].location.reload();
}
}
}
}
Solange nur ein Artikel angezeigt wird, kann die Funktion hinzu() etwas kürzer gestaltet werden. Da wir aber an späterer Stelle Codeteile daraus wiederverwenden möchten, ist sie hier ein wenig allgemeiner gehalten.
In der Datei artikel_einzeln_frames.html muss dann nur noch das Formular mit den Artikeldaten entsprechend ausgegeben werden.
Der Name der Kategorie wird nicht an die Seite mit übergeben, er kann auch anhand der Bestellnummer mit ein wenig zusätzlichem Code ermittelt werden:
function kategoriename(nr) {
if (top.frames["Code"]) {
c = top.frames["Code"];
for (var i=0; i<c.kategorie.length; i++) {
for (var j=0; j<c.kategorie[i].artikel.length; j++) {
if (c.kategorie[i].artikel[j].nr == nr) {
return c.kategorie[i].name;
}
}
}
}
return "";
}
Es folgt nun die komplette Datei artikel_einzeln_frames.html (siehe auch Abbildung 32.3):
<html>
<head>
<title>Online-Shop</title>
</head>
<body>
<h1>Willkommen im Online-Buch-Shop</h1>
<p> Bitte geben Sie die Stückzahl an!
<script type="text/javascript"><!--
function kategoriename(nr) {
if (top.frames["Code"]) {
c = top.frames["Code"];
for (var i=0; i<c.kategorie.length; i++) {
for (var j=0; j<c.kategorie[i].artikel.length; j++) {
if (c.kategorie[i].artikel[j].nr == nr) {
return c.kategorie[i].name;
}
}
}
}
return "";
}
function hinzu(f, nr) {
if (top.frames["Code"]) {
var c = top.frames["Code"];
if (f.elements["anzahl" + nr]) {
var anzahl = f.elements["anzahl" + nr].value;
anzahl = parseInt(anzahl); //Umwandlung in Int
if (isNaN(anzahl)) {
anzahl = 0;
}
c.warenkorb_hinzufuegen_frames(nr, anzahl);
alert("Artikel hinzugefügt!");
if (top.frames["Uebersicht"]) {
top.frames.location["Uebersicht"].reload();
}
}
}
}
document.write("<ul\>");
if (top.frames["Code"] && location.search.length > 1) {
var nr = location.search.substring(1,
location.search.length);
nr = unescape(nr);
var name = kategoriename(nr);
c = top.frames["Code"];
for (var i=0; i<c.kategorie.length; i++) {
if (c.kategorie[i].name == name) {
for (var j=0; j<c.kategorie[i].artikel.length; j++) {
if (c.kategorie[i].artikel[j].nr == nr) {
var a = c.kategorie[i].artikel[j];
document.write("<h2\>" + a.name + "</h2\>");
document.write("<b\>" + a.kurz + "</b\>");
document.write("<img src=\"" + a.grafik + "\" /\
>");
document.write("<br /\>" + a.lang + "<br /\>");
document.write("<form\>");
document.write("<input type=\"text\" ");
document.write("name=\"anzahl" + nr + "\" ");
document.write("size=\"2\" value=\"1\" /\> ");
document.write(name + " ");
document.write(a.preis + "€ "); // Preis in _
document.write("<input type=\"button\" value=\"In
den Warenkorb\" ");
document.write("onclick=\
"javascript:hinzu(this.form, '"
+ nr + "')\" /\><br /\>");
document.write("</form\>");
}
}
}
}
document.write("</ul\><a href=\"artikel_gesamt_frames.html?");
document.write(escape(name));
document.write("\"\>");
document.write("Zurück zu Kategorie " + name +"</a\>");
} else {
document.write("</ul\>");
}
//--></script>
</ul>
</p>
</body>
</html>
 Hier klicken, um das Bild zu Vergrößern
Abbildung 32.3 Detailansicht samt Bestellmöglichkeit
Einen Punkt haben wir jedoch noch unterschlagen: den Übersichtsframe. Dieser enthält wie versprochen die folgenden Elemente:
|
die Anzahl der (verschiedenen) Artikel im Warenkorb |
|
einen Link zur Bestellseite |
|
(als besonderes Extra) den aktuellen Gesamtwert des Warenkorbs |
Auf dieser Seite müssen in mehreren verschachtelten Schleifen alle Variablen aus der Datei artikel.js durchlaufen werden, also das gesamte Artikelsortiment. Die einzelnen gewünschten Werte werden wie folgt ermittelt:
|
Wenn die Eigenschaft anzahl eines Artikels größer als 0 ist, wird die Anzahl der Artikel um eins erhöht und die gesamte Artikelstückzahl um den Wert in anzahl. |
|
Die Eigenschaft anzahl wird mit dem Preis (Eigenschaft preis) multipliziert, um die aktuelle Gesamtsumme zu ermitteln. |
<html>
<head>
<title>Online-Shop</title>
</head>
<body>
<script type="text/javascript"><!--
if (top.frames["Code"] && top.frames["Code"].kategorie) {
c = top.frames["Code"];
var anzahl = 0;
var stueck = 0;
var summe = 0;
for (var i=0; i<c.kategorie.length; i++) {
for (var j=0; j<c.kategorie[i].artikel.length; j++) {
var a = c.kategorie[i].artikel[j];
if (a.anzahl>0) {
anzahl ++;
stueck += a.anzahl;
}
summe += a.anzahl * a.preis;
}
}
document.write(anzahl + " Artikel, ");
document.write(stueck + " Stück, ");
document.write(summe + " € ");
}
//--></script>
<a href="warenkorb_frames.html" target="Inhalt">Bestellung
aufgeben</a>
</body>
</html>
 Hier klicken, um das Bild zu Vergrößern
Abbildung 32.4 Die Übersicht zeigt die Stückzahl und den Wert des Warenkorbs an.
32.2.3 Warenkorb ändern  
Kommen wir nun zum letzten Schritt – zur Änderung und Versendung des Warenkorbs. Diese Seite ist relativ komplex, weil sie eine Reihe von Funktionen erfüllen muss.
Wir werden an dieser Stelle die Funktionen einzeln vorstellen und die zugehörigen Codefragmente zeigen. Am Ende dieses Abschnitts finden Sie das komplette Listing.
|
Es muss eine Schaltfläche zum Verschicken der Bestellung angeboten werden. |
Dazu können Sie eine einfache Versenden-Schaltfläche (<input type="submit" />) verwenden. Die Formulardaten werden dann an dasjenige Skript verschickt, das im action-Attribut des Formulars angegeben worden ist.In vielen Quellen finden Sie den »heißen Tipp«, die Daten ohne den Einsatz von serverseitigen Mitteln direkt per E-Mail zu verschicken:
<form method="post" enctype="text/plain"
action="mailto:ihre.adresse@xy.de">
Dieser Code führt beim Formularversand zu einer Warnmeldung an den Benutzer – wenn der Browser das Ganze überhaupt unterstützt. Insbesondere der Internet Explorer hat mit diesem Code oft seine Probleme. Setzen Sie lieber auf serverseitige Lösungen. Wenn Ihnen diese nicht zur Verfügung stehen, verwenden Sie einen Dienst wie etwa http://www.formmailer.com/.
|
Alle Artikel im Warenkorb müssen ausgegeben werden. Dazu verwenden Sie eine Schleife, die so ähnlich wie die Schleife aus der Datei uebersicht_frames.html aussieht: |
c = top.frames["Code"];
for (var i=0; i<c.kategorie.length; i++) {
for (var j=0; j<c.kategorie[i].artikel.length; j++) {
var a = c.kategorie[i].artikel[j];
if (a.anzahl>0) {
document.write("<p\>");
document.write("<i\>" + a.nr + "</i\> ");
document.write("<b\>" + a.name + "</b\> ");
document.write((a.anzahl * a.preis) + " € ");
document.write("</p\>");
}
}
}
|
Die Anzahl der einzelnen Elemente im Warenkorb muss änderbar sein. |
Dazu muss es zunächst neben jedem Element im Warenkorb noch zusätzlich ein Textfeld geben, das die aktuelle Anzahl enthält:
document.write("<input type=\"text\" ");
document.write("name=\"anzahl" + a.nr + "\" ");
document.write("size=\"2\" ");
document.write("value=\"" + a.anzahl + "\" /\> ");
Eine Schaltfläche startet dann den Update-Prozess:
<input type="button" onclick="update(this.form)"
value="Aktualisieren" />
In der Funktion update() werden dann in einer Schleife alle Formularelemente durchsucht, die Textfelder sind. Das name-Attribut besteht aus "anzahl" und der Bestellnummer, das value-Attribut gibt die gewünschte Anzahl an. Diese Werte können Sie dann als Parameter an warenkorb_editieren_frames() übergeben:
function update(f) {
if (parent.frames["Code"]) {
var c = parent.frames["Code"];
for (var i=0; i<f.elements.length; i++) {
if (f.elements[i].type == "text" &&
f.elements[i].name.substring(0, 6) == "anzahl") {
var nr = f.elements[i].name.substring(6,
f.elements[i].name.length);
var anzahl = f.elements[i].value;
anzahl = parseInt(anzahl);
if (isNaN(anzahl)) {
anzahl = 0;
}
c.warenkorb_editieren_frames(nr, anzahl);
}
}
}
if (parent.frames["Uebersicht"]) {
parent.frames["Uebersicht"].location.reload();
}
location.reload();
}
Beachten Sie, dass das aktuelle Dokument am Ende der Funktion neu geladen wird. Dann werden die Änderungen, die zuvor ja nur im Variablensatz vorgenommen worden sind, auch auf der Website sichtbar.
|
Die Summe der einzelnen Artikel wird am Ende der Seite ausgegeben. Dazu müssen Sie bei der Ausgabe der einzelnen Artikel lediglich in einer Variable mitzählen, welchen Betrag Sie bereits erreicht haben. |
Nachfolgend sehen Sie das komplette Skript. Dabei wurde die Ausgabe noch leicht kosmetisch aufbereitet, unter anderem durch die Verwendung einer Tabelle (siehe Abbildung 32.5):
<html>
<head>
<title>Online-Shop</title>
</head>
<body>
<h1>Warenkorb</h1>
<form method="post" action="skript.php">
<script type="text/javascript"><!--
function update(f) {
if (parent.frames["Code"]) {
var c = parent.frames["Code"]; {
for (var i=0; i<f.elements.length; i++)
if (f.elements[i].type == "text" &&
f.elements[i].name.substring(0, 6) == "anzahl") {
var nr = f.elements[i].name.substring(6,
f.elements[i].name.length);
var anzahl = f.elements[i].value;
anzahl = parseInt(anzahl);
if (isNaN(anzahl)) {
anzahl = 0;
}
c.warenkorb_editieren_frames(nr, anzahl);
}
}
}
if (parent.frames["Uebersicht"]) {
parent.frames["Uebersicht"].location.reload();
}
location.reload();
}
document.write("<table border=\"1\" cellpadding=\"2\"\>");
var summe = 0;
if (top.frames["Code"]) {
var c = top.frames["Code"];
for (var i=0; i<c.kategorie.length; i++) {
for (var j=0; j<c.kategorie[i].artikel.length; j++) {
var a = c.kategorie[i].artikel[j];
if (a.anzahl>0) {
document.write("<tr\><td\>");
document.write("<input type=\"text\" ");
document.write("name=\"anzahl" + a.nr + "\" ");
document.write("size=\"2\" ");
document.write("value=\"" +a.anzahl+ "\" /\> ");
document.write("</td\><td\>");
document.write("<i\>" + a.nr + "</i\> ");
document.write("</td\><td\>");
document.write("<b\>" + a.name + "</b\> ");
document.write("</td\><td\>");
document.write((a.anzahl * a.preis) + " € ");
document.write("</tr\>");
summe += a.anzahl * a.preis;
}
}
}
}
document.write("</table\>");
//--></script>
<br>
<input type="button" onclick="update(this.form)"
value="Aktualisieren" />
<input type="submit" value="Bestellung aufgeben" />
</form>
<a href="kategorien_frames.html">Zurück zur
Übersicht</a>
</body>
</html>
 Hier klicken, um das Bild zu Vergrößern
Abbildung 32.5 Letzte Änderungsmöglichkeit vor der Bestellung
Ihnen steht nun ein funktionierender Warenkorb zur Verfügung. Als Erweiterung sollen Sie nun noch beispielsweise Eingabefelder für die Adress- und Rechnungsdaten Ihrer Kunden einfügen.
|