Workshop JavaScript . 3827317185, 9783827317186 [PDF]


133 36 2MB

German Pages 374 Year 2000

Report DMCA / Copyright

DOWNLOAD PDF FILE

Table of contents :
Workshop JavaScript......Page 3
Event-Handling......Page 5
Stichwortverzeichnis......Page 6
Vorwort......Page 9
Die Icons im JavaScript-Workshop......Page 11
Grundlagen......Page 13
3. Übung......Page 19
Lösung zu 3......Page 20
Lösung zu 7......Page 21
Variablen......Page 23
Zeichenketten......Page 24
Programmsteuerung......Page 25
Funktionen......Page 27
Arrays......Page 30
4. Übung......Page 31
Tipp zu 4......Page 32
Lösung zu 2......Page 33
Lösung zu 4......Page 34
Lösung zu 5......Page 36
Lösung zu 6......Page 37
Die Sprache in ihrer Umgebung......Page 39
Denken in Objekten......Page 40
window......Page 42
Form-Objekt......Page 44
Image-Objekt......Page 46
Eigenschaften definieren......Page 48
Event-Handler......Page 49
Nur was der Browser kennt, kann man verwenden......Page 50
Welcher Browser bietet was?......Page 51
navigator......Page 52
3. Übung......Page 55
Tipps zu 4......Page 56
Lösung zu 3......Page 57
Lösung zu 4......Page 58
Eigene Objekte definieren......Page 59
Eigenschaften und Methoden hinzufügen......Page 62
Übungen......Page 64
2. Übung......Page 65
6. Zusatz-Übungen (ohne Lösungen)......Page 66
Tipps zu 4......Page 67
Lösung zu 3......Page 68
Lösung zu 4......Page 71
Lösung zu 5......Page 74
Grundlagen......Page 77
Objekttyp »Form«......Page 78
Eigenschaft elements......Page 79
Methode submit......Page 80
Formularelemente und Objekttypen......Page 81
Eigenschaften der Objekttypen......Page 82
Event-Handler der Objekttypen......Page 83
Eigenschaft name......Page 84
Methode focus......Page 85
Event-Handler onClick......Page 86
Objekttypen Hidden, Password, Text, Textarea......Page 87
Event-Handler onChange......Page 88
Eigenschaft checked......Page 89
Eigenschaft options......Page 90
Objekttyp Option......Page 91
Konstruktor......Page 92
Objekttyp Submit......Page 93
5. Übung......Page 94
12. Übung......Page 95
Tipps zu 7......Page 96
Tipps zu 12......Page 97
Lösungsansatz A......Page 98
Lösungsansatz B......Page 99
Lösungsansatz C......Page 100
Lösungsansatz A – onSubmit bei dem HTML-Start-Tag ......Page 101
Lösung zu 3......Page 102
Lösung zu 4......Page 103
Lösung zu 5......Page 104
Lösung zu 8......Page 105
Lösung zu 9......Page 106
Löschen eines Eintrags aus einer Auswahlliste......Page 107
Wert eines Eintrags ändern......Page 108
Lösung zu 12......Page 109
Grundlagen......Page 111
Event-Handler......Page 112
Event-Handler......Page 113
Event-Handler und typische HTML-Elemente......Page 114
Event-Handler onLoad......Page 115
Event-Handler onUnload......Page 116
Eigenschaften eines Images......Page 117
5. Übung......Page 118
Lösung zu 1......Page 119
Lösung zu 2......Page 120
Lösung zu 3......Page 122
Lösung zu 5......Page 123
Lösungsansatz A......Page 124
Lösungsansatz B......Page 125
Eigenschaften des window-Objektes......Page 127
Event-Handler......Page 128
Eigene Fenster verwenden......Page 129
Beziehungen zwischen Fenstern und Frames......Page 132
Inhalte dynamisch generieren......Page 134
Informationen weitergeben......Page 137
window.name verwenden......Page 138
Größe und Position......Page 140
Fenster verschieben, Fenstergröße ändern......Page 141
Fenstergröße erfahren......Page 142
1. Übung......Page 144
6. Übung......Page 145
Tipp zur 7. Übung......Page 146
Lösung zu 3......Page 147
Lösung zu 5......Page 149
Lösung zu 6......Page 151
Lösung zu 7......Page 157
Cookies lesen und schreiben......Page 159
Zeiten in JavaScript: Das Date-Objekt......Page 161
Alternativen zu Cookies......Page 162
5. Übung......Page 163
Tipp zu 3......Page 164
Grundlagen......Page 171
Tipps zu 8......Page 165
Lösung zu 3......Page 166
Lösung zu 5......Page 167
Lösung zu 7......Page 168
Lösung zu 8......Page 169
Style Sheets definieren......Page 172
CSS-Angaben......Page 173
CSS-Positionierung und Block-Effekte......Page 174
DHTML mit dem Netscape Navigator 4......Page 176
Layer in HTML......Page 177
Layer in JavaScript......Page 178
Layer-Eigenschaften......Page 179
Layer-Eigenschaften ändern......Page 180
Die document.all-Collection......Page 181
Element-Inhalte ändern......Page 182
Dokumente aus der Sicht des DOM......Page 184
Node-Eigenschaften......Page 186
Lesen und schreiben im DOM-Baum......Page 187
3. Übung......Page 189
8. Übung......Page 190
11. Übung......Page 191
19. Übung......Page 194
22. Übung......Page 195
27. Übung......Page 196
30. Übung......Page 197
Tipps zu 14......Page 198
Tipps zu 22......Page 199
Tipps zu 28......Page 200
Tipps zu 29......Page 201
Lösung zu 1......Page 202
Lösung zu 6......Page 203
Lösung zu 9......Page 204
Lösung zu 11......Page 205
Lösung zu 12......Page 207
Lösung zu 13......Page 209
Lösung zu 14......Page 210
Lösung zu 17......Page 211
Lösung zu 19......Page 212
Lösung zu 20......Page 213
Lösung zu 21......Page 214
Lösung zu 22......Page 215
Lösung zu 23......Page 216
Lösung zu 25......Page 217
Lösung zu 27......Page 218
Lösung zu 28......Page 219
Lösung zu 29......Page 220
Lösung zu 30......Page 221
Vorüberlegungen zur Zielgruppe......Page 223
Browser-Check......Page 224
Strategie 1: Verschiedene Seiten für verschiedene Browser......Page 225
Strategie 2: Verschiedene Anweisungen für verschiedene Browser......Page 226
Strategie 3: Cross-Browser-Funktionen......Page 227
Strategie 4: Cross-Browser-Objekte......Page 228
Noch ein paar Grundregeln......Page 229
6. Übung......Page 230
10. Übung......Page 231
14. Übung......Page 232
15. Übung......Page 233
17. Übung......Page 234
20. Übung......Page 235
22. Übung......Page 236
24. Übung......Page 237
Tipps zu 5......Page 238
Tipps zu 9......Page 239
Tipps zu 13......Page 240
Tipps zu 20......Page 241
Tipps zu 21......Page 244
Lösung zu 2......Page 246
Lösung zu 5......Page 247
Lösung zu 6......Page 249
Lösung zu 8......Page 250
Lösung zu 9......Page 251
Lösung zu 11......Page 252
Lösung zu 13......Page 253
Lösung zu 15......Page 255
Lösung zu 17......Page 256
Lösung zu 18......Page 257
Lösung zu 19......Page 258
Lösung zu 20......Page 260
Lösung zu 21......Page 262
Lösung zu 22......Page 263
Lösung zu 23......Page 264
Lösung zu 24......Page 266
Anhang 1: Eine Checkliste für Netscape 4......Page 268
Anhang 2: Kleine Cross-Browser-Referenz......Page 269
Event-Handler registrieren......Page 271
Blubbern und Sickern......Page 272
Das event-Objekt......Page 275
Event-Steuerung und Rückgabewerte......Page 276
Tastatur-Ereignisse......Page 277
Cross-Browser Event-Handling......Page 279
Übungen......Page 280
5. Übung......Page 281
8. Übung......Page 282
12. Übung......Page 283
13. Übung......Page 284
15. Übung......Page 285
17. Übung......Page 286
Was ist ein Java-Applet?......Page 313
Tipps zu 9......Page 287
Tipps zu 12......Page 288
Tipps zu 13......Page 289
Lösung zu 2......Page 290
Lösung zu 5......Page 291
Lösung zu 6......Page 292
Lösung zu 7......Page 295
Lösung zu 8......Page 296
Lösung zu 9......Page 297
Lösung zu 10......Page 299
Lösung zu 11......Page 300
Lösung zu 12......Page 301
Lösung zu 13......Page 303
Lösung zu 14......Page 309
Lösung zu 15......Page 310
Lösung zu 16......Page 311
Lösung zu 17......Page 312
Einbettung von Applets in HTML-Seiten......Page 315
Lebenszyklus eines Java-Applets......Page 316
JavaScript steuert Applet......Page 318
Applet kommuniziert mit Browser......Page 319
Applet steuert JavaScript......Page 321
Was ist ein Plug-in?......Page 326
Einbettung von Plug-ins mit dem Internet Explorer......Page 327
Einbettung von Plug-ins mit dem Netscape Navigator......Page 328
Kombination von embed und object......Page 330
JavaScript kommuniziert mit Plug-in......Page 331
Netscape Navigator: JavaScript-Funktion als Event-Handler......Page 332
Internet Explorer: VBScript-Funktion als Event-Handler......Page 333
Blick hinter die Kulissen......Page 334
Erkennung von Plug-ins......Page 336
Plattformunabhängigkeit......Page 339
Restriktionen......Page 340
Java-Klassen mit JavaScript erzeugen......Page 341
Ausblick......Page 344
2. Übung......Page 345
7. Übung......Page 346
10. Übung......Page 347
13. Übung......Page 348
Tipp zu 6......Page 349
Tipp zu 14......Page 350
Lösung zu 1......Page 351
Lösung zu 3......Page 352
Lösung zu 4......Page 353
Lösung zu 5......Page 354
Lösung zu 6......Page 355
Lösung zu 7......Page 356
Lösung zu 9......Page 357
Lösung zu 11......Page 359
Lösung zu 13......Page 360
Lösung zu 15......Page 361
Lösung zu 16......Page 363
Bibliographie......Page 365
C......Page 367
E......Page 368
I......Page 369
L......Page 370
P......Page 371
S......Page 372
W......Page 373
Z......Page 374
Papiere empfehlen

Workshop JavaScript .
 3827317185, 9783827317186 [PDF]

  • 0 0 0
  • Gefällt Ihnen dieses papier und der download? Sie können Ihre eigene PDF-Datei in wenigen Minuten kostenlos online veröffentlichen! Anmelden
Datei wird geladen, bitte warten...
Zitiervorschau

Workshop JavaScript

Stefan Mintert und Christine Kühnel (Hrsg.)

Workshop JavaScript

Bitte beachten Sie: Der originalen Printversion liegt eine CD-ROM bei. In der vorliegenden elektronischen Version ist die Lieferung einer CD-ROM nicht enthalten. Alle Hinweise und alle Verweise auf die CD-ROM sind ungültig.

An imprint of Pearson Education München • Boston • San Francisco • Harlow, England Don Mills, Ontario • Sydney • Mexico City Madrid • Amsterdam

Die Deutsche Bibliothek – CIP-Einheitsaufnahme Ein Titeldatensatz für diese Publikation ist bei Der Deutschen Bibliothek erhältlich. Die Informationen in diesem Produkt werden ohne Rücksicht auf einen eventuellen Patentschutz veröffentlicht. Warennamen werden ohne Gewährleistung der freien Verwendbarkeit benutzt. Bei der Zusammenstellung von Texten und Abbildungen wurde mit größter Sorgfalt vorgegangen. Trotzdem können Fehler nicht vollständig ausgeschlossen werden. Verlag, Herausgeber und Autoren können für fehlerhafte Angaben und deren Folgen weder eine juristische Verantwortung noch irgendeine Haftung übernehmen. Für Verbesserungsvorschläge und Hinweise auf Fehler sind Verlag und Herausgeber dankbar. Alle Rechte vorbehalten, auch die der fotomechanischen Wiedergabe und der Speicherung in elektronischen Medien. Die gewerbliche Nutzung der in diesem Produkt gezeigten Modelle und Arbeiten ist nicht zulässig. Fast alle Hardware- und Softwarebezeichnungen, die in diesem Buch erwähnt werden, sind gleichzeitig auch eingetragene Warenzeichen oder sollten als solche betrachtet werden. Umwelthinweis: Dieses Produkt wurde auf chlorfrei gebleichtem Papier gedruckt. Die Einschrumpffolie – zum Schutz vor Verschmutzung – ist aus umweltverträglichem und recyclingfähigem PE-Material.

10 9 8 7 6 5 4 3 2 03 02 01 ISBN 3-8273-1718-5

© 2000 by Addison-Wesley Verlag, ein Imprint der Pearson Education Deutschland GmbH, Martin-Kollar-Straße 10–12, D-81829 München/Germany Alle Rechte vorbehalten Einbandgestaltung: Rita Fuhrmann, Frankfurt/Oder Lektorat: Sylvia Hasselbach, [email protected], Herstellung: TYPisch Müller, Arcevia, Italien Satz: reemers publishing services gmbh, Krefeld Druck: Bosch, Ergolding Printed in Germany

Inhaltsverzeichnis Vorwort. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

9

1 JavaScript und HTML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

13

1.1 1.2 1.3 1.4

Herkunft von JavaScript. . . . . . . . . . . . . . . . . . . . . . . . . . . . Grundlagen. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Übungen. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Lösungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

13 13 19 20

2 Die Sprache . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

23

2.1 2.2 2.3 2.4

Grundlagen. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Übungen. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Tipps. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Lösungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

23 31 32 33

3 Das Objektmodell . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

39

3.1 3.2 3.3 3.4

Grundlagen. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Übungen. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Tipps. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Lösungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

39 55 56 57

4 Eigene Objekte . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

59

4.1 4.2 4.3 4.4

Grundlagen. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Übungen. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Tipps. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Lösungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

59 64 67 68

5 Formulare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

77

5.1 5.2 5.3 5.4

Grundlagen. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Übungen. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Tipps. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Lösungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

77 94 96 98

6 Event-Handling. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111 6.1 6.2 6.3 6.4

Grundlagen. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Übungen. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Tipps. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Lösungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

111 118 119 120

5

Inhaltsverzeichnis

7 Fenster und Frames . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127 7.1 7.2 7.3 7.4

Grundlagen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Übungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Tipps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Lösungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

127 144 146 147

8 Cookies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159 8.1 8.2 8.3 8.4

Grundlagen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Übungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Tipps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Lösungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

159 163 164 166

9 Drei Einführungen in DHTML . . . . . . . . . . . . . . . . . . . . . . . . . . 171 9.1 9.2 9.3 9.4

Grundlagen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Übungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Tipps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Lösungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

171 189 198 202

10 DHTML: Cross-Browser-Strategien . . . . . . . . . . . . . . . . . . . . . . 223 10.1 10.2 10.3 10.4 10.5 10.6

Grundlagen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Übungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Tipps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Lösungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Anhang 1: Eine Checkliste für Netscape 4 . . . . . . . . . . . . . . Anhang 2: Kleine Cross-Browser-Referenz . . . . . . . . . . . . .

223 230 238 246 268 269

11 Erweitertes Event-Handling . . . . . . . . . . . . . . . . . . . . . . . . . . . 271 11.1 11.2 11.3 11.4

Grundlagen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Übungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Tipps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Lösungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

271 280 287 290

12 LiveConnect . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 313 12.1 12.2 12.3 12.4

Grundlagen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Übungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Tipps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Lösungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

313 345 349 351

13 Bibliographie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 365 Stichwortverzeichnis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 367

6

Für Brendan Eich, ohne den es diese Sprache nicht gäbe, und für das Web Standards Project, auf dass diese Sprache irgendwann problemloser zu benutzen ist.

Vorwort JavaScript, eine ehemals einfache Skriptsprache zur Einbettung in HTML-Seiten, ist das Thema dieses Buches. Als sie Ende 1995 im Navigator 2 erschienen ist, waren die Dinge tatsächlich noch einfach. In der Zwischenzeit hat JavaScript eine stürmische, ungeordnete, chaotische, kreative Entwicklung durchlaufen. Die Fähigkeiten, die die Sprache oder die mit ihr unmittelbar verbundenen Techniken heute bieten, übersteigen bei weitem das, was 1995 zunächst unter dem Namen LiveScript abzusehen war. Der Preis für diese Entwicklung und den heutigen Zustand ist hoch. Er ist bestimmt aus zum Teil undurchschaubaren Imkompatibilitäten zwischen den Browsern und einem komplexen Zusammenspiel von mehreren beteiligten Komponenten und Aspekten (Programmiersprache, Objektmodell, Auszeichnungssprache, StyleSheets, Applets, Plug-ins u.a.m.). Wie geht man diese Schwierigkeiten an? Die Antwort lautet: mit viel praktischem Know-how. Aus diesem Grund ist das Buch, das Sie in den Händen halten, nicht von einem einzelnen Autor geschrieben worden. Beide Herausgeber haben eine weit zurückreichende JavaScript-Erfahrung, Christine Kühnel bereits seit 1996, Stefan Mintert schon seit den Anfängen 1995. Dennoch wollten wir das Buch nicht alleine schreiben. Als die Idee für den JavaScript-Workshop entstand, gab es folgende Vorgaben des Verlags: kompakt, praxisrelevant, übungsbasiert sollte es sein, ganz im Sinne der gesamten Buchreihe. Dass die Eigenschaften kompetent und fachlich fundiert dazu gehören, versteht sich von selbst; andernfalls lohnt sich der Aufwand nicht, ein solches Projekt anzugehen. Was lag also näher, als Autoren zusammenzubringen, die den JavaScript-Workshop mit Leben füllen könnten? Wir betreuen bereits seit 1997 die FAQ zur deutschsprachigen JavaScriptNewsgruppe. Gemeinsam haben wir Autoren gefunden, die zum Beispiel in ihren Beiträgen in der Newsgruppe immer wieder bewiesen haben, dass sie die nötige fachliche Kompetenz mitbringen, einen Beitrag für unser Buch zu schreiben. Wir haben ein Grobkonzept für den Aufbau des Buches vorgegeben. Die Gliederung der Kapitel in Grundlagen, Übungen, Tipps und Lösungen ist eine Eigenschaft der Workshop-Reihe. Die inhaltliche Ausgestaltung der Kapitel haben wir in die Hände der einzelnen Autoren gelegt. Sie, die Leserin bzw. der Leser, finden im vorliegenden Buch daher eine Sammlung von Beiträgen, von deren fachlicher Qualität wir überzeugt sind. Mit dem Ziel, die Unabhängigkeit der Kapitel zu bewahren, haben wir andererseits versucht, durch die Zusammenstellung und die Reihenfolge einen Aufbau des Buches zu erreichen, der das sequentielle Durchlesen oder besser das Durcharbeiten von Anfang bis Ende erlaubt. Die Komplexität des Themas in Verbindung mit einem natürlich begrenzten Umfang verhindert leider eine vollständige Behandlung aller Aspekte und Ein-

9

Vorwort satzmöglichkeiten von JavaScript. Auch in diesem Punkt greifen wir auf die Erfahrung unserer Autoren zurück. Sie gewährleistet, dass der Leser die Auswahl an praxisrelevantem Wissen vorfindet, die er für den täglichen Einsatz als Web-Autor benötigt, und nicht mit den weniger wichtigen Fakten belästigt wird. Die angestrebte Kompaktheit des Buches setzt voraus, dass Sie sich mit benachbarten Techniken (wie HTML und ggf. Java) bereits auskennen. Mit den im Buch enthaltenen Übungen wollen wir Sie in die Lage versetzen, das Erlernte unmittelbar anzuwenden. Inwieweit uns das Erreichen all dieser Ziele gelungen ist, bleibt Ihrer Beurteilung überlassen. Über Kritik jedweder Art freuen wir uns selbstverständlich. Wie Sie die Autoren der Kapitel erreichen können, steht jeweils zu Beginn eines jeden Kapitels. Bitte beachten Sie jedoch, dass wir nicht ohne Weiteres JavaScript-Support leisten können. Die Erfahrungen mit der JavaScript-FAQ und anderen JavaScript-Veröffentlichungen haben gezeigt, dass das Mailaufkommen, das uns erreicht, nicht in vernünftiger Zeit zu bearbeiten ist. Aus diesem Grund bitten wir Sie, allgemeine Fragen zu JavaScript, die nichts mit diesem Buch zu tun haben, in der Newsgruppe zu stellen: de.comp.lang.javascript. Weitere aktuelle Informationen, auch dazu, wie Sie uns erreichen können, finden Sie im Web unter http://www.javascript-workshop.de/. Bitte sehen Sie zuerst dort nach, bevor Sie uns kontaktieren. Wir haben an dieser Stelle die Möglichkeit, stets unsere aktuellen Adressen u.Ä. anzubieten. Abschließend bleibt uns eine Verpflichtung, der wir gerne nachkommen, nämlich der Dank an Thomas Fischer, Michael Praast und Stefano Picco, die zwar leider nicht als Autoren dabei waren, uns aber unterstützt haben. Und selbstverständlich freuen wir uns, Ihnen nachfolgend die Autoren unseres Buches sowie uns selbst vorstellen zu können.

Stefan Mintert, Dortmund Christine Kühnel, Hengersberg Juli 2000

10

Die Autoren des JavaScript-Workshops

