Flash CS3,
AJAX und PHP
Flash CS3,
AJAX und PHP
Ein Imprint von Pearson Education
München • Boston • San Francisco • Harlow,England
Don Mills,Ontario • Sydney • Mexico City
Madrid • Amsterdam
ADDISON-WESLEY
Uwe Mutz
Bibliografische Information Der Deutschen Bibliothek
Die Deutsche Bibliothek verzeichnet diese Publikation in der
Deutschen Nationalbibliografie; detaillierte bibliografische Daten
sind im Internet über http://dnb.ddb.de abrufbar.
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 und weitere Stichworte und sonstige Angaben, die in
diesem Buch verwendet werden, sind als eingetragene Marken geschützt. Da es nicht möglich ist, in allen
Fällen zeitnah zu ermitteln, ob ein Markenschutz besteht, wird das
®Symbol in diesem Buch nicht
verwendet.
Umwelthinweis:
Dieses Buch wurde auf chlorfrei gebleichtem Papier gedruckt.
Alle Rechte vorbehalten. Kein Teil des Buches darf ohne Erlaubnis der Pearson Education Inc. in
fotomechanischer oder elektronischer Form reproduziert oder gespeichert werden.
10 9 8 7 6 5 4 3 2 1
09 08 07
ISBN 978-3-8273-2528-0
© 2007 Addison-Wesley Verlag,
ein Imprint der PEARSON EDUCATION DEUTSCHLAND GmbH,
Martin-Kollar-Str. 10-12, 81829 München/Germany
Alle Rechte vorbehalten
Lektorat: Brigitte Bauer-Schiewek, bbauer@pearson.de
Fachlektorat: Matthias Kannengiesser
Korrektorat: Petra Kienle
Herstellung: Claudia Bäurle, cbaeurle@pearson.de
Satz: Ulrich Borstelmann, Dortmund (www.borstelmann.de)
Einbandgestaltung: Marco Lindenbeck, webwo GmbH, mlindenbeck@webwo.de
Druck und Verarbeitung: Kösel Druck, Krugzell (www.koeselBuch.de)
Printed in Germany
V
INHALTSVERZEICHNIS
Sieh' einer an … IX
Kapitel 1 Einleitung 1
Kapitel 2 Grundlagen der Programmierung 5
2.1 Programmierung in Flash 6
2.1.1 Anlehnung an JavaScript 6
2.1.2 Objektorientiertes Programmieren 6
2.2 Kommentare 7
2.2.1 Einzeilige Kommentare 7
2.2.2 Mehrzeilige Kommentare 7
2.2.3 Verschachtelte Kommentare 8
2.3 Variablen und Datentypen 8
2.3.1 Variablendeklaration 8
2.3.2 Variablennamen 9
2.3.3 Datentypen 10
2.3.4 Gültigkeitsbereiche von Variablen 13
2.4 Operatoren 17
2.4.1 Arithmetische Operatoren 17
2.4.2 Zuweisungsoperatoren 18
2.4.3 Bitoperatoren 21
2.4.4 Logische Operatoren 21
2.4.5 Vergleichsoperatoren 22
2.4.6 Rangordnung der Operatoren 22
2.5 Arrays 24
2.5.1 Indizierte Arrays 24
2.5.2 Assoziative Arrays 25
2.6 Bedingungen 28
2.6.1 if-Bedingung 28
2.6.2 switch-Bedingung 30
VI
2.7 Schleifen 31
2.7.1 for-Schleife 31
2.7.2 for...each- oder for...in-Schleife 37
2.7.3 do..while-Schleife 39
2.7.4 while-Schleife 40
2.8 Funktionen 41
2.9 Cookies 47
2.9.1 Exkurs HTTP 47
2.10 Sessions 50
2.10.1 session_start() 51
2.10.2 session_register() vs. $_SESSION 51
2.10.3 session_unregister() vs. $_SESSION 53
2.10.4 session_destroy() 53
2.11 Caching 53
2.12 XML auslesen und erstellen 56
2.12.1 Der Aufbau eines XML-Dokuments – Blitzeinführung 56
2.12.2 Auslesen einer XML-Struktur 60
2.12.3 XML-Dokumente erstellen 62
Kapitel 3 Basiswissen 65
3.1 PHP 66
3.2 JavaScript (AJAX) & DOM 66
3.2.1 „Kern-DOM“ 67
3.2.2 Alternativer Zugriff auf Objekte 69
3.3 Flash 72
3.3.1 Sinnvolle Kombination von Flash und PHP 72
3.3.2 Weitere Verbindungsmöglichkeiten zur Serverseite 73
3.3.3 ActionScript 3.0 – die wichtigsten Änderungen 73
Kapitel 4 AJAX – Asynchronus JavaScript and XML 119
4.1 Was ist AJAX? 120
4.2 Was ist AJAX nicht? 120
4.3 Der XMLHttpRequest 122
4.3.1 Details zum XMLHttpRequest-Objekt 125
4.3.2 AJAX im Einsatz 128
VII
4.4 Flash vs. AJAX 164
4.5 Flash & AJAX 165
Kapitel 5 Clientseitiger Datenaustausch – Flash & Javascript 167
5.1 Daten senden: Browser an Flash 168
5.1.1 Variante 1: JavaScript greift auf die SWF-Datei zu 168
5.1.2 Variante 2: Verwenden von HTML-Attributen
zum Setzen von Variablen 179
5.2 Daten senden: Flash an Browser 181
5.2.1 Kontaktaufnahme mit getURL 181
5.3 Die ExternalInterface-Klasse – Flash 8 und höher 184
5.3.1 ExternalInterface-Klasse mit ActionScript 1.0/2.0 185
5.3.2 ExternalInterface-Klasse mit ActionScript 3.0 207
5.4 Flash & AJAX 208
5.4.1 Parameterübergabe: Text 209
5.4.2 Parameterübergabe: XML 233
Kapitel 6 Serverseitiger Datenaustausch –
Flash, PHP & Datenbank 239
6.1 Drei Technologien im Einsatz 240
6.2 Das LoadVars-Objekt 241
6.3 Die Basis: das XML-Objekt & ActionScript 2.0 266
6.3.1 Grundlegende XML-Befehle 266
6.3.2 Einlesen von XML-Daten 266
6.3.3 Ausgeben von XML-Daten in eine PHP-Seite 286
6.3.4 Die XMLConnector-Komponente 298
6.4 ActionScript 3.0: Neues und Änderungen 309
6.4.1 Das URLLoader- und URLRequest-Objekt 309
6.4.2 Der Aufbau: das XML-Objekt & ActionScript 3.0 325
Kapitel 7 Audio-Jukebox 337
7.1 Abfragen serverseitiger Informationen 338
7.2 Multimediale Anwendungen 338
7.3 Konzept der Jukebox 338
7.3.1 Playlist generieren 338
VIII
7.4 Jukebox in ActionScript 2.0 340
7.4.1 XML-Daten laden 341
7.4.2 Abspielen der Songs 344
7.4.3 ID3-Tags auslesen 349
7.4.4 Abspielsteuerung 351
7.4.5 Lautstärkeregler 353
7.5 Der PHP-Part 355
7.6 Jukebox in ActionScript 3.0 359
7.6.1 Allgemeine Änderungen 359
7.6.2 Änderungen beim Laden der XML-Daten 360
7.6.3 Änderungen im Soundobjekt 363
7.6.4 Änderungen in der Abspielsteuerung 363
7.6.5 Änderungen in der Lautstärkeregelung 370
7.6.6 Songs aus einer ComboBox abspielen 372
7.7 Mögliche Erweiterungen 374
Kapitel 8 Videoplayer (ActionScript 3.0) 375
8.1 Das Konzept des Videoplayers 376
8.2 Flash & Video 376
8.3 Die Umsetzung 378
8.3.1 Flash und die FLVPlayback-Komponente 378
8.3.2 Videos im FLV-Format 382
8.3.3 Dynamisches Verknüpfen der
FLVPlayback-Komponente mit einem Video 392
8.3.4 Schritt 1: Abspielen einer Liste von Videos (Array) 394
8.3.5 Schritt 2: Abspielen einer Liste von Videos (XML) 401
8.3.6 Arbeiten mit Cue-Points 426
Stichwortverzeichnis 429
IX
SIEH’EINER AN …
Schön, Sie hier zu treffen! Ein Sprichwort sagt „Alles neu macht der Mai“ – nun, Flash erstrahlt
in Version CS3, PHP läuft stabil in Version 5 und um AJAX müssen wir uns keine Sorgen
machen, denn da setzen wir auf die bekannten (und bewährten) Technologien JavaScript und
XML. Mit anderen Worten: Dieses Buch baut auf Bewährtem und Neuem auf. Lassen Sie sich
überraschen!
Aber alles der Reihe nach. Zunächst einmal freut es mich, dass Sie sich für dieses Buch entschie-
den haben. Es zeigt mir, dass die Kombination von Flash und PHP nach wie vor ein beliebtes
Thema ist. Und mit „Web 2.0“ ist auch AJAX in aller Munde – und wie es scheint auch in Ihrem
Interesse.
Meine geschätzte Leserschaft
Bevor wir ans Eingemachte gehen, möchte ich ein paar Worte vorausschicken, für wen dieses
Buch geschrieben ist und – vor allem! – für wen dieses Buch nicht geschrieben ist (ich denke,
es ist wichtiger, solche „Nicht-Ziele“ zu definieren).
Das sind meine Leser!
Dieses Buch ist für Einsteiger in die Thematik „Flash & PHP & AJAX“ geschrieben. Dabei gehe
ich davon aus, dass meine Leser mit der Arbeitsweise von Flash, PHP & JavaScript vertraut sind,
sie also den Umgang mit Folgendem im Schlaf beherrschen :
Flash:
Die „Zeit“: Der Umgang mit der Zeitleiste ist kein Problem, ebenso wissen Sie über
Schlüsselbilder, benannte Bilder und Szenen Bescheid.
Die „Elemente“: Formen, Symbole und Instanzen, grundlegende Komponenten stellen
für Sie in der Anwendung kein Problem dar, Benennung von Instanzen, Definieren von
Instanz-Eigenschaften etc. erledigen Sie ohne nachzudenken.
.fla versus .swf: Selbstverständlich ist Ihnen der Unterschied zwischen der Flash- und der
SWF-Datei bekannt, auch haben Sie schon unzählige Male eine SWF-Datei in ein Web-
dokument eingebunden. Die Problematik verschiedener Browser-Systeme (Einbinden
der SWF-Dateien mittels <embed> oder <object>) kennen Sie ebenso.
ActionScript: Dass hiermit die in Flash verwendete Programmiersprache gemeint ist,
wissen Sie. Dabei hatten Sie bereits ersten Kontakt mit grundlegenden Befehlen wie etwa
stop(), play(), gotoAndPlay(), gotoAndStop() usw. – die Grundlagen der Pro-
grammierung sind Ihnen bekannt und ein wenig programmiert haben Sie auch schon.
u
u
u
u
u
X
JavaScript: Sie sind eventuell (noch) kein Programmierprofi, jedoch wissen Sie, wie man
mit dem <script>-Tag umgeht und dass man JavaScript-Code in einer externen Datei
ablegen kann, welche sich im Weiteren mit einem Webdokument verknüpfen lässt. Wahr-
scheinlich sind Sie sogar in der Lage, grundlegenden Code zu schreiben und auch kleinere
Projekte zu verstehen – ansonsten helfen Ihnen das einleitende Kapitel „Grundlagen der
Programmierung“ und die einschlägige Literatur weiter.
PHP und MySQL:
Server- versus Clientseite: PHP ist eine serverseitige, JavaScript eine clientseitige Pro-
grammiersprache – kein Thema, das wissen Sie.
Programmierung: Ein wenig Erfahrung haben Sie bereits gesammelt bzw. Sie haben
zumindest schon einmal PHP-Code geschrieben. Sollte dem nicht so sein – wie gesagt,
dann ist das Einleitungskapitel für Sie gedacht.
Datenbanken: Die Grundlagen relationaler Datenbanken kennen Sie, ebenso haben Sie
bereits einmal mit MySQL in Zusammenhang mit einer datenbankbasierten Weban-
wendung gearbeitet. Das System PHPMyAdmin ist Ihnen auch ein Begriff und Tabel-
len können Sie anlegen, mit Daten befüllen und auch administrieren. Nein? Kapitel
„Grundlagen der Programmierung“ …
Die liebe Programmierung …
Sollten Sie mit der Programmierung noch nicht so sehr vertraut sein, so ist Ihnen das Kapitel „Grundlagen
der Programmierung“ gewidmet, in dem Sie das notwendige Rüstzeug vermittelt bekommen, um die fol-
genden Kapitel locker bewältigen zu können.
Bedenken Sie jedoch bitte, dass es sich hierbei nicht um ein allumfassendes Werk zu den genannten
Technologien handelt und deshalb im Abschnitt zu den Grundlagen der Programmierung auch nur die für
die restlichen Kapitel notwendigen Themen behandelt werden.
Diese Leser werden nicht glücklich!
Wie schon eingangs erwähnt, ist dieses Buch für Einsteiger geschrieben. Sollten Sie also bereits
Programmierprofi sein, Hunderte Projekte in Flash realisiert und jegliche Arten von Daten-
banksystemen realisiert haben, dann werden Sie die in diesem Buch beschriebenen Inhalte
nicht befriedigen. Das Anwenden von Flash-Komponenten zur Kommunikation mit serversei-
tigen (Adobe-)Anwendungen ist zwar ein Teil des Buchs, spielt jedoch nur eine untergeordnete
Rolle.
Ich werde auch nicht den Versuch machen, den kürzest möglichen Programmcode zu schrei-
ben, denn dies geht meist auf Kosten der Lesbarkeit und somit der Verständlichkeit des Pro-
grammierten. Ein perfekter Programmierer wird man nie, ein sehr guter Programmierer wird
man durch das tägliche Programmieren – auf diesen Weg kann ich Sie führen, indem ich Ihnen
den Einstieg so einfach wie möglich mache.
u
u
u
u
u
XI
Ein immerwährendes Problem in der Welt des Internets sind die Browser: verschiedene Gene-
rationen von Browsern, verschiedene Browser, verschiedene Plattformen – zumeist verhalten
sie sich unterschiedlich und liefern unterschiedliche Resultate. Ich werde in diesem Buch nicht
den Versuch anstellen, alle nur erdenkbaren Eventualitäten zu berücksichtigen, sondern viel-
mehr Rücksicht auf die gängigen Browser nehmen:
Microsoft Internet Explorer 6 unter Windows
Microsoft Internet Explorer 7 unter Windows
Firefox 2 unter Windows und Mac OS X
Opera 9.1 unter Windows und Mac OS X
Safari 2.0.4 unter Windows
Diese Browser stellen mit Sicherheit den repräsentativen Querschnitt über alle gängigen und
im Einsatz befindlichen Browser weltweit dar – alle weiteren Browser lasse ich „links liegen“.
Zusammengefasst: Profis werden in diesem Buch nicht die gewünschten Inhalte finden – dies
ist ein Einsteigerbuch! Für Sie, meine lieben Experten, hält Addison-Wesley eine Reihe von
Büchern bereit, die Ihren Ansprüchen gerecht werden und auch noch die letzte Frage beant-
worten.
Danke!
An dieser Stelle wird es im Allgemeinen persönlich … Wohl nichts, das den Inhalt eines Buchs
wesentlich beeinflussen würde, aber eine wunderbare Möglichkeit, sich zurückzulehnen, zu
erfreuen an einem sonnigen Tag und die verstrichene Zeit Revue passieren zu lassen. Mit
der Zeit tritt dann eine innere Dankbarkeit ein, die darauf wartet, nach außen zu treten und
DANKE in die Welt zu schreien – danke all den Menschen, die mir wertvoll sind und mein
tägliches Leben bereichern.
Allen voran meiner geliebten Freundin Doris, die mir mein tägliches Maß an Freude und Spaß
zu servieren weiß und mich mit Motivation und Lebensfreude versorgt – meine lieben Herren,
ihr könnt euch glücklich schätzen, wenn auch ihr mit einer solch tollen Freundin gesegnet seid.
Werte Damen – sorry, ich bin vergeben!
Im selben Atemzug danke ich meiner Familie für eigentlich alles! Geburt (inklusive Zeugung),
Erziehung, Ausbildung, Unterstützung, Liebe, Freundschaft, Rat und Tat – nichts blieb auf der
Strecke. Und ganz nebenbei haben diese beiden auch dafür gesorgt, mir eine tolle Schwester zu
schenken (die mir wiederum einen tollen Neffen geschenkt hat ...)!
Alle meine Freunde, mit denen ich feiern und Spaß haben kann. Jungs, manchmal muss ich
euch zwar motivieren, aus euren trauten Heimen zu kriechen, um etwas zu unternehmen, aber
das erledige ich gerne. Caro, AIC, ToM, Gott, Chris, Clemens, Erik, Hari und viele mehr, die
u
u
u
u
u
XII
mich sicherlich schimpfen werden, dass sie hier namentlich nicht erwähnt sind („… wie konn-
test du mich nur vergessen …“ usw.).
Ein herzlicher Dank gebührt auch meinem Verlag und meinen Lektoren, die mich so nett in
ihren Kreis aufgenommen haben und mir bei jeder Frage und jedem Anliegen mit Tipp und Tat
zur Seite standen – ich freue mich auf jede Zusammenarbeit, die noch kommen wird!
Zu guter Letzt danke ich Ducati für meine Monster, Metallica für die Art von Musik, die ich
täglich brauche, und meinem Doktorvater Gü Blaschek für all die tollen Gespräche, die mich
immer wieder über Gott und die Welt nachdenken lassen.
Me, myself and I …
Uwe Mutz
1
EINLEITUNG
Flash, AJAX und PHP – das wird spannend!
Vor kurzem ist die neueste Version von Flash in deutscher Ver-
sion erschienen: Flash CS3. Viele Entwickler waren schon sehr
auf die Neuerungen und Änderungen gespannt. Und wissen Sie
was – sie wurden nicht enttäuscht! Sogar ganz im Gegenteil ...
Was Flash speziell für Programmierer durch die Einführung
von ActionScript 3.0 zu bieten hat, ist schon fast eine Sensation.
Beinahe kein Stein blieb auf dem anderen, die hart erworbenen
Kenntnisse in ActionScript 2.0 dienen mehr oder weniger nur
noch dafür, dass man sich ein bisschen „zurechtfindet“. Ange-
fangen von einfachen Änderungen in den Bezeichnungen von
Eigenschaften bis hin zum kompletten Wegfall diverser Klassen
(bzw. Verschieben in andere Pakete) ist alles gegeben.
Da ich an dieser Stelle aber nicht davon ausgehen kann, dass
ab jetzt sämtliche Entwicklungen in ActionScript 3.0 erfolgen
(dies setzt nämlich den Flash9-Player voraus), gehe ich in
diesem Buch sowohl auf die Version 2.0 als auch auf 3.0 von
ActionScript ein. Gerade einmal das letzte Beispiel in diesem
Buch – der Videoplayer – ist komplett in ActionScript 3.0 ent-
wickelt worden. Gerade bei Videos bietet sich ActionScript 3.0
geradezu an. Der zweite große Workshop im Buch – der Audio-
player – ist sowohl in ActionScript 2.0 als auch 3.0 entwickelt.
Ideal also, um einen Vergleich der beiden Versionen zu ziehen.
K A P I T E L 12
Mein Tipp in Bezug auf die beiden Versionen (ActionScript 1.0 mal außer Acht gelas-
sen): Sollten Sie sich in eine Version gezielt einarbeiten wollen, beschäftigen Sie sich
primär mit der 3.0er Version, denn sie ist mit Sicherheit die Zukunft. Es wird nicht
mehr lange dauern, bis die Mehrheit der Internet-User auf den Flash9-Player umge-
stellt hat.
Dieses Buch wird sich nur sehr oberflächlich mit allen Komponenten und Möglich-
keiten befassen, die im Rahmen der Entwicklungsumgebung auf der Bühne platziert
werden. Umso mehr ist der Fokus auf die Programmierung gerichtet. Ein Flash Com-
munication Server wird ebenso wenig ein Thema sein wie Elemente der FileReference-
Klasse usw. Primäres Ziel des Buchs ist es, die Möglichkeiten der Zusammenarbeit
dreier Technologien zu zeigen und nicht jede Technologie für sich.
Warum sich das Buch mit PHP beschäftigt, liegt auf der Hand: PHP hat sich zu
der serverseitigen Programmiersprache entwickelt, um die man einfach nicht mehr
herumkommt. Und das aus gutem Grunde, wurde sie doch speziell für den Einsatz
im Web entwickelt. Und welche andere serverseitige Programmiersprache kann das
schon von sich behaupten? Da sich die Syntax an die gängigen Standards anlehnt, ist
das Erlernen nicht allzu aufwändig. Hat man den Unterschied zwischen Server- und
Clientseite einmal verstanden, ist eigentlich alles klar.
Alternativ könnte man genauso gut auf ASP, ASP.NET oder JSP zurückgreifen, aber
warum eine weniger gängige Technologie einsetzen, wenn das Gute doch so nah
liegt?
Dass das Thema AJAX in diesem Buch aufgegriffen wird, mag schon etwas weniger
auf der Hand liegen, denn im Grunde genommen ist Flash in der Lage, so gut wie alle
Bereiche abzudecken, die uns AJAX auf Clientseite ermöglicht. Spannend wird die
Sache jedoch, wenn man sich die Möglichkeiten überlegt, wie sich Flash und AJAX
ergänzen können. Ein guter Webdesigner entwickelt nicht stur in eine Richtung, son-
dern kennt die User seiner Webanwendungen. Genau aus diesem Grund ist es manch-
mal notwendig, parallel in AJAX und Flash zu entwickeln. Sollte man dann nicht genau
wissen, in welchen Bereichen sich AJAX und Flash überschneiden? Ich denke schon.
Mindestens genauso spannend ist es, wenn „gemischte“ Webanwendungen mit AJAX
und Flash entwickelt werden müssen. Flash interagiert mit AJAX, AJAX interagiert mit
Flash. So läuft der Hase!
Dass in diesem Buch nicht alle Anwendungsgebiete abgedeckt werden können, versteht
sich von selbst. Aus diesem Grunde habe ich mich für multimediale Anwendungen
mit Audio- und Videodaten entschieden. Das „Dahinter“ („Wie erhält ein Videoplayer
seine Playlist?“ etc.) wird vor allem über XML-Daten realisiert, Interaktion mit dem
Browser erfolgt zumeist über die ExternalInterface-Klasse.
PHPPHP
AJAXAJAX
E I N L E I T U N G 3
Besonders wichtig ist mir, dass Sie nach dem Lesen dieses Buchs ein Grundverständnis
für die Arbeit mit Flash, AJAX und PHP als Paket entwickelt haben und einsetzen
können. Kochrezepte werden Sie nur wenige finden. Aber Hand aufs Herz – ohne
Denken läuft in unserem Business sowieso nichts mehr! Dann empfiehlt es sich, lieber
ein gutes Verständnis einer Thematik zu haben, als Kochrezepte einzusetzen, die man
nicht versteht!
Abschließend: Sollten Sie Fragen zu den Inhalten oder Anregungen haben, so freue ich
mich über eine Kontaktaufnahme per E-Mail: flashajaxphp@syne.at.
2
GRUNDLAGEN DER
PROGRAMMIERUNG
Variablen, Arrays, Schleifen und Co. sind das Handwerkszeug
eines Programmierers. In diesem Kapitel werden wir uns
mit den theoretischen Grundlagen von Programmiersprachen
befassen. Haben Sie diese Grundlagen einmal verstanden, steht
Ihnen eigentlich die ganze Welt der Programmierung offen.
Da dieses Buch dynamische Flash-Anwendungen durch den
Einsatz von ActionScript und PHP zum Thema hat, zeigen
wir Ihnen die Grundlagen der Programmierung auch gleich
anhand dieser zwei Programmiersprachen. Des Weiteren erhal-
ten Sie im Rahmen dieses Kapitels eine Blitzeinführung zum
Thema XML.
InvielenFällenmüssenwirdabeinichtzwischenPHP,JavaScript
und ActionScript unterscheiden. Wo dies jedoch notwendig ist,
finden Sie in der äußeren Spalte neben dem Text einen Hinweis
für PHP, JavaScript bzw. für ActionScript.
K A P I T E L 26
Bitte beachten Sie jedoch, dass dieses Buch ein umfassendes Buch zu den Themen PHP,
JavaScript und ActionScript weder ersetzen kann noch soll. Dieses Kapitel dient dazu,
Ihnen die notwendigen Voraussetzungen mit auf den Weg zu geben – jedoch nur die
notwendigen Voraussetzungen, die Sie für die weiteren Kapitel benötigen.
2.1 Programmierung in Flash
Anders als in gängigen Programmiersprachen muss in Flash – aufgrund seines
Ursprungs als Animationsprogramm – die Zeitleiste berücksichtigt werden. Somit
müssen wir mit dem Faktor „Zeit“ umgehen lernen. Wie Sie bereits gehört haben, ist
die Programmierung in Flash auf drei verschiedene Arten möglich:
1. Programmierung in der Zeitleiste (egal, ob Zeitleiste der Bühne oder die eines
MovieClip)
2. Bei MovieClips über MovieClip-Ereignisse (diese werden Sie noch kennenlernen)
3. Bei Schaltflächen über Schaltflächen-Ereignisse (sie werden ebenfalls noch
vorgestellt)
2.1.1 Anlehnung an JavaScript
ActionScript ist eine Programmiersprache, die sich an JavaScript (bekannt aus der
Webprogrammierung) anlehnt, jedoch nicht genau deren Umfang hat. Detailliert soll
auf diese Tatsache nicht eingegangen werden, nur eines sei noch erwähnt: Können Sie
JavaScript programmieren, so ist es ein Leichtes, ActionScript zu programmieren.
2.1.2 Objektorientiertes Programmieren
Oft ist die Rede von ActionScript 1.0, ActionScript 2.0 und ActionScript 3.0. Der
wesentliche Unterschied zwischen den ersten beiden Versionen besteht darin, dass
Version 2.0 im Gegensatz zu Version 1.0 objektorientiert ist. Ein weiteres Feature
ist die Möglichkeit einer strikten Typisierung, auf die wir im Verlauf dieses Kapitels
noch näher eingehen werden. Für unsere Anwendungen wird es nicht notwendig
sein, objektorientiert zu programmieren, deshalb ist ein umfassendes Verständnis von
ActionScript 2.0 nicht erforderlich. ActionScript 3.0 stellt eine beinahe vollkommene
Neuentwicklung von ActionScript dar. Sämtliche Unterschiede und Änderungen fin-
den Sie in der ActionScript-Referenz unter dem Schlagwort „ActionScript 2.0 Migra-
tion“, auf die wesentlichen Änderungen gehen wir im Weiteren noch genauer ein. Bitte
beachten Sie jedoch, dass die einleitenden Kapitel dieses Buchs keinesfalls ein Action-
Script-Buch und schon gar kein ActionScript 3.0-Buch ersetzen können!
Kein allumfas-
sendes Werk zu
PHP, JavaScript
und ActionScript!
Kein allumfas-
sendes Werk zu
PHP, JavaScript
und ActionScript!
MovieClips
Bei der Programmierung
mit MovieClips ist es von
besonderer Bedeutung, den
verwendeten MovieClips
einen Namen zu geben.
G R U N D L A G E N D E R P R O G R A M M I E R U N G 7
So weit zu den einfachen Dingen, nun zu den etwas schwierigeren: Wir müssen uns die
Grundlagen der Programmierung aneignen und das bedeutet ein hartes Stück Arbeit.
Es wäre viel zu trocken, diesen Part rein theoretisch zu halten, also werden wir beglei-
tend dazu einige kleine Beispiele programmieren.
Die folgenden Ausführungen können – wenn nicht anders vermerkt – für die Pro-
grammiersprachen JavaScript, ActionScript und PHP verstanden werden.
2.2 Kommentare
Gleich zu Beginn dieses Kapitels möchten wir Sie auf die Möglichkeit der Kommentie-
rung Ihrer Scripte hinweisen. Dies ist natürlich nicht zwingend notwendig, jedoch sehr
wichtig und hilfreich. Beim Erstellen Ihres Programms ist wahrscheinlich der Code
noch verständlich und logisch. Ob dies nach ein oder zwei Monaten immer noch so
ist, ist fraglich. Zusätzlich erleichtern Sie Kollegen die Arbeit mit Ihren Scripten, wenn
diese gut kommentiert sind. Nutzen Sie Kommentare also so oft wie möglich.
2.2.1 Einzeilige Kommentare
Zwei Schrägstriche // leiten einen Kommentar ein, und zwar einen zeilenweisen Kom-
mentar. Alles, was Sie in dieser Zeile nach den Schrägstrichen schreiben, wird nicht als
Befehl interpretiert, sondern nur als Anmerkung, also als Kommentar.
//dies ist ein einzeiliger Kommentar
2.2.2 Mehrzeilige Kommentare
Sollten Sie einen Kommentar benötigen, der über mehrere Zeilen geht, so können
Sie ihn mit einem beginnenden /* und einem (in irgendeiner der darunterstehenden
Zeilen) endenden */ einschließen, also z.B. so:
/* dies
ist
ein
mehrzeiliger
Kommentar */
Im Allgemeinen werden Kommentare im Code verwendet, um die Ideen während der
Entwicklung des Codes bzw. wichtige Informationen zu Variablen, Objekten etc. (etwa
deren Bedeutung oder mögliche Werte) festzuhalten. Ein weiteres Anwendungsgebiet
ist das „Auskommentieren„ von nicht verwendeten Codezeilen: Der Entwickler ist
grundsätzlich immer versucht, den bereits geschriebenen Code bei Nichtverwendung
keinesfalls einfach zu löschen, sondern ihn – sollte er wider Erwarten doch noch benö-
tigt werden – auszukommentieren.
K A P I T E L 28
Bitte beachten Sie, dass sowohl ein- als auch mehrzeilige Kommentare an derjenigen
Stelle beginnen, an der die Kommentarzeichen gesetzt werden. Dabei werden einzeilige
Kommentare oft verwendet, um am Ende einer Codezeile diverse Anmerkungen zu
platzieren, wie etwa:
var modus:Number = 1; //Nur die Werte 1 und 2 sind gueltig
Im obigen Beispiel wird so deutlich, dass bei Verwendung der Variablen modus nur die
Werte 1 oder 2 zugewiesen werden dürfen.
Beachten Sie bitte weiterhin, dass erklärende (ein- oder mehrzeilige) Kommentare
besser vor den Codeblock geschrieben werden, wo diese Erklärung benötigt wird.
2.2.3 Verschachtelte Kommentare
Verschachtelte Kommentare sind in PHP nicht erlaubt. Das Ausführen Ihres Pro-
gramms wird in solch einem Fall abgebrochen.
2.3 Variablen und Datentypen
2.3.1 Variablendeklaration
Wenn Sie ein Programm erstellen, müssen Sie bestimmte Werte für die spätere Ver-
wendung sicher und eindeutig speichern. Denken Sie einfach an ein Spiel, in dem der
User zu Beginn seinen Nickname nennt. Im weiteren Verlauf des Spiels werden wir
diesen Spieler immer an diesem Namen erkennen und ihn auch mit diesem Namen
ansprechen. Damit ist eine klare Identität gegeben. Eingegebene Werte sind dann unter
diesem Namen jederzeit abrufbar.
In diesem Fall würden wir zum Beispiel eine Variable namens plNickname anlegen
und in ihr den eingegebenen Namen des Spielers speichern.
$plNickname ; // Variablendeklaration
$plNickname = "Uwe"; // der Variable $plNickname wird der Wert Uwe
zugewiesen
Listing 2.1: PHP erkennt Variablen immer am $-Zeichen, das ohne Leerzeichen direkt vor dem Namen der
Variable stehen muss.
In sehr vielen anderen Programmiersprachen muss eine Variable vor ihrer Verwen-
dung deklariert, d.h. ins Leben gerufen werden. Würde dies nicht erfolgen, könnte
man mit der gewünschten Variable nicht arbeiten, da sie noch nicht existiert. Da wir
PHP als serverseitige Programmiersprache verwenden, wäre es eigentlich nicht nötig,
Variablen am Anfang eines Scripts zu deklarieren. Jedoch sollten Sie sich trotzdem
angewöhnen, Variablen immer anzugeben, da Sie dadurch einen besseren Überblick
über die verwendeten Variablen erhalten.
PHPPHP
Variablen-
deklaration
immer am
Anfang
Variablen-
deklaration
immer am
Anfang
G R U N D L A G E N D E R P R O G R A M M I E R U N G 9
Befehle abschließen
Im obigen Fall finden Sie noch einen weiteren Punkt, der bei der Programmierung
wichtig ist: Wie Sie sehen, ist jede Zeile mit einem Strichpunkt abgeschlossen. Dies ist
in PHP zwingend notwendig, in Flash nicht.
Variablentypen
In Flash verhält es sich ähnlich, jedoch hat man seit der Einführung von ActionScript
2.0 die Möglichkeit, Variablen explizit zu deklarieren, wovon Sie auch Gebrauch
machen sollten. Wie Sie gleich im nächsten Abschnitt sehen werden, sollte bei guter
Programmierung in Flash neben dem „Erwähnen“ der Variable über deren Namen
auch der Typ der Variable angegeben werden. Würden wir das Beispiel aus PHP von
oben umsetzen, so würde das wie folgt aussehen:
var plNickname:String;
plNickname = "Uwe";
Listing 2.2: Variablendeklaration und anschließende Wertzuweisung in Flash
In der ersten Zeile wird eine Variable vom Typ String (das ist ein Text) angelegt. Dies
bedeutet nichts anderes, als dass in dieser Variablen nur Textwerte gespeichert werden.
In der zweiten Zeile wird dieser Variablen der Wert „Uwe“ zugewiesen. Bitte beachten
Sie an dieser Stelle, dass String-Werte immer in Anführungszeichen stehen.
Kürzt man die beiden Zeilen noch etwas ab, so erhält man nachfolgenden Code, in
dem gleichzeitig mit der Variablendeklaration auch eine Wertzuweisung erfolgt:
var plNickname:String = "Uwe";
Listing 2.3: Variablendeklaration und gleichzeitige Wertzuweisung
Somit wissen wir, wie man Variablen anlegt und ihnen einen Wert zuweist. Jetzt müs-
sen wir uns kurz Gedanken darüber machen, welche Variablennamen gültig sind und
welche nicht.
In JavaScript wird wie in PHP bei der Variablendeklaration nicht zwischen verschie-
denen Variablentypen unterschieden, deshalb erfolgt die Zuweisung wie folgt:
var plNickname = "Uwe";
Listing 2.4: Variablendeklaration und anschließende Wertzuweisung in JavaScript
2.3.2 Variablennamen
Bei der Namensgebung der Variablen in Flash, JavaScript und PHP müssen Sie einige
Regeln strikt beachten:
ActionScriptActionScript
JavaScriptJavaScript
K A P I T E L 210
Variablen …
müssen in PHP mit einem Dollarzeichen „$“ beginnen (in Flash und JavaScript ist
dies nicht der Fall).
dürfen keine Leerzeichen enthalten.
dürfen nur aus Buchstaben und Ziffern bestehen, wobei das erste Zeichen nach
dem Dollarzeichen ein Buchstabe sein muss.
dürfen Groß- und Kleinbuchstaben enthalten. PHP und ActionScript (ab Version
2.0) sind Case-sensitive und erkennen die Unterschiede.
dürfen keine Umlaute wie ä, ö, ü und kein ß enthalten.
dürfen als einziges Sonderzeichen den Unterstrich „_“ enthalten.
dürfen nicht wie Befehle der Sprache PHP, JavaScript bzw. ActionScript benannt
sein (eine Auflistung aller Befehle entnehmen Sie bitte den jeweiligen Sprachrefe-
renzen).
Bitte gewöhnen Sie sich an, für die „Taufe“ der Variablen möglichst selbst erklärende
Namen zu verwenden. Damit sind Sie (und auch andere Personen) in der Lage, Ihren
Code auch später schnell und unmissverständlich zu lesen und zu erfassen. Originali-
tät bei der Namensvergabe wäre hier völlig fehl am Platz.
2.3.3 Datentypen
Der Typ der Daten legt verbindlich fest, welcher Inhalt in den Variablen gespeichert
werden kann. Man kann auch sagen, dass der Datentyp die Art der Information
beschreibt, die in der Variable gespeichert werden soll.
In PHP gibt es folgende Datentypen:
Ganze Zahlen (Integer)
Zahlen mit Nachkommastellen (Float)
Zeichenketten (String)
Felder (Array)
Objekte
Zum Glück müssen wir uns in PHP und JavaScript über den Inhalt von Variablen
wenig Gedanken machen. PHP und JavaScript entscheiden nämlich selbst, welcher
Datentyp für welchen Inhalt verwendet werden soll. So kann es durchaus vorkommen,
dass eine Variable im Laufe eines Programms ihren Datentyp selbstständig ändert.
u
u
u
u
u
u
u
u
u
u
u
u
PHPPHP
G R U N D L A G E N D E R P R O G R A M M I E R U N G 11
Ein kleines Beispiel in PHP:
<?php
//Anlegen der Variablen
$plNickname = "Uwe"; // Uwe wird in der Variable $plNickname
gespeichert. (Typ: String)
$pointsUwe = 24.3; // Variable $pointsUwe bekommt den Wert 24,3 (Typ:
Float)
$bonuspoints = 10; // Variable $bonuspoints bekommt den Wert 10 (Typ:
Integer)
$final_points = 15; // Variable $final_points hat den Wert 15 (Typ: Integer)
//Berechnung der neuen final_points
$final_points = $pointsUwe + $bonuspoints;
?>
<html>
<head><title>Uebung Variablen / Datentyp</title></head>
<body>
<?php
echo("Endstand von ");
echo($plNickname);
echo(": ");
echo($final_points;)
?>
</body>
</html>
Listing 2.5: PHP-Code in einer HTML-Seite
Die Variable $finalpoints hatte zu Beginn des Programms den Datentyp „Integer“.
Nach der Neuberechnung des Endstands wurde in der Variable $final_points der
Fließkommawert „34.3“ gespeichert. Somit hat sich der Datentyp von „Integer“ zu
„Float“ geändert.
In Flash sieht die Sachlage ähnlich, wenn auch etwas unterschiedlich aus. Flash unter-
scheidet zwischen „Grunddatentypen“ und „Referenzdatentypen“ (oder „integrierten
Datentypen“). Des Weiteren existieren die speziellen Datentypen Null und undefi-
ned.
ActionScriptActionScript
K A P I T E L 212
Grunddatentypen sind:
Number: numerische Variablen (Zahlen)
String: Textvariablen
Boolean: Variablen, die nur die Werte true oder false speichern können
Diese Datentypen werden verwendet, um mit Variablen zu arbeiten. Die Referenzda-
tentypen (oder „integrierte Datentypen“) werden hingegen eingesetzt, um einerseits
mit MovieClips zu arbeiten, und andererseits, um komplexere Objekte zu erstellen
– auf die meisten Vertreter der Referenzdatentypen werden wir später noch zu spre-
chen kommen.
Referenzdatentypen sind also unter anderem:
MovieClip
TextField
Date
Der Datentyp Null deutet an, dass hier kein Wert existiert bzw. keine Daten vorhan-
den sind. undefined kennzeichnet, dass einer Variable noch kein Wert zugewiesen
wurde.
Seit ActionScript 3.0 existieren neben Number nun auch die numerischen Datentypen
int (Integer) und uint, wobei uint für „unsigned integer“ (Ganzzahl ohne Vorzei-
chen) steht:
int: eine Ganzzahl (= Zahl ohne Kommastelle)
uint: eine Ganzzahl ohne Vorzeichen (somit können nur Zahlen größer oder
gleich 0 gespeichert werden)
Datentypen bei der Deklaration
Um nun Variablen verschiedener Datentypen zu deklarieren, wird der Datentyp nach
dem Variablennamen und einem (deklarierenden) Doppelpunkt geschrieben. Die
Syntax lautet wie folgt:
var Variablenname:Datentyp;
Listing 2.6: Variablendeklaration mit Datentyp
Wird der Datentyp angegeben (was nicht zwingend erforderlich ist – siehe hierzu
auch die Info-Box „Automatische versus strikte Typisierung“), nennt man dies „Strikte
Typisierung“. Angewandt auf einige Beispiele sieht das Ganze dann so aus:
var myNumber:Number = 17;
var myString:String = "Uwe";
u
u
u
u
u
u
u
u
ActionScript 3.0:
int und uint
ActionScript 3.0:
int und uint
G R U N D L A G E N D E R P R O G R A M M I E R U N G 13
var myBoolean:Boolean = true;
trace("Der Wert der (nicht existenten) Variable myNumber2="+myNumber2);
Listing 2.7: Beispiele einiger Variablendeklarationen inklusive Wertzuweisung
Automatische versus strikte Typisierung (ActionScript 1.0 und 2.0)
Grundsätzlich muss im Rahmen von Flash der Datentyp nicht explizit angegeben werden, denn
Flash erzeugt bei der Wertzuweisung automatisch den korrekten Datentyp, wie Sie in der nach-
folgenden Zeile sehen:
var myNumber = 17;
Nachteilig an dieser sogenannten „Automatischen Typisierung“ ist, dass der Code fehleranfälliger
wird, da man in solchen Fällen einer Variable vom (angedachten) Typ Number auch beispiels-
weise einen String-Wert zuweisen könnte.
Im Fall der „Strikten Typisierung“ kann dies nicht geschehen und der Compiler von Flash würde
beim Veröffentlichen eine entsprechende Fehlermeldung erzeugen. Deshalb der Tipp: Versuchen
Sie immer, eine strikte Typisierung zu verwenden.
ActionScript 3.0 erfordert in jedem Fall eine strikte Typisierung. Es ist zwar eine Typ-
umwandlung möglich, standardmäßig erfordert ActionScript 3.0 jedoch eine strikte
Typisierung.
2.3.4 Gültigkeitsbereiche von Variablen
Der Gültigkeitsbereich einer Variablen gibt an, in welchem Bereich des Codes eine
Variable gültig ist. Anders gesprochen: Der Gültigkeitsbereich soll ausdrücken, wo im
Code der Wert der Variable verfügbar ist und wo nicht. Außerhalb des Gültigkeits-
bereichs existiert die Variable dann ganz einfach nicht (oder nicht mehr). Insbeson-
dere im Rahmen von Funktionen und speziellen Codeblöcken (PHP, JavaScript und
ActionScript) müssen wir uns um Gültigkeitsbereiche Gedanken machen.
Grundlegend unterscheidet man zwischen zwei Bereichen (drei hingegen für Action-
Script):
Lokale Variablen: Diese sind nur innerhalb eines gewissen Codeblocks gültig und
verlieren mit dem Ende des Codeblocks ihre Gültigkeit. Sie werden z.B. innerhalb
von Funktionen und Schleifen eingesetzt.
Globale Variablen: Diese sind überall gültig und verlieren ihre Gültigkeit erst mit
Ende des Scripts. In ActionScript 3.0 wurden globale Variablen entfernt.
Zeitleistenvariablen (nur in ActionScript): Diese sind für alle Codeblöcke inner-
halb der Zeitleiste verfügbar.
Im Rahmen der bisher erlernten Programmierung müssen Sie sich noch keine Gedan-
ken über lokale, globale und Zeitleistenvariablen machen. Mit Einführung von Funk-
tionen wird sich dies ändern, aber darauf werden wir Sie zu gegebenem Zeitpunkt
noch konkret hinweisen.
u
u
u
ActionScript 3.0ActionScript 3.0
K A P I T E L 214
Flash: nicht deklarierte lokale Variablen in Codeblöcken
In Flash unterscheiden wir zwischen deklarierten und nicht deklarierten Variablen innerhalb von
Codeblöcken, beispielsweise Funktionen. Wird eine Variable implizit deklariert (d. h., es wird ihr
ein Wert zugewiesen, ohne dass die Variable zuvor mit var deklariert wurde), verliert die Variable
erst bei Ende des Scripts ihre Gültigkeit. Anders bei deklarierten Variablen: Diese verlieren mit
Ende des Codeblocks ihre Gültigkeit!
Superglobale Variablen und Arrays
Superglobale Arrays kennt nur PHP. In Flash (bis einschließlich ActionScript 2.0)
existiert ein ähnliches Array namens _global. Anhand des Namens „superglobal“
erahnen Sie wahrscheinlich schon den Sinn dieser Variablen.
Superglobale Variablen sind zu jeder Zeit und an jeder Stelle in einem Script bekannt
und somit les- und veränderbar. Diese werden PHP-intern in einem Array gespeichert.
Was genau ein Array ist und wozu man sie verwenden kann, können Sie in diesem
Kapitel in Abschnitt 2.5 nachlesen.
Der Name des Arrays lautet $GLOBALS[]. Den Einsatz von $GLOBALS[] sollten wir für
ein leichteres Verständnis in einem Beispiel genauer betrachten.
// Definition der Variable textstring
$textstring = "Info in der Variable textstring";
// Eine Funktion zum Anzeigen des Variableninhalts
function showData {
echo("Der Inhalt der Variable lautet: $textstring");
}
showData();
Listing 2.8: Der Inhalt der Variable $textstring soll ausgegeben werden.
Leider wird aber im Browser der Inhalt der Variable $textstring nicht angezeigt.
Dies liegt einzig und allein daran, dass innerhalb einer Funktion Variablen nicht
bekannt sind, die außerhalb dieser Funktion definiert wurden. Es existiert in der Funk-
tion showData() keine Variable mit dem Namen $textstring. Um dieses Problem
nun zu lösen, werden wir $GLOBALS[] einsetzen.
// Definition der Variable textstring
$textstring = "Info in der Variable textstring";
// Eine Funktion zum Anzeigen des Variableninhalts
function showData {
echo("Der Inhalt der Variable lautet: ".$GLOBALS[textstring]);
}
showData();
Listing 2.9: Mit dem Array $GLOBALS[] kann die Variable ausgelesen werden.
PHPPHP
G R U N D L A G E N D E R P R O G R A M M I E R U N G 15
Wie Sie erkennen, haben wir nicht sehr viel geändert. Innerhalb der Funktion greifen
wir nun nicht mehr auf die Variable $textstring, sondern auf das Element text-
string im Array $GLOBALS[] zu. Bitte beachten Sie, dass der Parameter des Arrays
– also der Variablenname – ohne führendes $-Zeichen aufgerufen werden kann.
PHP kennt noch weitere superglobale Arrays, die uns die Arbeit zum Beispiel mit For-
mulardaten sehr erleichtern:
$GLOBALS
$_SERVER
$_GET
$_POST
$_COOKIE
$_FILES
$_ENV
$_REQUEST
$_SESSION
Formulardaten versenden
Im ersten Kapitel dieses Buchs hörten Sie bereits von GET und POST. Wenn Sie Formu-
lardaten von einer Seite zu einer anderen Seite schicken und die gesendeten Daten wei-
terverarbeiten möchten, benötigen Sie die superglobalen Arrays $_GET oder $_POST,
wenn in der php.ini die Einstellung register_globals auf off gesetzt ist.
Angenommen, Sie haben ein Kontaktformular für Ihre User erstellt, in dem ein Text-
feld mit dem Namen „Vorname“ existiert. Beim Absenden des Formulars wird der
Inhalt dieses Textfelds an eine weitere PHP-Seite geschickt. Nun haben Sie zwei Mög-
lichkeiten zum Auslesen des Textfelds, je nachdem, ob register_globals auf off
oder on gesetzt ist.
Wenn off eingestellt ist, dann können Sie nur über das superglobale Array $_POST
(oder $_GET) auf den Inhalt des Textfelds „Vorname“ zugreifen.
$_POST[‚Vorname'];
Im zweiten Fall (register_globals ist on) können Sie mit $Vorname direkt
auf den Inhalt des Textfelds zugreifen. Der Name der Variable ist automatisch der
Name des Textfelds.
Sollten Sie noch nähere Information über die restlichen superglobalen Arrays benö-
tigen, bitten wir Sie, in der PHP-Referenz nachzuschlagen. Diese finden Sie auch im
Internet unter www.php.net.
u
u
u
u
u
u
u
u
u
u
u
u
register_globalsregister_globals
K A P I T E L 216
Tipp: Ich würde Ihnen in jedem Fall empfehlen, die Eigenschaft register_globals
auf off zu belassen (oder zu setzen), auch wenn es scheinbar einfacher wäre, wenn sie
on ist. register_globals stellt eine nicht zu unterschätzende Sicherheitslücke dar,
da PHP keinen Unterschied zwischen einer GET- oder POST-Variable mit gleichem
Namen machen kann.
Globale Variablen (und Funktionen) sind Variablen, die in allen Zeitleisten und allen
Hierarchiebereichen, also Gültigkeitsbereichen, verfügbar sind. Lokale Variablen
haben dagegen nur einen eingeschränkten Gültigkeitsbereich.
Um eine globale Variable zu erzeugen, wird der Variable der Bezeichner _global
vorangestellt. Globale Variablen werden nicht mit var deklariert und ihnen werden
auch keine Datentypen zugewiesen.
_global.myNumberGlobal = 17;
Listing 2.10: Deklaration einer globalen Variable in ActionScript
var myNumberLocal:Number = 17;
Listing 2.11: Deklaration einer lokalen Variable in ActionScript
Globale versus lokale Variablen
Der Sinn der globalen Variable ist, dass sie von überall aus zugänglich ist. Natürlich wäre es
nett, wenn jede Variable von überall aus zugänglich wäre, frei nach dem Motto „Weg frei für die
Globalisierung jeder Variable“ ...
Ein guter Programmierer zeichnet sich aber auch dadurch aus, dass er weiß, wann eine Variable
global sein muss und wann eine Variable lokal sein kann. Zumeist werden Variablen nur für
gewisse Bereiche benötigt – deshalb die Regel: lokal vor global!
In ActionScript 3.0 existiert das Array _globals nicht mehr. Vielmehr behandelt
ActionScript 3.0 alle Variablen als global, die in der root-Ebene eines Clips (oder einer
externen ActionScript-Datei) definiert wurden.
In JavaScript verhält es sich ähnlich wie in ActionScript – global sind Variablen dann,
wenn sie auf äußerster Ebene erzeugt wurden. Beispiel:
var global01 = 15;
function showVariables() {
var nichtglobal = 17;
alert("INNERHALB: global01="+global01+"; nichtglobal="+nichtglobal);
}
showVariables();
alert("AUSSERHALB: global01="+global01+"; nichtglobal="+nichtglobal);
Listing 2.12: Ein Beispiel für globale und lokale Variablen
ActionScript bis
inklusive 2.0
ActionScript bis
inklusive 2.0
ActionScript 3.0ActionScript 3.0
JavaScriptJavaScript
G R U N D L A G E N D E R P R O G R A M M I E R U N G 17
Außerhalb der Funktion showVariables wird eine Variable global01 angelegt. Da
diese Variable global ist, kann sie innerhalb der Funktion showVariables abgerufen
werden: Wird die Funktion showVariables aufgerufen (vorletzte Zeile), so erhalten
Sie eine funktionierende alert-Ausgabe. Innerhalb der Funktion wird zusätzlich noch
die lokale Variable nichtglobal definiert. Greift man nun von „außen“ auf die loka-
le Variable nichtglobal zu, so erhält man einen Fehler, da diese Variable eben nur
innerhalb der Funktion showVariables existiert.
2.4 Operatoren
Operatoren dienen dem Zweck, Variablenwerte miteinander zu kombinieren. Dies
kann einerseits eine einfache arithmetische Addition sein, andererseits aber auch dazu
dienen, logische Verknüpfungen von Zuständen zu erzeugen.
2.4.1 Arithmetische Operatoren
Wie der Name schon sagt, handelt es sich hierbei um eine mathematische Verknüpfung
von Werten. Im folgenden Beispiel sehen Sie die Anwendung der Operation „Addi-
tion“ oder „+“:
$anzahl1 = 23;
$anzahl2 = 15;
$anzahl3; //bis jetzt wurde anzahl3 noch kein Wert zugewiesen
$anzahl3 = $anzahl1 + $anzahl2;
Listing 2.13: Eine Addition in PHP ...
var anzahl1 = 23;
var anzahl2 = 15;
var anzahl3;
anzahl3 = anzahl1+anzahl2;
Listing 2.14: ... in JavaScript ...
var anzahl1:Number = 23;
var anzahl2:Number = 15;
var anzahl3:Number;
anzahl3 = anzahl1+anzahl2;
Listing 2.15: ... und in Flash
PHPPHP
JavaScriptJavaScript
ActionScriptActionScript
K A P I T E L 218
Operatoren
Numerische Werte kann man mithilfe von folgenden Operatoren miteinander ver-
knüpfen: Nehmen wir für das Beispiel in der Tabelle an, die Variablen $a (bzw. a) und
$b (bzw. b) erhalten die Werte $a=22 und $b=5. In $c (bzw. c) wird das Ergebnis der
Berechnung gespeichert.
Operator Operation Beispiel
+ Addition (dies gilt in JavaScript und
Flash für numerische ebenso wie für
String-Variablen)
$c=$a+$b; (PHP) bzw.c=a+b; (JavaScript,
Flash) liefert $c=27
- Subtraktion $c=$a-$b; (PHP) bzw.c=a-b; (JavaScript,Flash)
liefert $c=17
* Multiplikation $c=$a*$b; (PHP) bzw.c=a*b; (JavaScript,Flash)
liefert $c=110
/ Division $c=$a/$b; (PHP) bzw.c=a/b; (JavaScript,Flash)
liefert $c=4.4
% Modulo-Rechnung (gibt den Rest
einer Division zurück)
$c=$a%$b; (PHP) bzw.c=a%b; (JavaScript,Flash)
liefert $c=2
Tabelle 2.1: Arithmetische Operatoren
Inkrement und Dekrement
Um Werte um eins zu erhöhen oder zu verringern, können Sie die Inkrement- und
Dekrementoperatoren verwenden.
$variable++;
$variable--;
Listing 2.16: In PHP ...
variable++;
variable--;
Listing 2.17: ... und in JavaScript bzw. Flash
2.4.2 Zuweisungsoperatoren
Ein Zuweisungsoperator ist Ihnen auf den vorigen Seiten bereits begegnet. Es handelt
sich hierbei im einfachsten Fall um das Gleichheitszeichen „=“. Es ist dafür bestimmt,
einer Variable einen Wert zuzuweisen.
Neben dieser Art von Zuweisung existieren jedoch auch noch weitere Zuweisungsope-
ratoren, die Sie in Tabelle 2.2 aufgelistet sehen. Der verwendete Wert kann selbstver-
ständlich auch eine Variable sein – in diesem Fall passiert nichts anderes, als dass der
Inhalt, sprich der Wert der Variable, ausgelesen und dieser Inhalt für die Berechnung
herangezogen wird. Die Zuweisungen gelten dabei immer von rechts nach links.
PHPPHP
JavaScript und
ActionScript
JavaScript und
ActionScript
G R U N D L A G E N D E R P R O G R A M M I E R U N G 19
Zuweisungsoperator Operation
variable = Wert Einer Variable wird ein Wert zugewiesen.
variable += Wert Eine Variable wird um einen Wert erhöht
variable -= Wert Eine Variable wird um einen Wert verringert.
variable *= Wert Eine Variable wird mit einem Wert multipliziert.
variable /= Wert Eine Variable wird durch einen Wert dividiert.
variable %= Wert Einer Variable wird durch einen Wert dividiert und es wird ihr der
Restwert der Division zugewiesen.
Tabelle 2.2: Mögliche Arten von arithmetischen Zuweisungsoperatoren. Wie Sie bereits wissen, muss eine
PHP-Variable selbstverständlich ein führendes $-Zeichen besitzen.
Ein Beispiel für die Anwendung des Operators +=, der zu einer Variable den Wert einer
zweiten Variable hinzuaddiert:
$variable1 = 23; // variable1 bekommt den Wert 23
$variable2 = 20; // variable2 bekommt den Wert 20
$variable1 += $variable2; // variable2 wird zu variable1 addiert
Listing 2.18: Der Operator += in PHP …
var variable1 = 23;
var variable2 = 20;
variable1 += variable2;
Listing 2.19: ... in JavaScript ...
var variable1:Number = 23;
var variable2:Number = 20;
variable1 += variable2;
Listing 2.20: ... und in Flash
In unserem Beispiel hat die variable1 nach der Addition den Wert 43, variable2
dagegen weiterhin den Wert 20.
Ein weiteres Beispiel für eine Anwendung des Modulo-Operators %, der den Restwert
einer Division berechnet:
$variable1 = 23; // variable1 bekommt den Wert 23
$variable2 = 20; // variable2 bekommt den Wert 20
$variable3 = variable1 % $variable2; //Ergebnis: 3
Der Modulo-Operator in PHP …
var variable1 = 23; // variable1 bekommt den Wert 23
var variable2 = 20; // variable2 bekommt den Wert 20
var variable3 = variable1 % variable2; //Ergebnis: 3
Listing 2.21: ... in JavaScript ...
PHPPHP
JavaScriptJavaScript
ActionScriptActionScript
PHPPHP
JavaScriptJavaScript
K A P I T E L 220
var variable1:Number = 23;
var variable2:Number = 20;
var variable3:Number = variable1 % variable2; //Ergebnis: 3
Listing 2.22: ... und in Flash
Die Modulo-Rechnung ist prinzipiell einfach zu verstehen, denn die Berechnung folgt
dem gleichen Prinzip, wie Sie es aus der Volksschule kennen: Möchte man eine Zahl
durch eine andere dividieren, so versucht man zunächst zu erkennen, wie oft die eine
Zahl in der zweiten Zahl vorkommt, bis man letztendlich zu den Kommazahlen der
Division gelangt. In unserem Beispiel ist die erste Zahl 23 und die zweite Zahl 20.
Rechnet man 23 dividiert durch 20, so ist leicht zu erkennen, dass 20 in 23 genau ein
Mal vorkommt und der Wert 3 als Rest übrig bleibt, also:
23/20 = 1 Rest 3
Die Modulo-Rechnung gibt Ihnen genau diese Restzahl als Ergebnis zurück, also:
23%20 = 3
Einige weitere Beispiele zur Modulo-Rechnung:
23%5 = 3
23%6 = 5
23%23 = 0
8%2 = 0
Verknüpfung von Strings
Ein weiterer wichtiger Operator dient zur Verknüpfung von Strings.
In PHP wird dafür der Operator .= verwendet. In unserem Beispiel aus Listing 2.23
würde die Variable text nach der Zuweisung den Text „Name = Uwe“ im Browser
ausgeben.
$text = "Name = ";
$text .= "Uwe";
Listing 2.23: Verknüpfung von Texten in PHP
In JavaScript und ActionScript erfolgt die Verknüpfung von Texten mithilfe des Addi-
tions-Operators +=. Die Ausgabe würde hier „Name = Uwe“ lauten.
var myText = "Name = ";
myText += "Uwe";
Listing 2.24: Verknüpfung von Texten in JavaScript ...
ActionScriptActionScript
PHPPHP
JavaScript und
ActionScript
JavaScript und
ActionScript
G R U N D L A G E N D E R P R O G R A M M I E R U N G 21
var myText:String = "Name = ";
myText += "Uwe";
Listing 2.25: ... und in ActionScript
2.4.3 Bitoperatoren
Bitoperatoren sind hier nur der Vollständigkeit halber erwähnt. Sie werden bei Variab-
len mit Werten in Bit- oder Byteform eingesetzt. Nähere Informationen dazu entneh-
men Sie bitte der jeweiligen Sprachreferenz.
2.4.4 Logische Operatoren
Logische Operatoren zählen sicher zu den wichtigsten Bestandteilen einer Program-
miersprache. Sie werden dafür verwendet, um Zustände (true oder false) mitein-
ander zu verknüpfen. Beispielsweise könnte man bei einer elektrischen Wechselschal-
tung entweder den einen oder den anderen Lichtschalter betätigen, damit das Licht
aufleuchtet – in diesem Fall würde man die beiden Lichtschalter gedanklich mit einem
„oder“ verknüpfen.
Logische Operatoren Operation
and logische UND-Verknüpfung (in Flash veraltet)
&& logische UND-Verknüpfung
or logische ODER-Verknüpfung (in Flash veraltet)
xor logische Entweder-oder-Verknüpfung (gilt nur für PHP)
|| logische ODER-Verknüpfung
! logisches NICHT
Tabelle 2.3: Die wichtigsten logischen Operatoren
Punkt vor Strich
Wichtig ist immer die Rangordnung der Operatoren: Ähnlich wie in der Mathematik-
stunde in der Schule gilt die Punkt-vor-Strich-Regel, wobei && der Punkt- und || der
Strichrechnung zuzuweisen ist. Sollte ein Rechenvorgang allein mit Punkt- und Strich-
rechnung nicht ausführbar sein, stehen Ihnen genau wie in der Algebra Klammern zur
Verfügung, wobei dieselben Klammersetzungsregeln gelten.
Werte prüfen
Mit den logischen Operatoren ist es weiterhin möglich, in Kombination mit Bedingungen Werte
auf „Richtig“ (true) oder „Falsch“ (false) zu prüfen. Beispiele finden Sie etwas später bei den
Bedingungen im Abschnitt 2.6.
Der Grund für jeweils zwei logische UND- und ODER-Verknüpfungen in PHP liegt
einzig in der Rangordnung der Operatoren: && ist „stärker“ als and und wird deshalb
zuerst ausgeführt; Gleiches gilt für || vor or.
K A P I T E L 222
Die Wirkungsweise der einzelnen Operationen sehen Sie in der nachfolgenden Tabelle.
Variable 1 Variable 2 AND- (&&-) Verknüpfung OR- (||-) Verknüpfung XOR-Verknüpfung
(nur PHP)
false false false false false
false true false true true
true false false true true
true true true true false
Tabelle 2.4: Verschiedene Verknüpfungsoperatoren angewandt auf zwei Variablen
2.4.5 Vergleichsoperatoren
Um Werte miteinander zu vergleichen, benötigen wir Vergleichsoperatoren. Folgende
Möglichkeiten stehen uns dabei zur Verfügung:
Vergleichsoperatoren Operation
== Gleichheit der Werte
!= Ungleichheit der Werte
=== Gleichheit der Werte und des Datentyps („Strikte Gleichheit“)
!== Ungleichheit der Werte oder des Datentyps („Strikte Ungleichheit“)
> größer als
< kleiner als
>= größer als oder gleich
<= kleiner als oder gleich
Tabelle 2.5: Vergleichsoperatoren
Das Resultat eines Vergleiches ist immer ein boolescher Wert, denn einem Vergleich
geht stets eine „Frage“ voran, wobei die Antwort auf diese Frage immer entweder „ja“
(true) oder „nein“ (false) lautet. Der Vergleich selbst ist nichts anderes als beispiels-
weise die Frage, ob ein Wert kleiner gleich einem anderen Wert ist.
2.4.6 Rangordnung der Operatoren
Nachfolgend finden Sie die Rangordnung der Operatoren, wobei diejenigen, die in
derselben Zeile aufgeführt sind, gleichberechtigt sind. Am stärksten sind demnach die
Operatoren !, ~, ++ und --, am schwächsten das or (die bitweisen Operatoren haben
wir in diese Liste ebenso mit aufgenommen):
1. ! , ~, ++, --
2. *, /, %
3. +, -, .
4. <<, >>
5. <, <=, >, >=
G R U N D L A G E N D E R P R O G R A M M I E R U N G 23
6. ==, != , ===, !==
7. &
8. |
9. &&
10. ||
11. ?, :
12. =, +=, -=, *=, /=, .= , %=, &=, |=, <<=, >>=
13. and
14. or
In folgendem Beispiel wird mit diesen Rangordnungen gearbeitet.
var a:Number = 17, b:Number = -3, c:Number = 11;
var d:Number = 200, ergB:Boolean, ergN:Number;
var bool1:Boolean = true, bool2:Boolean = false;
ergN = ++a*17-d; //(1+17)*17-200=106; a hat sich von 17 auf 18 erhöht
ergB = ergN==89 //false
ergN = (a*d+b)%5-c*d; // (18*200-3)%5-11*200 = 3597%5-2200 = 2-2200 = -2198
ergB = ergN !=-250 && bool2;
/* Erklärung:
Zunächst wird überprüft, ob der Inhalt von ergN ungleich (!=) -250 ist.
Nachdem dies der Fall ist, ergibt der Vergleich den Wert true. Dieser
wird danach mit dem Inhalt von bool2 mit UND verknüpft. Da bool2 den
Wert false aufweist, ist das Ergebnis der UND-Verknüpfung ebenfalls
false. Somit wird der Variable ergB der Wert false zugewiesen. Beachten
Sie bitte, dass sich a durch die Operation ++a von 17 auf 18 erhöht hat!
-2198!=250 && false = true && false = false
*/
Listing 2.26: Einige Beispiele zur Reihenfolge von Operationen
K A P I T E L 224
2.5 Arrays
Arrays sind für die Arbeit eines jeden Programmierers von großer Bedeutung. Sie
können sich einen Array als einen Datenpool oder – einfacher – als Tabelle vorstellen.
Jeder dieser Werte des Datenpools ist in einem eigenen Bereich gespeichert. Arrays
könnte man auch mit einem Setzkasten vergleichen, in dem jede Figur einen eigenen
Platz hat.
Am Anfang dieses Kapitels haben wir für ein Online-Spiel den Nicknamen des Users
benötigt. Wenn wir nun dieses Beispiel erweitern und pro User zusätzliche Daten wie
Vorname, Nachname, Adresse und Wohnort speichern möchten, benötigten wir sehr
viele Variablen, vor allem wenn mehrere User an unserem Online-Spiel teilnehmen.
Dieses Problem können wir mit Arrays in den Griff bekommen.
Zunächst einmal die Syntax zur Array-Erstellung:
$myArray = array();
Listing 2.27: In PHP ...
var myArray = new Array();
Listing 2.28: ... in JavaScript ...
var myArray:Array = new Array();
Listing 2.29: ... und in Flash
Arrays in Flash und JavaScript
In JavaScript und Flash spricht man im Fall von Arrays von „Objekten“ (man spricht auch von der
„Klasse der Arrays“), in PHP gehören sie zu den „komplexen Datentypen“. Bei der Verwendung
in JavaScript und Flash ist daher darauf zu achten, dass beim Erzeugen der Konstruktor new
Array() verwendet wird.
Es gibt unterschiedliche Arten, Werte in den Arrays zu speichern: Unterschieden wird
dabei zwischen indizierten und assoziativen Arrays.
2.5.1 Indizierte Arrays
Die Werte eines Arrays werden immer durch eine fortlaufende Nummer gekennzeich-
net. Indizierte Arrays beginnen immer bei 0, deshalb spricht man gern von „zero-
based“ Elementen. Das zweite Element des Arrays bekommt die Nummer 1, das dritte
die Nummer 2 zugewiesen usw. Das letzte Element eines Arrays mit fünf Elementen
hat also die Nummer 4.
$arrUser = array("Uwe", "Uwe", "Mutz");
Listing 2.30: In PHP ...
Arrays erstellenArrays erstellen
Werte in Arrays
speichern
Werte in Arrays
speichern
G R U N D L A G E N D E R P R O G R A M M I E R U N G 25
var arrUser = new Array("Uwe", "Uwe", "Mutz");
Listing 2.31: ... in JavaScript ...
var arrUser:Array = new Array("Uwe", "Uwe", "Mutz");
Listing 2.32: ... und in Flash
Möchten wir nun den Usernamen des Users aus dem Array $arrUser/arrUser aus-
geben, müssten wir folgenden Code schreiben.
echo($arrUser[0]); //Ausgabe in den Browser
Listing 2.33: In PHP ...
alert(arrUser[0]); //Ausgabe in einer Alert-Box
Listing 2.34: ... in JavaScript ...
trace(arrUser[0]); //Ausgabe in das Ausgabefenster
Listing 2.35: ... und in Flash
Elementname Nummer (Index) des Elements Wert
$arrUser[0] 0 Uwe
$arrUser[1] 1 Uwe
$arrUser[2] 2 Mutz
Tabelle 2.6: Inhalte des indizierten Arrays $arrUser (gleichermaßen gültig für arrUser in JavaScript
und Flash)
2.5.2 Assoziative Arrays
Bei einem assoziativen Array („Hash-Table“) werden die Werte nicht durch fortlau-
fende Nummern gekennzeichnet, sondern durch eine eindeutige Bezeichnung wie bei
Variablen.
Arrays erstellen
Das Erzeugen „echter“ assoziativer Arrays ist nur in PHP möglich – in JavaScript und
ActionScript läuft die Sache etwas anders, denn hier müsste man Objekte in Arrays
verschachteln – sollten Sie „um die Burg“ assoziative Arrays in Flash oder JavaScript
benötigen, so empfehle ich Ihnen die ActionScript- bzw. JavaScript-Referenz.
Werfen wir zunächst einen Blick auf PHP. Um diesen Array-Typ zu erstellen, benötigen
wir den Operator =>.
$arrUser = array(
"Nickname" => "Uwe",
"Vorname" => "Uwe",
PHPPHP
K A P I T E L 226
"Nachname" => "Mutz"
);
Jetzt hat jeder Wert des Arrays eine eindeutige Bezeichnung erhalten. Man spricht hier
auch vom „Key“ und dessen „Value“.
Elementname Key Value
$arrUser["Nickname"] Nickname Uwe
$arrUser["Vorname"] Vorname Uwe
$arrUser["Nachname"] Nachname Mutz
Tabelle 2.7: Inhalte des assoziativen Arrays $arrUser
Mehrdimensionale Arrays
Im Moment haben wir nur eindimensionale Arrays erzeugt, die man mit einzeiligen
Tabellen vergleichen kann, bei denen alle Werte hintereinander in den Zellen der
Tabelle gespeichert werden. Möglich ist aber auch der Einsatz von mehrdimensionalen
Arrays.
Angenommen, wir möchten alle User unseres Online-Spiels mit deren Nicknamen,
Vornamen und Nachnamen speichern, so wäre der Einsatz eines mehrdimensionalen
Arrays denkbar und sinnvoll:
$arrUser = array("User1" => array("Uwe", "Uwe", "Mutz"), "User2" =>
array("Uwe", "Uwe", "Mutz"));
Das Array $arrUser hat zwei Elemente User1 und User2. Diese Elemente sind wie-
derum selbst Arrays, in denen dann die eigentlichen Werte gespeichert werden. Möch-
ten wir nun den Nachnamen des Users 2 ausgeben, schreiben wir folgenden Code:
echo($arrUser["User2"][2]);
Bei der Ausgabe müssen wir nur Schritt für Schritt vom äußersten Array in das
gewünschte Array wandern. Unser Array $arrUser beinhaltet ein assoziatives Array
namens User2 und dieses beinhaltet wiederum ein „normales“ Array. Mit [2] geben
wir somit nur die Stelle im Array User2 an, an der der Nachname gespeichert wurde.
Natürlich könnten wir das zweite Array auch assoziativ aufbauen:
$arrUser = array("User1" => array("Nickname" => "Uwe", "Vorname" =>
"Uwe", "Nachname" => "Mutz"), "User2" => array("Nickname" => "Uwe",
"Vorname" => "Uwe", "Nachname" => "Mutz"));
Um wieder den Nachnamen des zweiten Users auszugeben, schreiben wir nun:
echo($arrUser["User2"]["Nachname"]);
Äquivalent können wir dieses Beispiel in JavaScript und ActionScript nicht umsetzen,
da es wie erwähnt in JavaScript und ActionScript keine assoziativen Arrays gibt. Der
Ausweg hier führt über Objekte, die innerhalb von Arrays angelegt werden.
JavaScript und
ActionScript
JavaScript und
ActionScript
G R U N D L A G E N D E R P R O G R A M M I E R U N G 27
Mehrdimensionale Arrays (jedoch nicht assoziativ) anzulegen, ist jedoch auch in
JavaScript und ActionScript kein Problem:
var arrUser = new Array("User1", "User2"); //macht keinen Sinn!
arrUser[0] = new Array("Uwe", "Uwe", "Mutz");
arrUser[1] = new Array("Alex", "Alexander", "Grasser");
alert("Bezeichnung des ersten Eintrags der User-Tabelle: "+arrUser[0]);
alert("Nachname des zweiten Users: "+arrUser[1][2]);
Listing 2.36: Ein mehrdimensionales Array, wobei die erste Zeile in dieser Form wenig Sinn macht
Mehrdimensionale Arrays werden nach dem Muster:
var myArray = new Array();
myArray[n] = new Array();
angelegt, wobei n eine beliebige Stelle im Array ist. Sollte an Stelle n des Arrays myAr-
ray bereits ein Inhalt vorhanden sein, so wird dieser überschrieben. Aus diesem Grund
ergibt die erste Zeile in Listing 2.36 keinen Sinn, da die Einträge „User1“ und „User2“
in den nächsten Zeilen gleich wieder überschrieben werden. Sinnvoll ist daher anstatt
dieser Zeile die folgende:
var arrUser = new Array();
Selbiges gilt in Flash, wobei in diesem Fall noch die Typisierung hinzukommt:
var arrUser:Array = new Array();
arrUser[0] = new Array("Uwe", "Uwe", "Mutz");
arrUser[1] = new Array("Alex", "Alexander", "Grasser");
trace("Bezeichnung des ersten Eintrags der User-Tabelle: "+arrUser[0]);
trace("Nachname des zweiten Users: "+arrUser[1][2]);
Listing 2.37: Mehrdimensionale Arrays in Flash nach demselben Muster wie in JavaScript, nur mit zusätzli-
cher strikter Typisierung
Vielleicht haben Sie sich schon die Frage gestellt, ob es nicht eigentlich
var myArray = new Array();
var myArray[0] = new Array();
heißen müsste – also mit einem zusätzlichen var in der zweiten Zeile. Nun, diese Art
der Schreibweise ist aufgrund des inneren Aufbaus der Arrays als Objekte nicht zuläs-
sig – Details dazu finden Sie in der Objektorientierten Programmierung (OOP).
JavaScriptJavaScript
K A P I T E L 228
2.6 Bedingungen
In der Programmierung gibt es oft Situationen, in denen ein Programmblock nur unter
einer gewissen Bedingung ausgeführt werden soll. Diese Bedingung muss geprüft und
daraufhin eine Entscheidung getroffen werden, wie das Script weiterverarbeitet wer-
den soll. Fällt die Entscheidung positiv aus, wird der Programmblock ausgeführt, ist
sie negativ, kann an dieser Stelle beispielsweise abgebrochen werden.
2.6.1 if-Bedingung
Die gültige Syntax ist:
if(Bedingung) {
Programmblock, falls die Bedingung zutrifft
}
else {
Programmblock, falls die Bedingung nicht zutrifft
}
Listing 2.38: Syntax für if-Bedingungen
Was genau ist nun eine Bedingung und was liefert sie für Resultate? Nun, eine Bedin-
gung ist in den meisten Fällen ein Vergleich zweier (oder mehrerer) Werte. Man kann
Vergleiche in Bezug auf „gleich (==)“, „kleiner (<)“, „größer (>)“ usw. anstellen – das
haben Sie im letzten Abschnitt bereits erfahren. Das Resultat ist dann immer eine
Antwort des Systems, das sagt: „Wert 1 ist gleich Wert 2“ oder „Wert 1 ist nicht gleich
Wert 2“, wenn man mit == auf Gleichheit prüft. Der Programmcode für dieses Beispiel
würde folgendermaßen aussehen:
if (Wert1 == Wert2) {
//Wert1 ist gleich Wert2
}
else {
//Wert1 ist nicht gleich Wert2
}
G R U N D L A G E N D E R P R O G R A M M I E R U N G 29
Ein einfaches Beispiel vergleicht die Variablen a und b miteinander und ermittelt, wel-
che der beiden Variablen den größeren Wert beinhaltet:
$a = 23; //einen fiktiven Wert eingeben, wie z.B. 23
$b = 17;
if ($a > $b) {
echo("$a ist groesser als $b");
}
else {
echo("$b ist groesser oder gleich $a");
}
Listing 2.39: In PHP ...
var a = 23;
var b = 17;
if(a>b) {
alert("a ist groesser als b");
}
else {
alert("b ist groesser oder gleich a");
}
Listing 2.40: ... in JavaScript ...
ABBILDUNG 2.1
Schematische Darstellung
einer if-Bedingung
K A P I T E L 230
var a:Number = 23;
var b:Number = 17;
if(a>b) {
trace("a ist groesser als b");
}
else {
trace("b ist groesser oder gleich a");
}
Listing 2.41: ... und in ActionScript
Geschweifte Klammern bei Programmblöcken
Vielleicht ist Ihnen in der Syntax des obigen Beispiels aufgefallen, dass nach der Über-
prüfung der Bedingung (die übrigens immer in runden Klammern stehen muss) eine
geschweifte Klammer „{„ geöffnet wird. Dies deutet an, dass die nachfolgenden Code-
zeilen zum if-Befehl gehören. Gleiches gilt für den else-Teil.
2.6.2 switch-Bedingung
Das Problem der if-Bedingung ist, dass diese Bedingung immer nur auf einen Wert
überprüft, also eine Fallunterscheidung nur durch Verschachtelung möglich ist. Muss
auf sehr viele verschiedene Werte überprüft werden, so wird eine solche Fallunterschei-
dung mit verschachtelten if-Bedingungen sehr schnell sehr unübersichtlich. Abhilfe
schafft hier die switch-Bedingung, die eine Variable auf beliebig viele verschiedene
Werte überprüft und je nachdem verschiedene Programmblöcke ausführt. Werfen wir
einen Blick auf die Syntax:
switch (Variable) {
case Wert 1:
//Programmblock 1
break;
case Wert 2:
//Programmblock 2
break;
...
case Wert n:
//Programmblock n
break;
default:
Zeichenketten
vergleichen
Wenn Sie Zeichenketten
vergleichen, benutzen Sie
=== oder !==, da hier auch
der Datentyp verglichen
wird.
Einzeiliger
Programmcode
Sollte der Programmblock
aus nur einer einzigen
Zeile bestehen, könnte
man die geschweiften
Klammern weglassen.
In Hinblick auf andere
Programmiersprachen sollte
man sie aber auch bei nur
einer Zeile setzen.
G R U N D L A G E N D E R P R O G R A M M I E R U N G 31
//Programmblock, falls keiner der Werte auf die Variable zutrifft
}
Listing 2.42: Syntax für switch-Bedingungen
Die Variable wird Schritt für Schritt auf die Werte überprüft. Trifft einer der innerhalb
des switch-Blocks aufgelisteten Werte auf die Variable zu, so wird der zugehörige
Programmblock ausgeführt; trifft keiner der Werte auf die Variable zu, so wird der
Programmblock im default-Teil ausgeführt. Dieser default-Teil kann aber auch
gänzlich wegfallen – sollte also kein Wert auf den Inhalt der Variable zutreffen, würde
einfach gar nichts geschehen. Die break-Anweisung sorgt dafür, dass der nachfolgende
Code innerhalb der switch-Anweisung nicht mehr ausgeführt wird – hierdurch wird
das Abarbeiten des Codes schneller.
2.7 Schleifen
Ein weiterer wichtiger Bestandteil in der Programmierung sind Schleifen. Sie kommen
immer dann zum Einsatz, wenn ein Block von Befehlen mehrmals hintereinander
ablaufen soll.
Grundsätzlich unterscheidet man zwischen Schleifen mit einer festen Anzahl von
Durchläufen und solchen mit einer variablen Anzahl von Durchläufen.
2.7.1 for-Schleife
Beginnen wir bei einer Schleife mit einer festen Anzahl von Durchläufen, der for-
Schleife. Die for-Schleife benötigt drei Werte, die gesetzt werden müssen:
Startwert einer sogenannten Zähl- oder Schleifenvariable
Abbruch- oder Ende-Bedingung
Zählvariablen-Inkrement
Zählvariable
Die Zählvariable ist die Variable, die die Anzahl der Schleifendurchläufe zählt. In der
obigen Auflistung steht „Startwert einer Zählvariablen“. Dies bedeutet, dass dieser
Variablen ein Anfangswert zugewiesen wird. Oftmals wird als Startwert der Wert „0“
verwendet; es muss aber nicht so sein.
Sie sollten sich dies aber nicht so vorstellen, dass pro Schleifendurchlauf die Variable
um eins erhöht wird (was als Spezialfall natürlich möglich ist und oft verwendet wird),
sondern die Zählvariable wird um den Wert des Zählvariablen-Inkrements verändert.
Wir schreiben an dieser Stelle bewusst „verändert“ und nicht „erhöht“, weil die Vari-
u
u
u
K A P I T E L 232
able genauso um einen gewissen Wert verringert werden könnte, je nachdem, was im
Zählvariablen-Inkrement angegeben ist.
Abbruchbedingung
Die Abbruchbedingung überprüft die Zählvariable pro Schleifendurchlauf auf einen
gewissen Wert. Sollte dieser Wert (je nach Art der Bedingung) über- oder unterschrit-
ten werden, wird die Schleife abgebrochen, sprich, sie wird nicht mehr ausgeführt.
Endlosschleife
Wichtig hierbei ist, dass die Abbruchbedingung auch wirklich irgendwann erreicht
werden kann, ansonsten haben Sie eine sogenannte Endlosschleife programmiert. Dies
führt zu einer Überlastung des Prozessors und wird im Allgemeinen vom Betriebssys-
tem nach einer gewissen Zeit automatisch abgebrochen, was logischerweise zur Folge
ABBILDUNG 2.2
Schematische Darstellung
einer for-Schleife
G R U N D L A G E N D E R P R O G R A M M I E R U N G 33
hat, dass die PHP- oder Flash-Datei bzw. JavaScript-Anwendung nicht mehr weiter
ausgeführt wird.
Warum all der Aufwand mit der Zählvariable? Wenn sie nur dafür da ist, dass man die
Anzahl der Durchläufe auf alle möglichen Arten abprüft, hätte sich der Aufwand nicht
gelohnt. Der Grund dafür ist, dass die Variable selbst im Programmblock der Schleife
sehr oft als ganz normale Variable verwendet wird.
Die korrekte Syntax der for-Schleife lautet:
for(Initialisierung der Zählvariablen; Abbruchbedingung; Inkrement) {
Programmblock
}
Listing 2.43: Syntax für for-Schleifen
Initialisierung der Schleife
Die Initialisierung kann z.B. wie folgt aussehen:
for($i = 0; …) //Zählvariable $i mit Startwert 0
for($a = 23; …) //Zählvariable $a mit Startwert 23
for($i = -17; …) //Zählvariable $i mit Startwert -17
Listing 2.44: In PHP ...
for(var i:Number = 0; ...) //Zählvariable i mit Startwert 0
for(var a:Number = 23; ...) //Zählvariable a mit Startwert 23
for(var i:Number = -17; ...) //Zählvariable i mit Startwert -17
Listing 2.45: ... in JavaScript ...
for(var i = 0; ...) //Zählvariable i mit Startwert 0
for(var a = 23; ...) //Zählvariable a mit Startwert 23
for(var i = -17; ...) //Zählvariable i mit Startwert -17
Listing 2.46: ... und in Flash
Typischerweise werden als Variablennamen für Zählvariablen die Buchstaben i, j, k
usw. verwendet, einen besonderen Grund gibt es dafür wohl nicht.
Typische Abbruchbedingungen
Typische Abbruchbedingungen sind:
for($i = 0; $i<15; ...)
for($a = 23; $a>15; ...)
K A P I T E L 234
/* falls $a pro Schleifendurchlauf erhöht wird, ist die obige Schleife
eine Endlosschleife; falls $a verringert wird, wird die Abbruchbedingung
erreicht */
for(var $i = -17; $i<0; ...)
Listing 2.47: In PHP ...
for(var i = 0; i<15; ...)
for(var a = 23;a>15; ...)
for(var i = -17; i<0; ...)
Listing 2.48: ... in JavaScript ...
for(var i:Number = 0; i<15; ...)
for(var a:Number = 23;a>15; ...)
for(var i:Number = -17; i<0; ...)
Listing 2.49: ... und in Flash
Inkrement
Nun müssen wir uns noch um das Zählvariablen-Inkrement kümmern. Wir können
die Zählvariable pro Durchlauf entweder verringern oder erhöhen, die Frage ist nur,
um welchen Wert wir verringern oder erhöhen. Oft wird die Variable pro Schleifen-
durchlauf um eins erhöht, das muss aber eben nicht so sein. Möchte man um eins
erhöhen, würde man schreiben:
$i = $i+1; //erhöht die Variable i um eins
Dies bedeutet, dass der neue Wert der Variablen i 1 aus dem alten Wert 2 plus eins 3
errechnet wird. Diese Schreibweise ist speziell in diesem Fall nicht besonders üblich,
vielmehr schreibt man:
$i++; //erhöht die Variable i um eins
Listing 2.50: in PHP ...
i++; //erhöht die Variable i um eins
Listing 2.51: ... und in JavaScript bzw. Flash
Eine weitere allgemeinere Schreibweise ist:
$i += 1; //erhöht die Variable i um eins
$i += 3; //erhöht die Variable i um drei
$i -= 1; //verringert die Variable i um eins
Listing 2.52: In PHP ...
G R U N D L A G E N D E R P R O G R A M M I E R U N G 35
i += 1; //erhöht die Variable i um eins
i += 3; //erhöht die Variable i um drei
i -= 1; //verringert die Variable i um eins
Listing 2.53: ... und in JavaScript bzw. Flash
Beispiele von for-Schleifen
Damit sind wir in der Lage, komplette Schleifen zu programmieren. Sehen wir uns nun
einige Beispiele von for-Schleifen an:
for($i=0; $i<10; $i++) {
echo("i = $i");
/* Diese Schleife beginnt mit $i = 0; $i wird pro Schleifendurchlauf
um eins erhöht und es wird pro Durchlauf abgeprüft, ob $i immer noch
kleiner als 10 ist; ist das irgendwann nicht mehr der Fall, wird die
Schleife abgebrochen. Insgesamt sind es 10 Schleifendurchläufe */
}
for($i = -17; $i<30; $i+= 3) {
echo("i = $i");
//16 Durchläufe
}
Listing 2.54: In PHP ...
for(var i =0; i<10; i++) {
alert("i = "+i);
}
for(var i = -17; i<30; i+= 3) {
alert("i= "+i);
//16 Durchläufe
}
Listing 2.55: ... in JavaScript ...
for(var i:Number=0; i<10; i++) {
trace("i = "+i);
}
for(var i:Number = -17; i<30; i+= 3) {
trace("i= "+i);
//16 Durchläufe
}
Listing 2.56: ... und in Flash
K A P I T E L 236
Jetzt ein praktisches Beispiel. Sie erinnern sich sicher noch an unser Array mit den
Userdaten.
Mit echo($arrUser[0]) haben wir den Nicknamen ausgegeben. Nun möchten wir
alle Daten des Users ausgeben.
// Erstellen des Arrays
$arrUser = array("Uwe", "Uwe", "Mutz");
//Ausgabe des Arrays mit einer for-Schleife
for($i=0; $i<3; $i++){
echo($arrUser[$i]."<br />");
}
Mit diesen paar Zeilen werden alle Daten des Arrays durch Zeilenumbrüche getrennt
ausgegeben: Die verwendete for-Schleife wird dreimal durchlaufen, weil wir als Start-
wert 0 und als maximalen Wert 2 (< 3) definiert haben. Somit hat $i beim ersten
Durchlauf der Schleife den Wert 0 und holt den Wert an der Stelle 0 aus unserem Array
$arrUser[]. Beim nächsten Durchlauf hat $i den Wert 1 und wir lesen den Wert an
der Stelle 1 aus unserem Array aus usw.
Anzahl der Elemente eines Arrays
Wir haben nur ein Problem, denn die for-Schleife läuft im Moment nur von Index 0
bis Index 2. Sobald mehr Daten in das Array gespeichert werden, würde ein Wert mit
zum Beispiel Index 3 oder Index 4 nicht ausgegeben werden. Zu lösen ist das Problem
über eine PHP-Funktion, die die Anzahl der Werte eines Arrays zurückgibt.
Hier können wir zwischen der Funktion count() und sizeOf() wählen. Welche
Funktion Sie nutzen, ist egal. Beide geben die Anzahl der Elemente eines Arrays
zurück.
for($i=0; $i<sizeof($arrUser); $i++){
echo($arrUser[$i]."<br />");
}
In ActionScript sähe der Code wie folgt aus, die Erklärung kann im Wesentlichen von
oben übernommen werden:
var arrUser:Array = new Array("Uwe","Uwe","Mutz");
for(var i:Number=0; i<arrUser.length; i++) {
trace("arrUser["+i+"] = "+arrUser[i]);
}
Entgegen der Beschreibung von oben wird in Flash zur Ermittlung der Anzahl der
Einträge in einem Array die Eigenschaft length des Arrays verwendet.
PHPPHP
ActionScriptActionScript
G R U N D L A G E N D E R P R O G R A M M I E R U N G 37
var arrUser = new Array("Uwe","Uwe","Mutz");
for(var i =0; i<arrUser.length; i++) {
alert("arrUser["+i+"] = "+arrUser[i]);
}
JavaScript ist – wie Sie ja wissen – sehr ähnlich wie ActionScript aufgebaut (nachdem
beide demselben Standard angehören, ist das auch nicht wirklich schwer ...) – einzig
die strikte Typisierung fehlt uns in JavaScript.
2.7.2 for...each- oder for...in-Schleife
Die for...each-Schleife steht uns in PHP speziell für Arrays zur Verfügung, in
JavaScript und Flash verwendet man sie auch gern zum Auslesen aller Eigenschaften
und Methoden eines Objekts. Dort ist sie als for...in-Schleife bekannt. Diese
Schleife löst unser Problem der for-Schleife, dass die Anzahl der Einträge des Arrays
nicht bekannt ist, denn mit einer for...each-Schleife werden alle Felder des Arrays
durchlaufen.
Hier zunächst die Syntax der for...each-Schleife:
foreach($array as element) {
Programmblock;
}
Listing 2.57: In PHP ...
for(element in myArray) {
Programmblock;
}
Listing 2.58: ... und in JavaScript bzw. Flash
Unser voriges Beispiel mit einer for...each-Schleife würde demnach wie folgt aus-
sehen:
// Erstellen des Arrays
$arrUser = array("Uwe", "Uwe", "Mutz");
//Ausgabe des Arrays mit einer for...each-Schleife
foreach($arrUser as $userdaten){
echo($userdaten."<br />");
}
Listing 2.59: In PHP ...
JavaScriptJavaScript
K A P I T E L 238
var arrUser:Array = new Array("Uwe","Uwe","Mutz");
for(element in arrUser) {
trace("arrUser["+element+"] = "+arrUser[element]);
}
Listing 2.60: ... in JavaScript ...
var arrUser = new Array("Uwe","Uwe","Mutz");
for(element in arrUser) {
alert("arrUser["+element+"] = "+arrUser[element]);
}
Listing 2.61: ... und in Flash
Für die Verarbeitung eines assoziativen Arrays müssen wir die for...each-Schleife
noch etwas erweitern. Die Syntax für das Durchlaufen eines assoziativen Arrays lau-
tet:
foreach($array as key => value){
Programmblock;
}
Listing 2.62: Syntax für eine for...each-Schleife in einem assoziativen Array
Wie schon bei der Erstellung eines assoziativen Arrays benötigen wir den Operator =>.
// Erstellen des Arrays
$arrUser = array(
"Nickname" => "Uwe",
"Vorname" => "Uwe",
"Nachname" => "Mutz"
);
// Ausgabe des assoziativen Arrays mit einer for...each-Schleife
foreach($arrUser as $key => $value){
echo("$key: <b>$value</b><br />");
}
Wissenswertes zur for...in-Schleife in Flash
Mithilfe der for...in-Schleife in Flash können zwar beinahe, jedoch nicht alle Eigenschaften
und Methoden von Objekten ermittelt werden. Hierzu verweise ich auf die ActionScript-
Referenz, die Sie auf der Site von Macromedia (www.macromedia.com) im Menüpunkt SUPPORT
> DOKUMENTATION finden.
Des Weiteren listet die for...in-Schleife die eingetragenen Elemente nicht in der Reihenfolge
des Vorkommens auf. Dies wird speziell im Fall des Auslesens von Array-Elementen interessant.
PHPPHP
G R U N D L A G E N D E R P R O G R A M M I E R U N G 39
Seit ActionScript 3.0 existiert in Flash nun auch eine for each..in-Schleife, die
primär zum Durchlaufen von Objekten eines bestimmten Typs verwendet wird. Sol-
che Objekte sind beispielsweise XML- oder XMLList-Objekte. Im Gegensatz zu einer
for...in-Schleife wird über den Iterator der Schleife der Wert und nicht der Name
der jeweiligen Eigenschaft ermittelt.
Als Beispiel arbeiten wir uns durch ein XML-Objekt, um alle Werte auszugeben:
var myXML:XML =
<Playliste>
<song src="BeAWarrior.mp3">Be a Warrior</song>
<song src="WarriorsOfTheWasteland.mp3">Warriors of the Wasteland</
song>
</Playliste>;
for each (var item in myXML.song) { trace("item="+item); }
Als Ausgabe erhalten wir „Be A Warrior“ und „Warriors of the Wasteland“.
2.7.3 do..while-Schleife
Diese und die nächste Schleife sind Vertreter von Schleifen mit einer variablen Anzahl
von Durchläufen. Damit kommen wir mehr denn je in die Situation, dass wir selbst
überprüfen müssen, dass die Schleife auch wirklich jemals abbricht. Sorgen wir pro-
grammiertechnisch nicht für die Möglichkeit des Schleifenendes, erzeugen wir die
schon bei der for-Schleife angesprochene Endlosschleife.
Mindestens einmal durchlaufen
Bei der do..while-Schleife wird der Programmblock, der sich in ihr befindet, auf
jeden Fall einmal durchlaufen. Die Bedingung, ob die Schleife ein weiteres Mal durch-
laufen wird, hängt von der Abbruchbedingung ab, die aber erst am Ende der Schleife
überprüft wird.
Boolesche Werte
Genauso wie bei der for-Schleife (und jeder anderen Situation, in der Bedingungen
gefordert sind) liefert die Bedingung einen booleschen Wert. Oft wird anstatt der
Bedingung selbst einfach eine boolesche Variable verwendet, deren Wert dann für
einen weiteren Schleifendurchlauf oder einen Schleifenabbruch entsprechend gesetzt
wird. Der Variable wird dann z.B. innerhalb der Schleife ein Wert zugewiesen, damit
die Schleife abbrechen kann.
Werfen wir einen Blick auf die Syntax:
for each..in in
ActionScript 3.0
for each..in in
ActionScript 3.0
K A P I T E L 240
do{
//Programmblock
} while(Bedingung);
Listing 2.63: Syntax für do..while-Schleifen
Die do..while- und die while-Schleife werden dann verwendet, wenn man nicht
sicher ist, wie oft die Schleife durchlaufen werden soll.
2.7.4 while-Schleife
Entgegen der oben beschriebenen do..while-Schleife läuft die while-Schleife nicht
notwendigerweise durch. Trifft die Bedingung schon von Beginn an nicht zu, führt
kein Weg in das Innere der Schleife.
Die korrekte Syntax ist:
while(Bedingung) {
//Programmblock
}
Listing 2.64: Syntax für while-Schleifen
ABBILDUNG 2.3
Schematische Darstellung
einer do..while-Schleife
G R U N D L A G E N D E R P R O G R A M M I E R U N G 41
Die Anmerkungen zur Abbruchbedingung bei der do..while-Schleife gelten hier
natürlich entsprechend.
Hilfreiches bei Schleifen: break und continue
Zwei Befehle sind im Zusammenhang mit Schleifen oft hilfreich:
break: veranlasst den Interpreter, zum Beispiel den Flash-Player, die Schleife zu verlassen, ohne
dass die Bedingung noch weiter geprüft wird.
continue: veranlasst den Interpreter, zur Bedingungsprüfung zu springen, ohne dass die restli-
chen Zeilen des Programmblocks weiter ausgeführt werden.
2.8 Funktionen
Bisher haben wir die notwendigen Grundlagen der Programmierung betrachtet. Sie
sind bereits jetzt in der Lage, einfachere Programme zu schreiben. Auf den nächs-
ten Seiten lernen Sie die Möglichkeit kennen, Programmteile erst bei Bedarf auszu-
führen.
u
u
ABBILDUNG 2.1
Schematische Abbildung
einer while-Schleife
K A P I T E L 242
Funktionen bieten uns bei der Programmierung zwei entscheidende Vorteile:
Funktionen können bei Bedarf – also erst dann, wenn man diesen Programmblock
wirklich braucht – aufgerufen werden.
Funktionen lassen sich beliebig oft aufrufen.
Funktionen können Ergebnisse an das Hauptprogramm zurückgeben.
Stellen Sie sich zum Beispiel ein Computerspiel vor: Jedes Mal, wenn der Spieler mit
seinem Raumschiff abgeschossen wird, soll die Anzahl seiner „Leben“ um eins redu-
ziert werden. Das wäre ein Beispiel dafür, dass ein Programmblock nur bei Bedarf und
so oft man will abgerufen werden kann.
Funktionsdeklaration
Sehen wir uns die korrekte Syntax der Funktionsdeklaration für verschiedene Anwen-
dungsmöglichkeiten einmal an. Funktionen werden dabei immer durch das Schlüssel-
wort function eingeleitet.
1. Funktion, an die weder Daten übergeben noch von der Daten zurückgegeben
werden:
function Funktionsname() {
Programmblock
}
2. Funktion, an die Daten übergeben, von der jedoch keine Daten zurückgegeben
werden:
function Funktionsname(Variablensatz) {
Programmblock
}
3. Funktion, an die keine Daten übergeben, von der jedoch Daten zurückgegeben
werden:
function Funktionsname() {
Programmblock
return Variable / Wert;
}
4. Funktion, an die sowohl Daten übergeben als auch Daten von ihr zurückgegeben
werden:
function Funktionsname(Variablensatz) {
Programmblock
u
u
u
G R U N D L A G E N D E R P R O G R A M M I E R U N G 43
return Variable / Wert;
}
Übergabe von Daten und Rückgabe
In dieser Syntax sehen Sie Dinge, von denen bis jetzt noch gar nicht die Rede war. Dar-
auf müssen wir genauer eingehen. Machen wir dies aber lieber anhand eines Beispiels:
Wir programmieren eine Funktion, welche zwei Zahlen zusammenzählt (diese beiden
Zahlen werden an die Funktion übergeben) und das Ergebnis an das Hauptprogramm
zurückliefert.
function Addiere($zahl1,$zahl2) {
$ergebnis = $zahl1 + $zahl2;
return $ergebnis;
}
Listing 2.65: In PHP ...
function Addiere(zahl1,zahl2) {
var ergebnis = zahl1 + zahl2;
return ergebnis;
}
Listing 2.66: ... in JavaScript ...
function Addiere(zahl1:Number,zahl2:Number) {
var ergebnis:Number = zahl1 + zahl2;
return ergebnis;
}
Listing 2.67: ... und in Flash
Lesen wir diese Funktion einmal in Worten: Erzeugt wurde eine Funktion mit dem
Namen Addiere. An die Funktion werden zwei Werte übergeben, welche innerhalb
der Funktion über die Variablennamen $zahl1 (bzw. zahl1) und $zahl2 (bzw.
zahl2) angesprochen werden können. Die Übergabe der Werte erfolgt in runden
Klammern direkt hinter dem Funktionsnamen. Innerhalb der Funktion legen wir
eine Variable $ergebnis/ergebnis an, der wir das Ergebnis der Addition der Zahlen
$zahl1/zahl1 und $zahl2/zahl2 zuweisen. Der Inhalt der Variable wird dann über
return an das aufgerufene Programm zurückgegeben.
K A P I T E L 244
Funktionsaufruf
Aufgerufen wird eine Funktion über den Namen der Funktion, wie z.B.:
Addiere(1,3); //wenn kein Wert zurückgegeben wird
$ergebnis = Addiere(1,3) // mit einem Rückgabewert
Listing 2.68: In PHP …
Addiere(1,3); // wenn kein Wert zurückgegeben wird
var ergebnis = Addiere(1,3); mit einem Rückgabewert
Listing 2.69: … in JavaScript …
Addiere(1,3); // wenn kein Wert zurückgegeben wird
var ergebnis:Number = Addiere(1,3); mit einem Rückgabewert
Listing 2.70: … und in Flash
Hier wird die Funktion Addiere mit den Zahlen 1 und 3 aufgerufen. Der Rückgabe-
wert $ergebnis (bzw. ergebnis in JavaScript/Flash) sollte 4 sein.
Funktionen ohne Rückgabewert
Oft ist es nicht notwendig, einen Wert aus der Funktion zurückzugeben, da die Daten
schon innerhalb der Funktion entweder ausgegeben oder anderweitig verwendet wer-
den. Sie werden sogar sehr oft auf Funktionen treffen, an die weder Daten übergeben
noch Daten von ihr zurückgegeben werden. Sollte jedoch ein Wert von der Funktion
an den „Aufrufer“ zurückgegeben werden, wird dieser im Allgemeinen im aufrufenden
Programmblock benötigt. Aus diesem Grund werden die Rückgabewerte gerne im
aufrufenden Teil als Variablen gespeichert. Eine andere Variante ist das Ausgeben des
Variablenwerts per echo (PHP), alert (JavaScript) oder trace (Flash).
Hier ein Beispiel für eine Funktion, die keinen Wert zurückliefert, da ein etwaig errech-
neter Wert bereits innerhalb der Funktion ausgegeben wird:
function Addiere2($zahl1,$zahl2) {
$ergebnis = $zahl1 + $zahl2;
echo($ergebnis);
//Rückgabe ist nicht notwendig, da Ergebnis im Browser angezeigt wird
}
Addiere2(10,340);
Listing 2.71: Der Wert der Variable (350) wird in PHP per echo im Browser ausgegeben.
function Addiere2(zahl1,zahl2) {
var ergebnis = zahl1 + zahl2;
G R U N D L A G E N D E R P R O G R A M M I E R U N G 45
alert(ergebnis);
}
Addiere2(10,340);
Listing 2.72: JavaScript gibt das Ergebnis in einer Alert-Box aus.
function Addiere2(zahl1:Number,zahl2:Number) {
var ergebnis:Number = zahl1 + zahl2;
trace(ergebnis);
}
Addiere2(10,340);
Listing 2.73: In Flash benutzt man trace für eine Ausgabe im Ausgabefenster.
Arrays übergeben
Wenn an eine Funktion Variablen übergeben werden, die in der Funktionsdeklaration
explizit aufgeführt sind, so können diese Werte eben über diese Variablennamen (hier:
$zahl1 / zahl1 und $zahl2 / zahl2) angesprochen werden. Ist von vorneherein
nicht eindeutig klar, wie viele Werte man an eine Funktion übergeben möchte, dekla-
riert man diese nicht explizit, sondern greift auf die Verwendung eines Arrays zurück.
Alles, was wir dazu wissen müssen, ist:
1. Wie erstelle ich ein Array? (nur PHP)
2. Wie erhalte ich die Anzahl der Werte eines Arrays?
3. Wie kann ich diese Werte in einer Schleife auslesen?
Ein Beispiel:
// Funktion deklarieren
function Addiere3($arr){
//Anzahl der Elemente des Arrays $arr in $anzParams speichern
$anzParams = count($arr);
$ergebnis = 0;
for($i=0; $i < $anzParams; $i++){
// Addieren aller Parameter
$ergebnis = $ergebnis + $arr[$i];
// $ergebnis += $ergebnis wäre auch richtig
}
// Ergebnis zurückgeben
PHPPHP
Lokale Variablen
in Funktionen
Grundsätzlich sind
Variablen, die innerhalb
einer Funktion angelegt
werden, nicht außerhalb
der Funktion bekannt.
Aus diesem Grund gibt es
return, um Werte außer-
halb der Funktion weit-
erverwenden zu können.
K A P I T E L 246
return $ergebnis;
}
//Array der Parameter erzeugen
$params = array(1,3,5,2,8);
//Aufruf der Funktion Addiere3 und Übergabe des Arrays $params
$resultat = Addiere3($params);
echo($resultat);
Listing 2.74: Auswerten einer beliebigen Anzahl von Übergabeparametern an eine PHP-Funktion
Insgesamt wird also in unserer Funktion Addiere3 die for-Schleife fünfmal durch-
laufen. Bei jedem Durchlauf wird $ergebnis um den gerade aktuellen Wert aus dem
Array $params erhöht. Das Endergebnis ist somit 18.
In JavaScript und Flash stellt sich die Sachlage etwas differenzierter dar, denn hier kann
man innerhalb einer Funktion auf ein Array namens „arguments“ zurückgreifen, das
alle an die Funktion übergebenen Werte beinhaltet – dieses Array muss somit nur noch
ausgelesen werden. Der Aufruf der Funktion gleicht dem vorherigen:
function Addiere3() {
var args = Addiere3.arguments;
var ergebnis = 0;
for(var i =0; i<args.length; i++) {
ergebnis += args[i];
}
return ergebnis;
}
Addiere3(1,3,5,2,8);
Listing 2.75: JavaScript erhält eine beliebige Anzahl an Parametern übergeben.
function Addiere3() {
var args:Array = arguments;
var ergebnis:Number = 0;
for(var i:Number=0; i<args.length; i++) {
ergebnis += args[i];
}
return ergebnis;
JavaScript und
ActionScript
JavaScript und
ActionScript
G R U N D L A G E N D E R P R O G R A M M I E R U N G 47
}
Addiere3(1,3,5,2,8);
Listing 2.76: Auswerten einer beliebigen Anzahl von Übergabeparametern an eine Flash-Funktion. Möch-
ten Sie das Ergebnis der Addition ausgeben, so ersetzen Sie die letzte Zeile mit trace(Addiere3(1,3,
5,2,8));.
Im Gegensatz zu Flash (es wird lediglich auf das Array arguments zugegriffen) erfolgt
in JavaScript der Zugriff über: Funktionsname.arguments.
2.9 Cookies
Im Internet würde nur sehr wenig ohne Cookies funktionieren. Jeder Webshop und
jedes Forum arbeiten im Grunde mit Cookies. Diese ermöglichen es, User bei einem
Wiederaufruf einer Website zu erkennen und persönlich zu begrüßen oder, wie es bei
einem Webshop üblich ist, ihnen ihren Warenkorb anzuzeigen.
Einige User haben leider das Setzen von Cookies deaktiviert. Meist geschieht dies aus
Angst, dass fremde Personen Zugriff auf die eigenen Daten bekommen. Diese Angst
ist aber unbegründet, da nicht der Server Cookies am User-PC ausliest, sondern der
Client, also der Browser des Users, sendet die Cookie-Daten an die URL zurück.
Unterscheiden kann man zwischen persistenten Cookies und Session-Cookies. Letzte-
re werden wir im nächsten Abschnitt behandeln.
2.9.1 Exkurs HTTP
Wahrscheinlich ist Ihnen der Begriff HTTP schon öfter bei der Eingabe eines Links
oder einer Webadresse aufgefallen. Doch was ist dieses HTTP eigentlich und wozu
dient es?
HTTP ist eine Abkürzung für „HyperText Transfer Protocol“ und ist ein Grundstein
des Internets. Mittels HTTP wird die Verständigung des Clients mit dem Server erst
möglich. Bei dem Aufruf einer Website geschieht immer dasselbe.
1. Request – der Client (Browser) stellt eine Verbindung mit dem Server her und
fragt nach der gewünschten Webseite.
2. Response – Antwort des Webservers mit den Daten oder einer Fehlermeldung, falls
die gewünschten Daten nicht vorhanden sind
3. Der Client empfängt die Antwort des Servers und stellt die gewünschten Daten
dar.
4. Anschließend wird die Verbindung zwischen Client und Browser geschlossen.
Definition
von Cookies
Cookies sind ein Mecha-
nismus, um clientseitige
Informationen zu speichern
und wieder auszulesen.
Diesen Mechanismus
nutzen serverseitige
Verbindungen.
K A P I T E L 248
HTTP und Cookies
So weit, so gut, aber wahrscheinlich stellen Sie sich nun die Frage: „Was hat jetzt HTTP
mit Cookies zu tun?“ Im Grunde haben sie nichts miteinander zu tun. Wichtig für uns
ist einzig die Tatsache, dass eine Verbindung zwischen Client und Server immer nach
Übergabe der gewünschten Daten geschlossen wird. Dies ist auch nicht weiter schlimm,
solange Sie nicht gewisse Daten zu einem späteren Zeitpunkt auf einer weiteren Seite
benötigen. Denken wir zum Beispiel an einen Warenkorb bei einem Online-Shop. User
können nach Auswahl eines Artikels nach weiteren Produkten suchen und diese dann
dem eigenen Warenkorb hinzufügen. Jedoch müssen wir dazu immer wissen, welcher
User gerade in unserem Webshop surft. Ansonsten könnte es ja passieren, dass der
gewünschte Artikel im Warenkorb eines falschen Kunden gespeichert wird.
Genau hier liegt das Problem von HTTP, da sofort nach Übergabe der gewünschten
Daten dieVerbindung zwischen Browser und Client geschlossen wird. Somit wissen wir
zu keiner Zeit, dass der User X vorher auf der Seite Y gesurft hat. Um dieses Problem in
den Griff zu bekommen, können wir auf Cookies oder Sessions zurückgreifen.
Cookies setzen
In PHP steht uns nur eine Funktion zur Verfügung, die es ermöglicht, Cookies zu set-
zen und diese auch wieder auszulesen:
setcookie();
Die setcookie()-Funktion muss unbedingt vor dem ersten Ausgeben von Zeichen
im Browser gesetzt werden. Sie erwartet sechs Parameter, wobei alle außer dem ersten
optional sind. Die Parameter sind:
1. Name
2. Inhalt
3. Verfallsdatum
4. Pfad
5. Domain
6. secure
Optionale Parameter
Auch wenn der Name-Parameter als einziger Pflicht ist, müssen Sie die Angaben zu Pfad und
Domain durch eine leere Zeichenkette „“ und das Verfallsdatum und secure durch die Ziffer 0
ersetzen. Die Funktion sähe dann wie folgt aus:
setcookie (cookie1, "", 0, "", "", 0);
G R U N D L A G E N D E R P R O G R A M M I E R U N G 49
Sehen wir uns die einzelnen Parameter genauer an:
Name: Der Name des Cookies darf keine Leerzeichen, Kommas und Semikolons
beinhalten. Alles andere ist erlaubt.
Inhalt: Der Inhalt des Cookies kann ein Text sein. Meist werden Sie als Inhalt aber
eine Variable speichern, deren Inhalt Text ist. Denkbar wäre der Username oder die
ID des Users in der Datenbank. Der Inhalt wird auch automatisch über die Funk-
tion urlencode() für die URL kodiert.
Verfallsdatum: Das Verfallsdatum gibt an, ab wann ein Cookie nicht mehr gültig
ist. Geben Sie als Verfallsdatum 0 an, wird das Cookie sofort nach Ende der Sitzung
gelöscht. Das Verfallsdatum muss in Sekunden angegeben werden.
Angenommen,Ihr Cookie soll nach fünf Minuten verfallen,so müssen Sie folgenden
Code für das Verfallsdatum eingeben: time()+300. Mit der Funktion time()
bekommt man die aktuelle Uhrzeit. Zu dieser rechnen Sie einfach 300 Sekunden
dazu. Um ein bestehendes Cookie früher zu löschen als geplant, geben Sie einfach
für das Cookie mit demselben Namen ein Verfallsdatum in der Vergangenheit an.
Zum Beispiel time()-300.
Domain: Wir haben hier ganz bewusst den Parameter für die Domain vorgezogen,
da erst dann der Sinn des Pfad-Parameters erkennbar wird.
Ein Browser sucht in der kompletten Liste der Cookies des Users nach einer
Übereinstimmung des Domain-Parameters mit dem Internet-Domainnamen des
Servers, der die Seite aufgerufen hat. Berücksichtigt werden auch Teile einer Domain.
Angenommen, Ihr Domain-Parameter lautet syne.at. Dann ist auch der Aufruf über
test.syne.at richtig und das Cookie wird zum Auslesen erkannt. Wenn Sie keine
Domain angeben, wird der Name des Servers (hostname) verwendet.
Pfad: Mit dem Pfad-Parameter können Sie zur Domain noch einen eigenen Pfad
angeben. Erst wenn Domainname und Pfad übereinstimmen, wird das Cookie zum
Auslesen bereitgestellt.
secure: Mit secure können Sie einstellen, dass ein Cookie nur gesetzt wird, wenn
eine sichere Verbindung vorhanden ist. Eine sichere Verbindung erkennt man
am https (statt http) in der Adresszeile des Browsers und zusätzlich an einem
Schloss-Symbol, dass sich meist in der rechten unteren Ecke befindet.
User-ID speichern
Nun Schluss mit der Theorie, sehen wir uns ein kleines Beispiel an. Angenommen, wir
haben einen Login-Bereich für unsere User erstellt. Um dem User das lästige Anmel-
den bei einem erneuten Besuch unserer Website zu ersparen, speichern wir seine User-
ID in einem Cookie ab. Durch diese User-ID können wir dann ganz einfach die Daten
des Users aus unserer Datenbank laden und den User mit seinem Namen begrüßen.
u
u
u
u
u
u
K A P I T E L 250
Für unser Beispiel nehmen wir eine fiktive User-ID von 4 an. Diese ID speichern wir in
der Variable $idUser ab. Nun können wir ein Cookie für den User definieren.
setcookie("user",$idUser, time+300(), "","syne.at",0);
Sofern der User das Setzen von Cookies akzeptiert, wird mit obigem Code ein Coo-
kie mit dem Namen user und seiner User-ID gespeichert. Dieses Cookie ist für fünf
Minuten gültig und bezieht sich auf die Domain syne.at.
Nun müssen wir uns überlegen, wie wir beim nächsten Besuch unseres Users kontrol-
lieren können, ob ein Cookie existiert, um diesen begrüßen zu können. Dazu nutzen
wir das superglobale Array $_COOKIE[].
if(isset($_COOKIE[‚user']))
Mit diesem Code überprüfen wir, ob das Cookie mit dem Namen user bei unserem
User in der Cookieliste existiert. Wenn es nicht gefunden ist, wird false zurückgege-
ben. Wenn das Cookie gefunden wird, ist unsere Bedingung true und wir könnten
dann die Daten unseres Users aus der Datenbank laden.
2.10 Sessions
Sessions helfen uns wie Cookies beim Identifizieren des Users, um auch wirklich die
richtigen Daten anzuzeigen.
Lebensdauer von Session-Cookies: Der große Unterschied von persistenten Coo-
kies zu Session-Cookies liegt allein in der Lebensdauer. Session-Cookies werden
sofort nach Ablauf der Session, also nach Schließen des Browser-Fensters, zerstört.
Session-ID: Beim Erstellen einer Session erhält man eine ID zurück. PHP speichert
dann alle Daten, die unter dieser ID anfallen, zentral und abrufbereit auf dem Ser-
ver. Der Browser hingegen merkt sich bloß die ID der Session. Meist wird diese in
einem Session-Cookie gespeichert.
Sessions ohne Cookies: Probleme gibt es hier, wenn der User in seinem Browser
keine temporären Cookies akzeptiert. Doch das Gute an Sessions ist, dass wir hier
mehrere Möglichkeiten ohne Cookies nutzen können. Denkbar wäre der Einsatz
von versteckten Formularfeldern, die die Daten des Users aufnehmen. Dies ist aber
eine eher aufwändige und umständliche Variante. Eine bessere Möglichkeit ist, die
Session-ID direkt an die Links anzuhängen und auf jeder Seite zu kontrollieren, ob
diese Session-ID mit der der aktuellen Sitzung des Browsers übereinstimmt. Nur
dann darf der User die jeweilige Seite betrachten. Trotz allem bleibt die Variante mit
temporären Cookies am sichersten.
Name und ID speichern: In einem dieser Cookies werden nur die Session-ID und
der frei wählbare Name der Session gespeichert. Wenn Sie keinen Namen angeben,
wird automatisch der Name PHPSESSID genutzt. In der php.ini können Sie den
u
u
u
u
G R U N D L A G E N D E R P R O G R A M M I E R U N G 51
voreingestellten Namen einer Session ändern, indem Sie für session.name einen
eigenen String angeben.
Die wichtigsten Session-Funktionen sind:
session_start()
session_register()
session_unregister()
session_destroy()
2.10.1 session_start()
Mittels session_start() wird eine Session initialisiert und das Session-Cookie
erstellt.
<?php
// Session initialisieren
session_start();
// Ausgabe der erzeugten Session-ID
echo(session_id());
?>
Vor dem Erzeugen einer Session dürfen auf keinen Fall Zeichen an den Browser gesen-
det werden. Aus diesem Grund sollten Sie eine Session immer am Beginn eines Scripts
initialisieren.
Automatische Initialisierung
In der php.ini gibt es eine Einstellung session_autostart. Wenn diese auf 1 gestellt
ist, können Sie sich den Aufruf von session_start() ersparen. Trotzdem rate ich
Ihnen, die Session immer explizit zu initialisieren, da Sie nicht darauf vertrauen kön-
nen, dass diese Einstellung bei Ihrem Provider auch in Zukunft so bleibt.
2.10.2 session_register() vs. $_SESSION
Bei der Verwendung von Sessions haben Sie auch die Möglichkeit, Variablen in der Ses-
sion zu speichern. Denkbar wäre der Username oder dessen Kundennummer. Dem Auf-
ruf von session_register() muss ein Aufruf von session_start() vorangehen.
<?php
// Variablen
$username = "Uwe";
$kundennummer = 1234;
u
u
u
u
K A P I T E L 252
// Session initialisieren
session_start();
// register_globals = ON
session_register(‚username','kundennummer');
?>
Listing 2.77: Verwendung bei register_globals=on. Nicht ideal!
Bitte beachten Sie, dass es sich bei den Parametern von session_register() nicht
um die Variablen, sondern um deren Namen handelt. Somit müssen Sie das $-Zeichen
weglassen.
Array bei register_globals = OFF
Wenn in der php.ini register_globals auf OFF steht, sollten Sie das superglobalen Array
$_SESSION anstelle von session_register() verwenden:
//register_globals = OFF
$_SESSION[‚username'];
$_SESSION[‚kdnr'];
Mein Tipp ist, dass Sie sich von vorneherein angewöhnen, auf die superglobalen Arrays zurück-
zugreifen, denn diese werden in jedem Fall funktionieren. Bei Einstellungen, die register_
globals betreffen, sollte man generell vorsichtig sein. Auch gehen fast alle gängigen Provider
aus Sicherheitsgründen weg von register_globals=on.
Wichtig ist, dass die gewünschten Variablen erst zum Ende des Scripts in die Session
gespeichert werden. Dadurch ist es möglich, dass Sie den Wert der Variablen im Laufe
des kompletten Scripts ändern, da ja erst der Endwert in die Session geschrieben wird.
Als Folge daraus können wir auf die Sessionvariablen frühestens nach Beendigung des
aktuellen Scripts und beim nächsten session_start() zugreifen.
<?php
// Variablen
$username = "Uwe";
$kundennummer = 1234;
// Session initialisieren
session_start();
// register_globals = OFF
$_SESSION["username"] = $username;
$_SESSION["kundennummer"] = $kundennummer;
?>
Listing 2.78: Verwendung bei register_globals=off. Ideal!
G R U N D L A G E N D E R P R O G R A M M I E R U N G 53
2.10.3 session_unregister() vs. $_SESSION
session_unregister() ist das genaue Gegenteil von session_register(). Es
dient dazu, eine oder mehrere Variablen aus der Session zu verwerfen.
<?php
session_start();
// register_globals = ON
session_unregister('username');
?>
unset() bei register_globals = OFF
Ist register_globals auf OFF gestellt, dürfen wir session_unregister() nicht verwen-
den, da man bei dieser Einstellung nicht auf diese Funktion zurückgreifen darf. Wir nutzen zum
Löschen einer Sessionvariable dann die PHP-Funktion unset():
// register_globals_ OFF
unset($_SESSION['username']);
Heben Sie aber nicht $_SESSION selbst mit unset() auf, weil dies die besondere Funktion des
superglobalen Arrays $_SESSION deaktivieren würde.
2.10.4 session_destroy()
Die Funktion session_destroy() veranlasst PHP, alle Variablen einer Session zu
verwerfen und die Session zu löschen. Dem Aufruf von session_destroy() muss
ein Aufruf von session_start() vorangehen.
<?php
session_start();
// Session zerstören
session_destroy();
?>
2.11 Caching
Caching ist das Zwischenspeichern von Daten einer Webseite im Cache (Speicher) des
Browsers, um diese beim nächsten Aufruf schneller darstellen zu können. Dies ist im
Grunde von Vorteil für den User. Wenn Flash mit PHP zusammenarbeitet, kann dies
aber hinderlich sein, da der User möglicherweise veraltete Daten angezeigt bekommt.
Um das Caching zu beeinflussen oder auch zu verhindern, nutzen wir die Funktion
header() von PHP. Der Header einer Webseite beinhaltet Anfangsinformationen, wie
Caching in PHPCaching in PHP
K A P I T E L 254
zum Beispiel den Typ des Dokuments und eben auch, wie lange eine Seite im Cache
des Browsers gespeichert werden soll.
Um einem Browser mitzuteilen, dass eine Seite nicht zwischengespeichert werden soll,
müssen wir drei Dinge einstellen.
1. Wann soll die Webseite aus dem Cache gelöscht werden?
2. Wann wurde die Webseite modifiziert?
3. Die Webseite soll nicht gecacht werden.
Für die Einstellung, wann die Webseite aus dem Cache gelöscht werden soll, geben wir
einfach ein Datum in der Vergangenheit an. Wichtig ist die Formatierung des Datums
selbst und die Zeitzone.
// Datum aus der Vergangenheit
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
Um zu bestimmen, wann die Webseite zum letzten Mal modifiziert wurde, geben
wir auch wieder ein Datum ein. Hier soll logischerweise kein Datum in der Vergan-
genheit angegeben werden, sondern immer das aktuelle. Dies können wir über die
PHP-Datumsfunktion gmdate() realisieren. Mit dieser Funktion können wir immer
das Datum mit der Zeitangabe von Greenwich Mean Time (GMT) auslesen. Wie wir
dieses Datum und die Uhrzeit formatieren möchten, können wir in den Parametern
von gmdate() angeben.
a – am/pm
A – AM/PM
B – Swatch-Internetzeit (Internetzeit, die überall auf der Welt gleich ist)
d – Tag des Monats mit zwei Stellen und führender Null (01-31)
D – Tag der Woche als Abkürzung mit drei Buchstaben
F – Monat, ausgeschrieben
h – Stunde im 12-Stunden-Format
H – Stunde im 24-Stunden-Format
g – Stunde im 12-Stunden-Format ohne führende Null
G – Stunde im 24-Stunden-Format ohne führende Null
i – Minuten von 0 bis 59
I – 1 bei Sommerzeit, 0 bei Winterzeit
j – Tag des Monats ohne führende Null (1-31)
l – Wochentag, voll ausgeschrieben
u
u
u
u
u
u
u
u
u
u
u
u
u
u
Caching
verhindern
Caching
verhindern
Datum angebenDatum angeben
G R U N D L A G E N D E R P R O G R A M M I E R U N G 55
L – boolescher Wert, ob das Datum in einem Schaltjahr liegt
m – Monat mit führender Null
n – Monat ohne führende Null
M – Monat als Abkürzung
s – Sekunden mit führender Null (00-59)
S – Suffix der englischen Ordnungszahlen (bei 1 = 1st (first), bei 2 = 2nd (second)
usw.)
T – Einstellung der Zeitzone des Servers (GMT oder MET ...)
t – Anzahl der Tage in einem Monat
U – Sekunden seit Beginn der UNIX-Zeitepoche (Beginn der UNIX-Zeitepoche ist
der 1.1.1970, 00 Uhr)
w – numerische Darstellung des Wochentags (beginnend bei 0 für Sonntag)
Y – vierstellige Ausgabe des Jahres
y – zweistellige Ausgabe des Jahres
z – Tag im Jahr (0-365)
Z – Differenz von UTC zur benannten Zeitzone in Sekunden. Der Offset für die
Zeitzone West nach UTC ist immer negativ und für die Zeitzone Ost nach UTC
immer positiv (-43200 bis 43200).
Somit könnte die Header-Angabe für die letzte Modifizierung der Seite zum Beispiel
folgendermaßen aussehen:
// immer geändert
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
Zu guter Letzt müssen wir noch einstellen, dass die Webseite generell nicht zwischen-
gespeichert werden soll. Hier müssen wir aber die Einstellung für die verschiedenen
HTTP-Versionen, welche Browser verwenden, definieren.
// für HTTP 1.1
header("Cache-Control: no-store, no-cache, must-revalidate");
header("Cache-Control: post-check=0, pre-check=0", false);
// für HTTP 1.0
header("Pragma: no-cache");
Bei der Verwendung der header-Funktion sollten Sie immer beachten, dass vor deren
Aufruf kein Zeichen an den Browser gesendet werden darf. Um keine Fehlermeldungen
zu bekommen, geben Sie die header-Funktionen immer am Beginn einer PHP-Seite
an. Achten Sie auch darauf, dass kein Leerzeichen davorsteht.
u
u
u
u
u
u
u
u
u
u
u
u
u
u
header()-
Funktion
immer zuerst
header()-
Funktion
immer zuerst
K A P I T E L 256
2.12 XML auslesen und erstellen
In PHP 4 war das Arbeiten mit XML noch sehr mühsam. Zum Glück hat sich das in
PHP 5 grundlegend geändert. Nun ist die Grundlage von XML in PHP das Docu-
ment Object Model, kurz DOM. Wenn Sie JavaScript kennen, wird Ihnen das DOM
mit Sicherheit etwas sagen. Das DOM ist ein vom W3C verabschiedeter Standard für
XML-Programmierschnittstellen.
Zusätzlich gibt es seit PHP 5 die Erweiterung SimpleXML, mit der es sehr einfach ist,
mit XML-Daten zu arbeiten.
2.12.1 Der Aufbau eines XML-Dokuments –
Blitzeinführung
XML ist wie HTML und XHTML eine Bezeichnungssprache, die von der überge-
ordneten Bezeichnungssprache SGML („Standard Generalized Markup Language“)
abstammt. Man spricht auch gerne davon, dass XML eine „Teilmenge von SGML“
ist. XML für sich bildet wiederum die Basis für weitere Bezeichnungssprachen wie
XHTML, RSS usw.
Entgegen HTML existieren in XML keine vorgefertigten Tags und aus diesem Grund
sollte man auch XML nicht mit HTML vergleichen. XML stellt – für unsere Zwecke
– lediglich ein Modell zur Verfügung, mit dem wir auf einfache Art und Weise struk-
turierte Daten darstellen können.
ABBILDUNG 2.5
XML stammt von SGML ab.
G R U N D L A G E N D E R P R O G R A M M I E R U N G 57
Ein XML-Dokument besteht aus zwei Teilen:
1. Prolog: Hierin werden der SGML-Typ deklariert (in unserem Fall also XML),
Informationen zum Dokumenttyp dargestellt und etwaige Kommentare
eingefügt.
2. Inhalt: Dieser Teil beinhaltet die darzustellenden Informationen, die durch das
sogenannte „Wurzelelement“ umhüllt werden.
Der Prolog
Der Prolog beginnt mit der Deklaration des Dokuments, es wird also festgelegt, dass
es sich hierbei um ein XML-Dokument handelt. Als Attribute dienen die Version
(version), Informationen zum Zeichensatz (encoding) und zur Eigenständigkeit
(standalone) des Dokuments:
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
Werfen wir einen Blick auf die einzelnen Attribute:
version: Gibt die verwendete Version von XML an, wobei derzeit die Version 1.0
aktuell ist.
encoding: Gibt Informationen zum verwendeten Zeichensatz an. Typische Zei-
chensätze sind der (eingeschränkte) Zeichensatz UTF-8 sowie der (westliche) Zei-
chensatz ISO-8859-1.
standalone: Kann die Werte no oder yes annehmen, die ausdrücken sollen, ob
zusätzlich zu diesem Dokument noch ein weiteres Dokument (wie beispielsweise
eine externe DTD – Document Type Definition) benötigt wird (standalone="no")
oder nicht (standalone="yes"). Da XML in diesem Buch als „Datenschnittstelle“
zwischen PHP und Flash dienen soll, wird zumeist standalone="yes" verwendet.
In den meisten anderen Anwendungen (bei denen beispielsweise XML zur Dar-
stellung von Daten in einem Browser-Fenster verwendet wird) benötigt man eine
zusätzliche DTD und somit muss es dort standalone="no" heißen.
Auf den Prolog folgt bei Bedarf eine Dokumenttyp-Definition, damit ein Browser
neben der Wohlgeformtheit auch die Gültigkeit des Dokuments überprüfen kann. In
gewissen Fällen kann dies notwendig sein. Wir gehen jedoch davon aus, dass unsere
(geringen Mengen an) Daten korrekt sind. Als Beispiel könnte die DTD wie folgt aus-
sehen:
<!DOCTYPE Kundendaten SYSTEM "http://www.syne.at/xml/kunden.dtd">
u
u
u
K A P I T E L 258
Wohlgeformtheit und Gültigkeit
Wohlgeformtheit deutet an, dass eine XML-Datei die Regeln von XML korrekt einhält. Diese sind:
Am Beginn der XML-Datei steht die XML-Deklaration: <?xml version="…">.
Das Dokument enthält zumindest ein Datenelement.
Es existiert ein Datenelement, das alle weiteren Datenelemente umfasst.
Ein gültiges XML-Dokument enthält neben der XML-Deklaration zusätzlich eine anschließende
Dokumenttyp-Deklaration (DTD), die entweder auf eine externe DTD-Datei verweist oder die not-
wendigen DTD-Regeln beinhaltet.
Eine gute Übersicht zu Wohlgeformtheit und Gültigkeit finden Sie auf der Website SelfHTML.de
(http://de.selfhtml.org/xml).
Sollen im Prolog noch Kommentare eingefügt werden, so kann dies mithilfe der aus
HTML ebenfalls bekannten Kommentarzeichen <!-- (Beginn des ein- oder mehrzei-
ligen Kommentars) und --> (Kommentarende) geschehen.
Der Inhaltsbereich
Dieser Bereich des Dokuments beinhaltet sämtliche Daten. Besonders zu beachten
ist, dass ein einziges Tag (das „Wurzelelement“) sämtliche weiteren Tags umschließt.
Wie das Wurzelelement benannt wird, spielt keine Rolle und ist vollkommen Ihnen
überlassen. Auch sind der Verwendung von Verschachtelungen beliebigen Ausmaßes
sowie von Attributen keine Grenzen gesetzt. Im Allgemeinen achtet man darauf, dass
bei beispielsweise einer Datenbankabfrage die Struktur der verwendete(n) Tabelle(n)
widergespiegelt wird. Letztendlich ist es nur wichtig, dass die Struktur zum Auslesen
der Daten bekannt und vereinbart ist.
Nachfolgend finden Sie ein Beispiel eines XML-Dokuments, bei dem Daten aus einem
Verzeichnis auf dem Webserver ausgelesen werden. Beide Dokumentstrukturen sind
gültig – Sie entscheiden, wie das XML-Dokument aufgebaut wird:
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<Playlist rootDir="songs" autostart="0">
<song src="01_GuentherStraub_Demo-CD_KeepOnGwine.mp3"
Interpret="Guenther Straub"/>
<song src="02_GuentherStraub_Demo-CD_RockingNightExpress.mp3"
Interpret="Guenther Straub"/>
<song src="03_GuentherStraub_Demo-CD_DizzyFingers.mp3"
Interpret="Guenther Straub"/>
<song src="04_GuentherStraub_Demo-CD_ArkansasBlues.mp3"
Interpret="Guenther Straub"/>
</Playlist>
Listing 2.79: Eine Möglichkeit des Aufbaus eines XML-Dokuments
u
u
u
Das Wurzelelement
eines XML-Dokuments
Bitte achten Sie darauf,
dass sämtliche Daten von
einem Wurzelelement
eingeschlossen werden
müssen, wobei die
Betonung auf „einem“ liegt.
G R U N D L A G E N D E R P R O G R A M M I E R U N G 59
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<Playlist rootDir="songs" autostart="0">
<song>
<src>01_GuentherStraub_Demo-CD_KeepOnGwine.mp3</src>
<Interpret>Guenther Straub</Interpret>
</song>
<song>
<src>02_GuentherStraub_Demo-CD_RockingNightExpress.mp3</src>
<Interpret>Guenther Straub</Interpret>
</song>
<song>
<src>03_GuentherStraub_Demo-CD_DizzyFingers.mp3</src>
<Interpret>Guenther Straub</Interpret>
</song>
<song>
<src>04_GuentherStraub_Demo-CD_ArkansasBlues.mp3</src>
<Interpret>Guenther Straub</Interpret>
</song>
</Playlist>
Listing 2.80: Auch so kann ein XML-Dokument aufgebaut werden.
Strenge Syntax von XML-Dokumenten
Entgegen der Tag-Schreibweise von HTML-Dokumenten muss man bei XML-Dokumenten unter
anderem folgende Punkte beachten:
Jedes geöffnete Tag muss auch wieder geschlossen werden. Tags, die sofort geöffnet und wieder
geschlossen werden, unterliegen der Schreibweise <Tagname [Attribut="Wert" ...] />.
Es wird auf Groß- und Kleinschreibung der Tag-Namen geachtet.
Alle Werte von Attributen stehen in Anführungszeichen.
XML-Dokumente sind selbstverständlich in einem wesentlich größeren Umfang ver-
wendbar. Es ist jedoch nicht sinnvoll, Sie mit sämtlichen Informationen hinsichtlich
XML „vollzufüttern“, wenn wir im Rahmen dieses Buchs nur einen Bruchteil davon
benötigen. Sollten Sie an weiterführenden Informationen interessiert sein, so finden
Sie diese beispielsweise auf der XML-Website des W3-Konsortiums (http://www.
w3.org/XML).
u
u
u
Tags, Attribute,
Knoten & Co.
Eine ausführliche
Dokumentation zu
XML finden Sie unter
anderem auf der Website
SelfHTML.de (http://
de.selfhtml.org/xml).
K A P I T E L 260
2.12.2 Auslesen einer XML-Struktur
SimpleXML bietet uns ein Objekt, mit dem wir XML-Daten einlesen können und
dessen Daten in einer Objektstruktur dargestellt werden. Um XML-Daten in PHP
einzulesen, stehen uns zwei Funktionen zur Verfügung:
Wenn Sie eine XML-Datei einlesen, können Sie simplexml_load_file() nutzen.
Als Parameter wird allein der Dateiname mit der Pfadangabe benötigt.
Um einen XML-String weiterverarbeiten zu können, müssen wir diesen mit
simplexml_load_string() einlesen. Hier ist logischerweise als Parameter die
Variable des XML-Strings erforderlich. In unseren Workshops werden wir später
mit dieser Funktion die XML-Daten auslesen, die Flash an PHP gesendet hat.
Sehen wir uns ein kleines Beispiel an. Erstellen Sie in einem Editor eine XML-Datei
und geben Sie ihr den Namen bb_players.xml. Der Inhalt dieser Datei sollte folgender-
maßen aussehen:
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<basketball>
<spieler>
<name>Michael Jordan</name>
<team>Chicago Bulls</team>
</spieler>
<spieler>
<name>Allen Iverson</name>
<team>Philadelphia 76ers</team>
</spieler>
</basketball>
Listing 2.81: Eine einfache XML-Datei
Angenommen, wir möchten nun den Namen des ersten Spielereintrags in der XML-
Datei bb_players.xml ausgeben, so müssen wir zuerst einmal das XML-File einlesen:
// Einlesen der XML-Datei, die im gleichen Ordner des Scripts liegt
$xmlData = simplexml_load_string("bb_players.xml");
Als Nächstes geht es nun ans Auslesen des ersten Spielereintrags:
// Ausgabe des Spielernamens
echo($xmlData->spieler[0]->name);
Um das Team des ersten Spielers zu erfahren, müssen wir nur den folgenden Code
eingeben:
echo($xmlData->spieler[0]->team);
u
u
G R U N D L A G E N D E R P R O G R A M M I E R U N G 61
Das Auslesen der Daten eines XML-Knotens ist denkbar einfach. Es funktioniert im
Grunde wie bei einem Array. Um den ersten Eintrag auslesen zu können, müssen wir
im Fall eines Arrays an der Stelle 0 beginnen und bei einem XML-Knoten ist es genau-
so. Will man die Daten des zweiten Spielers unserer XML-Datei ausgeben, müssen wir
nur den zweiten Spielereintrag mit spieler[1] aufrufen.
// Ausgabe der zweiten Spielerdaten
echo($xmlData->spieler[1]->name);
echo($xmlData->spieler[1]->team);
Um alle Knoten der XML-Datei auszugeben, können wir eine for...each-Schleife
nutzen.
foreach($xmlData->spieler as $mySpieler){
echo($mySpieler -> name);
echo(" – ");
echo($mySpieler->team."<br />");
}
Attribute auslesen
Das Auslesen von Attributen in XML-Tags ist auch denkbar einfach. Diese können wie
assoziative Array-Einträge behandelt werden. Um dies zu testen, erweitern wir unsere
XML-Datei um ein Attribut mit dem Namen nickname im Tag name.
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<basketball>
<spieler>
<name nickname="Air Jordan">Michael Jordan</name>
<team>Chicago Bulls</team>
</spieler>
<spieler>
<name nickname="The Answer">Allen Iverson</name>
<team>Philadelphia 76ers</team>
</spieler>
</basketball>
Listing 2.82: Das Tag name wurde um ein Attribut erweitert.
Unsere angepasste for...each-Schleife sieht demnach so aus:
foreach($xmlData->spieler as $mySpieler){
echo($mySpieler -> name);
K A P I T E L 262
echo(" – ");
echo($mySpieler -> name[‚nickname']);
echo(" – ");
echo($mySpieler -> team."<br />");
}
Untergeordnete Knoten auslesen
Interessant ist noch, wie wir XML-Knoten auslesen können, deren Bezeichnung wir
nicht kennen. Dazu steht uns eine Funktion mit dem Namen children zur Verfü-
gung. Diese Funktion liest alle einem Knoten untergeordneten Knoten aus und spei-
chert diese in einem Array.
$arrKnoten = $xmlData->children();
foreach($arrKnoten as $arrMyKnoten){
$arrChildren = $arrMyKnoten->children();
foreach($arrChildren as $strKnoten => $varValue) {
echo("Knoten ".$strKnoten." hat den Wert ".$varValue."<br />");
}
}
Zuerst holen wir mit $arrKnoten = $xmlData->children(); alle Kindelemente des
obersten Elements <basketball> aus dem XML-Objekt $xmlData und speichern
diese in dem Array $arrKnoten.
Dann verarbeiten wir dieses Array mit einer for...each-Schleife. In dieser Schleife
werden alle Kinder des zweiten XML-Knotens <spieler> ausgelesen und im Array
$arrChildren gespeichert. Besonders an dieser for...each-Schleife ist, dass wir
neben den Werten des assoziativen Arrays auch die Schlüssel auslesen.
foreach($arrChildren as $strKnoten => $varValue)
Zum Schluss müssen wir nur noch die Daten des XML-Objekts auslesen.
echo("Knoten ".$strKnoten." hat den Wert ".$varValue."<br />");
2.12.3 XML-Dokumente erstellen
Um eine XML-Datei zu erstellen, nutzen wir die SimpleXML-Funktion asXML().
Wir erstellen einfach einen String mit der bereits bekannten XML-Struktur. Auf das
XML-Tag können wir verzichten, da dieses die Funktion asXML() für uns automatisch
hinzugefügt.
$data = "
<basketball>
G R U N D L A G E N D E R P R O G R A M M I E R U N G 63
<spieler>
<name>Michael Jordan</name>
<team>Chicago Bulls</team>
</spieler>
<spieler>
<name>Allen Iverson</name>
<team>Philadelphia 76ers</team>
</spieler>
</basketball>
";
Dann erstellen wir wieder ein SimpleXML-Objekt und definieren dieses als XML:
$xmlData = simplexml_load_string($data);
$xmlData = $xmlData->asXML();
Das war’s auch schon wieder. Zum Testen können wir die XML-Struktur noch im
Browser anzeigen:
echo($xmlData);
So, nun sind Sie für die weiteren Themen und die Workshops gerüstet. Viel Spaß beim
Weiterlesen.
3
BASISWISSEN
Ein Programm zum Erstellen von Animationen – passt das zur
Programmierung? Wir werden sehen ... Eines aber trotzdem
schon vorweg – die Antwort ist ja, ohne wenn und aber!
Im einführenden Kapitel vermittelte ich Ihnen die Grundlagen
der Programmierung. Dort haben Sie auch erfahren, dass diese
Grundlagen für (beinahe) alle Programmiersprachen gleich
sind. Es ist im Grunde meist vollkommen irrelevant, in welcher
Programmiersprache man gelernt hat zu programmieren – die
Logik ist immer dieselbe. In diesem Buch werden aber nur
PHP, JavaScript und ActionScript genutzt und erklärt. Welche
Punkte außerdem noch beachtet werden sollten und was Sie
als Flash-Entwickler an Basiswissen mitbringen sollten, klärt
dieses kurze Kapitel.
Wann immer eine neue Version von Flash auf dem Markt
erscheint, glänzen bei den Entwicklern die Augen. Auch bei mir
– ich muss es ehrlich zugeben. Jedoch sprechen wir in diesem
Buch über ein Thema, bei dem Weiterentwicklungen sehr träge
und zäh wirken, und das aus einem sehr einfachen Grund: Es
geht hier nicht um eine Schnittstelle zwischen Flash und PHP,
sondern um eine zwischen dem Browser auf der einen Seite
(dem Client) und dem Server auf der anderen. Flash läuft
clientseitig, PHP wird serverseitig ausgeführt. Wenn nicht am
Standard der Datenübertragung zwischen Server und Client
gearbeitet wird, sieht die Situation wie folgt aus: Die Daten-
übertragung erfolgt per GET oder per POST.
K A P I T E L 366
Was sollte hier noch hinzukommen? Nichts mehr, da muss ich Sie wohl enttäuschen.
Nein, „enttäuschen“ ist hier nicht die korrekte Aussage – vielmehr möchten wir Sie
noch einmal an die Technik „Server vs. Client“ erinnern, die klar und deutlich defi-
niert, dass eine Datenübertragung zwischen Client und Server auf genau diese beiden
Arten erfolgen kann und nicht anders!
Die wesentlich wichtigere Frage ist, was Sie unter diesen Bedingungen alles erzeugen
können. Genau hierauf eine Antwort zu geben, ist Ziel dieses Buchs. Einzig die Kom-
munikation zwischen Browser und Flash ist von grundlegendem Interesse für uns.
AJAX tut an dieser Stelle nichts anderes: Es greift auf den Datenaustausch zwischen
Server und Client per POST oder GET zurück. Der wesentliche Unterschied zum bis-
herigen Denken ist, dass AJAX auf Clientseite in der Lage ist, ohne ein Neuladen der
Seite nachträglich Daten vom Server abzufragen – dies ist ein Novum!
3.1 PHP
PHP läuft mittlerweile in Version 5 (bei Drucklegung war die letztgültige Version die
Version 5.2.3) objektorientiert – das konnte die Version 4 noch nicht. Obwohl – in
unseren Anwendungen trifft uns das nicht, denn die meisten gängigen Anwendungen
in Zusammenhang mit Flash oder AJAX werden nach wie vor ohne Objektorientierung
entwickelt. Natürlich kann man an dieser Stelle keine generelle Aussage treffen, denn
so ziemlich jede Anwendung ließe sich auch objektorientiert erstellen. Im Allgemeinen
sind die Scripts für die Zusammenarbeit mit Flash jedoch so kurz, das Objektorien-
tierte Programmierung (OOP) erst gar nicht zum Einsatz gelangt.
3.2 JavaScript (AJAX) & DOM
Im vorigen Kapitel wiederholten wir die Grundlagen der Programmierung, die natür-
lich auch für JavaScript gelten. Jede Programmiersprache hat ihre eigene „Umgebung“,
in der sie wirken – im Fall von JavaScript ist dies das XHTML-Dokument. Es besteht
zwar auch die Möglichkeit, JavaScript auf Serverseite zu verwenden, jedoch kommt
diese Variante in unserem Fall nicht zum Einsatz.
Die grundlegende Frage ist also, wie JavaScript mit seiner Umgebung interagieren
kann. In den letzten Jahren hat sich der Begriff DHTML (Dynamic HTML) eingebür-
gert – grundsätzlich meint man damit die Möglichkeit, JavaScript, CSS und XHTML
miteinander arbeiten zu lassen. Bleibt also zu klären, wie das möglich ist.
Unweigerlich stößt man dabei auf den Begriff des Document Object Model (DOM).
Ein DOM beschreibt grundsätzlich die Objekte, die in einem Dokument verwendet
werden, deshalb ist ein DOM auch nicht auf ein XHTML-Dokument beschränkt. Für
JavaScript in Zusammenhang mit (damals noch) HTML wurde vom W3-Consorti-
um ein DOM erstmals am 1. Oktober 1998 eingeführt, um der ewigen Diskrepanz
B A S I S W I S S E N 67
zwischen Netscape und Microsoft in Bezug auf JavaScript und JScript ein für alle mal
einen Riegel vorzuschieben. Ende September 2000 wurde dann eine weitere Version
dieses DOM veröffentlicht, das im November 2000 dann eine offizielle Empfehlung
des W3C erhielt. Ein wichtiger Punkt ist, dass sich das DOM (ich beziehe mich ab jetzt
nur noch auf das DOM für JavaScript) nicht speziell auf HTML-Elemente bezieht,
sondern in abstrakter Form Zugriff auf Objekte definiert. Grundsätzlich ist mit dem
DOM der Zugriff auf jedes XML-basierte Dokument möglich. Da jedoch auch auf die
Gegebenheiten von HTML im Speziellen eingegangen werden muss, existiert eine Art
„Kern-DOM“ speziell für die Bedürfnisse von HTML und den sich aus den Zwistig-
keiten zwischen Netscape und Microsoft ergebenen Differenzen.
Leider wurde in der Erstversion von DOM komplett auf ein Eventhandling verzichtet,
was speziell bei größeren Projekten unabdingbar notwendig ist. Daher muss oft auf die
Möglichkeiten des DOM 2.0 zurückgegriffen werden, das – und das haben Sie sicher-
lich schon erraten – in den verschiedenen Browsern noch nicht vollständig unterstützt
wird ...
3.2.1 „Kern-DOM“
ABBILDUNG 3.1
„Kern-DOM“ – die Grundlage
für alle gängigen Browser
K A P I T E L 368
Die obige Abbildung zeigt die Kernversion des DOM, das den Zugriff auf alle Elemente
innerhalb eines XHTML-Dokuments ermöglicht. Der Zugriff erfolgt grundsätzlich
hierarchisch: Möchte man beispielsweise auf ein Element innerhalb eines Formulars
zugreifen, so muss man den „Weg durch den Hierarchiebaum“ gehen:
1. Das übergeordnetste Element ist das window, also bezieht man sich zunächst auf
dieses Element: window. Selbstverständlich kann ein window auch ein Frame
sein.
2. Daraufhin greift man auf das Dokument im window zu: window.document.
3. Danach muss auf das Formular zugegriffen werden. Da es in einem XHTML-
DokumentmehralsnureinFormulargebenkann,existierteinArrayanFormularen,
das entweder assoziativ oder über den Formularindex angesprochen werden kann.
Der Formularindex bezieht sich auf die Reihenfolge der Formulare im Dokument:
Das nullte Formular ist somit das erste vorkommende Formular im XHTML-
Code. Viel einfacher ist der Zugriff über den Formularnamen (assoziativ):
window.document.forms[Formularindex]
oder
window.document.forms["Formularname"]
4. Hat man sich für ein Formular entschieden, kann man auf die Elemente (Buttons,
Eingabefelder etc.) innerhalb des Formulars zugreifen. Auch hier besteht natürlich
die Möglichkeit, dass sich mehr als nur ein Element im Formular befinden, deshalb
erfolgt der Zugriff auf die Elemente wieder über ein (assoziatives) Array:
window.document.forms["Formularname" oder –index].
elements["Elementname" oder –index]
5. Hat man diesen Weg erst einmal hinter sich gebracht, kann man auf alle
Eigenschaften und Methoden des Elements zugreifen.
Der Zugriff auf sämtliche HTML-Elemente funktioniert hier also immer gleich:
1. Weg durch den Hierarchiebaum zum Objekt finden
2. Auf die Attribute bzw. Eigenschaften des Objekts zugreifen
Eine komplette Auflistung aller Elemente und deren Eigenschaften und Methoden
ist die Aufgabe einer Referenz – ich empfehle Ihnen eine einschlägige Literatur bzw.
die Website http://de.selfhtml.org. Bücher zu diesem Thema füllen zum Teil
mehrere hundert Seiten und beschreiben im Detail jedes Element und alle zugehörigen
Details. Als Webdesigner sind Sie sicherlich mit diesen Elementen bereits vertraut, wes-
halb Sie sehr wahrscheinlich auch mit SelfHTML schon zu tun hatten.
B A S I S W I S S E N 69
3.2.2 Alternativer Zugriff auf Objekte
Eine andere Variante des Zugriffs auf Objekte innerhalb eines (XML-basierten) Doku-
ments ist der Zugriff über die Baumstruktur des Dokuments an sich. Betrachten wir
folgendes Beispiel:
<h1 class="myH1">Hier ist eine erste &Uuml;berschrift.</h1>
<p>Nun folgt Text, der verschiedene Auszeichnungen wie <strong>fett</
strong> oder <em>kursiv</em> aufweist.</p>
<p>So, ein zweiter Text, der <em><strong>fett und kursiv</strong></em>
geschrieben ist.</p>
Listing 3.1: Ein einfaches Beispiel eines XHTML-Dokuments
Die entsprechende Struktur dieses Dokuments wäre wie folgt:
Jedes Element innerhalb der Baumstruktur wird als Knoten bezeichnet. Man unter-
scheidet zwischen drei Arten von Knoten:
1. Elementknoten
2. Attributknoten
3. Textknoten
In der obigen Abbildung (Abbildung 3.2) sind nur Elementknoten dargestellt. Würden
wir alle Knoten darstellen, würde sich die Abbildung wie folgt erweitern:
ABBILDUNG 3.2
Die Baumstruktur des obigen
Beispiels (Listing 3.1)
K A P I T E L 370
Was in den Abbildungen auffällt (und selbstverständlich auch absichtlich so gezeichnet
ist ...), ist die Einteilung in sogenannte „Parent- und Child-Knoten“ sowie „Siblings“.
Die Baumstruktur ist wie eine Ahnengalerie zu verstehen:
Parent-Knoten sind übergeordnete Knoten: Zu <h1> existiert in unserem Fall kein
Parent-Knoten, zum ersten <strong> (zweite Ebene) ist der Parent-Knoten <p>,
zum zweiten <strong> (dritte Ebene) ist der Parent-Knoten <em>, dessen Parent
wiederum ein <p> ist.
Child-Knoten sind untergeordnete Knoten: <strong> ist beispielsweise ein
Child-Knoten von <p> usw.
Siblings sind „Geschwister“: <h1> hat beispielsweise die beiden Geschwister <p>
und <p>.
Um direkt und schnell auf einen beliebigen Knoten innerhalb eines Dokuments
zugreifen zu können, wurden drei Funktionen eingeführt:
getElementById(Element-ID): greift auf ein Element (einen Knoten) mit einer
(eindeutigen) id zu.
getElementsByName(Elementname)[i]: greift auf Elemente eines gewissen
Namens zu. Da der Name von Elementen im Dokument nicht eindeutig sein muss,
wird auf ein Array zugegriffen.
u
u
u
u
u
ABBILDUNG 2.3
Dieselbe Baumstruktur inklu-
sive Attribut- (durchgezogen
umrandet) und Textknoten
(gestrichelt umrandet)
B A S I S W I S S E N 71
getElementsByTagName(Tagname)[i]: greift auf Elemente eines gewissen Tag-
Namens (wie etwa „p“, „h1“ etc.) zu. Wie im Fall von getElementsByName gilt
auch hier: Es können mehrere Tags dieser Art existieren, deshalb erfolgt der Zugriff
über ein Array.
Hat man ein Element eindeutig identifiziert, kann man sich über die Eigenschaften
und Methoden des node-Objekts zu den weiteren Elementen „durcharbeiten“. Neh-
men wir ein Beispiel:
<h1 class="myH1">Hier ist eine erste &Uuml;berschrift.</h1>
<p id="myP01">Nun folgt Text, der verschiedene Auszeichnungen wie
<strong>fett</strong> oder <em>kursiv</em> aufweist.</p>
<p>So, ein zweiter Text, der <em><strong>fett und kursiv</strong></em>
geschrieben ist.</p>
Listing 3.2: Erweiterung des obigen Beispiels um id="myP01". Der Zugriff soll auf das Element <em>
erfolgen.
Ziel ist es, den Textknoten des <em> auszulesen. Um zunächst auf den Paragrafen mit
der id="myP01" zuzugreifen, verwendet man folgenden Befehl:
document.getElementById("myP01")
Da das Tag <em> das zweite Kind von <p> ist, verwenden wir das Array childNodes,
welches den Zugriff auf alle Child-Elemente eines gegebenen Knotens zulässt:
document.getElementById("myP01").childNodes[1]
Nun erfolgt der Zugriff auf den Textknoten. Hierbei ist zu berücksichtigen, dass ein
Textknoten immer ein Child-Knoten eines Elementknotens ist. Aus diesem Grund
erfolgt der Zugriff wie folgt:
document.getElementById("myP01").childNodes[1].firstChild
Der letzte Schritt besteht im Auslesen des Werts des Knotens – dies erfolgt über die
Eigenschaft nodeValue eines Knotens:
document.getElementById("myP01").childNodes[1].firstChild.nodeValue
Damit hätten wir den Wert des Knotens erreicht! Weitere Informationen zu Knoten
und deren Eigenschaften und Methoden finden Sie in der einschlägigen Literatur wie
beispielsweise der SelfHTML-Site.
Ein abschließender Tipp noch: Bedenken Sie, dass Sie per JavaScript erst dann auf
Knoten zugreifen können, wenn diese zum User übertragen wurden. Aus diesem
Grund sollte der Zugriff erst erfolgen, wenn die gesamte Seite zum User übertragen
wurde – ideal ist hier das Verwenden des Ereignisses onload des window-Objekts.
u
Textknoten ist
ein Kind des
Elementknotens
Textknoten ist
ein Kind des
Elementknotens
K A P I T E L 372
3.3 Flash
3.3.1 Sinnvolle Kombination von Flash und PHP
Ab wann – sprich ab welcher Generation von Flash – ist der Einsatz von Flash auf
Clientseite und PHP auf Serverseite sinnvoll? Seit der sechsten Version (Flash MX)
können wir bereits relativ problemlos über die LoadVars- und die XML-Klasse Daten
versenden und einlesen. Zwar wurde die XML-Klasse bereits mit Flash 5 eingeführt,
man konnte jedoch nur sehr eingeschränkt damit arbeiten. Die LoadVars-Klasse exis-
tiert hingegen erst ab Flash 6. Fassen wir kurz zusammen, ab welcher Generation uns
welche Möglichkeiten zur Verfügung standen:
1. Flash 5: Die Methode loadVariables (mittlerweile nur noch sehr selten
verwendet) stand schon ab Generation 4 von Flash bereit, die XML-Klasse wird
mit Flash 5 eingeführt.
2. Flash 6 (Flash MX): Macromedia integriert die LoadVars-Klasse.
3. Flash 7 (Flash MX 2004): Nachdem die loadVariables-Methode nicht mehr
adäquat ist, wird diese mit Release 7 von Flash überarbeitet und hat seitdem ein
geändertes Verhalten.
4. Flash 8: keine Neuerungen
5. Flash CS3: umfassende Änderungen durch die Einführung von ActionScript 3.0
Die achte Version von Flash brachte uns in puncto Kommunikation mit PHP auf Ser-
verseite also keine Neuerungen, weil sie technisch nicht sinnvoll bzw. möglich wären:
Zum Datenaustausch mit PHP stehen im Prinzip alle notwendigen Klassen bereit und
hinsichtlich der Client-Server-Kommunikation müsste ein Technologiewechsel statt-
finden. Die Möglichkeit, XML-Daten in Flash einzulesen, hat uns einen wesentlichen
Schritt weitergebracht und die Tür zu strukturierten Daten geöffnet. Eine Neuerung
hinsichtlich der Datenstrukturierung à la XML ist in naher Zukunft nicht zu erwarten
– auch Techniken wie RSS (Real Simple Syndication) bauen auf XML auf.
Flash CS3 bedeutete in dieser Hinsicht in Zusammenhang mit ActionScript 3.0 beina-
he eine „Revolution“. Das Laden von Daten jeglicher Art wurde durch die Einführung
der URLLoader- und URLRequest-Objekte komplett geändert. Viele der aus Action-
Script 2.0 bekannten Klassen wurden in ActionScript 3.0 entweder verschoben oder
umfassend umstrukturiert. Eine Übersicht aller Änderungen finden Sie am Ende des
Kapitels.
ActionScript
3.0 bringt die
Revolution
ActionScript
3.0 bringt die
Revolution
B A S I S W I S S E N 73
3.3.2 Weitere Verbindungsmöglichkeiten zur
Serverseite
Neben den genannten Klassen sind in Flash auch Komponenten installiert, mit deren
Hilfe man zu einem Server Kontakt aufbauen kann. Sie erfordern jedoch eine Instal-
lation auch auf Serverseite, die im Allgemeinen nicht gegeben ist (das Betreiben eines
Communication-Servers von Macromedia wäre ein Beispiel).
Jeder gute Webentwickler sollte in der Lage sein, auf solche zusätzlichen serverseitigen
Komponenten verzichten zu können, weil es einfach nicht der Realität entspricht, dass
uns solche Installationen zur Verfügung stehen. Deshalb wird der Beschreibung dieser
Komponenten in diesem Buch nur wenig Platz eingeräumt. Sollten Sie in der glück-
lichen Lage sein, auf einen Communication-Server von Macromedia zurückgreifen
zu können, dann schlagen Sie doch mal in der ActionScript-Referenz bei Camera und
Microphone nach – und flugs haben Sie einen Video-Chat gebastelt.
Keine zusätzlichen Server-Dienste verfügbar? Egal oder vielmehr – Gott sei dank! Wir
sind in der glücklichen Lage, eine definierte und (in naher Zukunft) auch nicht verän-
derbare Schnittstelle vorliegen zu haben, mit der wir in aller Ausführlichkeit arbeiten
können – nämlich das Senden von Daten vom Client zum Server per GET oder POST.
Dazu mehr in den folgenden Kapiteln.
3.3.3 ActionScript 3.0 – die wichtigsten
Änderungen
Nachfolgend finden Sie die wesentlichen Änderungen von ActionScript 2.0 auf Action-
Script 3.0 in Bezug auf die Themen dieses Buchs – eine umfassende Darstellung aller
Änderungen in den Klassen finden Sie im Anschluss.
1. Eigenschaften von MovieClips: Der bekannte Unterstrich „_“ am Beginn einer
MovieClip-Eigenschaftwurdeeliminiert(visibleanstatt_visible,alphaanstatt
_alpha, x anstatt _x usw.). Ebenso wurde die Handhabung von Prozentwerten
geändert: Die Werte werden nun von 0–1 anstatt von 0–100 angegeben.
2. Levelbezug und -verwaltung: Die Arrays _global und _root existieren nicht
mehr, wobei anstatt _root der Bezug über stage verwendet werden kann. Anstatt
_parent muss nun parent verwendet werden.
Ebenso hat sich die gesamte Verwaltung der Levels geändert. Die Methoden
swapDepths und getNextHighestDepth sind Vergangenheit – stattdessen
wird die Level-Verwaltung nun über die DisplayObjectContainer-Klasse
gespielt, wobei diese Klasse als ein Array aller verwendeten Objekte auf der Bühne
verstanden werden kann, die über einen Index angesprochen werden. So kann die
Reihenfolge (in z-Richtung) von Elementen nach wie vor beeinflusst und gesetzt
werden.
K A P I T E L 374
3. MovieClip vs. DisplayObjectContainer: Die meisten MovieClip-Funk-
tionen, die man bisher zur Entwicklung verwendet hat, wurden geändert.
Beispielsweise existiert die Methode createEmptyMovieClip nicht mehr.
Stattdessen wird die Methode addChild der DisplayObjectContainer-Klasse
verwendet. Dementsprechend lassen sich auch die Methoden createTextField,
duplicateMovieClip usw. nicht mehr auffinden.
4. Laden von Daten: In allen Bereichen des Datenladens haben sich Änderungen
ergeben.Grundsätzlich erfolgt nun der Ladevorgang immer über das URLRequest-
Objekt in Zusammenhang mit diversen anderen Objekten:
Bilder und SWF-Dateien: Es werden die Objekte URLRequest und URLLoader
verwendet. Die ActionScript 2.0-Variante mit loadMovie bzw. MovieClipLoader
wurde entfernt.
XML-Daten und Servervariablen: Auch hier wird auf die Objekte URLRequest
und URLLoader zurückgegriffen. Als zusätzliches Objekt kommt hier natürlich
das XML-Objekt zum Einsatz. Servervariablen können nach dem Laden direkt
angesprochen werden.
Laden einer URL: Die Funktion getURL wurde ebenfalls eliminiert. An ihre Stelle
treten die Funktionen sendToURL und navigateToURL.
5. Eventhandler: auch bei der Ereignisbehandlung hat sich einiges getan. Die
Ereignisse sind nun strukturierter, auch können – wie in ActionScript 2.0 gang
und gäbe – Button-Ereignisse auf MovieClips nicht mehr angewandt werden. Es
wurde beispielsweise auch das Ereignis onReleaseOutside komplett eliminiert
und es muss durch andere Techniken ersetzt werden. Eine Umbenennung vieler
Ereignisse (speziell Mausereignisse) hat ebenfalls stattgefunden.
B A S I S W I S S E N 75
ActionScript 3.0 – sämtliche Änderungen
ActionScript 2.0 ActionScript 3.0 Kommentare
Accessibility-Klasse flash.accessibility.
Accessibility
isActive() flash.accessibility.
Accessibility.active
Von einer Funktion zu einer
Accessor-Eigenschaft geändert.
Der Name wurde von isActive in
active geändert.
updateProperties() flash.accessibility.
Accessibility.updateProperties()
arguments-Klasse arguments
caller Entfernt Sie erreichen die gleiche
Funktionalität durch Übergeben
von arguments.callee als ein
Argument von der anrufenden
Funktion an die angerufene
Funktion.Ein Beispiel finden Sie im
Abschnitt„Beispiele“ unter argu-
ments.callee.
Array-Klasse Array Keine Änderung
CASEINSENSITIVE Array.CASEINSENSITIVE Der Datentyp wurde in uint
geändert.
DESCENDING Array.DESCENDING Der Datentyp wurde in uint
geändert.
length Array.length Der Datentyp wurde in uint
geändert.
NUMERIC Array.NUMERIC Der Datentyp wurde in uint
geändert.
RETURNINDEXEDARRAY Array.RETURNINDEXEDARRAY Der Datentyp wurde in uint
geändert.
UNIQUESORT Array.UNIQUESORT Der Datentyp wurde in uint
geändert.
Array Array.Array() Der Parameter wurde geändert
und verwendet jetzt das Format
...(rest).
push() Array.push() Der Parameter wurde geän-
dert und verwendet jetzt das
Parameterformat ...(rest).
sort() Array.sort() Der Datentyp des options-
Parameters wurde in uint geän-
dert.
K A P I T E L 376
ActionScript 2.0 ActionScript 3.0 Kommentare
sortOn() Array.sortOn() Der Datentyp des options-Para-
meters wurde in uint geändert.
Der Funktionsumfang wurde
unter ActionScript 3.0 erweitert.
Jetzt können Sie nach mehreren
Feldnamen sortieren,indem Sie
ein Objekte-Array für den field-
Name-Parameter übergeben.Wenn
Sie außerdem ein entsprechendes
Optionsflags-Array für den op-
tions-Parameter übergeben,kann
jedes Sortierfeld seinen eigenen
übereinstimmenden options-
Parameter aufweisen.
splice() Array.splice() Die Parameter können jeden Daten-
typ annehmen,die bevorzugten
Datentypen sind jedoch int und
uint.Der Parameter value wurde
in das Parameterformat ...(rest)
geändert.
unshift() Array.unshift() Der Parameter value wurde in das
Parameterformat ...(rest) geändert.
Der Datentyp des Rückgabewerts
wurde in uint geändert.
AsBroadcaster-Klasse flash.events.EventDispatcher
_listeners flash.events.EventDispatcher.
willTrigger()
Kein direktes Äquivalent.Die
willTrigger()-Methode meldet
Ihnen zwar,ob Listener regis-
triert sind,jedoch nicht wie viele.
addListener() flash.events.EventDispatcher.
addEventListener()
Kein direktes Äquivalent,da Sie im
ActionScript 3.0-Ereignismodell
nicht nur dem Broadcaster-
Objekt,sondern jedem Objekt im
Ereignisablauf Ereignis-Listener
hinzufügen können.
broadcastMessage() flash.events.EventDispatcher.
dispatchEvent()
Kein direktes Äquivalent,da das
ActionScript 3.0-Ereignismodell
auf andere Weise arbeitet.Die
dispatchEvent()-Methode
sendet ein Ereignisobjekt in
den Ereignisablauf,während die
broadcastMessage()-Methode
Meldungen direkt an jedes regis-
trierte Listener-Objekt sendet.
B A S I S W I S S E N 77
ActionScript 2.0 ActionScript 3.0 Kommentare
initialize() Entfernt Es gibt kein direktes Äquivalent
in ActionScript 3.0,aber eine
ähnliche Funktionalität wird
durch die Unterklassen der
EventDispatcher-Klasse er-
reicht.Beispielsweise erweitert
die DisplayObject-Klasse
EventDispatcher,daher sind alle
Instanzen von DisplayObject
und der DisplayObject-
Unterklassen in der Lage,
Ereignisobjekte zu senden und zu
empfangen.
removeListener() flash.events.EventDispatcher.
removeEventListener()
Kein direktes Äquivalent,da Sie im
ActionScript 3.0-Ereignismodell
nicht nur dem Broadcaster-
Objekt,sondern jedem Objekt im
Ereignisablauf Ereignis-Listener
hinzufügen und wieder entfernen
können.
BitmapData-Klasse flash.display.BitmapData ActionScript 3.0 verwendet die
BitmapDataChannel-Klasse zur
Aufzählung der Konstanten,die
den zu verwendenden Kanal
angeben.
height flash.display.BitmapData.
height
Der Datentyp wurde von Number
in int geändert.
rectangle flash.display.BitmapData.rect Die Eigenschaft wurde um-
benannt,um für Konsistenz mit
anderen Mitgliedern der API zu
sorgen.
width flash.display.BitmapData.width Der Datentyp wurde von Number
in int geändert.
copyChannel() flash.display.BitmapData.co-
pyChannel()
Die Datentypen der Parameter
code,sourceChannel und dest-
Channel wurden in uint geän-
dert.
draw() flash.display.BitmapData.
draw()
Der source-Parameter lau-
tet jetzt IBitmapDrawable;
DisplayObject und BitmapData
implementieren jetzt die
IBitmapDrawable-Schnittstelle,
so dass Sie entweder ein
DisplayObject- oder ein
BitmapData-Objekt an den
Parameter source übergeben
können.
fillRect() flash.display.BitmapData.fill-
Rect()
Der Datentyp des Parameters
color wurde in uint geändert.
floodFill() flash.display.BitmapData.
floodFill()
Akzeptiert jetzt int-Werte für die
Parameter x und y sowie einen
uint-Wert für color.
getColorBoundsRect() flash.display.BitmapData.get-
ColorBoundsRect()
Akzeptiert jetzt uint-Werte für die
Parameter mask und color.
K A P I T E L 378
ActionScript 2.0 ActionScript 3.0 Kommentare
getPixel() flash.display.BitmapData.get-
Pixel()
Akzeptiert jetzt int-Parameter-
werte und gibt einen uint-Wert
zurück.
getPixel32() flash.display.BitmapData.get-
Pixel32()
Akzeptiert jetzt int-Parameter-
werte und gibt einen uint-Wert
zurück.
hitTest() flash.display.BitmapData.hit-
Test()
Akzeptiert jetzt uint-Werte für die
Parameter firstAlphaThreshold
und secondAlphaThreshold.
loadBitmap() Entfernt Diese Funktion wird wegen der
neuen Bitmap-Unterstützung in
ActionScript 3.0 nicht mehr be-
nötigt.
merge() flash.display.BitmapData.
merge()
Akzeptiert jetzt uint-Werte für die
Multiplizierer-Parameter.
noise() flash.display.BitmapData.noi-
se()
Akzeptiert jetzt einen int-Wert für
den Parameter randomSeed und
uint-Werte für die Parameter low,
high und channelOptions.
perlinNoise() flash.display.BitmapData.per-
linNoise()
Akzeptiert jetzt einen int-Wert
für den Parameter randomSeed
und uint-Werte für die Parameter
numOctaves und channel-
Options.
pixelDissolve() flash.display.BitmapData.
pixelDissolve()
Akzeptiert jetzt einen int-Wert für
die Parameter randomSeed und
numPixels sowie einen uint-Wert
für den Parameter fillColor.
(Der numPixels-Parameter wurde
in ActionScript 2.0 in numberOf-
Pixels umbenannt.)
scroll() flash.display.BitmapData.
scroll()
Akzeptiert jetzt int-Werte für die
Parameter x und y.
setPixel() flash.display.BitmapData.set-
Pixel()
Akzeptiert jetzt int-Werte für die
Parameter x und y sowie einen
uint-Wert für color.
setPixel32() flash.display.BitmapData.set-
Pixel32()
Akzeptiert jetzt int-Werte für die
Parameter x und y sowie einen
uint-Wert für color.
threshold() flash.display.BitmapData.
threshold()
Akzeptiert jetzt uint-Werte für die
Parameter threshold,color und
mask und gibt einen uint-Wert
zurück.
BlurFilter-Klasse
quality flash.filters.BlurFilter.qua-
lity
Der Datentyp der quality-
Eigenschaft wurde von Number in
uint geändert.
Button-Klasse flash.display.SimpleButton
_alpha flash.display.DisplayObject.
alpha
blendMode flash.display.DisplayObject.
blendMode
B A S I S W I S S E N 79
ActionScript 2.0 ActionScript 3.0 Kommentare
cacheAsBitmap flash.display.DisplayObject.
cacheAsBitmap
enabled flash.display.SimpleButton.
enabled
filters flash.display.DisplayObject.
filters
In ActionScript 3.0 lautet der
Datentyp Array.
_focusrect flash.display.
InteractiveObject.focusRect
_height flash.display.DisplayObject.
height
_highquality Entfernt Siehe Stage.quality
_name flash.display.DisplayObject.
name
_parent flash.display.DisplayObject.
parent
_quality Entfernt Sie können die Wiedergabequalität
aller Anzeigeobjekte mit flash.
display.Stage.quality ein-
stellen.
_rotation flash.display.DisplayObject.
rotation
scale9Grid flash.display.DisplayObject.
scale9Grid
_soundbuftime flash.media.SoundMixer.buffer-
Time
In die SoundMixer-Klasse
verschoben,die zur globalen
Soundsteuerung verwendet
wird.Umbenannt,sodass keine
Abkürzungen mehr vorhanden
sind.Der Unterstrich am Anfang
des Namens wurde entfernt.
tabEnabled flash.display.
InteractiveObject.tabEnabled
tabIndex flash.display.
InteractiveObject.tabIndex
_target Entfernt ActionScript 3.0 identifiziert
Anzeigeobjekte direkt,daher
ist die Identifizierung eines
Anzeigeobjekts über dessen Pfad
nicht mehr notwendig.
trackAsMenu flash.display.SimpleButton.
trackAsMenu
_url Entfernt Siehe DisplayObject.loader-
Info.url
useHandCursor flash.display.SimpleButton.
useHandCursor
_visible flash.display.DisplayObject.
visible
_width flash.display.DisplayObject.
width
_x flash.display.DisplayObject.x
_xmouse flash.display.DisplayObject.
mouseX
_xscale flash.display.DisplayObject.
scaleX
_y flash.display.DisplayObject.y
K A P I T E L 380
ActionScript 2.0 ActionScript 3.0 Kommentare
_ymouse flash.display.DisplayObject.
mouseY
_yscale flash.display.DisplayObject.
scaleY
getDepth() flash.display.
DisplayObjectContainer.get-
ChildIndex()
ActionScript 3.0 bietet direkten
Zugriff auf die Anzeigeliste,daher
wird die Tiefe auf andere Weise
bearbeitet.
onDragOut() flash.display.
InteractiveObject dispatches
event: mouseOut
Wurde im neuen Ereignismodell
durch ein mouseOut-Ereignis
ersetzt.
onDragOver() flash.display.
InteractiveObject dispatches
event: mouseOver
Wurde im neuen Ereignismodell
durch ein mouseOver-Ereignis
ersetzt.
onKeyDown() flash.display.
InteractiveObject dispatches
event: keyDown
Wurde im neuen Ereignismodell
durch ein keyDown-Ereignis er-
setzt.
onKeyUp() flash.display.
InteractiveObject dispatches
event: keyUp
Wurde im neuen Ereignismodell
durch ein keyUp-Ereignis ersetzt.
onKillFocus() flash.display.
InteractiveObject dispatches
event: focusOut
Wurde im neuen Ereignismodell
durch ein focusOut-Ereignis
ersetzt.
onPress() flash.display.
InteractiveObject dispatches
event: mouseDown
Wurde im neuen Ereignismodell
durch ein mouseDown-Ereignis
ersetzt.
onRelease() flash.display.
InteractiveObject dispatches
event: mouseUp
Wurde im neuen Ereignismodell
durch ein mouseUp-Ereignis er-
setzt.
onReleaseOutside() flash.display.
InteractiveObject dispatches
event: mouseUp
Wurde im neuen Ereignismodell
durch ein mouseUp-Ereignis er-
setzt.
onRollOut() flash.display.
InteractiveObject dispatches
event: mouseOut
Wurde im neuen Ereignismodell
durch ein mouseOut-Ereignis
ersetzt.
onRollOver() flash.display.
InteractiveObject dispatches
event: mouseOver
Wurde im neuen Ereignismodell
durch ein mouseOver-Ereignis
ersetzt.
onSetFocus() flash.display.
InteractiveObject dispatches
event: focusIn
Wurde im neuen Ereignismodell
durch ein focusIn-Ereignis er-
setzt.
Camera-Klasse flash.media.Camera
activityLevel flash.media.Camera.activity-
Level
bandwidth flash.media.Camera.bandwidth
currentFps flash.media.Camera.currentFPS Änderung bei der Groß-/
Kleinschreibung von FPS
fps flash.media.Camera.fps
height flash.media.Camera.height Der Datentyp wurde von Number
in int geändert.
index flash.media.Camera.index Der Datentyp wurde von String
in int geändert.
B A S I S W I S S E N 81
ActionScript 2.0 ActionScript 3.0 Kommentare
motionLevel flash.media.Camera.motionLevel Der Datentyp wurde von Number
in int geändert.
motionTimeOut flash.media.Camera.motionTime-
out
Der Datentyp wurde von Number
in int geändert.
muted flash.media.Camera.muted
name flash.media.Camera.name
names flash.media.Camera.names
quality flash.media.Camera.quality Der Datentyp wurde von Number
in int geändert.
width flash.media.Camera.width Der Datentyp wurde von Number
in int geändert.
get() flash.media.Camera.getCamera()
onActivity() flash.events.ActivityEvent.
ACTIVITY
onStatus() flash.media.Camera dispatches
event: status
Wurde im neuen Ereignismodell
durch ein StatusEvent-Objekt
status ersetzt.
setMode() flash.media.Camera.setMode() Die Parameter width und height
wurden zum Datentyp int geän-
dert.
setMotionLevel() flash.media.Camera.setMotion-
Level()
Beide Parameter wurden zum
Datentyp int geändert.
setQuality() flash.media.Camera.setQuality() Beide Parameter wurden zum
Datentyp int geändert.
capabilities-Klasse flash.system.Capabilities Bei diesem Klassennamen wurde
die Groß-/Kleinschreibung geän-
dert.
Color-Klasse flash.geom.ColorTransform Die Color-Klasse wurde entfernt,
da die gesamte Funktionalität
dieser Klasse auch mit der
flash.geom.ColorTransform-
Klasse erreicht werden kann.
Farbwerte lassen sich mit-
hilfe des ColorTransform-
Klassenkonstruktors oder dessen
Eigenschaften direkt zuweisen.
ColorTransform-Objekte können
dann der Eigenschaft color-
Transform eines Transform-
Objekts zugewiesen werden,
die wiederum der Eigenschaft
transform einer DisplayObject-
Instanz zugewiesen werden kann.
Color flash.geom.ColorTransform.
ColorTransform()
Entfernt.Sie können Farbwerte
mithilfe des ColorTransform()-
Konstruktors zuweisen.
getRGB() flash.geom.ColorTransform.
color
Auf den RGB-Farbwert kann mithil-
fe der Accessor-Eigenschaft co-
lor der ColorTransform-Klasse
zugegriffen werden.
K A P I T E L 382
ActionScript 2.0 ActionScript 3.0 Kommentare
getTransform() Entfernt Farbwerte können mithilfe
des ColorTransform()-
Klassenkonstruktors oder dessen
Eigenschaften direkt zugewiesen
werden.
setRGB() flash.geom.ColorTransform.
color
Der RGB-Farbwert kann mithilfe
der Accessor-Eigenschaft color
der ColorTransform-Klasse ein-
gerichtet werden.
setTransform() Entfernt Farbwerte können mithilfe
des ColorTransform()-
Klassenkonstruktors oder dessen
Eigenschaften direkt zugewiesen
werden.
ContextMenu-Klasse flash.ui.ContextMenu Die ContextMenu-Klasse ist jetzt
Teil des flash.ui-Pakets.
builtInItems flash.ui.ContextMenu.built-
InItems
customItems flash.ui.ContextMenu.custom-
Items
ContextMenu flash.ui.ContextMenu.
ContextMenu()
copy() flash.ui.ContextMenu.clone()
hideBuiltInItems() flash.ui.ContextMenu.hideBuilt-
InItems()
onSelect() flash.ui.ContextMenu dispat-
ches event: menuSelect
Anstatt die Ereignisprozedur on-
Select() aufzurufen,löst diese
ActionScript 3.0-Klasse ein menu-
Select-Ereignis aus.
ContextMenuItem-Klasse flash.ui.ContextMenuItem Die ContextMenuItem-Klasse ist
jetzt Teil des flash.ui-Pakets.
caption flash.ui.ContextMenuItem.cap-
tion
enabled flash.ui.ContextMenuItem.en-
abled
separatorBefore flash.ui.ContextMenuItem.sepa-
ratorBefore
visible flash.ui.ContextMenuItem.vi-
sible
ContextMenuItem flash.ui.ContextMenuItem.
ContextMenuItem()
copy() flash.ui.ContextMenuItem.clo-
ne()
onSelect() flash.ui.ContextMenuItem dis-
patches event: menuItemSelect
Anstatt die Ereignisprozedur on-
Select() aufzurufen,löst diese
ActionScript 3.0-Klasse ein menu-
Select-Ereignis aus.
ConvolutionFilter-
Klasse
clone() flash.filters.
ConvolutionFilter.clone()
Gibt jetzt ein BitmapFilter-
Objekt zurück.
B A S I S W I S S E N 83
ActionScript 2.0 ActionScript 3.0 Kommentare
Date-Klasse Date ActionScript 3.0 umfasst ein neu-
es Set von Read-Accessoren für
alle Methoden,die mit getxxx()
beginnen.Beispielsweise geben
Date.getDate() und Date.date
in ActionScript 3.0 den gleichen
Wert zurück.
getUTCFullYear() Date.getUTCFullYear() Keine Änderung.
getYear() Date.getFullYear() Diese Methode wurde entfernt,da
sie nicht zum ECMAScript gehört.
Verwenden Sie stattdessen Date.
getFullYear().
setFullYear() Date.setFullYear() Keine Änderung
DisplacementMapFilter-
Klasse
flash.filters.
DisplacementMapFilter
Der Datentyp verschiedener
Parameter wurde von Number in
uint geändert.
color flash.filters.
DisplacementMapFilter.color
Der Datentyp dieses Parameters
lautet jetzt uint.
componentX flash.filters.
DisplacementMapFilter.compo-
nentX
Der Datentyp dieses Parameters
lautet jetzt uint.
componentY flash.filters.
DisplacementMapFilter.compo-
nentY
Der Datentyp dieses Parameters
lautet jetzt uint.
DisplacementMapFilter flash.filters.
DisplacementMapFilter.
DisplacementMapFilter()
Der Datentyp der Parameter com-
ponentX,componentY und color
wurde in uint geändert.
clone() flash.filters.
DisplacementMapFilter.clone()
Gibt jetzt ein BitmapFilter-
Objekt zurück.
DropShadowFilter-Klasse flash.filters.DropShadowFilter
color flash.filters.
DropShadowFilter.color
Der Datentyp dieses Parameters
wurde von Number in uint geän-
dert.
quality flash.filters.
DropShadowFilter.quality
Der Datentyp dieses Parameters
wurde von Number in uint geän-
dert.
DropShadowFilter flash.filters.
DropShadowFilter.
DropShadowFilter()
Alle Parameter weisen jetzt ei-
nen Standardwert auf.Einige
Parametertypen wurden geändert.
clone() flash.filters.
DropShadowFilter.clone()
Gibt jetzt ein BitmapFilter-
Objekt anstelle eines Drop-
ShadowFilter-Objekts zurück.
Error-Klasse Error Zur Unterstützung beim
Debugging wurde eine neue
getStackTrace()-Methode
hinzugefügt.
ExternalInterface-
Klasse
flash.external.
ExternalInterface
Für zwei Methoden dieser Klasse
wurden die Parameter geändert.
K A P I T E L 384
ActionScript 2.0 ActionScript 3.0 Kommentare
addCallback() flash.external.
ExternalInterface.addCall-
back()
Die ActionScript 3.0-Version dieser
Methode akzeptiert keinen in-
stance-Parameter.Der method-
Parameter wurde durch einen
closure-Parameter ersetzt,der
einen Verweis auf eine Funktion,
eine Klassenmethode oder eine
Methode einer bestimmten
Klasseninstanz enthalten kann.
Darüber hinaus kann der aufrufen-
de Code aus Sicherheitsgründen
nicht auf den Verweis closure
zugreifen.In diesem Fall wird der
Ausnahmefehler SecurityError
erzeugt.
call() flash.external.
ExternalInterface.call()
Wenn ein Problem auftritt,erzeugt
die ActionScript 3.0-Version dieser
Methode eine Fehlermeldung
oder den Ausnahmefehler
SecurityError und gibt darüber
hinaus null zurück.
FileReference-Klasse flash.net.FileReference Die ActionScript 3.0-Version dieser
Klasse übernimmt die Methoden
addEventListener() und
removeEventListener() von
der EventDispatcher-Klasse.
Die Ereignisverarbeitungsfunk-
tionen werden durch ausgelöste
Ereignisse ersetzt.
postData flash.net.URLRequest.data ActionScript 2.0 in Flash Player 9
wurde die postData-Eigenschaft
hinzugefügt,um POST-Daten
mit dem Datei-Upload oder
-Download zu senden.In
ActionScript 3.0 verwenden Sie die
Eigenschaft data der URLRequest-
Klasse,um entweder POST- oder
GET-Daten zu senden.Weitere
Informationen finden Sie unter
flash.net.URLRequest.data in
diesem Referenzhandbuch.
size flash.net.FileReference.size Gibt den Datentyp uint anstelle
von Number zurück.
addListener() flash.events.EventDispatcher.
addEventListener()
Im neuen Ereignismodell ist
eine klassenspezifische addLis-
tener()-Methode nicht mehr
erforderlich,da die Klasse die
addEventListener()-Methode
von der EventDispatcher-Klasse
übernimmt.
B A S I S W I S S E N 85
ActionScript 2.0 ActionScript 3.0 Kommentare
browse() flash.net.FileReference.brow-
se()
Gibt in ActionScript 2.0 beim
Auftreten eines Fehlers fal-
se zurück.In ActionScript 3.0
wird der Ausnahmefehler
IllegalOperationError oder
ArgumentError erzeugt.Dennoch
gibt die Methode noch immer
false zurück,wenn die Parameter
ungültig sind,das Dialogfeld zum
Suchen nach Dateien nicht öffnet
oder eine weitere Browser-Sitzung
ausgeführt wird.Darüber hinaus
wurde der typelist-Parameter
geändert.In ActionScript 2.0 kön-
nen Sie die browse()-Methode an
ein Array mit Zeichenfolgen über-
geben,um einen Dateifilter anzu-
geben.In ActionScript 3.0 überge-
ben Sie ein Array von Filtern.
download() flash.net.FileReference.down-
load()
Gibt beim Auftreten eines Fehlers
Ausnahmefehler anstelle von
false aus.Der Datentyp des ers-
ten Parameters wurde geändert.In
ActionScript 2.0 ist der erste von
Ihnen an download() übergebene
Parameter eine Zeichenfolge.In
ActionScript 3.0 übergeben Sie ein
URLRequest-Objekt.
removeListener() flash.events.EventDispatcher.
removeEventListener()
Im neuen Ereignismodell ist eine
klassenspezifische removeLis-
tener()-Methode nicht mehr
erforderlich,da die Klasse die re-
moveEventListener()-Methode
von der EventDispatcher-Klasse
übernimmt.
K A P I T E L 386
ActionScript 2.0 ActionScript 3.0 Kommentare
upload() flash.net.FileReference.up-
load()
Es wurden verschiedene
Änderungen vorgenommen:
Der Datentyp des ersten
Parameters wurde geändert.In
ActionScript 2.0 ist der erste von
Ihnen an upload() übergebene
Parameter eine Zeichenfolge.In
ActionScript 3.0 übergeben Sie ein
URLRequest-Objekt.
In ActionScript 3.0 gibt es einen
neuen zweiten Parameter,up-
loadDataFieldName,bei dem es
sich um einen Feldnamen handelt,
der den Dateidaten in der POST-
Operation des Upload-Vorgangs
voransteht.
In ActionScript 3.0 gibt es einen
neuen dritten Parameter,test-
Upload,mit dem Sie steuern
können,ob Flash Player einen Test-
Upload durchführt,bevor die Datei
hochgeladen wird.
Wenn ein Fehler auftritt,erzeugt
browse() Ausnahmefehler-
meldungen anstelle von false.
onCancel flash.net.FileReference dis-
patches event: cancel
Diese Klasse ruft in ActionScript 3.0
nicht mehr die Ereignisprozedur
onCancel() auf,sondern löst
ein Ereignis mit der Bezeichnung
cancel aus.
onComplete flash.net.FileReference dis-
patches event: complete
Diese Klasse ruft in ActionScript 3.0
nicht mehr die Ereignisprozedur
onComplete() auf,sondern löst
ein Ereignis mit der Bezeichnung
complete aus.
onHTTPError flash.net.FileReference dis-
patches event: httpStatus
Diese Klasse ruft in ActionScript 3.0
nicht mehr die Ereignisprozedur
onHTTPError() auf,sondern löst
ein Ereignis mit der Bezeichnung
httpStatus aus.
onIOError flash.net.FileReference dis-
patches event: ioError
Diese Klasse ruft in ActionScript 3.0
nicht mehr die Ereignisprozedur
onIOError() auf,sondern löst
ein Ereignis mit der Bezeichnung
ioError aus.
onOpen flash.net.FileReference dis-
patches event: open
Diese Klasse ruft in ActionScript 3.0
nicht mehr die Ereignisprozedur
onOpen() auf,sondern löst ein
Ereignis mit der Bezeichnung open
aus.
B A S I S W I S S E N 87
ActionScript 2.0 ActionScript 3.0 Kommentare
onProgress flash.net.FileReference dis-
patches event: progress
Diese Klasse ruft in ActionScript 3.0
nicht mehr die Ereignisprozedur
onProgress() auf,sondern löst
ein Ereignis mit der Bezeichnung
progress aus.
onSecurityError flash.net.FileReference dis-
patches event: securityError
Diese Klasse ruft in ActionScript 3.0
nicht mehr die Ereignisprozedur
onSecurityError() auf,son-
dern löst ein Ereignis mit der
Bezeichnung securityError aus.
onSelect flash.net.FileReference dis-
patches event: select
Diese Klasse ruft in ActionScript 3.0
nicht mehr die Ereignisprozedur
onSelect() auf,sondern löst
ein Ereignis mit der Bezeichnung
select aus.
onUploadCompleteData flash.net.FileReference dis-
patches event: complete
Diese Klasse ruft in ActionScript 3.0
nicht mehr die Ereignisprozedur
onUploadCompleteData() auf,
sondern löst ein Ereignis mit der
Bezeichnung uploadComplete-
Data aus.
FileReferenceList-
Klasse
flash.net.FileReferenceList Diese ActionScript 3.0-Klasse
übernimmt die Methoden ad-
dEventListener() und remo-
veEventListener() von der
EventDispatcher-Klasse.Anstelle
der Ereignisprozeduren onCan-
cel() und onSelect() verwen-
det diese ActionScript 3.0-Klasse
die Ereignisse cancel und select.
addListener() flash.events.EventDispatcher.
addEventListener()
Im neuen Ereignismodell ist
eine klassenspezifische addLis-
tener()-Methode nicht mehr
erforderlich,da die Klasse die
addEventListener()-Methode
von der EventDispatcher-Klasse
übernimmt.
browse() flash.net.FileReferenceList.
browse()
Diese Methode gibt in ActionScript
3.0 beim Auftreten eines Fehlers
nicht false zurück,sondern
erzeugt den Ausnahmefehler
IllegalOperationError.
Darüber hinaus wurde der type-
list-Parameter geändert.In
ActionScript 2.0 können Sie die
browse()-Methode an ein Array
mit Zeichenfolgen übergeben,um
einen Dateifilter anzugeben.In
ActionScript 3.0 übergeben Sie ein
Array von Filtern.
K A P I T E L 388
ActionScript 2.0 ActionScript 3.0 Kommentare
removeListener() flash.events.EventDispatcher.
removeEventListener()
Im neuen Ereignismodell ist eine
klassenspezifische removeLis-
tener()-Methode nicht mehr
erforderlich,da die Klasse die re-
moveEventListener()-Methode
von der EventDispatcher-Klasse
übernimmt.
onCancel flash.net.FileReferenceList
dispatches event: cancel
Diese Klasse ruft in ActionScript 3.0
nicht mehr die Ereignisprozedur
onCancel() auf,sondern löst
ein Ereignis mit der Bezeichnung
cancel aus.
onSelect flash.net.FileReferenceList
dispatches event: select
Diese Klasse ruft in ActionScript 3.0
nicht mehr die Ereignisprozedur
onSelect() auf,sondern löst
ein Ereignis mit der Bezeichnung
select aus.
GlowFilter-Klasse flash.filters.GlowFilter Der Datentyp mehrerer Parameter
wurde von Number zu uint ge-
ändert.
color flash.filters.GlowFilter.color Der Datentyp dieser Eigenschaft
wurde von Number zu uint ge-
ändert.
quality flash.filters.GlowFilter.qua-
lity
Der Datentyp dieser Eigenschaft
wurde von Number zu uint ge-
ändert.
GlowFilter flash.filters.GlowFilter.
GlowFilter()
Die Parameter color und qua-
lity weisen jetzt die Datentypen
uint und int anstelle von Number
auf.Allen Parametern ist jetzt ein
Standardwert zugewiesen.
clone() flash.filters.GlowFilter.
clone()
Gibt ein BitmapFilter-Objekt an-
stelle eines GlowFilter-Objekts
zurück.
GradientBevelFilter-
Klasse
flash.filters.
GradientBevelFilter
quality flash.filters.
GradientBevelFilter.quality
Der Datentyp dieser Eigenschaft
wurde von Number in int geän-
dert.
clone() flash.filters.
GradientBevelFilter.clone()
Gibt ein BitmapFilter-
Objekt anstelle eines
GradientBevelFilter-Objekts
zurück.
GradientGlowFilter-
Klasse
flash.filters.
GradientGlowFilter
quality flash.filters.
GradientGlowFilter.quality
Der Datentyp dieser Eigenschaft
wurde von Number zu int geän-
dert.
GradientGlowFilter flash.filters.
GradientGlowFilter.
GradientGlowFilter()
Allen Parametern sind jetzt
Standardwerte zugewiesen und
der Datentyp des quality-
Parameters wurde von Number zu
int geändert.
B A S I S W I S S E N 89
ActionScript 2.0 ActionScript 3.0 Kommentare
clone() flash.filters.
GradientGlowFilter.clone()
Gibt ein BitmapFilter-Objekt an-
stelle eines GradientGlowFilter-
Objekts zurück.
IME-Klasse flash.system.IME Diese Klasse wurde in das flash.
system-Paket verschoben.
ALPHANUMERIC_FULL flash.system.
IMEConversionMode.
ALPHANUMERIC_FULL
ALPHANUMERIC_HALF flash.system.
IMEConversionMode.
ALPHANUMERIC_HALF
CHINESE flash.system.
IMEConversionMode.CHINESE
JAPANESE_HIRAGANA flash.system.
IMEConversionMode.JAPANESE_
HIRAGANA
JAPANESE_KATAKANA_FULL flash.system.
IMEConversionMode.JAPANESE_
KATAKANA_FULL
JAPANESE_KATAKANA_HALF flash.system.
IMEConversionMode.JAPANESE_
KATAKANA_HALF
KOREAN flash.system.
IMEConversionMode.KOREAN
UNKNOWN flash.system.
IMEConversionMode.UNKNOWN
addListener() flash.events.EventDispatcher.
addEventListener()
Im neuen Ereignismodell ist
eine klassenspezifische addLis-
tener()-Methode nicht mehr
erforderlich,da die Klasse die
addEventListener()-Methode
von der EventDispatcher-Klasse
übernimmt.
getConversionMode() flash.system.IME.conversion-
Mode
Wurde in eine Accessor-
Eigenschaft geändert.
getEnabled() flash.system.IME.enabled Wurde in eine Accessor-
Eigenschaft geändert.
removeListener() flash.events.EventDispatcher.
removeEventListener()
Im neuen Ereignismodell ist eine
klassenspezifische removeLis-
tener()-Methode nicht mehr
erforderlich,da die Klasse die re-
moveEventListener()-Methode
von der EventDispatcher-Klasse
übernimmt.
setConversionMode() flash.system.IME.conversion-
Mode
Wurde in eine Accessor-
Eigenschaft geändert.
setEnabled() flash.system.IME.enabled Wurde in eine Accessor-
Eigenschaft geändert.
onIMEComposition flash.system.IME dispatches
event: imeComposition
Diese Klasse ruft in ActionScript 3.0
nicht mehr die Ereignisprozedur
onIMEComposition() auf,son-
dern löst ein Ereignis mit der
Bezeichnung imeComposition
aus.
K A P I T E L 390
ActionScript 2.0 ActionScript 3.0 Kommentare
Key-Klasse flash.ui.Keyboard Diese Klasse hat in ActionScript
3.0 einen neuen Namen,damit
sie anderen zur Keyboard-Klasse
gehörenden Klassen entspricht,
wie z.B.KeyboardEvent.
BACKSPACE flash.ui.Keyboard.BACKSPACE Wird in ActionScript 3.0 als eine
Konstante deklariert.Der Datentyp
wurde in uint geändert.
CAPSLOCK flash.ui.Keyboard.CAPS_LOCK Wird in ActionScript 3.0 als
eine Konstante deklariert.Ein
Unterstrich wurde hinzugefügt
und der Datentyp wurde in uint
geändert.
CONTROL flash.ui.Keyboard.CONTROL Wird in ActionScript 3.0 als eine
Konstante deklariert.Der Datentyp
wurde in uint geändert.
DELETEKEY flash.ui.Keyboard.DELETE Der Name wurde in ActionScript
3.0 zu DELETE geändert.Das
Objekt wird als eine Konstante
deklariert und der Datentyp wurde
in uint geändert.
DOWN flash.ui.Keyboard.DOWN Wird in ActionScript 3.0 als eine
Konstante deklariert.Der Datentyp
wurde in uint geändert.
END flash.ui.Keyboard.END Wird in ActionScript 3.0 als eine
Konstante deklariert.Der Datentyp
wurde in uint geändert.
ENTER flash.ui.Keyboard.ENTER Wird in ActionScript 3.0 als eine
Konstante deklariert.Der Datentyp
wurde in uint geändert.
ESCAPE flash.ui.Keyboard.ESCAPE Wird in ActionScript 3.0 als eine
Konstante deklariert.Der Datentyp
wurde in uint geändert.
HOME flash.ui.Keyboard.HOME Wird in ActionScript 3.0 als eine
Konstante deklariert.Der Datentyp
wurde in uint geändert.
INSERT flash.ui.Keyboard.INSERT Wird in ActionScript 3.0 als eine
Konstante deklariert.Der Datentyp
wurde in uint geändert.
LEFT flash.ui.Keyboard.LEFT Wird in ActionScript 3.0 als eine
Konstante deklariert.Der Datentyp
wurde in uint geändert.
_listeners flash.events.EventDispatcher.
willTrigger()
Kein direktes Äquivalent.Die
willTrigger()-Methode meldet
Ihnen zwar,ob Listener registriert
sind,jedoch nicht wie viele.
PGDN flash.ui.Keyboard.PAGE_DOWN Der Name wurde in ActionScript
3.0 in PAGE_DOWN geändert.Das
Objekt wird als eine Konstante
deklariert und der Datentyp wurde
in uint geändert.
B A S I S W I S S E N 91
ActionScript 2.0 ActionScript 3.0 Kommentare
PGUP flash.ui.Keyboard.PAGE_UP Der Name wurde in ActionScript
3.0 in PAGE_UP geändert.Das
Objekt wird als eine Konstante
deklariert und der Datentyp wurde
in uint geändert.
RIGHT flash.ui.Keyboard.RIGHT Wird in ActionScript 3.0 als eine
Konstante deklariert.Der Datentyp
wurde in uint geändert.
SHIFT flash.ui.Keyboard.SHIFT Wird in ActionScript 3.0 als eine
Konstante deklariert.Der Datentyp
wurde in uint geändert.
SPACE flash.ui.Keyboard.SPACE Wird in ActionScript 3.0 als eine
Konstante deklariert.Der Datentyp
wurde in uint geändert.
TAB flash.ui.Keyboard.TAB Wird in ActionScript 3.0 als eine
Konstante deklariert.Der Datentyp
wurde in uint geändert.
UP flash.ui.Keyboard.UP Wird in ActionScript 3.0 als eine
Konstante deklariert.Der Datentyp
wurde in uint geändert.
addListener() flash.events.EventDispatcher.
addEventListener()
In ActionScript 3.0 ist eine klas-
senspezifische addListener()-
Methode nicht mehr erforderlich,
da alle Anzeigeobjekte die add-
EventListener()-Methode von
der EventDispatcher-Klasse
übernehmen.
getAscii() flash.events.KeyboardEvent.
charCode
getCode() flash.events.KeyboardEvent.
keyCode
isAccessible() flash.ui.Keyboard.isAccessib-
le()
isDown() Entfernt Aus Sicherheitsgründen entfernt
isToggled() Entfernt Aus Sicherheitsgründen entfernt
removeListener() flash.events.EventDispatcher.
removeEventListener()
In ActionScript 3.0 ist eine klassen-
spezifische removeListener()-
Methode nicht mehr erforderlich,
daalleAnzeigeobjektedieremove-
EventListener()-Methode von
der EventDispatcher-Klasse
übernehmen.
onKeyDown flash.display.
InteractiveObject dispatches
event: keyDown
In ActionScript 3.0 löst die
InteractiveObject-Klasse das
KeyboardEvent-Objekt keyDown
aus,anstatt die onKeyDown-
Ereignisprozedur aufzurufen.
onKeyUp flash.display.
InteractiveObject dispatches
event: keyUp
In ActionScript 3.0 löst die
InteractiveObject-Klasse
das KeyboardEvent-Objekt
keyUp aus,anstatt die onKeyUp-
Ereignisprozedur aufzurufen.
K A P I T E L 392
ActionScript 2.0 ActionScript 3.0 Kommentare
LoadVars-Klasse flash.net.URLLoader Die LoadVars-Klassenfunktionen
wurden durch die Klassen
URLLoader,URLRequest,
URLStream,und URLVariables
ersetzt.
contentType flash.net.URLRequest.conten-
tType
loaded Entfernt Es gibt keine entsprechende.
LoadVars flash.net.URLLoader.
URLLoader()
addRequestHeader() flash.net.URLRequestHeader
decode() flash.net.URLVariables.de-
code()
getBytesLoaded() flash.net.URLLoader.bytesLoa-
ded
Die Klasse wurde in URLLoader
geändert,von einem Funktionen-
zu einem Eigenschaften-Accessor
geändert und der Name wurde
von getBytesLoaded zu by-
tesLoaded geändert.
getBytesTotal() flash.net.URLLoader.bytesTotal Die Klasse wurde in URLLoader
geändert,von einem Funktionen-
zu einem Eigenschaften-Accessor
geändert und der Name wurde
von getBytesTotal zu bytes-
Total geändert.
load() flash.net.URLLoader.load()
onData() flash.net.URLLoader dispatches
event: complete
Siehe URLLoader-Klasse.Nach
Abschluss des Download-
Vorgangs,aber noch vor dem
Parsen der Daten wird ein comple-
te-Ereignis ausgelöst.
onHTTPStatus() flash.net.URLLoader dispatches
event: httpStatus
In ActionScript 3.0 löst die
URLLoader-Klasse das HTTP-
StatusEvent-Objekt httpStatus
aus,anstatt die onHTTPStatus-
Ereignisprozedur aufzurufen.
onLoad() flash.net.URLLoader dispatches
event: complete
Siehe URLLoader-Klasse.Nach
Abschluss des Download-
Vorgangs wird ein complete-
Ereignis ausgelöst.
send() flash.net.sendToURL()
sendAndLoad() flash.net.sendToURL() Die sendToURL()-Methode sen-
det eine URL-Anforderung an den
Server,ignoriert aber die Antwort.
Zum Empfangen der Antwort
verwenden Sie flash.net.send-
ToURL().
toString() Entfernt Diese Methode ist in ActionScript
3.0 nicht mehr erforderlich.
LocalConnection-Klasse flash.net.LocalConnection Diese Klasse wurde in das flash.
net-Paket verschoben.
LocalConnection flash.net.LocalConnection.
LocalConnection()
B A S I S W I S S E N 93
ActionScript 2.0 ActionScript 3.0 Kommentare
allowDomain() flash.net.LocalConnection.
allowDomain()
Wurde in ActionScript 3.0 zu einer
regulären Methode geändert und
ist jetzt keine Ereignisprozedur
mehr.Der Parameter wurde ge-
ändert und verwendet jetzt das
Format ...(rest).Der Rückgabewert
wurde in void geändert.
allowInsecureDomain() flash.net.LocalConnection.
allowInsecureDomain()
Wurde in ActionScript 3.0 zu einer
regulären Methode geändert und
ist jetzt keine Ereignisprozedur
mehr.Der Parameter wurde ge-
ändert und verwendet jetzt das
Format ...(rest).Der Rückgabewert
wurde in void geändert.
close() flash.net.LocalConnection.
close()
connect() flash.net.LocalConnection.
connect()
domain() flash.net.LocalConnection.
domain
Zu einem Eigenschaften-Accessor
geändert
onStatus() flash.net.LocalConnection dis-
patches event: status
Im neuen Ereignismodell wurden
die Rückruffunktionen durch
Ereignisobjekte ersetzt.
send() flash.net.LocalConnection.
send()
Der dritte Parameter wurde ge-
ändert und verwendet jetzt das
Parameterformat ...(rest).Der
Rückgabetyp wurde in void ge-
ändert.
Microphone-Klasse flash.media.Microphone Diese Klasse wurde in das flash.
media-Paket verschoben.
index flash.media.Microphone.index Der Datentyp wurde in uint ge-
ändert.
rate flash.media.Microphone.rate Der Datentyp wurde in uint ge-
ändert.
silenceTimeOut flash.media.Microphone.
silenceTimeout
Die Groß-/Kleinschreibung wur-
de in„Timeout“ geändert.Der
Datentyp wurde in int geändert.
get() flash.media.Microphone.getMi-
crophone()
Der Name wurde von get() zu
getMicrophone() geändert.Der
Datentyp des Parameters wurde in
uint geändert.
onActivity() flash.media.Microphone dispat-
ches event: activity
Diese Klasse ruft in ActionScript 3.0
nicht mehr die Ereignisprozedur
onActivity auf,sondern löst
ein Ereignis mit der Bezeichnung
activity aus.
onStatus() flash.media.Microphone dispat-
ches event: status
Diese Klasse ruft in ActionScript 3.0
nicht mehr die Ereignisprozedur
onStatus auf,sondern löst ein
Ereignis mit der Bezeichnung
status aus.
K A P I T E L 394
ActionScript 2.0 ActionScript 3.0 Kommentare
setGain() flash.media.Microphone.gain Die gain-Eigenschaft und die
setGain()-Methode wurden zu
einem get/set-Eigenschaften-
Accessor mit der Bezeichnung
gain zusammengefasst.Der
Datentyp wurde in uint geändert.
setRate() flash.media.Microphone.rate Die rate-Eigenschaft und die
setRate()-Methode wurden zu
einem get/set-Eigenschaften-
Accessor mit der Bezeichnung
rate zusammengefasst.Der
Datentyp wurde in uint geändert.
setSilenceLevel() flash.media.Microphone.set-
SilenceLevel()
Der Datentyp des timeOut-
Parameters wurde in int geändert.
Die Groß-/Kleinschreibung des
timeOut-Parameter wurde in
timeout geändert.
setUseEchoSuppressi-
on()
flash.media.Microphone.setU-
seEchoSuppression()
Mouse-Klasse flash.ui.Mouse
addListener() flash.events.EventDispatcher.
addEventListener()
Im neuen ActionScript 3.0-
Ereignismodell ist eine klassenspe-
zifische addListener()-Methode
nicht mehr erforderlich,da alle
Anzeigeobjekte die addEvent-
Listener()-Methode von der
EventDispatcher-Klasse über-
nehmen.
hide() flash.ui.Mouse.hide() Gibt jetzt void zurück.
removeListener() flash.events.EventDispatcher.
removeEventListener()
Im neuen ActionScript 3.0-
Ereignismodell ist eine klassen-
spezifische removeListener()-
Methode nicht mehr erforderlich,
da alle Anzeigeobjekte die remo-
veEventListener()-Methode
von der EventDispatcher-Klasse
übernehmen.
show() flash.ui.Mouse.show() Gibt jetzt void zurück.
onMouseDown flash.display.
InteractiveObject dispatches
event: mouseDown
Wurde im neuen Ereignismodell
durch ein mouseDown-Ereignis
ersetzt.
onMouseMove flash.display.
InteractiveObject dispatches
event: mouseMove
Wurde im neuen Ereignismodell
durch ein mouseMove-Ereignis
ersetzt.
onMouseUp flash.display.
InteractiveObject dispatches
event: mouseUp
Wurde im neuen Ereignismodell
durch ein mouseUp-Ereignis er-
setzt.
onMouseWheel flash.display.
InteractiveObject dispatches
event: mouseWheel
Wurde im neuen Ereignismodell
durch ein mouseWheel-Ereignis
ersetzt.
B A S I S W I S S E N 95
ActionScript 2.0 ActionScript 3.0 Kommentare
MovieClip-Klasse flash.display.MovieClip Viele MovieClip-Methoden
wurden in ActionScript 3.0 in
andere Klassen verschoben.Alle
Ereignisprozeduren wurden im
neuen Ereignismodell durch
Ereignisobjekte ersetzt.
_alpha flash.display.DisplayObject.
alpha
In die DisplayObject-Klasse
verschoben.Der Unterstrich am
Anfang des Namens wurde ent-
fernt.
blendMode flash.display.DisplayObject.
blendMode
cacheAsBitmap flash.display.DisplayObject.
cacheAsBitmap
_currentframe flash.display.MovieClip.cur-
rentFrame
Der Unterstrich am Anfang des
Namens wurde entfernt.
_droptarget flash.display.Sprite.dropTar-
get
In die Sprite-Klasse verschoben.
Der Unterstrich am Anfang des
Namens wurde entfernt und die
Groß-/Kleinschreibung wurde
geändert.
filters flash.display.DisplayObject.
filters
focusEnabled Entfernt In ActionScript 3.0 sind alle inter-
aktiven Objekte Fokus-aktiviert.
Diese Eigenschaft ist daher nicht
mehr erforderlich.
_focusrect flash.display.
InteractiveObject.focusRect
In die InteractiveObject-Klasse
verschoben.Der Unterstrich
am Anfang des Namens wur-
de entfernt und die Groß-/
Kleinschreibung wurde geändert.
_framesloaded flash.display.MovieClip.fra-
mesLoaded
Der Unterstrich am Anfang des
Namens wurde entfernt und die
Groß-/Kleinschreibung wurde
geändert.
_height flash.display.DisplayObject.
height
In die DisplayObject-Klasse
verschoben.Der Unterstrich am
Anfang des Namens wurde ent-
fernt.
_highquality Entfernt Siehe Stage.quality
hitArea flash.display.Sprite.hitArea In die Sprite-Klasse verschoben
_lockroot Entfernt In ActionScript 3.0 wird der Stamm
eines Anzeigeobjekts automatisch
festgelegt.Die Eigenschaft _lock-
root ist damit praktisch immer
aktiviert.Siehe flash.display.
DisplayObject.root.
menu Entfernt Siehe InteractiveObject.
contextMenu
_name flash.display.DisplayObject.
name
In die DisplayObject-Klasse
verschoben.Der Unterstrich am
Anfang des Namens wurde ent-
fernt.
K A P I T E L 396
ActionScript 2.0 ActionScript 3.0 Kommentare
opaqueBackground flash.display.DisplayObject.
opaqueBackground
_parent flash.display.DisplayObject.
parent
In die DisplayObject-Klasse
verschoben.Der Unterstrich am
Anfang des Namens wurde ent-
fernt.
_quality flash.display.Stage.quality
_rotation flash.display.DisplayObject.
rotation
In die DisplayObject-Klasse
verschoben.Der Unterstrich am
Anfang des Namens wurde ent-
fernt.
scale9Grid flash.display.DisplayObject.
scale9Grid
scrollRect flash.display.DisplayObject.
scrollRect
In den Datentyp Rectangle ge-
ändert
_soundbuftime flash.media.SoundMixer.buffer-
Time
In die SoundMixer-Klasse
verschoben,die zur globalen
Soundsteuerung verwendet wird.
Infolge der Umbenennung ist
keine Abkürzung mehr vorhanden
und der Unterstrich am Anfang
des Namens wurde entfernt.
tabChildren flash.display.
DisplayObjectContainer.
tabChildren
tabEnabled flash.display.
InteractiveObject.tabEnabled
tabIndex flash.display.
InteractiveObject.tabIndex
_target Entfernt ActionScript 3.0 identifiziert
Anzeigeobjekte direkt,daher
ist die Identifizierung eines
Anzeigeobjekts über dessen Pfad
nicht mehr notwendig.
_totalframes flash.display.MovieClip.total-
Frames
Die Groß-/Kleinschreibung wurde
geändert.Der Unterstrich am
Anfang des Namens wurde ent-
fernt.
trackAsMenu flash.display.MovieClip.
trackAsMenu
transform flash.display.DisplayObject.
transform
_url flash.display.Loader.content-
LoaderInfo
useHandCursor flash.display.Sprite.useHand-
Cursor
_visible flash.display.DisplayObject.
visible
In die DisplayObject-Klasse
verschoben.Der Unterstrich am
Anfang des Namens wurde ent-
fernt.
_width flash.display.DisplayObject.
width
In die DisplayObject-Klasse
verschoben.Der Unterstrich am
Anfang des Namens wurde ent-
fernt.
B A S I S W I S S E N 97
ActionScript 2.0 ActionScript 3.0 Kommentare
_x flash.display.DisplayObject.x In die DisplayObject-Klasse
verschoben.Der Unterstrich am
Anfang des Namens wurde ent-
fernt.
_xmouse flash.display.DisplayObject.
mouseX
In die DisplayObject-Klasse
verschoben.Der Name wurde
in mouseX geändert und der
Unterstrich am Anfang des
Namens wurde entfernt.
_xscale flash.display.DisplayObject.
scaleX
In die DisplayObject-Klasse
verschoben.Der Name wurde
in scaleX geändert und der
Unterstrich am Anfang des
Namens wurde entfernt.
_y flash.display.DisplayObject.y In die DisplayObject-Klasse
verschoben.Der Unterstrich am
Anfang des Namens wurde ent-
fernt.
_ymouse flash.display.DisplayObject.
mouseY
In die DisplayObject-Klasse
verschoben.Der Name wurde
in mouseY geändert und der
Unterstrich am Anfang des
Namens wurde entfernt.
_yscale flash.display.DisplayObject.
scaleY
In die DisplayObject-Klasse
verschoben.Der Name wurde
in scaleY geändert und der
Unterstrich am Anfang des
Namens wurde entfernt.
attachAudio() Entfernt Wenn es sich bei der Audioquelle
um ein Microphone-Objekt
handelt,verwenden Sie
NetStream.attachAudio() oder
Microphone.setLoopBack().
Handelt es sich bei der Audio-
quelle um eine FLV-Datei,
verwenden Sie Video.attach-
NetStream() und ein NetStream-
Objekt.
attachBitmap() Entfernt In ActionScript 3.0 verwenden Sie
addChild(),um untergeordnete
Anzeigeobjekte hinzuzufügen.
attachMovie() Entfernt In ActionScript 3.0 verwenden Sie
addChild(),um untergeordnete
Anzeigeobjekte hinzuzufügen.
beginBitmapFill() flash.display.Graphics.begin-
BitmapFill()
beginFill() flash.display.Graphics.begin-
Fill()
In die Graphics-Klasse verscho-
ben.Der Datentyp des ersten
Parameters wurde in uint geän-
dert.
beginGradientFill() flash.display.Graphics.begin-
GradientFill()
clear() flash.display.Graphics.clear()
K A P I T E L 398
ActionScript 2.0 ActionScript 3.0 Kommentare
createEmptyMovieClip() Entfernt In ActionScript 3.0 verwenden Sie
zum Erstellen von MovieClips den
new-Operator.
createTextField() Entfernt In ActionScript 3.0 verwenden Sie
zum Erstellen von Textfeldern den
new-Operator.
curveTo() flash.display.Graphics.curve-
To()
duplicateMovieClip() Entfernt In ActionScript 3.0 verwenden Sie
zum Erstellen einer neuen Instanz
den new-Operator.
endFill() flash.display.Graphics.end-
Fill()
getBounds() flash.display.DisplayObject.
getBounds()
getBytesLoaded() flash.net.URLLoader.bytesLoa-
ded
In die URLLoader-Klasse verscho-
ben.Der Datentyp wurde von
Number in int geändert.
getBytesTotal() flash.net.URLLoader.bytesTotal In die URLLoader-Klasse verscho-
ben.Der Datentyp wurde von
Number in int geändert.
getDepth() flash.display.
DisplayObjectContainer.get-
ChildIndex()
ActionScript 3.0 bietet direkten
Zugriff auf die Anzeigeliste,daher
wird die Tiefe auf andere Weise
bearbeitet.
getInstanceAtDepth() flash.display.
DisplayObjectContainer.get-
ChildAt()
ActionScript 3.0 bietet direkten
Zugriff auf die Anzeigeliste,daher
wird die Tiefe auf andere Weise
bearbeitet.
getNextHighestDepth() flash.display.
DisplayObjectContainer.add-
Child()
Kein direktes Äquivalent,aber die
addChild()-Methode fügt nach
allen untergeordneten Objekten
der DisplayObjectContainer-
Instanz ein weiteres untergeord-
netes Objekt hinzu.Daher ist eine
Methode,mit der die nächste
verfügbare Tiefe ermittelt wird,
nicht mehr erforderlich.
getRect() flash.display.DisplayObject.
getRect()
getSWFVersion() flash.display.LoaderInfo.swf-
Version
In die LoaderInfo-Klasse verscho-
ben.Der Datentyp wurde in uint
geändert.
getTextSnapshot() flash.display.
DisplayObjectContainer.textS-
napshot
getURL() flash.net.navigateToURL() Wurde durch die Methoden
flash.net.navigateToURL()
und flash.net.sentToURL()
ersetzt.Siehe auch URLLoader-
Klasse.
globalToLocal() flash.display.DisplayObject.
globalToLocal()
B A S I S W I S S E N 99
ActionScript 2.0 ActionScript 3.0 Kommentare
gotoAndStop() flash.display.MovieClip.goto-
AndStop()
hitTest() flash.display.DisplayObject.
hitTestObject()
lineGradientStyle() flash.display.Graphics.line-
GradientStyle()
lineStyle() flash.display.Graphics.li-
neStyle()
lineTo() flash.display.Graphics.line-
To()
loadMovie() flash.display.Loader.load() Siehe Loader-Klasse
loadVariables() flash.net.URLLoader Entfernt; siehe URLLoader-Klasse
localToGlobal() flash.display.DisplayObject.
localToGlobal()
moveTo() flash.display.Graphics.move-
To()
nextFrame() flash.display.MovieClip.next-
Frame()
onData() flash.display.LoaderInfo dis-
patches event: complete
Wurde im neuen Ereignismodell
durch ein complete-Ereignis
ersetzt,das nach Abschluss des
Download-Vorgangs,aber noch
vor dem Parsen der Daten ausge-
löst wird.
onDragOut() flash.display.
InteractiveObject dispatches
event: mouseOut
Wurde im neuen Ereignismodell
durch ein mouseOut-Ereignis
ersetzt.
onDragOver() flash.display.
InteractiveObject dispatches
event: mouseOver
Wurde im neuen Ereignismodell
durch ein mouseOver-Ereignis
ersetzt.
onEnterFrame() flash.display.DisplayObject
dispatches event: enterFrame
Wurde im neuen Ereignismodell
durch ein enterFrame-Ereignis
ersetzt.
onKeyDown() flash.display.
InteractiveObject dispatches
event: keyDown
Wurde im neuen Ereignismodell
durch ein keyDown-Ereignis er-
setzt.
onKeyUp() flash.display.
InteractiveObject dispatches
event: keyUp
Wurde im neuen Ereignismodell
durch ein keyUp-Ereignis ersetzt.
onKillFocus() flash.display.
InteractiveObject dispatches
event: focusOut
Wurde im neuen Ereignismodell
durch ein focusOut-Ereignis
ersetzt.
onLoad() flash.display.LoaderInfo dis-
patches event: complete
Siehe auch URLLoader-Klasse.
Nach Abschluss des Download-
Vorgangs wird ein complete-
Ereignis ausgelöst.
onMouseDown() flash.display.
InteractiveObject dispatches
event: mouseDown
Wurde im neuen Ereignismodell
durch ein mouseDown-Ereignis
ersetzt.
onMouseMove() flash.display.
InteractiveObject dispatches
event: mouseMove
Wurde im neuen Ereignismodell
durch ein mouseMove-Ereignis
ersetzt.
K A P I T E L 3100
ActionScript 2.0 ActionScript 3.0 Kommentare
onMouseUp() flash.display.
InteractiveObject dispatches
event: mouseUp
Wurde im neuen Ereignismodell
durch ein mouseUp-Ereignis er-
setzt.
onPress() flash.display.
InteractiveObject dispatches
event: mouseDown
Wurde im neuen Ereignismodell
durch ein mouseDown-Ereignis
ersetzt.
onRelease() flash.display.
InteractiveObject dispatches
event: mouseUp
Wurde im neuen Ereignismodell
durch ein mouseUp-Ereignis er-
setzt.
onReleaseOutside() flash.display.
InteractiveObject dispatches
event: mouseUp
Wurde im neuen Ereignismodell
durch ein mouseUp-Ereignis er-
setzt.
onRollOut() flash.display.
InteractiveObject dispatches
event: mouseOut
Wurde im neuen Ereignismodell
durch ein mouseOut-Ereignis
ersetzt.
onRollOver() flash.display.
InteractiveObject dispatches
event: mouseOver
Wurde im neuen Ereignismodell
durch ein mouseOver-Ereignis
ersetzt.
onSetFocus() flash.display.
InteractiveObject dispatches
event: focusIn
Wurde im neuen Ereignismodell
durch ein focusIn-Ereignis er-
setzt.
onUnload() flash.display.LoaderInfo dis-
patches event: unload
Wurde im neuen Ereignismodell
durch ein unload-Ereignis ersetzt.
play() flash.display.MovieClip.play()
prevFrame() flash.display.MovieClip.prev-
Frame()
removeMovieClip() flash.display.
DisplayObjectContainer.remove-
Child()
Entfernt.Rufen Sie die remove-
Child()-Methode des übergeord-
neten Anzeigeobjekt-Containers
auf,der den MovieClip enthält.
setMask() flash.display.DisplayObject.
mask
startDrag() flash.display.Sprite.start-
Drag()
stop() flash.display.MovieClip.stop()
stopDrag() flash.display.Sprite.
stopDrag()
swapDepths() Entfernt In ActionScript 3.0 erreichen
Sie eine ähnliche Funktionalität
mithilfe der Methoden der
DisplayObjectContainer-Klasse,
z.B.addChildAt(),setChild-
Index(),swapChildren() und
swapChildrenAt().
unloadMovie() flash.display.Loader.unload()
MovieClipLoader-Klasse flash.display.Loader Wurde durch die flash.dis-
play.Loader-Klasse ersetzt.
MovieClipLoader flash.display.Loader.Loader()
B A S I S W I S S E N 101
ActionScript 2.0 ActionScript 3.0 Kommentare
addListener() flash.events.EventDispatcher.
addEventListener()
Im neuen Ereignismodell ist
eine klassenspezifische addLis-
tener()-Methode nicht mehr
erforderlich,da die Klasse die
addEventListener()-Methode
von der EventDispatcher-Klasse
übernimmt.
getProgress() flash.display.LoaderInfo dis-
patches event: progress
Wurde im neuen Ereignismodell
durch ein progress-Ereignis
ersetzt.Ereignisobjekte des Typs
progress enthalten Eigenschaften
mit den Bezeichnungen by-
tesLoaded und bytesTotal.
loadClip() flash.display.Loader.load() Wurde durch die load()-Methode
der flash.display.Loader-
Klasse ersetzt.
removeListener() flash.events.EventDispatcher.
removeEventListener()
Im neuen Ereignismodell ist eine
klassenspezifische removeLis-
tener()-Methode nicht mehr
erforderlich,da die Klasse die re-
moveEventListener()-Methode
von der EventDispatcher-Klasse
übernimmt.
unloadClip() flash.display.Loader.unload() Wurde durch die unload()-
Methode der flash.display.
Loader-Klasse ersetzt.
onLoadComplete flash.display.LoaderInfo dis-
patches event: complete
Wurde im neuen Ereignismodell
durch ein complete-Ereignis
ersetzt.
onLoadError flash.display.LoaderInfo dis-
patches event: ioError
Wurde im neuen Ereignismodell
durch ein ioError-Ereignis er-
setzt.
onLoadInit flash.display.LoaderInfo dis-
patches event: init
Wurde im neuen Ereignismodell
durch ein init-Ereignis ersetzt.
onLoadProgress flash.display.LoaderInfo dis-
patches event: progress
Wurde im neuen Ereignismodell
durch ein progress-Ereignis
ersetzt.
onLoadStart flash.display.LoaderInfo dis-
patches event: open
Wurde im neuen Ereignismodell
durch ein open-Ereignis ersetzt.
NetConnection-Klasse flash.net.NetConnection Diese Klasse wurde in das flash.
net-Paket verschoben.
NetConnection flash.net.NetConnection.
NetConnection()
connect() flash.net.NetConnection.con-
nect()
In der ActionScript 3.0-Version
wurde ein ...(rest)-Parameter hin-
zugefügt.
NetStream-Klasse flash.net.NetStream Diese Klasse wurde in das flash.
net-Paket verschoben.
bytesLoaded flash.net.NetStream.bytesLoa-
ded
Der Datentyp wurde in uint
geändert.
bytesTotal flash.net.NetStream.bytesTotal Der Datentyp wurde in uint
geändert.
K A P I T E L 3102
ActionScript 2.0 ActionScript 3.0 Kommentare
currentFps flash.net.NetStream.currentFPS In ActionScript 3.0 steht FPS in
Großbuchstaben.
onStatus() flash.net.NetStream dispatches
event: netStatus
Wurde im neuen Ereignismodell
durch ein netStatus-Ereignis
ersetzt.
pause() flash.net.NetStream.pause() In ActionScript 3.0 nimmt die pau-
se-Methode keinen Parameter auf.
Es stehen zwei neue Methoden zur
Verfügung,mit denen die gleiche
Funktionalität erreicht wird:resu-
me() und togglePause().
play() flash.net.NetStream.play() Die Parameter name,start,len
und reset sind nicht mehr gültig,
stattdessen wird ...arguments
verwendet.
setBufferTime() flash.net.NetStream.bufferTime Wurde in ActionScript 3.0 zu einer
Accessor-Eigenschaft mit Lese-
und Schreibzugriff geändert.
Number-Klasse Number
Number Number.Number() In ActionScript 3.0 haben der
Number()-Konstruktor und die
globale Funktion Number() die
gleichen Auswirkungen.Darüber
hinaus gibt es keinen Unterschied
zwischen einem Number-Objekt
und einem literalen Zahlenwert.
Object-Klasse Object
__proto__ Entfernt In ActionScript 3.0 ist eine direkte
Bearbeitung der Prototypkette
nicht zulässig.Zum Erstellen
einer Unterklasse verwenden
Sie die extends-Anweisung in
der Unterklassendeklaration.
Um weitere Informationen über
die Vererbungsstruktur und den
Datentyp eines Objekts zu er-
halten,verwenden Sie die neue
Reflection-API flash.utils.
describeType().
__resolve flash.utils.Proxy Verwenden Sie die neue Proxy-
Klasse,um eine ähnliche Funktion
umzusetzen.
addProperty() Entfernt In ActionScript 3.0 können
Accessor-Eigenschaften mithilfe
der Schlüsselwörter get und set
direkt erstellt werden.
B A S I S W I S S E N 103
ActionScript 2.0 ActionScript 3.0 Kommentare
registerClass() Entfernt In ActionScript 3.0 sind alle
Klassen standardmäßig registriert.
Wenn Sie ein Objekt mithilfe
von AMF verschlüsseln,wird
die Objektklasse während des
Verschlüsselungsvorgangs nicht
beibehalten,es sei denn,Sie
verwenden die Funktion flash.
utils.registerClassAlias().
unwatch() Entfernt ActionScript 3.0 hat keine
Watchpoints,daher ist die
Methode unwatch() überholt.
watch() Entfernt Verwenden Sie die Accessor-
Eigenschaften (get/set-
Funktionen) oder die flash.
utils.Proxy-Klasse,um eine ähn-
liche Funktionalität zu erreichen.
PrintJob-Klasse flash.printing.PrintJob
orientation flash.printing.PrintJob.orien-
tation
Diese Eigenschaft hat jetzt den
Wert der PrintJobOrientation-
Klasse.
pageHeight flash.printing.PrintJob.page-
Height
Der Datentyp wurde in int
geändert.
pageWidth flash.printing.PrintJob.page-
Width
Der Datentyp wurde in int
geändert.
paperHeight flash.printing.PrintJob.paper-
Height
Der Datentyp wurde in int
geändert.
paperWidth flash.printing.PrintJob.paper-
Width
Der Datentyp wurde in int
geändert.
PrintJob flash.printing.PrintJob.
PrintJob()
addPage() flash.printing.PrintJob.add-
Page()
In ActionScript 3.0 wurden die
Datentypen der Parameter
geändert:Der erste Parameter
target weist jetzt den Datentyp
Sprite auf; der zweite Parameter
printArea den Datentyp
Rectangle; der dritte Parameter
options hat den neuen Datentyp
PrintJobOptions und der vierte
Parameter frameNum hat den
Datentyp int.
send() flash.printing.PrintJob.send()
start() flash.printing.PrintJob.
start()
Rectangle-Klasse
containsRectangle() flash.geom.Rectangle.contains-
Rect()
Aus Konsistenzgründen um-
benannt
security-Klasse flash.system.Security Diese Klasse wurde in das flash.
system-Paket verschoben.
Selection-Klasse Entfernt Die Methoden dieser Klasse wur-
den in andere Klassen verschoben.
K A P I T E L 3104
ActionScript 2.0 ActionScript 3.0 Kommentare
addListener() flash.events.EventDispatcher.
addEventListener()
Im neuen Ereignismodell ist eine
klassenspezifische addListe-
ner()-Methode nicht mehr erfor-
derlich,da alle Anzeigeobjekte die
addEventListener()-Methode
von der EventDispatcher-Klasse
übernehmen.
getBeginIndex() flash.text.TextField.selec-
tionBeginIndex
Wurde von einer Methode in eine
Accessor-Eigenschaft geändert.
Der Name wurde in selection-
BeginIndex geändert.
getCaretIndex() flash.text.TextField.caret-
Index
Wurde von einer Methode in eine
Accessor-Eigenschaft geändert.
Der Name wurde in caretIndex
geändert.
getEndIndex() flash.text.TextField.selectio-
nEndIndex
Wurde von einer Methode in eine
Accessor-Eigenschaft geändert.
Der Name wurde in selection-
EndIndex geändert.
getFocus() flash.display.Stage.focus Wurde von einer Methode in einen
Eigenschaften-Accessor geändert.
Der Name wurde in focus ge-
ändert.In ActionScript 2.0 hatte
der Rückgabewert den Datentyp
String,in ActionScript 3.0 hin-
gegen weist die Eigenschaft den
Datentyp InteractiveObject
auf.
removeListener() flash.events.EventDispatcher.
removeEventListener()
Im neuen Ereignismodell ist eine
klassenspezifische removeListe-
ner()-Methode nicht mehr erfor-
derlich,da Anzeigeobjekte die re-
moveEventListener()-Methode
von der EventDispatcher-Klasse
übernehmen.
setFocus() flash.display.Stage.focus Wurde von einer Methode zu einer
Accessor-Eigenschaft geändert.
Der Name wurde in focus ge-
ändert.In ActionScript 2.0 hatte
der Rückgabewert den Datentyp
String,in ActionScript 3.0 hin-
gegen weist die Eigenschaft den
Datentyp InteractiveObject
auf.
setSelection() flash.text.TextField.setSelec-
tion()
Der Datentyp beider Parameter
wurde von Number in uint geän-
dert.
onSetFocus flash.display.
InteractiveObject dispatches
event: focusIn
Wurde im neuen Ereignismodell
durch ein focusIn-Ereignis er-
setzt.
SharedObject-Klasse flash.net.SharedObject Diese Klasse wurde in das flash.
net-Paket verschoben.
B A S I S W I S S E N 105
ActionScript 2.0 ActionScript 3.0 Kommentare
flush() flash.net.SharedObject.flush() Diese Methode gibt jetzt kei-
nen booleschen Wert mehr
zurück.Wenn die Ausgabe fehl-
schlägt,gibt Flash Player einen
Ausnahmefehler aus.Wenn die
Ausgabe erfolgreich ist oder eine
Benutzerreaktion aussteht,gibt
der Flash Player die Zeichenfolge
„flushed“ oder„pending“ zu-
rück.Darüber hinaus wurde der
Datentyp des minDiskSpace-
Parameters in int geändert.
getSize() flash.net.SharedObject.size Wurde in eine Accessor-
Eigenschaft geändert.Der
Datentyp wurde in uint geändert.
onStatus() flash.net.SharedObject dispat-
ches event: netStatus
Wurde im neuen Ereignismodell
durch ein netStatus-Ereignis
ersetzt.
Sound-Klasse flash.media.Sound Diese Klasse wurde in das flash.
media-Paket verschoben.
checkPolicyFile flash.media.SoundChannel.
stop()
Wurde durch die flash.media.
SoundChannel.stop()-Methode
ersetzt.
duration flash.media.Sound.length
id3 flash.media.Sound.id3 Der Datentyp wurde von Object
in ID3Info geändert.ID3Info
ist eine neue Klasse,die die ID3-
Eigenschaften enthält.Darüber
hinaus wurde die Schreibweise der
songname-Eigenschaft in song-
Name geändert.
position flash.media.SoundChannel.po-
sition
In die SoundChannel-Klasse ver-
schoben
attachSound() Entfernt Erstellen Sie eine Instanz eines
Sound-Objektes.
getBytesLoaded() flash.media.Sound.bytesLoaded Wurde in eine Accessor-
Eigenschaft geändert.Der
Datentyp wurde in uint geändert.
getBytesTotal() flash.media.Sound.bytesTotal Wurde in einen Eigenschaften-
Accessor geändert.Der Datentyp
wurde in uint geändert.
getPan() flash.media.SoundTransform.pan Wurde in eine Accessor-
Eigenschaft geändert und in die
SoundTransform-Klasse verscho-
ben.
getTransform() flash.media.SoundMixer.sound-
Transform
Wurde in eine Accessor-
Eigenschaft geändert.
Der Datentyp wurde in
SoundTransform geändert.
getVolume() flash.media.SoundTransform.
volume
Richten Sie die flashmedia.
SoundTransform.volu-
me-Eigenschaft ein,um die
Soundlautstärke zu steuern.
K A P I T E L 3106
ActionScript 2.0 ActionScript 3.0 Kommentare
loadSound() flash.media.Sound.load() Der erste Parameter wurde von
einem einfachen URL-String in
ein URLRequest-Objekt geändert.
Der zweite Parameter wurde von
einem booleschen Wert,mit dem
angegeben wird,ob der Sound so
bald wie möglich wiedergegeben
wird,in ein SoundLoaderContext-
Objekt geändert.
onID3() flash.media.Sound dispatches
event: id3
Wurde im neuen Ereignismodell
durch ein id3-Ereignis ersetzt.
onLoad() flash.media.Sound dispatches
event: complete
Wurde im neuen Ereignismodell
durch ein complete-Ereignis
ersetzt.
onSoundComplete() flash.media.SoundChannel dis-
patches event: soundComplete
Wurde im neuen Ereignismodell
durch ein soundComplete-Ereignis
ersetzt.
setPan() flash.media.SoundTransform.pan Wurde in eine Accessor-
Eigenschaft geändert und in die
SoundTransform-Klasse verscho-
ben.
setTransform() flash.media.SoundMixer.sound-
Transform
Wurde in eine Accessor-
Eigenschaft geändert.
Der Datentyp wurde in
SoundTransform geändert.
setVolume() flash.media.SoundChannel Entfernt.Verwenden Sie flash.
media.SoundChannel.left-
Peak und flash.media.
SoundChannel.rightPeak zur
Überwachung der Amplitude
eines Soundkanals.
start() flash.media.Sound.play() Der Datentyp des loops-
Parameters wurde von Number
in int geändert.Ein dritter
Parameter,sndTransform,wurde
hinzugefügt,um die anfängliche
Soundtransformation festzulegen,
die vom Soundkanal verwendet
werden soll.
stop() flash.media.SoundChannel.
stop()
Stage-Klasse flash.display.Stage Diese Klasse wurde in das flash.
display-Paket verschoben.
align flash.display.Stage.align
height flash.display.Stage.stage-
Height
Der Name wurde von height
in stageHeight geändert,so-
dass jetzt kein Konflikt mehr
mit der flash.display.
DisplayObject.height-
Eigenschaft auftreten kann.
scaleMode flash.display.Stage.scaleMode
showMenu flash.display.Stage.showDe-
faultContextMenu
Der Name wurde geändert,um das
angezeigte Menü besser widerzu-
spiegeln.
B A S I S W I S S E N 107
ActionScript 2.0 ActionScript 3.0 Kommentare
width flash.display.Stage.stageWidth Der Name wurde von width in
stageWidth geändert,sodass jetzt
kein Konflikt mehr mit der flash.
display.DisplayObject.width-
Eigenschaft auftreten kann.
addListener() flash.events.EventDispatcher.
addEventListener()
Im neuen Ereignismodell ist
eine klassenspezifische addLis-
tener()-Methode nicht mehr
erforderlich,da die Klasse die
addEventListener()-Methode
von der EventDispatcher-Klasse
übernimmt.
removeListener() flash.events.EventDispatcher.
removeEventListener()
Im neuen Ereignismodell ist eine
klassenspezifische removeLis-
tener()-Methode nicht mehr
erforderlich,da die Klasse die re-
moveEventListener()-Methode
von der EventDispatcher-Klasse
übernimmt.
onResize flash.display.Stage dispatches
event: resize
Wurde im neuen Ereignismodell
durch ein resize-Ereignis ersetzt.
String-Klasse String Unterstützung für reguläre
Ausdrücke mit drei neuen
Methoden hinzugefügt:match(),
replace() und search().
concat() String.concat() Der Parameter wurde geändert
und verwendet jetzt das Format
...(rest).
StyleSheet-Klasse flash.text.StyleSheet Diese Klasse wurde in das flash.
text-Paket verschoben.Die
Mitglieder load() und onLoad()
wurden entfernt und einige pri-
vate Funktionen und Variablen
wurden hinzugefügt.
StyleSheet flash.text.StyleSheet.
StyleSheet()
clear() flash.text.StyleSheet.clear()
getStyle() flash.text.StyleSheet.get-
Style()
Der Name des Parameters wurde
in n geändert.
getStyleNames() flash.text.StyleSheet.style-
Names
Wurde in eine Accessor-
Eigenschaft geändert.
load() flash.net.URLLoader.load() Verwenden Sie die neuen Klassen
URLLoader und URLRequest zum
Laden von URLs.
onLoad() flash.net.URLLoader dispatches
event: complete
Wurde im neuen Ereignismodell
durch ein complete-Ereignis
ersetzt.
parseCSS() flash.text.StyleSheet.par-
seCSS()
Gibt in ActionScript 3.0 void
anstelle eines booleschen Werts
zurück.
setStyle() flash.text.StyleSheet.set-
Style()
Der Name des Parameters wurde
in n und der Stil in s geändert.
transform() flash.text.StyleSheet.trans-
form()
K A P I T E L 3108
ActionScript 2.0 ActionScript 3.0 Kommentare
System-Klasse flash.system.System
exactSettings flash.system.Security.exact-
Settings
In die flash.System.Security-
Klasse verschoben
useCodepage flash.system.System.useCode-
Page
In ActionScript 3.0 ist der
Buchstabe„P“ in useCodePage ein
Großbuchstabe.
onStatus() Entfernt Diese Ereignisprozedur ist im
ActionScript 3.0-Ereignismodell
überholt.
setClipboard() flash.system.System.setClip-
board()
showSettings() flash.system.Security.showSet-
tings()
TextField-Klasse flash.text.TextField Diese Klasse wurde in das flash.
text-Paket verschoben.
_alpha flash.display.DisplayObject.
alpha
Diese Eigenschaft wird jetzt
von der DisplayObject-Klasse
übernommen.Der Unterstrich am
Anfang wurde entfernt.
antiAliasType flash.text.TextField.antiAli-
asType
autoSize flash.text.TextField.autoSize
background flash.text.TextField.back-
ground
backgroundColor flash.text.TextField.back-
groundColor
border flash.text.TextField.border
borderColor flash.text.TextField.border-
Color
In ActionScript 3.0 wird ein uint-
Wert anstelle eines Number-Werts
zurückgegeben.
bottomScroll flash.text.TextField.bottom-
ScrollV
In ActionScript 3.0 wird ein uint-
Wert anstelle eines Number-Werts
zurückgegeben.
condenseWhite flash.text.TextField.conden-
seWhite
embedFonts flash.text.TextField.embed-
Fonts
filters flash.display.DisplayObject.
filters
gridFitType flash.text.TextField.gridFit-
Type
_height flash.display.DisplayObject.
height
Diese Eigenschaft wird jetzt
von der DisplayObject-Klasse
übernommen.Der Unterstrich am
Anfang wurde entfernt.
_highquality flash.display.Stage.quality Entfernt.
hscroll flash.text.TextField.scrollH Der Datentyp wurde von Number
zu uint geändert.Der Name
wurde von hscroll zu scrollH
geändert.
B A S I S W I S S E N 109
ActionScript 2.0 ActionScript 3.0 Kommentare
html flash.text.TextField.htmlText Entfernt.In ActionScript 3.0
werden alle Textfelder als HTML-
Textfelder behandelt.Verwenden
Sie die TextField.htmlText-
Eigenschaft,um HTML-Text einzu-
richten.
htmlText flash.text.TextField.htmlText
length flash.text.TextField.length Der Datentyp wurde von Number
in uint geändert.
maxChars flash.text.TextField.maxChars Der Datentyp wurde von Number
in uint geändert.
maxhscroll flash.text.TextField.maxSc-
rollH
Der Datentyp wurde von Number
in uint geändert.
maxscroll flash.text.TextField.maxSc-
rollV
Der Datentyp wurde von
Number in uint geändert.Im
neuen Namen ist das S ein
Großbuchstabe und der Buchstabe
V wurde hinzugefügt,um das verti-
kale Scrollen zu verdeutlichen.
menu flash.display.
InteractiveObject.contextMenu
Diese Eigenschaft wird jetzt von
der InteractiveObject-Klasse
übernommen.
mouseWheelEnabled flash.text.TextField.mouse-
WheelEnabled
multiline flash.text.TextField.multiline
_name flash.display.DisplayObject.
name
Diese Eigenschaft wird jetzt
von der DisplayObject-Klasse
übernommen.Der Unterstrich am
Anfang wurde entfernt.
_parent flash.display.DisplayObject.
parent
Diese Eigenschaft wird jetzt
von der DisplayObject-Klasse
übernommen.Der Unterstrich
am Anfang wurde entfernt.Der
Datentyp wurde von MovieClip
in DisplayObjectContainer
geändert.
password flash.text.TextField.displayA-
sPassword
Diese Eigenschaft wurde aus
Konsistenzgründen umbenannt.
_quality flash.display.Stage.quality In die Stage-Klasse verschoben
restrict flash.text.TextField.restrict
_rotation flash.display.DisplayObject.
rotation
Diese Eigenschaft wird jetzt
von der DisplayObject-Klasse
übernommen.Der Unterstrich am
Anfang wurde entfernt.
scroll flash.text.TextField.scrollV Der Datentyp wurde von Number
in uint geändert und der Name
von scroll in scrollV.
selectable flash.text.TextField.selec-
table
sharpness flash.text.TextField.sharpness
K A P I T E L 3110
ActionScript 2.0 ActionScript 3.0 Kommentare
_soundbuftime flash.media.SoundMixer.buffer-
Time
Eigenschaften und Methoden für
die globale Soundsteuerung in
einer SWF-Datei befinden sich jetzt
in der flash.media.SoundMixer-
Klasse.
styleSheet flash.text.TextField.styleS-
heet
tabEnabled flash.display.
InteractiveObject.tabEnabled
Diese Eigenschaft wird jetzt von
der InteractiveObject-Klasse
übernommen.
tabIndex flash.display.
InteractiveObject.tabIndex
Diese Eigenschaft wird jetzt von
der InteractiveObject-Klasse
übernommen.
_target Entfernt ActionScript 3.0 identifiziert
Anzeigeobjekte direkt,daher ist
die Identifizierung des Pfads nicht
mehr notwendig.
text flash.text.TextField.text
textColor flash.text.TextField.textColor Der Datentyp wurde von Number
in uint geändert.
textHeight flash.text.TextField.text-
Height
textWidth flash.text.TextField.textWidth
thickness flash.text.TextField.thickness
type flash.text.TextField.type
_url flash.display.LoaderInfo.url
variable Entfernt Diese Variable ist in ActionScript
3.0 nicht mehr erforderlich.
_visible flash.display.DisplayObject.
visible
Diese Eigenschaft wird jetzt
von der DisplayObject-Klasse
übernommen.Der Unterstrich am
Anfang wurde entfernt.
_width flash.display.DisplayObject.
width
Diese Eigenschaft wird jetzt
von der DisplayObject-Klasse
übernommen.Der Unterstrich am
Anfang wurde entfernt.
wordWrap flash.text.TextField.wordWrap
_x flash.display.DisplayObject.x Diese Eigenschaft wird jetzt
von der DisplayObject-Klasse
übernommen.Der Unterstrich am
Anfang wurde entfernt.
_xmouse flash.display.DisplayObject.
mouseX
Diese Eigenschaft wird jetzt
von der DisplayObject-Klasse
übernommen.Der Unterstrich am
Anfang wurde entfernt.
_xscale flash.display.DisplayObject.
scaleX
Diese Eigenschaft wird jetzt
von der DisplayObject-Klasse
übernommen.Der Unterstrich am
Anfang wurde entfernt.
_y flash.display.DisplayObject.y Diese Eigenschaft wird jetzt
von der DisplayObject-Klasse
übernommen.Der Unterstrich am
Anfang wurde entfernt.
B A S I S W I S S E N 111
ActionScript 2.0 ActionScript 3.0 Kommentare
_ymouse flash.display.DisplayObject.
mouseY
Diese Eigenschaft wird jetzt
von der DisplayObject-Klasse
übernommen.Der Unterstrich am
Anfang wurde entfernt.
_yscale flash.display.DisplayObject.
scaleY
Diese Eigenschaft wird jetzt
von der DisplayObject-Klasse
übernommen.Der Unterstrich am
Anfang wurde entfernt.
addListener() flash.events.EventDispatcher.
addEventListener()
Im neuen Ereignismodell ist
eine klassenspezifische addLis-
tener()-Methode nicht mehr
erforderlich,da die Klasse die
addEventListener()-Methode
von der EventDispatcher-Klasse
übernimmt.
getDepth() flash.display.
DisplayObjectContainer
Entfernt.Verwenden Sie
jetzt die Methoden der
DisplayObjectContainer-Klasse,
um die Textfeldtiefe festzustellen.
getFontList() flash.text.Font.enumerate-
Fonts()
Entfernt.Verwenden Sie Font.
enumerateFonts() und setzen
Sie den Parameter enumerate-
DeviceFonts auf true.
getNewTextFormat() flash.text.TextField.default-
TextFormat
Der Name wurde von getNew-
TextFormat in defaultTextFor-
mat geändert.Von einer Methode
in eine Accessor-Eigenschaft
geändert.
getTextFormat() flash.text.TextField.getText-
Format()
Der Datentyp beider Parameter
wurde von Number in uint geän-
dert.
onChanged() flash.text.TextField dispat-
ches event: change
Wurde im neuen Ereignismodell
durch ein change-Ereignis ersetzt.
onKillFocus() flash.display.
InteractiveObject dispatches
event: focusOut
Wurde im neuen Ereignismodell
durch ein focusOut-Ereignis
ersetzt.
onScroller() flash.text.TextField dispat-
ches event: scroll
Wurde im neuen Ereignismodell
durch ein scroll-Ereignis ersetzt.
onSetFocus() flash.display.
InteractiveObject dispatches
event: focusIn
Wurde im neuen Ereignismodell
durch ein focusIn-Ereignis er-
setzt.
removeListener() flash.events.EventDispatcher.
removeEventListener()
Im neuen Ereignismodell ist eine
klassenspezifische removeLis-
tener()-Methode nicht mehr
erforderlich,da die Klasse die re-
moveEventListener()-Methode
von der EventDispatcher-Klasse
übernimmt.
removeTextField() flash.display.
DisplayObjectContainer.remove-
Child()
Entfernt.Rufen Sie die remove-
Child()-Methode des übergeord-
neten Anzeigeobjekt-Containers
auf,der das Textfeld enthält.
K A P I T E L 3112
ActionScript 2.0 ActionScript 3.0 Kommentare
replaceSel() flash.text.TextField.replaceS-
electedText()
Der Name wurde von replaces-
el() in replaceSelectedText()
geändert.Der newText-Parameter
wurde durch eine Zeichenfolge
ersetzt.
replaceText() flash.text.TextField.replace-
Text()
Der Datentyp der ersten beiden
Parameter wurde von Number zu
uint geändert.
setNewTextFormat() flash.text.TextField.default-
TextFormat
Der Name wurde von setNew-
TextFormat in defaultTextFor-
mat geändert.Von einer Methode
in eine Accessor-Eigenschaft
geändert.
setTextFormat() flash.text.TextField.setText-
Format()
Die Reihenfolge der Parameter
wurde geändert.Der Datentyp
der Indexparameter wurde von
Number in int geändert.
TextFormat-Klasse flash.text.TextFormat Diese Klasse wurde in das flash.
text-Paket verschoben.
align flash.text.TextFormat.align
blockIndent flash.text.TextFormat.blockIn-
dent
Der Datentyp wurde in
ActionScript 3.0 in Object ge-
ändert,da einer der möglichen
Werte null ist.Dieser Wert ist in
ActionScript 3.0 kein Mitglied des
Datentyps Number.
bold flash.text.TextFormat.bold Der Datentyp wurde in
ActionScript 3.0 in Object ge-
ändert,da einer der möglichen
Werte null ist.Dieser Wert ist in
ActionScript 3.0 kein Mitglied des
Datentyps Boolean.
bullet flash.text.TextFormat.bullet Der Datentyp wurde in
ActionScript 3.0 in Object ge-
ändert,da einer der möglichen
Werte null ist.Dieser Wert ist in
ActionScript 3.0 kein Mitglied des
Datentyps Boolean.
color flash.text.TextFormat.color Der Datentyp wurde in
ActionScript 3.0 in Object ge-
ändert,da einer der möglichen
Werte null ist.Dieser Wert ist in
ActionScript 3.0 kein Mitglied des
Datentyps Number.
font flash.text.TextFormat.font
indent flash.text.TextFormat.indent Der Datentyp wurde in
ActionScript 3.0 in Object ge-
ändert,da einer der möglichen
Werte null ist.Dieser Wert ist in
ActionScript 3.0 kein Mitglied des
Datentyps Number.
B A S I S W I S S E N 113
ActionScript 2.0 ActionScript 3.0 Kommentare
italic flash.text.TextFormat.bullet Der Datentyp wurde in
ActionScript 3.0 in Object ge-
ändert,da einer der möglichen
Werte null ist.Dieser Wert ist in
ActionScript 3.0 kein Mitglied des
Datentyps Boolean.
kerning flash.text.TextFormat.kerning Der Datentyp wurde in
ActionScript 3.0 in Object ge-
ändert,da einer der möglichen
Werte null ist.Dieser Wert ist in
ActionScript 3.0 kein Mitglied des
Datentyps Boolean.
leading flash.text.TextFormat.leading Der Datentyp wurde in
ActionScript 3.0 in Object ge-
ändert,da einer der möglichen
Werte null ist.Dieser Wert ist in
ActionScript 3.0 kein Mitglied des
Datentyps Number.
leftMargin flash.text.TextFormat.leftM-
argin
Der Datentyp wurde in
ActionScript 3.0 in Object ge-
ändert,da einer der möglichen
Werte null ist.Dieser Wert ist in
ActionScript 3.0 kein Mitglied des
Datentyps Number.
letterSpacing flash.text.TextFormat.letter-
Spacing
Der Datentyp wurde in
ActionScript 3.0 in Object ge-
ändert,da einer der möglichen
Werte null ist.Dieser Wert ist in
ActionScript 3.0 kein Mitglied des
Datentyps Number.
rightMargin flash.text.TextFormat.rightM-
argin
Der Datentyp wurde in
ActionScript 3.0 in Object ge-
ändert,da einer der möglichen
Werte null ist.Dieser Wert ist in
ActionScript 3.0 kein Mitglied des
Datentyps Number.
size flash.text.TextFormat.size Der Datentyp wurde in
ActionScript 3.0 in Object ge-
ändert,da einer der möglichen
Werte null ist.Dieser Wert ist in
ActionScript 3.0 kein Mitglied des
Datentyps Number.
underline flash.text.TextFormat.under-
line
Der Datentyp wurde in
ActionScript 3.0 in Object ge-
ändert,da einer der möglichen
Werte null ist.Dieser Wert ist in
ActionScript 3.0 kein Mitglied des
Datentyps Boolean.
url flash.text.TextFormat.url
TextFormat flash.text.TextFormat.
TextFormat()
Die Parameter size,color,bold,
italic,underline,url,left-
Margin,rightMargin,indent
und leading wurden in Objekte
umgewandelt.
K A P I T E L 3114
ActionScript 2.0 ActionScript 3.0 Kommentare
getTextExtent() Entfernt Verwenden Sie die Eigenschaften
von flash.text.TextField
zum Messen eines Felds mit ei-
ner Textzeile und flash.text.
TextLineMetrics zum Messen
des Inhalts innerhalb eines
Textfelds.
TextRenderer-Klasse flash.text.TextRenderer Der Speicherort wurde geändert.
In das flash.text-Paket verscho-
ben.
maxLevel flash.text.TextRenderer.max-
Level
In ActionScript 3.0 als uint defi-
niert
setAdvancedAntialia-
singTable()
flash.text.TextRenderer.setA-
dvancedAntiAliasingTable()
Die Parameterwerte fontStyle
und colorType können jetzt
mit den Konstanten FontStyle
und TextColorType eingestellt
werden.Der advancedAntiAlia-
singTable-Parameter nimmt jetzt
ein Array mit mindestens einem
CSMSettings-Objekt an.
TextSnapshot-Klasse flash.text.TextSnapshot Diese Klasse wurde in das
flash.text-Paket verschoben.
Verschiedene Parameter wur-
den geändert,ebenso einige
Methodennamen und einige
Rückgabetypen.
findText() flash.text.TextSnapshot.find-
Text()
Der Name des startIndex-
Parameters wurde in beginIndex
geändert.Der Datentyp des star-
tIndex-Parameters wurde von
Number zu int geändert.
getCount() flash.text.TextSnapshot.char-
Count
Von einer Methode zu einer
Accessor-Eigenschaft geändert.
Der Datenrückgabetyp wurde von
Number in uint geändert.
getSelected() flash.text.TextSnapshot.getSe-
lected()
Der Datentyp der Parameter wur-
de von Number in uint geändert
und die Namen wurden von start
und end in beginIndex und
EndIndex geändert.
getSelectedText() flash.text.TextSnapshot.getSe-
lectedText()
In ActionScript 3.0 hat der
Parameter den Standardwert
false.
getText() flash.text.TextSnapshot.get-
Text()
Der Datentyp der Parameter start
und end wurde von Number in
uint geändert und die Namen
wurden von start und end in
beginIndex und endIndex ge-
ändert.
getTextRunInfo() flash.text.TextSnapshot.getT-
extRunInfo()
Der Datentyp der Parameter wur-
de von Number in uint geändert.
B A S I S W I S S E N 115
ActionScript 2.0 ActionScript 3.0 Kommentare
hitTestTextNearPos() flash.text.TextSnapshot.hit-
TestTextNearPos()
Der Name des closeDist-
Parameters wurde in maxDistance
geändert.Dieser Parameter hat
jetzt den Standardwert = 0.
setSelectColor() flash.text.TextSnapshot.setSe-
lectColor()
Der Datentyp des Parameters
wurde von Number in uint geän-
dert.Der Parameter hat jetzt den
Standardwert = 0xFFFF00.
setSelected() flash.text.TextSnapshot.setSe-
lected()
Der Datentyp der Parameter start
und end wurde von Number in
uint geändert und die Namen
wurden von start und end in
beginIndex und endIndex ge-
ändert.
Video-Klasse flash.media.Video Diese Klasse wurde in das
flash.media-Paket verscho-
ben.Videoobjekte können in
ActionScript jetzt dynamisch
mit dem Video()-Konstruktor
erstellt werden.Hängen Sie einen
Videostream mit attachCamera()
oder attachNetStream() an das
Videoobjekt an.
_alpha flash.display.DisplayObject.
alpha
Diese Eigenschaft wird von der
DisplayObject-Klasse übernom-
men.Der Unterstrich am Anfang
wurde entfernt.
deblocking flash.media.Video.deblocking Der Datentyp wurde von Number
in int geändert.
_height flash.display.DisplayObject.
height
Diese Eigenschaft wird von der
DisplayObject-Klasse übernom-
men.Der Unterstrich am Anfang
wurde entfernt.
height flash.media.Video.videoHeight Der Datentyp wurde von Number
in int geändert.
_name flash.display.DisplayObject.
name
Diese Eigenschaft wird von der
DisplayObject-Klasse übernom-
men.Der Unterstrich am Anfang
wurde entfernt.
_parent flash.display.DisplayObject.
parent
Diese Eigenschaft wird von der
DisplayObject-Klasse übernom-
men.Der Unterstrich am Anfang
wurde entfernt.
_rotation flash.display.DisplayObject.
rotation
Diese Eigenschaft wird von der
DisplayObject-Klasse übernom-
men.Der Unterstrich am Anfang
wurde entfernt.
smoothing flash.media.Video.smoothing
_visible flash.display.DisplayObject.
visible
Diese Eigenschaft wird von der
DisplayObject-Klasse übernom-
men.Der Unterstrich am Anfang
wurde entfernt.
K A P I T E L 3116
ActionScript 2.0 ActionScript 3.0 Kommentare
_width flash.display.DisplayObject.
width
Diese Eigenschaft wird von der
DisplayObject-Klasse übernom-
men.Der Unterstrich am Anfang
wurde entfernt.
width flash.media.Video.videoWidth Der Datentyp wurde von Number
zu int geändert.
_x flash.display.DisplayObject.x Diese Eigenschaft wird von der
DisplayObject-Klasse übernom-
men.Der Unterstrich am Anfang
wurde entfernt.
_xmouse flash.display.DisplayObject.
mouseX
Diese Eigenschaft wird von der
DisplayObject-Klasse übernom-
men.Der Unterstrich am Anfang
wurde entfernt.
_xscale flash.display.DisplayObject.
scaleX
Diese Eigenschaft wird von der
DisplayObject-Klasse übernom-
men.Der Unterstrich am Anfang
wurde entfernt.
_y flash.display.DisplayObject.y Diese Eigenschaft wird von der
DisplayObject-Klasse übernom-
men.Der Unterstrich am Anfang
wurde entfernt.
_ymouse flash.display.DisplayObject.
mouseY
Diese Eigenschaft wird von der
DisplayObject-Klasse übernom-
men.Der Unterstrich am Anfang
wurde entfernt.
_yscale flash.display.DisplayObject.
scaleY
Diese Eigenschaft wird von der
DisplayObject-Klasse übernom-
men.Der Unterstrich am Anfang
wurde entfernt.
attachVideo() flash.media.Video.attachNet-
Stream()
Verwenden Sie flash.media.
Video.attachCamera(),um
einen Videostream von einem
Kameraobjekt anzugeben.
clear() flash.media.Video.clear()
XML-Klasse flash.xml.XMLDocument Diese Klasse wurde in das flash.
xml-Paket verschoben und der
Name in XMLDocument geändert,
um einen Konflikt mit der neuen
Top-Level XML-Klasse zu vermei-
den,die ECMAScript für XML (E4X)
implementiert.
contentType flash.net.URLRequest.conten-
tType
docTypeDecl flash.xml.XMLDocument.docType-
Decl
idMap flash.xml.XMLDocument.idMap
ignoreWhite flash.xml.XMLDocument.ignore-
White
loaded Entfernt Die Funktionen zum Laden
einer Datei wurden aus der
XMLDocument-Klasse entfernt.
Verwenden Sie stattdessen
URLLoader.
B A S I S W I S S E N 117
ActionScript 2.0 ActionScript 3.0 Kommentare
status Entfernt Fehler beim Parsen werden jetzt
über Ausnahmefehler gemeldet.
xmlDecl flash.xml.XMLDocument.xmlDecl
XML flash.xml.XMLDocument.
XMLDocument()
addRequestHeader() flash.net.URLRequest.request-
Headers
createElement() flash.xml.XMLDocument.create-
Element()
createTextNode() flash.xml.XMLDocument.create-
TextNode()
getBytesLoaded() flash.net.URLLoader.bytes-
Loaded
Die Funktionen zum Laden
einer Datei wurden aus der
XMLDocument-Klasse entfernt.
Verwenden Sie stattdessen
URLLoader.
getBytesTotal() flash.net.URLLoader.bytesTotal Die Funktionen zum Laden
einer Datei wurden aus der
XMLDocument-Klasse entfernt.
Verwenden Sie stattdessen
URLLoader.
load() Entfernt Die Funktionen zum Laden
einer Datei wurden aus der
XMLDocument-Klasse entfernt (in
ActionScript 2.0 war dies die XML-
Klasse).Verwenden Sie stattdessen
URLLoader.
onData() flash.net.URLLoader dispatches
event: complete
Die Funktionen zum Laden
einer Datei wurden aus der
XMLDocument-Klasse entfernt.
Verwenden Sie stattdessen
URLLoader.Wurde im neuen Ereig-
nismodell durch ein complete-
Ereignis ersetzt.
onHTTPStatus() flash.net.URLLoader dispatches
event: httpStatus
Die Funktionen zum Laden
einer Datei wurden aus der
XMLDocument-Klasse entfernt.
Verwenden Sie stattdessen
URLLoader.Wurde im neuen
Ereignismodell durch ein http-
Status-Ereignis ersetzt.
onLoad() flash.net.URLLoader dispatches
event: complete
Die Funktionen zum Laden
einer Datei wurden aus der
XMLDocument-Klasse entfernt.
Verwenden Sie stattdessen
URLLoader.Wurde im neuen Ereig-
nismodell durch ein complete-
Ereignis ersetzt.
parseXML() flash.xml.XMLDocument.
parseXML()
K A P I T E L 3118
ActionScript 2.0 ActionScript 3.0 Kommentare
send() Entfernt Die Funktionen zum Senden
einer Datei wurden aus der
XMLDocument-Klasse entfernt (in
ActionScript 2.0 war dies die XML-
Klasse).Verwenden Sie stattdessen
die Funktionen und Klassen im
flash.net-Paket.
sendAndLoad() Entfernt Die Funktionen zum Senden und
Laden einer Datei wurden aus der
XMLDocument-Klasse entfernt (in
ActionScript 2.0 war dies die XML-
Klasse).Verwenden Sie stattdessen
URLRequest und URLLoader.
XMLNode-Klasse flash.xml.XMLNode Der Speicherort wurde geändert.
Diese Klasse wurde in das flash.
xml-Paket verschoben.
nodeType flash.xml.XMLNode.nodeType Der Datentyp wurde von Number
in uint geändert.
XMLNode flash.xml.XMLNode.XMLNode() Der Datentyp des type-Parameters
wurde von Number in uint geän-
dert.
XMLSocket-Klasse flash.net.XMLSocket Diese Klasse wurde in das flash.
net-Paket verschoben.
XMLSocket flash.net.XMLSocket.
XMLSocket()
Es wurden zwei optionale
Parameter zum Festlegen von Host
und Port hinzugefügt.
connect() flash.net.XMLSocket.connect() Der Datentyp des port-Parameters
wurde in int geändert.
onClose() flash.net.XMLSocket dispatches
event: close
Wurde im neuen Ereignismodell
durch ein close-Ereignis ersetzt.
onConnect() flash.net.XMLSocket dispatches
event: connect
Wurde im neuen Ereignismodell
durch ein connect-Ereignis er-
setzt.
onData() flash.net.XMLSocket dispatches
event: data
Wurde im neuen Ereignismodell
durch ein data-Ereignis ersetzt.
onXML() Entfernt In ActionScript 3.0 wird nur das
data-Ereignis ausgelöst,sodass
Sie entweder E4X- oder den äl-
teren XML-Parser (XMLDocument-
Klasse) verwenden können.Die
alte Ereignisprozedur onXML
wurde nach dem Parsen des XML-
Codes aufgerufen.Dies ergibt in
ActionScript 3.0 keinen Sinn,weil
Sie zum Parsen des XML-Codes
jetzt zwischen der XML-Klasse
(E4X) und der XMLDocument-Klasse
(ältere Version) wählen können.
Tabelle 3.1: Migration von ActionScript 2.0 auf ActionScript 3.0 (Quelle: ActionScript-Hilfe von Flash CS3)
4
AJAX –
ASYNCHRONUS
JAVASCRIPT AND XML
In diesem Kapitel setzen wir uns mit den Grundlagen von
AJAX auseinander und zeigen die Möglichkeiten der „Zusam-
menarbeit“ mit Flash auf. Unweigerlich werden wir in diesem
Kapitel zu dem Schluss gelangen, dass alle Möglichkeiten von
AJAX (Web 2.0) in Flash schon seit langem implementiert sind.
Aus diesem Grund müssen wir uns auch mit der Thematik
befassen, inwiefern AJAX eine Konkurrenz bzw. Alternative zu
Flash darstellt und wo der Einsatz der einen oder der anderen
Technologie mehr oder weniger Sinn macht.
Klarerweise ist dieses Buch kein AJAX-Buch – aus diesem Grund
werden wir uns auch nur mit den Kernthemen von AJAX befas-
sen (die im Übrigen gar nicht so umfassend sind) und diese für
uns sinnvoll nutzen. Auch möchte ich nicht auf die Entwicklung
aller Scripten eingehen, sondern vielmehr diese als „Entwickelt
und zum Benutzen bereitgestellt“ vorstellen.
K A P I T E L 4120
4.1 Was ist AJAX?
Der grundlegende Vorteil von AJAX ist, dass auf ein bereits vollständig vom Server
zum Client übertragenes Webdokument im Nachhinein und ohne Neuladen des
Dokuments weitere Daten vom Server abgefragt werden können. Eine Interaktion mit
dem Server ist also ohne Neuladen (Refresh) des Dokuments möglich.
AJAX ist im Grunde genommen eine Kombination mehrerer Technologien:
XHTML und CSS: Diese beiden Technologien verwenden wir zur Darstellung der
Daten auf einer Website – sie bilden bekannterweise unser Gerüst. Dies gilt selbst-
verständlich nach wie vor und – wie wir wissen – hierin werden alle unsere Assets
wie Texte, Grafiken, SWF-Dateien usw. eingebettet.
XML: wird zur Übertragung von Daten zwischen Server und Client verwendet.
XMLHttpRequest: stellt die essenziell wichtige Möglichkeit des asynchronen Nach-
ladens von Informationen vom Server dar. Erst mithilfe dieser „Technologie“ wird
es möglich, auf einer bereits vollständig zum User übertragenen Website weitere
Daten vom Server nachzuladen.
JavaScript: bildet die Schnittstelle zwischen allen Technologien. Das DOM (Docu-
ment Object Model) steht hier als die Möglichkeit, bereits im Webdokument vor-
handene Daten nachträglich zu verändern.
Das einzig wirklich Neue an AJAX ist der XMLHttpRequest, alles andere ist bekannt.
Dies soll jedoch keineswegs bedeuten, dass wir sofort AJAX-Experten sind, wenn wir
XHTML-Dokumente mit CSS aufbauen und JavaScript programmieren können. Kei-
neswegs! Gerade das Zusammenspiel aller Technologien stellt die eigentliche Schwie-
rigkeit dar. Auch müssen wir im Umgang mit dem Document Object Model relativ fit
sein.
4.2 Was ist AJAX nicht?
AJAX ist in aller Munde und Web 2.0 sowieso. Je mehr „Web 2.0“ eine Website ist,
umso trendiger und moderner ist sie. Oder etwa nicht?
AJAX ist kein Allheilmittel für alle Probleme und Workarounds, die während der Ent-
wicklung einer Website auftreten. Klar – jeder Webdesigner, der etwas auf sich hält,
wird versuchen, um die Burg eine AJAX-Anwendung zu programmieren. Ja, AJAX
stellt eine Abhilfe für dynamische Anwendungen dar, die während der Darstellung
eines einzelnen Webdokuments im Nachhinein noch Daten zusätzlich anzeigen möch-
ten (ohne das Dokument neu zu laden). Jedoch darf nicht außer Acht gelassen werden,
dass AJAX sinnvoll eingesetzt gehört: Je häufiger die Anfragen an einen Server gestellt
werden, umso mehr gerät der Server unter Last.
u
u
u
u
Nachladen von
Daten ohne
Refresh
Nachladen von
Daten ohne
Refresh
A J A X – A S Y N C H R O N U S J AVA S C R I P T A N D X M L 121
Stellen Sie sich folgendes Szenario vor: Auf einer Website werden die Schlagzeilen des
Tages (in Österreich haben wir das Beispiel des Österreichischen Rundfunks (ORF)
– www.orf.at) dargestellt. Mehrmals am Tag besuche ich die Seite und sehe nach,
was sich getan hat (gehen wir mal davon aus, dass ich keinen Newsreader verwende).
Nachdem ich einen Proxy-Server in Betrieb habe und somit die Inhalte gecached
werden, muss ich die Seite aktualisieren, um zu den neuesten Informationen zu kom-
men. Eigentlich würde man meinen, dass dies ein tolles Einsatzgebiet für eine AJAX-
Anwendung ist: Statt dass ein User den Refresh-Button klicken muss, lädt sich die Seite
in regelmäßigen Abständen (beispielsweise jede Minute) die neuesten Informationen
automatisch down und gibt diese aus. Bei einer geschätzten Anzahl von zigtausend
Usern der ORF-Seite wäre das eine ungeheure Belastung für den Server: Für diese
zigtausend User muss er jede Minute einen Datenbank-Server abfragen, die News
zusammenstellen und den (zigtausend) Usern zurückschicken. Der Datentransfer wäre
enorm! Ein guter Webdesigner ist deshalb ein solcher, der die zur Verfügung stehenden
Technologien sinnvoll und bewusst einsetzt.
Es gibt jedoch noch weitere Probleme, die im Zusammenhang mit AJAX auftreten:
1. Der Back- oder Zurück-Button hat bei AJAX-Anwendungen keine Bedeutung
mehr: Nachdem der Back-Button dafür bestimmt ist, das zuvor angezeigte
Webdokument anzuzeigen, wird dies vom Server neu angefordert. Genau das
ist aber das Verfahren, das wir bei AJAX vermeiden (umgehen) wollen: das
Neuladen eines Dokuments. In einem AJAX-basierten Dokument werden die
neuen/zusätzlichen Inhalte nicht in Form eines neuen (anderen) Webdokuments,
sondern im aktuellen Webdokument selbst dargestellt.
2. Keine Unterstützung in älteren Browsern: AJAX in vollem Umfang setzt relativ
neue Browser voraus! Konkret heißt das, dass diese Browser zwar mit der
asynchronen Datenübertragung keine Probleme haben, jedoch das Document
Object Model (DOM) und die zugehörigen JavaScript-Befehle nicht in dem
Umfang unterstützen, wie AJAX das für vernünftige Anwendungen benötigt.
3. Thema Barrierefreiheit: AJAX ist beileibe nicht barrierefrei. Nehmen wir den
Fall eines sehbehinderten Users: Dieser verwendet zumeist eine Software, die
den Quellcode einer Seite liest, diesen interpretiert und akustisch ausgibt. Nun,
AJAX verändert im Nachhinein den Inhalt eines Webdokuments, jedoch nicht den
Quelltext (dieser ist unveränderlich und liegt so auf, wie er vom Server geliefert
wurde). Somit kann ein Quellcode-Interpreter die durch AJAX geänderten Inhalte
auch nicht wiedergeben.
Setzen Sie AJAX bewusst ein – bedenken Sie insbesondere auch die Serverseite wie
oben angesprochen. Was haben Ihre User davon, dass das Webdokument zwar nicht
mehr aktualisiert werden muss, jedoch der Server regelmäßig unter Volllast in die Knie
geht.
K A P I T E L 4122
4.3 Der XMLHttpRequest
Wie wir bereits aus dem Grundlagenkapitel wissen, erfolgt eine Datenanforderung
eines Clients (im Allgemeinen meinen wir hier den User und seinen Browser) an einen
Server (Webserver) aus folgenden Gründen:
1. Anfordern eines Webdokuments: Der User sitzt vor seinem Browser und gibt in
der Adresszeile eine URL an oder klickt in einer bereits angezeigten Website auf
einen Link.
2. Aktualisieren eines (bereits angezeigten) Webdokuments: Der User entscheidet
sich für ein Aktualisieren der Site und klickt auf den Refresh-Button.
3. Abschicken eines Formulars: Der User füllt (bewusst oder unbewusst) ein
Formular innerhalb eines Webdokuments aus und schickt das Formular (bewusst
oder unbewusst) ab.
In jedem der drei Fälle entsteht für den User durch die Datenanforderung eine Warte-
zeit, die sich wie folgt zusammensetzt – in dieser Zeit kann der User die Website nicht
bedienen, sie ist inaktiv:
1. Datenübertragung vom Client zum Server: Die Anforderung des Clients an den
Server wird abgeschickt. Dieser Teil der Wartezeit ist relativ gering und hängt
wesentlich von der Anbindung des Users ans Internet ab. Im Allgemeinen ist diese
Zeitspanne jedoch vernachlässigbar gering.
2. Datenverarbeitung am Server: Die Anforderung des Clients wird am Server
verarbeitet.Je nach angeforderten Informationen stellt dies eine mehr oder weniger
lange Wartezeit dar – für den Fall, dass beispielsweise Daten aus einer Datenbank
gelesen werden und in ein PHP- (oder ähnliches) Dokument geschrieben werden
müssen, kann dies durchaus eine Wartezeit von mehreren Sekunden bedeuten.
3. Datenübertragung vom Server zum Client: Die vom Server aufbereiteten Daten
(XHTML-basiertes Webdokument) werden zurück an den Client geschickt. An
dieser Stelle spielt selbstverständlich die Menge an zu übertragenden Daten sowie
die Anbindung des Users an das Internet eine wesentliche Rolle.
4. Aufbau der Site auf Userseite: Je nach Komplexität des Webdokuments kann der
Aufbau der Website mehr oder weniger lange dauern. Im Allgemeinen dauert
jedoch auch diese Zeitspanne mehrere Sekunden.
Die nachfolgende Grafik verdeutlicht die Wartezeiten:
A J A X – A S Y N C H R O N U S J AVA S C R I P T A N D X M L 123
Mit dem Einsatz von AJAX (im Speziellen: dem XMLHttpRequest) wird sich das
Thema „Inaktivität der Website“ grundlegend ändern. Selbstverständlich bleiben die
Schritte 1 (Clientanforderung an den Server) und 2 (Serververarbeitung) bestehen,
jedoch wird die Site durch die Clientanforderung nicht inaktiv, da die Site nicht wie
bisher neu geladen wird, sondern ihr vielmehr nur mehr Daten hinzugefügt wer-
den – das angezeigte Webdokument bleibt im Browser bestehen und der User kann
somit normal weiterarbeiten. Durch dieses Prinzip verringern sich zusätzlich auch
die Wartezeiten auf die nachgeladenen Daten, da einerseits nicht mehr das gesamte
Webdokument vom Server zurückgeschickt wird und andererseits nur noch ein Teil
des (bestehen gebliebenen) Webdokuments neu aufgebaut werden muss. Dies gilt
selbstverständlich nur für den Fall, dass der Webdesigner umdenkt:
Anzeigen eines anderen Webdokuments wird ersetzt durch Verändern der Inhalte
eines bereits angezeigten Webdokuments.
Anzeigen von zusätzlichen Formularfeldern je nach voriger Auswahl durch den
User (bei Formularen): Es wird nicht mehr dasselbe Dokument zum Server zurück-
geschickt und vom Server mit zusätzlichen Formularfeldern versehen, sondern
dem bestehenden Dokument werden neue Formularfelder hinzugefügt.
usw.
u
u
u
ABBILDUNG 4.1
Durch eine Anfrage des
Clients an den Server ent-
steht ein nicht unerheblicher
Zeitraum, in dem die Website
inaktiv ist.
K A P I T E L 4124
Diese Liste lässt sich noch weiter fortsetzen, doch letzten Endes wäre sie nur eine
Auflistung von Möglichkeiten, die nie vollständig sein wird. Ich überlasse es Ihnen,
lieber Leser, die Möglichkeiten im Rahmen von XHTML zu erkennen und daraus Ihre
Schlüsse zu ziehen. Uns geht es darum, wie AJAX mit Flash arbeiten kann bzw. inwie-
weit Flash in Hinblick auf AJAX Gefahr läuft, den Rang abgelaufen zu bekommen.
Das Prinzip des „Nachladens“ stellt sich also wie folgt dar – während der gesamten
Zeitspanne kann der User ungehindert auf der Website weiterarbeiten:
1. Datenübertragung vom Client zum Server: Die Anforderung des Clients an den
Server wird abgeschickt. Dies geschieht im Hintergrund und der User kann weiter
auf der Website arbeiten.
2. Datenverarbeitung am Server: Die Anforderung des Clients wird am Server
verarbeitet. Da im Allgemeinen nun die Menge an Daten geringer ist als ohne
AJAX (jetzt werden nur mehr zusätzliche Daten aufbereitet und nicht mehr das
gesamte Webdokument), verringert sich auch die Abarbeitungszeit am Server.
3. Datenübertragung vom Server zum Client: Die vom Server aufbereiteten Daten
(XML-basiert) werden zurück an den Client geschickt. An dieser Stelle spielt wie
auch zuvor die Menge an zu übertragenden Daten sowie die Anbindung des Users
an das Internet eine wesentliche Rolle, jedoch gilt auch hier: Man kann davon
ausgehen, dass diese Zeitspanne geringer ist als ohne AJAX, da wiederum nur
weniger Daten zum Client zurückgeschickt werden.
4. Anzeigen der Daten auf Userseite: Die nachgeladenen Daten werden durch
JavaScript mithilfe des DOM auf der Website dargestellt.
Als Webdesigner muss man an dieser Stelle davon ausgehen, dass dem User ein etwa-
iges Nachladen gar nicht bewusst ist – Usability kommt ins Spiel! Sollten Sie davon
ausgehen müssen, dass der Nachladevorgang einige Sekunden in Anspruch nimmt, so
teilen Sie dies dem User mit. Dem User ist nicht klar, ob die betrachtete Webanwen-
dung AJAX-basiert ist (und er somit zu jeder Zeit damit rechnen muss, dass Daten
nachgeladen werden) oder nicht.
AJAX & UsabilityAJAX & Usability
A J A X – A S Y N C H R O N U S J AVA S C R I P T A N D X M L 125
4.3.1 Details zum XMLHttpRequest-Objekt
Nun ist es an der Zeit, das XMLHttpRequest-Objekt aus Programmiersicht einmal
genauer zu betrachten. Wie jedes Objekt in der Objektorientierten Programmierung
(OOP) besteht es aus Methoden und Eigenschaften:
Methode Beschreibung
abort() Eine aktuelle mit (send()) abgeschickte Serveranfrage wird
gestoppt.
getAllResponseHeaders() Auslesen der vom Server zurückgesandten Header-Felder in
Form eines String
getResponseHeader("Feldname") Funktioniert wie die Methode getAllResponseHeaders(),
nur dass hier über einen Parameter Feldname ein spezielles
Feld abgefragt wird.Der Rückgabewert ist vom Typ String.
open("Methode", "URL" [,asyncMo-
de[, "Username"[, "Passwort"]]])
Diese Methode wird verwendet,um eine Verbindung zu
einem Webserver zu öffnen.(Beachte:Eine konkrete Anfrage
an den Server wird zu diesem Zeitpunkt noch nicht gestellt
– dies geschieht erst mit der Methode send()).Auf die
einzelnen Parameter gehen wir weiter unten genau ein.
send(Content) Hiermit wird die Anfrage an den Server übermittelt und
nach der Methode open() ausgeführt.Der Parameter
Content ist entweder null (bei einer gewählten
Übertragungsmethode GET) oder ein QueryString (bei
POST).
ABBILDUNG 4.2
Im Falle des Nachladens von
Daten durch AJAX kann der
User ungehindert weiter mit
der Site arbeiten – es ent-
steht keinerlei Inaktivität auf
Clientseite!
K A P I T E L 4126
setRequestHeader("Label", "Wert") Diese Methode wird dafür verwendet,etwaige Header-
Felder mit bestimmten Werten zu füllen.Beispielsweise wird
diese Methode benötigt,um dem Server bekanntzugeben,
dass die gesandten Daten Formulardaten sind.
setMimeType("Typ") Hiermit wird der Typ der angeforderten (und per Response
zurückzuschickenden) Daten angegeben und zwar wie üb-
lich in Form eines Strings wie etwa "text/xml".Da manche
Browser (hierunter auch der Internet Explorer) Probleme mit
diesem Parameter haben,wird er zumeist einfach wegge-
lassen,da beim Anfordern von XML-Daten keine konkrete
Kennzeichnung als XML erforderlich ist.
Tabelle 4.1: Methoden des XMLHttpRequest-Objekts
Betrachten wir die Parameter der open()-Methode etwas genauer:
Methode (String): Dieser Parameter kann GET, POST, HEAD oder PUT sein.
Typischerweise werden die (bekannteren) Methoden GET oder POST verwendet.
HEAD wird verwendet, wenn man nur die Header-Informationen und keine Daten
erhalten möchte. PUT verwendet man, wenn beispielsweise Dateien zum Server
transferiert werden sollen (doch selbst in diesem Fall wird oft mit der POST-
Methode übertragen).
URL (String): Gibt an, welches serverseitige Script (mit anderen Worten, welche
PHP-Datei) aufgerufen werden soll. Der Bezug auf das Script kann absolut oder
relativ gewählt werden.
asyncMode (Boolean): Kennzeichnet die Art der Abarbeitung der Anfrage an
den Server:
asyncMode==true: Die Anfrage wird asynchron verarbeitet, was so viel bedeu-
tet, wie dass das Webdokument auf Userseite nicht blockiert wird und somit der
User weiter im Dokument arbeite
e Antwort vom Server eingelangt ist – der User kann in der Zwischenzeit nicht
im Dokument weiterarbeiten.
Username (String) und Passwort (String): In manchen Fällen sind ein
Username ein und Passwort für den Zugriff auf Ressourcen (beispielsweise Scripts
in geschützten Ordnern, die nicht für den Zugriff des Internet-Users freigegeben
sind) des Webservers von Nöten, die über diese beiden Parameter angegeben wer-
den können.
Nachdem wir nun die Methoden des XMLHttpRequest-Objekts kennen, müssen wir
uns noch um die Eventhandler und Eigenschaften kümmern:
u
u
u
u
u
u
A J A X – A S Y N C H R O N U S J AVA S C R I P T A N D X M L 127
Eventhandler Beschreibung
onreadystatechange Dieser Handler wird immer dann aufgerufen,wenn sich der
Verbindungsstatus (readyState) des XMLHttpRequest-Objekts ver-
ändert hat.Mithilfe der Eigenschaft readyState kann der aktuelle
Verbindungsstatus verarbeitet werden.In der Regel wird über diesen
Eventhandler eine Funktion aufgerufen – man nennt solche Funktionen
wie oben beschrieben Callback-Funktionen.
Tabelle 4.2: Eventhandler des XMLHttpRequest-Objekts
Eigenschaft Beschreibung
readyState Hiermit wird der aktuelle Status der Verbindung zum Server abgefragt.
Die möglichen Werte werden weiter unten genau behandelt.
responseText Hierin befinden sich die vom Server nach einer Anfrage übermittelten
Daten in Textform.
responseXML Gleich wie responseText,nur dass die Daten eine XML-Struktur auf-
weisen.Sollten die Daten nicht in XML-Form vom Server verschickt
worden sein,ist diese Eigenschaft null.
status Beinhaltet den HTTP-Status der aktuellen Verbindung als Zahl.
statusText Gleich wie status,nur wird der Status in Form einer Textmeldung
ausgegeben (dies muss nicht notwendigerweise der Fall sein – arbeiten
Sie deshalb besser mit der Eigenschaft status).
Tabelle 4.3: Eigenschaften des XMLHttpRequest-Objekts
responseText oder responseXML?
Wie Sie anhand der oben stehenden Tabelle sehen, existieren zwei (Formatierungs-)Arten
der Rückgabedaten durch den Server: responseText und responseXML. Je nach
Anwendungsgebiet verwendet man eine der beiden Varianten. Man sollte jedoch nicht außer
Acht lassen, dass AJAX – wie der Name „Asynchronous JavaScript and XML“ schon sagt
– darauf spezialisiert ist, mit XML-Daten zu arbeiten. Wann immer es darum geht, komplexere
Datenstrukturen darzustellen, sollte man deshalb zu responseXML greifen. Sie sollten sich
jedoch bewusst sein, dass eine Abarbeitung von XML für eine Browser-Darstellung mitunter sehr
aufwändig sein kann.
Von besonderem Interesse für uns ist auch die Eigenschaft readyState, die alle Infor-
mationen über die aktuelle Verbindung zum Server für uns hat:
Wert Bedeutung Beschreibung
0 UNITIALIZED Es besteht derzeit keine geöffnete
Verbindung,da die Methode
open() noch nicht aufgerufen
wurde.Man könnte sagen,dies
entspricht dem„Ruhezustand“
des XMLHttpRequest-Objekts.
1 LOADING Zu diesem Zeitpunkt wur-
de mit open() bereits ein
XMLHttpRequest-Objekt erstellt,
jedoch wurde die Methode
send() noch nicht aufgerufen.
K A P I T E L 4128
2 LOADED Die Anfrage wurde per send()
bereits abgeschickt.Auf den
Header der Antwort vom Server
kann bereits zugegriffen werden,
jedoch nicht auf die zurückge-
schickten Daten (diese sind zu
diesem Zeitpunkt noch nicht
eingetroffen).
3 INTERACTIVE Zu diesem Zeitpunkt sind die ers-
ten Daten bereits übermittelt und
es treffen noch weitere Daten ein.
Man kann zwar schon Daten von
responseText und responseXML
abfragen,jedoch sind diese noch
nicht vollständig.
4 COMPLETED Jetzt sind alle Daten vom
Server zum Client übermittelt
worden (sofern während der
Übermittlung kein Fehler auf-
getreten ist).Nun sind auch die
Eigenschaften responseText
und responseXML mit sämtlichen
Daten gefüllt und können voll-
ständig verarbeitet werden.
Tabelle 4.4: Werte der Eigenschaft readyState des XMLHttpRequest-Objekts
4.3.2 AJAX im Einsatz
Wenn wir nun alles Gelesene des XMLHttpRequest-Objekts zusammenfassen, können
wir die Abarbeitung dessen wie folgt zusammenfassen:
1. Instanz des XMLHttpRequest-Objekts anlegen: Zunächst muss eine Instanz des
XMLHttpRequest-Objekts angelegt werden.Weiter unten sehen wir, dass wir – wie
üblich – auf verschiedene Browser eingehen müssen.
2. Callback-Funktion definieren: Noch bevor wir uns um eine etwaige Anfrage
an einen Server kümmern, müssen wir festlegen, was passieren soll, wenn
die Übertragung einmal läuft. Hierzu bedienen wir uns des Eventhandlers
onreadystatechange, der uns gemeinsam mit der Eigenschaft readyState
genau Auskunft gibt, wie es um die Kommunikation mit dem Server bestellt ist.
3. Verbindung öffnen: Mithilfe der Methode open() wird eine Verbindung zum
Server geöffnet, jedoch noch nicht abgeschickt. Solange send() nicht aufgerufen
wird, passiert gar nichts.
4. Anfrage abschicken: Dies geschieht wie angesprochen mit send(). Ab diesem
Zeitpunkt wird der Server aktiv. Nun gilt es abzuwarten, bis der Server alle
angeforderten Daten zurückgeschickt hat – wann dies der Fall ist, sagt uns die
Eigenschaft readyState des XMLHttpRequest-Objekts.
A J A X – A S Y N C H R O N U S J AVA S C R I P T A N D X M L 129
5. Auf abgeschlossene Übertragung warten: Wie eingangs erwähnt, ist nun
der Eventhandler onreadystatechange am Werkeln. Hat die Eigenschaft
readyState den Wert 4, so ist die Kommunikation zwischen Server und Client
wieder abgeschlossen und es kann auf die übermittelten Daten zugegriffen
werden.
ABBILDUNG 4.3
Die fünf Schritte einer
XMLHttpRequest-Anfrage
Kommen wir also zur essenziellen Frage, wie diese fünf Schritte aus Sicht des Pro-
grammierers aussehen. Bitte beachten Sie an dieser Stelle, dass wir weiter unten im
Buch eine alternative Variante (Listing 4.8) für die Abarbeitung von AJAX-Anfragen
besprechen werden, da diese erste Variante im Internet Explorer nur ein einziges
Mal ausgeführt werden kann. Jedoch verdeutlicht diese erste Variante sehr schön die
(korrekte) Vorgehensweise, sodass ich Sie zunächst über diesen Weg in die Thematik
einführen möchte.
In Schritt 1 kümmern wir uns um die Instanzierung des XMLHttpRequest-Objekts.
Wie oben schon angedeutet, müssen wir auf verschiedene Browser Rücksicht neh-
men. Beispielsweise verhalten sich verschiedene Browser-Generationen des Internet
Explorer ebenfalls unterschiedlich. Der „offizielle Weg“ führt über die Instanzierung
mittels:
var myXMLHttpRequest = new XMLHttpRequest();
Listing 4.1: Der „offizielle Weg“ zum Instanzieren eines XMLHttpRequest-Objekts. Im Gegensatz zu allen
Mozilla-basierten Browsern (wie etwa dem Firefox) versteht der Internet Explorer diese Instanzierung
nicht.
Instanzierung für
Firefox & Co.
Instanzierung für
Firefox & Co.
K A P I T E L 4130
Diese Instanzierung verwenden alle Mozilla-basierten Browser wie etwa der Firefox.
Ein Internet Explorer der Generation 6 und höher erwartet eine Instanzierung wie
folgt:
var myXMLHttpRequest = new ActiveXObject("MSXML2.XMLHTTP");
Listing 4.2: Instanzierung für den Internet Explorer 6 und höher
Ältere Internet Explorer hingegen möchten folgende Instanzierung:
var myXMLHttpRequest = new ActiveXObject("Microsoft.XMLHTTP");
Listing 4.3: Instanzierung für Internet Explorer-Versionen kleiner als 6
Fasst man diese drei Wege in einem gemeinsamen Script zusammen, so bedient man
sich gerne der Methode „try & catch“, wo mithilfe des try-Befehls eine Variante
ausprobiert wird. Sollte diese fehlschlagen, so wird der Programmblock im catch-
Abschnitt ausgeführt:
try { var myXMLHttpRequest = new XMLHttpRequest(); }
catch(error) {
try { var myXMLHttpRequest = new ActiveXObject("MSXML2.XMLHTTP"); }
catch(error) { var myXMLHttpRequest = new ActiveXObject("Microsoft.
XMLHTTP"); }
}
}
Listing 4.4: Nachdem alle Möglichkeiten von Browsern berücksichtigt („durchprobiert“) wurden, beinhaltet
die Variable myXMLHttpRequest eine gültige Instanz eines XMLHttpRequest-Objekts.
Idealerweise verpackt man dieses Script in eine Funktion, die als Rückgabewert die
Instanz liefert.
In Schritt 2 kümmern wir uns darum, dass wir clientseitig in der Lage sind, auf die
abgeschlossene Übertragung der vom Server angeforderten Daten reagieren zu kön-
nen.
myXMLHttpRequest.onreadystatechange = function() {
switch(myXMLHttpRequest.readyState) {
case 0:
case 1:
case 2:
case 3: return;
case 4: showResponse(); return;
Instanzierung für
IE-Versionen 6
und höher
Instanzierung für
IE-Versionen 6
und höher
Instanzierung
für IE-Versionen
kleiner als 6
Instanzierung
für IE-Versionen
kleiner als 6
A J A X – A S Y N C H R O N U S J AVA S C R I P T A N D X M L 131
}
}
Listing 4.5: Der Eventhandler onreadystatechange hilft uns, auf Änderungen in unserem XMLHtt-
pRequest-Objekt zu reagieren. Lediglich der Fall 4 (Übertragung aller vom Server angeforderten Daten
abgeschlossen) ist für uns interessant.
Mithilfe einer switch-Anweisung werden alle Möglichkeiten der Eigenschaft ready-
State durchgegangen. Für die Fälle 0–3 macht die Funktion nichts, erst im Fall 4 rea-
giert sie und ruft ihrerseits die Funktion showResponse auf. Diese Funktion erledigt
dann die Ausgabe der vom Server angeforderten und vollständig zurückgelieferten
Daten.
In Schritt 3 wollen wir die soeben erzeugte Instanz öffnen und bedienen uns daher der
open-Methode:
myXMLHttpRequest.open("GET", "testrequest.htm", true);
Listing 4.6: Anfrage für das Dokument testrequest.htm per POST im Asynchron-Modus (Parameter
true)
Schritt 4 schickt die Anfrage ab:
myXMLHttpRequest.send(null);
Listing 4.7: Absenden der Anfrage an den Server: „Schick mir das Dokument testrequest.htm“
Zusammengefasst in einem Beispiel könnte das wie folgt aussehen: Per Klick auf einen
Button fordern wir den Server auf, uns die Datei testrequest.htm zu schicken. Nachdem
wir das Dokument erhalten haben, geben wir es in ein Textfeld (<textarea>) aus.
Gleichzeitig erzeugen wir ein zweites Textfeld, wo wir uns jeweils den aktuellen Wert
der Eigenschaft readyState ausgeben lassen. Dies ist zwar nicht erforderlich, jedoch
ist es gut zu wissen, welchen Status readyState gerade einnimmt (speziell hinsicht-
lich der Fehlersuche ist eine solche Ausgabe immer ganz geschickt).
K A P I T E L 4132
Bitte beachten Sie, dass das obige Beispiel im Internet Explorer bei einem wiederhol-
ten Klick auf den „Klick mich!“-Button keine neuerliche Anfrage an den Server stellt.
Dieses Problem lösen wir weiter unten.
Dieses Beispiel war ja noch nicht sonderlich aufregend, da uns nicht so recht bewusst
ist, dass wir während der Anfrage ohne weiteres auf der Seite weiterarbeiten können
(was hätten wir neben dem Klicken auf den „Klick mich!“-Button auch tun sollen?).
Interessanter wird die Sache aber dann, wenn es uns bewusst wird, dass ohne Neuladen
der Seite immer Daten vom Server abgefragt werden können.
Problem bei
der Mehrfach-
nutzung eines
Eventhandlers
im IE
Problem bei
der Mehrfach-
nutzung eines
Eventhandlers
im IE
ABBILDUNG 4.4
Unser Beispiel vor und
nach dem Klicken des „Klick
mich!“-Buttons. Wie Sie
sehen, wird das hinzu-
geladene Dokument als
reiner String im Textfeld
ausgegeben. Das Dokument
finden Sie unter dem Namen
ajax01.htm im Kapitel
zum Buch auf der Buch-CD.
A J A X – A S Y N C H R O N U S J AVA S C R I P T A N D X M L 133
Denken wir beispielsweise an ein Chat-System in XHTML: Angenommen, alle einge-
henden Messages von Usern werden in einer Datenbank gespeichert. Sobald ein User
eine Message eingibt, muss diese an den Server geschickt und dort in der Datenbank
gespeichert werden.Würden wir nicht AJAX verwenden, müssten wir nun aus XHTML
ein Formular abschicken, um wieder Kontakt mit dem Server aufzunehmen – unser
Chat wäre für diesen Zeitraum inaktiv. Erst wenn uns der Server das aktualisierte
Dokument wieder zurückgeschickt hat (darin sollte sich dann auch unsere soeben
eingegebene Message wiederfinden lassen), können wir weiter chatten. Zusätzlich
müssten wir in regelmäßigen Abständen den Server abfragen, ob neue Messages ein-
getroffen sind – auch hier ist unser Chat wieder inaktiv. Verwenden wir jedoch AJAX,
sind wir in der Lage, jederzeit weitere Daten (= Messages) vom Server abzufragen,
ohne dabei jedes Mal die Seite neu zu laden.
Problem im Internet Explorer: Mehrfachnutzung eines XMLHttpRequest-Eventhandlers
Leider tritt im Internet Explorer ein Problem mit der Mehrfachnutzung eines Eventhandlers einer
XMLHttpRequest-Instanz auf: Wird eine global definierte XMLHttpRequest-Instanz
mehr als einmal mit der send-Methode dazu aufgefordert, Daten vom Server anzufordern,
geschieht dies leider nicht, da (global definierte) Eventhandler nicht mehr abgearbeitet werden.
Aus diesem Grund muss nach jedem Aufruf der open-Methode der Eventhandler neu zugewie-
sen werden.
Im Firefox und Opera tritt dieses Phänomen nicht auf.
Das oben geschilderte Problem lässt sich relativ einfach lösen, indem der Eventhandler
der XMLHttpRequest-Instanz nach jeder open-Anforderung neu zugewiesen wird:
var myXMLHttpRequest = createRequestObject();
function sendRequest() {
myXMLHttpRequest.open("GET", "testrequest.htm", true);
myXMLHttpRequest.onreadystatechange = handleRequest;
myXMLHttpRequest.send(null);
}
function createRequestObject() {
try { var myRequest = new XMLHttpRequest(); }
catch(error) {
try { var myRequest = new ActiveXObject("MSXML2.XMLHTTP"); }
catch(error) { var myRequest = new ActiveXObject("Microsoft.
XMLHTTP"); }
}
K A P I T E L 4134
return myRequest;
}
function handleRequest() {
document.forms["frmAjax"].elements["msgStatus"].value += "readyState
changed: "+myXMLHttpRequest.readyState+"n";
switch(myXMLHttpRequest.readyState) {
case 0:
case 1:
case 2:
case 3: return;
case 4: showResponse(); return;
}
}
function showResponse() {
document.forms["frmAjax"].elements["msgOut"].value = myXMLHttpRequest.
responseText;
}
Listing 4.8: Alternatives Listing für eine Mehrfachanwendung einer XMLHttpRequest-Instanz, die auch den
Internet Explorer zufriedenstellt. Die entsprechende Datei finden Sie auf der Buch-CD im Buchkapitel unter
dem Namen ajax01_alternativ.htm.
Im Script sehen Sie den Ablauf und folgende Änderungen gegenüber unserer ersten
Variante:
1. Es wird zwar eine globale Variable myXMLHttpRequest angelegt und diese mittels
createRequestObject definiert. Somit liegt die Variable myXMLHttpRequest
global vor.
2. Sobald der User den Button „Klick mich!“ anklickt, wird die Funktion
sendRequest aufgerufen (das ist ebenfalls noch nicht neu – das hatten wir vorher
auch schon). Innerhalb der Funktion wird nun mittels open der globalen Variable
myXMLHttpRequest mitgeteilt, dass eine Anforderung an den Server ansteht.
3. Ebenfalls innerhalb von sendRequest wird in der darauffolgenden Zeile der
Eventhandler für dieses Objekt definiert:
myXMLHttpRequest.onreadystatechange = handleRequest;
A J A X – A S Y N C H R O N U S J AVA S C R I P T A N D X M L 135
Geändert hat sich die Definition des Eventhandlers: Entgegen der ursprünglichen
Variante wird nicht mehr mit einer sogenannten nativen Funktion gearbeitet,
sondern eine Funktion angegeben, die im Falle dieses Events aufgerufen wird (in
unserem Fall ist dies die Funktion handleRequest).
Alles andere ist unverändert geblieben. Wo liegen also die Nachteile dieser Variante
bzw. warum haben wir nicht sofort diese Variante entwickelt? Nun, der Nachteil liegt
einzig und allein in der Performance: In der neuen Variante wird mit jedem send-
Request-Aufruf der Eventhandler der XMLHttpRequest-Instanz neu zugewiesen und
dies benötigt Zeit. Diese Problematik wird uns zwar in dieser Anwendung nicht auf
den Kopf fallen, in zeitkritischen Anwendungen jedoch schon. Leider kommen wir
nicht herum, so zu arbeiten und deshalb mein Tipp: Verwenden Sie die soeben neu
entwickelte Variante, wo der Eventhandler nach jedem Aufruf der open-Methode neu
zugewiesen wird.
Informationen an die Serverseite übermitteln
In vielen Fällen ist es notwendig, diverse Informationen von Clientseite auf Serverseite
zu übermitteln. In XHTML war das sehr einfach: Man musste lediglich ein Formular
bemühen und schon konnte man per GET oder POST Daten (Formularfeldinhalte)
zum Server schicken. Diese Varianten stehen uns in AJAX ebenfalls zur Verfügung,
wobei wir jedoch in beiden Fällen einen Querystring zusammenbasteln müssen, der
danach entweder per GET (als Anhängsel zur aufzurufenden Datei) oder per POST
(im Body der send-Methode) an den Server übergeben wird. Im Übrigen gelten für
den Versand dieselben Regeln wie bei Formularen in XHTML-Dokumenten: Werden
die Daten per GET übertragen, so werden diese an die URL angehängt; werden sie
hingegen per POST versandt, befinden sich die Formulardaten im HTTP-Header.
Gesetzt den Fall, wir programmieren ein kleines Kontaktformular und möchten zwei
Werte an den Server übermitteln: eine E-Mail-Adresse und eine Nachricht. Ein ent-
sprechender Querystring würde dann folgendes Aussehen haben:
var querystring = "Email=uwe.mutz@syne.at&Nachricht=TEST";
bzw. (wenn wir die Werte aus einem Formular mit dem Namen frmKontakt über-
nehmen):
var querystring = "Email="+document.forms["frmKontakt"].
elements["Email"].value+"&Nachricht="+document.forms["frmKontakt"].
elements["Nachricht"].value;
Listing 4.9: Zusammenbasteln eines Querystrings aus gegebenen Formularfeldern „E-Mail“ und „Nach-
richt“
Übergeben wir nun diese Daten an den Server, so müssen wir die zwei Varianten der
Übertragungsmethode wie folgt anweisen:
GET oder POST?GET oder POST?
K A P I T E L 4136
GET-Variante:
contactXMLHttpRequest.open("GET", "includes/kontakt.inc.
php?"+querystring, true);
contactXMLHttpRequest.send(null);
Hierbei ist auf drei Punkte zu achten:
In der open-Methode muss die Übertragungsmethode GET gewählt werden.
An den Namen der am Server aufzurufenden Funktion wird ein Querystring
im Format Feld=Wert angehängt.
Der Body in der send-Methode hat den Wert null.
POST-Variante:
contactXMLHttpRequest.open("POST", "includes/kontakt.inc.php", true);
contactXMLHttpRequest.setRequestHeader("Content-Type","application/x-
www-form-urlencoded");
contactXMLHttpRequest.send(querystring);
Entgegen der GET-Variante wird hier etwas anders gearbeitet:
In der open-Methode muss die Übertragungsmethode POST gewählt werden.
An den Namen der am Server aufzurufenden Funktion wird nichts ange
hängt.
Es muss dem Server mittels der setRequestHeader-Methode mitgeteilt
werden, dass die gesendeten Daten Formulardaten sind – dies geschieht durch
die Definition des Content-Type als application/x-www-form-urlencoded.
Der Body in der send-Methode beinhaltet den Querystring im Format
Feld=Wert.
Auf zu einem konkreten Beispiel, wenn wir schon von einem Kontaktformular spre-
chen:
u
1.
2.
3.
u
1.
2.
3.
4.
A J A X – A S Y N C H R O N U S J AVA S C R I P T A N D X M L 137
Ziel ist es, per AJAX ein serverseitiges Script aufzurufen, das eine E-Mail an uwe.mutz@
syne.at schickt, worin der Name des Absenders und deren Nachricht zu finden sind.
Der HTML-Part ist relativ unspektakulär – ein paar DIVs, ein Formular mit zwei
Feldern und zwei Buttons:
...
<script language="javascript" type="text/javascript" src="js/common.inc.
js"></script>
<script language="javascript" type="text/javascript" src="js/kontakt.
inc.js"></script>
...
<form name="frmKontakt" id="frmKontakt" action="">
<div id="msgOut"></div>
<div class="label">Ihre Email-Adresse:</div>
<div class="field"><input type="text" name="Email" id="Email" /></div>
<div class="cleaner"></div>
<div class="label">Ihre Nachricht an mich:</div>
<div class="field"><textarea name="Nachricht" cols="50" rows="10"
id="Nachricht"></textarea></div>
<div class="cleaner"></div>
<div class="button">
<input type="button" name="submitIt" id="submitIt" value="Abschicken
E-Mails versen-
den mit AJAX
und PHP
E-Mails versen-
den mit AJAX
und PHP
ABBILDUNG 4.5
Ein einfaches Kontakt-
formular für die Eingabe
von E-Mail-Adresse und
Nachricht. Wir können
wählen, ob die Daten per
GET oder POST übertragen
werden.
K A P I T E L 4138
(GET)" onclick="sendContact('GET');" />
<input type="button" name="submitIt2" id="submitIt2" value="Abschicken
(POST)" onclick="sendContact('POST');" />
</div>
</form>
...
Listing 4.10: Wir finden ein (noch) leeres <div id="msgOut"> zur Ausgabe der Statusmeldung nach
dem Versenden der E-Mail sowie zwei Buttons, die jeweils dieselbe Funktion sendContact mit zwei
unterschiedlichen Parametern aufrufen.
Der JavaScript-Code ist komplett in zwei externe Dateien namens common.inc.js
und kontakt.inc.js ausgelagert worden, um den XHTML-Code übersichtlicher zu
halten bzw. den JavaScript-Code für weitere Beispiele einfach verknüpfen zu können.
Das derzeit noch leere <div id="msgOut"> wird im Weiteren dafür verwendet, dass
wir eine Meldung nach dem Versenden der E-Mail ausgeben, ob der Versand erfolg-
reich oder eben nicht erfolgreich war.
Des Weiteren sehen Sie, dass wir eine Funktion sendContact in Verwendung haben,
an die über einen Parameter übergeben wird, mit welcher Methode wir die Daten an
den Server übergeben werden: GET oder POST.
Die Datei common.inc.js beinhaltet lediglich die Auswahl des korrekten XMLHttp-
Request-Objekts aus Listing 4.4. In kontakt.inc.js sind die für das Beispiel spezifischen
Codes abgelegt, worin zunächst einmal eine Variable für die Instanz des XMLHttp-
Request-Objekts angelegt wird:
var contactXMLHttpRequest;
function sendContact(method) {
contactXMLHttpRequest = createRequestObject();
contactXMLHttpRequest.onreadystatechange = handleRequestContact;
var querystring = "Email="+document.forms["frmKontakt"].
elements["Email"].value+"&Nachricht="+document.forms["frmKontakt"].
elements["Nachricht"].value+"&Methode="+method;
if(method.toLowerCase()=="get") {
contactXMLHttpRequest.open("GET", "includes/kontakt.inc.
php?"+querystring, true);
contactXMLHttpRequest.send(null);
}
else {
contactXMLHttpRequest.open("POST", "includes/kontakt.inc.php", true);
A J A X – A S Y N C H R O N U S J AVA S C R I P T A N D X M L 139
contactXMLHttpRequest.setRequestHeader("Content-Type","application/
x-www-form-urlencoded");
contactXMLHttpRequest.send(querystring);
}
}
function showResponse2() {
document.getElementById("msgOut").innerHTML = contactXMLHttpRequest.
responseText;
}
function handleRequestContact() {
switch(contactXMLHttpRequest.readyState) {
case 0:
case 1:
case 2:
case 3: return;
case 4: showResponse2(); return;
}
}
Listing 4.11: Code der Datei kontakt.inc.js
Die Funktion sendContact mit dem Parameter method dient dazu, je nach geklicktem
Button die Nachricht entweder per GET oder per POST zu versenden (dies geschieht in
der if-Anweisung). Bevor eine Auswahl für GET oder POST geschieht, wird erst einmal
dem XMLHttpRequest-Objekt ein Eventhandler zugewiesen. (dieser ist ebenfalls schon
bekannt – siehe Listing 4.8 in leicht abgeänderter Form: Aufruf von showResponse2
anstatt showResponse, da wir eine andere Funktion für den Fall der abgeschlossenen
Übertragung verwenden.) Danach werden wie oben besprochen im Fall von GET die
Formularfeldwerte an die URL der am Server aufzurufenden Datei angehängt und der
Body in der send-Methode leergelassen. Bei POST wird an die URL nichts angehängt,
dafür werden die Formularfeldwerte in den Body der send-Anweisung gegeben. Bei
POST muss ebenfalls noch angegeben werden, dass es sich bei den Daten um Formu-
larfelder handelt (Content-Type=application/x-www-form-urlencoded).
Um dem User nach dem Versenden der E-Mail auch eine Erfolgs- (oder Misserfolgs-
)Meldung auszugeben, wird in der Funktion showResponse2 auf das weiter oben
angesprochene <div id="msgOut"> zugegriffen und dort hinein (innerHTML)
geschrieben, was uns die (serverseitige) Datei kontakt.inc.php zurückliefert. Also wer-
fen wir mal einen Blick auf diese Datei:
K A P I T E L 4140
<?php
function create_email_header($name, $value) {
return ($name && $value) ? "$name: $valuern" : "";
}
function sendContact() {
$success = "";
if(count($_REQUEST)>0) {
$REQUESTdata = $_REQUEST;
$msg = "Kontaktaufnahme auf flashphpajax.beelzebuben.at.nDie
eingegebenen Daten waren:nn";
foreach($REQUESTdata as $itm=>$val) { $msg.= "t$itm: $valn"; }
$mailto = "uwe.mutz@syne.at";
$mailfrom = "autosender@syne.at";
$headers = «»;
$cc_email = $REQUESTdata[«Email»];
$bcc_email = «uwe.mutz@gmx.at»;
$headers .= create_email_header(«Cc», $cc_email);
$headers .= create_email_header(«Bcc», $bcc_email);
$headers .= create_email_header(«From», $mailfrom);
if(!mail($mailto, «- Kontaktaufnahme auf flashphpajax.beelzebuben.at
-», $msg, $headers)) { $success = $msg; }
else { $success = «OK»; }
}
return $success;
}
$msgOut = sendContact();
if($msgOut=="OK") { echo('<p class="success">Ihre Anfrage wurde
ERFOLGREICH an uns versandt.</p>'); }
else { echo('<p class="error">Ihre Anfrage wurde NICHT ERFOLGREICH an
uns versandt.</p>'); }
?>
Listing 4.12: Code der Datei kontakt.inc.php, die rein serverseitig liegt und der User nie zu Gesicht bekommt
A J A X – A S Y N C H R O N U S J AVA S C R I P T A N D X M L 141
Wird diese Datei serverseitig aufgerufen, wird nach dem Aufruf von sendContact()
(dies geschieht im unteren Teil des Scripts mittels $msgOut = sendContact();)
zunächst einmal überprüft, ob an die Datei Formulardaten gleich welcher Art überge-
ben wurden:
...
if(count($_REQUEST)>0) {
...
Der Nachrichtentext wird in der Variablen $msg gespeichert, worin zunächst ein kur-
zer Infotext geschrieben wird:
$msg = "Kontaktaufnahme auf flashphpajax.beelzebuben.at.nDie
eingegebenen Daten waren:nn";
Die weiteren Inhalte werden über eine foreach-Schleife aus den übergebenen Formu-
larfelddaten gelesen und zeilenweise in den Text geschrieben.
Die Funktion create_email_header dient dazu, die Header-Informationen für eine
E-Mail korrekt zu formatieren (dieses Script ist schon quasi Standard – vielen Dank
an www.php.net). Sollte zu guter Letzt das Abschicken der E-Mail mittels der mail-
Funktion geklappt haben, wird in $success der Wert „OK“ geschrieben, ansonsten
der Inhalt der E-Mail (um etwaige Tests durchführen zu können). Selbstverständlich
könnte anstatt eines Textes auch einfach der Rückgabewert (true oder false) von
mail() geschrieben werden – in diesem Fall hätte man jedoch keine Möglichkeit, zu
überprüfen, ob der Nachrichtentext überhaupt korrekt geschrieben wurde. Der User
selbst erhält die E-Mail in CC ($cc_email = $REQUESTdata["Email"];).
Ganz unten im Script wird zuletzt noch überprüft,ob in $msg derWert„OK“ steht (und
somit die E-Mail erfolgreich versandt wurde) – wenn ja, wird in das PHP-Dokument
per echo der XHTML-Code <p class="success">Ihre Anfrage wurde ERFOLG-
REICH an uns versandt.</p> geschrieben, ansonsten <p class="error">Ihre
Anfrage wurde NICHT ERFOLGREICH an uns versandt.</p>. Genau dieser
XHTML-Code stellt also den Wert dar, der von AJAX vom Server angefordert und in
dem Tag <div id="msgOut"> ausgegeben wird.
Wenn ich also eine E-Mail an mich selbst schicke, sieht unser Beispiel wie folgt aus:
K A P I T E L 4142
Die Ergebnis-Mails (einmal per GET, einmal per POST verschickt) sehen Sie in den
nachfolgenden Abbildungen (mit Umlauten gibt’s so kleine Probleme, da wir nicht den
korrekten Zeichensatz definiert haben):
ABBILDUNG 4.6
AJAX in Verbindung mit
einem geeigneten PHP-Script
verschickt E-Mails.
ABBILDUNG 4.7
Die empfangenen E-Mails
– hat also super funktioniert!
Um den Code so einfach wie möglich zu halten, habe ich bewusst auf Formatierungen
der E-Mail verzichtet – selbstverständlich könnte die E-Mail auch als HTML-E-Mail
verschickt werden. PHP macht auf Serverseite keine Unterscheidung, ob die Seite nur
serverseitig aufgerufen wird oder doch als XHTML-Dokument zum User übertragen
A J A X – A S Y N C H R O N U S J AVA S C R I P T A N D X M L 143
wird. Ob nun AJAX die Seite anfordert oder der User selbst (beispielsweise durch einen
Klick auf einen Link), spielt keine Rolle.
Darstellen des Ladezustands
In letzter Zeit findet man auf AJAX-basierten Websites immer öfter eine Anzeige des
Ladezustands, da der User im Fall von AJAX nichts davon mitbekommt, dass Daten an
den Server übertragen werden – im Gegensatz zu Standard-XHTML-Anwendungen,
wo der weitere Ablauf der Site blockiert wird. Deshalb ist es als Entwickler nicht unge-
schickt, dem User eine entsprechende Meldung am Bildschirm auszugeben. Ideal dafür
geeignet sind die verschiedenen Stati der readyState-Eigenschaft, denn solange rea-
dyState nicht den Wert 4 erreicht hat, ist die Übertragung der Daten noch im Gange.
Erweitern wir also unser zuvor entwickeltes Kontaktformular um eine Grafik, die
immer dann eingeblendet wird, wenn eine aktive Übertragung stattfindet. Dies sollte
wie folgt am Bildschirm des Users aussehen:
ABBILDUNG 4.8
Verwenden eines
„Abdunklers“, um dem User
eine gerade stattfindende
Übertragung zu verdeut-
lichen
Abdunkler oder Sanduhr?
An dieser Stelle kommt wieder Usability ins Spiel: Wann soll man bei AJAX-Anwendungen einen
Abdunkler, wann eine Sanduhr (oder etwas Ähnliches) verwenden? Nun, Abdunkler sollten immer
dann zum Einsatz kommen, wenn dem User verdeutlicht werden soll, dass er „jetzt bitte einen
Moment warten“ soll. Eine Sanduhr als Grafik neben beispielsweise dem Abschicken-Button hinge-
gen soll nur einen laufenden Prozess verdeutlichen – der User kann aber ungestört weiterarbeiten.
Bitte sehen Sie davon ab, den Cursor in eine Sanduhr zu „verwandeln“, denn das hätte zur Folge,
dass der User meint, er dürfe nun gar nichts mehr tun – da könnten Sie den Abdunkler auch
gleich verwenden ;=).
K A P I T E L 4144
Um den Abdunkler in die Realität umzusetzen, bediene ich mich eines teiltranspa-
renten Bilds in Form einer PNG-Datei (Schwarz mit 70% Deckkraft) sowie eines vor-
erst unsichtbaren Layers namens abdunkler:
div#abdunkler {
visibility:hidden;
text-transform:uppercase;
position:absolute;
width:100%;
height:100%;
padding:10px;
background-image:url(../../images_standard/abdunkler70.png);
background-repeat:repeat;
font-size:16px;
color:white;
}
Listing 4.13: CSS-Definition des Layers
<div id="abdunkler">Bitte einen Moment Geduld - Ihre Anfrage wird gerade
an uns weitergeleitet...</div>
Listing 4.14: XHTML-Code des Layers mit einem entsprechenden Mitteilungstext an den User. Dieser Layer
wird vorerst durch die obige CSS-Definition ausgeblendet.
Um diesen Layer während der Übertragung anzeigen zu lassen, verwenden wir den
Eventhandler des XMLHttpRequest-Objekts und modifizieren ihn ein wenig:
function handleRequestContact() {
switch(contactXMLHttpRequest.readyState) {
case 0:
case 1: return;
case 2: showHideDiv("abdunkler",true); return;
case 3: return;
case 4:
showHideDiv("abdunkler",false);
showResponse2();
return;
}
}
Listing 4.15: Die adaptierte Eventhandler-Funktion
A J A X – A S Y N C H R O N U S J AVA S C R I P T A N D X M L 145
Anstatt im Fall 2 (die send-Methode wurde aufgerufen) einfach nur die Funktion mit
einem return abzubrechen (die Fälle 0 und 1 tun dies indes immer noch), rufen wir
eine Funktion auf, die über die Funktion showHideDiv den Abdunkler-Layer einblen-
det:
function showHideDiv(divname,isVisible) {
if(isVisible) { document.getElementById(divname).style.visibility =
"visible"; }
else { document.getElementById(divname).style.visibility = "hidden"; }
}
Listing 4.16: Die Funktion showHideDiv blendet – je nach Wert der Variable isVisible – einen über die
Variable divname definierten Layer ein oder aus.
Dieser Layer wird im Fall von readyState==4 über dieselbe Funktion wieder ausge-
blendet.
In unserem Fall wäre es genauso möglich, bereits bei readyState==1 (die open-
Methode wurde aufgerufen) den Layer einzublenden, da open und danach send in
unserem Fall durch dieselbe Funktion sendContact aufgerufen werden und es somit
keine Unterbrechung zwischen open und send gibt.
Bevor wir in den Workshops zu komplexeren Themen übergehen, werden wir einige
Anwendungen für AJAX entwickeln, damit Sie einen tieferen Einblick gewinnen kön-
nen.
Anwendung 1 – Mini-Website
In diesem Beispiel werden wir eine Mini-Website entwickeln, wo sich die Hauptseite
nicht ändert, sondern nur per AJAX Dokumente hinzugeladen werden.
Wie funktioniert eine Website bisher:
Variante 1: Es wird eine Frame-Site verwendet.
Diese Variante ist mittlerweile zwar verpönt (und in XHTML Strict auch nicht
mehr standardisiert), findet in manchen Fällen aber immer noch Verwendung.
Durch Klick auf einen Link wird in einen Frame ein neues Dokument geladen.
Nachteilig ist, dass die Site so lange nicht verwendbar ist, solange dieses Dokument
nicht geladen ist.
Variante 2: Es wird ein IFrame verwendet.
Die Möglichkeit der IFrames gibt es zwar auch schon länger, jedoch ist die
Verwendung der IFrames erst in den letzten Jahren so wirklich in Mode gekommen,
da alle gängigen Browser mittlerweile IFrames unterstützen. IFrames funktionieren
wie Frames, jedoch mit dem Unterschied, dass kein Frameset benötigt wird – ein
IFrame wird wie eine Grafik direkt im XHTML-Code platziert.
u
u
K A P I T E L 4146
Variante 3: Für jedes Inhaltselement (Navigationspunkt) wird die Site komplett
neu geladen.
Dies ist die Standardvariante, die auch vom XHTML-Standard gutgeheißen wird.
Nachteilig ist, dass immer wiederkehrende Elemente permanent neu geladen
werden und sich so die Ladezeit der Site erhöht. Zwar werden Grafiken im Cache
gespeichert und müssen so nicht neu vom Server angefordert werden, jedoch gilt
dies nicht für Texte etc. Somit fällt ein nicht zu geringer Brocken an Daten an, die
mit jedem Klick redundant übertragen werden.
Variante 4: Ein und dieselbe Seite wird serverseitig mit geänderten Inhalten
gefüllt.
Typischerweise arbeiten Content Management Systeme (CMS) auf diese Weise: Es
existiert lediglich eine Indexseite mit integrierten Platzhaltern. Diese Platzhalter
werden serverseitig durch geeignete (PHP oder ähnliche) Programmierung mit
Inhalten gefüllt, die vorzugsweise aus einer Datenbank generiert werden. Nachteilig
ist wie in Variante 3 die Tatsache, dass die Seite immer wieder neu geladen wird, da
ja die Inhalte auf Serverseite generiert werden.
Der Vorteil unseres Systems wird sein, dass wir unsere Seite nie neu laden müssen,
sondern nur geänderte Inhalte vom Server auf Anfrage geliefert bekommen, die wir
dann mithilfe des DOM an vorgegebene Stellen im Dokument (Platzhalter) schreiben
werden.
Sehen wir es uns einfach mal an.
u
u
ABBILDUNG 4.9
Eine einfache Website
mit vier Links und einem
Content-Bereich. Die
Gestaltung haben wir erst
mal außer Acht gelassen,
um nicht den Fokus auf das
Wesentliche zu verlieren.
A J A X – A S Y N C H R O N U S J AVA S C R I P T A N D X M L 147
Wenn wir kurz zusammenfassen, benötigen wir folgende Dokumente:
1. index.htm: Die „Startseite“ oder „Homepage“ unserer Mini-Website. Hierin
befinden sich die Links sowie ein Container (ein <div>) für die Darstellung der
Inhalte.
2. home.htm: Der Begrüßungstext, der unseren User auf der Website willkommen
heißt. Dieses Dokument wird als Erstes automatisch in den leeren Container
geladen. An diesem Dokument werden wir lernen, wie man nach erfolgtem Laden
der index.htm ein Dokument per AJAX in den leeren Container lädt.
3. ueberuns.htm: Eine statische Seite ohne spezielle Features.Sie wird uns gute Dienste
leisten, indem wir lernen, wie man ein statisches Dokument auf Klick lädt.
4. kontakt.php: Entgegen ueberuns.htm ist dies eine dynamische Seite mit der
Möglichkeit des Versendens einer Nachricht an einen gegebenen Empfänger. An
ihr zeigen wir auf, wie ein dynamisches Dokument per AJAX geladen und von
sich aus wiederum AJAX zum Versenden von Nachrichten funktioniert. Das
Dokument kontakt.php ist im Wesentlichen mit dem Dokument vom letzten
Beispiel identisch.
5. links.php: Ebenfalls ein dynamisches Dokument – in diesem Fall wird eine
Datenbank abgefragt und die Ergebnisse (Links) werden in Form einer Liste
wiedergegeben.
Zunächst kümmern wir uns um unser Gerüst index.htm:
...
<div id="navigation">
<div class="navitem"><a href="#" id="home">Home</a></div>
<div class="navitem"><a href="#" id="ueberuns">&Uuml;ber uns</a></div>
<div class="navitem"><a href="#" id="kontakt">Kontakt</a></div>
<div class="navitem"><a href="#" id="links">Links</a></div>
<div class="cleaner"></div>
</div>
<div id="content"></div>
...
Listing 4.17: Auszug aus dem Listing der Datei index.htm unserer Mini-Website (wie üblich zu finden auf
der beiliegenden Buch-CD)
In diesem Script existiert nichts Aufregendes – einzig das (noch) leere <div
id="content"> für das nachträgliche Einfügen von Inhalt. Die vier Navigationsele-
mente sind bewusst ohne onclick-Ereignis definiert, da wir in diesem Beispiel auch
K A P I T E L 4148
sehen werden, wie man im Nachhinein (nämlich nach dem vollständigen Laden des
Dokuments) einem gegebenen Element ein Ereignis zuweisen kann. Des Weiteren hat
diese Vorgehensweise den Vorteil, dass der User erst dann auf einen Link klicken kann,
wenn die Site vollständig geladen ist (was man ihm aus Usability-Gründen eventuell
mitteilen sollte …). Das Element der Klasse cleaner dient dazu, dass die float-
Eigenschaft der Elemente der Klasse navitem wieder beendet wird. Ein Blick auf die
CSS-Definition verdeutlicht dies:
div.navitem {
float:left;
margin-right:20px;
}
div.cleaner {
clear:both;
}
Listing 4.18: CSS-Definition für <div> der Klassen navitem und cleaner
Die Eigenschaft float:left bewirkt, dass DIV-Tags nebeneinander angeordnet wer-
den (und zwar mit dem Platz, den sie benötigen – es sei denn, Sie geben eine Breite
an), clear:both bewirkt, dass eine float-Eigenschaft (egal ob left oder right)
wieder eliminiert wird. Wir benötigen einen solchen „Cleaner“, damit das darauffol-
gende Element (bei uns ist das das DIV mit der id=content) nicht auch rechts neben
den Navigationselementen platziert wird. Falls Sie mehr über CSS erfahren möchten,
so kann ich Ihnen die einschlägige Literatur aus dem Verlag Addison-Wesley nur ans
Herz legen.
Nun müssen wir uns überlegen, wie den Links die onclick-Ereignisse zugewiesen
werden können. Wie oben erwähnt, wollen wir eine Zuweisung erst nach dem voll-
ständigen Laden des Dokuments. Hierzu bedienen wir uns des onload-Ereignisses
des window-Objekts:
window.onload = init;
function init() {
navigateTo("home.htm"); //Homepage laden
document.getElementById("home").onclick = function() {
navigateTo("home.htm"); }
document.getElementById("kontakt").onclick = function() {
navigateTo("kontakt.htm"); }
document.getElementById("ueberuns").onclick = function() {
navigateTo("ueberuns.htm"); }
A J A X – A S Y N C H R O N U S J AVA S C R I P T A N D X M L 149
document.getElementById("links").onclick = function() {
navigateTo("links.php"); }
}
Listing 4.19: Wir nutzen das onload-Ereignis des window-Objekts, um nach dem vollständigen Laden
des Dokuments im Browser des Users den Links ein onclick-Ereignis zuzuweisen. Des Weiteren wird als
„Homepage“ das Dokument home.htm geladen.
Wir gehen den ausführlichen Weg und weisen dem Ereignis onload vom window-
Objekt zunächst eine Funktion init zu und definieren diese Funktion im nächsten
Schritt. Innerhalb von init wird zunächst eine Funktion navigateTo mit dem Para-
meter home.htm aufgerufen – diese Funktion wird im Weiteren dafür sorgen, dass ein
Dokument per AJAX in den Container content geladen wird. Genau diese Funktion
verwenden wir auch in den onclick-Ereignissen der einzelnen Links. Wenn wir einen
solchen Eventhandler genauer betrachten, finden wir Folgendes:
document.getElementById("home").onclick = function() { navigateTo("home.
htm"); }
Zunächst wird über die Methode getElementById auf ein benanntes Element (hier:
"home") zugegriffen und diejenige Methode definiert (hier: onclick), die wir benö-
tigen. Danach wird dieser Methode eine Funktion zugewiesen, die beim Aufruf des
Ereignisses abgearbeitet werden muss. In unserem Fall sorgt diese Funktion lediglich
dafür, dass eine weitere Funktion namens navigateTo aufgerufen wird. Kommen wir
also zu navigateTo:
function navigateTo(URL) {
myXMLHttpRequest = createRequestObject();
myXMLHttpRequest.onreadystatechange = handleRequest;
myXMLHttpRequest.open("GET", URL, true);
myXMLHttpRequest.send(null);
}
Listing 4.20: Listing der Funktion navigateTo, die die Schnittstelle zu AJAX bildet
Der Inhalt der Funktion ist aus den vorigen Beispielen bekannt: Es wird eine Ins-
tanz des XMLHttpRequest-Objekts gebildet. (Die Funktion createRequestObject
wurde im Listing 4.4 ausführlich besprochen; in diesem Beispiel ist sie in der extern
verknüpften Datei common.inc.js im Verzeichnis js des aktuellen Kapitels abgelegt,
sollten Sie die Funktion auf der CD suchen.) Danach wird ein Request-Handler hand-
leRequest definiert (dessen Funktionalität kennen wir aus Listing 4.5). Mit open
wird eine Anfrage für die per URL definierte Datei an den Server geöffnet und mit send
abgeschickt.
function handleRequest() {
switch(myXMLHttpRequest.readyState) {
K A P I T E L 4150
case 0:
case 1:
case 2:
case 3: return;
case 4: showResponse(); return;
}
}
function showResponse() {
var myContent = document.getElementById("content");
myContent.innerHTML = myXMLHttpRequest.responseText;
}
Listing 4.21: Der Eventhandler handleRequest ruft nach der vollständigen Übertragung der Anfrage
eine Funktion showResponse auf.
Nachdem die Anfrage per send abgeschickt und die Übertragung (readyState==4)
vollständig abgeschlossen wurde, wird mithilfe von showResponse auf das Element
content zugegriffen und dessen Inhalt über die Anweisung innerHTML auf den
zurückgegebenen Text (responseText) der XMLHttpRequest-Instanz gesetzt – fertig.
DOM und innerHTML
Wie Sie sehen, habe ich im letzten Beispiel die Methode innerHTML verwendet, um das
„Innere“ eines XHTML-Elements zu setzen – diese Methode ist jedoch nicht im Standard des
W3C enthalten. Jedoch hat sich diese ursprünglich von Microsoft eingeführte Methode mit-
tlerweile in allen Browsern durchgesetzt, sodass man sie als Quasi-Standard ansehen kann. Aus
dem Kapitel zum DOM kennen Sie jedoch auch Varianten, ohne diese – zugegebenermaßen sehr
einfache – Methode zu arbeiten.
So weit, so gut. Dass wir natürlich ganz zu Beginn eine Variable für die XMLHttpRe-
quest-Instanz anlegen mussten, versteht sich von selbst. Das gesamte Script dieser
Datei finden Sie auf der Buch-CD im Verzeichnis Miniwebsite im Verzeichnis zum
Kapitel.
Nachdem unsere Navigation nun funktioniert, wenden wir uns den einzelnen Web-
dokumenten zu – zunächst hier einmal die statischen Dokumente:
<h2>Home...</h2>
<p>Willkommen auf der Miniwebsite zum Testen von AJAX!</p>
Listing 4.22: Quellcode von home.htm
<h2>&Uuml;ber uns...</h2>
<p>Ein bisschen BlaBla, oder auch nicht...?!</p>
Listing 4.23: Quellcode von ueberuns.htm
A J A X – A S Y N C H R O N U S J AVA S C R I P T A N D X M L 151
Sollten Sie sich nun die Frage stellen, ob dieser Quellcode nur ein Auszug ist oder
schon alles war, dann seien Sie versichert: Das ist der gesamte Quellcode der beiden
Dokumente! Warum? Ganz einfach: Wir laden diese Daten in ein bereits bestehendes
Webdokument (index.htm) hinzu – darin befinden sich sämtliche Tags zum Seiten-
aufbau (<html>, <head>, <body> etc.) und bilden somit ein gültiges Webdokument.
Die gute Nachricht ist, dass Sie in Dreamweaver Dokumente mit nur einem Teilcode
eines gültigen Webdokuments ebenso bearbeiten können, als wäre es ein vollständiges
Webdokument:
Da der Dreamweaver eines der gängigsten Tools für das Arbeiten mit Webdokumenten
ist, habe auch ich mich in diesem Buch für dieses Tool entschieden.
Das Nachladen eines statischen Dokuments ist also denkbar einfach – per AJAX das
Dokument anfordern und den responseText einem Container zuweisen.
Im Fall von dynamischen Dokumenten würden wir erwarten, dass sich die Sache viel-
leicht doch etwas komplizierter darstellt. Deshalb werfen wir doch mal einen Blick auf
ein solches: links.php:
<link href="css/common.inc.css" rel="stylesheet" type="text/css">
<h2>Links...</h2>
<?php require("includes/links.inc.php"); ?>
Listing 4.24: Auch die Einbindung eines dynamischen Dokuments ist nichts anderes als das Einbinden eines
statischen Dokuments, da der PHP-Code ja bereits auf Serverseite verarbeitet wird.
Grundsätzlich ist alles gleich wie beim statischen Dokument, da der PHP-Code ser-
verseitig in XHTML-Code umgewandelt wird. Um das Dokument übersichtlicher
ABBILDUNG 4.10
Bearbeiten eines nicht voll-
ständigen Webdokuments
in Dreamweaver – alles wie
gehabt
K A P I T E L 4152
zu gestalten, habe ich die eigentliche PHP-Funktionalität in eine Datei links.inc.php
verlegt, die ich per require anfordere (sollte Ihnen das unbekannt vorkommen, so
schlagen Sie bitte im Grundlagenkapitel zur Programmierung nach):
<?php
function showLinks() {
if(!$conn = mysql_connect("mysql.syneweb.com","usr_flashphpajax","12
3passwort")) { die(‚<p>Der Datenbankserver konnte nicht kontaktiert
werden. ERROR='.mysql_error()); }
if(!$db = mysql_select_db("db_flashphpajax")) { die(‚<p>Die Datenbank
konnte nicht ausgewaehlt werden. ERROR='.mysql_error()); }
$sql = "SELECT * FROM tbl_04links WHERE(bitP_chk_aktiv=1)";
$query = mysql_query($sql);
$returner = ‚';
if(mysql_num_rows($query)>0) {
$returner.= '<ul>';
while($data = mysql_fetch_array($query)) { $returner.= '<li><a
href="'.$data["vcP_URL"].'" target="_blank">'.$data["vcP_
Bezeichnung"].'</a></li>';
}
$returner.= '</ul>';
}
else { $returner.= '<p class="info">Keine Links vorhanden.</p>'; }
return $returner;
}
echo(showLinks());
?>
Listing 4.25: Der vollständige Code der Datei links.inc.php, in der sich die gesamte PHP-Funktionalität zum
Generieren des XHTML-Codes befindet
Ich verwende in solchen Fällen gerne eine Funktion, die mir eine Variable (hier:
$returner) mit dem generierten XHTML-Code zurückgibt. Alternativ wäre man
auch ohne Funktion und anschließendem Funktionsaufruf ausgekommen.
In der untersten Zeile wird also die Funktion showLinks aufgerufen – der von ihr
zurückgelieferte Wert wird danach per echo ausgegeben. Die Funktion selbst nimmt
zunächst Kontakt mit einem Datenbankserver auf, danach wird die Datenbank ausge-
wählt. Sollte einer der beiden Aufrufe nicht funktionieren, wird mittels die abgebro-
chen und eine entsprechende Fehlermeldung ausgegeben. Sollte alles geklappt haben,
wird für den Zugriff auf die Tabelle tbl_04links ein entsprechendes SQL-Statement
erzeugt. Die Tabelle selbst besteht aus vier Feldern:
A J A X – A S Y N C H R O N U S J AVA S C R I P T A N D X M L 153
Feldname Typ Extras Beschreibung
idP_Links int(11) auto-increment,Primary
Key,not null
Dieses Feld stellt die ID der Tabelle
dar – dementsprechend verwende
ich ein auto-increment und definiere
es als Primärschlüssel.
vcP_Bezeichnung varchar(128) not null Linktext wie etwa„Addison-Wesley“
für die URL„http://www.addison-
wesley.de“
vcP_URL varchar(128) not null URL zur Website (beispielsweise
„http://www.addison-wesley.de“)
bitP_chk_aktiv tinyint(1) not null,Standardwert=1 Kennzeichnet,ob der Link auf der
Website ausgegeben werden soll
Tabelle 4.5: Tabellenstruktur der verwendeten Tabelle tbl_04links
Wir fragen nur Links ab, die die Kennzeichnung bitP_chk_aktiv=1 aufweisen.
Danach wird das SQL-Statement abgesetzt und das Ergebnis der Abfrage in der Vari-
ablen $query gespeichert. Sollten mehr als null Zeilen zurückgeliefert worden sein,
wird ein <ul> in $returner hinzugefügt. In einer while-Schleife geht man zeilen-
weise das Ergebnis durch und generiert in $returner einen XHTML-Code in Form
von <li><a href="URL" target="_blank">LINKTEXT</a></li>. Nachdem
die while-Schleife vollständig durchgelaufen ist, wird ein abschließendes </ul> an
$returner angehängt und die Variable $returner an den Aufrufer zurückgeliefert
(= Rückgabewert der Funktion). Sollte unsere Abfrage keine Daten zurückgeliefert
haben, so wird der Text <p class="info">Keine Links vorhanden.</p> an den
Aufrufer zurückgeschickt.
In unserem Fall liefert das SQL-Statement fünf Links zurück, die per echo in das
Dokument geschrieben werden:
ABBILDUNG 4.11
AJAX fordert ein PHP-
Dokument an, das auf
Serverseite eine Datenbank
ausliest und das Ergebnis
per echo in das Dokument
schreibt.
K A P I T E L 4154
Wie zu erwarten war, ist auch das Anfordern von PHP-basierten Dokumenten kein
Problem, da diese zunächst am Server abgearbeitet werden und somit das Rückgabe-
dokument in jedem Fall reinen XHTML-Code beinhaltet.
Wenden wir uns also der schwierigsten Aufgabe zu: einem Dokument (kontakt.htm),
das per AJAX eingebunden wird und von sich aus wieder per AJAX eine Anfrage an
den Server stellt. Zunächst einmal nachfolgend der Code dieses Dokuments:
<link href="css/common.inc.css" rel="stylesheet" type="text/css">
<h2>Kontakt...</h2>
<p>Hier ein Kontaktformular, damit Sie mir auch eine Email schreiben
k&ouml;nnen:</p>
<form name="frmKontakt" id="frmKontakt" method="post" action="">
<div id="msgOut"></div>
<div class="label">Ihre Email-Adresse:</div>
<div class="field"><input type="text" name="Email" id="Email" /></div>
<div class="cleaner"></div>
<div class="label">Ihre Nachricht an mich:</div>
<div class="field"><textarea name="Nachricht" cols="50" rows="10"
id="Nachricht"></textarea></div>
<div class="cleaner"></div>
<div class="button"><input type="button" name="submitIt" id="submitIt"
value="Abschicken" onclick="sendContact();" /></div>
<div><textarea name="msgStatus" rows="10" id="msgStatus">Status:n</
textarea>
</div>
</form>
Listing 4.26: Der XHTML-Code bietet keine Überraschungen: Es wird ein Formular mit zwei Feldern und
einem Button verwendet, welche allesamt in DIV-Tags eingebettet sind.
In Listing 4.10 wurde ein sehr ähnliches Beispiel gezeigt. Das derzeit noch leere <div
id="msgOut"> verwenden wir wie üblich dafür, dass wir eine Statusmeldung an den
User ausgeben. Sobald der Button „Abschicken“ geklickt wird, wird die Funktion
sendContact aufgerufen. Fraglich ist jedoch, wo sich diese Funktion befindet, da in
der Datei kontakt.htm keinerlei Hinweis auf eine JavaScript-Funktion gefunden wer-
den kann. Wenn wir jedoch die Datei index.htm genauer betrachten, finden wir in ihr
einen Verweis auf eine JavaScript-Datei kontakt.inc.js:
<script language="javascript" type="text/javascript" src="js/kontakt.
inc.js"></script>
Listing 4.27: Die verknüpfte Datei kontakt.inc.js befindet sich in der Datei index.htm und nicht in
kontakt.htm.
A J A X – A S Y N C H R O N U S J AVA S C R I P T A N D X M L 155
An dieser Stelle möchte ich Sie bewusst auf einen Punkt hinweisen, der bei der Ent-
wicklung erster AJAX-Anwendungen sehr häufig auftritt: das Abfragen von Doku-
menten mit inkludierten JavaScript-Anweisungen, die per responseText einem
Dokument hinzugefügt werden.
Einschub: AJAX und JavaScript
Beim Einfügen von XHTML-basiertem Code, der per responseText von einer
XMLHttpRequest-Instanz bereitgestellt wurde, wird der Code als reiner Text einem
bereits bestehenden Element hinzugefügt. Sollte dieser XHTML-Code JavaScript bein-
halten (was für manche Anwendungen erwünscht sein kann), so wird dieser nicht als
JavaScript, sondern als normaler Text interpretiert.
Ein Ausweg aus dieser Misere ist die Verwendung der eval-Funktion: Sie weist den
Interpreter an, einen String so zu verarbeiten, als wäre er ein echter JavaScript-Code.
Nehmen wir den einfachen Fall, dass per AJAX ein Dokument simplejs.js angefor-
dert wird, das reinen JavaScript-Code (und nicht mehr!) beinhaltet:
alert("Ein erster Test");
Das Dokument besteht also aus nur einer einzigen Zeile. Fordern wir nun dieses
Dokument wie gewohnt an, so würden wir wie folgt verfahren:
function showResponse() {
document.getElementById("msgOut").innerHTML = myXMLHttpRequest.
responseText;
}
function sendRequest() {
myXMLHttpRequest.open("GET", "simplejs.js", true);
myXMLHttpRequest.send(null);
}
Listing 4.28: Die für unser Beispiel wichtigen Funktionen sendRequest und showResponse in der Datei
ajax03.htm
Die Funktion sendRequest fordert die Datei simplejs.js an und showResponse gibt
wie gewohnt den Inhalt dieser Datei in ein leeres DIV aus. Statt dass der Code ausge-
führt wird, wird er als reiner Text ausgegeben:
AJAX und
JavaScript
AJAX und
JavaScript
K A P I T E L 4156
Gut, da könnten Sie noch antworten: „War ja klar – binden wir doch ein XHTML-
Dokument ein, das den Code schön zwischen <script> und </script> verpackt!“
Gesagt, getan, versuchen wir die Datei simplejs.htm und ändern den Aufruf in der
Funktion sendRequest entsprechend:
<script language="javascript" type="text/javascript">
alert("Ein erster Test");
</script>
Listing 4.29: Code von simplejs.htm
...
myXMLHttpRequest.open("GET", "simplejs.htm", true);
...
Listing 4.30: Anfrage der Datei simplejs.htm
Der geänderte Aufruf führt zu folgendem Ergebnis (ajax03a.htm):
ABBILDUNG 4.12
Statt dass der JavaScript-
Code ausgeführt wird, wird
er als Text ins Dokument
eingebettet.
A J A X – A S Y N C H R O N U S J AVA S C R I P T A N D X M L 157
Leider ist unser Versuch gescheitert – das Ergebnis des Beispiels ist nicht besser gewor-
den, denn jetzt sehen wir gar nichts mehr. Versuchen wir es also noch mal anders.
Verwenden wir wieder die Datei simplejs.js (mit nichts als JavaScript-Code im Inhalt)
und versuchen die eval-Methode bei der Ausgabe der Rückgabe (ajax03b.htm):
function showResponse() {
document.getElementById("msgOut").innerHTML = eval(myXMLHttpRequest.
responseText);
}
function sendRequest() {
myXMLHttpRequest.open("GET", "simplejs.js", true);
myXMLHttpRequest.send(null);
}
Listing 4.31: Wir verwenden die Methode eval sowie die zuvor erstellte Datei simplejs.js.
Wir erhalten nun (fast) das gewünschte Ergebnis:
ABBILDUNG 4.13
Diesmal liefert unsere
Anfrage gar nichts …
K A P I T E L 4158
Die Ausgabe des Textes „undefined“ ist verständlich, da wirListing . einem Container
einen XHTML-Text zuweisen, der nicht vorhanden ist (es wurde lediglich JavaScript-
Code ausgeführt). Wir korrigieren also die Ausgabe der JavaScript-Datei wie folgt:
Aus
function showResponse() {
document.getElementById("msgOut").innerHTML = eval(myXMLHttpRequest.
responseText);
}
ABBILDUNG 4.14
Fast wie gewünscht: einzig
der Text „undefined“ wird
ausgegeben.
A J A X – A S Y N C H R O N U S J AVA S C R I P T A N D X M L 159
wird
function showResponse() {
eval(myXMLHttpRequest.responseText);
}
Listing 4.32: Die Ausgabe an das DIV-Tag „msgOut“ wurde entfernt, da wir nur JavaScript-Code ausführen
und nichts weiteres an das Dokument ausgeben wollen (ajax03c.htm).
Halten wir also fest: Wenn Sie eine reine JavaScript-Datei anfordern und abarbeiten
wollen, so müssen Sie den Rückgabewert von AJAX (responseText) mit der Methode
eval abarbeiten lassen, sodass der Code als Code und nicht als Text interpretiert wird.
Diese Variante funktioniert übrigens auch, wenn Sie mit Funktionen in der JavaScript-
Datei arbeiten (simplejs2.js):
function myAlert(msg) {
alert(msg);
}
myAlert("Ein erster Test");
Listing 4.33: Eine Funktion anstatt eines direkten Aufrufs von alert
Wie stellt sich die Sachlage jedoch dar, wenn wir eine XHTML-Datei anfordern, die
sowohl aus XHTML als auch aus JavaScript-Code besteht? Nehmen wir folgendes
Beispiel (notsosimplejs.htm):
<script language="javascript" type="text/javascript">
alert("Ein zweiter Test");
</script>
<p>So - wir erwarten eine alert-Box sowie die Ausgabe dieses Textes auf
dem Bildschirm!</p>
<script language="javascript" type="text/javascript">
<!--
function myAlert(msg) {
alert(msg);
}
myAlert("Ein dritter Test");
//-->
</script>
<p>Und noch ein Text!</p>
Listing 4.34: Eine gemischte XHTML-Datei (XHTML und JavaScript)
JavaScript-
Dateien anfor-
dern und Code
ausführen
JavaScript-
Dateien anfor-
dern und Code
ausführen
K A P I T E L 4160
An dieser Stelle bleibt uns dann nicht mehr viel anderes übrig, als den XHTML-Code
zu parsen und den JavaScript-Code vom XHTML-Code zu trennen. Hierbei bedient
man sich gerne sogenannter „Regular Expressions“. Sie werden verwendet, um in
Strings gewisse Suchausdrücke zu definieren und diese durch andere Strings zu erset-
zen. Mithilfe der JavaScript-Methode RegExp können wir direkt zur Laufzeit Scripts
erzeugen (Details zur Funktion RegExp entnehmen Sie bitte beispielsweise der Website
http://de.selfhtml.org).
Wir werden also versuchen, den XHTML-Code vom JavaScript-Code zu trennen,
danach den JavaScript-Code auszuführen und den XHTML-Code in unserem Ausga-
be-DIV (<div id="msgOut">) auszugeben.
Zunächst laden wir hierzu die Antwort vom Server in eine Variable respRaw:
var respRaw = myXMLHttpRequest.responseText;
Nun definieren wir einen ersten String, den wir aus dieser Variable entfernen wollen,
da er uns bei der Ausführung von JavaScript-Code stören wird. Des Weiteren legen wir
eine Instanz des Objekts RegExp an:
var findStr = "(?:<script.*?>)((n|r|.)*?)(?:</script>)";
var myRegExp = new RegExp(findStr,"img");
Der Instanz myRegExp werden zwei Parameter übergeben:
Parameter 1 bezeichnet den Ausdruck, der innerhalb eines Textes gefunden werden
soll. In unserem Fall sind das alle Tags, die mit „<script .. >“ anfangen (mit
beliebig vielen Attributen zwischen „<script“ und „>“), alle Zeilenumbrüche (
n), alle Wagenrückläufe (r) sowie alle Tags „</script>“.
Parameter 2 kann folgende Einstellungen bezeichnen:
g: Kennzeichnet ein „global matching“: Es werden im Fall der Verwendung von
replace alle gefundenen Ausdrücke von Parameter 1 aus dem String entfernt.
i: Kennzeichnet, dass wir Groß- und Kleinschreibung nicht beachten (case-
insensitive).
m: Kennzeichnet den Multiline Mode – somit werden vor und nach neuen Zeilen
Ausdrücke mit einem beginnenden $ oder ^ gesucht (diese Einstellung gibt es
nur in JavaScript 1.5 und höher).
Um nun den XHTML-Teil vom JavaScript-Teil zu trennen, müssen wir also aus dem
Antworttext vom Server (respRaw) für den XHTML-Teil genau diesen String entfer-
nen und für den JavaScript-Teil genau diesen Teil aufheben – dazu verwendet man die
Methoden match und response:
u
u
u
u
u
A J A X – A S Y N C H R O N U S J AVA S C R I P T A N D X M L 161
var xhtml = resp.replace(myRegExp,"");
var js = resp.match(myRegExp);
Listing 4.35: Entfernen des Suchstrings mit replace (genau gesprochen: Ersetzen des Suchstrings mit „“)
und speichern des Suchstrings mit match.
Den XHTML-Teil müssen wir nicht mehr verändern, dieser ist bereits komplett und
wartet auf seine Ausgabe. Den JavaScript-Teil hingegen müssen wir nun wieder von
den Tags <script> und </script> säubern, da wir – wie wir weiter oben schon
besprochen haben – für die Abarbeitung des Codes die Methode eval verwenden und
diese nur puren JavaScript-Code ausführen kann. (Zur Erinnerung: Das Tag <script>
gehört nicht zum Sprachumfang von JavaScript, sondern von XHTML.) Des Weiteren
stört uns auch die Kommentarkennzeichnung aus HTML „<!--“, die ebenfalls ent-
fernt gehört:
var myRegExp3 = new RegExp(findStr,"im");
for(var i=0; i<js.length; i++) {
var toEval = js[i].match(myRegExp3)[1].replace(/<!--/g,"");
eval(toEval);
}
Listing 4.36: Entfernen des ursprünglichen Suchstrings aus js sowie Entfernen des Strings „<!--“ mittels
replace
Nachdem also unser JavaScript-Code ausgeführt wurde, geben wir auch noch den
XHTML-Code im dafür vorgesehenen Container aus:
document.getElementById("msgOut").innerHTML = xhtml;
Listing 4.37: Ausgabe der Variable xhtml in den Container msgOut
Damit können wir den Einschub: AJAX und JavaScript abschließen und uns wieder
unserer Miniwebsite widmen. Wir sind bei der in index.htm eingebundenen Datei
kontakt.inc.js stehen geblieben – werfen wir einen Blick darauf:
var contactXMLHttpRequest;
function sendContact() {
contactXMLHttpRequest = createRequestObject();
contactXMLHttpRequest.onreadystatechange = handleRequestContact;
var querystring = "Email="+document.forms["frmKontakt"].
elements["Email"].value+"&Nachricht="+document.forms["frmKontakt"].
elements["Nachricht"].value
contactXMLHttpRequest.open("GET", "includes/kontakt.inc.
php?"+querystring, true);
K A P I T E L 4162
contactXMLHttpRequest.send(null);
}
function showResponse2() {
document.getElementById("msgOut").innerHTML = contactXMLHttpRequest.
responseText;
}
function handleRequestContact() {
document.forms["frmKontakt"].elements["msgStatus"].value +=
contactXMLHttpRequest.readyState+"n";
switch(contactXMLHttpRequest.readyState) {
case 0:
case 1:
case 2:
case 3: return;
case 4: showResponse2(); return;
}
}
Listing 4.38: Der Inhalt der Datei kontakt.inc.js
Da der Code aus einem vorigen Beispiel (siehe Listing 4.11) bereits bekannt ist, fasse
ich noch einmal zusammen:
1. Die Variable contactXMLHttpRequest dient als Instanz für den XMLHttpRequest.
2. Bei Aufruf von sendContact wird contactXMLHttpRequest zur Instanz von
XMLHttpRequest und es wird ihr ein Eventhandler handleRequestContact
zugewiesen. In diesem Atemzug werden auch ein Querystring (Variable
querystring) mit allen eingegebenen Daten aus dem Formular sowie der open-
Aufruf an die Datei kontakt.inc.php durchgeführt.
3. Hat contactXMLHttpRequest die Eigenschaft readyState==4 erreicht
(der Datentransfer von Server zu Client ist abgeschlossen), wird die Funktion
showResponse2 aufgerufen. Solange dies nicht der Fall ist (also readyState<4),
passiert nichts.
4. Die Funktion showResponse2 sorgt dafür, dass der Rückgabewert von kontakt.
inc.php (dies wird eine Erfolgs- oder Misserfolgsmeldung sein) in dem leeren DIV
msgOut dargestellt wird.
A J A X – A S Y N C H R O N U S J AVA S C R I P T A N D X M L 163
Da wir auch die Funktionsweise der Datei kontakt.inc.php bereits in Listing 4.12
ausführlich besprochen haben, bleibt uns nichts weiter zu tun, als kurz zusammenzu-
fassen:
1. Durch den send-Aufruf der XMLHttpRequest-Instanz wird auf Serverseite die
Datei kontakt.inc.php aufgerufen, wobei dieser der oben genannte Querystring mit
den Formularfeldwerten übermittelt wird (als GET-Variable).
2. Innerhalb von kontakt.inc.php wird eine Funktion definiert (und selbstverständlich
auch aufgerufen), die aus den gegebenen Daten eine E-Mail „bastelt“ und diese
mithilfe der mail-Funktion verschickt.
3. Liefert mail den Wert true zurück, war der Mail-Versand erfolgreich und es wird
eine Erfolgsmeldung per echo als XHTML ausgegeben; im Fall eines Misserfolgs
wird eine Misserfolgsmeldung ausgegeben. In jedem Fall bildet der so erzeugte
XHTML-Code den Rückgabewert an die XMLHttpRequest-Instanz.
Das Ergebnis können Sie wie gewohnt (nachdem Sie die Daten online gestellt haben)
in einem Browser testen:
ABBILDUNG 4.15
Wie zu erwarten, hat alles
funktioniert – die E-Mail
wurde versandt (siehe fol-
gende Abbildung).
Und hier noch – quasi als Beweis – die empfangene E-Mail:
K A P I T E L 4164
Bilden wir ein Resümee zu unserer Website-Entwicklung. Wie wir gesehen haben,
sind zwar alle gängigen Anforderungen an eine Website erfüllt worden: Wir konnten
statische, dynamische sowie AJAX-basierte Dokumente einbinden. Jedoch muss man
auch offen gestehen, dass es immer wieder einiger Tricks bedurfte, um letzten Endes
das Ziel zu erreichen – und genau so ein„Tricksen“ ist nicht sinnvoll! Man sollte immer
die optimale Technologie für den optimalen Fall verwenden und nicht zwanghaft auf
eine Technologie setzen, die für die gegebene Anwendung gar nicht so sehr geeignet ist.
AJAX leistet große Dienste, wenn im Nachhinein Daten in ein Dokument hinzugela-
den werden sollen – wir meinen jedoch zumeist statische Information wie zusätzliche
Texte, Grafiken etc. In nur wenigen (Ausnahme-)Fällen ist von dynamischen oder gar
AJAX-basierten Daten die Rede.
In den nächsten beiden Kapiteln wollen wir uns deshalb ein bisschen die Augen öffnen
lassen für Anwendungsgebiete, in denen AJAX Platz findet – vor allem liegt uns jedoch
das Zusammenspiel mit Flash am Herzen!
4.4 Flash vs. AJAX
Wie wir aus den Darstellungen des letzten Kapitels gesehen haben, ist AJAX in der
Lage, nachträglich und ohne Neuladen des Webdokuments Daten vom Server nach-
zuladen – sogar dynamische wie AJAX-basierte Dokumente können (ausgewertet
und) nachgeladen werden. Flash kann das schon sehr lange und deshalb wurden viele
Anwendungen, in denen immer wieder mal Daten nachgeladen werden müssen (aber
deshalb die Seite nicht neu geladen wird) in Flash realisiert. Man denke beispielsweise
an Chat-Systeme – eine typische Flash-Domäne (sehen wir einmal von ActiveX-Kom-
ponenten oder Applets ab).
Warum war Flash eigentlich immer schon in der Lage, das zu tun, was mit AJAX
mühsam eingeführt wurde? Nun, das liegt daran, dass AJAX auf Standardtechnologien
ABBILDUNG 4.16
Die versandte E-Mail ist
angekommen – was wollen
wir noch mehr?
A J A X – A S Y N C H R O N U S J AVA S C R I P T A N D X M L 165
basiert, die jeder halbwegs gängige Browser unterstützt: XHTML und JavaScript. Flash
hingegen ist ein Plug-in, das ein User selbstständig installieren muss (sollte es nicht
bereits installiert sein). Solche Plug-ins haben wesentlich mehr „Rechte“ im Browser
des Users als die Standardtechnologien. Dies liegt mitunter auch daran, dass wir User
selbst das Einverständnis dafür gegeben haben: Mit dem Zeitpunkt der Installation
haben wir Flash implizit „erlaubt“, das zu tun, was Flash imstande ist – dazu gehört
unter anderem auch das Nachladen von Daten beispielsweise mithilfe des LoadVars-
Objekts, das wir im Laufe dieses Buchs noch genau kennenlernen werden.
Nachdem die Applikation„Flash“ immer noch (und das wird es auch immer bleiben) ein
rotes Tuch in den Augen mancher User im Internet ist (O-Ton:„Dieses Flash: Alles dreht
sich und überall wird böse Musik abgespielt!“), hat man mit AJAX nun eine Möglichkeit,
einige der Anwendungen zu realisieren, die man ursprünglich nur mit Flash (oder einem
anderen Plug-in) realisieren konnte. Man könnte also sagen, dass Flash in gewissen
Bereichen des Internets ein bisschen an Boden verlieren wird. Speziell in Hinblick auf
News-Systeme (Anzeigen der aktuellsten Newsticker in einem regelmäßigen Abstand),
dynamische Grafiken (Börsenkurse usw.), Chat-Systeme, dynamische Auswahlsysteme
(Google Suggest, Suche in wikipedia.de usw.) stellt AJAX eine ernst zu nehmende Kon-
kurrenz zu Flash dar. Wobei – und das sollte man nicht außer Acht lassen! – Flash für
solchen Anwendungen oft auch nur eine „Notlösung“ war: Warum sollte man für einen
simplen Newsticker Flash installiert haben, wenn die Darstellung der News ja lediglich
Textinformationen sind? XHTML ist dafür wesentlich besser geeignet.
Ein Killerargument für Flash ist selbstverständlich die Plattformunabhängigkeit: Egal,
ob eine Flash-Anwendung auf einem PC, Mac oder einem Handy angezeigt wird – sie
wird immer gleich ablaufen. Im Fall von AJAX-Anwendungen können wir das nicht
behaupten, da wir immer noch mit unterschiedlichen Browsern rechnen müssen.
Viel wichtiger, als herauszufinden, wo AJAX Flash eine Konkurrenz sein kann (eigent-
lich ist es ja müßig, darüber überhaupt nachzudenken), ist es, herauszufinden, wo
diese beiden großartigen Technologien zusammenarbeiten können – die Devise lautet
also „Flash & AJAX“ statt „Flash vs. AJAX“.
4.5 Flash & AJAX
Viel interessanter ist also die Frage, in welcher Hinsicht Flash und AJAX zusammenspie-
len können oder AJAX eine (zusätzliche) Alternative zu Flash bietet. Um diese Frage zu
beantworten, müssen wir uns zunächst einmal bewusst werden, welche der möglichen
Technologien in welchen Bereichen Vor- und in welchen Bereichen Nachteile aufweist.
Bereich AJAX Flash
Kein Plug-in erforderlich + -
Darstellen von ausschließlich Textinformationen
(inklusive Bildern)
+ -
Darstellen von pixelbasierten Grafiken + +
K A P I T E L 4166
Bereich AJAX Flash
Darstellen von Vektorgrafiken - +
Darstellen von Animationen - +
Darstellen von weiteren multimedialen Inhalten - +
Arbeiten mit Formularen und Formularinhalten + +/-
Browser-Unterstützung + +/-
Akzeptanz des Users + +/-
Barrierefreiheit - +/-
Schnelligkeit in der Darstellung + +
Kompatibilität zwischen verschiedenen Versionen - browserabhängig +
Programmiermodell +/- JavaScript 1.5 wird bei größeren OOP-
Anwendungen nicht empfohlen
+
Unterstützung von XML-Darstellung - +
Tabelle 4.6: Übersicht von Vor- und Nachteilen der Technologien AJAX und Flash (ohne Anspruch auf
Vollständigkeit)
Aus der obigen Tabelle ergeben sich folgende Synergien:
Einsatz von AJAX und Flash parallel: Sollten Sie die Möglichkeit haben, eine Flash-
Anwendung in AJAX nachzubauen (Newsticker, Auswahlsysteme etc.), so ist dies
für den User positiv, da Sie den User nicht zum Einsatz von Flash nötigen müssen.
Somit nutzen Sie den Vorteil, dass der User kein Flash-Plug-in installiert haben
muss und trotzdem interaktiv arbeiten kann. Im Rahmen der Workshops werden
wir beispielsweise ein Chat-System entwickeln, das sowohl in Flash als auch in
XHTML gleichermaßen gut funktioniert.
Interaktive Darstellung von Bildern/Statistiken: Über Standard-XHTML-Doku-
mente wird der User zur Eingabe diverser Daten aufgefordert (beispielsweise Tabel-
len wie etwa ein „Online-Excel“). Die Grafiken werden dynamisch mit jeder Ein-
gabe in einer Flash-Anwendung angezeigt. Generell ist Flash zum Visualisieren von
Informationen (basierend auf beispielsweise XML-Daten hervorragend geeignet).
Letzten Endes ist die Kombination von Flash und AJAX immer dann sinnvoll, wenn
man die Vorteile beider Welten miteinander kombinieren möchte. Flash ist in der
Lage, alles abzudecken, was AJAX kann – dementsprechend könnte man sagen, dass
für einen Flash-Entwickler AJAX keinen Vorteil bringen würde. Nachteilig ist ja nur,
dass Flash ein Plug-in ist …
Doch nachdem ein Web-Designer kein reiner Flash-Entwickler ist und selbst Flash-
Entwickler hin und wieder über den eigenen Tellerrand blicken sollten, kann man
AJAX als „Flashlose“ Alternative betrachten. Denn anders gefragt: Warum sollte man
auf die Idee kommen, beispielsweise ein Webmail-System mit Flash zu programmie-
ren, wo man doch die wirklichen Vorteile von Flash gar nicht nützen kann? Hier ist
man mit AJAX viel besser aufgehoben.
In den folgenden Kapiteln werden wir uns ausführlich mit den Möglichkeiten von
Flash & AJAX befassen – also nehmen Sie sich nicht zu viel vor, wenn Sie gerade am
Buchlesen sind, denn Sie werden das Buch nicht mehr weglegen können.
u
u
5
CLIENTSEITIGER
DATENAUSTAUSCH –
FLASH & JAVASCRIPT
In den folgenden Kapiteln befassen wir uns mit der Frage, wie
Flash mit seiner Umgebung Daten austauschen kann – einer-
seits serverseitig mit dem Webserver und andererseits clientsei-
tig mit dem Browser über das Flash-Plug-in.
Die Schnittstelle zur Außenwelt … Bei dieser Betrachtung wer-
den wir die zwei Bereiche server- und clientseitig voneinander
trennen, da hier zwei ganz verschiedene Vorgehensweisen von-
nöten sind.
Wenn man von clientseitigem Datenaustausch spricht, so meint
man immer zwei Richtungen:
Der Browser sendet Daten an Flash.
Flash versendet Daten an den Browser.
Wie Sie wissen, stehen uns auf Clientseite zwei Technologien
zur Verfügung, die uns beim Datenaustausch behilflich sein
können – (X)HTML und JavaScript. (X)HTML ist die Bezeich-
nungssprache, die für den Aufbau des Webdokuments verwen-
det wird. JavaScript hingegen ermöglicht uns eine Interaktion
mit dem User und den eingebundenen Objekten. Dadurch wird
JavaScript diejenige der beiden genannten Technologien sein,
die uns beim Datenaustausch hilfreich zur Seite steht.
u
u
K A P I T E L 5168
XHTML versus HTML
Jedes Webdokument basiert auf einer Bezeichnungssprache. Ursprünglich wurde die
Bezeichnungssprache HTML verwendet, die sich jedoch als nicht sehr konsistent erwiesen hat,
werden doch zu viele Ungereimtheiten geduldet wie beispielsweise das Schließen der meisten,
aber nicht aller Tags. HTML stammt direkt vom übergeordneten Standard SGML (Standard
Generalized Markup Language) ab, XHTML hingegen von XML (Extended Markup Language), das
wiederum von SGML abstammt.
Nachdem XML in seiner Anwendung sehr strikt und konsequent ist (sprich: keine Fehler duldet)
und XHTML diese Eigenschaften vererbt wurden, ist XHTML in der Anwendung ebenfalls nicht
fehlertolerant. Letzten Endes ist dies eine große Erleichterung für jeden Webdesigner, da ihm
weniger Fehler erlaubt werden und sein Code dadurch immer besser wird. HTML wird seit der
Version 4.01 nicht mehr weiterentwickelt – an seine Stelle ist XHTML 1.0 getreten.
In diesem Buch werden wir konsequent mit XHTML arbeiten.
5.1 Daten senden: Browser an Flash
Man kann auf zwei Arten Daten an Flash übergeben:
1. Es wird von JavaScript auf die SWF-Datei zugegriffen und dort innerhalb der
SWF-Datei eine Variable gesetzt: Diese Variante hat den Vorteil, dass das Senden
von Daten an Flash beispielsweise auch über einen Klick auf einen Button erfolgen
kann – sprich durch eine Benutzereingabe. Nachteilig ist, dass verschiedene
Browser diese Variante unterschiedlich unterstützen.
2. Über geeignete Attribute im HTML-Code werden direkt beim Laden der SWF-
Datei Daten an die SWF-Datei übergeben: Entgegen der oben genannten Variante
besteht hier keine Möglichkeit, per Benutzereingabe Daten an die SWF-Datei zu
senden. Der grundlegende Vorteil dieser Variante ist, dass alle gängigen Browser
eine Datenübergabe in dieser Form unterstützen.
Im Folgenden werde ich auf diese beiden Varianten genauer eingehen.
5.1.1 Variante 1: JavaScript greift auf die
SWF-Datei zu
Für den Fall, dass der Browser mittels JavaScript Daten an Flash übermitteln soll, sind
folgende Schritte notwendig:
1. JavaScript muss die eingebundene SWF-Datei bzw. Flash-Datei eindeutig
identifizieren können.
2. MithilfeeinesgeeignetenBefehlswirdeineVariableinderFlash-Dateiangesprochen
und es wird dieser ein Wert zugewiesen.
C L I E N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 169
Die einzige Variante, um vom Browser aus Daten an Flash zu übermitteln, ist die, dass
man Flash-Variablen einen Wert zuweist. Hierbei ist es nicht zwingend notwendig,
dass die Variable zu diesem Zeitpunkt bereits existiert – Flash ist in der Lage, dyna-
misch Variablen anzulegen, wie Sie in den vorigen Kapiteln bereits erfahren haben.
Einbinden von Flash
Je nach verwendetem Browser wird die Flash-Datei entweder mit dem <object>-
(Standard-HTML, Internet Explorer) oder dem <embed>-Tag (Mozilla-basierte Brow-
ser wie etwa der Netscape Navigator) in die HTML-Datei eingebunden. Damit die
Flash-Datei in diesem HTML-Dokument eindeutig identifiziert werden kann, wird
das <object>- bzw. das <embed>-Tag mit dem id-Attribut eindeutig gekennzeichnet.
Im Allgemeinen wird eine Flash-Datei mithilfe beider Tags eingebunden – dadurch hat
man beiden größeren Browser-Typen Genüge getan und sichergestellt, dass die Datei
auch wirklich verarbeitet werden kann.
<object id="myFlash" classid="clsid:D27CDB6E-AE6D-11cf-96B8-
444553540000" codebase="http://download.macromedia.com/pub/shockwave/
cabs/flash/swflash.cab#version=6,0,29,0" width="200" height="150"style="bo
rder:1px solid #999999;">
<param name="movie" value="browserAnFlash01.swf" />
<param name="quality" value="high" />
<embed id="myswf" name="myFlash" src="browserAnFlash01.swf" width="200"
height="150" quality="high" pluginspage="http://www.macromedia.com/go/
getflashplayer" type="application/x-shockwave-flash"></embed>
</object>
Listing 5.1: Einbinden einer Flash-Datei in HTML-Code
classid und codebase
Mit dem Attribut classid gibt man an, welche Applikation in die Seite eingebun-
den werden soll. Jede (einbindbare) Applikation hat eine eigene eindeutige classid
(classid = class identifier = Klassenbezeichner). Die Angabe besteht aus der fest
vorgegebenen Zeichenfolge CLSID:, gefolgt von der Bezeichner-ID. Im Fall von Flash
ist das: classid="CLSID:D27CDB6E-AE6D-11cf-96B8-444553540000".
Mithilfe der codebase kann eine Quelle für das Downloaden der Applikation angege-
ben werden. Im Fall von Flash ist dies das Flash-Plug-in. Auf die codebase wird dann
zugegriffen, wenn das benötigte Plug-in nicht im Browser des Users installiert ist.
Die Attribute id und name
Wie man aus dem obigen Codefragment leicht erkennen kann, wurde das id-Attri-
but in beiden genannten Tags gleichermaßen angewendet. Grundsätzlich ist es nicht
erlaubt, ein und dieselbe ID mehrmals zu verwenden. Nachdem jedoch in allen Fäl-
K A P I T E L 5170
len nur eines der beiden Tags zum Einsatz kommt, stellt dies kein Problem dar: Der
Internet Explorer von Microsoft ignoriert das in das <object>-Tag verschachtelte
<embed>-Tag, genau wie der Netscape Navigator das <object>-Tag ignoriert. Viel-
mehr wäre dieser Einsatz von IDs für uns sogar ein großer Vorteil, da wir somit auf
eine immer gleiche ID zugreifen können.
Anders verhält es sich beim name-Attribut. Im Weiteren werden wir sehen, dass es
keine einheitliche Möglichkeit gibt, um eine eingebundene Flash-Datei über JavaScript
anzusprechen. Aus diesem Grund möchte ich an dieser Stelle folgenden Tipp geben:
Verwenden Sie das id-Attribut für das <object> und <embed>.
Verwenden Sie das name-Attribut nur für das <embed>.
Nachdem dieser (wichtigste) Schritt erledigt ist, ist unsere Flash-Datei eindeutig iden-
tifizierbar und kann nun per JavaScript angesprochen werden. An dieser Stelle muss
man – wie es der Webdesigner leider schon allzu oft gewohnt ist – zwischen verschie-
denen Browsern unterscheiden.
Allgemein dient der Befehl SetVariable dazu, auf Variablen innerhalb von Flash
zuzugreifen. Hierzu müssen diesem Befehl zwei Attribute zugewiesen werden:
SetVariable("Variablenname", Wert);
Dieser Befehl muss noch auf das Flash-Objekt angewandt werden – man muss sich also
Zugriff auf die eingebundene Flash-Datei verschaffen. Sofern der verwendete Brow-
ser das DOM (Document Object Model) für JavaScript unterstützt, ist der geeignete
Befehl in JavaScript getElementById.
Den eher ungewöhnlichen Fall (dass dieser Fall gar nicht so ungewöhnlich ist, werden
wir leider weiter unten noch sehen …) einmal ausgeschlossen, dass das DOM nicht
unterstützt wird, lautet der vollständige Zugriff auf die eingebundene Flash-Datei
demnach wie folgt:
document.getElementById("ID des Elements").SetVariable("Variablenname",
Wert);
Listing 5.2: DOM-korrekte Syntax für den Zugriff auf eine Flash-Variable per JavaScript
Alternativ dazu lässt sich im Internet Explorer jedes vorhandene Element auch über
document.all ansprechen, also:
document.all["ID des Elements"].SetVariable("Variablenname",Wert);
Listing 5.3: Alternative Syntax für den Internet Explorer
Um den Code für alle gängigen Browser zu optimieren, müssen wir jedoch ein biss-
chen tiefer in die Trickkiste greifen. Je nach Browser möchte das Flash-Plug-in unter-
schiedlich angesprochen werden. Einerseits haben wir gesehen, wie es der Internet
Explorer „gerne hätte“, andererseits müssen wir uns an dieser Stelle auch noch um den
u
u
id für <object>,
name für <embed>
id für <object>,
name für <embed>
DOM-korrekte
Syntax
DOM-korrekte
Syntax
Internet Explorer
Syntaxalternative
Internet Explorer
Syntaxalternative
Firefox
Syntaxalternative
Firefox
Syntaxalternative
C L I E N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 171
(beliebten) Browser namens Firefox kümmern – dieser möchte wiederum, dass er über
das embeds-Objekt angesprochen wird, also:
document.embeds["Name des Elements"].SetVariable("Variablenname",Wert);
Listing 5.4: Syntax für den Zugriff auf eine Flash-Variable per JavaScript im Firefox
Wie nicht anders zu erwarten war, funktioniert die Sache leider nicht im Safari-Brow-
ser unter Mac OS. Somit bleibt uns nichts anderes übrig, als noch tiefer in der Trick-
kiste zu stöbern …
Grundsätzlich kann man auch direkt über das document-Objekt auf HTML-Elemente
zugreifen, sofern der Browser das zulässt:
document["Name des Elements"].SetVariable("Variablenname", Wert);
Listing 5.5: Alternative Schreibweise, um auch noch den Safari-Browser „mit ins Boot“ zu holen.
Fassen wir all die Varianten zusammen, um schlussendlich ein Script zu erhalten, mit
dem der Zugriff auf die Flash-Datei in allen gängigen Browsern möglich ist, so erhalten
wir:
function getFlashElement(elem) {
var app = navigator.appName.toLowerCase();
var nav = navigator.userAgent.toLowerCase();
if((app.indexOf("microsoft") != -1 || nav.indexOf("microsoft") != -1)
&& !Boolean(window["opera"])) { return document.all[elem]; }
else { return document[elem]; }
}
function sendDataToFlash() {
var myswf = getFlashElement("myswf");
myswf.SetVariable("myVar", "EXPLODE");
}
Listing 5.6: Universalzugriff auf eine eingebundene Flash-Datei
Zur Erklärung:
Die Funktion getFlashElement() findet den korrekten„Zugang“ zur Flash-Datei
und liefert die entsprechende Referenzierung an das aufrufende Script zurück:
Sollte es sich um den Internet Explorer handeln (und nicht um einen Opera-
Browser, der sich als Internet Explorer ausgibt), so liefert es document.
all[elem] zurück.
Sollte es sich nicht um den Internet Explorer handeln, so erhält man
document[elem].
u
u
u
K A P I T E L 5172
Die Funktion sendDataToFlash() ruft die oben genannte Funktion auf, um kor-
rekt auf die Flash-Datei zuzugreifen, und setzt danach mit der Methode SetVari-
able eine Variable namens myVar auf den Wert „EXPLODE“.
Aktion in Flash auslösen
Sehen wir uns dies an einem Beispiel an: Einmal angenommen, man möchte durch
Klicken auf einen HTML-Button in Flash eine Aktion auslösen. Nachdem man per
JavaScript einzig und allein Variablenwerte in Flash setzen kann, ist der Aufruf einer
Funktion in Flash also nicht möglich. Man umgeht dieses Problem, indem man in
Flash so lange auf einen gewissen Wert einer Variablen„wartet“, bis dieser – in unserem
Fall mittels JavaScript – gesetzt wird.
Im Kapitel über die ExternalInterface-Klasse werden wir sehen, dass das Procedere
„Warten auf das Setzen einer Variable“ wegfällt, da es uns diese Klasse ermöglicht,
direkt aus JavaScript auf ActionScript-Funktionen zuzugreifen – eine große Erleichte-
rung, die jedoch erst seit Flash 8 funktioniert.
Schritt für Schritt: Flash-Aktion per JavaScript
In Flash benötigen wir für dieses Beispiel vier (vorerst) leere Bilder in der Zeitleiste.
Wie üblich legen wir für unseren ActionScript-Code eine eigene Ebene in der Zeitleiste
an und benennen sie mit „Aktionen“. Die darüberliegende Ebene beinhaltet nichts
anderes als Bildnamen. Solche Bildnamen erleichtern die Übersichtlichkeit in Pro-
grammen enorm, außerdem ist das nachträgliche Einfügen von Bildern so auch kein
Problem für das korrekte Ausführen des Codes.
Arbeitet man nicht mit Bildnamen, sondern mit den Bildnummern, müsste man nach
dem Einfügen oder Löschen von Bildern immer überprüfen, ob nicht ein Codefrag-
ment auf eine spezielle Bildnummer zugreift, die sich nun eventuell geändert hat.
u
External-
Interface-Klasse
als Erleichterung
External-
Interface-Klasse
als Erleichterung
1. Bilder anlegen1. Bilder anlegen
C L I E N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 173
In der untersten Ebene befinden sich je nach Bild in der Zeitleiste verschiedene Texte.
Dies hilft uns dabei, uns bei der Darstellung der Flash-Datei im Browser leicht zurecht-
zufinden. Anhand der ausgegebenen Texte können wir leicht überprüfen, ob unser
Code funktioniert.
Im ersten Bild – dem Initialisierungsbild der Zeitleiste – deklarieren wir eine Variable
namens myVar vom Typ String und weisen dieser den Wert "" (leerer String) zu.
Zur Erinnerung: Möchten Sie in ein Bild der Zeitleiste ActionScript-Code schreiben,
so müssen Sie das Bild in der Zeitleiste markieren und danach im ActionScript-Editor
den Code eingeben. Sollte der Editor nicht eingeblendet sein, so finden Sie diesen in
der Menüzeile im Menü FENSTER bzw. durch Drücken der Taste (F9).
var myVar:String = "";
Im Folgenden werden wir diese Variable auf ihren Wert abfragen.
Im zweiten Bild wird kein Code ausgeführt. Dieses Bild bekommt jedoch einen Namen
(„warten“), den wir zum Zurückspringen verwenden werden.
Um einem Bild der Zeitleiste einen Namen zu geben, muss es in der Zeitleiste zuerst
markiert werden und danach im Eigenschaften-Inspektor im Feld „Bild“ ein Name
eingetragen werden.
2.Variablen-
deklaration
2.Variablen-
deklaration
3. Namens-
gebung für das
„Wartebild“
3. Namens-
gebung für das
„Wartebild“
ABBILDUNG 5.1
Das fertig programmierte
Beispiel – hier unser erstes
Bild in der Zeitleiste
K A P I T E L 5174
Im dritten Bild wird der Wert von myVar abgefragt – sollte dieser (immer noch) auf ""
gesetzt sein, springen wir auf das Bild mit dem Namen „warten“ zurück. Dies geschieht
so lange, bis die Variable einen String beinhaltet, der ungleich "" ist.
if(myVar=="") { gotoAndPlay("warten"); }
4.Wert von myVar
abfragen
4.Wert von myVar
abfragen
ABBILDUNG 5.2
Dem zweiten Bild wird kein
ActionScript-Code zugewie-
sen, es dient vielmehr nur als
„Sprungbild“ zum Warten auf
das Setzen von myVar durch
den externen JavaScript-
Code.
ABBILDUNG 5.3
Wurde durch den externen
JavaScript-Code myVar
auf einen Wert ungleich ""
gesetzt, so erfüllt sich die
Bedingung in Bild 3 und
Flash springt ins vierte Bild
der Zeitleiste weiter, wo
durch einen stop()-Befehl
das Weiterlaufen des Zeigers
in der Zeitleiste verhindert
wird.
C L I E N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 175
In Bild 4 ist das Beispiel auch schon zu Ende – mithilfe des Befehls stop(); beenden
wir das Abspielen der Zeitleiste.
stop();
Des Weiteren beinhaltet das vierte Bild ein dynamisches Textfeld zur Ausgabe einer
Kontrollmeldung.
Hierzu erzeugen Sie mithilfe des Textwerkzeugs ein Textfeld, dem Sie im Eigenschaften-
Inspektor den Typ „Dynamischer Text“ zuweisen.
5. Das Ende-Bild5. Das Ende-Bild
Tipp zum Ausgeben von Kontrollinformationen
Der Entwickler von Flash-Anwendungen kommt oftmals in die Situation, dass er die Flash-
Anwendung online in einem Browser testen muss. Nachdem ihm dort das Ausgabefenster
von Flash nicht zur Verfügung steht, verwendet er gern dynamische Textfelder oder TextArea-
Komponenten zum Ausgeben von Variablenwerten. Welche der beiden Varianten Sie verwenden,
ist Ihnen überlassen. Für einzeilige Ausgaben verwenden wir bevorzugt dynamische Textfelder,
für mehrzeilige Ausgaben TextArea-Komponenten, wegen des dort automatisch erzeugten
Scrollbalkens.
Werfen wir noch einmal einen Blick auf unseren Code und dessen Ablauf: Offen-
sichtlich wird in Bild 1 eine Variable myVar vom Typ String deklariert und es wird
ihr der Wert "" zugewiesen. Gelangt der Bildzeiger in der Zeitleiste zu Bild 3, so wird
hier überprüft, ob diese Variable den Wert "" besitzt – sollte dies der Fall sein, springt
Flash in das Bild mit dem Namen „warten“ (in unserem Fall das zweite Bild) zurück
und spielt von dort aus weiter ab. Solange myVar also den Wert "" besitzt, springt
Flash fortwährend zwischen Bild 2 und 3 hin und her. Sollte myVar irgendwann einen
6. Codeanalyse6. Codeanalyse
ABBILDUNG 5.4
In Bild 4 erstellen Sie ein
dynamisches Textfeld.
K A P I T E L 5176
Wert ungleich "" besitzen, spielt Flash zu Bild 4 weiter ab und wird dort per stop();
angehalten. Im Prinzip haben wir also eine sehr einfache Schleife programmiert!
Im nächsten Schritt überlegen wir uns den JavaScript-Code, der unserer Flash-Variable
myVar den Wert „EXPLODE“ zuweist, um zum vierten Bild in der Flash-Zeitleiste zu
gelangen. Dieser Wert soll genau dann gesetzt werden, wenn wir auf einen Button im
HTML-Dokument klicken.
7. JavaScript-
Code
7. JavaScript-
Code
ABBILDUNG 5.5
So soll unser kleines Beispiel
in einem Browser darge-
stellt werden. Die Flash-
Anwendung wartet auf einen
Klick auf den nachfolgenden
Button.
Wenden wir uns zunächst einmal dem Inhalt des <body> zu. Um einen Button HTML-
konform in das Dokument einzubauen, benötigen wir ein Formular. Außer für diesen
Button wäre das Formular nicht erforderlich, lassen Sie sich deshalb also nicht davon
ablenken. Ebenso dient die eingebaute Tabelle nur der übersichtlicheren Darstellung.
Letzten Endes soll das HTML-Dokument in einem Browser wie in Abbildung 5.5
gezeigt dargestellt werden.
<div id="Flash">
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/
swflash.cab#version=7,0,19,0" width="200" height="150" id="myswf">
<param name="movie" value="browserAnFlash01.swf" />
<param name="quality" value="high" />
<embed id="myswf" name="myswf" src="browserAnFlash01.swf"
width="200" height="150" quality="high" pluginspage="http://www.
macromedia.com/go/getflashplayer" type="application/x-shockwave-
flash"></embed>
</object>
8. HTML-
Dokument
erstellen
8. HTML-
Dokument
erstellen
C L I E N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 177
</div>
<div id="SendButton">
<form name="frmSetVariable" id="frmSetVariable" method="post"
action="">
<input type="button" value="Daten senden" onClick="sendDataToFlash();" />
</form>
</div>
Listing 5.7: Einbinden der Flash-Datei und Erzeugen des Formulars inklusive Button
Der wesentliche Teil des Codes – neben dem eingebundenen Flash-Dokument, das
im <object> durch id="myswf" und im <embed> durch name=" myswf" eindeutig
gekennzeichnet ist – ist der Aufruf der Funktion sendDataToFlash() durch Klicken
auf den Button:
<input type="button" value="Daten senden" onclick="sendDataToFlash();" />
Es wird also eine JavaScript-Funktion namens sendDataToFlash() aufgerufen,
wobei der Name der Funktion frei wählbar ist, da es sich hier nicht um eine vordefi-
nierte Funktion handelt.
Im Allgemeinen werden JavaScript-Blöcke (und da im Speziellen Funktionsdefini-
tionen) im <head>-Bereich eines HTML-Dokuments eingebunden, weshalb auch ich
Ihnen diese Vorgehensweise empfehle.
Hier zunächst einmal der benötigte JavaScript-Code:
function getFlashElement(elem) {
var app = navigator.appName.toLowerCase();
var nav = navigator.userAgent.toLowerCase();
if((app.indexOf("microsoft") != -1 || nav.indexOf("microsoft") != -1)
&& !Boolean(window["opera"])) { return document.all[elem]; }
else { return document[elem]; }
}
function sendDataToFlash() {
var myswf = getFlashElement("myswf");
myswf.SetVariable("myVar", "EXPLODE");
}
Listing 5.8: Die benötigten Funktionen zum Erkennen der korrekten „Ansprache“ der SWF-Datei einerseits
(Funktion getFlashElement) sowie dem Schreiben der Variable innerhalb Flash andererseits (Funktion
sendDataToFlash).
Die Funktion sendDataToFlash() (das ist diejenige, die beim Klick auf den Button
aufgerufen wird) selbst ruft – wie im einleitenden Teil dieses Kapitels dargelegt – wie-
9. JavaScript-
Funktion
schreiben
9. JavaScript-
Funktion
schreiben
K A P I T E L 5178
derum eine Funktion getFlashElement(elem) auf, welche laut Document Object
Model von JavaScript die eingebundene Flash-Datei (Attribut elem) anspricht. Die
entsprechende Referenzierung wird von der Funktion per return zurückgeliefert.
Nachdem die Rückgabe der Referenzierung erfolgt ist, wird mithilfe der Methode
SetVariable("Variablenname", "Variablenwert") innerhalb der Flash-Datei
die Variable myVar auf den Wert „EXPLODE“ gesetzt.
Als Ergebnis unserer Bemühungen erhalten wir also:10.Testen der
Funktionalität
10.Testen der
Funktionalität
ABBILDUNG 5.6
Per Klick auf den Button
wurde die Variable myVar
in der eingebundenen
Flash-Datei auf den
Wert „EXPLODE“ gesetzt.
Möglich wird das durch die
Verwendung der JavaScript-
Funktion SetVariable().
Mögliche Fehlerquelle: die Adobe-eigene Funktion AC_FL_RunContent()
An dieser Stelle sei angemerkt, dass hier eine potenzielle Fehlerquelle zutage treten kann: Im
Internet Explorer muss eine eingebundene Flash-Datei „aktiviert“ werden. Dies bedeutet, dass
der User die Flash-Datei im Browser anklicken muss, erst dann gilt sie als aktiviert und es kön-
nen etwaige Benutzereingaben (Klicken eines Buttons in der Flash-Datei o.Ä.) getätigt werden.
Um dies zu umgehen, hat sich Adobe entschlossen, einen Workaround anzubieten und damit die
Flash-Datei per JavaScript einzubinden.
Die von Adobe angebotene JavaScript-Funktion (AC_FL_RunContent()) lässt leider nicht
zu, dass das <object> ein id-Attribut und das <embed> ein name-Attribut erhalten. Somit
würde unser Code zum Ansprechen der Flash-Datei beispielsweise im Firefox und im Safari nicht
mehr funktionieren.
Um dies zu korrigieren, muss man in der Datei AC_RunActiveContent.js in der Funktion AC_FL_
RunContent() die Zeilen
case "id":
durch
case "id":
C L I E N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 179
ret.objAttrs[args[i]] = args[i+1];
break;
und
case "name":
durch
case "name":
ret.embedAttrs[args[i]] = args[i+1];
break;
ersetzen.
5.1.2 Variante 2:Verwenden von HTML-
Attributen zum Setzen von Variablen
Eine zweite Möglichkeit, Variablen von „außerhalb“ in einer Flash-Datei zu setzen,
erfolgt mithilfe geeigneter Attribute in den Tags <object> und <embed>. Je nach ver-
wendetem Browser müssen die entsprechenden Tags verwendet werden.
Nachdem die Attribute direkt in den HTML-Code geschrieben werden, ist diese Vari-
ante unabhängig von JavaScript.
Grundsätzlich wird mit dem Attribut FlashVars gearbeitet, dem als Wert der Variab-
lenname inklusive Wertzuweisung zugewiesen wird:
FlashVars = "meineVariable=meinWert"
Die Variablen inklusive Wert sind bereits im ersten Frame der Flash-Datei verfügbar
und müssen nicht explizit deklariert werden. Es sollte darauf geachtet werden, dass
– entgegen der vorigen Variante – die Variable nicht deklariert und ihr ein Wert zuge-
wiesen wird, denn ansonsten würde der von außerhalb gesetzte Wert der Variablen
überschrieben werden.
Beachten Sie bitte außerdem, dass – unabhängig vom Wertetyp – der Wert von meine-
Variable immer ohne Anführungszeichen geschrieben wird. Somit:
korrekt: FlashVars = “myVar=once again”
falsch: FlashVars = „myVar=‘once again‘“
Es können beliebig viele Variablen über diese Methode gesetzt werden.
Attribute in <object>
Im Fall des <object> wird mit dem im <object> verschachtelten <param> gearbeitet:
<param name="FlashVars" value="myVar=once again" />
u
u
Kein JavaScript
benötigt
Kein JavaScript
benötigt
K A P I T E L 5180
Attribute in <embed>
Im Fall des <embed> verhält sich die Sache ähnlich, jedoch wird üblicherweise kein
zusätzliches verschachteltes Tag (wie oben das <param>) verwendet, sondern alle Attri-
bute werden direkt im <embed> aufgelistet:
<embed FlashVars="myVar=once again" .. ></embed>
In der nachfolgenden Abbildung sehen Sie eine Anwendung, die ähnlich wie die
Anwendung im vorigen Kapitel arbeitet. Der Auszug des entsprechenden HTML-
Codes ist wie folgt:
..
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.
cab#version=7,0,19,0" width="200" height="150" id="myswf">
<param name="movie" value="browserAnFlash01_var2.swf" />
<param name="quality" value="high" />
<param name="FlashVars" value="myVar=once again" />
<embed id="myswf" name="myswf" FlashVars="myVar=once again"
src="browserAnFlash01_var2.swf" width="200" height="150" quality="high"
pluginspage="http://www.macromedia.com/go/getflashplayer"
type="application/x-shockwave-flash"></embed>
</object>
..
Listing 5.9: Auszug aus dem Listing der Datei browserAnFlash_var2.php, das Sie auf der Website zum Buch
downloaden können.
ABBILDUNG 5.7
Ausgabe der Variante 2,
in Flash-Dateien
Variablenwerte zu setzen.
Wie Sie sehen, wird kein
Button mehr zum Setzen des
Variablenwerts benötigt – die
Variablen und zugehörigen
Werte werden als Attribute
in den entsprechenden Tags
<object> und <embed>
gesetzt.
C L I E N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 181
Der große Vorteil dieser Variante 2 ist, dass sie ohne weiteres in jedem halbwegs gän-
gigen Browser funktioniert und kein JavaScript benötigt wird. Nachteilig ist, dass sie
nicht interaktiv (also beispielsweise per Klick auf einen Button) verwendet werden
kann.
5.2 Daten senden: Flash an Browser
In diesem Abschnitt beschäftigen wir uns damit, wie Flash auf Clientseite mit seiner
Außenwelt Kontakt aufnehmen kann. Im nächsten Abschnitt widmen wir uns dann
der Frage, wie Flash auf Serverseite Daten übermitteln kann.
5.2.1 Kontaktaufnahme mit getURL
Gehen wir doch kurz auf die Frage ein, welche Möglichkeiten der Webentwickler in
Flash nutzen kann, damit Flash mit seinem „Äußeren“ – nämlich dem Browser – in
Kontakt tritt. Als Erstes würde uns hier wohl der Flash-Befehl getURL() einfallen, mit
dem man eine URL in einem Browser-Fenster oder einem Frame öffnen kann. Dieser
Befehl ist demnach mit einem Anker <a> in HTML vergleichbar.
Nach kürzerem (oder längerem) Nachdenken über die Möglichkeiten von Ankern in
HTML fällt uns ein, dass mithilfe des reservierten Worts javascript: im href-Attri-
but ein JavaScript-Befehl ausgeführt werden kann, also:
<a href="javascript:JavaScript-Befehl;">Klick mich</a>
oder in einem Beispiel:
<a href="javascript:alert(‚Hallo Welt!');">Klick mich</a>
JavaScript ausführen
Beim Klick auf diesen Link wird der JavaScript-Befehl alert() ausgeführt, der in
einem Meldefenster den Text „Hallo Welt!“ ausgibt. Das bedeutet also, dass HTML
mithilfe von Ankern doch in der Lage ist, JavaScript-Befehle auszuführen. Wenn also
dieses Tag vergleichbar mit dem Flash-Befehl getURL() ist, so liegt der Versuch nahe,
dies auch mit dem Flash-Befehl auszuprobieren. Gesagt, getan:
getURL("javascript:JavaScript-Befehl;");
ist exakt vergleichbar mit dem HTML-Befehl
<a href="javascript:JavaScript-Befehl;">…</a>
Sobald in getURL() im URL-Bereich javascript: eingegeben wird, wird an den
Browser eine JavaScript-Anfrage gesendet – so einfach ist die Kontaktaufnahme von
Flash mit dem Browser per JavaScript also! Testen wir unser neu erlangtes Wissen an
einem konkreten Beispiel.
K A P I T E L 5182
Schritt für Schritt: JavaScript-Funktion in Browser-Fenster über
Flash aufrufen
Ziel dieses Beispiels ist, dass durch Klicken auf einen Flash-Button eine JavaScript-
Funktion aufgerufen wird, die wiederum ein Meldungsfenster mit dem Text „Hallo
Außenwelt!“ öffnet.
Wenden wir uns zunächst Flash zu. Hier ist die Sachlage sehr einfach – benötigt wird
ein Button auf der Flash-Bühne, der beim Loslassen den getURL()-Befehl aufruft.
Dieser veranlasst wiederum das Ausführen von JavaScript-Code im Browser.
Der zugehörige Code für den Button ist also:
on(release) {
getURL("javascript:executeMyCode();");
}
Listing 5.10: Mehr an Code ist in Flash nicht nötig, um eine (externe) JavaScript-Funktion aufzurufen – die
Kommunikation zwischen Flash und JavaScript von Flash aus ist somit denkbar einfach.
1. ActionScript-
Code erstellen
1. ActionScript-
Code erstellen
ABBILDUNG 5.8
Die Abbildung zeigt den
Code aus dem obigen Listing
(angewandt auf den Button).
Alternativ hätte man auch
ein Script schreiben können,
das nicht dem Button zuge-
wiesen wird, sondern in der
Zeitleiste programmiert wird.
Für den Fall, dass Ihnen das Anbringen von Script-Code auf einen Button nicht so
„sympathisch“ ist (vgl. hierzu auch das Kapitel über die Grundlagen der Programmie-
rung), könnte man alternativ auch folgenden Code in die Zeitleiste der Bühne platzie-
ren (vorausgesetzt, Sie haben dem Button den Namen „callJS_btn“ gegeben):
C L I E N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 183
callJS_btn.onRelease = function():Void {
getURL("javascript:executeMyCode();");
}
Listing 5.11: Alternativer Code für die Abarbeitung eines Klicks auf den Flash-Button (genau genommen
handelt es sich um das Loslassen der Maustaste (onRelease), aber das wissen Sie ja bereits vom Grund-
lagenkapitel).
Mehr Arbeit fällt für die Flash-Abteilung auch schon nicht mehr an. Beachten Sie
jedoch bitte an dieser Stelle, dass sofern das Flash-Dokument nicht in einer Browser-
Umgebung getestet wird, das Aufrufen dieses Codes nicht funktioniert – die Testum-
gebung in Flash ist hier nicht ausreichend.
Bedeutet das Weniger an Arbeit in Flash nun ein Mehr an Arbeit in JavaScript im
HTML-Dokument, wo auch die Flash-Datei eingebunden ist? Mitnichten, auch in
JavaScript fällt der Arbeitsaufwand sehr gering aus:
<script language="javascript" type="text/javascript">
<!--
function executeMyCode() {
alert("Hallo Aussenwelt!");
}
//-->
</script>
Listing 5.12: JavaScript-Code, um die Anweisungen aus Flash heraus abarbeiten zu können.
2. JavaScript-
Code erstellen
2. JavaScript-
Code erstellen
ABBILDUNG 5.9
Wie Sie sehen, ist die obige
Schreibweise ebenso mög-
lich. Im Allgemeinen wird
diese Schreibweise auch
bevorzugt, da so der Code
übersichtlicher – da in der
Zeitleiste platziert – bleibt.
K A P I T E L 5184
Die aus Flash aufzurufende JavaScript-Funktion wird – wie üblich – zwischen den
HTML-Tags <script> und </script> definiert. Flash ist in der Lage, mithilfe des
Befehls getURL und dem verwendeten URL-Attribut mit beginnendem javascript:
direkt die JavaScript-Funktion aufzurufen.
ABBILDUNG 5.10
Das Ergebnis unserer Arbeit:
Flash hat eine JavaScript-
Funktion angesprochen.
5.3 Die ExternalInterface-Klasse –
Flash 8 und höher
Seit der Einführung von Flash 8 ist Flash in der Lage, besser und umfassender
mit JavaScript zu interagieren (versierte Leser wissen, dass dieses System auf dem
„JavaScript Integration Kit“ basiert, der erstmals für den Flash-Player r6.5 vorgestellt
wurde und somit eigentlich schon in früheren Versionen von Flash als „Add-On“
verfügbar war). Die Möglichkeit, von der hier gesprochen wird, ist die External-
Interface-Klasse – diese ermöglicht die Kommunikation einer Flash-Anwendung
mit irgendeiner anderen Anwendung, in der Flash eingebettet ist. In unserem Fall ist
diese „andere Anwendung“ eine HTML-Seite – es könnte jedoch auch eine beliebige
andere Anwendung (etwa eine Director-Umgebung) sein.
Vonseiten Adobe wird die Kommunikation zwischen ActionScript und JavaScript
über die ExternalInterface-Klasse empfohlen. Folgende Möglichkeiten stehen uns zur
Verfügung:
Flash an Browser: Von ActionScript aus können beliebige JavaScript-Funktionen
aufgerufen werden, und zwar mit einer beliebigen Anzahl an Übergabeparametern.
Des Weiteren ist ActionScript in der Lage, Rückgabewerte aus der aufgerufenen
JavaScript-Funktion zu erhalten.
u
C L I E N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 185
Browser an Flash: Von JavaScript aus können beliebige ActionScript-Funktionen
aufgerufen werden. Eventuelle Rückgabewerte der ActionScript-Funktion werden
direkt von der JavaScript-Funktion entgegengenommen.
Ein großer Vorteil der Verwendung der ExternalInterface-Klasse ist, dass sie von
allen gängigen Browsern unterstützt wird (Internet Explorer ab Version 5, Netscape
ab 8, Mozilla ab 1.7.5, Firefox ab 1.0, Safari ab 1.3). Nichtsdestotrotz bleibt es uns
natürlich nicht erspart, beim Ansprechen der SWF-Datei zwischen den Browsern
zu unterscheiden – hierzu haben wir uns im vorigen Kapitel „Einbinden von Flash“
Gedanken gemacht und ein allgemein gültiges Script entwickelt. Des Weiteren müssen
wir beachten, dass der Browser für die Verwendung dieser Klasse entweder ActiveX
oder die NPRuntime-API unterstützen muss.
Der Hauptvorteil dieser Klasse ist jedoch, dass von beiden Seiten aus (von Seiten
JavaScript und von Seiten ActionScript) Funktionen der jeweils anderen Technologie
aufgerufen werden können. Dies bringt nämlich auch mit sich, dass – entgegen unserer
bisherigen Kenntnis – man nicht mehr explizit auf das Setzen von Variablenwerten
warten muss, sondern direkt Funktionen aufgerufen werden können.
Wo liegt also der Nachteil dieser Klasse, wenn doch alles so toll scheint? Nun, zwei
Punkte könnte man als Nachteil anmerken: Zunächst einmal funktioniert diese Klasse
standardmäßig erst ab Flash 8 (ist das wirklich ein Nachteil, schließlich arbeiten wir
bereits mit Flash CS3, also dem Nachfolger von Flash 8?!). Außerdem bedeutet das
Arbeiten mit externen Klassen auch immer einen Mehraufwand in der Dateigröße
(wir werden jedoch sehen, dass sich der „Mehraufwand“ sehr in Grenzen hält, zumal
Übertragungszeiten für Dateien im Kbyte-Bereich nicht mehr wirklich ein Problem
darstellen).
Im Weiteren werden wir sehen, dass mit der Einführung von Flash CS3 und somit
ActionScript 3.0 einige Erweiterungen erfolgt sind – mehr dazu im ActionScript 3.0-
Teil dieses Kapitels.
5.3.1 ExternalInterface-Klasse
mit ActionScript 1.0/2.0
Wie bereits oben erwähnt, ermöglicht uns die ExternalInterface-Klasse das wech-
selseitige Aufrufen von Funktionen in sowohl JavaScript als auch ActionScript.
Bevor wir jedoch in medias res gehen können, müssen wir uns zunächst noch Gedan-
ken machen, wie wir die externe Klasse einbinden und ob die ExternalInterface-
Klasse von der „Gegenseite“ (also in unserem Fall ein XHTML-basiertes Dokument)
überhaupt unterstützt wird.
Die zu importierende Klasse trägt den Namen „ExternalInterface“ und ist eine Unter-
klasse von external, die wiederum eine Unterklasse der allgemeinen Klasse flash ist.
u
Vorteile!Vorteile!
Nachteile?Nachteile?
Importieren der
Klasse
Importieren der
Klasse
K A P I T E L 5186
Da ExternalInterface in ActionScript 2.0 die einzige Unterklasse von external
ist, lautet der geeignete Befehl zum Importieren somit:
import flash.external.*;
Alternativ wäre auch folgende Variante zulässig:
import flash.external.ExternalInterface;
Sobald der Import geschehen ist, stehen uns folgende Möglichkeiten der Klasse zur
Verfügung:
Eigenschaften
Eigenschaft Typ Beschreibung
available Boolean Gibt an,ob das Dokument,in dem die SWF-Datei
eingebunden ist,die ExternalInterface-
Klasse unterstützt.Diese Eigenschaft sollte
immer zuerst abgeprüft werden,bevor man
weitere Methoden und Eigenschaften der Klasse
benützt.
Bei true wird die Klasse unterstützt,bei false
nicht.
objectID String Gibt den Wert des name- bzw.id-Attributs zu-
rück:
Internet Explorer:Wert des id-Attributs im
<object>
Firefox (Mozilla-basierte Browser):Wert des
name-Attributs im <embed>
Beachten Sie bitte,dass Sie – wie schon des
Öfteren angemerkt – für das <object> aus-
schließlich das id-Attribut und für das <embed>
ausschließlich das name-Attribut verwenden.
Methode Attribute Beschreibung
addCallback :Boolean Registriert eine Funktion als„von JavaScript
aufrufbar“.Diese Methode muss verwendet wer-
den,um eine ActionScript-Funktion überhaupt
für JavaScript„verwendbar“ zu machen – wird
diese Methode für eine spezielle ActionScript-
Funktion nicht verwendet,kann JavaScript
diese Funktion nicht aufrufen.Deshalb:jede
„für JavaScript sichtbare“ Funktion mit dieser
Methode explizit angeben (registrieren).
Die Methode liefert den Wert true zurück,sollte
das Registrieren erfolgreich gewesen sein; an-
sonsten liefert sie false.
methodName:String Ein Name (kann auch ein„Alias“ sein) für die
Funktion,die JavaScript aufrufen kann.Dieser
Name muss nicht notwendigerweise mit dem
tatsächlichen Namen der ActionScript-Funktion
übereinstimmen.
instance:Object Hier kann ein spezielles Objekt angegeben
werden.Ist im Allgemeinen nicht notwendig,
deshalb wird zumeist der Wert null verwendet.
C L I E N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 187
method:Function Als drittes Attribut wird der tatsächliche Name
der ActionScript-Funktion angegeben.Bitte
beachten Sie,dass der Name der Funktion ohne
Anführungszeichen angegeben werden muss
(Typ:Function,nicht String).
call:* Ruft eine JavaScript-Funktion auf.Wie Sie
wissen,muss es sich nicht notwendigerweise
um JavaScript (in XHTML) handeln – viel-
mehr ruft die Methode call eine beliebige
Funktion in einem beliebigen„Container“
(bei uns:das XHTML-Dokument) auf,der das
ExternalInterface-API unterstützt.In unserem Fall
als Webdesigner ist es zumeist eben ein XHTML-
Dokument.
Der Rückgabewert der Funktion ist abhängig
von der Funktion selbst:
null:Es ist ein Fehler aufgetreten.
Andere Typen:Es ist kein Fehler aufgetreten.
Die möglichen Fehler werden weiter unten im
Abschnitt Browser an Flash an Browser ausführ-
lich erklärt.
functionName:String An dieser Stelle wird der Name der JavaScript-
Funktion angegeben,die von Flash aus aufgeru-
fen werden soll.
arguments:Object An die JavaScript-Funktion kann eine beliebige
Anzahl von Werten übergeben werden,wobei
die Werte durch Komma voneinander zu tren-
nen sind.Die Datentypen aus ActionScript wer-
den automatisch in Datentypen von JavaScript
überführt („marshalling“).
Tabelle 5.1: Mit diesen Eigenschaften und Methoden ausgestattet können wir ans Werk gehen.
Neben diesen Eigenschaften und Methoden der ExternalInterface-Klasse existie-
ren noch weitere (an diese Klasse vererbte) Eigenschaften und Methoden, die für uns
jedoch nicht wirklich wichtig sind – eine Übersicht derer finden Sie in der ActionS-
cript-Hilfe, wenn Sie im Komponenten-Referenzhandbuch die ExternalInterface
class nachschlagen.
Netterweise stellt uns Flash zum Überprüfen der Verfügbarkeit der Klasse also eine ein-
fache Möglichkeit zur Verfügung: die Eigenschaft available der ExternalInter-
face-Klasse. Sollte ein Abfragen dieser Eigenschaft true ergeben, sind wir sozusagen
„im Spiel“ und können die Klasse verwenden. Sollte wider Erwarten doch der Wert
false zurückgeliefert werden, so müssen wir den altbewährten Weg mit den anfangs
im Kapitel erlernten Fähigkeiten gehen.
Der grundlegende Scriptcode für das Arbeiten mit der ExternalInterface-Klasse
sieht dementsprechend wie folgt aus:
import flash.external.*;
if(ExternalInterface.available) {
ExternalInterface.
available
ExternalInterface.
available
K A P I T E L 5188
trace("EXTERNAL INTERFACE verfüg150
bar");
}
else {
trace("EXTERNAL INTERFACE NICHT verfügbar");
}
Listing 5.13: Das wichtige Codefragment zum Einbinden der ExternalInterface-Klasse (die trace-Befehle
können selbstverständlich auskommentiert werden)
Ein Wort zum Testen der Klasse
Bitte bedenken Sie, dass Sie die Möglichkeiten der ExternalInterface-Klasse nur dann
nutzen können, wenn Sie eine entsprechende „Umgebung“ vorfinden. Eine solche Umgebung ist
ein XHTML-Dokument in einem Browser mit den oben genannten Voraussetzungen (Versionen
beachten) oder eben die Entwicklungsumgebung von Flash. Wenn Sie also den obigen Code
testen und die Eigenschaft available immer false zurückgibt, dann ist kein entsprechender
Container vorhanden.
Browser an Flash Variante 2
Möchte man nun den Weg gehen und den Browser eine Flash-Funktion aufrufen las-
sen, so müssen drei Schritte vorgenommen werden:
1. Die entsprechende ActionScript-Funktion muss erzeugt werden.
2. Diese Funktion muss mithilfe der Methode addCallback freigegeben werden.
3. Die Funktion muss von JavaScript aus aufgerufen werden.
Sehen wir uns also die drei Schritte der Reihe nach an. Als Beispiel verwenden wir das-
jenige aus Abbildung 5.6, nur dass wir nun die ExternalInterface-Klasse bemühen.
Ziel des Beispiels ist es, dass per Klick auf einen Button eine JavaScript-Funktion auf-
gerufen wird, die wiederum eine in Flash vorhandene ActionScript-Funktion aufruft.
Die ActionScript-Funktion soll dann in einem dynamischen Textfeld denjenigen Wert
ausgeben, der von JavaScript an ActionScript übergeben wurde (in unserem Fall wird
es der Text „EXPLODE“ sein):
C L I E N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 189
Entgegen unserer Entwicklung aus dem Kapitel Browser an Flash werden nun in der
ActionScript-Datei nur noch zwei Bilder in der Zeitleiste benötigt (wobei wir es theo-
retisch auch auf ein Bild reduzieren könnten, wenn wir die Textfelder dynamisch
erzeugen):
ABBILDUNG 5.11
Die Flash-Anwendung befin-
det sich im „Wartezustand“
auf das Klicken des Buttons.
ABBILDUNG 5.12
Sobald geklickt wurde, wird
der Text „EXPLODE“ in einem
dynamischen Textfeld aus-
gegeben.
K A P I T E L 5190
Wenden wir uns zunächst dem Einbinden der ExternalInterface-Klasse und dem
Überprüfen der Verfügbarkeit zu (Aktionenebene):
var msg:mx.controls.TextArea; //TextArea initialisieren
msg.text = "Initialisiere...n"; //Text der TextArea zuweisen
import flash.external.*;
if(ExternalInterface.available) {
ABBILDUNG 5.13
Bild 1 unserer Flash-
Anwendung. Wie Sie sehen,
besteht das zweite Bild
lediglich noch aus anderen
Elementen in der Ebene
„Ausgabetext“ – die (wich-
tigen) Ebenen „Funktionen“
und „Aktionen“ beinhalten
keinerlei weiteren Code.
C L I E N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 191
msg.text += "EXTERNAL INTERFACE verfügbarn";
..
}
else {
msg.text += "EXTERNAL INTERFACE NICHT verfügbarn";
}
stop();
Listing 5.14: Importieren der ExternalInterface-Klasse und überprüfen, ob diese auch verfügbar ist.
In den ersten beiden Zeilen wird lediglich noch die auf der Bühne verwendete TextArea initialisiert und ihr
der Text „Initialisiere…“ mit einem folgenden Zeilenumbruch (n) zugewiesen. Die beiden Punkte „..“ deuten
an, dass an dieser Stelle noch weiterer Code eingefügt wird.
War das Einbinden erfolgreich und sind die benötigten Möglichkeiten verfügbar, so
wird der TextArea mit dem Namen „msg“ der Text „EXTERNAL INTERFACE verfüg-
bar“ zugewiesen. Gesetzt den unwahrscheinlichen Fall, dass es nicht geklappt hat, wird
der entsprechend andere Text ausgegeben.
Im nächsten Schritt definieren wir in der Funktionenebene diejenige Funktion, die
später aus JavaScript aus aufgerufen werden soll:
function jumpWithJS(myText:String):Void {
myVar = myText;
gotoAndStop("fertig");
}
Listing 5.15: Definieren der Funktion jumpWithJS, die per JavaScript aufgerufen wird. Der Funktion wird
ein Wert übergeben, der dann in einem dynamischen Textfeld (Variable myVar) angezeigt werden soll. Des
Weiteren wird in der Zeitleiste auf das Bild mit dem Namen „fertig“ gesprungen.
Schritt drei ist nun das Registrieren dieser ActionScript-Funktion für die Verwendung
durch JavaScript:
var msg:mx.controls.TextArea;
msg.text = "Initialisiere...n";
import flash.external.*;
if(ExternalInterface.available) {
msg.text += "EXTERNAL INTERFACE verfügbarn";
if(ExternalInterface.addCallback("tryIt",null,jumpWithJS)) {
msg.text += "Callback-Funktion ERFOLGREICH registriertn";
}
else {
msg.text += "Callback-Funktion NICHT erfolgreich registriertn";
K A P I T E L 5192
}
}
else {
msg.text += "EXTERNAL INTERFACE NICHT verfügbarn";
}
stop();
Listing 5.16: Mithilfe der Methode addCallback wird die (tatsächlich vorhandene) ActionScript-Funkti-
on jumpWithJS unter dem Pseudonym tryIt (mittels dieses Namens wird JavaScript auf die Funktion
zugreifen) im Objekt null registriert. War die Registrierung der Callback-Funktion erfolgreich, wird in der
darauffolgenden Zeile in die TextArea „msg“ eine entsprechende Meldung ausgegeben (dies gilt auch für
den Fall, dass die Registrierung nicht erfolgreich war).
Selbstverständlich können die tatsächliche Funktion (hier: jumpWithJS) und der
Aufrufname für JavaScript (hier: tryIt) gleich benannt werden – dieses Beispiel soll
lediglich demonstrieren, dass dies eben nicht notwendigerweise der Fall sein muss.
Damit ist die Flash-Entwicklung so weit abgeschlossen und wir können uns dem
XHTML- und JavaScript-Teil zuwenden. Zunächst wird die SWF-Datei wie gewohnt
in ein XHTML-Dokument eingebettet:
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.
cab#version=7,0,19,0" width="200" height="150" id="myswf">
<param name="movie" value="browserAnFlash02.swf">
<param name="quality" value="high">
<embed name="myswf" src="browserAnFlash02.swf" width="200"
height="150" quality="high" pluginspage="http://www.macromedia.com/go/
getflashplayer" type="application/x-shockwave-flash"></embed>
</object>
Listing 5.17: Einbetten der SWF-Datei, wobei wir wie immer darauf achten, dass das id-Attribut aus-
schließlich dem <object> und das name-Attribut ausschließlich dem <embed> zugewiesen wurde.
Auch unser bereits entwickeltes Script zum korrekten Ansprechen der SWF-Datei
kann ohne Einschränkungen übernommen werden:
function getFlashElement(elem) {
var app = navigator.appName.toLowerCase();
var nav = navigator.userAgent.toLowerCase();
if((app.indexOf("microsoft") != -1 || nav.indexOf("microsoft") != -1)
&& !Boolean(window["opera"])) {
return document.all[elem];
}
else {
C L I E N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 193
return document[elem];
}
}
Listing 5.18: Ansprechen der SWF-Datei mittels JavaScript – eins zu eins übernommen von dem Kapitel
Browser an Flash.
Der noch ausstehende Arbeitsschritt ist nun also nur noch, die ActionScript-Funktion
(beachte: diese Funktion hat das Pseudonym „tryIt“) per JavaScript aufzurufen. Hierzu
übernehmen wir ebenfalls die bereits entwickelte JavaScript-Funktion aus dem Kapitel
Browser an Flash und benennen sie von sendDataToFlash in sendDataToFlash2
um, da wir geringfügige Änderungen vornehmen: In Zeile drei des Scripts wird die
(ActionScript-)Funktion tryIt mit dem Übergabewert „EXPLODE“ aufgerufen.
function sendDataToFlash2() {
var myswf = getFlashElement("myswf");
myswf.tryIt("EXPLODE");
}
Listing 5.19: Über die JavaScript-Funktion sendDataToFlash2 wird die ActionScript-Funktion tryIt
(in Wirklichkeit heißt diese Funktion in Flash nicht tryIt, sondern jumpWithJS) mit dem Übergabewert
„EXPLODE“ aufgerufen.
Zu guter Letzt müssen wir noch dafür sorgen, dass unsere Funktion sendData-
ToFlash2 aufgerufen wird – hierzu bedienen wir uns eines XHTML-Buttons, der auf
Klick die Funktion aufruft:
<input type="button" value="Daten senden" onClick="sendDataToFlash2();" />
Listing 5.20: Ein Standard-XHTML-Button sorgt für den Aufruf der JavaScript-Funktion.
Damit sind wir fertig – mehr ist dann auch nicht mehr notwendig! Sobald Sie den
Button klicken, wird die JavaScript-Funktion sendDataToFlash2 aufgerufen, die
wiederum die ActionScript-Funktion tryIt (Pseudonym für jumpWithJS) mit
dem Übergabewert „EXPLODE“ aufruft. Dadurch wird innerhalb der Flash-Datei
die ActionScript-Funktion jumpWithJS angesprochen, die den Text „EXPLODE“ in
einem dynamischen Textfeld anzeigt, welches sich im Bild mit dem Namen „fertig“
befindet.
Als Erweiterung könnte man beispielsweise nicht einen fixen Wert (wie bei uns
„EXPLODE“) an Flash übergeben, sondern ein Eingabefeld in XHTML basteln und
den dort eingegebenen Wert an Flash übergeben. Um dies zu bewerkstelligen, muss
erst mal ein Textfeld her:
<input type="text" name="myText" id="myText" />
Danach muss die JavaScript-Funktion so angepasst werden, dass sie den Inhalt des
Textfelds ausliest und an die ActionScript-Funktion übergibt:
K A P I T E L 5194
var textToFlash = document.forms["frmExternalInterface"].
elements["myText"].value;
myswf.tryIt(textToFlash);
Listing 5.21: Zunächst wird eine Variable textToFlash angelegt, die den Inhalt des Formularfelds my-
Text im Formular frmExternalInterface ausliest. Der Inhalt von textToFlash wird dann mithilfe
des Funktionsaufrufs tryIt an Flash übermittelt.
Gesagt – getan. Hier das Ergebnis:
ABBILDUNG 5.14
Der im Formularfeld einge-
gebene Text „Hallo Welt“ wird
in Kürze an die Flash-Datei
übermittelt (siehe folgende
Abbildung).
ABBILDUNG 5.15
Der Text „Hallo Welt“ wurde
an Flash übermittelt und
im dynamischen Textfeld
angezeigt.
C L I E N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 195
Tipp: Testen Sie immer wieder in verschiedenen Browsern (Internet Explorer, Firefox,
Opera, Safari) die Funktionalität Ihrer Anwendungen – Ihre User werden es Ihnen mit
Sicherheit danken.
Können wir das somit erlangte Wissen nun auf andere Technologien anwenden? Die
Antwort ist eindeutig: ja! Die Türe steht nun sperrangelweit offen für AJAX-basierte
interaktive Anwendungen zwischen Flash und XHTML, denn mit dem Zeitpunkt, wo
man von JavaScript auf ActionScript-Funktionen zugreifen kann, muss Flash nicht
mehr – wie bisher – auf das Setzen einer Variable „warten“, sondern kann funktions-
basiert gesteuert werden. Wann diese Funktionen durch JavaScript aufgerufen werden
(beispielsweise nach dem Nachladen von Daten vom Server durch AJAX), ist nun
freigestellt.
Flash an Browser Variante 2
Betrachten wir den umgekehrten Fall, nämlich dass Flash eine JavaScript-Funkti-
on aufruft. Hierzu bedienen wir uns der ActionScript-Methode call, die von uns
(zumindest) den Namen der JavaScript-Funktion fordert, die aufgerufen werden soll.
Zusätzlich können (je nach Definition der JavaScript-Funktion) noch weitere Parame-
ter übergeben werden. Die allgemeine Syntax wäre:
ExternalInterface.call("Funktionsname", [Parameter1, Parameter2, ..]);
Bemühen wir das im Vorgängerkapitel Flash an Browser entwickelte Beispiel (Flas-
hAnBrowser_alternativ.fla – zu finden wie üblich auf der Buch-CD mit dem Namen
FlashAnBrowser02_alternativ.fla), wo wir mithilfe der Methode getURL auf eine
JavaScript-Funktion zugegriffen haben, so würden wir den Code zunächst um den
Import der ExternalInterface-Klasse erweitern (neben der Klasse wurde auch
noch – wie im letzten Beispiel – eine TextArea angelegt, um uns ausgeben zu lassen, ob
beim Import der Klasse alles geklappt hat):
var msg:mx.controls.TextArea;
msg.text = "Initialisiere...n";
import flash.external.*;
if(ExternalInterface.available) {
msg.text += "EXTERNAL INTERFACE verfügbarn";
}
else {
msg.text += "EXTERNAL INTERFACE NICHT verfügbarn";
}
Listing 5.22: Code zum Importieren der benötigten Klasse. Neben dem Import wurde noch eine TextArea
initialisiert – siehe auch nachfolgende Abbildung.
AJAX & Web 2.0?AJAX & Web 2.0?
K A P I T E L 5196
Dieser Teil war so weit ja schon aus dem vorigen Abschnitt bekannt. Interessanter wird
es, wenn wir den Code betrachten, der bei Klick auf den Button ausgeführt werden
soll:
callJS_btn.onRelease = function():Void {
msg.text+= ExternalInterface.call("executeMyCode2")+"n";
}
Listing 5.23: Aufruf der JavaScript-Funktion executeMyCode2. Es werden bis dato noch keine Werte an
die Funktion übergeben.
Der Befehl ExternalInterface.call("executeMyCode2") sorgt dafür, dass die
JavaScript-Funktion executeMyCode2 (diese muss selbstverständlich in der XHTML-
Datei vorhanden sein) aufgerufen wird. Da wir unsere JavaScript-Funktion so auslegen
werden, dass sie uns einen Wert zurückliefert, wird dieser Wert als Text der TextArea
hinzugefügt, n sorgt wie üblich für einen Zeilenumbruch innerhalb der TextArea.
Auch die JavaScript-Funktion muss gegenüber dem Ursprungsbeispiel nicht wesent-
lich verändert werden (um Verwechslungen zu vermeiden, habe ich die aufzurufende
Funktion von executeMyCode auf executeMyCode2 umbenannt):
function executeMyCode2() {
alert("Hallo Außenwelt!");
return "JavaScript-Antwort: OK";
}
Listing 5.24: Sobald die JavaScript-Funktion durch ActionScript aufgerufen wird, wird in einer Alert-Box
der Text „Hallo Außenwelt!“ ausgegeben und der Wert „JavaScript-Antwort: OK“ an ActionScript zurückge-
geben.
ABBILDUNG 5.16
Ein Blick auf die
Entwicklungsumgebung
zeigt, dass wir dem Beispiel
aus dem letzten Kapitel eine
TextArea hinzugefügt haben,
um diverse Statusmeldungen
ausgeben zu können.
Grundsätzlich würde man
die TextArea jedoch nicht
benötigen.
C L I E N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 197
Ein Test der Anwendung zeigt, dass wie zu erwarten war alles einwandfrei klappt:
Bitte beachten Sie, dass der Rückgabetext „JavaScript-Antwort: OK“ erst dann in der
TextArea von Flash erscheint, wenn Sie den OK-Button der Alert-Box geklickt haben,
da eine Alert-Box so lange das weitere Abarbeiten des Codes unterbricht, bis die Box
wieder geschlossen ist.
Nun erweitern wir unser bestehendes Beispiel um eine Parameterübergabe von Flash
an JavaScript. Konkret wollen wir zwei Parameter (eine Zahl und einen String) an
JavaScript übermitteln. Um zu sehen, dass die übergebene Zahl auch wirklich eine
Zahl ist, werden wir sie mit zwei multiplizieren – sollte das klappen, handelt es sich
mit Sicherheit um eine Zahl!
Zunächst adaptieren wir den call-Aufruf:
callJS_btn.onRelease = function():Void {
msg.text+= ExternalInterface.call("executeMyCode2",23.5,"Uwe Mutz")+"n";
}
Listing 5.25: Erweiterung des Codes um die Parameter 23.5 (Zahl) und „Uwe Mutz“ (Text) – die entsprechen-
de Datei lautet FlashAnBrowser03_alternativ.fla und findet sich auf der Buch-CD wieder.
Danach erweitern wir die JavaScript-Funktion, sodass die übergebene Zahl mit zwei
multipliziert und gemeinsam mit dem übergebenen Text in der Alert-Box ausgegeben
wird:
function executeMyCode2(myNumber,myText) {
var msg = 2*myNumber+" / "+myText;
Parameter-
übergabe an
JavaScript
Parameter-
übergabe an
JavaScript
ABBILDUNG 5.17
Flash nimmt Kontakt mit
JavaScript auf.
K A P I T E L 5198
alert(msg);
return "JavaScript-Antwort: OK";
}
Listing 5.26: An die JavaScript-Funktion werden zwei Parameter (myNumber und myText) übergeben.
myNumber wird mit zwei multipliziert und dann gemeinsam mit myText in der Variable msg gespeichert,
welche danach in der Alert-Box ausgegeben wird.
Browser an Flash an Browser
Nun machen wir die Probe aufs Exempel und übergeben von JavaScript an Flash
einen Wert, der dann auf Knopfdruck (warum nur „auf Knopfdruck“ und nicht gleich
direkt, werden wir noch klären müssen – Thema „Rekursion“) von Flash erweitert und
an JavaScript zurückgegeben wird. Den zu übergebenen Wert werden wir aus einem
Eingabefeld lesen, den zurückgegebenen Wert einem Textfeld anhängen. Der fertige
Aufbau sieht dann folgendermaßen aus:
ABBILDUNG 5.18
Die übergebene Zahl (in
unserem Fall: 23.5) wird
mit zwei multipliziert:
Das Ergebnis lautet 47.
Gemeinsam mit dem über-
gebenen Text („Uwe Mutz“)
wird sie in einer Alert-Box
ausgegeben.
C L I E N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 199
Der Ablauf wird also wie folgt vor sich gehen:
1. In das Eingabefeld wird Text eingegeben und nach Klick auf den Button „Daten
senden“ an Flash übergeben.
2. Flash empfängt den übermittelten Text und stellt diesen in der TextArea dar.
3. Bei Klick auf den Button „Zurück an JS…“ wird der übergebene Text wieder an
JavaScript zurückgeschickt und im Ausgabebereich angezeigt.
So weit der Plan. Der XHTML-Teil wird uns wenig Kopfzerbrechen machen, denn bis
auf zwei Felder und eine eingebettete SWF-Datei ist nicht viel zu tun:
...
<form name="frmExternalInterface" id="frmExternalInterface"
method="post" action="">
<input type="text" name="myText" id="myText" />
<input type="button" value="Daten senden" onclick="sendDataToFlash2();" />
</form>
...
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.
cab#version=7,0,19,0" width="300" height="200" id="myswf">
<param name="movie" value="browserAnFlashAnBrowser.swf">
<param name="quality" value="high">
<embed name="myswf" src="browserAnFlashAnBrowser.swf" width="300"
ABBILDUNG 5.19
Ein Eingabefeld zum
Versenden von Text an
Flash, eine TextArea
und ein „Zurücksende“-
Button in Flash sowie ein
Ausgabebereich (readonly)
für die von Flash gesandten
Daten.
K A P I T E L 5200
height="200" quality="high" pluginspage="http://www.macromedia.com/go/
getflashplayer" type="application/x-shockwave-flash"></embed>
</object>
...
<form name="frmExternalInterface2" id="frmExternalInterface2"
method="post" action="">
<textarea name="myText2" cols="30" rows="10" id="myText2"
readonly="readonly"></textarea>
</form>
...
...
Listing 5.27: Auszug aus dem XHTML-Listing. Es werden die Felder myText (Eingabe) und myText2 (Aus-
gabe) erzeugt sowie wie üblich die SWF-Datei eingebettet. Die Formularelemente sind von zwei Formularen
frmExternalInterface und frmExternalInterface2 umgeben.
Auch die JavaScript-Funktionen werden uns keine Kopfzerbrechen bereiten, denn da
ist alles wie gehabt – einzig die Ausgabe des von Flash zurückgelieferten Textes bedarf
einer zusätzlichen JavaScript-Programmierung:
function sendDataToFlash2() {
var myswf = getFlashElement("myswf");
var textToFlash = document.forms["frmExternalInterface"].
elements["myText"].value;
myswf.tryIt(textToFlash);
}
function executeMyCode2(textFromFlash) {
document.forms["frmExternalInterface2"].elements["myText2"].value +=
"AS says: "+textFromFlash+"n";
return "OK";
}
Listing 5.28: Einzig die Ausgabe in eine <textarea> namens myText2 ist noch mehr oder weniger
unbekannt.
Vielleicht ist Ihnen aufgefallen, dass wir uns zweier Formulare bedienen. Dies resul-
tiert aus dem Grund, dass der Internet Explorer beim Verwenden des Adobe-Scripts
zum Einbetten von SWF-Dateien (AC_RunActiveContent.js) so seine Probleme hat,
wenn dieser Code innerhalb eines Formulars steht. Deshalb der Tipp: Teilen Sie Ihren
XHTML-Code so auf, dass der Scriptaufruf AC_FL_RunContent(..) sich nicht
innerhalb eines umgebenden <form> befindet.
Weiter zu Flash & ActionScript. Der Bühnenaufbau von Flash ist denkbar einfach, da
wir nur noch ein Bild in der Zeitleiste benötigen. An dieser Stelle möchte ich jedoch
AC_FL_
RunContent(..)
nicht zwischen
<form> und
</form>
AC_FL_
RunContent(..)
nicht zwischen
<form> und
</form>
C L I E N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 201
wieder einmal in Erinnerung rufen, dass man die Ebenen der Bühne so übersichtlich
wie möglich gestalten sollte. Den Hardcore-Programmierern unter uns wird dies wohl
ein bisschen Kopfschütteln abverlangen („Eine einzige Ebene würde auch ausreichen,
da ja alle Elemente auch per ActionScript erzeugt werden könnten!“), jedoch ist dieses
Buch als Einsteigerbuch gedacht und deshalb auch so aufgebaut, dass Einsteiger die
Beispiele so übersichtlich wie nur möglich vorfinden. Und „falsch“ ist es keineswegs
– es wäre eben nur ein wenig „reduzierter“ auch möglich.
Wie dem auch sei, hier die zusammengeräumte Bühne:
ABBILDUNG 5.20
„As aufgeräumt as possible“
Die Aktionenebene beinhaltet wie gewohnt den Import der ExternalInterface-
Klasse und deren Verwendung inklusive Callback-Registrierung sowie den Event-
Handler für das Klicken des Buttons:
var msg:mx.controls.TextArea;
msg.text = "Initialisiere...n";
var lastMsg:String = "(bisher nichts von JS erhalten..)";
import flash.external.*;
if(ExternalInterface.available) {
msg.text += "EXTERNAL INTERFACE verfügbarn";
if(ExternalInterface.addCallback("tryIt",null,calledByJS)) {
K A P I T E L 5202
msg.text += "Callback-Funktion ERFOLGREICH registriertn";
}
else {
msg.text += "Callback-Funktion NICHT erfolgreich registriertn";
}
}
else {
msg.text += "EXTERNAL INTERFACE NICHT verfügbarn";
}
callJS_btn.onRelease = function():Void {
var returnedFromJS = ExternalInterface.call("executeMyCode2",lastMsg);
if(returnedFromJS==null) { msg.text+= "after AS sent-> JS returned an
ERRORn"; }
else { msg.text+= "after AS sent-> JS returns: "+returnedFromJS+"n";
}
}
Listing 5.29: Die Aktionenebene beinhaltet den Import der ExternalInterface-Klasse sowie den not-
wendigen Aufruf addCallback (Registrieren der Funktion calledByJS unter dem Pseudonym „tryIt“
für den Aufruf durch JavaScript) sowie call (Aufruf einer JavaScript-Funktion durch ActionScript).
Zusätzlich hinzugekommen sind lediglich zwei Punkte: Erstens, dass wir den Rückga-
bewert der Methode call nach dem Aufruf einer JavaScript-Funktion in einer Vari-
able returnedFromJS speichern und diesen dann in einer if-Anweisung auswerten:
Sollte der Rückgabewert null sein, so ist ein Fehler aufgetreten, der mehrere Gründe
haben kann:
Die aufgerufene JavaScript-Funktion (hier: executeMyCode2) existiert nicht: Pro-
grammiererfehler … Sehen Sie nach, ob die JavaScript-Funktion tatsächlich unter
dem Namen aufrufbar ist, den Sie verwenden.
Die API (Anwendungsprogrammierungs-Schnittstelle) auf Browser-Seite zum
Arbeiten mit der ExernalInterface-Klasse ist nicht vorhanden: Dies ist im
Allgemeinen nur dann der Fall, wenn der Browser des Users die am Anfang des
Kapitels aufgelisteten Mindestanforderungen nicht erfüllt. Da jedoch jeder halb-
wegs gängige Browser diese Hürde mit Leichtigkeit überwindet, tritt dieser Fehler
relativ selten auf.
Es ist eine Rekursion aufgetreten: Rekursionen sind im Allgemeinen genau
das Problem, das am häufigsten auftritt. Sie sind auch der Grund, warum eine
automatische Rückmeldung von Flash an den Browser nicht funktioniert: Ruft
u
u
u
C L I E N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 203
JavaScript eine ActionScript-Funktion auf und ruft ActionScript wiederum eine
JavaScript-Funktion auf, die von sich aus wiederum eine Antwort an ActionScript
zurückliefert, erweckt es den Anschein einer Rekursion (in Wirklichkeit ist es keine
Rekursion, aber Flash behauptet es zumindest).
Es ist ein Sicherheitsproblem aufgetreten: Dies ist normalerweise innerhalb eines
Browsers nicht der Fall, es sei denn, Sie arbeiten Domain-übergreifend. Hier schafft
die Methode allowDomain der security-Klasse Abhilfe. Schlagen Sie in der
ACTIONSCRIPT-REFERENZ unter security.allowDomain nach.
Da man nicht genau eruieren kann, wodurch der Fehler aufgetreten ist (eine aus-
führliche Fehlerbehandlungsmöglichkeit existiert erst ab ActionScript 3.0), wird von
unserem Script nicht mehr als ein „after AS sent-> JS returned an ERROR“ ausgegeben
– eine Fehlersuche (sollte wirklich ein Fehler auftreten) bliebe uns an dieser Stelle nicht
erspart.
Der zweite hinzugekommene Punkt ist eine (globale, da auf der Hauptzeitleiste
erzeugte) Variable lastText, die den zuletzt von JavaScript gesandten Text speichert
und so für die Rückgabe nach Klick auf den Button „Zurück an JS...“ bereithält. Der
jeweils aktuelle Wert dieser Variable wird in der Funktion calledByJS gespeichert, die
sich wie folgt darstellt:
function calledByJS(myText:String):Void {
msg.text+= "JS says: "+myText+"n";
var returnToJS:String = "OK: "+myText;
lastMsg = myText;
}
Listing 5.30: Auch diese Funktion ist bereits hinlänglich bekannt – hinzugefügt wurde, dass der zuletzt von
JavaScript gesandte Text in der Variable lastMsg gespeichert wird.
Das fertige Beispiel finden Sie wie üblich auf der Buch-CD unter dem Namen brow-
serAnFlashAnBrowser.fla sowie browserAnFlash_var3b.php.
u
K A P I T E L 5204
Flash an Browser an Flash
Nun sehen wir uns die umgekehrte Richtung an: ActionScript sendet eine Message an
JavaScript, welches wiederum eine Rückmeldung an ActionScript schickt. In diesem
Fall werden wir das Problem einer Rekursion nicht vorfinden, da die Rückmeldung
von JavaScript an Flash systembedingt erlaubt ist.
Dieser Fall ist wesentlich einfach als der vorige, da ActionScript von JavaScript in
jedem Fall eine Rückmeldung erhält, nachdem ActionScript eine JavaScript-Funktion
aufgerufen hat – die ActionScript-Funktion call sorgt hierfür.
Damit reduziert sich der JavaScript-Code auf:
function executeMyCode2(textFromFlash) {
return "OK, got '"+textFromFlash+"'";
}
Listing 5.31: Die Funktion executeMyCode2 wird wie üblich diejenige Funktion sein, die von ActionScript
aufgerufen wird. Sobald dies geschehen ist, liefert sie den an Sie übergebenen Wert inklusive des Textes
„OK, got“ wieder zurück an Flash. Dies demonstriert sehr schön, wie ActionScript und JavaScript aus Rich-
tung ActionScript zusammenarbeiten.
Auch der ActionScript-Code ist wesentlich einfacher, da wir im Gegensatz zum vorigen
Beispiel erstens keine Callback-Funktion mehr definieren und diese zweitens somit
auch nicht mehr registrieren müssen. Einzig die Ein- und Ausgabefelder in Form von
TextAreas sind mehr geworden – siehe Abbildung:
ABBILDUNG 5.21
Der Text „teste mich!“ wird
nach Klick auf „Daten sen-
den“ an Flash geschickt, dort
in der TextArea angezeigt.
Nach Klick auf „Zurück
an JS...“ wird der Text „AS
says: teste mich!“ in die
<textarea> (XHTML)
geschrieben und von
JavaScript die Meldung „OK“
an Flash zurückgeschickt,
welche wiederum in der
(Flash-)TextArea angezeigt
wird. Basta!
C L I E N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 205
var msgStatus:mx.controls.TextArea;
msgStatus.text = "Initialisiere...n";
var msgIn:mx.controls.TextArea;
msgIn.text = "";
var msgOut:mx.controls.TextArea;
msgOut.text = "(type message)";
import flash.external.*;
if(ExternalInterface.available) {
msgStatus.text += "EXTERNAL INTERFACE verfügbarn";
}
else {
msgStatus.text += "EXTERNAL INTERFACE NICHT verfügbarn";
}
callJS_btn.onRelease = function():Void {
var sendMsg:String = msgOut.text;
var returnedFromJS = ExternalInterface.call("executeMyCode2",sendMsg);
msgStatus.text += "AS says: "+sendMsg+"n";
if(returnedFromJS==null) { msgIn.text+= "after AS sent-> JS returned
an ERRORn"; }
ABBILDUNG 5.22
Wie man schön sehen
kann, befindet sich in
der Funktionenebene
kein Inhalt mehr, da wir
keine Funktionen mehr
benötigen. Die Anzahl der
TextAreas hat sich erhöht,
da wir eine TextArea für die
Statusmeldungen, eine für
den Eingabetext und eine
für die Rückmeldungen von
JavaScript an ActionScript
verwenden.
K A P I T E L 5206
else { msgIn.text+= "after AS sent-> JS returns: "+returnedFromJS+"
n"; }
}
Listing 5.32: Code der Aktionenebene: Es werden insgesamt drei TextAreas definiert – msgStatus für
Statusmeldungen, msgIn für von JavaScript an ActionScript gesandte Rückmeldungen und msgOut für
den Eingabetext, der an JavaScript gesandt wird. Bei Klick auf den Button wird der vom User eingegebene
Text in der Variable sendMsg zwischengespeichert, dann zunächst an JavaScript gesandt und danach in
das Statusfeld als „an JS versendet“ ausgegeben.
Zunächst werden die drei TextAreas„msgStatus“,„msgIn“ und„msgOut“ definiert und
die ExternalInterface-Klasse importiert. Wie üblich überprüfen wir, ob die API
im Browser verfügbar ist. Die eigentliche „Intelligenz“ liegt diesmal im Event-Handler
des Buttons:
Zunächst wird der vom User eingegebene Text in einer Variable sendMsg zwischen-
gespeichert.
Über die Methode call der ExternalInterface-Klasse wird die JavaScript-Funktion
executeMyCode2 aufgerufen und dieser der Wert der zuvor gespeicherten Variable
sendMsg übergeben. Der Rückgabewert der JavaScript-Funtkion wird danach in
der Variable returnedFromJS gespeichert.
Je nachdem, ob der JavaScript-Rückgabewert null oder nicht null war, wird
unterschiedlich weiterverfahren:
Bei null ist ein Fehler aufgetreten – welche Gründe für Fehler existieren, haben
wir im Kapitel Browser an Flash an Browser ausführlich behandelt.
Falls der Rückgabewert ungleich null ist, wird der von JavaScript zurückgelie-
ferte Wert in der TextArea msgIn ausgegeben.
Das getestete Beispiel sehen Sie in der nachfolgenden Abbildung:
u
u
u
u
u
C L I E N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 207
5.3.2 ExternalInterface-Klasse mit ActionScript 3.0
Bei Verwendung von ActionScript 3.0 hat sich bei den beiden Methoden addCallback
und call etwas geändert:
Methode Beschreibung
addCallback(Pseudonym:String,
AS-Funktion:Function):void
Gegenüber der addCallback-Methode in ActionScript 2.0 exis-
tiert der Instanz-Parameter nicht mehr.Außerdem liefert die
Funktion nach dem Aufruf keinen Wert mehr zurück.
call(JS-Funktion:String,
Parameter:Object):*
Sollte beim Aufruf der JavaScript-Funktion ein Fehler auftreten,so
wird entweder ein System- oder ein Security-Fehler erzeugt.Somit
besteht die Möglichkeit einer besseren Fehleranalyse.Der Wert
null würde bei einem Fehler in jedem Fall zurückgeliefert werden.
Tabelle 5.2: Änderungen der ExternalInterface-Klasse von ActionScript 2.0 auf 3.0
Wie wir also sehen, birgt ActionScript 3.0 keine herausragenden Neuerungen für uns.
Und in Hinblick auf die Tatsache, dass es nicht Teil dieses Buchs ist, sich in die Tiefen
von ActionScript 3.0 zu begeben, werde ich an dieser Stelle dem Gesagten auch nichts
hinzufügen, sondern vielmehr auf die hervorragende Literatur zu AS 3.0 im Addison-
Wesley Verlag hinweisen:
„ActionScript 3.0“ von Selma-Caroline Kannengießer und Matthias Kannengießer,
ISBN 978-3827325365
Wenden wir uns also wieder dem eigentlichen und grundlegenderen Thema zu: Flash
& AJAX. Wie im vorigen Kapitel angekündigt, packen wir den Stier bei den Hörnern,
reißen ihn zu Boden und warten ab.
u
ABBILDUNG 5.23
Es klappt – der von Flash
an JavaScript übermit-
telte Text „teste auch
mich!“ wird von JavaScript
empfangen und wieder
an Flash zurückgeliefert.
Das Beispiel liegt auf der
Buch-CD unter den Namen
FlashAnBrowserAnFlash.fla
sowie flashAnBrowser04.
htm zum Testen für Sie
bereit.
K A P I T E L 5208
5.4 Flash & AJAX
Gehen wir in Medias Res. Wir wollen uns nun die Frage stellen, wie man das erwor-
bene Wissen rund um unsere „Flash-Browser- bzw. Browser-Flash-Kommunikation“
mit dem vorigen Kapitel über AJAX kombinieren kann.
Halten wir kurz fest:
1. Flash kann (mithilfe von getURL oder der ExternalInterface-Klasse) mit dem
Browser kommunizieren: Es können JavaScript-Funktionen aufgerufen und an sie
Variablenwerte übergeben werden.
2. Ein Browser kann mit Flash kommunizieren:
1. Mithilfe von setVariable können von einem Browser aus Variablenwerte
gesetzt werden.
2. Binden wir die ExternalInterface-Klasse ein, sind wir sogar in der Lage,
(freigegebene) Funktionen in Flash aufzurufen und an diese Variablen zu
übergeben.
3. Nachdem AJAX auf Browser-Seite arbeitet und somit ebenso Flash-Funktionen
aufrufen kann,sind wir somit auch in der Lage,beispielsweise nach einem erfolgten
Laden von (zusätzlichen) serverseitigen Daten diese an Flash weiterzugeben.
Hierzu ein kleines Diagramm, um unsere Idee grafisch festzuhalten:
ABBILDUNG 5.24
AJAX kommuniziert mit dem
Server und mit Flash.
C L I E N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 209
5.4.1 Parameterübergabe:Text
In diesem Teil des Flash & AJAX-Kapitels befassen wir uns mit der Übergabe von
textbasierten Daten an Flash, im folgenden Kapitel werden wir statt Text- dann XML-
Daten an Flash übergeben.
Wir starten mit einer kleinen Anwendung, wo Sie die Interaktion von Flash und AJAX
grafisch dargestellt sehen: Mithilfe einer kleinen „Ampel“ werden wir in Flash die
AJAX-Kommunikation mit dem Server einerseits und Flash andererseits darstellen.
Die Funktionsweise soll folgende sein:
1. Wir basteln eine XHTML-Seite, die drei Buttons beinhaltet:
Initialisieren-Button: Wird auf diesen Button geklickt, wird das XMLHttp-
Request-Objekt als Instanz angelegt und ihr ein Eventhandler zugewiesen.
Öffnen-Button: Mithilfe dieses Buttons wird die Verbindung geöffnet, jedoch
noch nicht abgeschickt.
Senden-Button: Bei Klick wird die Anfrage an den Server abgeschickt.
2. Jeder (messbare) Zustand der XMLHttpRequest-Instanz soll in Flash in Form
einer Art „Ampel“ angezeigt werden:
Ampel ist rot: AJAX-technisch ist noch nichts passiert.
Ampel ist orange: Die XMLHttpRequest-Instanz hat eine Verbindung zum
Server geöffnet. In diesem Fall trägt die Eigenschaft readyState der Instanz
den Wert 1.
Ampel ist gelb: readyState hat den Wert 2 erreicht.
Ampel ist dunkelgrün: readyState hat den Wert 3 erreicht.
Ampel ist leuchtend grün: readyState ist nun auf den Wert 4 gewechselt, der
uns kennzeichnet, dass die Anfrage erfolgreich stattgefunden hat und wir nun
mit den erhaltenen Daten arbeiten können.
3. Ist die Anfrage abgeschlossen, soll der zurückgegebene Text (= Inhalt der Datei
testrequest.txt) an Flash übergeben und in der TextArea angezeigt werden.
Der Clou an dem Beispiel ist, dass wir unser erworbenes Wissen nur mehr zusammen-
fügen müssen, da wir folgende Punkte bereits wissen:
1. Wir wissen, wie die AJAX-Kommunikation mit dem Server vor sich geht.
2. Wir wissen, wie die Kommunikation zwischen JavaScript und Flash vor sich geht.
Was bleibt also zu tun? Um jeden Zustand der readyState-Eigenschaft in Flash
anzuzeigen, müssen wir im Eventhandler der XMLHttpRequest-Instanz für jeden
u
u
u
u
u
u
u
u
K A P I T E L 5210
der Zustände eine Flash-Funktion aufrufen – dazu werden wir auf die External-
Interface-Klasse in Flash zurückgreifen. Ebenso verhält es sich mit der Anzeige des
vom Server (durch die Datei testrequest.txt, die wir vom Server per AJAX anfordern)
zurückgelieferten Textes: Wiederum rufen wir eine Flash-Funktion auf, die den Rest
erledigt.
Wir können die Aufgabe in drei Teile unterteilen:
Das XHTML-Dokument mit den Buttons.
Den AJAX-(JavaScript-)Teil, der einerseits die Datei testrequest.txt vom Server
anfordert und andererseits mit Flash kommuniziert.
Den Flash-Teil, der eine TextArea für die Ausgabe des Textes und unsere Ampel für
die Anzeige der Zustände von readyState beinhaltet.
Zur besseren Veranschaulichung finden Sie nachfolgend einen Screenshot, der das
Ausgangsszenario widerspiegelt:
u
u
u
Der XHTML-Teil ist denkbar einfach, da im Wesentlichen nur die drei Buttons von
Interesse sind:
...
<input name="btnInit" type="submit" id="btnInit" value="Initialisieren"
onclick="initXHR();" />
<input name="btnOpen" type="button" id="btnOpen" value="&Ouml;ffnen"
onclick="openXHR();" />
ABBILDUNG 5.25
Unser Beispiel beinhaltet
drei Buttons (Initialisieren,
Öffnen und Senden) sowie
eine SWF-Datei für die
Anzeige von einerseits einem
(Rückgabe-)Text und ande-
rerseits einer kleinen „Ampel“.
C L I E N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 211
<input name="btnSend" type="submit" id="btnSend" value="Senden"
onclick="sendXHR();" />
...
Listing 5.33: Im XHTML-Teil werden über drei Buttons drei verschiedene Funktionen initXHR, openXHR
und sendXHR aufgerufen.
Befassen wir uns also gleich einmal mit dem JavaScript- und AJAX-Part. Die drei Funkti-
onen initXHR, openXHR und sendXHR, die durch Klick auf die drei Buttons aufgerufen
werden, initialisieren, öffnen und versenden die Anfrage an den Server. Zuvor wird in
Zeile 1 des Scripts noch eine Variable für die XMLHttpRequest-Instanz angelegt:
var myXMLHttpRequest;
function initXHR() {
myXMLHttpRequest = createRequestObject();
myXMLHttpRequest.onreadystatechange = handleRequest;
}
function openXHR() {
myXMLHttpRequest.open("GET", "testrequest.txt", true);
}
function sendXHR() {
myXMLHttpRequest.send(null);
}
Listing 5.34: Drei Funktionen für drei Aufgaben: Initialisieren, Öffnen und Abschicken. Zu Beginn wird noch
eine Variable myXMLHttpRequest für die spätere XMLHttpRequest-Instanz angelegt.
Die Funktion createRequestObject aus der Funktion init ist uns aus dem vorigen
Kapitel über AJAX noch gut in Erinnerung, deshalb halte ich mich bei der Beschrei-
bung relativ kurz:
function createRequestObject() {
try { var myRequest = new XMLHttpRequest(); }
catch(error) {
try { var myRequest = new ActiveXObject("MSXML2.XMLHTTP"); }
catch(error) { var myRequest = new ActiveXObject("Microsoft.
XMLHTTP"); }
}
return myRequest;
}
Listing 5.35: createRequestObject sorgt je nach verwendetem Browser für die korrekte Initialisierung
der XMLHttpRequest-Instanz.
K A P I T E L 5212
createRequestObject funktioniert nach dem „Trial and Error“-Prinzip: Klappt ein
Codefragment (damit ist gemeint, dass beim Ausführen des Codefragments kein Feh-
ler aufgetreten ist), das sich innerhalb einer try-Anweisung befindet, wird der catch-
Abschnitt nicht mehr ausgeführt. Klappt es hingegen nicht, wird der catch-Teil
ausgeführt. In unserer Funktion werden somit nach und nach alle Möglichkeiten des
Instanzierens eines XMLHttpRequest-Objekts durchprobiert, bis ein Versuch geklappt
hat. Details dazu finden Sie im Kapitel über AJAX. Das schlussendlich korrekt instan-
zierte Objekt wird mit der return-Anweisung an den Aufrufer zurückgeliefert.
Neben der Instanzierung wird im nächsten Schritt der soeben geschaffenen Instanz ein
Eventhandler handleRequest für das Ereignis onreadystatechange zugewiesen.
Diesem Eventhandler widmen wir uns weiter unten noch.
In der Funktion openXHR wird die Instanz myXMLHttpRequest aufgefordert, eine
Verbindung zur serverseitigen Datei testrequest.txt per GET herzustellen.
Die Funktion sendXHR sorgt dann dafür, dass die geöffnete (aber noch nicht abge-
schickte) Verbindungsanforderung auch abgeschickt wird.
Der Eventhandler handleRequest ist der eigentlich interessante Teil für die Kom-
munikation mit Flash: Bei jeder Zustandsänderung (spiegelt sich in der Eigenschaft
readyState der XMLHttpRequest-Instanz wider) wird diese Funktion aufgerufen.
Die switch-Anweisung hilft uns dabei, die fünf möglichen Zustände zu verarbeiten:
function handleRequest() {
var mySWF = getFlashElement("myswf");
switch(myXMLHttpRequest.readyState) {
case 0:
case 1:
case 2:
case 3: mySWF.showState(myXMLHttpRequest.readyState); break;
case 4: mySWF.showState(myXMLHttpRequest.readyState); mySWF.showRet
urnedText(myXMLHttpRequest.responseText); break;
}
}
Listing 5.36: Zunächst finden wir durch den Funktionsaufruf getFlashElement eine korrekte Referen-
zierung auf die SWF-Datei, danach kümmern wir uns darum, die readyState-Eigenschaft auszuwerten.
Wie oben erwähnt soll der Eventhandler das bindende Glied zwischen AJAX und Flash
darstellen – aus diesem Grund stellen wir eine Referenz zur SWF-Datei mit der ID
(dem Namen) myswf her. Dies geschieht mittels der Funktion getFlashElement, die
aus Listing 5.6 bekannt ist. Danach werten wir die Eigenschaft readyState aus: Für
die Fälle 0–3 rufen wir eine Flash-Funktion namens showState auf, der wir den Wert
von readyState übergeben (Flash wird diesen Wert in Form der angesprochenen
C L I E N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 213
Ampel ausgeben). Ist readyState==4, hat der Server sämtliche angeforderten Daten
zurückgeliefert – auch dieser Zustand soll von unserer Ampel angezeigt werden, des-
halb rufen wir wie auch zuvor showState aus. Des Weiteren wollen wir die Rückgabe
vom Server aber auch noch in einer TextArea anzeigen lassen, weshalb die Funktion
showReturnedText zum Einsatz kommt.
Kommen wir also zu Flash und seinen (freigegebenen) Funktionen:
function showReturnedText(myText:String):Void {
msg.text+= "AJAX says: "+myText+"n";
}
function showState(readyState:Number):Void {
msg.text+= "readyState: "+readyState+"n";
mcAmpel.gotoAndStop(readyState+1);
}
Listing 5.37: Die Flash-Funktionen showReturnedText und showState sorgen für die (grafische wie
textuelle) Ausgabe.
Es war anzunehmen, dass diese beiden Funktionen denkbar einfach sind, da es einer-
seits nur um die Ausgabe von Text oder andererseits das Ansprechen eines MovieClips
geht. showState gibt zunächst den (übergebenen) Wert von readyState in der
TextArea aus und spricht dann den MovieClip mcAmpel an. Je nach Wert von ready-
State werden ein, zwei, drei, vier oder fünf Ampellichter angezeigt – die Zwiebelscha-
lendarstellung des MovieClips zeigt dies:
ABBILDUNG 5.26
Die „Ampel“ in der Zwiebel-
schalendarstellung. Pro Bild
in der Zeitleiste kommt ein
Satz an „Lampen“ hinzu.
K A P I T E L 5214
Um die Funktionen showState und showReturnedText für JavaScript (oder letztens
AJAX) verfügbar zu machen, müssen sie noch freigegeben werden. Aus Kapitel 5.3 ken-
nen wir den Vorgang zwar, jedoch ist eine kleine Wiederholung nicht schlecht:
...
import flash.external.*;
if(ExternalInterface.available) {
msg.text += "EXTERNAL INTERFACE verfügbarn";
if(ExternalInterface.addCallback("showState",null,showState) &&
ExternalInterface.addCallback("showReturnedText",null,showReturnedText
)) {
msg.text += "Callback-Funktionen ERFOLGREICH registriertn";
}
else { msg.text += "Callback-Funktionen NICHT erfolgreich registriert
n"; }
}
else { msg.text += "EXTERNAL INTERFACE NICHT verfügbarn"; }
Listing 5.38: Auszug aus dem Code zum Registrieren/Freigeben der Flash-Funktion für JavaScript – add-
Callback macht’s möglich.
Hat das Registrieren beider Funktionen ordnungsgemäß funktioniert, wird in der
TextArea msg der Text „Callback-Funktion ERFOLGREICH registriert“ ausgegeben
– dies ist unsere Kontrolle, dass keine Fehler vorgefallen sind.
Testen wir das Beispiel, um uns von dessen Funktion zu vergewissern:
ABBILDUNG 5.27
Nachdem die Buttons
„Initialisieren“ und „Öffnen“
angeklickt wurden, schaltet
die Ampel auf Orange (zweite
Ampelreihe).
C L I E N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 215
Überlegen wir uns nun als konkretes Beispiel folgenden Fall: Wir erstellen eine kleine
Umfrageseite, in der ein User aufgefordert wird, aus einer Liste von Antworten zu
einer gegebenen Frage eine Antwort auszuwählen. Sobald er seine Auswahl bestätigt
hat, wird seine „Stimme“ per AJAX an den Server geschickt und dort in einer Daten-
bank abgelegt. Der Server soll die Anzahl der „Stimmen“ pro vorgegebener Antwort
zurückliefern. Sobald der Server dies getan hat, übergibt AJAX an Flash diese Informa-
tionen, wodurch Flash eine kleine Grafik (eine Art „Balkendiagramm“) aufbaut, die
das Ergebnis der Umfrage in Form eines Balkendiagramms grafisch darstellt. Klickt der
User dann auf einen der Balken in der Flash-Anwendung, so sollen Details zu diesem
Balken in der XHTML-Datei angezeigt werden.
Im nachfolgenden Bild finden Sie zunächst einmal die Ausgangssituation, dass die
Anwendung auf eine Stimme von Ihnen wartet – auch die Flash-Anwendung zeigt im
Moment noch keine Grafik an:
ABBILDUNG 5.28
Klicken wir auch noch den
„Senden“-Button, schal-
tet die Ampel nach und
nach auf Grün (unterste
Lampenreihe) und gibt den
per AJAX angeforderten Text
der Datei testrequest.txt in
der TextArea aus. Perfectly
done! Klappt natürlich in
jedem (gängigen) Browser ...
K A P I T E L 5216
Hat der User eine Auswahl getroffen und seine Stimme durch einen Klick auf den
Button „Abstimmen“ abgegeben, wird diese Stimme in der Datenbank gespeichert
(AJAX & PHP). Der Server gibt als Response eine URL-codierte Ausgabe an AJAX
zurück, welche wiederum an Flash übergeben wird. Flash bastelt aus diesen Daten die
Balkengrafik:
ABBILDUNG 5.29
Die Applikation wartet auf
Ihre Stimme …
ABBILDUNG 5.30
Es wurde eine Stimme für
„Ducati“ abgegeben. Flash
zeigt sogleich auch das bis-
herige Voting an.
Klickt der User danach auf einen der Balken in der Flash-Datei, so wird unterhalb
des „Abstimmen“-Buttons eine detailliertere Ausgabe des Votings für den geklickten
Balken ausgegeben:
C L I E N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 217
Wie üblich beginnen wir mit der Analyse der XHTML-Datei. Ich empfehle Ihnen, par-
allel zum Buch die jeweiligen Dateien auf Ihrem Computer zu öffnen – im jetzigen Fall
handelt es sich um die Datei ajax02.php aus dem Verzeichnis zum aktuellen Kapitel.
...
<div id="Umfrage">
<form name="frmVote" id="frmVote" action="">
<div>
<?php
$conn = mysql_connect("mysql.syneweb.com","usr_flashphpajax","flashmyph
pajax") or die('<div class="error">Die Verbindung zum Datenbankserver
konnte NICHT hergestellt werden. Error: '.mysql_error().'</div>');
$db = mysql_select_db("db_flashphpajax") or die('<div class="error">Die
Datenbank konnte NICHT ausgewaehlt werden. Error: ‚.mysql_error().'</div>');
$sql = "SELECT * FROM tbl_05fragen WHERE(bitP_chk_aktiv=1) ORDER BY
RAND() LIMIT 1";
$query = mysql_query($sql);
$data = mysql_fetch_array($query);
$sql = "UPDATE tbl_05fragen SET dt_LetzterAufruf='".date("Y-m-d")."', int_
AnzahlAufrufe=int_AnzahlAufrufe+1 WHERE idP_Frage=".$data["idP_Frage"];
$query = mysql_query($sql);
$msgOut = '<input type="hidden" name="idP_Frage" id="idP_Frage"
ABBILDUNG 5.31
Nachdem der User einen
Balken (in unserem Fall den
Balken „Ducati“) angeklickt
hat, werden die Details der
Umfrage für diese Auswahl
dargestellt (unterhalb des
„Abstimmen“-Buttons).
K A P I T E L 5218
value="'.$data["idP_Frage"].'" />';
$msgOut.= '<p>'.$data["vcP_Bezeichnung"].'</p>';
$sql = "SELECT * FROM tbl_05antworten WHERE(fidP_select_Bezeichnung_
Frage=".$data["idP_Frage"]." AND bitP_chk_aktiv=1) ORDER BY int_
Reihenfolge";
$query = mysql_query($sql);
while($data2 = mysql_fetch_array($query)) {
$msgOut.= '<div><input type="radio" name="antwort"
value="'.$data2["idP_Antwort"].'" />'.$data2["vcP_Antwort"].'</div>';
}
echo($msgOut);
?>
</div>
<div><input type="button" name="btnVote" id="btnVote" value="Abstimmen"
onclick="vote();" /></div>
</form>
<div id="Details"></div>
</div>
<div id="Flash">...</div>
<div class="cleaner"></div>
...
Listing 5.39: Auszug aus dem Code der XHTML-Datei ajax02.php
Wir finden darin einige wesentliche Elemente:
Ein Formular „frmVote“, um auf die Formularfelder (Radiobuttons) zugreifen zu
können.
Zwei SQL-Abfragen, wobei die erste der beiden per Zufall eine Frage aus der Daten-
bank auswählt und die zweite danach die zugehörigen Antwortmöglichkeiten aus
einer zweiten Tabelle lädt (das Tabellengerüst finden Sie in nachfolgender Abbil-
dung).
Den Button „btnVote“ zum Abstimmen, der auf onclick die Funktion vote auf-
ruft.
Einen (noch) leeren DIV-Container „Details“, den wir für die Ausgabe der Detail-
infos verwenden.
u
u
u
u
C L I E N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 219
Die eingebundene Flash-Datei (im Container „Flash“) versteht sich von selbst und
wurde deshalb aus dem Script entfernt, um es besser lesbar zu machen – in der Origi-
naldatei ist ein entsprechendes <object> usw. selbstverständlich enthalten.
Der erste interessante Part ist also die Abfrage der Datenbank, um zu einer Umfra-
ge zu kommen. In den ersten Zeilen des PHP-Teils wird zunächst Verbindung mit
dem Datenbankserver aufgenommen (mysql_connect), danach eine Datenbank
ausgewählt (mysql_select_db) und schließlich ein SQL-Statement $sql abgesetzt
(mysql_query), das aus den gegebenen und aktiven (bitP_chk_aktiv=1) Einträgen
der Tabelle tbl_05fragen per Zufall (RAND()) einen (LIMIT 1) Datensatz zurückliefert.
Dieser eine Datensatz wird in $data gespeichert.
Im zweiten SQL-Statement wird der Eintrag mit der soeben gewählten Frage dahin-
gehend verändert, als dass die Anzahl der Aufrufe der Frage um eins erhöht (int_
AnzahlAufrufe=int_AnzahlAufrufe+1) und als letztes Abfragedatum das aktuelle
Datum eingetragen wird (dt_LetzterAufruf='".date("Y-m-d")).
Danach wird ein drittes SQL-Statement (welches wieder den Namen $sql trägt)
abgesetzt, das aus der Tabelle tbl_05antworten zu der gegebenen Frage (fidP_select_
Bezeichnung_Frage=".$data["idP_Frage"]) alle aktiven (bitP_chk_aktiv=1)
Antworten auswählt und entsprechend der in der Tabelle gespeicherten Reihenfolge
(ORDER BY int_Reihenfolge) zurückliefert. Mithilfe einer while-Schleife wird aus
dem Ergebnis eine Variable $msgOut zusammengebastelt, die als Inhalt eine Anzahl an
Radio-Buttons mit den entsprechenden Antworten enthält. Am Ende der Schleife wird
$msgOut per echo ausgegeben. Das entsprechende Ergebnis sehen Sie in Abbildung
5.29.
Gehen wir weiter zur Funktionalität des„Abstimmen“-Buttons. Dieser stellt wie üblich
die Schnittstelle zu AJAX her, indem er die Funktion vote aufruft, die die Anfrage an
den Server stellt:
function vote() {
var found = false;
for(var i=0; i<document.forms["frmVote"].elements["antwort"].length; i++) {
if(document.forms["frmVote"].elements["antwort"][i].checked==true) {
var theVote = document.forms["frmVote"].elements["antwort"][i].value;
found = true;
ABBILDUNG 5.32
Eine einfache
Tabellenstruktur bil-
det die Basis unserer
Umfrageanwendung.
K A P I T E L 5220
break;
}
}
if(found) {
var idP_Frage = document.forms["frmVote"].elements["idP_Frage"].
value;
var querystring = "idP_Frage="+idP_Frage+"&idP_Antwort="+theVote;
myXMLHttpRequest.open("GET", "storevote.php?"+querystring, true);
myXMLHttpRequest.onreadystatechange = handleRequest;
myXMLHttpRequest.send(null);
document.getElementById("Details").innerHTML = "";
}
else { alert("Bitte treffen Sie Ihre Wahl..."); }
}
Listing 5.40: Die Funktion vote, welche die Schnittstelle zwischen dem Formular zum Abstimmen und der
AJAX-Anwendung bildet.
Ziel dieser Funktion ist zweierlei:
1. Überprüfen, ob der User auch wirklich eine Auswahl getroffen hat (er könnte
ja auch auf den „Abstimmen“-Button geklickt haben, ohne zuvor eine Auswahl
getroffen zu haben) und wenn ja, welche.
2. Die getroffene Auswahl per AJAX an den Server übermitteln, um diese in die
Datenbank zu schreiben.
Ob der User tatsächlich abgestimmt hat, wird in der Variable found gespeichert.
Hierzu wird in einer for-Schleife jeder Radio-Button namens „antwort“ auf den Wert
checked==true überprüft. Wurde ein solcher Radio-Button gefunden, wird der Wert
dieses Buttons in theVote gespeichert und found auf true gesetzt. Danach wird die
Schleife abgebrochen (break), da es wenig Sinn macht, die restlichen Radio-Buttons
auch noch zu überprüfen, da nur ein einziger Button ausgewählt sein kann. Wurde
hingegen kein ausgewählter Radio-Button gefunden, ist found nach wie vor false.
Genau dieser Wert wird darauffolgend mithilfe der if-Bedingung überprüft. Bei true
wird eine Variable querystring erzeugt, welche die ID der Frage (idP_Frage) und
die ID der Antwort (idP_Antwort) speichert. Diese Variable wird danach an die Datei
storevote.php als URL-codierter Query-String angehängt. Per open wird die Verbin-
dung zum Server geöffnet, onreadystatechange definiert einen Eventhandler für
Änderungen in der Eigenschaft readyState und send schickt die Anfrage schlussend-
lich ab. Danach wird noch dafür gesorgt, dass der Container „Details“ leer ist.
C L I E N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 221
Natürlich wurde weiter oben die Variable myXMLHttpRequest per
var myXMLHttpRequest = createRequestObject();
als Instanz eines XMLHttpRequest-Objekts angelegt – die Zuweisung des korrekten
Objekts (je nach verwendetem Browser) erfolgt in einer Funktion createRequest-
Object, welche in der externen JavaScript-Datei common.inc.js abgelegt ist. Dieses
Prozedere ist aus dem vorigen Kapitel hinlänglich bekannt.
Gehen wir also weiter zum Eventhandler handleRequest:
function handleRequest() {
switch(myXMLHttpRequest.readyState) {
case 0:
case 1:
case 2:
case 3: break;
case 4:
if(myXMLHttpRequest.responseText.indexOf("ERROR")!=-1) {
alert("Es ist ein FEHLER beim Voting aufgetreten - bitte versuchen
Sie es erneut!");
}
else {
var mySWF = getFlashElement("myswf");
mySWF.showVoteData(myXMLHttpRequest.responseText);
}
break;
}
}
Listing 5.41: Der Eventhandler für die AJAX-Kommunikation
Wie wir wissen, erledigt dieser Eventhandler die Abarbeitung der möglichen Zustände
der readyState-Eigenschaft. Die Fälle 0–3 sind nicht interessant, deshalb brechen wir
hier einfach mit break ab (sollte Ihnen das Kopfzerbrechen bereiten, so schlagen Sie
bitte im vorigen Kapitel zu AJAX nach). Viel interessanter ist der Fall 4, wo der Server
sämtliche angeforderten Daten zurückgeliefert hat. Die angeforderte Datei storevote.
php ist so aufgebaut, dass sie im Fall eines Fehlers eine entsprechende Fehlermeldung
mit dem Text „ERROR“ ausgibt. Das Script sucht also in der Rückgabe (response-
Text) nach dem Text„ERROR“ – sollte dieser vorkommen, liefert die Methode index-
Of diejenige Position im String zurück, wo „ERROR“ vorkommt. Sollte „ERROR“
nicht gefunden werden, liefert sie -1 zurück. Finden wir einen Fehler, wird über alert
K A P I T E L 5222
eine entsprechende Fehlermeldung ausgegeben, finden wir keinen Fehler, erzeugen
wir eine Referenz auf das eingebundene Flash-Element „myswf“ und rufen die dort
freigegebene Funktion showVoteData mit dem soeben erhaltenen Rückgabewert von
storevote.php auf.
Bevor wir uns der Flash-Anwendung widmen, müssen wir noch einen Blick auf store-
vote.php werfen:
if(count($_GET)>0 && isset($_GET["idP_Antwort"]) && isset($_GET["idP_Frage"])) {
$conn = mysql_connect("mysql.syneweb.com","usr_flashphpajax","flashmyph
pajax") or die('<div class="error">Die Verbindung zum Datenbankserver
konnte NICHT hergestellt werden. Error: '.mysql_error().'</div>');
$db = mysql_select_db("db_flashphpajax") or die('<div class="error">Die
Datenbank konnte NICHT ausgewaehlt werden. Error: ‚.mysql_error().'</div>');
$sql = "UPDATE tbl_05antworten SET int_AnzahlStimmen=int_
AnzahlStimmen+1 WHERE(idP_Antwort=".$_GET["idP_Antwort"].")";
if(!$query = mysql_query($sql)) { $returner = "ERROR (1)"; }
else {
$sql = "SELECT * FROM tbl_05antworten WHERE(fidP_select_Bezeichnung_
Frage=".$_GET["idP_Frage"].")";
if(!$query = mysql_query($sql)) { $returner = "ERROR (2)"; }
else {
$returner = '';
$i = 0;
while($data = mysql_fetch_array($query)) {
$returner.= 'ID'.$i.'='.$data["idP_Antwort"].'&Antwort'.$i.'='.$dat
a["vcP_Antwort"].'&Anzahl'.$i.'='.$data["int_AnzahlStimmen"].'&';
$i++;
}
$returner = substr($returner,0,$returner.length-1);
}
}
}
else { $returner = "ERROR (3)"; }
echo($returner);
Listing 5.42: Der Code der Datei storevote.php (zu finden auf der Buch-CD)
Gleich im ersten Schritt der Datei wird überprüft, ob an die Datei überhaupt GET-
Daten übergeben wurden (count($_GET)>0) und ob die benötigten Informationen
über die Frage und die Antwort darin enthalten sind (isset($_GET["idP_Ant-
C L I E N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 223
wort"]) && isset($_GET["idP_Frage"])). Sollte dem nicht so sein, wird eine
Rückgabevariable $returner auf den Wert „ERROR (3)“ gesetzt. War hingegen alles
wie gewünscht, so gehen wir einen Schritt weiter und stellen die Verbindung zum
Datenbankserver und zur Datenbank her.
Das erste SQL-Statement sorgt dafür, dass die Stimme des Users für die gegebene
Antwort gespeichert wird. Falls dieses UPDATE-Statement fehlgeschlagen ist, wird in
$returner der Wert „ERROR (1)“ gespeichert und abgebrochen. War es erfolgreich,
wird das zweite SQL-Statement ausgeführt, das für die gestellte Frage alle Antworten
mit ID, Antworttext und Anzahl abgegebener Stimme in eine entsprechende Form
bringt (gesetzt den Fall, dass die Abfrage erfolgreich durchgeführt werden konnte):
IDn=...&Antwortn=...&Anzahln=...
n steht für eine Zählvariable, um jede „Variable“ eindeutig zu machen. Es ist Ihnen
sicherlich aufgefallen, dass der Rückgabestring in URL-codierter Form generiert wird
– im nächsten Kapitel werden wir noch lernen, warum diese Form ideal für eine
Datenübergabe an Flash ist. Als Beispiel für den Rückgabestring hier eine Ausgabe zu
den obig dargestellten Abbildungen:
ID0=14&Antwort0=BMW&Anzahl0=7&ID1=15&Antwort1=Ducati&Anzahl
1=34&ID2=16&Antwort2=KTM&Anzahl2=10&ID3=17&Antwort3=keine der
angegebenen&Anzahl3=2
Listing 5.43: Ein möglicher Rückgabestring in URL-codierter Form
Im Ideal- oder Normalfall (nämlich dann, wenn das Abarbeiten von storevote.php
erfolgreich war) erhalten wir als responseText der XMLHttpRequest-Instanz genau
diesen Text, der schnell an Flash übergeben wird (siehe Listing 5.41).
Also auf zu Flash! Wir benötigen einerseits die ExternalInterface-Klasse, um die
reibungslose Kommunikation zwischen Flash und JavaScript zu gewährleisten, und
andererseits die DropShadowFilter-Klasse, um die Ausgabe ein wenig aufzupeppen:
import flash.filters.DropShadowFilter;
var dropShadow:DropShadowFilter = new DropShadowFilter(4, 45, 0x333333,
0.8, 10, 10, 2, 3);
import flash.external.*;
//var msg:mx.controls.TextArea;
if(ExternalInterface.available) {
if(ExternalInterface.addCallback("showVoteData",null,showVoteData)) {
//msg.text += "Callback-Funktion ERFOLGREICH registriertn";
}
K A P I T E L 5224
else {
//msg.text += "Callback-Funktion NICHT erfolgreich registriertn";
}
}
else {
//msg.text += "EXTERNAL INTERFACE NICHT verfügbarn";
}
Listing 5.44: Der Code der Aktionenebene: Es werden zwei Klassen eingebunden, ein Schlagschatten
definiert und überprüft, ob ExternalInterface verfügbar ist und die Callback-Funktion erfolgreich registriert
wurde.
Die Variable dropShadow speichert eine Instanz des Objekts DropShadowFilter für
die weitere Verwendung (Details zu den Parametern finden Sie in der ActionScript-
Referenz). Des Weiteren finden Sie einige auskommentierte Codeteile für den Fall, dass
Sie eine TextArea namens msg in Verwendung haben (beispielsweise für die Ausgabe
etwaiger Informationsmeldungen).
Rufen wir uns in Erinnerung, dass JavaScript eine Funktion showVoteData aufruft
(diese Funktion wurde als Callback-Funktion registriert):
function showVoteData(myData:String):Void {
var myDataArray:Array = parseDataIntoArray(myData);
createDiagram(myDataArray);
}
Listing 5.45: Die Funktion showVoteData, die für JavaScript freigegeben wurde
An showVoteData wird wie oben beschrieben vonAJAX (JavaScript) der URL-codierte
String der PHP-Datei storevote.php übergeben: Die Variable myData wird diesen String
beinhalten. Um mit diesem String ordentlich arbeiten zu können, werden wir ihn in
ein Array parsen – dazu verwenden wir die Funktion parseDataIntoArray:
function parseDataIntoArray(myData:String):Array {
var myLoadVars:LoadVars = new LoadVars();
myLoadVars.decode(myData);
var returner:Array = new Array();
var i:Number = 1, j:Number = 0, highestVal:Number = 0, itmname:String;
returner[0] = new Array();
for(itm in myLoadVars) {
itmname = itm.toLowerCase();
if(itmname.indexOf("anzahl")!=-1 && parseInt(myLoadVars[itm])>highe
stVal) { highestVal = parseInt(myLoadVars[itm]); }
C L I E N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 225
if(j==0) { returner[i] = new Array(); }
returner[i][j] = myLoadVars[itm];
j++;
if(j==3) { j = 0; i++; }
}
returner[0][0] = highestVal;
return returner;
}
Listing 5.46: Die Funktion parseDataIntoArray schreibt die von JavaScript übergebenen Werte in ein
zweidimensionales Array returner.
Die einfachste Art, um mit URL-codierten Daten zu arbeiten ist, diese in ein sogenann-
tes LoadVars-Objekt zu laden – dazu dient die Methode decode.
Das LoadVars-Objekt
Grundsätzlich wird dieses Objekt zum Laden serverseitiger Daten in Flash verwendet – Details
hierzu lernen Sie im folgenden Kapitel. Da wir in diesem Beispiel eigentlich auch mit serverseiti-
gen Daten zu tun haben (unsere URL-codierten Daten), können wir das LoadVars-Objekt ein
bisschen zweckentfremden und es zum leichteren Auslesen dieser URL-codierten Daten verwen-
den.
Nach dem Ausführen von decode befinden sich alle Daten als Variablen in der Load-
Vars-Instanz – eine for-in Schleife ist somit ideal zum Auslesen aller Daten. Zuvor
legen wir noch einen ersten Eintrag im Array returner an, wo wir an Stelle [0][0] die
höchste eingelesene Anzahl an Stimmen speichern werden.
Innerhalb der for-in-Schleife müssen wir beim Parsen berücksichtigen, dass wir pro
Datensatz immer drei Informationen einlesen müssen: ID, Anzahl und Antwort. Aus
diesem Grund lassen wir eine Variable j mitzählen, die die Werte 0–2 einnehmen soll.
Sobald j==3 ist, wird j wieder auf 0 gesetzt und i um eins erhöht. Ist j==0, wird ein
neuer Eintrag im returner-Array erzeugt. So weit zum grundsätzlichen Ablauf. Sollte
die gerade bearbeitete Variable einen Text „anzahl“ im Namen tragen, wird der Wert
in eine Ganzzahl umgewandelt (parseInt) und überprüft, ob die gerade eingelesene
Anzahl größer als der höchste gespeicherte Wert für die Anzahl der abgegebenen Stim-
men ist (parseInt(myLoadVars[itm])>highestVal). Falls ja, wird dieser Wert als
der höchste Wert gespeichert.
Zuletzt schreiben wir den Wert von highestVal wie besprochen an die Stelle [0][0]
des returner-Arrays und liefern das Array an den Aufrufer (die Funktion showVo-
teData) zurück, wo das Array als myDataArray weiterverarbeitet wird. Um die Daten
nun darzustellen, wird im zweiten Schritt die Funktion createDiagram aufgerufen,
die das eigentliche Balkendiagramm erzeugt:
LoadVars & URL-
codierte Informa-
tionen
LoadVars & URL-
codierte Informa-
tionen
K A P I T E L 5226
function createDiagram(myDataArray:Array):Void {
mcWarten._visible = false;
var maxVal:Number = 160;
var xScaler:Number = maxVal/myDataArray[0][0];
var stringMaxLength:Number = 15;
var balkenOffsetX:Number = 120;
var balkenOffsetY:Number = 0;
var myFormat:TextFormat = new TextFormat();
myFormat.font = "Arial";
myFormat.size = 12;
for(var i:Number=1; i<myDataArray.length; i++) {
var myName:String = "Balken"+i;
this.createEmptyMovieClip(myName,i);
this[myName].id = myDataArray[i][2];
this[myName]._x = 120;
this[myName]._y = 5+(i-1)*15;
this[myName].createTextField("myTextfield",0,-110,0,100,20);
var theText:String = myDataArray[i][1];
if(theText.length>stringMaxLength) { theText = theText.
substr(0,stringMaxLength-2)+".."; }
this[myName]["myTextfield"].text = theText;
this[myName]["myTextfield"].setTextFormat(0, this[myName]["myTextfiel
d"].text.length, myFormat);
this[myName].createEmptyMovieClip("mcRechteck",1);
drawBalken(this[myName]["mcRechteck"], myDataArray[i][0]*xScaler,
10, 0x99FF00);
this[myName].onRelease = function():Void {
import flash.external.*;
ExternalInterface.call("showDetailData",this.id)
}
C L I E N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 227
}
}
Listing 5.47: Die Funktion createDiagram sorgt dafür, dass aus den übermittelten Daten ein Balkendia-
gramm erzeugt wird.
Betrachten wir die Funktion genauer, stechen zunächst folgende Schritte bzw. Defini-
tionen ins Auge:
mcWarten._visible = false: Der Text „WARTE AUF DATEN…“ (siehe Abbil-
dung 5.29) ist im MovieClip mcWarten verpackt. Da dieser nach dem Aufbau der
Balken nicht mehr benötigt wird, wird er ausgeblendet.
var maxVal:Number = 160: Die Variable maxVal bestimmt die Länge des längs-
ten Balkens – an ihm werden alle anderen Balken gemessen und so entsprechend
skaliert.
var xScaler:Number = maxVal/myDataArray[0][0]: xScaler berechnet aus
der zuvor angegebenen maximalen Länge eines Balkens (maxVal) und der höchs-
ten Anzahl an Stimmen (myDataArray[0][0] – siehe Beschreibung zu highest-
Val weiter oben) den Skalierungsfaktor für jeden Balken.
var stringMaxLength:Number = 15: Diese Variable gibt an, wie lange der
Beschriftungstext (die „Antwort“, die der User angezeigt bekommen hat) vor einem
Balken maximal sein darf, bevor er abgeschnitten wird und ihm zwei Punkte „..“
angehängt werden.
var balkenOffsetX:Number = 120: Nullabstand des Balkens in horizontaler
Richtung vom Anfang der Beschriftung des Balkens
var balkenOffsetY:Number = 3: Nullabstand des Balkens in vertikaler Rich-
tung vom Anfang der Beschriftung des Balkens
Zwischenzeitlich erzeugen wir noch eine Formatvorlage myFormat (Schriftart Arial,
Textgröße 12 Pixel) für den Beschriftungstext, die wir dann auf alle Beschriftungstexte
anwenden werden:
var myFormat:TextFormat = new TextFormat();
myFormat.font = "Arial";
myFormat.size = 12;
Danach werden in einer for-Schleife sämtliche Balkendaten im Array myDataArray
durchgegangen, wobei wir uns in Erinnerung halten müssen, dass pro Eintrag in
myDataArray ein weiteres Array mit drei Einträgen steckt:
myDataArray[n][0]: Anzahl der Stimmen
myDataArray[n][1]: Beschriftung des Balkens
u
u
u
u
u
u
u
u
K A P I T E L 5228
myDataArray[n][2]: ID der Antwort (in unserer Tabelle tbl_05antworten ent-
spricht dieser Wert dem Feld idP_Antwort)
(n steht für einen beliebigen Eintrag im Array.)
Innerhalb der Schleife erzeugen wir zunächst einen leeren MovieClip mit dem Namen
„BalkenN“ (wobei N wiederum für einen fortlaufenden Zähler der Schleife – bei uns:
die Variable i – steht). Innerhalb des neu erstellten Clips merken wir uns die zugehö-
rige ID in der Variable id und setzen den Clip entsprechend des Schleifenzählers an
eine x- (immer 0) und y-Position (mit einem Offset von 5 Pixel dann alle 15 Pixel nach
unten: 5+(i-1)*15).
Vielleicht ist Ihnen aufgefallen, dass die for-Schleife nicht bei 0 zu zählen beginnt, wie
das normalerweise üblich wäre, wenn man alle Einträge des myDataArray durchgehen
möchte. In unserem Fall ist jedoch die Position 0 dieses Arrays durch die höchste vor-
kommende Stimmenanzahl (highestVal aus der Funktion parseDataIntoArray)
definiert und erst ab Position 1 sind die eigentlichen Balkenwerte gespeichert.
Im neuen Clip legen wir für die Beschriftung ein neues Textfeld an (dies trägt pro
Clip immer denselben Namen „myTextfield“), Position [0][0] mit einer Länge von
120 Pixel und einer Höhe von 20 Pixel. Im selben Atemzug kümmern wir uns um den
Inhalt dieses Textfelds: Sollte der Beschriftungstext länger als die maximal von uns
gewünschte Anzahl an Zeichen sein (theText.length>stringMaxLength), so kür-
zen wir den Text auf diese Länge minus 2 Pixel (= Anzahl der Punkte, die angehängt
werden), hängen zwei Punkte „..“ an und weisen den Text korrekter Länge dann dem
zuvor neu erzeugten Textfeld zu. Abschließend wenden wir die Formatvorlage myFor-
mat noch auf den gesamten Text an – der Beschriftungsteil ist abgehakt.
Wenden wir uns dem Erzeugen eines Balkens (letzten Endes eines Rechtecks oder
vierer Linien) zu. Schritt eins ist das Erzeugen eines eigenen MovieClips im MovieC-
lip BalkenN mit dem Namen „mcRechteck“. Schritt zwei umfasst das Aufrufen einer
selbst gebastelten Funktion drawBalken, an die wir den Namen des MovieClips, worin
der Balken gezeichnet werden soll, den Offset zum Zeichnen in x- und y-Richtung, die
Breite und Höhe des Balkens sowie die Farbe des Balkens (in hexadezimaler Notation)
übergeben:
function drawBalken(mcBalken:MovieClip, boxOffsetX:Number, boxOffsetY:
Number, boxWidth:Number, boxHeight:Number, fillColor:Number):Void {
if(boxWidth==0) { boxWidth = 1; }
with (mcBalken) {
beginFill(fillColor, 100);
moveTo(boxOffsetX,boxOffsetY+0);
lineTo(boxOffsetX+boxWidth, boxOffsetY);
lineTo(boxOffsetX+boxWidth, boxOffsetY+boxHeight);
lineTo(boxOffsetX, boxOffsetY+boxHeight);
u
Schleifenbeginn
bei 1, nicht bei 0
Schleifenbeginn
bei 1, nicht bei 0
C L I E N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 229
lineTo(boxOffsetX, boxOffsetY);
endFill();
filters = [dropShadow];
}
}
Listing 5.48: Die Funktion drawBalken zeichnet einen Balken mit Mindestlänge 1 Pixel, bestehend aus
vier Linien, die mit einer Füllfarbe gefüllt werden und dem so erzeugten Rechteck einen Schlagschatten
zuweisen.
Da es wenig Sinn macht, einen Balken mit der Länge null zu zeichnen, setzen wir die
Länge des Balkens auf minimal 1 Pixel (ansonsten würden wir auch Gefahr laufen, dass
der User annimmt, hier würden Balken einfach fehlen):
Usability: bei
keinen Stimmen
trotzdem Balken
mit Länge 1 Pixel
Usability: bei
keinen Stimmen
trotzdem Balken
mit Länge 1 Pixel
Mit dem übergebenen MovieClip starten wir das Zeichnen eines Balkens, indem wir
vier Linien zeichnen und den Bereich füllen (beginFill(fillColor, 100) – es wird
die Füllfarbe fillColor zu 100% Deckkraft, wobei die Deckkraft nicht gesondert
angegeben werden müsste). Die Methode moveTo sorgt dafür, dass wir an der richtigen
Stelle zu zeichnen beginnen, da sie die Zeichnen-Startposition an die gegebene Stelle
setzt. Sind alle vier Linien mit lineTo gezeichnet worden, kann das Füllen der so
entstandenen Fläche wieder beendet und der Schlagschatten dropShadow angewandt
werden (die Definition des Schlagschattens finden Sie in der Aktionenebene, die in
Listing 5.44 beschrieben wurde).
Mittlerweile sind Beschriftung und Balken erzeugt. (Zur Erinnerung: Wir befinden
uns im letzten Teil der for-Schleife aus Listing 5.47.) Unsere Aufgabenstellung sieht
jedoch vor, dass der User einen Klick auf den Balken machen kann und so Details zum
geklickten Balken bekommt – dies bedeutet für uns, dass wir unserem gesamten Clip
noch ein onRelease-Ereignis zuweisen müssen:
...
this[myName].onRelease = function():Void {
import flash.external.*;
ABBILDUNG 5.33
Besser einen Balken mit
1 Pixel Länge erzeugen (bei
null Stimmen) als keinen
Balken – kein Balken wirkt
auf den User als „Fehler“.
K A P I T E L 5230
ExternalInterface.call("showDetailData",this.id)
}
...
Listing 5.49: Auszug aus Listing 5.47
Beim Loslassen der Maustaste (onRelease) laden wir nochmals die External-
Interface-Klasse (diese ist die einzige Klasse innerhalb flash.external) und rufen
die JavaScript-Funktion showDetailData mit der MovieClip-eigenen id-Variable
(idP_Antwort der Tabelle tbl_05antworten) auf. Der Flash-Part wäre aber an dieser
Stelle beendet – also zurück zu JavaScript.
Wie oben beschrieben wird beim Klick auf einen Balken (oder auf dessen Beschrif-
tung) über die ExternalInterface-Klasse die JavaScript-Funktion showDetail-
Data aufgerufen. Sie sorgt dafür, dass per AJAX Detaildaten zum geklickten Balken
angezeigt werden:
function showDetailData(idP_Antwort) {
var querystring = "idP_Antwort="+idP_Antwort;
myXMLHttpRequest.open("GET", "getdetails.php?"+querystring, true);
myXMLHttpRequest.onreadystatechange = handleRequestDetail;
myXMLHttpRequest.send(null);
}
Die Funktion showDetailData öffnet ihrerseits eine Verbindung zum Server auf die
Datei getdetails.php, um Detailinformationen zu einer gegebenen Antwort abzuru-
fen. Hierzu wird die angeforderte Antwort-ID als Querystring an den Dateinamen
angehängt, der XMLHttpRequest-Instanz ein Eventhandler handleRequestDetail
zugewiesen und die Anfrage abgeschickt. Der an dieser Stelle verwendete Eventhandler
ist selbstverständlich nicht derselbe wie der Eventhandler, den wir für die Abarbeitung
der Anfrage für Fragen aus Listing 5.41 verwendet haben – wir wollen ja den Rückga-
bewert nicht an Flash übergeben, sondern in dem dafür vorgesehenen DIV-Container
„Details“ (siehe Listing 5.39) darstellen.
Keine großen Geheimnisse birgt die Datei getdetails.php für uns:
if(count($_GET)>0 && isset($_GET["idP_Antwort"])) {
$conn = mysql_connect("mysql.syneweb.com","usr_flashphpajax","flashmyph
pajax") or die('<div class="error">Die Verbindung zum Datenbankserver
konnte NICHT hergestellt werden. Error: '.mysql_error().'</div>');
$db = mysql_select_db("db_flashphpajax") or die('<div class="error">Die
Datenbank konnte NICHT ausgewaehlt werden. Error: ‚.mysql_error().'</
div>');
$sql = "SELECT * FROM tbl_05antworten WHERE(idP_Antwort=".$_GET["idP_
Antwort"].")";
C L I E N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 231
$query = mysql_query($sql);
$data = mysql_fetch_array($query);
$sql = "SELECT SUM(int_AnzahlStimmen) AS sum FROM tbl_05antworten
WHERE(bitP_chk_aktiv=1 AND fidP_select_Bezeichnung_Frage=".$data["fidP_
select_Bezeichnung_Frage"].")";
$query = mysql_query($sql) or die("ERROR: ".mysql_error());
$data2 = mysql_fetch_array($query);
$sum = $data2["sum"];
echo('
<ul>
<li>Anzahl abgebebener Stimmen gesamt: '.$sum.'</li>
<li>Anzahl Stimmen f&uuml; ''.$data["vcP_Antwort"].'':
'.$data["int_AnzahlStimmen"].'</li>
<li><span style="font-weight:bold;">Prozentsatz:
'.round(100*$data["int_AnzahlStimmen"]/$sum,2).'%</span></li>
</ul>
‚);
}
Listing 5.50: Das gesamte Listing von getdetails.php ist mehr oder weniger Routine – zwei Abfragen,
ein bisschen Ausgabe per echo.
Das Ziel dieser Datei ist Folgendes:
1. Überprüfen, ob an sie GET-Daten übergeben wurden und ob es sich um die GET-
Variable idP_Antwort handelt (ansonsten würde das Abarbeiten dieser Datei
keinen Sinn machen):
if(count($_GET)>0 && isset($_GET["idP_Antwort"]))
2. Ein erstes SQL-Statement abzusetzen, das alle Infos zur geforderten Antwort aus
der Datenbank liest (zuvor muss natürlich der Datenbankserver kontaktiert und
die Datenbank ausgewählt werden, aber das wissen Sie sicherlich):
SELECT * FROM tbl_05antworten WHERE(idP_Antwort=".$_GET["idP_
Antwort"].")
3. Ein zweites SQL-Statement, das alle zur gegebenen Frage (die auch für unsere
Antwort gegolten hat) abgegebenen Stimmen zählt (aufsummiert) und die Summe
zurückliefert:
K A P I T E L 5232
SELECTSUM(int_AnzahlStimmen)ASsumFROMtbl_05antwortenWHERE(bitP_
chk_aktiv=1 AND fidP_select_Bezeichnung_Frage=".$data["fidP_select_
Bezeichnung_Frage"].")
4. Aus den so gewonnenen Informationen eine Liste mit folgenden Informationen
zusammenzustellen:
Anzahl der insgesamt abgegebenen Stimmen zu dieser Frage
Anzahl der Stimmen für die geklickte Antwort
Prozentsatz der auf die angeklickte Antwort abfallenden Stimmen
Diese zuletzt genannte Liste wird per echo ausgegeben und bildet somit den Rück-
gabewert responseText für die XMLHttpRequest-Instanz myXMLHttpRequest.
Der zuvor angesprochene Eventhandler handleRequestDetail sorgt schlussendlich
dafür, dass dieser Rückgabewert in den DIV-Container „Details“ geschrieben wird:
function handleRequestDetail() {
switch(myXMLHttpRequest.readyState) {
case 0:
case 1:
case 2:
case 3: break;
case 4: document.getElementById("Details").innerHTML =
myXMLHttpRequest.responseText; break;
}
}
Listing 5.51: Abschluss unserer Bemühungen: Der Rückgabewert responseText von getdetails.php wird
in den dafür vorgesehenen DIV-Container „Details“ geschrieben.
Das war’s, meine Damen und Herren! Und damit wir nicht vergessen, warum wir
den Aufwand mit AJAX getrieben haben: Dieses Umfragetool muss nicht die Seite
neu laden, um die aktualisierten Daten anzuzeigen, wie es sonst üblich ist. Und wenn
Sie Lust darauf haben, dass auch mehrere Umfragen ohne Neuladen des Dokuments
durchgeführt werden sollen, dann sehen Sie sich die Datei ajax02a.htm an, die Sie auf
der Buch-CD finden:
u
u
u
C L I E N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 233
Na, Lust auf mehr bekommen? ajax02a.htm, ajax02a.fla und getquestion.php sind die
Antwort! Zu finden auf der Buch-CD. Folgende Änderungen wurden vorgenommen:
1. Die PHP-Abfrage der Frage und zugehörigen Antworten wurde in eine externe
Datei verlegt (getquestion.php), die im Weiteren per AJAX abgefragt wird. Der erste
Aufruf erfolgt beim Eintreten des onload-Ereignisses für das window-Objekt.
2. Bei Klick auf den Button „Neue Frage“ passiert genau dasselbe wie beim onload-
Ereignis von oben, nur dass zusätzlich noch die Flash-Datei „zurückgesetzt“ wird
(die von einer vorigen Frage dargestellten Balken werden eliminiert und es wird
wieder der Text „WARTE AUF DATEN“ eingeblendet.
Werfen Sie einen Blick darauf ...
5.4.2 Parameterübergabe: XML
Bisher haben wir ausschließlich mit der Eigenschaft responseText eines XMLHttp-
Request-Objekts gearbeitet. Nun wollen wir die Gelegenheit beim Schopf packen und
anstatt Text- nun XML-Daten vom Server abfragen und an Flash weiterleiten.
XML ist ideal dafür geeignet, strukturierte Daten darzustellen – genau wie unser
obiges Beispiel es fordert. Würden wir die der Balkengrafik zugrunde liegenden Daten
in XML-Form ausgeben, könnte das beispielsweise wie folgt aussehen:
ABBILDUNG 5.34
Nun werden auch die Fragen
und zugehörigen Antworten
per AJAX angefordert.
K A P I T E L 5234
Fraglich ist nun, ob die Daten vom Server als XML- (responseXML) oder Textdaten
(responseText) abgefragt werden sollen. Überraschenderweise wählen wir auch
hier die Variante responseText, obwohl die Daten in XML-Form bereitstehen. Flash
verträgt sich jedoch nicht mit der Darstellung der XML-Daten, wie sie uns AJAX zur
Verfügung stellen würde. Somit ergäben sich zwei Möglichkeiten:
1. Wir wandeln das per AJAX angeforderte XML-basierte Dokument so um, dass
Flash damit etwas anfangen kann.
2. Wir laden die XML-Daten als Text und übergeben den Text an Flash, das für sich
wiederum den Text in XML-Form umwandelt.
Variante 2 ist wesentlich einfacher, weshalb wir nach wie vor responseText an Flash
schicken und dieses dann „echtes“ XML daraus macht.
AJAX-technisch ist an unserem Beispiel nichts zu ändern, trotzdem möchte ich Sie an
dieser Stelle noch auf eine kleine Sache hinweisen, die Ihnen wahrscheinlich schon auf-
gefallen ist und die wir idealerweise an dieser Stelle diskutieren können. Bisher hatten
unsere Eventhandler immer eine relativ komplexe Struktur, da wir eine Auswertemög-
lichkeit für jeden Wert der readyState-Eigenschaft des XMLHttpRequest-Objekts
vorgesehen hatten:
function handleRequest() {
switch(myXMLHttpRequest.readyState) {
case 0:
case 1:
case 2:
response-
Text oder
responseXML?
response-
Text oder
responseXML?
ABBILDUNG 5.35
Die Antwortdaten für eine
gegebene Frage in XML-
Form – vergleichen Sie doch
mal mit Listing 5.43 und
Sie werden sicherlich auch
der Meinung sein, dass
diese Form der Darstellung
wesentlich übersichtlicher
ist.
C L I E N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 235
case 3: break;
case 4: FUNKTIONSAUFRUF BZW. CODE; break;
}
}
Listing 5.52: Ein typischer Aufbau der von uns verwendeten Eventhandler
Wie Sie aus dem obigen Listing entnehmen können, sind die Fälle 0–3 der switch-
Anweisung sinnlos – wir werten diese Fälle gar nicht aus, sondern brechen vielmehr
mit break ab.Warum sollten wir diese Fälle dann überhaupt verwenden? Wenn jedoch
die Fälle 0–3 wegfallen, benötigen wir auch keine switch-Anweisung mehr, sondern
kommen mit einer einfachen if-Anweisung aus:
function handleRequest() {
if(myXMLHttpRequest.readyState==4) {
FUNKTIONSAUFRUF BZW. CODE;
}
}
Listing 5.53: Sieht doch gleich einfacher aus – if anstatt switch für nur einen möglichen Wert von
readyState.
Somit reduziert sich unser Script auf:
function handleRequest() {
if(myXMLHttpRequest.readyState==4) {
if(myXMLHttpRequest.responseText.indexOf("ERROR")!=-1) { alert("Es
ist ein FEHLER beim Voting aufgetreten - bitte versuchen Sie es
erneut!"); }
else { var mySWF = getFlashElement("myswf"); mySWF.showVoteData(myX
MLHttpRequest.responseText); }
}
}
Listing 5.54: Unser Eventhandler hat sich gegenüber dem vorigen Beispiel von der Funktionsweise nicht ge-
ändert – wir haben ihn nur etwas „abgespeckt“ und so auf unsere Bedürfnisse optimal angepasst. Obwohl
wir XML-Daten vom Server laden, übergeben wir diese als responseText an Flash.
Nachdem wir so viel über XML-Daten gesprochen haben, wollen Sie sicherlich auch
erfahren, wie die serverseitige Datei storevote.php sich nun ändern muss, sodass wir
XML- anstatt Textdaten zurückerhalten. (Sie finden die neue Version von storevote.php
übrigens unter dem Namen storevote2.php auf der Buch-CD.) Der wesentliche Unter-
schied liegt in folgenden Zeilen:
K A P I T E L 5236
Bisher (für die Textrückgabe in URL-codierter Form) haben wir folgenden Code
verwendet:
$returner = ‚';
$i = 0;
while($data = mysql_fetch_array($query)) {
$returner.= 'ID'.$i.'='.$data["idP_Antwort"].'&Antwort'.$i.'='.$data
["vcP_Antwort"].'&Anzahl'.$i.'='.$data["int_AnzahlStimmen"].'&';
$i++;
}
$returner = substr($returner,0,$returner.length-1);
Nun verwenden wir:
header("Content-type: text/xml");
$returner = '
<?xml version="1.0" encoding="ISO-8859-1" standalone="yes" ?>
<Umfrage>
';
while($data = mysql_fetch_array($query)) {
$returner.= '
<Antwort ID="'.$data["idP_Antwort"].'" Antworttext="'.$data["vcP_
Antwort"].'" Anzahl="'.$data["int_AnzahlStimmen"].'" />
‚;
}
$returner.= ‚</Umfrage>';
Der wichtigste Unterschied liegt zunächst in der Definition des Content-type des Doku-
ments: Mittels header("Content-type: text/xml") definieren wir, dass es sich bei
den enthaltenen Daten um XML-basierte Daten in Textform handelt. Danach erzeugen
wir das für ein XML-Dokument notwendige Tag <?xml ?>, wo wir als Attribute die
verwendete XML-Version (version="1.0"), den Zeichensatz (encoding="ISO-
8859-1") sowie die Info, ob das Dokument für die Darstellung noch ein Stylesheet
benötigt oder nicht (kein Stylesheet benötigt: standalone="yes"), angeben.
Innerhalb der while-Schleife basteln wir nun keinen URL-codierten Text, sondern Tags
zusammen, und zwar in der Form:
<Antwort ID="..." Antworttext="..." Anzahl="..." />
Das Ergebnis dessen haben Sie in Abbildung 5.35 bereits gesehen.
Viel interessanter ist nun die Frage, wie Flash mit den nun XML-basierten Daten
umgeht. Betroffen davon sind vor allem die Funktionen storeVoteData (dies ist die
u
u
C L I E N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 237
Funktion, die von JavaScript (AJAX) aufgerufen wird) und parseDataIntoArray.
Die Datei storeVoteData erhält nach wie vor einen Text als Übergabeparameter, der
mit geeigneten Flash-Befehlen in eine XML-Struktur gebracht gehört. Nachdem das
gesamte Parsing der Daten jedoch in der Funktion parseDataIntoArray vor sich
geht, muss an storeVoteData nichts geändert werden.
Wie steht es also um die Funktion parseDataIntoArray? Werfen wir einen Blick
darauf:
function parseDataIntoArray(myData:String):Array {
var myXML:XML = new XML();
myXML.ignoreWhite = true;
myXML.parseXML(myData);
var returner:Array = new Array();
returner[0] = new Array();
returner[0][0] = 0;
var theData:Array = myXML.firstChild.childNodes;
for(var i:Number=0; i<theData.length; i++) {
returner[i+1] = new Array();
returner[i+1][0] = theData[i].attributes["Anzahl"];
returner[i+1][1] = theData[i].attributes["Antworttext"];
returner[i+1][2] = theData[i].attributes["ID"];
if(parseInt(returner[i+1][0])>returner[0][0]) { returner[0][0] =
parseInt(returner[i+1][0]); }
}
return returner;
}
Listing 5.55: Die Funktion parseDataIntoArray in etwas geänderter Form: Anstatt des LoadVars-
Objekts verwenden wir nun das XML-Objekt.
Statt der Verwendung des LoadVars-Objekts in Flash kommt nun das XML-Objekt
zum Einsatz (var myXML:XML = new XML();). Um unnötige Zeilenumbrüche, Leer-
zeichen und -zeilen (sog. „Whitespaces“) zu ignorieren, wird die Eigenschaft ignore-
White auf den Wert true gesetzt. Um die von AJAX übergebenen Daten schlussen-
dlich in das XML-Objekt zu bekommen, wenden wir den Befehl parseXML an. (Zur
Erinnerung: Im Fall von LoadVars war es der Befehl decode.)
K A P I T E L 5238
An der Stelle [0][0] des returner-Arrays werden wir nach wie vor den höchsten
gefundenen Wert von„Anzahl“ speichern, jedoch verwenden wir nun keine zusätzliche
Variable highestVal mehr, sondern arbeiten gleich direkt mit diesem Wert.
Um in der XML-Struktur an das für uns interessante Tag „Umfrage“ zu gelangen, ver-
wenden wir die Eigenschaft firstChild der XML-Instanz myXML; die einzelnen „Ant-
wort“-Tags befinden sich als sog. „Kinder“ (Children) innerhalb des „Umfrage“-Tags.
Aus diesem Grund gehen wir Schritt für Schritt alle dieser Kinder durch und speichern
die Informationen „Anzahl“,„Antworttext“ und „ID“ (diese befinden sich als Attribute
im jeweiligen „Antwort“-Tag – siehe Abbildung 5.35) im returner-Array. Da wie
auch im letzten Beispiel die Stelle [0][0] des returner-Arrays für den Höchstwert
an Stimmen reserviert ist, wir jedoch in diesem Fall bei i=0 in der Schleife zu zählen
beginnen, schreiben wir diese Werte jeweils an die Stelle [i+1].
Alles weitere ist wie gehabt – es müssen keine weiteren Änderungen mehr vorgenom-
men werden. Das Resultat sollte sich nicht geändert haben:
Stellt sich die abschließende Frage, warum wir nun XML-basierte Daten anstatt text-
basierter Daten verwendet haben? Nun, die größte Stärke liegt bei Flash verborgen,
denn Flash kann wesentlich besser mit XML- als mit Textdaten umgehen. Mit der
Einführung von ActionScript 3.0 hat sich in Bezug auf Flash & XML noch einmal
ordentlich was getan. Freuen Sie sich auf das nächste Kapitel, wo wir ausführlich mit
XML-Daten arbeiten werden, denn dort geht es darum, wie Flash mit der Serverseite
arbeiten kann.
ABBILDUNG 5.36
Auch bei Verwendung von
XML-Daten hat sich an der
Funktionsweise unseres
Beispiels nichts geän-
dert – wäre ja auch fatal
gewesen …
6
SERVERSEITIGER DATEN-
AUSTAUSCH – FLASH,
PHP & DATENBANK
Um die Frage zu beantworten, wie die Kommunikation zwi-
schen Flash und einer serverseitigen Anwendung (wie etwa
das Ansprechen eines serverseitigen Scripts oder das Anbinden
einer Datenbank oder Ähnliches) erfolgt, müssen wir uns die
Vorgehensweise bei der Darstellung eines Webdokuments (mit
eingebundener Flash-Datei) auf Clientseite noch einmal kon-
kret vor Augen führen.
Zunächst erhält der Server vom Browser des Users (also dem
„Client“) eine Anfrage für ein Webdokument in Form einer
URL. Der (Web-)Server bereitet die Daten für den Client auf
und schickt diese (paketweise) zum Client zurück. Ist das
Dokument vollständig beim Client eingetroffen, spricht man
vom „fertig geladenen“ Dokument. Mit Beendigung dieses
Schritts ist die Kommunikation zwischen Client und Server
abgeschlossen und beide agieren wieder vollkommen unabhän-
gig voneinander.
Nachdem Flash ein Plug-in auf Clientseite ist, kann Flash auch
nur auf Clientseite agieren. Ein (serverseitiges) PHP-Script,
eine Datenbank zum Abfragen oder Speichern von Daten im
Rahmen einer Website liegt jedoch immer auf Serverseite vor,
demnach muss Flash also mit der Serverseite Kontakt aufneh-
men können. Ohne eine geeignete Technologie als „Vermittler“
zwischen Client- und Serverseite ist Flash dazu nicht (oder nur
mit Einschränkungen – siehe etwas weiter unten) in der Lage.
K A P I T E L 6240
Soll eine Datenbank angesprochen werden, muss diese (oder eine zweite) Technologie
zusätzlich noch die von Flash gesandten Daten in eine für die Datenbank verständliche
Form bringen. PHP stellt also die ideale Kombination dieser beiden Anforderungen
dar.
Fassen wir den theoretischen Teil noch einmal zusammen:
1. Flash möchte ein serverseitiges Script ansprechen.
Hierzu muss in jedem Fall eine Kommunikation mit dem Server hergestellt werden.
Da in Flash (ohne Zusatztools auf Serverseite) keine Möglichkeiten zur direkten
Anbindung mit einer Datenbank gegeben sind, muss eine geeignete Technologie
bereitstehen, die diese Aufgabe erledigt.
2. Es wird durch Flash eine PHP-Seite aufgerufen.
PHP agiert auf Serverseite und bringt die übermittelten Daten in eine geeignete
Form – die Daten werden „aufbereitet“.
3. Soll eine Datenbank angesprochen werden,nimmt PHP Kontakt zur Datenbank
auf und schreibt bzw. liest mithilfe der Abfragesprache SQL die Daten.
PHP allein kann wiederum nicht mit einer Datenbank arbeiten.Aus diesem Grund
bedient man sich einer weiteren Sprache – der Abfragesprache SQL (Structured
Query Language).
Selbstverständlich könnten auch andere serverseitige Technologien wie etwa ASP
zum Einsatz kommen. In diesem Buch haben wir uns für PHP entschieden, da PHP
einerseits einfach zu erlernen und andererseits in Web-Entwicklerkreisen sehr weit
verbreitet ist. Des Weiteren hat PHP mit der Datenbank MySQL wiederum eine im
Web sehr verbreitete Datenbank zur Seite, wobei die Kommunikation zwischen diesen
beiden auch noch hervorragend funktioniert. Schlussendlich sollten wir aber auch
nicht vergessen, dass „serverseitiges Arbeiten“ ja nicht nur „Ansprechen einer Daten-
bank“ bedeutet.
In den ersten Kapiteln befassen wir uns mit den Möglichkeiten, die sich im Rahmen
von ActionScript 2.0 bieten. Danach sehen wir uns die – nicht unwesentlichen – Ände-
rungen und Neuerungen im Rahmen von ActionScript 3.0 an (Kapitel 6.4).
6.1 Drei Technologien im Einsatz
Wie man sieht, ist das Arbeiten mit serverseitigen Technologien und im Weiteren
mit einer Datenbank durchaus nicht trivial, da man zumindest zwei (drei bei Daten-
banken) verschiedene Technologien vereinen muss. Dies soll uns jedoch nicht davon
abhalten, diesen Schritt zu wagen – dafür ist dieses Thema in der Webwelt schon jetzt
viel zu wichtig!
ActionScript 2.0
vs. ActionScript
3.0
ActionScript 2.0
vs. ActionScript
3.0
SERVERSEITIGER DATENAUSTAUSCH – FLASH, PHP & DATENBANK 241
In den nächsten Kapiteln werden wir uns mit genau dieser Thematik befassen – zuvor
bleibt es uns aber nicht erspart, noch ein bisschen Theorie zu erläutern. Bitte bedenken
Sie, dass sämtliche Ausführungen in den nächsten Kapiteln aus dem Blickwinkel von
ActionScript 2.0 zu sehen sind – ActionScript 3.0 wird erst weiter unten behandelt. Erst
dort werden wir erkennen, welche ungeheuren Fortschritte und auch Änderungen die
neue Sprachversion uns Entwicklern bringt.
6.2 Das LoadVars-Objekt
Im ersten Teil dieses Kapitels haben wir gesehen, wie JavaScript auf einfache Art und
Weise beispielsweise Variablen in Flash setzen kann. Jetzt befassen wir uns mit der
Frage, wie man in einem wesentlichen größeren Ausmaß Variablen in Flash einlesen
(und auch ausgeben) kann – beispielsweise aus einer Textdatei.
Das LoadVars-Objekt in Flash wird aber nicht nur für das Einlesen von Daten zustän-
dig sein – vielmehr werden wir auch Daten (sichtbar und unsichtbar) verschicken
können. Der Empfänger der Daten könnte beispielsweise ein PHP-Dokument sein, das
die Daten an eine Datenbank weiterleitet.
Daten aus einer Textdatei einlesen
Voraussetzung für das Einlesen von Daten ist zunächst einmal das Vorhandensein einer
Textdatei. Hier ist für uns wichtig, dass diese Datei einem gewissen Muster entspricht:
Sie muss „URL-codiert“ sein. Mit URL-Codierung oder URL-Encodierung meint man
im ersten Schritt das Verfahren der Variable=Wert-Zuweisung. Es ist nicht ausrei-
chend, in das Textdokument reinen Text zu schreiben (das wird erst mit ActionScript
3.0 klappen), wir müssen den Text (also den Wert) einer Variablen zuweisen.
ABBILDUNG 6.1
Die linke Datei „nichtKor-
rekt“ ist ungeeignet für
das Einlesen von Daten
in Flash mit ActionScript
2.0 – in ActionScript 3.0
hätten wir damit keine
Probleme. Die rechte Datei
ist korrekt, da sie das
Konzept Variable=Wert
korrekt anwendet. Um die
Leerzeichen müssen wir uns
noch kümmern – mehr dazu
weiter unten im Abschnitt
zur URL-Codierung.
Abbildung 6.1 zeigt dieses Vorgehen. Die linke Abbildung zeigt eine für das Einlesen
von Text nicht korrekte Textdatei, da sämtliche Informationen, die an Flash übergeben
werden sollen, dem Konzept Variable=Wert genügen müssen (dies gilt für Version
2.0 von ActionScript, in Version 3.0 könnten wir mit dieser Datei arbeiten – siehe
hierzu das Kapitel Laden von Textdaten). In der rechten Abbildung ist dieses Vorgehen
zu sehen: Der (fiktiven) Variable myText wird der Wert „Hallo Welt!“ zugewiesen. Zu
einem späteren Zeitpunkt werden wir sehen, dass wir eventuell aufgrund des Leerzei-
chens auch an der rechten Darstellung noch ein wenig arbeiten müssen, um es perfekt
zu machen.
K A P I T E L 6242
URL-Codierung
Ganz so einfach ist die Sache mit der Kodierung also nicht, denn es müssen einige
Punkte beachtet werden:
1. DieSchreibweisevonURL-Encodierungbasiertauf derVariable=Wert-Zuweisung,
d.h., es existiert immer eine Variable, der – getrennt durch ein Gleichheitszeichen
– ein Wert zugewiesen wird.
2. Da die URL-Encodierung international gültig ist, dürfen im Text natürlich keine
Umlaute vorhanden sein. Das bedeutet, dass alle Umlaute durch entsprechende
Codes ersetzt werden müssen.
3. Auch Sonderzeichen (wie beispielsweise „ß“, Bindestriche und Fragezeichen)
müssendurchentsprechendeCodesausgetauschtwerden.Theoretischmüsstesogar
das Leerzeichen ersetzt werden, Gott sei Dank ist das aber nur bei Formularfeldern
nötig.
Sonderzeichen
Eine vollständige Auflistung aller Sonderzeichen finden Sie unter http://www.unicode.org/
charts/PDF/U0080.pdf – die im PDF-Dokument angeführten Codes werden als sog. „Escape
Codes“ eingesetzt: Beispielsweise hat ein Leerzeichen den Code 0020, das in einem URL-codi-
erten Dokument als %20 (die beiden Nullen werden durch ein Prozentzeichen ersetzt) eingefügt
wird. Generell wird für die Codierung der Latin-1-Zeichensatz verwendet. Genaue Informationen
über Unicode finden Sie auch unter http://www.unicode.org.
URL-Codierung:
keine Leer- und
Sonderzeichen
URL-Codierung:
keine Leer- und
Sonderzeichen
ABBILDUNG 6.2
Eine korrekt URL-codierte
Datei
Mehrere Variablen übergeben
Jegliche Informationen, die URL-codiert an Flash übermittelt werden sollen, müssen
also in Form von Variablen in der Textdatei vorliegen. Möchte man mehr als nur eine
einzige Variable verwenden, so müssen die Variablen mithilfe des kaufmännischen
Und „&“ verbunden werden:
Textdatei mit nur einer Variablen: myText=Hallo%20Welt
Textdatei mit mehreren Variablen: myText=Hallo%20Welt&myText2=Test
u
u
SERVERSEITIGER DATENAUSTAUSCH – FLASH, PHP & DATENBANK 243
Zu guter Letzt muss noch darauf geachtet werden, dass alle verwendeten Variablen
eindeutige Namen erhalten. Sollte es vorkommen, dass ein Variablenname doppelt
verwendet wird, so erhält diese Variable den Wert des letzten Eintrags.
„Quelle“ der einzulesenden Daten
Letzten Endes ist es für Flash vollkommen irrelevant, ob die Datei, aus der Flash auslesen soll,
eine Textdatei ist oder eine andere Datei eines anderen Formats, die nur genauso aufgebaut ist.
Dies eröffnet uns die Möglichkeit, beispielsweise eine PHP-Datei mit einem solchen Aufbau zu
verwenden. Diese wiederum kann die Daten aus einer Datenbank auslesen, wobei wir schon
beim Thema wären. Aber alles zu seiner Zeit – zunächst gehen wir den einfachen Weg des
Auslesens aus einer (statischen, bereits existenten) Textdatei.
Ablauf eines Ladevorgangs
Das Hinzuladen der Daten aus der Textdatei erfolgt aus Flash heraus in folgenden
Schritten:
1. Zunächst muss in Flash per ActionScript ein sogenanntes LoadVars-Objekt
angelegt werden.
Mithilfe dieses Objekts wird es dann möglich sein, Daten einzulesen bzw. zu
versenden, wie Sie in den nachfolgenden Kapiteln sehen werden. Das LoadVars-
Objekt dient als eine Art Container, in dem alle eingelesenen Variablen abgelegt
werden. Man kann sich ein solches Objekt wie eine Schachtel vorstellen, wo die
Daten in Form von Variablen abgelegt sind.
2. Ein entsprechendes Ereignis – das onLoad-Ereignis – in Flash signalisiert, wann
das Lesen der externen Datei abgeschlossen ist.
Wichtig ist hierbei, dass beim Auftreten dieses Ereignisses noch nicht gesagt ist,
dass die Daten auch erfolgreich geladen wurden. Deshalb muss im nächsten Schritt
noch überprüft werden, ob das Laden der Daten funktioniert hat.
3. Danach wird diesem LoadVars-Objekt eine Datei zugewiesen, von der die Daten
gelesen werden sollen.
4. Nun muss geprüft werden, ob das Laden der Daten erfolgreich war.
Die Eigenschaft loaded des LoadVars-Objekts sagt uns mit dem Wert true,
ob dies geschehen ist. Sollte loaded den Wert false aufweisen, muss man sich
überlegen, ob das Laden der Datei erneut versucht werden sollte.
Eindeutige
Variablennamen
Eindeutige
Variablennamen
ABBILDUNG 6.3
Die Textdatei links beinhal-
tet lediglich eine einzige
Variable, die Textdatei rechts
umfasst fünf Variablen.
K A P I T E L 6244
Die Reihenfolge von Ereignissen bei Ladevorgängen
Man sollte darauf achten, dass Ereignisse, die unmittelbar mit dem Laden eines Dokuments in
Verbindung stehen (wie beispielsweise das onLoad-Ereignis beim Laden externer Daten oder
später auch einer XML-Datei), vor dem eigentliche Ladeaufruf definiert werden. Sollte beispiels-
weise der Ladevorgang beendet sein, noch bevor die Ereignisprozedur zum Laden definiert wurde,
wird diese eventuell nicht ausgeführt. Dieser Fall ist zwar zu beinahe 100% auszuschließen (keine
Datei wird so schnell geladen werden, noch bevor die nächsten Zeilen des Flash-Dokuments
abgearbeitet wurden), jedoch arbeitet man doch gerne konform der geltenden Regeln.
Mehrere Ladeversuche
Ein paar Worte zum Thema „Das Laden der Daten ist fehlgeschlagen“. Hier stellt sich
unweigerlich die Frage, wodurch dies passieren kann. Mögliche Ursachen für den Fehl-
schlag sind beispielsweise:
Die Verbindung zum Server ist abgebrochen.
Die Datei konnte nicht gefunden werden.
Die Datei ist nicht korrekt aufgebaut.
Natürlich wäre nur der erste Punkt der Liste ein Grund, das Laden der Datei erneut zu
versuchen. Flash gibt uns leider nicht Auskunft darüber, warum, sondern nur, ob das
Laden fehlgeschlagen ist. Aus diesem Grund sollte man auf jeden Fall einen erneuten
Ladeversuch, maximal aber drei, in Erwägung ziehen.
Die nachfolgende Abbildung 6.4 zeigt den Ablauf eines Ladevorgangs mit einer maxi-
malen Anzahl an Wiederholungen.
u
u
u
ABBILDUNG 6.4
Diese Abbildung zeigt
einen typischen Ablauf
eines Ladevorgangs mit
einer maximalen Anzahl
an Wiederholungen. Sollte
diese Anzahl erreicht werden,
bricht das Skript das
Laden ab.
SERVERSEITIGER DATENAUSTAUSCH – FLASH, PHP & DATENBANK 245
Gehen wir die notwendigen Schritte in Flash also im Detail durch. Schritt eins besagt,
dass wir ein neues LoadVars-Objekt anlegen müssen. Wir sind in der Namensgebung
für das Objekt mit denselben Einschränkungen konfrontiert wie bei den Variablen,
abgesehen davon muss nichts berücksichtigt werden.
1. Anlegen eines LoadVars-Objekts:
var myData:LoadVars = new LoadVars();
Im nächsten Schritt muss diesem LoadVars-Objekt eine Quelldatei zugewiesen
werden, aus der die Daten geladen werden sollen. Diese Datei kann sowohl im
selben wie auch in einem Unterverzeichnis abgelegt sein.
2. Warten auf das Auftreten des onLoad-Ereignisses mithilfe einer nativen Funk-
tion:
myData.onLoad = function(loadedOK:Boolean):Void {
// Ereignisbehandlungsroutine
}
Innerhalb der Ereignisprozedur (bezeichnet dasselbe wie „Ereignisbehand-
lungsroutine“) wird nun kontrolliert, ob das Laden der Datei erfolgreich war. Ein
erfolgreiches Laden wird durch die Variable loadedOK==true des LoadVars-
Objekts dargestellt.DerWert derVariablen loadedOK wird direkt von Flash erzeugt
– man könnte auch sagen, Flash „übergibt“ den Wert der Variablen loadedOK an
die Funktion. Solche Variablen bezeichnet man gerne als Ereignisparameter.
Alternativ zu dieser Vorgehensweise existiert auch noch eine zweite Variante: das
Abfragen der Eigenschaft loaded eines LoadVars-Objekts – siehe hierzu den
„Exkurs Ereignisparameter vs. Objekteigenschaft“.
3. Zuweisen einer Quelldatei:
myData.load("URL zur Quelldatei");
4. Überprüfen, ob das Laden erfolgreich war:
if(loadedOK) {
//beispielsweise Auslesen der Daten
}
else {
//Fehler beim Laden aufgetreten. Evtl. erneuter Ladeversuch?
}
K A P I T E L 6246
Exkurs: Ereignisparameter vs. Objekteigenschaft
Um zu überprüfen, ob ein Ladevorgang erfolgreich durchgeführt wurde, kann man sich zweierlei
Möglichkeiten bedienen:
Man verwendet einen von Flash erzeugten Parameterwert der Ereignisprozedur onload eines
LoadVars-Objekts. In unserem Fall wurde dieser Parameter in der Variable loadedOK gespei-
chert.
Man überprüft die Eigenschaft loaded eines LoadVars-Objekts. In unserem Beispiel würde man
in der if-Abfrage die Variable loadedOK durch den Ausdruck myData.loaded ersetzen. Ist
myData.loaded==true, war der Ladevorgang erfolgreich, bei myData.loaded==false war
er nicht erfolgreich.
Beide Möglichkeiten führen zum selben Ergebnis – welche Variante Sie einsetzen möchten,
bleibt völlig Ihnen überlassen.
Geladene Daten auslesen
Sollte der Ladeversuch erfolgreich verlaufen sein, muss man sich darum kümmern,
die geladenen Daten auszuwerten. Man muss sich bewusst sein, dass sämtliche einge-
lesenen Daten im Container LoadVars gespeichert sind und von dort gelesen werden
müssen. Wurde beispielsweise in der Quelldatei eine Variable mit dem Namen myText
angelegt, so ist der Wert dieser Variable – in unserem Beispiel – über das LoadVars-
Objekt myData abrufbar, und zwar wie folgt:
trace("myText="+myData.myText);
Listing 6.1: Auslesen der gelesenen Daten – beispielsweise per Ausgabe in das Ausgabefenster
In der obigen Zeile sieht man, dass die Variablen der Quelldatei in jedem Fall Variablen
des LoadVars-Objekts werden und nicht Variablen der Hauptzeitleiste. Es steht dem
Entwickler natürlich frei, die gelesenen Variablen in anderen (globalen) Variablen zu
schreiben (siehe Abbildung 6.5).
u
u
ABBILDUNG 6.5
Die in der Textdatei unter
dem Namen myText dekla-
rierte Variable ist nach dem
Laden mithilfe des LoadVars-
Objekts myData über eben
dieses Objekt auslesbar
– myData.myText. Schritt für Schritt: Daten aus einer Textdatei mit Flash laden
In diesem Beispiel wollen wir das soeben erworbene theoretische Wissen in die Praxis
umsetzen, indem wir Adressinformationen aus einer Textdatei auslesen.
Im ersten Schritt müssen wir also die Textdatei erstellen. Hierzu sei erwähnt, dass die
Daten URL-codiert in die Textdatei eingefügt werden sollten.
1.Textdatei
erstellen
1.Textdatei
erstellen
SERVERSEITIGER DATENAUSTAUSCH – FLASH, PHP & DATENBANK 247
Der Inhalt der Textdatei sollte dann wie folgt aufgebaut werden (wie schon oben
erwähnt, ist es nicht notwendig, dass die Leerzeichen mit „%20“ URL-codiert werden
– deshalb verzichten wir hinsichtlich besserer Lesbarkeit im Folgenden darauf):
Vorname0=Uwe
&Nachname0=Mutz
&Firma=SYNE Marketing und Consulting GmbH
&Adresse0=Am Graben 29
&PLZ0=4020
&Ort0=Linz
&Staat0=AUT
&email0=uwe.mutz@syne.at
Vielleicht werden Sie sich wundern, warum wir bei den Variablen eine Nummerierung
eingeführt haben. Diese ist in unserem Beispiel eigentlich nicht notwendig. Möchte
man jedoch zu einem späteren Zeitpunkt dieses Beispiel erweitern und nicht nur eine
Person, sondern mehrere Personen einlesen, ist es notwendig, eindeutige Variablen-
namen zu verwenden. Durch eine derartige Nummerierung ist dies auf jeden Fall
gewährleistet (die nächste Person hätte dann Vorname1, Nachname1 usw.).
Abbildung 6.6 zeigt die Datei Einlesedaten01.txt, wo wir unser Beispiel von oben umge-
setzt haben.
Eindeutige
Variablennamen
Eindeutige
Variablennamen
ABBILDUNG 6.6
Die Datei Einlesedaten01.txt
beinhaltet alle für unser
Beispiel notwendigen Infor-
mationen. Achten Sie stets
darauf, dass alle Variablen-
namen eindeutig sind.
Tipp zum Einlesen von Textdaten
Bitte beachten Sie, dass es bei manchen Versionen des Flash-Plug-in zu Problemen beim
Einlesen kommen kann, wenn in der einzulesenden Datei Zeilenumbrüche nach den
Variablenwerten eingefügt werden. Speziell beim Weiterverarbeiten von Dateinamen sollte
darauf geachtet werden.
Ist die Textdatei fertig erstellt, können wir uns Flash widmen. Idealerweise teilt man in
diesem Beispiel die Zeitleiste mithilfe von Bildern in drei „Bereiche“ auf.
Der erste Bereich dient dazu, Variablen zu deklarieren und dem LoadVars-Objekt
die einzulesende Quelldatei anzugeben. Des Weiteren wird hier die Ereignisproze-
dur definiert, die uns signalisiert, wann das Laden der Textdatei abgeschlossen ist.
u
2. Flash-Datei
erstellen
2. Flash-Datei
erstellen
K A P I T E L 6248
Hierin werden auch die eingelesenen Werte weiterverarbeitet. Außerdem wird von
hier aus zum zweiten („Ladevorgang war nicht erfolgreich“) oder dritten („Lade-
vorgang war erfolgreich“) Bereich weitergeleitet.
Der zweite Bereich ist dafür bestimmt, dem User bei einem fehlgeschlagenen Lade-
vorgang eine entsprechende Meldung zu geben.
Der dritte Bereich („Ladevorgang war erfolgreich“) dient der Anzeige der eingele-
senen Daten.
Die Bereichsunterteilung ist in Abbildung 6.7 ersichtlich, ebenso die verwendeten
Ebenen. Die Dokumentgröße wurde auf 500x200 Pixel festgelegt. Wie schon im ein-
leitenden Kapitel zu Flash erwähnt, spielt es keine (wesentliche) Rolle, wie viele leere
Bilder in der Zeitleiste existieren – in unserem Beispiel sehen Sie, dass wir unser erstes
Schlüsselbild an Position 1, das nächste und übernächste Schlüsselbild aber erst an den
Positionen 5 und 25 platziert haben. Der große Vorteil an der gezeigten Arbeitsweise
ist die Übersichtlichkeit der Flash-Datei.
u
u
ABBILDUNG 6.7
Das Flash-Dokument wurde
in drei Bereiche unterteilt –
Bild 1 für das Deklarieren der
Variablen, „LadevorgangFehl-
geschlagen“, sofern das
Laden nicht geklappt
hat, und „Ladevorgang-
Erfolgreich“ für das Anzeigen
der geladenen Daten.
In Bild 1 werden zunächst alle Variablen und Objekte deklariert. Des Weiteren küm-
mern wir uns um die Ereignisprozedur, die nach dem abgeschlossenen Ladevorgang
aufgerufen wird.
var anzLadeversuche:Number = 0;
var maxLadeversuche:Number = 3;
var myLoader:LoadVars = new LoadVars();
myLoader.onLoad = function(loadedOK:Boolean):Void {
//Ladevorgang abgeschlossen.
3. Deklarieren
der notwendigen
Variablen und
Objekte
3. Deklarieren
der notwendigen
Variablen und
Objekte
SERVERSEITIGER DATENAUSTAUSCH – FLASH, PHP & DATENBANK 249
anzLadeversuche++;
if(loadedOK) {
//Daten wurden ERFOLGREICH geladen.
gotoAndStop("LadevorgangErfolgreich");
}
else {
if(anzLadeversuche<maxLadeversuche) { myLoader.
load("Einlesedaten01.txt"); }
else { gotoAndStop("LadevorgangFehlgeschlagen"); }
}
}
myLoader.load("Einlesedaten01.txt");
Listing 6.2: Code für den Ladevorgang der Daten aus einer Textdatei
Mit Einführung von Flash CS3 wurden wie erwähnt neue Zahlentypen eingeführt,
die den Umgang mit Ganzzahlen wesentlich vereinfachen: int und uint. Da diese
jedoch erst in ActionScript 3 verfügbar sind, stellt sich die Frage, ob man sie bei relativ
einfachen und wenig umfangreichen Beispielen einsetzen sollte. Oder stellen wir die
Frage anders herum: Warum sollte man sie denn nicht einsetzen? Nun, sehen wir uns
die Vor- und Nachteile noch einmal kurz an:
Vorteil: Der Prozessor kann mit Ganzzahlen wesentlich besser umgehen als mit
Fließkommazahlen („Floating Point Numbers“) – somit erfolgt das Abarbeiten von
Ganzzahlen wesentlich schneller.
Nachteil: Die Unterscheidung von Ganz- und Fließkommazahlen erfordert Action-
Script 3, wodurch man gezwungen ist, den Flash 9 Player einzusetzen. Da dieser
jedoch bei weitem nicht so verbreitet ist wie beispielsweise ein Flash 7 Player (dieser
würde für unseren Fall vollkommen ausreichen), schließt man einen nicht unbe-
trächtlichen Userkreis aus bzw. zwingt diese User, den 9er-Player zu installieren
(und wie wir wissen, ist die Überwindung zum Installieren einer Software nach
wie vor hoch).
Aus diesem Grund würde ich Ihnen raten, nach wie vor den Typ Number zu verwenden
und nur im „Ernstfall“ auf int oder uint zurückzugreifen.
Wie bereits weiter oben erwähnt, empfiehlt es sich, die Anzahl der Ladeversuche auf
einen maximalen Wert zu beschränken. Sollte der Ladevorgang danach noch immer
nicht erfolgreich verlaufen sein, würde man den Ladevorgang abbrechen und dem
Benutzer eine entsprechende Meldung am Bildschirm ausgeben.
In unserem Fall werden wir die Anzahl der Ladeversuche auf drei Versuche beschrän-
ken. Damit wir flexibel arbeiten, legen wir diesen Wert in einer Variablen fest.
u
u
Number oder
int / uint?
Number oder
int / uint?
4. Anzahl der
Ladeversuche
4. Anzahl der
Ladeversuche
K A P I T E L 6250
In Zeile drei wird das LoadVars-Objekt erzeugt und diesem ganz unten im Script eine
Datei zum Einlesen zugewiesen (Einlesedaten01.txt).
Ist dies geschehen, startet Flash automatisch den Ladevorgang. Sobald dieser abge-
schlossen ist, tritt das Ereignis onLoad auf, das wir in den folgenden Zeilen auswerten.
Zu diesem Zeitpunkt wissen wir noch nicht, ob der Ladevorgang erfolgreich oder
nicht erfolgreich abgeschlossen wurde. Auskunft darüber gibt uns die Variable (der
Ereignisparameter) loadedOK, die von Flash an die Funktion (korrekt gesprochen
handelt es sich hierbei wie erwähnt um eine Ereignisprozedur des LoadVars-Objekts)
übergeben wird, also:
loadedOK==true; //erfolgreich
loadedOK==false; //nicht erfolgreich
Listing 6.3: Ladeerfolg überprüfen mittels Ereignisparameter
Wie erwähnt können Sie anstatt des Ereignisparameters auch die Eigenschaft loaded
des LoadVars-Objekts überprüfen:
myloader.loaded==true; //erfolgreich
myloader.loaded==false; //nicht erfolgreich
Listing 6.4: Ladeerfolg überprüfen mittels der loaded-Eigenschaft
Dementsprechend wird in unserer Ereignisprozedur im Fall eines erfolgreichen Ladens
mithilfe von gotoAndStop("LadevorgangErfolgreich"); in der Zeitleiste auf das
Bild gesprungen, in der die Daten angezeigt werden.
War das Laden nicht erfolgreich, wird die Anzahl der Ladeversuche (gespeichert in der
Variable anzLadeversuche) um eins erhöht und – sofern wir noch unter der Maxi-
malzahl der Ladeversuche sind – der Vorgang erneut aufgerufen.
Im eher atypischen Fall, dass wir die Maximalzahl erreicht haben, verzweigt das Skript
zum Bild „LadevorgangFehlgeschlagen“ – darauf kommen wir etwas später noch zu
sprechen.
Vielleicht ist Ihnen aufgefallen, dass das obenstehende Skript keinen stop()-Befehl
beinhaltet. Dies würde ja bedeuten, dass Flash automatisch ins zweite Bild der Zeit-
leiste weiterspringt, und erst in Bild 2 wurde der stop()-Befehl von uns eingefügt.
Warum also erst in Bild 2 und nicht bereits in Bild 1?
Der Grund dafür ist, dass wir dem User im Bild „LadevorgangFehlgeschlagen“ die
Möglichkeit geben, den Ladevorgang „von Hand“ erneut zu starten, und wir somit
wieder zurück in das erste Bild springen. Dies kann entweder mit gotoAndPlay()
oder mit gotoAndStop() erfolgen. Der erste Befehl hat den Nachteil, dass ein etwai-
ges stop() im ersten Bild ignoriert und der Bildzeiger ins zweite Bild weiterspringen
5. LoadVars-
Objekt definieren
und Datei zum
Einlesen angeben
5. LoadVars-
Objekt definieren
und Datei zum
Einlesen angeben
6. Ladevorgang
starten und
Erfolg prüfen
Ereignisprozedur
onload
6. Ladevorgang
starten und
Erfolg prüfen
Ereignisprozedur
onload
7. Fallunter-
scheidung
7. Fallunter-
scheidung
8. stop()-Befehl
in Bild 2
8. stop()-Befehl
in Bild 2
SERVERSEITIGER DATENAUSTAUSCH – FLASH, PHP & DATENBANK 251
würde. Der zweite Befehl würde in manchen Plug-in-Generationen des Flash-Plug-ins
den Code im ersten Bild nicht ausführen.
Beide Probleme ersparen Sie sich, indem Sie erst im zweiten Bild den stop()-Befehl
setzen.
Zum Darstellen der Daten verwendet man am einfachsten dynamische Textfelder,
die direkt auf das LoadVars-Objekt myLoader zugreifen und die dort eingelesenen
gespeicherten Werte darstellen.
9. Darstellen
der eingele-
senen Werte
bei erfolgreich
verlaufenem
Ladevorgang
9. Darstellen
der eingele-
senen Werte
bei erfolgreich
verlaufenem
Ladevorgang
Für den Fall eines fehlgeschlagenen Ladens muss – schon aus Usability-Gründen
– dem User auf jeden Fall eine entsprechende Meldung ausgegeben werden.
Diese Meldung wird im else-Abschnitt der if-Bedingung mit folgendem Code fest-
gelegt:
else {
gotoAndStop("LadevorgangFehlgeschlagen");
}
Zu diesem Zeitpunkt ist es dann relativ unwahrscheinlich, dass ein erneuter Ladever-
such den gewünschten Erfolg bringen wird. Nichtsdestotrotz soll der User die Mög-
lichkeit haben, einen erneuten Versuch zu starten.
Dies lässt sich natürlich relativ einfach realisieren, da in der Zeitleiste nur wieder
auf das erste Bild gesprungen werden muss und somit der Ladeprozess von neuem
10. Ladevorgang
nicht erfolgreich
10. Ladevorgang
nicht erfolgreich
11. Ladevorgang
erneut starten
11. Ladevorgang
erneut starten
ABBILDUNG 6.8
Sofern der Ladevorgang
erfolgreich verlaufen ist,
wird in die dynamischen
Textfelder der Wert der
jeweiligen Variablen des
myLoader-Objekts ein-
gelesen, zum Beispiel der
Nachname 1.
K A P I T E L 6252
beginnt. Hierzu erzeugt man einen Button und weist diesem den entsprechenden Code
zu. Wir haben uns für eine Button-Komponente entschieden und dieser den Namen
„restartBtn“ gegeben.
var btnListener:Object = new Object();
btnListener.click = function():Void {
gotoAndStop(1);
}
restartBtn.addEventListener("click", btnListener);
Listing 6.5: Dieser Code wird benötigt, damit der User den Ladevorgang erneut ausführen lassen kann.
Zunächst erzeugen wir ein neues Objekt, das als Listener dienen soll, und weisen
diesem eine Funktion zu, die bei Klick aufgerufen werden soll (gotoAndStop(1);).
Danach weisen wir dem Button „restartBtn“ diesen Ereignislistener mittels
restartBtn.addEventListener("click", btnListener);
zu. Hiermit springt Flash bei Klick auf den Button in das erste Bild der Zeitleiste
zurück und alles beginnt von vorne.
ABBILDUNG 6.9
Sollte der Ladevorgang fehl-
schlagen, muss dem User
aus Usability-Gründen eine
entsprechende Meldung aus-
gegeben werden. Eventuell
ermöglicht man ihm einen
erneuten Ladeversuch über
einen Button.
Auf der Website zum Buch finden Sie dieses Beispiel – um mehrere Adressdaten
ergänzt – zu einer Adresssammlung erweitert. Auf diese Art kann man auf sehr ein-
fachem Wege Adressdaten von beispielsweise der Firmendatenbank per Handy oder
PDA abfragen – natürlich nur, sofern diese Geräte auch einen Internetzugang und
einen funktionsfähigen Webbrowser inklusive installiertem Flash-Plug-in haben.
SERVERSEITIGER DATENAUSTAUSCH – FLASH, PHP & DATENBANK 253
Usability
So einfach Ihre Flash-Anwendung für Sie anmuten sollte, so schwierig ist sie eventuell für
den User zu nutzen. Gehen Sie immer vom „Dümmsten anzunehmenden User“ (DAU) aus.
Keinesfalls wollen wir unsere User als dumm bezeichnen, jedoch hat sich dieser Ausdruck in
Entwicklerkreisen eingebürgert. Je eindeutiger die Warn- oder Hinweismeldungen sind, desto
leichter wird sich Ihr User beim Anwenden tun.
Daten aus einer Datenbank einlesen
Das Einlesen von Daten aus einer Datenbank funktioniert im Wesentlichen exakt
so wie das Einlesen von Daten aus einer simplen Textdatei. Der einzige Unterschied
gegenüber dem Auslesen aus der Textdatei besteht darin, dass keine Textdatei existiert,
sondern die entsprechenden Inhalte der Textdatei in einer PHP-Datei erzeugt werden.
Würde man die Textdatei und die PHP-Datei (in einem Browser) zur selben Zeit öff-
nen und die beiden betrachten, könnte man keinen Unterschied feststellen. Im Fall der
Textdatei sind die Inhalte „statisch“ (wir haben diese „per Hand“ in die Datei geschrie-
ben), im Fall der PHP-Datei „dynamisch“, denn die Inhalte werden über geeignete
PHP-Funktionen aus einer Datenbank ausgelesen.
Nehmen wir der Einfachheit halber das vorige Beispiel zur Hand, wo wir mit der Text-
datei Einlesedaten01.txt gearbeitet haben, die folgenden Inhalt aufweist:
Vorname0=Uwe
&Nachname0=Mutz
&Firma0=SYNE Marketing und Consulting GmbH
&Adresse0=Am Graben 29
&PLZ0=4020
&Ort0=Linz
&Staat0=AUT
&email0=uwe.mutz@syne.at
Listing 6.6: Inhalt der Datei Einlesedaten01.txt
Genau diesen Inhalt möchten wir nun mithilfe einer Datenbank und einer zugehö-
rigen PHP-Datei erzeugen. Zunächst benötigt man also eine Datenbank mit einer
entsprechenden Tabelle, welche die auszulesenden Daten beinhaltet.
K A P I T E L 6254
Ist diese Tabelle mit Daten gefüllt, können wir per PHP auch schon auf diese Daten
zugreifen. Wie Sie im Grundlagenteil über PHP & MySQL erfahren haben, ist der erste
Schritt der Zugriff auf die Datenbank mithilfe eines Users und eines Passworts. Sofern
die Datenbank lokal am jeweiligen Webserver installiert ist, kann per „localhost“ der
entsprechende Server ausgewählt werden.
localhost oder doch eine IP-Adresse?
Typischerweise werden auf Seiten des Providers der Web- und der Datenbankserverdienst auf
demselben Gerät betrieben. Ist dies der Fall, so kann eine serverseitige Technologie wie PHP über
die Adresse „localhost“ („der lokale Rechner“) auf den Datenbank- und Webserver-Dienst zugrei-
fen. Alternativ dazu könnte man auch die IP-Adresse 127.0.0.1 verwenden.
Zunächst einmal das benötigte Script:
$hostname = "IHR HOSTNAME";
$username = "IHR USERNAME";
$password = "IHR PASSWORT";
if(!$conn = mysql_connect($hostname, $username, $password)) {
die('<div class="error">Verbindung zur Datenbank konnte nicht
hergestellt werden. Errorcode: ‚.mysql_error().'</div>');}
else {
//echo('<div class="success">Die Verbindung zur Datenbank wurde
erfolgreich hergestellt.</div>');
}
Listing 6.7: Verbindungsaufbau zur Datenbank. Sollte die Verbindung zum Datenbankserver erfolgreich
gewesen sein, so muss keine „Erfolgsmeldung“ ausgegeben werden – aus diesem Grund ist der echo-
Befehl im else-Teil der if-Bedingung auskommentiert (für Testzwecke werden solche Ausgaben gerne
verwendet, denn dann hat man beispielsweise Gewissheit, dass die Verbindung zum Datenbankserver
geklappt hat). Klarerweise müssen Sie bei $hostname, $username und $passwort Ihre korrekten
Zugangsdaten eingeben.
1. Connect zum
Datenbankserver
1. Connect zum
Datenbankserver
ABBILDUNG 6.10
Die obige Tabelle „tbl_
Kunden“ speichert die
gewünschten Informationen
über unsere Kunden.
SERVERSEITIGER DATENAUSTAUSCH – FLASH, PHP & DATENBANK 255
In den Variablen $hostname, $username und $password werden die drei für den
Verbindungsaufbau zum Datenbankserver und zur Datenbank notwendigen Infor-
mationen gespeichert, die dann wiederum mithilfe der PHP-Funktion mysql_con-
nect() zum Aufbau der Verbindung herangezogen werden.
Alternativ dazu könnten Sie selbstverständlich auch diese drei Variablen in einem
Array zusammenfassen:
$dbConnect = array(
"hostname" => "IHR HOSTNAME",
"username" => "IHR USERNAME ",
"password" => "IHR PASSWORT",
"db" => "IHRE DATENBANK"
);
Listing 6.8: Alternative zu den verwendeten vier (bisher drei) Variablen für den Verbindungsaufbau sowie
den Datenbankzugriff
Die Verbindung selbst wird in einer Variablen $conn hinterlegt. Sollte der Verbin-
dungsaufbau aus irgendwelchen Gründen nicht funktioniert haben, weil z.B. Userna-
me bzw. Passwort falsch ist, wird von der Funktion mysql_connect() der Wert false
zurückgegeben und in der if-Bedingung entsprechend ausgewertet. Die Funktion
die() beendet den weiteren Ablauf der PHP-Datei und gibt mithilfe der Funktion
mysql_error() eine entsprechende Meldung inklusive der MySQL-Fehlermeldung
auf den Bildschirm aus.
War der Verbindungsaufbau erfolgreich, so wird in unserem Fall eine Meldung auf
den Bildschirm ausgegeben. Normalerweise werden solche „Erfolgsmeldungen“ nicht
angezeigt, sondern maximal für Testzwecke mit in den Code aufgenommen und
danach auskommentiert – unsere Erfolgsmeldung würde im „wahren“ Betrieb eben-
falls nicht zur Verwendung kommen, denn dass der Code erfolgreich war, merken
sowohl Entwickler als auch User, indem die Site funktioniert.
Wenn der Verbindungsaufbau zum Datenbankserver gelungen ist, stehen uns meistens
mehrere Datenbanken, die für uns freigegeben sind – sprich für die wir die notwen-
digen Berechtigungen haben –, zur Verfügung. Demnach müssen wir uns für eine
Datenbank entscheiden, was mithilfe der Methode mysql_select_db() erfolgt:
$db = "db_BuchFlashPHP";
if(!mysql_select_db($db)) {
die('<div class="error">Die Datenbank '.$db.' konnte nicht ausgewaehlt
werden. Errorcode: ‚.mysql_error().'</div>');
}
else {
2. Auswählen der
Datenbank
2. Auswählen der
Datenbank
K A P I T E L 6256
//echo('<div class="success">Die Datenbank '.$db.' wurde erfolgreich
ausgewaehlt.</div>');
}
Listing 6.9: Auswählen der Datenbank
Der Ablauf ist wieder der gleiche wie schon zuvor:
1. Definieren, welche Datenbank verwendet wird
Dies kann einerseits über die Definition einer Variablen (wie in diesem Fall) oder
direkt als Parameter der Methode mysql_select_db() geschehen. Ich habe mich
für Ersteres entschieden, da diese Variante übersichtlicher ist (als Alternative zur
Verwendung einer Variablen habe ich weiter oben schon die Verwendung eines
Arrays dargestellt).
2. Prüfen, ob das Auswählen der Datenbank erfolgreich war
Sollte die Methode mysql_select_db() den Wert false zurückgeben, war
die Auswahl der Datenbank nicht erfolgreich und man beendet im Allgemeinen
die weitere Ausführung der Site durch Verwendung der Methode die(). Der
Rückgabewert true signalisiert, dass die Auswahl der Datenbank in Ordnung
war.
3. SQL-Statement ausführen
War die Auswahl der Datenbank erfolgreich, können aus den Tabellen der
Datenbank Daten ausgelesen werden. Wie Ihnen bereits bekannt ist, verwendet
man hierzu die standardisierte Abfragesprache SQL.
Der Einfachheit halber wird der SQL-String zunächst einer Variablen zugewiesen
und danach ausgeführt. Diese Vorgehensweise hat den Vorteil, dass Testings einfacher
durchgeführt werden können, sollte ein Fehler bei der Abfrage generiert werden.
Selbstverständlich kann – wie bei den meisten PHP-Methoden – der entsprechende
Parameter auch direkt an die Methode übergeben werden. Hier sprechen wir von dem
SQL-Statement als String-Parameter für die Methode mysql_query(). Die meisten
Entwickler entscheiden sich jedoch für eine übersichtlichere Vorgehensweise mithilfe
zusätzlicher Variablen, in denen diese Parameter als Strings oder Ähnliches gespeichert
werden.
$sql = "SELECT * FROM tbl_Kunden";
if(!$query = mysql_query($sql)) {
die('<div class="error">Das SQL-Statement konnte nicht durchgefuehrt
werden. Errorcode: ‚.mysql_error().'</div>');
}
else {
SERVERSEITIGER DATENAUSTAUSCH – FLASH, PHP & DATENBANK 257
//echo('<div class="success">Das SQL-Statement:<br/>$sql<br/>wurde
erfolgreich abgesetzt.</div>');
}
Listing 6.10: Das SQL-Statement $sql wird der Methode mysql_query() als String-Parameter
übergeben.
Sie kennen ja mittlerweile das Procedere: Zunächst wird geprüft, ob das Absetzen des
SQL-Statement erfolgreich war. Dies erkennt man daran, dass in der Variable $query
nicht der Wert false gespeichert wird. Danach kann mit dem weiteren Ablauf der
Seite fortgesetzt werden. Für den Fall, dass das SQL-Statement nicht ausgeführt wer-
den konnte, wird mithilfe von die() abgebrochen.
Haben wir auch diesen Schritt erfolgreich hinter uns gebracht, müssen wir nur noch
für die korrekte Ausgabe der Daten sorgen. Idealerweise wird hierzu eine while()-
Schleife verwendet, in der so lange Daten ausgelesen werden, wie sich Datensätze in
der Tabelle befinden. Die Funktion mysql_fetch_array() läuft Zeile für Zeile die
Tabelle durch und speichert die Daten in einem assoziativen Array (alternativ dazu
können Sie auch die Funktion mysql_fetch_object() verwenden – diese Funktion
liefert anstatt eines assoziativen Arrays ein Objekt zurück). Des Weiteren zählen wir
die Anzahl der Zeilen mit – am einfachsten wird dies mit einer Variable (hier: $cnt)
erreicht, die pro Schleifendurchlauf um eins erhöht wird.
Das Verwenden dieser Zählvariable $cnt hat auch noch einen zweiten Grund: Letzten
Endes machen wir nichts anderes, als Text in ein „HTML“-Dokument zu schreiben,
indem wir die echo()-Funktion verwenden. Die ausgegebenen Daten stellen dann
nichts anderes als Variablen=Wert-Zuweisungen dar. Generiert man beispielsweise aus
unserer bestehenden Tabelle Daten, so könnte das wie unten gezeigt aussehen:
Vorname=Uwe
&Nachname=Mutz
&Firma=SYNE Marketing und Consulting GmbH
&Adresse=Am Graben 29
&PLZ=4020
&Ort=Linz
&Staat=AUT
&email=uwe.mutz@syne.at
Listing 6.11: Ausgabe des ersten Datensatzes. Diese Art der Datenausgabe ist nur für einen einzigen Daten-
satz verwendbar. Warum dem so ist, wird weiter unten erläutert.
Gesetzt den Fall, unsere Tabelle speichert aber mehr als nur einen einzigen Datensatz.
Dies hätte dann zur Folge, dass auch der zweite Datensatz in derselben Art und Weise
ausgegeben wird:
3. Daten zeilen-
weise auslesen
3. Daten zeilen-
weise auslesen
K A P I T E L 6258
Vorname=Thomas
&Nachname=Wegerer
&Firma=Softnomics Werbeagentur
&Adresse=Hart 14
&PLZ=4060
&Ort=Leonding
&Staat=AUT
&email=t.wegerer@softnomics.at
Listing 6.12: Ausgabe des zweiten Datensatzes
Eindeutige Variablenbenennung
Betrachten wir kurz das obige Beispiel: Welchen Wert hätte beim Auslesen durch Flash
beispielsweise die Variable Vorname? Die Antwort würde in unserem Fall „Thomas“ lauten, denn
in beiden Fällen (bei Vorname=Uwe und Vorname=Thomas) wurde dieselbe Variable (näm-
lich Vorname) als Speicherort verwendet. Um dieses Überschreiben zu verhindern, müssen die
Variablen eindeutig benannt sein, was im einfachsten Fall durch eine Durchnummerierung der
Variablen erreicht werden kann.
Vorname=Uwe und Vorname=Thomas liefern das falsche, Vorname0=Uwe und
Vorname1=Thomas das gewünschte Resultat. Somit lautet der korrekte Code zur Aus-
gabe der Daten:
$cnt = 0;
while($theData = mysql_fetch_array($query)) {
$msg = "";
if($cnt!=0) { $msg.="&"; }
$msg.="Vorname$cnt=".$theData["vc_Vorname"];
$msg.="&Nachname$cnt=".$theData["vcP_Nachname"];
$msg.="&Firma$cnt=".$theData["vc_Firma"];
$msg.="&Adresse$cnt=".$theData["vc_Adresse"];
$msg.="&PLZ$cnt=".$theData["vc_PLZ"];
$msg.="&Ort$cnt=".$theData["vc_Ort"];
$msg.="&Staat$cnt=".$theData["vc_Staat"];
$msg.="&email$cnt=".$theData["vc_email"];
echo($msg);
$cnt++;
}
Listing 6.13: Auslesen der Daten in einer while-Schleife in der Datei Einlesedaten02.php
4. Nummerierung
der Variablen
4. Nummerierung
der Variablen
SERVERSEITIGER DATENAUSTAUSCH – FLASH, PHP & DATENBANK 259
Sehen wir uns kurz den Code an: Über die Variable $cnt haben wir bereits gesprochen.
Die Variable $msg wird dazu verwendet, um pro Datensatz einen String zu speichern,
der dann später mit echo() ausgegeben wird (Codezeile 13). Mithilfe der Funkti-
on mysql_fetch_array() wird in die Variable (besser: das Array) $theData pro
Schleifendurchlauf ein kompletter Datensatz eingelesen, der dann in den Zeilen 5–12
zum Auslesen der einzelnen Spaltenwerte verwendet wird. Lediglich Zeile 4 des Codes
bedarf noch der Erklärung: Hier wird geprüft, ob gerade der erste Datensatz zum Aus-
geben in die HTML-Seite ansteht. Ist dies nämlich der Fall, darf kein führendes „&“
ausgegeben werden, in allen anderen Fällen jedoch schon.
Damit wären wir komplett – mehr darf auf die HTML-Seite an Information auch nicht
ausgegeben werden (beachten Sie bitte, dass selbstverständlich nur das im Browser aus-
gegeben wird, was durch einen echo()- oder die()-Befehl erzeugt wird). Vergleicht
man das Resultat mit der (händisch erzeugten) Textdatei aus dem vorigen Kapitel, so
werden Sie – bis eventuell auf Zeilenumbrüche – keinen Unterschied feststellen.
5. Ausgabe in
eine HTML-Datei
5. Ausgabe in
eine HTML-Datei
ABBILDUNG 6.11
Unsere PHP-Datei erzeugt
den gewünschten Inhalt im
Browser-Fenster.
Nun machen wir die Probe aufs Exempel und bringen Flash dazu, statt aus einer sta-
tischen Textdatei aus einer dynamischen PHP-Datei Daten einzulesen. Wir ersetzen
die Textdatei Einlesedaten01.txt in unserem Flash-Beispiel durch die PHP-Datei Einle-
sedaten02.php und testen, ob das Einlesen in Flash klappt.
PHP anstatt TXT in der Entwicklungsumgebung „Flash“
Bitte beachten Sie an dieser Stelle, dass PHP-Dateien durch einen Webserver verarbeitet werden
müssen. Aus diesem Grund können Sie PHP-Dateien nicht – wie gewohnt – direkt in Flash tes-
ten, sondern müssen die fertige SWF-Datei auf einen Webserver hochladen (dies kann selbstver-
ständlich auch ein lokal installiertes Webserver-Paket wie etwa XAMPP sein) und dort testen.
Schritt für Schritt: Daten aus einer PHP-Datei lesen
Ersetzt man in der vierten Codezeile des ersten Bilds der Flash-Datei aus der Schritt-
für-Schritt-Anleitung „Daten aus einer Textdatei mit Flash laden“ von weiter oben:
myLoader.load("Einlesedaten01.txt");
durch:
myLoader.load("Einlesedaten02.php");
sollten wir schon „im Geschäft“ sein. Haben Sie das vorige Beispiel nicht mitgemacht,
liegt die entsprechende Datei auch auf der Website zum Buch.
PHP anstatt TXTPHP anstatt TXT
1. Einlesen der
PHP-Datei
1. Einlesen der
PHP-Datei
K A P I T E L 6260
Daten aus Flash heraus übergeben
Bis jetzt haben wir Daten aus einer Textdatei oder einer Datenbank ausgelesen. Nun
wollen wir den umgekehrten Weg gehen und uns mit der Frage beschäftigen, wie man
Daten aus Flash heraus entweder einer (serverseitigen!) PHP-Datei zur Ausgabe auf
den Bildschirm übergibt oder die Daten in eine Datenbank speichert.
In diesem Fall ist es also so, dass Flash Daten sendet und PHP Daten empfängt. Nach-
dem PHP bekannterweise auf Serverseite und Flash auf Clientseite ausgeführt wird,
kann die Übergabe der Daten aus Flash auf zwei Arten erfolgen:
1. Flash ruft über den Befehl getURL() ein Dokument auf und übergibt mithilfe von
GET-Variablen auf diese Weise Daten an die PHP-Datei.
2. Flash verschickt Formulardaten und es wird das aus HTML bekannte Abschicken
von Formularinhalten verwendet. Die Methode send() des LoadVars-Objekts ist
dazu in der Lage.
Daten versenden mit GET & getURL
Beschäftigen wir uns also zunächst einmal mit Variante eins – dem Übergeben von
Werten über GET-Variablen an eine PHP-Datei. Diese Variante ist denkbar einfach,
denn es muss nichts anderes als ein URL-String „zusammengebaut“ werden, beispiels-
weise in der Art:
ausgabe01.php?variable0=wert0&variable1=wert1
Listing 6.14: Über & werden einzelne Strings verkettet.
ABBILDUNG 6.12
Das Einlesen der PHP-Datei
Einlesedaten02.php war
erfolgreich – so wie wir es
wollten! Perfekt.
SERVERSEITIGER DATENAUSTAUSCH – FLASH, PHP & DATENBANK 261
Umgesetzt in Flash würde dies dann wie folgt aussehen:
getURL("ausgabe01.php?variable0=wert0&variable1=wert1");
Alternativ dazu könnte man alle verwendeten Variablen durch ein zusätzliches Attribut
in der getURL()-Methode übergeben:
getURL("ausgabe01.php", "", "GET");
Listing 6.15: Versenden aller Variablen an die Datei ausgabe01.php
Das Attribut GET gibt also an, dass alle verwendeten Variablen per GET an die Datei
ausgabe01.php geschickt werden sollen. Wie leicht zu erraten ist, können die Variablen
auch per POST übergeben werden – darauf werden wir etwas weiter unten noch zu
sprechen kommen. Die vollständige Syntax dieser Methode lautet:
getURL("URL", "Fenster", "GET/POST");
Listing 6.16: Syntax der Methode getURL()
Die URL gibt an, welche Adresse aufgerufen werden soll. „Fenster“ steht für die aus
HTML bekannten Fenster (_self, _blank, _parent, _top, Standard ist _self) bzw.
Frames. GET/POST wurde bereits oben dargestellt – sämtliche Variablen werden ent-
weder per GET oder POST an die URL übergeben.
Für das Testen, ob die Daten aus Flash auch wirklich ankommen, verwenden wir fol-
gendes sehr einfaches PHP-Skript:
if(count($_GET)>0) {
foreach($_GET as $variable=>$wert) {
echo("$variable=$wert<br/>");
}
}
else {
echo("Es wurden keine Daten &uuml;bergeben.");
}
Listing 6.17: Ein kurzes Skript zum Überprüfen und etwaigen Ausgeben von übergebenen Daten
Die Variable $_GET ist ein assoziatives Array und beinhaltet alle per GET übergebenen
Daten. Die Funktion count() gibt an, wie viele Elemente im Array gespeichert sind.
Sollte die Anzahl der gespeicherten Elemente größer null sein, so wurden Daten über-
geben und man kann mit dem Auslesen der Daten beginnen. Die foreach-Schleife
liest alle übergebenen Variablen in Form von Variablenname ($variable) und Vari-
ablenwert ($wert) aus.
Wie Sie im Grundlagenkapitel zu PHP erfahren haben, dient die foreach-Schleife
dazu, alle Elemente eines Arrays (oder Ähnlichem) auszulesen. Sie bricht ab, sollte kein
K A P I T E L 6262
weiteres Element mehr existieren. In jedem Schleifendurchlauf werden den Variablen
$variable der Name der Variablen und $wert der Wert der Variablen zugewiesen. Ich
möchte an dieser Stelle noch einmal darauf hinweisen, dass alle übergebenen Variablen
immer vom Typ String sind.
$_GET, $_POST und $_REQUEST
Neben der Variable $_GET für per GET übergebene Variablen existieren auch noch die Variablen
$_POST (für alle per POST übergebenen Variablen) und $_REQUEST (generell für alle überge-
benen Variablen). In früheren Versionen wurden die Variablen $HTTP_GET_VARS und $HTTP_
POST_VARS genutzt, die im Gegensatz zu den jetzt verwendeten Variablen nicht global waren.
Nehmen wir mal an, wir würden in Flash folgendes Script verwenden:
var mySender:LoadVars = new LoadVars();
mySender.Vorname = "Uwe";
mySender.Nachname = "Mutz";
mySender.Variante = "LoadVars.send, per GET";
mySender.send("ausgabe01.php", "_blank", "GET");
Listing 6.18: Ein kleines Script, das drei Informationen (Vorname="Uwe", Nachmane="Mutz" sowie
Variante="LoadVars.send, per GET") an eine Datei namens ausgabe01.php schickt. Dieses
Dokument soll in einem neuen Fenster (_blank) aufgehen und die Daten werden mittels GET verschickt.
Das Resultat unseres kleinen Testbeispiels wird wie erwartet dargestellt (siehe Abbil-
dung 6.13). Rufen Sie dazu einfach die Datei LoadVars03.htm in Ihrem Browser auf.
ABBILDUNG 6.13
Die Übergabe der
Informationen von Flash an
die Datei ausgabe01.php hat
also geklappt.
Beachten Sie bitte auch die Adresszeile – sie beinhaltet sämtliche Variablen und zuge-
hörigen Werte:
http://flashphpajax.syneweb.com/Buchkapitel/Kap06/LoadVars/ausgabe01.php?
Variante=LoadVars%2Esend%2C%20per%20GET&Nachname=Mutz&Vorname=Uwe
Listing 6.19: In der Adresszeile des Browsers finden Sie die übergebenen Variablen, da wir uns für die Vari-
ante GET zum Versenden der Daten entschieden haben.
Daten versenden mit POST
Selbstverständlich werden wir die Probe aufs Exempel machen und die Daten per
POST aus Flash heraus verschicken. Dazu bedarf es im Flash-Code nur einer geringfü-
gigen Änderung – anstatt der Übergabemethode GET wird nun POST verwendet:
SERVERSEITIGER DATENAUSTAUSCH – FLASH, PHP & DATENBANK 263
getURL("ausgabe02.php", "_blank", "POST");
Des Weiteren wurde eine andere PHP-Datei geschrieben, denn im vorangegangenen
Beispiel wurden von der PHP-Datei nur GET-Variablen ausgewertet:
if(count($_POST)>0) {
foreach($_POST as $variable=>$wert) {
echo("$variable=$wert<br/>");
}
}
else {
echo("Es wurden keine Daten &uuml;bergeben.");
}
Listing 6.20: Dieses Skript überprüft, ob Daten per POST gesendet wurden, und gibt diese aus.
ABBILDUNG 6.14
Entgegen dem vorangegan-
genen Beispiel werden die
Daten hier per POST an die
PHP-Datei ausgabe02.php
übergeben.
Wie Sie sehen, ist das Resultat dasselbe wie zuvor, jedoch werden – wie bei POST-
Datenübergabe gewünscht – die Daten nicht sichtbar in der Adresszeile des Browsers
übergeben.
Daten versenden mithilfe des LoadVars-Objekts
Damit haben wir die Methode getURL() ausgereizt, also wenden wir uns der zweiten
Variante der Datenübergabe aus Flash heraus zu – nämlich dem LoadVars-Objekt
und dessen Methode send(). Im Abschnitt über das Empfangen von Daten haben
Sie gesehen, dass das LoadVars-Objekt alle eingelesenen Daten „in sich“ speichert.
Entsprechend geht man auch beim Senden von Daten vor.
1. Zunächst wird ein LoadVars-Objekt angelegt:
Wie auch beim Einlesen von Daten muss – sofern das LoadVars-Objekt zum
Einsatz kommen soll – zunächst ein LoadVars-Objekt angelegt werden:
var mySender:LoadVars = new LoadVars();
2. Danach müssen im LoadVars-Objekt Variablen angelegt werden, die die zu
versendenden Daten enthalten:
In vielen Fällen werden die zu versendenden Variablen zunächst in Flash als
normale Variablen angelegt und ihnen so Werte zugewiesen. Einfacher und
K A P I T E L 6264
eleganter ist es jedoch in jedem Fall, wenn die zu versendenden Daten sofort als
Variablen des LoadVars-Objekts deklariert werden. Da die zweite Variante auch
nicht mehr Arbeit erfordert, ist ihr also der Vorzug zu geben:
mySender.Vorname = "Uwe";
mySender.Nachname = "Mutz";
3. Zu guter Letzt müssen die Daten nur noch versandt werden:
Hierbei steht uns die send()-Methode des LoadVars-Objekts hilfreich zur Seite:
mySender.send("ausgabe01.php", "_blank", "GET");
bzw.
mySender.send("ausgabe02.php", "_blank", "POST");
Die beiden Zeilen unterscheiden sich nur in der Übergabe mit GET oder POST.
Das Prozedere ist das gleiche wie auch bei der Übergabe mittels getURL(). Die
vollständige Syntax unterscheidet sich – wenig überraschend – von getURL() in
keiner Weise:
LoadVars.send("URL", "Fenster", "GET/POST");
Listing 6.21: Syntax zum Versenden der Daten mithilfe des LoadVars-Objekts
Das Fenster kann wiederum entweder ein HTML-Fenster (_self, _blank, _parent,
_top) oder ein Frame sein. Die folgende Abbildung zeigt das Ergebnis sowohl der
GET- als auch der POST-Übergabe.
ABBILDUNG 6.15
Datenübergabe durch
die send-Methode des
LoadVars-Objekts
– einmal per GET (oben)
und einmal per POST
(unten). Die Abbildungen
unterscheiden von den
Abbildungen Abbildung
6.13 und Abbildung 6.14
nur in der Reihenfolge der
Variablenausgabe und der
Übergabevariante – die
Daten sind selbstverständlich
gleich.
send oder sendAndLoad?
Zum Schluss sei noch erwähnt, dass das LoadVars-Objekt noch eine weitere Methode
zum Senden und Empfangen von Daten besitzt – die Methode sendAndLoad. Diese
erledigt genau das, was der Name verspricht: nämlich das Senden und das Laden von
SERVERSEITIGER DATENAUSTAUSCH – FLASH, PHP & DATENBANK 265
Daten in dem Sinne, wie Sie es oben kennengelernt haben. Ein wesentlicher Vorteil von
sendAndLoad ist jedoch, dass die versendeten Daten nicht notwendigerweise in einem
Browser-Fenster dargestellt werden müssen.
Die Klasse LoadVars und die ActionScript-Referenz
An dieser Stelle möchte ich Ihnen noch einmal ans Herz legen, viel mit der ActionScript-
Referenz von Flash zu arbeiten. Allein beim Durchsehen der Referenz stößt man nicht selten auf
Klassen und Befehle, nach denen man schon lange gesucht hat.
Differenzierte Daten
Neben dem Senden von klassischen Formulardaten oder Variablen ist es hin und wie-
der auch erforderlich, differenzierte Daten zu verschicken. Ein Klassiker solcher Daten
ist beispielsweise eine Grafik oder eine PDF-Datei, die man auf einen Server hochladen
möchte. Seit Flash 8 besteht die Möglichkeit, solche Aufgaben mithilfe der FileRefe-
rence-Klasse zu erledigen.
Fassen wir noch einmal kurz zusammen:
Zum Versenden von Daten aus Flash heraus stehen uns die Möglichkeiten getURL
und die Methode send des LoadVars-Objekts (genauer: der LoadVars-Klasse) zur
Verfügung.
In beiden Varianten kann das Versenden per GET oder POST erfolgen.
Entscheidet man sich für die Variante getURL, so kann man beim Versenden mit
GET die URL schon so aufbereiten, dass die Variablen an den URL-String ange-
hängt werden. Beispielsweise so:
getURL("http://www.mydomain.at/mypage.php?myData=myValue;");
Oder man schickt automatisch alle in Flash verwendeten Variablen mithilfe des
Parameters GET an die Seite. Beispielsweise so:
getURL("http://www.mydomain.at/mypage.php", "", "GET");)
Sollen die Variablen per POST verschickt werden, so muss in jedem Fall der
Parameter POST verwendet werden.
Entscheidet man sich für die Variante mit der Methode send des LoadVars-
Objekts, so hat man hier wieder die Wahl zwischen Versand per GET oder POST,
wobei nur diejenigen Variablen verschickt werden, die dem LoadVars-Objekt
zugewiesen wurden.
u
u
u
u
K A P I T E L 6266
6.3 Die Basis: das XML-Objekt &
ActionScript 2.0
Die Herangehensweise an das Arbeiten mit XML-Daten hat sich zwischen ActionScript
2.0 und ActionScript 3.0 grundlegend geändert. Wurde in der Version 2.0 noch mit
einer einzigen Klasse (XML) gearbeitet, sind die daraus bekannten Eigenschaften und
Methoden in mehrere Klassen aufgeteilt worden, um Konflikte mit der in der Version
3.0 neu eingeführten XML-Klasse zu vermeiden. Seit ActionScript 3.0 wird nun im
Rahmen der XML-Klasse ECMAScript for XML (E4X) unterstützt.
Ähnlich wie das LoadVars-Objekt aus dem vorigen Kapitel dient das XML-Objekt
(exakt: die XML-Klasse) zum Einlesen und Versenden von Daten. XML bildet ebenso
wie das LoadVars-Objekt eine Schnittstelle zwischen Flash und der „Außenwelt“,
wobei XML als Bezeichnungssprache wesentlich umfassender und strukturierter ist als
das Arbeiten mit GET- oder POST-Variablen.
Zunächst stellt sich für den Flash-Entwickler jedoch die Frage, wann die XML-Klasse
und wann die LoadVars-Klasse eingesetzt werden. Man kann davon ausgehen, dass
eine Datenübergabe per XML immer dann Sinn macht, wenn die Datenmenge eini-
ge wenige Datensätze überschreitet. Spätestens bei mehr als 20 oder 30 Datensätzen
(welcher Form auch immer) würden wir persönlich zur XML-Klasse greifen, da die
Struktur von XML sehr viel übersichtlicher ist.
6.3.1 Grundlegende XML-Befehle
Die Vorgehensweise beim Arbeiten mit der XML-Klasse ähnelt dem bei der LoadVars-
Klasse. Auch hier muss zunächst eine neue Instanz der XML-Klasse erzeugt werden.
Darauf aufbauend können dann unter anderem die Methoden load(), send() und
sendAndLoad() verwendet werden.
Neben diesen grundlegenden Methoden bietet die XML-Klasse aufgrund des anders
gearteten Aufbaus gegenüber der LoadVars-Klasse eine Reihe von Methoden und
Eigenschaften, die das Parsen der eingelesenen Daten ermöglichen. An dieser Stelle
möchten wir noch einmal auf den Grundlagenteil zu XML verweisen, wo die Struktur
eines XML-Dokuments dargestellt und erläutert wird.
6.3.2 Einlesen von XML-Daten
Grundsätzlich kann jede bestehende XML-Datei in Flash eingelesen werden, wobei die
Dateiendung (.xml, .txt, .php ...) keine Rolle spielt. Entscheidend ist einzig und allein
der Inhalt der verwendeten Datei. Dadurch wird uns das dynamische Erzeugen von
XML-Content durch beispielsweise PHP ermöglicht. Andererseits ist es somit genauso
legitim, einen XML-Content in einer Textdatei abzuspeichern und diese auszulesen.
Parsen
Mit Parsen meint man in
diesem Zusammenhang das
(schrittweise) Auswerten
der eingelesenen Daten.
SERVERSEITIGER DATENAUSTAUSCH – FLASH, PHP & DATENBANK 267
XML oder Textdatei?
Immer dann, wenn eine Datenübergabe von einer Datenbank zu Flash oder umgekehrt
stattfinden soll, bei der die Daten strukturiert aufgebaut sind, empfiehlt sich die Ver-
wendung von XML-Dokumenten. Denkt man beispielsweise an einfache Beispiele wie
eine Kundenliste oder an komplexere Beispiele wie etwa das dynamische Generieren
von Flash-Spielen für unterschiedliche Kunden, was unterschiedliche Gestaltung von
Logos, Schriften, Level-Limits etc. mit sich bringt, so ist die Verwendung eines XML-
Dokuments als Schnittstelle perfekt.
Laden von XML-Daten ausschließlich von derselben Domain
Seit der Einführung von Flash 7 ist das Laden von XML-Daten nur noch von derselben Domain,
in der auch die Flash-Datei liegt, erlaubt. Man kann diese Einschränkung umgehen, indem man
eine lokale PHP-Datei verwendet, die eine entfernte URL in den Quellcode einliest – mehr dazu
im Anwendungsteil beim RSS-Reader.
Einlesen einer XML-Datei
Beginnen wir also mit dem Einlesen einer Textdatei mit XML-Content mit folgendem
Inhalt:
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<XML-Kundenliste>
<Kunden>
<Kunde>
<Vorname>Uwe</Vorname>
<Nachname>Mutz</Nachname>
<Firma>SYNE Marketing und Consulting GmbH</Firma>
<Adresse>Am Graben 29</Adresse>
<PLZ>4020</PLZ>
<Ort>Linz</Ort>
<Staat>AUT</Staat>
<email>uwe.mutz@syne.at</email>
</Kunde>
</Kunden>
</XML-Kundenliste>
Listing 6.22: Listing einer Textdatei mit XML-Content (EinlesedatenXML01.txt)
Öffnet man diese Datei online (offline werden Sie mitunter die Datei nur in Textform
erhalten) in einem Browser, so erhält man nachfolgende Abbildung.
K A P I T E L 6268
Man erkennt sehr schnell, dass der Internet Explorer nicht entsprechend der Datei-
endung (hier: .txt), sondern entsprechend des Inhalts die geeignete Darstellungsform
wählt. Beachten Sie jedoch bitte, dass die XML-konforme Art der Darstellung nicht
alle Browser beherrschen – derzeit ist von den gängigen Browsern nur der Internet
Explorer in der Lage, diese Darstellungsform auszugeben:
ABBILDUNG 6.16
Eine Textdatei mit XML-
Content in der Browser-
Darstellung im Internet
Explorer von Microsoft. Der
XML-Content wird als sol-
cher vom Browser erkannt
und XML-konform darge-
stellt.
ABBILDUNG 6.17
Sowohl der Opera-Browser
als auch der Firefox stellen
die Textdatei (mit XML-
Content) als Textdatei dar.
SERVERSEITIGER DATENAUSTAUSCH – FLASH, PHP & DATENBANK 269
Letzten Endes ist es jedoch für uns unerheblich, ob die verschiedenen Browser den
Inhalt als XML oder eben nicht interpretieren – wichtig für uns ist einzig und allein
die Tatsache, dass der Inhalt XML-konform ist.
Möchte man diese XML-Datei in Flash einlesen, so sind folgende Schritte vorzuneh-
men:
1. Anlegen einer Instanz der XML-Klasse
var myData:XML = new XML();
2. Ereignisprozedur für onLoad und Laden der Datei
Hier wird definiert, was beim Auftreten des onLoad-Ereignisses geschehen soll.
Hierfür verwenden wir wie auch schon aus dem vorigen Kapitel gewohnt eine
native Funktion:
myData.onLoad = function(loadedOK:Boolean):Void {
//Ereignisbehandlungsroutine
}
Im nächsten Schritt muss dieser XML-Instanz eine Quelldatei zugewiesen werden,
aus welcher die Daten geladen werden sollen. Diese Datei kann sowohl im selben
als auch in einem Unterverzeichnis abgelegt sein. Der eigentliche Aufruf passiert
erst ganz unten im Script (beachten Sie hierzu bitte auch die Ausführungen zur
„Reihenfolge von Ereignisprozeduren beim Laden“ aus dem vorigen Kapitel):
myData.load("URL zur Quelldatei");
3. Überprüfen, ob das Laden erfolgreich war
Innerhalb der Ereignisbehandlungsroutine wird nun kontrolliert, ob das Laden
der Datei erfolgreich war. Ein erfolgreiches Laden wird durch die Eigenschaft
loadedOK==true (oder einfacher: loadedOK) des XML-Objekts dargestellt.
if(loadedOK) {
//beispielsweise Auslesen der Daten.
}
else {
//Fehler beim Laden aufgetreten. Evtl. erneuter Ladeversuch?
}
4. Überprüfen der eingelesenen Daten:
Sollte der Ladeversuch erfolgreich verlaufen sein,muss man sich darum kümmern,
die so geladenen Daten auszuwerten. Dabei muss man sich bewusst sein, dass
sämtliche eingelesenen Daten im Container myData gespeichert sind und von dort
gelesen werden müssen.
K A P I T E L 6270
Um auf sehr schnelle Art und Weise zu testen, ob die eingelesenen Daten korrekt
sind,kannmandengesamteneingelesenenXML-BaumineinenStringumwandeln
und als solchen ausgeben lassen:
myLoader.toString ();
XML-Baum in Flash ausgeben
Angewandt in einem Flash-Skript würden die oben dargestellten Schritte wie folgt
aussehen:
System.useCodepage = true;
var anzLadeversuche:Number = 0;
var maxLadeversuche:Number = 3;
var myLoader:XML = new XML();
var mySource:String = "EinlesedatenXML01_UTF-8.txt";
myLoader.ignoreWhite = true;
myLoader.onLoad = function(loadedOK:Boolean) {
//Ladevorgang abgeschlossen.
anzLadeversuche++;
if(loadedOK) {
//Daten wurden ERFOLGREICH geladen.
trace("[ SYSTEM ]: Daten erfolgreich geladen.nn");
trace("Die eingelesenen Daten waren:n");
trace(myLoader.toString());
}
else {
if(anzLadeversuche<maxLadeversuche) { myLoader.load(mySource); }
else { trace("[ SYSTEM ]: Maximale Anzahl der Ladeversuche
("+anzLadeversuche+") erreicht. Weiteres Laden wird abgebrochen");
}
}
}
SERVERSEITIGER DATENAUSTAUSCH – FLASH, PHP & DATENBANK 271
myLoader.load(mySource);
stop();
Listing 6.23: Das Flash-Skript XMLLoad01.fla zum Einlesen und Darstellen der XML-Daten in Form eines
Strings liegt wie gewohnt auf der Buch-CD. Sollte die XML-Datei bereits UTF-8-codiert sein, so können Sie
die erste Zeile des Scripts entfernen, da Flash standardmäßig bereits UTF-8-codiert arbeitet.
Leere Textknoten: ignoreWhite = true
In vielen Fällen werden in Flash XML-Daten eingelesen, die Textknoten nur mit Leerzeichen
enthalten. Erkennt Flash solche „leeren“ Textknoten, so werden diese normalerweise gelöscht
und nicht geparst. Genau dieser Fall könnte aber fatal enden, denn leere Textknoten treten rela-
tiv häufig auf – auch in unserem Beispiel. Setzen Sie deshalb die Eigenschaft ignoreWhite des
XML-Objekts auf true, um das Löschen der leeren Textknoten zu verhindern.
Führt man dieses Skript in Flash aus, so erhält man im Ausgabefenster den kompletten
XML-Baum angezeigt. Klarerweise sind die Daten in dieser Form nicht verwendbar
– sie müssen in die einzelnen Bestandteile zerlegt werden. Hierzu muss man Stufe für
Stufe den XML-Baum zerlegen, wobei die Struktur bzw. die Verschachtelungen nicht
notwendigerweise bekannt sein müssen. Flash ist in der Lage, den Tag-Namen, die
Attribute und den Wert jedes Tag auszulesen. Des Weiteren stehen hilfreiche Methoden
zum Überprüfen zur Verfügung, beispielsweise ob ein Elternelement Kindelemente
aufweist bzw. wie viele es aufweist. Aber fangen wir klein an!
ABBILDUNG 6.18
In der Testumgebung von
Flash kann man auf einfache
Art die eingelesenen Daten
in Form eines Strings ausge-
ben lassen.
K A P I T E L 6272
Vorgehensweise beim Einlesen der XML-Daten
Der aufwändigere Part ist nun das Zerlegen des XML-Baums in seine Bestandteile.
Dazu ist es notwendig, sich Schritt für Schritt durch den XML-Baum zu arbeiten. Aus
dem Grundlagenteil wissen Sie, dass die erste Zeile in einem XML-Dokument eine
Kennzeichnung dieses Dokuments als XML-Dokument ist. Das darauffolgende Ele-
ment repräsentiert das sogenannte Wurzelelement und umschließt alle weiteren Tags.
In unserem Fall ist dies das Element <XML-Kundenliste>.
Des Weiteren kann man den Baum wie folgt zerlegen:
1. <XML-Kundenliste> ist das Wurzelelement und beinhaltet als erstes Kind
(„Child“) das Element <Kunden>.
2. <Kunden> beinhaltet ein Child-Element namens <Kunde>.
3. <Kunde> beinhaltet acht Child-Elemente: <Vorname>, <Nachname>, <Firma>,
<Adresse>, <PLZ>, <Ort>, <Staat> und <email>.
4. Jedes der Child-Elemente von <Kunde> hat sieben (oben genannte) Geschwister-
Elemente (im Englischen „Sibling“ genannt).
5. JedesdieserChild-Elementevon<Kunde> weistTextelementeauf,alsoimEndeffekt
Werte. Im Allgemeinen sind wir genau an diesen Werten interessiert.
Auf XML-Elemente zugreifen
Um nun ausgehend von den eingelesenen Daten auf die einzelnen Elemente zuzu-
greifen, geht man folgendermaßen vor. Zunächst einmal ist die Kennzeichnung des
Dokuments als XML-Dokument für uns nicht von Bedeutung. Trotzdem ist dies genau
ABBILDUNG 6.19
Das eingelesene XML-
Dokument in Baumform
(Strukturdiagramm)
dargestellt
SERVERSEITIGER DATENAUSTAUSCH – FLASH, PHP & DATENBANK 273
das erste eingelesene Element in unserer Liste, wobei es somit auch das übergeordnete
Element im Baum darstellt. Demnach müssen wir auch auf ein erstes Child zugreifen,
was wir mit folgendem Befehl erreichen:
myLoader.firstChild
Somit haben wir in der Baumstruktur des XML-Dokuments das Element <XML-Kun-
denliste> erreicht.
Aus dem oben dargestellten Baum erkennt man, dass auch dieses Element nicht von
allzu großem Interesse für uns ist, denn auch <XML-Kundenliste> beinhaltet nur ein
weiteres Child-Element namens <Kunden>, welches wir wiederum durch den Befehl
firstChild (diesmal vom Tag <XML-Kundenliste>) erreichen:
myLoader.firstChild.firstChild
In unserem Fall enthält das Tag <Kunden> nur einen einzigen Kunden (Uwe Mutz),
dessen Daten wir auslesen können. Also ist unser nächster Schritt das Zugreifen auf
die Daten des Tag <Kunde>, welches ein Child-Element von <Kunden> ist. Der Zugriff
erfolgt wie schon bekannt per:
myLoader.firstChild.firstChild.firstChild
ABBILDUNG 6.20
Nach dem Einlesen eines
XML-Dokuments arbeitet
man sich Schritt für Schritt
(„Child für Child“) vom über-
geordnetsten Element nach
unten.
Zugriff über das Array childNodes
Über den Zugriff auf das Array childNodes eines jeweiligen Knotens bzw. Elements
hat man Zugriff auf alle Child-Elemente dieses Knotens. Standardmäßig wird im Array
wie immer bei 0 zu zählen begonnen, die Anzahl der Werte im Array erhält man über
dessen Eigenschaft length.
K A P I T E L 6274
Möchte man nun auf die einzelnen Kinder von <Kunde> zugreifen, so erledigt man
dies am einfachsten über genau das oben beschriebene Array childNodes in Verbin-
dung mit einer for-Schleife:
var theData:Array = myLoader.firstChild.firstChild.firstChild.childNodes;
for(var i:Number=0; i<theData.length; i++) {
trace("Child"+i+": <"+theData[i].nodeName+">");
trace("Wert="+theData[i].firstChild.nodeValue);
}
Listing 6.24: Auslesen aller Child-Elemente eines Knotens mithilfe einer for-Schleife
Inhalt der Knoten mit nodeValue
Im obigen Beispiel sieht man, dass auch die Werte eines Knotens wiederum ein Child-
Element des Knotens sind. Aus diesem Grund musste in Zeile 5 per firstChild auf
das Child-Element zugegriffen werden, bevor der Textwert per nodeValue ausgelesen
werden kann. Erst dieses Child-Element stellt den ersehnten Textknoten mit dem
eigentlich auszulesenden Wert dar.
Oft ist es hilfreich zu wissen, ob ein Knoten überhaupt Child-Elemente umfasst. Die
Methode hasChildNodes() eines Knotens gibt uns darüber Auskunft. Würden wir
diese Methode auf den ersten Knoten unseres XML-Dokuments, also die Definition
des XML-Dokuments, anwenden, würde sie den Wert true zurückliefern, da der erste
Knoten sehr wohl ein Child-Element umfasst, nämlich <XML-Kundenliste>.
myLoader.hasChildNodes(); //liefert den Wert true
Die nachfolgende Auflistung von Methoden und Eigenschaften der XML-Daten soll
Ihnen helfen, sich beim Einlesen von XML-Daten zurechtzufinden:
Methoden Verwendung
hasChildNodes Gibt Auskunft darüber,ob ein Knoten über Kinder verfügt.Ist dem so,so liefert die
Methode den Wert true zurück,andernfalls false.
Eigenschaften Verwendung
firstChild Verweist auf das erste Child-Element des angegebenen Knotens.
lastChild Verweist auf das letzte Child-Element des angegebenen Knotens.
nextSibling Verweist auf das nächste Geschwister-Element (den„Nachbarn links im XML-Baum“)
des angegebenen Knotens.
previousSibling Verweist auf das vorherige Geschwister-Element (den„Nachbarn rechts im XML-
Baum“) des angegebenen Knotens.
nodeName Gibt den Namen des aktuellen Knotens aus.
nodeType Gibt den Typ des aktuellen Knotens aus.Folgende Werte sind möglich:1 steht für ein
XML-Element und 3 für einen Textknoten.
nodeValue Gibt den Text des angegebenen Knotens aus,sofern es sich um einen Textknoten
handelt.
parentNode Verweist auf den übergeordneten Knoten (das Eltern-Element).
SERVERSEITIGER DATENAUSTAUSCH – FLASH, PHP & DATENBANK 275
Arrays Verwendung
attributes Dies ist ein Objekt,welches alle Attribute des aktuellen Knotens beinhaltet.
childNodes Ein Array mit Bezügen auf sämtliche Child-Elemente des aktuellen Knotens.
Tabelle 6.1: Die wichtigsten Methoden, Eigenschaften und Arrays im Überblick – eine vollständige
Auflistung aller Ereignisse, Methoden und Eigenschaften finden Sie in der ActionScript-Referenz von
Adobe oder in der Flash-Hilfe.
Wie sieht es nun mit konkreten Anwendungen von XML-Daten aus? Zunächst einmal
sei gesagt, dass es wenig Sinn macht, eine XML-Datei einzulesen, deren Aufbau man
nicht kennt. Grundsätzlich ist es mithilfe von rekursiver Programmierung zwar mög-
lich, auf alle eingelesenen Daten zuzugreifen, andererseits ist dies nutzlos, wenn man
nicht weiß, was man mit den eingelesenen Daten nun anstellen soll.
Rekursive Programmierung
Mit rekursiver Programmierung ist eine Programmiertechnik gemeint, bei der sich Funktionen
(Methoden) bei Bedarf selbst aufrufen. Beispielsweise beim Programmieren von Newsgroups
wird gerne auf rekursive Programmierung zurückgegriffen, da man in diesem Fall etwa
Kommentare zu Kommentaren von Einträgen finden muss und es von vorneherein nicht fest-
steht, wie tief diese Verschachtelung von Kommentaren geht.
Auswerten von XML-Daten
Gehen wir das Einlesen und Auswerten der Daten an, denn hier ist noch ein bisschen
Arbeit vonnöten. Gegenüber dem Einlesen der Textdatei aus dem ersten Beispiel (erin-
nern Sie sich: Es wurden die „Kundendaten“ durchnummeriert, also beispielsweise
„Nachname0“, „Nachname1“ usw.) muss jetzt der XML-Baum zerlegt werden. Am
einfachsten wird das entweder durch Einlesen der Werte in entsprechende Variablen
oder über das Verwenden von Arrays im Zusammenhang mit Objekten erledigt. Ent-
scheidet man sich für die erste Variante, so muss man sich darüber im Klaren sein, dass
man eventuell eine größere Anzahl von Variablen benötigt (in unserem Fall wären das
bei nur einem Datensatz bereits acht Variablen: Vorname, Nachname, Firma, Adresse,
PLZ, Ort, Staat, email). Die zweite Variante bietet den großen Vorteil, mit nur einer
einzigen „Variablen“ – genau genommen dem Array – arbeiten zu müssen.
Wir werden uns beide Varianten ansehen und Sie können dann selbst entscheiden,
welche Variante Ihnen eher zusagt bzw. auf Ihren speziellen Anwendungsfall am besten
passt.
Idealerweise findet das Auslesen des XML-Baums gleich nach dem Laden statt. Das
wäre in unserem Fall zu dem Zeitpunkt, wo das Ereignis onLoad auftritt und der
Ladevorgang erfolgreich war:
myLoader.onLoad = function(loadedOK:Boolean):Void {
//Ladevorgang abgeschlossen.
anzLadeversuche++;
K A P I T E L 6276
if(loadedOK) {
//Daten wurden ERFOLGREICH geladen.
...
Listing 6.25: Auszug aus dem Skript des Ladevorgangs der XML-Datei. Hier sollte man mit dem Auswerten
des XML-Baums beginnen.
XML-Daten über Variablen auswerten
Führen wir uns zunächst Variante 1 zu Gemüte, bei der wir den eingelesenen Datensatz
in Variablen speichern. Hierzu gehen wir wie folgt vor:
1. Zunächst erzeugen wir die Variablen, in denen die eingelesenen Werte gespeichert
werden sollen.
2. Danach springen wir im eingelesenen XML-Baum an die Stelle, wo die für uns
relevanten Kundendaten beginnen.
3. Ab dieser Stelle gehen wir die Daten Schritt für Schritt durch, lesen die Werte aus
und schreiben sie in die entsprechenden Variablen.
Nun denn – Schritt für Schritt: Daten aus einer XML-Datei lesen, Variante 1:
Basis dieses Beispiels ist wieder die Flash-Datei aus der Schritt-für-Schritt-Anleitung
„Daten aus einer Textdatei mit Flash laden“. Sie finden die Datei auch auf der Buch-
CD.
1. Anlegen der Variablen zum späteren Speichern der eingelesenen Werte
Wie oben bereits erwähnt, benötigen wir acht Variablen (pro Datensatz, wobei
wir derzeit mit nur einem Datensatz arbeiten). Beachten Sie, dass die Variablen
außerhalb der Funktion für das onLoad-Ereignis angelegt werden müssen, da
sie sonst nur innerhalb der Funktion gültig sind (sollte Ihnen das unklar sein, so
schlagen Sie bitte bei den Grundlagen der Programmierung nach):
var Vorname:String, Nachname:String, Firma:String, PLZ:String, Ort:
String, Staat:String, email:String;
Alle Variablen sind vom Typ String – auch die Postleitzahl, denn es könnte sich
um Kunden aus beispielsweise Großbritannien handeln, wo die Postleitzahlen aus
Ziffern und Buchstaben bestehen.
2. Springen zu dem Punkt im XML-Baum, wo die relevanten Daten beginnen
Nehmen Sie hierzu bitte die Abbildung 6.19 zur Hand – hier sehen Sie, dass wir
zum Tag <Kunde> springen müssen,um zu den relevanten Daten zu gelangen.Dies
geschieht – wie in Listing 6.25 zu sehen – innerhalb der Funktion zum onLoad-
Ereignis:
var theData:Array = myLoader.firstChild.firstChild.firstChild.childNodes;
SERVERSEITIGER DATENAUSTAUSCH – FLASH, PHP & DATENBANK 277
3. Speichern der XML-Daten in Variablen
Abschließend werden die Daten in der richtigen Reihenfolge in den dafür
vorgesehenen Variablen gespeichert:
Vorname = theData[0].firstChild.nodeValue;
Nachname = theData[1].firstChild.nodeValue;
Firma = theData[2].firstChild.nodeValue;
Adresse = theData[3].firstChild.nodeValue;
PLZ = theData[4].firstChild.nodeValue;
Ort = theData[5].firstChild.nodeValue;
Staat = theData[6].firstChild.nodeValue;
email = theData[7].firstChild.nodeValue;
Listing 6.26: Die eingelesenen Daten werden in den dafür vorgesehenen Variablen gespeichert (Auszug).
Reihenfolge beachten
Bitte beachten Sie, dass die Reihenfolge der Informationen (zuerst Vorname, dann Nachname,
Firma usw.) von entscheidender Bedeutung ist und uns beim Einlesen bekannt sein muss. Das
Speichern der Daten in genau der richtigen Reihenfolge ist natürlich eine lästige Angelegenheit,
nicht zuletzt deshalb, weil es eine potenzielle Fehlerquelle darstellt.
4. Dynamische Variablennamen
Hier stellt sich unweigerlich die Frage, ob man nicht die schon in der XML-Datei
verwendetenTag-Namen<Vorname>,<Nachname> usw.direktalsVariablennamen
heranziehen kann. Ja, dem ist so – es besteht in Flash die Möglichkeit, dynamisch
Variablennamen zu erzeugen. Jedem Hierarchie-Objekt in Flash ist ein Array von
Variablen zugeordnet – möchte man beispielsweise dem _root-Objekt dynamisch
Variablen zuweisen, so ist dies über den Zugriff auf das Array-Objekt möglich:
_root["Variablenname"] = Wert;
Dies kann man sich zu Nutze machen,indem man denVariablennamen,der letzten
Endes ein reiner String ist, aus dem Tagnamen der XML-Datei generiert:
_root[theData[x].nodeName] = Wert;
x stellt eine beliebige Stelle im Array der eingelesenen Daten dar. Angewandt auf
unser konkretes Beispiel würde dies wie folgt aussehen:
for(var i:Number=0; i<theData.length; i++) {
_root[theData[i].nodeName] = theData[i].firstChild.nodeValue;
}
In dieser for-Schleife werden sämtliche eingelesenen Knoten als Werte des
Arrays theData (hierin sind die einzelnen Einträge als Objekte angelegt) mit
K A P I T E L 6278
dem zugehörigen Knotennamen gespeichert. Beachten Sie, dass i (im Script fett
geschrieben) der Index über alle Einträge des Arrays ist.
5. Das fertige Skript
Das vollständige Skript dieses Beispiels sieht wie folgt aus. Sie finden es auch noch ein-
mal auf der Buch-CD (XMLLoad02a.fla). Wie bereits weiter oben besprochen, können
Sie in diesem Script die erste Zeile entfernen, wenn ein Dokument bereits den UTF-8-
Zeichensatz verwendet (Flash arbeitet standardmäßig mit dem UTF-8-Zeichensatz):
System.useCodepage = true;
var anzLadeversuche:Number = 0;
var maxLadeversuche:Number = 3;
var myLoader:XML = new XML();
var mySource:String = "EinlesedatenXML01_UTF-8.txt";
myLoader.ignoreWhite=true;
//var Vorname:String, Nachname:String, Firma:String, PLZ:String, Ort:
String, Staat:String, email:String; //nicht mehr notwendig, da diese
Variablen implizit deklariert werden
myLoader.onLoad = function(loadedOK:Boolean) {
//Ladevorgang abgeschlossen.
anzLadeversuche++;
if(loadedOK) {
var theData:Array = myLoader.firstChild.firstChild.firstChild.
childNodes;
for(var i:Number=0; i<theData.length; i++) { _root[theData[i].
nodeName] = theData[i].firstChild.nodeValue; }
gotoAndStop("LadevorgangErfolgreich");
}
else {
if(anzLadeversuche<maxLadeversuche) { myLoader.load(mySource); }
else { gotoAndStop("LadevorgangFehlgeschlagen"); }
}
}
myLoader.load(mySource);
Listing 6.27: Der Lohn unserer Mühen – das vollständige Einleseskript für die XML-Daten aus unserem
Beispiel (XMLLoad02a.fla)
SERVERSEITIGER DATENAUSTAUSCH – FLASH, PHP & DATENBANK 279
Das _root-Array
Dieses Array ist ideal für das dynamische Anlegen von eventuell nicht von vorneherein bekannt-
en Variablennamen. Das _root-Array ist somit ein assoziatives Array, wobei die Elemente im
Array die _root-Variablen darstellen. Variablen auf Root-Ebene sind für alle Scripts zugänglich
und somit quasi „global“. (Hardcore-Programmierer würden mich jetzt zwar schimpfen, da man
hier nicht von globalen Variablen spricht, aber mir ist an dieser Stelle der Sinn solcher Variablen
wichtiger … liebe Programmierer, bitte verzeiht mit diesen kleinen Fehler!)
6. Daten in Flash ausgeben
Nun müssen wir uns nur noch um die Darstellung der gespeicherten Daten
kümmern. Anders als im vorigen Beispiel mit der Textdarstellung der Daten
können wir nun direkt Variablenwerte in den dynamischen Textfeldern darstellen.
Die dynamischen Textfelder geben somit die Variablen Vorname, Nachname,
Firma usw. aus.
Hierzu werden – wie in der folgenden Abbildung dargestellt – die Variablen
Nachname, Vorname usw. als Ausgabevariablen der dynamischen Textfelder
verwendet.
ABBILDUNG 6.21
Beim Ausgeben der gespei-
cherten Daten muss gegen-
über dem Einlesen von URL-
kodierten Textdaten darauf
geachtet werden, dass nun
reine Variablenwerte ausge-
geben werden.
XML-Daten über Arrays auswerten
Nun zu Variante 2 – das Einlesen der Daten in ein Array, das Objekte beinhaltet. Gra-
fisch dargestellt würde das zu verwendende Array wie in der Abbildung 6.22 gezeigt
aufgebaut sein.
K A P I T E L 6280
1. Zunächst wird ein Array erzeugt, das so viele Zellen beinhaltet wie – in unserem
Fall – der XML-Baum Kunden beinhaltet. Derzeit ist dies nur ein einziger Kunde,
jedoch sollte das Beispiel später auch für mehrere Kunden funktionieren. Die
Anzahl der Array-Zellen kann natürlich auch dynamisch erzeugt werden, wenn
von vorneherein nicht feststeht, wie viele Daten eingelesen werden.
2. Danach wird in jeder Zelle des Arrays pro Kunde ein Objekt angelegt, das alle
Informationen zum Kunden speichert (Vorname, Nachname etc.).
Sinn macht das Speichern in Arrays und Objekten nur dann, wenn wir mehr als
einen einzigen Datensatz einlesen, denn wozu sollten wir sonst ein Array an Objekten
anlegen. Obwohl jedoch unsere eingelesene Datei aus nur einem einzigen Datensatz
besteht, arbeiten wir dieses Beispiel trotzdem exemplarisch mit einem Datensatz ab.
Im Workshop-Teil greifen wir dieses Beispiel noch einmal auf und laden mehrere
Datensätze ein.
Schritt für Schritt: Daten aus einer XML-Datei lesen,Variante 2. Folgende Schritte sind
vorzunehmen, um den XML-Baum einzulesen:
1. Array anlegen
In diesem Array werden die jeweiligen Informationen als Objekt gespeichert. Der
Name des Arrays ist selbstverständlich frei wählbar – wir haben uns an dieser Stelle
für theDataStore entschieden.
var theDataStore:Array = new Array();
2. for-Schleife über alle Datensätze
Unser Beispiel ist bereits so weit vorbereitet, dass eine Reihe von Datensätzen
eingelesen werden könnten. Aus diesem Grund lassen wir eine for-Schleife über
alle eingelesenen Datensätze laufen.
var theData:Array = myLoader.firstChild.firstChild.childNodes;
for(var i:Number=0; i<theData.length; i++) {
…
ABBILDUNG 6.22
Speichern der eingelesenen
Daten in Objekten, die sich in
einem Array befinden.
Objekte
Selbst erzeugte Objekte
sind zum Speichern von
strukturierten Daten her-
vorragend geeignet. Dies
sollte man sich in Flash zu
Nutze machen.
SERVERSEITIGER DATENAUSTAUSCH – FLASH, PHP & DATENBANK 281
3. Erzeugen eines Objekts pro Zelle im Array
Innerhalb der Schleife muss dann im Array an der jeweiligen Stelle (Zelle) ein
Objekt angelegt werden.
Pro eingelesenem Datensatz (hier: pro Kunde) wird im Array eine eigene Zelle
benötigt, der ein Objekt zugewiesen wird. Das Objekt selbst speichert die
gewünschten Informationen, welche hier Vorname, Nachname usw. sind.
theDataStore[i] = new Object();
4. Speichern der XML-Daten im Objekt
Zu guter Letzt werden die Daten ins Objekt geschrieben:
theDataStore[i].Vorname = theData[i].childNodes[0].firstChild.nodeValue;
theDataStore[i].Nachname = theData[i].childNodes[1].firstChild.nodeValue;
theDataStore[i].Firma = theData[i].childNodes[2].firstChild.nodeValue;
theDataStore[i].Adresse = theData[i].childNodes[3].firstChild.nodeValue;
theDataStore[i].PLZ = theData[i].childNodes[4].firstChild.nodeValue;
theDataStore[i].Ort = theData[i].childNodes[5].firstChild.nodeValue;
theDataStore[i].Staat = theData[i].childNodes[6].firstChild.nodeValue;
theDataStore[i].email = theData[i].childNodes[7].firstChild.nodeValue;
Listing 6.28: Sämtliche zu speichernde Daten werden im Objekt abgelegt (Auszug).
5. Variablen anlegen
Da unser Beispiel einen Datensatz ausgeben soll,werden die darzustellenden Daten
wie schon zuvor in Variablen gespeichert, die dann in dynamischen Textfeldern
ausgegeben werden.
Vorname = theDataStore[0].Vorname;
Nachname = theDataStore[0].Nachname;
Firma = theDataStore[0].Firma;
Adresse = theDataStore[0].Adresse;
PLZ = theDataStore[0].PLZ;
Ort = theDataStore[0].Ort;
Staat = theDataStore[0].Staat;
email = theDataStore[0].email;
Listing 6.29: Einlesen der Informationen der XML-Datei (Auszug)
Eines ist am vorigen Beispiel zu beachten: Weil das Beispiel bereits so weit
vorbereitet wurde,um mehr als nur einen Datensatz einzulesen,wurde nicht wie in
K A P I T E L 6282
den vorigen Beispielen direkt auf das Tag <Kunde>, sondern auf das Tag <Kunden>
zugegriffen (<Kunden> ist das übergeordnete Tag zu <Kunde>).
Daher heißt es:
var theData:Array = myLoader.firstChild.firstChild.childNodes;
anstatt:
var theData:Array = myLoader.firstChild.firstChild.firstChild.childNodes;
Das gesamte Beispiel finden Sie wie gewohnt auf der Buch-CD als Datei mit dem
Namen XMLLoad02b.fla.
XML-Daten mit Attributen
Wir möchten nun eine weitere Möglichkeit darstellen, wie ein XML-Baum aufgebaut
werden kann. Letzten Endes ist die Möglichkeit der Wertübergabe nicht auf Textkno-
ten beschränkt, sondern kann ebenso über Attribute erfolgen. Die Anwendung gleicht
der der bekannten Attribute aus XHTML, wobei wir in XML bei der Wahl der Attri-
butnamen frei sind. Betrachtet man beispielsweise das Listing in Listing 6.29, so sieht
man dort, dass anstelle der Textknoten <Vorname>, <Nachname> etc. die Attribute
Vorname, Nachname usw. verwendet werden.
ABBILDUNG 6.23
Anstatt der Textknoten
wurden dieses Mal Attribute
eingesetzt. Die Auswertung
in Flash muss entsprechend
geändert werden.
Um Attribute auswerten zu können, steht aus Flash das Objekt attributes zur Ver-
wendung bereit. Auf die Werte des Objekts kann man über den Namen der verwen-
deten Variable („Spaltenname“) zugreifen. In unserem Fall wären folgende Anwen-
dungen gleichbedeutend und führen zum selben Ergebnis:
attributes["Vorname"]; //liefert "Uwe"
attributes.Vorname; //liefert "Uwe"
Für welche Variante Sie sich entscheiden, liegt bei Ihnen. Sollte etwa nicht bekannt
sein, wie viele Attribute verwendet werden, empfiehlt sich eine Schleife über alle Attri-
bute (attributes.length).
Vergleicht man das dazu notwendige Skript mit unserem Beispiel aus Listing 6.27, so
muss dieses Listing durch das nachfolgende Skript ersetzt werden:
SERVERSEITIGER DATENAUSTAUSCH – FLASH, PHP & DATENBANK 283
theDataStore[i].Vorname = theData[i].attributes.Vorname;
theDataStore[i].Nachname = theData[i].attributes.Nachname;
theDataStore[i].Firma = theData[i].attributes.Firma;
theDataStore[i].Adresse = theData[i].attributes.Adresse;
theDataStore[i].PLZ = theData[i].attributes.PLZ;
theDataStore[i].Ort = theData[i].attributes.Ort;
theDataStore[i].Staat = theData[i].attributes.Staat;
theDataStore[i].email = theData[i].attributes.email;
Listing 6.30: Anstatt wie im letzten Beispiel auf einen Textknoten zuzugreifen, wird nun auf die Attribute
eines Knotens zugegriffen.
Die Ausgabe der eingelesenen Daten ist dieselbe – hier sind keine Änderungen notwen-
dig. Fassen wir also kurz zusammen, was wir soeben getan haben:
1. Anstatt mit Textknoten zu arbeiten, setzen wir Attribute ein.
2. Die „Werte“ der Textknoten werden zu Werten von Attributen, veranschaulicht
dargestellt:
<Textknoten>Wert</Textknoten>
wird zu:
<Knoten Textknoten_Wert="Wert" />
3. Die Werte der Attribute kann man in Flash mithilfe des assoziativen Arrays
attributes auslesen.
Ihnen als Webentwickler steht es frei, welche Art der Wertedarstellung (Textknoten
oder Attribute) Sie verwenden. Natürlich können Sie die Darstellung auch mischen.
Eine Generalaussage, wann welche Variante zum Einsatz gelangen sollte, kann und soll
an dieser Stelle nicht getroffen werden, weil es von Fall zu Fall unterschiedlich ist.
Einlesen einer XML-konformen PHP-Datei
Wenden wir uns einer ähnlichen Thematik zu, nämlich dem Einlesen einer PHP-Datei,
die Daten XML-konform darstellt. Wie zu erwarten, läuft dies exakt gleich ab wie das
Einlesen einer Textdatei. Der einzige Unterschied für Flash besteht darin, dass man
anstatt einer Datei mit der Endung „.txt“ eine Datei mit der Endung „.php“ einliest.
Der Aufwand hinsichtlich der Erstellung der einzulesenden Datei gestaltet sich natür-
lich etwas anders, da der XML-Baum durch PHP generiert werden muss. Die Vorge-
hensweise hierbei entspricht der Vorgehensweise bei der Generierung eines „Textin-
halts“. Da dies bereits am Anfang dieses Kapitels sehr ausführlich beschrieben wurde,
beschränken wir uns hier auf die Zusammenfassung der wesentlichen Schritte.
K A P I T E L 6284
Das Generieren einer XML-Datei durch PHP ist im Wesentlichen nichts anderes als
das Generieren irgendeines Inhalts eines Webdokuments. Entscheidend ist nur, was
der Client zu sehen bekommt, und das ist in diesem Fall ein XML-konform aufge-
bautes Dokument.
1. Definieren, welche Datenbank verwendet wird
myysql_select_db();
2. Auswahl der Datenbank prüfen
Sollte die Methode mysql_select_db() den Wert false zurückgeben, war die
Auswahl der Datenbank nicht erfolgreich. Der Rückgabewert true signalisiert,
dass die Auswahl der Datenbank in Ordnung war.
3. Absetzen eines SQL-Statements
$sql = "SELECT * FROM tbl_Kunden";
if(!$query = mysql_query($sql)) {
die('<div class="error">Das SQL-Statement konnte nicht
durchgef&uuml;hrt werden. Errorcode: ‚.mysql_error().'</div>');
}
else {
//echo('<div class="success">Das SQL-Statement:<br/>'.$sql.'<br/
>wurde erfolgreich abgesetzt.</div>');
}
4. Ausgeben der Daten in die PHP-Seite
Diesem Teil müssen wir doch etwas mehr Aufmerksamkeit zuteil werden lassen,
denn anders als bei einer einzulesenden Textdatei muss dieses Dokument XML-
konform aufbereitet werden. Zunächst wird das Dokument als XML-Dokument
gekennzeichnet:
<?php echo(‚<?xml version="1.0" encoding="ISO-8859-1" standalone="yes"
?>'); ?>
Im nächsten Schritt fügt man die Struktur der XML-Datei in Form von Tags ein:
<XML-Kundenliste>
<Kunden>
Zuletzt werden die in der Datenbank gespeicherten Daten mithilfe einer Schleife
ausgegeben:
<?php
while($theData = mysql_fetch_array($query)) {
echo("<Kunde>");
SERVERSEITIGER DATENAUSTAUSCH – FLASH, PHP & DATENBANK 285
echo("<Vorname>".$theData["vc_Vorname"]."</Vorname>");
echo("<Nachname>".$theData["vcP_Nachname"]."</Nachname>");
echo("<Firma>".$theData["vc_Firma"]."</Firma>");
echo("<Adresse>".$theData["vc_Adresse"]."</Adresse>");
echo("<PLZ>".$theData["vc_PLZ"]."</PLZ>");
echo("<Ort>".$theData["vc_Ort"]."</Ort>");
echo("<Staat>".$theData["vc_Staat"]."</Staat>");
echo("<email>".$theData["vc_email"]."</email>");
echo("</Kunde>");
}
?>
Danach schließt man die geöffneten Tags:
</Kunden>
</XML-Kundenliste>
Listing 6.31: Auszug aus dem Listing der Datei EinlesedatenXML02.php
Die clientseitige Sicht
Man muss sich immer vor Augen führen, dass Flash eine clientseitige Anwendung ist und dem-
nach auch nur Informationen einlesen kann, die clientseitig (in irgendeiner Form) dargestellt
werden können. In unserem Fall produziert der Server auf Anfrage durch PHP-Programmierung
dieses XML-konforme Dokument, das – und das ist der springende Punkt – aus Sicht des Clients
aus purem XML-Inhalt besteht.
5. Flash-Datei anpassen
Die Änderungen in Flash hinsichtlich des Einlesens der Datei sind gegenüber dem
vorangegangenen Beispiel minimal. Es muss lediglich die Zeile:
var mySource:String = "EinlesedatenXML01_UTF-8.txt";
mit der einzulesenden Datei in EinlesedatenXML02.php geändert werden:
var mySource:String = "EinlesedatenXML02.php";
Damit wäre dieses Beispiel aus Flash- und PHP-Sicht abgeschlossen.
6. Attribute statt Textknoten
K A P I T E L 6286
Für den Fall, dass wir anstatt der Textknoten in PHP Attribute zur Darstellung der
Werte verwenden (vgl. Listing 6.31), muss die PHP-Datei innerhalb der while-
Schleife in nachfolgendes Skript geändert werden:
while($theData = mysql_fetch_array($query)) {
echo("<Kunde");
echo(" Vorname='".$theData["vc_Vorname"]."'");
echo(" Nachname='".$theData["vcP_Nachname"]."'");
echo(" Firma='".$theData["vc_Firma"]."'");
echo(" Adresse='".$theData["vc_Adresse"]."'");
echo(" PLZ='".$theData["vc_PLZ"]."'");
echo(" Ort='".$theData["vc_Ort"]."'");
echo(" Staat='".$theData["vc_Staat"]."'");
echo(" email='".$theData["vc_email"]."'");
echo(" />");
}
Listing 6.32: Anstatt der Textknoten werden auch beim Erzeugen der XML-Daten nun Attribute eingesetzt
(Auszug aus dem Listing der Datei EinlesedatenXML03.php).
6.3.3 Ausgeben von XML-Daten in eine PHP-Seite
Ebenso wie man Daten aus einer XML-Datei einlesen kann, besteht auch die Möglich-
keit, XML-Daten an ein serverseitiges Dokument (in unserem Fall eine PHP-Datei)
zu übergeben, das die Daten weiterverarbeitet und beispielsweise in eine Datenbank
schreibt.
Man sollte an dieser Stelle nicht unerwähnt lassen, dass das Ausgeben von Informati-
onen per XML aus Flash heraus bei weitem nicht so oft eingesetzt wird wie das Einle-
sen von XML-Daten. Der Grund ist sicherlich auch der, dass auf Serverseite die Daten
über ein geeignetes Skript erst noch geparst und aufbereitet werden müssen, wodurch
ein (oft nicht unerheblicher) Mehraufwand bei der Entwicklung entsteht. Stattdessen
ABBILDUNG 6.24
Anstelle der Textknoten im
vorigen Beispiel werden nun
Attribute innerhalb der Tags
zum Einsatz kommen.
SERVERSEITIGER DATENAUSTAUSCH – FLASH, PHP & DATENBANK 287
könnte auch das LoadVars-Objekt zum Einsatz kommen. Nichtsdestotrotz stellt das
Ausgeben von XML-Daten eine sehr elegante und auch zukunftsweisende Variante
dar.
Vorgehensweise beim Ausgeben von XML-Daten
Im Wesentlichen erfolgt das Senden und Verarbeiten der Daten in drei Schritten:
1. Erzeugen eines XML-Baums inklusive Header-Informationen in Flash
Zunächst wird in Flash ein XML-Baum mit den zu sendenden Daten erstellt.
Hierzu stehen uns in Flash alle notwendigen Hilfsmittel zur Verfügung – auf diese
werden wir im Folgenden noch genauer eingehen.
2. Versenden der XML-Daten an eine PHP-Seite
Flash ist nicht in der Lage, direkt Daten an eine Datenbank zu senden, da Flash
– wie Sie natürlich wissen – eine clientseitige Anwendung ist.
3. Parsen der übergebenen XML-Daten in PHP
Die aus Flash übergebenen Daten werden nun in der PHP-Datei geparst und
beispielsweise in eine Datenbank geschrieben.
Der XML-Header
Grundsätzlich kann jeder XML-Baum nach eigenen Regeln aufgebaut werden. Soll der Baum
jedoch zur weiteren Verwendung an beispielsweise eine PHP-Datei übertragen werden, ist
ein korrekter Header unabdingbar. Ein typischer XML-Header ist <?xml version='1.0'
encoding='UTF-8'?>.
Erzeugen eines XML-Baums in Flash
Mal andersrum – im vorigen Abschnitt haben wir uns damit beschäftigt, einen XML-
Baum in PHP zu erzeugen, um diesen dann in Flash einzulesen. In PHP haben wir
auf XML-spezifische Befehle zum Erzeugen eines XML-Baums „verzichtet“, da einfach
keine Befehle in PHP hierzu existieren, sieht man einmal von der Verwendung zusätz-
licher Bibliotheken ab.
In Flash stellt sich die Sache etwas differenzierter dar, da Flash uns sehr wohl einige
Möglichkeiten bietet. In der nachfolgenden Tabelle finden Sie diese aufgelistet und mit
einer kurzen Erklärung versehen. Danach schreiten wir zur Tat und erzeugen anhand
eines konkreten Beispiels einen XML-Baum.
K A P I T E L 6288
Methode Verwendung
new XML() Konstruktor zum Erstellen eines neuen XML-Objekts.
Wie auch beim Einlesen von XML-Daten muss zunächst
ein solches XML-Objekt angelegt werden.
createElement(Elementname) Erzeugt ein neues XML-Element (einen Knoten) mit
dem angegebenen Namen (Elementname).Sämtliche
Child- oder Parent-Knoten sowie Attribute müssen
nachträglich erzeugt werden,da diese von vorneherein
nicht existieren.Mithilfe von appendChild kann das
Element danach an einen bestehenden XML-Baum
angehängt werden.
createTextNode(Text) Erzeugt ähnlich der Methode createElement einen
XML-Knoten,jedoch handelt es sich in diesem Fall um
einen Textknoten.Der Inhalt dieses Textknotens ist der
Wert aus Text.Wie auch bei createElement muss
dieses Element nach dem Anlegen per appendChild
an einen bestehenden XML-Baum angehängt werden.
appendChild(Childknoten) Fügt den angegebenen Child-Knoten (der zuvor per
createElement oder createTextNode erzeugt wur-
de) am Ende eines bestehenden XML-Baums an.
insertBefore(Childknoten, Vor-Knoten) Fügt den angegebenen Child-Knoten vor dem Vor-
Knoten ein.Wird kein Vor-Knoten angegeben,so wird
die Methode appendChild verwendet und der Knoten
somit am Ende des XML-Baums angehängt.
firstChild Diese Eigenschaft ist bereits aus dem vorigen Kapitel
bekannt.Mit ihrer Hilfe kann man von einem Parent- in
einen Child-Knoten wechseln.
attributes Mithilfe dieses Objekts können für bestehende Knoten
Attribute erzeugt werden.
xmlDecl Legt die grundlegenden Informationen zum XML-
Dokument fest:Versionsnummer von XML,Kodiertyp
etc.
contentType Legt den MIME-Type fest,der an den Server (bei send
oder sendAndLoad) übermittelt wird.Wird typischer-
weise auf„text/html“ gesetzt.
Tabelle 6.2: XML-Befehle in Flash zum Erzeugen eines XML-Baums
Unser Ziel ist es nun, die Theorie in die Praxis umzusetzen, und zwar anhand des von
uns in den vorigen Kapiteln verwendeten Beispiels der Kundendatendarstellung. Wie
schon weiter oben im Kapitel angedeutet, müssen wir zunächst einen neuen XML-
Baum „erschaffen“, was mit dem Konstruktor new XML() möglich wird:
1. Erzeugen eines neuen XML-Baums inklusive Header
Damit das XML-Dokument auch seine Gültigkeit hat, benötigt es einen Header,
der gleich mit der Deklaration des XML-Objekts angegeben werden kann:
var myXML:XML = new XML("<?xml version='1.0' encoding='UTF-8'?>");
Alternative: Deklaration als XML-Daten
Alternativ dazu (und für PHP besser verständlich) kann man auch wie folgt
vorgehen:
SERVERSEITIGER DATENAUSTAUSCH – FLASH, PHP & DATENBANK 289
var myXML:XML = new XML();
myXML.ignoreWhite = true;
myXML.contentType = ‚text/html';
myXML.xmlDecl = "<?xml version='1.0' encoding='UTF-8' ?>";
Wie Sie sehen, wird im alternativen Skript im Prinzip dasselbe XML-Objekt
erzeugt, mit dem Unterschied, dass die Definition (Deklaration) des XML über die
Eigenschaft xmlDecl erfolgt.
Des Weiteren wird für das XML-Objekt der contentType definiert sowie die
schon bekannte Eigenschaft ignoreWhite=true gesetzt. Dies ist im Allgemeinen
nur dann notwendig, wenn Sie damit rechnen müssen, dass leere Textknoten
auftreten.
Wir würden an dieser Stelle empfehlen, die zweite Methode zu verwenden,
da PHP beim Einlesen der XML-Daten aus Flash mit dieser Variante besser
zurechtkommt.
2. Erzeugen des Hauptknotens
Danach wollen wir denselben XML-Baum wie in Abbildung 6.19 dargestellt
aufbauen.Diesbedeutetalso,dasszunächstderHauptknoten<XML-Kundenliste>
anzulegen ist. Hierzu wird zunächst mithilfe der Methode createElement ein
neues (unabhängiges) Knoten-Element erzeugt und danach mittels appendChild
an das Ende unseres (derzeit ohnehin noch leeren) XML-Baums angehängt.
Wie der Knoten benannt wird, steht Ihnen vollkommen frei – wir haben uns für
rootNode entschieden:
var rootNode:XMLNode = myXML.createElement("XML-Kundenliste");
myXML.appendChild(rootNode);
WürdedasElementrootNode nichtperappendCild andenXML-Baumangefügt,
so wäre die ganze Arbeit umsonst gewesen.
ABBILDUNG 6.25
Das root-Element ist bereits
erzeugt.
3. Erzeugen eines Knotens innerhalb eines bereits bestehenden Knotens
Um den nächsten Knoten <Kunden> innerhalb des Elements <XML-Kundenliste>
anzulegen, müssen wir – nachdem wir wieder per createElement ein
unabhängiges Element erzeugt haben – in das Element <XML-Kundenliste>
selbst hineinspringen, also auf das erste Child des XML-Baums verweisen. Dies
gelingt durch den Einsatz der Eigenschaft firstChild:
K A P I T E L 6290
var subNode1:XMLNode = myXML.createElement("Kunden");
myXML.firstChild.appendChild(subNode1);
Somit haben wir also erreicht, dass innerhalb des Elements <XML-Kundenliste>
ein Element namens <Kunden> angelegt wurde.
4. Erzeugen eines Child-Knotens im Knoten <Kunden>
Gleiches wie im Arbeitsschritt zum Erzeugen des Knotens <Kunden> ist auch für
den Knoten <Kunde> (Child von <Kunden>) vorzunehmen.
var subNode2:XMLNode = myXML.createElement("Kunde");
myXML.firstChild.firstChild.appendChild(subNode2);
Wie Sie sehen, wird nun zweimal per firstChild vom XML-Objekt myXML
ausgehend verwiesen. Dies hat den einfachen Grund, dass <Kunde> ein Child von
<Kunden> und dieses wiederum ein Child von <XML-Kundenliste> ist – somit
ist <Kunde> quasi das „Enkelkind“ von <XML-Kundenliste>.
ABBILDUNG 6.26
In den Hauptknoten <XML-
Kundenliste> wurde
ein Child-Knoten namens
<Kunden> eingefügt.
5. Erzeugen von Child-Knoten und Zuweisen von Werten im Knoten <Kunde>
Nun ist es an der Zeit, die Knoten für Nachname, Vorname, Firma usw. anzulegen
und diese mit Werten (dies sind in unserem Fall Textknoten) zu füllen. Da die
Vorgehensweise für alle Knoten gleich ist, demonstrieren wir dies anhand eines
Knotens.
Im Folgenden werden wir dann Überlegungen anstellen, wie wir uns die Arbeit für
diese Knoten doch erheblich vereinfachen können. Doch zunächst zum Anlegen
der Knoten.
var subNode3:XMLNode = myXML.createElement("Vorname");
myXML.firstChild.firstChild.firstChild.appendChild(subNode3);
var subNode3a:XMLNode = myXML.createTextNode(Vorname);
myXML.firstChild.firstChild.firstChild.childNodes[0].appendChild(subNode3a);
Zunächst wird – wie schon hinlänglich bekannt – ein neues unabhängiges Element
per createElement erzeugt.In unserem Fall ist das der Knoten <Vorname>.Dieser
Knoten wird der „Urenkel“ von <XML-Kundenliste>, deshalb muss dreimal die
Eigenschaft firstChild angewendet werden.
ABBILDUNG 6.27
Der Knoten <Kunden>
hat ein Kind bekommen
– <Kunde>.
SERVERSEITIGER DATENAUSTAUSCH – FLASH, PHP & DATENBANK 291
Ist dies geschehen, wird zunächst ein neuer, wieder unabhängiger Textknoten
erzeugt und dieser dann innerhalb des soeben neu erzeugten Knotens <Vorname>
(dies ist ja der nullte Child-Knoten von <Kunde>) per appendChild eingefügt.
Der Wert des Textknotens wird aus der Variable Vorname ermittelt, die zuvor von
uns angelegt und mit dem Wert [ Vorname ] versehen wurde. Das Ergebnis sehen
Sie in Abbildung 6.28.
6. Weitere Knoten
Jetzt könnte man für alle weiteren Knoten (<Nachname>, <Firma> etc.) genau
gleich verfahren. Dies bedingt jedoch eine relativ „unelegante“ Programmierung,
was wir als erfahrene Programmierer ja eigentlich gar nicht so gerne sehen ... Wie
das aussehen würde, sehen Sie im nachfolgenden Listing.
//Erzeugen eines neuen XML-Baums: ---------------------
var myXML:XML = new XML();
myXML.ignoreWhite = true;
myXML.contentType = "text/html";
myXML.xmlDecl = "<?xml version='1.0' encoding='UTF-8' ?>";
var rootNode:XMLNode = myXML.createElement("XML-Kundenliste");
myXML.appendChild(rootNode);
// -----------------------------------------------------
//Erzeugen des ersten Unterknotens: --------------------
var subNode1:XMLNode = myXML.createElement("Kunden");
myXML.firstChild.appendChild(subNode1);
// -----------------------------------------------------
//Erzeugen des ersten Unter-Unterknotens: --------------
var subNode2:XMLNode = myXML.createElement("Kunde");
myXML.firstChild.firstChild.appendChild(subNode2);
// -----------------------------------------------------
var subNode3:XMLNode = myXML.createElement("Vorname");
ABBILDUNG 6.25
Der Knoten <Vorname>
wurde eingefügt und ihm
wurde ein Wert mithilfe
eines Textknotens zuge-
wiesen.
K A P I T E L 6292
myXML.firstChild.firstChild.firstChild.appendChild(subNode3);
var subNode3a:XMLNode = myXML.createTextNode(Vorname);
myXML.firstChild.firstChild.firstChild.childNodes[0].appendChild(subNode3a);
subNode3 = myXML.createElement("Nachname");
myXML.firstChild.firstChild.firstChild.appendChild(subNode3);
subNode3a = myXML.createTextNode(Nachname);
myXML.firstChild.firstChild.firstChild.childNodes[1].appendChild(subNode3a);
subNode3 = myXML.createElement("Firma");
subNode3a = myXML.createTextNode(Firma);
myXML.firstChild.firstChild.firstChild.childNodes[2].appendChild(subNode3a);
myXML.firstChild.firstChild.firstChild.appendChild(subNode3);
subNode3 = myXML.createElement("Adresse");
myXML.firstChild.firstChild.firstChild.appendChild(subNode3);
subNode3a = myXML.createTextNode(Adresse);
myXML.firstChild.firstChild.firstChild.childNodes[3].appendChild(subNode3a);
subNode3 = myXML.createElement("PLZ");
myXML.firstChild.firstChild.firstChild.appendChild(subNode3);
subNode3a = myXML.createTextNode(PLZ);
myXML.firstChild.firstChild.firstChild.childNodes[4].appendChild(subNode3a);
subNode3 = myXML.createElement("Ort");
myXML.firstChild.firstChild.firstChild.appendChild(subNode3);
subNode3a = myXML.createTextNode(Ort);
myXML.firstChild.firstChild.firstChild.childNodes[5].appendChild(subNode3a);
subNode3 = myXML.createElement("Staat");
myXML.firstChild.firstChild.firstChild.appendChild(subNode3);
subNode3a = myXML.createTextNode(Staat);
myXML.firstChild.firstChild.firstChild.childNodes[6].appendChild(subNode3a);
SERVERSEITIGER DATENAUSTAUSCH – FLASH, PHP & DATENBANK 293
subNode3 = myXML.createElement("email");
myXML.firstChild.firstChild.firstChild.appendChild(subNode3);
subNode3a = myXML.createTextNode(email);
myXML.firstChild.firstChild.firstChild.childNodes[7].appendChild(subNode3a);
Listing 6.33: Ein etwas mühseliges Skript zum Erzeugen des XML-Baums – das muss doch auch einfacher
gehen ...
Alternative: Schleife statt stures Programmieren
Aus diesem Grund haben wir uns dafür entschieden,den eleganteren Weg zu gehen
und diese Knoten über eine Schleife zu erzeugen. Um dies zu bewerkstelligen,
gehen wir folgendermaßen vor:
Zunächst erzeugen wir ein Array, in dem die Namen aller einzulesenden Tags
gespeichert sind.
var theNodes:Array = new Array("Vorname", "Nachname", "Firma",
"Adresse", "PLZ", "Ort", "Staat", "email");
Danach gehen wir in einer Schleife alle Einträge dieses Arrays durch und schreiben
die entsprechenden Daten in den XML-Baum:
var subNode3:XMLNode, subNode3a:XMLNode;
for(var i:Number=0; i<theNodes.length; i++) {
subNode3 = myXML.createElement(theNodes[i]);
myXML.firstChild.firstChild.firstChild.appendChild(subNode3);
subNode3a = myXML.createTextNode(eval(theNodes[i]));
myXML.firstChild.firstChild.firstChild.childNodes[i].
appendChild(subNode3a);
}
Listing 6.34: Auszug aus dem Skript zum Erzeugen des XML-Baums (alternative Arbeitsweise zu Listing
6.33). Das Beispiel finden Sie auf der Buch-CD unter dem Namen XMLSend01a.fla.
Die Methode eval()
Wichtig in diesem Skriptblock beim Erzeugen des subNode3a ist die Methode eval(). Mit ihr
wird es möglich, einen String als Variablennamen anzusehen und somit den Inhalt der Variablen
auszulesen. Mit anderen Worten kann man sagen, dass ein String als Variable interpretiert wird.
K A P I T E L 6294
7. Versenden der XML-Daten
In beiden Fällen – ob nun mühselig oder leicht – fehlt noch der entscheidende
Schritt des Versendens der XML-Daten.
Dieser Schritt ist wohl derjenige, der am einfachsten fällt. Die dafür vorgesehene
Methode heißt send() und erwartet von uns minimal einen Parameter – die URL,
an die die Daten verschickt werden sollen – und maximal zwei Parameter – als
zweiten Parameter den Fensternamen aus HTML, in dem die URL dargestellt
werden soll.
Möchte man, dass das „Empfängerdokument“ nur am Server verarbeitet, jedoch
nicht für den User sichtbar dargestellt wird, muss man nur auf den zweiten
Parameter verzichten:
myXML.send("parserXML01.php");
In diesem Fall werden demnach alle Informationen dem Dokument parserXML01.
php übermittelt.
Daten mit PHP auswerten
Mit dem Zeitpunkt des Versendens der Daten aus der Flash-Datei heraus ist sämtliche
Arbeit für den Flash-Entwickler erledigt. Bleibt noch zu klären, wie die Daten per PHP
ausgewertet werden können.
Bevor wir nun das XML-Objekt aus Flash weiterverarbeiten können, müssen wir uns
kurz Gedanken darüber machen, in welchem Format diese Daten von Flash an PHP
übergeben werden.
Normalerweise übergibt Flash Daten vom Typ application/x-www-form-url-
encoded. Wäre dies der Fall, würde PHP die Daten parsen und von der Variable
$HTTP_RAW_POST_DATA in ein assoziatives Array namens $_POST verschieben.
DaaberderFlash-ProgrammiererdurchdieAngabevonmyXML.contentType='text/
html' den Datentyp in text/html geändert hat, bleiben die Daten in der Variable
$HTTP_RAW_POST_DATA. Sie wissen nun also, dass wir die Daten von Flash über die
Variable $HTTP_RAW_POST_DATA ansprechen können. Nun geht es daran, diese Daten
auszulesen und anschließend in die Datenbank zu speichern.
Kein Zugriff auf $HTTP_RAW_POST_DATA?
Sollten Sie auf $HTTP_RAW_POST_DATA nicht zugreifen können, kontrollieren Sie in der php.ini,
ob die Einstellung always_populate_raw_post_data auf on gesetzt ist.
ABBILDUNG 6.29
Hier nun das fertige XML-
Dokument, das für das
Versenden an eine PHP-Datei
bereitsteht
SERVERSEITIGER DATENAUSTAUSCH – FLASH, PHP & DATENBANK 295
Für das Auslesen haben wir mehrere Möglichkeiten. Wir könnten über das DOM
die Informationen bekommen oder auch aber über die neuen Funktionen von Sim-
pleXML. (Zur Erinnerung: SimpleXML ist eine Funktionsbibliothek von PHP.) Nähe-
res dazu haben Sie schon im Grundlagenteil der Programmierung erfahren. Ich schlage
Ihnen vor, SimpleXML zu benutzen, da es – so finde ich – um einiges einfacher ist.
Gehen wir es an: Daten auslesen und in eine Datenbank speichern.
1. Daten aus Flash in einer Variable speichern
$XMLData = $HTTP_RAW_POST_DATA;
Um die XML-Daten anzusehen, können wir ganz einfach die Variable $XMLData
über den echo-Befehl anzeigen lassen. Somit können wir uns auch die XML-
Struktur anschauen.
2. SimpleXML-Objekt anlegen
SimpleXML bietet uns die Möglichkeit, über simplexml_load_string() ein
XML-Objekt zu erstellen. Dieses Objekt werden wir $objKunde zuweisen.
$objKunde = simplexml_load_string($XMLData);
3. Auf die Daten in $objKunde zugreifen
Wir wissen, dass wir folgende Daten bekommen:
Vorname
Nachname
Firma
Adresse
Staat
PLZ
Ort
E-Mail
Zusätzlich wissen wir, dass wir immer nur die Daten eines Kunden bekommen.
Somit greifen wir auf die XML-Daten des jeweiligen Knotens an der Stelle 0 zu.
Stellen Sie sich eine XML-Struktur am besten wie eine Ordnerstruktur im
Windows-Explorer vor. Somit wäre der erste Ordner der Ordner „Kunden“. In
diesem Ordner gibt es einen weiteren namens „Kunde“. Im Kunde-Ordner gibt es
dann acht zusätzliche Ordner auf der gleichen Ebene, nämlich einen für Vorname,
Nachname, Firma, Adresse, Staat, PLZ, Ort und E-Mail. Nun müssen wir nur
noch dieser Struktur folgend von außen nach innen in PHP wandern, um an die
richtigen Daten zu kommen. Aber bestimmt sind Sie mit der XML-Struktur schon
so weit vertraut, dass dieses Thema für Sie keine Hürde mehr darstellt.
K A P I T E L 6296
Beginnen wir mit dem Vornamen des Kunden: Wir wissen, im Objekt $objKunde
sind unsere XML-Daten gespeichert. Zusätzlich kennen wir die Struktur von
„Kunden“ über „Kunde“ zu „Vorname“:
$vorname = $objKunde->Kunden[0]->Kunde[0]->Vorname;
Den Vornamen des Kunden speichern wir nun nur noch in eine Variable namens
$vorname. Jetzt ist sicher auch klar, wie wir an die anderen Daten „Kunden“
herankommen:
$nachname = $objKunde->Kunden[0]->Kunde[0]->Nachname;
$firma = $objKunde->Kunden[0]->Kunde[0]->Firma;
$adresse = $objKunde->Kunden[0]->Kunde[0]->Adresse;
$staat = $objKunde->Kunden[0]->Kunde[0]->Staat;
$plz = $objKunde->Kunden[0]->Kunde[0]->PLZ;
$ort = $objKunde->Kunden[0]->Kunde[0]->Ort;
$email = $objKunde->Kunden[0]->Kunde[0]->email;
Das war’s auch schon – ging doch sehr einfach. Ein Lob an SimpleXML. Als
Nächstes müssen wir noch die gewonnenen Daten in unsere Datenbank sichern.
4. Verbindung zur Datenbank
Wie gewohnt nehmen wir Kontakt zum Datenbankserver auf und verbinden uns
mit einer dort befindlichen Datenbank:
$hostname = "IHR HOSTNAME";
$username = "IHR USERNAME";
$password = "IHR PASSWORT";
if(!$conn = mysql_connect($hostname, $username, $password)) {
die('<div class="error">Verbindung zur Datenbank konnte nicht
hergestellt werden. Errorcode: '.mysql_error().'</div>');
}
Wir speichern den Rückgabewert in der Variable $conn. Danach überprüfen wir,
ob $conn false ist. Ist das der Fall, wird mit der Funktion die() das Ausführen
des Skripts abgebrochen und der Text „Verbindung zur Datenbank konnte nicht
hergestellt werden.“ sowie der entsprechende Fehlercode ausgegeben.
5. Datenbank auswählen
Wenn das Verbinden erfolgreich war, müssen wir noch unsere gewünschte
Datenbank am Server auswählen. Dazu nutzen wir die Funktion mysql_select_
db(). Diese erwartet den Datenbanknamen und die Verbindungskennung, die wir
zuvor realisiert haben.
SERVERSEITIGER DATENAUSTAUSCH – FLASH, PHP & DATENBANK 297
$db = "IHRE DATENBANK";
if(!mysql_select_db($db)) {
die('<div class="error">Die Datenbank '.$db.' konnte nicht
ausgewaehlt werden. Errorcode: '.mysql_error().'</div>');
}
Da wir nun die Verbindung zu unserer gewünschten Datenbank hergestellt haben,
können wir die XML-Daten in diese speichern.
6. Speichern der XML-Daten in die Datenbank
Dazu müssen natürlich in der Datenbank eine Tabelle und die notwendigen Felder
angelegt sein. Wir haben bereits im Vorfeld eine Tabelle namens „tbl_kunden“ mit
den Feldern „idP_Kunde“, „vc_Vorname“, „vcP_Nachname“, „vc_Adresse“, „vc_
Staat“, „vc_PLZ“, „vc_Ort“ und „vc_email“ angelegt. Diesen Schritt müssten Sie
also an dieser Stelle noch dazwischenschieben.
Über INSERT INTO tabellenname (tabellenfelder) VALUES (‚werte')
können wir die Daten in unsere Datenbank speichern.Wir speichern dies als String
in die Variable $sql ab.
$sql = "
INSERT INTO tbl_kunden
(vc_Vorname,vcP_Nachname,vc_Firma,vc_Adresse,vc_Staat,vc_PLZ,vc_
Ort,vc_email)
VALUES
(‚$vorname','$nachname','$firma','$adresse','$staat','$plz','$ort','
$email')
";
7. Anfrage an die Datenbank senden
Jetzt müssen wir noch die Anfrage an die Datenbank senden. Dazu nutzen
wir mysql_query(). Dieser Funktion müssen wir unseren Anfragestring als
Parameter angeben. Ist das Speichern der Daten erfolgreich, so liefert auch diese
Funktion true zurück. Wenn nicht, brechen wir das Ausführen des Skripts wieder
mit die() ab.
$rs = mysql_query($sql) or die ("Die Daten konnten nicht gespeichert
werden.");
Das war’s auch schon. Jetzt sind unsere Daten des Kunden in der Datenbank
gespeichert. Sämtliche Daten dieses Beispiels finden Sie selbstverständlich auf der
Website zum Buch sowie auf der Buch-CD.
K A P I T E L 6298
6.3.4 Die XMLConnector-Komponente
Flash hat im Zusammenhang mit XML noch mehr zu bieten als das sture Parsen von
XML-Daten. Seit der Version Flash MX 2004 stellt uns Adobe die XMLConnector-
Komponente zur Seite, um auf einfache Art und Weise mit XML-Daten arbeiten zu
können.
Komponenten gehören zur Symbolgruppe der MovieClips und stellen die Möglichkeit
dar, während der Entwicklung parametergestützt Eigenschaften und Methoden zu
erhalten. Mithilfe von ActionScript ist es uns jedoch auch möglich, diese Parameter zur
Laufzeit zu ändern (das ist Ihnen sicherlich noch in Zusammenhang mit der TextArea-
Komponente im Gedächtnis).
Die XMLConnector-Komponente gehört zur Gruppe der Data-Komponenten:
ABBILDUNG 6.30
Sämtliche Daten wurden
von Flash an die PHP-Datei
parserXML01.php übergeben.
Diese Datei sorgt dafür, dass
die Daten in die Datenbank
gespeichert werden.
ABBILDUNG 6.31
Die Gruppe der Data-
Komponenten beinhaltet
die von uns benötigte
XMLConnector-Komponente.
SERVERSEITIGER DATENAUSTAUSCH – FLASH, PHP & DATENBANK 299
Grundsätzlich bietet uns diese XMLConnector-Komponente Zugriff auf eine beliebige
externe Datenquelle, die XML-basierte Daten mittels HTTP bereitstellen (oder auch
empfangen) können. Mithilfe eines sogenannten „Schemas“ wird die XML-Quelle
dann ausgelesen – auf das Thema der Schemata kommen wir etwas später noch einmal
zurück.
Wie im Umgang mit Komponenten üblich, wird eine Komponente in der Flash-Ent-
wicklungsumgebung auf die Bühne gezogen. Dies ist im Allgemeinen nicht unbedingt
erforderlich, denn wir können auch zur Laufzeit mithilfe von ActionScript Kompo-
nenten erstellen, jedoch gehen wir diesen Weg, um uns das Vorgehen zunächst so
einfach wie möglich zu gestalten. An welcher Stelle Sie die Komponente auf der Bühne
platzieren, ist vollkommen irrelevant, da diese selbstverständlich nicht sichtbar ist:
Als Tipp gilt: Legen Sie die Komponente außerhalb des (sichtbaren) Bühnenbereichs
ab, damit Sie diese während der Arbeit nicht irritiert.
Wie läuft nun die Arbeit mit einem XMLConnector ab? Die nachfolgende Auflistung
sorgt für Klarheit:
1. Es wird eine Instanz der XMLConnector-Komponente auf (oder außerhalb) der
Bühne platziert.
2. Der Instanz wird ein Instanzname zugewiesen.
ABBILDUNG 6.32
An welcher Stelle Sie die
XMLConnector-Komponente
einfügen, bleibt gänzlich
Ihnen überlassen, da diese
(siehe swf-Datei) selbstver-
ständlich nicht sichtbar ist.
K A P I T E L 6300
3. Die Instanzparameter werden angegeben:
URL: Adresse, von wo die Instanz die XML-Datei bezieht.
direction: je nachdem, ob gesendet und geladen (send/receive), nur gela-
den (receive) oder nur gesendet (send) werden soll. In den meisten Fällen
wird nur geladen, deshalb ist die Einstellung receive wohl die gängigste.
ignoreWhite: Um Zeilenumbrüche, Leerzeichen etc. aus den Daten zu elimi-
nieren, wird dieser Parameter auf true gesetzt. Diese Einstellung ist in jedem
Fall zu empfehlen und auch deshalb standardmäßig auf true gesetzt.
multipleSimultaneousAllowed: bestimmt, ob mehrere Anfragen gleich-
zeitig ablaufen dürfen. Da nicht garantiert werden kann, dass genau in der
Reihenfolge der Aufrufe auch die Antworten eintreffen, und alle gängigen
Browser eine höchstzulässige Anzahl an gleichzeitig herunterzuladenden URLs
besitzen, spricht nichts dagegen, diesen Parameterwert auf false zu setzen. Ist
der Parameter auf false gesetzt, wird der Aufruf über die Methode trigger
durchgeführt, die wiederum ein status-Ereignis (CallAlreadyInProgress)
ausgibt. Details hierzu finden Sie im ActionScript 2.0-Referenzhandbuch.
supressInvalidCalls: Mithilfe dieses Parameters wird sichergestellt, dass
bei dem Wert true Aufrufe mit ungültigen Parametern erst gar nicht durch-
geführt werden.
Die nachfolgende Abbildung verdeutlicht die bisher getroffenen Einstellungen für ein
erstes Beispiel (auf der Buch-CD zu finden unter dem Namen XMLConnector01.fla):
u
u
u
u
u
ABBILDUNG 6.33
Die XMLConnector-
Komponente wurde auf der
Bühne platziert (im Weiteren
werde ich diese neben die
Bühne stellen, damit sie
mich nicht irritiert) und es
wurden ihr alle notwendigen
Parameter zugewiesen.
Als Quelle dient die Datei
XMLConnector01.xml.
SERVERSEITIGER DATENAUSTAUSCH – FLASH, PHP & DATENBANK 301
XML- vs. Textdatei für das Schema
An dieser Stelle sprechen wir zum ersten Mal von einer „echten“ XML-Datei: In unserem Kontext
verstehen wir darin eine Datei, die nicht nur „gültig“ und „wohlgeformt“ ist, sondern auch die
Endung .xml trägt. Obwohl eine Text- und eine XML-Datei dieselben Inhalte aufweisen können,
benötigt Flash eine Datei mit der Endung .xml für eine Schema-Datei. Die eigentliche einzule-
sende Datei (also unsere XML-Quelle) kann nach wie vor die Endung .txt tragen!
Damit wären die notwendigen Schritte getan – bleibt nur noch zu klären, wohin die
Daten nun gelangen, denn ein Laden von Daten ohne zugehöriges Darstellen ist wohl
in den wenigsten Fällen zielführend. Werfen wir einmal einen Blick auf die einzu-
lesende Datei XMLConnector01.xml (bzw. XMLConnector01.txt, wenn Sie eine Text-
datei einlesen möchten):
<?xml version="1.0" encoding="ISO-8859-1" standalone="yes" ?>
<Mitarbeiterliste>
<Mitarbeiter>
<Vorname>Uwe</Vorname>
<Nachname>Mutz</Nachname>
<Firma>SYNE Marketing & Consulting GmbH</Firma>
<Adresse>Am Graben 29</Adresse>
<PLZ>4020</PLZ>
<Ort>Linz</Ort>
<Staat>AUT</Staat>
<email>uwe.mutz@syne.at</email>
</Mitarbeiter>
<Mitarbeiter>
<Vorname>Alexander</Vorname>
<Nachname>Grasser</Nachname>
<Firma>SYNE Marketing & Consulting GmbH</Firma>
<Adresse>Am Graben 29</Adresse>
<PLZ>4020</PLZ>
<Ort>Linz</Ort>
<Staat>AUT</Staat>
<email>alexander.grasser@syne.at</email>
</Mitarbeiter>
<Mitarbeiter>
<Vorname>Doris</Vorname>
K A P I T E L 6302
<Nachname>Manzenreiter</Nachname>
<Firma>SYNE Marketing & Consulting GmbH</Firma>
<Adresse>Am Graben 29</Adresse>
<PLZ>4020</PLZ>
<Ort>Linz</Ort>
<Staat>AUT</Staat>
<email>doris.manzenreiter@syne.at</email>
</Mitarbeiter>
</Mitarbeiterliste>
Listing 6.35: Eingelesen wird eine nicht allzu aufregend komplexe XML-Datei: eine Mitarbeiterliste mit drei
Mitarbeitern (XMLConnector01.xml).
Es wird also Zeit, den nächsten Schritt zu tun: Wir müssen ein Schema angeben. Ein
Schema gibt an, wie die einzulesende XML-Quelle aufgebaut ist oder mit anderen
Worten: wie die XML-Quelle strukturiert ist (Verschachtelungen, Tags, Attribute).
Hierzu blenden wir uns erst einmal den Komponenten-Inspektor ein (entweder in der
Menüzeile auf FENSTER/KOMPONENTEN-INSPEKTOR oder unter Windows die Tastenkom-
bination (ª)+(F7) bzw. unter Mac OS die Tastenkombination (†)+(F7)):
ABBILDUNG 6.34
Der Komponenten-Inspektor
im Fall der XMLConnector-
Komponente
In der obigen Abbildung sehen Sie die erste Lasche PARAMETER des Komponenten-
Inspektors, deren Einträge wir auch im Eigenschaften-Inspektor zur Komponenten-
Instanz gefunden haben. Interessanter werden die Laschen BINDUNGEN und SCHEMA.
Beginnen wir mit der SCHEMA-Lasche: Markieren Sie den Eintrag < RESULTS : XML, kli-
cken Sie auf das Flyout-Menü und wählen Sie dort den Eintrag XML-SCHEMA IMPOR-
SERVERSEITIGER DATENAUSTAUSCH – FLASH, PHP & DATENBANK 303
TIEREN aus. Es öffnet sich ein Fenster, in dem Sie eine XML-Datei auswählen können,
woraus das XML-Schema importiert wird. Wie schon weiter oben erwähnt, können Sie
nur Dateien mit der Endung .xml auswählen. Für unser Beispiel importieren wir also
der Einfachheit halber genau unsere Quelldatei XMLConnector01.xml, deren Schema
sofort auch im Komponenten-Inspektor angezeigt wird:
Wenn wir nun dieses Schema mit der Quelldatei vergleichen, fällt sofort auf, dass nur
die Tags Mitarbeiterliste, Mitarbeiter, Vorname, Nachname und Firma einge-
lesen wurden – da fehlt doch was?! Es fehlen die Tags PLZ, Ort, Staat und Email!
Gehen wir der Sache auf den Grund.
Der Fehler liegt anscheinend am Inhalt der XML-Datei: Im Firmennamen „SYNE
Marketing & Consulting GmbH“ wird ein kaufmännisches Und „&“ verwendet, das
das Einlesen des Schemas blockiert. Um diese Fehlerquelle zu eliminieren, müssen wir
das „&“ URL-codieren: Der entsprechende Code lautet %26. Somit würde sich unsere
XML-Datei (das Schema!) wie folgt ändern (Auszug aus der Datei XMLConnector01b.
xml):
...
<Mitarbeiter>
<Vorname>Uwe</Vorname>
<Nachname>Mutz</Nachname>
<Firma>SYNE Marketing %26 Consulting GmbH</Firma>
<Adresse>Am Graben 29</Adresse>
<PLZ>4020</PLZ>
Fehler in der
Quelldatei oder
im Schema?
Fehler in der
Quelldatei oder
im Schema?
ABBILDUNG 6.35
Nach dem Importieren
des Schemas zeigt der
Komponenten-Inspektor den
Aufbau (= Schema) der XML-
Datei an.
K A P I T E L 6304
<Ort>Linz</Ort>
<Staat>AUT</Staat>
<email>uwe.mutz@syne.at</email>
</Mitarbeiter>
...
Listing 6.36: Auszug aus der nun URL-codierten Datei XMLConnector01b.xml: Das kaufmännische Und
„&“ wurde durch den Code %26 ersetzt. Bitte beachten Sie jedoch die nachfolgende Auflistung, denn nicht
alles, was als Fehler erscheint, ist auch ein Fehler!
An dieser Stelle möchte ich Sie auf einen meines Erachtens sehr wichtigen Punkt hin-
weisen, der immer wieder zu Verwechslungen führt:
Das Schema einer einzulesenden XML-Datei sollte idealerweise nur das „Gerüst“
(die Struktur) der einzulesenden XML-Quelle beinhalten – somit besitzt die Sche-
ma-Datei keinerlei Inhalte. Im obigen Beispiel haben wir nur zu gut erfahren, zu
welchen Problemen das führt! Des Weiteren müssen wir beachten, dass das Schema
eine Datei mit der Endung .xml ist.
Die einzulesende XML-Quelle ist nach der von der Schema-Datei vorgegebenen
Struktur aufgebaut und beinhaltet (klarerweise) sämtliche Inhalte. Diese Datei
kann eine beliebige Dateiendung aufweisen (.xml, .txt, .php etc.), solange diese
Daten XML-konform sind (Thema „Gültig“ und „Wohlgeformt“).
Somit würde sich als XML-Schema eine Datei mit folgendem Inhalt anbieten:
<?xml version="1.0" encoding="ISO-8859-1" standalone="yes" ?>
<Mitarbeiterliste>
<Mitarbeiter>
<Vorname />
<Nachname />
<Firma />
<Adresse />
<PLZ />
<Ort />
<Staat />
<email />
</Mitarbeiter>
</Mitarbeiterliste>
Listing 6.37: Ein korrektes XML-Schema (und das wollten wir ja auch!), eine sinnlose XML-Quelle!
u
u
XML-Quelle vs.
XML-Schema
XML-Quelle vs.
XML-Schema
SERVERSEITIGER DATENAUSTAUSCH – FLASH, PHP & DATENBANK 305
Beim Importieren dieses Schemas sind jedoch ein paar zusätzliche Schritte erforder-
lich:
1. Da die Felder nun ohne Inhalte sind, muss für jedes Feld der Feldtyp (Number,
String etc.) angegeben werden, ansonsten würde Flash davon ausgehen, dass diese
Felder leer sein müssen. Würden wir ein Schema mit Inhalten importieren, würde
Flash die eingelesenen Inhalte analysieren und einen entsprechenden Feldtyp
automatisch wählen.
2. Da das Tag <Mitarbeiterliste> aus nur einem verschachtelten Tag
<Mitarbeiter> besteht, nimmt Flash automatisch an, dass immer nur ein Tag
(und nicht eine Liste von Tags) eingelesen werden muss.
In der Abbildung 6.36 sehen Sie einen Screenshot, wie Flash mit diesem Schema arbei-
ten würde:
Um den Tags einen Feldtypen zuzuweisen, klicken Sie auf den Feldnamen und wählen
in der Parameterliste darunter den Eintrag DATA TYPE aus. In unserem Fall sind alle
Einträge vom Typ STRING:
ABBILDUNG 6.36
Flash geht davon aus,
dass die eingelesenen Tags
Vorname, Nachname etc.
immer leer sind. Unsere
Aufgabe wird sein, den
Feldern den zugehörigen
Datentyp zuzuweisen.
K A P I T E L 6306
Diesen Vorgang müssen wir nun für alle Felder wiederholen. Ist dies geschehen, müs-
sen wir Flash noch zu verstehen geben, dass wir mehr als nur einen einzelnen Eintrag
einlesen werden. Hierzu markieren wir den Eintrag MITARBEITER : OBJECT und wählen
in der Parameterliste als DATA TYPE den Typ ARRAY (anstatt OBJECT):
ABBILDUNG 6.37
Das Feld Vorname bekommt
den Feldtyp String zuge-
wiesen.
ABBILDUNG 6.38
Mit Angabe des Datentyps
Array geben wir Flash zu
verstehen, dass es sich nicht
um ein einzelnes Objekt han-
delt, das wir einlesen werden,
sondern vielmehr um eine
Liste von Objekten.
Haben wir diesen Schritt geschafft, geht es daran, die eigentlichen Daten einzulesen
und anzuzeigen. Wir machen uns die Sache einfach und wählen für die Anzeige eine
Tabellenform. Zunächst einmal ein Screenshot des Ergebnisses:
SERVERSEITIGER DATENAUSTAUSCH – FLASH, PHP & DATENBANK 307
Unter den KOMPONENTEN finden Sie die Komponentengruppe USER INTERFACE und
darin die Komponente DATAGRID. Ziehen Sie eine Instanz davon auf die Bühne, geben
Sie ihr einen Namen (z.B. Mitarbeitertabelle) und weisen Sie ihr eine entspre-
chende Größe zu (in meinem Fall waren das 590x350 Pixel bei einer Bühnengröße von
600x400 Pixel). Markieren Sie danach wieder die Instanz unseres XMLConnector und
weisen Sie ihr – sollten Sie das nicht bereits gemacht haben – einen Instanznamen zu
(beispielsweise myXMLConnector). Gehen Sie anschließend wie folgt vor:
1. Wählen Sie für myXMLConnector im Komponenten-Inspektor die Lasche
BINDUNGEN aus.
2. Klicken Sie auf das blaue Symbol „+“ zum Hinzufügen einer neuen Bindung:
ABBILDUNG 6.39
Einlesen einer XML-Datei
(basierend auf einem vor-
gegebenen Schema) und
Darstellen der Daten in
Tabellenform (es kommt ein
sogenanntes „DataGrid“ zur
Verwendung). Eingelesen
wird nach wie vor die Datei
XMLConnector01.xml, die
auch die kaufmännischen
Und „&“ beinhaltet – diese
waren ja nur für unser
Schema gefährlich ...
ABBILDUNG 6.40
Hinzufügen einer neuen
Bindung durch Klicken auf
das blaue „+“
K A P I T E L 6308
3. Wählen Sie aus der möglichen Bindung den Eintrag MITARBEITER : ARRAY aus und
bestätigen Sie mit OK:
4. Markieren Sie die so entstandene Bindung, wählen Sie in den Parametern zunächst
für den Parameter DIRECTION den Wert out und klicken Sie dann im Parameterfeld
BOUND TO auf die Suchlupe ganz rechts im Feld. Es öffnet sich ein Fenster mit den
möglichen Komponenten, wo Sie die DataGrid-Komponente auswählen:
ABBILDUNG 6.41
Auswählen der Liste an
Mitarbeitern (Array) für die
Anzeige im DataGrid
ABBILDUNG 6.42
Die Daten werden mithilfe
des Parameters BOUND TO dem
DataGrid „Mitarbeitertabelle“
zugewiesen.
Somit haben wir sämtliche Arbeit an sowohl dem XML-Connector als auch dem
DataGrid erledigt. Testen wir jedoch unser Beispiel, werden wir feststellen, dass trotz-
dem nichts passiert. Das liegt daran, dass das Einlesen der Daten aus der XML-Quelle
nicht automatisch passiert, sondern „angestoßen“ werden muss. Der geeignete Befehl
ist hierfür der Befehl trigger, der auf die Instanz der XMLConnector-Komponente
myXMLConnector angewandt wird:
SERVERSEITIGER DATENAUSTAUSCH – FLASH, PHP & DATENBANK 309
myXMLConnector.trigger();
Listing 6.38: Erst die Methode trigger veranlasst Flash, die XML-Quelle einzulesen und in das DataGrid
zu schreiben.
Das Ergebnis sahen Sie bereits in Abbildung 6.39.
Letzten Endes ist das Arbeiten mit Komponenten immer dann anzuraten, wenn es
schnell gehen soll und man nicht allzu viel Zeit mit Programmierung „vergeuden“
möchte. Wenn wir ehrlich sind, war das letzte Beispiel mehr „Drag&Drop“ als ernste
Entwicklung. Doch wie gesagt: Wenn es die Aufgabenstellung erfordert, ist auch gegen
„Drag&Drop“ nichts einzuwenden!
Neben der hier vorgestellten DataGrid-Komponente existieren noch einige weitere
User Interface-Komponenten, die für die Darstellung von XML-Daten hervorragend
geeignet sind:
Komponente Beschreibung
Accordion Darstellen von Daten in Form von Bereichen,die angeklickt werden und sich dann
wie ein Akkordeon aufklappen
Tree Darstellen von Daten in Form einer Baumstruktur (vergleichbar mit dem Windows
Explorer,sollten Sie diesen kennen)
Tabelle 6.3: Komponenten zur Darstellung von (beispielsweise) XML-Daten
Ein guter Anhaltspunkt, das Arbeiten mit Komponenten zu intensivieren, ist die
Beispielsammlung von Adobe, die Sie auf der Adobe-Website finden: http://www.
adobe.com/de/devnet.
6.4 ActionScript 3.0: Neues und
Änderungen
In diesem Kapitel befassen wir uns mit den Änderungen und Neuerungen, die Action-
Script 3.0 mit sich bringt.
6.4.1 Das URLLoader- und URLRequest-Objekt
In den bisherigen Ausführungen (Verwendung von ActionScript 2.0) erfuhren Sie, wie
man für ein gegebenes Objekt – sei es ein LoadVars- oder XML-Objekt – geeignete
(objektspezifische) Methoden verwendet, um die benötigten Daten zu laden. Der
Nachteil an diesen Methoden war, dass diese sich immer auf das Objekt selbst bezogen
haben: XML.load() hatte mit LoadVars.load() bis auf den (zufälligerweise) glei-
chen Namen nichts gemeinsam.
Drag&Drop
oder Program-
mierung?
Drag&Drop
oder Program-
mierung?
K A P I T E L 6310
Dies ändert sich mit ActionScript 3.0 gewaltig, denn ab nun existiert ein einziges
Objekt zum Laden von externen Daten: das URLLoader-Objekt. Das bisher bekannte
LoadVars-Objekt ist zur Gänze eliminiert worden. Im Klartext bedeutet dies, dass das
Laden externer Daten nun vollständig über das URLLoader-Objekt (in Verbindung
mit dem URLRequest-Objekt, auf das wir noch zu sprechen kommen) abgewickelt
wird!
Die Übersicht der Eigenschaften, Methoden und Ereignisse liefert uns einen Hinweis
über die Möglichkeiten dieses Objekts:
Eigenschaft Typ und Standardwert Beschreibung
bytesLoaded uint = 0 Stellt die Anzahl der Bytes dar,die bereits geladen wurden
bytesTotal uint = 0 Stellt die Anzahl der gesamt zu ladenden Bytes dar (sprich:
die Dateigröße)
data * Repräsentiert die empfangenen Daten
dataFormat String = "text" Gibt an,von welchem Typ die zu ladenden Daten sind.
Folgende Typen sind möglich:
TEXT
BINARY
VARIABLES
Tabelle 6.4: Eigenschaften des URLLoader-Objekts
Vorrangig wichtige Eigenschaften sind also data und dataFormat. Die Eigenschaften
bytesLoaded und bytesTotal benötigen Sie für den Fall, dass Sie dem User eine
Ladestandsanzeige darstellen wollen.
Methode Beschreibung
URLLoader(request:URLRequest = null) Erzeugt ein URLLoader-Objekt,dem ein URLRequest-
Objekt zugewiesen werden kann
close():void Beendet einen laufenden Ladevorgang
load(request:URLRequest):void Sendet und lädt Daten von der im URLRequest angege-
benen URL
Tabelle 6.5: Methoden des URLLoader-Objekts
Ereignis Ereignisobjekttyp und -
eigenschaft
Beschreibung
complete Event.COMLETE Wird ausgelöst,wenn der
Ladevorgang abgeschlossen
und sämtliche Daten dekodiert
wurden sowie sämtliche empfan-
genen Daten in der Eigenschaft
data des URLLoader gespeichert
wurden.Dieses Ereignis gilt es
also – wie auch schon weiter
oben beschrieben – abzuwarten.
LoadVars in
ActionScript
3.0 nicht mehr
existent!
LoadVars in
ActionScript
3.0 nicht mehr
existent!
SERVERSEITIGER DATENAUSTAUSCH – FLASH, PHP & DATENBANK 311
httpStatus HTTPStatusEvent.HTTP_STATUS Sollte ein URLLoader-Objekt per
HTTP auf Daten zugreifen wollen
und der Flash-Player in der Lage
sein,den Statuscode zu erkennen
und zurückzugeben,wird dieses
Ereignis ausgelöst.Die wichtige
Eigenschaft in diesem Fall ist die
Eigenschaft status.
ioError IOErrorEvent.IO_ERROR Tritt auf,wenn während eines
Ladeversuchs ein schwerwie-
gender Fehler auftritt und
der Download abgebrochen
werden musste.Wichtig ist die
Eigenschaft text.
open Event.OPEN Tritt nach dem Aufruf der load-
Methode auf.
progress ProgressEvent.PROGRESS Tritt auf,wenn Daten während
eines Ladevorgangs empfan-
gen werden.Die wichtigen
Eigenschaften sind bytesLoaded
und bytesTotal.Dieses Ereignis
tritt wiederholt auf.
securityError SecurityErrorEvent.
SECURITY_ERROR
Tritt auf,wenn versucht wird
auf Daten zuzugreifen,die nicht
innerhalb des Sicherheitskreises
(„Security Sandbox“) der Flash-
Anwendung liegen.Wichtig ist in
diesem Fall wie auch bei ioError
die Eigenschaft text.
Tabelle 6.6: Übersicht der Ereignisse des URLLoader-Objekts
Das URLRequest-Objekt hält mehrere Eigenschaften für uns bereit, die in Tabelle 6.7
beschrieben sind.
Eigenschaften Typ Beschreibung
contentType String Liefert den MIME-Typ eventueller POST-Daten
data Object Die angeforderten Daten
method String Legt die Übertragungsmethode fest.Mögliche Werte sind„GET“ oder
„POST“.
prototype Object Verweist auf das Prototypobjekt der Klasse
requestHeaders Array Mithilfe dieses Arrays lässt sich der HTTP-Header manipulieren.
url String Die URL,die für das Senden oder Empfangen von Daten verwendet
wird
Tabelle 6.7: Eigenschaften des URLRequest-Objekts. Besonders interessant sind die Eigenschaften data,
method und url.
K A P I T E L 6312
Laden von Daten
Werfen wir einen Blick auf die Vorgehensweise beim Laden von Daten:
1. Anlegen eines URLLoader-Objekts:
var myLoader:URLLoader = new URLLoader();
2. Anlegen eines URLRequest-Objekts zur Angabe einer Quelle:
var myURL:URLRequest = new URLRequest("URL_ZUR_QUELLE");
3. Definieren eines Eventhandler für den Fall, dass die Daten geladen wurden. Es
kommt das Ereignis COMPLETE zum Einsatz:
function FUNKTIONSNAME_DES_HANDLERS(myEvent:Event):void {
...
}
myLoader.addEventListener(Event.COMPLETE, FUNKTIONSNAME_DES_HANDLERS);
Listing 6.39: Beachten Sie in diesem Listing bitte die Tatsache, dass der Typ void nun – im Gegensatz zu
ActionScript 2.0 – klein geschrieben wird.
4. Ladevorgang starten, basierend auf den Angaben in der URLRequest-Instanz
(myURL):
myLoader.load(myURL);
Wie Sie sehen, wird an dieser Stelle noch kein Wort darüber verloren, welche Art von
Daten sich in der Datenquelle befinden. Lediglich die Voraussetzung, dass es sich um
Text, Binärdaten oder URL-codierte Variablen handelt, muss erfüllt sein. Zusammen-
gefasst sieht ein Ladevorgang nun also folgendermaßen aus:
var myLoader:URLLoader = new URLLoader();
var theURL:String = "URL_ZUR_QUELLE";
var myURL:URLRequest = new URLRequest(theURL);
function completelyLoaded(myEvent:Event):void {
...
}
myLoader.addEventListener(Event.COMPLETE, completelyLoaded);
myLoader.load(myURL);
Listing 6.40: Der Ladevorgang von Text, Binär- oder URL-codierten Daten in ActionScript 3.0. Den Umgang
mit den Eventlistenern sehen Sie in Listing 6.41 sehr ausführlich.
Laden von Text,
Binärdaten oder
URL-codierten
Daten
Laden von Text,
Binärdaten oder
URL-codierten
Daten
SERVERSEITIGER DATENAUSTAUSCH – FLASH, PHP & DATENBANK 313
Erst im nächsten Schritt wird entschieden, was mit den eingelesenen Daten geschehen
soll. Still und heimlich haben wir bisher noch vorausgesetzt, dass die einzulesenden
Daten Textdaten sind – wären es Binär- oder URL-codierte Daten, so müssten wir das
explizit angeben.
Um als Beispiel einmal die in Tabelle 6.6 aufgelisteten Ereignisse abzufragen, müssen
diese über die Methode addEventListener einer URLLoader-Instanz zugewiesen
werden. Das könnte folgendermaßen aussehen (das Beispiel finden Sie auf der Buch-
CD unter dem Namen URLLoader02_AS3.fla):
var myLoader:URLLoader = new URLLoader();
var theURL:String = "URLLoader02_AS3.xml";
var myURL:URLRequest = new URLRequest(theURL);
function EOpen(myEvent:Event):void {
statusMsg.appendText("Ladevorgang gestartetn");
}
function EProgress(myEvent:ProgressEvent):void {
statusMsg.appendText("Ladevorgang läuft... Fortschritt: "+Math.
round(myEvent.bytesLoaded/myEvent.bytesTotal*100)+"%n");
}
function EComplete(myEvent:Event):void {
statusMsg.appendText("Ladevorgang abgeschlossenn");
}
function EHttpStatus(myEvent:HTTPStatusEvent):void {
statusMsg.appendText("Http-Status eingelangt: Status="+myEvent.status+"n");
}
function EIOError(myEvent:IOErrorEvent):void {
statusMsg.appendText("IO-Error aufgetreten: Error="+myEvent.text+"n");
}
function ESecurityError(myEvent:SecurityErrorEvent):void {
statusMsg.appendText("Security-Error aufgetreten: Error="+myEvent.text+"n");
}
myLoader.addEventListener(Event.OPEN, EOpen);
myLoader.addEventListener(ProgressEvent.PROGRESS, EProgress);
myLoader.addEventListener(Event.COMPLETE, EComplete);
K A P I T E L 6314
myLoader.addEventListener(HTTPStatusEvent.HTTP_STATUS, EHttpStatus);
myLoader.addEventListener(IOErrorEvent.IO_ERROR, EIOError);
myLoader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, ESecurityError);
myLoader.load(myURL);
Listing 6.41: Für jedes auftretende Ereignis des URLLoader-Objekts wurde ein eigener Eventlistener defi-
niert. Zu beachten ist vor allem, dass die verschiedenen Ereignisse von verschiedenen Ereignisobjekttypen
abgearbeitet werden.
Hier einige Tipps für den Umgang mit den verschiedenen Ereignissen:
Ladefortschritt anzeigen
ProgressEvent.PROGRESS sowie die Eigenschaften bytesLoaded und
bytesTotal geben Ihnen Auskunft über den Ladezustand. Da dieses Ereig-
nis wiederholt auftritt, kann sehr einfach eine Ladefortschrittsanzeige erstellt
werden.
Event.COMPLETE teilt Ihnen mit, wann das Laden der Daten beendet ist.
Errorhandling
IOErrorEvent.IO_ERROR und SecurityErrorEvent.SECURITY_ERROR mit
dem Ereignis text (in beiden Fällen) lässt eine Fehlerabarbeitung zu.
Event.COMPLETE teilt Ihnen mit, wann das Laden der Daten zu Ende ist.
Kümmern wir uns im nächsten Schritt um die eingelesenen Daten. In den meisten
Fällen wird es sich um textbasierte oder URL-codierte Daten handeln, deshalb ste-
hen diese Anwendungsgebiete auch bei uns im Vordergrund. XML-Daten und deren
Auswertung nehmen wir uns in Kapitel 6.4.2 sehr ausführlich zur Brust, den Part des
Ladens der Variablen bzw. des Textes behandeln wir gleich hier.
Der Zugriff auf die geladenen Daten erfolgt in jedem Fall über die Eigenschaft data
des URLLoader-Objekts, die idealerweise beim Auftreten des Eevent.COMPLETE-
Ereignisses ausgelesen wird (target ist in diesem Fall das Netzwerkobjekt, über wel-
ches der Ladevorgang abgewickelt wurde):
function EComplete(myEvent:Event):void {
trace(myEvent.target.data);
}
Listing 6.42: Zugriff auf die geladenen Daten
Laden von URL-codierten Daten (Variablen)
In diesem Fall muss der URLLoader-Instanz zunächst mitgeteilt werden, dass die zu
ladenden Daten URL-codiert sind:
u
u
u
u
u
u
SERVERSEITIGER DATENAUSTAUSCH – FLASH, PHP & DATENBANK 315
var myLoader:URLLoader = new URLLoader();
myLoader.dataFormat = URLLoaderDataFormat.VARIABLES;
Listing 6.43: Das Datenformat wird auf „URL-codierte Variablen“ (VARIABLES) gesetzt.
Als Beispiel einzulesender (URL-codierter) Daten soll uns die Datei URLLoader03_
AS3.txt mit folgendem Inhalt dienen:
test=1&vorname=Uwe&nachname=Mutz
Der Zugriff auf die Variablen erfolgt wie in Listing 6.43 dargestellt über die data-
Eigenschaft der URLLoader-Instanz:
function EComplete(myEvent:Event):void {
... = myEvent.target.data;
}
Um nun eine spezielle Variable aus der geladenen Datei abzufragen, kann die Variable
direkt angesprochen werden. Wollen wir beispielsweise die Variable „nachname“ aus-
lesen, geschieht dies wie folgt:
...
var nn:String = myEvent.target.data.nachname;
trace("nn="+nn);
...
Listing 6.44: Zugriff auf die Variable „nachname“
Damit sind wir auch schon wieder am Ende angelangt, denn sobald wir wissen, wie die
Variablen angesprochen werden können, läuft das Spiel genau wie in den Beispielen
aus Kapitel 6.2.
Laden von Textdaten
Da das Laden von textbasierten Daten standardmäßig vom URLLoader-Objekt ange-
nommen wird, müssen wir dies nicht explizit angeben, obwohl man es theoretisch
natürlich könnte:
var myLoader:URLLoader = new URLLoader();
myLoader.dataFormat = URLLoaderDataFormat.TEXT;
Listing 6.45: Das Setzen des Datenformats ist im Fall von textbasierten Daten nicht notwendig, da dies die
Standardeinstellung ist. Somit könnten Sie getrost auf Zeile 2 des obigen Listings verzichten.
Die einzulesende Datei URLLoader04_AS3.txt, die uns hier als Beispiel dient, hat fol-
genden Inhalt:
K A P I T E L 6316
Dies ist Text, den es einzulesen gilt. Mal sehen, ob es uns gelingen
wird... Zu allem Überfluss kommen auch noch Umlaute und Sonderzeichen
vor.
Uwe Mutz
SYNE Marketing & Consulting GmbH
Listing 6.46: Inhalt der Datei URLLoader04_AS3.txt – beachten Sie die Leer- und Sonderzeichen sowie die
Umlaute.
Wie auch schon beim Laden von URL-codierten Daten greifen wir auf die Eigenschaft
data der URLLoader-Instanz zu. Wir können uns glücklich schätzen, wie einfach das
Laden von Textdaten ist, denn mit dem Zugriff auf data ist die Arbeit für uns getan
– sogar Leer- und Sonderzeichen sowie Umlaute bereiten uns keine Sorgen. Sehen Sie
selbst – zuerst der Code der Datei URLLoader04_AS3.fla, dann der Screenshot. Kurz
noch zur Erklärung: statusMsg bezeichnet eine TextArea-Instanz, die uns zur Ausga-
be der Daten dient.
var myLoader:URLLoader = new URLLoader();
//myLoader.dataFormat = URLLoaderDataFormat.TEXT; //Standardwert
var theURL:String = "URLLoader04_AS3.txt";
var myURL:URLRequest = new URLRequest(theURL);
function EComplete(myEvent:Event):void {
statusMsg.appendText("Ladevorgang abgeschlossenn");
statusMsg.appendText("Eingelesener Text:n"+myEvent.target.data);
}
myLoader.addEventListener(Event.COMPLETE, EComplete);
myLoader.load(myURL);
Listing 6.47: Laden von externen Textdaten – wie einfach die Welt doch sein kann! In der Datei auf der
Buch-CD ist das Beispiel noch um ein Eventhandling erweitert.
SERVERSEITIGER DATENAUSTAUSCH – FLASH, PHP & DATENBANK 317
Vielleicht sollten wir an dieser Stelle einmal festhalten, dass dieses Verfahren ein
Novum in der Geschichte von Flash darstellt: Ohne den Text innerhalb der Textdatei
einer Variable zuzuweisen und diese dann auszulesen, haben wir nun Zugriff auf
Texte!
Senden von Daten
Gehen wir den umgekehrten Weg und betrachten das Senden von Daten an einen Ser-
ver (sprich: ein serverseitiges Script). Da wir bisher noch keine Möglichkeit kennen-
gelernt haben, die zu versendenden Variablen zu definieren (erinnern Sie sich: im Fall
von ActionScript 2.0 und dem LoadVars-Objekt mussten wir lediglich die Variablen
innerhalb einer LoadVars-Instanz anlegen – fertig!), muss es wohl einen anderen Weg
geben ... dieser Weg heißt URLVariables. Mit anderen Worten: Eine Instanz des URL-
Variables-Objekts dient uns nun als Container für die zu versendenden Variablen.
Nehmen wir an, wir wollen die Variablen „Vorname“ und „Nachname“ an ein server-
seitiges Script übermitteln. Also nichts wie rein mit den Variablen in unseren Contai-
ner:
var myVars:URLVariables = new URLVariables();
myVars.Vorname = "Uwe";
myVars.Nachname = "Mutz";
Listing 6.48: Die Verwendung des URLVariables-Objekts ist denkbar einfach: Instanz anlegen, Variablen
darin anlegen und ihnen einen Wert zuweisen.
Wie wir wissen, wird das URLRequest-Objekt zum Laden und Senden von Daten ver-
wendet. In Tabelle 6.7 haben wir uns über die Verwendung der Konstanten GET und
POST Gedanken gemacht – genau dieses Thema müssen wir nun berücksichtigen:
Sollen die Daten später per POST oder GET versandt werden?
ABBILDUNG 6.43
Na, was sagen Sie –
Laden von Textdaten
ohne umständliche
Variablenzuweisung, wie es
noch in ActionScript 2.0 not-
wendig war!
K A P I T E L 6318
Schritt 2 in unserem Beispiel umfasst demnach das Anlegen einer neuen URLRequest-
Instanz und das Festlegen der Übertragungsmethode über die Eigenschaft method:
var myURL:URLRequest = new URLRequest();
myURL.method = "GET";
Listing 6.49: Eine neue URLRequest-Instanz wurde erzeugt und es wurde ihr die Übertragungsmethode
GET zugewiesen.
Jetzt müssen wir die beiden Objekte URLVariables und URLRequest noch „zusam-
menbringen“, sodass die URLRequest-Instanz die angelegten Variablen später auch
versenden kann. Das korrekte Decodieren der Daten (in beispielsweise URL-codierte
Form) geschieht dabei ganz automatisch:
myURL.data = myVars;
Listing 6.50: Der URLRequest-Instanz myURL werden über die Eigenschaft data alle in myVars er-
zeugten Variablen zugewiesen.
Alle Vorbereitungen für das Versenden der Daten sind nun erledigt – bleibt zu klären,
zu welchem Zweck die Daten versandt werden sollen. Hier einige Möglichkeiten:
Daten an ein serverseitiges Script übergeben, das die Daten dann weiterverarbei-
tet: Ein Beispiel dafür wäre das Speichern der Daten in einer Datenbank oder das
Überprüfen der Daten für ein eventuelles Login.
Daten an ein Dokument übergeben und dieses in einem neuen Fenster öffnen. Soll-
ten die Daten per GET übergeben worden sein, so können diese sowohl server- als
auch clientseitig verarbeitet werden.
Variante 1: Daten senden mit dem URLLoader-Objekt
Vielleicht kommt es Ihnen eigenartig vor, dass wir ein Objekt mit dem Wort „Loa-
der“ im Namen zum Versenden von Daten verwenden. Ganz so abwegig ist die Sache
jedoch nicht, da ein URLLoader nach dem Senden eine etwaige Antwort des Servers
empfängt und somit „lädt“. Alle weitere Arbeit mit dem URLLoader-Objekt erfolgt wie
gehabt, denn dem URLRequest-Objekt wurden bereits alle Variablen zum Versenden
zugewiesen:
var theURL:String = "urlvariables01.php";
myURL.url = theURL;
var myLoader:URLLoader = new URLLoader();
function EOpen(myEvent:Event):void {
statusMsg.appendText("Ladevorgang gestartetn");
}
u
u
SERVERSEITIGER DATENAUSTAUSCH – FLASH, PHP & DATENBANK 319
function EComplete(myEvent:Event):void {
statusMsg.appendText("Ladevorgang abgeschlossenn");
statusMsg.appendText("Rückgabetext der PHP-Datei:n"+myEvent.target.data);
}
myLoader.addEventListener(Event.OPEN, EOpen);
myLoader.addEventListener(Event.COMPLETE, EComplete);
myLoader.load(myURL);
Listing 6.51: Fortsetzung des angefangenen Scripts. Den gesamten Code finden Sie in der Datei
URLVariables01_AS3.fla.
Die Eigenschaft url ist zwar schon hinlänglich bekannt, jedoch ist die hier angespro-
chene URL ein Verweis auf die Datei (in unserem Fall handelt es sich um urlvariab-
les01.php), welche die gesendeten Daten entgegennimmt und entsprechend auswertet.
Hier deren Inhalt:
$returner = "ERROR (0)";
if(count($_REQUEST)>0) {
$returner = "empfangende Daten:n";
foreach($_REQUEST as $itm=>$val) {
$returner.= "$itm=$valn";
}
}
else { $returner = "ERROR (1)"; }
echo($returner);
Listing 6.52: Die Datei urlvariables01.php nimmt etwaig gesendete Daten gleich welcher Sendemethode
(GET oder POST) entgegen und erzeugt hieraus eine Variable $returner, die im Weiteren per echo in den
Ausgabepuffer der Datei geschrieben wird.
Das PHP-Script setzt zunächst eine Variable $returner auf den Wert „ERROR (0)“,
der uns mitteilt, dass ein unbekannter Fehler aufgetreten ist. Danach wird überprüft,
ob Daten per POST oder GET gesendet wurden (diese müssten sich dann im $_
REQUEST-Array befinden und somit müsste das Array eine Länge größer null aufwei-
sen). Ist dies nicht der Fall, dann wird $returner der Wert „ERROR (1)“ zugewiesen.
Wurden jedoch Daten übermittelt, wird $returner dazu verwendet, einen String aus
den gesandten Daten zusammenzustellen. Dieser String bzw. die Fehlerkennzeichnung
„ERROR (0)“ oder „ERROR (1)“ wird am Ende des Scripts per echo ausgegeben:
echo($returner);.
K A P I T E L 6320
Zurück zu Flash. Das URLLoader-Objekt nimmt den von der PHP-Datei erzeugten
String entgegen und gibt den String in der TextArea statusMsg aus – all dies ist in der
Funktion EComplete zu finden.
Nach einem Test online (diesmal benötigen wir ja wieder einen Server, der die PHP-
Anweisungen verarbeiten kann) erhalten wir dieses Ergebnis:
Variante 2: Senden mit sendToURL
Die Methode sendToURL ist vergleichbar mit der Methode send des LoadVars-
Objekts: Es werden Variablen an einen Server übertragen, eine etwaige Antwort des
Servers wird jedoch ignoriert (im Gegensatz zur obig beschriebenen Methode, die eine
Antwort des Servers auswertet). Sie ist also ideal dafür geeignet, wenn man an einen
Server Daten übermitteln will, die zwar serverseitig abgearbeitet werden sollen, wobei
aber eine Antwort des Servers nicht notwendig ist – einfache Datenbankanwendungen
wie Schreiben von statistischen Werten in Bezug auf das User-Verhalten oder zeitkri-
tische Anwendungen sind Einsatzgebiete von sendToURL.
sendToURL ersetzt gemeinsam mit der Methode navigateToURL die getURL-Metho-
de aus ActionScript 2.0.
Die Verwendung ist sehr ähnlich wie die zuvor mit dem URLLoader vorgestellte
Variante. Es besteht jedoch keine Möglichkeit, eine abgeschlossene Übertragung abzu-
warten, da der Server keinen Response gibt. Lediglich die Möglichkeit einer einfachen
Fehlerüberprüfung mit der im AJAX-Kapitel bereits hinlänglich dargestellten try-
catch-Methode ist möglich:
Ersatz eins für
getURL aus
ActionScript 2.0
ABBILDUNG 6.44
Flash sendet die in
URLVariables definierten
Variablen an die Datei
urlvariables01.php, welche
wiederum einen (Rückgabe-
)String zusammenbastelt, in
dem die gesandten Variablen
vorkommen. Flash empfängt
diesen String und gibt ihn in
der TextArea aus.
SERVERSEITIGER DATENAUSTAUSCH – FLASH, PHP & DATENBANK 321
var myVars:URLVariables = new URLVariables();
myVars.Vorname = "Uwe";
myVars.Nachname = "Mutz";
var myURL:URLRequest = new URLRequest();
myURL.method = "GET";
myURL.data = myVars;
var theURL:String = "sendtourl01.php";
myURL.url = theURL;
try {
sendToURL(myURL);
}
catch(myError:Error) {
statusMsg.appendText("FEHLER beim Versenden:ntMessage: "+myError.
message+"ntName: "+myError.name+"nterrorID: "+myError.errorID);
}
Listing 6.53: Versenden von Daten an einen Server per sendToURL
Das Listing entspricht bis auf den try-catch-Abschnitt den Listings Listing 6.48 bis
Listing 6.50:
Anlegen einer URLVariables-Instanz, um die zu übertragenen Daten zu definie-
ren
Anlegen einer URLRequest-Instanz, um Daten versenden zu können. In unserem
Fall werden die in myVars abgelegten Daten per GET an die Datei sendtourl01.php
verschickt.
Im Grunde genommen hätte ein abschließender Aufruf von sendToURL ausgereicht,
um die Daten zu übermitteln. Der umgebende try-catch-Bereich gibt uns die Mög-
lichkeit, eine entsprechende Fehlermeldung in einer TextArea statusMsg auszuge-
ben, sollte der sendToURL-Aufruf zu einem Fehler geführt haben. Benötigen Sie eine
Fehlerabarbeitung nicht, so lassen Sie den try-catch-Bereich einfach weg und rufen
lediglich die sendToURL-Methode auf.
Um unser Beispiel überprüfen zu können, ist die Datei sendtourl01.php so aufgebaut,
dass sie die einkommenden Daten übernimmt und daraus eine E-Mail zusammen-
stellt:
function create_email_header($name, $value) {
return ($name && $value) ? "$name: $valuern" : "";
u
u
K A P I T E L 6322
}
if(count($_REQUEST)>0) {
$mailfrom = "autosender@syne.at";
$mailto = "uwe.mutz@syne.at";
$subject = "TESTMAIL von sendtourl01.php";
$msg = "Uebertragene Daten:n";
foreach($_REQUEST as $itm=>$val) {
$msg.= "$itm=$valn";
}
$msg.= "n(Versand per Email an: $mailto)";
$headers = "";
$headers .= create_email_header("From", $mailfrom);
$headers .= create_email_header("Reply-to", $mailto);
if(!mail($mailto, $subject, $msg, $headers)) {
die("ERROR: FEHLER beim Versand der Email");
}
}
Listing 6.54: sendtourl01.php empfängt die von Flash versendeten Daten, generiert daraus den Inhalt einer
E-Mail (foreach-Schleife) und versendet die E-Mail an eine vorgegebene E-Mail-Adresse (hier: uwe.
mutz@syne.at) mithilfe der mail-Funktion.
Ignorieren wir einmal vorerst die Funktion create_email_header und wenden uns
gleich dem Bereich darunter zu:
count($_REQUEST) gibt die Anzahl der (per GET oder POST) übermittelten
Daten an. Waren es mehr als null Daten, so werden die Daten abgearbeitet.
Die Variablen $mailfrom, $mailto und $subject speichern den Absender,
Empfänger und den Betreff respektive und dienen lediglich der Übersichtlichkeit
(ebenso hätte man die Absender- und Empfängeradresse sowie den Betreff auch
direkt im mail-Befehl unterbringen können).
$msg soll den Inhalt der E-Mail beinhalten.Zunächst weisen wir ihr den Text„Ueber-
tragene Daten:n“ zu, danach gehen wir in der foreach-Schleife alle erhaltenen
Daten durch und erweitern die Variable $msg durch den Variablennamen ($itm)
u
u
u
SERVERSEITIGER DATENAUSTAUSCH – FLASH, PHP & DATENBANK 323
und den Variableninhalt ($val). Abschließend hängen wir an $msg noch den Text
„n(Versand per Email an: $mailto)“ an. Sie erinnern sich sicherlich, dass „n“
einen Zeilenumbruch im Text erzeugt.
Die Variable $headers beinhaltet im weiteren die Header-Informationen für den
Versand der E-Mail. Nachdem diese nach einem vorgegebenen Prinzip aufgebaut
werden müssen, verwendet man gerne eine Funktion, die dies erledigt (somit sind
wir bei der Funktion create_email_header angelangt, deren Erklärung ich
zunächst übersprungen hatte).
Abschließend wird die E-Mail versandt (mail-Befehl) – sollte bei der Abarbeitung
von mail ein Fehler auftreten, wird das Script abgebrochen und eine entspre-
chende Fehlermeldung ausgegeben.
u
u
Variante 3: Senden mit navigateToURL
Die Variante mit navigateToURL ist im Wesentlichen die gleiche wie diejenige mit
sendToURL, mit einem einzigen Unterschied: navigateToURL öffnet die von Flash
aufgerufene (und an diese übergebene Daten) in einem Fenster.
navigateToURL erwartet bei einem Aufruf zwei Parameter:
navigateToURL(request:URLRequest, window:String):void
Ersatz zwei für
getURL
ABBILDUNG 6.45
Flash teilt der Datei send-
tourl01.php mit, welche
Daten in einer E-Mail
gesammelt und versendet
werden sollen. Fehler sind
keine aufgetreten, eine
Rückmeldung über einen
positiven Versand der E-Mail
haben wir jedoch auch nicht
erhalten.
K A P I T E L 6324
request ist eine Instanz des URLRequest-Objekts und beinhaltet die Daten, die
Sendemethode (GET oder POST) sowie die URL.
window bezeichnet das Fenster, in welchem die gegebene URL geöffnet werden soll.
Die möglichen Werte kommen Ihnen sicherlich bekannt vor:
„_self“: Die URL wird im aktuellen Frame im aktuellen Fenster geöffnet.
„_blank“: Die URL wird in einem neuen Fenster geöffnet (Standardeinstel-
lung).
„_parent“: Die URL wird im übergeordneten Frame des aktuellen Frame im
aktuellen Fenster geöffnet.
„_top“: Die URL wird im obersten Frame des aktuellen Fensters geöffnet.
„FRAMENAME“: Die URL wird in dem von Ihnen benannten Frame geöffnet.
Inwieweit Sie noch mit Frames arbeiten, müssen Sie für sich selbst und für Ihre Kun-
den entscheiden. Ich würde Ihnen den Tipp geben, keine neuen Webprojekte mit
Frames anzugehen, da sie jetzt schon nicht mehr zum offiziellen Standard „strict“ von
XHTML gehören.
Ändern wir das aus Listing 6.53 bekannte Beispiel entsprechend um, so erhalten wir:
...
var theURL:String = "navigatetourl01.php";
...
try {
navigateToURL(myURL);
}
catch(myError:Error) {
statusMsg.appendText("FEHLER beim Versenden:ntMessage: "+myError.
message+"ntName: "+myError.name+"nterrorID: "+myError.errorID);
}
...
Listing 6.55: Aus Listing 6.53 haben sich lediglich der Methodenaufruf von sendToURL auf navigate-
ToURL sowie die aufzurufende URL (jetzt: navigatetourl01.php) geändert.
Die Daten werden somit an die Datei navigatetourl01.php per GET versandt, wobei
navigatetourl01.php in einem neuen Fenster (Standardeinstellung, sofern kein eigenes
Fenster angegeben wurde) geöffnet wird:
u
u
u
u
u
u
u
Frames?
SERVERSEITIGER DATENAUSTAUSCH – FLASH, PHP & DATENBANK 325
6.4.2 Der Aufbau: das XML-Objekt &
ActionScript 3.0
Mit Einführung von ActionScript 3.0 wurden an vielen Klassen Änderungen vor-
genommen. Im Speziellen betrifft dies auch die XML-Klasse, die nun den Standard
ECMAScript for XML (E4X) unterstützt. Da dies eine wesentliche Änderung gegenü-
ber der bisherigen Handhabung von XML-Daten bedeutet, haben die Entwickler von
Adobe kurzerhand die bisherige XML-Klasse in andere Klassen verschoben und eine
neue XML-Klasse eingeführt. Die nachfolgende Tabelle soll Ihnen die Änderungen
verdeutlichen (Quelle: Referenzhandbuch für ActionScript 3.0):
XML-Klasse flash.xml.XMLDocument Diese Klasse wurde in das flash.
xml-Paket verschoben und der
Name wurde in XMLDocument
geändert,um einen Konflikt mit
der neuen Top-Level XML-Klasse
zu vermeiden,die ECMAScript für
XML (E4X) implementiert.
contentType flash.net.URLRequest.contentType
docTypeDecl flash.xml.XMLDocument.docTypeDecl
idMap flash.xml.XMLDocument.idMap
ignoreWhite flash.xml.XMLDocument.ignoreWhite
loaded Entfernt Die Funktionen zum Laden
einer Datei wurden aus der
XMLDocument-Klasse entfernt.
Verwenden Sie stattdessen
URLLoader.
status Entfernt Fehler beim Parsen werden jetzt
über Ausnahmefehler gemeldet.
ABBILDUNG 6.46
Ähnlich wie bei sendToURL
werden die Daten an ein
geeignetes Webdokument
übergeben, wobei
navigateToURL dieses in
einem Fenster darstellt.
K A P I T E L 6326
xmlDecl flash.xml.XMLDocument.xmlDecl
XML flash.xml.XMLDocument.XMLDocument()
addRequestHeader() flash.net.URLRequest.requestHeaders
createElement() flash.xml.XMLDocument.createElement()
createTextNode() flash.xml.XMLDocument.createTextNode()
getBytesLoaded() flash.net.URLLoader.bytesLoaded Die Funktionen zum Laden einer
Datei wurden aus der XMLDocu-
ment-Klasse entfernt.Verwenden
Sie stattdessen URLLoader.
getBytesTotal() flash.net.URLLoader.bytesTotal Die Funktionen zum Laden einer
Datei wurden aus der XMLDocu-
ment-Klasse entfernt.Verwenden
Sie stattdessen URLLoader.
load() Entfernt Die Funktionen zum Laden
einer Datei wurden aus der
XMLDocument-Klasse entfernt (in
ActionScript 2.0 war dies die XML-
Klasse).Verwenden Sie stattdes-
sen URLLoader.
onData() flash.net.URLLoader dispatches event:
complete
Die Funktionen zum Laden
einer Datei wurden aus der
XMLDocument-Klasse entfernt.
Verwenden Sie stattdessen
URLLoader.Wurde im neuen
Ereignismodell durch ein com-
plete-Ereignis ersetzt.
onHTTPStatus() flash.net.URLLoader dispatches event:
httpStatus
Die Funktionen zum Laden
einer Datei wurden aus der
XMLDocument-Klasse entfernt.
Verwenden Sie stattdessen
URLLoader.Wurde im neuen
Ereignismodell durch ein http-
Status-Ereignis ersetzt.
onLoad() flash.net.URLLoader dispatches event:
complete
Die Funktionen zum Laden
einer Datei wurden aus der
XMLDocument-Klasse entfernt.
Verwenden Sie stattdessen
URLLoader.Wurde im neuen
Ereignismodell durch ein com-
plete-Ereignis ersetzt.
parseXML() flash.xml.XMLDocument.parseXML()
send() Entfernt Die Funktionen zum Senden
einer Datei wurden aus der
XMLDocument-Klasse entfernt (in
ActionScript 2.0 war dies die XML-
Klasse).Verwenden Sie stattdes-
sen die Funktionen und Klassen
im flash.net-Paket.
sendAndLoad() Entfernt Die Funktionen zum Senden und
Laden einer Datei wurden aus der
XMLDocument-Klasse entfernt (in
ActionScript 2.0 war dies die XML-
Klasse).Verwenden Sie stattdes-
sen URLRequest und URLLoader.
Tabelle 6.8: Änderungen in der XML-Klasse von ActionScript 2.0 zu ActionScript 3.0
SERVERSEITIGER DATENAUSTAUSCH – FLASH, PHP & DATENBANK 327
XMLNode-Klasse flash.xml.XMLNode Der Speicherort wurde geändert.Diese Klasse
wurde in das flash.xml-Paket verschoben.
nodeType flash.xml.XMLNode.nodeType Der Datentyp wurde von Number zu uint geän-
dert.
XMLNode flash.xml.XMLNode.XMLNode() Der Datentyp des type-Parameters wurde von
Number zu uint geändert.
Tabelle 6.9: Änderungen in der XMLNode-Klasse von ActionScript 2.0 zu ActionScript 3.0
XMLSocket-Klasse flash.net.XMLSocket Diese Klasse wurde in das flash.
net-Paket verschoben.
XMLSocket flash.net.XMLSocket.XMLSocket() Es wurden zwei optionale
Parameter zum Festlegen von
Host und Port hinzugefügt.
connect() flash.net.XMLSocket.connect() Der Datentyp des port-
Parameters wurde in int geän-
dert.
onClose() flash.net.XMLSocket dispatches event:close Wurde im neuen Ereignismodell
durch ein close-Ereignis ersetzt.
onConnect() flash.net.XMLSocket dispatches event:connect Wurde im neuen Ereignismodell
durch ein connect-Ereignis er-
setzt.
onData() flash.net.XMLSocket dispatches event:data Wurde im neuen Ereignismodell
durch ein data-Ereignis ersetzt.
onXML() Entfernt In ActionScript 3.0 wird nur das
data-Ereignis ausgelöst,sodass
Sie entweder E4X- oder den äl-
teren XML-Parser (XMLDocument-
Klasse) verwenden können.Die
alte Ereignisprozedur onXML
wurde nach dem Parsen des XML-
Codes aufgerufen.Dies ergibt in
ActionScript 3.0 keinen Sinn,weil
Sie zum Parsen des XML-Codes
jetzt zwischen der XML-Klasse
(E4X) und der XMLDocument-
Klasse (ältere Version) wählen
können.
Tabelle 6.10: Änderungen in der XMLSocket-Klasse von ActionScript 2.0 zu ActionScript 3.0
Wie Sie aus den obigen Tabellen entnehmen können, betreffen viele Änderungen das
Senden und Laden von XML-Dateien, die insgesamt in die Klasse URLLoader verscho-
ben worden sind. Dementsprechend müssen wir das gesamte Prozedere des Ladens
von XML-Daten in ActionScript 3.0 überdenken.
Im Fall von ActionScript 3.0 verhält sich das Laden von XML-Daten folgendermaßen
(diese Vorgehensweise haben wir bereits in Kapitel 6.4.1 kennengelernt):
1. Anlegen eines URLLoader-Objekts: Dieses Objekt wird in ActionScript 3.0 generell
zum Laden von Daten verwendet:
var myLoader:URLLoader = new URLLoader();
K A P I T E L 6328
2. Anlegen eines URLRequest-Objekts zum Angeben einer Quelle:
var myURL:URLRequest = new URLRequest("URL_ZUR_QUELLE");
3. Definieren eines Eventhandler für den Fall, dass die Daten geladen wurden. Es
kommt das Ereignis COMPLETE zum Einsatz:
function FUNKTIONSNAME_DES_HANDLERS(myEvent:Event):void {
...
}
myLoader.addEventListener(Event.COMPLETE, FUNKTIONSNAME_DES_HANDLERS);
Listing 6.56: Ladevorgang mit dem URLLoader- und URLRequest-Objekt
4. Ladevorgang starten basierend auf den Angaben in der URLRequest-Instanz
(myURL):
myLoader.load(myURL);
Wenn wir diese Vorgehensweise mit der von ActionScript 2.0 vergleichen, fallen uns
folgende Punkte auf:
Während in ActionScript 2.0 im XML-Objekt eine eigene Methode zum Laden von
Daten (XML.load) zur Verfügung stand, wird nun ein eigenes „Lade-Objekt“ URL-
Loader verwendet. Dieses Objekt ist nicht auf das XML-Objekt beschränkt, sondern
ist generell zum Laden von Text, Binär- oder URL-codierten Daten verwendbar.
Eine genauere Beschreibung dieses Objekts finden Sie weiter oben.
In ActionScript 2.0 war die zu ladende Quelle ein einfacher Parameter der load-
Methode (XML.load("URL ZUR QUELLE")), in ActionScript 3.0 wird hierfür
ebenfalls ein eigenes Objekt URLRequest verwendet.
Entgegen dem für das bisherige XML-Objekt bereits vorhandenen Eventhandler
onLoad muss in ActionScript 3.0 ein Eventhandler zugewiesen werden (addE-
ventListener). Das Ereignis selbst wird aus der (Basis-)Klasse Event bezogen.
Eine genaue Beschreibung der Event-Klasse finden Sie in der ActionScript 3.0-
Referenz.
Beim gesamten Ladevorgang in ActionScript 3.0 wurde noch kein einziges Mal ein
XML- oder ähnliches Objekt ins Spiel gebracht, denn der Ladevorgang ist unabhän-
gig vom Inhalt der zu ladenden Daten. Erst nach dem Ladevorgang wird entschie-
den, was mit den geladenen Daten eigentlich getan werden soll.
Bevor wir auf die gerade verwendeten neuen Objekte URLLoader und URLRequest zu
sprechen kommen, sehen wir uns noch den weiteren Vorgang zum Auslesen der XML-
Daten an. Wobei ich an dieser Stelle gleich vorausschicken möchte, dass wir in diesem
ersten Beispiel beim Auswerten der XML-Daten lediglich an der Oberfläche kratzen
werden – viel tiefer in die Materie gehen wir dann weiter unten im Kapitel.
u
u
u
u
SERVERSEITIGER DATENAUSTAUSCH – FLASH, PHP & DATENBANK 329
Die nächsten Schritte des Ladezyklus sind:
5. Anlegen eines XML-Objekts:
var myXML:XML;
6. Einlesen der XML-Daten in das XML-Objekt und Festlegen der grundlegenden
Eigenschaften des XML-Objekts. Dieser Vorgang wird erst nach dem Laden durch
den URLLoader durchgeführt und im Allgemeinen befindet sich dieser Teil
innerhalb des Event.COMPLETE-Eventhandler:
myXML = new XML(myEvent.target.data);
myXML.ignoreWhitespace = true;
myXML.ignoreComments = true; //Standard: true
myXML.ignoreProcessingInstructions = true; //Standard: true
Neben der schon bekannten Eigenschaft ignoreWhitespace (Eliminieren/
„Ignorieren“ von Zeilenumbrüchen, Leerzeichen etc.) sind die Eigenschaften igno-
reComments (Eliminieren von XML-Kommentaren) und ignoreProcessingIn-
structions (Ignorieren von Verarbeitungsanweisungen) hinzugekommen. Beide
Eigenschaften sind standardmäßig bereits auf den Wert true gesetzt, deshalb müssen
Sie diese Eigenschaften nicht noch einmal konkret auf true setzen. Jedoch wollte ich
Ihnen diese Eigenschaften nicht vorenthalten, worauf ich sie kurzerhand eingebaut
habe. In zukünftigen Beispielen werden wir diese Eigenschaften nicht mehr explizit
auf true setzen.
Fassen wir die obigen Schritte in ein Script zusammen und wenden es auf eine XML-
Datei namens XML01_AS3.xml an, so erhalten wir nachfolgendes Listing. Die eingele-
senen XML-Daten wandeln wir mit toXMLString in einen String um und schreiben
diesen in eine TextArea statusMsg. Der Inhalt der XML-Datei entspricht demjenigen
aus Listing 6.35 mit dem Unterschied, dass die kaufmännischen Und „&“ durch ent-
sprechende Escape-Zeichen ersetzt wurden:
...
<Firma>SYNE Marketing %26 Consulting GmbH</Firma>
...
Listing 6.57: Ein kaufmännisches Und „&“ wird in URL-Codierung mit %26 angegeben.
Wir bedienen uns der Funktion decodeURIComponent, um diese Escape-Zeichen
wieder in die entsprechenden Zeichen rückzuwandeln. (Tipp: Schlagen Sie in der
ActionScript-Referenz nach, um den Unterschied zwischen decodeURI und decodeU-
RIComponent herauszufinden.)
var myLoader:URLLoader = new URLLoader();
var theURL:String = "XML01_AS3.xml";
ignoreComments
und ignore-
Processing-
Instructions
K A P I T E L 6330
var myURL:URLRequest = new URLRequest(theURL);
var myXML:XML;
function completelyLoaded(myEvent:Event):void {
myXML = new XML(myEvent.target.data);
myXML.ignoreWhitespace = true;
myXML.ignoreComments = true; //Standard: true
myXML.ignoreProcessingInstructions = true; //Standard: true
statusMsg.appendText(decodeURIComponent(myXML.toXMLString()));
}
myLoader.addEventListener(Event.COMPLETE, completelyLoaded);
myLoader.load(myURL);
Listing 6.58: XML-Verarbeitung in ActionScript 3.0. Die Funktion decodeURIComponent sorgt dafür, dass
die Escape-Zeichen in normale Zeichen umgewandelt werden.
Ein Screenshot liefert den Beweis der Funktionstüchtigkeit unseres Beispiels, welches
Sie übrigens wie gewohnt auf der Buch-CD finden (XML01_AS3.fla):
ABBILDUNG 6.47
Einlesen und Ausgeben
einer XML-Quelle mittels
ActionScript 3.0
SERVERSEITIGER DATENAUSTAUSCH – FLASH, PHP & DATENBANK 331
„Ur“-XML in ActionScript 3.0
Falls Sie in ActionScript 3.0 entwickeln, jedoch auf die bisherige Arbeitsweise mit dem XML-
Objekt aus ActionScript 2.0 nicht verzichten wollen, können Sie nach wie vor auf dieses zugrei-
fen. Wie in den obigen Tabellen dargestellt, wurden sämtliche XML-Klassen in ein (extern einzu-
bindendes) Paket flash.xml verschoben, wobei die aus ActionScript 2.0 bekannte XML-Klasse
in XMLDocument umbenannt wurde, damit keine Kollisionen mit der neuen XML-Klasse aus
ActionScript 3.0 auftreten können.
Irgendwann werden Sie sich wahrscheinlich die Frage stellen, was jetzt in ActionScript
3.0 im Umgang mit XML so viel besser geworden sein soll. Bis zu diesem Zeitpunkt ist
die Frage auch ganz und gar nicht unberechtigt, haben wir uns denn noch gar keine
wesentlichen Änderungen angesehen. Das gehen wir jetzt an!
Bisher hatten wir das „Problem“, dass die eingelesenen XML-Daten geparst werden
mussten, was mitunter relativ aufwändig hatte sein können. Durch die Unterstützung
von ECMAScript for XML gehört das Parsen mehr und mehr der Vergangenheit an.
E4X definiert an sich eine große Menge an Klassen zur Verarbeitung von XML-Daten,
von denen die Klassen XML, XMLList, QName und Namespace in ActionScript 3.0 über-
nommen wurden, von denen wiederum zwei von größerem Interesse für uns sind:
XML: Das XML-Objekt enthält eine Anzahl von Methoden und Eigenschaften für die
Verarbeitung der geladenen XML-Daten.
XMLList: Ein XMLList-Objekt ist für die Verarbeitung mehrerer XML-Objekte
gedacht – es ist mehr oder weniger eine Sammlung einzelner XML-Objekte.
In den meisten Fällen werden wir uns ausschließlich mit dem XML-Objekt begnügen,
lediglich in Projekten mit vielen XML-Objekten gleichzeitig macht das XMLList-Objekt
Sinn.
Folgende XML-Datei soll uns als Quelle dienen:
<?xml version="1.0" encoding="ISO-8859-1" standalone="yes" ?>
<Audioplayer>
<Player version="1.3" skin="2">
<Autoplay>1</Autoplay>
<verwendeReihenfolge>1</verwendeReihenfolge>
<Begruessungstext>Be my DJ</Begruessungstext>
</Player>
<Playliste>
<Song pos="1" useID3="1">
<Titel>Warriors of the wasteland</Titel>
<Interpret>Frankie goes to Hollywood</Interpret>
<Src>WarriorsOfTheWasteland.mp3</Src>
u
u
Warum
ActionScript 3.0?
K A P I T E L 6332
</Song>
<Song pos="4" useID3="1">
<Titel>Be a Warrior</Titel>
<Interpret>Jestofunk</Interpret>
<Src>BeAWarrior.mp3</Src>
</Song>
</Playliste>
<Playliste>
<Song pos="5" useID3="0">
<Titel>Numb</Titel>
<Interpret>Linkin Park</Interpret>
<Src>Numb.mp3</Src>
</Song>
</Playliste>
</Audioplayer>
Listing 6.59: Diese XML-Datei ist ein wenig komplexer aufgebaut als die des vorigen Beispiels und dient uns
somit als besseres Anschauungsobjekt.
Lesen wir doch mal mit ActionScript 3.0 die Daten aus dem XML-Objekt aus. Das
Schöne an Version 3 ist, dass man nun direkt auf die einzelnen Tags zugreifen kann.
Einige Beispiele:
Wir wollen auf Anhieb wissen, welche Player-Version (zu finden im Tag <Player
version="1.3"...> als Attribut version) verwendet werden soll:
myXML.Player.@version;
Folgende Punkte möchte ich festhalten:
Das Tag <Player> kann direkt angesprochen werden – es muss lediglich auf
die Verschachtelung geachtet werden. (<Player> liegt in der Hierarchie direkt
unter dem Root-Tag <Audioplayer>, welches durch myXML repräsentiert
wird.) Der Zugriff erfolgt direkt über den Tag-Namen. Es besteht also keine
Notwendigkeit mehr, mit den Eigenschaften wie firstChild usw. zu arbei-
ten.
Würde sich <Player> nicht an erster Stelle im Code befinden, sondern etwa
am Ende des Listings (jedoch in derselben Hierarchiestufe wie jetzt), würde
der Zugriff auf die gleiche Art und Weise erfolgen (lesen Sie hierzu die XML-
Datei XML02a_AS3.xml in XML02_AS3.fla ein, um dies zu verifizieren):
<?xml version="1.0" encoding="ISO-8859-1" standalone="yes" ?>
<Audioplayer>
u
u
u
SERVERSEITIGER DATENAUSTAUSCH – FLASH, PHP & DATENBANK 333
<Playliste>
...
</Playliste>
<Playliste>
...
</Playliste>
<Player version="1.3" skin="2">
...
</Player>
</Audioplayer>
Listing 6.60: Die Reihenfolge von <Player> und der <Playliste>-Tags wurde vertauscht – <Player>
steht nun am Ende der Liste.
Ebenso kann direkt auf ein Attribut innerhalb eines Tag zugegriffen werden:
Hierzu wird das „@“ mit dem darauffolgenden Attributnamen angegeben.
Wir wollen wissen, welchen Titel der zweite Song der ersten Playliste hat (das wäre
in unserem Fall „Be a warrior“):
myXML.Playliste[0].Song[1].Titel;
Der Zugriff auf die erste <Playliste>-Gruppe erfolgt wie gewohnt über das
Array Playliste (sobald ein Tag mehr als nur einmal vorkommt, wird es in
Form eines Arrays dargestellt), und zwar im speziellen auf den nullten Eintrag
dieses Arrays: myXML.Playliste[0]. Da das Tag <Song> ein untergeordnetes Tag
von <Playliste> ist, greifen wir über die Punktnotation auf diese Gruppe zu und
wählen den Eintrag 1 aus: myXML.Playliste[0].Song[1]. Bleibt nur noch das
Tag <Titel> abzufragen: myXML.Playliste[0].Song[1].Titel.
Halten wir fest:
Wie schon oben erwähnt, ist die Position eines Tag in der XML-Struktur nicht
mehr von Bedeutung für das Auslesen – lediglich die Verschachtelung der Tags
muss beachtet werden.
Um den Wert (besser: Inhalt) eines Knotens auszulesen, muss nicht mehr wie
in ActionScript 2.0 auf das erste Kind (firstChild) eines Knotens/Tag zuge-
griffen und dort der nodeValue ausgelesen werden – vielmehr wird das Tag
direkt angesprochen und so der Wert ermittelt.
u
u
u
u
K A P I T E L 6334
Textknoten mit mehreren Textteilen
In den obigen Überlegungen haben wir gesehen, dass man den Inhalt eines Knotens direkt über
den Zugriff auf den Knoten erhält: XMLObjekt.Knoten liefert den Inhalt des Knotens. Sollten
sich innerhalb dieses Knotens jedoch weitere Knoten befinden, so werden diese als Ganzes aus-
gelesen. Sollten Sie nur auf die Textteile eines Knotens zugreifen wollen, so geschieht dies über
die Methode text, also etwa: XMLObjekt.Knoten.text() liefert den gesamten Text eines
Knotens zurück. Sollte dieser Text wiederum durch Knoten unterbrochen sein, so erhalten Sie ein
Array an Textteilen.
Ein kleines Beispiel:
var myXML:XML = new XML("<p>Text 1.<br />Text 2</p>");
trace(myXML.text()[0]); //liefert "Text 1."
trace(myXML.text()[1]); //liefert "Text 2"
trace(myXML.text()); //liefert Text1.Text2
Da <p> der äußerste Knoten ist, wird dieser nicht explizit angegeben. Anders würde es sich
verhalten, wenn <p> in ein <body> verschachtelt wäre – dann muss man das <p> explizit
angeben (Thema Hierarchie):
var myXML:XML = new XML("<body><p>Text 1.<br />Text 2</p></body>");
trace(myXML.p.text()[0]); //liefert "Text 1"
trace(myXML.p.text()[1]); //liefert "Text 2"
trace(myXML.p.text()); //liefert Text1.Text2
Weitere sehr interessante Eigenschaften sind in nachfolgender Liste zu sehen:
length liefert nach wie vor die Anzahl von vorkommenden Knoten eines bestimm-
ten Namens. Beispielsweise würde myXML.Playliste.length die Anzahl der vor-
kommenden Tags <Playliste> liefern (in unserem Fall wäre das Ergebnis drei).
Bitte beachten Sie jedoch, dass length nun eine Methode und keine Eigenschaft
darstellt:
myXML.Playliste.length(); //liefert: 3
Mittels zweier Punkte „..“ kann man ein bestimmtes Tag (einen bestimmten Kno-
ten) in beliebiger Hierarchietiefe ansprechen:
myXML..Song[2];
Diese Anfrage würde folgendes Ergebnis liefern:
<Song pos="5" useID3="0">
<Titel>Numb</Titel>
<Interpret>Linkin Park</Interpret>
<Src>Numb.mp3</Src>
</Song>
Listing 6.61: Die Anfrage für den dritten Song-Knoten (Song[2] – wir beginnen ja wie gewohnt bei Null
zu zählen) liefert den gesamten Inhalt dieses Knotens. Bitte vergleichen Sie die Ausgabe mit dem Inhalt der
XML-Quelle aus Listing 6.59.
u
u
SERVERSEITIGER DATENAUSTAUSCH – FLASH, PHP & DATENBANK 335
Eine sehr interessante Funktion ist eine Art „Suchfunktion“ innerhalb der XML-
Daten: Über einen Vergleich kann auf bestimmte Knoten oder Attribute mit
bestimmten Werten zugegriffen werden:
Zugriff auf einen (beliebigen) Song-Knoten, wo das pos-Attribut den Wert 1
besitzt: myXML..Song.(@pos=="1");
Zugriff auf einen (beliebigen) Titel-Knoten mit Textinhalt gleich „Be a Warri-
or“: myXML..Titel.(text()=="Be a Warrior");
Solche Vergleiche können auch (nach den bekannten Verknüpfungs-
regeln) verknüpft werden: myXML..Titel.(text()=="Be a Warrior" ||
text()=="Numb");
u
u
u
Ich hoffe, ich habe Ihnen das neue XML-Objekt schmackhaft machen können. Trotz
aller Vorteile möchte ich an dieser Stelle trotzdem noch einmal konkret auf die Tatsa-
che hinweisen, dass das Flash-Dokument nun mit ActionScript 3.0 aufgebaut werden
muss, und dies bedarf schon einer gründlichen Einarbeitung in diese Sprache! Aus
diesem Grund möchte ich Ihnen erneut die entsprechende Literatur zu ActionScript
3.0 ans Herz legen:
Selma-Caroline und Matthias Kannengießer: ActionScript 3.0. 1. Auflage. Bonn: Addi-
son-Wesley 2007, ISBN 978-3827325365
Auch ist die ActionScript 3.0-Referenz in Flash eine sehr gute Quelle und ein unschätz-
bares Nachschlagewerk!
ABBILDUNG 6.48
Die Ausgabe aller unserer
Anweisungen in einer
TextArea. XML goes
ActionScript 3.0.
7
AUDIO-JUKEBOX
Dieses und die folgenden Kapitel widmen sich ausschließlich
der Praxis. Hier sollen Sie sehen, auf welche Arten wir uns ein
Zusammenspiel von Flash und PHP vorstellen.
Anwendungsbeispiele gibt es wohl wie Sand am Meer, Ideen
und Vorstellungen zu Anwendungen noch viele mehr. Aus
diesem Grund werden Sie auch zu diesem Buch gegriffen
haben. Die serverseitige Programmierung als (hauptsächlicher)
Datenlieferant auf der einen Seite, Flash als das Animations-
und Multimedia-Tool auf der Clientseite.
Zu den gängigsten Aufgabengebieten finden Sie im Folgenden
konkret durchgeplante und durchprogrammierte Übungen.
Ich habe in allen Workshops die Flash- und die PHP-Entwick-
lung strikt getrennt, sodass Sie ein Optimum an Übersicht
genießen können.
Die Audio-Jukebox wird zunächst in ActionScript 2.0 und spä-
ter in ActionScript 3.0 entwickelt.
Viel Spaß beim Umsetzen und Anwenden!
K A P I T E L 7338
7.1 Abfragen serverseitiger Informationen
Eine Variante, sich PHP für Flash zunutze zu machen, liegt in der simplen Abfrage von
Daten aus einer Datenbank oder einem Filesystem. Dieses Kapitel widmet sich genau
dieser Thematik. Als konkrete Anwendungen habe ich an dieser Stelle bevorzugt an
multimediale Anwendungen gedacht, da sie im Allgemeinen keine Rückgaben an den
Server erfordern.
7.2 Multimediale Anwendungen
Was ist Multimedia? Multimedia ist das Verwenden verschiedener Ausgabemedien zur
selben Zeit. Hierzu zählt man Inhalte wie Text, Audio, Video usw. Je mehr dieser Assets
zur gleichen Zeit ausgegeben werden, desto interessanter gestaltet sich die Entwicklung
in Flash. Einmal ganz ehrlich – kennen Sie ein Tool, das besser für Multimedia auf
Clientseite geeignet ist als Flash? Wohl kaum.
7.3 Konzept der Jukebox
Als erstes Beispiel dient dabei mein persönlicher Favorit. Kaum eine andere Anwen-
dung hat mir in der Verwendung wie in der Entwicklung mehr Freude bereitet.
Am Anfang steht das Entwickeln eines Konzepts, also mehr oder weniger die Antwort
auf die Frage: „Was soll das Tool eigentlich können?“ Hier die Anforderungen an unse-
re Audio-Jukebox aus Flash-Sicht:
1. Die Audio-Jukebox soll in der Lage sein, gestreamt MP3-Dateien abzuspielen.
Somit ist die erste Anforderung, dass MP3-Dateien dynamisch in Flash eingelesen
werden sollen.
2. Innerhalb der Jukebox soll volle Kontrolle über das Abspielen der Songs
gewährleistet sein. Dies schließt Buttons für: „Start“, „Stopp“, „Ein Song weiter“
und „Ein Song zurück“ ein. Des Weiteren muss die Lautstärke regelbar sein.
3. Die gängigen Informationen zu den Songs sollen direkt aus den ID3-Tags der
MP3-Dateien ermittelt und ausgegeben werden.
4. Die Restabspielzeit zum jeweiligen Song soll ausgegeben werden.
5. Es soll eine parametergesteuerte Autostart-Möglichkeit vorhanden sein.
7.3.1 Playlist generieren
Grundsätzlich stellt sich natürlich die Frage, wie Flash zu den Songs kommt, also
woher die Playlist kommt bzw. wer sie generiert und wie sie eingelesen wird. Unser
ID3-Tags
Die ID3-Tags sind
(benannte) Informationen
wie „Titel“, „Interpret“,
„Album“ usw., die mit der
MP3-Datei gespeichert
werden können. Geeignete
Programme – wie auch
Flash – können diese Tags
auslesen.
A U D I O - J U K E B O X 339
Plan soll sein, dass sämtliche in einem Verzeichnis aufgelisteten MP3-Dateien verwen-
det werden. Eine auf diese Art erzeugte Playlist soll per Aufruf von Flash eine XML-
Datei generieren, die Flash wiederum einliest.
XML-Struktur
Aus Sicht von Flash ist es vollkommen irrelevant, „wer“ (der Webdesigner in Form
einer Textdatei, ein Server basierend auf PHP-Code usw.) und auf welche Art die
Playlist als XML-Datei generiert wird – Hauptsache, die Struktur ist bekannt und die
XML-Daten stehen zur Verfügung. Punkt eins ist also, dass die Struktur der XML-
Datei feststehen muss.
Abbildung 7.1 verdeutlicht, wie die Informationen an die Flash-Anwendung überge-
ben werden sollen. Neben den Tags für die einzelnen Songs wird in zwei Attributen
festgelegt, welches das Stammverzeichnis der Songs ist (rootDir) und ob ein Autostart
– also ein automatisches Abspielen der Playlist – stattfinden soll (autostart). Wird
die Variable autostart auf 0 gesetzt, so findet kein Autoplay statt, steht sie hingegen
auf 1, erfolgt das Abspielen der Playlist automatisch.
Flash-Datei vorbereiten
Gehen wir’s an. Zunächst gliedern wir die Flash-Datei in drei gedachte Bereiche:
Im ersten Bereich soll das Laden der XML-Daten erfolgen.
Der zweite Bereich ist dafür gedacht, dem User eine Fehlermeldung auszugeben,
sollte das Laden der XML-Daten nach einer gewissen Zahl von Wiederholungen
nicht möglich gewesen sein.
Der dritte Bereich stellt die eigentliche Jukebox dar. Dort befinden sich die Abspiel-
steuerung und die Informationsdarstellung der MP3-Daten.
u
u
u
ABBILDUNG 7.1
Auf diese Art und Weise wer-
den die MP3-Informationen
an die Flash-Datei überge-
ben. XML is on its way.
K A P I T E L 7340
7.4 Jukebox in ActionScript 2.0
Nachdem diese Vorkehrungen getroffen sind, konzentrieren wir uns nun wirklich auf
das Programmieren. Zunächst muss definiert werden, aus welcher Datei die Playlist
geladen werden soll – hierzu bedienen wir uns einer Stringvariablen namens mySource,
die den Namen (oder auch eine komplette URL inklusive eventueller Unterverzeich-
nisse) der Playlist-Datei speichert. Des Weiteren legen wir – wie auch schon in den
Theoriekapiteln gezeigt – in einer Variable maxLadeversuche eine gewisse Anzahl an
Ladeversuchen fest, sollte das Laden der Daten nicht beim ersten Mal klappen. Hierzu
muss in weiteren Variablen mitgezählt werden, wie viele Ladeversuche bereits vorge-
nommen wurden. Dies übernimmt die Variable anzLadeversuche.
var anzLadeversuche:Number = 0;
var maxLadeversuche:Number = 3;
var mySource:String = "playlist.php";
Listing 7.1: Die ersten drei wichtigen Variablen für die mitgezählte Anzahl an Ladeversuchen (anzLade-
versuche), die maximale Anzahl an Ladeversuchen (maxLadeversuche) und die URL zur Playlist-Datei
(mySource) sind somit angelegt.
Neben den oben angeführten Variablen werden wir im Weiteren noch einige zusätz-
liche globale Variablen benötigen, nämlich ein Array, das alle unsere eingelesenen
Songs speichert (theSongs), zwei Variablen für die Ausgabe von Informationen zu
den Songs in dynamischen Textfeldern (theSongInfo1, theSongInfo2) sowie eine
Variable für die Darstellung der verbleibenden Abspielzeit, ebenfalls in einem dyna-
mischen Textfeld (theTimeInfo).
var theSongs:Array = new Array();
var songTitel:String = "loading Playlist...";
var songInterpret:String = "";
var songAlbum:String = "";
var theTimeInfo:String = "--:--";
Listing 7.2: Anlegen einiger wesentlicher Variablen, die wir für den weiteren Ablauf der Jukebox benötigen
werden
Natürlich müssen die Variablen songTitel, songInterpret, songAlbum und the-
TimeInfo nicht notwendigerweise genau zu diesem Zeitpunkt angelegt werden. Dies
empfiehlt sich jedoch, da man (als guter Programmierer) davon ausgehen kann, dass
man bis zum Abspielen der Songs kommt und somit diese Variablen auch benötigen
wird.
A U D I O - J U K E B O X 341
7.4.1 XML-Daten laden
Nun kümmern wir uns darum, dass die XML-Daten geladen werden können. Das
Flash-Objekt XML wird diese Aufgabe für uns erledigen. Obwohl wir keine leeren
Textknoten zu erwarten haben, ist das Setzen der Eigenschaft ignoreWhite des XML-
Objekts auf den Wert true eine gute Wahl, denn so kann diese mögliche Fehlerquelle
ausgeschlossen werden.
var myLoader:XML = new XML();
myLoader.ignoreWhite = true;
myLoader.load(mySource);
Listing 7.3: Es wird ein neues XML-Objekt erzeugt, die Eigenschaft ignoreWhite auf true gesetzt und
von der zuvor definierten URL (mySource) werden XML-Daten eingelesen.
Über das Ereignis onLoad des XML-Objekts wird signalisiert, dass das Laden der Daten
abgeschlossen ist. Dies bedeutet aber noch nicht, dass das Laden auch erfolgreich war.
Das erfolgreiche Laden signalisiert erst die Eigenschaft loaded. Dies bedeutet für uns,
dass wir zunächst das Ereignis onLoad auswerten (wir erzeugen eine sogenannte Ereig-
nisroutine oder Ereignisprozedur) und danach abprüfen müssen, ob die Eigenschaft
loaded auf true gesetzt ist. Sollte dem nicht so sein, wird ein erneuter Ladeversuch
gestartet. Das Definieren der Ereignisroutine muss kein zweites Mal vorgenommen
werden, da beim erneuten Ladeversuch dasselbe XML-Objekt ein weiteres Mal verwen-
det wird. In jedem Fall wird die Variable anzLadeversuche um eins erhöht.
myLoader.onLoad = function():Void {
anzLadeversuche++;
if(myLoader.loaded) {
//Hier folgt das Auslesen der Attribute und Tags.
//Der Code wird weiter unten erläutert.
}
else {
if(anzLadeversuche<maxLadeversuche) { myLoader.load(mySource); }
else {
//Code, falls Anzahl der Ladeversuche erreicht ist
}
}
}
Listing 7.4: Die Ereignisbehandlungsroutine wertet die Daten bei erfolgreichem Laden aus, bei nicht
erfolgreichem Laden wird – sofern die Maximalanzahl an Ladeversuchen noch nicht erreicht ist (also
anzLadeversuche<maxLadeversuche) – ein erneuter Ladeversuch gestartet. Ansonsten müssen wir
uns etwas einfallen lassen.
onLoad versus
loaded
onLoad versus
loaded
K A P I T E L 7342
Attribute speichern
War das Laden erfolgreich (und davon gehen wir einmal aus), werden zunächst alle im
zweiten Tag (<Playlist>; siehe Abbildung 7.1) vorkommenden Attribute als globale
Variablen gespeichert.
Eine for..in-Schleife empfiehlt sich hier: Alle im Objekt attributes vorkom-
menden Eigenschaften (hier: Variablen) werden ausgelesen und durch die Funktion
_global in die Kollektion der globalen Variablen übernommen.
Danach werden alle folgenden Tags angesprochen und das Attribut src wird aus-
gelesen. In diesem befinden sich die Namen der MP3-Dateien. Vergleicht man den
nachfolgenden Code mit der Abbildung der einzulesenden XML-Datei, so sieht man,
dass das erste Child <Playlist> des Hauptknotens <?xml> eine gewisse Anzahl wei-
terer Child-Knoten umfasst (die Tags <song>). Wie viele es sind, lässt sich über die
Eigenschaft length dieser childNodes-Sammlung herausfinden. Diese Information
verpackt man in eine for-Schleife, liest Zug um Zug jedes Tag und dessen Attribut src
aus und speichert die ermittelten Werte im globalen Array theSongs.
Ist dieser Schritt vollzogen, ist sämtliches Einlesen der XML-Daten abgeschlossen und
es kann mit dem weiteren Gang der Jukebox fortgefahren werden.
//Dieses Code-Fragment wird an oben erwähnter Stelle eingefügt
for(itm in myLoader.firstChild.attributes) {
_global[itm] = myLoader.firstChild.attributes[itm];
}
for(var i:Number=0; i<myLoader.firstChild.childNodes.length; i++) {
theSongs[i] = myLoader.firstChild.childNodes[i].attributes.src;
}
Listing 7.5: Das Auswerten und Speichern der eingelesenen Daten erfolgt in diesem Codefragment. Sobald
dieses Prozedere abgeschlossen ist, ist der wesentlichste Schritt getan und es kann mit dem Abspielen der
Songs begonnen werden.
Für den Fall, dass der Ladevorgang nicht erfolgreich beendet werden konnte und
auch die weiteren Ladeversuche zu keinem positiven Ergebnis geführt haben, wird ein
MovieClip eingeblendet, der eine entsprechende Fehlermeldung auf den Bildschirm
ausgibt. Ob Sie hier nun dem User die Meldung ausgeben, dass das Laden nicht
geklappt hat, oder zusätzlich einen Button einfügen, der bei Klick einen neuerlichen
Ladezyklus einleitet, hängt von Ihrem persönlichen Geschmack ab. Wir sind der
Ansicht, dass sofern drei Ladeversuche fehlgeschlagen sind, ein weiterer Ladezyklus
auch keinen Sinn mehr macht. Natürlich ist es aber Ihnen überlassen, ob Sie diese
Möglichkeit in Betracht ziehen wollen oder nicht.
Ich habe mich für die Variante „Fehlermeldung & Buttons zum Neuladen“ entschie-
den, die wie folgt aussehen könnte:
A U D I O - J U K E B O X 343
Hierzu legt man einen MovieClip mcError an, der zwei Buttons (btnNein, btnJa)
beinhaltet, und platziert ihn der Einfachheit halber neben der Bühne (quasi im
unsichtbaren Bereich – siehe Abbildung 7.3). Um den MovieClip mcError gleich „am
richtigen Platz“ zu haben, sollte er eingeblendet werden müssen, fügt man folgenden
Code in der Aktionenebene ein:
mcError._visible = false;
mcError._x = 0;
mcError._y = 0;
ABBILDUNG 7.2
Der User erhält eine
Fehlermeldung sowie
die Möglichkeit, den
Ladevorgang erneut
einzuleiten.
ABBILDUNG 7.3
Der MovieClip mcError wird
im unsichtbaren Bereich
neben der Bühne platziert.
Sollte die Anzahl der Ladeversuche erreicht sein (siehe Listing 7.4), fügt man folgenden
Code ein:
K A P I T E L 7344
...
if(anzLadeversuche<maxLadeversuche) { myLoader.load(mySource); }
else { mcError._visible = true; }
...
Listing 7.6: Die Zeile mcError._visible = true; wird dem Code aus Listing 7.4 hinzugefügt.
Nun verschaffen wir den beiden Buttons noch etwas „Intelligenz“, indem wir Ihnen
den Code zuweisen, den sie auslösen sollen:
mcError.btnNein.onRelease = function():Void {
_root.mcError._visible = false;
_root.songTitel = "ERROR WHILE LOADING PLAYLIST";
}
mcError.btnJa.onRelease = function():Void {
_root.myLoader.load(mySource);
_root.mcError._visible = false;
}
Listing 7.7: Die Eventhandler der Buttons btnNein und btnJa
Wird der Nein-Button geklickt, blenden wir den MovieClip mcError aus und geben in
den Textfeldern eine Fehlermeldung aus, im Fall des Ja-Buttons wird zusätzlich noch
der Ladevorgang erneut gestartet.
7.4.2 Abspielen der Songs
Befassen wir uns also nun mit dem wichtigen Thema des Abspielens der Songs. An
dieser Stelle ist wieder etwas Konzept vonnöten. Überlegen wir uns, wie das Anwenden
der Jukebox vonstatten gehen soll:
1. ÜberdieglobaleVariableautostart wirdentschieden,obderersteSongabgespielt
oder auf das Klicken des Play-Buttons durch den User gewartet werden soll.
2. Mithilfe der Buttons „Start“, „Stopp“, „Ein Song vor“, „Ein Song zurück“ soll man
die Playlist abspielen und stoppen können. Des Weiteren wären kleine Icons (eines
für jeden Song) nett, die bei Klick den Song gleich direkt aufrufen und abspielen.
3. Ein Lautstärkeregler muss ebenso vorhanden sein wie zwei Informationsfelder,
eines zum abgespielten Song und eines zum Darstellen der verbleibenden
Abspielzeit.
So weit der Plan. Programmiertechnisch ergeben sich hieraus vorerst einige wesent-
liche Konsequenzen:
A U D I O - J U K E B O X 345
1. Klarerweise wird ein Soundobjekt benötigt, um überhaupt Songs abspielen zu
können.
2. In jedem Fall müssen wir uns merken, der wievielte Song aus unserer Songliste des
Arrays theSongs zu einem gewissen Zeitpunkt abgespielt wird. Hierfür werden
wir eine Variable actualSong verwenden, die auf den Index des Arrays theSongs
zeigt.
Variablen für die Jukebox
Die beiden Punkte werden uns die wenigsten Kopfschmerzen bereiten, sind sie doch
mit wenigen Zeilen erledigt.
var mySong:Sound = new Sound();
var actualSong:Number = 0;
Listing 7.8: Anlegen der beiden Variablen mySong (Soundobjekt) und actualSong im Bild Ladevor-
gangErfolgreich in der Ebene „Aktionen“
Autostart der Songs
Widmen wir uns wieder den einfacheren Aufgaben, nämlich dem Auswerten der
autostart-Variable. Wie schon weiter oben angesprochen, wird im Fall von auto-
start==1 der erste Song (entspricht dem Wert von actualSong) abgespielt, indem
die Funktion playSong aufgerufen wird. Auf diese Funktion wird weiter unten einge-
gangen. Ansonsten wird im oberen der beiden dynamischen Textfelder der Text „press
the PLAY-Button to play songs …“ ausgegeben. Das zweite Textfeld bleibt nach wie
vor leer.
Um diesen Vorgang in Gang zu setzen, muss zunächst in Listing 7.5 nach dem Auslesen
der XML-Daten der Aufruf der Funktion initPlayer eingefügt werden:
initPlayer();
Diese Funktion erledigt dann die oben genannten Aufgaben:
function initPlayer():Void {
if(parseInt(autostart)==1) { playSong(0); }
else {
theSongInfo1 = "(press the PLAY-Button to play songs...)";
}
}
Listing 7.9: Die if-Bedingung entscheidet über autostart==1 darüber, ob der erste Song abgespielt
wird oder ob bei autostart!=1 gewartet und eine entsprechende Meldung übergeben werden soll.
K A P I T E L 7346
Hauptfunktion der Jukebox: playSong()
Wenden wir uns nun der Funktion playSong zu, die einen wesentlichen Bestandteil
der Jukebox darstellt. Wie bereits im letzten Listing gezeigt, wird an diese Funktion ein
noch nicht näher beschriebener Parameter übergeben. Dieser Parameter wird verwen-
det, um genau um den Wert dieses Parameters in der Liste der Songs weiterzuspringen.
Dabei kann dieser Parameter drei Werte annehmen, wie Sie der nachfolgenden Tabelle
entnehmen können:
Wert Bedeutung
0 Zum aktuellen Songindex (actualSong) wird der Wert 0 hinzugezählt und dieser Song abge-
spielt.Dies bedeutet also nichts anderes,als dass der aktuelle Song erneut abgespielt wird.
1 Zum aktuellen Songindex (actualSong) wird der Wert 1 hinzugezählt und dieser Song abge-
spielt.Es wird demnach in der Liste der Songs (theSongs) um einen Song weitergesprungen.
Was geschehen soll,wenn das Ende der Liste erreicht ist,muss noch definiert werden.
-1 Zum aktuellen Songindex (actualSong) wird der Wert -1 hinzugezählt und dieser Song ab-
gespielt.Es wird demnach in der Liste der Songs (theSongs) um einen Song zurückgesprun-
gen.Was geschehen soll,wenn der Anfang der Liste erreicht ist,muss noch definiert werden.
Tabelle 7.1: Mögliche Übergabewerteparameter der playSong-Funktion
Anfang und Ende der Playlist
Innerhalb der Funktion playSong wird der Parameter als numerische Variable mit
dem Namen dir (für „direction“ – Richtung) geführt. Was soll nun geschehen, wenn
entweder das Ende oder der Anfang der Songliste überschritten wird? Wir haben uns
entschieden, dass bei Überschreiten des Listenendes an den Anfang der Liste und bei
Überschreiten des Listenanfangs an das Ende der Liste gesprungen werden soll.
Das Überschreiten des Listenendes erkennt man daran, dass der Listenindex von
actualSong gleich der Länge der Liste ist – die Zählung der Listeneinträge im Array
beginnt ja bekanntlich bei 0. Das Überschreiten des Listenanfangs erkennt man wie-
derum daran, dass der Index den Wert -1 hat: actualSong==-1.
Songindex auslesen
Hat die Variable actualSong schlussendlich den gewünschten Wert erhalten, kann
mit dem Laden des entsprechenden Songs aus der Liste begonnen werden. Man
liest hierfür aus der Playlist theSongs den Wert aus, der über den Index actual-
Song definiert ist: theSongs[actualSong]. Vor diesen Eintrag hängt man noch das
Stammverzeichnis der Songs und einen Slash „/“. Das Stammverzeichnis wird über die
globale Variable rootDir definiert, die aus der XML-Datei eingelesen wird, und ohne
schließendes „/“ angegeben.
Fertig ist die URL, von der Flash die Songdatei beziehen soll. Die Methode loadSound
des Soundobjekts erwartet diese URL als ersten Parameter sowie eine Kennzeichnung,
ob (true) oder ob die Datei nicht (false) gestreamt geladen werden soll, als zweiten
Parameter:
mySong.loadSound("URL", isStreaming)
A U D I O - J U K E B O X 347
Das nachfolgende Listing zeigt Ihnen einen Auszug der Funktion playSong, worin die
soeben dargestellten Aufgaben erledigt werden. Das vollständige Listing wird am Ende
dieses Abschnitts aufgeführt.
function playSong(dir:Number) {
...
actualSong += dir;
if(actualSong==theSongs.length) { actualSong = 0; }
if(actualSong==-1) { actualSong = theSongs.length-1; }
mySong.loadSound(rootDir+"/"+theSongs[actualSong],true);
...
}
Listing 7.10: Codefragment zum Setzen der Variable actualSong und Laden des entsprechenden Songs
aus der Playlist theSongs
Zwischen zwei Songs
Bevor jedoch die MP3-Datei geladen wird, sind noch ein paar „administrative“ Punkte
zu regeln:
1. Zwischenzeitlich(bisderneueSonggestartetist)sollkeineRestabspielzeitangezeigt
werden, sondern etwas in der Art „--:--“:
theTimeInfo="--:--";
2. Gleiches gilt auch für die zwei Informationszeilen am Display:
songTitel = "getting MP3-Information...";
songInterpret = "";
songAlbum = "";
Somit erweitert sich die Funktion playSong um folgenden Code:
function playSong(dir:Number):Void {
theTimeInfo = "--:--";
songTitel = "getting MP3-Information...";
songInterpret = "";
songAlbum = "";
...
}
Listing 7.11: Codefragment zum Erledigen der „administrativen“ Angelegenheiten.
K A P I T E L 7348
Das vollständige Script zur Funktion playSong sieht somit wie folgt aus:
function playSong(dir:Number):Void {
theTimeInfo = "--:--";
songTitel = "getting MP3-Information...";
songAlbum = "";
songInterpret = "";
actualSong += dir;
if(actualSong==theSongs.length) { actualSong = 0; }
if(actualSong==-1) { actualSong = theSongs.length-1; }
mySong.loadSound(rootDir+"/"+theSongs[actualSong],true);
}
Listing 7.12: Die Funktion playSong in all ihrer Pracht!
Song beendet: nächsten Song abspielen
Nun müssen wir uns noch überlegen, was zu geschehen hat, wenn der nun abgespielte
Song zu Ende ist. Wir haben uns entschieden, nach einem fertig abgespielten Song
ganz einfach den nächsten Song in der Liste abzuspielen. Die Methode onSoundCom-
plete des Soundobjekts wird genau dann aktiv, wenn ein Song komplett wiedergege-
ben wurde. Nichts ist leichter, als zu diesem Zeitpunkt den nächsten Song in der Liste
abzuspielen, denn die dafür erforderliche Funktion haben wir bereits: playSong(1).
Der Wert 1 als Übergabeparameter teilt der Funktion mit, dass das nächste Lied der
Liste abgespielt werden soll.
mySong.onSoundComplete = function() {
playSong(1);
}
Listing 7.13: Codefragment für die Ereignisbehandlung von onSoundComplete, die direkt nach dem
Anlegen der Sound-Instanz mySong definiert werden kann.
Songs per Klick abspielen
Neben dem Abspielen des vorigen, aktuellen oder nächsten Songs soll eventuell auch
noch die Möglichkeit bestehen, einen Song direkt anzuwählen. Dafür ist unsere Funk-
tion playSong jedoch nicht ausgelegt – hierzu müsste man eine eigene Funktion pro-
grammieren, wo etwa die Songs in einer ComboBox aufgelistet werden. Kein Problem
für uns – öffnen Sie die Datei audioplayer_03.fla von der Buch-CD – die Erklärung
finden Sie weiter unten im Kapitel, da diese Variante in ActionScript 3.0 umgesetzt
wurde.
A U D I O - J U K E B O X 349
7.4.3 ID3-Tags auslesen
Abschließend sollte man bei Auswahl eines neuen Songs natürlich auch die entspre-
chenden Informationen zu ihm erhalten. Wurde beim Aufnehmen der MP3-Daten
darauf geachtet, dass die Informationen zum Album mitgespeichert werden, so werden
diese Informationen beim Aufnehmen mit in die MP3-Datei„verpackt“ und sind somit
zu jeder Zeit verfügbar. Im Allgemeinen geschieht dies entweder durch automatisiertes
Abfragen einer Datenbank (beispielsweise CDDB) durch Ihr Aufnahmeprogramm
oder durch händisches Eingeben der Informationen vor der Aufnahme.
Da alle gängigen Aufnahmeprogramme wie zum Beispiel iTunes von Apple oder
die Jukebox von MusicMatch (Yahoo) nach diesem Verfahren arbeiten, können
wir Entwickler davon ausgehen, dass auch unsere MP3-Daten diese Informationen
gespeichert haben. Flash kann – wie sollte es auch anders sein – auf diese Informa-
tionen zugreifen. Hierzu existiert für ein Soundobjekt das Sub-Objekt id3, dessen
Eigenschaften genau die gewünschten Daten beinhaltet. Man nennt diese MP3-Infor-
mationen auch die „ID3-Tags“, deshalb auch der Objektname id3. Die für uns interes-
santen Eigenschaften sind in der folgenden Tabelle zusammengefasst. Eine komplette
Auflistung aller Eigenschaften finden Sie in der ActionScript-Referenz, die Sie von der
Macromedia-Site downloaden können: http://www.macromedia.com/support/
documentation/de/flash/. Alternativ dazu könnte man natürlich die notwen-
digen Informationen zum Song in die XML-Datei aufnehmen, da man – möchte man
absolut sichergehen – nicht zu 100% davon ausgehen kann, dass die ID3-Tags wirklich
in der MP3-Datei gespeichert sind.
Tag Enthaltene Information
id3.artist Name des Interpreten
id3.songname Songtitel
id3.album Name des Albums
id3.TLEN Länge des Songs (in
Millisekunden)
Tabelle 7.2: Auflistung der für unsere Jukebox interessanten
Eigenschaften des id3-Objekts der Version 1
Neben den hier dargestellten id3-Tags existieren noch weitere, die einer neueren
Generation angehören. Sie sind in Flash unter der Bezeichnung id3 Version 2 zu finden
– genauere Informationen hierzu entnehmen Sie bitte der Flash-Referenz.
In der ersten Zeile des Displays sollen die Informationen zum Titel in Zeile 2 und in
Zeile 3 die Infos zu Interpret und dem Albumtitel stehen. Wie diese Informationen in
die dynamischen Textfelder gelangen, wird hier nicht gesondert erläutert. Sollten Sie
dazu Fragen haben, schauen Sie sich den Code am besten direkt in der fla-Datei von
der Buch-CD an.
K A P I T E L 7350
Da die ID3-Informationen nicht sofort zur Verfügung stehen, sondern erst dann, wenn
ein gewisser Teil der MP3-Datei geladen ist, müssen wir ein Ereignis abwarten, das uns
das Vorhandensein dieser Informationen anzeigt: onID3.
mySong.onID3 = function():Void {
songInterpret = mySong.id3.artist;
songAlbum = mySong.id3.album;
songTitel = mySong.id3.songname;
showTimer(Math.floor(mySong.id3.TLEN/1000));
}
Listing 7.14: Codefragment zum Einlesen und Ausgeben der ID3-Informationen
Restspielzeit anzeigen
Die Darstellung der Restspielzeit gestaltet sich dabei auch etwas aufwändiger – hier
werden wir eine eigene Funktion aufrufen, in der wir mit einem Intervall arbeiten.
Dieser Funktion (showTimer) übergeben wir primär die Länge des Songs in Sekun-
den, weshalb eine Division durch 1000 und eine Rundung des Ergebnisses erforderlich
ist. Alles weitere passiert dann innerhalb dieser Funktion.
Idealerweise realisiert man dies mithilfe der Methode setInterval. Wie in der Funk-
tion playSong ersichtlich, wird in der Ereignisbehandlungsroutine des Ereignisses
onID3 die Funktion showTimer wie folgt aufgerufen:
showTimer(Math.floor(mySong.id3.TLEN/1000));
Der Übergabewert an showTimer ist die (abgerundete) Länge des MP3-File und wird
innerhalb der Funktion in der Variable theLength gespeichert. Sobald die Funktion
showTimer aufgerufen wird, wird zunächst ein (bis dato noch nicht verwendetes)
Intervall gelöscht: clearInterval(itvTimer). Der Grund dafür ist, dass im Wei-
teren über showTimer jede Sekunde dasselbe Intervall erneut gestartet wird, das
wiederum die Funktion showTimer mit einem genau um eine Sekunde verminderten
Wert für den Parameter aufruft.
Letzten Endes wird hier nicht die Funktionsweise des Intervalls, sondern vielmehr die
eines Timers verwendet. Sollte theLength>=0 sein – also das Lied noch nicht zu Ende
sein –, wird der Wert für die Restabspielzeit wie folgt berechnet:
1. Zunächst werden die Minuten ermittelt: Hierzu dividiert man die Restzeit in
Sekunden durch 60 und rundet ab:
theTimeInfo = "-"+Math.floor(theLength/60)+":";
Vor diesen Wert wird noch ein „–“ (Minus) gesetzt, um die Restdauer anzudeuten.
Hinter den Minutenwert wird ein Doppelpunkt gesetzt.
A U D I O - J U K E B O X 351
2. Danach werden die restlichen Sekunden ermittelt, indem man den Minutenwert
mit 60 multipliziert und diesen Wert von den Gesamtsekunden (theLength)
abzieht:
theLength-60*Math.floor(theLength/60)
Sollte dieser Wert kleiner als zehn sein, so sollte man der Sekundenanzeige eine
Null vorsetzen („09“ wirkt besser als „9“):
if(theLength-60*Math.floor(theLength/60)<10) { theTimeInfo += "0"; }
DerSekundenwertwirdschlussendlichauchnochandenbeinaheschonkompletten
String für die Ausgabe angehängt:
theTimeInfo += theLength-60*Math.floor(theLength/60);
3. Nur zur Erinnerung: Die globale Variable theTimeInfo ist diejenige Variable, die
im dynamischen Textfeld für die Restabspielzeit ausgegeben wird. Abschließend
muss das Intervall nur noch erneut aufgerufen werden:
itvTimer = setInterval(showTimer,1000,theLength-1);
Das vollständige Listing der Funktion showTimer sieht wie folgt aus:
function showTimer(theLength:Number):Void {
clearInterval(itvTimer);
if(theLength>=0) {
theTimeInfo = "-"+Math.floor(theLength/60)+":";
if(theLength-60*Math.floor(theLength/60)<10) { theTimeInfo += "0"; }
theTimeInfo += theLength-60*Math.floor(theLength/60);
itvTimer = setInterval(showTimer,1000,theLength-1);
}
}
Listing 7.15: Das vollständige Listing der Funktion showTimer
7.4.4 Abspielsteuerung
Erfreulicherweise haben wir alle aufwändigeren Codes hinter uns gebracht und kön-
nen uns nun einer einfacheren Funktion widmen: der Funktion stopSound, die für
das Stoppen eines gerade abgespielten Songs verantwortlich ist. Dies geschieht über die
einfache Methode stop() des Soundobjekts: mySong.stop();. Gleichzeitig mit dem
Stoppen des Songs müssen noch zwei weitere Aufgaben erledigt werden:
Das laufende Intervall muss gelöscht werden:
clearInterval(itvTimer);
K A P I T E L 7352
Das Display muss aktualisiert werden:
theTimeInfo = "--:--";
theSongInfo1 = "(stopped)";
theSongInfo2 = "";
Erledigt. Abschließend noch das Listing:
function stopSong():Void {
mySong.stop();
clearInterval(itvTimer);
theTimeInfo = "--:--";
songTitel = "(stopped)";
songInterpret = "";
songAlbum = "";
}
Listing 7.16: Code der Funktion stopSong
Kommen wir zu den Buttons, also der Abspielsteuerung unserer Jukebox. Sie werden
sehen, dass die Buttons mit Sicherheit die einfachste Aufgabe darstellen:
Button „Play“:
btnPlay.onRelease = function():Void {
playSong(0);
}
Button „Stopp“:
btnStop.onRelease = function():Void {
stopSong();
}
Button „Ein Song zurück“:
btnRWD.onRelease = function():Void {
playSong(-1);
}
Button „Ein Song vor“:
btnFWD.onRelease = function:Void {
playSong(1);
}
u
u
u
u
A U D I O - J U K E B O X 353
7.4.5 Lautstärkeregler
Sie denken, wir hätten damit das Ende erreicht? Beinahe. Bleibt einzig noch der Laut-
stärkeregler, der eigentlich ganz simpel zu programmieren ist. Aber zunächst einige
Gedanken zur Funktionsweise:
1. Durch Klicken auf die Spur des Reglers soll die Lautstärke auf den entsprechenden
Wert gesetzt werden.
2. Die Lautstärke soll mit der Maus per Drag&Drop gesetzt werden können, wobei
sich während des Ziehens die Lautstärke kontinuierlich verändern soll.
Diese aufgelisteten Punkte werden uns zum Ende hin noch einmal ein wenig schwitzen
lassen, aber dafür haben wir es dann geschafft – zumindest in Flash.
ABBILDUNG 7.4
Der Lautstärkeregler ist
ein eigenes Symbol in der
Bibliothek, ebenso wie die
Spur & Maske des Reglers
(MovieClip).
Das Symbol ist in vier Ebenen unterteilt:
Ebene „hg“: Diese beinhaltet den MovieClip mcSpur, der zu 50% transparent ist.
Er dient dazu, dass der User beim Verstellen der Lautstärke immer noch weiß, wie
hoch er die Lautstärke stellen kann. Des Weiteren werden wir die Spur dafür ver-
wenden, dass der User auf diese klicken und somit die Lautstärke verstellen kann.
Ebene „Text“: Diese beinhaltet lediglich den Text „VOL“.
Ebene „Items“: Sie beherbergt die zehn blauen Striche, die zur symbolhaften Dar-
stellung der Lautstärke dienen.
Ebene „Maske“: Sie legt fest, wie viel der Ebene „Items“ angezeigt wird. Als Maske
wird derselbe MovieClip verwendet wie für die Spur (mcLautstaerkeMaske in der
Bibliothek), da diese sowieso nie sichtbar sein wird.
u
u
u
u
K A P I T E L 7354
In der Listener-Ebene auf der Hauptbühne platzieren wir den Code, der beim Drücken
und Loslassen der Maustaste über dem Lautstärkeregler ausgeführt werden soll:
var itvLautstaerke;
mcLautstaerke.mcSpur.onPress = function():Void {
itvLautstaerke = setInterval(setLautstaerke,50);
}
mcLautstaerke.mcSpur.onRelease = function():Void {
clearInterval(itvLautstaerke);
}
mcLautstaerke.mcSpur.onReleaseOutside = function():Void {
clearInterval(itvLautstaerke);
}
Listing 7.17: Der Code für die Lautstärkesteuerung ist relativ einfach, sehen wir einmal von der noch nicht
definierten Funktion setLautstaerke ab.
Die Variable itvLautstaerke wird für ein Intervall verwendet, auf das wir später
noch zu sprechen kommen. Interessanter wird es schon, wenn wir die Funktionenebe-
ne etwas näher betrachten:
function setLautstaerke():Void {
var mousex:Number = mcLautstaerke._xmouse;
var maxX:Number = mcLautstaerke.mcSpur._width;
mcLautstaerke.mcMaske._width = mousex;
mySong.setVolume(mousex/maxX*100);
}
Listing 7.18: In der Funktionenebene wird die Funktion setLautstaerke definiert.
Sobald die Funktion setLautstaerke aufgerufen wird, wird die Position der Maus
innerhalb des Lautstärkereglers ermittelt (mcLautstaerke._xmouse). Da sich die
Spur an der Position (0/0) befindet, entspricht die Mausposition in x-Richtung auch
direkt der zu setzenden Lautstärke. Die Variable maxX fragt die maximale Lautstärke ab,
indem sie die Breite der Spur ermittelt (mcLautstaerke.mcSpur._width). Danach
wird die Breite der Maske für die Lautstärke-Items (siehe Erklärung zu Abbildung 7.4)
noch auf genau den Wert gesetzt, wo die Maus des Users gerade steht. Abschließend
errechnen wir aus Mausposition und maximaler Lautstärke die tatsächliche Lautstärke
für den Song (in Prozent von 0–100) und weisen diese der Soundinstanz mySong zu
(mousex/maxX*100).
Sprechen wir noch kurz über das Intervall itvLautstaerke. Das Problem mit einer
Lautstärkeregelung in dieser Art und Weise ist, dass der Ablauf wie folgt sein soll:
A U D I O - J U K E B O X 355
1. Sobald der User auf den Lautstärkeregler klickt und die Maus noch gedrückt hält,
soll die Lautstärke gesetzt werden – auch wenn der User dabei die Maus bewegt. Da
das auftretende Ereignis das Ereignis onPress ist und dieses nur einmal auftritt
(nämlich beim Hinunterdrücken der Maustaste), könnte die Lautstärke auch nur
zu diesem Zeitpunkt gesetzt werden,unabhängig davon,wie lange er die Maustaste
unten hält.
2. Beim Loslassen der Maustaste (innerhalb oder außerhalb des Reglers) soll das
Setzen der Lautstärke wieder beendet werden. Die möglichen auftretenden
Ereignisse nennen sich onRelease und onReleaseOutside – auch diese beiden
treten nur einmal auf, was uns jedoch nicht behindert.
Der Ausweg aus der im ersten Punkt dargestellten Problematik ist, dass sobald der User
die Maustaste nach unten drückt, ein Intervall itvLautstaerke startet, das in regel-
mäßigen Abständen (bei uns sind das 50 Millisekunden – entspricht einer Framerate
von 20 Bildern pro Sekunde: 1/20 Sekunde pro Bild) die Lautstärke setzt (über den
Aufruf der Funktion setLautstaerke). Beim Loslassen der Maustaste muss dieses
Intervall nur noch wieder gelöscht werden.
7.5 Der PHP-Part
Nun geht’s endlich mit der PHP-Programmierung los. Unser Ziel ist es, alle MP3-
Dateien eines bestimmten Verzeichnisses unseres Webservers auszulesen und diese
Daten in XML-Form an Flash zu übergeben. Sie werden sehen, dass dies auf einfache
Art und Weise zu realisieren ist.
Zuerst müssen wir natürlich eine PHP-Datei erstellen. Der Name wird uns in diesem
Fall von Flash vorgegeben, da beim Einlesen der XML-Datei die Datei playlist.php
gewünscht wird. Somit nennen wir unsere Datei auch entsprechend „playlist.php“.
Sofern Sie noch keinen Ordner mit MP3-Dateien auf Ihrem Server erstellt haben,
sollten Sie das jetzt tun. Erstellen Sie den Ordner im gleichen Verzeichnis wie die Flash-
Datei und nennen Sie ihn „songs“. Zur Sicherheit sollten Sie bei der Benennung der
Files auf Leer- und Sonderzeichen verzichten. So weit, so gut.
Um in unserer Programmierung flexibel zu bleiben, speichern wir den Ordner der
MP3-Files und auch die Einstellung für den Autostart in jeweils einer eigenen Variable
ab. Würde sich später der Ordnername ändern, müssten wir bloß den Wert der Variable
korrigieren und nicht an jeder Stelle im Skript, an der auf den Ordner verwiesen wird.
if(!isset($_GET["dir"])) { $dir = "songs"; }
else { $dir = $_GET["dir"]; }
if(!isset($_GET["autostart"]) || is_nan($_GET["autostart"])) { $autostart = 0; }
else { $autostart = $_GET["autostart"]; }
Listing 7.19: Anlegen der Variablen für den MP3-Ordner ($dir) und den Wert von $autostart
K A P I T E L 7356
Wie Sie sehen, kann per GET sowohl das auszulesende Verzeichnis der MP3-Files
($_GET["dir"]) als auch die Info über ein Autostart ($_GET["autostart"]) an die
Datei übergeben werden, was unser Script sehr flexibel macht.
Verzeichnis auslesen
Um an die Dateien eines Verzeichnisses zu kommen und diese auszulesen, benötigen
wir insgesamt drei PHP-Funktionen.
opendir(): Mit der Funktion opendir() können wir den gewünschten Ordner
öffnen. Diese Funktion erfordert nur den Pfad zum Ordner und logischerweise
auch den Ordernamen selbst.
readdir(): Mit readdir() können wir immer eine Datei des geöffneten Ordners
auslesen. Um alle Files nacheinander auszulesen, werden wir uns einer Schleife
bedienen. Auch readdir() benötigt allein den Pfad zum Ordner und den Ord-
nernamen.
closdir(): Diese Funktion ist notwendig, um das geöffnete Verzeichnis wieder
zu schließen.
Da wir nun die notwendigen PHP-Funktionen kennen, ist es nicht mehr schwer, unse-
re MP3-Files auszulesen. Zuerst öffnen wir das benötigte Verzeichnis mit opendir().
Als Parameter geben wir einfach die Variable $dir aus Listing 7.19 an, da in dieser ja
der Ordnername, in unserem Fall „songs“, gespeichert wurde.
$verz = opendir($dir);
Zur Erinnerung schauen wir uns noch einmal die gewünschte XML-Struktur an, die
Flash benötigt.
<Playlist rootDir="Verzeichnis" autostart="0">
<song src="MP3-Filename"></song>
...
</Playlist>
Listing 7.20: Die notwendige XML-Struktur, die es zu erzeugen gilt
Bei Betrachten des ersten Knotens sehen Sie, dass wir mit diesem bereits alle notwen-
digen Informationen angeben, also den Pfad zum Ordner, den Ordnernamen und den
Wert für Autostart. Um später eine korrekte XML-Struktur mit der richtigen Forma-
tierung erstellen zu können, speichern wir unsere Knoten in einer Variable $playlist.
Diese Variable werden wir schlussendlich per echo in das Dokument ausgeben..
$playlist = ‚<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>';
$playlist.= ‚<Playlist rootDir="'.$dir.'" autostart="'.$autostart.'">';
Listing 7.21: Erstellen der XML-Definition des Dokuments sowie des ersten Knotens <Playlist>
u
u
u
A U D I O - J U K E B O X 357
Als Nächstes müssen wir die MP3-Files aus unserem Ordner auslesen. Dazu bedienen
wir uns der PHP-Funktion readdir(), mit der man immer eine Datei eines bestimm-
ten Ordners auslesen kann. Um alle Dateien des Ordners auslesen zu können, werden
wir eine while-Schleife nutzen.
Die Funktion readdir() gibt den booleschen Wert true zurück, wenn das Lesen im
Verzeichnis erfolgreich war. In unserer while-Schleife soll der Knoten song so lange
erstellt werden, wie Dateien im Ordner „songs“ gefunden werden. Die gefundenen
Dateien speichern wir in der Variable $file ab.
while($file = readdir($verz)) {
...
}
Daten prüfen
Ein guter Programmierer sollte immer alle notwendigen Daten überprüfen. In
unserem Fall möchten wir nur Dateien vom Typ .mp3 in unsere XML-Struktur auf-
nehmen. Somit müssen wir zum einen kontrollieren, ob es sich generell um eine Datei
(und keinen weiteren Ordner) handelt und ob diese vom Typ .mp3 ist. Dazu bietet uns
PHP wieder Funktionen, die wir direkt nutzen können.
is_dir(): Mit is_dir() prüfen wir, ob es sich um ein Verzeichnis handelt. In
unserem Fall werden wir diese Abfrage negieren, da wir wissen wollen, ob es sich
nicht um einen weiteren Ordner handelt.
substr(): Diese Funktion gehört zu den Zeichenkettenfunktionen. substr()
erwartet einen String und einen Startwert (Position im String), ab dem der Teilst-
ring erzeugt werden soll. Als Rückgabe wird der restliche String ab dem definierten
Startwert zurückgeben. Um die Zählung von hinten beginnen zu lassen, wird ein-
fach der Startwert negativ gesetzt.
Somit ergibt sich folgender Code für die Abfrage:
if(!is_dir($file) && (substr($file,-3)=="mp3"))
Innerhalb der Abfrage erweitern wir die bereits vorhandene Variable $playlist um
die eingelesene Datei:
$playlist .= ‚<song src="'.$file.'" />';
Nachdem wir nun alle MP3-Files aus dem Ordner „songs“ gelesen haben, schließen
wir außerhalb der while-Schleife den geöffneten Ordner wieder.
closedir($verz);
Abschließend wird das geöffnete <Playlist>-Tag wieder geschlossen, der Inhalt in
eine UTF8-kodierte Form gebracht (sollte das nicht gewünscht sein, so entfernen Sie
diese Zeile einfach aus Ihrem Script) und $playlist per echo ausgegeben:
u
u
K A P I T E L 7358
$playlist .= ‚</Playlist>';
$playlist = utf8_encode($playlist);
echo($playlist);
Das vollständige Skript sollte nun so aussehen:
if(!isset($_GET["dir"])) { $dir = "songs"; }
else { $dir = $_GET["dir"]; }
if(!isset($_GET["autostart"]) || is_nan($_GET["autostart"])) { $autostart = 0; }
else { $autostart = $_GET["autostart"]; }
$verz = opendir($dir);
$playlist = '<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>';
$playlist.= '<Playlist rootDir="'.$dir.'" autostart="'.$autostart.'">';
while($file = readdir($verz)) {
if(!is_dir($file) && (substr($file,-3)=="mp3")) {
$playlist .= '<song src="'.$file.'" />';
}
}
closedir($verz);
$playlist .= ‚</Playlist>';
$playlist = utf8_encode($playlist);
echo($playlist);
Listing 7.22: Erstellen der XML-Struktur durch Auslesen der MP3-Files aus einem gegebenen Ordner
Um die Jukebox zu testen, müsste die PHP-Datei in einer Serverumgebung (wie etwa
dem XAMPP-Server oder online) getestet werden. Hierzu laden Sie die Datei inklusive
der MP3-Dateien im angegebenen Ordner in das Verzeichnis, das Sie bei der Installa-
tion als Root-Verzeichnis angegeben haben, und rufen Sie die php-Datei im Browser
auf:
A U D I O - J U K E B O X 359
7.6 Jukebox in ActionScript 3.0
In Kapitel 7.4 wurde die Jukebox in ActionScript 2.0 entwickelt – nun wenden wir
uns ActionScript 3.0 zu und werden sehen, an welchen Stellen der Code (eventuell
grundlegend) verändert werden muss. Idealerweise nehmen Sie sich die Datei audio-
player_01.fla von der Buch-CD zur Hand und verfolgen dort die Änderungen.
7.6.1 Allgemeine Änderungen
Ein wesentlicher Unterschied von ActionScript 2.0 auf ActionScript 3.0 ist die geän-
derte Schreibweise des reservierten Worts VOID:
ActionScript 2.0: VOID wird mit einem großen Anfangsbuchstaben geschrieben:
Void.
ActionScript 3.0: VOID wird mit einem kleinen Anfangsbuchstaben geschrieben:
void.
Dies betrifft alle unsere Funktionen ohne Rückgabewert und das sind 15 an der Zahl,
die wir verteilt in den Ebenen Aktionen, Funktionen und Listener finden.
Weitere Änderungen sind:
Sämtliche Variablen, die innerhalb von ActionScript 3.0 Verwendung finden,
müssen explizit deklariert werden – eine implizite Deklarierung ist nicht möglich.
Somit müssen die Attribute autostart und rootDir, die in der XML-Datei im
Tag <Playlist> verwendet werden, explizit deklariert werden.
u
u
u
ABBILDUNG 7.5
Die Erfolgsbilanz ist positiv:
Der Audioplayer läuft auch
im Browser ohne Probleme!
K A P I T E L 7360
Ein Zugriff auf globale Variablen ist nicht mehr möglich, da es keine globalen Vari-
ablen mehr gibt. Damit entfällt der Verweis auf _global komplett.
Ebenso existiert der Zugriff auf _root nicht mehr – dieser lautet nun nur noch
root (ohne Unterstrich am Anfang).
Im Allgemeinen werden Eigenschaften eines MovieClips nun nicht mehr mit einem
beginnenden Unterstrich „_“ angegeben – der Unterstrich entfällt komplett.
Textfelder, die auf Variablennamen zugreifen, um so den Wert der Variable darzu-
stellen, werden nicht mehr unterstützt – diese müssen nunmehr mit dem Feldna-
men angesprochen werden.
7.6.2 Änderungen beim Laden der XML-Daten
Da in ActionScript 3.0 ein allgemeines Objekt URLRequest in Verbindung mit URL-
Loader zum Laden von Daten eingeführt wurde, läuft das Laden von XML-Daten
nun auch anders ab – damit haben wir uns schon recht ausführlich im vorigen Kapitel
befasst. Anstatt die load-Methode des XML-Objekts zu verwenden, wird nun mit
URLLoader und URLRequest gearbeitet. Somit wird:
var myLoader:XML = new XML();
myLoader.ignoreWhite = true;
...
myLoader.load(mySource);
zu:
var myRequest:URLRequest = new URLRequest(mySource);
var myLoader:URLLoader = new URLLoader();
var myXML:XML;
...
myLoader.load(myRequest);
Die Eigenschaftszuweisung ignoreWhite = true darf erst dann passieren, wenn der
XML-Instanz wirklich XML-Daten zugewiesen wurden.
Der Eventhandler, der beim vollständigen Laden der Daten aufgerufen wird, muss
auch entsprechend abgeändert werden. Aus:
myLoader.onLoad = function():Void {
...
}
wird:
function EXMLComplete(myEvent:Event):void {
u
u
u
u
A U D I O - J U K E B O X 361
...
}
myLoader.addEventListener(Event.COMPLETE, EXMLComplete);
Innerhalb des Eventhandler EXMLComplete wird nun ebenfalls auf geänderte Art und
Weise auf die XML-Daten zugegriffen. Anstatt die Elemente des XML-Baums Schritt
für Schritt durchzuparsen, können wir direkt auf die Elemente zugreifen. Die gesamte
Funktion erhält nun folgenden Inhalt:
function EXMLComplete(myEvent:Event):void {
myXML = new XML(myEvent.target.data);
myXML.ignoreWhite = true;
autostart = parseInt(myXML.@autostart);
rootDir = myXML.@rootDir;
for(var i:uint=0; i<myXML.song.length(); i++) {
theSongs[i] = myXML.song[i].@src;
}
}
Listing 7.23: Die Funktion EXMLComplete (Eventhandler für das Laden von Daten) enthält nun keine
Fehlerbehandlung mehr.
Die Fehlerbehandlung (mehrmaliges Laden von Daten, falls der Ladeversuch fehl-
geschlagen hat) ist hierin nicht mehr definiert, da die gesamte Fehlerbehandlung in
ActionScript 3.0 nun anders verläuft. Ein Fehler, der am wahrscheinlichsten auftritt,
ist ein IOError – diesen gilt es abzufangen:
function EIOError(myEvent:IOErrorEvent):void {
anzLadeversuche++;
if(anzLadeversuche<maxLadeversuche) { myLoader.load(myRequest); }
else {
mcError.visible = true;
}
}
myLoader.addEventListener(IOErrorEvent.IO_ERROR, EIOError);
Listing 7.24: Die Funktion EIOError verarbeitet einen IOError. Bitte beachten Sie auch, dass die Eigen-
schaft visible nun ohne führendem Unterstrich „_“ geschrieben wird.
K A P I T E L 7362
Schaltflächenereignisse: addEventListener
Da wir mit dem MovieClip mcError arbeiten und den Buttons btnJa und btnNein in
diesem MovieClip release-Ereignisse zugewiesen haben, müssen wir uns noch um
diese kümmern. In ActionScript 3.0 lassen sich Schaltflächenereignisse nicht mehr
direkt zuweisen – vielmehr muss der Weg über addEventListener führen:
Aus:
var songTitel:String = "loading Playlist...";
var songInterpret:String = "";
var songAlbum:String = "";
var theTimeInfo:String = "--:--";
mcError.btnNein.onRelease = function():Void {
_root.mcError._visible = false;
_root.songTitel = "ERROR WHILE LOADING PLAYLIST";
}
mcError.btnJa.onRelease = function():Void {
_root.myLoader.load(mySource);
_root.mcError._visible = false;
}
wird:
Titel.text = "loading Playlist...";
Interpret.text = "";
Album.text = "";
Restzeit.text = "--:--";
function ENeinUp(myEvent:MouseEvent):void {
mcError.visible = false;
Titel.text = "ERROR WHILE LOADING PLAYLIST";
}
function EJaUp(myEvent:MouseEvent):void {
myLoader.load(myRequest);
mcError.visible = false;
}
mcError.btnNein.addEventListener(MouseEvent.MOUSE_UP, ENeinUp);
mcError.btnJa.addEventListener(MouseEvent.MOUSE_UP, EJaUp);
Listing 7.25: ActionScript 3.0 erfordert addEventListener für die Zuweisung von Eventhandlern
(auch bei Schaltflächen).
addEventListe-
ner nun auch für
Schaltflächen
addEventListe-
ner nun auch für
Schaltflächen
A U D I O - J U K E B O X 363
Diese Vorgehensweise gilt im Übrigen selbstverständlich auch für sämtliche anderen
Buttons, die wir im Audioplayer verwenden: Play, Stop, FWD, RWD.
Die Variablen songTitel, songAlbum und songInterpret aus ActionScript 2.0
wurden durch den Zugriff auf die dynamischen Textfelder über deren Namen ersetzt,
da der direkte Zugriff von dynamischen Textfeldern auf Variablen (zur Darstellung
von deren Werten) nicht mehr möglich ist. Stattdessen greift man auf den Namen des
Textfelds und dessen Eigenschaft text zu.
7.6.3 Änderungen im Soundobjekt
Grundsätzlich wurde die Sound-Klasse in das Paket flash.media.Sound verschoben.
Jedoch ist dies bei weitem nicht die einzige Änderung, welche die neue ActionScript-
Version mit sich bringt.
1. Laden von Sounddateien: Wie in ActionScript 3.0 üblich, erfolgt das gesamte
Laden von Dateien über das URLRequest-Objekt. Somit wird beim Laden von
Sounddateien einem Soundobjekt beim Laden eine Instanz eines URLRequest-
Objekts zugewiesen.
2. Verwenden der Sound-Klasse: Diese wird zum Laden von Sounddateien,Verwalten
allgemeiner Soundeigenschaften sowie zum Starten der Soundwiedergabe
verwendet.
3. Verwenden der SoundChannel-Klasse: Sobald über die Sound-Klasse eine
Sounddatei abgespielt wird, wird eine neue Instanz eines SoundChannel-Objekts
erzeugt. Damit wird im Weiteren die Wiedergabe gesteuert.
Des Weiteren ist es nun möglich, auch gestreamte Sounds ab einer gewissen Position
abspielen zu lassen – dies ermöglicht es uns, einen Pause-Button für Streaming-Sounds
zu erstellen. (Dies ist in diesem Beispiel auch umgesetzt worden: Der Stop-Button
wurde in einen Pause/Stop-Button umgewandelt – Details siehe weiter unten.)
7.6.4 Änderungen in der Abspielsteuerung
Die Abspielsteuerung betrifft die Buttons Play, Stop, RWD und FWD. Hier sind Ände-
rungen an den Eventhandlern der Buttons vorzunehmen, da die direkte Zuweisung von
Ereignissen in ActionScript 3.0 nicht mehr funktioniert. Somit erhalten wir anstatt:
btnPlay.onRelease = function():Void { playSong(0); }
btnStop.onRelease = function():Void { stopSong(); }
btnRWD.onRelease = function():Void { playSong(-1); }
btnFWD.onRelease = function():Void { playSong(1); }
Listing 7.26: ActionScript-2.0-Code ...
Zugriff auf dyna-
mische Textfelder
über text
Zugriff auf dyna-
mische Textfelder
über text
K A P I T E L 7364
nun:
var isPaused:Boolean = false;
var isStopped:Boolean = false;
var pausingPos:Number = 0;
function EPlay(myEvent:MouseEvent):void { playSong(0); }
function EStop(myEvent:MouseEvent):void {
if(!isStopped) {
if(!isPaused) {
isPaused = true;
pausingPos = mySoundchannel.position;
}
else {
isPaused = false;
isStopped = true;
pausingPos = 0;
}
stopSong();
}
}
function ERWD(myEvent:MouseEvent):void { playSong(-1); }
function EFWD(myEvent:MouseEvent):void { playSong(1); }
btnPlay.addEventListener(MouseEvent.MOUSE_UP, EPlay);
btnStop.addEventListener(MouseEvent.MOUSE_UP, EStop);
btnFWD.addEventListener(MouseEvent.MOUSE_UP, EFWD);
btnRWD.addEventListener(MouseEvent.MOUSE_UP, ERWD);
Listing 7.27: ... im Gegensatz zu ActionScript-3.0-Code. Die Funktion EStop musste erweitert werden, da
der Stop-Button nun zwei Funktionen (Pause und Stopp) übernehmen soll.
Wie Sie sehen, nennt sich das onRelease-Ereignis nun Mouse_UP und befindet sich in
der Klasse MouseEvent. In der Funktion EStop finden Sie wesentlich mehr Code als
im vergleichbaren Code in ActionScript 2.0. Dies hat hauptsächlich mit zwei Dingen
zu tun:
A U D I O - J U K E B O X 365
1. Nachdem es in ActionScript 3.0 nun auch möglich ist, einen gestreamten Sound an
einer gewissen Stelle starten zu lassen, kann ein „Pause“-Verhalten programmiert
werden: Beim ersten Klick auf den Pause/Stop-Button wird der Song pausiert
(bei Klick auf den Play-Button startet der Sound an der gestoppten Stelle), beim
zweiten Klick wird er tatsächlich gestoppt und beginnt bei einem Klick auf den
Play-Button von Neuem.
2. Da nun sowohl mit einem Sound- als auch mit einem SoundChannel-Objekt
zu arbeiten ist, wird das Stoppen eines Sounds aufwändiger: Es muss einerseits
(sofern der Datentransfer der Datei noch im Gange ist; betrifft die Sound-
Instanz) der Datentransfer und andererseits das Abspielen des Songs (betrifft die
SoundChannel-Instanz) gestoppt werden. Da nur ein laufender Transfer und
nur ein gerade aktiver SoundChannel gestoppt werden kann, muss man sich –
beispielsweise in Form einer Variable – „merken“, ob eben gerade abgespielt wird.
Eine Alternative zu dieser Vorgehensweise ist die Variante mit try & catch, die in
der Datei audioplayer_02a.fla dargestellt ist.
Der Ablauf der EStop-Funktion ist also wie folgt:
Sofern der Song nicht schon gestoppt ist (das wäre bei isStopped==true), wird
überprüft ob der Song noch nicht pausiert ist (isPaused==false).
Falls isPaused==false wird der Song „pausiert“ (natürlich wird das Abspielen
komplett gestoppt, aber die Position des Abstoppens wird in der Variable pausing-
Pos gespeichert).
Falls isPaused==true wird der Song gestoppt (dies bedeutet, dass pausingPos=0
gesetzt wird).
Wie Sie sehen, spielt die Variable pausingPos eine wesentliche Rolle: Grundsätzlich
wird jeder Song über diese Variable pausingPos (Anzahl der Millisekunden ab Beginn
der Sounddatei) gestartet. Aus diesem Grund muss im Fall eines tatsächlich gestoppten
Sounds die Variable pausingPos den Wert 0 erhalten.
Des Weiteren müssen die Funktionen playSong und stopSong entsprechend ange-
passt werden:
var mySound:Sound;
var mySoundchannel:SoundChannel;
function playSong(dir:Number):void {
if(isStopped || dir!=0) { Restzeit.text = "--:--"; }
Titel.text = "getting MP3-Information...";
Album.text = "";
Interpret.text = "";
u
u
u
K A P I T E L 7366
actualSong += dir;
if(actualSong==theSongs.length) { actualSong = 0; }
if(actualSong==-1) { actualSong = theSongs.length-1; }
isPaused = false;
isStopped = false;
if(dir!=0) { pausingPos = 0; }
if(mySound!=null && !isStopped) { stopSong(); }
myRequest.url = rootDir+"/"+theSongs[actualSong];
mySound = new Sound();
mySound.addEventListener(Event.ID3, EID3);
mySoundchannel = new SoundChannel();
mySoundchannel.addEventListener(Event.SOUND_COMPLETE, ESoundComplete);
mySound.load(myRequest);
mySoundchannel = mySound.play(pausingPos);
}
function stopSong():void {
mySoundchannel.stop();
if(mySound.bytesLoaded!=mySound.bytesTotal) { mySound.close(); }
clearInterval(itvTimer);
if(isStopped) {
Restzeit.text = "--:--";
Titel.text = "(stopped)";
Interpret.text = "";
Album.text = "";
}
}
Listing 7.28: Die „neuen“ Funktionen playSong und stopSong
A U D I O - J U K E B O X 367
Befassen wir uns zunächst mit der playSong-Funktion, welche die eingangs erzeugte
Sound-Instanz mySound sowie die SoundChannel-Instanz mySoundchannel verwen-
det (diese wurde – um Verwechslungen mit der ActionScript-2.0-Variante zu vermei-
den – von mySong auf mySound umgetauft):
Zu Beginn werden die dynamischen Textfelder „zurückgesetzt“.
Danach wird der aktuell abzuspielende Song ermittelt (siehe hierzu auch die Erklä-
rungen aus dem ActionScript-2.0-Teil: Listing 7.10).
Da beim Aufruf dieser Funktion in jedem Fall ein Song abgespielt werden soll,
werden die Variablen isPaused und isStopped auf den Wert false gesetzt:
isPaused = false; isStopped = false;.
Je nachdem, ob der aktuelle (dir==0) oder der nächste oder vorige Song abzuspielen
ist, wird die Variable pausingPos auf 0 gesetzt, da nur im Fall des aktuellen Songs
(Betätigen des Play-Buttons nach dem Betätigen des Pause/Stop-Buttons) ab einer
gewissen Position abgespielt werden soll: if(dir!=0) { pausingPos = 0; }.
InjedemFallmusseinderzeitabgespielterSongbeendetwerden:if(mySound!=null
&& !isStopped) { stopSong(); }. Da dies nur geschehen kann, wenn bereits
ein Soundobjekt existiert (also ungleich null ist) und ein Stoppen nur dann Sinn
macht, wenn der Song noch nicht gestoppt ist, werden diese beiden Eigenschaften
bzw. Variablen zuvor abgefragt.
Nun folgt der eigentlich wichtige Teil beim Arbeiten mit Sounds:
Zunächst bedienen wir uns der bereits seit dem Laden der XML-Daten existen-
ten URLRequest-Instanz myRequest und weisen der Eigenschaft url die URL
zur Sounddatei aus dem Sound-Array zu: myRequest.url = rootDir+"/
"+theSongs[actualSong];.
Danach wird eine Sound-Instanz gesetzt und dieser und der SoundChannel-
Instanz ein Eventhandler (für das Ereignis ID3; Auslesen der ID3-Tags möglich)
zugewiesen:
mySound = new Sound();
mySound.addEventListener(Event.ID3, EID3);
Zu guter Letzt wird das in der URLRequest-Instanz definierte MP3-File geladen,
der SoundChannel mit dem Abspielen der Datei beauftragt und dem Sound-
Channel mitgeteilt, was nach dem erfolgten Abspielen der Sounddatei gesche-
hen soll (Ereignis SOUND_COMPLETE; Abspielen der Sounddatei beendet):
mySound.load(myRequest);
mySoundchannel = mySound.play(pausingPos);
mySoundchannel.addEventListener(Event.SOUND_COMPLETE, ESoundComplete);
Fassen wir noch kurz zusammen:
u
u
u
u
u
u
u
u
u
K A P I T E L 7368
1. Zum Laden von Daten (auch MP3-Files) wird generell das URLRequest-Objekt
verwendet.
2. Das Soundobjekt erhält die Daten des URLRequest-Objekts und „verwaltet“ diese
sozusagen. Im Gegensatz zu ActionScript 2.0 wird das Soundobjekt nun nicht
mehr zum Abspielen des Sound-File verwendet.
3. Zum Steuern der Sounddaten wird das SoundChannel-Objekt verwendet.
Bleibt noch die Funktion stopSound:
Im ersten Schritt wird das Abspielen in der SoundChannel-Instanz mySoundchan-
nel gestoppt: mySoundchannel.stop();.
Sollte in der Soundinstanz mySound noch ein Datentransfer aktiv sein (das
wäre der Fall, wenn die geladenen Bytes der MP3-Datei noch nicht den zu
übertragenen Bytes entsprechen), wird dieser ebenfalls beendet: if(mySound.
bytesLoaded!=mySound.bytesTotal) { mySound.close(); }.
Danach wird das gerade laufende Intervall zum Anzeigen der Restzeit gestoppt:
clearInterval(itvTimer);.
Falls der Sound nicht pausiert, sondern gestoppt wird, werden zusätzlich noch die
Textfelder zurückgesetzt.
Alternative: try & catch in der Funktion stopSound
function stopSong():void {
try { mySoundchannel.stop(); }
catch(myError:Error) { trace("SoundChannel kann nicht gestoppt werden.
Error="+myError.message); }
try { mySound.close(); }
catch(myError:Error) { trace("Soundtransfer kann nicht geschlossen
werden, da er wahrscheinlich bereits abgeschlossen ist.
Error="+myError.message); }
clearInterval(itvTimer);
if(isStopped) {
Restzeit.text = "--:--";
Titel.text = "(stopped)";
Interpret.text = "";
Album.text = "";
}
}
Listing 7.29: Alternative Abarbeitung der stopSound-Funktion in der Datei audioplayer_02a.fla
u
u
u
u
A U D I O - J U K E B O X 369
Anstatt die SoundChannel-Instanz mySoundchannel „einfach so“ zu stoppen, wird
dies mittels try versucht. Sollte der Versuch nicht klappen (was nicht tragisch wäre,
sondern nur die Info, dass das Abspielen bereits gestoppt wurde), kann man im catch-
Teil den Fehler ausgeben – unbedingt notwendig ist das jedoch nicht.
Dasselbe Prozedere durchläuft der Versuch, die Sound-Instanz mySound in ihrer Über-
tragung zu beenden.
Kommen wir zum Auslesen der ID3-Tags sowie dem Timer für die Restzeitanzeige. Das
Auslesen der ID3-Tags erfolgt nach wie vor im Sound-Objekt (wie in der Beschreibung
der Funktion playSong beschrieben):
var itvTimer:Number;
function EID3(myEvent:Event):void {
Interpret.text = mySound.id3.TPE1;
Album.text = mySound.id3.TALB;
Titel.text = mySound.id3.TIT2;
itvTimer = setInterval(showTimer,1000);
}
function showTimer():void {
var theLength:Number = Math.floor((mySound.id3.TLEN-mySoundchannel.
position)/1000);
var min:Number = Math.floor(theLength/60);
var sek:String = "";
if(theLength-60*min<10) { sek += "0"; }
sek += theLength-60*min;
Restzeit.text = "-"+min+":"+sek;
}
Listing 7.30: Die Funktion EID3 wird zum Anzeigen der ID3-Tags einer MP3-Datei benötigt, die Funktion
showTimer dient zur Anzeige der Restzeit eines abspielenden Songs.
Diese beiden Funktion sind relativ straight forward:
Die Funktion EID3 dient als Eventhandler und wird aufgerufen, sobald eine
Sound-Instanz die ID3-Tags aus einer MP3-Datei auslesen konnte, wobei wir uns
hier lediglich auf die ID3-Tags der Version 2 beziehen. Sie liest die Tags TPE1 (Inter-
pret), TALB (Album) und TIT2 (Titel) der MP3-Datei aus. Sobald dies geschehen
ist, wird ein Intervall gesetzt, das in regelmäßigen Abständen (alle 1000 Millisekun-
den, also jede Sekunde) die Funktion showTimer aufruft.
u
K A P I T E L 7370
Die Funktion showTimer errechnet aus der Länge der MP3-Datei (TLEN; in Mil-
lisekunden) und der aktuellen Abspielposition (mySoundchannel.position; in
Millisekunden) die aktuelle Restzeit in Sekunden. Daraus werden die Minuten und
die Sekunden für die Anzeige berechnet, wobei den Sekunden eine führende Null
angehängt wird, sollten die Sekunden weniger als zehn sein. Zum Schluss wird aus
den berechneten Werten ein String der Form „-MM:SS“ gebastelt und dem Textfeld
Restzeit zugewiesen.
7.6.5 Änderungen in der Lautstärkeregelung
Die letzte Änderung betrifft die Lautstärkeregelung. Da MovieClips in ActionScript 3.0
keine Button-Ereignisse mehr zugewiesen werden können, muss dem Lautstärkeregler
im Design ein unsichtbarer Button hinzugefügt werden, den der User dann ankli-
cken kann. Dieser Button wird die Größe der Spur des Hintergrunds haben – somit
bekommt der User den Eindruck, er könnte direkt den Lautstärkeregler anklicken:
u
ABBILDUNG 7.6
Der Lautstärkeregler erhält
einen zusätzlichen unsicht-
baren Button namens
btnSpur.
Die Änderungen bezüglich des Lautstärkereglers ergeben sich dann wie nachfolgend.
Aus:
var itvLautstaerke:Number;
mcLautstaerke.mcSpur.onPress = function():Void {
itvLautstaerke = setInterval(setLautstaerke,50);
}
mcLautstaerke.mcSpur.onRelease = function():Void {
clearInterval(itvLautstaerke);
A U D I O - J U K E B O X 371
}
mcLautstaerke.mcSpur.onReleaseOutside = function():Void {
clearInterval(itvLautstaerke);
}
wird:
var itvLautstaerke:Number;
function ELautstaerkePress(myEvent:MouseEvent):void {
itvLautstaerke = setInterval(setLautstaerke,50);
}
function ELautstaerkeRelease(myEvent:MouseEvent):void {
clearInterval(itvLautstaerke);
}
function ELautstaerkeRollOutside(myEvent:MouseEvent):void {
clearInterval(itvLautstaerke);
}
mcLautstaerke.btnSpur.addEventListener(MouseEvent.MOUSE_DOWN,
ELautstaerkePress);
mcLautstaerke.btnSpur.addEventListener(MouseEvent.MOUSE_UP,
ELautstaerkeRelease);
mcLautstaerke.btnSpur.addEventListener(MouseEvent.ROLL_OUT,
ELautstaerkeRollOutside);
Listing 7.31: Die neue Ereignisbehandlung für den Lautstärkeregler
Letzten Endes hat sich lediglich der Aufruf der Eventhandler geändert, wobei uns das
schon aus früheren Überlegungen bekannt ist. Da das Ereignis onReleaseOutside
nicht mehr existiert, muss man auf das Ereignis ROLL_OUT zurückgreifen: Dieses
Ereignis tritt auf, sobald der User mit der Maus aus einem bestimmten MovieClip
herausrollt.
Die Funktion setLautstaerke hat sich gegenüber der ActionScript-2.0-Variante
ebenfalls deutlich geändert. Aus:
function setLautstaerke():Void {
var mousex:Number = mcLautstaerke._xmouse;
var maxX:Number = mcLautstaerke.mcSpur._width;
mcLautstaerke.mcMaske._width = mousex;
mySong.setVolume(mousex/maxX*100);
}
K A P I T E L 7372
wird:
function setLautstaerke():void {
if(mySoundchannel!=null) {
var mousex:Number = mcLautstaerke.mouseX;
var maxX:Number = mcLautstaerke.mcSpur.width;
mcLautstaerke.mcMaske.width = mousex;
var myTransform:SoundTransform = mySoundchannel.soundTransform;
myTransform.volume = mousex/maxX;
mySoundchannel.soundTransform = myTransform;
}
}
Listing 7.32: Um die Lautstärke einer SoundChannel-Instanz zu verändern, bedarf es einer Sound-
Transform-Instanz.
Grundsätzlich kann eine Veränderung der Lautstärke nur dann erfolgen, wenn es eine
SoundChannel-Instanz gibt – in unserem Fall trägt diese den Namen mySoundchan-
nel. Ist diese vorhanden, werden x- und y-Position der Maus innerhalb des MovieC-
lips mcLautstaerke ausgelesen und die Maske zum Anzeigen der Lautstärkestriche
wird entsprechend gesetzt.
Danach erfolgt der erste wichtige Schritt: die derzeitigen SoundTransform-Einstel-
lungen werden aus der SoundChannel-Instanz mySoundchannel ausgelesen und der
SoundTransform-Instanz myTransform zugewiesen:
var myTransform:SoundTransform = mySoundchannel.soundTransform;
Danach wird in dieser gerade erzeugten Instanz der Wert der Eigenschaft volume auf
den entsprechenden Wert gesetzt. Bitte beachten Sie an dieser Stelle, dass die Eigen-
schaft volume nun nicht mehr in Prozent, sondern in Werten zwischen 0 und 1 ange-
geben werden muss:
myTransform.volume = mousex/maxX;
Ist dies erfolgt, schreibt man die geänderten Einstellungen wieder zurück in die
SoundChannel-Instanz:
mySoundchannel.soundTransform = myTransform;
7.6.6 Songs aus einer ComboBox abspielen
Als Erweiterung des aktuellen Players könnte man beispielsweise eine ComboBox mit
allen Songs der Playlist füllen und durch Auswählen eines Songs aus der ComboBox
A U D I O - J U K E B O X 373
diesen direkt abspielen. Gesagt – getan: Ziehen Sie hierzu eine ComboBox aus den
Komponenten auf die Bühne und geben Sie dieser den Namen „myPlaylist“.
Nachdem dies erledigt ist, muss die Funktion EXMLComplete vor dem Aufruf der
Funktion initPlayer wie folgt erweitert werden, um die ComboBox mit Inhalt zu
füllen:
...
myPlaylist.addEventListener(Event.CHANGE, EChange);
myPlaylist.addItem({ label:"Bitte wählen Sie:", data:-1 });
for(i=0; i<myXML.song.length(); i++) {
myPlaylist.addItem({ label:myXML.song[i].@src, data:i });
}
initPlayer();
}
Listing 7.33: Befüllen der ComboBox myPlaylist mit den MP3-Dateien aus der Playlist
Bevor die for-Schleife das Befüllen der ComboBox übernimmt, wird noch ein Eintrag
mit der Beschriftung „Bitte wählen Sie“ in die ComboBox geschrieben. Der zugehörige
Wert dieses Eintrags ist -1 (dieser Wert wird später benötigt, da die Wahl des Users
auch auf diesen Eintrag fallen kann, jedoch dann kein Song geladen werden soll).
Innerhalb der for-Schleife werden alle Einträge der XML-Datei-Tags <song> als
Beschriftung (label) in die ComboBox geschrieben. Die zugehörigen Werte (data)
der Einträge sind die fortlaufenden Zahlen der for-Schleife (und somit der Index
innerhalb der Playlist theSongs).
Der Eventhandler EChange bestimmt, was beim Auswählen eines Songs aus der Com-
boBox geschehen soll:
function EChange(myEvent:Event):void {
if(myPlaylist.selectedItem.data!=-1) {
var dir:Number = myPlaylist.selectedItem.data-actualSong;
playSong(dir);
}
}
Listing 7.34: Der Eventhandler EChange, der aufgerufen wird, sobald der User eine neue Auswahl in der
ComboBox getroffen hat
Sollte die Auswahl einen Wert ungleich -1 haben (-1 war der Wert für den Eintrag
„Bitte wählen Sie:“), so wird in der Variable dir die Anzahl der Songs ermittelt, um
K A P I T E L 7374
die in der Playlist zurück (falls kleiner 0) oder vor (falls größer 0) gesprungen werden
muss. Dieser Wert wird dann an die Funktion playSong übergeben – fertig.
7.7 Mögliche Erweiterungen
Neben der Abspielsteuerung in Flash kann selbstverständlich auch eine Abspielsteue-
rung in XHTML erfolgen. Dabei müssen in XHTML entsprechende Buttons angelegt
werden, die in Flash freigegebene Funktionen aufrufen (wie Sie das realisieren können,
erfahren Sie im Kapitel Clientseitiger Datenaustausch).
Eine andere Erweiterung wäre etwa, dass per AJAX in regelmäßigen Abständen in der
Datenbank nachgesehen wird, ob sich an der Playlist etwas verändert hat – wäre dies
der Fall, so könnte die Playlist in Flash nachgeladen werden. Ein entsprechendes Bei-
spiel finden Sie im Anschluss: der Videoplayer. Viel Spaß dabei!
8
VIDEOPLAYER
(ACTIONSCRIPT 3.0)
Ziel dieses Workshops ist die Erstellung eines Videoplayers, der
die abzuspielenden Videos aus einer XML-Datei entnimmt und
nacheinander anzeigt. Die XML-basierte Abspielliste soll per
PHP dynamisch generiert werden und entweder alle in einem
Verzeichnis befindlichen Flash-Videodateien (.FLV) oder eine
über eine Datenbank generierte Liste an Videos beinhalten.
Weiters sei vorausgeschickt, dass der Videoplayer in ActionS-
cript 3.0 entwickelt wird und somit mit älteren Playern nicht
abgespielt werden kann.
Gleich vorwegschicken möchte ich auch eine Quellenangabe
sowie ein Copyright zu allen Videos, die in diesem Work-
shop verwendet wurden: Die Videos wurden mit freundlicher
Genehmigung von TV1.at zur Verfügung gestellt. Herzlichen
Dank!
K A P I T E L 8376
8.1 Das Konzept des Videoplayers
1. Der Videoplayer soll in der Lage sein, gestreamt FLV-Dateien abzuspielen. Somit
ist die erste Anforderung, dass FLV-Dateien dynamisch in Flash eingelesen werden
sollen.
2. Innerhalb des Videoplayers soll volle Kontrolle über das Abspielen der Videos
gewährleistet sein. In diesem Fall werden wir die Möglichkeiten der Video-Skins
von Flash nutzen.
3. Es soll eine parametergesteuerte Autostart-Möglichkeit vorhanden sein.
4. Des Weiteren soll in der XML-Datei die Möglichkeit bestehen, im Falle einer
datenbankgenerierten XML-Datei Informationen zu Autor, Inhalt usw. zu
beinhalten.
Wir werden den Videoplayer in mehreren Schritten entwickeln:
Zunächst lernen wir, wie man generell mit FLV-basierten Videodaten in Flash
arbeitet (an dieser Stelle lernen wir die Komponente „FLV Playback“ kennen).
Danach werden wir den Player so erweitern, dass er mehr als nur ein Video abspie-
len kann.
Ist dies geschehen, werden wir per PHP eine XML-basierte Abspielliste generieren,
welche wir im Weiteren in die Flash-Datei laden.
Anschließend bringen wir noch AJAX ins Spiel und lassen uns überraschen, wie
AJAX uns im Fall eines neuen Videos informiert.
Zu guter Letzt greifen wir das Thema der Cue-Points auf, um zu sehen, wie man
auf diese zugreifen kann.
8.2 Flash & Video
Sinnvoll mit Video arbeiten kann Flash im Prinzip seit Version 6. Jedoch besteht mit
Einführung von Flash 8 die Möglichkeit, neben dem Sorenson Spark Codec den (bes-
seren und leistungsfähigeren) On2VP6 Codec zu verwenden.
Grundsätzlich sollte man sich für den On2 VP6 Codec entscheiden, da dieser bei glei-
cher Datenrate das (qualitativ) wesentlich bessere Ergebnis liefert. Auf der Habenseite
steht jedoch, dass der Flash-Player beim Decodieren während der Anzeige beim User
wesentlich mehr Prozessorleistung benötigt. Nicht zuletzt auch aus diesem Grund ist
beim Einsatz von Video ein Grundsatz wesentlich und entscheidend: „Kenne deine
User“. Gerade im Fall von Video müssen an den User sehr hohe Anforderungen gestellt
werden:
u
u
u
u
u
„Kenne deine
User“
„Kenne deine
User“
V I D E O P L AY E R ( A C T I O N S C R I P T 3 . 0 ) 377
1. Der User sollte über eine entsprechend gute Internetanbindung verfügen: DSL mit
einer Download-Rate von mind. 400 Kbit/S für Videos in einer Standardgröße von
320x240 Pixel ist ideal. Bitraten á la ISDN oder gar Modem fallen gänzlich durch
den Rost (außer die Videos sind in ihren Abmessungen relativ klein: beispielsweise
160x120 Pixel).
2. Des Weiteren ist in jedem Fall der Flash8-Player auf Userseite vorauszusetzen.
3. Außerdem wird wie oben erwähnt relativ viel Prozessorleistung beim Decodieren
eines FLV-Videos benötigt.
Ziehen Sie in jedem Fall eine Useranalyse in Erwägung – Ihre Kunden und vor allem
Ihre User werden es Ihnen danken! Eine entsprechende „Warnmeldung“ für User mit
schlechteren Internetanbindungen bzw. älteren Rechnern ist sowieso Pflicht.
Aus Sicht von ActionScript spielt die Wahl des Decoder keine entscheidende Rolle,
vielmehr ist die Wahl des korrekten Videoformats von entscheidender Bedeutung:
Hier sollte in jedem Fall die Wahl auf das FLV-Format fallen – von der Möglichkeit,
Videos in SWF-Dateien zu importieren und diese SWF-Datei dynamisch hinzuzula-
den, möchte ich aus mehrerlei Gründen abraten:
1. Bildrate von Video und Flash-Datei (zumeist) unterschiedlich:
Bettet man Videos in die Zeitleiste einer Flash-Datei ein, so tritt unweigerlich das
Problem auf,dass die Bildraten vonVideo und Flash-Datei nicht zusammenpassen.
TypischerweisewerdenVideosmiteinerBildratevon25BildernproSekundeerstellt
(B/s) – diese Bildrate ist jedoch für den Flash-Player (bzw. das Flash-Plug-in – Sie
kennen den Unterschied …) zu hoch,was dann zu einem Ruckeln imAbspielen des
Videos führt. Der Ausweg wäre, einen ganzzahligen Teiler zu verwenden, wodurch
beispielsweise nur jedes zweite oder dritte Bild aus dem Video in die Flash-Datei
übernommen wird (vergleiche hierzu auch die nachfolgende Abbildung). Leider
existiert kein sinnvoller Teiler, denn ein Teiler 2 würde zu einer Bildrate von 12.5
Bildern pro Sekunde führen, ein Teiler 3 zu 8.333 B/s, ein Teiler 4 zu 6.25 B/s usw.
Erst ein Teiler 5 würde zu einer ganzzahligen Bildrate in Flash führen – nur eine
Bildrate von 5 B/s ist eindeutig zu wenig. Ich denke, da geben Sie mir Recht – das
menschliche Auge würde es in jedem Fall tun,denn erst ab einer Bildrate von 22 B/s
erkennt das menschliche Auge den Unterschied zwischen Einzelbildern (ein Video
ist ja schlussendlich eine Abfolge von Einzelbildern) und einem fortlaufenden Bild
nicht mehr. Der Grund dafür, dass wir in Flash typischerweise mit einer Bildrate
von 10–15 B/s arbeiten, ist in der geringen Leistungsfähigkeit des Flash-Players
begründet.
2. Probleme in der Synchronisierung von Audio- und Videospur:
Da Flash beim Einbetten von Videos letzten Endes nichts andres tut, als das Video
in Form von Einzelbildern abzuspielen, werden die Audio- und „Video“-Spur
K A P I T E L 8378
voneinander getrennt. In diesem Fall wird die Audiospur konventionell als Sound
abgespielt und dadurch ergeben sich die üblichen Probleme beim gleichzeitigen
Abspielen von Audio und Animation. Bitte schlagen Sie in der Referenz zu Flash
nach, um hierzu weiterführende Informationen zu erhalten.
3. Der Produktionszyklus: vom Video zur SWF- bzw. FLV-Datei
Das Einbetten von Videos in eine Flash-Datei erfordert einen zusätzlichen
Arbeitsschritt, der zeitlich gesehen mitunter nicht zu unterschätzen ist. Auf
der anderen Seite können Flash-Videos (FLV-Dateien) oft direkt aus den
Videobearbeitungsprogrammen exportiert werden.
ABBILDUNG 8.1
Unterschiedliche Bitraten
zwischen der Quelldatei
und der SWF-Datei führen
beim Einbetten des Videos
dazu, dass aus der Quelldatei
unregelmäßig Bilder in das
eingebettete Video der SWF-
Datei übernommen werden.
Der Grund dafür ist, dass in
unserem Fall die Bildrate der
Quelldatei (25 B/s) und der
SWF-Datei (15 B/s) keinen
sinnvollen gemeinsamen
Teiler besitzen (der größte
gemeinsame Teiler wäre 5,
jedoch ist eine Bildrate von
5 B/s nicht sinnvoll).
Aus diesem Grund entscheidet man sich gerne für FLV- anstatt für eingebettete Videos
in SWF-Dateien. Bitte beachten Sie jedoch, dass erst mit der Einführung von Flash 7
das Arbeiten mit FLV-Dateien möglich wurde.
Ein weiterer wesentlicher Vorteil von FLV- gegenüber SWF-Dateien sind die in die
FLV-Dateien integrierten Metadaten (vergleichen Sie hierzu auch den Workshop
„Audio-Jukebox“ und die dort verwendeten MP3-Dateien), die abgerufen und somit
angezeigt werden können.
8.3 Die Umsetzung
8.3.1 Flash und die FLVPlayback-Komponente
Flash bietet uns seit Version 7 die Möglichkeit, Videodateien im FLV-Format mit einer
geeigneten Komponente abzuspielen. Es empfiehlt sich an dieser Stelle, die Kom-
ponente nicht per ActionScript zu erstellen, sondern diese direkt auf der Bühne zu
platzieren, da dies sehr einfach und komfortabel geschieht: Unter den Komponenten
(das entsprechende Register können Sie über den Menüpunkt FENSTER/KOMPONENTEN
einblenden) finden Sie die Komponenten für „User Interface“ und eben „Video“. Zie-
hen Sie die Komponente FLVPlayback auf die Bühne:
V I D E O P L AY E R ( A C T I O N S C R I P T 3 . 0 ) 379
In der Registerkarte PARAMETER hat man die Möglichkeit, die benötigten Buttons für
die Abspielsteuerung in Form von sogenannten Skins zu wählen. In unserem Fall
genügen die Buttons Play, Stopp, Rewind, Forward, Lautstärke (inklusive Regelung)
und eine Abspielleiste. Neben den Elementen kann man noch wählen, ob diese über
oder unter dem Video liegen. (Kleiner Tipp: Testen Sie mal durch, welche der Skins
Ihnen zusagt.) Des Weiteren ist auch die Hintergrundfarbe der Skins frei wählbar (ich
habe mich an dieser Stelle für ein dunkles Grau entschieden).
SkinsSkins
ABBILDUNG 8.2
Eine Instanz der
FLVPlayback-
Komponente wurde auf
der Bühne platziert.
Welche Buttons zur
Abspielsteuerung angezeigt
und verwendet werden, kön-
nen Sie im Register PARAMETER
wählen.
ABBILDUNG 8.3
Wahl der Abspielbuttons
(skin) und der Hintergrund-
farbe (skinBackgroundColor).
An dieser Stelle empfehle ich
Ihnen, ein bisschen mit den
Parametern zu experimen-
tieren (beispielsweise erzeugt
das Setzen des Alphakanals
skinBackgroundAlpha
auf den Wert 0.7 einen
besseren Effekt als der
Wert 1, da so das Video im
Hintergrund noch sichtbar
bleibt).
K A P I T E L 8380
Um für ActionScript Zugriff auf die Komponenten-Instanz zu erhalten, müssen wir
der Komponente noch einen Instanznamen zuweisen:
ABBILDUNG 8.4
Zuweisen eines Instanz-
namens für die zuvor
auf der Bühne platzierte
Komponente
Wählen Sie für die Bühne eine Größe von 600x500 Pixel und legen Sie die FLV-
Playback-Komponente mittig auf die Bühne (aus X-Richtung gesehen) und an die
Y-Position 10 Pixel. Als Größe der FLVPlayback-Komponente habe ich 512x416 Pixel
gewählt:
ABBILDUNG 8.5
Alle Vorkehrungen sind
getroffen (Bühnengröße
600x500 Pixel, Größe der
FLVPlayback-Komponente
512x416 Pixel) – kümmern
wir uns um die Videos.
Die FLVPlayback-Komponente per ActionScript erstellen
Wie oben bereits erwähnt, kann eine FLVPlayback-Komponente auch zur Laufzeit
erzeugt werden. Voraussetzung dafür ist, dass sich die Komponente bereits in der
Bibliothek befindet. Dies bewerkstelligt man am einfachsten, indem man das Kompo-
nentenfenster öffnet und die entsprechende Komponente in die Bibliothek zieht:
V I D E O P L AY E R ( A C T I O N S C R I P T 3 . 0 ) 381
Diese Vorgehensweise mit ActionScript bedeutet zwar etwas mehr an Code, ist dafür
flexibler und für Programmierer zumeist „sympathischer“. Natürlich können Sie auf
alle Eigenschaften zugreifen, die die FLVPlayback-Komponente für uns bereithält.
Sehen wir uns die nötigen Schritte an:
Zunächst benötigt man einmal die Klasse FLVPlayback, die sich innerhalb der
fl.video-Klasse befindet. Da wir aus dieser Klasse noch weitere Klassen benöti-
gen, importieren wir idealerweise gleich die gesamte Klasse fl.video:
import fl.video.*;
Danach definiert man eine neue FLVPlayback-Instanz:
var myVideoplayer:FLVPlayback = new FLVPlayback();
Ist dies getan, kann man sofort auf sämtliche Eigenschaften der Instanz
myVideoplayer zugreifen. Im Folgenden lege ich jede Eigenschaft fest, die wir
auch im vorigen Abschnitt festgelegt haben, jedoch dort noch über die Parameter
der Komponente:
X- und Y-Position: myVideoplayer.x = 44; myVideoplayer.y = 10;
Breite und Höhe: myVideoplayer.width = 512; myVideoplayer.height
= 418;
Auto-Play deaktivieren: myVideoplayer.autoPlay = false;
Skin zuweisen: myVideoplayer.skin = "SkinOverAllNoVolNoCaptionNo-
Full.swf"; myVideoplayer.skinBackgroundAlpha = 0.7; myVideoplay-
er.skinBackgroundColor = 0x333333;
u
u
u
u
u
u
u
ABBILDUNG 8.6
Die FLVPlayback-
Komponente wird in der
Bibliothek der Flash-
Anwendung benötigt
– ansonsten ist es auch mit
ActionScript nicht möglich,
dynamisch eine Instanz
davon zu erzeugen.
K A P I T E L 8382
Alle diese Schritte würden uns nicht viel helfen, würden wir unser virtuelles Display-
Objekt nicht noch unserer Bühne zuweisen:
Display-Objekt der Bühne (oder einem anderen Objekt) zuweisen: this.
addChild(myVideoplayer);
Vergleichen Sie beide Vorgehensweisen (Arbeiten mit Komponenten direkt auf der
Bühne oder Erzeugen einer Komponenten-Instanz per ActionScript) – Sie werden
feststellen, dass sie ein identisches Ergebnis liefern. Welche Variante Sie bevorzugen, ist
Ihnen überlassen – das Ergebnis ist gleichwertig.
Die eben dargestellte Variante ist auf der Buch-CD im aktuellen Kapitel unter dem
Namen videoplayer_02a.flv zu finden. Da wir noch keine Videoquelle zugewiesen
haben, wird das Beispiel zwar eine Playback-Komponente erzeugen, aber eben kein
Video darstellen. In den nächsten Ausführungen entwickeln wir das Beispiel immer
weiter, sodass Sie den Fortschritt gut mitverfolgen können.
Damit sind wir mal fürs Erste gerüstet und können uns um die Videodatei kümmern.
8.3.2 Videos im FLV-Format
Nun, an dieser Stelle stellt sich zunächst einmal die Frage, von welchen Vorausset-
zungen wir ausgehen können:
1. Das Video wird bereits als FLV-Datei geliefert:
In seltenen Fällen kann es vorkommen, dass Sie als Webentwickler bereits fertige
FLV-Dateien (vom Kunden) zur Verfügung gestellt bekommen. In diesem Fall
müssen wir keine vorbereitenden Maßnahmen mehr treffen. Gehen wir einmal
davon aus, dass dies die Ausnahme ist.
2. Sie selbst sind der Videoproduzent:
Für den Fall, dass Sie selbst das Video produzieren, unterstützt Flash Ihr
Videobearbeitungsprogramm mit einem eigens mitgelieferten Plug-in namens
„FLV QuickTime Export Plug-in“ (bei Flash 8 gilt dies nur für die Professional-
Variante), sofern Sie mit einem der folgenden Videobearbeitungsprogramme
arbeiten:
Adobe After Effects (Windows und Macintosh)
Apple Final Cut (Macintosh)
Apple QuickTime Pro (Windows und Macintosh)
Avid XPress DV (Windows und Macintosh)
Mithilfe dieses Plug-ins sind Sie in der Lage, direkt aus Ihrem Video-
bearbeitungsprogramm eine entsprechende FLV-Datei zu exportieren.
u
u
u
u
u
V I D E O P L AY E R ( A C T I O N S C R I P T 3 . 0 ) 383
3. Sie besitzen das Video im Rohformat und müssen es selbst in ein FLV-Format
konvertieren:
In diesem Fall haben Sie zwei Möglichkeiten:
1. Sie verwenden die Importmöglichkeit von Flash: Hierzu erzeugen Sie
zunächst eine neue Flash-Datei, klicken dann auf DATEI/IMPORTIEREN/VIDEO
IMPORTIEREN… Danach öffnet sich der Importassistent für Videos.
2. Sie verwenden den Flash Video Encoder, der im Lieferumfang von Flash
CS3 Professional (oder Flash 8 Professional) enthalten ist. Sie finden ihn als
eigenständiges Programm, das zusätzlich zu Flash installiert wurde.
Bleibt nur zu klären, mit welchen Videoformaten Flash umgehen kann. Diese sind:
Macintosh mit installiertem QuickTime 7:
Audio Video Interleaved: AVI
Digital Video: DV
Motion Picture Experts Group: MPG, MPEG
QuickTime-Video: MOV
Windows mit installiertem DirectX ab Version 9:
Audio Video Interleaved: AVI
Motion Picture Experts Group: MPG, MPEG
QuickTime-Video: MOV (nur bei zusätzlich installiertem QuickTime 7)
Windows Media-Datei: WMV, ASF
Wenn Sie grundsätzlich mit dem QuickTime-Videoformat oder dem AVI-Format
arbeiten, sind Sie auf beiden gängigen Betriebssystemen also „auf der sicheren Seite“.
Achten Sie darauf, dass das Video möglichst unkomprimiert und somit in einer hohen
Qualität zur Verfügung steht. Sollten Sie beispielsweise ein bereits codiertes und
komprimiertes Video verwenden, so wurde durch die Komprimierung schon ein Teil
der Qualität eingebüßt. Nachdem jedoch Flash das Video erneut komprimieren wird,
hätte man eine doppelte Komprimierung – das schlägt sich dann in jedem Fall auf die
Qualität der Darstellung nieder.
u
u
u
u
u
u
u
u
u
u
K A P I T E L 8384
Variante 1 (Importieren eines Videos in eine leere Flash-Datei) hat gegenüber Variante
2 (Arbeiten mit dem Flash Video Encoder) den Nachteil, dass das Importieren von
Videos im Allgemeinen sehr viel Zeit in Anspruch nimmt und Sie in der Zwischenzeit
Flash nicht verwenden können. Da der Flash Video Encoder ein eigenständiges Pro-
gramm ist (und dieser noch dazu in der Lage ist, mehrere Videos hintereinander in
einem sogenannten „Batch-Modus“ abzuarbeiten), können Sie so weiterhin ungestört
mit Flash arbeiten und nebenbei die Videos konvertieren. Langer Rede kurzer Sinn:
Verwenden Sie den Flash Video Encoder. Infos zum Importieren von Videos in Flash
Erste Wahl: der
Flash Video
Encoder
Erste Wahl: der
Flash Video
Encoder
ABBILDUNG 8.7
Variante 1: Importieren eines
Videos in ein noch leeres
Flash-Dokument
ABBILDUNG 8.8
Variante 2: Verwenden des
Flash Video Encoder, der als
eigenständiges Programm
mit der Installation von Flash
installiert wird
V I D E O P L AY E R ( A C T I O N S C R I P T 3 . 0 ) 385
finden Sie im Flash CS3-Handbuch (PDF-Datei), das Sie von der Adobe-Website
(www.adobe.de) downloaden können.
Der Flash Video Encoder
Einmal gestartet, präsentiert sich der Flash Video Encoder wie in der nachfolgenden
Abbildung.
ABBILDUNG 8.9
Schön aufgeräumt und
übersichtlich – der Flash
Video Encoder wartet auf
Ihre Videos.
Über den Button HINZUFÜGEN… können Sie ein oder mehrere Videos auswählen, die
Sie konvertiert haben möchten. Einmal der Warteschlange (so nennt sich die Liste an
abzuarbeitenden Videos) hinzugefügt, können Sie ein oder mehrere Videos auswählen
und über den Button EINSTELLUNGEN… die entsprechenden Einstellungen für den
Export des Videos treffen:
K A P I T E L 8386
Betrachten wir die einzelnen Registerkarten dieses Fensters einmal ein bisschen
genauer:
Registerkarte KODIERUNGSPROFILE
In dieser Registerkarte haben Sie zunächst einmal die Möglichkeit, aus vordefinierten
Profilen zu wählen. Wie schon weiter oben erwähnt, würde ich Ihnen in jedem Fall
Flash 8 Profile empfehlen,da diese mit dem On2VP6 Codec arbeiten.Die Einstellung
„Flash 8 – Mittlere Qualität (400 Kbit/s)“ trifft unsere Erwartungen schon relativ gut.
Detaileinstellungen zu diesem Profil treffen Sie dann in den weiteren Registerkarten.
Registerkarte VIDEO
Hierin treffen Sie die Einstellungen zur Codierung derVideospur (die Einstellungen
zur Codierung der Audiospur finden Sie in der nächsten Registerkarte). Neben der
Qualität bzw. Datenrate (diese beiden Einstellungen hängen zusammen) und dem
Video-Codec ist vor allem das Kontrollkästchen ALPHAKANAL CODIEREN interessant:
Ist dieses Kontrollkästchen aktiviert, so werden eventuell im Video vorhandene
Alphakanäle (beispielsweise bei Blue-Box-Aufnahmen) transparent gemacht,
sodass Sie nach dem Einbinden der FLV-Datei den Hintergrund Ihrer SWF-Datei
durch das Video hindurch sehen.
Ebenso wichtig ist die Einstellung zur Bildrate: Wie schon weiter oben ausgeführt,
ist von einer Veränderung der Bildrate eines Videos abzuraten, da dadurch Bilder
im Video verloren gehen. Da in SWF-Dateien verknüpfte FLV-Videos nicht dieselbe
Bildrate aufweisen müssen wie die SWF-Datei selbst, rate ich zur Einstellung „Wie
Quelle“.
u
u
ABBILDUNG 8.10
In diesem Fenster können Sie
alle Einstellungen treffen, die
für den Export des Videos in
eine FLV-Datei notwendig
sind. Video-Copyright: TV1.at
– www.tv1.at.
V I D E O P L AY E R ( A C T I O N S C R I P T 3 . 0 ) 387
Das Kontrollkästchen DEINTERLACE wird verwendet, um das Video in ein
Vollbildformat umzuwandeln. Sämtliche weitere Information hierzu entnehmen
Sie bitte dem Flash-Handbuch.
Registerkarte AUDIO
Hierin bestimmen Sie die Datenrate, wie qualitativ hochwertig die Audiospur im
Video sein soll. Eine Datenrate von beispielsweise 96 Kbit/s (stereo) ist von relativ
hoher Qualität (CD-Qualität liegt bei etwa 128–160 Kbit/s) – eine etwas geringere
Bitrate ist für Videos im Internet immer noch ausreichend.
Registerkarte CUE-POINTS
Cue-Points sind eine sehr interessante Angelegenheit in Videos. Mithilfe von Cue-
Points sind Sie in der Lage, Ereignisse in der SWF-Datei zu erzeugen, in der die
FLV-Datei eingebunden ist. So sind Sie etwa in der Lage, gleichzeitig mit dem
Erreichen einer bestimmten Position im Video in der SWF-Datei Texte, Grafiken
etc. anzuzeigen. Ebenso eignen sich Cue-Points als Navigationspunkte innerhalb
des Videos. Mehr dazu weiter unten.
Registerkarte ZUSCHNEIDEN UND GRÖSSE ÄNDERN
Die letzte Registerkarte dient dazu, das Video in Größe (Cropping bzw. Breite und
Höhe) und Länge zu beschneiden.
Werfen wir noch einen etwas genaueren Blick auf die Registerkarte CUE-POINTS. Um
einen neuen Cue-Point hinzuzufügen, wählen Sie über die Abspielleiste zunächst ein-
mal die Position aus, die Sie im Video als Cue-Point wählen wollen (natürlich können
Sie beliebig viele Cue-Points setzen). Danach geben Sie einen Namen für den Cue-
Point sowie einen Typ (Ereignis oder Navigation) an. Zu guter Letzt haben Sie noch
die Möglichkeit, diesem Cue-Point einen oder mehrere Parameter inklusive Werten
zuzuweisen. Diese werden innerhalb der FLV-Datei gespeichert. Zusätzlich haben Sie
die Möglichkeit, die Cue-Points in einer separaten XML-Datei zu speichern.
Der Cue-Point Typ ist wie folgt zu wählen:
Typ „Ereignis“: Es wird ein ActionScript-Ereignis namens CUE_POINT ausgelöst.
Zumeist werden solche Cue-Points für die Synchronisation mit anderen Animatio-
nen in der Flash-Anwendung verwendet.
Typ „Navigation“: Es wird neben dem Auslösen des CUE_POINT-Ereignisses in der
FLV-Datei ein Schlüsselbild an dieser Position angelegt. Da zusätzliche Schlüs-
selbilder im Video die Gesamtqualität beeinträchtigen können, sollten derartige
Cue-Points nur dann verwendet werden, wenn dem User beim Abspielen eine Art
„Navigation“ zur Verfügung gestellt werden soll (beispielsweise wenn der User nach
einer bestimmten Stelle im Video suchen können soll). Dieser Typ von Cue-Point
wird im Allgemeinen zumeist verwendet.
u
u
u
u
u
K A P I T E L 8388
Beachten Sie, dass es zwischen ActionScript 2 und 3 Unterschiede in der Handhabung
von Cue-Points gibt. Darauf kommen wir weiter unten noch zu sprechen.
Unterschiede
bei Cue-Points
zwischen
ActionScript 2
und 3
Unterschiede
bei Cue-Points
zwischen
ActionScript 2
und 3
ABBILDUNG 8.11
Cue-Points in FLV-Dateien.
Video-Copyright: TV1.at
– www.tv1.at
In den meisten Fällen verwenden Sie Cue-Points vom Typ „Navigation“, um diese per
ActionScript später auch einfach anspringen zu können:
V I D E O P L AY E R ( A C T I O N S C R I P T 3 . 0 ) 389
Sind Sie mit den gesetzten Cue-Points zufrieden, so können Sie diese bei Bedarf in
Form einer XML-Datei mit Hilfe des Speichern-Buttons abspeichern:
ABBILDUNG 8.12
Die meist verwendeten
Cue-Points sind vom Typ
„Navigation“.
ABBILDUNG 8.13
Die Cue-Points werden in
Form einer (separaten) XML-
Datei abgespeichert.
K A P I T E L 8390
Der Inhalt der XML-Datei spricht für sich:
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<FLVCoreCuePoints Version="1">
<CuePoint>
<Time>0</Time>
<Type>navigation</Type>
<Name>Die schönste Monster</Name>
</CuePoint>
<CuePoint>
<Time>34355</Time>
<Type>navigation</Type>
<Name>Interview Andreas Wolfesberger</Name>
</CuePoint>
<CuePoint>
<Time>81017</Time>
<Type>navigation</Type>
<Name>Interview Zweitplatzierter</Name>
</CuePoint>
<CuePoint>
<Time>106143</Time>
<Type>navigation</Type>
<Name>Interview Rupert Kaspar</Name>
</CuePoint>
<CuePoint>
<Time>155369</Time>
<Type>navigation</Type>
<Name>Interview Gaetano Spagnolo</Name>
</CuePoint>
<CuePoint>
<Time>193314</Time>
<Type>navigation</Type>
<Name>Interview Andreas Czejka</Name>
</CuePoint>
<CuePoint>
V I D E O P L AY E R ( A C T I O N S C R I P T 3 . 0 ) 391
<Time>233823</Time>
<Type>navigation</Type>
<Name>Interview Freundin von Rupert Kaspar</Name>
</CuePoint>
<CuePoint>
<Time>264589</Time>
<Type>navigation</Type>
<Name>Interview Julia Roiss</Name>
</CuePoint>
<CuePoint>
<Time>286638</Time>
<Type>navigation</Type>
<Name>Interview Chris Zaiser</Name>
</CuePoint>
<CuePoint>
<Time>329711</Time>
<Type>navigation</Type>
<Name>Abschluss</Name>
</CuePoint>
</FLVCoreCuePoints>
Listing 8.1: Die XML-Datei beinhaltet sämtliche gesetzte Cue-Points mit Zeitpunkt des Cue-Point (angege-
ben in Millisekunden), Typ und Namen.
Diese XML-Datei hängt grundsätzlich nicht mit der FLV-Datei zusammen. Dies soll
bedeuten, dass Sie selbst auch eine derartige XML-Datei erstellen können bzw. eine
gegebene XML-Datei jederzeit ändern können. Derartige XML-Dateien werden bei
Bedarf zusätzlich zur FLV-Datei (und nicht gemeinsam mit ihr) in die SWF-Datei
geladen. Einzig die Syntax der XML-Daten muss erhalten bleiben.
Zurück zum Flash Video Encoder. Nachdem wir alle Einstellungen zum Video getrof-
fen haben und zurück in der Dateiübersichtsmaske sind, können Sie entweder weitere
Videos hinzufügen (und wieder die entsprechenden Einstellungen treffen) oder über den
Button WARTESCHLANGE STARTEN den Codiervorgang in Gang setzen. Flash arbeitet dann
alle in der Warteschlange befindlichen Videos ab und speichert diese im selben Verzeich-
nis wie die Quelldaten. Bedenken Sie bitte, dass der Codiervorgang mitunter relativ lange
dauern kann (dies ist auch abhängig davon, welches Format Ihre Quelldatei aufweist)
– beispielsweise dauerte bei mir das Codieren eines Videos mit einer Länge von etwa
5:30 Minuten im Format MP4 (Codierung: Video: h264, Audio: mp3) etwa 40 Minuten.
Dasselbe Video im QuickTime-Format dauerte bei der Codierung etwa 3 Minuten.
K A P I T E L 8392
8.3.3 Dynamisches Verknüpfen der FLVPlayback-
Komponente mit einem Video
Da wir neben dem reinen Anzeigen des Videos auch die Möglichkeit haben wollen,
das Video zu steuern (und somit auch alle Ereignisse, Eigenschaften und Methoden
der FLVPlayback-Komponente zu nutzen), laden wir zunächst einmal die zugehörigen
Klassen (sollten Sie die Komponente per ActionScript eingebunden haben, haben Sie
die benötigten Klassen bereits geladen):
import fl.video.*;
Danach weisen wir der Playback-Komponente (ihr Name war myVideoplayer) eine
Videoquelle zu – in diesem Fall liegt die Videoquelle im selben Verzeichnis wie die
SWF-Datei:
myVideoplayer.source = "FestaDucati2006.flv";
Mit diesen beiden Codezeilen hätten wir schon alle Arbeiten erledigt und wären somit
fertig. Ich möchte Ihnen jedoch an dieser Stelle noch einige Eventhandler zeigen, die
für die Arbeit mit Videos von Vorteil sein können:
VideoEvent-Klasse:
COMPLETE: wird ausgelöst, wenn das Video fertig abgespielt wurde
READY: wird ausgelöst, wenn das Video bereit zum Abspielen ist
Neben den beiden genannten Ereignissen existiert noch eine größere Liste an weiteren
Ereignissen, die Sie im Komponenten-Referenzhandbuch nachlesen können.
Ich möchte Ihnen an dieser Stelle zeigen, wie Sie die beiden Ereignisse verwenden kön-
nen. Offensichtlich ist zunächst das READY-Ereignis von Interesse, denn bevor dieses
Ereignis nicht aufgetreten ist, kann das Video auch nicht gestartet/verwendet werden.
In diesem Fall sollte natürlich die Abspielkonsole – die Skin – auch nicht sichtbar sein.
„Nicht sichtbar“ wäre im einfachsten Fall so zu realisieren, dass der Alphawert der Skin
zunächst auf den Wert 0 gesetzt wird und erst nach Eintreten des READY-Ereignisses
den vorgegebenen Wert von – in unserem Fall – 0.7 bekommt.
Hierfür sind drei Schritte notwendig:
1. Den Alphawert der Skin zunächst auf den Wert 0 setzen:
myVideoplayer.skinBackgroundAlpha = 0;
2. Einen Eventhandler definieren, der bei Auftreten des READY-Ereignisses den
Alphakanal auf 0.7 setzt:
function EReady(myEvent:VideoEvent):void {
myVideoplayer.skinBackgroundAlpha = 0.7;
}
u
u
u
V I D E O P L AY E R ( A C T I O N S C R I P T 3 . 0 ) 393
3. Den Eventhandler unserer FLVPlayback-Instanz zuweisen:
myVideoplayer.addEventListener(VideoEvent.READY, EReady);
Nach Auftreten des COMPLETE-Ereignisses wäre es beispielsweise nett, wenn dem User
eine entsprechende Meldung im Fenster ausgegeben wird. Hierzu ein Beispiel:
ABBILDUNG 8.14
Teilen Sie dem User zusätz-
lich mit, wann das Ende
eines Videos erreicht ist
(auch wenn er es vielleicht
in der Abspielleiste sehen
könnte ...). Video-Copyright:
TV1.at – www.tv1.at
Der eingeblendete Text befindet sich in einem MovieClip mcFinish, der als Instanz auf
der Bühne den Namen mcFinished erhalten hat (siehe Abbildung 8.15):
ABBILDUNG 8.15
Der MovieClip mcFinish
erhält als Instanzname
auf der Bühne den Namen
mcFinished.
K A P I T E L 8394
Um die Instanz zunächst auszublenden, wird die Eigenschaft visible auf den Wert
false gesetzt:
mcFinished.visible = false;
Bitte beachten Sie an dieser Stelle wieder den Unterschied von ActionScript 2.0 und
ActionScript 3.0: Trug die Eigenschaft in ActionScript 2.0 noch den Namen _visible
(inklusive Unterstrich „_“ am Anfang) und war eine Eigenschaft innerhalb der Movie-
Clip-Klasse, so wurde der Unterstrich in ActionScript 3.0 entfernt und die Eigenschaft
in die DisplayObject-Klasse verschoben.
Bei Auftreten des Ereignisses COMPLETE wird die Instanz wieder eingeblendet:
function EComplete(myEvent:VideoEvent):void {
mcFinished.visible = true;
}
myVideoplayer.addEventListener(VideoEvent.COMPLETE, EComplete);
Listing 8.2: Sobald das COMPLETE-Ereignis auftritt, wird die MovieClip-Instanz mcFinished
eingeblendet.
Das entsprechende Beispiel finden Sie auf der Buch-CD unter dem Namen videoplay-
er_01a.flv im Verzeichnis des aktuellen Kapitels.
Im Hinblick auf die weitere Entwicklung des Videoplayers werden wir das COMPLETE-
Ereignis dahingehend verwenden, dass nach dem Abspielen eines Videos das nächste
Video gestartet wird.
8.3.4 Schritt 1: Abspielen einer Liste von Videos
(Array)
Nachdem wir es nun vollbracht haben, ein Video dynamisch einzubinden, kann das
nächste Ziel nur sein, mit einer Liste von Videos zu arbeiten. Mit anderen Worten
wollen wir Folgendes:
Nachdem ein Video fertig abgespielt wurde, soll das nächste Video abgespielt wer-
den.
Es soll die Möglichkeit bestehen, aus einer Liste von Videos eine Auswahl zu treffen
und somit ein Video direkt auszuwählen.
Es soll von einem Video zum nächsten bzw. zum vorigen gesprungen werden
können.
Punkt eins ist relativ einfach realisiert, nachdem wir zuvor gerade das COMPLETE-
Ereignis kennengelernt haben. Der zweite Punkt wird über eine ComboBox realisiert,
Punkt drei über entsprechende Tasten in der Skin.
u
u
u
_visible in
ActionScript
2.0, visible in
ActionScript 3.0
_visible in
ActionScript
2.0, visible in
ActionScript 3.0
V I D E O P L AY E R ( A C T I O N S C R I P T 3 . 0 ) 395
Bevor wir die Punkte nacheinander angehen, müssen wir aber erst mal für eine Video-
liste und einen Index sorgen:
var videoList:Array = new Array ("videos/Dueringer.flv"," videos/
Faak2005.flv"," videos/FestaDucati2006.flv"," videos/Juvenile.flv");
var videoIndex:uint = 0;
Listing 8.3: videoList und videoIndex definieren die Liste an abzuspielenden Videos und den Index
des Videos aus der Liste, das gerade abgespielt wird.
Den Index verwenden wir dazu, um uns zu merken, welches Video aus der Liste gerade
abgespielt wird (oder werden soll) – der Index zeigt also genau auf die Position des
aktuellen Videos im Array videoList.
So, dann gehen wir die drei Punkte aus der obigen Liste an. Punkt eins war die Forde-
rung nach dem Abspielen des nächsten Videos, sobald ein Video komplett abgespielt
wurde. Stellt sich nur noch die Frage, was passieren soll, wenn das Ende der Videoliste
erreicht ist ... Wir handhaben diesen Fall derart, dass wir in einer Variablen loopAtEnd
uns diesen Fall offen lassen: Ist loopAtEnd==true, so wird beim Erreichen des Endes
der Liste das erste Video in der Liste abgespielt (und somit eine Schleife erzeugt). Ist
loopAtEnd==false, beenden wir das Abspielen am Ende der Liste und blenden die
MovieClip-Instanz mcFinished ein.
Sämtliche oben genannte Änderungen betreffen den Eventhandler EComplete:
var loopAtEnd:Boolean = true;
function EComplete(myEvent:VideoEvent):void {
videoIndex++;
if(videoIndex==videoList.length) {
if(loopAtEnd) { videoIndex = 0; }
else { mcFinished.visible = true; return; }
}
myVideoplayer.source = videoList[videoIndex];
}
Listing 8.4: Änderungen an dem Eventhandler loopAtEnd
Bei Eintreten des Ereignisses COMPLETE wird die Funktion EComplete aufgerufen.
Hierin wird zunächst der videoIndex um eins erhöht und kontrolliert, ob so even-
tuell das Ende der Liste erreicht wurde. Ist dies der Fall, müssen wir überprüfen, ob
wir in der Videoliste wieder von vorne beginnen (loopAtEnd==true) oder nicht
(loopAtEnd==false). Wenn ja, wird also der Index (videoIndex) auf null gesetzt.
Bei nein blenden wir mcFinished ein und brechen die Funktion mit return ab. Sollte
das Ende der Liste noch nicht erreicht gewesen sein oder die Liste wieder von vorne
K A P I T E L 8396
abgespielt werden, weisen wir der FLVPlayback-Instanz myVideoplayer eine neue
Quelle aus der Liste zu und weiter geht’s mit Abspielen ...
Auf zur nächsten Aufgabe: Aus der Liste an Videos soll eine Kombo-Box (ComboBox-
Komponente) gefüllt werden. Wie auch schon zuvor werden wir in einem Beispiel
(dasjenige mit der 1 im Dateinamen: videoplayer_01x.fla) eine Komponente auf die
Bühne ziehen und im anderen Beispiel (dasjenige mit der 2 im Dateinamen: videoplay-
er_02x.fla) die Komponente mit ActionScript erstellen.
In den User Interface-Komponenten finden Sie die ComboBox-Komponente. Plat-
zieren Sie eine Instanz auf der Bühne an der Position (44/436), ändern Sie die Breite
auf 200 Pixel und weisen Sie ihr den Namen myCombobox zu. Um die ComboBox mit
Daten zu füllen, benötigen wir dennoch ActionScript:
var theObject:Object = new Object();
for(var i:Number = 0; i<videoList.length; i++) {
theObject = { label:videoList[i], data:i };
myCombobox.addItem(theObject);
}
Listing 8.5: Listing zum Generieren der Inhalte der ComboBox-Instanz myCombobox
Das Füllen der Daten erfolgt mithilfe eines Objekts, das eine klare Struktur aufweist:
{ label:BESCHRIFTUNG, data:WERT }
label bezeichnet die Beschriftung, die in der ComboBox abgelesen werden kann.
data bestimmt den Wert der ComboBox, der beim Auswählen eines Eintrags
gesetzt wird.
Der Code kann entweder sehr ausführlich geschrieben werden (wie im obigen Script
dargestellt) oder auch sehr kompakt:
for(var i:Number = 0; i<videoList.length; i++) {
myCombobox.addItem({ label:videoList[i], data:i });
}
Listing 8.6: Alternative Kurzschreibweise von <?xml version="1.0"
encoding="ISO-8859-1" standalone="yes" ?>
<Playlist rootDir="videos" autostart="0">
<File src="FestaDucati2006.flv">
<Author>www.tv1.at</Author>
<Content>Festa Ducati 2006</Content>
<Date>2006-07-08</Date>
</File>
<File src="Faak2005.flv">
u
u
V I D E O P L AY E R ( A C T I O N S C R I P T 3 . 0 ) 397
<Author>www.tv1.at</Author>
<Content>Motorradtreffen Faak am See 2005</Content>
<Date />
</File>
<File src="Tattooconvention.flv">
<Author>www.tv1.at</Author>
<Content>Tattoo Convention 2006</Content>
<Date />
</File>
<File src=»Juvenile.flv»>
<Author>www.tv1.at</Author>
<Content>HipHop-Festival Wels</Content>
<Date />
</File>
<File src="Dueringer.flv">
<Author>www.tv1.at</Author>
<Content>Dueringer ab 4.99</Content>
<Date />
</File>
</Playlist>
Listing 8.6.
Das Füllen der ComboBox hätten wir geschafft, jedoch hilft uns das wenig, wenn die
Auswahl eines Videos in der ComboBox nichts bewirkt. Mit anderen Worten: Die
ComboBox muss ein bisschen „Intelligenz“ erhalten: Sobald eine Änderung in der
Auswahl der ComboBox erfolgt, soll eine Funktion aufgerufen werden, die das neu
gewählte Video abspielt. Ein geeigneter Event für diese Aufgabe ist CHANGE, das bei
jeder Änderung der Auswahl in einer ComboBox auftritt:
function EChange(myEvent:Event):void {
videoIndex = myCombobox.selectedIndex;
myVideoplayer.source = videoList[videoIndex];
myVideoplayer.play();
}
myCombobox.addEventListener(Event.CHANGE, EChange);
Listing 8.7: Der Eventhandler für das CHANGE-Ereignis setzt den Index auf den gewählten Eintrag der
ComboBox, setzt die Videoquelle auf die entsprechende Videodatei aus der Liste und lässt das Video
abspielen.
K A P I T E L 8398
Der Ablauf ist relativ einfach und übersichtlich:
1. Es wird eine Funktion EChange definiert, die bei Aufruf den Wert der ComboBox
myCombobox ausliest und den Index (videoIndex) auf genau diesen Wert setzt.
2. Aus der Videoliste videoList wird die entsprechende URL zur Videodatei gelesen
und der FLVPlayback-Instanz myVideoplayer als Quelle zugewiesen.
3. Das Video wird abgespielt (myVideoplayer.play();).
Wie würde der Code aussehen, würden wir die ComboBox per ActionScript generie-
ren? Nun, auch nicht sehr viel aufwändiger. Lediglich die folgenden Zeilen müssten
den Listings Listing 8.6 und Listing 8.7 vorangestellt werden, um den ActionScript-
Part abzudecken:
import fl.controls.ComboBox;
var myCombobox:ComboBox = new ComboBox();
myCombobox.move(44,436);
myCombobox.width = 200;
addChild(myCombobox);
Listing 8.8: Generieren einer ComboBox per ActionScript. Alternativ hätten Sie die ComboBox auch über die
Eigenschaften x und y verschieben können (myCombobox.x = 44; myCombobox.y = 436).
Wie auch im Fall der FLVPlayback-Komponente muss die ComboBox-Komponente
von der Komponentenübersicht in die Bibliothek gezogen werden, um im Weiteren für
ActionScript verfügbar zu sein:
ABBILDUNG 8.16
Um per ActionScript zur
Laufzeit eine Komponente
erstellen zu können, muss
sich diese in der Bibliothek
befinden.
V I D E O P L AY E R ( A C T I O N S C R I P T 3 . 0 ) 399
Folgendes ist also geschehen: Die ComboBox-Komponente wurde für den Einsatz mit
ActionScript zur Laufzeit bereitgestellt. Diese Informationen finden Sie, wenn Sie die
Eigenschaften der ComboBox in der Bibliothek aufrufen:
ABBILDUNG 8.17
In den Eigenschaften der
ComboBox erfahren Sie, dass
diese für den „Export für
ActionScript“ bereitgestellt
wurde.
Es wird Zeit, dass wir mal ein bisschen rekapitulieren. Mittlerweile existieren in
unserem Script schon zwei Aufrufe für das Zuweisen einer Quelle und das Abspielen
des aktuellen Videos. Besser wäre es, wir würden eine Funktion schreiben, welche diese
Aufgabe erledigt, dass unser Code so übersichtlicher wird. Die Daten bis zu diesem
Punkt finden Sie in der Datei videoplayer_01b.fla (sowie videoplayer_02b.fla), die „bes-
ser strukturierte und aufgeräumte Datei“ ist videoplayer_01c.fla (videoplayer_02c.fla).
Die neue Funktion loadVideo zum Laden und Abspielen eines Videos erhält zwei
Parameter übergeben:
function loadVideo(increaseIndex:uint, playVideo:Boolean):void {
...
}
increaseIndex: ein numerischer Wert, um wie viel der aktuelle videoIndex
erhöht oder verringert wird. (Typischerweise ist dieser Wert gleich eins, da nach
einem komplett abgespielten Video das nächste Video der Liste abgespielt wird.)
playVideo: eine boolesche Variable, die angibt, ob das nun geladene Video auch
gleich gestartet werden soll.
u
u
K A P I T E L 8400
Die Funktion selbst wird auch dafür Sorge tragen, dass, sofern das Ende der Videoliste
erreicht ist, entweder das Abspielen beendet oder von vorne begonnen werden soll
(siehe hierzu auch Listing 8.4):
function loadVideo(increaseIndex:uint, playVideo:Boolean):void {
videoIndex+=increaseIndex;
if(videoIndex==videoList.length) {
if(loopAtEnd) { videoIndex = 0; }
else { mcFinished.visible = true; return; }
}
myVideoplayer.source = videoList[videoIndex];
if(playVideo) { myVideoplayer.play(); }
}
Listing 8.9: Die neu eingeführte Funktion entspricht im Wesentlichen Listing 8.4, jedoch wird videoIn-
dex um den übergebenen Wert von increaseIndex erhöht und das Video nur dann abgespielt, wenn
playVideo==true ist.
Somit verändern sich die Eventhandler für die ComboBox (Ereignis CHANGE) und die
FLVPlayback-Komponente (Ereignis COMPLETE):
function EChange(myEvent:Event):void {
videoIndex = myCombobox.selectedIndex;
loadVideo(1,true);
}
function EComplete(myEvent:VideoEvent):void {
loadVideo(1,true);
}
Listing 8.10: Änderungen in den Eventhandlern CHANGE und COMPLETE
Zu guter Letzt ändert sich auch die letzte Zeile des Scripts von:
myVideoplayer.source = videoList[videoIndex];
in:
loadVideo(0,false);
V I D E O P L AY E R ( A C T I O N S C R I P T 3 . 0 ) 401
8.3.5 Schritt 2: Abspielen einer Liste von Videos
(XML)
Alternativ zu einer fest vorgegebenen Liste an Videos bietet sich XML als „Listen-
Geber“ an.
Die XML-Datei können wir im Wesentlichen in ihrer Struktur der Audio-Jukebox
entnehmen – in diesem Workshop haben wir uns schon sehr ausführlich mit der Idee
des Aufbaus der XML-Struktur befasst.
Werfen wir noch einmal einen kurzen Blick auf die Struktur:
<?xml version="1.0" encoding="ISO-8859-1" standalone="yes" ?>
<Playlist rootDir="videos" autostart="0">
<File src="FestaDucati2006.flv">
<Author>www.tv1.at</Author>
<Content>Festa Ducati 2006</Content>
<Date>2006-07-08</Date>
</File>
<File src="Faak2005.flv">
<Author>www.tv1.at</Author>
<Content>Motorradtreffen Faak am See 2005</Content>
<Date />
</File>
<File src="Tattooconvention.flv">
<Author>www.tv1.at</Author>
<Content>Tattoo Convention 2006</Content>
<Date />
</File>
<File src=»Juvenile.flv»>
<Author>www.tv1.at</Author>
<Content>HipHop-Festival Wels</Content>
<Date />
</File>
<File src="Dueringer.flv">
<Author>www.tv1.at</Author>
<Content>Dueringer ab 4.99</Content>
<Date />
K A P I T E L 8402
</File>
</Playlist>
Listing 8.11: Die XML-Struktur für die Playlist unseres Videoplayers (Beispieldatei playlist.txt). Sämtliche
Videos sind im Verzeichnis „videos“ untergebracht.
Wie schön öfter erwähnt, ist einer der großen Vorteile von XML-Dateien, dass es (fast)
keine Vorgaben bezüglich des Aufbaus gibt, also auch kein „richtig“ und „falsch“. Aus
diesem Grund ist auch die obig dargestellte Struktur nur eine von vielen Möglich-
keiten. Alternativ dazu könnte man beispielsweise auch das Attribut src als eigenes
Tag führen oder die Tags <Author>, <Content> und <Date> als Attribute führen:
...
<File>
<src>Video01.flv</src>
<Author>Ducati Club Linz</Author>
<Content>1. Mai Ausfahrt 2007</Content>
<Date>2007-05-01</Date>
</File>
...
Listing 8.12: Variante 1 ...
...
<File src="Video01.flv" Author="Ducati Club Linz" Content="1. Mai
Ausfahrt 2007" Date="2007-05-01 />
...
Listing 8.13: ... und Variante 2. Welche Variante Sie bevorzugen, liegt an Ihnen.
Da wir die in Abschnitt 8.3.4 erzeugte Liste nun nicht mehr in der damaligen Form
benötigen, ändern wir die Zeile
var videoList:Array = new Array("videos/Dueringer.flv","videos/Faak2005.
flv","videos/FestaDucati2006.flv","videos/Juvenile.flv");
in
var videoList:Array = new Array();
um. Somit ist das Array derzeit noch leer – das Füllen des Arrays erledigen wir, nach-
dem die XML-Daten aus der entsprechenden Datei gelesen wurden. Weiter unten wird
die Definition des Arrays von dieser Stelle entfernt und an eine andere Stelle im Code
gesetzt. Wie eine XML-Datei gelesen wird, haben wir sehr ausführlich im Kapitel „Ser-
verseitiger Datenaustausch“ gesehen – nun wollen wir die Früchte dessen ernten und
das Laden von Videolisten über eine XML-Datei spielen.
„Richtige“ und
„falsche“ XML-
Strukturen?
„Richtige“ und
„falsche“ XML-
Strukturen?
V I D E O P L AY E R ( A C T I O N S C R I P T 3 . 0 ) 403
Das Grundgerüst stellt sich wie folgt dar:
System.useCodePage = true;
var myLoader:URLLoader = new URLLoader();
var theURL:String = "URL_ZUR_XML-DATEI";
var myURL:URLRequest = new URLRequest(theURL);
var myXML:XML;
function EXMLComplete(myEvent:Event):void {
myXML = new XML(myEvent.target.data);
myXML.ignoreWhitespace = true;
...
}
myLoader.addEventListener(Event.COMPLETE, EXMLComplete);
myLoader.load(myURL);
Listing 8.14: Grundgerüst zum Laden von XML-Daten aus einer gegebenen Datei
Die wesentlichen Punkte sind also folgende:
Zeichensatz auf den in der XML-Datei definierten setzen: System.useCodePage
= true;
URLLoader-Instanz zum Laden von (textbasierten) Daten anlegen: myLoader
URLRequest-Instanz zum Angeben einer Datenquelle anlegen: myURL
XML-Objekt definieren, das die geladenen Daten erhält: myXML
Eventhandler definieren, der reagieren soll, sobald die Daten aus der Quelle geladen
wurden: EXMLComplete.
Angewandt auf unser Beispiel muss zunächst einmal nur die Variable theURL gesetzt
werden:
var theURL:String = "playlist.txt";
Listing 8.15: Es soll die Datei playlist.txt geladen werden.
Der einfachste (aber manchen Hardcore-Programmierern eher widerstrebende) Weg
zum Laden von XML-Daten ist der, dass der Ladevorgang der XML-Daten in einem
Bild der Zeitleiste (oder sogar einer eigenen Szene) und das Abspielen der Videos in
einem zweiten Bild erfolgt:
u
u
u
u
u
K A P I T E L 8404
Eine weitere Alternative wäre:
1. XML-Daten laden
2. Erst nach dem vollständigen Laden der XML-Daten den Bildschirm inklusive
FLVPlayback-Komponente, ComboBox etc. aufbauen
Da ich jedoch großen Wert darauf lege, dass die Programmierung noch nachvollzieh-
bar und übersichtlich bleibt, möchte ich trotz aller Unkenrufe aus der Hardcore-Pro-
grammierer-Abteilung diesen Weg beschreiten.
Vor den derzeit vorhandenen Bildern in der Flash-Datei legen Sie bitte daher ein neues
Bild an (siehe Abbildung 8.18). In der Elementeebene wurde lediglich der statische
Text „Lade XML-File – bitte einen Moment Geduld…“ eingefügt. Die Aktionenebene
erhält folgenden Code:
// ---- XML-Daten laden: ----
System.useCodePage = true;
var videoList:Array = new Array();
var myLoader:URLLoader = new URLLoader();
var theURL:String = "playlist.txt";
var myURL:URLRequest = new URLRequest(theURL);
ABBILDUNG 8.18
Laden der XML-Daten und
Abspielen der Videos ist
in der Zeitleiste in Bildern
getrennt.
V I D E O P L AY E R ( A C T I O N S C R I P T 3 . 0 ) 405
var myXML:XML;
function EXMLComplete (myEvent:Event):void {
myXML = new XML(myEvent.target.data);
myXML.ignoreWhitespace = true;
for(var i:uint=0; i<myXML.File.length(); i++) {
videoList[i] = myXML.@rootDir+"/"+myXML.File[i].@src;
}
gotoAndStop(2);
}
myLoader.addEventListener(Event.COMPLETE, EXMLComplete);
myLoader.load(myURL);
// ENDE XML-Daten laden: ----
stop();
Listing 8.16: Vollständiges Listing der Aktionenebene (Bild 1)
Zu dem in Listing 8.14 vorgestellten Gerüst sind folgende Fragmente hinzugekom-
men:
Das Anlegen der Videoliste wurde von Bild 2 der Aktionenebene in Bild 1 über-
nommen:
var videoList:Array = new Array();
Innerhalb des Eventhandler EXMLComplete werden in einer for-Schleife alle
File-Knoten durchgegangen und deren Attribut src (aus dem Tag <Playlist>,
welches dem Objekt myXML entspricht, da es das Root-Element ist) zusammen mit
dem Attribut rootDir in das Array videoList geschrieben.
Abschließend wird nach dem Füllen des Arrays auf das zweite Bild der Zeitleiste
gesprungen.
Im zweiten Bild der Zeitleiste musste aus der Aktionenebene lediglich die Definition
der Videoliste gelöscht werden. So weit sollte alles klappen – mehr ist vorerst nicht zu
tun:
u
u
u
K A P I T E L 8406
Details zum Video anzeigen
Aus Listing 8.11 können Sie entnehmen, dass neben der Videoquelle noch mehr an
Informationen zum Video in der XML-Datei versteckt sind, die es darzustellen gilt.
Beispielsweise könnte man die ComboBox aus Abbildung 8.19 mit dem Videotitel
(<Content>Tattoo Convention 2006</Content>) statt dem Namen der Quellda-
tei füllen. Auch sollten der Autor und das Aufnahmedatum (sofern vorhanden) nicht
verschwiegen werden.
Bisher war unsere Vorgehensweise folgende:
Die Beschriftung (label) innerhalb der ComboBox beinhaltet den Namen der
Video-Quelldatei.
Der Wert (data) der Combobox war der Index des Videos in der Videoliste video-
List.
Den Wert werden wir so beibehalten, die Beschriftung soll sich auf den Videotitel
ändern. Hierzu müssen wir jedoch ein bisschen weiter ausholen, da wir den Videotitel
bisher noch gar nicht gespeichert haben. Daher wird unsere videoList eine kleine
Änderung durchmachen müssen: Anstatt nur die Videoquelle zu speichern, speichern
wir die videoList gar nicht mehr, sondern greifen direkt auf die eingelesenen XML-
Daten in myXML zu! Dank ActionScript 3.0 ist das nun denkbar einfach.
u
u
Titel statt
Videoquelle in
der ComboBox
anzeigen
Titel statt
Videoquelle in
der ComboBox
anzeigen
ABBILDUNG 8.19
Das Laden der XML-Daten
war erfolgreich – alles
andere ist wie gehabt.
V I D E O P L AY E R ( A C T I O N S C R I P T 3 . 0 ) 407
Im Eventhandler zum Laden der XML-Daten entfernen wir folgende Teile komplett:
var videoList:Array = new Array();
Listing 8.17: Das Array wird nicht mehr benötigt.
for(var i:uint=0; i<myXML.File.length(); i++) {
videoList[i] = myXML.@rootDir+"/"+myXML.File[i].@src;
}
Listing 8.18: Dieser Teil wird aus dem Eventhandler EXMLComplete vollständig entfernt.
Beim Füllen der ComboBox (Bild 2 der Aktionenebene) ändern wir die for-Schleife
von
for(var i:Number = 0; i<videoList.length; i++) {
myCombobox.addItem({ label:videoList[i], data:i });
}
in
for(var i:Number = 0; i<myXML.File.length(); i++) {
myCombobox.addItem({ label:myXML.File[i].Content, data:i });
}
Listing 8.19: Anstatt auf die videoList zuzugreifen, nehmen wir gleich den Inhalt der XML-Daten aus
myXML.
myXML.File greift auf alle Knoten mit dem Namen „File“ zu, die wir Eintrag für Ein-
trag auslesen, um aus diesen Knoten jeweils auf den Sub-Knoten namens „Content“
zuzugreifen.
Am Laden und Abspielen der Videodaten muss auch noch ein bisschen gefeilt werden,
da dort immer noch auf die Videoliste videoList zugegriffen wird. In der Funktion
loadVideo in Bild 2 der Funktionenebene müssen zwei Änderungen vorgenommen
werden. Aus den Zeilen
if(videoIndex==videoList.length) {
...
myVideoplayer.source = videoList[videoIndex];
wird
if(videoIndex==myXML.File.length()) {
...
myVideoplayer.source = myXML.@rootDir+"/"+myXML.File[videoIndex].@src;
Listing 8.20: Aus videoList.length wird myXML.File.length() und aus dem Inhalt von
videoList[i] wird myXML.@rootDir+"/"+myXML.File[videoIndex].@src.
K A P I T E L 8408
Letzten Endes wurde das Array videoList nicht mehr benötigt, da myXML mehr oder
weniger auch als Liste angesehen werden kann. Da der Zugriff auf XML-Daten seit
ActionScript 3.0 nun denkbar einfach ist, sollte man davon auch Gebrauch machen.
ABBILDUNG 8.20
Nun ist der Inhalt der
ComboBox auch informa-
tiver und sprechender.
Autor und Aufnahmedatum anzeigen
Kümmern wir uns noch um die Ausgabe von Autor und Aufnahmedatum. Hier offen-
baren sich mehrere mögliche Wege:
Es werden dynamische Textfelder angelegt und diese beim Laden einer Videoquelle
mit Inhalt gefüllt.
Die Textfelder werden nicht vorab angelegt, sondern bei jedem Laden einer Video-
quelle neu erzeugt.
Sämtliche Informationen werden in einer TextArea-Komponente angezeigt.
Wir werden den dritten Weg einschlagen und eine TextArea-Komponente verwen-
den, die wir einerseits (videoplayer_01e.fla) direkt auf der Bühne platzieren und ande-
rerseits (videoplayer_02e.fla) per ActionScript generieren.
Im Fall der direkten Platzierung der TextArea-Komponente auf der Bühne geben wir
der Instanz den Namen „videoinfos“ und stellen folgende Eigenschaften um:
editable: false
horizontalScrollPolicy: off
u
u
u
u
u
V I D E O P L AY E R ( A C T I O N S C R I P T 3 . 0 ) 409
Breite: 300 Pixel
Höhe: 40 Pixel
Position (x/y): (256/436)
u
u
u
Die Funktion loadVideo in Bild 2 der Funktionenebene erweitern wir entsprechend
um die Zeile
function loadVideo(increaseIndex:uint, playVideo:Boolean):void {
videoIndex+=increaseIndex;
if(videoIndex==myXML.File.length()) {
if(loopAtEnd) { videoIndex = 0; }
else { mcFinished.visible = true; return; }
}
videoinfos.text = "Author: "+myXML.File[videoIndex].Author+"
nAufnahmedatum: "+myXML.File[videoIndex].Date;
myVideoplayer.source = myXML.@rootDir+"/"+myXML.File[videoIndex].@src;
if(playVideo) { myVideoplayer.play(); }
}
Listing 8.21: In die TextArea-Instanz „videoinfos“ werden Autor und Aufnahmedatum geschrieben.
Würden wir die TextArea-Komponente hingegen per ActionScript einbinden, müss-
ten wir folgendermaßen vorgehen:
ABBILDUNG 8.21
Eine Instanz der TextArea-
Komponente wurde auf der
Bühne in der Elementeebene
eingefügt.
K A P I T E L 8410
TextArea-Komponente in die Bibliothek ziehen
Folgenden ActionScript-Code in das zweite Bild der Aktionenebene einbauen:
...
// ---- TextArea-Komponente: ----
import fl.controls.TextArea;
import fl.controls.ScrollPolicy;
var videoinfos:TextArea = new TextArea();
videoinfos.editable = false;
videoinfos.horizontalScrollPolicy = ScrollPolicy.OFF;
videoinfos.width = 300;
videoinfos.height = 40;
videoinfos.move(256,436);
addChild(videoinfos);
// ENDE TextArea-Komponente: ----
loadVideo(0,false);
Listing 8.22: Die zwischen den Kommentaren gelisteten Zeilen sind in der Aktionenebene in Bild 2 hinzuge-
fügt worden.
Zunächst werden die Klassen TextArea und ScrollPolicy aus der Klasse
fl.controls hinzugeladen, wobei die erste für das Ansprechen der TextArea und die
zweite für das Setzen von Scrollparametern für eine eventuelle Scrollbar zuständig ist.
Danach wird eine Instanz der TextArea-Komponente erzeugt (videoinfos) und die
benötigten Eigenschaften und Parameter werden gesetzt. Abschließend fügt man die
Instanz noch dem DisplayObject zu (addChild(videoinfos);) und hat es auch
schon wieder geschafft!
Die entsprechenden Dateien finden Sie wie üblich auf der Buch-CD unter den Namen
videoplayer_01e.fla und videoplayer_02e.fla.
XML-Datei serverseitig aus einer Datenbank generieren
Nehmen wir folgenden Fall an: In einer Datenbank wurde Ihnen eine Playlist zuge-
wiesen, welcher wiederum eine Liste an Videos angehören. Ein PHP-Script erzeugt
bei Übergabe einer Playlist-ID (die Übergabe erfolgt per GET) ein XML-File laut dem
bisherigen Aufbau unserer verwendeten XML-Datei (siehe Listing 8.11).
Nehmen wir folgende Struktur der Tabellen an:
u
u
V I D E O P L AY E R ( A C T I O N S C R I P T 3 . 0 ) 411
Tabelle Feld Typ Details Beschreibung
tbl_08playlist idP_Playlist int(11) auto-increment,
Primary Key,not
null
ID der Playlist
vcP_Bezeichnung varchar(128) not null Eine interne Playlist-
Bezeichnung,die innerhalb
der XML-Struktur nicht
verwendet wird
vcP_Rootdir varchar(128) not null URL zum Root-Verzeichnis
der Videos in der Playlist
bitP_chk_autostart tinyint(1) not null,
Standard = 1
Kennzeichnung,ob
Autostart der Playlist an (1)
oder aus (0) ist
tbl_08videos idP_video int(11) auto-increment,
Primary Key,not
null
ID des Videos
fidP_select_
Bezeichnung_Playlist
int(11) not null Ein Feld,das als Foreign
Key zur Tabelle tbl_08play-
list verwendet wird
vcP_Src varchar(128) not null URL zur Videoquelle
vcP_Content varchar(128) not null Name des Videos
vc_Author varchar(64) null Name des Autors (sofern
vorhanden)
dt_Date date null Aufnahmedatum (sofern
vorhanden)
tmP_Uploadtimestamp timestamp not null,
CURRENT_
TIMESTAMP
Timestamp des Eintrags
des Videos in die Tabelle
Tabelle 8.1: Aufbau der beiden Tabellen für unser Beispiel
Eine solche PHP-Datei zum Generieren von XML-Content aus den beiden oben defi-
nierten Tabellen könnte folgendermaßen aussehen:
function createXML($idP_Playlist) {
$dbData = array(
"dbServer" => "mysql.syneweb.com",
"dbUser" => "usr_mysql2",
"dbPWD" => "456mysql!",
"dbName" => "db_flashphpajax"
);
if(!$conn = mysql_connect($dbData["dbServer"],$dbData["dbUser"],$dbDat
a["dbPWD"])) {
die('<div class="Error">Der Datenbankserver konnte nicht erreicht
werden.<br/>ERROR='.mysql_error().'</div>');
}
K A P I T E L 8412
if(!mysql_select_db($dbData["dbName"])) {
die('<div class="Error">Die Datenbank konnte nicht ausgewaehlt
werden.<br/>ERROR='.mysql_error().'</div>');
}
$sql = "SELECT * FROM tbl_08playlist WHERE(idP_Playlist=$idP_Playlist)";
$query = mysql_query($sql) or die('<div class="Error">Die Query konnte
nicht abgesetzt werden.<br/>ERROR='.mysql_error().'</div>');
$data = mysql_fetch_array($query);
$msg = ‚<?xml version="1.0" encoding="ISO-8859-1" standalone="yes" ?>';
$msg.= ‚<Playlist rootDir="'.$data["vc_Rootdir"].'"
autostart="'.$data["bitP_chk_autostart"].'">';
$sql = "SELECT * FROM tbl_08videos WHERE(fidP_select_Bezeichnung_
Playlist=$idP_Playlist)";
$query = mysql_query($sql) or die('<div class="Error">Die Query konnte
nicht abgesetzt werden.<br/>ERROR='.mysql_error().'</div>');
while($data = mysql_fetch_array($query)) {
$msg.= '
<File src="'.$data["vcP_Src"].'">
<Author>'.$data["vc_Author"].'</Author>
<Content>'.$data["vcP_Content"].'</Content>
<Date>'.$data["dt_Date"].'</Date>
</File>
';
}
$msg.= '</Playlist>';
return $msg;
}
if(count($_GET)>0 && isset($_GET["idP_Playlist"])) { echo(createXML($_
GET["idP_Playlist"])); }
else { echo('<div class="Error">Sie haben keine Berechtigung f&uuml;r
diese Site.</div>'); }
Listing 8.23: Eine PHP-Datei namens playlist.php erzeugt aus einer Datenbank mit den Tabellen tbl_
08playlist und tbl_08videos eine XML-Struktur laut den bisherigen Vorgaben.
V I D E O P L AY E R ( A C T I O N S C R I P T 3 . 0 ) 413
Betrachtet man das Script Schritt für Schritt, so sind folgende Punkte von besonderem
Interesse:
1. Sofern an das Script GET-Variablen und im Speziellen die GET-Variable idP_
Playlist übergebenwurden,wirddieFunktioncreateXML mitdieserVariableals
Parameter aufgerufen und deren Rückgabewert per echo ausgegeben. Sollte nichts
an die Datei übergeben worden sein, so wird eine entsprechende Fehlermeldung
ausgegeben.
2. Die Funktion createXML definiert zunächst die für den Connect zu einer
Datenbank notwendigen Informationen in dem Array $dbData, stellt danach die
Verbindung zum Datenbankserver her und wählt zuletzt die Datenbank aus. Sollte
einer dieser Befehle misslingen, endet das Script mit einem die.
3. Danach wird erst einmal aus der Tabelle tbl_08playlist alles ausgelesen, was zur
übergebenen Playlist-ID gehört. Dies umfasst neben dem Playlist-Namen (der für
unsere Zwecke irrelevant ist) auch das Root-Verzeichnis der Videos (vcP_Rootdir)
und die Information zu einem Autostart der Playlist (bitP_chk_autostart).Aus
diesen Informationen wird der erste Teil der XML-Struktur erzeugt (dieser wird
vollständig in der Variablen $msg gespeichert):
$msg = ‚<?xml version="1.0" encoding="ISO-8859-1" standalone="yes" ?>';
$msg.= ‚<Playlist rootDir="'.$data["vc_Rootdir"].'"
autostart="'.$data["bitP_chk_autostart"].'">';
4. Ist dies erfolgt,werden in einem zweiten SQL-Statement aus tbl_08videos sämtliche
Videoinformationen zur gegebenen Playlist geladen. Aus diesen Informationen
wird in einer while-Schleife der weitere XML-Baum aufgebaut:
$msg.= ‚
<File src="'.$data["vcP_Src"].'">
<Author>'.$data["vc_Author"].'</Author>
<Content>'.$data["vcP_Content"].'</Content>
<Date>'.$data["dt_Date"].'</Date>
</File>
‚;
5. Zuletzt wird noch das geöffnete Tag <Playlist> geschlossen und der gesamte
String $msg von der Funktion an den Aufrufer zurückgegeben.
Das Ergebnis für beispielsweise idP_Playlist=1 sieht dann folgendermaßen aus:
K A P I T E L 8414
Flash muss demnach eine XML-basierte PHP-Datei playlist.php einlesen, die über
einen GET-Parameter die korrekten Daten aus einer Datenbank ausliest. Nun offen-
baren sich zwei Wege:
1. Unser Flash-Beispiel wird so aufgebaut, dass immer dieselbe Playlist ausgelesen
wird. Das bedeutet, jeder User ruft dieselben Videos ab.
2. Es soll für jeden User eine individuelle Playlist existieren. Daher muss die Flash-
Datei so aufgebaut sein, dass sie zunächst auf den Playlist-Parameter wartet (die
Flash-Datei muss ja unabhängig von einem User sein) und danach basierend auf
diesem Parameter die XML-Daten anfordert.
Wir werden zunächst den ersten Teil entwickeln (das ist sehr einfach, da wir nur die
URL zur einzulesenden Datei ändern müssen) und uns danach den zweiten Teil vor-
nehmen.
Fixe Playlist für alle User
Dieser Fall ist sehr einfach, denn es macht keinen Unterschied, ob wir eine Textdatei
mit XML als Inhalt oder eine PHP-Datei mit XML als Inhalt einlesen. Einzig die Tat-
sache, dass wir ab nun eine Server-Umgebung benötigen (PHP ist im Spiel ...), macht
die Sache ein wenig aufwändiger.
Bauen wir auf der Datei videoplayer_01e.fla auf, so muss lediglich in der Aktionenebe-
ne in Bild 1 die Zeile
var theURL:String = "playlist.txt";
ABBILDUNG 8.22
Nun wurde die XML-Datei
nicht mehr „von Hand“
geschrieben, sondern per
PHP aus einer Datenbank
und zwei Tabellen erzeugt.
V I D E O P L AY E R ( A C T I O N S C R I P T 3 . 0 ) 415
in
var theURL:String = "playlist.php?idP_Playlist=1";
geändert werden. Testen Sie online und Sie werden sehen, dass sich nichts geändert
hat:
ABBILDUNG 8.23
Auch mit dynamisch erzeug-
ten XML-Daten und online
funktioniert der Video-Player
prächtig.
Die Datei finden Sie unter dem Namen videoplayer_01f.fla (bzw. videoplayer_02f.fla)
auf der Buch-CD.
Variable Playlist für jeden User individuell
Jetzt wird die Sache etwas komplizierter, denn nun muss das umgebende Webdoku-
ment zunächst die ID der Playlist an Flash übergeben – erst dann kann Flash die XML-
Daten anfordern. Somit muss Flash beigebracht werden, dass es auf das Setzen der
Playlist-ID warten muss, bevor die Daten geladen werden. Aus den vorigen Kapiteln
wissen wir, dass sich das über das ExternalInterface sehr einfach lösen lässt: Erst wird
eine Funktion definiert, die als eine Art „JavaScript-Handler“ dient und danach wird
diese Funktion für JavaScript freigegeben. Ebenso muss dafür gesorgt werden, dass erst
nach dem Funktionsaufruf auf die XML-Quelle zugegriffen wird.
Zunächst die „JavaScript-Handler“-Funktion:
function loadXMLVideodata(PlaylistID:Number):void {
idP_Playlist = PlaylistID;
K A P I T E L 8416
nextFrame();
}
Listing 8.24: Die Funktion loadXLMVideodata erhält als Übergabeparameter die Playlist-ID von Java-
Script.
JavaScript wird später auf diese Funktion zugreifen und ihr als Übergabeparameter
die zu ladende Playlist-ID übergeben. Diese Übergabevariable wird in der globalen
Variablen idP_Playlist gespeichert und danach erfolgt ein Sprung in den nächsten
Frame, wo das Laden der XML-Datei erfolgt (an der Stelle, wo die URL zur XML-Datei
definiert ist, müssen wir dann noch eine Änderung vornehmen).
Die obige Funktion wird mittels des nachfolgenden Codes für JavaScript registriert:
import flash.external.*;
var idP_Playlist:Number;
if(ExternalInterface.available) {
try {
ExternalInterface.addCallback("loadXMLVideodata",loadXMLVideodata);
}
catch(myError:Error) {
trace("Error: "+myError);
}
}
stop();
Listing 8.25: Die zuvor definierte Funktion loadXMLVideodata wird als sogenannte „Callback-Funktion“
für JavaScript registriert. Die Flash-Datei finden Sie auf der Buch-CD unter dem Namen videoplayer_01g.fla.
Um mit der ExternalInterface-Klasse zu arbeiten, muss die entsprechende Klasse
flash.external.* importiert werden. Danach wird eine (globale) Variable namens
idP_Playlist definiert, der im Weiteren der Übergabewert von JavaScript zugewie-
sen wird. Sollte das ExternalInterface verfügbar sein, wird versucht, die Callback-Funk-
tion zu registrieren. Schlägt dies fehl, wird per trace eine Fehlermeldung ausgegeben.
Danach wird das Script noch abgestoppt, da die Flash-Anwendung so lange mit dem
Laden der XML-Daten warten soll, bis es eine Playlist-ID zugewiesen bekommt. Weiter
gesprungen und geladen wird im nächsten Frame.
Zuletzt muss in Bild 2 in der Aktionenebene noch angegeben werden, wie Flash zu den
korrekten Playlist-Daten gelangt:
var theURL:String = "playlist.php?idP_Playlist="+idP_Playlist;
Listing 8.26: Die korrekte Playlist wird über die Variable idP_Playlist definiert, die beim Laden der XML-
Daten an das entsprechende PHP-Script angehängt wird.
V I D E O P L AY E R ( A C T I O N S C R I P T 3 . 0 ) 417
Damit wäre der Flash-Teil abgeschlossen und wir können uns der XHTML-Aufgabe
widmen. Es ist relativ wenig JavaScript-Code notwendig, um die Playlist-ID an Flash
zu übergeben. Grundsätzlich gehen wir davon aus, dass die Playlist-ID bereits an die
XHTML-Datei per GET übergeben wurde:
function sendDataToFlash(idP_Playlist) {
var myswf = getFlashElement("myswf");
myswf.loadXMLVideodata(idP_Playlist);
}
window.onload = function() {
sendDataToFlash(<?php echo($_GET["idP_Playlist"]); ?>);
}
Listing 8.27: Übergabe der per GET definierten Variable idP_Playlist an Flash. Die entsprechende
XHTML-Datei hört auf den Namen videoplayer_01g.php.
Nachdem die XHMTL-Seite vollständig geladen wurde (window.onload) wird die
Funktion sendDataToFlash mit der GET-Variable idP_Playlist als Übergabepa-
rameter aufgerufen. Diese Funktion sucht sich zunächst die korrekte Referenz auf die
eingebundene SWF-Datei myswf über die Funktion getFlashElement (die Erklärung
dazu finden Sie im Kapitel zu AJAX bzw. clientseitigem Datenaustausch) und ruft in
dieser SWF-Datei danach die Callback-Funktion loadXMLVideodata mit wiederum
idP_Playlist als Übergabeparameter auf. Somit schließt sich der Kreis und Flash
hat, was es braucht: die Playlist-ID.
Der Vollständigkeit halber hier noch einmal die Funktion getFlashElement:
function getFlashElement(elem) {
var app = navigator.appName.toLowerCase();
var nav = navigator.userAgent.toLowerCase();
if((app.indexOf("microsoft") != -1 || nav.indexOf("microsoft") != -1)
&& !Boolean(window["opera"])) { return document.all[elem]; }
else { return document[elem]; }
}
Listing 8.28: Die Funktion getFlashElement findet den korrekten Verweis auf die Flash-Datei – egal,
welcher Browser verwendet wird.
Alternativ zum Setzen der Playlist-ID basierend auf GET-Variablen könnten wir dem
User auch die Möglichkeit geben, die Playlist-ID selbst einzugeben oder aus einer
Select-Box selbst zu wählen. Diese Variante ist in der Datei videoplayer_01h.php zu
finden. Hierzu entfernen Sie zunächst den window.onload-Teil aus Listing 8.27 und
fügen stattdessen den nachfolgenden Code ein:
K A P I T E L 8418
function setPlaylistID() {
var idP_Playlist = document.forms["frmVideoplayer"].
elements["selPlaylist"].value;
if(idP_Playlist!=-1) { sendDataToFlash(idP_Playlist); }
}
Listing 8.29: Setzen der PlaylistID
Die Funktion setPlaylistID wird bei einer Auswahl eines Videos aus einer Select-
Box aufgerufen. Sofern die Auswahl mit einem Wert ungleich -1 endet (der Wert -1
ist dem Eintrag „Bitte wählen Sie aus:“ zugewiesen), wird die Auswahl an sendData-
ToFlash übergeben.
Die Select-Box wird per PHP aus der Datenbank erzeugt, indem wir die Tabelle
tbl_08playlist auslesen:
...
$sql = "SELECT * FROM tbl_08playlist";
$query = mysql_query($sql) or die('<div class="Error">Fehler beim
Absetzen der Query.<br/>ERROR='.mysql_error().'</div>');
if(mysql_num_rows($query)>0) {
$returner = '
<select name="selPlaylist" id="selPlaylist" onchange="setPlaylistI
D();">
<option value="-1">Bitte w&auml;hlen Sie aus:</option>
‚;
while($data = mysql_fetch_array($query)) {
$returner.= '
<option value="'.$data["idP_Playlist"].'">'.$data["vcP_
Bezeichnung"].'</option>
';
}
$returner.= '</select>';
}
else { $returner = '(kein Zugriff auf die Playlists)'; }
echo($returner);
Listing 8.30: Auszug aus dem Script zum Auslesen der Tabelle tbl_08playlist, um alle Playlists in eine
Select-Box zu schreiben. Der Teil für die Verbindung zur Datenbank wurde weggelassen, da dieses Proze-
dere hinlänglich bekannt ist. Die Datei finden Sie auf der Buch-CD unter videoplayer_01h.php.
V I D E O P L AY E R ( A C T I O N S C R I P T 3 . 0 ) 419
Sollten in der Tabelle Playlists vorhanden sein, wird eine Select-Box selPlaylist mit
einem Eintrag „Bitte wählen Sie aus:“ und den restlichen Einträgen aus der Tabelle
generiert. Die Werte der Einträge entsprechen den IDs der Playlists (idP_Playlist).
Sobald sich eine Änderung in der Auswahl ergibt, wird das Ereignis onchange ausge-
löst, das die Funktion setPlaylistID aufruft. Das Ergebnis ist wie folgt:
ABBILDUNG 8.24
Flash wartet auf eine
Auswahl aus der Select-Box.
Sobald eine Auswahl getroffen wurde, lädt Flash die entsprechende Playlist:
ABBILDUNG 8.25
Wurde eine Auswahl getrof-
fen, lädt Flash die Videos zur
Playlist und stellt diese in der
ComboBox dar.
K A P I T E L 8420
AJAX zum Nachladen der Videos
Bis zu diesem Zeitpunkt haben wir alle Ziele erreicht, die wir uns gesetzt hatten. Nun
wollen wir folgende Erweiterung programmieren: Angenommen, es wurde ein weiteres
Video zur Playlist hinzugefügt, während der User gerade die Animation offen hat. Ist
dies der Fall, würde der User genau das neue Video nicht in der Playlist sehen, da es ja
gerade hinzugekommen ist. Per AJAX hätten wir jedoch sehr einfach die Möglichkeit,
Flash mitzuteilen, dass ein neues Video der Playlist hinzugefügt wurde – wir müssen
nur per AJAX in regelmäßigen Abständen nachsehen, ob sich etwas an der Playlist
geändert hat, und übergeben in diesem Fall die Änderungen an Flash.
Die Idee ist, dass bei einem Eintrag eines Videos in die Datenbank ein Timestamp
gespeichert wird. Beim Öffnen des Dokuments videoplayer_01i.php wird der neueste
Timestamp ausgelesen und clientseitig gespeichert. In regelmäßigen Abständen wird
die Tabelle per AJAX abgefragt und nachgesehen, ob es ein aktuelleres Video gibt.
Sollte dies der Fall sein, wird eine entsprechende Meldung an Flash übergeben. In den
folgenden Abbildungen sehen Sie die Anwendung.
Schritt 1: Der User hat eine Playlist („Uwes Playlist 1“) ausgewählt, die derzeit noch
vier Videos enthält (Abbildung 8.26).
ABBILDUNG 8.26
Es wurde die Playlist „Uwes
Playlist 1“ ausgewählt – sie
enthält derzeit noch vier
Videos.
Schritt 2: Zwischenzeitlich wurde in die Datenbank ein neues Video eingetragen. Nach
spätestens 60 Sekunden (alle 60 Sekunden fragt AJAX die Datenbank ab) erhält der
User eine Meldung innerhalb der Flash-Anwendung, dass ein neues Video zum Abruf
bereitsteht (Abbildung 8.27).
V I D E O P L AY E R ( A C T I O N S C R I P T 3 . 0 ) 421
Schritt 3: Hat sich der User dafür entschieden, das Video in seine Abspielliste zu über-
nehmen, wird die Abspielliste entsprechend erweitert (Abbildung 8.28).
ABBILDUNG 8.27
Ein neues Video wurde in der
Datenbank gespeichert. Der
User hat nun die Möglichkeit
zu entscheiden, ob er es in
seine Playlist (ComboBox)
aufnehmen möchte.
ABBILDUNG 8.28
Das neue Video („Düringer
ab 4,99“) wurde in die
Abspielliste aufgenommen.
Damit AJAX das aktuellste Video ermitteln kann, benötigt es auf Serverseite ein Script,
das genau die benötigten Informationen liefert:
K A P I T E L 8422
...
$sql = "SELECT tmP_Uploaddatum FROM tbl_08videos WHERE(fidP_select_
Bezeichnung_Playlist=".$_GET["idP_Playlist"].") ORDER BY tmP_Uploaddatum
DESC LIMIT 1";
$query = mysql_query($sql) or die('<div class="Error">ERROR='.mysql_
error().'</div>');
$data = mysql_fetch_array($query);
echo(strtotime($data["tmP_Uploaddatum"]));
...
Listing 8.31: Auszug aus der Datei getnewestvideo.php, der die ID der aktuellen Playlist als GET-Parameter
übergibt.
Ein geeignetes SQL-Statement ruft das neuesteVideo ab,indem es einen Eintrag (LIMIT
1) aus der Tabelle tbl_08videos abruft, wobei die Ergebnisliste absteigend (also das neu-
este zuerst: ORDER BY tmP_Uploaddatum DESC) sortiert ist. Es werden nur Videos
abgerufen, die einer gegebenen Playlist angehören (fidP_select_Bezeichnung_
Playlist=".$_GET["idP_Playlist"]). Das Ergebnis wird in einen Timestamp
umgewandelt (strtotime($data["tmP_Uploaddatum"])) und ausgegeben.
Der JavaScript-Part aus Listing 8.29 wird zunächst um eine Variable firstShow erwei-
tert:
var firstShow = true;
var itv;
function setPlaylistID() {
var idP_Playlist = document.forms["frmVideoplayer"].
elements["selPlaylist"].value;
if(idP_Playlist!=-1) {
if(firstShow) { itv = setInterval("sendRequest("+idP_
Playlist+")",60000); }
sendDataToFlash(idP_Playlist);
}
}
Listing 8.32: Erweiterung von Listing 8.29 um die Variablen firstShow und itv
Die Variable firstShow definiert, ob die Playlist das erste Mal geladen wird oder
nicht. Wir benötigen diese Info, damit der Timer (setInterval) für die AJAX-
Abfrage gestartet wird, denn bevor eine Playlist das erste Mal gewählt wurde, bringt
eine AJAX-Anfrage an den Server zum Überprüfen eventuell neu hinzugekommener
Videos nichts. Wurde also eine Playlist ausgewählt, wird ein Intervall (itv) gestar-
tet, das alle 60 Sekunden eine Funktion sendRequest mit dem Übergabeparameter
V I D E O P L AY E R ( A C T I O N S C R I P T 3 . 0 ) 423
idP_Playlist aufruft. Diese Funktion erzeugt eine Anfrage an die Datenbank über
das im folgenden Listing dargestellte Script:
var myXMLHttpRequest = createRequestObject();
function sendRequest(idP_Playlist) {
myXMLHttpRequest.open("GET", "getnewestvideo.php?idP_Playlist="+idP_
Playlist, true);
myXMLHttpRequest.onreadystatechange = handleRequest;
myXMLHttpRequest.send(null);
}
Listing 8.33: Anfrage an die Datenbank über die Datei getnewestvideo.php, die als GET-Parameter
idP_Playlist übermittelt bekommt.
Nachdem eine XMLHttpRequest-Instanz erzeugt wurde (die dafür verantwortliche
Funktion createRequestObject wurde im Kapitel zu AJAX hinlänglich beschrieben,
deshalb verzichte ich an dieser Stelle auf die Erklärung der Funktion), kann die Verbin-
dung zur Datei getnewestvideo.php geöffnet (myXMLHttpRequest.open), der Instanz
ein Eventhandler zugewiesen (myXMLHttpRequest.onreadystatechange) und die
Anfrage versandt werden (myXMLHttpRequest.send). Der Eventhandler handleRe-
quest, der bei jeder Änderung des Status der AJAX-Anfrage aufgerufen wird, stellt sich
folgendermaßen dar:
function handleRequest() {
if(myXMLHttpRequest.readyState==4) {
if(firstShow) {
firstShow = false;
newestVideo = parseInt(myXMLHttpRequest.responseText);
}
else { proveReturner(myXMLHttpRequest.responseText); }
}
}
Listing 8.34: Der Eventhandler sorgt für den korrekten Aufruf der Funktion proveReturner.
Sollte der Eventhandler erkennen, dass die Eigenschaft readyState den Wert 4 hat
(Übermittlung der Daten vom Server zur XMLHttpRequest-Instanz abgeschlos-
sen), wird zunächst überprüft, ob diese Anfrage das erste Mal stattgefunden hat
(firstShow==true). In diesem Fall wird zunächst firstShow=false gesetzt und die
Variable newestVideo auf den Rückgabewert von getnewestvideo.php gesetzt (dies ist
wie oben beschrieben der Timestamp des neuesten Videos in der Playlist). Da es sich
in diesem Fall um den ersten Aufruf der AJAX-Anwendung gehandelt hat, muss auch
noch nicht überprüft werden, ob ein neueres Video vorhanden ist (die Videos zur Play-
K A P I T E L 8424
list wurden gerade zuvor das erste Mal geladen). Sollte hingegen firstShow==false
sein, wird die Funktion proveReturner aufgerufen, die als Übergabeparameter den
Wert responseText erhält:
function proveReturner(timestamp) {
if(newestVideo<parseInt(timestamp)) {
newestVideo = parseInt(timestamp);
var myswf = getFlashElement("myswf");
myswf.newVideoAvailable();
}
}
Listing 8.35: Die Funktion proveReturner überprüft, ob das neueste Video bereits Bestandteil der schon
geladenen Playlist ist.
Bei Aufruf von proveReturner wird verglichen, ob der Timestamp des ermittelten
Videos größer als der Timestamp des zuletzt (vor 60 Sekunden) ermittelten Videos
ist. Ist dies der Fall, wurde also zwischenzeitlich ein neues Video in die Datenbank
geschrieben – somit muss Folgendes getan werden:
1. Der Timestamp des somit „neuesten“ Videos muss gespeichert werden, damit
man in 60 Sekunden mit diesem Timestamp vergleichen kann: newestVideo =
parseInt(timestamp);.
2. Es muss Flash mitgeteilt werden, dass (zumindest) ein neues Video vorhanden ist:
myswf.newVideoAvailable();.
Ob in den letzten 60 Sekunden ein oder mehrere neue Videos hinzugekommen sind,
ist letztlich egal, denn Flash wird seinerseits die komplette Playlist neu laden und erhält
somit alle neuen Videos.
Der Flash-Teil ist nicht wesentlich aufwändiger, jedoch mussten einige Änderungen in
der Struktur vorgenommen werden:
1. Sämtlicher Code befindet sich nun in einem einzigen Bild der Zeitleiste.
2. Der Aufbau der Bühne erfolgt ereignisorientiert:
1. Die Funktion loadXMLVideodata (diese wird von JavaScript aufgerufen)
steuert den Aufbau. Sobald sie aufgerufen wird, wird die Funktion loadXML
aufgerufen.
2. Sobald für loadXML das Ereignis COMPLETE auftritt („XML-Daten geladen“),
wird die Bühne aufgebaut. Da die Funktion loadXML öfter als nur einmal
aufgerufen wird (sobald ein neues Video entdeckt wurde und der User dieses
neue Video in die Abspielliste aufgenommen hat, wird diese Funktion erneut
V I D E O P L AY E R ( A C T I O N S C R I P T 3 . 0 ) 425
aufgerufen), müssen wir zwischen dem ersten und allen folgenden Aufrufen
unterscheiden: Im Fall des ersten Aufrufs generieren wir eine TextArea-, eine
ComboBox- und eine FLVPlayback-Komponente und danach den Inhalt der
ComboBox für die Abspielliste. Für alle weiteren Aufrufe wird nur der Inhalt
der ComboBox neu generiert.
3. Bei Aufruf der Funktion newVideoAvailable durch JavaScript und positiver
Bestätigung der Aufnahme des Videos durch den User wird die Funktion
loadXML erneut ausgeführt und das oben beschriebene Prozedere geschieht
von neuem.
Die Funktion newVideoAvailable setzt zunächst das Infofenster in den Vordergrund
(setChildIndex) und blendet es dann ein:
function newVideoAvailable():void {
var topPosition:uint = numChildren - 1;
setChildIndex(mcNewVideoInfo, topPosition);
mcNewVideoInfo.visible = true;
}
Kurz zum Infofenster, sobald ein neues Video von AJAX entdeckt wurde: Der Einfach-
heit halber wurde das Infofenster „Ein neues Video ist vorhanden...“ als MovieClip in
Flash ausgeführt und nicht per ActionScript erzeugt. Der Code zu den beiden Buttons
„Nein“ und „Ja“ ist wie folgt:
function cancelNewVideolist(myEvent:MouseEvent):void {
mcNewVideoInfo.visible = false;
}
function loadNewVideolist(myEvent:MouseEvent):void {
mcNewVideoInfo.visible = false;
loadXML(idP_Playlist);
}
mcNewVideoInfo.btnNein.addEventListener(MouseEvent.MOUSE_
UP,cancelNewVideolist);
mcNewVideoInfo.btnJa.addEventListener(MouseEvent.MOUSE_UP,loadNewVideolist);
Listing 8.36: Die Eventlistener der Buttons „Nein“ und „Ja“ für die Aufnahme eines neuen Videos in die
Abspielliste
Im Fall eines Klicks auf den „Nein“-Button wird lediglich das Infofenster (mcNew-
VideoInfo) wieder ausgeblendet, im Fall eines Klicks auf den „Ja“-Button wird
zusätzlich (wie oben beschrieben) die Funktion loadXML aufgerufen. Die Variable
idP_Playlist ist eine Variable auf root-Ebene und somit „global“. Und dann geht
alles seinen Lauf ...
K A P I T E L 8426
Einen wichtigen Punkt sollte man nicht außer Acht lassen: Browser wie Server neigen
dazu, XML-Daten (auch solche, die von PHP erzeugt wurden) im Cache abzulegen.
Um dies sehr einfach zu umgehen, hängt man an die XML-Anfrage einen zufälligen
String an, sodass dem Server (wie Browser) eine neue Anfrage mit neuen GET-Variab-
len vorgegaukelt wird:
var dStr:String = "&timestamp="+new Date().getTime();
var theURL:String = "playlist.php?idP_Playlist="+PlaylistID+"&CacheBuste
r="+Math.random()+dStr;
Listing 8.37: Ein sehr zufälliger String wird an die Anfrage angehängt.
Der Zufallsstring setzt sich aus dem aktuellen Datum, der aktuellen Zeit und einer
Zufallszahl zwischen 0 und 1 zusammen – das sollte Zufall genug sein ...
Die entsprechenden Dateien finden Sie auf der Buch-CD unter folgenden Namen:
Flash-Datei: videoplayer_03.fla
XHTML-Datei: videoplayer_01i.php
XML-basierte PHP-Datei (Playlist): playlist.php
Ermitteln neuer Videos in der Datenbank: getnewestvideo.php
Include-Datei zum Verbindungsaufbau mit der Datenbank: includes/connectdb.inc.
php
8.3.6 Arbeiten mit Cue-Points
Hierzu erweitern wir die zuvor entwickelte Flash-Anwendung videoplayer_03.fla und
speichern sie unter dem Namen videoplayer_04.fla.
Um mit in FLV-Dateien eingebetteten CuePoints zu arbeiten, stellt uns Flash folgende
wichtige Eigenschaften, Methoden und Ereignisse zur Seite:
MetadataEvent.METADATA_RECEIVED: Dieses Ereignis tritt auf, sobald Meta-
daten (dazu gehören auch CuePoints) von der FLV-Datei gelesen werden konnten
– dies gilt es abzuwarten.
Aus dem Array FLVPlayback.metadata.cuePoints können sämtliche Cue-
Points ausgelesen werden. Diese sind darin als Objekte abgelegt:
type:String: Typ des CuePoint. Mögliche Werte sind „event“ oder „navigati-
on“. Siehe hierzu auch die Ausführungen im Abschnitt 8.3.2.
name:String: Name des CuePoint
time:Number: Eine auf drei Kommastellen genaue Zahl, die den Zeitpunkt des
CuePoint angibt
u
u
u
u
u
u
u
u
u
u
XML im Cache?XML im Cache?
V I D E O P L AY E R ( A C T I O N S C R I P T 3 . 0 ) 427
parameters:Object: Ein optionales Objekt (beinhaltet Name-Wert-Paare),
das beim Erstellen der CuePoints mit beispielsweise dem Flash Video Encoder
erstellt wurde
Die wichtigen Parameter sind name und time, sofern man sich über den Typ des
CuePoint im Klaren ist.
In Flash fügen wir der FLVPlayback-Instanz zunächst einen Eventhandler für das
Ereignis METADATA_RECEIVED zu:
myVideoplayer.addEventListener(MetadataEvent.METADATA_RECEIVED,
EMetadata);´
function EMetadata(myEvent:MetadataEvent):void {
loadCuePoints(myVideoplayer.metadata.cuePoints);
}
Sobald Metadaten vorhanden sind, wird die Funktion loadCuePoints aufgerufen:
function loadCuePoints(myData:Array):void {
myCombobox2.removeAll();
for(var i:Number = 0; i<myData.length; i++) {
myCombobox2.addItem({ label:myData[i].name, data:myData[i].time });
}
}
Listing 8.38: Laden der CuePoint-Informationen in eine ComboBox
In einer for-Schleife werden alle CuePoints durchlaufen, wobei die Beschriftung der
ComboBox den Namen des CuePoint (myData[i].name) und der Wert der Combo-
Box den Zeitpunkt des CuePoint (myData[i].time) erhält.
Um mit dieser ComboBox myCombobox2 überhaupt arbeiten zu können, muss sie
natürlich zuvor angelegt werden:
var myCombobox2:ComboBox;
function createComboBoxCuePoints():void {
myCombobox2 = new ComboBox();
myCombobox2.move(44,460);
myCombobox2.width = 200;
addChild(myCombobox2);
myCombobox2.addEventListener(Event.CHANGE, EChange2);
}
Listing 8.39: Erzeugen der zweiten ComboBox unterhalb der bestehenden ComboBox für die Abspielliste
u
K A P I T E L 8428
Die Funktion createComboBoxCuePoints wird beim Auftreten des COMPLETE-Ereig-
nisses beim Laden einer XML-Datei aus der Funktion EXMLComplete aufgerufen:
function EXMLComplete(myEvent:Event):void {
mcLade.visible = false;
myXML = new XML(myEvent.target.data);
myXML.ignoreWhitespace = true;
if(firstShow) {
firstShow = false;
createTextArea();
createFLVPlayback();
createComboBox();
createComboBoxCuePoints();
}
loadComboBoxData();
}
Das Ergebnis spricht wie immer für sich:
Viel Spaß beim Umsetzen!
ABBILDUNG 8.29
Die geladenen CuePoints,
über die man direkt
Abschnitte in der FLV-Datei
anspringen kann
Stichwortverzeichnis
Symbole
$-Zeichen 8
$_GET 261
$HTTP_GET_VARS 262
$HTTP_POST_VARS 262
A
AC_FL_RunContent 178
ActionScript 1.0 6
ActionScript 2.0 6
ActionScript-Referenz 349
addEventListener 362
Addition 18
Aktionen auslösen 172
all 170
appendChild 290
Array 10, 24
assoziatives 25, 257
attributes 282
auslesen 257
Elementanzahl 36
erstellen 24, 25
indiziertes 24
in Flash 282
Länge 36
superglobales 14
übergeben 45
Attribute 282
Ausgeben von XML-Daten
286
Auskommentieren 7
Automatische Typisierung 13
B
Bedingungen 28
break 41
C
Cache 426
Caching 53
verhindern 54
Case-sensitive 10
Child 272
childNodes 273
classid 169
clearInterval 351
closdir() 356
codebase 169
contentType 289
continue 41
Cookies 47
Gültigkeit 49
Session 50
setzen 48
Verfallsdatum 49
count () 261
createElement 290
D
data 314
Daten
an Browser 181
an Flash 168
an Flash senden 172
aus Datenbank 253
Datenbank speichern 295
schreiben 260
übergeben 260
verschicken 241
versenden, GET 260
versenden, POST 262
von Flash auslesen 295
Datenbank
auswählen 255
Verbindungsaufbau 255
Datentypen 8, 10
Flash 11
PHP 10
Datum 54
Dekrement 18
die 255
do..while-Schleife 39
Document Object Model 170
DOM 56, 170
E
Ebenen
Bildnamen 172
embeds 171
Endlosschleife 32
Entwicklung
Anforderungen 338
Ereignisbehandlungs-
routine 245
Ereignisparameter 245
Ereignisprozedur 245, 250,
341
Ereignisroutinen 341
ExternalInterface 184
available 187
Rekursion 202
F
firstChild 273
Flash
Datenübergabe 294
JavaScript aufrufen 182
Flash Video Encoder 385
FlashVars 179
FLV-Format 377
FLVPlayback 378
for-Schleife 31
Abbruchbedingung 32
Syntax 33
for...each-Schleife 37
Syntax 37
for...in-Schleife 37, 342
Formulardaten
versenden 15
Formulare 176
Daten verschicken 260
function 42
S T I C H W O R T V E R Z E I C H N I S430
Funktionen 41
Arrays 45
aufrufen 44
deklarieren 42
lokale Variablen 45
G
GET 15, 260
getElementById 170
getURL 181
getURL() 260
GET 261
POST 263
Gleichheit
strikte 22
Grafiken
hochladen 265
Grunddatentypen 11
H
hasChildNodes () 274
Header 53
header() 53
HTML
JavaScript ausführen 181
HTTP 47
https 49
I
id3-Objekt 349
ID3-Tag 338
auslesen 349
if
Syntax 28
if-Bedingungen 28
ignoreComments 329
ignoreProcessingInstructions
329
ignoreWhite 271
ignoreWhitespace 329
Inkrement 18
innerHTML 150
int 12
Integer 10
is_dir() 357
J
JavaScript 6, 158, 167
Flash ansprechen 172
Flash-Aktion auslösen 172
Wert übergeben 172
K
Klammern
geschweifte 30
Kommentare 7, 58
einzeilige 7
mehrzeilige 7
Komponente
XMLConnector 298
L
Ladevorgang
fehlgeschlagen 251
wiederholen 244
Lautstärkeregler 353
length 334
list 261
loaded 243, 341
loadVariables 72
LoadVars 72, 165, 225, 241,
243, 263
Daten versenden 264
LoadVars-Klasse 72
LoadVars-Objekt
anlegen 263
Variablen anlegen 263
M
Modulo 19
MP3 338, 376
streamen 346
Multimedia 338
mysql_fetch_array 257
mysql_pconnect 255
mysql_query 256
mysql_select_db 255
N
navigateToURL 323
nodeValue 274
Null 12
O
On2VP6 376
onLoad 243, 341
opendir() 356
Operatoren 17, 18
arithmetisch 17
Bit 21
logische 21
Rangordnung 21, 22
Vergleich 22
Zuweisung 18
Ordner öffnen 356
P
parsen 266
PDF-Datei
hochladen 265
PHP
XML generieren 283
PHP-Referenz 15
POST 15, 262
Programmieren
objektorientiert 6
R
readdir() 356
readyState 127
Referenzdatentypen 11, 12
register_globals 15
Regular Expression 160
responseText 127, 234
responseXML 127, 234
return 43, 45
RSS 72
S
Schleifen 31
break 41
S T I C H W O R T V E R Z E I C H N I S 431
continue 41
Durchläufe 31
send 294
send() 260, 263
sendAndLoad() 264
sendToURL 320
Server
Verbindung abgebrochen
244
Session 50
initialisieren 51
löschen 53
Variablen entfernen 53
Variablen speichern 51
Session-ID 50
setInterval 350
setRequestHeader 136
SetVariable 170
SGML 168
Sibling 272
SimpleXML 56
Skins 379
Sonderzeichen 242
Soundobjekt 345
loadSound 346
onSoundComplete 348
SoundTransform 372
Streaming 346
String 9, 10, 262
verketten 261
verknüpfen 20
substr 357
substr() 357
Subtraktion 18
switch
Syntax 30
switch-Bedingungen 30
switch-case 30
T
TEXT
URLLoaderDataFormat 315
text 334
TextArea 175
Textdatei
Daten einlesen 241
einlesen 267
toString 270
U
uint 12
undefined 12
Ungleichheit
strikte 22
URL-Codierung 241, 242
URLLoader 309
URLRequest 309
Usability 253
V
Variablen 8
einlesen 241
globale 13
Gültigkeitsbereiche 13
in Arrays 280
lokale 13
nicht deklarierte 14
superglobale 14
Variablendeklaration 8
explizit 9
globale 16
implizit 14
lokale 16
Variablennamen 9
dynamisch erzeugen 277
Variablentypen 9
VARIABLES
URLLoaderDataFormat 315
Verzeichnisse
auslesen 356
volume 372
W
Werte zuweisen 19
WHILE-Schleife 40
Wurzelelement 58, 272
X
XHTML 167
XML 56, 168, 233, 266, 325
Arrays auslesen 273
Attribute 339
Attribute auslesen 61
auf Elemente zugreifen 272
auswerten 275
Befehle 266
Child 272
Dokumente 56
einlesen 266
encoding 57
erstellen 62
Gültigkeit 57
Inhalt 57
in String umwandeln 270
Knoten 273, 274
Knoten auslesen 62
Prolog 57
Sibling 272
standalone 57
Syntax 59
versenden 294
version 57
Wohlgeformtheit 57
XML-Attribute
speichern 342
XML-Baum 270
in Flash erzeugen 287
XMLConnector 298
xmlDecl 289
XML-Header 287
XMLHttpRequest 125
XML-Klasse 72
XML-konform 268
XML-Objekt 266, 325, 341
XML-Struktur 339
Z
Zählvariable 31, 257
Zeitleistenvariablen 13
Zustände 21
Copyright
Daten, Texte, Design und Grafiken dieses eBooks, sowie die eventuell angebotenen
eBook-Zusatzdaten sind urheberrechtlich geschützt. Dieses eBook stellen wir
lediglich als persönliche Einzelplatz-Lizenz zur Verfügung!
Jede andere Verwendung dieses eBooks oder zugehöriger Materialien und
Informationen, einschliesslich
• der Reproduktion,
• der Weitergabe,
• des Weitervertriebs,
• der Platzierung im Internet,
in Intranets, in Extranets,
• der Veränderung,
• des Weiterverkaufs
• und der Veröffentlichung
bedarf der schriftlichen Genehmigung des Verlags.
Insbesondere ist die Entfernung oder Änderung des vom Verlag vergebenen
Passwortschutzes ausdrücklich untersagt!
Bei Fragen zu diesem Thema wenden Sie sich bitte an: info@pearson.de
Zusatzdaten
Möglicherweise liegt dem gedruckten Buch eine CD-ROM mit Zusatzdaten bei. Die
Zurverfügungstellung dieser Daten auf unseren Websites ist eine freiwillige Leistung
des Verlags. Der Rechtsweg ist ausgeschlossen.
Hinweis
Dieses und viele weitere eBooks können Sie rund um die Uhr
und legal auf unserer Website
http://www.informit.de
herunterladen

Flash cs3, ajax und php

  • 2.
  • 4.
    Flash CS3, AJAX undPHP Ein Imprint von Pearson Education München • Boston • San Francisco • Harlow,England Don Mills,Ontario • Sydney • Mexico City Madrid • Amsterdam ADDISON-WESLEY Uwe Mutz
  • 5.
    Bibliografische Information DerDeutschen Bibliothek Die Deutsche Bibliothek verzeichnet diese Publikation in der Deutschen Nationalbibliografie; detaillierte bibliografische Daten sind im Internet über http://dnb.ddb.de abrufbar. 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 und weitere Stichworte und sonstige Angaben, die in diesem Buch verwendet werden, sind als eingetragene Marken geschützt. Da es nicht möglich ist, in allen Fällen zeitnah zu ermitteln, ob ein Markenschutz besteht, wird das ®Symbol in diesem Buch nicht verwendet. Umwelthinweis: Dieses Buch wurde auf chlorfrei gebleichtem Papier gedruckt. Alle Rechte vorbehalten. Kein Teil des Buches darf ohne Erlaubnis der Pearson Education Inc. in fotomechanischer oder elektronischer Form reproduziert oder gespeichert werden. 10 9 8 7 6 5 4 3 2 1 09 08 07 ISBN 978-3-8273-2528-0 © 2007 Addison-Wesley Verlag, ein Imprint der PEARSON EDUCATION DEUTSCHLAND GmbH, Martin-Kollar-Str. 10-12, 81829 München/Germany Alle Rechte vorbehalten Lektorat: Brigitte Bauer-Schiewek, bbauer@pearson.de Fachlektorat: Matthias Kannengiesser Korrektorat: Petra Kienle Herstellung: Claudia Bäurle, cbaeurle@pearson.de Satz: Ulrich Borstelmann, Dortmund (www.borstelmann.de) Einbandgestaltung: Marco Lindenbeck, webwo GmbH, mlindenbeck@webwo.de Druck und Verarbeitung: Kösel Druck, Krugzell (www.koeselBuch.de) Printed in Germany
  • 6.
    V INHALTSVERZEICHNIS Sieh' einer an… IX Kapitel 1 Einleitung 1 Kapitel 2 Grundlagen der Programmierung 5 2.1 Programmierung in Flash 6 2.1.1 Anlehnung an JavaScript 6 2.1.2 Objektorientiertes Programmieren 6 2.2 Kommentare 7 2.2.1 Einzeilige Kommentare 7 2.2.2 Mehrzeilige Kommentare 7 2.2.3 Verschachtelte Kommentare 8 2.3 Variablen und Datentypen 8 2.3.1 Variablendeklaration 8 2.3.2 Variablennamen 9 2.3.3 Datentypen 10 2.3.4 Gültigkeitsbereiche von Variablen 13 2.4 Operatoren 17 2.4.1 Arithmetische Operatoren 17 2.4.2 Zuweisungsoperatoren 18 2.4.3 Bitoperatoren 21 2.4.4 Logische Operatoren 21 2.4.5 Vergleichsoperatoren 22 2.4.6 Rangordnung der Operatoren 22 2.5 Arrays 24 2.5.1 Indizierte Arrays 24 2.5.2 Assoziative Arrays 25 2.6 Bedingungen 28 2.6.1 if-Bedingung 28 2.6.2 switch-Bedingung 30
  • 7.
    VI 2.7 Schleifen 31 2.7.1for-Schleife 31 2.7.2 for...each- oder for...in-Schleife 37 2.7.3 do..while-Schleife 39 2.7.4 while-Schleife 40 2.8 Funktionen 41 2.9 Cookies 47 2.9.1 Exkurs HTTP 47 2.10 Sessions 50 2.10.1 session_start() 51 2.10.2 session_register() vs. $_SESSION 51 2.10.3 session_unregister() vs. $_SESSION 53 2.10.4 session_destroy() 53 2.11 Caching 53 2.12 XML auslesen und erstellen 56 2.12.1 Der Aufbau eines XML-Dokuments – Blitzeinführung 56 2.12.2 Auslesen einer XML-Struktur 60 2.12.3 XML-Dokumente erstellen 62 Kapitel 3 Basiswissen 65 3.1 PHP 66 3.2 JavaScript (AJAX) & DOM 66 3.2.1 „Kern-DOM“ 67 3.2.2 Alternativer Zugriff auf Objekte 69 3.3 Flash 72 3.3.1 Sinnvolle Kombination von Flash und PHP 72 3.3.2 Weitere Verbindungsmöglichkeiten zur Serverseite 73 3.3.3 ActionScript 3.0 – die wichtigsten Änderungen 73 Kapitel 4 AJAX – Asynchronus JavaScript and XML 119 4.1 Was ist AJAX? 120 4.2 Was ist AJAX nicht? 120 4.3 Der XMLHttpRequest 122 4.3.1 Details zum XMLHttpRequest-Objekt 125 4.3.2 AJAX im Einsatz 128
  • 8.
    VII 4.4 Flash vs.AJAX 164 4.5 Flash & AJAX 165 Kapitel 5 Clientseitiger Datenaustausch – Flash & Javascript 167 5.1 Daten senden: Browser an Flash 168 5.1.1 Variante 1: JavaScript greift auf die SWF-Datei zu 168 5.1.2 Variante 2: Verwenden von HTML-Attributen zum Setzen von Variablen 179 5.2 Daten senden: Flash an Browser 181 5.2.1 Kontaktaufnahme mit getURL 181 5.3 Die ExternalInterface-Klasse – Flash 8 und höher 184 5.3.1 ExternalInterface-Klasse mit ActionScript 1.0/2.0 185 5.3.2 ExternalInterface-Klasse mit ActionScript 3.0 207 5.4 Flash & AJAX 208 5.4.1 Parameterübergabe: Text 209 5.4.2 Parameterübergabe: XML 233 Kapitel 6 Serverseitiger Datenaustausch – Flash, PHP & Datenbank 239 6.1 Drei Technologien im Einsatz 240 6.2 Das LoadVars-Objekt 241 6.3 Die Basis: das XML-Objekt & ActionScript 2.0 266 6.3.1 Grundlegende XML-Befehle 266 6.3.2 Einlesen von XML-Daten 266 6.3.3 Ausgeben von XML-Daten in eine PHP-Seite 286 6.3.4 Die XMLConnector-Komponente 298 6.4 ActionScript 3.0: Neues und Änderungen 309 6.4.1 Das URLLoader- und URLRequest-Objekt 309 6.4.2 Der Aufbau: das XML-Objekt & ActionScript 3.0 325 Kapitel 7 Audio-Jukebox 337 7.1 Abfragen serverseitiger Informationen 338 7.2 Multimediale Anwendungen 338 7.3 Konzept der Jukebox 338 7.3.1 Playlist generieren 338
  • 9.
    VIII 7.4 Jukebox inActionScript 2.0 340 7.4.1 XML-Daten laden 341 7.4.2 Abspielen der Songs 344 7.4.3 ID3-Tags auslesen 349 7.4.4 Abspielsteuerung 351 7.4.5 Lautstärkeregler 353 7.5 Der PHP-Part 355 7.6 Jukebox in ActionScript 3.0 359 7.6.1 Allgemeine Änderungen 359 7.6.2 Änderungen beim Laden der XML-Daten 360 7.6.3 Änderungen im Soundobjekt 363 7.6.4 Änderungen in der Abspielsteuerung 363 7.6.5 Änderungen in der Lautstärkeregelung 370 7.6.6 Songs aus einer ComboBox abspielen 372 7.7 Mögliche Erweiterungen 374 Kapitel 8 Videoplayer (ActionScript 3.0) 375 8.1 Das Konzept des Videoplayers 376 8.2 Flash & Video 376 8.3 Die Umsetzung 378 8.3.1 Flash und die FLVPlayback-Komponente 378 8.3.2 Videos im FLV-Format 382 8.3.3 Dynamisches Verknüpfen der FLVPlayback-Komponente mit einem Video 392 8.3.4 Schritt 1: Abspielen einer Liste von Videos (Array) 394 8.3.5 Schritt 2: Abspielen einer Liste von Videos (XML) 401 8.3.6 Arbeiten mit Cue-Points 426 Stichwortverzeichnis 429
  • 10.
    IX SIEH’EINER AN … Schön,Sie hier zu treffen! Ein Sprichwort sagt „Alles neu macht der Mai“ – nun, Flash erstrahlt in Version CS3, PHP läuft stabil in Version 5 und um AJAX müssen wir uns keine Sorgen machen, denn da setzen wir auf die bekannten (und bewährten) Technologien JavaScript und XML. Mit anderen Worten: Dieses Buch baut auf Bewährtem und Neuem auf. Lassen Sie sich überraschen! Aber alles der Reihe nach. Zunächst einmal freut es mich, dass Sie sich für dieses Buch entschie- den haben. Es zeigt mir, dass die Kombination von Flash und PHP nach wie vor ein beliebtes Thema ist. Und mit „Web 2.0“ ist auch AJAX in aller Munde – und wie es scheint auch in Ihrem Interesse. Meine geschätzte Leserschaft Bevor wir ans Eingemachte gehen, möchte ich ein paar Worte vorausschicken, für wen dieses Buch geschrieben ist und – vor allem! – für wen dieses Buch nicht geschrieben ist (ich denke, es ist wichtiger, solche „Nicht-Ziele“ zu definieren). Das sind meine Leser! Dieses Buch ist für Einsteiger in die Thematik „Flash & PHP & AJAX“ geschrieben. Dabei gehe ich davon aus, dass meine Leser mit der Arbeitsweise von Flash, PHP & JavaScript vertraut sind, sie also den Umgang mit Folgendem im Schlaf beherrschen : Flash: Die „Zeit“: Der Umgang mit der Zeitleiste ist kein Problem, ebenso wissen Sie über Schlüsselbilder, benannte Bilder und Szenen Bescheid. Die „Elemente“: Formen, Symbole und Instanzen, grundlegende Komponenten stellen für Sie in der Anwendung kein Problem dar, Benennung von Instanzen, Definieren von Instanz-Eigenschaften etc. erledigen Sie ohne nachzudenken. .fla versus .swf: Selbstverständlich ist Ihnen der Unterschied zwischen der Flash- und der SWF-Datei bekannt, auch haben Sie schon unzählige Male eine SWF-Datei in ein Web- dokument eingebunden. Die Problematik verschiedener Browser-Systeme (Einbinden der SWF-Dateien mittels <embed> oder <object>) kennen Sie ebenso. ActionScript: Dass hiermit die in Flash verwendete Programmiersprache gemeint ist, wissen Sie. Dabei hatten Sie bereits ersten Kontakt mit grundlegenden Befehlen wie etwa stop(), play(), gotoAndPlay(), gotoAndStop() usw. – die Grundlagen der Pro- grammierung sind Ihnen bekannt und ein wenig programmiert haben Sie auch schon. u u u u u
  • 11.
    X JavaScript: Sie sindeventuell (noch) kein Programmierprofi, jedoch wissen Sie, wie man mit dem <script>-Tag umgeht und dass man JavaScript-Code in einer externen Datei ablegen kann, welche sich im Weiteren mit einem Webdokument verknüpfen lässt. Wahr- scheinlich sind Sie sogar in der Lage, grundlegenden Code zu schreiben und auch kleinere Projekte zu verstehen – ansonsten helfen Ihnen das einleitende Kapitel „Grundlagen der Programmierung“ und die einschlägige Literatur weiter. PHP und MySQL: Server- versus Clientseite: PHP ist eine serverseitige, JavaScript eine clientseitige Pro- grammiersprache – kein Thema, das wissen Sie. Programmierung: Ein wenig Erfahrung haben Sie bereits gesammelt bzw. Sie haben zumindest schon einmal PHP-Code geschrieben. Sollte dem nicht so sein – wie gesagt, dann ist das Einleitungskapitel für Sie gedacht. Datenbanken: Die Grundlagen relationaler Datenbanken kennen Sie, ebenso haben Sie bereits einmal mit MySQL in Zusammenhang mit einer datenbankbasierten Weban- wendung gearbeitet. Das System PHPMyAdmin ist Ihnen auch ein Begriff und Tabel- len können Sie anlegen, mit Daten befüllen und auch administrieren. Nein? Kapitel „Grundlagen der Programmierung“ … Die liebe Programmierung … Sollten Sie mit der Programmierung noch nicht so sehr vertraut sein, so ist Ihnen das Kapitel „Grundlagen der Programmierung“ gewidmet, in dem Sie das notwendige Rüstzeug vermittelt bekommen, um die fol- genden Kapitel locker bewältigen zu können. Bedenken Sie jedoch bitte, dass es sich hierbei nicht um ein allumfassendes Werk zu den genannten Technologien handelt und deshalb im Abschnitt zu den Grundlagen der Programmierung auch nur die für die restlichen Kapitel notwendigen Themen behandelt werden. Diese Leser werden nicht glücklich! Wie schon eingangs erwähnt, ist dieses Buch für Einsteiger geschrieben. Sollten Sie also bereits Programmierprofi sein, Hunderte Projekte in Flash realisiert und jegliche Arten von Daten- banksystemen realisiert haben, dann werden Sie die in diesem Buch beschriebenen Inhalte nicht befriedigen. Das Anwenden von Flash-Komponenten zur Kommunikation mit serversei- tigen (Adobe-)Anwendungen ist zwar ein Teil des Buchs, spielt jedoch nur eine untergeordnete Rolle. Ich werde auch nicht den Versuch machen, den kürzest möglichen Programmcode zu schrei- ben, denn dies geht meist auf Kosten der Lesbarkeit und somit der Verständlichkeit des Pro- grammierten. Ein perfekter Programmierer wird man nie, ein sehr guter Programmierer wird man durch das tägliche Programmieren – auf diesen Weg kann ich Sie führen, indem ich Ihnen den Einstieg so einfach wie möglich mache. u u u u u
  • 12.
    XI Ein immerwährendes Problemin der Welt des Internets sind die Browser: verschiedene Gene- rationen von Browsern, verschiedene Browser, verschiedene Plattformen – zumeist verhalten sie sich unterschiedlich und liefern unterschiedliche Resultate. Ich werde in diesem Buch nicht den Versuch anstellen, alle nur erdenkbaren Eventualitäten zu berücksichtigen, sondern viel- mehr Rücksicht auf die gängigen Browser nehmen: Microsoft Internet Explorer 6 unter Windows Microsoft Internet Explorer 7 unter Windows Firefox 2 unter Windows und Mac OS X Opera 9.1 unter Windows und Mac OS X Safari 2.0.4 unter Windows Diese Browser stellen mit Sicherheit den repräsentativen Querschnitt über alle gängigen und im Einsatz befindlichen Browser weltweit dar – alle weiteren Browser lasse ich „links liegen“. Zusammengefasst: Profis werden in diesem Buch nicht die gewünschten Inhalte finden – dies ist ein Einsteigerbuch! Für Sie, meine lieben Experten, hält Addison-Wesley eine Reihe von Büchern bereit, die Ihren Ansprüchen gerecht werden und auch noch die letzte Frage beant- worten. Danke! An dieser Stelle wird es im Allgemeinen persönlich … Wohl nichts, das den Inhalt eines Buchs wesentlich beeinflussen würde, aber eine wunderbare Möglichkeit, sich zurückzulehnen, zu erfreuen an einem sonnigen Tag und die verstrichene Zeit Revue passieren zu lassen. Mit der Zeit tritt dann eine innere Dankbarkeit ein, die darauf wartet, nach außen zu treten und DANKE in die Welt zu schreien – danke all den Menschen, die mir wertvoll sind und mein tägliches Leben bereichern. Allen voran meiner geliebten Freundin Doris, die mir mein tägliches Maß an Freude und Spaß zu servieren weiß und mich mit Motivation und Lebensfreude versorgt – meine lieben Herren, ihr könnt euch glücklich schätzen, wenn auch ihr mit einer solch tollen Freundin gesegnet seid. Werte Damen – sorry, ich bin vergeben! Im selben Atemzug danke ich meiner Familie für eigentlich alles! Geburt (inklusive Zeugung), Erziehung, Ausbildung, Unterstützung, Liebe, Freundschaft, Rat und Tat – nichts blieb auf der Strecke. Und ganz nebenbei haben diese beiden auch dafür gesorgt, mir eine tolle Schwester zu schenken (die mir wiederum einen tollen Neffen geschenkt hat ...)! Alle meine Freunde, mit denen ich feiern und Spaß haben kann. Jungs, manchmal muss ich euch zwar motivieren, aus euren trauten Heimen zu kriechen, um etwas zu unternehmen, aber das erledige ich gerne. Caro, AIC, ToM, Gott, Chris, Clemens, Erik, Hari und viele mehr, die u u u u u
  • 13.
    XII mich sicherlich schimpfenwerden, dass sie hier namentlich nicht erwähnt sind („… wie konn- test du mich nur vergessen …“ usw.). Ein herzlicher Dank gebührt auch meinem Verlag und meinen Lektoren, die mich so nett in ihren Kreis aufgenommen haben und mir bei jeder Frage und jedem Anliegen mit Tipp und Tat zur Seite standen – ich freue mich auf jede Zusammenarbeit, die noch kommen wird! Zu guter Letzt danke ich Ducati für meine Monster, Metallica für die Art von Musik, die ich täglich brauche, und meinem Doktorvater Gü Blaschek für all die tollen Gespräche, die mich immer wieder über Gott und die Welt nachdenken lassen. Me, myself and I … Uwe Mutz
  • 14.
    1 EINLEITUNG Flash, AJAX undPHP – das wird spannend! Vor kurzem ist die neueste Version von Flash in deutscher Ver- sion erschienen: Flash CS3. Viele Entwickler waren schon sehr auf die Neuerungen und Änderungen gespannt. Und wissen Sie was – sie wurden nicht enttäuscht! Sogar ganz im Gegenteil ... Was Flash speziell für Programmierer durch die Einführung von ActionScript 3.0 zu bieten hat, ist schon fast eine Sensation. Beinahe kein Stein blieb auf dem anderen, die hart erworbenen Kenntnisse in ActionScript 2.0 dienen mehr oder weniger nur noch dafür, dass man sich ein bisschen „zurechtfindet“. Ange- fangen von einfachen Änderungen in den Bezeichnungen von Eigenschaften bis hin zum kompletten Wegfall diverser Klassen (bzw. Verschieben in andere Pakete) ist alles gegeben. Da ich an dieser Stelle aber nicht davon ausgehen kann, dass ab jetzt sämtliche Entwicklungen in ActionScript 3.0 erfolgen (dies setzt nämlich den Flash9-Player voraus), gehe ich in diesem Buch sowohl auf die Version 2.0 als auch auf 3.0 von ActionScript ein. Gerade einmal das letzte Beispiel in diesem Buch – der Videoplayer – ist komplett in ActionScript 3.0 ent- wickelt worden. Gerade bei Videos bietet sich ActionScript 3.0 geradezu an. Der zweite große Workshop im Buch – der Audio- player – ist sowohl in ActionScript 2.0 als auch 3.0 entwickelt. Ideal also, um einen Vergleich der beiden Versionen zu ziehen.
  • 15.
    K A PI T E L 12 Mein Tipp in Bezug auf die beiden Versionen (ActionScript 1.0 mal außer Acht gelas- sen): Sollten Sie sich in eine Version gezielt einarbeiten wollen, beschäftigen Sie sich primär mit der 3.0er Version, denn sie ist mit Sicherheit die Zukunft. Es wird nicht mehr lange dauern, bis die Mehrheit der Internet-User auf den Flash9-Player umge- stellt hat. Dieses Buch wird sich nur sehr oberflächlich mit allen Komponenten und Möglich- keiten befassen, die im Rahmen der Entwicklungsumgebung auf der Bühne platziert werden. Umso mehr ist der Fokus auf die Programmierung gerichtet. Ein Flash Com- munication Server wird ebenso wenig ein Thema sein wie Elemente der FileReference- Klasse usw. Primäres Ziel des Buchs ist es, die Möglichkeiten der Zusammenarbeit dreier Technologien zu zeigen und nicht jede Technologie für sich. Warum sich das Buch mit PHP beschäftigt, liegt auf der Hand: PHP hat sich zu der serverseitigen Programmiersprache entwickelt, um die man einfach nicht mehr herumkommt. Und das aus gutem Grunde, wurde sie doch speziell für den Einsatz im Web entwickelt. Und welche andere serverseitige Programmiersprache kann das schon von sich behaupten? Da sich die Syntax an die gängigen Standards anlehnt, ist das Erlernen nicht allzu aufwändig. Hat man den Unterschied zwischen Server- und Clientseite einmal verstanden, ist eigentlich alles klar. Alternativ könnte man genauso gut auf ASP, ASP.NET oder JSP zurückgreifen, aber warum eine weniger gängige Technologie einsetzen, wenn das Gute doch so nah liegt? Dass das Thema AJAX in diesem Buch aufgegriffen wird, mag schon etwas weniger auf der Hand liegen, denn im Grunde genommen ist Flash in der Lage, so gut wie alle Bereiche abzudecken, die uns AJAX auf Clientseite ermöglicht. Spannend wird die Sache jedoch, wenn man sich die Möglichkeiten überlegt, wie sich Flash und AJAX ergänzen können. Ein guter Webdesigner entwickelt nicht stur in eine Richtung, son- dern kennt die User seiner Webanwendungen. Genau aus diesem Grund ist es manch- mal notwendig, parallel in AJAX und Flash zu entwickeln. Sollte man dann nicht genau wissen, in welchen Bereichen sich AJAX und Flash überschneiden? Ich denke schon. Mindestens genauso spannend ist es, wenn „gemischte“ Webanwendungen mit AJAX und Flash entwickelt werden müssen. Flash interagiert mit AJAX, AJAX interagiert mit Flash. So läuft der Hase! Dass in diesem Buch nicht alle Anwendungsgebiete abgedeckt werden können, versteht sich von selbst. Aus diesem Grunde habe ich mich für multimediale Anwendungen mit Audio- und Videodaten entschieden. Das „Dahinter“ („Wie erhält ein Videoplayer seine Playlist?“ etc.) wird vor allem über XML-Daten realisiert, Interaktion mit dem Browser erfolgt zumeist über die ExternalInterface-Klasse. PHPPHP AJAXAJAX
  • 16.
    E I NL E I T U N G 3 Besonders wichtig ist mir, dass Sie nach dem Lesen dieses Buchs ein Grundverständnis für die Arbeit mit Flash, AJAX und PHP als Paket entwickelt haben und einsetzen können. Kochrezepte werden Sie nur wenige finden. Aber Hand aufs Herz – ohne Denken läuft in unserem Business sowieso nichts mehr! Dann empfiehlt es sich, lieber ein gutes Verständnis einer Thematik zu haben, als Kochrezepte einzusetzen, die man nicht versteht! Abschließend: Sollten Sie Fragen zu den Inhalten oder Anregungen haben, so freue ich mich über eine Kontaktaufnahme per E-Mail: flashajaxphp@syne.at.
  • 18.
    2 GRUNDLAGEN DER PROGRAMMIERUNG Variablen, Arrays,Schleifen und Co. sind das Handwerkszeug eines Programmierers. In diesem Kapitel werden wir uns mit den theoretischen Grundlagen von Programmiersprachen befassen. Haben Sie diese Grundlagen einmal verstanden, steht Ihnen eigentlich die ganze Welt der Programmierung offen. Da dieses Buch dynamische Flash-Anwendungen durch den Einsatz von ActionScript und PHP zum Thema hat, zeigen wir Ihnen die Grundlagen der Programmierung auch gleich anhand dieser zwei Programmiersprachen. Des Weiteren erhal- ten Sie im Rahmen dieses Kapitels eine Blitzeinführung zum Thema XML. InvielenFällenmüssenwirdabeinichtzwischenPHP,JavaScript und ActionScript unterscheiden. Wo dies jedoch notwendig ist, finden Sie in der äußeren Spalte neben dem Text einen Hinweis für PHP, JavaScript bzw. für ActionScript.
  • 19.
    K A PI T E L 26 Bitte beachten Sie jedoch, dass dieses Buch ein umfassendes Buch zu den Themen PHP, JavaScript und ActionScript weder ersetzen kann noch soll. Dieses Kapitel dient dazu, Ihnen die notwendigen Voraussetzungen mit auf den Weg zu geben – jedoch nur die notwendigen Voraussetzungen, die Sie für die weiteren Kapitel benötigen. 2.1 Programmierung in Flash Anders als in gängigen Programmiersprachen muss in Flash – aufgrund seines Ursprungs als Animationsprogramm – die Zeitleiste berücksichtigt werden. Somit müssen wir mit dem Faktor „Zeit“ umgehen lernen. Wie Sie bereits gehört haben, ist die Programmierung in Flash auf drei verschiedene Arten möglich: 1. Programmierung in der Zeitleiste (egal, ob Zeitleiste der Bühne oder die eines MovieClip) 2. Bei MovieClips über MovieClip-Ereignisse (diese werden Sie noch kennenlernen) 3. Bei Schaltflächen über Schaltflächen-Ereignisse (sie werden ebenfalls noch vorgestellt) 2.1.1 Anlehnung an JavaScript ActionScript ist eine Programmiersprache, die sich an JavaScript (bekannt aus der Webprogrammierung) anlehnt, jedoch nicht genau deren Umfang hat. Detailliert soll auf diese Tatsache nicht eingegangen werden, nur eines sei noch erwähnt: Können Sie JavaScript programmieren, so ist es ein Leichtes, ActionScript zu programmieren. 2.1.2 Objektorientiertes Programmieren Oft ist die Rede von ActionScript 1.0, ActionScript 2.0 und ActionScript 3.0. Der wesentliche Unterschied zwischen den ersten beiden Versionen besteht darin, dass Version 2.0 im Gegensatz zu Version 1.0 objektorientiert ist. Ein weiteres Feature ist die Möglichkeit einer strikten Typisierung, auf die wir im Verlauf dieses Kapitels noch näher eingehen werden. Für unsere Anwendungen wird es nicht notwendig sein, objektorientiert zu programmieren, deshalb ist ein umfassendes Verständnis von ActionScript 2.0 nicht erforderlich. ActionScript 3.0 stellt eine beinahe vollkommene Neuentwicklung von ActionScript dar. Sämtliche Unterschiede und Änderungen fin- den Sie in der ActionScript-Referenz unter dem Schlagwort „ActionScript 2.0 Migra- tion“, auf die wesentlichen Änderungen gehen wir im Weiteren noch genauer ein. Bitte beachten Sie jedoch, dass die einleitenden Kapitel dieses Buchs keinesfalls ein Action- Script-Buch und schon gar kein ActionScript 3.0-Buch ersetzen können! Kein allumfas- sendes Werk zu PHP, JavaScript und ActionScript! Kein allumfas- sendes Werk zu PHP, JavaScript und ActionScript! MovieClips Bei der Programmierung mit MovieClips ist es von besonderer Bedeutung, den verwendeten MovieClips einen Namen zu geben.
  • 20.
    G R UN D L A G E N D E R P R O G R A M M I E R U N G 7 So weit zu den einfachen Dingen, nun zu den etwas schwierigeren: Wir müssen uns die Grundlagen der Programmierung aneignen und das bedeutet ein hartes Stück Arbeit. Es wäre viel zu trocken, diesen Part rein theoretisch zu halten, also werden wir beglei- tend dazu einige kleine Beispiele programmieren. Die folgenden Ausführungen können – wenn nicht anders vermerkt – für die Pro- grammiersprachen JavaScript, ActionScript und PHP verstanden werden. 2.2 Kommentare Gleich zu Beginn dieses Kapitels möchten wir Sie auf die Möglichkeit der Kommentie- rung Ihrer Scripte hinweisen. Dies ist natürlich nicht zwingend notwendig, jedoch sehr wichtig und hilfreich. Beim Erstellen Ihres Programms ist wahrscheinlich der Code noch verständlich und logisch. Ob dies nach ein oder zwei Monaten immer noch so ist, ist fraglich. Zusätzlich erleichtern Sie Kollegen die Arbeit mit Ihren Scripten, wenn diese gut kommentiert sind. Nutzen Sie Kommentare also so oft wie möglich. 2.2.1 Einzeilige Kommentare Zwei Schrägstriche // leiten einen Kommentar ein, und zwar einen zeilenweisen Kom- mentar. Alles, was Sie in dieser Zeile nach den Schrägstrichen schreiben, wird nicht als Befehl interpretiert, sondern nur als Anmerkung, also als Kommentar. //dies ist ein einzeiliger Kommentar 2.2.2 Mehrzeilige Kommentare Sollten Sie einen Kommentar benötigen, der über mehrere Zeilen geht, so können Sie ihn mit einem beginnenden /* und einem (in irgendeiner der darunterstehenden Zeilen) endenden */ einschließen, also z.B. so: /* dies ist ein mehrzeiliger Kommentar */ Im Allgemeinen werden Kommentare im Code verwendet, um die Ideen während der Entwicklung des Codes bzw. wichtige Informationen zu Variablen, Objekten etc. (etwa deren Bedeutung oder mögliche Werte) festzuhalten. Ein weiteres Anwendungsgebiet ist das „Auskommentieren„ von nicht verwendeten Codezeilen: Der Entwickler ist grundsätzlich immer versucht, den bereits geschriebenen Code bei Nichtverwendung keinesfalls einfach zu löschen, sondern ihn – sollte er wider Erwarten doch noch benö- tigt werden – auszukommentieren.
  • 21.
    K A PI T E L 28 Bitte beachten Sie, dass sowohl ein- als auch mehrzeilige Kommentare an derjenigen Stelle beginnen, an der die Kommentarzeichen gesetzt werden. Dabei werden einzeilige Kommentare oft verwendet, um am Ende einer Codezeile diverse Anmerkungen zu platzieren, wie etwa: var modus:Number = 1; //Nur die Werte 1 und 2 sind gueltig Im obigen Beispiel wird so deutlich, dass bei Verwendung der Variablen modus nur die Werte 1 oder 2 zugewiesen werden dürfen. Beachten Sie bitte weiterhin, dass erklärende (ein- oder mehrzeilige) Kommentare besser vor den Codeblock geschrieben werden, wo diese Erklärung benötigt wird. 2.2.3 Verschachtelte Kommentare Verschachtelte Kommentare sind in PHP nicht erlaubt. Das Ausführen Ihres Pro- gramms wird in solch einem Fall abgebrochen. 2.3 Variablen und Datentypen 2.3.1 Variablendeklaration Wenn Sie ein Programm erstellen, müssen Sie bestimmte Werte für die spätere Ver- wendung sicher und eindeutig speichern. Denken Sie einfach an ein Spiel, in dem der User zu Beginn seinen Nickname nennt. Im weiteren Verlauf des Spiels werden wir diesen Spieler immer an diesem Namen erkennen und ihn auch mit diesem Namen ansprechen. Damit ist eine klare Identität gegeben. Eingegebene Werte sind dann unter diesem Namen jederzeit abrufbar. In diesem Fall würden wir zum Beispiel eine Variable namens plNickname anlegen und in ihr den eingegebenen Namen des Spielers speichern. $plNickname ; // Variablendeklaration $plNickname = "Uwe"; // der Variable $plNickname wird der Wert Uwe zugewiesen Listing 2.1: PHP erkennt Variablen immer am $-Zeichen, das ohne Leerzeichen direkt vor dem Namen der Variable stehen muss. In sehr vielen anderen Programmiersprachen muss eine Variable vor ihrer Verwen- dung deklariert, d.h. ins Leben gerufen werden. Würde dies nicht erfolgen, könnte man mit der gewünschten Variable nicht arbeiten, da sie noch nicht existiert. Da wir PHP als serverseitige Programmiersprache verwenden, wäre es eigentlich nicht nötig, Variablen am Anfang eines Scripts zu deklarieren. Jedoch sollten Sie sich trotzdem angewöhnen, Variablen immer anzugeben, da Sie dadurch einen besseren Überblick über die verwendeten Variablen erhalten. PHPPHP Variablen- deklaration immer am Anfang Variablen- deklaration immer am Anfang
  • 22.
    G R UN D L A G E N D E R P R O G R A M M I E R U N G 9 Befehle abschließen Im obigen Fall finden Sie noch einen weiteren Punkt, der bei der Programmierung wichtig ist: Wie Sie sehen, ist jede Zeile mit einem Strichpunkt abgeschlossen. Dies ist in PHP zwingend notwendig, in Flash nicht. Variablentypen In Flash verhält es sich ähnlich, jedoch hat man seit der Einführung von ActionScript 2.0 die Möglichkeit, Variablen explizit zu deklarieren, wovon Sie auch Gebrauch machen sollten. Wie Sie gleich im nächsten Abschnitt sehen werden, sollte bei guter Programmierung in Flash neben dem „Erwähnen“ der Variable über deren Namen auch der Typ der Variable angegeben werden. Würden wir das Beispiel aus PHP von oben umsetzen, so würde das wie folgt aussehen: var plNickname:String; plNickname = "Uwe"; Listing 2.2: Variablendeklaration und anschließende Wertzuweisung in Flash In der ersten Zeile wird eine Variable vom Typ String (das ist ein Text) angelegt. Dies bedeutet nichts anderes, als dass in dieser Variablen nur Textwerte gespeichert werden. In der zweiten Zeile wird dieser Variablen der Wert „Uwe“ zugewiesen. Bitte beachten Sie an dieser Stelle, dass String-Werte immer in Anführungszeichen stehen. Kürzt man die beiden Zeilen noch etwas ab, so erhält man nachfolgenden Code, in dem gleichzeitig mit der Variablendeklaration auch eine Wertzuweisung erfolgt: var plNickname:String = "Uwe"; Listing 2.3: Variablendeklaration und gleichzeitige Wertzuweisung Somit wissen wir, wie man Variablen anlegt und ihnen einen Wert zuweist. Jetzt müs- sen wir uns kurz Gedanken darüber machen, welche Variablennamen gültig sind und welche nicht. In JavaScript wird wie in PHP bei der Variablendeklaration nicht zwischen verschie- denen Variablentypen unterschieden, deshalb erfolgt die Zuweisung wie folgt: var plNickname = "Uwe"; Listing 2.4: Variablendeklaration und anschließende Wertzuweisung in JavaScript 2.3.2 Variablennamen Bei der Namensgebung der Variablen in Flash, JavaScript und PHP müssen Sie einige Regeln strikt beachten: ActionScriptActionScript JavaScriptJavaScript
  • 23.
    K A PI T E L 210 Variablen … müssen in PHP mit einem Dollarzeichen „$“ beginnen (in Flash und JavaScript ist dies nicht der Fall). dürfen keine Leerzeichen enthalten. dürfen nur aus Buchstaben und Ziffern bestehen, wobei das erste Zeichen nach dem Dollarzeichen ein Buchstabe sein muss. dürfen Groß- und Kleinbuchstaben enthalten. PHP und ActionScript (ab Version 2.0) sind Case-sensitive und erkennen die Unterschiede. dürfen keine Umlaute wie ä, ö, ü und kein ß enthalten. dürfen als einziges Sonderzeichen den Unterstrich „_“ enthalten. dürfen nicht wie Befehle der Sprache PHP, JavaScript bzw. ActionScript benannt sein (eine Auflistung aller Befehle entnehmen Sie bitte den jeweiligen Sprachrefe- renzen). Bitte gewöhnen Sie sich an, für die „Taufe“ der Variablen möglichst selbst erklärende Namen zu verwenden. Damit sind Sie (und auch andere Personen) in der Lage, Ihren Code auch später schnell und unmissverständlich zu lesen und zu erfassen. Originali- tät bei der Namensvergabe wäre hier völlig fehl am Platz. 2.3.3 Datentypen Der Typ der Daten legt verbindlich fest, welcher Inhalt in den Variablen gespeichert werden kann. Man kann auch sagen, dass der Datentyp die Art der Information beschreibt, die in der Variable gespeichert werden soll. In PHP gibt es folgende Datentypen: Ganze Zahlen (Integer) Zahlen mit Nachkommastellen (Float) Zeichenketten (String) Felder (Array) Objekte Zum Glück müssen wir uns in PHP und JavaScript über den Inhalt von Variablen wenig Gedanken machen. PHP und JavaScript entscheiden nämlich selbst, welcher Datentyp für welchen Inhalt verwendet werden soll. So kann es durchaus vorkommen, dass eine Variable im Laufe eines Programms ihren Datentyp selbstständig ändert. u u u u u u u u u u u u PHPPHP
  • 24.
    G R UN D L A G E N D E R P R O G R A M M I E R U N G 11 Ein kleines Beispiel in PHP: <?php //Anlegen der Variablen $plNickname = "Uwe"; // Uwe wird in der Variable $plNickname gespeichert. (Typ: String) $pointsUwe = 24.3; // Variable $pointsUwe bekommt den Wert 24,3 (Typ: Float) $bonuspoints = 10; // Variable $bonuspoints bekommt den Wert 10 (Typ: Integer) $final_points = 15; // Variable $final_points hat den Wert 15 (Typ: Integer) //Berechnung der neuen final_points $final_points = $pointsUwe + $bonuspoints; ?> <html> <head><title>Uebung Variablen / Datentyp</title></head> <body> <?php echo("Endstand von "); echo($plNickname); echo(": "); echo($final_points;) ?> </body> </html> Listing 2.5: PHP-Code in einer HTML-Seite Die Variable $finalpoints hatte zu Beginn des Programms den Datentyp „Integer“. Nach der Neuberechnung des Endstands wurde in der Variable $final_points der Fließkommawert „34.3“ gespeichert. Somit hat sich der Datentyp von „Integer“ zu „Float“ geändert. In Flash sieht die Sachlage ähnlich, wenn auch etwas unterschiedlich aus. Flash unter- scheidet zwischen „Grunddatentypen“ und „Referenzdatentypen“ (oder „integrierten Datentypen“). Des Weiteren existieren die speziellen Datentypen Null und undefi- ned. ActionScriptActionScript
  • 25.
    K A PI T E L 212 Grunddatentypen sind: Number: numerische Variablen (Zahlen) String: Textvariablen Boolean: Variablen, die nur die Werte true oder false speichern können Diese Datentypen werden verwendet, um mit Variablen zu arbeiten. Die Referenzda- tentypen (oder „integrierte Datentypen“) werden hingegen eingesetzt, um einerseits mit MovieClips zu arbeiten, und andererseits, um komplexere Objekte zu erstellen – auf die meisten Vertreter der Referenzdatentypen werden wir später noch zu spre- chen kommen. Referenzdatentypen sind also unter anderem: MovieClip TextField Date Der Datentyp Null deutet an, dass hier kein Wert existiert bzw. keine Daten vorhan- den sind. undefined kennzeichnet, dass einer Variable noch kein Wert zugewiesen wurde. Seit ActionScript 3.0 existieren neben Number nun auch die numerischen Datentypen int (Integer) und uint, wobei uint für „unsigned integer“ (Ganzzahl ohne Vorzei- chen) steht: int: eine Ganzzahl (= Zahl ohne Kommastelle) uint: eine Ganzzahl ohne Vorzeichen (somit können nur Zahlen größer oder gleich 0 gespeichert werden) Datentypen bei der Deklaration Um nun Variablen verschiedener Datentypen zu deklarieren, wird der Datentyp nach dem Variablennamen und einem (deklarierenden) Doppelpunkt geschrieben. Die Syntax lautet wie folgt: var Variablenname:Datentyp; Listing 2.6: Variablendeklaration mit Datentyp Wird der Datentyp angegeben (was nicht zwingend erforderlich ist – siehe hierzu auch die Info-Box „Automatische versus strikte Typisierung“), nennt man dies „Strikte Typisierung“. Angewandt auf einige Beispiele sieht das Ganze dann so aus: var myNumber:Number = 17; var myString:String = "Uwe"; u u u u u u u u ActionScript 3.0: int und uint ActionScript 3.0: int und uint
  • 26.
    G R UN D L A G E N D E R P R O G R A M M I E R U N G 13 var myBoolean:Boolean = true; trace("Der Wert der (nicht existenten) Variable myNumber2="+myNumber2); Listing 2.7: Beispiele einiger Variablendeklarationen inklusive Wertzuweisung Automatische versus strikte Typisierung (ActionScript 1.0 und 2.0) Grundsätzlich muss im Rahmen von Flash der Datentyp nicht explizit angegeben werden, denn Flash erzeugt bei der Wertzuweisung automatisch den korrekten Datentyp, wie Sie in der nach- folgenden Zeile sehen: var myNumber = 17; Nachteilig an dieser sogenannten „Automatischen Typisierung“ ist, dass der Code fehleranfälliger wird, da man in solchen Fällen einer Variable vom (angedachten) Typ Number auch beispiels- weise einen String-Wert zuweisen könnte. Im Fall der „Strikten Typisierung“ kann dies nicht geschehen und der Compiler von Flash würde beim Veröffentlichen eine entsprechende Fehlermeldung erzeugen. Deshalb der Tipp: Versuchen Sie immer, eine strikte Typisierung zu verwenden. ActionScript 3.0 erfordert in jedem Fall eine strikte Typisierung. Es ist zwar eine Typ- umwandlung möglich, standardmäßig erfordert ActionScript 3.0 jedoch eine strikte Typisierung. 2.3.4 Gültigkeitsbereiche von Variablen Der Gültigkeitsbereich einer Variablen gibt an, in welchem Bereich des Codes eine Variable gültig ist. Anders gesprochen: Der Gültigkeitsbereich soll ausdrücken, wo im Code der Wert der Variable verfügbar ist und wo nicht. Außerhalb des Gültigkeits- bereichs existiert die Variable dann ganz einfach nicht (oder nicht mehr). Insbeson- dere im Rahmen von Funktionen und speziellen Codeblöcken (PHP, JavaScript und ActionScript) müssen wir uns um Gültigkeitsbereiche Gedanken machen. Grundlegend unterscheidet man zwischen zwei Bereichen (drei hingegen für Action- Script): Lokale Variablen: Diese sind nur innerhalb eines gewissen Codeblocks gültig und verlieren mit dem Ende des Codeblocks ihre Gültigkeit. Sie werden z.B. innerhalb von Funktionen und Schleifen eingesetzt. Globale Variablen: Diese sind überall gültig und verlieren ihre Gültigkeit erst mit Ende des Scripts. In ActionScript 3.0 wurden globale Variablen entfernt. Zeitleistenvariablen (nur in ActionScript): Diese sind für alle Codeblöcke inner- halb der Zeitleiste verfügbar. Im Rahmen der bisher erlernten Programmierung müssen Sie sich noch keine Gedan- ken über lokale, globale und Zeitleistenvariablen machen. Mit Einführung von Funk- tionen wird sich dies ändern, aber darauf werden wir Sie zu gegebenem Zeitpunkt noch konkret hinweisen. u u u ActionScript 3.0ActionScript 3.0
  • 27.
    K A PI T E L 214 Flash: nicht deklarierte lokale Variablen in Codeblöcken In Flash unterscheiden wir zwischen deklarierten und nicht deklarierten Variablen innerhalb von Codeblöcken, beispielsweise Funktionen. Wird eine Variable implizit deklariert (d. h., es wird ihr ein Wert zugewiesen, ohne dass die Variable zuvor mit var deklariert wurde), verliert die Variable erst bei Ende des Scripts ihre Gültigkeit. Anders bei deklarierten Variablen: Diese verlieren mit Ende des Codeblocks ihre Gültigkeit! Superglobale Variablen und Arrays Superglobale Arrays kennt nur PHP. In Flash (bis einschließlich ActionScript 2.0) existiert ein ähnliches Array namens _global. Anhand des Namens „superglobal“ erahnen Sie wahrscheinlich schon den Sinn dieser Variablen. Superglobale Variablen sind zu jeder Zeit und an jeder Stelle in einem Script bekannt und somit les- und veränderbar. Diese werden PHP-intern in einem Array gespeichert. Was genau ein Array ist und wozu man sie verwenden kann, können Sie in diesem Kapitel in Abschnitt 2.5 nachlesen. Der Name des Arrays lautet $GLOBALS[]. Den Einsatz von $GLOBALS[] sollten wir für ein leichteres Verständnis in einem Beispiel genauer betrachten. // Definition der Variable textstring $textstring = "Info in der Variable textstring"; // Eine Funktion zum Anzeigen des Variableninhalts function showData { echo("Der Inhalt der Variable lautet: $textstring"); } showData(); Listing 2.8: Der Inhalt der Variable $textstring soll ausgegeben werden. Leider wird aber im Browser der Inhalt der Variable $textstring nicht angezeigt. Dies liegt einzig und allein daran, dass innerhalb einer Funktion Variablen nicht bekannt sind, die außerhalb dieser Funktion definiert wurden. Es existiert in der Funk- tion showData() keine Variable mit dem Namen $textstring. Um dieses Problem nun zu lösen, werden wir $GLOBALS[] einsetzen. // Definition der Variable textstring $textstring = "Info in der Variable textstring"; // Eine Funktion zum Anzeigen des Variableninhalts function showData { echo("Der Inhalt der Variable lautet: ".$GLOBALS[textstring]); } showData(); Listing 2.9: Mit dem Array $GLOBALS[] kann die Variable ausgelesen werden. PHPPHP
  • 28.
    G R UN D L A G E N D E R P R O G R A M M I E R U N G 15 Wie Sie erkennen, haben wir nicht sehr viel geändert. Innerhalb der Funktion greifen wir nun nicht mehr auf die Variable $textstring, sondern auf das Element text- string im Array $GLOBALS[] zu. Bitte beachten Sie, dass der Parameter des Arrays – also der Variablenname – ohne führendes $-Zeichen aufgerufen werden kann. PHP kennt noch weitere superglobale Arrays, die uns die Arbeit zum Beispiel mit For- mulardaten sehr erleichtern: $GLOBALS $_SERVER $_GET $_POST $_COOKIE $_FILES $_ENV $_REQUEST $_SESSION Formulardaten versenden Im ersten Kapitel dieses Buchs hörten Sie bereits von GET und POST. Wenn Sie Formu- lardaten von einer Seite zu einer anderen Seite schicken und die gesendeten Daten wei- terverarbeiten möchten, benötigen Sie die superglobalen Arrays $_GET oder $_POST, wenn in der php.ini die Einstellung register_globals auf off gesetzt ist. Angenommen, Sie haben ein Kontaktformular für Ihre User erstellt, in dem ein Text- feld mit dem Namen „Vorname“ existiert. Beim Absenden des Formulars wird der Inhalt dieses Textfelds an eine weitere PHP-Seite geschickt. Nun haben Sie zwei Mög- lichkeiten zum Auslesen des Textfelds, je nachdem, ob register_globals auf off oder on gesetzt ist. Wenn off eingestellt ist, dann können Sie nur über das superglobale Array $_POST (oder $_GET) auf den Inhalt des Textfelds „Vorname“ zugreifen. $_POST[‚Vorname']; Im zweiten Fall (register_globals ist on) können Sie mit $Vorname direkt auf den Inhalt des Textfelds zugreifen. Der Name der Variable ist automatisch der Name des Textfelds. Sollten Sie noch nähere Information über die restlichen superglobalen Arrays benö- tigen, bitten wir Sie, in der PHP-Referenz nachzuschlagen. Diese finden Sie auch im Internet unter www.php.net. u u u u u u u u u u u u register_globalsregister_globals
  • 29.
    K A PI T E L 216 Tipp: Ich würde Ihnen in jedem Fall empfehlen, die Eigenschaft register_globals auf off zu belassen (oder zu setzen), auch wenn es scheinbar einfacher wäre, wenn sie on ist. register_globals stellt eine nicht zu unterschätzende Sicherheitslücke dar, da PHP keinen Unterschied zwischen einer GET- oder POST-Variable mit gleichem Namen machen kann. Globale Variablen (und Funktionen) sind Variablen, die in allen Zeitleisten und allen Hierarchiebereichen, also Gültigkeitsbereichen, verfügbar sind. Lokale Variablen haben dagegen nur einen eingeschränkten Gültigkeitsbereich. Um eine globale Variable zu erzeugen, wird der Variable der Bezeichner _global vorangestellt. Globale Variablen werden nicht mit var deklariert und ihnen werden auch keine Datentypen zugewiesen. _global.myNumberGlobal = 17; Listing 2.10: Deklaration einer globalen Variable in ActionScript var myNumberLocal:Number = 17; Listing 2.11: Deklaration einer lokalen Variable in ActionScript Globale versus lokale Variablen Der Sinn der globalen Variable ist, dass sie von überall aus zugänglich ist. Natürlich wäre es nett, wenn jede Variable von überall aus zugänglich wäre, frei nach dem Motto „Weg frei für die Globalisierung jeder Variable“ ... Ein guter Programmierer zeichnet sich aber auch dadurch aus, dass er weiß, wann eine Variable global sein muss und wann eine Variable lokal sein kann. Zumeist werden Variablen nur für gewisse Bereiche benötigt – deshalb die Regel: lokal vor global! In ActionScript 3.0 existiert das Array _globals nicht mehr. Vielmehr behandelt ActionScript 3.0 alle Variablen als global, die in der root-Ebene eines Clips (oder einer externen ActionScript-Datei) definiert wurden. In JavaScript verhält es sich ähnlich wie in ActionScript – global sind Variablen dann, wenn sie auf äußerster Ebene erzeugt wurden. Beispiel: var global01 = 15; function showVariables() { var nichtglobal = 17; alert("INNERHALB: global01="+global01+"; nichtglobal="+nichtglobal); } showVariables(); alert("AUSSERHALB: global01="+global01+"; nichtglobal="+nichtglobal); Listing 2.12: Ein Beispiel für globale und lokale Variablen ActionScript bis inklusive 2.0 ActionScript bis inklusive 2.0 ActionScript 3.0ActionScript 3.0 JavaScriptJavaScript
  • 30.
    G R UN D L A G E N D E R P R O G R A M M I E R U N G 17 Außerhalb der Funktion showVariables wird eine Variable global01 angelegt. Da diese Variable global ist, kann sie innerhalb der Funktion showVariables abgerufen werden: Wird die Funktion showVariables aufgerufen (vorletzte Zeile), so erhalten Sie eine funktionierende alert-Ausgabe. Innerhalb der Funktion wird zusätzlich noch die lokale Variable nichtglobal definiert. Greift man nun von „außen“ auf die loka- le Variable nichtglobal zu, so erhält man einen Fehler, da diese Variable eben nur innerhalb der Funktion showVariables existiert. 2.4 Operatoren Operatoren dienen dem Zweck, Variablenwerte miteinander zu kombinieren. Dies kann einerseits eine einfache arithmetische Addition sein, andererseits aber auch dazu dienen, logische Verknüpfungen von Zuständen zu erzeugen. 2.4.1 Arithmetische Operatoren Wie der Name schon sagt, handelt es sich hierbei um eine mathematische Verknüpfung von Werten. Im folgenden Beispiel sehen Sie die Anwendung der Operation „Addi- tion“ oder „+“: $anzahl1 = 23; $anzahl2 = 15; $anzahl3; //bis jetzt wurde anzahl3 noch kein Wert zugewiesen $anzahl3 = $anzahl1 + $anzahl2; Listing 2.13: Eine Addition in PHP ... var anzahl1 = 23; var anzahl2 = 15; var anzahl3; anzahl3 = anzahl1+anzahl2; Listing 2.14: ... in JavaScript ... var anzahl1:Number = 23; var anzahl2:Number = 15; var anzahl3:Number; anzahl3 = anzahl1+anzahl2; Listing 2.15: ... und in Flash PHPPHP JavaScriptJavaScript ActionScriptActionScript
  • 31.
    K A PI T E L 218 Operatoren Numerische Werte kann man mithilfe von folgenden Operatoren miteinander ver- knüpfen: Nehmen wir für das Beispiel in der Tabelle an, die Variablen $a (bzw. a) und $b (bzw. b) erhalten die Werte $a=22 und $b=5. In $c (bzw. c) wird das Ergebnis der Berechnung gespeichert. Operator Operation Beispiel + Addition (dies gilt in JavaScript und Flash für numerische ebenso wie für String-Variablen) $c=$a+$b; (PHP) bzw.c=a+b; (JavaScript, Flash) liefert $c=27 - Subtraktion $c=$a-$b; (PHP) bzw.c=a-b; (JavaScript,Flash) liefert $c=17 * Multiplikation $c=$a*$b; (PHP) bzw.c=a*b; (JavaScript,Flash) liefert $c=110 / Division $c=$a/$b; (PHP) bzw.c=a/b; (JavaScript,Flash) liefert $c=4.4 % Modulo-Rechnung (gibt den Rest einer Division zurück) $c=$a%$b; (PHP) bzw.c=a%b; (JavaScript,Flash) liefert $c=2 Tabelle 2.1: Arithmetische Operatoren Inkrement und Dekrement Um Werte um eins zu erhöhen oder zu verringern, können Sie die Inkrement- und Dekrementoperatoren verwenden. $variable++; $variable--; Listing 2.16: In PHP ... variable++; variable--; Listing 2.17: ... und in JavaScript bzw. Flash 2.4.2 Zuweisungsoperatoren Ein Zuweisungsoperator ist Ihnen auf den vorigen Seiten bereits begegnet. Es handelt sich hierbei im einfachsten Fall um das Gleichheitszeichen „=“. Es ist dafür bestimmt, einer Variable einen Wert zuzuweisen. Neben dieser Art von Zuweisung existieren jedoch auch noch weitere Zuweisungsope- ratoren, die Sie in Tabelle 2.2 aufgelistet sehen. Der verwendete Wert kann selbstver- ständlich auch eine Variable sein – in diesem Fall passiert nichts anderes, als dass der Inhalt, sprich der Wert der Variable, ausgelesen und dieser Inhalt für die Berechnung herangezogen wird. Die Zuweisungen gelten dabei immer von rechts nach links. PHPPHP JavaScript und ActionScript JavaScript und ActionScript
  • 32.
    G R UN D L A G E N D E R P R O G R A M M I E R U N G 19 Zuweisungsoperator Operation variable = Wert Einer Variable wird ein Wert zugewiesen. variable += Wert Eine Variable wird um einen Wert erhöht variable -= Wert Eine Variable wird um einen Wert verringert. variable *= Wert Eine Variable wird mit einem Wert multipliziert. variable /= Wert Eine Variable wird durch einen Wert dividiert. variable %= Wert Einer Variable wird durch einen Wert dividiert und es wird ihr der Restwert der Division zugewiesen. Tabelle 2.2: Mögliche Arten von arithmetischen Zuweisungsoperatoren. Wie Sie bereits wissen, muss eine PHP-Variable selbstverständlich ein führendes $-Zeichen besitzen. Ein Beispiel für die Anwendung des Operators +=, der zu einer Variable den Wert einer zweiten Variable hinzuaddiert: $variable1 = 23; // variable1 bekommt den Wert 23 $variable2 = 20; // variable2 bekommt den Wert 20 $variable1 += $variable2; // variable2 wird zu variable1 addiert Listing 2.18: Der Operator += in PHP … var variable1 = 23; var variable2 = 20; variable1 += variable2; Listing 2.19: ... in JavaScript ... var variable1:Number = 23; var variable2:Number = 20; variable1 += variable2; Listing 2.20: ... und in Flash In unserem Beispiel hat die variable1 nach der Addition den Wert 43, variable2 dagegen weiterhin den Wert 20. Ein weiteres Beispiel für eine Anwendung des Modulo-Operators %, der den Restwert einer Division berechnet: $variable1 = 23; // variable1 bekommt den Wert 23 $variable2 = 20; // variable2 bekommt den Wert 20 $variable3 = variable1 % $variable2; //Ergebnis: 3 Der Modulo-Operator in PHP … var variable1 = 23; // variable1 bekommt den Wert 23 var variable2 = 20; // variable2 bekommt den Wert 20 var variable3 = variable1 % variable2; //Ergebnis: 3 Listing 2.21: ... in JavaScript ... PHPPHP JavaScriptJavaScript ActionScriptActionScript PHPPHP JavaScriptJavaScript
  • 33.
    K A PI T E L 220 var variable1:Number = 23; var variable2:Number = 20; var variable3:Number = variable1 % variable2; //Ergebnis: 3 Listing 2.22: ... und in Flash Die Modulo-Rechnung ist prinzipiell einfach zu verstehen, denn die Berechnung folgt dem gleichen Prinzip, wie Sie es aus der Volksschule kennen: Möchte man eine Zahl durch eine andere dividieren, so versucht man zunächst zu erkennen, wie oft die eine Zahl in der zweiten Zahl vorkommt, bis man letztendlich zu den Kommazahlen der Division gelangt. In unserem Beispiel ist die erste Zahl 23 und die zweite Zahl 20. Rechnet man 23 dividiert durch 20, so ist leicht zu erkennen, dass 20 in 23 genau ein Mal vorkommt und der Wert 3 als Rest übrig bleibt, also: 23/20 = 1 Rest 3 Die Modulo-Rechnung gibt Ihnen genau diese Restzahl als Ergebnis zurück, also: 23%20 = 3 Einige weitere Beispiele zur Modulo-Rechnung: 23%5 = 3 23%6 = 5 23%23 = 0 8%2 = 0 Verknüpfung von Strings Ein weiterer wichtiger Operator dient zur Verknüpfung von Strings. In PHP wird dafür der Operator .= verwendet. In unserem Beispiel aus Listing 2.23 würde die Variable text nach der Zuweisung den Text „Name = Uwe“ im Browser ausgeben. $text = "Name = "; $text .= "Uwe"; Listing 2.23: Verknüpfung von Texten in PHP In JavaScript und ActionScript erfolgt die Verknüpfung von Texten mithilfe des Addi- tions-Operators +=. Die Ausgabe würde hier „Name = Uwe“ lauten. var myText = "Name = "; myText += "Uwe"; Listing 2.24: Verknüpfung von Texten in JavaScript ... ActionScriptActionScript PHPPHP JavaScript und ActionScript JavaScript und ActionScript
  • 34.
    G R UN D L A G E N D E R P R O G R A M M I E R U N G 21 var myText:String = "Name = "; myText += "Uwe"; Listing 2.25: ... und in ActionScript 2.4.3 Bitoperatoren Bitoperatoren sind hier nur der Vollständigkeit halber erwähnt. Sie werden bei Variab- len mit Werten in Bit- oder Byteform eingesetzt. Nähere Informationen dazu entneh- men Sie bitte der jeweiligen Sprachreferenz. 2.4.4 Logische Operatoren Logische Operatoren zählen sicher zu den wichtigsten Bestandteilen einer Program- miersprache. Sie werden dafür verwendet, um Zustände (true oder false) mitein- ander zu verknüpfen. Beispielsweise könnte man bei einer elektrischen Wechselschal- tung entweder den einen oder den anderen Lichtschalter betätigen, damit das Licht aufleuchtet – in diesem Fall würde man die beiden Lichtschalter gedanklich mit einem „oder“ verknüpfen. Logische Operatoren Operation and logische UND-Verknüpfung (in Flash veraltet) && logische UND-Verknüpfung or logische ODER-Verknüpfung (in Flash veraltet) xor logische Entweder-oder-Verknüpfung (gilt nur für PHP) || logische ODER-Verknüpfung ! logisches NICHT Tabelle 2.3: Die wichtigsten logischen Operatoren Punkt vor Strich Wichtig ist immer die Rangordnung der Operatoren: Ähnlich wie in der Mathematik- stunde in der Schule gilt die Punkt-vor-Strich-Regel, wobei && der Punkt- und || der Strichrechnung zuzuweisen ist. Sollte ein Rechenvorgang allein mit Punkt- und Strich- rechnung nicht ausführbar sein, stehen Ihnen genau wie in der Algebra Klammern zur Verfügung, wobei dieselben Klammersetzungsregeln gelten. Werte prüfen Mit den logischen Operatoren ist es weiterhin möglich, in Kombination mit Bedingungen Werte auf „Richtig“ (true) oder „Falsch“ (false) zu prüfen. Beispiele finden Sie etwas später bei den Bedingungen im Abschnitt 2.6. Der Grund für jeweils zwei logische UND- und ODER-Verknüpfungen in PHP liegt einzig in der Rangordnung der Operatoren: && ist „stärker“ als and und wird deshalb zuerst ausgeführt; Gleiches gilt für || vor or.
  • 35.
    K A PI T E L 222 Die Wirkungsweise der einzelnen Operationen sehen Sie in der nachfolgenden Tabelle. Variable 1 Variable 2 AND- (&&-) Verknüpfung OR- (||-) Verknüpfung XOR-Verknüpfung (nur PHP) false false false false false false true false true true true false false true true true true true true false Tabelle 2.4: Verschiedene Verknüpfungsoperatoren angewandt auf zwei Variablen 2.4.5 Vergleichsoperatoren Um Werte miteinander zu vergleichen, benötigen wir Vergleichsoperatoren. Folgende Möglichkeiten stehen uns dabei zur Verfügung: Vergleichsoperatoren Operation == Gleichheit der Werte != Ungleichheit der Werte === Gleichheit der Werte und des Datentyps („Strikte Gleichheit“) !== Ungleichheit der Werte oder des Datentyps („Strikte Ungleichheit“) > größer als < kleiner als >= größer als oder gleich <= kleiner als oder gleich Tabelle 2.5: Vergleichsoperatoren Das Resultat eines Vergleiches ist immer ein boolescher Wert, denn einem Vergleich geht stets eine „Frage“ voran, wobei die Antwort auf diese Frage immer entweder „ja“ (true) oder „nein“ (false) lautet. Der Vergleich selbst ist nichts anderes als beispiels- weise die Frage, ob ein Wert kleiner gleich einem anderen Wert ist. 2.4.6 Rangordnung der Operatoren Nachfolgend finden Sie die Rangordnung der Operatoren, wobei diejenigen, die in derselben Zeile aufgeführt sind, gleichberechtigt sind. Am stärksten sind demnach die Operatoren !, ~, ++ und --, am schwächsten das or (die bitweisen Operatoren haben wir in diese Liste ebenso mit aufgenommen): 1. ! , ~, ++, -- 2. *, /, % 3. +, -, . 4. <<, >> 5. <, <=, >, >=
  • 36.
    G R UN D L A G E N D E R P R O G R A M M I E R U N G 23 6. ==, != , ===, !== 7. & 8. | 9. && 10. || 11. ?, : 12. =, +=, -=, *=, /=, .= , %=, &=, |=, <<=, >>= 13. and 14. or In folgendem Beispiel wird mit diesen Rangordnungen gearbeitet. var a:Number = 17, b:Number = -3, c:Number = 11; var d:Number = 200, ergB:Boolean, ergN:Number; var bool1:Boolean = true, bool2:Boolean = false; ergN = ++a*17-d; //(1+17)*17-200=106; a hat sich von 17 auf 18 erhöht ergB = ergN==89 //false ergN = (a*d+b)%5-c*d; // (18*200-3)%5-11*200 = 3597%5-2200 = 2-2200 = -2198 ergB = ergN !=-250 && bool2; /* Erklärung: Zunächst wird überprüft, ob der Inhalt von ergN ungleich (!=) -250 ist. Nachdem dies der Fall ist, ergibt der Vergleich den Wert true. Dieser wird danach mit dem Inhalt von bool2 mit UND verknüpft. Da bool2 den Wert false aufweist, ist das Ergebnis der UND-Verknüpfung ebenfalls false. Somit wird der Variable ergB der Wert false zugewiesen. Beachten Sie bitte, dass sich a durch die Operation ++a von 17 auf 18 erhöht hat! -2198!=250 && false = true && false = false */ Listing 2.26: Einige Beispiele zur Reihenfolge von Operationen
  • 37.
    K A PI T E L 224 2.5 Arrays Arrays sind für die Arbeit eines jeden Programmierers von großer Bedeutung. Sie können sich einen Array als einen Datenpool oder – einfacher – als Tabelle vorstellen. Jeder dieser Werte des Datenpools ist in einem eigenen Bereich gespeichert. Arrays könnte man auch mit einem Setzkasten vergleichen, in dem jede Figur einen eigenen Platz hat. Am Anfang dieses Kapitels haben wir für ein Online-Spiel den Nicknamen des Users benötigt. Wenn wir nun dieses Beispiel erweitern und pro User zusätzliche Daten wie Vorname, Nachname, Adresse und Wohnort speichern möchten, benötigten wir sehr viele Variablen, vor allem wenn mehrere User an unserem Online-Spiel teilnehmen. Dieses Problem können wir mit Arrays in den Griff bekommen. Zunächst einmal die Syntax zur Array-Erstellung: $myArray = array(); Listing 2.27: In PHP ... var myArray = new Array(); Listing 2.28: ... in JavaScript ... var myArray:Array = new Array(); Listing 2.29: ... und in Flash Arrays in Flash und JavaScript In JavaScript und Flash spricht man im Fall von Arrays von „Objekten“ (man spricht auch von der „Klasse der Arrays“), in PHP gehören sie zu den „komplexen Datentypen“. Bei der Verwendung in JavaScript und Flash ist daher darauf zu achten, dass beim Erzeugen der Konstruktor new Array() verwendet wird. Es gibt unterschiedliche Arten, Werte in den Arrays zu speichern: Unterschieden wird dabei zwischen indizierten und assoziativen Arrays. 2.5.1 Indizierte Arrays Die Werte eines Arrays werden immer durch eine fortlaufende Nummer gekennzeich- net. Indizierte Arrays beginnen immer bei 0, deshalb spricht man gern von „zero- based“ Elementen. Das zweite Element des Arrays bekommt die Nummer 1, das dritte die Nummer 2 zugewiesen usw. Das letzte Element eines Arrays mit fünf Elementen hat also die Nummer 4. $arrUser = array("Uwe", "Uwe", "Mutz"); Listing 2.30: In PHP ... Arrays erstellenArrays erstellen Werte in Arrays speichern Werte in Arrays speichern
  • 38.
    G R UN D L A G E N D E R P R O G R A M M I E R U N G 25 var arrUser = new Array("Uwe", "Uwe", "Mutz"); Listing 2.31: ... in JavaScript ... var arrUser:Array = new Array("Uwe", "Uwe", "Mutz"); Listing 2.32: ... und in Flash Möchten wir nun den Usernamen des Users aus dem Array $arrUser/arrUser aus- geben, müssten wir folgenden Code schreiben. echo($arrUser[0]); //Ausgabe in den Browser Listing 2.33: In PHP ... alert(arrUser[0]); //Ausgabe in einer Alert-Box Listing 2.34: ... in JavaScript ... trace(arrUser[0]); //Ausgabe in das Ausgabefenster Listing 2.35: ... und in Flash Elementname Nummer (Index) des Elements Wert $arrUser[0] 0 Uwe $arrUser[1] 1 Uwe $arrUser[2] 2 Mutz Tabelle 2.6: Inhalte des indizierten Arrays $arrUser (gleichermaßen gültig für arrUser in JavaScript und Flash) 2.5.2 Assoziative Arrays Bei einem assoziativen Array („Hash-Table“) werden die Werte nicht durch fortlau- fende Nummern gekennzeichnet, sondern durch eine eindeutige Bezeichnung wie bei Variablen. Arrays erstellen Das Erzeugen „echter“ assoziativer Arrays ist nur in PHP möglich – in JavaScript und ActionScript läuft die Sache etwas anders, denn hier müsste man Objekte in Arrays verschachteln – sollten Sie „um die Burg“ assoziative Arrays in Flash oder JavaScript benötigen, so empfehle ich Ihnen die ActionScript- bzw. JavaScript-Referenz. Werfen wir zunächst einen Blick auf PHP. Um diesen Array-Typ zu erstellen, benötigen wir den Operator =>. $arrUser = array( "Nickname" => "Uwe", "Vorname" => "Uwe", PHPPHP
  • 39.
    K A PI T E L 226 "Nachname" => "Mutz" ); Jetzt hat jeder Wert des Arrays eine eindeutige Bezeichnung erhalten. Man spricht hier auch vom „Key“ und dessen „Value“. Elementname Key Value $arrUser["Nickname"] Nickname Uwe $arrUser["Vorname"] Vorname Uwe $arrUser["Nachname"] Nachname Mutz Tabelle 2.7: Inhalte des assoziativen Arrays $arrUser Mehrdimensionale Arrays Im Moment haben wir nur eindimensionale Arrays erzeugt, die man mit einzeiligen Tabellen vergleichen kann, bei denen alle Werte hintereinander in den Zellen der Tabelle gespeichert werden. Möglich ist aber auch der Einsatz von mehrdimensionalen Arrays. Angenommen, wir möchten alle User unseres Online-Spiels mit deren Nicknamen, Vornamen und Nachnamen speichern, so wäre der Einsatz eines mehrdimensionalen Arrays denkbar und sinnvoll: $arrUser = array("User1" => array("Uwe", "Uwe", "Mutz"), "User2" => array("Uwe", "Uwe", "Mutz")); Das Array $arrUser hat zwei Elemente User1 und User2. Diese Elemente sind wie- derum selbst Arrays, in denen dann die eigentlichen Werte gespeichert werden. Möch- ten wir nun den Nachnamen des Users 2 ausgeben, schreiben wir folgenden Code: echo($arrUser["User2"][2]); Bei der Ausgabe müssen wir nur Schritt für Schritt vom äußersten Array in das gewünschte Array wandern. Unser Array $arrUser beinhaltet ein assoziatives Array namens User2 und dieses beinhaltet wiederum ein „normales“ Array. Mit [2] geben wir somit nur die Stelle im Array User2 an, an der der Nachname gespeichert wurde. Natürlich könnten wir das zweite Array auch assoziativ aufbauen: $arrUser = array("User1" => array("Nickname" => "Uwe", "Vorname" => "Uwe", "Nachname" => "Mutz"), "User2" => array("Nickname" => "Uwe", "Vorname" => "Uwe", "Nachname" => "Mutz")); Um wieder den Nachnamen des zweiten Users auszugeben, schreiben wir nun: echo($arrUser["User2"]["Nachname"]); Äquivalent können wir dieses Beispiel in JavaScript und ActionScript nicht umsetzen, da es wie erwähnt in JavaScript und ActionScript keine assoziativen Arrays gibt. Der Ausweg hier führt über Objekte, die innerhalb von Arrays angelegt werden. JavaScript und ActionScript JavaScript und ActionScript
  • 40.
    G R UN D L A G E N D E R P R O G R A M M I E R U N G 27 Mehrdimensionale Arrays (jedoch nicht assoziativ) anzulegen, ist jedoch auch in JavaScript und ActionScript kein Problem: var arrUser = new Array("User1", "User2"); //macht keinen Sinn! arrUser[0] = new Array("Uwe", "Uwe", "Mutz"); arrUser[1] = new Array("Alex", "Alexander", "Grasser"); alert("Bezeichnung des ersten Eintrags der User-Tabelle: "+arrUser[0]); alert("Nachname des zweiten Users: "+arrUser[1][2]); Listing 2.36: Ein mehrdimensionales Array, wobei die erste Zeile in dieser Form wenig Sinn macht Mehrdimensionale Arrays werden nach dem Muster: var myArray = new Array(); myArray[n] = new Array(); angelegt, wobei n eine beliebige Stelle im Array ist. Sollte an Stelle n des Arrays myAr- ray bereits ein Inhalt vorhanden sein, so wird dieser überschrieben. Aus diesem Grund ergibt die erste Zeile in Listing 2.36 keinen Sinn, da die Einträge „User1“ und „User2“ in den nächsten Zeilen gleich wieder überschrieben werden. Sinnvoll ist daher anstatt dieser Zeile die folgende: var arrUser = new Array(); Selbiges gilt in Flash, wobei in diesem Fall noch die Typisierung hinzukommt: var arrUser:Array = new Array(); arrUser[0] = new Array("Uwe", "Uwe", "Mutz"); arrUser[1] = new Array("Alex", "Alexander", "Grasser"); trace("Bezeichnung des ersten Eintrags der User-Tabelle: "+arrUser[0]); trace("Nachname des zweiten Users: "+arrUser[1][2]); Listing 2.37: Mehrdimensionale Arrays in Flash nach demselben Muster wie in JavaScript, nur mit zusätzli- cher strikter Typisierung Vielleicht haben Sie sich schon die Frage gestellt, ob es nicht eigentlich var myArray = new Array(); var myArray[0] = new Array(); heißen müsste – also mit einem zusätzlichen var in der zweiten Zeile. Nun, diese Art der Schreibweise ist aufgrund des inneren Aufbaus der Arrays als Objekte nicht zuläs- sig – Details dazu finden Sie in der Objektorientierten Programmierung (OOP). JavaScriptJavaScript
  • 41.
    K A PI T E L 228 2.6 Bedingungen In der Programmierung gibt es oft Situationen, in denen ein Programmblock nur unter einer gewissen Bedingung ausgeführt werden soll. Diese Bedingung muss geprüft und daraufhin eine Entscheidung getroffen werden, wie das Script weiterverarbeitet wer- den soll. Fällt die Entscheidung positiv aus, wird der Programmblock ausgeführt, ist sie negativ, kann an dieser Stelle beispielsweise abgebrochen werden. 2.6.1 if-Bedingung Die gültige Syntax ist: if(Bedingung) { Programmblock, falls die Bedingung zutrifft } else { Programmblock, falls die Bedingung nicht zutrifft } Listing 2.38: Syntax für if-Bedingungen Was genau ist nun eine Bedingung und was liefert sie für Resultate? Nun, eine Bedin- gung ist in den meisten Fällen ein Vergleich zweier (oder mehrerer) Werte. Man kann Vergleiche in Bezug auf „gleich (==)“, „kleiner (<)“, „größer (>)“ usw. anstellen – das haben Sie im letzten Abschnitt bereits erfahren. Das Resultat ist dann immer eine Antwort des Systems, das sagt: „Wert 1 ist gleich Wert 2“ oder „Wert 1 ist nicht gleich Wert 2“, wenn man mit == auf Gleichheit prüft. Der Programmcode für dieses Beispiel würde folgendermaßen aussehen: if (Wert1 == Wert2) { //Wert1 ist gleich Wert2 } else { //Wert1 ist nicht gleich Wert2 }
  • 42.
    G R UN D L A G E N D E R P R O G R A M M I E R U N G 29 Ein einfaches Beispiel vergleicht die Variablen a und b miteinander und ermittelt, wel- che der beiden Variablen den größeren Wert beinhaltet: $a = 23; //einen fiktiven Wert eingeben, wie z.B. 23 $b = 17; if ($a > $b) { echo("$a ist groesser als $b"); } else { echo("$b ist groesser oder gleich $a"); } Listing 2.39: In PHP ... var a = 23; var b = 17; if(a>b) { alert("a ist groesser als b"); } else { alert("b ist groesser oder gleich a"); } Listing 2.40: ... in JavaScript ... ABBILDUNG 2.1 Schematische Darstellung einer if-Bedingung
  • 43.
    K A PI T E L 230 var a:Number = 23; var b:Number = 17; if(a>b) { trace("a ist groesser als b"); } else { trace("b ist groesser oder gleich a"); } Listing 2.41: ... und in ActionScript Geschweifte Klammern bei Programmblöcken Vielleicht ist Ihnen in der Syntax des obigen Beispiels aufgefallen, dass nach der Über- prüfung der Bedingung (die übrigens immer in runden Klammern stehen muss) eine geschweifte Klammer „{„ geöffnet wird. Dies deutet an, dass die nachfolgenden Code- zeilen zum if-Befehl gehören. Gleiches gilt für den else-Teil. 2.6.2 switch-Bedingung Das Problem der if-Bedingung ist, dass diese Bedingung immer nur auf einen Wert überprüft, also eine Fallunterscheidung nur durch Verschachtelung möglich ist. Muss auf sehr viele verschiedene Werte überprüft werden, so wird eine solche Fallunterschei- dung mit verschachtelten if-Bedingungen sehr schnell sehr unübersichtlich. Abhilfe schafft hier die switch-Bedingung, die eine Variable auf beliebig viele verschiedene Werte überprüft und je nachdem verschiedene Programmblöcke ausführt. Werfen wir einen Blick auf die Syntax: switch (Variable) { case Wert 1: //Programmblock 1 break; case Wert 2: //Programmblock 2 break; ... case Wert n: //Programmblock n break; default: Zeichenketten vergleichen Wenn Sie Zeichenketten vergleichen, benutzen Sie === oder !==, da hier auch der Datentyp verglichen wird. Einzeiliger Programmcode Sollte der Programmblock aus nur einer einzigen Zeile bestehen, könnte man die geschweiften Klammern weglassen. In Hinblick auf andere Programmiersprachen sollte man sie aber auch bei nur einer Zeile setzen.
  • 44.
    G R UN D L A G E N D E R P R O G R A M M I E R U N G 31 //Programmblock, falls keiner der Werte auf die Variable zutrifft } Listing 2.42: Syntax für switch-Bedingungen Die Variable wird Schritt für Schritt auf die Werte überprüft. Trifft einer der innerhalb des switch-Blocks aufgelisteten Werte auf die Variable zu, so wird der zugehörige Programmblock ausgeführt; trifft keiner der Werte auf die Variable zu, so wird der Programmblock im default-Teil ausgeführt. Dieser default-Teil kann aber auch gänzlich wegfallen – sollte also kein Wert auf den Inhalt der Variable zutreffen, würde einfach gar nichts geschehen. Die break-Anweisung sorgt dafür, dass der nachfolgende Code innerhalb der switch-Anweisung nicht mehr ausgeführt wird – hierdurch wird das Abarbeiten des Codes schneller. 2.7 Schleifen Ein weiterer wichtiger Bestandteil in der Programmierung sind Schleifen. Sie kommen immer dann zum Einsatz, wenn ein Block von Befehlen mehrmals hintereinander ablaufen soll. Grundsätzlich unterscheidet man zwischen Schleifen mit einer festen Anzahl von Durchläufen und solchen mit einer variablen Anzahl von Durchläufen. 2.7.1 for-Schleife Beginnen wir bei einer Schleife mit einer festen Anzahl von Durchläufen, der for- Schleife. Die for-Schleife benötigt drei Werte, die gesetzt werden müssen: Startwert einer sogenannten Zähl- oder Schleifenvariable Abbruch- oder Ende-Bedingung Zählvariablen-Inkrement Zählvariable Die Zählvariable ist die Variable, die die Anzahl der Schleifendurchläufe zählt. In der obigen Auflistung steht „Startwert einer Zählvariablen“. Dies bedeutet, dass dieser Variablen ein Anfangswert zugewiesen wird. Oftmals wird als Startwert der Wert „0“ verwendet; es muss aber nicht so sein. Sie sollten sich dies aber nicht so vorstellen, dass pro Schleifendurchlauf die Variable um eins erhöht wird (was als Spezialfall natürlich möglich ist und oft verwendet wird), sondern die Zählvariable wird um den Wert des Zählvariablen-Inkrements verändert. Wir schreiben an dieser Stelle bewusst „verändert“ und nicht „erhöht“, weil die Vari- u u u
  • 45.
    K A PI T E L 232 able genauso um einen gewissen Wert verringert werden könnte, je nachdem, was im Zählvariablen-Inkrement angegeben ist. Abbruchbedingung Die Abbruchbedingung überprüft die Zählvariable pro Schleifendurchlauf auf einen gewissen Wert. Sollte dieser Wert (je nach Art der Bedingung) über- oder unterschrit- ten werden, wird die Schleife abgebrochen, sprich, sie wird nicht mehr ausgeführt. Endlosschleife Wichtig hierbei ist, dass die Abbruchbedingung auch wirklich irgendwann erreicht werden kann, ansonsten haben Sie eine sogenannte Endlosschleife programmiert. Dies führt zu einer Überlastung des Prozessors und wird im Allgemeinen vom Betriebssys- tem nach einer gewissen Zeit automatisch abgebrochen, was logischerweise zur Folge ABBILDUNG 2.2 Schematische Darstellung einer for-Schleife
  • 46.
    G R UN D L A G E N D E R P R O G R A M M I E R U N G 33 hat, dass die PHP- oder Flash-Datei bzw. JavaScript-Anwendung nicht mehr weiter ausgeführt wird. Warum all der Aufwand mit der Zählvariable? Wenn sie nur dafür da ist, dass man die Anzahl der Durchläufe auf alle möglichen Arten abprüft, hätte sich der Aufwand nicht gelohnt. Der Grund dafür ist, dass die Variable selbst im Programmblock der Schleife sehr oft als ganz normale Variable verwendet wird. Die korrekte Syntax der for-Schleife lautet: for(Initialisierung der Zählvariablen; Abbruchbedingung; Inkrement) { Programmblock } Listing 2.43: Syntax für for-Schleifen Initialisierung der Schleife Die Initialisierung kann z.B. wie folgt aussehen: for($i = 0; …) //Zählvariable $i mit Startwert 0 for($a = 23; …) //Zählvariable $a mit Startwert 23 for($i = -17; …) //Zählvariable $i mit Startwert -17 Listing 2.44: In PHP ... for(var i:Number = 0; ...) //Zählvariable i mit Startwert 0 for(var a:Number = 23; ...) //Zählvariable a mit Startwert 23 for(var i:Number = -17; ...) //Zählvariable i mit Startwert -17 Listing 2.45: ... in JavaScript ... for(var i = 0; ...) //Zählvariable i mit Startwert 0 for(var a = 23; ...) //Zählvariable a mit Startwert 23 for(var i = -17; ...) //Zählvariable i mit Startwert -17 Listing 2.46: ... und in Flash Typischerweise werden als Variablennamen für Zählvariablen die Buchstaben i, j, k usw. verwendet, einen besonderen Grund gibt es dafür wohl nicht. Typische Abbruchbedingungen Typische Abbruchbedingungen sind: for($i = 0; $i<15; ...) for($a = 23; $a>15; ...)
  • 47.
    K A PI T E L 234 /* falls $a pro Schleifendurchlauf erhöht wird, ist die obige Schleife eine Endlosschleife; falls $a verringert wird, wird die Abbruchbedingung erreicht */ for(var $i = -17; $i<0; ...) Listing 2.47: In PHP ... for(var i = 0; i<15; ...) for(var a = 23;a>15; ...) for(var i = -17; i<0; ...) Listing 2.48: ... in JavaScript ... for(var i:Number = 0; i<15; ...) for(var a:Number = 23;a>15; ...) for(var i:Number = -17; i<0; ...) Listing 2.49: ... und in Flash Inkrement Nun müssen wir uns noch um das Zählvariablen-Inkrement kümmern. Wir können die Zählvariable pro Durchlauf entweder verringern oder erhöhen, die Frage ist nur, um welchen Wert wir verringern oder erhöhen. Oft wird die Variable pro Schleifen- durchlauf um eins erhöht, das muss aber eben nicht so sein. Möchte man um eins erhöhen, würde man schreiben: $i = $i+1; //erhöht die Variable i um eins Dies bedeutet, dass der neue Wert der Variablen i 1 aus dem alten Wert 2 plus eins 3 errechnet wird. Diese Schreibweise ist speziell in diesem Fall nicht besonders üblich, vielmehr schreibt man: $i++; //erhöht die Variable i um eins Listing 2.50: in PHP ... i++; //erhöht die Variable i um eins Listing 2.51: ... und in JavaScript bzw. Flash Eine weitere allgemeinere Schreibweise ist: $i += 1; //erhöht die Variable i um eins $i += 3; //erhöht die Variable i um drei $i -= 1; //verringert die Variable i um eins Listing 2.52: In PHP ...
  • 48.
    G R UN D L A G E N D E R P R O G R A M M I E R U N G 35 i += 1; //erhöht die Variable i um eins i += 3; //erhöht die Variable i um drei i -= 1; //verringert die Variable i um eins Listing 2.53: ... und in JavaScript bzw. Flash Beispiele von for-Schleifen Damit sind wir in der Lage, komplette Schleifen zu programmieren. Sehen wir uns nun einige Beispiele von for-Schleifen an: for($i=0; $i<10; $i++) { echo("i = $i"); /* Diese Schleife beginnt mit $i = 0; $i wird pro Schleifendurchlauf um eins erhöht und es wird pro Durchlauf abgeprüft, ob $i immer noch kleiner als 10 ist; ist das irgendwann nicht mehr der Fall, wird die Schleife abgebrochen. Insgesamt sind es 10 Schleifendurchläufe */ } for($i = -17; $i<30; $i+= 3) { echo("i = $i"); //16 Durchläufe } Listing 2.54: In PHP ... for(var i =0; i<10; i++) { alert("i = "+i); } for(var i = -17; i<30; i+= 3) { alert("i= "+i); //16 Durchläufe } Listing 2.55: ... in JavaScript ... for(var i:Number=0; i<10; i++) { trace("i = "+i); } for(var i:Number = -17; i<30; i+= 3) { trace("i= "+i); //16 Durchläufe } Listing 2.56: ... und in Flash
  • 49.
    K A PI T E L 236 Jetzt ein praktisches Beispiel. Sie erinnern sich sicher noch an unser Array mit den Userdaten. Mit echo($arrUser[0]) haben wir den Nicknamen ausgegeben. Nun möchten wir alle Daten des Users ausgeben. // Erstellen des Arrays $arrUser = array("Uwe", "Uwe", "Mutz"); //Ausgabe des Arrays mit einer for-Schleife for($i=0; $i<3; $i++){ echo($arrUser[$i]."<br />"); } Mit diesen paar Zeilen werden alle Daten des Arrays durch Zeilenumbrüche getrennt ausgegeben: Die verwendete for-Schleife wird dreimal durchlaufen, weil wir als Start- wert 0 und als maximalen Wert 2 (< 3) definiert haben. Somit hat $i beim ersten Durchlauf der Schleife den Wert 0 und holt den Wert an der Stelle 0 aus unserem Array $arrUser[]. Beim nächsten Durchlauf hat $i den Wert 1 und wir lesen den Wert an der Stelle 1 aus unserem Array aus usw. Anzahl der Elemente eines Arrays Wir haben nur ein Problem, denn die for-Schleife läuft im Moment nur von Index 0 bis Index 2. Sobald mehr Daten in das Array gespeichert werden, würde ein Wert mit zum Beispiel Index 3 oder Index 4 nicht ausgegeben werden. Zu lösen ist das Problem über eine PHP-Funktion, die die Anzahl der Werte eines Arrays zurückgibt. Hier können wir zwischen der Funktion count() und sizeOf() wählen. Welche Funktion Sie nutzen, ist egal. Beide geben die Anzahl der Elemente eines Arrays zurück. for($i=0; $i<sizeof($arrUser); $i++){ echo($arrUser[$i]."<br />"); } In ActionScript sähe der Code wie folgt aus, die Erklärung kann im Wesentlichen von oben übernommen werden: var arrUser:Array = new Array("Uwe","Uwe","Mutz"); for(var i:Number=0; i<arrUser.length; i++) { trace("arrUser["+i+"] = "+arrUser[i]); } Entgegen der Beschreibung von oben wird in Flash zur Ermittlung der Anzahl der Einträge in einem Array die Eigenschaft length des Arrays verwendet. PHPPHP ActionScriptActionScript
  • 50.
    G R UN D L A G E N D E R P R O G R A M M I E R U N G 37 var arrUser = new Array("Uwe","Uwe","Mutz"); for(var i =0; i<arrUser.length; i++) { alert("arrUser["+i+"] = "+arrUser[i]); } JavaScript ist – wie Sie ja wissen – sehr ähnlich wie ActionScript aufgebaut (nachdem beide demselben Standard angehören, ist das auch nicht wirklich schwer ...) – einzig die strikte Typisierung fehlt uns in JavaScript. 2.7.2 for...each- oder for...in-Schleife Die for...each-Schleife steht uns in PHP speziell für Arrays zur Verfügung, in JavaScript und Flash verwendet man sie auch gern zum Auslesen aller Eigenschaften und Methoden eines Objekts. Dort ist sie als for...in-Schleife bekannt. Diese Schleife löst unser Problem der for-Schleife, dass die Anzahl der Einträge des Arrays nicht bekannt ist, denn mit einer for...each-Schleife werden alle Felder des Arrays durchlaufen. Hier zunächst die Syntax der for...each-Schleife: foreach($array as element) { Programmblock; } Listing 2.57: In PHP ... for(element in myArray) { Programmblock; } Listing 2.58: ... und in JavaScript bzw. Flash Unser voriges Beispiel mit einer for...each-Schleife würde demnach wie folgt aus- sehen: // Erstellen des Arrays $arrUser = array("Uwe", "Uwe", "Mutz"); //Ausgabe des Arrays mit einer for...each-Schleife foreach($arrUser as $userdaten){ echo($userdaten."<br />"); } Listing 2.59: In PHP ... JavaScriptJavaScript
  • 51.
    K A PI T E L 238 var arrUser:Array = new Array("Uwe","Uwe","Mutz"); for(element in arrUser) { trace("arrUser["+element+"] = "+arrUser[element]); } Listing 2.60: ... in JavaScript ... var arrUser = new Array("Uwe","Uwe","Mutz"); for(element in arrUser) { alert("arrUser["+element+"] = "+arrUser[element]); } Listing 2.61: ... und in Flash Für die Verarbeitung eines assoziativen Arrays müssen wir die for...each-Schleife noch etwas erweitern. Die Syntax für das Durchlaufen eines assoziativen Arrays lau- tet: foreach($array as key => value){ Programmblock; } Listing 2.62: Syntax für eine for...each-Schleife in einem assoziativen Array Wie schon bei der Erstellung eines assoziativen Arrays benötigen wir den Operator =>. // Erstellen des Arrays $arrUser = array( "Nickname" => "Uwe", "Vorname" => "Uwe", "Nachname" => "Mutz" ); // Ausgabe des assoziativen Arrays mit einer for...each-Schleife foreach($arrUser as $key => $value){ echo("$key: <b>$value</b><br />"); } Wissenswertes zur for...in-Schleife in Flash Mithilfe der for...in-Schleife in Flash können zwar beinahe, jedoch nicht alle Eigenschaften und Methoden von Objekten ermittelt werden. Hierzu verweise ich auf die ActionScript- Referenz, die Sie auf der Site von Macromedia (www.macromedia.com) im Menüpunkt SUPPORT > DOKUMENTATION finden. Des Weiteren listet die for...in-Schleife die eingetragenen Elemente nicht in der Reihenfolge des Vorkommens auf. Dies wird speziell im Fall des Auslesens von Array-Elementen interessant. PHPPHP
  • 52.
    G R UN D L A G E N D E R P R O G R A M M I E R U N G 39 Seit ActionScript 3.0 existiert in Flash nun auch eine for each..in-Schleife, die primär zum Durchlaufen von Objekten eines bestimmten Typs verwendet wird. Sol- che Objekte sind beispielsweise XML- oder XMLList-Objekte. Im Gegensatz zu einer for...in-Schleife wird über den Iterator der Schleife der Wert und nicht der Name der jeweiligen Eigenschaft ermittelt. Als Beispiel arbeiten wir uns durch ein XML-Objekt, um alle Werte auszugeben: var myXML:XML = <Playliste> <song src="BeAWarrior.mp3">Be a Warrior</song> <song src="WarriorsOfTheWasteland.mp3">Warriors of the Wasteland</ song> </Playliste>; for each (var item in myXML.song) { trace("item="+item); } Als Ausgabe erhalten wir „Be A Warrior“ und „Warriors of the Wasteland“. 2.7.3 do..while-Schleife Diese und die nächste Schleife sind Vertreter von Schleifen mit einer variablen Anzahl von Durchläufen. Damit kommen wir mehr denn je in die Situation, dass wir selbst überprüfen müssen, dass die Schleife auch wirklich jemals abbricht. Sorgen wir pro- grammiertechnisch nicht für die Möglichkeit des Schleifenendes, erzeugen wir die schon bei der for-Schleife angesprochene Endlosschleife. Mindestens einmal durchlaufen Bei der do..while-Schleife wird der Programmblock, der sich in ihr befindet, auf jeden Fall einmal durchlaufen. Die Bedingung, ob die Schleife ein weiteres Mal durch- laufen wird, hängt von der Abbruchbedingung ab, die aber erst am Ende der Schleife überprüft wird. Boolesche Werte Genauso wie bei der for-Schleife (und jeder anderen Situation, in der Bedingungen gefordert sind) liefert die Bedingung einen booleschen Wert. Oft wird anstatt der Bedingung selbst einfach eine boolesche Variable verwendet, deren Wert dann für einen weiteren Schleifendurchlauf oder einen Schleifenabbruch entsprechend gesetzt wird. Der Variable wird dann z.B. innerhalb der Schleife ein Wert zugewiesen, damit die Schleife abbrechen kann. Werfen wir einen Blick auf die Syntax: for each..in in ActionScript 3.0 for each..in in ActionScript 3.0
  • 53.
    K A PI T E L 240 do{ //Programmblock } while(Bedingung); Listing 2.63: Syntax für do..while-Schleifen Die do..while- und die while-Schleife werden dann verwendet, wenn man nicht sicher ist, wie oft die Schleife durchlaufen werden soll. 2.7.4 while-Schleife Entgegen der oben beschriebenen do..while-Schleife läuft die while-Schleife nicht notwendigerweise durch. Trifft die Bedingung schon von Beginn an nicht zu, führt kein Weg in das Innere der Schleife. Die korrekte Syntax ist: while(Bedingung) { //Programmblock } Listing 2.64: Syntax für while-Schleifen ABBILDUNG 2.3 Schematische Darstellung einer do..while-Schleife
  • 54.
    G R UN D L A G E N D E R P R O G R A M M I E R U N G 41 Die Anmerkungen zur Abbruchbedingung bei der do..while-Schleife gelten hier natürlich entsprechend. Hilfreiches bei Schleifen: break und continue Zwei Befehle sind im Zusammenhang mit Schleifen oft hilfreich: break: veranlasst den Interpreter, zum Beispiel den Flash-Player, die Schleife zu verlassen, ohne dass die Bedingung noch weiter geprüft wird. continue: veranlasst den Interpreter, zur Bedingungsprüfung zu springen, ohne dass die restli- chen Zeilen des Programmblocks weiter ausgeführt werden. 2.8 Funktionen Bisher haben wir die notwendigen Grundlagen der Programmierung betrachtet. Sie sind bereits jetzt in der Lage, einfachere Programme zu schreiben. Auf den nächs- ten Seiten lernen Sie die Möglichkeit kennen, Programmteile erst bei Bedarf auszu- führen. u u ABBILDUNG 2.1 Schematische Abbildung einer while-Schleife
  • 55.
    K A PI T E L 242 Funktionen bieten uns bei der Programmierung zwei entscheidende Vorteile: Funktionen können bei Bedarf – also erst dann, wenn man diesen Programmblock wirklich braucht – aufgerufen werden. Funktionen lassen sich beliebig oft aufrufen. Funktionen können Ergebnisse an das Hauptprogramm zurückgeben. Stellen Sie sich zum Beispiel ein Computerspiel vor: Jedes Mal, wenn der Spieler mit seinem Raumschiff abgeschossen wird, soll die Anzahl seiner „Leben“ um eins redu- ziert werden. Das wäre ein Beispiel dafür, dass ein Programmblock nur bei Bedarf und so oft man will abgerufen werden kann. Funktionsdeklaration Sehen wir uns die korrekte Syntax der Funktionsdeklaration für verschiedene Anwen- dungsmöglichkeiten einmal an. Funktionen werden dabei immer durch das Schlüssel- wort function eingeleitet. 1. Funktion, an die weder Daten übergeben noch von der Daten zurückgegeben werden: function Funktionsname() { Programmblock } 2. Funktion, an die Daten übergeben, von der jedoch keine Daten zurückgegeben werden: function Funktionsname(Variablensatz) { Programmblock } 3. Funktion, an die keine Daten übergeben, von der jedoch Daten zurückgegeben werden: function Funktionsname() { Programmblock return Variable / Wert; } 4. Funktion, an die sowohl Daten übergeben als auch Daten von ihr zurückgegeben werden: function Funktionsname(Variablensatz) { Programmblock u u u
  • 56.
    G R UN D L A G E N D E R P R O G R A M M I E R U N G 43 return Variable / Wert; } Übergabe von Daten und Rückgabe In dieser Syntax sehen Sie Dinge, von denen bis jetzt noch gar nicht die Rede war. Dar- auf müssen wir genauer eingehen. Machen wir dies aber lieber anhand eines Beispiels: Wir programmieren eine Funktion, welche zwei Zahlen zusammenzählt (diese beiden Zahlen werden an die Funktion übergeben) und das Ergebnis an das Hauptprogramm zurückliefert. function Addiere($zahl1,$zahl2) { $ergebnis = $zahl1 + $zahl2; return $ergebnis; } Listing 2.65: In PHP ... function Addiere(zahl1,zahl2) { var ergebnis = zahl1 + zahl2; return ergebnis; } Listing 2.66: ... in JavaScript ... function Addiere(zahl1:Number,zahl2:Number) { var ergebnis:Number = zahl1 + zahl2; return ergebnis; } Listing 2.67: ... und in Flash Lesen wir diese Funktion einmal in Worten: Erzeugt wurde eine Funktion mit dem Namen Addiere. An die Funktion werden zwei Werte übergeben, welche innerhalb der Funktion über die Variablennamen $zahl1 (bzw. zahl1) und $zahl2 (bzw. zahl2) angesprochen werden können. Die Übergabe der Werte erfolgt in runden Klammern direkt hinter dem Funktionsnamen. Innerhalb der Funktion legen wir eine Variable $ergebnis/ergebnis an, der wir das Ergebnis der Addition der Zahlen $zahl1/zahl1 und $zahl2/zahl2 zuweisen. Der Inhalt der Variable wird dann über return an das aufgerufene Programm zurückgegeben.
  • 57.
    K A PI T E L 244 Funktionsaufruf Aufgerufen wird eine Funktion über den Namen der Funktion, wie z.B.: Addiere(1,3); //wenn kein Wert zurückgegeben wird $ergebnis = Addiere(1,3) // mit einem Rückgabewert Listing 2.68: In PHP … Addiere(1,3); // wenn kein Wert zurückgegeben wird var ergebnis = Addiere(1,3); mit einem Rückgabewert Listing 2.69: … in JavaScript … Addiere(1,3); // wenn kein Wert zurückgegeben wird var ergebnis:Number = Addiere(1,3); mit einem Rückgabewert Listing 2.70: … und in Flash Hier wird die Funktion Addiere mit den Zahlen 1 und 3 aufgerufen. Der Rückgabe- wert $ergebnis (bzw. ergebnis in JavaScript/Flash) sollte 4 sein. Funktionen ohne Rückgabewert Oft ist es nicht notwendig, einen Wert aus der Funktion zurückzugeben, da die Daten schon innerhalb der Funktion entweder ausgegeben oder anderweitig verwendet wer- den. Sie werden sogar sehr oft auf Funktionen treffen, an die weder Daten übergeben noch Daten von ihr zurückgegeben werden. Sollte jedoch ein Wert von der Funktion an den „Aufrufer“ zurückgegeben werden, wird dieser im Allgemeinen im aufrufenden Programmblock benötigt. Aus diesem Grund werden die Rückgabewerte gerne im aufrufenden Teil als Variablen gespeichert. Eine andere Variante ist das Ausgeben des Variablenwerts per echo (PHP), alert (JavaScript) oder trace (Flash). Hier ein Beispiel für eine Funktion, die keinen Wert zurückliefert, da ein etwaig errech- neter Wert bereits innerhalb der Funktion ausgegeben wird: function Addiere2($zahl1,$zahl2) { $ergebnis = $zahl1 + $zahl2; echo($ergebnis); //Rückgabe ist nicht notwendig, da Ergebnis im Browser angezeigt wird } Addiere2(10,340); Listing 2.71: Der Wert der Variable (350) wird in PHP per echo im Browser ausgegeben. function Addiere2(zahl1,zahl2) { var ergebnis = zahl1 + zahl2;
  • 58.
    G R UN D L A G E N D E R P R O G R A M M I E R U N G 45 alert(ergebnis); } Addiere2(10,340); Listing 2.72: JavaScript gibt das Ergebnis in einer Alert-Box aus. function Addiere2(zahl1:Number,zahl2:Number) { var ergebnis:Number = zahl1 + zahl2; trace(ergebnis); } Addiere2(10,340); Listing 2.73: In Flash benutzt man trace für eine Ausgabe im Ausgabefenster. Arrays übergeben Wenn an eine Funktion Variablen übergeben werden, die in der Funktionsdeklaration explizit aufgeführt sind, so können diese Werte eben über diese Variablennamen (hier: $zahl1 / zahl1 und $zahl2 / zahl2) angesprochen werden. Ist von vorneherein nicht eindeutig klar, wie viele Werte man an eine Funktion übergeben möchte, dekla- riert man diese nicht explizit, sondern greift auf die Verwendung eines Arrays zurück. Alles, was wir dazu wissen müssen, ist: 1. Wie erstelle ich ein Array? (nur PHP) 2. Wie erhalte ich die Anzahl der Werte eines Arrays? 3. Wie kann ich diese Werte in einer Schleife auslesen? Ein Beispiel: // Funktion deklarieren function Addiere3($arr){ //Anzahl der Elemente des Arrays $arr in $anzParams speichern $anzParams = count($arr); $ergebnis = 0; for($i=0; $i < $anzParams; $i++){ // Addieren aller Parameter $ergebnis = $ergebnis + $arr[$i]; // $ergebnis += $ergebnis wäre auch richtig } // Ergebnis zurückgeben PHPPHP Lokale Variablen in Funktionen Grundsätzlich sind Variablen, die innerhalb einer Funktion angelegt werden, nicht außerhalb der Funktion bekannt. Aus diesem Grund gibt es return, um Werte außer- halb der Funktion weit- erverwenden zu können.
  • 59.
    K A PI T E L 246 return $ergebnis; } //Array der Parameter erzeugen $params = array(1,3,5,2,8); //Aufruf der Funktion Addiere3 und Übergabe des Arrays $params $resultat = Addiere3($params); echo($resultat); Listing 2.74: Auswerten einer beliebigen Anzahl von Übergabeparametern an eine PHP-Funktion Insgesamt wird also in unserer Funktion Addiere3 die for-Schleife fünfmal durch- laufen. Bei jedem Durchlauf wird $ergebnis um den gerade aktuellen Wert aus dem Array $params erhöht. Das Endergebnis ist somit 18. In JavaScript und Flash stellt sich die Sachlage etwas differenzierter dar, denn hier kann man innerhalb einer Funktion auf ein Array namens „arguments“ zurückgreifen, das alle an die Funktion übergebenen Werte beinhaltet – dieses Array muss somit nur noch ausgelesen werden. Der Aufruf der Funktion gleicht dem vorherigen: function Addiere3() { var args = Addiere3.arguments; var ergebnis = 0; for(var i =0; i<args.length; i++) { ergebnis += args[i]; } return ergebnis; } Addiere3(1,3,5,2,8); Listing 2.75: JavaScript erhält eine beliebige Anzahl an Parametern übergeben. function Addiere3() { var args:Array = arguments; var ergebnis:Number = 0; for(var i:Number=0; i<args.length; i++) { ergebnis += args[i]; } return ergebnis; JavaScript und ActionScript JavaScript und ActionScript
  • 60.
    G R UN D L A G E N D E R P R O G R A M M I E R U N G 47 } Addiere3(1,3,5,2,8); Listing 2.76: Auswerten einer beliebigen Anzahl von Übergabeparametern an eine Flash-Funktion. Möch- ten Sie das Ergebnis der Addition ausgeben, so ersetzen Sie die letzte Zeile mit trace(Addiere3(1,3, 5,2,8));. Im Gegensatz zu Flash (es wird lediglich auf das Array arguments zugegriffen) erfolgt in JavaScript der Zugriff über: Funktionsname.arguments. 2.9 Cookies Im Internet würde nur sehr wenig ohne Cookies funktionieren. Jeder Webshop und jedes Forum arbeiten im Grunde mit Cookies. Diese ermöglichen es, User bei einem Wiederaufruf einer Website zu erkennen und persönlich zu begrüßen oder, wie es bei einem Webshop üblich ist, ihnen ihren Warenkorb anzuzeigen. Einige User haben leider das Setzen von Cookies deaktiviert. Meist geschieht dies aus Angst, dass fremde Personen Zugriff auf die eigenen Daten bekommen. Diese Angst ist aber unbegründet, da nicht der Server Cookies am User-PC ausliest, sondern der Client, also der Browser des Users, sendet die Cookie-Daten an die URL zurück. Unterscheiden kann man zwischen persistenten Cookies und Session-Cookies. Letzte- re werden wir im nächsten Abschnitt behandeln. 2.9.1 Exkurs HTTP Wahrscheinlich ist Ihnen der Begriff HTTP schon öfter bei der Eingabe eines Links oder einer Webadresse aufgefallen. Doch was ist dieses HTTP eigentlich und wozu dient es? HTTP ist eine Abkürzung für „HyperText Transfer Protocol“ und ist ein Grundstein des Internets. Mittels HTTP wird die Verständigung des Clients mit dem Server erst möglich. Bei dem Aufruf einer Website geschieht immer dasselbe. 1. Request – der Client (Browser) stellt eine Verbindung mit dem Server her und fragt nach der gewünschten Webseite. 2. Response – Antwort des Webservers mit den Daten oder einer Fehlermeldung, falls die gewünschten Daten nicht vorhanden sind 3. Der Client empfängt die Antwort des Servers und stellt die gewünschten Daten dar. 4. Anschließend wird die Verbindung zwischen Client und Browser geschlossen. Definition von Cookies Cookies sind ein Mecha- nismus, um clientseitige Informationen zu speichern und wieder auszulesen. Diesen Mechanismus nutzen serverseitige Verbindungen.
  • 61.
    K A PI T E L 248 HTTP und Cookies So weit, so gut, aber wahrscheinlich stellen Sie sich nun die Frage: „Was hat jetzt HTTP mit Cookies zu tun?“ Im Grunde haben sie nichts miteinander zu tun. Wichtig für uns ist einzig die Tatsache, dass eine Verbindung zwischen Client und Server immer nach Übergabe der gewünschten Daten geschlossen wird. Dies ist auch nicht weiter schlimm, solange Sie nicht gewisse Daten zu einem späteren Zeitpunkt auf einer weiteren Seite benötigen. Denken wir zum Beispiel an einen Warenkorb bei einem Online-Shop. User können nach Auswahl eines Artikels nach weiteren Produkten suchen und diese dann dem eigenen Warenkorb hinzufügen. Jedoch müssen wir dazu immer wissen, welcher User gerade in unserem Webshop surft. Ansonsten könnte es ja passieren, dass der gewünschte Artikel im Warenkorb eines falschen Kunden gespeichert wird. Genau hier liegt das Problem von HTTP, da sofort nach Übergabe der gewünschten Daten dieVerbindung zwischen Browser und Client geschlossen wird. Somit wissen wir zu keiner Zeit, dass der User X vorher auf der Seite Y gesurft hat. Um dieses Problem in den Griff zu bekommen, können wir auf Cookies oder Sessions zurückgreifen. Cookies setzen In PHP steht uns nur eine Funktion zur Verfügung, die es ermöglicht, Cookies zu set- zen und diese auch wieder auszulesen: setcookie(); Die setcookie()-Funktion muss unbedingt vor dem ersten Ausgeben von Zeichen im Browser gesetzt werden. Sie erwartet sechs Parameter, wobei alle außer dem ersten optional sind. Die Parameter sind: 1. Name 2. Inhalt 3. Verfallsdatum 4. Pfad 5. Domain 6. secure Optionale Parameter Auch wenn der Name-Parameter als einziger Pflicht ist, müssen Sie die Angaben zu Pfad und Domain durch eine leere Zeichenkette „“ und das Verfallsdatum und secure durch die Ziffer 0 ersetzen. Die Funktion sähe dann wie folgt aus: setcookie (cookie1, "", 0, "", "", 0);
  • 62.
    G R UN D L A G E N D E R P R O G R A M M I E R U N G 49 Sehen wir uns die einzelnen Parameter genauer an: Name: Der Name des Cookies darf keine Leerzeichen, Kommas und Semikolons beinhalten. Alles andere ist erlaubt. Inhalt: Der Inhalt des Cookies kann ein Text sein. Meist werden Sie als Inhalt aber eine Variable speichern, deren Inhalt Text ist. Denkbar wäre der Username oder die ID des Users in der Datenbank. Der Inhalt wird auch automatisch über die Funk- tion urlencode() für die URL kodiert. Verfallsdatum: Das Verfallsdatum gibt an, ab wann ein Cookie nicht mehr gültig ist. Geben Sie als Verfallsdatum 0 an, wird das Cookie sofort nach Ende der Sitzung gelöscht. Das Verfallsdatum muss in Sekunden angegeben werden. Angenommen,Ihr Cookie soll nach fünf Minuten verfallen,so müssen Sie folgenden Code für das Verfallsdatum eingeben: time()+300. Mit der Funktion time() bekommt man die aktuelle Uhrzeit. Zu dieser rechnen Sie einfach 300 Sekunden dazu. Um ein bestehendes Cookie früher zu löschen als geplant, geben Sie einfach für das Cookie mit demselben Namen ein Verfallsdatum in der Vergangenheit an. Zum Beispiel time()-300. Domain: Wir haben hier ganz bewusst den Parameter für die Domain vorgezogen, da erst dann der Sinn des Pfad-Parameters erkennbar wird. Ein Browser sucht in der kompletten Liste der Cookies des Users nach einer Übereinstimmung des Domain-Parameters mit dem Internet-Domainnamen des Servers, der die Seite aufgerufen hat. Berücksichtigt werden auch Teile einer Domain. Angenommen, Ihr Domain-Parameter lautet syne.at. Dann ist auch der Aufruf über test.syne.at richtig und das Cookie wird zum Auslesen erkannt. Wenn Sie keine Domain angeben, wird der Name des Servers (hostname) verwendet. Pfad: Mit dem Pfad-Parameter können Sie zur Domain noch einen eigenen Pfad angeben. Erst wenn Domainname und Pfad übereinstimmen, wird das Cookie zum Auslesen bereitgestellt. secure: Mit secure können Sie einstellen, dass ein Cookie nur gesetzt wird, wenn eine sichere Verbindung vorhanden ist. Eine sichere Verbindung erkennt man am https (statt http) in der Adresszeile des Browsers und zusätzlich an einem Schloss-Symbol, dass sich meist in der rechten unteren Ecke befindet. User-ID speichern Nun Schluss mit der Theorie, sehen wir uns ein kleines Beispiel an. Angenommen, wir haben einen Login-Bereich für unsere User erstellt. Um dem User das lästige Anmel- den bei einem erneuten Besuch unserer Website zu ersparen, speichern wir seine User- ID in einem Cookie ab. Durch diese User-ID können wir dann ganz einfach die Daten des Users aus unserer Datenbank laden und den User mit seinem Namen begrüßen. u u u u u u
  • 63.
    K A PI T E L 250 Für unser Beispiel nehmen wir eine fiktive User-ID von 4 an. Diese ID speichern wir in der Variable $idUser ab. Nun können wir ein Cookie für den User definieren. setcookie("user",$idUser, time+300(), "","syne.at",0); Sofern der User das Setzen von Cookies akzeptiert, wird mit obigem Code ein Coo- kie mit dem Namen user und seiner User-ID gespeichert. Dieses Cookie ist für fünf Minuten gültig und bezieht sich auf die Domain syne.at. Nun müssen wir uns überlegen, wie wir beim nächsten Besuch unseres Users kontrol- lieren können, ob ein Cookie existiert, um diesen begrüßen zu können. Dazu nutzen wir das superglobale Array $_COOKIE[]. if(isset($_COOKIE[‚user'])) Mit diesem Code überprüfen wir, ob das Cookie mit dem Namen user bei unserem User in der Cookieliste existiert. Wenn es nicht gefunden ist, wird false zurückgege- ben. Wenn das Cookie gefunden wird, ist unsere Bedingung true und wir könnten dann die Daten unseres Users aus der Datenbank laden. 2.10 Sessions Sessions helfen uns wie Cookies beim Identifizieren des Users, um auch wirklich die richtigen Daten anzuzeigen. Lebensdauer von Session-Cookies: Der große Unterschied von persistenten Coo- kies zu Session-Cookies liegt allein in der Lebensdauer. Session-Cookies werden sofort nach Ablauf der Session, also nach Schließen des Browser-Fensters, zerstört. Session-ID: Beim Erstellen einer Session erhält man eine ID zurück. PHP speichert dann alle Daten, die unter dieser ID anfallen, zentral und abrufbereit auf dem Ser- ver. Der Browser hingegen merkt sich bloß die ID der Session. Meist wird diese in einem Session-Cookie gespeichert. Sessions ohne Cookies: Probleme gibt es hier, wenn der User in seinem Browser keine temporären Cookies akzeptiert. Doch das Gute an Sessions ist, dass wir hier mehrere Möglichkeiten ohne Cookies nutzen können. Denkbar wäre der Einsatz von versteckten Formularfeldern, die die Daten des Users aufnehmen. Dies ist aber eine eher aufwändige und umständliche Variante. Eine bessere Möglichkeit ist, die Session-ID direkt an die Links anzuhängen und auf jeder Seite zu kontrollieren, ob diese Session-ID mit der der aktuellen Sitzung des Browsers übereinstimmt. Nur dann darf der User die jeweilige Seite betrachten. Trotz allem bleibt die Variante mit temporären Cookies am sichersten. Name und ID speichern: In einem dieser Cookies werden nur die Session-ID und der frei wählbare Name der Session gespeichert. Wenn Sie keinen Namen angeben, wird automatisch der Name PHPSESSID genutzt. In der php.ini können Sie den u u u u
  • 64.
    G R UN D L A G E N D E R P R O G R A M M I E R U N G 51 voreingestellten Namen einer Session ändern, indem Sie für session.name einen eigenen String angeben. Die wichtigsten Session-Funktionen sind: session_start() session_register() session_unregister() session_destroy() 2.10.1 session_start() Mittels session_start() wird eine Session initialisiert und das Session-Cookie erstellt. <?php // Session initialisieren session_start(); // Ausgabe der erzeugten Session-ID echo(session_id()); ?> Vor dem Erzeugen einer Session dürfen auf keinen Fall Zeichen an den Browser gesen- det werden. Aus diesem Grund sollten Sie eine Session immer am Beginn eines Scripts initialisieren. Automatische Initialisierung In der php.ini gibt es eine Einstellung session_autostart. Wenn diese auf 1 gestellt ist, können Sie sich den Aufruf von session_start() ersparen. Trotzdem rate ich Ihnen, die Session immer explizit zu initialisieren, da Sie nicht darauf vertrauen kön- nen, dass diese Einstellung bei Ihrem Provider auch in Zukunft so bleibt. 2.10.2 session_register() vs. $_SESSION Bei der Verwendung von Sessions haben Sie auch die Möglichkeit, Variablen in der Ses- sion zu speichern. Denkbar wäre der Username oder dessen Kundennummer. Dem Auf- ruf von session_register() muss ein Aufruf von session_start() vorangehen. <?php // Variablen $username = "Uwe"; $kundennummer = 1234; u u u u
  • 65.
    K A PI T E L 252 // Session initialisieren session_start(); // register_globals = ON session_register(‚username','kundennummer'); ?> Listing 2.77: Verwendung bei register_globals=on. Nicht ideal! Bitte beachten Sie, dass es sich bei den Parametern von session_register() nicht um die Variablen, sondern um deren Namen handelt. Somit müssen Sie das $-Zeichen weglassen. Array bei register_globals = OFF Wenn in der php.ini register_globals auf OFF steht, sollten Sie das superglobalen Array $_SESSION anstelle von session_register() verwenden: //register_globals = OFF $_SESSION[‚username']; $_SESSION[‚kdnr']; Mein Tipp ist, dass Sie sich von vorneherein angewöhnen, auf die superglobalen Arrays zurück- zugreifen, denn diese werden in jedem Fall funktionieren. Bei Einstellungen, die register_ globals betreffen, sollte man generell vorsichtig sein. Auch gehen fast alle gängigen Provider aus Sicherheitsgründen weg von register_globals=on. Wichtig ist, dass die gewünschten Variablen erst zum Ende des Scripts in die Session gespeichert werden. Dadurch ist es möglich, dass Sie den Wert der Variablen im Laufe des kompletten Scripts ändern, da ja erst der Endwert in die Session geschrieben wird. Als Folge daraus können wir auf die Sessionvariablen frühestens nach Beendigung des aktuellen Scripts und beim nächsten session_start() zugreifen. <?php // Variablen $username = "Uwe"; $kundennummer = 1234; // Session initialisieren session_start(); // register_globals = OFF $_SESSION["username"] = $username; $_SESSION["kundennummer"] = $kundennummer; ?> Listing 2.78: Verwendung bei register_globals=off. Ideal!
  • 66.
    G R UN D L A G E N D E R P R O G R A M M I E R U N G 53 2.10.3 session_unregister() vs. $_SESSION session_unregister() ist das genaue Gegenteil von session_register(). Es dient dazu, eine oder mehrere Variablen aus der Session zu verwerfen. <?php session_start(); // register_globals = ON session_unregister('username'); ?> unset() bei register_globals = OFF Ist register_globals auf OFF gestellt, dürfen wir session_unregister() nicht verwen- den, da man bei dieser Einstellung nicht auf diese Funktion zurückgreifen darf. Wir nutzen zum Löschen einer Sessionvariable dann die PHP-Funktion unset(): // register_globals_ OFF unset($_SESSION['username']); Heben Sie aber nicht $_SESSION selbst mit unset() auf, weil dies die besondere Funktion des superglobalen Arrays $_SESSION deaktivieren würde. 2.10.4 session_destroy() Die Funktion session_destroy() veranlasst PHP, alle Variablen einer Session zu verwerfen und die Session zu löschen. Dem Aufruf von session_destroy() muss ein Aufruf von session_start() vorangehen. <?php session_start(); // Session zerstören session_destroy(); ?> 2.11 Caching Caching ist das Zwischenspeichern von Daten einer Webseite im Cache (Speicher) des Browsers, um diese beim nächsten Aufruf schneller darstellen zu können. Dies ist im Grunde von Vorteil für den User. Wenn Flash mit PHP zusammenarbeitet, kann dies aber hinderlich sein, da der User möglicherweise veraltete Daten angezeigt bekommt. Um das Caching zu beeinflussen oder auch zu verhindern, nutzen wir die Funktion header() von PHP. Der Header einer Webseite beinhaltet Anfangsinformationen, wie Caching in PHPCaching in PHP
  • 67.
    K A PI T E L 254 zum Beispiel den Typ des Dokuments und eben auch, wie lange eine Seite im Cache des Browsers gespeichert werden soll. Um einem Browser mitzuteilen, dass eine Seite nicht zwischengespeichert werden soll, müssen wir drei Dinge einstellen. 1. Wann soll die Webseite aus dem Cache gelöscht werden? 2. Wann wurde die Webseite modifiziert? 3. Die Webseite soll nicht gecacht werden. Für die Einstellung, wann die Webseite aus dem Cache gelöscht werden soll, geben wir einfach ein Datum in der Vergangenheit an. Wichtig ist die Formatierung des Datums selbst und die Zeitzone. // Datum aus der Vergangenheit header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); Um zu bestimmen, wann die Webseite zum letzten Mal modifiziert wurde, geben wir auch wieder ein Datum ein. Hier soll logischerweise kein Datum in der Vergan- genheit angegeben werden, sondern immer das aktuelle. Dies können wir über die PHP-Datumsfunktion gmdate() realisieren. Mit dieser Funktion können wir immer das Datum mit der Zeitangabe von Greenwich Mean Time (GMT) auslesen. Wie wir dieses Datum und die Uhrzeit formatieren möchten, können wir in den Parametern von gmdate() angeben. a – am/pm A – AM/PM B – Swatch-Internetzeit (Internetzeit, die überall auf der Welt gleich ist) d – Tag des Monats mit zwei Stellen und führender Null (01-31) D – Tag der Woche als Abkürzung mit drei Buchstaben F – Monat, ausgeschrieben h – Stunde im 12-Stunden-Format H – Stunde im 24-Stunden-Format g – Stunde im 12-Stunden-Format ohne führende Null G – Stunde im 24-Stunden-Format ohne führende Null i – Minuten von 0 bis 59 I – 1 bei Sommerzeit, 0 bei Winterzeit j – Tag des Monats ohne führende Null (1-31) l – Wochentag, voll ausgeschrieben u u u u u u u u u u u u u u Caching verhindern Caching verhindern Datum angebenDatum angeben
  • 68.
    G R UN D L A G E N D E R P R O G R A M M I E R U N G 55 L – boolescher Wert, ob das Datum in einem Schaltjahr liegt m – Monat mit führender Null n – Monat ohne führende Null M – Monat als Abkürzung s – Sekunden mit führender Null (00-59) S – Suffix der englischen Ordnungszahlen (bei 1 = 1st (first), bei 2 = 2nd (second) usw.) T – Einstellung der Zeitzone des Servers (GMT oder MET ...) t – Anzahl der Tage in einem Monat U – Sekunden seit Beginn der UNIX-Zeitepoche (Beginn der UNIX-Zeitepoche ist der 1.1.1970, 00 Uhr) w – numerische Darstellung des Wochentags (beginnend bei 0 für Sonntag) Y – vierstellige Ausgabe des Jahres y – zweistellige Ausgabe des Jahres z – Tag im Jahr (0-365) Z – Differenz von UTC zur benannten Zeitzone in Sekunden. Der Offset für die Zeitzone West nach UTC ist immer negativ und für die Zeitzone Ost nach UTC immer positiv (-43200 bis 43200). Somit könnte die Header-Angabe für die letzte Modifizierung der Seite zum Beispiel folgendermaßen aussehen: // immer geändert header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); Zu guter Letzt müssen wir noch einstellen, dass die Webseite generell nicht zwischen- gespeichert werden soll. Hier müssen wir aber die Einstellung für die verschiedenen HTTP-Versionen, welche Browser verwenden, definieren. // für HTTP 1.1 header("Cache-Control: no-store, no-cache, must-revalidate"); header("Cache-Control: post-check=0, pre-check=0", false); // für HTTP 1.0 header("Pragma: no-cache"); Bei der Verwendung der header-Funktion sollten Sie immer beachten, dass vor deren Aufruf kein Zeichen an den Browser gesendet werden darf. Um keine Fehlermeldungen zu bekommen, geben Sie die header-Funktionen immer am Beginn einer PHP-Seite an. Achten Sie auch darauf, dass kein Leerzeichen davorsteht. u u u u u u u u u u u u u u header()- Funktion immer zuerst header()- Funktion immer zuerst
  • 69.
    K A PI T E L 256 2.12 XML auslesen und erstellen In PHP 4 war das Arbeiten mit XML noch sehr mühsam. Zum Glück hat sich das in PHP 5 grundlegend geändert. Nun ist die Grundlage von XML in PHP das Docu- ment Object Model, kurz DOM. Wenn Sie JavaScript kennen, wird Ihnen das DOM mit Sicherheit etwas sagen. Das DOM ist ein vom W3C verabschiedeter Standard für XML-Programmierschnittstellen. Zusätzlich gibt es seit PHP 5 die Erweiterung SimpleXML, mit der es sehr einfach ist, mit XML-Daten zu arbeiten. 2.12.1 Der Aufbau eines XML-Dokuments – Blitzeinführung XML ist wie HTML und XHTML eine Bezeichnungssprache, die von der überge- ordneten Bezeichnungssprache SGML („Standard Generalized Markup Language“) abstammt. Man spricht auch gerne davon, dass XML eine „Teilmenge von SGML“ ist. XML für sich bildet wiederum die Basis für weitere Bezeichnungssprachen wie XHTML, RSS usw. Entgegen HTML existieren in XML keine vorgefertigten Tags und aus diesem Grund sollte man auch XML nicht mit HTML vergleichen. XML stellt – für unsere Zwecke – lediglich ein Modell zur Verfügung, mit dem wir auf einfache Art und Weise struk- turierte Daten darstellen können. ABBILDUNG 2.5 XML stammt von SGML ab.
  • 70.
    G R UN D L A G E N D E R P R O G R A M M I E R U N G 57 Ein XML-Dokument besteht aus zwei Teilen: 1. Prolog: Hierin werden der SGML-Typ deklariert (in unserem Fall also XML), Informationen zum Dokumenttyp dargestellt und etwaige Kommentare eingefügt. 2. Inhalt: Dieser Teil beinhaltet die darzustellenden Informationen, die durch das sogenannte „Wurzelelement“ umhüllt werden. Der Prolog Der Prolog beginnt mit der Deklaration des Dokuments, es wird also festgelegt, dass es sich hierbei um ein XML-Dokument handelt. Als Attribute dienen die Version (version), Informationen zum Zeichensatz (encoding) und zur Eigenständigkeit (standalone) des Dokuments: <?xml version="1.0" encoding="UTF-8" standalone="yes" ?> Werfen wir einen Blick auf die einzelnen Attribute: version: Gibt die verwendete Version von XML an, wobei derzeit die Version 1.0 aktuell ist. encoding: Gibt Informationen zum verwendeten Zeichensatz an. Typische Zei- chensätze sind der (eingeschränkte) Zeichensatz UTF-8 sowie der (westliche) Zei- chensatz ISO-8859-1. standalone: Kann die Werte no oder yes annehmen, die ausdrücken sollen, ob zusätzlich zu diesem Dokument noch ein weiteres Dokument (wie beispielsweise eine externe DTD – Document Type Definition) benötigt wird (standalone="no") oder nicht (standalone="yes"). Da XML in diesem Buch als „Datenschnittstelle“ zwischen PHP und Flash dienen soll, wird zumeist standalone="yes" verwendet. In den meisten anderen Anwendungen (bei denen beispielsweise XML zur Dar- stellung von Daten in einem Browser-Fenster verwendet wird) benötigt man eine zusätzliche DTD und somit muss es dort standalone="no" heißen. Auf den Prolog folgt bei Bedarf eine Dokumenttyp-Definition, damit ein Browser neben der Wohlgeformtheit auch die Gültigkeit des Dokuments überprüfen kann. In gewissen Fällen kann dies notwendig sein. Wir gehen jedoch davon aus, dass unsere (geringen Mengen an) Daten korrekt sind. Als Beispiel könnte die DTD wie folgt aus- sehen: <!DOCTYPE Kundendaten SYSTEM "http://www.syne.at/xml/kunden.dtd"> u u u
  • 71.
    K A PI T E L 258 Wohlgeformtheit und Gültigkeit Wohlgeformtheit deutet an, dass eine XML-Datei die Regeln von XML korrekt einhält. Diese sind: Am Beginn der XML-Datei steht die XML-Deklaration: <?xml version="…">. Das Dokument enthält zumindest ein Datenelement. Es existiert ein Datenelement, das alle weiteren Datenelemente umfasst. Ein gültiges XML-Dokument enthält neben der XML-Deklaration zusätzlich eine anschließende Dokumenttyp-Deklaration (DTD), die entweder auf eine externe DTD-Datei verweist oder die not- wendigen DTD-Regeln beinhaltet. Eine gute Übersicht zu Wohlgeformtheit und Gültigkeit finden Sie auf der Website SelfHTML.de (http://de.selfhtml.org/xml). Sollen im Prolog noch Kommentare eingefügt werden, so kann dies mithilfe der aus HTML ebenfalls bekannten Kommentarzeichen <!-- (Beginn des ein- oder mehrzei- ligen Kommentars) und --> (Kommentarende) geschehen. Der Inhaltsbereich Dieser Bereich des Dokuments beinhaltet sämtliche Daten. Besonders zu beachten ist, dass ein einziges Tag (das „Wurzelelement“) sämtliche weiteren Tags umschließt. Wie das Wurzelelement benannt wird, spielt keine Rolle und ist vollkommen Ihnen überlassen. Auch sind der Verwendung von Verschachtelungen beliebigen Ausmaßes sowie von Attributen keine Grenzen gesetzt. Im Allgemeinen achtet man darauf, dass bei beispielsweise einer Datenbankabfrage die Struktur der verwendete(n) Tabelle(n) widergespiegelt wird. Letztendlich ist es nur wichtig, dass die Struktur zum Auslesen der Daten bekannt und vereinbart ist. Nachfolgend finden Sie ein Beispiel eines XML-Dokuments, bei dem Daten aus einem Verzeichnis auf dem Webserver ausgelesen werden. Beide Dokumentstrukturen sind gültig – Sie entscheiden, wie das XML-Dokument aufgebaut wird: <?xml version="1.0" encoding="UTF-8" standalone="yes" ?> <Playlist rootDir="songs" autostart="0"> <song src="01_GuentherStraub_Demo-CD_KeepOnGwine.mp3" Interpret="Guenther Straub"/> <song src="02_GuentherStraub_Demo-CD_RockingNightExpress.mp3" Interpret="Guenther Straub"/> <song src="03_GuentherStraub_Demo-CD_DizzyFingers.mp3" Interpret="Guenther Straub"/> <song src="04_GuentherStraub_Demo-CD_ArkansasBlues.mp3" Interpret="Guenther Straub"/> </Playlist> Listing 2.79: Eine Möglichkeit des Aufbaus eines XML-Dokuments u u u Das Wurzelelement eines XML-Dokuments Bitte achten Sie darauf, dass sämtliche Daten von einem Wurzelelement eingeschlossen werden müssen, wobei die Betonung auf „einem“ liegt.
  • 72.
    G R UN D L A G E N D E R P R O G R A M M I E R U N G 59 <?xml version="1.0" encoding="UTF-8" standalone="yes" ?> <Playlist rootDir="songs" autostart="0"> <song> <src>01_GuentherStraub_Demo-CD_KeepOnGwine.mp3</src> <Interpret>Guenther Straub</Interpret> </song> <song> <src>02_GuentherStraub_Demo-CD_RockingNightExpress.mp3</src> <Interpret>Guenther Straub</Interpret> </song> <song> <src>03_GuentherStraub_Demo-CD_DizzyFingers.mp3</src> <Interpret>Guenther Straub</Interpret> </song> <song> <src>04_GuentherStraub_Demo-CD_ArkansasBlues.mp3</src> <Interpret>Guenther Straub</Interpret> </song> </Playlist> Listing 2.80: Auch so kann ein XML-Dokument aufgebaut werden. Strenge Syntax von XML-Dokumenten Entgegen der Tag-Schreibweise von HTML-Dokumenten muss man bei XML-Dokumenten unter anderem folgende Punkte beachten: Jedes geöffnete Tag muss auch wieder geschlossen werden. Tags, die sofort geöffnet und wieder geschlossen werden, unterliegen der Schreibweise <Tagname [Attribut="Wert" ...] />. Es wird auf Groß- und Kleinschreibung der Tag-Namen geachtet. Alle Werte von Attributen stehen in Anführungszeichen. XML-Dokumente sind selbstverständlich in einem wesentlich größeren Umfang ver- wendbar. Es ist jedoch nicht sinnvoll, Sie mit sämtlichen Informationen hinsichtlich XML „vollzufüttern“, wenn wir im Rahmen dieses Buchs nur einen Bruchteil davon benötigen. Sollten Sie an weiterführenden Informationen interessiert sein, so finden Sie diese beispielsweise auf der XML-Website des W3-Konsortiums (http://www. w3.org/XML). u u u Tags, Attribute, Knoten & Co. Eine ausführliche Dokumentation zu XML finden Sie unter anderem auf der Website SelfHTML.de (http:// de.selfhtml.org/xml).
  • 73.
    K A PI T E L 260 2.12.2 Auslesen einer XML-Struktur SimpleXML bietet uns ein Objekt, mit dem wir XML-Daten einlesen können und dessen Daten in einer Objektstruktur dargestellt werden. Um XML-Daten in PHP einzulesen, stehen uns zwei Funktionen zur Verfügung: Wenn Sie eine XML-Datei einlesen, können Sie simplexml_load_file() nutzen. Als Parameter wird allein der Dateiname mit der Pfadangabe benötigt. Um einen XML-String weiterverarbeiten zu können, müssen wir diesen mit simplexml_load_string() einlesen. Hier ist logischerweise als Parameter die Variable des XML-Strings erforderlich. In unseren Workshops werden wir später mit dieser Funktion die XML-Daten auslesen, die Flash an PHP gesendet hat. Sehen wir uns ein kleines Beispiel an. Erstellen Sie in einem Editor eine XML-Datei und geben Sie ihr den Namen bb_players.xml. Der Inhalt dieser Datei sollte folgender- maßen aussehen: <?xml version="1.0" encoding="utf-8" standalone="yes" ?> <basketball> <spieler> <name>Michael Jordan</name> <team>Chicago Bulls</team> </spieler> <spieler> <name>Allen Iverson</name> <team>Philadelphia 76ers</team> </spieler> </basketball> Listing 2.81: Eine einfache XML-Datei Angenommen, wir möchten nun den Namen des ersten Spielereintrags in der XML- Datei bb_players.xml ausgeben, so müssen wir zuerst einmal das XML-File einlesen: // Einlesen der XML-Datei, die im gleichen Ordner des Scripts liegt $xmlData = simplexml_load_string("bb_players.xml"); Als Nächstes geht es nun ans Auslesen des ersten Spielereintrags: // Ausgabe des Spielernamens echo($xmlData->spieler[0]->name); Um das Team des ersten Spielers zu erfahren, müssen wir nur den folgenden Code eingeben: echo($xmlData->spieler[0]->team); u u
  • 74.
    G R UN D L A G E N D E R P R O G R A M M I E R U N G 61 Das Auslesen der Daten eines XML-Knotens ist denkbar einfach. Es funktioniert im Grunde wie bei einem Array. Um den ersten Eintrag auslesen zu können, müssen wir im Fall eines Arrays an der Stelle 0 beginnen und bei einem XML-Knoten ist es genau- so. Will man die Daten des zweiten Spielers unserer XML-Datei ausgeben, müssen wir nur den zweiten Spielereintrag mit spieler[1] aufrufen. // Ausgabe der zweiten Spielerdaten echo($xmlData->spieler[1]->name); echo($xmlData->spieler[1]->team); Um alle Knoten der XML-Datei auszugeben, können wir eine for...each-Schleife nutzen. foreach($xmlData->spieler as $mySpieler){ echo($mySpieler -> name); echo(" – "); echo($mySpieler->team."<br />"); } Attribute auslesen Das Auslesen von Attributen in XML-Tags ist auch denkbar einfach. Diese können wie assoziative Array-Einträge behandelt werden. Um dies zu testen, erweitern wir unsere XML-Datei um ein Attribut mit dem Namen nickname im Tag name. <?xml version="1.0" encoding="utf-8" standalone="yes" ?> <basketball> <spieler> <name nickname="Air Jordan">Michael Jordan</name> <team>Chicago Bulls</team> </spieler> <spieler> <name nickname="The Answer">Allen Iverson</name> <team>Philadelphia 76ers</team> </spieler> </basketball> Listing 2.82: Das Tag name wurde um ein Attribut erweitert. Unsere angepasste for...each-Schleife sieht demnach so aus: foreach($xmlData->spieler as $mySpieler){ echo($mySpieler -> name);
  • 75.
    K A PI T E L 262 echo(" – "); echo($mySpieler -> name[‚nickname']); echo(" – "); echo($mySpieler -> team."<br />"); } Untergeordnete Knoten auslesen Interessant ist noch, wie wir XML-Knoten auslesen können, deren Bezeichnung wir nicht kennen. Dazu steht uns eine Funktion mit dem Namen children zur Verfü- gung. Diese Funktion liest alle einem Knoten untergeordneten Knoten aus und spei- chert diese in einem Array. $arrKnoten = $xmlData->children(); foreach($arrKnoten as $arrMyKnoten){ $arrChildren = $arrMyKnoten->children(); foreach($arrChildren as $strKnoten => $varValue) { echo("Knoten ".$strKnoten." hat den Wert ".$varValue."<br />"); } } Zuerst holen wir mit $arrKnoten = $xmlData->children(); alle Kindelemente des obersten Elements <basketball> aus dem XML-Objekt $xmlData und speichern diese in dem Array $arrKnoten. Dann verarbeiten wir dieses Array mit einer for...each-Schleife. In dieser Schleife werden alle Kinder des zweiten XML-Knotens <spieler> ausgelesen und im Array $arrChildren gespeichert. Besonders an dieser for...each-Schleife ist, dass wir neben den Werten des assoziativen Arrays auch die Schlüssel auslesen. foreach($arrChildren as $strKnoten => $varValue) Zum Schluss müssen wir nur noch die Daten des XML-Objekts auslesen. echo("Knoten ".$strKnoten." hat den Wert ".$varValue."<br />"); 2.12.3 XML-Dokumente erstellen Um eine XML-Datei zu erstellen, nutzen wir die SimpleXML-Funktion asXML(). Wir erstellen einfach einen String mit der bereits bekannten XML-Struktur. Auf das XML-Tag können wir verzichten, da dieses die Funktion asXML() für uns automatisch hinzugefügt. $data = " <basketball>
  • 76.
    G R UN D L A G E N D E R P R O G R A M M I E R U N G 63 <spieler> <name>Michael Jordan</name> <team>Chicago Bulls</team> </spieler> <spieler> <name>Allen Iverson</name> <team>Philadelphia 76ers</team> </spieler> </basketball> "; Dann erstellen wir wieder ein SimpleXML-Objekt und definieren dieses als XML: $xmlData = simplexml_load_string($data); $xmlData = $xmlData->asXML(); Das war’s auch schon wieder. Zum Testen können wir die XML-Struktur noch im Browser anzeigen: echo($xmlData); So, nun sind Sie für die weiteren Themen und die Workshops gerüstet. Viel Spaß beim Weiterlesen.
  • 78.
    3 BASISWISSEN Ein Programm zumErstellen von Animationen – passt das zur Programmierung? Wir werden sehen ... Eines aber trotzdem schon vorweg – die Antwort ist ja, ohne wenn und aber! Im einführenden Kapitel vermittelte ich Ihnen die Grundlagen der Programmierung. Dort haben Sie auch erfahren, dass diese Grundlagen für (beinahe) alle Programmiersprachen gleich sind. Es ist im Grunde meist vollkommen irrelevant, in welcher Programmiersprache man gelernt hat zu programmieren – die Logik ist immer dieselbe. In diesem Buch werden aber nur PHP, JavaScript und ActionScript genutzt und erklärt. Welche Punkte außerdem noch beachtet werden sollten und was Sie als Flash-Entwickler an Basiswissen mitbringen sollten, klärt dieses kurze Kapitel. Wann immer eine neue Version von Flash auf dem Markt erscheint, glänzen bei den Entwicklern die Augen. Auch bei mir – ich muss es ehrlich zugeben. Jedoch sprechen wir in diesem Buch über ein Thema, bei dem Weiterentwicklungen sehr träge und zäh wirken, und das aus einem sehr einfachen Grund: Es geht hier nicht um eine Schnittstelle zwischen Flash und PHP, sondern um eine zwischen dem Browser auf der einen Seite (dem Client) und dem Server auf der anderen. Flash läuft clientseitig, PHP wird serverseitig ausgeführt. Wenn nicht am Standard der Datenübertragung zwischen Server und Client gearbeitet wird, sieht die Situation wie folgt aus: Die Daten- übertragung erfolgt per GET oder per POST.
  • 79.
    K A PI T E L 366 Was sollte hier noch hinzukommen? Nichts mehr, da muss ich Sie wohl enttäuschen. Nein, „enttäuschen“ ist hier nicht die korrekte Aussage – vielmehr möchten wir Sie noch einmal an die Technik „Server vs. Client“ erinnern, die klar und deutlich defi- niert, dass eine Datenübertragung zwischen Client und Server auf genau diese beiden Arten erfolgen kann und nicht anders! Die wesentlich wichtigere Frage ist, was Sie unter diesen Bedingungen alles erzeugen können. Genau hierauf eine Antwort zu geben, ist Ziel dieses Buchs. Einzig die Kom- munikation zwischen Browser und Flash ist von grundlegendem Interesse für uns. AJAX tut an dieser Stelle nichts anderes: Es greift auf den Datenaustausch zwischen Server und Client per POST oder GET zurück. Der wesentliche Unterschied zum bis- herigen Denken ist, dass AJAX auf Clientseite in der Lage ist, ohne ein Neuladen der Seite nachträglich Daten vom Server abzufragen – dies ist ein Novum! 3.1 PHP PHP läuft mittlerweile in Version 5 (bei Drucklegung war die letztgültige Version die Version 5.2.3) objektorientiert – das konnte die Version 4 noch nicht. Obwohl – in unseren Anwendungen trifft uns das nicht, denn die meisten gängigen Anwendungen in Zusammenhang mit Flash oder AJAX werden nach wie vor ohne Objektorientierung entwickelt. Natürlich kann man an dieser Stelle keine generelle Aussage treffen, denn so ziemlich jede Anwendung ließe sich auch objektorientiert erstellen. Im Allgemeinen sind die Scripts für die Zusammenarbeit mit Flash jedoch so kurz, das Objektorien- tierte Programmierung (OOP) erst gar nicht zum Einsatz gelangt. 3.2 JavaScript (AJAX) & DOM Im vorigen Kapitel wiederholten wir die Grundlagen der Programmierung, die natür- lich auch für JavaScript gelten. Jede Programmiersprache hat ihre eigene „Umgebung“, in der sie wirken – im Fall von JavaScript ist dies das XHTML-Dokument. Es besteht zwar auch die Möglichkeit, JavaScript auf Serverseite zu verwenden, jedoch kommt diese Variante in unserem Fall nicht zum Einsatz. Die grundlegende Frage ist also, wie JavaScript mit seiner Umgebung interagieren kann. In den letzten Jahren hat sich der Begriff DHTML (Dynamic HTML) eingebür- gert – grundsätzlich meint man damit die Möglichkeit, JavaScript, CSS und XHTML miteinander arbeiten zu lassen. Bleibt also zu klären, wie das möglich ist. Unweigerlich stößt man dabei auf den Begriff des Document Object Model (DOM). Ein DOM beschreibt grundsätzlich die Objekte, die in einem Dokument verwendet werden, deshalb ist ein DOM auch nicht auf ein XHTML-Dokument beschränkt. Für JavaScript in Zusammenhang mit (damals noch) HTML wurde vom W3-Consorti- um ein DOM erstmals am 1. Oktober 1998 eingeführt, um der ewigen Diskrepanz
  • 80.
    B A SI S W I S S E N 67 zwischen Netscape und Microsoft in Bezug auf JavaScript und JScript ein für alle mal einen Riegel vorzuschieben. Ende September 2000 wurde dann eine weitere Version dieses DOM veröffentlicht, das im November 2000 dann eine offizielle Empfehlung des W3C erhielt. Ein wichtiger Punkt ist, dass sich das DOM (ich beziehe mich ab jetzt nur noch auf das DOM für JavaScript) nicht speziell auf HTML-Elemente bezieht, sondern in abstrakter Form Zugriff auf Objekte definiert. Grundsätzlich ist mit dem DOM der Zugriff auf jedes XML-basierte Dokument möglich. Da jedoch auch auf die Gegebenheiten von HTML im Speziellen eingegangen werden muss, existiert eine Art „Kern-DOM“ speziell für die Bedürfnisse von HTML und den sich aus den Zwistig- keiten zwischen Netscape und Microsoft ergebenen Differenzen. Leider wurde in der Erstversion von DOM komplett auf ein Eventhandling verzichtet, was speziell bei größeren Projekten unabdingbar notwendig ist. Daher muss oft auf die Möglichkeiten des DOM 2.0 zurückgegriffen werden, das – und das haben Sie sicher- lich schon erraten – in den verschiedenen Browsern noch nicht vollständig unterstützt wird ... 3.2.1 „Kern-DOM“ ABBILDUNG 3.1 „Kern-DOM“ – die Grundlage für alle gängigen Browser
  • 81.
    K A PI T E L 368 Die obige Abbildung zeigt die Kernversion des DOM, das den Zugriff auf alle Elemente innerhalb eines XHTML-Dokuments ermöglicht. Der Zugriff erfolgt grundsätzlich hierarchisch: Möchte man beispielsweise auf ein Element innerhalb eines Formulars zugreifen, so muss man den „Weg durch den Hierarchiebaum“ gehen: 1. Das übergeordnetste Element ist das window, also bezieht man sich zunächst auf dieses Element: window. Selbstverständlich kann ein window auch ein Frame sein. 2. Daraufhin greift man auf das Dokument im window zu: window.document. 3. Danach muss auf das Formular zugegriffen werden. Da es in einem XHTML- DokumentmehralsnureinFormulargebenkann,existierteinArrayanFormularen, das entweder assoziativ oder über den Formularindex angesprochen werden kann. Der Formularindex bezieht sich auf die Reihenfolge der Formulare im Dokument: Das nullte Formular ist somit das erste vorkommende Formular im XHTML- Code. Viel einfacher ist der Zugriff über den Formularnamen (assoziativ): window.document.forms[Formularindex] oder window.document.forms["Formularname"] 4. Hat man sich für ein Formular entschieden, kann man auf die Elemente (Buttons, Eingabefelder etc.) innerhalb des Formulars zugreifen. Auch hier besteht natürlich die Möglichkeit, dass sich mehr als nur ein Element im Formular befinden, deshalb erfolgt der Zugriff auf die Elemente wieder über ein (assoziatives) Array: window.document.forms["Formularname" oder –index]. elements["Elementname" oder –index] 5. Hat man diesen Weg erst einmal hinter sich gebracht, kann man auf alle Eigenschaften und Methoden des Elements zugreifen. Der Zugriff auf sämtliche HTML-Elemente funktioniert hier also immer gleich: 1. Weg durch den Hierarchiebaum zum Objekt finden 2. Auf die Attribute bzw. Eigenschaften des Objekts zugreifen Eine komplette Auflistung aller Elemente und deren Eigenschaften und Methoden ist die Aufgabe einer Referenz – ich empfehle Ihnen eine einschlägige Literatur bzw. die Website http://de.selfhtml.org. Bücher zu diesem Thema füllen zum Teil mehrere hundert Seiten und beschreiben im Detail jedes Element und alle zugehörigen Details. Als Webdesigner sind Sie sicherlich mit diesen Elementen bereits vertraut, wes- halb Sie sehr wahrscheinlich auch mit SelfHTML schon zu tun hatten.
  • 82.
    B A SI S W I S S E N 69 3.2.2 Alternativer Zugriff auf Objekte Eine andere Variante des Zugriffs auf Objekte innerhalb eines (XML-basierten) Doku- ments ist der Zugriff über die Baumstruktur des Dokuments an sich. Betrachten wir folgendes Beispiel: <h1 class="myH1">Hier ist eine erste &Uuml;berschrift.</h1> <p>Nun folgt Text, der verschiedene Auszeichnungen wie <strong>fett</ strong> oder <em>kursiv</em> aufweist.</p> <p>So, ein zweiter Text, der <em><strong>fett und kursiv</strong></em> geschrieben ist.</p> Listing 3.1: Ein einfaches Beispiel eines XHTML-Dokuments Die entsprechende Struktur dieses Dokuments wäre wie folgt: Jedes Element innerhalb der Baumstruktur wird als Knoten bezeichnet. Man unter- scheidet zwischen drei Arten von Knoten: 1. Elementknoten 2. Attributknoten 3. Textknoten In der obigen Abbildung (Abbildung 3.2) sind nur Elementknoten dargestellt. Würden wir alle Knoten darstellen, würde sich die Abbildung wie folgt erweitern: ABBILDUNG 3.2 Die Baumstruktur des obigen Beispiels (Listing 3.1)
  • 83.
    K A PI T E L 370 Was in den Abbildungen auffällt (und selbstverständlich auch absichtlich so gezeichnet ist ...), ist die Einteilung in sogenannte „Parent- und Child-Knoten“ sowie „Siblings“. Die Baumstruktur ist wie eine Ahnengalerie zu verstehen: Parent-Knoten sind übergeordnete Knoten: Zu <h1> existiert in unserem Fall kein Parent-Knoten, zum ersten <strong> (zweite Ebene) ist der Parent-Knoten <p>, zum zweiten <strong> (dritte Ebene) ist der Parent-Knoten <em>, dessen Parent wiederum ein <p> ist. Child-Knoten sind untergeordnete Knoten: <strong> ist beispielsweise ein Child-Knoten von <p> usw. Siblings sind „Geschwister“: <h1> hat beispielsweise die beiden Geschwister <p> und <p>. Um direkt und schnell auf einen beliebigen Knoten innerhalb eines Dokuments zugreifen zu können, wurden drei Funktionen eingeführt: getElementById(Element-ID): greift auf ein Element (einen Knoten) mit einer (eindeutigen) id zu. getElementsByName(Elementname)[i]: greift auf Elemente eines gewissen Namens zu. Da der Name von Elementen im Dokument nicht eindeutig sein muss, wird auf ein Array zugegriffen. u u u u u ABBILDUNG 2.3 Dieselbe Baumstruktur inklu- sive Attribut- (durchgezogen umrandet) und Textknoten (gestrichelt umrandet)
  • 84.
    B A SI S W I S S E N 71 getElementsByTagName(Tagname)[i]: greift auf Elemente eines gewissen Tag- Namens (wie etwa „p“, „h1“ etc.) zu. Wie im Fall von getElementsByName gilt auch hier: Es können mehrere Tags dieser Art existieren, deshalb erfolgt der Zugriff über ein Array. Hat man ein Element eindeutig identifiziert, kann man sich über die Eigenschaften und Methoden des node-Objekts zu den weiteren Elementen „durcharbeiten“. Neh- men wir ein Beispiel: <h1 class="myH1">Hier ist eine erste &Uuml;berschrift.</h1> <p id="myP01">Nun folgt Text, der verschiedene Auszeichnungen wie <strong>fett</strong> oder <em>kursiv</em> aufweist.</p> <p>So, ein zweiter Text, der <em><strong>fett und kursiv</strong></em> geschrieben ist.</p> Listing 3.2: Erweiterung des obigen Beispiels um id="myP01". Der Zugriff soll auf das Element <em> erfolgen. Ziel ist es, den Textknoten des <em> auszulesen. Um zunächst auf den Paragrafen mit der id="myP01" zuzugreifen, verwendet man folgenden Befehl: document.getElementById("myP01") Da das Tag <em> das zweite Kind von <p> ist, verwenden wir das Array childNodes, welches den Zugriff auf alle Child-Elemente eines gegebenen Knotens zulässt: document.getElementById("myP01").childNodes[1] Nun erfolgt der Zugriff auf den Textknoten. Hierbei ist zu berücksichtigen, dass ein Textknoten immer ein Child-Knoten eines Elementknotens ist. Aus diesem Grund erfolgt der Zugriff wie folgt: document.getElementById("myP01").childNodes[1].firstChild Der letzte Schritt besteht im Auslesen des Werts des Knotens – dies erfolgt über die Eigenschaft nodeValue eines Knotens: document.getElementById("myP01").childNodes[1].firstChild.nodeValue Damit hätten wir den Wert des Knotens erreicht! Weitere Informationen zu Knoten und deren Eigenschaften und Methoden finden Sie in der einschlägigen Literatur wie beispielsweise der SelfHTML-Site. Ein abschließender Tipp noch: Bedenken Sie, dass Sie per JavaScript erst dann auf Knoten zugreifen können, wenn diese zum User übertragen wurden. Aus diesem Grund sollte der Zugriff erst erfolgen, wenn die gesamte Seite zum User übertragen wurde – ideal ist hier das Verwenden des Ereignisses onload des window-Objekts. u Textknoten ist ein Kind des Elementknotens Textknoten ist ein Kind des Elementknotens
  • 85.
    K A PI T E L 372 3.3 Flash 3.3.1 Sinnvolle Kombination von Flash und PHP Ab wann – sprich ab welcher Generation von Flash – ist der Einsatz von Flash auf Clientseite und PHP auf Serverseite sinnvoll? Seit der sechsten Version (Flash MX) können wir bereits relativ problemlos über die LoadVars- und die XML-Klasse Daten versenden und einlesen. Zwar wurde die XML-Klasse bereits mit Flash 5 eingeführt, man konnte jedoch nur sehr eingeschränkt damit arbeiten. Die LoadVars-Klasse exis- tiert hingegen erst ab Flash 6. Fassen wir kurz zusammen, ab welcher Generation uns welche Möglichkeiten zur Verfügung standen: 1. Flash 5: Die Methode loadVariables (mittlerweile nur noch sehr selten verwendet) stand schon ab Generation 4 von Flash bereit, die XML-Klasse wird mit Flash 5 eingeführt. 2. Flash 6 (Flash MX): Macromedia integriert die LoadVars-Klasse. 3. Flash 7 (Flash MX 2004): Nachdem die loadVariables-Methode nicht mehr adäquat ist, wird diese mit Release 7 von Flash überarbeitet und hat seitdem ein geändertes Verhalten. 4. Flash 8: keine Neuerungen 5. Flash CS3: umfassende Änderungen durch die Einführung von ActionScript 3.0 Die achte Version von Flash brachte uns in puncto Kommunikation mit PHP auf Ser- verseite also keine Neuerungen, weil sie technisch nicht sinnvoll bzw. möglich wären: Zum Datenaustausch mit PHP stehen im Prinzip alle notwendigen Klassen bereit und hinsichtlich der Client-Server-Kommunikation müsste ein Technologiewechsel statt- finden. Die Möglichkeit, XML-Daten in Flash einzulesen, hat uns einen wesentlichen Schritt weitergebracht und die Tür zu strukturierten Daten geöffnet. Eine Neuerung hinsichtlich der Datenstrukturierung à la XML ist in naher Zukunft nicht zu erwarten – auch Techniken wie RSS (Real Simple Syndication) bauen auf XML auf. Flash CS3 bedeutete in dieser Hinsicht in Zusammenhang mit ActionScript 3.0 beina- he eine „Revolution“. Das Laden von Daten jeglicher Art wurde durch die Einführung der URLLoader- und URLRequest-Objekte komplett geändert. Viele der aus Action- Script 2.0 bekannten Klassen wurden in ActionScript 3.0 entweder verschoben oder umfassend umstrukturiert. Eine Übersicht aller Änderungen finden Sie am Ende des Kapitels. ActionScript 3.0 bringt die Revolution ActionScript 3.0 bringt die Revolution
  • 86.
    B A SI S W I S S E N 73 3.3.2 Weitere Verbindungsmöglichkeiten zur Serverseite Neben den genannten Klassen sind in Flash auch Komponenten installiert, mit deren Hilfe man zu einem Server Kontakt aufbauen kann. Sie erfordern jedoch eine Instal- lation auch auf Serverseite, die im Allgemeinen nicht gegeben ist (das Betreiben eines Communication-Servers von Macromedia wäre ein Beispiel). Jeder gute Webentwickler sollte in der Lage sein, auf solche zusätzlichen serverseitigen Komponenten verzichten zu können, weil es einfach nicht der Realität entspricht, dass uns solche Installationen zur Verfügung stehen. Deshalb wird der Beschreibung dieser Komponenten in diesem Buch nur wenig Platz eingeräumt. Sollten Sie in der glück- lichen Lage sein, auf einen Communication-Server von Macromedia zurückgreifen zu können, dann schlagen Sie doch mal in der ActionScript-Referenz bei Camera und Microphone nach – und flugs haben Sie einen Video-Chat gebastelt. Keine zusätzlichen Server-Dienste verfügbar? Egal oder vielmehr – Gott sei dank! Wir sind in der glücklichen Lage, eine definierte und (in naher Zukunft) auch nicht verän- derbare Schnittstelle vorliegen zu haben, mit der wir in aller Ausführlichkeit arbeiten können – nämlich das Senden von Daten vom Client zum Server per GET oder POST. Dazu mehr in den folgenden Kapiteln. 3.3.3 ActionScript 3.0 – die wichtigsten Änderungen Nachfolgend finden Sie die wesentlichen Änderungen von ActionScript 2.0 auf Action- Script 3.0 in Bezug auf die Themen dieses Buchs – eine umfassende Darstellung aller Änderungen in den Klassen finden Sie im Anschluss. 1. Eigenschaften von MovieClips: Der bekannte Unterstrich „_“ am Beginn einer MovieClip-Eigenschaftwurdeeliminiert(visibleanstatt_visible,alphaanstatt _alpha, x anstatt _x usw.). Ebenso wurde die Handhabung von Prozentwerten geändert: Die Werte werden nun von 0–1 anstatt von 0–100 angegeben. 2. Levelbezug und -verwaltung: Die Arrays _global und _root existieren nicht mehr, wobei anstatt _root der Bezug über stage verwendet werden kann. Anstatt _parent muss nun parent verwendet werden. Ebenso hat sich die gesamte Verwaltung der Levels geändert. Die Methoden swapDepths und getNextHighestDepth sind Vergangenheit – stattdessen wird die Level-Verwaltung nun über die DisplayObjectContainer-Klasse gespielt, wobei diese Klasse als ein Array aller verwendeten Objekte auf der Bühne verstanden werden kann, die über einen Index angesprochen werden. So kann die Reihenfolge (in z-Richtung) von Elementen nach wie vor beeinflusst und gesetzt werden.
  • 87.
    K A PI T E L 374 3. MovieClip vs. DisplayObjectContainer: Die meisten MovieClip-Funk- tionen, die man bisher zur Entwicklung verwendet hat, wurden geändert. Beispielsweise existiert die Methode createEmptyMovieClip nicht mehr. Stattdessen wird die Methode addChild der DisplayObjectContainer-Klasse verwendet. Dementsprechend lassen sich auch die Methoden createTextField, duplicateMovieClip usw. nicht mehr auffinden. 4. Laden von Daten: In allen Bereichen des Datenladens haben sich Änderungen ergeben.Grundsätzlich erfolgt nun der Ladevorgang immer über das URLRequest- Objekt in Zusammenhang mit diversen anderen Objekten: Bilder und SWF-Dateien: Es werden die Objekte URLRequest und URLLoader verwendet. Die ActionScript 2.0-Variante mit loadMovie bzw. MovieClipLoader wurde entfernt. XML-Daten und Servervariablen: Auch hier wird auf die Objekte URLRequest und URLLoader zurückgegriffen. Als zusätzliches Objekt kommt hier natürlich das XML-Objekt zum Einsatz. Servervariablen können nach dem Laden direkt angesprochen werden. Laden einer URL: Die Funktion getURL wurde ebenfalls eliminiert. An ihre Stelle treten die Funktionen sendToURL und navigateToURL. 5. Eventhandler: auch bei der Ereignisbehandlung hat sich einiges getan. Die Ereignisse sind nun strukturierter, auch können – wie in ActionScript 2.0 gang und gäbe – Button-Ereignisse auf MovieClips nicht mehr angewandt werden. Es wurde beispielsweise auch das Ereignis onReleaseOutside komplett eliminiert und es muss durch andere Techniken ersetzt werden. Eine Umbenennung vieler Ereignisse (speziell Mausereignisse) hat ebenfalls stattgefunden.
  • 88.
    B A SI S W I S S E N 75 ActionScript 3.0 – sämtliche Änderungen ActionScript 2.0 ActionScript 3.0 Kommentare Accessibility-Klasse flash.accessibility. Accessibility isActive() flash.accessibility. Accessibility.active Von einer Funktion zu einer Accessor-Eigenschaft geändert. Der Name wurde von isActive in active geändert. updateProperties() flash.accessibility. Accessibility.updateProperties() arguments-Klasse arguments caller Entfernt Sie erreichen die gleiche Funktionalität durch Übergeben von arguments.callee als ein Argument von der anrufenden Funktion an die angerufene Funktion.Ein Beispiel finden Sie im Abschnitt„Beispiele“ unter argu- ments.callee. Array-Klasse Array Keine Änderung CASEINSENSITIVE Array.CASEINSENSITIVE Der Datentyp wurde in uint geändert. DESCENDING Array.DESCENDING Der Datentyp wurde in uint geändert. length Array.length Der Datentyp wurde in uint geändert. NUMERIC Array.NUMERIC Der Datentyp wurde in uint geändert. RETURNINDEXEDARRAY Array.RETURNINDEXEDARRAY Der Datentyp wurde in uint geändert. UNIQUESORT Array.UNIQUESORT Der Datentyp wurde in uint geändert. Array Array.Array() Der Parameter wurde geändert und verwendet jetzt das Format ...(rest). push() Array.push() Der Parameter wurde geän- dert und verwendet jetzt das Parameterformat ...(rest). sort() Array.sort() Der Datentyp des options- Parameters wurde in uint geän- dert.
  • 89.
    K A PI T E L 376 ActionScript 2.0 ActionScript 3.0 Kommentare sortOn() Array.sortOn() Der Datentyp des options-Para- meters wurde in uint geändert. Der Funktionsumfang wurde unter ActionScript 3.0 erweitert. Jetzt können Sie nach mehreren Feldnamen sortieren,indem Sie ein Objekte-Array für den field- Name-Parameter übergeben.Wenn Sie außerdem ein entsprechendes Optionsflags-Array für den op- tions-Parameter übergeben,kann jedes Sortierfeld seinen eigenen übereinstimmenden options- Parameter aufweisen. splice() Array.splice() Die Parameter können jeden Daten- typ annehmen,die bevorzugten Datentypen sind jedoch int und uint.Der Parameter value wurde in das Parameterformat ...(rest) geändert. unshift() Array.unshift() Der Parameter value wurde in das Parameterformat ...(rest) geändert. Der Datentyp des Rückgabewerts wurde in uint geändert. AsBroadcaster-Klasse flash.events.EventDispatcher _listeners flash.events.EventDispatcher. willTrigger() Kein direktes Äquivalent.Die willTrigger()-Methode meldet Ihnen zwar,ob Listener regis- triert sind,jedoch nicht wie viele. addListener() flash.events.EventDispatcher. addEventListener() Kein direktes Äquivalent,da Sie im ActionScript 3.0-Ereignismodell nicht nur dem Broadcaster- Objekt,sondern jedem Objekt im Ereignisablauf Ereignis-Listener hinzufügen können. broadcastMessage() flash.events.EventDispatcher. dispatchEvent() Kein direktes Äquivalent,da das ActionScript 3.0-Ereignismodell auf andere Weise arbeitet.Die dispatchEvent()-Methode sendet ein Ereignisobjekt in den Ereignisablauf,während die broadcastMessage()-Methode Meldungen direkt an jedes regis- trierte Listener-Objekt sendet.
  • 90.
    B A SI S W I S S E N 77 ActionScript 2.0 ActionScript 3.0 Kommentare initialize() Entfernt Es gibt kein direktes Äquivalent in ActionScript 3.0,aber eine ähnliche Funktionalität wird durch die Unterklassen der EventDispatcher-Klasse er- reicht.Beispielsweise erweitert die DisplayObject-Klasse EventDispatcher,daher sind alle Instanzen von DisplayObject und der DisplayObject- Unterklassen in der Lage, Ereignisobjekte zu senden und zu empfangen. removeListener() flash.events.EventDispatcher. removeEventListener() Kein direktes Äquivalent,da Sie im ActionScript 3.0-Ereignismodell nicht nur dem Broadcaster- Objekt,sondern jedem Objekt im Ereignisablauf Ereignis-Listener hinzufügen und wieder entfernen können. BitmapData-Klasse flash.display.BitmapData ActionScript 3.0 verwendet die BitmapDataChannel-Klasse zur Aufzählung der Konstanten,die den zu verwendenden Kanal angeben. height flash.display.BitmapData. height Der Datentyp wurde von Number in int geändert. rectangle flash.display.BitmapData.rect Die Eigenschaft wurde um- benannt,um für Konsistenz mit anderen Mitgliedern der API zu sorgen. width flash.display.BitmapData.width Der Datentyp wurde von Number in int geändert. copyChannel() flash.display.BitmapData.co- pyChannel() Die Datentypen der Parameter code,sourceChannel und dest- Channel wurden in uint geän- dert. draw() flash.display.BitmapData. draw() Der source-Parameter lau- tet jetzt IBitmapDrawable; DisplayObject und BitmapData implementieren jetzt die IBitmapDrawable-Schnittstelle, so dass Sie entweder ein DisplayObject- oder ein BitmapData-Objekt an den Parameter source übergeben können. fillRect() flash.display.BitmapData.fill- Rect() Der Datentyp des Parameters color wurde in uint geändert. floodFill() flash.display.BitmapData. floodFill() Akzeptiert jetzt int-Werte für die Parameter x und y sowie einen uint-Wert für color. getColorBoundsRect() flash.display.BitmapData.get- ColorBoundsRect() Akzeptiert jetzt uint-Werte für die Parameter mask und color.
  • 91.
    K A PI T E L 378 ActionScript 2.0 ActionScript 3.0 Kommentare getPixel() flash.display.BitmapData.get- Pixel() Akzeptiert jetzt int-Parameter- werte und gibt einen uint-Wert zurück. getPixel32() flash.display.BitmapData.get- Pixel32() Akzeptiert jetzt int-Parameter- werte und gibt einen uint-Wert zurück. hitTest() flash.display.BitmapData.hit- Test() Akzeptiert jetzt uint-Werte für die Parameter firstAlphaThreshold und secondAlphaThreshold. loadBitmap() Entfernt Diese Funktion wird wegen der neuen Bitmap-Unterstützung in ActionScript 3.0 nicht mehr be- nötigt. merge() flash.display.BitmapData. merge() Akzeptiert jetzt uint-Werte für die Multiplizierer-Parameter. noise() flash.display.BitmapData.noi- se() Akzeptiert jetzt einen int-Wert für den Parameter randomSeed und uint-Werte für die Parameter low, high und channelOptions. perlinNoise() flash.display.BitmapData.per- linNoise() Akzeptiert jetzt einen int-Wert für den Parameter randomSeed und uint-Werte für die Parameter numOctaves und channel- Options. pixelDissolve() flash.display.BitmapData. pixelDissolve() Akzeptiert jetzt einen int-Wert für die Parameter randomSeed und numPixels sowie einen uint-Wert für den Parameter fillColor. (Der numPixels-Parameter wurde in ActionScript 2.0 in numberOf- Pixels umbenannt.) scroll() flash.display.BitmapData. scroll() Akzeptiert jetzt int-Werte für die Parameter x und y. setPixel() flash.display.BitmapData.set- Pixel() Akzeptiert jetzt int-Werte für die Parameter x und y sowie einen uint-Wert für color. setPixel32() flash.display.BitmapData.set- Pixel32() Akzeptiert jetzt int-Werte für die Parameter x und y sowie einen uint-Wert für color. threshold() flash.display.BitmapData. threshold() Akzeptiert jetzt uint-Werte für die Parameter threshold,color und mask und gibt einen uint-Wert zurück. BlurFilter-Klasse quality flash.filters.BlurFilter.qua- lity Der Datentyp der quality- Eigenschaft wurde von Number in uint geändert. Button-Klasse flash.display.SimpleButton _alpha flash.display.DisplayObject. alpha blendMode flash.display.DisplayObject. blendMode
  • 92.
    B A SI S W I S S E N 79 ActionScript 2.0 ActionScript 3.0 Kommentare cacheAsBitmap flash.display.DisplayObject. cacheAsBitmap enabled flash.display.SimpleButton. enabled filters flash.display.DisplayObject. filters In ActionScript 3.0 lautet der Datentyp Array. _focusrect flash.display. InteractiveObject.focusRect _height flash.display.DisplayObject. height _highquality Entfernt Siehe Stage.quality _name flash.display.DisplayObject. name _parent flash.display.DisplayObject. parent _quality Entfernt Sie können die Wiedergabequalität aller Anzeigeobjekte mit flash. display.Stage.quality ein- stellen. _rotation flash.display.DisplayObject. rotation scale9Grid flash.display.DisplayObject. scale9Grid _soundbuftime flash.media.SoundMixer.buffer- Time In die SoundMixer-Klasse verschoben,die zur globalen Soundsteuerung verwendet wird.Umbenannt,sodass keine Abkürzungen mehr vorhanden sind.Der Unterstrich am Anfang des Namens wurde entfernt. tabEnabled flash.display. InteractiveObject.tabEnabled tabIndex flash.display. InteractiveObject.tabIndex _target Entfernt ActionScript 3.0 identifiziert Anzeigeobjekte direkt,daher ist die Identifizierung eines Anzeigeobjekts über dessen Pfad nicht mehr notwendig. trackAsMenu flash.display.SimpleButton. trackAsMenu _url Entfernt Siehe DisplayObject.loader- Info.url useHandCursor flash.display.SimpleButton. useHandCursor _visible flash.display.DisplayObject. visible _width flash.display.DisplayObject. width _x flash.display.DisplayObject.x _xmouse flash.display.DisplayObject. mouseX _xscale flash.display.DisplayObject. scaleX _y flash.display.DisplayObject.y
  • 93.
    K A PI T E L 380 ActionScript 2.0 ActionScript 3.0 Kommentare _ymouse flash.display.DisplayObject. mouseY _yscale flash.display.DisplayObject. scaleY getDepth() flash.display. DisplayObjectContainer.get- ChildIndex() ActionScript 3.0 bietet direkten Zugriff auf die Anzeigeliste,daher wird die Tiefe auf andere Weise bearbeitet. onDragOut() flash.display. InteractiveObject dispatches event: mouseOut Wurde im neuen Ereignismodell durch ein mouseOut-Ereignis ersetzt. onDragOver() flash.display. InteractiveObject dispatches event: mouseOver Wurde im neuen Ereignismodell durch ein mouseOver-Ereignis ersetzt. onKeyDown() flash.display. InteractiveObject dispatches event: keyDown Wurde im neuen Ereignismodell durch ein keyDown-Ereignis er- setzt. onKeyUp() flash.display. InteractiveObject dispatches event: keyUp Wurde im neuen Ereignismodell durch ein keyUp-Ereignis ersetzt. onKillFocus() flash.display. InteractiveObject dispatches event: focusOut Wurde im neuen Ereignismodell durch ein focusOut-Ereignis ersetzt. onPress() flash.display. InteractiveObject dispatches event: mouseDown Wurde im neuen Ereignismodell durch ein mouseDown-Ereignis ersetzt. onRelease() flash.display. InteractiveObject dispatches event: mouseUp Wurde im neuen Ereignismodell durch ein mouseUp-Ereignis er- setzt. onReleaseOutside() flash.display. InteractiveObject dispatches event: mouseUp Wurde im neuen Ereignismodell durch ein mouseUp-Ereignis er- setzt. onRollOut() flash.display. InteractiveObject dispatches event: mouseOut Wurde im neuen Ereignismodell durch ein mouseOut-Ereignis ersetzt. onRollOver() flash.display. InteractiveObject dispatches event: mouseOver Wurde im neuen Ereignismodell durch ein mouseOver-Ereignis ersetzt. onSetFocus() flash.display. InteractiveObject dispatches event: focusIn Wurde im neuen Ereignismodell durch ein focusIn-Ereignis er- setzt. Camera-Klasse flash.media.Camera activityLevel flash.media.Camera.activity- Level bandwidth flash.media.Camera.bandwidth currentFps flash.media.Camera.currentFPS Änderung bei der Groß-/ Kleinschreibung von FPS fps flash.media.Camera.fps height flash.media.Camera.height Der Datentyp wurde von Number in int geändert. index flash.media.Camera.index Der Datentyp wurde von String in int geändert.
  • 94.
    B A SI S W I S S E N 81 ActionScript 2.0 ActionScript 3.0 Kommentare motionLevel flash.media.Camera.motionLevel Der Datentyp wurde von Number in int geändert. motionTimeOut flash.media.Camera.motionTime- out Der Datentyp wurde von Number in int geändert. muted flash.media.Camera.muted name flash.media.Camera.name names flash.media.Camera.names quality flash.media.Camera.quality Der Datentyp wurde von Number in int geändert. width flash.media.Camera.width Der Datentyp wurde von Number in int geändert. get() flash.media.Camera.getCamera() onActivity() flash.events.ActivityEvent. ACTIVITY onStatus() flash.media.Camera dispatches event: status Wurde im neuen Ereignismodell durch ein StatusEvent-Objekt status ersetzt. setMode() flash.media.Camera.setMode() Die Parameter width und height wurden zum Datentyp int geän- dert. setMotionLevel() flash.media.Camera.setMotion- Level() Beide Parameter wurden zum Datentyp int geändert. setQuality() flash.media.Camera.setQuality() Beide Parameter wurden zum Datentyp int geändert. capabilities-Klasse flash.system.Capabilities Bei diesem Klassennamen wurde die Groß-/Kleinschreibung geän- dert. Color-Klasse flash.geom.ColorTransform Die Color-Klasse wurde entfernt, da die gesamte Funktionalität dieser Klasse auch mit der flash.geom.ColorTransform- Klasse erreicht werden kann. Farbwerte lassen sich mit- hilfe des ColorTransform- Klassenkonstruktors oder dessen Eigenschaften direkt zuweisen. ColorTransform-Objekte können dann der Eigenschaft color- Transform eines Transform- Objekts zugewiesen werden, die wiederum der Eigenschaft transform einer DisplayObject- Instanz zugewiesen werden kann. Color flash.geom.ColorTransform. ColorTransform() Entfernt.Sie können Farbwerte mithilfe des ColorTransform()- Konstruktors zuweisen. getRGB() flash.geom.ColorTransform. color Auf den RGB-Farbwert kann mithil- fe der Accessor-Eigenschaft co- lor der ColorTransform-Klasse zugegriffen werden.
  • 95.
    K A PI T E L 382 ActionScript 2.0 ActionScript 3.0 Kommentare getTransform() Entfernt Farbwerte können mithilfe des ColorTransform()- Klassenkonstruktors oder dessen Eigenschaften direkt zugewiesen werden. setRGB() flash.geom.ColorTransform. color Der RGB-Farbwert kann mithilfe der Accessor-Eigenschaft color der ColorTransform-Klasse ein- gerichtet werden. setTransform() Entfernt Farbwerte können mithilfe des ColorTransform()- Klassenkonstruktors oder dessen Eigenschaften direkt zugewiesen werden. ContextMenu-Klasse flash.ui.ContextMenu Die ContextMenu-Klasse ist jetzt Teil des flash.ui-Pakets. builtInItems flash.ui.ContextMenu.built- InItems customItems flash.ui.ContextMenu.custom- Items ContextMenu flash.ui.ContextMenu. ContextMenu() copy() flash.ui.ContextMenu.clone() hideBuiltInItems() flash.ui.ContextMenu.hideBuilt- InItems() onSelect() flash.ui.ContextMenu dispat- ches event: menuSelect Anstatt die Ereignisprozedur on- Select() aufzurufen,löst diese ActionScript 3.0-Klasse ein menu- Select-Ereignis aus. ContextMenuItem-Klasse flash.ui.ContextMenuItem Die ContextMenuItem-Klasse ist jetzt Teil des flash.ui-Pakets. caption flash.ui.ContextMenuItem.cap- tion enabled flash.ui.ContextMenuItem.en- abled separatorBefore flash.ui.ContextMenuItem.sepa- ratorBefore visible flash.ui.ContextMenuItem.vi- sible ContextMenuItem flash.ui.ContextMenuItem. ContextMenuItem() copy() flash.ui.ContextMenuItem.clo- ne() onSelect() flash.ui.ContextMenuItem dis- patches event: menuItemSelect Anstatt die Ereignisprozedur on- Select() aufzurufen,löst diese ActionScript 3.0-Klasse ein menu- Select-Ereignis aus. ConvolutionFilter- Klasse clone() flash.filters. ConvolutionFilter.clone() Gibt jetzt ein BitmapFilter- Objekt zurück.
  • 96.
    B A SI S W I S S E N 83 ActionScript 2.0 ActionScript 3.0 Kommentare Date-Klasse Date ActionScript 3.0 umfasst ein neu- es Set von Read-Accessoren für alle Methoden,die mit getxxx() beginnen.Beispielsweise geben Date.getDate() und Date.date in ActionScript 3.0 den gleichen Wert zurück. getUTCFullYear() Date.getUTCFullYear() Keine Änderung. getYear() Date.getFullYear() Diese Methode wurde entfernt,da sie nicht zum ECMAScript gehört. Verwenden Sie stattdessen Date. getFullYear(). setFullYear() Date.setFullYear() Keine Änderung DisplacementMapFilter- Klasse flash.filters. DisplacementMapFilter Der Datentyp verschiedener Parameter wurde von Number in uint geändert. color flash.filters. DisplacementMapFilter.color Der Datentyp dieses Parameters lautet jetzt uint. componentX flash.filters. DisplacementMapFilter.compo- nentX Der Datentyp dieses Parameters lautet jetzt uint. componentY flash.filters. DisplacementMapFilter.compo- nentY Der Datentyp dieses Parameters lautet jetzt uint. DisplacementMapFilter flash.filters. DisplacementMapFilter. DisplacementMapFilter() Der Datentyp der Parameter com- ponentX,componentY und color wurde in uint geändert. clone() flash.filters. DisplacementMapFilter.clone() Gibt jetzt ein BitmapFilter- Objekt zurück. DropShadowFilter-Klasse flash.filters.DropShadowFilter color flash.filters. DropShadowFilter.color Der Datentyp dieses Parameters wurde von Number in uint geän- dert. quality flash.filters. DropShadowFilter.quality Der Datentyp dieses Parameters wurde von Number in uint geän- dert. DropShadowFilter flash.filters. DropShadowFilter. DropShadowFilter() Alle Parameter weisen jetzt ei- nen Standardwert auf.Einige Parametertypen wurden geändert. clone() flash.filters. DropShadowFilter.clone() Gibt jetzt ein BitmapFilter- Objekt anstelle eines Drop- ShadowFilter-Objekts zurück. Error-Klasse Error Zur Unterstützung beim Debugging wurde eine neue getStackTrace()-Methode hinzugefügt. ExternalInterface- Klasse flash.external. ExternalInterface Für zwei Methoden dieser Klasse wurden die Parameter geändert.
  • 97.
    K A PI T E L 384 ActionScript 2.0 ActionScript 3.0 Kommentare addCallback() flash.external. ExternalInterface.addCall- back() Die ActionScript 3.0-Version dieser Methode akzeptiert keinen in- stance-Parameter.Der method- Parameter wurde durch einen closure-Parameter ersetzt,der einen Verweis auf eine Funktion, eine Klassenmethode oder eine Methode einer bestimmten Klasseninstanz enthalten kann. Darüber hinaus kann der aufrufen- de Code aus Sicherheitsgründen nicht auf den Verweis closure zugreifen.In diesem Fall wird der Ausnahmefehler SecurityError erzeugt. call() flash.external. ExternalInterface.call() Wenn ein Problem auftritt,erzeugt die ActionScript 3.0-Version dieser Methode eine Fehlermeldung oder den Ausnahmefehler SecurityError und gibt darüber hinaus null zurück. FileReference-Klasse flash.net.FileReference Die ActionScript 3.0-Version dieser Klasse übernimmt die Methoden addEventListener() und removeEventListener() von der EventDispatcher-Klasse. Die Ereignisverarbeitungsfunk- tionen werden durch ausgelöste Ereignisse ersetzt. postData flash.net.URLRequest.data ActionScript 2.0 in Flash Player 9 wurde die postData-Eigenschaft hinzugefügt,um POST-Daten mit dem Datei-Upload oder -Download zu senden.In ActionScript 3.0 verwenden Sie die Eigenschaft data der URLRequest- Klasse,um entweder POST- oder GET-Daten zu senden.Weitere Informationen finden Sie unter flash.net.URLRequest.data in diesem Referenzhandbuch. size flash.net.FileReference.size Gibt den Datentyp uint anstelle von Number zurück. addListener() flash.events.EventDispatcher. addEventListener() Im neuen Ereignismodell ist eine klassenspezifische addLis- tener()-Methode nicht mehr erforderlich,da die Klasse die addEventListener()-Methode von der EventDispatcher-Klasse übernimmt.
  • 98.
    B A SI S W I S S E N 85 ActionScript 2.0 ActionScript 3.0 Kommentare browse() flash.net.FileReference.brow- se() Gibt in ActionScript 2.0 beim Auftreten eines Fehlers fal- se zurück.In ActionScript 3.0 wird der Ausnahmefehler IllegalOperationError oder ArgumentError erzeugt.Dennoch gibt die Methode noch immer false zurück,wenn die Parameter ungültig sind,das Dialogfeld zum Suchen nach Dateien nicht öffnet oder eine weitere Browser-Sitzung ausgeführt wird.Darüber hinaus wurde der typelist-Parameter geändert.In ActionScript 2.0 kön- nen Sie die browse()-Methode an ein Array mit Zeichenfolgen über- geben,um einen Dateifilter anzu- geben.In ActionScript 3.0 überge- ben Sie ein Array von Filtern. download() flash.net.FileReference.down- load() Gibt beim Auftreten eines Fehlers Ausnahmefehler anstelle von false aus.Der Datentyp des ers- ten Parameters wurde geändert.In ActionScript 2.0 ist der erste von Ihnen an download() übergebene Parameter eine Zeichenfolge.In ActionScript 3.0 übergeben Sie ein URLRequest-Objekt. removeListener() flash.events.EventDispatcher. removeEventListener() Im neuen Ereignismodell ist eine klassenspezifische removeLis- tener()-Methode nicht mehr erforderlich,da die Klasse die re- moveEventListener()-Methode von der EventDispatcher-Klasse übernimmt.
  • 99.
    K A PI T E L 386 ActionScript 2.0 ActionScript 3.0 Kommentare upload() flash.net.FileReference.up- load() Es wurden verschiedene Änderungen vorgenommen: Der Datentyp des ersten Parameters wurde geändert.In ActionScript 2.0 ist der erste von Ihnen an upload() übergebene Parameter eine Zeichenfolge.In ActionScript 3.0 übergeben Sie ein URLRequest-Objekt. In ActionScript 3.0 gibt es einen neuen zweiten Parameter,up- loadDataFieldName,bei dem es sich um einen Feldnamen handelt, der den Dateidaten in der POST- Operation des Upload-Vorgangs voransteht. In ActionScript 3.0 gibt es einen neuen dritten Parameter,test- Upload,mit dem Sie steuern können,ob Flash Player einen Test- Upload durchführt,bevor die Datei hochgeladen wird. Wenn ein Fehler auftritt,erzeugt browse() Ausnahmefehler- meldungen anstelle von false. onCancel flash.net.FileReference dis- patches event: cancel Diese Klasse ruft in ActionScript 3.0 nicht mehr die Ereignisprozedur onCancel() auf,sondern löst ein Ereignis mit der Bezeichnung cancel aus. onComplete flash.net.FileReference dis- patches event: complete Diese Klasse ruft in ActionScript 3.0 nicht mehr die Ereignisprozedur onComplete() auf,sondern löst ein Ereignis mit der Bezeichnung complete aus. onHTTPError flash.net.FileReference dis- patches event: httpStatus Diese Klasse ruft in ActionScript 3.0 nicht mehr die Ereignisprozedur onHTTPError() auf,sondern löst ein Ereignis mit der Bezeichnung httpStatus aus. onIOError flash.net.FileReference dis- patches event: ioError Diese Klasse ruft in ActionScript 3.0 nicht mehr die Ereignisprozedur onIOError() auf,sondern löst ein Ereignis mit der Bezeichnung ioError aus. onOpen flash.net.FileReference dis- patches event: open Diese Klasse ruft in ActionScript 3.0 nicht mehr die Ereignisprozedur onOpen() auf,sondern löst ein Ereignis mit der Bezeichnung open aus.
  • 100.
    B A SI S W I S S E N 87 ActionScript 2.0 ActionScript 3.0 Kommentare onProgress flash.net.FileReference dis- patches event: progress Diese Klasse ruft in ActionScript 3.0 nicht mehr die Ereignisprozedur onProgress() auf,sondern löst ein Ereignis mit der Bezeichnung progress aus. onSecurityError flash.net.FileReference dis- patches event: securityError Diese Klasse ruft in ActionScript 3.0 nicht mehr die Ereignisprozedur onSecurityError() auf,son- dern löst ein Ereignis mit der Bezeichnung securityError aus. onSelect flash.net.FileReference dis- patches event: select Diese Klasse ruft in ActionScript 3.0 nicht mehr die Ereignisprozedur onSelect() auf,sondern löst ein Ereignis mit der Bezeichnung select aus. onUploadCompleteData flash.net.FileReference dis- patches event: complete Diese Klasse ruft in ActionScript 3.0 nicht mehr die Ereignisprozedur onUploadCompleteData() auf, sondern löst ein Ereignis mit der Bezeichnung uploadComplete- Data aus. FileReferenceList- Klasse flash.net.FileReferenceList Diese ActionScript 3.0-Klasse übernimmt die Methoden ad- dEventListener() und remo- veEventListener() von der EventDispatcher-Klasse.Anstelle der Ereignisprozeduren onCan- cel() und onSelect() verwen- det diese ActionScript 3.0-Klasse die Ereignisse cancel und select. addListener() flash.events.EventDispatcher. addEventListener() Im neuen Ereignismodell ist eine klassenspezifische addLis- tener()-Methode nicht mehr erforderlich,da die Klasse die addEventListener()-Methode von der EventDispatcher-Klasse übernimmt. browse() flash.net.FileReferenceList. browse() Diese Methode gibt in ActionScript 3.0 beim Auftreten eines Fehlers nicht false zurück,sondern erzeugt den Ausnahmefehler IllegalOperationError. Darüber hinaus wurde der type- list-Parameter geändert.In ActionScript 2.0 können Sie die browse()-Methode an ein Array mit Zeichenfolgen übergeben,um einen Dateifilter anzugeben.In ActionScript 3.0 übergeben Sie ein Array von Filtern.
  • 101.
    K A PI T E L 388 ActionScript 2.0 ActionScript 3.0 Kommentare removeListener() flash.events.EventDispatcher. removeEventListener() Im neuen Ereignismodell ist eine klassenspezifische removeLis- tener()-Methode nicht mehr erforderlich,da die Klasse die re- moveEventListener()-Methode von der EventDispatcher-Klasse übernimmt. onCancel flash.net.FileReferenceList dispatches event: cancel Diese Klasse ruft in ActionScript 3.0 nicht mehr die Ereignisprozedur onCancel() auf,sondern löst ein Ereignis mit der Bezeichnung cancel aus. onSelect flash.net.FileReferenceList dispatches event: select Diese Klasse ruft in ActionScript 3.0 nicht mehr die Ereignisprozedur onSelect() auf,sondern löst ein Ereignis mit der Bezeichnung select aus. GlowFilter-Klasse flash.filters.GlowFilter Der Datentyp mehrerer Parameter wurde von Number zu uint ge- ändert. color flash.filters.GlowFilter.color Der Datentyp dieser Eigenschaft wurde von Number zu uint ge- ändert. quality flash.filters.GlowFilter.qua- lity Der Datentyp dieser Eigenschaft wurde von Number zu uint ge- ändert. GlowFilter flash.filters.GlowFilter. GlowFilter() Die Parameter color und qua- lity weisen jetzt die Datentypen uint und int anstelle von Number auf.Allen Parametern ist jetzt ein Standardwert zugewiesen. clone() flash.filters.GlowFilter. clone() Gibt ein BitmapFilter-Objekt an- stelle eines GlowFilter-Objekts zurück. GradientBevelFilter- Klasse flash.filters. GradientBevelFilter quality flash.filters. GradientBevelFilter.quality Der Datentyp dieser Eigenschaft wurde von Number in int geän- dert. clone() flash.filters. GradientBevelFilter.clone() Gibt ein BitmapFilter- Objekt anstelle eines GradientBevelFilter-Objekts zurück. GradientGlowFilter- Klasse flash.filters. GradientGlowFilter quality flash.filters. GradientGlowFilter.quality Der Datentyp dieser Eigenschaft wurde von Number zu int geän- dert. GradientGlowFilter flash.filters. GradientGlowFilter. GradientGlowFilter() Allen Parametern sind jetzt Standardwerte zugewiesen und der Datentyp des quality- Parameters wurde von Number zu int geändert.
  • 102.
    B A SI S W I S S E N 89 ActionScript 2.0 ActionScript 3.0 Kommentare clone() flash.filters. GradientGlowFilter.clone() Gibt ein BitmapFilter-Objekt an- stelle eines GradientGlowFilter- Objekts zurück. IME-Klasse flash.system.IME Diese Klasse wurde in das flash. system-Paket verschoben. ALPHANUMERIC_FULL flash.system. IMEConversionMode. ALPHANUMERIC_FULL ALPHANUMERIC_HALF flash.system. IMEConversionMode. ALPHANUMERIC_HALF CHINESE flash.system. IMEConversionMode.CHINESE JAPANESE_HIRAGANA flash.system. IMEConversionMode.JAPANESE_ HIRAGANA JAPANESE_KATAKANA_FULL flash.system. IMEConversionMode.JAPANESE_ KATAKANA_FULL JAPANESE_KATAKANA_HALF flash.system. IMEConversionMode.JAPANESE_ KATAKANA_HALF KOREAN flash.system. IMEConversionMode.KOREAN UNKNOWN flash.system. IMEConversionMode.UNKNOWN addListener() flash.events.EventDispatcher. addEventListener() Im neuen Ereignismodell ist eine klassenspezifische addLis- tener()-Methode nicht mehr erforderlich,da die Klasse die addEventListener()-Methode von der EventDispatcher-Klasse übernimmt. getConversionMode() flash.system.IME.conversion- Mode Wurde in eine Accessor- Eigenschaft geändert. getEnabled() flash.system.IME.enabled Wurde in eine Accessor- Eigenschaft geändert. removeListener() flash.events.EventDispatcher. removeEventListener() Im neuen Ereignismodell ist eine klassenspezifische removeLis- tener()-Methode nicht mehr erforderlich,da die Klasse die re- moveEventListener()-Methode von der EventDispatcher-Klasse übernimmt. setConversionMode() flash.system.IME.conversion- Mode Wurde in eine Accessor- Eigenschaft geändert. setEnabled() flash.system.IME.enabled Wurde in eine Accessor- Eigenschaft geändert. onIMEComposition flash.system.IME dispatches event: imeComposition Diese Klasse ruft in ActionScript 3.0 nicht mehr die Ereignisprozedur onIMEComposition() auf,son- dern löst ein Ereignis mit der Bezeichnung imeComposition aus.
  • 103.
    K A PI T E L 390 ActionScript 2.0 ActionScript 3.0 Kommentare Key-Klasse flash.ui.Keyboard Diese Klasse hat in ActionScript 3.0 einen neuen Namen,damit sie anderen zur Keyboard-Klasse gehörenden Klassen entspricht, wie z.B.KeyboardEvent. BACKSPACE flash.ui.Keyboard.BACKSPACE Wird in ActionScript 3.0 als eine Konstante deklariert.Der Datentyp wurde in uint geändert. CAPSLOCK flash.ui.Keyboard.CAPS_LOCK Wird in ActionScript 3.0 als eine Konstante deklariert.Ein Unterstrich wurde hinzugefügt und der Datentyp wurde in uint geändert. CONTROL flash.ui.Keyboard.CONTROL Wird in ActionScript 3.0 als eine Konstante deklariert.Der Datentyp wurde in uint geändert. DELETEKEY flash.ui.Keyboard.DELETE Der Name wurde in ActionScript 3.0 zu DELETE geändert.Das Objekt wird als eine Konstante deklariert und der Datentyp wurde in uint geändert. DOWN flash.ui.Keyboard.DOWN Wird in ActionScript 3.0 als eine Konstante deklariert.Der Datentyp wurde in uint geändert. END flash.ui.Keyboard.END Wird in ActionScript 3.0 als eine Konstante deklariert.Der Datentyp wurde in uint geändert. ENTER flash.ui.Keyboard.ENTER Wird in ActionScript 3.0 als eine Konstante deklariert.Der Datentyp wurde in uint geändert. ESCAPE flash.ui.Keyboard.ESCAPE Wird in ActionScript 3.0 als eine Konstante deklariert.Der Datentyp wurde in uint geändert. HOME flash.ui.Keyboard.HOME Wird in ActionScript 3.0 als eine Konstante deklariert.Der Datentyp wurde in uint geändert. INSERT flash.ui.Keyboard.INSERT Wird in ActionScript 3.0 als eine Konstante deklariert.Der Datentyp wurde in uint geändert. LEFT flash.ui.Keyboard.LEFT Wird in ActionScript 3.0 als eine Konstante deklariert.Der Datentyp wurde in uint geändert. _listeners flash.events.EventDispatcher. willTrigger() Kein direktes Äquivalent.Die willTrigger()-Methode meldet Ihnen zwar,ob Listener registriert sind,jedoch nicht wie viele. PGDN flash.ui.Keyboard.PAGE_DOWN Der Name wurde in ActionScript 3.0 in PAGE_DOWN geändert.Das Objekt wird als eine Konstante deklariert und der Datentyp wurde in uint geändert.
  • 104.
    B A SI S W I S S E N 91 ActionScript 2.0 ActionScript 3.0 Kommentare PGUP flash.ui.Keyboard.PAGE_UP Der Name wurde in ActionScript 3.0 in PAGE_UP geändert.Das Objekt wird als eine Konstante deklariert und der Datentyp wurde in uint geändert. RIGHT flash.ui.Keyboard.RIGHT Wird in ActionScript 3.0 als eine Konstante deklariert.Der Datentyp wurde in uint geändert. SHIFT flash.ui.Keyboard.SHIFT Wird in ActionScript 3.0 als eine Konstante deklariert.Der Datentyp wurde in uint geändert. SPACE flash.ui.Keyboard.SPACE Wird in ActionScript 3.0 als eine Konstante deklariert.Der Datentyp wurde in uint geändert. TAB flash.ui.Keyboard.TAB Wird in ActionScript 3.0 als eine Konstante deklariert.Der Datentyp wurde in uint geändert. UP flash.ui.Keyboard.UP Wird in ActionScript 3.0 als eine Konstante deklariert.Der Datentyp wurde in uint geändert. addListener() flash.events.EventDispatcher. addEventListener() In ActionScript 3.0 ist eine klas- senspezifische addListener()- Methode nicht mehr erforderlich, da alle Anzeigeobjekte die add- EventListener()-Methode von der EventDispatcher-Klasse übernehmen. getAscii() flash.events.KeyboardEvent. charCode getCode() flash.events.KeyboardEvent. keyCode isAccessible() flash.ui.Keyboard.isAccessib- le() isDown() Entfernt Aus Sicherheitsgründen entfernt isToggled() Entfernt Aus Sicherheitsgründen entfernt removeListener() flash.events.EventDispatcher. removeEventListener() In ActionScript 3.0 ist eine klassen- spezifische removeListener()- Methode nicht mehr erforderlich, daalleAnzeigeobjektedieremove- EventListener()-Methode von der EventDispatcher-Klasse übernehmen. onKeyDown flash.display. InteractiveObject dispatches event: keyDown In ActionScript 3.0 löst die InteractiveObject-Klasse das KeyboardEvent-Objekt keyDown aus,anstatt die onKeyDown- Ereignisprozedur aufzurufen. onKeyUp flash.display. InteractiveObject dispatches event: keyUp In ActionScript 3.0 löst die InteractiveObject-Klasse das KeyboardEvent-Objekt keyUp aus,anstatt die onKeyUp- Ereignisprozedur aufzurufen.
  • 105.
    K A PI T E L 392 ActionScript 2.0 ActionScript 3.0 Kommentare LoadVars-Klasse flash.net.URLLoader Die LoadVars-Klassenfunktionen wurden durch die Klassen URLLoader,URLRequest, URLStream,und URLVariables ersetzt. contentType flash.net.URLRequest.conten- tType loaded Entfernt Es gibt keine entsprechende. LoadVars flash.net.URLLoader. URLLoader() addRequestHeader() flash.net.URLRequestHeader decode() flash.net.URLVariables.de- code() getBytesLoaded() flash.net.URLLoader.bytesLoa- ded Die Klasse wurde in URLLoader geändert,von einem Funktionen- zu einem Eigenschaften-Accessor geändert und der Name wurde von getBytesLoaded zu by- tesLoaded geändert. getBytesTotal() flash.net.URLLoader.bytesTotal Die Klasse wurde in URLLoader geändert,von einem Funktionen- zu einem Eigenschaften-Accessor geändert und der Name wurde von getBytesTotal zu bytes- Total geändert. load() flash.net.URLLoader.load() onData() flash.net.URLLoader dispatches event: complete Siehe URLLoader-Klasse.Nach Abschluss des Download- Vorgangs,aber noch vor dem Parsen der Daten wird ein comple- te-Ereignis ausgelöst. onHTTPStatus() flash.net.URLLoader dispatches event: httpStatus In ActionScript 3.0 löst die URLLoader-Klasse das HTTP- StatusEvent-Objekt httpStatus aus,anstatt die onHTTPStatus- Ereignisprozedur aufzurufen. onLoad() flash.net.URLLoader dispatches event: complete Siehe URLLoader-Klasse.Nach Abschluss des Download- Vorgangs wird ein complete- Ereignis ausgelöst. send() flash.net.sendToURL() sendAndLoad() flash.net.sendToURL() Die sendToURL()-Methode sen- det eine URL-Anforderung an den Server,ignoriert aber die Antwort. Zum Empfangen der Antwort verwenden Sie flash.net.send- ToURL(). toString() Entfernt Diese Methode ist in ActionScript 3.0 nicht mehr erforderlich. LocalConnection-Klasse flash.net.LocalConnection Diese Klasse wurde in das flash. net-Paket verschoben. LocalConnection flash.net.LocalConnection. LocalConnection()
  • 106.
    B A SI S W I S S E N 93 ActionScript 2.0 ActionScript 3.0 Kommentare allowDomain() flash.net.LocalConnection. allowDomain() Wurde in ActionScript 3.0 zu einer regulären Methode geändert und ist jetzt keine Ereignisprozedur mehr.Der Parameter wurde ge- ändert und verwendet jetzt das Format ...(rest).Der Rückgabewert wurde in void geändert. allowInsecureDomain() flash.net.LocalConnection. allowInsecureDomain() Wurde in ActionScript 3.0 zu einer regulären Methode geändert und ist jetzt keine Ereignisprozedur mehr.Der Parameter wurde ge- ändert und verwendet jetzt das Format ...(rest).Der Rückgabewert wurde in void geändert. close() flash.net.LocalConnection. close() connect() flash.net.LocalConnection. connect() domain() flash.net.LocalConnection. domain Zu einem Eigenschaften-Accessor geändert onStatus() flash.net.LocalConnection dis- patches event: status Im neuen Ereignismodell wurden die Rückruffunktionen durch Ereignisobjekte ersetzt. send() flash.net.LocalConnection. send() Der dritte Parameter wurde ge- ändert und verwendet jetzt das Parameterformat ...(rest).Der Rückgabetyp wurde in void ge- ändert. Microphone-Klasse flash.media.Microphone Diese Klasse wurde in das flash. media-Paket verschoben. index flash.media.Microphone.index Der Datentyp wurde in uint ge- ändert. rate flash.media.Microphone.rate Der Datentyp wurde in uint ge- ändert. silenceTimeOut flash.media.Microphone. silenceTimeout Die Groß-/Kleinschreibung wur- de in„Timeout“ geändert.Der Datentyp wurde in int geändert. get() flash.media.Microphone.getMi- crophone() Der Name wurde von get() zu getMicrophone() geändert.Der Datentyp des Parameters wurde in uint geändert. onActivity() flash.media.Microphone dispat- ches event: activity Diese Klasse ruft in ActionScript 3.0 nicht mehr die Ereignisprozedur onActivity auf,sondern löst ein Ereignis mit der Bezeichnung activity aus. onStatus() flash.media.Microphone dispat- ches event: status Diese Klasse ruft in ActionScript 3.0 nicht mehr die Ereignisprozedur onStatus auf,sondern löst ein Ereignis mit der Bezeichnung status aus.
  • 107.
    K A PI T E L 394 ActionScript 2.0 ActionScript 3.0 Kommentare setGain() flash.media.Microphone.gain Die gain-Eigenschaft und die setGain()-Methode wurden zu einem get/set-Eigenschaften- Accessor mit der Bezeichnung gain zusammengefasst.Der Datentyp wurde in uint geändert. setRate() flash.media.Microphone.rate Die rate-Eigenschaft und die setRate()-Methode wurden zu einem get/set-Eigenschaften- Accessor mit der Bezeichnung rate zusammengefasst.Der Datentyp wurde in uint geändert. setSilenceLevel() flash.media.Microphone.set- SilenceLevel() Der Datentyp des timeOut- Parameters wurde in int geändert. Die Groß-/Kleinschreibung des timeOut-Parameter wurde in timeout geändert. setUseEchoSuppressi- on() flash.media.Microphone.setU- seEchoSuppression() Mouse-Klasse flash.ui.Mouse addListener() flash.events.EventDispatcher. addEventListener() Im neuen ActionScript 3.0- Ereignismodell ist eine klassenspe- zifische addListener()-Methode nicht mehr erforderlich,da alle Anzeigeobjekte die addEvent- Listener()-Methode von der EventDispatcher-Klasse über- nehmen. hide() flash.ui.Mouse.hide() Gibt jetzt void zurück. removeListener() flash.events.EventDispatcher. removeEventListener() Im neuen ActionScript 3.0- Ereignismodell ist eine klassen- spezifische removeListener()- Methode nicht mehr erforderlich, da alle Anzeigeobjekte die remo- veEventListener()-Methode von der EventDispatcher-Klasse übernehmen. show() flash.ui.Mouse.show() Gibt jetzt void zurück. onMouseDown flash.display. InteractiveObject dispatches event: mouseDown Wurde im neuen Ereignismodell durch ein mouseDown-Ereignis ersetzt. onMouseMove flash.display. InteractiveObject dispatches event: mouseMove Wurde im neuen Ereignismodell durch ein mouseMove-Ereignis ersetzt. onMouseUp flash.display. InteractiveObject dispatches event: mouseUp Wurde im neuen Ereignismodell durch ein mouseUp-Ereignis er- setzt. onMouseWheel flash.display. InteractiveObject dispatches event: mouseWheel Wurde im neuen Ereignismodell durch ein mouseWheel-Ereignis ersetzt.
  • 108.
    B A SI S W I S S E N 95 ActionScript 2.0 ActionScript 3.0 Kommentare MovieClip-Klasse flash.display.MovieClip Viele MovieClip-Methoden wurden in ActionScript 3.0 in andere Klassen verschoben.Alle Ereignisprozeduren wurden im neuen Ereignismodell durch Ereignisobjekte ersetzt. _alpha flash.display.DisplayObject. alpha In die DisplayObject-Klasse verschoben.Der Unterstrich am Anfang des Namens wurde ent- fernt. blendMode flash.display.DisplayObject. blendMode cacheAsBitmap flash.display.DisplayObject. cacheAsBitmap _currentframe flash.display.MovieClip.cur- rentFrame Der Unterstrich am Anfang des Namens wurde entfernt. _droptarget flash.display.Sprite.dropTar- get In die Sprite-Klasse verschoben. Der Unterstrich am Anfang des Namens wurde entfernt und die Groß-/Kleinschreibung wurde geändert. filters flash.display.DisplayObject. filters focusEnabled Entfernt In ActionScript 3.0 sind alle inter- aktiven Objekte Fokus-aktiviert. Diese Eigenschaft ist daher nicht mehr erforderlich. _focusrect flash.display. InteractiveObject.focusRect In die InteractiveObject-Klasse verschoben.Der Unterstrich am Anfang des Namens wur- de entfernt und die Groß-/ Kleinschreibung wurde geändert. _framesloaded flash.display.MovieClip.fra- mesLoaded Der Unterstrich am Anfang des Namens wurde entfernt und die Groß-/Kleinschreibung wurde geändert. _height flash.display.DisplayObject. height In die DisplayObject-Klasse verschoben.Der Unterstrich am Anfang des Namens wurde ent- fernt. _highquality Entfernt Siehe Stage.quality hitArea flash.display.Sprite.hitArea In die Sprite-Klasse verschoben _lockroot Entfernt In ActionScript 3.0 wird der Stamm eines Anzeigeobjekts automatisch festgelegt.Die Eigenschaft _lock- root ist damit praktisch immer aktiviert.Siehe flash.display. DisplayObject.root. menu Entfernt Siehe InteractiveObject. contextMenu _name flash.display.DisplayObject. name In die DisplayObject-Klasse verschoben.Der Unterstrich am Anfang des Namens wurde ent- fernt.
  • 109.
    K A PI T E L 396 ActionScript 2.0 ActionScript 3.0 Kommentare opaqueBackground flash.display.DisplayObject. opaqueBackground _parent flash.display.DisplayObject. parent In die DisplayObject-Klasse verschoben.Der Unterstrich am Anfang des Namens wurde ent- fernt. _quality flash.display.Stage.quality _rotation flash.display.DisplayObject. rotation In die DisplayObject-Klasse verschoben.Der Unterstrich am Anfang des Namens wurde ent- fernt. scale9Grid flash.display.DisplayObject. scale9Grid scrollRect flash.display.DisplayObject. scrollRect In den Datentyp Rectangle ge- ändert _soundbuftime flash.media.SoundMixer.buffer- Time In die SoundMixer-Klasse verschoben,die zur globalen Soundsteuerung verwendet wird. Infolge der Umbenennung ist keine Abkürzung mehr vorhanden und der Unterstrich am Anfang des Namens wurde entfernt. tabChildren flash.display. DisplayObjectContainer. tabChildren tabEnabled flash.display. InteractiveObject.tabEnabled tabIndex flash.display. InteractiveObject.tabIndex _target Entfernt ActionScript 3.0 identifiziert Anzeigeobjekte direkt,daher ist die Identifizierung eines Anzeigeobjekts über dessen Pfad nicht mehr notwendig. _totalframes flash.display.MovieClip.total- Frames Die Groß-/Kleinschreibung wurde geändert.Der Unterstrich am Anfang des Namens wurde ent- fernt. trackAsMenu flash.display.MovieClip. trackAsMenu transform flash.display.DisplayObject. transform _url flash.display.Loader.content- LoaderInfo useHandCursor flash.display.Sprite.useHand- Cursor _visible flash.display.DisplayObject. visible In die DisplayObject-Klasse verschoben.Der Unterstrich am Anfang des Namens wurde ent- fernt. _width flash.display.DisplayObject. width In die DisplayObject-Klasse verschoben.Der Unterstrich am Anfang des Namens wurde ent- fernt.
  • 110.
    B A SI S W I S S E N 97 ActionScript 2.0 ActionScript 3.0 Kommentare _x flash.display.DisplayObject.x In die DisplayObject-Klasse verschoben.Der Unterstrich am Anfang des Namens wurde ent- fernt. _xmouse flash.display.DisplayObject. mouseX In die DisplayObject-Klasse verschoben.Der Name wurde in mouseX geändert und der Unterstrich am Anfang des Namens wurde entfernt. _xscale flash.display.DisplayObject. scaleX In die DisplayObject-Klasse verschoben.Der Name wurde in scaleX geändert und der Unterstrich am Anfang des Namens wurde entfernt. _y flash.display.DisplayObject.y In die DisplayObject-Klasse verschoben.Der Unterstrich am Anfang des Namens wurde ent- fernt. _ymouse flash.display.DisplayObject. mouseY In die DisplayObject-Klasse verschoben.Der Name wurde in mouseY geändert und der Unterstrich am Anfang des Namens wurde entfernt. _yscale flash.display.DisplayObject. scaleY In die DisplayObject-Klasse verschoben.Der Name wurde in scaleY geändert und der Unterstrich am Anfang des Namens wurde entfernt. attachAudio() Entfernt Wenn es sich bei der Audioquelle um ein Microphone-Objekt handelt,verwenden Sie NetStream.attachAudio() oder Microphone.setLoopBack(). Handelt es sich bei der Audio- quelle um eine FLV-Datei, verwenden Sie Video.attach- NetStream() und ein NetStream- Objekt. attachBitmap() Entfernt In ActionScript 3.0 verwenden Sie addChild(),um untergeordnete Anzeigeobjekte hinzuzufügen. attachMovie() Entfernt In ActionScript 3.0 verwenden Sie addChild(),um untergeordnete Anzeigeobjekte hinzuzufügen. beginBitmapFill() flash.display.Graphics.begin- BitmapFill() beginFill() flash.display.Graphics.begin- Fill() In die Graphics-Klasse verscho- ben.Der Datentyp des ersten Parameters wurde in uint geän- dert. beginGradientFill() flash.display.Graphics.begin- GradientFill() clear() flash.display.Graphics.clear()
  • 111.
    K A PI T E L 398 ActionScript 2.0 ActionScript 3.0 Kommentare createEmptyMovieClip() Entfernt In ActionScript 3.0 verwenden Sie zum Erstellen von MovieClips den new-Operator. createTextField() Entfernt In ActionScript 3.0 verwenden Sie zum Erstellen von Textfeldern den new-Operator. curveTo() flash.display.Graphics.curve- To() duplicateMovieClip() Entfernt In ActionScript 3.0 verwenden Sie zum Erstellen einer neuen Instanz den new-Operator. endFill() flash.display.Graphics.end- Fill() getBounds() flash.display.DisplayObject. getBounds() getBytesLoaded() flash.net.URLLoader.bytesLoa- ded In die URLLoader-Klasse verscho- ben.Der Datentyp wurde von Number in int geändert. getBytesTotal() flash.net.URLLoader.bytesTotal In die URLLoader-Klasse verscho- ben.Der Datentyp wurde von Number in int geändert. getDepth() flash.display. DisplayObjectContainer.get- ChildIndex() ActionScript 3.0 bietet direkten Zugriff auf die Anzeigeliste,daher wird die Tiefe auf andere Weise bearbeitet. getInstanceAtDepth() flash.display. DisplayObjectContainer.get- ChildAt() ActionScript 3.0 bietet direkten Zugriff auf die Anzeigeliste,daher wird die Tiefe auf andere Weise bearbeitet. getNextHighestDepth() flash.display. DisplayObjectContainer.add- Child() Kein direktes Äquivalent,aber die addChild()-Methode fügt nach allen untergeordneten Objekten der DisplayObjectContainer- Instanz ein weiteres untergeord- netes Objekt hinzu.Daher ist eine Methode,mit der die nächste verfügbare Tiefe ermittelt wird, nicht mehr erforderlich. getRect() flash.display.DisplayObject. getRect() getSWFVersion() flash.display.LoaderInfo.swf- Version In die LoaderInfo-Klasse verscho- ben.Der Datentyp wurde in uint geändert. getTextSnapshot() flash.display. DisplayObjectContainer.textS- napshot getURL() flash.net.navigateToURL() Wurde durch die Methoden flash.net.navigateToURL() und flash.net.sentToURL() ersetzt.Siehe auch URLLoader- Klasse. globalToLocal() flash.display.DisplayObject. globalToLocal()
  • 112.
    B A SI S W I S S E N 99 ActionScript 2.0 ActionScript 3.0 Kommentare gotoAndStop() flash.display.MovieClip.goto- AndStop() hitTest() flash.display.DisplayObject. hitTestObject() lineGradientStyle() flash.display.Graphics.line- GradientStyle() lineStyle() flash.display.Graphics.li- neStyle() lineTo() flash.display.Graphics.line- To() loadMovie() flash.display.Loader.load() Siehe Loader-Klasse loadVariables() flash.net.URLLoader Entfernt; siehe URLLoader-Klasse localToGlobal() flash.display.DisplayObject. localToGlobal() moveTo() flash.display.Graphics.move- To() nextFrame() flash.display.MovieClip.next- Frame() onData() flash.display.LoaderInfo dis- patches event: complete Wurde im neuen Ereignismodell durch ein complete-Ereignis ersetzt,das nach Abschluss des Download-Vorgangs,aber noch vor dem Parsen der Daten ausge- löst wird. onDragOut() flash.display. InteractiveObject dispatches event: mouseOut Wurde im neuen Ereignismodell durch ein mouseOut-Ereignis ersetzt. onDragOver() flash.display. InteractiveObject dispatches event: mouseOver Wurde im neuen Ereignismodell durch ein mouseOver-Ereignis ersetzt. onEnterFrame() flash.display.DisplayObject dispatches event: enterFrame Wurde im neuen Ereignismodell durch ein enterFrame-Ereignis ersetzt. onKeyDown() flash.display. InteractiveObject dispatches event: keyDown Wurde im neuen Ereignismodell durch ein keyDown-Ereignis er- setzt. onKeyUp() flash.display. InteractiveObject dispatches event: keyUp Wurde im neuen Ereignismodell durch ein keyUp-Ereignis ersetzt. onKillFocus() flash.display. InteractiveObject dispatches event: focusOut Wurde im neuen Ereignismodell durch ein focusOut-Ereignis ersetzt. onLoad() flash.display.LoaderInfo dis- patches event: complete Siehe auch URLLoader-Klasse. Nach Abschluss des Download- Vorgangs wird ein complete- Ereignis ausgelöst. onMouseDown() flash.display. InteractiveObject dispatches event: mouseDown Wurde im neuen Ereignismodell durch ein mouseDown-Ereignis ersetzt. onMouseMove() flash.display. InteractiveObject dispatches event: mouseMove Wurde im neuen Ereignismodell durch ein mouseMove-Ereignis ersetzt.
  • 113.
    K A PI T E L 3100 ActionScript 2.0 ActionScript 3.0 Kommentare onMouseUp() flash.display. InteractiveObject dispatches event: mouseUp Wurde im neuen Ereignismodell durch ein mouseUp-Ereignis er- setzt. onPress() flash.display. InteractiveObject dispatches event: mouseDown Wurde im neuen Ereignismodell durch ein mouseDown-Ereignis ersetzt. onRelease() flash.display. InteractiveObject dispatches event: mouseUp Wurde im neuen Ereignismodell durch ein mouseUp-Ereignis er- setzt. onReleaseOutside() flash.display. InteractiveObject dispatches event: mouseUp Wurde im neuen Ereignismodell durch ein mouseUp-Ereignis er- setzt. onRollOut() flash.display. InteractiveObject dispatches event: mouseOut Wurde im neuen Ereignismodell durch ein mouseOut-Ereignis ersetzt. onRollOver() flash.display. InteractiveObject dispatches event: mouseOver Wurde im neuen Ereignismodell durch ein mouseOver-Ereignis ersetzt. onSetFocus() flash.display. InteractiveObject dispatches event: focusIn Wurde im neuen Ereignismodell durch ein focusIn-Ereignis er- setzt. onUnload() flash.display.LoaderInfo dis- patches event: unload Wurde im neuen Ereignismodell durch ein unload-Ereignis ersetzt. play() flash.display.MovieClip.play() prevFrame() flash.display.MovieClip.prev- Frame() removeMovieClip() flash.display. DisplayObjectContainer.remove- Child() Entfernt.Rufen Sie die remove- Child()-Methode des übergeord- neten Anzeigeobjekt-Containers auf,der den MovieClip enthält. setMask() flash.display.DisplayObject. mask startDrag() flash.display.Sprite.start- Drag() stop() flash.display.MovieClip.stop() stopDrag() flash.display.Sprite. stopDrag() swapDepths() Entfernt In ActionScript 3.0 erreichen Sie eine ähnliche Funktionalität mithilfe der Methoden der DisplayObjectContainer-Klasse, z.B.addChildAt(),setChild- Index(),swapChildren() und swapChildrenAt(). unloadMovie() flash.display.Loader.unload() MovieClipLoader-Klasse flash.display.Loader Wurde durch die flash.dis- play.Loader-Klasse ersetzt. MovieClipLoader flash.display.Loader.Loader()
  • 114.
    B A SI S W I S S E N 101 ActionScript 2.0 ActionScript 3.0 Kommentare addListener() flash.events.EventDispatcher. addEventListener() Im neuen Ereignismodell ist eine klassenspezifische addLis- tener()-Methode nicht mehr erforderlich,da die Klasse die addEventListener()-Methode von der EventDispatcher-Klasse übernimmt. getProgress() flash.display.LoaderInfo dis- patches event: progress Wurde im neuen Ereignismodell durch ein progress-Ereignis ersetzt.Ereignisobjekte des Typs progress enthalten Eigenschaften mit den Bezeichnungen by- tesLoaded und bytesTotal. loadClip() flash.display.Loader.load() Wurde durch die load()-Methode der flash.display.Loader- Klasse ersetzt. removeListener() flash.events.EventDispatcher. removeEventListener() Im neuen Ereignismodell ist eine klassenspezifische removeLis- tener()-Methode nicht mehr erforderlich,da die Klasse die re- moveEventListener()-Methode von der EventDispatcher-Klasse übernimmt. unloadClip() flash.display.Loader.unload() Wurde durch die unload()- Methode der flash.display. Loader-Klasse ersetzt. onLoadComplete flash.display.LoaderInfo dis- patches event: complete Wurde im neuen Ereignismodell durch ein complete-Ereignis ersetzt. onLoadError flash.display.LoaderInfo dis- patches event: ioError Wurde im neuen Ereignismodell durch ein ioError-Ereignis er- setzt. onLoadInit flash.display.LoaderInfo dis- patches event: init Wurde im neuen Ereignismodell durch ein init-Ereignis ersetzt. onLoadProgress flash.display.LoaderInfo dis- patches event: progress Wurde im neuen Ereignismodell durch ein progress-Ereignis ersetzt. onLoadStart flash.display.LoaderInfo dis- patches event: open Wurde im neuen Ereignismodell durch ein open-Ereignis ersetzt. NetConnection-Klasse flash.net.NetConnection Diese Klasse wurde in das flash. net-Paket verschoben. NetConnection flash.net.NetConnection. NetConnection() connect() flash.net.NetConnection.con- nect() In der ActionScript 3.0-Version wurde ein ...(rest)-Parameter hin- zugefügt. NetStream-Klasse flash.net.NetStream Diese Klasse wurde in das flash. net-Paket verschoben. bytesLoaded flash.net.NetStream.bytesLoa- ded Der Datentyp wurde in uint geändert. bytesTotal flash.net.NetStream.bytesTotal Der Datentyp wurde in uint geändert.
  • 115.
    K A PI T E L 3102 ActionScript 2.0 ActionScript 3.0 Kommentare currentFps flash.net.NetStream.currentFPS In ActionScript 3.0 steht FPS in Großbuchstaben. onStatus() flash.net.NetStream dispatches event: netStatus Wurde im neuen Ereignismodell durch ein netStatus-Ereignis ersetzt. pause() flash.net.NetStream.pause() In ActionScript 3.0 nimmt die pau- se-Methode keinen Parameter auf. Es stehen zwei neue Methoden zur Verfügung,mit denen die gleiche Funktionalität erreicht wird:resu- me() und togglePause(). play() flash.net.NetStream.play() Die Parameter name,start,len und reset sind nicht mehr gültig, stattdessen wird ...arguments verwendet. setBufferTime() flash.net.NetStream.bufferTime Wurde in ActionScript 3.0 zu einer Accessor-Eigenschaft mit Lese- und Schreibzugriff geändert. Number-Klasse Number Number Number.Number() In ActionScript 3.0 haben der Number()-Konstruktor und die globale Funktion Number() die gleichen Auswirkungen.Darüber hinaus gibt es keinen Unterschied zwischen einem Number-Objekt und einem literalen Zahlenwert. Object-Klasse Object __proto__ Entfernt In ActionScript 3.0 ist eine direkte Bearbeitung der Prototypkette nicht zulässig.Zum Erstellen einer Unterklasse verwenden Sie die extends-Anweisung in der Unterklassendeklaration. Um weitere Informationen über die Vererbungsstruktur und den Datentyp eines Objekts zu er- halten,verwenden Sie die neue Reflection-API flash.utils. describeType(). __resolve flash.utils.Proxy Verwenden Sie die neue Proxy- Klasse,um eine ähnliche Funktion umzusetzen. addProperty() Entfernt In ActionScript 3.0 können Accessor-Eigenschaften mithilfe der Schlüsselwörter get und set direkt erstellt werden.
  • 116.
    B A SI S W I S S E N 103 ActionScript 2.0 ActionScript 3.0 Kommentare registerClass() Entfernt In ActionScript 3.0 sind alle Klassen standardmäßig registriert. Wenn Sie ein Objekt mithilfe von AMF verschlüsseln,wird die Objektklasse während des Verschlüsselungsvorgangs nicht beibehalten,es sei denn,Sie verwenden die Funktion flash. utils.registerClassAlias(). unwatch() Entfernt ActionScript 3.0 hat keine Watchpoints,daher ist die Methode unwatch() überholt. watch() Entfernt Verwenden Sie die Accessor- Eigenschaften (get/set- Funktionen) oder die flash. utils.Proxy-Klasse,um eine ähn- liche Funktionalität zu erreichen. PrintJob-Klasse flash.printing.PrintJob orientation flash.printing.PrintJob.orien- tation Diese Eigenschaft hat jetzt den Wert der PrintJobOrientation- Klasse. pageHeight flash.printing.PrintJob.page- Height Der Datentyp wurde in int geändert. pageWidth flash.printing.PrintJob.page- Width Der Datentyp wurde in int geändert. paperHeight flash.printing.PrintJob.paper- Height Der Datentyp wurde in int geändert. paperWidth flash.printing.PrintJob.paper- Width Der Datentyp wurde in int geändert. PrintJob flash.printing.PrintJob. PrintJob() addPage() flash.printing.PrintJob.add- Page() In ActionScript 3.0 wurden die Datentypen der Parameter geändert:Der erste Parameter target weist jetzt den Datentyp Sprite auf; der zweite Parameter printArea den Datentyp Rectangle; der dritte Parameter options hat den neuen Datentyp PrintJobOptions und der vierte Parameter frameNum hat den Datentyp int. send() flash.printing.PrintJob.send() start() flash.printing.PrintJob. start() Rectangle-Klasse containsRectangle() flash.geom.Rectangle.contains- Rect() Aus Konsistenzgründen um- benannt security-Klasse flash.system.Security Diese Klasse wurde in das flash. system-Paket verschoben. Selection-Klasse Entfernt Die Methoden dieser Klasse wur- den in andere Klassen verschoben.
  • 117.
    K A PI T E L 3104 ActionScript 2.0 ActionScript 3.0 Kommentare addListener() flash.events.EventDispatcher. addEventListener() Im neuen Ereignismodell ist eine klassenspezifische addListe- ner()-Methode nicht mehr erfor- derlich,da alle Anzeigeobjekte die addEventListener()-Methode von der EventDispatcher-Klasse übernehmen. getBeginIndex() flash.text.TextField.selec- tionBeginIndex Wurde von einer Methode in eine Accessor-Eigenschaft geändert. Der Name wurde in selection- BeginIndex geändert. getCaretIndex() flash.text.TextField.caret- Index Wurde von einer Methode in eine Accessor-Eigenschaft geändert. Der Name wurde in caretIndex geändert. getEndIndex() flash.text.TextField.selectio- nEndIndex Wurde von einer Methode in eine Accessor-Eigenschaft geändert. Der Name wurde in selection- EndIndex geändert. getFocus() flash.display.Stage.focus Wurde von einer Methode in einen Eigenschaften-Accessor geändert. Der Name wurde in focus ge- ändert.In ActionScript 2.0 hatte der Rückgabewert den Datentyp String,in ActionScript 3.0 hin- gegen weist die Eigenschaft den Datentyp InteractiveObject auf. removeListener() flash.events.EventDispatcher. removeEventListener() Im neuen Ereignismodell ist eine klassenspezifische removeListe- ner()-Methode nicht mehr erfor- derlich,da Anzeigeobjekte die re- moveEventListener()-Methode von der EventDispatcher-Klasse übernehmen. setFocus() flash.display.Stage.focus Wurde von einer Methode zu einer Accessor-Eigenschaft geändert. Der Name wurde in focus ge- ändert.In ActionScript 2.0 hatte der Rückgabewert den Datentyp String,in ActionScript 3.0 hin- gegen weist die Eigenschaft den Datentyp InteractiveObject auf. setSelection() flash.text.TextField.setSelec- tion() Der Datentyp beider Parameter wurde von Number in uint geän- dert. onSetFocus flash.display. InteractiveObject dispatches event: focusIn Wurde im neuen Ereignismodell durch ein focusIn-Ereignis er- setzt. SharedObject-Klasse flash.net.SharedObject Diese Klasse wurde in das flash. net-Paket verschoben.
  • 118.
    B A SI S W I S S E N 105 ActionScript 2.0 ActionScript 3.0 Kommentare flush() flash.net.SharedObject.flush() Diese Methode gibt jetzt kei- nen booleschen Wert mehr zurück.Wenn die Ausgabe fehl- schlägt,gibt Flash Player einen Ausnahmefehler aus.Wenn die Ausgabe erfolgreich ist oder eine Benutzerreaktion aussteht,gibt der Flash Player die Zeichenfolge „flushed“ oder„pending“ zu- rück.Darüber hinaus wurde der Datentyp des minDiskSpace- Parameters in int geändert. getSize() flash.net.SharedObject.size Wurde in eine Accessor- Eigenschaft geändert.Der Datentyp wurde in uint geändert. onStatus() flash.net.SharedObject dispat- ches event: netStatus Wurde im neuen Ereignismodell durch ein netStatus-Ereignis ersetzt. Sound-Klasse flash.media.Sound Diese Klasse wurde in das flash. media-Paket verschoben. checkPolicyFile flash.media.SoundChannel. stop() Wurde durch die flash.media. SoundChannel.stop()-Methode ersetzt. duration flash.media.Sound.length id3 flash.media.Sound.id3 Der Datentyp wurde von Object in ID3Info geändert.ID3Info ist eine neue Klasse,die die ID3- Eigenschaften enthält.Darüber hinaus wurde die Schreibweise der songname-Eigenschaft in song- Name geändert. position flash.media.SoundChannel.po- sition In die SoundChannel-Klasse ver- schoben attachSound() Entfernt Erstellen Sie eine Instanz eines Sound-Objektes. getBytesLoaded() flash.media.Sound.bytesLoaded Wurde in eine Accessor- Eigenschaft geändert.Der Datentyp wurde in uint geändert. getBytesTotal() flash.media.Sound.bytesTotal Wurde in einen Eigenschaften- Accessor geändert.Der Datentyp wurde in uint geändert. getPan() flash.media.SoundTransform.pan Wurde in eine Accessor- Eigenschaft geändert und in die SoundTransform-Klasse verscho- ben. getTransform() flash.media.SoundMixer.sound- Transform Wurde in eine Accessor- Eigenschaft geändert. Der Datentyp wurde in SoundTransform geändert. getVolume() flash.media.SoundTransform. volume Richten Sie die flashmedia. SoundTransform.volu- me-Eigenschaft ein,um die Soundlautstärke zu steuern.
  • 119.
    K A PI T E L 3106 ActionScript 2.0 ActionScript 3.0 Kommentare loadSound() flash.media.Sound.load() Der erste Parameter wurde von einem einfachen URL-String in ein URLRequest-Objekt geändert. Der zweite Parameter wurde von einem booleschen Wert,mit dem angegeben wird,ob der Sound so bald wie möglich wiedergegeben wird,in ein SoundLoaderContext- Objekt geändert. onID3() flash.media.Sound dispatches event: id3 Wurde im neuen Ereignismodell durch ein id3-Ereignis ersetzt. onLoad() flash.media.Sound dispatches event: complete Wurde im neuen Ereignismodell durch ein complete-Ereignis ersetzt. onSoundComplete() flash.media.SoundChannel dis- patches event: soundComplete Wurde im neuen Ereignismodell durch ein soundComplete-Ereignis ersetzt. setPan() flash.media.SoundTransform.pan Wurde in eine Accessor- Eigenschaft geändert und in die SoundTransform-Klasse verscho- ben. setTransform() flash.media.SoundMixer.sound- Transform Wurde in eine Accessor- Eigenschaft geändert. Der Datentyp wurde in SoundTransform geändert. setVolume() flash.media.SoundChannel Entfernt.Verwenden Sie flash. media.SoundChannel.left- Peak und flash.media. SoundChannel.rightPeak zur Überwachung der Amplitude eines Soundkanals. start() flash.media.Sound.play() Der Datentyp des loops- Parameters wurde von Number in int geändert.Ein dritter Parameter,sndTransform,wurde hinzugefügt,um die anfängliche Soundtransformation festzulegen, die vom Soundkanal verwendet werden soll. stop() flash.media.SoundChannel. stop() Stage-Klasse flash.display.Stage Diese Klasse wurde in das flash. display-Paket verschoben. align flash.display.Stage.align height flash.display.Stage.stage- Height Der Name wurde von height in stageHeight geändert,so- dass jetzt kein Konflikt mehr mit der flash.display. DisplayObject.height- Eigenschaft auftreten kann. scaleMode flash.display.Stage.scaleMode showMenu flash.display.Stage.showDe- faultContextMenu Der Name wurde geändert,um das angezeigte Menü besser widerzu- spiegeln.
  • 120.
    B A SI S W I S S E N 107 ActionScript 2.0 ActionScript 3.0 Kommentare width flash.display.Stage.stageWidth Der Name wurde von width in stageWidth geändert,sodass jetzt kein Konflikt mehr mit der flash. display.DisplayObject.width- Eigenschaft auftreten kann. addListener() flash.events.EventDispatcher. addEventListener() Im neuen Ereignismodell ist eine klassenspezifische addLis- tener()-Methode nicht mehr erforderlich,da die Klasse die addEventListener()-Methode von der EventDispatcher-Klasse übernimmt. removeListener() flash.events.EventDispatcher. removeEventListener() Im neuen Ereignismodell ist eine klassenspezifische removeLis- tener()-Methode nicht mehr erforderlich,da die Klasse die re- moveEventListener()-Methode von der EventDispatcher-Klasse übernimmt. onResize flash.display.Stage dispatches event: resize Wurde im neuen Ereignismodell durch ein resize-Ereignis ersetzt. String-Klasse String Unterstützung für reguläre Ausdrücke mit drei neuen Methoden hinzugefügt:match(), replace() und search(). concat() String.concat() Der Parameter wurde geändert und verwendet jetzt das Format ...(rest). StyleSheet-Klasse flash.text.StyleSheet Diese Klasse wurde in das flash. text-Paket verschoben.Die Mitglieder load() und onLoad() wurden entfernt und einige pri- vate Funktionen und Variablen wurden hinzugefügt. StyleSheet flash.text.StyleSheet. StyleSheet() clear() flash.text.StyleSheet.clear() getStyle() flash.text.StyleSheet.get- Style() Der Name des Parameters wurde in n geändert. getStyleNames() flash.text.StyleSheet.style- Names Wurde in eine Accessor- Eigenschaft geändert. load() flash.net.URLLoader.load() Verwenden Sie die neuen Klassen URLLoader und URLRequest zum Laden von URLs. onLoad() flash.net.URLLoader dispatches event: complete Wurde im neuen Ereignismodell durch ein complete-Ereignis ersetzt. parseCSS() flash.text.StyleSheet.par- seCSS() Gibt in ActionScript 3.0 void anstelle eines booleschen Werts zurück. setStyle() flash.text.StyleSheet.set- Style() Der Name des Parameters wurde in n und der Stil in s geändert. transform() flash.text.StyleSheet.trans- form()
  • 121.
    K A PI T E L 3108 ActionScript 2.0 ActionScript 3.0 Kommentare System-Klasse flash.system.System exactSettings flash.system.Security.exact- Settings In die flash.System.Security- Klasse verschoben useCodepage flash.system.System.useCode- Page In ActionScript 3.0 ist der Buchstabe„P“ in useCodePage ein Großbuchstabe. onStatus() Entfernt Diese Ereignisprozedur ist im ActionScript 3.0-Ereignismodell überholt. setClipboard() flash.system.System.setClip- board() showSettings() flash.system.Security.showSet- tings() TextField-Klasse flash.text.TextField Diese Klasse wurde in das flash. text-Paket verschoben. _alpha flash.display.DisplayObject. alpha Diese Eigenschaft wird jetzt von der DisplayObject-Klasse übernommen.Der Unterstrich am Anfang wurde entfernt. antiAliasType flash.text.TextField.antiAli- asType autoSize flash.text.TextField.autoSize background flash.text.TextField.back- ground backgroundColor flash.text.TextField.back- groundColor border flash.text.TextField.border borderColor flash.text.TextField.border- Color In ActionScript 3.0 wird ein uint- Wert anstelle eines Number-Werts zurückgegeben. bottomScroll flash.text.TextField.bottom- ScrollV In ActionScript 3.0 wird ein uint- Wert anstelle eines Number-Werts zurückgegeben. condenseWhite flash.text.TextField.conden- seWhite embedFonts flash.text.TextField.embed- Fonts filters flash.display.DisplayObject. filters gridFitType flash.text.TextField.gridFit- Type _height flash.display.DisplayObject. height Diese Eigenschaft wird jetzt von der DisplayObject-Klasse übernommen.Der Unterstrich am Anfang wurde entfernt. _highquality flash.display.Stage.quality Entfernt. hscroll flash.text.TextField.scrollH Der Datentyp wurde von Number zu uint geändert.Der Name wurde von hscroll zu scrollH geändert.
  • 122.
    B A SI S W I S S E N 109 ActionScript 2.0 ActionScript 3.0 Kommentare html flash.text.TextField.htmlText Entfernt.In ActionScript 3.0 werden alle Textfelder als HTML- Textfelder behandelt.Verwenden Sie die TextField.htmlText- Eigenschaft,um HTML-Text einzu- richten. htmlText flash.text.TextField.htmlText length flash.text.TextField.length Der Datentyp wurde von Number in uint geändert. maxChars flash.text.TextField.maxChars Der Datentyp wurde von Number in uint geändert. maxhscroll flash.text.TextField.maxSc- rollH Der Datentyp wurde von Number in uint geändert. maxscroll flash.text.TextField.maxSc- rollV Der Datentyp wurde von Number in uint geändert.Im neuen Namen ist das S ein Großbuchstabe und der Buchstabe V wurde hinzugefügt,um das verti- kale Scrollen zu verdeutlichen. menu flash.display. InteractiveObject.contextMenu Diese Eigenschaft wird jetzt von der InteractiveObject-Klasse übernommen. mouseWheelEnabled flash.text.TextField.mouse- WheelEnabled multiline flash.text.TextField.multiline _name flash.display.DisplayObject. name Diese Eigenschaft wird jetzt von der DisplayObject-Klasse übernommen.Der Unterstrich am Anfang wurde entfernt. _parent flash.display.DisplayObject. parent Diese Eigenschaft wird jetzt von der DisplayObject-Klasse übernommen.Der Unterstrich am Anfang wurde entfernt.Der Datentyp wurde von MovieClip in DisplayObjectContainer geändert. password flash.text.TextField.displayA- sPassword Diese Eigenschaft wurde aus Konsistenzgründen umbenannt. _quality flash.display.Stage.quality In die Stage-Klasse verschoben restrict flash.text.TextField.restrict _rotation flash.display.DisplayObject. rotation Diese Eigenschaft wird jetzt von der DisplayObject-Klasse übernommen.Der Unterstrich am Anfang wurde entfernt. scroll flash.text.TextField.scrollV Der Datentyp wurde von Number in uint geändert und der Name von scroll in scrollV. selectable flash.text.TextField.selec- table sharpness flash.text.TextField.sharpness
  • 123.
    K A PI T E L 3110 ActionScript 2.0 ActionScript 3.0 Kommentare _soundbuftime flash.media.SoundMixer.buffer- Time Eigenschaften und Methoden für die globale Soundsteuerung in einer SWF-Datei befinden sich jetzt in der flash.media.SoundMixer- Klasse. styleSheet flash.text.TextField.styleS- heet tabEnabled flash.display. InteractiveObject.tabEnabled Diese Eigenschaft wird jetzt von der InteractiveObject-Klasse übernommen. tabIndex flash.display. InteractiveObject.tabIndex Diese Eigenschaft wird jetzt von der InteractiveObject-Klasse übernommen. _target Entfernt ActionScript 3.0 identifiziert Anzeigeobjekte direkt,daher ist die Identifizierung des Pfads nicht mehr notwendig. text flash.text.TextField.text textColor flash.text.TextField.textColor Der Datentyp wurde von Number in uint geändert. textHeight flash.text.TextField.text- Height textWidth flash.text.TextField.textWidth thickness flash.text.TextField.thickness type flash.text.TextField.type _url flash.display.LoaderInfo.url variable Entfernt Diese Variable ist in ActionScript 3.0 nicht mehr erforderlich. _visible flash.display.DisplayObject. visible Diese Eigenschaft wird jetzt von der DisplayObject-Klasse übernommen.Der Unterstrich am Anfang wurde entfernt. _width flash.display.DisplayObject. width Diese Eigenschaft wird jetzt von der DisplayObject-Klasse übernommen.Der Unterstrich am Anfang wurde entfernt. wordWrap flash.text.TextField.wordWrap _x flash.display.DisplayObject.x Diese Eigenschaft wird jetzt von der DisplayObject-Klasse übernommen.Der Unterstrich am Anfang wurde entfernt. _xmouse flash.display.DisplayObject. mouseX Diese Eigenschaft wird jetzt von der DisplayObject-Klasse übernommen.Der Unterstrich am Anfang wurde entfernt. _xscale flash.display.DisplayObject. scaleX Diese Eigenschaft wird jetzt von der DisplayObject-Klasse übernommen.Der Unterstrich am Anfang wurde entfernt. _y flash.display.DisplayObject.y Diese Eigenschaft wird jetzt von der DisplayObject-Klasse übernommen.Der Unterstrich am Anfang wurde entfernt.
  • 124.
    B A SI S W I S S E N 111 ActionScript 2.0 ActionScript 3.0 Kommentare _ymouse flash.display.DisplayObject. mouseY Diese Eigenschaft wird jetzt von der DisplayObject-Klasse übernommen.Der Unterstrich am Anfang wurde entfernt. _yscale flash.display.DisplayObject. scaleY Diese Eigenschaft wird jetzt von der DisplayObject-Klasse übernommen.Der Unterstrich am Anfang wurde entfernt. addListener() flash.events.EventDispatcher. addEventListener() Im neuen Ereignismodell ist eine klassenspezifische addLis- tener()-Methode nicht mehr erforderlich,da die Klasse die addEventListener()-Methode von der EventDispatcher-Klasse übernimmt. getDepth() flash.display. DisplayObjectContainer Entfernt.Verwenden Sie jetzt die Methoden der DisplayObjectContainer-Klasse, um die Textfeldtiefe festzustellen. getFontList() flash.text.Font.enumerate- Fonts() Entfernt.Verwenden Sie Font. enumerateFonts() und setzen Sie den Parameter enumerate- DeviceFonts auf true. getNewTextFormat() flash.text.TextField.default- TextFormat Der Name wurde von getNew- TextFormat in defaultTextFor- mat geändert.Von einer Methode in eine Accessor-Eigenschaft geändert. getTextFormat() flash.text.TextField.getText- Format() Der Datentyp beider Parameter wurde von Number in uint geän- dert. onChanged() flash.text.TextField dispat- ches event: change Wurde im neuen Ereignismodell durch ein change-Ereignis ersetzt. onKillFocus() flash.display. InteractiveObject dispatches event: focusOut Wurde im neuen Ereignismodell durch ein focusOut-Ereignis ersetzt. onScroller() flash.text.TextField dispat- ches event: scroll Wurde im neuen Ereignismodell durch ein scroll-Ereignis ersetzt. onSetFocus() flash.display. InteractiveObject dispatches event: focusIn Wurde im neuen Ereignismodell durch ein focusIn-Ereignis er- setzt. removeListener() flash.events.EventDispatcher. removeEventListener() Im neuen Ereignismodell ist eine klassenspezifische removeLis- tener()-Methode nicht mehr erforderlich,da die Klasse die re- moveEventListener()-Methode von der EventDispatcher-Klasse übernimmt. removeTextField() flash.display. DisplayObjectContainer.remove- Child() Entfernt.Rufen Sie die remove- Child()-Methode des übergeord- neten Anzeigeobjekt-Containers auf,der das Textfeld enthält.
  • 125.
    K A PI T E L 3112 ActionScript 2.0 ActionScript 3.0 Kommentare replaceSel() flash.text.TextField.replaceS- electedText() Der Name wurde von replaces- el() in replaceSelectedText() geändert.Der newText-Parameter wurde durch eine Zeichenfolge ersetzt. replaceText() flash.text.TextField.replace- Text() Der Datentyp der ersten beiden Parameter wurde von Number zu uint geändert. setNewTextFormat() flash.text.TextField.default- TextFormat Der Name wurde von setNew- TextFormat in defaultTextFor- mat geändert.Von einer Methode in eine Accessor-Eigenschaft geändert. setTextFormat() flash.text.TextField.setText- Format() Die Reihenfolge der Parameter wurde geändert.Der Datentyp der Indexparameter wurde von Number in int geändert. TextFormat-Klasse flash.text.TextFormat Diese Klasse wurde in das flash. text-Paket verschoben. align flash.text.TextFormat.align blockIndent flash.text.TextFormat.blockIn- dent Der Datentyp wurde in ActionScript 3.0 in Object ge- ändert,da einer der möglichen Werte null ist.Dieser Wert ist in ActionScript 3.0 kein Mitglied des Datentyps Number. bold flash.text.TextFormat.bold Der Datentyp wurde in ActionScript 3.0 in Object ge- ändert,da einer der möglichen Werte null ist.Dieser Wert ist in ActionScript 3.0 kein Mitglied des Datentyps Boolean. bullet flash.text.TextFormat.bullet Der Datentyp wurde in ActionScript 3.0 in Object ge- ändert,da einer der möglichen Werte null ist.Dieser Wert ist in ActionScript 3.0 kein Mitglied des Datentyps Boolean. color flash.text.TextFormat.color Der Datentyp wurde in ActionScript 3.0 in Object ge- ändert,da einer der möglichen Werte null ist.Dieser Wert ist in ActionScript 3.0 kein Mitglied des Datentyps Number. font flash.text.TextFormat.font indent flash.text.TextFormat.indent Der Datentyp wurde in ActionScript 3.0 in Object ge- ändert,da einer der möglichen Werte null ist.Dieser Wert ist in ActionScript 3.0 kein Mitglied des Datentyps Number.
  • 126.
    B A SI S W I S S E N 113 ActionScript 2.0 ActionScript 3.0 Kommentare italic flash.text.TextFormat.bullet Der Datentyp wurde in ActionScript 3.0 in Object ge- ändert,da einer der möglichen Werte null ist.Dieser Wert ist in ActionScript 3.0 kein Mitglied des Datentyps Boolean. kerning flash.text.TextFormat.kerning Der Datentyp wurde in ActionScript 3.0 in Object ge- ändert,da einer der möglichen Werte null ist.Dieser Wert ist in ActionScript 3.0 kein Mitglied des Datentyps Boolean. leading flash.text.TextFormat.leading Der Datentyp wurde in ActionScript 3.0 in Object ge- ändert,da einer der möglichen Werte null ist.Dieser Wert ist in ActionScript 3.0 kein Mitglied des Datentyps Number. leftMargin flash.text.TextFormat.leftM- argin Der Datentyp wurde in ActionScript 3.0 in Object ge- ändert,da einer der möglichen Werte null ist.Dieser Wert ist in ActionScript 3.0 kein Mitglied des Datentyps Number. letterSpacing flash.text.TextFormat.letter- Spacing Der Datentyp wurde in ActionScript 3.0 in Object ge- ändert,da einer der möglichen Werte null ist.Dieser Wert ist in ActionScript 3.0 kein Mitglied des Datentyps Number. rightMargin flash.text.TextFormat.rightM- argin Der Datentyp wurde in ActionScript 3.0 in Object ge- ändert,da einer der möglichen Werte null ist.Dieser Wert ist in ActionScript 3.0 kein Mitglied des Datentyps Number. size flash.text.TextFormat.size Der Datentyp wurde in ActionScript 3.0 in Object ge- ändert,da einer der möglichen Werte null ist.Dieser Wert ist in ActionScript 3.0 kein Mitglied des Datentyps Number. underline flash.text.TextFormat.under- line Der Datentyp wurde in ActionScript 3.0 in Object ge- ändert,da einer der möglichen Werte null ist.Dieser Wert ist in ActionScript 3.0 kein Mitglied des Datentyps Boolean. url flash.text.TextFormat.url TextFormat flash.text.TextFormat. TextFormat() Die Parameter size,color,bold, italic,underline,url,left- Margin,rightMargin,indent und leading wurden in Objekte umgewandelt.
  • 127.
    K A PI T E L 3114 ActionScript 2.0 ActionScript 3.0 Kommentare getTextExtent() Entfernt Verwenden Sie die Eigenschaften von flash.text.TextField zum Messen eines Felds mit ei- ner Textzeile und flash.text. TextLineMetrics zum Messen des Inhalts innerhalb eines Textfelds. TextRenderer-Klasse flash.text.TextRenderer Der Speicherort wurde geändert. In das flash.text-Paket verscho- ben. maxLevel flash.text.TextRenderer.max- Level In ActionScript 3.0 als uint defi- niert setAdvancedAntialia- singTable() flash.text.TextRenderer.setA- dvancedAntiAliasingTable() Die Parameterwerte fontStyle und colorType können jetzt mit den Konstanten FontStyle und TextColorType eingestellt werden.Der advancedAntiAlia- singTable-Parameter nimmt jetzt ein Array mit mindestens einem CSMSettings-Objekt an. TextSnapshot-Klasse flash.text.TextSnapshot Diese Klasse wurde in das flash.text-Paket verschoben. Verschiedene Parameter wur- den geändert,ebenso einige Methodennamen und einige Rückgabetypen. findText() flash.text.TextSnapshot.find- Text() Der Name des startIndex- Parameters wurde in beginIndex geändert.Der Datentyp des star- tIndex-Parameters wurde von Number zu int geändert. getCount() flash.text.TextSnapshot.char- Count Von einer Methode zu einer Accessor-Eigenschaft geändert. Der Datenrückgabetyp wurde von Number in uint geändert. getSelected() flash.text.TextSnapshot.getSe- lected() Der Datentyp der Parameter wur- de von Number in uint geändert und die Namen wurden von start und end in beginIndex und EndIndex geändert. getSelectedText() flash.text.TextSnapshot.getSe- lectedText() In ActionScript 3.0 hat der Parameter den Standardwert false. getText() flash.text.TextSnapshot.get- Text() Der Datentyp der Parameter start und end wurde von Number in uint geändert und die Namen wurden von start und end in beginIndex und endIndex ge- ändert. getTextRunInfo() flash.text.TextSnapshot.getT- extRunInfo() Der Datentyp der Parameter wur- de von Number in uint geändert.
  • 128.
    B A SI S W I S S E N 115 ActionScript 2.0 ActionScript 3.0 Kommentare hitTestTextNearPos() flash.text.TextSnapshot.hit- TestTextNearPos() Der Name des closeDist- Parameters wurde in maxDistance geändert.Dieser Parameter hat jetzt den Standardwert = 0. setSelectColor() flash.text.TextSnapshot.setSe- lectColor() Der Datentyp des Parameters wurde von Number in uint geän- dert.Der Parameter hat jetzt den Standardwert = 0xFFFF00. setSelected() flash.text.TextSnapshot.setSe- lected() Der Datentyp der Parameter start und end wurde von Number in uint geändert und die Namen wurden von start und end in beginIndex und endIndex ge- ändert. Video-Klasse flash.media.Video Diese Klasse wurde in das flash.media-Paket verscho- ben.Videoobjekte können in ActionScript jetzt dynamisch mit dem Video()-Konstruktor erstellt werden.Hängen Sie einen Videostream mit attachCamera() oder attachNetStream() an das Videoobjekt an. _alpha flash.display.DisplayObject. alpha Diese Eigenschaft wird von der DisplayObject-Klasse übernom- men.Der Unterstrich am Anfang wurde entfernt. deblocking flash.media.Video.deblocking Der Datentyp wurde von Number in int geändert. _height flash.display.DisplayObject. height Diese Eigenschaft wird von der DisplayObject-Klasse übernom- men.Der Unterstrich am Anfang wurde entfernt. height flash.media.Video.videoHeight Der Datentyp wurde von Number in int geändert. _name flash.display.DisplayObject. name Diese Eigenschaft wird von der DisplayObject-Klasse übernom- men.Der Unterstrich am Anfang wurde entfernt. _parent flash.display.DisplayObject. parent Diese Eigenschaft wird von der DisplayObject-Klasse übernom- men.Der Unterstrich am Anfang wurde entfernt. _rotation flash.display.DisplayObject. rotation Diese Eigenschaft wird von der DisplayObject-Klasse übernom- men.Der Unterstrich am Anfang wurde entfernt. smoothing flash.media.Video.smoothing _visible flash.display.DisplayObject. visible Diese Eigenschaft wird von der DisplayObject-Klasse übernom- men.Der Unterstrich am Anfang wurde entfernt.
  • 129.
    K A PI T E L 3116 ActionScript 2.0 ActionScript 3.0 Kommentare _width flash.display.DisplayObject. width Diese Eigenschaft wird von der DisplayObject-Klasse übernom- men.Der Unterstrich am Anfang wurde entfernt. width flash.media.Video.videoWidth Der Datentyp wurde von Number zu int geändert. _x flash.display.DisplayObject.x Diese Eigenschaft wird von der DisplayObject-Klasse übernom- men.Der Unterstrich am Anfang wurde entfernt. _xmouse flash.display.DisplayObject. mouseX Diese Eigenschaft wird von der DisplayObject-Klasse übernom- men.Der Unterstrich am Anfang wurde entfernt. _xscale flash.display.DisplayObject. scaleX Diese Eigenschaft wird von der DisplayObject-Klasse übernom- men.Der Unterstrich am Anfang wurde entfernt. _y flash.display.DisplayObject.y Diese Eigenschaft wird von der DisplayObject-Klasse übernom- men.Der Unterstrich am Anfang wurde entfernt. _ymouse flash.display.DisplayObject. mouseY Diese Eigenschaft wird von der DisplayObject-Klasse übernom- men.Der Unterstrich am Anfang wurde entfernt. _yscale flash.display.DisplayObject. scaleY Diese Eigenschaft wird von der DisplayObject-Klasse übernom- men.Der Unterstrich am Anfang wurde entfernt. attachVideo() flash.media.Video.attachNet- Stream() Verwenden Sie flash.media. Video.attachCamera(),um einen Videostream von einem Kameraobjekt anzugeben. clear() flash.media.Video.clear() XML-Klasse flash.xml.XMLDocument Diese Klasse wurde in das flash. xml-Paket verschoben und der Name in XMLDocument geändert, um einen Konflikt mit der neuen Top-Level XML-Klasse zu vermei- den,die ECMAScript für XML (E4X) implementiert. contentType flash.net.URLRequest.conten- tType docTypeDecl flash.xml.XMLDocument.docType- Decl idMap flash.xml.XMLDocument.idMap ignoreWhite flash.xml.XMLDocument.ignore- White loaded Entfernt Die Funktionen zum Laden einer Datei wurden aus der XMLDocument-Klasse entfernt. Verwenden Sie stattdessen URLLoader.
  • 130.
    B A SI S W I S S E N 117 ActionScript 2.0 ActionScript 3.0 Kommentare status Entfernt Fehler beim Parsen werden jetzt über Ausnahmefehler gemeldet. xmlDecl flash.xml.XMLDocument.xmlDecl XML flash.xml.XMLDocument. XMLDocument() addRequestHeader() flash.net.URLRequest.request- Headers createElement() flash.xml.XMLDocument.create- Element() createTextNode() flash.xml.XMLDocument.create- TextNode() getBytesLoaded() flash.net.URLLoader.bytes- Loaded Die Funktionen zum Laden einer Datei wurden aus der XMLDocument-Klasse entfernt. Verwenden Sie stattdessen URLLoader. getBytesTotal() flash.net.URLLoader.bytesTotal Die Funktionen zum Laden einer Datei wurden aus der XMLDocument-Klasse entfernt. Verwenden Sie stattdessen URLLoader. load() Entfernt Die Funktionen zum Laden einer Datei wurden aus der XMLDocument-Klasse entfernt (in ActionScript 2.0 war dies die XML- Klasse).Verwenden Sie stattdessen URLLoader. onData() flash.net.URLLoader dispatches event: complete Die Funktionen zum Laden einer Datei wurden aus der XMLDocument-Klasse entfernt. Verwenden Sie stattdessen URLLoader.Wurde im neuen Ereig- nismodell durch ein complete- Ereignis ersetzt. onHTTPStatus() flash.net.URLLoader dispatches event: httpStatus Die Funktionen zum Laden einer Datei wurden aus der XMLDocument-Klasse entfernt. Verwenden Sie stattdessen URLLoader.Wurde im neuen Ereignismodell durch ein http- Status-Ereignis ersetzt. onLoad() flash.net.URLLoader dispatches event: complete Die Funktionen zum Laden einer Datei wurden aus der XMLDocument-Klasse entfernt. Verwenden Sie stattdessen URLLoader.Wurde im neuen Ereig- nismodell durch ein complete- Ereignis ersetzt. parseXML() flash.xml.XMLDocument. parseXML()
  • 131.
    K A PI T E L 3118 ActionScript 2.0 ActionScript 3.0 Kommentare send() Entfernt Die Funktionen zum Senden einer Datei wurden aus der XMLDocument-Klasse entfernt (in ActionScript 2.0 war dies die XML- Klasse).Verwenden Sie stattdessen die Funktionen und Klassen im flash.net-Paket. sendAndLoad() Entfernt Die Funktionen zum Senden und Laden einer Datei wurden aus der XMLDocument-Klasse entfernt (in ActionScript 2.0 war dies die XML- Klasse).Verwenden Sie stattdessen URLRequest und URLLoader. XMLNode-Klasse flash.xml.XMLNode Der Speicherort wurde geändert. Diese Klasse wurde in das flash. xml-Paket verschoben. nodeType flash.xml.XMLNode.nodeType Der Datentyp wurde von Number in uint geändert. XMLNode flash.xml.XMLNode.XMLNode() Der Datentyp des type-Parameters wurde von Number in uint geän- dert. XMLSocket-Klasse flash.net.XMLSocket Diese Klasse wurde in das flash. net-Paket verschoben. XMLSocket flash.net.XMLSocket. XMLSocket() Es wurden zwei optionale Parameter zum Festlegen von Host und Port hinzugefügt. connect() flash.net.XMLSocket.connect() Der Datentyp des port-Parameters wurde in int geändert. onClose() flash.net.XMLSocket dispatches event: close Wurde im neuen Ereignismodell durch ein close-Ereignis ersetzt. onConnect() flash.net.XMLSocket dispatches event: connect Wurde im neuen Ereignismodell durch ein connect-Ereignis er- setzt. onData() flash.net.XMLSocket dispatches event: data Wurde im neuen Ereignismodell durch ein data-Ereignis ersetzt. onXML() Entfernt In ActionScript 3.0 wird nur das data-Ereignis ausgelöst,sodass Sie entweder E4X- oder den äl- teren XML-Parser (XMLDocument- Klasse) verwenden können.Die alte Ereignisprozedur onXML wurde nach dem Parsen des XML- Codes aufgerufen.Dies ergibt in ActionScript 3.0 keinen Sinn,weil Sie zum Parsen des XML-Codes jetzt zwischen der XML-Klasse (E4X) und der XMLDocument-Klasse (ältere Version) wählen können. Tabelle 3.1: Migration von ActionScript 2.0 auf ActionScript 3.0 (Quelle: ActionScript-Hilfe von Flash CS3)
  • 132.
    4 AJAX – ASYNCHRONUS JAVASCRIPT ANDXML In diesem Kapitel setzen wir uns mit den Grundlagen von AJAX auseinander und zeigen die Möglichkeiten der „Zusam- menarbeit“ mit Flash auf. Unweigerlich werden wir in diesem Kapitel zu dem Schluss gelangen, dass alle Möglichkeiten von AJAX (Web 2.0) in Flash schon seit langem implementiert sind. Aus diesem Grund müssen wir uns auch mit der Thematik befassen, inwiefern AJAX eine Konkurrenz bzw. Alternative zu Flash darstellt und wo der Einsatz der einen oder der anderen Technologie mehr oder weniger Sinn macht. Klarerweise ist dieses Buch kein AJAX-Buch – aus diesem Grund werden wir uns auch nur mit den Kernthemen von AJAX befas- sen (die im Übrigen gar nicht so umfassend sind) und diese für uns sinnvoll nutzen. Auch möchte ich nicht auf die Entwicklung aller Scripten eingehen, sondern vielmehr diese als „Entwickelt und zum Benutzen bereitgestellt“ vorstellen.
  • 133.
    K A PI T E L 4120 4.1 Was ist AJAX? Der grundlegende Vorteil von AJAX ist, dass auf ein bereits vollständig vom Server zum Client übertragenes Webdokument im Nachhinein und ohne Neuladen des Dokuments weitere Daten vom Server abgefragt werden können. Eine Interaktion mit dem Server ist also ohne Neuladen (Refresh) des Dokuments möglich. AJAX ist im Grunde genommen eine Kombination mehrerer Technologien: XHTML und CSS: Diese beiden Technologien verwenden wir zur Darstellung der Daten auf einer Website – sie bilden bekannterweise unser Gerüst. Dies gilt selbst- verständlich nach wie vor und – wie wir wissen – hierin werden alle unsere Assets wie Texte, Grafiken, SWF-Dateien usw. eingebettet. XML: wird zur Übertragung von Daten zwischen Server und Client verwendet. XMLHttpRequest: stellt die essenziell wichtige Möglichkeit des asynchronen Nach- ladens von Informationen vom Server dar. Erst mithilfe dieser „Technologie“ wird es möglich, auf einer bereits vollständig zum User übertragenen Website weitere Daten vom Server nachzuladen. JavaScript: bildet die Schnittstelle zwischen allen Technologien. Das DOM (Docu- ment Object Model) steht hier als die Möglichkeit, bereits im Webdokument vor- handene Daten nachträglich zu verändern. Das einzig wirklich Neue an AJAX ist der XMLHttpRequest, alles andere ist bekannt. Dies soll jedoch keineswegs bedeuten, dass wir sofort AJAX-Experten sind, wenn wir XHTML-Dokumente mit CSS aufbauen und JavaScript programmieren können. Kei- neswegs! Gerade das Zusammenspiel aller Technologien stellt die eigentliche Schwie- rigkeit dar. Auch müssen wir im Umgang mit dem Document Object Model relativ fit sein. 4.2 Was ist AJAX nicht? AJAX ist in aller Munde und Web 2.0 sowieso. Je mehr „Web 2.0“ eine Website ist, umso trendiger und moderner ist sie. Oder etwa nicht? AJAX ist kein Allheilmittel für alle Probleme und Workarounds, die während der Ent- wicklung einer Website auftreten. Klar – jeder Webdesigner, der etwas auf sich hält, wird versuchen, um die Burg eine AJAX-Anwendung zu programmieren. Ja, AJAX stellt eine Abhilfe für dynamische Anwendungen dar, die während der Darstellung eines einzelnen Webdokuments im Nachhinein noch Daten zusätzlich anzeigen möch- ten (ohne das Dokument neu zu laden). Jedoch darf nicht außer Acht gelassen werden, dass AJAX sinnvoll eingesetzt gehört: Je häufiger die Anfragen an einen Server gestellt werden, umso mehr gerät der Server unter Last. u u u u Nachladen von Daten ohne Refresh Nachladen von Daten ohne Refresh
  • 134.
    A J AX – A S Y N C H R O N U S J AVA S C R I P T A N D X M L 121 Stellen Sie sich folgendes Szenario vor: Auf einer Website werden die Schlagzeilen des Tages (in Österreich haben wir das Beispiel des Österreichischen Rundfunks (ORF) – www.orf.at) dargestellt. Mehrmals am Tag besuche ich die Seite und sehe nach, was sich getan hat (gehen wir mal davon aus, dass ich keinen Newsreader verwende). Nachdem ich einen Proxy-Server in Betrieb habe und somit die Inhalte gecached werden, muss ich die Seite aktualisieren, um zu den neuesten Informationen zu kom- men. Eigentlich würde man meinen, dass dies ein tolles Einsatzgebiet für eine AJAX- Anwendung ist: Statt dass ein User den Refresh-Button klicken muss, lädt sich die Seite in regelmäßigen Abständen (beispielsweise jede Minute) die neuesten Informationen automatisch down und gibt diese aus. Bei einer geschätzten Anzahl von zigtausend Usern der ORF-Seite wäre das eine ungeheure Belastung für den Server: Für diese zigtausend User muss er jede Minute einen Datenbank-Server abfragen, die News zusammenstellen und den (zigtausend) Usern zurückschicken. Der Datentransfer wäre enorm! Ein guter Webdesigner ist deshalb ein solcher, der die zur Verfügung stehenden Technologien sinnvoll und bewusst einsetzt. Es gibt jedoch noch weitere Probleme, die im Zusammenhang mit AJAX auftreten: 1. Der Back- oder Zurück-Button hat bei AJAX-Anwendungen keine Bedeutung mehr: Nachdem der Back-Button dafür bestimmt ist, das zuvor angezeigte Webdokument anzuzeigen, wird dies vom Server neu angefordert. Genau das ist aber das Verfahren, das wir bei AJAX vermeiden (umgehen) wollen: das Neuladen eines Dokuments. In einem AJAX-basierten Dokument werden die neuen/zusätzlichen Inhalte nicht in Form eines neuen (anderen) Webdokuments, sondern im aktuellen Webdokument selbst dargestellt. 2. Keine Unterstützung in älteren Browsern: AJAX in vollem Umfang setzt relativ neue Browser voraus! Konkret heißt das, dass diese Browser zwar mit der asynchronen Datenübertragung keine Probleme haben, jedoch das Document Object Model (DOM) und die zugehörigen JavaScript-Befehle nicht in dem Umfang unterstützen, wie AJAX das für vernünftige Anwendungen benötigt. 3. Thema Barrierefreiheit: AJAX ist beileibe nicht barrierefrei. Nehmen wir den Fall eines sehbehinderten Users: Dieser verwendet zumeist eine Software, die den Quellcode einer Seite liest, diesen interpretiert und akustisch ausgibt. Nun, AJAX verändert im Nachhinein den Inhalt eines Webdokuments, jedoch nicht den Quelltext (dieser ist unveränderlich und liegt so auf, wie er vom Server geliefert wurde). Somit kann ein Quellcode-Interpreter die durch AJAX geänderten Inhalte auch nicht wiedergeben. Setzen Sie AJAX bewusst ein – bedenken Sie insbesondere auch die Serverseite wie oben angesprochen. Was haben Ihre User davon, dass das Webdokument zwar nicht mehr aktualisiert werden muss, jedoch der Server regelmäßig unter Volllast in die Knie geht.
  • 135.
    K A PI T E L 4122 4.3 Der XMLHttpRequest Wie wir bereits aus dem Grundlagenkapitel wissen, erfolgt eine Datenanforderung eines Clients (im Allgemeinen meinen wir hier den User und seinen Browser) an einen Server (Webserver) aus folgenden Gründen: 1. Anfordern eines Webdokuments: Der User sitzt vor seinem Browser und gibt in der Adresszeile eine URL an oder klickt in einer bereits angezeigten Website auf einen Link. 2. Aktualisieren eines (bereits angezeigten) Webdokuments: Der User entscheidet sich für ein Aktualisieren der Site und klickt auf den Refresh-Button. 3. Abschicken eines Formulars: Der User füllt (bewusst oder unbewusst) ein Formular innerhalb eines Webdokuments aus und schickt das Formular (bewusst oder unbewusst) ab. In jedem der drei Fälle entsteht für den User durch die Datenanforderung eine Warte- zeit, die sich wie folgt zusammensetzt – in dieser Zeit kann der User die Website nicht bedienen, sie ist inaktiv: 1. Datenübertragung vom Client zum Server: Die Anforderung des Clients an den Server wird abgeschickt. Dieser Teil der Wartezeit ist relativ gering und hängt wesentlich von der Anbindung des Users ans Internet ab. Im Allgemeinen ist diese Zeitspanne jedoch vernachlässigbar gering. 2. Datenverarbeitung am Server: Die Anforderung des Clients wird am Server verarbeitet.Je nach angeforderten Informationen stellt dies eine mehr oder weniger lange Wartezeit dar – für den Fall, dass beispielsweise Daten aus einer Datenbank gelesen werden und in ein PHP- (oder ähnliches) Dokument geschrieben werden müssen, kann dies durchaus eine Wartezeit von mehreren Sekunden bedeuten. 3. Datenübertragung vom Server zum Client: Die vom Server aufbereiteten Daten (XHTML-basiertes Webdokument) werden zurück an den Client geschickt. An dieser Stelle spielt selbstverständlich die Menge an zu übertragenden Daten sowie die Anbindung des Users an das Internet eine wesentliche Rolle. 4. Aufbau der Site auf Userseite: Je nach Komplexität des Webdokuments kann der Aufbau der Website mehr oder weniger lange dauern. Im Allgemeinen dauert jedoch auch diese Zeitspanne mehrere Sekunden. Die nachfolgende Grafik verdeutlicht die Wartezeiten:
  • 136.
    A J AX – A S Y N C H R O N U S J AVA S C R I P T A N D X M L 123 Mit dem Einsatz von AJAX (im Speziellen: dem XMLHttpRequest) wird sich das Thema „Inaktivität der Website“ grundlegend ändern. Selbstverständlich bleiben die Schritte 1 (Clientanforderung an den Server) und 2 (Serververarbeitung) bestehen, jedoch wird die Site durch die Clientanforderung nicht inaktiv, da die Site nicht wie bisher neu geladen wird, sondern ihr vielmehr nur mehr Daten hinzugefügt wer- den – das angezeigte Webdokument bleibt im Browser bestehen und der User kann somit normal weiterarbeiten. Durch dieses Prinzip verringern sich zusätzlich auch die Wartezeiten auf die nachgeladenen Daten, da einerseits nicht mehr das gesamte Webdokument vom Server zurückgeschickt wird und andererseits nur noch ein Teil des (bestehen gebliebenen) Webdokuments neu aufgebaut werden muss. Dies gilt selbstverständlich nur für den Fall, dass der Webdesigner umdenkt: Anzeigen eines anderen Webdokuments wird ersetzt durch Verändern der Inhalte eines bereits angezeigten Webdokuments. Anzeigen von zusätzlichen Formularfeldern je nach voriger Auswahl durch den User (bei Formularen): Es wird nicht mehr dasselbe Dokument zum Server zurück- geschickt und vom Server mit zusätzlichen Formularfeldern versehen, sondern dem bestehenden Dokument werden neue Formularfelder hinzugefügt. usw. u u u ABBILDUNG 4.1 Durch eine Anfrage des Clients an den Server ent- steht ein nicht unerheblicher Zeitraum, in dem die Website inaktiv ist.
  • 137.
    K A PI T E L 4124 Diese Liste lässt sich noch weiter fortsetzen, doch letzten Endes wäre sie nur eine Auflistung von Möglichkeiten, die nie vollständig sein wird. Ich überlasse es Ihnen, lieber Leser, die Möglichkeiten im Rahmen von XHTML zu erkennen und daraus Ihre Schlüsse zu ziehen. Uns geht es darum, wie AJAX mit Flash arbeiten kann bzw. inwie- weit Flash in Hinblick auf AJAX Gefahr läuft, den Rang abgelaufen zu bekommen. Das Prinzip des „Nachladens“ stellt sich also wie folgt dar – während der gesamten Zeitspanne kann der User ungehindert auf der Website weiterarbeiten: 1. Datenübertragung vom Client zum Server: Die Anforderung des Clients an den Server wird abgeschickt. Dies geschieht im Hintergrund und der User kann weiter auf der Website arbeiten. 2. Datenverarbeitung am Server: Die Anforderung des Clients wird am Server verarbeitet. Da im Allgemeinen nun die Menge an Daten geringer ist als ohne AJAX (jetzt werden nur mehr zusätzliche Daten aufbereitet und nicht mehr das gesamte Webdokument), verringert sich auch die Abarbeitungszeit am Server. 3. Datenübertragung vom Server zum Client: Die vom Server aufbereiteten Daten (XML-basiert) werden zurück an den Client geschickt. An dieser Stelle spielt wie auch zuvor die Menge an zu übertragenden Daten sowie die Anbindung des Users an das Internet eine wesentliche Rolle, jedoch gilt auch hier: Man kann davon ausgehen, dass diese Zeitspanne geringer ist als ohne AJAX, da wiederum nur weniger Daten zum Client zurückgeschickt werden. 4. Anzeigen der Daten auf Userseite: Die nachgeladenen Daten werden durch JavaScript mithilfe des DOM auf der Website dargestellt. Als Webdesigner muss man an dieser Stelle davon ausgehen, dass dem User ein etwa- iges Nachladen gar nicht bewusst ist – Usability kommt ins Spiel! Sollten Sie davon ausgehen müssen, dass der Nachladevorgang einige Sekunden in Anspruch nimmt, so teilen Sie dies dem User mit. Dem User ist nicht klar, ob die betrachtete Webanwen- dung AJAX-basiert ist (und er somit zu jeder Zeit damit rechnen muss, dass Daten nachgeladen werden) oder nicht. AJAX & UsabilityAJAX & Usability
  • 138.
    A J AX – A S Y N C H R O N U S J AVA S C R I P T A N D X M L 125 4.3.1 Details zum XMLHttpRequest-Objekt Nun ist es an der Zeit, das XMLHttpRequest-Objekt aus Programmiersicht einmal genauer zu betrachten. Wie jedes Objekt in der Objektorientierten Programmierung (OOP) besteht es aus Methoden und Eigenschaften: Methode Beschreibung abort() Eine aktuelle mit (send()) abgeschickte Serveranfrage wird gestoppt. getAllResponseHeaders() Auslesen der vom Server zurückgesandten Header-Felder in Form eines String getResponseHeader("Feldname") Funktioniert wie die Methode getAllResponseHeaders(), nur dass hier über einen Parameter Feldname ein spezielles Feld abgefragt wird.Der Rückgabewert ist vom Typ String. open("Methode", "URL" [,asyncMo- de[, "Username"[, "Passwort"]]]) Diese Methode wird verwendet,um eine Verbindung zu einem Webserver zu öffnen.(Beachte:Eine konkrete Anfrage an den Server wird zu diesem Zeitpunkt noch nicht gestellt – dies geschieht erst mit der Methode send()).Auf die einzelnen Parameter gehen wir weiter unten genau ein. send(Content) Hiermit wird die Anfrage an den Server übermittelt und nach der Methode open() ausgeführt.Der Parameter Content ist entweder null (bei einer gewählten Übertragungsmethode GET) oder ein QueryString (bei POST). ABBILDUNG 4.2 Im Falle des Nachladens von Daten durch AJAX kann der User ungehindert weiter mit der Site arbeiten – es ent- steht keinerlei Inaktivität auf Clientseite!
  • 139.
    K A PI T E L 4126 setRequestHeader("Label", "Wert") Diese Methode wird dafür verwendet,etwaige Header- Felder mit bestimmten Werten zu füllen.Beispielsweise wird diese Methode benötigt,um dem Server bekanntzugeben, dass die gesandten Daten Formulardaten sind. setMimeType("Typ") Hiermit wird der Typ der angeforderten (und per Response zurückzuschickenden) Daten angegeben und zwar wie üb- lich in Form eines Strings wie etwa "text/xml".Da manche Browser (hierunter auch der Internet Explorer) Probleme mit diesem Parameter haben,wird er zumeist einfach wegge- lassen,da beim Anfordern von XML-Daten keine konkrete Kennzeichnung als XML erforderlich ist. Tabelle 4.1: Methoden des XMLHttpRequest-Objekts Betrachten wir die Parameter der open()-Methode etwas genauer: Methode (String): Dieser Parameter kann GET, POST, HEAD oder PUT sein. Typischerweise werden die (bekannteren) Methoden GET oder POST verwendet. HEAD wird verwendet, wenn man nur die Header-Informationen und keine Daten erhalten möchte. PUT verwendet man, wenn beispielsweise Dateien zum Server transferiert werden sollen (doch selbst in diesem Fall wird oft mit der POST- Methode übertragen). URL (String): Gibt an, welches serverseitige Script (mit anderen Worten, welche PHP-Datei) aufgerufen werden soll. Der Bezug auf das Script kann absolut oder relativ gewählt werden. asyncMode (Boolean): Kennzeichnet die Art der Abarbeitung der Anfrage an den Server: asyncMode==true: Die Anfrage wird asynchron verarbeitet, was so viel bedeu- tet, wie dass das Webdokument auf Userseite nicht blockiert wird und somit der User weiter im Dokument arbeite e Antwort vom Server eingelangt ist – der User kann in der Zwischenzeit nicht im Dokument weiterarbeiten. Username (String) und Passwort (String): In manchen Fällen sind ein Username ein und Passwort für den Zugriff auf Ressourcen (beispielsweise Scripts in geschützten Ordnern, die nicht für den Zugriff des Internet-Users freigegeben sind) des Webservers von Nöten, die über diese beiden Parameter angegeben wer- den können. Nachdem wir nun die Methoden des XMLHttpRequest-Objekts kennen, müssen wir uns noch um die Eventhandler und Eigenschaften kümmern: u u u u u u
  • 140.
    A J AX – A S Y N C H R O N U S J AVA S C R I P T A N D X M L 127 Eventhandler Beschreibung onreadystatechange Dieser Handler wird immer dann aufgerufen,wenn sich der Verbindungsstatus (readyState) des XMLHttpRequest-Objekts ver- ändert hat.Mithilfe der Eigenschaft readyState kann der aktuelle Verbindungsstatus verarbeitet werden.In der Regel wird über diesen Eventhandler eine Funktion aufgerufen – man nennt solche Funktionen wie oben beschrieben Callback-Funktionen. Tabelle 4.2: Eventhandler des XMLHttpRequest-Objekts Eigenschaft Beschreibung readyState Hiermit wird der aktuelle Status der Verbindung zum Server abgefragt. Die möglichen Werte werden weiter unten genau behandelt. responseText Hierin befinden sich die vom Server nach einer Anfrage übermittelten Daten in Textform. responseXML Gleich wie responseText,nur dass die Daten eine XML-Struktur auf- weisen.Sollten die Daten nicht in XML-Form vom Server verschickt worden sein,ist diese Eigenschaft null. status Beinhaltet den HTTP-Status der aktuellen Verbindung als Zahl. statusText Gleich wie status,nur wird der Status in Form einer Textmeldung ausgegeben (dies muss nicht notwendigerweise der Fall sein – arbeiten Sie deshalb besser mit der Eigenschaft status). Tabelle 4.3: Eigenschaften des XMLHttpRequest-Objekts responseText oder responseXML? Wie Sie anhand der oben stehenden Tabelle sehen, existieren zwei (Formatierungs-)Arten der Rückgabedaten durch den Server: responseText und responseXML. Je nach Anwendungsgebiet verwendet man eine der beiden Varianten. Man sollte jedoch nicht außer Acht lassen, dass AJAX – wie der Name „Asynchronous JavaScript and XML“ schon sagt – darauf spezialisiert ist, mit XML-Daten zu arbeiten. Wann immer es darum geht, komplexere Datenstrukturen darzustellen, sollte man deshalb zu responseXML greifen. Sie sollten sich jedoch bewusst sein, dass eine Abarbeitung von XML für eine Browser-Darstellung mitunter sehr aufwändig sein kann. Von besonderem Interesse für uns ist auch die Eigenschaft readyState, die alle Infor- mationen über die aktuelle Verbindung zum Server für uns hat: Wert Bedeutung Beschreibung 0 UNITIALIZED Es besteht derzeit keine geöffnete Verbindung,da die Methode open() noch nicht aufgerufen wurde.Man könnte sagen,dies entspricht dem„Ruhezustand“ des XMLHttpRequest-Objekts. 1 LOADING Zu diesem Zeitpunkt wur- de mit open() bereits ein XMLHttpRequest-Objekt erstellt, jedoch wurde die Methode send() noch nicht aufgerufen.
  • 141.
    K A PI T E L 4128 2 LOADED Die Anfrage wurde per send() bereits abgeschickt.Auf den Header der Antwort vom Server kann bereits zugegriffen werden, jedoch nicht auf die zurückge- schickten Daten (diese sind zu diesem Zeitpunkt noch nicht eingetroffen). 3 INTERACTIVE Zu diesem Zeitpunkt sind die ers- ten Daten bereits übermittelt und es treffen noch weitere Daten ein. Man kann zwar schon Daten von responseText und responseXML abfragen,jedoch sind diese noch nicht vollständig. 4 COMPLETED Jetzt sind alle Daten vom Server zum Client übermittelt worden (sofern während der Übermittlung kein Fehler auf- getreten ist).Nun sind auch die Eigenschaften responseText und responseXML mit sämtlichen Daten gefüllt und können voll- ständig verarbeitet werden. Tabelle 4.4: Werte der Eigenschaft readyState des XMLHttpRequest-Objekts 4.3.2 AJAX im Einsatz Wenn wir nun alles Gelesene des XMLHttpRequest-Objekts zusammenfassen, können wir die Abarbeitung dessen wie folgt zusammenfassen: 1. Instanz des XMLHttpRequest-Objekts anlegen: Zunächst muss eine Instanz des XMLHttpRequest-Objekts angelegt werden.Weiter unten sehen wir, dass wir – wie üblich – auf verschiedene Browser eingehen müssen. 2. Callback-Funktion definieren: Noch bevor wir uns um eine etwaige Anfrage an einen Server kümmern, müssen wir festlegen, was passieren soll, wenn die Übertragung einmal läuft. Hierzu bedienen wir uns des Eventhandlers onreadystatechange, der uns gemeinsam mit der Eigenschaft readyState genau Auskunft gibt, wie es um die Kommunikation mit dem Server bestellt ist. 3. Verbindung öffnen: Mithilfe der Methode open() wird eine Verbindung zum Server geöffnet, jedoch noch nicht abgeschickt. Solange send() nicht aufgerufen wird, passiert gar nichts. 4. Anfrage abschicken: Dies geschieht wie angesprochen mit send(). Ab diesem Zeitpunkt wird der Server aktiv. Nun gilt es abzuwarten, bis der Server alle angeforderten Daten zurückgeschickt hat – wann dies der Fall ist, sagt uns die Eigenschaft readyState des XMLHttpRequest-Objekts.
  • 142.
    A J AX – A S Y N C H R O N U S J AVA S C R I P T A N D X M L 129 5. Auf abgeschlossene Übertragung warten: Wie eingangs erwähnt, ist nun der Eventhandler onreadystatechange am Werkeln. Hat die Eigenschaft readyState den Wert 4, so ist die Kommunikation zwischen Server und Client wieder abgeschlossen und es kann auf die übermittelten Daten zugegriffen werden. ABBILDUNG 4.3 Die fünf Schritte einer XMLHttpRequest-Anfrage Kommen wir also zur essenziellen Frage, wie diese fünf Schritte aus Sicht des Pro- grammierers aussehen. Bitte beachten Sie an dieser Stelle, dass wir weiter unten im Buch eine alternative Variante (Listing 4.8) für die Abarbeitung von AJAX-Anfragen besprechen werden, da diese erste Variante im Internet Explorer nur ein einziges Mal ausgeführt werden kann. Jedoch verdeutlicht diese erste Variante sehr schön die (korrekte) Vorgehensweise, sodass ich Sie zunächst über diesen Weg in die Thematik einführen möchte. In Schritt 1 kümmern wir uns um die Instanzierung des XMLHttpRequest-Objekts. Wie oben schon angedeutet, müssen wir auf verschiedene Browser Rücksicht neh- men. Beispielsweise verhalten sich verschiedene Browser-Generationen des Internet Explorer ebenfalls unterschiedlich. Der „offizielle Weg“ führt über die Instanzierung mittels: var myXMLHttpRequest = new XMLHttpRequest(); Listing 4.1: Der „offizielle Weg“ zum Instanzieren eines XMLHttpRequest-Objekts. Im Gegensatz zu allen Mozilla-basierten Browsern (wie etwa dem Firefox) versteht der Internet Explorer diese Instanzierung nicht. Instanzierung für Firefox & Co. Instanzierung für Firefox & Co.
  • 143.
    K A PI T E L 4130 Diese Instanzierung verwenden alle Mozilla-basierten Browser wie etwa der Firefox. Ein Internet Explorer der Generation 6 und höher erwartet eine Instanzierung wie folgt: var myXMLHttpRequest = new ActiveXObject("MSXML2.XMLHTTP"); Listing 4.2: Instanzierung für den Internet Explorer 6 und höher Ältere Internet Explorer hingegen möchten folgende Instanzierung: var myXMLHttpRequest = new ActiveXObject("Microsoft.XMLHTTP"); Listing 4.3: Instanzierung für Internet Explorer-Versionen kleiner als 6 Fasst man diese drei Wege in einem gemeinsamen Script zusammen, so bedient man sich gerne der Methode „try & catch“, wo mithilfe des try-Befehls eine Variante ausprobiert wird. Sollte diese fehlschlagen, so wird der Programmblock im catch- Abschnitt ausgeführt: try { var myXMLHttpRequest = new XMLHttpRequest(); } catch(error) { try { var myXMLHttpRequest = new ActiveXObject("MSXML2.XMLHTTP"); } catch(error) { var myXMLHttpRequest = new ActiveXObject("Microsoft. XMLHTTP"); } } } Listing 4.4: Nachdem alle Möglichkeiten von Browsern berücksichtigt („durchprobiert“) wurden, beinhaltet die Variable myXMLHttpRequest eine gültige Instanz eines XMLHttpRequest-Objekts. Idealerweise verpackt man dieses Script in eine Funktion, die als Rückgabewert die Instanz liefert. In Schritt 2 kümmern wir uns darum, dass wir clientseitig in der Lage sind, auf die abgeschlossene Übertragung der vom Server angeforderten Daten reagieren zu kön- nen. myXMLHttpRequest.onreadystatechange = function() { switch(myXMLHttpRequest.readyState) { case 0: case 1: case 2: case 3: return; case 4: showResponse(); return; Instanzierung für IE-Versionen 6 und höher Instanzierung für IE-Versionen 6 und höher Instanzierung für IE-Versionen kleiner als 6 Instanzierung für IE-Versionen kleiner als 6
  • 144.
    A J AX – A S Y N C H R O N U S J AVA S C R I P T A N D X M L 131 } } Listing 4.5: Der Eventhandler onreadystatechange hilft uns, auf Änderungen in unserem XMLHtt- pRequest-Objekt zu reagieren. Lediglich der Fall 4 (Übertragung aller vom Server angeforderten Daten abgeschlossen) ist für uns interessant. Mithilfe einer switch-Anweisung werden alle Möglichkeiten der Eigenschaft ready- State durchgegangen. Für die Fälle 0–3 macht die Funktion nichts, erst im Fall 4 rea- giert sie und ruft ihrerseits die Funktion showResponse auf. Diese Funktion erledigt dann die Ausgabe der vom Server angeforderten und vollständig zurückgelieferten Daten. In Schritt 3 wollen wir die soeben erzeugte Instanz öffnen und bedienen uns daher der open-Methode: myXMLHttpRequest.open("GET", "testrequest.htm", true); Listing 4.6: Anfrage für das Dokument testrequest.htm per POST im Asynchron-Modus (Parameter true) Schritt 4 schickt die Anfrage ab: myXMLHttpRequest.send(null); Listing 4.7: Absenden der Anfrage an den Server: „Schick mir das Dokument testrequest.htm“ Zusammengefasst in einem Beispiel könnte das wie folgt aussehen: Per Klick auf einen Button fordern wir den Server auf, uns die Datei testrequest.htm zu schicken. Nachdem wir das Dokument erhalten haben, geben wir es in ein Textfeld (<textarea>) aus. Gleichzeitig erzeugen wir ein zweites Textfeld, wo wir uns jeweils den aktuellen Wert der Eigenschaft readyState ausgeben lassen. Dies ist zwar nicht erforderlich, jedoch ist es gut zu wissen, welchen Status readyState gerade einnimmt (speziell hinsicht- lich der Fehlersuche ist eine solche Ausgabe immer ganz geschickt).
  • 145.
    K A PI T E L 4132 Bitte beachten Sie, dass das obige Beispiel im Internet Explorer bei einem wiederhol- ten Klick auf den „Klick mich!“-Button keine neuerliche Anfrage an den Server stellt. Dieses Problem lösen wir weiter unten. Dieses Beispiel war ja noch nicht sonderlich aufregend, da uns nicht so recht bewusst ist, dass wir während der Anfrage ohne weiteres auf der Seite weiterarbeiten können (was hätten wir neben dem Klicken auf den „Klick mich!“-Button auch tun sollen?). Interessanter wird die Sache aber dann, wenn es uns bewusst wird, dass ohne Neuladen der Seite immer Daten vom Server abgefragt werden können. Problem bei der Mehrfach- nutzung eines Eventhandlers im IE Problem bei der Mehrfach- nutzung eines Eventhandlers im IE ABBILDUNG 4.4 Unser Beispiel vor und nach dem Klicken des „Klick mich!“-Buttons. Wie Sie sehen, wird das hinzu- geladene Dokument als reiner String im Textfeld ausgegeben. Das Dokument finden Sie unter dem Namen ajax01.htm im Kapitel zum Buch auf der Buch-CD.
  • 146.
    A J AX – A S Y N C H R O N U S J AVA S C R I P T A N D X M L 133 Denken wir beispielsweise an ein Chat-System in XHTML: Angenommen, alle einge- henden Messages von Usern werden in einer Datenbank gespeichert. Sobald ein User eine Message eingibt, muss diese an den Server geschickt und dort in der Datenbank gespeichert werden.Würden wir nicht AJAX verwenden, müssten wir nun aus XHTML ein Formular abschicken, um wieder Kontakt mit dem Server aufzunehmen – unser Chat wäre für diesen Zeitraum inaktiv. Erst wenn uns der Server das aktualisierte Dokument wieder zurückgeschickt hat (darin sollte sich dann auch unsere soeben eingegebene Message wiederfinden lassen), können wir weiter chatten. Zusätzlich müssten wir in regelmäßigen Abständen den Server abfragen, ob neue Messages ein- getroffen sind – auch hier ist unser Chat wieder inaktiv. Verwenden wir jedoch AJAX, sind wir in der Lage, jederzeit weitere Daten (= Messages) vom Server abzufragen, ohne dabei jedes Mal die Seite neu zu laden. Problem im Internet Explorer: Mehrfachnutzung eines XMLHttpRequest-Eventhandlers Leider tritt im Internet Explorer ein Problem mit der Mehrfachnutzung eines Eventhandlers einer XMLHttpRequest-Instanz auf: Wird eine global definierte XMLHttpRequest-Instanz mehr als einmal mit der send-Methode dazu aufgefordert, Daten vom Server anzufordern, geschieht dies leider nicht, da (global definierte) Eventhandler nicht mehr abgearbeitet werden. Aus diesem Grund muss nach jedem Aufruf der open-Methode der Eventhandler neu zugewie- sen werden. Im Firefox und Opera tritt dieses Phänomen nicht auf. Das oben geschilderte Problem lässt sich relativ einfach lösen, indem der Eventhandler der XMLHttpRequest-Instanz nach jeder open-Anforderung neu zugewiesen wird: var myXMLHttpRequest = createRequestObject(); function sendRequest() { myXMLHttpRequest.open("GET", "testrequest.htm", true); myXMLHttpRequest.onreadystatechange = handleRequest; myXMLHttpRequest.send(null); } function createRequestObject() { try { var myRequest = new XMLHttpRequest(); } catch(error) { try { var myRequest = new ActiveXObject("MSXML2.XMLHTTP"); } catch(error) { var myRequest = new ActiveXObject("Microsoft. XMLHTTP"); } }
  • 147.
    K A PI T E L 4134 return myRequest; } function handleRequest() { document.forms["frmAjax"].elements["msgStatus"].value += "readyState changed: "+myXMLHttpRequest.readyState+"n"; switch(myXMLHttpRequest.readyState) { case 0: case 1: case 2: case 3: return; case 4: showResponse(); return; } } function showResponse() { document.forms["frmAjax"].elements["msgOut"].value = myXMLHttpRequest. responseText; } Listing 4.8: Alternatives Listing für eine Mehrfachanwendung einer XMLHttpRequest-Instanz, die auch den Internet Explorer zufriedenstellt. Die entsprechende Datei finden Sie auf der Buch-CD im Buchkapitel unter dem Namen ajax01_alternativ.htm. Im Script sehen Sie den Ablauf und folgende Änderungen gegenüber unserer ersten Variante: 1. Es wird zwar eine globale Variable myXMLHttpRequest angelegt und diese mittels createRequestObject definiert. Somit liegt die Variable myXMLHttpRequest global vor. 2. Sobald der User den Button „Klick mich!“ anklickt, wird die Funktion sendRequest aufgerufen (das ist ebenfalls noch nicht neu – das hatten wir vorher auch schon). Innerhalb der Funktion wird nun mittels open der globalen Variable myXMLHttpRequest mitgeteilt, dass eine Anforderung an den Server ansteht. 3. Ebenfalls innerhalb von sendRequest wird in der darauffolgenden Zeile der Eventhandler für dieses Objekt definiert: myXMLHttpRequest.onreadystatechange = handleRequest;
  • 148.
    A J AX – A S Y N C H R O N U S J AVA S C R I P T A N D X M L 135 Geändert hat sich die Definition des Eventhandlers: Entgegen der ursprünglichen Variante wird nicht mehr mit einer sogenannten nativen Funktion gearbeitet, sondern eine Funktion angegeben, die im Falle dieses Events aufgerufen wird (in unserem Fall ist dies die Funktion handleRequest). Alles andere ist unverändert geblieben. Wo liegen also die Nachteile dieser Variante bzw. warum haben wir nicht sofort diese Variante entwickelt? Nun, der Nachteil liegt einzig und allein in der Performance: In der neuen Variante wird mit jedem send- Request-Aufruf der Eventhandler der XMLHttpRequest-Instanz neu zugewiesen und dies benötigt Zeit. Diese Problematik wird uns zwar in dieser Anwendung nicht auf den Kopf fallen, in zeitkritischen Anwendungen jedoch schon. Leider kommen wir nicht herum, so zu arbeiten und deshalb mein Tipp: Verwenden Sie die soeben neu entwickelte Variante, wo der Eventhandler nach jedem Aufruf der open-Methode neu zugewiesen wird. Informationen an die Serverseite übermitteln In vielen Fällen ist es notwendig, diverse Informationen von Clientseite auf Serverseite zu übermitteln. In XHTML war das sehr einfach: Man musste lediglich ein Formular bemühen und schon konnte man per GET oder POST Daten (Formularfeldinhalte) zum Server schicken. Diese Varianten stehen uns in AJAX ebenfalls zur Verfügung, wobei wir jedoch in beiden Fällen einen Querystring zusammenbasteln müssen, der danach entweder per GET (als Anhängsel zur aufzurufenden Datei) oder per POST (im Body der send-Methode) an den Server übergeben wird. Im Übrigen gelten für den Versand dieselben Regeln wie bei Formularen in XHTML-Dokumenten: Werden die Daten per GET übertragen, so werden diese an die URL angehängt; werden sie hingegen per POST versandt, befinden sich die Formulardaten im HTTP-Header. Gesetzt den Fall, wir programmieren ein kleines Kontaktformular und möchten zwei Werte an den Server übermitteln: eine E-Mail-Adresse und eine Nachricht. Ein ent- sprechender Querystring würde dann folgendes Aussehen haben: var querystring = "Email=uwe.mutz@syne.at&Nachricht=TEST"; bzw. (wenn wir die Werte aus einem Formular mit dem Namen frmKontakt über- nehmen): var querystring = "Email="+document.forms["frmKontakt"]. elements["Email"].value+"&Nachricht="+document.forms["frmKontakt"]. elements["Nachricht"].value; Listing 4.9: Zusammenbasteln eines Querystrings aus gegebenen Formularfeldern „E-Mail“ und „Nach- richt“ Übergeben wir nun diese Daten an den Server, so müssen wir die zwei Varianten der Übertragungsmethode wie folgt anweisen: GET oder POST?GET oder POST?
  • 149.
    K A PI T E L 4136 GET-Variante: contactXMLHttpRequest.open("GET", "includes/kontakt.inc. php?"+querystring, true); contactXMLHttpRequest.send(null); Hierbei ist auf drei Punkte zu achten: In der open-Methode muss die Übertragungsmethode GET gewählt werden. An den Namen der am Server aufzurufenden Funktion wird ein Querystring im Format Feld=Wert angehängt. Der Body in der send-Methode hat den Wert null. POST-Variante: contactXMLHttpRequest.open("POST", "includes/kontakt.inc.php", true); contactXMLHttpRequest.setRequestHeader("Content-Type","application/x- www-form-urlencoded"); contactXMLHttpRequest.send(querystring); Entgegen der GET-Variante wird hier etwas anders gearbeitet: In der open-Methode muss die Übertragungsmethode POST gewählt werden. An den Namen der am Server aufzurufenden Funktion wird nichts ange hängt. Es muss dem Server mittels der setRequestHeader-Methode mitgeteilt werden, dass die gesendeten Daten Formulardaten sind – dies geschieht durch die Definition des Content-Type als application/x-www-form-urlencoded. Der Body in der send-Methode beinhaltet den Querystring im Format Feld=Wert. Auf zu einem konkreten Beispiel, wenn wir schon von einem Kontaktformular spre- chen: u 1. 2. 3. u 1. 2. 3. 4.
  • 150.
    A J AX – A S Y N C H R O N U S J AVA S C R I P T A N D X M L 137 Ziel ist es, per AJAX ein serverseitiges Script aufzurufen, das eine E-Mail an uwe.mutz@ syne.at schickt, worin der Name des Absenders und deren Nachricht zu finden sind. Der HTML-Part ist relativ unspektakulär – ein paar DIVs, ein Formular mit zwei Feldern und zwei Buttons: ... <script language="javascript" type="text/javascript" src="js/common.inc. js"></script> <script language="javascript" type="text/javascript" src="js/kontakt. inc.js"></script> ... <form name="frmKontakt" id="frmKontakt" action=""> <div id="msgOut"></div> <div class="label">Ihre Email-Adresse:</div> <div class="field"><input type="text" name="Email" id="Email" /></div> <div class="cleaner"></div> <div class="label">Ihre Nachricht an mich:</div> <div class="field"><textarea name="Nachricht" cols="50" rows="10" id="Nachricht"></textarea></div> <div class="cleaner"></div> <div class="button"> <input type="button" name="submitIt" id="submitIt" value="Abschicken E-Mails versen- den mit AJAX und PHP E-Mails versen- den mit AJAX und PHP ABBILDUNG 4.5 Ein einfaches Kontakt- formular für die Eingabe von E-Mail-Adresse und Nachricht. Wir können wählen, ob die Daten per GET oder POST übertragen werden.
  • 151.
    K A PI T E L 4138 (GET)" onclick="sendContact('GET');" /> <input type="button" name="submitIt2" id="submitIt2" value="Abschicken (POST)" onclick="sendContact('POST');" /> </div> </form> ... Listing 4.10: Wir finden ein (noch) leeres <div id="msgOut"> zur Ausgabe der Statusmeldung nach dem Versenden der E-Mail sowie zwei Buttons, die jeweils dieselbe Funktion sendContact mit zwei unterschiedlichen Parametern aufrufen. Der JavaScript-Code ist komplett in zwei externe Dateien namens common.inc.js und kontakt.inc.js ausgelagert worden, um den XHTML-Code übersichtlicher zu halten bzw. den JavaScript-Code für weitere Beispiele einfach verknüpfen zu können. Das derzeit noch leere <div id="msgOut"> wird im Weiteren dafür verwendet, dass wir eine Meldung nach dem Versenden der E-Mail ausgeben, ob der Versand erfolg- reich oder eben nicht erfolgreich war. Des Weiteren sehen Sie, dass wir eine Funktion sendContact in Verwendung haben, an die über einen Parameter übergeben wird, mit welcher Methode wir die Daten an den Server übergeben werden: GET oder POST. Die Datei common.inc.js beinhaltet lediglich die Auswahl des korrekten XMLHttp- Request-Objekts aus Listing 4.4. In kontakt.inc.js sind die für das Beispiel spezifischen Codes abgelegt, worin zunächst einmal eine Variable für die Instanz des XMLHttp- Request-Objekts angelegt wird: var contactXMLHttpRequest; function sendContact(method) { contactXMLHttpRequest = createRequestObject(); contactXMLHttpRequest.onreadystatechange = handleRequestContact; var querystring = "Email="+document.forms["frmKontakt"]. elements["Email"].value+"&Nachricht="+document.forms["frmKontakt"]. elements["Nachricht"].value+"&Methode="+method; if(method.toLowerCase()=="get") { contactXMLHttpRequest.open("GET", "includes/kontakt.inc. php?"+querystring, true); contactXMLHttpRequest.send(null); } else { contactXMLHttpRequest.open("POST", "includes/kontakt.inc.php", true);
  • 152.
    A J AX – A S Y N C H R O N U S J AVA S C R I P T A N D X M L 139 contactXMLHttpRequest.setRequestHeader("Content-Type","application/ x-www-form-urlencoded"); contactXMLHttpRequest.send(querystring); } } function showResponse2() { document.getElementById("msgOut").innerHTML = contactXMLHttpRequest. responseText; } function handleRequestContact() { switch(contactXMLHttpRequest.readyState) { case 0: case 1: case 2: case 3: return; case 4: showResponse2(); return; } } Listing 4.11: Code der Datei kontakt.inc.js Die Funktion sendContact mit dem Parameter method dient dazu, je nach geklicktem Button die Nachricht entweder per GET oder per POST zu versenden (dies geschieht in der if-Anweisung). Bevor eine Auswahl für GET oder POST geschieht, wird erst einmal dem XMLHttpRequest-Objekt ein Eventhandler zugewiesen. (dieser ist ebenfalls schon bekannt – siehe Listing 4.8 in leicht abgeänderter Form: Aufruf von showResponse2 anstatt showResponse, da wir eine andere Funktion für den Fall der abgeschlossenen Übertragung verwenden.) Danach werden wie oben besprochen im Fall von GET die Formularfeldwerte an die URL der am Server aufzurufenden Datei angehängt und der Body in der send-Methode leergelassen. Bei POST wird an die URL nichts angehängt, dafür werden die Formularfeldwerte in den Body der send-Anweisung gegeben. Bei POST muss ebenfalls noch angegeben werden, dass es sich bei den Daten um Formu- larfelder handelt (Content-Type=application/x-www-form-urlencoded). Um dem User nach dem Versenden der E-Mail auch eine Erfolgs- (oder Misserfolgs- )Meldung auszugeben, wird in der Funktion showResponse2 auf das weiter oben angesprochene <div id="msgOut"> zugegriffen und dort hinein (innerHTML) geschrieben, was uns die (serverseitige) Datei kontakt.inc.php zurückliefert. Also wer- fen wir mal einen Blick auf diese Datei:
  • 153.
    K A PI T E L 4140 <?php function create_email_header($name, $value) { return ($name && $value) ? "$name: $valuern" : ""; } function sendContact() { $success = ""; if(count($_REQUEST)>0) { $REQUESTdata = $_REQUEST; $msg = "Kontaktaufnahme auf flashphpajax.beelzebuben.at.nDie eingegebenen Daten waren:nn"; foreach($REQUESTdata as $itm=>$val) { $msg.= "t$itm: $valn"; } $mailto = "uwe.mutz@syne.at"; $mailfrom = "autosender@syne.at"; $headers = «»; $cc_email = $REQUESTdata[«Email»]; $bcc_email = «uwe.mutz@gmx.at»; $headers .= create_email_header(«Cc», $cc_email); $headers .= create_email_header(«Bcc», $bcc_email); $headers .= create_email_header(«From», $mailfrom); if(!mail($mailto, «- Kontaktaufnahme auf flashphpajax.beelzebuben.at -», $msg, $headers)) { $success = $msg; } else { $success = «OK»; } } return $success; } $msgOut = sendContact(); if($msgOut=="OK") { echo('<p class="success">Ihre Anfrage wurde ERFOLGREICH an uns versandt.</p>'); } else { echo('<p class="error">Ihre Anfrage wurde NICHT ERFOLGREICH an uns versandt.</p>'); } ?> Listing 4.12: Code der Datei kontakt.inc.php, die rein serverseitig liegt und der User nie zu Gesicht bekommt
  • 154.
    A J AX – A S Y N C H R O N U S J AVA S C R I P T A N D X M L 141 Wird diese Datei serverseitig aufgerufen, wird nach dem Aufruf von sendContact() (dies geschieht im unteren Teil des Scripts mittels $msgOut = sendContact();) zunächst einmal überprüft, ob an die Datei Formulardaten gleich welcher Art überge- ben wurden: ... if(count($_REQUEST)>0) { ... Der Nachrichtentext wird in der Variablen $msg gespeichert, worin zunächst ein kur- zer Infotext geschrieben wird: $msg = "Kontaktaufnahme auf flashphpajax.beelzebuben.at.nDie eingegebenen Daten waren:nn"; Die weiteren Inhalte werden über eine foreach-Schleife aus den übergebenen Formu- larfelddaten gelesen und zeilenweise in den Text geschrieben. Die Funktion create_email_header dient dazu, die Header-Informationen für eine E-Mail korrekt zu formatieren (dieses Script ist schon quasi Standard – vielen Dank an www.php.net). Sollte zu guter Letzt das Abschicken der E-Mail mittels der mail- Funktion geklappt haben, wird in $success der Wert „OK“ geschrieben, ansonsten der Inhalt der E-Mail (um etwaige Tests durchführen zu können). Selbstverständlich könnte anstatt eines Textes auch einfach der Rückgabewert (true oder false) von mail() geschrieben werden – in diesem Fall hätte man jedoch keine Möglichkeit, zu überprüfen, ob der Nachrichtentext überhaupt korrekt geschrieben wurde. Der User selbst erhält die E-Mail in CC ($cc_email = $REQUESTdata["Email"];). Ganz unten im Script wird zuletzt noch überprüft,ob in $msg derWert„OK“ steht (und somit die E-Mail erfolgreich versandt wurde) – wenn ja, wird in das PHP-Dokument per echo der XHTML-Code <p class="success">Ihre Anfrage wurde ERFOLG- REICH an uns versandt.</p> geschrieben, ansonsten <p class="error">Ihre Anfrage wurde NICHT ERFOLGREICH an uns versandt.</p>. Genau dieser XHTML-Code stellt also den Wert dar, der von AJAX vom Server angefordert und in dem Tag <div id="msgOut"> ausgegeben wird. Wenn ich also eine E-Mail an mich selbst schicke, sieht unser Beispiel wie folgt aus:
  • 155.
    K A PI T E L 4142 Die Ergebnis-Mails (einmal per GET, einmal per POST verschickt) sehen Sie in den nachfolgenden Abbildungen (mit Umlauten gibt’s so kleine Probleme, da wir nicht den korrekten Zeichensatz definiert haben): ABBILDUNG 4.6 AJAX in Verbindung mit einem geeigneten PHP-Script verschickt E-Mails. ABBILDUNG 4.7 Die empfangenen E-Mails – hat also super funktioniert! Um den Code so einfach wie möglich zu halten, habe ich bewusst auf Formatierungen der E-Mail verzichtet – selbstverständlich könnte die E-Mail auch als HTML-E-Mail verschickt werden. PHP macht auf Serverseite keine Unterscheidung, ob die Seite nur serverseitig aufgerufen wird oder doch als XHTML-Dokument zum User übertragen
  • 156.
    A J AX – A S Y N C H R O N U S J AVA S C R I P T A N D X M L 143 wird. Ob nun AJAX die Seite anfordert oder der User selbst (beispielsweise durch einen Klick auf einen Link), spielt keine Rolle. Darstellen des Ladezustands In letzter Zeit findet man auf AJAX-basierten Websites immer öfter eine Anzeige des Ladezustands, da der User im Fall von AJAX nichts davon mitbekommt, dass Daten an den Server übertragen werden – im Gegensatz zu Standard-XHTML-Anwendungen, wo der weitere Ablauf der Site blockiert wird. Deshalb ist es als Entwickler nicht unge- schickt, dem User eine entsprechende Meldung am Bildschirm auszugeben. Ideal dafür geeignet sind die verschiedenen Stati der readyState-Eigenschaft, denn solange rea- dyState nicht den Wert 4 erreicht hat, ist die Übertragung der Daten noch im Gange. Erweitern wir also unser zuvor entwickeltes Kontaktformular um eine Grafik, die immer dann eingeblendet wird, wenn eine aktive Übertragung stattfindet. Dies sollte wie folgt am Bildschirm des Users aussehen: ABBILDUNG 4.8 Verwenden eines „Abdunklers“, um dem User eine gerade stattfindende Übertragung zu verdeut- lichen Abdunkler oder Sanduhr? An dieser Stelle kommt wieder Usability ins Spiel: Wann soll man bei AJAX-Anwendungen einen Abdunkler, wann eine Sanduhr (oder etwas Ähnliches) verwenden? Nun, Abdunkler sollten immer dann zum Einsatz kommen, wenn dem User verdeutlicht werden soll, dass er „jetzt bitte einen Moment warten“ soll. Eine Sanduhr als Grafik neben beispielsweise dem Abschicken-Button hinge- gen soll nur einen laufenden Prozess verdeutlichen – der User kann aber ungestört weiterarbeiten. Bitte sehen Sie davon ab, den Cursor in eine Sanduhr zu „verwandeln“, denn das hätte zur Folge, dass der User meint, er dürfe nun gar nichts mehr tun – da könnten Sie den Abdunkler auch gleich verwenden ;=).
  • 157.
    K A PI T E L 4144 Um den Abdunkler in die Realität umzusetzen, bediene ich mich eines teiltranspa- renten Bilds in Form einer PNG-Datei (Schwarz mit 70% Deckkraft) sowie eines vor- erst unsichtbaren Layers namens abdunkler: div#abdunkler { visibility:hidden; text-transform:uppercase; position:absolute; width:100%; height:100%; padding:10px; background-image:url(../../images_standard/abdunkler70.png); background-repeat:repeat; font-size:16px; color:white; } Listing 4.13: CSS-Definition des Layers <div id="abdunkler">Bitte einen Moment Geduld - Ihre Anfrage wird gerade an uns weitergeleitet...</div> Listing 4.14: XHTML-Code des Layers mit einem entsprechenden Mitteilungstext an den User. Dieser Layer wird vorerst durch die obige CSS-Definition ausgeblendet. Um diesen Layer während der Übertragung anzeigen zu lassen, verwenden wir den Eventhandler des XMLHttpRequest-Objekts und modifizieren ihn ein wenig: function handleRequestContact() { switch(contactXMLHttpRequest.readyState) { case 0: case 1: return; case 2: showHideDiv("abdunkler",true); return; case 3: return; case 4: showHideDiv("abdunkler",false); showResponse2(); return; } } Listing 4.15: Die adaptierte Eventhandler-Funktion
  • 158.
    A J AX – A S Y N C H R O N U S J AVA S C R I P T A N D X M L 145 Anstatt im Fall 2 (die send-Methode wurde aufgerufen) einfach nur die Funktion mit einem return abzubrechen (die Fälle 0 und 1 tun dies indes immer noch), rufen wir eine Funktion auf, die über die Funktion showHideDiv den Abdunkler-Layer einblen- det: function showHideDiv(divname,isVisible) { if(isVisible) { document.getElementById(divname).style.visibility = "visible"; } else { document.getElementById(divname).style.visibility = "hidden"; } } Listing 4.16: Die Funktion showHideDiv blendet – je nach Wert der Variable isVisible – einen über die Variable divname definierten Layer ein oder aus. Dieser Layer wird im Fall von readyState==4 über dieselbe Funktion wieder ausge- blendet. In unserem Fall wäre es genauso möglich, bereits bei readyState==1 (die open- Methode wurde aufgerufen) den Layer einzublenden, da open und danach send in unserem Fall durch dieselbe Funktion sendContact aufgerufen werden und es somit keine Unterbrechung zwischen open und send gibt. Bevor wir in den Workshops zu komplexeren Themen übergehen, werden wir einige Anwendungen für AJAX entwickeln, damit Sie einen tieferen Einblick gewinnen kön- nen. Anwendung 1 – Mini-Website In diesem Beispiel werden wir eine Mini-Website entwickeln, wo sich die Hauptseite nicht ändert, sondern nur per AJAX Dokumente hinzugeladen werden. Wie funktioniert eine Website bisher: Variante 1: Es wird eine Frame-Site verwendet. Diese Variante ist mittlerweile zwar verpönt (und in XHTML Strict auch nicht mehr standardisiert), findet in manchen Fällen aber immer noch Verwendung. Durch Klick auf einen Link wird in einen Frame ein neues Dokument geladen. Nachteilig ist, dass die Site so lange nicht verwendbar ist, solange dieses Dokument nicht geladen ist. Variante 2: Es wird ein IFrame verwendet. Die Möglichkeit der IFrames gibt es zwar auch schon länger, jedoch ist die Verwendung der IFrames erst in den letzten Jahren so wirklich in Mode gekommen, da alle gängigen Browser mittlerweile IFrames unterstützen. IFrames funktionieren wie Frames, jedoch mit dem Unterschied, dass kein Frameset benötigt wird – ein IFrame wird wie eine Grafik direkt im XHTML-Code platziert. u u
  • 159.
    K A PI T E L 4146 Variante 3: Für jedes Inhaltselement (Navigationspunkt) wird die Site komplett neu geladen. Dies ist die Standardvariante, die auch vom XHTML-Standard gutgeheißen wird. Nachteilig ist, dass immer wiederkehrende Elemente permanent neu geladen werden und sich so die Ladezeit der Site erhöht. Zwar werden Grafiken im Cache gespeichert und müssen so nicht neu vom Server angefordert werden, jedoch gilt dies nicht für Texte etc. Somit fällt ein nicht zu geringer Brocken an Daten an, die mit jedem Klick redundant übertragen werden. Variante 4: Ein und dieselbe Seite wird serverseitig mit geänderten Inhalten gefüllt. Typischerweise arbeiten Content Management Systeme (CMS) auf diese Weise: Es existiert lediglich eine Indexseite mit integrierten Platzhaltern. Diese Platzhalter werden serverseitig durch geeignete (PHP oder ähnliche) Programmierung mit Inhalten gefüllt, die vorzugsweise aus einer Datenbank generiert werden. Nachteilig ist wie in Variante 3 die Tatsache, dass die Seite immer wieder neu geladen wird, da ja die Inhalte auf Serverseite generiert werden. Der Vorteil unseres Systems wird sein, dass wir unsere Seite nie neu laden müssen, sondern nur geänderte Inhalte vom Server auf Anfrage geliefert bekommen, die wir dann mithilfe des DOM an vorgegebene Stellen im Dokument (Platzhalter) schreiben werden. Sehen wir es uns einfach mal an. u u ABBILDUNG 4.9 Eine einfache Website mit vier Links und einem Content-Bereich. Die Gestaltung haben wir erst mal außer Acht gelassen, um nicht den Fokus auf das Wesentliche zu verlieren.
  • 160.
    A J AX – A S Y N C H R O N U S J AVA S C R I P T A N D X M L 147 Wenn wir kurz zusammenfassen, benötigen wir folgende Dokumente: 1. index.htm: Die „Startseite“ oder „Homepage“ unserer Mini-Website. Hierin befinden sich die Links sowie ein Container (ein <div>) für die Darstellung der Inhalte. 2. home.htm: Der Begrüßungstext, der unseren User auf der Website willkommen heißt. Dieses Dokument wird als Erstes automatisch in den leeren Container geladen. An diesem Dokument werden wir lernen, wie man nach erfolgtem Laden der index.htm ein Dokument per AJAX in den leeren Container lädt. 3. ueberuns.htm: Eine statische Seite ohne spezielle Features.Sie wird uns gute Dienste leisten, indem wir lernen, wie man ein statisches Dokument auf Klick lädt. 4. kontakt.php: Entgegen ueberuns.htm ist dies eine dynamische Seite mit der Möglichkeit des Versendens einer Nachricht an einen gegebenen Empfänger. An ihr zeigen wir auf, wie ein dynamisches Dokument per AJAX geladen und von sich aus wiederum AJAX zum Versenden von Nachrichten funktioniert. Das Dokument kontakt.php ist im Wesentlichen mit dem Dokument vom letzten Beispiel identisch. 5. links.php: Ebenfalls ein dynamisches Dokument – in diesem Fall wird eine Datenbank abgefragt und die Ergebnisse (Links) werden in Form einer Liste wiedergegeben. Zunächst kümmern wir uns um unser Gerüst index.htm: ... <div id="navigation"> <div class="navitem"><a href="#" id="home">Home</a></div> <div class="navitem"><a href="#" id="ueberuns">&Uuml;ber uns</a></div> <div class="navitem"><a href="#" id="kontakt">Kontakt</a></div> <div class="navitem"><a href="#" id="links">Links</a></div> <div class="cleaner"></div> </div> <div id="content"></div> ... Listing 4.17: Auszug aus dem Listing der Datei index.htm unserer Mini-Website (wie üblich zu finden auf der beiliegenden Buch-CD) In diesem Script existiert nichts Aufregendes – einzig das (noch) leere <div id="content"> für das nachträgliche Einfügen von Inhalt. Die vier Navigationsele- mente sind bewusst ohne onclick-Ereignis definiert, da wir in diesem Beispiel auch
  • 161.
    K A PI T E L 4148 sehen werden, wie man im Nachhinein (nämlich nach dem vollständigen Laden des Dokuments) einem gegebenen Element ein Ereignis zuweisen kann. Des Weiteren hat diese Vorgehensweise den Vorteil, dass der User erst dann auf einen Link klicken kann, wenn die Site vollständig geladen ist (was man ihm aus Usability-Gründen eventuell mitteilen sollte …). Das Element der Klasse cleaner dient dazu, dass die float- Eigenschaft der Elemente der Klasse navitem wieder beendet wird. Ein Blick auf die CSS-Definition verdeutlicht dies: div.navitem { float:left; margin-right:20px; } div.cleaner { clear:both; } Listing 4.18: CSS-Definition für <div> der Klassen navitem und cleaner Die Eigenschaft float:left bewirkt, dass DIV-Tags nebeneinander angeordnet wer- den (und zwar mit dem Platz, den sie benötigen – es sei denn, Sie geben eine Breite an), clear:both bewirkt, dass eine float-Eigenschaft (egal ob left oder right) wieder eliminiert wird. Wir benötigen einen solchen „Cleaner“, damit das darauffol- gende Element (bei uns ist das das DIV mit der id=content) nicht auch rechts neben den Navigationselementen platziert wird. Falls Sie mehr über CSS erfahren möchten, so kann ich Ihnen die einschlägige Literatur aus dem Verlag Addison-Wesley nur ans Herz legen. Nun müssen wir uns überlegen, wie den Links die onclick-Ereignisse zugewiesen werden können. Wie oben erwähnt, wollen wir eine Zuweisung erst nach dem voll- ständigen Laden des Dokuments. Hierzu bedienen wir uns des onload-Ereignisses des window-Objekts: window.onload = init; function init() { navigateTo("home.htm"); //Homepage laden document.getElementById("home").onclick = function() { navigateTo("home.htm"); } document.getElementById("kontakt").onclick = function() { navigateTo("kontakt.htm"); } document.getElementById("ueberuns").onclick = function() { navigateTo("ueberuns.htm"); }
  • 162.
    A J AX – A S Y N C H R O N U S J AVA S C R I P T A N D X M L 149 document.getElementById("links").onclick = function() { navigateTo("links.php"); } } Listing 4.19: Wir nutzen das onload-Ereignis des window-Objekts, um nach dem vollständigen Laden des Dokuments im Browser des Users den Links ein onclick-Ereignis zuzuweisen. Des Weiteren wird als „Homepage“ das Dokument home.htm geladen. Wir gehen den ausführlichen Weg und weisen dem Ereignis onload vom window- Objekt zunächst eine Funktion init zu und definieren diese Funktion im nächsten Schritt. Innerhalb von init wird zunächst eine Funktion navigateTo mit dem Para- meter home.htm aufgerufen – diese Funktion wird im Weiteren dafür sorgen, dass ein Dokument per AJAX in den Container content geladen wird. Genau diese Funktion verwenden wir auch in den onclick-Ereignissen der einzelnen Links. Wenn wir einen solchen Eventhandler genauer betrachten, finden wir Folgendes: document.getElementById("home").onclick = function() { navigateTo("home. htm"); } Zunächst wird über die Methode getElementById auf ein benanntes Element (hier: "home") zugegriffen und diejenige Methode definiert (hier: onclick), die wir benö- tigen. Danach wird dieser Methode eine Funktion zugewiesen, die beim Aufruf des Ereignisses abgearbeitet werden muss. In unserem Fall sorgt diese Funktion lediglich dafür, dass eine weitere Funktion namens navigateTo aufgerufen wird. Kommen wir also zu navigateTo: function navigateTo(URL) { myXMLHttpRequest = createRequestObject(); myXMLHttpRequest.onreadystatechange = handleRequest; myXMLHttpRequest.open("GET", URL, true); myXMLHttpRequest.send(null); } Listing 4.20: Listing der Funktion navigateTo, die die Schnittstelle zu AJAX bildet Der Inhalt der Funktion ist aus den vorigen Beispielen bekannt: Es wird eine Ins- tanz des XMLHttpRequest-Objekts gebildet. (Die Funktion createRequestObject wurde im Listing 4.4 ausführlich besprochen; in diesem Beispiel ist sie in der extern verknüpften Datei common.inc.js im Verzeichnis js des aktuellen Kapitels abgelegt, sollten Sie die Funktion auf der CD suchen.) Danach wird ein Request-Handler hand- leRequest definiert (dessen Funktionalität kennen wir aus Listing 4.5). Mit open wird eine Anfrage für die per URL definierte Datei an den Server geöffnet und mit send abgeschickt. function handleRequest() { switch(myXMLHttpRequest.readyState) {
  • 163.
    K A PI T E L 4150 case 0: case 1: case 2: case 3: return; case 4: showResponse(); return; } } function showResponse() { var myContent = document.getElementById("content"); myContent.innerHTML = myXMLHttpRequest.responseText; } Listing 4.21: Der Eventhandler handleRequest ruft nach der vollständigen Übertragung der Anfrage eine Funktion showResponse auf. Nachdem die Anfrage per send abgeschickt und die Übertragung (readyState==4) vollständig abgeschlossen wurde, wird mithilfe von showResponse auf das Element content zugegriffen und dessen Inhalt über die Anweisung innerHTML auf den zurückgegebenen Text (responseText) der XMLHttpRequest-Instanz gesetzt – fertig. DOM und innerHTML Wie Sie sehen, habe ich im letzten Beispiel die Methode innerHTML verwendet, um das „Innere“ eines XHTML-Elements zu setzen – diese Methode ist jedoch nicht im Standard des W3C enthalten. Jedoch hat sich diese ursprünglich von Microsoft eingeführte Methode mit- tlerweile in allen Browsern durchgesetzt, sodass man sie als Quasi-Standard ansehen kann. Aus dem Kapitel zum DOM kennen Sie jedoch auch Varianten, ohne diese – zugegebenermaßen sehr einfache – Methode zu arbeiten. So weit, so gut. Dass wir natürlich ganz zu Beginn eine Variable für die XMLHttpRe- quest-Instanz anlegen mussten, versteht sich von selbst. Das gesamte Script dieser Datei finden Sie auf der Buch-CD im Verzeichnis Miniwebsite im Verzeichnis zum Kapitel. Nachdem unsere Navigation nun funktioniert, wenden wir uns den einzelnen Web- dokumenten zu – zunächst hier einmal die statischen Dokumente: <h2>Home...</h2> <p>Willkommen auf der Miniwebsite zum Testen von AJAX!</p> Listing 4.22: Quellcode von home.htm <h2>&Uuml;ber uns...</h2> <p>Ein bisschen BlaBla, oder auch nicht...?!</p> Listing 4.23: Quellcode von ueberuns.htm
  • 164.
    A J AX – A S Y N C H R O N U S J AVA S C R I P T A N D X M L 151 Sollten Sie sich nun die Frage stellen, ob dieser Quellcode nur ein Auszug ist oder schon alles war, dann seien Sie versichert: Das ist der gesamte Quellcode der beiden Dokumente! Warum? Ganz einfach: Wir laden diese Daten in ein bereits bestehendes Webdokument (index.htm) hinzu – darin befinden sich sämtliche Tags zum Seiten- aufbau (<html>, <head>, <body> etc.) und bilden somit ein gültiges Webdokument. Die gute Nachricht ist, dass Sie in Dreamweaver Dokumente mit nur einem Teilcode eines gültigen Webdokuments ebenso bearbeiten können, als wäre es ein vollständiges Webdokument: Da der Dreamweaver eines der gängigsten Tools für das Arbeiten mit Webdokumenten ist, habe auch ich mich in diesem Buch für dieses Tool entschieden. Das Nachladen eines statischen Dokuments ist also denkbar einfach – per AJAX das Dokument anfordern und den responseText einem Container zuweisen. Im Fall von dynamischen Dokumenten würden wir erwarten, dass sich die Sache viel- leicht doch etwas komplizierter darstellt. Deshalb werfen wir doch mal einen Blick auf ein solches: links.php: <link href="css/common.inc.css" rel="stylesheet" type="text/css"> <h2>Links...</h2> <?php require("includes/links.inc.php"); ?> Listing 4.24: Auch die Einbindung eines dynamischen Dokuments ist nichts anderes als das Einbinden eines statischen Dokuments, da der PHP-Code ja bereits auf Serverseite verarbeitet wird. Grundsätzlich ist alles gleich wie beim statischen Dokument, da der PHP-Code ser- verseitig in XHTML-Code umgewandelt wird. Um das Dokument übersichtlicher ABBILDUNG 4.10 Bearbeiten eines nicht voll- ständigen Webdokuments in Dreamweaver – alles wie gehabt
  • 165.
    K A PI T E L 4152 zu gestalten, habe ich die eigentliche PHP-Funktionalität in eine Datei links.inc.php verlegt, die ich per require anfordere (sollte Ihnen das unbekannt vorkommen, so schlagen Sie bitte im Grundlagenkapitel zur Programmierung nach): <?php function showLinks() { if(!$conn = mysql_connect("mysql.syneweb.com","usr_flashphpajax","12 3passwort")) { die(‚<p>Der Datenbankserver konnte nicht kontaktiert werden. ERROR='.mysql_error()); } if(!$db = mysql_select_db("db_flashphpajax")) { die(‚<p>Die Datenbank konnte nicht ausgewaehlt werden. ERROR='.mysql_error()); } $sql = "SELECT * FROM tbl_04links WHERE(bitP_chk_aktiv=1)"; $query = mysql_query($sql); $returner = ‚'; if(mysql_num_rows($query)>0) { $returner.= '<ul>'; while($data = mysql_fetch_array($query)) { $returner.= '<li><a href="'.$data["vcP_URL"].'" target="_blank">'.$data["vcP_ Bezeichnung"].'</a></li>'; } $returner.= '</ul>'; } else { $returner.= '<p class="info">Keine Links vorhanden.</p>'; } return $returner; } echo(showLinks()); ?> Listing 4.25: Der vollständige Code der Datei links.inc.php, in der sich die gesamte PHP-Funktionalität zum Generieren des XHTML-Codes befindet Ich verwende in solchen Fällen gerne eine Funktion, die mir eine Variable (hier: $returner) mit dem generierten XHTML-Code zurückgibt. Alternativ wäre man auch ohne Funktion und anschließendem Funktionsaufruf ausgekommen. In der untersten Zeile wird also die Funktion showLinks aufgerufen – der von ihr zurückgelieferte Wert wird danach per echo ausgegeben. Die Funktion selbst nimmt zunächst Kontakt mit einem Datenbankserver auf, danach wird die Datenbank ausge- wählt. Sollte einer der beiden Aufrufe nicht funktionieren, wird mittels die abgebro- chen und eine entsprechende Fehlermeldung ausgegeben. Sollte alles geklappt haben, wird für den Zugriff auf die Tabelle tbl_04links ein entsprechendes SQL-Statement erzeugt. Die Tabelle selbst besteht aus vier Feldern:
  • 166.
    A J AX – A S Y N C H R O N U S J AVA S C R I P T A N D X M L 153 Feldname Typ Extras Beschreibung idP_Links int(11) auto-increment,Primary Key,not null Dieses Feld stellt die ID der Tabelle dar – dementsprechend verwende ich ein auto-increment und definiere es als Primärschlüssel. vcP_Bezeichnung varchar(128) not null Linktext wie etwa„Addison-Wesley“ für die URL„http://www.addison- wesley.de“ vcP_URL varchar(128) not null URL zur Website (beispielsweise „http://www.addison-wesley.de“) bitP_chk_aktiv tinyint(1) not null,Standardwert=1 Kennzeichnet,ob der Link auf der Website ausgegeben werden soll Tabelle 4.5: Tabellenstruktur der verwendeten Tabelle tbl_04links Wir fragen nur Links ab, die die Kennzeichnung bitP_chk_aktiv=1 aufweisen. Danach wird das SQL-Statement abgesetzt und das Ergebnis der Abfrage in der Vari- ablen $query gespeichert. Sollten mehr als null Zeilen zurückgeliefert worden sein, wird ein <ul> in $returner hinzugefügt. In einer while-Schleife geht man zeilen- weise das Ergebnis durch und generiert in $returner einen XHTML-Code in Form von <li><a href="URL" target="_blank">LINKTEXT</a></li>. Nachdem die while-Schleife vollständig durchgelaufen ist, wird ein abschließendes </ul> an $returner angehängt und die Variable $returner an den Aufrufer zurückgeliefert (= Rückgabewert der Funktion). Sollte unsere Abfrage keine Daten zurückgeliefert haben, so wird der Text <p class="info">Keine Links vorhanden.</p> an den Aufrufer zurückgeschickt. In unserem Fall liefert das SQL-Statement fünf Links zurück, die per echo in das Dokument geschrieben werden: ABBILDUNG 4.11 AJAX fordert ein PHP- Dokument an, das auf Serverseite eine Datenbank ausliest und das Ergebnis per echo in das Dokument schreibt.
  • 167.
    K A PI T E L 4154 Wie zu erwarten war, ist auch das Anfordern von PHP-basierten Dokumenten kein Problem, da diese zunächst am Server abgearbeitet werden und somit das Rückgabe- dokument in jedem Fall reinen XHTML-Code beinhaltet. Wenden wir uns also der schwierigsten Aufgabe zu: einem Dokument (kontakt.htm), das per AJAX eingebunden wird und von sich aus wieder per AJAX eine Anfrage an den Server stellt. Zunächst einmal nachfolgend der Code dieses Dokuments: <link href="css/common.inc.css" rel="stylesheet" type="text/css"> <h2>Kontakt...</h2> <p>Hier ein Kontaktformular, damit Sie mir auch eine Email schreiben k&ouml;nnen:</p> <form name="frmKontakt" id="frmKontakt" method="post" action=""> <div id="msgOut"></div> <div class="label">Ihre Email-Adresse:</div> <div class="field"><input type="text" name="Email" id="Email" /></div> <div class="cleaner"></div> <div class="label">Ihre Nachricht an mich:</div> <div class="field"><textarea name="Nachricht" cols="50" rows="10" id="Nachricht"></textarea></div> <div class="cleaner"></div> <div class="button"><input type="button" name="submitIt" id="submitIt" value="Abschicken" onclick="sendContact();" /></div> <div><textarea name="msgStatus" rows="10" id="msgStatus">Status:n</ textarea> </div> </form> Listing 4.26: Der XHTML-Code bietet keine Überraschungen: Es wird ein Formular mit zwei Feldern und einem Button verwendet, welche allesamt in DIV-Tags eingebettet sind. In Listing 4.10 wurde ein sehr ähnliches Beispiel gezeigt. Das derzeit noch leere <div id="msgOut"> verwenden wir wie üblich dafür, dass wir eine Statusmeldung an den User ausgeben. Sobald der Button „Abschicken“ geklickt wird, wird die Funktion sendContact aufgerufen. Fraglich ist jedoch, wo sich diese Funktion befindet, da in der Datei kontakt.htm keinerlei Hinweis auf eine JavaScript-Funktion gefunden wer- den kann. Wenn wir jedoch die Datei index.htm genauer betrachten, finden wir in ihr einen Verweis auf eine JavaScript-Datei kontakt.inc.js: <script language="javascript" type="text/javascript" src="js/kontakt. inc.js"></script> Listing 4.27: Die verknüpfte Datei kontakt.inc.js befindet sich in der Datei index.htm und nicht in kontakt.htm.
  • 168.
    A J AX – A S Y N C H R O N U S J AVA S C R I P T A N D X M L 155 An dieser Stelle möchte ich Sie bewusst auf einen Punkt hinweisen, der bei der Ent- wicklung erster AJAX-Anwendungen sehr häufig auftritt: das Abfragen von Doku- menten mit inkludierten JavaScript-Anweisungen, die per responseText einem Dokument hinzugefügt werden. Einschub: AJAX und JavaScript Beim Einfügen von XHTML-basiertem Code, der per responseText von einer XMLHttpRequest-Instanz bereitgestellt wurde, wird der Code als reiner Text einem bereits bestehenden Element hinzugefügt. Sollte dieser XHTML-Code JavaScript bein- halten (was für manche Anwendungen erwünscht sein kann), so wird dieser nicht als JavaScript, sondern als normaler Text interpretiert. Ein Ausweg aus dieser Misere ist die Verwendung der eval-Funktion: Sie weist den Interpreter an, einen String so zu verarbeiten, als wäre er ein echter JavaScript-Code. Nehmen wir den einfachen Fall, dass per AJAX ein Dokument simplejs.js angefor- dert wird, das reinen JavaScript-Code (und nicht mehr!) beinhaltet: alert("Ein erster Test"); Das Dokument besteht also aus nur einer einzigen Zeile. Fordern wir nun dieses Dokument wie gewohnt an, so würden wir wie folgt verfahren: function showResponse() { document.getElementById("msgOut").innerHTML = myXMLHttpRequest. responseText; } function sendRequest() { myXMLHttpRequest.open("GET", "simplejs.js", true); myXMLHttpRequest.send(null); } Listing 4.28: Die für unser Beispiel wichtigen Funktionen sendRequest und showResponse in der Datei ajax03.htm Die Funktion sendRequest fordert die Datei simplejs.js an und showResponse gibt wie gewohnt den Inhalt dieser Datei in ein leeres DIV aus. Statt dass der Code ausge- führt wird, wird er als reiner Text ausgegeben: AJAX und JavaScript AJAX und JavaScript
  • 169.
    K A PI T E L 4156 Gut, da könnten Sie noch antworten: „War ja klar – binden wir doch ein XHTML- Dokument ein, das den Code schön zwischen <script> und </script> verpackt!“ Gesagt, getan, versuchen wir die Datei simplejs.htm und ändern den Aufruf in der Funktion sendRequest entsprechend: <script language="javascript" type="text/javascript"> alert("Ein erster Test"); </script> Listing 4.29: Code von simplejs.htm ... myXMLHttpRequest.open("GET", "simplejs.htm", true); ... Listing 4.30: Anfrage der Datei simplejs.htm Der geänderte Aufruf führt zu folgendem Ergebnis (ajax03a.htm): ABBILDUNG 4.12 Statt dass der JavaScript- Code ausgeführt wird, wird er als Text ins Dokument eingebettet.
  • 170.
    A J AX – A S Y N C H R O N U S J AVA S C R I P T A N D X M L 157 Leider ist unser Versuch gescheitert – das Ergebnis des Beispiels ist nicht besser gewor- den, denn jetzt sehen wir gar nichts mehr. Versuchen wir es also noch mal anders. Verwenden wir wieder die Datei simplejs.js (mit nichts als JavaScript-Code im Inhalt) und versuchen die eval-Methode bei der Ausgabe der Rückgabe (ajax03b.htm): function showResponse() { document.getElementById("msgOut").innerHTML = eval(myXMLHttpRequest. responseText); } function sendRequest() { myXMLHttpRequest.open("GET", "simplejs.js", true); myXMLHttpRequest.send(null); } Listing 4.31: Wir verwenden die Methode eval sowie die zuvor erstellte Datei simplejs.js. Wir erhalten nun (fast) das gewünschte Ergebnis: ABBILDUNG 4.13 Diesmal liefert unsere Anfrage gar nichts …
  • 171.
    K A PI T E L 4158 Die Ausgabe des Textes „undefined“ ist verständlich, da wirListing . einem Container einen XHTML-Text zuweisen, der nicht vorhanden ist (es wurde lediglich JavaScript- Code ausgeführt). Wir korrigieren also die Ausgabe der JavaScript-Datei wie folgt: Aus function showResponse() { document.getElementById("msgOut").innerHTML = eval(myXMLHttpRequest. responseText); } ABBILDUNG 4.14 Fast wie gewünscht: einzig der Text „undefined“ wird ausgegeben.
  • 172.
    A J AX – A S Y N C H R O N U S J AVA S C R I P T A N D X M L 159 wird function showResponse() { eval(myXMLHttpRequest.responseText); } Listing 4.32: Die Ausgabe an das DIV-Tag „msgOut“ wurde entfernt, da wir nur JavaScript-Code ausführen und nichts weiteres an das Dokument ausgeben wollen (ajax03c.htm). Halten wir also fest: Wenn Sie eine reine JavaScript-Datei anfordern und abarbeiten wollen, so müssen Sie den Rückgabewert von AJAX (responseText) mit der Methode eval abarbeiten lassen, sodass der Code als Code und nicht als Text interpretiert wird. Diese Variante funktioniert übrigens auch, wenn Sie mit Funktionen in der JavaScript- Datei arbeiten (simplejs2.js): function myAlert(msg) { alert(msg); } myAlert("Ein erster Test"); Listing 4.33: Eine Funktion anstatt eines direkten Aufrufs von alert Wie stellt sich die Sachlage jedoch dar, wenn wir eine XHTML-Datei anfordern, die sowohl aus XHTML als auch aus JavaScript-Code besteht? Nehmen wir folgendes Beispiel (notsosimplejs.htm): <script language="javascript" type="text/javascript"> alert("Ein zweiter Test"); </script> <p>So - wir erwarten eine alert-Box sowie die Ausgabe dieses Textes auf dem Bildschirm!</p> <script language="javascript" type="text/javascript"> <!-- function myAlert(msg) { alert(msg); } myAlert("Ein dritter Test"); //--> </script> <p>Und noch ein Text!</p> Listing 4.34: Eine gemischte XHTML-Datei (XHTML und JavaScript) JavaScript- Dateien anfor- dern und Code ausführen JavaScript- Dateien anfor- dern und Code ausführen
  • 173.
    K A PI T E L 4160 An dieser Stelle bleibt uns dann nicht mehr viel anderes übrig, als den XHTML-Code zu parsen und den JavaScript-Code vom XHTML-Code zu trennen. Hierbei bedient man sich gerne sogenannter „Regular Expressions“. Sie werden verwendet, um in Strings gewisse Suchausdrücke zu definieren und diese durch andere Strings zu erset- zen. Mithilfe der JavaScript-Methode RegExp können wir direkt zur Laufzeit Scripts erzeugen (Details zur Funktion RegExp entnehmen Sie bitte beispielsweise der Website http://de.selfhtml.org). Wir werden also versuchen, den XHTML-Code vom JavaScript-Code zu trennen, danach den JavaScript-Code auszuführen und den XHTML-Code in unserem Ausga- be-DIV (<div id="msgOut">) auszugeben. Zunächst laden wir hierzu die Antwort vom Server in eine Variable respRaw: var respRaw = myXMLHttpRequest.responseText; Nun definieren wir einen ersten String, den wir aus dieser Variable entfernen wollen, da er uns bei der Ausführung von JavaScript-Code stören wird. Des Weiteren legen wir eine Instanz des Objekts RegExp an: var findStr = "(?:<script.*?>)((n|r|.)*?)(?:</script>)"; var myRegExp = new RegExp(findStr,"img"); Der Instanz myRegExp werden zwei Parameter übergeben: Parameter 1 bezeichnet den Ausdruck, der innerhalb eines Textes gefunden werden soll. In unserem Fall sind das alle Tags, die mit „<script .. >“ anfangen (mit beliebig vielen Attributen zwischen „<script“ und „>“), alle Zeilenumbrüche ( n), alle Wagenrückläufe (r) sowie alle Tags „</script>“. Parameter 2 kann folgende Einstellungen bezeichnen: g: Kennzeichnet ein „global matching“: Es werden im Fall der Verwendung von replace alle gefundenen Ausdrücke von Parameter 1 aus dem String entfernt. i: Kennzeichnet, dass wir Groß- und Kleinschreibung nicht beachten (case- insensitive). m: Kennzeichnet den Multiline Mode – somit werden vor und nach neuen Zeilen Ausdrücke mit einem beginnenden $ oder ^ gesucht (diese Einstellung gibt es nur in JavaScript 1.5 und höher). Um nun den XHTML-Teil vom JavaScript-Teil zu trennen, müssen wir also aus dem Antworttext vom Server (respRaw) für den XHTML-Teil genau diesen String entfer- nen und für den JavaScript-Teil genau diesen Teil aufheben – dazu verwendet man die Methoden match und response: u u u u u
  • 174.
    A J AX – A S Y N C H R O N U S J AVA S C R I P T A N D X M L 161 var xhtml = resp.replace(myRegExp,""); var js = resp.match(myRegExp); Listing 4.35: Entfernen des Suchstrings mit replace (genau gesprochen: Ersetzen des Suchstrings mit „“) und speichern des Suchstrings mit match. Den XHTML-Teil müssen wir nicht mehr verändern, dieser ist bereits komplett und wartet auf seine Ausgabe. Den JavaScript-Teil hingegen müssen wir nun wieder von den Tags <script> und </script> säubern, da wir – wie wir weiter oben schon besprochen haben – für die Abarbeitung des Codes die Methode eval verwenden und diese nur puren JavaScript-Code ausführen kann. (Zur Erinnerung: Das Tag <script> gehört nicht zum Sprachumfang von JavaScript, sondern von XHTML.) Des Weiteren stört uns auch die Kommentarkennzeichnung aus HTML „<!--“, die ebenfalls ent- fernt gehört: var myRegExp3 = new RegExp(findStr,"im"); for(var i=0; i<js.length; i++) { var toEval = js[i].match(myRegExp3)[1].replace(/<!--/g,""); eval(toEval); } Listing 4.36: Entfernen des ursprünglichen Suchstrings aus js sowie Entfernen des Strings „<!--“ mittels replace Nachdem also unser JavaScript-Code ausgeführt wurde, geben wir auch noch den XHTML-Code im dafür vorgesehenen Container aus: document.getElementById("msgOut").innerHTML = xhtml; Listing 4.37: Ausgabe der Variable xhtml in den Container msgOut Damit können wir den Einschub: AJAX und JavaScript abschließen und uns wieder unserer Miniwebsite widmen. Wir sind bei der in index.htm eingebundenen Datei kontakt.inc.js stehen geblieben – werfen wir einen Blick darauf: var contactXMLHttpRequest; function sendContact() { contactXMLHttpRequest = createRequestObject(); contactXMLHttpRequest.onreadystatechange = handleRequestContact; var querystring = "Email="+document.forms["frmKontakt"]. elements["Email"].value+"&Nachricht="+document.forms["frmKontakt"]. elements["Nachricht"].value contactXMLHttpRequest.open("GET", "includes/kontakt.inc. php?"+querystring, true);
  • 175.
    K A PI T E L 4162 contactXMLHttpRequest.send(null); } function showResponse2() { document.getElementById("msgOut").innerHTML = contactXMLHttpRequest. responseText; } function handleRequestContact() { document.forms["frmKontakt"].elements["msgStatus"].value += contactXMLHttpRequest.readyState+"n"; switch(contactXMLHttpRequest.readyState) { case 0: case 1: case 2: case 3: return; case 4: showResponse2(); return; } } Listing 4.38: Der Inhalt der Datei kontakt.inc.js Da der Code aus einem vorigen Beispiel (siehe Listing 4.11) bereits bekannt ist, fasse ich noch einmal zusammen: 1. Die Variable contactXMLHttpRequest dient als Instanz für den XMLHttpRequest. 2. Bei Aufruf von sendContact wird contactXMLHttpRequest zur Instanz von XMLHttpRequest und es wird ihr ein Eventhandler handleRequestContact zugewiesen. In diesem Atemzug werden auch ein Querystring (Variable querystring) mit allen eingegebenen Daten aus dem Formular sowie der open- Aufruf an die Datei kontakt.inc.php durchgeführt. 3. Hat contactXMLHttpRequest die Eigenschaft readyState==4 erreicht (der Datentransfer von Server zu Client ist abgeschlossen), wird die Funktion showResponse2 aufgerufen. Solange dies nicht der Fall ist (also readyState<4), passiert nichts. 4. Die Funktion showResponse2 sorgt dafür, dass der Rückgabewert von kontakt. inc.php (dies wird eine Erfolgs- oder Misserfolgsmeldung sein) in dem leeren DIV msgOut dargestellt wird.
  • 176.
    A J AX – A S Y N C H R O N U S J AVA S C R I P T A N D X M L 163 Da wir auch die Funktionsweise der Datei kontakt.inc.php bereits in Listing 4.12 ausführlich besprochen haben, bleibt uns nichts weiter zu tun, als kurz zusammenzu- fassen: 1. Durch den send-Aufruf der XMLHttpRequest-Instanz wird auf Serverseite die Datei kontakt.inc.php aufgerufen, wobei dieser der oben genannte Querystring mit den Formularfeldwerten übermittelt wird (als GET-Variable). 2. Innerhalb von kontakt.inc.php wird eine Funktion definiert (und selbstverständlich auch aufgerufen), die aus den gegebenen Daten eine E-Mail „bastelt“ und diese mithilfe der mail-Funktion verschickt. 3. Liefert mail den Wert true zurück, war der Mail-Versand erfolgreich und es wird eine Erfolgsmeldung per echo als XHTML ausgegeben; im Fall eines Misserfolgs wird eine Misserfolgsmeldung ausgegeben. In jedem Fall bildet der so erzeugte XHTML-Code den Rückgabewert an die XMLHttpRequest-Instanz. Das Ergebnis können Sie wie gewohnt (nachdem Sie die Daten online gestellt haben) in einem Browser testen: ABBILDUNG 4.15 Wie zu erwarten, hat alles funktioniert – die E-Mail wurde versandt (siehe fol- gende Abbildung). Und hier noch – quasi als Beweis – die empfangene E-Mail:
  • 177.
    K A PI T E L 4164 Bilden wir ein Resümee zu unserer Website-Entwicklung. Wie wir gesehen haben, sind zwar alle gängigen Anforderungen an eine Website erfüllt worden: Wir konnten statische, dynamische sowie AJAX-basierte Dokumente einbinden. Jedoch muss man auch offen gestehen, dass es immer wieder einiger Tricks bedurfte, um letzten Endes das Ziel zu erreichen – und genau so ein„Tricksen“ ist nicht sinnvoll! Man sollte immer die optimale Technologie für den optimalen Fall verwenden und nicht zwanghaft auf eine Technologie setzen, die für die gegebene Anwendung gar nicht so sehr geeignet ist. AJAX leistet große Dienste, wenn im Nachhinein Daten in ein Dokument hinzugela- den werden sollen – wir meinen jedoch zumeist statische Information wie zusätzliche Texte, Grafiken etc. In nur wenigen (Ausnahme-)Fällen ist von dynamischen oder gar AJAX-basierten Daten die Rede. In den nächsten beiden Kapiteln wollen wir uns deshalb ein bisschen die Augen öffnen lassen für Anwendungsgebiete, in denen AJAX Platz findet – vor allem liegt uns jedoch das Zusammenspiel mit Flash am Herzen! 4.4 Flash vs. AJAX Wie wir aus den Darstellungen des letzten Kapitels gesehen haben, ist AJAX in der Lage, nachträglich und ohne Neuladen des Webdokuments Daten vom Server nach- zuladen – sogar dynamische wie AJAX-basierte Dokumente können (ausgewertet und) nachgeladen werden. Flash kann das schon sehr lange und deshalb wurden viele Anwendungen, in denen immer wieder mal Daten nachgeladen werden müssen (aber deshalb die Seite nicht neu geladen wird) in Flash realisiert. Man denke beispielsweise an Chat-Systeme – eine typische Flash-Domäne (sehen wir einmal von ActiveX-Kom- ponenten oder Applets ab). Warum war Flash eigentlich immer schon in der Lage, das zu tun, was mit AJAX mühsam eingeführt wurde? Nun, das liegt daran, dass AJAX auf Standardtechnologien ABBILDUNG 4.16 Die versandte E-Mail ist angekommen – was wollen wir noch mehr?
  • 178.
    A J AX – A S Y N C H R O N U S J AVA S C R I P T A N D X M L 165 basiert, die jeder halbwegs gängige Browser unterstützt: XHTML und JavaScript. Flash hingegen ist ein Plug-in, das ein User selbstständig installieren muss (sollte es nicht bereits installiert sein). Solche Plug-ins haben wesentlich mehr „Rechte“ im Browser des Users als die Standardtechnologien. Dies liegt mitunter auch daran, dass wir User selbst das Einverständnis dafür gegeben haben: Mit dem Zeitpunkt der Installation haben wir Flash implizit „erlaubt“, das zu tun, was Flash imstande ist – dazu gehört unter anderem auch das Nachladen von Daten beispielsweise mithilfe des LoadVars- Objekts, das wir im Laufe dieses Buchs noch genau kennenlernen werden. Nachdem die Applikation„Flash“ immer noch (und das wird es auch immer bleiben) ein rotes Tuch in den Augen mancher User im Internet ist (O-Ton:„Dieses Flash: Alles dreht sich und überall wird böse Musik abgespielt!“), hat man mit AJAX nun eine Möglichkeit, einige der Anwendungen zu realisieren, die man ursprünglich nur mit Flash (oder einem anderen Plug-in) realisieren konnte. Man könnte also sagen, dass Flash in gewissen Bereichen des Internets ein bisschen an Boden verlieren wird. Speziell in Hinblick auf News-Systeme (Anzeigen der aktuellsten Newsticker in einem regelmäßigen Abstand), dynamische Grafiken (Börsenkurse usw.), Chat-Systeme, dynamische Auswahlsysteme (Google Suggest, Suche in wikipedia.de usw.) stellt AJAX eine ernst zu nehmende Kon- kurrenz zu Flash dar. Wobei – und das sollte man nicht außer Acht lassen! – Flash für solchen Anwendungen oft auch nur eine „Notlösung“ war: Warum sollte man für einen simplen Newsticker Flash installiert haben, wenn die Darstellung der News ja lediglich Textinformationen sind? XHTML ist dafür wesentlich besser geeignet. Ein Killerargument für Flash ist selbstverständlich die Plattformunabhängigkeit: Egal, ob eine Flash-Anwendung auf einem PC, Mac oder einem Handy angezeigt wird – sie wird immer gleich ablaufen. Im Fall von AJAX-Anwendungen können wir das nicht behaupten, da wir immer noch mit unterschiedlichen Browsern rechnen müssen. Viel wichtiger, als herauszufinden, wo AJAX Flash eine Konkurrenz sein kann (eigent- lich ist es ja müßig, darüber überhaupt nachzudenken), ist es, herauszufinden, wo diese beiden großartigen Technologien zusammenarbeiten können – die Devise lautet also „Flash & AJAX“ statt „Flash vs. AJAX“. 4.5 Flash & AJAX Viel interessanter ist also die Frage, in welcher Hinsicht Flash und AJAX zusammenspie- len können oder AJAX eine (zusätzliche) Alternative zu Flash bietet. Um diese Frage zu beantworten, müssen wir uns zunächst einmal bewusst werden, welche der möglichen Technologien in welchen Bereichen Vor- und in welchen Bereichen Nachteile aufweist. Bereich AJAX Flash Kein Plug-in erforderlich + - Darstellen von ausschließlich Textinformationen (inklusive Bildern) + - Darstellen von pixelbasierten Grafiken + +
  • 179.
    K A PI T E L 4166 Bereich AJAX Flash Darstellen von Vektorgrafiken - + Darstellen von Animationen - + Darstellen von weiteren multimedialen Inhalten - + Arbeiten mit Formularen und Formularinhalten + +/- Browser-Unterstützung + +/- Akzeptanz des Users + +/- Barrierefreiheit - +/- Schnelligkeit in der Darstellung + + Kompatibilität zwischen verschiedenen Versionen - browserabhängig + Programmiermodell +/- JavaScript 1.5 wird bei größeren OOP- Anwendungen nicht empfohlen + Unterstützung von XML-Darstellung - + Tabelle 4.6: Übersicht von Vor- und Nachteilen der Technologien AJAX und Flash (ohne Anspruch auf Vollständigkeit) Aus der obigen Tabelle ergeben sich folgende Synergien: Einsatz von AJAX und Flash parallel: Sollten Sie die Möglichkeit haben, eine Flash- Anwendung in AJAX nachzubauen (Newsticker, Auswahlsysteme etc.), so ist dies für den User positiv, da Sie den User nicht zum Einsatz von Flash nötigen müssen. Somit nutzen Sie den Vorteil, dass der User kein Flash-Plug-in installiert haben muss und trotzdem interaktiv arbeiten kann. Im Rahmen der Workshops werden wir beispielsweise ein Chat-System entwickeln, das sowohl in Flash als auch in XHTML gleichermaßen gut funktioniert. Interaktive Darstellung von Bildern/Statistiken: Über Standard-XHTML-Doku- mente wird der User zur Eingabe diverser Daten aufgefordert (beispielsweise Tabel- len wie etwa ein „Online-Excel“). Die Grafiken werden dynamisch mit jeder Ein- gabe in einer Flash-Anwendung angezeigt. Generell ist Flash zum Visualisieren von Informationen (basierend auf beispielsweise XML-Daten hervorragend geeignet). Letzten Endes ist die Kombination von Flash und AJAX immer dann sinnvoll, wenn man die Vorteile beider Welten miteinander kombinieren möchte. Flash ist in der Lage, alles abzudecken, was AJAX kann – dementsprechend könnte man sagen, dass für einen Flash-Entwickler AJAX keinen Vorteil bringen würde. Nachteilig ist ja nur, dass Flash ein Plug-in ist … Doch nachdem ein Web-Designer kein reiner Flash-Entwickler ist und selbst Flash- Entwickler hin und wieder über den eigenen Tellerrand blicken sollten, kann man AJAX als „Flashlose“ Alternative betrachten. Denn anders gefragt: Warum sollte man auf die Idee kommen, beispielsweise ein Webmail-System mit Flash zu programmie- ren, wo man doch die wirklichen Vorteile von Flash gar nicht nützen kann? Hier ist man mit AJAX viel besser aufgehoben. In den folgenden Kapiteln werden wir uns ausführlich mit den Möglichkeiten von Flash & AJAX befassen – also nehmen Sie sich nicht zu viel vor, wenn Sie gerade am Buchlesen sind, denn Sie werden das Buch nicht mehr weglegen können. u u
  • 180.
    5 CLIENTSEITIGER DATENAUSTAUSCH – FLASH &JAVASCRIPT In den folgenden Kapiteln befassen wir uns mit der Frage, wie Flash mit seiner Umgebung Daten austauschen kann – einer- seits serverseitig mit dem Webserver und andererseits clientsei- tig mit dem Browser über das Flash-Plug-in. Die Schnittstelle zur Außenwelt … Bei dieser Betrachtung wer- den wir die zwei Bereiche server- und clientseitig voneinander trennen, da hier zwei ganz verschiedene Vorgehensweisen von- nöten sind. Wenn man von clientseitigem Datenaustausch spricht, so meint man immer zwei Richtungen: Der Browser sendet Daten an Flash. Flash versendet Daten an den Browser. Wie Sie wissen, stehen uns auf Clientseite zwei Technologien zur Verfügung, die uns beim Datenaustausch behilflich sein können – (X)HTML und JavaScript. (X)HTML ist die Bezeich- nungssprache, die für den Aufbau des Webdokuments verwen- det wird. JavaScript hingegen ermöglicht uns eine Interaktion mit dem User und den eingebundenen Objekten. Dadurch wird JavaScript diejenige der beiden genannten Technologien sein, die uns beim Datenaustausch hilfreich zur Seite steht. u u
  • 181.
    K A PI T E L 5168 XHTML versus HTML Jedes Webdokument basiert auf einer Bezeichnungssprache. Ursprünglich wurde die Bezeichnungssprache HTML verwendet, die sich jedoch als nicht sehr konsistent erwiesen hat, werden doch zu viele Ungereimtheiten geduldet wie beispielsweise das Schließen der meisten, aber nicht aller Tags. HTML stammt direkt vom übergeordneten Standard SGML (Standard Generalized Markup Language) ab, XHTML hingegen von XML (Extended Markup Language), das wiederum von SGML abstammt. Nachdem XML in seiner Anwendung sehr strikt und konsequent ist (sprich: keine Fehler duldet) und XHTML diese Eigenschaften vererbt wurden, ist XHTML in der Anwendung ebenfalls nicht fehlertolerant. Letzten Endes ist dies eine große Erleichterung für jeden Webdesigner, da ihm weniger Fehler erlaubt werden und sein Code dadurch immer besser wird. HTML wird seit der Version 4.01 nicht mehr weiterentwickelt – an seine Stelle ist XHTML 1.0 getreten. In diesem Buch werden wir konsequent mit XHTML arbeiten. 5.1 Daten senden: Browser an Flash Man kann auf zwei Arten Daten an Flash übergeben: 1. Es wird von JavaScript auf die SWF-Datei zugegriffen und dort innerhalb der SWF-Datei eine Variable gesetzt: Diese Variante hat den Vorteil, dass das Senden von Daten an Flash beispielsweise auch über einen Klick auf einen Button erfolgen kann – sprich durch eine Benutzereingabe. Nachteilig ist, dass verschiedene Browser diese Variante unterschiedlich unterstützen. 2. Über geeignete Attribute im HTML-Code werden direkt beim Laden der SWF- Datei Daten an die SWF-Datei übergeben: Entgegen der oben genannten Variante besteht hier keine Möglichkeit, per Benutzereingabe Daten an die SWF-Datei zu senden. Der grundlegende Vorteil dieser Variante ist, dass alle gängigen Browser eine Datenübergabe in dieser Form unterstützen. Im Folgenden werde ich auf diese beiden Varianten genauer eingehen. 5.1.1 Variante 1: JavaScript greift auf die SWF-Datei zu Für den Fall, dass der Browser mittels JavaScript Daten an Flash übermitteln soll, sind folgende Schritte notwendig: 1. JavaScript muss die eingebundene SWF-Datei bzw. Flash-Datei eindeutig identifizieren können. 2. MithilfeeinesgeeignetenBefehlswirdeineVariableinderFlash-Dateiangesprochen und es wird dieser ein Wert zugewiesen.
  • 182.
    C L IE N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 169 Die einzige Variante, um vom Browser aus Daten an Flash zu übermitteln, ist die, dass man Flash-Variablen einen Wert zuweist. Hierbei ist es nicht zwingend notwendig, dass die Variable zu diesem Zeitpunkt bereits existiert – Flash ist in der Lage, dyna- misch Variablen anzulegen, wie Sie in den vorigen Kapiteln bereits erfahren haben. Einbinden von Flash Je nach verwendetem Browser wird die Flash-Datei entweder mit dem <object>- (Standard-HTML, Internet Explorer) oder dem <embed>-Tag (Mozilla-basierte Brow- ser wie etwa der Netscape Navigator) in die HTML-Datei eingebunden. Damit die Flash-Datei in diesem HTML-Dokument eindeutig identifiziert werden kann, wird das <object>- bzw. das <embed>-Tag mit dem id-Attribut eindeutig gekennzeichnet. Im Allgemeinen wird eine Flash-Datei mithilfe beider Tags eingebunden – dadurch hat man beiden größeren Browser-Typen Genüge getan und sichergestellt, dass die Datei auch wirklich verarbeitet werden kann. <object id="myFlash" classid="clsid:D27CDB6E-AE6D-11cf-96B8- 444553540000" codebase="http://download.macromedia.com/pub/shockwave/ cabs/flash/swflash.cab#version=6,0,29,0" width="200" height="150"style="bo rder:1px solid #999999;"> <param name="movie" value="browserAnFlash01.swf" /> <param name="quality" value="high" /> <embed id="myswf" name="myFlash" src="browserAnFlash01.swf" width="200" height="150" quality="high" pluginspage="http://www.macromedia.com/go/ getflashplayer" type="application/x-shockwave-flash"></embed> </object> Listing 5.1: Einbinden einer Flash-Datei in HTML-Code classid und codebase Mit dem Attribut classid gibt man an, welche Applikation in die Seite eingebun- den werden soll. Jede (einbindbare) Applikation hat eine eigene eindeutige classid (classid = class identifier = Klassenbezeichner). Die Angabe besteht aus der fest vorgegebenen Zeichenfolge CLSID:, gefolgt von der Bezeichner-ID. Im Fall von Flash ist das: classid="CLSID:D27CDB6E-AE6D-11cf-96B8-444553540000". Mithilfe der codebase kann eine Quelle für das Downloaden der Applikation angege- ben werden. Im Fall von Flash ist dies das Flash-Plug-in. Auf die codebase wird dann zugegriffen, wenn das benötigte Plug-in nicht im Browser des Users installiert ist. Die Attribute id und name Wie man aus dem obigen Codefragment leicht erkennen kann, wurde das id-Attri- but in beiden genannten Tags gleichermaßen angewendet. Grundsätzlich ist es nicht erlaubt, ein und dieselbe ID mehrmals zu verwenden. Nachdem jedoch in allen Fäl-
  • 183.
    K A PI T E L 5170 len nur eines der beiden Tags zum Einsatz kommt, stellt dies kein Problem dar: Der Internet Explorer von Microsoft ignoriert das in das <object>-Tag verschachtelte <embed>-Tag, genau wie der Netscape Navigator das <object>-Tag ignoriert. Viel- mehr wäre dieser Einsatz von IDs für uns sogar ein großer Vorteil, da wir somit auf eine immer gleiche ID zugreifen können. Anders verhält es sich beim name-Attribut. Im Weiteren werden wir sehen, dass es keine einheitliche Möglichkeit gibt, um eine eingebundene Flash-Datei über JavaScript anzusprechen. Aus diesem Grund möchte ich an dieser Stelle folgenden Tipp geben: Verwenden Sie das id-Attribut für das <object> und <embed>. Verwenden Sie das name-Attribut nur für das <embed>. Nachdem dieser (wichtigste) Schritt erledigt ist, ist unsere Flash-Datei eindeutig iden- tifizierbar und kann nun per JavaScript angesprochen werden. An dieser Stelle muss man – wie es der Webdesigner leider schon allzu oft gewohnt ist – zwischen verschie- denen Browsern unterscheiden. Allgemein dient der Befehl SetVariable dazu, auf Variablen innerhalb von Flash zuzugreifen. Hierzu müssen diesem Befehl zwei Attribute zugewiesen werden: SetVariable("Variablenname", Wert); Dieser Befehl muss noch auf das Flash-Objekt angewandt werden – man muss sich also Zugriff auf die eingebundene Flash-Datei verschaffen. Sofern der verwendete Brow- ser das DOM (Document Object Model) für JavaScript unterstützt, ist der geeignete Befehl in JavaScript getElementById. Den eher ungewöhnlichen Fall (dass dieser Fall gar nicht so ungewöhnlich ist, werden wir leider weiter unten noch sehen …) einmal ausgeschlossen, dass das DOM nicht unterstützt wird, lautet der vollständige Zugriff auf die eingebundene Flash-Datei demnach wie folgt: document.getElementById("ID des Elements").SetVariable("Variablenname", Wert); Listing 5.2: DOM-korrekte Syntax für den Zugriff auf eine Flash-Variable per JavaScript Alternativ dazu lässt sich im Internet Explorer jedes vorhandene Element auch über document.all ansprechen, also: document.all["ID des Elements"].SetVariable("Variablenname",Wert); Listing 5.3: Alternative Syntax für den Internet Explorer Um den Code für alle gängigen Browser zu optimieren, müssen wir jedoch ein biss- chen tiefer in die Trickkiste greifen. Je nach Browser möchte das Flash-Plug-in unter- schiedlich angesprochen werden. Einerseits haben wir gesehen, wie es der Internet Explorer „gerne hätte“, andererseits müssen wir uns an dieser Stelle auch noch um den u u id für <object>, name für <embed> id für <object>, name für <embed> DOM-korrekte Syntax DOM-korrekte Syntax Internet Explorer Syntaxalternative Internet Explorer Syntaxalternative Firefox Syntaxalternative Firefox Syntaxalternative
  • 184.
    C L IE N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 171 (beliebten) Browser namens Firefox kümmern – dieser möchte wiederum, dass er über das embeds-Objekt angesprochen wird, also: document.embeds["Name des Elements"].SetVariable("Variablenname",Wert); Listing 5.4: Syntax für den Zugriff auf eine Flash-Variable per JavaScript im Firefox Wie nicht anders zu erwarten war, funktioniert die Sache leider nicht im Safari-Brow- ser unter Mac OS. Somit bleibt uns nichts anderes übrig, als noch tiefer in der Trick- kiste zu stöbern … Grundsätzlich kann man auch direkt über das document-Objekt auf HTML-Elemente zugreifen, sofern der Browser das zulässt: document["Name des Elements"].SetVariable("Variablenname", Wert); Listing 5.5: Alternative Schreibweise, um auch noch den Safari-Browser „mit ins Boot“ zu holen. Fassen wir all die Varianten zusammen, um schlussendlich ein Script zu erhalten, mit dem der Zugriff auf die Flash-Datei in allen gängigen Browsern möglich ist, so erhalten wir: function getFlashElement(elem) { var app = navigator.appName.toLowerCase(); var nav = navigator.userAgent.toLowerCase(); if((app.indexOf("microsoft") != -1 || nav.indexOf("microsoft") != -1) && !Boolean(window["opera"])) { return document.all[elem]; } else { return document[elem]; } } function sendDataToFlash() { var myswf = getFlashElement("myswf"); myswf.SetVariable("myVar", "EXPLODE"); } Listing 5.6: Universalzugriff auf eine eingebundene Flash-Datei Zur Erklärung: Die Funktion getFlashElement() findet den korrekten„Zugang“ zur Flash-Datei und liefert die entsprechende Referenzierung an das aufrufende Script zurück: Sollte es sich um den Internet Explorer handeln (und nicht um einen Opera- Browser, der sich als Internet Explorer ausgibt), so liefert es document. all[elem] zurück. Sollte es sich nicht um den Internet Explorer handeln, so erhält man document[elem]. u u u
  • 185.
    K A PI T E L 5172 Die Funktion sendDataToFlash() ruft die oben genannte Funktion auf, um kor- rekt auf die Flash-Datei zuzugreifen, und setzt danach mit der Methode SetVari- able eine Variable namens myVar auf den Wert „EXPLODE“. Aktion in Flash auslösen Sehen wir uns dies an einem Beispiel an: Einmal angenommen, man möchte durch Klicken auf einen HTML-Button in Flash eine Aktion auslösen. Nachdem man per JavaScript einzig und allein Variablenwerte in Flash setzen kann, ist der Aufruf einer Funktion in Flash also nicht möglich. Man umgeht dieses Problem, indem man in Flash so lange auf einen gewissen Wert einer Variablen„wartet“, bis dieser – in unserem Fall mittels JavaScript – gesetzt wird. Im Kapitel über die ExternalInterface-Klasse werden wir sehen, dass das Procedere „Warten auf das Setzen einer Variable“ wegfällt, da es uns diese Klasse ermöglicht, direkt aus JavaScript auf ActionScript-Funktionen zuzugreifen – eine große Erleichte- rung, die jedoch erst seit Flash 8 funktioniert. Schritt für Schritt: Flash-Aktion per JavaScript In Flash benötigen wir für dieses Beispiel vier (vorerst) leere Bilder in der Zeitleiste. Wie üblich legen wir für unseren ActionScript-Code eine eigene Ebene in der Zeitleiste an und benennen sie mit „Aktionen“. Die darüberliegende Ebene beinhaltet nichts anderes als Bildnamen. Solche Bildnamen erleichtern die Übersichtlichkeit in Pro- grammen enorm, außerdem ist das nachträgliche Einfügen von Bildern so auch kein Problem für das korrekte Ausführen des Codes. Arbeitet man nicht mit Bildnamen, sondern mit den Bildnummern, müsste man nach dem Einfügen oder Löschen von Bildern immer überprüfen, ob nicht ein Codefrag- ment auf eine spezielle Bildnummer zugreift, die sich nun eventuell geändert hat. u External- Interface-Klasse als Erleichterung External- Interface-Klasse als Erleichterung 1. Bilder anlegen1. Bilder anlegen
  • 186.
    C L IE N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 173 In der untersten Ebene befinden sich je nach Bild in der Zeitleiste verschiedene Texte. Dies hilft uns dabei, uns bei der Darstellung der Flash-Datei im Browser leicht zurecht- zufinden. Anhand der ausgegebenen Texte können wir leicht überprüfen, ob unser Code funktioniert. Im ersten Bild – dem Initialisierungsbild der Zeitleiste – deklarieren wir eine Variable namens myVar vom Typ String und weisen dieser den Wert "" (leerer String) zu. Zur Erinnerung: Möchten Sie in ein Bild der Zeitleiste ActionScript-Code schreiben, so müssen Sie das Bild in der Zeitleiste markieren und danach im ActionScript-Editor den Code eingeben. Sollte der Editor nicht eingeblendet sein, so finden Sie diesen in der Menüzeile im Menü FENSTER bzw. durch Drücken der Taste (F9). var myVar:String = ""; Im Folgenden werden wir diese Variable auf ihren Wert abfragen. Im zweiten Bild wird kein Code ausgeführt. Dieses Bild bekommt jedoch einen Namen („warten“), den wir zum Zurückspringen verwenden werden. Um einem Bild der Zeitleiste einen Namen zu geben, muss es in der Zeitleiste zuerst markiert werden und danach im Eigenschaften-Inspektor im Feld „Bild“ ein Name eingetragen werden. 2.Variablen- deklaration 2.Variablen- deklaration 3. Namens- gebung für das „Wartebild“ 3. Namens- gebung für das „Wartebild“ ABBILDUNG 5.1 Das fertig programmierte Beispiel – hier unser erstes Bild in der Zeitleiste
  • 187.
    K A PI T E L 5174 Im dritten Bild wird der Wert von myVar abgefragt – sollte dieser (immer noch) auf "" gesetzt sein, springen wir auf das Bild mit dem Namen „warten“ zurück. Dies geschieht so lange, bis die Variable einen String beinhaltet, der ungleich "" ist. if(myVar=="") { gotoAndPlay("warten"); } 4.Wert von myVar abfragen 4.Wert von myVar abfragen ABBILDUNG 5.2 Dem zweiten Bild wird kein ActionScript-Code zugewie- sen, es dient vielmehr nur als „Sprungbild“ zum Warten auf das Setzen von myVar durch den externen JavaScript- Code. ABBILDUNG 5.3 Wurde durch den externen JavaScript-Code myVar auf einen Wert ungleich "" gesetzt, so erfüllt sich die Bedingung in Bild 3 und Flash springt ins vierte Bild der Zeitleiste weiter, wo durch einen stop()-Befehl das Weiterlaufen des Zeigers in der Zeitleiste verhindert wird.
  • 188.
    C L IE N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 175 In Bild 4 ist das Beispiel auch schon zu Ende – mithilfe des Befehls stop(); beenden wir das Abspielen der Zeitleiste. stop(); Des Weiteren beinhaltet das vierte Bild ein dynamisches Textfeld zur Ausgabe einer Kontrollmeldung. Hierzu erzeugen Sie mithilfe des Textwerkzeugs ein Textfeld, dem Sie im Eigenschaften- Inspektor den Typ „Dynamischer Text“ zuweisen. 5. Das Ende-Bild5. Das Ende-Bild Tipp zum Ausgeben von Kontrollinformationen Der Entwickler von Flash-Anwendungen kommt oftmals in die Situation, dass er die Flash- Anwendung online in einem Browser testen muss. Nachdem ihm dort das Ausgabefenster von Flash nicht zur Verfügung steht, verwendet er gern dynamische Textfelder oder TextArea- Komponenten zum Ausgeben von Variablenwerten. Welche der beiden Varianten Sie verwenden, ist Ihnen überlassen. Für einzeilige Ausgaben verwenden wir bevorzugt dynamische Textfelder, für mehrzeilige Ausgaben TextArea-Komponenten, wegen des dort automatisch erzeugten Scrollbalkens. Werfen wir noch einmal einen Blick auf unseren Code und dessen Ablauf: Offen- sichtlich wird in Bild 1 eine Variable myVar vom Typ String deklariert und es wird ihr der Wert "" zugewiesen. Gelangt der Bildzeiger in der Zeitleiste zu Bild 3, so wird hier überprüft, ob diese Variable den Wert "" besitzt – sollte dies der Fall sein, springt Flash in das Bild mit dem Namen „warten“ (in unserem Fall das zweite Bild) zurück und spielt von dort aus weiter ab. Solange myVar also den Wert "" besitzt, springt Flash fortwährend zwischen Bild 2 und 3 hin und her. Sollte myVar irgendwann einen 6. Codeanalyse6. Codeanalyse ABBILDUNG 5.4 In Bild 4 erstellen Sie ein dynamisches Textfeld.
  • 189.
    K A PI T E L 5176 Wert ungleich "" besitzen, spielt Flash zu Bild 4 weiter ab und wird dort per stop(); angehalten. Im Prinzip haben wir also eine sehr einfache Schleife programmiert! Im nächsten Schritt überlegen wir uns den JavaScript-Code, der unserer Flash-Variable myVar den Wert „EXPLODE“ zuweist, um zum vierten Bild in der Flash-Zeitleiste zu gelangen. Dieser Wert soll genau dann gesetzt werden, wenn wir auf einen Button im HTML-Dokument klicken. 7. JavaScript- Code 7. JavaScript- Code ABBILDUNG 5.5 So soll unser kleines Beispiel in einem Browser darge- stellt werden. Die Flash- Anwendung wartet auf einen Klick auf den nachfolgenden Button. Wenden wir uns zunächst einmal dem Inhalt des <body> zu. Um einen Button HTML- konform in das Dokument einzubauen, benötigen wir ein Formular. Außer für diesen Button wäre das Formular nicht erforderlich, lassen Sie sich deshalb also nicht davon ablenken. Ebenso dient die eingebaute Tabelle nur der übersichtlicheren Darstellung. Letzten Endes soll das HTML-Dokument in einem Browser wie in Abbildung 5.5 gezeigt dargestellt werden. <div id="Flash"> <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/ swflash.cab#version=7,0,19,0" width="200" height="150" id="myswf"> <param name="movie" value="browserAnFlash01.swf" /> <param name="quality" value="high" /> <embed id="myswf" name="myswf" src="browserAnFlash01.swf" width="200" height="150" quality="high" pluginspage="http://www. macromedia.com/go/getflashplayer" type="application/x-shockwave- flash"></embed> </object> 8. HTML- Dokument erstellen 8. HTML- Dokument erstellen
  • 190.
    C L IE N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 177 </div> <div id="SendButton"> <form name="frmSetVariable" id="frmSetVariable" method="post" action=""> <input type="button" value="Daten senden" onClick="sendDataToFlash();" /> </form> </div> Listing 5.7: Einbinden der Flash-Datei und Erzeugen des Formulars inklusive Button Der wesentliche Teil des Codes – neben dem eingebundenen Flash-Dokument, das im <object> durch id="myswf" und im <embed> durch name=" myswf" eindeutig gekennzeichnet ist – ist der Aufruf der Funktion sendDataToFlash() durch Klicken auf den Button: <input type="button" value="Daten senden" onclick="sendDataToFlash();" /> Es wird also eine JavaScript-Funktion namens sendDataToFlash() aufgerufen, wobei der Name der Funktion frei wählbar ist, da es sich hier nicht um eine vordefi- nierte Funktion handelt. Im Allgemeinen werden JavaScript-Blöcke (und da im Speziellen Funktionsdefini- tionen) im <head>-Bereich eines HTML-Dokuments eingebunden, weshalb auch ich Ihnen diese Vorgehensweise empfehle. Hier zunächst einmal der benötigte JavaScript-Code: function getFlashElement(elem) { var app = navigator.appName.toLowerCase(); var nav = navigator.userAgent.toLowerCase(); if((app.indexOf("microsoft") != -1 || nav.indexOf("microsoft") != -1) && !Boolean(window["opera"])) { return document.all[elem]; } else { return document[elem]; } } function sendDataToFlash() { var myswf = getFlashElement("myswf"); myswf.SetVariable("myVar", "EXPLODE"); } Listing 5.8: Die benötigten Funktionen zum Erkennen der korrekten „Ansprache“ der SWF-Datei einerseits (Funktion getFlashElement) sowie dem Schreiben der Variable innerhalb Flash andererseits (Funktion sendDataToFlash). Die Funktion sendDataToFlash() (das ist diejenige, die beim Klick auf den Button aufgerufen wird) selbst ruft – wie im einleitenden Teil dieses Kapitels dargelegt – wie- 9. JavaScript- Funktion schreiben 9. JavaScript- Funktion schreiben
  • 191.
    K A PI T E L 5178 derum eine Funktion getFlashElement(elem) auf, welche laut Document Object Model von JavaScript die eingebundene Flash-Datei (Attribut elem) anspricht. Die entsprechende Referenzierung wird von der Funktion per return zurückgeliefert. Nachdem die Rückgabe der Referenzierung erfolgt ist, wird mithilfe der Methode SetVariable("Variablenname", "Variablenwert") innerhalb der Flash-Datei die Variable myVar auf den Wert „EXPLODE“ gesetzt. Als Ergebnis unserer Bemühungen erhalten wir also:10.Testen der Funktionalität 10.Testen der Funktionalität ABBILDUNG 5.6 Per Klick auf den Button wurde die Variable myVar in der eingebundenen Flash-Datei auf den Wert „EXPLODE“ gesetzt. Möglich wird das durch die Verwendung der JavaScript- Funktion SetVariable(). Mögliche Fehlerquelle: die Adobe-eigene Funktion AC_FL_RunContent() An dieser Stelle sei angemerkt, dass hier eine potenzielle Fehlerquelle zutage treten kann: Im Internet Explorer muss eine eingebundene Flash-Datei „aktiviert“ werden. Dies bedeutet, dass der User die Flash-Datei im Browser anklicken muss, erst dann gilt sie als aktiviert und es kön- nen etwaige Benutzereingaben (Klicken eines Buttons in der Flash-Datei o.Ä.) getätigt werden. Um dies zu umgehen, hat sich Adobe entschlossen, einen Workaround anzubieten und damit die Flash-Datei per JavaScript einzubinden. Die von Adobe angebotene JavaScript-Funktion (AC_FL_RunContent()) lässt leider nicht zu, dass das <object> ein id-Attribut und das <embed> ein name-Attribut erhalten. Somit würde unser Code zum Ansprechen der Flash-Datei beispielsweise im Firefox und im Safari nicht mehr funktionieren. Um dies zu korrigieren, muss man in der Datei AC_RunActiveContent.js in der Funktion AC_FL_ RunContent() die Zeilen case "id": durch case "id":
  • 192.
    C L IE N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 179 ret.objAttrs[args[i]] = args[i+1]; break; und case "name": durch case "name": ret.embedAttrs[args[i]] = args[i+1]; break; ersetzen. 5.1.2 Variante 2:Verwenden von HTML- Attributen zum Setzen von Variablen Eine zweite Möglichkeit, Variablen von „außerhalb“ in einer Flash-Datei zu setzen, erfolgt mithilfe geeigneter Attribute in den Tags <object> und <embed>. Je nach ver- wendetem Browser müssen die entsprechenden Tags verwendet werden. Nachdem die Attribute direkt in den HTML-Code geschrieben werden, ist diese Vari- ante unabhängig von JavaScript. Grundsätzlich wird mit dem Attribut FlashVars gearbeitet, dem als Wert der Variab- lenname inklusive Wertzuweisung zugewiesen wird: FlashVars = "meineVariable=meinWert" Die Variablen inklusive Wert sind bereits im ersten Frame der Flash-Datei verfügbar und müssen nicht explizit deklariert werden. Es sollte darauf geachtet werden, dass – entgegen der vorigen Variante – die Variable nicht deklariert und ihr ein Wert zuge- wiesen wird, denn ansonsten würde der von außerhalb gesetzte Wert der Variablen überschrieben werden. Beachten Sie bitte außerdem, dass – unabhängig vom Wertetyp – der Wert von meine- Variable immer ohne Anführungszeichen geschrieben wird. Somit: korrekt: FlashVars = “myVar=once again” falsch: FlashVars = „myVar=‘once again‘“ Es können beliebig viele Variablen über diese Methode gesetzt werden. Attribute in <object> Im Fall des <object> wird mit dem im <object> verschachtelten <param> gearbeitet: <param name="FlashVars" value="myVar=once again" /> u u Kein JavaScript benötigt Kein JavaScript benötigt
  • 193.
    K A PI T E L 5180 Attribute in <embed> Im Fall des <embed> verhält sich die Sache ähnlich, jedoch wird üblicherweise kein zusätzliches verschachteltes Tag (wie oben das <param>) verwendet, sondern alle Attri- bute werden direkt im <embed> aufgelistet: <embed FlashVars="myVar=once again" .. ></embed> In der nachfolgenden Abbildung sehen Sie eine Anwendung, die ähnlich wie die Anwendung im vorigen Kapitel arbeitet. Der Auszug des entsprechenden HTML- Codes ist wie folgt: .. <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash. cab#version=7,0,19,0" width="200" height="150" id="myswf"> <param name="movie" value="browserAnFlash01_var2.swf" /> <param name="quality" value="high" /> <param name="FlashVars" value="myVar=once again" /> <embed id="myswf" name="myswf" FlashVars="myVar=once again" src="browserAnFlash01_var2.swf" width="200" height="150" quality="high" pluginspage="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash"></embed> </object> .. Listing 5.9: Auszug aus dem Listing der Datei browserAnFlash_var2.php, das Sie auf der Website zum Buch downloaden können. ABBILDUNG 5.7 Ausgabe der Variante 2, in Flash-Dateien Variablenwerte zu setzen. Wie Sie sehen, wird kein Button mehr zum Setzen des Variablenwerts benötigt – die Variablen und zugehörigen Werte werden als Attribute in den entsprechenden Tags <object> und <embed> gesetzt.
  • 194.
    C L IE N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 181 Der große Vorteil dieser Variante 2 ist, dass sie ohne weiteres in jedem halbwegs gän- gigen Browser funktioniert und kein JavaScript benötigt wird. Nachteilig ist, dass sie nicht interaktiv (also beispielsweise per Klick auf einen Button) verwendet werden kann. 5.2 Daten senden: Flash an Browser In diesem Abschnitt beschäftigen wir uns damit, wie Flash auf Clientseite mit seiner Außenwelt Kontakt aufnehmen kann. Im nächsten Abschnitt widmen wir uns dann der Frage, wie Flash auf Serverseite Daten übermitteln kann. 5.2.1 Kontaktaufnahme mit getURL Gehen wir doch kurz auf die Frage ein, welche Möglichkeiten der Webentwickler in Flash nutzen kann, damit Flash mit seinem „Äußeren“ – nämlich dem Browser – in Kontakt tritt. Als Erstes würde uns hier wohl der Flash-Befehl getURL() einfallen, mit dem man eine URL in einem Browser-Fenster oder einem Frame öffnen kann. Dieser Befehl ist demnach mit einem Anker <a> in HTML vergleichbar. Nach kürzerem (oder längerem) Nachdenken über die Möglichkeiten von Ankern in HTML fällt uns ein, dass mithilfe des reservierten Worts javascript: im href-Attri- but ein JavaScript-Befehl ausgeführt werden kann, also: <a href="javascript:JavaScript-Befehl;">Klick mich</a> oder in einem Beispiel: <a href="javascript:alert(‚Hallo Welt!');">Klick mich</a> JavaScript ausführen Beim Klick auf diesen Link wird der JavaScript-Befehl alert() ausgeführt, der in einem Meldefenster den Text „Hallo Welt!“ ausgibt. Das bedeutet also, dass HTML mithilfe von Ankern doch in der Lage ist, JavaScript-Befehle auszuführen. Wenn also dieses Tag vergleichbar mit dem Flash-Befehl getURL() ist, so liegt der Versuch nahe, dies auch mit dem Flash-Befehl auszuprobieren. Gesagt, getan: getURL("javascript:JavaScript-Befehl;"); ist exakt vergleichbar mit dem HTML-Befehl <a href="javascript:JavaScript-Befehl;">…</a> Sobald in getURL() im URL-Bereich javascript: eingegeben wird, wird an den Browser eine JavaScript-Anfrage gesendet – so einfach ist die Kontaktaufnahme von Flash mit dem Browser per JavaScript also! Testen wir unser neu erlangtes Wissen an einem konkreten Beispiel.
  • 195.
    K A PI T E L 5182 Schritt für Schritt: JavaScript-Funktion in Browser-Fenster über Flash aufrufen Ziel dieses Beispiels ist, dass durch Klicken auf einen Flash-Button eine JavaScript- Funktion aufgerufen wird, die wiederum ein Meldungsfenster mit dem Text „Hallo Außenwelt!“ öffnet. Wenden wir uns zunächst Flash zu. Hier ist die Sachlage sehr einfach – benötigt wird ein Button auf der Flash-Bühne, der beim Loslassen den getURL()-Befehl aufruft. Dieser veranlasst wiederum das Ausführen von JavaScript-Code im Browser. Der zugehörige Code für den Button ist also: on(release) { getURL("javascript:executeMyCode();"); } Listing 5.10: Mehr an Code ist in Flash nicht nötig, um eine (externe) JavaScript-Funktion aufzurufen – die Kommunikation zwischen Flash und JavaScript von Flash aus ist somit denkbar einfach. 1. ActionScript- Code erstellen 1. ActionScript- Code erstellen ABBILDUNG 5.8 Die Abbildung zeigt den Code aus dem obigen Listing (angewandt auf den Button). Alternativ hätte man auch ein Script schreiben können, das nicht dem Button zuge- wiesen wird, sondern in der Zeitleiste programmiert wird. Für den Fall, dass Ihnen das Anbringen von Script-Code auf einen Button nicht so „sympathisch“ ist (vgl. hierzu auch das Kapitel über die Grundlagen der Programmie- rung), könnte man alternativ auch folgenden Code in die Zeitleiste der Bühne platzie- ren (vorausgesetzt, Sie haben dem Button den Namen „callJS_btn“ gegeben):
  • 196.
    C L IE N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 183 callJS_btn.onRelease = function():Void { getURL("javascript:executeMyCode();"); } Listing 5.11: Alternativer Code für die Abarbeitung eines Klicks auf den Flash-Button (genau genommen handelt es sich um das Loslassen der Maustaste (onRelease), aber das wissen Sie ja bereits vom Grund- lagenkapitel). Mehr Arbeit fällt für die Flash-Abteilung auch schon nicht mehr an. Beachten Sie jedoch bitte an dieser Stelle, dass sofern das Flash-Dokument nicht in einer Browser- Umgebung getestet wird, das Aufrufen dieses Codes nicht funktioniert – die Testum- gebung in Flash ist hier nicht ausreichend. Bedeutet das Weniger an Arbeit in Flash nun ein Mehr an Arbeit in JavaScript im HTML-Dokument, wo auch die Flash-Datei eingebunden ist? Mitnichten, auch in JavaScript fällt der Arbeitsaufwand sehr gering aus: <script language="javascript" type="text/javascript"> <!-- function executeMyCode() { alert("Hallo Aussenwelt!"); } //--> </script> Listing 5.12: JavaScript-Code, um die Anweisungen aus Flash heraus abarbeiten zu können. 2. JavaScript- Code erstellen 2. JavaScript- Code erstellen ABBILDUNG 5.9 Wie Sie sehen, ist die obige Schreibweise ebenso mög- lich. Im Allgemeinen wird diese Schreibweise auch bevorzugt, da so der Code übersichtlicher – da in der Zeitleiste platziert – bleibt.
  • 197.
    K A PI T E L 5184 Die aus Flash aufzurufende JavaScript-Funktion wird – wie üblich – zwischen den HTML-Tags <script> und </script> definiert. Flash ist in der Lage, mithilfe des Befehls getURL und dem verwendeten URL-Attribut mit beginnendem javascript: direkt die JavaScript-Funktion aufzurufen. ABBILDUNG 5.10 Das Ergebnis unserer Arbeit: Flash hat eine JavaScript- Funktion angesprochen. 5.3 Die ExternalInterface-Klasse – Flash 8 und höher Seit der Einführung von Flash 8 ist Flash in der Lage, besser und umfassender mit JavaScript zu interagieren (versierte Leser wissen, dass dieses System auf dem „JavaScript Integration Kit“ basiert, der erstmals für den Flash-Player r6.5 vorgestellt wurde und somit eigentlich schon in früheren Versionen von Flash als „Add-On“ verfügbar war). Die Möglichkeit, von der hier gesprochen wird, ist die External- Interface-Klasse – diese ermöglicht die Kommunikation einer Flash-Anwendung mit irgendeiner anderen Anwendung, in der Flash eingebettet ist. In unserem Fall ist diese „andere Anwendung“ eine HTML-Seite – es könnte jedoch auch eine beliebige andere Anwendung (etwa eine Director-Umgebung) sein. Vonseiten Adobe wird die Kommunikation zwischen ActionScript und JavaScript über die ExternalInterface-Klasse empfohlen. Folgende Möglichkeiten stehen uns zur Verfügung: Flash an Browser: Von ActionScript aus können beliebige JavaScript-Funktionen aufgerufen werden, und zwar mit einer beliebigen Anzahl an Übergabeparametern. Des Weiteren ist ActionScript in der Lage, Rückgabewerte aus der aufgerufenen JavaScript-Funktion zu erhalten. u
  • 198.
    C L IE N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 185 Browser an Flash: Von JavaScript aus können beliebige ActionScript-Funktionen aufgerufen werden. Eventuelle Rückgabewerte der ActionScript-Funktion werden direkt von der JavaScript-Funktion entgegengenommen. Ein großer Vorteil der Verwendung der ExternalInterface-Klasse ist, dass sie von allen gängigen Browsern unterstützt wird (Internet Explorer ab Version 5, Netscape ab 8, Mozilla ab 1.7.5, Firefox ab 1.0, Safari ab 1.3). Nichtsdestotrotz bleibt es uns natürlich nicht erspart, beim Ansprechen der SWF-Datei zwischen den Browsern zu unterscheiden – hierzu haben wir uns im vorigen Kapitel „Einbinden von Flash“ Gedanken gemacht und ein allgemein gültiges Script entwickelt. Des Weiteren müssen wir beachten, dass der Browser für die Verwendung dieser Klasse entweder ActiveX oder die NPRuntime-API unterstützen muss. Der Hauptvorteil dieser Klasse ist jedoch, dass von beiden Seiten aus (von Seiten JavaScript und von Seiten ActionScript) Funktionen der jeweils anderen Technologie aufgerufen werden können. Dies bringt nämlich auch mit sich, dass – entgegen unserer bisherigen Kenntnis – man nicht mehr explizit auf das Setzen von Variablenwerten warten muss, sondern direkt Funktionen aufgerufen werden können. Wo liegt also der Nachteil dieser Klasse, wenn doch alles so toll scheint? Nun, zwei Punkte könnte man als Nachteil anmerken: Zunächst einmal funktioniert diese Klasse standardmäßig erst ab Flash 8 (ist das wirklich ein Nachteil, schließlich arbeiten wir bereits mit Flash CS3, also dem Nachfolger von Flash 8?!). Außerdem bedeutet das Arbeiten mit externen Klassen auch immer einen Mehraufwand in der Dateigröße (wir werden jedoch sehen, dass sich der „Mehraufwand“ sehr in Grenzen hält, zumal Übertragungszeiten für Dateien im Kbyte-Bereich nicht mehr wirklich ein Problem darstellen). Im Weiteren werden wir sehen, dass mit der Einführung von Flash CS3 und somit ActionScript 3.0 einige Erweiterungen erfolgt sind – mehr dazu im ActionScript 3.0- Teil dieses Kapitels. 5.3.1 ExternalInterface-Klasse mit ActionScript 1.0/2.0 Wie bereits oben erwähnt, ermöglicht uns die ExternalInterface-Klasse das wech- selseitige Aufrufen von Funktionen in sowohl JavaScript als auch ActionScript. Bevor wir jedoch in medias res gehen können, müssen wir uns zunächst noch Gedan- ken machen, wie wir die externe Klasse einbinden und ob die ExternalInterface- Klasse von der „Gegenseite“ (also in unserem Fall ein XHTML-basiertes Dokument) überhaupt unterstützt wird. Die zu importierende Klasse trägt den Namen „ExternalInterface“ und ist eine Unter- klasse von external, die wiederum eine Unterklasse der allgemeinen Klasse flash ist. u Vorteile!Vorteile! Nachteile?Nachteile? Importieren der Klasse Importieren der Klasse
  • 199.
    K A PI T E L 5186 Da ExternalInterface in ActionScript 2.0 die einzige Unterklasse von external ist, lautet der geeignete Befehl zum Importieren somit: import flash.external.*; Alternativ wäre auch folgende Variante zulässig: import flash.external.ExternalInterface; Sobald der Import geschehen ist, stehen uns folgende Möglichkeiten der Klasse zur Verfügung: Eigenschaften Eigenschaft Typ Beschreibung available Boolean Gibt an,ob das Dokument,in dem die SWF-Datei eingebunden ist,die ExternalInterface- Klasse unterstützt.Diese Eigenschaft sollte immer zuerst abgeprüft werden,bevor man weitere Methoden und Eigenschaften der Klasse benützt. Bei true wird die Klasse unterstützt,bei false nicht. objectID String Gibt den Wert des name- bzw.id-Attributs zu- rück: Internet Explorer:Wert des id-Attributs im <object> Firefox (Mozilla-basierte Browser):Wert des name-Attributs im <embed> Beachten Sie bitte,dass Sie – wie schon des Öfteren angemerkt – für das <object> aus- schließlich das id-Attribut und für das <embed> ausschließlich das name-Attribut verwenden. Methode Attribute Beschreibung addCallback :Boolean Registriert eine Funktion als„von JavaScript aufrufbar“.Diese Methode muss verwendet wer- den,um eine ActionScript-Funktion überhaupt für JavaScript„verwendbar“ zu machen – wird diese Methode für eine spezielle ActionScript- Funktion nicht verwendet,kann JavaScript diese Funktion nicht aufrufen.Deshalb:jede „für JavaScript sichtbare“ Funktion mit dieser Methode explizit angeben (registrieren). Die Methode liefert den Wert true zurück,sollte das Registrieren erfolgreich gewesen sein; an- sonsten liefert sie false. methodName:String Ein Name (kann auch ein„Alias“ sein) für die Funktion,die JavaScript aufrufen kann.Dieser Name muss nicht notwendigerweise mit dem tatsächlichen Namen der ActionScript-Funktion übereinstimmen. instance:Object Hier kann ein spezielles Objekt angegeben werden.Ist im Allgemeinen nicht notwendig, deshalb wird zumeist der Wert null verwendet.
  • 200.
    C L IE N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 187 method:Function Als drittes Attribut wird der tatsächliche Name der ActionScript-Funktion angegeben.Bitte beachten Sie,dass der Name der Funktion ohne Anführungszeichen angegeben werden muss (Typ:Function,nicht String). call:* Ruft eine JavaScript-Funktion auf.Wie Sie wissen,muss es sich nicht notwendigerweise um JavaScript (in XHTML) handeln – viel- mehr ruft die Methode call eine beliebige Funktion in einem beliebigen„Container“ (bei uns:das XHTML-Dokument) auf,der das ExternalInterface-API unterstützt.In unserem Fall als Webdesigner ist es zumeist eben ein XHTML- Dokument. Der Rückgabewert der Funktion ist abhängig von der Funktion selbst: null:Es ist ein Fehler aufgetreten. Andere Typen:Es ist kein Fehler aufgetreten. Die möglichen Fehler werden weiter unten im Abschnitt Browser an Flash an Browser ausführ- lich erklärt. functionName:String An dieser Stelle wird der Name der JavaScript- Funktion angegeben,die von Flash aus aufgeru- fen werden soll. arguments:Object An die JavaScript-Funktion kann eine beliebige Anzahl von Werten übergeben werden,wobei die Werte durch Komma voneinander zu tren- nen sind.Die Datentypen aus ActionScript wer- den automatisch in Datentypen von JavaScript überführt („marshalling“). Tabelle 5.1: Mit diesen Eigenschaften und Methoden ausgestattet können wir ans Werk gehen. Neben diesen Eigenschaften und Methoden der ExternalInterface-Klasse existie- ren noch weitere (an diese Klasse vererbte) Eigenschaften und Methoden, die für uns jedoch nicht wirklich wichtig sind – eine Übersicht derer finden Sie in der ActionS- cript-Hilfe, wenn Sie im Komponenten-Referenzhandbuch die ExternalInterface class nachschlagen. Netterweise stellt uns Flash zum Überprüfen der Verfügbarkeit der Klasse also eine ein- fache Möglichkeit zur Verfügung: die Eigenschaft available der ExternalInter- face-Klasse. Sollte ein Abfragen dieser Eigenschaft true ergeben, sind wir sozusagen „im Spiel“ und können die Klasse verwenden. Sollte wider Erwarten doch der Wert false zurückgeliefert werden, so müssen wir den altbewährten Weg mit den anfangs im Kapitel erlernten Fähigkeiten gehen. Der grundlegende Scriptcode für das Arbeiten mit der ExternalInterface-Klasse sieht dementsprechend wie folgt aus: import flash.external.*; if(ExternalInterface.available) { ExternalInterface. available ExternalInterface. available
  • 201.
    K A PI T E L 5188 trace("EXTERNAL INTERFACE verfüg150 bar"); } else { trace("EXTERNAL INTERFACE NICHT verfügbar"); } Listing 5.13: Das wichtige Codefragment zum Einbinden der ExternalInterface-Klasse (die trace-Befehle können selbstverständlich auskommentiert werden) Ein Wort zum Testen der Klasse Bitte bedenken Sie, dass Sie die Möglichkeiten der ExternalInterface-Klasse nur dann nutzen können, wenn Sie eine entsprechende „Umgebung“ vorfinden. Eine solche Umgebung ist ein XHTML-Dokument in einem Browser mit den oben genannten Voraussetzungen (Versionen beachten) oder eben die Entwicklungsumgebung von Flash. Wenn Sie also den obigen Code testen und die Eigenschaft available immer false zurückgibt, dann ist kein entsprechender Container vorhanden. Browser an Flash Variante 2 Möchte man nun den Weg gehen und den Browser eine Flash-Funktion aufrufen las- sen, so müssen drei Schritte vorgenommen werden: 1. Die entsprechende ActionScript-Funktion muss erzeugt werden. 2. Diese Funktion muss mithilfe der Methode addCallback freigegeben werden. 3. Die Funktion muss von JavaScript aus aufgerufen werden. Sehen wir uns also die drei Schritte der Reihe nach an. Als Beispiel verwenden wir das- jenige aus Abbildung 5.6, nur dass wir nun die ExternalInterface-Klasse bemühen. Ziel des Beispiels ist es, dass per Klick auf einen Button eine JavaScript-Funktion auf- gerufen wird, die wiederum eine in Flash vorhandene ActionScript-Funktion aufruft. Die ActionScript-Funktion soll dann in einem dynamischen Textfeld denjenigen Wert ausgeben, der von JavaScript an ActionScript übergeben wurde (in unserem Fall wird es der Text „EXPLODE“ sein):
  • 202.
    C L IE N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 189 Entgegen unserer Entwicklung aus dem Kapitel Browser an Flash werden nun in der ActionScript-Datei nur noch zwei Bilder in der Zeitleiste benötigt (wobei wir es theo- retisch auch auf ein Bild reduzieren könnten, wenn wir die Textfelder dynamisch erzeugen): ABBILDUNG 5.11 Die Flash-Anwendung befin- det sich im „Wartezustand“ auf das Klicken des Buttons. ABBILDUNG 5.12 Sobald geklickt wurde, wird der Text „EXPLODE“ in einem dynamischen Textfeld aus- gegeben.
  • 203.
    K A PI T E L 5190 Wenden wir uns zunächst dem Einbinden der ExternalInterface-Klasse und dem Überprüfen der Verfügbarkeit zu (Aktionenebene): var msg:mx.controls.TextArea; //TextArea initialisieren msg.text = "Initialisiere...n"; //Text der TextArea zuweisen import flash.external.*; if(ExternalInterface.available) { ABBILDUNG 5.13 Bild 1 unserer Flash- Anwendung. Wie Sie sehen, besteht das zweite Bild lediglich noch aus anderen Elementen in der Ebene „Ausgabetext“ – die (wich- tigen) Ebenen „Funktionen“ und „Aktionen“ beinhalten keinerlei weiteren Code.
  • 204.
    C L IE N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 191 msg.text += "EXTERNAL INTERFACE verfügbarn"; .. } else { msg.text += "EXTERNAL INTERFACE NICHT verfügbarn"; } stop(); Listing 5.14: Importieren der ExternalInterface-Klasse und überprüfen, ob diese auch verfügbar ist. In den ersten beiden Zeilen wird lediglich noch die auf der Bühne verwendete TextArea initialisiert und ihr der Text „Initialisiere…“ mit einem folgenden Zeilenumbruch (n) zugewiesen. Die beiden Punkte „..“ deuten an, dass an dieser Stelle noch weiterer Code eingefügt wird. War das Einbinden erfolgreich und sind die benötigten Möglichkeiten verfügbar, so wird der TextArea mit dem Namen „msg“ der Text „EXTERNAL INTERFACE verfüg- bar“ zugewiesen. Gesetzt den unwahrscheinlichen Fall, dass es nicht geklappt hat, wird der entsprechend andere Text ausgegeben. Im nächsten Schritt definieren wir in der Funktionenebene diejenige Funktion, die später aus JavaScript aus aufgerufen werden soll: function jumpWithJS(myText:String):Void { myVar = myText; gotoAndStop("fertig"); } Listing 5.15: Definieren der Funktion jumpWithJS, die per JavaScript aufgerufen wird. Der Funktion wird ein Wert übergeben, der dann in einem dynamischen Textfeld (Variable myVar) angezeigt werden soll. Des Weiteren wird in der Zeitleiste auf das Bild mit dem Namen „fertig“ gesprungen. Schritt drei ist nun das Registrieren dieser ActionScript-Funktion für die Verwendung durch JavaScript: var msg:mx.controls.TextArea; msg.text = "Initialisiere...n"; import flash.external.*; if(ExternalInterface.available) { msg.text += "EXTERNAL INTERFACE verfügbarn"; if(ExternalInterface.addCallback("tryIt",null,jumpWithJS)) { msg.text += "Callback-Funktion ERFOLGREICH registriertn"; } else { msg.text += "Callback-Funktion NICHT erfolgreich registriertn";
  • 205.
    K A PI T E L 5192 } } else { msg.text += "EXTERNAL INTERFACE NICHT verfügbarn"; } stop(); Listing 5.16: Mithilfe der Methode addCallback wird die (tatsächlich vorhandene) ActionScript-Funkti- on jumpWithJS unter dem Pseudonym tryIt (mittels dieses Namens wird JavaScript auf die Funktion zugreifen) im Objekt null registriert. War die Registrierung der Callback-Funktion erfolgreich, wird in der darauffolgenden Zeile in die TextArea „msg“ eine entsprechende Meldung ausgegeben (dies gilt auch für den Fall, dass die Registrierung nicht erfolgreich war). Selbstverständlich können die tatsächliche Funktion (hier: jumpWithJS) und der Aufrufname für JavaScript (hier: tryIt) gleich benannt werden – dieses Beispiel soll lediglich demonstrieren, dass dies eben nicht notwendigerweise der Fall sein muss. Damit ist die Flash-Entwicklung so weit abgeschlossen und wir können uns dem XHTML- und JavaScript-Teil zuwenden. Zunächst wird die SWF-Datei wie gewohnt in ein XHTML-Dokument eingebettet: <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash. cab#version=7,0,19,0" width="200" height="150" id="myswf"> <param name="movie" value="browserAnFlash02.swf"> <param name="quality" value="high"> <embed name="myswf" src="browserAnFlash02.swf" width="200" height="150" quality="high" pluginspage="http://www.macromedia.com/go/ getflashplayer" type="application/x-shockwave-flash"></embed> </object> Listing 5.17: Einbetten der SWF-Datei, wobei wir wie immer darauf achten, dass das id-Attribut aus- schließlich dem <object> und das name-Attribut ausschließlich dem <embed> zugewiesen wurde. Auch unser bereits entwickeltes Script zum korrekten Ansprechen der SWF-Datei kann ohne Einschränkungen übernommen werden: function getFlashElement(elem) { var app = navigator.appName.toLowerCase(); var nav = navigator.userAgent.toLowerCase(); if((app.indexOf("microsoft") != -1 || nav.indexOf("microsoft") != -1) && !Boolean(window["opera"])) { return document.all[elem]; } else {
  • 206.
    C L IE N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 193 return document[elem]; } } Listing 5.18: Ansprechen der SWF-Datei mittels JavaScript – eins zu eins übernommen von dem Kapitel Browser an Flash. Der noch ausstehende Arbeitsschritt ist nun also nur noch, die ActionScript-Funktion (beachte: diese Funktion hat das Pseudonym „tryIt“) per JavaScript aufzurufen. Hierzu übernehmen wir ebenfalls die bereits entwickelte JavaScript-Funktion aus dem Kapitel Browser an Flash und benennen sie von sendDataToFlash in sendDataToFlash2 um, da wir geringfügige Änderungen vornehmen: In Zeile drei des Scripts wird die (ActionScript-)Funktion tryIt mit dem Übergabewert „EXPLODE“ aufgerufen. function sendDataToFlash2() { var myswf = getFlashElement("myswf"); myswf.tryIt("EXPLODE"); } Listing 5.19: Über die JavaScript-Funktion sendDataToFlash2 wird die ActionScript-Funktion tryIt (in Wirklichkeit heißt diese Funktion in Flash nicht tryIt, sondern jumpWithJS) mit dem Übergabewert „EXPLODE“ aufgerufen. Zu guter Letzt müssen wir noch dafür sorgen, dass unsere Funktion sendData- ToFlash2 aufgerufen wird – hierzu bedienen wir uns eines XHTML-Buttons, der auf Klick die Funktion aufruft: <input type="button" value="Daten senden" onClick="sendDataToFlash2();" /> Listing 5.20: Ein Standard-XHTML-Button sorgt für den Aufruf der JavaScript-Funktion. Damit sind wir fertig – mehr ist dann auch nicht mehr notwendig! Sobald Sie den Button klicken, wird die JavaScript-Funktion sendDataToFlash2 aufgerufen, die wiederum die ActionScript-Funktion tryIt (Pseudonym für jumpWithJS) mit dem Übergabewert „EXPLODE“ aufruft. Dadurch wird innerhalb der Flash-Datei die ActionScript-Funktion jumpWithJS angesprochen, die den Text „EXPLODE“ in einem dynamischen Textfeld anzeigt, welches sich im Bild mit dem Namen „fertig“ befindet. Als Erweiterung könnte man beispielsweise nicht einen fixen Wert (wie bei uns „EXPLODE“) an Flash übergeben, sondern ein Eingabefeld in XHTML basteln und den dort eingegebenen Wert an Flash übergeben. Um dies zu bewerkstelligen, muss erst mal ein Textfeld her: <input type="text" name="myText" id="myText" /> Danach muss die JavaScript-Funktion so angepasst werden, dass sie den Inhalt des Textfelds ausliest und an die ActionScript-Funktion übergibt:
  • 207.
    K A PI T E L 5194 var textToFlash = document.forms["frmExternalInterface"]. elements["myText"].value; myswf.tryIt(textToFlash); Listing 5.21: Zunächst wird eine Variable textToFlash angelegt, die den Inhalt des Formularfelds my- Text im Formular frmExternalInterface ausliest. Der Inhalt von textToFlash wird dann mithilfe des Funktionsaufrufs tryIt an Flash übermittelt. Gesagt – getan. Hier das Ergebnis: ABBILDUNG 5.14 Der im Formularfeld einge- gebene Text „Hallo Welt“ wird in Kürze an die Flash-Datei übermittelt (siehe folgende Abbildung). ABBILDUNG 5.15 Der Text „Hallo Welt“ wurde an Flash übermittelt und im dynamischen Textfeld angezeigt.
  • 208.
    C L IE N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 195 Tipp: Testen Sie immer wieder in verschiedenen Browsern (Internet Explorer, Firefox, Opera, Safari) die Funktionalität Ihrer Anwendungen – Ihre User werden es Ihnen mit Sicherheit danken. Können wir das somit erlangte Wissen nun auf andere Technologien anwenden? Die Antwort ist eindeutig: ja! Die Türe steht nun sperrangelweit offen für AJAX-basierte interaktive Anwendungen zwischen Flash und XHTML, denn mit dem Zeitpunkt, wo man von JavaScript auf ActionScript-Funktionen zugreifen kann, muss Flash nicht mehr – wie bisher – auf das Setzen einer Variable „warten“, sondern kann funktions- basiert gesteuert werden. Wann diese Funktionen durch JavaScript aufgerufen werden (beispielsweise nach dem Nachladen von Daten vom Server durch AJAX), ist nun freigestellt. Flash an Browser Variante 2 Betrachten wir den umgekehrten Fall, nämlich dass Flash eine JavaScript-Funkti- on aufruft. Hierzu bedienen wir uns der ActionScript-Methode call, die von uns (zumindest) den Namen der JavaScript-Funktion fordert, die aufgerufen werden soll. Zusätzlich können (je nach Definition der JavaScript-Funktion) noch weitere Parame- ter übergeben werden. Die allgemeine Syntax wäre: ExternalInterface.call("Funktionsname", [Parameter1, Parameter2, ..]); Bemühen wir das im Vorgängerkapitel Flash an Browser entwickelte Beispiel (Flas- hAnBrowser_alternativ.fla – zu finden wie üblich auf der Buch-CD mit dem Namen FlashAnBrowser02_alternativ.fla), wo wir mithilfe der Methode getURL auf eine JavaScript-Funktion zugegriffen haben, so würden wir den Code zunächst um den Import der ExternalInterface-Klasse erweitern (neben der Klasse wurde auch noch – wie im letzten Beispiel – eine TextArea angelegt, um uns ausgeben zu lassen, ob beim Import der Klasse alles geklappt hat): var msg:mx.controls.TextArea; msg.text = "Initialisiere...n"; import flash.external.*; if(ExternalInterface.available) { msg.text += "EXTERNAL INTERFACE verfügbarn"; } else { msg.text += "EXTERNAL INTERFACE NICHT verfügbarn"; } Listing 5.22: Code zum Importieren der benötigten Klasse. Neben dem Import wurde noch eine TextArea initialisiert – siehe auch nachfolgende Abbildung. AJAX & Web 2.0?AJAX & Web 2.0?
  • 209.
    K A PI T E L 5196 Dieser Teil war so weit ja schon aus dem vorigen Abschnitt bekannt. Interessanter wird es, wenn wir den Code betrachten, der bei Klick auf den Button ausgeführt werden soll: callJS_btn.onRelease = function():Void { msg.text+= ExternalInterface.call("executeMyCode2")+"n"; } Listing 5.23: Aufruf der JavaScript-Funktion executeMyCode2. Es werden bis dato noch keine Werte an die Funktion übergeben. Der Befehl ExternalInterface.call("executeMyCode2") sorgt dafür, dass die JavaScript-Funktion executeMyCode2 (diese muss selbstverständlich in der XHTML- Datei vorhanden sein) aufgerufen wird. Da wir unsere JavaScript-Funktion so auslegen werden, dass sie uns einen Wert zurückliefert, wird dieser Wert als Text der TextArea hinzugefügt, n sorgt wie üblich für einen Zeilenumbruch innerhalb der TextArea. Auch die JavaScript-Funktion muss gegenüber dem Ursprungsbeispiel nicht wesent- lich verändert werden (um Verwechslungen zu vermeiden, habe ich die aufzurufende Funktion von executeMyCode auf executeMyCode2 umbenannt): function executeMyCode2() { alert("Hallo Außenwelt!"); return "JavaScript-Antwort: OK"; } Listing 5.24: Sobald die JavaScript-Funktion durch ActionScript aufgerufen wird, wird in einer Alert-Box der Text „Hallo Außenwelt!“ ausgegeben und der Wert „JavaScript-Antwort: OK“ an ActionScript zurückge- geben. ABBILDUNG 5.16 Ein Blick auf die Entwicklungsumgebung zeigt, dass wir dem Beispiel aus dem letzten Kapitel eine TextArea hinzugefügt haben, um diverse Statusmeldungen ausgeben zu können. Grundsätzlich würde man die TextArea jedoch nicht benötigen.
  • 210.
    C L IE N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 197 Ein Test der Anwendung zeigt, dass wie zu erwarten war alles einwandfrei klappt: Bitte beachten Sie, dass der Rückgabetext „JavaScript-Antwort: OK“ erst dann in der TextArea von Flash erscheint, wenn Sie den OK-Button der Alert-Box geklickt haben, da eine Alert-Box so lange das weitere Abarbeiten des Codes unterbricht, bis die Box wieder geschlossen ist. Nun erweitern wir unser bestehendes Beispiel um eine Parameterübergabe von Flash an JavaScript. Konkret wollen wir zwei Parameter (eine Zahl und einen String) an JavaScript übermitteln. Um zu sehen, dass die übergebene Zahl auch wirklich eine Zahl ist, werden wir sie mit zwei multiplizieren – sollte das klappen, handelt es sich mit Sicherheit um eine Zahl! Zunächst adaptieren wir den call-Aufruf: callJS_btn.onRelease = function():Void { msg.text+= ExternalInterface.call("executeMyCode2",23.5,"Uwe Mutz")+"n"; } Listing 5.25: Erweiterung des Codes um die Parameter 23.5 (Zahl) und „Uwe Mutz“ (Text) – die entsprechen- de Datei lautet FlashAnBrowser03_alternativ.fla und findet sich auf der Buch-CD wieder. Danach erweitern wir die JavaScript-Funktion, sodass die übergebene Zahl mit zwei multipliziert und gemeinsam mit dem übergebenen Text in der Alert-Box ausgegeben wird: function executeMyCode2(myNumber,myText) { var msg = 2*myNumber+" / "+myText; Parameter- übergabe an JavaScript Parameter- übergabe an JavaScript ABBILDUNG 5.17 Flash nimmt Kontakt mit JavaScript auf.
  • 211.
    K A PI T E L 5198 alert(msg); return "JavaScript-Antwort: OK"; } Listing 5.26: An die JavaScript-Funktion werden zwei Parameter (myNumber und myText) übergeben. myNumber wird mit zwei multipliziert und dann gemeinsam mit myText in der Variable msg gespeichert, welche danach in der Alert-Box ausgegeben wird. Browser an Flash an Browser Nun machen wir die Probe aufs Exempel und übergeben von JavaScript an Flash einen Wert, der dann auf Knopfdruck (warum nur „auf Knopfdruck“ und nicht gleich direkt, werden wir noch klären müssen – Thema „Rekursion“) von Flash erweitert und an JavaScript zurückgegeben wird. Den zu übergebenen Wert werden wir aus einem Eingabefeld lesen, den zurückgegebenen Wert einem Textfeld anhängen. Der fertige Aufbau sieht dann folgendermaßen aus: ABBILDUNG 5.18 Die übergebene Zahl (in unserem Fall: 23.5) wird mit zwei multipliziert: Das Ergebnis lautet 47. Gemeinsam mit dem über- gebenen Text („Uwe Mutz“) wird sie in einer Alert-Box ausgegeben.
  • 212.
    C L IE N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 199 Der Ablauf wird also wie folgt vor sich gehen: 1. In das Eingabefeld wird Text eingegeben und nach Klick auf den Button „Daten senden“ an Flash übergeben. 2. Flash empfängt den übermittelten Text und stellt diesen in der TextArea dar. 3. Bei Klick auf den Button „Zurück an JS…“ wird der übergebene Text wieder an JavaScript zurückgeschickt und im Ausgabebereich angezeigt. So weit der Plan. Der XHTML-Teil wird uns wenig Kopfzerbrechen machen, denn bis auf zwei Felder und eine eingebettete SWF-Datei ist nicht viel zu tun: ... <form name="frmExternalInterface" id="frmExternalInterface" method="post" action=""> <input type="text" name="myText" id="myText" /> <input type="button" value="Daten senden" onclick="sendDataToFlash2();" /> </form> ... <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash. cab#version=7,0,19,0" width="300" height="200" id="myswf"> <param name="movie" value="browserAnFlashAnBrowser.swf"> <param name="quality" value="high"> <embed name="myswf" src="browserAnFlashAnBrowser.swf" width="300" ABBILDUNG 5.19 Ein Eingabefeld zum Versenden von Text an Flash, eine TextArea und ein „Zurücksende“- Button in Flash sowie ein Ausgabebereich (readonly) für die von Flash gesandten Daten.
  • 213.
    K A PI T E L 5200 height="200" quality="high" pluginspage="http://www.macromedia.com/go/ getflashplayer" type="application/x-shockwave-flash"></embed> </object> ... <form name="frmExternalInterface2" id="frmExternalInterface2" method="post" action=""> <textarea name="myText2" cols="30" rows="10" id="myText2" readonly="readonly"></textarea> </form> ... ... Listing 5.27: Auszug aus dem XHTML-Listing. Es werden die Felder myText (Eingabe) und myText2 (Aus- gabe) erzeugt sowie wie üblich die SWF-Datei eingebettet. Die Formularelemente sind von zwei Formularen frmExternalInterface und frmExternalInterface2 umgeben. Auch die JavaScript-Funktionen werden uns keine Kopfzerbrechen bereiten, denn da ist alles wie gehabt – einzig die Ausgabe des von Flash zurückgelieferten Textes bedarf einer zusätzlichen JavaScript-Programmierung: function sendDataToFlash2() { var myswf = getFlashElement("myswf"); var textToFlash = document.forms["frmExternalInterface"]. elements["myText"].value; myswf.tryIt(textToFlash); } function executeMyCode2(textFromFlash) { document.forms["frmExternalInterface2"].elements["myText2"].value += "AS says: "+textFromFlash+"n"; return "OK"; } Listing 5.28: Einzig die Ausgabe in eine <textarea> namens myText2 ist noch mehr oder weniger unbekannt. Vielleicht ist Ihnen aufgefallen, dass wir uns zweier Formulare bedienen. Dies resul- tiert aus dem Grund, dass der Internet Explorer beim Verwenden des Adobe-Scripts zum Einbetten von SWF-Dateien (AC_RunActiveContent.js) so seine Probleme hat, wenn dieser Code innerhalb eines Formulars steht. Deshalb der Tipp: Teilen Sie Ihren XHTML-Code so auf, dass der Scriptaufruf AC_FL_RunContent(..) sich nicht innerhalb eines umgebenden <form> befindet. Weiter zu Flash & ActionScript. Der Bühnenaufbau von Flash ist denkbar einfach, da wir nur noch ein Bild in der Zeitleiste benötigen. An dieser Stelle möchte ich jedoch AC_FL_ RunContent(..) nicht zwischen <form> und </form> AC_FL_ RunContent(..) nicht zwischen <form> und </form>
  • 214.
    C L IE N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 201 wieder einmal in Erinnerung rufen, dass man die Ebenen der Bühne so übersichtlich wie möglich gestalten sollte. Den Hardcore-Programmierern unter uns wird dies wohl ein bisschen Kopfschütteln abverlangen („Eine einzige Ebene würde auch ausreichen, da ja alle Elemente auch per ActionScript erzeugt werden könnten!“), jedoch ist dieses Buch als Einsteigerbuch gedacht und deshalb auch so aufgebaut, dass Einsteiger die Beispiele so übersichtlich wie nur möglich vorfinden. Und „falsch“ ist es keineswegs – es wäre eben nur ein wenig „reduzierter“ auch möglich. Wie dem auch sei, hier die zusammengeräumte Bühne: ABBILDUNG 5.20 „As aufgeräumt as possible“ Die Aktionenebene beinhaltet wie gewohnt den Import der ExternalInterface- Klasse und deren Verwendung inklusive Callback-Registrierung sowie den Event- Handler für das Klicken des Buttons: var msg:mx.controls.TextArea; msg.text = "Initialisiere...n"; var lastMsg:String = "(bisher nichts von JS erhalten..)"; import flash.external.*; if(ExternalInterface.available) { msg.text += "EXTERNAL INTERFACE verfügbarn"; if(ExternalInterface.addCallback("tryIt",null,calledByJS)) {
  • 215.
    K A PI T E L 5202 msg.text += "Callback-Funktion ERFOLGREICH registriertn"; } else { msg.text += "Callback-Funktion NICHT erfolgreich registriertn"; } } else { msg.text += "EXTERNAL INTERFACE NICHT verfügbarn"; } callJS_btn.onRelease = function():Void { var returnedFromJS = ExternalInterface.call("executeMyCode2",lastMsg); if(returnedFromJS==null) { msg.text+= "after AS sent-> JS returned an ERRORn"; } else { msg.text+= "after AS sent-> JS returns: "+returnedFromJS+"n"; } } Listing 5.29: Die Aktionenebene beinhaltet den Import der ExternalInterface-Klasse sowie den not- wendigen Aufruf addCallback (Registrieren der Funktion calledByJS unter dem Pseudonym „tryIt“ für den Aufruf durch JavaScript) sowie call (Aufruf einer JavaScript-Funktion durch ActionScript). Zusätzlich hinzugekommen sind lediglich zwei Punkte: Erstens, dass wir den Rückga- bewert der Methode call nach dem Aufruf einer JavaScript-Funktion in einer Vari- able returnedFromJS speichern und diesen dann in einer if-Anweisung auswerten: Sollte der Rückgabewert null sein, so ist ein Fehler aufgetreten, der mehrere Gründe haben kann: Die aufgerufene JavaScript-Funktion (hier: executeMyCode2) existiert nicht: Pro- grammiererfehler … Sehen Sie nach, ob die JavaScript-Funktion tatsächlich unter dem Namen aufrufbar ist, den Sie verwenden. Die API (Anwendungsprogrammierungs-Schnittstelle) auf Browser-Seite zum Arbeiten mit der ExernalInterface-Klasse ist nicht vorhanden: Dies ist im Allgemeinen nur dann der Fall, wenn der Browser des Users die am Anfang des Kapitels aufgelisteten Mindestanforderungen nicht erfüllt. Da jedoch jeder halb- wegs gängige Browser diese Hürde mit Leichtigkeit überwindet, tritt dieser Fehler relativ selten auf. Es ist eine Rekursion aufgetreten: Rekursionen sind im Allgemeinen genau das Problem, das am häufigsten auftritt. Sie sind auch der Grund, warum eine automatische Rückmeldung von Flash an den Browser nicht funktioniert: Ruft u u u
  • 216.
    C L IE N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 203 JavaScript eine ActionScript-Funktion auf und ruft ActionScript wiederum eine JavaScript-Funktion auf, die von sich aus wiederum eine Antwort an ActionScript zurückliefert, erweckt es den Anschein einer Rekursion (in Wirklichkeit ist es keine Rekursion, aber Flash behauptet es zumindest). Es ist ein Sicherheitsproblem aufgetreten: Dies ist normalerweise innerhalb eines Browsers nicht der Fall, es sei denn, Sie arbeiten Domain-übergreifend. Hier schafft die Methode allowDomain der security-Klasse Abhilfe. Schlagen Sie in der ACTIONSCRIPT-REFERENZ unter security.allowDomain nach. Da man nicht genau eruieren kann, wodurch der Fehler aufgetreten ist (eine aus- führliche Fehlerbehandlungsmöglichkeit existiert erst ab ActionScript 3.0), wird von unserem Script nicht mehr als ein „after AS sent-> JS returned an ERROR“ ausgegeben – eine Fehlersuche (sollte wirklich ein Fehler auftreten) bliebe uns an dieser Stelle nicht erspart. Der zweite hinzugekommene Punkt ist eine (globale, da auf der Hauptzeitleiste erzeugte) Variable lastText, die den zuletzt von JavaScript gesandten Text speichert und so für die Rückgabe nach Klick auf den Button „Zurück an JS...“ bereithält. Der jeweils aktuelle Wert dieser Variable wird in der Funktion calledByJS gespeichert, die sich wie folgt darstellt: function calledByJS(myText:String):Void { msg.text+= "JS says: "+myText+"n"; var returnToJS:String = "OK: "+myText; lastMsg = myText; } Listing 5.30: Auch diese Funktion ist bereits hinlänglich bekannt – hinzugefügt wurde, dass der zuletzt von JavaScript gesandte Text in der Variable lastMsg gespeichert wird. Das fertige Beispiel finden Sie wie üblich auf der Buch-CD unter dem Namen brow- serAnFlashAnBrowser.fla sowie browserAnFlash_var3b.php. u
  • 217.
    K A PI T E L 5204 Flash an Browser an Flash Nun sehen wir uns die umgekehrte Richtung an: ActionScript sendet eine Message an JavaScript, welches wiederum eine Rückmeldung an ActionScript schickt. In diesem Fall werden wir das Problem einer Rekursion nicht vorfinden, da die Rückmeldung von JavaScript an Flash systembedingt erlaubt ist. Dieser Fall ist wesentlich einfach als der vorige, da ActionScript von JavaScript in jedem Fall eine Rückmeldung erhält, nachdem ActionScript eine JavaScript-Funktion aufgerufen hat – die ActionScript-Funktion call sorgt hierfür. Damit reduziert sich der JavaScript-Code auf: function executeMyCode2(textFromFlash) { return "OK, got '"+textFromFlash+"'"; } Listing 5.31: Die Funktion executeMyCode2 wird wie üblich diejenige Funktion sein, die von ActionScript aufgerufen wird. Sobald dies geschehen ist, liefert sie den an Sie übergebenen Wert inklusive des Textes „OK, got“ wieder zurück an Flash. Dies demonstriert sehr schön, wie ActionScript und JavaScript aus Rich- tung ActionScript zusammenarbeiten. Auch der ActionScript-Code ist wesentlich einfacher, da wir im Gegensatz zum vorigen Beispiel erstens keine Callback-Funktion mehr definieren und diese zweitens somit auch nicht mehr registrieren müssen. Einzig die Ein- und Ausgabefelder in Form von TextAreas sind mehr geworden – siehe Abbildung: ABBILDUNG 5.21 Der Text „teste mich!“ wird nach Klick auf „Daten sen- den“ an Flash geschickt, dort in der TextArea angezeigt. Nach Klick auf „Zurück an JS...“ wird der Text „AS says: teste mich!“ in die <textarea> (XHTML) geschrieben und von JavaScript die Meldung „OK“ an Flash zurückgeschickt, welche wiederum in der (Flash-)TextArea angezeigt wird. Basta!
  • 218.
    C L IE N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 205 var msgStatus:mx.controls.TextArea; msgStatus.text = "Initialisiere...n"; var msgIn:mx.controls.TextArea; msgIn.text = ""; var msgOut:mx.controls.TextArea; msgOut.text = "(type message)"; import flash.external.*; if(ExternalInterface.available) { msgStatus.text += "EXTERNAL INTERFACE verfügbarn"; } else { msgStatus.text += "EXTERNAL INTERFACE NICHT verfügbarn"; } callJS_btn.onRelease = function():Void { var sendMsg:String = msgOut.text; var returnedFromJS = ExternalInterface.call("executeMyCode2",sendMsg); msgStatus.text += "AS says: "+sendMsg+"n"; if(returnedFromJS==null) { msgIn.text+= "after AS sent-> JS returned an ERRORn"; } ABBILDUNG 5.22 Wie man schön sehen kann, befindet sich in der Funktionenebene kein Inhalt mehr, da wir keine Funktionen mehr benötigen. Die Anzahl der TextAreas hat sich erhöht, da wir eine TextArea für die Statusmeldungen, eine für den Eingabetext und eine für die Rückmeldungen von JavaScript an ActionScript verwenden.
  • 219.
    K A PI T E L 5206 else { msgIn.text+= "after AS sent-> JS returns: "+returnedFromJS+" n"; } } Listing 5.32: Code der Aktionenebene: Es werden insgesamt drei TextAreas definiert – msgStatus für Statusmeldungen, msgIn für von JavaScript an ActionScript gesandte Rückmeldungen und msgOut für den Eingabetext, der an JavaScript gesandt wird. Bei Klick auf den Button wird der vom User eingegebene Text in der Variable sendMsg zwischengespeichert, dann zunächst an JavaScript gesandt und danach in das Statusfeld als „an JS versendet“ ausgegeben. Zunächst werden die drei TextAreas„msgStatus“,„msgIn“ und„msgOut“ definiert und die ExternalInterface-Klasse importiert. Wie üblich überprüfen wir, ob die API im Browser verfügbar ist. Die eigentliche „Intelligenz“ liegt diesmal im Event-Handler des Buttons: Zunächst wird der vom User eingegebene Text in einer Variable sendMsg zwischen- gespeichert. Über die Methode call der ExternalInterface-Klasse wird die JavaScript-Funktion executeMyCode2 aufgerufen und dieser der Wert der zuvor gespeicherten Variable sendMsg übergeben. Der Rückgabewert der JavaScript-Funtkion wird danach in der Variable returnedFromJS gespeichert. Je nachdem, ob der JavaScript-Rückgabewert null oder nicht null war, wird unterschiedlich weiterverfahren: Bei null ist ein Fehler aufgetreten – welche Gründe für Fehler existieren, haben wir im Kapitel Browser an Flash an Browser ausführlich behandelt. Falls der Rückgabewert ungleich null ist, wird der von JavaScript zurückgelie- ferte Wert in der TextArea msgIn ausgegeben. Das getestete Beispiel sehen Sie in der nachfolgenden Abbildung: u u u u u
  • 220.
    C L IE N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 207 5.3.2 ExternalInterface-Klasse mit ActionScript 3.0 Bei Verwendung von ActionScript 3.0 hat sich bei den beiden Methoden addCallback und call etwas geändert: Methode Beschreibung addCallback(Pseudonym:String, AS-Funktion:Function):void Gegenüber der addCallback-Methode in ActionScript 2.0 exis- tiert der Instanz-Parameter nicht mehr.Außerdem liefert die Funktion nach dem Aufruf keinen Wert mehr zurück. call(JS-Funktion:String, Parameter:Object):* Sollte beim Aufruf der JavaScript-Funktion ein Fehler auftreten,so wird entweder ein System- oder ein Security-Fehler erzeugt.Somit besteht die Möglichkeit einer besseren Fehleranalyse.Der Wert null würde bei einem Fehler in jedem Fall zurückgeliefert werden. Tabelle 5.2: Änderungen der ExternalInterface-Klasse von ActionScript 2.0 auf 3.0 Wie wir also sehen, birgt ActionScript 3.0 keine herausragenden Neuerungen für uns. Und in Hinblick auf die Tatsache, dass es nicht Teil dieses Buchs ist, sich in die Tiefen von ActionScript 3.0 zu begeben, werde ich an dieser Stelle dem Gesagten auch nichts hinzufügen, sondern vielmehr auf die hervorragende Literatur zu AS 3.0 im Addison- Wesley Verlag hinweisen: „ActionScript 3.0“ von Selma-Caroline Kannengießer und Matthias Kannengießer, ISBN 978-3827325365 Wenden wir uns also wieder dem eigentlichen und grundlegenderen Thema zu: Flash & AJAX. Wie im vorigen Kapitel angekündigt, packen wir den Stier bei den Hörnern, reißen ihn zu Boden und warten ab. u ABBILDUNG 5.23 Es klappt – der von Flash an JavaScript übermit- telte Text „teste auch mich!“ wird von JavaScript empfangen und wieder an Flash zurückgeliefert. Das Beispiel liegt auf der Buch-CD unter den Namen FlashAnBrowserAnFlash.fla sowie flashAnBrowser04. htm zum Testen für Sie bereit.
  • 221.
    K A PI T E L 5208 5.4 Flash & AJAX Gehen wir in Medias Res. Wir wollen uns nun die Frage stellen, wie man das erwor- bene Wissen rund um unsere „Flash-Browser- bzw. Browser-Flash-Kommunikation“ mit dem vorigen Kapitel über AJAX kombinieren kann. Halten wir kurz fest: 1. Flash kann (mithilfe von getURL oder der ExternalInterface-Klasse) mit dem Browser kommunizieren: Es können JavaScript-Funktionen aufgerufen und an sie Variablenwerte übergeben werden. 2. Ein Browser kann mit Flash kommunizieren: 1. Mithilfe von setVariable können von einem Browser aus Variablenwerte gesetzt werden. 2. Binden wir die ExternalInterface-Klasse ein, sind wir sogar in der Lage, (freigegebene) Funktionen in Flash aufzurufen und an diese Variablen zu übergeben. 3. Nachdem AJAX auf Browser-Seite arbeitet und somit ebenso Flash-Funktionen aufrufen kann,sind wir somit auch in der Lage,beispielsweise nach einem erfolgten Laden von (zusätzlichen) serverseitigen Daten diese an Flash weiterzugeben. Hierzu ein kleines Diagramm, um unsere Idee grafisch festzuhalten: ABBILDUNG 5.24 AJAX kommuniziert mit dem Server und mit Flash.
  • 222.
    C L IE N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 209 5.4.1 Parameterübergabe:Text In diesem Teil des Flash & AJAX-Kapitels befassen wir uns mit der Übergabe von textbasierten Daten an Flash, im folgenden Kapitel werden wir statt Text- dann XML- Daten an Flash übergeben. Wir starten mit einer kleinen Anwendung, wo Sie die Interaktion von Flash und AJAX grafisch dargestellt sehen: Mithilfe einer kleinen „Ampel“ werden wir in Flash die AJAX-Kommunikation mit dem Server einerseits und Flash andererseits darstellen. Die Funktionsweise soll folgende sein: 1. Wir basteln eine XHTML-Seite, die drei Buttons beinhaltet: Initialisieren-Button: Wird auf diesen Button geklickt, wird das XMLHttp- Request-Objekt als Instanz angelegt und ihr ein Eventhandler zugewiesen. Öffnen-Button: Mithilfe dieses Buttons wird die Verbindung geöffnet, jedoch noch nicht abgeschickt. Senden-Button: Bei Klick wird die Anfrage an den Server abgeschickt. 2. Jeder (messbare) Zustand der XMLHttpRequest-Instanz soll in Flash in Form einer Art „Ampel“ angezeigt werden: Ampel ist rot: AJAX-technisch ist noch nichts passiert. Ampel ist orange: Die XMLHttpRequest-Instanz hat eine Verbindung zum Server geöffnet. In diesem Fall trägt die Eigenschaft readyState der Instanz den Wert 1. Ampel ist gelb: readyState hat den Wert 2 erreicht. Ampel ist dunkelgrün: readyState hat den Wert 3 erreicht. Ampel ist leuchtend grün: readyState ist nun auf den Wert 4 gewechselt, der uns kennzeichnet, dass die Anfrage erfolgreich stattgefunden hat und wir nun mit den erhaltenen Daten arbeiten können. 3. Ist die Anfrage abgeschlossen, soll der zurückgegebene Text (= Inhalt der Datei testrequest.txt) an Flash übergeben und in der TextArea angezeigt werden. Der Clou an dem Beispiel ist, dass wir unser erworbenes Wissen nur mehr zusammen- fügen müssen, da wir folgende Punkte bereits wissen: 1. Wir wissen, wie die AJAX-Kommunikation mit dem Server vor sich geht. 2. Wir wissen, wie die Kommunikation zwischen JavaScript und Flash vor sich geht. Was bleibt also zu tun? Um jeden Zustand der readyState-Eigenschaft in Flash anzuzeigen, müssen wir im Eventhandler der XMLHttpRequest-Instanz für jeden u u u u u u u u
  • 223.
    K A PI T E L 5210 der Zustände eine Flash-Funktion aufrufen – dazu werden wir auf die External- Interface-Klasse in Flash zurückgreifen. Ebenso verhält es sich mit der Anzeige des vom Server (durch die Datei testrequest.txt, die wir vom Server per AJAX anfordern) zurückgelieferten Textes: Wiederum rufen wir eine Flash-Funktion auf, die den Rest erledigt. Wir können die Aufgabe in drei Teile unterteilen: Das XHTML-Dokument mit den Buttons. Den AJAX-(JavaScript-)Teil, der einerseits die Datei testrequest.txt vom Server anfordert und andererseits mit Flash kommuniziert. Den Flash-Teil, der eine TextArea für die Ausgabe des Textes und unsere Ampel für die Anzeige der Zustände von readyState beinhaltet. Zur besseren Veranschaulichung finden Sie nachfolgend einen Screenshot, der das Ausgangsszenario widerspiegelt: u u u Der XHTML-Teil ist denkbar einfach, da im Wesentlichen nur die drei Buttons von Interesse sind: ... <input name="btnInit" type="submit" id="btnInit" value="Initialisieren" onclick="initXHR();" /> <input name="btnOpen" type="button" id="btnOpen" value="&Ouml;ffnen" onclick="openXHR();" /> ABBILDUNG 5.25 Unser Beispiel beinhaltet drei Buttons (Initialisieren, Öffnen und Senden) sowie eine SWF-Datei für die Anzeige von einerseits einem (Rückgabe-)Text und ande- rerseits einer kleinen „Ampel“.
  • 224.
    C L IE N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 211 <input name="btnSend" type="submit" id="btnSend" value="Senden" onclick="sendXHR();" /> ... Listing 5.33: Im XHTML-Teil werden über drei Buttons drei verschiedene Funktionen initXHR, openXHR und sendXHR aufgerufen. Befassen wir uns also gleich einmal mit dem JavaScript- und AJAX-Part. Die drei Funkti- onen initXHR, openXHR und sendXHR, die durch Klick auf die drei Buttons aufgerufen werden, initialisieren, öffnen und versenden die Anfrage an den Server. Zuvor wird in Zeile 1 des Scripts noch eine Variable für die XMLHttpRequest-Instanz angelegt: var myXMLHttpRequest; function initXHR() { myXMLHttpRequest = createRequestObject(); myXMLHttpRequest.onreadystatechange = handleRequest; } function openXHR() { myXMLHttpRequest.open("GET", "testrequest.txt", true); } function sendXHR() { myXMLHttpRequest.send(null); } Listing 5.34: Drei Funktionen für drei Aufgaben: Initialisieren, Öffnen und Abschicken. Zu Beginn wird noch eine Variable myXMLHttpRequest für die spätere XMLHttpRequest-Instanz angelegt. Die Funktion createRequestObject aus der Funktion init ist uns aus dem vorigen Kapitel über AJAX noch gut in Erinnerung, deshalb halte ich mich bei der Beschrei- bung relativ kurz: function createRequestObject() { try { var myRequest = new XMLHttpRequest(); } catch(error) { try { var myRequest = new ActiveXObject("MSXML2.XMLHTTP"); } catch(error) { var myRequest = new ActiveXObject("Microsoft. XMLHTTP"); } } return myRequest; } Listing 5.35: createRequestObject sorgt je nach verwendetem Browser für die korrekte Initialisierung der XMLHttpRequest-Instanz.
  • 225.
    K A PI T E L 5212 createRequestObject funktioniert nach dem „Trial and Error“-Prinzip: Klappt ein Codefragment (damit ist gemeint, dass beim Ausführen des Codefragments kein Feh- ler aufgetreten ist), das sich innerhalb einer try-Anweisung befindet, wird der catch- Abschnitt nicht mehr ausgeführt. Klappt es hingegen nicht, wird der catch-Teil ausgeführt. In unserer Funktion werden somit nach und nach alle Möglichkeiten des Instanzierens eines XMLHttpRequest-Objekts durchprobiert, bis ein Versuch geklappt hat. Details dazu finden Sie im Kapitel über AJAX. Das schlussendlich korrekt instan- zierte Objekt wird mit der return-Anweisung an den Aufrufer zurückgeliefert. Neben der Instanzierung wird im nächsten Schritt der soeben geschaffenen Instanz ein Eventhandler handleRequest für das Ereignis onreadystatechange zugewiesen. Diesem Eventhandler widmen wir uns weiter unten noch. In der Funktion openXHR wird die Instanz myXMLHttpRequest aufgefordert, eine Verbindung zur serverseitigen Datei testrequest.txt per GET herzustellen. Die Funktion sendXHR sorgt dann dafür, dass die geöffnete (aber noch nicht abge- schickte) Verbindungsanforderung auch abgeschickt wird. Der Eventhandler handleRequest ist der eigentlich interessante Teil für die Kom- munikation mit Flash: Bei jeder Zustandsänderung (spiegelt sich in der Eigenschaft readyState der XMLHttpRequest-Instanz wider) wird diese Funktion aufgerufen. Die switch-Anweisung hilft uns dabei, die fünf möglichen Zustände zu verarbeiten: function handleRequest() { var mySWF = getFlashElement("myswf"); switch(myXMLHttpRequest.readyState) { case 0: case 1: case 2: case 3: mySWF.showState(myXMLHttpRequest.readyState); break; case 4: mySWF.showState(myXMLHttpRequest.readyState); mySWF.showRet urnedText(myXMLHttpRequest.responseText); break; } } Listing 5.36: Zunächst finden wir durch den Funktionsaufruf getFlashElement eine korrekte Referen- zierung auf die SWF-Datei, danach kümmern wir uns darum, die readyState-Eigenschaft auszuwerten. Wie oben erwähnt soll der Eventhandler das bindende Glied zwischen AJAX und Flash darstellen – aus diesem Grund stellen wir eine Referenz zur SWF-Datei mit der ID (dem Namen) myswf her. Dies geschieht mittels der Funktion getFlashElement, die aus Listing 5.6 bekannt ist. Danach werten wir die Eigenschaft readyState aus: Für die Fälle 0–3 rufen wir eine Flash-Funktion namens showState auf, der wir den Wert von readyState übergeben (Flash wird diesen Wert in Form der angesprochenen
  • 226.
    C L IE N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 213 Ampel ausgeben). Ist readyState==4, hat der Server sämtliche angeforderten Daten zurückgeliefert – auch dieser Zustand soll von unserer Ampel angezeigt werden, des- halb rufen wir wie auch zuvor showState aus. Des Weiteren wollen wir die Rückgabe vom Server aber auch noch in einer TextArea anzeigen lassen, weshalb die Funktion showReturnedText zum Einsatz kommt. Kommen wir also zu Flash und seinen (freigegebenen) Funktionen: function showReturnedText(myText:String):Void { msg.text+= "AJAX says: "+myText+"n"; } function showState(readyState:Number):Void { msg.text+= "readyState: "+readyState+"n"; mcAmpel.gotoAndStop(readyState+1); } Listing 5.37: Die Flash-Funktionen showReturnedText und showState sorgen für die (grafische wie textuelle) Ausgabe. Es war anzunehmen, dass diese beiden Funktionen denkbar einfach sind, da es einer- seits nur um die Ausgabe von Text oder andererseits das Ansprechen eines MovieClips geht. showState gibt zunächst den (übergebenen) Wert von readyState in der TextArea aus und spricht dann den MovieClip mcAmpel an. Je nach Wert von ready- State werden ein, zwei, drei, vier oder fünf Ampellichter angezeigt – die Zwiebelscha- lendarstellung des MovieClips zeigt dies: ABBILDUNG 5.26 Die „Ampel“ in der Zwiebel- schalendarstellung. Pro Bild in der Zeitleiste kommt ein Satz an „Lampen“ hinzu.
  • 227.
    K A PI T E L 5214 Um die Funktionen showState und showReturnedText für JavaScript (oder letztens AJAX) verfügbar zu machen, müssen sie noch freigegeben werden. Aus Kapitel 5.3 ken- nen wir den Vorgang zwar, jedoch ist eine kleine Wiederholung nicht schlecht: ... import flash.external.*; if(ExternalInterface.available) { msg.text += "EXTERNAL INTERFACE verfügbarn"; if(ExternalInterface.addCallback("showState",null,showState) && ExternalInterface.addCallback("showReturnedText",null,showReturnedText )) { msg.text += "Callback-Funktionen ERFOLGREICH registriertn"; } else { msg.text += "Callback-Funktionen NICHT erfolgreich registriert n"; } } else { msg.text += "EXTERNAL INTERFACE NICHT verfügbarn"; } Listing 5.38: Auszug aus dem Code zum Registrieren/Freigeben der Flash-Funktion für JavaScript – add- Callback macht’s möglich. Hat das Registrieren beider Funktionen ordnungsgemäß funktioniert, wird in der TextArea msg der Text „Callback-Funktion ERFOLGREICH registriert“ ausgegeben – dies ist unsere Kontrolle, dass keine Fehler vorgefallen sind. Testen wir das Beispiel, um uns von dessen Funktion zu vergewissern: ABBILDUNG 5.27 Nachdem die Buttons „Initialisieren“ und „Öffnen“ angeklickt wurden, schaltet die Ampel auf Orange (zweite Ampelreihe).
  • 228.
    C L IE N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 215 Überlegen wir uns nun als konkretes Beispiel folgenden Fall: Wir erstellen eine kleine Umfrageseite, in der ein User aufgefordert wird, aus einer Liste von Antworten zu einer gegebenen Frage eine Antwort auszuwählen. Sobald er seine Auswahl bestätigt hat, wird seine „Stimme“ per AJAX an den Server geschickt und dort in einer Daten- bank abgelegt. Der Server soll die Anzahl der „Stimmen“ pro vorgegebener Antwort zurückliefern. Sobald der Server dies getan hat, übergibt AJAX an Flash diese Informa- tionen, wodurch Flash eine kleine Grafik (eine Art „Balkendiagramm“) aufbaut, die das Ergebnis der Umfrage in Form eines Balkendiagramms grafisch darstellt. Klickt der User dann auf einen der Balken in der Flash-Anwendung, so sollen Details zu diesem Balken in der XHTML-Datei angezeigt werden. Im nachfolgenden Bild finden Sie zunächst einmal die Ausgangssituation, dass die Anwendung auf eine Stimme von Ihnen wartet – auch die Flash-Anwendung zeigt im Moment noch keine Grafik an: ABBILDUNG 5.28 Klicken wir auch noch den „Senden“-Button, schal- tet die Ampel nach und nach auf Grün (unterste Lampenreihe) und gibt den per AJAX angeforderten Text der Datei testrequest.txt in der TextArea aus. Perfectly done! Klappt natürlich in jedem (gängigen) Browser ...
  • 229.
    K A PI T E L 5216 Hat der User eine Auswahl getroffen und seine Stimme durch einen Klick auf den Button „Abstimmen“ abgegeben, wird diese Stimme in der Datenbank gespeichert (AJAX & PHP). Der Server gibt als Response eine URL-codierte Ausgabe an AJAX zurück, welche wiederum an Flash übergeben wird. Flash bastelt aus diesen Daten die Balkengrafik: ABBILDUNG 5.29 Die Applikation wartet auf Ihre Stimme … ABBILDUNG 5.30 Es wurde eine Stimme für „Ducati“ abgegeben. Flash zeigt sogleich auch das bis- herige Voting an. Klickt der User danach auf einen der Balken in der Flash-Datei, so wird unterhalb des „Abstimmen“-Buttons eine detailliertere Ausgabe des Votings für den geklickten Balken ausgegeben:
  • 230.
    C L IE N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 217 Wie üblich beginnen wir mit der Analyse der XHTML-Datei. Ich empfehle Ihnen, par- allel zum Buch die jeweiligen Dateien auf Ihrem Computer zu öffnen – im jetzigen Fall handelt es sich um die Datei ajax02.php aus dem Verzeichnis zum aktuellen Kapitel. ... <div id="Umfrage"> <form name="frmVote" id="frmVote" action=""> <div> <?php $conn = mysql_connect("mysql.syneweb.com","usr_flashphpajax","flashmyph pajax") or die('<div class="error">Die Verbindung zum Datenbankserver konnte NICHT hergestellt werden. Error: '.mysql_error().'</div>'); $db = mysql_select_db("db_flashphpajax") or die('<div class="error">Die Datenbank konnte NICHT ausgewaehlt werden. Error: ‚.mysql_error().'</div>'); $sql = "SELECT * FROM tbl_05fragen WHERE(bitP_chk_aktiv=1) ORDER BY RAND() LIMIT 1"; $query = mysql_query($sql); $data = mysql_fetch_array($query); $sql = "UPDATE tbl_05fragen SET dt_LetzterAufruf='".date("Y-m-d")."', int_ AnzahlAufrufe=int_AnzahlAufrufe+1 WHERE idP_Frage=".$data["idP_Frage"]; $query = mysql_query($sql); $msgOut = '<input type="hidden" name="idP_Frage" id="idP_Frage" ABBILDUNG 5.31 Nachdem der User einen Balken (in unserem Fall den Balken „Ducati“) angeklickt hat, werden die Details der Umfrage für diese Auswahl dargestellt (unterhalb des „Abstimmen“-Buttons).
  • 231.
    K A PI T E L 5218 value="'.$data["idP_Frage"].'" />'; $msgOut.= '<p>'.$data["vcP_Bezeichnung"].'</p>'; $sql = "SELECT * FROM tbl_05antworten WHERE(fidP_select_Bezeichnung_ Frage=".$data["idP_Frage"]." AND bitP_chk_aktiv=1) ORDER BY int_ Reihenfolge"; $query = mysql_query($sql); while($data2 = mysql_fetch_array($query)) { $msgOut.= '<div><input type="radio" name="antwort" value="'.$data2["idP_Antwort"].'" />'.$data2["vcP_Antwort"].'</div>'; } echo($msgOut); ?> </div> <div><input type="button" name="btnVote" id="btnVote" value="Abstimmen" onclick="vote();" /></div> </form> <div id="Details"></div> </div> <div id="Flash">...</div> <div class="cleaner"></div> ... Listing 5.39: Auszug aus dem Code der XHTML-Datei ajax02.php Wir finden darin einige wesentliche Elemente: Ein Formular „frmVote“, um auf die Formularfelder (Radiobuttons) zugreifen zu können. Zwei SQL-Abfragen, wobei die erste der beiden per Zufall eine Frage aus der Daten- bank auswählt und die zweite danach die zugehörigen Antwortmöglichkeiten aus einer zweiten Tabelle lädt (das Tabellengerüst finden Sie in nachfolgender Abbil- dung). Den Button „btnVote“ zum Abstimmen, der auf onclick die Funktion vote auf- ruft. Einen (noch) leeren DIV-Container „Details“, den wir für die Ausgabe der Detail- infos verwenden. u u u u
  • 232.
    C L IE N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 219 Die eingebundene Flash-Datei (im Container „Flash“) versteht sich von selbst und wurde deshalb aus dem Script entfernt, um es besser lesbar zu machen – in der Origi- naldatei ist ein entsprechendes <object> usw. selbstverständlich enthalten. Der erste interessante Part ist also die Abfrage der Datenbank, um zu einer Umfra- ge zu kommen. In den ersten Zeilen des PHP-Teils wird zunächst Verbindung mit dem Datenbankserver aufgenommen (mysql_connect), danach eine Datenbank ausgewählt (mysql_select_db) und schließlich ein SQL-Statement $sql abgesetzt (mysql_query), das aus den gegebenen und aktiven (bitP_chk_aktiv=1) Einträgen der Tabelle tbl_05fragen per Zufall (RAND()) einen (LIMIT 1) Datensatz zurückliefert. Dieser eine Datensatz wird in $data gespeichert. Im zweiten SQL-Statement wird der Eintrag mit der soeben gewählten Frage dahin- gehend verändert, als dass die Anzahl der Aufrufe der Frage um eins erhöht (int_ AnzahlAufrufe=int_AnzahlAufrufe+1) und als letztes Abfragedatum das aktuelle Datum eingetragen wird (dt_LetzterAufruf='".date("Y-m-d")). Danach wird ein drittes SQL-Statement (welches wieder den Namen $sql trägt) abgesetzt, das aus der Tabelle tbl_05antworten zu der gegebenen Frage (fidP_select_ Bezeichnung_Frage=".$data["idP_Frage"]) alle aktiven (bitP_chk_aktiv=1) Antworten auswählt und entsprechend der in der Tabelle gespeicherten Reihenfolge (ORDER BY int_Reihenfolge) zurückliefert. Mithilfe einer while-Schleife wird aus dem Ergebnis eine Variable $msgOut zusammengebastelt, die als Inhalt eine Anzahl an Radio-Buttons mit den entsprechenden Antworten enthält. Am Ende der Schleife wird $msgOut per echo ausgegeben. Das entsprechende Ergebnis sehen Sie in Abbildung 5.29. Gehen wir weiter zur Funktionalität des„Abstimmen“-Buttons. Dieser stellt wie üblich die Schnittstelle zu AJAX her, indem er die Funktion vote aufruft, die die Anfrage an den Server stellt: function vote() { var found = false; for(var i=0; i<document.forms["frmVote"].elements["antwort"].length; i++) { if(document.forms["frmVote"].elements["antwort"][i].checked==true) { var theVote = document.forms["frmVote"].elements["antwort"][i].value; found = true; ABBILDUNG 5.32 Eine einfache Tabellenstruktur bil- det die Basis unserer Umfrageanwendung.
  • 233.
    K A PI T E L 5220 break; } } if(found) { var idP_Frage = document.forms["frmVote"].elements["idP_Frage"]. value; var querystring = "idP_Frage="+idP_Frage+"&idP_Antwort="+theVote; myXMLHttpRequest.open("GET", "storevote.php?"+querystring, true); myXMLHttpRequest.onreadystatechange = handleRequest; myXMLHttpRequest.send(null); document.getElementById("Details").innerHTML = ""; } else { alert("Bitte treffen Sie Ihre Wahl..."); } } Listing 5.40: Die Funktion vote, welche die Schnittstelle zwischen dem Formular zum Abstimmen und der AJAX-Anwendung bildet. Ziel dieser Funktion ist zweierlei: 1. Überprüfen, ob der User auch wirklich eine Auswahl getroffen hat (er könnte ja auch auf den „Abstimmen“-Button geklickt haben, ohne zuvor eine Auswahl getroffen zu haben) und wenn ja, welche. 2. Die getroffene Auswahl per AJAX an den Server übermitteln, um diese in die Datenbank zu schreiben. Ob der User tatsächlich abgestimmt hat, wird in der Variable found gespeichert. Hierzu wird in einer for-Schleife jeder Radio-Button namens „antwort“ auf den Wert checked==true überprüft. Wurde ein solcher Radio-Button gefunden, wird der Wert dieses Buttons in theVote gespeichert und found auf true gesetzt. Danach wird die Schleife abgebrochen (break), da es wenig Sinn macht, die restlichen Radio-Buttons auch noch zu überprüfen, da nur ein einziger Button ausgewählt sein kann. Wurde hingegen kein ausgewählter Radio-Button gefunden, ist found nach wie vor false. Genau dieser Wert wird darauffolgend mithilfe der if-Bedingung überprüft. Bei true wird eine Variable querystring erzeugt, welche die ID der Frage (idP_Frage) und die ID der Antwort (idP_Antwort) speichert. Diese Variable wird danach an die Datei storevote.php als URL-codierter Query-String angehängt. Per open wird die Verbin- dung zum Server geöffnet, onreadystatechange definiert einen Eventhandler für Änderungen in der Eigenschaft readyState und send schickt die Anfrage schlussend- lich ab. Danach wird noch dafür gesorgt, dass der Container „Details“ leer ist.
  • 234.
    C L IE N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 221 Natürlich wurde weiter oben die Variable myXMLHttpRequest per var myXMLHttpRequest = createRequestObject(); als Instanz eines XMLHttpRequest-Objekts angelegt – die Zuweisung des korrekten Objekts (je nach verwendetem Browser) erfolgt in einer Funktion createRequest- Object, welche in der externen JavaScript-Datei common.inc.js abgelegt ist. Dieses Prozedere ist aus dem vorigen Kapitel hinlänglich bekannt. Gehen wir also weiter zum Eventhandler handleRequest: function handleRequest() { switch(myXMLHttpRequest.readyState) { case 0: case 1: case 2: case 3: break; case 4: if(myXMLHttpRequest.responseText.indexOf("ERROR")!=-1) { alert("Es ist ein FEHLER beim Voting aufgetreten - bitte versuchen Sie es erneut!"); } else { var mySWF = getFlashElement("myswf"); mySWF.showVoteData(myXMLHttpRequest.responseText); } break; } } Listing 5.41: Der Eventhandler für die AJAX-Kommunikation Wie wir wissen, erledigt dieser Eventhandler die Abarbeitung der möglichen Zustände der readyState-Eigenschaft. Die Fälle 0–3 sind nicht interessant, deshalb brechen wir hier einfach mit break ab (sollte Ihnen das Kopfzerbrechen bereiten, so schlagen Sie bitte im vorigen Kapitel zu AJAX nach). Viel interessanter ist der Fall 4, wo der Server sämtliche angeforderten Daten zurückgeliefert hat. Die angeforderte Datei storevote. php ist so aufgebaut, dass sie im Fall eines Fehlers eine entsprechende Fehlermeldung mit dem Text „ERROR“ ausgibt. Das Script sucht also in der Rückgabe (response- Text) nach dem Text„ERROR“ – sollte dieser vorkommen, liefert die Methode index- Of diejenige Position im String zurück, wo „ERROR“ vorkommt. Sollte „ERROR“ nicht gefunden werden, liefert sie -1 zurück. Finden wir einen Fehler, wird über alert
  • 235.
    K A PI T E L 5222 eine entsprechende Fehlermeldung ausgegeben, finden wir keinen Fehler, erzeugen wir eine Referenz auf das eingebundene Flash-Element „myswf“ und rufen die dort freigegebene Funktion showVoteData mit dem soeben erhaltenen Rückgabewert von storevote.php auf. Bevor wir uns der Flash-Anwendung widmen, müssen wir noch einen Blick auf store- vote.php werfen: if(count($_GET)>0 && isset($_GET["idP_Antwort"]) && isset($_GET["idP_Frage"])) { $conn = mysql_connect("mysql.syneweb.com","usr_flashphpajax","flashmyph pajax") or die('<div class="error">Die Verbindung zum Datenbankserver konnte NICHT hergestellt werden. Error: '.mysql_error().'</div>'); $db = mysql_select_db("db_flashphpajax") or die('<div class="error">Die Datenbank konnte NICHT ausgewaehlt werden. Error: ‚.mysql_error().'</div>'); $sql = "UPDATE tbl_05antworten SET int_AnzahlStimmen=int_ AnzahlStimmen+1 WHERE(idP_Antwort=".$_GET["idP_Antwort"].")"; if(!$query = mysql_query($sql)) { $returner = "ERROR (1)"; } else { $sql = "SELECT * FROM tbl_05antworten WHERE(fidP_select_Bezeichnung_ Frage=".$_GET["idP_Frage"].")"; if(!$query = mysql_query($sql)) { $returner = "ERROR (2)"; } else { $returner = ''; $i = 0; while($data = mysql_fetch_array($query)) { $returner.= 'ID'.$i.'='.$data["idP_Antwort"].'&Antwort'.$i.'='.$dat a["vcP_Antwort"].'&Anzahl'.$i.'='.$data["int_AnzahlStimmen"].'&'; $i++; } $returner = substr($returner,0,$returner.length-1); } } } else { $returner = "ERROR (3)"; } echo($returner); Listing 5.42: Der Code der Datei storevote.php (zu finden auf der Buch-CD) Gleich im ersten Schritt der Datei wird überprüft, ob an die Datei überhaupt GET- Daten übergeben wurden (count($_GET)>0) und ob die benötigten Informationen über die Frage und die Antwort darin enthalten sind (isset($_GET["idP_Ant-
  • 236.
    C L IE N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 223 wort"]) && isset($_GET["idP_Frage"])). Sollte dem nicht so sein, wird eine Rückgabevariable $returner auf den Wert „ERROR (3)“ gesetzt. War hingegen alles wie gewünscht, so gehen wir einen Schritt weiter und stellen die Verbindung zum Datenbankserver und zur Datenbank her. Das erste SQL-Statement sorgt dafür, dass die Stimme des Users für die gegebene Antwort gespeichert wird. Falls dieses UPDATE-Statement fehlgeschlagen ist, wird in $returner der Wert „ERROR (1)“ gespeichert und abgebrochen. War es erfolgreich, wird das zweite SQL-Statement ausgeführt, das für die gestellte Frage alle Antworten mit ID, Antworttext und Anzahl abgegebener Stimme in eine entsprechende Form bringt (gesetzt den Fall, dass die Abfrage erfolgreich durchgeführt werden konnte): IDn=...&Antwortn=...&Anzahln=... n steht für eine Zählvariable, um jede „Variable“ eindeutig zu machen. Es ist Ihnen sicherlich aufgefallen, dass der Rückgabestring in URL-codierter Form generiert wird – im nächsten Kapitel werden wir noch lernen, warum diese Form ideal für eine Datenübergabe an Flash ist. Als Beispiel für den Rückgabestring hier eine Ausgabe zu den obig dargestellten Abbildungen: ID0=14&Antwort0=BMW&Anzahl0=7&ID1=15&Antwort1=Ducati&Anzahl 1=34&ID2=16&Antwort2=KTM&Anzahl2=10&ID3=17&Antwort3=keine der angegebenen&Anzahl3=2 Listing 5.43: Ein möglicher Rückgabestring in URL-codierter Form Im Ideal- oder Normalfall (nämlich dann, wenn das Abarbeiten von storevote.php erfolgreich war) erhalten wir als responseText der XMLHttpRequest-Instanz genau diesen Text, der schnell an Flash übergeben wird (siehe Listing 5.41). Also auf zu Flash! Wir benötigen einerseits die ExternalInterface-Klasse, um die reibungslose Kommunikation zwischen Flash und JavaScript zu gewährleisten, und andererseits die DropShadowFilter-Klasse, um die Ausgabe ein wenig aufzupeppen: import flash.filters.DropShadowFilter; var dropShadow:DropShadowFilter = new DropShadowFilter(4, 45, 0x333333, 0.8, 10, 10, 2, 3); import flash.external.*; //var msg:mx.controls.TextArea; if(ExternalInterface.available) { if(ExternalInterface.addCallback("showVoteData",null,showVoteData)) { //msg.text += "Callback-Funktion ERFOLGREICH registriertn"; }
  • 237.
    K A PI T E L 5224 else { //msg.text += "Callback-Funktion NICHT erfolgreich registriertn"; } } else { //msg.text += "EXTERNAL INTERFACE NICHT verfügbarn"; } Listing 5.44: Der Code der Aktionenebene: Es werden zwei Klassen eingebunden, ein Schlagschatten definiert und überprüft, ob ExternalInterface verfügbar ist und die Callback-Funktion erfolgreich registriert wurde. Die Variable dropShadow speichert eine Instanz des Objekts DropShadowFilter für die weitere Verwendung (Details zu den Parametern finden Sie in der ActionScript- Referenz). Des Weiteren finden Sie einige auskommentierte Codeteile für den Fall, dass Sie eine TextArea namens msg in Verwendung haben (beispielsweise für die Ausgabe etwaiger Informationsmeldungen). Rufen wir uns in Erinnerung, dass JavaScript eine Funktion showVoteData aufruft (diese Funktion wurde als Callback-Funktion registriert): function showVoteData(myData:String):Void { var myDataArray:Array = parseDataIntoArray(myData); createDiagram(myDataArray); } Listing 5.45: Die Funktion showVoteData, die für JavaScript freigegeben wurde An showVoteData wird wie oben beschrieben vonAJAX (JavaScript) der URL-codierte String der PHP-Datei storevote.php übergeben: Die Variable myData wird diesen String beinhalten. Um mit diesem String ordentlich arbeiten zu können, werden wir ihn in ein Array parsen – dazu verwenden wir die Funktion parseDataIntoArray: function parseDataIntoArray(myData:String):Array { var myLoadVars:LoadVars = new LoadVars(); myLoadVars.decode(myData); var returner:Array = new Array(); var i:Number = 1, j:Number = 0, highestVal:Number = 0, itmname:String; returner[0] = new Array(); for(itm in myLoadVars) { itmname = itm.toLowerCase(); if(itmname.indexOf("anzahl")!=-1 && parseInt(myLoadVars[itm])>highe stVal) { highestVal = parseInt(myLoadVars[itm]); }
  • 238.
    C L IE N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 225 if(j==0) { returner[i] = new Array(); } returner[i][j] = myLoadVars[itm]; j++; if(j==3) { j = 0; i++; } } returner[0][0] = highestVal; return returner; } Listing 5.46: Die Funktion parseDataIntoArray schreibt die von JavaScript übergebenen Werte in ein zweidimensionales Array returner. Die einfachste Art, um mit URL-codierten Daten zu arbeiten ist, diese in ein sogenann- tes LoadVars-Objekt zu laden – dazu dient die Methode decode. Das LoadVars-Objekt Grundsätzlich wird dieses Objekt zum Laden serverseitiger Daten in Flash verwendet – Details hierzu lernen Sie im folgenden Kapitel. Da wir in diesem Beispiel eigentlich auch mit serverseiti- gen Daten zu tun haben (unsere URL-codierten Daten), können wir das LoadVars-Objekt ein bisschen zweckentfremden und es zum leichteren Auslesen dieser URL-codierten Daten verwen- den. Nach dem Ausführen von decode befinden sich alle Daten als Variablen in der Load- Vars-Instanz – eine for-in Schleife ist somit ideal zum Auslesen aller Daten. Zuvor legen wir noch einen ersten Eintrag im Array returner an, wo wir an Stelle [0][0] die höchste eingelesene Anzahl an Stimmen speichern werden. Innerhalb der for-in-Schleife müssen wir beim Parsen berücksichtigen, dass wir pro Datensatz immer drei Informationen einlesen müssen: ID, Anzahl und Antwort. Aus diesem Grund lassen wir eine Variable j mitzählen, die die Werte 0–2 einnehmen soll. Sobald j==3 ist, wird j wieder auf 0 gesetzt und i um eins erhöht. Ist j==0, wird ein neuer Eintrag im returner-Array erzeugt. So weit zum grundsätzlichen Ablauf. Sollte die gerade bearbeitete Variable einen Text „anzahl“ im Namen tragen, wird der Wert in eine Ganzzahl umgewandelt (parseInt) und überprüft, ob die gerade eingelesene Anzahl größer als der höchste gespeicherte Wert für die Anzahl der abgegebenen Stim- men ist (parseInt(myLoadVars[itm])>highestVal). Falls ja, wird dieser Wert als der höchste Wert gespeichert. Zuletzt schreiben wir den Wert von highestVal wie besprochen an die Stelle [0][0] des returner-Arrays und liefern das Array an den Aufrufer (die Funktion showVo- teData) zurück, wo das Array als myDataArray weiterverarbeitet wird. Um die Daten nun darzustellen, wird im zweiten Schritt die Funktion createDiagram aufgerufen, die das eigentliche Balkendiagramm erzeugt: LoadVars & URL- codierte Informa- tionen LoadVars & URL- codierte Informa- tionen
  • 239.
    K A PI T E L 5226 function createDiagram(myDataArray:Array):Void { mcWarten._visible = false; var maxVal:Number = 160; var xScaler:Number = maxVal/myDataArray[0][0]; var stringMaxLength:Number = 15; var balkenOffsetX:Number = 120; var balkenOffsetY:Number = 0; var myFormat:TextFormat = new TextFormat(); myFormat.font = "Arial"; myFormat.size = 12; for(var i:Number=1; i<myDataArray.length; i++) { var myName:String = "Balken"+i; this.createEmptyMovieClip(myName,i); this[myName].id = myDataArray[i][2]; this[myName]._x = 120; this[myName]._y = 5+(i-1)*15; this[myName].createTextField("myTextfield",0,-110,0,100,20); var theText:String = myDataArray[i][1]; if(theText.length>stringMaxLength) { theText = theText. substr(0,stringMaxLength-2)+".."; } this[myName]["myTextfield"].text = theText; this[myName]["myTextfield"].setTextFormat(0, this[myName]["myTextfiel d"].text.length, myFormat); this[myName].createEmptyMovieClip("mcRechteck",1); drawBalken(this[myName]["mcRechteck"], myDataArray[i][0]*xScaler, 10, 0x99FF00); this[myName].onRelease = function():Void { import flash.external.*; ExternalInterface.call("showDetailData",this.id) }
  • 240.
    C L IE N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 227 } } Listing 5.47: Die Funktion createDiagram sorgt dafür, dass aus den übermittelten Daten ein Balkendia- gramm erzeugt wird. Betrachten wir die Funktion genauer, stechen zunächst folgende Schritte bzw. Defini- tionen ins Auge: mcWarten._visible = false: Der Text „WARTE AUF DATEN…“ (siehe Abbil- dung 5.29) ist im MovieClip mcWarten verpackt. Da dieser nach dem Aufbau der Balken nicht mehr benötigt wird, wird er ausgeblendet. var maxVal:Number = 160: Die Variable maxVal bestimmt die Länge des längs- ten Balkens – an ihm werden alle anderen Balken gemessen und so entsprechend skaliert. var xScaler:Number = maxVal/myDataArray[0][0]: xScaler berechnet aus der zuvor angegebenen maximalen Länge eines Balkens (maxVal) und der höchs- ten Anzahl an Stimmen (myDataArray[0][0] – siehe Beschreibung zu highest- Val weiter oben) den Skalierungsfaktor für jeden Balken. var stringMaxLength:Number = 15: Diese Variable gibt an, wie lange der Beschriftungstext (die „Antwort“, die der User angezeigt bekommen hat) vor einem Balken maximal sein darf, bevor er abgeschnitten wird und ihm zwei Punkte „..“ angehängt werden. var balkenOffsetX:Number = 120: Nullabstand des Balkens in horizontaler Richtung vom Anfang der Beschriftung des Balkens var balkenOffsetY:Number = 3: Nullabstand des Balkens in vertikaler Rich- tung vom Anfang der Beschriftung des Balkens Zwischenzeitlich erzeugen wir noch eine Formatvorlage myFormat (Schriftart Arial, Textgröße 12 Pixel) für den Beschriftungstext, die wir dann auf alle Beschriftungstexte anwenden werden: var myFormat:TextFormat = new TextFormat(); myFormat.font = "Arial"; myFormat.size = 12; Danach werden in einer for-Schleife sämtliche Balkendaten im Array myDataArray durchgegangen, wobei wir uns in Erinnerung halten müssen, dass pro Eintrag in myDataArray ein weiteres Array mit drei Einträgen steckt: myDataArray[n][0]: Anzahl der Stimmen myDataArray[n][1]: Beschriftung des Balkens u u u u u u u u
  • 241.
    K A PI T E L 5228 myDataArray[n][2]: ID der Antwort (in unserer Tabelle tbl_05antworten ent- spricht dieser Wert dem Feld idP_Antwort) (n steht für einen beliebigen Eintrag im Array.) Innerhalb der Schleife erzeugen wir zunächst einen leeren MovieClip mit dem Namen „BalkenN“ (wobei N wiederum für einen fortlaufenden Zähler der Schleife – bei uns: die Variable i – steht). Innerhalb des neu erstellten Clips merken wir uns die zugehö- rige ID in der Variable id und setzen den Clip entsprechend des Schleifenzählers an eine x- (immer 0) und y-Position (mit einem Offset von 5 Pixel dann alle 15 Pixel nach unten: 5+(i-1)*15). Vielleicht ist Ihnen aufgefallen, dass die for-Schleife nicht bei 0 zu zählen beginnt, wie das normalerweise üblich wäre, wenn man alle Einträge des myDataArray durchgehen möchte. In unserem Fall ist jedoch die Position 0 dieses Arrays durch die höchste vor- kommende Stimmenanzahl (highestVal aus der Funktion parseDataIntoArray) definiert und erst ab Position 1 sind die eigentlichen Balkenwerte gespeichert. Im neuen Clip legen wir für die Beschriftung ein neues Textfeld an (dies trägt pro Clip immer denselben Namen „myTextfield“), Position [0][0] mit einer Länge von 120 Pixel und einer Höhe von 20 Pixel. Im selben Atemzug kümmern wir uns um den Inhalt dieses Textfelds: Sollte der Beschriftungstext länger als die maximal von uns gewünschte Anzahl an Zeichen sein (theText.length>stringMaxLength), so kür- zen wir den Text auf diese Länge minus 2 Pixel (= Anzahl der Punkte, die angehängt werden), hängen zwei Punkte „..“ an und weisen den Text korrekter Länge dann dem zuvor neu erzeugten Textfeld zu. Abschließend wenden wir die Formatvorlage myFor- mat noch auf den gesamten Text an – der Beschriftungsteil ist abgehakt. Wenden wir uns dem Erzeugen eines Balkens (letzten Endes eines Rechtecks oder vierer Linien) zu. Schritt eins ist das Erzeugen eines eigenen MovieClips im MovieC- lip BalkenN mit dem Namen „mcRechteck“. Schritt zwei umfasst das Aufrufen einer selbst gebastelten Funktion drawBalken, an die wir den Namen des MovieClips, worin der Balken gezeichnet werden soll, den Offset zum Zeichnen in x- und y-Richtung, die Breite und Höhe des Balkens sowie die Farbe des Balkens (in hexadezimaler Notation) übergeben: function drawBalken(mcBalken:MovieClip, boxOffsetX:Number, boxOffsetY: Number, boxWidth:Number, boxHeight:Number, fillColor:Number):Void { if(boxWidth==0) { boxWidth = 1; } with (mcBalken) { beginFill(fillColor, 100); moveTo(boxOffsetX,boxOffsetY+0); lineTo(boxOffsetX+boxWidth, boxOffsetY); lineTo(boxOffsetX+boxWidth, boxOffsetY+boxHeight); lineTo(boxOffsetX, boxOffsetY+boxHeight); u Schleifenbeginn bei 1, nicht bei 0 Schleifenbeginn bei 1, nicht bei 0
  • 242.
    C L IE N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 229 lineTo(boxOffsetX, boxOffsetY); endFill(); filters = [dropShadow]; } } Listing 5.48: Die Funktion drawBalken zeichnet einen Balken mit Mindestlänge 1 Pixel, bestehend aus vier Linien, die mit einer Füllfarbe gefüllt werden und dem so erzeugten Rechteck einen Schlagschatten zuweisen. Da es wenig Sinn macht, einen Balken mit der Länge null zu zeichnen, setzen wir die Länge des Balkens auf minimal 1 Pixel (ansonsten würden wir auch Gefahr laufen, dass der User annimmt, hier würden Balken einfach fehlen): Usability: bei keinen Stimmen trotzdem Balken mit Länge 1 Pixel Usability: bei keinen Stimmen trotzdem Balken mit Länge 1 Pixel Mit dem übergebenen MovieClip starten wir das Zeichnen eines Balkens, indem wir vier Linien zeichnen und den Bereich füllen (beginFill(fillColor, 100) – es wird die Füllfarbe fillColor zu 100% Deckkraft, wobei die Deckkraft nicht gesondert angegeben werden müsste). Die Methode moveTo sorgt dafür, dass wir an der richtigen Stelle zu zeichnen beginnen, da sie die Zeichnen-Startposition an die gegebene Stelle setzt. Sind alle vier Linien mit lineTo gezeichnet worden, kann das Füllen der so entstandenen Fläche wieder beendet und der Schlagschatten dropShadow angewandt werden (die Definition des Schlagschattens finden Sie in der Aktionenebene, die in Listing 5.44 beschrieben wurde). Mittlerweile sind Beschriftung und Balken erzeugt. (Zur Erinnerung: Wir befinden uns im letzten Teil der for-Schleife aus Listing 5.47.) Unsere Aufgabenstellung sieht jedoch vor, dass der User einen Klick auf den Balken machen kann und so Details zum geklickten Balken bekommt – dies bedeutet für uns, dass wir unserem gesamten Clip noch ein onRelease-Ereignis zuweisen müssen: ... this[myName].onRelease = function():Void { import flash.external.*; ABBILDUNG 5.33 Besser einen Balken mit 1 Pixel Länge erzeugen (bei null Stimmen) als keinen Balken – kein Balken wirkt auf den User als „Fehler“.
  • 243.
    K A PI T E L 5230 ExternalInterface.call("showDetailData",this.id) } ... Listing 5.49: Auszug aus Listing 5.47 Beim Loslassen der Maustaste (onRelease) laden wir nochmals die External- Interface-Klasse (diese ist die einzige Klasse innerhalb flash.external) und rufen die JavaScript-Funktion showDetailData mit der MovieClip-eigenen id-Variable (idP_Antwort der Tabelle tbl_05antworten) auf. Der Flash-Part wäre aber an dieser Stelle beendet – also zurück zu JavaScript. Wie oben beschrieben wird beim Klick auf einen Balken (oder auf dessen Beschrif- tung) über die ExternalInterface-Klasse die JavaScript-Funktion showDetail- Data aufgerufen. Sie sorgt dafür, dass per AJAX Detaildaten zum geklickten Balken angezeigt werden: function showDetailData(idP_Antwort) { var querystring = "idP_Antwort="+idP_Antwort; myXMLHttpRequest.open("GET", "getdetails.php?"+querystring, true); myXMLHttpRequest.onreadystatechange = handleRequestDetail; myXMLHttpRequest.send(null); } Die Funktion showDetailData öffnet ihrerseits eine Verbindung zum Server auf die Datei getdetails.php, um Detailinformationen zu einer gegebenen Antwort abzuru- fen. Hierzu wird die angeforderte Antwort-ID als Querystring an den Dateinamen angehängt, der XMLHttpRequest-Instanz ein Eventhandler handleRequestDetail zugewiesen und die Anfrage abgeschickt. Der an dieser Stelle verwendete Eventhandler ist selbstverständlich nicht derselbe wie der Eventhandler, den wir für die Abarbeitung der Anfrage für Fragen aus Listing 5.41 verwendet haben – wir wollen ja den Rückga- bewert nicht an Flash übergeben, sondern in dem dafür vorgesehenen DIV-Container „Details“ (siehe Listing 5.39) darstellen. Keine großen Geheimnisse birgt die Datei getdetails.php für uns: if(count($_GET)>0 && isset($_GET["idP_Antwort"])) { $conn = mysql_connect("mysql.syneweb.com","usr_flashphpajax","flashmyph pajax") or die('<div class="error">Die Verbindung zum Datenbankserver konnte NICHT hergestellt werden. Error: '.mysql_error().'</div>'); $db = mysql_select_db("db_flashphpajax") or die('<div class="error">Die Datenbank konnte NICHT ausgewaehlt werden. Error: ‚.mysql_error().'</ div>'); $sql = "SELECT * FROM tbl_05antworten WHERE(idP_Antwort=".$_GET["idP_ Antwort"].")";
  • 244.
    C L IE N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 231 $query = mysql_query($sql); $data = mysql_fetch_array($query); $sql = "SELECT SUM(int_AnzahlStimmen) AS sum FROM tbl_05antworten WHERE(bitP_chk_aktiv=1 AND fidP_select_Bezeichnung_Frage=".$data["fidP_ select_Bezeichnung_Frage"].")"; $query = mysql_query($sql) or die("ERROR: ".mysql_error()); $data2 = mysql_fetch_array($query); $sum = $data2["sum"]; echo(' <ul> <li>Anzahl abgebebener Stimmen gesamt: '.$sum.'</li> <li>Anzahl Stimmen f&uuml; ''.$data["vcP_Antwort"].'': '.$data["int_AnzahlStimmen"].'</li> <li><span style="font-weight:bold;">Prozentsatz: '.round(100*$data["int_AnzahlStimmen"]/$sum,2).'%</span></li> </ul> ‚); } Listing 5.50: Das gesamte Listing von getdetails.php ist mehr oder weniger Routine – zwei Abfragen, ein bisschen Ausgabe per echo. Das Ziel dieser Datei ist Folgendes: 1. Überprüfen, ob an sie GET-Daten übergeben wurden und ob es sich um die GET- Variable idP_Antwort handelt (ansonsten würde das Abarbeiten dieser Datei keinen Sinn machen): if(count($_GET)>0 && isset($_GET["idP_Antwort"])) 2. Ein erstes SQL-Statement abzusetzen, das alle Infos zur geforderten Antwort aus der Datenbank liest (zuvor muss natürlich der Datenbankserver kontaktiert und die Datenbank ausgewählt werden, aber das wissen Sie sicherlich): SELECT * FROM tbl_05antworten WHERE(idP_Antwort=".$_GET["idP_ Antwort"].") 3. Ein zweites SQL-Statement, das alle zur gegebenen Frage (die auch für unsere Antwort gegolten hat) abgegebenen Stimmen zählt (aufsummiert) und die Summe zurückliefert:
  • 245.
    K A PI T E L 5232 SELECTSUM(int_AnzahlStimmen)ASsumFROMtbl_05antwortenWHERE(bitP_ chk_aktiv=1 AND fidP_select_Bezeichnung_Frage=".$data["fidP_select_ Bezeichnung_Frage"].") 4. Aus den so gewonnenen Informationen eine Liste mit folgenden Informationen zusammenzustellen: Anzahl der insgesamt abgegebenen Stimmen zu dieser Frage Anzahl der Stimmen für die geklickte Antwort Prozentsatz der auf die angeklickte Antwort abfallenden Stimmen Diese zuletzt genannte Liste wird per echo ausgegeben und bildet somit den Rück- gabewert responseText für die XMLHttpRequest-Instanz myXMLHttpRequest. Der zuvor angesprochene Eventhandler handleRequestDetail sorgt schlussendlich dafür, dass dieser Rückgabewert in den DIV-Container „Details“ geschrieben wird: function handleRequestDetail() { switch(myXMLHttpRequest.readyState) { case 0: case 1: case 2: case 3: break; case 4: document.getElementById("Details").innerHTML = myXMLHttpRequest.responseText; break; } } Listing 5.51: Abschluss unserer Bemühungen: Der Rückgabewert responseText von getdetails.php wird in den dafür vorgesehenen DIV-Container „Details“ geschrieben. Das war’s, meine Damen und Herren! Und damit wir nicht vergessen, warum wir den Aufwand mit AJAX getrieben haben: Dieses Umfragetool muss nicht die Seite neu laden, um die aktualisierten Daten anzuzeigen, wie es sonst üblich ist. Und wenn Sie Lust darauf haben, dass auch mehrere Umfragen ohne Neuladen des Dokuments durchgeführt werden sollen, dann sehen Sie sich die Datei ajax02a.htm an, die Sie auf der Buch-CD finden: u u u
  • 246.
    C L IE N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 233 Na, Lust auf mehr bekommen? ajax02a.htm, ajax02a.fla und getquestion.php sind die Antwort! Zu finden auf der Buch-CD. Folgende Änderungen wurden vorgenommen: 1. Die PHP-Abfrage der Frage und zugehörigen Antworten wurde in eine externe Datei verlegt (getquestion.php), die im Weiteren per AJAX abgefragt wird. Der erste Aufruf erfolgt beim Eintreten des onload-Ereignisses für das window-Objekt. 2. Bei Klick auf den Button „Neue Frage“ passiert genau dasselbe wie beim onload- Ereignis von oben, nur dass zusätzlich noch die Flash-Datei „zurückgesetzt“ wird (die von einer vorigen Frage dargestellten Balken werden eliminiert und es wird wieder der Text „WARTE AUF DATEN“ eingeblendet. Werfen Sie einen Blick darauf ... 5.4.2 Parameterübergabe: XML Bisher haben wir ausschließlich mit der Eigenschaft responseText eines XMLHttp- Request-Objekts gearbeitet. Nun wollen wir die Gelegenheit beim Schopf packen und anstatt Text- nun XML-Daten vom Server abfragen und an Flash weiterleiten. XML ist ideal dafür geeignet, strukturierte Daten darzustellen – genau wie unser obiges Beispiel es fordert. Würden wir die der Balkengrafik zugrunde liegenden Daten in XML-Form ausgeben, könnte das beispielsweise wie folgt aussehen: ABBILDUNG 5.34 Nun werden auch die Fragen und zugehörigen Antworten per AJAX angefordert.
  • 247.
    K A PI T E L 5234 Fraglich ist nun, ob die Daten vom Server als XML- (responseXML) oder Textdaten (responseText) abgefragt werden sollen. Überraschenderweise wählen wir auch hier die Variante responseText, obwohl die Daten in XML-Form bereitstehen. Flash verträgt sich jedoch nicht mit der Darstellung der XML-Daten, wie sie uns AJAX zur Verfügung stellen würde. Somit ergäben sich zwei Möglichkeiten: 1. Wir wandeln das per AJAX angeforderte XML-basierte Dokument so um, dass Flash damit etwas anfangen kann. 2. Wir laden die XML-Daten als Text und übergeben den Text an Flash, das für sich wiederum den Text in XML-Form umwandelt. Variante 2 ist wesentlich einfacher, weshalb wir nach wie vor responseText an Flash schicken und dieses dann „echtes“ XML daraus macht. AJAX-technisch ist an unserem Beispiel nichts zu ändern, trotzdem möchte ich Sie an dieser Stelle noch auf eine kleine Sache hinweisen, die Ihnen wahrscheinlich schon auf- gefallen ist und die wir idealerweise an dieser Stelle diskutieren können. Bisher hatten unsere Eventhandler immer eine relativ komplexe Struktur, da wir eine Auswertemög- lichkeit für jeden Wert der readyState-Eigenschaft des XMLHttpRequest-Objekts vorgesehen hatten: function handleRequest() { switch(myXMLHttpRequest.readyState) { case 0: case 1: case 2: response- Text oder responseXML? response- Text oder responseXML? ABBILDUNG 5.35 Die Antwortdaten für eine gegebene Frage in XML- Form – vergleichen Sie doch mal mit Listing 5.43 und Sie werden sicherlich auch der Meinung sein, dass diese Form der Darstellung wesentlich übersichtlicher ist.
  • 248.
    C L IE N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 235 case 3: break; case 4: FUNKTIONSAUFRUF BZW. CODE; break; } } Listing 5.52: Ein typischer Aufbau der von uns verwendeten Eventhandler Wie Sie aus dem obigen Listing entnehmen können, sind die Fälle 0–3 der switch- Anweisung sinnlos – wir werten diese Fälle gar nicht aus, sondern brechen vielmehr mit break ab.Warum sollten wir diese Fälle dann überhaupt verwenden? Wenn jedoch die Fälle 0–3 wegfallen, benötigen wir auch keine switch-Anweisung mehr, sondern kommen mit einer einfachen if-Anweisung aus: function handleRequest() { if(myXMLHttpRequest.readyState==4) { FUNKTIONSAUFRUF BZW. CODE; } } Listing 5.53: Sieht doch gleich einfacher aus – if anstatt switch für nur einen möglichen Wert von readyState. Somit reduziert sich unser Script auf: function handleRequest() { if(myXMLHttpRequest.readyState==4) { if(myXMLHttpRequest.responseText.indexOf("ERROR")!=-1) { alert("Es ist ein FEHLER beim Voting aufgetreten - bitte versuchen Sie es erneut!"); } else { var mySWF = getFlashElement("myswf"); mySWF.showVoteData(myX MLHttpRequest.responseText); } } } Listing 5.54: Unser Eventhandler hat sich gegenüber dem vorigen Beispiel von der Funktionsweise nicht ge- ändert – wir haben ihn nur etwas „abgespeckt“ und so auf unsere Bedürfnisse optimal angepasst. Obwohl wir XML-Daten vom Server laden, übergeben wir diese als responseText an Flash. Nachdem wir so viel über XML-Daten gesprochen haben, wollen Sie sicherlich auch erfahren, wie die serverseitige Datei storevote.php sich nun ändern muss, sodass wir XML- anstatt Textdaten zurückerhalten. (Sie finden die neue Version von storevote.php übrigens unter dem Namen storevote2.php auf der Buch-CD.) Der wesentliche Unter- schied liegt in folgenden Zeilen:
  • 249.
    K A PI T E L 5236 Bisher (für die Textrückgabe in URL-codierter Form) haben wir folgenden Code verwendet: $returner = ‚'; $i = 0; while($data = mysql_fetch_array($query)) { $returner.= 'ID'.$i.'='.$data["idP_Antwort"].'&Antwort'.$i.'='.$data ["vcP_Antwort"].'&Anzahl'.$i.'='.$data["int_AnzahlStimmen"].'&'; $i++; } $returner = substr($returner,0,$returner.length-1); Nun verwenden wir: header("Content-type: text/xml"); $returner = ' <?xml version="1.0" encoding="ISO-8859-1" standalone="yes" ?> <Umfrage> '; while($data = mysql_fetch_array($query)) { $returner.= ' <Antwort ID="'.$data["idP_Antwort"].'" Antworttext="'.$data["vcP_ Antwort"].'" Anzahl="'.$data["int_AnzahlStimmen"].'" /> ‚; } $returner.= ‚</Umfrage>'; Der wichtigste Unterschied liegt zunächst in der Definition des Content-type des Doku- ments: Mittels header("Content-type: text/xml") definieren wir, dass es sich bei den enthaltenen Daten um XML-basierte Daten in Textform handelt. Danach erzeugen wir das für ein XML-Dokument notwendige Tag <?xml ?>, wo wir als Attribute die verwendete XML-Version (version="1.0"), den Zeichensatz (encoding="ISO- 8859-1") sowie die Info, ob das Dokument für die Darstellung noch ein Stylesheet benötigt oder nicht (kein Stylesheet benötigt: standalone="yes"), angeben. Innerhalb der while-Schleife basteln wir nun keinen URL-codierten Text, sondern Tags zusammen, und zwar in der Form: <Antwort ID="..." Antworttext="..." Anzahl="..." /> Das Ergebnis dessen haben Sie in Abbildung 5.35 bereits gesehen. Viel interessanter ist nun die Frage, wie Flash mit den nun XML-basierten Daten umgeht. Betroffen davon sind vor allem die Funktionen storeVoteData (dies ist die u u
  • 250.
    C L IE N T S E I T I G E R D AT E N A U S TA U S C H – F L A S H & J AVA S C R I P T 237 Funktion, die von JavaScript (AJAX) aufgerufen wird) und parseDataIntoArray. Die Datei storeVoteData erhält nach wie vor einen Text als Übergabeparameter, der mit geeigneten Flash-Befehlen in eine XML-Struktur gebracht gehört. Nachdem das gesamte Parsing der Daten jedoch in der Funktion parseDataIntoArray vor sich geht, muss an storeVoteData nichts geändert werden. Wie steht es also um die Funktion parseDataIntoArray? Werfen wir einen Blick darauf: function parseDataIntoArray(myData:String):Array { var myXML:XML = new XML(); myXML.ignoreWhite = true; myXML.parseXML(myData); var returner:Array = new Array(); returner[0] = new Array(); returner[0][0] = 0; var theData:Array = myXML.firstChild.childNodes; for(var i:Number=0; i<theData.length; i++) { returner[i+1] = new Array(); returner[i+1][0] = theData[i].attributes["Anzahl"]; returner[i+1][1] = theData[i].attributes["Antworttext"]; returner[i+1][2] = theData[i].attributes["ID"]; if(parseInt(returner[i+1][0])>returner[0][0]) { returner[0][0] = parseInt(returner[i+1][0]); } } return returner; } Listing 5.55: Die Funktion parseDataIntoArray in etwas geänderter Form: Anstatt des LoadVars- Objekts verwenden wir nun das XML-Objekt. Statt der Verwendung des LoadVars-Objekts in Flash kommt nun das XML-Objekt zum Einsatz (var myXML:XML = new XML();). Um unnötige Zeilenumbrüche, Leer- zeichen und -zeilen (sog. „Whitespaces“) zu ignorieren, wird die Eigenschaft ignore- White auf den Wert true gesetzt. Um die von AJAX übergebenen Daten schlussen- dlich in das XML-Objekt zu bekommen, wenden wir den Befehl parseXML an. (Zur Erinnerung: Im Fall von LoadVars war es der Befehl decode.)
  • 251.
    K A PI T E L 5238 An der Stelle [0][0] des returner-Arrays werden wir nach wie vor den höchsten gefundenen Wert von„Anzahl“ speichern, jedoch verwenden wir nun keine zusätzliche Variable highestVal mehr, sondern arbeiten gleich direkt mit diesem Wert. Um in der XML-Struktur an das für uns interessante Tag „Umfrage“ zu gelangen, ver- wenden wir die Eigenschaft firstChild der XML-Instanz myXML; die einzelnen „Ant- wort“-Tags befinden sich als sog. „Kinder“ (Children) innerhalb des „Umfrage“-Tags. Aus diesem Grund gehen wir Schritt für Schritt alle dieser Kinder durch und speichern die Informationen „Anzahl“,„Antworttext“ und „ID“ (diese befinden sich als Attribute im jeweiligen „Antwort“-Tag – siehe Abbildung 5.35) im returner-Array. Da wie auch im letzten Beispiel die Stelle [0][0] des returner-Arrays für den Höchstwert an Stimmen reserviert ist, wir jedoch in diesem Fall bei i=0 in der Schleife zu zählen beginnen, schreiben wir diese Werte jeweils an die Stelle [i+1]. Alles weitere ist wie gehabt – es müssen keine weiteren Änderungen mehr vorgenom- men werden. Das Resultat sollte sich nicht geändert haben: Stellt sich die abschließende Frage, warum wir nun XML-basierte Daten anstatt text- basierter Daten verwendet haben? Nun, die größte Stärke liegt bei Flash verborgen, denn Flash kann wesentlich besser mit XML- als mit Textdaten umgehen. Mit der Einführung von ActionScript 3.0 hat sich in Bezug auf Flash & XML noch einmal ordentlich was getan. Freuen Sie sich auf das nächste Kapitel, wo wir ausführlich mit XML-Daten arbeiten werden, denn dort geht es darum, wie Flash mit der Serverseite arbeiten kann. ABBILDUNG 5.36 Auch bei Verwendung von XML-Daten hat sich an der Funktionsweise unseres Beispiels nichts geän- dert – wäre ja auch fatal gewesen …
  • 252.
    6 SERVERSEITIGER DATEN- AUSTAUSCH –FLASH, PHP & DATENBANK Um die Frage zu beantworten, wie die Kommunikation zwi- schen Flash und einer serverseitigen Anwendung (wie etwa das Ansprechen eines serverseitigen Scripts oder das Anbinden einer Datenbank oder Ähnliches) erfolgt, müssen wir uns die Vorgehensweise bei der Darstellung eines Webdokuments (mit eingebundener Flash-Datei) auf Clientseite noch einmal kon- kret vor Augen führen. Zunächst erhält der Server vom Browser des Users (also dem „Client“) eine Anfrage für ein Webdokument in Form einer URL. Der (Web-)Server bereitet die Daten für den Client auf und schickt diese (paketweise) zum Client zurück. Ist das Dokument vollständig beim Client eingetroffen, spricht man vom „fertig geladenen“ Dokument. Mit Beendigung dieses Schritts ist die Kommunikation zwischen Client und Server abgeschlossen und beide agieren wieder vollkommen unabhän- gig voneinander. Nachdem Flash ein Plug-in auf Clientseite ist, kann Flash auch nur auf Clientseite agieren. Ein (serverseitiges) PHP-Script, eine Datenbank zum Abfragen oder Speichern von Daten im Rahmen einer Website liegt jedoch immer auf Serverseite vor, demnach muss Flash also mit der Serverseite Kontakt aufneh- men können. Ohne eine geeignete Technologie als „Vermittler“ zwischen Client- und Serverseite ist Flash dazu nicht (oder nur mit Einschränkungen – siehe etwas weiter unten) in der Lage.
  • 253.
    K A PI T E L 6240 Soll eine Datenbank angesprochen werden, muss diese (oder eine zweite) Technologie zusätzlich noch die von Flash gesandten Daten in eine für die Datenbank verständliche Form bringen. PHP stellt also die ideale Kombination dieser beiden Anforderungen dar. Fassen wir den theoretischen Teil noch einmal zusammen: 1. Flash möchte ein serverseitiges Script ansprechen. Hierzu muss in jedem Fall eine Kommunikation mit dem Server hergestellt werden. Da in Flash (ohne Zusatztools auf Serverseite) keine Möglichkeiten zur direkten Anbindung mit einer Datenbank gegeben sind, muss eine geeignete Technologie bereitstehen, die diese Aufgabe erledigt. 2. Es wird durch Flash eine PHP-Seite aufgerufen. PHP agiert auf Serverseite und bringt die übermittelten Daten in eine geeignete Form – die Daten werden „aufbereitet“. 3. Soll eine Datenbank angesprochen werden,nimmt PHP Kontakt zur Datenbank auf und schreibt bzw. liest mithilfe der Abfragesprache SQL die Daten. PHP allein kann wiederum nicht mit einer Datenbank arbeiten.Aus diesem Grund bedient man sich einer weiteren Sprache – der Abfragesprache SQL (Structured Query Language). Selbstverständlich könnten auch andere serverseitige Technologien wie etwa ASP zum Einsatz kommen. In diesem Buch haben wir uns für PHP entschieden, da PHP einerseits einfach zu erlernen und andererseits in Web-Entwicklerkreisen sehr weit verbreitet ist. Des Weiteren hat PHP mit der Datenbank MySQL wiederum eine im Web sehr verbreitete Datenbank zur Seite, wobei die Kommunikation zwischen diesen beiden auch noch hervorragend funktioniert. Schlussendlich sollten wir aber auch nicht vergessen, dass „serverseitiges Arbeiten“ ja nicht nur „Ansprechen einer Daten- bank“ bedeutet. In den ersten Kapiteln befassen wir uns mit den Möglichkeiten, die sich im Rahmen von ActionScript 2.0 bieten. Danach sehen wir uns die – nicht unwesentlichen – Ände- rungen und Neuerungen im Rahmen von ActionScript 3.0 an (Kapitel 6.4). 6.1 Drei Technologien im Einsatz Wie man sieht, ist das Arbeiten mit serverseitigen Technologien und im Weiteren mit einer Datenbank durchaus nicht trivial, da man zumindest zwei (drei bei Daten- banken) verschiedene Technologien vereinen muss. Dies soll uns jedoch nicht davon abhalten, diesen Schritt zu wagen – dafür ist dieses Thema in der Webwelt schon jetzt viel zu wichtig! ActionScript 2.0 vs. ActionScript 3.0 ActionScript 2.0 vs. ActionScript 3.0
  • 254.
    SERVERSEITIGER DATENAUSTAUSCH –FLASH, PHP & DATENBANK 241 In den nächsten Kapiteln werden wir uns mit genau dieser Thematik befassen – zuvor bleibt es uns aber nicht erspart, noch ein bisschen Theorie zu erläutern. Bitte bedenken Sie, dass sämtliche Ausführungen in den nächsten Kapiteln aus dem Blickwinkel von ActionScript 2.0 zu sehen sind – ActionScript 3.0 wird erst weiter unten behandelt. Erst dort werden wir erkennen, welche ungeheuren Fortschritte und auch Änderungen die neue Sprachversion uns Entwicklern bringt. 6.2 Das LoadVars-Objekt Im ersten Teil dieses Kapitels haben wir gesehen, wie JavaScript auf einfache Art und Weise beispielsweise Variablen in Flash setzen kann. Jetzt befassen wir uns mit der Frage, wie man in einem wesentlichen größeren Ausmaß Variablen in Flash einlesen (und auch ausgeben) kann – beispielsweise aus einer Textdatei. Das LoadVars-Objekt in Flash wird aber nicht nur für das Einlesen von Daten zustän- dig sein – vielmehr werden wir auch Daten (sichtbar und unsichtbar) verschicken können. Der Empfänger der Daten könnte beispielsweise ein PHP-Dokument sein, das die Daten an eine Datenbank weiterleitet. Daten aus einer Textdatei einlesen Voraussetzung für das Einlesen von Daten ist zunächst einmal das Vorhandensein einer Textdatei. Hier ist für uns wichtig, dass diese Datei einem gewissen Muster entspricht: Sie muss „URL-codiert“ sein. Mit URL-Codierung oder URL-Encodierung meint man im ersten Schritt das Verfahren der Variable=Wert-Zuweisung. Es ist nicht ausrei- chend, in das Textdokument reinen Text zu schreiben (das wird erst mit ActionScript 3.0 klappen), wir müssen den Text (also den Wert) einer Variablen zuweisen. ABBILDUNG 6.1 Die linke Datei „nichtKor- rekt“ ist ungeeignet für das Einlesen von Daten in Flash mit ActionScript 2.0 – in ActionScript 3.0 hätten wir damit keine Probleme. Die rechte Datei ist korrekt, da sie das Konzept Variable=Wert korrekt anwendet. Um die Leerzeichen müssen wir uns noch kümmern – mehr dazu weiter unten im Abschnitt zur URL-Codierung. Abbildung 6.1 zeigt dieses Vorgehen. Die linke Abbildung zeigt eine für das Einlesen von Text nicht korrekte Textdatei, da sämtliche Informationen, die an Flash übergeben werden sollen, dem Konzept Variable=Wert genügen müssen (dies gilt für Version 2.0 von ActionScript, in Version 3.0 könnten wir mit dieser Datei arbeiten – siehe hierzu das Kapitel Laden von Textdaten). In der rechten Abbildung ist dieses Vorgehen zu sehen: Der (fiktiven) Variable myText wird der Wert „Hallo Welt!“ zugewiesen. Zu einem späteren Zeitpunkt werden wir sehen, dass wir eventuell aufgrund des Leerzei- chens auch an der rechten Darstellung noch ein wenig arbeiten müssen, um es perfekt zu machen.
  • 255.
    K A PI T E L 6242 URL-Codierung Ganz so einfach ist die Sache mit der Kodierung also nicht, denn es müssen einige Punkte beachtet werden: 1. DieSchreibweisevonURL-Encodierungbasiertauf derVariable=Wert-Zuweisung, d.h., es existiert immer eine Variable, der – getrennt durch ein Gleichheitszeichen – ein Wert zugewiesen wird. 2. Da die URL-Encodierung international gültig ist, dürfen im Text natürlich keine Umlaute vorhanden sein. Das bedeutet, dass alle Umlaute durch entsprechende Codes ersetzt werden müssen. 3. Auch Sonderzeichen (wie beispielsweise „ß“, Bindestriche und Fragezeichen) müssendurchentsprechendeCodesausgetauschtwerden.Theoretischmüsstesogar das Leerzeichen ersetzt werden, Gott sei Dank ist das aber nur bei Formularfeldern nötig. Sonderzeichen Eine vollständige Auflistung aller Sonderzeichen finden Sie unter http://www.unicode.org/ charts/PDF/U0080.pdf – die im PDF-Dokument angeführten Codes werden als sog. „Escape Codes“ eingesetzt: Beispielsweise hat ein Leerzeichen den Code 0020, das in einem URL-codi- erten Dokument als %20 (die beiden Nullen werden durch ein Prozentzeichen ersetzt) eingefügt wird. Generell wird für die Codierung der Latin-1-Zeichensatz verwendet. Genaue Informationen über Unicode finden Sie auch unter http://www.unicode.org. URL-Codierung: keine Leer- und Sonderzeichen URL-Codierung: keine Leer- und Sonderzeichen ABBILDUNG 6.2 Eine korrekt URL-codierte Datei Mehrere Variablen übergeben Jegliche Informationen, die URL-codiert an Flash übermittelt werden sollen, müssen also in Form von Variablen in der Textdatei vorliegen. Möchte man mehr als nur eine einzige Variable verwenden, so müssen die Variablen mithilfe des kaufmännischen Und „&“ verbunden werden: Textdatei mit nur einer Variablen: myText=Hallo%20Welt Textdatei mit mehreren Variablen: myText=Hallo%20Welt&myText2=Test u u
  • 256.
    SERVERSEITIGER DATENAUSTAUSCH –FLASH, PHP & DATENBANK 243 Zu guter Letzt muss noch darauf geachtet werden, dass alle verwendeten Variablen eindeutige Namen erhalten. Sollte es vorkommen, dass ein Variablenname doppelt verwendet wird, so erhält diese Variable den Wert des letzten Eintrags. „Quelle“ der einzulesenden Daten Letzten Endes ist es für Flash vollkommen irrelevant, ob die Datei, aus der Flash auslesen soll, eine Textdatei ist oder eine andere Datei eines anderen Formats, die nur genauso aufgebaut ist. Dies eröffnet uns die Möglichkeit, beispielsweise eine PHP-Datei mit einem solchen Aufbau zu verwenden. Diese wiederum kann die Daten aus einer Datenbank auslesen, wobei wir schon beim Thema wären. Aber alles zu seiner Zeit – zunächst gehen wir den einfachen Weg des Auslesens aus einer (statischen, bereits existenten) Textdatei. Ablauf eines Ladevorgangs Das Hinzuladen der Daten aus der Textdatei erfolgt aus Flash heraus in folgenden Schritten: 1. Zunächst muss in Flash per ActionScript ein sogenanntes LoadVars-Objekt angelegt werden. Mithilfe dieses Objekts wird es dann möglich sein, Daten einzulesen bzw. zu versenden, wie Sie in den nachfolgenden Kapiteln sehen werden. Das LoadVars- Objekt dient als eine Art Container, in dem alle eingelesenen Variablen abgelegt werden. Man kann sich ein solches Objekt wie eine Schachtel vorstellen, wo die Daten in Form von Variablen abgelegt sind. 2. Ein entsprechendes Ereignis – das onLoad-Ereignis – in Flash signalisiert, wann das Lesen der externen Datei abgeschlossen ist. Wichtig ist hierbei, dass beim Auftreten dieses Ereignisses noch nicht gesagt ist, dass die Daten auch erfolgreich geladen wurden. Deshalb muss im nächsten Schritt noch überprüft werden, ob das Laden der Daten funktioniert hat. 3. Danach wird diesem LoadVars-Objekt eine Datei zugewiesen, von der die Daten gelesen werden sollen. 4. Nun muss geprüft werden, ob das Laden der Daten erfolgreich war. Die Eigenschaft loaded des LoadVars-Objekts sagt uns mit dem Wert true, ob dies geschehen ist. Sollte loaded den Wert false aufweisen, muss man sich überlegen, ob das Laden der Datei erneut versucht werden sollte. Eindeutige Variablennamen Eindeutige Variablennamen ABBILDUNG 6.3 Die Textdatei links beinhal- tet lediglich eine einzige Variable, die Textdatei rechts umfasst fünf Variablen.
  • 257.
    K A PI T E L 6244 Die Reihenfolge von Ereignissen bei Ladevorgängen Man sollte darauf achten, dass Ereignisse, die unmittelbar mit dem Laden eines Dokuments in Verbindung stehen (wie beispielsweise das onLoad-Ereignis beim Laden externer Daten oder später auch einer XML-Datei), vor dem eigentliche Ladeaufruf definiert werden. Sollte beispiels- weise der Ladevorgang beendet sein, noch bevor die Ereignisprozedur zum Laden definiert wurde, wird diese eventuell nicht ausgeführt. Dieser Fall ist zwar zu beinahe 100% auszuschließen (keine Datei wird so schnell geladen werden, noch bevor die nächsten Zeilen des Flash-Dokuments abgearbeitet wurden), jedoch arbeitet man doch gerne konform der geltenden Regeln. Mehrere Ladeversuche Ein paar Worte zum Thema „Das Laden der Daten ist fehlgeschlagen“. Hier stellt sich unweigerlich die Frage, wodurch dies passieren kann. Mögliche Ursachen für den Fehl- schlag sind beispielsweise: Die Verbindung zum Server ist abgebrochen. Die Datei konnte nicht gefunden werden. Die Datei ist nicht korrekt aufgebaut. Natürlich wäre nur der erste Punkt der Liste ein Grund, das Laden der Datei erneut zu versuchen. Flash gibt uns leider nicht Auskunft darüber, warum, sondern nur, ob das Laden fehlgeschlagen ist. Aus diesem Grund sollte man auf jeden Fall einen erneuten Ladeversuch, maximal aber drei, in Erwägung ziehen. Die nachfolgende Abbildung 6.4 zeigt den Ablauf eines Ladevorgangs mit einer maxi- malen Anzahl an Wiederholungen. u u u ABBILDUNG 6.4 Diese Abbildung zeigt einen typischen Ablauf eines Ladevorgangs mit einer maximalen Anzahl an Wiederholungen. Sollte diese Anzahl erreicht werden, bricht das Skript das Laden ab.
  • 258.
    SERVERSEITIGER DATENAUSTAUSCH –FLASH, PHP & DATENBANK 245 Gehen wir die notwendigen Schritte in Flash also im Detail durch. Schritt eins besagt, dass wir ein neues LoadVars-Objekt anlegen müssen. Wir sind in der Namensgebung für das Objekt mit denselben Einschränkungen konfrontiert wie bei den Variablen, abgesehen davon muss nichts berücksichtigt werden. 1. Anlegen eines LoadVars-Objekts: var myData:LoadVars = new LoadVars(); Im nächsten Schritt muss diesem LoadVars-Objekt eine Quelldatei zugewiesen werden, aus der die Daten geladen werden sollen. Diese Datei kann sowohl im selben wie auch in einem Unterverzeichnis abgelegt sein. 2. Warten auf das Auftreten des onLoad-Ereignisses mithilfe einer nativen Funk- tion: myData.onLoad = function(loadedOK:Boolean):Void { // Ereignisbehandlungsroutine } Innerhalb der Ereignisprozedur (bezeichnet dasselbe wie „Ereignisbehand- lungsroutine“) wird nun kontrolliert, ob das Laden der Datei erfolgreich war. Ein erfolgreiches Laden wird durch die Variable loadedOK==true des LoadVars- Objekts dargestellt.DerWert derVariablen loadedOK wird direkt von Flash erzeugt – man könnte auch sagen, Flash „übergibt“ den Wert der Variablen loadedOK an die Funktion. Solche Variablen bezeichnet man gerne als Ereignisparameter. Alternativ zu dieser Vorgehensweise existiert auch noch eine zweite Variante: das Abfragen der Eigenschaft loaded eines LoadVars-Objekts – siehe hierzu den „Exkurs Ereignisparameter vs. Objekteigenschaft“. 3. Zuweisen einer Quelldatei: myData.load("URL zur Quelldatei"); 4. Überprüfen, ob das Laden erfolgreich war: if(loadedOK) { //beispielsweise Auslesen der Daten } else { //Fehler beim Laden aufgetreten. Evtl. erneuter Ladeversuch? }
  • 259.
    K A PI T E L 6246 Exkurs: Ereignisparameter vs. Objekteigenschaft Um zu überprüfen, ob ein Ladevorgang erfolgreich durchgeführt wurde, kann man sich zweierlei Möglichkeiten bedienen: Man verwendet einen von Flash erzeugten Parameterwert der Ereignisprozedur onload eines LoadVars-Objekts. In unserem Fall wurde dieser Parameter in der Variable loadedOK gespei- chert. Man überprüft die Eigenschaft loaded eines LoadVars-Objekts. In unserem Beispiel würde man in der if-Abfrage die Variable loadedOK durch den Ausdruck myData.loaded ersetzen. Ist myData.loaded==true, war der Ladevorgang erfolgreich, bei myData.loaded==false war er nicht erfolgreich. Beide Möglichkeiten führen zum selben Ergebnis – welche Variante Sie einsetzen möchten, bleibt völlig Ihnen überlassen. Geladene Daten auslesen Sollte der Ladeversuch erfolgreich verlaufen sein, muss man sich darum kümmern, die geladenen Daten auszuwerten. Man muss sich bewusst sein, dass sämtliche einge- lesenen Daten im Container LoadVars gespeichert sind und von dort gelesen werden müssen. Wurde beispielsweise in der Quelldatei eine Variable mit dem Namen myText angelegt, so ist der Wert dieser Variable – in unserem Beispiel – über das LoadVars- Objekt myData abrufbar, und zwar wie folgt: trace("myText="+myData.myText); Listing 6.1: Auslesen der gelesenen Daten – beispielsweise per Ausgabe in das Ausgabefenster In der obigen Zeile sieht man, dass die Variablen der Quelldatei in jedem Fall Variablen des LoadVars-Objekts werden und nicht Variablen der Hauptzeitleiste. Es steht dem Entwickler natürlich frei, die gelesenen Variablen in anderen (globalen) Variablen zu schreiben (siehe Abbildung 6.5). u u ABBILDUNG 6.5 Die in der Textdatei unter dem Namen myText dekla- rierte Variable ist nach dem Laden mithilfe des LoadVars- Objekts myData über eben dieses Objekt auslesbar – myData.myText. Schritt für Schritt: Daten aus einer Textdatei mit Flash laden In diesem Beispiel wollen wir das soeben erworbene theoretische Wissen in die Praxis umsetzen, indem wir Adressinformationen aus einer Textdatei auslesen. Im ersten Schritt müssen wir also die Textdatei erstellen. Hierzu sei erwähnt, dass die Daten URL-codiert in die Textdatei eingefügt werden sollten. 1.Textdatei erstellen 1.Textdatei erstellen
  • 260.
    SERVERSEITIGER DATENAUSTAUSCH –FLASH, PHP & DATENBANK 247 Der Inhalt der Textdatei sollte dann wie folgt aufgebaut werden (wie schon oben erwähnt, ist es nicht notwendig, dass die Leerzeichen mit „%20“ URL-codiert werden – deshalb verzichten wir hinsichtlich besserer Lesbarkeit im Folgenden darauf): Vorname0=Uwe &Nachname0=Mutz &Firma=SYNE Marketing und Consulting GmbH &Adresse0=Am Graben 29 &PLZ0=4020 &Ort0=Linz &Staat0=AUT &email0=uwe.mutz@syne.at Vielleicht werden Sie sich wundern, warum wir bei den Variablen eine Nummerierung eingeführt haben. Diese ist in unserem Beispiel eigentlich nicht notwendig. Möchte man jedoch zu einem späteren Zeitpunkt dieses Beispiel erweitern und nicht nur eine Person, sondern mehrere Personen einlesen, ist es notwendig, eindeutige Variablen- namen zu verwenden. Durch eine derartige Nummerierung ist dies auf jeden Fall gewährleistet (die nächste Person hätte dann Vorname1, Nachname1 usw.). Abbildung 6.6 zeigt die Datei Einlesedaten01.txt, wo wir unser Beispiel von oben umge- setzt haben. Eindeutige Variablennamen Eindeutige Variablennamen ABBILDUNG 6.6 Die Datei Einlesedaten01.txt beinhaltet alle für unser Beispiel notwendigen Infor- mationen. Achten Sie stets darauf, dass alle Variablen- namen eindeutig sind. Tipp zum Einlesen von Textdaten Bitte beachten Sie, dass es bei manchen Versionen des Flash-Plug-in zu Problemen beim Einlesen kommen kann, wenn in der einzulesenden Datei Zeilenumbrüche nach den Variablenwerten eingefügt werden. Speziell beim Weiterverarbeiten von Dateinamen sollte darauf geachtet werden. Ist die Textdatei fertig erstellt, können wir uns Flash widmen. Idealerweise teilt man in diesem Beispiel die Zeitleiste mithilfe von Bildern in drei „Bereiche“ auf. Der erste Bereich dient dazu, Variablen zu deklarieren und dem LoadVars-Objekt die einzulesende Quelldatei anzugeben. Des Weiteren wird hier die Ereignisproze- dur definiert, die uns signalisiert, wann das Laden der Textdatei abgeschlossen ist. u 2. Flash-Datei erstellen 2. Flash-Datei erstellen
  • 261.
    K A PI T E L 6248 Hierin werden auch die eingelesenen Werte weiterverarbeitet. Außerdem wird von hier aus zum zweiten („Ladevorgang war nicht erfolgreich“) oder dritten („Lade- vorgang war erfolgreich“) Bereich weitergeleitet. Der zweite Bereich ist dafür bestimmt, dem User bei einem fehlgeschlagenen Lade- vorgang eine entsprechende Meldung zu geben. Der dritte Bereich („Ladevorgang war erfolgreich“) dient der Anzeige der eingele- senen Daten. Die Bereichsunterteilung ist in Abbildung 6.7 ersichtlich, ebenso die verwendeten Ebenen. Die Dokumentgröße wurde auf 500x200 Pixel festgelegt. Wie schon im ein- leitenden Kapitel zu Flash erwähnt, spielt es keine (wesentliche) Rolle, wie viele leere Bilder in der Zeitleiste existieren – in unserem Beispiel sehen Sie, dass wir unser erstes Schlüsselbild an Position 1, das nächste und übernächste Schlüsselbild aber erst an den Positionen 5 und 25 platziert haben. Der große Vorteil an der gezeigten Arbeitsweise ist die Übersichtlichkeit der Flash-Datei. u u ABBILDUNG 6.7 Das Flash-Dokument wurde in drei Bereiche unterteilt – Bild 1 für das Deklarieren der Variablen, „LadevorgangFehl- geschlagen“, sofern das Laden nicht geklappt hat, und „Ladevorgang- Erfolgreich“ für das Anzeigen der geladenen Daten. In Bild 1 werden zunächst alle Variablen und Objekte deklariert. Des Weiteren küm- mern wir uns um die Ereignisprozedur, die nach dem abgeschlossenen Ladevorgang aufgerufen wird. var anzLadeversuche:Number = 0; var maxLadeversuche:Number = 3; var myLoader:LoadVars = new LoadVars(); myLoader.onLoad = function(loadedOK:Boolean):Void { //Ladevorgang abgeschlossen. 3. Deklarieren der notwendigen Variablen und Objekte 3. Deklarieren der notwendigen Variablen und Objekte
  • 262.
    SERVERSEITIGER DATENAUSTAUSCH –FLASH, PHP & DATENBANK 249 anzLadeversuche++; if(loadedOK) { //Daten wurden ERFOLGREICH geladen. gotoAndStop("LadevorgangErfolgreich"); } else { if(anzLadeversuche<maxLadeversuche) { myLoader. load("Einlesedaten01.txt"); } else { gotoAndStop("LadevorgangFehlgeschlagen"); } } } myLoader.load("Einlesedaten01.txt"); Listing 6.2: Code für den Ladevorgang der Daten aus einer Textdatei Mit Einführung von Flash CS3 wurden wie erwähnt neue Zahlentypen eingeführt, die den Umgang mit Ganzzahlen wesentlich vereinfachen: int und uint. Da diese jedoch erst in ActionScript 3 verfügbar sind, stellt sich die Frage, ob man sie bei relativ einfachen und wenig umfangreichen Beispielen einsetzen sollte. Oder stellen wir die Frage anders herum: Warum sollte man sie denn nicht einsetzen? Nun, sehen wir uns die Vor- und Nachteile noch einmal kurz an: Vorteil: Der Prozessor kann mit Ganzzahlen wesentlich besser umgehen als mit Fließkommazahlen („Floating Point Numbers“) – somit erfolgt das Abarbeiten von Ganzzahlen wesentlich schneller. Nachteil: Die Unterscheidung von Ganz- und Fließkommazahlen erfordert Action- Script 3, wodurch man gezwungen ist, den Flash 9 Player einzusetzen. Da dieser jedoch bei weitem nicht so verbreitet ist wie beispielsweise ein Flash 7 Player (dieser würde für unseren Fall vollkommen ausreichen), schließt man einen nicht unbe- trächtlichen Userkreis aus bzw. zwingt diese User, den 9er-Player zu installieren (und wie wir wissen, ist die Überwindung zum Installieren einer Software nach wie vor hoch). Aus diesem Grund würde ich Ihnen raten, nach wie vor den Typ Number zu verwenden und nur im „Ernstfall“ auf int oder uint zurückzugreifen. Wie bereits weiter oben erwähnt, empfiehlt es sich, die Anzahl der Ladeversuche auf einen maximalen Wert zu beschränken. Sollte der Ladevorgang danach noch immer nicht erfolgreich verlaufen sein, würde man den Ladevorgang abbrechen und dem Benutzer eine entsprechende Meldung am Bildschirm ausgeben. In unserem Fall werden wir die Anzahl der Ladeversuche auf drei Versuche beschrän- ken. Damit wir flexibel arbeiten, legen wir diesen Wert in einer Variablen fest. u u Number oder int / uint? Number oder int / uint? 4. Anzahl der Ladeversuche 4. Anzahl der Ladeversuche
  • 263.
    K A PI T E L 6250 In Zeile drei wird das LoadVars-Objekt erzeugt und diesem ganz unten im Script eine Datei zum Einlesen zugewiesen (Einlesedaten01.txt). Ist dies geschehen, startet Flash automatisch den Ladevorgang. Sobald dieser abge- schlossen ist, tritt das Ereignis onLoad auf, das wir in den folgenden Zeilen auswerten. Zu diesem Zeitpunkt wissen wir noch nicht, ob der Ladevorgang erfolgreich oder nicht erfolgreich abgeschlossen wurde. Auskunft darüber gibt uns die Variable (der Ereignisparameter) loadedOK, die von Flash an die Funktion (korrekt gesprochen handelt es sich hierbei wie erwähnt um eine Ereignisprozedur des LoadVars-Objekts) übergeben wird, also: loadedOK==true; //erfolgreich loadedOK==false; //nicht erfolgreich Listing 6.3: Ladeerfolg überprüfen mittels Ereignisparameter Wie erwähnt können Sie anstatt des Ereignisparameters auch die Eigenschaft loaded des LoadVars-Objekts überprüfen: myloader.loaded==true; //erfolgreich myloader.loaded==false; //nicht erfolgreich Listing 6.4: Ladeerfolg überprüfen mittels der loaded-Eigenschaft Dementsprechend wird in unserer Ereignisprozedur im Fall eines erfolgreichen Ladens mithilfe von gotoAndStop("LadevorgangErfolgreich"); in der Zeitleiste auf das Bild gesprungen, in der die Daten angezeigt werden. War das Laden nicht erfolgreich, wird die Anzahl der Ladeversuche (gespeichert in der Variable anzLadeversuche) um eins erhöht und – sofern wir noch unter der Maxi- malzahl der Ladeversuche sind – der Vorgang erneut aufgerufen. Im eher atypischen Fall, dass wir die Maximalzahl erreicht haben, verzweigt das Skript zum Bild „LadevorgangFehlgeschlagen“ – darauf kommen wir etwas später noch zu sprechen. Vielleicht ist Ihnen aufgefallen, dass das obenstehende Skript keinen stop()-Befehl beinhaltet. Dies würde ja bedeuten, dass Flash automatisch ins zweite Bild der Zeit- leiste weiterspringt, und erst in Bild 2 wurde der stop()-Befehl von uns eingefügt. Warum also erst in Bild 2 und nicht bereits in Bild 1? Der Grund dafür ist, dass wir dem User im Bild „LadevorgangFehlgeschlagen“ die Möglichkeit geben, den Ladevorgang „von Hand“ erneut zu starten, und wir somit wieder zurück in das erste Bild springen. Dies kann entweder mit gotoAndPlay() oder mit gotoAndStop() erfolgen. Der erste Befehl hat den Nachteil, dass ein etwai- ges stop() im ersten Bild ignoriert und der Bildzeiger ins zweite Bild weiterspringen 5. LoadVars- Objekt definieren und Datei zum Einlesen angeben 5. LoadVars- Objekt definieren und Datei zum Einlesen angeben 6. Ladevorgang starten und Erfolg prüfen Ereignisprozedur onload 6. Ladevorgang starten und Erfolg prüfen Ereignisprozedur onload 7. Fallunter- scheidung 7. Fallunter- scheidung 8. stop()-Befehl in Bild 2 8. stop()-Befehl in Bild 2
  • 264.
    SERVERSEITIGER DATENAUSTAUSCH –FLASH, PHP & DATENBANK 251 würde. Der zweite Befehl würde in manchen Plug-in-Generationen des Flash-Plug-ins den Code im ersten Bild nicht ausführen. Beide Probleme ersparen Sie sich, indem Sie erst im zweiten Bild den stop()-Befehl setzen. Zum Darstellen der Daten verwendet man am einfachsten dynamische Textfelder, die direkt auf das LoadVars-Objekt myLoader zugreifen und die dort eingelesenen gespeicherten Werte darstellen. 9. Darstellen der eingele- senen Werte bei erfolgreich verlaufenem Ladevorgang 9. Darstellen der eingele- senen Werte bei erfolgreich verlaufenem Ladevorgang Für den Fall eines fehlgeschlagenen Ladens muss – schon aus Usability-Gründen – dem User auf jeden Fall eine entsprechende Meldung ausgegeben werden. Diese Meldung wird im else-Abschnitt der if-Bedingung mit folgendem Code fest- gelegt: else { gotoAndStop("LadevorgangFehlgeschlagen"); } Zu diesem Zeitpunkt ist es dann relativ unwahrscheinlich, dass ein erneuter Ladever- such den gewünschten Erfolg bringen wird. Nichtsdestotrotz soll der User die Mög- lichkeit haben, einen erneuten Versuch zu starten. Dies lässt sich natürlich relativ einfach realisieren, da in der Zeitleiste nur wieder auf das erste Bild gesprungen werden muss und somit der Ladeprozess von neuem 10. Ladevorgang nicht erfolgreich 10. Ladevorgang nicht erfolgreich 11. Ladevorgang erneut starten 11. Ladevorgang erneut starten ABBILDUNG 6.8 Sofern der Ladevorgang erfolgreich verlaufen ist, wird in die dynamischen Textfelder der Wert der jeweiligen Variablen des myLoader-Objekts ein- gelesen, zum Beispiel der Nachname 1.
  • 265.
    K A PI T E L 6252 beginnt. Hierzu erzeugt man einen Button und weist diesem den entsprechenden Code zu. Wir haben uns für eine Button-Komponente entschieden und dieser den Namen „restartBtn“ gegeben. var btnListener:Object = new Object(); btnListener.click = function():Void { gotoAndStop(1); } restartBtn.addEventListener("click", btnListener); Listing 6.5: Dieser Code wird benötigt, damit der User den Ladevorgang erneut ausführen lassen kann. Zunächst erzeugen wir ein neues Objekt, das als Listener dienen soll, und weisen diesem eine Funktion zu, die bei Klick aufgerufen werden soll (gotoAndStop(1);). Danach weisen wir dem Button „restartBtn“ diesen Ereignislistener mittels restartBtn.addEventListener("click", btnListener); zu. Hiermit springt Flash bei Klick auf den Button in das erste Bild der Zeitleiste zurück und alles beginnt von vorne. ABBILDUNG 6.9 Sollte der Ladevorgang fehl- schlagen, muss dem User aus Usability-Gründen eine entsprechende Meldung aus- gegeben werden. Eventuell ermöglicht man ihm einen erneuten Ladeversuch über einen Button. Auf der Website zum Buch finden Sie dieses Beispiel – um mehrere Adressdaten ergänzt – zu einer Adresssammlung erweitert. Auf diese Art kann man auf sehr ein- fachem Wege Adressdaten von beispielsweise der Firmendatenbank per Handy oder PDA abfragen – natürlich nur, sofern diese Geräte auch einen Internetzugang und einen funktionsfähigen Webbrowser inklusive installiertem Flash-Plug-in haben.
  • 266.
    SERVERSEITIGER DATENAUSTAUSCH –FLASH, PHP & DATENBANK 253 Usability So einfach Ihre Flash-Anwendung für Sie anmuten sollte, so schwierig ist sie eventuell für den User zu nutzen. Gehen Sie immer vom „Dümmsten anzunehmenden User“ (DAU) aus. Keinesfalls wollen wir unsere User als dumm bezeichnen, jedoch hat sich dieser Ausdruck in Entwicklerkreisen eingebürgert. Je eindeutiger die Warn- oder Hinweismeldungen sind, desto leichter wird sich Ihr User beim Anwenden tun. Daten aus einer Datenbank einlesen Das Einlesen von Daten aus einer Datenbank funktioniert im Wesentlichen exakt so wie das Einlesen von Daten aus einer simplen Textdatei. Der einzige Unterschied gegenüber dem Auslesen aus der Textdatei besteht darin, dass keine Textdatei existiert, sondern die entsprechenden Inhalte der Textdatei in einer PHP-Datei erzeugt werden. Würde man die Textdatei und die PHP-Datei (in einem Browser) zur selben Zeit öff- nen und die beiden betrachten, könnte man keinen Unterschied feststellen. Im Fall der Textdatei sind die Inhalte „statisch“ (wir haben diese „per Hand“ in die Datei geschrie- ben), im Fall der PHP-Datei „dynamisch“, denn die Inhalte werden über geeignete PHP-Funktionen aus einer Datenbank ausgelesen. Nehmen wir der Einfachheit halber das vorige Beispiel zur Hand, wo wir mit der Text- datei Einlesedaten01.txt gearbeitet haben, die folgenden Inhalt aufweist: Vorname0=Uwe &Nachname0=Mutz &Firma0=SYNE Marketing und Consulting GmbH &Adresse0=Am Graben 29 &PLZ0=4020 &Ort0=Linz &Staat0=AUT &email0=uwe.mutz@syne.at Listing 6.6: Inhalt der Datei Einlesedaten01.txt Genau diesen Inhalt möchten wir nun mithilfe einer Datenbank und einer zugehö- rigen PHP-Datei erzeugen. Zunächst benötigt man also eine Datenbank mit einer entsprechenden Tabelle, welche die auszulesenden Daten beinhaltet.
  • 267.
    K A PI T E L 6254 Ist diese Tabelle mit Daten gefüllt, können wir per PHP auch schon auf diese Daten zugreifen. Wie Sie im Grundlagenteil über PHP & MySQL erfahren haben, ist der erste Schritt der Zugriff auf die Datenbank mithilfe eines Users und eines Passworts. Sofern die Datenbank lokal am jeweiligen Webserver installiert ist, kann per „localhost“ der entsprechende Server ausgewählt werden. localhost oder doch eine IP-Adresse? Typischerweise werden auf Seiten des Providers der Web- und der Datenbankserverdienst auf demselben Gerät betrieben. Ist dies der Fall, so kann eine serverseitige Technologie wie PHP über die Adresse „localhost“ („der lokale Rechner“) auf den Datenbank- und Webserver-Dienst zugrei- fen. Alternativ dazu könnte man auch die IP-Adresse 127.0.0.1 verwenden. Zunächst einmal das benötigte Script: $hostname = "IHR HOSTNAME"; $username = "IHR USERNAME"; $password = "IHR PASSWORT"; if(!$conn = mysql_connect($hostname, $username, $password)) { die('<div class="error">Verbindung zur Datenbank konnte nicht hergestellt werden. Errorcode: ‚.mysql_error().'</div>');} else { //echo('<div class="success">Die Verbindung zur Datenbank wurde erfolgreich hergestellt.</div>'); } Listing 6.7: Verbindungsaufbau zur Datenbank. Sollte die Verbindung zum Datenbankserver erfolgreich gewesen sein, so muss keine „Erfolgsmeldung“ ausgegeben werden – aus diesem Grund ist der echo- Befehl im else-Teil der if-Bedingung auskommentiert (für Testzwecke werden solche Ausgaben gerne verwendet, denn dann hat man beispielsweise Gewissheit, dass die Verbindung zum Datenbankserver geklappt hat). Klarerweise müssen Sie bei $hostname, $username und $passwort Ihre korrekten Zugangsdaten eingeben. 1. Connect zum Datenbankserver 1. Connect zum Datenbankserver ABBILDUNG 6.10 Die obige Tabelle „tbl_ Kunden“ speichert die gewünschten Informationen über unsere Kunden.
  • 268.
    SERVERSEITIGER DATENAUSTAUSCH –FLASH, PHP & DATENBANK 255 In den Variablen $hostname, $username und $password werden die drei für den Verbindungsaufbau zum Datenbankserver und zur Datenbank notwendigen Infor- mationen gespeichert, die dann wiederum mithilfe der PHP-Funktion mysql_con- nect() zum Aufbau der Verbindung herangezogen werden. Alternativ dazu könnten Sie selbstverständlich auch diese drei Variablen in einem Array zusammenfassen: $dbConnect = array( "hostname" => "IHR HOSTNAME", "username" => "IHR USERNAME ", "password" => "IHR PASSWORT", "db" => "IHRE DATENBANK" ); Listing 6.8: Alternative zu den verwendeten vier (bisher drei) Variablen für den Verbindungsaufbau sowie den Datenbankzugriff Die Verbindung selbst wird in einer Variablen $conn hinterlegt. Sollte der Verbin- dungsaufbau aus irgendwelchen Gründen nicht funktioniert haben, weil z.B. Userna- me bzw. Passwort falsch ist, wird von der Funktion mysql_connect() der Wert false zurückgegeben und in der if-Bedingung entsprechend ausgewertet. Die Funktion die() beendet den weiteren Ablauf der PHP-Datei und gibt mithilfe der Funktion mysql_error() eine entsprechende Meldung inklusive der MySQL-Fehlermeldung auf den Bildschirm aus. War der Verbindungsaufbau erfolgreich, so wird in unserem Fall eine Meldung auf den Bildschirm ausgegeben. Normalerweise werden solche „Erfolgsmeldungen“ nicht angezeigt, sondern maximal für Testzwecke mit in den Code aufgenommen und danach auskommentiert – unsere Erfolgsmeldung würde im „wahren“ Betrieb eben- falls nicht zur Verwendung kommen, denn dass der Code erfolgreich war, merken sowohl Entwickler als auch User, indem die Site funktioniert. Wenn der Verbindungsaufbau zum Datenbankserver gelungen ist, stehen uns meistens mehrere Datenbanken, die für uns freigegeben sind – sprich für die wir die notwen- digen Berechtigungen haben –, zur Verfügung. Demnach müssen wir uns für eine Datenbank entscheiden, was mithilfe der Methode mysql_select_db() erfolgt: $db = "db_BuchFlashPHP"; if(!mysql_select_db($db)) { die('<div class="error">Die Datenbank '.$db.' konnte nicht ausgewaehlt werden. Errorcode: ‚.mysql_error().'</div>'); } else { 2. Auswählen der Datenbank 2. Auswählen der Datenbank
  • 269.
    K A PI T E L 6256 //echo('<div class="success">Die Datenbank '.$db.' wurde erfolgreich ausgewaehlt.</div>'); } Listing 6.9: Auswählen der Datenbank Der Ablauf ist wieder der gleiche wie schon zuvor: 1. Definieren, welche Datenbank verwendet wird Dies kann einerseits über die Definition einer Variablen (wie in diesem Fall) oder direkt als Parameter der Methode mysql_select_db() geschehen. Ich habe mich für Ersteres entschieden, da diese Variante übersichtlicher ist (als Alternative zur Verwendung einer Variablen habe ich weiter oben schon die Verwendung eines Arrays dargestellt). 2. Prüfen, ob das Auswählen der Datenbank erfolgreich war Sollte die Methode mysql_select_db() den Wert false zurückgeben, war die Auswahl der Datenbank nicht erfolgreich und man beendet im Allgemeinen die weitere Ausführung der Site durch Verwendung der Methode die(). Der Rückgabewert true signalisiert, dass die Auswahl der Datenbank in Ordnung war. 3. SQL-Statement ausführen War die Auswahl der Datenbank erfolgreich, können aus den Tabellen der Datenbank Daten ausgelesen werden. Wie Ihnen bereits bekannt ist, verwendet man hierzu die standardisierte Abfragesprache SQL. Der Einfachheit halber wird der SQL-String zunächst einer Variablen zugewiesen und danach ausgeführt. Diese Vorgehensweise hat den Vorteil, dass Testings einfacher durchgeführt werden können, sollte ein Fehler bei der Abfrage generiert werden. Selbstverständlich kann – wie bei den meisten PHP-Methoden – der entsprechende Parameter auch direkt an die Methode übergeben werden. Hier sprechen wir von dem SQL-Statement als String-Parameter für die Methode mysql_query(). Die meisten Entwickler entscheiden sich jedoch für eine übersichtlichere Vorgehensweise mithilfe zusätzlicher Variablen, in denen diese Parameter als Strings oder Ähnliches gespeichert werden. $sql = "SELECT * FROM tbl_Kunden"; if(!$query = mysql_query($sql)) { die('<div class="error">Das SQL-Statement konnte nicht durchgefuehrt werden. Errorcode: ‚.mysql_error().'</div>'); } else {
  • 270.
    SERVERSEITIGER DATENAUSTAUSCH –FLASH, PHP & DATENBANK 257 //echo('<div class="success">Das SQL-Statement:<br/>$sql<br/>wurde erfolgreich abgesetzt.</div>'); } Listing 6.10: Das SQL-Statement $sql wird der Methode mysql_query() als String-Parameter übergeben. Sie kennen ja mittlerweile das Procedere: Zunächst wird geprüft, ob das Absetzen des SQL-Statement erfolgreich war. Dies erkennt man daran, dass in der Variable $query nicht der Wert false gespeichert wird. Danach kann mit dem weiteren Ablauf der Seite fortgesetzt werden. Für den Fall, dass das SQL-Statement nicht ausgeführt wer- den konnte, wird mithilfe von die() abgebrochen. Haben wir auch diesen Schritt erfolgreich hinter uns gebracht, müssen wir nur noch für die korrekte Ausgabe der Daten sorgen. Idealerweise wird hierzu eine while()- Schleife verwendet, in der so lange Daten ausgelesen werden, wie sich Datensätze in der Tabelle befinden. Die Funktion mysql_fetch_array() läuft Zeile für Zeile die Tabelle durch und speichert die Daten in einem assoziativen Array (alternativ dazu können Sie auch die Funktion mysql_fetch_object() verwenden – diese Funktion liefert anstatt eines assoziativen Arrays ein Objekt zurück). Des Weiteren zählen wir die Anzahl der Zeilen mit – am einfachsten wird dies mit einer Variable (hier: $cnt) erreicht, die pro Schleifendurchlauf um eins erhöht wird. Das Verwenden dieser Zählvariable $cnt hat auch noch einen zweiten Grund: Letzten Endes machen wir nichts anderes, als Text in ein „HTML“-Dokument zu schreiben, indem wir die echo()-Funktion verwenden. Die ausgegebenen Daten stellen dann nichts anderes als Variablen=Wert-Zuweisungen dar. Generiert man beispielsweise aus unserer bestehenden Tabelle Daten, so könnte das wie unten gezeigt aussehen: Vorname=Uwe &Nachname=Mutz &Firma=SYNE Marketing und Consulting GmbH &Adresse=Am Graben 29 &PLZ=4020 &Ort=Linz &Staat=AUT &email=uwe.mutz@syne.at Listing 6.11: Ausgabe des ersten Datensatzes. Diese Art der Datenausgabe ist nur für einen einzigen Daten- satz verwendbar. Warum dem so ist, wird weiter unten erläutert. Gesetzt den Fall, unsere Tabelle speichert aber mehr als nur einen einzigen Datensatz. Dies hätte dann zur Folge, dass auch der zweite Datensatz in derselben Art und Weise ausgegeben wird: 3. Daten zeilen- weise auslesen 3. Daten zeilen- weise auslesen
  • 271.
    K A PI T E L 6258 Vorname=Thomas &Nachname=Wegerer &Firma=Softnomics Werbeagentur &Adresse=Hart 14 &PLZ=4060 &Ort=Leonding &Staat=AUT &email=t.wegerer@softnomics.at Listing 6.12: Ausgabe des zweiten Datensatzes Eindeutige Variablenbenennung Betrachten wir kurz das obige Beispiel: Welchen Wert hätte beim Auslesen durch Flash beispielsweise die Variable Vorname? Die Antwort würde in unserem Fall „Thomas“ lauten, denn in beiden Fällen (bei Vorname=Uwe und Vorname=Thomas) wurde dieselbe Variable (näm- lich Vorname) als Speicherort verwendet. Um dieses Überschreiben zu verhindern, müssen die Variablen eindeutig benannt sein, was im einfachsten Fall durch eine Durchnummerierung der Variablen erreicht werden kann. Vorname=Uwe und Vorname=Thomas liefern das falsche, Vorname0=Uwe und Vorname1=Thomas das gewünschte Resultat. Somit lautet der korrekte Code zur Aus- gabe der Daten: $cnt = 0; while($theData = mysql_fetch_array($query)) { $msg = ""; if($cnt!=0) { $msg.="&"; } $msg.="Vorname$cnt=".$theData["vc_Vorname"]; $msg.="&Nachname$cnt=".$theData["vcP_Nachname"]; $msg.="&Firma$cnt=".$theData["vc_Firma"]; $msg.="&Adresse$cnt=".$theData["vc_Adresse"]; $msg.="&PLZ$cnt=".$theData["vc_PLZ"]; $msg.="&Ort$cnt=".$theData["vc_Ort"]; $msg.="&Staat$cnt=".$theData["vc_Staat"]; $msg.="&email$cnt=".$theData["vc_email"]; echo($msg); $cnt++; } Listing 6.13: Auslesen der Daten in einer while-Schleife in der Datei Einlesedaten02.php 4. Nummerierung der Variablen 4. Nummerierung der Variablen
  • 272.
    SERVERSEITIGER DATENAUSTAUSCH –FLASH, PHP & DATENBANK 259 Sehen wir uns kurz den Code an: Über die Variable $cnt haben wir bereits gesprochen. Die Variable $msg wird dazu verwendet, um pro Datensatz einen String zu speichern, der dann später mit echo() ausgegeben wird (Codezeile 13). Mithilfe der Funkti- on mysql_fetch_array() wird in die Variable (besser: das Array) $theData pro Schleifendurchlauf ein kompletter Datensatz eingelesen, der dann in den Zeilen 5–12 zum Auslesen der einzelnen Spaltenwerte verwendet wird. Lediglich Zeile 4 des Codes bedarf noch der Erklärung: Hier wird geprüft, ob gerade der erste Datensatz zum Aus- geben in die HTML-Seite ansteht. Ist dies nämlich der Fall, darf kein führendes „&“ ausgegeben werden, in allen anderen Fällen jedoch schon. Damit wären wir komplett – mehr darf auf die HTML-Seite an Information auch nicht ausgegeben werden (beachten Sie bitte, dass selbstverständlich nur das im Browser aus- gegeben wird, was durch einen echo()- oder die()-Befehl erzeugt wird). Vergleicht man das Resultat mit der (händisch erzeugten) Textdatei aus dem vorigen Kapitel, so werden Sie – bis eventuell auf Zeilenumbrüche – keinen Unterschied feststellen. 5. Ausgabe in eine HTML-Datei 5. Ausgabe in eine HTML-Datei ABBILDUNG 6.11 Unsere PHP-Datei erzeugt den gewünschten Inhalt im Browser-Fenster. Nun machen wir die Probe aufs Exempel und bringen Flash dazu, statt aus einer sta- tischen Textdatei aus einer dynamischen PHP-Datei Daten einzulesen. Wir ersetzen die Textdatei Einlesedaten01.txt in unserem Flash-Beispiel durch die PHP-Datei Einle- sedaten02.php und testen, ob das Einlesen in Flash klappt. PHP anstatt TXT in der Entwicklungsumgebung „Flash“ Bitte beachten Sie an dieser Stelle, dass PHP-Dateien durch einen Webserver verarbeitet werden müssen. Aus diesem Grund können Sie PHP-Dateien nicht – wie gewohnt – direkt in Flash tes- ten, sondern müssen die fertige SWF-Datei auf einen Webserver hochladen (dies kann selbstver- ständlich auch ein lokal installiertes Webserver-Paket wie etwa XAMPP sein) und dort testen. Schritt für Schritt: Daten aus einer PHP-Datei lesen Ersetzt man in der vierten Codezeile des ersten Bilds der Flash-Datei aus der Schritt- für-Schritt-Anleitung „Daten aus einer Textdatei mit Flash laden“ von weiter oben: myLoader.load("Einlesedaten01.txt"); durch: myLoader.load("Einlesedaten02.php"); sollten wir schon „im Geschäft“ sein. Haben Sie das vorige Beispiel nicht mitgemacht, liegt die entsprechende Datei auch auf der Website zum Buch. PHP anstatt TXTPHP anstatt TXT 1. Einlesen der PHP-Datei 1. Einlesen der PHP-Datei
  • 273.
    K A PI T E L 6260 Daten aus Flash heraus übergeben Bis jetzt haben wir Daten aus einer Textdatei oder einer Datenbank ausgelesen. Nun wollen wir den umgekehrten Weg gehen und uns mit der Frage beschäftigen, wie man Daten aus Flash heraus entweder einer (serverseitigen!) PHP-Datei zur Ausgabe auf den Bildschirm übergibt oder die Daten in eine Datenbank speichert. In diesem Fall ist es also so, dass Flash Daten sendet und PHP Daten empfängt. Nach- dem PHP bekannterweise auf Serverseite und Flash auf Clientseite ausgeführt wird, kann die Übergabe der Daten aus Flash auf zwei Arten erfolgen: 1. Flash ruft über den Befehl getURL() ein Dokument auf und übergibt mithilfe von GET-Variablen auf diese Weise Daten an die PHP-Datei. 2. Flash verschickt Formulardaten und es wird das aus HTML bekannte Abschicken von Formularinhalten verwendet. Die Methode send() des LoadVars-Objekts ist dazu in der Lage. Daten versenden mit GET & getURL Beschäftigen wir uns also zunächst einmal mit Variante eins – dem Übergeben von Werten über GET-Variablen an eine PHP-Datei. Diese Variante ist denkbar einfach, denn es muss nichts anderes als ein URL-String „zusammengebaut“ werden, beispiels- weise in der Art: ausgabe01.php?variable0=wert0&variable1=wert1 Listing 6.14: Über & werden einzelne Strings verkettet. ABBILDUNG 6.12 Das Einlesen der PHP-Datei Einlesedaten02.php war erfolgreich – so wie wir es wollten! Perfekt.
  • 274.
    SERVERSEITIGER DATENAUSTAUSCH –FLASH, PHP & DATENBANK 261 Umgesetzt in Flash würde dies dann wie folgt aussehen: getURL("ausgabe01.php?variable0=wert0&variable1=wert1"); Alternativ dazu könnte man alle verwendeten Variablen durch ein zusätzliches Attribut in der getURL()-Methode übergeben: getURL("ausgabe01.php", "", "GET"); Listing 6.15: Versenden aller Variablen an die Datei ausgabe01.php Das Attribut GET gibt also an, dass alle verwendeten Variablen per GET an die Datei ausgabe01.php geschickt werden sollen. Wie leicht zu erraten ist, können die Variablen auch per POST übergeben werden – darauf werden wir etwas weiter unten noch zu sprechen kommen. Die vollständige Syntax dieser Methode lautet: getURL("URL", "Fenster", "GET/POST"); Listing 6.16: Syntax der Methode getURL() Die URL gibt an, welche Adresse aufgerufen werden soll. „Fenster“ steht für die aus HTML bekannten Fenster (_self, _blank, _parent, _top, Standard ist _self) bzw. Frames. GET/POST wurde bereits oben dargestellt – sämtliche Variablen werden ent- weder per GET oder POST an die URL übergeben. Für das Testen, ob die Daten aus Flash auch wirklich ankommen, verwenden wir fol- gendes sehr einfaches PHP-Skript: if(count($_GET)>0) { foreach($_GET as $variable=>$wert) { echo("$variable=$wert<br/>"); } } else { echo("Es wurden keine Daten &uuml;bergeben."); } Listing 6.17: Ein kurzes Skript zum Überprüfen und etwaigen Ausgeben von übergebenen Daten Die Variable $_GET ist ein assoziatives Array und beinhaltet alle per GET übergebenen Daten. Die Funktion count() gibt an, wie viele Elemente im Array gespeichert sind. Sollte die Anzahl der gespeicherten Elemente größer null sein, so wurden Daten über- geben und man kann mit dem Auslesen der Daten beginnen. Die foreach-Schleife liest alle übergebenen Variablen in Form von Variablenname ($variable) und Vari- ablenwert ($wert) aus. Wie Sie im Grundlagenkapitel zu PHP erfahren haben, dient die foreach-Schleife dazu, alle Elemente eines Arrays (oder Ähnlichem) auszulesen. Sie bricht ab, sollte kein
  • 275.
    K A PI T E L 6262 weiteres Element mehr existieren. In jedem Schleifendurchlauf werden den Variablen $variable der Name der Variablen und $wert der Wert der Variablen zugewiesen. Ich möchte an dieser Stelle noch einmal darauf hinweisen, dass alle übergebenen Variablen immer vom Typ String sind. $_GET, $_POST und $_REQUEST Neben der Variable $_GET für per GET übergebene Variablen existieren auch noch die Variablen $_POST (für alle per POST übergebenen Variablen) und $_REQUEST (generell für alle überge- benen Variablen). In früheren Versionen wurden die Variablen $HTTP_GET_VARS und $HTTP_ POST_VARS genutzt, die im Gegensatz zu den jetzt verwendeten Variablen nicht global waren. Nehmen wir mal an, wir würden in Flash folgendes Script verwenden: var mySender:LoadVars = new LoadVars(); mySender.Vorname = "Uwe"; mySender.Nachname = "Mutz"; mySender.Variante = "LoadVars.send, per GET"; mySender.send("ausgabe01.php", "_blank", "GET"); Listing 6.18: Ein kleines Script, das drei Informationen (Vorname="Uwe", Nachmane="Mutz" sowie Variante="LoadVars.send, per GET") an eine Datei namens ausgabe01.php schickt. Dieses Dokument soll in einem neuen Fenster (_blank) aufgehen und die Daten werden mittels GET verschickt. Das Resultat unseres kleinen Testbeispiels wird wie erwartet dargestellt (siehe Abbil- dung 6.13). Rufen Sie dazu einfach die Datei LoadVars03.htm in Ihrem Browser auf. ABBILDUNG 6.13 Die Übergabe der Informationen von Flash an die Datei ausgabe01.php hat also geklappt. Beachten Sie bitte auch die Adresszeile – sie beinhaltet sämtliche Variablen und zuge- hörigen Werte: http://flashphpajax.syneweb.com/Buchkapitel/Kap06/LoadVars/ausgabe01.php? Variante=LoadVars%2Esend%2C%20per%20GET&Nachname=Mutz&Vorname=Uwe Listing 6.19: In der Adresszeile des Browsers finden Sie die übergebenen Variablen, da wir uns für die Vari- ante GET zum Versenden der Daten entschieden haben. Daten versenden mit POST Selbstverständlich werden wir die Probe aufs Exempel machen und die Daten per POST aus Flash heraus verschicken. Dazu bedarf es im Flash-Code nur einer geringfü- gigen Änderung – anstatt der Übergabemethode GET wird nun POST verwendet:
  • 276.
    SERVERSEITIGER DATENAUSTAUSCH –FLASH, PHP & DATENBANK 263 getURL("ausgabe02.php", "_blank", "POST"); Des Weiteren wurde eine andere PHP-Datei geschrieben, denn im vorangegangenen Beispiel wurden von der PHP-Datei nur GET-Variablen ausgewertet: if(count($_POST)>0) { foreach($_POST as $variable=>$wert) { echo("$variable=$wert<br/>"); } } else { echo("Es wurden keine Daten &uuml;bergeben."); } Listing 6.20: Dieses Skript überprüft, ob Daten per POST gesendet wurden, und gibt diese aus. ABBILDUNG 6.14 Entgegen dem vorangegan- genen Beispiel werden die Daten hier per POST an die PHP-Datei ausgabe02.php übergeben. Wie Sie sehen, ist das Resultat dasselbe wie zuvor, jedoch werden – wie bei POST- Datenübergabe gewünscht – die Daten nicht sichtbar in der Adresszeile des Browsers übergeben. Daten versenden mithilfe des LoadVars-Objekts Damit haben wir die Methode getURL() ausgereizt, also wenden wir uns der zweiten Variante der Datenübergabe aus Flash heraus zu – nämlich dem LoadVars-Objekt und dessen Methode send(). Im Abschnitt über das Empfangen von Daten haben Sie gesehen, dass das LoadVars-Objekt alle eingelesenen Daten „in sich“ speichert. Entsprechend geht man auch beim Senden von Daten vor. 1. Zunächst wird ein LoadVars-Objekt angelegt: Wie auch beim Einlesen von Daten muss – sofern das LoadVars-Objekt zum Einsatz kommen soll – zunächst ein LoadVars-Objekt angelegt werden: var mySender:LoadVars = new LoadVars(); 2. Danach müssen im LoadVars-Objekt Variablen angelegt werden, die die zu versendenden Daten enthalten: In vielen Fällen werden die zu versendenden Variablen zunächst in Flash als normale Variablen angelegt und ihnen so Werte zugewiesen. Einfacher und
  • 277.
    K A PI T E L 6264 eleganter ist es jedoch in jedem Fall, wenn die zu versendenden Daten sofort als Variablen des LoadVars-Objekts deklariert werden. Da die zweite Variante auch nicht mehr Arbeit erfordert, ist ihr also der Vorzug zu geben: mySender.Vorname = "Uwe"; mySender.Nachname = "Mutz"; 3. Zu guter Letzt müssen die Daten nur noch versandt werden: Hierbei steht uns die send()-Methode des LoadVars-Objekts hilfreich zur Seite: mySender.send("ausgabe01.php", "_blank", "GET"); bzw. mySender.send("ausgabe02.php", "_blank", "POST"); Die beiden Zeilen unterscheiden sich nur in der Übergabe mit GET oder POST. Das Prozedere ist das gleiche wie auch bei der Übergabe mittels getURL(). Die vollständige Syntax unterscheidet sich – wenig überraschend – von getURL() in keiner Weise: LoadVars.send("URL", "Fenster", "GET/POST"); Listing 6.21: Syntax zum Versenden der Daten mithilfe des LoadVars-Objekts Das Fenster kann wiederum entweder ein HTML-Fenster (_self, _blank, _parent, _top) oder ein Frame sein. Die folgende Abbildung zeigt das Ergebnis sowohl der GET- als auch der POST-Übergabe. ABBILDUNG 6.15 Datenübergabe durch die send-Methode des LoadVars-Objekts – einmal per GET (oben) und einmal per POST (unten). Die Abbildungen unterscheiden von den Abbildungen Abbildung 6.13 und Abbildung 6.14 nur in der Reihenfolge der Variablenausgabe und der Übergabevariante – die Daten sind selbstverständlich gleich. send oder sendAndLoad? Zum Schluss sei noch erwähnt, dass das LoadVars-Objekt noch eine weitere Methode zum Senden und Empfangen von Daten besitzt – die Methode sendAndLoad. Diese erledigt genau das, was der Name verspricht: nämlich das Senden und das Laden von
  • 278.
    SERVERSEITIGER DATENAUSTAUSCH –FLASH, PHP & DATENBANK 265 Daten in dem Sinne, wie Sie es oben kennengelernt haben. Ein wesentlicher Vorteil von sendAndLoad ist jedoch, dass die versendeten Daten nicht notwendigerweise in einem Browser-Fenster dargestellt werden müssen. Die Klasse LoadVars und die ActionScript-Referenz An dieser Stelle möchte ich Ihnen noch einmal ans Herz legen, viel mit der ActionScript- Referenz von Flash zu arbeiten. Allein beim Durchsehen der Referenz stößt man nicht selten auf Klassen und Befehle, nach denen man schon lange gesucht hat. Differenzierte Daten Neben dem Senden von klassischen Formulardaten oder Variablen ist es hin und wie- der auch erforderlich, differenzierte Daten zu verschicken. Ein Klassiker solcher Daten ist beispielsweise eine Grafik oder eine PDF-Datei, die man auf einen Server hochladen möchte. Seit Flash 8 besteht die Möglichkeit, solche Aufgaben mithilfe der FileRefe- rence-Klasse zu erledigen. Fassen wir noch einmal kurz zusammen: Zum Versenden von Daten aus Flash heraus stehen uns die Möglichkeiten getURL und die Methode send des LoadVars-Objekts (genauer: der LoadVars-Klasse) zur Verfügung. In beiden Varianten kann das Versenden per GET oder POST erfolgen. Entscheidet man sich für die Variante getURL, so kann man beim Versenden mit GET die URL schon so aufbereiten, dass die Variablen an den URL-String ange- hängt werden. Beispielsweise so: getURL("http://www.mydomain.at/mypage.php?myData=myValue;"); Oder man schickt automatisch alle in Flash verwendeten Variablen mithilfe des Parameters GET an die Seite. Beispielsweise so: getURL("http://www.mydomain.at/mypage.php", "", "GET");) Sollen die Variablen per POST verschickt werden, so muss in jedem Fall der Parameter POST verwendet werden. Entscheidet man sich für die Variante mit der Methode send des LoadVars- Objekts, so hat man hier wieder die Wahl zwischen Versand per GET oder POST, wobei nur diejenigen Variablen verschickt werden, die dem LoadVars-Objekt zugewiesen wurden. u u u u
  • 279.
    K A PI T E L 6266 6.3 Die Basis: das XML-Objekt & ActionScript 2.0 Die Herangehensweise an das Arbeiten mit XML-Daten hat sich zwischen ActionScript 2.0 und ActionScript 3.0 grundlegend geändert. Wurde in der Version 2.0 noch mit einer einzigen Klasse (XML) gearbeitet, sind die daraus bekannten Eigenschaften und Methoden in mehrere Klassen aufgeteilt worden, um Konflikte mit der in der Version 3.0 neu eingeführten XML-Klasse zu vermeiden. Seit ActionScript 3.0 wird nun im Rahmen der XML-Klasse ECMAScript for XML (E4X) unterstützt. Ähnlich wie das LoadVars-Objekt aus dem vorigen Kapitel dient das XML-Objekt (exakt: die XML-Klasse) zum Einlesen und Versenden von Daten. XML bildet ebenso wie das LoadVars-Objekt eine Schnittstelle zwischen Flash und der „Außenwelt“, wobei XML als Bezeichnungssprache wesentlich umfassender und strukturierter ist als das Arbeiten mit GET- oder POST-Variablen. Zunächst stellt sich für den Flash-Entwickler jedoch die Frage, wann die XML-Klasse und wann die LoadVars-Klasse eingesetzt werden. Man kann davon ausgehen, dass eine Datenübergabe per XML immer dann Sinn macht, wenn die Datenmenge eini- ge wenige Datensätze überschreitet. Spätestens bei mehr als 20 oder 30 Datensätzen (welcher Form auch immer) würden wir persönlich zur XML-Klasse greifen, da die Struktur von XML sehr viel übersichtlicher ist. 6.3.1 Grundlegende XML-Befehle Die Vorgehensweise beim Arbeiten mit der XML-Klasse ähnelt dem bei der LoadVars- Klasse. Auch hier muss zunächst eine neue Instanz der XML-Klasse erzeugt werden. Darauf aufbauend können dann unter anderem die Methoden load(), send() und sendAndLoad() verwendet werden. Neben diesen grundlegenden Methoden bietet die XML-Klasse aufgrund des anders gearteten Aufbaus gegenüber der LoadVars-Klasse eine Reihe von Methoden und Eigenschaften, die das Parsen der eingelesenen Daten ermöglichen. An dieser Stelle möchten wir noch einmal auf den Grundlagenteil zu XML verweisen, wo die Struktur eines XML-Dokuments dargestellt und erläutert wird. 6.3.2 Einlesen von XML-Daten Grundsätzlich kann jede bestehende XML-Datei in Flash eingelesen werden, wobei die Dateiendung (.xml, .txt, .php ...) keine Rolle spielt. Entscheidend ist einzig und allein der Inhalt der verwendeten Datei. Dadurch wird uns das dynamische Erzeugen von XML-Content durch beispielsweise PHP ermöglicht. Andererseits ist es somit genauso legitim, einen XML-Content in einer Textdatei abzuspeichern und diese auszulesen. Parsen Mit Parsen meint man in diesem Zusammenhang das (schrittweise) Auswerten der eingelesenen Daten.
  • 280.
    SERVERSEITIGER DATENAUSTAUSCH –FLASH, PHP & DATENBANK 267 XML oder Textdatei? Immer dann, wenn eine Datenübergabe von einer Datenbank zu Flash oder umgekehrt stattfinden soll, bei der die Daten strukturiert aufgebaut sind, empfiehlt sich die Ver- wendung von XML-Dokumenten. Denkt man beispielsweise an einfache Beispiele wie eine Kundenliste oder an komplexere Beispiele wie etwa das dynamische Generieren von Flash-Spielen für unterschiedliche Kunden, was unterschiedliche Gestaltung von Logos, Schriften, Level-Limits etc. mit sich bringt, so ist die Verwendung eines XML- Dokuments als Schnittstelle perfekt. Laden von XML-Daten ausschließlich von derselben Domain Seit der Einführung von Flash 7 ist das Laden von XML-Daten nur noch von derselben Domain, in der auch die Flash-Datei liegt, erlaubt. Man kann diese Einschränkung umgehen, indem man eine lokale PHP-Datei verwendet, die eine entfernte URL in den Quellcode einliest – mehr dazu im Anwendungsteil beim RSS-Reader. Einlesen einer XML-Datei Beginnen wir also mit dem Einlesen einer Textdatei mit XML-Content mit folgendem Inhalt: <?xml version="1.0" encoding="UTF-8" standalone="yes" ?> <XML-Kundenliste> <Kunden> <Kunde> <Vorname>Uwe</Vorname> <Nachname>Mutz</Nachname> <Firma>SYNE Marketing und Consulting GmbH</Firma> <Adresse>Am Graben 29</Adresse> <PLZ>4020</PLZ> <Ort>Linz</Ort> <Staat>AUT</Staat> <email>uwe.mutz@syne.at</email> </Kunde> </Kunden> </XML-Kundenliste> Listing 6.22: Listing einer Textdatei mit XML-Content (EinlesedatenXML01.txt) Öffnet man diese Datei online (offline werden Sie mitunter die Datei nur in Textform erhalten) in einem Browser, so erhält man nachfolgende Abbildung.
  • 281.
    K A PI T E L 6268 Man erkennt sehr schnell, dass der Internet Explorer nicht entsprechend der Datei- endung (hier: .txt), sondern entsprechend des Inhalts die geeignete Darstellungsform wählt. Beachten Sie jedoch bitte, dass die XML-konforme Art der Darstellung nicht alle Browser beherrschen – derzeit ist von den gängigen Browsern nur der Internet Explorer in der Lage, diese Darstellungsform auszugeben: ABBILDUNG 6.16 Eine Textdatei mit XML- Content in der Browser- Darstellung im Internet Explorer von Microsoft. Der XML-Content wird als sol- cher vom Browser erkannt und XML-konform darge- stellt. ABBILDUNG 6.17 Sowohl der Opera-Browser als auch der Firefox stellen die Textdatei (mit XML- Content) als Textdatei dar.
  • 282.
    SERVERSEITIGER DATENAUSTAUSCH –FLASH, PHP & DATENBANK 269 Letzten Endes ist es jedoch für uns unerheblich, ob die verschiedenen Browser den Inhalt als XML oder eben nicht interpretieren – wichtig für uns ist einzig und allein die Tatsache, dass der Inhalt XML-konform ist. Möchte man diese XML-Datei in Flash einlesen, so sind folgende Schritte vorzuneh- men: 1. Anlegen einer Instanz der XML-Klasse var myData:XML = new XML(); 2. Ereignisprozedur für onLoad und Laden der Datei Hier wird definiert, was beim Auftreten des onLoad-Ereignisses geschehen soll. Hierfür verwenden wir wie auch schon aus dem vorigen Kapitel gewohnt eine native Funktion: myData.onLoad = function(loadedOK:Boolean):Void { //Ereignisbehandlungsroutine } Im nächsten Schritt muss dieser XML-Instanz eine Quelldatei zugewiesen werden, aus welcher die Daten geladen werden sollen. Diese Datei kann sowohl im selben als auch in einem Unterverzeichnis abgelegt sein. Der eigentliche Aufruf passiert erst ganz unten im Script (beachten Sie hierzu bitte auch die Ausführungen zur „Reihenfolge von Ereignisprozeduren beim Laden“ aus dem vorigen Kapitel): myData.load("URL zur Quelldatei"); 3. Überprüfen, ob das Laden erfolgreich war Innerhalb der Ereignisbehandlungsroutine wird nun kontrolliert, ob das Laden der Datei erfolgreich war. Ein erfolgreiches Laden wird durch die Eigenschaft loadedOK==true (oder einfacher: loadedOK) des XML-Objekts dargestellt. if(loadedOK) { //beispielsweise Auslesen der Daten. } else { //Fehler beim Laden aufgetreten. Evtl. erneuter Ladeversuch? } 4. Überprüfen der eingelesenen Daten: Sollte der Ladeversuch erfolgreich verlaufen sein,muss man sich darum kümmern, die so geladenen Daten auszuwerten. Dabei muss man sich bewusst sein, dass sämtliche eingelesenen Daten im Container myData gespeichert sind und von dort gelesen werden müssen.
  • 283.
    K A PI T E L 6270 Um auf sehr schnelle Art und Weise zu testen, ob die eingelesenen Daten korrekt sind,kannmandengesamteneingelesenenXML-BaumineinenStringumwandeln und als solchen ausgeben lassen: myLoader.toString (); XML-Baum in Flash ausgeben Angewandt in einem Flash-Skript würden die oben dargestellten Schritte wie folgt aussehen: System.useCodepage = true; var anzLadeversuche:Number = 0; var maxLadeversuche:Number = 3; var myLoader:XML = new XML(); var mySource:String = "EinlesedatenXML01_UTF-8.txt"; myLoader.ignoreWhite = true; myLoader.onLoad = function(loadedOK:Boolean) { //Ladevorgang abgeschlossen. anzLadeversuche++; if(loadedOK) { //Daten wurden ERFOLGREICH geladen. trace("[ SYSTEM ]: Daten erfolgreich geladen.nn"); trace("Die eingelesenen Daten waren:n"); trace(myLoader.toString()); } else { if(anzLadeversuche<maxLadeversuche) { myLoader.load(mySource); } else { trace("[ SYSTEM ]: Maximale Anzahl der Ladeversuche ("+anzLadeversuche+") erreicht. Weiteres Laden wird abgebrochen"); } } }
  • 284.
    SERVERSEITIGER DATENAUSTAUSCH –FLASH, PHP & DATENBANK 271 myLoader.load(mySource); stop(); Listing 6.23: Das Flash-Skript XMLLoad01.fla zum Einlesen und Darstellen der XML-Daten in Form eines Strings liegt wie gewohnt auf der Buch-CD. Sollte die XML-Datei bereits UTF-8-codiert sein, so können Sie die erste Zeile des Scripts entfernen, da Flash standardmäßig bereits UTF-8-codiert arbeitet. Leere Textknoten: ignoreWhite = true In vielen Fällen werden in Flash XML-Daten eingelesen, die Textknoten nur mit Leerzeichen enthalten. Erkennt Flash solche „leeren“ Textknoten, so werden diese normalerweise gelöscht und nicht geparst. Genau dieser Fall könnte aber fatal enden, denn leere Textknoten treten rela- tiv häufig auf – auch in unserem Beispiel. Setzen Sie deshalb die Eigenschaft ignoreWhite des XML-Objekts auf true, um das Löschen der leeren Textknoten zu verhindern. Führt man dieses Skript in Flash aus, so erhält man im Ausgabefenster den kompletten XML-Baum angezeigt. Klarerweise sind die Daten in dieser Form nicht verwendbar – sie müssen in die einzelnen Bestandteile zerlegt werden. Hierzu muss man Stufe für Stufe den XML-Baum zerlegen, wobei die Struktur bzw. die Verschachtelungen nicht notwendigerweise bekannt sein müssen. Flash ist in der Lage, den Tag-Namen, die Attribute und den Wert jedes Tag auszulesen. Des Weiteren stehen hilfreiche Methoden zum Überprüfen zur Verfügung, beispielsweise ob ein Elternelement Kindelemente aufweist bzw. wie viele es aufweist. Aber fangen wir klein an! ABBILDUNG 6.18 In der Testumgebung von Flash kann man auf einfache Art die eingelesenen Daten in Form eines Strings ausge- ben lassen.
  • 285.
    K A PI T E L 6272 Vorgehensweise beim Einlesen der XML-Daten Der aufwändigere Part ist nun das Zerlegen des XML-Baums in seine Bestandteile. Dazu ist es notwendig, sich Schritt für Schritt durch den XML-Baum zu arbeiten. Aus dem Grundlagenteil wissen Sie, dass die erste Zeile in einem XML-Dokument eine Kennzeichnung dieses Dokuments als XML-Dokument ist. Das darauffolgende Ele- ment repräsentiert das sogenannte Wurzelelement und umschließt alle weiteren Tags. In unserem Fall ist dies das Element <XML-Kundenliste>. Des Weiteren kann man den Baum wie folgt zerlegen: 1. <XML-Kundenliste> ist das Wurzelelement und beinhaltet als erstes Kind („Child“) das Element <Kunden>. 2. <Kunden> beinhaltet ein Child-Element namens <Kunde>. 3. <Kunde> beinhaltet acht Child-Elemente: <Vorname>, <Nachname>, <Firma>, <Adresse>, <PLZ>, <Ort>, <Staat> und <email>. 4. Jedes der Child-Elemente von <Kunde> hat sieben (oben genannte) Geschwister- Elemente (im Englischen „Sibling“ genannt). 5. JedesdieserChild-Elementevon<Kunde> weistTextelementeauf,alsoimEndeffekt Werte. Im Allgemeinen sind wir genau an diesen Werten interessiert. Auf XML-Elemente zugreifen Um nun ausgehend von den eingelesenen Daten auf die einzelnen Elemente zuzu- greifen, geht man folgendermaßen vor. Zunächst einmal ist die Kennzeichnung des Dokuments als XML-Dokument für uns nicht von Bedeutung. Trotzdem ist dies genau ABBILDUNG 6.19 Das eingelesene XML- Dokument in Baumform (Strukturdiagramm) dargestellt
  • 286.
    SERVERSEITIGER DATENAUSTAUSCH –FLASH, PHP & DATENBANK 273 das erste eingelesene Element in unserer Liste, wobei es somit auch das übergeordnete Element im Baum darstellt. Demnach müssen wir auch auf ein erstes Child zugreifen, was wir mit folgendem Befehl erreichen: myLoader.firstChild Somit haben wir in der Baumstruktur des XML-Dokuments das Element <XML-Kun- denliste> erreicht. Aus dem oben dargestellten Baum erkennt man, dass auch dieses Element nicht von allzu großem Interesse für uns ist, denn auch <XML-Kundenliste> beinhaltet nur ein weiteres Child-Element namens <Kunden>, welches wir wiederum durch den Befehl firstChild (diesmal vom Tag <XML-Kundenliste>) erreichen: myLoader.firstChild.firstChild In unserem Fall enthält das Tag <Kunden> nur einen einzigen Kunden (Uwe Mutz), dessen Daten wir auslesen können. Also ist unser nächster Schritt das Zugreifen auf die Daten des Tag <Kunde>, welches ein Child-Element von <Kunden> ist. Der Zugriff erfolgt wie schon bekannt per: myLoader.firstChild.firstChild.firstChild ABBILDUNG 6.20 Nach dem Einlesen eines XML-Dokuments arbeitet man sich Schritt für Schritt („Child für Child“) vom über- geordnetsten Element nach unten. Zugriff über das Array childNodes Über den Zugriff auf das Array childNodes eines jeweiligen Knotens bzw. Elements hat man Zugriff auf alle Child-Elemente dieses Knotens. Standardmäßig wird im Array wie immer bei 0 zu zählen begonnen, die Anzahl der Werte im Array erhält man über dessen Eigenschaft length.
  • 287.
    K A PI T E L 6274 Möchte man nun auf die einzelnen Kinder von <Kunde> zugreifen, so erledigt man dies am einfachsten über genau das oben beschriebene Array childNodes in Verbin- dung mit einer for-Schleife: var theData:Array = myLoader.firstChild.firstChild.firstChild.childNodes; for(var i:Number=0; i<theData.length; i++) { trace("Child"+i+": <"+theData[i].nodeName+">"); trace("Wert="+theData[i].firstChild.nodeValue); } Listing 6.24: Auslesen aller Child-Elemente eines Knotens mithilfe einer for-Schleife Inhalt der Knoten mit nodeValue Im obigen Beispiel sieht man, dass auch die Werte eines Knotens wiederum ein Child- Element des Knotens sind. Aus diesem Grund musste in Zeile 5 per firstChild auf das Child-Element zugegriffen werden, bevor der Textwert per nodeValue ausgelesen werden kann. Erst dieses Child-Element stellt den ersehnten Textknoten mit dem eigentlich auszulesenden Wert dar. Oft ist es hilfreich zu wissen, ob ein Knoten überhaupt Child-Elemente umfasst. Die Methode hasChildNodes() eines Knotens gibt uns darüber Auskunft. Würden wir diese Methode auf den ersten Knoten unseres XML-Dokuments, also die Definition des XML-Dokuments, anwenden, würde sie den Wert true zurückliefern, da der erste Knoten sehr wohl ein Child-Element umfasst, nämlich <XML-Kundenliste>. myLoader.hasChildNodes(); //liefert den Wert true Die nachfolgende Auflistung von Methoden und Eigenschaften der XML-Daten soll Ihnen helfen, sich beim Einlesen von XML-Daten zurechtzufinden: Methoden Verwendung hasChildNodes Gibt Auskunft darüber,ob ein Knoten über Kinder verfügt.Ist dem so,so liefert die Methode den Wert true zurück,andernfalls false. Eigenschaften Verwendung firstChild Verweist auf das erste Child-Element des angegebenen Knotens. lastChild Verweist auf das letzte Child-Element des angegebenen Knotens. nextSibling Verweist auf das nächste Geschwister-Element (den„Nachbarn links im XML-Baum“) des angegebenen Knotens. previousSibling Verweist auf das vorherige Geschwister-Element (den„Nachbarn rechts im XML- Baum“) des angegebenen Knotens. nodeName Gibt den Namen des aktuellen Knotens aus. nodeType Gibt den Typ des aktuellen Knotens aus.Folgende Werte sind möglich:1 steht für ein XML-Element und 3 für einen Textknoten. nodeValue Gibt den Text des angegebenen Knotens aus,sofern es sich um einen Textknoten handelt. parentNode Verweist auf den übergeordneten Knoten (das Eltern-Element).
  • 288.
    SERVERSEITIGER DATENAUSTAUSCH –FLASH, PHP & DATENBANK 275 Arrays Verwendung attributes Dies ist ein Objekt,welches alle Attribute des aktuellen Knotens beinhaltet. childNodes Ein Array mit Bezügen auf sämtliche Child-Elemente des aktuellen Knotens. Tabelle 6.1: Die wichtigsten Methoden, Eigenschaften und Arrays im Überblick – eine vollständige Auflistung aller Ereignisse, Methoden und Eigenschaften finden Sie in der ActionScript-Referenz von Adobe oder in der Flash-Hilfe. Wie sieht es nun mit konkreten Anwendungen von XML-Daten aus? Zunächst einmal sei gesagt, dass es wenig Sinn macht, eine XML-Datei einzulesen, deren Aufbau man nicht kennt. Grundsätzlich ist es mithilfe von rekursiver Programmierung zwar mög- lich, auf alle eingelesenen Daten zuzugreifen, andererseits ist dies nutzlos, wenn man nicht weiß, was man mit den eingelesenen Daten nun anstellen soll. Rekursive Programmierung Mit rekursiver Programmierung ist eine Programmiertechnik gemeint, bei der sich Funktionen (Methoden) bei Bedarf selbst aufrufen. Beispielsweise beim Programmieren von Newsgroups wird gerne auf rekursive Programmierung zurückgegriffen, da man in diesem Fall etwa Kommentare zu Kommentaren von Einträgen finden muss und es von vorneherein nicht fest- steht, wie tief diese Verschachtelung von Kommentaren geht. Auswerten von XML-Daten Gehen wir das Einlesen und Auswerten der Daten an, denn hier ist noch ein bisschen Arbeit vonnöten. Gegenüber dem Einlesen der Textdatei aus dem ersten Beispiel (erin- nern Sie sich: Es wurden die „Kundendaten“ durchnummeriert, also beispielsweise „Nachname0“, „Nachname1“ usw.) muss jetzt der XML-Baum zerlegt werden. Am einfachsten wird das entweder durch Einlesen der Werte in entsprechende Variablen oder über das Verwenden von Arrays im Zusammenhang mit Objekten erledigt. Ent- scheidet man sich für die erste Variante, so muss man sich darüber im Klaren sein, dass man eventuell eine größere Anzahl von Variablen benötigt (in unserem Fall wären das bei nur einem Datensatz bereits acht Variablen: Vorname, Nachname, Firma, Adresse, PLZ, Ort, Staat, email). Die zweite Variante bietet den großen Vorteil, mit nur einer einzigen „Variablen“ – genau genommen dem Array – arbeiten zu müssen. Wir werden uns beide Varianten ansehen und Sie können dann selbst entscheiden, welche Variante Ihnen eher zusagt bzw. auf Ihren speziellen Anwendungsfall am besten passt. Idealerweise findet das Auslesen des XML-Baums gleich nach dem Laden statt. Das wäre in unserem Fall zu dem Zeitpunkt, wo das Ereignis onLoad auftritt und der Ladevorgang erfolgreich war: myLoader.onLoad = function(loadedOK:Boolean):Void { //Ladevorgang abgeschlossen. anzLadeversuche++;
  • 289.
    K A PI T E L 6276 if(loadedOK) { //Daten wurden ERFOLGREICH geladen. ... Listing 6.25: Auszug aus dem Skript des Ladevorgangs der XML-Datei. Hier sollte man mit dem Auswerten des XML-Baums beginnen. XML-Daten über Variablen auswerten Führen wir uns zunächst Variante 1 zu Gemüte, bei der wir den eingelesenen Datensatz in Variablen speichern. Hierzu gehen wir wie folgt vor: 1. Zunächst erzeugen wir die Variablen, in denen die eingelesenen Werte gespeichert werden sollen. 2. Danach springen wir im eingelesenen XML-Baum an die Stelle, wo die für uns relevanten Kundendaten beginnen. 3. Ab dieser Stelle gehen wir die Daten Schritt für Schritt durch, lesen die Werte aus und schreiben sie in die entsprechenden Variablen. Nun denn – Schritt für Schritt: Daten aus einer XML-Datei lesen, Variante 1: Basis dieses Beispiels ist wieder die Flash-Datei aus der Schritt-für-Schritt-Anleitung „Daten aus einer Textdatei mit Flash laden“. Sie finden die Datei auch auf der Buch- CD. 1. Anlegen der Variablen zum späteren Speichern der eingelesenen Werte Wie oben bereits erwähnt, benötigen wir acht Variablen (pro Datensatz, wobei wir derzeit mit nur einem Datensatz arbeiten). Beachten Sie, dass die Variablen außerhalb der Funktion für das onLoad-Ereignis angelegt werden müssen, da sie sonst nur innerhalb der Funktion gültig sind (sollte Ihnen das unklar sein, so schlagen Sie bitte bei den Grundlagen der Programmierung nach): var Vorname:String, Nachname:String, Firma:String, PLZ:String, Ort: String, Staat:String, email:String; Alle Variablen sind vom Typ String – auch die Postleitzahl, denn es könnte sich um Kunden aus beispielsweise Großbritannien handeln, wo die Postleitzahlen aus Ziffern und Buchstaben bestehen. 2. Springen zu dem Punkt im XML-Baum, wo die relevanten Daten beginnen Nehmen Sie hierzu bitte die Abbildung 6.19 zur Hand – hier sehen Sie, dass wir zum Tag <Kunde> springen müssen,um zu den relevanten Daten zu gelangen.Dies geschieht – wie in Listing 6.25 zu sehen – innerhalb der Funktion zum onLoad- Ereignis: var theData:Array = myLoader.firstChild.firstChild.firstChild.childNodes;
  • 290.
    SERVERSEITIGER DATENAUSTAUSCH –FLASH, PHP & DATENBANK 277 3. Speichern der XML-Daten in Variablen Abschließend werden die Daten in der richtigen Reihenfolge in den dafür vorgesehenen Variablen gespeichert: Vorname = theData[0].firstChild.nodeValue; Nachname = theData[1].firstChild.nodeValue; Firma = theData[2].firstChild.nodeValue; Adresse = theData[3].firstChild.nodeValue; PLZ = theData[4].firstChild.nodeValue; Ort = theData[5].firstChild.nodeValue; Staat = theData[6].firstChild.nodeValue; email = theData[7].firstChild.nodeValue; Listing 6.26: Die eingelesenen Daten werden in den dafür vorgesehenen Variablen gespeichert (Auszug). Reihenfolge beachten Bitte beachten Sie, dass die Reihenfolge der Informationen (zuerst Vorname, dann Nachname, Firma usw.) von entscheidender Bedeutung ist und uns beim Einlesen bekannt sein muss. Das Speichern der Daten in genau der richtigen Reihenfolge ist natürlich eine lästige Angelegenheit, nicht zuletzt deshalb, weil es eine potenzielle Fehlerquelle darstellt. 4. Dynamische Variablennamen Hier stellt sich unweigerlich die Frage, ob man nicht die schon in der XML-Datei verwendetenTag-Namen<Vorname>,<Nachname> usw.direktalsVariablennamen heranziehen kann. Ja, dem ist so – es besteht in Flash die Möglichkeit, dynamisch Variablennamen zu erzeugen. Jedem Hierarchie-Objekt in Flash ist ein Array von Variablen zugeordnet – möchte man beispielsweise dem _root-Objekt dynamisch Variablen zuweisen, so ist dies über den Zugriff auf das Array-Objekt möglich: _root["Variablenname"] = Wert; Dies kann man sich zu Nutze machen,indem man denVariablennamen,der letzten Endes ein reiner String ist, aus dem Tagnamen der XML-Datei generiert: _root[theData[x].nodeName] = Wert; x stellt eine beliebige Stelle im Array der eingelesenen Daten dar. Angewandt auf unser konkretes Beispiel würde dies wie folgt aussehen: for(var i:Number=0; i<theData.length; i++) { _root[theData[i].nodeName] = theData[i].firstChild.nodeValue; } In dieser for-Schleife werden sämtliche eingelesenen Knoten als Werte des Arrays theData (hierin sind die einzelnen Einträge als Objekte angelegt) mit
  • 291.
    K A PI T E L 6278 dem zugehörigen Knotennamen gespeichert. Beachten Sie, dass i (im Script fett geschrieben) der Index über alle Einträge des Arrays ist. 5. Das fertige Skript Das vollständige Skript dieses Beispiels sieht wie folgt aus. Sie finden es auch noch ein- mal auf der Buch-CD (XMLLoad02a.fla). Wie bereits weiter oben besprochen, können Sie in diesem Script die erste Zeile entfernen, wenn ein Dokument bereits den UTF-8- Zeichensatz verwendet (Flash arbeitet standardmäßig mit dem UTF-8-Zeichensatz): System.useCodepage = true; var anzLadeversuche:Number = 0; var maxLadeversuche:Number = 3; var myLoader:XML = new XML(); var mySource:String = "EinlesedatenXML01_UTF-8.txt"; myLoader.ignoreWhite=true; //var Vorname:String, Nachname:String, Firma:String, PLZ:String, Ort: String, Staat:String, email:String; //nicht mehr notwendig, da diese Variablen implizit deklariert werden myLoader.onLoad = function(loadedOK:Boolean) { //Ladevorgang abgeschlossen. anzLadeversuche++; if(loadedOK) { var theData:Array = myLoader.firstChild.firstChild.firstChild. childNodes; for(var i:Number=0; i<theData.length; i++) { _root[theData[i]. nodeName] = theData[i].firstChild.nodeValue; } gotoAndStop("LadevorgangErfolgreich"); } else { if(anzLadeversuche<maxLadeversuche) { myLoader.load(mySource); } else { gotoAndStop("LadevorgangFehlgeschlagen"); } } } myLoader.load(mySource); Listing 6.27: Der Lohn unserer Mühen – das vollständige Einleseskript für die XML-Daten aus unserem Beispiel (XMLLoad02a.fla)
  • 292.
    SERVERSEITIGER DATENAUSTAUSCH –FLASH, PHP & DATENBANK 279 Das _root-Array Dieses Array ist ideal für das dynamische Anlegen von eventuell nicht von vorneherein bekannt- en Variablennamen. Das _root-Array ist somit ein assoziatives Array, wobei die Elemente im Array die _root-Variablen darstellen. Variablen auf Root-Ebene sind für alle Scripts zugänglich und somit quasi „global“. (Hardcore-Programmierer würden mich jetzt zwar schimpfen, da man hier nicht von globalen Variablen spricht, aber mir ist an dieser Stelle der Sinn solcher Variablen wichtiger … liebe Programmierer, bitte verzeiht mit diesen kleinen Fehler!) 6. Daten in Flash ausgeben Nun müssen wir uns nur noch um die Darstellung der gespeicherten Daten kümmern. Anders als im vorigen Beispiel mit der Textdarstellung der Daten können wir nun direkt Variablenwerte in den dynamischen Textfeldern darstellen. Die dynamischen Textfelder geben somit die Variablen Vorname, Nachname, Firma usw. aus. Hierzu werden – wie in der folgenden Abbildung dargestellt – die Variablen Nachname, Vorname usw. als Ausgabevariablen der dynamischen Textfelder verwendet. ABBILDUNG 6.21 Beim Ausgeben der gespei- cherten Daten muss gegen- über dem Einlesen von URL- kodierten Textdaten darauf geachtet werden, dass nun reine Variablenwerte ausge- geben werden. XML-Daten über Arrays auswerten Nun zu Variante 2 – das Einlesen der Daten in ein Array, das Objekte beinhaltet. Gra- fisch dargestellt würde das zu verwendende Array wie in der Abbildung 6.22 gezeigt aufgebaut sein.
  • 293.
    K A PI T E L 6280 1. Zunächst wird ein Array erzeugt, das so viele Zellen beinhaltet wie – in unserem Fall – der XML-Baum Kunden beinhaltet. Derzeit ist dies nur ein einziger Kunde, jedoch sollte das Beispiel später auch für mehrere Kunden funktionieren. Die Anzahl der Array-Zellen kann natürlich auch dynamisch erzeugt werden, wenn von vorneherein nicht feststeht, wie viele Daten eingelesen werden. 2. Danach wird in jeder Zelle des Arrays pro Kunde ein Objekt angelegt, das alle Informationen zum Kunden speichert (Vorname, Nachname etc.). Sinn macht das Speichern in Arrays und Objekten nur dann, wenn wir mehr als einen einzigen Datensatz einlesen, denn wozu sollten wir sonst ein Array an Objekten anlegen. Obwohl jedoch unsere eingelesene Datei aus nur einem einzigen Datensatz besteht, arbeiten wir dieses Beispiel trotzdem exemplarisch mit einem Datensatz ab. Im Workshop-Teil greifen wir dieses Beispiel noch einmal auf und laden mehrere Datensätze ein. Schritt für Schritt: Daten aus einer XML-Datei lesen,Variante 2. Folgende Schritte sind vorzunehmen, um den XML-Baum einzulesen: 1. Array anlegen In diesem Array werden die jeweiligen Informationen als Objekt gespeichert. Der Name des Arrays ist selbstverständlich frei wählbar – wir haben uns an dieser Stelle für theDataStore entschieden. var theDataStore:Array = new Array(); 2. for-Schleife über alle Datensätze Unser Beispiel ist bereits so weit vorbereitet, dass eine Reihe von Datensätzen eingelesen werden könnten. Aus diesem Grund lassen wir eine for-Schleife über alle eingelesenen Datensätze laufen. var theData:Array = myLoader.firstChild.firstChild.childNodes; for(var i:Number=0; i<theData.length; i++) { … ABBILDUNG 6.22 Speichern der eingelesenen Daten in Objekten, die sich in einem Array befinden. Objekte Selbst erzeugte Objekte sind zum Speichern von strukturierten Daten her- vorragend geeignet. Dies sollte man sich in Flash zu Nutze machen.
  • 294.
    SERVERSEITIGER DATENAUSTAUSCH –FLASH, PHP & DATENBANK 281 3. Erzeugen eines Objekts pro Zelle im Array Innerhalb der Schleife muss dann im Array an der jeweiligen Stelle (Zelle) ein Objekt angelegt werden. Pro eingelesenem Datensatz (hier: pro Kunde) wird im Array eine eigene Zelle benötigt, der ein Objekt zugewiesen wird. Das Objekt selbst speichert die gewünschten Informationen, welche hier Vorname, Nachname usw. sind. theDataStore[i] = new Object(); 4. Speichern der XML-Daten im Objekt Zu guter Letzt werden die Daten ins Objekt geschrieben: theDataStore[i].Vorname = theData[i].childNodes[0].firstChild.nodeValue; theDataStore[i].Nachname = theData[i].childNodes[1].firstChild.nodeValue; theDataStore[i].Firma = theData[i].childNodes[2].firstChild.nodeValue; theDataStore[i].Adresse = theData[i].childNodes[3].firstChild.nodeValue; theDataStore[i].PLZ = theData[i].childNodes[4].firstChild.nodeValue; theDataStore[i].Ort = theData[i].childNodes[5].firstChild.nodeValue; theDataStore[i].Staat = theData[i].childNodes[6].firstChild.nodeValue; theDataStore[i].email = theData[i].childNodes[7].firstChild.nodeValue; Listing 6.28: Sämtliche zu speichernde Daten werden im Objekt abgelegt (Auszug). 5. Variablen anlegen Da unser Beispiel einen Datensatz ausgeben soll,werden die darzustellenden Daten wie schon zuvor in Variablen gespeichert, die dann in dynamischen Textfeldern ausgegeben werden. Vorname = theDataStore[0].Vorname; Nachname = theDataStore[0].Nachname; Firma = theDataStore[0].Firma; Adresse = theDataStore[0].Adresse; PLZ = theDataStore[0].PLZ; Ort = theDataStore[0].Ort; Staat = theDataStore[0].Staat; email = theDataStore[0].email; Listing 6.29: Einlesen der Informationen der XML-Datei (Auszug) Eines ist am vorigen Beispiel zu beachten: Weil das Beispiel bereits so weit vorbereitet wurde,um mehr als nur einen Datensatz einzulesen,wurde nicht wie in
  • 295.
    K A PI T E L 6282 den vorigen Beispielen direkt auf das Tag <Kunde>, sondern auf das Tag <Kunden> zugegriffen (<Kunden> ist das übergeordnete Tag zu <Kunde>). Daher heißt es: var theData:Array = myLoader.firstChild.firstChild.childNodes; anstatt: var theData:Array = myLoader.firstChild.firstChild.firstChild.childNodes; Das gesamte Beispiel finden Sie wie gewohnt auf der Buch-CD als Datei mit dem Namen XMLLoad02b.fla. XML-Daten mit Attributen Wir möchten nun eine weitere Möglichkeit darstellen, wie ein XML-Baum aufgebaut werden kann. Letzten Endes ist die Möglichkeit der Wertübergabe nicht auf Textkno- ten beschränkt, sondern kann ebenso über Attribute erfolgen. Die Anwendung gleicht der der bekannten Attribute aus XHTML, wobei wir in XML bei der Wahl der Attri- butnamen frei sind. Betrachtet man beispielsweise das Listing in Listing 6.29, so sieht man dort, dass anstelle der Textknoten <Vorname>, <Nachname> etc. die Attribute Vorname, Nachname usw. verwendet werden. ABBILDUNG 6.23 Anstatt der Textknoten wurden dieses Mal Attribute eingesetzt. Die Auswertung in Flash muss entsprechend geändert werden. Um Attribute auswerten zu können, steht aus Flash das Objekt attributes zur Ver- wendung bereit. Auf die Werte des Objekts kann man über den Namen der verwen- deten Variable („Spaltenname“) zugreifen. In unserem Fall wären folgende Anwen- dungen gleichbedeutend und führen zum selben Ergebnis: attributes["Vorname"]; //liefert "Uwe" attributes.Vorname; //liefert "Uwe" Für welche Variante Sie sich entscheiden, liegt bei Ihnen. Sollte etwa nicht bekannt sein, wie viele Attribute verwendet werden, empfiehlt sich eine Schleife über alle Attri- bute (attributes.length). Vergleicht man das dazu notwendige Skript mit unserem Beispiel aus Listing 6.27, so muss dieses Listing durch das nachfolgende Skript ersetzt werden:
  • 296.
    SERVERSEITIGER DATENAUSTAUSCH –FLASH, PHP & DATENBANK 283 theDataStore[i].Vorname = theData[i].attributes.Vorname; theDataStore[i].Nachname = theData[i].attributes.Nachname; theDataStore[i].Firma = theData[i].attributes.Firma; theDataStore[i].Adresse = theData[i].attributes.Adresse; theDataStore[i].PLZ = theData[i].attributes.PLZ; theDataStore[i].Ort = theData[i].attributes.Ort; theDataStore[i].Staat = theData[i].attributes.Staat; theDataStore[i].email = theData[i].attributes.email; Listing 6.30: Anstatt wie im letzten Beispiel auf einen Textknoten zuzugreifen, wird nun auf die Attribute eines Knotens zugegriffen. Die Ausgabe der eingelesenen Daten ist dieselbe – hier sind keine Änderungen notwen- dig. Fassen wir also kurz zusammen, was wir soeben getan haben: 1. Anstatt mit Textknoten zu arbeiten, setzen wir Attribute ein. 2. Die „Werte“ der Textknoten werden zu Werten von Attributen, veranschaulicht dargestellt: <Textknoten>Wert</Textknoten> wird zu: <Knoten Textknoten_Wert="Wert" /> 3. Die Werte der Attribute kann man in Flash mithilfe des assoziativen Arrays attributes auslesen. Ihnen als Webentwickler steht es frei, welche Art der Wertedarstellung (Textknoten oder Attribute) Sie verwenden. Natürlich können Sie die Darstellung auch mischen. Eine Generalaussage, wann welche Variante zum Einsatz gelangen sollte, kann und soll an dieser Stelle nicht getroffen werden, weil es von Fall zu Fall unterschiedlich ist. Einlesen einer XML-konformen PHP-Datei Wenden wir uns einer ähnlichen Thematik zu, nämlich dem Einlesen einer PHP-Datei, die Daten XML-konform darstellt. Wie zu erwarten, läuft dies exakt gleich ab wie das Einlesen einer Textdatei. Der einzige Unterschied für Flash besteht darin, dass man anstatt einer Datei mit der Endung „.txt“ eine Datei mit der Endung „.php“ einliest. Der Aufwand hinsichtlich der Erstellung der einzulesenden Datei gestaltet sich natür- lich etwas anders, da der XML-Baum durch PHP generiert werden muss. Die Vorge- hensweise hierbei entspricht der Vorgehensweise bei der Generierung eines „Textin- halts“. Da dies bereits am Anfang dieses Kapitels sehr ausführlich beschrieben wurde, beschränken wir uns hier auf die Zusammenfassung der wesentlichen Schritte.
  • 297.
    K A PI T E L 6284 Das Generieren einer XML-Datei durch PHP ist im Wesentlichen nichts anderes als das Generieren irgendeines Inhalts eines Webdokuments. Entscheidend ist nur, was der Client zu sehen bekommt, und das ist in diesem Fall ein XML-konform aufge- bautes Dokument. 1. Definieren, welche Datenbank verwendet wird myysql_select_db(); 2. Auswahl der Datenbank prüfen Sollte die Methode mysql_select_db() den Wert false zurückgeben, war die Auswahl der Datenbank nicht erfolgreich. Der Rückgabewert true signalisiert, dass die Auswahl der Datenbank in Ordnung war. 3. Absetzen eines SQL-Statements $sql = "SELECT * FROM tbl_Kunden"; if(!$query = mysql_query($sql)) { die('<div class="error">Das SQL-Statement konnte nicht durchgef&uuml;hrt werden. Errorcode: ‚.mysql_error().'</div>'); } else { //echo('<div class="success">Das SQL-Statement:<br/>'.$sql.'<br/ >wurde erfolgreich abgesetzt.</div>'); } 4. Ausgeben der Daten in die PHP-Seite Diesem Teil müssen wir doch etwas mehr Aufmerksamkeit zuteil werden lassen, denn anders als bei einer einzulesenden Textdatei muss dieses Dokument XML- konform aufbereitet werden. Zunächst wird das Dokument als XML-Dokument gekennzeichnet: <?php echo(‚<?xml version="1.0" encoding="ISO-8859-1" standalone="yes" ?>'); ?> Im nächsten Schritt fügt man die Struktur der XML-Datei in Form von Tags ein: <XML-Kundenliste> <Kunden> Zuletzt werden die in der Datenbank gespeicherten Daten mithilfe einer Schleife ausgegeben: <?php while($theData = mysql_fetch_array($query)) { echo("<Kunde>");
  • 298.
    SERVERSEITIGER DATENAUSTAUSCH –FLASH, PHP & DATENBANK 285 echo("<Vorname>".$theData["vc_Vorname"]."</Vorname>"); echo("<Nachname>".$theData["vcP_Nachname"]."</Nachname>"); echo("<Firma>".$theData["vc_Firma"]."</Firma>"); echo("<Adresse>".$theData["vc_Adresse"]."</Adresse>"); echo("<PLZ>".$theData["vc_PLZ"]."</PLZ>"); echo("<Ort>".$theData["vc_Ort"]."</Ort>"); echo("<Staat>".$theData["vc_Staat"]."</Staat>"); echo("<email>".$theData["vc_email"]."</email>"); echo("</Kunde>"); } ?> Danach schließt man die geöffneten Tags: </Kunden> </XML-Kundenliste> Listing 6.31: Auszug aus dem Listing der Datei EinlesedatenXML02.php Die clientseitige Sicht Man muss sich immer vor Augen führen, dass Flash eine clientseitige Anwendung ist und dem- nach auch nur Informationen einlesen kann, die clientseitig (in irgendeiner Form) dargestellt werden können. In unserem Fall produziert der Server auf Anfrage durch PHP-Programmierung dieses XML-konforme Dokument, das – und das ist der springende Punkt – aus Sicht des Clients aus purem XML-Inhalt besteht. 5. Flash-Datei anpassen Die Änderungen in Flash hinsichtlich des Einlesens der Datei sind gegenüber dem vorangegangenen Beispiel minimal. Es muss lediglich die Zeile: var mySource:String = "EinlesedatenXML01_UTF-8.txt"; mit der einzulesenden Datei in EinlesedatenXML02.php geändert werden: var mySource:String = "EinlesedatenXML02.php"; Damit wäre dieses Beispiel aus Flash- und PHP-Sicht abgeschlossen. 6. Attribute statt Textknoten
  • 299.
    K A PI T E L 6286 Für den Fall, dass wir anstatt der Textknoten in PHP Attribute zur Darstellung der Werte verwenden (vgl. Listing 6.31), muss die PHP-Datei innerhalb der while- Schleife in nachfolgendes Skript geändert werden: while($theData = mysql_fetch_array($query)) { echo("<Kunde"); echo(" Vorname='".$theData["vc_Vorname"]."'"); echo(" Nachname='".$theData["vcP_Nachname"]."'"); echo(" Firma='".$theData["vc_Firma"]."'"); echo(" Adresse='".$theData["vc_Adresse"]."'"); echo(" PLZ='".$theData["vc_PLZ"]."'"); echo(" Ort='".$theData["vc_Ort"]."'"); echo(" Staat='".$theData["vc_Staat"]."'"); echo(" email='".$theData["vc_email"]."'"); echo(" />"); } Listing 6.32: Anstatt der Textknoten werden auch beim Erzeugen der XML-Daten nun Attribute eingesetzt (Auszug aus dem Listing der Datei EinlesedatenXML03.php). 6.3.3 Ausgeben von XML-Daten in eine PHP-Seite Ebenso wie man Daten aus einer XML-Datei einlesen kann, besteht auch die Möglich- keit, XML-Daten an ein serverseitiges Dokument (in unserem Fall eine PHP-Datei) zu übergeben, das die Daten weiterverarbeitet und beispielsweise in eine Datenbank schreibt. Man sollte an dieser Stelle nicht unerwähnt lassen, dass das Ausgeben von Informati- onen per XML aus Flash heraus bei weitem nicht so oft eingesetzt wird wie das Einle- sen von XML-Daten. Der Grund ist sicherlich auch der, dass auf Serverseite die Daten über ein geeignetes Skript erst noch geparst und aufbereitet werden müssen, wodurch ein (oft nicht unerheblicher) Mehraufwand bei der Entwicklung entsteht. Stattdessen ABBILDUNG 6.24 Anstelle der Textknoten im vorigen Beispiel werden nun Attribute innerhalb der Tags zum Einsatz kommen.
  • 300.
    SERVERSEITIGER DATENAUSTAUSCH –FLASH, PHP & DATENBANK 287 könnte auch das LoadVars-Objekt zum Einsatz kommen. Nichtsdestotrotz stellt das Ausgeben von XML-Daten eine sehr elegante und auch zukunftsweisende Variante dar. Vorgehensweise beim Ausgeben von XML-Daten Im Wesentlichen erfolgt das Senden und Verarbeiten der Daten in drei Schritten: 1. Erzeugen eines XML-Baums inklusive Header-Informationen in Flash Zunächst wird in Flash ein XML-Baum mit den zu sendenden Daten erstellt. Hierzu stehen uns in Flash alle notwendigen Hilfsmittel zur Verfügung – auf diese werden wir im Folgenden noch genauer eingehen. 2. Versenden der XML-Daten an eine PHP-Seite Flash ist nicht in der Lage, direkt Daten an eine Datenbank zu senden, da Flash – wie Sie natürlich wissen – eine clientseitige Anwendung ist. 3. Parsen der übergebenen XML-Daten in PHP Die aus Flash übergebenen Daten werden nun in der PHP-Datei geparst und beispielsweise in eine Datenbank geschrieben. Der XML-Header Grundsätzlich kann jeder XML-Baum nach eigenen Regeln aufgebaut werden. Soll der Baum jedoch zur weiteren Verwendung an beispielsweise eine PHP-Datei übertragen werden, ist ein korrekter Header unabdingbar. Ein typischer XML-Header ist <?xml version='1.0' encoding='UTF-8'?>. Erzeugen eines XML-Baums in Flash Mal andersrum – im vorigen Abschnitt haben wir uns damit beschäftigt, einen XML- Baum in PHP zu erzeugen, um diesen dann in Flash einzulesen. In PHP haben wir auf XML-spezifische Befehle zum Erzeugen eines XML-Baums „verzichtet“, da einfach keine Befehle in PHP hierzu existieren, sieht man einmal von der Verwendung zusätz- licher Bibliotheken ab. In Flash stellt sich die Sache etwas differenzierter dar, da Flash uns sehr wohl einige Möglichkeiten bietet. In der nachfolgenden Tabelle finden Sie diese aufgelistet und mit einer kurzen Erklärung versehen. Danach schreiten wir zur Tat und erzeugen anhand eines konkreten Beispiels einen XML-Baum.
  • 301.
    K A PI T E L 6288 Methode Verwendung new XML() Konstruktor zum Erstellen eines neuen XML-Objekts. Wie auch beim Einlesen von XML-Daten muss zunächst ein solches XML-Objekt angelegt werden. createElement(Elementname) Erzeugt ein neues XML-Element (einen Knoten) mit dem angegebenen Namen (Elementname).Sämtliche Child- oder Parent-Knoten sowie Attribute müssen nachträglich erzeugt werden,da diese von vorneherein nicht existieren.Mithilfe von appendChild kann das Element danach an einen bestehenden XML-Baum angehängt werden. createTextNode(Text) Erzeugt ähnlich der Methode createElement einen XML-Knoten,jedoch handelt es sich in diesem Fall um einen Textknoten.Der Inhalt dieses Textknotens ist der Wert aus Text.Wie auch bei createElement muss dieses Element nach dem Anlegen per appendChild an einen bestehenden XML-Baum angehängt werden. appendChild(Childknoten) Fügt den angegebenen Child-Knoten (der zuvor per createElement oder createTextNode erzeugt wur- de) am Ende eines bestehenden XML-Baums an. insertBefore(Childknoten, Vor-Knoten) Fügt den angegebenen Child-Knoten vor dem Vor- Knoten ein.Wird kein Vor-Knoten angegeben,so wird die Methode appendChild verwendet und der Knoten somit am Ende des XML-Baums angehängt. firstChild Diese Eigenschaft ist bereits aus dem vorigen Kapitel bekannt.Mit ihrer Hilfe kann man von einem Parent- in einen Child-Knoten wechseln. attributes Mithilfe dieses Objekts können für bestehende Knoten Attribute erzeugt werden. xmlDecl Legt die grundlegenden Informationen zum XML- Dokument fest:Versionsnummer von XML,Kodiertyp etc. contentType Legt den MIME-Type fest,der an den Server (bei send oder sendAndLoad) übermittelt wird.Wird typischer- weise auf„text/html“ gesetzt. Tabelle 6.2: XML-Befehle in Flash zum Erzeugen eines XML-Baums Unser Ziel ist es nun, die Theorie in die Praxis umzusetzen, und zwar anhand des von uns in den vorigen Kapiteln verwendeten Beispiels der Kundendatendarstellung. Wie schon weiter oben im Kapitel angedeutet, müssen wir zunächst einen neuen XML- Baum „erschaffen“, was mit dem Konstruktor new XML() möglich wird: 1. Erzeugen eines neuen XML-Baums inklusive Header Damit das XML-Dokument auch seine Gültigkeit hat, benötigt es einen Header, der gleich mit der Deklaration des XML-Objekts angegeben werden kann: var myXML:XML = new XML("<?xml version='1.0' encoding='UTF-8'?>"); Alternative: Deklaration als XML-Daten Alternativ dazu (und für PHP besser verständlich) kann man auch wie folgt vorgehen:
  • 302.
    SERVERSEITIGER DATENAUSTAUSCH –FLASH, PHP & DATENBANK 289 var myXML:XML = new XML(); myXML.ignoreWhite = true; myXML.contentType = ‚text/html'; myXML.xmlDecl = "<?xml version='1.0' encoding='UTF-8' ?>"; Wie Sie sehen, wird im alternativen Skript im Prinzip dasselbe XML-Objekt erzeugt, mit dem Unterschied, dass die Definition (Deklaration) des XML über die Eigenschaft xmlDecl erfolgt. Des Weiteren wird für das XML-Objekt der contentType definiert sowie die schon bekannte Eigenschaft ignoreWhite=true gesetzt. Dies ist im Allgemeinen nur dann notwendig, wenn Sie damit rechnen müssen, dass leere Textknoten auftreten. Wir würden an dieser Stelle empfehlen, die zweite Methode zu verwenden, da PHP beim Einlesen der XML-Daten aus Flash mit dieser Variante besser zurechtkommt. 2. Erzeugen des Hauptknotens Danach wollen wir denselben XML-Baum wie in Abbildung 6.19 dargestellt aufbauen.Diesbedeutetalso,dasszunächstderHauptknoten<XML-Kundenliste> anzulegen ist. Hierzu wird zunächst mithilfe der Methode createElement ein neues (unabhängiges) Knoten-Element erzeugt und danach mittels appendChild an das Ende unseres (derzeit ohnehin noch leeren) XML-Baums angehängt. Wie der Knoten benannt wird, steht Ihnen vollkommen frei – wir haben uns für rootNode entschieden: var rootNode:XMLNode = myXML.createElement("XML-Kundenliste"); myXML.appendChild(rootNode); WürdedasElementrootNode nichtperappendCild andenXML-Baumangefügt, so wäre die ganze Arbeit umsonst gewesen. ABBILDUNG 6.25 Das root-Element ist bereits erzeugt. 3. Erzeugen eines Knotens innerhalb eines bereits bestehenden Knotens Um den nächsten Knoten <Kunden> innerhalb des Elements <XML-Kundenliste> anzulegen, müssen wir – nachdem wir wieder per createElement ein unabhängiges Element erzeugt haben – in das Element <XML-Kundenliste> selbst hineinspringen, also auf das erste Child des XML-Baums verweisen. Dies gelingt durch den Einsatz der Eigenschaft firstChild:
  • 303.
    K A PI T E L 6290 var subNode1:XMLNode = myXML.createElement("Kunden"); myXML.firstChild.appendChild(subNode1); Somit haben wir also erreicht, dass innerhalb des Elements <XML-Kundenliste> ein Element namens <Kunden> angelegt wurde. 4. Erzeugen eines Child-Knotens im Knoten <Kunden> Gleiches wie im Arbeitsschritt zum Erzeugen des Knotens <Kunden> ist auch für den Knoten <Kunde> (Child von <Kunden>) vorzunehmen. var subNode2:XMLNode = myXML.createElement("Kunde"); myXML.firstChild.firstChild.appendChild(subNode2); Wie Sie sehen, wird nun zweimal per firstChild vom XML-Objekt myXML ausgehend verwiesen. Dies hat den einfachen Grund, dass <Kunde> ein Child von <Kunden> und dieses wiederum ein Child von <XML-Kundenliste> ist – somit ist <Kunde> quasi das „Enkelkind“ von <XML-Kundenliste>. ABBILDUNG 6.26 In den Hauptknoten <XML- Kundenliste> wurde ein Child-Knoten namens <Kunden> eingefügt. 5. Erzeugen von Child-Knoten und Zuweisen von Werten im Knoten <Kunde> Nun ist es an der Zeit, die Knoten für Nachname, Vorname, Firma usw. anzulegen und diese mit Werten (dies sind in unserem Fall Textknoten) zu füllen. Da die Vorgehensweise für alle Knoten gleich ist, demonstrieren wir dies anhand eines Knotens. Im Folgenden werden wir dann Überlegungen anstellen, wie wir uns die Arbeit für diese Knoten doch erheblich vereinfachen können. Doch zunächst zum Anlegen der Knoten. var subNode3:XMLNode = myXML.createElement("Vorname"); myXML.firstChild.firstChild.firstChild.appendChild(subNode3); var subNode3a:XMLNode = myXML.createTextNode(Vorname); myXML.firstChild.firstChild.firstChild.childNodes[0].appendChild(subNode3a); Zunächst wird – wie schon hinlänglich bekannt – ein neues unabhängiges Element per createElement erzeugt.In unserem Fall ist das der Knoten <Vorname>.Dieser Knoten wird der „Urenkel“ von <XML-Kundenliste>, deshalb muss dreimal die Eigenschaft firstChild angewendet werden. ABBILDUNG 6.27 Der Knoten <Kunden> hat ein Kind bekommen – <Kunde>.
  • 304.
    SERVERSEITIGER DATENAUSTAUSCH –FLASH, PHP & DATENBANK 291 Ist dies geschehen, wird zunächst ein neuer, wieder unabhängiger Textknoten erzeugt und dieser dann innerhalb des soeben neu erzeugten Knotens <Vorname> (dies ist ja der nullte Child-Knoten von <Kunde>) per appendChild eingefügt. Der Wert des Textknotens wird aus der Variable Vorname ermittelt, die zuvor von uns angelegt und mit dem Wert [ Vorname ] versehen wurde. Das Ergebnis sehen Sie in Abbildung 6.28. 6. Weitere Knoten Jetzt könnte man für alle weiteren Knoten (<Nachname>, <Firma> etc.) genau gleich verfahren. Dies bedingt jedoch eine relativ „unelegante“ Programmierung, was wir als erfahrene Programmierer ja eigentlich gar nicht so gerne sehen ... Wie das aussehen würde, sehen Sie im nachfolgenden Listing. //Erzeugen eines neuen XML-Baums: --------------------- var myXML:XML = new XML(); myXML.ignoreWhite = true; myXML.contentType = "text/html"; myXML.xmlDecl = "<?xml version='1.0' encoding='UTF-8' ?>"; var rootNode:XMLNode = myXML.createElement("XML-Kundenliste"); myXML.appendChild(rootNode); // ----------------------------------------------------- //Erzeugen des ersten Unterknotens: -------------------- var subNode1:XMLNode = myXML.createElement("Kunden"); myXML.firstChild.appendChild(subNode1); // ----------------------------------------------------- //Erzeugen des ersten Unter-Unterknotens: -------------- var subNode2:XMLNode = myXML.createElement("Kunde"); myXML.firstChild.firstChild.appendChild(subNode2); // ----------------------------------------------------- var subNode3:XMLNode = myXML.createElement("Vorname"); ABBILDUNG 6.25 Der Knoten <Vorname> wurde eingefügt und ihm wurde ein Wert mithilfe eines Textknotens zuge- wiesen.
  • 305.
    K A PI T E L 6292 myXML.firstChild.firstChild.firstChild.appendChild(subNode3); var subNode3a:XMLNode = myXML.createTextNode(Vorname); myXML.firstChild.firstChild.firstChild.childNodes[0].appendChild(subNode3a); subNode3 = myXML.createElement("Nachname"); myXML.firstChild.firstChild.firstChild.appendChild(subNode3); subNode3a = myXML.createTextNode(Nachname); myXML.firstChild.firstChild.firstChild.childNodes[1].appendChild(subNode3a); subNode3 = myXML.createElement("Firma"); subNode3a = myXML.createTextNode(Firma); myXML.firstChild.firstChild.firstChild.childNodes[2].appendChild(subNode3a); myXML.firstChild.firstChild.firstChild.appendChild(subNode3); subNode3 = myXML.createElement("Adresse"); myXML.firstChild.firstChild.firstChild.appendChild(subNode3); subNode3a = myXML.createTextNode(Adresse); myXML.firstChild.firstChild.firstChild.childNodes[3].appendChild(subNode3a); subNode3 = myXML.createElement("PLZ"); myXML.firstChild.firstChild.firstChild.appendChild(subNode3); subNode3a = myXML.createTextNode(PLZ); myXML.firstChild.firstChild.firstChild.childNodes[4].appendChild(subNode3a); subNode3 = myXML.createElement("Ort"); myXML.firstChild.firstChild.firstChild.appendChild(subNode3); subNode3a = myXML.createTextNode(Ort); myXML.firstChild.firstChild.firstChild.childNodes[5].appendChild(subNode3a); subNode3 = myXML.createElement("Staat"); myXML.firstChild.firstChild.firstChild.appendChild(subNode3); subNode3a = myXML.createTextNode(Staat); myXML.firstChild.firstChild.firstChild.childNodes[6].appendChild(subNode3a);
  • 306.
    SERVERSEITIGER DATENAUSTAUSCH –FLASH, PHP & DATENBANK 293 subNode3 = myXML.createElement("email"); myXML.firstChild.firstChild.firstChild.appendChild(subNode3); subNode3a = myXML.createTextNode(email); myXML.firstChild.firstChild.firstChild.childNodes[7].appendChild(subNode3a); Listing 6.33: Ein etwas mühseliges Skript zum Erzeugen des XML-Baums – das muss doch auch einfacher gehen ... Alternative: Schleife statt stures Programmieren Aus diesem Grund haben wir uns dafür entschieden,den eleganteren Weg zu gehen und diese Knoten über eine Schleife zu erzeugen. Um dies zu bewerkstelligen, gehen wir folgendermaßen vor: Zunächst erzeugen wir ein Array, in dem die Namen aller einzulesenden Tags gespeichert sind. var theNodes:Array = new Array("Vorname", "Nachname", "Firma", "Adresse", "PLZ", "Ort", "Staat", "email"); Danach gehen wir in einer Schleife alle Einträge dieses Arrays durch und schreiben die entsprechenden Daten in den XML-Baum: var subNode3:XMLNode, subNode3a:XMLNode; for(var i:Number=0; i<theNodes.length; i++) { subNode3 = myXML.createElement(theNodes[i]); myXML.firstChild.firstChild.firstChild.appendChild(subNode3); subNode3a = myXML.createTextNode(eval(theNodes[i])); myXML.firstChild.firstChild.firstChild.childNodes[i]. appendChild(subNode3a); } Listing 6.34: Auszug aus dem Skript zum Erzeugen des XML-Baums (alternative Arbeitsweise zu Listing 6.33). Das Beispiel finden Sie auf der Buch-CD unter dem Namen XMLSend01a.fla. Die Methode eval() Wichtig in diesem Skriptblock beim Erzeugen des subNode3a ist die Methode eval(). Mit ihr wird es möglich, einen String als Variablennamen anzusehen und somit den Inhalt der Variablen auszulesen. Mit anderen Worten kann man sagen, dass ein String als Variable interpretiert wird.
  • 307.
    K A PI T E L 6294 7. Versenden der XML-Daten In beiden Fällen – ob nun mühselig oder leicht – fehlt noch der entscheidende Schritt des Versendens der XML-Daten. Dieser Schritt ist wohl derjenige, der am einfachsten fällt. Die dafür vorgesehene Methode heißt send() und erwartet von uns minimal einen Parameter – die URL, an die die Daten verschickt werden sollen – und maximal zwei Parameter – als zweiten Parameter den Fensternamen aus HTML, in dem die URL dargestellt werden soll. Möchte man, dass das „Empfängerdokument“ nur am Server verarbeitet, jedoch nicht für den User sichtbar dargestellt wird, muss man nur auf den zweiten Parameter verzichten: myXML.send("parserXML01.php"); In diesem Fall werden demnach alle Informationen dem Dokument parserXML01. php übermittelt. Daten mit PHP auswerten Mit dem Zeitpunkt des Versendens der Daten aus der Flash-Datei heraus ist sämtliche Arbeit für den Flash-Entwickler erledigt. Bleibt noch zu klären, wie die Daten per PHP ausgewertet werden können. Bevor wir nun das XML-Objekt aus Flash weiterverarbeiten können, müssen wir uns kurz Gedanken darüber machen, in welchem Format diese Daten von Flash an PHP übergeben werden. Normalerweise übergibt Flash Daten vom Typ application/x-www-form-url- encoded. Wäre dies der Fall, würde PHP die Daten parsen und von der Variable $HTTP_RAW_POST_DATA in ein assoziatives Array namens $_POST verschieben. DaaberderFlash-ProgrammiererdurchdieAngabevonmyXML.contentType='text/ html' den Datentyp in text/html geändert hat, bleiben die Daten in der Variable $HTTP_RAW_POST_DATA. Sie wissen nun also, dass wir die Daten von Flash über die Variable $HTTP_RAW_POST_DATA ansprechen können. Nun geht es daran, diese Daten auszulesen und anschließend in die Datenbank zu speichern. Kein Zugriff auf $HTTP_RAW_POST_DATA? Sollten Sie auf $HTTP_RAW_POST_DATA nicht zugreifen können, kontrollieren Sie in der php.ini, ob die Einstellung always_populate_raw_post_data auf on gesetzt ist. ABBILDUNG 6.29 Hier nun das fertige XML- Dokument, das für das Versenden an eine PHP-Datei bereitsteht
  • 308.
    SERVERSEITIGER DATENAUSTAUSCH –FLASH, PHP & DATENBANK 295 Für das Auslesen haben wir mehrere Möglichkeiten. Wir könnten über das DOM die Informationen bekommen oder auch aber über die neuen Funktionen von Sim- pleXML. (Zur Erinnerung: SimpleXML ist eine Funktionsbibliothek von PHP.) Nähe- res dazu haben Sie schon im Grundlagenteil der Programmierung erfahren. Ich schlage Ihnen vor, SimpleXML zu benutzen, da es – so finde ich – um einiges einfacher ist. Gehen wir es an: Daten auslesen und in eine Datenbank speichern. 1. Daten aus Flash in einer Variable speichern $XMLData = $HTTP_RAW_POST_DATA; Um die XML-Daten anzusehen, können wir ganz einfach die Variable $XMLData über den echo-Befehl anzeigen lassen. Somit können wir uns auch die XML- Struktur anschauen. 2. SimpleXML-Objekt anlegen SimpleXML bietet uns die Möglichkeit, über simplexml_load_string() ein XML-Objekt zu erstellen. Dieses Objekt werden wir $objKunde zuweisen. $objKunde = simplexml_load_string($XMLData); 3. Auf die Daten in $objKunde zugreifen Wir wissen, dass wir folgende Daten bekommen: Vorname Nachname Firma Adresse Staat PLZ Ort E-Mail Zusätzlich wissen wir, dass wir immer nur die Daten eines Kunden bekommen. Somit greifen wir auf die XML-Daten des jeweiligen Knotens an der Stelle 0 zu. Stellen Sie sich eine XML-Struktur am besten wie eine Ordnerstruktur im Windows-Explorer vor. Somit wäre der erste Ordner der Ordner „Kunden“. In diesem Ordner gibt es einen weiteren namens „Kunde“. Im Kunde-Ordner gibt es dann acht zusätzliche Ordner auf der gleichen Ebene, nämlich einen für Vorname, Nachname, Firma, Adresse, Staat, PLZ, Ort und E-Mail. Nun müssen wir nur noch dieser Struktur folgend von außen nach innen in PHP wandern, um an die richtigen Daten zu kommen. Aber bestimmt sind Sie mit der XML-Struktur schon so weit vertraut, dass dieses Thema für Sie keine Hürde mehr darstellt.
  • 309.
    K A PI T E L 6296 Beginnen wir mit dem Vornamen des Kunden: Wir wissen, im Objekt $objKunde sind unsere XML-Daten gespeichert. Zusätzlich kennen wir die Struktur von „Kunden“ über „Kunde“ zu „Vorname“: $vorname = $objKunde->Kunden[0]->Kunde[0]->Vorname; Den Vornamen des Kunden speichern wir nun nur noch in eine Variable namens $vorname. Jetzt ist sicher auch klar, wie wir an die anderen Daten „Kunden“ herankommen: $nachname = $objKunde->Kunden[0]->Kunde[0]->Nachname; $firma = $objKunde->Kunden[0]->Kunde[0]->Firma; $adresse = $objKunde->Kunden[0]->Kunde[0]->Adresse; $staat = $objKunde->Kunden[0]->Kunde[0]->Staat; $plz = $objKunde->Kunden[0]->Kunde[0]->PLZ; $ort = $objKunde->Kunden[0]->Kunde[0]->Ort; $email = $objKunde->Kunden[0]->Kunde[0]->email; Das war’s auch schon – ging doch sehr einfach. Ein Lob an SimpleXML. Als Nächstes müssen wir noch die gewonnenen Daten in unsere Datenbank sichern. 4. Verbindung zur Datenbank Wie gewohnt nehmen wir Kontakt zum Datenbankserver auf und verbinden uns mit einer dort befindlichen Datenbank: $hostname = "IHR HOSTNAME"; $username = "IHR USERNAME"; $password = "IHR PASSWORT"; if(!$conn = mysql_connect($hostname, $username, $password)) { die('<div class="error">Verbindung zur Datenbank konnte nicht hergestellt werden. Errorcode: '.mysql_error().'</div>'); } Wir speichern den Rückgabewert in der Variable $conn. Danach überprüfen wir, ob $conn false ist. Ist das der Fall, wird mit der Funktion die() das Ausführen des Skripts abgebrochen und der Text „Verbindung zur Datenbank konnte nicht hergestellt werden.“ sowie der entsprechende Fehlercode ausgegeben. 5. Datenbank auswählen Wenn das Verbinden erfolgreich war, müssen wir noch unsere gewünschte Datenbank am Server auswählen. Dazu nutzen wir die Funktion mysql_select_ db(). Diese erwartet den Datenbanknamen und die Verbindungskennung, die wir zuvor realisiert haben.
  • 310.
    SERVERSEITIGER DATENAUSTAUSCH –FLASH, PHP & DATENBANK 297 $db = "IHRE DATENBANK"; if(!mysql_select_db($db)) { die('<div class="error">Die Datenbank '.$db.' konnte nicht ausgewaehlt werden. Errorcode: '.mysql_error().'</div>'); } Da wir nun die Verbindung zu unserer gewünschten Datenbank hergestellt haben, können wir die XML-Daten in diese speichern. 6. Speichern der XML-Daten in die Datenbank Dazu müssen natürlich in der Datenbank eine Tabelle und die notwendigen Felder angelegt sein. Wir haben bereits im Vorfeld eine Tabelle namens „tbl_kunden“ mit den Feldern „idP_Kunde“, „vc_Vorname“, „vcP_Nachname“, „vc_Adresse“, „vc_ Staat“, „vc_PLZ“, „vc_Ort“ und „vc_email“ angelegt. Diesen Schritt müssten Sie also an dieser Stelle noch dazwischenschieben. Über INSERT INTO tabellenname (tabellenfelder) VALUES (‚werte') können wir die Daten in unsere Datenbank speichern.Wir speichern dies als String in die Variable $sql ab. $sql = " INSERT INTO tbl_kunden (vc_Vorname,vcP_Nachname,vc_Firma,vc_Adresse,vc_Staat,vc_PLZ,vc_ Ort,vc_email) VALUES (‚$vorname','$nachname','$firma','$adresse','$staat','$plz','$ort',' $email') "; 7. Anfrage an die Datenbank senden Jetzt müssen wir noch die Anfrage an die Datenbank senden. Dazu nutzen wir mysql_query(). Dieser Funktion müssen wir unseren Anfragestring als Parameter angeben. Ist das Speichern der Daten erfolgreich, so liefert auch diese Funktion true zurück. Wenn nicht, brechen wir das Ausführen des Skripts wieder mit die() ab. $rs = mysql_query($sql) or die ("Die Daten konnten nicht gespeichert werden."); Das war’s auch schon. Jetzt sind unsere Daten des Kunden in der Datenbank gespeichert. Sämtliche Daten dieses Beispiels finden Sie selbstverständlich auf der Website zum Buch sowie auf der Buch-CD.
  • 311.
    K A PI T E L 6298 6.3.4 Die XMLConnector-Komponente Flash hat im Zusammenhang mit XML noch mehr zu bieten als das sture Parsen von XML-Daten. Seit der Version Flash MX 2004 stellt uns Adobe die XMLConnector- Komponente zur Seite, um auf einfache Art und Weise mit XML-Daten arbeiten zu können. Komponenten gehören zur Symbolgruppe der MovieClips und stellen die Möglichkeit dar, während der Entwicklung parametergestützt Eigenschaften und Methoden zu erhalten. Mithilfe von ActionScript ist es uns jedoch auch möglich, diese Parameter zur Laufzeit zu ändern (das ist Ihnen sicherlich noch in Zusammenhang mit der TextArea- Komponente im Gedächtnis). Die XMLConnector-Komponente gehört zur Gruppe der Data-Komponenten: ABBILDUNG 6.30 Sämtliche Daten wurden von Flash an die PHP-Datei parserXML01.php übergeben. Diese Datei sorgt dafür, dass die Daten in die Datenbank gespeichert werden. ABBILDUNG 6.31 Die Gruppe der Data- Komponenten beinhaltet die von uns benötigte XMLConnector-Komponente.
  • 312.
    SERVERSEITIGER DATENAUSTAUSCH –FLASH, PHP & DATENBANK 299 Grundsätzlich bietet uns diese XMLConnector-Komponente Zugriff auf eine beliebige externe Datenquelle, die XML-basierte Daten mittels HTTP bereitstellen (oder auch empfangen) können. Mithilfe eines sogenannten „Schemas“ wird die XML-Quelle dann ausgelesen – auf das Thema der Schemata kommen wir etwas später noch einmal zurück. Wie im Umgang mit Komponenten üblich, wird eine Komponente in der Flash-Ent- wicklungsumgebung auf die Bühne gezogen. Dies ist im Allgemeinen nicht unbedingt erforderlich, denn wir können auch zur Laufzeit mithilfe von ActionScript Kompo- nenten erstellen, jedoch gehen wir diesen Weg, um uns das Vorgehen zunächst so einfach wie möglich zu gestalten. An welcher Stelle Sie die Komponente auf der Bühne platzieren, ist vollkommen irrelevant, da diese selbstverständlich nicht sichtbar ist: Als Tipp gilt: Legen Sie die Komponente außerhalb des (sichtbaren) Bühnenbereichs ab, damit Sie diese während der Arbeit nicht irritiert. Wie läuft nun die Arbeit mit einem XMLConnector ab? Die nachfolgende Auflistung sorgt für Klarheit: 1. Es wird eine Instanz der XMLConnector-Komponente auf (oder außerhalb) der Bühne platziert. 2. Der Instanz wird ein Instanzname zugewiesen. ABBILDUNG 6.32 An welcher Stelle Sie die XMLConnector-Komponente einfügen, bleibt gänzlich Ihnen überlassen, da diese (siehe swf-Datei) selbstver- ständlich nicht sichtbar ist.
  • 313.
    K A PI T E L 6300 3. Die Instanzparameter werden angegeben: URL: Adresse, von wo die Instanz die XML-Datei bezieht. direction: je nachdem, ob gesendet und geladen (send/receive), nur gela- den (receive) oder nur gesendet (send) werden soll. In den meisten Fällen wird nur geladen, deshalb ist die Einstellung receive wohl die gängigste. ignoreWhite: Um Zeilenumbrüche, Leerzeichen etc. aus den Daten zu elimi- nieren, wird dieser Parameter auf true gesetzt. Diese Einstellung ist in jedem Fall zu empfehlen und auch deshalb standardmäßig auf true gesetzt. multipleSimultaneousAllowed: bestimmt, ob mehrere Anfragen gleich- zeitig ablaufen dürfen. Da nicht garantiert werden kann, dass genau in der Reihenfolge der Aufrufe auch die Antworten eintreffen, und alle gängigen Browser eine höchstzulässige Anzahl an gleichzeitig herunterzuladenden URLs besitzen, spricht nichts dagegen, diesen Parameterwert auf false zu setzen. Ist der Parameter auf false gesetzt, wird der Aufruf über die Methode trigger durchgeführt, die wiederum ein status-Ereignis (CallAlreadyInProgress) ausgibt. Details hierzu finden Sie im ActionScript 2.0-Referenzhandbuch. supressInvalidCalls: Mithilfe dieses Parameters wird sichergestellt, dass bei dem Wert true Aufrufe mit ungültigen Parametern erst gar nicht durch- geführt werden. Die nachfolgende Abbildung verdeutlicht die bisher getroffenen Einstellungen für ein erstes Beispiel (auf der Buch-CD zu finden unter dem Namen XMLConnector01.fla): u u u u u ABBILDUNG 6.33 Die XMLConnector- Komponente wurde auf der Bühne platziert (im Weiteren werde ich diese neben die Bühne stellen, damit sie mich nicht irritiert) und es wurden ihr alle notwendigen Parameter zugewiesen. Als Quelle dient die Datei XMLConnector01.xml.
  • 314.
    SERVERSEITIGER DATENAUSTAUSCH –FLASH, PHP & DATENBANK 301 XML- vs. Textdatei für das Schema An dieser Stelle sprechen wir zum ersten Mal von einer „echten“ XML-Datei: In unserem Kontext verstehen wir darin eine Datei, die nicht nur „gültig“ und „wohlgeformt“ ist, sondern auch die Endung .xml trägt. Obwohl eine Text- und eine XML-Datei dieselben Inhalte aufweisen können, benötigt Flash eine Datei mit der Endung .xml für eine Schema-Datei. Die eigentliche einzule- sende Datei (also unsere XML-Quelle) kann nach wie vor die Endung .txt tragen! Damit wären die notwendigen Schritte getan – bleibt nur noch zu klären, wohin die Daten nun gelangen, denn ein Laden von Daten ohne zugehöriges Darstellen ist wohl in den wenigsten Fällen zielführend. Werfen wir einmal einen Blick auf die einzu- lesende Datei XMLConnector01.xml (bzw. XMLConnector01.txt, wenn Sie eine Text- datei einlesen möchten): <?xml version="1.0" encoding="ISO-8859-1" standalone="yes" ?> <Mitarbeiterliste> <Mitarbeiter> <Vorname>Uwe</Vorname> <Nachname>Mutz</Nachname> <Firma>SYNE Marketing & Consulting GmbH</Firma> <Adresse>Am Graben 29</Adresse> <PLZ>4020</PLZ> <Ort>Linz</Ort> <Staat>AUT</Staat> <email>uwe.mutz@syne.at</email> </Mitarbeiter> <Mitarbeiter> <Vorname>Alexander</Vorname> <Nachname>Grasser</Nachname> <Firma>SYNE Marketing & Consulting GmbH</Firma> <Adresse>Am Graben 29</Adresse> <PLZ>4020</PLZ> <Ort>Linz</Ort> <Staat>AUT</Staat> <email>alexander.grasser@syne.at</email> </Mitarbeiter> <Mitarbeiter> <Vorname>Doris</Vorname>
  • 315.
    K A PI T E L 6302 <Nachname>Manzenreiter</Nachname> <Firma>SYNE Marketing & Consulting GmbH</Firma> <Adresse>Am Graben 29</Adresse> <PLZ>4020</PLZ> <Ort>Linz</Ort> <Staat>AUT</Staat> <email>doris.manzenreiter@syne.at</email> </Mitarbeiter> </Mitarbeiterliste> Listing 6.35: Eingelesen wird eine nicht allzu aufregend komplexe XML-Datei: eine Mitarbeiterliste mit drei Mitarbeitern (XMLConnector01.xml). Es wird also Zeit, den nächsten Schritt zu tun: Wir müssen ein Schema angeben. Ein Schema gibt an, wie die einzulesende XML-Quelle aufgebaut ist oder mit anderen Worten: wie die XML-Quelle strukturiert ist (Verschachtelungen, Tags, Attribute). Hierzu blenden wir uns erst einmal den Komponenten-Inspektor ein (entweder in der Menüzeile auf FENSTER/KOMPONENTEN-INSPEKTOR oder unter Windows die Tastenkom- bination (ª)+(F7) bzw. unter Mac OS die Tastenkombination (†)+(F7)): ABBILDUNG 6.34 Der Komponenten-Inspektor im Fall der XMLConnector- Komponente In der obigen Abbildung sehen Sie die erste Lasche PARAMETER des Komponenten- Inspektors, deren Einträge wir auch im Eigenschaften-Inspektor zur Komponenten- Instanz gefunden haben. Interessanter werden die Laschen BINDUNGEN und SCHEMA. Beginnen wir mit der SCHEMA-Lasche: Markieren Sie den Eintrag < RESULTS : XML, kli- cken Sie auf das Flyout-Menü und wählen Sie dort den Eintrag XML-SCHEMA IMPOR-
  • 316.
    SERVERSEITIGER DATENAUSTAUSCH –FLASH, PHP & DATENBANK 303 TIEREN aus. Es öffnet sich ein Fenster, in dem Sie eine XML-Datei auswählen können, woraus das XML-Schema importiert wird. Wie schon weiter oben erwähnt, können Sie nur Dateien mit der Endung .xml auswählen. Für unser Beispiel importieren wir also der Einfachheit halber genau unsere Quelldatei XMLConnector01.xml, deren Schema sofort auch im Komponenten-Inspektor angezeigt wird: Wenn wir nun dieses Schema mit der Quelldatei vergleichen, fällt sofort auf, dass nur die Tags Mitarbeiterliste, Mitarbeiter, Vorname, Nachname und Firma einge- lesen wurden – da fehlt doch was?! Es fehlen die Tags PLZ, Ort, Staat und Email! Gehen wir der Sache auf den Grund. Der Fehler liegt anscheinend am Inhalt der XML-Datei: Im Firmennamen „SYNE Marketing & Consulting GmbH“ wird ein kaufmännisches Und „&“ verwendet, das das Einlesen des Schemas blockiert. Um diese Fehlerquelle zu eliminieren, müssen wir das „&“ URL-codieren: Der entsprechende Code lautet %26. Somit würde sich unsere XML-Datei (das Schema!) wie folgt ändern (Auszug aus der Datei XMLConnector01b. xml): ... <Mitarbeiter> <Vorname>Uwe</Vorname> <Nachname>Mutz</Nachname> <Firma>SYNE Marketing %26 Consulting GmbH</Firma> <Adresse>Am Graben 29</Adresse> <PLZ>4020</PLZ> Fehler in der Quelldatei oder im Schema? Fehler in der Quelldatei oder im Schema? ABBILDUNG 6.35 Nach dem Importieren des Schemas zeigt der Komponenten-Inspektor den Aufbau (= Schema) der XML- Datei an.
  • 317.
    K A PI T E L 6304 <Ort>Linz</Ort> <Staat>AUT</Staat> <email>uwe.mutz@syne.at</email> </Mitarbeiter> ... Listing 6.36: Auszug aus der nun URL-codierten Datei XMLConnector01b.xml: Das kaufmännische Und „&“ wurde durch den Code %26 ersetzt. Bitte beachten Sie jedoch die nachfolgende Auflistung, denn nicht alles, was als Fehler erscheint, ist auch ein Fehler! An dieser Stelle möchte ich Sie auf einen meines Erachtens sehr wichtigen Punkt hin- weisen, der immer wieder zu Verwechslungen führt: Das Schema einer einzulesenden XML-Datei sollte idealerweise nur das „Gerüst“ (die Struktur) der einzulesenden XML-Quelle beinhalten – somit besitzt die Sche- ma-Datei keinerlei Inhalte. Im obigen Beispiel haben wir nur zu gut erfahren, zu welchen Problemen das führt! Des Weiteren müssen wir beachten, dass das Schema eine Datei mit der Endung .xml ist. Die einzulesende XML-Quelle ist nach der von der Schema-Datei vorgegebenen Struktur aufgebaut und beinhaltet (klarerweise) sämtliche Inhalte. Diese Datei kann eine beliebige Dateiendung aufweisen (.xml, .txt, .php etc.), solange diese Daten XML-konform sind (Thema „Gültig“ und „Wohlgeformt“). Somit würde sich als XML-Schema eine Datei mit folgendem Inhalt anbieten: <?xml version="1.0" encoding="ISO-8859-1" standalone="yes" ?> <Mitarbeiterliste> <Mitarbeiter> <Vorname /> <Nachname /> <Firma /> <Adresse /> <PLZ /> <Ort /> <Staat /> <email /> </Mitarbeiter> </Mitarbeiterliste> Listing 6.37: Ein korrektes XML-Schema (und das wollten wir ja auch!), eine sinnlose XML-Quelle! u u XML-Quelle vs. XML-Schema XML-Quelle vs. XML-Schema
  • 318.
    SERVERSEITIGER DATENAUSTAUSCH –FLASH, PHP & DATENBANK 305 Beim Importieren dieses Schemas sind jedoch ein paar zusätzliche Schritte erforder- lich: 1. Da die Felder nun ohne Inhalte sind, muss für jedes Feld der Feldtyp (Number, String etc.) angegeben werden, ansonsten würde Flash davon ausgehen, dass diese Felder leer sein müssen. Würden wir ein Schema mit Inhalten importieren, würde Flash die eingelesenen Inhalte analysieren und einen entsprechenden Feldtyp automatisch wählen. 2. Da das Tag <Mitarbeiterliste> aus nur einem verschachtelten Tag <Mitarbeiter> besteht, nimmt Flash automatisch an, dass immer nur ein Tag (und nicht eine Liste von Tags) eingelesen werden muss. In der Abbildung 6.36 sehen Sie einen Screenshot, wie Flash mit diesem Schema arbei- ten würde: Um den Tags einen Feldtypen zuzuweisen, klicken Sie auf den Feldnamen und wählen in der Parameterliste darunter den Eintrag DATA TYPE aus. In unserem Fall sind alle Einträge vom Typ STRING: ABBILDUNG 6.36 Flash geht davon aus, dass die eingelesenen Tags Vorname, Nachname etc. immer leer sind. Unsere Aufgabe wird sein, den Feldern den zugehörigen Datentyp zuzuweisen.
  • 319.
    K A PI T E L 6306 Diesen Vorgang müssen wir nun für alle Felder wiederholen. Ist dies geschehen, müs- sen wir Flash noch zu verstehen geben, dass wir mehr als nur einen einzelnen Eintrag einlesen werden. Hierzu markieren wir den Eintrag MITARBEITER : OBJECT und wählen in der Parameterliste als DATA TYPE den Typ ARRAY (anstatt OBJECT): ABBILDUNG 6.37 Das Feld Vorname bekommt den Feldtyp String zuge- wiesen. ABBILDUNG 6.38 Mit Angabe des Datentyps Array geben wir Flash zu verstehen, dass es sich nicht um ein einzelnes Objekt han- delt, das wir einlesen werden, sondern vielmehr um eine Liste von Objekten. Haben wir diesen Schritt geschafft, geht es daran, die eigentlichen Daten einzulesen und anzuzeigen. Wir machen uns die Sache einfach und wählen für die Anzeige eine Tabellenform. Zunächst einmal ein Screenshot des Ergebnisses:
  • 320.
    SERVERSEITIGER DATENAUSTAUSCH –FLASH, PHP & DATENBANK 307 Unter den KOMPONENTEN finden Sie die Komponentengruppe USER INTERFACE und darin die Komponente DATAGRID. Ziehen Sie eine Instanz davon auf die Bühne, geben Sie ihr einen Namen (z.B. Mitarbeitertabelle) und weisen Sie ihr eine entspre- chende Größe zu (in meinem Fall waren das 590x350 Pixel bei einer Bühnengröße von 600x400 Pixel). Markieren Sie danach wieder die Instanz unseres XMLConnector und weisen Sie ihr – sollten Sie das nicht bereits gemacht haben – einen Instanznamen zu (beispielsweise myXMLConnector). Gehen Sie anschließend wie folgt vor: 1. Wählen Sie für myXMLConnector im Komponenten-Inspektor die Lasche BINDUNGEN aus. 2. Klicken Sie auf das blaue Symbol „+“ zum Hinzufügen einer neuen Bindung: ABBILDUNG 6.39 Einlesen einer XML-Datei (basierend auf einem vor- gegebenen Schema) und Darstellen der Daten in Tabellenform (es kommt ein sogenanntes „DataGrid“ zur Verwendung). Eingelesen wird nach wie vor die Datei XMLConnector01.xml, die auch die kaufmännischen Und „&“ beinhaltet – diese waren ja nur für unser Schema gefährlich ... ABBILDUNG 6.40 Hinzufügen einer neuen Bindung durch Klicken auf das blaue „+“
  • 321.
    K A PI T E L 6308 3. Wählen Sie aus der möglichen Bindung den Eintrag MITARBEITER : ARRAY aus und bestätigen Sie mit OK: 4. Markieren Sie die so entstandene Bindung, wählen Sie in den Parametern zunächst für den Parameter DIRECTION den Wert out und klicken Sie dann im Parameterfeld BOUND TO auf die Suchlupe ganz rechts im Feld. Es öffnet sich ein Fenster mit den möglichen Komponenten, wo Sie die DataGrid-Komponente auswählen: ABBILDUNG 6.41 Auswählen der Liste an Mitarbeitern (Array) für die Anzeige im DataGrid ABBILDUNG 6.42 Die Daten werden mithilfe des Parameters BOUND TO dem DataGrid „Mitarbeitertabelle“ zugewiesen. Somit haben wir sämtliche Arbeit an sowohl dem XML-Connector als auch dem DataGrid erledigt. Testen wir jedoch unser Beispiel, werden wir feststellen, dass trotz- dem nichts passiert. Das liegt daran, dass das Einlesen der Daten aus der XML-Quelle nicht automatisch passiert, sondern „angestoßen“ werden muss. Der geeignete Befehl ist hierfür der Befehl trigger, der auf die Instanz der XMLConnector-Komponente myXMLConnector angewandt wird:
  • 322.
    SERVERSEITIGER DATENAUSTAUSCH –FLASH, PHP & DATENBANK 309 myXMLConnector.trigger(); Listing 6.38: Erst die Methode trigger veranlasst Flash, die XML-Quelle einzulesen und in das DataGrid zu schreiben. Das Ergebnis sahen Sie bereits in Abbildung 6.39. Letzten Endes ist das Arbeiten mit Komponenten immer dann anzuraten, wenn es schnell gehen soll und man nicht allzu viel Zeit mit Programmierung „vergeuden“ möchte. Wenn wir ehrlich sind, war das letzte Beispiel mehr „Drag&Drop“ als ernste Entwicklung. Doch wie gesagt: Wenn es die Aufgabenstellung erfordert, ist auch gegen „Drag&Drop“ nichts einzuwenden! Neben der hier vorgestellten DataGrid-Komponente existieren noch einige weitere User Interface-Komponenten, die für die Darstellung von XML-Daten hervorragend geeignet sind: Komponente Beschreibung Accordion Darstellen von Daten in Form von Bereichen,die angeklickt werden und sich dann wie ein Akkordeon aufklappen Tree Darstellen von Daten in Form einer Baumstruktur (vergleichbar mit dem Windows Explorer,sollten Sie diesen kennen) Tabelle 6.3: Komponenten zur Darstellung von (beispielsweise) XML-Daten Ein guter Anhaltspunkt, das Arbeiten mit Komponenten zu intensivieren, ist die Beispielsammlung von Adobe, die Sie auf der Adobe-Website finden: http://www. adobe.com/de/devnet. 6.4 ActionScript 3.0: Neues und Änderungen In diesem Kapitel befassen wir uns mit den Änderungen und Neuerungen, die Action- Script 3.0 mit sich bringt. 6.4.1 Das URLLoader- und URLRequest-Objekt In den bisherigen Ausführungen (Verwendung von ActionScript 2.0) erfuhren Sie, wie man für ein gegebenes Objekt – sei es ein LoadVars- oder XML-Objekt – geeignete (objektspezifische) Methoden verwendet, um die benötigten Daten zu laden. Der Nachteil an diesen Methoden war, dass diese sich immer auf das Objekt selbst bezogen haben: XML.load() hatte mit LoadVars.load() bis auf den (zufälligerweise) glei- chen Namen nichts gemeinsam. Drag&Drop oder Program- mierung? Drag&Drop oder Program- mierung?
  • 323.
    K A PI T E L 6310 Dies ändert sich mit ActionScript 3.0 gewaltig, denn ab nun existiert ein einziges Objekt zum Laden von externen Daten: das URLLoader-Objekt. Das bisher bekannte LoadVars-Objekt ist zur Gänze eliminiert worden. Im Klartext bedeutet dies, dass das Laden externer Daten nun vollständig über das URLLoader-Objekt (in Verbindung mit dem URLRequest-Objekt, auf das wir noch zu sprechen kommen) abgewickelt wird! Die Übersicht der Eigenschaften, Methoden und Ereignisse liefert uns einen Hinweis über die Möglichkeiten dieses Objekts: Eigenschaft Typ und Standardwert Beschreibung bytesLoaded uint = 0 Stellt die Anzahl der Bytes dar,die bereits geladen wurden bytesTotal uint = 0 Stellt die Anzahl der gesamt zu ladenden Bytes dar (sprich: die Dateigröße) data * Repräsentiert die empfangenen Daten dataFormat String = "text" Gibt an,von welchem Typ die zu ladenden Daten sind. Folgende Typen sind möglich: TEXT BINARY VARIABLES Tabelle 6.4: Eigenschaften des URLLoader-Objekts Vorrangig wichtige Eigenschaften sind also data und dataFormat. Die Eigenschaften bytesLoaded und bytesTotal benötigen Sie für den Fall, dass Sie dem User eine Ladestandsanzeige darstellen wollen. Methode Beschreibung URLLoader(request:URLRequest = null) Erzeugt ein URLLoader-Objekt,dem ein URLRequest- Objekt zugewiesen werden kann close():void Beendet einen laufenden Ladevorgang load(request:URLRequest):void Sendet und lädt Daten von der im URLRequest angege- benen URL Tabelle 6.5: Methoden des URLLoader-Objekts Ereignis Ereignisobjekttyp und - eigenschaft Beschreibung complete Event.COMLETE Wird ausgelöst,wenn der Ladevorgang abgeschlossen und sämtliche Daten dekodiert wurden sowie sämtliche empfan- genen Daten in der Eigenschaft data des URLLoader gespeichert wurden.Dieses Ereignis gilt es also – wie auch schon weiter oben beschrieben – abzuwarten. LoadVars in ActionScript 3.0 nicht mehr existent! LoadVars in ActionScript 3.0 nicht mehr existent!
  • 324.
    SERVERSEITIGER DATENAUSTAUSCH –FLASH, PHP & DATENBANK 311 httpStatus HTTPStatusEvent.HTTP_STATUS Sollte ein URLLoader-Objekt per HTTP auf Daten zugreifen wollen und der Flash-Player in der Lage sein,den Statuscode zu erkennen und zurückzugeben,wird dieses Ereignis ausgelöst.Die wichtige Eigenschaft in diesem Fall ist die Eigenschaft status. ioError IOErrorEvent.IO_ERROR Tritt auf,wenn während eines Ladeversuchs ein schwerwie- gender Fehler auftritt und der Download abgebrochen werden musste.Wichtig ist die Eigenschaft text. open Event.OPEN Tritt nach dem Aufruf der load- Methode auf. progress ProgressEvent.PROGRESS Tritt auf,wenn Daten während eines Ladevorgangs empfan- gen werden.Die wichtigen Eigenschaften sind bytesLoaded und bytesTotal.Dieses Ereignis tritt wiederholt auf. securityError SecurityErrorEvent. SECURITY_ERROR Tritt auf,wenn versucht wird auf Daten zuzugreifen,die nicht innerhalb des Sicherheitskreises („Security Sandbox“) der Flash- Anwendung liegen.Wichtig ist in diesem Fall wie auch bei ioError die Eigenschaft text. Tabelle 6.6: Übersicht der Ereignisse des URLLoader-Objekts Das URLRequest-Objekt hält mehrere Eigenschaften für uns bereit, die in Tabelle 6.7 beschrieben sind. Eigenschaften Typ Beschreibung contentType String Liefert den MIME-Typ eventueller POST-Daten data Object Die angeforderten Daten method String Legt die Übertragungsmethode fest.Mögliche Werte sind„GET“ oder „POST“. prototype Object Verweist auf das Prototypobjekt der Klasse requestHeaders Array Mithilfe dieses Arrays lässt sich der HTTP-Header manipulieren. url String Die URL,die für das Senden oder Empfangen von Daten verwendet wird Tabelle 6.7: Eigenschaften des URLRequest-Objekts. Besonders interessant sind die Eigenschaften data, method und url.
  • 325.
    K A PI T E L 6312 Laden von Daten Werfen wir einen Blick auf die Vorgehensweise beim Laden von Daten: 1. Anlegen eines URLLoader-Objekts: var myLoader:URLLoader = new URLLoader(); 2. Anlegen eines URLRequest-Objekts zur Angabe einer Quelle: var myURL:URLRequest = new URLRequest("URL_ZUR_QUELLE"); 3. Definieren eines Eventhandler für den Fall, dass die Daten geladen wurden. Es kommt das Ereignis COMPLETE zum Einsatz: function FUNKTIONSNAME_DES_HANDLERS(myEvent:Event):void { ... } myLoader.addEventListener(Event.COMPLETE, FUNKTIONSNAME_DES_HANDLERS); Listing 6.39: Beachten Sie in diesem Listing bitte die Tatsache, dass der Typ void nun – im Gegensatz zu ActionScript 2.0 – klein geschrieben wird. 4. Ladevorgang starten, basierend auf den Angaben in der URLRequest-Instanz (myURL): myLoader.load(myURL); Wie Sie sehen, wird an dieser Stelle noch kein Wort darüber verloren, welche Art von Daten sich in der Datenquelle befinden. Lediglich die Voraussetzung, dass es sich um Text, Binärdaten oder URL-codierte Variablen handelt, muss erfüllt sein. Zusammen- gefasst sieht ein Ladevorgang nun also folgendermaßen aus: var myLoader:URLLoader = new URLLoader(); var theURL:String = "URL_ZUR_QUELLE"; var myURL:URLRequest = new URLRequest(theURL); function completelyLoaded(myEvent:Event):void { ... } myLoader.addEventListener(Event.COMPLETE, completelyLoaded); myLoader.load(myURL); Listing 6.40: Der Ladevorgang von Text, Binär- oder URL-codierten Daten in ActionScript 3.0. Den Umgang mit den Eventlistenern sehen Sie in Listing 6.41 sehr ausführlich. Laden von Text, Binärdaten oder URL-codierten Daten Laden von Text, Binärdaten oder URL-codierten Daten
  • 326.
    SERVERSEITIGER DATENAUSTAUSCH –FLASH, PHP & DATENBANK 313 Erst im nächsten Schritt wird entschieden, was mit den eingelesenen Daten geschehen soll. Still und heimlich haben wir bisher noch vorausgesetzt, dass die einzulesenden Daten Textdaten sind – wären es Binär- oder URL-codierte Daten, so müssten wir das explizit angeben. Um als Beispiel einmal die in Tabelle 6.6 aufgelisteten Ereignisse abzufragen, müssen diese über die Methode addEventListener einer URLLoader-Instanz zugewiesen werden. Das könnte folgendermaßen aussehen (das Beispiel finden Sie auf der Buch- CD unter dem Namen URLLoader02_AS3.fla): var myLoader:URLLoader = new URLLoader(); var theURL:String = "URLLoader02_AS3.xml"; var myURL:URLRequest = new URLRequest(theURL); function EOpen(myEvent:Event):void { statusMsg.appendText("Ladevorgang gestartetn"); } function EProgress(myEvent:ProgressEvent):void { statusMsg.appendText("Ladevorgang läuft... Fortschritt: "+Math. round(myEvent.bytesLoaded/myEvent.bytesTotal*100)+"%n"); } function EComplete(myEvent:Event):void { statusMsg.appendText("Ladevorgang abgeschlossenn"); } function EHttpStatus(myEvent:HTTPStatusEvent):void { statusMsg.appendText("Http-Status eingelangt: Status="+myEvent.status+"n"); } function EIOError(myEvent:IOErrorEvent):void { statusMsg.appendText("IO-Error aufgetreten: Error="+myEvent.text+"n"); } function ESecurityError(myEvent:SecurityErrorEvent):void { statusMsg.appendText("Security-Error aufgetreten: Error="+myEvent.text+"n"); } myLoader.addEventListener(Event.OPEN, EOpen); myLoader.addEventListener(ProgressEvent.PROGRESS, EProgress); myLoader.addEventListener(Event.COMPLETE, EComplete);
  • 327.
    K A PI T E L 6314 myLoader.addEventListener(HTTPStatusEvent.HTTP_STATUS, EHttpStatus); myLoader.addEventListener(IOErrorEvent.IO_ERROR, EIOError); myLoader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, ESecurityError); myLoader.load(myURL); Listing 6.41: Für jedes auftretende Ereignis des URLLoader-Objekts wurde ein eigener Eventlistener defi- niert. Zu beachten ist vor allem, dass die verschiedenen Ereignisse von verschiedenen Ereignisobjekttypen abgearbeitet werden. Hier einige Tipps für den Umgang mit den verschiedenen Ereignissen: Ladefortschritt anzeigen ProgressEvent.PROGRESS sowie die Eigenschaften bytesLoaded und bytesTotal geben Ihnen Auskunft über den Ladezustand. Da dieses Ereig- nis wiederholt auftritt, kann sehr einfach eine Ladefortschrittsanzeige erstellt werden. Event.COMPLETE teilt Ihnen mit, wann das Laden der Daten beendet ist. Errorhandling IOErrorEvent.IO_ERROR und SecurityErrorEvent.SECURITY_ERROR mit dem Ereignis text (in beiden Fällen) lässt eine Fehlerabarbeitung zu. Event.COMPLETE teilt Ihnen mit, wann das Laden der Daten zu Ende ist. Kümmern wir uns im nächsten Schritt um die eingelesenen Daten. In den meisten Fällen wird es sich um textbasierte oder URL-codierte Daten handeln, deshalb ste- hen diese Anwendungsgebiete auch bei uns im Vordergrund. XML-Daten und deren Auswertung nehmen wir uns in Kapitel 6.4.2 sehr ausführlich zur Brust, den Part des Ladens der Variablen bzw. des Textes behandeln wir gleich hier. Der Zugriff auf die geladenen Daten erfolgt in jedem Fall über die Eigenschaft data des URLLoader-Objekts, die idealerweise beim Auftreten des Eevent.COMPLETE- Ereignisses ausgelesen wird (target ist in diesem Fall das Netzwerkobjekt, über wel- ches der Ladevorgang abgewickelt wurde): function EComplete(myEvent:Event):void { trace(myEvent.target.data); } Listing 6.42: Zugriff auf die geladenen Daten Laden von URL-codierten Daten (Variablen) In diesem Fall muss der URLLoader-Instanz zunächst mitgeteilt werden, dass die zu ladenden Daten URL-codiert sind: u u u u u u
  • 328.
    SERVERSEITIGER DATENAUSTAUSCH –FLASH, PHP & DATENBANK 315 var myLoader:URLLoader = new URLLoader(); myLoader.dataFormat = URLLoaderDataFormat.VARIABLES; Listing 6.43: Das Datenformat wird auf „URL-codierte Variablen“ (VARIABLES) gesetzt. Als Beispiel einzulesender (URL-codierter) Daten soll uns die Datei URLLoader03_ AS3.txt mit folgendem Inhalt dienen: test=1&vorname=Uwe&nachname=Mutz Der Zugriff auf die Variablen erfolgt wie in Listing 6.43 dargestellt über die data- Eigenschaft der URLLoader-Instanz: function EComplete(myEvent:Event):void { ... = myEvent.target.data; } Um nun eine spezielle Variable aus der geladenen Datei abzufragen, kann die Variable direkt angesprochen werden. Wollen wir beispielsweise die Variable „nachname“ aus- lesen, geschieht dies wie folgt: ... var nn:String = myEvent.target.data.nachname; trace("nn="+nn); ... Listing 6.44: Zugriff auf die Variable „nachname“ Damit sind wir auch schon wieder am Ende angelangt, denn sobald wir wissen, wie die Variablen angesprochen werden können, läuft das Spiel genau wie in den Beispielen aus Kapitel 6.2. Laden von Textdaten Da das Laden von textbasierten Daten standardmäßig vom URLLoader-Objekt ange- nommen wird, müssen wir dies nicht explizit angeben, obwohl man es theoretisch natürlich könnte: var myLoader:URLLoader = new URLLoader(); myLoader.dataFormat = URLLoaderDataFormat.TEXT; Listing 6.45: Das Setzen des Datenformats ist im Fall von textbasierten Daten nicht notwendig, da dies die Standardeinstellung ist. Somit könnten Sie getrost auf Zeile 2 des obigen Listings verzichten. Die einzulesende Datei URLLoader04_AS3.txt, die uns hier als Beispiel dient, hat fol- genden Inhalt:
  • 329.
    K A PI T E L 6316 Dies ist Text, den es einzulesen gilt. Mal sehen, ob es uns gelingen wird... Zu allem Überfluss kommen auch noch Umlaute und Sonderzeichen vor. Uwe Mutz SYNE Marketing & Consulting GmbH Listing 6.46: Inhalt der Datei URLLoader04_AS3.txt – beachten Sie die Leer- und Sonderzeichen sowie die Umlaute. Wie auch schon beim Laden von URL-codierten Daten greifen wir auf die Eigenschaft data der URLLoader-Instanz zu. Wir können uns glücklich schätzen, wie einfach das Laden von Textdaten ist, denn mit dem Zugriff auf data ist die Arbeit für uns getan – sogar Leer- und Sonderzeichen sowie Umlaute bereiten uns keine Sorgen. Sehen Sie selbst – zuerst der Code der Datei URLLoader04_AS3.fla, dann der Screenshot. Kurz noch zur Erklärung: statusMsg bezeichnet eine TextArea-Instanz, die uns zur Ausga- be der Daten dient. var myLoader:URLLoader = new URLLoader(); //myLoader.dataFormat = URLLoaderDataFormat.TEXT; //Standardwert var theURL:String = "URLLoader04_AS3.txt"; var myURL:URLRequest = new URLRequest(theURL); function EComplete(myEvent:Event):void { statusMsg.appendText("Ladevorgang abgeschlossenn"); statusMsg.appendText("Eingelesener Text:n"+myEvent.target.data); } myLoader.addEventListener(Event.COMPLETE, EComplete); myLoader.load(myURL); Listing 6.47: Laden von externen Textdaten – wie einfach die Welt doch sein kann! In der Datei auf der Buch-CD ist das Beispiel noch um ein Eventhandling erweitert.
  • 330.
    SERVERSEITIGER DATENAUSTAUSCH –FLASH, PHP & DATENBANK 317 Vielleicht sollten wir an dieser Stelle einmal festhalten, dass dieses Verfahren ein Novum in der Geschichte von Flash darstellt: Ohne den Text innerhalb der Textdatei einer Variable zuzuweisen und diese dann auszulesen, haben wir nun Zugriff auf Texte! Senden von Daten Gehen wir den umgekehrten Weg und betrachten das Senden von Daten an einen Ser- ver (sprich: ein serverseitiges Script). Da wir bisher noch keine Möglichkeit kennen- gelernt haben, die zu versendenden Variablen zu definieren (erinnern Sie sich: im Fall von ActionScript 2.0 und dem LoadVars-Objekt mussten wir lediglich die Variablen innerhalb einer LoadVars-Instanz anlegen – fertig!), muss es wohl einen anderen Weg geben ... dieser Weg heißt URLVariables. Mit anderen Worten: Eine Instanz des URL- Variables-Objekts dient uns nun als Container für die zu versendenden Variablen. Nehmen wir an, wir wollen die Variablen „Vorname“ und „Nachname“ an ein server- seitiges Script übermitteln. Also nichts wie rein mit den Variablen in unseren Contai- ner: var myVars:URLVariables = new URLVariables(); myVars.Vorname = "Uwe"; myVars.Nachname = "Mutz"; Listing 6.48: Die Verwendung des URLVariables-Objekts ist denkbar einfach: Instanz anlegen, Variablen darin anlegen und ihnen einen Wert zuweisen. Wie wir wissen, wird das URLRequest-Objekt zum Laden und Senden von Daten ver- wendet. In Tabelle 6.7 haben wir uns über die Verwendung der Konstanten GET und POST Gedanken gemacht – genau dieses Thema müssen wir nun berücksichtigen: Sollen die Daten später per POST oder GET versandt werden? ABBILDUNG 6.43 Na, was sagen Sie – Laden von Textdaten ohne umständliche Variablenzuweisung, wie es noch in ActionScript 2.0 not- wendig war!
  • 331.
    K A PI T E L 6318 Schritt 2 in unserem Beispiel umfasst demnach das Anlegen einer neuen URLRequest- Instanz und das Festlegen der Übertragungsmethode über die Eigenschaft method: var myURL:URLRequest = new URLRequest(); myURL.method = "GET"; Listing 6.49: Eine neue URLRequest-Instanz wurde erzeugt und es wurde ihr die Übertragungsmethode GET zugewiesen. Jetzt müssen wir die beiden Objekte URLVariables und URLRequest noch „zusam- menbringen“, sodass die URLRequest-Instanz die angelegten Variablen später auch versenden kann. Das korrekte Decodieren der Daten (in beispielsweise URL-codierte Form) geschieht dabei ganz automatisch: myURL.data = myVars; Listing 6.50: Der URLRequest-Instanz myURL werden über die Eigenschaft data alle in myVars er- zeugten Variablen zugewiesen. Alle Vorbereitungen für das Versenden der Daten sind nun erledigt – bleibt zu klären, zu welchem Zweck die Daten versandt werden sollen. Hier einige Möglichkeiten: Daten an ein serverseitiges Script übergeben, das die Daten dann weiterverarbei- tet: Ein Beispiel dafür wäre das Speichern der Daten in einer Datenbank oder das Überprüfen der Daten für ein eventuelles Login. Daten an ein Dokument übergeben und dieses in einem neuen Fenster öffnen. Soll- ten die Daten per GET übergeben worden sein, so können diese sowohl server- als auch clientseitig verarbeitet werden. Variante 1: Daten senden mit dem URLLoader-Objekt Vielleicht kommt es Ihnen eigenartig vor, dass wir ein Objekt mit dem Wort „Loa- der“ im Namen zum Versenden von Daten verwenden. Ganz so abwegig ist die Sache jedoch nicht, da ein URLLoader nach dem Senden eine etwaige Antwort des Servers empfängt und somit „lädt“. Alle weitere Arbeit mit dem URLLoader-Objekt erfolgt wie gehabt, denn dem URLRequest-Objekt wurden bereits alle Variablen zum Versenden zugewiesen: var theURL:String = "urlvariables01.php"; myURL.url = theURL; var myLoader:URLLoader = new URLLoader(); function EOpen(myEvent:Event):void { statusMsg.appendText("Ladevorgang gestartetn"); } u u
  • 332.
    SERVERSEITIGER DATENAUSTAUSCH –FLASH, PHP & DATENBANK 319 function EComplete(myEvent:Event):void { statusMsg.appendText("Ladevorgang abgeschlossenn"); statusMsg.appendText("Rückgabetext der PHP-Datei:n"+myEvent.target.data); } myLoader.addEventListener(Event.OPEN, EOpen); myLoader.addEventListener(Event.COMPLETE, EComplete); myLoader.load(myURL); Listing 6.51: Fortsetzung des angefangenen Scripts. Den gesamten Code finden Sie in der Datei URLVariables01_AS3.fla. Die Eigenschaft url ist zwar schon hinlänglich bekannt, jedoch ist die hier angespro- chene URL ein Verweis auf die Datei (in unserem Fall handelt es sich um urlvariab- les01.php), welche die gesendeten Daten entgegennimmt und entsprechend auswertet. Hier deren Inhalt: $returner = "ERROR (0)"; if(count($_REQUEST)>0) { $returner = "empfangende Daten:n"; foreach($_REQUEST as $itm=>$val) { $returner.= "$itm=$valn"; } } else { $returner = "ERROR (1)"; } echo($returner); Listing 6.52: Die Datei urlvariables01.php nimmt etwaig gesendete Daten gleich welcher Sendemethode (GET oder POST) entgegen und erzeugt hieraus eine Variable $returner, die im Weiteren per echo in den Ausgabepuffer der Datei geschrieben wird. Das PHP-Script setzt zunächst eine Variable $returner auf den Wert „ERROR (0)“, der uns mitteilt, dass ein unbekannter Fehler aufgetreten ist. Danach wird überprüft, ob Daten per POST oder GET gesendet wurden (diese müssten sich dann im $_ REQUEST-Array befinden und somit müsste das Array eine Länge größer null aufwei- sen). Ist dies nicht der Fall, dann wird $returner der Wert „ERROR (1)“ zugewiesen. Wurden jedoch Daten übermittelt, wird $returner dazu verwendet, einen String aus den gesandten Daten zusammenzustellen. Dieser String bzw. die Fehlerkennzeichnung „ERROR (0)“ oder „ERROR (1)“ wird am Ende des Scripts per echo ausgegeben: echo($returner);.
  • 333.
    K A PI T E L 6320 Zurück zu Flash. Das URLLoader-Objekt nimmt den von der PHP-Datei erzeugten String entgegen und gibt den String in der TextArea statusMsg aus – all dies ist in der Funktion EComplete zu finden. Nach einem Test online (diesmal benötigen wir ja wieder einen Server, der die PHP- Anweisungen verarbeiten kann) erhalten wir dieses Ergebnis: Variante 2: Senden mit sendToURL Die Methode sendToURL ist vergleichbar mit der Methode send des LoadVars- Objekts: Es werden Variablen an einen Server übertragen, eine etwaige Antwort des Servers wird jedoch ignoriert (im Gegensatz zur obig beschriebenen Methode, die eine Antwort des Servers auswertet). Sie ist also ideal dafür geeignet, wenn man an einen Server Daten übermitteln will, die zwar serverseitig abgearbeitet werden sollen, wobei aber eine Antwort des Servers nicht notwendig ist – einfache Datenbankanwendungen wie Schreiben von statistischen Werten in Bezug auf das User-Verhalten oder zeitkri- tische Anwendungen sind Einsatzgebiete von sendToURL. sendToURL ersetzt gemeinsam mit der Methode navigateToURL die getURL-Metho- de aus ActionScript 2.0. Die Verwendung ist sehr ähnlich wie die zuvor mit dem URLLoader vorgestellte Variante. Es besteht jedoch keine Möglichkeit, eine abgeschlossene Übertragung abzu- warten, da der Server keinen Response gibt. Lediglich die Möglichkeit einer einfachen Fehlerüberprüfung mit der im AJAX-Kapitel bereits hinlänglich dargestellten try- catch-Methode ist möglich: Ersatz eins für getURL aus ActionScript 2.0 ABBILDUNG 6.44 Flash sendet die in URLVariables definierten Variablen an die Datei urlvariables01.php, welche wiederum einen (Rückgabe- )String zusammenbastelt, in dem die gesandten Variablen vorkommen. Flash empfängt diesen String und gibt ihn in der TextArea aus.
  • 334.
    SERVERSEITIGER DATENAUSTAUSCH –FLASH, PHP & DATENBANK 321 var myVars:URLVariables = new URLVariables(); myVars.Vorname = "Uwe"; myVars.Nachname = "Mutz"; var myURL:URLRequest = new URLRequest(); myURL.method = "GET"; myURL.data = myVars; var theURL:String = "sendtourl01.php"; myURL.url = theURL; try { sendToURL(myURL); } catch(myError:Error) { statusMsg.appendText("FEHLER beim Versenden:ntMessage: "+myError. message+"ntName: "+myError.name+"nterrorID: "+myError.errorID); } Listing 6.53: Versenden von Daten an einen Server per sendToURL Das Listing entspricht bis auf den try-catch-Abschnitt den Listings Listing 6.48 bis Listing 6.50: Anlegen einer URLVariables-Instanz, um die zu übertragenen Daten zu definie- ren Anlegen einer URLRequest-Instanz, um Daten versenden zu können. In unserem Fall werden die in myVars abgelegten Daten per GET an die Datei sendtourl01.php verschickt. Im Grunde genommen hätte ein abschließender Aufruf von sendToURL ausgereicht, um die Daten zu übermitteln. Der umgebende try-catch-Bereich gibt uns die Mög- lichkeit, eine entsprechende Fehlermeldung in einer TextArea statusMsg auszuge- ben, sollte der sendToURL-Aufruf zu einem Fehler geführt haben. Benötigen Sie eine Fehlerabarbeitung nicht, so lassen Sie den try-catch-Bereich einfach weg und rufen lediglich die sendToURL-Methode auf. Um unser Beispiel überprüfen zu können, ist die Datei sendtourl01.php so aufgebaut, dass sie die einkommenden Daten übernimmt und daraus eine E-Mail zusammen- stellt: function create_email_header($name, $value) { return ($name && $value) ? "$name: $valuern" : ""; u u
  • 335.
    K A PI T E L 6322 } if(count($_REQUEST)>0) { $mailfrom = "autosender@syne.at"; $mailto = "uwe.mutz@syne.at"; $subject = "TESTMAIL von sendtourl01.php"; $msg = "Uebertragene Daten:n"; foreach($_REQUEST as $itm=>$val) { $msg.= "$itm=$valn"; } $msg.= "n(Versand per Email an: $mailto)"; $headers = ""; $headers .= create_email_header("From", $mailfrom); $headers .= create_email_header("Reply-to", $mailto); if(!mail($mailto, $subject, $msg, $headers)) { die("ERROR: FEHLER beim Versand der Email"); } } Listing 6.54: sendtourl01.php empfängt die von Flash versendeten Daten, generiert daraus den Inhalt einer E-Mail (foreach-Schleife) und versendet die E-Mail an eine vorgegebene E-Mail-Adresse (hier: uwe. mutz@syne.at) mithilfe der mail-Funktion. Ignorieren wir einmal vorerst die Funktion create_email_header und wenden uns gleich dem Bereich darunter zu: count($_REQUEST) gibt die Anzahl der (per GET oder POST) übermittelten Daten an. Waren es mehr als null Daten, so werden die Daten abgearbeitet. Die Variablen $mailfrom, $mailto und $subject speichern den Absender, Empfänger und den Betreff respektive und dienen lediglich der Übersichtlichkeit (ebenso hätte man die Absender- und Empfängeradresse sowie den Betreff auch direkt im mail-Befehl unterbringen können). $msg soll den Inhalt der E-Mail beinhalten.Zunächst weisen wir ihr den Text„Ueber- tragene Daten:n“ zu, danach gehen wir in der foreach-Schleife alle erhaltenen Daten durch und erweitern die Variable $msg durch den Variablennamen ($itm) u u u
  • 336.
    SERVERSEITIGER DATENAUSTAUSCH –FLASH, PHP & DATENBANK 323 und den Variableninhalt ($val). Abschließend hängen wir an $msg noch den Text „n(Versand per Email an: $mailto)“ an. Sie erinnern sich sicherlich, dass „n“ einen Zeilenumbruch im Text erzeugt. Die Variable $headers beinhaltet im weiteren die Header-Informationen für den Versand der E-Mail. Nachdem diese nach einem vorgegebenen Prinzip aufgebaut werden müssen, verwendet man gerne eine Funktion, die dies erledigt (somit sind wir bei der Funktion create_email_header angelangt, deren Erklärung ich zunächst übersprungen hatte). Abschließend wird die E-Mail versandt (mail-Befehl) – sollte bei der Abarbeitung von mail ein Fehler auftreten, wird das Script abgebrochen und eine entspre- chende Fehlermeldung ausgegeben. u u Variante 3: Senden mit navigateToURL Die Variante mit navigateToURL ist im Wesentlichen die gleiche wie diejenige mit sendToURL, mit einem einzigen Unterschied: navigateToURL öffnet die von Flash aufgerufene (und an diese übergebene Daten) in einem Fenster. navigateToURL erwartet bei einem Aufruf zwei Parameter: navigateToURL(request:URLRequest, window:String):void Ersatz zwei für getURL ABBILDUNG 6.45 Flash teilt der Datei send- tourl01.php mit, welche Daten in einer E-Mail gesammelt und versendet werden sollen. Fehler sind keine aufgetreten, eine Rückmeldung über einen positiven Versand der E-Mail haben wir jedoch auch nicht erhalten.
  • 337.
    K A PI T E L 6324 request ist eine Instanz des URLRequest-Objekts und beinhaltet die Daten, die Sendemethode (GET oder POST) sowie die URL. window bezeichnet das Fenster, in welchem die gegebene URL geöffnet werden soll. Die möglichen Werte kommen Ihnen sicherlich bekannt vor: „_self“: Die URL wird im aktuellen Frame im aktuellen Fenster geöffnet. „_blank“: Die URL wird in einem neuen Fenster geöffnet (Standardeinstel- lung). „_parent“: Die URL wird im übergeordneten Frame des aktuellen Frame im aktuellen Fenster geöffnet. „_top“: Die URL wird im obersten Frame des aktuellen Fensters geöffnet. „FRAMENAME“: Die URL wird in dem von Ihnen benannten Frame geöffnet. Inwieweit Sie noch mit Frames arbeiten, müssen Sie für sich selbst und für Ihre Kun- den entscheiden. Ich würde Ihnen den Tipp geben, keine neuen Webprojekte mit Frames anzugehen, da sie jetzt schon nicht mehr zum offiziellen Standard „strict“ von XHTML gehören. Ändern wir das aus Listing 6.53 bekannte Beispiel entsprechend um, so erhalten wir: ... var theURL:String = "navigatetourl01.php"; ... try { navigateToURL(myURL); } catch(myError:Error) { statusMsg.appendText("FEHLER beim Versenden:ntMessage: "+myError. message+"ntName: "+myError.name+"nterrorID: "+myError.errorID); } ... Listing 6.55: Aus Listing 6.53 haben sich lediglich der Methodenaufruf von sendToURL auf navigate- ToURL sowie die aufzurufende URL (jetzt: navigatetourl01.php) geändert. Die Daten werden somit an die Datei navigatetourl01.php per GET versandt, wobei navigatetourl01.php in einem neuen Fenster (Standardeinstellung, sofern kein eigenes Fenster angegeben wurde) geöffnet wird: u u u u u u u Frames?
  • 338.
    SERVERSEITIGER DATENAUSTAUSCH –FLASH, PHP & DATENBANK 325 6.4.2 Der Aufbau: das XML-Objekt & ActionScript 3.0 Mit Einführung von ActionScript 3.0 wurden an vielen Klassen Änderungen vor- genommen. Im Speziellen betrifft dies auch die XML-Klasse, die nun den Standard ECMAScript for XML (E4X) unterstützt. Da dies eine wesentliche Änderung gegenü- ber der bisherigen Handhabung von XML-Daten bedeutet, haben die Entwickler von Adobe kurzerhand die bisherige XML-Klasse in andere Klassen verschoben und eine neue XML-Klasse eingeführt. Die nachfolgende Tabelle soll Ihnen die Änderungen verdeutlichen (Quelle: Referenzhandbuch für ActionScript 3.0): XML-Klasse flash.xml.XMLDocument Diese Klasse wurde in das flash. xml-Paket verschoben und der Name wurde in XMLDocument geändert,um einen Konflikt mit der neuen Top-Level XML-Klasse zu vermeiden,die ECMAScript für XML (E4X) implementiert. contentType flash.net.URLRequest.contentType docTypeDecl flash.xml.XMLDocument.docTypeDecl idMap flash.xml.XMLDocument.idMap ignoreWhite flash.xml.XMLDocument.ignoreWhite loaded Entfernt Die Funktionen zum Laden einer Datei wurden aus der XMLDocument-Klasse entfernt. Verwenden Sie stattdessen URLLoader. status Entfernt Fehler beim Parsen werden jetzt über Ausnahmefehler gemeldet. ABBILDUNG 6.46 Ähnlich wie bei sendToURL werden die Daten an ein geeignetes Webdokument übergeben, wobei navigateToURL dieses in einem Fenster darstellt.
  • 339.
    K A PI T E L 6326 xmlDecl flash.xml.XMLDocument.xmlDecl XML flash.xml.XMLDocument.XMLDocument() addRequestHeader() flash.net.URLRequest.requestHeaders createElement() flash.xml.XMLDocument.createElement() createTextNode() flash.xml.XMLDocument.createTextNode() getBytesLoaded() flash.net.URLLoader.bytesLoaded Die Funktionen zum Laden einer Datei wurden aus der XMLDocu- ment-Klasse entfernt.Verwenden Sie stattdessen URLLoader. getBytesTotal() flash.net.URLLoader.bytesTotal Die Funktionen zum Laden einer Datei wurden aus der XMLDocu- ment-Klasse entfernt.Verwenden Sie stattdessen URLLoader. load() Entfernt Die Funktionen zum Laden einer Datei wurden aus der XMLDocument-Klasse entfernt (in ActionScript 2.0 war dies die XML- Klasse).Verwenden Sie stattdes- sen URLLoader. onData() flash.net.URLLoader dispatches event: complete Die Funktionen zum Laden einer Datei wurden aus der XMLDocument-Klasse entfernt. Verwenden Sie stattdessen URLLoader.Wurde im neuen Ereignismodell durch ein com- plete-Ereignis ersetzt. onHTTPStatus() flash.net.URLLoader dispatches event: httpStatus Die Funktionen zum Laden einer Datei wurden aus der XMLDocument-Klasse entfernt. Verwenden Sie stattdessen URLLoader.Wurde im neuen Ereignismodell durch ein http- Status-Ereignis ersetzt. onLoad() flash.net.URLLoader dispatches event: complete Die Funktionen zum Laden einer Datei wurden aus der XMLDocument-Klasse entfernt. Verwenden Sie stattdessen URLLoader.Wurde im neuen Ereignismodell durch ein com- plete-Ereignis ersetzt. parseXML() flash.xml.XMLDocument.parseXML() send() Entfernt Die Funktionen zum Senden einer Datei wurden aus der XMLDocument-Klasse entfernt (in ActionScript 2.0 war dies die XML- Klasse).Verwenden Sie stattdes- sen die Funktionen und Klassen im flash.net-Paket. sendAndLoad() Entfernt Die Funktionen zum Senden und Laden einer Datei wurden aus der XMLDocument-Klasse entfernt (in ActionScript 2.0 war dies die XML- Klasse).Verwenden Sie stattdes- sen URLRequest und URLLoader. Tabelle 6.8: Änderungen in der XML-Klasse von ActionScript 2.0 zu ActionScript 3.0
  • 340.
    SERVERSEITIGER DATENAUSTAUSCH –FLASH, PHP & DATENBANK 327 XMLNode-Klasse flash.xml.XMLNode Der Speicherort wurde geändert.Diese Klasse wurde in das flash.xml-Paket verschoben. nodeType flash.xml.XMLNode.nodeType Der Datentyp wurde von Number zu uint geän- dert. XMLNode flash.xml.XMLNode.XMLNode() Der Datentyp des type-Parameters wurde von Number zu uint geändert. Tabelle 6.9: Änderungen in der XMLNode-Klasse von ActionScript 2.0 zu ActionScript 3.0 XMLSocket-Klasse flash.net.XMLSocket Diese Klasse wurde in das flash. net-Paket verschoben. XMLSocket flash.net.XMLSocket.XMLSocket() Es wurden zwei optionale Parameter zum Festlegen von Host und Port hinzugefügt. connect() flash.net.XMLSocket.connect() Der Datentyp des port- Parameters wurde in int geän- dert. onClose() flash.net.XMLSocket dispatches event:close Wurde im neuen Ereignismodell durch ein close-Ereignis ersetzt. onConnect() flash.net.XMLSocket dispatches event:connect Wurde im neuen Ereignismodell durch ein connect-Ereignis er- setzt. onData() flash.net.XMLSocket dispatches event:data Wurde im neuen Ereignismodell durch ein data-Ereignis ersetzt. onXML() Entfernt In ActionScript 3.0 wird nur das data-Ereignis ausgelöst,sodass Sie entweder E4X- oder den äl- teren XML-Parser (XMLDocument- Klasse) verwenden können.Die alte Ereignisprozedur onXML wurde nach dem Parsen des XML- Codes aufgerufen.Dies ergibt in ActionScript 3.0 keinen Sinn,weil Sie zum Parsen des XML-Codes jetzt zwischen der XML-Klasse (E4X) und der XMLDocument- Klasse (ältere Version) wählen können. Tabelle 6.10: Änderungen in der XMLSocket-Klasse von ActionScript 2.0 zu ActionScript 3.0 Wie Sie aus den obigen Tabellen entnehmen können, betreffen viele Änderungen das Senden und Laden von XML-Dateien, die insgesamt in die Klasse URLLoader verscho- ben worden sind. Dementsprechend müssen wir das gesamte Prozedere des Ladens von XML-Daten in ActionScript 3.0 überdenken. Im Fall von ActionScript 3.0 verhält sich das Laden von XML-Daten folgendermaßen (diese Vorgehensweise haben wir bereits in Kapitel 6.4.1 kennengelernt): 1. Anlegen eines URLLoader-Objekts: Dieses Objekt wird in ActionScript 3.0 generell zum Laden von Daten verwendet: var myLoader:URLLoader = new URLLoader();
  • 341.
    K A PI T E L 6328 2. Anlegen eines URLRequest-Objekts zum Angeben einer Quelle: var myURL:URLRequest = new URLRequest("URL_ZUR_QUELLE"); 3. Definieren eines Eventhandler für den Fall, dass die Daten geladen wurden. Es kommt das Ereignis COMPLETE zum Einsatz: function FUNKTIONSNAME_DES_HANDLERS(myEvent:Event):void { ... } myLoader.addEventListener(Event.COMPLETE, FUNKTIONSNAME_DES_HANDLERS); Listing 6.56: Ladevorgang mit dem URLLoader- und URLRequest-Objekt 4. Ladevorgang starten basierend auf den Angaben in der URLRequest-Instanz (myURL): myLoader.load(myURL); Wenn wir diese Vorgehensweise mit der von ActionScript 2.0 vergleichen, fallen uns folgende Punkte auf: Während in ActionScript 2.0 im XML-Objekt eine eigene Methode zum Laden von Daten (XML.load) zur Verfügung stand, wird nun ein eigenes „Lade-Objekt“ URL- Loader verwendet. Dieses Objekt ist nicht auf das XML-Objekt beschränkt, sondern ist generell zum Laden von Text, Binär- oder URL-codierten Daten verwendbar. Eine genauere Beschreibung dieses Objekts finden Sie weiter oben. In ActionScript 2.0 war die zu ladende Quelle ein einfacher Parameter der load- Methode (XML.load("URL ZUR QUELLE")), in ActionScript 3.0 wird hierfür ebenfalls ein eigenes Objekt URLRequest verwendet. Entgegen dem für das bisherige XML-Objekt bereits vorhandenen Eventhandler onLoad muss in ActionScript 3.0 ein Eventhandler zugewiesen werden (addE- ventListener). Das Ereignis selbst wird aus der (Basis-)Klasse Event bezogen. Eine genaue Beschreibung der Event-Klasse finden Sie in der ActionScript 3.0- Referenz. Beim gesamten Ladevorgang in ActionScript 3.0 wurde noch kein einziges Mal ein XML- oder ähnliches Objekt ins Spiel gebracht, denn der Ladevorgang ist unabhän- gig vom Inhalt der zu ladenden Daten. Erst nach dem Ladevorgang wird entschie- den, was mit den geladenen Daten eigentlich getan werden soll. Bevor wir auf die gerade verwendeten neuen Objekte URLLoader und URLRequest zu sprechen kommen, sehen wir uns noch den weiteren Vorgang zum Auslesen der XML- Daten an. Wobei ich an dieser Stelle gleich vorausschicken möchte, dass wir in diesem ersten Beispiel beim Auswerten der XML-Daten lediglich an der Oberfläche kratzen werden – viel tiefer in die Materie gehen wir dann weiter unten im Kapitel. u u u u
  • 342.
    SERVERSEITIGER DATENAUSTAUSCH –FLASH, PHP & DATENBANK 329 Die nächsten Schritte des Ladezyklus sind: 5. Anlegen eines XML-Objekts: var myXML:XML; 6. Einlesen der XML-Daten in das XML-Objekt und Festlegen der grundlegenden Eigenschaften des XML-Objekts. Dieser Vorgang wird erst nach dem Laden durch den URLLoader durchgeführt und im Allgemeinen befindet sich dieser Teil innerhalb des Event.COMPLETE-Eventhandler: myXML = new XML(myEvent.target.data); myXML.ignoreWhitespace = true; myXML.ignoreComments = true; //Standard: true myXML.ignoreProcessingInstructions = true; //Standard: true Neben der schon bekannten Eigenschaft ignoreWhitespace (Eliminieren/ „Ignorieren“ von Zeilenumbrüchen, Leerzeichen etc.) sind die Eigenschaften igno- reComments (Eliminieren von XML-Kommentaren) und ignoreProcessingIn- structions (Ignorieren von Verarbeitungsanweisungen) hinzugekommen. Beide Eigenschaften sind standardmäßig bereits auf den Wert true gesetzt, deshalb müssen Sie diese Eigenschaften nicht noch einmal konkret auf true setzen. Jedoch wollte ich Ihnen diese Eigenschaften nicht vorenthalten, worauf ich sie kurzerhand eingebaut habe. In zukünftigen Beispielen werden wir diese Eigenschaften nicht mehr explizit auf true setzen. Fassen wir die obigen Schritte in ein Script zusammen und wenden es auf eine XML- Datei namens XML01_AS3.xml an, so erhalten wir nachfolgendes Listing. Die eingele- senen XML-Daten wandeln wir mit toXMLString in einen String um und schreiben diesen in eine TextArea statusMsg. Der Inhalt der XML-Datei entspricht demjenigen aus Listing 6.35 mit dem Unterschied, dass die kaufmännischen Und „&“ durch ent- sprechende Escape-Zeichen ersetzt wurden: ... <Firma>SYNE Marketing %26 Consulting GmbH</Firma> ... Listing 6.57: Ein kaufmännisches Und „&“ wird in URL-Codierung mit %26 angegeben. Wir bedienen uns der Funktion decodeURIComponent, um diese Escape-Zeichen wieder in die entsprechenden Zeichen rückzuwandeln. (Tipp: Schlagen Sie in der ActionScript-Referenz nach, um den Unterschied zwischen decodeURI und decodeU- RIComponent herauszufinden.) var myLoader:URLLoader = new URLLoader(); var theURL:String = "XML01_AS3.xml"; ignoreComments und ignore- Processing- Instructions
  • 343.
    K A PI T E L 6330 var myURL:URLRequest = new URLRequest(theURL); var myXML:XML; function completelyLoaded(myEvent:Event):void { myXML = new XML(myEvent.target.data); myXML.ignoreWhitespace = true; myXML.ignoreComments = true; //Standard: true myXML.ignoreProcessingInstructions = true; //Standard: true statusMsg.appendText(decodeURIComponent(myXML.toXMLString())); } myLoader.addEventListener(Event.COMPLETE, completelyLoaded); myLoader.load(myURL); Listing 6.58: XML-Verarbeitung in ActionScript 3.0. Die Funktion decodeURIComponent sorgt dafür, dass die Escape-Zeichen in normale Zeichen umgewandelt werden. Ein Screenshot liefert den Beweis der Funktionstüchtigkeit unseres Beispiels, welches Sie übrigens wie gewohnt auf der Buch-CD finden (XML01_AS3.fla): ABBILDUNG 6.47 Einlesen und Ausgeben einer XML-Quelle mittels ActionScript 3.0
  • 344.
    SERVERSEITIGER DATENAUSTAUSCH –FLASH, PHP & DATENBANK 331 „Ur“-XML in ActionScript 3.0 Falls Sie in ActionScript 3.0 entwickeln, jedoch auf die bisherige Arbeitsweise mit dem XML- Objekt aus ActionScript 2.0 nicht verzichten wollen, können Sie nach wie vor auf dieses zugrei- fen. Wie in den obigen Tabellen dargestellt, wurden sämtliche XML-Klassen in ein (extern einzu- bindendes) Paket flash.xml verschoben, wobei die aus ActionScript 2.0 bekannte XML-Klasse in XMLDocument umbenannt wurde, damit keine Kollisionen mit der neuen XML-Klasse aus ActionScript 3.0 auftreten können. Irgendwann werden Sie sich wahrscheinlich die Frage stellen, was jetzt in ActionScript 3.0 im Umgang mit XML so viel besser geworden sein soll. Bis zu diesem Zeitpunkt ist die Frage auch ganz und gar nicht unberechtigt, haben wir uns denn noch gar keine wesentlichen Änderungen angesehen. Das gehen wir jetzt an! Bisher hatten wir das „Problem“, dass die eingelesenen XML-Daten geparst werden mussten, was mitunter relativ aufwändig hatte sein können. Durch die Unterstützung von ECMAScript for XML gehört das Parsen mehr und mehr der Vergangenheit an. E4X definiert an sich eine große Menge an Klassen zur Verarbeitung von XML-Daten, von denen die Klassen XML, XMLList, QName und Namespace in ActionScript 3.0 über- nommen wurden, von denen wiederum zwei von größerem Interesse für uns sind: XML: Das XML-Objekt enthält eine Anzahl von Methoden und Eigenschaften für die Verarbeitung der geladenen XML-Daten. XMLList: Ein XMLList-Objekt ist für die Verarbeitung mehrerer XML-Objekte gedacht – es ist mehr oder weniger eine Sammlung einzelner XML-Objekte. In den meisten Fällen werden wir uns ausschließlich mit dem XML-Objekt begnügen, lediglich in Projekten mit vielen XML-Objekten gleichzeitig macht das XMLList-Objekt Sinn. Folgende XML-Datei soll uns als Quelle dienen: <?xml version="1.0" encoding="ISO-8859-1" standalone="yes" ?> <Audioplayer> <Player version="1.3" skin="2"> <Autoplay>1</Autoplay> <verwendeReihenfolge>1</verwendeReihenfolge> <Begruessungstext>Be my DJ</Begruessungstext> </Player> <Playliste> <Song pos="1" useID3="1"> <Titel>Warriors of the wasteland</Titel> <Interpret>Frankie goes to Hollywood</Interpret> <Src>WarriorsOfTheWasteland.mp3</Src> u u Warum ActionScript 3.0?
  • 345.
    K A PI T E L 6332 </Song> <Song pos="4" useID3="1"> <Titel>Be a Warrior</Titel> <Interpret>Jestofunk</Interpret> <Src>BeAWarrior.mp3</Src> </Song> </Playliste> <Playliste> <Song pos="5" useID3="0"> <Titel>Numb</Titel> <Interpret>Linkin Park</Interpret> <Src>Numb.mp3</Src> </Song> </Playliste> </Audioplayer> Listing 6.59: Diese XML-Datei ist ein wenig komplexer aufgebaut als die des vorigen Beispiels und dient uns somit als besseres Anschauungsobjekt. Lesen wir doch mal mit ActionScript 3.0 die Daten aus dem XML-Objekt aus. Das Schöne an Version 3 ist, dass man nun direkt auf die einzelnen Tags zugreifen kann. Einige Beispiele: Wir wollen auf Anhieb wissen, welche Player-Version (zu finden im Tag <Player version="1.3"...> als Attribut version) verwendet werden soll: myXML.Player.@version; Folgende Punkte möchte ich festhalten: Das Tag <Player> kann direkt angesprochen werden – es muss lediglich auf die Verschachtelung geachtet werden. (<Player> liegt in der Hierarchie direkt unter dem Root-Tag <Audioplayer>, welches durch myXML repräsentiert wird.) Der Zugriff erfolgt direkt über den Tag-Namen. Es besteht also keine Notwendigkeit mehr, mit den Eigenschaften wie firstChild usw. zu arbei- ten. Würde sich <Player> nicht an erster Stelle im Code befinden, sondern etwa am Ende des Listings (jedoch in derselben Hierarchiestufe wie jetzt), würde der Zugriff auf die gleiche Art und Weise erfolgen (lesen Sie hierzu die XML- Datei XML02a_AS3.xml in XML02_AS3.fla ein, um dies zu verifizieren): <?xml version="1.0" encoding="ISO-8859-1" standalone="yes" ?> <Audioplayer> u u u
  • 346.
    SERVERSEITIGER DATENAUSTAUSCH –FLASH, PHP & DATENBANK 333 <Playliste> ... </Playliste> <Playliste> ... </Playliste> <Player version="1.3" skin="2"> ... </Player> </Audioplayer> Listing 6.60: Die Reihenfolge von <Player> und der <Playliste>-Tags wurde vertauscht – <Player> steht nun am Ende der Liste. Ebenso kann direkt auf ein Attribut innerhalb eines Tag zugegriffen werden: Hierzu wird das „@“ mit dem darauffolgenden Attributnamen angegeben. Wir wollen wissen, welchen Titel der zweite Song der ersten Playliste hat (das wäre in unserem Fall „Be a warrior“): myXML.Playliste[0].Song[1].Titel; Der Zugriff auf die erste <Playliste>-Gruppe erfolgt wie gewohnt über das Array Playliste (sobald ein Tag mehr als nur einmal vorkommt, wird es in Form eines Arrays dargestellt), und zwar im speziellen auf den nullten Eintrag dieses Arrays: myXML.Playliste[0]. Da das Tag <Song> ein untergeordnetes Tag von <Playliste> ist, greifen wir über die Punktnotation auf diese Gruppe zu und wählen den Eintrag 1 aus: myXML.Playliste[0].Song[1]. Bleibt nur noch das Tag <Titel> abzufragen: myXML.Playliste[0].Song[1].Titel. Halten wir fest: Wie schon oben erwähnt, ist die Position eines Tag in der XML-Struktur nicht mehr von Bedeutung für das Auslesen – lediglich die Verschachtelung der Tags muss beachtet werden. Um den Wert (besser: Inhalt) eines Knotens auszulesen, muss nicht mehr wie in ActionScript 2.0 auf das erste Kind (firstChild) eines Knotens/Tag zuge- griffen und dort der nodeValue ausgelesen werden – vielmehr wird das Tag direkt angesprochen und so der Wert ermittelt. u u u u
  • 347.
    K A PI T E L 6334 Textknoten mit mehreren Textteilen In den obigen Überlegungen haben wir gesehen, dass man den Inhalt eines Knotens direkt über den Zugriff auf den Knoten erhält: XMLObjekt.Knoten liefert den Inhalt des Knotens. Sollten sich innerhalb dieses Knotens jedoch weitere Knoten befinden, so werden diese als Ganzes aus- gelesen. Sollten Sie nur auf die Textteile eines Knotens zugreifen wollen, so geschieht dies über die Methode text, also etwa: XMLObjekt.Knoten.text() liefert den gesamten Text eines Knotens zurück. Sollte dieser Text wiederum durch Knoten unterbrochen sein, so erhalten Sie ein Array an Textteilen. Ein kleines Beispiel: var myXML:XML = new XML("<p>Text 1.<br />Text 2</p>"); trace(myXML.text()[0]); //liefert "Text 1." trace(myXML.text()[1]); //liefert "Text 2" trace(myXML.text()); //liefert Text1.Text2 Da <p> der äußerste Knoten ist, wird dieser nicht explizit angegeben. Anders würde es sich verhalten, wenn <p> in ein <body> verschachtelt wäre – dann muss man das <p> explizit angeben (Thema Hierarchie): var myXML:XML = new XML("<body><p>Text 1.<br />Text 2</p></body>"); trace(myXML.p.text()[0]); //liefert "Text 1" trace(myXML.p.text()[1]); //liefert "Text 2" trace(myXML.p.text()); //liefert Text1.Text2 Weitere sehr interessante Eigenschaften sind in nachfolgender Liste zu sehen: length liefert nach wie vor die Anzahl von vorkommenden Knoten eines bestimm- ten Namens. Beispielsweise würde myXML.Playliste.length die Anzahl der vor- kommenden Tags <Playliste> liefern (in unserem Fall wäre das Ergebnis drei). Bitte beachten Sie jedoch, dass length nun eine Methode und keine Eigenschaft darstellt: myXML.Playliste.length(); //liefert: 3 Mittels zweier Punkte „..“ kann man ein bestimmtes Tag (einen bestimmten Kno- ten) in beliebiger Hierarchietiefe ansprechen: myXML..Song[2]; Diese Anfrage würde folgendes Ergebnis liefern: <Song pos="5" useID3="0"> <Titel>Numb</Titel> <Interpret>Linkin Park</Interpret> <Src>Numb.mp3</Src> </Song> Listing 6.61: Die Anfrage für den dritten Song-Knoten (Song[2] – wir beginnen ja wie gewohnt bei Null zu zählen) liefert den gesamten Inhalt dieses Knotens. Bitte vergleichen Sie die Ausgabe mit dem Inhalt der XML-Quelle aus Listing 6.59. u u
  • 348.
    SERVERSEITIGER DATENAUSTAUSCH –FLASH, PHP & DATENBANK 335 Eine sehr interessante Funktion ist eine Art „Suchfunktion“ innerhalb der XML- Daten: Über einen Vergleich kann auf bestimmte Knoten oder Attribute mit bestimmten Werten zugegriffen werden: Zugriff auf einen (beliebigen) Song-Knoten, wo das pos-Attribut den Wert 1 besitzt: myXML..Song.(@pos=="1"); Zugriff auf einen (beliebigen) Titel-Knoten mit Textinhalt gleich „Be a Warri- or“: myXML..Titel.(text()=="Be a Warrior"); Solche Vergleiche können auch (nach den bekannten Verknüpfungs- regeln) verknüpft werden: myXML..Titel.(text()=="Be a Warrior" || text()=="Numb"); u u u Ich hoffe, ich habe Ihnen das neue XML-Objekt schmackhaft machen können. Trotz aller Vorteile möchte ich an dieser Stelle trotzdem noch einmal konkret auf die Tatsa- che hinweisen, dass das Flash-Dokument nun mit ActionScript 3.0 aufgebaut werden muss, und dies bedarf schon einer gründlichen Einarbeitung in diese Sprache! Aus diesem Grund möchte ich Ihnen erneut die entsprechende Literatur zu ActionScript 3.0 ans Herz legen: Selma-Caroline und Matthias Kannengießer: ActionScript 3.0. 1. Auflage. Bonn: Addi- son-Wesley 2007, ISBN 978-3827325365 Auch ist die ActionScript 3.0-Referenz in Flash eine sehr gute Quelle und ein unschätz- bares Nachschlagewerk! ABBILDUNG 6.48 Die Ausgabe aller unserer Anweisungen in einer TextArea. XML goes ActionScript 3.0.
  • 350.
    7 AUDIO-JUKEBOX Dieses und diefolgenden Kapitel widmen sich ausschließlich der Praxis. Hier sollen Sie sehen, auf welche Arten wir uns ein Zusammenspiel von Flash und PHP vorstellen. Anwendungsbeispiele gibt es wohl wie Sand am Meer, Ideen und Vorstellungen zu Anwendungen noch viele mehr. Aus diesem Grund werden Sie auch zu diesem Buch gegriffen haben. Die serverseitige Programmierung als (hauptsächlicher) Datenlieferant auf der einen Seite, Flash als das Animations- und Multimedia-Tool auf der Clientseite. Zu den gängigsten Aufgabengebieten finden Sie im Folgenden konkret durchgeplante und durchprogrammierte Übungen. Ich habe in allen Workshops die Flash- und die PHP-Entwick- lung strikt getrennt, sodass Sie ein Optimum an Übersicht genießen können. Die Audio-Jukebox wird zunächst in ActionScript 2.0 und spä- ter in ActionScript 3.0 entwickelt. Viel Spaß beim Umsetzen und Anwenden!
  • 351.
    K A PI T E L 7338 7.1 Abfragen serverseitiger Informationen Eine Variante, sich PHP für Flash zunutze zu machen, liegt in der simplen Abfrage von Daten aus einer Datenbank oder einem Filesystem. Dieses Kapitel widmet sich genau dieser Thematik. Als konkrete Anwendungen habe ich an dieser Stelle bevorzugt an multimediale Anwendungen gedacht, da sie im Allgemeinen keine Rückgaben an den Server erfordern. 7.2 Multimediale Anwendungen Was ist Multimedia? Multimedia ist das Verwenden verschiedener Ausgabemedien zur selben Zeit. Hierzu zählt man Inhalte wie Text, Audio, Video usw. Je mehr dieser Assets zur gleichen Zeit ausgegeben werden, desto interessanter gestaltet sich die Entwicklung in Flash. Einmal ganz ehrlich – kennen Sie ein Tool, das besser für Multimedia auf Clientseite geeignet ist als Flash? Wohl kaum. 7.3 Konzept der Jukebox Als erstes Beispiel dient dabei mein persönlicher Favorit. Kaum eine andere Anwen- dung hat mir in der Verwendung wie in der Entwicklung mehr Freude bereitet. Am Anfang steht das Entwickeln eines Konzepts, also mehr oder weniger die Antwort auf die Frage: „Was soll das Tool eigentlich können?“ Hier die Anforderungen an unse- re Audio-Jukebox aus Flash-Sicht: 1. Die Audio-Jukebox soll in der Lage sein, gestreamt MP3-Dateien abzuspielen. Somit ist die erste Anforderung, dass MP3-Dateien dynamisch in Flash eingelesen werden sollen. 2. Innerhalb der Jukebox soll volle Kontrolle über das Abspielen der Songs gewährleistet sein. Dies schließt Buttons für: „Start“, „Stopp“, „Ein Song weiter“ und „Ein Song zurück“ ein. Des Weiteren muss die Lautstärke regelbar sein. 3. Die gängigen Informationen zu den Songs sollen direkt aus den ID3-Tags der MP3-Dateien ermittelt und ausgegeben werden. 4. Die Restabspielzeit zum jeweiligen Song soll ausgegeben werden. 5. Es soll eine parametergesteuerte Autostart-Möglichkeit vorhanden sein. 7.3.1 Playlist generieren Grundsätzlich stellt sich natürlich die Frage, wie Flash zu den Songs kommt, also woher die Playlist kommt bzw. wer sie generiert und wie sie eingelesen wird. Unser ID3-Tags Die ID3-Tags sind (benannte) Informationen wie „Titel“, „Interpret“, „Album“ usw., die mit der MP3-Datei gespeichert werden können. Geeignete Programme – wie auch Flash – können diese Tags auslesen.
  • 352.
    A U DI O - J U K E B O X 339 Plan soll sein, dass sämtliche in einem Verzeichnis aufgelisteten MP3-Dateien verwen- det werden. Eine auf diese Art erzeugte Playlist soll per Aufruf von Flash eine XML- Datei generieren, die Flash wiederum einliest. XML-Struktur Aus Sicht von Flash ist es vollkommen irrelevant, „wer“ (der Webdesigner in Form einer Textdatei, ein Server basierend auf PHP-Code usw.) und auf welche Art die Playlist als XML-Datei generiert wird – Hauptsache, die Struktur ist bekannt und die XML-Daten stehen zur Verfügung. Punkt eins ist also, dass die Struktur der XML- Datei feststehen muss. Abbildung 7.1 verdeutlicht, wie die Informationen an die Flash-Anwendung überge- ben werden sollen. Neben den Tags für die einzelnen Songs wird in zwei Attributen festgelegt, welches das Stammverzeichnis der Songs ist (rootDir) und ob ein Autostart – also ein automatisches Abspielen der Playlist – stattfinden soll (autostart). Wird die Variable autostart auf 0 gesetzt, so findet kein Autoplay statt, steht sie hingegen auf 1, erfolgt das Abspielen der Playlist automatisch. Flash-Datei vorbereiten Gehen wir’s an. Zunächst gliedern wir die Flash-Datei in drei gedachte Bereiche: Im ersten Bereich soll das Laden der XML-Daten erfolgen. Der zweite Bereich ist dafür gedacht, dem User eine Fehlermeldung auszugeben, sollte das Laden der XML-Daten nach einer gewissen Zahl von Wiederholungen nicht möglich gewesen sein. Der dritte Bereich stellt die eigentliche Jukebox dar. Dort befinden sich die Abspiel- steuerung und die Informationsdarstellung der MP3-Daten. u u u ABBILDUNG 7.1 Auf diese Art und Weise wer- den die MP3-Informationen an die Flash-Datei überge- ben. XML is on its way.
  • 353.
    K A PI T E L 7340 7.4 Jukebox in ActionScript 2.0 Nachdem diese Vorkehrungen getroffen sind, konzentrieren wir uns nun wirklich auf das Programmieren. Zunächst muss definiert werden, aus welcher Datei die Playlist geladen werden soll – hierzu bedienen wir uns einer Stringvariablen namens mySource, die den Namen (oder auch eine komplette URL inklusive eventueller Unterverzeich- nisse) der Playlist-Datei speichert. Des Weiteren legen wir – wie auch schon in den Theoriekapiteln gezeigt – in einer Variable maxLadeversuche eine gewisse Anzahl an Ladeversuchen fest, sollte das Laden der Daten nicht beim ersten Mal klappen. Hierzu muss in weiteren Variablen mitgezählt werden, wie viele Ladeversuche bereits vorge- nommen wurden. Dies übernimmt die Variable anzLadeversuche. var anzLadeversuche:Number = 0; var maxLadeversuche:Number = 3; var mySource:String = "playlist.php"; Listing 7.1: Die ersten drei wichtigen Variablen für die mitgezählte Anzahl an Ladeversuchen (anzLade- versuche), die maximale Anzahl an Ladeversuchen (maxLadeversuche) und die URL zur Playlist-Datei (mySource) sind somit angelegt. Neben den oben angeführten Variablen werden wir im Weiteren noch einige zusätz- liche globale Variablen benötigen, nämlich ein Array, das alle unsere eingelesenen Songs speichert (theSongs), zwei Variablen für die Ausgabe von Informationen zu den Songs in dynamischen Textfeldern (theSongInfo1, theSongInfo2) sowie eine Variable für die Darstellung der verbleibenden Abspielzeit, ebenfalls in einem dyna- mischen Textfeld (theTimeInfo). var theSongs:Array = new Array(); var songTitel:String = "loading Playlist..."; var songInterpret:String = ""; var songAlbum:String = ""; var theTimeInfo:String = "--:--"; Listing 7.2: Anlegen einiger wesentlicher Variablen, die wir für den weiteren Ablauf der Jukebox benötigen werden Natürlich müssen die Variablen songTitel, songInterpret, songAlbum und the- TimeInfo nicht notwendigerweise genau zu diesem Zeitpunkt angelegt werden. Dies empfiehlt sich jedoch, da man (als guter Programmierer) davon ausgehen kann, dass man bis zum Abspielen der Songs kommt und somit diese Variablen auch benötigen wird.
  • 354.
    A U DI O - J U K E B O X 341 7.4.1 XML-Daten laden Nun kümmern wir uns darum, dass die XML-Daten geladen werden können. Das Flash-Objekt XML wird diese Aufgabe für uns erledigen. Obwohl wir keine leeren Textknoten zu erwarten haben, ist das Setzen der Eigenschaft ignoreWhite des XML- Objekts auf den Wert true eine gute Wahl, denn so kann diese mögliche Fehlerquelle ausgeschlossen werden. var myLoader:XML = new XML(); myLoader.ignoreWhite = true; myLoader.load(mySource); Listing 7.3: Es wird ein neues XML-Objekt erzeugt, die Eigenschaft ignoreWhite auf true gesetzt und von der zuvor definierten URL (mySource) werden XML-Daten eingelesen. Über das Ereignis onLoad des XML-Objekts wird signalisiert, dass das Laden der Daten abgeschlossen ist. Dies bedeutet aber noch nicht, dass das Laden auch erfolgreich war. Das erfolgreiche Laden signalisiert erst die Eigenschaft loaded. Dies bedeutet für uns, dass wir zunächst das Ereignis onLoad auswerten (wir erzeugen eine sogenannte Ereig- nisroutine oder Ereignisprozedur) und danach abprüfen müssen, ob die Eigenschaft loaded auf true gesetzt ist. Sollte dem nicht so sein, wird ein erneuter Ladeversuch gestartet. Das Definieren der Ereignisroutine muss kein zweites Mal vorgenommen werden, da beim erneuten Ladeversuch dasselbe XML-Objekt ein weiteres Mal verwen- det wird. In jedem Fall wird die Variable anzLadeversuche um eins erhöht. myLoader.onLoad = function():Void { anzLadeversuche++; if(myLoader.loaded) { //Hier folgt das Auslesen der Attribute und Tags. //Der Code wird weiter unten erläutert. } else { if(anzLadeversuche<maxLadeversuche) { myLoader.load(mySource); } else { //Code, falls Anzahl der Ladeversuche erreicht ist } } } Listing 7.4: Die Ereignisbehandlungsroutine wertet die Daten bei erfolgreichem Laden aus, bei nicht erfolgreichem Laden wird – sofern die Maximalanzahl an Ladeversuchen noch nicht erreicht ist (also anzLadeversuche<maxLadeversuche) – ein erneuter Ladeversuch gestartet. Ansonsten müssen wir uns etwas einfallen lassen. onLoad versus loaded onLoad versus loaded
  • 355.
    K A PI T E L 7342 Attribute speichern War das Laden erfolgreich (und davon gehen wir einmal aus), werden zunächst alle im zweiten Tag (<Playlist>; siehe Abbildung 7.1) vorkommenden Attribute als globale Variablen gespeichert. Eine for..in-Schleife empfiehlt sich hier: Alle im Objekt attributes vorkom- menden Eigenschaften (hier: Variablen) werden ausgelesen und durch die Funktion _global in die Kollektion der globalen Variablen übernommen. Danach werden alle folgenden Tags angesprochen und das Attribut src wird aus- gelesen. In diesem befinden sich die Namen der MP3-Dateien. Vergleicht man den nachfolgenden Code mit der Abbildung der einzulesenden XML-Datei, so sieht man, dass das erste Child <Playlist> des Hauptknotens <?xml> eine gewisse Anzahl wei- terer Child-Knoten umfasst (die Tags <song>). Wie viele es sind, lässt sich über die Eigenschaft length dieser childNodes-Sammlung herausfinden. Diese Information verpackt man in eine for-Schleife, liest Zug um Zug jedes Tag und dessen Attribut src aus und speichert die ermittelten Werte im globalen Array theSongs. Ist dieser Schritt vollzogen, ist sämtliches Einlesen der XML-Daten abgeschlossen und es kann mit dem weiteren Gang der Jukebox fortgefahren werden. //Dieses Code-Fragment wird an oben erwähnter Stelle eingefügt for(itm in myLoader.firstChild.attributes) { _global[itm] = myLoader.firstChild.attributes[itm]; } for(var i:Number=0; i<myLoader.firstChild.childNodes.length; i++) { theSongs[i] = myLoader.firstChild.childNodes[i].attributes.src; } Listing 7.5: Das Auswerten und Speichern der eingelesenen Daten erfolgt in diesem Codefragment. Sobald dieses Prozedere abgeschlossen ist, ist der wesentlichste Schritt getan und es kann mit dem Abspielen der Songs begonnen werden. Für den Fall, dass der Ladevorgang nicht erfolgreich beendet werden konnte und auch die weiteren Ladeversuche zu keinem positiven Ergebnis geführt haben, wird ein MovieClip eingeblendet, der eine entsprechende Fehlermeldung auf den Bildschirm ausgibt. Ob Sie hier nun dem User die Meldung ausgeben, dass das Laden nicht geklappt hat, oder zusätzlich einen Button einfügen, der bei Klick einen neuerlichen Ladezyklus einleitet, hängt von Ihrem persönlichen Geschmack ab. Wir sind der Ansicht, dass sofern drei Ladeversuche fehlgeschlagen sind, ein weiterer Ladezyklus auch keinen Sinn mehr macht. Natürlich ist es aber Ihnen überlassen, ob Sie diese Möglichkeit in Betracht ziehen wollen oder nicht. Ich habe mich für die Variante „Fehlermeldung & Buttons zum Neuladen“ entschie- den, die wie folgt aussehen könnte:
  • 356.
    A U DI O - J U K E B O X 343 Hierzu legt man einen MovieClip mcError an, der zwei Buttons (btnNein, btnJa) beinhaltet, und platziert ihn der Einfachheit halber neben der Bühne (quasi im unsichtbaren Bereich – siehe Abbildung 7.3). Um den MovieClip mcError gleich „am richtigen Platz“ zu haben, sollte er eingeblendet werden müssen, fügt man folgenden Code in der Aktionenebene ein: mcError._visible = false; mcError._x = 0; mcError._y = 0; ABBILDUNG 7.2 Der User erhält eine Fehlermeldung sowie die Möglichkeit, den Ladevorgang erneut einzuleiten. ABBILDUNG 7.3 Der MovieClip mcError wird im unsichtbaren Bereich neben der Bühne platziert. Sollte die Anzahl der Ladeversuche erreicht sein (siehe Listing 7.4), fügt man folgenden Code ein:
  • 357.
    K A PI T E L 7344 ... if(anzLadeversuche<maxLadeversuche) { myLoader.load(mySource); } else { mcError._visible = true; } ... Listing 7.6: Die Zeile mcError._visible = true; wird dem Code aus Listing 7.4 hinzugefügt. Nun verschaffen wir den beiden Buttons noch etwas „Intelligenz“, indem wir Ihnen den Code zuweisen, den sie auslösen sollen: mcError.btnNein.onRelease = function():Void { _root.mcError._visible = false; _root.songTitel = "ERROR WHILE LOADING PLAYLIST"; } mcError.btnJa.onRelease = function():Void { _root.myLoader.load(mySource); _root.mcError._visible = false; } Listing 7.7: Die Eventhandler der Buttons btnNein und btnJa Wird der Nein-Button geklickt, blenden wir den MovieClip mcError aus und geben in den Textfeldern eine Fehlermeldung aus, im Fall des Ja-Buttons wird zusätzlich noch der Ladevorgang erneut gestartet. 7.4.2 Abspielen der Songs Befassen wir uns also nun mit dem wichtigen Thema des Abspielens der Songs. An dieser Stelle ist wieder etwas Konzept vonnöten. Überlegen wir uns, wie das Anwenden der Jukebox vonstatten gehen soll: 1. ÜberdieglobaleVariableautostart wirdentschieden,obderersteSongabgespielt oder auf das Klicken des Play-Buttons durch den User gewartet werden soll. 2. Mithilfe der Buttons „Start“, „Stopp“, „Ein Song vor“, „Ein Song zurück“ soll man die Playlist abspielen und stoppen können. Des Weiteren wären kleine Icons (eines für jeden Song) nett, die bei Klick den Song gleich direkt aufrufen und abspielen. 3. Ein Lautstärkeregler muss ebenso vorhanden sein wie zwei Informationsfelder, eines zum abgespielten Song und eines zum Darstellen der verbleibenden Abspielzeit. So weit der Plan. Programmiertechnisch ergeben sich hieraus vorerst einige wesent- liche Konsequenzen:
  • 358.
    A U DI O - J U K E B O X 345 1. Klarerweise wird ein Soundobjekt benötigt, um überhaupt Songs abspielen zu können. 2. In jedem Fall müssen wir uns merken, der wievielte Song aus unserer Songliste des Arrays theSongs zu einem gewissen Zeitpunkt abgespielt wird. Hierfür werden wir eine Variable actualSong verwenden, die auf den Index des Arrays theSongs zeigt. Variablen für die Jukebox Die beiden Punkte werden uns die wenigsten Kopfschmerzen bereiten, sind sie doch mit wenigen Zeilen erledigt. var mySong:Sound = new Sound(); var actualSong:Number = 0; Listing 7.8: Anlegen der beiden Variablen mySong (Soundobjekt) und actualSong im Bild Ladevor- gangErfolgreich in der Ebene „Aktionen“ Autostart der Songs Widmen wir uns wieder den einfacheren Aufgaben, nämlich dem Auswerten der autostart-Variable. Wie schon weiter oben angesprochen, wird im Fall von auto- start==1 der erste Song (entspricht dem Wert von actualSong) abgespielt, indem die Funktion playSong aufgerufen wird. Auf diese Funktion wird weiter unten einge- gangen. Ansonsten wird im oberen der beiden dynamischen Textfelder der Text „press the PLAY-Button to play songs …“ ausgegeben. Das zweite Textfeld bleibt nach wie vor leer. Um diesen Vorgang in Gang zu setzen, muss zunächst in Listing 7.5 nach dem Auslesen der XML-Daten der Aufruf der Funktion initPlayer eingefügt werden: initPlayer(); Diese Funktion erledigt dann die oben genannten Aufgaben: function initPlayer():Void { if(parseInt(autostart)==1) { playSong(0); } else { theSongInfo1 = "(press the PLAY-Button to play songs...)"; } } Listing 7.9: Die if-Bedingung entscheidet über autostart==1 darüber, ob der erste Song abgespielt wird oder ob bei autostart!=1 gewartet und eine entsprechende Meldung übergeben werden soll.
  • 359.
    K A PI T E L 7346 Hauptfunktion der Jukebox: playSong() Wenden wir uns nun der Funktion playSong zu, die einen wesentlichen Bestandteil der Jukebox darstellt. Wie bereits im letzten Listing gezeigt, wird an diese Funktion ein noch nicht näher beschriebener Parameter übergeben. Dieser Parameter wird verwen- det, um genau um den Wert dieses Parameters in der Liste der Songs weiterzuspringen. Dabei kann dieser Parameter drei Werte annehmen, wie Sie der nachfolgenden Tabelle entnehmen können: Wert Bedeutung 0 Zum aktuellen Songindex (actualSong) wird der Wert 0 hinzugezählt und dieser Song abge- spielt.Dies bedeutet also nichts anderes,als dass der aktuelle Song erneut abgespielt wird. 1 Zum aktuellen Songindex (actualSong) wird der Wert 1 hinzugezählt und dieser Song abge- spielt.Es wird demnach in der Liste der Songs (theSongs) um einen Song weitergesprungen. Was geschehen soll,wenn das Ende der Liste erreicht ist,muss noch definiert werden. -1 Zum aktuellen Songindex (actualSong) wird der Wert -1 hinzugezählt und dieser Song ab- gespielt.Es wird demnach in der Liste der Songs (theSongs) um einen Song zurückgesprun- gen.Was geschehen soll,wenn der Anfang der Liste erreicht ist,muss noch definiert werden. Tabelle 7.1: Mögliche Übergabewerteparameter der playSong-Funktion Anfang und Ende der Playlist Innerhalb der Funktion playSong wird der Parameter als numerische Variable mit dem Namen dir (für „direction“ – Richtung) geführt. Was soll nun geschehen, wenn entweder das Ende oder der Anfang der Songliste überschritten wird? Wir haben uns entschieden, dass bei Überschreiten des Listenendes an den Anfang der Liste und bei Überschreiten des Listenanfangs an das Ende der Liste gesprungen werden soll. Das Überschreiten des Listenendes erkennt man daran, dass der Listenindex von actualSong gleich der Länge der Liste ist – die Zählung der Listeneinträge im Array beginnt ja bekanntlich bei 0. Das Überschreiten des Listenanfangs erkennt man wie- derum daran, dass der Index den Wert -1 hat: actualSong==-1. Songindex auslesen Hat die Variable actualSong schlussendlich den gewünschten Wert erhalten, kann mit dem Laden des entsprechenden Songs aus der Liste begonnen werden. Man liest hierfür aus der Playlist theSongs den Wert aus, der über den Index actual- Song definiert ist: theSongs[actualSong]. Vor diesen Eintrag hängt man noch das Stammverzeichnis der Songs und einen Slash „/“. Das Stammverzeichnis wird über die globale Variable rootDir definiert, die aus der XML-Datei eingelesen wird, und ohne schließendes „/“ angegeben. Fertig ist die URL, von der Flash die Songdatei beziehen soll. Die Methode loadSound des Soundobjekts erwartet diese URL als ersten Parameter sowie eine Kennzeichnung, ob (true) oder ob die Datei nicht (false) gestreamt geladen werden soll, als zweiten Parameter: mySong.loadSound("URL", isStreaming)
  • 360.
    A U DI O - J U K E B O X 347 Das nachfolgende Listing zeigt Ihnen einen Auszug der Funktion playSong, worin die soeben dargestellten Aufgaben erledigt werden. Das vollständige Listing wird am Ende dieses Abschnitts aufgeführt. function playSong(dir:Number) { ... actualSong += dir; if(actualSong==theSongs.length) { actualSong = 0; } if(actualSong==-1) { actualSong = theSongs.length-1; } mySong.loadSound(rootDir+"/"+theSongs[actualSong],true); ... } Listing 7.10: Codefragment zum Setzen der Variable actualSong und Laden des entsprechenden Songs aus der Playlist theSongs Zwischen zwei Songs Bevor jedoch die MP3-Datei geladen wird, sind noch ein paar „administrative“ Punkte zu regeln: 1. Zwischenzeitlich(bisderneueSonggestartetist)sollkeineRestabspielzeitangezeigt werden, sondern etwas in der Art „--:--“: theTimeInfo="--:--"; 2. Gleiches gilt auch für die zwei Informationszeilen am Display: songTitel = "getting MP3-Information..."; songInterpret = ""; songAlbum = ""; Somit erweitert sich die Funktion playSong um folgenden Code: function playSong(dir:Number):Void { theTimeInfo = "--:--"; songTitel = "getting MP3-Information..."; songInterpret = ""; songAlbum = ""; ... } Listing 7.11: Codefragment zum Erledigen der „administrativen“ Angelegenheiten.
  • 361.
    K A PI T E L 7348 Das vollständige Script zur Funktion playSong sieht somit wie folgt aus: function playSong(dir:Number):Void { theTimeInfo = "--:--"; songTitel = "getting MP3-Information..."; songAlbum = ""; songInterpret = ""; actualSong += dir; if(actualSong==theSongs.length) { actualSong = 0; } if(actualSong==-1) { actualSong = theSongs.length-1; } mySong.loadSound(rootDir+"/"+theSongs[actualSong],true); } Listing 7.12: Die Funktion playSong in all ihrer Pracht! Song beendet: nächsten Song abspielen Nun müssen wir uns noch überlegen, was zu geschehen hat, wenn der nun abgespielte Song zu Ende ist. Wir haben uns entschieden, nach einem fertig abgespielten Song ganz einfach den nächsten Song in der Liste abzuspielen. Die Methode onSoundCom- plete des Soundobjekts wird genau dann aktiv, wenn ein Song komplett wiedergege- ben wurde. Nichts ist leichter, als zu diesem Zeitpunkt den nächsten Song in der Liste abzuspielen, denn die dafür erforderliche Funktion haben wir bereits: playSong(1). Der Wert 1 als Übergabeparameter teilt der Funktion mit, dass das nächste Lied der Liste abgespielt werden soll. mySong.onSoundComplete = function() { playSong(1); } Listing 7.13: Codefragment für die Ereignisbehandlung von onSoundComplete, die direkt nach dem Anlegen der Sound-Instanz mySong definiert werden kann. Songs per Klick abspielen Neben dem Abspielen des vorigen, aktuellen oder nächsten Songs soll eventuell auch noch die Möglichkeit bestehen, einen Song direkt anzuwählen. Dafür ist unsere Funk- tion playSong jedoch nicht ausgelegt – hierzu müsste man eine eigene Funktion pro- grammieren, wo etwa die Songs in einer ComboBox aufgelistet werden. Kein Problem für uns – öffnen Sie die Datei audioplayer_03.fla von der Buch-CD – die Erklärung finden Sie weiter unten im Kapitel, da diese Variante in ActionScript 3.0 umgesetzt wurde.
  • 362.
    A U DI O - J U K E B O X 349 7.4.3 ID3-Tags auslesen Abschließend sollte man bei Auswahl eines neuen Songs natürlich auch die entspre- chenden Informationen zu ihm erhalten. Wurde beim Aufnehmen der MP3-Daten darauf geachtet, dass die Informationen zum Album mitgespeichert werden, so werden diese Informationen beim Aufnehmen mit in die MP3-Datei„verpackt“ und sind somit zu jeder Zeit verfügbar. Im Allgemeinen geschieht dies entweder durch automatisiertes Abfragen einer Datenbank (beispielsweise CDDB) durch Ihr Aufnahmeprogramm oder durch händisches Eingeben der Informationen vor der Aufnahme. Da alle gängigen Aufnahmeprogramme wie zum Beispiel iTunes von Apple oder die Jukebox von MusicMatch (Yahoo) nach diesem Verfahren arbeiten, können wir Entwickler davon ausgehen, dass auch unsere MP3-Daten diese Informationen gespeichert haben. Flash kann – wie sollte es auch anders sein – auf diese Informa- tionen zugreifen. Hierzu existiert für ein Soundobjekt das Sub-Objekt id3, dessen Eigenschaften genau die gewünschten Daten beinhaltet. Man nennt diese MP3-Infor- mationen auch die „ID3-Tags“, deshalb auch der Objektname id3. Die für uns interes- santen Eigenschaften sind in der folgenden Tabelle zusammengefasst. Eine komplette Auflistung aller Eigenschaften finden Sie in der ActionScript-Referenz, die Sie von der Macromedia-Site downloaden können: http://www.macromedia.com/support/ documentation/de/flash/. Alternativ dazu könnte man natürlich die notwen- digen Informationen zum Song in die XML-Datei aufnehmen, da man – möchte man absolut sichergehen – nicht zu 100% davon ausgehen kann, dass die ID3-Tags wirklich in der MP3-Datei gespeichert sind. Tag Enthaltene Information id3.artist Name des Interpreten id3.songname Songtitel id3.album Name des Albums id3.TLEN Länge des Songs (in Millisekunden) Tabelle 7.2: Auflistung der für unsere Jukebox interessanten Eigenschaften des id3-Objekts der Version 1 Neben den hier dargestellten id3-Tags existieren noch weitere, die einer neueren Generation angehören. Sie sind in Flash unter der Bezeichnung id3 Version 2 zu finden – genauere Informationen hierzu entnehmen Sie bitte der Flash-Referenz. In der ersten Zeile des Displays sollen die Informationen zum Titel in Zeile 2 und in Zeile 3 die Infos zu Interpret und dem Albumtitel stehen. Wie diese Informationen in die dynamischen Textfelder gelangen, wird hier nicht gesondert erläutert. Sollten Sie dazu Fragen haben, schauen Sie sich den Code am besten direkt in der fla-Datei von der Buch-CD an.
  • 363.
    K A PI T E L 7350 Da die ID3-Informationen nicht sofort zur Verfügung stehen, sondern erst dann, wenn ein gewisser Teil der MP3-Datei geladen ist, müssen wir ein Ereignis abwarten, das uns das Vorhandensein dieser Informationen anzeigt: onID3. mySong.onID3 = function():Void { songInterpret = mySong.id3.artist; songAlbum = mySong.id3.album; songTitel = mySong.id3.songname; showTimer(Math.floor(mySong.id3.TLEN/1000)); } Listing 7.14: Codefragment zum Einlesen und Ausgeben der ID3-Informationen Restspielzeit anzeigen Die Darstellung der Restspielzeit gestaltet sich dabei auch etwas aufwändiger – hier werden wir eine eigene Funktion aufrufen, in der wir mit einem Intervall arbeiten. Dieser Funktion (showTimer) übergeben wir primär die Länge des Songs in Sekun- den, weshalb eine Division durch 1000 und eine Rundung des Ergebnisses erforderlich ist. Alles weitere passiert dann innerhalb dieser Funktion. Idealerweise realisiert man dies mithilfe der Methode setInterval. Wie in der Funk- tion playSong ersichtlich, wird in der Ereignisbehandlungsroutine des Ereignisses onID3 die Funktion showTimer wie folgt aufgerufen: showTimer(Math.floor(mySong.id3.TLEN/1000)); Der Übergabewert an showTimer ist die (abgerundete) Länge des MP3-File und wird innerhalb der Funktion in der Variable theLength gespeichert. Sobald die Funktion showTimer aufgerufen wird, wird zunächst ein (bis dato noch nicht verwendetes) Intervall gelöscht: clearInterval(itvTimer). Der Grund dafür ist, dass im Wei- teren über showTimer jede Sekunde dasselbe Intervall erneut gestartet wird, das wiederum die Funktion showTimer mit einem genau um eine Sekunde verminderten Wert für den Parameter aufruft. Letzten Endes wird hier nicht die Funktionsweise des Intervalls, sondern vielmehr die eines Timers verwendet. Sollte theLength>=0 sein – also das Lied noch nicht zu Ende sein –, wird der Wert für die Restabspielzeit wie folgt berechnet: 1. Zunächst werden die Minuten ermittelt: Hierzu dividiert man die Restzeit in Sekunden durch 60 und rundet ab: theTimeInfo = "-"+Math.floor(theLength/60)+":"; Vor diesen Wert wird noch ein „–“ (Minus) gesetzt, um die Restdauer anzudeuten. Hinter den Minutenwert wird ein Doppelpunkt gesetzt.
  • 364.
    A U DI O - J U K E B O X 351 2. Danach werden die restlichen Sekunden ermittelt, indem man den Minutenwert mit 60 multipliziert und diesen Wert von den Gesamtsekunden (theLength) abzieht: theLength-60*Math.floor(theLength/60) Sollte dieser Wert kleiner als zehn sein, so sollte man der Sekundenanzeige eine Null vorsetzen („09“ wirkt besser als „9“): if(theLength-60*Math.floor(theLength/60)<10) { theTimeInfo += "0"; } DerSekundenwertwirdschlussendlichauchnochandenbeinaheschonkompletten String für die Ausgabe angehängt: theTimeInfo += theLength-60*Math.floor(theLength/60); 3. Nur zur Erinnerung: Die globale Variable theTimeInfo ist diejenige Variable, die im dynamischen Textfeld für die Restabspielzeit ausgegeben wird. Abschließend muss das Intervall nur noch erneut aufgerufen werden: itvTimer = setInterval(showTimer,1000,theLength-1); Das vollständige Listing der Funktion showTimer sieht wie folgt aus: function showTimer(theLength:Number):Void { clearInterval(itvTimer); if(theLength>=0) { theTimeInfo = "-"+Math.floor(theLength/60)+":"; if(theLength-60*Math.floor(theLength/60)<10) { theTimeInfo += "0"; } theTimeInfo += theLength-60*Math.floor(theLength/60); itvTimer = setInterval(showTimer,1000,theLength-1); } } Listing 7.15: Das vollständige Listing der Funktion showTimer 7.4.4 Abspielsteuerung Erfreulicherweise haben wir alle aufwändigeren Codes hinter uns gebracht und kön- nen uns nun einer einfacheren Funktion widmen: der Funktion stopSound, die für das Stoppen eines gerade abgespielten Songs verantwortlich ist. Dies geschieht über die einfache Methode stop() des Soundobjekts: mySong.stop();. Gleichzeitig mit dem Stoppen des Songs müssen noch zwei weitere Aufgaben erledigt werden: Das laufende Intervall muss gelöscht werden: clearInterval(itvTimer);
  • 365.
    K A PI T E L 7352 Das Display muss aktualisiert werden: theTimeInfo = "--:--"; theSongInfo1 = "(stopped)"; theSongInfo2 = ""; Erledigt. Abschließend noch das Listing: function stopSong():Void { mySong.stop(); clearInterval(itvTimer); theTimeInfo = "--:--"; songTitel = "(stopped)"; songInterpret = ""; songAlbum = ""; } Listing 7.16: Code der Funktion stopSong Kommen wir zu den Buttons, also der Abspielsteuerung unserer Jukebox. Sie werden sehen, dass die Buttons mit Sicherheit die einfachste Aufgabe darstellen: Button „Play“: btnPlay.onRelease = function():Void { playSong(0); } Button „Stopp“: btnStop.onRelease = function():Void { stopSong(); } Button „Ein Song zurück“: btnRWD.onRelease = function():Void { playSong(-1); } Button „Ein Song vor“: btnFWD.onRelease = function:Void { playSong(1); } u u u u
  • 366.
    A U DI O - J U K E B O X 353 7.4.5 Lautstärkeregler Sie denken, wir hätten damit das Ende erreicht? Beinahe. Bleibt einzig noch der Laut- stärkeregler, der eigentlich ganz simpel zu programmieren ist. Aber zunächst einige Gedanken zur Funktionsweise: 1. Durch Klicken auf die Spur des Reglers soll die Lautstärke auf den entsprechenden Wert gesetzt werden. 2. Die Lautstärke soll mit der Maus per Drag&Drop gesetzt werden können, wobei sich während des Ziehens die Lautstärke kontinuierlich verändern soll. Diese aufgelisteten Punkte werden uns zum Ende hin noch einmal ein wenig schwitzen lassen, aber dafür haben wir es dann geschafft – zumindest in Flash. ABBILDUNG 7.4 Der Lautstärkeregler ist ein eigenes Symbol in der Bibliothek, ebenso wie die Spur & Maske des Reglers (MovieClip). Das Symbol ist in vier Ebenen unterteilt: Ebene „hg“: Diese beinhaltet den MovieClip mcSpur, der zu 50% transparent ist. Er dient dazu, dass der User beim Verstellen der Lautstärke immer noch weiß, wie hoch er die Lautstärke stellen kann. Des Weiteren werden wir die Spur dafür ver- wenden, dass der User auf diese klicken und somit die Lautstärke verstellen kann. Ebene „Text“: Diese beinhaltet lediglich den Text „VOL“. Ebene „Items“: Sie beherbergt die zehn blauen Striche, die zur symbolhaften Dar- stellung der Lautstärke dienen. Ebene „Maske“: Sie legt fest, wie viel der Ebene „Items“ angezeigt wird. Als Maske wird derselbe MovieClip verwendet wie für die Spur (mcLautstaerkeMaske in der Bibliothek), da diese sowieso nie sichtbar sein wird. u u u u
  • 367.
    K A PI T E L 7354 In der Listener-Ebene auf der Hauptbühne platzieren wir den Code, der beim Drücken und Loslassen der Maustaste über dem Lautstärkeregler ausgeführt werden soll: var itvLautstaerke; mcLautstaerke.mcSpur.onPress = function():Void { itvLautstaerke = setInterval(setLautstaerke,50); } mcLautstaerke.mcSpur.onRelease = function():Void { clearInterval(itvLautstaerke); } mcLautstaerke.mcSpur.onReleaseOutside = function():Void { clearInterval(itvLautstaerke); } Listing 7.17: Der Code für die Lautstärkesteuerung ist relativ einfach, sehen wir einmal von der noch nicht definierten Funktion setLautstaerke ab. Die Variable itvLautstaerke wird für ein Intervall verwendet, auf das wir später noch zu sprechen kommen. Interessanter wird es schon, wenn wir die Funktionenebe- ne etwas näher betrachten: function setLautstaerke():Void { var mousex:Number = mcLautstaerke._xmouse; var maxX:Number = mcLautstaerke.mcSpur._width; mcLautstaerke.mcMaske._width = mousex; mySong.setVolume(mousex/maxX*100); } Listing 7.18: In der Funktionenebene wird die Funktion setLautstaerke definiert. Sobald die Funktion setLautstaerke aufgerufen wird, wird die Position der Maus innerhalb des Lautstärkereglers ermittelt (mcLautstaerke._xmouse). Da sich die Spur an der Position (0/0) befindet, entspricht die Mausposition in x-Richtung auch direkt der zu setzenden Lautstärke. Die Variable maxX fragt die maximale Lautstärke ab, indem sie die Breite der Spur ermittelt (mcLautstaerke.mcSpur._width). Danach wird die Breite der Maske für die Lautstärke-Items (siehe Erklärung zu Abbildung 7.4) noch auf genau den Wert gesetzt, wo die Maus des Users gerade steht. Abschließend errechnen wir aus Mausposition und maximaler Lautstärke die tatsächliche Lautstärke für den Song (in Prozent von 0–100) und weisen diese der Soundinstanz mySong zu (mousex/maxX*100). Sprechen wir noch kurz über das Intervall itvLautstaerke. Das Problem mit einer Lautstärkeregelung in dieser Art und Weise ist, dass der Ablauf wie folgt sein soll:
  • 368.
    A U DI O - J U K E B O X 355 1. Sobald der User auf den Lautstärkeregler klickt und die Maus noch gedrückt hält, soll die Lautstärke gesetzt werden – auch wenn der User dabei die Maus bewegt. Da das auftretende Ereignis das Ereignis onPress ist und dieses nur einmal auftritt (nämlich beim Hinunterdrücken der Maustaste), könnte die Lautstärke auch nur zu diesem Zeitpunkt gesetzt werden,unabhängig davon,wie lange er die Maustaste unten hält. 2. Beim Loslassen der Maustaste (innerhalb oder außerhalb des Reglers) soll das Setzen der Lautstärke wieder beendet werden. Die möglichen auftretenden Ereignisse nennen sich onRelease und onReleaseOutside – auch diese beiden treten nur einmal auf, was uns jedoch nicht behindert. Der Ausweg aus der im ersten Punkt dargestellten Problematik ist, dass sobald der User die Maustaste nach unten drückt, ein Intervall itvLautstaerke startet, das in regel- mäßigen Abständen (bei uns sind das 50 Millisekunden – entspricht einer Framerate von 20 Bildern pro Sekunde: 1/20 Sekunde pro Bild) die Lautstärke setzt (über den Aufruf der Funktion setLautstaerke). Beim Loslassen der Maustaste muss dieses Intervall nur noch wieder gelöscht werden. 7.5 Der PHP-Part Nun geht’s endlich mit der PHP-Programmierung los. Unser Ziel ist es, alle MP3- Dateien eines bestimmten Verzeichnisses unseres Webservers auszulesen und diese Daten in XML-Form an Flash zu übergeben. Sie werden sehen, dass dies auf einfache Art und Weise zu realisieren ist. Zuerst müssen wir natürlich eine PHP-Datei erstellen. Der Name wird uns in diesem Fall von Flash vorgegeben, da beim Einlesen der XML-Datei die Datei playlist.php gewünscht wird. Somit nennen wir unsere Datei auch entsprechend „playlist.php“. Sofern Sie noch keinen Ordner mit MP3-Dateien auf Ihrem Server erstellt haben, sollten Sie das jetzt tun. Erstellen Sie den Ordner im gleichen Verzeichnis wie die Flash- Datei und nennen Sie ihn „songs“. Zur Sicherheit sollten Sie bei der Benennung der Files auf Leer- und Sonderzeichen verzichten. So weit, so gut. Um in unserer Programmierung flexibel zu bleiben, speichern wir den Ordner der MP3-Files und auch die Einstellung für den Autostart in jeweils einer eigenen Variable ab. Würde sich später der Ordnername ändern, müssten wir bloß den Wert der Variable korrigieren und nicht an jeder Stelle im Skript, an der auf den Ordner verwiesen wird. if(!isset($_GET["dir"])) { $dir = "songs"; } else { $dir = $_GET["dir"]; } if(!isset($_GET["autostart"]) || is_nan($_GET["autostart"])) { $autostart = 0; } else { $autostart = $_GET["autostart"]; } Listing 7.19: Anlegen der Variablen für den MP3-Ordner ($dir) und den Wert von $autostart
  • 369.
    K A PI T E L 7356 Wie Sie sehen, kann per GET sowohl das auszulesende Verzeichnis der MP3-Files ($_GET["dir"]) als auch die Info über ein Autostart ($_GET["autostart"]) an die Datei übergeben werden, was unser Script sehr flexibel macht. Verzeichnis auslesen Um an die Dateien eines Verzeichnisses zu kommen und diese auszulesen, benötigen wir insgesamt drei PHP-Funktionen. opendir(): Mit der Funktion opendir() können wir den gewünschten Ordner öffnen. Diese Funktion erfordert nur den Pfad zum Ordner und logischerweise auch den Ordernamen selbst. readdir(): Mit readdir() können wir immer eine Datei des geöffneten Ordners auslesen. Um alle Files nacheinander auszulesen, werden wir uns einer Schleife bedienen. Auch readdir() benötigt allein den Pfad zum Ordner und den Ord- nernamen. closdir(): Diese Funktion ist notwendig, um das geöffnete Verzeichnis wieder zu schließen. Da wir nun die notwendigen PHP-Funktionen kennen, ist es nicht mehr schwer, unse- re MP3-Files auszulesen. Zuerst öffnen wir das benötigte Verzeichnis mit opendir(). Als Parameter geben wir einfach die Variable $dir aus Listing 7.19 an, da in dieser ja der Ordnername, in unserem Fall „songs“, gespeichert wurde. $verz = opendir($dir); Zur Erinnerung schauen wir uns noch einmal die gewünschte XML-Struktur an, die Flash benötigt. <Playlist rootDir="Verzeichnis" autostart="0"> <song src="MP3-Filename"></song> ... </Playlist> Listing 7.20: Die notwendige XML-Struktur, die es zu erzeugen gilt Bei Betrachten des ersten Knotens sehen Sie, dass wir mit diesem bereits alle notwen- digen Informationen angeben, also den Pfad zum Ordner, den Ordnernamen und den Wert für Autostart. Um später eine korrekte XML-Struktur mit der richtigen Forma- tierung erstellen zu können, speichern wir unsere Knoten in einer Variable $playlist. Diese Variable werden wir schlussendlich per echo in das Dokument ausgeben.. $playlist = ‚<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>'; $playlist.= ‚<Playlist rootDir="'.$dir.'" autostart="'.$autostart.'">'; Listing 7.21: Erstellen der XML-Definition des Dokuments sowie des ersten Knotens <Playlist> u u u
  • 370.
    A U DI O - J U K E B O X 357 Als Nächstes müssen wir die MP3-Files aus unserem Ordner auslesen. Dazu bedienen wir uns der PHP-Funktion readdir(), mit der man immer eine Datei eines bestimm- ten Ordners auslesen kann. Um alle Dateien des Ordners auslesen zu können, werden wir eine while-Schleife nutzen. Die Funktion readdir() gibt den booleschen Wert true zurück, wenn das Lesen im Verzeichnis erfolgreich war. In unserer while-Schleife soll der Knoten song so lange erstellt werden, wie Dateien im Ordner „songs“ gefunden werden. Die gefundenen Dateien speichern wir in der Variable $file ab. while($file = readdir($verz)) { ... } Daten prüfen Ein guter Programmierer sollte immer alle notwendigen Daten überprüfen. In unserem Fall möchten wir nur Dateien vom Typ .mp3 in unsere XML-Struktur auf- nehmen. Somit müssen wir zum einen kontrollieren, ob es sich generell um eine Datei (und keinen weiteren Ordner) handelt und ob diese vom Typ .mp3 ist. Dazu bietet uns PHP wieder Funktionen, die wir direkt nutzen können. is_dir(): Mit is_dir() prüfen wir, ob es sich um ein Verzeichnis handelt. In unserem Fall werden wir diese Abfrage negieren, da wir wissen wollen, ob es sich nicht um einen weiteren Ordner handelt. substr(): Diese Funktion gehört zu den Zeichenkettenfunktionen. substr() erwartet einen String und einen Startwert (Position im String), ab dem der Teilst- ring erzeugt werden soll. Als Rückgabe wird der restliche String ab dem definierten Startwert zurückgeben. Um die Zählung von hinten beginnen zu lassen, wird ein- fach der Startwert negativ gesetzt. Somit ergibt sich folgender Code für die Abfrage: if(!is_dir($file) && (substr($file,-3)=="mp3")) Innerhalb der Abfrage erweitern wir die bereits vorhandene Variable $playlist um die eingelesene Datei: $playlist .= ‚<song src="'.$file.'" />'; Nachdem wir nun alle MP3-Files aus dem Ordner „songs“ gelesen haben, schließen wir außerhalb der while-Schleife den geöffneten Ordner wieder. closedir($verz); Abschließend wird das geöffnete <Playlist>-Tag wieder geschlossen, der Inhalt in eine UTF8-kodierte Form gebracht (sollte das nicht gewünscht sein, so entfernen Sie diese Zeile einfach aus Ihrem Script) und $playlist per echo ausgegeben: u u
  • 371.
    K A PI T E L 7358 $playlist .= ‚</Playlist>'; $playlist = utf8_encode($playlist); echo($playlist); Das vollständige Skript sollte nun so aussehen: if(!isset($_GET["dir"])) { $dir = "songs"; } else { $dir = $_GET["dir"]; } if(!isset($_GET["autostart"]) || is_nan($_GET["autostart"])) { $autostart = 0; } else { $autostart = $_GET["autostart"]; } $verz = opendir($dir); $playlist = '<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>'; $playlist.= '<Playlist rootDir="'.$dir.'" autostart="'.$autostart.'">'; while($file = readdir($verz)) { if(!is_dir($file) && (substr($file,-3)=="mp3")) { $playlist .= '<song src="'.$file.'" />'; } } closedir($verz); $playlist .= ‚</Playlist>'; $playlist = utf8_encode($playlist); echo($playlist); Listing 7.22: Erstellen der XML-Struktur durch Auslesen der MP3-Files aus einem gegebenen Ordner Um die Jukebox zu testen, müsste die PHP-Datei in einer Serverumgebung (wie etwa dem XAMPP-Server oder online) getestet werden. Hierzu laden Sie die Datei inklusive der MP3-Dateien im angegebenen Ordner in das Verzeichnis, das Sie bei der Installa- tion als Root-Verzeichnis angegeben haben, und rufen Sie die php-Datei im Browser auf:
  • 372.
    A U DI O - J U K E B O X 359 7.6 Jukebox in ActionScript 3.0 In Kapitel 7.4 wurde die Jukebox in ActionScript 2.0 entwickelt – nun wenden wir uns ActionScript 3.0 zu und werden sehen, an welchen Stellen der Code (eventuell grundlegend) verändert werden muss. Idealerweise nehmen Sie sich die Datei audio- player_01.fla von der Buch-CD zur Hand und verfolgen dort die Änderungen. 7.6.1 Allgemeine Änderungen Ein wesentlicher Unterschied von ActionScript 2.0 auf ActionScript 3.0 ist die geän- derte Schreibweise des reservierten Worts VOID: ActionScript 2.0: VOID wird mit einem großen Anfangsbuchstaben geschrieben: Void. ActionScript 3.0: VOID wird mit einem kleinen Anfangsbuchstaben geschrieben: void. Dies betrifft alle unsere Funktionen ohne Rückgabewert und das sind 15 an der Zahl, die wir verteilt in den Ebenen Aktionen, Funktionen und Listener finden. Weitere Änderungen sind: Sämtliche Variablen, die innerhalb von ActionScript 3.0 Verwendung finden, müssen explizit deklariert werden – eine implizite Deklarierung ist nicht möglich. Somit müssen die Attribute autostart und rootDir, die in der XML-Datei im Tag <Playlist> verwendet werden, explizit deklariert werden. u u u ABBILDUNG 7.5 Die Erfolgsbilanz ist positiv: Der Audioplayer läuft auch im Browser ohne Probleme!
  • 373.
    K A PI T E L 7360 Ein Zugriff auf globale Variablen ist nicht mehr möglich, da es keine globalen Vari- ablen mehr gibt. Damit entfällt der Verweis auf _global komplett. Ebenso existiert der Zugriff auf _root nicht mehr – dieser lautet nun nur noch root (ohne Unterstrich am Anfang). Im Allgemeinen werden Eigenschaften eines MovieClips nun nicht mehr mit einem beginnenden Unterstrich „_“ angegeben – der Unterstrich entfällt komplett. Textfelder, die auf Variablennamen zugreifen, um so den Wert der Variable darzu- stellen, werden nicht mehr unterstützt – diese müssen nunmehr mit dem Feldna- men angesprochen werden. 7.6.2 Änderungen beim Laden der XML-Daten Da in ActionScript 3.0 ein allgemeines Objekt URLRequest in Verbindung mit URL- Loader zum Laden von Daten eingeführt wurde, läuft das Laden von XML-Daten nun auch anders ab – damit haben wir uns schon recht ausführlich im vorigen Kapitel befasst. Anstatt die load-Methode des XML-Objekts zu verwenden, wird nun mit URLLoader und URLRequest gearbeitet. Somit wird: var myLoader:XML = new XML(); myLoader.ignoreWhite = true; ... myLoader.load(mySource); zu: var myRequest:URLRequest = new URLRequest(mySource); var myLoader:URLLoader = new URLLoader(); var myXML:XML; ... myLoader.load(myRequest); Die Eigenschaftszuweisung ignoreWhite = true darf erst dann passieren, wenn der XML-Instanz wirklich XML-Daten zugewiesen wurden. Der Eventhandler, der beim vollständigen Laden der Daten aufgerufen wird, muss auch entsprechend abgeändert werden. Aus: myLoader.onLoad = function():Void { ... } wird: function EXMLComplete(myEvent:Event):void { u u u u
  • 374.
    A U DI O - J U K E B O X 361 ... } myLoader.addEventListener(Event.COMPLETE, EXMLComplete); Innerhalb des Eventhandler EXMLComplete wird nun ebenfalls auf geänderte Art und Weise auf die XML-Daten zugegriffen. Anstatt die Elemente des XML-Baums Schritt für Schritt durchzuparsen, können wir direkt auf die Elemente zugreifen. Die gesamte Funktion erhält nun folgenden Inhalt: function EXMLComplete(myEvent:Event):void { myXML = new XML(myEvent.target.data); myXML.ignoreWhite = true; autostart = parseInt(myXML.@autostart); rootDir = myXML.@rootDir; for(var i:uint=0; i<myXML.song.length(); i++) { theSongs[i] = myXML.song[i].@src; } } Listing 7.23: Die Funktion EXMLComplete (Eventhandler für das Laden von Daten) enthält nun keine Fehlerbehandlung mehr. Die Fehlerbehandlung (mehrmaliges Laden von Daten, falls der Ladeversuch fehl- geschlagen hat) ist hierin nicht mehr definiert, da die gesamte Fehlerbehandlung in ActionScript 3.0 nun anders verläuft. Ein Fehler, der am wahrscheinlichsten auftritt, ist ein IOError – diesen gilt es abzufangen: function EIOError(myEvent:IOErrorEvent):void { anzLadeversuche++; if(anzLadeversuche<maxLadeversuche) { myLoader.load(myRequest); } else { mcError.visible = true; } } myLoader.addEventListener(IOErrorEvent.IO_ERROR, EIOError); Listing 7.24: Die Funktion EIOError verarbeitet einen IOError. Bitte beachten Sie auch, dass die Eigen- schaft visible nun ohne führendem Unterstrich „_“ geschrieben wird.
  • 375.
    K A PI T E L 7362 Schaltflächenereignisse: addEventListener Da wir mit dem MovieClip mcError arbeiten und den Buttons btnJa und btnNein in diesem MovieClip release-Ereignisse zugewiesen haben, müssen wir uns noch um diese kümmern. In ActionScript 3.0 lassen sich Schaltflächenereignisse nicht mehr direkt zuweisen – vielmehr muss der Weg über addEventListener führen: Aus: var songTitel:String = "loading Playlist..."; var songInterpret:String = ""; var songAlbum:String = ""; var theTimeInfo:String = "--:--"; mcError.btnNein.onRelease = function():Void { _root.mcError._visible = false; _root.songTitel = "ERROR WHILE LOADING PLAYLIST"; } mcError.btnJa.onRelease = function():Void { _root.myLoader.load(mySource); _root.mcError._visible = false; } wird: Titel.text = "loading Playlist..."; Interpret.text = ""; Album.text = ""; Restzeit.text = "--:--"; function ENeinUp(myEvent:MouseEvent):void { mcError.visible = false; Titel.text = "ERROR WHILE LOADING PLAYLIST"; } function EJaUp(myEvent:MouseEvent):void { myLoader.load(myRequest); mcError.visible = false; } mcError.btnNein.addEventListener(MouseEvent.MOUSE_UP, ENeinUp); mcError.btnJa.addEventListener(MouseEvent.MOUSE_UP, EJaUp); Listing 7.25: ActionScript 3.0 erfordert addEventListener für die Zuweisung von Eventhandlern (auch bei Schaltflächen). addEventListe- ner nun auch für Schaltflächen addEventListe- ner nun auch für Schaltflächen
  • 376.
    A U DI O - J U K E B O X 363 Diese Vorgehensweise gilt im Übrigen selbstverständlich auch für sämtliche anderen Buttons, die wir im Audioplayer verwenden: Play, Stop, FWD, RWD. Die Variablen songTitel, songAlbum und songInterpret aus ActionScript 2.0 wurden durch den Zugriff auf die dynamischen Textfelder über deren Namen ersetzt, da der direkte Zugriff von dynamischen Textfeldern auf Variablen (zur Darstellung von deren Werten) nicht mehr möglich ist. Stattdessen greift man auf den Namen des Textfelds und dessen Eigenschaft text zu. 7.6.3 Änderungen im Soundobjekt Grundsätzlich wurde die Sound-Klasse in das Paket flash.media.Sound verschoben. Jedoch ist dies bei weitem nicht die einzige Änderung, welche die neue ActionScript- Version mit sich bringt. 1. Laden von Sounddateien: Wie in ActionScript 3.0 üblich, erfolgt das gesamte Laden von Dateien über das URLRequest-Objekt. Somit wird beim Laden von Sounddateien einem Soundobjekt beim Laden eine Instanz eines URLRequest- Objekts zugewiesen. 2. Verwenden der Sound-Klasse: Diese wird zum Laden von Sounddateien,Verwalten allgemeiner Soundeigenschaften sowie zum Starten der Soundwiedergabe verwendet. 3. Verwenden der SoundChannel-Klasse: Sobald über die Sound-Klasse eine Sounddatei abgespielt wird, wird eine neue Instanz eines SoundChannel-Objekts erzeugt. Damit wird im Weiteren die Wiedergabe gesteuert. Des Weiteren ist es nun möglich, auch gestreamte Sounds ab einer gewissen Position abspielen zu lassen – dies ermöglicht es uns, einen Pause-Button für Streaming-Sounds zu erstellen. (Dies ist in diesem Beispiel auch umgesetzt worden: Der Stop-Button wurde in einen Pause/Stop-Button umgewandelt – Details siehe weiter unten.) 7.6.4 Änderungen in der Abspielsteuerung Die Abspielsteuerung betrifft die Buttons Play, Stop, RWD und FWD. Hier sind Ände- rungen an den Eventhandlern der Buttons vorzunehmen, da die direkte Zuweisung von Ereignissen in ActionScript 3.0 nicht mehr funktioniert. Somit erhalten wir anstatt: btnPlay.onRelease = function():Void { playSong(0); } btnStop.onRelease = function():Void { stopSong(); } btnRWD.onRelease = function():Void { playSong(-1); } btnFWD.onRelease = function():Void { playSong(1); } Listing 7.26: ActionScript-2.0-Code ... Zugriff auf dyna- mische Textfelder über text Zugriff auf dyna- mische Textfelder über text
  • 377.
    K A PI T E L 7364 nun: var isPaused:Boolean = false; var isStopped:Boolean = false; var pausingPos:Number = 0; function EPlay(myEvent:MouseEvent):void { playSong(0); } function EStop(myEvent:MouseEvent):void { if(!isStopped) { if(!isPaused) { isPaused = true; pausingPos = mySoundchannel.position; } else { isPaused = false; isStopped = true; pausingPos = 0; } stopSong(); } } function ERWD(myEvent:MouseEvent):void { playSong(-1); } function EFWD(myEvent:MouseEvent):void { playSong(1); } btnPlay.addEventListener(MouseEvent.MOUSE_UP, EPlay); btnStop.addEventListener(MouseEvent.MOUSE_UP, EStop); btnFWD.addEventListener(MouseEvent.MOUSE_UP, EFWD); btnRWD.addEventListener(MouseEvent.MOUSE_UP, ERWD); Listing 7.27: ... im Gegensatz zu ActionScript-3.0-Code. Die Funktion EStop musste erweitert werden, da der Stop-Button nun zwei Funktionen (Pause und Stopp) übernehmen soll. Wie Sie sehen, nennt sich das onRelease-Ereignis nun Mouse_UP und befindet sich in der Klasse MouseEvent. In der Funktion EStop finden Sie wesentlich mehr Code als im vergleichbaren Code in ActionScript 2.0. Dies hat hauptsächlich mit zwei Dingen zu tun:
  • 378.
    A U DI O - J U K E B O X 365 1. Nachdem es in ActionScript 3.0 nun auch möglich ist, einen gestreamten Sound an einer gewissen Stelle starten zu lassen, kann ein „Pause“-Verhalten programmiert werden: Beim ersten Klick auf den Pause/Stop-Button wird der Song pausiert (bei Klick auf den Play-Button startet der Sound an der gestoppten Stelle), beim zweiten Klick wird er tatsächlich gestoppt und beginnt bei einem Klick auf den Play-Button von Neuem. 2. Da nun sowohl mit einem Sound- als auch mit einem SoundChannel-Objekt zu arbeiten ist, wird das Stoppen eines Sounds aufwändiger: Es muss einerseits (sofern der Datentransfer der Datei noch im Gange ist; betrifft die Sound- Instanz) der Datentransfer und andererseits das Abspielen des Songs (betrifft die SoundChannel-Instanz) gestoppt werden. Da nur ein laufender Transfer und nur ein gerade aktiver SoundChannel gestoppt werden kann, muss man sich – beispielsweise in Form einer Variable – „merken“, ob eben gerade abgespielt wird. Eine Alternative zu dieser Vorgehensweise ist die Variante mit try & catch, die in der Datei audioplayer_02a.fla dargestellt ist. Der Ablauf der EStop-Funktion ist also wie folgt: Sofern der Song nicht schon gestoppt ist (das wäre bei isStopped==true), wird überprüft ob der Song noch nicht pausiert ist (isPaused==false). Falls isPaused==false wird der Song „pausiert“ (natürlich wird das Abspielen komplett gestoppt, aber die Position des Abstoppens wird in der Variable pausing- Pos gespeichert). Falls isPaused==true wird der Song gestoppt (dies bedeutet, dass pausingPos=0 gesetzt wird). Wie Sie sehen, spielt die Variable pausingPos eine wesentliche Rolle: Grundsätzlich wird jeder Song über diese Variable pausingPos (Anzahl der Millisekunden ab Beginn der Sounddatei) gestartet. Aus diesem Grund muss im Fall eines tatsächlich gestoppten Sounds die Variable pausingPos den Wert 0 erhalten. Des Weiteren müssen die Funktionen playSong und stopSong entsprechend ange- passt werden: var mySound:Sound; var mySoundchannel:SoundChannel; function playSong(dir:Number):void { if(isStopped || dir!=0) { Restzeit.text = "--:--"; } Titel.text = "getting MP3-Information..."; Album.text = ""; Interpret.text = ""; u u u
  • 379.
    K A PI T E L 7366 actualSong += dir; if(actualSong==theSongs.length) { actualSong = 0; } if(actualSong==-1) { actualSong = theSongs.length-1; } isPaused = false; isStopped = false; if(dir!=0) { pausingPos = 0; } if(mySound!=null && !isStopped) { stopSong(); } myRequest.url = rootDir+"/"+theSongs[actualSong]; mySound = new Sound(); mySound.addEventListener(Event.ID3, EID3); mySoundchannel = new SoundChannel(); mySoundchannel.addEventListener(Event.SOUND_COMPLETE, ESoundComplete); mySound.load(myRequest); mySoundchannel = mySound.play(pausingPos); } function stopSong():void { mySoundchannel.stop(); if(mySound.bytesLoaded!=mySound.bytesTotal) { mySound.close(); } clearInterval(itvTimer); if(isStopped) { Restzeit.text = "--:--"; Titel.text = "(stopped)"; Interpret.text = ""; Album.text = ""; } } Listing 7.28: Die „neuen“ Funktionen playSong und stopSong
  • 380.
    A U DI O - J U K E B O X 367 Befassen wir uns zunächst mit der playSong-Funktion, welche die eingangs erzeugte Sound-Instanz mySound sowie die SoundChannel-Instanz mySoundchannel verwen- det (diese wurde – um Verwechslungen mit der ActionScript-2.0-Variante zu vermei- den – von mySong auf mySound umgetauft): Zu Beginn werden die dynamischen Textfelder „zurückgesetzt“. Danach wird der aktuell abzuspielende Song ermittelt (siehe hierzu auch die Erklä- rungen aus dem ActionScript-2.0-Teil: Listing 7.10). Da beim Aufruf dieser Funktion in jedem Fall ein Song abgespielt werden soll, werden die Variablen isPaused und isStopped auf den Wert false gesetzt: isPaused = false; isStopped = false;. Je nachdem, ob der aktuelle (dir==0) oder der nächste oder vorige Song abzuspielen ist, wird die Variable pausingPos auf 0 gesetzt, da nur im Fall des aktuellen Songs (Betätigen des Play-Buttons nach dem Betätigen des Pause/Stop-Buttons) ab einer gewissen Position abgespielt werden soll: if(dir!=0) { pausingPos = 0; }. InjedemFallmusseinderzeitabgespielterSongbeendetwerden:if(mySound!=null && !isStopped) { stopSong(); }. Da dies nur geschehen kann, wenn bereits ein Soundobjekt existiert (also ungleich null ist) und ein Stoppen nur dann Sinn macht, wenn der Song noch nicht gestoppt ist, werden diese beiden Eigenschaften bzw. Variablen zuvor abgefragt. Nun folgt der eigentlich wichtige Teil beim Arbeiten mit Sounds: Zunächst bedienen wir uns der bereits seit dem Laden der XML-Daten existen- ten URLRequest-Instanz myRequest und weisen der Eigenschaft url die URL zur Sounddatei aus dem Sound-Array zu: myRequest.url = rootDir+"/ "+theSongs[actualSong];. Danach wird eine Sound-Instanz gesetzt und dieser und der SoundChannel- Instanz ein Eventhandler (für das Ereignis ID3; Auslesen der ID3-Tags möglich) zugewiesen: mySound = new Sound(); mySound.addEventListener(Event.ID3, EID3); Zu guter Letzt wird das in der URLRequest-Instanz definierte MP3-File geladen, der SoundChannel mit dem Abspielen der Datei beauftragt und dem Sound- Channel mitgeteilt, was nach dem erfolgten Abspielen der Sounddatei gesche- hen soll (Ereignis SOUND_COMPLETE; Abspielen der Sounddatei beendet): mySound.load(myRequest); mySoundchannel = mySound.play(pausingPos); mySoundchannel.addEventListener(Event.SOUND_COMPLETE, ESoundComplete); Fassen wir noch kurz zusammen: u u u u u u u u u
  • 381.
    K A PI T E L 7368 1. Zum Laden von Daten (auch MP3-Files) wird generell das URLRequest-Objekt verwendet. 2. Das Soundobjekt erhält die Daten des URLRequest-Objekts und „verwaltet“ diese sozusagen. Im Gegensatz zu ActionScript 2.0 wird das Soundobjekt nun nicht mehr zum Abspielen des Sound-File verwendet. 3. Zum Steuern der Sounddaten wird das SoundChannel-Objekt verwendet. Bleibt noch die Funktion stopSound: Im ersten Schritt wird das Abspielen in der SoundChannel-Instanz mySoundchan- nel gestoppt: mySoundchannel.stop();. Sollte in der Soundinstanz mySound noch ein Datentransfer aktiv sein (das wäre der Fall, wenn die geladenen Bytes der MP3-Datei noch nicht den zu übertragenen Bytes entsprechen), wird dieser ebenfalls beendet: if(mySound. bytesLoaded!=mySound.bytesTotal) { mySound.close(); }. Danach wird das gerade laufende Intervall zum Anzeigen der Restzeit gestoppt: clearInterval(itvTimer);. Falls der Sound nicht pausiert, sondern gestoppt wird, werden zusätzlich noch die Textfelder zurückgesetzt. Alternative: try & catch in der Funktion stopSound function stopSong():void { try { mySoundchannel.stop(); } catch(myError:Error) { trace("SoundChannel kann nicht gestoppt werden. Error="+myError.message); } try { mySound.close(); } catch(myError:Error) { trace("Soundtransfer kann nicht geschlossen werden, da er wahrscheinlich bereits abgeschlossen ist. Error="+myError.message); } clearInterval(itvTimer); if(isStopped) { Restzeit.text = "--:--"; Titel.text = "(stopped)"; Interpret.text = ""; Album.text = ""; } } Listing 7.29: Alternative Abarbeitung der stopSound-Funktion in der Datei audioplayer_02a.fla u u u u
  • 382.
    A U DI O - J U K E B O X 369 Anstatt die SoundChannel-Instanz mySoundchannel „einfach so“ zu stoppen, wird dies mittels try versucht. Sollte der Versuch nicht klappen (was nicht tragisch wäre, sondern nur die Info, dass das Abspielen bereits gestoppt wurde), kann man im catch- Teil den Fehler ausgeben – unbedingt notwendig ist das jedoch nicht. Dasselbe Prozedere durchläuft der Versuch, die Sound-Instanz mySound in ihrer Über- tragung zu beenden. Kommen wir zum Auslesen der ID3-Tags sowie dem Timer für die Restzeitanzeige. Das Auslesen der ID3-Tags erfolgt nach wie vor im Sound-Objekt (wie in der Beschreibung der Funktion playSong beschrieben): var itvTimer:Number; function EID3(myEvent:Event):void { Interpret.text = mySound.id3.TPE1; Album.text = mySound.id3.TALB; Titel.text = mySound.id3.TIT2; itvTimer = setInterval(showTimer,1000); } function showTimer():void { var theLength:Number = Math.floor((mySound.id3.TLEN-mySoundchannel. position)/1000); var min:Number = Math.floor(theLength/60); var sek:String = ""; if(theLength-60*min<10) { sek += "0"; } sek += theLength-60*min; Restzeit.text = "-"+min+":"+sek; } Listing 7.30: Die Funktion EID3 wird zum Anzeigen der ID3-Tags einer MP3-Datei benötigt, die Funktion showTimer dient zur Anzeige der Restzeit eines abspielenden Songs. Diese beiden Funktion sind relativ straight forward: Die Funktion EID3 dient als Eventhandler und wird aufgerufen, sobald eine Sound-Instanz die ID3-Tags aus einer MP3-Datei auslesen konnte, wobei wir uns hier lediglich auf die ID3-Tags der Version 2 beziehen. Sie liest die Tags TPE1 (Inter- pret), TALB (Album) und TIT2 (Titel) der MP3-Datei aus. Sobald dies geschehen ist, wird ein Intervall gesetzt, das in regelmäßigen Abständen (alle 1000 Millisekun- den, also jede Sekunde) die Funktion showTimer aufruft. u
  • 383.
    K A PI T E L 7370 Die Funktion showTimer errechnet aus der Länge der MP3-Datei (TLEN; in Mil- lisekunden) und der aktuellen Abspielposition (mySoundchannel.position; in Millisekunden) die aktuelle Restzeit in Sekunden. Daraus werden die Minuten und die Sekunden für die Anzeige berechnet, wobei den Sekunden eine führende Null angehängt wird, sollten die Sekunden weniger als zehn sein. Zum Schluss wird aus den berechneten Werten ein String der Form „-MM:SS“ gebastelt und dem Textfeld Restzeit zugewiesen. 7.6.5 Änderungen in der Lautstärkeregelung Die letzte Änderung betrifft die Lautstärkeregelung. Da MovieClips in ActionScript 3.0 keine Button-Ereignisse mehr zugewiesen werden können, muss dem Lautstärkeregler im Design ein unsichtbarer Button hinzugefügt werden, den der User dann ankli- cken kann. Dieser Button wird die Größe der Spur des Hintergrunds haben – somit bekommt der User den Eindruck, er könnte direkt den Lautstärkeregler anklicken: u ABBILDUNG 7.6 Der Lautstärkeregler erhält einen zusätzlichen unsicht- baren Button namens btnSpur. Die Änderungen bezüglich des Lautstärkereglers ergeben sich dann wie nachfolgend. Aus: var itvLautstaerke:Number; mcLautstaerke.mcSpur.onPress = function():Void { itvLautstaerke = setInterval(setLautstaerke,50); } mcLautstaerke.mcSpur.onRelease = function():Void { clearInterval(itvLautstaerke);
  • 384.
    A U DI O - J U K E B O X 371 } mcLautstaerke.mcSpur.onReleaseOutside = function():Void { clearInterval(itvLautstaerke); } wird: var itvLautstaerke:Number; function ELautstaerkePress(myEvent:MouseEvent):void { itvLautstaerke = setInterval(setLautstaerke,50); } function ELautstaerkeRelease(myEvent:MouseEvent):void { clearInterval(itvLautstaerke); } function ELautstaerkeRollOutside(myEvent:MouseEvent):void { clearInterval(itvLautstaerke); } mcLautstaerke.btnSpur.addEventListener(MouseEvent.MOUSE_DOWN, ELautstaerkePress); mcLautstaerke.btnSpur.addEventListener(MouseEvent.MOUSE_UP, ELautstaerkeRelease); mcLautstaerke.btnSpur.addEventListener(MouseEvent.ROLL_OUT, ELautstaerkeRollOutside); Listing 7.31: Die neue Ereignisbehandlung für den Lautstärkeregler Letzten Endes hat sich lediglich der Aufruf der Eventhandler geändert, wobei uns das schon aus früheren Überlegungen bekannt ist. Da das Ereignis onReleaseOutside nicht mehr existiert, muss man auf das Ereignis ROLL_OUT zurückgreifen: Dieses Ereignis tritt auf, sobald der User mit der Maus aus einem bestimmten MovieClip herausrollt. Die Funktion setLautstaerke hat sich gegenüber der ActionScript-2.0-Variante ebenfalls deutlich geändert. Aus: function setLautstaerke():Void { var mousex:Number = mcLautstaerke._xmouse; var maxX:Number = mcLautstaerke.mcSpur._width; mcLautstaerke.mcMaske._width = mousex; mySong.setVolume(mousex/maxX*100); }
  • 385.
    K A PI T E L 7372 wird: function setLautstaerke():void { if(mySoundchannel!=null) { var mousex:Number = mcLautstaerke.mouseX; var maxX:Number = mcLautstaerke.mcSpur.width; mcLautstaerke.mcMaske.width = mousex; var myTransform:SoundTransform = mySoundchannel.soundTransform; myTransform.volume = mousex/maxX; mySoundchannel.soundTransform = myTransform; } } Listing 7.32: Um die Lautstärke einer SoundChannel-Instanz zu verändern, bedarf es einer Sound- Transform-Instanz. Grundsätzlich kann eine Veränderung der Lautstärke nur dann erfolgen, wenn es eine SoundChannel-Instanz gibt – in unserem Fall trägt diese den Namen mySoundchan- nel. Ist diese vorhanden, werden x- und y-Position der Maus innerhalb des MovieC- lips mcLautstaerke ausgelesen und die Maske zum Anzeigen der Lautstärkestriche wird entsprechend gesetzt. Danach erfolgt der erste wichtige Schritt: die derzeitigen SoundTransform-Einstel- lungen werden aus der SoundChannel-Instanz mySoundchannel ausgelesen und der SoundTransform-Instanz myTransform zugewiesen: var myTransform:SoundTransform = mySoundchannel.soundTransform; Danach wird in dieser gerade erzeugten Instanz der Wert der Eigenschaft volume auf den entsprechenden Wert gesetzt. Bitte beachten Sie an dieser Stelle, dass die Eigen- schaft volume nun nicht mehr in Prozent, sondern in Werten zwischen 0 und 1 ange- geben werden muss: myTransform.volume = mousex/maxX; Ist dies erfolgt, schreibt man die geänderten Einstellungen wieder zurück in die SoundChannel-Instanz: mySoundchannel.soundTransform = myTransform; 7.6.6 Songs aus einer ComboBox abspielen Als Erweiterung des aktuellen Players könnte man beispielsweise eine ComboBox mit allen Songs der Playlist füllen und durch Auswählen eines Songs aus der ComboBox
  • 386.
    A U DI O - J U K E B O X 373 diesen direkt abspielen. Gesagt – getan: Ziehen Sie hierzu eine ComboBox aus den Komponenten auf die Bühne und geben Sie dieser den Namen „myPlaylist“. Nachdem dies erledigt ist, muss die Funktion EXMLComplete vor dem Aufruf der Funktion initPlayer wie folgt erweitert werden, um die ComboBox mit Inhalt zu füllen: ... myPlaylist.addEventListener(Event.CHANGE, EChange); myPlaylist.addItem({ label:"Bitte wählen Sie:", data:-1 }); for(i=0; i<myXML.song.length(); i++) { myPlaylist.addItem({ label:myXML.song[i].@src, data:i }); } initPlayer(); } Listing 7.33: Befüllen der ComboBox myPlaylist mit den MP3-Dateien aus der Playlist Bevor die for-Schleife das Befüllen der ComboBox übernimmt, wird noch ein Eintrag mit der Beschriftung „Bitte wählen Sie“ in die ComboBox geschrieben. Der zugehörige Wert dieses Eintrags ist -1 (dieser Wert wird später benötigt, da die Wahl des Users auch auf diesen Eintrag fallen kann, jedoch dann kein Song geladen werden soll). Innerhalb der for-Schleife werden alle Einträge der XML-Datei-Tags <song> als Beschriftung (label) in die ComboBox geschrieben. Die zugehörigen Werte (data) der Einträge sind die fortlaufenden Zahlen der for-Schleife (und somit der Index innerhalb der Playlist theSongs). Der Eventhandler EChange bestimmt, was beim Auswählen eines Songs aus der Com- boBox geschehen soll: function EChange(myEvent:Event):void { if(myPlaylist.selectedItem.data!=-1) { var dir:Number = myPlaylist.selectedItem.data-actualSong; playSong(dir); } } Listing 7.34: Der Eventhandler EChange, der aufgerufen wird, sobald der User eine neue Auswahl in der ComboBox getroffen hat Sollte die Auswahl einen Wert ungleich -1 haben (-1 war der Wert für den Eintrag „Bitte wählen Sie:“), so wird in der Variable dir die Anzahl der Songs ermittelt, um
  • 387.
    K A PI T E L 7374 die in der Playlist zurück (falls kleiner 0) oder vor (falls größer 0) gesprungen werden muss. Dieser Wert wird dann an die Funktion playSong übergeben – fertig. 7.7 Mögliche Erweiterungen Neben der Abspielsteuerung in Flash kann selbstverständlich auch eine Abspielsteue- rung in XHTML erfolgen. Dabei müssen in XHTML entsprechende Buttons angelegt werden, die in Flash freigegebene Funktionen aufrufen (wie Sie das realisieren können, erfahren Sie im Kapitel Clientseitiger Datenaustausch). Eine andere Erweiterung wäre etwa, dass per AJAX in regelmäßigen Abständen in der Datenbank nachgesehen wird, ob sich an der Playlist etwas verändert hat – wäre dies der Fall, so könnte die Playlist in Flash nachgeladen werden. Ein entsprechendes Bei- spiel finden Sie im Anschluss: der Videoplayer. Viel Spaß dabei!
  • 388.
    8 VIDEOPLAYER (ACTIONSCRIPT 3.0) Ziel diesesWorkshops ist die Erstellung eines Videoplayers, der die abzuspielenden Videos aus einer XML-Datei entnimmt und nacheinander anzeigt. Die XML-basierte Abspielliste soll per PHP dynamisch generiert werden und entweder alle in einem Verzeichnis befindlichen Flash-Videodateien (.FLV) oder eine über eine Datenbank generierte Liste an Videos beinhalten. Weiters sei vorausgeschickt, dass der Videoplayer in ActionS- cript 3.0 entwickelt wird und somit mit älteren Playern nicht abgespielt werden kann. Gleich vorwegschicken möchte ich auch eine Quellenangabe sowie ein Copyright zu allen Videos, die in diesem Work- shop verwendet wurden: Die Videos wurden mit freundlicher Genehmigung von TV1.at zur Verfügung gestellt. Herzlichen Dank!
  • 389.
    K A PI T E L 8376 8.1 Das Konzept des Videoplayers 1. Der Videoplayer soll in der Lage sein, gestreamt FLV-Dateien abzuspielen. Somit ist die erste Anforderung, dass FLV-Dateien dynamisch in Flash eingelesen werden sollen. 2. Innerhalb des Videoplayers soll volle Kontrolle über das Abspielen der Videos gewährleistet sein. In diesem Fall werden wir die Möglichkeiten der Video-Skins von Flash nutzen. 3. Es soll eine parametergesteuerte Autostart-Möglichkeit vorhanden sein. 4. Des Weiteren soll in der XML-Datei die Möglichkeit bestehen, im Falle einer datenbankgenerierten XML-Datei Informationen zu Autor, Inhalt usw. zu beinhalten. Wir werden den Videoplayer in mehreren Schritten entwickeln: Zunächst lernen wir, wie man generell mit FLV-basierten Videodaten in Flash arbeitet (an dieser Stelle lernen wir die Komponente „FLV Playback“ kennen). Danach werden wir den Player so erweitern, dass er mehr als nur ein Video abspie- len kann. Ist dies geschehen, werden wir per PHP eine XML-basierte Abspielliste generieren, welche wir im Weiteren in die Flash-Datei laden. Anschließend bringen wir noch AJAX ins Spiel und lassen uns überraschen, wie AJAX uns im Fall eines neuen Videos informiert. Zu guter Letzt greifen wir das Thema der Cue-Points auf, um zu sehen, wie man auf diese zugreifen kann. 8.2 Flash & Video Sinnvoll mit Video arbeiten kann Flash im Prinzip seit Version 6. Jedoch besteht mit Einführung von Flash 8 die Möglichkeit, neben dem Sorenson Spark Codec den (bes- seren und leistungsfähigeren) On2VP6 Codec zu verwenden. Grundsätzlich sollte man sich für den On2 VP6 Codec entscheiden, da dieser bei glei- cher Datenrate das (qualitativ) wesentlich bessere Ergebnis liefert. Auf der Habenseite steht jedoch, dass der Flash-Player beim Decodieren während der Anzeige beim User wesentlich mehr Prozessorleistung benötigt. Nicht zuletzt auch aus diesem Grund ist beim Einsatz von Video ein Grundsatz wesentlich und entscheidend: „Kenne deine User“. Gerade im Fall von Video müssen an den User sehr hohe Anforderungen gestellt werden: u u u u u „Kenne deine User“ „Kenne deine User“
  • 390.
    V I DE O P L AY E R ( A C T I O N S C R I P T 3 . 0 ) 377 1. Der User sollte über eine entsprechend gute Internetanbindung verfügen: DSL mit einer Download-Rate von mind. 400 Kbit/S für Videos in einer Standardgröße von 320x240 Pixel ist ideal. Bitraten á la ISDN oder gar Modem fallen gänzlich durch den Rost (außer die Videos sind in ihren Abmessungen relativ klein: beispielsweise 160x120 Pixel). 2. Des Weiteren ist in jedem Fall der Flash8-Player auf Userseite vorauszusetzen. 3. Außerdem wird wie oben erwähnt relativ viel Prozessorleistung beim Decodieren eines FLV-Videos benötigt. Ziehen Sie in jedem Fall eine Useranalyse in Erwägung – Ihre Kunden und vor allem Ihre User werden es Ihnen danken! Eine entsprechende „Warnmeldung“ für User mit schlechteren Internetanbindungen bzw. älteren Rechnern ist sowieso Pflicht. Aus Sicht von ActionScript spielt die Wahl des Decoder keine entscheidende Rolle, vielmehr ist die Wahl des korrekten Videoformats von entscheidender Bedeutung: Hier sollte in jedem Fall die Wahl auf das FLV-Format fallen – von der Möglichkeit, Videos in SWF-Dateien zu importieren und diese SWF-Datei dynamisch hinzuzula- den, möchte ich aus mehrerlei Gründen abraten: 1. Bildrate von Video und Flash-Datei (zumeist) unterschiedlich: Bettet man Videos in die Zeitleiste einer Flash-Datei ein, so tritt unweigerlich das Problem auf,dass die Bildraten vonVideo und Flash-Datei nicht zusammenpassen. TypischerweisewerdenVideosmiteinerBildratevon25BildernproSekundeerstellt (B/s) – diese Bildrate ist jedoch für den Flash-Player (bzw. das Flash-Plug-in – Sie kennen den Unterschied …) zu hoch,was dann zu einem Ruckeln imAbspielen des Videos führt. Der Ausweg wäre, einen ganzzahligen Teiler zu verwenden, wodurch beispielsweise nur jedes zweite oder dritte Bild aus dem Video in die Flash-Datei übernommen wird (vergleiche hierzu auch die nachfolgende Abbildung). Leider existiert kein sinnvoller Teiler, denn ein Teiler 2 würde zu einer Bildrate von 12.5 Bildern pro Sekunde führen, ein Teiler 3 zu 8.333 B/s, ein Teiler 4 zu 6.25 B/s usw. Erst ein Teiler 5 würde zu einer ganzzahligen Bildrate in Flash führen – nur eine Bildrate von 5 B/s ist eindeutig zu wenig. Ich denke, da geben Sie mir Recht – das menschliche Auge würde es in jedem Fall tun,denn erst ab einer Bildrate von 22 B/s erkennt das menschliche Auge den Unterschied zwischen Einzelbildern (ein Video ist ja schlussendlich eine Abfolge von Einzelbildern) und einem fortlaufenden Bild nicht mehr. Der Grund dafür, dass wir in Flash typischerweise mit einer Bildrate von 10–15 B/s arbeiten, ist in der geringen Leistungsfähigkeit des Flash-Players begründet. 2. Probleme in der Synchronisierung von Audio- und Videospur: Da Flash beim Einbetten von Videos letzten Endes nichts andres tut, als das Video in Form von Einzelbildern abzuspielen, werden die Audio- und „Video“-Spur
  • 391.
    K A PI T E L 8378 voneinander getrennt. In diesem Fall wird die Audiospur konventionell als Sound abgespielt und dadurch ergeben sich die üblichen Probleme beim gleichzeitigen Abspielen von Audio und Animation. Bitte schlagen Sie in der Referenz zu Flash nach, um hierzu weiterführende Informationen zu erhalten. 3. Der Produktionszyklus: vom Video zur SWF- bzw. FLV-Datei Das Einbetten von Videos in eine Flash-Datei erfordert einen zusätzlichen Arbeitsschritt, der zeitlich gesehen mitunter nicht zu unterschätzen ist. Auf der anderen Seite können Flash-Videos (FLV-Dateien) oft direkt aus den Videobearbeitungsprogrammen exportiert werden. ABBILDUNG 8.1 Unterschiedliche Bitraten zwischen der Quelldatei und der SWF-Datei führen beim Einbetten des Videos dazu, dass aus der Quelldatei unregelmäßig Bilder in das eingebettete Video der SWF- Datei übernommen werden. Der Grund dafür ist, dass in unserem Fall die Bildrate der Quelldatei (25 B/s) und der SWF-Datei (15 B/s) keinen sinnvollen gemeinsamen Teiler besitzen (der größte gemeinsame Teiler wäre 5, jedoch ist eine Bildrate von 5 B/s nicht sinnvoll). Aus diesem Grund entscheidet man sich gerne für FLV- anstatt für eingebettete Videos in SWF-Dateien. Bitte beachten Sie jedoch, dass erst mit der Einführung von Flash 7 das Arbeiten mit FLV-Dateien möglich wurde. Ein weiterer wesentlicher Vorteil von FLV- gegenüber SWF-Dateien sind die in die FLV-Dateien integrierten Metadaten (vergleichen Sie hierzu auch den Workshop „Audio-Jukebox“ und die dort verwendeten MP3-Dateien), die abgerufen und somit angezeigt werden können. 8.3 Die Umsetzung 8.3.1 Flash und die FLVPlayback-Komponente Flash bietet uns seit Version 7 die Möglichkeit, Videodateien im FLV-Format mit einer geeigneten Komponente abzuspielen. Es empfiehlt sich an dieser Stelle, die Kom- ponente nicht per ActionScript zu erstellen, sondern diese direkt auf der Bühne zu platzieren, da dies sehr einfach und komfortabel geschieht: Unter den Komponenten (das entsprechende Register können Sie über den Menüpunkt FENSTER/KOMPONENTEN einblenden) finden Sie die Komponenten für „User Interface“ und eben „Video“. Zie- hen Sie die Komponente FLVPlayback auf die Bühne:
  • 392.
    V I DE O P L AY E R ( A C T I O N S C R I P T 3 . 0 ) 379 In der Registerkarte PARAMETER hat man die Möglichkeit, die benötigten Buttons für die Abspielsteuerung in Form von sogenannten Skins zu wählen. In unserem Fall genügen die Buttons Play, Stopp, Rewind, Forward, Lautstärke (inklusive Regelung) und eine Abspielleiste. Neben den Elementen kann man noch wählen, ob diese über oder unter dem Video liegen. (Kleiner Tipp: Testen Sie mal durch, welche der Skins Ihnen zusagt.) Des Weiteren ist auch die Hintergrundfarbe der Skins frei wählbar (ich habe mich an dieser Stelle für ein dunkles Grau entschieden). SkinsSkins ABBILDUNG 8.2 Eine Instanz der FLVPlayback- Komponente wurde auf der Bühne platziert. Welche Buttons zur Abspielsteuerung angezeigt und verwendet werden, kön- nen Sie im Register PARAMETER wählen. ABBILDUNG 8.3 Wahl der Abspielbuttons (skin) und der Hintergrund- farbe (skinBackgroundColor). An dieser Stelle empfehle ich Ihnen, ein bisschen mit den Parametern zu experimen- tieren (beispielsweise erzeugt das Setzen des Alphakanals skinBackgroundAlpha auf den Wert 0.7 einen besseren Effekt als der Wert 1, da so das Video im Hintergrund noch sichtbar bleibt).
  • 393.
    K A PI T E L 8380 Um für ActionScript Zugriff auf die Komponenten-Instanz zu erhalten, müssen wir der Komponente noch einen Instanznamen zuweisen: ABBILDUNG 8.4 Zuweisen eines Instanz- namens für die zuvor auf der Bühne platzierte Komponente Wählen Sie für die Bühne eine Größe von 600x500 Pixel und legen Sie die FLV- Playback-Komponente mittig auf die Bühne (aus X-Richtung gesehen) und an die Y-Position 10 Pixel. Als Größe der FLVPlayback-Komponente habe ich 512x416 Pixel gewählt: ABBILDUNG 8.5 Alle Vorkehrungen sind getroffen (Bühnengröße 600x500 Pixel, Größe der FLVPlayback-Komponente 512x416 Pixel) – kümmern wir uns um die Videos. Die FLVPlayback-Komponente per ActionScript erstellen Wie oben bereits erwähnt, kann eine FLVPlayback-Komponente auch zur Laufzeit erzeugt werden. Voraussetzung dafür ist, dass sich die Komponente bereits in der Bibliothek befindet. Dies bewerkstelligt man am einfachsten, indem man das Kompo- nentenfenster öffnet und die entsprechende Komponente in die Bibliothek zieht:
  • 394.
    V I DE O P L AY E R ( A C T I O N S C R I P T 3 . 0 ) 381 Diese Vorgehensweise mit ActionScript bedeutet zwar etwas mehr an Code, ist dafür flexibler und für Programmierer zumeist „sympathischer“. Natürlich können Sie auf alle Eigenschaften zugreifen, die die FLVPlayback-Komponente für uns bereithält. Sehen wir uns die nötigen Schritte an: Zunächst benötigt man einmal die Klasse FLVPlayback, die sich innerhalb der fl.video-Klasse befindet. Da wir aus dieser Klasse noch weitere Klassen benöti- gen, importieren wir idealerweise gleich die gesamte Klasse fl.video: import fl.video.*; Danach definiert man eine neue FLVPlayback-Instanz: var myVideoplayer:FLVPlayback = new FLVPlayback(); Ist dies getan, kann man sofort auf sämtliche Eigenschaften der Instanz myVideoplayer zugreifen. Im Folgenden lege ich jede Eigenschaft fest, die wir auch im vorigen Abschnitt festgelegt haben, jedoch dort noch über die Parameter der Komponente: X- und Y-Position: myVideoplayer.x = 44; myVideoplayer.y = 10; Breite und Höhe: myVideoplayer.width = 512; myVideoplayer.height = 418; Auto-Play deaktivieren: myVideoplayer.autoPlay = false; Skin zuweisen: myVideoplayer.skin = "SkinOverAllNoVolNoCaptionNo- Full.swf"; myVideoplayer.skinBackgroundAlpha = 0.7; myVideoplay- er.skinBackgroundColor = 0x333333; u u u u u u u ABBILDUNG 8.6 Die FLVPlayback- Komponente wird in der Bibliothek der Flash- Anwendung benötigt – ansonsten ist es auch mit ActionScript nicht möglich, dynamisch eine Instanz davon zu erzeugen.
  • 395.
    K A PI T E L 8382 Alle diese Schritte würden uns nicht viel helfen, würden wir unser virtuelles Display- Objekt nicht noch unserer Bühne zuweisen: Display-Objekt der Bühne (oder einem anderen Objekt) zuweisen: this. addChild(myVideoplayer); Vergleichen Sie beide Vorgehensweisen (Arbeiten mit Komponenten direkt auf der Bühne oder Erzeugen einer Komponenten-Instanz per ActionScript) – Sie werden feststellen, dass sie ein identisches Ergebnis liefern. Welche Variante Sie bevorzugen, ist Ihnen überlassen – das Ergebnis ist gleichwertig. Die eben dargestellte Variante ist auf der Buch-CD im aktuellen Kapitel unter dem Namen videoplayer_02a.flv zu finden. Da wir noch keine Videoquelle zugewiesen haben, wird das Beispiel zwar eine Playback-Komponente erzeugen, aber eben kein Video darstellen. In den nächsten Ausführungen entwickeln wir das Beispiel immer weiter, sodass Sie den Fortschritt gut mitverfolgen können. Damit sind wir mal fürs Erste gerüstet und können uns um die Videodatei kümmern. 8.3.2 Videos im FLV-Format Nun, an dieser Stelle stellt sich zunächst einmal die Frage, von welchen Vorausset- zungen wir ausgehen können: 1. Das Video wird bereits als FLV-Datei geliefert: In seltenen Fällen kann es vorkommen, dass Sie als Webentwickler bereits fertige FLV-Dateien (vom Kunden) zur Verfügung gestellt bekommen. In diesem Fall müssen wir keine vorbereitenden Maßnahmen mehr treffen. Gehen wir einmal davon aus, dass dies die Ausnahme ist. 2. Sie selbst sind der Videoproduzent: Für den Fall, dass Sie selbst das Video produzieren, unterstützt Flash Ihr Videobearbeitungsprogramm mit einem eigens mitgelieferten Plug-in namens „FLV QuickTime Export Plug-in“ (bei Flash 8 gilt dies nur für die Professional- Variante), sofern Sie mit einem der folgenden Videobearbeitungsprogramme arbeiten: Adobe After Effects (Windows und Macintosh) Apple Final Cut (Macintosh) Apple QuickTime Pro (Windows und Macintosh) Avid XPress DV (Windows und Macintosh) Mithilfe dieses Plug-ins sind Sie in der Lage, direkt aus Ihrem Video- bearbeitungsprogramm eine entsprechende FLV-Datei zu exportieren. u u u u u
  • 396.
    V I DE O P L AY E R ( A C T I O N S C R I P T 3 . 0 ) 383 3. Sie besitzen das Video im Rohformat und müssen es selbst in ein FLV-Format konvertieren: In diesem Fall haben Sie zwei Möglichkeiten: 1. Sie verwenden die Importmöglichkeit von Flash: Hierzu erzeugen Sie zunächst eine neue Flash-Datei, klicken dann auf DATEI/IMPORTIEREN/VIDEO IMPORTIEREN… Danach öffnet sich der Importassistent für Videos. 2. Sie verwenden den Flash Video Encoder, der im Lieferumfang von Flash CS3 Professional (oder Flash 8 Professional) enthalten ist. Sie finden ihn als eigenständiges Programm, das zusätzlich zu Flash installiert wurde. Bleibt nur zu klären, mit welchen Videoformaten Flash umgehen kann. Diese sind: Macintosh mit installiertem QuickTime 7: Audio Video Interleaved: AVI Digital Video: DV Motion Picture Experts Group: MPG, MPEG QuickTime-Video: MOV Windows mit installiertem DirectX ab Version 9: Audio Video Interleaved: AVI Motion Picture Experts Group: MPG, MPEG QuickTime-Video: MOV (nur bei zusätzlich installiertem QuickTime 7) Windows Media-Datei: WMV, ASF Wenn Sie grundsätzlich mit dem QuickTime-Videoformat oder dem AVI-Format arbeiten, sind Sie auf beiden gängigen Betriebssystemen also „auf der sicheren Seite“. Achten Sie darauf, dass das Video möglichst unkomprimiert und somit in einer hohen Qualität zur Verfügung steht. Sollten Sie beispielsweise ein bereits codiertes und komprimiertes Video verwenden, so wurde durch die Komprimierung schon ein Teil der Qualität eingebüßt. Nachdem jedoch Flash das Video erneut komprimieren wird, hätte man eine doppelte Komprimierung – das schlägt sich dann in jedem Fall auf die Qualität der Darstellung nieder. u u u u u u u u u u
  • 397.
    K A PI T E L 8384 Variante 1 (Importieren eines Videos in eine leere Flash-Datei) hat gegenüber Variante 2 (Arbeiten mit dem Flash Video Encoder) den Nachteil, dass das Importieren von Videos im Allgemeinen sehr viel Zeit in Anspruch nimmt und Sie in der Zwischenzeit Flash nicht verwenden können. Da der Flash Video Encoder ein eigenständiges Pro- gramm ist (und dieser noch dazu in der Lage ist, mehrere Videos hintereinander in einem sogenannten „Batch-Modus“ abzuarbeiten), können Sie so weiterhin ungestört mit Flash arbeiten und nebenbei die Videos konvertieren. Langer Rede kurzer Sinn: Verwenden Sie den Flash Video Encoder. Infos zum Importieren von Videos in Flash Erste Wahl: der Flash Video Encoder Erste Wahl: der Flash Video Encoder ABBILDUNG 8.7 Variante 1: Importieren eines Videos in ein noch leeres Flash-Dokument ABBILDUNG 8.8 Variante 2: Verwenden des Flash Video Encoder, der als eigenständiges Programm mit der Installation von Flash installiert wird
  • 398.
    V I DE O P L AY E R ( A C T I O N S C R I P T 3 . 0 ) 385 finden Sie im Flash CS3-Handbuch (PDF-Datei), das Sie von der Adobe-Website (www.adobe.de) downloaden können. Der Flash Video Encoder Einmal gestartet, präsentiert sich der Flash Video Encoder wie in der nachfolgenden Abbildung. ABBILDUNG 8.9 Schön aufgeräumt und übersichtlich – der Flash Video Encoder wartet auf Ihre Videos. Über den Button HINZUFÜGEN… können Sie ein oder mehrere Videos auswählen, die Sie konvertiert haben möchten. Einmal der Warteschlange (so nennt sich die Liste an abzuarbeitenden Videos) hinzugefügt, können Sie ein oder mehrere Videos auswählen und über den Button EINSTELLUNGEN… die entsprechenden Einstellungen für den Export des Videos treffen:
  • 399.
    K A PI T E L 8386 Betrachten wir die einzelnen Registerkarten dieses Fensters einmal ein bisschen genauer: Registerkarte KODIERUNGSPROFILE In dieser Registerkarte haben Sie zunächst einmal die Möglichkeit, aus vordefinierten Profilen zu wählen. Wie schon weiter oben erwähnt, würde ich Ihnen in jedem Fall Flash 8 Profile empfehlen,da diese mit dem On2VP6 Codec arbeiten.Die Einstellung „Flash 8 – Mittlere Qualität (400 Kbit/s)“ trifft unsere Erwartungen schon relativ gut. Detaileinstellungen zu diesem Profil treffen Sie dann in den weiteren Registerkarten. Registerkarte VIDEO Hierin treffen Sie die Einstellungen zur Codierung derVideospur (die Einstellungen zur Codierung der Audiospur finden Sie in der nächsten Registerkarte). Neben der Qualität bzw. Datenrate (diese beiden Einstellungen hängen zusammen) und dem Video-Codec ist vor allem das Kontrollkästchen ALPHAKANAL CODIEREN interessant: Ist dieses Kontrollkästchen aktiviert, so werden eventuell im Video vorhandene Alphakanäle (beispielsweise bei Blue-Box-Aufnahmen) transparent gemacht, sodass Sie nach dem Einbinden der FLV-Datei den Hintergrund Ihrer SWF-Datei durch das Video hindurch sehen. Ebenso wichtig ist die Einstellung zur Bildrate: Wie schon weiter oben ausgeführt, ist von einer Veränderung der Bildrate eines Videos abzuraten, da dadurch Bilder im Video verloren gehen. Da in SWF-Dateien verknüpfte FLV-Videos nicht dieselbe Bildrate aufweisen müssen wie die SWF-Datei selbst, rate ich zur Einstellung „Wie Quelle“. u u ABBILDUNG 8.10 In diesem Fenster können Sie alle Einstellungen treffen, die für den Export des Videos in eine FLV-Datei notwendig sind. Video-Copyright: TV1.at – www.tv1.at.
  • 400.
    V I DE O P L AY E R ( A C T I O N S C R I P T 3 . 0 ) 387 Das Kontrollkästchen DEINTERLACE wird verwendet, um das Video in ein Vollbildformat umzuwandeln. Sämtliche weitere Information hierzu entnehmen Sie bitte dem Flash-Handbuch. Registerkarte AUDIO Hierin bestimmen Sie die Datenrate, wie qualitativ hochwertig die Audiospur im Video sein soll. Eine Datenrate von beispielsweise 96 Kbit/s (stereo) ist von relativ hoher Qualität (CD-Qualität liegt bei etwa 128–160 Kbit/s) – eine etwas geringere Bitrate ist für Videos im Internet immer noch ausreichend. Registerkarte CUE-POINTS Cue-Points sind eine sehr interessante Angelegenheit in Videos. Mithilfe von Cue- Points sind Sie in der Lage, Ereignisse in der SWF-Datei zu erzeugen, in der die FLV-Datei eingebunden ist. So sind Sie etwa in der Lage, gleichzeitig mit dem Erreichen einer bestimmten Position im Video in der SWF-Datei Texte, Grafiken etc. anzuzeigen. Ebenso eignen sich Cue-Points als Navigationspunkte innerhalb des Videos. Mehr dazu weiter unten. Registerkarte ZUSCHNEIDEN UND GRÖSSE ÄNDERN Die letzte Registerkarte dient dazu, das Video in Größe (Cropping bzw. Breite und Höhe) und Länge zu beschneiden. Werfen wir noch einen etwas genaueren Blick auf die Registerkarte CUE-POINTS. Um einen neuen Cue-Point hinzuzufügen, wählen Sie über die Abspielleiste zunächst ein- mal die Position aus, die Sie im Video als Cue-Point wählen wollen (natürlich können Sie beliebig viele Cue-Points setzen). Danach geben Sie einen Namen für den Cue- Point sowie einen Typ (Ereignis oder Navigation) an. Zu guter Letzt haben Sie noch die Möglichkeit, diesem Cue-Point einen oder mehrere Parameter inklusive Werten zuzuweisen. Diese werden innerhalb der FLV-Datei gespeichert. Zusätzlich haben Sie die Möglichkeit, die Cue-Points in einer separaten XML-Datei zu speichern. Der Cue-Point Typ ist wie folgt zu wählen: Typ „Ereignis“: Es wird ein ActionScript-Ereignis namens CUE_POINT ausgelöst. Zumeist werden solche Cue-Points für die Synchronisation mit anderen Animatio- nen in der Flash-Anwendung verwendet. Typ „Navigation“: Es wird neben dem Auslösen des CUE_POINT-Ereignisses in der FLV-Datei ein Schlüsselbild an dieser Position angelegt. Da zusätzliche Schlüs- selbilder im Video die Gesamtqualität beeinträchtigen können, sollten derartige Cue-Points nur dann verwendet werden, wenn dem User beim Abspielen eine Art „Navigation“ zur Verfügung gestellt werden soll (beispielsweise wenn der User nach einer bestimmten Stelle im Video suchen können soll). Dieser Typ von Cue-Point wird im Allgemeinen zumeist verwendet. u u u u u
  • 401.
    K A PI T E L 8388 Beachten Sie, dass es zwischen ActionScript 2 und 3 Unterschiede in der Handhabung von Cue-Points gibt. Darauf kommen wir weiter unten noch zu sprechen. Unterschiede bei Cue-Points zwischen ActionScript 2 und 3 Unterschiede bei Cue-Points zwischen ActionScript 2 und 3 ABBILDUNG 8.11 Cue-Points in FLV-Dateien. Video-Copyright: TV1.at – www.tv1.at In den meisten Fällen verwenden Sie Cue-Points vom Typ „Navigation“, um diese per ActionScript später auch einfach anspringen zu können:
  • 402.
    V I DE O P L AY E R ( A C T I O N S C R I P T 3 . 0 ) 389 Sind Sie mit den gesetzten Cue-Points zufrieden, so können Sie diese bei Bedarf in Form einer XML-Datei mit Hilfe des Speichern-Buttons abspeichern: ABBILDUNG 8.12 Die meist verwendeten Cue-Points sind vom Typ „Navigation“. ABBILDUNG 8.13 Die Cue-Points werden in Form einer (separaten) XML- Datei abgespeichert.
  • 403.
    K A PI T E L 8390 Der Inhalt der XML-Datei spricht für sich: <?xml version="1.0" encoding="UTF-8" standalone="no" ?> <FLVCoreCuePoints Version="1"> <CuePoint> <Time>0</Time> <Type>navigation</Type> <Name>Die schönste Monster</Name> </CuePoint> <CuePoint> <Time>34355</Time> <Type>navigation</Type> <Name>Interview Andreas Wolfesberger</Name> </CuePoint> <CuePoint> <Time>81017</Time> <Type>navigation</Type> <Name>Interview Zweitplatzierter</Name> </CuePoint> <CuePoint> <Time>106143</Time> <Type>navigation</Type> <Name>Interview Rupert Kaspar</Name> </CuePoint> <CuePoint> <Time>155369</Time> <Type>navigation</Type> <Name>Interview Gaetano Spagnolo</Name> </CuePoint> <CuePoint> <Time>193314</Time> <Type>navigation</Type> <Name>Interview Andreas Czejka</Name> </CuePoint> <CuePoint>
  • 404.
    V I DE O P L AY E R ( A C T I O N S C R I P T 3 . 0 ) 391 <Time>233823</Time> <Type>navigation</Type> <Name>Interview Freundin von Rupert Kaspar</Name> </CuePoint> <CuePoint> <Time>264589</Time> <Type>navigation</Type> <Name>Interview Julia Roiss</Name> </CuePoint> <CuePoint> <Time>286638</Time> <Type>navigation</Type> <Name>Interview Chris Zaiser</Name> </CuePoint> <CuePoint> <Time>329711</Time> <Type>navigation</Type> <Name>Abschluss</Name> </CuePoint> </FLVCoreCuePoints> Listing 8.1: Die XML-Datei beinhaltet sämtliche gesetzte Cue-Points mit Zeitpunkt des Cue-Point (angege- ben in Millisekunden), Typ und Namen. Diese XML-Datei hängt grundsätzlich nicht mit der FLV-Datei zusammen. Dies soll bedeuten, dass Sie selbst auch eine derartige XML-Datei erstellen können bzw. eine gegebene XML-Datei jederzeit ändern können. Derartige XML-Dateien werden bei Bedarf zusätzlich zur FLV-Datei (und nicht gemeinsam mit ihr) in die SWF-Datei geladen. Einzig die Syntax der XML-Daten muss erhalten bleiben. Zurück zum Flash Video Encoder. Nachdem wir alle Einstellungen zum Video getrof- fen haben und zurück in der Dateiübersichtsmaske sind, können Sie entweder weitere Videos hinzufügen (und wieder die entsprechenden Einstellungen treffen) oder über den Button WARTESCHLANGE STARTEN den Codiervorgang in Gang setzen. Flash arbeitet dann alle in der Warteschlange befindlichen Videos ab und speichert diese im selben Verzeich- nis wie die Quelldaten. Bedenken Sie bitte, dass der Codiervorgang mitunter relativ lange dauern kann (dies ist auch abhängig davon, welches Format Ihre Quelldatei aufweist) – beispielsweise dauerte bei mir das Codieren eines Videos mit einer Länge von etwa 5:30 Minuten im Format MP4 (Codierung: Video: h264, Audio: mp3) etwa 40 Minuten. Dasselbe Video im QuickTime-Format dauerte bei der Codierung etwa 3 Minuten.
  • 405.
    K A PI T E L 8392 8.3.3 Dynamisches Verknüpfen der FLVPlayback- Komponente mit einem Video Da wir neben dem reinen Anzeigen des Videos auch die Möglichkeit haben wollen, das Video zu steuern (und somit auch alle Ereignisse, Eigenschaften und Methoden der FLVPlayback-Komponente zu nutzen), laden wir zunächst einmal die zugehörigen Klassen (sollten Sie die Komponente per ActionScript eingebunden haben, haben Sie die benötigten Klassen bereits geladen): import fl.video.*; Danach weisen wir der Playback-Komponente (ihr Name war myVideoplayer) eine Videoquelle zu – in diesem Fall liegt die Videoquelle im selben Verzeichnis wie die SWF-Datei: myVideoplayer.source = "FestaDucati2006.flv"; Mit diesen beiden Codezeilen hätten wir schon alle Arbeiten erledigt und wären somit fertig. Ich möchte Ihnen jedoch an dieser Stelle noch einige Eventhandler zeigen, die für die Arbeit mit Videos von Vorteil sein können: VideoEvent-Klasse: COMPLETE: wird ausgelöst, wenn das Video fertig abgespielt wurde READY: wird ausgelöst, wenn das Video bereit zum Abspielen ist Neben den beiden genannten Ereignissen existiert noch eine größere Liste an weiteren Ereignissen, die Sie im Komponenten-Referenzhandbuch nachlesen können. Ich möchte Ihnen an dieser Stelle zeigen, wie Sie die beiden Ereignisse verwenden kön- nen. Offensichtlich ist zunächst das READY-Ereignis von Interesse, denn bevor dieses Ereignis nicht aufgetreten ist, kann das Video auch nicht gestartet/verwendet werden. In diesem Fall sollte natürlich die Abspielkonsole – die Skin – auch nicht sichtbar sein. „Nicht sichtbar“ wäre im einfachsten Fall so zu realisieren, dass der Alphawert der Skin zunächst auf den Wert 0 gesetzt wird und erst nach Eintreten des READY-Ereignisses den vorgegebenen Wert von – in unserem Fall – 0.7 bekommt. Hierfür sind drei Schritte notwendig: 1. Den Alphawert der Skin zunächst auf den Wert 0 setzen: myVideoplayer.skinBackgroundAlpha = 0; 2. Einen Eventhandler definieren, der bei Auftreten des READY-Ereignisses den Alphakanal auf 0.7 setzt: function EReady(myEvent:VideoEvent):void { myVideoplayer.skinBackgroundAlpha = 0.7; } u u u
  • 406.
    V I DE O P L AY E R ( A C T I O N S C R I P T 3 . 0 ) 393 3. Den Eventhandler unserer FLVPlayback-Instanz zuweisen: myVideoplayer.addEventListener(VideoEvent.READY, EReady); Nach Auftreten des COMPLETE-Ereignisses wäre es beispielsweise nett, wenn dem User eine entsprechende Meldung im Fenster ausgegeben wird. Hierzu ein Beispiel: ABBILDUNG 8.14 Teilen Sie dem User zusätz- lich mit, wann das Ende eines Videos erreicht ist (auch wenn er es vielleicht in der Abspielleiste sehen könnte ...). Video-Copyright: TV1.at – www.tv1.at Der eingeblendete Text befindet sich in einem MovieClip mcFinish, der als Instanz auf der Bühne den Namen mcFinished erhalten hat (siehe Abbildung 8.15): ABBILDUNG 8.15 Der MovieClip mcFinish erhält als Instanzname auf der Bühne den Namen mcFinished.
  • 407.
    K A PI T E L 8394 Um die Instanz zunächst auszublenden, wird die Eigenschaft visible auf den Wert false gesetzt: mcFinished.visible = false; Bitte beachten Sie an dieser Stelle wieder den Unterschied von ActionScript 2.0 und ActionScript 3.0: Trug die Eigenschaft in ActionScript 2.0 noch den Namen _visible (inklusive Unterstrich „_“ am Anfang) und war eine Eigenschaft innerhalb der Movie- Clip-Klasse, so wurde der Unterstrich in ActionScript 3.0 entfernt und die Eigenschaft in die DisplayObject-Klasse verschoben. Bei Auftreten des Ereignisses COMPLETE wird die Instanz wieder eingeblendet: function EComplete(myEvent:VideoEvent):void { mcFinished.visible = true; } myVideoplayer.addEventListener(VideoEvent.COMPLETE, EComplete); Listing 8.2: Sobald das COMPLETE-Ereignis auftritt, wird die MovieClip-Instanz mcFinished eingeblendet. Das entsprechende Beispiel finden Sie auf der Buch-CD unter dem Namen videoplay- er_01a.flv im Verzeichnis des aktuellen Kapitels. Im Hinblick auf die weitere Entwicklung des Videoplayers werden wir das COMPLETE- Ereignis dahingehend verwenden, dass nach dem Abspielen eines Videos das nächste Video gestartet wird. 8.3.4 Schritt 1: Abspielen einer Liste von Videos (Array) Nachdem wir es nun vollbracht haben, ein Video dynamisch einzubinden, kann das nächste Ziel nur sein, mit einer Liste von Videos zu arbeiten. Mit anderen Worten wollen wir Folgendes: Nachdem ein Video fertig abgespielt wurde, soll das nächste Video abgespielt wer- den. Es soll die Möglichkeit bestehen, aus einer Liste von Videos eine Auswahl zu treffen und somit ein Video direkt auszuwählen. Es soll von einem Video zum nächsten bzw. zum vorigen gesprungen werden können. Punkt eins ist relativ einfach realisiert, nachdem wir zuvor gerade das COMPLETE- Ereignis kennengelernt haben. Der zweite Punkt wird über eine ComboBox realisiert, Punkt drei über entsprechende Tasten in der Skin. u u u _visible in ActionScript 2.0, visible in ActionScript 3.0 _visible in ActionScript 2.0, visible in ActionScript 3.0
  • 408.
    V I DE O P L AY E R ( A C T I O N S C R I P T 3 . 0 ) 395 Bevor wir die Punkte nacheinander angehen, müssen wir aber erst mal für eine Video- liste und einen Index sorgen: var videoList:Array = new Array ("videos/Dueringer.flv"," videos/ Faak2005.flv"," videos/FestaDucati2006.flv"," videos/Juvenile.flv"); var videoIndex:uint = 0; Listing 8.3: videoList und videoIndex definieren die Liste an abzuspielenden Videos und den Index des Videos aus der Liste, das gerade abgespielt wird. Den Index verwenden wir dazu, um uns zu merken, welches Video aus der Liste gerade abgespielt wird (oder werden soll) – der Index zeigt also genau auf die Position des aktuellen Videos im Array videoList. So, dann gehen wir die drei Punkte aus der obigen Liste an. Punkt eins war die Forde- rung nach dem Abspielen des nächsten Videos, sobald ein Video komplett abgespielt wurde. Stellt sich nur noch die Frage, was passieren soll, wenn das Ende der Videoliste erreicht ist ... Wir handhaben diesen Fall derart, dass wir in einer Variablen loopAtEnd uns diesen Fall offen lassen: Ist loopAtEnd==true, so wird beim Erreichen des Endes der Liste das erste Video in der Liste abgespielt (und somit eine Schleife erzeugt). Ist loopAtEnd==false, beenden wir das Abspielen am Ende der Liste und blenden die MovieClip-Instanz mcFinished ein. Sämtliche oben genannte Änderungen betreffen den Eventhandler EComplete: var loopAtEnd:Boolean = true; function EComplete(myEvent:VideoEvent):void { videoIndex++; if(videoIndex==videoList.length) { if(loopAtEnd) { videoIndex = 0; } else { mcFinished.visible = true; return; } } myVideoplayer.source = videoList[videoIndex]; } Listing 8.4: Änderungen an dem Eventhandler loopAtEnd Bei Eintreten des Ereignisses COMPLETE wird die Funktion EComplete aufgerufen. Hierin wird zunächst der videoIndex um eins erhöht und kontrolliert, ob so even- tuell das Ende der Liste erreicht wurde. Ist dies der Fall, müssen wir überprüfen, ob wir in der Videoliste wieder von vorne beginnen (loopAtEnd==true) oder nicht (loopAtEnd==false). Wenn ja, wird also der Index (videoIndex) auf null gesetzt. Bei nein blenden wir mcFinished ein und brechen die Funktion mit return ab. Sollte das Ende der Liste noch nicht erreicht gewesen sein oder die Liste wieder von vorne
  • 409.
    K A PI T E L 8396 abgespielt werden, weisen wir der FLVPlayback-Instanz myVideoplayer eine neue Quelle aus der Liste zu und weiter geht’s mit Abspielen ... Auf zur nächsten Aufgabe: Aus der Liste an Videos soll eine Kombo-Box (ComboBox- Komponente) gefüllt werden. Wie auch schon zuvor werden wir in einem Beispiel (dasjenige mit der 1 im Dateinamen: videoplayer_01x.fla) eine Komponente auf die Bühne ziehen und im anderen Beispiel (dasjenige mit der 2 im Dateinamen: videoplay- er_02x.fla) die Komponente mit ActionScript erstellen. In den User Interface-Komponenten finden Sie die ComboBox-Komponente. Plat- zieren Sie eine Instanz auf der Bühne an der Position (44/436), ändern Sie die Breite auf 200 Pixel und weisen Sie ihr den Namen myCombobox zu. Um die ComboBox mit Daten zu füllen, benötigen wir dennoch ActionScript: var theObject:Object = new Object(); for(var i:Number = 0; i<videoList.length; i++) { theObject = { label:videoList[i], data:i }; myCombobox.addItem(theObject); } Listing 8.5: Listing zum Generieren der Inhalte der ComboBox-Instanz myCombobox Das Füllen der Daten erfolgt mithilfe eines Objekts, das eine klare Struktur aufweist: { label:BESCHRIFTUNG, data:WERT } label bezeichnet die Beschriftung, die in der ComboBox abgelesen werden kann. data bestimmt den Wert der ComboBox, der beim Auswählen eines Eintrags gesetzt wird. Der Code kann entweder sehr ausführlich geschrieben werden (wie im obigen Script dargestellt) oder auch sehr kompakt: for(var i:Number = 0; i<videoList.length; i++) { myCombobox.addItem({ label:videoList[i], data:i }); } Listing 8.6: Alternative Kurzschreibweise von <?xml version="1.0" encoding="ISO-8859-1" standalone="yes" ?> <Playlist rootDir="videos" autostart="0"> <File src="FestaDucati2006.flv"> <Author>www.tv1.at</Author> <Content>Festa Ducati 2006</Content> <Date>2006-07-08</Date> </File> <File src="Faak2005.flv"> u u
  • 410.
    V I DE O P L AY E R ( A C T I O N S C R I P T 3 . 0 ) 397 <Author>www.tv1.at</Author> <Content>Motorradtreffen Faak am See 2005</Content> <Date /> </File> <File src="Tattooconvention.flv"> <Author>www.tv1.at</Author> <Content>Tattoo Convention 2006</Content> <Date /> </File> <File src=»Juvenile.flv»> <Author>www.tv1.at</Author> <Content>HipHop-Festival Wels</Content> <Date /> </File> <File src="Dueringer.flv"> <Author>www.tv1.at</Author> <Content>Dueringer ab 4.99</Content> <Date /> </File> </Playlist> Listing 8.6. Das Füllen der ComboBox hätten wir geschafft, jedoch hilft uns das wenig, wenn die Auswahl eines Videos in der ComboBox nichts bewirkt. Mit anderen Worten: Die ComboBox muss ein bisschen „Intelligenz“ erhalten: Sobald eine Änderung in der Auswahl der ComboBox erfolgt, soll eine Funktion aufgerufen werden, die das neu gewählte Video abspielt. Ein geeigneter Event für diese Aufgabe ist CHANGE, das bei jeder Änderung der Auswahl in einer ComboBox auftritt: function EChange(myEvent:Event):void { videoIndex = myCombobox.selectedIndex; myVideoplayer.source = videoList[videoIndex]; myVideoplayer.play(); } myCombobox.addEventListener(Event.CHANGE, EChange); Listing 8.7: Der Eventhandler für das CHANGE-Ereignis setzt den Index auf den gewählten Eintrag der ComboBox, setzt die Videoquelle auf die entsprechende Videodatei aus der Liste und lässt das Video abspielen.
  • 411.
    K A PI T E L 8398 Der Ablauf ist relativ einfach und übersichtlich: 1. Es wird eine Funktion EChange definiert, die bei Aufruf den Wert der ComboBox myCombobox ausliest und den Index (videoIndex) auf genau diesen Wert setzt. 2. Aus der Videoliste videoList wird die entsprechende URL zur Videodatei gelesen und der FLVPlayback-Instanz myVideoplayer als Quelle zugewiesen. 3. Das Video wird abgespielt (myVideoplayer.play();). Wie würde der Code aussehen, würden wir die ComboBox per ActionScript generie- ren? Nun, auch nicht sehr viel aufwändiger. Lediglich die folgenden Zeilen müssten den Listings Listing 8.6 und Listing 8.7 vorangestellt werden, um den ActionScript- Part abzudecken: import fl.controls.ComboBox; var myCombobox:ComboBox = new ComboBox(); myCombobox.move(44,436); myCombobox.width = 200; addChild(myCombobox); Listing 8.8: Generieren einer ComboBox per ActionScript. Alternativ hätten Sie die ComboBox auch über die Eigenschaften x und y verschieben können (myCombobox.x = 44; myCombobox.y = 436). Wie auch im Fall der FLVPlayback-Komponente muss die ComboBox-Komponente von der Komponentenübersicht in die Bibliothek gezogen werden, um im Weiteren für ActionScript verfügbar zu sein: ABBILDUNG 8.16 Um per ActionScript zur Laufzeit eine Komponente erstellen zu können, muss sich diese in der Bibliothek befinden.
  • 412.
    V I DE O P L AY E R ( A C T I O N S C R I P T 3 . 0 ) 399 Folgendes ist also geschehen: Die ComboBox-Komponente wurde für den Einsatz mit ActionScript zur Laufzeit bereitgestellt. Diese Informationen finden Sie, wenn Sie die Eigenschaften der ComboBox in der Bibliothek aufrufen: ABBILDUNG 8.17 In den Eigenschaften der ComboBox erfahren Sie, dass diese für den „Export für ActionScript“ bereitgestellt wurde. Es wird Zeit, dass wir mal ein bisschen rekapitulieren. Mittlerweile existieren in unserem Script schon zwei Aufrufe für das Zuweisen einer Quelle und das Abspielen des aktuellen Videos. Besser wäre es, wir würden eine Funktion schreiben, welche diese Aufgabe erledigt, dass unser Code so übersichtlicher wird. Die Daten bis zu diesem Punkt finden Sie in der Datei videoplayer_01b.fla (sowie videoplayer_02b.fla), die „bes- ser strukturierte und aufgeräumte Datei“ ist videoplayer_01c.fla (videoplayer_02c.fla). Die neue Funktion loadVideo zum Laden und Abspielen eines Videos erhält zwei Parameter übergeben: function loadVideo(increaseIndex:uint, playVideo:Boolean):void { ... } increaseIndex: ein numerischer Wert, um wie viel der aktuelle videoIndex erhöht oder verringert wird. (Typischerweise ist dieser Wert gleich eins, da nach einem komplett abgespielten Video das nächste Video der Liste abgespielt wird.) playVideo: eine boolesche Variable, die angibt, ob das nun geladene Video auch gleich gestartet werden soll. u u
  • 413.
    K A PI T E L 8400 Die Funktion selbst wird auch dafür Sorge tragen, dass, sofern das Ende der Videoliste erreicht ist, entweder das Abspielen beendet oder von vorne begonnen werden soll (siehe hierzu auch Listing 8.4): function loadVideo(increaseIndex:uint, playVideo:Boolean):void { videoIndex+=increaseIndex; if(videoIndex==videoList.length) { if(loopAtEnd) { videoIndex = 0; } else { mcFinished.visible = true; return; } } myVideoplayer.source = videoList[videoIndex]; if(playVideo) { myVideoplayer.play(); } } Listing 8.9: Die neu eingeführte Funktion entspricht im Wesentlichen Listing 8.4, jedoch wird videoIn- dex um den übergebenen Wert von increaseIndex erhöht und das Video nur dann abgespielt, wenn playVideo==true ist. Somit verändern sich die Eventhandler für die ComboBox (Ereignis CHANGE) und die FLVPlayback-Komponente (Ereignis COMPLETE): function EChange(myEvent:Event):void { videoIndex = myCombobox.selectedIndex; loadVideo(1,true); } function EComplete(myEvent:VideoEvent):void { loadVideo(1,true); } Listing 8.10: Änderungen in den Eventhandlern CHANGE und COMPLETE Zu guter Letzt ändert sich auch die letzte Zeile des Scripts von: myVideoplayer.source = videoList[videoIndex]; in: loadVideo(0,false);
  • 414.
    V I DE O P L AY E R ( A C T I O N S C R I P T 3 . 0 ) 401 8.3.5 Schritt 2: Abspielen einer Liste von Videos (XML) Alternativ zu einer fest vorgegebenen Liste an Videos bietet sich XML als „Listen- Geber“ an. Die XML-Datei können wir im Wesentlichen in ihrer Struktur der Audio-Jukebox entnehmen – in diesem Workshop haben wir uns schon sehr ausführlich mit der Idee des Aufbaus der XML-Struktur befasst. Werfen wir noch einmal einen kurzen Blick auf die Struktur: <?xml version="1.0" encoding="ISO-8859-1" standalone="yes" ?> <Playlist rootDir="videos" autostart="0"> <File src="FestaDucati2006.flv"> <Author>www.tv1.at</Author> <Content>Festa Ducati 2006</Content> <Date>2006-07-08</Date> </File> <File src="Faak2005.flv"> <Author>www.tv1.at</Author> <Content>Motorradtreffen Faak am See 2005</Content> <Date /> </File> <File src="Tattooconvention.flv"> <Author>www.tv1.at</Author> <Content>Tattoo Convention 2006</Content> <Date /> </File> <File src=»Juvenile.flv»> <Author>www.tv1.at</Author> <Content>HipHop-Festival Wels</Content> <Date /> </File> <File src="Dueringer.flv"> <Author>www.tv1.at</Author> <Content>Dueringer ab 4.99</Content> <Date />
  • 415.
    K A PI T E L 8402 </File> </Playlist> Listing 8.11: Die XML-Struktur für die Playlist unseres Videoplayers (Beispieldatei playlist.txt). Sämtliche Videos sind im Verzeichnis „videos“ untergebracht. Wie schön öfter erwähnt, ist einer der großen Vorteile von XML-Dateien, dass es (fast) keine Vorgaben bezüglich des Aufbaus gibt, also auch kein „richtig“ und „falsch“. Aus diesem Grund ist auch die obig dargestellte Struktur nur eine von vielen Möglich- keiten. Alternativ dazu könnte man beispielsweise auch das Attribut src als eigenes Tag führen oder die Tags <Author>, <Content> und <Date> als Attribute führen: ... <File> <src>Video01.flv</src> <Author>Ducati Club Linz</Author> <Content>1. Mai Ausfahrt 2007</Content> <Date>2007-05-01</Date> </File> ... Listing 8.12: Variante 1 ... ... <File src="Video01.flv" Author="Ducati Club Linz" Content="1. Mai Ausfahrt 2007" Date="2007-05-01 /> ... Listing 8.13: ... und Variante 2. Welche Variante Sie bevorzugen, liegt an Ihnen. Da wir die in Abschnitt 8.3.4 erzeugte Liste nun nicht mehr in der damaligen Form benötigen, ändern wir die Zeile var videoList:Array = new Array("videos/Dueringer.flv","videos/Faak2005. flv","videos/FestaDucati2006.flv","videos/Juvenile.flv"); in var videoList:Array = new Array(); um. Somit ist das Array derzeit noch leer – das Füllen des Arrays erledigen wir, nach- dem die XML-Daten aus der entsprechenden Datei gelesen wurden. Weiter unten wird die Definition des Arrays von dieser Stelle entfernt und an eine andere Stelle im Code gesetzt. Wie eine XML-Datei gelesen wird, haben wir sehr ausführlich im Kapitel „Ser- verseitiger Datenaustausch“ gesehen – nun wollen wir die Früchte dessen ernten und das Laden von Videolisten über eine XML-Datei spielen. „Richtige“ und „falsche“ XML- Strukturen? „Richtige“ und „falsche“ XML- Strukturen?
  • 416.
    V I DE O P L AY E R ( A C T I O N S C R I P T 3 . 0 ) 403 Das Grundgerüst stellt sich wie folgt dar: System.useCodePage = true; var myLoader:URLLoader = new URLLoader(); var theURL:String = "URL_ZUR_XML-DATEI"; var myURL:URLRequest = new URLRequest(theURL); var myXML:XML; function EXMLComplete(myEvent:Event):void { myXML = new XML(myEvent.target.data); myXML.ignoreWhitespace = true; ... } myLoader.addEventListener(Event.COMPLETE, EXMLComplete); myLoader.load(myURL); Listing 8.14: Grundgerüst zum Laden von XML-Daten aus einer gegebenen Datei Die wesentlichen Punkte sind also folgende: Zeichensatz auf den in der XML-Datei definierten setzen: System.useCodePage = true; URLLoader-Instanz zum Laden von (textbasierten) Daten anlegen: myLoader URLRequest-Instanz zum Angeben einer Datenquelle anlegen: myURL XML-Objekt definieren, das die geladenen Daten erhält: myXML Eventhandler definieren, der reagieren soll, sobald die Daten aus der Quelle geladen wurden: EXMLComplete. Angewandt auf unser Beispiel muss zunächst einmal nur die Variable theURL gesetzt werden: var theURL:String = "playlist.txt"; Listing 8.15: Es soll die Datei playlist.txt geladen werden. Der einfachste (aber manchen Hardcore-Programmierern eher widerstrebende) Weg zum Laden von XML-Daten ist der, dass der Ladevorgang der XML-Daten in einem Bild der Zeitleiste (oder sogar einer eigenen Szene) und das Abspielen der Videos in einem zweiten Bild erfolgt: u u u u u
  • 417.
    K A PI T E L 8404 Eine weitere Alternative wäre: 1. XML-Daten laden 2. Erst nach dem vollständigen Laden der XML-Daten den Bildschirm inklusive FLVPlayback-Komponente, ComboBox etc. aufbauen Da ich jedoch großen Wert darauf lege, dass die Programmierung noch nachvollzieh- bar und übersichtlich bleibt, möchte ich trotz aller Unkenrufe aus der Hardcore-Pro- grammierer-Abteilung diesen Weg beschreiten. Vor den derzeit vorhandenen Bildern in der Flash-Datei legen Sie bitte daher ein neues Bild an (siehe Abbildung 8.18). In der Elementeebene wurde lediglich der statische Text „Lade XML-File – bitte einen Moment Geduld…“ eingefügt. Die Aktionenebene erhält folgenden Code: // ---- XML-Daten laden: ---- System.useCodePage = true; var videoList:Array = new Array(); var myLoader:URLLoader = new URLLoader(); var theURL:String = "playlist.txt"; var myURL:URLRequest = new URLRequest(theURL); ABBILDUNG 8.18 Laden der XML-Daten und Abspielen der Videos ist in der Zeitleiste in Bildern getrennt.
  • 418.
    V I DE O P L AY E R ( A C T I O N S C R I P T 3 . 0 ) 405 var myXML:XML; function EXMLComplete (myEvent:Event):void { myXML = new XML(myEvent.target.data); myXML.ignoreWhitespace = true; for(var i:uint=0; i<myXML.File.length(); i++) { videoList[i] = myXML.@rootDir+"/"+myXML.File[i].@src; } gotoAndStop(2); } myLoader.addEventListener(Event.COMPLETE, EXMLComplete); myLoader.load(myURL); // ENDE XML-Daten laden: ---- stop(); Listing 8.16: Vollständiges Listing der Aktionenebene (Bild 1) Zu dem in Listing 8.14 vorgestellten Gerüst sind folgende Fragmente hinzugekom- men: Das Anlegen der Videoliste wurde von Bild 2 der Aktionenebene in Bild 1 über- nommen: var videoList:Array = new Array(); Innerhalb des Eventhandler EXMLComplete werden in einer for-Schleife alle File-Knoten durchgegangen und deren Attribut src (aus dem Tag <Playlist>, welches dem Objekt myXML entspricht, da es das Root-Element ist) zusammen mit dem Attribut rootDir in das Array videoList geschrieben. Abschließend wird nach dem Füllen des Arrays auf das zweite Bild der Zeitleiste gesprungen. Im zweiten Bild der Zeitleiste musste aus der Aktionenebene lediglich die Definition der Videoliste gelöscht werden. So weit sollte alles klappen – mehr ist vorerst nicht zu tun: u u u
  • 419.
    K A PI T E L 8406 Details zum Video anzeigen Aus Listing 8.11 können Sie entnehmen, dass neben der Videoquelle noch mehr an Informationen zum Video in der XML-Datei versteckt sind, die es darzustellen gilt. Beispielsweise könnte man die ComboBox aus Abbildung 8.19 mit dem Videotitel (<Content>Tattoo Convention 2006</Content>) statt dem Namen der Quellda- tei füllen. Auch sollten der Autor und das Aufnahmedatum (sofern vorhanden) nicht verschwiegen werden. Bisher war unsere Vorgehensweise folgende: Die Beschriftung (label) innerhalb der ComboBox beinhaltet den Namen der Video-Quelldatei. Der Wert (data) der Combobox war der Index des Videos in der Videoliste video- List. Den Wert werden wir so beibehalten, die Beschriftung soll sich auf den Videotitel ändern. Hierzu müssen wir jedoch ein bisschen weiter ausholen, da wir den Videotitel bisher noch gar nicht gespeichert haben. Daher wird unsere videoList eine kleine Änderung durchmachen müssen: Anstatt nur die Videoquelle zu speichern, speichern wir die videoList gar nicht mehr, sondern greifen direkt auf die eingelesenen XML- Daten in myXML zu! Dank ActionScript 3.0 ist das nun denkbar einfach. u u Titel statt Videoquelle in der ComboBox anzeigen Titel statt Videoquelle in der ComboBox anzeigen ABBILDUNG 8.19 Das Laden der XML-Daten war erfolgreich – alles andere ist wie gehabt.
  • 420.
    V I DE O P L AY E R ( A C T I O N S C R I P T 3 . 0 ) 407 Im Eventhandler zum Laden der XML-Daten entfernen wir folgende Teile komplett: var videoList:Array = new Array(); Listing 8.17: Das Array wird nicht mehr benötigt. for(var i:uint=0; i<myXML.File.length(); i++) { videoList[i] = myXML.@rootDir+"/"+myXML.File[i].@src; } Listing 8.18: Dieser Teil wird aus dem Eventhandler EXMLComplete vollständig entfernt. Beim Füllen der ComboBox (Bild 2 der Aktionenebene) ändern wir die for-Schleife von for(var i:Number = 0; i<videoList.length; i++) { myCombobox.addItem({ label:videoList[i], data:i }); } in for(var i:Number = 0; i<myXML.File.length(); i++) { myCombobox.addItem({ label:myXML.File[i].Content, data:i }); } Listing 8.19: Anstatt auf die videoList zuzugreifen, nehmen wir gleich den Inhalt der XML-Daten aus myXML. myXML.File greift auf alle Knoten mit dem Namen „File“ zu, die wir Eintrag für Ein- trag auslesen, um aus diesen Knoten jeweils auf den Sub-Knoten namens „Content“ zuzugreifen. Am Laden und Abspielen der Videodaten muss auch noch ein bisschen gefeilt werden, da dort immer noch auf die Videoliste videoList zugegriffen wird. In der Funktion loadVideo in Bild 2 der Funktionenebene müssen zwei Änderungen vorgenommen werden. Aus den Zeilen if(videoIndex==videoList.length) { ... myVideoplayer.source = videoList[videoIndex]; wird if(videoIndex==myXML.File.length()) { ... myVideoplayer.source = myXML.@rootDir+"/"+myXML.File[videoIndex].@src; Listing 8.20: Aus videoList.length wird myXML.File.length() und aus dem Inhalt von videoList[i] wird myXML.@rootDir+"/"+myXML.File[videoIndex].@src.
  • 421.
    K A PI T E L 8408 Letzten Endes wurde das Array videoList nicht mehr benötigt, da myXML mehr oder weniger auch als Liste angesehen werden kann. Da der Zugriff auf XML-Daten seit ActionScript 3.0 nun denkbar einfach ist, sollte man davon auch Gebrauch machen. ABBILDUNG 8.20 Nun ist der Inhalt der ComboBox auch informa- tiver und sprechender. Autor und Aufnahmedatum anzeigen Kümmern wir uns noch um die Ausgabe von Autor und Aufnahmedatum. Hier offen- baren sich mehrere mögliche Wege: Es werden dynamische Textfelder angelegt und diese beim Laden einer Videoquelle mit Inhalt gefüllt. Die Textfelder werden nicht vorab angelegt, sondern bei jedem Laden einer Video- quelle neu erzeugt. Sämtliche Informationen werden in einer TextArea-Komponente angezeigt. Wir werden den dritten Weg einschlagen und eine TextArea-Komponente verwen- den, die wir einerseits (videoplayer_01e.fla) direkt auf der Bühne platzieren und ande- rerseits (videoplayer_02e.fla) per ActionScript generieren. Im Fall der direkten Platzierung der TextArea-Komponente auf der Bühne geben wir der Instanz den Namen „videoinfos“ und stellen folgende Eigenschaften um: editable: false horizontalScrollPolicy: off u u u u u
  • 422.
    V I DE O P L AY E R ( A C T I O N S C R I P T 3 . 0 ) 409 Breite: 300 Pixel Höhe: 40 Pixel Position (x/y): (256/436) u u u Die Funktion loadVideo in Bild 2 der Funktionenebene erweitern wir entsprechend um die Zeile function loadVideo(increaseIndex:uint, playVideo:Boolean):void { videoIndex+=increaseIndex; if(videoIndex==myXML.File.length()) { if(loopAtEnd) { videoIndex = 0; } else { mcFinished.visible = true; return; } } videoinfos.text = "Author: "+myXML.File[videoIndex].Author+" nAufnahmedatum: "+myXML.File[videoIndex].Date; myVideoplayer.source = myXML.@rootDir+"/"+myXML.File[videoIndex].@src; if(playVideo) { myVideoplayer.play(); } } Listing 8.21: In die TextArea-Instanz „videoinfos“ werden Autor und Aufnahmedatum geschrieben. Würden wir die TextArea-Komponente hingegen per ActionScript einbinden, müss- ten wir folgendermaßen vorgehen: ABBILDUNG 8.21 Eine Instanz der TextArea- Komponente wurde auf der Bühne in der Elementeebene eingefügt.
  • 423.
    K A PI T E L 8410 TextArea-Komponente in die Bibliothek ziehen Folgenden ActionScript-Code in das zweite Bild der Aktionenebene einbauen: ... // ---- TextArea-Komponente: ---- import fl.controls.TextArea; import fl.controls.ScrollPolicy; var videoinfos:TextArea = new TextArea(); videoinfos.editable = false; videoinfos.horizontalScrollPolicy = ScrollPolicy.OFF; videoinfos.width = 300; videoinfos.height = 40; videoinfos.move(256,436); addChild(videoinfos); // ENDE TextArea-Komponente: ---- loadVideo(0,false); Listing 8.22: Die zwischen den Kommentaren gelisteten Zeilen sind in der Aktionenebene in Bild 2 hinzuge- fügt worden. Zunächst werden die Klassen TextArea und ScrollPolicy aus der Klasse fl.controls hinzugeladen, wobei die erste für das Ansprechen der TextArea und die zweite für das Setzen von Scrollparametern für eine eventuelle Scrollbar zuständig ist. Danach wird eine Instanz der TextArea-Komponente erzeugt (videoinfos) und die benötigten Eigenschaften und Parameter werden gesetzt. Abschließend fügt man die Instanz noch dem DisplayObject zu (addChild(videoinfos);) und hat es auch schon wieder geschafft! Die entsprechenden Dateien finden Sie wie üblich auf der Buch-CD unter den Namen videoplayer_01e.fla und videoplayer_02e.fla. XML-Datei serverseitig aus einer Datenbank generieren Nehmen wir folgenden Fall an: In einer Datenbank wurde Ihnen eine Playlist zuge- wiesen, welcher wiederum eine Liste an Videos angehören. Ein PHP-Script erzeugt bei Übergabe einer Playlist-ID (die Übergabe erfolgt per GET) ein XML-File laut dem bisherigen Aufbau unserer verwendeten XML-Datei (siehe Listing 8.11). Nehmen wir folgende Struktur der Tabellen an: u u
  • 424.
    V I DE O P L AY E R ( A C T I O N S C R I P T 3 . 0 ) 411 Tabelle Feld Typ Details Beschreibung tbl_08playlist idP_Playlist int(11) auto-increment, Primary Key,not null ID der Playlist vcP_Bezeichnung varchar(128) not null Eine interne Playlist- Bezeichnung,die innerhalb der XML-Struktur nicht verwendet wird vcP_Rootdir varchar(128) not null URL zum Root-Verzeichnis der Videos in der Playlist bitP_chk_autostart tinyint(1) not null, Standard = 1 Kennzeichnung,ob Autostart der Playlist an (1) oder aus (0) ist tbl_08videos idP_video int(11) auto-increment, Primary Key,not null ID des Videos fidP_select_ Bezeichnung_Playlist int(11) not null Ein Feld,das als Foreign Key zur Tabelle tbl_08play- list verwendet wird vcP_Src varchar(128) not null URL zur Videoquelle vcP_Content varchar(128) not null Name des Videos vc_Author varchar(64) null Name des Autors (sofern vorhanden) dt_Date date null Aufnahmedatum (sofern vorhanden) tmP_Uploadtimestamp timestamp not null, CURRENT_ TIMESTAMP Timestamp des Eintrags des Videos in die Tabelle Tabelle 8.1: Aufbau der beiden Tabellen für unser Beispiel Eine solche PHP-Datei zum Generieren von XML-Content aus den beiden oben defi- nierten Tabellen könnte folgendermaßen aussehen: function createXML($idP_Playlist) { $dbData = array( "dbServer" => "mysql.syneweb.com", "dbUser" => "usr_mysql2", "dbPWD" => "456mysql!", "dbName" => "db_flashphpajax" ); if(!$conn = mysql_connect($dbData["dbServer"],$dbData["dbUser"],$dbDat a["dbPWD"])) { die('<div class="Error">Der Datenbankserver konnte nicht erreicht werden.<br/>ERROR='.mysql_error().'</div>'); }
  • 425.
    K A PI T E L 8412 if(!mysql_select_db($dbData["dbName"])) { die('<div class="Error">Die Datenbank konnte nicht ausgewaehlt werden.<br/>ERROR='.mysql_error().'</div>'); } $sql = "SELECT * FROM tbl_08playlist WHERE(idP_Playlist=$idP_Playlist)"; $query = mysql_query($sql) or die('<div class="Error">Die Query konnte nicht abgesetzt werden.<br/>ERROR='.mysql_error().'</div>'); $data = mysql_fetch_array($query); $msg = ‚<?xml version="1.0" encoding="ISO-8859-1" standalone="yes" ?>'; $msg.= ‚<Playlist rootDir="'.$data["vc_Rootdir"].'" autostart="'.$data["bitP_chk_autostart"].'">'; $sql = "SELECT * FROM tbl_08videos WHERE(fidP_select_Bezeichnung_ Playlist=$idP_Playlist)"; $query = mysql_query($sql) or die('<div class="Error">Die Query konnte nicht abgesetzt werden.<br/>ERROR='.mysql_error().'</div>'); while($data = mysql_fetch_array($query)) { $msg.= ' <File src="'.$data["vcP_Src"].'"> <Author>'.$data["vc_Author"].'</Author> <Content>'.$data["vcP_Content"].'</Content> <Date>'.$data["dt_Date"].'</Date> </File> '; } $msg.= '</Playlist>'; return $msg; } if(count($_GET)>0 && isset($_GET["idP_Playlist"])) { echo(createXML($_ GET["idP_Playlist"])); } else { echo('<div class="Error">Sie haben keine Berechtigung f&uuml;r diese Site.</div>'); } Listing 8.23: Eine PHP-Datei namens playlist.php erzeugt aus einer Datenbank mit den Tabellen tbl_ 08playlist und tbl_08videos eine XML-Struktur laut den bisherigen Vorgaben.
  • 426.
    V I DE O P L AY E R ( A C T I O N S C R I P T 3 . 0 ) 413 Betrachtet man das Script Schritt für Schritt, so sind folgende Punkte von besonderem Interesse: 1. Sofern an das Script GET-Variablen und im Speziellen die GET-Variable idP_ Playlist übergebenwurden,wirddieFunktioncreateXML mitdieserVariableals Parameter aufgerufen und deren Rückgabewert per echo ausgegeben. Sollte nichts an die Datei übergeben worden sein, so wird eine entsprechende Fehlermeldung ausgegeben. 2. Die Funktion createXML definiert zunächst die für den Connect zu einer Datenbank notwendigen Informationen in dem Array $dbData, stellt danach die Verbindung zum Datenbankserver her und wählt zuletzt die Datenbank aus. Sollte einer dieser Befehle misslingen, endet das Script mit einem die. 3. Danach wird erst einmal aus der Tabelle tbl_08playlist alles ausgelesen, was zur übergebenen Playlist-ID gehört. Dies umfasst neben dem Playlist-Namen (der für unsere Zwecke irrelevant ist) auch das Root-Verzeichnis der Videos (vcP_Rootdir) und die Information zu einem Autostart der Playlist (bitP_chk_autostart).Aus diesen Informationen wird der erste Teil der XML-Struktur erzeugt (dieser wird vollständig in der Variablen $msg gespeichert): $msg = ‚<?xml version="1.0" encoding="ISO-8859-1" standalone="yes" ?>'; $msg.= ‚<Playlist rootDir="'.$data["vc_Rootdir"].'" autostart="'.$data["bitP_chk_autostart"].'">'; 4. Ist dies erfolgt,werden in einem zweiten SQL-Statement aus tbl_08videos sämtliche Videoinformationen zur gegebenen Playlist geladen. Aus diesen Informationen wird in einer while-Schleife der weitere XML-Baum aufgebaut: $msg.= ‚ <File src="'.$data["vcP_Src"].'"> <Author>'.$data["vc_Author"].'</Author> <Content>'.$data["vcP_Content"].'</Content> <Date>'.$data["dt_Date"].'</Date> </File> ‚; 5. Zuletzt wird noch das geöffnete Tag <Playlist> geschlossen und der gesamte String $msg von der Funktion an den Aufrufer zurückgegeben. Das Ergebnis für beispielsweise idP_Playlist=1 sieht dann folgendermaßen aus:
  • 427.
    K A PI T E L 8414 Flash muss demnach eine XML-basierte PHP-Datei playlist.php einlesen, die über einen GET-Parameter die korrekten Daten aus einer Datenbank ausliest. Nun offen- baren sich zwei Wege: 1. Unser Flash-Beispiel wird so aufgebaut, dass immer dieselbe Playlist ausgelesen wird. Das bedeutet, jeder User ruft dieselben Videos ab. 2. Es soll für jeden User eine individuelle Playlist existieren. Daher muss die Flash- Datei so aufgebaut sein, dass sie zunächst auf den Playlist-Parameter wartet (die Flash-Datei muss ja unabhängig von einem User sein) und danach basierend auf diesem Parameter die XML-Daten anfordert. Wir werden zunächst den ersten Teil entwickeln (das ist sehr einfach, da wir nur die URL zur einzulesenden Datei ändern müssen) und uns danach den zweiten Teil vor- nehmen. Fixe Playlist für alle User Dieser Fall ist sehr einfach, denn es macht keinen Unterschied, ob wir eine Textdatei mit XML als Inhalt oder eine PHP-Datei mit XML als Inhalt einlesen. Einzig die Tat- sache, dass wir ab nun eine Server-Umgebung benötigen (PHP ist im Spiel ...), macht die Sache ein wenig aufwändiger. Bauen wir auf der Datei videoplayer_01e.fla auf, so muss lediglich in der Aktionenebe- ne in Bild 1 die Zeile var theURL:String = "playlist.txt"; ABBILDUNG 8.22 Nun wurde die XML-Datei nicht mehr „von Hand“ geschrieben, sondern per PHP aus einer Datenbank und zwei Tabellen erzeugt.
  • 428.
    V I DE O P L AY E R ( A C T I O N S C R I P T 3 . 0 ) 415 in var theURL:String = "playlist.php?idP_Playlist=1"; geändert werden. Testen Sie online und Sie werden sehen, dass sich nichts geändert hat: ABBILDUNG 8.23 Auch mit dynamisch erzeug- ten XML-Daten und online funktioniert der Video-Player prächtig. Die Datei finden Sie unter dem Namen videoplayer_01f.fla (bzw. videoplayer_02f.fla) auf der Buch-CD. Variable Playlist für jeden User individuell Jetzt wird die Sache etwas komplizierter, denn nun muss das umgebende Webdoku- ment zunächst die ID der Playlist an Flash übergeben – erst dann kann Flash die XML- Daten anfordern. Somit muss Flash beigebracht werden, dass es auf das Setzen der Playlist-ID warten muss, bevor die Daten geladen werden. Aus den vorigen Kapiteln wissen wir, dass sich das über das ExternalInterface sehr einfach lösen lässt: Erst wird eine Funktion definiert, die als eine Art „JavaScript-Handler“ dient und danach wird diese Funktion für JavaScript freigegeben. Ebenso muss dafür gesorgt werden, dass erst nach dem Funktionsaufruf auf die XML-Quelle zugegriffen wird. Zunächst die „JavaScript-Handler“-Funktion: function loadXMLVideodata(PlaylistID:Number):void { idP_Playlist = PlaylistID;
  • 429.
    K A PI T E L 8416 nextFrame(); } Listing 8.24: Die Funktion loadXLMVideodata erhält als Übergabeparameter die Playlist-ID von Java- Script. JavaScript wird später auf diese Funktion zugreifen und ihr als Übergabeparameter die zu ladende Playlist-ID übergeben. Diese Übergabevariable wird in der globalen Variablen idP_Playlist gespeichert und danach erfolgt ein Sprung in den nächsten Frame, wo das Laden der XML-Datei erfolgt (an der Stelle, wo die URL zur XML-Datei definiert ist, müssen wir dann noch eine Änderung vornehmen). Die obige Funktion wird mittels des nachfolgenden Codes für JavaScript registriert: import flash.external.*; var idP_Playlist:Number; if(ExternalInterface.available) { try { ExternalInterface.addCallback("loadXMLVideodata",loadXMLVideodata); } catch(myError:Error) { trace("Error: "+myError); } } stop(); Listing 8.25: Die zuvor definierte Funktion loadXMLVideodata wird als sogenannte „Callback-Funktion“ für JavaScript registriert. Die Flash-Datei finden Sie auf der Buch-CD unter dem Namen videoplayer_01g.fla. Um mit der ExternalInterface-Klasse zu arbeiten, muss die entsprechende Klasse flash.external.* importiert werden. Danach wird eine (globale) Variable namens idP_Playlist definiert, der im Weiteren der Übergabewert von JavaScript zugewie- sen wird. Sollte das ExternalInterface verfügbar sein, wird versucht, die Callback-Funk- tion zu registrieren. Schlägt dies fehl, wird per trace eine Fehlermeldung ausgegeben. Danach wird das Script noch abgestoppt, da die Flash-Anwendung so lange mit dem Laden der XML-Daten warten soll, bis es eine Playlist-ID zugewiesen bekommt. Weiter gesprungen und geladen wird im nächsten Frame. Zuletzt muss in Bild 2 in der Aktionenebene noch angegeben werden, wie Flash zu den korrekten Playlist-Daten gelangt: var theURL:String = "playlist.php?idP_Playlist="+idP_Playlist; Listing 8.26: Die korrekte Playlist wird über die Variable idP_Playlist definiert, die beim Laden der XML- Daten an das entsprechende PHP-Script angehängt wird.
  • 430.
    V I DE O P L AY E R ( A C T I O N S C R I P T 3 . 0 ) 417 Damit wäre der Flash-Teil abgeschlossen und wir können uns der XHTML-Aufgabe widmen. Es ist relativ wenig JavaScript-Code notwendig, um die Playlist-ID an Flash zu übergeben. Grundsätzlich gehen wir davon aus, dass die Playlist-ID bereits an die XHTML-Datei per GET übergeben wurde: function sendDataToFlash(idP_Playlist) { var myswf = getFlashElement("myswf"); myswf.loadXMLVideodata(idP_Playlist); } window.onload = function() { sendDataToFlash(<?php echo($_GET["idP_Playlist"]); ?>); } Listing 8.27: Übergabe der per GET definierten Variable idP_Playlist an Flash. Die entsprechende XHTML-Datei hört auf den Namen videoplayer_01g.php. Nachdem die XHMTL-Seite vollständig geladen wurde (window.onload) wird die Funktion sendDataToFlash mit der GET-Variable idP_Playlist als Übergabepa- rameter aufgerufen. Diese Funktion sucht sich zunächst die korrekte Referenz auf die eingebundene SWF-Datei myswf über die Funktion getFlashElement (die Erklärung dazu finden Sie im Kapitel zu AJAX bzw. clientseitigem Datenaustausch) und ruft in dieser SWF-Datei danach die Callback-Funktion loadXMLVideodata mit wiederum idP_Playlist als Übergabeparameter auf. Somit schließt sich der Kreis und Flash hat, was es braucht: die Playlist-ID. Der Vollständigkeit halber hier noch einmal die Funktion getFlashElement: function getFlashElement(elem) { var app = navigator.appName.toLowerCase(); var nav = navigator.userAgent.toLowerCase(); if((app.indexOf("microsoft") != -1 || nav.indexOf("microsoft") != -1) && !Boolean(window["opera"])) { return document.all[elem]; } else { return document[elem]; } } Listing 8.28: Die Funktion getFlashElement findet den korrekten Verweis auf die Flash-Datei – egal, welcher Browser verwendet wird. Alternativ zum Setzen der Playlist-ID basierend auf GET-Variablen könnten wir dem User auch die Möglichkeit geben, die Playlist-ID selbst einzugeben oder aus einer Select-Box selbst zu wählen. Diese Variante ist in der Datei videoplayer_01h.php zu finden. Hierzu entfernen Sie zunächst den window.onload-Teil aus Listing 8.27 und fügen stattdessen den nachfolgenden Code ein:
  • 431.
    K A PI T E L 8418 function setPlaylistID() { var idP_Playlist = document.forms["frmVideoplayer"]. elements["selPlaylist"].value; if(idP_Playlist!=-1) { sendDataToFlash(idP_Playlist); } } Listing 8.29: Setzen der PlaylistID Die Funktion setPlaylistID wird bei einer Auswahl eines Videos aus einer Select- Box aufgerufen. Sofern die Auswahl mit einem Wert ungleich -1 endet (der Wert -1 ist dem Eintrag „Bitte wählen Sie aus:“ zugewiesen), wird die Auswahl an sendData- ToFlash übergeben. Die Select-Box wird per PHP aus der Datenbank erzeugt, indem wir die Tabelle tbl_08playlist auslesen: ... $sql = "SELECT * FROM tbl_08playlist"; $query = mysql_query($sql) or die('<div class="Error">Fehler beim Absetzen der Query.<br/>ERROR='.mysql_error().'</div>'); if(mysql_num_rows($query)>0) { $returner = ' <select name="selPlaylist" id="selPlaylist" onchange="setPlaylistI D();"> <option value="-1">Bitte w&auml;hlen Sie aus:</option> ‚; while($data = mysql_fetch_array($query)) { $returner.= ' <option value="'.$data["idP_Playlist"].'">'.$data["vcP_ Bezeichnung"].'</option> '; } $returner.= '</select>'; } else { $returner = '(kein Zugriff auf die Playlists)'; } echo($returner); Listing 8.30: Auszug aus dem Script zum Auslesen der Tabelle tbl_08playlist, um alle Playlists in eine Select-Box zu schreiben. Der Teil für die Verbindung zur Datenbank wurde weggelassen, da dieses Proze- dere hinlänglich bekannt ist. Die Datei finden Sie auf der Buch-CD unter videoplayer_01h.php.
  • 432.
    V I DE O P L AY E R ( A C T I O N S C R I P T 3 . 0 ) 419 Sollten in der Tabelle Playlists vorhanden sein, wird eine Select-Box selPlaylist mit einem Eintrag „Bitte wählen Sie aus:“ und den restlichen Einträgen aus der Tabelle generiert. Die Werte der Einträge entsprechen den IDs der Playlists (idP_Playlist). Sobald sich eine Änderung in der Auswahl ergibt, wird das Ereignis onchange ausge- löst, das die Funktion setPlaylistID aufruft. Das Ergebnis ist wie folgt: ABBILDUNG 8.24 Flash wartet auf eine Auswahl aus der Select-Box. Sobald eine Auswahl getroffen wurde, lädt Flash die entsprechende Playlist: ABBILDUNG 8.25 Wurde eine Auswahl getrof- fen, lädt Flash die Videos zur Playlist und stellt diese in der ComboBox dar.
  • 433.
    K A PI T E L 8420 AJAX zum Nachladen der Videos Bis zu diesem Zeitpunkt haben wir alle Ziele erreicht, die wir uns gesetzt hatten. Nun wollen wir folgende Erweiterung programmieren: Angenommen, es wurde ein weiteres Video zur Playlist hinzugefügt, während der User gerade die Animation offen hat. Ist dies der Fall, würde der User genau das neue Video nicht in der Playlist sehen, da es ja gerade hinzugekommen ist. Per AJAX hätten wir jedoch sehr einfach die Möglichkeit, Flash mitzuteilen, dass ein neues Video der Playlist hinzugefügt wurde – wir müssen nur per AJAX in regelmäßigen Abständen nachsehen, ob sich etwas an der Playlist geändert hat, und übergeben in diesem Fall die Änderungen an Flash. Die Idee ist, dass bei einem Eintrag eines Videos in die Datenbank ein Timestamp gespeichert wird. Beim Öffnen des Dokuments videoplayer_01i.php wird der neueste Timestamp ausgelesen und clientseitig gespeichert. In regelmäßigen Abständen wird die Tabelle per AJAX abgefragt und nachgesehen, ob es ein aktuelleres Video gibt. Sollte dies der Fall sein, wird eine entsprechende Meldung an Flash übergeben. In den folgenden Abbildungen sehen Sie die Anwendung. Schritt 1: Der User hat eine Playlist („Uwes Playlist 1“) ausgewählt, die derzeit noch vier Videos enthält (Abbildung 8.26). ABBILDUNG 8.26 Es wurde die Playlist „Uwes Playlist 1“ ausgewählt – sie enthält derzeit noch vier Videos. Schritt 2: Zwischenzeitlich wurde in die Datenbank ein neues Video eingetragen. Nach spätestens 60 Sekunden (alle 60 Sekunden fragt AJAX die Datenbank ab) erhält der User eine Meldung innerhalb der Flash-Anwendung, dass ein neues Video zum Abruf bereitsteht (Abbildung 8.27).
  • 434.
    V I DE O P L AY E R ( A C T I O N S C R I P T 3 . 0 ) 421 Schritt 3: Hat sich der User dafür entschieden, das Video in seine Abspielliste zu über- nehmen, wird die Abspielliste entsprechend erweitert (Abbildung 8.28). ABBILDUNG 8.27 Ein neues Video wurde in der Datenbank gespeichert. Der User hat nun die Möglichkeit zu entscheiden, ob er es in seine Playlist (ComboBox) aufnehmen möchte. ABBILDUNG 8.28 Das neue Video („Düringer ab 4,99“) wurde in die Abspielliste aufgenommen. Damit AJAX das aktuellste Video ermitteln kann, benötigt es auf Serverseite ein Script, das genau die benötigten Informationen liefert:
  • 435.
    K A PI T E L 8422 ... $sql = "SELECT tmP_Uploaddatum FROM tbl_08videos WHERE(fidP_select_ Bezeichnung_Playlist=".$_GET["idP_Playlist"].") ORDER BY tmP_Uploaddatum DESC LIMIT 1"; $query = mysql_query($sql) or die('<div class="Error">ERROR='.mysql_ error().'</div>'); $data = mysql_fetch_array($query); echo(strtotime($data["tmP_Uploaddatum"])); ... Listing 8.31: Auszug aus der Datei getnewestvideo.php, der die ID der aktuellen Playlist als GET-Parameter übergibt. Ein geeignetes SQL-Statement ruft das neuesteVideo ab,indem es einen Eintrag (LIMIT 1) aus der Tabelle tbl_08videos abruft, wobei die Ergebnisliste absteigend (also das neu- este zuerst: ORDER BY tmP_Uploaddatum DESC) sortiert ist. Es werden nur Videos abgerufen, die einer gegebenen Playlist angehören (fidP_select_Bezeichnung_ Playlist=".$_GET["idP_Playlist"]). Das Ergebnis wird in einen Timestamp umgewandelt (strtotime($data["tmP_Uploaddatum"])) und ausgegeben. Der JavaScript-Part aus Listing 8.29 wird zunächst um eine Variable firstShow erwei- tert: var firstShow = true; var itv; function setPlaylistID() { var idP_Playlist = document.forms["frmVideoplayer"]. elements["selPlaylist"].value; if(idP_Playlist!=-1) { if(firstShow) { itv = setInterval("sendRequest("+idP_ Playlist+")",60000); } sendDataToFlash(idP_Playlist); } } Listing 8.32: Erweiterung von Listing 8.29 um die Variablen firstShow und itv Die Variable firstShow definiert, ob die Playlist das erste Mal geladen wird oder nicht. Wir benötigen diese Info, damit der Timer (setInterval) für die AJAX- Abfrage gestartet wird, denn bevor eine Playlist das erste Mal gewählt wurde, bringt eine AJAX-Anfrage an den Server zum Überprüfen eventuell neu hinzugekommener Videos nichts. Wurde also eine Playlist ausgewählt, wird ein Intervall (itv) gestar- tet, das alle 60 Sekunden eine Funktion sendRequest mit dem Übergabeparameter
  • 436.
    V I DE O P L AY E R ( A C T I O N S C R I P T 3 . 0 ) 423 idP_Playlist aufruft. Diese Funktion erzeugt eine Anfrage an die Datenbank über das im folgenden Listing dargestellte Script: var myXMLHttpRequest = createRequestObject(); function sendRequest(idP_Playlist) { myXMLHttpRequest.open("GET", "getnewestvideo.php?idP_Playlist="+idP_ Playlist, true); myXMLHttpRequest.onreadystatechange = handleRequest; myXMLHttpRequest.send(null); } Listing 8.33: Anfrage an die Datenbank über die Datei getnewestvideo.php, die als GET-Parameter idP_Playlist übermittelt bekommt. Nachdem eine XMLHttpRequest-Instanz erzeugt wurde (die dafür verantwortliche Funktion createRequestObject wurde im Kapitel zu AJAX hinlänglich beschrieben, deshalb verzichte ich an dieser Stelle auf die Erklärung der Funktion), kann die Verbin- dung zur Datei getnewestvideo.php geöffnet (myXMLHttpRequest.open), der Instanz ein Eventhandler zugewiesen (myXMLHttpRequest.onreadystatechange) und die Anfrage versandt werden (myXMLHttpRequest.send). Der Eventhandler handleRe- quest, der bei jeder Änderung des Status der AJAX-Anfrage aufgerufen wird, stellt sich folgendermaßen dar: function handleRequest() { if(myXMLHttpRequest.readyState==4) { if(firstShow) { firstShow = false; newestVideo = parseInt(myXMLHttpRequest.responseText); } else { proveReturner(myXMLHttpRequest.responseText); } } } Listing 8.34: Der Eventhandler sorgt für den korrekten Aufruf der Funktion proveReturner. Sollte der Eventhandler erkennen, dass die Eigenschaft readyState den Wert 4 hat (Übermittlung der Daten vom Server zur XMLHttpRequest-Instanz abgeschlos- sen), wird zunächst überprüft, ob diese Anfrage das erste Mal stattgefunden hat (firstShow==true). In diesem Fall wird zunächst firstShow=false gesetzt und die Variable newestVideo auf den Rückgabewert von getnewestvideo.php gesetzt (dies ist wie oben beschrieben der Timestamp des neuesten Videos in der Playlist). Da es sich in diesem Fall um den ersten Aufruf der AJAX-Anwendung gehandelt hat, muss auch noch nicht überprüft werden, ob ein neueres Video vorhanden ist (die Videos zur Play-
  • 437.
    K A PI T E L 8424 list wurden gerade zuvor das erste Mal geladen). Sollte hingegen firstShow==false sein, wird die Funktion proveReturner aufgerufen, die als Übergabeparameter den Wert responseText erhält: function proveReturner(timestamp) { if(newestVideo<parseInt(timestamp)) { newestVideo = parseInt(timestamp); var myswf = getFlashElement("myswf"); myswf.newVideoAvailable(); } } Listing 8.35: Die Funktion proveReturner überprüft, ob das neueste Video bereits Bestandteil der schon geladenen Playlist ist. Bei Aufruf von proveReturner wird verglichen, ob der Timestamp des ermittelten Videos größer als der Timestamp des zuletzt (vor 60 Sekunden) ermittelten Videos ist. Ist dies der Fall, wurde also zwischenzeitlich ein neues Video in die Datenbank geschrieben – somit muss Folgendes getan werden: 1. Der Timestamp des somit „neuesten“ Videos muss gespeichert werden, damit man in 60 Sekunden mit diesem Timestamp vergleichen kann: newestVideo = parseInt(timestamp);. 2. Es muss Flash mitgeteilt werden, dass (zumindest) ein neues Video vorhanden ist: myswf.newVideoAvailable();. Ob in den letzten 60 Sekunden ein oder mehrere neue Videos hinzugekommen sind, ist letztlich egal, denn Flash wird seinerseits die komplette Playlist neu laden und erhält somit alle neuen Videos. Der Flash-Teil ist nicht wesentlich aufwändiger, jedoch mussten einige Änderungen in der Struktur vorgenommen werden: 1. Sämtlicher Code befindet sich nun in einem einzigen Bild der Zeitleiste. 2. Der Aufbau der Bühne erfolgt ereignisorientiert: 1. Die Funktion loadXMLVideodata (diese wird von JavaScript aufgerufen) steuert den Aufbau. Sobald sie aufgerufen wird, wird die Funktion loadXML aufgerufen. 2. Sobald für loadXML das Ereignis COMPLETE auftritt („XML-Daten geladen“), wird die Bühne aufgebaut. Da die Funktion loadXML öfter als nur einmal aufgerufen wird (sobald ein neues Video entdeckt wurde und der User dieses neue Video in die Abspielliste aufgenommen hat, wird diese Funktion erneut
  • 438.
    V I DE O P L AY E R ( A C T I O N S C R I P T 3 . 0 ) 425 aufgerufen), müssen wir zwischen dem ersten und allen folgenden Aufrufen unterscheiden: Im Fall des ersten Aufrufs generieren wir eine TextArea-, eine ComboBox- und eine FLVPlayback-Komponente und danach den Inhalt der ComboBox für die Abspielliste. Für alle weiteren Aufrufe wird nur der Inhalt der ComboBox neu generiert. 3. Bei Aufruf der Funktion newVideoAvailable durch JavaScript und positiver Bestätigung der Aufnahme des Videos durch den User wird die Funktion loadXML erneut ausgeführt und das oben beschriebene Prozedere geschieht von neuem. Die Funktion newVideoAvailable setzt zunächst das Infofenster in den Vordergrund (setChildIndex) und blendet es dann ein: function newVideoAvailable():void { var topPosition:uint = numChildren - 1; setChildIndex(mcNewVideoInfo, topPosition); mcNewVideoInfo.visible = true; } Kurz zum Infofenster, sobald ein neues Video von AJAX entdeckt wurde: Der Einfach- heit halber wurde das Infofenster „Ein neues Video ist vorhanden...“ als MovieClip in Flash ausgeführt und nicht per ActionScript erzeugt. Der Code zu den beiden Buttons „Nein“ und „Ja“ ist wie folgt: function cancelNewVideolist(myEvent:MouseEvent):void { mcNewVideoInfo.visible = false; } function loadNewVideolist(myEvent:MouseEvent):void { mcNewVideoInfo.visible = false; loadXML(idP_Playlist); } mcNewVideoInfo.btnNein.addEventListener(MouseEvent.MOUSE_ UP,cancelNewVideolist); mcNewVideoInfo.btnJa.addEventListener(MouseEvent.MOUSE_UP,loadNewVideolist); Listing 8.36: Die Eventlistener der Buttons „Nein“ und „Ja“ für die Aufnahme eines neuen Videos in die Abspielliste Im Fall eines Klicks auf den „Nein“-Button wird lediglich das Infofenster (mcNew- VideoInfo) wieder ausgeblendet, im Fall eines Klicks auf den „Ja“-Button wird zusätzlich (wie oben beschrieben) die Funktion loadXML aufgerufen. Die Variable idP_Playlist ist eine Variable auf root-Ebene und somit „global“. Und dann geht alles seinen Lauf ...
  • 439.
    K A PI T E L 8426 Einen wichtigen Punkt sollte man nicht außer Acht lassen: Browser wie Server neigen dazu, XML-Daten (auch solche, die von PHP erzeugt wurden) im Cache abzulegen. Um dies sehr einfach zu umgehen, hängt man an die XML-Anfrage einen zufälligen String an, sodass dem Server (wie Browser) eine neue Anfrage mit neuen GET-Variab- len vorgegaukelt wird: var dStr:String = "&timestamp="+new Date().getTime(); var theURL:String = "playlist.php?idP_Playlist="+PlaylistID+"&CacheBuste r="+Math.random()+dStr; Listing 8.37: Ein sehr zufälliger String wird an die Anfrage angehängt. Der Zufallsstring setzt sich aus dem aktuellen Datum, der aktuellen Zeit und einer Zufallszahl zwischen 0 und 1 zusammen – das sollte Zufall genug sein ... Die entsprechenden Dateien finden Sie auf der Buch-CD unter folgenden Namen: Flash-Datei: videoplayer_03.fla XHTML-Datei: videoplayer_01i.php XML-basierte PHP-Datei (Playlist): playlist.php Ermitteln neuer Videos in der Datenbank: getnewestvideo.php Include-Datei zum Verbindungsaufbau mit der Datenbank: includes/connectdb.inc. php 8.3.6 Arbeiten mit Cue-Points Hierzu erweitern wir die zuvor entwickelte Flash-Anwendung videoplayer_03.fla und speichern sie unter dem Namen videoplayer_04.fla. Um mit in FLV-Dateien eingebetteten CuePoints zu arbeiten, stellt uns Flash folgende wichtige Eigenschaften, Methoden und Ereignisse zur Seite: MetadataEvent.METADATA_RECEIVED: Dieses Ereignis tritt auf, sobald Meta- daten (dazu gehören auch CuePoints) von der FLV-Datei gelesen werden konnten – dies gilt es abzuwarten. Aus dem Array FLVPlayback.metadata.cuePoints können sämtliche Cue- Points ausgelesen werden. Diese sind darin als Objekte abgelegt: type:String: Typ des CuePoint. Mögliche Werte sind „event“ oder „navigati- on“. Siehe hierzu auch die Ausführungen im Abschnitt 8.3.2. name:String: Name des CuePoint time:Number: Eine auf drei Kommastellen genaue Zahl, die den Zeitpunkt des CuePoint angibt u u u u u u u u u u XML im Cache?XML im Cache?
  • 440.
    V I DE O P L AY E R ( A C T I O N S C R I P T 3 . 0 ) 427 parameters:Object: Ein optionales Objekt (beinhaltet Name-Wert-Paare), das beim Erstellen der CuePoints mit beispielsweise dem Flash Video Encoder erstellt wurde Die wichtigen Parameter sind name und time, sofern man sich über den Typ des CuePoint im Klaren ist. In Flash fügen wir der FLVPlayback-Instanz zunächst einen Eventhandler für das Ereignis METADATA_RECEIVED zu: myVideoplayer.addEventListener(MetadataEvent.METADATA_RECEIVED, EMetadata);´ function EMetadata(myEvent:MetadataEvent):void { loadCuePoints(myVideoplayer.metadata.cuePoints); } Sobald Metadaten vorhanden sind, wird die Funktion loadCuePoints aufgerufen: function loadCuePoints(myData:Array):void { myCombobox2.removeAll(); for(var i:Number = 0; i<myData.length; i++) { myCombobox2.addItem({ label:myData[i].name, data:myData[i].time }); } } Listing 8.38: Laden der CuePoint-Informationen in eine ComboBox In einer for-Schleife werden alle CuePoints durchlaufen, wobei die Beschriftung der ComboBox den Namen des CuePoint (myData[i].name) und der Wert der Combo- Box den Zeitpunkt des CuePoint (myData[i].time) erhält. Um mit dieser ComboBox myCombobox2 überhaupt arbeiten zu können, muss sie natürlich zuvor angelegt werden: var myCombobox2:ComboBox; function createComboBoxCuePoints():void { myCombobox2 = new ComboBox(); myCombobox2.move(44,460); myCombobox2.width = 200; addChild(myCombobox2); myCombobox2.addEventListener(Event.CHANGE, EChange2); } Listing 8.39: Erzeugen der zweiten ComboBox unterhalb der bestehenden ComboBox für die Abspielliste u
  • 441.
    K A PI T E L 8428 Die Funktion createComboBoxCuePoints wird beim Auftreten des COMPLETE-Ereig- nisses beim Laden einer XML-Datei aus der Funktion EXMLComplete aufgerufen: function EXMLComplete(myEvent:Event):void { mcLade.visible = false; myXML = new XML(myEvent.target.data); myXML.ignoreWhitespace = true; if(firstShow) { firstShow = false; createTextArea(); createFLVPlayback(); createComboBox(); createComboBoxCuePoints(); } loadComboBoxData(); } Das Ergebnis spricht wie immer für sich: Viel Spaß beim Umsetzen! ABBILDUNG 8.29 Die geladenen CuePoints, über die man direkt Abschnitte in der FLV-Datei anspringen kann
  • 442.
    Stichwortverzeichnis Symbole $-Zeichen 8 $_GET 261 $HTTP_GET_VARS262 $HTTP_POST_VARS 262 A AC_FL_RunContent 178 ActionScript 1.0 6 ActionScript 2.0 6 ActionScript-Referenz 349 addEventListener 362 Addition 18 Aktionen auslösen 172 all 170 appendChild 290 Array 10, 24 assoziatives 25, 257 attributes 282 auslesen 257 Elementanzahl 36 erstellen 24, 25 indiziertes 24 in Flash 282 Länge 36 superglobales 14 übergeben 45 Attribute 282 Ausgeben von XML-Daten 286 Auskommentieren 7 Automatische Typisierung 13 B Bedingungen 28 break 41 C Cache 426 Caching 53 verhindern 54 Case-sensitive 10 Child 272 childNodes 273 classid 169 clearInterval 351 closdir() 356 codebase 169 contentType 289 continue 41 Cookies 47 Gültigkeit 49 Session 50 setzen 48 Verfallsdatum 49 count () 261 createElement 290 D data 314 Daten an Browser 181 an Flash 168 an Flash senden 172 aus Datenbank 253 Datenbank speichern 295 schreiben 260 übergeben 260 verschicken 241 versenden, GET 260 versenden, POST 262 von Flash auslesen 295 Datenbank auswählen 255 Verbindungsaufbau 255 Datentypen 8, 10 Flash 11 PHP 10 Datum 54 Dekrement 18 die 255 do..while-Schleife 39 Document Object Model 170 DOM 56, 170 E Ebenen Bildnamen 172 embeds 171 Endlosschleife 32 Entwicklung Anforderungen 338 Ereignisbehandlungs- routine 245 Ereignisparameter 245 Ereignisprozedur 245, 250, 341 Ereignisroutinen 341 ExternalInterface 184 available 187 Rekursion 202 F firstChild 273 Flash Datenübergabe 294 JavaScript aufrufen 182 Flash Video Encoder 385 FlashVars 179 FLV-Format 377 FLVPlayback 378 for-Schleife 31 Abbruchbedingung 32 Syntax 33 for...each-Schleife 37 Syntax 37 for...in-Schleife 37, 342 Formulardaten versenden 15 Formulare 176 Daten verschicken 260 function 42
  • 443.
    S T IC H W O R T V E R Z E I C H N I S430 Funktionen 41 Arrays 45 aufrufen 44 deklarieren 42 lokale Variablen 45 G GET 15, 260 getElementById 170 getURL 181 getURL() 260 GET 261 POST 263 Gleichheit strikte 22 Grafiken hochladen 265 Grunddatentypen 11 H hasChildNodes () 274 Header 53 header() 53 HTML JavaScript ausführen 181 HTTP 47 https 49 I id3-Objekt 349 ID3-Tag 338 auslesen 349 if Syntax 28 if-Bedingungen 28 ignoreComments 329 ignoreProcessingInstructions 329 ignoreWhite 271 ignoreWhitespace 329 Inkrement 18 innerHTML 150 int 12 Integer 10 is_dir() 357 J JavaScript 6, 158, 167 Flash ansprechen 172 Flash-Aktion auslösen 172 Wert übergeben 172 K Klammern geschweifte 30 Kommentare 7, 58 einzeilige 7 mehrzeilige 7 Komponente XMLConnector 298 L Ladevorgang fehlgeschlagen 251 wiederholen 244 Lautstärkeregler 353 length 334 list 261 loaded 243, 341 loadVariables 72 LoadVars 72, 165, 225, 241, 243, 263 Daten versenden 264 LoadVars-Klasse 72 LoadVars-Objekt anlegen 263 Variablen anlegen 263 M Modulo 19 MP3 338, 376 streamen 346 Multimedia 338 mysql_fetch_array 257 mysql_pconnect 255 mysql_query 256 mysql_select_db 255 N navigateToURL 323 nodeValue 274 Null 12 O On2VP6 376 onLoad 243, 341 opendir() 356 Operatoren 17, 18 arithmetisch 17 Bit 21 logische 21 Rangordnung 21, 22 Vergleich 22 Zuweisung 18 Ordner öffnen 356 P parsen 266 PDF-Datei hochladen 265 PHP XML generieren 283 PHP-Referenz 15 POST 15, 262 Programmieren objektorientiert 6 R readdir() 356 readyState 127 Referenzdatentypen 11, 12 register_globals 15 Regular Expression 160 responseText 127, 234 responseXML 127, 234 return 43, 45 RSS 72 S Schleifen 31 break 41
  • 444.
    S T IC H W O R T V E R Z E I C H N I S 431 continue 41 Durchläufe 31 send 294 send() 260, 263 sendAndLoad() 264 sendToURL 320 Server Verbindung abgebrochen 244 Session 50 initialisieren 51 löschen 53 Variablen entfernen 53 Variablen speichern 51 Session-ID 50 setInterval 350 setRequestHeader 136 SetVariable 170 SGML 168 Sibling 272 SimpleXML 56 Skins 379 Sonderzeichen 242 Soundobjekt 345 loadSound 346 onSoundComplete 348 SoundTransform 372 Streaming 346 String 9, 10, 262 verketten 261 verknüpfen 20 substr 357 substr() 357 Subtraktion 18 switch Syntax 30 switch-Bedingungen 30 switch-case 30 T TEXT URLLoaderDataFormat 315 text 334 TextArea 175 Textdatei Daten einlesen 241 einlesen 267 toString 270 U uint 12 undefined 12 Ungleichheit strikte 22 URL-Codierung 241, 242 URLLoader 309 URLRequest 309 Usability 253 V Variablen 8 einlesen 241 globale 13 Gültigkeitsbereiche 13 in Arrays 280 lokale 13 nicht deklarierte 14 superglobale 14 Variablendeklaration 8 explizit 9 globale 16 implizit 14 lokale 16 Variablennamen 9 dynamisch erzeugen 277 Variablentypen 9 VARIABLES URLLoaderDataFormat 315 Verzeichnisse auslesen 356 volume 372 W Werte zuweisen 19 WHILE-Schleife 40 Wurzelelement 58, 272 X XHTML 167 XML 56, 168, 233, 266, 325 Arrays auslesen 273 Attribute 339 Attribute auslesen 61 auf Elemente zugreifen 272 auswerten 275 Befehle 266 Child 272 Dokumente 56 einlesen 266 encoding 57 erstellen 62 Gültigkeit 57 Inhalt 57 in String umwandeln 270 Knoten 273, 274 Knoten auslesen 62 Prolog 57 Sibling 272 standalone 57 Syntax 59 versenden 294 version 57 Wohlgeformtheit 57 XML-Attribute speichern 342 XML-Baum 270 in Flash erzeugen 287 XMLConnector 298 xmlDecl 289 XML-Header 287 XMLHttpRequest 125 XML-Klasse 72 XML-konform 268 XML-Objekt 266, 325, 341 XML-Struktur 339 Z Zählvariable 31, 257 Zeitleistenvariablen 13 Zustände 21
  • 445.
    Copyright Daten, Texte, Designund Grafiken dieses eBooks, sowie die eventuell angebotenen eBook-Zusatzdaten sind urheberrechtlich geschützt. Dieses eBook stellen wir lediglich als persönliche Einzelplatz-Lizenz zur Verfügung! Jede andere Verwendung dieses eBooks oder zugehöriger Materialien und Informationen, einschliesslich • der Reproduktion, • der Weitergabe, • des Weitervertriebs, • der Platzierung im Internet, in Intranets, in Extranets, • der Veränderung, • des Weiterverkaufs • und der Veröffentlichung bedarf der schriftlichen Genehmigung des Verlags. Insbesondere ist die Entfernung oder Änderung des vom Verlag vergebenen Passwortschutzes ausdrücklich untersagt! Bei Fragen zu diesem Thema wenden Sie sich bitte an: info@pearson.de Zusatzdaten Möglicherweise liegt dem gedruckten Buch eine CD-ROM mit Zusatzdaten bei. Die Zurverfügungstellung dieser Daten auf unseren Websites ist eine freiwillige Leistung des Verlags. Der Rechtsweg ist ausgeschlossen. Hinweis Dieses und viele weitere eBooks können Sie rund um die Uhr und legal auf unserer Website http://www.informit.de herunterladen