Mit Standard-Web-Tools zur nativen App

Android Apps
mit HTML, CSS und JavaScript
O’Reilly
Jonathan Stark
Deutsche Übersetzung von Lars Schulten
wiwobooks 2.0

Android Apps mit HTML, CSS und JavaScript

Jonathan Stark

Deutsche Übersetzung von Lars Schulten

Beijing Á Cambridge Á Farnham Á Köln Á Sebastopol Á Tokyo

www. .de abrufbar. Köln Belichtung. Dennoch können Fehler nicht vollständig ausgeschlossen werden. Köln Korrektorat: Friederike Daenecke. Der Verlag richtet sich im Wesentlichen nach den Schreibweisen der Hersteller.Die Informationen in diesem Buch wurden mit größter Sorgfalt erarbeitet. CSS and JavaScript bei O’Reilly Media. Zülpich Satz: Thilo Bollmann. Krugzell. Druck und buchbinderische Verarbeitung: Druckerei Kösel. Alle Rechte vorbehalten einschließlich der Vervielfältigung. detaillierte bibliografische Daten sind im Internet über http://dnb. Inc. Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Die Darstellung eines Hammerhuhns im Zusammenhang mit dem Thema Android-Entwicklung ist ein Warenzeichen von O’Reilly Media. Alle Warennamen werden ohne Gewährleistung der freien Verwendbarkeit benutzt und sind möglicherweise eingetragene Warenzeichen. Köln Lektorat: Christine Haite.koeselbuch. www. Inc.d-nb. Kommentare und Fragen können Sie gerne an uns richten: O’Reilly Verlag Balthasarstr. Verlag. 81 50670 Köln E-Mail: kommentar@oreilly.reemers. KG 1. Boston Produktion: Andrea Miß. Übersetzung.de Copyright der deutschen Ausgabe:  2011 by O’Reilly Verlag GmbH & Co. Übersetzung und deutsche Bearbeitung: Lars Schulten.de ISBN 978-3-89721-573-3 Dieses Buch ist auf 100% chlorfrei gebleichtem Papier gedruckt. Krefeld. Bibliografische Information Der Deutschen Nationalbibliothek Die Deutsche Nationalbibliothek verzeichnet diese Publikation in der Deutschen Nationalbibliografie.de Umschlaggestaltung: Karen Montgomery. Reemers Publishing Services GmbH. Autoren und Übersetzer übernehmen keine juristische Verantwortung oder irgendeine Haftung für eventuell verbliebene Fehler und deren Folgen. Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen. Auflage 2011 Die Originalausgabe erschien 2010 unter dem Titel Building Android Apps with HTML.

Für Erica & Cooper .

.

.......... . .. .. ... ... .. ... . .... ...... . .... .... ...... ....... 1 Erste Schritte . .... .......... .. Erste Schritte . . . .... .... . .. .. ......... . 33 33 34 39 53 54 Einen Spritzer Ajax einbringen .... . . .. .. .... .... ... . .. .... .. ... ..... .... .... ..... . . .... .. Dem Home-Screen ein Symbol hinzufügen Was Sie gelernt haben . .. ....... . ... . Etwas Schnickschnack . ... VII IX 1 1 3 Einleitung .. .. ... .. .. .... ..Inhalt Inhalt ..... .. . .. ... . ..... 13 13 14 20 23 25 31 Sie haben keine Website? . . ...... . .. .... .. . ...... .. . .. .... . ......... . ...... ....... . ... ... ... .. . . . ...... . ............... ...... . ...... ...... ........ .... .... 4 Animationen . ... ..... ... . Kurzeinführung in die Webprogrammierung . . .... . .. . ... ... . . . 55 55 59 61 | VII . ... . .. ...... .. .. ... . .. . Das Android-CSS hinzufügen...... . .... ... ........ ..... .... ... .. . Web-Apps im Vergleich zu nativen Apps ... ........ ..... ... . . .. ... .... . ... . .......... ..... .. ........ ...... . ..... . ... . .. ... 2 Elementares Styling ... Die Seite »Tage« hinzufügen ..... . ... ...... .... .. . . . . .. .... . .. ... . .... .. ... . .. . .. ............ ........ ... . . ... . . ... . . ........ .. .... .... ... . Der Verkehrspolizist . .... .. ....... ... .. . . . . . .. . .. . . ...... ...... ....... .... ....... 3 Fortgeschrittenes Styling . .. ...... . . ... . ............ . ... .. ... .. ... ... . ... .. . ... ... . .. Die Seite »Tag« .. .... . . . ... ... ..... .. . .. .... . ...... Was Sie gelernt haben ............ .... . . . .... ........ ... .. .. ..... . .... .... . . . .... ......... . . . . .. ... ....... ... . . . . . Das Android-Look-and-Feel einbringen Mit jQuery erste Verhalten einführen . ... ... .. .. ............ . . .. .. 55 Mit etwas Hilfe von unserem Freund Nach Hause rutschen .. .... . . . . ...... ... .... ..

. . .... ........... . ... .. . .. .......... . ...... . ... Web SQL Database . .... 145 149 151 152 Anhang: Browsererkennung mit WURFL . .......... ..... .. .. . . . .. .. . ... . .. Eine dynamische Manifest-Datei erstellen . .. . ........ ... . ... .. .... ......und -Fallback-Optionen .. ....... .. . . .. ... . ...... ... 62 65 67 69 72 5 Clientseitige Datenspeicherung 73 73 79 94 94 Web Storage .... ....... ...... . .. .. .... .. . . .. .. ... . .. ... . . ....... ..... ....... . .. .. .... ... .. 155 Index ... Was Sie gelernt haben .. ..... .... .Die Seite »Neuer Eintrag« Die Seite »Einstellungen« .. ... .. . .... . ... . . . . . ... .... ... ...... .. .. ...... .. . .. . KiloGap im Emulator installieren ... . . ...... . .. . ... Ein virtuelles Android-Gerät erstellen ... .. .. . Weitere Lektüre ... . . ... ... ....... .. . .. Referenz zu den Web Database-Fehlercodes . ... ... Was Sie gelernt haben ... ...... ... ..... . . . ...... ... .... 145 Die Release-Version der App vorbereiten .... .. .. .... . .. .... . ... ... .. .. . ...... . . .. .... .. .... ...... ... . . .. ... . ....... . . ... .. ..... ... . .... ....... .... .... ... .. Die Teile zusammenfügen jQTouch anpassen . 7 Native Apps.. ..... .. . .. . 113 PhoneGap . . .... ...... ........ . . ... . ... .. . .. .. ...... ... ... . .................. . ... ...... . ...... .... .. . . .. ... ... ... .... .... .... . ... .... ... ... .... . .. ... . .... . .... . ... ....... . .... . ...... . . . . ..... .. Die Umgebung einrichten . ..... . ..... .... . .. ... . .. .. ........ ... Das Gerät mit JavaScript steuern ................ ... . .. . ... Was Sie gelernt haben .... ..... ...... .... .......... 6 Offline gehen ... ... . .. . . . . PhoneGap herunterladen ...... ........ . .. .. ... . 113 115 118 119 121 123 126 131 132 144 8 Die App auf dem Android Market einreichen .... . ... .. .. .... . . .... .. ... ... ... ........ .... .. .. .. KiloGap auf Ihrem Gerät installieren .. ...... ..... ... . .. Debugging ..... ... Das Android SDK herunterladen .. .......... . . . Apps direkt verteilen ..... 159 VIII | Inhalt . ..... ... . . ..... ........ . . KiloGap erstellen .. . . . .. ... .. .. .. . .... ... ....... ...... .... .... . . ... . .... . . . ............ . ..... ....... ...... .. ........ .. .. ... .... . . .. .... . .. .. ........ .... ..... . ..... .. . . Was Sie gelernt haben . .. .... .... .......... . .. . ...... . ........ .... . ..... . .. . ... ..... ... ................ ... ....... .... . . . .. ... . .. ... ............. .. .. .. .... .. .. . ........ ....... . ........... . . ..... . .... .. ..... .... ..... ........... ...... .... Die App auf den Android Market hochladen ........ .. ... 95 95 98 101 107 110 Die Grundlagen des Offline Application Caches Die Online-Whitelist.. . .. ....

Das ist vielleicht die größte Leistung unserer Generation. Immer mehr Android-Geräte der unterschiedlichsten Formen und Größen strömen auf den Markt. Die Entwicklungswerkzeuge sind ausgereift und mächtig. finanzielle und politische Kräfte sorgen für eine beispiellose Fragmentierung der Plattformen – und es ist zu befürchten.Einleitung Dank Handys sind wir von einer Phase. in der auch unerfahrene Entwickler mobile Anwendungen erstellen können. in der beinahe jeder auf die gewaltigen Ressourcen des Webs zugreifen kann. Technische. Für Entwickler ist das eine zweischneidige Angelegenheit. Wenn ich | IX . Trotz ihrer allumfassenden Bedeutung steckt die mobile Informationsinfrastruktur immer noch in den Kinderschuhen. Entwickler. Natürlich sind nicht alle Anwendungsfälle für eine Entwicklung mit Webtechnologien geeignet. und sie laufen auf einer Vielzahl von Plattformen. Googles Android-Betriebssystem ist eine faszinierende Ergänzung im Raum mobiler Informationsverarbeitung. dass Sie Apps mit HTML. wenn auch etwas geekhaft. in der fast niemand Zugang zu Informationen hatte. die sich ebenso gut mit HTML hätten implementieren lassen. in eine Phase gelangt. Telekommunikationsunternehmen und Gerätehersteller sind auf den Android-Zug aufgesprungen. frei und höchst interoperabel. die das Leben von Menschen auf der ganzen Erde erleichtern können. die große und heterogene Gruppen von Personen ansprechen müssen. dass das zunächst einmal noch schlimmer wird. Aber andererseits sind mir schon eine Menge mit nativem Code geschriebene Apps begegnet. Andererseits bedeuten mehr Geräte auch mehr Fragmentierung. Einerseits bedeuten mehr Geräte auch einen größeren Markt. stehen vor einer scheinbar unüberwindlichen Herausforderung: »Wie implementieren wir unsere mobile Vision auf machbare und finanzierbare Weise und erreichen mit ihr eine möglichst große Zahl von Teilnehmern?« In vielen Fällen sind Webtechnologien die Lösung. Im wahren Google-Geiste ist die Plattform offen. CSS und JavaScript erstellen. Der Fragmentierung im Android-Markt können Sie ebenso wie der Fragmentierung im allgemeinen Markt mobiler Technologien dadurch begegnen. Die Kombination der Fortschritte von HTML5 und von Mobilgeräten hat eine Umgebung geschaffen.

Dateinamen und Dateinamenserweiterungen. X | Einleitung .mit Entwicklern spreche. sollten Sie das wahrscheinlich auch tun. Typografische Konventionen In diesem Buch werden die folgenden typografischen Konventionen verwendet: Kursiv Kennzeichnet neu eingeführte Begriffe. sage ich ihnen Folgendes: Wenn Sie Ihre App mit HTML. dass Sie gewisse Erfahrung im Umgang mit HTML. nach Bedarf einige gerätespezifische Funktionen ergänzen und die App dann auf dem Android Market einreichen oder auf Ihrer Website zum Download bereithalten. URLs. Für den größten Teil der Beispiele benötigen Sie nur einen Texteditor und Google Chrome (einen brandaktuellen Webbrowser.com/chrome herunterladen können). Wenn Sie so weit sind. wie Sie Ihre Web-App in eine native App umwandeln. Nichtproportionalschrift Wird für Codebeispiele und im Fließtext für Programmelemente wie Variablen. enthält einfachen SQL-Code. der wörtlich so eingegeben werden muss. Das Android SDK benötigen Sie nur für das PhoneGap-Material in Kapitel 7. Datenbanken. können Sie PhoneGap nutzen. Umgebungsvariablen und Schlüsselwörter verwendet. Der Einsatz offener. E-Mail-Adressen. »Native Apps«. Kapitel 5. um Ihre Web-App in eine native Android-App zu konvertieren. die Sie auf dem Android Market einreichen können. wo immer es geht.google. ist aber nicht unbedingt erforderlich. Klingt gut. CSS und JavaScript (insbesondere mit jQuery haben). in dem ich erläutere. Nichtproportionalschrift fett Kennzeichnet Befehle oder anderen Text. Was Sie für dieses Buch brauchen Dieses Buch vermeidet das Android SDK. den Sie für Mac und Windows unter http://www. die sich nicht sicher sind. die größte Reichweite und die geringsten Kosten. Eine gewisse Vertrautheit mit der SQL-Syntax wäre also ebenfalls hilfreich. standardbasierter Webtechnologien bietet Ihnen die größte Flexibilität. welches Verfahren sie wählen sollen. Datentypen. »Clientseitige Datenspeicherung«. nicht wahr? Wer dieses Buch lesen sollte Ich setze voraus.oder Funktionsnamen. Sie können die App problemlos als Web-App veröffentlichen und dann im Betrieb mit Tausenden realen Anwendern testen und debuggen. CSS und JavaScript erstellen können.

CSS und JavaScript. Verlag und die ISBN. Sie darin zu unterstützen.KAPITÄLCHEN Verwenden wir für GUI-Elemente wie Menüeinträge. können Sie uns gern unter permissions@oreilly. Buttons und andere Schaltflächen. Wenn Sie denken. brauchen Sie keine Genehmigung. zum Beispiel: Android Apps mit HTML. der durch eigene oder aus dem Kontext zu erschließende Werte ersetzt werden muss. solange Sie keine erhebliche Menge an Code reproduzieren. 978-3-89721-573-3. Wenn Sie beispielsweise ein Programm schreiben. wird eine Erlaubnis benötigt. einen Hinweis oder eine allgemeine Anmerkung an. Copyright 2010 O’Reilly Verlag. Ihre Arbeit zu tun. wenn Sie große Teile dieses Buchs in die Dokumentation Ihres Produkts einfließen lassen.com kontaktieren. Einleitung | XI . Nichtproportionalschrift kursiv Kennzeichnet Text. Dieses Symbol zeigt einen Tipp. Das Beantworten von Fragen durch das Zitieren von Texten oder Listings aus diesem Buch ist ohne Genehmigung möglich. Im Allgemeinen dürfen Sie die Quelltexte aus diesem Buch in Ihren Programmen und Dokumentationen nutzen. Sie brauchen uns nicht um Erlaubnis fragen. Ihr Gebrauch der Programmbeispiele fiele nicht in die oben abgegebene Genehmigung. Verwendung der Codebeispiele Dieses Buch ist dazu da. das Teile der Beispiele aus diesem Buch verwendet. Wir begrüßen Quellenangaben. Sollten Sie allerdings eine CD-ROM mit Beispielen aus O’Reilly-Büchern verkaufen oder verteilen. Quellenangaben beinhalten üblicherweise den Titel sowie Autor. Dieses Symbol zeigt eine Warnung an. setzen sie aber nicht voraus. Sie brauchen aber eine Erlaubnis.

PPK. John Allsopp und John Resig für ihre Beiträge zu den Technologien. die großzügig Kommentare und Fragen auf der OFPS-Site zu diesem Buch anboten. Euer Feedback war äußerst hilfreich und willkommen. John Gruber. Tim O’Reilly. Das gefällt mir. Meiner wunderbaren Familie. Sara Czyzewicz und die Schar anderer Menschen. die PhoneGap geschaffen hat und weiterhin unterstützt. der meinen Blick auf das Mobile über die Begeisterung für die neueste und tollste Hardware erweitert hat. Du machst alles möglich. während ich an die Tastatur gekettet war. Mein herzlichster Dank gilt den folgenden Personen für ihre großzügigen Beiträge. Brian kennt die Mobillandschaft seit den Anfangstagen. Brian Jepson und den anderen Mitarbeitern von O'Reilly Media dafür. Ich liebe dich! XII | Einleitung . dass sie das Schreiben dieses Buches zu einer so lohnenden und lehrreichen Erfahrung machten. Ob es etwas Code oder eine Animation der Benutzeroberfläche ist. bis die Sache perfekt ist. Und schließlich an Erica. Der Mannschaft bei Nitobi. es lässt ihm keine Ruhe. meinen Freunden und Kunden für ihr Verständnis und ihre Unterstützung. Joe Bowser. Brian Fling. und für ihre Unterstützung eben dieser Technologien. Er ist ein wunderbarer Autor und außerdem ein äußerst großzügiger Mensch. die dieses Buch möglich gemacht haben. David Kaneda für sein wunderbar obsessives Streben nach Schönheit. Brian LeRoux.Danksagungen Das Schreiben eines Buches ist Teamarbeit.

Was ist eine Webanwendung? Die wichtigsten Kennzeichen einer Web-App sind. Web-Apps im Vergleich zu nativen Apps Zuerst möchte ich klären. Beschleunigungssensor.und Nachteile erörtern. privat oder authentifizierungspflichtig) zugegriffen wird und dass sie für die Eigenarten mobiler Geräte optimiert ist. Kamera usw.) und sind in Java geschrieben. was ich unter Web-App und nativer App verstehe. die in diesem Buch eingesetzt werden.und Nachteile Unterschiedliche Anwendungen stellen unterschiedliche Anforderungen.und Nachteile der beiden Ansätze überblicken. | 1 . In diesem Kapitel werde ich die wichtigsten Begriffe definieren. mich eingeschlossen. die die Fantasie einer Horde von Software-Unternehmern weltweit in Wallung versetzte. dass die Benutzerschnittstelle (UI) auf Basis von Standard-Webtechnologien aufgebaut ist. Was ist eine native App? Im Unterschied dazu werden native Apps auf einem Android-Gerät installiert. dass sie im Android Market verfügbar ist – eine Eigenschaft. Einige Anwendungen sind besser für Webtechnologien geeignet als andere. ist nicht im Android Market verfügbar und wurde nicht in Java geschrieben. haben Zugriff auf die Hardware (Lautsprecher. Eine Web-App wird nicht auf dem Gerät installiert. Wenn Sie die Vor. die Vor. werden Sie leichter und besser entscheiden können. welcher für Ihre Zweck geeigneter ist. dass auf sie über eine URL (öffentlich.KAPITEL 1 Erste Schritte Bevor wir uns ins Spiel stürzen. Vor.und Nachteile der beiden wichtigsten Entwicklungsansätze vergleichen und Ihnen eine Schnelleinführung in die drei grundlegenden Webtechnologieen geben. und die jeweiligen Vor. möchte ich kurz das Spielfeld skizzieren. Das entscheidende Kennzeichen einer nativen App ist jedoch.

• Fehler können im laufenden Betrieb behoben werden. • Der Entwicklungszyklus ist kurz.Hier sind die Vorteile der Entwicklung von nativen Apps: • Unmengen registrierte Kreditkartenbesitzer sind nur einen Klick entfernt. 2 | Kapitel 1: Erste Schritte . dass die Trennlinie zwischen Web-Apps und nativen Apps unscharf wird. ein »Premium-Modell« für Ihre App einzusetzen – Sie gewähren freien Zugriff auf die Web-App und verlangen Gebühren für die funktionsreichere native Version. • Sie können auf alle coolen Hardware-Funktionen des Geräts zugreifen. Für mich ist das die optimale Mischung. Dass ein Android-Gerät immer online ist. die es Webentwicklern ermöglichen. • Es kann kompliziert sein. eine Webanwendung bei Bedarf offline auszuführen.und Webentwicklungsfertigkeiten nutzen. • Sie müssen mit Java entwickeln. • Sie müssen ein eigenes Zahlungssystem einrichten. • Sie können die Ihre vorhandenen Webdesign. das einen Webbrowser besitzt. um eine erweiterte native Version zu erstellen. komplexe UI-Effekte zu erzielen. das Produkt als reine Web-App (für Android und andere Geräte mit modernen Browsern) veröffentlichen und die gleiche Codebasis nutzen. Außerdem entwickeln mehrere externe Projekte – PhoneGap ist das erwähnenswerteste – Lösungen. wenn die Nutzung der App kostenpflichtig sein soll. • Ihre App läuft nur auf Android-Geräten. Welcher Ansatz ist für Sie der Richtige? Jetzt wird es spannend. wenn Sie Android-Entwickler werden wollen. Hier sind die Nachteile der Entwicklung nativer Apps: • Sie müssen zahlen. die auf die Hardware des Geräts zugreifen und möglicherweise über den Android Market verkauft werden kann. Hier sind die Vorteile der Entwicklung von Web-Apps: • Webentwickler können mit den ihnen vertrauten Entwicklungswerkzeugen arbeiten. »Offline gehen«). Web-Apps als native Apps für Android und andere Mobilplattformen zu verpacken. • Ihre App läuft auf jedem Gerät. Es gibt sogar einige wenig bekannte Funktionen des Android-Webbrowsers (siehe Kapitel 6. Ich kann in der mir vertrauten Sprache entwickeln. die es Ihnen ermöglichen. • Der Entwicklungszyklus ist umständlich (stete Wiederholung des Kreislaufs Entwickeln-Kompilieren-Verteilen). Das ist eine ausgezeichnete Möglichkeit. bewirkt. Hier sind die Nachteile der Entwicklung von Web-Apps: • Sie haben keinen Zugriff auf die coolen Hardware-Funktionen des Geräts.

Kurzeinführung in die Webprogrammierung
Die drei Grundtechnologien, die wir zum Aufbau von Web-Apps nutzen werden, sind HTML, CSS und JavaScript. Wir werden uns alle drei kurz vornehmen, damit wir tatsächlich alle auf dem gleichen Stand sind, wenn wir uns an die interessanteren Dinge machen.

Einführung in HTML
Wenn Sie im Web surfen, betrachten Sie im Prinzip gewöhnliche Textdokumente, die sich auf dem Rechner anderer befinden. Der Text in einer normalen Webseite ist in HTMLTags eingebettet, die Ihrem Browser die Struktur des Dokuments anzeigen. Diese Informationen nutzt der Browser, um zu entscheiden, wie die Inhalte sinnvollerweise angezeigt werden sollten. Schauen Sie sich das Webseitenfragment in Beispiel 1-1 an. In der ersten Zeile steht der Text Hallo! in einem Satz von h1-Tags. Beachten Sie, dass das Start-Tag und das End-Tag etwas unterschiedlich sind: Das End-Tag enthält an zweiter Stelle einen Schrägstrich (/), das Start-Tag hingegen nicht. Steht Text in h1-Tags, sagt das dem Browser, dass die eingeschlossenen Wörter eine Überschrift darstellen. Das veranlasst ihn, den Text in großen Buchstaben auf einer eigenen Zeile darzustellen. Es gibt auch h2-, h3-, h4-, h5- und h6-Überschriften-Tags. Je kleiner die Zahl ist, um so wichtiger ist die Überschrift. Der in ein h6-Tag eingebettete Text wird also kleiner dargestellt (weniger hervorstechend also) als Text in einem h3-Tag. Auf das h1-Tag in Beispiel 1-1 folgen zwei Zeilen, die in p-Tags eingeschlossen sind. Diese bezeichnet man als Absatz-Tags. Browser zeigen jeden Absatz auf einer eigenen Zeile an. Ist der Absatz so lang, dass er die Breite des Browserfensters übersteigt, wird der Text umbrochen und auf der nächsten Zeile fortgesetzt. In beiden Fällen wird nach jedem Absatz eine leere Zeile eingefügt, um ihn vom folgenden Seitenelement abzuheben.
Beispiel 1-1: HTML-Auszug
<h1>Hallo!</h1> <p>Danke, dass Sie sich die Zeit nehmen, meine Webseite zu besuchen.</p> <p>Ich hoffe, sie gefallt Ihnen.</p> ¨

Sie können HTML-Tags auch in andere HTML-Tags stecken. Beispiel 1-2 zeigt ein Tag für eine ungeordnete Liste (ul), das drei Listenelemente (li) enthält. In einem Browser erscheint das als Aufzählung, in der jedes Element auf einer eigenen Zeile steht. Wenn Sie ein Tag oder mehrere Tags in einem anderen Tag verschachtelt haben, nennt man die inneren Tags Kindelemente oder Kinder des Eltern-Tags. In diesem Beispiel sind also die li-Tags Kinder des ul-Tags.

Kurzeinführung in die Webprogrammierung

|

3

Beispiel 1-2: Ungeordnete Liste
<ul> <li>Pizza</li> <li>Bier</li> <li>Hunde</li> </ul>

Die bislang behandelten Tags sind alle Block-Tags. Das entscheidende Kennzeichen von Block-Tags ist, dass sie auf eigenen Zeilen angezeigt werden und rechts oder links von ihnen keine weiteren Elemente stehen. Deswegen werden Überschriften, Abschnitte und Listenelemente untereinander und nicht hintereinander auf der Seite dargestellt. Das Gegenstück zu einem Block-Tag ist ein Inline-Tag, das, wie der englische Name anzeigt, in einer Zeile erscheinen kann. Das Emphasis-Tag (em) ist ein Beispiel für ein Inline-Tag. Es sieht so aus:
<p>Ich hoffe, sie gefallt Ihnen <em>wirklich</em>.</p> ¨

Der Urahn aller Inline-Tags – und wahrscheinlich die coolste Eigenschaft von HTML überhaupt – ist das a-Tag. Das »a« steht für Anker, aber ich werde das Tag gelegentlich auch als Link oder Hyperlink bezeichnen. Text, der in einem Anker-Tag steht, kann angeklickt werden, und das Anklicken bewirkt, dass der Browser eine neue HTML-Seite lädt. Um dem Browser zu sagen, welche neue Seite er laden soll, müssen wir dem Tag ein sogenanntes Attribut hinzufügen. Attribute sind benannte Werte, die Sie in ein Start-Tag einfügen können. In einem Anker-Tag nutzen Sie das Attribut href, um den Ort der Zielseite anzugeben. Hier ist ein Link auf die Google-Homepage:
<a href="http://www.google.de/">Google</a>

Sollten Sie es nicht gewohnt sein, so mit HTML zu arbeiten, könnte Ihnen das etwas chaotisch vorkommen. Trotzdem sollten Sie aus dem Zeichensalat die URL der GoogleHomepage herausfischen können. In diesem Buch werden Sie eine Menge a-Tags und href-Attribute sehen. Nehmen Sie sich also einen Augenblick Zeit, um Ihren Kopf und Ihre Augen damit vertraut zu machen, falls Ihnen das nicht auf den ersten Blick einleuchtet.
Bei Attributen muss man verschiedene Dinge beachten. Die unterschiedlichen HTML-Tags unterstützen unterschiedliche Attribute. Sie können einem Start-Tag mehrere Attribute hinzufügen, indem Sie sie mit Leerzeichen voneinander abgrenzen. End-Tags dürfen nie Attribute hinzugefügt werden. Es gibt Hunderte möglicher Kombinationen von Attributen und Tags, doch das ist kein Grund zur Sorge – wir werden uns im gesamten Buch mit nur rund einem Dutzend befassen müssen.

Das HTML-Fragment, das wir betrachtet haben, befände sich normalerweise im bodyAbschnitt eines vollständigen HTML-Dokuments. Ein HTML-Dokument besteht aus zwei Abschnitten: dem Head und dem Body. Im Body geben Sie den Inhalt an, den Ihre Nutzer sehen sollen. Der Head enthält Informationen zur Seite, von denen die meisten für den Nutzer unsichtbar sind. Body und Head stecken immer in einem html-Element. Beispiel 1-3 zeigt unser Fragment im Kontext eines ordentlichen HTML-Dokuments. Im Augenblick enthält der head-Ab4 | Kapitel 1: Erste Schritte

schnitt nur ein title-Element, das dem Browser sagt, welchen Text er in der Titelleiste des Fensters anzeigen soll, und das meta-Element mit dem charset-Attribut, das dem Browser sagt, in welcher Zeichenkodierung das Dokument geschrieben wurde. Es ist erforderlich, damit der Browser Umlaute und andere spezielle Zeichen korrekt darstellt. Der Wert "utf-8" steht für die gängigste Unicode-Kodierung, die von allen modernen (und allen unten aufgeführten) Editoren unterstützt wird. Wenn Sie eine andere Kodierung, ISO 8859-1 beispielsweise, nutzen, müssen Sie den Attributwert entsprechend anpassen.
Beispiel 1-3: Ein vollständiges HTML-Dokument
<html> <head> <title>Meine umwerfende Seite</title> <meta charset="utf-8" /> </head> <body> <h1>Hallo!</h1> <p>Danke, dass Sie sich die Zeit nehmen, meine Webseite zu besuchen.</p> <p>Ich hoffe, sie gefallt Ihnen.</p> ¨ <ul> <li>Pizza</li> <li>Bier</li> <li>Hunde</li> </ul> </body> </html>

Wenn Sie Ihren Webbrowser einsetzen, betrachten Sie gewöhnlich Seiten, die im Internet gespeichert sind. Aber Browser können ebenso gut HTML-Dokumente anzeigen, die auf Ihrer lokalen Maschine gespeichert sind. Um Ihnen zu demonstrieren, was ich meine, lade ich Sie ein, einen Texteditor zu öffnen und den Code in Beispiel 1-3 einzugeben.

Den richtigen Texteditor wählen
Einige Texteditoren sind zum Schreiben von HTML nicht geeignet. Insbesondere sollten Sie Editoren meiden, die für das Rich-Text-Editing gedacht sind, wie Microsoft WordPad (Windows) oder TextEdit (Mac OS X). Editoren dieser Art können Ihre Dateien in anderen Formaten als Klartext speichern, wodurch Ihr HTML beschädigt wird. Wenn Sie mit TextEdit arbeiten müssen, speichern Sie Klartext, indem Sie FORMAT→IN REINEN TEXT UMWANDELN wählen. Unter Windows sollten Sie Notepad statt WordPad nutzen. Wenn Sie nach einem guten Texteditor suchen, empfehle ich Ihnen für den Mac TextMate (http://macromates.com/). Es gibt einen Windows-Klon mit dem Namen E Text Editor (http://www.e-texteditor.com/). Wenn Sie nach etwas Kostenlosem suchen, können Sie auf dem Mac Text Wrangler (http://www.barebones.com/products/TextWrangler/ ) herunterladen. Unter Windows haben Notepad2 (http://www.flos-freeware.ch/notepad2.html) und Notepad++ (http://notepad-plus-plus.org/ ) einen guten Ruf. Linux bringt von Haus aus eine ganze Sammlung von Texteditoren wie vi, nano, emacs und gedit mit.

Kurzeinführung in die Webprogrammierung

|

5

die (von links nach rechts) Rot-. auf Ihrem Desktop unter dem Namen test. d. dass der gesamte Text im body-Element in der Farbe Rot darzustellen ist. auf das drei Paare hexadezimaler Ziffern (0–F) folgen. stellen Browser bestimmte HTML-Elemente in spezifischer Form dar (Überschriften beispielsweise groß und fett. Diese Darstellungsformen sind sehr elementar und sollen im Wesentlichen dafür sorgen. Beispiel 1-4: Eine einfache CSS-Regel body { color: red.. Beispiel 1-4 zeigt eine CSS-Regel. was von der Regel betroffen ist). eine Sprache.html funktioniert ebenfalls.) steuern. die Maßangaben erwarten. und öffnen Sie ihn dann mit Chrome.de/ chrome verfügbar. dass Sie sich nicht einfach welche ausdenken können. Jede Eigenschaft erwartet einen passenden Wert. die dem Browser sagt. nachdem Sie ihn eingegeben haben. color ist die Eigenschaft. sollten Sie Chrome nutzen. Farbgradienten. könnte die Datei aber auch in einem Texteditor oder einem anderen Browser öffnen. die eine hexadezimale Form nutzt: ein Doppelkreuzzeichen (#). Wenn Sie über diese einfache strukturbasierte Darstellung hinausgehen wollen. nutzen Sie Cascading Style Sheets (CSS). Chrome ist für Mac und Windows unter http://google.h.und Blauwerte darstellen (Rot wird als #FF0000 geschrieben). dass der Leser die Struktur und den Inhalt des Dokuments versteht. was angibt. mit der Sie die sichtbare Darstellung eines HTML-Dokuments definieren können. Einführung in CSS Wie Sie gesehen haben. CSS ist eine Stylesheet-Sprache. Ein Doppelklick auf test. aber auch komplexe Dinge wie das Seitenlayout. In diesem Beispiel ist body der Selektor (das. und red ist der Wert der Eigenschaft color. je nachdem. Deckkraft und vieles mehr. -größe und -art (fett.html. Die Deklaration enthält einen Satz von Eigenschaften und ihre Werte.Speichern Sie den Code aus Beispiel 1-3. Eigenschaften. kursiv usw. können Werte wie 10px. Grün. Abschnitte mit einer leeren Zeile danach und so weiter). und die geschweiften Klammern schließen die Deklaration (die Regel selbst) ein. und es gibt eine Menge geeigneter Werte und Formate für Werte für die einzelnen Eigenschaften. wenn Sie Ihre Android-Web-Apps in einem Desktop-Browser testen. Auch wenn Sie nicht mit Mac OS X arbeiten. da Chrome von allen Desktop-Browsern dem mobilen Android-Browser am ähnlichsten ist. indem Sie die Datei auf das Anwendungssymbol für Chrome ziehen oder Chrome öffnen und DATEI →DATEI ÖFFNEN wählen. Sie können mit CSS ganz einfache Dinge wie die Textfarbe. 6 | Kapitel 1: Erste Schritte . Beispielsweise können Sie Farben mit vordefinierten Schlüsselwörtern wie red angeben oder indem Sie die HTML-Notation für Farbcodes verwenden. Das bedeutet. wie Ihr System eingestellt ist. } Eigenschaftsnamen werden von der CSS-Spezifikation definiert.

} Es gibt unterschiedliche Arten von Selektoren. dass die Regel für ein HTML-Tag mit der ID hervorheben gilt. Zusammenfassung: Sie können Elemente über den Tag-Namen (d. . sie gefallt Ihnen. Wenn alle Ihre Hyperlinks (das a-Element) kursiv dargestellt werden sollen.</p> ¨ <ul> <li class="loud">Pizza</li> <li>Bier</li> <li>Hunde</li> </ul> Fügen wir dem CSS für dieses HTML . funktioniert ähnlich. sucht CSS nach einem laut-Tag. weil beide das class-Attribut loud haben. . Beispiel 1-5 zeigt einige gängige Deklarationen. Betrachten Sie das folgende HTML-Fragment: <h1 class="laut">Hallo!</h1> <p>Danke. CSS über eine id anzuwenden. Der Punkt vor dem Selektor . background-color: #808080. } Wollen Sie die Darstellung granularer steuern und nur diejenigen Hyperlinks kursiv darstellen. nutzen Sie die folgende Regel: #hervorheben { background-color: yellow.</p> <p>Ich hoffe. können Sie Ihrem Stylesheet die folgende Regel hinzufügen: a { font-style: italic. .h. font-weight: bold. Lassen Sie den Punkt weg.fehler) oder über eine ID (d.h.laut. Der für die Eigenschaft background-color angegebene Farbcode entspricht dem CSS-Schlüsselwort »gray«. um genauer zu sein). h1 oder p).h. } hinzu. dass eine Regel für HTML-Tags mit dem class-Attribut laut gilt. } Sie können auch angepasste Selektoren definieren. werden Hallo! und Pizza kursiv dargestellt. body.laut ist wichtig – so sagen Sie mit CSS.und/oder class-Attribute hinzufügen.75% oder 1em erhalten. das es in diesem Fragment nicht gibt (das es in HTML nicht gibt. Kurzeinführung in die Webprogrammierung | 7 . über eine Klasse (d.subtil. #hervorheben. meine Webseite zu besuchen. die sich in einem h1-Tag befinden. font-family: Arial. Um dem Inhalt eines hervorhebenAbsatz-Tags einen gelben Hintergrund zu geben. können Sie Ihrem Stylesheet Folgendes hinzufügen: h1 a { font-style: italic. indem Sie Ihren Tags id. font-size: 12px.laut { font-style: italic. dass Sie sich die Zeit nehmen. } Hier sagt das Symbol #. #login. font-style: italic. Beispiel 1-5: Einige gängige CSS-Deklarationen body { color: red.

css Wenn Sie Ihre HTML-Dateien auf Ihrem eigenen Rechner speichern. Nutzen Sie class-Attribute. indem Sie sie verketten (d. Es gibt Unterschiede zwischen class und id.</p> <p>Ich hoffe.#aktion) auswählen. fragen sich aber vielleicht. Und Sie können Ihre Selektoren spezifischer machen. Aber es ist erheblich schneller. h1 a. Elemente über die ID zu wählen als über die Klasse. dass eine ID in meinen Dokumenten doppelt vorkommt. damit ich überhaupt nicht Gefahr laufen kann. body ul . Das href-Attribut in diesem Beispiel gibt einen relativen Pfad an. meine Webseite zu besuchen. wie man ein Stylesheet auf eine HTML-Seite anwendet? Das ist eigentlich ganz einfach! Erst speichern Sie das CSS irgendwo auf Ihrem Server (gewöhnlich im gleichen Verzeichnis wie Ihre HTML-Datei. id-Werte hingegen müssen auf einer Seite eindeutig sein. und nutzen Sie relative Pfade wie in Beispiel 1-6. wie Sie es im Folgenden sehen: http://example. wenn Sie auf einer Seite mehrere Elemente mit dem gleichen class-Wert haben. dass Sie sich die Zeit nehmen. dass ich einfach immer class-Attribute nutzen werde. obwohl Sie sie ebenso gut in ein Unterverzeichnis stecken können). Als ich das zum ersten Mal lernte. Dann binden Sie das Stylesheet im Head des HTML-Dokuments ein. Ein Stylesheet anwenden Jetzt beherrschen Sie die Grundlagen von CSS.css im gleichen Verzeichnis wie Ihre HTMLSeite. wenn Sie zu viel mit Klassenselektoren arbeiten. Beispiel 1-6: Ein CSS-Stylesheet einbinden <html> <head> <title>Meine umwerfende Seite</title> <meta charset="utf-8" /> <link rel="stylesheet" href="screen. sollten Sie die Dinge einfach halten: Stecken Sie die CSS-Datei in das gleiche Verzeichnis wie die HTML-Datei. habe ich mir überlegt.css" type="text/css" /> </head> <body> <h1 class="laut">Hallo!</h1> <p>Danke.h.laut).com/screen. wie Sie es in Beispiel 1-6 sehen.</p> ¨ <ul> <li class="laut">Pizza</li> <li>Bier</li> <li>Hunde</li> </ul> </body> </html> 8 | Kapitel 1: Erste Schritte . Sie können auch absolute Pfade nutzen. Das bedeutet. es verweist auf eine Textdatei namens screen. sie gefallt Ihnen. Es kann sich also auf die Leistung auswirken.

while. } . und dieses spezielle Buch ist so kurz. dass Sie auch Stylesheets einbinden können.B. Änderungen an einer Datenbank vornehmen. unter der sich das HTML-Dokument befindet. Beispiel 1-7: Ein einfaches Stylesheet body { font-size: 12px. damit die Dinge in Bewegung kommen. font-weight: bold. Kurzeinführung in die Webprogrammierung | 9 . was CSS betrifft. } #hervorheben { background-color: yellow. (Es sei denn. JavaScript kann sogar mit dem Webserver in Verbindung treten und z. } h1 a { font-style: italic. ohne ihre Genehmigung einzuholen. Jetzt werden wir JavaScript einbringen.B. Beispielsweise können Sie JavaScript schreiben. ohne dass dazu die aktuelle Seite neu geladen werden muss. Sie sollten jene Datei am gleichen Ort speichern wie die HTML-Datei. auf die Stylesheets anderer zu verweisen. Objekte und alle gängigen Kontrollstrukturen (z. das die Werte in einem Formular darauf prüft. je nachdem. um Elemente der Seite anzuzeigen oder zu verbergen.laut { font-style: italic. wie man ein Dokument mit HTML strukturiert und wie man seine visuelle Darstellung mit CSS ändert. um sie interaktiver und angenehmer für den Nutzer zu machen. Bitte verweisen Sie deswegen nur auf Ihre eigenen Stylesheets. Einführung in JavaScript Sie wissen jetzt. Als kompakten und gründlichen CSS-Crash-Kurs kann ich Ihnen wärmstens CSS – kurz & gut (http://oreilly. Arrays. das einige der grundlegenden Konzepte der Sprache illustriert. die Sie in HTML-Seiten einbetten können. Wie jede moderne Skriptsprache bietet JavaScript Variablen.Beispiel 1-7 zeigt den Inhalt von screen. } Es sollte noch darauf hingewiesen werden. for).css. Sie sitzen hinter dem Steuer. dann könnte es erheblich länger dauern – ich hatte doch nicht etwa »Crash-Kurs« gesagt?).de/catalog/9783897215481) von Eric Meyer (O’Reilly) empfehlen. JavaScript ist eine Skriptsprache. die auf einer anderen Domain vorgehalten werden als der. Eric Meyer ist die letzte Instanz in allem. dass man es problemlos während des allmorgendlichen Staus lesen kann. Beispiel 1-8 zeigt ein JavaScript-Fragment. worauf der Nutzer klickt. font-family: Arial. Es gilt allerdings als sehr unhöflich. ob sie gültig sind. Oder Sie können JavaScript nutzen. if. } a { font-style: italic.

wenn die beiden Werte äquivalent sind). • Das Pluszeichen (+) ist der Verkettungsoperator für Strings (kombiniert zwei Strings). was dort passiert: 1 Definiert ein Array (eine Wertliste) namens nahrung. 4 } else { alert(nahrung[i] + ’ schmecken auch. das prüft. 5 } } Hier ist eine Erläuterung dessen. DOM steht für Document Object Model und bezeichnet in diesem Zusammenhang die Art und Weise. • Code-Blöcke werden in geschweifte Klammern ({}) eingeschlossen. A Achten Sie auf folgende Aspekte der JavaScript-Syntax: • Anweisungen werden mit einem Semikolon (.) beendet.length.) 3 Ein Standard-if. A ¨ 4 Wird angezeigt. das einen Text ändert. die eine Variable namens i mit 0 initialisiert.’).wikipedia. wenn das aktuelle Element des Arrays gleich Apfel ist. wie ein Browser eine HTML-Seite interpretiert. ’Bananen’. ob das aktuelle Element des Arrays gleich ¨pfel ist.org/wiki/Document_Object_Model. Mehr über das DOM erfahren Sie hier: http://en. wenn der Nutzer auf das h1-Element klickt. wenn i größer als die Länge des Arrays nahrung ist – und i bei jedem Schleifendurchlauf um 1 erhöht. dass es mit den Elementen auf einer HTML-Seite interagieren kann (die coolen Jungs bezeichnen das als »DOM-Manipulation«). wenn das aktuelle Element des Arrays nicht gleich ¨pfel ist. • Die Zuweisung der Array-Schlüssel beginnt bei 0. das drei Elemente enthält. 5 Wird angezeigt. 1 for (var i=0. Die für unsere Zwecke wichtigste Eigenschaft von JavaScript ist. ein Beendigungskriterium angibt – hier.Beispiel 1-8: Grundlagen der JavaScript-Syntax ¨ var nahrung = [’Apfel’. • Auf Array-Elemente kann mit der Eckige-Klammern-Notation ([]) zugegriffen werden. ’Orangen’]. i<nahrung. • Das einfache Gleichheitszeichen (=) ist der Zuweisungsoperator (weist einer Variablen einen Wert zu). • Das doppelte Gleichheitszeichen (==) ist der logische Äquivalenzoperator (vergleicht zwei Werte und wird mit wahr ausgewertet. • Variablen werden mit dem Schlüsselwort var deklariert. 10 | Kapitel 1: Erste Schritte . 2 Leitet eine gewöhnliche for-Schleife ein. i++) { 2 ¨ if (nahrung[i] == ’Apfel’) { 3 alert(nahrung[i] + ’ mag ich am liebsten!’). Beispiel 1-9 zeigt ein einfaches JavaScript-Beispiel. (i++ ist eine Kurzform für: »Füge dem aktuellen Wert von i 1 hinzu«.

3 Die sagHallo()-Funktion enthält nur eine einzige Anweisung. Dann kam jQuery. Im düsteren Mittelalter der Webentwicklung boten die unterschiedlichen Browser unterschiedliche Unterstützung für JavaScript. 5 Ende des Script-Blocks.Beispiel 1-9: Ein einfacher Onclick-Handler <html> <head> <title>Meine umwerfende Seite</title> <meta charset="utf-8" /> <script type="text/javascript" charset="utf-8"> 1 function sagHallo() { 2 document. Zusätzlich vereinfacht es auch noch eine Vielzahl von gängigen Aufgaben bei der Webentwicklung. Beispiel 1-10 ist eine jQuery-basierte Neufassung von Beispiel 1-9. Man musste ziemlich viel Aufwand treiben. dass der Text »Klick mich!« durch den Text »Hallo!« ersetzt wird. Zu jener Zeit war die Webprogrammierung mit JavaScript die Hölle. } 4 </script> 5 </head> <body> <h1 id="foo" onclick6="sagHallo()">Klick mich!</h1> </body> </html> 3 Hier ist die Erläuterung: 1 Ein Script-Block im Head eines HTML-Dokuments. Als die Zahl der Browser und Browser-Versionen wuchs. die es Ihnen ermöglicht. der in Safari 2 lief. um die einzelnen Browser (oder gar spezifische Versionen einzelner Browser) zu testen. Kurzeinführung in die Webprogrammierung | 11 . im Dokument nach einem Element mit der ID foo zu suchen und seinen HTML-Inhalt auf Hallo! zu setzen. wenn man sicherstellen wollte.getElementById(’foo’). 2 Diese Zeile im Script-Block definiert eine JavaScript-Funktion namens sagHallo(). die den Browser anweist. Ihren JavaScript-Code so zu schreiben.innerHTML = ’Hallo!’. Aus diesen Gründen nutze ich bei den meisten meiner Webentwicklungsaufgaben jQuery und werde es auch für die JavaScript-Beispiele in diesem Buch nutzen. dass er auf die gleiche Weise in einer großen Vielzahl von Browsern läuft. dass der eigene Code tatsächlich in allen Browsern lief. jQuery ist eine verhältnismäßig kleine JavaScript-Bibliothek. Das bewirkt im Browser. wurde es zunehmend unmöglich. 4 Ende der Funktion sagHallo(). Das hieß. nicht notwendigerweise auch im Internet Explorer 6 lief. wenn der Nutzer auf das entsprechende h1-Element klickt. 6 Das onclick.Attribut des h1-Elements sagt dem Browser. dass Code. den eigenen JavaScript-Code für alle Umgebungen zu testen und zu pflegen. wenn der Nutzer auf das h1-Element klickt. In diesem Fall soll er die Funktion sagHallo() ausführen. was er tun soll.

com. wie es Beispiel 1-9 zeigt. Sie können sie jedoch auch direkt von unterschiedlichen Internetorten einbinden. Später werden Sie noch eine Menge praxistauglicher jQuery-Beispiele sehen. Sie nutzt einen relativen Pfad. Das heißt. aber ich kann Ihnen versichern.js umbenennen und eine Kopie in das Verzeichnis stecken. wenn die jQuery-Bibliothek. nicht vorhanden ist).Beispiel 1-10: jQuery-Onclick-Handler <html> <head> <title>Meine umwerfende Seite</title> <meta charset="utf-8" /> <script type="text/javascript" src="jquery. müssen Sie die Datei dort herunterladen.js-Bibliothek ein. in dem sich auch Ihr HTML-Dokument befindet.min.js oder so ähnlich) in jquery.text(’Hallo!’). dass sich die Datei im gleichen Verzeichnis befindet wie die Seite. die heruntergeladene Datei (sie heißt jquery-1. dass es bei komplexen Lösungen ein wahrer Lebensretter sein kann. die sie nutzt (dieses Beispiel funktioniert nicht korrekt.js. 2 Beachten Sie. 12 | Kapitel 1: Erste Schritte . Bei einem derart trivialen Beispiel scheint das keine große Sache zu sein. jquery. Für den Augenblick werde ich es deswegen dabei belassen. an denen sie vorgehalten wird. 2 } </script> </head> <body> <h1 id="foo" onclick="sagHallo()">Klick mich!</h1> </body> </html> 1 1 Diese Zeile schließt die jquery. jQuery-Downloads. Wenn Sie jQuery so nutzen wollen. um den Text im h1-Element zu ersetzen.2. -Dokumentation und -Einführungen finden Sie unter http://jquery. den wir benötigen.js"></script> <script type="text/javascript" charset="utf-8"> function sagHallo() { $(’#foo’). wie deutlich der Code reduziert wurde.4.

• Sie können Ihre Webseiten auf einem Webserver hosten. Sie nähern sich damit nicht nur dem Ziel. dass Ihr Internet Service Provider (ISP) zusätzlich Webhosting bietet. eine native Anwendung aufzubauen. dass Sie die Beispiele ausprobieren können. Dazu müssen Sie einen Server aufsetzen. die für die Darstellung auf einem Android-Gerät angemessen ist.us/ ) bieten grundlegende Webdienste mit PHP-Unterstützung für zwischen 5 und 10 E im Monat. laden Sie sie einfach neu in einem Browser (vorzugsweise dem Android-Browser). wenn Sie einem der Beispiele etwas Neues hinzufügen. der auf Ihrem eigenen Rechner läuft. wenn sich Ihr Android-Gerät und Ihr Rechner im gleichen Drahtlosnetzwerk befinden. CSS und JavaScript eine native Android-App zu erstellen. welche Option zur Betrachtung der Webseiten Sie wählen.KAPITEL 2 Elementares Styling Unser endgültiges Ziel ist. Wenn wir Kapitel 6. Der erste Schritt auf dieser Reise besteht darin. dass es wie eine mobile App wirkt. und sich mit Ihrem Android-Gerät mit diesem Webserver verbinden. erreichen. dass wir uns damit vertraut machen. während Sie es durcharbeiten. wie Laughing Squid (http://laughingsquid. Sie sollten deswegen nach einem preiswerten Webhoster suchen. die auf einem Webserver läuft. Viele Unternehmen. wie man HTML so stylt. PHP ist eine Skriptsprache. werden wir PHP nutzen müssen. In diesem Kapitel werde ich Ihnen zeigen. um bestehenden HTML-Seiten eine Gestalt zu geben. mit HTML. dass | 13 . In der Regel unterstützt das allerdings nur grundlegende Funktionen wie HTML. Das funktioniert aber nur. können Sie sie nicht auf Ihrem Android-Gerät betrachten. Ganz gleich. wie Sie CSS-Styles einsetzen. Es ist recht wahrscheinlich. Folgende Optionen stehen Ihnen zur Verfügung: • Sie können Ihre Webseiten auf einem Webserver hosten und sich mit Ihrem AndroidGerät mit ihm verbinden. Sie haben keine Website? Sollten Sie Ihre Webseiten auf Ihrem lokalen Rechner testen. »Offline gehen«. Dieses Kapitel ist so aufgebaut. Sie sollten allerdings darauf achten. die Sie unmittelbar einsetzen können. sondern erwerben zugleich eine praktische (und wertvolle) Fertigkeit.

Sie Ihre Seiten im Texteditor gespeichert haben, bevor Sie sie mit dem Browser neu laden, denn sonst werden Sie keine Änderungen sehen.

Einen Webserver lokal ausführen
Alle aktuell relevanten Betriebssysteme ( Linux, Windows, Mac OS X) bringen irgendeine Form von Webserver mit. Öffnen Sie unter Mac OS X die Systemeinstellungen, wählen Sie Sharing, und aktivieren Sie WEB-SHARING. Haben Sie das Web-Sharing gestartet, zeigen Ihnen die Web-Sharing-Einstellungen die URL Ihrer persönlichen Website an (diese schließt alles ein, dass Sie im Websites-Unterverzeichnis Ihres Benutzerverzeichnisses abgelegt haben). Die URL hat die Form http://lokaler_Hostname/~Ihr_Benutzername. Unter einigen Linux-Versionen wie Ubuntu müssen Sie einige zusätzliche Schritte vornehmen, um einen Webserver zu installieren und zu aktivieren. Erst installieren Sie über die Kommandozeile mit dem Befehl sudo aptitude install apache2 Apache. Dann aktivieren Sie das Benutzerverzeichnis-Modul mit sudo a2enmod userdir. Haben Sie das erledigt, starten Sie Apache mit folgendem Befehl neu: sudo /etc/init.d/apache2 restart. Anschließend können Sie in Ihrem Benutzerverzeichnis ein Verzeichnis mit dem Namen public_html erstellen und auf alle Dateien darin über eine URL der Form http://lokaler_Hostname/~Ihr_Benutzername zugreifen. Unter Windows ist die Sache etwas komplizierter. Sie müssen eine Windows-Version nutzen, die die Internet Information Services (IIS) enthält. Diese aktivieren Sie über die WINDOWSKOMPONENTEN HINZUFÜGEN ODER ENTFERNEN-Option der Systemsteuerungskomponente SOFTWARE. Nachdem Sie das getan haben, können Sie Ihre Webdokumente ins Dokumentenwurzelverzeichnis des IIS stecken, das sich üblicherweise unter C:\inetpub\wwwroot befindet. Wenn Sie auch unter Windows den Apache-Webserver vorziehen, sollten Sie sich eines der vorkonfigurierten Pakete wie EasyPHP (http://www.easyphp.org/ ) ansehen oder einen Blick auf die Wikipedia-Seite zu diesem Thema werfen: http://en.wikipedia.org/wiki/Comparison_of_WAMPs.

Erste Schritte
Theorie ist nett, aber da ich eher der »Red' nicht, zeig's mir«-Typ bin, sollten wir jetzt doch langsam mal zur Sache kommen. Stellen Sie sich vor, Sie haben eine Webseite, die Sie »mobil machen« wollen (Abbildung 2-1). Wenn das der Fall ist, können Sie einige einfache Dinge tun, um eine Site für Android zu optimieren. In diesem Kapitel werde ich die Möglichkeiten durchgehen, die Ihnen zur Verfügung stehen. Abbildung 2-2 zeigt, wie diese Webseite auf einem Android-Gerät aussieht. Man kann sie nutzen, aber auf die Anforderungen eines Android-Geräts ist sie eigentlich nicht zugeschnitten.

14

|

Kapitel 2: Elementares Styling

Beispiel 2-1 zeigt eine verkürzte Version der Website in Abbildung 2-2. Das ist das HTML, mit dem wir in diesem Kapitel arbeiten werden. Sie können es von der Webseite zum Buch (http://www.oreilly.de/catalog/9783897215733) herunterladen, wenn Sie sich selbst im Stylen versuchen wollen, während Sie das Kapitel durchgehen. Das Desktop-Stylesheet (screen.css) wird hier nicht gezeigt, da es nicht relevant ist. Aber Sie können das Stylesheet aus dem letzten Kapitel nehmen, wenn Sie etwas zum Spielen brauchen.

Abbildung 2-1: Die Desktop-Version einer Standard-Webseite in Chrome auf dem Desktop Beispiel 2-1: Das HTML-Dokument, das wir stylen werden
<html> <head> <link rel="stylesheet" href="screen.css" type="text/css" /> <meta charset="utf-8" /> <title>Jonathan Stark</title> </head> <body> <div id="container"> <div id="header"> <h1><a href="./">Jonathan Stark</a></h1> <div id="utility"> <ul> <li><a href="about.html">Info</a></li>

Erste Schritte

|

15

<li><a href="blog.html">Blog</a></li> <li><a href="contact.html">Kontakt</a></li> </ul> </div> <div id="nav"> <ul> <li><a href="consulting-clinic.html">Consulting-Klinik</a></li> <li><a href="on-call.html">Bereitschaftsdienst</a></li> <li><a href="development.html">Entwicklung</a></li> <li><a href="http://www.oreilly.com">O’Reilly Media, Inc.</a></li> </ul> </div> </div> <div id="content"> <h2>Info</h2> <p>Jonathan Stark ist Webentwickler, Redner und Autor. Zu den Kunden seines ConsultingUnternehmen, Jonathan Stark Consulting, Inc., zahlen unter anderem Staples, Turner ¨ Broadcasting und die PGA Tour. ... </p> </div> <div id="sidebar"> <img alt="Manga-Portrait von Jonathan Stark" src="jonathanstark-manga-small.png"/> <p>Jonathan Stark ist Entwickler fur Mobil- und Webanwendungen und wurde vom Wall Street ¨ Journal als Experte fur die Veroffentlichung von Desktop-Daten im Web bezeichnet.</p> ¨ ¨ </div> <div id="footer"> <ul> <li><a href="services.html">Dienste</a></li> <li><a href="about.html">Info</a></li> <li><a href="blog.html">Blog</a></li> </ul> <p class="subtle">Jonathan Stark Consulting, Inc.</p> </div> </div> </body> </html>

Jahrelang nutzten Webentwickler Tabellen, um Elemente in einem Raster anzuordnen. Fortschritte in CSS und HTML haben dieses Verfahren nicht nur überflüssig, sondern gar unerwünscht gemacht. Heutzutage nutzen wir hauptsächlich div-Elemente (mit einer Vielzahl von Attributen), um bei besseren Steuerungsmöglichkeiten das Gleiche zu erreichen. Obwohl eine vollständige Erklärung div-basierter Layouts den Horizont dieses Buches deutlich übersteigt, werden Sie beim Lesen dieses Buches viele Beispiele dafür finden. Wenn Sie mehr wissen wollen, sollten Sie das Buch Designing with Web Standards von Jeffrey Zeldman (New Rider Press) lesen, das das Thema mit großer Ausführlichkeit behandelt.

16

|

Kapitel 2: Elementares Styling

eindeutige und authoritative Repräsentation in einem System haben!« Der Begriff wurde von Andrew Hunt und David Thomas in ihrem Buch The Pragmatic Programmer (Addison-Wesley Professional) geprägt. alle CSS-Regeln in ein einziges Stylesheet zu zwängen. und legen Sie zwei eigenständige Dateien an – das wird Sie ruhiger schlafen lassen. dass Sie einen Berg irrelevanter Desktop-Style-Regeln an ein Handy versenden und damit wertvolle Bandbreite und Speicherplatz vergeuden. aber das ist aus mehreren Gründen wenig empfehlenswert.Abbildung 2-2: Desktop-Versionen von Webseiten sehen auf Android-Geräten ordentlich aus. Glauben Sie mir einfach.css" media="screen and (min-width: 481px)" /> Erste Schritte | 17 . Ein separates Android-Stylesheet vorbereiten Auch wenn ich ebenso DRY wie alle anderen bin. Die Alternative ist. Um ein spezielles Stylesheet für Android anzugeben. aber das geht noch erheblich besser. einen klaren Trennstrich zwischen Desktop-Stylesheets und AndroidStylesheets zu ziehen. ersetzen Sie das Link-Tag in unserem HTML-Beispiel durch eines mit den folgenden Ausdrücken: <link rel="stylesheet" type="text/css" href="android.css" media="only screen and (max-width: 480px)" /> <link rel="stylesheet" type="text/css" href="desktop. DRY steht für »Don’t Repeat Yourself« (»Vermeiden Sie Wiederholungen«) und ist ein Prinzip der Softwareentwicklung. ist es im wahren Leben häufig empfehlenswert. Der offensichtlichste Grund ist. das besagt: »Jedes Wissenselement muss eine einzige.

der auf die Desktop-Version des CSS verweist: <link rel="stylesheet" type="text/css" href="android. können Sie das Stylesheet aus dem letzten Kapitel nutzen.css" media="all" /><![endif]--> Jetzt wird es Zeit. müssten Sie screen. die größer als 480 px sind (Tablets beispielsweise). Kann es nicht geladen werden. dass die Mobilversion der Seite erscheint. Unglücklicherweise versteht der Internet Explorer diese Ausdrücke nicht. die Sie nutzen können. dass Sie das HTML-Dokument bearbeiten (sollten Sie das nicht schon während des Lesens gemacht haben): Löschen Sie das vorhandene link-Element.oder einem Desktop-Browser aufrufen. Wenn Sie Android-Geräte erkennen müssen. So wird immer die Android-Version der Seite geladen.css zeigt. Wenn Sie es vorziehen. Aber wenn Sie Chrome nutzen möchten.css umbenennen. sollten Sie stattdessen max-device-width und min-device-width nutzen.css eigentlich in desktop. können Sie die WURFL PHP API nutzen. Wir müssen also einen bedingten Kommentar einfügen (das.css durch einen Verweis auf android.max-width und min-width habe ich hier genutzt. sollten Sie den Verweis auf desktop. oder wenn Sie nicht möchten. 18 | Kapitel 2: Elementares Styling . das auf screen. damit Sie Ihren DesktopBrowser nur verkleinern müssen. um eine Vielzahl von Drahtlosgeräten zu identifizieren. Aber da wir uns hier auf das Android-Stylesheet konzentrieren. desktop. unabhängig davon. Wenn Sie die Diskussion anhand des Beispieldokuments in Beispiel 2-1 nachvollziehen. und ersetzen Sie es durch die angegebenen Zeilen.css erhalten. android. So haben Sie freie Bahn für das Android-spezifische CSS in diesem Kapitel. Die Wireless Universal Resource File (WURFL) enthält Informationen. Die Datei desktop.css" media="only screen and (max-width: 480px)" /> <link rel="stylesheet" type="text/css" href="desktop. dass Desktop-Nutzer unabhängig von der Größe Ihres Browserfensters das Stylesheet desktop. um sich die mobile Version einer Seite anzusehen. die wir uns gleich gründlicher ansehen werden.css ist nicht notwendig. Mehr Informationen zu WURFL finden Sie im Anhang.css ist das alte Desktop-Stylesheet.css ersetzen. ob Sie sie in einem Handy. aber wenn Sie möchten. was fett dargestellt wird).css" media="screen and (min-width: 481px)" /> <!--[if IE]> <link rel="stylesheet" type="text/css" href="explorer. wenn Nutzer ihr Browserfenster kleiner als 480 px machen.css eine neue Datei. können Sie es auch vollständig ignorieren. um spezifische Browser präzise zu erkennen. Android-Geräte eingeschlossen. wird sich Ihr Browser nicht weiter aufregen. um die Android-optimierte Version der Seite zu betrachten.

css verwenden. müssen Sie das dem Mobilbrowser sagen.Die Skalierung der Seite steuern Wenn Sie nichts anderes sagen. Sie können es also einschließen. um Ihre Seiten für Android-Nutzer erheblich angenehmer zu gestalten (Abbildung 2-4). Aber wir wollen mehr als das: Wir wollen sie beeindrucken und werden dazu jetzt das Stylesheet android. geht der Android-Browser davon aus. ohne dass Sie sich Gedanken über die Desktop-Version Ihrer Seite machen müssen. Aber wenn Sie den Inhalt speziell für die kleineren Ausmaße eines Android-Handys formatieren. dass eine gewöhnliche Webseite 980 px breit ist. Abbildung 2-3: Android geht davon aus. Erste Schritte | 19 . indem Sie dem head-Element im HTML ein viewport-meta-Tag hinzufügen: <meta name="viewport" content="user-scalable=no. width=device-width" /> Desktop-Browser ignorieren das viewport-meta-Tag. In den meisten Fällen funktioniert das wunderbar. dass Ihre Seite 980 px breit ist (Abbildung 2-3). das Desktop-Stylesheet zu unterdrücken und den Viewport zu konfigurieren. Es reicht schon aus.

und fügen Sie den Code ein. mit der Ihre Anwendung dargestellt wird. welche Vergrößerung dabei gewählt wird. die die Anpassung der Vergrößerung ermöglicht.Abbildung 2-4: Setzen Sie »viewport« auf die Breite des Geräts. Die Optionen sind KLEIN. Auch wenn Sie die Viewport-Breite festlegen. macht das Ihre Seiten auf Android erheblich lesbarer. MEDIUM (der Standard) und GROß. In nächsten Abschnitt werden wir die charakteristische Titelleiste mit abgerundeten Ecken ergänzen. Es ist schwer. da der Android-Browser eine Option bietet. wird die Seite beim Laden vergrößert. fingerfreundliche Links. Erstellen Sie mit einem Texteditor Ihrer Wahl eine Datei namens android. wirken sich diese Benutzereinstellungen auf die Vergrößerung aus. 20 | Kapitel 2: Elementares Styling .css. den Sie in Beispiel 2-2 sehen. Wenn Sie die Viewport-Breite nicht setzen. die eine Android-App zu einer Android-App macht. Das Android-CSS hinzufügen Es gibt eine Reihe von UI-Konventionen (Benutzerschnittstellenkonventionen). die wie schimmernde Buttons aussehen usw. genau zu sagen. Speichern Sie dann die Datei im gleichen Verzeichnis wie Ihr HTML-Dokument.

Beispiel 2-2: Einige allgemeine seitenweite Styles auf dem HTML-Body-Element
body { background-color: #ddd; color: #222; font-family: Helvetica; font-size: 14px; margin: 0; padding: 0; } /* Hintergrundfrage */ /* Vordergrundfarbe fur den Text */ ¨

/* Der Freiraum außerhalb des Bodys */ /* Der Freiraum innerhalb des Bodys */

Text wird unter Android immer mit einer eigenen Schrift namens Droid dargestellt. Die Schriftfamilie Droid wurde speziell für die Verwendung auf mobilen Geräten geschaffen. Sie bietet ausgezeichnete Zeichensatzunterstützung und enthält drei Varianten: Droid Sans, Droid Sans Mono und Droid Serif. Die Schriftfamilie Helvetica, die wir angegeben haben, wird sich also nur auf anderen Geräten als Android-Geräten angezeigt.

Gehen wir jetzt das Header-div an, das den übergeordneten Verweis auf die Homepage enthält (d.h. den Logo-Link) sowie die primäre und sekundäre Site-Navigation. Der erste Schritt ist, den Logo-Link als eine anklickbare Titelleiste zu formatieren. Fügen Sie Folgendes der Datei android.css hinzu:
#header h1 { margin: 0; padding: 0; } #header h1 a { background-color: #ccc; border-bottom: 1px solid #666; color: #222; display: block; font-size: 20px; font-weight: bold; padding: 10px 0; text-align: center; text-decoration: none; }

Wir werden die ul-Blöcke für die primäre und die sekundäre Navigation gleich formatieren, können also allgemeine Tag-Selektoren (d.h. #header ul) statt Tag-IDs (d.h. #header ul#utility, #header ul#nav) verwenden:
#header ul { list-style: none; margin: 10px; padding: 0; } #header ul li a { background-color: #FFFFFF; border: 1px solid #999999; color: #222222; display: block; font-size: 17px;

Das Android-CSS hinzufügen

|

21

font-weight: bold; margin-bottom: -1px; padding: 12px 10px; text-decoration: none; }

Bislang war das recht simpel, nicht wahr? Mit ein paar Strichen CSS haben wir schon eine große Verbesserung des Android-Seiten-Designs erreicht (Abbildung 2-5). Fügen wir jetzt dem Inhalt und den Sidebar-divs etwas Padding hinzu, um den Text etwas vom Rand des Bildschirm abzurücken (Abbildung 2-6):
#content, #sidebar { padding: 10px; }

Vielleicht fragen Sie sich, warum wir das Padding dem Inhalt und den Sidebar-Elementen hinzugefügt haben, statt es global auf dem Body-Element selbst zu setzen. Der Grund dafür ist, dass man häufig Elemente hat, die vom einen Rand zum anderen gehen (wie die Kopfleiste in diesem Beispiel). Deswegen kann Padding auf dem Body oder einem anderen Element, das viele andere Elemente einschließt, mehr Ärger verursachen, als es wert ist.

Abbildung 2-5: Mit etwas CSS können Sie viel erreichen, um die Nutzbarkeit Ihrer Android-App zu verbessern.

22

|

Kapitel 2: Elementares Styling

Abbildung 2-6: Text von den Rändern abrücken

Der Inhalt in der Fußleiste der Seite ist im Wesentlichen eine Kopie des Navigation-Elements (des ul-Elements mit der ID nav) oben auf der Seite. Wir können die Fußleiste also aus der Android-Version der Seite entfernen, indem wir display wie folgt auf none setzen:
#footer { display: none; }

Das Android-Look-and-Feel einbringen
Es ist an der Zeit, etwas ausgefallener zu werden. Beginnen Sie oben auf der Seite, fügen Sie dem Text in der Kopfleiste einen ein Pixel breiten Schlagschatten hinzu und dem Hintergrund einen CSS-Gradienten:
#header h1 a { text-shadow: 0px 1px 1px #fff; background-image: -webkit-gradient(linear, left top, left bottom, from(#ccc), to(#999)); }

Die Parameter in der text-shadow-Deklaration haben (von links nach rechts) folgende Bedeutung: horizontale Verschiebung, vertikale Verschiebung, Unschärfe und Farbe. Meist werden Sie genau die Werte anwenden, die Sie hier sehen, weil eben das auf
Das Android-Look-and-Feel einbringen | 23

-webkit-border-bottom-right-radius: 8px. left top. Dies ist eine Anweisung. die Ausgangsfarbe und die Zielfarbe. Das Beste ist. Sie wenden die Rundung auf die a-Tags selbst an. 24 | Kapitel 2: Elementares Styling . indem wir den Radius auf das ul anwenden. Bei den meisten Browsern kann man auch einen Unschärferadius von 0 px angeben. left bottom. Wir könnten die abgerundeten Ecken um die Listen erzielen. right top oder right bottom). der Startpunkt des Gradienten (kann lefttop. Der nächste Schritt ist. wenn man den Radius für die Ecken des Rahmens einfach auf das umschließende ul anwenden könnte. -webkit-border-top-right-radius: 8px. bottom left. weil es Ihrem Design einen feinen.h. Sie können die horizontalen und vertikalen Teile der Konstanten für die Gradienten-Start. Die -webkit-gradient-Zeile verdient besondere Beachtung. nutzen wir für die eckspezifischen Versionen die -webkit-border-radiusEigenschaft. Android jedoch verlangt von Ihnen. für ein Hintergrund. Deswegen können Sie CSS-Gradienten überall nutzen. werden Sie sehen. dass der Unschärferadius mindestens 1 px beträgt. top right und bottom right sind ungültige Werte. aber ausgefeilten Anstrich verleihen kann. Wenn Sie es ausprobieren. left bottom. Wenn Sie eine Unschärfe von 0 angeben. wird der Textschatten auf Android-Geräten nicht angezeigt. die den Browser ein Gradientenbild erzeugen lässt. } #header ul li:last-child a { -webkit-border-bottom-left-radius: 8px.oder ein List-Style-Bild). right top oder right bottom sein). wo Sie normalerweise eine url() angeben (z. aber das funktioniert nicht. um einen Radius von 8 Pixeln auf die beiden oberen Ecken des ersten Listenelements und die beiden unteren Ecken des letzten Listenelements anzuwenden (Abbildung 2-7). Aber wenn der Nutzer auf das erste oder letzte Element der Liste klickt. wie ich es Ihnen gezeigt habe. Es wäre cool. was schrecklich aussieht.Android gut aussieht. Anders gesagt: top left. wenn wir die Hintergrundfarbe des ul-Elements auf Weiß und den Hintergrund seiner Kindelemente auf Transparent setzen. wird die Hervorhebung quadratisch erscheinen. Die Parameter sind von links nach rechts: der Gradienttyp (kann linear oder radial sein). der Endpunkt des Gradienten. dass wir den Navigationsmenüs die traditionellen abrundeten Ecken geben: #header ul li:first-child a { -webkit-border-top-left-radius: 8px. Trotzdem ist es interessant. dass die eckigen Ecken der untergeordneten Listenelemente über die abgerundeten Ecken des ul-Elements hinausragen und damit den Effekt negieren. } Wie Sie sehen.und -Zielpunkte nicht umkehren (d.B. etwas mit text-shadow zu experimentieren.

damit der Browser weiß. Mit jQuery erste Verhalten einführen Der nächste Schritt ist. der es Ihnen ermöglicht.und :last-child-Ergänzungen an den Selektoren nennt man Pseudoklassen. wenn sie es wollen. Pseudoklassen sind eine spezielle Art von CSS-Selektor. ob sie Cursorfokus haben oder ob sie angeklickt wurden –. Die :first-child. Sie können Dinge auf Basis von Kennzeichen formatieren – wie dem Ort des Erscheinens in einer Liste. Textschatten und runde Ecken leiten die Umwandlung einer Web-App in eine nativ-wirkende Android-App ein. damit wir dynamische Verhalten bieten können. die bestimmte implizite Kontextkriterien erfüllen. Ohne die Pseudoklasse hätten wir dem ersten li manuell eine Klasse hinzufügen müssen. Insbesondere werden wir es den Benutzern ermöglichen. ohne dazu manuell Ihr Markup anpassen zu müssen. Elemente zu wählen. den übermäßig großen Navigationsabschnitt in der Kopfzeile zu verbergen. Dazu werden wir noch etwas CSS schreiben und dann etwas JavaScript einsetzen müssen. dass es das erste ist. Anders gesagt. der Seite etwas JavaScript hinzuzufügen. damit sie ihn nur sehen. li:first-child beispielsweise wählt das erste li-Kind eines ul-Elements.Abbildung 2-7: Gradienten. um das neue CSS auf das vorhandene HTML anzuwenden. Mit jQuery erste Verhalten einführen | 25 .

Wenn Sie die Schritte zu Hause nachverfolgen.es wird so aussehen: <div class="leftButton" onclick="toggleMenu()">Menu</div> Ich werde das Button-HTML im Abschnitt ausführlicher beschreiben.2 font-weight: bold. das Ihr HTML-Dokument enthält (dazu werden Sie wahrscheinlich das Verzeichnis images erstellen müssen).7 } Die in diesem Kapitel verwendeten Abbildungen können Sie mit den Beispielen unter http://examples. left: 6px. Hier ist die CSS-Regel für den Button (Sie können schon loslegen und sie der Datei android. 1 Beginnen wir oben.1 top: 7px. Diese Anweisung setzt die Position auf absolute.3 text-align: center.6) 0px -1px 1px.Werfen wir zunächst einen Blick auf das neue CSS. } Das verbirgt erst etwas. text-shadow: rgba4(0.6 -webkit-border-image: url(images/button. dass das ein div mit der Klasse leftButton ist und dass es in die Kopfleiste eingefügt werden wird. 26 | Kapitel 2: Elementares Styling .css-Datei und fügen Sie ihr Folgendes hinzu: #header ul.png) 0 8 0 8. Wichtig ist.css hinzufügen): #header div. height: 30px. Damit Sie es wissen . Mit jQTouch werden wir uns in Kapitel 4. dass wir die ul-Elemente in der Kopfleiste verbergen. um das div aus dem Dokumentfluss zu entfernen. Das ermöglicht es Ihnen.de/catalog/9783897215733 herunterladen und aus dem Verzeichnis images kopieren. damit man leicht darauf tippen kann.leftButton { position: absolute. wenn Sie den ul-Elementen die Klasse hide hinzufügen (das werden Sie gleich mit etwas JavaScript nachholen). damit sie nicht angezeigt werden. line-height: 28px. ausführlich befassen. color: white. öffnen Sie Ihre android.0.oreilly. Anschließend definieren Sie die Styles für den Button. Stecken Sie diese Kopien in ein images-Unterverzeichnis des Verzeichnisses.0. dass Sie verstehen. Das HTML für den Button haben wir noch nicht angelegt. die Koordinaten für die obere linke Ecke zu setzen.hide { display: none. »Animationen«.5 border-width: 0 8px 0 8px. der das Menü anzeigt und verbirgt. wenn der Besucher die Seite lädt. fügen Sie die entsprechende Zeile also noch nicht in die HTML-Datei ein.0. 2 Setzt die Höhe auf 30 px. Schritt 1 ist.

denn es bedeutet weniger Bilder. Nehmen wir die rechte Seite als Beispiel. die dem Browser sagen. dezimale Werte zwischen 0 und 1 werden durchscheinend dargestellt. Die fünf Parameter sind von rechts nach links: die URL des Bildes. 255) und rgb(100%. Wenn das ordentlich funktionieren soll. die aus dem Bild zu schneiden sind. schien es mir komisch. 6 Die Zeilen für border-width und -webkit-border-image verlangen eine etwas umfassendere Erläuterung. es sind die Breiten. Verändert sich die Größe des Inhaltsbereichs. 4 Die Funktion rgb ist eine CSS-Alternative zur vertrauten Hexadezimalnotation. wird auch die Größe des Bildes entsprechend angepasst. weil der Text vergrößert oder verkleinert wird. Man kann auch unvernünftige Dinge tun. die Deckkraft) der Farbe angibt. was er mit dem Ausschnitt in der verfügbaren Breite des Rahmens anfangen soll (wiederholen. rgb(255.. dass die Breiten in border-image keine Rahmenbreiten sind. dass er die linken 8 px des Bildes nehmen und auf die rechte Seite des Rahmens anwenden soll. die die Angabe eines vierten Parameters ermöglicht. 7 Sind die Rahmenbreiten eingerichtet. dass er oben einen Rahmen der Breite 0. die vier Parameter beginnen oben und laufen im Uhrzeigersinn um den Inhalt). müssen Sie die optional Parameter für webkitborder-image nutzen.com/myBorderImage. Gemeinsam ermöglichen Ihnen diese beiden Eigenschaften. Mit dem entsprechenden Code sage ich dem Browser. obwohl ich das bereits mit der Eigenschaft border-width gemacht hatte. Die URL kann absolut (http://example.png) oder relativ sein. die Breite unten und die Breite links (wieder von oben ausgehend im Uhrzeigersinn). #FFFFFF). beispielsweise die rechten 4 Pixel eines Bildes auf einen Rahmen anwenden. Ich probiere damit seit drei Jahren herum und habe dennoch Mit jQuery erste Verhalten einführen | 27 . Relative Pfade basieren auf dem Ort des Stylesheets. die das Stylesheet einschließt. 100%) sind beide das Gleiche wie #FFFFFF.Die border-width-Zeile sagt dem Browser.3 Stylt den Text fett und weiß mit einem leichten Schlagschatten und im eigenen Inhaltsrechteck zentriert. 5 Die line-height-Deklaration verschiebt den Text vertikal im Rahmenrechteck. anpassen usw. die ebenfalls 8 px breit ist. unten einen Rahmen von 0 px und links wieder einen Rahmen von 8 px anwenden soll (d. können Sie das Rahmenbild anwenden. strecken. damit er nicht unmittelbar gegen den oberen Rand stößt. 100%. der den Alpha-Wert (d.B. wobei 0 gänzlich transparent und 1 vollständig undurchsichtig ist. die Breite rechts. Das ist wirklich eine gute Sache. den Rahmenbereichen eines Elements Ausschnitte eines einzigen Bildes zuzuweisen. der 20 Pixel breit ist. weniger Bandbreite und kürzere Ladezeiten.h. Nach einigen schmerzhaften Experimenten entdeckte ich. 255. Dieser Parameter unterstützt Werte zwischen 0 und 1. rechts einen Rahmen von 8 px. Vor Kurzem wurde zusätzlich die Funktion rgba() eingeführt.h. die üblicherweise zur Angabe von Farben genutzt wird (z. nicht auf dem Ort der HTML-Seite. die Breite oben. Als mir die Eigenschaft für Rahmenbilder das erste Mal begegnete. dass ich Rahmenbreiten angeben muss.). Hier müssen wir für den Rahmen keinen Stil und keine Farbe angeben. weniger Arbeit.

} } 6 1 Der gesamte Codeblock ist in eine if-Anweisung eingepackt. diese verwirrende und unpraktische Option einer Funktion zu beschreiben. die heruntergeladene Datei (die einen Namen wie jquery1.js und android. damit es jquery.ready(function(){ 2 $(’#header ul’).js umbenennen und in das Verzeichnis kopieren. wenn die Seite mit einem typischen Android-Handy oder einem Gerät ähnlicher Größe besucht wird. 28 | Kapitel 2: Elementares Styling . müssen Sie das HTML-Dokument anpassen.toggleClass(’hide’). Wenn Sie Ihre Android-Webseiten mit der Desktop-Version von Chrome testen. und laden Sie die Seite dann neu. und speichern Sie diese im gleichen Verzeichnis wie die HTML-Datei: if (window. 5 $(’#header . 4 }). die Navigationsmenüs ein.js"></script> <script type="text/javascript" src="android. die prüft. dass es dem Nutzer ermöglicht. schlägt diese if-Anweisung fehl.js"></script> jQuery-Downloads. Jetzt wird es Zeit für etwas JavaScript. die andernfalls der Hammer wäre. Schließen Sie dazu diese Zeilen in den head-Abschnitt des HTML-Dokuments ein: <script type="text/javascript" src="jquery. Zur Vorbereitung für das JavaScript. in dem sich auch Ihr HTML-Dokument befindet. Passen Sie die Größe des Fensters manuell so an.com.min.js einschließt. dass es so schmal wie möglich wird.innerWidth && window. wenn Ihr Browserfenster zu groß ist. Gut. Diese Zeile sorgt dafür. wie es in Abschnitt »Sie haben keine Website?« auf Seite 13 beschrieben wird. Deswegen will ich hier keinen Platz damit verschwenden. dass der Code nur ausgeführt wird. 3 $(’#header’). Kopieren Sie das folgende JavaScript in eine Datei namens android. Bevor Sie jQuery nutzen können.addClass(’hide’). -Dokumentationen und -Einführungen finden Sie unter http://jquery. function toggleMenu() { $(’#header ul’).innerWidth <= 480) { 1 $(document).js haben wird) in jquery. das Sie gleich schreiben werden.und auszublenden.2. müssen Sie es dort herunterladen.js ist.toggleClass(’pressed’).js. Die wichtigste Aufgabe des JavaScripts in android.leftButton’). ob die Eigenschaft innerWidth des window-Objekts vorhanden ist (in einigen Versionen des Internet Explorers ist das nicht der Fall) und dass die Breite kleiner gleich 480 px ist (eine vernünftige Maximalbreite für die meisten Handys).keine vernünftige Lösung gefunden.append(’<div class="leftButton" onclick="toggleMenu()">Menu</div>’).3. das zu tun.

wäre sie mit großer Wahrscheinlichkeit ausgeführt worden. Das sichtbare Resultat der Ausführung dieser Zeile ist. 3 Das ist typischer jQuery-Code. dass die uls in der Kopfleiste ausgewählt und ihnen die CSS-Klasse hide hinzugefügt wird. Wenn Sie noch nie mit jQuery gearbeitet haben. werden Sie gleich erfahren. diese Zeile aber würde fehlschlagen. kann diese Funktion etwas erschlagend wirken. bis ich mir die Syntax eingeprägt hatte. entspricht dem zuvor geschriebenen CSS . wenn das Dokument bereit ist. die wir gleich nachschieben werden. aber die uls würden erscheinen. Aber es lohnt sich. Mit jQuery erste Verhalten einführen | 29 . 4 Hier hängen wir einen Button an die Kopfleiste. weil die uls noch nicht existieren. dass es eine Weile gedauert hat. über den der Nutzer das Menü anzeigen oder verbergen kann (Abbildung 2-8). Die Klasse. Ich gebe zu. Abbildung 2-8: Der »Menu«-Button wurde der Werkzeugleiste dynamisch mit jQuery hinzugefügt.leftButton. da Sie sie häufig nutzen werden. dass die ul-Elemente in der Kopfleiste verborgen werden. Außerdem hat er einen onclick-Handler. und Sie würden sich den Kopf kratzen (oder auf Ihre Tastatur einschlagen) und sich wundern. der damit beginnt. JavaScript würde geladen. Dennoch würde das Laden der Seite fortgesetzt. dass Sie sich diese Zeit nehmen. die er hat.« Warum das wichtig ist. Hätten wir diese Zeile nicht in die Document-Ready-Funktion eingehüllt. warum das JavaScript nicht funktioniert. Erinnern Sie sich: hide ist der Selektor. Das heißt. der die Funkion toggleMenu() anzeigt. bevor die uls überhaupt vollständig geladen gewesen wären.2 Hier haben wir die sogenannte Document-Ready-Funktion. den wir in unserem CSS oben genutzt haben. Eigentlich sagt die Document-Ready-Funktion Folgendes: »Führe diesen Code aus.

Tun wir das jetzt. 6 Hier schalten wir die pressed-Klasse auf dem leftButton in der Kopfleiste um. wenn er gedrückt wurde. Das gibt dem Button den Anschein.png) 0 8 0 8. als habe er zwei Zustände.5 Die Funktion toggleMenu() nutzt jQuerys toggleClass(). dass der Button das Menü sowohl anzeigen als auch verbergen kann (Abbildung 2-9).pressed { -webkit-border-image: url(images/button_clicked. die das Menü und etwas Text anzeigt. } Wie Sie sehen können.css. Abbildung 2-10 zeigt eine vergrößerte Darstellung der Seite. In dieser Zeile schalten wir die hide-Klasse für die uls in der Kopfleiste um. geben wir einfach ein anderes Bild für den Button-Rahmen an (das etwas dunkler ist). und dies sollte es für den Benutzer offensichtlich machen. Und bevor wir es vergessen: Wir haben das CSS für die Klasse pressed noch nicht geschrieben. zu deaktivieren. um auf dem ausgewählten Objekt die angegebene Klasse zu aktivieren bzw. 30 | Kapitel 2: Elementares Styling . Öffnen Sie erneut die Datei android. und fügen Sie ihr Folgendes hinzu: #header div. Abbildung 2-9: Der »Menu«-Button wird etwas dunkler angezeigt.

es warten insbesondere saftige AjaxLeckereien. Was Sie gelernt haben | 31 . um Navigationsfelder anzuzeigen und auszublenden. Wir haben sogar etwas dynamisches HTML eingesetzt.Abbildung 2-10: Eine Gesamtansicht des vollständigen CSS für Android Was Sie gelernt haben In diesem Kapitel haben wir uns die Grundlagen für die Verwandlung einer bestehenden Webseite in ein Android-freundlicheres Format angesehen. Im nächsten Kapitel werden wir auf diesen Beispielen aufbauen. während wir einige etwas fortgeschrittenere JavaScript-Konzepte erforschen.

.

| 33 . Wenn Sie externe Seiten dynamisch laden. Im Kontext dieses Buches werde ich den Begriff Ajax für die Technik verwenden. In diesem Kapitel werden wir die Grundlage dafür legen. Web-App angenehmer. Diese Technik macht die Arbeit mit einer Website bzw.KAPITEL 3 Fortgeschrittenes Styling Während unseres Unternehmens. diese Seite dazu zu bringen. Außerdem funkioniert der ZURÜCKButton nicht mehr wie erwartet. weil Ajax es Ihnen ermöglicht. was er eigentlich bedeutet. sich auch wie eine Android-App zu verhalten.. eine Android-App ohne Java aufzubauen. Aber diese zusätzlichen Mühen können sich tatsächlich rentieren. dass man eine Menge Räder neu erfindet. mit JavaScript Anfragen an einen Webserver zu senden (z. ihn zu unterstützen. Anders formuliert: Sie müssen eine Menge leisten. ohne die aktuelle Seite dabei neu zu laden.B. dem Nutzer eine viel angenehmere Interaktion mit Ihrer App zu bieten. um etwas HTML abzurufen oder ein Formular abzuschicken). haben wir uns angesehen. dass sie wie eine Android-App aussieht. erfordert aber. um eine Ajax-App wirklich schmackhaft zu machen. liefert der Browser dem Benutzer beispielsweise keine Hinweise zum Fortschritt oder zu Fehlern. dass ich fast schon nicht mehr weiß. wenn Sie nicht persönlich die Mühe auf sich nehmen. Im Einzelnen werden wir uns dabei folgende Dinge ansehen: • wie man mit Ajax eine vollständige Website in eine einseitige App verwandelt • wie man mit JavaScript einen ZURÜCK-Button mit Verlauf erstellt • wie man die App als Symbol auf dem Home-Screen speichert Einen Spritzer Ajax einbringen Der Begriff Ajax (Asynchronous JavaScript and XML) ist zu einem derartigen Schlagwort geworden. wie man mit CSS eine HTML-Seite so stylt.

Nach dem Laden präsentiert android. 34 | Kapitel 3: Fortgeschrittenes Styling . »Elementares Styling«.css) und zwei JavaScript-Dateien ein: jquery. vermischen (d. die vor allen anderen Seiten der Site sitzt. werden wir einige der Eigenschaften aus den letzten Beispielen in Kapitel 2.js finden und was Sie damit tun. wenn der Benutzer auf einen Link klickt. Sie müssen eine Kopie von jquery. nicht zum Ziel des Links navigiert. die aus den anderen Seiten abgerufen werden.css zu. width=device-width" /> <link rel="stylesheet" href="android.Der Verkehrspolizist Für die nächsten Beispiele werden wir eine Seite namens android. Mehr Informationen dazu. um die onclick-Aktionen der nav-Links abzufangen. Wie Sie in Beispiel 3-2 sehen können. Der Body enthält bloß zwei div-Container: eine Kopfleiste mit einem anfänglichen Titel in einem h1-Tag sowie einen leeren div-Container. So soll es funktionieren: 1.und viewport-Optionen und schließen die Links auf ein Stylesheet (android. finden Sie in . Beispiel 3-1: Dieses einfache HTML-Wrapper-Markup wird später vor allen anderen Seiten der Site sitzen. damit der Browser. Wir werden mit der einfachsten funktionierenden Version des Codes beginnen und diese beim Fortschreiten verbessern.js"></script> <script type="text/javascript" src="android.js"></script> </head> <body> <div id="header"><h1>Jonathan Stark</h1></div> <div id="container"></div> </body> </html> Wenden wir uns der Datei android.h.html schreiben. indem die aktuelle Seite aktualisiert wird.css" type="text/css" media="screen" /> <script type="text/javascript" src="jquery.. Stattdessen wird jQuery einen Teil des HTMLs der entfernten Seite laden und die entsprechenden Daten an den Nutzer ausliefern.js in das Verzeichnis kopieren. Das HTML für die Wrapper-Seite android. einige der #header h1-Eigenschaften wurden in #header verschoben). Im head-Abschnitt setzen Sie die title.html ist äußerst einfach (siehe Beispiel 3-1).html dem Benutzer eine freundlich formatierte Version der Site-Navigation. der später die HTML-Fragmente aufnimmt. 2. in dem sich die HTML-Datei befindet.js und eine eigene JavaScript-Datei namens android. Dann werden wir jQuery nutzen. wo Sie jquery. <html> <head> <title>Jonathan Stark</title> <meta charset="utf-8" /> <meta name="viewport" content="user-scalable=no.js. Das sollten Sie jetzt tun – bevor Sie mit diesem Kapitel fortfahren.

font-size: 20px. left bottom. padding: 0. »Elementares Styling«. font-size: 17px. } ul { list-style: none. font-weight: bold. display: block. background-image: -webkit-gradient(linear. sehen Sie sich noch einmal Kapitel 2.aber im Ganzen sollte Ihnen die Sache vertraut erscheinen (falls nicht. color: #222. color: #222. border-color: #666. } #header h1 { color: #222. text-align: center. } ul li:first-child a { -webkit-border-top-left-radius: 8px. -webkit-border-bottom-right-radius: 8px. -webkit-border-top-right-radius: 8px. left top. margin: 0 auto. padding: 0. padding: 10px 0. } ul li:last-child a { -webkit-border-bottom-left-radius: 8px. } ul li a { background-color: #FFF. padding: 12px 10px. from(#ccc). font-size: 14px. to(#999)). border-width: 0 0 1px 0. text-decoration: none. font-family: Helvetica. text-shadow: 0px 1px 1px #fff. margin: 10px. Beispiel 3-2: Das Ausgangs-CSS für die Seite ist eine etwas angepasste Fassung der vorangegangenen Beispiele. } #header { background-color: #ccc. } Der Verkehrspolizist | 35 . border-style: solid. margin-bottom: -1px. an). body { background-color: #ddd. margin: 0. border: 1px solid #999. font-weight: bold.

html Eine Kopie von index.html Diese Datei haben Sie in Beispiel 3-1 erstellt. android. in dem sich auch android. Bevor Sie fortfahren.html Eine Kopie der HTML-Datei aus Beispiel 2-1.ul li a:active. about. können Sie about. Jetzt sollten Sie in Ihrem Arbeitsverzeichnis die folgenden Dateien haben: android.html befindet. dass Sie ihr den Namen index. } Etwas darzustellenden Inhalt einrichten Dieses JavaScript lädt ein Dokument namens index.html erstellen.html unter geändertem Namen. } #content a { color: blue.css Diese Datei haben Sie in Beispiel 3-2 erstellt. text-shadow: 0px 1px 1px #fff. damit Sie etwas zum Spielen haben. sollten Sie die HTML-Datei aus Beispiel 2-1 in das Verzeichnis kopieren.ul li a:hover { background-color:blue.html. } #content { padding: 10px. Wenn Sie wenigstens ein paar Links funktionsfähig machen wollen. color:white. Sie können diese Dateien selbst erstellen oder den Beispielcode von der Website zum Buch (http://www. blog. index. Wenn Sie die Wirkung etwas aufpolieren wollen. Beispielsweise würde das h2 in blog.html.de/catalog/9783897215733) herunterladen. oreilly. und darauf achten. Legen Sie dazu einfach ein paar Kopien von index. Allerdings wird keiner der Links in dieser Datei funktionieren. in der im h2 »Info« steht. dass sie den jeweiligen Links entsprechen. 36 | Kapitel 3: Fortgeschrittenes Styling .html. und ändern Sie deren Namen so.html und funktioniert ohne eine entsprechende Datei nicht.html Eine Kopie von index.html an.html und consulting-clinic. in der im h2 »Consulting-Klinik« steht.html zu <h2>Blog</h2>. können Sie den Inhalt des h2-Tags in den Dateien an den jeweiligen Dateinamen anpassen. blog.html geben.html Eine Kopie von index. consulting-clinic. bevor die entsprechenden Link-Ziele vorhanden sind. in der im h2 »Blog« steht.

8 }). führe die Funktion hijackLinks() aus. Beispiel 3-3: Dieser Happen JavaScript in "android. }). hijackLinks). sollten Sie index. und füge es in das #container-Element der aktuellen Seite ein.« index.7 loadPage(e. während wir es zeilenweise durchgehen.html.js ist der Ort.html.html verwendet haben.load(’index.3 } else { $(’#container’). wenn du das erledigt hast.html #header ul’. Werfen Sie immer wieder einen Blick auf Beispiel 3-3.ready(function(){ 1 loadPage(). Erstellen Sie diese Datei im gleichen Verzeichnis wie die Datei android.js" wandelt die Links auf der Seite in Ajax-Anfragen um.target.click(function(e){6 e. Würden wir diese Zeile ins Deutsche übersetzen.load(url + ’ #content’. ob ihr ein Wert übergeben wurde. Wenn Sie die Beispiele nacharbeiten. an dem alles geschieht. $(document). hijackLinks). die ausgeführt wird. Diese und die folgende Zeile sind Beispiele für jQuerys load()-Funktion. was an diesem Beispiel interessant ist.Anfragesteuerung mit JavaScript Das JavaScript in android.href). ist url undefiniert. Heißt Ihre Homepage anders.preventDefault(). Dann wird diese Zeile aufgerufen. Die load()-Funktion ist äußerst praktisch. wenn er den Aufbau der Seite abgeschlossen hat. 4 Das ist die Zeile. 3 Wird der Funktion kein Wert übergeben (was der Fall ist. und führe die Funktion hijackLinks() aus. würde sie ungefähr Folgendes sagen: »Hole alle ul-Elemente aus dem #headerElement von index. wenn Sie einer Seite auf die Schnelle Ajax-Funktionalitäten spendieren wollen. wenn der url-Parameter einen Wert hat. müssen Sie hier stattdessen diesen Dateinamen verwenden. Sie sagt im Prinzip: »Hole das #content-Element der Seite unter der an die Funktion loadPage() übergebenen url.html verweist auf die Homepage der Site. wenn sie das erste Mal aus der Document-Ready-Funktion aufgerufen wird). füge sie in das #container-Element der aktuellen Seite ein. function loadPage(url) {2 if (url == undefined) { $(’#container’).« Der Verkehrspolizist | 37 .4 } } function hijackLinks() {5 $(’#container a’). 2 Die Funktion loadPage() erwartet einen Parameter namens url und prüft (in der nächsten Zeile). um den Browser die Funktion loadPage() aufrufen zu lassen. Wenn du fertig bist. } 1 Hier nutzen wir jQuerys Document-Ready-Funktion.

Klick-Handler werden nicht ausgeführt. Wenn Sie den Code in diesem Kapitel testen. Das Event-Objekt eines angeklickten Links enthält die URL der entfernten Seite in e. enthält das #container-Element der aktuellen Seite das abgerufene HTML-Fragment. wenn der Nutzer auf Links klickt. Click-Handlern wird automatisch ein Event-Objekt übergeben. Diese Navigationsreaktion wird als das Standardverhalten des Links bezeichnet. 38 | Kapitel 3: Fortgeschrittenes Styling . wird die URL der entfernten Seite an die Funktion loadPage() übergeben und damit der Kreislauf neu angestoßen. sollten Sie darauf achten. wenn der Nutzer tatsächlich auf einen Link klickt.com/htmldom/ dom_obj_event. 6 Auf dieser Zeile sucht hijackLinks() alle Links im neuen HTML-Fragment und bindet mit dem nachfolgenden Code einen Click-Handler an sie. müssen wir das Standardverhalten verhindern. Ihren Code modularer und wiederverwendbarer zu machen. die mir an JavaScript am besten gefällt.href. aber in diesem Fall führt es zu einem Problem. das wir mit dem Funktionsparameter e festhalten. Obgleich das auf den ersten Blick befremdlich anmutet.html an. Lassen wir diese Zeile weg. wenn die Seite geladen wird. ist es unglaublich mächtig und ermöglicht Ihnen. Die Zuweisung von KlickHandlern ist also wie die Konstruktion einer Sprengfalle. Wenn Sie mit JavaScript arbeiten. es getan zu haben. Webserver zeigen standardmäßig die Seite index. Eine der Sachen. wird die eingebaute Funktion preventDefault()-Methode der Event-Objekts aufgerufen. Später werden Sie froh sein. dass Sie mit dem Browser tatsächlich zur Seite android. das später in Gang gesetzt werden kann oder auch nicht.5 Hat die Funktion load() ihre Arbeit erledigt. dass Sie einer Funktion als Parameter eine andere Funktion übergeben können. sollten Sie sich Das Beste an JavaScript (http://oreilly. wenn der Nutzer auf einen Link klickt.target. in dem sich die Dateien befinden. die (gemeinsam mit der nächsten Zeile) ausgelöst wird. 8 Klickt der Nutzer auf einen Link.w3schools. Sie bereiten etwas vor.asp. Auf dieser Zeile. Wenn Sie mehr über diese Technik erfahren wollen. Dann führt load() die Funktion hijackLinks() aus. Da wir Klicks hier selbst verarbeiten und Seiten mit JavaScript laden. sich einmal die Eigenschaften des Events anzusehen. sollten Sie sich eigentlich alles von Douglas Crockford ansehen.html gehen. das JavaScript bei Benutzeraktionen im Browser erzeugt. Sie sollten sich die Zeit nehmen. verlässt der Browser pflichtbewusst die aktuelle Seite und navigiert zur URL des angeklickten Links. 7 Normalerweise würde ein Webbrowser zu der neuen Seite navigieren.de/catalog/9783897218765) von Douglas Crockford (O’Reilly) ansehen. ist. Eine gute Referenz finden Sie unter http://www. wenn Sie nur das Verzeichnis angeben. Meist ist das praktisch. Sie werden ausgeführt.

was der Ausgangspunkt einer erhöhten Last auf dem Server und eventuell auch der Instabilität der Anwendung (d. und entfernen es. damit sie wissen. die Sie android. Wir hängen einfach an den Body ein Lade-div an. dass tatsächlich etwas passiert. könnten sie sich fragen.h. Beispiel 3-4 zeigt eine modifizierte Version von Beispiel 3-3. Dennoch lässt sie immer noch einiges zu wünschen übrig. Polieren wir die Sache noch etwas auf. wenn loadPage() startet. um eine Fortschrittsanzeige zu implementieren. Abbildung 3-1: Ohne Fortschrittsanzeige scheint die App zu hängen und frustriert den Nutzer.ready(function(){ loadPage(). Dank jQuery benötigen wir nur zwei Zeilen. Wir müssen den Nutzern etwas Feedback geben. Erhalten sie dieses Feedback nicht. erhält der Nutzer keinen Hinweis auf den Fortschritt.js hinzufügen müssen. Die Zeilen. die Quelle von Abstürzen) sein kann. wenn hijackLinks() fertig ist. Beispiel 3-4: Der Seite eine einfache Fortschrittsanzeige hinzufügen $(document). dass sie frustriert überall herumklicken. während die Daten geladen werden (siehe Abbildung 3-1). CSS und JavaScript konnten wir tatsächlich eine vollständige Website in eine Einseitenanwendung verwandeln. Etwas Schnickschnack | 39 .Etwas Schnickschnack Mit diesen winzigen Happen HTML. Fortschrittsanzeige Da wir wir dem Browser nicht gestatten. werden fett dargestellt. Das kann häufig dazu führen. }). ob sie tatsächlich auf den Link geklickt oder ihn etwa verfehlt haben. von Seite zu Seite zu navigieren.

} } function hijackLinks() { $(’#container a’).aspx) (http://www. Wenn Sie den Emulator mit den Argumenten -netspeed edge aufrufen. } else { $(’#container’). if (url == undefined) { $(’#container’). }). Wenn Sie das Testen abgeschlossen haben.load(url + ’ #content’.com) Wenn Sie den Android-Emulator (siehe Abschnitt »Ein virtuelles Android-Gerät erstellen« auf Seite 121) nutzen..8 Kilobit pro Sekunde Downstream).single.append(’<div id="progress">Lade. $(’#progress’). löschen Sie die Regel mit sudo ipfw delete 100 (mit ipfw flush können Sie alle eigenen Regeln löschen). können Sie den einkommenden Netzwerkverkehr bremsen. indem Sie im Terminal ein paar ipfw-Befehle eingeben. Folgende Befehle werden den gesamten Netzwerkverkehr beispielsweise auf 4 Kilobyte pro Sekunde verlangsamen: sudo ipfw pipe 1 config bw 4KByte/s sudo ipfw add 100 pipe 1 tcp from any to me 80 Sie sollten in der URL den Hostnamen Ihres Rechners oder eine externe IP-Adresse angeben (zum Beispiel mein_computer.html) Für Windows finden Sie hier Hinweise: • • (http://blogs. Wenn Sie Mac OS X nutzen.ratelimit. Ähnliche Dinge können Sie auch unter Linux und Windows tun.remove().local statt localhost).html #header ul’.com/b/wndp/archive/2006/06/30/653047.4 Kilobit pro Sekunde Upstream. 236. hijackLinks).. 40 | Kapitel 3: Fortgeschrittenes Styling . um sich eine Aufstellung aller unterstützten Geschwindigkeiten anzeigen zu lassen.click(function(e){ e.function loadPage(url) { $(’body’). dass Sie die Fortschrittsanzeige nie zu Gesicht bekommen.target. wird die Netzwerkgeschwindigkeit wahrscheinlich so groß sein. loadPage(e.preventDefault().load(’index. } Simulation der tatsächlichen Netzwerkleistung Wenn Sie diese Web-App in einem lokalen Netzwerk testen.net/articles/Traffic-Control-HOWTO/classless-qdiscs.msdn. Starten Sie den Emulater auf der Kommandozeile mit emulator -help-netspeed.href).</div>’).html) (http://lartc. Sehen Sie sich für Linux unter den folgenden Links um: • • (http://linux-ip. simulieren Sie tatsächliche EDGE-Netzwerkgeschwindigkeit (118. können Sie mit der Kommandozeilenoption -netspeed die verwendete Netzwerkgeschwindigkeit steuern.netlimiter. hijackLinks).org/howto/lartc.

left: 60px.remove(). }). } Den Seitentitel festlegen Jede Seite unserer Site hat ganz zufällig zu Anfang ein h2. werden wir diesen Titel aus dem Inhalt herausziehen und in die Kopfleiste packen (siehe Abbildung 3-3).html() || ’Hallo!’. background-color: rgba(0. um das zu erreichen. var title = $(’h2’). das einen wunderbaren Seitentitel abgeben würde (siehe Abbildung 3-2). font-weight: bold.target. Wieder hilft uns dabei jQuery: Wir müssen hijackLinks() ganze drei Zeilen Code hinzufügen. $(’h2’). das Sie android. Das können Sie in der HTML-Quelle in Kapitel 2. $(’h1’). top: 120px. color: white.css hinzufügen müssen.css« hinzugefügte CSS zum Stylen des Fortschrittsanzeigers #progress { -webkit-border-radius: 10px. Beispiel 3-5: Das zu »android. »Elementares Styling« sehen. width: 200px.html(title). Beispiel 3-6: Das »h2« der Seiten als Werkzeugleistentitel nutzen function hijackLinks() { $(’#container a’).preventDefault(). um das progress-div zu stylen.0.click(function(e){ e.0. loadPage(e. margin: 0 auto.7). line-height: 80px. font-size: 18px.remove(). position: absolute.href). $(’#progress’).. Beispiel 3-6 zeigt hijackLinks mit den entsprechenden Änderungen.In Beispiel 3-5 sehen Sie das CSS. } Etwas Schnickschnack | 41 . height: 80px. Um unsere Seite für Mobilgeräte tauglicher zu machen. text-align: center.

und nachdem der Titel in die Werkzeugleiste verschoben wurde 42 | Kapitel 3: Fortgeschrittenes Styling .. Abbildung 3-3: .Abbildung 3-2: Bevor der Titel in die Werkzeugleiste verschoben wurde ....

Das doppelte Pipe-Zeichen (||) in der ersten eingefügten Codezeile (fett dargestellt) ist der logische ODER-Operator von JavaScript. text-overflow: ellipsis. die die Fortschrittsanzeige entfernt. text-align: center. Dieser Punkt verlangt wahrscheinlich eine weitere Klarstellung. Wir könnten den Text einfach mehrere Seiten einnehmen lassen. dass er nicht in die Titelzeile passt (siehe Abbildung 3-4). da ich der Meinung bin. der zu lang ist. Die Fortschrittsanzeige möchte ich so spät wie möglich entfernen. } Etwas Schnickschnack | 43 . Stattdessen können wir die #header h1-Styles so aktualisieren. Lange Titel bewältigen Angenommen.Die Zeilen für den Titel habe ich vor der Zeile eingefügt. siehe Abbildung 3-5 und Beispiel 3-7) angezeigt wird. Das könnte mein Liebling unter den unbekannteren CSS-Tricks sein. padding: 10px 0. nicht ihren Inhalt. white-space: nowrap. wenn es kein h2-Element gibt. Beispiel 3-7: Ein Ellipsenzeichen an Text anhängen. der so lang ist. abgeschnitten und durch ein Ellipsenzeichen (Auslassungszeichen.html laden. der zu lang für seine Container ist #header h1 { color: #222. Auf Deutsch hieße das: »Setze die Variable title auf den HTML-Inhalt des h2-Elements oder auf die Zeichenfolge ’Hallo!’. aber das wäre nicht sonderlich attraktiv. margin: 0 auto. da wir nur die Navigations-uls abrufen.« Das ist wichtig. font-weight: bold. overflow: hidden. Site-Inhalte werden ihnen erst präsentiert. wenn sie auf dieser anfänglichen Navigationsseite auf einen Link klicken. font-size: 20px. max-width: 160px. text-shadow: 0px 1px 1px #fff. weil die erste geladene Seite kein h2 enthält. dass Text. Wenn Nutzer die URL android. dass das der Anwendung einen dynamischeren Anschein verleiht. sehen sie nur die übergeordneten Navigationselemente der Site. wir hätten in unserer Site eine Seite mit einem Titel.

kann aber durch eine CSS-Ellipse vermieden werden. Abbildung 3-5: . .. 44 | Kapitel 3: Fortgeschrittenes Styling .Abbildung 3-4: Textumbruch in der Werkzeugleiste ist nicht sonderlich ansehnlich....

} else { $(’#container’).load(url + ’ #content’. wenn ein Nutzer zu einer neuen Seite navigiert. Das können wir geraderücken. Sie müssen das jonathanstark. Schließlich hängt text-overflow: ellipsis drei Punkte an den abgeschnittenen Text an. Wird er gefunden.0). wieder nach oben zu scrollen.html #header ul’. Technisch ist das sinnvoll. dass der Browser die Zeile auf zwei Zeilen aufteilt. dass Inhalt. indem wir der Funktion loadPage() einen scrollTo()-Befehl hinzufügen (siehe Beispiel 3-8). da die aktuelle (gescrollte) Seite ja nicht verlassen wird. Wie Beispiel 3-9 zeigt. können wir eine Bedingung einbauen. Seiten auf anderen Domains). Klickt der Nutzer auf einen Link. hijackLinks). Etwas Schnickschnack | 45 . der sich über das Inhaltsrechteck eines Elements hinaus erstreckt. function loadPage(url) { $(’body’). Wird er nicht gefunden. springt die Seite zuerst an den Anfang.load(’index. Diese externen Links sollten wir nicht abfangen. if (url == undefined) { $(’#container’). wird der Link abgefangen und der Inhalt in die aktuelle Seite geladen (d. die länger als der sichtbare Bereich auf dem Gerät ist. Das hat zusätzlich den Vorteil. die sogar noch länger ist.oder Hostnamen für Ihre Website ändern. ob in der URL unser Domainname vorkommt. abgeschnitten werden soll. die prüft.com in den passenden Domain.h. mehr als 160px einzunehmen. Automatisch zum Seitenanfang scrollen Angenommen. dass die Fortschrittsanzeige auch sichtbar ist.append(’<div id="progress">Lade.Hier ist die Zusammenfassung: max-width: 160px sagt dem Browser. Sie haben eine Seite. Ohne diese Zeile würde das h1 einfach höher werden.. wenn der Nutzer ganz unten auf einer langen Seite auf einen Link klickt. wie man es erwarten würde. um dem Nutzer anzuzeigen. dass er dem h1-Element nicht gestatten soll. scrollTo(0. für den Nutzer ist es dennoch verwirrend. Der Nutzer besucht die Seite. Beispiel 3-8: Es ist ratsam. } } Nur lokale Links abfangen Wie die meisten Sites hat auch unsere Links auf externe Seiten (d. Die neue Seite wird dann »vorgescrollt« erscheinen und nicht in der Ausgangsposition.</div>’).h. da andernfalls die Links auf die Seiten Ihrer Website nicht mehr abgefangen werden. Dann verhindert white-space: nowrap. scrollt bis an ihr Ende und klickt auf den Link zu einer Seite. damit es den Text in der vorgegebenen Breite unterbringen kann. ihr HTML in unser Android-spezifisches Layout zu integrieren. navigiert der Browser ganz gewöhnlich zur entsprechenden URL.. Ajax kommt ins Spiel). dass er nicht den vollständigen Text sieht.. hijackLinks). Dann sagt overflow: hidden dem Browser. weil es wenig sinnvoll wäre.

regular-expressions.info/javascriptexample.remove(). zu zuvor besuchten Seiten zurückzukehren (denken Sie daran. 46 | Kapitel 3: Fortgeschrittenes Styling . $(’h2’). Der eigene Zurück-Button Beim derzeitigen Stand unserer Anwendung hat der Anwender keine Möglichkeit. } Die Funktion url. Dieser reguläre Ausdruck ist einfach. komplexere Ausdrücke können etwas einschüchternd wirken. damit wir zu ihr zurückkehren können • den Titel der vorangegangenen Seite speichern.click(function(e){ var url = e. dass wir alle Links abfangen und die Verlaufsfunktion des Browsers deswegen nicht funktioniert).js zeilenweise durchgehen (siehe Beispiel 3-10). Das Ergebnis wird so aussehen wie in Abbildung 3-6. loadPage(url). } }). die häufig in andere Programmiersprachen wie JavaScript.preventDefault().com/)) { e.match nutzt eine Sprache. Meine Lieblings-Regex-Seite ist http://www. Dazu werden wir folgende Dinge tun müssen: • die URL der vorangegangenen Seite speichern.match(/jonathanstark.html(title). das wir in diesem Kapitel geschrieben haben.target. PHP und Perl eingebettet wird. welchen Text wir auf dem Button anzeigen müssen Das Hinzufügen dieser Funktion wirkt sich auf große Teile des JavaScripts aus. dann kümmern wir uns um das CSS. damit wir wissen.html() || ’Hallo!’. Kümmern wir uns darum.Beispiel 3-9: Den Domainnamen in der URL prüfen.html. sind es aber dennoch wert.href. die sogenannten regulären Ausdrücke. deswegen werde ich die neue Version von android. if (url. Erst aktualisieren wir das JavaScript.remove(). indem wir oben links im Fenster einen eigenen ZURÜCK-Button einbauen. Wollen wir der App einen gewöhnlichen ZURÜCK-Button hinzufügen. var title = $(’h2’). müssen wir den Klick-Verlauf der Nutzers nachhalten. $(’h1’). damit externe Seiten normal geladen werden function hijackLinks() { $(’#container a’). $(’#progress’). dass Sie sich mit ihnen vertraut machen.

click(function(e){= var url = e.shift(). } 1 Diese Zeile initialisiert eine Variable namens hist als leeres Array.unshift({’url’:url.html() || ’Hallo!’. da das eine vordefinierte JavaScript-Eigenschaft ist. } }). loadPage(url).load(url + element. Beachten Sie.: $(’#header .shift(). dass nicht der vollständige Name history genutzt wird. }). } $(’#container’)..ready(function(){3 loadPage(startUrl). var thisPage = hist.title+’</div>’). Anders als in früheren Beispielen übergeben wir hier die Startseite an die Funktion loadPage(). if (url == startUrl) {5 var element = ’ #header ul’.</div>’).click(function(){.match(/jonathanstark. 3 Diese und die folgende Zeile bilden die Definition der Document-Ready-Funktion. $(’. loadPage(previousPage. 2 Diese Zeile definiert die relative URL der entfernten Seite.2 $(document). Aber in diesem Beispiel werden wir die Startseite an einigen Punkten nutzen. function(){6 var title = $(’h2’). } $(’#container a’).leftButton’). Da sie außerhalb aller Funktionen definiert wird.target. dass frühere Beispiele url == undefined prüften.remove().4 scrollTo(0.com/)) {> e.Beispiel 3-10: Das JavaScript zur Unterstützung eines »Zurück«-Buttons überarbeiten var hist = [].leftButton’).length > 1) {9 $(’#header’).html den ersten Besuch abstattet.append(’<div id="progress">Lade. } else { var element = ’ #content’.. wenn der Nutzer android. ’title’:title}). hat sie globale Geltung und ist damit in der gesamten Seite sichtbar. um das erste Laden zu verarbeiten. if (url. Deswegen ist es vernünftig.preventDefault().0). }). $(’#progress’).1 var startUrl = ’index.href.remove().remove(). $(’h2’).append(’<div class="leftButton">’+hist[1]. deren Namen Sie in Ihrem eigenen Code vermeiden sollten.8 if (hist. Etwas Schnickschnack | 47 . Vielleicht erinnern Sie sich.7 hist. die geladen werden soll.url).< var previousPage = hist. $(’h1’). sie global zu definieren.html’. function loadPage(url) { $(’body’).html(title). }).

um am Anfang des Arrays hist ein Element einzufügen. Das mag etwas seltsam anmuten.Abbildung 3-6: Ohne einen schimmernden Button mit einem Pfeil zurück wäre es keine Mobil-App. 8 Hier nutzen wir die eingebaute unshift-Methode des JavaScript-Arrays. Als zweiten Parameter übergeben wir direkt eine anonyme Funktion (eine unbenannte Funktion. 48 | Kapitel 3: Fortgeschrittenes Styling . andernfalls das div mit dem Inhalt. 6 Auf dieser Zeile werden der url-Parameter und das entsprechende Quellelement zum ersten Parameter für die Ladefunktion verbunden. Wenn wir diese Funktion durchgehen.else-Anweisung prüft. um die Anzeige und das Verhalten eines ZURÜCK-Buttons zu unterstützen... da wir es der Seite noch gar nicht hinzugefügt haben. 5 Diese if. Das Objekt hat zwei Eigenschaften: url und title – die beiden Informationen. Die folgenden drei Zeilen sind beispielsweise mit den vorangegangenen Beispielen identisch. welche Elemente von der entfernten Seite zu laden sind. die durch diese anonyme Funktion ersetzt wurde. Brauchen wir die Startseite. 7 Auf dieser Zeile entfernen wir das . wird Ihnen eine große Ähnlichkeit mit der Funktion hijackLinks() auffallen. 4 Weiter zur Funktion loadPage(): Diese und die folgende Zeile wurden vollständig aus den letzten Beispielen übernommen. werden die uls aus der Kopfleiste abgerufen. aber das werden wir ein paar Schritte weiter unten nachholen. die inline definiert wird).leftButton-Objekt aus der Seite. die wir benötigen.

white-space. title zu. wie viele Objekte der Verlauf enthält. Wir müssen also noch keinen ZURÜCK-Button anzeigen. da die lokalen Links sonst nicht abgefangen und in die Seite geladen werden. da das Bild durch den Pfeilkopf auf der linken Seite asymmetrisch ist. Anders gesagt. Dann sendet die letzte Zeile der Funktion die URL der vorangegangenen Seite an die Funktion loadPage(). wo wir es haben wollen. Etwas Schnickschnack | 49 . Beginnen wir damit. um die ersten beiden Elemente aus dem Array hist zu entfernen. müssen wir der Kopfleiste einen Button hinzufügen.com/blogs/Mastering_Javascript_Arrays finden Sie eine vollständige Aufstellung aller JavaScript-Array-Funktionen samt Beschreibungen und Beispielen. Dann fahren wir damit fort. Jetzt haben wir unseren ZURÜCK-Button und müssen ihn bloß noch mit etwas CSS aufmöbeln (siehe Beispiel 3-11).hunlock.oder Hostnamens Ihrer Website ersetzen müssen. Denken Sie daran. color und text-shadow anpassen. dass wir den Text mit den Eigenschaften font-weight. deswegen werde ich sie hier nicht erneut durchkauen. wenn der Benutzer nach dem Laden der Seite auf den Button klickt. der Index 0 entspricht der aktuellen Seite.9 Diese Zeile nutzt die eingebaute length-Methode eines JavaScript-Arrays. der Index 2 der Seite davor und so weiter. top und left genau dort in die Seite einbauen. nicht wenn die Seite geladen wird. Anders als beim vorangegangenen Rahmenbildbeispiel gibt es bei diesem Bild unterschiedliche Breiten für die linke und die rechte Rahmenseite. : Diese Zeile fügt den oben erwähnten . dass der Nutzer auf der ersten Seite ist. Dann sorgen wir mit den Eigenschaften max-width. line-height. > Das ist der zuvor in diesem Kapitel eingeführte Code zum Prüfen der URLs. Denken Sie daran. dass Sie jonathanstark. Enthält das Array mehr Objekte. Auf diesen greifen wir über hist[1]. text-align. um zur vorigen Seite zurückzukehren. Schließlich wenden wir mit den Eigenschaften border-width und -webkit-border-image eine Grafik an. Unter http://www.leftButton ein. overflow und text-overflow dafür. um herauszufinden. < Diese und die folgende Zeile nutzen die eingebaute shift-Methode von Arrays. Dieser Block Code bindet eine anonyme Funktion an den Klick-Handler des ZURÜCKButtons. das erste Element in der Liste (die aktuelle Seite) hat also immer den Index 0. wenn der Nutzer auf etwas klickt. . JavaScript-Arrays sind nullbasiert. heißt das. dass der Code eines Klick-Handlers ausgeführt wird. Der Code in dieser Funktion wird also dann ausgeführt. Enthält der Verlauf nur ein Objekt. dass wir das div mit position. der Index 1 der vorangegangenen Seite.com durch einen Teil des Domain. Der Text des Buttons wird den Titel der Seite vor der aktuellen Seite enthalten. = Die verbleibenden Zeilen wurden vollständig aus den vorangegangenen Beispielen übernommen. dass zu langer Text im Button-Text abgeschnitten und mit einer Ellipse angezeigt wird.

png) 0 8 0 14.6). text-overflow: ellipsis. position: absolute.leftButton { font-weight: bold. left: 6px. overflow: hidden. das Ihre HTML-Datei enthält. -webkit-border-image: url(images/back_button. Unter finden Sie Tipps zur Erstellung von eigenen Button-Bildern. text-align: center. color: white. } Abbildung 3-7: Standardmäßig zeigt Android um angetippte klickbare Objekte eine orange Markierung an. dass Sie für diesen Button ein Bild benötigen.0.0. text-shadow: 0px -1px 1px rgba(0. #header div. line-height: 28px.Vergessen Sie nicht. border-width: 0 8px 0 14px. Beispiel 3-11: Fügen Sie »android. um den »Zurück«-Button mit einem Rahmenbild zu verschönern. top: 7px. white-space: nowrap.0. 50 | Kapitel 3: Fortgeschrittenes Styling .png im images-Unterverzeichnis des Verzeichnisses speichern.css« Folgendes hinzu. max-width: 50px. Sie müssen es unter dem Namen back_button.

bevor der Inhalt der letzten Seite erscheint. -webkit-tap-highlight-color: rgba(0. left: 6px.0. können wir den Button so konfigurieren. -webkit-border-image: url(images/back_button. Etwas Schnickschnack | 51 .png) 0 8 0 14. Um Frustrationen zu vermeiden.leftButton { font-weight: bold. text-shadow: 0px -1px 1px rgba(0.h. border-width: 0 8px 0 14px.Standardmäßig blendet Android eine orange Markierung um klickbare Objekte ein. Ich weiß nicht. lässt sich aber leicht entfernen. wie Sie eigene Button-Bilder erstellen.0. Diese erscheint zwar nur kurz. In finden Sie Hinweise dazu. die wir hier aufbauen. auch einige Erfolge erzielt. Glücklicherweise unterstützt Android eine CSS-Eigenschaft namens -webkit-tap-highlight-color. Bei einem Desktop-Browser ist das ein Kinderspiel: Sie fügen Ihrem CSS einfach eine Deklaration mit der Pseudoklasse :active hinzu.0). Sie benötigen ein Button-Bild namens back_button_clicked. Beispiel 3-12: Fügen Sie »android. und fügen Sie dem Button die Klasse clicked hinzu. text-align: center.6). auch nachdem der Finger ihn freigegeben hat). dass er in dem Augenblick. in dem auf ihn getippt wird.0. color: white. top: 7px. } Bei unserem ZURÜCK-Button kann es zu einer Verzögerung von ein bis zwei Sekunden kommen. der Button scheint »geklickt« zu bleiben. Ich habe mit verschiedenen Kombinationen der Pseudoklassen :active und :hover herumgespielt und bei Apps. was die App viel ansehnlicher macht. indem wir die Tippmarkierung auf eine gänzlich transparente Farbe setzen (siehe Beispiel 3-12). position: absolute. die nicht auf Ajax basierten. eine dunklere Version des Button-Bildes im Beispiel auf den Button anzuwenden (siehe Abbildung 3-8 und Beispiel 3-13). #header div.0. Der Selektor :active wird ignoriert. wenn der Nutzer darauf tippt. ob es ein Bug oder ein Feature ist. max-width: 50px.css« Folgendes hinzu. Ich habe mich entschieden.. overflow: hidden. Hier tun wir das. um den standardmäßigen Tippmarkierungseffekt zu entfernen. über die Sie dieses Verhalten unterdrücken können. white-space: nowrap. text-overflow: ellipsis. aber eben das funktioniert bei Android nicht. auf die getippt wurde (siehe Abbildung 3-7). um einen alternativen Style für das Objekt anzugeben. line-height: 28px. geklickt aussieht. Aber bei Ajax-Apps wie der.0. sind die mit :hover definierten Styles haftend (d. wenn der Nutzer darauf geklickt hat. Glücklicherweise gibt es eine preiswerte Medizin – nehmen Sie jQuery.png im images-Unterverzeichnis.

js aktualisieren. damit der Button auch wie geklickt aussieht. #header div. werde ich im nächsten Kapitel beschreiben. } Abbildung 3-8: Im Druck erkennt man es vielleicht nicht so gut.png) 0 8 0 14. Zunächst geben wir der anonymen Funktion einen Parameter. wenn der Benutzer auf ihn tippt. können wir den Teil von android. aber der geklickte Button ist etwas dunkler. dieses vorab zu laden. damit sie das übergebene Click-Event festhalten kann. wäre es klug.leftButton.Beispiel 3-13: Fügen Sie »android. Nachdem wir das CSS eingerichtet haben. Da wir für den Klick-Style ein Bild nutzen.css« Folgendes hinzu. der den Click-Handler dem ZURÜCK-Button zuweist. während die Grafik für den geklickten Zustand noch heruntergeladen wird.clicked { -webkit-border-image: url(images/back_button_clicked. Dann packen wir das Event-Ziel in einen jQuery-Selektor und rufen jQuerys addClass()Funktion auf. Wie man Bilder vorab herunterlädt. um dem Button die CSS-Klasse clicked« zuzuweisen: 52 | Kapitel 3: Fortgeschrittenes Styling . Andernfalls verschwände die Button-Grafik beim ersten Antippen. e.

Der Unterschied ist. bevor Sie die optimalen Maße gefunden haben. die von Android adoptiert wurde. sollten Sie die Datei 56 px × 56 px groß machen. Laden Sie zunächst eine .addClass(’clicked’). dass wir ein Bild angeben werden.png" /> Vielleicht ist es Ihnen ja aufgefallen: Das ist eine Apple-spezifische Direktive. indem sie auf ihrem Home-Bild-Screen ein Lesezeichen für eine App anlegen.shift(). Das tun sie.html hinzu (ersetzen Sie myCustomIcon.url).png durch den absoluten oder relativen Pfad zu dem Bild): <link rel="apple-touch-icon-precomposed" href="myCustomIcon. Ausführliche Anleitungen und frei herunterladbare Vorlagen finden Sie auf der Icon-Design-Seite der AndroidEntwickler-Site (http://developer. var thisPage = hist.leftButton’). Ein besonderer Hinweis an alle CSS-Gurus im Auditorium: Die von »A List Apart« bekannt gemachte CSS-Sprite-Technik ist hier keine Option. andernfalls 60 px × 60 px. wenn der sichtbare Bereich im Wesentlichen quadratisch ist. ist es recht kompliziert. Da Android auf unterschiedlichen Geräten mit unterschiedlichen Bildschirmgrößen und -auflösungen läuft.png-Bilddatei auf Ihren Webserver herauf. Damit das visuelle Gleichgewicht mit anderen Launcher-Symbolen gewahrt bleibt. loadPage(lastUrl.target). Die Eigenschaft -webkit-border-image unterstützt keine Abstände für Bilder.click(function(e){ $(e. die überall gleich gut aussehen. }).$(’#header . das anstelle des Standardsymbols für Lesezeichen angezeigt werden soll.com/guide/practices/ui_guidelines/ icon_design. Symbole zu erstellen. Sie werden mit Ihrer jeweiligen Grafik wahrscheinlich etwas experimentieren müssen.shift(). Das unterscheidet sich in keiner Weise von jedem anderen Lesezeichen. das auf dem Home-Screen angelegt wird.html#launcherstructure). da sie Offsets für das Bild verlangt.android. Dem Home-Screen ein Symbol hinzufügen Hoffentlich wollen Ihre Nutzer ein Symbol für Ihre Web-App zu ihren Home-Screens hinzufügen (so etwas nennt man ein »Launcher-Symbol«). Dem Home-Screen ein Symbol hinzufügen | 53 . var previousPage = hist. Fügen Sie dann die folgende Zeile dem head-Abschnitt unseres Stellwerk-HTML-Dokuments android.

Im nächsten Kapitel werden Sie lernen. Sie haben richtig gelesen. Jetzt kommen die Dinge. wie Sie eine gewöhnliche Website in eine Ajax-App samt Forschrittsanzeiger und eines nativ aussehenden ZURÜCK-Buttons umwandeln. die Laune machen! 54 | Kapitel 3: Fortgeschrittenes Styling . wie man einer App mit nativen UI-Animationen Leben einhaucht.Was Sie gelernt haben In diesem Kapitel haben Sie gelernt.

die dem Benutzer Kontextinformationen geben. TAGE. offizieller Maintainer für jQTouch zu werden – eine Ehre. müsste man ihn von Grund auf schreiben. | 55 . wenn er wieder zurück navigiert. die die mobile Webentwicklung unglaublich vereinfacht. was wir im letzten Kapitel gelernt haben. das beinahe alles erledigen kann. Insgesamt wird es fünf Seiten geben: HOME.com/ herunterladen. TAG und NEUER EINTRAG. die ich mit größter Freude akzeptiert habe. der eine Menge Arbeit wäre. Beispielsweise rutschen Seiten nach links. ist kein Kinderspiel. Mit etwas Hilfe von unserem Freund Ich will aufrichtig sein: Eine Web-App so zu animieren wie eine native App.KAPITEL 4 Animationen Android-Apps weisen einige charakteristische Animationskennzeichen auf. EINSTELLUNGEN. Nach Hause rutschen Wir werden eine einfach Kalorienzähler-App namens Kilo aufbauen. was er an einem Tag zu sich genommen hat. jQTouch ist ein Open Source-JQuery-Plugin. Wir werden mit zwei Fenstern beginnen und uns langsam vorarbeiten. Sie können die letzte Version von jQTouch unter http://jqtouch. dass David mich vor Kurzem bat. in der der Anwender eintragen kann. Glücklicherweise hat ein unternehmungslustiger junger Spund namens David Kaneda eine JavaScript-Bibliothek namens jQTouch entwickelt. erheblich komplexeren Kram. Diese Änderungen werden Ihre Web-App von einer nativen Anwendung fast nicht mehr unterscheidbar machen. wie man charakteristische Verhalten wie Rutschen. wenn der Anwender über Links nach unten navigiert. Im Sinne der Veröffentlichungspflicht sollten Sie wissen. und nach rechts. und darüber hinaus noch eine Menge anderen. In diesem Kapitel werden Sie lernen. Umblättern und mehr in einer Web-App implementiert.

allein dadurch. Beginnen wir damit. zwei divs: 1 Dieses div (und ebenso das ein paar Zeilen später zu findende Info-div) wird zu einem Fenster in der App. back). der Kodierungsangabe und einen Body mit zwei Kindern.B. Da wir hier bei null beginnen werden. Diese toolbar-Klasse ist in den jQTouch-Themes speziell für das Stylen von Elementen vordefiniert. indem Sie bestehende jQTouch-Themes modifizieren oder eigene neu erstellen.Einigen Elementen der HTML-Dokumente werden wir CSS-Klassen zuweisen (z. die wie eine standardmäßige Mobilgerät-Werkzeugleiste aussehen. dass Sie eigene Klassen erstellen und nutzen können.</p> ¨ </div> </div> </body> </html> Das HTML hier enthält gerade einmal einen Header mit einem Titel. eine Datei namens index. Diese Klassen entsprechen immer vordefinierten Klassenselektoren im Standard-jQTouch-Theme. toolbar. 2 In jedem Fenster-div gibt es ein div mit der Klasse toolbar.und INFO-Fenster hinzuzufügen. die wir in den letzten Kapiteln erstellt haben. dass die Liste den ganzen sichtbaren Bereich von links nach rechts einnehmen soll. Denken Sie daran. 56 | Kapitel 4: Animationen .html« <html> <head> <title>Kilo</title> <meta charset="utf-8" /> </head> <body> <div id="home">1 <div class="toolbar">2 <h1>Kilo</h1> </div> <ul class="edgetoedge">3 <li class="arrow"><a href="#about">Info</a></li>4 </ul> </div> <div id="about"> <div class="toolbar"> <h1>Info</h1> <a class="button back" href="#">Zuruck</a>5 ¨ </div> <div> <p>Mit Kilo haben Sie Ihren Ernahrungsplan jederzeit im Griff. Beispiel 4-1: HTML für die »Home«. 3 Diese ungeordnete Liste hat die Klasse edgetoedge. in diesen Beispielen werden wir einfach die Standards nutzen. können Sie die Dateien beiseitelegen.und »Info«-Fenster in »index. button. edgetoedge. dass es ein unmittelbares Kind von body ist. Das sagt jQTouch. arrow.html zu erstellen und ihr das HTML in Beispiel 4-1 für die HOME.

css">2 <script type="text/javascript" src="jqtouch/jquery. 5 Diese Werkzeugleistenelemente enthalten jeweils ein einzelnes h1-Element. Ein Nach Hause rutschen | 57 . Diese Datei ist erforderlich. </script> 1 Diese Zeile schließt die Datei jqtouch.3.jQTouch({ icon: ’kilo. das zum Titel des Fensters werden wird.js"></script>3 <script type="text/javascript" src="jqtouch/jqtouch. Beispiel 4-2: Fügen Sie die folgenden Zeilen dem Head des Dokuments hinzu. Auf dieser Zeile gibt es zwei Links mit den Klassen button und back.com herunterladen.css">1 <link type="text/css" rel="stylesheet" media="screen" href="themes/jqt/theme. müssen Sie bloß noch dem Head Ihrer Seite ein paar Zeilen Code hinzufügen (siehe Beispiel 4-2). Normalerweise würde das Ihrem Browser sagen.4 Auf dieser Zeile ist ein li. Sie sorgt nur dafür. und eigentlich sollten Sie keine Veranlassung haben.png’ }). Für dieses Beispiel und die anderen Beispiele in diesem Buch müssen Sie jQTouch unter http://www. die ganz speziell für Animationen. dass Sie zum letzten Fenster zurückkehren. Aber wenn Sie jQTouch nutzen.css ein. hier das »jqt«-Theme. Zusätzlich müssen Sie in das Verzeichnis jqtouch navigieren und die jQuery-JavaScript-Datei (etwas wie jquery. die wir im HTML genutzt haben.jqtouch. jQTouch bietet standardmäßig zwei Themes. dass rechts des Elements in der Liste ein Gänsefüßchen eingefügt wird.2. bewirkt es.js"></script>4 <script type="text/javascript">5 var jQT = $. egal bei welchem Fenster wir uns unmittelbar zuvor befanden. Haben wir dieses elementare HTML eingerichtet. das in jQTouch eingebaut ist. das einen Link enthält. sie zu bearbeiten. wird es Zeit. Jene Datei definiert einige elementare strukturelle Design-Regeln.und themes-Verzeichnisse in das gleiche Verzeichnis wie Ihr HTMLDokument verschieben. In fortgeschritteneren Szenarien sollten Sie hier eventuell einen bestimmten Anker wie #home nutzen. Orientierung und andere Android-spezifische Einzelheiten gedacht sind. dass die Links wie Buttons aussehen und sich wie ZURÜCK-Buttons verhalten sollen.min.js umbenennen. <link type="text/css" rel="stylesheet" media="screen" href="jqtouch/jqtouch. die jQTouch sagen. um jQTouch zu aktivieren.1. dass er zum Anfang des aktuellen Dokuments zurückkehren soll. dass er zu einem bestimmten Fenster führen soll. entsprechen den Selektoren in diesem Dokument. dessen href auf das Fenster INFO zeigt. Die Klassen. in dem sich auch Ihr HTML-Dokument befindet. Das href auf dem ZURÜCK-Button ist auf # gesetzt. 2 Diese Zeile gibt das CSS für das gewählte Theme an. der dem ZURÜCK-Button sagt. Die arrow-Klasse auf dem li ist nicht unbedingt erforderlich. Nachdem Sie jQTouch heruntergeladen und in das Verzeichnis entpackt haben. entpacken und die jqtouch. jQTouch die Bühne betreten zu lassen.js) in jquery.

Beachten Sie.js umbenennen müssen). Dennoch werden Sie fast immer zumindest einige von ihnen nutzen. aber wenn Sie wollen. Der Unterschied zwischen der App vor jQTouch (siehe Abbildung 4-1) und nach jQTouch (siehe Abbildung 4-2) ist dramatisch. wo das selbst definierte Home-Screen-Symbol zu finden ist. übergeben. 58 | Kapitel 4: Animationen . indem Sie eines der Standard-Themes kopieren und anpassen oder indem Sie ein neues von Grund auf schreiben..eigenes können Sie erstellen. 4 Hier schließen wir jQTouch selbst ein. über die Sie das Verhalten und das Erscheinungsbild Ihrer App anpassen können. icon. aber das wirklich Erstaunliche ist. in dem wir das jQTouch-Objekt initialisieren und einen Eigenschaftswert.jQTouch veröffentlicht eine Reihe von Eigenschaften. dass Sie den Seiten Ihrer Anwendung mit nur 10 Codezeilen ein Gleiten nach links/rechts spendiert haben. das deswegen hier eingeschlossen werden muss. 5 Das führt uns zu dem Skript-Block. dass Sie jQTouch nach jQuery einschließen müssen . jQTouch ist umwerfend.. 3 jQTouch benötigt jQuery.Hier sagt icon jQTouch.sonst funktioniert es nicht. Abbildung 4-1: Kilo vor jQTouch . Eine Reihe davon werden Ihnen in diesem Buch begegnen. jQTouch enthält eine eigene jQuery-Kopie (die Sie wie zuvor gesagt in jquery. aber sie sind alle optional. und wir haben gerade erst die ersten Schritte damit gemacht. können Sie auch auf eine andere Version verweisen.

die beim heutigen Tag beginnt und fünf Tage zurückreicht (siehe Abbildung 4-3).. unmittelbar vor dem schließenden </body> (ich werde Ihnen gleich zeigen. Beispiel 4-3: Das HTML für das Datumsfenster <div id="dates"> <div class="toolbar"> <h1>Dates</h1> <a class="button back" href="#">Back</a> </div> <ul class="edgetoedge"> <li class="arrow"><a id="0" href="#date">Today</a></li> <li class="arrow"><a id="1" href="#date">Yesterday</a></li> <li class="arrow"><a id="2" href="#date">2 Days Ago</a></li> <li class="arrow"><a id="3" href="#date">3 Days Ago</a></li> <li class="arrow"><a id="4" href="#date">4 Days Ago</a></li> <li class="arrow"><a id="5" href="#date">5 Days Ago</a></li> </ul> </div> Die Seite »Tage« hinzufügen | 59 .. wie Sie auf der Startseite einen Link darauf erstellen). Die Seite TAGE soll eine Liste mit Datumsangaben enthalten. und Kilo nach jQTouch Die Seite »Tage« hinzufügen Bauen wir jetzt die Seite TAGE auf.Abbildung 4-2: . Fügen Sie das HTML für die Seite TAGE (das Sie in Beispiel 4-3 sehen) und zwar unmittelbar nach dem INFO-Fenster ein.

h. 0 bis 5). Beachten Sie. aber das gleiche href (d. 60 | Kapitel 4: Animationen . Noch bleibt ein Klick auf einen Eintrag in der Seite TAGE allerdings ohne Wirkung. die einen Eintrag aus der Liste anzeigt (die Seite TAG).h. indem wir eine weitere Seite ergänzen. Fügen Sie der Startseite in index.html die fettgedruckte Zeile hinzu: <div id="home"> <div class="toolbar"> <h1>Kilo</h1> </div> <ul class="edgetoedge"> <li class="arrow"><a href="#dates">Tage</a></li> <li class="arrow"><a href="#about">Info</a></li> </ul> </div> Und so haben wir ganz im Handumdrehen unserer App eine neue Seite hinzugefügt (siehe Abbildung 4-4). Beheben wir das. Auf die Werkzeugleiste folgt eine ungeordnete edgetoedge-Liste mit Links. Anschließend müssen Sie der Startseite einen Link auf die TAGE-Seite geben.Abbildung 4-3: Die Seite "Tage" besteht aus einer Werkzeugleiste mit einem "Zurück"-Button und einer anklickbaren. Wie die INFO-Seite hat auch die TAGE-Seite eine Werkzeugleiste mit einem Titel und einem ZURÜCK-Button. #date) – mehr dazu gleich. auf den heutigen Tag bezogenen Liste von Tagen. dass all diese Links eindeutige IDs haben (d.

Beispiel 4-4: Das HTML für das »Tag«-Fenster <div id="date"> <div class="toolbar"> <h1>Tag</h1> <a class="button back" href="#">Zuruck</a> ¨ <a class="button slideup" href="#createEntry">+</a>1 </div> <ul class="edgetoedge"> <li id="entryTemplate" class="entry" style="display:none">2 <span class="label">Beschreibung</span> <span class="calories">000</span> <span class="delete">Loschen</span> ¨ </li> </ul> </div> 1 Die Werkzeugleiste der Seite TAG hat einen weiteren Button. Ein Klick darauf öffnet die Seite NEUER EINTRAG (die wir noch nicht erstellt haben). Die Seite »Tag« | 61 .Abbildung 4-4: Die Startseite enthält jetzt einen Link auf die Tage-Seite. von einigen Ausnahmen abgesehen (schauen Sie in Beispiel 4-4). Die Seite »Tag« Die TAG-Seite weist große Ähnlichkeiten mit den letzten Seiten auf. Fügen Sie das HTML für die TAG-Seite direkt nach dem für die TAGE-Seite ein. Der Link hat die Klasse slideup. unmittelbar vor dem schließenden </body>-Tag.

Fügen Sie diesen Code am Ende von index. 2 Der andere ungewöhnliche Aspekt an dieser Seite ist. Abbildung 4-5: Von der Werkzeugleiste abgesehen. Noch gibt es keine Einträge. dass wir ein Listenelement mit dem Style display:none definieren und damit unsichtbar machen.html vor dem schließenden </body>-Tag ein. sieht man einmal von der Werkzeugleiste ab. Beispiel 4-5: Das HTML für das Fenster »Neuer Eintrag« <div id="createEntry"> <div class="toolbar"> <h1>Neuer Eintrag</h1> <a class="button cancel" href="#">Abbrechen</a>1 </div> 62 | Kapitel 4: Animationen .Wie Sie später sehen werden. ist die Seite »Tag« zu Anfang leer.die jQTouch sagt. Die Seite »Neuer Eintrag« Beispiel 4-5 zeigt den Quellcode für die Seite NEUER EINTRAG. werden wir dieses unsichtbare Listenelement als Schablone zur Anzeige von Einträgen nutzen. dass die entsprechende Seite von unten hereingleiten soll. die Seite wird also leer sein. Nachdem Sie die Seite TAG erstellt haben. nachdem diese erstellt wurden. schiebt jeder Klick auf einen Eintrag in der Seite TAGE die leere Seite TAG in die Ansicht (siehe Abbildung 4-5). nicht von links oder rechts wie bei der gewöhnlichen Navigation.

<form method="post">2 <ul class="rounded"> <li><input type="text" placeholder="Nahrung" name="food" id="food" autocapitalize="off" autocorrect="off" autocomplete="off" /></li> <li><input type="text" placeholder="Kalorien" name="calories" id="calories" autocapitalize="off" autocorrect="off" autocomplete="off" /></li> <li><input type="submit" class="submit" name="action" value="Eintrag speichern" /></li>3 </ul> </form> </div> 1 Das Erste. dass das Steuerelement ein einfaches einzeiliges Textfeld ist. Hat bei Android keinerlei Auswirkungen. weil das Fenster NEUER EINTRAG von unten hereingleitet und deswegen auch nach unten verschwinden wird. Hat bei Android keine Auswirkungen. id Ein eindeutiger Bezeichner für das Element innerhalb der gesamten Seite. placeholder Ein String. Es würde der Erwartungshaltung widersprechen. Die Seite »Neuer Eintrag« | 63 . solange es leer ist. ermöglichen wir es dem jqt-Theme. was man zur Seite NEUER EINTRAG anmerken sollte. Ich habe hier einen ABBRECHEN-Button genutzt. die gezeigt wurde. der im Eingabefeld angezeigt wird. ABBRECHEN-Buttons in jQTouch verhalten sich genau so wie ZURÜCK-Buttons: Sie blenden die aktuelle Seite mit der Umkehrung der Animation aus. der mit dem vom Nutzer eingegebenen Wert verknüpft wird. name Der Name. dass sie keinen ZURÜCK-. würde eine Seite bei einem Klick auf einen ZURÜCK-Button nach unten verschwinden. als sie eingeblendet wurde. sondern einen ABBRECHEN-Button hat. das Formular so zu stylen. autocapitalize Ermöglicht es Ihnen. wenn das Formular abgeschickt wird. wie Sie es in Abbildung 4-6 sehen. 2 Dieses HTML-Formular enthält eine ungeordnete Liste mit drei Elementen: zwei Textfeldern und einem ABSENDEN-Button. Indem wir die Formularsteuerelemente in lis einbetten. ist. autocorrect Ermöglicht es Ihnen.Auf den beiden Textfeldern sind jeweils eine ganze Reihe von Attributen definiert: type="text" Gibt an. die Rechtschreibkorrektur in Mobile Safari und auf dem iPhone zu steuern. die automatische Großschreibung des ersten Buchstabens unter Mobile Safari und auf dem iPhone zu steuern. Aber ABBRECHEN-Buttons sind nicht wie ZURÜCK-Buttons wie Pfeile nach links geformt.

Abbildung 4-6: Das jqt-Theme sorgt für eine ansprechende Gestaltung der Formularelemente. Diese Tastatur hat unten rechts einen LOS-Button. wenn sich der Cursor in einem Feld befindet. die automatisch den Cursor aus dem aktiven Feld entfernt.autocomplete Ermöglicht es Ihnen. Diese Funktion können Sie nutzen. indem Sie den Absenden-Elementen von Formularen die Klasse submit hinzufügen. »Clientseitige Datenspeicherung«. bietet jQTouch eine Hilfsmethode. damit der Eintrag tatsächlich gespeichert wird. Wenn Sie wie wir hier die Absenden-Funktion abfangen. Hat bei Android keine Auswirkungen. Das Android-Gerät zeigt eine Tastatur an. Noch haben wir nichts getan. der das Formular abgesendet. 64 | Kapitel 4: Animationen . Um das zu beheben. ansehen. 3 Das class-Attribut des ABSENDEN-Buttons verlangt eine Erklärung. wenn er angeklickt wird. entfernt das Absenden über den LOS-Button auf der Tastatur den Cursor nicht aus dem aktiven Feld. Das werden wir uns in Kapitel 5. die Autovervollständigung in Mobile Safari und auf dem iPhone zu steuern. und folglich wird auch die Tastatur nicht ausgeblendet. Abbildung 4-7 zeigt das Formular NEUER EINTRAG in Aktion. wenn der Nutzer auf EINTRAG SPEICHERN klickt. wenn ein Formular abgeschickt wird.

1 Das ist die HTML-Zeile. über den die Nutzer zur EINSTELLUNGEN-Seite navigieren können. dass wir dem Link die Klasse flip zugewiesen haben. Dazu benötigen wir nur eine einzige Zeile HTML. Um dem Vorgang eine zusätzliche Die Seite »Einstellungen« | 65 .. den Übergang von der Startseite zur Einstellungsseite zu gestalten. Beachten Sie.Abbildung 4-7: Dateneingabe per Tastatur im Formular »Neuer Eintrag« Die Seite »Einstellungen« Wir haben noch keinen Button erstellt. die den Button hinzufügt (siehe Abbildung 4-8).. Die Klasse flip weist jQTouch an. die hier fett dargestellt wird: <div id="home"> <div class="toolbar"> <h1>Kilo</h1> <a class="button flip" href="#settings">Einstellungen</a>1 </div> <ul class="edgetoedge"> <li class="arrow"><a href="#dates">Tage</a></li> <li class="arrow"><a href="#about">Info</a></li> </ul> </div> . das restliche HTML sparen wir uns . indem die Seite entlang ihrer vertikalen Achse gedreht wird. Fügen wir jetzt also einen zur Werkzeugleiste der Startseite hinzu...

Fügen Sie das genau so Ihrem HTMLDokument hinzu. wird Ihnen das HTML für die Seite EINSTELLUNGEN recht vertraut erscheinen (siehe Beispiel 4-6). aber konzeptionell sind beide gleich. Abbildung 4-8: Der »Einstellungen«-Button wurde der Werkzeugleiste der Startseite hinzugefügt. Den Handler für das Abschicken werden wir im nächsten Kapitel beschreiben. Deswegen weichen Flip. Cube und andere 3D-Animationen auf 2D-Animationen aus. wenn 3D nicht unterstützt wird. Es gibt ein zusätzliches Textfeld. Nachdem wir uns um die Seite NEUER EINTRAG gekümmert haben. Schick. 66 | Kapitel 4: Animationen . und einige der Attribute wurden weggelassen oder haben andere Werte. Swap. wie Sie es bei den anderen Seiten gemacht haben. Wie das Formular NEUER EINTRAG speichert auch das EINSTELLUNGEN-Formular noch keine der in es eingegebenen Daten (siehe Abbildung 4-9). wird die Seite während der Animation auch noch etwas vergrößert.Dimension zu geben. nicht wahr? Leider ist die Unterstützung von 3D-Animationen auf den unterschiedlichen Mobilplattformen einschließlich Android sehr unausgeglichen.

stimmt’s? Die Teile zusammenfügen | 67 .Beispiel 4-6: Das HTML für das »Einstellungen«-Fenster <div id="settings"> <div class="toolbar"> <h1>Einstellungen</h1> <a class="button cancel" href="#">Abbrechen</a> </div> <form method="post"> <ul class="rounded"> <li><input placeholder="Alter" type="text" name="age" id="age" /></li> <li><input placeholder="Gewicht" type="text" name="weight" id="weight" /></li> <li><input placeholder="Budget" type="text" name="budget" id="budget" /></li> <li><input type="submit" class="submit" name="action" ¨ value="Anderungen speichern" /></li> </ul> </form> </div> Abbildung 4-9: Das »Einstellungen«-Fenster Die Teile zusammenfügen So. Sie haben es also geschafft. In Beispiel 4-7 finden Sie eine vollständige Fassung des endgültigen HTMLs. Nicht gerade mickrig. samt drei unterschiedlichen Animationen für die Seitenübergänge. Mit weniger als 100 Zeilen Code haben Sie eine nativ gestylte Benutzeroberfläche für eine Anwendung mit fünf Seiten geschaffen.

</p> ¨ </div> </div> <div id="dates"> <div class="toolbar"> <h1>Tage</h1> <a class="button back" href="#">Zuruck</a> ¨ </div> <ul class="edgetoedge"> <li class="arrow"><a id="0" href="#date">Heute</a></li> <li class="arrow"><a id="1" href="#date">Gestern</a></li> <li class="arrow"><a id="2" href="#date">Vorgestern</a></li> <li class="arrow"><a id="3" href="#date">Vor 3 Tagen</a></li> <li class="arrow"><a id="4" href="#date">Vor 4 Tagen</a></li> <li class="arrow"><a id="5" href="#date">Vor 5 Tagen</a></li> </ul> </div> <div id="date"> <div class="toolbar"> <h1>Date</h1> <a class="button back" href="#">Zuruck</a> ¨ <a class="button slideup" href="#createEntry">+</a> </div> <ul class="edgetoedge"> 68 | Kapitel 4: Animationen .js"></script> <script type="text/javascript"> var jQT = $.css"> <script type="text/javascript" src="jqtouch/jquery.js"></script> <script type="text/javascript" src="jqtouch/jqtouch.css"> <link type="text/css" rel="stylesheet" media="screen" href="themes/jqt/theme.Beispiel 4-7: Der vollständige HTML-Code für die fünfseitige Benutzeroberfläche <html> <head> <title>Kilo</title> <link type="text/css" rel="stylesheet" media="screen" href="jqtouch/jqtouch.png’ }). </script> </head> <body> <div id="home"> <div class="toolbar"> <h1>Kilo</h1> <a class="button flip" href="#settings">Einstellungen</a> </div> <ul class="edgetoedge"> <li class="arrow"><a href="#dates">Tage</a></li> <li class="arrow"><a href="#about">Info</a></li> </ul> </div> <div id="about"> <div class="toolbar"> <h1>Info</h1> <a class="button back" href="#">Zuruck</a> ¨ </div> <div> <p>Mit Kilo haben Sie Ihren Ernahrungsplan jederzeit im Griff.jQTouch({ icon: ’kilo.

jQTouch anpassen | 69 . aber daneben gibt es noch einige weitere Eigenschaften. Weiter oben haben Sie mit der Eigenschaft icon schon ein Beispiel dafür gesehen.<li id="entryTemplate" class="entry" style="display:none"> <span class="label">Beschreibung</span> <span class="calories">000</span> <span class="delete">Loschen</span> ¨ </li> </ul> </div> <div id="createEntry"> <div class="toolbar"> <h1>Neuer Eintrag</h1> <a class="button cancel" href="#">Abbrechen</a> </div> <form method="post"> <ul class="rounded"> <li><input type="text" placeholder="Nahrung" name="food" id="food" autocapitalize="off" autocorrect="off" autocomplete="off" /></li> <li><input type="text" placeholder="Kalorien" name="calories" id="calories" autocapitalize="off" autocorrect="off" autocomplete="off" /></li> <li><input type="submit" class="submit" name="action" value="Eintrag speichern" /></li> </ul> </form> </div> <div id="settings"> <div class="toolbar"> <h1>Einstellungen</h1> <a class="button cancel" href="#">Abbrechen</a> </div> <form method="post"> <ul class="rounded"> <li><input placeholder="Alter" type="text" name="age" id="age" /></li> <li><input placeholder="Gewicht" type="text" name="weight" id="weight" /></li> <li><input placeholder="Limit" type="text" name="budget" id="budget" /></li> <li><input type="submit" class="submit" name="action" ¨ value="Anderungen speichern" /></li> </ul> </form> </div> </body> </html> jQTouch anpassen Sie können das jQTouch-Standardverhalten mit einer Vielzahl von Eigenschaften anpassen. die Sie kennen sollten (siehe Tabelle 4-1). die an den Konstruktor übergeben werden.

mit der sie eingeblendet wurde.flip' Jeden gültigen CSS-Selektor. Definiert Elemente. formSelector 'form' 70 | Kapitel 4: Animationen . true oder false dissolveSelector '. Jeden gültigen CSS-Selektor. Ist diese Eigenschaft auf true gesetzt. wird die aktuelle Seite mit der Umkehrung der Animation ausgeblendet. die das »Zurück«-Verhalten von jQTouch auslösen. Wenn hier true gesetzt ist. . die eine Flip-Animation von der aktuellen Seite zur Zielseite anstoßen. Definiert Elemente. die eine Cube-Animation von der aktuellen Seite zur Zielseite anstoßen.cube' Jeden gültigen CSS-Selektor. verhindert sie. die den OnsubmitHandler erhalten sollten. Definiert Elemente. wenn getippt wird. mehrere Werte können durch Kommata getrennt werden.dissolve' fadeSelector '. . Jeden gültigen CSS-Selektor. mehrere Werte können durch Kommata getrennt werden. mehrere Werte können durch Kommata getrennt werden.back. Das hat bei Android keine Auswirkungen. wird dem Home-Screen auf dem iPhone Glimmer hinzugefügt. Jeden gültigeen CSS-Selektor. damit nachfolgende Klicks die bereits geladenen Daten referenzieren. die eine Fade-Animation von der aktuellen Seite zur Zielseite anstoßen. Definiert Elemente. Definiert Elemente. Definiert Elemente. werden GET-Anfragen automatisch zwischengespeichert. cacheGetRequests true true oder false cubeSelector '. und aus dem Verlauf entfernt.goback' Jeden gültigen CSS-Selektor. mehrere Werte können durch Kommata getrennt werden. mehrere Werte können durch Kommata getrennt werden.cancel. backSelector '. mehrere Werte können durch Kommata getrennt werden. dass Nutzer in die Seite oder aus der Seite heraus zoomen können. die eine DissolveAnimation von der aktuellen Seite zur Zielseite anstoßen.fade' fixedViewport true flipSelector '. Wenn das »Zurück«-Verhalten aufgerufen wird.Tabelle 4-1: jQTouch-Anpassungsoptionen Eigenschaft addGlossToIcon Standard true Erwartet true oder false Anmerkungen Ist diese Eigenschaft auf true gesetzt.

wenn Sie statusBar auf black-translucent setzen. Ist diese Eigenschaft auf true gesetzt. Der Klassenname. von unten über die aktuelle Seite zu gleiten. Übergeben Sie den relativen oder absoluten Pfad zu einem 320 px × 460 px großen Bild für den Startbildschirm einer Vollbild-App. mehrere Werte können durch Kommata getrennt werden. die eine Slide-LeftAnimation von der aktuellen Seite zur Zielseite anstoßen. wenn die App in Mobile Safari läuft. Ermöglicht Ihnen. oder einen absoluten Pfad Das ist das Bild. auf eine . wenn die App im Vollbild-Modus gestartet wird. slideupSelector '.png-Bilddatei wenn ein Anwender seinem HomeScreen ein Lesezeichen für Ihre App hinzufügt. das angezeigt wird. Jeden gültigen CSS-Selektor. Nutzen Sie ein 320 px × 480 px großes Bild. die die Zielseite veranlassen. fullScreenClass 'fullscreen' String icon null null oder einen relativen Das Home-Screen-Symbol für Ihre App. Nur iPhone. bevor die Seite geladen wird. der auf den Body angewandt wird. hat bei Android keine Auswirkungen. Zum Beispiel: ['images/link_over. popSelector '. mehrere Werte können durch Kommata getrennt werden. wird Ihre App im FullScreen-Modus geöffnet.Tabelle 4-1: jQTouch-Anpassungsoptionen (Fortsetzung) Eigenschaft fullScreen Standard true Erwartet true oder false Anmerkungen Nur iPhone. mehrere Werte können durch Kommata getrennt werden.png'] preloadImages false slideInSelector 'ul li a' Jeden gültigen CSS-Selektor. Hat keine Auswirkungen auf die Anzeige.pop' Jeden gültigen CSS-Selektor. eigenes CSS zu schreiben. Definiert Elemente.png'. hat bei Android keine Auswirkungen. Definiert Bilder. die eine Pop-Animation von der aktuellen Seite zur Zielseite anstoßen. null oder ein relativer oder absoluter Pfad zu einer Bilddatei Definiert Elemente. Nur iPhone. Ein Array mit Bildpfaden Definiert Elemente. 'images/link_select. das nur wirksam wird. wenn Ihre App im Vollbildmodus ausgeführt wird.slideup' startupScreen null jQTouch anpassen | 71 . hat bei Android keine Auswirkungen. wenn sie vom Home-Screen des Benutzers gestartet wird. die geladen werden.

Was Sie gelernt haben In diesem Kapitel haben Sie gelernt. die im Vollbildmodus gestartet wurde. falls diese geöffnet ist). die die aktuelle Seite in die Zielseite umkippen. Im nächsten Kapitel werden Sie erfahren. 72 | Kapitel 4: Animationen . um einer App eine persistente Speicherung zu spendieren. hat bei Android keine Auswirkungen. wie man die neuen HTML5-Funktionen für lokalen Speicher und clientseitige Datenbanken nutzt. mehrere Werte können durch Kommata getrennt werden. der bei einem Klick sein Formular abschickt (und die Tastatur schließt. submitSelector '. black Anmerkungen Nur iPhone.submit' Jeden gültigen CSS-Selektor.swap' useAnimations true Setzen Sie diese Eigenschaft auf false. Definiert Elemente.Tabelle 4-1: jQTouch-Anpassungsoptionen (Fortsetzung) Eigenschaft statusBar Standard 'default' Erwartet default. blacktranslucent. um alle Animationen abzuschalten. Der Selektor. mehrere Werte können durch Kommata getrennt werden. wie man einer Web-App mit jQTouch nativ wirkende Animationen hinzufügt. Definiert das Erscheinungsbild der 20-px-Statusleiste oben im Fenster einer App. true oder false swapSelector '. Jeden gültigen CSS-Selektor.

die Browser für die Web Storage-Datenmenge aufstellen. Das Aufkommen von HTML5 bietet Webentwicklern jetzt einige weitere Möglichkeiten: Web Storage und Web SQL Database. Bei Webanwendungen wird diese Aufgabe traditionellerweise entweder über eine serverseitige Datenbank oder über im Browser gesetzte Cookies erfüllt. die beide Cookies darin ähneln. und sind für alle Fenster (oder Tabs) verfügbar. mit JavaScript benannte Name/ Wert-Paare zu setzen. Anders als Cookies werden die Web Storage-Daten aber nicht mit jeder Browser-Anfrage versendet. sessionStorage Daten werden auf dem window-Objekt gespeichert. Sie unterscheiden sich nur in Bezug auf die Persistenz und die Gültigkeit: localStorage Daten bleiben erhalten. Meine letzten Tests deuteten jedoch darauf hin. wenn das Fenster/Tab geschlossen | 73 . nachdem das Fenster geschlossen wurde. dass die Obergrenze aktuell bei rund 2. Andere Fenster/Tabs sehen die Werte nicht. noch nicht fixiert. Als dies geschrieben wurde. Funktionell sind localStorage und sessionStorage äquivalent. sondern verbleiben vollständig auf dem Client. Deswegen können erheblich mehr Daten gespeichert werden als mit Cookies. waren die Schranken. Web Storage Web Storage gibt es in zwei Varianten – localStorage und sessionStorage –. Protokoll und Port müssen identisch sein). wenn sie Daten irgendwie dauerhaft speichern können. dass sie es Ihnen ermöglichen. und die Daten werden verworfen.5 MB liegt. die von der gleichen Quelle geladen werden (Domainname. die zwischen Seitenaufrufen erhalten bleiben.KAPITEL 5 Clientseitige Datenspeicherung Die meisten Anwendungen können ihre Aufgabe nur erfüllen. Das ist für Dinge wie Anwendungseinstellungen geeignet.

damit die Formularwerte in localStorage gespeichert werden. Aktualisieren wir die EINSTELLUNGEN-Seite der Beispielanwendung. Erstellen Sie deswegen im gleichen Verzeichnis wie die HTML-Datei eine Datei namen kilo. da das unseren Code recht chaotisch machen würde. und fügen Sie in den head-Abschnitt des HTML-Dokuments einen Link auf kilo. 40). Benutzereinstellungen in lokalem Speicher speichern Machen wir uns an ein praktisches Beispiel. Das ist für Dinge wie fensterspezifische Zustände wie die Hervorhebung des aktiven Tabs oder die Sortierfolge einer Tabelle geeignet. Es kommt also nicht zu Konflikten. können Sie alternativ folgende Syntax nutzen: localStorage.und sessionStorage-Schlüssel werden separat gespeichert.age. wenn Sie für beide Schlüssel gleichen Namens nutzen. Wenn Ihre Schlüssel gültige JavaScript-Bezeichner sind (d. Wir werden in diesem Kapitel eine ganze Menge JavaScript schreiben. // Entfernt age aus der Speicherung Die localStorage.getItem(’age’). das ich nicht einfach in den Head-Abschnitt unseres HTML-Dokuments quetschen will. »Animationen« begonnen haben.clear(). Folgendermaßen können Sie ein bestimmtes Schlüssel/Wert-Paar aus dem Speicher löschen: localStorage.js ein: <head> <title>Kilo</title> <link type="text/css" rel="stylesheet" media="screen" 74 | Kapitel 5: Clientseitige Datenspeicherung .h. sie enthalten keine Leerzeichen und keine Interpunktionszeichen außer dem Unterstrich). // Holt den age-Wert delete localStorage. Das Setzen eines Wertes ist ein Kinderspiel: localStorage. In allen folgenden Beispielen können Sie einfach jedes Vorkommen von localStorage durch sessionStorage ersetzen.js. dass sessionStorage verschwindet.age.setItem(’age’. Der Zugriff auf einen gespeicherten Wert ebenfalls: var age = localStorage. Oder so sämtliche Schlüssel/Wert-Paare: localStorage.. Denken Sie allerdings daran. deren Erstellung wir in Kapitel 4. wenn das Fenster oder Tab geschlossen wird.age = 40 // Setzt den age-Wert var age = localStorage.removeItem(’age’).wird.

href="jqtouch/jqtouch. Hätten wir diese Zeile weggelassen. Fügen Sie kilo. Ich habe ihn einfach in kilo. und prüfen Sie. wäre die aktuelle Seite neu geladen worden. Laden Sie das HTML-Dokument in Ihrem Browser neu.css"> <script type="text/javascript" src="jqtouch/jquery. Wird die Funktion saveSettings() aufgerufen.jQTouch({ icon: ’kilo.js hinzu: function saveSettings() { localStorage. localStorage. localStorage. Erstellen Sie die Datei kilo. dass ich außerdem den jQTouch-Konstruktor aus dem Head des HTML-Dokuments entfernt habe.goBack().ready(function(){ $(’#settings form’).age = $(’#age’). der die Einstellungen speichert. Dank jQuery können Sie das mit einer einzigen Zeile Code erledigen. dass alles noch funktioniert: var jQT = $.submit(saveSettings). jQT. können wir uns an den Aufbau des Codes machen.js"></script> <script type="text/javascript" src="kilo. }). } Sind die Werte gespeichert.js Folgendes hinzu: $(document).css"> <link type="text/css" rel="stylesheet" media="screen" href="themes/jqt/theme. nutzen wir jQuerys goBack()-Funktion (auf der vorletzten Zeile).js"></script> <script type="text/javascript" src="jqtouch/jqtouch.val(). Web Storage | 75 .budget = $(’#budget’). sondern durch diese Funktion verarbeitet wird. Das bewirkt. das diese Funktion anstößt. Nachdem wir diese Umorganisation unseres Codes hinter uns haben. Dann wird false geliefert. wenn der Nutzer auf Absenden klickt. Achten Sie darauf.js im gleichen Verzeichnis mit folgendem Inhalt.val(). Aber er ist nicht einfach verschwunden. ruft sie mit jQuerys val()-Funktion die Werte aus den drei Formularfeldern ab und speichert diese in localStorage-Variablen gleichen Namens. Sie müssen die AbsendenAktion des EINSTELLUNGEN-Formulars überschreiben und durch eine eigene Funktion namens saveSettings() ersetzen.png’ }). return false. dass auch Sie ihn aus der Haupt-HTML-Datei entfernen. um die Seite zu schließen und zur vorangehenden zurückzukehren.js"></script> </head> Aufmerksame Leser haben sicher bemerkt.val().weight = $(’#weight’). dass das Formular nicht wirklich abgeschickt. was wir eigentlich vermeiden wollen. um die Standardaktion des Submit-Events zu unterbinden. die Sie in die Document-Ready-Funktion stecken müssen. Fügen Sie diese Funktion kilo.js verschoben.

js dazu die folgende Funktion hinzu: function loadSettings() { $(’#age’). Die frisch geänderten Werte befinden sich dann immer noch im Formular. obwohl die Werte gespeichert wurden. um die drei Werte des EINSTELLUNGEN-Formulars auf die entsprechenden in localStorage gespeicherten Werte zu setzen. wenn der Benutzer die Einstellungen wieder öffnet. aber mir scheint es am passendsten zu sein. } Die Funktion loadSettings() ist das Gegenstück zu saveSettings(). Da wir die Felder nicht leeren. Um das zu beheben. $(’#weight’). werden die gespeicherten Werte wiederhergestellt. weil sie gespeichert wurden (denn das wurden sie nicht). sondern weil sie sich immer noch dort befinden. Sondern es liegt schlicht daran. ohne das Formular abzusenden. nachdem sie eingegeben wurden. Aber nicht. Startet der Nutzer die App neu. Der offensichtlichste Zeitpunkt dafür ist der Start der Anwendung. }). dass sie immer noch vorhanden sind. Fügen Sie kilo. Dank jQTouch muss man dazu einfach die Funktion loadSettings() an das pageAnimationStart-Event der EINSTELLUNGEN-Seite binden.js einfach folgende Zeile hinzufügen: $(document). loadSettings(). Das lässt sich auf unterschiedliche Weise beheben. zur Seite EINSTELLUNGEN navigieren. bleiben die Felder deswegen leer. $(’#budget’). Das liegt aber nicht daran. bleiben die eingegebenen Werte erhalten. Startet der Nutzer die Anwendung neu und geht dann zur EINSTELLUNGEN-Seite. wenn der Nutzer zu den Einstellungen geht. die angezeigten Werte bei jeder Bewegung der EINSTELLUNGEN-Seite aufzufrischen. um die Einstellungen in localStorage zu speichern.val(localStorage. weil sie von loadSettings() beim Start neu gelesen werden. müssen wir die Einstellungen mit der Funktion loadSettings() laden.val(localStorage.age). Sie nutzt jQuerys val()-Funktion. Das erreichen Sie. Ersetzen Sie die gerade eingefügte Zeile durch den fett dargestellten Code: 76 | Kapitel 5: Clientseitige Datenspeicherung . Leider lässt das Laden beim Start ein Lücke. seine Einstellungen eingeben und das Formular absenden.budget).Jetzt kann der Nutzer die App starten. dass die Werte in localStorage gespeichert sind. einige Werte ändert und dann auf ABBRECHEN tippt.weight).submit(saveSettings). Jetzt haben wir eine loadSettings()-Funktion und müssen diese anstoßen.ready(function(){ $(’#settings form’). wenn der Benutzer später zur EINSTELLUNGEN-Seite zurückkehrt. wenn das Formular abgeschickt wird. egal ob sie sich auf den Bildschirm bewegt oder von ihm herunter. die sichtbar wird.val(localStorage. indem Sie der Document-Ready-Funktion in kilo.

val(localStorage. Dazu muss die TAG-Seite wissen. $(’#budget’).js ein paar weitere Zeilen hinzufügen: $(document).id.budget). und für den LÖSCHEN-Button in der Eingabeschablone der TAG-Seite (mehr dazu später) einbauen. }). } Das ausgewählte Datum im Sitzungsspeicher speichern Unser eigentliches Ziel ist es. Dazu müssen Sie der Document-Ready-Funktion in kilo. $(’#settings’).age = $(’#age’).bind(’pageAnimationStart’.budget = $(’#budget’). Das JavaScript in der Datei kilo. Außerdem möchten wir dem Nutzer das Hinzufügen und Löschen von Datenbankeinträgen ermöglichen.val(localStorage. loadSettings).click(function(){1 var dayOffset = this.ready(function(){ $(’#settings form’).$(document).submit(saveSettings).val(). Mit diesen Informationen können Sie den erforderlichen Datumskontext berechnen. loadSettings). sehen Sie.goBack(). } function saveSettings() { localStorage.js bietet jetzt Datenpersistenzunterstützung für die Einstellungen-Seite. dass da nicht viel dran ist.2 var date = new Date(). Der erste Schritt ist.3 Web Storage | 77 . auf welchen Tag der Nutzer auf der Seite TAGE getippt hat.submit(saveSettings). Hier ist der gesamte Inhalt von kilo. dass wir der Tag-Seite mitteilen.val(). return false.bind(’pageAnimationStart’. function loadSettings() { $(’#age’). Wenn Sie sich den Code ansehen. jQT.js. $(’#weight’). $(document).jQTouch({ icon: ’kilo.bind(’pageAnimationStart’. den wir bisher erstellt haben: var jQT = $. als er über TAGE zu ihr navigierte.png’ }).val(localStorage. }).val().ready(function(){ $(’#settings form’). den die TAG-Seite bereits enthält. auf welches Element der Nutzer klickte.weight = $(’#weight’). localStorage. $(’#settings’). $(’#settings’).age).ready(function(){ $(’#settings form’). die TAG-Seite so einzurichten. localStorage. Wir müssen also Unterstützung für den +-Button. $(’#dates li a’). dass sie bei der Anzeige in der Datenbank alle Einträge für dieses Datum nachschlägt und diese als Liste über die gesamte Bildschirmbreite anzeigt. mit dem wir das bewirkt haben.weight).submit(saveSettings). loadSettings).

die erforderlich sind.MM. 0 Tage zurück ist gleich heute.currentDate. $(’#date h1’).getMonth() + 1 ist erforderlich. Deswegen müssen wir 1 hinzufügen. Die Aufgabe dieser Funktion ist die Aktualisierung der TAG-Seite auf Basis des Tags.dayOffset). Deswegen ziehen wir auf der nächsten Zeile dayOffset vom Ergebnis der getDate()Funktion ab und nutzen setDate(). wie Sie in Abbildung 5-1 sehen.) Die getMonth()-Methode von Date liefert Werte zwischen 0–11.5 }).text(currentDate). Vielleicht erinnern Sie sich: Die Links auf der Seite TAGE haben IDs von 0 bis 5. sessionStorage. } 78 | Kapitel 5: Clientseitige Datenspeicherung .getDate() .’ + date. 1 Tag zurück ist gleich gestern. (Die Klammer um date. 2 Tage zurück ist gleich vorgestern). auf den der Anwender auf der Seite TAGE tippte. Zu Anfang wird dieses auf den Moment seiner Erstellung gesetzt sein.4 refreshEntries().date. 1 gestern und so weiter). 3 Diese Zeile erstellt ein neues JavaScript-Date-Objekt und speichert es in einer Variablen namens date.setDate(date.currentDate = date. das das Ziel des Click-Events war.js die folgende Funktion hinzu: function refreshEntries() { var currentDate = sessionStorage. um das Datum auf das ausgewählte Datum zu ändern (ein dayOffset0 wäre heute.. um den erforderlichen Wert für den formatierten String zu generieren. In diesem Kontext enthält das Schlüsselwort this eine Referenz auf das Objekt. 5 Schließlich rufen wir die Funktion refreshEntries() auf. damit Sie sehen können. 2 Diese Zeile ruft die ID des angeklickten Objekts ab und speichert sie in der Variablen dayOffset.JJJJ-formatierten Datumsstring und speichert ihn als currentDate in sessionStorage. 1 Auf dieser Zeile bindet jQuerys click()-Funktion den nachfolgenden JavaScript-Code an das click-Event der Links auf der TAGE-Seite.getDate() + ’. damit der +-Operator als numerischer Operator und nicht als Stringverkettungsoperator verstanden wird. dass es funktioniert. 4 Dieser Code erzeugt einen TT. Die ID des angeklickten Links entspricht also der Anzahl von Tagen. um das angeklickte Datum zu berechnen (d.h. Aktuell wollen wir uns nur darum kümmern. wobei 0 Januar entspricht. dass der Titel in der Werkzeugleiste der Seite TAG aktualisiert wird. }).’ + (date. Fügen Sie zu kilo.getMonth() + 1) + ’. Bislang sehen Sie einfach das Wort »Tag«. Abbildung 5-2 zeigt die Funktion refreshEntries() bei der Arbeit.getFullYear().

Sie wurde aus der ursprünglichen HTML5-Spezifikation herausgelöst und in eine eigene Spezifikation ausgelagert.. Genau genommen ist die Web SQL Database-Spezifikation nicht Teil von HTML5. Web SQL Database | 79 . die wir nutzen werden. Die Web SQL Database-Spezifikation bietet Entwicklern eine einfache.Datenbank. die meiner Arbeit die meisten Impulse gibt. Web SQL Database Von allen aufregenden Funktionen von HTML5 ist Web SQL Database die. Abbildung 5-1: Vor dem Einfügen der Funktion »refreshEntries()« sagt der Titel einfach »Tag«. . aber mächtige JavaScript-Datenbank-API zur Speicherung persistenter Daten in einer lokalen SQLite..Als Nächstes werden wir uns eine mächtigere und komplexere Methode zur clientseitigen Datenspeicherung ansehen. um die Nahrung-Einträge auf der Seite TAG zu speichern. Aber gewöhnlich bezeichnet man die entsprechenden Funktionalitäten immer noch als »HTML5-Funktionen«.

submit(saveSettings). $(’#settings’). in der wir die abgeschickten Daten speichern können (das ist eine einmalige Operation). Eine Datenbank erstellen Unsere TAG-Seite weiß jetzt. Wir werden kilo. date. $(’#dates li a’). var date = new Date(). Bevor wir die Funktion createEntry() erstellen können.click(function(){ var dayOffset = this.js dazu ein paar Zeilen hinzufügen: var db. 80 | Kapitel 5: Clientseitige Datenspeicherung . die sie benötigt. die Sie dafür aufwenden.setDate(date. auswählen. Die JavaScript-Datenbank-API bietet sogar Unterstützung für Transaktionen.bind(’pageAnimationStart’. wahrscheinlich eine sehr gute Investition.id.dayOffset)..ready(function(){ $(’#settings form’). kompliziert die Sache natürlich etwas.getDate() . um dem Benutzer die Erstellung von Einträgen zu ermöglichen. Dass wir es hier mit SQL zu tun haben. müssen wir eine Datenbanktabelle einrichten. welchen Tag der Nutzer ausgewählt hat. loadSettings).Abbildung 5-2: . hat also alle Informationen. Entwickler können mit gewöhnlichen SQL-Anweisungen Tabellen erstellen und Zeilen einfügen. ist die Zeit. und nach »refreshEntries()« gibt der Titel das ausgewählte Datum an. Aber da diese Funktion die Landschaft vollkommen umkrempelt.. aktualisieren oder löschen.1 $(document).

Gestattet er die Vergrößerung. Diese Variable hält eine Referenz auf die Datenbankverbindung fest.currentDate = date. }).getMonth() + 1 + ’/’ + date. die Datenbank-Version beim Start der App prüfen und eine neue Datenbank erstellen und die alten Daten in die neue verschieben. weil wir auf sie an den unterschiedlichsten Stellen zugreifen müssen. var displayName = ’Kilo’. 1 Das erste Bemerkenswerte hier ist die Variable namens db im globalen Geltungsbereich der Anwendung. version Eine Zahl zur Steuerung von Aktualisierung und Rückwärtskompatibilität. die Ihre Datenbank einnehmen darf.executeSql(6 ’CREATE TABLE IF NOT EXISTS entries ’ + ’ (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT. food TEXT NOT NULL.getFullYear(). ’ + ’ calories INTEGER NOT NULL ). Sie wird im globalen Geltungsbereich definiert.3 db. Verweigert er sie. der auf die Datenbankdatei auf der Festplatte verweist. db = openDatabase(shortName. ’ + ’ date DATE NOT NULL. Web SQL Database | 81 .2 var version = ’1. Beispielsweise erscheint dieser Name im STORAGE-Tab der Entwicklertools in der Chrome Desktop-Version (DARSTELLUNG→ENTWICKLER→ENTWICKLERTOOLS).getDate() + ’/’ + date. Die Größenbeschränkungen für Datenbanken werden aktuell erst in Browsern implementiert. 2 Diese vier Zeilen definieren einige Variablen für den openDatabase-Aufruf: shortName Ein String. wird die Größenbeschränkung Ihrer Datenbank auf 10 MB erhöht. var shortName = ’Kilo’. version. displayName. maxSize). } ).0’. refreshEntries().’ )..h.sessionStorage. nachdem wir diese hergestellt haben.var maxSize = 65536. maxSize Die maximale Anzahl Kilobytes. wird ein QUOTA_ERR-Fehler geliefert. Eine Liste der Datenbank-Fehlercodes finden Sie in Tabelle 5-1. }). wenn Sie das Datenbankschema ändern müssen (d. displayName Ein String. wird der Benutzer automatisch gefragt.transaction(4 function(transaction) {5 transaction. der dem Benutzer auf GUI-Ebene angezeigt wird. ob er eine Änderung der Größe zulassen will. Übersteigt Ihre Datenbank diese Grenze. aber das W3C empfiehlt eine willkürliche Schranke von 5 MB pro Herkunft. wenn die Datenbank zu alt ist).

die der Transaktion als einziger Parameter gesendet wird. Ich will ehrlich sein: Ich finde es schon recht seltsam. 5 Diese Zeile beginnt eine anonyme Funktion und übergibt ihr das Transaktionsobjekt. indem Sie DARSTELLUNG→ENTWICKLER→ENTWICKLERTOOLS wählen und auf den Tab STORAGE klicken. würde sie auf dem Android-Gerät eine Datenbank namens Kilo erstellen. aber genau das muss man tun. Die Klausel IF NOT EXISTS verhindert. ruft diese Zeile openDatabase auf und speichert die Verbindung in der Variablen db. dass man das Transaktionsobjekt an die eigene Callback-Funktion übergeben muss (warum nimmt man nicht einfach this?). 6 Befinden wir uns in der Funktion. rufen wir einfach die executeSql-Methode des Transaktionsobjekts auf und führen eine ganz gewöhnliche CREATE TABLE. deswegen rufen wir hier zunächst die transaction-Methode des db-Objekts auf. Die verbleibenden Zeilen bilden eine Funktion. dass die Tabelle neu erstellt wird. wenn sie bereits existiert. Abbildung 5-3: Das »Storage«-Tab in den Entwicklertools von Chrome mit einigen Testdatensätzen 82 | Kapitel 5: Clientseitige Datenspeicherung . wird sie erstellt. 4 Alle Datenbankabfragen müssen im Kontext einer Transaktion erfolgen. In der Desktop-Version von Chrome können Sie Ihre Datenbanken betrachten und bearbeiten. Existiert die Datenbank noch nicht.Anweisung aus.3 Nachdem die Parameter eingerichtet sind. Würden Sie die App im jetzigen Zustand starten.

Zeilen einfügen Nachdem wir die Datenbank zur Aufnahme von Einträgen eingerichtet haben. $(’#settings’).bind(’pageAnimationStart’. Wenn ein Nutzer das Formular #createEntry abschickt. .js dann Folgendes hinzu. indem Sie in der Document-Ready-Funktion in kilo. indem Sie einfach auf den Datenbanknamen klicken (siehe Abbildung 5-4).. Zunächst müssen wir das Submit-Event des Formulars #createEntry überschreiben. Wenn Sie auf das Undock-Symbol klicken (lassen Sie die Maus über den Symbolen unten links schweben. die Funktion createEntry() zu erstellen. darunter fett dargestellt.ready(function(){ $(’#createEntry form’). wird jetzt die Funktion createEntry() aufgerufen. beliebige SQLAnweisungen auf Ihrer Datenbank auszuführen. Das können Sie tun.. erscheinen sie so wie in Abbildung 5-3 in einem eigenen Fenster. um mehr zu ihrer Funktion zu erfahren). können wir darangehen.submit(saveSettings). sind äußerst nützlich beim Debugging.submit(createEntry). Fügen Sie kilo. die neue): $(document).js die Funktion createEntry() an das SubmitEvent binden (hier zeige ich nur die ersten paar Zeilen. um den Eintrag in der Datenbank zu erstellen: Web SQL Database | 83 . $(’#settings form’). die in der Desktop-Version von Chrome enthalten sind. Über die Schnittstelle können Sie sogar beliebige SQL-Abfragen an die Datenbank schicken. Abbildung 5-4: Das »Storage«-Tab in Chromes Entwicklertools ermöglicht es Ihnen.Die Entwicklertools. loadSettings). Standardmäßig erscheinen sie als eigener Bereich im aktuellen Browserfenster.

Die Position der Daten entspricht den Platzhalterfragezeichen in der SQL-Anweisung. function(){ refreshEntries().goBack(). die ausgeführt werden wird. wenn die Ausführung der SQL-Anweisung fehlschlägt. Die beiden anderen Werte (calories für die Kalorien und food für die Nahrung) werden auf gleichem Wege aus dem Formular für die Dateneingabe entnommen.jQT. }. food) VALUES (?.function createEntry() { var date = sessionStorage. [date. Anführungszeichen (' oder ") sind um die ?-Platzhalter nicht erforderlich – das Maskieren und Quotieren der Daten erfolgt automatisch. food]. calories. 2 Dieser Code öffnet eine Datenbanktransaktion und führt einen executeSql()-Aufruf aus.' Das ist die Anweisung.1 var calories = $(’#calories’). 84 | Kapitel 5: Clientseitige Datenspeicherung . var food = $(’#food’). db. Wie Sie (aus dem Abschnitt »Das ausgewählte Datum im Sitzungsspeicher speichern« auf Seite 77) wissen. die ausgeführt wird. Hier übergeben wir der Methode executeSql() vier Parameter: 'INSERT INTO entries (date. auf den der Nutzer auf der TAGE-Seite klickt. wird der Tag. die wir in der SQL-Abfrage nutzen werden. function(){refreshEntries().val(). } ). ?). wenn die SQL-Anweisung erfolgreich ist. ?. ?. die an die Datenbank gesendet werden. Die Fragezeichen sind Platzhalter für die Daten. wie wir es zuvor mit den Einstellungen beim EINSTELLUNGEN-Formular gemacht haben. food) VALUES (?.goBack(). food] Das ist ein Array mit den Werten. calories. } 1 Dieser Abschnitt enthält einige Variablen.currentDate gespeichert.} Diese anonyme Funktion wird ausgeführt. calories.val().transaction(2 function(transaction) { transaction. errorHandler Das ist der Name der Funktion.executeSql( ’INSERT INTO entries (date. return false. [date. in sessionStorage. jQT. calories.’. ?).currentDate. errorHandler ).

die Sie vorgenommen haben. Wie wir zuvor schon bei der Seite EINSTELLUNGEN gesehen haben. die als dritter Parameter übergeben wird.. dass Sie in einem Fehler-Handler eine SQL-Anweisung ausführen wollen. die beim Debugging oder Crash-Reporting genutzt werden können. Manchmal möchten Sie in Abhängigkeit von der Art des Fehlers entscheiden. Fehler-Handler müssen true oder false liefern. es wird nur ausgeführt. vielleicht. »Ja. transaction. wenn Sie die errors-Tabelle erstellt haben.’. } Der Fehler-Handler erhält zwei Parameter: das Transaktionsobjekt und das Fehlerobjekt. error.message]). ?). error) { alert(’Fehler: ’+error. dass die Einträge. aus dem Fehler-Handler heraus weitere executeSql()-Aufrufe durchzuführen. return false.message+’ (Code ’+error. auf dem »Abbrechen« steht und der nicht wie ein Pfeil nach links geformt ist. »Nein. wird die Ausführung angehalten und die Transaktion vollständig zurückgerollt. Liefert ein Fehler-Handler false (d. wird die anonyme Funktion ausgeführt.Fehlerbehandlung Ist das Einfügen erfolgreich. bricht der Button ABBRECHEN die Absenden-Aktion nicht ab – eigentlich ist das nur ein ZURÜCKButton. das ist ein fataler Fehler«).code+’)’). wird die Funktion errorHandler() ausgeführt.executeSql(’INSERT INTO errors (code. Ist das Einfügen nicht erfolgreich. um den Benutzer zu benachrichtigen und ihm die Meldung und den Fehlercode mitzuteilen. dass die Fehler-Handler-Funktion neben dem Fehlerobjekt auch ein Transaktionsobjekt erwartet. um die Seite NEUER EINTRAG zu schließen und zur Seite TAG zurückzukehren. die ausgelöst wurden. Wahrscheinlich ist Ihnen aufgefallen.code. um den Fehler zu protokollieren oder um einige Metadaten aufzuzeichnen. das ist kein fataler Fehler«).h. error) { alert(’Fehler: ’+error.h. } Web SQL Database | 85 . Sie ruft die Funktion refreshEntries() auf (zurzeit aktualisiert diese nur den Titel der Seite TAG..message+’ (Code ’+error. so beispielsweise (das ist nur ein Beispiel. wird die Ausführung fortgesetzt. Fügen Sie der Datei kilo.js Folgendes hinzu: function errorHandler(transaction. Hier nutzen wir das Fehlerobjekt. Tabelle 5-1 am Ende dieses Kapitels zeigt Ihnen die (aktuell) möglichen Fehlercodes gemäß der Web SQL Database-Working-Draft-Spezifikation des W3C. [error. message) VALUES (?. ob Sie true oder false liefern sollten. in der dortigen Liste erscheinen) und simuliert ein Tippen auf den Button ABBRECHEN. Der Transaktionsobjekt-Parameter ermöglicht es Ihnen. In einigen Fällen kann es möglich sein. die es referenziert): function errorHandler(transaction. sie wird aber bald dafür sorgen.code+’)’). Liefert ein Fehler-Handler true (d. return true.

wird die vollständige Transaktion – einschließlich dieser SQL-Anweisung – zurückgerollt und verhindert so das gewünschte Ergebnis. return false. wenn die executeSql()-Anweisung ausgeführt werden soll. werden wir die Datenbank auf Einträge für das ausgewählte Datum abfragen und diese dann an das #date ul-Element anhängen. [date. Hier ist eine Version der Funktion createEntry(). bei der am Ende die Transaktions-Callbacks angehängt wurden (fügen Sie diese kilo.val().html.’. db.currentDate. dann Erfolg (also genau umgekehrt wie bei executeSql()). Das gibt Ihnen einen geeigneten Platz für Code. nachdem eine lange Reihe von executeSql()-Anweisungen abgeschlossen wurde. dass sie nicht mehr nur die Titelleiste des ausgewählten Tages setzt. Liefern wir true (oder gar nichts).Achten Sie hier besonders darauf. Seltsamerweise ist die erforderliche Parameterreihenfolge für die Callbacks der Methode transaction Fehler.executeSql( ’INSERT INTO entries (date. calories. dass Sie auch bei der transaction-Methode selbst Handler für den Erfolgsund den Fehlerfall angeben können. calories. dass wir uns diesen Code angesehen haben. transactionSuccessHandler ). die Funktion refreshEntries() dazu zu bringen. function(){ refreshEntries(). Sie müssen den Code also nicht erneut einfügen): 86 | Kapitel 5: Clientseitige Datenspeicherung .js nicht hinzu. errorHandler ). weil wir keine dieser Methoden definiert haben): function createEntry() { var date = sessionStorage. }. food]. Es ist eine Weile her. ?. jQT.goBack().transaction( function(transaction) { transaction. indem wir für die Struktur das verborgene entryTemplate-HTML nutzen. var food = $(’#food’). deswegen sehen Sie hier noch einmal die Seite TAG (sie befindet sich bereits in index. } Zeilen auswählen und Ergebnismengen verarbeiten Der nächste Schritt ist. ?). der ausgeführt werden soll. Genauer gesagt. Obwohl ich das in meinen Beispielen nicht tun werde. var calories = $(’#calories’).val(). food) VALUES (?. sollten Sie wissen. }. transactionErrorHandler. dass wir false aus dem Fehler-Handler liefern müssen.

currentDate.calories’).9 newEntryRow.item(i). Beim ersten Durchlauf hat das keinerlei Auswirkungen.text(currentDate).id). 5 function (transaction. i++) { var row = result.food).text(row. i < result.rows. newEntryRow.length. dass wir das style-Attribut des li auf display: none setzen mussten.1 $(’#date h1’). $(’#date ul li:gt(0)’).4 [currentDate]. newEntryRow.’.clone(). der in sessionStorage gespeichert ist. da das einzige li dasjenige mit der ID Web SQL Database | 87 .2 db.transaction(3 function(transaction) { transaction. um alle li-Elemente mit einem Index größer als 0 auszuwählen und zu entfernen. damit wir dieses HTML-Fragment als Schablone für die Datenbankzeilen nutzen können. newEntryRow.rows.text(row.data(’entryId’. Hier ist die vollständige Funktion refreshEntries().<div id="date"> <div class="toolbar"> <h1>Date</h1> <a class="button back" href="#">Back</a> <a class="button slideup" href="#createEntry">+</a> </div> <ul class="edgetoedge"> <li id="entryTemplate" class="entry" style="display:none">1 <span class="label">Beschreibung</span> <span class="calories">000</span> <span class="delete">Loschen</span> ¨ </li> </ul> </div> 1 Erinnern Sie sich.removeAttr(’id’).js durch Folgendes ersetzen: function refreshEntries() { var currentDate = sessionStorage. } }. result) {6 for (var i=0. 2 Diese Zeilen nutzen jQuerys gt()-Funktion ("gt" steht für »größer als«). } ).find(’. row.executeSql( ’SELECT * FROM entries WHERE date = ? ORDER BY food.find(’. errorHandler ). } 1 Diese beiden Zeilen setzen die Titelleiste der Seite TAG auf den Inhalt des currentDateWerts.calories).remove().8 newEntryRow.: newEntryRow.removeAttr(’style’).appendTo(’#date ul’).7 var newEntryRow = $(’#entryTemplate’). Sie müssen die vorhandene refreshEntries()-Funktion in kilo. damit es nicht auf der Seite erscheint? Das taten wir.label’).

wenn die Abfrage erfolgreich ist. das als Datenplatzhalter dient.und style-Attribute. das uns hier am meisten interessiert. um die Anzeige ordentlich zu gestalten (Abbildung 5-5). 4 Diese Zeile enthält den ersten Parameter für die executeSql-Anweisung. die in der for-Schleife auf der nächsten Zeile erscheint. Jede Zeile enthält eine Beschreibung. um neue Abfragen an die Datenbank zu senden. zeigt die Seite TAG ein li für jede Zeile in der Datenbank an. Das Entfernen des Stils macht die Zeile sichtbar.entryTemplate ist. Kalorien und einen LÖSCHEN-Button. Es hat drei schreibgeschützte Eigenschaften: rowsAffected. 3 Diese drei Zeilen richten die Datenbanktransaktion ein und führen die executeSqlAnweisung aus. Aber bei nachfolgenden Besuchen der Seite müssen wir alle anderen lis entfernen. von einer Insert-Operation betroffenen Zeile liefert.Das Objekt rows enthält 0 oder mehr row-Objekte und hat eine length-Eigenschaft. insertId. Updateoder Delete-Abfrage betroffen sind.und calories-Span-Kindelemente des lis mit den entsprechenden Daten aus dem row-Objekt. können Sie sehen. Da wir das in diesem Fall nicht benötigen werden. die Sie nutzen können. weil die Seite ansonsten mehrere Elemente mit der gleichen id enthielt. 88 | Kapitel 5: Clientseitige Datenspeicherung .Das Objekt result ist es. um die Anzahl von Zeilen zu ermitteln. das das aktuell ausgewählte Datum enthält. und rows. die die gefundenen Datensätze enthält. Es ist eine einfache SELECT-Anweisung mit einem Fragezeichen. Haben wir ein paar Zeilen erzeugt. wie wir es zuvor beim Fehler-Handler gesehen haben. das dem ausgewählten Datum entspricht. Die beiden nächsten Zeilen aktualisieren die label.Das Objekt transaction kann im Erfolgs-Handler genutzt werden. da wir immer wieder die gleichen Elemente hinzufügen. : Dieser Code hängt das li-Element an das ul an. werden wir es hier allerdings nicht nutzen. 8 Auf dieser Zeile nutzen wir clone(). 6 Diese anonyme Funktion wird ausgeführt. das den Index 0 hat und obendrein verborgen ist. die von einer Insert-. Nachdem wir all das aus dem Weg geschafft haben. 5 Das ist ein Array mit einem einzigen Element. Sie erwartet zwei Parameter: transaction und result. und das Entfernen der id ist wichtig. Dieses Element liefert den Wert für das Fragezeichen in der SQL-Abfrage. um die Variable row auf den Inhalt der aktuellen Zeile zu setzen. dass wir noch etwas CSS benötigen. 7 Diese Zeile nutzt die item()-Methode des rows-Objekts. falls sich der Benutzer entschließt. 9 Diese Zeile speichert den Wert der id-Eigenschaft der row als Wert auf dem li selbst (wir benötigen ihn später. und entfernen auf den nächsten beiden Zeilen die id. um das Schablonen-li zu klonen. die den Primärschlüssel der letzten. Andernfalls würden Einträge mehrfach in der Liste erscheinen. bevor wir die Zeilen aus der Datenbank wieder anhängen. den Eintrag zu löschen).

-webkit-border-image: url(themes/jqt/img/button.css ein. font-size: 12px.png) 0 5 0 5..delete { position: absolute.css"> Web SQL Database | 89 . border-width: 0 5px.0.7). text-shadow: 0 1px 2px rgba(0.html die folgende Zeile einfügen: <link type="text/css" rel="stylesheet" media="screen" href="kilo. Speichern Sie das folgende CSS in einer Datei namens kilo. right: 6px. top: 5px.css (und speichern Sie diese im gleichen Verzeichnis wie die HTML-Datei): #date ul li { position: relative. padding: 0 3px. indem Sie in den Head-Abschnitt von index. line-height: 30px.Abbildung 5-5: Die Einträge werden jetzt angezeigt. müssen aber noch mit etwas CSS aufpoliert werden. } #date ul li .0. } Binden Sie jetzt kilo. } #date ul li span { color: #FFFFFF.

Im Unterschied zu den Elementen der Seite TAGE sind die Elemente der Seite TAG nicht statisch. Die Lösung ist. wenn auf sie geklickt wird. Wenn die Anwendung startet. nachdem CSS auf sie angewandt wurde Zeilen löschen Damit unsere LÖSCHEN-Buttons etwas tun. an das wir den click-Handler binden könnten. dass wir sie mit Hilfe eines span-Tags eingebaut haben. Das heißt.Obwohl die LÖSCHEN-Buttons jetzt wie Buttons aussehen (siehe Abbildung 5-6). gibt es überhaupt noch keine Einträge in der Seite TAG. wenn sie in der Funktion refreshEntries() erzeugt werden. Das liegt daran. Leider funktioniert dieses Verfahren in diesem Fall nicht. sie werden während der Sitzung hinzugefügt und entfernt. tun sie noch nichts. Fügen Sie dazu am Ende der for-Schleife die fettgedruckten Zeilen ein: 90 | Kapitel 5: Clientseitige Datenspeicherung . das kein interaktives Element in einer HTML-Seite ist. Deswegen gibt es beim Start nichts. indem wir jQuerys click()-Methode genutzt haben. wenn darauf getippt wird. Das Gleiche haben wir zuvor mit den Elementen in der TAG-Seite gemacht. müssen wir mit jQuery einen Click-Event-Handler an sie binden. Abbildung 5-6: Die Einträge. dass wir die click-Events an die LÖSCHEN-Buttons binden.

3 Diese Zeile setzt die Variable clickedEntryId auf den Wert der entryId.calories). wird das Elternelement des LÖSCHEN-Buttons (d. Als drittes Argument würde der Handler für den Erfolgsfall folgen. aber eigentlich mussten wir gar nicht so viel Code schreiben. newEntryRow. Die click()-Methode akzeptiert als Parameter eine anonyme Funktion. Es hat schon eine ganze Menge an Beschreibung erfordert. Und damit haben Sie es geschafft..click(function(){1 var clickedEntry = $(this). errorHandler).find(’. [id].’.h. Web SQL Database | 91 . dass wir angeben.parent(). als es von der Funktion refreshEntries() erstellt wurde. Fügen Sie folgende deleteEntryById()-Funktion zu kilo.js hinzu. und auf der nächsten Zeile entfernt jQuerys slideUp()-Methode das li aus der Seite. } 1 Die Funktion beginnt damit.data(’entryId’). Wir übergeben die SQL-Abfrage und die ID des angeklickten Datensatzes als die beiden ersten Argumente. die das Event verarbeitet. geben wir einfach null an.executeSql(’DELETE FROM entries WHERE id=?. den wir schon die ganze Zeit nutzen. aber da wir einen solchen hier nicht benötigen. bis wir diesen Punkt erreicht haben.2 var clickedEntryId = clickedEntry.find(’. die die Klasse delete haben und sich in einem Element mit der ID date befinden. übergeben ihr eine Callback-Funktion mit dem Transaktionsobjekt als Parameter und rufen die Methode executeSql() auf..transaction( function(transaction) { transaction. } ). 2 Wird der Click-Handler angestoßen. das li) aufgesucht und in der Variablen clickedEntry gespeichert. Als viertes Argument geben wir den Fehler-Handler an.3 deleteEntryById(clickedEntryId). öffnen wir eine Transaktion.text(row. 4 Diese Zeile übergibt die angeklickte ID an die Funktion deleteEntryById(). dass wir nach Elementen suchen.js nur rund 100 Zeilen JavaScript (siehe Beispiel 5-1). newEntryRow. null.slideUp().delete’). Tatsächlich enthält kilo. und sie ruft die click()-Methode auf diesen Elementen auf.calories’)..4 clickedEntry. um den Eintrag aus der Datenbank zu entfernen: function deleteEntryById(id) { db. } Wie wir es in den vorangegangenen Beispielen getan haben. }). die wir auf dem li-Element gespeichert haben.

food]. date.weight).’ ). ’ + ’ calories INTEGER NOT NULL).executeSql( ’CREATE TABLE IF NOT EXISTS entries ’ + ’ (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT.click(function(){ var dayOffset = this. db. localStorage.val().val().executeSql( ’INSERT INTO entries (date.getFullYear(). $(’#weight’). var shortName = ’Kilo’. $(’#dates li a’). jQT. } function createEntry() { var date = sessionStorage.’.val(localStorage. return false.currentDate.val(). version. ’ + ’ date DATE NOT NULL. var food = $(’#food’). $(’#settings form’).submit(createEntry). calories.currentDate = date. food) VALUES (?.weight = $(’#weight’).submit(saveSettings). sessionStorage. maxSize).age).jQTouch({ icon: ’kilo.val().transaction( function(transaction) { transaction. }). [date.Beispiel 5-1: Das vollständige JavaScript für die »Kilo«-Datenbankinteraktion var jQT = $. var displayName = ’Kilo’.age = $(’#age’).getDate() + ’/’ + date. }). function loadSettings() { $(’#age’).val(localStorage.goBack(). db = openDatabase(shortName. refreshEntries(). db. localStorage.budget = $(’#budget’). var date = new Date(). calories.dayOffset). var calories = $(’#calories’). food TEXT NOT NULL. } function saveSettings() { localStorage. displayName. ?.0’. $(’#budget’).val(localStorage. ?).ready(function(){ $(’#createEntry form’). function(){ 92 | Kapitel 5: Clientseitige Datenspeicherung . $(’#settings’).id. var maxSize = 65536.png’ }).bind(’pageAnimationStart’.val().setDate(date. var version = ’1. loadSettings).getDate() . var db.getMonth() + 1 + ’/’ + date. $(document).transaction( function(transaction) { transaction. } ).budget).

} ).text(row.removeAttr(’id’).text(row.code+’)’). newEntryRow. } function deleteEntryById(id) { db.’.rows. } ).calories’). error) { alert(’Fehler: ’+error. function (transaction.item(i).find(’.parent().removeAttr(’style’). errorHandler ).click(function(){ var clickedEntry = $(this). }.food). [currentDate].length. $(’#date h1’). } function errorHandler(transaction. newEntryRow. return true.rows. $(’#date ul li:gt(0)’). newEntryRow. newEntryRow.text(currentDate). db. }). } Web SQL Database | 93 . deleteEntryById(clickedEntryId).clone(). errorHandler).refreshEntries().transaction( function(transaction) { transaction. } }. clickedEntry. newEntryRow. return false. i++) { var row = result. result) { for (var i=0. } function refreshEntries() { var currentDate = sessionStorage.transaction( function(transaction) { transaction.find(’. row. null.find(’. var clickedEntryId = clickedEntry. [id].label’).data(’entryId’.goBack().’.id). var newEntryRow = $(’#entryTemplate’).data(’entryId’).calories). errorHandler ). newEntryRow.executeSql( ’SELECT * FROM entries WHERE date = ? ORDER BY food.appendTo(’#date ul’). i < result.message+’ (Code ’+error. newEntryRow. jQT.remove().currentDate.delete’).slideUp().executeSql(’DELETE FROM entries WHERE id=?. } ).

Das Einzige.B. die von keinem anderen Fehlercode abgedeckt werden.changeVersion() eine Version übergeben wurde. Der SQL-Modifizierer LIMIT könnte nützlich sein.oder REPLACE-Anweisung schlug aufgrund eines Constraint-Fehlers fehl. UPDATE.changeVersion() oder DatabaseSync. COMMIT oder ROLLBACK) oder weil die Anweisung versuchte. die nicht der tatsächlichen Datenbankversion entspricht. Insbesondere Web SQL Database bietet Ihnen bei der Entwicklung webbasierter Anwendungen eine ganze Welt von Möglichkeiten. wenn wir all diese Sachen lokal auf dem Gerät speichern könnten? Ja.oder DatabaseSync-Objekte entspricht oder dass den Methoden Database. Beispielsweise wurde versucht. das wäre es. um den Umfang der Ergebnismenge zu reduzieren. weil die Anzahl der Argumente nicht der Anzahl der ?-Platzhalter in der Anweisung entsprach oder weil die Anweisung versuchte. die Datenbank zu modifizieren. um Benutzerdaten auf dem Client zu speichern: Web Storage und Web SQL Database. die im Primärschlüsselfeld einen Wert enthält. eine Zeile einzufügen. was uns davon abhält. Die Anweisung schlug fehl. Die Anweisung schlug aufgrund eines Syntaxfehlers fehl.Was Sie gelernt haben In diesem Kapitel haben Sie zwei Verfahren kennengelernt. Tabelle 5-1: Web Database-Fehlercodes Konstante UNKNOWN_ERR DATABASE_ERR VERSION_ERR Code 0 1 2 Situation Die Transaktion schlug aus Gründen fehl. weil die aktuelle Datenbankversion nicht korrekt ist. weil die von der Datenbank gelieferten Daten zu groß waren. Eine INSERT-. Wäre es nicht nett. der in der entsprechenden Spalte bereits vorhanden ist. z. die nicht gestattet ist (wie BEGIN. Referenz zu den Web Database-Fehlercodes Ein Fehler in einer SQL-Datenbank-API wird über ein Callback gemeldet. dass die tatsächliche Datenbankversion nicht mehr der erwarteten Version der Database. ist. die nichts mit der Datenbank selbst zu tun haben und von keinem der anderen Fehlercodes abgedeckt werden. diese Anwendung auch im Offline-Modus auszuführen. weil es nicht genug freien Speicherplatz gab oder das Speicher-Quota erreicht wurde und der Benutzer der Anwendung keinen weiteren Speicherplatz zugestanden hat. Die Sperre für die Transaktion konnte in der vorgegebenen Zeit nicht eingerichtet werden. TOO_LARGE_ERR 3 QUOTA_ERR SYNTAX_ERR 4 5 CONSTRAINT_ERR TIMEOUT_ERR 6 7 94 | Kapitel 5: Clientseitige Datenspeicherung . Die Anweisung schlug aus Datenbankgründen fehl. dass bei jedem Start der Anwendung eine Verbindung mit dem Webserver hergestellt werden muss. um das HTML und die mit ihm verbundenen Ressourcen herunterzuladen. eine Anweisung zu nutzen. Beispielsweise kann eine Anweisung festgestellt haben. Die Operation schlug fehl. Die Anweisung schlug fehl. das einen der Codes aus Tabelle 5-1 erhält. obwohl die Transaktion schreibgeschützt war.

jpg scripts/demo. Das Manifest enthält eine Liste der Dateien.css index.html ist die Seite. die das Gerät des Anwenders herunterladen und speichern muss. wie Sie das Gelernte auf das Kilo-Beispiel anwenden. Eine Manifest-Datei ist ein einfaches Textdokument. anstatt sie aus dem Netzwerk zu beziehen. nachdem die Datei hinzugefügt wurde: demo. CSS. Anschließend werde ich Ihnen zeigen. die er zur Anzeige der Seite benötigt (HTML. Hier ist der Inhalt des Verzeichnisses. die es Nutzern ermöglicht. Die anderen Dateien werden aus index. wenn keine Verbindung zum Internet besteht. erkennt der Browser die URL wieder und liefert die Dateien aus dem lokalen Anwendungs-Cache.html logo.jpg | 95 . lädt der Browser alle Dateien.manifest index.html referenziert. Die Grundlagen des Offline Application Caches Die Hauptkomponente eines Offline Application Caches ist eine Cache-Manifest-Datei. Betrachten Sie ein Webverzeichnis mit den folgenden Dateien: index. Um alles offline verfügbar zu machen. um die entsprechenden Konzepte zu erläutern. JavaScript. Geht der Anwender das nächste Mal zu dieser Web-App. das sich auf Ihrem Webserver befindet und an das Gerät des Anwenders mit dem Inhaltstyp cache-manifest geliefert wird.KAPITEL 6 Offline gehen In HTML5 gibt es eine Funktionalität namens Offline Application Cache.) herunter und speichert sie.js styles/screen. erstellen Sie eine Datei namens demo. Bilder usw.html logo. an dem wir gearbeitet haben. Ich werde ein einfaches Beispiel nutzen. die Anwender in ihren Browern laden. Web-Apps auszuführen. Diese funktioniert so: Navigiert der Anwender zu einer Web-App. wenn sie die Anwendung besuchen. damit die App funktioniert.manifest in diesem Verzeichnis. die Sie auf Ihrem Webserver vorhalten.

com/index.html ein manifest-Attribut hinzufügen: <html manifest="demo. bietet Ihnen Ihr Provider eventuell Einstellungsmöglichkeiten für Ihre Website.manifest die folgenden Zeilen hinzu: CACHE MANIFEST index. dass er das macht).html abstattet.css Nachdem Sie die Manifest-Datei erstellt haben.htaccess-Datei bei Ihnen nicht funktioniert.manifest mit dem MIME-Typ text/cache-manifest verbinden. indem Sie in Ihr Webverzeichnis eine . werfen Sie einen Blick in den Teil der Dokumentation Ihres Webservers. greift der Anwender.html durch die URL Ihrer Web-App).js http://www. Unser Offline Application Cache ist jetzt einsatzbereit.htaccess-Datei mit folgendem Inhalt einfügen: AddType text/cache-manifest . den ein Anwender http://example.css Fügen Sie dann demo.scripts/demo.com/index.com/logo. Sie werden gleich sehen.com/styles/screen. 96 | Kapitel 6: Offline gehen .manifest Wenn die .manifest"> Sie müssen die Manifest-Datei mit dem Inhaltstyp text/cache-manifest liefern. lokal gespeichert.htaccess-Datei ein PHP-Skript nutzt (weil PHP den MIME-Typ in Code setzen kann. wird die Seite samt aller Ressourcen über das Netzwerk geladen (ersetzen Sie example.example. Sie müssen die Dateierweiterung . nur auf die lokalen Dateien zu. das statt einer .jpg scripts/demo. müssen Sie sie einbinden.com/scripts/demo.html http://www. Dann kann auch nach einer Trennung der Internetverbindung auf die Web-App zugegriffen werden. Wenn Sie den Apache-Webserver oder einen kompatiblen Webserver nutzen. erreichen Sie das.css Die Pfade im Manifest sind relativ zum Ort der Manifest-Datei. Ist alles gespeichert.example. Sie können auch absolute URLs nutzen (machen Sie sich noch nicht die Mühe.html logo. damit der Browser sie erkennt. müssen Sie den Webserver nicht mehr so konfigurieren. die im Manifest aufgeführt sind.example. Wenn Ihre Website von einem WebhostingProvider gehostet wird.com/index.example.js styles/screen. wo Sie den entsprechenden MIME-Typ ergänzen können. Ich werde Ihnen zusätzlich etwas später in diesem Kapitel ein Beispiel zeigen. wenn er die Seite aktualisiert.jpg http://www. Im Hintergrund werden alle Dateien. der sich auf MIME-Typen bezieht.js styles/screen. indem Sie dem HTML-Tag in index. die Datei zu erstellen. wie Sie das auf Ihre Anwendung anwenden): CACHE MANIFEST http://www. Beim nächsten Besuch.

gehen Sie zu SHARING. (Unten im Fenster können Sie eine Liste der Editorbefehle sehen. und geben Sie die folgenden Befehle ein (Sie werden zur Eingabe Ihres Passwort aufgefordert): cd /etc/apache2/users sudo pico $USER.htaccess-Dateien in Ihrem persönlichen Webordner ignoriert (der Websites-Ordner in Ihrem Benutzerverzeichnis). Nutzen Sie die Pfeiltasten. ob es Änderungen gibt.htaccess können Sie mit den folgenden Schritten aktivieren: 1. wenn geprüft wird. Deaktivieren Sie die Checkbox neben WEB-SHARING. lädt der Browser alle darin aufgeführten Dateien im Hintergrund in einen temporären Cache herunter. antworten Sie mit Y. Die Unterstützung für . Hat sich das entfernte Manifest geändert. um Änderungen vorzunehmen«. wenn Sie dazu aufgefordert werden. um festzustellen. wenn wir Änderungen an der Website vornehmen? Hat der Anwender Zugang zum Internet und geht er zur URL der Web-App. Öffnen Sie PROGRAMME→DIENSTPROGRAMME→TERMINAL. um die Datei zu speichern. und drücken Sie Return. löschen Sie das Wort None. um den Editor zu beenden. werden . Der Vergleich zwischen dem lokalen und dem entfernten Manifest ist ein byteweiser Vergleich der Dateiinhalte (Kommentare und leere Zeilen eingeschlossen). 5. Die Grundlagen des Offline Application Caches | 97 . und klicken Sie. um zur Zeile AllowOverride None hinabzugehen. Geben Sie Ihr Passwort ein. haben wir ein neues Problem: Wie erhält er Aktualisierungen. werden beim nächsten Start der App die neuen Dateien verwendet. ob sie noch der lokalen Kopie entspricht. prüft der Browser die Manifest-Datei auf der Site. wird der partiell heruntergeladene Cache automatisch verworfen und der alte bleibt bestehen. Der Webserver auf Ihrem Mac sollte jetzt die Einstellungen in den .htaccess«-Datei Wenn Sie Webseiten in Ihrem lokalen Netzwerk über den in Mac OS X integrierten Apache Webserver ausliefern. Starten Sie die SYSTEMEINSTELLUNGEN. 3. 4.Mac OS X und die ». Das ^-Symbol zeigt die Control-Taste an. Der Dateiveränderungszeitstempel oder Änderungen an einer der betroffenen Ressourcen sind irrelevant. um die Änderungen zu speichern. und ersetzen Sie es durch All. und aktivieren Sie sie dann erneut (so starten Sie das Web-Sharing neu). Da der Anwender jetzt lokal auf seinem Gerät auf unsere Dateien zugreift. die Sie im Sites-Verzeichnis oder seinen Unterverzeichnissen angeben.conf Das lädt Ihre persönliche Apache-Konfigurationsdatei im pico-Editor. Wenn während des Downloads etwas schiefgeht (z. Ist der Download erfolgreich.htaccess-Dateien respektieren. auf das Symbol mit der Beschriftung »Klicken Sie auf das Schloss.) 2.B. Drücken Sie Control-X. die Internetverbindung unterbrochen wird). falls das erforderlich ist.

wird das Bild als defekter Bild-Link (Abbildung 6-1) angezeigt. nutzen Sie das Schlüsselwort FALLBACK. Sie starten eine Anwendung.css NETWORK: logo. um folgendermaßen eine Ausweichressource anzugeben: CACHE MANIFEST index.applicationCache-Objekt überwachen. dass der Benutzer auch nach Abschluss des Downloads noch mit alten Dateien arbeitet. damit die Updates wirksam werden. wenn der Download abgeschlossen ist.jpg jetzt im NETWORK-Abschnitt der Manifest-Datei aufgeführt wird. wenn der Benutzer offline ist. wenn der Anwender die App neu startet. den Browser zu zwingen. Sie bestätigen den Download der Updates. Ist er online. Die neuen Dateien.js styles/screen.html scripts/demo.Denken Sie daran. Die Online-Whitelist. Sollen Anwender offline kein defektes Bild sehen. dass es Updates gibt. Wollen Sie angeben.js styles/screen. Das bedeutet.html scripts/demo. nutzen Sie folgendermaßen das Schlüsselwort NETWORK: (der nachfolgende : ist wichtig) in der Manifest-Datei: CACHE MANIFEST index. dass der Browser die entsprechenden Dateien nicht lokal speichert. und diese sagt Ihnen. auf bestimmte Ressourcen immer über das Netzwerk zuzugreifen (diesen Vorgang bezeichnet man als Whitelisting). und den Benutzer dann auf die gewünschte Art benachrichtigen. dass eine Ressource nur online verwendet werden soll.jpg Da logo. sie also nicht verfügbar sind. nachdem die Anwendung gestartet wurde. die im Hintergrund heruntergeladen wurden. können Sie das updateready-Event auf dem window.jpg offline. dass die neuen Dateien bei einer Aktualisierung des Manifests im Hintergrund heruntergeladen werden. die Anwendung neu zu starten. erscheint es normal (Abbildung 6-2).jpg 98 | Kapitel 6: Offline gehen . Das heißt. werden erst aktiv. befindet es sich auf der Whitelist.css FALLBACK: logo. Wenn Sie in Ihrer App ein derartiges Verhalten implementieren wollen. Anders gesagt. die aktuell geladene Seite und die auf sie bezogenen Dateien werden nicht automatisch neu geladen. Das gleicht dem Aktualisierungsverhalten einer gewöhnlichen Desktopanwendung. und Sie werden aufgefordert. wie es in Abschnitt »Die JavaScript-Konsole« auf Seite 108 beschrieben wird. der Download wird abgeschlossen.und -Fallback-Optionen Es ist möglich. Ist der Benutzer offline.

Abbildung 6-2: Bilder auf der Whitelist werden normal angezeigt.jpg (Abbildung 6-3).Ist der Anwender offline. wenn der Anwender online ist.jpg (Abbildung 6-4). Abbildung 6-1: Bilder auf der Whitelist werden als defekte Bild-Links angezeigt. Ist er online. sieht er jetzt offline. Die Online-Whitelist. sieht er logo. wenn der Anwender offline ist.und -Fallback-Optionen | 99 .

wird eine Ausweichressource angezeigt. 100 | Kapitel 6: Offline gehen . Abbildung 6-4: Ist der Anwender online. werden die normalen Bilder aus dem Web angezeigt.Abbildung 6-3: Ist der Anwender offline.

In diesem Fall sollten Sie ein anderes Verfahren erwägen (z. Ob Sie den NETWORK. die zur Ausführung Ihrer App erforderlich sind.oder FALLBACK-Abschnitten der Manifest-Datei Ressourcen hinzufügen sollten. Apps lokal auf dem Gerät zu speichern.jpg und logo2. Es wäre deswegen recht umständlich. Angenommen. sieht er jetzt offline. Die Datei wird automatisch lokal gespeichert. In den meisten Fällen sollten Sie alle Dateien. dass er für alle Ressourcen im Ordner images die Datei offline.css Jetzt kann ich dem Browser folgendermaßen sagen. in der Manifest-Datei aufführen. sieht er logo. wenn Sie sich überlegen. Denken Sie daran.html scripts/demo.js /styles/screen.jpg einsetzen soll: CACHE MANIFEST index.B.jpg (Abbildung 6-5). wie Sie diese im Manifest referenzieren sollen. sehen Sie.jpg /scripts/demo.Sie sollten sich merken. können wir daran gehen. ist Ihre App wahrscheinlich nicht gut für den Offline Application Cache geeignet.jpg /images/offline.html /images/logo. Eine dynamische Manifest-Datei erstellen Da Sie jetzt mit der Funktionsweise des Offline-App-Caches vertraut sind. vielleicht eine clientseitige Datenbank). ich füge meiner Website ein images-Verzeichnis hinzu und packe einige Dateien in es: /demo.css FALLBACK: images/ images/offline.jpg nicht zusätzlich im CACHE MANIFEST-Abschnitt angeben müssen. sie alle einzeln der Eine dynamische Manifest-Datei erstellen | 101 .jpg (Abbildung 6-6). hängt von der Natur Ihrer Anwendung ab. Wie praktisch das wirklich sein kann.jpg Ist der Benutzer offline. dass der Offline Application Cache in erster Linie dazu dient. Kilo besteht mittlerweile aus einer ganzen Reihe von Dateien. einen solchen in unserer Kilo-App zu nutzen. Wenn Sie große Mengen dynamischer Inhalte haben und nicht wissen. ist er online.js styles/screen.jpg /images/logo2. die Server-Last zu vermindern oder die Leistung zu verbessern usw. da sie im FALLBACK-Abschnitt des Manifests aufgeführt wird. indem Sie einen partiellen Pfad nutzen. dass Sie offline.manifest /index. Er ist eigentlich nicht dazu gedacht. dass Sie eine einzige Ausweichressource für viele Ressourcen angeben können.

4.wikipedia. Wenn Ihr Webserver unter Windows läuft. dass diese Zeile aktiv ist. bestätigen Sie mit Y das Speichern der Änderungen. Nutzen Sie die Pfeiltasten. Geben Sie Ihr Passwort ein. Öffnen Sie PROGRAMME→DIENSTPROGRAMME→TERMINAL.conf. um Seiten an Ihr Android-Gerät auszuliefern. Um PHP im benutzerspezi- fischen public_html-Verzeichnis zu aktivieren. Aber Sie müssen wie in »Mac OS X und die ».php.php endet. Ihr Passwort einzugeben): cd /etc/apache2 sudo pico httpd. Wenn Sie einen Webserver auf Ihrem eigenen Rechner genutzt haben. Geben Sie php5 ein. dass die App offline funktioniert. Erstellen Sie im Websites-Unterverzeichnis Ihres Benutzerverzeichnisses eine Datei namens test. und löschen Sie das #-Kommentarzeichen. deren Name mit der Dateinamenserweiterung . und geben Sie die folgenden Befehle ein (Sie werden aufgefordert. 6. und aktivieren Sie sie dann wieder. Jetzt sollte PHP auf dem Webserver Ihres Macs aktiviert sein.php mit folgendem Inhalt: 102 | Kapitel 6: Offline gehen . das verhindert. um den Editor zu beenden. Gehen Sie zu SHARING. befolgen dabei die Anweisungen darin und kommentieren einige Zeilen aus (indem Sie ihnen ein # voranstellen). die von den meisten Hosting-Providern unterstützt wird. um Änderungen vorzunehmen«. bearbeiten Sie als Root die Datei /etc/ apache2/mods-available/php5. um PHP zu aktivieren: 1.conf 2. wenn Sie zur Eingabe aufgefordert werden. PHP-Skripten auf Ihrem Webserver ausführen PHP ist eine vielseitige Skriptsprache für das Web. Deaktivieren Sie die Checkbox neben WEB-SHARING. wenn Sie PHP-Skripten ausführen wollen. und klicken Sie falls erforderlich auf das Schlosssymbol neben dem Eintrag »Klicken Sie auf das Schloss. finden Sie Downloads und Informationen unter http://php. um die Datei zu speichern. um zum Anfang der Zeile zu gehen. Das heißt.easyphp. Das öffnet die Option zum Durchsuchen der Datei. und drücken Sie Return. Auf Macs ist PHP installiert. müssen Sie ihn entsprechend einrichten. dass Sie auf den meisten Webservern eine Datei erstellen können. Ubuntu-Nutzer können beispielsweise einfach sudo aptitude install apache2 php5 auf der Shell eingeben. Drücken Sie Control-W. ihr etwas PHP-Code hinzufügen und sie mit dem Webbrowser besuchen können. Öffnen Sie anschließend die SYSTEMEINSTELLUNGEN. Drücken Sie Control-X. Außerdem würde ein einziger Tippfehler die vollständige Manifest-Datei ungültig machen und verhindern. ohne dass Sie dazu noch etwas Weiteres tun müssen.Manifest-Datei hinzuzufügen. 7. die Sie unter http://en.net/manual/en/install. 5.htaccess«-Datei« auf Seite 97 einen Schritt unternehmen. die so aussehen sollte: #LoadModule php5_module libexec/apache2/libphp5.so 3.windows. Eventuell sollten Sie eine Lösung wie EasyPHP (http://www. Unter Linux ist PHP leicht zu installieren. und drücken Sie Return.org/ ) nutzen oder einen Blick auf die Wikipedia-Seite zu diesem Thema werfen. Das führt Sie zu einer Zeile.org/wiki/Comparison_of_WAMPs finden.

Funktioniert PHP nicht.<?php phpinfo(). ?> 8. sollten Sie eine Tabelle sehen.php. Abbildung 6-5: Ist der Benutzer offline. Eine dynamische Manifest-Datei erstellen | 103 . Unter http://www. die Ihre PHP-Versionsnummer und eine Menge anderer Informationen zu Ihrer PHP-Installation anzeigt. sehen Sie nur eine leere Seite. indem Sie echo $USER eingeben und Return drücken).net/support. Besuchen Sie dann mit Ihrem Browser die folgende URL: http://localhost/~IHR_ BENUTZERNAME/test.php finden Sie Links auf Dokumentationen und Hilfe zur Verwendung von PHP.php. wird ein einzelnes Ausweichbild anstelle der anderen Bilder angezeigt. Wenn PHP funktioniert. aber löschen Sie das ~ nicht (Ihren Benutzernamen können Sie im Terminal herausfinden. Ersetzen Sie IHR_BENUTZERNAME durch Ihren Benutzernamen.

2 Wie ich in diesem Kapitel bereits erwähnt habe./manifest. 0.Abbildung 6-6: Die Bilder aus dem Web werden angezeigt.htaccess-Datei den Inhaltstyp für eine Manifest-Datei angeben. die den Inhalt des Anwendungsverzeichnisses (und seiner Unterverzeichnisse) liest und für uns die Dateiliste erstellt. können Sie sie also löschen. wenn der Benutzer online ist.1 echo "CACHE MANIFEST\n". ’/.6 } } ?> 1 Die PHP-Funktion header gibt diese Datei mit dem Inhaltstyp cache-manifest aus.htaccess-Datei nicht zu anderen Zwecken benötigen.php" && !strpos($file. Wenn Sie die in erstellte .3 foreach(new RecursiveIteratorIterator($dir) as $file) {4 if ($file->IsFile() &&5 $file != ".") { echo $file . 1) != ". "\n". Auf diese Weise kann man ohne eine . Um das zu beheben. Erstellen Sie im Kilo-Verzeichnis eine neue Datei namens manifest.2 $dir = new RecursiveDirectoryIterator(". muss die erste Zeile einer Cache-Manifest-Datei CACHE MANIFEST lauten. werden wir eine kleine PHP-Datei schreiben.’) && substr($file->getFilename(). Für den Browser ist das die erste Zeile des Dokuments. und fügen Sie ihr den folgenden Code hinzu: <?php header(’Content-Type: text/cache-manifest’). 104 | Kapitel 6: Offline gehen .").php.

/themes/apple/img/toggle. und der Browser sieht nur die Ausgabe von Befehlen wie echo./kilo.css ./themes/apple/img/pinstripes. gibt es noch Dateien in Unterverzeichnissen. findet es auch diese./themes/apple/img/blueButton.png .png .transitions./jqtouch/jqtouch./themes/apple/img/cancel.png . und ignoriert Dateien mit dem Namen manifest.png .css ./themes/apple/img/backButton./themes/apple/img/on_off./themes/apple/img/listArrowSel. prüfen. beginnt.html .png Eine dynamische Manifest-Datei erstellen | 105 . 4 Bei jedem Durchlauf der Schleife setzt das Programm die Variable $file auf ein Objekt. der . deren Name mit einem ./ ist Teil des vollständigen Pfadnamens der Datei.png ./themes/apple/img/chevron.png . beginnen (wie .gif . die den Dateinamen ohne den vorangestellten Pfad liefert.« 5 Diese if-Anweisung prüft./jqtouch/jquery. und der / trennt die Elemente des Pfades der Datei. beginnt ( wie .png . die mit einem .png .php sowie alle Dateien. die du im aktuellen Verzeichnis und seinen Unterverzeichnissen findest./themes/apple/img/grayButton.png . Auf Deutsch hieße das: »Setze bei jeder Runde die Variable $file auf die nächste Datei. d./index.js . Aber wenn Sie den Dateinamen auf einen vorangestellten Punkt . Für den Browser sieht manifest.h.htaccess) oder in einem Verzeichnis enthalten sind.js .js . So können Sie Dateien aufspüren./themes/apple/img/toggleOn. das alle Dateien im aktuellen Verzeichnis aufführt. das mit einem .php so aus: CACHE MANIFEST . 6 Dieser Abschnitt zeigt die Namen aller Dateien an././themes/apple/img/thumb.png . Es gibt vor dem Dateinamen in der Ausgabe also immer ein .png . das eine der Dateien im aktuellen Verzeichnis repräsentiert./kilo. nutzen Sie die Funktion getFilename./jqtouch/jqtouch.svn). die Text ausgeben./jqtouch/jqtouch. verweist auf das aktuelle Verzeichnis./themes/apple/img/loading.png .. Das macht es rekursiv.js . selbst wenn diese tief in Unterverzeichnissen vergraben sind. Das vorangestellte . ob die Datei tatsächlich eine Datei ist (kein Verzeichnis oder symbolischer Link)./themes/apple/img/listGroup.die PHP-Datei läuft auf dem Webserver./themes/apple/img/selection. 3 Diese Zeile erstellt ein Objekt namens $dir.

php"> Jetzt wird das Manifest dynamisch generiert. Die Dateien LICENSE.. dass Ihr jQTouch-Paket zusätzliche Dateien enthält./themes/jqt/img/rowhead.php).svn sehen./themes/jqt/img/toggle.png .txt und sample. echo "CACHE MANIFEST\n".php" && substr($file->getFilename()./themes/jqt/img/button./themes/jqt/img/back_button_clicked. liegt das wahrscheinlich daran. und fügen Sie in das head-Element folgendermaßen einen Verweis auf manifest. wenn sich der Inhalt des Manifests geändert hat). wenn sich eine der Dateien im Verzeichnis ändert (erinnern Sie sich daran. Passen wir es also an.txt./themes/jqt/img/chevron_circle./themes/jqt/img/loading.htaccess können Sie löschen.gif ./themes/jqt/img/chevron.png . können Sie auch diese löschen (es sei denn. Öffnen Sie jetzt index. dass Sie sie mit einer HTTP-URL wie http://localhost/~IHR_BENUTZERNAME/ manifest./themes/jqt/img/whiteButton. Hier ist die modifizierte Datei manifest.png . Wenn Sie in Ihrer Liste mehr Dateien sehen.css Versuchen Sie.php ein: <html manifest="manifest.png . damit sich sein Inhalt ändert.1 $dir = new RecursiveDirectoryIterator("./themes/apple/img/toolbar./manifest.png ./themes/jqt/img/back_button. Dateien./themes/jqt/img/toggleOn./themes/apple/img/toolButton.png ./themes/jqt/img/grayButton. 0./themes/jqt/theme.png .") 106 | Kapitel 6: Offline gehen .html. foreach(new RecursiveIteratorIterator($dir) as $file) { if ($file->IsFile() && $file != ". 1) != ". die mit einem Punkt beginnen.php: <?php header(’Content-Type: text/cache-manifest’).png . die Seite selbst in einem Browser zu laden (achten Sie darauf.png . sind im Mac OS X Finder oder einem LinuxDateimanager standardmäßig unsichtbar (aber über die Kommandozeile können Sie mit ihnen arbeiten). Wenn Sie einige Verzeichnisse mit dem Namen .css .png ./themes/apple/theme. ebenso die Verzeichnisse demos und extensions.png .png .png .png . dass der Client die App nur neu herunterlädt./themes/apple/img/whiteButton.")./themes/jqt/img/on_off.png . Sie haben Ihr Arbeitsverzeichnis unter SVN-Versionskontrolle gestellt – dann sind diese Dateien und Verzeichnisse wichtig). README./themes/jqt/img/toolbar.png . $hashes = ""./themes/jqt/img/button_clicked.

/jqtouch/jqtouch.js . die den Offline Application Cache nutzen.png . So könnte das Manifest aussehen./jqtouch/jqtouch. Aber wenn sich eine der Dateien ändert.3 ?> 1 Diese Zeile initialisiert einen String. die App neu herunterzuladen. ändert sich auch diese Zeile.png . Sie ist ein Kommentar.css .. auch zu einer Änderung der Manifest-Datei führt. Das bedeutet. md5($hashes) ./index. dass jede Änderung. kann eine recht komplizierte Angelegenheit sein. 3 Dieser Code nimmt den String mit allen MD5-Hashes (die Verkettung der 32-ZeichenStrings für alle Dateien) und berechnet einen MD5-Hash für diesen String selbst. ob Ihre Dateien heruntergeladen wurden oder ob Sie entfernte oder lokale Ressourcen vor sich haben. dass sich das gesamte Manifest geändert hat. Jede noch so kleine Änderung an der Datei führt dazu. wenn der Anwender sie das nächste Mal startet.2 } } echo "# Hash: " . die mit dem Kommentarzeichen # beginnt). Ein MD5-Hash ist ein String mit 32 Zeichen wie 4ac3c9c004cac7785fa6b132b4f18efc. Sie werden sich immer wieder fragen. nicht wahr? Debugging Das Debugging von Apps. den der Browser ignoriert.html . Außerdem ist das Wechseln zwischen Debugging | 107 . was geschieht./themes/jqt/img/toolbar. dass ein neuer Hash-String in das Manifest geschrieben wird./themes/jqt/theme. .{ echo $file .css # Hash: ddaf5ebda18991c4a9da16c10f4e474a Die Konsequenz der ganzen Sache ist. dass sich das Ergebnis der Funktion md5_file ändert. "\n"./themes/jqt/img/whiteButton. die ihrerseits den Browser veranlasst. und das heißt. weil das. $hashes ..Für den Client-Browser hat diese Zeile keine Bedeutung. der MD5-Hashes für die Dateien enthält. der als Kommentar ausgegeben wird (eine Zeile. Das gibt uns einen kurzen String (er ist 32 Zeichen lang statt 32 Zeichen mal die Anzahl der Dateien). wenn sich nur ein einziges Zeichen in einer der Dateien im gesamten Verzeichnisbaum ändert. nachdem wir diese Änderung vorgenommen haben (einige Zeilen haben wir der Kürze halber weggelassen): CACHE MANIFEST . Ziemlich raffiniert. im Verborgenen passiert.= md5_file($file). die wir an einer der KiloDateien vornehmen. 2 Diese Zeile berechnet mit PHPs md5_file-Funktion (Message-Digest-Algorithmus 5) einen MD5-Hash für jede Datei und hängt ihn an das Ende des Strings $hashes an. "\n".

108 | Kapitel 6: Offline gehen . cache. false). Wenn Sie sehen wollen. können Sie seine Log-Dateien überwachen.addEventListener(’updateready’. logEvent. um die Betrachtung des Logs zu beenden. cache. wenn Sie in JavaScript eine Protokollierung auf der Konsole einrichten.addEventListener(’cached’. logEvent.applicationCache. cache. cacheStatusValues[2] = ’checking’.addEventListener(’checking’. logEvent. indem Sie Ihren Web-Apps während der Entwicklung folgendes JavaScript hinzufügen. drücken Sie Control-C.addEventListener(’noupdate’.addEventListener(’obsolete’. false). cacheStatusValues[0] = ’uncached’.addEventListener(’error’. logEvent. logEvent.addEventListener(’progress’. die Informationen wie den Zugriffszeitpunkt für eine Datei und den Dateinamen liefern. // Listener fur alle moglichen Events 2 ¨ ¨ var cache = window. Die JavaScript-Konsole Sie können sich das Leben erleichtern. unter Ubuntu Linux ist der Dateiname access. Es wird Ihnen helfen. cache. false). falls die Sache nicht wunschgemäß verläuft. und auf dem Mac lautet er access_log. wirklich zu verstehen. false). Sie können etwas leichter einsehen.oder Linux-Rechner ausführen. logEvent. cache. was hier geschieht.und Offline-Modus nicht unbedingt eine zeitsparende Sache und kann den Entwicklung/Test/Debugging-Zyklus erheblich ausbremsen. was aus Perspektive der Webservers geschieht. cache. cache. cacheStatusValues[5] = ’obsolete’. cache. false).Online. false). false). logEvent. Das folgende Skript sendet Meldungen an die Konsole und sorgt dafür. cacheStatusValues[1] = ’idle’. Wenn Sie eine andere Linux-Version oder Windows nutzen. was das Problem ist. Wenn Sie damit fertig sind.addEventListener(’downloading’. cacheStatusValues[3] = ’downloading’. cacheStatusValues[4] = ’updateready’. den Sie nicht eingeben dürfen): $ cd /var/log/apache2/ $ tail -f access?log Das zeigt die Log-Einträge des Webservers an.log. können Sie ein Kommandozeilenfenster öffnen (siehe »Die Kommandozeile nutzen« auf Seite 114) und die folgenden Befehle ausführen (das $ ist der Shell-Prompt. logEvent. kann die Datei einen anderen Namen haben und sich an einem anderen Platz befinden. Das ? auf der zweiten Zeile findet jedes Zeichen. Wenn Sie einen Webserver auf einem Mac. dass Sie die Seite im Browserfenster nicht permanent aktualisieren müssen: // Hilfs-Array fur Statuswerte 1 ¨ var cacheStatusValues = []. false).

update()}.log(message).// Alle Events auf der Konsole protokollieren function logEvent(e) {3 var online. false ). message = ’online: ’ + online. Debugging | 109 .onLine) ? ’yes’ : ’no’. um eine aussagekräftige Log-Meldung zu generieren.js"></script>. Diese Beschreibung schließen wir ein.status].applicationCache.B. status = cacheStatusValues[cache. message+= ’. console. } console. }. die von der Spezifikation definiert werden. werden spätere Aktualisierungen fehlschlagen. und dieser Code bildet die entsprechenden ganzzahligen Werte auf eine kurze Beschreibung ab (z.4 } // Die frisch heruntergeladenen Dateien einbinden. status. function(){ window. ¨ // Das Manifest alle 10 Sekunden auf Anderungen prufen ¨ setInterval(function(){cache. Von der HTML5-Spezifikation werden fünf mögliche Werte definiert. Syntaxfehler hat man sehr schnell ins Manifest eingeführt. aber eigentlich passiert hier gar nicht so viel: 1 Die ersten sieben Zeilen richten ein Array mit Statuswerten für das Application Cache-Objekt ein. Das scheint eine ganze Menge Code zu sein. Wenn Sie eine Datei umbenennen oder entfernen und vergessen. if (type == ’error’ && navigator. heißt der Status 3 »downloading«). wenn die Aktualisierung abgeschlossen ist window. Sie können das in einer . Ist der Event-Typ error und ist der Anwender online. type = e.js speichern.applicationCache.swapCache().B. z.type.addEventListener( ’updateready’. event: ’ + type.js-Datei namens debug. 2 Der nächste Codeteil richtet Event-Listener für alle Events ein. 3 Die Funktion logEvent erwartet als Eingabe das Event und führt einige einfache Berechnungen durch. Jeder ruft die Funktion logEvent auf.onLine) { message+= ’ (wahrscheinlich ein Syntaxfehler im Manifest)’. online = (navigator.log(’swap cache has been called’). status: ’ + status. die Sie dann über das src-Attribut des script in Ihr HTML-Dokument einbinden. gibt es wahrscheinlich einen Syntaxfehler im entfernten Manifest. so: <script type="text/javascript" src="debug. 10000). damit wir die Log-Einträge in der Funktion logEvent aussagekräftiger machen können. weil alle Pfade gültig sein müssen. type. message. message+= ’. das Manifest zu aktualisieren.

Sie können mit dem Manifest herumspielen (z. sehen Sie alle 10 Sekunden neue Meldungen erscheinen (siehe Abbildung 6-7). dass Sie sich damit so lange vertraut machen. es in ein anderes Verzeichnis verschieben) und beobachten. wie Sie Ihren Anwendern auch dann noch Zugriff auf Ihre App gewähren. Nachdem wir 110 | Kapitel 6: Offline gehen . seinen Inhalt änderen und speichern. bis Sie den Eindruck haben. Dann scheitert auch eine dynamische Manifestdatei. wenn sie keine Verbindung zum Internet haben.log() Debbuging-Meldungen an die JavaScript-Konsole senden Was Sie gelernt haben In diesem Kapitel haben Sie gelernt. seinen Namen ändern.B. was passiert. und frischen Sie die Seite in Ihrem Browser zweimal auf. ändern Sie den Inhalt einer der Dateien (oder den Namen einer Datei).svn-Unterverzeichnis). Aber Sie müssen darauf achten. die der Server nicht ausliefern kann. indem Sie DARSTELLUNG→ENTWICKwählen und auf CONSOLE klicken. weil Dateiberechtigungen das verhindern. wie die Konsequenzen Ihrer Handlungen wie durch Zauberhand in der Konsole sichtbar werden. 4 Diese Zeile sendet die aufgebaute Meldung an die Konsole. Abbildung 6-7: Mit console.Dynamische Manifestdateien helfen bei der Vermeidung von Syntaxfehlern. da die entsprechende Datei unlesbar ist. wenn diese nicht automatisch ausgewählt ist. dass Sie wirklich wissen. LER→JAVASCRIPT-Konsole In Chrome können Sie Konsolenmeldungen einsehen. Wenn Sie die Webseite in Ihrem Browser laden und die Konsole öffnen. Ich kann Ihnen nur empfehlen. dass Sie keine Dateien einschließen (wie die in einem . Sollten Sie nichts sehen.

fast nicht zu unterscheiden sind. die von nativen Apps. die vom Android Market heruntergeladen wurden. immer noch stark eingeschränkt. Im folgenden Kapitel werde ich diese Dinge mit Unterstützung eines Open Source-Projekts namens PhoneGap angehen. die Kamera. Offline-Apps zu erstellen. die Vibration oder den Beschleunigungssensor des Geräts zugreifen. die für alle Web-Apps gelten.unserem Werkzeugkasten diese Fertigkeit hinzugefügt haben. Natürlich bleibt eine reine Web-App wie diese durch die Sicherheitsbeschränkungen. sind wir in der Lage. Beispielsweise kann eine Web-App nicht auf das Adressbuch. Was Sie gelernt haben | 111 .

.

die Sie in den App-Stores der jeweiligen Plattformen einreichen können. Im Detail heißt das. 10 und mehr verschiedene Browserversionen über 10 und mehr verschiedene Betriebssystemversionen testen zu müssen. Ihrer Web-App mit etwas JavaScript Zugriff auf die Kamera eines iPhones. Aktuell werden iPhone. um für alle möglichen Kombinationen zu entwickeln und zu testen. eines Palm Pre und anderer Geräte zu bieten. an dem PhoneGap die Bühne betritt. in der jedes Projekt schlicht ein Chrome-freier Webbrowser mit erweiterten Berechtigungen ist. dass PhoneGap es Ihnen ermöglicht. wie das auf dem Markt für Mobilgeräte aussieht. das als vereinheitlichte Brücke zwischen Web-Apps und Mobilgeräten dient. Daten lokal auf dem Gerät speichern und im Offline-Modus operieren. Geolocation. Beschleunigungssensor. und Sie haben eine Vorstellung davon. Aber zwei Dinge kann sie immer noch nicht: Sie kann nicht auf Gerätefunktionen und -Hardware zugreifen (z. PhoneGap ist ein Open SourceEntwicklungswerkzeug von Nitobi (http://www. Das ist der Punkt. In diesem Kapitel werden Sie lernen. PhoneGap Die mobile Landschaft ist mit Geräten. CSS und JavaScript geschrieben haben. Sound und Vibration). und sie kann auch nicht auf dem Android Market eingereicht werden. in eine native App gehüllt.com/). Im Wesentlichen besteht es aus einer Vorlage für eine native App für die wichtigeren Plattformen. Multiplizieren Sie das mit 100. ist Ihnen die Qual nicht unbekannt.B. | 113 . eines Nexus One. obwohl Sie sie mit HTML. wie Sie mit Hilfe eines Open Source-Projekts namens PhoneGap die Reichweite Ihrer Web-App über die üblichen Grenzen des Browsers hinaus erweitern. Plattformen und Betriebssystemen übersät. BlackBerry. Wenn Sie Webentwickler sind. Android. Wir haben sie ansprechend für das Gerät formatiert und nativ wirkende Animationen eingerichtet. die native Apps beherrschen: Sie kann vom Homescreen gestartet werden.nitobi. Darüber hinaus wird die resultierende Anwendung. Es gibt schlicht kein kosteneffizientes Verfahren.KAPITEL 7 Native Apps Unsere Web-App kann mittlerweile viele Dinge tun. die dem Benutzer Rückmeldungen und Kontextinformationen liefern.

die einen ähnlichen Zweck erfüllen wie PhoneGap. Die Windows Phone 7-Unterstützung befindet sich in der Entwicklung. Die Kommandozeile kann auf den ersten Blick ziemlich geekhaft und kryptisch erscheinen.. Anders gesagt.appcelerator. Natürlich bieten unterschiedliche Geräte auch unterschiedliche Sätze von Funktionen. wie es hier erscheint. wenn Sie Copy-and-Paste vorziehen. das sich in einem Browser ausführen ließe). die Sie im Ordner /Programme/Dienstprogramme finden. überall den gleichen Code zu nutzen.Palm. um zu prüfen. verlangen. Palm und andere beliebte Geräte bereitzustellen. die ich mir angesehen habe. aber den Code der App müssen Sie nicht mehr anpassen. Die Kommandozeile nutzen In diesem Kapitel werden wir über die Kommandozeile mit PhoneGap und dem Android SDK arbeiten. dass Sie die Möglichkeit hätten. in der Sie Dinge tun können. bieten sie diese dem Entwickler wahrscheinlich auf jeweils unterschiedliche Weise an. Ich bin mit diesen Produkten nicht hinreichend vertraut. Sie müssen die App zwar noch manuell mit dem SDK (Software Development Kit) des jeweiligen Herstellers verteilen. Es gibt noch weitere Projekte und Produkte.com/ ). Unter Mac OS X ist das die Terminal-Anwendung. dass ich alles so einfach wie möglich halten und dabei so viel wie möglich erklären werde. weil man bei PhoneGap Standard-Web-Apps schreiben und diese dann fast unverändert in eine native Codeumgebung einfügen kann. Alle anderen Produkte. deswegen verspreche ich. Das eine Gerät hat vielleicht keine Kamera oder keinen Beschleunigungssensor. dass man Code auf Basis eines proprietären Frameworks schreibt. dass Sie alles genau so eingeben. Unter Linux öffnen Sie ein xterm oder Terminal. 114 | Kapitel 7: Native Apps . CSS und JavaScript. um Ihnen einen detailierten Vergleich bieten zu können. Ihre Anwendung ohne große Veränderungen für iPhone.h. Sie sollten eventuell also einen Blick auf sie werfen.com/) und Titanium Mobile (http://www. Während Sie die Beispiele durcharbeiten. die über die grafische Schnittstelle Ihres Betriebssystems wahrscheinlich nicht durchführbar sind.oreilly. Leerzeichen und Groß-/Kleinschreibung sind relevant. Und auch wenn Geräte die gleichen Eigenschaften bieten. Unter Windows ist es die Eingabeaufforderung (klicken Sie auf START. Da dies ein Android-Buch ist. aber ich ziehe PhoneGap vor. Sie können die Beispieldateien für dieses Kapitel auch von der O’Reilly-Seite zu diesem Buch (http://www. Nokia. wählen Sie ALLE PROGRAMME→ZUBEHÖR→EINGABEAUFFORDERUNG). Die Kommandozeile ist eine textbasierte Umgebung. Sie schreiben kein HTML. Symbian (Nokia) und Windows Mobile unterstützt. das nur nativen Code ausgibt (d. werde ich mich auf die Android-Version von PhoneGap konzentrieren. PhoneGap verallgemeinert die APIs der am verbreitetsten verfügbaren Funktionen mobiler Geräte und ermöglicht es Entwicklern damit. Sie sollten sich aber dessen bewusst sein. sollten Sie darauf achten. ob sie für Ihre Zwecke geeigneter sind als PhoneGap.de/catalog/9783897215733) herunterladen. beispielsweise RhoMobile (http://rhomobile.

Befolgen Sie die folgenden Schritte. Mein Entwicklungsrechner ist ein MacBook Pro. müssen wir also das Android SDK selbst herunterladen und installieren. Das 06 im SDK-Dateinamen bezieht sich auf die Version des Android SDK und kann bereits einen anderen Wert haben.com/sdk/index. Abbildung 7-1: Laden Sie das passende Android SDK für Ihren Entwicklungsrechner herunter.B. Das Android SDK herunterladen | 115 .sun. Gehen Sie zur Android SDK-Download-Seite (http://developer. Auf Mac OS X ist Java vorinstalliert. Wenn Sie unter Windows oder Linux arbeiten. Bevor wir mit PhoneGap loslegen können. müssen Sie die Umgebungsvariable JAVA_HOME setzen.html). Befolgen Sie dazu die Anweisungen in Abschnitt »Die Umgebung einrichten« auf Seite 119.android. Unter Linux ist es in der Regel über den jeweiligen Package-Manager verfügbar.0_21).com/javase/downloads). und laden Sie das passende Paket für Ihre Plattform herunter. Wenn Sie Java unter Windows installieren. Das passende Paket ist in meinem Fall also android-sdk_r06-mac_86.Das Android SDK herunterladen PhoneGap arbeitet mit dem Android SDK zusammen. in das Java installiert wurde (z. C:\Programmdateien\Java\jdk1.zip für Mac OS X (Intel) (siehe Abbildung 7-1). um dies zu tun: 1. wenn Sie dies lesen. aber verändern Sie nicht die Umgebungsvariable PATH. auf dem Mac OS X 10. sondern erstellen Sie eine neue Umgebungsvariable namens JAVA_HOME. müssen Sie erst Java installieren (siehe http://java. und setzen Sie sie auf das Verzeichnis.6.6 läuft.

in der linken Seitenleiste auf AVAILABLE PACKAGES. kreuzen Sie ACCEPT an. die Lizenzbedingungen zu akzeptieren. Starten Sie die Terminal-Anwendung. um den Download zu starten (siehe Abbildung 7-4). 8.2. um Android SDK and AVD Manager zu starten. sollten Sie deswegen ein Verzeichnis wie C:\Source nutzen. Klicken Sie in der rechten unteren Ecke des Fensters auf den Button INSTALL SELECTED. Auf dem Mac und unter Linux lautet der Befehl: . AND ARCHIVES sollte dann genau ein Element erscheinen (siehe Abbildung 7-2). Außerdem sollten Sie in den Pfadnamen Leerzeichen vermeiden. Im Bereich SITES. 3. Der Einfachheit halber werde ich das entpackte SDK-Verzeichnis in Android umbenennen. Es öffnet sich ein Fenster. das Sie auffordert. Unter Windows sähe der Befehl ungefähr so aus: cd %USERPROFILE%\Desktop\Android\tools 5. anstatt das Paket auf dem Desktop zu entpacken. da dieses sich unter Dokumente und Einstellungen befindet). 116 | Kapitel 7: Native Apps .google.com/android/repository/repository. und klicken Sie auf den Button INSTALLIEREN. Kreuzen Sie das Kästchen neben https://dl-ssl. und navigieren Sie in das tools-Unterverzeichnis des Android SDK-Verzeichnisses.html an./android Unter Windows lautet der Befehl: android 6. Ich werde meins auf den Desktop packen. können Sie dazu den folgenden Befehl nutzen: cd ~/Desktop/Android/tools/ Unter Linux sieht der Befehl identisch aus (wenn Sie das Verzeichnis Android in das Desktop-Unterverzeichnis Ihres Benutzerverzeichnisses gesteckt haben). Geben Sie den folgenden Befehl ein. 9. Entpacken Sie das heruntergeladene Archiv in einem beliebigen Verzeichnis. 7. 4. PACKAGES. Klicken Sie. um alle verfügbaren Pakete und Archive zu installieren (siehe Abbildung 7-3). Wenn Sie Windows XP nutzen (das mindestens zwei Leerzeichen im Pfad zu Ihrem Benutzerverzeichnis enthält. Lesen Sie diese. Unter Windows können Sie das ~-Kürzel für das Benutzerverzeichnis nicht verwenden. wenn das ANDROID SDK AND AVD MANAGER-Fenster geladen ist. Wenn Sie das Android-Verzeichnis auf Ihrem Desktop entpackt und umbenannt haben.

Abbildung 7-2: Mit dem »Android SDK and AVD Manager« laden Sie die SDK-Pakete für bestimmte Versionen des Android OS herunter.google. Abbildung 7-3: Wählen Sie »https://dl-ssl.com/android/repository/repository. und installieren Sie es mit »Install Selected«. Das Android SDK herunterladen | 117 .html« aus.

1.com/ jonathanstark/phonegap-android). 10. sollen Sie die Hauptseite des PhoneGap-Projekts (http://phonegap. PhoneGap herunterladen Nachdem wir das Android SDK installiert haben. und klicken Sie dann auf »Install«. und klicken Sie auf den DOWNLOAD SOURCE-Button oben rechts unter dem Suchfeld (siehe Abbildung 7-5). nachdem der Download abgeschlossen ist. und ich werde versuchen. sie recht konstant und stabil zu halten. 11. Schließen Sie unter Windows oder Linux einfach das Fenster. Sind Sie mit meiner Version von PhoneGap für die Entwicklung für Android hinreichend vertraut. um das Fenster zu schließen. 118 | Kapitel 7: Native Apps .Abbildung 7-4: Lesen und akzeptieren Sie die Plattformbeschreibung und -lizenz. können wir mit PhoneGap ein AndroidProjekt auf Grundlage unserer Web-App erstellen. habe ich eine eigene Version des PhoneGap-Android-Projekts erstellt. Wählen Sie auf Mac OS X QUIT ANDROID im ANDROID-MENÜ. Um sicherzustellen. ob es etwas aufregendes Neues gibt. dass die Anweisungen in diesem Buch über einen längeren Zeitraum funktionieren. das Sie eventuell in Ihre Apps einbauen wollen. Klicken Sie auf CLOSE. Gehen Sie zur Android PhoneGap-Downloadseite auf GitHub (http://github. um die Android-App zu verlassen.com) besuchen und schauen.

müssen Android SDK und PhoneGap einander finden können. Wenn Sie aufgefordert werden. Ihr Computer nutzt Umgebungsvariablen zur Speicherung gewisser Informationen.zip-Symbol. 2. Ich packe meines auf den Desktop und benenne das entpackte SDK-Verzeichnis der Kürze halber in »PhoneGap« um. Das ist eine Liste mit Verzeichnissen. Wenn Sie auf der Kommandozeile einen Befehl (wie grep oder findstr) eingeben. Um das zu vereinfachen. Die Umgebung einrichten | 119 . die von den Programmen genutzt werden. Die Umgebung einrichten Damit sie zusammenarbeiten können. müssen Sie Ihre PATH-Umgebungsvariable anpassen.Abbildung 7-5: Meine PhoneGap Android-Seite sichert die Zukunftsfähigkeit der Beispiele in diesem Buch. ein Archivformat zu wählen. Das Download-Bild bleibt auch nach Abschluss des Downloads geöffnet. die Sie ausführen. die Programmen sagt. klicken Sie auf das große . wo Sie nach anderen Programmen suchen müssen. sucht Ihr Computer in allen Verzeichnissen in Ihrem PATH nach dem Befehl. 3. Entpacken Sie das heruntergeladene Archiv in ein beliebiges Verzeichnis. Eine davon ist PATH.

und starten Sie sie dann neu. C:\Windows\ System32. EIGENSCHAFTEN wählen und dann zum Tab ERWEITERT gehen.bash_profile durch . Das können Sie tun. bearbeiten Sie diese. dass Sie noch nichts verändern (sollten Sie einen Fehler machen. Diese ist versteckt. öffnen Sie die Systemeigenschaften. können Sie jederzeit auf ABBRECHEN klicken und neu beginnen). Jetzt sollten Sie auf der Kommandozeile Befehle wie adb oder android ausführen können.B. Achten Sie darauf.com/sdk/installing. und schließen Sie die verbleibenden Dialogfenster. an dem Sie PhoneGap installiert haben.bash_profile Existiert diese Datei.bash_profile-Datei finden. Scrollen Sie unter SYSTEMVARIABLEN nach unten. C:\Users\Benutzername\ Desktop\ Android) und C:\PhoneGap durch den Ort.C:\Android\tools. Auf Mac OS X oder unter Linux sollten Sie in Ihrem Benutzerverzeichnis eine .profile): nano ~/.Unter Windows werden die Elemente im PATH durch ein Semikolon. und hängen Sie Folgendes an den vorhandenen Text an (ohne Leerzeichen vor dem Semikolon): .html#Installing. Auf dem Mac und unter Linux werden sie durch einen Doppelpunkt getrennt. bearbeiten Sie stattdessen jene Datei (ersetzen Sie einfach .B.profile-Datei (prüfen Sie das mit ls -l ~/. Probieren Sie also. werfen Sie einen Blick in http://developer. 120 | Kapitel 7: Native Apps . Klicken Sie auf OK. auf der Kommandozeile den folgenden Befehl auszuführen: ls -l ~/. und hängen Sie dort die folgende Zeile an: PATH=$PATH:~/Android/tools:~/PhoneGap/bin Ersetzen Sie ~/Android durch den Ort des Android SDKs (wie ~/Desktop/Android/tools) und ~/PhoneGap durch den Ort von PhoneGap. indem Sie mit links auf START klicken und unter Windows XP mit rechts auf ARBEITSPLATZ klicken.android. indem Sie Control-O und dann Enter drücken.C:\Windows getrennt. und schauen Sie sich Anleitungen dort an.C:\PhoneGap\bin Ersetzen Sie C:\Android durch den Ort des Android SDKs (z. aber eine . indem Sie wie unten zu sehen den nano-Editor ausführen. Falls nicht. /usr/bin:/usr/local/bin. z.bash_profile Scrollen Sie mit den Pfeiltasten in der Datei nach unten. Um unter Windows PATH ein Verzeichnis hinzuzufügen. Klicken Sie dann im erscheinenden Dialog auf UMGEBUNGSVARIABLEN. Gehen Sie mit dem Cursor ganz nach rechts. um nano zu verlassen. Drücken Sie Control-X. Schließen Sie alle offenen Eingabeaufforderungsfenster oder Terminals. bis Sie PATH sehen.profile). Gibt es diese Datei nicht. und klicken Sie doppelt darauf. Speichern Sie die Datei.B. unter Vista oder Windows 7 klicken Sie rechts auf COMPUTER und wählen EIGENSCHAFTEN und dann den Link ERWEITERTE SYSTEMEINSTELLUNGEN auf der linken Seite. z.

WQVGA432. müssen Sie eventuell erneut Ihre PATH-Variable bearbeiten. WVGA800. Ein virtuelles Android-Gerät erstellen | 121 . WQVGA400. QVGA-L. um eine Aufstellung der verfügbaren Ziele einzusehen: android list targets Ich habe alle SDK-Plattformen heruntergeladen.6 Type: Platform API level: 4 Revision: 3 Skins: HVGA (default). WVGA800. WVGA854 Beachten Sie den in der Ausgabe für Android 2. WVGA800. Geben Sie Folgendes ein. der es uns ermöglicht. HVGA-L. Denken Sie daran.5 Type: Platform API level: 3 Revision: 4 Skins: HVGA (default). QVGA.2 Type: Platform API level: 8 Revision: 1 Skins: HVGA (default). WVGA854 id: 4 or "android-8" Name: Android 2. wie beim letzten Mal dem Pfadeintrag ein Semikolon voranzustellen. WQVGA400. Wenn Sie es unter Windows installieren (siehe http://www. um ihr den Pfad zu Rubys bin-Verzeichnis (z.1 aufgeführten ID-String (android-7). QVGA.B. C:\Ruby191\bin) hinzuzufügen. WVGA854 id: 3 or "android-7" Name: Android 2.Das Hilfsprogramm im Verzeichnis PhoneGap/bin erfordert. QVGA-P id: 2 or "android-4" Name: Android 1. müssen wir einen Geräteemulator erstellen.1-update1 Type: Platform API level: 7 Revision: 2 Skins: HVGA (default). Auf Mac. 1. HVGA-P. unseren Code in einer simulierten Umgebung zu testen.oder Linux-Systemen sollte es standardmäßig installiert sein. WQVGA432. dass auf Ihrem Rechner Ruby installiert ist. Dieses SDK entspricht der aktuell am weitesten verbreiteten Version. QVGA.ruby-lang. Ein virtuelles Android-Gerät erstellen Nachdem wir das Android SDK und PhoneGap installiert (und unsere PATH-Variable aktualisiert) haben. Auf meinem Rechner zeigt dieser Befehl also vier Optionen an: jsc-mbp:~ jstark$ android list targets Available Android targets: id: 1 or "android-3" Name: Android 1.org/en/downloads/).

um Ihr AVD (Android Virtual Device) zu erzeugen: android create avd -n mySim -t android-7 Hier sagen wir Android. geben Sie einfach no ein und drücken Enter. dass es ein virtuelles Gerät (avd) mit dem Namen (-n) »mySim« erstellen soll. um den Emulator zu starten: emulator -avd mySim Hier nutzen wir den Befehl emulator. 3. als Sie das AVD im letzten Schritt erstellten. Geben Sie den folgenden Befehl ein. das die Plattform (-t) android-7 emuliert. Geben Sie folgenden Befehl ein. das wir gerade erstellt haben. Abbildung 7-6: Mit dem »Android Virtual Device« (AVD) können Sie Ihre App ohne echtes Gerät testen und debuggen. 122 | Kapitel 7: Native Apps . Warten Sie. ob Sie benutzerdefinierte Optionen konfigurieren wollen. Der erste Start kann ein oder zwei Minuten dauern. Auf den Schalter -avd folgt der Name. ist der Emulator installiert. Der Prozess sollte nur ein paar Sekunden in Anspruch nehmen. um das Android Virtual Device zu starten. üben Sie sich also in Geduld. bis der Emulator initialisiert ist und den Homescreen der Geräts anzeigt (siehe Abbildung 7-6). den Sie gewählt haben.2. Ist er abgeschlossen. Wenn Sie gefragt werden.

Das Programm ist wirklich umwerfend. KiloGap erstellen | 123 . um den Assistenten in Gang zu setzen: droidgap wiz Der Assistent wird von Ihnen einige Informationen einfordern. Sie müssen Ant installieren. angepasstes Android-Projekt. Abbildung 7-7: Der »droidgap«-Assistent stellt einige Fragen und erstellt ein auf Ihren Antworten basierendes. schauen Sie unter http://ant. Das Android SDK benötigt Apache Ant. Das ist der Name. und geben Sie den folgenden Befehl ein. die bei der Erstellung des PhoneGap-Projekts erforderlich sind (siehe Abbildung 7-7). der dem Benutzer an mehreren Orten auf seinem Gerät angezeigt wird (z. das unter Mac OS X und vielen Linux-Versionen vorinstalliert ist. einen Namen für Ihre App ein. unter dem Homescreen-Symbol für Ihre App und in der Liste von Apps).apache.KiloGap erstellen Als Nächstes werden wir unsere Web-App in eine native Android-App umwandeln. 1. müssen Sie einige Fragen beantworten und an den verschiedensten Stellen einer Vorlage Ihre Antworten platzieren. bevor Sie droidgap ausführen können. Wenn Sie droidgap ausführen. wenn Sie dazu aufgefordert werden. Ich gebe »Kilo« ein.html nach. Die Jungs bei Nitobi haben eine nützliche kleine Hilfsanwendung namens droidgap erstellt. 2.org/manual/install. Wenn Sie Windows nutzen. sollten Sie ihm ein Bier spendieren.B. sollte Ihnen je jemand von Nitobi über den Weg laufen. um Ihr Projekt zu erstellen. die uns dabei unterstützt. Geben Sie. Starten Sie die Terminal-Anwendung.

Sie sollten Ihren eigenen Domainnamen nutzen. Geben Sie. wenn Sie dazu aufgefordert werden. 4. CSS. Gibt es unter dem von Ihnen angegebenen Pfad ein Verzeichnis. Geben Sie. Meine Dateien befinden sich in einem Verzeichnis namens www auf meinem Desktop (siehe Abbildung 7-8). und gebe deswegen Folgendes ein: ~/Desktop/KiloGap 124 | Kapitel 7: Native Apps . Ich werde com.und JavaScript-Dateien für Ihre Web-App enthält. meldet droidgap einen Fehler und bittet um einen anderen Pfad. Üblicherweise nutzt man dazu die Reverse Domain Name-Syntax (den umgekehrten Domainnamen).3. Ich möchte. Der Package-Name dient als eindeutiger Bezeichner für Ihre App. ich gebe also Folgendes ein: ~/Desktop/www Abbildung 7-8: Meine HTML-.kilo eingeben. dass droidgap mein PhoneGap-Projekt auf meinem Desktop in einem Verzeichnis namens KiloGap ablegt. wenn Sie dazu aufgefordert werden. einen Verzeichnispfad für Ihr Projekt an. 5. einen Package-Namen für Ihre App an.jonathanstark. CSS. dem Pfad zum dem Verzeichnis auf Ihrem Rechner ein. Das Verzeichnis darf noch nicht bestehen – droidgap erstellt es für Sie. Geben Sie. wenn Sie dazu aufgefordert werden. das die HTML-.und JavaScript-Dateien liegen im »www«-Ordner auf meinem Desktop.

6. Geben Sie, wenn Sie dazu aufgefordert werden, die anvisierte Android SDK-Plattform an. Wenn Sie die Anweisungen oben befolgt und alle Android SDK-Plattformen installiert haben, ist die ID Ihrer Zielplattform android-7. Wenn Sie eine andere Plattform anvisieren wollen, können Sie sich erneut die Liste der verfügbaren Plattformen anzeigen lassen, indem Sie die Plattform-ID leer lassen und Enter drücken. In der ersten Zeile für die Einträge der erscheinenden Liste wird die ID in Zahl- und Textform angezeigt (d.h. id: 2 or "android-4"). Geben Sie die Textform der ID ohne Anführungszeichen ein (d.h. android-4), wenn Sie wieder auf der droidgap-Eingabeaufforderung sind. Nachdem Sie die ID der Zielplattform eingegeben haben, erstellt droidgap Ihr Projekt und steckt die Dateien in das von Ihnen angegebene Ausgabeverzeichnis. Dieser Vorgang sollte nur ein paar Sekunden dauern (siehe Abbildung 7-9).

Abbildung 7-9: »droidgap« erstellt das Projekt und steckt die Dateien in das angegebene Ausgabeverzeichnis.

Wenn Sie zum Verzeichnis ~/Desktop/KiloGap/assets/www/ gehen, sehen Sie, dass droidgap dort neben den anderen Dateien Ihrer Anwendung eine Datei namens phonegap.js abgelegt hat. Das ist die Datei, die PhoneGap nutzt, um verschiedene native Gerätfunktionen über JavaScript bereitzustellen. Wenn Sie phonegap.js nutzen wollen, müssen Sie die Datei in den head-Abschnitt Ihrer index.html-Datei einbinden:
KiloGap erstellen | 125

... <head> <title>Kilo</title> <link type="text/css" rel="stylesheet" media="screen" href="jqtouch/jqtouch.css"/> <link type="text/css" rel="stylesheet" media="screen" href="themes/jqt/theme.css"/> <link type="text/css" rel="stylesheet" media="screen" href="kilo.css"/> <script type="text/javascript" src="phonegap.js" charset="utf-8"></script> <script type="text/javascript" src="jqtouch/jquery.js" charset="utf-8"></script> <script type="text/javascript" src="jqtouch/jqtouch.js" charset="utf-8"></script> <script type="text/javascript" src="kilo.js" charset="utf-8"></script> </head> ...

KiloGap im Emulator installieren
Jetzt wird es Zeit, die nagelneue native Android-App im Emulator zu testen. 1. Wenn Ihr Emulator nicht läuft, starten Sie ihn, indem Sie im Terminal den folgenden Befehl eingeben (so kann er sich »warmlaufen« während Sie das Kilo-Package kompilieren):
emulator -avd mySim

Nach ein paar Sekunden sollte das Android-Emulator-Fenster erscheinen. Beachten Sie, dass der Cursor nicht in das Terminal-Fenster zurückkehrt – er sitzt dort und hängt, bis Sie den Emulator schließen. Wir werden mit diesem Fenster nicht mehr arbeiten, Sie können es also minimieren, um es aus dem Weg zu schaffen. 2. Öffnen Sie ein neues Terminal-Fenster, und gehen Sie ins KiloGap-Verzeichnis. In meinem Fall sieht der Befehl dazu so aus:
cd ~/Desktop/KiloGap

3. Geben Sie den folgenden Befehl ein, um Ihre App mit Debugging-Unterstützung zu kompilieren:
ant debug

Wenn alles funktioniert, sollten Sie einen Strom von Ausgaben sehen, der mit BUILD SUCCESSFUL endet (siehe Abbildung 7-10). Es sollte sich dann eine ausführbare Programmdatei namens Kilo-debug.apk im Verzeichnis ~/Desktop/KiloGap/bin befinden (siehe Abbildung 7-11). Ist der Kompilationsvorgang nicht erforderlich, sollten Sie die Schritte in Abschnitt »KiloGap erstellen« auf Seite 123 wiederholen.

126

|

Kapitel 7: Native Apps

Abbildung 7-10: Ist »ant debug« erfolgreich, sehen Sie am Ende der Ausgabe »BUILD SUCCESSFUL«.

Abbildung 7-11: »ant debug« erstellt die App »Kilo-debug.apk« im »bin«-Verzeichnis unter »KiloGap«.

KiloGap im Emulator installieren

|

127

~/Desktop/KiloGap/bin/Kilo-debug. das Teil des Android SDKs ist. den es findet. damit wir sie testen können. Geben Sie dazu den folgenden Befehl ein (wenn Sie einen anderen Ort verwendet haben. das Sie droidgap oben in Schritt erstellen ließen): adb -e install -r ~/Desktop/KiloGap/bin/Kilo-debug.h. Beispielsweise gibt es unten im Fenster eine ungefähr 40 px breite Lücke (siehe Abbildung 7-13). Abbildung 7-12: Ihre App ist jetzt wie eine gewöhnliche App im Emulator verfügbar.apk »adb« ist die Abkürzung für Android Debug Bridge.apk) auf dem ersten laufenden Emulator installieren soll. Wenn wir die Programmdatei haben. um die App zu starten. ein Werkzeug. dass es unser Binärpaket (d. Der Schalter -e sagt adb. das wir zu Anfang dieses Kapitels erstellt haben. 128 | Kapitel 7: Native Apps . Sie werden sofort sehen. dass es ein eventuell bereits auf dem Emulator vorhandenes Binärpaket ersetzen soll. können wir sie auf dem Emulator installieren. Der Schalter -r sagt adb. ersetzen Sie ~/Desktop/KiloGap/bin/ durch den Ort des bin-Unterverzeichnisses des Verzeichnisses. und probieren Sie es erneut. falls er gesperrt sein sollte (schieben Sie dazu unter Android 2. gehen Sie zum Emulator und entsperren ihn. dass noch einige Aufräumarbeiten anstehen. Wenn Sie die Fehlermeldung »device offline« erhalten.2 beispielsweise das grüne Schloss nach rechts). und klicken Sie darauf.4. Jetzt ist Ihre App wie jede andere App auf dem Emulator verfügbar (siehe Abbildung 7-12). Suchen Sie im App-Launcher nach Kilo.

dass die App nicht mehr in einem gewöhnlichen Browserfenster läuft und deswegen Platz für die Werkzeugleiste des Browsers lässt. Läuft der Code in PhoneGap.js. wird diese Bedingung mit true ausgewertet. weil jQTouch nicht erkennt.css({minHeight: window. um zu prüfen. Hängen Sie ans Ende die Direktive !important an.innerHeight + ’px !important’}).Abbildung 7-13: Ihre Web-App läuft jetzt als native App auf dem Android-Emulator. ist das PhoneGap-Objekt undefiniert. Wird die App mit PhoneGap gestartet. erhalten die unmittelbaren Kinder des HTMLbody-Elements eine minimale Höhe. Die Bedingung wird folglich mit false ausgewertet. um gegensätzliche Anweisungen an anderer Stelle der Stylesheets zu überschreiben. die der Höhe des Inhaltsbereichs entspricht (455 px im Emulator. und fügen Sie der Document-Ready-Funktion Folgendes hinzu: if (typeof(PhoneGap) != ’undefined’) { $(’body > *’). KiloGap im Emulator installieren | 129 . Öffnen Sie einfach ~/Desktop/KiloGap/assets/www/kilo. Wird der Code als Web-App gestartet. ob das PhoneGap-Objekt definiert ist. Jetzt füllt die App das Fenster beim Start (siehe Abbildung 7-14) vollständig auf. Die vollständige Höhe des Bildschirms nutzen Die Lücke taucht auf. } Dieser Code nutzt den typeof-Operator. Glücklicherweise lässt sich das ganz leicht reparieren. damit diese Regel in jedem Fall angewandt wird. 508 px auf dem Nexus One).

Abbildung 7-14: Die Höhe des Bodys wurde von 420 px in 455 px geändert. drawable-ldpi und drawable-mdpi. mdpi für Bildschirme mit 140 bis 180 dpi und hdpi für Bildschirme mit 190 bis 250 dpi. müssen wir unser eigenes Bild an einem bestimmten Ort im KiloGapProjektverzeichnis ablegen – genau genommen an drei Orten. Die Feinabstimmung Ihres Homescreen-Symbols für die unterschiedlichen Android-Geräte ist eine Sache. die den Horizont dieses Buchs übersteigt. Gehen Sie mit dem Dateimanager Ihres Systems zu ~/Desktop/KiloGap/res. Für die Beispiele hier nutze ich einen glasierten Schoko-Donut auf pinkem Hintergrund. 130 | Kapitel 7: Native Apps . wurden drei Ordner für unterschiedliche Versionen Ihres Anwendungssymbols mit unterschiedlicher Auflösung gespeichert. dass es auf den unterschiedlichen Geräten angemessen dargestellt wird. sehen Sie drei Ordner. Wenn wir das Aussehen des Symbols anpassen wollen. Mehr Informationen zu Launcher-Symbolen finden Sie im Abschnitt »Dem Home-Screen ein Symbol hinzufügen« auf Seite 53. Da Android eine Vielzahl von Geräten mit unterschiedlichen Bildschirmeigenschaften unterstützt. Das App-Symbol anpassen Bislang wird unsere App im Emulator mit dem Standard-PhoneGap-Symbol dargestellt (ein blaues Quadrat mit einer Leiter darauf). deren Namen mit dem Präfix drawable beginnen: drawable-hdpi. kümmert sich Android sehr erfolgreich darum.png-Bild ersetzen. ldpi dient für Bildschirme mit 100 bis 140 dpi. und die App nimmt jetzt den gesamten Bildschirm ein.png durch ein 56 Pixel im Quadrat großes . Aber machen Sie sich keine Sorgen: Wenn Sie das Standard-PhoneGap-Symbol icon.

und wechseln Sie in das KiloGap-Verzeichnis. Aktivieren Sie auf Ihrem Gerät das Debugging. Die Anweisungen dafür ähneln denen für die Installation im Emulator: 1. Verbinden Sie Ihr Gerät mit einem USB-Port Ihres Rechners. Abbildung 7-15: DSie können das Launcher-Symbol der App anpassen.apk Wenn der Vorgang abgeschlossen ist. 3. In meinem Fall ist der Befehl dazu: cd ~/Desktop/KiloGap KiloGap auf Ihrem Gerät installieren | 131 . können Sie Kilo darauf installieren. sollten Sie das neue Symbol im Launcher des Geräts sehen (siehe Abbildung 7-15).Geben Sie im Terminal die folgenden Befehle ein. indem Sie eine ».png«-Datei in den drei »drawable«-Verzeichnissen des Android-Projekts speichern. indem Sie zu EINSTELLUNGEN→ ANWENDUNGEN→ENTWICKLUNG navigieren und die Option USB DEBUGGING aktivieren. nachdem Sie die Standardsymbole ersetzt haben. KiloGap auf Ihrem Gerät installieren Wenn Sie ein richtiges Android-Gerät zur Verfügung haben. Öffnen Sie ein Konsolenfenster. um die App neu zu kompilieren und zu installieren: cd ~/Desktop/KiloGap ant debug adb -d install -r bin/Kilo-debug. 2.

executeSql(3 132 | Kapitel 7: Native Apps . die wir auf dem Gerät installieren können.apk. db. var dailyBudget = localStorage. die von der Meldung BUILD SUCCESSFUL abgeschlossen werden.vibrate().currentDate. Im Verzeichnis ~/Desktop/KiloGap/bin befindet sich dann die ausführbare Programmdatei Kilo-debug. unsere Anwendung um Aufrufe nativer Gerätefunktionen zu bereichern. wie sie funktioniert. das gefunden wird. wenn der Anwender einen Eintrag einfügt. vibrate. indem Sie in einem Konsolenfenster folgenden Befehl eingeben. sollten Sie eine Menge Ausgaben sehen. um ein Handy zum Vibrieren zu bringen: navigator. dass das Binärpaket (d. Geben Sie dazu den folgenden Befehl ein: adb -d install -r bin/Kilo-debug. In diesem werden wir die App dazu bringen. dass sie piept. bin/Kilo-debug. müssen Sie die Schritte in Abschnitt »KiloGap erstellen« auf Seite 123 wiederholen. tippen Sie darauf.4. und wir können damit beginnen.notification. Vibration und Warnungen PhoneGap stellt so einfache beep-. Das Gerät mit JavaScript steuern Jetzt ist alles vorbereitet. Dank phonegap.apk Der Schalter -d sagt adb.und alert-Funktionen zur Verfügung. und testen Sie. Jetzt haben wir eine Programmdatei. dass ich alle drei in einem einzigen Beispiel zusammenfassen werde.transaction(2 function(transaction) { transaction.js müssen Sie Ihrem JavaScript beispielsweise nur eine einzige Codezeile hinzufügen. Falls Sie die App noch nicht kompiliert haben.js-Datei im Verzeichnis ~/Desktop/ KiloGap/assets/www/ folgende Funktion an: function checkBudget() {1 var currentDate = sessionStorage. 5.budget. Ist die Kompilation nicht erfolgreich.h. Ihre App ist auf dem Gerät jetzt wie jede andere App verfügbar. tun Sie das. Hängen Sie dazu ans Ende der kilo. Suchen Sie Kilo in der Anwendungsliste.apk) auf dem ersten verbundenden Gerät installiert werden soll. um die App zu starten. eine Vibration generiert und eine Warnung anzeigt. Ziemlich simpel. der seine Nahrungsaufnahme das tägliche Kalorienlimit überschreiten lässt. oder etwa nicht? Piepen. um Ihre App mit Debugging-Unterstützung zu kompilieren: ant debug Wenn alles gut geht.

3 Führt die executeSql()-Methode des Transaktionsobjekts aus. wenn die SQL-Abfrage erfolgreich abgeschlossen wird (diese werden wir uns gleich genauer ansehen). Untersuchen wir die vier Parameter der executeSql()-Methode: 4 Der erste Parameter ist eine vorbereitete SQL-Anweisung. ¨ } catch(e) { alert(message). der in localStorage gespeichert ist (d.9 var message = ’Sie haben ihr Tageslimit um ’+overage+ ’uberschritten. deren Datum dem aktuellen Datum entsprechen.beep(1). navigator. null. Das Gerät mit JavaScript steuern | 133 . } Hier ist eine Beschreibung der einzelnen Schritte: 1 Das ist der Anfang der Funktion checkBudget().vibrate(). 5 function (transaction.h.notification. die aufgerufen wird. result) {6 var currentTotal = result.’.alert(message.: ¨ ¨ try {. ’Bumm!’). } catch(e){ ¨ // Kein Aquivalent in Web-Apps } try {< navigator. um die Werte in der Spalte calories für die Einträge zusammenzurechnen. die die Funktion SUM nutzt. Er initialisiert die Variable currentDate auf den in sessionStorage gespeicherten Wert (d.7 if (currentTotal > dailyBudget) {8 var overage = currentTotal .notification. auf den Wert. das Datum auf der Tage-Seite. } ). navigator.item(0). 6 Der dritte Parameter ist eine anonyme Funktion. der das Fragezeichen in der vorbereiteten Anweisung auf der vorangehenden Zeile ersetzt.’SELECT SUM(calories) AS currentTotal FROM entries WHERE date = ?. 5 Der zweite Parameter ist ein Array mit nur einem Wert.notification. auf das der Anwender getippt hat). Da ist eine Trainingseinheit fallig!’.currentTotal. ’Limit uberschritten’. } } }. den der Anwender auf der Seite EINSTELLUNGEN eingegeben hat) und setzt die Variable dailyBudget auf den Wert.h. 2 Öffnet eine Datenbanktransaktion zur Vorbereitung der Berechnung der Kalorien für den gesamten Tag.4 [currentDate]. errorHandler = ).rows.dailyBudget.

Da es kein browser-basiertes Gegenstück zu beep() oder vibrate() gibt. Das ist ein try/catch-Block. liefert die Datenbank nur eine Zeile (d. wie weit der Nutzer das Kalorienlimit überstiegen hat. dass die Ausführung an den catch-Block übergeben wird. bleibt der catch-Block leer. Das browser-basierte Gegenstück zu alert() ist ein gewöhnliches JavaScript-alert(). < Das ist ein try/catch-Block. Diese Methoden gibt es nur in PhoneGap. Anders gesagt. Beispielsweise können Sie beim PhoneGap alert() den Titel und den Namen des Buttons steuern (siehe Abbildung 7-16). 9 Berechnet. beim JavaScript alert() nicht (siehe Abbildung 7-17). der versucht. während sie bei der PhoneGap-Version fortgesetzt wird. Führt der Anwender die App in einem Browser aus. = Der vierte Parameter ist der Name des generischen SQL-Fehler-Handlers. : Baut eine Meldung auf. dass man auf die Elemente der Datensätze der Ergebnismenge mit der item()-Methode der rows-Eigenschaft des result-Objekts zugreift und dass die Zählung der Zeilen mit 0 beginnt (die erste Zeile also die Zeile 0 ist). das als Ausweichlösung aufgerufen wird. die alert()-Methode des navigator. die Ausführung des Skrips wird angehalten. Sie sollten sich diesen Unterschied deswegen einprägen. Da wir nur nach der Summe über eine Spalte fragen. die dem Anwender angezeigt wird. var food = $(’#food’). Nachdem wir die Funktion checkBudget() abgeschlossen haben.Folgendes passiert in der anonymen Funktion. indem wir dem Erfolgs-Callback der Funktion createEntry() eine einzige Zeile hinzufügen: function createEntry() { var date = sessionStorage.val(). schlagen diese Aufrufe fehl und führen dazu. ob die am aktuellen Tag aufgenommene Menge an Kalorien das Limit übersteigt.currentDate.Es gibt einige Unterschiede zwischen der PhoneGap-Warnung und der nativen JavaScript-Warnung. var calories = $(’#calories’). die PhoneGap-Warnung nicht. Diese Methode gibt es nur in PhoneGap.h. 8 Prüft. wenn Sie die native alert()-Funktion aufrufen. schlagen diese Aufrufe fehl und führen dazu.notification-Objekts aufzurufen. der bei einem SQL-Fehler aufgerufen wird. Bei einigen Anwendungen ist das wichtig. . diese Abfrage liefert immer genau eine Zeile).val(). das auf der Seite EINSTELLUNGEN eingegeben wurde. bei anderen nicht.Außerdem gibt es noch einen subtileren Unterschied zwischen den beiden Warnungen: Die native JavaScript-Warnung ist modal.. wird der nachfolgende Block ausgeführt. 134 | Kapitel 7: Native Apps . Führt der Anwender die Anwendung in einem Browser aus. Ist das der Fall. der versucht. können wir sie jetzt aufrufen. Erinnern Sie sich. dass die Ausführung an den catch-Block übergeben wird. die als dritter Parameter übergeben wurde: 7 Diese Zeile ruft die aktuelle Gesamtsumme aus der ersten Ergebniszeile ab.notification-Objekts aufzurufen. die Methoden beep(1) und vibrate() des navigator.

[date. ?).goBack(). food]. calories. errorHandler ). } ). um die App neu zu kompilieren und auf Ihrem Gerät zu installieren (ändern Sie -d in -e.db. wenn Sie lieber den Emulator nutzen wollen): ant debug adb -d install -r ~/Desktop/KiloGap/bin/Kilo-debug. food) VALUES (?.transaction( function(transaction) { transaction.executeSql( ’INSERT INTO entries (date.’. Das Gerät mit JavaScript steuern | 135 . calories. } Nehmen Sie alle erforderlichen Änderungen vor. return false. jQT.js. öffnen Sie ein Kommandozeilenfenster (siehe »Die Kommandozeile nutzen« auf Seite 114).apk Abbildung 7-16: Bei der PhoneGap-Warnung können Sie den Titel und die Beschriftung des Buttons anpassen. checkBudget(). speichern Sie kilo. }. und führen Sie die folgenden Befehle aus. ?. function(){ refreshEntries().

’ + ’ calories INTEGER NOT NULL. ’ + ’ date DATE NOT NULL. den Ort zu speichern. wenn Einträge erstellt werden. latitude TEXT NOT NULL). damit wir die entsprechenden Daten speichern können. ’ + ’ longitude TEXT NOT NULL.js durch die folgende: db. Geolocation Bringen wir die Kilo-App dazu.und den Breitengrad hinzufügen. 136 | Kapitel 7: Native Apps . an der der Eintrag erstellt wurde. } ). Ersetzen Sie dazu die CREATE TABLE in ~/Desktop/KiloGap/assets/www/kilo.executeSql( ’CREATE TABLE IF NOT EXISTS entries ’ + ’ (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT.Abbildung 7-17: Bei einer nativen JavaScript-Warnung können Sie den Titel und die Button-Beschriftung nicht anpassen.transaction( function(transaction) { transaction. Der erste Schritt ist. der die eingebaute Maps-Anwendung öffnet und in ihr eine Markierung an der Stelle anzeigt.’ ). food TEXT NOT NULL. Haben wir diese Informationen. werden wir einen KARTE-Button hinzufügen. dass wir der Datenbank Spalten für den Längen.

eine für den Fehlerfall.5 }. calories. latitude. longitude) ’ + Das Gerät mit JavaScript steuern | 137 .transaction(5 function(transaction) {6 transaction. 4 Diese beiden Zeilen rufen die Koordinaten latitude und longitude des positionObjekts ab.executeSql(7 ’INSERT INTO entries (date. um das Standardnavigationsverhalten eines Klicks auf den ABSENDENButton eines Formulars zu unterbinden.currentDate. wo die SQL-INSERT-Anweisung geblieben ist? Werfen wir einen Blick auf die Funktion insertEntry(). longitude). wenn der Geolocation-Aufruf fehlschlägt (beispielsweise wenn der Anwender der App den Zugriff auf Geolocation verweigert. insertEntry(latitude. 7 Da wir uns im Fehler-Callback befinden. Beachten Sie.geolocation. position) erwartet. function(){6 insertEntry(). longitude) {1 var date = sessionStorage.latitude. return false.und Längengrad zu bestimmen. insertEntry() wird deswegen ohne Parameter aufgerufen. Ersetzen Sie die createEntry()-Funktion in kilo.js durch folgenden Code: function createEntry() {1 navigator. wird dieser Code nur aufgerufen.3 var food = $(’#food’).js Folgendes hinzu: function insertEntry(latitude.2 var calories = $(’#calories’).coords. dass es einen Parameter (d. 6 Das ist der Anfang des Fehler-Callbacks. food. wenn er dazu aufgefordert wird). 3 Das ist der Anfang des Erfolgs-Callbacks.getCurrentPosition(2 function(position){3 var latitude = position.val().8 } 1 Das ist der Anfang der Funktion createEntry(). 2 Ruft die Funktion getCurrentPosition() des geolocation-Objekts auf und übergibt ihr zwei Callback-Funktionen: eine für den Erfolgsfall. Fügen Sie kilo.4 db.coords. die wir uns gleich ansehen werden.longitude. Sie fragen sich.Dann werden wir die in Kapitel 5 erstellte Funktion createEntry() so umschreiben. 8 Liefert false. um den aktuellen Breiten. Diese neue Funktion erstellt den Eintrag in der Datenbank.val(). dass sie die Geolocation-Funktion des Geräts nutzt.4 var longitude = position.7 } ).h. 5 Übergibt die Koordinaten latitude und longitude an eine Funktion namens insertEntry().

dass dieser Wert gesetzt wird. Parameter explizit als optional zu definieren. ob Kilo tatsächlich diese Ortswerte speichert. Damit wir sehen können. 5 Öffnet eine Datenbanktransaktion. checkBudget(). 9 Übergibt ein Array mit Werten für die Platzhalter. ?. ?. 8 Definiert die vorbereitete SQL-Anweisung mit Fragezeichen als Datenplatzhalter. ist dieser Wert immer noch auf das aktuell in der Seite TAG geöffnete Element gesetzt. Fügen Sie index. um die Seite TAG zu öffnen.’. Wenn latitude und longitude nicht an die Funktion insertEntry() übergeben werden. Wir werden der Seite einen KARTE-Button geben. um die gespeicherten Werte anzuzeigen. ?. 2 Liest currentDate aus sessionStorage. Erinnern Sie sich. longitude].8 [date. 6 Übergibt der Transaktion eine Callback-Funktion mit dem Transaktionsobjekt als einzigem Parameter. wenn sie nicht übergeben werden. Fügen wir dazu eine EINTRAG UNTERSUCHEN-Seite hinzu. Tippt er auf den +-Button. ?). food. } 1 Das ist der Anfang von insertEntry() mit den Parametern latitude und longitude für die Geolocation-Koordinaten.’VALUES (?. ).9 function(){: refreshEntries(). calories. jQT. } ). wenn der Anwender auf der Seite TAGE auf einen Eintrag tippt. um die Seite NEUER EINTRAG zu öffnen. latitude.goBack(). wo der Eintrag erstellt wurde. : Definiert die Callback-Funktion für den Erfolgsfall. Sie sind einfach undefiniert. wollen wir sie irgendwo in der Schnittstelle anzeigen. }. 3 Ruft die Kalorien aus dem Formular createEntry ab. sind die beiden Parameter undefined. In JavaScript gibt es keine Möglichkeit. 4 Ruft die Nahrung aus dem Formular createEntry ab. 7 Ruft die executeSql()-Methode des Transaktionsobjekts auf. errorHandler. .html unmittelbar vor dem schließenden Body-Tag (</body>) folgenden Code hinzu: <div id="inspectEntry"> <div class="toolbar"> <h1>Eintrag einfugen</h1> ¨ <a class="button cancel" href="#">Abbrechen</a> </div> 138 | Kapitel 7: Native Apps . der anzeigt. Definiert die Callback-Funktion für den Fehlerfall.

function (transaction.<form method="post"> <ul class="rounded"> <li><input type="text" placeholder="Nahrung" name="food" value="" /></li> <li><input type="tel" placeholder="Kalorien" name="calories" value="" /></li>1 ¨ <li><input type="submit" value="Anderungen speichern" /></li> </ul> <ul class="rounded"> <li><input type="text" name="latitude" value="" /></li>2 <li><input type="text" name="longitude" value="" /></li> <li><p class="whiteButton" id="mapLocation">Karte</p></li>3 </ul> </form> </div> Das hat große Ähnlichkeit mit der Seite NEUER EINTRAG. Das Gerät mit JavaScript steuern | 139 . wenn der Cursor in dieses Feld gesetzt wird. wenn er angeklickt wird. Wir werden ihm gleich einen Click-Handler hinzufügen. wie Klicks auf den LÖSCHEN-Button verarbeitet werden.executeSql( ’SELECT * FROM entries WHERE date = ? ORDER BY food. 2 Die Felder für den Breitengrad und den Längengrad können bearbeitet und in das Formular eingeschlossen werden. i < result.remove(). var newEntryRow = $(’#entryTemplate’).transaction( function(transaction) { transaction. $(’#date ul li:gt(0)’). 3 Noch macht der Button Karte nichts. da Sie die Werte manuell eingeben können. newEntryRow. Deswegen will ich nur einige Dinge hervorheben: 1 Der Eingabetyp wurde auf tel gesetzt. [currentDate]. dass wir einen Click-Event-Handler anbinden (den wir als Nächstes erstellen werden) und ebenfalls ändern. db. dass sich das lohnt. In der endgültigen Anwendung ist das wahrscheinlich wenig sinnvoll.rows. Fügen Sie die drei unten hervorgehobenen Änderungen in die Funktion refreshEntries() in kilo.item(i). dass der Benutzer sie bearbeiten kann.currentDate. Das ist ein kleiner Hack. um den Button KARTE zu testen. aber ich denke. dass von unten die Seite EINTRAG UNTERSUCHEN hereingleitet. um die Telefontastatur zu öffnen. Der erste Schritt ist. da diese Tastatur für ein numerisches Datenfeld viel geeigneter ist.rows. wenn der Benutzer auf einen Eintrag in der Liste tippt. Das heißt. Jetzt müssen wir dem Benutzer eine Möglichkeit geben. es vereinfacht aber das Testen. Wir werden dafür das Verhalten der Seite TAG so ändern.’.length. i++) { var row = result. zur Seite EINTRAG UNTERSUCHEN zu gehen. $(’#date h1’).removeAttr(’id’).clone().js ein: function refreshEntries() { var currentDate = sessionStorage. result) { for (var i=0. die uns das erste Mal in Beispiel 4-5 begegnete.text(currentDate).

result) {7 var row = result.data(’entryId’).8 var food = row. e.newEntryRow. dass er das Click-Event nicht im DOM zum Elternelement aufsteigen lassen soll.food). $(’#inspectEntry input[name="food"]’). Das ist wichtig. damit wir Zugriff auf die stopPropagation()-Methode des Events haben. var clickedEntryId = clickedEntry. die wir gleich nutzen werden.slideUp().data(’entryId’).val(calories). var latitude = row.executeSql(4 ’SELECT * FROM entries WHERE id = ?. deleteEntryById(clickedEntryId).stopPropagation() undefiniert.calories’).2 }). newEntryRow.appendTo(’#date ul’). dass er die Funktion entryClickHandler aufrufen soll.longitude. clickedEntry.js jetzt die Funktion entryClickHandler() hinzu: function entryClickHandler(e){ sessionStorage.find(’. var longitude = row. wenn auf den Eintrag getippt wird.’. newEntryRow.3 } }. newEntryRow. Fügen wir kilo.1 db. 6 function (transaction.stopPropagation(). row.text(row.click(entryClickHandler). newEntryRow. errorHandler ).delete’).9 var calories = row.calories. sagt dem Browser.entryId = $(this). } 1 Wir haben dem Funktionsaufruf den Parameter e (das Event) hinzugefügt.: $(’#inspectEntry input[name="calories"]’).click(entryClickHandler).food. 3 Das newEntryRow. sagt dem Browser. 140 | Kapitel 7: Native Apps . 5 [sessionStorage. newEntryRow.rows.parent(). } ).transaction(2 function(transaction) {3 transaction. würden sowohl der Handler auf dem LÖSCHEN-Button als auch der entryClickHandler angestoßen.find(’.stopPropagation().val(food).data(’entryId’. wäre e.latitude.calories). newEntryRow.removeAttr(’style’).item(0).entryId].label’).click(function(e){1 var clickedEntry = $(this). wenn auf den LÖSCHENButton getippt wird. weil wir jetzt der Zeile selbst einen Click-Handler hinzugefügt haben (und die Eintragszeile das Elternelement des LÖSCHEN-Buttons ist).id). 2 Das dem Click-Handler des LÖSCHEN-Buttons hinzugefügte e. Würden wir stopPropagation() nicht aufrufen.find(’. Würden wir den Parameter e nicht definieren.text(row.

val(longitude). Breitengrad und Längengrad müssen in der hier gezeigten Reihenfolge angegeben und durch ein Komma getrennt werden. Öffnen Sie ein Kommandozeilenfenster. } 1 Ruft die entryId des Eintrags ab. wird diese gestartet. = Definiert die Callback-Funktion für den Fehlerfall. damit Sie die neue Version testen können: ant debug adb -d install -r ~/Desktop/KiloGap/bin/Kilo-debug. da wir nur nach einem Eintrag suchen) Zeile des Ergebnisses ab. damit die Seite EINTRAG SUCHEN eingeblendet wird. ’slideup’). jQT. window.click(function(){.location = ’http://maps. 2 Öffnet eine Datenbanktransaktion. wechseln Sie mit cd in das KiloGap-Verzeichnis. 8 Ruft die erste (und einzige. errorHandler= ). um Ihre App neu zu kompilieren und auf dem Gerät zu installieren.google.location auf eine Standard-Google-Maps-URL. die am Ort angezeigt wird.com/maps?z=15&q=’+ food+’@’+latitude+’.’+longitude. $(’#mapLocation’). und führen Sie die folgenden Anweisungen aus. Der z-Wert setzt die anfängliche Zoomstufe. .apk UNTER- Das Gerät mit JavaScript steuern | 141 . 3 Übergibt eine Callback-Funktion an die Transaktion. 9 Setzt einige Variablen auf Grundlage von Werten aus der Zeile.$(’#inspectEntry input[name="latitude"]’). Bindet einen Click-Handler an den Button #mapLocation. Ist die Maps-Anwendung verfügbar. }). Die Funktion setzt window. } ). 5 Definiert eine vorbereitete SQL-Anweisung mit einem Fragezeichen als Platzhalter. und speichert sie im Session-Speicher. : Setzt die Werte der Formularfelder auf Basis der Variablen. Andernfalls wird die URL im Browser geladen. mit dem Transaktionsobjekt als einzigem Parameter. 7 Beginnt die Callback-Funktion für den Erfolgsfall. < Ruft die goTo()-Methode des jQTouch-Objekts auf.goTo(’#inspectEntry’. 6 Übergibt ein Array mit einem Element für den Platzhalter. den der Anwender angetippt hat.< }. 4 Ruft die executeSql()-Methode des Transaktionsobjekts auf.val(latitude). der String vor dem @-Symbol wird als Text für die Marke verwendet. $(’#inspectEntry input[name="longitude"]’).

Beschleunigungssensor Richten wir Kilo jetzt dafür ein. ¨ } else { db. wenn das Gerät geschüttelt wird. calories. latitude. Dazu müssen wir nur der Document-Ready-Funktion in kilo. die die Werte der angegebenen entryId kopiert. dass er gestartet wird. wenn sie beginnt.transaction(2 function(transaction) { transaction. 4 function() {5 refreshEntries(). }. Das ist ein Abfragetyp. food. wann sie den Beschleunigungssensor starten und anhalten soll.js die folgenden Zeilen hinzufügen: $(’#date’). [entryId]. Statt einer Liste von Werten nimmt dieses INSERT einfach die Werte aus den Ergebnissen einer SELECTAbfrage für die angegebene entryId. 4 Übergibt die entryId an die vorbereitete Anweisung und ersetzt das ? in der SELECTAbfrage durch den Wert von entryId. 142 | Kapitel 7: Native Apps .executeSql( ’INSERT INTO entries (date. ob der Funktion eine entryId übergeben wurde. info){1 if (info. wenn Sie ein Duplikat erschutteln wollen. wird der Benutzer benachrichtigt. dass der letzte Eintrag in der Liste dupliziert wird. 6 Bei einem Fehler wird der Standard-Handler für SQL-Fehler aufgerufen.bind(’pageAnimationEnd’. longitude) ’ + 3 ’SELECT date. Jetzt müssen wir der Anwendung sagen. } ). } } 1 Diese Zeile prüft. vom Bildschirm zu verschwinden. Ist das nicht der Fall. die die neu eingefügte Kopie anzeigt. errorHandler6 ).direction == ’in’) {2 startWatchingShake(). 2 Beginnt die üblichen Schritte für eine Datenbanktransaktion. 3 Definiert eine INSERT-Anweisung. Wir werden ihn so einrichten. wenn die Seite TAG vollständig auf dem Bildschirm ist. latitude.’. calories. der Ihnen bislang noch nicht begegnet ist.js die folgende Funktion an: function dupeEntryById(entryId) { if (entryId == undefined) {1 alert(’Die Liste muss mindestens einen Eintrag haben.’). 5 Bei Erfolg wird die Funktion refreshEntries() aufgerufen. food. function(e. longitude ’ + ’FROM entries WHERE id = ?. Hängen Sie ans Ende von kilo. und dass er angehalten wird.

: } Das Gerät mit JavaScript steuern | 143 . ob die direction-Eigenschaft des info-Objekts gleich out ist.x) > max || Math.z) > max) {4 var entryId = $(’#date ul li:last’).8 options.5 dupeEntryById(entryId). wenn die Seitenanimation abgeschlossen ist. Ist das der Fall. wenn wir folgendermaßen nur an eines der Seitenanimations-Events einen Handler bänden: $(’#date’).watchAcceleration(success.bind(’pageAnimationStart’. var error = function(){}. ob die direction-Eigenschaft des info-Objekts gleich in ist.} }). function(e. 3 Bindet einen anonymen Handler an das pageAnimationBegin-Event der #date-Seite. 4 Prüft. die wir uns gleich ansehen werden. } }). Fügen Sie kilo.abs(coords.accelerometer. wird die Funktion stopWatchingShake() aufgerufen. die wir uns gleich ansehen werden. info){3 if (info.frequency = 100.9 sessionStorage. 2 Prüft.bind(’pageAnimationEnd’.abs(coords. Jetzt müssen wir nur noch den Code für die Funktionen startWatchingShake() und stopWatchingShake() schreiben.7 var options = {}.watchId = navigator. Ist das der Fall.6 } }. Eigentlich würde es auch reichen. info){ if (info. Der Beschleunigungssensor wäre dann während der Seitenanimation noch aktiv. weil stopWatchingShake() dann erst aufgerufen wird. Übergibt das Event und die zusätzlichen Daten als Parameter.direction == ’out’) {4 stopWatchingShake(). options). Das habe ich nicht gemacht. error. Übergibt das Event und die zusätzlichen Daten als Parameter.direction == ’in’) { startWatchingShake().data(’entryId’).abs(coords. 1 Bindet einen anonymen Handler an das pageAnimationEnd-Event der Seite #date. } else { stopWatchingShake(). } }).y) > max || Math.js die folgenden Funktionen hinzu: function startWatchingShake() {1 var success = function(coords){2 var max = 2. function(e. was in manchen Fallen zu Rucklern in der Animation führen kann.3 if (Math. $(’#date’). wird die Funktion startWatchingShake() aufgerufen.

die in browser-basierten Web-Apps nicht verfügbar sind (Alarmton. Geolocation und Beschleunigungssensor). das wir für die Funktion stopWatchingShake() benötigen. Er erwartet ein coordinates-Objekt als Parameter. Im nächsten Kapitel werden Sie erfahren. um so heftiger muss der Anwender schütteln. navigator. Je größer die Zahl ist. wenn die Animation gestartet wird. Vibration. Beginnt die Funktion stopWatchingShake().watchId. wie Sie Ihre App als Programm verpacken und auf dem Android Market einreichen. : Ruft die watchAcceleration()-Methode des accelerometer-Objekts auf und übergibt dabei den Erfolgs-Handler. 2 Beginnt die Definition des Erfolgs-Handlers. wie Sie Ihre Web-App in PhoneGap laden. Speichert das Ergebnis im Feld sessionStorage. 3 Definiert die Schwelle für das Schütteln. Diese Funktion wird aufgerufen. 7 Definiert einen leeren Fehler-Handler. 5 Ruft die entryId des letzten Eintrags auf der Seite #date ab. auf dem Gerät installieren und auf fünf Gerätefunktionen zugreifen. . 4 Prüft. den Fehler-Handler und das Optionsobjekt als Parameter. wenn die Animation. ob die Koordinaten die Schwelle übersteigen. das an die watchAcceleration()-Methode des accelerometer-Objekt übergeben wird.function stopWatchingShake() {. 6 Ruft die Funktion dupeEntryById() auf. mit der die Seite #date eingeblendet wird. abgeschlossen ist.< } 1 Beginnt die Funktion startWatchingShake().accelerometer. mit der die Seite #date den Bildschirm verlässt. 9 Setzt die frequency-Eigenschaft des Optionsobjekts auf die Verzögerung zwischen dem Empfang vom Beschleunigungssensor in Millisekunden. 8 Definiert ein options-Objekt. Warnungsmeldung. < Ruft die clearWatch()-Methode des accelerometer-Objekts auf und übergibt watchId aus dem Session-Speicher.clearWatch(sessionStorage.watchId). 144 | Kapitel 7: Native Apps . Diese Funktion wird aufgerufen. Was Sie gelernt haben In diesem Kapitel haben Sie gelernt.

| 145 . um die App für die Verbreitung vorzubereiten: • eventuellen Debugging.KAPITEL 8 Die App auf dem Android Market einreichen Endlich ist er da. <application android:icon="@drawable/icon" android:label="@string/app_name" android:debuggable="false"> . Wenn Sie das getan haben. an dem Sie Ihre fertige App auf dem Android Market einreichen. Die Release-Version der App vorbereiten Sie müssen ein paar Dinge tun. ist es jetzt an der Zeit. Der Vorgang ist eigentlich recht einfach: Sie bereiten eine Release-Version der App vor und laden sie hoch.. Sie sollten auch Ihre AndroidManifest. CSS.oder JavaScript-Dateien derartigen Code enthalten (siehe ).und Logging-Code entfernen • der App eine Versionsnummer geben • die App kompilieren • die App mit einem privaten Schlüssel signieren Debugging-Code entfernen Es gibt keinen Grund. diesen zu entfernen..xml-Datei im KiloGap-Ordner öffnen. die App von Debugging. auf den Sie gewartet haben: der Zeitpunkt. Wenn Ihre HTML-. nach »debuggable« suchen und es auf false setzen. der Moment.oder Logging-Code ausbremsen zu lassen. sollte diese Datei ungefähr so aussehen: . während sie auf dem Gerät eines Anwenders läuft...

passen Sie diese Werte entsprechend an. Das Verfahren dazu ist einfach. Kompilieren Sie die App im Release-Modus: ant release Es schwappt ein Strom von Ausgaben über den Bildschirm. die von BUILD SUCCESSFUL abgeschlossen werden..B.0.xml sollten Sie den Versionsnamen und den Versionscode für Ihre App sehen: . aber etwas kryptisch: 1. Haben Sie Ihre App veröffentlicht und wollen Sie später ein Update veröffentlichen. 1. Er muss dem Versionsnamen in keiner Weise entsprechen. PhoneGap kümmert sich normalerweise für Sie darum. aber Sie sollten das dennoch überprüfen. Wahrscheinlich wird das nie der Fall sein – da Sie ihn einfach um 1 erhöhen sollten. Sie können hier also angeben.<Point>-Format (z. Anschließend befindet sich im Verzeichnis ~/Desktop/KiloGap/bin/ ein unsigniertes Paket namens Kilo-unsigned. Öffnen Sie ein Kommandozeilenfenster. Es ist ein Textwert.0" android:versionCode="1"> . aber üblicherweise nutzt man das <Major>. Die App signieren Android verlangt.. was Sie wollen. können Sie auch gleich prüfen. dass alle Apps vom Entwickler digital signiert werden. weil Sie Ihre App nicht hochladen können. ob es sich um eine wichtigere Verbesserung oder um einen kleineren Bugfix handelt. 146 | Kapitel 8: Die App auf dem Android Market einreichen .<Minor>.kilo" android:versionName="1.com/apk/res/android" package="com.Wo Sie die Manifest-Datei gerade geöffnet haben. wenn diese Werte nicht gesetzt sind. Der Versionsname ist der Wert. <manifest xmlns:android="http://schemas. und wechseln Sie ins KiloGap-Verzeichnis: cd ~/Desktop/KiloGap 2. Das Android-System prüft oder erzwingt diese Versionsinformationen nicht.0. sind diese Werte so wahrscheinlich in Ordnung. aber sie sind ein entscheidender Bestandteil einer langfristigen App-Strategie. ganz gleich. wenn Sie ein Update veröffentlichen.0)..jonathanstark. ob android:icon und android:label wie im Codeauszug oben angegeben sind.. Da das vermutlich Ihre erste App ist.apk (siehe Abbildung 8-1). der dem Benutzer angezeigt wird.android. Die App versionieren Oben in der Datei AndroidManifest. Der Versionscode soll eine positive Ganzzahl sein.

ST=RI.keystore \ -alias myAndroidKeyAlias -keyalg RSA -validity 10000 Enter keystore password: Re-enter new password: What is your first and last name? [Unknown]: Jonathan Stark What is the name of your organizational unit? [Unknown]: What is the name of your organization? [Unknown]: Jonathan Stark Consulting What is the name of your City or Locality? [Unknown]: Providence What is the name of your State or Province? [Unknown]: RI What is the two-letter country code for this unit? [Unknown]: US Is CN=Jonathan Stark. OU=Unknown. C=US Die Release-Version der App vorbereiten | 147 . C=US correct? [no]: yes Generating 1. Bei mir sieht das so aus: JSC-MBP:KiloGap jstark$ keytool -genkey -v -keystore myAndroidKey. OU=Unknown.024 bit RSA key pair and self-signed certificate (SHA1withRSA) with a validity of 10. ST=RI. L=Providence. O=Jonathan Stark Consulting. O=Jonathan Stark Consulting. 3. Erstellen Sie einen privaten Schlüssel: 12 keytool -genkey -v -keystore keystore -alias alias -keyalg RSA -validity days Dieser Befehl ist interaktiv und stellt Ihnen einen Haufen Fragen.000 days for: CN=Jonathan Stark. L=Providence.Abbildung 8-1: Der Befehl »ant release« erstellt ein unsigniertes Paket namens »Kilo-unsigned.apk« im Verzeichnis »~/Desktop/KiloGap/bin/«.

Wenn Sie Ihr Keystore-Passwort vergessen./bin/Kilo. sollten Sie die Keystore-Datei an einen zentraleren Ort verschieben. werden Sie um Ihr Keystore-Passwort gebeten.apk Es strömen einige Ausgaben über den Bildschirm. Signieren Sie die App mit dem gerade erstellten Schlüssel: jarsigner -verbose -keystore myAndroidKey.keystore« im Verzeichnis »KiloGap«. Diese . Wenn Sie diesen Keystore bei zukünftigen Apps wiederverwenden wollen.apk-Datei ist Ihre fertige App! 148 | Kapitel 8: Die App auf dem Android Market einreichen . GlättenSie die . die mit »Verification successful« abgeschlossen werden.keystore . Abbildung 8-2: Der Befehl »keytool« generiert eine Keystore-Datei namens »myAndroidKey./bin/Kilo-unsigned.keystore] Ist der Vorgang abgeschlossen. Verbummeln Sie dieses Passwort nicht. 5.apk-Datei mit zipalign: zipalign -v 4 . Jetzt befindet sich das signierte Paket namens Kilo. sollten Sie die Datei myAndroidKey.apk myAndroidKeyAlias Wenn Sie diesen Befehl ausführen.keystore im Verzeichnis ~/Desktop/KiloGap sehen (siehe Abbildung 8-2).Enter key password for <myAndroidKeyAlias> (RETURN if same as keystore password): [Storing myAndroidKey. können Sie Ihre App nach der Veröffentlichung nicht mehr aktualisieren. 4./bin/Kilo-unsigned.apk .apk im Verzeichnis ~/Desktop/KiloGap/bin/ (siehe Abbildung 8-3).

Die App auf den Android Market hochladen | 149 .com/publish/Home.android.).com/publish/. bezahlen Sie die Registrierungsgebühr von 25 $ (mit Google Checkout). Das ist ein einfacher und unkomplizierter Vorgang – geben Sie ein paar Profilinformationen ein (Name. Wenn Sie noch nicht registriert sind. und stimmen Sie dem Android Market Developer Distribution Agreement zu. gehen Sie zu http://market.android. Die App auf den Android Market hochladen Jetzt muss das signierte Paket nur noch auf den Android Market hochgeladen werden.Abbildung 8-3: Haben Sie die Befehle »jarsigner« und »zipalign« ausgeführt. wird Ihre fertige App im Verzeichnis »~/Desktop/KiloGap/bin/« generiert. Wenn Sie nach dem Einloggen nicht automatisch weitergeleitet werden. und klicken Sie auf den Button UPLOAD APPLICATION (siehe Abbildung 8-4). Sie müssen ein registrierter Android Developer sein. wenn Sie Ihre App hochladen wollen.com/publish/signup tun. E-Mail-Adresse. und melden Sie sich mit Ihrem Google-Konto an. gehen Sie zu http://market. 1. können Sie das unter http://market. Telefonnummer etc.android. 2. Starten Sie Ihren Webbrowser.

5. und klicken Sie dann auf den Button UPLOAD. die auf der Market-Seite für Ihre App angezeigt werden. 6. 150 | Kapitel 8: Die App auf dem Android Market einreichen . um Kilo. 4.apk auf Ihrer Festplatte zu suchen. Geben Sie den Titel für Ihre App im Abschnitt LISTING DETAILS ein (maximal 30 Zeichen). 8. um Ihre App einzureichen. einige Screenshots hochzuladen. Geben Sie eine Beschreibung für Ihre App ein (maximal 325 Zeichen). Ihre E-Mail-Adresse und Ihre Telefonnummer im Abschnitt Contact Information ein. Wählen Sie einen Typ und eine Kategorie für Ihre App. 10.apk-Datei«. Sie haben optional die Möglichkeit. Geben Sie im Abschnitt PUBLISHING OPTIONS die Einstellungen für Kopierschutz und Ort ein. 9. Geben Sie die Adresse Ihrer Website. 3. 7. Legen Sie einen Preis für Ihre App fest.Abbildung 8-4: Gehen Sie zur Android Market-Upload-Seite. Klicken Sie auf den CHOOSE FILE-Button neben »Application .

com/apis/chart/docs/gallery/qr_codes. Was auch immer Ihr Grund dafür sein könnte. dass die Installation blockiert ist (siehe Abbildung 8-6). die unmittelbare Verteilung könnte einfacher nicht sein: Laden Sie Ihr signiertes . Ein QR-Code ist ein zweidimensionaler Strichcode. sofort zur entsprechenden Einstellung zu navigieren oder die Installation abzubrechen. Stimmen Sie im Abschnitt CONSENT den Bedingungen zu. Aktiviert der Benutzer die Checkbox. Oder vielleicht möchten Sie eine private Beta Ihrer App ausgeben. dass sie Entwicklern gestattet. dass der Anwender zuvor die Installation von Nicht-Market-Apps gestatten muss.html).296 alphanumerische Zeichen mit beliebigem Text speichern kann und der von der Kamera des Android-Geräts gelesen werden kann. bevor Sie sie auf dem Android Market verteilen.com/apis/chart/docs/chart_playground. wird aber dann benachrichtigt. in einer E-Mail oder auf einer Website –. Apps direkt verteilen Eine sehr interessante Eigenschaft der Android-Plattform ist. Mehr darüber erfahren Sie auf der Google Chart Tools-Seite zu QR-Codes (http://code. sieht er einen Bestätigungsdialog. Apps direkt verteilen | 151 . Hat der Anwender Downloads von unbekannten Quellen noch nicht aktiviert.11. kann er die App zwar herunterladen. 12. und die App wird heruntergeladen und installiert. kann er ihn mit Google Goggles (oder einer andern QRCode-Reader-App) fotografieren und erhält so einen Link auf Ihre App. um Links auf Ihre App zu verteilen.apk-Paket auf Ihren Webserver hoch. den Android Market zu übergehen und Apps direkt an Anwender zu verteilen. indem er zu EINSTELLUNGEN→ANWENDUNGEN geht und die Option UNBEKANNTE QUELLEN aktiviert (siehe Abbildung 8-5). Der Anwender klickt auf den Link – z. Eigene QRCodes können Sie kostenlos mit Googles Live Chart Playground (http://code.html) erstellen. Das einzige Problem ist. Glückwunsch! Ihre App wird beinahe sofort im Android Market verfügbar sein. der ihn auf die möglichen Folgen seiner Wahl hinweist (siehe Abbildung 8-7). Stößt der Anwender auf Ihren QR-Code. In vielen Fällen ist das eine wunderbare Option. Beispielsweise könnte die IT-Abteilung eines Unternehmens den Angestellten auf diese Weise eine private App zur Verfügung stellen. Der Warndialog bietet ihm die Möglichkeit. und schicken Sie Ihren Anwendern einen Link darauf.google. Simpel.google. der bis zu 4. Sie können auch QR-Codes einsetzen.B. Klicken Sie auf den Button PUBLISH.

com/group/android-discuss) • Android Developers-Mailing-Liste (http://groups.com/ der beste Ausgangspunkt.android.google.google.Abbildung 8-5: Anwender können den Download von anderen Quellen als dem Android Market zulassen.google. die ich nützlich finde und häufig nutze: • Android Discuss-Mailing-Liste (http://groups.com/group/android-developers) • jQTouch-Mailing-Liste (http://groups.com/group/jqtouch) • PhoneGap-Mailing-Liste (http://groups. Hier sind einige weitere Ressourcen. ist die exzellente Online-Dokumentation unter http://developer.com/group/phonegap) 152 | Kapitel 8: Die App auf dem Android Market einreichen .google. Weitere Lektüre Wenn Sie sich gründlicher mit den Mechanismen des Android SDKs befassen wollen.

Abbildung 8-6: Versucht der Anwender. ohne zuvor die entsprechende Einstellung zu ändern. eine App von einer unbekannten Quelle zu installieren. wird ihm ein Bestätigungsdialog präsentiert. die Einstellung zu ändern oder die Installation abzubrechen. Abbildung 8-7: Aktiviert der Anwender die Option »Unknown Sources«. wird er aufgefordert. der ihn vor den Folgen warnt. Weitere Lektüre | 153 .

android. Noch einmal: Über diese Dinge müssen Sie sich keine Gedanken machen.html) • Android-Referenz zu WebSettings (http://developer. Und WebSettings gibt Ihnen Zugriff auf WebViewEinstellungen mit Methoden wie getDatabaseEnabled() und setUserAgentString().html) Die Android-Referenzen in der Liste oben sind nur interessant. wenn Sie sich mit dem PhoneGap-Quellcode befassen oder gar einen eigenen nativen HTML-App-Wrapper schreiben wollen.android. und schaffen Sie einige wunderbare Android-Apps! 154 | Kapitel 8: Die App auf dem Android Market einreichen .h. ZURÜCK/ VOR-Buttons) oder Fehlerbehandlung. Favicons.com/reference/android/webkit/WebView.com/reference/android/ webkit/WebViewClient. WebViewClient ergänzt Unterstützung für einige nützliche Event-Listener wie onFormResubmission(). onPageStarted() und onPageFinished().android. Browser-Widgets (d. Die drei anderen Klassen erweitern WebView auf unterschiedliche Weise.android. WebView ist die wichtigste Klasse und wird genutzt. Sie möchten sich dem Java hinter den Kulissen zuwenden.html) • Android-Referenz zu WebChromeClient (http://developer.html) • Android-Referenz zu WebViewClient (http://developer.com/reference/android/webkit/WebChromeClient. Legen Sie jetzt los. es sei denn. um HTML anzuzeigen.• Android-Referenz für WebView (http://developer. Titel und Fortschrittsindikatoren.com/reference/android/ webkit/WebSettings. Adressleiste. standardmäßig bietet sie keine Unterstützung für JavaScript. WebChromeClient ergänzt Unterstützung für JavaScript-Dialoge.

In diesem Anhang werde ich Ihnen zeigen. die erkennen können. WURFL und wurfl-php auf dem Server zu installieren. an dem Sie das Paket installieren wollen. Beispielsweise können Sie mit wurfl-php (http://sourceforge. aber hinreichend Erfahrung mit PHP haben. Ersetzen Sie ~/src durch den Ort. wie man das mit der Unix.1.ANHANG Browsererkennung mit WURFL WURFL (Wireless Universal Resource File) ist eine XML-Datei.oder Mac OS X-Kommandozeile tut. Aber wenn Sie eine der vielen verfügbaren Bibliotheken für das Format nutzen. böte es Ihrem Hosting-Provider einen Wettbewerbsvorteil. können Sie Web-Apps erstellen. um eine große Bandbreite an Mobilgeräten zu erkennen. wie man Dateien und PHP-Bibliotheken auf Ihrem Server installiert. Bibliotheken im öffentlichen Webordner abzulegen. setzen Sie sich mit dem Support Ihres Providers in Verbindung. Für sich allein tut diese Datei nichts.gz Laden Sie anschließend die neueste WURFL-Datei (http://sourceforge. kopieren Sie sie in das Verzeichnis wurfl-php. die Daten enthält. unter welchem Betriebssystem ein entferntes Gerät läuft. Wenn Sie einen Shared Server nutzen.net/projects/wurfl/files/ WURFL%20PHP/) in einem PHP-Skript erkennen. und wurfl-php1. muss Ihre Web-App auf einem Host laufen. Wenn Sie WURFL und wurfl-php nutzen wollen. der PHP unterstützt. Installation Laden Sie zunächst wurfl-php herunter. Außerdem müssen Sie wissen. Wenn Sie mit beidem nicht vertraut sind. was für ein Gerät sich mit Ihrer App verbunden hat.tar.tar. die Sie tatsächlich heruntergeladen haben: $ mkdir ~/src $ cd ~/src $ tar xvfz ~/Downloads/wurfl-php-1. die erforderlich sind. den Sie nutzen.net/projects/wurfl/ files/WURFL/) herunter. und entpacken Sie das Paket auf Ihrem Server (üblicherweise ist es nicht ratsam.1. und entpacken Sie | 155 . wenn er diese Funktion allen Kunden zur Verfügung stellt. und fragen Sie.gz durch den Namen der Datei. ob er bereit wäre. deswegen stecke ich sie in das src-Verzeichnis meines Benutzerverzeichnisses).

den Sie zuvor erstellt haben. das Sie heruntergeladen haben: $ cd ~/src/wurfl-php-1. unter dem Ihre PHP-Skripten laufen.xml</main-file> <patches> <patch>web_browsers_patch. $ gunzip wurfl-latest. dass Ihre PHP-Skripten unter Ihren Benutzerberechtigungen laufen.gz .xml. setzen Sie sich mit dem technischen Support Ihres Hosting-Providers in Verbindung und erklären Sie.xml.1/ $ cp ~/Downloads/wurfl-latest. sollte dieser Schritt nicht erforderlich sein. das im letzten Schritt erstellt wurde. als Sie wurfl-php entpackt haben): <?xml version="1. und ersetzen Sie ~/Downloads/wurfl-latest. Wenn Ihr Webserver so konfiguriert ist. wenn jemand Ihre Seite mit einem Desktop-Browser besucht: $ curl -O http://wurfl.sourceforge.1/cache $ sudo chown _www ~/src/wurfl-php-1./cache</params> </persistence> </wurfl-config> Erstellen Sie ein Cache-Verzeichnis.gz durch den Pfad zum WURFL-Paket. als Sie das wurfl-php-Paket entpackt haben.net/web_browsers_patch.1/ durch den vollständigen Pfad des Verzeichnisses. und stellen Sie sicher.sie (in der wurfl-php-Dokumentation finden Sie Hinweise darauf. dass es für das Konto schreibbar ist.gz Laden Sie zum Abschluss den Desktop Web Browser-Patch herunter. dass das Cache-Verzeichnis für Ihre PHP-Skripten schreibbar sein soll.xml. Ersetzen Sie ~/src/wurfl-php-1. das Sie erstellt haben. Ersetzen Sie _www durch das Benutzerkonto. damit WURFL keine Fehler erzeugt.1/cache Sollten Sie Zweifel oder Probleme haben. unter dem Ihre PHP-Skripten laufen (Sie benötigen Superuser-Berechtigung. 156 | Anhang: Browsererkennung mit WURFL . Ersetzen Sie wie bei den vorangegangenen Beispielen ~/src/wurflphp-1. um diesen Befehl auszuführen): $ mkdir ~/src/wurfl-php-1.xml</patch> </patches> </wurfl> <persistence> <provider>file</provider> <params>dir=.xml) in ~/src/wurfl-php-1.xml Konfiguration Erstellen Sie die folgende wurfl-config-Datei (wurfl-config. wie Sie die Datei in komprimierter Form nutzen können).1/ durch den Ort.1/ (oder in dem Verzeichnis.0" encoding="UTF-8"?> <wurfl-config> <wurfl> <main-file>wurfl-latest.

wird es längere Zeit dauern.wurfl-php testen Erstellen Sie dann in Ihrem Webverzeichnis (z. "/Users/bjepson/src/wurfl-php-1. ein Android-Gerat. weil der anfängliche Cache aufgebaut wird. ersetzen Sie /Users/NAME/src/wurfl-php-1. $wurflConfigFile = RESOURCES_DIR .1/").". width=device-width" /> <title>WURFL Test</title> <?php define("WURFL_DIR". ’Application. Websites oder public_html) die folgende PHP-Datei (nennen Sie sie beispielsweise wurfl-test. } ?> </ul> </body> </html> Ich konnte ~ nicht nutzen.xml’. Jetzt können Sie diesen PHP-Code Ihren Bedürfnissen gemäß anpassen: <html> <head> <meta name="viewport" content="user-scalable=no. Danach sollte das Skript zügig ablaufen.1/WURFL/"). if ($requestingDevice->getCapability("device_os") == "Android") { $is_android = TRUE. Beim ersten Besuch. $requestingDevice = $wurflManager->getDeviceForHttpRequest($_SERVER). $wurflManagerFactory = new WURFL_WURFLManagerFactory($wurflConfig). $wurflInfo = $wurflManager->getWURFLInfo(). wie das in Ihrem Browser aussehen sollte.1/ durch den vollständigen Pfad zum zuvor erstellten wurfl-php-Verzeichnis. musste also den vollständigen Pfad zum WURFLKram angeben. $wurflConfig = new WURFL_Configuration_XmlConfig($wurflConfigFile). "/Users/bjepson/src/wurfl-php-1. ¨ } ?> <ul> <?php foreach ($requestingDevice->getAllCapabilities() as $key => $value) { echo "<li>$key = $value".php). require_once WURFL_DIR .php’. den Sie dieser Seite mit Ihrem Android-Gerät (oder einem anderen Browser) abstatten. } ?> </head> <body> <?php if ($is_android) { echo "Aha. define("RESOURCES_DIR".B. Abbildung A-1 zeigt. $wurflManager = $wurflManagerFactory->create(). $is_android = FALSE. wurfl-php testen | 157 . ’wurfl-config.

Abbildung A-1: Ausgabe des »wurfl-php«-Beispielskripts 158 | Anhang: Browsererkennung mit WURFL .

Fortschrittsanzeige 40 Android-Gerät Apps testen 13 KiloGap installieren 131 mit JavaScript steuern 132 Seitenskalierung steuern 19 Standardvergrößerungsstufe 19 wenig bekannte Funktionen 2 Anfragen steuern 37 anhängende Ellipse 43 Animationen jQTouch-Bibliothek und 55. logisch 10 Attribute (HTML) angepasste Selektoren und 7 Definition 4 automatisch zum Seitenanfang scrollen 45 B background-color-Eigenschaft 7 backSelector-Eigenschaft 70 beep-Funktion 132 BEGIN-Anweisung 94 Beschleunigungsensor 142 Block-Tags (HTML) 4 Body-Element CSS-Darstellung 6 Padding-Probleme 23 PhoneGap-Beispiel 129 border-width-Eigenschaft 27. 69 Kalorienzähler-App erstellen 55 Kalorienzähler-App.Index Symbole : (Doppelpunkt) 98. 120 $ (Shell-Prompt) 108 / (Schrägstrich) 3. (Punkt) 7. 134 Apache Ant 123 Apps testen Chrome 6. 120 {} (geschweifte Klammern) 6. 10 . (Semikolon) 10. 105 = (Gleichheitszeichen) 10 # (Doppelkreuzzeichen) 6–7 | (Pipe) 43 + (Pluszeichen) 10 . 28 Fortschrittsanzeige 40 Hosting 13 Apps versionieren 146 Äquivalenzoperator. 18. Code 67 anonyme Funktionen 48. 49 Browser siehe spezifische Browser C Cache-Manifest-Datei absolute URLs und 96 Index | 159 . HTML) 4 Abbrechen-Button 63 absolute URLs 96 :active-Pseudoklasse 51 adb-Tool 128 addGlossToIcon-Eigenschaft 70 Ajax (Asynchronous JavaScript and XML) Definition 33 Stellwerkseite 34 alert-Funktion 132 Alpha-Wert (Farbe) 27 Android Market App hochladen auf 149 Apps direkt verteilen 151 Release-Version einer App 145 Android SDK herunterladen 115 weitere Lektüre 152 Android-Emulator erstellen 121 gesamte Bildschirmhöhe 129 KiloGap installieren 126 Symbol anpassen 130 Testen. 105 A a-Tag (Anker.

134. 88. 133 F fadeSelector-Eigenschaft 70 FALLBACK:-Schlüsselwort 98 Farbcode-Notation (HTML) 6 Fehlerbehandlung Einfügen von Zeilen 85 Web SQL Database 85. Notation 10 Eigenschaften. HTML) 4 emacs (Texteditor) 5 End-Tag (HTML) 3 entryClickHandler()-Funktion 140 Ergebnismengen verarbeiten 86 errorHandler()-Funktion 85 executeSql()-Methode 84. Douglas 38 CSS (Cascading Style Sheets) 13 anhängende Ellipse 43 Einführung 6 hinzufügen 20 Look-and-Feel ergänzen 23 Stylesheets anwenden 8 cubeSelector-Eigenschaft 70 Debugging 108 Debugging-Code entfernen 145 JavaScript-Konsole 108 Offline Application Cache 107 Deckkraft (Farbe) 27 deleteEntryById()-Funktion 91 digitale Signaturen 146 dissolveSelector-Eigenschaft 70 Document Object Model (DOM) 10 Document-Ready-Funktion 29. 136 createEntry()-Funktion 83. anhängende 43 em-Tag (Hervorhebung.dynamische erstellen 101 elementarer Überblick 95 Syntaxfehler und 109 cacheGetRequests-Eigenschaft 70 Cascading Style Sheets siehe CSS checkBudget()-Funktion 133 Chrome-Browser Apps testen 6 clientseitige Datenbanken und 82 Entwicklertools 83 Testüberlegungen 18.changeVersion()-Methode 94 Datenbanken Ergebnismengen verarbeiten 86 erstellen 80 Zeilen auswählen 86 Zeilen einfügen 83 Zeilen löschen 90 Datenspeicherung Fehlercode-Referenz 94 Web SQL Database 79 Web Storage 73 160 | Index .changeVersion()-Methode 94 DATABASE_ERR-Fehlercode 94 DatabaseSync. Vergleich 8 Kalorienzähler-App 64 click()-Funktion 78. 94 :first-child-Pseudoklasse 25 fixedViewport-Eigenschaft 70 flipSelector-Eigenschaft 70 font-weight-Eigenschaft 49 formSelector-Eigenschaft 70 Fortschrittsanzeige 39 fullScreen-Eigenschaft 71 fullScreenClass-Eigenschaft 71 D Database. 28 class-Attribut angepasste Selektoren und 7 id-Attribut. 137 Crockford. 120 Droid-Schriftfamilie 21 droidgap-App 123 DRY-Akronym 17 dupeEntryById()-Funktion 144 E E Text Editor 5 eckige Klammern. 90 Click-Handler 38 clone()-Funktion 88 color-Eigenschaft Beispiel 6 Zurück-Button 49 COMMIT-Anweisung 94 CONSTRAINT_ERR-Fehlercode 94 CREATE TABLE-Anweisung 82. 37 DOM (Document Object Model) 10 Doppelkreuzzeichen (#) 6–7 Doppelpunkt (:) 98. CSS 6 Einrücken von Text 22 Ellipse.

37 Einführung 11 Fortschrittsanzeige 39 goBack()-Funktion 75 gt()-Funktion 87 Kalorienzähler-App 58 load()-Funktion 37 Onclick-Aktionen kapern 34 Seitentitel festlegen 41 slideUp()-Methode 91 toggleClass()-Funktion 30 val()-Funktion 75 Index | 161 . alert()-Funktionen 132 Beschleunigungssensor 142 Debugging 108 Einführung 9 Geolocation 136 Geräte steuern 132 Syntax 10 jQTouch-Bibliothek Abbrechen-Button 63 anpassen 69 Benutzereinstellungen speichern 76 Browser-Toolbar und 129 Einführung 55 goTo()-Methode 141 Kalorienzähler-App 57 jQuery-Bibliothek click()-Funktion 78. 137 insertEntry()-Funktion 137 Internet Explorer-Browser 18 Internet Information Services (IIS) 14 Internet Service Provider (ISP) 13 ipfw-Befehl 40 ISP (Internet Service Provider) 13 H h1-Tags (HTML) Text einbetten in 3 herunterladen Android SDK 115 PhoneGap-Entwicklungswerkzeug 118 hexadezimale Notation 6 hijackLinks()-Funktion 37. Einrichtung 13 :hover-Pseudoklasse 51 href-Attribut absoluter Pfad. Beispiel 8 Funktion 4 relative Pfade. Beispiel 8 .htaccess-Datei 96–97 HTML 13 Einführung 3 Kalorienzähler-App 56 Web SQL Database-Spezifikation und 79 html-Element Funktion 4 manifest-Attribut 96 HTML-Farbcode-Notation 6 HTML-Tags CSS-Formatierung 7 Hyperlinks und 4 übliche Struktur 3 unterstützte Kategorien 4 Hunt. Symbole hinzufügen zu 53 Hosting. 48 Home-Screen. vibrate()-. Andrew 17 Hyperlinks CSS-Formatierung 7 HTML-Tags 4 lokale abfangen 45 J JAVA_HOME-Umgebungsvariable 115 JavaScript 108 Anfragesteuerung 37 beep()-.html-Seite 95 Inline-Tags (HTML) 4 innerWidth-Eigenschaft (window) 28 INSERT-Anweisung 94.G gedit (Texteditor) 5 Geolocation 136 Geräteemulator siehe Android-Emulator geschweifte Klammern {} 6. 10 getCurrentPosition()-Funktion 137 getDate()-Funktion 78 getFilename-Funktion 105 getMonth()-Methode 78 Gleichheitszeichen (=) 10 goBack()-Funktion 75 Google Goggles 151 goTo()-Methode 141 Gradienten (CSS) 24 gt()-Funktion 87 I icon-Eigenschaft 71 id-Attribut 7–8 IF NOT EXISTS-Klausel 82 IIS (Internet Information Services) 14 !important-Direktive 129 index. 90 Document-Ready-Funktion 29.

120 native Apps 123 Entwicklung. Fortschrittsanzeige 40 Texteditor 5 Umgebungsvariablen 120 Webserver-Unterstützung 14 Manifest-Datei siehe Cache-Manifest-Datei max-device-width-Eigenschaft 18 max-width-Eigenschaft 18. 131 Kommandozeilenumgebung 114 L :last-child-Pseudoklasse 25 Lesezeichen für Apps 53 li-Tag (Listenelement.Verhalten gestalten 25 Zurück-Button 51 M Mac-Betriebssystem Android SDK herunterladen 115 Apache Ant-Unterstützung 123 Chrome-Browser 6 Debugging 108 . Fortschrittsanzeige 40 Texteditor 5 Umgebungsvariablen 120 Webserver-Unterstützung 14 load()-Funktion 37 loadPage()-Funktion Anfragesteuerung 37 automatisch an Anfang scrollen 45 Zurück-Button 48 loadSettings()-Funktion 76 localStorage-Attribut Benutzereinstellungen speichern 74 Funktionalität 73 PhoneGap-Beispiel 133 logEvent-Funktion 109 Logo-Link 21 Löschen von Zeilen 90 162 | Index N nano (Texteditor) 5. 77 Tage-Seite 59.htaccess-Datei und 97 PHP-Skripten ausführen 102 Terminal-Anwendung 114 Testen. 49 md5_file-Funktion 107 Meyer. Vor-/Nachteile 2 Merkmale 1 richtigen Ansatz wählen 2 Navigation erstellen 21 Menüs abgerundete Ecken geben 24 Zurück-Button 46 -netspeed-Kommandozeilenoption 40 NETWORK:-Schlüsselwort 98 Nitobi-Entwicklungswerkzeuge 113. 45. Eric 9 MIME-Typen 96 min-device-width-Eigenschaft 18 min-width-Eigenschaft 18 K Kalorienzähler-App Einstellungen-Seite 65. HTML) Beispiel 3 Pseudoclasses und 25 line-height-Eigenschaft 49 Linux-Betriebssystem Android SDK herunterladen 115 Apache Ant-Unterstützung 123 Debugging 108 Kommandozeilenunterstützung 114 PHP-Skripten ausführen 102 Testen. David 55 keytool-Befehl 148 Kilo-App siehe Kalorienzähler-App KiloGap-App erstellen 123 installieren 126. 49 . 74 Info-Seite 59 Neuer Eintrag-Seite 61 Startseite 55 Tag-Seite 61. 77 vollständiger HTML-Code 67 Kaneda. 123 Notepad 5 O Offline Application Cache Debugging 107 Definition 95 dynamische Manifest-Datei erstellen 101 elementarer Überblick 95 Whitelisting und 98 onclick-Attribut Aktionen abfangen 34 JavaScript-Beispiel 11 overflow-Eigenschaft 45.

105 Schriften.) 10.P p-Tag (HTML-Absatz-Tag) 3 Padding. 120 sessionStorage-Attribut ausgewähltes Datum speichern 77 currentDate-Wert 78. 119–120 PhoneGap-Entwicklungswerkzeug Android SDK herunterladen 115 beep()-. vibrate()-. 84. 87 Funktionalität 73 PhoneGap-Beispiel 133 setDate()-Funktion 78 Shell-Prompt ($) 108 Skripten ausführen 102 slideInSelector-Eigenschaft 71 slideUp()-Methode 91 slideupSelector-Eigenschaft 71 Speicherung Fehlercode-Referenz 94 Web SQL Database 79 Web Storage 73 Start-Tag (HTML) 3–4 Starter-Symbole 53 startupScreen-Eigenschaft 71 startWatchingShake()-Funktion 143 statusBar-Eigenschaft 72 stopPropagation()-Methode 140 stopWatchingShake()-Funktion 143 String-Verkettungsoperator 10 Stylen von HTML-Seiten Ajax 33–34 automatisch zum Seitenanfang scrollen 45 CSS einbinden 20 erste Schritte 14 Fortschrittsanzeige 39 jQuery-Unterstützung 25 Q QR-Code 151 QUOTA_ERR-Fehlercode 94 R refreshEntries()-Funktion Funktion 78 PhoneGap-Beispiel 139. alert()-Funktionen 132 Beschleunigungssensor-App 142 Einführung 113 Geolocation-App 136 Geräte mit JavaScript steuern 132 herunterladen 118 KiloGap erstellen 123 KiloGap installieren 126. Inhalt hinzufügen 22 pageAnimationBegin-Event 143 pageAnimationEnd-Event 143 PATH-Umgebungsvariable 115. 142 Zeilen auswählen 86 Zeilen einfügen 85 Zeilen löschen 90 reguläre Ausdrücke 46 REPLACE-Anweisung 94 Reverse Domain Name-Syntax 124 RhoMobile-Projekt 114 Rich-Text-Editing 5 Index | 163 . mobile Geräte 21 script-Element 108 scrollTo()-Befehl 45 Seitenskalierung steuern 19 Seitentitel festlegen 41 SELECT-Anweisung 142 Selektoren (CSS) Definition 6 Hyperlink-Beispiel 7 Navigation aufbauen 21 Pseudoklassen und 25 Semikolon (. 105 ROLLBACK-Anweisung 94 Ruby-Sprache 120 S saveSettings()-Funktion 75–76 Schrägstrich (/) 3.) 7. 131 Umgebung einrichten 119 virtuelles Android-Gerät erstellen 121 PHP-Skriptsprache Hosting-Überlegungen 13 md5_file-Funktion 107 MIME-Typen und 96 Skripten ausführen 102 pico-Editor 97 Pipe (|) 43 Pluszeichen (+) 10 popSelector-Eigenschaft 71 preloadImages-Eigenschaft 71 Premium-Modell 2 preventDefault()-Methode (Event) 38 Pseudoklassen 25 Punkt (.

49 TextEdit 5 Texteditor. auswählen 5 TextMate (text editor) 5 Thomas. HTML) Elemente verbergen 26 164 | Index . 77. 52 -webkit-border-radius-Eigenschaft 24 -webkit-gradient()-Funktion 24 -webkit-tap-highlight-color-Eigenschaft 51 U Überschriften-Tags (HTML) Hyperlink-Beispiel 7 ul-Tag (ungeordnete Liste. 94 Funktionalität 79 Zeilen auswählen 86 Zeilen einfügen 83 Zeilen löschen 90 Web Storage Funktionalität 73 localStorage-Attribut 73–74. David 17 TIMEOUT_ERR-Fehlercode 94 Titanium Mobile-Projekt 114 Titelleiste. 133 sessionStorage-Attribut 73. Vor-/Nachteile 2 Kennzeichen von 1 richtigen Ansatz wählen 2 Webbrowser siehe spezifische Browser WebChromeClient-Klasse 154 -webkit-border-image-Eigenschaft 27. 49 text-shadow-Eigenschaft 23. klickbare 21 title-Element 5 toggleClass()-Funktion 30 toggleMenu()-Funktion 30 TOO_LARGE_ERR-Fehlercode 94 Traffic Cop-App 34 typeof-Operator 129 W Web SQL Database Datenbanken erstellen 80 Ergebnismengen verarbeiten 86 Fehlercode-Referenz 85. 84. 133 Web-Apps 95 Entwicklung. 119 UNKNOWN_ERR-Fehlercode 94 UPDATE-Anweisung 94 updateready-Event 97 url. 87.match-Function 46 useAnimations-Eigenschaft 72 V val()-Funktion 75 var-Schlüsselwort 10 Variablen deklarieren 10 Umgebung 115. 28 Fortschrittsanzeige 40 Hosting 13 Text einrücken 22 Text Wrangler (Texteditor) 5 text-align-Eigenschaft 49 text-overflow-Eigenschaft 45. 18. 49. Standard 19 Verkettungsoperator 10 VERSION_ERR-Fehlercode 94 Versionieren von Apps 146 vi (Texteditor) 5 vibrate-Funktion 132 viewport-Meta-Tag 19 virtuelle Geräte siehe Android-Emulator T Testen von Apps Chrome 6.lange Titel bewältigen 43 lokale Links abfangen 45 Look-and-Feel ergänzen 23 Seitenskalierung steuern 19 Seitentitel festlegen 41 seitenweite Styles definieren 20 Stellwerkseite 34 Stylesheets vorbereiten 17 Symbole zu Home-Screens hinzufügen 53 Testüberlegungen 13 Zurück-Button 46 Stylesheets anwenden 8 vorbereiten 17 submitSelector-Eigenschaft 72 swapSelector-Eigenschaft 72 Symbole anpassen 130 zu Home-Screens hinzufügen 53 SYNTAX_ERR-Fehlercode 94 Funktionalität 3 Navigation aufbauen 21 Pseudoclasses und 25 Umgebungsvariablen 115. 119 Vergrößerungsstufe.

Fortschrittsanzeige 40 Texteditoren 5 Umgebungsvariablen 120 Webserver-Unterstützung 14 Wireless Universal Resource File (WURFL) 18. 155 WordPad 5 WURFL (Wireless Universal Resource File) 18.Webprogrammierung CSS-Einführung 6 HTML-Einführung 3 JavaScript-Einführung 9 Webserver Hosting-Überlegungen 13 Log-Dateien überwachen 108 lokal ausführen 14 PHP-Skripten ausführen 102 WebSettings-Klasse 154 WebView-Klasse 154 WebViewClient-Klasse 154 white-space-Eigenschaft 45. 155 Z Zeilen auswählen 86 einfügen 83 löschen 90 Zeldman. Jeffrey 17 Zurück-Button 46 Zuweisungsoperator 10 Index | 165 . 49 Whitelisting 98 window-Objekt applicationCache-Eigenschaft 97 innerWidth-Eigenschaft 28 Windows-Betriebssystem Android SDK herunterladen 115 Apache Ant-Unterstützung 123 Chrome-Browser 6 Eingabeaufforderung 114 PHP-Skripten ausführen 102 Testen.

.

ist es eigenständig und bereits flugfähig. legt das Hammerhuhn seine Eier in ein Loch im Sand. ist technischer Redakteur für php|architect und Advisor. wo sie durch die Sonne. Die Eier des Hammerhuhns sind rund fünfmal so groß wie Hühnereier und deswegen ein beliebter Bestandteil der lokalen Speisekarte. Die Liste der Dinge. Das Wall Street Journal bezeichnete ihn als Experten auf dem Gebiet der Aufbereitung von allen möglichen Daten für das Web. seltene Vogel ist ungefähr so groß wie ein ausgewachsenes Haushuhn. Die Schrift auf der Titelseite ist Adobe ITC Garamond. dass die Tiere kräftige Beine und große Köpfe haben.und Brustfedern. Eigentlich hat er mal Philosophie studiert. Kolophon Das Tier auf der Titelseite von Android Apps mit HTML. um die Bekanntheit der kontinuierlich schrumpfenden Art zu steigern und die Vögel vor menschlichen Eiersammlern zu schützen. da Windows laufen lernte.Über den Autor Jonathan Stark ist ein renommierter Berater für die Entwicklung von Web. Das Titelbild stammt aus Cassells Natural History. Ihre geneigte Stirn wird häufig als »helmförmig« bezeichnet. . Er hat schon zwei Bücher über Webentwicklung geschrieben.com und wird in den Medien immer wieder gern zu Web. Das vielleicht erstaunlichste Kennzeichen dieses monogamen Vogels ist sein Brutverhalten.und Lifestylefragen zitiert. die ihre Eier selbst bebrüten. CSS und JavaScript ist ein Hammerhuhn (Macrocephalon maleo). Wenn das Hammerhuhnküken schlüpft und nach zwei bis drei Monaten Brutdauer das Sandloch verlässt. Hammerhühner brüten gemeinsam – wahrscheinlich als Schutzmaßnahme vor Eierräubern. eine bedrohte Vogelart. launenhaft und heterogen wie die seiner Lieblingsessen und Lieblingsbücher. die Überschriftenschrift ist Adobe Myriad Condensed. Der wissenschaftliche Name des Hammerhuhns weist darauf hin. mit denen er sich beschäftigt. Er hat weiße und hellrosa Bauch. die sich deutlich von den schwarzen Federn des Rückens und der Flügel abheben. um sich vor Räubern zu verbergen und auf Nahrungssuche zu gehen. und die Codeschrift ist LucasFonts TheSansMonoCondensed. was man mit Computern so anstellen kann. Über den Übersetzer Lars Schulten ist freier Übersetzer für IT-Fachliteratur und hat für den O’Reilly Verlag schon unzählige Bücher zu ungefähr allem übersetzt. aber mit Computern schlägt er sich schon seit den Zeiten herum. Die Textschrift ist Linotype Birka.000 Tieren liegt und die nur auf den indonesischen Inseln Sulawesi und Buton anzutreffen ist. deren Populationsstärke aktuell zwischen 5000 und 10. 2009 erwarb die amerikanische Wildlife Conservation Society eine 36 Hektar große Fläche der Küste von Sulawesi (die rund 40 Nester beherbergt).und mobilen Anwendungen. ist ungefähr so lang. Anders als die meisten Vögel. Dieser markante. geothermale Energie oder beides ausgebrütet werden. Es eilt selbstständig in den Wald.

Sign up to vote on this title
UsefulNot useful