Spis treści Podziękowania 7 O autorze 9 O recenzentach 11 Wstęp 13 Rozdział 1. Obsługa zdarzeń w jQuery 17 Wprowadzenie 17 Wykonywanie funkcji w momen...
Wprowadzenie Wykonywanie funkcji w momencie załadowania strony Wiązanie i odwiązywanie elementów Dodawanie zdarzeń do elementów, które zostaną utworzone później Przesyłanie formularza za pomocą jQuery Kontrola brakujących obrazków Tworzenie funkcji zaznacz/usuń zaznaczenie wszystkich pól wyboru Przechwytywanie zdarzeń myszy Tworzenie skrótów klawiszowych Wyświetlanie tekstu wybranego przez użytkownika Przeciąganie elementów na stronie
Rozdział 2. Łączenie PHP i jQuery Wprowadzenie Pobieranie danych z PHP za pomocą jQuery Automatyczne tworzenie tekstu zapytania na podstawie elementów formularza Wykrywanie żądań AJAX w skryptach PHP Wysyłanie danych do PHP Przerywanie żądań AJAX Tworzenie pustej strony i ładowanie jej w częściach Obsługa błędów w żądaniach AJAX Blokowanie w przeglądarce buforowania żądań AJAX Ładowanie JavaScriptu na żądanie, aby zmniejszyć czas ładowania strony
17 18 20 24 27 29 32 36 39 43 47
51 51 53 57 60 62 66 69 73 77 79
Spis treści
Rozdział 3. Praca z dokumentami XML Wprowadzenie Ładowanie danych XML z plików oraz ciągów znaków za pomocą SimpleXML Korzystanie z elementów i atrybutów za pomocą SimpleXML Wyszukiwanie elementów za pomocą XPath Odczytywanie dokumentów XML za pomocą rozszerzenia DOM Tworzenie dokumentów XML za pomocą rozszerzenia DOM Modyfikowanie dokumentów XML za pomocą rozszerzenia DOM Parsowanie dokumentów XML za pomocą biblioteki jQuery
Rozdział 4. Praca z formatem JSON Wprowadzenie Tworzenie danych w formacie JSON za pomocą PHP Odczytywanie danych w formacie JSON za pomocą PHP Przechwytywanie błędów analizy danych w formacie JSON Korzystanie z danych w formacie JSON za pomocą jQuery
Rozdział 5. Praca z formularzami Wprowadzenie Dynamiczne dodawanie pól do formularza Wyszukiwanie na stronie tekstu wprowadzonego przez użytkownika Szukanie pustych pól za pomocą biblioteki jQuery Sprawdzanie poprawności liczb za pomocą biblioteki jQuery Sprawdzanie poprawności adresów e-mail i adresów WWW za pomocą wyrażeń regularnych Wyświetlanie błędów w czasie wprowadzania danych, czyli sprawdzanie danych na żywo Mocniejsza kontrola formularza, czyli ponowne kontrolowanie w PHP Tworzenie systemu do głosowania Zezwalanie na kod HTML w polach tekstowych i ograniczanie zbioru dozwolonych znaczników
Rozdział 6. Efekty specjalne w formularzach Wprowadzenie Tworzenie gry w kółko i krzyżyk Informowanie użytkownika o przetwarzaniu żądania AJAX Tworzenie rozwijanych i zwijanych ramek (harmonijek) Stopniowe ukrywanie elementu po jego zaktualizowaniu Wyświetlanie pływającego okienka na żądanie Aktualizowanie pozycji w koszyku na zakupy
Rozdział 7. Tworzenie menu nawigacyjnych Wprowadzenie Tworzenie prostych menu rozwijanych Tworzenie menu zmieniającego kolor tła po wskazaniu myszą Tworzenie menu harmonijkowego
4
83 83 86 89 94 98 102 105 109
113 113 115 117 120 122
129 129 130 133 137 141 144 148 152 158 163
167 167 168 175 181 185 188 192
201 201 202 206 209
Spis treści
Tworzenie menu pływającego Tworzenie interfejsu do nawigacji w kartach Dodawanie nowych kart Tworzenie kreatora za pomocą kart
216 221 225 231
Rozdział 8. Wiązanie danych w PHP i jQuery
239
Wprowadzenie Pobieranie danych z bazy i wyświetlanie ich w formie tabeli Zbieranie danych z formularza i zapisywanie ich w bazie Wypełnianie powiązanych ze sobą list rozwijanych Sprawdzanie w bazie danych dostępności nazwy użytkownika Podział dużych ilości danych na strony Dodawanie funkcji automatycznych podpowiedzi do pól tekstowych Tworzenie chmury znaczników
Rozdział 9. Rozbudowywanie stron za pomocą PHP i jQuery Wprowadzenie Wysyłanie żądań między domenami z wykorzystaniem serwera proxy Tworzenie międzydomenowych żądań za pomocą biblioteki jQuery Tworzenie strony przewijającej się w nieskończoność Tworzenie wtyczki do biblioteki jQuery Wyświetlanie kanałów RSS za pomocą PHP i jQuery
Dodatek A. Firebug Wprowadzenie Badanie elementów strony Edytowanie kodu HTML i stylów CSS Debugowanie kodu JavaScript
Skorowidz
239 240 246 251 257 262 267 275
281 281 282 288 293 298 302
309 309 311 313 315
319
5
Spis treści
6
Podziękowania Autor Vijay Joshi Reviewers Anis Ahmad Md. Mahmud Ahsan Joe Wu Shameemah Kurzawa Aquisition Editor Chaitanya Apte Development Editor Neha Mallik Technical Editors Mohd. Sahil Hitches Uchil
Editorial Team Leader Aanchal Kumar Project Team Leader Ashwin Shetty Project Coordinator Michelle Quadros Proofreader Mario Cecere Indexer Hemangini Bari Production Coordinator Aparna Bhagat Cover Work Aparna Bhagat
PHP i jQuery. Receptury
8
Wstęp
O autorze Vijay Joshi jest programistą z ponad sześcioletnim doświadczeniem w pracy na różnych platformach. Cztery lata temu odkrył w sobie pasję do pracy z otwartymi źródłami, kiedy to zaczął poznawać język PHP w ramach hobbistycznego projektu realizowanego po uzyskaniu tytułu magistra nauk komputerowych. Vijay jest teraz zawodowym twórcą stron WWW i zdecydowanie woli tworzyć ich kod w postaci otwartych źródeł (co niestety nie zawsze jest możliwe). W każdej chwili może dostosować się do aktualnych potrzeb. Pracuje na stanowisku głównego programisty w firmie Philogy, jest niezależnym konsultantem dla kilku wybranych firm, którym doradza w zakresie różnych przedsięwzięć związanych z internetem, a przy okazji nadal jest aktywnym blogerem prowadzącym serwis http://vijayjoshi.org. Poza swoją pracą Vijay lubi czytać, chodzić po górach, a czasami dostaje obsesji na punkcie fitnessu. Tworzenie książki jest długotrwałym i skomplikowanym procesem, który wymaga współpracy i koordynacji działań wielu osób. Jestem wdzięczny całemu zespołowi wydawnictwa Packt, a w szczególności Michelle, Chaitanyi oraz Nehe za doskonałą współpracę i wiele cierpliwości wobec mojej osoby. Tę książkę chciałbym zadedykować wszystkim twórcom oprogramowania o otwartych źródłach, ich współpracownikom i entuzjastom z całego świata, dzięki którym PHP i jQuery stały się głównymi narzędziami programistycznymi w naszej niszy. Jeszcze raz wielkie podziękowania dla wszystkich. Jestem dumny i podekscytowany faktem, że mogę udzielać się w tej społeczności, dzięki której tak wiele się nauczyłem. Chciałbym też podziękować swoim rodzicom, bratu Ajayowi oraz Sheethalowi za ich nieustające wsparcie i zachęty do dalszej pracy. Specjalne podziękowania kieruję też do Randivy Vikram Singh za pomoc przy uruchomieniu tego projektu.
9
PHP i jQuery. Receptury
10
Wstęp
O recenzentach Md. Mahmud Ahsan ukończył wydział nauk komputerowych i inżynierii na międzynarodowym uniwersytecie islamskim w Chittagong (IIUC) w Bangladeszu. Jest certyfikowanym inżynierem biblioteki Zend i ekspertem w tworzeniu aplikacji WWW, aplikacji dla Facebooka, aplikacji typu Mashup oraz aplikacji dla iPhona. Oprócz swojej normalnej pracy prowadzi też bloga pod adresem http://thinkdiff.net, a także pisze artykuły na temat różnych technologii, w szczególności na temat tworzenia aplikacji dla Facebooka. Mieszka w Bangladeszu ze swoją żoną Jinat. Aktualnie Mahmud pracuje jako Software Ingeneer (zdalnie) w firmie i2we inc., dla której tworzy społecznościowe aplikacje WWW, wykorzystując przy tym PHP, MySQL, JavaScript, biblioteki Zend, CodeIgniter, jQuery oraz różne API. Prowadzi także kilka małych i średnich projektów. Mahmud jest też twórcą aplikacji dla iPhona, a swoje dzieła publikuje na stronie http://ithinkdiff.net. Był już recenzentem technicznym książki Zend Framework 1.8 Web Application Development wydanej przez wydawnictwo Packt. Jestem niezmiernie wdzięczny swojemu ojcu, który dał mi komputer w 2001 roku. Od tego czasu pokochałem programowanie i prace z różnymi technologiami.
Joe Wu pracuje jako starszy programista PHP, a w branży działa już od 2005 roku. Pracował już nad wieloma projektami o różnej wielkości, dzięki czemu poznał większość istniejących technologii o otwartych źródłach otaczających język PHP. Joe zawsze entuzjastycznie podchodzi do nowo powstających technologii i bardzo chętnie zdobywa umiejętności wspomagające jego pracę nad aktualnymi i przyszłymi projektami. Bardzo chętnie też poznaje nowe możliwości i rodzące się na świecie innowacyjne idee. Wierzy, że rynek jest zawsze szeroko otwarty na wszelkie innowacje poprawiające jakość naszego życia.
11
PHP i jQuery. Receptury
Pomijając całą tę pracę przy komputerach, Joe jest zawodowym graczem w badmintona i jakoś stara się pogodzić swój harmonogram treningów z pracą zawodową. Do tej pory Joe znalazł się na 59. miejscu światowej listy najlepszych badmintonistów i uczestniczył w Igrzyskach Wspólnoty Narodów w Delhi w 2010 roku. Jak widać, jest równie doskonałym ekspertem w badmintonie, jak i w programowaniu. Oprócz tych wszystkich zajęć Joe pracuje też w swojej własnej firmie (razem ze wspólnikiem), udostępniając swoje umiejętności i doświadczenie wszystkim potrzebującym pomocy przy tworzeniu aplikacji WWW. Firma Wackyinnovation (www.wackyinnovation.com) promuje ideę ciągłego parcia naprzód i wykorzystywania nowych technologii oraz pomysłów. Zawsze pełni entuzjazmu oraz chęci realizacji tworzą rozwiązania niemal doskonałe i zdecydowanie bardziej innowacyjne niż konkurencja. Shameemah Kurzawa zajmowała się programowaniem od czasu szkoły średniej. Chcąc uzyskać stanowisko analityka systemowego, zajęła się studiami dziennymi i podyplomowymi na kierunkach Biznesowych systemów informacyjnych i Inżynierii oprogramowania. Przez ostatnich pięć lat pracowała dla znanej australijskiej firmy SBS (ang. Special Broadcasting Service) jako twórca aplikacji WWW i analityk. Oprócz tego chętnie spędza czas ze swoją rodziną (jest mamą dwuletniego chłopca), uwielbia podróże i poznawanie nowych technologii. Chciałabym podziękować swojemu mężowi, synowi oraz zespołowi wydawnictwa Packt za wsparcie oraz okazane zrozumienie podczas recenzowania tej książki.
12
Wstęp
Wstęp Dzisiejsze aplikacje WWW coraz bardziej zaczynają przypominać typowe aplikacje komputerowe, wymagają mniejszej liczby przeładowań stron, pozwalają na lepszą interakcję z użytkownikiem oraz tworzenie różnych efektów. Sieć WWW zdecydowanie przyspieszyła, a takie aplikacje jak Gmail i Facebook nadały sieci nowego znaczenia. Język PHP po stronie serwera i biblioteka jQuery po stronie klienta (przeglądarki) to doskonały zestaw do tworzenia interaktywnych aplikacji WWW. PHP jest podstawowym językiem wybieranym przez twórców stron WWW, a jQuery jest wykorzystywana na jednej trzeciej spośród tysiąca największych stron w internecie, co czyni ją najczęściej stosowaną biblioteką. Jedną ze wspólnych cech języka PHP i biblioteki jQuery jest to, że bardzo łatwo można się ich nauczyć. Po poznaniu podstaw bez większych problemów możemy przejść na wyższy poziom zaawansowania. Podobnie ma działać niniejsza książka. Ma być skrzynką zawierającą multum najróżniejszych narzędzi. Dzięki niej Czytelnik będzie mógł szybciej tworzyć aplikacje WWW, upodabniać je do aplikacji komputerowych, a to wszystko z wykorzystaniem PHP i jQuery. Niezależnie od tego, czy chcemy nauczyć się na bieżąco kontrolować dane z formularzy, tworzyć wtyczki, przeciągać elementy, tworzyć menu, oglądać filmy za pomocą API YouTube albo współpracować z bazą danych, wystarczy tylko zajrzeć do właściwego przepisu. Dokładnie opisywana jest również technologia AJAX, która jest podstawową funkcją dzisiejszych rozbudowanych aplikacji WWW. Nie wymagamy przeczytania tej książki od deski do deski. Każda receptura jest niezależna od pozostałych i koncentruje się na pewnym problemie lub opisuje niewielką aplikację. Wystarczy zatem poszukać rozwiązania męczącego nas kłopotu. Mam nadzieję, że książka okaże się pomocna w codziennej pracy i przyczyni się do podniesienia umiejętności Czytelnika.
13
PHP i jQuery. Receptury
Co znajdziemy w tej książce W rozdziale 1. „Obsługa zdarzeń w jQuery” poznamy metody biblioteki jQuery na obsługę zdarzeń w różnych przeglądarkach. Nauczymy się pracy ze zdarzeniami generowanymi przez mysz i klawiaturę. Oprócz tego omawiane będą też zaawansowane zagadnienia, takie jak przeciąganie i stosowanie skrótów klawiszowych. Rozdział 2. „Łączenie PHP i jQuery” poświęcony zostanie metodom wysyłania żądań AJAX za pomocą biblioteki jQuery oraz sposobom odpowiadania na takie żądania w języku PHP. Znajdą się tu również receptury buforowania żądań AJAX oraz obsługi błędów podczas obsługi takich żądań. W rozdziale 3. „Praca z dokumentami XML” wyjaśniać będziemy metody pracy z plikami XML w języku PHP oraz bibliotece jQuery. Poszczególne receptury będą opisywały sposoby odczytywania, zapisywania i modyfikowania dokumentów XML za pomocą rozszerzeń języka PHP — DOM i SimpleXML. Oprócz tego omawiane będzie też analizowanie dokumentów XML za pomocą biblioteki jQuery. Rozdział 4. „Praca z JSON” w całości poświęcony zostanie formatowi JSON. Przedstawione zostaną sposoby odczytywania i zapisywania danych w tym formacie, a także omówimy wbudowane w bibliotekę jQuery metody pracy z tak zapisanymi danymi. W rozdziale 5. „Praca z formularzami” zajmiemy się obsługą formularzy i kontrolą wprowadzonych do nich danych. Nauczymy się sprawdzać poprawność różnych rodzajów danych. Zajmiemy się kontrolą pustych pól, liczb, adresów e-mail, adresów WWW i wielu innych. Dodatkowo przeanalizujemy znacznie bardziej rozbudowane metody kontroli formularzy po stronie serwera. Rozdział 6. „Efekty specjalne w formularzach” stanowić będzie ciąg dalszy poprzedniego rozdziału, ale tym razem receptury będą dotyczyły upiększania formularzy różnymi efektami graficznymi. Dzięki nim będziemy mogli budować formularze przyjazne dla użytkownika poprzez dodanie do nich takich efektów, jak podświetlenia, rozwijane ramki i inne. W rozdziale 7. „Tworzenie menu nawigacyjnych” znajdą się receptury dotyczące tworzenia różnego rodzaju menu, takich jak menu animowane, harmonijki albo karty. Nie pominiemy też zaawansowanych technik, dzięki którym na bieżąco możliwe jest dodawanie i usuwanie kart. Rozdział 8. „Wiązanie danych w PHP i jQuery” dokładnie wyjaśni nam tajniki używania baz danych w połączeniu z PHP i jQuery. Podawane tu przykłady zaprezentują metody pobierana danych z bazy i prezentowania ich w formularzach WWW. W rozdziale 9. „Rozbudowywanie stron za pomocą PHP i jQuery” poznamy kilka zaawansowanych technik wykorzystania PHP i jQuery. Dowiemy się, jak można obejść niektóre ogra-
14
Wstęp
niczenia przeglądarek, takie jak żądania przesyłane między domenami. Nauczymy się też tworzyć wtyczki biblioteki jQuery, między innymi wtyczkę do ciągłego przewijania strony. Dodatek „Firebug” zostanie poświęcony wykorzystaniu narzędzia Firebug do debugowania kodu HTML i JavaScript użytego na stronach WWW. Nauczymy się edytować kod HTML i zmieniać wygląd stron w samej przeglądarce bez modyfikowania samych plików z kodem. Będziemy mogli wykonywać kod JavaScript bezpośrednio w Firebugu i nauczymy się debugować skrypty za pomocą tego dodatku.
Co będzie potrzebne W systemie konieczne będzie zainstalowanie serwera Apache (lub innego serwera WWW), interpretera PHP (wersja 5.0 lub nowsza) oraz bazy danych MySQL. Tylko w ten sposób możliwe będzie uruchomienie przykładów z tej książki. Można zainstalować te elementy jednocześnie za pomocą oprogramowania typu WampServer albo instalować poszczególne elementy osobno. Oczywiście niezbędne będzie też pobranie biblioteki jQuery (wersja 1.3.2 lub nowsza). Pod względem technicznym w naszej książce zakładamy, że Czytelnik ma już doświadczenie w pracy z językiem PHP, biblioteką jQuery oraz językami HTML i CSS. Wymagana będzie tylko znajomość podstaw, a resztą zajmiemy się już w książce.
Dla kogo jest ta książka Ta książka przeznaczona jest dla programistów korzystających z PHP i jQuery chcących lepiej poznać te technologie, aby za ich pomocą tworzyć rozbudowane aplikacje WWW. W każdym rozdziale książki zostanie podanych wiele przykładów opisujących kolejne kroki wykonywania poszczególnych zadań, dzięki którym nawet początkujący programista będzie mógł zostać zawodowcem.
Konwencje W niniejszej książce zostanie wykorzystanych wiele stylów tekstu, za pomocą których wyróżnione będą różne rodzaje informacje. Poniżej prezentuję przykłady poszczególnych stylów wraz z ich dokładnym opisem.
15
PHP i jQuery. Receptury
Wycinki kodu znajdujące się w tekście zostaną wyróżnione w następujący sposób: „Przycisk input również zostanie połączony ze zdarzeniem click”. Blok kodu będzie wyglądał tak jak poniżej: $('input:text').bind( { focus: function() { $(this).val(''); }, blur: function() { $(this).val('Wprowadź tutaj tekst'); } });
Nowe pojęcie oraz ważne słowa wyróżniane będą pogrubieniem. Słowa pojawiające się na ekranie w ramach menu albo okienek dialogowych zostaną wyróżnione tak: „Teraz kliknij kilka razy przycisk Utwórz nowy element, aby utworzyć elementy DIV”. Wskazówki, sugestie i ważne informacje pojawiać się będą w takich ramkach.
16
1 Obsługa zdarzeń w jQuery W tym rozdziale zajmiemy się: Q uruchamianiem funkcji po załadowaniu strony, Q wiązaniem i odwiązywaniem elementów, Q dodawaniem zdarzeń do elementów, które zostaną utworzone później, Q przesyłaniem formularzy za pomocą jQuery, Q wyszukiwaniem brakujących obrazków, Q tworzeniem funkcji zaznaczającej lub usuwającej zaznaczenie wszystkich pól wyboru, Q przechwytywaniem ruchów myszy, Q tworzeniem skrótów klawiszowych, Q wyświetlaniem tekstu wybranego przez użytkownika, Q przeciąganiem elementów na stronie.
Wprowadzenie Zdarzenia są akcjami wykonującymi kod JavaScript w celu osiągnięcia określonego efektu. Może tu chodzić o różnego rodzaju manipulacje na dokumencie albo o wykonanie wewnętrznych obliczeń. Ze względu na to, że poszczególne przeglądarki inaczej obsługują zdarzenia, napisanie kodu JavaScript pracującego poprawnie we wszystkich przeglądarkach jest niezwykle trudne. W tym rozdziale poznamy tajniki obsługi zdarzeń oraz metody biblioteki jQuery związane z tym zagadnieniem,
PHP i jQuery. Receptury
dzięki którym nasze skrypty będą działały prawidłowo we wszystkich przeglądarkach. Nie możemy też pominąć zaawansowanych metod obsługi zdarzeń, takich jak przeciąganie i skróty klawiszowe.
Wykonywanie funkcji w momencie załadowania strony Aplikacje wykorzystujące technologię AJAX bardzo intensywnie używają języka Javascript do manipulowania zawartością i wyglądem stron WWW. Przed uruchomieniem jakiegokolwiek kodu JavaScript, który chciałby dokonać operacji, strony te powinny mieć załadowany kompletny dokument DOM. W tej recepturze podam sposób uruchomienia kodu JavaScript dopiero po całkowitym załadowaniu dokumentu DOM.
Przygotowania Wystarczy pobrać kopię najnowszej wersji biblioteki jQuery.
Jak to zrobić? 1. Utwórz plik i nazwij go domReady.html. 2. Aby uruchomić kod JavaScript po załadowaniu dokumentu DOM zapisz go pomiędzy klamrowymi nawiasami metody .ready():
Jak to działa? Biblioteka jQuery gwarantuje, że kod zapisany wewnątrz metody .ready() zostanie wykonany dopiero po całkowitym załadowaniu dokumentu DOM. Dotyczy to zarówno pełnego drzewa dokumentu HTML, arkuszy stylów oraz innych skryptów. Oznacza to, że możemy tu manipulować stroną, dodawać zdarzenia i wykonywać dowolne inne operacje. Trzeba jednak pamiętać, że metoda .ready() nie czeka na załadowanie obrazków. Na nie można zaczekać za pomocą metody .load(), o której będziemy mówić w innej recepturze z tego rozdziału.
18
Rozdział 1. • Obsługa zdarzeń w jQuery
Jeżeli nie skorzystamy z metody .ready(), to biblioteka jQuery nie poczeka na załadowanie całego dokumentu, a kod wykona się od razu po przesłaniu go do przeglądarki. Oznacza to, że mogą się w nim pojawić błędy, jeżeli będziemy próbowali manipulować elementami HTML, CSS lub innymi, które jeszcze nie zostały załadowane.
Przekazywanie metodzie .ready() funkcji obsługującej W poprzednim przykładzie podaliśmy metodzie .ready() funkcję anonimową. Możemy też przekazać do niej zwyczajną funkcję, tak jak pokazano poniżej:
Inny sposób używania metody .ready() Nie musimy jednak tworzyć kodu według podanego wyżej wzorca. Możemy też skorzystać z jednego z poniższych sposobów na określenie momentu pełnego załadowania dokumentu DOM: $(function () { });
lub $(doSomething); function doSomething() { // Dokument DOM jest już gotowy }
Wiele metod .ready() Jeżeli w naszej aplikacji działa wiele skryptów, to możemy w każdym z nich wykorzystać metodę .ready(). Biblioteka jQuery uruchomi wszystko po załadowaniu dokumentu. Przykładem takiej sytuacji może być użycie na stronie kilku wtyczek, z których każda zapisana jest w osobnym pliku .js.
19
PHP i jQuery. Receptury
Wiązanie i odwiązywanie elementów W tej recepturze zademonstrujemy sposoby dowiązywania zdarzeń do elementów DOM za pomocą metody .bind(). Oprócz tego nauczymy się usuwać takie dowiązania za pomocą metody .unbind().
Przygotowania Wystarczy pobrać kopię najnowszej wersji biblioteki jQuery.
Jak to zrobić? 1. W katalogu o nazwie rozdzial1 utwórz nowy plik i nazwij go binding.html. 2. Napisz kod HTML zawierający przynajmniej kilka elementów. Utwórz w nim wypunktowanie z nazwami kilku krajów. Następnie utwórz pole wyboru zawierające listę nazw kontynentów. Na zakończenie utwórz jeszcze przycisk, którego użyjemy do usuwania metody obsługi zdarzenia z pola wyboru. Wiązanie elementów
Indie
USA
UK
Francja
3. Teraz możemy skorzystać z magii biblioteki jQuery. Za pomocą metody .bind() dowiąż metodę obsługi zdarzenia click do elementów listy. Metoda ta zmieni kolor tła klikniętego elementu na czerwony. Do pola wyboru dowiąż metodę obsługującą zdarzenie change. Powinna ona wyświetlać wartość wybraną z tego pola. Na koniec potrzebna będzie jeszcze metoda obsługująca zdarzenie click przycisku. Kliknięcie go będzie odwiązywało metodę obsługi zdarzenia z pola wyboru.
4. Otwórz plik binding.html w przeglądarce i kliknij kilka pozycji z listy. Tło każdego klikniętego elementu powinno przyjąć czerwoną barwę. Następnie wybierz jedną z wartości pola wyboru, a powinno się pojawić okienko z wybraną właśnie wartością, takie jak na poniższym rysunku:
21
PHP i jQuery. Receptury
Kliknięcie przycisku Usuń wiązanie z pola wyboru spowoduje odłączenie metody obsługi zdarzenia change, w wyniku czego wybieranie wartości z pola wyboru nie będzie powodowało już żadnych dodatkowych akcji.
Jak to działa? Biblioteka jQuery wykorzystuje metodę .bind() do przywiązania standardowych zdarzeń JavaScriptu do elementów strony. Metoda ta pobiera dwa parametry. Pierwszy określa rodzaj wiązanego zdarzenia. Parametr ten przekazywany jest jako ciąg znaków i można w nim zawrzeć takie zdarzenia, jak click, change, keyup, keydown, focus, blur i inne. Drugi parametr definiuje funkcję wywołania zwrotnego, która ma zostać wykonana w momencie uruchomienia zdarzenia. W podanym kodzie użyliśmy metody .bind(), aby przypiąć metodę obsługi zdarzenia click do elementów listy. Wewnątrz funkcji wywołania zwrotnego zapis $(this) opisuje element, który to zdarzenie wywołał. Następnie używana jest metoda .css(), za pomocą której modyfikowany jest kolor tła klikniętego elementu. W podobny sposób za pomocą metody .bind() przypięliśmy metodę obsługującą zdarzenie change do pola wyboru. Podana tu funkcja wywołania zwrotnego będzie wywoływana za każdym razem, gdy zmieni się wartość w polu wyboru. Oprócz tego do przycisku input przyłączone zostało zdarzenie click. Kliknięcie tego przycisku powoduje wywołanie metody .unbind(), która przyjmuje w parametrze nazwę rodzaju zdarze-
22
Rozdział 1. • Obsługa zdarzeń w jQuery
nia, a następnie usuwa to zdarzenie z elementu. W naszym przykładzie usuwamy zdarzenie change z pola wyboru. Oznacza to, że od teraz zmiana wartości w polu wyboru nie będzie powodowała wyświetlenia okienka z komunikatem.
I coś więcej Wiązanie wielu zdarzeń Za pomocą metody .bind() można też wiązać wiele różnych zdarzeń. W poniższym kodzie wiązane są zdarzenia focus i blur pola tekstowego. Umieszczenie kursora w polu tekstowym spowoduje usunięcie jego zawartości, natomiast przeniesienie kursora poza to pole spowoduje wpisanie do niego jakiegoś tekstu. $('input:text').bind( { focus: function() { $(this).val(''); }, blur: function() { $(this).val('Wprowadź tutaj tekst'); } }); Trzeba pamiętać, że taka możliwość została wprowadzona dopiero w wersji 1.4 biblioteki jQuery. Przed uruchomieniem tego kodu proszę się upewnić, czy mamy dostępną właściwą wersję.
Skrócona metoda wiązania Nie musimy korzystać z metody .bind(), aby powiązać zdarzenia z metodami. Takie powiązanie można wykonać bezpośrednio na zdarzeniu przy zastosowaniu odpowiedniej składni. Na przykład zapis $(element).click(function() { }); może zostać użyty zamiast wywołania $(element). ´bind('click', function() { });. Pozostałe zdarzenia można wiązać w podobny sposób.
Wywoływanie zdarzeń Zdarzenia mogą być też wywoływane w kodzie. W tym celu wystarczy wpisać nazwę zdarzenia bez podawania żadnych parametrów.
Podany kod wywoła zdarzenie keydown elementu element2 w przypadku kliknięcia elementu element1.
Często używane zdarzenia Poniżej podaję listę najczęściej używanych zdarzeń, które można przekazywać metodom .bind() i .unbind(). blur
focus
load
unload
scroll
click
dblclick
mousedown
mouseup
mousemove
mouseover
mouseout
change
select
submit
keydown
keypress
keyup
Usuwanie wszystkich zdarzeń z elementu Jeżeli do metody .unbind() nie podamy żadnych parametrów, to usunie ona wszystkie zdarzenia powiązane z danym elementem. $(element).unbind();
Dodawanie zdarzeń do elementów, które zostaną utworzone później Metoda .bind() jest w stanie dodać zdarzenie tylko do tych elementów, które w danej chwili istnieją na stronie. Jeżeli później zostaną utworzone kolejne elementy spełniające warunki podane w wywołaniu tej metody, to nie będą one miały żadnych metod obsługi zdarzeń.
24
Rozdział 1. • Obsługa zdarzeń w jQuery
Jak to zrobić? 1. W katalogu rozdzial1 utwórz nowy plik o nazwie live.html. 2. Wpisz do pliku kod HTML tworzący przycisk i element div, a następnie dodaj do nich kilka stylów. Dodawanie zdarzeń do elementów
Jest już na stronie
3. Teraz możemy dodać troszkę magii biblioteki jQuery. Do przycisku dodaj zdarzenie click. Kliknięcie tego przycisku będzie tworzyć nowy element div i wstawiać go do kodu strony. Do tak utworzonych elementów div dodamy obsługę zdarzenia click za pomocą metody .live(). Kliknięcie takiego elementu spowoduje zmianę jego kodu HTML i CSS.
4. Uruchom plik live.html w przeglądarce i kliknij na stronie element div. Jak widać, kod HTML i CSS tego elementu uległ zmianie. Teraz kliknij kilka razy przycisk Utwórz nowy element, aby na stronę wstawić nowe elementy div. Okazuje się, że kliknięcie tych elementów również powoduje zmianę ich wyglądu. Poniżej przedstawiam typowy wygląd strony, na której kliknięto już niektóre elementy.
25
PHP i jQuery. Receptury
Jak to działa? Przycisk input tworzy nowe elementy div i dodaje je do kodu dokumentu. Cała magia znajduje się w następnej funkcji. Metoda live() biblioteki jQuery dodaje po prostu zdarzenie click do elementu div. Pod tym względem zachowuje się dokładnie tak samo, jak metoda bind(), czyli związuje element strony z metodami obsługi zdarzeń. Istnieje jednak między nimi pewna istotna różnica. Metoda bind() może dodać zdarzenie tylko do istniejących już elementów, natomiast metoda live() zachowuje sobie selektor CSS oraz zdarzenie i będzie je stosowała wobec wszystkich elementów, które w późniejszym czasie zostaną utworzone i wstawione do kodu strony. Oznacza to, że nowe elementy div utworzone w wyniku kliknięcia przycisku Utwórz nowy element również będą miały dodaną metodę obsługi zdarzenia click.
Usuwanie metod obsługi zdarzeń za pomocą metody die() Metoda die() ma podobne działanie jak metoda unbind(). Używana jest do usuwania metod obsługi zdarzenia utworzonych za pomocą metody live(). Podobnie jak metoda unbind(), die() również występuje w dwóch wariantach. Jeżeli zostanie wywołana bez parametrów, to usunie z elementu wszystkie metody obsługi zdarzeń. $(element).die();
Drugi wariant przyjmuje w parametrze rodzaj zdarzenia i usuwa z elementu tylko metodę obsługującą podane zdarzenie: $(element).die('click');
26
Rozdział 1. • Obsługa zdarzeń w jQuery
Jeżeli element ma przypiętych kilka metod obsługi zdarzeń, to podany wyżej kod usunie tylko metodę obsługującą zdarzenie click, ale pozostałe pozostawi nienaruszone.
Zobacz też Q Receptura „Wiązanie i odwiązywanie elementów” podaje podstawowe informacje
na temat dodawania i usuwania zdarzeń z elementów.
Przesyłanie formularza za pomocą jQuery Wiemy, że przyciski typu submit używane są w formularzach HTML do przesyłania danych na serwer. Niezależnie od tych przycisków język JavaScript również udostępnia metodę pozwalającą na takie przesyłanie informacji. W tej recepturze nauczymy się wysyłać dane formularzy z wykorzystaniem biblioteki jQuery i kontrolować ten proces za pomocą przycisku typu submit.
Przygotowania Wystarczy pobrać kopię najnowszej wersji biblioteki jQuery.
Jak to zrobić? 1. W katalogu rozdzial1 utwórz nowy plik o nazwie formSubmit.html. 2. Zapisz do pliku poniższy kod, który tworzy formularz z przyciskiem typu input (nie submit). Następnie dopisz kod korzystający z biblioteki jQuery, który będzie uruchamiany po kliknięciu przycisku i zajmie się wysłaniem danych. Wysyłanie formularzy
1. Otwórz w przeglądarce plik formSubmit.html i kliknij przycisk. Dane formularza zostaną wysłane.
Jak to działa? W tym przykładzie dodaliśmy metodę obsługującą zdarzenie click przycisku typu input. Funkcja ta zostanie zatem wykonana po kliknięciu przycisku, a wtedy wywołana zostanie metoda submit() biblioteki jQuery, która wyśle dane z formularza na serwer. Każda przeglądarka ma swoją własną metodę do programowego wysyłania danych, a biblioteka jQuery opakowała tę funkcję w ramach własnej metody submit().
Coś więcej Kontrolowanie przesyłania danych Jeżeli na formularzu jest już przycisk typu submit, to możemy mimo wszystko zadecydować, czy dane mają zostać wysłane czy też nie. W takiej sytuacji trzeba podłączyć do formularza metodę obsługi zdarzenia, która zostanie wykonana po kliknięciu przycisku typu submit tego formularza. $('#myForm').submit(function() { return false; });
Podany kod zostanie wykonany po kliknięciu przycisku typu submit znajdującego się na formularzu o identyfikatorze myForm. Jeżeli funkcja obsługi tego zdarzenia zwraca wartość false, to formularz nie zostanie przesłany do serwera. Jest to niezmiernie wygodne w przypadku sprawdzania poprawności danych z formularza, ponieważ kod wykonujący to zadanie może zostać umieszczony w funkcji obsługi zdarzenia. Jeżeli wartości w formularzu są poprawne, to funkcja zwróci wartość true, a formularz zostanie przesłany. Jeżeli jednak wykryte zostaną nieprawidłowości, to funkcja zwróci wartość false i zablokuje możliwość wysłania danych.
28
Rozdział 1. • Obsługa zdarzeń w jQuery
Innym rozwiązaniem jest zastosowanie funkcji preventDefault(). Jak sugeruje jej nazwa, blokuje ona wykonanie domyślnej metody obsługi wskazanego zdarzenia. Funkcja ta jest właściwością obiektów typu event. $('#myForm').submit(function(event) { event.preventDefault() });
Zobacz też Q Receptura „Wiązanie i odwiązywanie elementów” objaśnia metody dodawania i usuwania
zdarzeń z elementów.
Kontrola brakujących obrazków Jeżeli na stronie wyświetlanych ma być kilka obrazków, ale niestety części z nich brakuje, to przeglądarka wyświetli albo puste miejsce, albo specjalny symbol zastępujący obrazek (czerwony krzyżyk). Z pewnością nie poprawia to wyglądu strony, dlatego lepiej byłoby unikać takich sytuacji. Czy nie byłoby wspaniale, gdybyśmy mieli metodę, która byłaby w stanie odszukać brakujące obrazki albo te, których nie udało się pobrać? Po przeczytaniu tej receptury będziemy mogli wykrywać problemy z obrazkami i zastępować je wybranym przez siebie obrazem.
Przygotowania Przygotuj sobie trzy lub cztery obrazki, które wykorzystamy w ramach tej receptury. Oprócz tego potrzebna będzie też kopia biblioteki jQuery. Za pomocą programu graficznego (choćby najprostszego) przygotuj kolejny obrazek z tekstem „Nie można załadować obrazka”, który wykorzystamy jako zastępnik dla brakujących obrazków.
Jak to zrobić? 1. W katalogu rozdzial1 utwórz nowy plik i nazwij go error.html. 2. Na stronie umieść element div, w którym umieścimy obrazki. Oprócz tego wpisz jeszcze kilka stylów CSS dla elementu div i samych obrazków.
29
PHP i jQuery. Receptury
Kontrola brakujących obrazków
3. Dopisz kod korzystający z biblioteki jQuery do utworzenia tablicy z nazwami obrazków. Celowo umieść kilka losowych nazw obrazków, które na pewno nie istnieją. Następnie wypełnij element div znacznikami obrazków z tej tablicy. W kolejnym kroku trzeba powiązać metodę obsługi zdarzenia error z elementami obrazków.
30
Rozdział 1. • Obsługa zdarzeń w jQuery
4. Uruchom plik error.html w przeglądarce. Zobaczysz, że przynajmniej dwóch obrazków brakuje, dlatego zostały one zastąpione naszym zastępnikiem z tekstem Nie można załadować obrazka.
Jak to działa? Na początek używamy metody $.each(), aby przejść elementy tablicy z nazwami plików i utworzyć znaczniki img wewnątrz elementu div. Następnie do każdego znacznika img przywiązywana jest metoda obsługi zdarzenia error. Metoda ta jest wykonywana, w przypadku gdy obrazka nie uda się załadować albo atrybut src znacznika ma nieprawidłową wartość. W ramach tej metody nieistniejący obrazek zastępowany jest przygotowanym przez nas obrazkiem zastępującym. W naszym przypadku wstawiany jest obrazek z tekstem Nie można załadować obrazka.
Zobacz też Q Receptura „Wiązanie i odwiązywanie elementów” objaśnia metody dodawania
i usuwania zdarzeń z elementów.
31
PHP i jQuery. Receptury
Tworzenie funkcji zaznacz/usuń zaznaczenie wszystkich pól wyboru Jest to często wykorzystywana funkcja aplikacji WWW. Na stronie dostępna jest grupa pól wyboru, które można kontrolować za pomocą jednego, dodatkowego pola. Kliknięcie tego nadrzędnego pola wyboru powoduje zaznaczenie lub usunięcie zaznaczenia wszystkich pól podrzędnych. W tej recepturze przygotujemy zatem funkcję przełączania zaznaczenia grupy pól wyboru. Oprócz tego dowiemy się, jak odczytywać wartości zaznaczonych elementów za pomocą selektorów jQuery.
Przygotowania Upewnij się, że masz gotową kopię biblioteki jQuery.
Jak to zrobić? 1. W katalogu rozdzial1 utwórz nowy plik o nazwie checkbox.html. 2. Najpierw musimy przygotować stronę. Utwórz listę wypunktowaną i dodaj do niej kilka stylów CSS. Pierwszy element tej listy będzie polem wyboru nadrzędnym w stosunku do pozostałych. W pozostałych elementach listy umieść pola wyboru z nazwami książek. Każde z tych pól powinno mieć tę samą klasę: toggle. Utwórz też dodatkowy element listy zawierający przycisk, którego kliknięcie wyświetlać będzie nazwy zaznaczonych książek. Na koniec utwórz jeszcze jeden element listy i przypisz do niego identyfikator. To właśnie tutaj będą wyświetlane nazwy wybranych książek. Zaznacz/usuń zaznaczenie pola wyboru
32
Rozdział 1. • Obsługa zdarzeń w jQuery
3. Po uruchomieniu pliku checkbox.html w przeglądarce powinniśmy zobaczyć następującą stronę.
33
PHP i jQuery. Receptury
4. Aby tak przygotowana strona zaczęła żyć, dołącz do niej bibliotekę jQuery i dowiąż metody obsługi zdarzeń do pól wyboru. Pierwsza z tych metod zostanie związana z pierwszym polem wyboru i zajmie się zaznaczaniem i usuwaniem zaznaczenia z pozostałych pól. Drugą metodę powiążemy z poszczególnymi polami wyboru. Będzie ona sprawdzać stan wszystkich pól i odpowiednio ustawiać wartość pola nadrzędnego. Ostatnia metoda obsługi zdarzenia związana zostanie z przyciskiem typu input i zajmie się wyświetlaniem nazw zaznaczonych książek.
5. Teraz odśwież stronę w przeglądarce i poklikaj trochę pola wyboru. Po kliknięciu pola Przełącz wszystkie wszystkie pozostałe pola zostaną zaznaczone lub ich zaznaczenie zostanie usunięte. Na koniec kliknij jeszcze przycisk Wyświetl zaznaczone książki, a pojawi się okienko z listą nazw książek rozdzielanych przecinkami.
34
Rozdział 1. • Obsługa zdarzeń w jQuery
Jak to działa? Kliknięcie pola wyboru Przełącz wszystkie powoduje włączenie lub wyłączenie zaznaczenia w tym polu. Jeżeli pole to zostało zaznaczone, to zaznaczamy też wszystkie te pola wyboru, które mają klasę toggle. W tym celu używamy selektora klasy i przypisujemy wybranym elementom wartość true do atrybutu checked. Z drugiej strony, jeżeli zaznaczenie zostało usunięte, to usuwamy też ze wszystkich pozostałych pól wyboru atrybut checked. W tym miejscu trzeba zająć się jeszcze jednym problemem. Jeżeli wszystkie pola wyboru zostały już zaznaczone, a następnie z jednego z nich usunięto zaznaczenie, to główne pole wyboru również powinno stracić swoje zaznaczenie. Podobnie, jeżeli wszystkie pola wyboru zostaną zaznaczone pojedynczo, to pole nadrzędne również powinno zostać zaznaczone. W tym celu osobną metodę obsługi zdarzenia wiążemy ze wszystkimi polami wyboru o klasie toggle. Selektor .toggle:checked wybiera wszystkie te pola, które mają klasę toggle, a jednocześnie zostały już zaznaczone. Jeżeli liczba wybranych elementów jest równa całkowitej liczbie pól wyboru, to możemy z tego wywnioskować, że wszystkie są zaznaczone i możemy zaznaczyć też główne pole wyboru. Jeżeli liczba zaznaczonych elementów jest mniejsza od całkowitej liczby pól wyboru, to możemy usunąć atrybut checked z głównego pola i w ten sposób usunąć jego zaznaczenie.
35
PHP i jQuery. Receptury
Coś więcej Używanie selektorów W poprzednim przykładzie korzystaliśmy z selektora .toggle:checked, aby wybrać wszystkie zaznaczone pola wyboru klasy toggle. Dwukropek (:) jest selektorem, który może służyć jako filtr listy elementów. Poniżej przedstawiam przykład obrazujący sposób filtrowania elementów za jego pomocą: $('div:first').click(function() { //zrób coś });
Podany kod wybierze pierwszy element div znajdujący się na stronie i dowiąże do niego metodę obsługującą zdarzenie click. $(p:gt(2)').hide();
Selektor gt oznacza „więcej niż” (ang. greater than). Przyjmuje on indeks (liczony od zera) i dopasowuje elementy o indeksie większym niż podany w parametrze. Jeżeli na stronie znajduje się pięć elementów p, to przykładowy kod ukryje elementy o numerze 3 i 4. Trzeba pamiętać, że indeksy liczone są od zera. Więcej informacji na temat selektorów biblioteki jQuery znaleźć można pod adresem http://api.jquery.com/category/selectors/.
Przechwytywanie zdarzeń myszy Za pomocą biblioteki jQuery możemy określić pozycję wskaźnika myszy na ekranie. W tej recepturze poznamy technikę odczytywania tej informacji. Nauczymy się, jak należy tworzyć wyskakujące podpowiedzi, które pojawiać się będą wtedy, gdy wskaźnik myszy znajdzie się nad określonym elementem.
Przygotowania Niezbędna będzie aktualna kopia biblioteki jQuery.
36
Rozdział 1. • Obsługa zdarzeń w jQuery
Jak to zrobić? 1. W katalogu rozdzial1 utwórz nowy plik o nazwij go mouse.html. 2. Utwórz element div o identyfikatorze tip i atrybucie display o wartości none. Element ten będzie nam służył do wyświetlania podpowiedzi. Utwórz też trzy kolejne elementy div, a do pierwszego i ostatniego z nich przypisz klasę hoverMe. Dla tych elementów konieczne będzie też przygotowanie stylów CSS. Element div używany do wyświetlania podpowiedzi musi otrzymać styl CSS z atrybutem position o wartości absolute. Ruchy myszy
Hura! Jestem podpowiedzią.
Wskaż mnie myszą, aby uzyskać podpowiedź.
Ten element div nie będzie wyświetlał podpowiedzi.
Wskaż mnie myszą, aby uzyskać podpowiedź.
3. Dopisz kod korzystający z biblioteki jQuery, który zajmie się wyświetlaniem podpowiedzi, gdy wskaźnik myszy znajdzie się nad elementem div. Będą nam do tego potrzebne dwie funkcje. Pierwsza z nich zajmie się wyświetlaniem i ukrywaniem podpowiedzi z efektem łagodnego pojawiania się i znikania. Druga funkcja ustali pozycję podpowiedzi i będzie ją przesuwać wraz z ruchem myszy.
37
PHP i jQuery. Receptury
4. Otwórz w przeglądarce plik mouse.html. Po umieszczeniu wskaźnika myszy nad pierwszym i ostatnim elementem div łagodnie pojawi się podpowiedź. Co więcej, podpowiedź ta będzie podążała za ruchami wskaźnika myszy.
38
Rozdział 1. • Obsługa zdarzeń w jQuery
Jak to działa? Wykorzystaliśmy metodę hover() przypisaną do elementów div, aby wyświetlać i ukrywać okienko podpowiedzi. Metoda ta wiąże z danym elementem dwie metody obsługi zdarzeń. Pierwsza metoda jest wywoływana, w momencie gdy wskaźnik myszy pojawia się nad elementem, a druga, gdy wskaźnik opuszcza element. Użyliśmy tu metody fadeIn(), aby wyświetlić podpowiedź na ekranie w momencie pojawienia się wskaźnika myszy nad elementem, a metody fadeOut() do ukrycia podpowiedzi, gdy wskaźnik myszy został przesunięty poza element. Najważniejszą rzeczą jest teraz umieszczenie podpowiedzi w tym miejscu na ekranie, w którym znajduje się wskaźnik myszy. W tym celu przygotowaliśmy metodę obsługującą zdarzenie mousemove elementu div. Jak wskazuje nazwa zdarzenia, metoda ta jest uruchamiana przy każdym poruszeniu wskaźnika myszy nad elementem div. Biblioteka jQuery udostępnia metodzie obsługującej to zdarzenie specjalny obiekt, w którym zapisana jest pozycja wskaźnika myszy. Właściwość pageX tego obiektu przechowuje pozycję wskaźnika myszy względem lewego brzegu dokumentu. Podobnie z właściwości pageY możemy odczytać pozycję wskaźnika myszy względem górnej krawędzi dokumentu. Mamy już pełną informację na temat pozycji wskaźnika myszy na ekranie. Możemy zatem przypisać wartości właściwości pageX i pageY do właściwości stylu CSS (left i top) pozycjonujących element div. Do każdej z tych wartości dodajemy jeszcze 5, tak żeby wskaźnik myszy nie zasłaniał części okienka podpowiedzi.
Tworzenie skrótów klawiszowych Sterowanie klawiszami jest bardzo powszechne wśród aplikacji komputerowych. Jest to bardzo wygodna metoda często stosowana przez osoby lepiej radzące sobie z klawiaturą niż z myszą. Skróty klawiszowe można też tworzyć w aplikacjach WWW, ale niestety są one trudne do zaimplementowania ze względu na niezgodności między przeglądarkami. W tej recepturze utworzymy prosty przykład, w którym poznamy podstawowe sposoby tworzenia skrótów klawiszowych. Nauczymy się tworzyć własne skróty ułatwiające obsługę naszych aplikacji.
Przygotowania Pobierz najnowszą wersję biblioteki jQuery.
39
PHP i jQuery. Receptury
Jak to zrobić? 1. W katalogu rozdzial1 utwórz nowy plik o nazwie keyboard.html. 2. W kodzie HTML nowej strony utwórz dwa elementy div, a w sekcji dopisz kilka stylów CSS zmieniających wygląd elementów div. Skróty klawiszowe
Skorzystaj z klawiszy Alt+S
Skorzystaj z klawiszy Alt+G
Naciśnij Alt+B, aby przełączyć oba elementy div
3. Dopisz kod korzystający z biblioteki jQuery, który utworzy skróty klawiszowe przełączające elementy div. Do zaimplementowania takiego zachowania użyjemy metody obsługi zdarzenia keydown. Będzie ona sprawdzała naciśnięte klawisze i wprowadzała odpowiednie reakcje. Utworzymy tu trzy różne skróty klawiszowe. Naciśnięcie klawiszy Alt+S będzie przełączało pierwszy element div, klawisze Alt+G będą odpowiadały za przełączanie drugiego elementu div, natomiast klawisze Alt+B spowodują przełączanie obu tych elementów. Metoda obsługi zdarzenia keyup zajmować się będzie kasowaniem zmiennej kontrolnej.
4. Otwórz w przeglądarce plik keyboard.html. Spróbuj nacisnąć zdefiniowane właśnie skróty klawiszowe. Zobaczymy wtedy elementy div zmieniające się z wykorzystaniem specjalnej animacji.
41
PHP i jQuery. Receptury
Jak to działa? Chcąc tworzyć w programie skróty klawiszowe, musimy się najpierw dowiedzieć, jakie klawisze zostały naciśnięte. Każda przeglądarka udostępnia swoje własne metody odczytywania wartości naciśniętego klawisza, natomiast biblioteka jQuery ujednolica sposób wykonania tej operacji we wszystkich przeglądarkach. Metoda obsługująca zdarzenie otrzymuje obiekt event, którego właściwość which przechowuje kod naciśniętego klawisza. Klawisz Alt ma tutaj kod 18. W podanych tu przykładowych skrótach klawiszowych wykorzystujemy kombinację klawisza Alt z innym klawiszem. Zaczynamy zatem od zadeklarowania globalnej zmiennej altPressed, której nadajemy wartość false. Do samej strony przypinamy natomiast dwie metody obsługi zdarzenia. Zdarzenie keydown wywoływane jest w momencie naciśnięcia klawisza, natomiast zdarzenie keyup — w momencie jego puszczenia. Gdy naciśnięty zostanie klawisz Alt, wywoływane jest zdarzenie keydown, które nadaje zmiennej altPressed wartość true, natomiast puszczenie tego klawisza wiąże się z wywołaniem zdarzenia keydown, które tej zmiennej nada wartość false. Następnie należy przyjrzeć się instrukcji if, której warunek będzie prawdziwy, jeżeli aktualnie wciśnięty jest klawisz Alt. Jeżeli w takiej sytuacji naciśnięty jest jeszcze jakiś inny klawisz, to instrukcja switch sprawdza kod tego klawisza i wykonuje odpowiednią sekcję kodu. Kod naciśnięcia klawisza S to 83. Oznacza to, że naciśnięcie klawisza S w połączeniu z klawiszem Alt spowoduje wybranie pierwszego elementu div i zastosowanie na nim efektu slideToggle. Podobnie naciśnięcie kombinacji Alt+G odnosić się będzie do drugiego elementu div, a klawisze Alt+B wpłyną na oba te elementy. Proszę zwrócić uwagę na to, że każda sekcja instrukcji switch zwraca wartość false. Jest to niezbędne, żeby wyłączyć domyślne zachowanie przeglądarki. Jeżeli ta wartość nie zostanie zwrócona przez funkcję, to naciśnięcie klawisza Alt spowoduje włączenie menu przeglądarki.
I coś więcej… Lista kodów klawiszy Listę kodów klawiszy można znaleźć na stronie http://goo.gl/v2Fk.
Zobacz też Q Receptura „Wiązanie i odwiązywanie elementów” objaśnia metody dodawania
i usuwania zdarzeń z elementów.
42
Rozdział 1. • Obsługa zdarzeń w jQuery
Wyświetlanie tekstu wybranego przez użytkownika Każdy z pewnością widział już edytory typu WYSIWYG (ang. What You See Is What You Get) działające w aplikacjach WWW, które pozwalają na zaznaczenie części tekstu za pomocą myszy lub klawiatury, a następnie sformatowanie go (włączając styl pogrubienia, zmieniając kolor itd.). W tej recepturze nauczymy się, jak odczytywać tekst zaznaczony przez użytkownika i wykonać na nim pewne operacje.
Przygotowania Wystarczy nam biblioteka jQuery.
Jak to zrobić? 1. W katalogu rozdzial1 utwórz plik o nazwie textSelect.html. 2. W tym pliku utwórz cztery przyciski, z których trzy pierwsze posłużą nam do nadawania tekstowi pogrubienia, kursywy lub podkreślenia. Następnie utwórz pole tekstowe i wpisz do niego jakiś tekst. Na zakończenie wprowadź akapit, którego użyjemy do wyświetlenia sformatowanego kodu HTML. Ostatni przycisk wykorzystamy do pobierania zawartości pola tekstowego i wstawiania go do akapitu. Manipulowanie tekstem zaznaczonym przez użytkownika
43
PHP i jQuery. Receptury
3. Dopisz kod korzystający z biblioteki jQuery i napisz funkcję, która będzie pobierać początek i koniec zaznaczenia tekstu.
4. Otwórz przeglądarkę i uruchom w niej plik drag.html. Oba elementy div powinny dać się teraz przeciągnąć. Wystarczy tylko nacisnąć nad nimi przycisk myszy i przesunąć je w inne miejsce.
49
PHP i jQuery. Receptury
Jak to działa? Zmienne globalne mousex i mousey będą używane do przechowywania współrzędnych wskaźnika myszy, natomiast zmienne divLeft i divTop będą przechowywały współrzędne górnego lewego narożnika elementu div. Do każdego elementu klasy dragMe przypięte zostały dwie metody obsługi zdarzeń. Pierwsza z nich zajmuje się zdarzeniem mousedown, które wywoływane jest w momencie naciśnięcia przycisku myszy nad wybranym elementem. W tej funkcji pobieramy pozycję przeciąganego elementu div i zapisujemy ją w zmiennych divLeft i divTop. Poza tym współrzędne wskaźnika myszy pobierane są z obiektu zdarzenia i zapisywane do zmiennych mousex i mousey. Teraz, dopóki przycisk będzie naciśnięty, przypisujemy zdarzenie mousemove do przeciąganego elementu div. W ramach tego zdarzenia funkcja dragElement zostanie wywołana, o ile wskaźnik myszy się przesunął, podczas gdy naciśnięty był jej przycisk. W ramach funkcji dragElement wyznaczana jest nowa pozycja przeciąganego elementu div. W ramach wyliczania nowej wartości współrzędnej poziomej używana jest aktualna współrzędna elementu (zmienna divLeft) i dodawana jest do niej wartość przesunięcia w pozycji myszy. Różnica pozycji myszy wyliczana jest przez odjęcie poprzedniej współrzędnej wskaźnika myszy od jej aktualnej pozycji. W podobny sposób wyliczana jest nowa współrzędna pionowa elementu div. Po wyliczeniu obu tych wartości za pomocą metody css() wpisywane są one do przeciąganego elementu. Nie można zapominać o tym, że są to pozycje typu absolute. Bez zastosowania tego rodzaju pozycjonowania nie bylibyśmy w stanie przeciągać elementów po stronie.
Zobacz też Q Receptura „Przechwytywanie zdarzeń myszy” wyjaśnia sposoby odczytywania
współrzędnych wskaźnika myszy. Q Receptura „Wiązanie i odwiązywanie elementów” objaśnia metody dodawania
i usuwania zdarzeń z elementów.
50
2 Łączenie PHP i jQuery W tym rozdziale zajmiemy się: Q pobieraniem danych z PHP za pomocą jQuery, Q automatycznym tworzeniem tekstu zapytania na podstawie elementów formularza, Q wykrywaniem żądań AJAX w PHP, Q wysyłaniem danych do PHP, Q przerywaniem żądań AJAX, Q tworzeniem pustej strony i ładowaniem jej części, Q obsługą błędów w żądaniach AJAX, Q blokowaniem w przeglądarce buforowania żądań AJAX, Q ładowaniem JavaScriptu na żądanie, aby zmniejszyć czas ładowania strony.
Wprowadzenie Z pewnością każdy wie, jak działają aplikacje WWW. Wprowadzamy adres URL do przeglądarki, a ta ładuje dla nas stronę. Jeżeli musimy przesłać dane z formularza, to najpierw taki formularz wypełniamy, a następnie przeglądarka wysyła zebrane dane do serwera, gdzie są one przetwarzane. W tym czasie musimy czekać na ponowne załadowanie strony. Jeżeli korzystamy z wolnego łącza, to czas takiego oczekiwania może się znacznie wydłużyć. Przedstawię tu jeszcze inny przykład strony, na której umieszczono dwa pola wyboru. W pierwszym z nich możemy wybrać nazwę państwa, a po dokonaniu wyboru strona jest przeładowywana, tak żeby do drugiego pola wprowadzić nazwy miast z wybranego kraju. Jeżeli przez pomyłkę wybierzemy nie tę pozycję, to korekta tego błędu wymagać będzie kolejnego przeładowania strony. Irytujące?
PHP i jQuery. Receptury
Chodzi mi tutaj o to, że, być może, nie zawsze konieczne jest każdorazowe ładowanie całej strony. Dlaczego nie moglibyśmy po prostu wybrać z listy państwa, a w tle, przy pomocy jakiejś magii, drugie pole wyboru samo załadowałoby się nazwami miast. W przypadku gdy takie żądanie będzie trwać dłużej, moglibyśmy wypełnić kilka innych pól. W tym miejscu na scenę wkracza technologia AJAX. Jej nazwa jest skrótem od Asynchronous JavaScript and XML (asynchroniczny JavaScript i XML), a oznacza technikę pozwalającą na komunikację skryptów działających po stronie klienta ze skryptami działającymi po stronie serwera, z wykorzystaniem standardowych protokołów HTML. Dzięki temu dane mogą być przesyłane między klientem a serwerem bez konieczności przeładowywania strony. Przyjrzyjmy się teraz dokładniej nazwie tej technologii: Q Asynchroniczny — Oznacza to, że żądania realizowane są w tle, przez co znika
konieczność przeładowywania całej strony. Można je też wysyłać równolegle, a w międzyczasie użytkownik może pracować z innymi elementami strony. Nie jest zatem zmuszany do oczekiwania na zakończenie obsługi żądania. Wracając do przykładu z państwami i miastami… owszem, to można zrobić. Q JavaScript — Oznacza, że żądania przesyłane do serwera tworzone są w skryptach
JavaScriptu. Przeglądarki udostępniają własne implementacje obiektu o nazwie XMLHttpRequest. Nie jest on standaryzowany, dlatego poszczególne przeglądarki udostępniają swoje własne implementacje. Q XML — Żądania AJAX mogą być przesyłane do dowolnej platformy, niezależnie,
czy będzie to PHP czy też Java. Oznacza to, że w celu wymiany danych między klientem a serwerem musimy mieć wspólny format danych zrozumiały zarówno dla JavaScriptu, jak i języków serwerowych. Jednym z takich formatów jest XML, za pomocą którego możemy bezproblemowo przesyłać dane. Q Skrót XML w nazwie AJAX nie oznacza, że koniecznie musimy korzystać z formatu
XML. Dane można wymieniać też w innych formatach. Możliwe jest zastosowanie własnego formatu, formatu tekstowego, HTML lub JSON. Najczęściej stosowane są dzisiaj formaty HTML i JSON. Ze względu na to, że implementacja obiektu XMLHttpRequest różni się w poszczególnych przeglądarkach, biblioteka jQuery opakowuje ten obiekt tak, żeby ułatwić przesyłanie danych między językami JavaScript i PHP. Nauczymy się tutaj tworzyć żądania AJAX, wysyłać dane do skryptów PHP i wykonywać różne operacje na otrzymanych danych. Oprócz tego przyjrzymy się mechanizmom obsługi błędów udostępnianym przez bibliotekę jQuery. W tym rozdziale będziemy pracować przede wszystkim z odpowiedziami tekstowymi i w formacie HTML. Ze względu na to, że formaty JSON i XML wymagają dokładniejszego zbadania, poświęcimy im osobny rozdział. 52
Rozdział 2. • Łączenie PHP i jQuery
We wszystkich przedstawionych tu recepturach odwołanie do biblioteki jQuery i związany z nią kod będziemy umieszczać tuż przed zamykającym znacznikiem body, a nie w sekcji head, tak jak do tej pory. Umieszczenie tych plików w sekcji head blokuje rysowanie strony do momentu załadowania wszystkich skryptów. Dzięki umieszczeniu ich na końcu strony cały kod HTML może zostać od razu narysowany, a dokument DOM będzie już gotowy. Po zakończeniu ładowania strony możemy dodać jeszcze pliki JavaScript i jQuery. W ten sposób strona będzie działać szybciej.
Pobieranie danych z PHP za pomocą jQuery W tej recepturze nauczymy się korzystać z metody get udostępnianej przez bibliotekę jQuery do pobierania danych ze skryptów PHP. Zobaczymy tu prosty przykład pobierania danych z serwera z wykorzystaniem metody get na podstawie wyboru dokonanego przez użytkownika w formularzu.
Przygotowania W głównym katalogu serwera WWW utwórz katalog o nazwie rozdzial2 i umieść w nim plik biblioteki jQuery. Utwórz teraz nowy katalog i nazwij go receptura1. Teraz receptury będą składały się z kilku plików, więc lepiej umieszczać je w osobnych katalogach.
Jak to zrobić? 1. W katalogu receptura1 utwórz plik index.html. W tym pliku zapisz kod HTML tworzący pole wyboru z kilkoma opcjami. jQuery.get()
2. Tuż przed zamykającym znacznikiem body wstaw plik biblioteki jQuery i zapisz kod, który dołączy metodę obsługi zdarzenia change do pola wyboru. Funkcja obsługująca zdarzenie otrzyma wybraną w polu wartość i wyśle do skryptu PHP żądanie AJAX, używając do tego metody get. Po zakończeniu obsługi żądania otrzymany w odpowiedzi kod HTML zostanie wstawiony na stronę do istniejącego już na niej akapitu.
3. Przygotujmy teraz skrypt PHP odpowiadający na żądanie AJAX. W tym samym katalogu utwórz plik data.php i wpisz do niego kod sprawdzający, jaki parametr otrzymał w żądaniu. W zależności od wartości tego parametru skrypt PHP utworzy odpowiedni kod HTML i odeśle go z powrotem do przeglądarki.
54
4. Uruchom plik index.html w przeglądarce, a następnie z pola wyboru wybierz jedną z wartości. Biblioteka jQuery wyśle żądanie do skryptu PHP i w odpowiedzi otrzyma sformatowany kod HTML i wyświetli go w przeglądarce.
Jak to działa? W momencie wybrania wartości z listy rozwijanej uruchamiana jest metoda obsługi zdarzenia. Po sprawdzeniu, że wybrana wartość nie jest pusta, wysyłane jest żądanie za pomocą metody get udostępnianej przez bibliotekę jQuery.
55
PHP i jQuery. Receptury
Metoda ta wysyła do skryptu PHP żądanie typu HTTP GET. Wywołanie $.get() przyjmuje cztery parametry, które dokładniej opiszę poniżej. Za wyjątkiem pierwszego wszystkie parametry są opcjonalne: Q URL — wskazuje plik na serwerze, do którego zostanie przesłane żądanie. Może to
być nazwa pliku PHP lub strony HTML. Q Dane — w tym parametrze podawane są dane, które mają zostać przesłane na
serwer. Może on przyjmować postać ciągu znaków lub zbioru par klucz-wartość. Q Funkcja obsługująca — określa funkcję wywoływaną w przypadku udanej obsługi
żądania, czyli w momencie odesłania odpowiedzi przez serwer. Q Typ danych — można tu określić typ HTML, XML, JSON lub skrypt. Jeżeli nie
podamy wartości, to biblioteka jQuery będzie próbowała sama ustalić typ danych. Trzeba pamiętać, że URL podany w żądaniu musi dotyczyć tej samej domeny, w której działa nasza aplikacja. Po prostu przeglądarki ze względów bezpieczeństwa nie pozwalają na uruchamianie żądań pomiędzy domenami. Na przykład, jeżeli dana strona działa w domenie http://abc.com, to może ona wysyłać żądania AJAX tylko do skryptów również działających w domenie http://abc.com lub w jej poddomenach. Próba wysłania żądania na inny adres, taki jak http://innastrona.com/, zostanie zablokowana.
W adresie URL podaliśmy plik data.php. Jako dane żądania przesłany został klucz o nazwie what i wartości wybranej przez użytkownika z listy rozwijanej. Na koniec podano jeszcze nazwę funkcji wywołania zwrotnego. Ze względu na to, że dane wysyłane są metodą GET, zostaną one dołączone do adresu URL. Po wysłaniu żądania musi ono dotrzeć do skryptu PHP zapisanego w pliku data.php. Ze względu na to, że jest to żądanie typu GET, skrypt otrzyma wypełnioną tablicę superglobalną $_GET. W zależności od wartości klucza what (może się tam znaleźć tekst good lub bad) skrypt utworzy tablicę o nazwie $names i przekaże ją do funkcji getHTML(). Funkcja ta tworzy listę wypunktowaną na podstawie nazwisk zapisanych w tablicy i przesyła ją do przeglądarki. Proszę zauważyć, że w skrypcie zastosowano instrukcję echo. Jest ona stosowana do wypisywania ciągów znaków na stronie. W tym przypadku jest jednak używana w ramach obsługi żądania AJAX. Oznacza to, że wynik działania skryptu odsyłany jest do funkcji, która go wywołała. Biblioteka jQuery odbiera takie odpowiedzi i dzięki temu możemy je odebrać w metodzie obsługi zdarzenia success. W tej metodzie wstawiamy tylko otrzymany kod HTML do elementu p o identyfikatorze result.
Zobacz też Q Recepturę „Wysyłanie danych do skryptu PHP” w dalszej części tego rozdziału. Q Recepturę „Tworzenie pustej strony i ładowanie jej w częściach”.
56
Rozdział 2. • Łączenie PHP i jQuery
Automatyczne tworzenie tekstu zapytania na podstawie elementów formularza Przygotowania W katalogu rozdzial2 utwórz katalog receptura2. W tak przygotowanym katalogu utwórz nowy plik o nazwie index.html.
Jak to zrobić? 1. Otwórz plik index.html i wpisz do niego kilka elementów HTML, takich jak pola tekstowe, przyciski i pola wyboru. Serializowanie wartości z formularzy
2. Wprowadź łącze do pliku biblioteki jQuery. Następnie dodaj metodę obsługi zdarzenia click dla przycisku typu input. Użyjemy w niej metody serialize(), a otrzymany ciąg znaków zaprezentujemy za pomocą metody alert().
3. Otwórz w przeglądarce plik index.html, wypełnij formularz i kliknij przycisk Wyślij. Przeglądarka wyświetli wartości pobrane z poszczególnych elementów w formacie tekstu zapytania, podobnym do przedstawionego na poniższym rysunku:
58
Rozdział 2. • Łączenie PHP i jQuery
Jak to działa? Metoda serialize() udostępniana przez bibliotekę jQuery przekształca dane z pól formularza do postaci tekstu zapytania. Zamiast ręcznego pobierania wszystkich wartości i składania tekstu zapytania możemy wywołać tę funkcję, aby w prosty sposób przesłać zawartość wszystkich pól formularza jako dane żądania AJAX. Podczas przesyłania danych na serwer możemy skorzystać z dowolnej metody: GET lub POST.
I coś jeszcze Metoda serializeArray() Inną ciekawą funkcją pobierającą wartości z elementów jest funkcja serializeArray(), która zmienia wszystkie elementy formularza w obiekty JavaScriptu. var data = $('form:first').serializeArray();
Jeżeli w formularzu znajdują się dwa pola tekstowe o nazwach input1 i input2, a w polach tych znajdują się teksty wartość1 i wartość2, to w efekcie działania tej funkcji otrzymamy następujący tekst: [ { input1: 'wartość1' }, { input2: 'wartość2' }, ]
Nie wszystkie wartości są serializowane Proszę pamiętać, że przyciski typu submit oraz elementy wyboru plików nie podlegają serializacji.
Elementy muszą mieć nazwy Aby serializacja elementów formularza przebiegła pomyślnie, nie można zapomnieć o przypisaniu im wszystkim atrybutu name. Jeżeli elementowi przypisano identyfikator, ale nie przypisano nazwy, to nie zostanie on zserializowany.
Zobacz też Q Recepturę „Pobieranie danych z PHP za pomocą jQuery”. Q Recepturę „Wysyłanie danych do PHP”.
59
PHP i jQuery. Receptury
Wykrywanie żądań AJAX w skryptach PHP Po przeczytaniu tej receptury będziemy mogli w skryptach PHP odróżnić żądania AJAX od prostych żądań HTTP.
Przygotowania W katalogu rozdzial2 utwórz nowy katalog receptura3. W nowym katalogu utwórz plik o nazwie index.html oraz drugi o nazwie check.php.
Jak to zrobić? 1. Otwórz plik index.html i wpisz do niego przycisk, który będzie ładował ciąg znaków ze skryptu PHP za pomocą metody get(). Wykrywanie żądań AJAX
2. Następnie dołącz do pliku bibliotekę jQuery i dopisz metodę obsługującą zdarzenie click przycisku. Kliknięcie tego przycisku spowoduje wysłanie żądania AJAX do pliku check.php, który zwróci w odpowiedzi ciąg znaków. Tak otrzymany ciąg znaków zostanie dopisany do strony zaraz za przyciskiem.
3. W ramach sprawdzenia, czy otrzymane żądanie jest rzeczywiście żądaniem AJAX, a nie bezpośrednim wywołaniem z przeglądarki, otwórz plik check.php i wpisz do niego poniższy kod:
4. Uruchom plik index.php w przeglądarce i kliknij przycisk Załaduj dane. Na stronie, tuż za przyciskiem, pojawi się tekst Hura! Żądanie obsłużone!. Teraz w innym oknie przeglądarki wprowadź bezpośrednią ścieżkę do pliku check.php. Na stronie pojawi się tylko tekst komunikatu: To nie jest żądanie AJAX. Ta strona nie może być otwierana bezpośrednio.
Jak to działa? Przeglądarki wysyłają nagłówki HTTP, dołączając je do każdego żądania wysyłanego do serwera. W ramach rozróżnienia między normalnymi żądaniami a żądaniami AJAX nowoczesne biblioteki dołączają do tych ostatnich specjalny nagłówek. Nazwa tego nagłówka to X-Requested-With, a jego wartość to XMLHttpRequest. Superglobalna tablica $_SERVER przechowuje nagłówki wysłane wraz z żądaniem. W naszym przykładzie sprawdziliśmy, czy w tablicy $_SERVER znajduje się klucz o nazwie HTTP_X_REQUESTED_WITH. Jeżeli taki klucz został znaleziony, a jego wartością jest XMLHttpRequest, to możemy założyć, że mamy do czynienia z żądaniem AJAX. W zależności od uzyskanego wyniku instrukcja if wyświetli odpowiedni komunikat.
61
PHP i jQuery. Receptury
I coś jeszcze Nie sprawdzaj tylko klucza X-Requested-With Biblioteka jQuery i większość nowoczesnych bibliotek (takich jak Prototype lub Dojo) wysyła nagłówek X-Requested-With do serwera. Nie zaleca się jednak sprawdzania wyłącznie tego nagłówka. Wynika to z faktu, że nagłówki HTTP mogą zostać poddane manipulacji. Oznacza to, że użytkownik może wysłać żądanie z takim nagłówkiem, a nasz kod założy wtedy, iż ma do czynienia z żądaniem AJAX, choć nie będzie to prawdą. Istnieją jeszcze inne metody sprawdzania rodzaju otrzymanego żądania, ale ich dokładny opis wykracza już poza ramy tej książki.
Wysyłanie danych do PHP GET i POST to dwie najczęściej używane metody dostępu do stron. W pierwszej recepturze poznaliśmy sposoby tworzenia żądań za pomocą metody GET.
W tej recepturze skorzystamy z dostępnej w bibliotece jQuery metody post() i z jej pomocą odczytamy dane ze skryptu PHP. Zobaczymy tu prosty przykład, w ramach którego wypełnimy formularz danymi i wyślemy je do skryptu PHP za pomocą metody POST. Dane te zostaną przetworzone w skrypcie PHP, a na koniec wyświetlone na stronie.
Przygotowania W katalogu rozdzial2 utwórz nowy katalog o nazwie receptura4.
Jak to zrobić? 1. W katalogu receptura4 utwórz nowy plik o nazwie index.html. W tej recepturze wykorzystamy ten sam formularz, którego użyliśmy już w drugiej recepturze (Automatyczne tworzenie tekstu zapytania na podstawie elementów formularza) tego rozdziału. Przygotuj zatem kod HTML tworzący formularz z wieloma kontrolkami. Wysyłanie danych metodą post
62
Rozdział 2. • Łączenie PHP i jQuery
2. Dołącz plik biblioteki jQuery i dopisz metodę obsługi zdarzeń przycisku. Kliknięcie tego przycisku spowoduje wysłanie żądania AJAX do skryptu PHP za pośrednictwem metody HTTP POST. Po zakończeniu obsługi tego żądania formularz zostanie ukryty, a tekst odpowiedzi przesłanej przez skrypt PHP zostanie wstawiony do akapitu.
3. Żądanie zostanie przesłane do pliku PHP, dlatego w tym samym katalogu utwórz nowy plik o nazwie process.php. Kod zapisany w tym pliku utworzy ciąg znaków na podstawie danych wprowadzonych przez użytkownika do formularza. Tak przygotowany tekst zostanie odesłany do przeglądarki, aby potwierdzić wartości z formularza. '; $responseString.= 'E-mail: '.$_POST['email']; $responseString.= ' '; $responseString.= 'Płeć: '.$_POST['sex']; $responseString.= ' '; $responseString.= 'Kraj: '.$_POST['country']; header('Content-type:text/html'); echo $responseString; ?>'
4. Uruchom w przeglądarce plik index.html, a zobaczysz formularz z kilkoma polami. Wypełnij wszystkie pola i kliknij przycisk Wyślij. Formularz zostanie wtedy ukryty, a na stronie pojawi się tekst potwierdzający dane z formularza. Drogi/droga Vijay Joshi, Twoje informacje kontaktowe zostały zapisane. Otrzymaliśmy od Ciebie następujące dane: E-mail: [email protected] Płeć: Mężczyzna Kraj: Indie
64
Rozdział 2. • Łączenie PHP i jQuery
Jak to działa? Do przycisku Wyślij dowiązaliśmy metodę obsługi zdarzenia click. Kliknięcie przycisku wysyła żądanie do serwera za pośrednictwem metody post() z biblioteki jQuery. Metoda post() jest bardzo podobna do metody get(). Istnieje między nimi tylko kilka drobnych różnic. Pierwszą i podstawową różnicą jest fakt, że metoda post() uruchamia żądania typu POST, a metoda get() żądania typu GET. Druga różnica polega na tym, że żądania POST nie są buforowane przez przeglądarkę, a żądania typu GET zawsze lądują w buforze. Oznacza to, że włączenie opcji buforowania w żądaniach typu POST nie będzie miało żadnego efektu. Poza tym obie te metody mają identyczne sygnatury. W naszym przykładzie żądanie kierowane jest do pliku process.php, któremu przekazywane są zserializowane dane z formularza. Ze względu na to, że jest to żądanie typu POST, danymi wypełniana jest superglobalna tablica $_POST. Następnie pobieramy poszczególne pola z tej tablicy i umieszczamy zawarte w nich dane w sformatowanym ciągu znaków. Po przygotowaniu tego tekstu odsyłamy go do przeglądarki za pomocą instrukcji echo. Po otrzymaniu pozytywnej odpowiedzi ukrywamy formularz i wstawiamy otrzymany kod HTML do akapitu.
I coś więcej Alternatywa dla metody post() Metody post(), get() i inne z tej grupy można też zaimplementować za pomocą metody ajax(). Poniżej prezentuję implementację metody post() za pomocą metody ajax(). W kolejnych recepturach zobaczymy jeszcze kilka innych zastosowań metody ajax(). $.ajax( { url: 'process.php', method: 'post', data: $('form:first').serialize(), dataType: 'html', success: function(response) { $('#information').hide(); $('#response').html(response); } });
65
PHP i jQuery. Receptury
Ze względu na to, że metoda ajax() daje nam większe pole manewru niż metoda post(), możemy z niej skorzystać, w przypadku gdybyśmy chcieli przypisać do żądania funkcję obsługi błędu.
Zobacz też Q Recepturę „Pobieranie danych z PHP za pomocą jQuery”, która dokładniej objaśnia działanie metody get(). Q Recepturę „Automatyczne tworzenie tekstu zapytania na podstawie elementów
formularza”. Q Recepturę „Obsługa błędów w żądaniach AJAX”, która prezentuje metodę obsługi błędów powstających podczas obsługi żądań AJAX.
Przerywanie żądań AJAX Rozważmy teraz sytuację, w której użytkownik wybiera na stronie WWW datę, a następnie wysyłane jest do serwera żądanie AJAX nakazujące pobranie danych związanych z tą datą. Jeżeli w czasie przetwarzania pierwszego żądania użytkownik wybierze inną datę, to wysłane zostanie kolejne żądanie, a serwer będzie musiał obsłużyć dwa żądania równolegle. Wyobraźmy sobie, co będzie się działo, jeżeli z aplikacji będzie korzystać wielu użytkowników ciągle powtarzających tę samą operację. W takiej sytuacji najlepiej byłoby anulować wcześniejsze żądanie i pozwolić na obsługę tylko najaktualniejszego. W tej recepturze wyjaśnimy, jak należy anulować wysłane wcześniej żądania.
Przygotowania W katalogu rozdzial2 utwórz nowy katalog o nazwie receptura5.
Jak to zrobić? 1. Wykorzystamy tutaj ten sam kod HTML, którego użyliśmy już w pierwszej recepturze tego rozdziału. Utwórz zatem plik index.html i wpisz do niego kod strony zawierającej dwie listy rozwijane i dwie opcje. Oprócz tego utwórz element akapitu (p), w którym będziemy wyświetlać otrzymane odpowiedzi. Przerywanie żądań AJAX
66
Rozdział 2. • Łączenie PHP i jQuery
2. Teraz wpisz kod korzystający z biblioteki jQuery. Zdefiniuj zmienną globalną, a następnie dołącz metodę obsługi zdarzeń do listy rozwijanej. Funkcja obsługi zdarzenia sprawdza, czy do serwera zostało już wysłane żądanie. Jeżeli jakieś żądanie jest już obsługiwane, to nasza funkcja je anuluje i wyśle nowe.
3. Na koniec potrzebujemy jeszcze skryptu PHP. Utwórz nowy plik i nazwij go wait.php. Wpisz do niego ten sam kod, którego użyliśmy w recepturze „Pobieranie danych z PHP za pomocą jQuery”. Nasz skrypt będzie sprawdzał otrzymane wartości i odsyłał dopasowaną do nich odpowiedź. W tym przykładzie jednak skrypt będzie czekał 10 sekund na wysłanie odpowiedzi, tak żebyśmy mieli okazję wysłać w tym czasie kilka żądań. '; for($i=0; $i" .$names[$i].'< li>'; } $strResult.= ''; return $strResult; } ?>
4. Teraz uruchom w przeglądarce plik index.php i wybierz z listy rozwijanej jedną z wartości. Skrypt PHP odeśle nam odpowiedź dopiero po 10 sekundach. Teraz wybierz z listy inną wartość. Poprzednie żądanie zostanie anulowane, a do serwera zostanie wysłane nowe. Otrzymana w końcu odpowiedź dotyczyła będzie tylko ostatnio wysłanego żądania. Nie otrzymamy natomiast odpowiedzi na żadne z wcześniejszych żądań.
68
Rozdział 2. • Łączenie PHP i jQuery
Jak to działa? Wszystkie metody biblioteki jQuery związane z technologią AJAX zwracają obiekt XMLHttpRequest. Zadeklarowaliśmy zatem globalną zmienną ajax, w której zapisujemy ten obiekt. W momencie wybrania wartości z listy rozwijanej funkcja obsługująca to zdarzenie sprawdza zawartość zmiennej ajax. W przypadku dokonania pierwszego wyboru zawartość tej zmiennej nie będzie zdefiniowana, a zatem żądanie zostanie wysłane do pliku wait.php. Utworzony przy tym obiekt XMLHttpRequest zostanie natomiast zapisany w zmiennej ajax. Przy następnej zmianie wartości wybranej z listy rozwijanej w zmiennej ajax zapisany będzie już obiekt XMLHttpRequest utworzony na potrzeby poprzedniego żądania. Obiekt ten udostępnia metodę abort(), która anuluje dane żądanie. W naszym przykładzie takie obsługiwane jeszcze przez serwer żądanie jest anulowane i przygotowywane jest nowe, które również zapisywane jest do zmiennej ajax. Jak widać, wybranie nowej wartości z listy wyboru w ciągu 10 sekund od dokonania ostatniego wyboru spowoduje anulowanie dotychczasowego żądania i wysłanie do nowego.
Zobacz też Q Recepturę „Obsługa błędów w żądaniach AJAX”.
Tworzenie pustej strony i ładowanie jej w częściach Im większa będzie nasza strona, tym więcej czasu potrzebować będzie przeglądarka, aby ją załadować. Może to mieć negatywny wpływ na zadowolenie użytkownika, szczególnie korzystającego z wolniejszego łącza. Jednym z rozwiązań tego problemu jest natychmiastowe ładowanie tylko niezbędnych elementów strony i doładowywanie pozostałych elementów tylko wtedy, gdy faktycznie będą potrzebne. W końcu niektóre części strony używane są niezmiernie rzadko. Dzięki temu strona będzie ładowała się szybciej, co z pewnością ucieszy użytkownika. W tej recepturze zademonstrujemy prosty przykład zastosowania tej metody. Utworzymy prostą stronę HTML i pozwolimy użytkownikowi załadować jedną z jej sekcji.
69
PHP i jQuery. Receptury
Przygotowania W katalogu rozdzial2 utwórz nowy katalog o nazwie receptura6.
Jak to zrobić? 1. Utwórz nowy plik i nadaj mu nazwę index.html. Nowa strona będzie składała się z trzech części: nagłówka, treści i stopki. Kod HTML stopki nie zostanie jednak umieszczony w pliku strony, ale będzie ładowany później, na żądanie. Oprócz tego w sekcji head strony umieściliśmy kilka stylów CSS zmieniających wygląd strony. Ładowanie strony po kawałku
Moja nowa, doskonała strona
Aliquam quis massa at elit fermentum vestibulum. Vestibulum id nunc et nulla placerat gravida. Praesent sed purus ante. Vestibulum pulvinar tortor sed odio accumsan a cursus magna pellentesque. In hac habitasse platea dictumst. Cras viverra sodales sem in facilisis. Nulla congue, risus eget gravida feugiat, nisi ante laoreet est, ullamcorper hendrerit lacus velit eget urna. Suspendisse rutrum lacus eget nulla semper sit amet egestas tellus scelerisque. Maecenas at vulputate enim. Etiam blandit magna iaculis tellus tincidunt vel ornare diam.
70
Rozdział 2. • Łączenie PHP i jQuery
2. Następnie musimy utworzyć plik zawierający kod HTML stopki. Utwórz nowy plik o nazwie footer.html i zapisz w nim poniższy kod:
href="#">Link1 href="#">Link2 href="#">Link3 href="#">Link4 href="#">Link5
3. W ramach łączenia tych dwóch elementów wracamy do pliku index.html i zapisujemy do niego kod korzystający z biblioteki jQuery, powiązany z łączem Pokaż stopkę.
4. Otwórz w przeglądarce plik index.html i kliknij na stronie łącze Pokaż stopkę. Biblioteka jQuery załaduje wtedy kod HTML stopki z pliku footer.html i wstawi go w odpowiednie miejsce na stronie.
71
PHP i jQuery. Receptury
Jak to działa? Biblioteka jQuery udostępnia metodę load(), która działa na elementy HTML. Pobiera ona dane z serwera i wstawia je do elementu HTML, który ją wywołał. Metoda load() przyjmuje trzy parametry. Pierwszym jest adres URL, z którego mają być pobrane dane. Drugi to dane, które mają zostać wysłane do serwera, a trzecim jest funkcja wywołania zwrotnego, która wywoływana jest po otrzymaniu danych. W poprzednim przykładzie kliknięcie łącza Pokaż stopkę wywołuje metodę load() na rzecz elementu o identyfikatorze footer. W efekcie ładowana jest zawartość pliku footer.html, w którym zapisany jest cały kod HTML stopki. Po udanym pobraniu tego pliku z serwera kod HTML wstawiany jest do stopki strony.
I coś jeszcze Różnica między metodą load() i get() Obie te metody są do siebie bardzo podobne, z tym że zadaniem metody load() jest praca na elemencie strony wybranym przez selektor. Po zakończeniu żądania kod HTML wpisywany jest do elementu określonego selektorem. Z drugiej strony metoda get() jest metodą globalną, która ma ściśle zdefiniowaną metodę wywołania zwrotnego.
72
Rozdział 2. • Łączenie PHP i jQuery
Zobacz też Q Recepturę „Pobieranie danych z PHP za pomocą jQuery”. Q Recepturę „Wysyłanie danych do PHP”. Q Recepturę „Ładowanie JavaScriptu na żądanie, aby zmniejszyć czas ładowania strony”.
Obsługa błędów w żądaniach AJAX Błędy są nieuniknione. Kropka. Czasami rzeczy pozostają poza naszą kontrolą (na przykład awarie serwera) i w takich sytuacjach musimy mieć gotowy mechanizm obsługi błędów, który odpowiednio zareaguje, informując użytkownika o zaistniałej sytuacji. W recepturach prezentowanych w tym rozdziale zawsze implementowaliśmy funkcje wywołania zwrotnego wykonywane w momencie zakończenia obsługi żądania. Może się jednak zdarzyć (i obiecuję, że na pewno się zdarzy), iż nieprawidłowo podamy nazwę pliku albo w serwerze wystąpi błąd i zamiast właściwej odpowiedzi dostaniemy tylko informację o błędzie. W tej recepturze wyjaśnię metody radzenia sobie w takiej sytuacji.
Przygotowania W katalogu rozdzial2 utwórz katalog receptura7.
Jak to zrobić? 1. W katalogu receptura7 utwórz nowy plik o nazwie index.html. Zdefiniuj w nim kilka stylów CSS i utwórz przycisk oraz pole tekstowe, w które użytkownik będzie wpisywał nazwę pliku do załadowania. Oprócz tego utwórz też akapit, w którym wyświetlana będzie zawartość załadowanego pliku. Obsługa błędów
2. Przed zamykającym znacznikiem body dołącz plik biblioteki jQuery i wpisz kod korzystający z metody ajax(), który uruchomi żądanie AJAX ładujące plik zdefiniowany przez użytkownika. W kodzie trzeba zdefiniować dwie metody wywołania zwrotnego, obsługujące sukces i błąd żądania.
3. Utwórz kolejny plik HTML i nazwij go books.html. W pliku tym wpisz listę wypunktowaną z tytułami książek:
Studium w szkarłacie
74
Rozdział 2. • Łączenie PHP i jQuery
Znak Czterech
Przygody Sherlocka Holmesa
Wspomnienia Sherlocka Holmesa
Pies Baskerville'ów
Powrót Sherlocka Holmesa
Księga przypadków Sherlocka Holmesa
4. Uruchom w przeglądarce plik index.html. Wprowadź w polu tekstowym nazwę pliku books.html i kliknij przycisk Załaduj plik. Biblioteka jQuery wyśle wtedy żądanie AJAX, a na stronie pojawi się ładnie sformatowana lista książek. Jeżeli jednak pole tekstowe będzie puste, a klikniemy przycisk Załaduj plik, to pojawi się komunikat o błędzie.
5. Teraz proszę wprowadzić nazwę nieistniejącego pliku, taką jak brak.html lub none.html. Po kliknięciu przycisku Załaduj plik wyświetlony zostanie komunikat o błędzie.
75
PHP i jQuery. Receptury
Jak to działa? W tym przykładzie korzystamy z niskopoziomowej implementacji technologii AJAX w bibliotece jQuery. Inne metody, takie jak get() lub post() i inne, są tylko specjalizowanymi implementacjami metody ajax(). Jak widzieliśmy, metoda get() zajmuje się obsługą żądań GET, natomiast metoda getScript() używana jest tylko do ładowania skryptów. Jedną z wielu opcji metody ajax() jest funkcja wywołania zwrotnego na wypadek wystąpienia błędu. Jeżeli w czasie obsługi żądania wystąpi błąd, taki jak brak pliku, opóźnienie na serwerze albo inny błąd serwera, to wywołana zostanie ta właśnie funkcja. Metody wyższego poziomu w takiej sytuacji nie wykonują żadnej operacji. W poprzednim przykładzie wykorzystaliśmy funkcję wywołania zwrotnego do wyświetlenia na stronie komunikatu o błędzie. Celowo wpisaliśmy nazwę nieistniejącego pliku, a biblioteka jQuery przekazała sterowanie do funkcji obsługującej błędy.
I coś jeszcze Parametry przekazywane do funkcji obsługi błędu Biblioteka jQuery przekazuje funkcji obsługi błędu trzy parametry. Pierwszym jest obiekt XMLHttpRequest utworzony w ramach żądania, drugim — ciąg znaków z typem błędu, a trzecim (opcjonalnym) wyjątek powstały w kodzie JavaScript.
76
Rozdział 2. • Łączenie PHP i jQuery
W ciągu znaków przekazywanym w drugim parametrze mogą się znaleźć następujące teksty: timeout, notmodified, parseerror lub null.
Błąd ajaxError() Inną metodą, którą można przyłączyć do elementów HTML, jest metoda ajaxError(). Metoda ta będzie wykonywana za każdym razem, gdy podczas obsługi żądania AJAX powstanie jakiś błąd. $('#result').ajaxError(function() { $(this).html('Wystąpił błąd.'); })
Powyższy kod wystarczy umieścić wewnątrz metody document.ready(), a następnie usunąć funkcję obsługi błędu z kodu naszego przykładu. Teraz po wprowadzeniu nieprawidłowej nazwy pliku i kliknięciu przycisku zobaczymy, że komunikat o błędzie nadal się pojawia. Ta metoda może okazać się bardzo użyteczna, jeżeli żądania AJAX na naszej stronie generowane są w wielu miejscach, a chcielibyśmy mieć centralny punkt obsługi wszystkich błędów. Taki komunikat o błędzie będzie pojawiał się zawsze, ponieważ funkcja wywoływana jest niezależnie od tego, gdzie wygenerowano żądanie.
Zobacz też Q Recepturę „Pobieranie danych z PHP za pomocą jQuery”. Q Recepturę „Wysyłanie danych do PHP”. Q Recepturę „Tworzenie pustej strony i ładowanie jej w częściach”. Q Recepturę „Ładowanie JavaScriptu na żądanie, aby zmniejszyć czas ładowania strony”.
Blokowanie w przeglądarce buforowania żądań AJAX W przypadku żądań typu GET przeglądarka umieszcza je w swojej pamięci podręcznej i w przypadku ponownego wysłania tego samego żądania nie jest ono przesyłane na serwer, tylko obsługiwane z bufora. W tej recepturze wyjaśnię, jak zmusić przeglądarkę do wysłania żądania do serwera za każdym razem, z pominięciem pamięci podręcznej.
77
PHP i jQuery. Receptury
Jak to zrobić? 1. Podczas wysyłania żądania AJAX użyj opcji cache, aby wyłączyć buforowanie tego żądania w przeglądarce. Nadanie opcji cache wartości false nie pozwala przeglądarce na buforowanie jakichkolwiek żądań AJAX, a zatem za każdym razem dane są pobierane z serwera. $.ajax({ url : 'someurl.php', cache: false, success: function(data) { //zrób coś z otrzymanymi danymi } });
Jak to działa? W przypadku żądań AJAX przeglądarka sprawdza najpierw, czy żądanie z takim adresem URL znajduje się już w jej pamięci podręcznej. Jeżeli takie żądanie zostanie w niej znalezione, to nie jest ono wysyłane do serwera, ale odpowiedź pobierana jest z pamięci podręcznej. Biblioteka jQuery udostępnia nam opcję cache, której można użyć, aby zablokować zachowanie przeglądarki. Domyślnie opcja ta ma wartość true, a po przypisaniu jej wartości false biblioteka jQuery doda do adresu URL żądania klucz znaku podkreślenia (_) i losowo wybraną liczbę. Dzięki temu przeglądarka będzie zakładała, że za każdym razem ma do czynienia z osobnym żądaniem, mimo iż zmieni się tylko jedna nieistotna wartość w adresie URL. Oznacza to, że przeglądarka nie będzie mogła buforować żądań, a te będą za każdym razem przesyłane do serwera.
I coś jeszcze Buforowane są tylko żądania typu GET Warto tutaj wspomnieć, że w pamięci podręcznej przeglądarki umieszczane są tylko żądania typu GET, ale już żądania typu POST nie podlegają buforowaniu. Oznacza to, że opcja cache zastosowana wobec żądania typu POST nie ma na nie żadnego wpływu. Po prostu każde żądanie tego typu jest unikalne.
78
Rozdział 2. • Łączenie PHP i jQuery
Zobacz jeszcze Q Receptura „Pobieranie danych z PHP za pomocą jQuery” wyjaśnia zasady używania metody get() do tworzenia żądań typu GET. Q Receptura „Wysyłanie danych do PHP” objaśnia sposoby użycia metody post() do tworzenia żądań typu POST.
Ładowanie JavaScriptu na żądanie, aby zmniejszyć czas ładowania strony Wyobraźmy sobie rozbudowaną aplikację internetową, która często korzysta z JavaScriptu, aby komunikować się z użytkownikiem. Taka strona zwykle składa się z kilku plików zawierających skrypty JavaScript. Na przykład w jednym pliku zdefiniowana jest kontrolka kalendarza, w drugim powstają efekty specjalne, a jeszcze jeden zajmuje się tworzeniem harmonijek. Wszystko to powoduje wydłużenie czasu ładowania strony, ponieważ przeglądarki nie mogą pobierać wszystkich tych plików jednocześnie. Najlepszym rozwiązaniem jest zatem ładowanie tylko absolutnie niezbędnych plików i późniejsze doładowywanie kolejnych w razie potrzeby. W tej recepturze nauczymy się używać JavaScriptu do ładowania plików na żądanie.
Przygotowania W katalogu rozdzial2 utwórz nowy katalog receptura9.
Jak to zrobić? 1. W katalogu receptura9 utwórz plik index.html. Zapisz w nim kod HTML tworzący stronę składającą się z akapitu i czterech przycisków. Pierwszego przycisku użyjemy do załadowania kolejnego pliku JavaScript, a pozostałe przyciski będą manipulowały zawartością akapitu. Przykład z getScript
2. Przed zamykającym znacznikiem body dołącz plik biblioteki jQuery i dopisz funkcję obsługi zdarzenia click pierwszego przycisku. Po kliknięciu tego przycisku biblioteka jQuery załaduje zewnętrzny plik JavaScript. Po udanym załadowaniu tego pliku wywołana zostanie funkcja o nazwie addEvents(), która doda funkcje obsługi kliknięć pozostałych trzech przycisków.
3. Teraz w tym samym katalogu utwórz nowy plik i nazwij go new.js. Zdefiniuj w nim funkcję addEvents(), która będzie dodawała funkcje obsługi zdarzenia click w trzech przyciskach. function addEvents() { $('.bold').click(function() { $('#container').css('font-weight', 'bold'); }); $('.color').click(function() { $('#container').css('color', 'red'); }); $('.change').click(function() { $('#container').html('Wstawiono nowy kod HTML'); }); }
80
Rozdział 2. • Łączenie PHP i jQuery
4. Otwórz w przeglądarce plik index.html. Kliknij dowolny z przycisków oprócz przycisku Załaduj skrypt. Okaże się, że takie klikanie nie daje żadnych efektów i tekst w akapicie się nie zmienia. Teraz kliknij przycisk Załaduj skrypt. Pojawi się okienko z informacją, że skrypt został załadowany. Od tego momentu klikanie pozostałych trzech przycisków będzie powodowało zmiany w akapicie.
Jak to działa? Kliknięcie przycisku Załaduj skrypt powoduje wywołanie metody getScript() udostępnianej przez bibliotekę jQuery. Funkcja ta przyjmuje dwa parametry: nazwę pliku do załadowania oraz funkcję wywołania zwrotnego wywoływaną po zakończeniu ładowania pliku. Wskazany plik jest ładowany z serwera w sposób asynchroniczny. Po zakończeniu ładowania wszystkie zmienne i funkcje z tego pliku stają się dostępne w kontekście globalnym. Oznacza to, że mogą być używane przez inne funkcje i pliki JavaScript. Wywołanie funkcji zwrotnej gwarantuje nam, że plik został w pełni załadowany i możemy bezpiecznie pracować z zawartymi w nim zmiennymi i funkcjami. W naszym przykładzie funkcja addEvents() została zdefiniowana w pliku new.js. Funkcja ta zajmuje się definiowaniem obsługi zdarzenia click w przyciskach dostępnych na stronie. Początkowo plik new.js nie jest dostępny na stronie, dlatego przyciski te nie spełniają żadnej funkcji. Po załadowaniu tego pliku wywoływana jest jednak funkcja addEvents(), która przypisuje przyciskom konkretne działania. Od tego momentu przyciski zaczynają wpływać na akapit.
81
PHP i jQuery. Receptury
I coś jeszcze Alternatywy dla metody getScript() Metoda getScript() przeznaczona jest do ładowania skryptów. Ten sam efekt można jednak uzyskać za pomocą metody ajax(). $.ajax( { url: 'new.js', dataType: 'script', success: function() { alert('Skrypt został załadowany!'); addEvents(); } });
Powyższy kod również załaduje plik new.js i wykona znajdującą się w nim funkcję. Z tego rozwiązania można skorzystać, w przypadku gdy chcemy zająć się obsługą ewentualnych błędów, co nie jest możliwe, jeżeli skorzystamy z metody getScript(). Proszę też zwrócić uwagę na wykorzystanie w tym rozwiązaniu opcji dataType, dla której zdefiniowaliśmy wartość script. Parametr ten informuje bibliotekę jQuery, jakiego typu będą dane, które otrzyma z serwera (w tym przypadku będzie to skrypt).
Zobacz też Q Recepturę „Pobieranie danych z PHP za pomocą jQuery”, która wyjaśnia sposób użycia metody get() do pobierania danych. Q Recepturę „Wysyłanie danych do PHP”, w której wyjaśniane są sposoby wysyłania
danych do skryptów PHP za pomocą biblioteki jQuery. Q Recepturę „Tworzenie pustej strony i ładowanie jej w częściach”.
82
3 Praca z dokumentami XML W tym rozdziale zajmiemy się: Q ładowaniem danych XML z plików oraz ciągów znaków za pomocą SimpleXML, Q korzystaniem z elementów i atrybutów za pomocą SimpleXML, Q wyszukiwaniem elementów za pomocą XPath, Q odczytywaniem dokumentów XML za pomocą rozszerzenia DOM, Q tworzeniem dokumentów XML za pomocą rozszerzenia DOM, Q modyfikowaniem dokumentów XML za pomocą rozszerzenia DOM, Q parsowaniem dokumentów XML za pomocą biblioteki jQuery.
Wprowadzenie Język XML (ang. Extensible Markup Language — elastyczny język znaczników) jest strukturą reprezentacji danych w formacie zrozumiałym dla człowieka. W przeciwieństwie do tego, co sugeruje nazwa, tak naprawdę nie jest to język, ale zbiór znaczników ukierunkowanych na definiowanie struktury danych. Składnia języka XML jest bardzo podobna do składni języka HTML, z tą różnicą, że ten ostatni przeznaczony jest do prezentacji danych, a pierwszy do ich przechowywania i wymiany. Co więcej wszystkie znaczniki języka XML są zdefiniowane przez użytkownika i można je formatować zgodnie z własnymi potrzebami. Niemniej jednak dokumenty XML muszą przestrzegać zasad określonych przez organizację W3C.
PHP i jQuery. Receptury
Dzięki znacznemu wzrostowi liczby aplikacji rozproszonych działających w internecie format XML stał się najczęściej stosowaną metodą wymiany danych. Usługi sieciowe korzystają z formatu XML do przenoszenia danych pomiędzy poszczególnymi częściami aplikacji. Dzięki temu, że język XML jest całkowicie niezależny od platformy i można go zapisać w postaci ciągu znaków, korzystają z niego aplikacje działające na różnego rodzaju technologiach serwerowych, komunikując się ze sobą za jego pośrednictwem. Proszę przyjrzeć się poniższemu dokumentowi XML:
Na podstawie tego dokumentu możemy wywnioskować, że jest to lista stron WWW zawierająca nazwę, adres URL oraz dodatkowe informacje na temat poszczególnych stron. W języku PHP dostępnych jest kilka klas i funkcji pozwalających na pracę z dokumentami XML. Za ich pomocą możemy łatwo odczytywać, zapisywać, modyfikować i przeszukiwać dokumenty. W tym rozdziale omawiać będziemy funkcje z dodatku SimpleXML oraz klasy DOMDocument pozwalające na manipulowanie dokumentami XML w języku PHP. Nauczymy się, jak należy czytać i modyfikować pliki XML, używając do tego interfejsów API bibliotek SimpleXML i DOM. Poznamy też metodę XPath, która bardzo ułatwia wyszukiwanie danych w dokumentach. Trzeba tu zauważyć, że możemy pracować tylko z prawidłowo sformatowanymi i zbudowanymi dokumentami XML. Istnieje wiele reguł opisujących prawidłową budowę dokumentu XML, spośród których poniżej przedstawiam zaledwie kilka: Dokument XML musi mieć tylko jeden element główny. Nie można wykorzystywać znaków specjalnych, takich jak nawiasy ostre (< i >) itp. Każdy znacznik XML musi mieć swój znacznik zamykający. W nazwach znaczników rozróżniane są wielkości znaków. Więcej informacji na temat prawidłowej budowy dokumentu XML znaleźć można pod adresem: http://pl.wikipedia.org/wiki/XML#Poprawno.C5.9B.C4.87_dokumentu.
84
Rozdział 3. • Praca z dokumentami XML
W większości receptur z tego rozdziału korzystać będziemy ze wstępnie przygotowanego pliku XML. Utwórz nowy plik o nazwie common.xml i zapisz go w katalogu rozdzial3. Do utworzonego pliku zapisz poniższy dokument XML. Przygody Sherlocka HolmesaSkandal w BohemiiPatrzysz, ale nie widzisz. Różnica jest oczywista.Związek rudowłosychTo problem na trzy fajki, dlatego proszę, żebyś nie mówił do mnie nic przez pięćdziesiąt minut.Człowiek z wywiniętą wargąTo jest oczywiście drobiazg, ale nie ma nic ważniejszego niż drobiazgi.Księga przypadków Sherlocka HolmesaWilla o trzech daszkachNie jestem prawem, ale reprezentuję sprawiedliwość na tyle, na ile mi siły pozwalają.Zabójstwo przy mościeMusimy szukać niesprzeczności. Gdzie tylko pojawi się jej zalążek, należy oczekiwać podstępu.Tajemnica dworu w ShoscombePsy nie popełniają błędów.Wspomnienia Sherlocka HolmesaŻółta twarzKażda prawda jest lepsza od nieokreślonych wątpliwości.Urzędnik maklerskiEfekty bez przyczyny robią o wiele większe wrażenie.
85
PHP i jQuery. Receptury
Ostatnia zagadkaJeżeli miałbym pewność twojej ostatecznej zagłady, to w interesie ogółu z chęcią zaakceptowałbym swoją.
Ładowanie danych XML z plików oraz ciągów znaków za pomocą SimpleXML Zgodnie ze swoją nazwą funkcje ze zbioru SimpleXML umożliwiają łatwy dostęp do danych zapisanych w dokumentach XML. Pliki lub ciągi znaków XML można konwertować do postaci obiektów, a następnie odczytywać z nich dane. Dowiemy się tu, jak odczytać dokument XML z pliku lub ciągu znaków za pomocą funkcji SimpleXML. Nauczymy się też radzić sobie z błędami w dokumentach XML.
Przygotowania Utwórz nowy katalog o nazwie rozdzial3. W tym katalogu będziemy umieszczać podkatalogi poszczególnych receptur. Utwórz zatem jeszcze jeden katalog o nazwie receptura1.
Jak to zrobić? 1. W katalogu receptura1 utwórz plik index.php i wpisz do niego kod PHP, który będzie ładował plik common.xml. Po załadowaniu tego pliku na stronie zostanie wyświetlona lista z tytułami książek. Skorzystamy też z funkcji biblioteki libxml, która wykryje ewentualne błędy i wyświetli na ekranie szczegółowe informacje na ich temat. message,' '; }
2. Otwórz w przeglądarce plik index.php. Dzięki temu, że już wcześniej sprawdziliśmy poprawność pliku XML, zobaczymy na ekranie następujące tytuły książek: Przygody Sherlocka Holmesa Księga przypadków Sherlocka Holmesa Wspomnienia Sherlocka Holmesa
3. Spróbujmy teraz zepsuć nasz plik XML. W tym celu otwórz plik common.xml w edytorze i usuń dowolny ze znaczników (na przykład znacznik zamykający tytułu pierwszej książki). Zapisz plik i ponownie załaduj plik index.php w przeglądarce. Zobaczysz tylko komunikat o błędzie podobny do poniższego:
Jak to działa? W pierwszym wierszu przekazujemy wartość true do funkcji libxml_use_internal_errors, która blokuje wszystkie błędy XML i pozwala nam na obsłużenie ich w naszym kodzie. W drugim wierszu próbujemy załadować plik XML za pomocą funkcji simplexml_load_file. Jeżeli uda się go załadować bez problemów, to otrzymamy od funkcji obiekt SimpleXMLElement, a w przypadku wystąpienia błędów — wartość false.
87
PHP i jQuery. Receptury
Następnie kontrolujemy wartość otrzymaną od wywołanej funkcji. Jeżeli jest to wartość false, to za pomocą funkcji libxml_get_errors() pobieramy listę błędów w postaci tablicy. Elementy tablicy będą tu obiektami typu LibXMLError, a każdy z nich będzie udostępniał kilka właściwości. W zaprezentowanym kodzie iterujemy po całej tablicy errors i wypisujemy na stronie właściwość message każdego z obiektów, która powinna dokładnie opisywać dany błąd. Jeżeli w dokumencie XML nie ma żadnych błędów, to otrzymujemy obiekt typu SimpleXMLElement, który zawiera wszystkie dane z załadowanego dokumentu. Iterujemy zatem po elementach book za pomocą instrukcji foreach i wypisujemy nazwy książek.
I coś jeszcze Parametry funkcji simplexml_load_file() Funkcja simplexml_load_file() może przyjmować jeszcze inne parametry: Q filename — Pierwszy parametr jest obowiązkowy. Może to być ścieżka do lokalnego
pliku albo adres URL. Q class_name — Klasę SimpleXMLElement można jeszcze rozbudować. W takiej sytuacji
możemy tutaj podać nazwę klasy, a funkcja będzie zwracała obiekty tej właśnie klasy. Tan parametr jest opcjonalny. Q options — Trzeci parametr funkcji pozwala podać opcje dla biblioteki libxml,
dzięki którym dokładniej panujemy nad procesem ładowania pliku XML. Ten parametr jest opcjonalny.
Funkcja simplexml_load_string() Funkcja simplexml_load_string() jest bardzo podobna do funkcji simplexml_load_file(). Po udanym załadowaniu dokumentu XML również zwraca obiekt typu SimpleXMLElement. Jeżeli funkcji przekażemy prawidłowo zbudowany ciąg znaków XML, to otrzymamy obiekt, a w przeciwnym przypadku tylko wartość false. $objXML = simplexml_load_string('Moja ulubiona książka');
Podany wyżej kod zwraca obiekt SimpleXMLElement z danymi załadowanymi z ciągu znaków XML. Drugi i trzeci parametr tej funkcji jest dokładnie taki sam, jak w przypadku funkcji simplexml_load_file().
Tworzenie obiektu za pomocą klasy SimpleXMLElement Możemy też wykorzystać konstruktor klasy SimpleXMLElement do tworzenia nowych obiektów.
88
Rozdział 3. • Praca z dokumentami XML
$objXML = new SimpleXMLElement('Moja ulubiona książka');
Więcej informacji na temat bibliotek SimpleXML i libxml Więcej informacji na temat biblioteki SimpleXML można znaleźć na stronie PHP pod adresem http://www.php.net/manual/pl/book.simplexml.php. Z kolei informacje na temat biblioteki libxml można znaleźć pod adresem http://www.php.net/manual/pl/book.libxml.php.
Zobacz też Q Recepturę „Korzystanie z elementów i atrybutów za pomocą SimpleXML”. Q Recepturę „Wyszukiwanie elementów za pomocą XPath”.
Korzystanie z elementów i atrybutów za pomocą SimpleXML W tej recepturze dowiemy się, jak można pobrać wartości węzła lub atrybutu z pliku XML, wykorzystując do tego bibliotekę SimpleXML. Przedstawiony tu przykład będzie używał pliku common.xml, z którego pobierać będziemy rok wydania lub listę opowiadań z danej książki.
Przygotowania W katalogu rozdzial2 utwórz nowy katalog o nazwie receptura2.
Jak to zrobić? 1. W katalogu rozdzial2 utwórz nowy plik o nazwie index.php i wpisz do niego listę rozwijaną razem z opcjami, którymi będą nazwy książek z pliku common.xml. Następnie utwórz dwa przyciski, które będą pobierały rok publikacji i listę opowiadań wybranej wcześniej książki. Każdy z tych przypadków powinien mieć atrybut ID — za jego pomocą będziemy określać, który z nich został kliknięty. Na koniec utwórz jeszcze akapit, w którym wyświetlane będą wyniki. Dostęp do wartości węzłów i atrybutów
89
PHP i jQuery. Receptury
2. Wykorzystamy bibliotekę jQuery do wybrania wartości z formularza i wysłania żądania AJAX do pliku, który obsłuży żądanie i wyśle na stronę odpowiednio przygotowane dane odpowiedzi. W tym celu musimy napisać kilka wierszy kodu i umieścić je tuż przed zamykającym znacznikiem body. Dołącz też plik biblioteki jQuery, nie zapominając o zastosowaniu właściwej ścieżki, a następnie podłącz funkcję obsługi zdarzenia click do obu przycisków. Po kliknięciu przycisku funkcja ta wyśle żądanie AJAX do pliku PHP, podając mu dane wybranej książki i klikniętego przycisku. Otrzymana odpowiedź zostanie wstawiona do akapitu o identyfikatorze result.
3. Teraz w tym samym katalogu utwórz plik process.php. W tym pliku wartości wybranych książek i klikniętych przycisków będą odczytywane z superglobalnej tablicy $_GET. Ładowany jest plik common.xml i w zależności od wartości zmiennych action i ID pobranych z tablicy $_GET iterujemy po książkach. Jednocześnie tworzona jest zawartość zmiennej odpowiedzi, która na zakończenie przesyłana jest do przeglądarki. book as $book) { if($book['index'] == $bookId) { if($action == 'year') { $strResponse = 'Ta książka została opublikowana w roku:'. $book->name['year']; } else if($action == 'stories') { $stories = $book->story; $strResponse = '
4. Uruchom w przeglądarce plik index.php. Zobaczysz na stronie listę rozwijaną i dwa przyciski. Wybierz z listy jedną z książek, a następnie kliknij dowolny z przycisków. Poniższy obrazek przedstawia listę opowiadań wyświetlanych po wybraniu książki i kliknięciu przycisku Pobierz listę opowiadań.
91
PHP i jQuery. Receptury
Jak to działa? Aby pobrać wartość węzła, możemy odwołać się do niego przez nazwę, traktując ją jak właściwość obiektu SimpleXMLElement. W pliku index.php utworzyliśmy obiekt SimpleXMLElement na podstawie pliku common.xml, ładując jego zawartość za pomocą funkcji simplexml_load_file(). Ze względu na to, że w pliku tym zostało zapisanych kilka węzłów książek, otrzymamy tablicę obiektów, po których możemy iterować, tak jak po każdej innej tablicy. Podobnie atrybuty węzła możemy pobierać jak wartości z tablicy, stosując nazwę atrybutu jako indeks tablicy asocjatywnej. Dla każdej książki tworzymy jeden element option, którego atrybutowi value przypisywana jest wartość atrybutu index książki, a tekst opcji wypełniany jest wartością atrybutu name książki. Sposób pobrania tych wartości pokazuje nam, jak prosto można odczytywać dane za pomocą metod biblioteki SimpleXML. Kod biblioteki jQuery rejestruje funkcje obsługi zdarzeń dla obu przycisków znajdujących się na stronie. Kliknięcie przycisku powoduje pobranie wartości wybranej książki oraz identyfikatora klikniętego przycisku i wysłanie ich do pliku process.php. Do wysłania żądania używamy tutaj metody get(). Wartości przesłane przez bibliotekę jQuery są dostępne w superglobalnej tablicy $_GET. Wartości te zapisywane są następnie do zmiennych PHP o nazwach $bookId i $action. W kolejnym kroku ładujemy plik XML i w ten sposób otrzymujemy obiekt typu SimpleXMLElement zapisany w zmiennej $objXML. Aby znaleźć książkę wybraną na stronie przez użytkownika, możemy iterować po wszystkich książkach i sprawdzać, czy atrybut index pokrywa się z tym zapisanym w zmiennej $bookId. Po 92
Rozdział 3. • Praca z dokumentami XML
znalezieniu pasującej książki sprawdzamy wartość zmiennej $action. Jeżeli znajduje się w niej wartość year, to pobieramy z węzła książki atrybut o nazwie year i wpisujemy go do ciągu znaków odpowiedzi zapisanej w zmiennej $strResponse. Jeżeli zmienna $action zawiera wartość stories, to z aktualnego obiektu $book pobieramy tablicę obiektów story. Następnie iterujemy po tej tablicy i tworzymy wypunktowaną listę nazw opowiadań. Na koniec zapisujemy ją do zmiennej $strResponse. W ostatnim kroku wypisujemy zawartość zmiennej $strResponse za pomocą instrukcji echo, wysyłając ją do przeglądarki, która wyświetla tekst w akapicie.
I coś jeszcze Modyfikowanie dokumentu XML za pomocą biblioteki SimpleXML Wartości węzłów w istniejącym dokumencie XML możemy też modyfikować za pomocą funkcji biblioteki SimpleXML. Na przykład, jeżeli chcielibyśmy zmienić nazwę pierwszej książki w naszym pliku common.xml, to możemy zrobić to za pomocą poniższego kodu: $objXML->book[0]->name = 'Nowa nazwa książki'; $result = $objXML->asXML();
Jeżeli metodzie asXML() nie przekażemy żadnych parametrów, to zwróci ona zmodyfikowany dokument XML w postaci ciągu znaków albo wartość false w przypadku problemów przy dokonywaniu zmiany. Metodzie asXML() można też przekazać nazwę pliku, a wtedy zapisze ona do tego pliku wynikowy dokument XML.
Dodawanie elementów do dokumentu XML Do dokumentu XML można też dodawać nowe elementy, tak jak pokazano to w poniższym kodzie: $objXML->book[0]->addChild('remark','Narrację opowiadań z tej książki prowadzi ´sam Sherlock Holmes'); $objXML->book[0]->remark->addAttribute('totalStories','13'); $result = $objXML->asXML();
Przedstawiony kod dodaje węzeł remark do pierwszego elementu book i uzupełnia ten węzeł o atrybut totalStories. Nie można zapomnieć, że wynikowy dokument XML zostanie zapisany w zmiennej $result, a nie w oryginalnym pliku XML. Można jednak zapisać dokument w tym pliku, podając odpowiednią nazwę jako parametr metody asXML(), o czym mówiłem już w poprzednim podpunkcie.
93
PHP i jQuery. Receptury
Zobacz też Q Recepturę „Ładowanie danych XML z plików oraz ciągów znaków za pomocą
SimpleXML”. Q Recepturę „Wyszukiwanie elementów za pomocą XPath”. Q Recepturę „Pobieranie danych z PHP za pomocą jQuery” z rozdziału 2.
Wyszukiwanie elementów za pomocą XPath Technologia XPath lub XML Path (ścieżka XML) jest używana do nawigowania w dokumencie XML. Jest to tak naprawdę język zapytań, który udostępnia standardowy zestaw wyrażeń oraz funkcji pozwalających na przeglądanie drzewa dokumentu. Język XPath działa na drzewie dokumentu i dzięki temu można go wykorzystywać w wielu funkcjach, takich jak przeszukiwanie, porównywanie i inne. PHP ma już wbudowaną obsługę języka XPath. W tej recepturze wyjaśnionych zostanie kilka koncepcji wykorzystanych w tym języku, a także pokazane zostaną sposoby pobierania informacji z dokumentów XML. Wykorzystamy tu plik common.xml i napiszemy prosty przykład demonstrujący możliwości języka XPath.
Przygotowania Podobnie jak w poprzednich recepturach, w katalogu rozdzial3 utwórz nowy katalog o nazwie receptura3.
Jak to zrobić? 1. Utwórz nowy plik HTML i nadaj mu nazwę index.html. Utwórz cztery przyciski, których użyjemy do zaprezentowania różnych zastosowań języka XPath. Oprócz tego utwórz też pusty element div, w którym będziemy wyświetlać wyniki naszych działań. Na koniec zdefiniuj jeszcze kilka stylów CSS w sekcji head, które poprawią czytelność naszej strony. Używanie XPath
94
Rozdział 3. • Praca z dokumentami XML
2. Dołącz bibliotekę jQuery i dopisz kod, który wyśle żądanie AJAX do pliku process.php. Żądanie to będzie zawierało identyfikator klikniętego przycisku, wywoła odpowiednią reakcję po stronie serwera. Odpowiedź skryptu PHP zostanie wstawiona do elementu div.
3. Przejdźmy teraz na stronę serwera. W tym samym katalogu utwórz plik PHP o nazwie process.php. W ramach tego skryptu będziemy ładować plik XML i wykonywać na nim określone operacje, zależnie od tego, który przycisk został kliknięty na stronie. Wykorzystamy tu metodę xpath(), aby przeszukać dokument i wypisać wyniki w oknie przeglądarki. Przesłana odpowiedź zostanie wstawiona w odpowiednie miejsce na stronie za pomocą biblioteki jQuery.
95
4. Uruchom w przeglądarce plik index.php i kliknij dowolny przycisk. Uruchomione zostanie wtedy żądanie AJAX, które uruchomi plik process.php, a wyniki jego pracy zostaną wyświetlone na stronie. Na przykład kliknięcie ostatniego przycisku spowoduje wyświetlenie książek, dla których atrybut value ma wartość mniejszą niż 1900.
Jak to działa? Na stronie zdefiniowaliśmy cztery przyciski. Pierwszy przycisk pobiera nazwy i lata wydania wszystkich książek, drugi wyświetla listę książek z listą opowiadań i cytatów, trzeci pobiera nazwę i rok wydania ostatniej książki, a czwarty wyświetla wszystkie książki, których wartość atrybutu year jest mniejsza niż 1900. Każdemu z tych przycisków przypisany został identyfikator, wśród których wymienić można: all, total, last i year. Kliknięcie przycisku powoduje wysłanie identyfikatora tego przycisku w ramach żądania AJAX do pliku process.php, gdzie jest on odbierany i zapisywany do zmiennej $action. Plik common.xml został już załadowany do zmiennej $objXML. Następnie za pomocą instrukcji switch wybierany jest rodzaj obsługi żądania pasujący do otrzymanego identyfikatora. Biblioteka SimpleXML udostępnia metodę xpath(), za pomocą której możemy wykonywać zapytania XPath na załadowanym dokumencie. Metoda ta pobiera w parametrze zapytanie XPath i zwraca tablice elementów typu SimpleXMLElement lub wartość false w przypadku wystąpienia błędu.
97
PHP i jQuery. Receptury
Wyrażenie //book wybierze nam z dokumentu wszystkie elementy book, niezależnie od ich pozycji. Wyrażenie //book/name wybierze z dokumentu wszystkie elementy name będące podelementami elementów book. Wyrażenie //book[last()] wybierze ostatni element book znajdujący się w dokumencie. Wyrażenie //book/name[@year<1900] wygląda troszkę przerażająco, ale tak naprawdę jest bardzo proste, wystarczy podzielić je na części. Znak @ odnosi się do atrybutu. Oznacza to, że wyrażenie wybierze wszystkie elementy name będące podelementami elementów book, których atrybut year ma wartość mniejszą niż 1900. W tym przypadku znajdziemy tylko dwie takie książki: pierwszą i ostatnią. W przypadku drugiej książki atrybut year ma wartość 1927, a zatem nie pasuje do podanych warunków. Na koniec formatujemy jeszcze wyniki, umieszczając je wśród znaczników HTML, i zwracamy tak przygotowany tekst do przeglądarki.
I coś jeszcze Więcej informacji na temat XPath Poniżej podaję adresy sieciowe, pod którymi można znaleźć dodatkowe informacje na temat składni zapytań XPath i ich zastosowań: Q http://www.w3schools.com/xpath/ Q http://oreilly.com/catalog/xmlnut/chapter/ch09.html
Zobacz też Q Recepturę „Korzystanie z elementów i atrybutów za pomocą SimpleXML”. Q Recepturę „Odczytywanie dokumentów XML za pomocą rozszerzenia DOM”.
Odczytywanie dokumentów XML za pomocą rozszerzenia DOM W tej recepturze nauczymy się używać rozszerzenia DOM do odczytywania dokumentów XML i wydobywania z nich informacji. Przygotujemy tutaj przykład, w którym będziemy wyświetlać listę książek. Kliknięcie nazwy książki będzie powodowało wyświetlenie listy opowiadań zawartych w tej książce.
98
Rozdział 3. • Praca z dokumentami XML
Przygotowania W katalogu rozdzial3 utwórz nowy katalog o nazwie receptura4 i upewnij się, że w katalogu rozdzial3 dostępny jest plik common.xml.
Jak to zrobić? 1. W katalogu receptura4 utwórz plik index.php. Zapisz do pliku kod HTML strony oraz kod PHP, który będzie ładował dokument XML za pomocą metod rozszerzenia DOM. Na podstawie załadowanego dokumentu utwórz elementy h1, w których znajdą się nazwy książek oraz rok ich wydania. 2. Poniżej każdego z elementów h1 utwórz wypunktowaną listę opowiadań z danej książki. Zauważ, że w sekcji head strony ukryliśmy elementy ul za pomocą właściwości display. Oznacza to, że na stronie widoczne będą tylko nazwy książek. Używanie modelu DOM load('../common.xml', LIBXML_NOBLANKS); $books = $objXML->getElementsByTagName('book'); foreach($books as $book) { echo '
3. Dla urozmaicenia wykorzystamy jeszcze bibliotekę jQuery, aby wyświetlać listę opowiadań z poszczególnych książek. Funkcja obsługująca zdarzenie click zostanie dołączona do wszystkich nazw książek i będzie ona wyświetlać i ukrywać listę opowiadań.
4. Uruchom plik index.php w przeglądarce, a zobaczysz na ekranie listę książek. Kliknięcie dowolnej książki spowoduje wyświetlenie listy znajdujących się w niej opowiadań z wykorzystaniem odpowiedniej animacji.
100
Rozdział 3. • Praca z dokumentami XML
Jak to działa? Na początku w zmiennej $objXML tworzymy obiekt klasy DOMDocument. Klasa ta udostępnia zestaw właściwości i metod, z których możemy skorzystać do manipulowania dokumentami XML. Z plików XML możemy za ich pomocą pobierać nazwy węzłów, ich wartości, atrybuty i inne elementy. Następnie wywołujemy metodę $objXMl.load(), która pobiera dwa parametry. Pierwszy z nich to nazwa pliku, a drugi to opcje dla biblioteki libxml, przy czym drugi parametr jest opcjonalny. Metodzie tej przekazujemy w pierwszym parametrze plik common.xml, a w drugim opcję LIBXML_NOBLANKS. Dzięki zastosowaniu tej opcji w dokumencie nie będą pojawiały się puste węzły. Ze względu na to, że chcemy skorzystać ze wszystkich węzłów book, wywołujemy metodę Get ´ElementsByTagName() i przekazujemy jej wartość book, a w odpowiedzi otrzymujemy obiekt typu DOMNodeList. Pętla foreach pozwala nam na iterowanie po takiej kolekcji. Obiekty klasy DOMNode również udostępniają kilka użytecznych metod, z których skorzystaliśmy w naszym przykładzie. Właściwość firstChild zwraca pierwszy element podrzędny względem aktualnego elementu, czyli w naszym przypadku będzie to element book. Właściwość nodeValue zwraca wartość zapisaną wewnątrz elementu book, czyli w tym przypadku nazwę książki. Otrzymaną wartość opakowujemy jeszcze w element h1. Aby odczytać wartość atrybutu, należy skorzystać z właściwości attributes. Uzyskamy w ten sposób dostęp do słownika atrybutów. Po takiej kolekcji atrybutów możemy iterować za pomocą właściwości item. Pobraliśmy wartość atrybutu na pozycji zerowej i w ten sposób uzyskaliśmy wartość atrybutu year. Podobnie listę opowiadań danej książki otrzymaliśmy za pomocą ponownego wywołania metody getElementsByTagName() i iterowania po zwróconych przez nią wartościach. Na zakończenie całość została zapakowana w listę wypunktowaną. Po przygotowaniu struktury DOM dokumentu w przeglądarce biblioteka jQuery dołącza funkcję obsługi zdarzenia click do wszystkich elementów h1 znajdujących się na stronie. Od tego momentu kliknięcie elementu h1 będzie powodować wyświetlenie lub ukrycie następującego po nim elementu ul.
I coś jeszcze Pobieranie węzłów podrzędnych Możemy też sprawdzić, czy dany węzeł ma węzły podrzędne, i ewentualnie je pobrać. W powyższym przykładzie można pobrać węzły podrzędne węzła book za pomocą poniższego kodu:
Właściwości nodeType, nodeName i nodeValue Jeżeli nie znamy dokładnie struktury dokumentu XML albo jego struktura jest niejednoznaczna, to możemy dodatkowo w swoim skrypcie skontrolować nazwę oraz wartość węzłów i atrybutów. $node->nodeType $node->nodeName $node->nodeValue
Właściwość nodeType będzie zwracać różne wartości w zależności od rodzaju węzła. Wartości te zdefiniowane są jako stałe biblioteki libxml. Najczęściej spotykanymi wartościami właściwości nodeType są: Q XML_ELEMENT_NODE Q XML_ATTRIBUTE_NODE Q XML_TEXT_NODE Q XML_CDATA_SECTION_NODE
Zobacz też Q Recepturę „Tworzenie dokumentów XML za pomocą rozszerzenia DOM”. Q Recepturę „Wyszukiwanie elementów za pomocą XPath”.
Tworzenie dokumentów XML za pomocą rozszerzenia DOM Rozszerzenie DOM daje nam możliwość tworzenia nowych dokumentów XML za pomocą całego zestawu udostępnianych metod. W tej recepturze dowiemy się, jak należy tworzyć nowe dokumenty XML za pomocą funkcji rozszerzenia DOM. Jak wiemy, w naszym przykładowym pliku common.xml mamy kilka elementów book, a zatem utworzymy podobne elementy składające się z nazwy oraz podelementów story, wykorzystując przy tym metody rozszerzenia DOM.
102
Rozdział 3. • Praca z dokumentami XML
Przygotowania W katalogu rozdzial3 utwórz nowy katalog o nazwie receptura5.
Jak to zrobić? 1. W katalogu recepture5 utwórz nowy plik o nazwie index.php. 2. Napisz kod PHP tworzący nowy dokument XML, a następnie przygotuj kilka elementów i dodaj je do nowego dokumentu. Niektóre z tych elementów powinny zawierać w sobie tekst, a także atrybuty z wartościami. Na zakończenie przygotowany dokument XML zostanie zapisany na dysku. */ $books = $objXML->createElement('books');//książki $book = $objXML->createElement('book'); $attrIndex = new DOMAttr("index", "4"); $book->appendChild($attrIndex); $bookName = $objXML->createElement('name','Księga przypadków Sherlocka ´Holmesa'); $attrYear = new DOMAttr("year", "1894"); $bookName->appendChild($attrYear); $book->appendChild($bookName); $story = $objXML->createElement('story'); $title = $objXML->createElement('title', 'Przypadek ....'); $quote = $objXML->createElement('quote', 'Jeszcze jeden cytat'); $story->appendChild($title); $story->appendChild($quote); $book->appendChild($story); $books->appendChild($book); $objXML->appendChild($books); if($objXML->save('new.xml') != FALSE) { echo 'Plik XML został wygenerowany.'; } else {
103
PHP i jQuery. Receptury
echo 'Wystąpił błąd.'; } ?>
3. Teraz uruchom plik index.php w przeglądarce. Jeżeli kod zostanie wykonany bez błędów, to powinien pojawić się komunikat z informacją, że plik XML został wygenerowany. Zajrzyj teraz do katalogu receptura5, a znajdziesz w nim nowy plik XML o strukturze identycznej ze strukturą pliku common.xml. Księga przypadków Sherlocka HolmesaPrzypadek ....Jeszcze jeden cytat
Jak to działa? Konstruktor klasy DOMDocument tworzy nowy obiekt typu DOMDocument. Konstruktorowi możemy przekazać dwa opcjonalne parametry. Pierwszy z nich określa wersję specyfikacji XML. Domyślną wartością jest tutaj 1.0. Drugi parametr definiuje natomiast sposób kodowania dokumentu. W celu utworzenia nowego węzła wywołujemy metodę createElement(), która tworzy nowy obiekt klasy DOMElement. Metoda da przyjmuje dwa parametry, przy czym drugi z nich jest opcjonalny. Pierwszy parametr określa nazwę węzła, a drugi definiuje tekst znajdujący się w tym węźle. Tworząc nowy atrybut, musimy utworzyć obiekt klasy DOMAttr. Podobnie jak to było w przypadku metody createElement(), konstruktor tej klasy przyjmuje dwa parametry: nazwę i wartość atrybutu. Przygotowane w ten sposób elementy i atrybuty są od siebie całkowicie niezależne i nie są częścią dokumentu. Aby wstawić je do struktury dokumentu, należy wywołać metodę appandChild(). Metoda ta pobiera element jako swój parametr i dołącza go do listy elementów podrzędnych obiektu wywołującego. W naszym przykładzie tworzyliśmy elementy za pomocą metody createElement() i dodawaliśmy je do dokumentu zgodnie z wcześniej założonym formatem. Po zakończeniu tworzenia elementów dokumentu zapisujemy wygenerowany dokument XML do pliku za pomocą metody save().
104
Rozdział 3. • Praca z dokumentami XML
Zobacz też Q Receptura „Odczytywanie dokumentów XML za pomocą rozszerzenia DOM”. Q Receptura „Modyfikowanie dokumentów XML za pomocą rozszerzenia DOM”.
Modyfikowanie dokumentów XML za pomocą rozszerzenia DOM Oprócz tworzenia nowego dokumentu XML od zera, tak jak robiliśmy to w poprzedniej recepturze, możemy też modyfikować istniejące już pliki XML. Do takiego pliku możemy dodawać nowe elementy, a także usuwać już istniejące. W tej recepturze przygotujemy stronę, która pozwoli nam dodawać nowe opowiadania do poszczególnych książek. Oprócz tego będziemy mogli też uzupełnić wybraną książkę o nowy tytuł oraz cytaty.
Przygotowania W katalogu rozdzial3 utwórz nowy katalog o nazwie receptura6.
Jak to zrobić? 1. Utwórz nowy plik o nazwie index.php. Następnie utwórz w tym pliku formularz składający się z listy książek oraz dwóch pól tekstowych umożliwiających wprowadzenie tytułu opowiadania oraz cytatu. Poza tym utwórz też przycisk, którego użyjemy do dodawania tytułu opowiadania oraz wprowadzonego cytatu do dokumentu XML. Modyfikowanie dokumentu XML
105
PHP i jQuery. Receptury
2. Teraz zapisz kod korzystający z biblioteki jQuery, który zostanie wywołany w przypadku kliknięcia przycisku. Zostaną wtedy zebrane wartości zapisane w polach tekstowych i wysłane do skryptu PHP o nazwie process.php, w ramach żądania AJAX. Odpowiedź otrzymana od skryptu zostanie wyświetlona zaraz obok przycisku.
3. Teraz zajmiemy się skryptem PHP, w którym wykonywane są interesujące nas działania. W tym samym katalogu utwórz nowy plik o nazwie process.php. Zawarty w nim skrypt będzie pobierał wartości z tablicy $_POST, a następnie załaduje zawartość pliku common.xml i wyszuka w nim wybraną przez użytkownika książkę. W kolejnym kroku utworzone zostaną nowe elementy, wypełnione otrzymanymi od przeglądarki danymi i zapisane w strukturze dokumentu XML. load('../common.xml', LIBXML_NOBLANKS); $books = $objXML->getElementsByTagName('book'); foreach($books as $book) { if($book->attributes->item(0)->value == $bookId) { $story = $objXML->createElement('story'); $title = $objXML->createElement('title', $title); $quote = $objXML->createElement('quote', $quote); $story->appendChild($title); $story->appendChild($quote); $book->appendChild($story); break; } } if($objXML->save('../common.xml') != FALSE) { echo 'Dodano nowe opowiadanie.'; } else { echo 'Wystąpił błąd.'; } ?>
4. Uruchom w przeglądarce plik index.php, a zobaczysz formularz, w którym z listy rozwijanej będzie można wybrać tytuł jednej z książek. Po wybraniu książki wpisz w pola tekstowe tytuł opowiadania oraz cytat i kliknij przycisk Dodaj nowe opowiadanie. Jeżeli uda się wprowadzić opowiadanie do dokumentu, to obok przycisku pojawi się stosowny komunikat. Otwórz teraz plik XML w edytorze i sprawdź, czy dane opowiadania zostały wprowadzone przy właściwej książce.
107
PHP i jQuery. Receptury
Jak to działa? Po wprowadzeniu wartości do formularza i kliknięciu przycisku biblioteka jQuery wysyła dane z formularza do pliku process.php. Na początku skrypt ten odczytuje otrzymane wartości z tablicy $_POST. W kolejnym kroku za pomocą klasy DOMDocument ładowany jest plik XML. Następnie korzystamy z metody getElementsByTagName(), aby pobrać wszystkie książki i przejrzeć je za pomocą pętli foreach. Naszym głównym zadaniem na tym etapie jest sprawdzenie, która książka została wybrana, i odpowiednie zmodyfikowanie jej węzła w strukturze XML. Za pomocą właściwości attributes możemy porównać wartość atrybutu index z wartością zmiennej $bookId i w ten sposób wyszukać odpowiednią książkę. Pętla zostanie przerwana, gdy tylko znajdziemy pasujący węzeł. Teraz mamy już książkę wybraną przez użytkownika, a zatem możemy skorzystać z funkcji rozszerzenia DOM, aby dodać do niej nowe elementy. W naszym przykładzie utworzyliśmy trzy takie elementy: story, title i quote, a następnie przypisaliśmy im otrzymane od przeglądarki teksty tytułu i cytatu. Aby dodać te nowo utworzone elementy do drzewa dokumentu, stosujemy metodę appendChild(), z której korzystaliśmy już w poprzedniej recepturze. Dołączyliśmy w ten sposób obiekty $title i $quote do obiektu $story, a następnie dołączyliśmy obiekt $story do obiektu $book. Na koniec musimy jeszcze zmienić zmodyfikowany obiekt XML w ciąg znaków. W tym celu możemy użyć jednej z dwóch metod: save() i saveXML(). Pierwsza z nich zapisuje dokument do pliku, natomiast metoda saveXML() zwraca tylko ciąg znaków reprezentujący cały dokument. Nie można jeszcze zapomnieć o odesłaniu do przeglądarki odpowiedniego komunikatu, który zostanie wyświetlony na stronie. Teraz możemy już sprawdzić, czy nowe wartości zostały faktycznie zapisane do pliku XML.
108
Rozdział 3. • Praca z dokumentami XML
I coś jeszcze Usuwanie węzłów Metoda removeChild() ma działanie odwrotne do działania metody createElement(), ponieważ służy do usuwania elementów z dokumentu. $objXML = new DOMDocument(); $objXML->load('new.xml'); $book = $objXML->getElementsByTagName('book')->item(0); $book->parentNode->removeChild($book); $objXML->save('new.xml');
Powyższy kod usunie z dokumentu pierwszy element book (razem z wszystkimi elementami podrzędnymi). Jeżeli chcielibyśmy wywołać metodę removeChild() na rzecz węzła głównego, to wystarczy tylko zamienić w powyższym kodzie wiersz: $book->parentNode->removeChild($book);
za pomocą poniższej instrukcji: $objXML->documentElement->removeChild($book);
Zobacz też Q Recepturę „Odczytywanie dokumentów XML za pomocą rozszerzenia DOM”. Q Recepturę „Tworzenie dokumentów XML za pomocą rozszerzenia DOM”. Q Recepturę „Korzystanie z elementów i atrybutów za pomocą SimpleXML”.
Parsowanie dokumentów XML za pomocą biblioteki jQuery Do analizy dokumentu XML można wykorzystać też bibliotekę jQuery. Plik z dokumentem XML możemy pobrać za pomocą żądań AJAX, a następnie obsłużyć go w przeglądarce, analizując zawarte w nim dane. Ponownie wykorzystamy tu przykład z receptury „Odczytywanie dokumentów XML za pomocą rozszerzenia DOM”. Różnica polegać będzie na tym, że poprzednio używaliśmy metod modelu DOM po stronie serwera, a teraz wykorzystamy funkcje selektorów biblioteki jQuery do przeglądania dokumentu XML.
109
PHP i jQuery. Receptury
Przygotowania W katalogu rozdzial3 utwórz nowy katalog o nazwie receptura 7. Oprócz tego skopiuj do tego katalogu plik common.xml.
Jak to zrobić? 1. W katalogu receptura7 utwórz nowy plik o nazwie index.html. W pliku tym zdefiniuj style dla elementów h1 i ul, które zostaną utworzone później za pomocą biblioteki jQuery. Utwórz też element div, do którego wstawiać będziemy kod HTML. Czytanie dokumentów XML za pomocą jQuery
2. Dołącz jeszcze plik biblioteki jQuery. W kolejnym kroku za pomocą metody live() połącz funkcję obsługującą zdarzenie click z wszystkimi elementami h1. Następnie wyślij żądanie AJAX, aby pobrać plik common.xml. Po jego otrzymaniu przejrzyj strukturę dokumentu i utwórz kod HTML w odpowiadającym nam formacie. Na zakończenie wstaw przygotowany kod HTML do elementu div.
3. Uruchom w przeglądarce plik index.html, a zobaczysz listę wszystkich książek w pliku XML. Kliknij dowolny z tytułów książek, aby wyświetlić lub ukryć listę opowiadań w tej książce.
Jak to działa? Po załadowaniu strony wysyłane jest żądanie AJAX w celu pobrania pliku common.xml. Proszę zauważyć, że właściwości dataType została przypisana wartość xml. Teraz biblioteka jQuery wie już, że w odpowiedzi może oczekiwać pliku XML. Oznacza to, że po otrzymaniu ciągu znaków XML biblioteka będzie próbowała zmienić go w obiekt dokumentu. 111
PHP i jQuery. Receptury
Teraz możemy zastosować na tym obiekcie dowolne funkcje selektorów biblioteki jQuery, aby pobrać z niego dane. W naszym przykładzie skorzystaliśmy z metody find(), aby pobrać wszystkie elementy book. Za pomocą funkcji each() iterowaliśmy po tych elementach, a także po zawartych w nich elementach story. W ramach tego procesu umieszczaliśmy nazwy książek w elementach h1, a tytuły opowiadań w elementach listy. Po zakończeniu pracy pętli będziemy mieli ciąg znaków z kodem HTML, który możemy wstawić na stronę. Dzięki temu, że wcześniej użyliśmy metody live() dla elementów h1, kliknięcie nazwy książki spowoduje wyświetlenie lub ukrycie listy opowiadań. Pamiętamy, że metoda live() pozwala na podłączanie metod obsługi zdarzeń do elementów, które zostaną utworzone w przyszłości.
I coś jeszcze Metoda delegate() Metoda delegate() jest bardzo podobna do metody live(). Różnica polega na tym, że pobiera ona w dodatkowym parametrze selektor elementu i z jego pomocą przeszukuje zbiór elementów wywołujących zdarzenie. $('div').delegate("span", "click", function(){ $(this).toggleClass("hover"); });
Jeżeli kliknięty zostanie element div, to kod sprawdzi, czy zdarzenie to zostało wywołane kliknięciem elementu span znajdującego się w elemencie div. Metoda toggleClass() zostanie wywołana tylko wtedy, gdy rzeczywiście kliknięty będzie element span w elemencie div. W tym przypadku odpowiednim filtrowaniem zajęła się metoda delegate().
Zobacz też Q Recepturę „Odczytywanie dokumentów XML za pomocą rozszerzenia DOM”. Q Recepturę „Korzystanie z elementów i atrybutów za pomocą SimpleXML”. Q Recepturę „Dodawanie zdarzeń do elementów, które zostaną utworzone później”
z rozdziału 1.
112
4 Praca z formatem JSON W tym rozdziale zajmiemy się: Q tworzeniem danych w formacie JSON za pomocą PHP, Q odczytywaniem danych w formacie JSON za pomocą PHP, Q przechwytywaniem błędów analizy danych w formacie JSON, Q korzystaniem z danych w formacie JSON za pomocą jQuery.
Wprowadzenie W ostatnim czasie format JSON (ang. JavaScript Object Notation) stał się bardzo popularnym formatem wymiany danych i coraz więcej programistów zaczyna przedkładać go nad format XML. Coraz więcej witryn WWW korzysta z tego formatu jako domyślnej formy udostępniania danych. JSON jest formatem tekstowym, który jest niezależny od języka programowania, ale stanowi wewnętrzną formę prezentacji danych w języku JavaScript. Jest to format znacznie szybszy i lżejszy niż XML, ponieważ w porównaniu do niego wymaga zastosowania mniejszej liczby znaczników. Ze względu na to, że format JSON jest wewnętrznym formatem danych języka JavaScript, możemy znacznie łatwiej korzystać z niego po stronie klienta w aplikacjach korzystających z technologii AJAX. Obiekty zapisane w formacie JSON zaczynają się od otwierającego nawiasu klamrowego ({), a kończą się zamykającym nawiasem klamrowym (}). Zgodnie ze specyfikacją formatu dozwolone jest w nim stosowanie następujących typów danych:
PHP i jQuery. Receptury
Q obiektów — Obiekt jest kolekcją par klucz-wartość zamkniętych pomiędzy nawiasami klamrowymi ({ i }), a rozdzielanych przecinkiem. Klucze i wartości są od siebie oddzielane za pomocą dwukropka (:). O takich obiektach można myśleć jak o tablicach
asocjatywnych lub tabelach skrótów. Klucze są tutaj prostymi ciągami znaków, a wartościami mogą być tablice, ciągi znaków, liczby, wartości logiczne lub wartość null. Q tablic — Podobnie jak w innych językach tablica jest uporządkowanym zbiorem
danych. Dane w tablicy rozdzielane są za pomocą przecinka, a wszystkie muszą znaleźć się między nawiasami kwadratowymi ([ i ]). Q ciągów znaków — Każdy ciąg znaków musi być zamknięty za pomocą znaków
cudzysłowu. Q liczb — To ostatni typ danych.
Dane w formacie JSON mogą być tak proste jak poniższe: { "name":"Superman", "address": "gdzieś" }
Poniżej przedstawiam też przykład korzystających z tablic: { "name": "Superman", "phoneNumbers": ["8010367150", "9898989898", "1234567890" ] }
I jeszcze jeden, troszkę bardziej skomplikowany przykład, w którym użyłem obiektów, tablic oraz wartości: { "people": [ { "name": "Vijay Joshi", "age": 28, "isAdult": true }, { "name": "Charles Simms", "age": 13, "isAdult": false } ] }
114
Rozdział 4. • Praca z formatem JSON
Należy tutaj wspomnieć o ważnym szczególe: { 'name':'Superman', 'address': 'gdzieś' }
Powyższy ciąg znaków jest prawidłowym obiektem JavaScript, ale nie jest zgodny z formatem JSON. Format ten wymaga, aby nazwa i wartość były umieszczone pomiędzy znakami cudzysłowu, i nie dopuszcza stosowania znaków apostrofu.
Inną rzeczą, o której trzeba pamiętać, jest konieczność stosowania właściwego zestawu znaków. Proszę pamiętać, że format JSON wymaga zapisywania danych w kodowaniu UTF-8, natomiast język PHP domyślnie zakłada stosowanie kodowania ISO-8859-1.
Trzeba też pamiętać o tym, że format JSON nie jest językiem JavaScript, a jedynie specyfikacją formatu danych lub jednym z wielu elementów języka JavaScript. Skoro wiemy już, czym jest format JSON, możemy przystąpić do tworzenia receptur, w których nauczymy się korzystać z tego formatu za pomocą języka PHP i biblioteki jQuery. Utwórz zatem nowy katalog i nadaj mu nazwę rozdzial4. Wszystkie receptury z tego rozdziału będziemy umieszczać w tym katalogu, dlatego skopiuj do niego jeszcze plik jquery.js. Chcąc skorzystać z funkcji obsługi formatu JSON w języku PHP, należy zainstalować interpreter PHP w wersji 5.2 lub wyższej.
Tworzenie danych w formacie JSON za pomocą PHP W tej recepturze można tworzyć struktury danych w formacie JSON za pomocą tablic i obiektów PHP.
Przygotowania W katalogu rozdzial4 utwórz nowy katalog i nazwij go receptura1.
115
PHP i jQuery. Receptury
Jak to zrobić? 1. W katalogu receptura1 utwórz nowy plik i nazwij go index.php. 2. Do pliku wpisz kod PHP tworzący ciąg znaków w formacie JSON na podstawie tablicy. 'Delhi', 'destination' => 'London', 'passengers' => array ( array('name' => 'Mr. Perry Mason', 'type' => 'Adult', 'age'=> 28), array('name' => 'Miss Irene Adler', 'type' => 'Adult', 'age'=> 28) ), 'travelDate' => '17-Dec-2010' ); echo json_encode($travelDetails); ?>
3. Uruchom plik w przeglądarce, a wyświetlony zostanie ciąg znaków w formacie JSON. Po wprowadzeniu odpowiednich wcięć całość będzie wyglądała następująco: { "origin":"Delhi", "destination":"London", "passengers":[ { "name":"Mr. Perry Mason", "type":"Adult", "age":28 }, { "name":"Miss Irene Adler", "type":"Adult", "age":28 } ], "travelDate":"17-Dec-2010" }
Jak to działa? Język PHP udostępnia nam funkcję json_encode(), która tworzy ciąg znaków w formacie JSON na podstawie obiektów i tablic. Funkcja ta przyjmuje dwa parametry: pierwszy z nich jest wartością przeznaczoną do zakodowania, a w drugim można podać opcje sterujące kodowaniem znaków specjalnych. Ten drugi parametr jest opcjonalny. 116
Rozdział 4. • Praca z formatem JSON
W podanym tu kodzie utworzyliśmy dość złożoną tablicę asocjatywną przechowującą dane o podróżach dwojga pasażerów. Przekazanie tej tablicy do funkcji json_encode() pozwoliło nam uzyskać reprezentację tej tablicy w formacie JSON.
I coś jeszcze Wstępnie zdefiniowane stałe Dowolną z podanych niżej stałych można przekazać jako drugi parametr funkcji json_encode(). Q JSON_HEX_TAG — Zamienia znaki < i > na encje \u003C i \u003E. Q JSON_HEX_AMP — Zamienia znak &s na \u0026. Q JSON_HEX_APOS — Zamienia znak ' na \u0027. Q JSON_HEX_QUOT — Zamienia znak " na \u0022. Q JSON_FORCE_OBJECT — Wymusza, żeby wartość zwracana w ciągu znaków była
obiektem, a nie tablicą. Podane tu stałe zdefiniowane są w języku PHP od wersji 5.3 wzwyż.
Zobacz również Q Recepturę „Odczytywanie danych w formacie JSON za pomocą PHP”. Q Recepturę „Przechwytywanie błędów analizy danych w formacie JSON”.
Odczytywanie danych w formacie JSON za pomocą PHP W przeciwieństwie do poprzedniej receptury tym razem zajmiemy się odczytywaniem ciągów znaków w formacie JSON i tworzeniem na ich podstawie obiektów lub tablic, a także dekodowaniem takich ciągów znaków dzięki udostępnianym przez język PHP funkcjom JSON.
117
PHP i jQuery. Receptury
Przygotowania W katalogu rozdzial4 utwórz nowy katalog o nazwie receptura2.
Jak to zrobić? 1. W katalogu receptura2 utwórz plik o nazwie index.php. 2. Spróbuj teraz zmienić ciąg znaków w formacie JSON w obiekt, używając do tego metody json_decode(). Po zakończeniu konwersji wypisz wynikowy obiekt na ekranie. Na potrzeby funkcji json_decode() możesz użyć wyniku działania poprzedniej receptury, ponieważ na pewno będzie to prawidłowy ciąg znaków JSON. '; $objJson = json_decode($json); print_r ($objJson); echo ''; ?>
3. Uruchom plik index.php w przeglądarce, a zobaczysz wynik przekształcenia ciągu znaków JSON do postaci obiektu. Chcąc skorzystać z wartości zapisanych w tym obiekcie, można się do nich odwołać dokładnie tak samo, jak do wartości każdego innego obiektu w języku PHP.
118
Rozdział 4. • Praca z formatem JSON
Jak to działa? Funkcja json_decode() przekształca prawidłowo zbudowane ciągi znaków JSON w obiekty języka PHP. Przyjmuje ona trzy parametry, które opisuję poniżej: Q Ciąg znaków w formacie JSON. Q Opcjonalny parametr assoc, którego domyślną wartością jest false. Jeżeli zmienimy ją na true, to funkcja json_decode() będzie przekształcała obiekty w tablice asocjatywne. Q Opcjonalny parametr depth, który definiuje maksymalną głębokość zagnieżdżania
rekursywnych struktur w ciągu znaków JSON. Przed wersją PHP 5.3 parametr ten miał domyślną wartość 128, ale od wersji 5.3 jego wartość wzrosła do 512. W podanym kodzie do zdefiniowania ciągu znaków JSON wykorzystaliśmy składnię HEREDOC. Następnie przekazaliśmy ten ciąg znaków do funkcji json_decode(), która przekształca go w obiekt. Teraz możemy już korzystać z wartości tego obiektu za pomocą standardowych operatorów języka PHP. Na przykład datę wycieczki możemy pobrać za pomocą następującej instrukcji: $objJson->travelDate
Podobnie instrukcja: $objJson->passengers[1]->name
zwróci nam nazwisko drugiego pasażera, czyli Miss Irene Adler.
119
PHP i jQuery. Receptury
Zobacz również Q Recepturę „Tworzenie danych w formacie JSON za pomocą PHP”. Q Recepturę „Korzystanie z danych w formacie JSON za pomocą jQuery”. Q Recepturę „Przechwytywanie błędów analizy danych w formacie JSON”.
Przechwytywanie błędów analizy danych w formacie JSON Błędy są nieodłączną częścią procesu tworzenia aplikacji. Dlatego właśnie powinniśmy jak najlepiej obsługiwać powstające błędy, tak żeby ułatwić życie użytkownikom naszych produktów. Podczas tworzenia i dekodowania ciągów znaków w formacie JSON mogą powstać różne błędy. Na przykład wartość przekazana do funkcji może mieć nieprawidłową postać i naruszać zasady budowy obiektów JSON. W takich przypadkach musimy wyłapać wszystkie błędy i odpowiednio je obsłużyć. W tej recepturze będziemy się zajmować obsługą błędów w funkcjach obsługujących format JSON. Wykorzystamy przy tym metody wbudowane w interpreter PHP, przeznaczone do wykrywania błędów w strukturach JSON. Proszę pamiętać o tym, że obsługa błędów w strukturach JSON dostępna jest dopiero od wersji PHP 5.3. W związku z tym proszę się upewnić, że mamy zainstalowaną właściwą wersję interpretera.
Przygotowania W katalogu rozdzial4 utwórz nowy katalog o nazwie receptura3. Sprawdź też, czy masz zainstalowany interpreter w wersji 5.3 lub nowszej.
Jak to zrobić? 1. W katalogu receptura3 utwórz nowy plik o nazwie index.php. 2. Korzystając z tego samego ciągu znaków w formacie JSON, którego użyliśmy w poprzedniej recepturze, spróbuj przekształcić go w obiekt. Następnie za pomocą instrukcji switch sprawdź, czy w czasie przekształcania nie wystąpiły żadne błędy, i odpowiednio wypisz wyniki na ekranie.
120
Rozdział 4. • Praca z formatem JSON
travelDate; break; case JSON_ERROR_DEPTH: echo 'Ciąg znaków JSON przekroczył maksymalną głębokość stosu.'; break; case JSON_ERROR_CTRL_CHAR: echo 'Błąd znaków kontrolnych'; break; case JSON_ERROR_SYNTAX: echo 'Nieprawidłowa struktura JSON : Proszę sprawdzić składnię'; break; } ?>
3. Uruchom plik index.php w przeglądarce. Ciąg znaków JSON ma prawidłową strukturę, dlatego na ekranie powinien pojawić się tekst Data wylotu: 17-Dec-2010. Teraz usuń przecinek z wiersza "destination":"London". Po zapisaniu pliku załaduj go ponownie w przeglądarce. Tym razem pojawi się w niej komunikat Nieprawidłowa struktura JSON : Proszę sprawdzić składnię.
121
PHP i jQuery. Receptury
Jak to działa? Od wersji PHP 5.3 dostępna jest funkcja json_last_error(), która nie pobiera żadnych parametrów, ale zwraca dane ostatniego błędu, jaki wystąpił podczas analizy ciągu znaków JSON. Zwraca ona wartość całkowitą, na podstawie której można określić rodzaj błędu. W PHP zdefiniowane zostały też stałe dla poszczególnych rodzajów błędów: Q JSON_ERROR_NONE — oznacza, że ciąg znaków JSON był prawidłowy i przy jego
analizie nie powstały żadne błędy. Q JSON_ERROR_SYNTAX — oznacza, że w ciągu znaków JSON pojawiły się błędy składniowe. Q JSON_ERROR_CTRL_CHAR — napotkano nieprawidłowy znak kontrolny. Q JSON_ERROR_DEPTH — ciąg znaków JSON przekroczył maksymalną dopuszczalną
głębokość stosu.
Zobacz również Q Recepturę „Odczytywanie danych w formacie JSON za pomocą PHP”.
Korzystanie z danych w formacie JSON za pomocą jQuery Wiemy już, jak należy generować obiekty JSON w języku PHP. Możemy zatem wykorzystać tę wiedzę w małym praktycznym projekcie. Napiszemy tutaj przykład, w którym będziemy żądali danych w formacie JSON od skryptu PHP (do tworzenia żądania wykorzystamy oczywiście bibliotekę jQuery), a następnie wyświetlimy je na stronie WWW.
Przygotowania W katalogu rozdzial4 utwór nowy katalog o nazwie receptura4.
Jak to zrobić? 1. W utworzonym przed chwilą katalogu receptura4 utwórz plik o nazwie index.html. 2. Do tego pliku zapisz kod HTML tworzący pustą listę rozwijaną oraz pustą listę wypunktowaną. W sekcji head zdefiniuj też kilka stylów CSS, tak żeby te elementy ładniej wyglądały. 122
Rozdział 4. • Praca z formatem JSON
Korzystanie z danych w formacie JSON
Wybierz datę, aby zobaczyć szczegóły lotu
3. Teraz dopiszemy kod używający biblioteki jQuery. Po pierwsze tuż przed zamykającym znacznikiem body dodaj referencję do pliku biblioteki. Następnie dopisz własny kod, który przygotuje żądanie danych w formacie JSON przesłane do pliku json.php. W momencie otrzymania odpowiedzi lista rozwijana zostanie wypełniona i dołączona zostanie do niej funkcja obsługi zdarzenia change. Po wybraniu wartości z listy wywoływana jest kolejna funkcja, która poszuka w otrzymanej wcześniej odpowiedzi w formacie JSON wybranej daty i wyświetli pasujące do niej informacje.
4. Teraz przyjrzyjmy się plikowi obsługującemu żądanie. Utwórz zatem nowy plik i nadaj mu nazwę json.php. W pliku tym zapisz tablicę z informacjami o lotach oraz dane kilku podróżników, a następnie przekształć ją do formatu JSON i odeślij do przeglądarki. 'London', 'destination' => 'Paris', 'passengers' => array ( array('name' => 'Mr. Sherlock Holmes', 'age'=> 34), array('name' => 'Mr. John H. Watson', 'age'=> 32) ), 'travelDate' => '17-Dec-2010'
5. I to już wszystko! Otwórz w przeglądarce plik index.html. Pojawi się wtedy lista wyboru, w której dostępnych będzie kilka dat. Wybierz jedną z nich, a zobaczysz dodatkowe informacje na temat wybranej opcji.
125
PHP i jQuery. Receptury
Jak to działa? Gdy struktura DOM dokumentu jest już gotowa, wywołujemy metodę getJSON(). Do tej pory poznaliśmy metody get() i post(). Tym razem korzystamy ze specjalizowanej metody używanej w przypadku, gdy chcemy pobrać z serwera dane w formacie JSON. Oto lista parametrów, jakie możemy przekazać funkcji getJSON(): Q URL — Adres URL, na który ma zostać wysłane żądanie. Q Dane — Dane, które mają zostać wysłane do serwera. Q Funkcja wywołania zwrotnego — Ta funkcja zostanie wywołana po odebraniu
odpowiedzi z serwera. W przypadku otrzymania danych JSON biblioteka jQuery najpierw je przeanalizuje i utworzy obiekt JavaScriptu, a następnie przekaże je do wskazanej w parametrze funkcji. W naszym przykładzie żądanie jest wysyłane do pliku json.php, w którym zadeklarowana została tablica z wieloma elementami. Następnie za pomocą metody json_encode() tablica ta przekształcana jest w ciąg znaków JSON i wysyłana do przeglądarki. W momencie otrzymania odpowiedzi biblioteka jQuery przekształca ją w obiekt i przekazuje do funkcji wywołania zwrotnego o nazwie displayData(). Otrzymany obiekt zapisywany jest w globalnej zmiennej jsonResult. Następnie iterujemy po tym obiekcie i wstawiamy do listy rozwijanej kolejne daty wylotów. Ze względu na to, że dane są teraz obiektem JavaScriptu, musimy stosować też składnię tego języka. Po wypełnieniu danymi listy rozwijanej dołączamy do niej funkcję obsługi zdarzenia change. W momencie wybrania wartości z listy wywołana zostanie zatem funkcja displayDetails(). Funkcja ta poszukuje w obiekcie wybranej przez użytkownika daty. Po jej znalezieniu odczytuje ona informacje o miejscu wylotu, przylotu oraz listę pasażerów. Wszystkie te dane są następnie wyświetlane na stronie.
I coś jeszcze Inne metody pozwalające na pobranie danych JSON Jak wspominałem już wcześniej, funkcja getJSON() została zaprojektowana do używania wyłącznie w sytuacji, w której z góry wiemy, że w odpowiedzi serwer przyśle nam dane w formacie JSON. Działanie tej funkcji można też symulować za pomocą innych metod biblioteki jQuery, takich jak get() lub post(), a nawet za pomocą niskopoziomowej funkcji ajax(). $.get( 'json.php',
126
Rozdział 4. • Praca z formatem JSON
displayData, 'json' );
Dzięki podaniu w ostatnim parametrze wartości json biblioteka jQuery będzie zakładała, że otrzymana od serwera odpowiedź jest ciągiem znaków JSON i spróbuje przekształcić go w obiekt. Podobne zachowanie można też zrealizować za pomocą funkcji post() i ajax().
Obsługa błędów podczas odbierania danych JSON Przedstawione powyżej sposoby pobierania danych wykorzystujące metody getJSON() lub get() nie pozwalają na samodzielną obsługę błędów. Na przykład, jeżeli żądaliśmy danych za pomocą metody getJSON(), a serwer prześle nam źle zbudowany ciąg znaków, to całe żądanie zostanie uznane w tle za nieudane. Istnieją zatem dwa sposoby radzenia sobie w takiej sytuacji. Albo skorzystamy z funkcji ajaxError(), która jest uruchamiana, w przypadku gdy w żądaniu AJAX powstaną jakieś błędy, albo użyjemy niskopoziomowej funkcji ajax(), która pozwala na wskazanie funkcji wywoływanej w przypadku wystąpienia błędu. Obie te funkcje zostały omówione dokładniej w recepturze „Obsługa błędów w żądaniach AJAX” w poprzednim rozdziale.
Parsowanie ciągu znaków w formacie JSON Oprócz używania funkcji getJSON() i podawania odpowiedniego typu danych w żądaniach AJAX możemy też samodzielnie parsować ciągi znaków JSON i przekształcać je w obiekty. Biblioteka jQuery udostępnia metodę parseJSON(), która przekształca ciąg znaków w obiekt języka JavaScript. var objJSON = jQuery.parseJSON('{"klucz":"wartość"}');
Od tego momentu w zmiennej objJSON zapisany jest obiekt JavaScriptu. Inną, niezalecaną, metodą jest wykorzystanie funkcji eval() udostępnianej przez język JavaScript. var objJSON = eval('(' + '{"klucz":"wartość"}' + ')')
Zastosowanie funkcji eval() może mieć fatalne skutki dla naszej strony, ponieważ funkcja ta wykona wszelkie przekazane jej dane. Oznacza to, że zalecanym sposobem jest używanie funkcji parseJSON() lub specjalnych metod biblioteki jQuery przeznaczonych do obsługi żądań AJAX.
Zobacz również Q Recepturę „Tworzenie danych w formacie JSON za pomocą PHP”. Q Recepturę „Pobieranie danych z PHP za pomocą jQuery” z rozdziału 2.
127
PHP i jQuery. Receptury
128
5 Praca z formularzami W tym rozdziale zajmiemy się: Q dynamicznym dodawaniem pól do formularza, Q wyszukiwaniem na stronie tekstu wprowadzonego przez użytkownika, Q szukaniem pustych pól za pomocą biblioteki jQuery, Q sprawdzaniem poprawności liczb za pomocą biblioteki jQuery, Q sprawdzaniem poprawności adresów e-mail i adresów WWW za pomocą wyrażeń Q Q Q Q
regularnych, wyświetlaniem błędów w czasie wprowadzania danych, czyli sprawdzaniem danych na żywo, mocniejszą kontrolą formularzy, czyli ponownym kontrolowaniem w PHP, tworzeniem systemu do głosowania, zezwalaniem na kod HTML w polach tekstowych i ograniczaniem zbioru dozwolonych znaczników.
Wprowadzenie Formularze i strony są jedyną częścią naszej aplikacji WWW, z których użytkownik korzysta w sposób bezpośredni. W związku z tym zadaniem twórców aplikacji jest przygotowanie formularzy tak, żeby były one łatwe w obsłudze i nawigacji oraz jak najbardziej interaktywne. Co więcej atakujący mogą próbować zaszkodzić naszej aplikacji przez wprowadzanie złośliwych danych do pól formularza. W tym rozdziale zajmiemy się formularzami oraz metodami kontroli formularzy, takimi jak szukanie danych zarówno po stronie klienta, jak i po stronie serwera. Co prawda formularz można skontrolować w przeglądarce za pomocą biblioteki jQuery, ale ponowna kontrola po stronie
PHP i jQuery. Receptury
serwera jest równie istotna. Jeżeli w przeglądarce wyłączona zostanie obsługa języka JavaScript, to wszystkie mechanizmy kontroli po stronie klienta staną się bezużyteczne. Po prostu kontrola formularzy w przeglądarce sprawia, że aplikacja staje się bardziej przyjazna użytkownikowi i mniej podatna na błędy. Nauczymy się tutaj zatem kontrolować w formularzach różne typy danych, takie jak puste pola, liczby, adresy e-mail lub adresy stron WWW i inne. Kontrola formularza po stronie serwera jest czymś absolutnie niezbędnym i nie można traktować kontroli po stronie klienta jako wygodnego zastępnika, ponieważ ta ostatnia może zostać bardzo łatwo wyłączona.
Dynamiczne dodawanie pól do formularza Przygotujemy tutaj formularz, w którym będziemy mogli dodawać kolejne pola bez konieczności odwoływania się do serwera. W naszym formularzu przedstawimy użytkownikowi jedno pole tekstowe oraz przyciski umożliwiające wstawianie i usuwanie kolejnych pól tekstowych.
Przygotowania W katalogu rozdzial5 utwórz nowy katalog dla tej receptury i nadaj mu nazwę receptura1. Nie zapomnij skopiować pliku jquery.js do utworzonego właśnie katalogu.
Jak to zrobić? 1. W katalogu receptura1 utwórz nowy plik o nazwie index.html i wpisz do niego kod, który będzie tworzyć listę o jednym tylko elemencie. Tym elementem będzie nasze jedyne pole tekstowe. Na koniec dodaj jeszcze przycisk umożliwiający dodawanie kolejnych pól tekstowych do naszego formularza. Dynamiczne dodawanie pól
2. Teraz dołącz plik biblioteki jQuery i dopisz funkcje obsługi zdarzeń. Pierwsza z nich będzie obsługiwać kliknięcia przycisku Dodaj kolejną i będzie dodawała do formularza nowe pole tekstowe razem z przyciskiem pozwalającym na jego usunięcie. W związku z tym druga funkcja będzie musiała zająć się usuwaniem wybranego pola tekstowego.
3. Uruchom teraz plik w przeglądarce. Kliknięcie przycisku Dodaj kolejną dodaje do strony nowe pole tekstowe. Można też usunąć dodatkowe pola tekstowe, klikając znajdujące się przy nich przyciski Usuń.
Jak to działa? Metoda obsługująca zdarzenie click przycisku Dodaj kolejną tworzy nowy element li zawierający pole tekstowe oraz przycisk Usuń, a następnie wywołuje metodę append() (udostępnianą przez bibliotekę jQuery), aby dodać go do istniejącej już listy. Proszę zauważyć, że przyciskowi Usuń zostaje przypisana klasa remove. Wcześniej użyliśmy już metody live(), aby podłączać funkcję obsługi zdarzenia click wszystkich elementów tej klasy. Jak pamiętamy, metoda ta dołącza funkcję obsługi zdarzenia do każdego istniejącego już elementu, a także do wszystkich tych elementów, które zostaną utworzone w przyszłości. Oznacza to, że kliknięcie przycisku Usuń spowoduje odszukanie nadrzędnego w stosunku do niego elementu li i usunięcie go ze struktury DOM.
I coś jeszcze Pobieranie wartości po stronie serwera Wszystkie te pola tekstowe generowane są po stronie klienta za pomocą biblioteki jQuery. Aby skorzystać z nich po stronie serwera, każde pole powinno otrzymać atrybut name. Ze względu na to,
132
Rozdział 5. • Praca z formularzami
że wszystkie należą do tej samej grupy (strony WWW), możemy zdefiniować wartości atrybutu name w postaci tablicy, dzięki czemu będziemy mogli odczytać wprowadzone wartości z tablicy. Wystarczy tylko dodać do istniejącego pola tekstowego, a także do wszystkich utworzonych później, atrybut name="sites[]". Teraz po przekazaniu formularza do serwera będziemy mogli odczytać wszystkie wartości z tablicy $_POST['sites']. Poniżej przedstawiam przykładową zawartość tablicy $_POST po przesłaniu formularza z kilkoma wypełnionymi polami. Array ( [sites] => Array ( [0] => Purpurowy [1] => Fioletowy [2] => Czerwony [3] => Zielony [4] => Żółty ) )
Wyszukiwanie na stronie tekstu wprowadzonego przez użytkownika Użyjemy tutaj biblioteki jQuery, aby wyróżnić słowo wprowadzone przez użytkownika. Dane wyświetlane w przeglądarce mogą być też udostępniane przez serwer, na przykład z bazy danych. W tym przykładzie umieścimy na stronie trochę tekstu. Użytkownik będzie wprowadzał do pola tekstowego zapytanie i po kliknięciu przycisku wyróżnione zostaną wszystkie słowa pasujące do tego zapytania.
Przygotowania W katalogu rozdzial5 utwórz nowy katalog o nazwie receptura2.
Jak to zrobić? 1. Utwórz nowy plik, nazwij go index.html i zapisz w katalogu receptura2. Zaczniemy od przygotowania podstawowego kodu strony. Wprowadź kilka akapitów i wpisz do nich trochę tekstu. Na końcu przygotuj jeszcze pole tekstowe i dwa przyciski. Zdefiniuj dodatkowo klasę CSS highlight, której będziemy używać do wyróżniania tekstu.
133
PHP i jQuery. Receptury
Wyszukiwanie
2. Przed zamykającym znacznikiem body dołącz plik biblioteki jQuery. Na formularzu umieściliśmy dwa przyciski, przy czym pierwszy z nich będzie uruchamiał procedurę szukania wprowadzonego tekstu, a drugi będzie usuwał podświetlenie z tekstu. Aby uruchomić szukanie, klikamy przycisk Szukaj i tym samym wywołujemy funkcję highlight(). Funkcja ta wyszukuje na stronie podany tekst i w przypadku znalezienia go umieszcza wokół niego znaczniki HTML, dołączając do nich klasę highlight. Drugi z przycisków wywołuje funkcję clearSelection(), która przywraca stronę do pierwotnej postaci.
3. Uruchom w przeglądarce plik index.html i wprowadź do pola tekstowego jakieś słowo. Kliknij przycisk Szukaj, a wszystkie słowa pasujące do wprowadzonego wzorca zostaną wyróżnione. Kliknięcie przycisku Wyczyść przywróci stronę do pierwotnego stanu.
Jak to działa? Po wprowadzeniu tekstu do pola tekstowego i kliknięciu przycisku Szukaj wywoływana jest funkcja highlight(). W pierwszej kolejności usuwa ona wszystkie istniejące wyróżnienia, wywołując w tym celu funkcję clearSelection(). W kolejnym kroku wprowadzona w polu tekstowym fraza wyszukiwania zapisywana jest w zmiennej searchText. Następnie tworzony jest obiekt na podstawie dostępnej w języku JavaScript klasy RegExp. To właśnie to wyrażenie regularne zajmie się faktycznym wyszukiwaniem tekstu na stronie.
136
Rozdział 5. • Praca z formularzami
Teraz iterujemy po wszystkich akapitach znajdujących się na stronie. Pobieramy kod HTML każdego z nich i wywołujemy funkcję replace(), która pobiera dwa parametry. Pierwszym z nich jest obiekt wyrażenia regularnego, a drugim tekst, który ma zastąpić fragmenty pasujące do wyrażenia. W tym przypadku umieszczamy po prostu wyszukiwany tekst w elemencie span, któremu przypisana została klasa highlight. Funkcja replace() zwraca całość tekstu z wprowadzonymi już do niego poprawkami, dlatego w ostatnim kroku musimy tylko podmienić oryginalny kod HTML akapitu.
I coś jeszcze Wyszukaj i zamień Rozbudowując przedstawiony tu mechanizm, można przygotować proste narzędzie do wyszukiwania i podmiany tekstu. Zamiast wyróżniać znaleziony tekst możemy wstawić w jego miejsce inny tekst.
Szukanie pustych pól za pomocą biblioteki jQuery Kontrola danych to bardzo ważny element skryptów działających po stronie klienta. Kontrola wykonywana po stronie klienta może znacząco zmniejszyć liczbę odwołań do serwera, prezentując użytkownikowi natychmiastowe informacje o danych w formularzu. Mimo tego nie zaleca się korzystania wyłącznie z kontroli po stronie klienta. Użytkownicy mogą wyłączyć w przeglądarce obsługę języka JavaScript, dlatego dane powinny być zawsze kontrolowane ponownie po stronie serwera.
Przygotowania W katalogu rozdzial5 utwórz nowy katalog o nazwie receptura3.
Jak to zrobić? 1. W katalogu receptura3 utwórz nowy plik i nazwij go index.html. W pliku tym przygotuj kilka pól tekstowych oraz przycisk typu input. Pamiętaj, że wszystkie pola tekstowe, z wyjątkiem pola city, muszą otrzymać klasę required. Będziemy z niej korzystać podczas kontrolowania zawartości formularza.
137
PHP i jQuery. Receptury
Kontrola pustych pól
2. Przed zamykającym znacznikiem body dołącz jeszcze plik biblioteki jQuery. Dopisz też kod sprawdzający i dołącz funkcję obsługującą zdarzenie click do przycisku. Funkcja validate() zostanie wywołana w momencie kliknięcia przycisku i sprawdzi, czy w polach tekstowych znajdują się jakieś wartości.
3. Uruchom w przeglądarce plik index.html. Nie wypełniaj pól tekstowych i od razu kliknij przycisk Sprawdź. Przy każdym wymaganym polu pojawi się komunikat o błędzie.
Po wprowadzeniu niezbędnych informacji do formularza ponownie kliknij przycisk Sprawdź. Tym razem ponad przyciskiem pojawi się zielony komunikat informujący o tym, że wszystkie dane w formularzu są poprawne.
139
PHP i jQuery. Receptury
Jak to działa? Na początek przypisujemy klasę required do każdego pola tekstowego, które uznajemy za wymagane. Dzięki temu będziemy mogli użyć selektora biblioteki jQuery, aby potem odszukać te pola. Najpierw do przycisku Sprawdź dołączamy funkcję obsługującą zdarzenie click, w ramach której wywołujemy tylko funkcję validate(). W tej funkcji na początek deklarowana jest zmienna dataValid i nadawana jest jej wartość true. Następnie wybierane są z formularza wszystkie pola tekstowe z przypisaną klasą required. W kolejnym kroku iterujemy po tej kolekcji i usuwamy ewentualne elementy span umieszczone obok pola tekstowego, które mogą być pozostałością nieaktualnych już komunikatów o błędach. Jeżeli nie usunęlibyśmy ich, to przy jednym polu tekstowym mogłoby się pojawić kilka komunikatów. Po tym wszystkim instrukcja if sprawdza wartość aktualnego pola tekstowego. Proszę zauważyć, że skorzystaliśmy tutaj z funkcji trim() udostępnianej przez bibliotekę jQuery. Ze względu na to, że znaki białe nie są uznawane za prawidłowe wartości, musimy je usunąć z pola tekstowego. Jeżeli w polu znajduje się pusta wartość, to umieszczamy przy nim element span z komunikatem o błędzie, a zmiennej dataValid przypisujemy wartość false. Po przejrzeniu wszystkich pól tekstowych sprawdzamy wartość zmiennej dataValid. Jeżeli nadal ma wartość true, to znaczy, że w każdym wymaganym polu wprowadzony został jakiś tekst i możemy wyświetlić na ekranie informację o poprawnej zawartości formularza.
140
Rozdział 5. • Praca z formularzami
I coś jeszcze Kontrolowanie pojedynczych pól Jeżeli nie chcielibyśmy wyświetlać wszystkich komunikatów naraz, ale nakazać użytkownikowi wypełnienie jednego pola i przejście do kolejnego, to należałoby zmodyfikować przedstawiony powyżej kod. W tym celu zmień instrukcję if, tak jak pokazano poniżej: if ($.trim(cur.val()) == '') { cur.after('To pole jest wymagane'); dataValid = false; }
Następnie usuń jeszcze tę instrukcję: if(dataValid) { $('#info').html('Formularz poprawny'); }
Zobacz też Q Recepturę „Sprawdzanie poprawności liczb za pomocą biblioteki jQuery”. Q Recepturę „Sprawdzanie poprawności adresów e-mail i adresów WWW za pomocą
wyrażeń regularnych”. Q Recepturę „Wyświetlanie błędów w czasie wprowadzania danych, czyli sprawdzanie danych na żywo”.
Sprawdzanie poprawności liczb za pomocą biblioteki jQuery W poprzedniej recepturze sprawdzaliśmy, czy w formularzu znajdują się niewypełnione pola. Tym razem rozbudujemy ten mechanizm kontrolny i oprócz wymogu wprowadzenia danych do pola będziemy sprawdzać, czy wprowadzona została liczba.
Przygotowania W katalogu rozdzial5 utwórz nowy katalog o nazwie receptura4.
141
PHP i jQuery. Receptury
Jak to zrobić? 1. W katalogu receptura4 utwórz nowy plik i nazwij go index.html. Wykorzystamy tutaj ten sam kod, którego użyliśmy w poprzedniej recepturze, ale dodamy do niego nowe elementy. Możesz zatem skopiować cały kod z poprzedniej receptury do pliku index.html. Teraz dodamy do niego nowe pola, w których użytkownik będzie mógł wprowadzić liczby. Utwórz zatem kolejną tabelę z opisem Inne dane. Trzeba tu nadmienić, że pola tekstowe w tej tabeli muszą zostać przypisane do klas numeric i required. Dzięki temu będziemy mogli sprawdzić, czy pola nie są puste i czy wpisano do nich liczbę.
142
Rozdział 5. • Praca z formularzami
2. Przejdźmy teraz do kodu JavaScript. Ponownie dołącz plik biblioteki jQuery i dopisz kod sprawdzający poprawność danych w formularzu. Tym razem kliknięcie przycisku najpierw uruchomi procedurę sprawdzania, czy pola nie są puste. Jeżeli takie zostaną znalezione, to wyświetlane są odpowiednie komunikaty, a funkcja kończy pracę. Gdy tylko wszystkie wymagane pola zostaną wypełnione, funkcja zacznie dodatkowo sprawdzać zawartość tych, w których mają znaleźć się tylko liczby. Poniżej przedstawiam pełny kod kontrolujący formularz:
143
PHP i jQuery. Receptury
Jak to działa? W podanym tu kodzie najpierw sprawdzamy, czy wszystkie pola zostały wypełnione, iterując po elementach klasy required. Po zakończeniu tej pętli sprawdzamy wartość zmiennej dataValid. Jeżeli ma ona wartość false, to natychmiast kończymy działanie funkcji. Jeżeli jednak wszystkie wymagane pola zostały wypełnione, to przechodzimy do sprawdzania pól liczbowych. Wybieramy zatem wszystkie elementy, którym przypisano klasę number, i za pomocą metody each() kontrolujemy zawartość tych elementów. Funkcja isNaN() języka JavaScript pozwala na stwierdzenie, czy podana jej wartość jest liczbą czy też nie. Jeżeli wartość z danego pola nie jest liczbą, to wstawiamy przy tym polu odpowiedni komunikat. Jeżeli wszystkie pola poprawnie przejdą wszystkie etapy kontroli formularza, to nad przyciskiem Sprawdź wyświetlany jest komunikat Formularz poprawny.
Zobacz też Q Recepturę „Szukanie pustych pól za pomocą biblioteki jQuery”. Q Recepturę „Sprawdzanie poprawności adresów e-mail i adresów WWW za pomocą
wyrażeń regularnych”. Q Recepturę „Wyświetlanie błędów w czasie wprowadzania danych, czyli sprawdzanie danych na żywo”.
Sprawdzanie poprawności adresów e-mail i adresów WWW za pomocą wyrażeń regularnych Podczas wypełniania formularzy w internecie bardzo często jesteśmy proszeni o podanie adresu e-mail lub adresu strony WWW. Te dwie wartości troszkę różnią się od zwyczajnych ciągów znaków, ponieważ charakteryzują się określonym wzorcem. Na przykład w adresach e-mail musi znaleźć się znak ampersand (@), natomiast adresy stron WWW zwykle zaczynają się od przedrostka http:// lub https://. Dla takich adresów można też zdefiniować wiele innych warunków. Tutaj na pomoc przychodzą nam wyrażenia regularne. W tej recepturze nauczymy się używać wyrażeń regularnych do sprawdzania poprawności takich wzorców, jak adresy e-mail lub adresy URL.
144
Rozdział 5. • Praca z formularzami
Przygotowania W katalogu rozdzial5 utwórz nowy katalog o nazwie receptura5.
Jak to zrobić? 1. W katalogu receptura5 utwórz nowy plik o nazwie index.html. Podobnie jak w poprzedniej recepturze, utwórz w nim dwa pola tekstowe. W jedno z nich wprowadzany będzie adres e-mail, a w drugie adres strony WWW. Oprócz tego pierwszemu polu przypisz klasę mail, a drugiemu klasę site. Sprawdzanie adresu e-mail
145
PHP i jQuery. Receptury
2. W ramach realizowania funkcji kontroli formularza najpierw dołącz plik biblioteki jQuery. Następnie dopisz funkcję obsługi zdarzenia click w przycisku Sprawdź. W pierwszej kolejności funkcja ta wyszuka wszystkie elementy klasy mail i skontroluje znajdujący się w niej tekst, wykorzystując do tego wyrażenie regularne. Następnie sprawdzone zostaną adresy stron WWW. Tym razem również użyte zostanie odpowiednie wyrażenie regularne. Jeżeli tekst z pola nie będzie pasował do wyrażenia sprawdzającego, to przy polu pojawi się komunikat.
Jak to działa? Po kliknięciu przycisku Sprawdź wywoływana jest funkcja validate(). W funkcji tej najpierw definiowana jest zmienna dataValid i przypisywana jest jej wartość true. Następnie pobierane są wszystkie pola tekstowe klasy mail i zaczynamy iterować po takiej kolekcji. Deklarujemy tu zmienną emailPattern, w której zapisywane jest wyrażenie regularne. Teraz wewnątrz instrukcji if używamy funkcji test(), aby porównać zawartość pola tekstowego z wyrażeniem regularnym. Jeżeli pole nie pasuje do wzorca, to obok pola tekstowego umieszczamy komunikat i nadajemy zmiennej dataValid wartość false. Tę samą procedurę powtarzamy jeszcze dla elementów klasy site. W tym przypadku stosujemy jednak nieco inne wyrażenie regularne. Jeżeli formularz pomyślnie przejdzie wszystkie etapy kontroli, to nad przyciskiem wyświetlamy tekst Formularz poprawny.
I coś jeszcze Wyrażenie regularne Więcej informacji na temat wyrażeń regularnych znaleźć można pod podanymi niżej adresami: Q http://www.regular-expressions.info/ Q http://pl.wikipedia.org/wiki/Wyrażenie_regularne
147
PHP i jQuery. Receptury
Zobacz też Q Recepturę „Szukanie pustych pól za pomocą biblioteki jQuery”. Q Recepturę „Sprawdzanie poprawności liczb za pomocą biblioteki jQuery”.
Wyświetlanie błędów w czasie wprowadzania danych, czyli sprawdzanie danych na żywo Czy nie byłoby lepiej, gdybyśmy mogli kontrolować dane wprowadzane przez użytkownika wtedy, gdy on je wprowadza? Nie musielibyśmy czekać na kliknięcie przycisku, komunikaty byłyby też znacznie czytelniejsze. W tej recepturze mocno rozbudujemy przykłady z poprzednich receptur i nauczymy się na żywo kontrolować poprawność danych w formularzu. Dzięki temu użytkownik będzie otrzymywał informacje w trakcie wprowadzania danych do pola tekstowego.
Przygotowania W katalogu rozdzial5 utwórz nowy katalog o nazwie receptura6.
Jak to zrobić? 1. W katalogu receptura6 utwórz nowy plik i nazwij go index.html. Zapisz do niego kod HTML tworzący dwa panele: jeden dla Danych osobowych, a drugi dla Innych. Pola tekstowe z pierwszego panelu zostaną związane z klasą required. Podobnie pola z drugiego panelu otrzymają klasy required i number. Kontrola formularza na żywo
148
Rozdział 5. • Praca z formularzami
2. Teraz dołącz plik biblioteki jQuery. Następnie dodaj do pól tekstowych funkcję obsługi zdarzenia, która zostanie wywołana, gdy w danym polu pojawi się kursor albo zostanie w nim puszczony klawisz. Nasz kod będzie wykonywany, w czasie gdy użytkownik będzie wpisywał dane, a ewentualne komunikaty będą się
149
PHP i jQuery. Receptury
pojawiały, w przypadku gdy użytkownik popełni błąd. Na koniec potrzebna będzie jeszcze funkcja obsługująca kliknięcia przycisku Zapisz, tak żeby użytkownik mógł go kliknąć przed wprowadzeniem do formularza jakichkolwiek danych.
Ekran ze źle wprowadzonymi danymi powinien wyglądać podobnie do poniższego rysunku.
Jak to działa? Ze względu na to, że chcemy na bieżąco kontrolować dane wprowadzane do formularza przez użytkownika, musimy podłączyć do pól tekstowych funkcje obsługujące dwa zdarzenia: focus i keyup. Pierwsze z nich wywoływane jest w momencie, gdy użytkownik umieści kursor w polu tekstowym (klikając je myszą albo naciskając klawisz Tab), a drugie w momencie puszczenia klawisza. W obu przypadkach wywoływana jest funkcja validate(). W ten sposób możemy natychmiast kontrolować wartość wprowadzaną do pola tekstowego.
151
PHP i jQuery. Receptury
Funkcja validate() wykonuje te same działania, które widzieliśmy już w kilku poprzednich recepturach. Pobierze wartość z pola tekstowego i w zależności od klasy, jaką przypisano temu polu, sprawdzi, czy pole nie jest puste albo czy wprowadzono do niego liczbę. Mamy tu jednak pewien problem. Jeżeli użytkownik kliknie przycisk Zapisz bez uprzedniego wypełnienia danych w formularzu, to nie dowie się, że formularz ten jest nieprawidłowy. Aby zapobiec takiej sytuacji, musimy przedsięwziąć odpowiednie kroki. Po pierwsze w ramach funkcji validate() każdemu polu tekstowemu przypisujemy wartość true lub false. Wykorzystujemy tutaj metodę data() biblioteki jQuery, która pozwala na zapisywanie dodatkowych informacji w elementach DOM. Podczas kontrolowania pola tekstowego zapisujemy do niego wartość z kluczem valid, przypisując mu jednocześnie wartość true lub false. Do przycisku Zapisz również przypinamy funkcję obsługi zdarzenia click. Załóżmy teraz, że użytkownik kliknął ten przycisk, nie wprowadzając wcześniej danych do pól tekstowych. Pobieramy wtedy wszystkie te pola i sprawdzamy, czy została z nimi związana jakaś wartość. Interesuje nas klucz o nazwie valid i przypisana mu wartość true. Jeżeli nie znajdziemy takiej kombinacji, to znaczy, że dane pole nie przeszło wcześniejszej kontroli, a wtedy zmiennej dataValid przypisujemy wartość false. Tę samą procedurę powtarzamy dla pól tekstowych klasy number. Na koniec wyświetlamy jeszcze komunikat odpowiedni do wartości zmiennej dataValid.
Zobacz też Q Recepturę „Szukanie pustych pól za pomocą biblioteki jQuery”. Q Recepturę „Sprawdzanie poprawności liczb za pomocą biblioteki jQuery”. Q Recepturę „Sprawdzanie poprawności adresów e-mail i adresów WWW za pomocą
wyrażeń regularnych”. Q Recepturę „Mocniejsza kontrola formularza, czyli ponowne kontrolowanie w PHP”.
Mocniejsza kontrola formularza, czyli ponowne kontrolowanie w PHP Jak już wcześniej wspominałem, kontrola formularzy po stronie klienta powinna być zawsze powiązana z podobnym mechanizmem kontroli po stronie serwera. Jeżeli użytkownik wyłączy w przeglądarce obsługę języka JavaScript, a nie będziemy mieli kontroli po stronie serwera, to będzie mógł wprowadzić do formularza absolutnie dowolne dane. Może to prowadzić do tragicznych efektów, takich jak utrata bazy danych itp.
152
Rozdział 5. • Praca z formularzami
W tej recepturze przyjrzymy się metodom kontroli oraz funkcjom dostępnym w języku PHP, które możemy wykorzystać do sprawdzenia poprawności danych w formularzu.
Przygotowania W katalogu rozdzial5 utwórz nowy katalog o nazwie receptura7. Upewnij się, że korzystasz z interpretera PHP w wersji wyższej niż 5.2. Będziemy tu używać funkcji filtrujących, które dostępne są dopiero od wersji 5.2.
Jak to zrobić? 1. W katalogu receptura7 utwórz plik o nazwie index.php. Przygotuj w nim formularz z różnymi polami przeznaczonymi do wprowadzania ciągów znaków, liczb, adresów e-mail i adresów stron WWW. Kontrola formularza po stronie serwera
Formularz powinien wyglądać podobnie do przedstawionego poniżej:
2. Po przesłaniu formularza na serwer uruchamiany jest plik index.php. Oznacza to, że procedury kontrolne musimy umieścić na samym początku tego pliku. Poniżej prezentuję kod PHP, który należy wstawić na sam początek pliku. Sprawdza on wszystkie pola formularza i w przypadku znalezienia jakiegoś błędu umieszcza komunikat w specjalnej tablicy.
154
3. Jak widać, w powyższym wycinku kodu tworzymy tablicę z komunikatami błędów (która może też być pusta). Poniższy kod zajmie się wyświetleniem tych komunikatów w przeglądarce. Umieść go zaraz za otwierającym znacznikiem form. 0) { ?>
'; } ?>
4. Uruchom w przeglądarce plik index.php. Wprowadź do formularza kilka nieprawidłowych wartości i kliknij przycisk Wyślij. Na stronie pojawi się wtedy lista komunikatów opisująca wszystkie błędy w formularzu.
155
PHP i jQuery. Receptury
Jak to działa? Najpierw za pomocą funkcji isset() sprawdzamy, czy dostępna jest wartość $_POST['save'], co oznaczałoby, że właśnie otrzymaliśmy dane z formularza. Następnie przepisujemy wartości z pól formularza do osobnych zmiennych i deklarujemy tablice $errorArray, w której będziemy zbierać komunikaty o błędach. Przystępując do kontroli formularza, sprawdzamy najpierw, czy wszystkie pola zostały wypełnione. Jeżeli w którymkolwiek z nich brakuje wartości, to wpisujemy odpowiedni komunikat o błędzie do tablicy $errorArray. W kolejnym kroku korzystamy z funkcji języka PHP filter_var(). Pobiera ona trzy parametry, z których dwa ostatnie są opcjonalne. Pierwszy parametr jest identyfikatorem filtra kontrolującego, który definiuje rodzaj kontroli, jakiej ma zostać poddane pole. Na przykład identyfikator FILTER_VALIDATE_INT nakazuje sprawdzić, czy dane pole zawiera liczbę całkowitą. W naszym przykładzie użyliśmy trzech rodzajów kontroli: FILTER_VALIDATE_INT, FILTER_VALIDATE_EMAIL i FILTER_VALIDATE_URL. Funkcja filter_var() zwraca przefiltrowaną wartość, w przypadku gdy przejdzie ona wszystkie testy, lub wartość false, jeżeli testów nie przejdzie. W naszym przykładzie w przypadku otrzymania wartości false umieszczamy w tablicy $errorArray odpowiedni komunikat. W samym formularzu sprawdzamy liczbę elementów znajdujących się w tablicy $errorArray. Jeżeli liczba ta jest większa od zera, to znaczy, że w formularzu znaleziono błędy. W takiej sytuacji iterujemy po tej tablicy i po kolei wypisujemy wszystkie komunikaty.
156
Rozdział 5. • Praca z formularzami
I coś jeszcze Lista dostępnych filtrów Q Q Q Q Q Q Q
Pełną listę filtrów kontrolnych dostępnych w języku PHP można znaleźć na stronach WWW tego języka, pod adresem http://www.php.net/manual/pl/filter.filters.validate.php.
Poprawianie danych Funkcja filter_var() oprócz sprawdzania poprawności danych może też zostać użyta do ich poprawiania. Chodzi tutaj o mechanizmy usuwające z danych złośliwe lub niepożądanie elementy wprowadzone przez użytkownika. Składnia wywołania funkcji nie zmienia się, a jedyna różnica polega na tym, że w drugim parametrze zamiast filtrów sprawdzających należy podać filtry poprawiające. Poniżej przedstawiam kilka często używanych filtrów poprawiających: Q Q Q Q Q Q Q
Listę wszystkich filtrów poprawiających można znaleźć na stronach języka PHP pod adresem http://www.php.net/manual/pl/filter.filters.sanitize.php.
Zobacz też Q Recepturę „Sprawdzanie poprawności liczb za pomocą biblioteki jQuery”. Q Recepturę „Sprawdzanie poprawności adresów e-mail i adresów WWW za pomocą
wyrażeń regularnych”. Q Recepturę „Wyświetlanie błędów w czasie wprowadzania danych, czyli sprawdzanie danych na żywo”.
157
PHP i jQuery. Receptury
Tworzenie systemu do głosowania Przygotujemy tutaj przykład, w którym użytkownicy będą mogli oddawać głosy na swoją ulubioną przeglądarkę. Po oddaniu głosu nie będą mogli oddać kolejnego przez następne 24 godziny. Wszystkie zebrane głosy będą przechowywane w pliku XML. Oprócz tego będziemy wyświetlać statystykę w postaci estetycznego wykresu. Plik XML został tu użyty jedynie w formie przykładu. W rzeczywistych aplikacjach dane są ładowane z baz danych lub usług sieciowych, które mogą stosować najróżniejsze formaty, takie jak XML, JSON lub inne.
Przygotowania W katalogu rozdzial5 utwórz nowy katalog o nazwie receptura8.
Jak to zrobić? 1. Ta receptura będzie trochę dłuższa niż pozostałe, dlatego nie zwlekajmy z początkiem prac. Najpierw w katalogu receptura8 utwórz plik XML i nazwij go browsers.xml. Będziemy w nim zapisywać informacje o przeglądarkach, które będziemy wyświetlać użytkownikom.
2. Teraz utwórz kolejny plik i nazwij go index.php. Odczytamy w nim zawartość pliku XML i zaprezentujemy użytkownikowi listę przeglądarek, na które może oddać głos. W tym samym pliku umieścimy też kod zajmujący się przesyłaniem formularza na serwer. Oprócz tego ograniczymy możliwość głosowania do jednego głosu dziennie.
158
3. Uruchom plik index.php w przeglądarce, a zobaczysz na stronie kilka opcji do wyboru oraz przycisk Głosuj, taki jak na poniższym rysunku.
4. Na powyższej stronie znajdziemy też łącze do strony z wynikami głosowania. Aby przygotować tę stronę, utwórz nowy plik i nazwij go results.php. Kod z tego pliku załaduje plik XML i wyświetli w przeglądarce aktualne wyniki głosowania. Wyniki głosowania
160
Rozdział 5. • Praca z formularzami
5. Wszystko jest już gotowe i możemy sprawdzić działanie naszego przykładu. Uruchom zatem plik index.php w przeglądarce, aby zobaczyć formularz. Wybierz ostatnią opcję i kliknij przycisk Głosuj. Pojawi się wtedy komunikat Twój głos został zapisany. Następnie wybierz inną przeglądarkę i jeszcze raz kliknij przycisk Głosuj. Tym razem pojawi się komunikat Twój głos został już przyjęty. Można glosować tylko raz dziennie. 6. Teraz kliknij przycisk Zobacz wyniki. Otwarta zostanie nowa strona, na której będziemy mogli zobaczyć liczbę głosów oddanych na każdą z przeglądarek. Oddany wcześniej głos zwiększył liczbę głosów na IE z 30 do 31.
161
PHP i jQuery. Receptury
Jak to działa? Na początek przyjrzyjmy się strukturze pliku browsers.xml. W tym pliku zapisane są trzy węzły przeglądarek, po jednym dla każdej z nich. Każdy z tych węzłów ma trzy atrybuty: name, value i votes. Wartość atrybutu name będzie wyświetlana na stronach, atrybut value używany jest w skryptach PHP, natomiast atrybut votes przechowuje liczbę głosów oddanych na daną przeglądarkę. Przejdźmy teraz do pliku index.php, w którym najpierw zajmiemy się kodem HTML. Za pomocą klasy DOMDocument ładujemy plik XML i na podstawie jego zawartości tworzymy listę wypunktowaną. Dla każdej przeglądarki tworzony jest jeden przycisk opcji. Na koniec tworzymy jeszcze przycisk Głosuj oraz łącze do strony z wynikami. A teraz podsumowanie operacji, jakie wykonywane są po przesłaniu formularza na serwer. Q Sprawdzamy, czy użytkownik już wcześniej oddał głos. W tym celu przyglądamy się superglobalnej zmiennej $_COOKIE. Jeżeli w ciasteczku zapisana jest już informacja
o głosowaniu, to musimy tylko wyświetlić komunikat o błędzie. Q Jeżeli użytkownik jeszcze nie głosował, to w pliku XML dodajemy jeden głos do
węzła wybranej przeglądarki. Q Aby dodać głos oddany na wybraną przeglądarkę, ładujemy dokument XML za pomocą klasy DOMDocument. Q Następnie przeszukujemy wszystkie węzły browser i porównujemy wartość atrybutu value z wartością wybraną przez użytkownika, którą odczytujemy z tablicy $_POST['browser']. Q Po znalezieniu właściwego węzła zwiększamy wartość jego atrybutu votes o jeden. Q W kolejnym kroku tworzymy ciasteczko o nazwie voted, które od teraz będzie
przechowywane przez przeglądarkę użytkownika. Wykorzystujemy do tego funkcję języka PHP setcookie(), która tworzy ciasteczko i ustala jego czas ważności na 24 godziny. W ten sposób użytkownik nie będzie mógł zagłosować częściej niż raz na dzień. Q Na zakończenie zapisujemy plik XML za pomocą metody save() z rozszerzenia DOM. Plik results.php generuje stronę wyników, ładując plik XML za pomocą klasy DOMDocument i iterując po węzłach browser, i tworząc jednocześnie listę wypunktowaną. Dla każdej przeglądarki tworzone są dwa elementy. W pierwszy element li wpisujemy nazwę przeglądarki oraz liczbę oddanych na nią głosów. W drugi element li wstawiamy element span, nadając mu szerokość w pikselach równą liczbie głosów oddanych na przeglądarkę. W ten sposób powstaje efekt słupka wykresu.
162
Rozdział 5. • Praca z formularzami
I coś jeszcze Czas życia ciasteczka W naszym przykładzie tworzyliśmy ciasteczka, które przedawniały się po jednym dniu. To ustawienie można oczywiście zmieniać zgodnie z własnymi potrzebami. Trzeba tylko pamiętać, że czas wygaśnięcia ciasteczka definiowany jest jako uniksowy znacznik czasu, dlatego trzeba podawać go w sekundach.
Zobacz też Q Recepturę „Odczytywanie dokumentów XML za pomocą rozszerzenia DOM”
z rozdziału 3. Q Recepturę „Modyfikowanie dokumentów XML za pomocą rozszerzenia DOM” z rozdziału 3.
Zezwalanie na kod HTML w polach tekstowych i ograniczanie zbioru dozwolonych znaczników Pozwalając użytkownikowi na wypełnianie formularza, możemy chcieć ograniczyć zbiór znaczników HTML, jakie będą dozwolone we wprowadzanych danych. Do niechcianych znaczników można na przykład dodać znacznik script, ponieważ może on źle wpłynąć na działanie naszej strony oraz na nasze dane. W tej recepturze nauczymy się filtrować znaczniki z danych otrzymanych z formularza i przyjmować tylko określony zbiór znaczników.
Przygotowania W katalogu rozdzial5 utwórz nowy katalog o nazwie receptura9.
163
PHP i jQuery. Receptury
Jak to zrobić? 1. W katalogu receptura9 utwórz nowy plik o nazwie index.html. W pliku tym utwórz dwa elementy typu textarea oraz jeden przycisk. W pierwszym polu tekstowym użytkownik będzie mógł wprowadzić tekst w formacie HTML. W drugim będziemy wyświetlać ten sam tekst po usunięciu z niego niedozwolonych znaczników. Usuwanie znaczników
2. Dołącz plik biblioteki jQuery, a następnie dodaj funkcję obsługi zdarzenia click przycisku Sprawdź. Kliknięcie tego przycisku wyśle dane z pierwszego pola tekstowego do skryptu PHP validate.php. W momencie otrzymania odpowiedzi wpiszemy ją do drugiego pola tekstowego.
3. Utwórz kolejny plik i nazwij go validate.php. Wpisz do niego kod usuwający niedozwolone znaczniki HTML z danych wprowadzonych przez użytkownika i wyślij wyniki tej pracy do przeglądarki. ')); ?>
4. Teraz otwórz w przeglądarce plik index.html i wpisz do pierwszego pola tekstowego nieco tekstu ze znacznikami HTML. Po kliknięciu przycisku Sprawdź w drugim polu pojawi się ten sam tekst z usuniętymi niedozwolonymi znacznikami.
165
PHP i jQuery. Receptury
Jak to działa? Po kliknięciu przycisku Sprawdź żądanie AJAX wysyłane jest do pliku validate.php. I tutaj wykonywana jest główna praca. Otrzymane dane pobierane są z tablicy $_POST. Następnie wywołujemy funkcję PHP strip_tags(), która usuwa z podanego jej ciągu znaków wszystkie znaczniki HTML. W pierwszym parametrze trzeba jej przekazać ciąg znaków, z którego chcemy usunąć znaczniki. Drugi parametr jest opcjonalny. Jeżeli nie zostanie przekazany do funkcji, to usunie ona z tekstu wszystkie znalezione znaczniki. W naszym przykładzie chcemy jednak zezwolić na stosowanie czterech znaczników: , , oraz , a zatem musimy podać je funkcji w drugim parametrze. W takiej sytuacji funkcja usunie z tekstu wszystkie znaczniki HTML z wyjątkiem tych czterech. Zwraca ona ciąg znaków, który możemy teraz bezpiecznie zapisać do bazy danych albo wykonać na nim kolejne operacje. W naszym przykładzie odsyłamy tekst do przeglądarki, aby użytkownik mógł sprawdzić, jak będzie on wyglądać. W samej przeglądarce biblioteka jQuery wstawi otrzymany tekst do drugiego pola tekstowego.
I coś jeszcze Usuwane są też znaczniki PHP Automatycznie usuwane są również komentarze HTML oraz znaczniki PHP.
166
6 Efekty specjalne w formularzach W tym rozdziale zajmiemy się: Q tworzeniem gry w kółko i krzyżyk, Q informowaniem użytkownika o przetwarzaniu żądania AJAX, Q tworzeniem rozwijanych i zwijanych ramek (harmonijek), Q stopniowym ukrywaniem elementu po jego zaktualizowaniu, Q wyświetlaniem pływającego okienka na żądanie, Q aktualizowaniem pozycji w koszyku na zakupy.
Wprowadzenie Właściwe zastosowanie na stronach WWW biblioteki jQuery może wprowadzić do nich niezwykłe efekty oraz spowodować poprawę interakcji z użytkownikiem. Istnieje wiele wtyczek do tej biblioteki, które udostępniają wiele narzędzi i gadżetów prezentowanych w tym rozdziale. W wielu przypadkach niestety wtyczki te próbują oferować tak wiele, że pojawiają się w nich zupełnie bezużyteczne funkcje.
PHP i jQuery. Receptury
W tym rozdziale zajmiemy się tworzeniem różnych gadżetów, takich jak harmonijki, pływające elementy div oraz znikające żółte tło, które są często wykorzystywane w dzisiejszych aplikacjach. Efekty te będziemy tworzyć najprostszymi metodami i za pomocą minimalnej ilości kodu.
Tworzenie gry w kółko i krzyżyk Formularze WWW powinny być jak najbardziej przyjazne użytkownikom, tak żeby ułatwiać im pracę. Oznacza to, że użytkownik nie powinien mieć kłopotów z określeniem, co do czego służy na stronie. W tej recepturze przygotujemy prostą grę w kółko i krzyżyk. Każdy z pewnością grał już w tę grę w dzieciństwie, a teraz wykorzystamy ją jako doskonały przykład tego, jak można wyróżniać poszczególne części strony, aby poinformować użytkownika, gdzie może dalej współpracować ze stroną. Będziemy tworzyć grę dla dwóch graczy, którym zaprezentujemy planszę o wielkości 3×3 lub 5×5 pól, zależnie od dokonanego wcześniej wyboru. Umieszczenie wskaźnika myszy nad polem planszy spowoduje wyróżnienie go, a kliknięciem będzie można umieścić w tym polu kółko lub krzyżyk, zależnie od tego, który gracz wykonuje ruch. Po wykonaniu każdego ruchu będziemy zmieniać gracza i sprawdzać, czy któryś z nich już nie wygrał.
Przygotowania W katalogu rozdzial6 utwórz nowy katalog o nazwie receptura1. Na potrzeby tej receptury będziemy potrzebowali dwóch obrazków: jednego z krzyżykiem i jednego z kółkiem, zgodnie z zasadami gry. Za pomocą dowolnego prostego programu graficznego przygotuj zatem oba obrazki. W swoim przykładzie zastosowałem poniższe:
Jak to zrobić? 1. Najpierw w katalogu receptura1 utwórz plik o nazwie main.css. W pliku tym umieścimy style CSS definiujące wygląd naszej gry. body{color:#FA6766;font-family:Trebuchet MS,arial,verdana;margin:20px; ´padding:0pt;}
2. Po zdefiniowaniu stylów utwórz kolejny plik w tym samym katalogu i nazwij go index.html. W tym pliku dołącz oczywiście plik main.css, a następnie utwórz listę rozwijaną, z której użytkownik będzie mógł wybrać wielkość pola gry (3×3 lub 5×5). Potem dopisz dwa elementy h2. Pierwszy z nich posłuży nam do wyświetlania danych gracza wykonującego ruch, a drugi pozwoli rozpocząć nową grę po zakończeniu poprzedniej. Na koniec utwórz jeszcze element div o identyfikatorze container, w którym znajdzie się plansza do gry. Tę najlepiej będzie przygotować za pomocą biblioteki jQuery. 3. W ostatnim kroku dodaj jeszcze referencję pliku biblioteki jQuery. Sam kod JavaScript będzie troszkę przydługawy, dlatego zapiszemy go w osobnym pliku o nazwie tictactoe.js. Oczywiście nie można też zapomnieć o dodaniu odwołania do tego pliku. Kółko i krzyżyk
Wielkość planszy:
Czekam na gracza numer 1
Od nowa
169
PHP i jQuery. Receptury
4. Teraz w katalogu receptura1 utwórz plik tictactoe.js. Tutaj zdefiniujemy osobną przestrzeń nazw game, w której umieścimy wszystkie nasze zmienne i funkcje. Kod zapisany w tym pliku musi między innymi definiować funkcję createGrid(), która będzie tworzyć pole gry zgodne z wybraną przez użytkownika wielkością. Następnie będzie ona dołączać funkcje obsługi zdarzeń kliknięcia poszczególnych pól planszy. $(document).ready(function() { function game() {}; game.init = function(size) { if(parseInt(size,10) <=0) return; this.gridSize = size; this.player = 0; // 0 - gracz 1; 1- gracz 2 this.marker; //przygotuj planszę this.createGrid(); $('.col').hover(function(){$(this).css('background-color', '#FBF9EA');},function(){$(this).css('background-color', '#FFF');}); $('.col').click(function() { //sprawdź, czy już nie kliknięty if($(this).hasClass('cross') || $(this).hasClass('round')) { return; }// kliknięty var who = (game.player ==0 ) ? "Gracz 1" : "Gracz 2"; game.marker = (game.player == 0 ) ? 'cross' : 'round'; $(this).addClass(game.marker); var won = game.checkForWin(this); if(!won) { //zmień gracza game.player = (game.player == 0) ? 1 : 0; var player = (game.player ==0 ) ? "Gracz 1" : "Gracz 2"; $('#log').html('Waiting for '+ player); } else { $('.col').unbind('click'); $('#log').html(who + ' wygrywa!!!'); $('h2:last').show('slow'); } }); }
170
Rozdział 6. • Efekty specjalne w formularzach
5. Kolejną funkcją zdefiniowaną w tym pliku będzie checkForWin(), której zadaniem jest sprawdzanie, czy gracz wygrał po kliknięciu jednego z pól planszy. Na koniec nie możemy jeszcze zapomnieć o dodaniu funkcji obsługi zdarzenia kliknięcia obu elementów h2. W ostatnim wierszu kodu zaczynamy grę, wywołując funkcję init(). game.checkForWin = function(current) { var size = this.gridSize; var row = $(current).attr('i'); var col = $(current).attr('j'); //sprawdź wiersze i kolumny var hDone = true, vDone = true; for(var i=0; i< size; i++) { if($('#'+(row + i)).hasClass(this.marker) != true) hDone = false; if($('#'+(i + col)).hasClass(this.marker) != true) vDone = false; } if(hDone == true || vDone == true) return true; //sprawdź przekątne if(row == col || ((parseInt(row) + parseInt(col)) == (this.gridSize)-1)) { var ldDone = true, rdDone = true; for(var i = 0, j = size-1; i< size; i++, j--) { if($('#'+i+i).hasClass(this.marker) != true) ldDone = false; if($('#'+i+j).hasClass(this.marker) != true) rdDone = false; } if(ldDone == true || rdDone == true) return true; } return false; } game.createGrid = function() { var size = this.gridSize; var str = '
'; for(var i=0; i" ; for(var j="0;" j
';
171
PHP i jQuery. Receptury
} str+= '
'; } $('#container').html(str); } $('#size').change(function() { game.init($(this).val()); $('#log').html('Waiting for Player 1'); }); $('h2:last').click(function() { game.init($('#size').val()); $('#log').html('Waiting for Player 1'); $(this).hide('slow'); }); game.init(3); });
6. Gra jest już ukończona i możemy spróbować, jak działa. Uruchom zatem plik index.html w przeglądarce, a zobaczysz planszę do gry w kółko i krzyżyk o wielkości 3 pól.
7. Zacznij grę. Umieszczenie wskaźnika myszy nad polem spowoduje, że zabarwi się ono na żółto. Kliknięcie dowolnego pola umieści na nim kółko lub krzyżyk. Gdy jeden z graczy wygra grę, okno przeglądarki będzie wyglądało podobnie do poniższego:
172
Rozdział 6. • Efekty specjalne w formularzach
Jak to działa? Najpierw definiujemy globalny obiekt game. Posłuży on nam za przestrzeń nazw, w której będziemy przechowywać wszystkie zmienne i funkcje potrzebne do funkcjonowania naszej gry. Zaczynamy od funkcji init(), której trzeba przekazać liczbę określającą wielkość planszy. Ważna jest też zmienna player, której wartość określa gracza wykonującego ruch. Wartość 0 wskazuje na gracza numer 1, a wartość 1 na gracza numer 2. Zmienna marker definiuje rodzaj ikony, jaką należy umieścić w polu, zależnie od tego, który gracz wykonuje swój ruch. Krzyżyki przypisane są graczowi numer 1, a kółka graczowi numer 2. Kolejnym elementem jest funkcja createGrid(), która przygotowuje planszę do gry. Tworzy ona element div z wierszami i kolumnami, którym przypisuje klasy CSS definiujące ich wygląd. Jeżeli plansza ma wielkość 3, to znaczy, że będzie ona miała wysokość i szerokość trzech pól. Po przygotowaniu kodu HTML planszy zostaje on wstawiony do elementu div o identyfikatorze container. Każdej kolumnie na planszy przypisywane są też dwa dodatkowe atrybuty i oraz j, których wartości definiują indeks pola w tablicy. Zasada przypisywania wartości tym atrybutom została wyjaśniona na poniższym rysunku.
173
PHP i jQuery. Receptury
Zanim przejdziemy dalej, muszę wspomnieć jeszcze o dwóch klasach CSS: cross i round. Pierwsza z nich dodaje w tle elementu obrazek z krzyżykiem, natomiast druga dodaje do tła elementu obrazek z kółkiem. Nasz interfejs użytkownika jest już gotowy, a zatem możemy przygotować funkcje obsługi zdarzeń. W naszym przykładzie definiujemy dwie ważne funkcje. Pierwsza z nich wywoływana jest, gdy użytkownik umieszcza wskaźnik myszy nad polami planszy. W takiej sytuacji korzystamy z funkcji biblioteki jQuery hover(), poprzez którą zmieniamy kolor pola na żółty. Gdy tylko wskaźnik zostanie przesunięty poza pole, jego kolor znów staje się biały. Najważniejsza jest jednak funkcja obsługująca zdarzenie click wywoływane przez pola planszy. W przypadku kliknięcia pola najpierw sprawdzamy, czy nie została mu już przypisana klasa cross lub round. Jeżeli tak jest, to po prostu kończymy pracę, ponieważ gracz może wykonać ruch tylko na pustym polu. Jak już wspominałem, zmienna who określa, który gracz wykonuje właśnie ruch, a zmienna marker definiuje styl CSS nadawany wybranemu przez gracza polu. W kolejnym kroku sprawdzamy, który gracz wykonuje ruch, i przypisujemy wybranemu przez niego polu odpowiednią klasę. Po umieszczeniu w polu właściwego stylu CSS sprawdzamy, czy gracz zdołał wygrać tę potyczkę. Posługujemy się w tym celu funkcją checkForWin(). Jeżeli zwróci ona wartość true, to znaczy, że aktualny gracz wygrał i możemy odpiąć funkcje obsługi zdarzenia click od pól planszy. Oprócz tego nie możemy też zapomnieć o wyświetleniu wyniku i informacji o zakończeniu gry.
174
Rozdział 6. • Efekty specjalne w formularzach
Jeżeli jednak funkcja checkForWin() zwróci nam wartość false, to zmieniamy tylko aktywnego gracza przez odpowiednią modyfikację zmiennej player i wyświetlenie tej informacji na stronie. Funkcja checkForWin() szuka tylko trzech jednakowych klas CSS w jednej kolumnie, wierszu lub na przekątnej planszy. Wiersze i kolumny przeszukiwane są za pomocą prostych pętli for. Następnie przystępujemy do sprawdzania przekątnych i tutaj potrzebne są już dwie współpracujące pętle. Sama logika jest bardzo prosta. Jeżeli wszystkie elementy w wierszu, kolumnie lub na przekątnej mają tę samą klasę CSS, to aktualny gracz wygrywa. Funkcja zwraca zatem wartość true lub false. Definiujemy też dwie kolejne funkcje obsługi zdarzeń. Jedną dla listy rozwijanej, w której wywołujemy funkcję init(), zmieniając tym samym wielkość pola gry. Druga funkcja związana jest z przyciskiem Od nowa, który pojawia się na stronie po wygranej jednego z graczy. Proszę zauważyć, że przygotowany przez nas kod jest bardzo uogólniony. Przekazując liczbę funkcji init(), możemy przygotować sobie planszę o dowolnej wielkości.
I coś jeszcze Ćwiczenie: sprawdź, czy nie mamy remisu Gdy się chwilę zastanowić, stwierdzimy, że nasz przykład wyświetla przycisk Od nowa jedynie w przypadku wygranej jednego z graczy. Jeżeli jednak uzyskamy remis, to nie będziemy mieli możliwości ponownego rozpoczęcia gry. Rozwiązanie tego dylematu pozostawiam jako ćwiczenie dla Czytelnika. W ramach sprawdzania, czy nie mamy remisu, musimy tylko liczyć kliknięcia wykonane na planszy i porównać je z liczbą pól. Na przykład dla planszy o wymiarach 3×3 po dziewięciu kliknięciach nastąpi remis, chyba że wcześniej funkcja checkForWin() zwróci wartość true.
Informowanie użytkownika o przetwarzaniu żądania AJAX Ze względu na to, że aplikacje AJAX nie przeładowują całej strony, użytkownik może czuć się nieco zagubiony, w czasie gdy żądanie wysłane do serwera jest w trakcie przetwarzania.
175
PHP i jQuery. Receptury
Oznacza to, że użytkownik musi otrzymać jakąś informację, że nasza aplikacja nadal pracuje. Jest to bardzo ważny element, o którym nie można zapominać, tworząc nawet najprostsze aplikacje używające technologii AJAX. W tej recepturze dowiemy się, jak można poinformować użytkownika, że aktualnie przetwarzane jest żądanie AJAX.
Przygotowania W katalogu rozdzial6 utwórz nowy katalog o nazwie receptura2. Oprócz tego zajrzyj na stronę pod adresem http://ajaxload.info lub http://preloadres.net. Na tych stronach znajdziesz różne animowane obrazki oraz ikony z informacją o ładowaniu danych. Wybierz sobie jeden z tych obrazków i pobierz go, ponieważ będzie nam potrzebny przy tworzeniu tej receptury. Osobiście wykorzystałem poniższy obrazek pobrany ze strony http://ajaxload.info.
Jak to zrobić? 1. W katalogu receptura2 utwórz nowy plik i nazwij go index.html. 2. Przygotuj formularz, do którego użytkownik będzie mógł wprowadzić pewne informacje i wysłać je na serwer. Oprócz takiego formularza umieść na stronie znacznik img, którego atrybut src będzie wskazywał na wspomniany wcześniej obrazek. Na razie ukryj go jednak, wykorzystując odpowiedni styl CSS. Dodatkowo dopisz jeszcze pusty akapit, w którym będziemy wyświetlali odpowiedź przesłaną przez serwer. Informacja dla użytkownika
177
PHP i jQuery. Receptury
3. Teraz przygotujmy kod korzystający z biblioteki jQuery, który będzie zbierał informacje z pól formularza i wysyłał je do skryptu process.php działającego po stronie serwera. Po otrzymaniu odpowiedzi ukryjemy formularz i wyświetlimy tylko dane przesłane przez serwer. Ten sam kod będzie się też zajmował wyświetlaniem wskaźnika postępu, w czasie gdy skrypt PHP będzie pracował na serwerze.
4. W katalogu receptura2 utwórz kolejny plik i nadaj mu nazwę process.php. Kod z tego pliku odeśle po prostu informacje otrzymane od przeglądarki, ale wcześniej opakuje je w odpowiednio sformatowany tekst. Aby zasymulować opóźnienia na serwerze, tak żeby w przeglądarce odpowiednio długo wyświetlany był pasek postępu, wywołujemy funkcję sleep(), która zatrzyma działanie skryptu na pięć sekund. '; $str.= 'Nazwisko - '. $_POST['name']; $str.= ' '; $str.= 'Adres - '. $_POST['address']; $str.= ' ';
5. Możemy już wypróbować działanie naszego kodu. Uruchom w przeglądarce plik index.html, wypełnij formularz danymi i kliknij przycisk Zapisz. Na stronie pojawi się pasek postępu, który będzie widoczny przez pięć sekund, aż do otrzymania przez przeglądarkę odpowiedzi ze skryptu PHP. Gdy tylko odpowiedź zostanie odebrana, na stronie pojawią się wartości wpisane przez nas do formularza.
6. Poniższy obrazek prezentuje wygląd strony po otrzymaniu odpowiedzi od skryptu PHP.
179
PHP i jQuery. Receptury
Jak to działa? Do przycisku Zapisz przypięliśmy funkcję obsługi zdarzenia click, która jest uruchamiana przy każdym kliknięciu przycisku. Po uruchomieniu funkcja wyświetla obrazek o identyfikatorze loading, wywołując w tym celu funkcję biblioteki jQuery show(). Jednocześnie tekst na obrazku zmieniany jest na Proszę czekać…, a do pliku process.php wysyłane jest żądanie AJAX. Skrypt PHP po otrzymaniu wartości od przeglądarki najpierw czeka pięć sekund, a następnie podsyła do niej przygotowany tekst. W momencie otrzymania odpowiedzi od skryptu PHP biblioteka jQuery ukrywa pasek postępu oraz formularz, a tekst przesłany przez serwer wyświetla w specjalnym akapicie na stronie. W ten sposób użytkownik jest informowany, że system przetwarza wprowadzone informacje i należy poczekać na zakończenie tych prac.
I coś jeszcze Używanie tekstu zamiast obrazków Jeżeli nie chcesz używać obrazków jako sygnalizacji dla użytkownika, to możesz zamiast nich wprowadzić na stronę odpowiedni tekst.
Używanie nakładek, aby zablokować możliwość interakcji z formularzem W poprzednim przykładzie w czasie obsługi jednego żądania użytkownik może ponownie kliknąć przycisk Zapisz, a wtedy do serwera zostanie przesłane kolejne żądanie. Aby uniknąć takich sytuacji, możemy wyłączyć przycisk Zapisz albo utworzyć nakładkę (ang. overlay), która zakryje cały formularz do czasu otrzymania odpowiedzi z serwera. Będzie to bardzo dobitna informacja dla użytkownika, że w czasie przetwarzania wprowadzanych danych nie można korzystać z formularza.
Zobacz też Q Recepturę „Wysyłanie danych do PHP” z rozdziału 2.
180
Rozdział 6. • Efekty specjalne w formularzach
Tworzenie rozwijanych i zwijanych ramek (harmonijek) Harmonijki są dobrym przykładem gadżetu pozwalającego na wyświetlenie większej ilości informacji w ograniczonej przestrzeni w interaktywny i atrakcyjny sposób. W tej recepturze nauczymy się tworzyć proste harmonijki za pomocą biblioteki jQuery.
Przygotowania W katalogu rozdzial6 utwórz nowy katalog i nazwij go receptura3.
Jak to zrobić? 1. W katalogu receptura3 utwórz nowy plik o nazwie index.html. 2. W utworzonym pliku zdefiniuj kod HTML opisujący harmonijkę. Harmonijka składa się z elementów div zawierających treść, przy których znajdują się elementy h1 służące za nagłówek sekcji. Każdej sekcji nadaj jakiś tytuł i wpisz do niej dowolną treść. Oprócz tego w sekcji head strony zdefiniuj też style CSS nadające harmonijce ładny wygląd. Harmonijka
PHP: PHP Preprocessor Hipertekstu
PHP jest szeroko używanym, serwerowym
181
PHP i jQuery. Receptury
językiem skryptowym, który wykorzystywany jest do tworzenia dynamicznych aplikacji WWW. PHP jest bardzo popularnym językiem wśród programistów, dlatego wiele ważnych witryn powstało z wykorzystaniem tego języka.
jQuery - JavaScript typu pisz mniej, uzyskaj więcej
Za Wikipedią: lekka biblioteka programistyczna dla języka JavaScript, ułatwiająca korzystanie z JavaScript (w tym manipulację drzewem DOM) [...] Wszystkie efekty osiągnięte za pomocą jQuery można osiągnąć również bez jej użycia. Jednak kod okazuje się nieporównywalnie dłuższy i bardziej skomplikowany.
AJAX - Asynchronous JavaScript and XML
Ajax jest grupą technik tworzenia interaktywnych aplikacji dla sieci WWW działającą po stronie klienta (w przeglądarce). Technologii tej można użyć do asynchronicznego pobierania danych z serwera w tle. Obiekt XMLHttpRequest jest używany w przeglądarce do nawiązywania kontaktu z serwerem.
JSON - JavaScript Object Notation
JSON jest skrótem od JavaScript Object Notation, czyli notacji obiektów języka JavaScript. Opisuje on lekki i interaktywny format wymiany danych. Jest też określany jako odchudzona alternatywa dla języka XML. Jest to format tekstowy, niezależny od języka programowania, ale w języku JavaScript używany jest w sposób naturalny. Jest znacznie szybszy i mniej obciążający system niż XML. Głównym popularyzatorem tego formatu jest Douglas Crockford.
Ze względu na to, że format JSON jest naturalnym formatem danych języka JavaScript, może być łatwo używany w aplikacjach po stronie klienta. Znacznie łatwiej niż format XML.
182
Rozdział 6. • Efekty specjalne w formularzach
Przygotowaną stronę można podziwiać na poniższym rysunku.
3. Przed zamykającym znacznikiem body dołącz plik biblioteki jQuery i dopisz kod, który zmieni nasze znaczniki HTML w działającą harmonijkę.
4. Teraz nasza harmonijka jest już gotowa. Uruchom w przeglądarce plik index.html, a zobaczysz na stronie cztery sekcje harmonijki. Kliknięcie nagłówka sekcji spowoduje jego rozwinięcie i jednoczesne ukrycie pozostałych sekcji.
Jak to działa? Podany tu kod HTML składa się z głównego elementu div oraz znajdujących się w nim czterech kolejnych elementów div. Każdy z tych czterech elementów będzie jedną z sekcji harmonijki. Każda sekcja składa się natomiast z dwóch elementów: znacznika h1 oraz elementu div klasy container. Znacznik h1 służyć nam będzie jako nagłówek sekcji, a w elemencie div umieszczona zostanie treść tej sekcji. Style CSS sprawiają, że całość wygląda tak, jak pokazano na powyższym rysunku. W ten sposób uzyskujemy podstawową strukturę, którą zamienimy w harmonijkę za pomocą biblioteki jQuery. Teraz możemy już zająć się skryptem korzystającym z biblioteki jQuery. Na początek ukrywamy wszystkie elementy div klasy container, tak żeby widoczne były tylko nagłówki sekcji. Następnie dodajemy do nagłówka h1 funkcję obsługi zdarzenia click. Proszę
184
Rozdział 6. • Efekty specjalne w formularzach
zauważyć, że zdefiniowaliśmy tu styl CSS o nazwie active, który będzie przypisywany klikniętemu elementowi h1. Po kliknięciu nagłówka najpierw usuwamy klasę active ze wszystkich nagłówków harmonijki, a następnie przypisujemy ją klikniętemu elementowi h1, dzięki czemu tekst nagłówka zabarwia się na czerwono. Za pomocą selektora .container:visible wybieramy wszystkie widoczne aktualnie segmenty harmonijki i ukrywamy je, wywołując metodę slideUp(). Na zakończenie wybieramy jeszcze element div następujący po klikniętym elemencie h1 i wywołujemy na jego rzecz metodę toggleSlide(), tak żeby go pokazać lub ukryć. W ten sposób zrealizowaliśmy mechanizm harmonijki. Podsumowując, wykonaliśmy poniższe kroki: Q pobranie klikniętego elementu h1, Q usunięcie klasy active ze wszystkich elementów h1, Q dodanie klasy active do klikniętego elementu h1, Q ukrycie widocznych sekcji harmonijki, Q wyświetlenie elementu div klasy container znajdującego się za klikniętym elementem h1.
I coś jeszcze Używanie różnych znaczników w harmonijce Tworząc harmonijkę, nie musimy ściśle trzymać się z góry wyznaczonych znaczników. W naszym przykładzie zastosowaliśmy elementy h1 i div do oznaczania nagłówków i treści sekcji. Możemy jednak wykorzystać też listy wypunktowane, znaczniki łączy, a także dowolny inny znacznik i uzyskać dokładnie te same rezultaty. Trzeba tylko pamiętać o odpowiednim dopasowaniu kodu JavaScript oraz stylów CSS, ponieważ poszczególne znaczniki są inaczej wyświetlane przez przeglądarki. Jako ćwiczenie proponuję spróbować zaimplementować harmonijkę za pomocą znaczników ul i li.
Stopniowe ukrywanie elementu po jego zaktualizowaniu W nowoczesnych aplikacjach WWW, w których poszczególne elementy strony są aktualizowane bez przeładowywania całości, niezbędne jest poinformowanie użytkownika o zmianach, które zostały wprowadzone. Bez takich powiadomień użytkownik może nie zauważyć, że zawartość pewnej części strony się zmieniła.
185
PHP i jQuery. Receptury
Jednym z często stosowanych rozwiązań jest tutaj technika YFT, czyli Yellow Fade Technique (technika płowiejącej żółci). Ogólna idea jest tutaj bardzo prosta. W momencie wprowadzenia zmiany w danej części strony jej tło otrzymuje kolor żółty, który z czasem staje się coraz bledszy, aż w końcu tło wraca do koloru pierwotnego. W ten sposób zwracamy uwagę użytkownika na zaktualizowaną część strony. Mimo swojej prostoty technika ta doskonale się sprawdza w czasie tworzenia aplikacji AJAX. Podstawowa biblioteka jQuery nie udostępnia tego efektu, ale za to znajdziemy go w dodatkowej bibliotece jQuery UI. Chcąc wykorzystać ten efekt, musimy jednak dołączyć do naszej strony dodatkowe pliki effects.core.js oraz effects.highlight.js pochodzące z biblioteki jQuery UI. Z drugiej strony możemy też wykorzystać wtyczkę jQuery easing dostępną na stronie http://gsgd.co.uk/sandbox/jquery/easing/. W tej recepturze nauczymy się, jak stworzyć podobny efekt za pomocą zaledwie kilku wierszy kodu, bez konieczności dołączania dodatkowych plików.
Przygotowania W katalogu rozdzial6 utwórz nowy katalog o nazwie receptura4.
Jak to zrobić? 1. W katalogu receptura4 utwórz nowy plik o nazwie index.html. 2. Do utworzonego pliku wpisz kod HTML tworzący pole tekstowe i przycisk. Oprócz tego utwórz też element p, w którym prezentowany będzie efekt podświetlenia. Efekt specjalny
186
Rozdział 6. • Efekty specjalne w formularzach
3. Teraz dołącz plik biblioteki jQuery i napisz kod, który po kliknięciu przycisku pobierze wartość pola tekstowego i wpisze ją do elementu p. Następnie element ten powinien zostać wyróżniony za pomocą funkcji fade().
4. I to już wszystko. Możemy już podziwiać przygotowany przez siebie efekt. Uruchom plik index.html w przeglądarce i wpisz w polu tekstowym swoje imię. Teraz kliknij przycisk Pokaż, a poniżej pojawi się akapit z tekstem wpisanym do formularza. Początkowe żółte tło akapitu będzie powoli blakło, aż wróci do pierwotnej barwy.
187
PHP i jQuery. Receptury
Jak to działa? Idea jest taka: aby zmienić kolor elementu z żółtego na biały, musimy zacząć od nadania mu koloru żółtego, a następnie zmieniać wartości RGB tak, żeby powoli zmieniać ten kolor w biały. I tak właśnie tutaj postępujemy. Na początek wstawiamy w tło akapitu kolor RGB o wartości 255, 255, 100, a następnie zwiększamy tę ostatnią wartość o 10 aż do osiągnięcia koloru RGB 255, 255, 255, czyli białego. Aby rozłożyć proces modyfikowania koloru w czasie, wykorzystujemy funkcję języka JavaScript setInterval(), dzięki której zmiana koloru następuje do 100 milisekund. Najpierw deklarujemy zmienne base i interval. Następnie do zdarzenia click przycisku dołączamy funkcję YFT(), która pobiera wartość z pola tekstowego i wstawia ją do akapitu. Następnie wpisujemy do zmiennej base wartość 100 i wywołujemy funkcję setInterval(), która co 100 milisekund będzie wywoływać funkcję fade(). W ramach funkcji fade() sprawdzamy wartość, jaka aktualnie zapisana jest w zmiennej base. Jeżeli wartość ta przekroczy 255, to funkcja fade() nie będzie więcej wywoływana. Będzie to oznaczało, że kolor tła akapitu jest już biały. Jeżeli jednak wartość zmiennej base nadal jest mniejsza od 255, to modyfikujemy barwę akapitu zmienioną wartością RGB, przy czym składowe R i G nadal będą miały wartość 255, a wartość składowej B zostanie zwiększona o 10. Jak już wcześniej wspominałem, funkcja setInterval() będzie wywoływała funkcję fade(), aż wartość składowej B przekroczy 255.
Wyświetlanie pływającego okienka na żądanie Wyobraźmy sobie stronę, na której wypisana jest długa lista produktów, z której możemy wybrać kilka pozycji, a wtedy aktualizowana jest lista w osobnym kontenerze. Po dotarciu wreszcie do końca strony możemy już nie pamiętać, co właściwie wybraliśmy, a okienko z wybranymi pozycjami znajduje się przy górnej krawędzi strony. Czyż nie byłoby wspaniale, gdyby takie pomocnicze okienko przesuwało się tak, żeby było zawsze widoczne, niezależnie od tego, którą część strony aktualnie oglądamy? Innymi słowy, musimy przygotować pływające okienko, które będzie przemieszczało się wraz z przewijaniem widoku strony. W tej recepturze zajmiemy się zatem tworzeniem pływającego okienka, które automatycznie będzie przesuwało się w dół i w górę strony.
188
Rozdział 6. • Efekty specjalne w formularzach
Przygotowania W katalogu rozdzial6 utwórz nowy katalog i nazwij go receptura5.
Jak to zrobić? 1. W katalogu receptura5 utwórz nowy plik o nazwie index.html. 2. Chcąc zaprezentować pływający element div, musimy przygotować sobie naprawdę długą stronę. W tym celu tworzymy kilka elementów akapitu i każdemu z nich nadajemy wysokość 200 pikseli (używamy do tego stylów CSS). Następnie tworzymy element div, który zmienimy w pływające okienko, korzystając z funkcji biblioteki jQuery, i przypisujemy mu klasę CSS oraz identyfikator float. Definiując styl CSS dla tego elementu, nie możemy zapomnieć o przypisaniu właściwości position wartości absolute. To właśnie dzięki temu nasze okienko zostanie oderwane od pozostałych części strony. Pływające okienko
Bardzo ciekawy tekst
Bardzo ciekawy tekst
189
PHP i jQuery. Receptury
Bardzo ciekawy tekst
Bardzo ciekawy tekst
Bardzo ciekawy tekst
Bardzo ciekawy tekst
Bardzo ciekawy tekst
Bardzo ciekawy tekst
Pływające okienko
3. Mamy już przygotowany kod HTML strony, a zatem możemy przystąpić do zmiany elementu div w pływające okienko. Na początek musimy oczywiście dołączyć wspaniałą bibliotekę jQuery. Następnie skorzystamy z funkcji floatDiv(), która zmieni nasz element div w pływające okienko. Po zdefiniowaniu tej funkcji dodajemy funkcję obsługi do zdarzenia przewijania okna, która będzie wywoływana przy każdym przewinięciu strony w górę lub w dół. Na koniec wywołujemy funkcję floatDiv(), tak żeby zaraz po załadowaniu strony element div stał się pływającym okienkiem.
190
Rozdział 6. • Efekty specjalne w formularzach
4. Uruchom w przeglądarce plik index.html i przewiń stronę w dół i w górę za pomocą klawiatury lub myszy. Zobaczysz, że nasze pływające okienko cały czas znajduje się w prawym górnym rogu strony, niezależnie od tego, która jej część jest aktualnie wyświetlana.
Jak to działa? Za tworzenie pływającego okienka z elementu div odpowiadają dwie funkcje. Pierwsza z nich to funkcja $(document).scrollTop(), która zwraca nam liczbę całkowitą określającą liczbę pikseli do górnej krawędzi okna przeglądarki, do aktualnej pozycji paska przewijania. Druga funkcja to animate(), której używamy do tworzenia własnych animacji za pomocą biblioteki jQuery. Do obiektu okna przypięliśmy funkcję floatDiv(), która zajmie się obsługą zdarzenia scroll. Będzie ona wywoływana za każdym razem, gdy użytkownik przewinie stronę za pomocą myszy lub klawiatury. Wewnątrz funkcji floatDiv() pobieramy z obiektu dokumentu wartość scrollTop, dodajemy ją do zmiennej defaultOffset i zapisujemy wynik do zmiennej offsetTop. W zmiennej defaultOffset zapisaliśmy wcześniej wartość 50, co oznacza, że pływające okienko zawsze będzie miało odstęp 50 pikseli od górnej krawędzi okna przeglądarki. Do zdefiniowania wartości pozycji górnej krawędzi elementu div wykorzystujemy funkcję animate(). Proszę zauważyć, że funkcji podajemy też opcję duration z wartością 500, przez co cała animacja będzie trwała dokładnie 500 milisekund. Drugą opcją jest queue z przypisaną wartością false, dzięki czemu biblioteka jQuery nie będzie czekać na zakończenie poprzedniej animacji, aby rozpocząć nową.
191
PHP i jQuery. Receptury
Na koniec zaraz po załadowaniu dokumentu DOM wywołujemy jeszcze funkcję floatDiv(). Jest to konieczne, jeżeli chcemy, żeby nasze okienko było pływające już od momentu załadowania strony. Całość można wypróbować, przewijając stronę w górę i w dół, a następnie naciskając klawisz F5. Przygotowane przez nas okienko będzie zawsze zajmowało to samo miejsce na stronie, niezależnie od jej aktualnej pozycji.
I coś jeszcze Ważna informacja o funkcji animate() Za pomocą funkcji animate() można tworzyć animacje innych właściwości przyjmujących wartości liczbowe. Właściwości nieliczbowych, takich jak color lub background-color, nie można animować w ten sposób. Na przykład proszę spojrzeć na poniższy kod: $('#float').animate({backgroundColor: "#ffffcc"},{duration:500,queue:false});
Jest to właśnie przykład niewłaściwego wykorzystania funkcji animate(). Z drugiej jednak strony poniższy przykład będzie działał doskonale: $('#float').animate({width: 500},{duration:500,queue:false});
Aktualizowanie pozycji w koszyku na zakupy Spróbujemy tutaj przygotować prostą stronę z listą produktów uzupełnioną o informacje o cenie i liczbie wybranych sztuk. Użytkownik będzie mógł tutaj wybrać dowolną liczbę produktów i ta informacja zostanie przesłana do serwera. Skrypt działający na serwerze będzie wyliczał cenę zamówienia i wyświetlał ją od razu na stronie. Jest to działanie podobne do koszyka na zakupy dostępnego na wielu stronach WWW. Różnica polega na tym, że nie będziemy tutaj mieli przeładowywania strony, dzięki czemu użytkownik nie będzie musiał tak długo czekać na dane. Ta receptura będzie tylko prostym przykładem, który można dowolnie rozbudowywać, tak żeby dopasować go do własnych wymagań.
Przygotowania W katalogu rozdzial6 utwórz nowy katalog i nazwij go receptura6. Następnie w tym samym katalogu utwórz plik XML, w którym zapiszemy listę książek. Każda z nich będzie miała identyfikator, tytuł oraz cenę. Z tego pliku będziemy korzystać przy wyświetlaniu na stronie listy książek dostępnych dla użytkownika. Utworzony plik nazwij books.xml. 192
Rozdział 6. • Efekty specjalne w formularzach
Książka o PHP35Książka o jQuery35Książka o API Twittera35Podstawy Facebooka35
Jak to zrobić? 1. W katalogu receptura6 utwórz plik o nazwie index.php. Kod z tego pliku będzie zapisywał pustą tablicę w sesji, którą wykorzystamy jako koszyk przechowujący informacje o wybranych książkach. Następnie zdefiniuj element div, który posłuży nam za koszyk. W kolejnym kroku wypisz listę książek wraz z ich cenami, odczytując dane z pliku XML za pomocą funkcji simplexml. Dla każdej książki wypisz jej tytuł, cenę, listę rozwijaną pozwalającą na wybranie liczby sztuk oraz przycisk do zapisania dokonanego wyboru. Oprócz tego przy każdej książce będziemy też potrzebować ukrytego pola, w którym zapisany będzie jej identyfikator. Koszyk sklepowy
2. Teraz dołącz plik biblioteki jQuery i zapisz funkcję obsługującą kliknięcia przycisków Wybierz tę książkę. Kliknięcie takiego przycisku będzie wysyłało żądanie AJAX skierowane do pliku PHP o nazwie calculate.php. Żądanie to będzie przenosiło identyfikator wybranej książki oraz liczbę sztuk. W momencie odebrania odpowiedzi od skryptu PHP wstawimy ją do elementu o identyfikatorze cart.
3. Przejdźmy teraz na stronę serwera. Utwórz zatem nowy plik i nazwij go calculate.php. To właśnie tutaj obsługiwane będą żądania AJAX. Najpierw sprawdzamy, czy wybrana książka jest już zapisana w sesji. Jeżeli tak nie jest, to zapisujemy w sesji identyfikator 195
PHP i jQuery. Receptury
książki oraz liczbę sztuk wybranych przez użytkownika, a w przeciwnym wypadku aktualizujemy jedynie informację o liczbie sztuk. W ostatnim kroku tworzymy kod HTML z informacją o stanie koszyka. Wypisujemy tu wszystkie wybrane książki, liczbę sztuk, cenę, a na koniec podajemy jeszcze ogólną wartość książek. 0) { for($i=0; $i< count($booksInfo); $i++) { if($booksInfo[$i]['bookId'] == $_POST['bookId']) { $booksInfo[$i]['quantity'] = $_POST['quantity']; $bookFound = true; break; } } } if(!$bookFound) { $book = array('bookId' => $_POST['bookId'], 'quantity' => $_POST['quantity']); array_push($booksInfo, $book); } $_SESSION['cart'] = $booksInfo; $grossTotal = 0; $str=''; for($i=0; $i< count($booksInfo); $i++) { $aBook = $booksInfo[$i]; $bookName = getBookName($booksInfo[$i]['bookId']); $bookPrice = getPriceForBook($booksInfo[$i]['bookId']); $totalPrice = $bookPrice * $booksInfo[$i]['quantity']; $grossTotal+= $totalPrice; $str.= 'Tytuł - '.$bookName; $str.= ' '; $str.= ' Egzemplarzy - '.$booksInfo[$i]['quantity']; $str.= ' '; $str.= 'Cena - '.$bookPrice. ' PLN * ' .$booksInfo[$i]['quantity'].' = '.$totalPrice.' PLN'; $str.= '
'; } $str.= 'Suma zamówienia - '.$grossTotal.' PLN'; echo $str; function getBookName($id) { $objXML = simplexml_load_file('books.xml'); foreach($objXML->book as $book)
4. I wszystko gotowe! Możemy już sprawdzić, jak działa nasz przykład. Uruchom w przeglądarce plik index.php. Zobaczysz listę dostępnych książek, a po prawej stronie okienko koszyka. Wybierz liczbę sztuk dowolnej książki i kliknij przycisk Wybierz tę książkę. Dane w okienku koszyka zostaną zaktualizowane. Spróbuj teraz wybrać wiele książek i zmieniać im liczbę sztuk. Koszyk powinien zawsze odzwierciedlać wszystkie dokonane przez nas wybory.
197
PHP i jQuery. Receptury
Jak to działa? Kod PHP w pliku index.php jest względnie prosty. Tworzymy w nim pustą tablicę $booksInfo i zapisujemy ją w sesji. To właśnie w tej tablicy będziemy przechowywać wybory dokonane przez użytkownika. Następnie za pomocą funkcji simplexml_load_file() ładujemy plik books.xml. Iterując po elementach book, tworzymy kod HTML, który wyświetla na stronie listę książek dostępnych w sklepie. Obok danych poszczególnych książek tworzymy też ukryte zmienne przechowujące ich identyfikatory, których będziemy potrzebować podczas przesyłania danych do serwera. Przyjrzyjmy się teraz kodowi korzystającemu z biblioteki jQuery. Po kliknięciu przycisku Wybierz tę książkę pobieramy wartość wybranej książki oraz jej ukryty identyfikator, wykorzystując do tego selektory jQuery. Zebrane dane wysyłamy następnie do pliku PHP o nazwie calculate.php za pośrednictwem żądania AJAX. Funkcja wywoływana po otrzymaniu odpowiedzi na to żądanie wstawia tylko przesłany tekst do elementu o identyfikatorze cart. Prawdziwe czary dzieją się jednak po stronie serwera, w pliku calculate.php. Na początek przyjrzyjmy się strukturze tablicy $booksInfo. Przechowujemy w niej identyfikatory książek wybranych przez użytkownika razem z informacją o liczbie sztuk. Sama tablica ma następującą strukturę: Array ( [0] => Array ( [bookId] => 1 [quantity] => 1 ) [1] => Array ( [bookId] => 3 [quantity] => 2 ) )
Kod w pliku calculate.php zaczyna się od wywołania funkcji session_start(), która inicjuje aktualną sesję w języku PHP. Następnie z uzyskanej sesji wydobywamy tablicę $booksInfo. Teraz sprawdzamy, czy wybrana przez użytkownika książka (jej identyfikator pobrany ze zmiennej $_POST['bookId']) jest już zapisana w tej tablicy. Jeżeli znajdziemy w niej identyfikator, to aktualizujemy tylko liczbę sztuk wartością otrzymaną w żądaniu AJAX ($_POST['quantity']). Jeżeli jednak książki jeszcze nie ma w tablicy $booksInfo, to tworzymy dla niej nową tablicę z danymi książki i wstawiamy jako kolejny element tablicy $booksInfo. W kolejnym kroku zapisujemy tablicę $booksInfo do aktualnej sesji.
198
Rozdział 6. • Efekty specjalne w formularzach
Teraz przystępujemy do obliczania ceny wszystkich książek wybranych przez użytkownika. W tym celu iterujemy po tablicy $booksInfo i pobieramy tytuł oraz cenę poszczególnych książek. Do pobierania tytułu książki przygotowaliśmy sobie specjalną funkcję o nazwie getBookName(), która przyjmuje w parametrze identyfikator książki i szuka go w pliku books.xml. Po znalezieniu właściwego węzła w strukturze XML funkcja zwraca ciąg znaków z tytułem książki. Podobnie działa funkcja getPriceForBook(), ale zwraca jednostkową cenę wybranej książki. Po uzyskaniu tych dwóch wartości tworzymy kod HTML wyświetlający tytuł każdej książki wraz z jej ceną. Na zakończenie podajemy jeszcze sumę zamówienia. Po obsłużeniu wszystkich książek zamówionych przez użytkownika odsyłamy przygotowany kod HTML do przeglądarki. Biblioteka jQuery po otrzymaniu odpowiedzi na wysłane wcześniej żądanie wstawia tekst do elementu o identyfikatorze cart. W tej recepturze stosujemy bardzo ważne rozwiązanie. Moglibyśmy przecież wykonywać wszystkie obliczenia po stronie klienta, używając do tego biblioteki jQuery, więc po co przesyłać na serwer dane każdego wyboru dokonanego przez użytkownika? Chodzi o to, że obliczenia wykonywane po stronie klienta można dowolnie zmanipulować, wprowadzając zmiany za pomocą takich narzędzi, jak Firebug. To dlatego całość obliczeń prowadziliśmy po stronie serwera, a w przeglądarce wyświetlaliśmy tylko ich wyniki. W takiej sytuacji użytkownik nie może wpływać na wykonywane kalkulacje, a serwer raczej nie powinien pomylić się podczas dodawania.
I coś jeszcze Usuwanie pozycji z koszyka Można jeszcze zmodyfikować naszą recepturę tak, żeby oprócz dodawania pozwalała ona również na usuwanie pozycji z koszyka. Wystarczy w tym celu umieścić łącze przy każdym z elementów znajdujących się w koszyku. Kliknięcie tego łącza uruchomi żądanie AJAX, które prześle identyfikator książki na serwer. Skrypt PHP będzie mógł wtedy wyszukać otrzymany identyfikator w aktualnej sesji i usunąć odpowiadającą mu pozycję w tablicy $booksInfo.
Zobacz też Q Recepturę „Ładowanie danych XML z plików oraz ciągów znaków za pomocą
SimpleXML” z rozdziału 3. Q Recepturę „Korzystanie z elementów i atrybutów za pomocą SimpleXML” z rozdziału 3.
199
PHP i jQuery. Receptury
200
7 Tworzenie menu nawigacyjnych W tym rozdziale zajmiemy się: Q tworzeniem prostych menu rozwijanych, Q tworzeniem menu zmieniających kolor tła po wskazaniu myszą, Q tworzeniem menu harmonijkowego, Q tworzeniem menu pływającego, Q tworzeniem interfejsu do nawigacji w kartach, Q dodawaniem nowych kart, Q tworzeniem kreatora za pomocą kart.
Wprowadzenie Menu stanowią podstawę każdej witryny WWW. Spróbujmy sobie wyobrazić stronę bez menu. Nawigacja na niej byłaby praktycznie niemożliwa. Witryna wyposażona w dobre łącza nawigacyjne staje się natomiast bardzo przyjazna dla użytkowników. Oznacza to, że dobre menu nawigacyjne są kluczem do zadowolenia użytkownika. W tym rozdziale przyjrzymy się kilku technikom pozwalającym nam na tworzenie różnego rodzaju menu. Zaczniemy od najprostszych menu rozwijanych, a potem przejdziemy do menu harmonijkowych oraz pływających.
PHP i jQuery. Receptury
Na zakończenie przygotujemy mechanizm nawigacji w kartach i zbadamy kilka metod implementacji kart.
Tworzenie prostych menu rozwijanych W tej recepturze przygotujemy proste menu rozwijane składające się z trzech pozycji. Umieszczenie wskaźnika myszy nad jedną z nich spowoduje wyświetlenie podmenu, a przesunięcie wskaźnika poza pozycję menu spowoduje ukrycie wyświetlonego wcześniej podmenu.
Przygotowania W katalogu rozdzial7 utwórz nowy katalog o nazwie receptura1. W nowym katalogu utwórz plik i nazwij go index.html.
Jak to zrobić? Zaczniemy od tworzenia struktury menu oraz dopasowanych do niego stylów CSS. Samo menu zostanie zbudowane z listy wypunktowanej, w której każda pozycja stanie się nagłówkiem menu. W elemencie listy umieścimy znacznik a, a w nim tekst pozycji menu. Obok znajdzie się kolejna lista wypunktowana, której elementy posłużą nam za pozycje podmenu. Każdy z tych elementów będzie zawierał łącze pozwalające na nawigowanie po stronie. 1. Podczas pisania kodu HTML musimy pamiętać też o tym, że całe menu musi być dostępne na stronie nawet wtedy, gdy wyłączymy obsługę języka JavaScript w przeglądarce. Poniższy kod definiuje omawianą przed momentem stronę: Menu jQuery
2. Teraz utwórz plik o nazwie style.css, który dołączaliśmy już do pliku index.html, i wpisz do niego poniższe style CSS. body { font-family:"Trebuchet MS",verdana; } ul { list-style:none; margin:0; padding:0; } li.menuHeader { border:1px solid #fff; float:left; padding:5px 10px; text-align:center; width:120px; } ul.menuItem { margin-top:5px; } .menuItem > li { padding:5px 10px;
Zaprezentowany poniżej rysunek przedstawia aktualny wygląd naszej strony.
3. Przez zamykającym znacznikiem body dołącz plik biblioteki jQuery. Teraz ukryjemy elementy podmenu i przygotujemy funkcję obsługi zdarzenia, która zajmie się wyświetlaniem i ukrywaniem podmenu zależnie od pozycji wskaźnika myszy.
4. Zapisz plik i otwórz go w przeglądarce. Zobaczysz nagłówki trzech menu rozwijanych. Wskaż myszą dowolny z nich, a pojawi się powiązane z tym nagłówkiem podmenu. Przesunięcie wskaźnika myszy poza nagłówek spowoduje ponownie ukrycie podmenu.
204
Rozdział 7. • Tworzenie menu nawigacyjnych
Jak to działa? Zaczynamy od przygotowania kodu HTML tworzącego strukturę menu. Zastosowaliśmy tu listę wypunktowaną, która przechowuje wszystkie pozycje menu i podmenu. Każda pozycja menu ma przypisaną klasę menuHeader. W każdym z tych elementów znajduje się znacznik a przechowujący tekst pozycji. W rzeczywistych zastosowaniach przypiszemy jeszcze faktyczną wartość do atrybutu href, tak żeby pozycja menu odsyłała użytkownika do konkretnej strony. Zaraz za łączem umieszczamy kolejną listę wypunktowaną, w której umieścimy pozycje tego menu rozwijanego. W liście tej może znaleźć się wiele pozycji, a każda z nich musi być wyposażona w łącze nawigacyjne. Po załadowaniu dokumentu DOM biblioteka jQuery ukrywa wszystkie elementy klasy menuItem. Jak już wcześniej wyjaśniałem, elementy te reprezentują pozycje menu, które powinny zostać ukryte zaraz po załadowaniu strony. Oznacza to, że początkowo widoczne będą jedynie nagłówki menu. Następnie za pomocą funkcji hover() włączamy animację menu. Jak dowiedzieliśmy się we wcześniejszych recepturach, funkcja hover() przyjmuje w parametrach dwie funkcje, które wykonywane są, w momencie gdy wskaźnik myszy znajdzie się nad elementem i gdy wskaźnik zostanie przesunięty poza ten element. W pierwszej funkcji wybieramy element ul znajdujący się w bieżącej pozycji listy i wywołujemy na jego rzecz metodę slideDown(), która wyświetla menu rozwijane. Podobnie druga funkcja wywołuje tylko metodę slideUp() ukrywającą menu po przesunięciu myszy.
I coś jeszcze Otwieranie menu kliknięciem Możemy też przygotować menu, które będzie się otwierało dopiero po kliknięciu. Poniższy kod otworzy menu rozwijane i jednocześnie ukryje wszystkie aktualnie otwarte inne menu.
Zobacz też Q Recepturę „Tworzenie menu zmieniającego kolor tła po wskazaniu myszą”. Q Recepturę „Tworzenie menu harmonijkowego”.
Tworzenie menu zmieniającego kolor tła po wskazaniu myszą W tej recepturze nauczymy się tworzyć menu podświetlające pozycję wskazywaną przez mysz. Pozostałe pozycje zostaną przyciemnione, tak że na pierwszy plan wybijać się będzie pozycja wskazana myszą.
Przygotowania W katalogu rozdzial7 utwórz nowy katalog o nazwie receptura2. Oprócz tego w nowym katalogu utwórz też plik o nazwie index.html. Przygotuj trzy obrazki, które wykorzystamy jako tło dla naszych menu. Każdy z tych obrazków powinien mieć wielkość 120×41 pikseli.
206
Rozdział 7. • Tworzenie menu nawigacyjnych
Jak to zrobić? 1. Na początek przygotuj strukturę HTML tworzącą menu. Wpisz kod listy wypunktowanej z trzema elementami. Każdemu z elementów przypisz klasę menuHeader, z której później będzie korzystać biblioteka jQuery. Kolejna nazwa klasy będzie służyła nam do dodawania obrazka tła. W każdym elemencie li umieść łącze i wpisz do atrybutu href adres strony docelowej. Menu jQuery
2. Teraz utwórz nowy plik o nazwie style.css, w którym zdefiniuj podane niżej style: body{ font-family:"Trebuchet MS",verdana; } ul { list-style:none; margin:0; padding:0; } li.menuHeader { border:1px solid #fff; cursor:pointer; float:left; padding:5px 10px; text-align:center;
3. Dołącz plik biblioteki jQuery. Następnie ustal przezroczystość wszystkich pozycji menu na 0.5, tak żeby po załadowaniu strony wyglądały na przyciemnione. Do każdego nagłówka menu podłącz funkcję obsługującą zdarzenie hover, która będzie podświetlała pozycję wskazaną myszą przez użytkownika. Gdy tylko wskaźnik myszy zostanie usunięty znad nagłówka menu, powinniśmy przywrócić jego początkowy stan.
4. Uruchom w przeglądarce plik index.html, a zobaczysz trzy wyblakłe pozycje menu. Wskaż jedną z nich myszą, a zostanie ona powoli podświetlona. Dodatkowo tekst tej pozycji staje się pogrubiony i pisany wielkimi literami. Na poniższym rysunku zobaczyć można wygląd menu z jedną pozycją wskazaną myszą.
208
Rozdział 7. • Tworzenie menu nawigacyjnych
Jak to działa? Na początek ustalamy przezroczystość wszystkich pozycji menu na wartość 0.5 za pomocą wyrażenia $("li.menuHeader").css("opacity", "0.5"). W ten sposób pozycje te będą wyglądały na przyciemnione. Ponownie będziemy tu wykorzystywać funkcję hover(), która wywoływana jest w momencie umieszczenia wskaźnika myszy nad elementem strony. Pierwsza przekazana jej funkcja (obsługuje zdarzenie wskazania pozycji menu) wywołuje funkcję animate(), aby powoli zmienić wartość przezroczystości elementu na 1. W drugim parametrze funkcji animate() podaliśmy wartość slow, a w trzecim funkcję wywoływaną po zakończeniu animacji. Funkcja ta wyszukuje pierwszy podelement aktualnej pozycji menu, nadaje jej właściwości CSS font-weight oraz text-transform, przez co tekst pozycji staje się pogrubiony i pisany wielkimi literami.
Zobacz też Q Recepturę „Tworzenie prostych menu rozwijanych”. Q Recepturę „Tworzenie menu harmonijkowego”.
Tworzenie menu harmonijkowego Harmonijek można też użyć jako menu. W końcu zawartość każdej sekcji harmonijki może być wykorzystana w dowolny sposób. W tej recepturze zajmiemy się tworzeniem prostej harmonijki, której użyjemy jako menu naszej strony. Nagłówki będą rozwijały sekcje z treścią, a w niej znajdzie się troszkę tekstu oraz łącze Czytaj więcej. Kliknięcie tego łącza spowoduje przesłanie żądania do pliku PHP, który odeśle tekst do wyświetlenia na stronie.
209
PHP i jQuery. Receptury
Takie rozwiązanie może przydawać się w sytuacji, gdy początkowo chcemy wyświetlić tylko podsumowanie (na przykład danych produktu), a pełną informację podawać tylko na żądanie. Jeżeli użytkownik zostanie zainteresowany tekstem podsumowania, to będzie mógł kliknąć łącze i przeczytać pozostałe informacje. W ten sposób zaoszczędzimy wiele miejsca na stronie, które można wykorzystać w inny sposób.
Przygotowania W katalogu rozdzial7 utwórz nowy katalog o nazwie receptura3.
Jak to zrobić? 1. W katalogu receptura3 utwórz nowy plik o nazwie index.html. Wpisz do niego kod HTML tworzący stronę z trzema sekcjami. Na górze znajdzie się nagłówek z nazwą strony. Poniżej strona zostanie podzielona na dwie części, które nazwiemy lewym i prawym panelem. W lewym panelu umieścimy kod tworzący harmonijkę. Znaczników h1 użyjemy tu jako nagłówków, a pod nimi umieszczać będziemy znaczniki div klasy containter, w których umieścimy treść oraz łącze pozwalające na pobranie z serwera danych odpowiednich dla danej sekcji harmonijki. W prawym panelu umieścimy tekst przesłany z serwera. W sekcji head kodu strony można też umieść kilka stylów CSS definiujących wygląd całej strony. Menu harmonijkowe
210
Rozdział 7. • Tworzenie menu nawigacyjnych
Moja wspaniała strona
PHP
PHP jest szeroko używanym, serwerowym językiem skryptowym... Czytaj więcej
jQuery
Za Wikipedią: lekka biblioteka programistyczna dla języka JavaScript... Czytaj więcej
AJAX
Ajax jest grupą technik tworzenia interaktywnych aplikacji dla sieci WWW... Czytaj więcej
JSON
JSON jest skrótem od JavaScript Object Notation, czyli notacji obiektów języka JavaScript... Czytaj więcej
Z lewego menu wybierz hasło, o którym chcesz uzyskać więcej informacji.
211
PHP i jQuery. Receptury
Tak przygotowana strona powinna wyglądać podobnie do poniższego rysunku:
2. Strona z poprzedniego rysunku nie korzysta jeszcze ze skryptów JavaScript i biblioteki jQuery. Dołącz zatem plik biblioteki jQuery, nie zapominając o podaniu właściwej ścieżki. Musimy teraz zrobić dwie rzeczy. Po pierwsze przygotować kod dla lewego panelu, który zmieni go w harmonijkę, a po drugie obsłużyć kliknięcia łącza Czytaj więcej, czyli pobierać odpowiednie dane z serwera. W tym celu musimy napisać dwie funkcje obsługi zdarzeń. Pierwsza z nich będzie wywoływana przy kliknięciu nagłówków harmonijki, a druga przy kliknięciu łącza Czytaj więcej. W tym drugim przypadku wywoływana będzie funkcja getData(), która wyśle żądanie do serwerowego skryptu data.php. Poprzez bibliotekę jQuery wyślemy też informację o tym, które z łączy zostało kliknięte.
3. Aby obsłużyć żądania AJAX przesyłane przez naszą stronę, utwórz w tym samym katalogu plik o nazwie data.php. W tym pliku umieścimy kod, który będzie odsyłał tekst odpowiedzi zależny od wartości otrzymanej w ramach żądania GET.
213
PHP i jQuery. Receptury
echo 'JSON jest skrótem od JavaScript Object Notation, czyli notacji obiektów języka JavaScript. i Opisuje on lekk i interaktywny format wymiany danych. Jest też określany jako odchudzona alternatywa dla języka XML. Jest to format tekstowy, niezależny od języka programowania, ale w języku JavaScript używany jest w sposób naturalny. Jest znacznie szybszy i mniej obciążający system niż XML. Głównym popularyzatorem tego formatu jest Douglas Crockford.'; break; } ?>
4. Po zakończeniu tych prac uruchom w przeglądarce plik index.html i kliknij jeden z nagłówków harmonijki. Zostanie ona rozwinięta, a wszystkie pozostałe sekcje zostaną ukryte. W lewym panelu zobaczysz wtedy krótkie podsumowanie oraz łącze. Kliknij je, a biblioteka jQuery załaduje odpowiednie dane z pliku data.php. Jeżeli klikniesz łącze Czytaj więcej w sekcji AJAX, to w prawym panelu powinien pojawić się tekst pokazany na poniższym rysunku.
Jak to działa? Elementy div, którym przypisano klasę container, reprezentują części harmonijki, w których przechowywane są dane. Po załadowaniu dokumentu ukrywamy te części strony za pomocą wyrażenia $('container').hide(), dzięki czemu widoczne są tylko nagłówki harmonijki. W kolejnym kroku wszystkim elementom h1 harmonijki przypisujemy funkcję obsługującą zdarzenie
214
Rozdział 7. • Tworzenie menu nawigacyjnych
click. Kliknięcie nagłówka h1 powoduje usunięcie najpierw klasy active ze wszystkich nagłów-
ków harmonijki. Potem ukrywane są wszystkie widoczne aktualnie sekcje, a następnie dodajemy klasę active do klikniętego nagłówka i rozwijamy następujący po nim element div. W ten sposób na stronie pojawia się podsumowanie zagadnienia wybranego przez użytkownika, a nasze zadanie związane z obsługą lewego panelu jest ukończone. Teraz musimy jeszcze aktywować łącza Czytaj więcej. W związku z tym dodajemy funkcję nasłuchującą zdarzeń pochodzących z elementu div klasy container. Proszę zauważyć, że atrybut href każdego łącza ma w tekście zapytania zapisany parametr page, którego wartość jest różna w każdej sekcji harmonijki. Kliknięcie łącza wywołuje funkcję getData(), która pobiera wartość atrybutu href z klikniętego łącza, a następnie wysyła na ten adres żądanie AJAX za pośrednictwem metody get(). Żądanie to jest odbierane przez serwerowy skrypt data.php, który analizuje otrzymaną zmienną page (pobiera ją z tablicy $_GET). Na podstawie tej wartości instrukcja switch wybiera tekst, który
ma zostać odesłany do klienta. W przeglądarce biblioteka jQuery po otrzymaniu odpowiedzi umieszcza tekst w prawym panelu, czyli w elemencie div i identyfikatorze rightPanel. Nie można zapomnieć o tym, żeby w funkcji getData() zwrócić wartość false. W przeciwnym wypadku przeglądarka otworzy po prostu stronę wskazywaną przez łącze Czytaj więcej.
I coś jeszcze Harmonijka biblioteki jQuery UI Więcej funkcji i szersze możliwości harmonijki można uzyskać, stosując implementację z biblioteki jQuery UI. Jest ona dostępna na stronie biblioteki pod adresem http://jqueryui.com/demos/ accordion/.
Zobacz też Q Recepturę „Tworzenie rozwijanych i zwijanych ramek (harmonijek)” z rozdziału 6. Q Recepturę „Pobieranie danych z PHP za pomocą jQuery” z rozdziału 2.
215
PHP i jQuery. Receptury
Tworzenie menu pływającego W poprzednim rozdziale „Efekty specjalne w formularzach” nauczyliśmy się tworzyć pływające okienko, które zmienia swoją pozycję podczas przewijania strony w górę i w dół, tak żeby zawsze znajdować się w widocznej części. Z tego efektu możemy też skorzystać do tworzenia menu, które będzie ułatwiało użytkownikom pracę na długich stronach. Zazwyczaj, gdy użytkownik przewinie stronę za daleko w dół, będzie musiał przewinąć ją na samą górę, żeby dostać się do menu. Możemy zatem umieścić menu wewnątrz pływającego okienka, tak żeby było ono dostępne dla użytkownika niezależnie od tego, w której części strony się on znajduje. W tej recepturze wyjaśnię metody tworzenia takiego menu. Kliknięcie pozycji menu spowoduje wyświetlenie związanego z nim podmenu. Takie menu będą mogły mieć kilka poziomów zagnieżdżania.
Przygotowania W katalogu rozdzial7 utwórz nowy katalog i nazwij go receptura4.
Jak to zrobić? 1. W katalogu receptura4 utwórz nowy plik o nazwie index.html. 2. Menu będziemy tu tworzyć w taki sposób, żeby możliwe było zdefiniowanie dowolnej liczby zagnieżdżonych podmenu bez konieczności wprowadzania zmian w kodzie JavaScript. Z tego powodu kod HTML musi być przygotowany tak, żeby mechanizmy biblioteki jQuery mogły być stosowane na dowolnym poziomie podmenu. 3. W pierwszej kolejności utwórz na stronie długi akapit, tak żebyśmy mogli podziwiać efekt pływającego menu. Następnie utwórz element div, który stanie się naszym pływającym okienkiem. W elemencie tym znajdzie się też kod tworzący strukturę menu. Do tego celu wykorzystamy listę wypunktowaną, której elementy będą pozycjami menu. W każdym elemencie listy znajdzie się element span, a za nim kolejna lista wypunktowana, która będzie spełniać rolę podmenu. Wszystkie elementy span otrzymają klasę CSS menu, a wszystkie listy wypunktowane tworzące podmenu otrzymają klasę menuItem. Na zakończenie w elementach ostatniej listy w hierarchii można umieścić łącza kierujące nas do innych stron. Taką strukturę można zagnieżdżać dowolną liczbę razy. W naszym przykładzie przygotujemy menu o głębokości trzech poziomów. Style CSS niezbędne do odpowiedniego zaprezentowania wszystkich elementów menu zostaną umieszczone w sekcji head.
Ten akapit ma wysokość 1000 pikseli i tworzy naprawdę długą stronę
218
Rozdział 7. • Tworzenie menu nawigacyjnych
Wyniki naszej pracy możemy podziwiać na poniższym rysunku.
4. Na razie nie ukryliśmy żadnych podmenu, dlatego takie rozwiązanie będzie działało dobrze nawet przy wyłączonej obsłudze języka JavaScript. Dodajmy teraz trochę magii biblioteki jQuery, aby nieco ożywić naszą stronę. Przed zamykającym znacznikiem body dołącz plik biblioteki. W pierwszym kroku dodaj metodę nasłuchującą zdarzeń przewijania okna. Będzie ona pozycjonowała okienko pływające w zależności od aktualnej pozycji strony. Następnie ukryj wszystkie podmenu i dodaj funkcję obsługującą zdarzenie click do elementów klasy menuItem.
5. I to już wszystko! Zapisz kod i uruchom plik index.html w przeglądarce. Zobaczysz długą stronę, którą można przewijać za pomocą suwaka. Po prawej stronie widoczne będzie okienko zawierające dwie pozycje menu. Za pomocą myszy lub klawiatury przewiń stronę w górę i w dół, a okienko z menu powinno przesuwać się razem ze stroną. Kliknij teraz dowolną z pozycji menu, a zostaną one rozwinięte, ukazując podmenu. Spróbuj otworzyć drugą pozycję: Pozycja menu2. Ukrywa się pod nią system trójpoziomowego menu. Na poniższym rysunku widoczne jest to właśnie menu z rozwiniętymi wszystkimi trzema poziomami.
Jak to działa? Zaczniemy od pływającego okienka. Funkcja floatDiv() wywoływana jest zaraz po załadowaniu strony albo po przewinięciu jej przez użytkownika. Funkcja pobiera pozycję suwaka liczoną od górnej krawędzi strony, wywołując metodę biblioteki jQuery $(document).scrollTop(), a następnie wywołuje metodę animate() i z jej pomocą, przez 250 milisekund, ustala wartość właściwości top naszego pływającego okienka. Funkcja ta wywoływana jest też po załadowaniu strony, tak żeby od samego początku ustalić właściwą pozycję okienka.
220
Rozdział 7. • Tworzenie menu nawigacyjnych
Po zakończeniu pracy funkcji floatDiv() pobieramy wszystkie elementy klasy menuItem i ukrywamy je. Nie zrobiliśmy tego w stylach CSS, ponieważ w przypadku wyłączenia obsługi języka JavaScript w przeglądarce użytkownik nie miałby możliwości skorzystania z wszystkich elementów menu. Wtedy nawigacja po stronie stałaby się koszmarem. Wyświetlenie podmenu w wyniku kliknięcia pozycji menu wymagało zastosowania funkcji nasłuchującej zdarzeń pochodzących z elementów span klasy menu. Gdy taki element zostanie kliknięty, pobieramy następujący po nim element ul (zawiera podmenu), wywołując metodę next(), i za pomocą funkcji slideToggle() przełączamy jej widoczność na ekranie. Dzięki zastosowaniu funkcji slideToggle() kolejne kliknięcia tej samej pozycji menu będą powodowały wyświetlenie lub ukrycie podmenu. W przeciwieństwie do funkcji show() lub hide() wpływa ona na wysokość elementu, tworząc efekt jego zwijania lub rozwijania. Przyjmuje ona parametry zbliżone do parametrów funkcji show() i hide(), dlatego można jej przekazać wartości slow, normal lub fast albo bezpośrednio podać liczbę milisekund trwania efektu.
Zobacz też Q Recepturę „Wyświetlanie pływającego okienka na żądanie” z rozdziału 6.
Tworzenie interfejsu do nawigacji w kartach Karty są bardzo użytecznym narzędziem pozwalającym zmieścić więcej treści na niewielkiej przestrzeni. W tej i kolejnych recepturach przyjrzymy się kilku technikom pozwalającym na tworzenie kart i wyświetlanie w nich danych.
Przygotowania W katalogu rozdzial7 utwórz nowy katalog i nazwij go receptura5.
Jak to zrobić? 1. W katalogu receptura5 utwórz plik o nazwie index.html. W tym samym katalogu utwórz jeszcze jeden plik i nazwij go tabs.css. Ten drugi będzie przechowywał style CSS elementów tworzących karty.
221
PHP i jQuery. Receptury
2. Otwórz plik index.html w edytorze i w sekcji head kodu HTML wpisz przede wszystkim referencję pliku tabs.css. Teraz przygotuj strukturę kart. Nagłówkami kart będą pozycje listy wypunktowanej, przy czym każda pozycja będzie nagłówkiem jednej karty. Zaraz za nią umieść element div, w którym znajdą się treści z poszczególnych kart umieszczone w osobnych elementach div. Pierwszej pozycji listy (nagłówkowi karty) przyporządkowany będzie pierwszy element div z treścią, druga pozycja listy zostanie związana z drugim elementem div itd. Oba elementy główne (listę i element div z treściami) umieść jeszcze w nadrzędnym elemencie div. Karty
Karta 1
Karta 2
Karta 3
Karta 1
Treść dla karty 1
Karta 2
Treść dla karty 2
Karta 3
Treść dla karty 3
3. Otwórz plik tabs.css w edytorze i zdefiniuj w nim właściwości CSS dla poszczególnych elementów strony. W tym przykładzie zastosujemy tylko bardzo ograniczoną stylizację, ale nic nie stoi na przeszkodzie, żeby dodać do kart obrazki lub zmienić ich kolory, uatrakcyjniając całą kompozycję. body { font-family:"Trebuchet MS",verdana;
Efekt naszych prac powinien być podobny do przedstawionego na poniższym rysunku:
4. Dołącz teraz plik biblioteki jQuery, stosując przy tym właściwą ścieżkę. Możemy już dopisać kod JavaScript, który zamieni nasze struktury w prawdziwe karty. Pierwszej karcie chcemy od razu nadać wygląd karty aktywnej, dlatego musimy zdefiniować funkcję showHideTabs(), która będzie wywoływana po kliknięciu nagłówka karty. Funkcja ta sprawi, że kliknięta karta stanie się aktywna i na ekranie pojawi się związana z nią treść.
5. Cały kod jest już gotowy. Uruchom plik index.html w przeglądarce. Zobaczysz trzy dostępne karty, ale tylko pierwsza z nich będzie oznaczona jako aktywna i tylko treść tej karty będzie widoczna na ekranie. Kliknięcie nagłówka innej karty spowoduje jednak, że to ona stanie się aktywna i zmieni się widoczna w przeglądarce treść. 224
Rozdział 7. • Tworzenie menu nawigacyjnych
Jak to działa? Logika działania kart nie jest szczególnie skomplikowana. Treść wszystkich kart przechowywana jest w elementach div klasy tabContent. Użyte w skrypcie wywołanie $('.tabContent:gt(0)').hide() ukrywa wszystkie elementy o indeksie większym od zera. Oznacza to, że początkowo widoczny będzie tylko pierwszy element div klasy tabContent. W kolejnym wierszu wyrażenie $('.tabHeader > li:eq(0)').addClass('active') dodaje klasę active do pierwszego elementu listy, dzięki czemu zostaje on wyróżniony. Następnie podłączamy do elementów listy funkcję obsługującą zdarzenie click. Kliknięcie powoduje wywołanie funkcji showHideTabs(), która zajmuje się przełączeniem aktywnej karty. Teraz zajmijmy się samą funkcją showHideTabs(). W pierwszej kolejności pobiera wszystkie elementy listy i usuwa z nich klasę active, wywołując w tym celu funkcję removeClass(). Następnie wywołuje funkcję addClass(), aby dodać klasę active do klikniętego elementu. W ten sposób wyróżniony zostaje kliknięty nagłówek karty. Pozostaje jeszcze wyświetlenie jej treści. Pobieramy zatem indeks klikniętego elementu listy, wywołując funkcję index(), która zwraca pozycję elementu w kolekcji, zaczynając numerację od zera. Następnie ukrywamy widoczny element div, wyszukując go za pomocą selektora :visible. Na zakończenie wyświetlamy jeszcze element div, którego indeks jest równy indeksowi klikniętego elementu listy. Jeżeli kliknięty zostanie drugi element listy, to jego indeks będzie równy 1. W związku z tym wywołanie $('.tabContent:eq('+index+')').show() pobierze element div o indeksie równym 1 i wyświetli go na ekranie.
Dodawanie nowych kart W tej recepturze przygotujemy nowe elementy uzupełniające poprzednią, w której nauczyliśmy się tworzyć karty. Tym razem zajmiemy się metodami dodawania nowych kart do zestawu już istniejących. Oczywiście możliwe będzie też określenie nazwy oraz treści nowych kart.
225
PHP i jQuery. Receptury
Przygotowania W katalogu rozdzial7 utwórz nowy katalog o nazwie receptura6.
Jak to zrobić? 1. W katalogu receptura6 utwórz nowy plik i nazwij go index.html. W tym samym katalogu utwórz dodatkowy plik o nazwie tabs.css. 2. Otwórz plik tabs.css w edytorze i wprowadź do niego poniższe właściwości elementów strony. Tym razem w pliku zapisanych będzie więcej właściwości niż w poprzedniej recepturze, ponieważ potrzebne nam będą też elementy umożliwiające wprowadzanie nazwy i treści nowej karty. body{ font-family:"Trebuchet MS",verdana;} ul { float: left; margin: 0pt; padding: 0pt; list-style: none; width:600px; } li { border-left:1px solid #000; border-right:1px solid #000; cursor:pointer; float:left; padding:5px; text-align:center; width:100px; } .tabContainer { border:1px solid #000; float:left; width:600px; } .tabContent { border-top:1px solid #000; float:left; height:200px; padding:5px; text-align:justify; width:590px; }
3. Przygotujemy teraz kod HTML tworzący karty. Wykorzystamy tutaj dokładnie tę samą strukturę, której użyliśmy w poprzedniej recepturze. Najpierw jednak wstawimy na stronę małe i duże pole tekstowe oraz jeden przycisk. Nazwę karty będziemy wprowadzać w małym polu tekstowym, a jej treść w dużym. Z kolei przyciskiem dodamy nową kartę po uprzednim wpisaniu jej danych. Otwórz zatem plik index.html w edytorze i wpisz do niego odwołanie do pliku tabs.css, a następnie uzupełnij kodem HTML przedstawionym poniżej: Karty
Dodaj nową kartę
Karta 1
Karta 2
Karta 3
227
PHP i jQuery. Receptury
Karta 1
Treść karty 1
Karta 2
Treść karty 2
Karta 3
Treść karty 3
Teraz nasza strona powinna wyglądać tak jak na poniższym rysunku:
228
Rozdział 7. • Tworzenie menu nawigacyjnych
4. Na początek dołącz plik biblioteki jQuery, nie zapominając o podaniu właściwej ścieżki. Oprócz aktywowania pierwszej karty i ukrycia wszystkich pozostałych napiszemy jeszcze funkcję addTab(), która będzie pobierała nazwę oraz treść karty i na ich podstawie dodawała nową kartę do już istniejących. Z poprzedniej receptury przejmiemy funkcje związane z przełączaniem aktywnej karty. W tym celu wykorzystamy funkcję showHideTabs(), która przełącza klikniętą kartę w stan aktywny i wyświetla przypisaną jej treść.
5. Zapisz plik index.html i uruchom go w przeglądarce. Po lewej stronie zobaczysz małe i duże pole tekstowe oraz przycisk. Po prawej stronie widoczne będą natomiast trzy karty, a pierwsza z nich będzie już aktywna. Wprowadź tekst do elementów z lewej strony okna i kliknij przycisk Dodaj nową kartę. Zostanie wtedy utworzona nowa karta, która pojawi się zaraz za już istniejącymi.
229
PHP i jQuery. Receptury
Jak to działa? Na początek muszę przypomnieć (choć mówiłem już o tym w poprzedniej recepturze), że funkcja showHideTabs() podłączana jest jako funkcja obsługi zdarzenia click nagłówków kart. W tej recepturze dodajemy nowe karty do już istniejących, a zatem chcielibyśmy, żeby zdarzenie click było obsługiwane również w nowych kartach. Oznacza to, że zamiast po prostu przyłączyć funkcję do zdarzenia click, wykorzystamy funkcję live(), która wiąże funkcję ze zdarzeniami w elementach tworzonych również później. Wróćmy teraz do dodawania nowej karty. Po kliknięciu przycisku Dodaj nową kartę wywoływana jest funkcja addTab(). Sprawdza ona, czy w polach tekstowych został wprowadzony jakiś tekst. Jeżeli którekolwiek z pól tekstowych nie zostało wypełnione, to wyświetlany jest komunikat o błędzie. Karta może zostać dodana jedynie w przypadku, gdy oba pola są wypełnione. Najpierw usuwana jest zawartość elementu span, w którym mógłby znajdować się komunikat o błędzie. W kolejnym wierszu tworzymy element listy z wpisaną nazwą karty (pobraną z małego pola tekstowego) i dodajemy go do listy wypunktowanej. Podobnie tworzymy też element div i wpisujemy do niego treść karty pobraną z dużego pola tekstowego, a następnie wstawiamy go do elementu div klasy contents. Wstawianemu elementowi div przypisujemy jeszcze klasę hide, przez co zostaje on ukryty i nie wpływa na aktualny wygląd strony. Dopiero kliknięcie nagłówka nowej karty spowoduje wyświetlenie jej zawartości.
I coś jeszcze Domyślne wyświetlanie nowej karty W podanym kodzie tworzona jest nowa karta, ale nie jest ona domyślnie ustawiana jako aktywna. Nic nie stoi jednak na przeszkodzie temu, żeby od razu wyświetlać nowo utworzoną kartę. W funkcji addTab() dodaj poniższe wiersze kodu na zakończenie bloku if.
Ze względu na to, że nowa karta dodawana jest jako ostatnia, pierwsze dwa wiersze usuwają klasę active z nagłówków kart, a następnie dodają ją do ostatniej karty. Kolejne dwa wiersze ukrywają najpierw wszystkie elementy div klasy content, a potem wyświetlają ostatni z nich. Oznacza to, że widoczna będzie tylko ostatnio dodana karta.
Zobacz też Q Recepturę „Tworzenie interfejsu do nawigacji w kartach”. Q Recepturę „Dodawanie zdarzeń do elementów, które zostaną utworzone później”
z rozdziału 1.
Tworzenie kreatora za pomocą kart W tej recepturze dowiemy się, jak można przygotować kreatora, który będzie krok po kroku prowadził użytkownika strony.
Przygotowania W katalogu rozdzial7 utwórz nowy katalog o nazwie receptura7, a następnie utwórz w nim plik i nazwij go index.html.
Jak to zrobić? 1. Podobnie jak to było w poprzedniej recepturze, zaczniemy od przygotowania struktury kart, wykorzystując do tego elementy listy wypunktowanej jako nagłówki oraz elementy div klasy tabContent jako kontenery na treść. Nie zapomnij o dodaniu stylów CSS w sekcji head strony. Karty
233
PHP i jQuery. Receptury
Na każdej karcie znajduje się kilka dodatkowych elementów. Na pierwszej zobaczymy pole tekstowe oraz przycisk Dalej, który pozwoli nam przejść do następnej karty. Na drugiej karcie umieściliśmy dwie listy rozwijane oraz przyciski Wróć i Dalej, za pomocą których można przejść do poprzedniej lub następnej karty. Trzeciej i ostatniej karcie przypisaliśmy dodatkowo klasę last, a jej element div otrzymał identyfikator order. Umieściliśmy na niej przycisk Wróć. Ogólny wygląd strony można zobaczyć na poniższym rysunku.
2. Teraz dołącz plik biblioteki jQuery i przygotuj funkcje obsługujące kliknięcia przycisków Wróć i Dalej. Dla uproszczenia nie będziemy reagować na kliknięcia nagłówków kart, przez co użytkownik nie będzie mógł przejść bezpośrednio do wybranej karty. Funkcje obsługujące przyciski muszą najpierw pobrać indeks
234
Rozdział 7. • Tworzenie menu nawigacyjnych
aktualnej karty, a następnie wywołać funkcję showHideTabs(), która zajmie się przełączeniem kart zgodnie z podaną jej w parametrze wartością. Oprócz tego sprawdzi też, czy aktywowana została ostatnia karta. W takiej sytuacji biblioteka jQuery zbierze dane wprowadzone przez użytkownika na poprzednich kartach i wyświetli podsumowanie na ostatniej.
3. Zapisz plik i otwórz go w przeglądarce. Zobaczysz wtedy trzy znane nam już karty. Wprowadź dane do formularza na pierwszej karcie i kliknij przycisk Dalej. Na drugiej karcie wybierz produkt i liczbę sztuk, a następnie kliknij przycisk Dalej. Na ostatniej karcie zobaczymy tylko komunikat potwierdzający dokonany wcześniej wybór.
Jak to działa? Najpierw ukrywamy wszystkie karty z wyjątkiem pierwszej i dodajemy do niej klasę active. Następnie dołączamy funkcję obsługującą zdarzenie click przycisków Wróć i Dalej. Po kliknięciu przycisku wywołujemy funkcję getCurrentTabIndes(), pobieramy za jej pomocą indeks nadrzędnego elementu div i zapisujemy go w zmiennej currentTabIndex. W kolejnym kroku sprawdzamy klasę klikniętego przycisku. Jeżeli jest to klasa prev, to znaczy, że użytkownik chce przejść do poprzedniej karty, a zatem zmniejszamy wartość zmiennej currentTabIndex i przekazujemy ją do funkcji showHideTabs(). Podobnie, jeżeli kliknięty został przycisk klasy next, to do funkcji showHideTabs() przekazujemy powiększoną uprzednio wartość zmiennej currentTabIndex. Funkcja showHideTabs() najpierw usuwa klasę active z elementów listy, a następnie szuka elementu o indeksie równym wartości przekazanej jej w parametrze i jemu przypisuje klasę active. W kolejnym kroku ukrywany jest aktualnie widoczny element div klasy tabContent, a wyświetlany jest ten o pasującym numerze indeksu.
236
Rozdział 7. • Tworzenie menu nawigacyjnych
Na zakończenie funkcja sprawdza jeszcze, czy nie została aktywowana ostatnia karta, szukając w niej klasy last. Jeżeli to rzeczywiście jest ostatnia karta, wywoływana jest funkcja display ´SelectedValues(). Funkcja displaySelectedValues() pobiera tekst wprowadzony do pola tekstowego userName oraz wartości wybrane z list rozwijanych product i quantity, a następnie przygotowuje na ich podstawie sformatowany komunikat, który umieszczany jest w elemencie div o identyfikatorze order.
Zobacz też Q Recepturę „Tworzenie interfejsu do nawigacji w kartach”. Q Recepturę „Dodawanie nowych kart”.
237
PHP i jQuery. Receptury
238
8 Wiązanie danych w PHP i jQuery W tym rozdziale zajmiemy się: Q pobieraniem danych z bazy i wyświetlaniem ich w formie tabeli, Q zbieraniem danych z formularza i zapisywaniem ich w bazie (formularz rejestracyjny), Q wypełnianiem powiązanych ze sobą list rozwijanych, Q sprawdzaniem w bazie danych dostępności nazwy użytkownika, Q podziałem dużych ilości danych na strony, Q dodawaniem funkcji podpowiedzi do pól tekstowych, Q tworzeniem chmury znaczników.
Wprowadzenie W tym rozdziale znajdą się receptury, w których po stronie serwera będziemy korzystać z bazy danych oraz języka PHP. Baza danych jest nieodzownym elementem niemal każdej dynamicznej aplikacji WWW. Język PHP udostępnia wiele funkcji ułatwiających pracę z bazami danych. W połączeniu z językiem PHP najczęściej używanym rodzajem bazy danych jest MySQL. W tym rozdziale będziemy korzystać ze specjalnej wersji rozszerzenia MySQL o nazwie MySQLi, gdzie literka i oznacza improved, czyli usprawniony. Wprowadza ona wiele poprawek w stosunku do standardowego rozszerzenia MySQL, przy czym najważniejszą zmianą jest obsługa obiektowego interfejsu obok dotychczasowego interfejsu proceduralnego. Wśród innych funkcji można wymienić obsługę transakcji, instrukcje wbudowane i inne.
PHP i jQuery. Receptury
Więcej informacji na temat rozszerzenia MySQLi można znaleźć na stronach języka PHP pod adresem http://www.php.net/manual/pl/book.mysqli.php. Rozszerzenie MySQLi dostępne jest tylko dla PHP od wersji 5.0 i nowszych. Upewnij się zatem, że korzystasz z właściwej wersji. Jeżeli korzystamy z wersji PHP 5.0 lub nowszej, to musimy osobno skonfigurować rozszerzenie MySQL jako domyślne dla języka PHP, ponieważ jego obsługa w tych wersjach interpretera został zarzucona.
Czyszczenie danych przed ich użyciem W recepturach prezentowanych w tej książce bezpośrednio korzystamy z danych wprowadzonych przez użytkownika, pobierając je z tablic $_GET lub $_POST. W przykładach takie postępowanie jest do zaakceptowania, jednak w praktycznych zastosowaniach dane wprowadzane przez użytkownika muszą zostać odpowiednio oczyszczone, zanim zostaną na nich wykonane jakiekolwiek inne operacje. Tylko w ten sposób można zabezpieczyć swoją aplikację przed złośliwymi działaniami. Poniżej przedstawiam adresy, pod którymi można znaleźć więcej informacji na temat zabezpieczenia danych i ogólnego bezpieczeństwa aplikacji. Konsorcjum PHP Security: http://phpsec.org. Podręcznik języka PHP: http://www.php.net/manual/pl/security.php.
Pobieranie danych z bazy i wyświetlanie ich w formie tabeli Zaczynamy prostą recepturą, w której będziemy pobierać dane z tabeli i wyświetlać je na stronie. Użytkownik zobaczy na stronie listę rozwijaną, z której będzie mógł wybrać język programowania. Wybranie języka spowoduje pobranie z bazy listy funkcji razem z ich opisami.
Przygotowania W katalogu rozdzial8 utwórz nowy katalog o nazwie receptura1. Teraz za pomocą narzędzia phpMyAdmin utwórz bazę danych exampleDB, a w niej tabelę o nazwie language. Wykorzystaj do tego poniższe zapytanie: CREATE TABLE `language` ( `id` int(3) NOT NULL auto_increment, `languageName` varchar(50) NOT NULL, PRIMARY KEY (`id`) );
240
Rozdział 8. • Wiązanie danych w PHP i jQuery
Teraz wstaw do nowej tabeli dwa wiersze, wpisując w kolumnie languageName nazwy PHP i jQuery. Utwórz też kolejną tabelę o nazwie functions, do której będziemy wpisywać nazwy funkcji z opisami oraz odnośnikiem do języka programowania. CREATE TABLE `functions` ( `id` int(3) NOT NULL auto_increment, `languageId` int(11) NOT NULL, `functionName` varchar(64) NOT NULL, `summary` varchar(128) NOT NULL, `example` text NOT NULL, PRIMARY KEY (`id`) );
W polu languageID znajdzie się identyfikator języka zapisany wcześniej w tabeli language. Wstaw teraz do tabeli functions kilka wierszy, opisując w nich funkcje znane z języka PHP i biblioteki jQuery. Oto widok tej tabeli po wprowadzeniu do niej danych:
Jak to zrobić? 1. W katalogu receptura1 utwórz nowy plik i nazwij go index.php. Za pomocą metod klasy MySQLi wybierz dane z tabeli language i wprowadź je do listy rozwijanej. Oprócz tego utwórz element p, w którym będą wyświetlane funkcje wybranego języka.
2. Teraz dodaj referencję pliku jQuery i dopisz funkcję obsługującą zmianę wartości wybranej z listy rozwijanej. Funkcja ta powinna wysyłać żądanie AJAX do pliku PHP o nazwie results.php, który pobierze z bazy dane wskazanego języka i prześle do przeglądarki, gdzie zostaną one umieszczone w elemencie p.
3. Utwórz kolejny plik i nazwij go result.php. Zapisany w nim skrypt będzie łączył się z bazą danych exampleDB i pobierał z niej dane związane ze wskazanym językiem. Następnie utworzy kod HTML i umieści w nim wyniki zapytania, po czym odeśle je do przeglądarki, tak żeby biblioteka jQuery mogła wstawić otrzymany tekst do elementu p. query($query)) { if ($result->num_rows > 0) { $resultStr.='
4. Uruchom teraz w przeglądarce plik index.php, a zobaczysz listę rozwijaną pozwalającą na wybranie języka. Dostępne są w niej dwie pozycje: PHP i jQuery. Wybierz jedną z tych opcji, a poniżej pojawi się lista funkcji wraz z krótkim objaśnieniem.
Jak to działa? Na początku tworzymy nowy obiekt klasy MySQLi, wywołując jej konstruktor. Przekazujemy mu nazwę hosta, nazwę użytkownika bazy danych, hasło oraz nazwę samej bazy. Następnie sprawdzamy, czy podczas nawiązywania połączenia z bazą danych nie wystąpiły żadne błędy. Jeżeli nie udało się nawiązać połączenia, to wyświetlamy komunikat o błędzie i kończymy działanie skryptu.
244
Rozdział 8. • Wiązanie danych w PHP i jQuery
Następnie wywołujemy metodę query obiektu mysqli, aby pobrać z bazy wszystkie informacje o dostępnych językach. Jeżeli zapytanie zakończy się sukcesem, to zapisujemy wynik jego pracy w zmiennej $result. W zmiennej tej znajdzie się obiekt klasy MySQLi_Result, która udostępnia kilka metod pobierania danych z obiektu. W naszym przykładzie skorzystaliśmy z metody fetch_assoc(), która pobiera wiersze danych w postaci tablicy asocjatywnej. Następnie w pętli while iterujemy po kolejnych wierszach danych z obiektu $result. Na tym etapie tworzymy listę rozwijaną o identyfikatorze selectLanguage, którą wypełniamy wartościami pola languageName, a wartość pola ID wstawiamy jako wartość danej opcji. W kodzie biblioteki jQuery dołączamy do przygotowanej wcześniej listy rozwijanej funkcję obsługującą zdarzenie change. Pobiera ona wartość wybranej opcji i przesyła ją jako parametr żądania AJAX kierowanego do pliku resutls.php. Skrypt z pliku results.php łączy się najpierw z bazą danych exampleDB, a następnie tworzy zapytania pobierające z bazy informacje o konkretnym języku. Biblioteka jQuery przesłała identyfikator języka w ramach żądania AJAX i teraz informacja ta zostanie wykorzystana w budowanym zapytaniu. Podobnie jak to było w pliku index.php, pobieramy wyniki zapytania i zapisujemy je w zmiennej $result. Teraz możemy już iterować po wynikach zapytania i na ich podstawie przygotować listę wypunktowaną i wpisać ją do zmiennej $resultStr. Każda pozycja listy będzie składała się z nazwy funkcji, krótkiego opisu oraz przykładu użycia. W przypadku wystąpienia jakiegokolwiek błędu do zmiennej $resultStr zapisywany jest odpowiedni komunikat. Na zakończenie odsyłamy zawartość zmiennej $resultStr do przeglądarki, gdzie biblioteka jQuery wstawi otrzymany tekst do elementu p o identyfikatorze result.
I coś jeszcze Czym jest konstruktor W programowaniu obiektowym konstruktor jest metodą, która jest wywoływana podczas tworzenia nowego obiektu danej klasy. Konstruktor zawsze nosi nazwę identyczną z nazwą klasy. $mysqli = new mysqli('localhost', 'root', '', 'exampleDB');
Powyższy wiersz kodu tworzy nowy obiekt klasy mysqli, której konstruktor przyjmuje cztery parametry. Trzeba tu pamiętać o jednej rzeczy. W języku PHP 5 i nowszych wersjach konstruktor definiowany jest wyrażeniem __construct(), podczas gdy w starszych wersjach interpretera konstruktor miał po prostu nazwę identyczną z nazwą klasy. Więcej informacji na temat konstruktorów w języku PHP można znaleźć na stronach PHP pod adresem http://www.php.net/manual/pl/language. oop5.decon.php.
245
PHP i jQuery. Receptury
Zbieranie danych z formularza i zapisywanie ich w bazie Wykorzystamy tu te same tabele, których użyliśmy w poprzedniej recepturze, i na tej podstawie przygotujemy formularz, w którym użytkownik będzie mógł wybrać język, wprowadzić nazwę funkcji, krótki opis i przykład zastosowania. Wszystkie te informacje zapiszemy potem w tabeli functions i powiążemy z wybranym językiem.
Przygotowania W katalogu rozdzial8 utwórz nowy katalog i nazwij go receptura2.
Jak to zrobić? 1. W katalogu receptura2 utwórz plik o nazwie index.php. Wpisz do niego kod formularza z czterema polami. Pierwszym będzie lista rozwijana, której wartości pobierz z tabeli language naszej bazy danych. Następnie utwórz dwa pola tekstowe, opisując je Nazwa funkcji i Opis. Na koniec wstaw jeszcze pole typu textarea, w którym podawany będzie przykład użycia funkcji. Nie zapomnij o przypisaniu wszystkim polom klasy CSS required.
246
Rozdział 8. • Wiązanie danych w PHP i jQuery
2. Przed zamykającym znacznikiem body dołącz plik jquery.js, a następnie wpisz funkcję obsługującą zdarzenie submit formularza. Funkcja ta przeprowadzi prostą kontrolę formularza, sprawdzając wartości wprowadzone do wszystkich pól. Jeżeli jakiekolwiek pole nie będzie wypełnione, to pojawi się komunikat o błędzie. Jeżeli jednak nie wystąpią żadne błędy, to formularz zostanie przesłany na serwer.
3. Po przesłaniu danych z formularza skrypt PHP pobierze wartości poszczególnych pól z globalnej tablicy $_POST i przypisze je do osobnych zmiennych, uprzednio oczyszczając ich zawartość. Następnie uruchamiane jest zapytanie INSERT, które wstawi otrzymane wartości do bazy danych. Przy okazji wyświetlony zostanie odpowiedni komunikat, zależnie od tego, czy operacja zapisu danych się powiodła czy też nie. Poniżej przedstawiam pełny kod pliku index.php.
247
PHP i jQuery. Receptury
real_escape_string($_POST['language']); $functionName = $mysqli->real_escape_string($_POST['functionName']); $summary = $mysqli->real_escape_string($_POST['summary']); $example = $mysqli->real_escape_string($_POST['example']); $query = 'INSERT INTO functions (languageId ,functionName ´,summary ,example) VALUES ('.$language.', "'.$functionName.'", "'.$summary.'","'.$example.'")'; if ($mysqli->query($query)) { echo 'Dane zostały zapisane.'; } else { echo 'Wystąpił błąd podczas zapisywania danych.'; } } $query = 'SELECT * FROM language'; if ($result = $mysqli->query($query)) { if ($result->num_rows > 0) { ?> close(); } else { echo 'Błąd w zapytaniu: $query. '.$mysqli->error; } $mysqli->close(); ?>
4. Teraz uruchom w przeglądarce nasz plik i wprowadź do formularza jakieś dane. Po kliknięciu przycisku Zapisz informacje teksty wprowadzone w formularzu zostaną zapisane do tabeli functions. Na stronie pojawi się też komunikat Dane zostały zapisane. Próba przesłania formularza bez wypełnienia wszystkich pól będzie skutkowała tylko pojawieniem się komunikatu o błędzie.
Jak to działa? Na początek łączymy się z bazą danych, wywołując konstruktor klasy mysqli. Następnie instrukcją if sprawdzamy, czy formularz został już przesłany czy też strona jest wyświetlona po raz pierwszy.
249
PHP i jQuery. Receptury
Następna sekcja kodu wykonywana jest tylko w przypadku otrzymania danych z formularza. Przyjrzymy się jej w dalszej części tego punktu. if(isset($_POST['save'])) { }
Niezależnie od podanego wyżej warunku pobieramy dane z tabeli language, uruchamiając zapytanie SELECT, i w ten sposób otrzymujemy listę języków obsługiwanych przez bazę danych. Wszystkie te języki wraz z ich identyfikatorami wpisujemy do listy rozwijanej. Oprócz tego w formularzu umieszczamy dwa pola tekstowe i jeden element typu textarea. Po przesłaniu na serwer wypełnionego formularza skrypt PHP pobiera wartości z tablicy $_POST i oczyszcza je za pomocą metody real_escape_string() dostępnej w klasie mysqli. Funkcja ta przygotowuje dane otrzymane przez użytkownika do dalszych operacji na bazie. W związku z tym wstawiamy te wartości (identyfikator języka, nazwa funkcji, jej opis i przykład użycia) do zapytania INSERT. Wywołana metoda query() zwróci wartość true, jeżeli uda się zapisać dane do tabeli, albo wartość false, jeżeli podczas zapisywania wystąpi jakiś błąd. Na zakończenie na podstawie wartości otrzymanej od tej metody wyświetlany jest jeszcze stosowny komunikat.
I coś jeszcze Funkcja real_escape_string() Funkcja real_escape_string() używana jest do zamaskowania znaków specjalnych, które mogłyby znaleźć się w ciągu znaków. Jeżeli w treści zapytania SQL znajdą się niezamaskowane znaki specjalne, to całe zapytanie może zakończyć się błędem. Z tego powodu przy korzystaniu z bazy danych zawsze należy korzystać z tej funkcji. Trzeba tu też nadmienić, że działanie tej funkcji wymaga aktywnego połączenia z bazą danych.
Wartości zwracane przez metodę mysqli->query() W przypadku zapytań typu SELECT, SHOW i podobnych metoda ta zwraca obiekt klasy MySQLi_ ´Result. W przypadku zapytań typu INSERT, UPDATE i DELETE zwraca jedynie wartość true lub false.
Zobacz też Q Recepturę „Szukanie pustych pól za pomocą biblioteki jQuery” z rozdziału 5.
250
Rozdział 8. • Wiązanie danych w PHP i jQuery
Wypełnianie powiązanych ze sobą list rozwijanych W tej recepturze postaramy się rozwiązać dość powszechny problem, występujący w wielu aplikacjach WWW. Chodzi o filtrowanie zawartości listy rozwijanej zgodnie z wyborem dokonanym na innej liście rozwijanej. Przygotujemy tutaj przykład, w którym użytkownik będzie mógł skorzystać z trzech list rozwijanych: w jednej znajdą się nazwy państw, w drugiej nazwy regionów, a w ostatniej nazwy miast. Wybranie kraju spowoduje wpisanie do drugiej listy nazw regionów, a wybranie jednego z regionów wypełni trzecią listę nazwami miast. Na zakończenie wybranie miasta spowoduje wyświetlenie krótkiej informacji na jego temat. Najważniejsze w tym wszystkim jest to, że nie będziemy w związku z tym przeładowywać strony, ale wykorzystamy żądania AJAX, aby w tle filtrować zawartość list. Dzięki temu doznania użytkownika poprawią się w stosunku do klasycznych rozwiązań z każdorazowym przeładowaniem całej strony po wykonaniu wyboru.
Przygotowania W katalogu rozdzial8 utwórz nowy katalog i nazwij go receptura3. Oprócz tego utwórz w bazie danych cztery nowe tabele. Ponownie skorzystaj z narzędzia phpMyAdmin i uruchom w nim podane niżej zapytania. Q Tabela Country CREATE TABLE `country` ( `id` int(11) NOT NULL auto_increment, `countryName` varchar(64) NOT NULL, PRIMARY KEY (`id`) ); INSERT INTO `country` (`id`, `countryName`) VALUES (1, 'Indie') Q Tabela States CREATE TABLE `states` ( `id` int(11) NOT NULL auto_increment, `countryId` int(11) NOT NULL, `stateName` varchar(64) NOT NULL, PRIMARY KEY (`id`) ); INSERT INTO `states` (`id`, `countryId`, `stateName`) VALUES (1, 1, 'U.P.'), (2, 1, 'Uttarakhand');
251
PHP i jQuery. Receptury
Q Tabela Towns CREATE TABLE `towns` ( `id` int(11) NOT NULL auto_increment, `stateId` int(11) NOT NULL, `townName` varchar(64) NOT NULL, PRIMARY KEY (`id`) ); INSERT INTO `towns` (`id`, `stateId`, `townName`) VALUES (1, 1, 'Lucknow'), (2, 1, 'Bareilly'), (3, 2, 'Pithoragarh'), (4, 2, 'Dehradun'), (5, 2, 'Nainital'); Q Tabela Towninfo CREATE TABLE `towninfo` ( `id` int(11) NOT NULL auto_increment, `townId` int(11) NOT NULL, `description` text NOT NULL, PRIMARY KEY (`id`) ); INSERT INTO `towninfo` (`id`, `townId`, `description`) VALUES (1, 3, 'Pithoragarh jest pięknym miastem położonym w regionie Kumaon. Średnia ´wysokość nad poziomem morza wynosi w tym mieście 1,514 metrów (4,967 stóp).'), (2, 4, 'Dehradun, nazywane jest też Doon, jest stolicą regionu Uttarakhand. ´Położone jest w odległości 250 kilometrów od stolicy państwa - Delhi.\r\nGłównymi ´produktami wytwarzanymi w tym mieście jest ryż i lychee.'), (3, 1, 'Lucknow jest stolicą regionu U.P. lub Uttar Pradesh.\r\nW Lucknow ´znajduje się pierwszy azjatycki bank DNA.\r\nNazywane jest też Miastem ´Nawabs, Złotym miastem wschodu albo Konstantynopolem Indii.');
Jak to zrobić? 1. W katalogu receptura3 utwórz nowy plik o nazwie index.html. Wpisz do niego kod HTML tworzący trzy listy rozwijane, w których znajdą się nazwy państw, regionów i miast, a także element p, w którym wypisywane będą informacje na temat wybranego miasta. W sekcji head strony dopisz też kilka stylów CSS zmieniających wygląd tych elementów. Wszystkie wartości dostępne na listach rozwijanych zostaną wprowadzone za pomocą żądań AJAX.
252
Rozdział 8. • Wiązanie danych w PHP i jQuery
Państwo
Region
Miasto
253
PHP i jQuery. Receptury
2. Przed zamykającym znacznikiem body dołącz plik biblioteki jQuery. Wpisz też funkcję getList(), która będzie wywoływana przy każdej zmianie wartości wybranej z listy rozwijanej. W zależności tego, z której listy wybrano nową pozycję, adres URL żądania zostanie uzupełniony o dwa parametry: find i id. Na zakończenie wysyłamy żądanie AJAX pod zbudowany wcześniej adres URL i odbieramy przesłane przez serwer wyniki. Funkcja getList() zostanie też wywołana zaraz po załadowaniu dokumentu, tak żeby już od samego początku dostępne były wartości na liście Państwo.
3. Żądanie AJAX zostanie przesłane do pliku results.php. Przygotuj zatem nowy plik o takiej właśnie nazwie. Skrypt znajdujący się w tym pliku musi najpierw połączyć się z bazą danych i zależnie od wartości parametrów find i id odczytać z niej dane z odpowiedniej tabeli. Na podstawie informacji uzyskanych z bazy danych tworzony jest kod HTML, który następnie odsyłany jest do przeglądarki, gdzie biblioteka jQuery może wstawić go w odpowiednie miejsce. query($query)) { $result = $mysqli->query($query); if($find == 'information') { if($result->num_rows > 0) { $row = $result->fetch_array(); echo $row[1]; } else { echo 'No Information found'; } } else { ?>
255
PHP i jQuery. Receptury
fetch_array()) { ?>
4. Uruchom plik index.html w przeglądarce. Zobaczysz, że na liście rozwijanej Państwo znajdują się już wartości, natomiast pozostałe listy są nadal puste. Wybierz z listy Państwo jedną z wartości, a lista Region zostanie wypełniona odpowiednimi opcjami. Po wybraniu regionu również ostatnia lista zostanie wypełniona nazwami miast. Na koniec wybierz jeszcze jedno z dostępnych miast, a żądanie AJAX pobierze z bazy danych krótki opis tego miasta i wyświetli go w elemencie p.
Jak to działa? Kod HTML z pliku index.html jest wyjątkowo prosty. Utworzyliśmy w nim trzy listy rozwijane oraz element typu p. Każdy z tych elementów otrzymał swój identyfikator: countryList, stateList, townList oraz information. W kodzie JavaScript dodaliśmy metodę nasłuchującą zdarzeń change we wszystkich znajdujących się na stronie listach rozwijanych, która w przypadku wybrania wartości w którejkolwiek z list wywołuje funkcję getList(). Funkcja ta definiuje dwie zmienne: url i target. Następnie pobiera identyfikator listy oraz wartość elementu wybranego z tej listy, a potem za pomocą instrukcji switch tworzy cztery ścieżki wykonywane zależnie od wartości pobranego wcześniej identyfikatora. Jeżeli wybrana została wartość z listy o identyfikatorze countryList, to w parametrze find adresu URL wstawiana jest wartość states oraz wartość wybrana z listy. Podobnie w przypadku wybrania wartości z listy stateList parametr find adresu URL otrzymuje wartość towns, a w przypadku listy
256
Rozdział 8. • Wiązanie danych w PHP i jQuery
townList — wartość information, ponieważ tym razem chcemy uzyskać opis wybranej miejscowości. W domyślnym przypadku parametr find otrzymuje wartość country, przez co z bazy danych pobierane będą wszystkie zdefiniowane w niej państwa, a następnie ich nazwy zostaną wpisane do pierwszej listy rozwijanej. Oprócz określenia adresu URL definiujemy również parametr target opisujący element, do którego skierowane zostaną dane.
Po zakończeniu instrukcji switch żądanie AJAX wysyłane jest za pomocą biblioteki jQuery do skryptu PHP results.php. Odpowiedź otrzymana od tego skryptu zostanie następnie wstawiona do elementu określonego parametrem target. Przyjrzyjmy się teraz skryptowi zapisanemu w pliku results.php. Na początku tworzy on połączenie z bazą danych exampleDB, a następnie pobiera z globalnej tablicy $_GET wartość klucza find. W kolejnym kroku instrukcja switch sprawdza wartość zmiennej $find i na tej podstawie uruchamia właściwe zapytanie. Jeżeli zmienna $find ma wartość states, to tworzone jest zapytanie korzystające ze zmiennej $countryID. W przypadku wartości information pobierane są dane z tabeli information dotyczące miasta o podanym identyfikatorze. Po pobraniu tych wartości z bazy danych pętla while iteruje po całej kolekcji wierszy tabeli i na podstawie ich zawartości tworzy kod HTML, który odsyłany jest do przeglądarki, gdzie biblioteka jQuery wstawia go do elementu wskazywanego przez parametr target.
Sprawdzanie w bazie danych dostępności nazwy użytkownika Przygotujemy tutaj przykładowy formularz rejestracyjny, który będzie szukał nazwy wprowadzonej przez użytkownika wśród wszystkich nazw zapisanych już w bazie danych. Jeżeli wprowadzona nazwa zostanie znaleziona, to użytkownik zostanie o tym poinformowany.
Przygotowania W katalogu rozdzial8 utwórz nowy katalog i nazwij go receptura4. Otwórz narzędzie phpMyAdmin i utwórz nową tabelę o nazwie users i strukturze podanej poniżej: CREATE TABLE `users` ( `id` int(11) NOT NULL AUTO_INCREMENT, `username` varchar(32) NOT NULL, `password` varchar(32) NOT NULL, PRIMARY KEY (`id`) ); INSERT INTO `users` (`id`, `username`, `password`) VALUES
Jak to zrobić? 1. W katalogu receptura4 utwórz nowy plik i nazwij go index.html. Wpisz do niego kod HTML tworzący pola tekstowe dla nazwy użytkownika i hasła. Obok pola nazwy użytkownika dodaj łącze, po którego kliknięciu sprawdzana będzie dostępność danej nazwy. Jeszcze jeden element umieszczony zaraz za łączem będzie sygnalizował, czy wybrana nazwa jest dostępna. Sprawdzanie nazwy użytkownika
2. Teraz dołącz plik biblioteki jQuery. Napisz też funkcję obsługującą kliknięcia elementu o identyfikatorze check. Będzie ona wysyłała żądanie AJAX do skryptu PHP zapisanego w pliku check.php, który z kolei zwracać będzie wartość true lub false zależnie od tego, czy dana nazwa użytkownika jest jeszcze wolna czy może jest już zajęta. Kolejna funkcja obsługi zdarzeń powinna zostać związana ze zdarzeniem submit wywoływanym z formularza. Pozwoli ona na przesłanie danych na serwer dopiero po wybraniu przez użytkownika dostępnej nazwy.
3. W tym samym katalogu utwórz kolejny plik i nazwij go check.php. Zapisz do niego skrypt sprawdzający wartość przekazaną mu przez bibliotekę jQuery, który przeszuka tabelę users i zwróci wartość true lub false. query($selectQuery); if($result) { if ($result->num_rows > 0) { echo false; } else { echo true;
260
Rozdział 8. • Wiązanie danych w PHP i jQuery
} } else { echo false; } ?>
4. Uruchom w przeglądarce plik index.php i wprowadź w formularzu nazwę użytkownika, która jest już zapisana w bazie danych, a następnie kliknij łącze Sprawdź. Zobaczysz komunikat, że ta nazwa użytkownika jest już zajęta. Wprowadź teraz dowolną nazwę użytkownika, której jeszcze nie ma w bazie, a pojawi się komunikat, że ta nazwa jest jeszcze wolna. Próba przesłania formularza bez uprzedniego sprawdzenia dostępności wybranej nazwy użytkownika również spowoduje wyświetlenie komunikatu z prośbą o kontrolę tej nazwy.
Jak to działa? Kliknięcie łącza Sprawdź uruchamia żądanie AJAX, które kierowane jest do pliku check.php. Po stronie serwera skrypt szuka otrzymanej nazwy użytkownika w tabeli users. Jeżeli w tabeli znajduje się niezerowa liczba wierszy z taką nazwą, to możemy mieć pewność, że nazwa ta jest już w użyciu i dlatego zwracana jest wartość false. W przeciwnym przypadku zwracana jest wartość true. Po stronie klienta funkcja wywoływana w przypadku poprawnej obsługi żądania sprawdza wartość odesłaną przez skrypt PHP i wyświetla odpowiedni komunikat. Dodatkowo zmienna checked używana jest do blokowania możliwości przesłania formularza, jeżeli wcześniej nie została sprawdzona dostępność wprowadzonej nazwy użytkownika. Tylko w przypadku gdy nazwa ta jest dostępna, zmiennej przypisywana jest wartość true, co pozwala na przesłanie formularza na serwer.
261
PHP i jQuery. Receptury
I coś jeszcze Alternatywna metoda implementacji W tej recepturze sprawdzaliśmy dostępność nazwy użytkownika po kliknięciu łącza. To samo zachowanie można jednak zaimplementować w ramach zdarzenia onkeydown pochodzącego z pola tekstowego. Wprowadzenie tej zmiany pozostawiam jako ćwiczenie dla Czytelnika.
Podział dużych ilości danych na strony Długie listy lub teksty dobrze jest podzielić na mniejsze strony i pozwolić na nawigowanie między nimi za pomocą przycisków typu Wstecz i Dalej oraz numerów kolejnych stron. W tej recepturze zajmiemy się długą listą elementów HTML i podzielimy ją na kilka stron, przy czym na każdej z nich znajdzie się z góry określona liczba tych elementów. Pozwolimy też użytkownikowi na natychmiastowe przejście do dowolnej strony przez wybranie jej z listy rozwijanej.
Przygotowania W katalogu rozdzial8 utwórz nowy katalog i nazwij go receptura5. Za pomocą narzędzia phpMyAdmin utwórz nową tabelę movies, nadając jej następującą strukturę. CREATE TABLE IF NOT EXISTS `movies` ( `id` int(11) NOT NULL AUTO_INCREMENT, `movieName` varchar(64) NOT NULL, PRIMARY KEY (`id`) );
Będziemy potrzebować też długiej listy tytułów filmowych, którą będziemy mogli podzielić na strony. Uzupełnij zatem utworzoną tabelę, wprowadzając do niej tytuły za pomocą narzędzia phpMyAdmin. W ramach tego przykładu wprowadziłem już do niej tytuły 100 filmów. Możesz zatem skorzystać z dołączonego do tej książki pliku movies.sql, który zapisze dane filmów do tabeli. Wszystkie te tytuły zostały pobrane ze strony http://www.thebest100lists.com/best100movies/.
Jak to zrobić? 1. W katalogu receptura5 utwórz plik o nazwie index.php. Nawiąż w nim połączenie z bazą danych i załaduj wszystkie tytuły filmów z tabeli movies, a następnie przygotuj na tej podstawie listę wypunktowaną. Dodatkowo utwórz element div o identyfikatorze
262
Rozdział 8. • Wiązanie danych w PHP i jQuery
navigation, w której znajdą się przyciski podziału listy na strony. Nie można też zapomnieć o zdefiniowaniu w sekcji head strony stylów CSS, które poprawią jej wygląd. 100 najlepszych filmów
2. Na powyższym rysunku można zobaczyć tylko część tekstu znajdującego się na stronie. W przeglądarce wyświetlona została jednak pełna lista 100 tytułów filmów. Dołącz teraz plik biblioteki jQuery i dopisz kod JavaScript dzielący tę listę na strony. Na początek zdefiniuj liczbę elementów na stronie oraz ogólną liczbę stron. W tym przykładzie będziemy wyświetlać po dziesięć tytułów na stronie, co oznacza, że ogólnie dostępnych będzie dziesięć stron. Następnie zdefiniuj funkcję createNavigation(), która będzie tworzyć łącza do poprzedniej i następnej strony oraz listę rozwijaną z numerami stron. W kolejnym kroku dopisz funkcję setDataAndEvents(), tworzącą funkcje obsługi zdarzeń pochodzących z narzędzi nawigacyjnych. Kliknięcie łącza nawigacyjnego albo wybranie numeru strony z listy rozwijanej spowoduje wywołanie funkcji goToPage(), która wyświetli listę tytułów filmów przypisanych do wybranej strony. 264
Rozdział 8. • Wiązanie danych w PHP i jQuery
3. Uruchom teraz plik index.php w przeglądarce, a zobaczysz listę plików oraz znajdujące się na dole łącza nawigacyjne. Na liście rozwijanej wybrany będzie już domyślny numer pierwszej strony. Ze względu na to, że jest to pierwsza strona, widoczne będzie tylko łącze Następna. Po jego kliknięciu zmieni się widoczna lista filmów oraz numer strony wyświetlany w liście rozwijanej. Po przejściu do ostatniej strony łącze Następna zniknie.
Jak to działa? Przede wszystkim pobieramy z bazy danych listę filmów, wywołując w tym celu metodę query() klasy mysqli. Następnie iterujemy po otrzymanych wynikach zapytania i na ich podstawie tworzymy wypunktowaną listę o identyfikatorze list. Jak można się domyślić, każdy tytuł filmu staje się kolejnym elementem listy. Zaraz za listą umieszczamy element div o identyfikatorze navigation, w którym umieszczane będą elementy nawigacji. Po załadowaniu strony najpierw
266
Rozdział 8. • Wiązanie danych w PHP i jQuery
uruchamiany jest kod JavaScript, który odczytuje liczbę pozycji znajdujących się na liście (liczbę elementów li) i przypisuje ją do zmiennej totalMovies. Następnie zmiennej moviesPerPage przypisujemy wartość 10, a potem wyliczamy ogólną liczbę stron, dzieląc wartość ze zmiennej totalMovies przez wartość zmiennej moviesPerPage. Teraz wywoływana jest funkcja createNavigation(), która tworzy w nawigacyjnym elemencie div dwa łącza spełniające rolę przycisków Wstecz i Dalej i przypisuje im identyfikatory prev i next. Tworzony jest też element listy rozwijanej o identyfikatorze goTo. Na liście tej zapisywane są numery dostępnych stron. Po utworzeniu tych wszystkich elementów wstawiane są do nawigacyjnego elementu div. Na zakończenie łącze Wstecz jest ukrywane, a w liście rozwijanej wybierana jest wartość 1. Następnie definiowana jest funkcja setDataAndEvents(). Chcąc nawigować pomiędzy poprzednimi i następnymi stronami, musimy znać numer aktualnej strony, tak żeby móc go powiększyć lub pomniejszyć podczas zmiany strony. Informację tę możemy uzyskać, wykorzystując funkcję biblioteki jQuery data(). Do elementu ul zapisujemy informację o kluczu currentPage i początkowej wartości 1. W kolejnym wierszu ukrywamy wszystkie te elementy li, których index jest większy niż 10, co oznacza, że nie mieszczą się na pierwszej stronie. W dalszej części definiowane są funkcje obsługujące kliknięcia łączy Wstecz i Dalej. Przy kliknięciu tego pierwszego pobieramy wartość currentPage, zmniejszamy ją o 1 i przekazujemy do funkcji goToPage(). Podobnie kliknięcie łącza Dalej powoduje zwiększenie wartości currentPage o 1 i przekazanie jej do funkcji goToPage(). Do zdarzenia change listy rozwijanej również dołączamy funkcję, która przekazuje funkcji goToPage() wartość wybraną aktualnie z listy. Funkcja goToPage() pobiera jeden parametr o nazwie pageNumber. Wartość tego parametru określa numer strony, na którą chcemy przejść. Musimy tutaj sprawdzić dwie rzeczy. Jeżeli użytkownik jest na pierwszej stronie, to ukrywamy łącze Wstecz, a na ostatniej stronie ukrywamy łącze Dalej. Następnie aktualizujemy zmienną currentPage i wpisujemy tę samą wartość do listy rozwijanej z numerami stron. Na koniec trzeba jeszcze zdecydować, które tytuły filmów mają zostać wyświetlone na aktualnej stronie. W tym celu wyliczamy wartości dwóch zmiennych: to i from. Ostatnie trzy wiersze ukrywają wszystkie pozycje listy filmów z wyjątkiem tych znajdujących się w zakresie od from do to.
Dodawanie funkcji automatycznych podpowiedzi do pól tekstowych Chyba najlepszym przykładem zastosowania funkcji automatycznych podpowiedzi jest strona główna firmy Google. Wpisując w polu tekstowym treść zapytania, możemy zauważyć, że poniżej wyświetlana jest lista proponowanych zapytań, pasujących do wprowadzonego przez nas tekstu.
267
PHP i jQuery. Receptury
Przygotujemy tutaj bardzo podobne rozwiązanie, w którym tekst wprowadzany przez użytkownika będzie porównywany z nazwami użytkowników zapisanymi w bazie, a pasujące pozycje będą wyświetlane na formularzu jako lista sugestii. Użytkownik będzie mógł wtedy użyć klawiszy strzałek, żeby wybrać właściwą nazwę.
Przygotowania W katalogu rozdzial8 utwórz nowy katalog o nazwie receptura6. W tej recepturze będziemy potrzebowali jeszcze tabeli z listą nazw użytkowników. Otwórz zatem narzędzie phpMyAdmin i utwórz nową tabelę users, nadając jej następującą strukturę. CREATE TABLE `users` ( `id` int(11) NOT NULL AUTO_INCREMENT, `username` varchar(32) NOT NULL, `password` varchar(32) NOT NULL, PRIMARY KEY (`id`) ); INSERT INTO `users` (`id`, `username`, `password`) VALUES (1, 'holmes', 'sherlockholmes'), (2, 'watson', 'johnwatson'), (3, 'sati', 'pranay'), (4, 'mantu', 'ajayjoshi'), (5, 'sahji', 'brijsah'), (6, 'vijay', 'vijayjoshi'), (7, 'brij', 'brijsah'), (8, 'arjun', 'samant'), (9, 'jyotsna', 'sonawane'), (12, 'ravindra', 'pokharia'), (13, 'prakash', 'joshi'), (14, 'sahji2', 'aloklal'), (15, 'basant', 'bhandari'), (16, 'ajay', 'gamer')
Jak to zrobić? 1. W katalogu receptura6 utwórz nowy plik o nazwie index.html. Wpisz do niego kod HTML tworzący element div klasy autosuggest, a wewnątrz niego pole tekstowe o identyfikatorze suggest oraz listę wypunktowaną o identyfikatorze suggestions. To w tej liście będziemy wyświetlać pasujące wyniki wyszukiwania. Utwórz też znacznik obrazka, w którym umieścimy obracający się znaczek informujący o ładowaniu danych. Będzie on wyświetlany podczas pobierania danych z bazy. Na zakończenie utwórz jeszcze element span o identyfikatorze error, w którym będziemy umieszczać informację o braku pasujących nazw użytkownika.
268
Rozdział 8. • Wiązanie danych w PHP i jQuery
Automatyczne podpowiedzi
2. Proszę zauważyć, że w sekcji head odwołujemy się do pliku style.css. W tym przykładzie atrybuty CSS są niezmiernie ważne, ponieważ musimy umieścić element ul w odpowiednim miejscu na stronie, tuż pod polem tekstowym. Utwórz zatem nowy plik o nazwie style.css i wpisz do niego poniższe style: body{ font-family: "Trebuchet MS", verdana, arial;width:400px;margin:0 auto; } .autosuggest { width:200px; top:5px; position:relative; } input { width:200px;} #suggestions { position:absolute; list-style:none; margin:0; padding:0; width:200px; display:none; background-color:#ECECF6; top:20px; left:0px; } #suggestions li { cursor:pointer; padding:5px; border-right:1px solid #000; border-bottom:1px solid #000;
3. Skupmy się teraz na wykorzystaniu biblioteki jQuery, dlatego tuż przez zamykającym znacznikiem body dołącz plik jquery.js. Zdefiniuj cztery funkcje obsługi zdarzeń, które będą odpowiadały za pobieranie podpowiedzi z bazy danych i wyświetlanie ich we właściwym miejscu na stronie. Do zdarzenia keyup pochodzącego z pola tekstowego podłącz funkcję getSuggestions(). Jest to główna funkcja naszego rozwiązania, która pobierając kolejne naciśnięte przez użytkownika klawisze, pobiera podpowiedz za pomocą żądań AJAX. Wartość znajdująca się w polu tekstowym wysyłana jest w żądaniu do serwerowego skryptu suggestions.php. Po otrzymaniu odpowiedzi z serwera uruchamiana jest funkcja showSuggestions(), która tworzy listę na podstawie otrzymanych danych i wyświetla ją pod polem tekstowym. 4. Funkcja navigaeList() wywoływana będzie przy każdym zdarzeniu keydown. Pozwoli ona nawigować w liście podpowiedzi za pomocą klawiszy strzałki w górę i w dół, a klawisz Enter będzie umożliwiał wybranie jednej z pozycji. Kolejne dwie funkcje będą obsługiwać zdarzenia myszy. Pierwsza — listHover() — będzie uruchamiana, w momencie gdy wskaźnik myszy znajdzie się nad elementem listy z podpowiedziami, zmieniając wygląd tego elementu. Drugą funkcję — listClick() — wykorzystamy do wypełnienia pola tekstowego wartością elementu listy klikniętego przez użytkownika.
5. W tym samym katalogu utwórz kolejny plik o nazwie suggestions.php. Skrypt z tego pliku powinien łączyć się z bazą danych exampleDB i uruchamiać w niej zapytanie wyszukujące w tabeli users wartości podobnych do pobranej z parametru żądania AJAX.
272
Rozdział 8. • Wiązanie danych w PHP i jQuery
Po uzyskaniu odpowiedzi należy zapisać ją w ciągu znaków JSON i wysłać do przeglądarki. 6. Uruchom plik index.html w przeglądarce i naciśnij dowolny klawisz. Wysłane zostanie żądanie AJAX, a wyniki pasujące do wprowadzonego tekstu pojawią się w postaci listy. Poniżej przedstawiam przykład listy podpowiedzi wyświetlanej po wpisaniu znaku a.
Jak to działa? Najpierw musimy się upewnić, że element ul będzie się zawsze pojawiał poniżej pola tekstowego. Istnieje tu bardzo prosty sposób realizacji. Po pierwsze pozycja zewnętrznego elementu div musi być względna (atrybut position:relative), co zapisujemy w pliku CSS. Teraz wszystkie elementy znajdujące się w tym elemencie div mogą otrzymać pozycję bezwzględną (position:absolute), liczoną względem współrzędnych elementu bazowego. Oznacza to, że poniższe właściwości CSS umieszczą element ul tuż pod polem tekstowym. position:absolute; top:20px; left:0px;
Pozostałe właściwości definiują już tylko ogólny wygląd listy podpowiedzi. W podobny sposób po prawej stronie umieszczamy rysunek informacji o ładowaniu danych. Teraz przystępujemy do implementowania mechanizmu automatycznych podpowiedzi. Na początek zajmiemy się funkcją obsługującą zdarzenie keyup pochodzące z pola tekstowego, która
273
PHP i jQuery. Receptury
wywołuje funkcję getSuggestions(). Pobiera ona wartość z pola tekstowego i kontynuuje prace tylko wtedy, gdy w polu tym został wprowadzony jakiś tekst. Następnie sprawdza, jaki klawisz został właśnie naciśnięty przez użytkownika, odczytując udostępnianą przez bibliotekę jQuery wartość event.which. Naciśnięcie klawiszy z zakresu a – z, A – Z, Delete lub Backspace spowoduje zmianę zawartości pola tekstowego, a zatem możemy pobrać znajdujący się w nim tekst i wysyłamy go do skryptu suggestions.php za pomocą żądania AJAX. Do obsługi odpowiedzi z tego żądania stosujemy natomiast funkcję showSuggestions(). W odpowiedzi może ona otrzymać tablicę pasujących nazw użytkownika albo wartość false, jeżeli serwerowy skrypt nie znalazł żadnych sugestii. W przypadku otrzymania wartości false ograniczamy się tylko do wyświetlenia komunikatu. Jeżeli jednak skrypt zwrócił nam tablicę wartości, to iterujemy po niej i z kolejnych jej wartości tworzymy elementy listy podpowiedzi. Po przejrzeniu całej tablicy wstawiamy otworzone elementy li do zbiorczego elementu ul o identyfikatorze suggestions. Tuż przed wysłaniem żądania wyświetlamy jeszcze obrazek z informacją o pobieraniu danych, a po otrzymaniu odpowiedzi funkcja showSuggestions() go ukrywa. Chcemy mieć możliwość wybierania najlepszej podpowiedzi za pomocą klawiszy strzałek i klawisza Enter. Przesuwając się w górę i w dół listy, wyróżniamy jeden z jej elementów za pomocą klasy CSS. W tym celu zdefiniowaliśmy funkcję navigateList() obsługującą zdarzenie keyDown. Za pomocą instrukcji switch obsługuje ona trzy różne przypadki. Pierwszym jest naciśnięcie klawisza strzałki w górę (kod klawisza 38). Sprawdzamy, czy któryś z elementów listy ma już przypisaną klasę active, a jeżeli takiego nie ma, to przypisujemy ją do ostatniego elementu listy. Jeżeli jednak znajdziemy element tej klasy, to funkcja usuwa klasę z tego elementu i przypisuje ją elementowi poprzedzającemu. W przypadku wykrycia naciśnięcia klawisza strzałki w dół postępujemy bardzo podobnie. Jeżeli nie jest zaznaczony żaden element listy, to zaznaczana jest jej pierwsza pozycja. Jeżeli jednak jeden z elementów jest już zaznaczony, to klasa active jest z niego usuwana, a nadawana jest następnemu elementowi. Trzecim i ostatnim przypadkiem jest naciśnięcie klawisza Enter o kodzie 13. W takiej sytuacji kod HTML aktualnie wybranego elementu listy jest wstawiany do pola tekstowego, a cały element ul zawierający podpowiedzi zostaje ukryty. Po zadbaniu o obsługę klawiatury musimy przyjrzeć się też funkcjom umożliwiającym obsługiwanie podpowiedzi za pomocą myszy. Umieszczenie wskaźnika myszy nad elementem listy powinno skutkować nadaniem temu elementowi klasy active, a przesunięcie wskaźnika poza ten element powinno spowodować usunięcie klasy. Oprócz tego kliknięcie jednej z podpowiedzi powinno przenieść jej zawartość do pola tekstowego. Ze względu na to, że początkowo w elemencie ul nie ma żadnych pozycji listy, funkcję listHover() przypisujemy do nich za pomocą metody live(). Będzie ona uruchamiana przy każdym wskazaniu elementu listy myszą, przesunięcia wskaźnika poza ten element albo kliknięcia elementu. W samej funkcji sprawdzamy, czy wywołana została zdarzeniem mouseover, a wtedy usuwamy klasę active z dowolnego wybranego aktualnie elementu, następnie wywołujemy funkcję toggleClass(), aby dodać lub usunąć tę klasę ze wskazywanego myszą elementu. W ten sposób klasa active będzie przypisywana elementowi wskazywanemu myszą i usuwana z każdego niewskazywanego elementu. 274
Rozdział 8. • Wiązanie danych w PHP i jQuery
Na zakończenie funkcja listHover() sprawdza, czy kliknięty został element li, a wtedy pobieramy zapisany w nim tekst HTML i umieszczamy go w polu tekstowym. Ostatecznie element ul jest opróżniany, a kursor umieszczany jest w polu tekstowym. Po stronie serwera skrypt suggestions.php odbiera przekazany w żądaniu tekst z pola tekstowego i poszukuje go w tabeli users, aby odnaleźć pasujące podpowiedzi. $query = 'SELECT username FROM users where username like "%'. $_GET['input']. '%"';
Zastosowanie znaku procentu (%) przed i za treścią pola tekstowego oznacza, że za lub przed podaną wartością mogą znajdować się jeszcze inne znaki. Oznacza to, że wprowadzona wartość sa zostanie dopasowana do słowa osa, ale także do słowa samochód. Po pobraniu wyników z bazy danych iterujemy po nich i zapisujemy do tablicy, którą po skonwertowaniu na format JSON wysyłamy do przeglądarki. Muszę tutaj też wspomnieć o bardzo ważnej zmiennej xhr, którą deklarowaliśmy już na samym początku pliku. Jeżeli użytkownik naciśnie wiele klawiszy, to do serwera zostanie wysłanych wiele żądań jednocześnie. Aby uniknąć takiej sytuacji, przypisujemy do zmiennej xhr obiekt otrzymany od funkcji getJSON(). Następnie przed wysłaniem żądania do serwera możemy przerwać ewentualne wcześniejsze żądania metodą abort(), tak żeby znaczenie miało tylko ostatnio wysłane żądanie.
Zobacz też Q Recepturę „Tworzenie skrótów klawiszowych” z rozdziału 1.
Tworzenie chmury znaczników Chmura znaczników jest wizualną reprezentacją słów kluczowych, w której wielkość i kolor danego słowa określa jego wagę. Wyobraźmy sobie bloga z wieloma artykułami, którym przypisano znaczniki kategorii, takich jak PHP, jQuery, XML, JSON itd. Jeżeli z kategorią PHP związanych jest 50 artykułów, z kategorią jQuery 30 artykułów, z XML 10, a z JSON 22 artykuły, to możemy powiedzieć, że znacznik PHP ma największą wagę, a znacznik XML najmniejszą. Jeżeli chcielibyśmy zaprezentować te znaczniki w formie graficznej, to ważniejsze słowa powinny zostać bardziej wyróżnione, co możemy zrealizować przez zastosowanie odpowiednio powiększonej i pogrubionej czcionki. Przygotujemy tu podobne rozwiązanie. Będziemy w nim pobierać z bazy danych listę miast, którym przypisywana jest ocena w skali od 0 do 100. Wszystkie te znaczniki zaprezentujemy w postaci chmury znaczników, w której wielkości poszczególnych znaczników będą uzależnione od oceny miasta.
275
PHP i jQuery. Receptury
Przygotowania W katalogu rozdzial8 utwórz nowy katalog o nazwie receptura7. Utwórz też w bazie danych tabelę o nazwie cities, stosując poniższe zapytanie SQL, którego możesz użyć w panelu phpMyAdmin. CREATE TABLE `cities` ( `id` int(3) NOT NULL AUTO_INCREMENT, `cityName` varchar(32) NOT NULL, `cityRating` int(3) NOT NULL, PRIMARY KEY (`id`) ); INSERT INTO `cities` (`id`, `cityName`, `cityRating`) VALUES (1, 'Udaipur', 71), (2, 'Leh', 55), (3, 'Mahabaleshwar', 28), (4, 'Mount Abu', 31), (5, 'Rishikesh', 15), (6, 'Hampi', 81), (7, 'Matheran', 29), (8, 'Manali', 85), (9, 'Mysore', 33), (10, 'Jaipur', 55), (11, 'Munnar', 89), (12, 'Bangalore', 66), (13, 'Wayanad', 42), (14, 'Amritsar', 29), (15, 'Gangtok', 69), (16, 'Havelock Islands', 27), (17, 'DharamShala', 57), (18, 'Kashmir', 78), (19, 'Tirupati', 22), (20, 'Goa', 75)
Jak to zrobić? 1. W katalogu receptura7 utwórz nowy plik o nazwie index.html. W tym pliku umieść znacznik div o identyfikatorze cloud i zdefiniuj style CSS dla tego elementu oraz znaczników a, które będziemy tworzyć na stronie. Chmura znaczników
Najczęściej odwiedzane miasta w Indiach
2. Przed zamykającym znacznikiem body dołącz plik biblioteki jQuery. Dopisz też kod wysyłający żądanie AJAX skierowane do pliku tags.php. Odpowiedź tego żądania powinna zostać obsłużona przez funkcję createTagCloud(). Będzie ona iterować po elementach odpowiedzi i tworzyć na ich podstawie chmurę znaczników.
277
PHP i jQuery. Receptury
3. Utwórz kolejny plik o nazwie tags.php. Zapisany w nim skrypt będzie łączył się z bazą danych i pobierał z nich informacje z tabeli cities. Na podstawie uzyskanych w ten sposób danych utworzymy ciąg znaków JSON i wyślemy go do przeglądarki, gdzie biblioteka jQuery utworzy chmurę znaczników. query($query)) { if ($result->num_rows > 0) { while($row = $result->fetch_assoc()) { array_push($arr, array('city' => $row['cityName'], 'rating' => $row['cityRating'])); } } } $result = array('tags' => $arr); header('Content-Type:text/json'); echo json_encode($result); ?>
4. Uruchom w przeglądarce plik index.php. Zobaczysz kolekcję nazw miast wyświetlonych w różnych kolorach i rozmiarach.
278
Rozdział 8. • Wiązanie danych w PHP i jQuery
Jak to działa? Po załadowaniu dokumentu HTML za pomocą metody getJSON() wysyłane jest żądanie AJAX skierowane do skryptu tags.php. Po otrzymaniu odpowiedzi wywoływana jest funkcja create ´TagCloud(). W pliku tags.php uruchamiane jest zapytanie SELECT, które pobiera z bazy nazwy miast oraz przypisane im oceny. Następnie wywołujemy metodę fetch_assoc(), aby odczytać dane z poszczególnych wierszy i umieścić je w asocjatywnej tablicy $arr. Po wypełnieniu tablicy $arr danymi przypisujemy je do tablicy asocjatywnej $result, stosując słowo tags jako klucz. Na zakończenie ustalamy typ odpowiedzi na text/json i przekształcamy tablicę $result w ciąg znaków JSON, przekazując ją metodzie json_encode(). Wynikowy ciąg znaków powinien wyglądać tak, jak na poniższym rysunku:
Teraz odpowiedź przekazywana jest do funkcji createTagCloud(), w ramach parametru o nazwie response. Za pomocą metody each() pochodzącej z biblioteki jQuery iterujemy po tablicy tags zapisanej w obiekcie JSON. Dla każdego elementu ustalamy różny kolor znacznika, sprawdzając
279
PHP i jQuery. Receptury
wartość zmiennej i. Wielkość czcionki znacznika ustalamy natomiast, dzieląc wartość oceny przez 30. Można oczywiście wybrać dowolny inny dzielnik zależnie od tego, jak wielkie lub jak małe chcemy uzyskać znaczniki. Po wybraniu wielkości i koloru czcionki tworzymy znacznik a, przypisujemy mu wszystkie wartości i dopisujemy do zmiennej str. Po zakończeniu iterowania po tablicy wstawiamy wartość zmiennej str do elementu div o identyfikatorze cloud. W efekcie powstaje wspaniała chmura znaczników.
Zobacz też Q Recepturę „Tworzenie danych w formacie JSON za pomocą PHP” z rozdziału 4. Q Recepturę „Korzystanie z danych w formacie JSON za pomocą jQuery” z rozdziału 4.
280
9 Rozbudowywanie stron za pomocą PHP i jQuery W tym rozdziale zajmiemy się: Q wysyłaniem żądań między domenami z wykorzystaniem serwera proxy, Q tworzeniem międzydomenowych żądań za pomocą biblioteki jQuery, Q tworzeniem strony przewijającej się w nieskończoność, Q tworzeniem wtyczki do biblioteki jQuery, Q wyświetlaniem kanałów RSS za pomocą PHP i jQuery.
Wprowadzenie W ostatnim rozdziale przyjrzymy się zaawansowanym technikom, których można użyć do rozbudowania funkcji oferowanych przez aplikację WWW. Przygotujemy tu kilka przykładów, w których będziemy szukać obrazów w usłudze Flickr i filmów na YouTubie, wykorzystując do tego API tych usług. Za pomocą biblioteki jQuery odczytamy też dane z kanału RSS zapisane w formacie XML i nauczymy się tworzyć przewijaną w nieskończoność stronę, taką jak w Google Reader albo w nowej wersji Twittera. Oprócz tego będziemy tworzyć wtyczki do biblioteki jQuery, których będziemy mogli użyć w dowolnej tworzonej później aplikacji WWW.
PHP i jQuery. Receptury
Wysyłanie żądań między domenami z wykorzystaniem serwera proxy Ze względów bezpieczeństwa przeglądarki nie pozwalają skryptom na wysyłanie żądań pomiędzy domenami. Oznacza to, że skrypt uruchomiony w domenie http://www.abc.com nie może wysłać żądania AJAX do domeny http://www.xyz.com. W tej recepturze dowiemy się, jak można obejść to ograniczenie za pomocą skryptów PHP działających po stronie serwera. Przygotujemy tu przykład pozwalający na wyszukiwanie obrazów w usłudze Flickr, która zwraca dane w formacie JSON, a te po przetworzeniu w bibliotece jQuery umożliwią nam wyświetlenie obrazków na naszej stronie. Na poniższym rysunku można zobaczyć przykład odpowiedzi serwera Flickr w formacie JSON.
Przygotowania W katalogu rozdzial9 utwórz nowy katalog o nazwie receptura1.
282
Rozdział 9. • Rozbudowywanie stron za pomocą PHP i jQuery
Oprócz tego pobierz też klucz dostępu do API Flickr dostępny pod adresem http://www. flickr.com/services/api/keys/.
Jak to zrobić? 1. W katalogu receptura1 utwórz plik o nazwie index.html. Zapisz w nim kod HTML tworzący formularz z trzema polami: znacznik, liczba obrazków i rozmiar obrazków. Oprócz tego utwórz też element ul, w którym będziemy wyświetlać wyniki naszych zapytań. Szukanie obrazków w usłudze Flickr
W przeglądarce powinniśmy zobaczyć teraz stronę podobną do poniższej.
2. Dołącz teraz plik biblioteki jQuery, a następnie wpisz kod, który zajmie się wysłaniem żądania AJAX do serwerowego skryptu search.php. Jako parametry tego żądania podane zostaną wartości wprowadzone do formularza. Odpowiedź serwera obsłuży z kolei funkcja showImages(), która odczyta dane w formacie JSON i wyświetli na stronie zestaw obrazków.
3. Utwórz kolejny plik i nazwij go search.php. Zapisany w nim kod PHP nawiąże kontakt z API usługi Flickr i poda jej kryteria wyszukiwania. Po otrzymaniu odpowiedzi w formacie JSON zostanie ona odesłana do przeglądarki, gdzie biblioteka jQuery będzie mogła wyświetlić obrazki.
285
4. Teraz uruchom w przeglądarce plik index.html i wprowadź hasło wyszukiwania, wybierz liczbę zdjęć i ich wielkość, a na koniec kliknij przycisk Wyszukaj. Po kilku sekundach zobaczysz, że na stronie pojawiają się obrazki pobierane z usługi Flickr.
Jak to działa? Po kliknięciu przycisku Wyszukaj wartości z formularza wysyłane są do serwerowego skryptu search.php. Musimy się jednak skontaktować z serwerem Flickr i pobrać z niego obrazki. Interfejs API tej usługi definiuje kilka metod dostępu do obrazków. Wykorzystamy tu metodę flickr.photos.search() pozwalającą na wyszukiwanie hasłowe. Oprócz nazwy metody w adresie URL musimy zamieścić jeszcze kilka innych parametrów: Q api_key — jest to parametr obowiązkowy. Własny klucz można uzyskać pod adresem
http://www.flickr.com/services/api/keys/.
286
Rozdział 9. • Rozbudowywanie stron za pomocą PHP i jQuery
Q tags — hasła do wyszukiwania. Można je podać w postaci listy rozdzielanej
przecinkami. Wpiszemy tu wartość z pola tekstowego. Q per_page — Liczba obrazków prezentowanych na stronie. Maksymalnie może ich być 99. Podamy tu wartość z listy rozwijanej numImages. Q format — Można wybrać format JSON, XML i inne. W naszym przykładzie
wykorzystamy format JSON. Q nojsoncallback — Należy tu wpisać wartość 1, jeżeli nie chcemy, żeby Flickr opakował dane JSON własną funkcją. Po przygotowaniu adresu URL możemy skontaktować się z serwerem Flickr, aby pobrać z niego dane. W tym celu używamy funkcji języka PHP file_get_contents(), która pobierze nam ciąg znaków JSON ze wskazanego adresu URL. Uzyskany w ten sposób ciąg znaków zostanie przesłany do przeglądarki. Biblioteka jQuery odbierze dane w formacie JSON w ramach funkcji showImages(). W pierwszej kolejności funkcja ta sprawdzi status odpowiedzi. Jeżeli będzie to wartość OK, to możemy z odpowiedzi pobrać elementy typu photo, a następnie iterować po nich za pomocą metody each(). Aby wyświetlić pojedynczy obrazek, musimy najpierw poznać jego adres URL, który możemy uzyskać, składając ze sobą różne parametry obiektu photo. Według dokumentacji API Flickr adres URL należy konstruować według poniższego wzorca: http://farm{farm-id}.static.flickr.com/{server-id}/{id}_{secret}_[size].jpg
Oznacza to, że z obiektu photo musimy pobrać parametry farmId, serverId, id oraz secret. Ostatni parametr — size — możemy zdefiniować samodzielnie, wybierając jedną z poniższych wartości: Q s — małe kwadraciki, Q t — miniaturki, Q - — średnie obrazki, Q b — duże obrazki, Q o — oryginalna wielkość.
Wielkość obrazka wybraliśmy już wcześniej na formularzu. Teraz wystarczy tylko połączyć ze sobą wszystkie te wartości i już możemy pobierać obrazki z serwerów Flickr. Każdy z nich umieszczamy w elemencie li i powtarzamy ten sam krok dla wszystkich obrazków. Na koniec utworzoną listę wstawiamy do elementu ul o identyfikatorze results.
Zobacz też Q Recepturę „Tworzenie międzydomenowych żądań za pomocą biblioteki jQuery”.
287
PHP i jQuery. Receptury
Tworzenie międzydomenowych żądań za pomocą biblioteki jQuery W poprzedniej recepturze zademonstrowałem sposób użycia skryptu PHP jako pośrednika przy uruchamianiu międzydomenowych żądań AJAX. W tej recepturze wykorzystamy specyfikację JSONP, aby wykonywać międzydomenowe żądania bezpośrednio z biblioteki jQuery. Przygotujemy tu rozwiązanie, w którym będziemy wyszukiwać filmy w usłudze YouTube i wyświetlać je w postaci listy. Kliknięcie miniaturki filmu otworzy nowe okno przeglądarki, w którym użytkownik będzie mógł obejrzeć wybrany film. Na kolejnym rysunku można zobaczyć przykładową odpowiedź serwera YouTube w formacie JSON.
Przygotowania W katalogu rozdzial9 utwórz nowy katalog o nazwie receptura2.
Jak to zrobić? 1. W katalogu receptura2 utwórz nowy plik i nazwij go index.html. Wpisz do niego kod HTML tworzący formularz z pojedynczym polem tekstowym oraz element div o identyfikatorze results, w którym będziemy umieszczać wyniki wyszukiwania. Szukanie filmów na YouTubie
2. Przed zamykającym znacznikiem body dołącz plik jquery.js. Teraz dopisz kod JavaScript, który pobierze kryterium wyszukiwania i będzie próbował uzyskać odpowiedź od serwera YouTube. Obsługująca tę odpowiedź funkcja showVideoList() przygotuje listę filmów i wyświetli ją na stronie.
3. I już wszystko gotowe, jesteśmy gotowi do wyszukiwania filmów na YouTubie. Uruchom w przeglądarce plik index.html i wprowadź hasło wyszukiwania. Po kliknięciu przycisku Szukaj zobaczysz listę filmów wraz z liczbą komentarzy oraz oceną.
291
PHP i jQuery. Receptury
Jak to działa? Znaczniki script stanowią wyjątek od zasady „tego samego źródła” (ang. same origin policy). Możemy to wykorzystać, żeby podać adres URL w atrybucie src znacznika script, a następnie opakować surową postać odpowiedzi w funkcję wywołania zwrotnego. W ten sposób odpowiedź nie będzie traktowana jak dane, ale jak kod JavaScript, który zostanie wykonany przez przeglądarkę. Adres URL wyszukiwania filmów w serwisie YouTube wygląda następująco: http://gdata.youtube.com/feeds/api/videos?q=' + query + '&alt=json-in-script
Parametr q definiuje zapytanie, które wprowadziliśmy do pola tekstowego, natomiast parametr alt określa rodzaj odpowiedzi, jaką chcemy otrzymać. Ze względu na to, że zamiast formatu JSON używamy tym razem formatu JSONP, w parametrze alt podajemy wartość json-in-script, zgodnie
292
Rozdział 9. • Rozbudowywanie stron za pomocą PHP i jQuery
z zaleceniami API serwisu YouTube. W momencie otrzymania odpowiedzi uruchamiana jest funkcja wywołania zwrotnego showVideoList(). Na początku sprawdza ona, czy w ogóle otrzymaliśmy jakieś wyniki, i ewentualnie wyświetla odpowiedni komunikat o błędzie. W kolejnym kroku pobieramy wszystkie elementy odpowiedzi i iterujemy po nich w ramach pętli for. Dla każdego filmu pobieramy wartości parametrów videoURL, thumbnail, thumbnailWidth, thumbnailHeight, numComments i rating. Następnie możemy wykorzystać pobrane wartości do przygotowania kodu HTML tworzącego listę z poszczególnymi filmami. Każdy z nich znajdzie się w znaczniku a, którego atrybutowi href przypisana zostanie wartość videoURL. Wewnątrz znacznika a znajdzie się jeszcze miniaturka filmu oraz znacznik p zawierający dane o liczbie komentarzy i ogólnej ocenie tego filmu. Po utworzeniu pełnego kodu HTML zostanie on wstawiony do elementu div o identyfikatorze result.
I coś jeszcze Co to jest JSONP Więcej informacji na temat formatu JSONP można znaleźć pod adresami: Q http://remysharp.com/2007/10/08/what-is-jsonp/ Q http://en.wikipedia.org/wiki/JSON#JSONP
Zobacz też Q Recepturę „Wysyłanie żądań między domenami z wykorzystaniem serwera proxy”.
Tworzenie strony przewijającej się w nieskończoność Jeżeli ktoś używa usługi Google Reader lub nowej wersji Twittera, to dokładnie wie, o czym będziemy mówić. W obu aplikacjach po przewinięciu strony na sam dół doładowywana jest dodatkowa treść, która doklejana jest jako ciąg dalszy strony. W ten sposób eliminowana jest konieczność podziału na strony i wstawiania przycisków Dalej i Wstecz. W tej recepturze przygotujemy przykład realizujący bardzo podobną funkcję. Po przewinięciu strony do dolnej krawędzi zostanie wysłane żądanie AJAX i dodatkowe dane zostaną załadowane ze skryptu PHP, a następnie dołączone jako ciąg dalszy strony.
293
PHP i jQuery. Receptury
Przygotowania W katalogu rozdzial9 utwórz nowy katalog o nazwie receptura3.
Jak to zrobić? 1. W katalogu receptura3 utwórz nowy plik i nazwij go index.html. Do tego pliku wpisz kod HTML tworzący element div o identyfikatorze container oraz kilka akapitów, dzięki którym strona stanie się naprawdę długa i będzie wymagała przewijania. Następnie utwórz kolejny akapit, którym będzie się pojawiać komunikat o ładowaniu danych, w czasie gdy będziemy je pobierać z serwera. Niekończące się przewijanie
Akapit testowy 1
Akapit testowy 2
Akapit testowy 3
Akapit testowy 4
Akapit testowy 5
Akapit testowy 6
Akapit testowy 7
Akapit testowy 8
Akapit testowy 9
Akapit testowy 10
Akapit testowy 11
Akapit testowy 12
Akapit testowy 13
Akapit testowy 14
Akapit testowy 15
Akapit testowy 16
Akapit testowy 17
Akapit testowy 18
Akapit testowy 19
Akapit testowy 20
Ładowanie danych...
294
Rozdział 9. • Rozbudowywanie stron za pomocą PHP i jQuery
2. Przed zamykającym znacznikiem body dołącz plik biblioteki jQuery. Dopisz kod JavaScript, który dołączy funkcję obsługującą zdarzenie przewijania zawartości okna. Jeżeli użytkownik dotrze do dolnej krawędzi, to wysłane zostanie żądanie AJAX do pliku data.php. Otrzymane od niego dane zostaną dołączone do już istniejących.
3. Po stronie serwera utwórz plik data.php. Zapisz w nim skrypt odsyłający po prostu krótki tekst do przeglądarki.
295
PHP i jQuery. Receptury
echo '
Te dane zostały załadowane z serwera...
';
?>
4. Uruchom w przeglądarce plik index.html. Zobaczysz na stronie listę akapitów, którą można przewijać za pomocą myszy lub klawiatury. Po przewinięciu strony na sam dół pojawi się informacja o pobieraniu danych z serwera.
5. Po krótkiej chwili dane zostaną załadowane, ze strony zniknie informacja o komunikacji z serwerem, ale za to pojawi się tekst przesłany przez skrypt PHP.
296
Rozdział 9. • Rozbudowywanie stron za pomocą PHP i jQuery
Jak to działa? Na początek do zdarzenia przewijania zawartości okna przypięliśmy obsługującą je funkcję. Podczas przewijania strony za pomocą myszy lub klawiszy strzałek wywoływana jest funkcja loadData(). Zanim jednak załadujemy jakiekolwiek dane, musimy się upewnić, że użytkownik rzeczywiście przewinął stronę na sam dół. W tym celu wywołujemy funkcję isUserAtBottom(), która określa aktualną pozycję strony za pomocą poniższych obliczeń: return ((($(document).height() - $(window).height()) - $(window).scrollTop()) ´<= 50) ? true : false;
Wyrażenie $(document).height() zwraca całkowitą wysokość strony HTML, natomiast $(window). ´height() opisuje wysokość widocznej w przeglądarce części strony, a $(window).scrollTop() zwraca pozycję pionowego paska przewijania. Ostateczną wartość wyliczamy zatem, odejmując pozycję paska przewijania i wysokość okna od całkowitej wysokości strony. Jeżeli ta wartość jest mniejsza niż 50, to znaczy, że strona została przewinięta do pozycji mniejszej niż 50 pikseli od dołu. Na podstawie tych obliczeń funkcja zwraca wartość true lub false. Gdy mamy już pewność, że użytkownik przewinął stronę na sam dół, możemy wywołać funkcję getData(), która na początek odłącza obsługę zdarzenia przewijania okna, tak żeby do zakończenia obsługi tego żądania nie były wysyłane kolejne. Następnie wyświetlana jest informacja o ładowaniu danych i wysyłane jest żądanie AJAX do pliku data.php. W naszym przykładzie skrypt ten odsyła tylko jeden wiersz tekstu. Gdy przygotowana na serwerze odpowiedź dociera do przeglądarki, ukrywany jest komunikat o ładowaniu danych, a otrzymany tekst dodawany jest do elementu div o identyfikatorze container. Funkcja obsługująca zdarzenie przewijania strony jest ponownie aktywowana, na wypadek gdyby użytkownik chciał załadować jeszcze więcej danych. Proces ten będzie powtarzany tak długo, jak długo wartość zmiennej counter będzie mniejsza od 5. Oznacza to, że tylko pięć razy będziemy mogli pobrać dane z serwera.
I coś jeszcze Ładowanie danych z innych źródeł W tym przykładzie odsyłaliśmy tylko wiersz tekstu przygotowany w skrypcie PHP. W rzeczywistych aplikacjach dane pobierane są z baz danych lub za pośrednictwem interfejsów API. Oznacza to, że powinniśmy założyć sytuację, w której nie ma już więcej danych do załadowania, i odpowiednio zakomunikować to użytkownikowi.
297
PHP i jQuery. Receptury
Tworzenie wtyczki do biblioteki jQuery W tej recepturze dowiemy się, jak można tworzyć proste wtyczki do biblioteki jQuery. Użytkownik będzie mógł wprowadzić na stronie dwie liczby, a nasza wtyczka zajmie się odliczaniem od pierwszej do drugiej liczby, zachowując się jak stoper. Naszą wtyczkę nazwiemy Licznik pieniędzy, a w jej ustawieniach będziemy mogli zdefiniować szybkość działania animacji.
Przygotowania W katalogu rozdzial9 utwórz nowy katalog o nazwie receptura4.
Jak to zrobić? 1. W katalogu receptura4 utwórz nowy plik i nazwij go index.html. Do pliku wpisz kod HTML tworzący dwa pola tekstowe na liczbę początkową i końcową, element h1, w którym będzie wyświetlana zmieniająca się wartość, oraz przycisk uruchamiający cały proces. Licznik pieniędzy
298
Rozdział 9. • Rozbudowywanie stron za pomocą PHP i jQuery
2. Następnie utwórz jeszcze jeden plik i nazwij go jquery.counter.js. Wpisz do niego przedstawiony poniżej kod naszej wtyczki: (function( $ ) { $.fn.cashCounter = function(options) { return this.each(function() { settings = $.extend ( { start: 0, end: 0, step: .5 }, options ); var e = $(this); if(isNaN(settings.start) || isNaN(settings.end) || ((settings.start) == (settings.end))) { return this; } settings.increasing = (settings.start < settings.end) ? true : false; if(settings.increasing) { if(settings.start >= settings.end) { return this;
3. Wróć teraz do pliku index.html i dołącz do niego plik jquery.js i utworzony przed chwilą plik wtyczki jquery.counter.js. Oprócz tego napisz też kod funkcji obsługującej kliknięcia przycisku, która będzie pobierała wartości z pola tekstowego i przekazywała je do naszej wtyczki.
4. Otwórz w przeglądarce plik index.html i wpisz do pól tekstowych Początek i Koniec dwie liczby, a następnie kliknij przycisk Zmień. Odliczanie rozpocznie się od wartości początkowej i będzie trwało aż do osiągnięcia wartości końcowej. Niestety w książce nie mam możliwości pokazania animacji, dlatego prezentuję tylko zrzut ekranu wykonany w trakcie jej trwania. Możesz też spróbować zmieniać wartość parametru step, aby zobaczyć, jak zachowuje się wolniejsze i szybsze odliczanie.
Jak to działa? Wtyczka cashCounter podczas inicjalizacji przyjmuje trzy parametry: start, end i step. Wartości parametrów start i end raczej nie wymagają dodatkowego opisu. Z kolei parametr step używany jest do definiowania szybkości odliczania. Jego wartość można zmieniać w zakresie od 0.1 do 0.9, przy czym wartość 0.1 oznacza najszybszą animację. Kod wtyczki zaczyna się od rozbudowania obiektu jQuery.fn. Naszą wtyczkę chcemy nazwać cashCounter, a zatem opakowujemy ją poniższym kodem: jQuery.fn.cashCounter = function(options) { };
301
PHP i jQuery. Receptury
Wewnątrz tego bloku kodu znajdzie się zatem całość naszej wtyczki. Następnie umieszczamy instrukcję return this.each(function(){}). Dzięki temu zyskujemy pewność, że obiekt biblioteki jQuery będzie zwracany do funkcji wywołującej, i utrzymamy możliwość stosowania łańcuchów wywołań, będących jedną z cech biblioteki jQuery. Następnie definiowany jest obiekt settings, który określa domyślne parametry pracy wtyczki, na wypadek gdyby nie zostały one podane w wywołaniu. Ostateczne parametry definiowane są przez połączenie podanych tu wartości domyślnych z obiektem options przekazanym przez użytkownika. Domyślnie wartość początkowa i końcowa jest równa zero, a parametr step otrzymuje wartość 0.5. Po wpisaniu tych wszystkich ustawień początkowych możemy przystąpić do tworzenia funkcji naszej wtyczki. Jeżeli parametry start lub end nie są wartościami liczbowymi albo jeżeli są sobie równe, to zatrzymujemy wykonanie kodu i wracamy do funkcji wywołującej. Następnie definiujemy właściwość increasing obiektu settings. Jeżeli wartość end jest większa od wartości start, to właściwość ta otrzymuje wartość true, a w przeciwnym wypadku wartość false. Teraz, jeżeli właściwość increasing ma wartość true, a wartość start jest większa od wartości end, kończymy pracę wtyczki. Podobnie, jeżeli właściwość increasing ma wartość false, a wartość end jest większa od wartości start, również kończymy pracę. W kolejnym kroku wyliczamy różnicę między wartościami start i end oraz wyliczamy wartość zmiennej changeBy, która w zależności od wartości zmiennej step będzie zmniejszała lub zwiększała wartość zmiennej start. Nowa wartość zmiennej start wstawiana jest również do elementu wywołującego wtyczkę, czyli w tym przypadku elementu h1 o identyfikatorze container. Na zakończenie wywołujemy jeszcze funkcję języka JavaScript setTimeout(), która wywoła funkcję cashCounter po upływie 100 milisekund. Przy każdym takim wywołaniu sprawdzane będą wszystkie warunki zdefiniowane w instrukcjach if, aż do osiągnięcia stanu nakazującego wyjście z funkcji.
Wyświetlanie kanałów RSS za pomocą PHP i jQuery W tej recepturze będziemy pobierać dane z kanału RSS (ang. Really Simple Syndication) pewnego bloga, wykorzystując do tego język PHP, i wyświetlać je na stronie za pomocą biblioteki jQuery. RSS jest standardowym formatem publikowania kanałów danych, choć wersji tego standardu istnieje już kilka. W tym przypadku będziemy używali wersji RSS 2.0, którego typową strukturę prezentuję poniżej.
302
Rozdział 9. • Rozbudowywanie stron za pomocą PHP i jQuery
Przygotowania W katalogu rozdzial9 utwórz nowy katalog o nazwie receptura5.
Jak to zrobić? 1. W katalogu receptura5 utwórz nowy plik i nazwij go index.html. W utworzonym pliku zdefiniuj kilka stylów CSS dla elementów strony, a następnie zdefiniuj na niej element div o identyfikatorze results, w którym będziemy wyświetlać dane pobrane z kanału. Kanał RSS
303
PHP i jQuery. Receptury
Ładowanie...
2. Przed zamykającym znacznikiem body dołącz plik biblioteki jQuery. Następnie wyślij żądanie AJAX do serwerowego pliku feed.php. W odpowiedzi otrzymamy dokument XML, który zostanie obsłużony przez funkcję showPosts(). Zdefiniuj tę funkcję tak, żeby na podstawie danych XML tworzyła odpowiadającą jej strukturę HTML, która ostatecznie zostanie wstawiona na stronę do elementu div o identyfikatorze results.
3. Teraz utwórz jeszcze plik feed.php. To właśnie tutaj będziemy pobierali dokument XML z kanału RSS o podanym adresie URL i wysyłali go do przeglądarki.
4. Uruchom plik index.html w przeglądarce. Na początek widoczny będzie tylko tekst informujący o ładowaniu danych. Po otrzymaniu odpowiedzi z serwera wyświetlona zostanie lista artykułów. Po kliknięciu jednego z nich rozwinięty zostanie ogólny opis treści, uzupełniony o datę publikacji oraz liczbę komentarzy. Dodatkowo dostępne będzie łącze Przeczytaj artykuł, którym będzie można otworzyć stronę z artykułem w nowym oknie.
305
PHP i jQuery. Receptury
Jak to działa? Po załadowaniu dokumentu DOM wywołane jest żądanie AJAX skierowane do pliku feed.php. W tym pliku wywoływana jest funkcja file_get_contents(), za pomocą której pobierana jest zawartość kanału RSS. Element rss jest zawsze głównym elementem dokumentu RSS XML, natomiast element channel jest jego podwęzłem zawierającym informacje o samym blogu oraz najnowszych artykułach. Każdy artykuł reprezentowany jest tutaj przez węzeł item. Możemy już teraz odesłać dokument XML do przeglądarki.
306
Rozdział 9. • Rozbudowywanie stron za pomocą PHP i jQuery
Po stronie klienta funkcja showPosts() zajmuje się obsługą odebranych danych XML, przekazanych jej w parametrze data. Biblioteka jQuery pozwala na korzystanie z dokumentów XML w dokładnie ten sam sposób, którego używamy wobec dokumentów HTML, a zatem pobieramy wszystkie artykuły za pomocą metody find(), która zwraca nam elementy item. var posts = $(data).find('channel>item');
Następnie iterujemy po zmiennej posts i przy każdym obiegu pobieramy wartości tytułu, łącza do treści artykułu, liczby komentarzy i daty publikacji. Korzystając z tych zmiennych, tworzymy kolejne elementy składające się na listę wypunktowaną. Tytuł artykułu umieszczany jest w nagłówku h3, za którym tworzony jest element div z krótkim opisem, łączem do całości tekstu, datą i liczbą komentarzy. Tak przygotowanemu elementowi div przypisywana jest jeszcze klasa content. W klasie tej właściwość display została wcześniej ustawiona na wartość none, w związku z tym zaraz po załadowaniu listy artykułów widoczne będą tylko ich nagłówki. Po zbudowaniu całej listy wstawiamy ją do elementu div o identyfikatorze results. Oprócz tego do elementów h3 dołączamy funkcję obsługującą zdarzenie click, która będzie wyszukiwała element div następujący po klikniętym nagłówku h3 i wywoływała dla niego funkcję slideToggle(). Oznacza to, że kliknięcie nagłówka będzie powodowało pojawienie się lub ukrycie podsumowania artykułu. Dopiero po kliknięciu łącza Przeczytaj artykuł otwarte zostanie nowe okno przeglądarki z załadowaną pełną treścią artykułu.
Zobacz też Q Recepturę „Dodawanie zdarzeń do elementów, które zostaną utworzone później”
z rozdziału 1.
307
PHP i jQuery. Receptury
308
A Firebug W tym dodatku zajmiemy się: Q badaniem elementów strony, Q edytowaniem kodu HTML i stylów CSS, Q debugowaniem kodu JavaScript.
Wprowadzenie Jeżeli ktoś nie zna jeszcze dodatku Firebug, to traci naprawdę świetne narzędzie do tworzenia stron WWW. Jest to dodatek do przeglądarki Firefox, który w samej przeglądarce udostępnia wiele narzędzi wspomagających nas w pracach nad stronami. Możemy w nim przeglądać strukturę dokumentu DOM lub HTML, analizować dołączone style CSS, debugować kod JavaScript i wiele więcej. Przede wszystkim zainstaluj ten dodatek ze strony http://getfirebug.com. Zaraz po zainstalowaniu będzie on gotowy do pracy, czyli będziemy mogli go aktywować, naciskając klawisz F12 albo klikając na pasku stanu ikonę z robaczkiem. Na pasku narzędzi dodatku Firebug zobaczymy sześć przycisków, które opiszę teraz w poniższej liście: Q Konsola — Wyświetla błędy pojawiające się w kodzie JavaScript, opakowując
je w przyjazne komunikaty, w których podany jest też numer wiersza. Oprócz tego wyświetlane są też żądania AJAX, w których możemy zobaczyć dane wysyłane z żądaniem, nagłówki żądania i odpowiedzi, a także dane przesłane w odpowiedzi. W konsoli możemy też protokołować dane z wykonywanego skryptu za pomocą metody console.log(). var x = 10; console.log('Zmienna x ma wartość: ' + x);
PHP i jQuery. Receptury
Powyższy kod umieszczony w naszym skrypcie spowoduje wyświetlenie w konsoli Firebuga poniższego tekstu: Zmienna x ma wartość 10
Q Q Q
Q
Q
310
W ten sposób można wyeliminować niewygodne i brzydkie okienka z komunikatami, które programiści często umieszczają w kodzie, aby sprawdzić wartości zmiennych i inne parametry skryptu. HTML — W tym panelu wyświetlana jest struktura kodu HTML. Po prawej stronie znajduje się też panel, w którym podawane są style CSS wybranego elementu. CSS — Wyświetla wszystkie style CSS, jakie są dostępne na danej stronie. Po wybraniu tego panelu możemy wybrać plik stylów CSS z listy rozwijanej i zacząć jego edycję. Skrypt — Tutaj wyświetlane są wszystkie pliki JavaScript wykorzystane na aktualnej stronie. Można tu wybrać jeden z plików, wstawić do niego punkty wstrzymania i obserwować wartości zmiennych. DOM — Podaje pełną listę wszystkich obiektów i funkcji DOM. Firebug wyświetli też ich odpowiednio sformatowane wartości. Istnieje też możliwość edytowania wartość poszczególnych zmiennych. Sieć — W tym panelu prezentowane są wszystkie zasoby, które zostały załadowane przez stronę. Firebug wyświetli rozmiar każdego z załadowanych plików, a także pasek postępu pokazujący czas ładowania poszczególnych elementów. Taki wykres można wykorzystać jako miarę szybkości działania naszej strony. Istnieje też możliwość monitorowania aktywności sieci z podziałem na rodzaj zasobów. W panelu Sieć dostępnych jest jeszcze więcej opcji, które umożliwiają grupowanie elementów HTML, CSS, JavaScript, żądań AJAX oraz obrazków.
Dodatek A • Firebug
Badanie elementów strony W tej recepturze zaprezentuję panel HTML dodatku Firebug i pokażę, jak należy go używać do kontrolowania struktury dokumentu, wybierania elementów HTML i sprawdzania ich stylów CSS.
Jak to zrobić? 1. Otwórz w przeglądarce stronę HTML, na przykład stronę http://www.google.com. 2. Teraz kliknij ikonę ze strzałką w pasku narzędzi Firebuga i przenieś wskaźnik myszy nad dowolny element strony. Zostanie on wyróżniony w panelu dodatku, a dodatkowo zostaną wyświetlone szczegóły wybranego elementu, tak jak widać to na poniższym obrazku.
3. Inna metoda jest znacznie szybsza i o wiele dokładniejsza. Wystarczy kliknąć dany element strony prawym przyciskiem myszy, a następnie wybrać z menu kontekstowego pozycję Zbadaj element. Dodatek Firebug wyświetli wszystkie informacje na temat tego elementu.
311
PHP i jQuery. Receptury
Jak to działa? Panel HTML dodatku Firebug podzielony jest na dwie części. W lewym panelu wyświetlana jest struktura dokumentu HTML, natomiast w prawym podawane są style CSS. Kliknięcie przycisku Zbadaj pozwala na sprawdzenie dowolnego elementu strony. Późniejsze wskazanie myszą elementu strony spowoduje wyświetlenie jego szczegółów w panelu HTML. W panelu tym dostępna jest pełna struktura HTML dokumentu. Dzięki temu możemy przejrzeć od razu całość dokumentu. Kontrolowanie dokumentu w panelu HTML ma jeszcze jedną zaletę. Pojawiają się w nim również elementy utworzone już po załadowaniu strony, czyli powstałe w wyniku działania skryptów JavaScript i biblioteki jQuery. Po wybraniu jednego elementu w prawym panelu okienka Firebuga wyświetlane będą też style CSS zdefiniowane w arkuszu stylów albo utworzone później w skrypcie.
I coś jeszcze Wtyczki do Firebuga To nie jest żart! Sam Firebug jest wtyczką, ale istnieje też kilka innych wtyczek użytecznych przy tworzeniu stron WWW, które działają w połączeniu z Firebugiem. Oba podane tu narzędzia bardzo pomagają kontrolować aktywność sieciową, wydajność pracy stron, czasy ładowania elementów itd. Oba dodatki podają wskaźniki wydajności wyznaczane zestawem reguł oraz podają zalecenia dotyczące poprawienia szybkości działania strony. Q Google Page Speed — Jest to wtyczka przygotowana przez firmę Google. Poniżej
podaję też opis podawany na stronach Google: Page Speed jest otwartym dodatkiem do Firebuga. Twórcy stron WWW mogą wykorzystać tę wtyczkę do oceniania szybkości działania swoich stron WWW i uzyskania podpowiedzi odnośnie do jej poprawiania. Dodatek ten można pobrać z poniższego adresu: http://code.google.com/speed/page-speed/download.html. Q Yahoo! YSlow — To wtyczka przygotowana przez firmę Yahoo, którą można pobrać
z adresu https://developer.yahoo.com/yslow/.
Zobacz też Q Recepturę „Edytowanie kodu HTML i stylów CSS”.
312
Dodatek A • Firebug
Edytowanie kodu HTML i stylów CSS Typowym sposobem edytowania strony jest otwarcie jej w edytorze, wprowadzenie w nim zmian i otwarcie jej w przeglądarce, aby ocenić uzyskane efekty. Jeżeli coś na stronie nie jest zgodne z naszymi oczekiwaniami, wraca się do edytora i cały cykl się powtarza. Dzięki zastosowaniu dodatku Firebug można to zrobić całkiem inaczej. W tej recepturze dowiemy się, jak należy edytować kod HTML i style CSS strony za pomocą panelu dodatku Firebug. Po wprowadzeniu zadowalających nas zmian można od razu wprowadzić je do kodu źródłowego.
Jak to zrobić? 1. Otwórz w przeglądarce plik dowolnej receptury z tej książki, na przykład receptury „Tworzenie menu harmonijkowego” z rozdziału 7.
2. Teraz za pomocą przycisku Zbadaj odszukaj na stronie element h1 z tekstem jQuery. Kliknij teraz przycisk Edytuj, aby uzyskać możliwość edytowania kodu HTML elementu h1. Zmień zatem znajdujący się w tym elemencie tekst na Biblioteka jQuery.
313
PHP i jQuery. Receptury
3. Teraz kliknij element div klasy container. W prawym panelu pojawi się klasa container i podane zostaną wszystkie jej właściwości. Możesz je edytować, klikając poszczególne wartości i zmieniając je zgodnie ze swoimi wymaganiami. Na przykład kliknij wartość właściwości background-color i zmień ją z #F0F8FF na #FF0000. Wszystkie elementy klasy container otrzymają teraz czerwony kolor tła. 4. Aby dodać nową właściwość do klasy, kliknij jej nazwę prawym przyciskiem myszy i wybierz z menu kontekstowego pozycję Nowa właściwość. Do istniejących już właściwości dopisany zostanie pusty wiersz, w którym możesz dopisać kolejną właściwość i nadać jej wartość. Do klasy container dodaj zatem dwie właściwości color i font-weight, a następnie nadaj im wartości #FFF i bold. Wprowadzona zmiana od razu będzie widoczna we wszystkich elementach klasy container.
I coś jeszcze Modyfikowanie stylu konkretnego elementu Oprócz zmieniania stylu CSS zdefiniowanej już klasy możemy też wprowadzać właściwości CSS poszczególnych elementów strony. W tym celu należy kliknąć prawym przyciskiem myszy w dowolnym miejscu prawego panelu i wybrać z menu kontekstowego pozycję Edytuj styl elementu. Pojawi się wtedy nowy wiersz w panelu właściwości CSS, w którym będziemy mogli wprowadzić dane tylko dla wybranego wcześniej elementu. 314
Dodatek A • Firebug
Debugowanie kodu JavaScript Dodatku Firebug można też użyć do debugowania kodu JavaScript bezpośrednio w przeglądarce. Możemy wstawiać w kodzie punkty wstrzymania i wykonywać go wiersz po wierszu. Oprócz tego możliwe jest też obserwowanie wartości zmiennych oraz elementów struktury DOM.
Jak to zrobić? 1. Aby umieścić w kodzie JavaScript punkt wstrzymania, otwórz dodatek Firebug, klikając jego ikonę na pasku stanu albo naciskając klawisz F12. 2. Następnie kliknij przycisk Skrypt na pasku narzędzi Firebuga. W ten sposób zostanie wyświetlona lista wszystkich skryptów związanych z daną stroną. 3. Wybierz z listy jeden ze skryptów, a jego zawartość zostanie wyświetlona w panelu treści Firebuga.
4. Po wybraniu pliku możesz umieścić w kodzie punkty wstrzymania, klikając tuż przed numerem wiersza kodu. Każdy punkt wstrzymania oznaczany jest za pomocą ciemnobrązowej kropki.
315
PHP i jQuery. Receptury
5. Teraz możemy rozpocząć debugowanie. W naszym przykładzie pokazanym na poniższym rysunku (gra w kółko i krzyżyk) punkt wstrzymania został umieszczony w 19. wierszu kodu. Sam skrypt zostanie uruchomiony w momencie kliknięcia jednego z pól planszy. 6. Kliknij jedno z pól, a zobaczysz, że wykonywanie kodu zostało zatrzymane w wybranym przez nas wierszu.
7. Teraz możesz wykonywać kod skryptu wiersz po wierszu. Aby przejść do kolejnego wiersza, naciśnij klawisz F10. Jeżeli natkniemy się na wywołanie funkcji, to naciskając klawisz F11, możemy wejść do niej i obserwować wykonywanie jej kodu. 8. Oprócz tego możesz też obserwować wartości zapisane w zmiennych. W prawym panelu widoczny jest wiersz z opisem Nowe wyrażenie czujki. Po jego kliknięciu możesz zapisać nazwę zmiennej lub wyrażenia, które chcesz obserwować. 9. Naciśnięcie klawisza F8 wznowi wykonywanie kodu JavaScript do momentu natknięcia się na kolejny punkt wstrzymania.
316
Dodatek A • Firebug
I coś jeszcze Debugowanie w skrócie Q F8 — Kontynuuj wykonywanie skryptu. Q F10 — Krok wykonania skryptu. Uruchamia skrypt do następnego wiersza. Q F11 — Krok z wejściem. Po naciśnięciu klawisza F11 w wierszu wywołującym
funkcję przejdziemy do pierwszego wiersza tej właśnie funkcji. Q F12 — Otwiera i zamyka Firebuga na wybranej stronie.
Sprawdzanie żądań AJAX Konsola Firebuga wyświetla też informacje o wszystkich żądaniach AJAX wysyłanych przez przeglądarkę. Podawany jest tutaj też kod odpowiedzi każdego z tych żądań. Oprócz tego wyświetlane są też parametry żądania, nagłówki żądania i odpowiedzi, a także treść odpowiedzi przesłanej przez serwer.
Pasek narzędzi Web developer Pasek narzędzi Web developer jest kolejnym przydatnym narzędziem umożliwiającym kontrolowanie zachowania poszczególnych elementów strony. On również udostępnia wiele narzędzi ułatwiających modyfikowanie stron WWW. Pozwala na włączanie lub wyłączanie wykonywania skryptów JavaScript, wyświetlania obrazków, podglądanie struktury strony, informacji o formularzach itd. Dodatek ten można pobrać ze strony http://addons.mozilla.org/firefox/addon/60.