Stark J. - Android. Tworzenie aplikacji w oparciu o HTML CSS i JavaScript

185 Pages • 36,261 Words • PDF • 2.1 MB
Uploaded at 2021-09-24 18:19

This document was submitted by our user and they confirm that they have the consent to share it. Assuming that you are writer or own the copyright of this document, report to us by using this DMCA report button.


Ebookpoint.pl kopia dla: Rodenko David [email protected]

Spis treści Wprowadzenie ................................................................................9 1. Zaczynamy ..................................................................................... 13 Aplikacje internetowe kontra aplikacje natywne Czym jest aplikacja internetowa? Czym jest aplikacja natywna? Wady i zalety Które podejście jest odpowiednie dla Ciebie? Ekspresowy kurs technologii internetowych Wprowadzenie do języka HTML Wprowadzenie do CSS Wprowadzenie do JavaScriptu

13 13 14 14 15 15 15 19 23

2. Praca ze stylami ............................................................................. 27 Nie masz własnej witryny? Pierwsze kroki Osobny arkusz stylów dla Androida Kontrolowanie skalowania strony Arkusz stylów dla Androida Wygląd i zachowanie w stylu Androida Proste zachowania z jQuery Czego się nauczyłeś?

27 29 33 35 36 39 41 47

3. Zaawansowane stylizowanie .......................................................49 Szczypta Ajaksa Kierowanie ruchem Przygotowanie treści Przekierowywanie żądań za pomocą JavaScriptu

49 50 52 53

5

Ebookpoint.pl kopia dla: Rodenko David [email protected]

Kilka wodotrysków Wskaźnik postępu Ustawianie tytułu strony Obsługa długich tytułów Automatyczne przewijanie do początku strony Przechwytywanie odsyłaczy lokalnych Dodawanie własnego przycisku „wstecz” Dodawanie ikony do pulpitu Czego się nauczyłeś?

55 56 59 61 62 64 64 72 73

4. Animacje ........................................................................................ 75 Z niewielką pomocą naszych przyjaciół Przewijanie Ekran Terminarz Ekran Dzień Ekran Nowy wpis Ekran Ustawienia Integracja całości Dostosowywanie biblioteki jQTouch Czego się nauczyłeś?

75 76 79 82 83 86 89 92 94

5. Składowanie danych po stronie klienta .......................................95 Web Storage Zapisywanie ustawień aplikacji w localStorage Zapisywanie daty w sessionStorage Web SQL Database Tworzenie bazy danych Wstawianie wierszy Wybieranie wierszy i obsługa otrzymanych danych Usuwanie wierszy Kody błędów Web SQL Database Czego się nauczyłeś?

95 97 100 102 104 106 110 115 118 118

6. Tryb offline ...................................................................................121 Podstawy aplikacji działających offline Sekcje NETWORK i FALLBACK Dynamiczne tworzenie pliku manifestu

6



Spis treści

Ebookpoint.pl kopia dla: Rodenko David [email protected]

121 126 132

Debugowanie Konsola JavaScriptu Czego się nauczyłeś?

136 137 140

7. W stronę natywności ....................................................................141 Wprowadzenie do PhoneGap Tworzenie aplikacji z wykorzystaniem Eclipse i Android SDK Pobieranie i instalowanie środowiska Eclipse Classic Pobieranie i instalowanie Android SDK Instalowanie dodatku ADT w Eclipse Dodawanie platform Android i innych składników Pobieranie najnowszej wersji PhoneGap Tworzenie nowego projektu Uruchamianie Kilo jako aplikacji dla Androida Sterowanie telefonem z poziomu JavaScriptu Dźwięki, wibracje i ostrzeżenia Geolokalizacja Akcelerometr Czego się nauczyłeś?

141 143 143 144 144 145 146 146 148 150 151 155 162 166

8. Publikowanie aplikacji w sklepie Google Play ........................... 167 Przygotowanie aplikacji do dystrybucji Usuwanie kodu na potrzeby debugowania Nadawanie aplikacji numeru wersji Kompilowanie i podpisywanie aplikacji Przesyłanie aplikacji do sklepu Google Play Bezpośrednie dystrybuowanie aplikacji Dalsza lektura

167 167 168 169 170 172 173

Dodatek. Wykrywanie przeglądarek za pomocą WURFL ...........177 Skorowidz .................................................................................... 183

Spis treści

Ebookpoint.pl kopia dla: Rodenko David [email protected]



7

8



Spis treści

Ebookpoint.pl kopia dla: Rodenko David [email protected]

Wprowadzenie

Dzięki telefonom i urządzeniom mobilnym przenieśliśmy się ze świata, w którym nikt nie miał dostępu do informacji, do świata, w którym każdy ma na wyciągnięcie ręki ogrom zasobów internetu. To chyba największe osiągnięcie naszego pokolenia. Technologie mobilne — pomimo tego, jak są istotne — nadal tkwią jednak w okresie niemowlęcym. Ze względów technicznych, finansowych i politycznych mobilny świat jest niesamowicie podzielony, a perspektywy poprawy tego stanu rzeczy są dosyć odległe. Twórcy oprogramowania dla dużych i zróżnicowanych grup odbiorców stoją przed wyzwaniem przekraczającym możliwości zwykłych śmiertelników — jak zmaterializować swoje pomysły w sposób możliwy do zrealizowania stosunkowo małym kosztem, tak by osiągnąć produkt dostępny dla jak największej liczby użytkowników? W wielu przypadkach odpowiedzią są technologie internetowe. Powiązanie zaawansowanych możliwości HTML5 z urządzeniami mobilnymi tworzy środowisko, w którym nawet początkujący twórca może stworzyć aplikację ułatwiającą życie ludziom mieszkającym w dowolnym zakątku świata. Platforma Android firmy Google jest istotnym elementem przestrzeni mobilnych technologii. Ma wszystkie cechy charakterystyczne dla Google — jest otwarta, bezpłatna i można jej używać w wielu różnych urządzeniach. Narzędzia programistyczne są dopracowane, mają spore możliwości i działają na wielu platformach systemowych. Producenci telefonów oraz innych urządzeń mobilnych wyczuli potencjał platformy i zalali rynek przeróżnymi urządzeniami pracującymi na Androidzie. Dla twórców oprogramowania to miecz obosieczny. Z jednej strony, im więcej urządzeń, tym większy rynek zbytu. Z drugiej jednak strony, większa różnorodność urządzeń to większa fragmentacja. Podobnie jak z fragmentacją na 9

Ebookpoint.pl kopia dla: Rodenko David [email protected]

rynku urządzeń mobilnych, to rozdrobnienie w ramach samej platformy Android może stwarzać problemy, których rozwiązanie jest jedno — aplikacje tworzone w technologiach HTML, CSS i JavaScript. Z oczywistych względów nie wszystkie aplikacje mogą powstawać z wykorzystaniem technologii internetowych, ale wielokrotnie można się spotkać z aplikacjami natywnymi, które z powodzeniem można by w ten sposób wytworzyć. Jeśli masz wątpliwości, którą drogę obrać, weź pod uwagę poniższą myśl: Jeśli daną aplikację możesz zbudować w oparciu o HTML, CSS i JavaScript, najprawdopodobniej tak właśnie powinieneś zrobić. Korzystanie z otwartych, ustandaryzowanych technologii internetowych daje niezwykłą elastyczność, szeroki zasięg i niskie koszty. Możesz zacząć od utworzenia aplikacji internetowej, i publikując ją w internecie, przetestować w rzeczywistych warunkach. Następnie dzięki PhoneGap możesz ją przerobić na natywną aplikację dla Androida, dodać kilka typowo sprzętowych funkcji, a potem opublikować w sklepie Google Play lub udostępnić do pobrania ze strony. Brzmi nieźle, prawda?

Kto powinien przeczytać tę książkę? Zakładamy, że masz przynajmniej podstawowe doświadczenie w technologiach HTML, CSS i JavaScript (a w szczególności w jQuery). W rozdziale 5. pojawia się kod SQL, więc znajomość składni SQL może być przydatna, choć nie jest obowiązkowa.