Christine Kühnel hat vor einigen Jahren das Netz für sich entdeckt, zuvor viele Jahre lang programmiert. Was lag also näher, als beides zu kombinieren und sich mit dynamischen Webseiten zu befassen? Die Idee, Antworten auf in der Newsgruppe oft gestellte JavaScript-Fragen in einer praxisorientierten FAQ im Web anzubieten, stammt von ihr. Stefan Mintert arbeitet mit JavaScript seit der Entstehung 1995. Neben einigen Artikeln erschien im Jahre 1996 sein erstes Buch, das erste nicht-englischsprachige JavaScript-Buch. Die Einrichtung der deutschsprachigen Newsgruppe zu diesem Thema geht auf seine Initiative zurück. Heute arbeitet er als selbständiger Berater im Bereich Internet, World Wide Web und Publishing mit dem Schwerpunkt XML sowie als Autor und Referent. Dietmar Rabich fand den Weg zum Internet und damit zu HTML und JavaScript vor einigen Jahren und folgt diesem Hobby seither. Die eigene Homepage spiegelt diese Themen wider. Schon vorher beschäftigte sich der Mathematiker beruflich wie privat lange Zeit – angefangen mit einem Wang 2200 (Kennt den noch jemand?) – mit Themen rund um die Datenverarbeitung: Programmierung, Datenbanken usw. So entstand von ihm als Coautor neben einigen Fachartikeln im Jahre 1987 das spätere Atari-Profibuch ST-STE-TT. Wolfgang Schwarz entwickelte im Frühsommer 1998 die Theorie der seinsschwangeren Selbstspiegelataraxie, die er, um unnötigen Rummel zu vermeiden, in einer kleinen Höhle in den Apenninen vergrub, wo er sich dem Senfanbau widmet und versucht, alte Zahlen auswendig zu lernen. Tobias Trelle hat an der Ruhr-Universität Bochum Mathematik studiert und war am dortigen Rechenzentrum vier Jahre lang als wissenschaftliche Hilfskraft beschäftigt. Seit 1995 ist er Teilhaber der CyCo Systems GmbH & Co. KG (http://www.cycosys.com/), einer Bochumer Firma, die auf 3D/Virtual RealitySysteme im Internet spezialisiert ist. Dort ist er als Anwendungsentwickler tätig. Die Icons im JavaScript-Workshop Folgende Icons werden Ihnen bei der Arbeit mit dem JavaScript-Workshop begegnen: Achtung: Dieses Icon warnt Sie vor Hürden, die JavaScript oder die BrowserHersteller aufgestellt haben. Beispiel: Als praxisorientiertes Buch besitzt der Workshop natürlich eine Vielzahl an Beispielen. Hinweis: Die Hinweise zeigen Ihnen, welchen Dingen Sie besondere Beachtung schenken sollten. Tipp: Unter den Tipps finden Sie wichtige Informationen für die Praxis.

11

Vorwort Die CD zum Buch Die CD, die Sie in diesem Buch finden, enthält die größeren, lauffähigen Beispiele sowie die lauffähigen Musterlösungen zu den Übungsaufgaben. Darüber hinaus haben wir jedem Autor einen persönlichen Bereich überlassen, in dem er eigenes Material unterbringen kann. Darin sind viele interessante JavaScript-Beispiele zu finden, die Sie sich unbedingt ansehen sollten. Außerdem finden Sie auf der CD als kleines Extra noch einen JavaScript-Test. Da dieser Test automatisch ausgewertet wird, versteht es sich von selbst, dass die Fragen nicht mit dem Anspruch unseres Buches mithalten können. Sollten Sie ernsthaft bemüht sein, JavaScript zu erlernen, empfehlen wir das Durcharbeiten des Buches inklusive der darin enthaltenen Übungen. Gelegentlich werden Sie auch noch einen Blick in die online verfügbare JavaScript-Dokumentationen werfen müssen; den Link finden Sie auf unserer Buchseite. Während der Arbeit mag der Test als kleine Motivation dienen, damit Sie sich dann umso interessierter auf die herausfordernden Übungen im Buch stürzen.

12

1

JavaScript und HTML Von Stefan Mintert, [email protected]

1.1

Herkunft von JavaScript

Im Jahre 1995 hat die Firma Netscape begonnen, für ihren Web-Browser Navigator eine Programmiersprache zu entwickeln, die den bis dahin unveränderlichen Web-Seiten Leben einhauchen sollte. Auf die Frage, weshalb denn eine neue Sprache entwickelt werden sollte und weshalb nicht etwa Perl verwendet werden könne, antwortete der maßgebliche Entwickler Brendan Eich in einer Newsgruppe: »Ich mag Perl sehr. Ich hatte aus Marketing-Gründen nicht die Möglichkeit, sie in den Navigator einzubetten, als ich JavaScript erschuf. Die Netscape-HTML-Skriptsprache sollte oberflächlich Java-ähnlich sein [...]. Mein erster Gedanke war übrigens, Scheme einzubauen, aber das wurde ebenfalls aus Marketing-Gründen abgelehnt sowie aus unbewiesenen, aber intuitiven Ängsten hinsichtlich der einfachen Handhabbarkeit, die auch für Perl gelten.« Ebenso wie die Entscheidung für die Sprache selbst mehr vom Marketingstandpunkt aus getroffen wurde, so wurde auch der Name gewählt. Ursprünglich war der Name LiveScript, was in die Linie mehrerer »Live«-Produkte von Netscape passte (LiveWire, LivePayment, LiveConnect usw.). Der Erfolg von Java und ein entsprechendes Abkommen mit der Firma Sun sorgte dann für den endgültigen Namen JavaScript. Ein wirklicher Bezug zu Java ist damit nicht gegeben, von gewissen syntaktischen Ähnlichkeiten abgesehen.

JavaScript ist nicht Java »light«

Der erste Web-Browser, der JavaScript-Programme ausführen konnte, war der Navigator 2. Ab der Version 3 hat auch Microsoft mit dem Internet Explorer die Sprache unterstützt, allerdings aus rechtlichen Gründen unter dem Namen JScript. Eine dritte Bezeichnung kam dann 1996 ins Spiel, als Netscape zusammen mit dem europäischen Konsortium ECMA eine standardisierte Form schaffen wollte. Das Ergebnis dieser Arbeit heißt heute ECMAScript. Mittlerweile ist die Sprache unter dem einen oder anderen Namen weit verbreitet. Neben den Web-Seiten können z.B. auch PDF-Dokumente JavaScript (bzw. ECMAScript) enthalten. Eine ausführliche Auflistung der wichtigen Stationen der Entwicklung ist im Netz unter der Adresse http://www.mintert.com/javascript/ zu finden.

JScript ECMAScript

1.2

Grundlagen

In diesem Buch geht es um JavaScript als Programmiersprache für das WebPublishing. Viele Anwendungsmöglichkeiten und Einsatzgebiete lassen wir außen vor, um uns auf die Verwendung der Sprache zusammen mit HTML zu

13

1 JavaScript und HTML konzentrieren. HTML betrachten wir hier als die Dokumentensprache für das World Wide Web; dass es verschiedene Versionen und Dialekte gibt, spielt hier keine Rolle. Ebensowenig die zukünftigen Möglichkeiten, die sich durch XML ergeben1. Als zu Grunde liegende HTML-Version verwenden wir hier XHTML 1.0, also eine Version, die funktionsgleich zu HTML 4 ist. Da es aber in diesem Buch nicht um HTML geht, werden wir im folgenden keine exakte Unterscheidung der Versionen machen und in den Beispielen einen pragmatischen Ansatz wählen. Im Einzelfall kann das bedeuten, dass wir vielleicht nicht ganz standardkonform sind, einfach deshalb, weil sich die Web-Browser nicht an Standards halten. Unsere Beispiele laufen dafür auch in der Praxis, nicht nur in der Theorie2. Für weitere Informationen zu HTML verweisen wir zum Beispiel auf [RAGG98] und natürlich auf http://www.w3.org/MarkUp/. Genug der Vorrede, kommen wir zur Sache. JavaScript-Programme werden in HTML-Dokumente eingebettet. Dazu muss es natürlich irgendein Element geben, damit der Text in einer Seite von dem Programm unterschieden werden kann. Das zuständige Element in HTML trägt den Namen script. Im einfachsten Fall sieht es so aus:

Das Element darf (fast) überall in einer Webseite enthalten sein, wobei es für viele Zwecke sinnvoll ist, script im Element head unterzubringen. Außerdem sagt der Name des Elements noch gar nichts darüber aus, um welche Programmiersprache es sich bei dem Inhalt handelt. Zwar geht es hier nur um JavaScript, es könnte aber auch eine andere Sprache sein. Der Internet Explorer kann beispielsweise auch VBScript ausführen3. Wir müssen dem Browser also noch einen Hinweis geben, welche Art von Inhalt er in script vorfindet. Dazu gibt es zwei Attribute, language und type. Das erste wurde von Netscape eingeführt, das zweite ist eine Vorgabe des HTML-Standards, die in der Praxis noch nicht relevant ist, die man aber schon jetzt einhalten kann. Damit ergibt sich als Muster für eine HTML-Datei mit einem JavaScript-Programm die folgende Darstellung:

... der Titel des Dokuments ...

1. Dies gilt umso mehr, als dass momentan (Mitte 2000) und auf absehbare Zeit XML-Dokumente im Browser (auch) in HTML gewandelt werden. Eine Kombination von XML mit einer Scriptingsprache wie JavaScript ist noch nicht implementiert. 2. Von Tipp- und weiteren Fehlern abgesehen. 3. Beim Navigator kann an Stelle von »JavaScript« auch heute noch »LiveScript« stehen. Von der Verwendung ist jedoch abzuraten.

14

Grundlagen

... hier steht die HTML-Seite ...

Diese Position von script – im Kopf der Seite – bietet sich an, um dort Funktionen, Variablen und weitere Datenstrukturen zu definieren, die zu einem späteren Zeitpunkt verwendet werden. Beispiele dafür werden die nachfolgenden Kapitel liefern. Eine wichtige Aufgabe von JavaScript-Programmen besteht darin, auf Ereignisse zu reagieren. Ereignisse können zum Beispiel Aktionen des Benutzers sein, wie etwa das Anklicken eines Buttons oder das Ändern eines Formularfeldes. Um darauf reagieren zu können, wurden mit JavaScript besondere Attribute für einige HTML-Elemente definiert, die so genannten Event-Handler. Auch in diesen Attributen können JavaScript-Anweisungen stehen, die bei Eintreten des Ereignisses ausgeführt werden. In Kapitel 6 erfahren Sie mehr darüber. An dieser Stelle nur ein kleines Beispiel:

Ereignisse

Noch einmal zusammengefasst: JavaScript-Anweisungen dürfen in HTML 왘 im Element

und

왘 in besonderen Attributen, den Event-Handlern, stehen.

Mit diesen wenigen Informationen haben wir nun schon genug zusammen, um endlich einmal ein erstes lauffähiges Beispiel zu zeigen. Zwar haben wir noch nicht alles erklärt, was in Listing 1.1 zu sehen ist. Aber zusammen mit der Abbildung ist zu erkennen, dass das Programm nach dem Laden ein kleines Fenster öffnet und den Leser begrüßt.

JavaScript-Hello-World

Das erste JavaScript-Beispiel

Listing 1.1: Ein Hello-World-Beispiel in JavaScript (beispiel0101.html)

15

1 JavaScript und HTML Abbildung 1.1: Das Hello-WorldBeispiel nach dem Laden der Seite

JavaScriptBibliotheken

Möglicherweise möchten Sie die oben definierte Funktion begruessung() auch in anderen Webseiten verwenden. In so einem Fall bietet es sich an, die Funktion(en) nicht in die Seite einzubetten, sondern sie in einer externen Datei zu speichern und diese Datei einzuladen. Genauso, wie Bilder auch nicht in der HTML-Datei stehen, kann man auch JavaScript-Programme extern speichern. Angenommen, eine solche Datei (mit unserer begruessung()-Funktion) trägt den Namen kernfunktionen.js, die im gleichen Verzeichnis wie die HTMLDatei steht, dann lässt sich obiges Beispiel folgendermaßen umschreiben:

JavaScript-Hello-World

Das erste JavaScript-Beispiel

Listing 1.2: Das Hello-World-Beispiel mit externer JavaScript-Datei

Auf eine Abbildung können wir hier verzichten, da sich das gleiche Ergebnis einstellt wie bei dem Listing zuvor.

16

Grundlagen Sie wissen sicherlich schon, dass nicht alle Browser JavaScript beherrschen. Es stellt sich daher die Frage, was machen diese Browser mit unserem JavaScriptProgramm? Mit etwas Glück lautet die Antwort: Ignorieren! Wenn der WebBrowser neueren Datums ist, wird er das Element script kennen und den Inhalt einfach übergehen. Eventuell kommt das Programm aber auf die Idee, den Inhalt anzuzeigen. Dann würde der Leser unserer Web-Seite also die JavaScript-Anweisungen zu sehen bekommen. Das ist zweifellos nicht das, was wir wollen. Um das zu verhindern, muss der Inhalt von script in HTML-Kommentare eingebettet werden:

In dieser Form ist nun alles zwischen

Das erste JavaScript-Beispiel

Ich hätte Sie gerne mit JavaScript begrüßt, aber Ihr Browser kann JavaScript-Programme nicht ausführen. :-(

Listing 1.3: Das Hello-World-Beispiel mit alternativem Text für JavaScript-unfähige Browser (beispiel0103.html)

Wie bei HTML, so gibt es mittlerweile auch von JavaScript mehrere Versionen. Da es natürlich Unterschiede zwischen den Versionen gibt, muss der Browser irgendwie erkennen können, um welche Version es sich handelt. Die bisher gezeigten Beispiele beziehen sich alle auf Version 1.0. Soll eine andere Version eingesetzt werden, so sollte dies mit dem Attribut language angezeigt werden. Folgende Beispiele zeigen, wie das geht1.

Lösung zu 3 Die JavaScript-Version wird über das Attribut language des script-Elements angegeben. Beispiel:

Inhalt verstecken -->

Der Anfang des HTML-Kommentares ist

Qudratzahlen



Ihr Browser kann keine JavaScript-Programme ausführen. Aus diesem Grund sehen Sie hier nichts. :-(

Listing 2.1: Einsatz der Quadratfunktion (beispiel0201.html) Sichtbarkeitsbereich von Variablen

Wenn Sie viele Variablen und viele Funktionen in Ihrem Programm verwenden, stellt sich rasch die Frage, in welchem Kontext eine Variable sichtbar ist oder nicht. Die Antwort ist relativ einfach: Eine Variable, die innerhalb einer Funktion mit var deklariert wird, ist nur innerhalb dieser Funktion sichtbar.

Sichtbarkeit von Variablen

28

Grundlagen

Sichtbarkeit von Variablen



Ihr Browser kann keine JavaScript-Programme ausführen. Aus diesem Grund sehen Sie hier nichts. :-(



Die Ausgabe, die durch dieses Programm erzeugt wird, zeigt das folgende Listing: HP: f1: f1: HP: f2: f2: HP:

Wert Wert Wert Wert Wert Wert Wert

von von von von von von von

x x x x x x x

ist ist ist ist ist ist ist

5 5 10 10 undefined 15 10

29

2 Die Sprache Es ist leicht zu erkennen, dass sich das Hauptprogramm und die Funktion f1() die Variable x »teilen«, sie ist global. Im Gegensatz dazu führt die Deklaration der Variablen x in f2() dazu, dass die Variable lokal ist. Sie besitzt zu Beginn sogar nicht einmal einen Wert, sie ist undefiniert. Nach Möglichkeit sollten globale Variablen vermieden werden, da durch sie das Programm unübersichtlicher und damit fehleranfälliger wird.

2.1.7

Arrays

Arrays besitzen wie Variablen einen Namen. Im Unterschied zu Variablen, können Arrays aber nicht nur einen Wert, sondern mehrere Werte speichern. Jeder dieser Werte steht an einer bestimmten Position im Array. Im einfachsten Fall werden diese Positionen einfach durchnummeriert und später über einen numerischen Index angesprochen. Das folgende Beispiel verdeutlicht dies: // Neues Array definieren: var meinArray = new Array(); // Array mit meinArray[0] meinArray[1] meinArray[2] meinArray[3]

Inhalt füllen: = "D"; = "C"; = "B"; = "A";

document.writeln("Das Array hat ", meinArray.length," Einträge"); for (var i = 0; i < meinArray.length; i = i+1) { document.writeln("Inhalt von Feld ", i," ist ",meinArray[i]); }

Als Ausgabe werden folgende Zeilen angezeigt: Das Array hat 4 Inhalt von Feld Inhalt von Feld Inhalt von Feld Inhalt von Feld

30

Einträge 0 ist D 1 ist C 2 ist B 3 ist A

Übungen Das Beispiel zeigt, dass 왘 Arrays mit new Array() erzeugt werden 왘 die Nummerierung bei Arrays immer bei Null beginnt 왘 die Anzahl der Einträge durch Anhängen von .length ermittelt werden

kann Neben der Verwendung von Nummern als Index ist auch ein String erlaubt. So könnte man beispielsweise ein Array namens telefon[] in der Form telefon["Elisa"] = "0 7372 / 6876"

mit Werten füllen, die anschließend etwa durch den Ausdruck telefon ["Elisa"] abgefragt werden könnten. Solche Arrays heißen assoziative Arrays. Das Durchlaufen mit der for-Schleife funktioniert hierbei natürlich nicht mehr.

2.2

Assoziative Arrays

Übungen

leicht

1. Übung

Schreiben Sie ein Programm, das die Quadrate der Zahlen von 0 bis 9 untereinander in einer HTML-Seite ausgibt. mittel

2. Übung

Schreiben Sie ein Programm, das untereinander die Zeichenfolge »0«, »01«, »012«, »0123«, ... »0123456789« ausgibt. Die Anführungszeichen gehören nicht zur Ausgabe. leicht

3. Übung

Benutzen Sie die Lösung für Übung 1 und schreiben Sie das Programm so um, dass an Stelle der for-Schleife eine while-Schleife zum Einsatz kommt. mittel

4. Übung

Schreiben Sie eine HTML-Seite, die den Besucher der Seite beim Laden nach seinem Vornamen fragt und in Erfahrung bringt, ob er mit »Du« oder »Sie« angesprochen werden möchte. Anschließend erscheint ein kurzer Begrüßungstext, der den Namen des Besuchers hervorgehoben (fett) enthält und ihn korrekt mit »Du« oder »Sie« anredet. Zur Hervorhebung des Namens schreiben Sie bitte eine Funktion, die einen beliebigen Text, der als Parameter übergeben wird, in die HTML-Tags und einschließt.

31

2 Die Sprache leicht

5. Übung

Schreiben Sie ein Programm, das ein assoziatives Array namens adresse[] definiert, dieses für die Indizes name, anschrift, plz, ort mit Werten füllt und die Werte anschließend in einer HTML-Tabelle darstellt. Vergleichen Sie, was passiert, wenn man das assoziative Array genau so mit einer for-Schleife durchläuft, wie es oben mit dem Array meinArray[] vorgeführt wurde. leicht

6. Übung

Testen Sie, wie sich der Inhalt des oben gezeigten Arrays meinArray[] ändert, wenn Sie die Anweisung meinArray.sort() ausführen.

2.3

Tipps

Tipp zu 1 Benutzen Sie eine for-Schleife, die von 0 bis 9 hochzählt, den Zähler quadriert und das Ergebnis mit document.writeln() ausgibt. Tipp zu 2 Verwenden Sie die Lösung aus der vorhergehenden Aufgabe und ändern Sie das Programm so ab, dass der Zähler nicht als Zahl, sondern als Zeichen interpretiert und ausgegeben wird. Tipp zu 3 Ersetzen Sie die for-Schleife durch eine while-Schleife, definieren Sie vor der Schleife die Zählvariable und erhöhen Sie diese im Schleifenrumpf durch Addition von 1. Tipp zu 4 Zur Abfrage der Besucherinformationen dienen die zu Beginn des Kapitels genannten Funktionen prompt() und confirm(). Die abgefragten Informationen können als Werte von globalen Variablen gespeichert werden, damit sie überall im Programm zur Verfügung stehen. Die Funktion zur Hervorhebung muss lediglich einen String als Parameter annehmen und als Ergebnis diese Zeichenkette, ergänzt um "" und "", mit return als Ergebnis liefern. Das Hauptprogramm erzeugt mit document.writeln() die Ausgabe, wobei an geeigneter Stelle der Name, durch den Funktionsaufruf hervorgehoben, ausgegeben werden muss. Zur Anrede mit »Du« oder »Sie« macht eine if-thenelse-Anweisung eine Fallunterscheidung, die auf die o.g. globale Variable Bezug nimmt.

32

Lösungen

2.4

Lösungen

Lösung zu 1



Die Ausgabe des Programms ist: Ausgabe Quadrat Quadrat Quadrat Quadrat Quadrat Quadrat Quadrat Quadrat Quadrat Quadrat

der von von von von von von von von von von

Quadratzahlen von 0 bis 9: 0 ist: 0 1 ist: 1 2 ist: 4 3 ist: 9 4 ist: 16 5 ist: 25 6 ist: 36 7 ist: 49 8 ist: 64 9 ist: 81

Lösung zu 2



Die Ausgabe des Programms ist: Ausgabe der Zeichenketten: 0 01 012 0123 01234 012345 0123456 01234567 012345678 0123456789

Lösung zu 3



Die Ausgabe des Programms ist identisch zur Ausgabe der Lösung zu Übung 1. Lösung zu 4

JavaScript-Workshop: Musterlösung

Herzlich Willkommen!



Je nachdem, was der Besucher eingibt, erhält er beispielsweise folgende HTML-Seite als Ergebnis:

35

2 Die Sprache Abbildung 2.1: Ausgabe der Musterlösung zu Übung 4

Lösung zu 5 Das folgende Listing zeigt eine Musterlösung für die Übung 5. In der anschließenden Abbildung 2.1 ist die Ausgabe des Programms im Navigator zu sehen. Sie erkennen, dass das Durchlaufen mit numerischem Index nicht funktioniert, weil der length-Wert Null ist.

JavaScript-Workshop: Musterlösung

Assoziative Arrays



Lösung zu 6 Durch Hinzufügen der Zeilen meinArray.sort(); document.writeln("Das Array hat ",meinArray.length, " Einträge"); for (var i = 0; i < meinArray.length; i = i+1) { document.writeln("Inhalt von Feld ",i, " ist ",meinArray[i]); }

37

2 Die Sprache Abbildung 2.2: Ausgabe der Musterlösung zu Übung 5

wird die zusätzliche Ausgabe Das Array hat 4 Inhalt von Feld Inhalt von Feld Inhalt von Feld Inhalt von Feld

Einträge 0 ist A 1 ist B 2 ist C 3 ist D

erzeugt. Die Arrayinhalte wurden also umsortiert.

38

3

Das Objektmodell Von Christine Kühnel, [email protected]

3.1

Grundlagen

JavaScript-Programme laufen nicht im luftleeren Raum, sie brauchen eine Umgebung. Da sie nicht wie viele andere Programme übersetzt werden, muss diese Umgebung die Syntax der Sprache beherrschen, um die Skripte1 interpretieren zu können.

3.1.1

Die Sprache in ihrer Umgebung

Wir beschäftigen uns hier mit JavaScript im Bereich Web-Publishing, deswegen ist unsere Umgebung der Web-Browser2. Der Browser übernimmt also die Rolle des Interpreters für unsere Skripte. Das Wichtige und Interessante daran ist, der Browser interpretiert nicht nur, er bietet auch Objekte an, auf die man zugreifen kann. Sie werden beim Schreiben Ihrer eigenen Skripte ständig mit diesen Objekten zu tun haben, ohne sie geht (fast) nichts. Sie sind einigen wenigen Objekten sogar schon hier in diesem Buch begegnet, auch wenn Ihnen das vielleicht gar nicht bewusst geworden ist. Sie erinnern sich gewiss an diese Anweisung: alert("Hallo Du!");

Schon dieses einfache Meldungsfenster setzt voraus, dass der Browser überhaupt in der Lage ist, es sichtbar zu machen. Er bietet im window-Objekt die Methode alert() an, die genau das realisiert, ein guter Grund also, dem Objektmodell (OM) – so nennt man die Struktur dieser Objekte – erhöhte Aufmerksamkeit zu widmen.

Objektmodell

Aber unternehmen wir zuvor einen kurzen Abstecher für diejenigen unter Ihnen, denen der Denkansatz der objektorientierten Programmierung noch nicht so vertraut ist, alle anderen dürfen schon mal weiter blättern.

1. Ich werde von jetzt an den Begriff »Skript« verwenden. Sollten andere Autoren »Programm«, »JavaScript-Programm« oder »Script« sagen, lassen Sie sich nicht verwirren, es ist dasselbe. 2. Der Vollständigkeit halber sei hier erwähnt, dass es im Bereich Web-Publishing auch serverseitiges JavaScript gibt. Das ist jedoch nicht Thema dieses Workshops.

39

3 Das Objektmodell

3.1.2

Denken in Objekten

Gebrauchen Sie das Wort Objekt ruhig im Wortsinn, denn genau darin besteht die Idee. Man benutzt eine aus dem täglichen Leben geläufige Art, Dinge zu betrachten. Wir veranschaulichen uns das Prinzip am besten an einem ganz einfachen Beispiel. Sie halten gerade ein Buch in den Händen. Dieses Buch ist ein Objekt. Einverstanden? Wenn Sie zunächst ein Buch überhaupt und dann speziell dieses Buch beschreiben sollten, wie würden Sie anfangen? Vielleicht so? 1. Ein Buch besteht aus einem Einband und einzelnen Seiten. Dieses Buch hier ist ein Taschenbuch, es hat einen vorwiegend gelben Einband, ... Sie analysieren das Objekt, beschreiben seine Eigenschaften und die seiner Bestandteile. Nichts anderes tut die objektorientierte Programmierung. Zur Darstellung dieser Hierarchie bedient man sich einer speziellen Syntax. Man beginnt mit dem Objekt auf der obersten Ebene, fügt dessen Eigenschaften durch einen Punkt getrennt an. Ist diese Eigenschaft (engl. Property) selbst wieder ein Objekt, hat also eigene Eigenschaften, dann fährt man ganz einfach nach diesem Prinzip fort. In einem Objekt Buch könnte man also z.B. Folgendes finden: Buch.Einband Buch.Seiten Buch.Titel Buch.Verlag

Natürlich sind das längst nicht alle Eigenschaften, aber im Alltag erwähnen Sie sicher auch nicht immer jedes einzelne Detail, sondern greifen die Eigenschaften heraus, die gerade interessant und wichtig sind. Das tun wir hier auch, und das werden Sie auch in Ihren Skripten so machen. Wir erkennen außerdem, einige Eigenschaften sind wiederum so komplex, dass es mit einer einfachen Wert-Zuweisung wohl nicht getan ist, der Einband zum Beispiel ruft geradezu nach einem eigenen Objekt. Vielleicht verwirrt es Sie, dass Objekte Eigenschaften anderer Objekte sein können? Dann versuchen Sie es zur Verdeutlichung einmal mit folgender gar grausigen Formulierung: Ein Buch hat die Eigenschaft, einen Einband zu haben. :-) Die folgende Syntax dafür ergibt sich aus den bisherigen Erklärungen. Ihnen ist sicher sofort klar, warum man zum Beispiel das hier schreibt: Buch.Einband.Farbe Buch.Einband.Art Buch.Seiten.Anzahl

40

Grundlagen Bisher haben wir das Objekt Buch ganz allgemein angesehen. Die erwähnten Eigenschaften existieren für jedes Buch; unterschiedlich sind dagegen die Werte dieser Eigenschaften. Betrachten wir dazu neben diesem Buch, in dem Sie gerade jetzt lesen, noch ein zweites. Der noch nicht zu Ende gelesene Roman auf Ihrem Nachtschrank ist ganz sicher auch ein (Objekt) Buch, hat ebenfalls (die Eigenschaften) Einband, Seitenund Titel. Wie unterscheiden sich aber die beiden Bücher, und wie unterscheidet man sie syntaktisch? Tabelle 3.1 verdeutlicht Zusammenhänge und Unterschiede. Dazu nennen wir die beiden Bücher, oder besser, die beiden Objekte diesesBuch und meinRoman. Eigenschaft

Wert

Eigenschaft

Wert* Typ

diesesBuch

meinRoman

.Einband

.Einband

Object

.Einband .Art

'Taschenbuch'

.Einband .Art

String

.Einband .Farbe

'gelb'

.Einband .Farbe

String

.Seiten

300

.Seiten

Integer

.Titel

'JavaScript WorkShop'

.Titel

String

.Verlag

'Addison-Wesley'

.Verlag

String

Tab. 3.1: Beispiel-Objekte, Eigenschaften, Werte

*Die Werte für meinRoman setzen Sie bitte selbst ein. Ich weiß nicht, was Sie gerade lesen.

Die (Werte der) Eigenschaften eines Buches, die wir gerade eben angesehen haben, können Sie nicht verändern, die Farbe des Einbandes wird immer so sein, wie sie jetzt ist (von eventuellen Gebrauchsspuren durch intensive Benutzung wollen wir hier einmal absehen). Das wird Ihnen auch künftig begegnen, nur lesbare Eigenschaften und solche, deren Werte überschrieben werden können. Auch bei einem Buch ist das so. Das Buch, das Sie in den Händen halten, wird sehr wahrscheinlich aufgeschlagen sein, sonst könnten Sie das hier ja nicht lesen. Es hat also auch eine Eigenschaft diesesBuch.offen

Im Moment ist der Wert wahr (true). Aber irgendwann werden Sie das Gelesene erst einmal verdauen müssen und das Buch zuschlagen., der Wert wird sich dabei ändern, anschließend falsch (false) sein. Eine Aktionen, das Zuschlagen, sorgt dafür. Diese Aktion, sie ahnen es, ist eine Methode des Objektes diesesBuch. Methoden ruft man so auf: diesesBuch.zuschlagen()

41

3 Das Objektmodell Dabei lassen sich in Klammern Parameter angeben, die der Aktion erforderliche Informationen liefern. So etwas kennen Sie schon von Funktionen her. Beim Zuschlagen eines Buches ist es sicher nicht notwendig, näher zu spezifizieren, aber bereits beim Gegenstück, dem Aufschlagen, kann das durchaus nützlich sein. Mit diesesBuch.aufschlagen(140)

könnte man der Methode sagen, dass das Buch auf Seite 140 aufgeschlagen werden soll. An der Stelle beenden wir unseren kleinen Ausflug. Wie man in JavaScript Objekte definiert, ihnen Eigenschaften und Methoden zuordnet, damit befassen wir uns im folgenden Kapitel genauer. Behalten Sie also das Buch in den Händen und das Objekt diesesBuch im Gedächtnis. Kehren wir zunächst zurück zum Objektmodell des Browsers und den darin enthaltenen »vorgefertigten« Objekten. Objekte in der Umgebung, oder einfacher – das OM des Browsers Schauen wir uns so ein Objektmodell aus der Nähe an. Abbildung 3.1 zeigt stark vereinfacht die Struktur, die wir bei allen bekannten Browsern wiederfinden.3 Wir können hier nicht auf alle Objekte eingehen. Das ist aber auch gar nicht erforderlich. Haben Sie einmal die Grundstruktur erkannt, herausgefunden, wie man damit umgeht, ist alles andere nicht mehr wirklich schwer. Werfen wir also nur einen Blick auf einige ausgewählte Objekte. window Es muss nicht nur ein window geben

Sie erkennen an der schematischen Darstellung, das Objekt window spielt eine zentrale Rolle. Um besser zu verstehen, nehmen Sie es ruhig wörtlich. window repräsentiert tatsächlich das geöffnete Fenster Ihres Browsers. Und damit ist sofort klar, es muss nicht nur ein window-Objekt geben. Sie könnten ja mehrere Browserfenster gleichzeitig verwenden. Alles, was in (und später auch mit) dem Fenster geschieht, spielt sich innerhalb dieses Objektes ab. Für die Praxis merken wir uns noch, dass von einem Skript aus das Fenster, in dem es läuft, immer über window zu erreichen ist. Damit haben wir den Startpunkt, um alle nachgeordneten Objekte anzusprechen, um zum Beispiel auf das Dokument in diesem Fenster zuzugreifen: window.document In vielen Fällen kann man auf die Angabe window verzichten, weil es vom Browser standardmäßig eingesetzt wird. Das heißt, window.document und document sagen dasselbe. 3. Korrekt müsste es heißen: fast bei allen bekannten Browsern. images gibt es erst ab JavaScript 1.1, also NN3, wurde aber hier ganz bewusst dennoch aufgenommen.

42

Grundlagen

window

navigator

Abbildung 3.1: Objektmodell stark vereinfacht

document forms elements

links

images

frames history location Ich werde jedoch jetzt und hier davon zunächst wenig Gebrauch machen, und empfehle das für den Anfang auch Ihnen. Sie schreiben bewusster, wenn Sie die vollständige Angabe wählen. Auch später ist es durchaus oft sinnvoll, für sich selbst die lange Form zu wählen. Spätestens beim Durcharbeiten von Kapitel 7, wenn es um Referenzierungen über Frame- und Fenstergrenzen hinweg geht, werden Sie mir vermutlich zustimmen. Gerade haben Sie verstanden, was das window-Objekt ist, und schon muss ich das eben Gesagte etwas einschränken. Dieses Objekt begegnet uns nicht nur in Form des Browserfensters, sondern auch noch in einer anderen, nämlich als Frame. Sie haben in Abbildung 3.1 zum Beispiel frames[] gesehen. Das ist nichts anderes als ein Array, bestehend aus window-Objekten, für jeden Frame eins, das nicht unabhängig existiert, sondern fest zum Hauptfenster gehört.

Ein Frame ist auch ein window

Um uns an den Umgang mit den browsereigenen Objekten heranzutasten, wählen wir zunächst die Eigenschaft location, das ist eine vergleichsweise übersichtliche Eigenschaft.

43

3 Das Objektmodell location location ist selbst ein Objekt, nämlich der Repräsentant des aktuellen URLs im Fenster. Von dessen Eigenschaften soll uns hier zunächst nur href interessieren;

ihr Wert gibt uns den aktuellen URL an. Probieren Sie es aus! Schreiben Sie dazu dieses kleine Skript, das die Information in einem Meldungs-Fenster zeigt:

Auf noch eine Eigenschaft von window wollen wir an dieser Stelle kurz einen Blick werfen, auf das wohl komplexeste Objekt, document. document document beinhaltet all das, was das gerade aktuelle Dokument im Fenster

betrifft. Es ist damit durchaus folgerichtig, dass alles, was Sie in einer HTMLDatei spezifizieren, unterhalb dieses Objektes wiederzufinden ist. Das sind. z.B. alle Links der Seite, enthaltene Formulare und Grafiken, Farbangaben für Text und Hintergrund etwa, und noch sehr vieles mehr. An zwei ausgewählten Objekten werden wir nun den Umgang etwas genauer betrachten. Machen Sie sich keine Sorgen, wenn Sie am Ende dieses Kapitels nicht absolut fit sind. Es soll Ihnen die Grundlagen vermitteln. Gelegenheit zum intensiveren Üben finden Sie später in diesem Buch. Beginnen wir mit einem oft gebrauchten Objekt, dem Form-Objekt, denn Formulare in HTML-Dateien sind Ihnen vertaut. Form-Objekt

Eine Datei wie die folgende ist Ihnen schon oft begegnet, ein einfaches Formular mit zwei Textfeldern zum Ausfüllen, drei Radio-Buttons zur Auswahl und einem Button, der am Ende für Action sorgt:

Angaben zur Person

Angaben zur Person

Vorname:

Nachname:

weiblich

44

Grundlagen männlich keine Angabe




Der Button »Anzeigen« ist im Moment noch vollkommen funktionslos. Seine Aufgabe soll es später sein, uns die eingegebenen Werte per alert() zu zeigen. Um die Werte zu ermitteln, müssen die einzelnen Elemente angesprochen werden. Dafür gibt es verschiedene Möglichkeiten. Wir entscheiden uns hier zunächst für die, wie ich finde, anschaulichste. Vorsorglich wurde allen Elementen über name-Attribute Namen4 gegeben, über die sie zu erreichen sind: window.document.Person.Vorname window.document.Person.Nachname window.document.Person.Anzeige

Es fällt sofort auf, der Name »Geschlecht« ist im Beispiel nicht eindeutig gewählt, er steht für alle drei Radio-Buttons. Wie also den einzelnen RadioButton erreichen? Dafür bietet der Browser eine andere Möglichkeit. Für die drei Buttons existiert ein Array Geschlecht[] mit drei Elementen5: window.document.Person.Geschlecht[0] window.document.Person.Geschlecht[1] window.document.Person.Geschlecht[2]

Damit fehlen zur Bewältigung der Aufgabe, die Werte zu ermitteln, nur noch Eigenschaften, in denen sich diese Werte finden. 왘 Für die Textfelder ist dies

value mit dem enthaltenen Text als String

왘 Für die Radiobuttons gibt es

checked als Boolean

Mit den nun vorhandenen Kenntnissen ist es nicht mehr schwer, eine Funktion vorzubreiten, die die gewünschte Ausgabe generiert. In einem Script-Block im head sieht das so aus:

Was noch fehlt, ist der Aufruf dieser Funktion. Die Anzeige soll bei Klick auf den Button »Anzeigen« erfolgen. Dafür benutzen wir den Event-Handler onclick. Darauf, was ein Event-Handler ist, kommen wir gleich zurück. Zunächst benutzen wir diesen hier, ohne weiter darauf einzugehen. Dazu muss im HTML-Code von oben lediglich dem input-Element ein entsprechendes Attribut hinzugefügt werden:

Eine andere Möglichkeit, dieselben Objekte anzusprechen, soll hier noch erwähnt werden. Gerade ist uns ein Array begegnet. Der Browser bietet für eine Reihe von Objekten Arrays an. Zum Beispiel könnte man die Werte der Textfelder so ermitteln: var x = window.document.forms[0].elements[0].value; var y = window.document.forms[0].elements[1].value;

Das Prinzip: In document gibt es ein Array forms[] mit allen Formularen, im Form-Objekt wiederum eins mit allen Elementen des Formulars, nämlich elements[], jeweils in der Reihenfolge ihres Auftretens. Verlassen wir hier das Form-Objekt, Sie werden an anderer Stelle Gelegenheit haben, sich eingehender damit zu beschäftigen. Hier sollte Ihnen zunächst nur deutlich werden, wie sich Ihnen vertraute HTML-Elemente in der Objekthierarchie des Browsers wiederfinden. Deswegen werfen wir nur noch kurz einen Blick auf ein anderes immer wieder anzutreffendes Objekt, das Image-Objekt. Image-Objekt

Wir benutzen wieder eine ganz einfache HTML-Datei:

Image-Objekt

46

Grundlagen Bilder eben

ein Bild:

und noch ein Bild:



Mit Hilfe von alert() wollen wir diesmal sehen, welche Grafik-Datei im zweiten img-Element benutzt wird. Unser Beispiel zeigt es, auch img-Elemente treten mehrfach auf. Sie kennen das inzwischen aus dem Formular-Beispiel, es existieren auch hier mehrere ImageObjekte in einem Array window.document.images

Ansprechen kann man sie deswegen ganz analog: window.document.images[0] window.document.images[1]

Da das name-Attribut verwendet wurde, geht auch: window.document.erstesBild window.document.zweitesBild

An dieser Stelle sei eine weitere Möglichkeit erwähnt. Die name-Eigenschaft dient dem Browser dazu, Arrays als assoziative Arrays6 anzubieten: window.document.images['erstesBild'] window.document.images['zweitesBild']

Ein anderer Begriff wird Ihnen ganz gewiss noch begegnen, wenn es um in Arrays »gesammelte« Objekte geht: Collection7 Kehren wir zu unserer Aufgabe zurück. Dazu müssen wir jetzt nur noch wissen, dass die Eigenschaft, in der der URL der Grafikdatei zu finden ist, src heißt, dann haben wir alle Voraussetzungen. Wir probieren bei der Gelegenheit gleich alle drei Möglichkeiten, unser Image-Objekt anzusprechen, die Ergebnisse sollten identisch sein:

6. Sie werden später sehen, es muss nicht name sein, vor allem im DHTML-Teil wird Ihnen id in dieser Rolle begegnen. 7. Auch wenn das Wort »collection« sich vergleichsweise problemlos in unsere Sprache übersetzen lässt, tun wir sicher gut daran, es auch weiterhin beim englischen Original zu belassen.

47

3 Das Objektmodell

Image-Objekt

Bilder eben

ein Bild:

und noch ein Bild:





Welche Form Sie in der Praxis benutzen, das hängt zum einen sicher vom konkreten Problem ab und zum anderen auch von Ihrer persönlichen Vorliebe. Ich verwende häufig die dritte Form, die hat einen oft sehr nützlichen Vorteil, Funktionen und Methoden kann man mitteilen, welches konkrete Objekt angesprochen werden soll, indem man Ihnen als Parameter einen String übergibt, der den Namen enthält. Sie werden sicher in den Beispielen und Übungen dieses Buches noch deutlicher sehen, was ich meine. Denken Sie bei der Wahl auch daran, dass die Verwendung numerischer Indizes wenig änderungsfreundlich ist. Bei jeder Änderung im HTML-Code müssen Sie nachschauen, ob die Indizes noch stimmen. Eigenschaften definieren Sie vermuten richtig; es ist kein Zufall, dass es eine Eigenschaft src gibt, die den URL der Grafikdatei enthält, und dass der Wert dieser Eigenschaft durch das src-Attribut im img-Tag festgelegt wurde. Attribute in HTML-Tags legen Eigenschaften von HTML-Elementen fest. Findet sich für so ein Element ein Objekt in Objektbaum, dann hat es im Allgemeinen Eigenschaften, die den Attributen entsprechen, deren Werte man wie gerade gesehen über Attribute festlegen kann.

48

Grundlagen width und height zum Beispiel sollten im Image-Objekt also auch zu finden sein. Probieren Sie es aus! alert(window.document.images['zweitesBild'].width); alert(window.document.images['zweitesBild'].height);

Event-Handler Sie kennen das; wenn Sie Links mit der Maus berühren, verändern sich Grafiken. Weil es das Paradebeispiel für den Einsatz von Event-Handlern ist, werde auch ich keine Ausnahme machen und genau diesen Effekt benutzen, um Ihnen Ereignisse (engl. events) etwas näher zu bringen. Die Veränderung ist natürlich nicht wirklich eine Veränderung, sondern lediglich die Zuweisung eines anderen Wertes (URL der angezeigten Grafik) zur srcEigenschaft des Image-Objektes. Der Trick, der eigentlich gar keiner ist, besteht lediglich darin, dass der neue Wert in einem ganz bestimmten Moment zugewiesen wird. Man macht sich zunutze, dass es der Browser ermöglicht, das Eintreten bestimmter Ereignisse zu erkennen. Die bekanntesten Ereignisse sind das Berühren eines Links mit der Maus bzw. das Verlassen des Links. Ereignisse sind an ein Objekt gebunden, hier ist es das Link-Objekt. Bei dem wollen wir vorerst auch bleiben. Das große Thema »Event-Handling« und seine Vielfalt werden Ihnen später noch mehrfach in diesem Workshop begegnen.

Das Eintreten bestimmter Ereignisse ist erkennbar

Aber zurück zu unserem Beispiel. Die Ereignisse »Maus berührt Link« und analog »Maus verlässt Link« zeigen so genannte Event-Handler an, die das LinkObjekt besitzt. Für den dritten Link innerhalb des Dokuments tun das zum Beispiel window.document.links[2].onmouseover window.document.links[2].onmouseout

Sie sehen bei der Gelegenheit, die Link-Objekte finden sich ebenfalls als Elemente eines Arrays, nämlich document.links[] Häufiger verwendet wird eine andere Schreibweise. Im Formular-Beispiel haben wir sie für onclick auch schon eingesetzt. So, wie sich Eigenschaften von Objekten sowohl im Script als auch als Attribut im HTML-Element festlegen lassen, ist auch bei Event-Handlern beides möglich. Damit haben wir schon alles, was für die einfachste Form, so einen Wechsel zu initiieren, erforderlich ist. Und so könnte er aussehen.

Events



Dass das so nicht die eleganteste Lösung für Bildwechsel ist, man in der Praxis noch auf ein paar Dinge am Rande achten sollte, lassen wir an dieser Stelle einmal außen vor. Das Prinzip ändert sich dadurch nicht, es wird Ihnen bei allen Bildwechseln immer wieder begegnen, so gut, vielleicht sogar raffiniert sie auch gemacht sein mögen. Eigene Variablen ordnen sich in die Objekthierarchie des Browsers ein Bisher haben wir uns Objekte angesehen, die der Browser mitbringt. In Kapitel 2 haben Sie Variablen definiert. Die existieren nicht etwa neben den Browserobjekten, sondern finden sich in der Objekthierarchie wieder. Erinnern Sie sich bitte an das vorangegangene Kapitel. Da ging es um Konten.

Probieren Sie aus, bauen Sie das hier kurz ein: Eigene Variablen finden sich im Objektbaum

alert(window.kontonummer); alert(window.kontoinhaber); alert(window.kontostand);

Das Ergebnis ist deutlicher als es jede Erklärung sein könnte. Ihre Variablen sind Eigenschaften von window. Das gilt so natürlich nur für Variablen, die auch im ganzen Fenster bekannt sind. Erinnern Sie sich bitte an Kapitel 2 und daran, welche Variablen wo sichtbar sind. Nur was der Browser kennt, kann man verwenden Bis hierher ist Ihnen ganz bestimmt klar geworden, dass man auf die Objekte angewiesen ist, die der Browser anbietet. Es muss ein window geben, ein document, document muss ein Array forms[] enthalten usw. Skripte, die Sie für das Web schreiben, laufen nicht in einer bekannten oder bestimmbaren Umgebung, sondern auf dem Client. Im Voraus wissen Sie nicht, welchen Browser der Besucher der Seiten verwendet, kennen also die Umgebung nicht, in der die Skripts angestoßen werden. Nun ist die Existenz der Objekte aber Voraussetzung, es stellt sich also eine wichtige Frage:

50

Grundlagen

3.1.3

Sind die Objektmodelle der Browser identisch?

Nein! JavaScript ist vergleichsweise jung. Was Navigator 2 von Netscape, der erste Browser mit JavaScript-Fähigkeit, konnte und kannte, waren allererste Anfänge. Die Entwicklungen, die man insbesondere bei den Browsern von Netscape und Microsoft seither beobachten kann, sind gravierend. Die Sprache selbst hat sich dabei gar nicht so sehr gewandelt, die Objektmodelle sind es, die sich so stürmisch verändern. Betrachtet man das OM des Navigator 2 heute, so nimmt es sich vergleichsweise bescheiden aus. Und die Entwicklung steht ganz sicher noch lange nicht still. Für uns, die wir JavaScript für das Web einsetzen, heißt das, wir müssen mit Unterschieden leben, sie kennen und berücksichtigen. Seiten, mit denen der Besucher nichts anfangen kann, die ihn vielleicht sogar mit Fehlermeldungen verjagen, gehören zum Unangenehmsten, was uns passieren kann. Welcher Browser bietet was? Ich würde Ihnen diese Frage gern beantworten, wenn ich es könnte. Ich fürchte allerdings, eine nur annähernd vollständige Liste füllt ein eigenes wesentlich dickeres Buch als dieses hier. Hilfreich ist es, etwas zur Geschichte der Browser zu wissen: 왘 Das, was der erwähnte Navigator 2 konnte und kannte, wird nachträglich als JavaScript 1.0 bezeichnet.8 왘 Etwas später zieht Microsoft mit dem Internet Explorer 3 nach, was die

JavaScript-Fähigkeit der Browser anging. Die Unterschiede zum Navigator 2 sind nicht wirklich gravierend, zumindest aus heutiger Sicht nicht mehr. 왘 Danach kommt der nächste von Netscape, die Version 3. Er bringt die ers-

ten wirklichen Neuerungen mit. Mit ihm erscheint auch die JavaScript-Versionsangabe und die Möglichkeit, sie in

Ihr Browser kann leider ohne JavaScript keine Informationen über ein JavaScript-Objekt liefern.



Ich habe gerade Netscape 4.72 unter Windows 98 hier. Damit erhalte ich: navigator.userAgent navigator.appCodeName navigator.appVersion navigator.appName navigator.language navigator.platform

Mozilla/4.72 [en] (Win98; I) Mozilla 4.72 [en] (Win98; I) Netscape en Win32

Und mein Internet Explorer 5 zeigt: navigator.userAgent Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt) navigator.appCodeName Mozilla navigator.appVersion 4.0 (compatible; MSIE 5.0; Windows 98; DigExt) navigator.appName Microsoft Internet Explorer navigator.language undefined navigator.platform Win32

Sie sehen, es sind Strings, die man natürlich auf ihren Inhalt hin untersuchen kann, und Sie sehen auch, dass navigator.userAgent die wichtigsten Informationen enthält. Je nachdem, wonach Sie unterscheiden wollen, untersuchen Sie dazu vielleicht noch andere Eigenschaften. Dafür lässt sich nur schwer ein Schema angeben, die Gründe, warum man unterscheiden will, sind zu vielfältig.

53

3 Das Objektmodell indexOf() leistet gute Dienste

Weil es um Auswertung von Zeichenfolgen geht, sei hier noch ein nützliches Hilfsmittel kurz vorgestellt: indexOf() bietet sich geradezu an. Das ist eine Methode, die Objekte vom Typ String besitzen, also alle Zeichenketten. Sie gibt Ihnen die Anfangsposition einer enthaltenen Zeichenfolge zurück. Und das ist die allgemeine Syntax: stringName.indexOf(searchValue, [fromIndex])

Wichtig und nützlich ist die Tatsache, dass -1 zurückgegeben wird, wenn die gesuchte Zeichenfolge nicht enthalten ist. Die Benutzung ist denkbar einfach: if(indexOf(navigator.userAgent,' MSIE')>-1) alert('Aha, ein Browser von Microsoft!');

Einen Hinweis muss ich zur Browsererkennung über navigator-Objekt unbedingt anbringen: Es wird oft davon ausgegangen, dass navigator.appName die Erkennung von Netscape-Browsern ermöglicht. Das stimmt so nicht. Zum Beispiel findet man auch bei Opera dort »Netscape«. Verwenden Sie bitte deswegen nie ausschließlich navigator.appName! Eine Übersicht darüber, was bei einer Reihe von Browsern in den Werten des navigator-Objektes alles so steckt, finden Sie im Web unter http://www.netznotizen.de/javascript/tipps/navigator.html. Unterscheidung per navigatorObjekt ist nicht unbedingt der beste Weg

Ich verwende derartige Browsererkennungen nur selten. Es gibt eine sicherere Methode: Man fragt den Browser, ob er die benötigte Eigenschaft des Objektes kennt, bevor man sie verwendet. Damit ist man etwas weniger auf Kenntnisse über jeden einzelnen Browser angewiesen. if (document.images)

liefert zum Beispiel abhängig davon, ob es document.images gibt oder nicht, true oder false. Will man also vermeiden, dass Browser, die gar kein ImageObjekt kennen, die Besucher mit lästigen Fehlermeldungen nerven, statt Bildwechseleffekte zu zeigen, führt man die Anweisungen nur im true-Fall aus. Deswegen sind die Beispiele zum image-Objekt weiter oben gar nicht besucherfreundlich, denn gerade das image-Objekt kennen die ersten Browser tatsächlich nicht. Wir hätten besser vorher nach seiner Existenz gefragt, zum Beipiel so:

Image-Objekt





Nun ist es sicher kaum praktikabel, nach jeder Eigenschaft zuvor zu fragen. Das ist auch nicht erforderlich. Auch hier ist Wissen um die Fähigkeiten der Browser sehr hilfreich. Man kann von der Existenz bestimmter Objekte ausgehend darauf schließen, dass auch anderes bekannt ist. Und genau das tun die meisten JavaScript-Programmierer auch. Das gerade erwähnte image-Objekt ist das Beispiel dafür. Es kam mit dem Navigator 3, also JavaScript 1.1, und man geht davon aus, dass ein Browser, der dieses Objekt kennt, auch alles andere beherrscht, was diese Version enthält.

3.2

Übungen

1. Übung Wer interpretiert Ihre Skripte? 1. Das Betriebssystem des Client-Rechners 2. Der Web-Server 3. Der Web-Browser Was ist neben der Sprache selbst die wichtigste Grundlage, auf die JavaScriptProgramme angewiesen sind? 2. Übung Wie könnte man den Browser veranlassen, eine andere Datei zu laden? 3. Übung Sie haben alternative Seiten vorbereitet: eine Version für Browser, die nichts mit JavaScript anfangen können oder nur etwa den Umfang von JavaScript 1.0 beherrschen, eine andere für alle anderen. Wie würden Sie dafür sorgen, dass jeder Browser die ihm zugedachte Seite zeigt?

55

3 Das Objektmodell 4. Übung Sie haben eine HTML-Datei, deren body so aussieht:







Sie wollen in das Textfeld des zweiten Formulars jeweils bei Klick auf einen der Buttons einen Text schreiben. Da das mit Hilfe der Funktion schreibeText() geschehen soll, haben Sie die Event-Handler, die den Aufruf der Funktion veranlassen sollen, schon mal vorsorglich eingefügt. Es fehlt noch die Funktion selbst. Schreiben Sie diese Funktion, wählen Sie aber jeweils eine andere Schreibweise, um das Textfeld anzusprechen.

3.3

Tipps

Tipp zu 2 Denken Sie bitte an das location-Objekt und dessen Eigenschaft href. Tipp zu 3 Das Image-Objekt wurde mit JavaScript 1.1 eingeführt. Tipps zu 4 Welcher Button angeklickt wurde, erkennen Sie am übergebenen Parameter. Für die Wahl der verschiedenen Schreibweisen denken Sie an Namen, Arrays und assoziative Arrays.

56

Lösungen

3.4

Lösungen

Lösung zu 1 Der Web-Browser interpretiert Ihre JavaScripts, und auf sein Objektmodell (OM) sind Sie angewiesen. Lösung zu 2 Diese Anweisung sorgt dafür, dass nach ihrer Ausführung der Wert von window. location.href den URL der zu ladenden Datei enthält und damit der Browser veranlasst wurde, diese Datei in das entsprechende Fenster (window) zu laden: window.location.href = 'andereSeite.html';

Lösung zu 3 Wir verwenden die Idee der vorherigen Übung, um weiterzuleiten, wenn der Browser über die geforderten Fähigkeiten verfügt. Wir prüfen in der Datei, die für Browser ohne oder mit zu geringen JavaScript-Fähigkeiten gedacht ist, ob document.images existiert, schließen wenn ja daraus, dass der Browser unsere Anforderungen erfüllt, und laden sofort die passende Datei.

Weiterleitung

Das ist die Seite für Browser ohne oder JavaScript oder mit etwas magerer JavaScript-Fähikeit.



Eine wichtige Anmerkung zu dieser Weiterleitung möchte ich Ihnen nicht vorenthalten: Diese Lösung zeigt das Prinzip, und sie funktioniert auch. Aber sie hat einen Nachteil: man kommt von der so geladenen Seite nicht per Back-Button weg. Probieren Sie es aus oder schauen Sie auf der CD nach, dort finden sie diese Lösung. Deswegen sollte man besser die Methode window.location.replace() benutzen, die dafür sorgt, dass die gerade aktuelle Seite nicht in die History aufgenommen wird. Leider existiert replace() aber erst seit JavaScript 1.1 Für den

57

3 Das Objektmodell Fall also, dass auch noch ältere Browser weitergeleitet werden sollen, kommt man nicht umhin, entweder die gerade gezeigte unschöne Lösung zu verwenden oder zusätzlich eine Unterscheidung einzubauen. Für unser Beispiel geht es ohne Unterscheidung; wir wollten ja ohnehin nur Browser weiterleiten, die etwas von JavaScript 1.1 verstehen. location. replace() erwartet als Parameter den URL der neuen Seite. Unser Script könnte also so aussehen:

Lösung zu 4 Diese drei Möglichkeiten, das Textfeld anzusprechen und dessen Wert zu verändern, sind mir gerade eingefallen:

58

4

Eigene Objekte Von Christine Kühnel, [email protected]

4.1

Grundlagen

Sie haben im vorangegangenen Kapitel gesehen, dass sich Ihre eigenen Variablen als Eigenschaften von window im Objektbaum wiederfinden. Damit ist die Frage nahe liegend, ob man auch eigene Objekte definieren kann. Natürlich kann man das. Im Interesse übersichtlicher, sauber strukturierter Programmierung ist es bei etwas komplexeren Aufgaben sogar sinnvoll, mit eigenen Objekten zu arbeiten.

4.1.1

Eigene Objekte definieren

Sie erinneren sich an diesesBuch und meinRoman, die Objekte aus Kapitel 3? Die wollen wir jetzt gemeinsam definieren. Zwei Dinge sind dafür erforderlich. Zunächst brauchen wir einen eigenen Objekttyp, in unserem Fall ist es das Buch. Die Aufgabe, diesen Typ zu definieren, übernimmt eine Funktion. In der Regel werden darin auch gleich die notwendigen Eigenschaften und Methoden angelegt. Außerdem benötigen wir einen Operator, der uns Instanzen, also unsere einzelnen Objekte vom Typ Buch aufbaut; dafür gibt es new, einen Operator, der ein Objekt anlegt mit Hilfe eines Konstruktors, so nennt man die Funktion, die den Objekttyp definiert. new sind Sie bereits in diesem Buch begegnet, denken Sie an

new-Operator

var meinArray = new Array();

Sie haben das Objekt meinArray angelegt, indem Sie mit Hilfe von new eine Instanz des Typs Array definiert haben. Die Funktion Array() ist z.B. so ein Konstruktor, nur mussten Sie sie nicht selbst schreiben, weil sie der Browser bereits vordefiniert enthält. Aber wir wollen jetzt eigene, dem Browser noch unbekannte Objekte definieren und müssen uns deswegen um einen geeigneten Konstruktor selbst kümmern. So könnte zum Beispiel die KonstruktorFunktion für den Objekttyp Buch aussehen:

KonstruktorFunktion

function Buch(pTitel, pVerlag, pSeiten) { this.Titel = pTitel; this.Verlag = pVerlag; this.Seiten = pSeiten; }

59

4 Eigene Objekte this-Keyword

Sie erkennen die Eigenschaften wieder, die wir bereits im vorangegangenen Kapitel betrachtet haben. Die Erklärung, was es mit this auf sich hat, bin ich Ihnen noch schuldig. this ist ein Keyword10, das immer auf das Objekt selbst weist, Sie können es auch innerhalb von Methoden jederzeit verwenden. Zusammen mit der Konstruktor-Funktion haben wir die Voraussetzungen, unsere einzelnen Objekte anzulegen, zum Beispiel: diesesBuch = new Buch(”JavaScript Workshop", ”Addison-Wesley", 300);

Als Parameter haben wir der Konstruktor-Funktion die konkreten Werte der Eigenschaften Titel, Verlag und Seiten für diesesBuch übergeben. Lassen wir uns jetzt die Werte auflisten, etwa mit

Wir erhalten eine solche Ausgabe: Das Buch »Workshop JavaScript« von »Addison-Wesley« hat ca. 300 Seiten. Objekt als Eigenschaft

Ist Ihnen aufgefallen, dass das noch gar nicht alle Eigenschaften sind, die uns an so einem Buch interessieren sollten? Richtig, der Einband fehlt. Der war insofern eine Besonderheit, dass er selbst wieder ein Objekt sein sollte. Wie geben wir dem Objekt diesesBuch eine solche Eigenschaft Einband? Sie ahnen es, wir benötigen einen Objekttyp und damit eine Konstruktor-Funktion function Einband(pFarbe, pArt) { this.Farbe = pFarbe; this.Art = pArt; }

Bevor wir uns darum kümmern, die Konstruktor-Funktion für Buch entsprechend zu ergänzen, denken wir gleich noch daran, dass wir auch eine Eigenschaft offen haben wollten, die uns sagt, ob das Buch geöffnet ist, wenn ja, auf welcher Seite es aufgeschlagen ist. Dafür bietet es sich geradezu an, einen Integer-Wert zu verwenden, man kann darin gleich die Seite unterbringen, auf der das Buch aufgeschlagen ist. 0 soll für »zugeschlagen« stehen.

10.Der englische Begriff, »Keyword«, ist in der Programmierung gebräuchlich, verzichten wir deshalb darauf, daraus ein »Schlüsselwort« zu machen.

60

Grundlagen Außerdem benötigen wir noch die Methoden für das Auf- und für das Zuschlagen. Methoden sind Referenzen auf Funktionen. Also gehen wir zunächst daran, die Funktionen zu schreiben.

Methoden sind Referenzen auf Funktionen

Was muss beim Zuschlagen passieren? Das ist nicht viel. Der Wert von offen muss lediglich auf 0 gesetzt werden: function zuschlagen() { this.offen = 0; }

Beim Aufschlagen müssen wir ein ganz klein wenig mehr tun, wir wollen ja eine bestimmte Seite erreichen. Die gewünschte Seite werden wir später beim Aufruf als Parameter übergeben: function aufschlagen(pSeite) { // erst mal nachsehen, ob es die Seite gibt if (0 < pSeite && this.Seiten 0) eval(this.options[this.selectedIndex].value)"> --- Bitte auswählen --Gruß Neues Fenster

Den Quelltext der Lösung finden Sie auf der CD unter \kapitel05\uebungen\ uebung0511.html. Lösung zu 12 Grundsätzlich ist die Gestaltung einer Funktion, die Felder eines Formulars belegt, kein Problem. Die Beispielfunktion zeigt dies mit einem Textfeld, welches mit dem aktuellen Datum gefüllt wird. // Vorbelegung function vorbelegung(formular_name) { var formular = document.forms[formular_name] var heute = new Date() formular.meinFeld.value = heute.toLocaleString() }

109

5 Formulare Die wichtigste Frage ist allerdings, wann bzw. wie diese Funktion aufgerufen wird. Man kann zum Beispiel am Ende des Dokuments die Funktion direkt aufrufen. Das ist zwar prinzipiell richtig, aber nicht ideal. Der geeignete Zeitpunkt ist der Event-Handler onLoad des HTML-Start-Tags . Er wird aktiviert, wenn das gesamte Dokument geladen ist. (Die Bilder zählen hier nicht mit, aber das ist für ein Formular auch gar nicht relevant.)

Das Formular in unserem Beispiel hat den Namen meinFormular. Den Quelltext der Lösung finden Sie auf der CD unter \kapitel05\uebungen\ uebung0512.html.

110

6

Event-Handling Von Dietmar Rabich, http://www.rabich.de, [email protected]

6.1

Grundlagen

Zwischen einem HTML-Dokument und den in diesem Dokument enthaltenen Skripten ist eine Schnittstelle erforderlich, um gerade interaktive Möglichkeiten zu nutzen. Mit Hilfe eines Links und javascript: kann eine Funktion aktiviert werden, aber das ist bei weitem nicht ausreichend. Bestimmte Funktionalitäten sind gewünscht, wenn spezielle Ereignisse eintreten. Es soll zum Beispiel ein Bild ausgetauscht werden, wenn der Mauszeiger über einen Link bewegt wird, oder ein Skript muss initialisiert werden, wenn das Dokument geladen ist. Für diese ereignisorientierten Aufgaben gibt es die Event-Handler (Event = Ereignis). Sie werden bei dem gewünschten HTML-Element (zum Beispiel einem Link) hinzugefügt – und zwar immer genau diejenigen, die gerade benötigt werden. Im Prinzip sieht der Aufruf eines Event-Handlers folgendermaßen aus:

HTML-Element und Event-Handler

Tritt bei dem durch das HTML-Element definierten Objekt das Ereignis auf, wird der zu dem Ereignis definierte JavaScript-Quelltext ausgeführt. Das HTML-Element, das Ereignis und der JavaScript-Quelltext müssen jeweils spezifiziert werden. Die Nutzung des Schlüsselworts this bezieht sich immer auf das zum HTML-Element korrespondierende JavaScript-Objekt. So besteht immer eine Zugriffsmöglichkeit auf dieses Objekt. Im Laufe der JavaScript-Versionen wurden übrigens immer mehr Event-Handler hinzugefügt bzw. waren bei immer mehr HTML-Elementen nutzbar. Die Skriptsprache bei den Event-Handlern ist nicht notwendigerweise JavaScript, auch andere Skriptsprachen sind verfügbar – allerdings bei weitem nicht so verbreitet. Trotzdem erscheint es sinnvoll, im Header des Dokuments folgende (seit HTML 4 verfügbare) Meta-Angabe aufzunehmen:

Ein besonderes Augenmerk liegt außerdem auf dem verwendeten JavaScriptQuelltext. Da es bei den Event-Handlern keine direkte Unterscheidung der JavaScript-Versionen gibt, wie sie bei dem Start-Tag

... ... ...

6.1.1

Event-Handler

Event-Handler sind reichlich vorhanden. Ein praktischer Fall für den Einsatz: Sobald ein Dokument geladen wird, soll ein zweites, kleines Fenster mit zusätzlicher Information geöffnet werden. Das Ereignis ist das Laden des Dokuments. So kommt man auf den Event-Handler onLoad, der bei dem Start-Tag ergänzt wird. Also sieht der HTML-Start-Tag folgendermaßen aus:

Um einen Überblick zu ermöglichen, sind hier erst einmal die wichtigsten Event-Handler zusammen in einer Tabelle aufgeführt. Spezielle Eigenheiten einzelner Event-Handler sind im Anschluss aufgeführt.

112

Grundlagen Event-Handler Event-Handler

Beschreibung

onAbort

Führt den JavaScript-Quelltext aus, wenn das Laden eines Bilds abgebrochen wird.

onBlur

Führt den JavaScript-Quelltext aus, wenn ein Formularelement oder das Fenster den Eingabefokus verliert.

onChange

Führt den JavaScript-Quelltext aus, wenn ein Formularelement (Select, Text, Textarea) verändert wird.

onClick

Führt den JavaScript-Quelltext aus, wenn das entsprechende Objekt angeklickt wird.

onDblClick

Führt den JavaScript-Quelltext aus, wenn auf das entsprechende Objekt ein Doppelklick ausgeführt wird.

onError

Führt den JavaScript-Quelltext aus, wenn beim Laden eines Dokuments oder eines Bilds ein Fehler aufgetreten ist – beispielsweise wenn der URL des Bilds nicht korrekt war, bei dem der Event-Handler aufgeführt ist.

onFocus

Führt den JavaScript-Quelltext aus, wenn ein Fenster, Frame, Frameset oder Formularelement den Eingabefokus erhält.

onLoad

Führt den JavaScript-Quelltext aus, wenn ein Dokument oder alle Dokumente eines Framesets geladen wurden.

onMouseDown

Führt den JavaScript-Quelltext aus, wenn eine Maustaste gedrückt wird.

onMouseOut

Führt den JavaScript-Quelltext aus, wenn der Mauszeiger das Objekt verlässt, zu dem der Event-Handler gehört.

onMouseOver

Führt den JavaScript-Quelltext aus, wenn der Mauszeiger das Objekt betritt, zu dem der Event-Handler gehört.

onMouseUp

Führt den JavaScript-Quelltext aus, wenn eine Maustaste losgelassen wird.

onReset

Führt den JavaScript-Quelltext aus, wenn ein Formular zurückgesetzt wird (Reset).

onResize

Führt den JavaScript-Quelltext aus, wenn ein Fenster oder Frame in der Größe verändert wird.

onSelect

Führt den JavaScript-Quelltext aus, wenn Text in einem Text- oder Textarea-Feld selektiert wird.

onSubmit

Führt den JavaScript-Quelltext aus, wenn ein Formular abgeschickt wird.

onUnload

Führt den JavaScript-Quelltext aus, wenn ein Dokument verlassen wird.

Tab. 6.1: Übersicht über die Event-Handler

Die Übersicht ist nicht vollständig, denn mit neueren Versionen kommen auch weitere Event-Handler hinzu und je nach Browser sind zudem proprietäre Erweiterungen vorhanden. Interessant ist jedoch noch, bei welchen HTML-Elementen die Event-Handler häufig verwendet werden und ab welcher JavaScript-Version sie verfügbar sind. 113

6 Event-Handling Event-Handler und typische HTML-Elemente Tab. 6.2: Typische HTMLElemente und JavaScript-Versionen

Event-Handler

Typische HTML-Elemente

Verfügbar seit JavaScriptVersion

onAbort

img

1.1

onBlur

input, body

1.0 1.1 (Button, Checkbox, FileUpload, Frame, Password, Radio, Reset, Submit, window)

onChange

input, select

1.0 1.1 (FileUpload)

onClick

a, input type="button", input type="submit"

1.0 1.1 (return false ist möglich)

onDblClick

a

1.2

onError

img

1.1

onFocus

input, body

1.0 1.1 (Button, Checkbox, FileUpload, Frame, Password, Radio, Reset, Submit, window) 1.2 (Layer)

onLoad

img, layer, body

1.0 1.1 (Image)

onMouseDown

input type="button", a

1.2

onMouseOut

layer, a

1.1

onMouseOver

layer, a

1.0 1.1 (Area)

onMouseUp

input type="button", a

1.2

onReset

form

1.1

onResize

body

1.2

onSelect

input type="text", tex- 1.0 tarea

onSubmit

form

1.0

onUnload

body

1.0

Auch die Liste der HTML-Elemente ist nicht vollständig. Zudem ist seit HTML 4 bei nahezu jedem HTML-Element eine größere Palette Event-Handler nutzbar. Die Liste beschränkt sich auf diejenigen HTML-Elemente, bei denen die jeweiligen Event-Handler üblicherweise auftreten.

114

Grundlagen Einige Eigenheiten von speziellen Event-Handlern sollen allerdings noch hervorgehoben werden. Zudem ist der Einsatz diverser Event-Handler im Kapitel »Formulare« beschrieben, weil diese im Zusammenhang mit Formularen relativ häufig eingesetzt werden. Event-Handler onBlur Besonders zu beachten ist, dass der Eingabefokus auch dann verloren geht, wenn ein anderes Fenster als das aktuelle Browserfenster in den Vordergrund gebracht wird. Und das kann ziemlich schnell passieren!

Event-Handler onClick Bei diesem Event-Handler ist Rückgabewert möglich. Mit diesem wird gesteuert, ob die begonnene Aktion ausgeführt werden soll oder nicht. Hier ein Beispiel: Vor dem Wechsel auf eine spezielle Seite soll nachgefragt werden, ob der Wechsel wirklich ausgeführt werden soll. Das Ereignis tritt folglich bei dem Link auf. Da auf einen Klick mit der Maus reagiert werden soll, ist der richtige EventHandler onClick. Zudem muss ein Rückgabewert berücksichtigt werden, um eventuell den Wechsel auf die andere Seite noch verhindern zu können. Dietmar Rabich's Homepage

Event-Handler onError Hauptaufgabe ist die Steuerung von Fehlern. Beispielsweise ist es mit diesem Handler möglich, ein Bild, welches nicht geladen werden kann, durch ein anderes zu ersetzen.

Event-Handler onFocus Wie bei dem Event-Handler onBlur sei hier erwähnt, dass dieses Ereignis auch außerhalb des eigentlichen Dokuments ausgelöst werden kann. Event-Handler onLoad Bei Dokumenten tritt dieses Ereignis auf, wenn das Dokument vollständig geladen ist – bei einigen wenigen Browsern leider ohne Rücksicht auf Bilder etc.!

115

6 Event-Handling Ist er bei Framesets aufgeführt, erfolgt das Ereignis, wenn alle zum Frameset gehörigen Dokumente geladen sind. Nutzt man onLoad bei Bildern, so erfolgt der Aufruf bei dem jeweiligen Tag des HTML-Elements, wenn das Bild geladen ist.

Event-Handler onMouseOut Ein wichtiges Ereignis, das auftritt, wenn zum Beispiel der Mauszeiger einen Link verlässt. Interessant ist, dass das Pärchen onMouseOut und onMouseOver nicht mit der gleichen JavaScript-Version eingeführt wurde. Auch hier ein Beispiel: Der URL zu einem Link soll in der Statuszeile nicht angezeigt werden. Stattdessen soll es ein frei wählbarer Text sein. Der richtige Ort für das Ereignis oder die Ereignisse ist der Link. Der URL wird angezeigt, wenn sich der Mauszeiger darüber befindet und sonst nicht. Wenn der Mauszeiger über den Link bewegt wird, zündet der Event-Handler onMouseOver, wird er wieder wegbewegt, ist es onMouseOut. Mein Verweis

Event-Handler onMouseOver Das Ereignis tritt zum Beispiel auf, wenn der Mauszeiger einen Link betritt. Siehe dazu auch die Beschreibung des Event-Handlers onMouseOut. Event-Handler onResize Wird ein Fenster in der Größe verändert, so erfolgt ein Aufruf des Event-Handlers onResize. Neupositionierungen von Layern o.Ä. lassen sich so automatisch veranlassen. Event-Handler onSubmit Ein wichtiger Event-Handler im Zusammenhang mit Formularprüfungen, denn er wird vor Versand von Formulardaten aufgerufen. Durch den Rückgabewert, der bei diesem Event-Handler genutzt wird, lässt sich der Versand von Formulardaten im Fehlerfall unterbinden. Event-Handler onUnload Das Gegenstück zum Event-Handler onLoad stellt dieser Handler dar. Er kann zum Beispiel genutzt werden, um eventuell geöffnete zusätzliche Fenster zu schließen.

116

Grundlagen

6.1.2

Objekttyp Image

Was wären Event-Handler, wenn man sie nicht einmal an einem praktischen Beispiel ausprobieren könnte? Der Objekttyp Image erfreut sich großer Beliebtheit, denn es ist der Objekttyp, welcher für die Buttoneffekte genutzt wird. Um einen derartigen Effekt aufzubauen, bedarf es allerdings auch geeigneter Event-Handler. Aber nun zum Objekttyp selbst. Ein Objekt vom Typ Image wird automatisch mit jedem Bild innerhalb eines Dokuments angelegt. Jedes dieser Objekte kann mit Hilfe des Arrays document.images angesprochen werden. Da sich die Indizierung der Objekte und damit die Verwendung der Nummern mit jeder Änderung der Seite verändern kann, sollte man jedem Bild, welches man ansprechen möchte, mit Hilfe des Attributs name einen Namen geben.

document.images["meinBild"]

Zusätzlich ist mit Hilfe des Konstruktors Image eine Anlage eines derartigen Objekts auch in Skripten möglich.

Neues ImageObjekt

new Image([Breite][, Höhe])

Die Breite und Höhe muss nicht unbedingt mit angegeben werden. In der Regel geschieht dies auch nicht. Noch erwähnt werden sollte, dass der Objekttyp mit den hier vorgestellten Eigenschaften mit der Version JavaScript 1.1 eingeführt wurde. Eigenschaften Die wesentliche Eigenschaft im Zusammenhang mit vielen Skripten ist src, hier aber trotzdem eine ausführlichere Liste: Eigenschaften eines Images Eigenschaft

Beschreibung

border

Breite des Rands; entspricht dem Attribut border des HTML-Elements

complete

Boole'scher Wert, der aussagt, ob ein Bild vollständig geladen wurde oder nicht.

lowsrc

URL des niedrigauflösenden Bilds; entspricht dem Attribut lowsrc des HTML-Elements und ist somit nur bei Browsern verfügbar, die auch dieses Attribut kennen

name

Name des Bilds; entspricht dem Attribut name des HTML-Elements

Tab. 6.3: Eigenschaften des Objekttyps Image

src

URL des Bilds; entspricht dem Attribut src des HTML-Elements

117

6 Event-Handling Ein neues Bild in einem Skript wird folglich so geladen: meinBild = new Image() meinBild.src = "neues_bild.gif"

Eigentlich ist der Begriff »laden« so zu verstehen, dass das Bild in den Cache des Browsers geladen wird. Ein Bild im Dokument passend zu tauschen geschieht folgendermaßen: document.images["vorhandenesBild"].src = meinBild.src

Dies setzt voraus, dass das Bild im HTML-Dokument den Namen vorhandenesBild bekam. Lädt man das Bild nicht vorab, so wird durch die dargestellte Zuweisung der Ladevorgang erst initiiert. Man »sieht« also, dass das Bild geladen wird, und eine Verzögerung stellt sich ein.

6.2

Übungen

leicht

1. Übung

Schreiben Sie ein Skript, welches Bilder vorab lädt. (Eine sinnvolle Anwendung wäre damit das Laden von Bildern zum Beispiel für eine Folgeseite. Die Zeit, in der die Seite betrachtet wird, vergeht so nicht ungenutzt.) leicht

2. Übung

Sie kennen den netten Effekt, dass sich das zu einem Link gehörige Bild ändert, wenn man den Mauszeiger über das Bild bewegt? Schreiben Sie ein solches Skript. mittel

3. Übung

Ändern Sie den Effekt aus der vorigen Übung so ab, dass ein drittes Bild erscheint, wenn man die Maustaste drückt. leicht

4. Übung

Schreiben Sie drei Funktionen, die jeweils eine Meldung liefern, wenn ein Bild geladen wurde, der Ladevorgang abgebrochen wurde oder der Ladevorgang fehlerhaft war. mittel

5. Übung

Schreiben Sie ein Skript, das eine JavaScript-gesteuerte Animation ablaufen lässt.

118

Tipps

6.3

Tipps

Tipps zu 1 왘 Vergegenwärtigen Sie sich die Möglichkeiten des Objekts Image. 왘 Suchen Sie sich ein HTML-Element und einen Event-Handler, der als Start

für die Ladefunktion dienen kann. Tipps zu 2 왘 Nutzen Sie die Erkenntnisse aus der vorigen Übung. 왘 Überlegen Sie sich geeignete Event-Handler und Stellen, an denen man sie

einbindet. Tipp zu 3 왘 Nutzen Sie wieder Erkenntnisse aus der vorigen Übung.

Tipp zu 4 왘 Überlegen Sie sich die passenden Event-Handler.

Tipps zu 5 왘 Nutzen Sie die Funktion setTimeout, um die Funktion für den Bildtausch

aufzurufen. (Die Funktion setTimeout führt den als ersten Parameter angegebenen JavaScript-Quelltext nach der als zweiten Parameter übergebenen Zeit – in Millisekunden – aus. Beispiel: setTimeout("und_los()", 5000)) 왘 Überlegen Sie sich eine Alternative zu Ihrer Lösung.

6.4

Lösungen

Lösung zu 1 Wichtig ist, sich erst einmal ein Array (oder andere geeignete Variablen) anzulegen, die die neuen Image-Objekte aufnehmen. var bilder = new Array()

Die Ladefunktion selbst besteht aus der Neuanlage eines Objekts vom Typ Image und dem Setzen einer passenden Quelle. function lade(img_name) { var anzahl_bilder

= bilder.length

119

6 Event-Handling bilder[anzahl_bilder] = new Image() bilder[anzahl_bilder].src = img_name }

Diese Ladefunktion muss für jedes Bild aufgerufen werden, welches vorab geladen werden soll, also noch eine Funktion. function vorabladen() { lade("bild1.gif") lade("bild2.jpg") lade("bild3.png") }

Diese Ladefunktion wird aktiviert, wenn das Dokument selbst geladen ist, also am besten mit dem Event-Handler onLoad bei dem HTML-Start-Tag .

Einen Gedanken sollte man noch der JavaScript-Version widmen. Insbesondere das genutzte Array ist erst ab JavaScript 1.1 verfügbar. Also muss auch das Skript mit der entsprechenden Version definiert werden. Damit es bei älteren Browsern nicht zu Problemen kommt, definiert man vor dem eigentlichen Skript eine leere Funktion mit passendem Namen. Diese wird bei passender JavaScript-Version vom folgenden Skript überschrieben.

Den Quelltext der Lösung finden Sie auf der CD unter \kapitel06\uebungen\ uebung0601.html. Lösung zu 2 Das Vorabladen kennen wir vom Prinzip her bereits aus der vorangegangenen Übung. Für jeden Button müssen zwei Bilder geladen werden, jeweils eines für den Normalzustand und eines, falls sich der Mauszeiger darüber befindet. Die Ladefunktion im Vergleich zur vorigen Lösung ein wenig abgewandelt: function button(dateiname_normal, dateiname_aktiv) { this.aktiv = new Image() this.normal = new Image() this.aktiv.src = dateiname_aktiv this.normal.src = dateiname_normal }

120

Lösungen Dazu wird eine passende Initialisierungsfunktion und das Array definiert. Das Bild in unserem Beispiel heißt übrigens meinButton. Praktischerweise wird dieser Name auch als Index für das Array genutzt. var bilder = new Array() function initialisierung() { bilder["meinButton"] = new button("bild1.gif", "bild2.gif") }

Letztlich wird bereits im Kopf des Dokuments diese Initialisierungsfunktion aufgerufen: initialisierung()

Damit ist der Ladevorgang abgeschlossen. Es fehlen noch zwei Funktionen, die helfen, das passende Bild zu setzen. Für das Bild im aktiven Zustand – also wenn sich der Mauszeiger darüber befindet – wäre das die Funktion function aktivbild(name) { document.images[name].src = bilder[name].aktiv.src }

und für das normale Bild die folgende Funktion function normalbild(name) { document.images[name].src = bilder[name].normal.src }

Neben dem Bild müssen auch die Event-Handler definiert werden. Die passenden finden sich bei dem Link: onMouseOver und onMouseOut.

Da auch hier JavaScript 1.1 Voraussetzung ist, muss darauf geachtet werden, Ersatzfunktionen für Browser mit älteren Versionen zu definieren. Bleibt vielleicht noch eine Frage zu klären: Warum wird die Funktion initialisierung diesmal nicht mit onLoad bei dem HTML-Start-Tag aufgerufen? Denken Sie einmal an den zeitlichen Ablauf. Erst wird das Dokument geladen – damit existiert auch der Link mit den Event-Handlern –, dann wird initialisiert. So könnte es passieren, dass der Link bereits genutzt wird, bevor

121

6 Event-Handling die Bilder und die JavaScript-Deklarationen dafür da sind! Mit dem Aufruf im Header werden diese Deklarationen bereits durchgeführt, bevor irgendein Bestandteil des Dokuments erscheint. Den Quelltext der Lösung finden Sie auf der CD unter \kapitel06\uebungen\ uebung0602.html. Lösung zu 3 Im Vergleich zur vorigen Übung wird erst einmal die Ladefunktion angepasst. Sie muss nun prinzipiell vier (eigentlich sogar nur drei) statt zwei Bilder laden. function button(dateiname_out, dateiname_over, dateiname_down) { this["over"] = new Image() this["out"] = new Image() this["down"] = new Image() this["up"] = new Image() this["over"].src this["out"].src this["down"].src this["up"].src

= = = =

dateiname_over dateiname_out dateiname_down dateiname_over

}

Bei der Initialisierungsfunktion ändert sich lediglich der Aufruf der gerade definierten Funktion button. bilder["meinButton"] = new button("bild1.gif", "bild2.gif", "bild3.gif")

Die Funktion, die für den Wechsel der Bilder sorgt, ist etwas allgemeiner gefasst: function bild(evnt, name) { document.images[name].src = bilder[name][evnt].src }

Letztlich ist auch der Link um zwei Event-Handler – onMouseDown und onMouseUp – zu erweitern: ...

Ansonsten gilt das, was schon bei der vorigen Übung genannt wurde.

122

Lösungen Den Quelltext der Lösung finden Sie auf der CD unter \kapitel06\uebungen\ uebung0603.html. Lösung zu 4 Die zentralen Event-Handler für diese Aufgabe sind die Event-Handler onLoad, onError und onAbort, die dem HTML-Tag des HTML-Elements hinzugefügt werden. Für die Meldung, falls das Bild erfolgreich geladen wurde, wäre das eine Funktion wie diese: function evnt_load(img) { alert("Bild" + ((img.name == "") ? "" : (" \"" + img.name + "\"")) + " geladen!") }

Im Fehlerfall sieht dies ähnlich aus: function evnt_error(img) { alert("Fehler beim Laden des Bilds" + ((img.name == "") ? "" : (" \"" + img.name + "\"")) + "!") }

Auch der Fall des abgebrochenen Ladevorgangs ist analog aufgebaut: function evnt_abort(img) { alert("Ladevorgang des Bilds" + ((img.name == "") ? "" : (" \"" + img.name + "\"")) + " abgebrochen!") }

Die Funktionen werden mit den passenden Event-Handlern aufgerufen:

Den Quelltext der Lösung finden Sie auf der CD unter \kapitel06\uebungen\ uebung0604.html. Lösung zu 5 Hier gibt es grundsätzlich zwei Lösungsansätze. Bei dem ersten wird eine Funktion per Event-Handler gestartet und danach läuft nur noch ein zeitgesteuertes Skript. Der zweite startet die Anzeige eines neuen Bilds jeweils eventgesteuert.

123

6 Event-Handling Die Bilder sollten alle die gleiche Größe haben. Allerdings muss der Dateityp nicht einheitlich sein. JPEG- oder PNG-Bilder sind ebenso wie GIF-Bilder gestattet. Beide Lösungen nutzen übrigens JavaScript 1.2-Funktionalitäten. Daher ist bei der Gestaltung der Skripte darauf zu achten, für ältere Browser Ersatzfunktionen vorzusehen. Lösungsansatz A

Der Ansatz geht davon aus, dass das Animationsskript an einer Stelle gestartet wird und dann abläuft. Dazu bietet sich der Start mit dem Event-Handler onLoad bei dem Start-Tag an. Die eigentliche Animation wird in einem Array abgelegt, jeweils mit dem Dateinamen datei, der Anzeigedauer zeit und einem Platzhalter bild für das korrespondierende Objekt vom Typ Image. function neues_bild(datei, zeit) { this.datei = datei this.zeit = zeit this.bild = null } var animation = new Array() animation[animation.length] = new neues_bild("bild1.gif", 2000) animation[animation.length] = new neues_bild("bild2.gif", 2000) animation[animation.length] = new neues_bild("bild3.gif", 2000)

Ferner wird eine globale Variable definiert, in der das aktuell angezeigte Bild gemerkt wird. var bild = -1

Die gesamte Animation wird vorab geladen, damit der Bildwechsel verzögerungsfrei erfolgt. function vorbereiten() { var i for(i = 0; i < animation.length; i++) { animation[i].bild = new Image() animation[i].bild.src = animation[i].datei } }

Die Startfunktion ist gleichzeitig die Funktion, die auch für den Bildwechsel zuständig ist. Hier wird der Bildzähler weitergezählt, das Bild ausgetauscht und

124

Lösungen am Ende die Funktion selbst wieder aufgerufen – mit dem passenden Zeitversatz. Das Bild trägt hier übrigens den Namen animation. function start() { bild++ if(bild >= animation.length) bild = 0 document.images["animation"].src = animation[bild].bild.src setTimeout("start()", animation[bild].zeit) }

Sowohl die Funktion für das Vorabladen der Bilder wie auch der Start der Animation wird mit dem Event-Handler onLoad des HTML-Elements body beim Start-Tag aktiviert.

Nicht zu vergessen, dass im HTML-Text ein Bild angelegt werden muss, damit das für das Skript notwendige Image-Objekt auch existiert:

Den Quelltext der Lösung finden Sie auf der CD unter \kapitel06\uebungen\ uebung0605a.html. Lösungsansatz B

Bei diesem Ansatz wird das Folgebild angefordert, wenn das aktuelle fertig geladen ist. Es bietet sich also wieder der Event-Handler onLoad an, diesmal allerdings eingesetzt bei dem HTML-Element . Dieser Lösungsansatz nutzt die gleichen Vorabladefunktionen wie der Lösungsansatz A. Lediglich der Bildzähler beginnt mit dem Wert 0 statt -1. var bild = 0

Die Funktion für den Bildwechsel ist in zwei Aufgabenteile getrennt. Der erste sorgt nur für den eigentlichen Wechsel: function wechsle_bild(name, nr) { document.images[name].src = animation[nr].bild.src }

Dann fehlt noch der Aufruf der gerade definierten Funktion und vorher natürlich das Weiterzählen. Der Aufruf des Folgebilds erfolgt hier zeitversetzt. function naechstes_bild(img) { bild++

125

6 Event-Handling if(bild >= animation.length) bild = 0 setTimeout("wechsle_bild('" + img.name + "'," + bild + ")", animation[bild].zeit) }

Sicherheitshalber wird die Funktion für die Vorbereitungen noch im Header aufgerufen. vorbereiten()

Das Bild für die Animation ist letztendlich noch durch den Event-Handler onLoad mit dem Aufruf der Funktion naechstes_bild zu erweitern.

Den Quelltext der Lösung finden Sie auf der CD unter \kapitel06\uebungen\ uebung0605b.html.

126

7

Fenster und Frames Von Christine Kühnel, [email protected]

7.1

Grundlagen

Spätestens bei der Verwendung von Frames fragen Sie sich sicher, ob denn Informationen zwischen Frames ausgetauscht werden können, ob auf Objekte anderer Frames zugegriffen werden kann. Sie wollen auch mal hier und da ein Fenster selbst öffnen, vielleicht sogar anschließend Beziehungen zum Ursprungsfenster herstellen. Geht das alles? Natürlich geht das.

7.1.1

Das window-Objekt

Sie haben das Objekt window bereits kennen gelernt, wissen, dass es der Repräsentant eines Fensters oder auch eines Frames ist. An diesem Objekt hängt alles, um dieses Objekt dreht sich alles, was es in diesen Zusammenhang zu sagen gibt. Wir tun deswegen gut daran, uns etwas genauer damit zu befassen.

Alles dreht sich um das windowObjekt

Werfen wir also zunächst einen Blick auf die Eigenschaften und Methoden, die wir in diesem Kapitel benötigen werden (Tabelle 7.1 und Tabelle 7.2). Eigenschaften des window-Objektes: Eigenschaft

Beschreibung

document

repräsentiert das geladene Dokument

frames

Array, das für alle enthaltenen Frames je ein window-Objekt enthält

location

enthält Information über den aktuellen URL

name

Name des Fensters bzw. Frames

opener

Fenster, welches dieses hier geöffnet hat

parent

übergeordnetes Fenster

self

Referenz auf das Fenster selbst

status

Nachricht in der Statuszeile

Top

Fenster der obersten Ebene, immer Repräsentant des tatsächlichen Browserfensters

window

window-Objekt(e) (so vorhanden)

Tab. 7.1: Eigenschaften des window-Objekts

127

7 Fenster und Frames Die Liste aller Eigenschaften ist je nach Browser wesentlich länger. Ich habe mich hier auf diejenigen beschränkt, die bei allen Browsern anzutreffen sind. Nicht erwähnte Eigenschaften sind leider zumeist browserspezifisch. In der Praxis bedeutet das: verzichten oder Unterschiede berücksichtigen. Lassen Sie sich aber deswegen keine grauen Haare wachsen; für das, was mit Fenstern und Frames am häufigsten passiert, reichen die angeführten Eigenschaften. Auch dieses Kapitel werden wir damit weitestgehend bewältigen, lediglich ganz am Ende, wenn es um Größen und Positionen geht, müssen wir an Unterschiede denken. Und dort beginnt sozusagen die Kür im Umgang mit Fenstern. Die Pflicht werden wir noch ohne das alles absolvieren können. Noch ein Wort zu self: self ist window »selbst«

Die self-Eigenschaft enthält eine Referenz auf das Fenster selbst. Das heißt, self.meineFunktion zum Beispiel ist identisch mit window.meineFunktion und self.irgendeinWert mit window.irgendeinWert. Ich benutze self gern; es ist so schön anschaulich, vom window »selbst« auszugehen. Finden Sie nicht auch?11 Methoden des window-Objektes:

Tab. 7.2: Methoden des window-Objektes

Methode

Beschreibung

Anmerkung

close()

schließt ein Fenster

moveBy()

bewegt ein Fenster um eine vorgegebene Distanz

ab MSIE4, NN4

moveTo()

bewegt ein Fenster zu einer vorgegebenen Position

ab MSIE4, NN4

open()

öffnet ein Fenster

resizeBy()

verändert die Größe um vorgegebene Werte

ab MSIE4, NN4

resizeTo()

verändert die Größe auf vorgegebene Werte

ab MSIE4, NN4

Muss ich es noch erwähnen? Auch diese Liste ist nicht vollständig. Ähnlich wie bei den Eigenschaften gibt es auch hier eine Reihe zusätzlicher browserspezifischer Methoden. Sie sehen, sogar einige der hier angegebenen kommen nicht ohne die Anmerkung aus, welche Browser sie kennen. Aber noch immer gilt: kein Grund zur Panik, erst ganz am Ende des Kapitels werden wir damit konfrontiert. Event-Handler Was fehlt uns neben Eigenschaften und Methoden des window-Objektes noch? Die Event-Handler. Wir benötigen hier nur einen: window.onload 11.Ich habe keine Idee, warum es so ist, weiß nur, dass es so ist: self wird gern mit this verwechselt. Dabei haben die beiden doch gar nichts miteinander zu tun!

128

Grundlagen In der Inline-Schreibweise im body-Tag ist er Ihnen bereits begegnet, etwa so:

Wie Sie wissen, feuert er, wenn das Dokument komplett geladen wurde. Das gilt sowohl für einfache Dokumente als auch für Framesets, bei denen bezieht sich »geladen« auf das gesamte Frameset:

7.1.2

Eigene Fenster verwenden

Jetzt aber erst einmal genug der grauen Theorie, wenden wir uns der Praxis zu, öffnen wir endlich unsere ersten eigenen Fenster. Das erledigt window.open() für uns; die allgemeine Syntax dafür sieht so aus: oNewWindow = window.open([sURL][,sName][,sFeatures]); 왘 oNewWindow legt den Namen des Objektes fest, über den Sie später Ihr

neues Fenster ansprechen können. 왘 sURL spezifiziert den URL des zu ladenden Dokuments. 왘 sName benötigen Sie, wenn das Fenster einen Namen haben soll, über den

Sie es per target in einem Link erreichen wollen. Bitte geben Sie hier Acht, sName und oNewWindow haben nichts miteinander zu tun. Das eine ist der Name, den Sie im HTML-Code verwenden können, das andere der Name Ihres Objektes in JavaScript. 왘 sFeatures gibt vor, wie das Fenster aussehen soll.

Bei sFeatures sollten wir etwas länger verweilen. Von Browser zu Browser müssen wir hier schon wieder mit Unterschieden leben. Am besten schauen wir uns das in der Übersicht in Tabelle 7.3: Parameter in window.open() an. Feature

Beschreibung

directories ={ yes | no | 1 | 0 }

Directory-Buttons

location ={ yes | no | 1 | 0 }

Adress-Zeile

menubar ={ yes | no | 1 | 0 }

Menü-Leiste

resizable ={ yes | no | 1 | 0 }

in der Größe veränderbar*

scrollbars ={ yes | no | 1 | 0 }

Scrollleisten

status ={ yes | no | 1 | 0 }

Statuszeile

Browser

Tab. 7.3: Parameter in window.open()

129

7 Fenster und Frames Feature

Beschreibung

Browser

height = number

Höhe

width = number

Breite

left = number

Abstand vom linken Bildschirmrand in Pixeln

MSIE ab4

top = number

Abstand vom oberen Bildschirmrand in Pixeln

MSIE ab4

screenX† = number

Abstand vom linken Bildschirmrand in Pixeln

NN4

ScreenY† = number

Abstand vom oberen Bildschirmrand in Pixeln

NN4

innerWidth = number

innere Breite (ersetzt width)

NN4

innerHeight = number

innere Höhe (ersetzt height)

NN4

fullscreen ={ yes | no | 1 | 0 }

Vollbildmodus, ohne jegliche Leisten

MSIE ab4

dependent ={ yes | no | 1 | 0 }

abhängiges Fenster, wird geschlossen, wenn öffnendes Fenster geschlossen wird

NN4

*Achtung: die Möglichkeit, Fenster zu minimieren bzw. zu maximieren, wird damit nicht beeinflusst †Obwohl nicht dokumentiert, zeigt die Erfahrung, dass auch NN4 left und top versteht.

Sie ahnen es, auch die Übersicht der Features ist nicht vollständig. Hier fehlen aber nur wenige, die Sie in der Praxis sicher kaum vermissen werden. Freuen Sie sich statt dessen mit mir, dass die Zahl der Übereinstimmungen recht groß ist. Wenn Sie nicht positionieren wollen oder nicht gerade vorhaben, den ohnehin nur bei MSIE ohne Weiteres möglichen Vollbildmodus zu nutzen, können Sie sogar auf jegliche Unterscheidung verzichten. Auf eines sollten Sie aber unbedingt achten: Leerzeichen zwischen den Parametern sind zum Beispiel für Netscape-Browser Fehler, sie führen in der Regel dazu, dass der Browser die Interpretation an der Stelle abbricht und für alles, was danach kommt, Standardwerte verwendet. Also gewöhnen Sie sich am besten gleich an, grundsätzlich keine Leerzeichen zu schreiben. Fenster kleiner als 100x100 können Sie nicht so ohne Weiteres öffnen. Das ist eines der Sicherheitsfeatures12 der Browser. Sowohl Microsoft als auch Netscape benutzen diese Grenze.

130

Grundlagen Jetzt wissen wir endlich genug, um unser erstes Fenster zu öffnen. Es soll fensterchen heißen (sName), 400x300 Pixel groß sein, Statuszeile und Menüleiste haben und, wenn notwendig, Scrollleisten zeigen, außerdem soll der Benutzer die Größe verändern können. Beginnen wir damit, den Parameterstring (sFeatures) in einer String-Variablen zusammenzubauen. So vorzugehen erweist sich meist als ein sehr praktisches Verfahren: var para = ''; para += 'width=400,height=300'; para += ',status=1,'; para += ',menubar=1'; para += ',scrollbars=1'; para += ',resizable=1'; para += ',toolbar=0'; para += ',location=0'; para += ',directories=0';

Diese Kombination halte ich persönlich übrigens für eine in vielen Fällen sinnvolle. Sie macht Vorgaben, lässt aber dem Benutzer noch genügend Freiheit, das Fenster seinen ganz persönlichen Wünschen anzupassen. Probieren Sie es ruhig aus, schauen Sie, ob Sie meine Meinung teilen. Mit dem so vorbereitenden String ist es nun eine Kleinigkeit, das Fenster selbst zu öffnen: neu = window.open('irgendwo.html','fensterchen',para);

Sinnvollerweise werden Sie die vorstehenden Anweisungen in einer Funktion unterbringen, um sie bei Bedarf aufrufen zu können. Fenster, die man geöffnet hat, kann man auch wieder schließen. window. close() erledigt das. Sie dürfen allerdings nicht jedes beliebige Fenster schließen. Bei Fenstern, die Sie selbst per JavaScript geöffnet haben, und solchen, deren History nur den gerade aktuellen Eintrag enthält, steht Ihnen nichts im Wege. Anderenfalls wird der Browser zuerst einmal dem Benutzer die Frage stellen, ob ihm das recht ist. Diese Sicherheitsmaßnahme hat ihre Berechtigung. Stellen Sie sich vor, Sie surfen durchs Web, klicken sich unbesorgt von Link zu Link, ohne sich den URL jeder einzelnen Seite einzuprägen. Das müssen Sie ja auch nicht, denn genau dafür gibt es die History, die Sie zu jeder besuchten Seite ganz einfach wieder zurückführt. Und nun gelangen Sie plötzlich auf eine Seite, deren Autor meint, das Fenster wäre überflüssig, macht es einfach zu. Wie würden Sie reagieren? Ich vermute, zu Jubelstürmen reißt Sie das nicht gerade hin. Aus dem Grund hat man diese Abfrage eingebaut, die solches nur 12.Es gibt Möglichkeiten, mit Hilfe erweiterter Privilegien einige der Einschränkungen aufzuheben, aber das ist ein eigenes umfangreiches, jedoch vergleichsweise wenig praxisrelevantes Thema. Deswegen konnte es in diesem Workshop nicht berücksichtigt werden.

131

7 Fenster und Frames mit Zustimmung des Benutzers zulässt. Existiert nur dieses eine Fenster, so dass window.close() auch gleich den gesamten Browser schließen würde, fragen sie in der Regel auch erst einmal nach.

7.1.3 window ist Eigenschaft von window

Beziehungen zwischen Fenstern und Frames

In der Liste der Eigenschaften haben Sie gelesen, dass window eine Eigenschaft von window sein kann. Wie das? Wir haben gerade eben mit neu = window.open(); ein Fenster geöffnet. Im Ergebnis ist jetzt neu eine Eigenschaft unseres Ursprungsfensters. Mit alert(self.neu);13

erkennen wir, dass es ein Objekt ist, genauer gesagt, ein window-Objekt. Damit haben wir auch gleich einen Weg gefunden, auf dessen Eigenschaften zuzugreifen: self.neu.Eigenschaft sollte uns das ermöglichen. Probieren wir es aus, bauen wir diesen Link in unsere Ursprungsdatei ein und klicken ihn nach dem Öffnen an:

über neu


Sie sehen, die Eigenschaften des neuen Fensters werden Ihnen der Reihe nach genannt.14 Damit ist es nun ein Leichtes für Sie, auch eventuell in diesem Fenster selbst definierte Variablen, Objekte und Funktionen zu erreichen. Ursprungsfenster erreichen über opener

Was uns noch fehlt, ist der umgekehrte Weg. Sie wollen vom neuen Fenster auf das Ursprungsfenster zugreifen. Dafür gibt es die Eigenschaft opener. Versuchen wir jetzt also, diesen umgekehrten Weg zu gehen, schreiben wir in die Datei, die in das neue Fenster geladen wird:

über neu


Es passiert, was wir erwartet haben: Wir bekommen die Eigenschaften des Ursprungsfensters nacheinander gezeigt. Haben Sie beobachtet, dass auch die Funktion oeffnen() und selbst neu dabei waren? Das war aber noch nicht alles, was es zu »window ist Eigenschaft von window« zu sagen gibt. Denken Sie bitte an Frames. Sie wissen, jeder Frame hat sein eigenes window-Objekt, gehört aber zum übergeordneten Fenster. Es sieht aus, als würde es jetzt kompliziert. Keine Sorge, es bleibt überschaubar. Man muss nur ein paar Dinge dazu wissen. 13.Voraussetzung ist natürlich, dass neu im gesamten window (global) bekannt ist, nicht etwa nur lokal innerhalb einer Funktion. 14.Komplett finden Sie das Beispiel, das wir gerade Schritt für Schritt aufgebaut haben, auf der beiliegenden CD.

132

Grundlagen Schauen wir uns ein Beispiel an, dessen Struktur Ihnen ganz sicher vertraut ist, ein Frameset mit zwei Frames.

ein Frameset





Bleiben wir zunächst auf dieser Ebene und sehen nach, welche Frames existieren. Dafür eignet sich frames[] recht gut. In dieser Collection finden wir die Frames eines Fensters wieder. Wie bereits bei anderen Collections gesehen, existiert eine Eigenschaft length, die uns die Anzahl der Elemente liefert. Da die Elemente window-Objekte sind, haben sie auch eine name-Eigenschaft. Das bedeutet, wir können den folgenden kleinen Script-Block im head unterbringen:

Nachdem der Inhalt geladen wurde, erfahren wir: frames.length : 2 frames[0].name : links frames[1].name : rechts

Die Werte der name-Eigenschaften resultieren also auch bei Frames aus nameAttributen, nämlich aus denen der frame-Tags. Diese frame-Tags sind es also, mit deren Hilfe im HTML-Code die window-Objekte definiert werden. Die Angabe numerischer Indizes in frames[] ist eine Möglichkeit, Frames anzusprechen. Wie bereits bei anderen Objekten gesehen, gibt es auch hier noch andere Wege. Sofort klar sind Ihnen sicher:

133

7 Fenster und Frames window.frames['links'] und window.links window.frames['rechts'] und window.rechts Wir haben weiter oben veranlasst, dass unsere Funktion zeigeFrames() nach dem Laden ausgeführt wird, indem wir mit window.onload = zeigeFrames; dem Event-Handler onload die Funktion zeigeFrames zugewiesen haben. Das ist zwar die eleganteste Art, aber Sie sollten daran denken, dass die alten Browser sie nicht kennen. Wenn Sie nicht ausschließen können, dass Ihre Skripte mit so einem Browser in Berührung kommen, verwenden Sie alternativ die Inline-Form:

Auf übergeordnete Fenster zugreifen

Auch hier ist die Umkehrung interessant: Wie kann man von einem Frame aus auf das »Hauptfenster« zugreifen? Auch einen Frame von einem anderen aus zu erreichen, hatte ich Ihnen versprochen. Dafür gibt es zwei Eigenschaften des window-Objektes, die uns gute Dienste leisten: top und parent.

top und parent

top weist immer auf das Fenster der obersten Ebene. parent weist auf die nächsthöhere Ebene. In unserem Beispiel sind sie identisch, aber manchmal geht es ja auch etwas verschachtelter zu. Sind gar keine Frames vorhanden, so sind beide identisch mit window selbst. Nehmen wir an, in unserem Frame links gibt es eine Variable abc und im Frame rechts eine Funktion xyz(). Dann erreichen wir die beiden zum Beispiel so: Von Frame links aus: self.abc oder einfach nur abc parent.rechts.xyz() Von Frame rechts aus: self.xyz() oder nur xyz() parent.links.abc Lassen Sie Ihrer Phantasie freien Lauf, überlegen Sie, wie man kreuz und quer referenzieren kann, wie man vielleicht zusätzlich noch von einem Frame aus geöffnete Fenster erreicht oder sogar darin enthaltene einzelne Frames. Dass das alles tatsächlich geht, ist Ihnen sicher inzwischen klar geworden. Das Prinzip ist sehr logisch, man muss nur die Strukturen ständig im Auge behalten.

7.1.4

Inhalte dynamisch generieren

Dass Sie Teile einer Seite dynamisch mit Hilfe von JavaScript generieren können, wissen Sie bereits; document.write() haben Sie schon des Öfteren benutzt. Das ist immer dann sinnvoll, wenn es Passagen gibt, die in Abhängigkeit von konkre-

134

Grundlagen ten Umständen variieren. Die entsprechenden JavaScript-Anweisungen dafür haben Sie an geeigneter Stelle in der Datei selbst untergebracht. Was aber, wenn die statischen Teile gar nicht vorhanden sind oder nicht mehr der Rede wert sind? Haben Sie schon einmal daran gedacht, ganze Seiten dynamisch aufzubauen? Das kann recht praktisch sein, Sie sparen sich eine statische Datei, die vermutlich ohnehin kaum mehr als , und enthalten würde. Dafür muss man den HTML-Code so einer physisch gar nicht existierenden Datei natürlich von »anderswo« aus aufbauen. Irgendwo müssen die dafür erforderlichen JavaScript-Anweisungen ja stehen. Wir haben gerade gesehen, dass Fenster und Frames von anderen Fenstern oder Frames aus angesprochen werden können. Was liegt also näher, als über genau diesen Weg komplette Inhalte aufzubauen? Bevor wir das nun ausprobieren, müssen wir uns noch zwei Methoden des document-Objektes ansehen: document.open() und document.close(). document.open([mimeTyp,[replace]]) öffnet einen Ausgabe-Stream. mimeTyp gibt dabei die Art der Daten an, zum Beispiel text/html für HTMLText, text/plain für ASCII-Text. replace sorgt dafür, dass kein neuer History-Eintrag erfolgt. In aller Regel ist es nicht erforderlich, Parameter anzugeben, denn text/html ist Standard, und replace braucht man nur selten. document.close() schließt den Stream ab. So ein dynamischer Aufbau hat damit immer die folgende Struktur15: Fensterreferenz.document.open(); Fensterreferenz.document.write(); Fensterreferenz.document.close();

Bitte verwechseln Sie document.open() und document.close() nicht mit window.open() und window.close(). Probieren wir es am Beispiel einer kleinen Test-Hilfe aus, lassen wir uns die Eigenschaften eines Objektes in einem neuen Fenster auflisten. Das Skript im folgenden Beispiel ist schon fast selbsterklärend, es öffnet ein Fenster, schreibt dort hinein den Code einer kompletten HTML-Datei von bis . Der eigentliche Inhalt ist eine Liste aller Eigenschaften unseres Objektes, die über for...in ermittelt wird. Beim Aufruf der Funktion zeigeObjekt() übergeben wir ganz einfach das Objekt als String, über das wir etwas erfahren wollen.

15. document.open() wird auch gelegentlich weggelassen

135

7 Fenster und Frames

zeige Objekt

Info



136

Grundlagen Warum habe ich zwei Funktionen benutzt, es ginge doch auch in einer? Ja, im Prinzip ist das richtig. Aber unter bestimmten Umständen kann es Ihnen passieren, dass die Zeit nicht ausreicht, die der Browser zum Öffnen des Fensters zur Verfügung hat. Sie erhalten eine Fehlermeldung, wenn Sie zu früh etwas hineinschreiben wollen. Deswegen bauen wir einen für uns kaum merklichen, für den Browser aber ausreichenden Zeitpuffer ein. Auf eines möchte ich noch hinweisen. Dieses einfache Skript hat einen ganz kleinen praktischen Haken: for...in funktioniert in einigen seltenen Fällen nicht 100%ig, NN3 zum Beispiel hat da schon ab und an einfach mal etwas weggelassen. Versuchen Sie, mit MSIE auf dem Weg eine leere Collection anzusprechen – navigator.mimeTypes ist so eine –, dann präsentiert er Ihnen eine Fehlermeldung. Für Testzwecke reicht es sicher, das zu wissen. Bei Skripten, die auf Rechnern der Besucher Ihrer Seiten laufen, sollten Sie sich allerdings Gedanken darüber machen, wie Fehler zu vermeiden, abzufangen und zu behandeln sind. Nutzen Sie das in Kapitel 3 über Browserunterschiede Gelernte und lesen Sie später in Kapitel 11, wie man Fehler abfangen und behandeln kann. Möchten Sie diese und ähnliche Funktionen parat haben, wenn es etwas zu testen gibt? Dann packen Sie sie einfach in eine externe JavaScript-Datei. Die ist bei Bedarf ganz schnell eingebunden.

Externe JavaScript-Dateien sind praktisch für Tests

Wünschen Sie sich solche Hilfsfunktionen zum Objektbaum Ihrer Seiten noch komfortabler? In Kapitel 9 bekommen Sie kundige Anleitung zum Basteln. Viel eleganter als externe JavaScript-Dateien sind für solche Zwecke übrigens Bookmarklets. Die kennen Sie nicht? Das sind JavaScript-Anweisungen, die man direkt als Bookmark im Browser speichert. Damit stehen sie auf jeder Seite zur Verfügung, ohne dass der Code direkt in die Datei eingebunden werden muss. Wollen Sie dies ausprobieren? Legen Sie sich einfach einmal ein Bookmark an, geben Sie lediglich anstelle des gewohnten URLs ein: javascript:alert('Hallo, ich bin ein Bookmarklet')

Was passiert, wenn Sie das Bookmark anwählen? Die Anweisung wird ausgeführt. Das ist das Prinzip – einfach und hilfreich. Mehr zum Thema Bookmarklets finden Sie auf der CD; schauen Sie bei Wolfgang Schwarz nach, er ist unter den Autoren dieses Buches der Spezialist für Bookmarklets.

7.1.5

Informationen weitergeben

Nicht immer reicht es aus, auf Fenster und deren Inhalte zuzugreifen, die zur gleichen Zeit geladen sind. Ab und an wünschen Sie sicher, Informationen an Seiten weiterzureichen, die erst später geladen werden. Dafür gibt es zwei grundlegende Herangehensweisen.

137

7 Fenster und Frames search- und hash-String benutzen Links, in denen zum Beispiel Anker angesprungen werden oder in denen Parameter mitgegeben werden, kennen Sie. So etwas ist Ihnen von daher geläufig: nach woanders

Wir machen uns zunutze, dass man Seiten so aufrufen kann. Das Link-Objekt stellt uns die Teile sogar als separate Eigenschaften zur Verfügung. Schauen wir mal, was es so alles gibt. Die weiter oben benutzte Funktion zeigeObjekt() kann uns auch dabei helfen. Konstruieren wir also zwei Links und sehen nach:

...#irgendwas
...?x=123&y=abc

Info zum ersten Link
Info zum zweiten Link



Je nach verwendetem Browser erhalten wir mehr oder weniger lange Listen der Eigenschaften unserer beiden Link-Objekte. Enthalten sind aber unabhängig vom Browser sicher document.links[0].hash=#irgendwas document.links[1].search=?x=123&y=abc

Folgen wir nun den beiden Links und sehen in der aufgerufenen Seite nach, ob die Werte in self.location wiederzufinden sind: self.location

Und siehe da, sie sind es16. Damit haben wir einen Weg gefunden, den wir beschreiten können, wenn Werte von Seite zu Seite weitergereicht werden sollen. window.name verwenden Die eben beschriebene Lösung funktioniert, aber sie hat auch ein paar kleine Nachteile. Zum Beispiel wird durch Anhängen eines search-Strings an den URL die Seite neu angefordert, eine vielleicht im Cache des Besuchers bereits vorhandene Kopie nicht genutzt.

16.Ausnahmen bestätigen auch hier die Regel. Unter file-Protokoll steht search nicht bei allen Browsern zur Verfügung, bekannt sind MSIE3 und MSIE4. Wahrscheinlich ist das kaum störend für Sie, denn unter http funktioniert es.

138

Grundlagen Schauen wir uns also noch eine andere Möglichkeit an, eine in meinen Augen viel elegantere. Die Idee besteht darin, window.name zu verwenden. Diese Eigenschaft existiert so lange, wie das Fenster selbst existiert. Eigentlich ganz einfach, nicht wahr? Man muss eben nur darauf kommen. Beschrieben wurde dieses Verfahren im März 1999 von Thomas Fischer in der Newsgroup de.comp.lang.javascript.

window.name

Wir benutzen wieder ein ganz einfaches Beispiel. Aus einer Select-Box soll der Besucher die Größe seines Wohnortes entsprechend der Einwohnerzahl heraussuchen.

Einwohnerzahlen



Wieviel Einwohner hat Ihr Wohnort?
Es sind mehr als

0 1.000 10.000 100.000 1.000.000



Die wirklich interessante Anweisung ist diese hier: window.name=pObjekt.options[pObjekt.selectedIndex].value; Der Wert von window.name wird in Abhängigkeit von der getroffenen Auswahl gesetzt. Eine andere Datei kann nun in dasselbe Fenster geladen werden, ohne dass die Information verloren geht. Versuchen wir es und greifen anschließend auf window.name zu:

139

7 Fenster und Frames

Einwohnerzahlen

Aha, Sie wohnen also in einem Ort mit

Einwohnern.



window.name bleibt auch weiterhin erhalten, Sie müssen nicht ständig »weiterreichen«, so wie das beim vorgenannten Verfahren nötig ist, wenn Sie auf die Information auch noch von weiteren Seiten aus zugreifen wollen. Ihre Besucher können zwischendurch sogar Abstecher zu anderen Seiten machen und wieder zurückkehren, sie dürfen nur das Fenster nicht schließen. Eine Einschränkung existiert allerdings. Es sind nur Ziffern, Buchstaben und der Unterstrich zulässig. Sollten Sie andere Zeichen benötigen, so müssen Sie sich etwas einfallen lassen, wie Sie sie geschickt durch zulässige ersetzen. Weil es zu weit führt, in diesem Buch auch darauf einzugehen, gestatten Sie mir, Sie auf einen Beitrag hinzuweisen, den Hatto v. Hatzfeld zu dieser Thematik für »SELFHTML aktuell« ([SELF00]) geschrieben hat. Er enthält u.a. auch eine Lösung zur Überwindung dieser kleinen Hürde: http://www.teamone.de/self aktuell/artikel/wertueb.htm.

7.1.6

Größe und Position

Kann man auch etwas über die Größe bestehender Fenster erfahren? Kann man Fenster positionieren? Kann man die Größe vorhandener Fenster verändern? Kann man Fenster verschieben? Ja, auch das ist möglich. Aber jetzt sind wir an der Stelle, an der die Einschränkungen und zum Teil auch die Unterschiede beginnen. Das alles ist ohnehin erst ab Netscape 4 bzw. Microsoft Internet Explorer 4 möglich, über ältere Browser brauchen wir also gar nicht zu reden. Und die neueren sind sich leider nicht einig, deswegen müssen wir unterscheiden. Also gehen wir die Möglichkeiten der Reihe nach an:

140

Grundlagen Position beim Öffnen vorgeben In Tabelle 7.3 haben wir gesehen, dass man dem Fenster im Parameterstring auch eine Position mitgeben kann. Zwar heißen die Vorgaben bei MS »left« und »top« und bei Netscape »screenX« und »screenY«, aber in der Praxis verstehen die Netscape-Browser, die ich kenne, auch »left« und »top«. Wollen Sie sich darauf nicht verlassen, dann bauen Sie beim Zusammenstellen der Parameter eine Browserunterscheidung ein. Darauf gehe ich hier nicht im Detail ein, denn Microsoft- und Netscape-Browser zu unterscheiden, wird Sie in Kapitel 10 ohnehin beschäftigen. Fenster verschieben, Fenstergröße ändern In Tabelle 7.2 haben wir Methoden des window-Objektes gesehen, die uns den Wunsch erfüllen, Fenstergrößen zu ändern (window.resizeBy(), window. resizeTo()) oder Fenster zu verschieben (window.moveTo(), window. moveBy()). Diese Methoden sind nicht kompliziert in ihrer Anwendung, ein paar kleine Beispiele verdeutlichen, was womit erreicht werden kann: 왘 window.resizeBy(100,-10) verbreitert das Fenster um 100 Pixel und redu-

ziert dessen Höhe um 10 Pixel 왘 window.resizeTo(300,200) setzt die Breite des Fensters auf 300 Pixel und

dessen Höhe auf 200 Pixel 왘 window.moveBy(100,-10) verschiebt das Fenster um 100 Pixel nach rechts

und um 10 Pixel nach oben 왘 window.moveTo(300,200) verschiebt das Fenster zur angegebenen Position

So, wie bereits beim Öffnen neuer Fenster, ist das Minimum auch hier 100x100, darin sind sich MS und Netscape einig. Beim Versuch, die linke obere Ecke eines Fensters auf negative Koordinaten zu schieben, reagieren sie nicht mehr so einheitlich, NN4 lässt das zum Beispiel nicht zu. Normalerweise werden Sie so etwas jedoch kaum brauchen, wenn doch, dann sollten Sie einen Blick in die jeweiligen Dokumentationen werfen und vor allem probieren. Wollen Sie wirklich vorhandene Fenster verschieben oder deren Größe ändern? Für Fenster, die Sie selbst geöffnet haben, kann das ganz nett und witzig sein. Bevor Sie sich aber an das vielleicht einzige Fenster des Besuchers wagen, denken Sie bitte sehr gründlich nach. Es könnte sein, Ihr Besucher empfindet das, was Sie für ungeheuer cool halten, als störend.

141

7 Fenster und Frames Fenstergröße erfahren Was verraten uns die Browser über Größe und Position von Fenstern? Der Navigator 4 bietet dafür window-Eigenschaften an: 왘 outerWidth / outerWidth – Außenmaße des Fensters 왘 innerWidth / innerWidth – Innenmaße des Fenster 왘 screenX / screenY – Koordinaten der linken oberen Fensterecke relativ zur

linken oberen Bildschirmecke Eine direkte Analogie dazu ist bei Microsoft-Browsern nicht zu finden. Das window-Objekt schweigt sich über all das aus. Die Innenmaße eines Fensters lassen sich dennoch ermitteln. Ich muss an dieser Stelle ein klein wenig vorgreifen, denn eigentlich gehört das, was jetzt kommt, in Kapitel 9. MSIE hat ein body-Objekt, das dem body-Element entspricht. Zwei der Eigenschaften sagen uns etwas über die Maße des Fensters: 왘 window.document.body.offsetHeight

und window.document.body.offsetWidth Da es sich um Eigenschaften von document handelt, ist ein geladenes Dokument Voraussetzung. Außenmaße und Position des Fensters bleibt uns MSIE schuldig. screen-Objekt

Will man auf dem Bildschirm genau positionieren, so ist oft dessen Größe interessant. Dafür existiert das screen-Objekt (auch erst ab MSIE 4 bzw. NN 4) mit den Eigenschaften width und height, das bedarf sicher keiner näheren Erklärung. Ein kleines Beispiel gönnen wir uns hier. Es hat zwar nicht unbedingt viel praktischen Nutzwert, ist aber anschaulich und außerdem ganz nett. Lassen wir ein Fenster hüpfen, von links oben nach rechts oben, nach rechts unten, nach links unten und immer so weiter. Für solche Spielereien öffnen wir uns ein zusätzliches Fenster:

Hopp, hopp, hopp

auf geht's

Das Hüpfen machen wir uns einfach. Wir schreiben vier Funktionen, für jede Ecke eine. Natürlich wäre es eleganter, nur eine Funktion zu verwenden, ihr jeweils zu sagen, was gerade zu tun ist. Aber wäre das auch so schön anschaulich wie in der folgenden hopphopp.html?

Hopp, hopp, hopp



7.2

Übungen

leicht

1. Übung

Schauen Sie sich bitte die Konstellation in Abbildung 7.1 an. Sie haben ein Frameset mit drei Frames: Links, Mitte und Rechts. Aus Mitte heraus haben Sie das Fenster Neu geöffnet. Das wiederum enthält die Frames Oben und Unten. Abbildung 7.1: Übung 1 Beziehungen zwischen Fenstern und Frames

Oben

)

( en

Unten

p

Links

.o w do

Mitte in

w

= eu

N

Rechts

1. Sie wollen das Fenster Neu vom Frame Unten aus schließen. Mit welcher Anweisung können Sie das erreichen? 2. Wie rufen Sie die Funktion machwas(), die sich in Links befindet, von Oben aus auf? 3. Wie ermitteln Sie von Mitte aus die Anzahl der Links in Rechts?

144

Übungen leicht

2. Übung

Wie stellen Sie fest, ob eine Datei Teil eines Framesets ist? mittel

3. Übung

Sie wollen eine kleine Galerie gleich großer Bilder präsentieren. Die Bilder sollen in einem kleinen zusätzlichen Fenster gezeigt werden. Für die Steuerung verwenden Sie bitte zwei Links: 왘 Der erste Link öffnet das Fenster und lädt eine fertige HTML-Datei, die das

erste Bild der Serie enthält. 왘 Der zweite Link sorgt dafür, dass im kleinen Fenster das vorhandene Bild

gegen das nächste ausgetauscht wird. Bitte tauschen Sie nur das Bild. Ist das letzte Bild erreicht, beginnen Sie einfach wieder von vorn. leicht

4. Übung

Welche Möglichkeiten haben Sie, Informationen von Seite zu Seite weiterzureichen? mittel

5. Übung

Eine kleine Farb-Spielerei gefällig? Lassen Sie doch mal die Hintergrundfarben für eine beliebige Anzahl von Frames zyklisch wechseln. schwer

6. Übung

Erinnern Sie sich an die Linkliste aus Kapitel 3? So richtig schön war sie noch nicht. Angewiesen darauf, für jede Form der Anzeige eine eigene Datei zu erstellen, war es nicht wirklich eine bequeme Lösung. Inzwischen wissen Sie, dass man Ausgaben auch in anderen Frames generieren kann. Das heißt, man könnte jetzt darüber nachdenken, die Liste selbst nur einmal zu laden und ganz verschiedene, sozusagen auf Knopfdruck abrufbare Anzeigefunktionen zu schreiben. 1. Wie könnte eine solche prinzipielle Lösung aussehen? Skizzieren Sie das Konzept. 2. So vorbereitet gehen wir nun daran, unsere Wünsche etwas zu präzisieren. Wir hätten gern eine ungeordnete Anzeige und eine thematisch geordnete (so ähnlich, wie wir sie bereits in Kapitel 3 realisiert haben), eine alphabetische Übersicht und eine einfache Suchfunktion.

145

7 Fenster und Frames mittel

7. Übung

Öffnen Sie ein kleines Fenster, positionieren Sie es in der linken oberen Bildschirmecke und verändern Sie die Größe schrittweise, bis sie ca. 2/3 der Bildschirmbreite und -höhe beträgt. Alle Aktionen sollen vom öffnenden Fenster aus erfolgen.

7.3

Tipps

Tipps zur 3. Übung 왘 Denken Sie daran, dass Sie auf das neue Fenster und auch auf das gela-

dene Dokument darin zugreifen können. Deswegen geben Sie dem imgElement in der Datei, die das erste Bild enthält, vorsorglich einen Namen. 왘 Die Bilder selbst, besser gesagt, deren URLs, legen Sie am besten in einem

Array ab. Das brauchen Sie dann nur zu durchwandern, um die Bilder der Reihe nach zu zeigen. Tipp zur 5. Übung 왘 Die notwendigen Funktionen bringen Sie am besten in der Datei unter, die

das Frameset enthält. Von da aus erreichen Sie bequem alle Frames, können die Hintergrundfarben auslesen und zum nächsten Frame »verschieben«. Für die Hintergrundfarbe steht der Wert in document.bgColor . Tipps zur 6. Übung 왘 Denken Sie daran, dass man komplette Seiten dynamisch aufbauen kann,

und denken Sie daran, dass solche Seiten sich in einem Frame befinden können. 왘 Sehen Sie für den Frame, der später die Ausgaben enthalten soll, zunächst

eine Dummy-Datei vor. Tipp zur 7. Übung 왘 Denken Sie daran, dass Netscape- und MS-Browser Fenstergrößen zwar mit

Hilfe derselben Methoden verändern können, die aktuelle Breite ihrer Fenster aber auf unterschiedlichen Wegen preisgeben.

146

Lösungen

7.4

Lösungen

Lösung zu 1 1. parent.close() oder top.close() 2. parent.opener.parent.Links.machwas() 3. Anzahl_der_Links = Parent.rechts.Links.length;

Lösung zu 2 Fragen Sie nach, ob das Fenster selbst identisch ist mit dem auf der obersten Ebene in der Fensterhierarchie: if (self == top) Lösung zu 3 Das hier könnte die Datei mit den beiden Links sein:

Kleine Galerie

Kleine Galerie

zeig mal die Bilder

nächstes Bild



Die Datei bilder.html könnte so aussehen:

Bilder

148

Lösungen



Lösung zu 4 Es gibt verschiedene Möglichkeiten. Zuerst ist die Frage zu stellen, ob die Seiten, zwischen denen Informationen auszutauschen sind, gleichzeitig geladen sind. Ist das mit Sicherheit der Fall, dann ist das Problem schon so gut wie gelöst. Wenn sich die Fenster untereinander »kennen«, können sie auch untereinander auf ihre Inhalte zugreifen. Sollen Informationen im Wortsinn »weitergegeben« werden, also wirklich später verfügbar sein, dann bieten sich an: search- bzw. hash-String und window.name. Lösung zu 5 Ich habe hier einmal 10 Frames benutzt17 und ganz einfach in jeden Frame dieselbe Datei geladen, es kam ja nicht auf Inhalte an, und nachträglich die Hintergrundfarben in der Funktion initia() gesetzt. Danach geht es los. faerben() wird ein wenig zeitverzögert aufgerufen, die Variable lauf zeigt an, dass der Wechsel läuft.

Famelei











In eine oder mehrere Dateien in den Einzelframes bauen wir noch eine Möglichkeit ein, das Spielchen zu stoppen. Was ist zu tun? Nicht viel. Das window mit dem Frameset enthält eine Variable lauf, nur wenn diese auf true steht, wird der nächste Farbwechselzyklus angestoßen. Also setzen wir die einfach auf false. Unsere kleine Beispieldatei farbig.html enthält dafür eine Funktion anhalten() und einen Button, mit dem sich die Funktion aufrufen lässt. Fehler vermeiden, wenn Frames fehlen

150

Weil es passieren kann, dass Dateien, die eigentlich in einen Frame gehören, auch mal einzeln geladen werden, sorgen wir dafür, dass das Fehlen von Funktionen oder Variablen in anderen Frames nicht zu lästigen Fehlern führt. Eine

Lösungen einfache Abfrage auf Existenz reicht in der Regel aus; ist irgendetwas nicht vorhanden, dann soll auch nichts passieren. Hier ist es die Variable lauf, die wir benötigen, deswegen fragen wir nach mit if(parent.lauf). Achtung! So etwas hat auch seine Tücken. Ist Ihnen aufgefallen, dass die Abfrage auch dann false liefert, wenn lauf zwar existiert, aber eben den Wert false hat? In dieser Übung macht das nichts, denn wir tun ohnehin nichts anderes als den Wert auf false zu setzen. Aber Sie sehen, man sollte kurz darüber nachdenken.





Lösung 6 Prinzip der Lösung:

Bauen wir ein Frameset mit zwei Frames. Die JavaScript-Routinen und die Daten, also das Array mit unseren Links, bringen wir am besten im Fenster der obersten Ebene unter, d.h., wir müssen sie in die Datei einbauen, in der das Frameset definiert wird. Das lässt uns die Freiheit, Frames nach Wunsch einfach zu ändern, ohne dass etwas verloren geht. Natürlich verwenden wir dafür externe JavaScript-Dateien. In einem der Frames können wir die »Knöpfe« unterbringen, auf die man nur noch drücken muss – na ja, Buttons tun es sicher auch. Der andere Frame wird die jeweils dynamisch generierte Anzeige enthalten. Ein paar zusätzliche Methoden für verschiedene Anzeigevarianten sind nach den Übungen in Kapitel 3 sicher keine Schwierigkeit mehr. Die Lösung selbst

Beginnen wir mit den Routinen zum Aufbauen der Daten und zum Ausgeben. Die packen wir alle zusammen in eine JavaScript-Datei, meine heißt

151

7 Fenster und Frames bookmark_routinen.js. Die Konstruktor-Funktion und ein paar Methoden sind Ihnen so neu nicht, sie ähneln denen, die wir bereits früher verwendet haben. So richtig neu sind die beiden Funktionen zeigeAlphabetisch() und such(). Ich werde darauf jetzt aber nicht so sehr eingehen, denn die Routinen sind nicht kompliziert, Sie verstehen sie sicher auch ohne weitere Erklärung. Für die Sortierung habe ich ein ganz einfaches Verfahren gewählt, das für diesen Zweck jedoch vollkommen ausreichend ist. Vielleicht fällt Ihnen auf, dass ich die Funktionen gar nicht als Methoden zugewiesen habe. Dann sehen Sie sich bitte die Datei mit den »Knöpfen« an. Da immer nur eine der Methoden gebraucht wird, habe ich kurz entschlossen auch nur eine im Objekt vorgesehen, nämlich zeigeEintrag. Aktuell ändere ich lediglich deren Referenz, weise die jeweils passende Funktion zu. // Konstruktorfunktion fuer Links function macheLink(pTitel, pAdresse, pAutor, pThema, pAnmerkung, pScreenshot) { this.Titel = pTitel; this.Adresse = pAdresse; this.Autor = pAutor; this.Thema = pThema; this.Anmerkung = pAnmerkung; if (pScreenshot.length > 0) this.Screenshot = pScreenshot; else this.Screenshot = 'keinbild.gif'; this.erledigt = false; this.zeigeEintrag = zeigeEintrag; } // fuegt als Methode einer Liste von Links neue hinzu function hinzufuegen(pTitel, pAdresse, pAutor, pThema, pAnmerkung, pScreenshot) { this[this.length] = new macheLink(pTitel, pAdresse, pAutor, pThema, pAnmerkung, pScreenshot); } // bereitet Ausgabe fuer einen einzelnen Eintrag vor // wird von allen anderen Ausgabefunktionen benutzt function zeigeEintrag() { var Aus = ''; Aus += ''; Aus += ''; Aus += ''; Aus += ''; this.Titel + ''; '' + this.Anmerkung + ''; '' + this.Autor + ''; ''; Aus;

}

Die folgende Funktion wird aufgerufen, wenn das komplette Frameset geladen ist, d.h., die Objekte werden angelegt, die Liste kann »mit Daten gefüllt« werden. Die Daten holen wir aus einer anderen Datei, das ist übersichtlicher und änderungsfreundlicher. Bei mir heißt sie bookmark_eintraege.js. Wir sehen sie gleich im Anschluss. /* * * legt Liste an * * */ function macheLinkliste() { // erst mal nachsehen, ob der Browser Arrays kennt if (window.Array) { // eine "Liste" fuer alle Links anlegen meineLinks = new Array(); // Methode fuer das Hinzufuegen definieren meineLinks.hinzufuegen = hinzufuegen; // Vorbereitungen sind abgeschlossen, // Daten koennen kommen Bookmarks_anlegen(); } } /* * * verschiedene Anzeigevarianten * * */ // zeigt ungeordnet function zeigeUngeordnet(wohin) { for (var i=0; i this[i+1].Titel) { fertig = false; Zw = this[i]; this[i] = this[i+1]; this[i+1] = Zw; } } } for (var i=0; i -1) || (this[i].Anmerkung.toLowerCase().indexOf(wonach) > -1)) wohin.document.writeln(this[i].zeigeEintrag()); }

154

Lösungen Datei bookmark_eintraege.js (auszugsweise): function Bookmarks_anlegen() { // einzelne Links eintragen with (meineLinks) { hinzufuegen('JavaScript-Informationen', 'http://mintert.com/javascript/', 'S. Mintert', 'JavaScript', 'Buch, Chronologie von JavaScript, Standards etc.', 'javascriptmintert.gif'); hinzufuegen('JavaScript-Notizen', 'http://netz-notizen.de/javascript', 'Ch. Kühnel', 'JavaScript', 'Beispiele, Tipps zu JavaScript und DHTML', 'javascriptnotizen.gif'); hinzufuegen('HTML 4', 'http://www.w3.org/TR/html4/', 'W3C', 'HTML', 'Spezifikation HTML 4', ''); } }

In der Frameset-Deklaration versorgen wir die beiden Frames mit Namen, dann können wir sie später leichter ansprechen. Nachdem alles geladen ist, müssen wir lediglich den Aufbau der Linkliste anstoßen, indem wir die Funktion macheLinkliste() aufrufen. Bis zu dem Augenblick sollten wir unbedingt damit warten, um sicher zu sein, dass wirklich alles da ist, was wir brauchen.

Linkliste





155

7 Fenster und Frames Was uns jetzt noch fehlt, sind lediglich die Aufrufe. Die finden wir in zu_linkliste_aufrufe.html. Hier merken wir uns geschickter Weise das Ausgabeziel in einer Variablen (wohin). Damit geben wir den Zielframe nur an dieser einen Stelle an, sind also recht flexibel, sollte uns irgendwann dieser Frame nicht mehr so recht gefallen für diesen Zweck. Alles andere ist sicher selbsterklärend. Doch nicht? Probieren Sie die Lösung von der CD! Anschauung ist auch keine schlechte Lehrmeisterin.



Meine Links

156

Lösungen


(in Thema, Autor und Anmerkung)



Lösung zu 7 Das ist eine mögliche Lösung:

Immer groesser

machauf



Die Datei, die in das kleine Fenster geladen wird, ist nicht interessant. Sie spielt selbst keine Rolle.

158

8

Cookies von Wolfgang Schwarz, [email protected]

8.1

Grundlagen

Cookies (Kekse) sind kleine Informationshäppchen, die eine Webseite auf dem Rechner des Anwenders ablegen und später wieder auslesen kann. In diesem Kapitel erfahren Sie, wie man Cookies setzt, liest und ihren Verfallszeitpunkt festlegt. Nebenbei lernen Sie noch etwas über das nützliche Date-Objekt. Die Geschichte der HTTP Cookies gehört in das große Buch der unerklärlichen psychologischen Massenphänomene, von denen die Menschheit hin und wieder heimgesucht wird. Seit ihrer Einführung durch Netscape 2 ranken sich die bizarrsten Gerüchte um die kleinen Kekse: angefangen vom Ausspionieren privater Internetgewohnheiten bis zu Angriffen auf die Windows-Registry soll mit Cookies angeblich alles möglich sein.

Cookie-Paranoia

In Wirklichkeit kann man, von gelegentlichen Browserbugs einmal abgesehen, aus Cookies nur lesen, was man selbst vorher hineingeschrieben hat, und hineinschreiben kann man nur kleine Textstücke von maximal 4 KB Größe (das sind 4000 Zeichen). Viele Online-Shops verwenden Cookies als Einkaufskorb, in dem sie festhalten, welche Artikel bereits ausgewählt wurden. Andere Seiten legen in Cookies Benutzereinstellungen ab, damit diese nicht bei jedem Besuch neu festgelegt werden müssen. Cookies lesen und schreiben Mit JavaScript finden wir die Cookies einer Seite in der Eigenschaft cookie des Objekts document:

document.cookie

document.cookie

Wenn Sie diesen Wert auslesen, erhalten Sie einen String, in dem alle für die Seite zugänglichen Cookies, durch Semikolons getrennt, als Name=Wert-Paare abgelegt sind. Ich habe zum Beispiel eben auf www.yahoo.com die Anweisung javascript:alert(document.cookie)

in die Location-Zeile meines Browsers geschrieben und diese Ausgabe bekommen: B=dmu8veh9mph4t

Interessant, nicht wahr?

159

8 Cookies Pro Domain dürfen bis zu 20 Cookies gesetzt werden. Um einen Cookie zu setzen, weist man dem cookie-Objekt einfach ein neues Name=Wert-Paar zu. Wollen Sie also beispielsweise die Information speichern, dass B derzeit dmu8veh9mph4t ist, dann schreiben Sie: document.cookie = "B=dmu8veh9mph4t";

Der Wert sollte möglichst keine Leerzeichen, Semikolons, Kommata und dergleichen enthalten. Wenn Sie solche Zeichen verwenden wollen, kodieren Sie den String mit der Funktion escape(StringMitSonderzeichen). Nach dem Auslesen erhalten Sie mit unescape(CookieString) wieder die ursprüngliche Zeichenkette. Wie Sie sehen, ist Lesen und Schreiben bei Cookies nicht symmetrisch: Schreiben können Sie immer nur einzelne Name=Wert-Paare, beim Lesen erhalten Sie aber alle Paare, die im Moment für Ihre Seite gelten. Das sind gewöhnlich alle diejenigen, die die Seite selbst oder eine in der Verzeichnishierarchie darüber liegende Seite gesetzt hat. Cookie-Parameter

Wenn Sie einen Cookie schreiben, können Sie festlegen, für welche Seiten er gelten soll, das heißt, von wo aus auf ihn zugegriffen werden darf. Dazu gibt es die Parameter path und domain: document.cookie = "Name=Wert; path=Verzeichnis; domain=Domain"

Lassen Sie diese Angaben weg, wird automatisch als path das aktuelle Verzeichnis und als domain der Hostname Ihres Servers eingetragen. Ein Beispiel: Angenommen, Sie sind Webmaster von www.greenpeace.de und setzen auf der Seite www.greenpeace.de/start.html einen Cookie mit dem Inhalt »Lieblingszahl=249.95«. Später schreiben Sie auf www.greenpeace.de/hier/dort/spaeter.html noch einen, sagen wir: »Lieblingssenf= Dijon«. Jetzt liefert document.cookie auf der Seite spaeter.html: "Lieblingszahl=249.95; Lieblingssenf=Dijon«

auf start.html aber nur: »Lieblingszahl=249.95« Um den zweiten Cookie auch auf start.html lesbar zu machen, müssen Sie beim Schreiben die path-Angabe benutzen: document.cookie = "Lieblingssenf=Dijon; path=/"

Damit der Cookie auch von Ihren anderen Servern aus gelesen werden kann, zum Beispiel von www2.greenpeace.de, verwenden Sie domain: document.cookie = "Lieblingssenf=Dijon; path=/; domain=greenpeace.de"

160

Grundlagen Aus Sicherheitsgründen können Sie übrigens nur Ihre eigene Domain angeben. Neben path und domain gibt es noch zwei weitere Attribute, die Sie beim Schreiben eines Cookies festlegen können (lesen kann man diese Parameter übrigens nicht): expires und secure. Die Angabe von secure sorgt dafür, dass der Cookie nur über sichere Verbindungen (SSL) gelesen werden darf. Der expires-Wert bestimmt den Verfallszeitpunkt des Cookies. Er sollte im Format GMT (Greenwich Mean Time) bzw. UTC (Universal Time Coordinated, der neue Name für GMT) stehen. Eine solche Zeitangabe sieht zum Beispiel so aus: Tue, 07 Nov 2084 12:00:00 GMT

Ohne eine expires-Angabe wird der Cookie beim nächsten Schließen des Browsers gelöscht. Sie können einen Cookie sofort löschen, indem Sie ihm ein in der Vergangenheit liegendes Verfallsdatum geben. Zeiten in JavaScript: Das Date-Objekt Für den Umgang mit Zeiten stellt JavaScript einen eigenen Objekttyp zur Verfügung: Date. Eine Instanz davon erzeugen Sie mit var datum = new Date();

Jede Date-Instanz repräsentiert einen bestimmten Zeitpunkt. Wenn Sie wie im obigen Beispiel keine Parameter übergeben, steht das Objekt für die Zeit, an der es erzeugt wurde. Um einen anderen Zeitpunkt darzustellen, übergeben Sie einfach das entsprechende Datum an den Konstruktor. Sie können es entweder als Zahl der Millisekunden seit dem 1. Januar 1970, 00:00 Uhr GMT angeben:

Ein Datum erzeugen

var datum = new Date(Millisekunden)

oder, wenn Sie diesen Wert gerade nicht parat haben, in etwas gewohnterer Form: var datum = new Date(Jahr, Monat, Tag, Stunden, Minuten, Sekunden, Millisekunden)

Alle diese Werte sind vom Typ Integer. Die Angabe von Stunden, Minuten, Sekunden und Millisekunden ist optional. Beachten Sie, dass die Zählung der Monate bei 0 beginnt. 0 steht also für Januar, 11 für Dezember. Wir erhalten deshalb mit var mauerfall = new Date(1989, 10, 9)

ein Objekt, das den 9. 11. 1989 repräsentiert.

161

8 Cookies Methoden von Date

Das Date-Objekt verfügt über einige recht praktische Methoden. So liefert mauerfall.getDate()

den Tag des mauerfall-Datums, also 9. Die anderen Werte bekommen Sie mit getMilliseconds(), getSeconds(), getMinutes(), getHours(), getMonth() (beim mauerfall also 10), getYear() und getDay(). Letzteres liefert den Wochentag in Form einer Zahl zwischen 0 (für Sonntag) und 6 (für Samstag). Die Implementation von getYear() ist leider bei den Browserherstellern etwas verunglückt: Internet Explorer 3, Netscape 4 und Netscape 6 liefern hier die Jahreszahl gerechnet ab 1900, also beispielsweise den Wert 102 für das Jahr 2002. Navigator 2 und 3 und Internet Explorer 4 und 5 geben dagegen für Jahre ab 2000 die vierstellige Jahreszahl zurück. Werte vor 1970 können ältere Browser überhaupt nicht darstellen. Seit JavaScript1.3 gibt es getFullYear(), was in jedem Fall die vollständige Jahreszahl zurückgeben sollte. Für die Arbeit mit Cookies sind vor allem die Methoden getTime(), setTime() und toGMTString() interessant. getTime() liefert die verstrichenen Millisekunden zwischen dem 1. Januar 1970 und dem repräsentierten Datum. Mit setTime() können Sie ein Date-Objekt im Nachhinein auf eine andere Zeit stellen. toGMTString() (seit JavaScript1.3 auch toUTCString()) schließlich gibt die Zeit im GMT- bzw. UTC-Format zurück. (Sollte es jedenfalls. Die MacIntosh-Versionen von Netscape verrechnen sich dabei jedoch um einen Tag: Sie sind immer 24 Stunden voraus.) In den Übungen werden Sie sehen, wie man die Date-Methoden für die Arbeit mit Cookies einsetzt. Alternativen zu Cookies Die Beschränkungen von Cookies liegen auf der Hand: Sie können nur relativ wenig Informationen in einem recht unflexiblen Format speichern. Wegen der teilweise fehlerhaften Umsetzung in den Browsern sollten außerdem empfindliche Daten am besten gar nicht in Cookies abgelegt werden. Dazu kommt, dass viele Leute aus Angst vor der Cookie-Attacke die entsprechenden Funktionen ihres Browsers kurzerhand abgeschaltet haben. Die sicherste Alternative zu Cookies ist die Daten serverseitig mit CGI zu speichern. Wenn Sie nur Informationen von einer Seite auf die nächste übermitteln wollen, können Sie sie auch, wie in Kapitel 7 beschrieben, als search-Parameter an den URL der aufgerufenen Seite hängen − zum Beispiel: location.href="naechsteSeite.html?B=dmu8veh9mph4t";

Auf naechsteSeite.html finden Sie dann unter window.location.search

den übergebenen String »?B=dmu8veh9mph4t«.

162

Übungen Oder Sie legen die Daten im name-Attribut des window fest. Hier bleiben sie so lange bestehen, bis der Name explizit geändert oder das Fenster geschlossen wird. Internet Explorer bietet außerdem seit Version 5 spezielle Persistenz-Techniken, die auf DHTML-Behaviors beruhen, auf die wir aber hier nicht eingehen können.

8.2

Übungen

leicht

1. Übung

Erstellen Sie eine Seite mit zwei Links. Wenn man auf den ersten Link klickt, soll ein Cookie mit dem Inhalt »Nachtisch=Kekse« gesetzt werden. Ein Klick auf den zweiten Link soll den Cookie-Inhalt in einem alert-Dialog ausgeben. Der Cookie muss nicht für längere Zeit gespeichert werden. leicht

2. Übung

Wenn Sie zwei Cookies mit demselben Namen anlegen, überschreibt der zweite den ersten. Löschen Sie den Cookie von Übung 1, indem Sie ihn nochmal setzen, diesmal aber mit einem vergangenen expires-Attribut. mittel

3. Übung

Schreiben Sie eine Funktion, die überprüft, ob der Besucher Ihrer Seite Cookies aktiviert hat. mittel

4. Übung

Einige Browser erlauben die (recht unbequeme) Option, dass jeder Versuch, einen Cookie zu setzen, eigens bestätigt werden muss. Ändern Sie die Cookietest-Funktion von Übung 3, so dass sie einen von drei Werten zurückliefert: 0 wenn Cookies deaktiviert sind, 1 wenn sie aktiviert sind und nicht bestätigt werden müssen, 2 wenn jedesmal eine Bestätigung nötig ist. mittel

5. Übung

Wie Sie wissen, liefert document.cookie oft nicht nur einen Cookie, sondern eine Liste aller Cookies, die für die Seite zugänglich sind. Schreiben Sie eine allgemein verwendbare Funktion liesCookie(), die diese Liste nach einem bestimmten Cookie durchsucht. Der Name des Cookies wird als Argument übergeben, die Funktion liefert dann den dazugehörigen Wert zurück.

163

8 Cookies mittel

6. Übung

Als Nächstes schreiben Sie eine allgemein verwendbare Funktion zum Setzen eines Cookies. Dieser Funktion werden bis zu sechs Parameter übergeben: Name, Wert, Verfallsdatum, Pfad, Domain und secure-Einstellung. Versuchen Sie auch, den MacIntosh-Bug des Netscape Navigators zu berücksichtigen: Legen Sie dazu beispielsweise mit new Date(1970,0,1,12); ein Date-Objekt an, das den Mittag des 1. 1. 1970 repräsentiert. Bei Netscape auf MacIntosh enthält dieses Datum, ins GMT-Format übertragen, eine »02«. Fragen Sie das ab und korrigieren Sie entsprechend das Datum. leicht

7. Übung

Auf einer Internetseite sollen die Besucher persönlich begrüßt werden. Dazu werden sie, wenn Cookies aktiviert sind, beim ersten Besuch nach ihrem Namen gefragt. Dieser wird in einem Cookie gespeichert und bei jedem Betreten der Seite ausgelesen und angezeigt. Erstellen Sie diese Seite. Verwenden Sie dabei die Funktionen cookie Aktiviert(), liesCookie() und schreibCookie() aus den Übungen 3, 6 und 7. schwer

8. Übung

Zum Schluss noch ein sinnvolles Anwendungsbeispiel. Schreiben Sie eine Seite, die den Besucher über alle Änderungen informiert, die sich dort seit seinem letzten Besuch zugetragen haben. Das Datum des letzten Besuchs halten Sie in einem Cookie fest − aber nur, wenn der Besucher es wünscht. Das bedeutet: Ist noch kein Cookie gesetzt, wird lediglich auf die Möglichkeit hingewiesen. Über einen Link kann der Besucher dann selbst den Cookie anlegen, wenn er möchte.

8.3

Tipps

Tipp zu 3: 왘 Setzen Sie einen Test-Cookie und versuchen Sie ihn anschließend auszule-

sen.

164

Tipps Tipps zu 4: 왘 Das Bestätigen oder Ablehnen eines Cookies nimmt eine gewisse Zeit in

Anspruch. Während dieser Zeit wird die Abarbeitung des aktuellen JavaScript-Blocks angehalten. 왘 Messen Sie die Zeit vor dem Setzen des Cookies und die Zeit nach dem Set-

zen. Errechnen Sie die Differenz (in Millisekunden) zwischen den beiden Zeiten. Daraus können Sie schließen, ob in der Zwischenzeit ein Dialogfenster erschienen ist oder nicht. Tipps zu 5: 왘 Achten Sie darauf, dass Ihre Funktion nicht in besonderen Fällen versagt.

Denken Sie beispielsweise daran, dass ein Name Teil eines anderen Namens sein kann (z.B. »mail« und »email«). 왘 Durchsuchen Sie document.cookie mit der indexOf-Methode nach der Zei-

chenkette »; übergebenerName=«. Wenn dieser String nicht im Cookie vorkommt, sehen Sie nach, ob der gesuchte Cookie vielleicht der erste in der Liste ist und deshalb kein Semikolon am Anfang hat. Wenn Sie den Namen gefunden haben, bestimmen Sie von dort aus wieder mit der indexOfMethode den dazugehörigen Wert. Tipps zu 8: 왘 Speichern Sie im Cookie die Zahl der Millisekunden seit dem letzten

Besuch. Wie könnten Sie die Seitenänderungen ablegen, so dass sie sich damit einfach nach neuen Einträgen durchsuchen lassen? 왘 Ein solcher Array würde sich anbieten:

aenderungen = new Array( new Date(2000,07,10), "- Hintergrundfarbe jetzt rot", new Date(2000,09,15), "- neue Bilder von der Katze", new Date(2001,00,05), "- Hintergrundfarbe wieder grün" );

Sie brauchen dann nur in Zweierschritten diesen Array durchgehen und jeweils den Eintrag, der das Datum der Änderung enthält (in Millisekunden seit 1970), mit dem Cookie-Datum vergleichen. 왘 Der Cookie-Wert ist ein String. Die Konstruktorfunktion Date() erwartet

aber keinen String, sondern eine Zahl. Sie müssen den Wert also umwandeln, zum Beispiel indem Sie ihn mit 1 multiplizieren. 왘 Zum Lesen und Schreiben der Cookies nehmen Sie wieder die Funktionen

schreibCookie() und liesCookie().

165

8 Cookies

8.4

Lösungen

Lösung zu 1:



setzen
lesen

Lösung zu 2: Wir erzeugen als erstes irgendein Datum in der Vergangenheit: var einst = new Date(1984, 0, 1);

formatieren es als GMT-String: var einstGMT = einst.toGMTString();

und hängen es als expires-Wert an den Cookie: document.cookie = "Nachtisch=irgendwas; expires="+einstGMT;

Lösung zu 3: function cookieAktiviert() { // Test-Cookie setzen document.cookie = "testCookie=bla"; // Cookie lesen: var keks = document.cookie // Wenn keks nicht undefiniert ist und "testCookie" // enthält, wurde der Cookie erfolgreich gesetzt: if (keks && keks.indexOf("testCookie") > -1) return true; // andernfalls werden Cookies nicht unterstützt: else return false; } // ein Test: alert(cookieAktiviert());

166

Lösungen Ab Version 4 des Internet Explorers und Version 6 von Netscape steht mit navigator.cookieEnabled auch eine vordefinierte Eigenschaft zur Verfügung, die angibt, ob Cookies aktiviert sind. Lösung zu 4: function cookieAktiviert() { // Start-Zeitpunkt festhalten var start = new Date(); // Test-Cookie setzen document.cookie = "testCookie=test"; // Die vergangene Zeit messen var jetzt = new Date(); var dauer = jetzt.getTime()-start.getTime(); // Wenn mehr als 500 ms vergangen sind, wurde ein Dialog // eingeblendet if (dauer > 500) { return 2; } else { // Cookie lesen var keks = document.cookie if (keks && keks.indexOf("testCookie") > -1) return 1; else return 0; } }

Lösung zu 5: function liesCookie(name) { var keks = document.cookie; // Anfangsposition des Name=Wert-Paars suchen var posName = keks.indexOf("; " + name + "="); if (posName == -1) { // vielleicht war's der erste Name in der Liste? if (keks.indexOf(name + "=") == 0) posName = 0; // nein? dann abbrechen mit Rückgabewert null else return null; } // Anfangs- und Endposition des Werts suchen var wertAnfang = keks.indexOf("=", posName)+1; var wertEnde = keks.indexOf(";", posName+1); if (wertEnde == -1) wertEnde = keks.length;

167

8 Cookies // Wert auslesen und zurückgeben var wert = keks.substring(wertAnfang, wertEnde); return unescape(wert); }

Lösung zu 6: // Diese Funktion korrigiert den Datums-Bug von // Netscape/Mac und liefert den korrekten GMTString: function fixedGMTString(datum){ var damals=new Date(1970,0,1,12); if (damals.toGMTString().indexOf("02")>0) { datum.setTime(datum.getTime()-1000*60*60*24); } return datum.toGMTString(); } function schreibCookie(name,wert,verfall,pfad,dom,secure) { neuerKeks = name + "=" + escape(wert); if (verfall) neuerKeks += "; expires=" + fixedGMTString(verfall); if (pfad) neuerKeks += "; path=" + path; if (dom) neuerKeks += "; domain=" + dom; if (secure) neuerKeks += "; secure"; document.cookie = neuerKeks; }

Lösung zu 7: Für die Ein- und Ausgabe des Besuchernamens gibt es verschiedene Wege. Wir wählen, besonders unelegant, prompt zur Eingabe und alert zur Ausgabe. ...

...

Überlegen Sie sich gut, ob Sie so etwas wirklich verwenden wollen. Erfahrungsgemäß sind Menschen nicht besonders glücklich darüber, wildfremden Seiten erst ihren Namen sagen zu müssen, bevor sie etwas zu sehen bekommen. Ich trage zum Beispiel in solchen Fällen nur schnell irgendwelche Buchstaben ein − bei jedem weiteren Besuch werde ich dann mit »Hallo asdfjk!« begrüßt. Lösung zu 8: Dieses Skript muss im body der Seite stehen, weil es document.write verwendet, um dynamisch ausgewählten Text zu schreiben. // Der Array mit den Änderungen aenderungen = new Array( new Date(2000,07,10), "- Hintergrundfarbe jetzt rot", new Date(2000,09,15), "- neue Bilder von der Katze", new Date(2001,00,05), "- Hintergrundfarbe wieder grün" ); function liesCookie(name) { // siehe Übung 6 } function schreibCookie(name,wert,verfall,pfad,dom,secure) { // siehe Übung 7 } // Cookie lesen var warda = liesCookie("letzterBesuch"); if (warda) { // Wenn der Cookie da ist, das entsprechende Date-Objekt // erzeugen und die Liste der Änderungen seit diesem // Datum schreiben: wardaDatum = new Date(warda*1);

169

8 Cookies var str = ''; for (i=0; i

z-index:10">

z-index:40">

z-index:20">

Wie Sie sehen, war ich faul und habe nur zwei Grafiken erstellt, die ich in verschiedene Größen skaliere. Genauso mache ich es bei den Fischen:





Jetzt müssen wir die Fische animieren. Dazu brauchen wir JavaScript.

205

9 Drei Einführungen in DHTML Es gibt zahlreiche Herangehensweisen für Animations-Effekte. Hier ein ganz einfacher Vorschlag. Im Laufe dieses und des nächsten Kapitels werden Ihnen noch elegantere Lösungen begegnen. Erst einmal halten wir die aktuelle Bewegungsrichtung unserer Fische fest: var richtung_fisch1 = "rechts"; var richtung_fisch2 = "links";

Dann brauchen wir eine Funktion, die die Fische um einen Schritt vorwärts bewegt und gegebenenfalls die Richtung wechselt: function bewegeFische(){ if (richtung_fisch1=="rechts") { // Fisch schwimmt nach rechts if (document.fisch1.left100) document.fisch1.left-=3; else { // wenden richtung_fisch1 = "rechts"; document.fisch1.document.f1.src="fischre.gif"; } } // Dasselbe fuer den zweiten Fisch: if (richtung_fisch2=="rechts") { if (document.fisch2.left0) document.fisch2.left-=2; else { richtung_fisch2 = "rechts"; document.fisch2.document.f2.src="fischre.gif"; } } }

206

Lösungen Mit setInterval rufen wir diese Funktion alle 50 Millisekunden auf: setInterval("bewegeFische()",50);

Für flüssige Bewegungen sollten Sie stets einen Zeitabstand von 30-50 Millisekunden wählen. Ein gewisses Ruckeln ist dabei leider immer noch zu erkennen. Niedrigere Werte können die Browser aber (zumindest auf Windows-Betriebssystemen) nicht verarbeiten. Nur auf MacIntosh und Unix/Linux sind wirklich weiche Bewegungsabläufe möglich. Lösung zu 12: Wir schreiben erst einmal die Layer. So sieht der erste aus:

Quadrat 1

Um die Stapelreihenfolge festzulegen, habe ich ihm neben einer Position und einer Hintergrundfarbe einen festen z-index-Wert zugewiesen. Lässt man bei einer Layer-Definition die z-index-Angabe weg, dann gibt Netscape dem Layer automatisch den z-index-Wert des zuletzt erzeugten Layers. Bei gleichem zindex-Wert liegt der zuletzt definierte Layer oben. Die anderen Quadrate sehen ähnlich aus, ich ändere einfach Namen, Position, Farbe und z-index:

Quadrat 2

Quadrat 3

Quadrat 4

207

9 Drei Einführungen in DHTML

Quadrat 5

Als Nächstes brauche ich ein Formular zur Steuerung der Stapelreihenfolge:







Jetzt fehlen nur noch die JavaScript-Funktionen. Diese sind ganz einfach: function hellhoch() { for (i=1;i-1)

auf Opera. Strategie 1: Verschiedene Seiten für verschiedene Browser Nachdem wir unsere Besucher nun in hübsche Gruppen einteilen können, müssen wir uns überlegen, was wir dort mit ihnen anfangen. Zum Beispiel könnten wir mehrere Versionen der Seite erstellen und auf der Startseite die Browser entsprechend umleiten. Das sieht dann ungefähr so aus:

BrowserUmleitung

if (document.getElementById) // W3C-kompatibel location.replace("w3cdhtml.html"); else if (document.layers) // Netscape 4 location.replace("netscape4dhtml.html"); else if (document.all) // IE4 location.replace("ie4dhtml.html"); else location.href = "nodhtml.html";

Hier werden Netscape 4, Internet Explorer 4 und W3C-kompatible Browser (sowie solche, die vorgeben W3C-kompatibel zu sein) auf eine jeweils eigene Seitenversion geschickt. Alle anderen Browser kommen, sofern sie JavaScript

225

10 DHTML: Cross-Browser-Strategien verstehen, nach nodhtml.html. Die Puristen, die kein JavaScript verstehen, bleiben einfach auf der Umleitungsseite stehen, wo wir Ihnen beispielsweise einen Link nach nodhtml.html anbieten können. Verwenden Sie für JavaScript-Umleitungen möglichst immer location.replace() und nicht location.href. Denn nur bei location.replace kommt man mit dem Back-Button des Browsers von der DHTML-Seite aus wie gewünscht zurück auf die Seite, auf der man vorher war (vgl. Kapitel 3). Browser-Umleitungen haben den Vorteil, dass Sie auf den DHTML-Seiten keine Rücksicht mehr auf Inkompatibilitäten zu nehmen brauchen. Es gibt einfach für jedes Objektmodell eine eigene Seite. Der Nachteil ist, dass Sie auf diese Weise schnell sehr viele Seiten erhalten, die sich nur schwer warten lassen. Außerdem müssen Sie zum Beispiel dafür sorgen, dass, wenn jemand einen Link auf Sie setzt, dieser immer auf die Umleitungsseite führt. Strategie 2: Verschiedene Anweisungen für verschiedene Browser Häufig ist es bequemer, nur eine einzige Seite für alle Browser zu haben. In diesem Fall ist dafür zu sorgen, dass jede Browserversion nur diejenigen SkriptBereiche zu sehen bekommt, die sie versteht. Die Puristen bereiten hier wenig Schwierigkeiten: Sie ignorieren ohnehin alle Skripte. Schwieriger wird es mit den Browsern der zweiten Gruppe, die JavaScript kennen und deshalb versuchen werden, die DHTML-Funktionen auszuführen – um dabei unweigerlich zu scheitern. Dieses Problem ließe sich im Grunde einfach lösen, indem man in allen scriptTags das Attribut language auf JavaScript1.2 setzt. Ihr Inhalt wird dann von Netscape und Internet Explorer erst ab Version 4 ausgewertet. Leider geben jedoch auch die neueren Opera-Versionen vor, JavaScript1.2 zu unterstützen, und Netscape 3 ignoriert Sprachangaben bei extern eingebundenen Skripten völlig. SkriptVerzweigung

Am besten verzweigt man deshalb in den Skript-Blöcken selbst je nach Browser auf die entsprechenden Anweisungen:

Von diesen Verzweigungen braucht man in der Praxis eine ganze Menge, denn bei DHTML kommt fast in jedem Skriptblock, in jeder Funktion zum Beispiel, etwas vor, was nicht alle Browser verstehen. Es ist deshalb üblich, am Anfang der Seite Abkürzungen anzulegen: var n4 = document.layers; var ie = document.all; var w3c = document.getElementById;

Dann sieht von da an eine Abfrage auf Netscape 4 zum Beispiel nur noch so aus: if (n4) { ... }

Am besten fangen Sie an der Stelle auch die Browser ab, die das jeweilige Objektmodell nicht ausreichend verstehen. Wenn Sie wie ich finden, Opera habe in der w3c-Kategorie nichts verloren, dann sieht die Abfrage aufs W3C DOM so aus: var w3c = (document.getElementById && (navigator.userAgent.toLowerCase().indexOf("opera")==-1)

Strategie 3: Cross-Browser-Funktionen Nehmen wir an, Sie möchten die visibility-Eigenschaft eines positionierten div-Elements ändern. Cross-Browser geht das so: if (document.getElementById) // W3C document.getElementById("divID").style.visibility = "hidden"; else if (document.layers) // Netscape 4 document.layers["divID"].visibility = "hidden"; else if (document.all) // IE 4/5 document.all["divID"].style.visibility = "hidden";

So etwas ist in Ordnung, wenn es ein- oder zweimal auf einer Seite verwendet wird. Spätestens beim zwanzigsten Wechsel von visibility werden Sie diese Vorgehensweise aber als ziemlich unhandlich empfinden. Besser wäre es, wenn man eine Funktion hätte, die die ganze Verzweigung übernimmt, und die man jedes Mal nur noch aufzurufen braucht. Wir definieren also eine Cross-Browser-Funktion verstecke(), der die ID eines positionierten Elements übergeben wird, woraufhin sie dessen visibilityEigenschaft auf "hidden" schaltet:

227

10 DHTML: Cross-Browser-Strategien function verstecke(id) { if (document.getElementById) { // W3C document.getElementById(id).style.visibility = "hidden"; } else if (document.layers) { // Netscape 4 document.layers[id].visibility = "hidden"; } else if (document.all) { // IE 4/5 document.all[id].style.visibility = "hidden"; } }

Der Vorteil dürfte einleuchten: Ist die Funktion einmal definiert, brauchen Sie nur noch verstecke("elementID") aufzurufen, um das Element mit der ID elementID unsichtbar zu machen. Die inkompatiblen Objektmodelle der einzelnen Browser brauchen Sie dabei nicht mehr zu interessieren. Cross-BrowserLibraries

Wenn Sie DHTML auf mehr als nur einer Seite einsetzen, dann können Sie sich eine Reihe allgemein verwendbarer Cross-Browser-Funktionen basteln, diese in einem externen Skript-File ablegen und auf jeder DHTML-Seite einbinden. Der Cross-Browser-Code wird durch diese Funktionen wesentlich einfacher und übersichtlicher – Browser-Verzweigungen sind auf der Seite selbst fast gar nicht mehr nötig. Wir werden im Übungsteil einige Cross-Browser-Funktionen schreiben. Fertige und umfassendere Bibliotheken finden Sie im Internet, zum Beispiel auf http://www.brainjar.com/dhtml/dhtmllib.html. Strategie 4: Cross-Browser-Objekte JavaScript ist zwar keine streng objektorientierte Sprache wie Java, aber trotzdem lässt sich damit recht gut objektorientiert programmieren. Folglich kann man statt Cross-Browser-Funktionen auch eigens erstellte Cross-BrowserObjekte verwenden. Angenommen, Sie haben einen DHTML-Newsticker auf Ihrer Seite. Dann könnten Sie einen Objekttyp Ticker definieren und für Ihren Newsticker eine Instanz dieses Typs erzeugen: newsticker = new Ticker();

Zur Steuerung des Tickers verwenden Sie Methoden, die Sie für das Objekt definiert haben, um Beispiel: newsticker.stop();

oder newsticker.richtungswechsel();

228

Grundlagen Keine Angst, wenn Ihnen das im Moment nicht allzu viel sagt. In den Übungen zu diesem Teil wird genau erklärt, wie die einzelnen Schritte funktionieren und wozu das Ganze gut ist. Auch fertige Bibliotheken mit nützlichen Cross-Browser-Objekten gibt es im Internet, etwa unter http://www.dansteinman.com/dynduo/. (Mehr und aktuellere Links finden Sie auf der Webseite zu diesem Buch: http://www.javascriptworkshop.de/.) Noch ein paar Grundregeln Die wichtigste Regel für DHTML ist wahrscheinlich: Testen. Die vorhandenen Browser enthalten in Sachen DHTML derart viele Bugs, dass Sie darauf vertrauen können, bei jeder Seite mindestens einem von ihnen zu begegnen. Wenn Sie regelmäßig Ihre Skripte testen, dann können Sie ziemlich genau herausfinden, ab wann etwas nicht mehr funktioniert und die entsprechende Stelle verändern. Andernfalls werden Sie Stunden damit verbringen, in einem 1.000-Zeilen-Code diese eine Stelle zu suchen, an der dem Browser etwas nicht gefällt.

Testen

Testen Sie mit möglichst vielen Browsern, wenn es geht auch auf verschiedenen Plattformen. Sie können ohne Weiteres mehrere Netscape-Versionen nebeneinander installieren – laden Sie sich also gleich ein paar davon herunter. Vor allem einen aus der Reihe 4.01-4.05 sollten Sie besitzen, da diese noch kein JavaScript1.3 verstehen. Leider ist es zumindest unter Windows praktisch unmöglich, mehrere Versionen des Internet Explorers gleichzeitig zu betreiben. Bevor Sie sich an die Programmierung machen, überlegen Sie sich erst einmal, wie Sie das gewünschte Ergebnis auf allen Ziel-Browsern realisieren können. Oft ist es hilfreich, dabei zuerst an Netscape 4 zu denken, denn dessen DHTML-Fähigkeiten sind in vieler Hinsicht die schwächsten. Ein Ansatz für Netscape 4 lässt sich in der Regel ohne allzu große Probleme auf Internet Explorer übertragen – anders herum geht das häufig nicht.

Nachdenken

Wollen Sie beispielsweise eine Animation erzeugen, dann könnten Sie dazu mit Internet Explorer die style-Eigenschaften eines beliebiges Elements verändern. Für Netscape 4 brauchen Sie aber einen Layer, weshalb Sie am besten von Anfang an ein positioniertes div-Element verwenden. Wenn Sie einen Ansatz für Netscape 4 und Internet Explorer gefunden haben, dann dürfte Ihnen das W3C DOM kein Kopfzerbrechen mehr bereiten: In der Regel können Sie genauso vorgehen wie beim Internet Explorer – lediglich die syntaktischen Unterschiede müssen berücksichtigt werden. Zum Beispiel heißt es beim W3C nicht document.all["elementID"], sondern document. getElementById("elementID"). Die schon bei Netscape 3 vorhandenen Collections document.images, document.forms usw. existieren übrigens im W3C DOM nach wie vor.

229

10 DHTML: Cross-Browser-Strategien

10.2

Übungen

DHTML-Übungen mit mehr Interaktion zwischen Webseite und Besucher finden Sie im Kapitel »Erweitertes Event-Handling«. leicht

1. Übung

Hier ist ein Stück aus einem HTML-Dokument:

Nichts ist besser als nichts.

Wie spricht man das Element mit der ID sohn in Netscape 4 an, wie im Internet Explorer, und wie im W3C DOM? leicht

2. Übung

Wie könnte man für alle drei Objektmodelle den sohn aus der vorigen Übung über seine clip-Eigenschaft(en) nachträglich unsichtbar machen? leicht

3. Übung

Welche Anweisungen verschieben für alle DHTML-Browser das Element vater aus Übung 3 an die Koordinaten 10/200? Nachdem dieses Skript ausgeführt wurde, wo steht dann das Element sohn? leicht

4. Übung

Nehmen wir an, Sie wollen beim Klick auf einen Link den Inhalt einer Tabellenzelle wechseln. Wie lässt sich das mit Internet Explorer und Netscape 6 erreichen? mittel

5. Übung

Gibt es zur vorigen Übung auch eine Lösung für Netscape 4? leicht

6. Übung

Schreiben Sie eine Seite, auf der stets die aktuelle Zeit im Format »Stunden:Minuten:Sekunden« angezeigt wird. Tauschen Sie dazu den Inhalt eines positionierten Elements einmal pro Sekunde durch die neue Zeit aus.

230

Übungen leicht

7. Übung

Programmieren Sie eine Funktion beschreibe(), die cross-browser den Inhalt eines positionierten Elements überschreibt. Der neue Inhalt wird als String an die Funktion übergeben, ebenso die ID des positionierten Elements. leicht

8. Übung

Wir wollen noch ein paar weitere Cross-Browser-Funktionen zusammenstellen. Schreiben Sie als Nächstes eine Funktion bewege(), die das Element mit der übergebenen ID an die ebenfalls als Parameter übergebenen Koordinaten stellt. mittel

9. Übung

Die nächste Funktion heißt schiebe(). Sie stellt ebenfalls das gewünschte Element an die gewünschte Position, allerdings nicht ruckartig, sondern in einer gleitenden Bewegung. Die Zahl der pro Schritt zurückzulegenden Pixel, also die Geschwindigkeit, wird als zusätzlicher Parameter übergeben. Wenn Sie Angst vor Zahlen haben, dann machen Sie eine Version, die das Element nur in einer Richtung verschiebt, also entweder horizontal oder vertikal. mittel

10. Übung

Die Objektmodelle von Netscape 4, Internet Explorer und W3C unterscheiden sich besonders stark beim Schreiben und Lesen der clip-Werte positionierter Elemente. Netscape 4 stellt dafür eine Reihe getrennter Eigenschaften bereit: clip.top; clip.right; clip.bottom; clip.left; clip.height; clip.width;

Beim Internet Explorer und ebenso beim W3C gibt es hingegen nur eine einzige style-Eigenschaft clip, in deren Wert, einem String, die vier clip-Kanten versteckt sind. Zum Beispiel: "rect(0px 200px 100px 10px)"

In der Praxis erweist sich das Modell von Netscape 4 meist als bequemer: String-Manipulationen sind mühsam, und die Reihenfolge der Kantenwerte bei IE und W3C (oben, rechts, unten, links) kann sich auch keiner merken. Schreiben Sie deshalb vier Cross-Browser-Funktionen zum Clippen: clipTop(), clipRight(), clipBottom() und clipLeft(). Wenn als Parameter nur die Element-ID übergeben wird, sollen diese Funktionen den aktuellen Wert der

231

10 DHTML: Cross-Browser-Strategien Kante, für die sie zuständig sind, zurückgeben. Wird hingegen zusätzlich ein weiterer Parameter übergeben, ändern sie die Kante auf den übergebenen Wert. leicht

11. Übung

Jetzt wollen wir unsere kleine Funktionsbibliothek einmal praktisch anwenden. Schreiben Sie eine Seite, deren Inhalt wie ein Filmabspann von unten nach oben über den Bildschirm läuft. Benutzen Sie dazu die Funktionen schiebe() und bewege(). Letztere brauchen Sie, um den Inhalt am Anfang an die Unterseite des Fensters zu bringen. Wie Sie die Fensterhöhe herausbekommen, erfahren Sie in Anhang 2 zu diesem Kapitel. mittel

12. Übung

Verbessern Sie die Lösung der vorigen Übung, so dass die Laufschrift erst mit 100px Abstand vom unteren Fensterrand erscheint und bereits 100px vor dem oberen Fensterrand wieder verschwindet. Das ergibt nicht nur einen hübschen Rand, es verhindert auch, dass man den Inhalt bereits vorzeitig lesen kann, indem man nach unten scrollt. Verwenden Sie weiterhin nur ein einziges positioniertes Element. mittel

13. Übung

Wir verbessern noch einmal unser Lauftext-Skript: Der Inhalt soll nun nicht mehr automatisch durchlaufen. Stattdessen stellen Sie zwei Links auf die Seite, mit denen man den Text nach oben bzw. nach unten bewegen kann. leicht

14. Übung

In den nächsten Übungen sehen wir uns an, wie man selbst definierte Objekttypen für den Cross-Browser-Einsatz anlegt. Auf den ersten Blick mag Ihnen dieser Weg, besonders wenn Sie mit objektorientierter Programmierung noch nicht so vertraut sind, vielleicht abwegig erscheinen. Für komplexe Seiten ist er aber oft die sauberste und übersichtlichste Methode. Wir werden einen Objekttyp XElement definieren, der für alle DHTML-Browser ungefähr das darstellt, was Netscape 4 durch den eingebauten Objekttyp Layer anbietet. Objekttypen definiert man durch eine Konstruktorfunktion: function XElement() { }

Wir können nun beispielsweise mit var grauschwarzeEbene = new XElement()

ein neues Objekt (eine Instanz) vom Typ XElement erzeugen.

232

Übungen Eine leere Konstruktorfunktion macht in der Regel wenig Sinn. In der Konstruktorfunktion werden wir vielmehr diejenigen Eigenschaften definieren, die alle Instanzen des Objekttyps besitzen sollen. Das sieht dann zum Beispiel so aus: function XElement() { this.x = 0; this.y = 0; }

Die Eigenschaften x und y sollen für die Koordinaten des XElements (das heißt: seine linke obere Ecke) stehen. Wie in Kapitel 4 erklärt verweist this auf die jeweils durch den Aufruf des Konstruktors erzeugte Instanz. Jede Instanz des Objekttyps XElement soll für ein bestimmtes div-Element auf der HTML-Seite stehen. Diese Elemente liegen vermutlich nicht alle in der linken oberen Ecke des Browserfensters. Wir könnten dem Konstruktor die aktuelle Position in Form von zwei Funktionsargumenten übergeben: function XElement(x, y) { this.x = x; this.y = y; } var grauschwarzeEbene = new XElement(100, 200);

Wir werden aber anders vorgehen: Der Konstruktor bekommt nur eine einzige Argumentstelle, und zwar übergeben wir ihm die ID des div-Elements. Es ist dann Aufgabe der Konstruktorfunktion, herauszufinden, an welcher Position sich das Element mit dieser ID befindet. Schreiben Sie nun diesen Konstruktor. mittel

15. Übung

Angenommen, auf einer HTML-Seite befindet sich ein positioniertes div-Element:

ein Gedanke

Mit Hilfe des Konstruktors XElement() wird ein Objekt angelegt, das dieses Element repräsentiert: var grauschwarzeEbene = new XElement("grauschwarz");

Was passiert, wenn Sie anschließend folgende JavaScript-Anweisungen aufrufen?

233

10 DHTML: Cross-Browser-Strategien alert(grauschwarzEbene.y); grauschwarzeEbene.y = 50; alert(grauschwarzeEbene.y); leicht

16. Übung

Erweitern Sie die Konstruktorfunktion XElement(), so dass sie neben der Position des Elements auch dessen Breite und Höhe sowie seinen z-index-Wert als Eigenschaften widerspiegelt. Außerdem sollen XElement-Objekte eine Eigenschaft el besitzen, die auf das HTML-Element verweist, das sie repräsentieren. Wie Sie die Breite und Höhe eines Elements herausbekommen, steht in Anhang 2. mittel

17. Übung

Es empfielt sich, neben el – der Referenz auf das repräsentierte Element selbst – noch eine Eigenschaft bereitzustellen, die auf die style-Property des Elements verweist. Nennen wir diese Eigenschaft css. Netscape 4 kennt kein style-Objekt, deshalb zeigt css hier einfach auf das Element selbst. Der Konstruktor sieht jetzt so aus: function XElement(id) { if (document.getElementById) { this.el = document.getElementById(id); this.css = this.el.style; } else if (document.all) { this.el = document.all[id]; this.css = this.el.style; } else if (document.layers) { this.el = document.layers[id]; this.css = this.el; } this.x = parseInt(this.css.left); this.y = parseInt(this.css.top); this.zIndex = this.css.zIndex; if (document.layers) { this.breite = this.el.document.width; this.hoehe = this.el.document.height; } else { this.breite = this.el.offsetWidth; this.hoehe = this.el.offsetHeight; } }

234

Übungen Bisher ist unser Cross-Browser-Objekt noch ziemlich nutzlos. Das ändert sich, wenn wir ihm jetzt ein paar Methoden verpassen. Objekt-Methoden werden genau wie Objekt-Eigenschaften definiert. Der Unterschied ist nur, dass dem Methodennamen als Wert die Referenz auf eine Funktion zugewiesen wird (also der Funktionsname ohne Klammern, vgl. Kapitel 4). Mit Hilfe von Methoden lösen wir die Schwierigkeit, der wir in Übung 15 begegneten. Sie erinnern sich: Die Änderung von XElement-Eigenschaften wirken sich nicht auf das repräsentierte HTML-Element aus. Geben Sie dem Objekttyp XElement eine Methode gehNach(x,y), die das HTML-Element an die übergebenen Koordinaten stellt. Die x- und y-Eigenschaften des XElement-Objekts sollen natürlich dabei auch aktualisiert werden. leicht

18. Übung

Mittlerweile sollte Ihnen dämmern, wozu Cross-Browser-Objekttypen gut sein können: Immer wenn Sie ein positioniertes Element definiert haben, das Sie hin- und herbewegen wollen, brauchen Sie nur eine entsprechende Instanz von XElement zu erzeugen und können dann dessen gehNach()-Methode benutzen, ohne sich um die drei verschiedenen Objektmodelle Gedanken zu machen. Und sollte demnächst zur allgemeinen Freude noch ein viertes Objektmodell auftauchen, dann brauchen Sie nur den Konstruktor XElement() zu verändern. Die konkreten Anwendungen bleiben, solange sie nur die Objektmethoden einsetzen, unberührt. Im Gegensatz zu Cross-Browser-Funktionen sind außerdem zusammengehörige Variablen und Funktionen auch ordentlich zusammen abgelegt. Erweitern Sie XElement noch um zwei weitere Methoden: zeige() und verstecke(). mittel

19. Übung

Als erste Anwendung des Cross-Browser-Objekttyps XElement lassen wir es nun regnen. Schreiben Sie eine Webseite mit 50 kleinen, grauen, länglichen Layern: die Regentropfen. Jeder Regentropfen wird durch ein eigenes XElement repräsentiert. Regentropfen fallen, wie Sie wissen, gewöhnlich von oben nach unten. Wenn sie am unteren Fensterrand angekommen sind, stellen Sie sie wieder nach ganz oben. Die horizontale Position überlassen Sie am besten dem Zufall. schwer

20. Übung

Setzen Sie XElement() jetzt ein, um das nicht besonders originelle, aber vermutlich beliebteste DHTML-Skript zu erstellen: Ein Menü, das ähnlich wie die Dateimanager vieler Betriebssysteme beim Klick auf einen Hauptpunkt eine Reihe von Unterpunkten einblendet und bei erneutem Klick wieder ausblendet.

235

10 DHTML: Cross-Browser-Strategien Ihr Menü braucht nur eine Untermenütiefe zu unterstützen, das heißt, Sie können annehmen, dass keine Unterpunkte im Menü vorgesehen sind, die selbst wieder Unterunterpunkte einblenden. schwer

21. Übung

Entwickeln Sie einen neuen Objekttyp KlappMenu, der ein ganzes Menü von der Art, wie wir es in der letzten Übung gebaut haben, repräsentiert. Im Unterschied zu XElement() erzeugt der KlappMenu-Konstruktor selbst die Elemente, die er repräsentiert. Das bedeutet: Im Konstruktor wird mit document.write der HTML-Quelltext des Menüs geschrieben. Objekte vom Typ KlappMenu müssen deshalb erzeugt werden, noch bevor die Seite fertig gerendert ist. Dem Konstruktor werden neben der Position des Menüs zwei Arrays übergeben: eine Liste mit den Hauptmenü-Punkten und eine mit den Untermenüs. Die Elemente des zweiten Arrays sind also selbst wieder Arrays, sie enthalten die Namen der Untermenü-Punkte und den dazugehörenden URL. Ein Aufruf könnte also wie folgt aussehen:

...

Diese Anweisungen sollen ausreichen, um das gewünschte Menü, voll funktionsfähig, an der gewünschten Position auf der Seite erscheinen zu lassen. mittel

22. Übung

Eines haben wir bislang sowohl bei den Cross-Browser-Funktionen als auch bei den Methoden von XElement übersehen: Layer können ineinander verschachtelt sein:



236

Übungen Hier liegt für Netscape 4 das eine positionierte div-Element im document des andern. Wenn wir die ID tochter an den XElement-Konstruktor oder eine der Cross-Browser-Funktionen übergeben, erhielten wir eine Fehlermeldung, denn document.layers["tochter"]

existiert nicht. Die korrekte Referenz wäre zum Beispiel: document.layers["mutter"].document.layers["tochter"].

Wie könnte man diese Schwierigkeit umgehen? leicht

23. Übung

Viele der in diesem Kapitel vorgestellten Lösungen führen auf DHTML-unkundigen Browsern zu Fehlermeldungen. Zum Abschluss deshalb noch zwei Aufgaben zum Umgang mit solchen Besuchern. Häufig legt man, besonders bei komplexen Auftritten, neben der DHTML-Seite eine Alternativseite für alle die Browser an, die kein DHTML beherrschen. Es handelt sich dabei meist um eine einfache HTML-Seite, die die wichtigsten Inhalte und Links des Angebots zusammenfasst. (Bei Angeboten ohne Inhalt enthält sie folgerichtig nur den Hinweis, dass man den falschen Browser verwendet.) Schreiben Sie eine Browser-Umleitung, die Netscape ab Version 4 und die Windows-Versionen von Internet Explorer 4 und 5 zur DHTML-Seite schickt, alle anderen dagegen auf die Alternativ-Seite. Überlegen Sie sich, ob man auch Browser, die kein JavaScript verstehen, direkt zur Alternativseite bringen könnte (und wenn ja, wie). mittel

24. Übung

Würden Sie für jede Browserversion eine eigene Seite schreiben, dann hätten Sie am Ende etwa 200 Versionen, die bei jeder Änderung alle überarbeitet werden müssen. Am schönsten wäre es deshalb, eine einzige Seite für alle zu haben. Die DHTML-Seite sollte also am besten auch mit Browsern betrachtet werden können, die kein DHTML oder sogar kein JavaScript verstehen. Ob das möglich ist, müssen Sie im Einzelfall selbst entscheiden. Bei der folgenden Seite ist es möglich. Allerdings muss dazu der Quelltext etwas umgebaut werden. Versuchen Sie es.





eins
zwei
drei


test



Vielleicht fallen Ihnen diese Zeilen in der init()-Funktion auf: if (testDiv.captureEvents) { // Netscape 4 testDiv.captureEvents(Event.MOUSEDOWN); document.captureEvents(Event.MOUSEMOVE | Event.MOUSEUP); } testDiv.onmousedown = mdown; testDiv.onmouseup = mup; document.onmousemove = mmove;

305

11 Erweitertes Event-Handling Anders als in den vorherigen Übungen setze ich captureEvents() nur bei Netscape 4, nicht aber bei Netscape 6 ein. Warum? Weil captureEvents() ausschließlich eine Methode von window-, document- und layer-Objekten ist. testDiv wird von Netscape 4 als Layer angesehen. Netscape 6 kennt aber keine Layer, weshalb er beim Versuch, auf testDiv die Methode captureEvents() anzuwenden, einen Fehler bringen würde. Man kann auf captureEvents() für Netscape 6 ruhig verzichten, weil dieser wie Internet Explorer Event-Bubbling unterstützt. Wenn Sie Schwierigkeiten beim »einfachen« Drag&Drop hatten, dann kopieren Sie sich die Lösung und versuchen Sie jetzt, sie so weiter zu entwickeln, dass sie universell einsetzbar wird. (Auf der CD finden Sie das oben abgedruckte Skript im Verzeichnis »sonstiges« als »dragndrop.html«). Hier ist die fertige Lösung:

Was noch fehlt, ist die Speicherung des Layouts in einem Cookie. Mit Hilfe der Cookie-Funktionen aus Kapitel 8 ist das gar nicht so schwierig. Zuerst ergänzen wir die Funktion mup() so, dass bei jedem Mouseup-Event die aktuellen div-Positionen in den Cookie geschrieben werden. Dazu gehen wir den Array divs[] durch, fragen die Koordinaten ab und hängen sie zusammen an einen String. Aus diesem String müssen wir später die Koordinaten wieder rekonstruieren können, deshalb stellen wir zwischen zwei zusammengehörige x/y-Werte jeweils ein Komma und trennen sie vom nächsten Wertpaar mit einem Plus-Zeichen: function mup(e){ drag = "inaktiv"; // Cookie-String zusammenstellen: var cookieString = ""; for (i=0; igetJavaEnv(); jref j =(jref)register_myWrapper(env); myWrapper *p =(myWrapper *)j; p->myConnection( env, (java_lang_String *)sCmd, (java_lang_String *)sParam );

Beachten Sie, dass sich nicht jedes ActiveX-Objekt zur Einbettung in HTML-Seiten eignet. Dazu muss es mit speziellen Interfaces ausgestattet sein. Erkennung von Plug-ins Unter Umständen kann es nötig werden, in einer HTML-Seite die Existenz eines Plug-ins zu erfragen. Möglicherweise möchten Sie den Benutzer Ihrer Site darauf hinweisen oder ihm die Wahlmöglichkeit zwischen einer »normalen«

336

Grundlagen Abbildung 12.3: Plug-in/JavaScriptKommunikation im Internet Explorer

und einer Plug-in-Repräsentation geben. Von einer automatisierten Weiterleitung in Abhängigkeit von der Installation des Plug-ins sollten Sie jedoch absehen. Der Benutzer weiß selbst am besten, ob er eine geflashte Version Ihrer Website sehen möchte oder nicht. Wie gehen wir nun vor, um herauszufinden, ob ein bestimmtes Plug-in installiert ist oder nicht? Auch an dieser Stelle müssen wir als JavaScript-Entwickler auf die unterschiedlichen Ansätze der Browser-Hersteller eingehen. Im Netscape Navigator können wir auf das Array navigator.plugins[] zugreifen. In Übung 14 wird der Umgang damit detailliert besprochen.

navigator.plugins[]

Jeder Array-Eintrag enthält ein Objekt vom Typ Plugin, das unter anderem die Property name hat, die auch als Array-Index verwendet werden kann:

337

12 LiveConnect about:plugins

Dazu muss natürlich der Name des zu testenden Plug-ins bekannt sein. Durch die Eingabe des URLs about:plugins finden Sie ihn heraus. Im Internet Explorer müssen wir anders vorgehen, denn dort ist navigator. plugins[] immer leer. Außerdem existiert in seinem DOM auch keine andere direkte Repräsentation der installierten Plug-ins. Mit einigen VBScript-Funktionen kommen wir jedoch an die gewünschten Informationen:

CreateObject, Err

OLE/COM Viewer

Abbildung 12.4: OLE/COM Viewer: Shockwave Flash

338

Die Funktion CreateObject(sProgID) benötigt einen Parameter vom Typ String, der das Plug-in identifiziert. Diesen sollten Sie in der Dokumentation des Herstellers finden. Sie können aber auch z.B. mit Werkzeugen wie dem OLE/COM Viewer arbeiten, einem Tool aus der Entwicklungsumgebung Visual Studio von Microsoft.

Grundlagen

12.1.3

Vergleich von Applets und Plug-ins

Wir wollen nun einmal Java-Applets und Plug-ins gegenüberstellen, und zwar in Bezug auf Handling, Plattformunabhängigkeit, Performance, Sicherheit und Restriktionen. Fangen wir an mit dem ... Handling Applets werden über das HTML-Element applet, Plug-ins je nach Browser über embed oder object eingebettet. Der Aufwand hierfür hält sich in etwa die Waage.

HTML

Anspruchsvolle Applets bestehen in der Regel aus einer Vielzahl von .classDateien, die alle bei jedem Laden der einbettenden HTML-Seite immer wieder geladen werden müssen. Ein wenig Abhilfe schafft hier der Einsatz eines JARs, in dem mehrere .class-Dateien zusammengefasst werden können. In beiden Fällen können die benötigte(n) Datei(en) im Cache des Browsers zwischengespeichert werden. Da die Cache-Konfiguration aber willkürlich ist und der Cache jederzeit manuell geleert werden kann, kann man sich nicht darauf verlassen, dass sich das Applet im Cache befindet.

Installation

Plug-ins hingegen werden genau einmal heruntergeladen und installiert. Dies geschieht in der Regel im Internet Explorer automatisch und im Netscape Navigator halbautomatisch durch Anzeige eines Download-URLs, unter dem das Setup des Plug-ins heruntergeladen werden kann. Im Internet Explorer bürgt der Anbieter durch den Einsatz einer digitalen Signatur mit einem starken asymmetrischen Verschlüsselungsverfahren für die Echtheit seiner Software. Auch im Navigator gibt es einen solchen automatischen Download-Mechanismus namens SmartUpdate, der aber selbst bei Entwicklern wenig bekannt ist und daher eher selten verwendet wird.

SmartUpdate

Was nützt das schönste Applet oder Plug-in, wenn es keine Daten zum Anzeigen hat? Hier gibt es keinen Unterschied, denn sowohl Applets als auch Plugins müssen ihre Daten zunächst einmal aus dem Netz laden. Beide können dabei auf den Browser-Cache hoffen, doch Plug-ins können ihre Daten grundsätzlich auch selbst auf der Festplatte cachen, um einen Mehrfach-Download zu vermeiden.

Download

Plattformunabhängigkeit Hier haben Applets ganz klar die Nase vorn, da sie auf der Sprache Java aufbauen, die grundlegend als plattformunabhängig konzipiert wurde. Bei Plug-ins muss man berücksichtigen, dass der Netscape Navigator für viele Plattformen, der Internet Explorer in vollem Umfang »nur« auf Windows-Plattformen verfügbar ist. Bedenken Sie weiterhin, dass ein Hersteller von Plug-ins für den Netscape Navigator auch eine eigene Version seiner Software für jedes Betriebssystem anfertigen muss. Bei Betriebssystemen mit geringem Marktanteil ist dies wirtschaftlich nicht immer sinnvoll.

339

12 LiveConnect Performance In dieser Rubrik erweist sich der Vorteil der Plattformunabhängigkeit von JavaApplets ganz klar als Nachteil. Durch die Verwendung der JVM ergibt sich ein spürbarer Geschwindigkeitsverlust im Vergleich zu nativem Objektcode. Dies wird insbesondere bei grafisch anspruchsvollen Anwendungen wie der Wiedergabe von Videos oder 3-D-Welten deutlich. Auch Just-In-Time (JIT) Compiler, die teilweise in den JVMs der Browser zum Einsatz kommen, schaffen hier keine Abhilfe. Plug-ins hingegen können bei Bedarf sogar auf hochoptimierte Assemblerroutinen und direkt auf spezielle Dienste des Betriebssystems zurückgreifen. Stellen Sie sich einmal die Frage, warum die Hersteller von Top-Computerspielen den Vorteil der Plattformunabhängigkeit der Sprache Java ignorieren und sich auf spezielle Plattformen wie Windows PC oder die Playstation beschränken! Sicherheit Um es kurz zu machen: Java-Applets unterliegen einem Sicherheitsmechanismus, Plug-ins nicht. »Nieder mit den Plug-ins!« werden Sie nun laut ausrufen. Denken Sie zuvor aber noch kurz nach. Security Manager

Bei Applets ist ein Sicherheitsmechanismus bitter nötig, da diese beim Laden einer HTML-Seite sofort in Aktion treten und so im Zweifelsfall Schaden auf Ihrem System anrichten könnten. Damit dies nicht geschieht, dürfen Applets bestimmte Befehle der Sprache Java nicht ausführen. Der Security Manager des Browsers entscheidet, welche Befehle ausgeführt werden dürfen und welche nicht. Die Entscheidung findet also erst zur Laufzeit des Applets statt, nicht während der Entwicklungszeit. Plug-ins hingegen müssen zunächst einmal auf Ihr System geladen und danach installiert werden. Dies geschieht nie ohne Ihre ausdrückliche Zustimmung, unabhängig davon, ob der Installationsprozess nun automatisch oder manuell erfolgt. Allerdings ist es richtig, dass Plug-ins nach der Installation im Gegensatz zu Applets grundsätzlich vollen Systemzugriff haben. Hier gilt für Plug-ins das Gleiche wie für jede andere Software, die Sie aus dem Netz laden oder von CD-ROM installieren: Sie vertrauen dem Hersteller und stimmen vor der Nutzung dem End User License Agreement (EULA) zu. Restriktionen Eine direkte Folge von Sicherheitsmechanismen sind funktionelle Beschränkungen der Software. Applets unterliegen einer ganzen Reihe solcher Restriktionen. Der Zugriff auf das lokale Dateisystem ist ebenso verboten wie die Errichtung von Netzwerkverbindungen zu fremden Servern oder der Zugriff auf Systemeigenschaften wie etwa den Usernamen. Plug-ins unterliegen keinen solchen Beschränkungen.

340

Grundlagen Zusammenfassung Tabelle 12.3 fasst unsere Vergleiche noch einmal zusammen. Applets

Plug-in IE

Plug-in NN

Handling

-

+

/

Plattformunabhängigkeit

+

-

/

Performance

-

+

+

Sicherheitsmechanismus

vorhanden

nicht vorhanden

nicht vorhanden

Restriktionen

ja

nein

nein

12.1.4

Tab. 12.3: Vergleich zwischen Applets und Plugins: + = gut, / = mittel, – = schlecht

Java-Klassen mit JavaScript erzeugen

Dieser Abschnitt setzt durchschnittliche Kenntnisse in Java voraus. Der Vollständigkeit halber wollen wir noch einen Aspekt von LiveConnect erwähnen, den es nur im Netscape Navigator gibt. Dort haben Sie die Möglichkeit, von JavaScript aus auf die Objekt-Hierarchie der Java Virtual Machine zuzugreifen. Intern geschieht dies durch die Nutzung von JavaScript-Objekten vom Typ JavaPackage, JavaClass, JavaObject und JavaArray.

JavaPackage JavaClass JavaObject JavaArray

Im Wesentlichen haben wir Zugriff auf öffentliche statische Methoden und Properties von Java-Klassen. Ebenso können wir neue Instanzen von JavaObjekten erzeugen. Ganz wie bei Java-Applets können Sie dann auf öffentliche Methoden und Properties solcher Instanzen zugreifen. Beachten Sie, dass Java eine typisierte Sprache ist. Wenn Sie Properties Werte zuweisen, muss der Typ des Wertes dem der Property entsprechen. Andernfalls erhalten Sie einen JavaScript-Fehler. Gleiches gilt auch für den Aufruf von parametrisierten Methoden und Konstruktoren. Schauen wir uns nun einmal einfach einige Beispiele an. Sie werden sehen, dass sich bisher alles viel komplizierter angehört hat, als es ist. Mit java.lang.System.out.println("Hello Java");

können wir z.B. Text auf die Java-Konsole ausgeben, wie wir es auch schon bei der Behandlung von Applets gesehen haben. Dabei greifen wir auf das Objekt java.lang.System zu. Dieses besitzt eine statische Property out (vom Typ java.io.PrintStream, wie wir gleich sehen werden). Dessen statische Methode println(String) erledigt die Ausgabe auf die Java-Konsole. JavaObjekte können ganz wie JavaScript-Objekte gehandhabt werden:

341

12 LiveConnect var java_console = java.lang.System.out; java_console.println("Hello Java");

Gerade wenn nun mehrmals ein println(...) aufgerufen werden sollte, sparen wir uns nicht nur Tipparbeit, sondern ersparen LiveConnect auch, jedes Mal durch die Objekthierarchie zu wandern, bis es bei out angelangt ist. Testen Sie, was alert(java_console); getClass(...)

ausgibt. Mit der JavaScript-Funktion getClass(...) können Sie den Klassennamen des angegebenen Objekts erfragen. Sie liefert einen Rückgabewert vom Typ JavaClass. alert(getClass(java_console));

liefert [JavaClass java/io/PrintStream]. Verwechseln Sie die JavaScript-Funktion getClass(...) nicht mit der Java-Methode getClass(), die jedem Java-Objekt zu eigen ist. In Beispiel 9 können Sie Obiges direkt ausprobieren. Das vollständige Beispiel finden Sie auf dem beiliegenden Datenträger unter Buchdaten\kapitel12 \beispiele\ java\console.html. new

Erzeugen wir nun eine Instanz eines Java-Objekts: var url = new java.net.URL("http://www.thx.com:1138/darth/vader.html");

Ganz wie JavaScript-Objekte werden auch Java-Objekte mit dem Operator new erzeugt. Greifen wir nun auf einige Methoden von url zu: Methode url...

liefert ...

getProtocol();

http

getHost();

www.thx.com

getPort();

1138

getPath();

/darth/vader.html

Den Umgang mit dem URL-Objekt können Sie in Beispiel 10 nachvollziehen. Das vollständige Beispiel finden Sie auf dem beiliegenden Datenträger unter Buchdaten\kapitel12\beispiele\java\url.html. Als Java-Programmierer werden sie aufhorchen und merken, dass wir beim vorangegangenen Konstruktor-Aufruf keine Exception abgefangen haben. Dies ist eine der Schwächen von LiveConnect. Es gibt kein Exception-Handling. Beim Aufruf von var url = new java.net.URL(document);

342

Grundlagen bekommen wir einen JavaScript-Error. Ebenso wenig können wir eigene JavaKlassen definieren oder neue von den Basisklassen ableiten. Auch gibt es keine direkte Unterstützung für das Event-Handling von AWT-Komponenten. Daher tendiert der praktische Nutzen dieses Aspekts von LiveConnect auch gegen Null, zumal er nur im Netscape Navigator vorhanden ist. Doch lassen wir uns davon nicht abschrecken und erzeugen einmal eine grafische Oberfläche: var fMain = new java.awt.Frame("Hello Java"); with (fMain) { tbInput = new java.awt.TextArea( "The quick\nbrown fox\njumps over\nthe lazy dog.", 15,60); setLayout(new java.awt.BorderLayout()); add(tbInput, "Center"); pack(); setLocation(0,0); setVisible(true); } Abbildung 12.5: Java-Dialog mit JavaScript erzeugt

Im Großen und Ganzen (bis auf das with-Statement) ist dies auch der Code, der in einer entsprechenden Java-Anwendung verwendet werden würde. Sie werden merken, dass Sie das neu erzeugte Window nicht mit dem Kreuz rechts in der Titelleiste schließen können. Dies liegt an dem bereits erwähnten fehlenden Event-Handling. Es schließt sich erst, wenn Sie das Browser-Fenster schließen. Der folgende Code demonstriert den Einsatz eines FileDialogs: fFile = new java.awt.FileDialog( fMain, "Datei öffnen", java.awt.FileDialog.LOAD); with (fFile) { show(); var fn = getFile(); if (fn)

343

12 LiveConnect { fn = getDirectory() + fn; var fp = new java.io.File(fn); alert(fn + " size: " + fp.length()); } }

Beispiel 11 fasst den Umgang mit AWT-Komponenten noch einmal zusammen. Das vollständige Beispiel finden Sie auf dem beiliegenden Datenträger unter Buchdaten\kapitel12\beispiele\java\awt.html. Sicherheit

Wie Sie sehen, erhalten wir so scheinbar einen Zugriff auf das lokale Dateisystem. Die Betonung liegt auf scheinbar, denn wir können die Datei nun nicht zum Lesen oder gar Schreiben öffnen. Wir unterliegen den gleichen Sicherheitsrestriktionen der JVM wie Applets. Seien Sie also beruhigt. Fassen wir noch einmal zusammen. Das direkte Ansprechen von Java-Objekten ist für den JavaScript-Entwickler von geringem Nutzen, weil es ... 왘 fundierte Kenntnisse über die Java-API voraussetzt. 왘 kein Exception-Handling anbietet. 왘 kein Event-Handling bereitstellt. 왘 nicht erlaubt, neue oder abgeleitete Java-Klassen zu definieren. 왘 den gleichen Sicherheitsrestriktionen wie Applets unterliegt.

Dennoch werden die Tüftler unter Ihnen in den Übungen noch einige nützliche Dinge entdecken.

12.1.5

Ausblick

Die folgenden Betrachtungen spiegeln den Wissensstand im Juni 2000 wider. Bis zum Erscheinen dieses Werkes kann und wird sich wahrscheinlich einiges geändert haben. Netscape 6

344

Was wird uns Netscape 6 hinsichtlich LiveConnect bringen? Insbesondere im Zusammenhang mit dieser Frage sollten Sie beachten, dass der Netscape 6 Preview Release 1 technisch gesehen noch nicht einmal im Beta-Stadium ist. Der Release einer Version 6 hat in der Hauptsache marketingtechnische Gründe, unter anderem nämlich den, den Internet Explorer, der zur Zeit bei 5.5 Beta ist, in der Versionsnummer (und auch wirklich nur hier) zu überrunden. Ein weiteres Argument aus der Marketingabteilung ist das des geringen Downloads gegenüber dem Internet Explorer, was unter anderem auch dadurch erreicht wird, dass die Java Virtual Machine nicht mehr in der Standard-Distribution von Netscape 6 enthalten sein wird. Allerdings ist dies auch eine Folge der strikten Beachtung der W3C-Standards.

Übungen Wie wir jedoch gesehen haben, basiert LiveConnect komplett auf einer JVM. Daher werden Java-Applets und Plug-ins, die LiveConnect verwenden, mit einer Standardinstallation nicht funktionieren. Doch auch mit einer optional installierten JVM (wie es z.B. beim Preview Release mit seinem »mageren« 15 MB Download möglich ist) funktionieren Plug-ins mit LiveConnect nicht, weil sich die Plug-in-API geändert hat und so zunächst der Plug-in-Hersteller eine neue Version seiner Software bereitstellen muss. Doch seien Sie unbesorgt. Es wird LiveConnect auch in Zukunft geben, dann jedoch unter anderem Namen: XPConnect. XP steht dabei für Cross Platform (engl. cross = Kreuz = X), ein Präfix für eine ganze Reihe von neuen Begriffen wie XPCOM und XPInstall. Näheres hierzu finden Sie unter http://www. mozilla.org/projects/xpcom/ .

XPConnect

XPConnect wird ohne eine JVM die Kommunikation zwischen Plug-ins und JavaScript ermöglichen. Dies ist zu begrüßen, da Plug-ins dann ohne den Umweg über Java gescriptet werden können. Näheres finden Sie unter http://www.mozilla.org/scriptable/. XPInstall wird aller Voraussicht nach der Nachfolger von SmartUpdate sein. SmartUpdate basiert momentan auch noch komplett auf der JVM des Browsers, so dass auch hier ein passender Ersatz gefunden werden muss.

XPInstall

Wann aber mit einer Beta-Version von Netscape 6, die all die Features anbietet, oder gar einer Vollversion gerechnet werden kann, ist zur Zeit noch nicht absehbar. Die aktuellsten Testversionen finden Sie stets unter http://www. mozilla.org/. Unterschiede zwischen diesem Open-Source-Softwareprojekt und dem späteren davon abgeleiteten Netscape 6 sind allerdings nicht auszuschließen.

12.2

Übungen

leicht

1. Übung

Wie referenzieren Sie im Netscape Navigator ein Applet namens myApplet in einem Layer namens myLayer? Nur eine der möglichen Antworten ist richtig. applets["myLayer"].document.myApplet document.["myLayer"].myApplet document.layers["myLayer"].document.myApplet document.myApplet leicht

2. Übung

Wie betten Sie ein Applet namens myApplet der Größe 500 mal 200 Pixel, dessen Java-Klasse myJava.class ist, in eine HTML-Seite ein?

345

12 LiveConnect



leicht

3. Übung

Ändern Sie den Text, den das Applet HelloLiveConnect anzeigt. Manipulieren Sie dazu die öffentliche Variable sMessage. Benutzen Sie zur Texteingabe den JavaScript-Befehl prompt. mittel

4. Übung

Erweitern Sie das Applet aus Übung 3 um eine öffentliche Variable nRepeats. Dabei soll nRepeats vom Typ int sein und angeben, wie oft der Text in sMessage untereinander gezeichnet werden soll. Der Zeilenabstand betrage 20 Pixel. Fügen Sie dem HTML-Dokument ein Formular hinzu mit Eingabe-Feldern für sMessage und nRepeats. leicht

5. Übung

Erweitern Sie das Applet aus Übung 4 um eine öffentliche Variable isDrop Shadow. Dabei soll isDropShadow vom Typ boolean sein und angeben, ob die Textausgabe mit Schattenwurf erfolgen soll. Fügen Sie dem HTML-Dokument eine Checkbox hinzu, deren Zustand den Wert von isDropShadow bestimmt. schwer

6. Übung

Schreiben Sie eine JavaScript-Funktion inspectObject(sItem), die alle Properties eines Applets in einem neuen Browser-Fenster auflistet. Dabei soll sItem ein String sein, der die Referenz auf ein Applet enthält, so z.B. "document. myApplet". schwer

7. Übung

Schreiben Sie ein Applet, das beim Bewegen der Maus deren Koordinaten in der Statuszeile des Browsers ausgibt. Außerdem soll das Applet beim Mausklick den URL in einem neuen Browserfenster anzeigen, der im AppletParameter url definiert wird.

346

Übungen leicht

8. Übung

Wie wird einem Applet der Zugriff auf die JavaScript-Objekthierarchie erlaubt? Nur eine der möglichen Lösungen ist richtig:





Sie beschleunigen, um den Gefahrenbereich so verlassen ;-)

width="100"

width="100"

width="100"

schnell wie möglich zu

schwer

9. Übung

Entwerfen Sie eine Java-Klasse JSWrapper(java.applet.Applet), die den Zugriff von Java aus auf die JavaScript-Objekthierarchie vereinfacht. Sie soll zwei Methoden String get(sDOMItem, sProperty); void set(sDOMItem, sProperty, sValue);

haben, mit denen Sie z.B. auf document.myForm.myInput.value wie folgt zugreifen: JSWrapper jsw = new JSWrapper(this); String val = jsw.get("document.myForm.myInput", "value"); jsw.set("document.myForm.myInput", "value", "LiveConnect");

Gehen Sie dabei von Beispiel 5 aus und ändern Sie dort die Methoden do_read() und do_write() so ab, dass Sie mit der neuen Klasse JSWrapper arbeiten. mittel

10. Übung

Geben Sie in einem Input-Feld eines HTML-Formulars den aktuellen Frame eines Flash-Movies aus, während dieser abgespielt wird. Gehen Sie dabei von Beispiel 7 aus.

347

12 LiveConnect leicht

11. Übung

Wie rufen Sie aus einer VBScript-Funktion eine JavaScript-Funktion namens myJavaScript(sParam) auf? Nur eine der möglichen Lösungen ist richtig: myJavaScript(sParam); call myJavaScript(sParam); sub myJavaScript(sParam) call myJavaScript(sParam) mittel

12. Übung

In dieser Übung machen wir uns mit den verschiedenen Properties eines FlashMovies vertraut. Tabelle 12.4 stellt nur einen Teil aller Properties dar. Tab. 12.4: Ausgesuchte Properties eines Flash-Movies

Property-ID

Bedeutung

0

X-Position (0, ...)

1

Y-Position (0, ...)

2

Skalierung in X-Richtung (prozentual, ganzzahlig)

3

Skalierung in Y-Richtung (prozentual, ganzzahlig)

6

Alpha-Blending (0=transparent, ..., 100=voll deckend)

7

Rotation in Grad (0, ..., 360)

Fügen Sie Ihrem HTML-Dokument ein select-Feld hinzu, dessen option-Elemente jeweils die Property-ID als Wert haben. In einem input-Feld kann ein Wert eingegeben werden, der per Druck auf einen Button dann der entsprechenden Property zugewiesen wird. schwer

13. Übung

Benutzen Sie ein fertiges Applet HSlider.class. Dieses stellt einen horizontalen Scrollbalken zur Verfügung, der bei Änderung seines Wertes eine JavaScript-Funktion aufruft, die den Wert als Parameter übergeben bekommt. Den Namen der aufzurufenden JS-Funktion und den Wertebereich legen Sie mit der Applet-Methode setHook(String sJSFunc, int iMin, int iMax);

fest. Erweitern Sie die vorangegangene Übung um zwei Input-Felder, über die Sie die Werte für iMin und iMax eingeben können. Diese und der Name einer JavaScript-Funktion function changeProperty(sValue)

übergeben Sie per Knopfdruck an das Applet. In changeProperty(...) werten Sie den Wert der select-Box aus, um die zu ändernde Property des FlashMovies zu erhalten.

348

Tipps mittel

14. Übung

Schreiben Sie für den Netscape Navigator einen Ersatz für den URL about: plugins. Dieser existiert im Preview Release des Netscape 6 noch nicht und wir möchten trotzdem gerne wissen, welche Plug-ins wir dort installiert haben. schwer

15. Übung

Zeigen Sie in einem neuen Browser-Fenster den Inhalt der aktuellen HTMLSeite als ASCII-Text an. Es geht also darum, eine eigene Behandlung des Pseudo-Protokolls view-source: zu implementieren. schwer

16. Übung

Schreiben Sie eine JavaScript-Funktion HTTPHeader(sURL), die einen HTTP HEAD-Request auf den angegebenen URL ausführt und das Ergebnis der Anfrage in einem neuen Browser-Fenster ausgibt.

12.3

Tipps

Tipp zu 4 Initialisieren Sie den Wert von nRepeats in der init()-Methode des Applets auf 1. Eine for-Schleife hat in Java fast genau die gleiche Syntax wie in JavaScript: for (int i=1; i