Co Ci będzie potrzebne? W książce staramy się unikać stosowania narzędzi Android SDK na tyle, na ile jest to możliwe. Wszystko, czego potrzebujesz, by wykonać większość ćwiczeń, to któryś z edytorów tekstu dla programistów oraz najnowsza wersja przeglądarki Google Chrome (jedna z lepszych przeglądarek; jest dostępna dla systemów Mac OS, Linux i Windows — http://www.google.com/chrome). Podczas pracy nad zagadnieniami z rozdziału 7. niezbędne jest zainstalowanie Android SDK na potrzeby PhoneGap, ponieważ zamieniamy tam aplikację internetową na natywną, którą można umieścić w sklepie Google Play.

10



Wprowadzenie

Ebookpoint.pl kopia dla: Rodenko David [email protected]

Przyjęte konwencje W książce stosowane są następujące konwencje typograficzne: Kursywa W ten sposób wyróżniamy nowe terminy, adresy URL, nazwy i rozszerzenia plików. Stała szerokość

Styl stosowany w blokach listingów oraz w tekście do elementów odnoszących się do kodu programu, takich jak nazwy zmiennych i funkcji, bazy danych, typy danych, instrukcje i słowa kluczowe. W ten sam sposób oznaczane są polecenia i teksty, które powinny zostać wprowadzone przez czytelnika.

Stała szerokość z pogrubieniem

W listingach oznaczamy w ten sposób nowe lub zmienione fragmenty. Ta ikona oznacza wskazówkę, sugestię lub ogólną uwagę.

Taką ikoną są oznaczane ostrzeżenia.

Korzystanie z kodu przykładów Książka ma na celu ułatwienie Ci wykonania pewnej pracy. Kod zawarty w książce możesz wykorzystać we własnych programach i dokumentacji. Nie musisz się kontaktować z wydawnictwem w celu uzyskania zgody, chyba że powielasz znaczną część kodu. Przykładowo pisanie programu, w którym używasz kilku fragmentów kodu z książki, nie wymaga zgody wydawnictwa, jednak zgoda ta jest potrzebna w przypadku sprzedaży lub dystrybucji nośników z przykładami z tej książki. Udzielenie odpowiedzi na pytanie z dołączeniem cytatu z książki nie wymaga zgody. Zgoda jest niezbędna, jeśli w dokumentacji własnego produktu umieścisz znaczną ilość kodu z książki.

Korzystanie z kodu przykładów

Ebookpoint.pl kopia dla: Rodenko David [email protected]



11

Wzmianka o twórcach kodu jest mile widziana, ale nie jest konieczna. Informacja taka zwykle uwzględnia autora, tytuł, wydawnictwo oraz miejsce i rok wydania. Na przykład: Jonathan Stark: Android. Tworzenie aplikacji w oparciu o HTML, CSS i JavaScript. Helion, Gliwice 2013. Jeśli uznasz, że sposób użycia przykładowych kodów wykracza poza opisane wyżej przypadki, powinieneś się skontaktować z wydawnictwem ([email protected]).

Podziękowania Pisanie książki to praca zespołowa. Dziękuję zatem wielu osobom, które przyczyniły się do jej powstania: Timowi O’Reilly’emu, Brianowi Jepsonowi i reszcie zespołu wydawnictwa O’Reilly Media, dzięki którym praca nad książką dała mi tak wiele satysfakcji i poszerzyła moje horyzonty. Davidowi Kanedzie za jego cudowną, obsesyjną wręcz pogoń za doskonałością. Nie ma szans, by David spokojnie zasnął, gdy jakiś fragment kodu lub animacja nie są dopieszczone w najmniejszych szczegółach. Zespołowi firmy Nitobi za stworzenie i ciągłe rozwijanie biblioteki PhoneGap. Brianowi Flingowi za uzmysłowienie mi, że świat mobilnych technologii nie kończy się na najnowszych i najlepszych urządzeniach. Brian zna ten świat od jego początków, doskonale pisze, a przede wszystkim ma wielkie serce. PPK, Johnowi Gruberowi, Johnowi Allsoppowi i Johnowi Resigowi za ich wkład w sprawy technologii, dzięki którym ta książka mogła powstać. Joemu Bowserowi, Brianowi LeRoux, Sarze Czyzewicz oraz rzeszy osób, które umieszczały komentarze i pytania na stronie internetowej tej książki. Wasz wkład jest nieoceniony. Mojej cudownej rodzinie, przyjaciołom oraz klientom, którzy wykazali się niezwykłym zrozumieniem i okazywali wsparcie przez cały czas, gdy byłem przykuty do klawiatury. Erice. Przy Tobie wszystko jest możliwe. Kocham Cię!

12



Wprowadzenie

Ebookpoint.pl kopia dla: Rodenko David [email protected]

ROZDZIAŁ 1.

Zaczynamy

Przed rozpoczęciem prawdziwych zmagań powinniśmy poznać pole walki. W tym rozdziale zaznajomisz się z definicjami kluczowych pojęć, a także poznasz wady i zalety dwóch głównych podejść do tworzenia aplikacji. Będziesz miał również szansę przejść ekspresowy kurs trzech podstawowych technologii wykorzystywanych w książce.

Aplikacje internetowe kontra aplikacje natywne Zaczniemy od zdefiniowania pojęć aplikacja internetowa i aplikacja natywna oraz wskażemy ich wady i zalety.

Czym jest aplikacja internetowa? W naszym odczuciu aplikacja internetowa jest witryną internetową dostosowaną do specyfiki urządzeń mobilnych. Tematyka takiej witryny może być dowolna — nie ma znaczenia, czy to będzie wizytówka firmy, kalkulator kredytowy, czy wirtualny asystent odchudzania. Aplikacje internetowe cechują się tym, że ich interfejs użytkownika (UI) jest zbudowany za pomocą standardowych technologii webowych, są dostępne pod określonym adresem URL (publicznie lub prywatnie, a także z możliwością logowania), oraz są zoptymalizowane pod kątem specyfiki urządzeń mobilnych. Aplikacje internetowe nie są instalowane na telefonach czy tabletach, nie są dostępne w sklepie z aplikacjami oraz nie są napisane w Javie.

13

Ebookpoint.pl kopia dla: Rodenko David [email protected]

Czym jest aplikacja natywna? Z kolei aplikacje natywne są instalowane na urządzeniu, mają dostęp do sprzętu (głośników, akcelerometru, kamery itp.) oraz są napisane w Javie. Poza tymich cechą charakterystyczną jest to, że są dostępne w sklepie z aplikacjami (Google Play), czyli miejscu, gdzie można znaleźć produkty wyobraźni programistów z całego świata.

Wady i zalety Różne aplikacje mają różne wymagania. Niektóre lepiej pasują do świata technologii internetowych, a inne gorzej. Dzięki temu, że poznasz zalety i wady każdego z tych podejść, łatwiej Ci będzie podejmować decyzje w konkretnych sytuacjach. Spójrzmy na dwie podstawowe zalety tworzenia aplikacji natywnych:  Miliony właścicieli kart kredytowych są w zasięgu zaledwie jednego

kliknięcia.  Masz dostęp do wszystkich sprzętowych możliwości urządzeń.

A oto wady tego podejścia:  Jeśli chcesz umieszczać natywne aplikacje dla Androida w sklepie

Google Play, musisz ponieść pewne koszty.  Twoje aplikacje będą działały tylko na urządzeniach z Androidem.  Musisz programować w Javie.  Cykl produkcji oprogramowania jest długi (programowanie, kompilowa-

nie, instalowanie — i tak w kółko). Tworzenie aplikacji internetowych ma kilka ciekawych zalet:  Twórcy stron internetowych mogą używać dotychczasowych narzędzi.  Możesz korzystać ze swoich doświadczeń i umiejętności związanych

z projektowaniem stron internetowych.  Twoje aplikacje będą działały na wszystkich urządzeniach posiadających

przeglądarkę internetową.  Błędy możesz poprawiać w dowolnej chwili.  Cykl produkcji oprogramowania jest krótki.

14



Rozdział 1. Zaczynamy

Ebookpoint.pl kopia dla: Rodenko David [email protected]

To rozwiązanie ma jednak też wady:  Nie masz dostępu do wszystkich możliwości sprzętowych urządzeń.  Jeśli chcesz zarabiać na aplikacjach, sam musisz zorganizować system

płatności.  Możesz mieć problemy z osiągnięciem zaawansowanych efektów interfejsu

użytkownika.

Które podejście jest odpowiednie dla Ciebie? I tu zaczyna się robić ciekawie. Sieciowa natura urządzeń z Androidem powoduje, że zaciera się granica między aplikacjami internetowymi i natywnymi. Coraz więcej przeglądarek (w tym również w Androidzie) ma pewną na razie mało znaną cechę, która umożliwia uruchamianie aplikacji internetowych w trybie offline (patrz rozdział 6.). Co więcej, obecnie jest rozwijanych wiele projektów — z których PhoneGap jest najbardziej znanym — umożliwiających konwertowanie aplikacji internetowych na natywne dla Androida i kilku innych mobilnych platform. To brzmi fantastycznie. Możemy tworzyć w oparciu o ulubione technologie i języki programowania, dostarczając czyste aplikacje internetowe (dla Androida i wszelkich innych urządzeń posiadających nowoczesną przeglądarkę), a dodatkowo — na bazie tego samego kodu — wypuszczać rozszerzone, bo mające dostęp do sprzętowych funkcjonalności urządzeń, natywne wersje tych aplikacji, które można sprzedawać w sklepie Google Play. Doskonale odpowiada to modelowi „freemium” — dostęp do aplikacji internetowej jest bezpłatny, ale jej rozszerzona wersja natywna jest już płatna.

Ekspresowy kurs technologii internetowych Trzy główne technologie używane podczas tworzenia aplikacji internetowych to: HTML, CSS i JavaScript. Omówimy pokrótce każdą z nich, aby zapewnić podstawę do dalszych, o wiele ciekawszych działań.

Wprowadzenie do języka HTML Strony, które wyświetlasz podczas przeglądania internetu, są niczym innym jak dokumentami tekstowymi umieszczonymi na innych komputerach. Zawartość typowej strony jest umieszczona w znacznikach języka HTML, które

Ekspresowy kurs technologii internetowych

Ebookpoint.pl kopia dla: Rodenko David [email protected]



15

informują przeglądarkę o strukturze dokumentu. Dzięki temu przeglądarka wie, jak wyświetlić ten dokument, by miał odpowiednią formę. Spójrz na fragment kodu zamieszczony w przykładzie 1.1. W pierwszym wierszu tekst Cześć! jest umieszczony w parze znaczników h1. Zwróć uwagę na różnicę między znacznikiem otwierającym i znacznikiem zamykającym: ten ostatni ma — jako drugi znak — dodatkowy symbol ukośnika (/). Umieszczenie tekstu w znaczniku h1 informuje przeglądarkę, że jest to nagłówek, w związku z czym zostanie on wyświetlony w odrębnym wierszu pogrubioną i większą czcionką. Poza h1 istnieją jeszcze nagłówki h2, h3, h4, h5 i h6. Liczba po h określa poziom nagłówka — im mniejsza, tym nagłówek jest ważniejszy, za czym idzie standardowe formatowanie stosowane w przeglądarkach, czyli nagłówek h6 będzie mniejszy (a więc i mniej ważny) niż na przykład h3. Na listingu 1.1 pod wierszem ze znacznikiem h1 znajdują się dwie linie tekstu umieszczone w znacznikach p, czyli akapitach. W przeglądarce każdy z tych akapitów zostanie wyświetlony w osobnym wierszu. Jeśli długość tekstu w jakimś akapicie przekroczy szerokość strony, tekst zostanie podzielony na wiele wierszy. Standardowo akapity są oddzielane od siebie dodatkowym odstępem. Listing 1.1. Fragment kodu HTML Cześć! Dziękujemy za odwiedzenie naszej strony. Mamy nadzieję, że Ci się podoba.

Znaczniki HTML możesz zagnieżdżać, czyli umieszczać w innych znacznikach. Na listingu 1.2 widać znacznik nieuporządkowanej listy (ul) zawierający trzy pozycje listy (li). W przeglądarce pojawi się w postaci wypunktowanej listy, a każda pozycja znajdzie się w osobnym wierszu. Zagnieżdżone znaczniki nazywa się elementami potomnymi lub dziećmi elementu rodzica. W omawianym przykładzie znaczniki li są zatem potomkami rodzica ul. Listing 1.2. Nieuporządkowana lista Pizza Piwo Hot dog

Omówione do tej pory znaczniki należą do grupy znaczników blokowych. Ich cechą charakterystyczną jest to, że są wyświetlane w osobnych wierszach i nie sąsiadują z innymi elementami, ani po lewej stronie, ani po prawej. 16



Rozdział 1. Zaczynamy

Ebookpoint.pl kopia dla: Rodenko David [email protected]

To dlatego nagłówek, akapity i pozycje listy są rozmieszczane w dół strony, a nie w poprzek. Przeciwieństwem znaczników blokowych są znaczniki liniowe (ang. inline), które — jak wynika z nazwy — mogą być wyświetlane w jednej linii. Przykładem takiego znacznika jest na przykład emfaza (em): Mamy nadzieję, że Ci się naprawdę podoba.

Jednym z ważniejszych w języku HTML znaczników liniowych jest a. Jego nazwa pochodzi od angielskiego słowa „anchor”, które oznacza kotwicę. Obecnie częściej mówi się jednak o odsyłaczach, hiperłączach albo linkach. Zawartość takiego znacznika można kliknąć, co powoduje przejście przeglądarki we wskazane miejsce (na przykład na inną stronę). Aby wskazać adres tego miejsca, do znacznika musimy dodać odpowiedni atrybut. Atrybuty umieszcza się w znaczniku otwierającym. W przypadku znacznika a użyjemy atrybutu href, który oznacza adres elementu docelowego hiperłącza. Przykładowy odsyłacz do strony głównej Google wygląda następująco: Google

Jeśli nie miałeś jeszcze styczności z językiem HTML, taki zapis może Ci się wydać mało czytelny, ale z pewnością umiesz z niego wyłowić adres Google. W tej książce wielokrotnie spotkasz się ze znacznikiem a i atrybutem href, więc jeśli nie wszystko jest dla Ciebie jasne, poświęć chwilę na dokładną analizę tego przykładu. Z atrybutami jest związanych kilka spraw. Przede wszystkim poszczególne znaczniki HTML przyjmują różne atrybuty. Do znacznika otwierającego możesz dodać wiele atrybutów, rozdzielając je spacjami. Nigdy nie możesz dodawać atrybutów do znaczników zamykających. Są tysiące kombinacji atrybutów i znaczników, ale nie martw się na zapas — w przykładach z książki znajdziesz tylko kilkanaście możliwości.

Omówione fragmenty kodu powinny się znaleźć w sekcji body dokumentu HTML. Każdy dokument składa się z dwóch sekcji: nagłówka (head) i ciała (body). W ciele umieszcza się całą zawartość, która ma zostać wyświetlona w przeglądarce. Z kolei nagłówek zawiera informacje o stronie, z których zdecydowana większość jest niewidoczna dla użytkownika. Obie sekcje znajdują się w elemencie html. Kod prawidłowego dokumentu HTML możesz zobaczyć na listingu 1.3. W sekcji head został umieszczony na razie tylko element title, który służy do ustawienia tekstu wyświetlanego w pasku tytułowym przeglądarki. Ekspresowy kurs technologii internetowych

Ebookpoint.pl kopia dla: Rodenko David [email protected]



17

Listing 1.3. Prawidłowy dokument HTML Moja wspaniała strona Cześć! Dziękujemy za odwiedzenie naszej strony. Mamy nadzieję, że Ci się podoba. Pizza Piwo Hot dog

Zazwyczaj w przeglądarce internetowej wyświetlasz strony znajdujące się na serwerach internetowych, ale tak naprawdę dla przeglądarek nie ma znaczenia, gdzie się znajdują wyświetlane dokumenty HTML — równie dobrze mogą pochodzić z Twojego komputera. Aby to sprawdzić, uruchom edytor tekstu i wpisz kod z listingu 1.3.

Wybór odpowiedniego edytora tekstu Nie wszystkie edytory tekstu nadają się do pracy z kodem HTML. Z całą pewnością musisz unikać edytorów tekstu takich jak Microsoft Word czy WordPad (w systemie Windows) i TextEdit (w Mac OS). Tego typu edytory zapisują dokumenty w specyficznych formatach, a nie jako czysty tekst, w związku z czym kod HTML zostałby popsuty. Jeśli już koniecznie musisz używać edytora TextEdit, podczas zapisywania koniecznie wybierz format czystego tekstu. W systemie Windows możesz, jeżeli nie masz innej możliwości, skorzystać z Notatnika. Na rynku jest dostępnych wiele dobrych edytorów nadających się do tworzenia stron. Dla systemu Mac OS polecamy TextMate (http://macromates.com/). Z kolei w systemie Windows dobrze się spisują edytory E Text Editor (http://www.e-texteditor.com/) i Sublime Text (http://www.sublimetext.com/). Jest również wiele bezpłatnych narzędzi — Text Wrangler (http://www. barebones.com/products/TextWrangler/) dla Maca, a dla systemu Windows Notepad2 (http://www.flos-freeware.ch/notepad2.html) lub Notepad++ (http://notepad-plus-plus.org/). Użytkownicy Linuksa mają na wyciągnięcie ręki całą masę dobrych edytorów, jak choćby vi, nano, emacs czy gedit.

18



Rozdział 1. Zaczynamy

Ebookpoint.pl kopia dla: Rodenko David [email protected]

Po wpisaniu kodu z listingu 1.3 zapisz go na pulpicie w pliku test.html, a następnie otwórz w przeglądarce Chrome. Aby to zrobić, możesz przeciągnąć plik na ikonę przeglądarki albo dwukrotnie go kliknąć. W takiej sytuacji plik zostanie otwarty w domyślnej aplikacji, którą może być edytor tekstu. Aby temu zaradzić, możesz skorzystać z polecenia otwierania w wybranej aplikacji (i wskazać przeglądarkę Chrome). Nawet jeśli do przeglądania internetu używasz innej przeglądarki, przykłady z tej książki otwieraj w przeglądarce Chrome, ponieważ jest najbardziej zbliżona do przeglądarki z Androida1. Aby ją zainstalować (w systemach Windows, Mac OS i Linux), przejdź na stronę http://google.com/chrome.

Wprowadzenie do CSS Jak już zauważyłeś, przeglądarki renderują poszczególne elementy dokumentu HTML w specyficzny sposób (nagłówki są większe i pogrubione, akapity są wyświetlane z dodatkowym odstępem od innych elementów i tak dalej). Te podstawowe, wbudowane w przeglądarkę style ułatwiają oglądającym stronę zrozumieć jej strukturę i wyodrębnić istotną zawartość. Aby wyjść poza te proste zasady renderowania, trzeba skorzystać z kaskadowych arkuszy stylów (ang. Cascading Style Sheets — CSS). CSS to język służący do definiowania wizualnej prezentacji dokumentu HTML. Można za jego pomocą ustalić tak podstawowe sprawy jak kolor tekstu, jego rozmiar i styl (pogrubienie, kursywę itp.), ale również bardziej złożone, jak układ strony, gradienty, przezroczystość i wiele innych. Na listingu 1.4 zamieściliśmy regułę CSS, która ustawia kolor tekstu z sekcji body na czerwony. W tym przykładzie body jest selektorem (wskazującym elementy podlegające zmianie), a w nawiasach klamrowych znajduje się deklaracja (czyli właściwa reguła). Na deklarację składa się zbiór właściwości i przypisanych im wartości. W omawianym przykładzie właściwością jest color, a jej wartością jest red. Listing 1.4. Prosta reguła CSS body { color: red; }

1

Przeglądarkę Chrome można też zainstalować na urządzeniach z Androidem w wersji co najmniej 4.0, a także w systemie iOS od wersji 4.3 — przyp. tłum.

Ekspresowy kurs technologii internetowych

Ebookpoint.pl kopia dla: Rodenko David [email protected]



19

Możliwe nazwy właściwości są zdefiniowane w specyfikacji CSS, a to oznacza, że nie możesz stosować własnych. Każda właściwość przyjmuje określone wartości, które można podawać w wielu różnych formatach. Kolory możesz na przykład ustalać za pomocą predefiniowanych słów kluczowych, takich jak red, albo notacji kolorów obowiązującej w języku HTML, bazującej na zapisie szesnastkowym2. Notacja ta wymaga wpisania znaku „płotka” (#) i trzech dwucyfrowych liczb szesnastkowych określających natężenie trzech składowych koloru: czerwonej, zielonej i niebieskiej. Odpowiednikiem słowa red jest w tym zapisie wartość #FF0000. Właściwościom ustalającym wymiary można przypisać wartości w postaci 10px, 75%, 1em itp. Na listingu 1.5 zamieściliśmy przykładowe deklaracje (kolor przypisany właściwości background-color odpowiada stałej gray). Listing 1.5. Kilka przykładowych deklaracji CSS body { color: red; background-color: #808080; font-size: 12px; font-style: italic; font-weight: bold; font-family: Arial; }

Selektory mogą przyjmować wiele różnych postaci. Gdybyś chciał na przykład, aby wszystkie odsyłacze (elementy a) były zapisane kursywą, do arkusza stylów musiałbyś dodać taką regułę: a { font-style: italic; }

Gdyby jednak odsyłacze miały być zapisane kursywą tylko w określonej sytuacji, na przykład w nagłówkach h1, selektor musiałby przyjąć następującą postać: h1 a { font-style: italic; }

Można również tworzyć własne selektory poprzez dodanie do wybranych znaczników atrybutów id i class. Spójrz na poniższy fragment kodu HTML: Cześć! Dziękujemy za odwiedzenie naszej strony. Mamy nadzieję, że Ci się podoba. Pizza 2

Istnieje jeszcze jeden sposób definiowania koloru — za pomocą „funkcji” rgb() i rgba(). Więcej informacji na ten temat możesz znaleźć w specyfikacji CSS3 pod adresem http://www.w3.org/TR/css3-color/ — przyp. tłum.

20



Rozdział 1. Zaczynamy

Ebookpoint.pl kopia dla: Rodenko David [email protected]

Piwo Hot dog

Po dopisaniu do arkusza CSS powiązanego z tym dokumentem HTML (więcej na ten temat już za chwilę) reguły .loud { font-style: italic; }, teksty Cześć! oraz Pizza zostaną wyświetlone pochylonym fontem, ponieważ oba mają przypisaną klasę loud. Kropka na początku selektora .loud jest bardzo ważna — dzięki niej wiadomo, że chodzi o elementy dokumentu z przypisaną klasą loud. Gdybyś pominął tę kropkę, przeglądarka starałaby się zastosować styl do elementów loud, których nie ma w tym dokumencie (ani w specyfikacji języka HTML). Stosowanie stylów do elementów z identyfikatorem (id) wygląda podobnie. Aby tekst ze znacznika akapitu highlight został wyświetlony na żółtym tle, do arkusza stylów wystarczy dodać poniższą regułę: #highlight { background-color: yellow; }

Symbol # oznacza, że chodzi o definicję CSS dla elementu HTML o identyfikatorze (id) highlight. Podsumowując, elementy można wybierać, korzystając z nazw znaczników (np. body, h1, p), klas (np. .loud, .subtle, .error) lub identyfikatorów (np. #highlight, #login, #promo). Można też tworzyć selektory złożone z kilku elementów, i w ten sposób wybierać pożądane elementy (np. h1 a, body ul .loud). Między klasami (class) i identyfikatorami (id) istnieje istotna różnica. Atrybutu class używa się wtedy, gdy w dokumencie jest więcej niż jeden element danej klasy. Na jednej stronie może być z kolei tylko jeden element o danym identyfikatorze. W związku z tym można by uznać, że dobrym wyjściem jest stosowanie w każdym przypadku atrybutu class, a nie id, ponieważ nie trzeba się wtedy przejmować liczbą wystąpień. Musisz jednak wiedzieć, że wskazywanie elementów poprzez identyfikatory jest znacznie szybsze niż przez klasy, więc nadużywanie klas może wyraźnie wpłynąć na wydajność.

Dołączanie arkusza stylów do dokumentu Teraz rozumiesz już podstawy arkuszy stylów, ale powstaje pytanie, jak dołączyć arkusz do strony HTML. Rozwiązanie jest niezwykle proste. Najpierw musisz zapisać plik arkusza w wybranym miejscu na serwerze (często jest to katalog, w którym znajduje się plik HTML, ale może to być dowolny podkatalog). Następnie w sekcji head dokumentu HTML trzeba dołączyć arkusz Ekspresowy kurs technologii internetowych

Ebookpoint.pl kopia dla: Rodenko David [email protected]



21

CSS, co zostało pokazane na listingu 1.6. Wartością atrybutu href w tym przypadku jest ścieżka względna, co oznacza, że plik screen.css znajduje się w tym samym katalogu co dokument HTML. W tym miejscu można oczywiście podawać też ścieżki bezwzględne, na przykład: http://przyklad.com/screen.css Jeśli zapisujesz pliki HTML na swoim komputerze, sprawa jest prosta — umieść plik CSS w tym samym katalogu co dokumenty HTML i użyj ścieżki względnej, tak samo jak na listingu 1.6.

Listing 1.6. Dołączanie pliku z arkuszem stylów Moja wspaniała strona Cześć! Dziękujemy za odwiedzenie naszej strony. Mamy nadzieję, że Ci się podoba. Pizza Piwo Hot dog

Zawartość pliku screen.css została przedstawiona na listingu 1.7. Powinieneś zapisać ten plik w tym samym katalogu co stronę HTML. Listing 1.7. Prosty arkusz stylów body { font-size: 12px; font-weight: bold; font-family: Arial; } a { font-style: italic; } h1 a { font-style: italic; } .loud { font-style: italic; } #highlight { background-color: yellow; }

Warto wspomnieć, że do strony możesz dołączyć arkusz stylów znajdujący się w innej domenie niż ta, w której jest dostępny dokument HTML. Pamiętaj, że korzystanie z cudzych arkuszy stylów bez pozwolenia nie jest zbyt eleganckie, więc lepiej tego unikaj.

22



Rozdział 1. Zaczynamy

Ebookpoint.pl kopia dla: Rodenko David [email protected]

Szybkie i skuteczne wprowadzenie w CSS oferuje książka CSS. Leksykon kieszonkowy3 Erica Meyera. Z całą pewnością polecamy tego autora, bo to do niego należy ostatnie słowo w sprawach związanych z CSS. Za wyborem tej książki przemawia też fakt, że jest niezwykle zwięzła, dzięki czemu na jej przeczytanie nie poświęcisz zbyt dużo swojego cennego czasu.

Wprowadzenie do JavaScriptu Do tej pory dowiedziałeś się, jak tworzyć strukturę dokumentów HTML i jak modyfikować ich stronę wizualną za pomocą arkuszy CSS. Teraz skupimy się na tym, jak dzięki językowi JavaScript sprawić, by coś zaczęło działać. JavaScript jest językiem skryptowym, który umożliwia dodanie do strony skryptów zwiększających interaktywność i wygodę korzystania ze strony. Możesz na przykład stworzyć kod sprawdzający dane wprowadzane w formularzu i powiadamiający użytkownika o ewentualnych błędach. Możesz też wyświetlać i ukrywać wybrane elementy strony w zależności od działań użytkownika. Z poziomu JavaScriptu możesz się nawet kontaktować z serwerem, przesyłając lub odbierając dane bez potrzeby przeładowywania całej strony. Jak w każdym nowoczesnym języku, w JavaScripcie dostępne są zmienne, tablice, obiekty i typowe instrukcje sterujące (takie jak if, while czy for). Na listingu 1.8 zamieściliśmy krótki skrypt napisany w JavaScripcie, który prezentuje kilka kluczowych elementów języka (na razie nie umieszczaj tego kodu w dokumencie HTML — sposób łączenia kodu HTML i JavaScript pokażemy za chwilę). Listing 1.8. Prosty skrypt JavaScript var foods = ['jabłka', 'banany', 'pomarańcze']; for (var i=0; i

Zanim przejdziemy dalej, koniecznie zmodyfikuj dokument HTML (jeśli jeszcze tego nie zrobiłeś) — usuń istniejący znacznik link dołączający plik screen.css i wpisz przedstawiony wyżej fragment kodu. Dzięki temu w każdej sytuacji zostanie dołączony odpowiedni arkusz stylów.

3

Zapytania o media (ang. Media Queries) są wspierane w Internet Explorerze dopiero od wersji 9. — przyp. tłum.

34



Rozdział 2. Praca ze stylami

Ebookpoint.pl kopia dla: Rodenko David [email protected]

Kontrolowanie skalowania strony Przeglądarka Androida zakłada, że strona ma szerokość 980 pikseli (co można zauważyć na rysunku 2.2). W większości przypadków takie założenie doskonale się sprawdza, ale tym razem jest inaczej — zamierzamy przecież dostosować stronę do mniejszych ekranów. Musimy zatem poinformować o tym przeglądarkę. W tym celu w sekcji head dokumentu HTML w znaczniku meta trzeba dodać definicję viewport:

Przeglądarki desktopowe ignorują znacznik meta viewport, więc możesz go dołączać do stron, nie martwiąc się o ich wygląd w tych przeglądarkach.

Samo dezaktywowanie desktopowego arkusza stylów i dodanie znacznika meta viewport wystarczyło, by w przeglądarce Androida strona wyglądała lepiej (patrz rysunek 2.4). To jednak dopiero początek poprawek — zabieramy się za arkusz android.css.

Rysunek 2.4. Dzięki ustaleniu szerokości dla viewport na szerokość ekranu zawartość strony jest bardziej czytelna Pierwsze kroki

Ebookpoint.pl kopia dla: Rodenko David [email protected]



35

Jeśli nie ustawisz szerokości dla viewport, strona zostanie przeskalowana przy pierwszym załadowaniu. Trudno powiedzieć, jaka skala zostanie ustalona, ponieważ w przeglądarce Androida użytkownik może zdefiniować domyślne powiększenie. Możliwe wartości to: Daleko, Normalny (domyślnie) i Blisko. Ustawiona wartość ma wpływ na stopień powiększenia strony, nawet jeśli ustawisz szerokość dla viewport.

Arkusz stylów dla Androida Istnieje wiele cech interfejsu użytkownika, dzięki którym aplikacji dla Androida nie pomylimy z żadną inną4. Zajmiemy się paskiem tytułowym, listami z zaokrąglonymi wierzchołkami, nawigacją, którą łatwo obsługiwać palcami, lśniącymi przyciskami itd. W wybranym edytorze tekstu utwórz nowy plik i zapisz go pod nazwą android.css w tym samym katalogu co dokument HTML. Następnie wpisz do niego kod z listingu 2.2. Listing 2.2. Podstawowe reguły dla elementu body dokumentu HTML body { background-color: #ddd; color: #222; font-family: Helvetica; font-size: 14px; margin: 0; padding: 0; }

/* Kolor tła */ /* Kolor pierwszoplanowy stosowany do tekstu */

/* Margines sekcji body */ /* Padding sekcji body */

Wszystkie teksty na Androidzie są wyświetlane czcionką Droid (w wersji 4. używana jest nowa czcionka — Roboto). Czcionki te zostały stworzone specjalnie z myślą o urządzeniach mobilnych. Występują w trzech wariantach: Droid Sans, Droid Sans Mono i Droid Serif. Z tego względu określenie we właściwości font-family czcionki Helvetica nie będzie miało znaczenia w urządzeniach z Androidem.

4

Wyczerpujące informacje na ten temat można znaleźć na stronie http://developer.android. com/design/. Nie wszystkie rozwiązania zastosowane przez autorów książki są zgodne z zawartymi tam wytycznymi, dlatego proponujemy, by zasięgnąć informacji u źródeł — przyp. tłum.

36



Rozdział 2. Praca ze stylami

Ebookpoint.pl kopia dla: Rodenko David [email protected]

Zajmiemy się teraz blokiem div nagłówka zawierającym odsyłacz do głównej strony (czyli logo) oraz główną i dodatkową nawigację. Zaczniemy od sformatowania odsyłacza logo — sprawimy, by stał się paskiem tytułowym, który można kliknąć. Do pliku android.css dodaj poniższy kod: #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; }

Główny i dodatkowy blok nawigacji (znaczniki ul) sformatujemy identycznie, więc możemy skorzystać z ogólnych selektorów elementów (czyli #header ul) zamiast odwoływać się do nich przez identyfikatory (czyli #header ul#utility, #header ul#nav): #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; font-weight: bold; margin-bottom: -1px; padding: 12px 10px; text-decoration: none; }

Proste, prawda? Ten krótki fragment CSS wystarczył, by wprowadzić całkiem sporo zmian w wyglądzie strony (rysunek 2.5). Teraz dodamy jeszcze niewielki padding do bloków div zawartości (#content) i bocznego paska (#sidebar), by odsunąć tekst od krawędzi ekranu (rysunek 2.6): #content, #sidebar { padding: 10px; }

Arkusz stylów dla Androida

Ebookpoint.pl kopia dla: Rodenko David [email protected]



37

Rysunek 2.5. Wystarczy odrobina stylów, a użyteczność strony zdecydowanie wzrasta

Rysunek 2.6. Efekt powiększenia odstępu zawartości od krawędzi strony 38



Rozdział 2. Praca ze stylami

Ebookpoint.pl kopia dla: Rodenko David [email protected]

Być może się zastanawiasz, dlaczego ustawiamy padding lokalnie tylko w tych dwóch blokach, a nie globalnie w elemencie body. Chodzi o to, by istniała możliwość umieszczenia jakichś elementów bezpośrednio przy krawędzi strony (czego przykładem może być pasek nagłówka). W podobnych sytuacjach zawsze dwa razy się zastanów, czy nie skomplikujesz sobie życia, ustawiając padding w elemencie otaczającym inne.

W stopce strony znajduje się powtórzony blok nawigacyjny (element ul o identyfikatorze nav), który w zoptymalizowanej wersji dla Androida możesz ukryć, ustawiając właściwość display na none: #footer { display: none; }

Wygląd i zachowanie w stylu Androida Pora zająć się dopieszczaniem. Zaczynamy od góry strony — do tekstu nagłówka dodamy 1-pikselowy biały cień, a do tła zastosujemy gradient: #header h1 a { text-shadow: 0px 1px 1px #fff; background-image: -webkit-gradient(linear, left top, left bottom, from(#ccc), to(#999)); }

W deklaracji text-shadow kolejne parametry to: przesunięcie w poziomie, w pionie, rozmycie i kolor. W większości będziesz stosować do tekstu właśnie takie wartości, ponieważ efekt końcowy dobrze wygląda na Androidzie. Proponujemy jednak, byś na własną rękę poeksperymentował z właściwością text-shadow, ponieważ jej umiejętne stosowanie może wzbogacić projekt. Większość przeglądarek zaakceptuje rozmycie o wartości 0px, jednak przeglądarka Androida wymaga wartości równej co najmniej 1px (gdybyś wyzerował tę wartość, cień w ogóle by się nie pojawił).

Właściwość -webkit-gradient wymaga większej uwagi. Powoduje ona wygenerowanie przez przeglądarkę obrazu gradientu. Z tego względu gradientów CSS możesz używać wszędzie tam, gdzie jest możliwe podanie adresu pliku obrazu za pomocą url(), czyli w przypadku ustalania obrazu tła, symboli wypunktowania itp. Kolejne parametry to: typ gradientu (linear lub radial), punkt początkowy gradientu (left top, left bottom, right top lub right bottom), punkt końcowy, kolor początkowy i kolor końcowy. Wygląd i zachowanie w stylu Androida

Ebookpoint.pl kopia dla: Rodenko David [email protected]



39

Nie można zamienić miejscami informacji o poziomym i pionowym położeniu punktów gradientu (czyli na przykład zamiast left top nie możesz wpisać top left). Zawsze stosuj tylko jedną z czterech możliwych wartości: left top, left bottom, right top lub right bottom.

Kolejnym krokiem jest dodanie zaokrąglonych wierzchołków do bloków elementów nawigacyjnych: #header ul li:first-child a { -webkit-border-top-left-radius: 8px; -webkit-border-top-right-radius: 8px; } #header ul li:last-child a { -webkit-border-bottom-left-radius: 8px; -webkit-border-bottom-right-radius: 8px; }

Jak widzisz, stosujemy właściwość -webkit-border-radius dla poszczególnych wierzchołków, by ustawić 8-pikselowe zaokrąglenie dla dwóch górnych oraz dwóch dolnych wierzchołków listy (rysunek 2.7).

Rysunek 2.7. Dzięki gradientom, cieniom i zaokrąglonym wierzchołkom strona zaczyna przypominać prawdziwą aplikację dla Androida 40



Rozdział 2. Praca ze stylami

Ebookpoint.pl kopia dla: Rodenko David [email protected]

Byłoby fajnie, gdyby dało się ustawić zaokrąglone wierzchołki w elemencie ul, ale niestety nie jest to możliwe. Nawet gdybyś spróbował to zrobić, ostre wierzchołki kolejnych pozycji listy przesłonią zaokrąglone wierzchołki elementu ul, więc nie uzyskasz pożądanego efektu. Tak naprawdę mogłoby nam się to udać, ale pod warunkiem, że ustawilibyśmy kolor tła dla ul na biały, a dla li na przezroczysty. W takiej sytuacji po kliknięciu pierwszego lub ostatniego elementu listy zostałby jednak wyświetlony prostokątny obszar kliknięcia o ostrych wierzchołkach, co wygląda fatalnie. Najlepszym wyjściem jest zastosowanie zaokrąglenia do znaczników a, czyli tak, jak w zaproponowanym przez nas rozwiązaniu. W powyższych regułach CSS zastosowaliśmy pseudoklasy :first-child i :last-child. Są to specjalne typy selektorów, które umożliwiają wskazanie elementów spełniających wybrane kryteria wynikające z kontekstu. Innymi słowy, możesz zastosować styl w zależności od pewnych cech, takich jak położenie na liście lub stan wynikający z położenia kursora czy kliknięcia, bez potrzeby ręcznej zmiany znacznika. Na przykład selektor li:first-child spowoduje wybranie pierwszego elementu li, który należy do wskazanej listy ul. Gdyby nie pseudoklasy, musielibyśmy ręcznie dodać klasę do pierwszego znacznika li, tak by przeglądarka wiedziała, że to jest pierwszy element.

Proste zachowania z jQuery Teraz dołączymy do strony skrypt JavaScript, który doda do niej proste dynamiczne zachowania. Przede wszystkim chcemy umożliwić użytkownikom wyświetlanie i ukrywanie sekcji nawigacji, tak by była widoczna tylko wtedy, gdy jest potrzebna. W tym celu musimy dopisać kilka reguł do arkusza CSS i napisać skrypt JavaScript, który będzie je stosował do istniejącego kodu HTML. Zaczynamy od stylów. Pierwszym krokiem jest ukrycie elementów ul w bloku div#header, tak by nie pojawiały się po pierwszym załadowaniu strony. Otwórz plik android.css i dopisz poniższą regułę: #header ul.hide { display: none; }

Aby zobaczyć efekt, musimy dodać do elementów ul klasę hide (zrobimy to niebawem z poziomu JavaScriptu). Wcześniej zdefiniujemy jeszcze styl

Proste zachowania z jQuery

Ebookpoint.pl kopia dla: Rodenko David [email protected]



41

dla przycisku, który będzie służył do wyświetlania i ukrywania menu. Nie utworzyliśmy jeszcze kodu HTML dla tego przycisku — będzie on wyglądał tak: Menu

Budowę tego kodu omówimy dokładniej później, więc na razie nie dopisuj go do dokumentu. Ważne jednak, byś zapamiętał, że tworzymy tu blok div należący do klasy leftButton, który ma się znaleźć w nagłówku strony. Poniżej znajduje się definicja stylu dla tego przycisku (możesz ją dopisać do pliku android.css): #header div.leftButton { position: absolute; top: 7px; left: 6px; height: 30px; font-weight: bold; text-align: center; color: white; (0,0,0,0.6) 0px -1px 1px; text-shadow: rgba line-height: 28px; border-width: 0 8px 0 8px; -webkit-border-image: url(images/button.png) 0 8 0 8; }

Niezbędne pliki znajdują się w paczce z plikami źródłowymi, którą możesz pobrać ze strony wydawnictwa (ftp://ftp.helion.pl/ przyklady/andrta.zip). Pliki graficzne są zapisane w katalogu images i w takim powinny pozostać. Jeśli zamierzasz umieścić je w innej lokalizacji, musisz zaktualizować ścieżki w omawianych regułach CSS.

Ustala pozycję na bezwzględną (absolute), aby wyjąć ten blok div z naturalnego biegu elementów dokumentu. Dzięki temu możesz ustalić pożądane współrzędne bloku (top i left). Ustawiamy wysokość na 30 pikseli, by łatwo było trafić w przycisk palcem. Tekst ma być wyświetlony pogrubioną, białą czcionką z delikatnym cieniem i wyrównaniem do środka. Zastosowanie funkcji rgb() jest alternatywnym dla wartości szesnastkowej sposobem określania koloru. Zapisowi #FFFFFF odpowiada rgb(255, 255, 255) lub rgb(100%, 100%, 100%). Ostatnio została wprowadzona funkcja rgba(), która pozwala na określenie czwartego parametru — stopnia krycia. Może on przyjąć wartości od 0 do 1, przy czym 0 oznacza pełną przezroczystość, a 1 — pełne krycie. 42



Rozdział 2. Praca ze stylami

Ebookpoint.pl kopia dla: Rodenko David [email protected]

Deklaracja line-height powoduje przesunięcie tekstu w dół, tak by nie był „przyklejony” do górnej krawędzi. Właściwości border-width i -webkit-border-image wymagają dokładniejszego wyjaśnienia. Umożliwiają one przyporządkowanie pojedynczego obrazu do obszarów elementu odpowiadających jego krawędziom. Jeśli zmienią się wymiary elementu (na przykład na skutek powiększenia lub pomniejszenia tekstu), obraz krawędzi zostanie odpowiednio dopasowany (poprzez ściśnięcie lub rozciągnięcie). W porównaniu z dawniej stosowanymi rozwiązaniami zyskujemy w kwestii pracy, jaka musi zostać wykonana, obciążenia połączenia internetowego i czasu ładowania strony. Właściwość border-width ustala szerokość krawędzi. W tym przypadku jest to: 0 pikseli na górze, 8 pikseli z prawej strony, 0 na dole i 8 z lewej (przy czterech parametrach pierwszy ustala górną krawędź, a pozostałe są ustawiane zgodnie z ruchem wskazówek zegara). Nie musisz definiować koloru i stylu krawędzi. Po ustaleniu szerokości krawędzi możemy zastosować obraz. Pierwszy parametr to adres URL pliku obrazu, a kolejne cztery to szerokość obrazu na górze, z prawej, na dole i z lewej strony (znów zgodnie z ruchem wskazówek zegara). Adres URL może być bezwzględny (np. http://przyklad. com/obrazKrawedzi.png) lub względny. Ścieżki względne są wyznaczane na podstawie lokalizacji arkusza stylów, a nie dokumentu HTML, do którego ten arkusz jest dołączany. Być może zastanawiasz się, dlaczego musisz dwa razy robić to samo — przecież szerokości krawędzi ustaliliśmy we właściwości border-width, a później robimy to samo w border-image. Sprawa wygląda jednak tak, że we właściwości border-image nie podajemy szerokości krawędzi, a szerokość obszaru, jaki należy wyciąć z obrazu. Spójrzmy na przykład na prawą krawędź — określamy, że z obrazu ma zostać wycięty 8-pikselowy obszar, licząc od lewej krawędzi. Oczywiście możliwe jest zdefiniowanie kombinacji, która nie ma sensu, na przykład zastosowanie 4-pikselowego wycinka obrazu do 20-pikselowej krawędzi. Czasami mogą się przydać opcjonalne parametry właściwości -webkit-border-image, które definiują zachowanie obrazu w obszarze krawędzi (między innymi rozciąganie, powtarzanie czy zaokrąglanie). W kilkuletniej praktyce autorzy nie napotkali jednak sytuacji, w której musieliby z nich skorzystać.

Proste zachowania z jQuery

Ebookpoint.pl kopia dla: Rodenko David [email protected]



43

W końcu przyszedł czas na skrypt. Zanim jednak zajmiemy się kodem, musisz dodać do dokumentu znaczniki dołączające pliki jquery.js i android.js. Do sekcji head dopisz poniższe dwa wiersze:

Bibliotekę jQuery możesz pobrać ze strony projektu (http://jquery.com). Znajdziesz tam też bogatą dokumentację i samouczki. Aby skorzystać z biblioteki, pobierz ją ze strony, zmień nazwę pobranego pliku na jquery.js (nazwa pobranego pliku zawiera wersję, np. jquery-1.7.2.min.js), a następnie umieść go w tym samym katalogu co dokument HTML.

Podstawowym zadaniem skryptu ma być wyświetlanie i ukrywanie bloków nawigacyjnych. Utwórz plik android.js, wpisz do niego poniższy kod i zapisz w tym samym katalogu co dokument HTML: if (window.innerWidth && window.innerWidth 1) { $('#header').append(''+hist[1].title+''); $('#header .leftButton').click(function(){ var thisPage = hist.shift(); var previousPage = hist.shift(); loadPage(previousPage.url); }); } $('#container a').click(function(e){ var url = e.target.href; if (url.match(window.location.hostname)) { e.preventDefault(); loadPage(url); } }); $('#progress').remove(); }); }

Ta linia inicjalizuje zmienną o nazwie hist jako pustą tablicę. Jest zdefiniowana poza wszystkimi funkcjami, dlatego też ma zasięg globalny i będzie dostępna dla całej strony. Zwróć uwagę na to, że nie użyliśmy słowa history jako nazwy zmiennej, ponieważ jest to predefiniowana właściwość obiektu w JavaScripcie i powinieneś jej unikać we własnym kodzie. Ta linia definiuje względny URL strony do załadowania po tym, jak użytkownik pierwszy raz otworzy dokument android.html. Pewnie pamiętasz, że w poprzednich przykładach podczas obsługi pierwszego załadowania strony sprawdzaliśmy warunek url == undefined, ale tym razem wykorzystujemy stronę startową. Dlatego też sensownym rozwiązaniem jest zdefiniowanie jej adresu jako zmiennej globalnej. 66



Rozdział 3. Zaawansowane stylizowanie

Ebookpoint.pl kopia dla: Rodenko David [email protected]

Ta i następna linia definiują funkcję uruchamianą wskutek zdarzenia $(document).ready. W przeciwieństwie do poprzednich przykładów, do funkcji loadPage()przekazujemy stronę startową.

Funkcja loadPage(). Ta i następna linia są skopiowane z poprzedniego przykładu. To wyrażenie if...else decyduje o tym, które elementy powinny zostać załadowane ze strony. Jeżeli przechodzimy do strony startowej, ładujemy elementy ul z nagłówka, a w przeciwnym przypadku — blok div z treścią. W tym wierszu łączymy łańcuchy zawierające parametr url i odpowiedni element źródłowy, a wynik przekazujemy jako pierwszy parametr funkcji load. Jako drugi parametr przekazujemy bezpośrednio funkcję anonimową (funkcję bez nazwy definiowaną w miejscu pierwszego użycia). W tej linii usuwamy element .leftButton ze strony. Może się to wydawać dziwne, ponieważ nie dodaliśmy go jeszcze do strony; dodamy go w jednym z następnych kroków. W tym miejscu wykorzystujemy wbudowaną metodę unshift, żeby dodać obiekt na początku tablicy hist. Ten obiekt posiada dwie właściwości: url i title — obie są potrzebne, by zapewnić odpowiedni wygląd i prawidłowe zachowanie przycisku „wstecz”. W tym wierszu korzystamy z wbudowanej metody length, żeby określić liczbę obiektów w historii. Jeżeli w historii jest tylko jeden obiekt, oznacza to, że użytkownik znajduje się na pierwszej stronie. Z tego wynika, że nie musimy wyświetlać przycisku „wstecz”. Gdy będzie ich więcej, będziemy musieli dodać przycisk do nagłówka strony. Tu dodajemy wspomniany wcześniej element .leftButton. Tekst tego przycisku będzie taki sam jak tytuł poprzednio odwiedzonej strony, który odczytujemy za pomocą kodu hist[1].title. Tablice w języku JavaScript są indeksowane od zera, więc pierwszy element na liście (bieżąca strona) ma indeks 0. Innymi słowy, bieżąca strona ma numer 0, poprzednia strona ma numer 1, strona przed nią ma numer 2 i tak dalej. Ten blok kodu wiąże anonimową funkcję z obsługą kliknięcia przycisku „wstecz”. Pamiętaj: kod obsługi kliknięcia jest wykonywany, gdy użytkownik kliknie, a nie kiedy strona się ładuje. Oznacza to, że kod funkcji zostanie wykonany po załadowaniu strony i kliknięciu przez użytkownika przycisku „wstecz”. W tej i następnej linii używamy wbudowanej metody shift do usunięcia dwóch pierwszych elementów z tablicy hist. W ostatnim wierszu funkcji przekazujemy adres URL poprzedniej strony do funkcji loadPage(). Kilka wodotrysków

Ebookpoint.pl kopia dla: Rodenko David [email protected]



67

Pozostałe linie są skopiowane z poprzednich wersji skryptu, więc nie ma potrzeby ich omawiać. To jest kod sprawdzający URL, który omówiliśmy wcześniej. Pełną listę metod dostępnych dla tablic w JavaScripcie oraz przykłady ich użycia znajdziesz na przykład na stronie http:// www.hunlock.com/blogs/Mastering_Javascript_Arrays.

Teraz, gdy mamy już przycisk „wstecz”, jedyne, co pozostaje, to upiększyć go za pomocą odpowiednich stylów CSS (patrz listing 3.11). Zaczniemy od stylizacji tekstu za pomocą właściwości font-weight, text-align, line-height, color i text-shadow. Następnie umieścimy element div dokładnie tam, gdzie chcemy, wykorzystując właściwości position, top i left, a potem ustalimy, by długi tekst na etykiecie przycisku był skracany przy użyciu wielokropka, za pomocą max-width, white-space, overflow i text-overflow. Na koniec dodamy grafikę dzięki właściwościom border-width i -webkit-border-image. Inaczej niż w poprzednim przykładzie z krawędziami obrazu, ten obrazek ma różne szerokości lewej i prawej krawędzi ze względu na to, że jest asymetryczny przez grot strzałki znajdujący się po lewej stronie. Listing 3.11. Dodaj kod do pliku android.css, żeby upiększyć przycisk grafiką krawędzi #header div.leftButton { font-weight: bold; text-align: center; line-height: 28px; color: white; text-shadow: 0px -1px 1px rgba(0,0,0,0.6); position: absolute; top: 7px; left: 6px; max-width: 50px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; border-width: 0 8px 0 14px; -webkit-border-image: url(images/back_button.png) 0 8 0 14; }

Nie zapominaj, że będziesz potrzebować grafiki dla tego przycisku. Musisz zapisać ją jako back_button.png w katalogu images w katalogu, w którym znajdują się pliki HTML. Wskazówki na temat szukania i tworzenia własnych grafik na przyciski znajdziesz w podrozdziale „Proste zachowania z jQuery” w rozdziale 2.

68



Rozdział 3. Zaawansowane stylizowanie

Ebookpoint.pl kopia dla: Rodenko David [email protected]

Domyślnie Android wyświetla pomarańczowe podświetlenie na klikalnych obiektach, które zostały dotknięte przez użytkownika (rysunek 3.7). Podświetlenie może być widoczne tylko przez chwilę, ale jego usunięcie jest proste i poprawia wygląd aplikacji. Na szczęście Android obsługuje właściwość CSS -webkit-tap-highlight-color, która pozwala na zmianę tego zachowania. Możemy zrobić to tutaj poprzez zmianę koloru podświetlenia na w pełni przezroczysty (patrz listing 3.12).

Rysunek 3.7. Elementy dotknięte przez użytkownika są domyślnie podświetlane na pomarańczowo przez system Android Listing 3.12. Dodaj poniższy kod do android.css, żeby usunąć domyślny efekt podświetlenia #header div.leftButton { font-weight: bold; text-align: center; line-height: 28px; color: white;

Kilka wodotrysków

Ebookpoint.pl kopia dla: Rodenko David [email protected]



69

text-shadow: 0px -1px 1px rgba(0,0,0,0.6); position: absolute; top: 7px; left: 6px; max-width: 50px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; border-width: 0 8px 0 14px; -webkit-border-image: url(images/back_button.png) 0 8 0 14; -webkit-tap-highlight-color: rgba(0,0,0,0); }

W przypadku przycisku „wstecz” możliwe jest jedno- lub dwusekundowe opóźnienie, zanim treść poprzedniej strony się pojawi. Żeby uniknąć frustracji, możemy tak skonfigurować przycisk, by wyglądał na kliknięty od razu, gdy zostanie dotknięty. W przeglądarkach na komputery osobiste jest to proste — do arkusza stylów wystarczy dodać deklarację wykorzystującą pseudoklasę :active do określenia alternatywnego stylu właśnie klikniętego obiektu. Nie wiadomo, czy jest to błąd, czy zamierzone zachowanie, ale to podejście nie działa w Androidzie — pseudoklasa :active jest ignorowana. Nasze liczne próby z :active i :hover przyniosły pewne efekty, ale w aplikacjach bez funkcji ajaksowych. Niestety w aplikacjach ajaksowych, takich jak nasza, pseudoklasa :hover zostaje na obiekcie (przycisk wydaje się być wciśnięty, nawet gdy użytkownik zdejmie z niego palec). Na szczęście poprawka jest dosyć prosta — trzeba użyć jQuery, by po kliknięciu przez użytkownika przycisku została do niego dodana klasa clicked. W tym przycisku użyjemy ciemniejszej wersji grafiki (rysunek 3.8 i listing 3.13). Aby to zadziałało, w katalogu images musi się znajdować plik back_button_clicked.png. Wskazówki na temat szukania i tworzenia własnych grafik na przyciski znajdziesz w podrozdziale „Proste zachowania z jQuery” w rozdziale 2. Listing 3.13. Dodaj poniższy kod do pliku android.css, aby przycisk „wstecz” wyglądał na kliknięty, kiedy użytkownik go dotknie #header div.leftButton.clicked { -webkit-border-image: url(images/back_button_clicked.png) 0 8 0 14; }

Ponieważ jako tła klikniętego przycisku używamy obrazka, rozsądne byłoby załadowanie tego obrazka wcześniej. W przeciwnym przypadku grafika tła nieklikniętego przycisku zniknie po pierwszym kliknięciu, a w tym czasie będzie ładowany obrazek klikniętego przycisku. Zagadnienie wczesnego ładowania obrazków omówimy w następnym rozdziale. 70



Rozdział 3. Zaawansowane stylizowanie

Ebookpoint.pl kopia dla: Rodenko David [email protected]

Rysunek 3.8. Może to być niewidoczne w druku, ale kliknięty przycisk „wstecz” jest trochę ciemniejszy niż w domyślnym stanie

Po uzupełnieniu arkusza CSS możemy zaktualizować fragment pliku android.js odpowiedzialny za obsługę kliknięcia przycisku „wstecz”. Najpierw dodamy zmienną e do funkcji anonimowej, żeby przechwycić przychodzące zdarzenie kliknięcia. Potem potraktujemy cel zdarzenia jako selektor i wywołamy funkcję addClass(), by do przycisku przypisać klasę clicked: $('#header .leftButton').click(function(e){ $(e.target).addClass('clicked'); var thisPage = hist.shift(); var previousPage = hist.shift(); loadPage(lastUrl.url); });

Kilka wodotrysków

Ebookpoint.pl kopia dla: Rodenko David [email protected]



71

Specjalna uwaga dla wszystkich guru CSS wśród czytelników — technika CSS Sprite, spopularyzowana przez serwis A List Apart, w tym przypadku nie wchodzi w rachubę, ponieważ wymaga podawania przesunięcia w obrębie obrazka, a właściwość -webkit-border-image tego nie obsługuje.

Dodawanie ikony do pulpitu Mam nadzieję, że użytkownicy będą chcieli dodać ikonę Twojej aplikacji do swojego ekranu domowego (zwaną „ikoną uruchamiającą”). Można to zrobić przez dodanie aplikacji do zakładek i umieszczenie skrótu do zakładki na ekranie domowym (czyli dokładnie tak samo jak w przypadku dowolnej innej zakładki). Różnica polega na tym, że określimy własny obrazek do wyświetlenia zamiast domyślnej ikony zakładki. Musimy zacząć od dodania pliku obrazu .png do witryny. Zalecany rozmiar grafiki to 5656 pikseli, jeżeli widzialna powierzchnia ma kształt kwadratu, a 6060 pikseli w przeciwnym przypadku. Pozwala to na zachowanie spójności wyglądu z innymi ikonami. Będziesz musiał poeksperymentować z grafiką, aby dobrać odpowiednie wymiary. Tworzenie ikon, które wyglądają dobrze na wszystkich urządzeniach, jest pracochłonne, ponieważ Android może działać na wielu różnych urządzeniach o różnych rozmiarach ekranu i różnej rozdzielczości. Szczegółowe instrukcje i darmowe szablony znajdziesz na podstronie Icon Desing strony dla deweloperów Androida (http://developer.android.com/guide/practices/ui_guidelines/ icon_design.html#launcherstructure).

Następnie dodaj poniższą linię do sekcji head pliku HTML android.html (zamień mojaIkona.png na względną lub bezwzględną ścieżkę do pliku obrazka):

Jak już pewnie zauważyłeś, jest to dyrektywa specyficzna dla firmy Apple, ale jest obsługiwana również w Androidzie.

72



Rozdział 3. Zaawansowane stylizowanie

Ebookpoint.pl kopia dla: Rodenko David [email protected]

Czego się nauczyłeś? W tym rozdziale nauczyłeś się, jak przekształcić zwykłą witrynę w aplikację ajaksową, łącznie z paskami postępu i przyciskiem „wstecz” wyglądającym jak natywny. W następnym rozdziale dowiesz się, jak ożywić swoją aplikację poprzez dodanie natywnych animacji interfejsu. Tak jest — teraz będzie się działo!

Czego się nauczyłeś?

Ebookpoint.pl kopia dla: Rodenko David [email protected]



73

74



Rozdział 3. Zaawansowane stylizowanie

Ebookpoint.pl kopia dla: Rodenko David [email protected]

ROZDZIAŁ 4.

Animacje

W aplikacjach dla Androida można się spotkać z wieloma charakterystycznymi elementami animacji, które często są dodatkową informacją dla użytkownika. Przykładem może być przewijanie ekranów w lewo podczas nawigowania w głąb struktury aplikacji, a w prawo podczas powrotów. W tym rozdziale dowiesz się, jak do aplikacji internetowej dodać tego typu zachowania, dzięki czemu w jeszcze większym stopniu będzie przypominała aplikację natywną.

Z niewielką pomocą naszych przyjaciół Prawda jest taka, że stworzenie animacji wyglądającej na natywną na stronie internetowej jest bardzo trudne. Na szczęście mamy do dyspozycji bibliotekę jQTouch autorstwa Davida Kanedy, dzięki której da się to osiągnąć znacznie prościej. Jest to rozprowadzana na zasadach open source wtyczka do jQuery, która rozwiązuje większość problemów przedstawionych do tej pory, a także wiele innych, dużo bardziej złożonych. Najnowszą dostępną wersją biblioteki jQTouch jest 1.0b4, którą możesz pobrać ze strony http://www.jqtouch.com/. W kolejnych wersjach są planowane istotne zmiany, więc — mimo że w chwili czytania tej książki jest zapewne dostępna nowsza wersja biblioteki — pozostań lepiej przy 1.0b4. Kiedy będziesz się już czuć na tyle pewnie, by zmierzyć się z ewentualnymi problemami, możesz zaktualizować bibliotekę do najnowszej wersji.

75

Ebookpoint.pl kopia dla: Rodenko David [email protected]

Przewijanie Tym razem przygotujemy prostą aplikację Kilo wspomagającą stosowanie diety. Jej podstawową funkcjonalnością ma być dodawanie (i usuwanie) informacji o posiłkach do poszczególnych dni. Aplikację podzielimy na pięć ekranów: Główny, Ustawienia, Terminarz, Dzień oraz Nowy wpis. Zaczniemy od dwóch ekranów, a pozostałe dodamy później. Do elementów dokumentu HTML będziemy stosować różne klasy CSS (takie jak toolbar, edgetoedge, arrow, button czy back). Wszystkie one odpowiadają predefiniowanym klasom pochodzącym z domyślnego arkusza CSS biblioteki jQTouch. Możesz oczywiście tworzyć i stosować własne klasy oraz modyfikować szablony jQTouch, ale na potrzeby tego przykładu pozostaniemy przy domyślnych klasach.

Pracę nad tą aplikacją zaczynamy od zera, więc pliki tworzone we wcześniejszych rozdziałach nie będą nam potrzebne. Przede wszystkim musisz utworzyć plik index.html i wpisać do niego kod HTML przedstawiony na listingu 4.1 (zawiera on główny ekran i informacje o aplikacji). Listing 4.1. Kod HTML pliku index.html Kilo Kilo O Kilo O Kilo Wstecz Aplikacja Kilo pomaga stosować dowolną dietę.

76



Rozdział 4. Animacje

Ebookpoint.pl kopia dla: Rodenko David [email protected]

W dokumencie HTML znajduje się tylko sekcja nagłówka z tytułem oraz dwa bloki div: Ten blok div (podobnie jak drugi — about) stanie się ekranem aplikacji. Wykorzystamy tu fakt, że oba bloki są bezpośrednimi potomkami elementu body. W każdym bloku div znajduje się element div klasy toolbar (jest ona zdefiniowana w arkuszu biblioteki jQTouch). Dzięki temu element będzie wyglądał jak standardowy pasek narzędzi w aplikacjach mobilnych. Ten znacznik nienumerowanej listy (ul) ma przypisaną klasę edgetoedge, dzięki której lista zostanie rozciągnięta w poziomie na całą szerokość ekranu. Ten element li zawiera odsyłacz (w atrybucie href) do ekranu O Kilo. Przypisanie do elementu li klasy arrow jest opcjonalne, ale jej zastosowanie spowoduje dodanie strzałki z prawej strony elementu. We wszystkich blokach z przypisaną klasą toolbar znajduje się jeden element h1, który będzie wyświetlany jako tytuł ekranu. Znacznik a ma przypisane klasy button oraz back, dzięki czemu będzie wyglądał jak przycisk „wstecz”. Atrybut href przycisku „wstecz” został ustawiony na #. Standardowym zachowaniem przeglądarki po kliknięciu takiego odsyłacza jest przejście na początek bieżącego dokumentu, jednak w przypadku biblioteki jQTouch spowoduje to przejście do poprzedniego ekranu. Zamiast ogólnego łącza # możesz zastosować konkretny punkt powrotu, na przykład #home, dzięki czemu wciśnięcie przycisku spowoduje wyświetlenie wskazanego ekranu, a nie poprzedniego.

Mamy już kod HTML podstawowej wersji strony, pora dołączyć jQTouch. Po zainstalowaniu jQTouch w tym samym katalogu co dokument HTML (patrz ramka „Instalowanie biblioteki jQTouch”) dodaj do sekcji head dokumentu kilka wierszy kodu (listing 4.2).

Instalowanie biblioteki jQTouch W tym i wielu innych przykładach zaprezentowanych w książce będzie używana biblioteka jQTouch. Ze strony http://www.jqtouch.com pobierz plik ZIP i rozpakuj go. W miejscu, w którym znajduje się dokument HTML aplikacji Kilo, utwórz podkatalog jqtouch i umieść w nim katalogi src oraz themes z wypakowanego archiwum ZIP.

Przewijanie

Ebookpoint.pl kopia dla: Rodenko David [email protected]



77

Listing 4.2. Aby skorzystać z jQTouch, w sekcji head dokumentu dopisz poniższe wiersze var jQT = $.jQTouch({ icon: 'kilo.png' });

W tym wierszu dołączamy arkusz stylów jqtouch.css, który jest domyślnym tematem graficznym stosowanym przez jQTouch. Są w nim zdefiniowane klasy, których używamy w dokumencie HTML. Nie powinieneś wprowadzać zmian w tym arkuszu. Poza domyślnym tematem w jQTouch w wersji 1.0b4 dostępne są jeszcze dwa: apple.css oraz vanilla.css. Aby sprawdzić, jak wyglądają, zmodyfikuj w kodzie HTML nazwę dołączanego pliku CSS. jQTouch wymaga biblioteki jQuery bądź Zepto (obie zostały dołączone do paczki ZIP). Rozwiązaniem sugerowanym przez twórców biblioteki jQTouch jest zastosowanie Zepto (biblioteki bazującej na jQuery, która jest polecana dla aplikacji mobilnych ze względu na zminimalizowany rozmiar1), jednak w omawianym przykładzie użyjemy biblioteki jQuery (z uwagi na nieobecność w Zepto potrzebnych nam funkcji). W takim przypadku konieczne jest dołączenie pliku jqtouch-jquery.min.js, który tworzy „most” między bibliotekami jQTouch i jQuery. W tym miejscu dołączamy skrypt biblioteki jQTouch. Bardzo ważna jest kolejność dołączania skryptów — najpierw jQuery (bądź Zepto), później jQTouch. W przeciwnym razie aplikacja by nie zadziałała. W bloku script tworzymy obiekt jQTouch i ustawiamy jego opcję icon. Obiekt jQTouch udostępnia wiele właściwości, dzięki którym można spersonalizować zachowanie i wygląd aplikacji. Kilka z nich omówimy w dalszej części książki. Co prawda wszystkie te właściwości są opcjonalne, ale w większości przypadków i tak trzeba użyć co najmniej kilku. Zastosowana w przykładzie właściwość icon odpowiada za ikonę wyświetlaną na ekranie domowym. Na rysunku 4.1 widać aplikację przed zastosowaniem biblioteki jQTouch, a na rysunku 4.2 — po jej dołączeniu. Różnica jest niesamowita, ale naprawdę zadziwiające jest to, że wystarczyło kilka linii kodu, by uzyskać efekt przewijania stron. Robi wrażenie, prawda? A to dopiero początek! 1

Szczegółowe informacje na temat biblioteki Zepto można znaleźć na stronie http://zeptojs.com/ — przyp. tłum.

78



Rozdział 4. Animacje

Ebookpoint.pl kopia dla: Rodenko David [email protected]

Rysunek 4.1. Aplikacja Kilo bez jQTouch…

Ekran Terminarz Teraz zajmiemy się ekranem Terminarz. Ma się na nim znaleźć lista dni zaczynająca się dzisiaj, a kończąca pięć dni wcześniej. W dokumencie HTML po kodzie ekranu O Kilo (ale przed zamykającym znacznikiem ) wpisz kod z listingu 4.3. Trzeba będzie jeszcze uzupełnić nawigację na ekranie głównym, ale tym zajmiemy się za moment. Listing 4.3. Kod HTML ekranu Terminarz Terminarz Wstecz

Ekran Terminarz

Ebookpoint.pl kopia dla: Rodenko David [email protected]



79

Rysunek 4.2. …i po dołączeniu biblioteki 5 dni temu

Podobnie jak na ekranie O Kilo, tu również ma się znaleźć pasek z tytułem i przycisk Wstecz. Dodatkowo umieściliśmy nienumerowaną listę odsyłaczy z przypisaną klasą edgetoedge. Zwróć uwagę, że wszystkie odsyłacze mają unikalne identyfikatory (od 0 do 5), ale tę samą wartość atrybutu href (#date) — dlaczego tak jest, dowiesz się niebawem.

80



Rozdział 4. Animacje

Ebookpoint.pl kopia dla: Rodenko David [email protected]

Następnie w kodzie głównego ekranu musimy umieścić odsyłacz do ekranu Terminarz (nowy kod jest wyróżniony pogrubieniem): Kilo Terminarz O Kilo

W ten oto sposób dodaliśmy do aplikacji kolejny ekran (rysunek 4.3). Po kliknięciu odsyłacza Terminarz zostanie wyświetlony ekran Terminarz (rysunek 4.4). Odsyłacze znajdujące się na tym ekranie na razie nie działają. Poradzimy sobie z tym problemem, tworząc ekran wyświetlający dni (czyli ekran Dzień).

Rysunek 4.3. Na głównym ekranie pojawił się odsyłacz Terminarz Ekran Terminarz

Ebookpoint.pl kopia dla: Rodenko David [email protected]



81

Rysunek 4.4. Ekran Terminarz zawiera pasek z tytułem i przyciskiem Wstecz oraz listę odsyłaczy do kolejnych dni

Ekran Dzień Ekran Dzień przypomina poprzednie ekrany z kilkoma drobnymi różnicami (spójrz na listing 4.4). Dopisz przedstawiony kod HTML pod kodem ekranu Dates, ale przed znacznikiem zamykającym . Listing 4.4. Kod HTML ekranu Dzień Dzień Wstecz +

82



Rozdział 4. Animacje

Ebookpoint.pl kopia dla: Rodenko David [email protected]

Etykieta 000 Usuń

Na pasku umieściliśmy dodatkowy przycisk. Po jego kliknięciu zostanie wyświetlony ekran Nowy wpis (którego jeszcze nie przygotowaliśmy). Odsyłaczowi jest przypisana klasa slideup, dzięki której podczas zmiany ekranów zostanie zastosowany efekt przewijania w górę, a nie, jak dotąd, z lewej lub z prawej strony. Kolejnym elementem odróżniającym ten ekran od pozostałych jest ustawienie stylu display:none w pozycji listy, co powoduje jej ukrycie. Jak wkrótce zobaczysz, użyjemy tej niewidocznej pozycji listy jako szablonu dla wyświetlanych wpisów. Na razie nie ma jednak żadnych wpisów, więc lista jest pusta. Po dodaniu kodu kliknięcie dowolnej pozycji na ekranie Terminarz spowoduje wyświetlenie ekranu Dzień (rysunek 4.5).

Ekran Nowy wpis Na listingu 4.5 znajduje się kod ekranu Nowy wpis. Umieść go na końcu pliku index.html (oczywiście przed zamykającym znacznikiem ). Listing 4.5. Kod HTML ekranu Nowy wpis Nowy wpis Anuluj

Pierwszym, na co należy zwrócić uwagę na ekranie Nowy wpis, jest inna nazwa przycisku — zamiast Wstecz jest Anuluj. Ekran Nowy wpis

Ebookpoint.pl kopia dla: Rodenko David [email protected]



83

Rysunek 4.5. Na razie ekran Dzień jest pusty (poza paskiem z tytułem i dwoma przyciskami)

Przycisk Anuluj (klasa cancel) zachowuje się w jQTouch tak samo jak przycisk Wstecz (klasa back), czyli usuwa bieżący ekran z zastosowaniem animacji odwrotnej do tej, która jest stosowana podczas pojawiania się ekranu. Można jednak zauważyć różnicę w wyglądzie — przycisk Anuluj nie ma charakterystycznego kształtu strzałki skierowanej w lewo. Zastosowaliśmy tu przycisk Anuluj ze względu na to, że ekran Nowy wpis jest wyświetlany z efektem wjazdu z góry, więc jego ukrywaniu powinien towarzyszyć ekran zjazdu w dół. Gdybyśmy użyli przycisku Wstecz, doprowadzilibyśmy do niekonsekwencji, ponieważ po naciśnięciu przycisku ze strzałką skierowaną w lewo ekran zjechałby w dół (a to mogłoby zmylić użytkowników).

84



Rozdział 4. Animacje

Ebookpoint.pl kopia dla: Rodenko David [email protected]

Formularz zawiera nienumerowaną (wypunktowaną) listę trzech elementów: dwóch pól tekstowych i przycisku potwierdzenia. Dzięki osadzeniu kontrolek formularza w elemencie li zostaną do nich zastosowane style jQTouch (rysunek 4.6).

Rysunek 4.6. Do elementów formularza zostały zastosowane style z jQTouch

W polach tekstowych umieściliśmy kilka atrybutów: type="text"

Definiuje kontrolkę formularza jako jednowierszowe pole tekstowe.

placeholder

Łańcuch tekstowy wyświetlany w pustym polu formularza.

name

Nazwa pola, która po przesłaniu formularza zostanie powiązana z wartością wpisaną przez użytkownika.

Ekran Nowy wpis

Ebookpoint.pl kopia dla: Rodenko David [email protected]



85

id

Unikalny identyfikator elementu w kontekście całej strony.

autocapitalize

Steruje automatyczną zamianą wprowadzanych liter na wielkie (działa tylko w przeglądarce Mobile Safari w iOS).

autocorrect

Steruje funkcją sprawdzania pisowni w przeglądarce Mobile Safari w iOS (nie działa na Androidzie).

autocomplete

Steruje funkcją automatycznego uzupełniania w przeglądarce Mobile Safari w iOS (nie działa na Androidzie).

Atrybut class przycisku przesyłającego formularz wymaga dokładniejszego wyjaśnienia. Przeglądarka Androida wyświetla klawiaturę ekranową, gdy kursor znajdzie się w polu formularza. W prawym dolnym rogu klawiatury znajduje się przycisk Idź, który służy do przesyłania formularza. W sytuacji, gdy przechwytujemy funkcję przesyłania (a tak się dzieje w omawianym przykładzie), wciśnięcie tego przycisku nie spowoduje usunięcia kursora z aktywnego pola, w związku z czym klawiatura nie zniknie z ekranu. Biblioteka jQTouch umożliwia rozwiązanie tego problemu poprzez automatyczne usuniecie kursora z pola po zatwierdzeniu formularza. Aby skorzystać z tej funkcji, do przycisku przesyłającego formularz trzeba przypisać klasę submit. Na rysunku 4.7 widać działający formularz Nowy wpis. Na razie nie zajęliśmy się faktycznym zapisywaniem wprowadzonych danych — omówimy to w rozdziale 5.

Ekran Ustawienia Do tej pory nie utworzyliśmy przycisku umożliwiającego przejście do ekranu Ustawienia. Zrobimy to teraz, dodając przycisk do paska tytułowego na głównym ekranie. W tym celu wystarczy dodać jedną linię kodu HTML (na listingu wyróżnioną pogrubieniem): Kilo Ustawienia

86



Rozdział 4. Animacje

Ebookpoint.pl kopia dla: Rodenko David [email protected]

Rysunek 4.7. Klawiatura ekranowa w formularzu Nowy wpis Terminarz O Kilo …pozostała część dokumentu HTML nie została zamieszczona…

W tym miejscu dodajemy przycisk (rysunek 4.8). Zwróć uwagę, że do odsyłacza przypisaliśmy klasę flip. Dzięki temu przejściu z ekranu głównego do ekranu Ustawienia będzie towarzyszył efekt obrócenia wokół osi pionowej. Dodatkowo, dla wzmocnienia efektu, strona jest lekko skalowana podczas animacji. Ładnie, prawda? Niestety ze wsparciem dla trójwymiarowych animacji w przeglądarkach urządzeń mobilnych bywa różnie (dotyczy to również Androida). Z tego względu na niektórych urządzeniach wszelkie obroty, przejścia i inne animacje 3D mogą zostać zastąpione dwuwymiarowymi odpowiednikami.

Ekran Ustawienia

Ebookpoint.pl kopia dla: Rodenko David [email protected]



87

Rysunek 4.8. Przycisk Ustawienia umieszczony w pasku na ekranie głównym

Kod ekranu Ustawienia (listing 4.6) jest bardzo podobny do tego, czym zajmowaliśmy się przed chwilą, czyli ekranu Nowy wpis. Znajduje się tu jedno pole tekstowe więcej, niektóre atrybuty są pominięte, niektóre mają inne wartości, ale sama koncepcja pozostaje podobna. Do dokumentu HTML dopisz kod z poniższego listingu, tak jak to robiłeś dla innych ekranów. Listing 4.6. Kod HTML ekranu Ustawienia Ustawienia Anuluj

88



Rozdział 4. Animacje

Ebookpoint.pl kopia dla: Rodenko David [email protected]



Podobnie jak w przypadku formularza Nowy wpis, w formularzu Ustawienia też nie ma jeszcze możliwości zapisania wprowadzonych danych (patrz rysunek 4.9). Problem ten rozwiążemy w kolejnym rozdziale.

Rysunek 4.9. Ekran Ustawienia

Integracja całości I to by było na tyle. Wystarczyło napisać niewiele ponad sto linii kodu HTML, by otrzymać pięcioekranową aplikację wyglądającą i zachowującą się jak natywna. Zastosowaliśmy w niej trzy różne efekty przejścia między ekranami. Pełny listing aplikacji znajdziesz na listingu 4.7. Nie wygląda to źle, prawda?

Integracja całości

Ebookpoint.pl kopia dla: Rodenko David [email protected]



89

Listing 4.7. Kompletny listing pięcioekranowej aplikacji Kilo var jQT = $.jQTouch({ icon: 'kilo.png' }); Kilo Ustawienia Terminarz O Kilo O Kilo Wstecz Aplikacja Kilo pomaga stosować dowolną dietę. Terminarz Wstecz Dzisiaj Wczoraj 2 dni temu 3 dni temu 4 dni temu 5 dni temu

90



Rozdział 4. Animacje

Ebookpoint.pl kopia dla: Rodenko David [email protected]

Dzień Wstecz + Etykieta 000 Usuń Nowy wpis Anuluj Ustawienia Anuluj

Integracja całości

Ebookpoint.pl kopia dla: Rodenko David [email protected]



91

Dostosowywanie biblioteki jQTouch Domyślne zachowanie jQTouch możesz dostosować do własnych potrzeb, przekazując w konstruktorze zestaw właściwości. W omawianym przykładzie skorzystaliśmy tylko z jednej — icon — ale dostępnych jest znacznie więcej. Z całą pewnością warto się z nimi zapoznać (tabela 4.1). Tabela 4.1. Opcje dostosowywania jQTouch Właściwość

Domyślna wartość

Oczekiwane wartości

Uwagi

addGlossToIcon

true

true albo false

Jeśli jest ustawione na true, do ikony na ekranie domowym zostanie dodana poświata (działa w iOS, ale nie w Androidzie)

backSelector

'.back, .cancel, .goback'

Dowolny poprawny selektor CSS; poszczególne wartości oddzielane przecinkami

Definiuje elementy, które po kliknięciu (bądź puknięciu) mają wyzwalać zachowanie powrotu polegające na usunięciu bieżącego ekranu z zastosowaniem przeciwnej animacji i usunięcie go z historii

cacheGetRequests

true

true albo false

Jeśli jest ustawione na true, wszystkie żądania GET są cachowane, więc kolejne wywołania korzystają z pobranych już danych

cubeSelector

'.cube'

Dowolny poprawny selektor CSS; poszczególne wartości oddzielane przecinkami

Definiuje elementy, które wyzwalają animację „cube” podczas zmiany ekranów

dissolveSelector

'.dissolve'

Dowolny poprawny selektor CSS; poszczególne wartości oddzielane przecinkami

Definiuje elementy, które wyzwalają animację „dissolve” podczas zmiany ekranów

fadeSelector

'.fade'

Dowolny poprawny selektor CSS; poszczególne wartości oddzielane przecinkami

Definiuje elementy, które wyzwalają animację „fade” podczas zmiany ekranów

fixedViewport

true

true albo false

Ustawione na true blokuje możliwość skalowania strony

flipSelector

'.flip'

Dowolny poprawny selektor CSS; poszczególne wartości oddzielane przecinkami

Definiuje elementy, które wyzwalają animację „flip” podczas zmiany ekranów

92



Rozdział 4. Animacje

Ebookpoint.pl kopia dla: Rodenko David [email protected]

Tabela 4.1. Opcje dostosowywania jQTouch — ciąg dalszy Właściwość

Domyślna wartość

formSelector

'form'

fullScreen

Oczekiwane wartości

Uwagi

Dowolny poprawny selektor CSS; poszczególne wartości oddzielane przecinkami

Definiuje elementy, które powinny odbierać zdarzenie

true

true albo false

Działa tylko w iOS. Jeśli jest ustawione na true i aplikacja jest uruchamiana z ekranu domowego, zostanie otwarta w trybie pełnoekranowym. Ta opcja nie działa, jeśli aplikacja jest uruchamiana z poziomu przeglądarki Mobile Safari

fullScreenClass

'fullscreen'

łańcuch tekstowy

Działa tylko w iOS. Nazwa klasy, która zostanie zastosowana do sekcji body po uruchomieniu aplikacji w trybie pełnoekranowym. Dzięki temu można zdefiniować style stosowane tylko w tym przypadku

icon

null

null bądź względna lub bezwzględna ścieżka do pliku PNG

Ikona aplikacji umieszczana na ekranie domowym. Ten obraz zostanie wyświetlony po dodaniu do ekranu domowego zakładki do aplikacji

popSelector

'.pop'

Dowolny poprawny selektor CSS; poszczególne wartości oddzielane przecinkami

Definiuje elementy, które wyzwalają animację „pop” podczas zmiany ekranów

preloadImages

false

Tablica ścieżek do obrazów

Definiuje obrazy, które mają zostać pobrane przed załadowaniem strony (na przykład:

onsubmit

['images/link_over.png', 'images/link_select.png']) slideInSelector

'ul li a'

Dowolny poprawny selektor CSS; poszczególne wartości oddzielane przecinkami

Definiuje elementy, które wyzwalają animację „slide in” podczas zmiany ekranów

slideupSelector

'.slideup'

Dowolny poprawny selektor CSS; poszczególne wartości oddzielane przecinkami

Definiuje elementy, które wyzwalają animację „slide up” podczas zmiany ekranów

Dostosowywanie biblioteki jQTouch

Ebookpoint.pl kopia dla: Rodenko David [email protected]



93

Tabela 4.1. Opcje dostosowywania jQTouch — ciąg dalszy Właściwość

Domyślna wartość

startupScreen

Oczekiwane wartości

Uwagi

Null

null bądź względna lub bezwzględna ścieżka do pliku obrazu

Działa tylko w iOS. Względna lub bezwzględna ścieżka do pliku z obrazem startowym (320×460 pikseli) dla pełnoekranowych aplikacji. Jeśli opcja statusBar jest ustawiona na black-translucent , obraz powinien mieć wymiary 320×480 pikseli.

statusBar

'default'

default, blacktranslucent, black

Działa tylko w iOS. Definiuje wygląd 20-pikselowego paska stanu znajdującego się na górze okna aplikacji działającej w trybie pełnoekranowym

submitSelector

'.submit'

Dowolny poprawny selektor CSS; poszczególne wartości oddzielane przecinkami

Selektor elementu, który ma przesyłać nadrzędny formularz (i zamykać panel klawiatury ekranowej)

swapSelector

'.swap'

Dowolny poprawny selektor CSS; poszczególne wartości oddzielane przecinkami

Definiuje elementy, które wyzwalają animację „swap” podczas zmiany ekranów

useAnimations

true

true albo false

Ustawienie na false powoduje wyłączenie wszystkich animacji

Czego się nauczyłeś? Z tego rozdziału dowiedziałeś się, jak dzięki bibliotece jQTouch dodać do aplikacji internetowej animacje charakterystyczne dla aplikacji natywnych. W kolejnym rozdziale nauczysz się korzystać z mechanizmu lokalnego składowania danych oraz poznasz możliwości baz danych działających po stronie klienta, by zapisywać dane wymagane przez tworzone aplikacje.

94



Rozdział 4. Animacje

Ebookpoint.pl kopia dla: Rodenko David [email protected]

ROZDZIAŁ 5.

Składowanie danych po stronie klienta

Większość aplikacji musi przechowywać dane w jakiś trwały sposób. Do niedawna w przypadku klasycznych aplikacji internetowych do wyboru były dwa rozwiązania — skorzystanie z bazy danych na serwerze lub ciasteczek w przeglądarce. Wraz z HTML5 pojawiły się nowe możliwości: Web Storage oraz Web SQL Database1.

Web Storage Istnieją dwa mechanizmy Web Storage: localStorage oraz sessionStorage. Swoim działaniem przypominają trochę ciasteczka — z poziomu JavaScriptu można zapisywać pary klucz — wartość, które są przechowywane nawet po przeładowaniu strony. W przeciwieństwie do ciasteczek dane Web Storage nie są przesyłane do serwera wraz z żądaniem zgłaszanym przez przeglądarkę — cały czas znajdują się po stronie klienta. Z tego względu możliwe jest zapisanie znacznie większej ilości danych. Do tej pory nie został jasno sprecyzowany limit rozmiaru Web Storage. W większości przeglądarek jest to około 2,5 lub 5 MB.

1

Organizacja W3C zarzuciła prace nad Web SQL Database w listopadzie 2010 roku, ale nadal są rozwijane standardy Web Storage oraz Indexed Database API — przyp. tłum.

95

Ebookpoint.pl kopia dla: Rodenko David [email protected]

Funkcjonalność localStorage i sessionStorage jest identyczna, ale te dwa mechanizmy różnią się trwałością danych oraz zakresem: localStorage

Dane pozostają trwale zapisane nawet po zamknięciu okna przeglądarki. Poza tym dane są dostępne we wszystkich oknach (lub kartach) przeglądarki, które zostały otwarte z tego samego źródła (musi się zgadzać domena, protokół i port). Przykładowym zastosowaniem może być zapisywanie preferencji aplikacji.

sessionStorage

Dane są przechowywane w obiekcie window i usuwane po zamknięciu okna. Inne okna (lub karty) przeglądarki nie mają dostępu do danych. Przykładowe zastosowania to zapisywanie tymczasowego stanu aplikacji (na przykład wybrana zakładka czy ustalona kolejność sortowania tabeli). W każdym z poniższych przykładów localStorage możesz zamienić na sessionStorage, ale pamiętaj, że dane zapisane w sessionStorage znikają po zamknięciu okna lub karty przeglądarki.

Ustawianie wartości jest dziecinnie proste: localStorage.setItem('age', 40);

Odczytanie zapisanej wartości jest równie łatwe: var age = localStorage.getItem('age');

Aby usunąć określoną parę klucz — wartość, należy wykonać kod: localStorage.removeItem('age');

Można też usunąć wszystkie dane: localStorage.clear();

Zakładając, że klucze są nazwami poprawnymi z perspektywy JavaScriptu (nie zawierają spacji i symboli z wyjątkiem znaku podkreślenia), można zastosować alternatywny zapis: localStorage.age = 40 // Ustawienie wartości dla klucza 'age' var age = localStorage.age; // Pobranie wartości dla klucza 'age' delete localStorage.age; // Usunięcie wpisu 'age'

Mechanizmy localStorage i sessionStorage są traktowane oddzielnie, więc bez niebezpieczeństwa konfliktu możesz w nich zapisywać wartości przypisane tym samym kluczom.

96



Rozdział 5. Składowanie danych po stronie klienta

Ebookpoint.pl kopia dla: Rodenko David [email protected]

Zapisywanie ustawień aplikacji w localStorage Sprawdzimy to na praktycznym przykładzie. Zmodyfikujemy ekran Ustawienia, który przygotowaliśmy w rozdziale 4., tak by dane wprowadzane w formularzu były zapisywane w localStorage. Ponieważ w tym rozdziale napiszemy sporo kodu JavaScript, utworzymy plik kilo.js, w którym zawrzemy cały skrypt. Unikniemy w ten sposób bałaganu w dokumencie HTML i ułatwimy utrzymanie kodu. Nowy plik zapisz w tym samym katalogu co plik HTML, a w sekcji nagłówka dokumentu dodaj znacznik dołączający skrypt kilo.js: Kilo

Jeśli jesteś spostrzegawczy, zauważyłeś, że z sekcji nagłówka usunęliśmy skrypt z konstruktorem jQTouch. Bez obaw — nie zniknął — przenieśliśmy go do pliku kilo.js. Zmodyfikuj swój dokument HTML, utwórz plik kilo.js, wpisz do niego poniższy kod i przeładuj stronę w przeglądarce. var jQT = $.jQTouch({ icon: 'kilo.png' });

Po tej małej reorganizacji kodu przyszedł czas na zaimplementowanie funkcji zapisującej ustawienia. Musimy zmodyfikować dotychczasową akcję wywoływaną przez formularz Ustawienia na wywołanie nowej funkcji saveSettings(). Dzięki jQuery zadanie to można zrealizować za pomocą jednej linii kodu umieszczonej w funkcji ready. Do pliku kilo.js dopisz poniższy kod: $(document).ready(function(){ $('#settings form').submit(saveSettings); });

W wyniku tej zmiany zatwierdzenie formularza spowoduje wywołanie funkcji saveSettings(), a nie przesłanie danych formularza. Funkcja saveSettings() pobiera wartości z trzech pól formularza za pomocą metody val() dostarczanej przez jQuery, a następnie zapisuje je w localStorage. Do skryptu kilo.js dodaj poniższy kod:

Web Storage

Ebookpoint.pl kopia dla: Rodenko David [email protected]



97

function saveSettings() { localStorage.age = $('#age').val(); localStorage.budget = $('#budget').val(); localStorage.weight = $('#weight').val(); jQT.goBack(); return false; }

Po zapisaniu wartości zostaje wywołana funkcja goBack() (w przedostatnim wierszu kodu), która powoduje opuszczenie bieżącego ekranu i przejście do poprzedniego. Funkcja zwraca wartość false, aby nie została wykonana domyślna akcja zdarzenia zatwierdzenia formularza. Gdybyśmy pominęli tę linię, strona zostałaby przeładowana, a tego chcemy uniknąć. Teraz użytkownik może uruchomić aplikację, przejść na ekran Ustawienia, wprowadzić dane i zatwierdzić formularz — dane zostaną zapisane w localStorage. Ponieważ nie wyczyściliśmy pól po zapisaniu danych, przy ponownym wyświetleniu ekranu Ustawienia będą wypełnione ostatnio wprowadzonymi wartościami. Nie wynika to jednak z faktu, że zapisaliśmy je w localStorage — są tam, ponieważ je wpisaliśmy. Z tego względu po ponownym uruchomieniu aplikacji pola w formularzu Ustawienia będą puste, mimo że dane zostały zapisane. Aby rozwiązać ten problem, musimy załadować ustawienia. Dodaj do skryptu funkcję loadSettings(): function loadSettings() { $('#age').val(localStorage.age); $('#budget').val(localStorage.budget); $('#weight').val(localStorage.weight); }

Działanie funkcji loadSettings() jest przeciwieństwem funkcji saveSettings() — odczytuje z localStorage wartości trzech pól i — za pomocą metody val() — ustawia pola formularza. Skoro mamy już funkcję loadSettings(), musimy ją jeszcze wywołać. Najlepiej będzie ją wywołać w chwili uruchamiania aplikacji. W tym celu do funkcji ready dodaj wyróżniony kod: $(document).ready(function(){ $('#settings form').submit(saveSettings); loadSettings(); });

98



Rozdział 5. Składowanie danych po stronie klienta

Ebookpoint.pl kopia dla: Rodenko David [email protected]

Niestety ładowanie ustawień tylko podczas uruchamiania aplikacji pozostawia pewną lukę — co będzie, jeśli użytkownik przejdzie na ekran Ustawienia, zmieni jakieś wartości, a następnie anuluje zmiany przyciskiem Anuluj? W takim przypadku po ponownym wyświetleniu formularza w polach pojawią się ostatnio wprowadzone wartości, mimo że nie zostały zatwierdzone. Gdyby użytkownik zamknął aplikację i ponownie ją uruchomił, w polach znalazłyby się prawidłowe, zapisane wcześniej wartości, ponieważ funkcja loadSettings() odczytałaby je z localStorage. Istnieje kilka sposobów na obejście tego problemu, ale chyba najbardziej odpowiednim w tym przypadku będzie wywoływanie funkcji ładującej ustawienia za każdym razem, gdy ekran Ustawienia jest wyświetlany (lub ukrywany). Dzięki jQTouch zadanie jest bardzo proste. Wystarczy powiązać funkcję loadSettings() ze zdarzeniem pageAnimationStart dla ekranu Ustawienia. Za-

mień ostatnio dodany wiersz na wyróżniony kod: $(document).ready(function(){ $('#settings form').submit(saveSettings); $('#settings').bind('pageAnimationStart', loadSettings); });

Pozostaje jednak pewien problem — jeśli w localStorage nie zostały jeszcze zapisane dane, funkcja loadSettings() nie zmieni wartości pól formularza. Musimy więc uzupełnić tę funkcję o kod ustawiający puste wartości w polach, które nie są zdefiniowane: if (!localStorage.age) { localStorage.age = ""; } if (!localStorage.budget) { localStorage.budget = ""; } if (!localStorage.weight) { localStorage.weight = ""; }

W pliku kilo.js mamy już kompletny kod zapisujący dane z ekranu Ustawienia. Zwróć uwagę, że nie jest ani zbyt obszerny, ani zbyt skomplikowany: var jQT = $.jQTouch({ icon: 'kilo.png' }); $(document).ready(function(){ $('#settings form').submit(saveSettings); $('#settings').bind('pageAnimationStart', loadSettings); }); function saveSettings() {

Web Storage

Ebookpoint.pl kopia dla: Rodenko David [email protected]



99

localStorage.age = $('#age').val(); localStorage.budget = $('#budget').val(); localStorage.weight = $('#weight').val(); jQT.goBack(); return false; } function loadSettings() { if (!localStorage.age) { localStorage.age = ""; } if (!localStorage.budget) { localStorage.budget = ""; } if (!localStorage.weight) { localStorage.weight = ""; } $('#age').val(localStorage.age); $('#budget').val(localStorage.budget); $('#weight').val(localStorage.weight); }

Zapisywanie daty w sessionStorage Dążymy do tego, by na ekranie Dzień była wyświetlana lista wpisów z danego dnia zapisanych w bazie danych. Aby to zrealizować, musimy znać dzień, który użytkownik wybrał na ekranie Terminarz. Chcemy też, by użytkownik mógł dodawać i usuwać wpisy, więc musimy zaimplementować obsługę przycisku + znajdującego się na ekranie Dzień oraz przycisku Usuń z szablonu wpisu (tym zajmiemy się trochę później). Zaczniemy od zapisania daty, którą użytkownik wybrał na ekranie Terminarz, tak by można ją było odczytać na ekranie Dzień. Dzięki informacji o numerze wybranej pozycji można wyznaczyć właściwą datę. W skrypcie kilo.js do funkcji ready dokumentu dopisz wyróżniony kod: $(document).ready(function(){ $('#settings form').submit(saveSettings); $('#settings').bind('pageAnimationStart', loadSettings); $('#dates li a').bind('click touchend', function(){ var dayOffset = this.id; var date = new Date(); date.setDate(date.getDate() - dayOffset); sessionStorage.currentDate = date.getDate() + '.' + (date.getMonth() + 1) + '.' + date.getFullYear(); refreshEntries(); }); });

100



Rozdział 5. Składowanie danych po stronie klienta

Ebookpoint.pl kopia dla: Rodenko David [email protected]

W tym miejscu za pomocą metody bind() z jQuery wiążemy kod anonimowej funkcji ze zdarzeniami click oraz touchend odsyłaczy z ekranu Terminarz. Zdarzenie touchend stosujemy ze względu na urządzenia z ekranami dotykowymi, a click po to, by móc testować ten kod w przeglądarkach desktopowych (które nie obsługują zdarzenia touchend). Tu pobieramy identyfikator klikniętego obiektu i zapisujemy go w zmiennej dayOffset. Jak pewnie pamiętasz, odsyłacze z panelu Terminarz mają identyfikatory od 0 do 5, więc otrzymana wartość jest równoważna liczbie dni, którą trzeba odliczyć od dzisiaj (pozycji Dzisiaj odpowiada wartość 0, Wczoraj — 1, 2 dni temu — 2 itd.). W tym przypadku słowo kluczowe this będzie zawierało referencję do obiektu, który był celem zdarzenia click lub touchend.

W tym wierszu tworzymy obiekt Date i zapisujemy go w zmiennej date. Początkową wartością jest bieżąca data, więc aby otrzymać pożądaną datę, wystarczy od niej odjąć przesunięcie zapisane w zmiennej dayOffset. Wynik tej operacji zapisujemy w tym samym obiekcie za pomocą metody setDate(). Tutaj budujemy łańcuch tekstowy zawierający datę w formacie DD.MM.RRRR i zapisujemy go w sessionStorage pod nazwą currentDate. Metoda getMonth() obiektu Date zwraca wartości z zakresu 0 – 11, gdzie 0 oznacza styczeń. Z tego względu, aby otrzymać prawidłowy zapis, do otrzymanej wartości musimy dodać 1.

Na końcu wywołujemy funkcję refreshEntries(). Jej zadaniem jest zaktualizowanie zawartości ekranu Dzień zgodnie z dniem wybranym przez użytkownika na ekranie Terminarz. Na razie, aby sprawdzić, czy to działa, ograniczymy się do wyświetlenia w pasku tytułowym aktualnej daty. Na rysunku 5.1 widać ekran Dzień bez aktualizacji paska tytułowego, a na rysunku 5.2 widać efekt wprowadzenia funkcji refreshEntries(). Do skryptu kilo.js dopisz poniższy kod: function refreshEntries() { var currentDate = sessionStorage.currentDate; $('#date h1').text(currentDate); }

Web Storage

Ebookpoint.pl kopia dla: Rodenko David [email protected]



101

Rysunek 5.1. Przed wprowadzeniem funkcji refreshEntries() w pasku tytułu był wyświetlany tekst „Dzień”…

Teraz zajmiemy się mechanizmem składowania danych po stronie klienta o znacznie większych możliwościach. Posłuży nam do zapisywania wpisów z ekranu Dzień.

Web SQL Database Specyfikacja Web SQL Database daje programistom do dyspozycji prosty interfejs API o całkiem sporych możliwościach, dzięki któremu mogą zapisywać dane w lokalnej bazie danych SQLite2. 2

Technologia Web SQL Database nie jest obsługiwana przez wszystkie przeglądarki. Szczegółowe informacje dotyczące wsparcia można znaleźć na stronie http://caniuse.com/sql-storage — przyp. tłum.

102



Rozdział 5. Składowanie danych po stronie klienta

Ebookpoint.pl kopia dla: Rodenko David [email protected]

Rysunek 5.2. …a po dodaniu funkcji refreshEntries() widać wybraną datę Tak naprawdę specyfikacja Web SQL Database nie jest już częścią HTML5 po tym, jak organizacja W3C porzuciła prace nad nią. Mimo to często można się spotkać ze stwierdzeniem, że ta technologia należy do HTML5.

Programiści mogą stosować standardowe instrukcje SQL, by tworzyć tabele oraz wstawiać, modyfikować, wybierać i usuwać wiersze. Javascriptowy interfejs API obsługuje nawet transakcje. Z tego wniosek, że będziemy musieli pomówić trochę o języku SQL, ale nie przejmuj się — nie jest to z pewnością stracony czas, bo ta wiedza może Ci się jeszcze nieraz przydać.

Web SQL Database

Ebookpoint.pl kopia dla: Rodenko David [email protected]



103

Tworzenie bazy danych Teraz, kiedy na ekranie Dzień mamy dostęp do informacji o wybranym dniu, możemy zająć się obsługą dodawania nowych wpisów. Zanim jednak napiszemy funkcję createEntry(), musimy utworzyć bazę danych oraz tabelę, w której będziemy przechowywać dane wprowadzone przez użytkownika (tę operację wykonuje się tylko jeden raz). Do skryptu kilo.js dopisz wyróżniony kod: var db; $(document).ready(function(){ $('#settings form').submit(saveSettings); $('#settings').bind('pageAnimationStart', loadSettings); $('#dates li a').bind('click touchend', function(){ var dayOffset = this.id; var date = new Date(); date.setDate(date.getDate() - dayOffset); sessionStorage.currentDate = date.getDate() + '.' + (date.getMonth() + 1) + '.' + date.getFullYear(); refreshEntries(); }); var shortName = 'Kilo'; var version = '1.0'; var displayName = 'Kilo'; var maxSize = 65536; db = openDatabase(shortName, version, displayName, maxSize); db.transaction( function(transaction) { transaction.executeSql( 'CREATE TABLE IF NOT EXISTS entries ' + ' (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, ' + ' date DATE NOT NULL, food TEXT NOT NULL, ' + ' calories INTEGER NOT NULL );' ); } ); });

W globalnej przestrzeni aplikacji utworzyliśmy zmienną db. Posłuży ona do przechowania referencji do obiektu reprezentującego połączenie z bazą danych. Jest to zmienna globalna, ponieważ musi być dostępna z wielu różnych miejsc aplikacji. W tym miejscu definiujemy zmienne wykorzystywane w wywołaniu funkcji openDatabase(): shortName

Łańcuch określający nazwę pliku bazy danych.

104



Rozdział 5. Składowanie danych po stronie klienta

Ebookpoint.pl kopia dla: Rodenko David [email protected]

version

Numer wersji przydatny w przypadku uaktualnień i zmian w schemacie bazy danych (dzięki temu w chwili uruchamiania aplikacji możesz sprawdzić wersję bazy danych, i jeśli jest to stara wersja, utworzyć nową bazę, a następnie przenieść dane ze starszej wersji; mechanizm jest opisany w rozdziale 7. w punkcie „Geolokalizacja”).

displayName

Łańcuch z nazwą bazy danych wyświetlany w interfejsie użytkownika, na przykład w zakładce Storage w panelu Narzędzia dla programistów w desktopowej przeglądarce Chrome (aby włączyć panel, kliknij ikonę klucza, a następnie z menu Narzędzia wybierz Narzędzia dla programistów3).

maxSize

Maksymalny rozmiar bazy danych. Maksymalny rozmiar bazy danych zależy od implementacji w konkretnej przeglądarce i przeważnie wynosi 5 MB. Jeśli baza danych urośnie poza ten limit, użytkownik zostanie zapytany o możliwość jego zwiększenia. Jeśli się zgodzi, maksymalny rozmiar bazy danych wzrośnie do 10 MB, a jeśli odmówi, zostanie zwrócony błąd QUOTA_ERR. Listę wszystkich kodów błędów bazy danych znajdziesz w tabeli 5.1.

Po ustawieniu wartości parametrów wywołujemy funkcję openDatabase() i zapisujemy zwracany obiekt połączenia w zmiennej db. Jeśli baza danych nie istniała, zostanie utworzona. Wszystkie kwerendy muszą być wykonywane w transakcjach, więc wywołujemy metodę transaction() obiektu db, by rozpocząć transakcję. Kolejne wiersze kodu to funkcja przekazywana do tej metody jako jedyny parametr. W tym miejscu rozpoczyna się anonimowa funkcja, do której jest przekazywany obiekt transaction. Szczerze mówiąc, przekazywanie tego obiektu w funkcji zwrotnej transakcji jest dosyć dziwne (przecież można by użyć słowa kluczowego this), ale tak to właśnie wygląda. W funkcji na obiekcie transaction wywołujemy metodę executeSql(), która wykonuje standardową kwerendę CREATE TABLE. Klauzula IF NOT EXISTS zabezpiecza nas przed powtórnym utworzeniem tabeli.

3

Szybszą metodą jest skorzystanie ze skrótu klawiaturowego Ctrl+Shift+I — przyp. tłum.

Web SQL Database

Ebookpoint.pl kopia dla: Rodenko David [email protected]



105

Gdybyś teraz uruchomił aplikację, zostałaby utworzona baza danych o nazwie Kilo. W desktopowej wersji przeglądarki Chrome możesz wyświetlić i modyfikować bazę danych. W tym celu włącz panel Narzędzia dla programistów (kliknij ikonę klucza, po czym z menu Narzędzia wybierz Narzędzia dla programistów), a następnie przejdź na zakładkę Resources. Widać tam między innymi pozycje Databases, Local Storage i Session Storage. Narzędzia te są bardzo przydatne podczas pracy nad aplikacją. Domyślnie panel jest wyświetlany na dole okna przeglądarki, ale jeśli klikniesz ikonę oddokowania (pierwsza z lewej strony na pasku stanu), zostanie otwarty w nowym oknie, tak jak na rysunku 5.3. Narzędzie to pozwala nawet na wykonywanie kwerend SQL na wybranej bazie danych (patrz rysunek 5.4).

Rysunek 5.3. Zawartość tabeli entries wyświetlona w zakładce Storage w panelu Narzędzia dla programistów w przeglądarce Chrome

Wstawianie wierszy W utworzonej bazie danych możemy już umieścić wpisy, więc najwyższy czas na utworzenie funkcji createEntry(). Przede wszystkim musimy przesłonić domyślne zdarzenie przesyłania formularza #createEntry. W tym celu wystarczy w funkcji ready() dokumentu powiązać zdarzenie przesyłania z funkcją createEntry(). Oto fragment kodu z wyróżnionym dopisanym wierszem: 106



Rozdział 5. Składowanie danych po stronie klienta

Ebookpoint.pl kopia dla: Rodenko David [email protected]

Rysunek 5.4. Z poziomu zakładki Storage panelu Narzędzia dla programistów można wykonywać kwerendy SQL na wybranej bazie danych $(document).ready(function(){ $('#createEntry form').submit(createEntry); $('#settings form').submit(saveSettings); $('#settings').bind('pageAnimationStart', loadSettings); ...

Od teraz kiedy użytkownik zatwierdzi formularz #createEntry, zostanie wywołana funkcja createEntry(). Dodaj do pliku kilo.js poniższy kod tworzący rekord w bazie danych: function createEntry() { var date = sessionStorage.currentDate; var calories = $('#calories').val(); var food = $('#food').val(); db.transaction( function(transaction) { transaction.executeSql( 'INSERT INTO entries (date, calories, food) VALUES (?, ?, ?);', [date, calories, food], function(){ refreshEntries(); jQT.goBack(); }, errorHandler ); } ); return false; }

Web SQL Database

Ebookpoint.pl kopia dla: Rodenko David [email protected]



107

W tym fragmencie kodu znajduje się kilka zmiennych, które zostaną użyte w kwerendzie SQL. Jak zapewne pamiętasz (z punktu „Zapisywanie daty w sessionStorage” w tym rozdziale), data wybrana przez użytkownika na ekranie Terminarz jest zapisywana w sessionStorage.currentDate. Pozostałe dwie wartości (kalorie i posiłek) są odczytywane z pól formularza, dokładnie tak samo, jak to robiliśmy w przypadku ekranu Ustawienia. Tu otwieramy transakcję i — poprzez wywołanie metody executeSql() — uruchamiamy kwerendę. Metodzie tej przekazujemy cztery parametry: 'INSERT INTO entries (date, calories, food) VALUES (?, ?, ?);'

Instrukcja SQL, która zostanie wykonana. Znaki zapytania to symbole zastępcze, pod które zostaną podstawione wartości.

[date, calories, food]

Tablica wartości przekazywanych do bazy danych. Odpowiadają one symbolom zastępczym (znakom zapytania) z instrukcji SQL.

function(){refreshEntries();jQT.goBack();}

Anonimowa funkcja wykonywana po pomyślnym wykonaniu kwerendy SQL.

errorHandler

Nazwa funkcji, która zostanie wykonana w przypadku niepowodzenia podczas wykonywania kwerendy. Znaki cudzysłowu (' lub ") wokół symboli zastępczych ? nie są obowiązkowe, ponieważ wartości podstawianych danych są automatycznie dostosowywane do wymagań instrukcji SQL.

Obsługa błędów Jeśli operacja wstawiania wiersza kończy się sukcesem, wywołana zostaje anonimowa funkcja przekazywana jako trzeci parametr metody executeSql(). Wywołujemy w niej funkcję refreshEntries() (w tej chwili jej działanie sprowadza się jedynie do zaktualizowania tytułu ekranu Dzień, ale już niebawem dodamy kod wyświetlający utworzone wpisy), a także symulujemy kliknięcie przycisku Anuluj, dzięki czemu ukrywany jest ekran Nowy wpis, i powracamy do ekranu Dzień. Widzieliśmy już to wcześniej podczas prac nad ekranem Ustawienia — przycisk Anuluj nie powoduje tak naprawdę anulowania przeprowadzonej operacji, ponieważ jest to przycisk typu „wstecz” oznaczony jedynie etykietą Anuluj (bez charakterystycznej strzałki z lewej strony).

108



Rozdział 5. Składowanie danych po stronie klienta

Ebookpoint.pl kopia dla: Rodenko David [email protected]

Jeśli operacja wstawiania wiersza się nie powiodła, wywołana zostaje funkcja errorHandler(). Ponieważ jeszcze jej nie mamy, do skryptu kilo.js dopisz następujący kod: function errorHandler(transaction, error) { alert('Oj! Wystąpił błąd '+error.message+' (kod błędu: '+error.code+')'); return true; }

Funkcji obsługi błędu przekazywane są dwa parametry: obiekt transakcji oraz obiekt błędu. W powyższej funkcji korzystamy z obiektu błędu, by wyświetlić użytkownikowi komunikat błędu i jego kod. Funkcje obsługi błędu muszą zwracać wartość true albo false. Gdy funkcja zwróci true (co można wytłumaczyć jako: „Tak, to jest błąd krytyczny”), wykonywanie kodu zostanie wstrzymane, a cała transakcja cofnięta. Z kolei gdy zostanie zwrócona wartość false („Nie, to nie jest błąd krytyczny”), wykonywanie kodu będzie kontynuowane. W niektórych przypadkach wskazane jest zwrócenie odpowiedniej wartości w zależności od typu błędu. W tabeli 5.1 zamieszczonej na końcu tego rozdziału znajdziesz możliwe kody błędów wynikające z bieżącej wersji specyfikacji Web SQL Database.

Wykonywanie instrukcji SQL wewnątrz funkcji obsługi błędu Jak zauważyłeś, funkcja obsługi błędu otrzymuje jako jeden z parametrów obiekt transakcji. Całkiem możliwe, że w niektórych sytuacjach będziesz chciał wewnątrz tej funkcji wykonać jakąś instrukcję SQL, która na przykład dopisze błąd do tabeli z logami lub zapisze inne dane na potrzeby debugowania lub raportowania błędów. Jest to możliwe właśnie dzięki obiektowi transakcji, na którym można wykonać więcej wywołań metody executeSql(). Poniżej zamieściliśmy przykład takiego działania (aby zadziałał, w bazie danych musi się znajdować tabela errors): function errorHandler(transaction, error) { alert('Oj! Wystąpił błąd '+error.message+' (kod błędu: '+error.code+')'); transaction.executeSql('INSERT INTO errors (code, message) VALUES (?, ?);', [error.code, error.message]); return false; }

Zwróć szczególną uwagę na to, że w takim przypadku musimy zwrócić z funkcji obsługi błędu wartość false. Gdybyśmy zwrócili true (lub nic), cała transakcja, włącznie z wykonaną w funkcji instrukcją, zostałaby wycofana, a więc nie osiągnęlibyśmy zamierzonego rezultatu.

Web SQL Database

Ebookpoint.pl kopia dla: Rodenko David [email protected]



109

Co prawda nie zostanie to pokazane w przykładach z książki, ale istnieje możliwość zdefiniowania funkcji wykonywanych w przypadku powodzenia i błędu bezpośrednio w wywołaniu metody transaction(). Dzięki temu można w czytelny sposób zdefiniować operacje wykonywane po zakończeniu serii wywołań executeSql(). Niestety kolejność parametrów w metodzie transaction() jest odwrotna niż w executeSql() — pierwsza jest funkcja błędu, druga pomyślnego wykonania. Poniżej zamieściliśmy wersję kodu funkcji createEntry(), w której funkcje zwrotne dodaliśmy do wywołania transaction() (nie wstawiaj tego kodu do pliku kilo.js, ponieważ nie zdefiniowaliśmy tych funkcji): function createEntry() { var date = sessionStorage.currentDate; var calories = $('#calories').val(); var food = $('#food').val(); db.transaction( function(transaction) { transaction.executeSql( 'INSERT INTO entries (date, calories, food) VALUES (?, ?, ?);', [date, calories, food], function(){ refreshEntries(); jQT.goBack(); }, errorHandler ); }, transactionErrorHandler, transactionSuccessHandler ); return false; }

Wybieranie wierszy i obsługa otrzymanych danych Kolejnym krokiem jest uzupełnienie kodu funkcji refreshEntries(), tak by robiła coś więcej niż tylko ustawianie wybranej daty w pasku tytułowym. Jej podstawowym zadaniem ma być odpytanie bazy danych o wpisy z konkretnego dnia i dołączenie ich do elementu #date ul za pomocą ukrytej struktury #entryTemplate. Nie zaglądaliśmy już jakiś czas do kodu HTML, więc dla przypomnienia zamieszczamy odpowiedni fragment (on już jest w pliku index.html, więc nie musisz go dopisywać):

110



Rozdział 5. Składowanie danych po stronie klienta

Ebookpoint.pl kopia dla: Rodenko David [email protected]

Dzień Wstecz + Etykieta 000 Usuń

Elementowi li przypisaliśmy atrybut display: none, więc nie jest on wyświetlany na stronie. Zrobiliśmy tak, by móc użyć tego fragmentu jako szablonu dla wierszy odczytywanych z bazy danych. Oto kompletna funkcja refreshEntries() (kod funkcji z pliku kilo.js zamień na poniższy): function refreshEntries() { var currentDate = sessionStorage.currentDate; $('#date h1').text(currentDate); $('#date ul li:gt(0)').remove(); db.transaction( function(transaction) { transaction.executeSql( 'SELECT * FROM entries WHERE date = ? ORDER BY food;', [currentDate], function (transaction, result) { for (var i=0; i < result.rows.length; i++) { var row = result.rows.item(i); var newEntryRow = $('#entryTemplate').clone(); newEntryRow.removeAttr('id'); newEntryRow.removeAttr('style'); newEntryRow.data('entryId', row.id); newEntryRow.appendTo('#date ul'); newEntryRow.find('.label').text(row.food); newEntryRow.find('.calories').text(row.calories); } }, errorHandler ); } ); }

W tych dwóch wierszach w pasku tytułowym ekranu Dzień ustawiamy wartość currentDate zapisaną w sessionStorage.

Web SQL Database

Ebookpoint.pl kopia dla: Rodenko David [email protected]



111

Korzystamy tu z funkcji gt() pochodzącej z jQuery („gt” to skrót od „greater than”, czyli „więcej niż”), dzięki której wybieramy i usuwamy wszystkie elementy li o indeksie większym niż 0. Przy pierwszym wywołaniu funkcji nic się nie stanie, ponieważ na liście znajduje się tylko jeden element li — ten o identyfikatorze entryTemplate, który ma indeks 0 i jest ukryty. Przy kolejnych wywołaniach przed wypełnieniem listy danymi otrzymanymi z bazy musimyjednak usunąć wszystkie wstawione wcześniej elementy. Gdybyśmy tego nie zrobili, nowe pozycje byłyby dołączane do istniejących. W tych trzech wierszach konfigurujemy transakcję oraz instrukcję dla metody executeSql(). To jest pierwszy parametr metody executeSql() — prosta kwerenda SELECT z jednym symbolem zastępczym. To jest jednoelementowa tablica zawierająca aktualnie wybraną datę, która zostanie wstawiona w miejsce symbolu zastępczego w kwerendzie SQL. Anonimowa funkcja wywoływana po pomyślnym wykonaniu kwerendy. Przyjmuje dwa parametry: transaction oraz result. Obiekt transaction może posłużyć do przesłania nowych kwerend do bazy danych, tak samo jak w przypadku omówionej wcześniej funkcji obsługi błędu. W tym przypadku nie skorzystamy z tej możliwości, więc w ogóle nie użyjemy tego obiektu. Najbardziej interesuje nas obiekt result. Ma on trzy właściwości tylko do odczytu: rowsAffected, która przechowuje liczbę wierszy zmienionych w wyniku wstawiania, aktualizowania lub usuwania, insertId, która zwraca klucz główny ostatniego wiersza utworzonego przez operację wstawiania, oraz rows, która zawiera wiersze zwracane przez bazę danych. Obiekt rows może zawierać zero lub więcej obiektów row. Ma on też właściwość length przechowującą liczbę wierszy, z której korzystamy w poniższej instrukcji for. Za pomocą metody item() obiektu rows przypisujemy zmiennej row zawartość bieżącego wiersza. Tu, korzystając z metody clone(), klonujemy element li szablonu wpisu, a następnie — w dwóch kolejnych wierszach — usuwamy atrybuty id oraz style. Dzięki usunięciu atrybutu style element li staje się widoczny, a usunięcie id jest konieczne, ponieważ w dokumencie może występować tylko jeden element o danym identyfikatorze. W tym wierszu wpisujemy do elementu li wartość właściwości id obiektu row (będzie to potrzebne w operacji usuwania wpisów). 112



Rozdział 5. Składowanie danych po stronie klienta

Ebookpoint.pl kopia dla: Rodenko David [email protected]

Dołączamy przygotowany element li do nadrzędnej listy ul. W kolejnych dwóch wierszach aktualizujemy potomne względem li elementy .label oraz .calories danymi pobranymi z obiektu row. Po wprowadzeniu opisanych zmian na ekranie Dzień zostaną wyświetlone elementy li dla wszystkich wierszy z bazy danych odpowiadających wybranej dacie. Każdy wpis ma etykietę, liczbę kalorii oraz przycisk Usuń. Po dodaniu kilku wpisów (patrz rysunek 5.5) możesz zdefiniować style, by ekran wyglądał lepiej.

Rysunek 5.5. Widać już dodane wpisy, ale wymagają dopracowania w CSS

Poniższy kod CSS zapisz w arkuszu kilo.css (plik zapisz w tym samym katalogu co dokument HTML): #date ul li { position: relative; } #date ul li span { color: #FFFFFF; text-shadow: 0 1px 2px rgba(0,0,0,.7); }

Web SQL Database

Ebookpoint.pl kopia dla: Rodenko David [email protected]



113

#date ul li .delete { position: absolute; top: 5px; right: 6px; font-size: 12px; line-height: 30px; padding: 0 3px; border-width: 0 5px; -webkit-border-image: url(themes/jqt/img/button.png) 0 5 0 5; }

Teraz wystarczy dołączyć utworzony arkusz stylów (kilo.css) do dokumentu HTML (index.html). Poniższy kod wpisz w sekcji head:

Chociaż przyciski Usuń wyglądają już jak przyciski (patrz rysunek 5.6), na razie nie wykonują żadnej operacji. Wynika to stąd, że utworzyliśmy je w oparciu o znaczniki , które nie są interaktywnymi elementami na stronie HTML.

Rysunek 5.6. Wygląd wpisów po zastosowaniu stylów

114



Rozdział 5. Składowanie danych po stronie klienta

Ebookpoint.pl kopia dla: Rodenko David [email protected]

Usuwanie wierszy Aby przyciski Usuń wykonywały jakąś operację, musimy powiązać je z funkcją obsługi kliknięcia, do czego przyda nam się jQuery. Nie możemy tu jednak skorzystać z rozwiązania, które zastosowaliśmy w przypadku kolejnych dni na ekranie Terminarz, ponieważ wpisy na ekranie Dzień nie są statyczne. Chodzi o to, że są dodawane i usuwane w trakcie działania aplikacji, a w chwili jej uruchamiania na liście wpisów nie ma żadnej pozycji. Z tego względu nie możemy podpiąć funkcji obsługi zdarzenia click w chwili uruchamiania aplikacji. Rozwiązaniem jest podpięcie tej funkcji w chwili tworzenia wpisów, czyli w funkcji refreshEntries(). W tym celu na końcu pętli for dopisz wyróżniony kod: ... newEntryRow.find('.calories').text(row.calories); newEntryRow.find('.delete').click(function(){ var clickedEntry = $(this).parent(); var clickedEntryId = clickedEntry.data('entryId'); deleteEntryById(clickedEntryId); clickedEntry.slideUp(); }); }

Zaczynamy od wybrania wszystkich elementów klasy delete i wywołaniu na nich metody click(). Metodzie tej przekazujemy anonimową funkcję, która będzie odpowiedzialna za obsługę zdarzenia kliknięcia. Po wywołaniu metody obsługi zdarzenia odszukiwany jest eleme9nt nadrzędny względem przycisku Usuń (czyli li); następnie element ten jest zapisywany w zmiennej clickedEntry. W tym wierszu do zmiennej clickedEntryId przypisujemy wartość entryId zapisaną w elemencie li podczas tworzenia wpisu (wcześniej w tej samej funkcji). Zmienną clickedEntryId przekazujemy do funkcji deleteEntryById(), a następnie — za pomocą metody slideUp() z jQuery — elegancko usuwamy element li ze strony. Do pliku kilo.js dopisz poniższą funkcję deleteEntryById(), której zadaniem jest usunięcie wpisu z bazy danych: function deleteEntryById(id) { db.transaction( function(transaction) { transaction.executeSql('DELETE FROM entries WHERE id=?;',

Web SQL Database

Ebookpoint.pl kopia dla: Rodenko David [email protected]



115

[id], null, errorHandler); } ); }

Podobnie jak wcześniej, otwieramy transakcję, przekazujemy funkcję zwrotną z obiektem transakcji jako parametrem i wywołujemy na nim metodę executeSql(). Metodzie tej przekazujemy instrukcję SQL oraz identyfikator wybranego wiersza. Trzecim parametrem wywołania mogłaby być funkcja obsługująca poprawnie wykonaną operację, ale — ponieważ jej nie potrzebujemy — przekazujemy null. Jako czwarty parametr przekazujemy tę samą funkcję obsługi błędu co poprzednim razem. W ten sposób zakończyliśmy pracę nad tą częścią aplikacji. Mimo że dopisany fragment kodu nie jest szczególnie obszerny, wyjaśnienie jego działania zajęło trochę miejsca. W tej chwili skrypt kilo.js zawiera nieco ponad sto linii kodu (listing 5.1). Listing 5.1. Kompletny kod skryptu kilo.js var db; var jQT = $.jQTouch({ icon: 'kilo.png' }); $(document).ready(function(){ $('#createEntry form').submit(createEntry); $('#settings form').submit(saveSettings); $('#settings').bind('pageAnimationStart', loadSettings); $('#dates li a').bind('click touchend', function(){ var dayOffset = this.id; var date = new Date(); date.setDate(date.getDate() - dayOffset); sessionStorage.currentDate = date.getDate() + '.' + (date.getMonth() + 1) + '.' + date.getFullYear(); refreshEntries(); }); var shortName = 'Kilo'; var version = '1.0'; var displayName = 'Kilo'; var maxSize = 65536; db = openDatabase(shortName, version, displayName, maxSize); db.transaction( function(transaction) { transaction.executeSql( 'CREATE TABLE IF NOT EXISTS entries ' + ' (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, ' + ' date DATE NOT NULL, food TEXT NOT NULL, ' + ' calories INTEGER NOT NULL);' ); }

116



Rozdział 5. Składowanie danych po stronie klienta

Ebookpoint.pl kopia dla: Rodenko David [email protected]

); }); function saveSettings() { localStorage.age = $('#age').val(); localStorage.budget = $('#budget').val(); localStorage.weight = $('#weight').val(); jQT.goBack(); return false; } function loadSettings() { if (!localStorage.age) { localStorage.age = ""; } if (!localStorage.budget) { localStorage.budget = ""; } if (!localStorage.weight) { localStorage.weight = ""; } $('#age').val(localStorage.age); $('#budget').val(localStorage.budget); $('#weight').val(localStorage.weight); } function refreshEntries() { var currentDate = sessionStorage.currentDate; $('#date h1').text(currentDate); $('#date ul li:gt(0)').remove(); db.transaction( function(transaction) { transaction.executeSql( 'SELECT * FROM entries WHERE date = ? ORDER BY food;', [currentDate], function (transaction, result) { for (var i=0; i < result.rows.length; i++) { var row = result.rows.item(i); var newEntryRow = $('#entryTemplate').clone(); newEntryRow.removeAttr('id'); newEntryRow.removeAttr('style'); newEntryRow.data('entryId', row.id); newEntryRow.appendTo('#date ul'); newEntryRow.find('.label').text(row.food); newEntryRow.find('.calories').text(row.calories); newEntryRow.find('.delete').click(function(){ var clickedEntry = $(this).parent(); var clickedEntryId = clickedEntry.data('entryId'); deleteEntryById(clickedEntryId); clickedEntry.slideUp(); }); } }, errorHandler ); }

Web SQL Database

Ebookpoint.pl kopia dla: Rodenko David [email protected]



117

); } function createEntry() { var date = sessionStorage.currentDate; var calories = $('#calories').val(); var food = $('#food').val(); db.transaction( function(transaction) { transaction.executeSql( 'INSERT INTO entries (date, calories, food) VALUES (?, ?, ?);', [date, calories, food], function(){ refreshEntries(); jQT.goBack(); }, errorHandler ); } ); return false; } function errorHandler(transaction, error) { alert('Oj! Wystąpił błąd '+error.message+' (kod błędu: '+error.code+')'); return true; } function deleteEntryById(id) { db.transaction( function(transaction) { transaction.executeSql('DELETE FROM entries WHERE id=?;', [id], null, errorHandler); } ); }

Kody błędów Web SQL Database Błąd, który wystąpił w interfejsie API Web SQL Database, jest zgłaszany w funkcji zwrotnej. Możliwe kody błędów zostały zebrane w tabeli 5.1.

Czego się nauczyłeś? W tym rozdziale poznałeś dwie techniki składowania danych po stronie klienta: Web Storage oraz Web SQL Database. Szczególnie ta druga technologia otwiera całkiem nowe możliwości dla twórców aplikacji internetowych.

118



Rozdział 5. Składowanie danych po stronie klienta

Ebookpoint.pl kopia dla: Rodenko David [email protected]

Tabela 5.1. Kody błędów bazy danych Stała

Kod

Sytuacja

UNKNOWN_ERR

0

Transakcja nie doszła do skutku z powodu niewynikającego bezpośrednio z samej bazy danych, ale nie jest możliwe wskazanie konkretnego kodu błędu.

DATABASE_ERR

1

Operacja zakończyła się niepowodzeniem na poziomie bazy danych, ale nie jest możliwe wskazanie konkretnego kodu błędu.

VERSION_ERR

2

Operacja zakończyła się niepowodzeniem, ponieważ dostępna jest nieodpowiednia wersja bazy danych. Błąd ten może zostać zgłoszony na przykład podczas wykonywania kwerendy po stwierdzeniu, że bieżąca wersja bazy danych nie jest zgodna ze spodziewaną wersją obiektów Database lub DatabaseSync. Inną sytuacją może być wywołanie metod Database.changeVersion() lub DatabaseSync.changeVersion() z przekazaną wersją nieodpowiadającą aktualnej.

TOO_LARGE_ERR

3

Wykonanie kwerendy zakończyło się niepowodzeniem, ponieważ dane zwrócone z bazy danych przekroczyły limit rozmiaru. W takiej sytuacji może być przydatny modyfikator LIMIT języka SQL, dzięki któremu można zredukować liczbę zwracanych rekordów.

QUOTA_ERR

4

Wykonanie kwerendy zakończyło się niepowodzeniem, ponieważ zabrakło miejsca na składowanie danych lub został osiągnięty limit rozmiaru składowania, a użytkownik nie zezwolił na jego powiększenie.

SYNTAX_ERR

5

Operacja zakończyła się niepowodzeniem ze względu na błąd składniowy. Przykładowe sytuacje: liczba argumentów nie odpowiada liczbie symboli zastępczych ? w kwerendzie; w instrukcji znalazły się nieprawidłowe komendy (na przykład BEGIN, COMMIT czy ROLLBACK); kwerenda modyfikująca bazę danych pracuje na transakcji otwartej w trybie tylko do odczytu.

CONSTRAINT_ERR

6

Wykonanie instrukcji INSERT, UPDATE lub REPLACE zakończyło się niepowodzeniem ze względu na ograniczenia bazy danych. Przykładem takiej sytuacji może być próba wstawienia wiersza, w którym w polu klucza głównego znajduje się wartość istniejąca już w tabeli.

TIMEOUT_ERR

7

W ustalonym czasie nie udało się zablokować bazy na potrzeby transakcji.

Jedynym, co nas powstrzymuje przed uruchomieniem omawianej aplikacji w trybie offline, jest to, że podczas jej uruchamiania z serwera pobieranyjest dokument HTML wraz z powiązanymi z nim zasobami. Czy nie byłoby cudownie, gdybyśmy mogli przechowywać te pliki lokalnie? Tak, byłoby cudownie…

Czego się nauczyłeś?

Ebookpoint.pl kopia dla: Rodenko David [email protected]



119

120



Rozdział 5. Składowanie danych po stronie klienta

Ebookpoint.pl kopia dla: Rodenko David [email protected]

ROZDZIAŁ 6.

Tryb offline

Jedną z nowości wprowadzonych w HTML5 jest technologia aplikacji działających offline, dzięki której możliwe jest uruchamianie aplikacji internetowych nawet bez aktywnego połączenia z internetem. Działa to w taki sposób: po przejściu użytkownika do aplikacji internetowej przeglądarka pobiera wszystkie pliki, które są wymagane do jej wyświetlenia i działania (HTML, CSS, JavaScript, obrazki itd.). Następnym razem, gdy użytkownik będzie chciał skorzystać z aplikacji, przeglądarka rozpozna jej adres URL i dostarczy lokalną kopię plików bez potrzeby ponownego ich pobierania.

Podstawy aplikacji działających offline Kluczowym elementem aplikacji działającej offline jest plik manifestu, który musi znajdować się na serwerze. Zaczniemy od prostego przykładu, dzięki któremu będziesz mógł poznać zasady pracy z plikiem manifestu, a następnie zastosujemy zdobytą wiedzę w projekcie aplikacji Kilo, nad którą pracujemy. Plik manifestu jest zwykłym plikiem tekstowym, który znajduje się na serwerze WWW i jest przesyłany do przeglądarki jako dokument typu cache-manifest. Zawiera on listę plików, które muszą zostać pobrane przez przeglądarkę i zapisane na potrzeby późniejszego użycia. Załóżmy, że na naszą aplikację składają się następujące pliki: index.html logo.jpg scripts/demo.js styles/screen.css

121

Ebookpoint.pl kopia dla: Rodenko David [email protected]

W tym przypadku plikiem, który jest ładowany po przejściu użytkownika na adres aplikacji, jest index.html. Plik ten zawiera odwołania do pozostałych przedstawionych plików. Aby wszystko działało w trybie offline, utworzymy plik demo.manifest, który musi się znaleźć w tym samym katalogu co strona index.html (nie musisz tego robić; niebawem pokażemy, jak to zrobić w przypadku naszej aplikacji). Po utworzeniu pliku struktura katalogu wygląda następująco: demo.manifest index.html logo.jpg scripts/demo.js styles/screen.css

Następnie w pliku demo.manifest trzeba umieścić poniższe wpisy: CACHE MANIFEST index.html logo.jpg scripts/demo.js styles/screen.css

Ścieżki w pliku manifestu są określane względem lokalizacji pliku manifestu. Można oczywiście użyć też ścieżek bezwzględnych: CACHE MANIFEST http://www.przyklad.com/index.html http://www.przyklad.com/logo.jpg http://www.przyklad.com/scripts/demo.js http://www.przyklad.com/styles/screen.css

W pliku index.html, za pomocą atrybutu manifest znacznika html, musimy dodać odsyłacz do pliku manifestu:

W dalszej części tego rozdziału będziemy używać PHP do dynamicznego tworzenia pliku manifestu. Zaletą skryptów PHP w tym przypadku jest to, że można określić ich typ dokumentu. Jeśli nie chcesz eksperymentować z plikami manifestu na serwerze, możesz pominąć poniższe czynności konfiguracyjne.

Plik manifestu musi być udostępniany jako dokument typu text/cache-manifest, tak by przeglądarka go rozpoznawała. Apache Jeśli korzystasz z serwera Apache, możesz to osiągnąć, umieszczając w katalogu witryny plik .htaccess z następującą zawartością: AddType text/cache-manifest .manifest

122



Rozdział 6. Tryb offline

Ebookpoint.pl kopia dla: Rodenko David [email protected]

Jeżeli pracujesz na Macu, zajrzyj do ramki „Plik .htaccess w Mac OS X” na następnej stronie, by dowiedzieć się, jak odblokować możliwość korzystania z dyrektywy AddType. IIS (Windows) Jeśli korzystasz z serwera IIS w systemie Windows, uruchom IIS Manager, odszukaj swoją witrynę w panelu Połączenia (z lewej strony) i wybierz ją. Następnie dwukrotnie kliknij Typy MIME i za pomocą akcji Dodaj powiąż rozszerzenie .manifest z typem text/cache-manifest. Jeśli pojawi się komunikat informujący o tym, że taki typ MIME już istnieje, możesz użyć innego rozszerzenia dla plików manifestu swojej aplikacji (na przykład webmanifest, jak pokazaliśmy na rysunku 6.1) lub dwukrotnie kliknij istniejącą pozycję dla rozszerzenia .manifest i zmień typ na text/ cache-manifest.

Rysunek 6.1. Konfigurowanie typów MIME w IIS

Firma hostingowa Jeśli korzystasz z usług firmy hostingowej, powinieneś mieć do dyspozycji panel zarządzania witryną, w którym możesz dodać dowolne typy MIME.

Podstawy aplikacji działających offline

Ebookpoint.pl kopia dla: Rodenko David [email protected]



123

Inne przypadki Jeśli w Twoim przypadku dołączenie pliku .htaccess nie przynosi spodziewanych rezultatów, zajrzyj do dokumentacji używanego serwera WWW i sprawdź, jak należy zdefiniować nowe typy MIME. Celem jest powiązanie rozszerzenia .manifest z typem text/cache-manifest. Nasza przykładowa aplikacja powinna zacząć działać. Po wejściu na stronę http://przyklad.com/index.html (to jest oczywiście przykładowy adres) przeglądarka pobierze dokument HTML i wszystkie powiązane z nim zasoby z sieci, ale pliki wskazane w pliku manifestu zostaną zapisane lokalnie. Gdy użytkownik odświeży okno przeglądarki, pliki będą już pobierane z lokalnej kopii, więc połączenie z internetem nie będzie już niezbędne do działania aplikacji.

Plik .htaccess w Mac OS X Jeśli korzystasz z serwera Apache będącego składnikiem systemu OS X, dyrektywy zawarte w pliku .htaccess zapisanym w folderze dokumentów WWW (domyślnie jest to folder Witryny) są ignorowane. Możesz jednak włączyć ich obsługę:

1. Przejdź do Programy/Narzędzia/Terminal i wpisz poniższe polecenia (będziesz musiał podać hasło): cd /etc/apache2/users sudo pico $USER.conf

W ten sposób otwieramy plik konfiguracyjny serwera Apache w edytorze pico (listę poleceń edytora znajdziesz na dole ekranu; symbol ^ oznacza klawisz Control). 2. Za pomocą klawiszy strzałek przejdź w dół do linii AllowOverride None, usuń słowo None i w jego miejsce wpisz FileInfo. 3. Wciśnij Control+X, aby zamknąć edytor. Na pytanie o zapisanie zmian odpowiedz Y (tak) i wciśnij klawisz Enter. 4. Otwórz okno ustawień systemowych, przejdź do panelu Udostępnianie i — jeśli trzeba — kliknij ikonę kłódki opisaną jako Kliknij w kłódkę, by dokonać zmian. Zostaniesz poproszony o podanie hasła.

5. Usuń zaznaczenie z pola Udostępnianie www, a następnie ponownie je zaznacz (spowoduje to przeładowanie serwera WWW). Od tej chwili serwer powinien uwzględniać dyrektywy AddType z plików .htaccess umieszczonych w folderze Witryny i jego podfolderach.

124



Rozdział 6. Tryb offline

Ebookpoint.pl kopia dla: Rodenko David [email protected]

Skoro przeglądarka korzysta z lokalnych kopii plików, pojawia się problem — w jaki sposób powiadomić ją o aktualizacjach wprowadzanych na serwerze? Jeśli użytkownik przejdzie na stronę aplikacji, a ma dostęp do internetu, przeglądarka sprawdzi, czy lokalna kopia plików odpowiada temu, co jest zamieszczone w pliku manifestu. Jeśli manifest się zmienił, przeglądarka pobierze jeszcze raz wszystkie wyszczególnione w nim pliki. Porównanie lokalnego manifestu ze zdalnym polega na sprawdzeniu, bajt po bajcie, zawartości pliku (czyli są uwzględniane również komentarze i puste wiersze). Podczas sprawdzania, czy pliki uległy zmianie, nie są brane pod uwagę ani data modyfikacji, ani inne zmiany wprowadzone w samych zasobach.

Jeśli podczas pobierania plików pojawiły się jakieś problemy (na przykład zostało utracone połączenie z internetem), częściowo pobrane zasoby są automatycznie usuwane, a w ich miejsce są wstawiane poprzednio pobrane. Po pomyślnym zakończeniu pobierania zasoby zostaną użyte podczas ponownego uruchomienia aplikacji. Pamiętaj, że jeśli plik manifestu został zaktualizowany, pobieranie nowych plików odbywa się po uruchomieniu aplikacji. Oznacza to, że użytkownik pracuje na starszej wersji aplikacji. Zakończenie pobierania nowych zasobów nie spowoduje automatycznego przeładowania aplikacji. Nowe pliki zostaną użyte dopiero przy ponownym uruchomieniu aplikacji. Działa to bardzo podobnie do standardowej procedury aktualizacji aplikacji desktopowych — użytkownik uruchamia aplikację, pojawia się okienko informujące o dostępnych aktualizacjach, użytkownik klika przycisk Pobierz aktualizacje, aktualizacje są pobierane, a następnie pojawia się kolejne okienko, tym razem informujące o konieczności ponownego uruchomienia aplikacji. Jeśli chcesz zaimplementować tego typu mechanizm w swojej aplikacji internetowej, musisz napisać funkcję obsługi zdarzenia updateready obiektu window.applicationCache, w której powiadomisz użytkownika o konieczności ponownego uruchomienia aplikacji. Więcej na ten temat znajdziesz w punkcie „Konsola JavaScriptu” w tym rozdziale.

Podstawy aplikacji działających offline

Ebookpoint.pl kopia dla: Rodenko David [email protected]



125

Sekcje NETWORK i FALLBACK Istnieje możliwość zmuszenia przeglądarki do pobierania wybranych zasobów z sieci za każdym razem (grupę tych plików nazywa się czasem białą listą). Oznacza to, że przeglądarka nie przechowuje ich lokalnej kopii, więc nie są dostępne w trybie offline. Aby wskazać zasoby dostępne jedynie w trybie online, w pliku manifestu musisz utworzyć sekcję NETWORK: (nie pomijaj znaku dwukropka): CACHE MANIFEST index.html scripts/demo.js styles/screen.css NETWORK: logo.jpg

Plik logo.jpg przenieśliśmy do sekcji NETWORK, a więc umieściliśmy go na białej liście. Gdy użytkownik pracuje w trybie offline, obraz nie zostanie wyświetlony — pojawia się ikona uszkodzonego łącza do obrazu (rysunek 6.2). Po połączeniu z internetem obraz jest wyświetlany normalnie (rysunek 6.3).

Rysunek 6.2. W trybie offline w miejscu obrazu umieszczonego na białej liście pojawia się ikona uszkodzonego łącza

126



Rozdział 6. Tryb offline

Ebookpoint.pl kopia dla: Rodenko David [email protected]

Rysunek 6.3. Po przejściu w tryb online obraz jest wyświetlany normalnie

Jeśli nie chcesz, by użytkownicy pracujący offline zobaczyli ikonę uszkodzonego łącza, możesz korzystać z sekcji FALLBACK, w której definiuje się zastępcze zasoby: CACHE MANIFEST index.html scripts/demo.js styles/screen.css FALLBACK: logo.jpg offline.jpg

Dzięki temu kiedy użytkownik będzie pracować w trybie offline, zobaczy obraz z pliku offline.jpg (rysunek 6.4), a po połączeniu — logo.jpg (rysunek 6.5). Pliku offline.jpg nie musisz dopisywać do głównej sekcji CACHE MANIFEST, ponieważ i tak zostanie automatycznie zapisany lokalnie z racji tego, że występuje w sekcji FALLBACK.

Opisany mechanizm staje się jeszcze ciekawszy, kiedy sobie uzmysłowimy, że możemy za jednym razem zdefiniować wiele zastępczych zasobów, korzystając z niepełnych ścieżek. Załóżmy, że pliki graficzne znajdują się w katalogu images:

Sekcje NETWORK i FALLBACK

Ebookpoint.pl kopia dla: Rodenko David [email protected]



127

Rysunek 6.4. Obraz z sekcji FALLBACK jest wyświetlany w trybie offline

Rysunek 6.5. W trybie online pojawia się zwykły obraz

128



Rozdział 6. Tryb offline

Ebookpoint.pl kopia dla: Rodenko David [email protected]

/demo.manifest /index.html /images/logo.jpg /images/logo2.jpg /images/offline.jpg /scripts/demo.js /styles/screen.css

Możemy teraz wskazać przeglądarce obraz zastępczy offline.jpg dla wszystkich obrazów z katalogu images: CACHE MANIFEST index.html scripts/demo.js styles/screen.css FALLBACK: images/ images/offline.jpg

Dzięki temu kiedy użytkownik pracuje offline, widzi obraz offline.jpg (rysunek 6.6), a kiedy jest online — obrazy logo.jpg i logo2.jpg (rysunek 6.7).

Rysunek 6.6. W miejscu wielu obrazów w trybie offline jest wyświetlany pojedynczy obraz zastępczy

Sekcje NETWORK i FALLBACK

Ebookpoint.pl kopia dla: Rodenko David [email protected]



129

Rysunek 6.7. Po przejściu do trybu online wyświetlane są właściwe obrazy

To, czy dodać wybrane zasoby do sekcji NETWORK, czy FALLBACK, zależy głównie od danej aplikacji. Pamiętaj, że mechanizm trybu offline służy przede wszystkim do lokalnego składowania zasobów aplikacji. Nie chodzi tu o odciążenie serwera czy zwiększenie wydajności. W większości przypadków powinieneś umieścić w pliku manifestu wszystkie zasoby wymagane do uruchomienia aplikacji. Jeśli jednak masz wiele dynamicznych źródeł danych i nie jesteś pewien, jak się do nich odwołać w manifeście, najprawdopodobniej powinieneś rozważyć rozwiązanie inne niż aplikacje offline (na przykład bazę danych działającą po stronie klienta). W kolejnym podrozdziale zajmiemy się dynamicznym plikiem manifestu, w czym pomoże nam język skryptowy PHP. Jeśli nie zainstalowałeś jeszcze PHP na swoim serwerze, zajrzyj do ramki „Uruchamianie skryptów PHP na serwerze WWW” na następnej stronie.

130



Rozdział 6. Tryb offline

Ebookpoint.pl kopia dla: Rodenko David [email protected]

Uruchamianie skryptów PHP na serwerze WWW PHP to uniwersalny język skryptowy działający po stronie serwera, który jest obsługiwany przez wiele serwerów. W związku z tym w większości przypadków wystarczy utworzyć plik z rozszerzeniem .php, wpisać jakiś kod PHP i otworzyć w przeglądarce ten dokument. Jeśli jednak Twój lokalny serwer WWW nie obsługuje PHP, powinieneś go odpowiednio skonfigurować.

Windows Jeśli korzystasz z serwera IIS, musisz włączyć usługi CGI, co opisaliśmy w ramce „Uruchamianie lokalnego serwera WWW” w rozdz. 2. Następnie przejdź na stronę http://php.iis.net/ i kliknij odsyłacz Install PHP, aby zainstalować PHP dla IIS. Jeśli używasz Windowsa, ale nie korzystasz z serwera IIS, zajrzyj na stronę http://php.net/manual/en/install.windows.php. Linux Zainstalowanie PHP na Linuksie jest bardzo proste. Na przykład w dystrybucji Ubuntu wystarczy wpisać w terminalu polecenie sudo apt-get install apache2 php5. Aby włączyć obsługę PHP w katalogu public_html użytkownika, zmodyfikuj plik /etc/apache2/mods-available/ php5.conf zgodnie z zawartymi w nim instrukcjami. Mac OS X W systemie Mac OS X PHP jest zainstalowany, ale trzeba go włączyć: 1. Otwórz terminal (Programy/Narzędzia/Terminal) i wpisz poniższe polecenia (będziesz musiał wprowadzić hasło): cd /etc/apache2 sudo pico httpd.conf

2. Wciśnij Control+W, aby włączyć funkcję wyszukiwania. Wpisz php5 i wciśnij Enter. W dokumencie znajdziesz następujący wiersz: #LoadModule php5_module

libexec/apache2/libphp5.so

3. Przejdź na początek wiersza i usuń symbol komentarza (#). 4. Wciśnij Control+X, aby zamknąć edytor. Na pytanie o zapisanie zmian odpowiedz Y (tak) i wciśnij klawisz Enter. 5. Następnie otwórz okno ustawień systemowych, przejdź do panelu Udostępnianie i — jeśli trzeba — kliknij ikonę kłódki opisaną jako Kliknij w kłódkę, by dokonać zmian. Zostaniesz poproszony o podanie hasła.

Sekcje NETWORK i FALLBACK

Ebookpoint.pl kopia dla: Rodenko David [email protected]



131

6. Usuń zaznaczenie z pola Udostępnianie www, a następnie ponownie je zaznacz (spowoduje to przeładowanie serwera WWW). Od tej chwili serwer będzie obsługiwał PHP. Po skonfigurowaniu serwera trzeba sprawdzić, czy wszystko działa. W katalogu dokumentów serwera WWW („Uruchamianie lokalnego serwera WWW” w rozdz. 6.) utwórz plik test.php z następującą zawartością:

Następnie w przeglądarce internetowej przejdź na odpowiedni adres: jeśli plik zapisałeś w głównym katalogu dokumentów serwera, jest to http://localhost/test.php; jeśli plik zapisałeś w katalogu użytkownika, jest to http://localhost/~NAZWAUŻYTKOWNIKA/test.php (w miejsce NAZWAUŻYTKOWNIKA wpisz swoją nazwę użytkownika, ale nie usuwaj tyldy ~; nazwę użytkownika możesz poznać, wpisując w terminalu polecenie echo $USER). Jeśli PHP działa prawidłowo, zostaną wyświetlone tabele ze szczegółowymi informacjami o zainstalowanej wersji PHP. Jeśli nie działa, zobaczysz pustą białą stronę. Na stronie http://php.net/support.php znajdziesz listę odsyłaczy do dokumentacji i innych zasobów związanych z PHP.

Dynamiczne tworzenie pliku manifestu Teraz już wiesz, na jakiej zasadzie działają aplikacje w trybie offline. Przyszedł więc czas na zastosowanie zdobytej wiedzy w aplikacji Kilo, nad którą pracujemy już od jakiegoś czasu. Na tę aplikację składa się całkiem sporo plików, więc ręczne dodawanie ich do pliku manifestu byłoby uciążliwe, a dodatkowo wystarczyłaby jedna literówka, by cały manifest był źle interpretowany, a co za tym idzie, aplikacja nie działałaby prawidłowo w trybie offline. Aby rozwiązać ten problem, napiszemy krótki skrypt PHP, który będzie odczytywał zawartość katalogu aplikacji (wraz z podkatalogami) i na tej podstawie tworzył listę plików. Zacznij od utworzenia pliku manifest.php w głównym katalogu aplikacji Kilo i wpisz w nim następujący kod:
Stark J. - Android. Tworzenie aplikacji w oparciu o HTML CSS i JavaScript

Related documents

3 Pages • 668 Words • PDF • 150.5 KB

512 Pages • 34,416 Words • PDF • 22.6 MB

2 Pages • 105 Words • PDF • 46.2 KB

2 Pages • 926 Words • PDF • 158.1 KB

166 Pages • 44,914 Words • PDF • 733.2 KB

132 Pages • PDF • 115.7 MB

119 Pages • 37,353 Words • PDF • 2.2 MB

92 Pages • 15,315 Words • PDF • 2.6 MB

12 Pages • 1,904 Words • PDF • 6.6 MB

51 Pages • 3,246 Words • PDF • 1.9 MB