Tytuł oryginału: Web Development Recipes
Tłumaczenie: Łukasz Piwko
ISBN: 978-83-246-5149-8
© Helion 2013.
All rights reserved.
Copyright © 2012 The Pragmatic Programmers, LLC.
All rights reserved.
No part of this publication may be reproduced, stored in a retrieval system, or transmitted,
in any form, or by any means, electronic, mechanical, photocopying, recording, or otherwise,
without the prior consent of the publisher.
Many of the designations used by manufacturers and sellers to distinguish their products are claimed
as trademarks. Where those designations appear in this book, and The Pragmatic Programmers, LLC
was aware of a trademark claim, the designations have been printed in initial capital letters or in all
capitals. The Pragmatic Starter Kit, The Pragmatic Programmer, Pragmatic Programming, Pragmatic
Bookshelf, PragProg and the linking g device are trademarks of The Pragmatic Programmers, LLC.
Wszelkie prawa zastrzeżone. Nieautoryzowane rozpowszechnianie całości lub fragmentu niniejszej
publikacji w jakiejkolwiek postaci jest zabronione. Wykonywanie kopii metodą kserograficzną,
fotograficzną, a także kopiowanie książki na nośniku filmowym, magnetycznym lub innym powoduje
naruszenie praw autorskich niniejszej publikacji.
Wszystkie znaki występujące w tekście są zastrzeżonymi znakami firmowymi bądź towarowymi ich
właścicieli.
Materiały graficzne na okładce zostały wykorzystane za zgodą iStockPhoto Inc.
Wydawnictwo HELION dołożyło wszelkich starań, by zawarte w tej książce informacje były kompletne
i rzetelne. Nie bierze jednak żadnej odpowiedzialności ani za ich wykorzystanie, ani za związane z tym
ewentualne naruszenie praw patentowych lub autorskich. Wydawnictwo HELION nie ponosi również
żadnej odpowiedzialności za ewentualne szkody wynikłe z wykorzystania informacji zawartych
w książce.
Wydawnictwo HELION
ul. Kościuszki 1c, 44-100 GLIWICE
tel. 32 231 22 19, 32 230 98 63
e-mail: helion@helion.pl
WWW: http://helion.pl (księgarnia internetowa, katalog książek)
Pliki z przykładami omawianymi w książce można znaleźć pod adresem:
ftp://ftp.helion.pl/przyklady/twstnr.zip
Drogi Czytelniku!
Jeżeli chcesz ocenić tę książkę, zajrzyj pod adres
http://helion.pl/user/opinie/twstnr
Możesz tam wpisać swoje uwagi, spostrzeżenia, recenzję.
Printed in Poland.
Spis treci
Podzikowania ..............................................................................................7
Wstp ...........................................................................................................11
Rozdzia 1. wiecideka ..............................................................................17
Receptura 1. Stylizowanie przycisków i czy ...........................................................17
Receptura 2. Stylizowanie cytatów przy uyciu CSS ................................................21
Receptura 3. Tworzenie animacji przy uyciu transformacji CSS3 ............................28
Receptura 4. Tworzenie interaktywnych pokazów slajdów przy uyciu jQuery ............33
Receptura 5. Tworzenie i stylizowanie wewntrztekstowych okienek pomocy ..............38
Rozdzia 2. Interfejs uytkownika ............................................................47
Receptura 6. Tworzenie szablonu wiadomoci e-mail ................................................47
Receptura 7. Wywietlanie treci na kartach .............................................................58
Receptura 8. Rozwijanie i zwijanie treci z zachowaniem zasad dostpnoci ...............65
Receptura 9. Nawigacja po stronie internetowej przy uyciu klawiatury ......................71
Receptura 10. Tworzenie szablonów HTML przy uyciu systemu Mustache ..............79
Receptura 11. Dzielenie treci na strony ....................................................................84
Receptura 12. Zapamitywanie stanu w Ajaksie ........................................................90
Receptura 13. Tworzenie interaktywnych interfejsów uytkownika
przy uyciu biblioteki Knockout.js .......................................................95
Receptura 14. Organizacja kodu przy uyciu biblioteki Backbone.js ..........................105
Rozdzia 3. Dane ........................................................................................123
Receptura 15. Wstawianie na stron mapy Google ...................................................123
Receptura 16. Tworzenie wykresów i grafów przy uyciu Highcharts ........................129
Receptura 17. Tworzenie prostego formularza kontaktowego ....................................137
Receptura 18. Pobieranie danych z innych serwisów przy uyciu formatu JSONP .....144
Kup książkę
Poleć książkę
6
Web development. Receptury nowej generacji
Receptura 19. Tworzenie widetów do osadzenia w innych serwisach ........................147
Receptura 20. Budowanie witryny przy uyciu JavaScriptu i CouchDB .....................153
Rozdzia 4. Urzdzenia przenone ..........................................................163
Receptura 21. Dostosowywanie stron do wymogów urzdze przenonych .................163
Receptura 22. Menu rozwijane reagujce na dotyk ...................................................168
Receptura 23. Operacja „przecignij i upu” w urzdzeniach przenonych ...............171
Receptura 24. Tworzenie interfejsów przy uyciu biblioteki jQuery Mobile ................178
Receptura 25. Sprite’y w CSS ................................................................................187
Rozdzia 5. Przepyw pracy ......................................................................191
Receptura 26. Szybkie tworzenie interaktywnych prototypów stron ............................191
Receptura 27. Tworzenie prostego bloga przy uyciu biblioteki Jekyll ........................200
Receptura 28. Tworzenie modularnych arkuszy stylów przy uyciu Sass ....................207
Receptura 29. Bardziej przejrzysty kod JavaScript, czyli CoffeeScript ........................215
Receptura 30. Zarzdzanie plikami przy uyciu narzdzia Git ..................................222
Rozdzia 6. Testowanie ............................................................................233
Receptura 31. Debugowanie JavaScriptu .................................................................233
Receptura 32. ledzenie aktywnoci uytkowników przy uyciu map cieplnych ...........239
Receptura 33. Testowanie przegldarek przy uyciu Selenium ..................................242
Receptura 34. Testowanie stron internetowych przy uyciu Selenium i Cucumber ......247
Receptura 35. Testowanie kodu JavaScript przy uyciu Jasmine ................................260
Rozdzia 7. Hosting i wdraanie ..............................................................271
Receptura 36. Wspólna praca nad stron poprzez Dropbox ......................................271
Receptura 37. Tworzenie maszyny wirtualnej ...........................................................275
Receptura 38. Zmienianie konfiguracji serwera WWW przy uyciu programu Vim ......279
Receptura 39. Zabezpieczanie serwera Apache za pomoc SSL i HTTPS ..............284
Receptura 40. Zabezpieczanie treci .......................................................................288
Receptura 41. Przepisywanie adresów URL w celu zachowania czy .......................292
Receptura 42. Automatyzacja procesu wdraania statycznych serwisów
za pomoc Jammit i Rake .................................................................296
Dodatek A. Instalowanie jzyka Ruby ...................................................305
Dodatek B. Bibliografia ............................................................................309
Skorowidz ..................................................................................................311
Kup książkę
Poleć książkę
Rozdzia 2. • Interfejs uytkownika
79
Receptura 10.
Tworzenie szablonów HTML
przy uyciu systemu Mustache
Problem
Do utworzenia naprawd wyjtkowego interfejsu potrzebne jest zastosowanie
zarówno dynamicznych, jak i asynchronicznych technik programowania. Dziki
Ajaksowi i takim bibliotekom jak jQuery moemy modyfikowa interfejs uytkow-
nika bez zmieniania jego kodu HTML, poniewa potrzebne elementy dodamy
za pomoc JavaScriptu. Elementy te zazwyczaj dodaje si, stosujc technik
konkatenacji acuchów. Powstay w wyniku tego kod jest, niestety, zagmatwany
i atwo w nim popeni bd. Peno w nim mieszajcych si ze sob pojedynczych
i podwójnych cudzysowów oraz niekoczcych si acuchów wywoa metody
append()
z biblioteki jQuery.
Skadniki
jQuery
Mustache.js
Rozwizanie
Na szczcie, s nowoczesne narzdzia, takie jak Mustache, dziki którym moemy
pisa prawdziwy kod HTML, renderowa przy jego uyciu dane oraz wstawia
go do dokumentów. Mustache to system szablonów HTML dostpny w kilku
popularnych jzykach programowania. Implementacja JavaScript pozwala na
pisanie widoków dla klienta przy uyciu czystego kodu HTML cakowicie
oddzielonego od kodu JavaScript. Mona w nim uywa take instrukcji logicz-
nych i iteracji.
Mustache pozwala uproci tworzenie kodu HTML podczas generowania nowej
treci. Skadni tego narzdzia poznamy na przykadzie aplikacji JavaScript do
zarzdzania produktami.
Obecnie aplikacja ta umoliwia dodawanie nowych produktów do listy. Ponie-
wa wszystkie dania s obsugiwane przez JavaScript i Ajax, w przykadzie tym
uywamy naszego standardowego serwera roboczego. Gdy uytkownik wypeni
formularz dodawania nowego produktu, wysya do serwera danie zapisania
Kup książkę
Poleć książkę
80
Web development. Receptury nowej generacji
tego produktu i wyrenderowania nowego produktu na licie. Aby doda produkt
do listy, musimy zastosowa konkatenacj acuchów, której kod jest zagmatwany
i nieelegancki:
mustache/submit.html
var newProduct = $('<li></li>');
newProduct.append('<span class="product-name">' +
product.name + '</span>');
newProduct.append('<em class="product-price">' +
product.price + '</em>');
newProduct.append('<div class="product-description">' +
product.description + '</div>');
productsList.append(newProduct);
Aby uy systemu Mustache.js, wystarczy go tylko zaadowa na stron. Jedn
z wersji tego pliku znajdziesz w pakiecie kodu towarzyszcym tej ksice, ale
moesz te pobra jego najnowsz wersj z serwisu GitHub
7
.
Renderowanie szablonu
Aby przerobi nasz istniejc aplikacj, przede wszystkim musimy dowiedzie
si, jak wyrenderowa szablon przy uyciu Mustache. Najprostszym sposobem na
zrobienie tego jest uycie funkcji
to_html()
.
Mustache.to_html(templateString, data);
Funkcja ta przyjmuje dwa argumenty. Pierwszy jest acuchem szablonowego kodu
HTML, w którym ma odbywa si renderowanie, a drugi to dane, które maj
zosta do tego szablonu wstawione. Zmienna
data
jest obiektem, którego klucze
w szablonie zostaj zamienione na lokalne zmienne. Spójrz na poniszy kod:
var artist = {name: "John Coltrane"};
var rendered = Mustache.to_html('<span class="artist name">{{ name }}</span>',
artist);
$('body').append(rendered);
Zmienna
rendered
zawiera nasz ostateczny kod HTML zwrócony przez metod
to_html()
. Aby umieci wasno
name
w naszym kodzie HTML, uylimy
znaczników Mustache ograniczonych podwójnymi klamrami. W klamrach tych
umieszcza si nazwy wasnoci. Ostatni wiersz kodu dodaje wyrenderowany kod
HTML do elementu
<body>
.
Jest to najprostsza technika renderowania szablonu przy uyciu Mustache.
W naszej aplikacji bdzie wicej kodu zwizanego z wysyaniem dania do serwera
w celu pobrania danych, ale proces tworzenia szablonu pozostanie bez zmian.
7
https://github.com/janl/mustache.js
Kup książkę
Poleć książkę
Rozdzia 2. • Interfejs uytkownika
81
Podmienianie istniejcego systemu
Skoro wiemy ju, jak si renderuje szablony, moemy z naszego programu usun
stary kod konkatenacji. Przyjrzymy mu si, aby zobaczy, co mona usun,
a co trzeba podmieni.
mustache/submit.html
function renderNewProduct() {
var productsList = $('#products-list');
var newProductForm = $('#new-product-form');
var product = {};
product.name = newProductForm.find('input[name*=name]').val();
product.price = newProductForm.find('input[name*=price]').val();
product.description =
newProductForm.find('textarea[name*=description]').val();
var newProduct = $('<li></li>');
newProduct.append('<span class="product-name">' +
product.name + '</span>');
newProduct.append('<em class="product-price">' +
product.price + '</em>');
newProduct.append('<div class="product-description">' +
product.description + '</div>');
productsList.append(newProduct);
productsList.find('input[type=text], textarea').each(function(input) {
input.attr('value', '');
});
}
Ten skomplikowany kod bardzo trudno jest rozszyfrowa, a jeszcze trudniej go
modyfikowa. Dlatego zamiast metody
append()
jQuery do budowy struktury
HTML uyjemy systemu Mustache. Moemy napisa prawdziwy kod HTML,
a nastpnie wyrenderowa dane przy uyciu Mustache! Pierwszym krokiem
w kierunku pozbycia si pltaniny JavaScriptu jest zbudowanie szablonu. Póniej
wyrenderujemy go wraz z danymi produktów w jednym prostym procesie.
Jeli utworzymy element
<script>
z typem treci
text/template
, to bdziemy mogli
w nim umieci kod HTML Mustache i pobiera go stamtd do szablonu.
Nadamy mu identyfikator, aby móc si do niego odwoywa z kodu jQuery.
<script type="text/template" id="product-template">
<!-- Szablon HTML -->
</script>
Nastpnie napiszemy kod HTML naszego szablonu. Mamy ju produkt w postaci
obiektu, a wic jego wasnoci w szablonie moemy uy jako nazw zmiennych:
Kup książkę
Poleć książkę
82
Web development. Receptury nowej generacji
Ja pyta:
Czy mona uywa zewntrznych szablonów?
Szablony wewntrzne s porczne, ale my chcemy oddzieli logik szablo-
now od widoków serwera. Na serwerze naleaoby utworzy folder
do przechowywania wszystkich plików widoków. Nastpnie, gdy trzeba
wyrenderowa jeden z szablonów, pobieramy go za pomoc jQery
i dania
GET
.
$.get("http://mojastrona.com/js_views/zewnetrzny_szablon.html",
function(template) {
Mustache.to_html(template, data).appendTo("body");
}
);
W ten sposób mona serwowa widoki serwera osobno od widoków
klienta.
<script type="text/template" id="product-template">
<li>
<span class="product-name">{{ name }}</span>
<em class="product-price">{{ price }}</em>
<div class="product-description">{{ description }}</div>
</li>
</script>
Majc gotowy szablon, moemy wróci do poprzedniego kodu, aby zmieni sposób
wstawiania kodu HTML. Moemy pobra odwoanie do szablonu przy uyciu
jQuery i za pomoc metody
html()
pobra tre wewntrzn. Póniej trzeba
jeszcze tylko przesa kod HTML i dane do Mustache.
var newProduct = Mustache.to_html( $('#product-template').html(), product);
Wynik tego powinien by ju zadowalajcy, chocia gdy nie ma adnego opisu,
pole opisu nie powinno by widoczne. Innymi sowy, jeli nie ma opisu, nie
powinnimy renderowa jego elementu
<div>
. Na szczcie, w Mustache mona
uywa instrukcji warunkowych. Przy ich uyciu sprawdzimy, czy opis istnieje,
i jeli tak, to wyrenderujemy dla niego element
<div>
.
{{#description}}
<div class="product-description">{{ description }}</div>
{{/description}}
Przy uyciu tego samego operatora Mustache wykona iteracj po tablicy. System
sprawdzi, czy dana wasno jest tablic, i jeli tak, to automatycznie zastosuje
iteracj.
Kup książkę
Poleć książkę
Rozdzia 2. • Interfejs uytkownika
83
Stosowanie iteracji
Poniewa udao nam si wymieni znaczn cz istniejcego kodu budujcego
nowy produkt, postanowilimy, e wiksz cz logiki aplikacji napiszemy
w JavaScripcie. Zamienimy stron indeksow, na której wywietlane s produkty
wraz z uwagami, na kod JavaScript, który bdzie robi to samo. Utworzymy tablic
produktów na jednej z wasnoci obiektu danych i kady produkt w tej tablicy
bdzie mia wasno
notes
. Wasno
notes
bdzie tablic, po której iteracja bdzie
si odbywa wewntrz szablonu.
Najpierw pobierzemy i wyrenderujemy produkty. Przyjmujemy zaoenie, e ser-
wer zwraca tablic w formacie JSON wygldajc tak:
$.getJSON('/products.json', function(products) {
var data = {products: products};
var rendered = Mustache.to_html($('#products-template').html(), data);
$('body').append(rendered);
});
Teraz musimy zbudowa szablon do wyrenderowania produktów. W Mustache
iteracj po tablicy wykonuje si, przekazujc t tablic operatorowi
#
, np.
{{#zmienna}}
. Wewntrz iteracji wasnoci, które wywoujemy, znajduj si
w kontekcie obiektów w tablicy.
mustache/index.html
<script type="text/template" id="products-template">
{{#products}}
<li>
<span class="product-name">{{ name }}</span>
<em class="product-price">{{ price }}</em>
<div class="product-description">{{ description }}</div>
<ul class="product-notes">
{{#notes}}
<li>{{ text }}</li>
{{/notes}}
</ul>
</li>
{{/products}}
</script>
Teraz nasza strona indeksowa moe by w caoci generowana w przegldarce
przy uyciu szablonów i Mustache.
Szablony JavaScript s doskonaym narzdziem pozwalajcym dobrze zorgani-
zowa kod aplikacji JavaScript. Nauczye si renderowa szablony, uywa
instrukcji warunkowych oraz stosowa iteracj. Mustache.js jest prostym narz-
dziem pozwalajcym pozby si konkatenacji acuchów i budowa struktur
HTML w czytelny i zgodny z semantyk sposób.
Kup książkę
Poleć książkę
84
Web development. Receptury nowej generacji
Kontynuacja
Szablony Mustache pozwalaj zachowa przejrzysto nie tylko kodu dziaajcego
po stronie klienta, ale równie serwerowego. Istniej implementacje tego systemu
w jzykach Ruby, Java, Python, ColdFusion i wielu innych. Wicej informacji
na ten temat mona znale na stronie Mustache
8
.
Mustache mona zatem uywa jako systemu szablonów zarówno przy budowie
frontu, jak i zaplecza aplikacji. Gdybymy na przykad mieli szablon Mustache
reprezentujcy wiersz tabeli HTML i uyli go wewntrz ptli budujcej tabel
przy wczytywaniu strony, to tego samego szablonu moglibymy te uy w celu
dodania wiersza do tej tabeli po udanym wykonaniu dania Ajax.
Zobacz równie
Receptura 11.: „Dzielenie treci na strony”
Receptura 13.: „Tworzenie interaktywnych interfejsów uytkownika
przy uyciu biblioteki Knockout.js”
Receptura 14.: „Organizacja kodu przy uyciu biblioteki Backbone.js”
Receptura 20.: „Budowanie witryny przy uyciu JavaScriptu
i CouchDB”
Receptura 11.
Dzielenie treci na strony
Problem
Aby zaoszczdzi uytkownikom nadmiaru treci na jednej stronie, a przy okazji
nie przeciy serwerów, naley ustali limit iloci danych, jaka moe zosta
wywietlona na jednej stronie. Najczciej w tym celu dodaje si mechanizm
dzielenia stron. Jego dziaanie polega na tym, e wywietlana jest tylko cz
zawartoci strony i uytkownik moe w razie potrzeby przejrze take pozostae
czci. Pocztkowo wywietlana jest tylko maa czstka tego, co mona obejrze.
W toku ewolucji stron internetowych ich twórcy spostrzegli, e uytkownicy
wikszo czasu spdzaj na przegldaniu treci w sposób liniowy. Najchtniej
8
http://mustache.github.com/
Kup książkę
Poleć książkę
Rozdzia 2. • Interfejs uytkownika
85
przegldaliby cae listy danych, a do znalezienia szukanych informacji albo
osignicia koca zbioru. Naszym zadaniem jest umoliwienie im takiego prze-
gldania i jednoczenie uniknicie przecienia serwera.
Skadniki
jQuery
Mustache.js
9
QEDServer
Rozwizanie
Paginacja to dobry sposób na zapanowanie nad zasobami, który dodatkowo ua-
twia korzystanie ze strony uytkownikowi. Zamiast zmusza uytkownika do
wybrania nastpnej strony wyników i wczytywa cay interfejs od nowa, nastpn
stron wczytujemy w tle i dodajemy j do biecej strony, podczas gdy uytkow-
nik zblia si do jej koca.
Chcemy umieci na stronie list naszych produktów, ale jest ich za duo, aby
wywietli je wszystkie naraz. Dlatego zastosujemy paginacj z ograniczeniem
polegajcym na wywietlaniu maksymalnie 10 produktów naraz. eby jeszcze
bardziej uatwi ycie uytkownikom, pozbdziemy si przycisku Nastpna strona
i zamiast tego bdziemy automatycznie wczytywa kolejne strony, gdy uznamy,
e naley to zrobi. Od strony uytkownika bdzie to wygldao tak, jakby caa
lista bya dostpna na stronie od samego pocztku.
Do budowy prototypu uyjemy QEDServera i jego katalogu produktów. Cay
kod ródowy umiecimy w folderze public w przestrzeni roboczej QEDServera.
Uruchom QEDServer i utwórz nowy plik o nazwie products.html w folderze
public utworzonym przez QEDServer. Jeli nie wiesz, czym jest QEDServer,
zajrzyj do „Wstpu”, w którym znajduje si objanienie.
Aby utrzyma porzdek w kodzie, uyjemy biblioteki szablonów Mustache,
o której bya mowa w recepturze 10., „Tworzenie szablonów HTML przy uyciu
systemu Mustache”. Pobierz t bibliotek i umie j take w folderze public.
Zaczniemy od utworzenia prostego szkieletu strony index.html w HTML5.
Doczymy do niej biblioteki jQuery, Mustache oraz plik endless_pagination.js,
który bdzie zawiera nasz kod paginacji.
9
http://github.com/documentcloud/underscore/blob/master/underscore.js
Kup książkę
Poleć książkę
86
Web development. Receptury nowej generacji
endlesspagination/products.html
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<title>Produkty AwesomeCo</title>
<link rel='stylesheet' href='endless_pagination.css'>
<script type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.7/jquery.min.js">
</script>
<script type="text/javascript" src="mustache.js"></script>
<script src="endless_pagination.js"></script>
</head>
<body>
<div id="wrap">
<header>
<h1>Produkty</h1>
</header>
</div>
</body>
</html>
W strukturze tej strony umiecilimy kontener na tre i obraz wirujcego kóka
widoczny na rysunku 2.8. Animacja ta ma na celu zasygnalizowa uytkownikowi,
e trwa wczytywanie nastpnej strony, które powinno si odbywa w tle.
endlesspagination/products.html
<div id='content'>
</div>
<img src='spinner.gif' id='next_page_spinner'>
API QEDServer jest tak skonfigurowane, e zwraca stronicowane wyniki i reaguje
na dania JSON. Moemy si o tym przekona, otwierajc adres http://localhost:
8080/Products.json?page=2.
Wiedzc, jakie informacje otrzymujemy od serwera, moemy rozpocz budow
kodu, który bdzie aktualizowa interfejs. W tym celu napiszemy funkcj pobiera-
jc tablic w formacie JSON, znakujc j przy uyciu szablonu Mustache
i wynik tego dziaania dodajc na kocu strony. Cay ten kod umiecimy w pliku
o nazwie endless_pagination.js. Zaczniemy od napisania funkcji pomocniczych.
Na pierwszy ogie pójdzie funkcja renderujca odpowied w formacie JSON do
HTML.
endlesspagination/endless_pagination.js
function loadData(data) {
$('#content').append(Mustache.to_html("{{#products}} \
<div class='product'> \
<a href='/products/{{id}}'>{{name}}</a> \
<br> \
<span class='description'>{{description}}</span> \
</div>{{/products}}", { products: data }));
}
Kup książkę
Poleć książkę
Rozdzia 2. • Interfejs uytkownika
87
Rysunek 2.8.
Widok dolnej czci strony
W procesie iteracji szablon utworzy dla kadego produktu element
<div>
, w któ-
rym tre jest nazw produktu w postaci cza. Nastpnie nowe elementy zostan
dodane na kocu listy produktów i pojawi si na stronie.
Nastpnie, jako e po dotarciu przez uytkownika na koniec strony chcemy
wczyta kolejn stron, musimy znale sposób na okrelenie, czym jest ta nastpna
strona. W tym celu moemy przechowywa biec stron jako zmienn globaln,
a nastpnie gdy bdziemy gotowi — utworzy URL dla nastpnej strony.
endlesspagination/endless_pagination.js
var currentPage = 0;
function nextPageWithJSON() {
currentPage += 1;
var newURL = 'http://localhost:8080/products.json?page=' + currentPage;
var splitHref = document.URL.split('?');
var parameters = splitHref[1];
Kup książkę
Poleć książkę
88
Web development. Receptury nowej generacji
if (parameters) {
parameters = parameters.replace(/[?&]page=[^&]*/, '');
newURL += '&' + parameters;
}
return newURL;
}
Funkcja
nextPageWithJSON()
zwiksza warto zmiennej
currentPage
i dodaje j
do biecego adresu jako warto parametru
page=
. Zapamitujemy te wszystkie
inne parametry znajdujce si w biecym URL. Jednoczenie upewniamy si,
e stary parametr
page
, jeli istnieje, zostanie nadpisany. Dziki temu otrzymamy
waciw odpowied od serwera.
Funkcje wywietlajce now tre i okrelajce adres nastpnej strony s ju
gotowe. Czas w takim razie napisa funkcj pobierajc tre z serwera. W istocie
funkcja ta bdzie po prostu daniem Ajax wysyanym do serwera. Musimy tylko
zaimplementowa w niej podstawowy mechanizm zapobiegajcy wysyaniu nie-
potrzebnych da. Utworzymy zmienn globaln o nazwie
loadingPage()
, któr
zainicjujemy wartoci
0
. Przed wykonaniem dania bdziemy j zwiksza,
a po jego zakoczeniu — zmniejsza z powrotem. Jest to co w rodzaju muteksu,
czyli mechanizmu blokujcego. Bez tej blokady do serwera wysyane byyby
dziesitki da, a serwer by na nie skwapliwie odpowiada, mimo e nie o to nam
chodzio.
endlesspagination/endless_pagination.js
var loadingPage = 0;
function getNextPage() {
if (loadingPage != 0) return;
loadingPage++;
$.getJSON(nextPageWithJSON(), {}, updateContent).
complete(function() { loadingPage-- });
}
function updateContent(response) {
loadData(response);
}
Po otrzymaniu odpowiedzi na danie Ajax przekazujemy j do funkcji
loadData()
,
której definicj przedstawiono wczeniej. Po dodaniu nowej treci przez funkcj
loadData()
aktualizujemy adres URL przechowywany w zmiennej
nextPage
. Jeste-
my gotowi na wykonanie kolejnego dania Ajax.
Majc funkcj dajc nastpnej strony, teraz musimy zaj si sprawdzaniem,
czy uytkownik w ogóle jest gotowy na wczytanie kolejnej strony. Normalnie
wywietlilibymy po prostu cze Nastpna strona, ale nam chodzi o co innego.
Potrzebujemy funkcji, która bdzie zwraca
true
, gdy dolna krawd okna prze-
gldarki znajdzie si w okrelonej odlegoci od dou strony.
Kup książkę
Poleć książkę
Rozdzia 2. • Interfejs uytkownika
89
endlesspagination/endless_pagination.js
function readyForNextPage() {
if (!$('#next_page_spinner').is(':visible')) return;
var threshold = 200;
var bottomPosition = $(window).scrollTop() + $(window).height();
var distanceFromBottom = $(document).height() - bottomPosition;
return distanceFromBottom <= threshold;
}
Na koniec dodajemy procedur obsugi zdarzenia przewijania kókiem myszy,
która wywouje funkcj
observeScroll()
. Gdy uytkownik przewinie stron za
pomoc kóka myszy, nastpi wywoanie funkcji pomocniczej
readyForNextPage()
.
Gdy funkcja ta zwróci
true
, wywoamy funkcj
getNextPage()
, aby wykona da-
nie Ajax.
endlesspagination/endless_pagination.js
function observeScroll(event) {
if (readyForNextPage()) getNextPage();
}
$(document).scroll(observeScroll);
Cz dotyczc „nieskoczonego wywietlania treci” mamy za sob, ale przecie
kiedy ta nasza tre jednak si skoczy. Po wywietleniu ostatniego produktu
wirujce kóko powinno zosta ukryte, poniewa jeli bdzie widoczne, uytkow-
nik pomyli, e albo co jest nie tak z jego czem internetowym, albo z nasz
stron. Aby usun wirujce kóko, dodamy test, który bdzie powodowa jego
ukrycie, gdy serwer zwróci pust list.
endlesspagination/endless_pagination.js
function loadData(data) {
$('#content').append(Mustache.to_html("{{#products}} \
<div class='product'> \
<a href='/products/{{id}}'>{{name}}</a> \
<br> \
<span class='description'>{{description}}</span> \
</div>{{/products}}", { products: data }));
if (data.length == 0) $('#next_page_spinner').hide();
}
To wszystko. Gdy dotrzemy do koca listy, wirujce kóko zniknie.
Kontynuacja
Opisana tu technika jest doskona metod wywietlania dugich list danych
w sposób zgodny z oczekiwaniami uytkowników. Dziki podziaowi rozwizania
na funkcje atwo je bdzie przystosowa do rónych projektów. Mona zmieni
Kup książkę
Poleć książkę
90
Web development. Receptury nowej generacji
Funkcjonalno przegldarki IE 8
W przegldarce IE 8 ten kod nie dziaa. Przegldarka ta wymaga, aby
nagówki da JSON byy w bardzo specyficznym formacie, np. strona
kodowa UTF-8 musi zosta wysana jako utf8. Bez poprawnych nagówków
danie Ajax nie powiedzie si i na stronie bdzie wywietlone tylko wiru-
jce kóko. Naley o tym pamita podczas pracy z formatem JSON na ser-
werze i w przegldarce IE.
warto zmiennej
treshold
, aby tre bya wczytywana wczeniej lub póniej, lub
zmodyfikowa funkcj
loadData()
, aby zwracaa odpowied w formacie HTML
lub XML zamiast JSON. A najlepsze jest to, e moemy by spokojni o dostp-
no naszej strony take wówczas, gdy z jakiego powodu biblioteka jQuery nie
bdzie obsugiwana. Moesz to sprawdzi, wyczajc JavaScript w swojej prze-
gldarce.
W nastpnej recepturze pokaemy Ci, jak ulepszy ten kod poprzez dodanie
obsugi zmian adresu URL i przycisku Wstecz.
Zobacz równie
Receptura 12.: „Zapamitywanie stanu w Ajaksie”
Receptura 10.: „Tworzenie szablonów HTML przy uyciu systemu
Mustache”
Receptura 12.
Zapamitywanie stanu w Ajaksie
Problem
Jedn z najwikszych zalet internetu jest moliwo dzielenia si odnonikami
z innymi ludmi. Jednak wraz z nadejciem ery Ajaksa nie wszystko jest takie
proste. Klikajc cze Ajax, nie mamy gwarancji, e spowoduje to zmian adresu
URL w pasku przegldarki. To nie tylko utrudnia wymian odnonikami z innymi
ludmi, ale równie powoduje wadliwe dziaanie przycisku Wstecz przegldarki.
Strony zawierajce takie cza nie s dobrymi obywatelami internetu, poniewa
gdy si je wyczy, nie da si wróci bezporednio do poprzedniego stanu.
Kup książkę
Poleć książkę
Rozdzia 2. • Interfejs uytkownika
91
Niestety, skrypt paginacji, który napisalimy w recepturze 11., „Dzielenie treci
na strony”, równie nie naley do wzorowych obywateli. Gdy uytkownik prze-
wija stron i przechodzi do kolejnych porcji informacji, adres URL cay czas
pozostaje taki sam. A przecie kade wczytanie oznacza nowy stan, w którym
prezentowane s inne dane ni bezporednio po wczytaniu strony. Gdyby
na przykad spodoba si nam produkt ze strony pitej i wysalibymy znajomemu
odnonik do niej, znajomy ten mógby nie znale tego, o czym mu pisalimy,
poniewa zobaczyby inn list ni my.
To nie wszystko. Gdy uytkownik kliknie przycisk Wstecz przegldarki na stro-
nie zbudowanej w caoci na bazie Ajaksa, to nie przejdzie tam, gdzie by chcia,
tylko na poprzedni stron, z której trafi do nas. Zdziwiony kliknie przycisk Dalej
i pogubi si cakowicie. Na szczcie, znamy rozwizanie tych problemów.
Skadniki
jQuery
Mustache.js
10
QEDServer
Rozwizanie
W tej recepturze dokoczymy prac rozpoczt w recepturze 11., „Dzielenie
treci na strony”. Mimo i zastosowana tam metoda ogólnie dziaa, to jednak ma
t wad, e uniemoliwia odwiedzajcym dzielenie si linkami do stron. Aby
speni wymogi dobrego projektowania stron i nie utrudnia ycia uytkowni-
kom, musimy sprawi, aby nasza lista produktów ledzia swój stan. Innymi
sowy, gdy zmieni si strona, na któr patrzymy, wraz z ni powinien zmienia si
adres URL. W specyfikacji HTML5 wprowadzono funkcj JavaScript o nazwie
pushState()
, która w wikszoci przegldarek pozwala na zmian adresu URL
bez opuszczania strony. To doskonaa wiadomo dla programistów stron inter-
netowych! Dziki temu moemy napisa stron w caoci opart na Ajaksie,
której przegldanie nigdy nie wymaga wykonywania caego cyklu da i przea-
dowa. Oznacza to, e nie musimy ju wczytywa takich zasobów, jak nagówek
i stopka dokumentu, wysya w nieskoczono da plików graficznych, arkuszy
stylów i skryptów JavaScript za kadym razem, gdy przechodzimy na now stron
10
http://github.com/documentcloud/underscore/blob/master/underscore.js
Kup książkę
Poleć książkę
92
Web development. Receptury nowej generacji
w obrbie witryny. A uytkownicy mog bez problemu przesya linki znajomym
i nigdy si nie pogubi, w którym miejscu w serwisie aktualnie si znajduj. Naj-
lepsze jest to, e przycisk Wstecz przegldarki równie bdzie dziaa poprawnie.
Funkcja pushState()
Funkcja
pushState()
jest jeszcze dopracowywana. Wikszo starych przeglda-
rek jej nie obsuguje, ale istniej rozwizania awaryjne wykorzystujce cz adresu
URL za znakiem
#
. Rozwizania te moe nie s eleganckie, ale dziaaj. Poza
tym nie chodzi tylko o pikne adresy URL. Internet ma bardzo dobr pami
dugotrwa. Stworzono go nie tylko do zabawy i pogaduszek, lecz równie po
to, aby mona byo nawet po latach znale stare strony, do których kiedy utwo-
rzyo si cze, a które zostay przeniesione na nowy serwer (pod warunkiem
e ich twórcy s dobrymi obywatelami internetu i stosuj poprawne przekierowa-
nia HTTP 301). Jeli bdziemy uywa znaku # w adresach URL jako tym-
czasowego rozwizania dla wanych informacji, to moe si okaza, e nigdy si
ich nie pozbdziemy
11
. Poniewa znaki # z adresów URL nigdy nie s wysyane
do serwera, nasza aplikacja musiaaby dalej przekierowywa ruch po tym, gdy
funkcja
pushState()
stanie si standardem.
Uzbrojeni w t now wiedz, zobaczmy, co trzeba zrobi, aby nasza niekoczca
si strona z produktami uzyskaa wiadomo swojego stanu.
Parametry, które trzeba ledzi
Poniewa nie wiemy, na któr stron uytkownik wejdzie za pierwszym razem,
bdziemy ledzi zarówno stron startow, jak i biec. Jeli uytkownik wejdzie
od razu na trzeci stron, to chcemy, aby przy kolejnych wizytach móg na ni
wróci. Jeli odwiedzajcy skorzysta z kóka myszy na stronie trzeciej i wczyta
kilka kolejnych stron, np. do strony siódmej, to równie chcemy o tym wiedzie.
Potrzebujemy sposobu na zapamitanie strony startowej i kocowej, aby w przy-
padku odwieenia uytkownik nie musia przewija wszystkiego od pocztku.
Musimy te znale sposób na wysyanie startowej i kocowej strony z klienta.
Najbardziej oczywistym rozwizaniem w tym przypadku wydaje si dodanie tych
parametrów do adresu URL w daniu
GET
. Przy pierwszym wczytaniu strony
ustawimy parametr
page
adresu na biec stron i przyjmiemy zaoenie, e
uytkownik chce obejrze tylko t stron. Gdy klient przekae dodatkowo para-
metr
start_page
, bdziemy wiedzie, e uytkownik chce obejrze kilka stron, od
11
http://danwebb.net/2011/5/28/it-is-about-the-hashbangs
Kup książkę
Poleć książkę
Rozdzia 2. • Interfejs uytkownika
93
start_page
do
page
. Wracajc do poprzedniego przykadu, gdybymy byli na
stronie siódmej, ale zaczli przegldanie od strony trzeciej, to nasz adres URL
wygldaby nastpujco http://localhost:8080/products?start_page=3&page=7.
Te parametry powinny nam wystarczy do odtworzenia listy produktów i po-
kazania uytkownikowi takiej samej strony za kadym razem.
statefulpagination/stateful_pagination.js
function getParameterByName(name) {
var match = RegExp('[?&]' + name + '=([^&]*)')
.exec(window.location.search);
return match && decodeURIComponent(match[1].replace(/\+/g, ' '));
}
var currentPage = 0;
var startPage = 0;
$(function() {
startPage = parseInt(getParameterByName('start_page'));
if (isNaN(startPage)) {
startPage = parseInt(getParameterByName('page'));
}
if (isNaN(startPage)) {
startPage = 1;
}
currentPage = startPage - 1;
if (getParameterByName('page')) {
endPage = parseInt(getParameterByName('page'));
for (i = currentPage; i < endPage; i++) {
getNextPage(true);
}
}
observeScroll();
});
Skrypt ten sprawdza parametry
start_page
i
page
, a nastpnie wysya danie
odpowiednich stron do serwera. Uylimy funkcji bardzo podobnej do
getNext
´
Page()
z poprzedniej receptury, tylko z obsug wielu da naraz. W odró-
nieniu od sytuacji, gdy uytkownik korzysta z kóka myszy i chcemy zapobiec
nakadaniu si da, w tym przypadku nie przeszkadza nam to, poniewa wiemy
dokadnie, których stron ma dotyczy danie.
Podobnie jak ledzilimy wczeniej warto zmiennej
currentPage
, teraz bdziemy
ledzi
startPage
. Parametr ten bdziemy pobiera z adresu URL, dziki czemu
bdziemy mogli wykonywa dania stron, które nie byy jeszcze wczytywane.
Liczba ta nie bdzie si zmienia, ale musi by dodawana do adresu URL i by
w nim przy kadym daniu nowej strony.
Kup książkę
Poleć książkę
94
Web development. Receptury nowej generacji
Aktualizowanie adresu URL w przegldarce
Do aktualizacji adresu URL w przegldarce napiszemy funkcj o nazwie
update
´
BrowserUrl()
, wywoujc funkcj
pushState()
oraz ustawiajc parametry
start_
´
page
i
page
. Naley przy okazji pamita, e nie wszystkie przegldarki obsu-
guj funkcj
pushState()
, i przed jej wywoaniem sprawdza, czy jest zdefinio-
wana. W tych przegldarkach nasze rozwizanie po prostu nie bdzie dziaa, ale
powinnimy przygotowywa nasze aplikacje z myl o przyszoci.
statefulpagination/stateful_pagination.js
function updateBrowserUrl() {
if (window.history.pushState == undefined) return;
var newURL = '?start_page=' + startPage + '&page=' + currentPage;
window.history.pushState({}, '', newURL);
}
Funkcja
pushState()
przyjmuje trzy parametry. Pierwszy jest obiekt stanu, który
jest w istocie obiektem w formacie JSON. Argument ten moglibymy wykorzysta
do przechowywania informacji dotyczcych stanu, poniewa w wyniku przewija-
nia od serwera otrzymujemy dane wanie w formacie JSON. Poniewa jednak
nasze dane s proste i atwe do pobrania z serwera, wydaje si, e nie jest to warte
zachodu. Drugi argument to tytu nowego stanu. Nie jest on na razie szeroko
obsugiwany przez przegldarki, ale w naszym przypadku to nie problem, bo
i tak bymy tego nie potrzebowali. W zwizku z tym przekazujemy w nim pusty
acuch.
W kocu dochodzimy do najwaniejszego elementu funkcji
pushState()
. Trzeci
parametr okrela, co ma si zmieni w adresie. Moe to by zarówno bezwzgldna
cieka, jak i zestaw parametrów, które maj zosta zmienione na kocu adresu.
Ze wzgldów bezpieczestwa nie mona zmienia domeny, ale wszystko, co
znajduje si za ni — tak. Poniewa nas interesuje tylko zmienianie parametrów
adresu URL, na pocztku trzeciego parametru funkcji
pushState()
wpisalimy
znak
?
. Nastpnie wpisalimy ustawienia parametrów
start_page
i
page
. Jeli
parametry te bd znajdowa si w adresie, funkcja sama je zaktualizuje.
statefulpagination/stateful_pagination.js
function updateContent(response) {
loadData(response);
updateBrowserUrl();
}
Na koniec, aby nasz mechanizm paginacji zacz rozpoznawa swój stan, doda-
limy wywoanie funkcji
updateBrowserUrl()
do funkcji
updateContent()
. Od tej pory
uytkownicy mog bez przeszkód uywa przycisku Wstecz, aby wyj ze strony,
i przycisku Dalej, aby na ni wróci do tego samego miejsca. Take odwieenie
Kup książkę
Poleć książkę
Rozdzia 2. • Interfejs uytkownika
95
strony niczego nie zepsuje. Co jednak najwaniejsze, teraz odwiedzajcy mog
wysya znajomym linki do naszych stron. Dziki cikiej pracy programistów
przegldarek internetowych udao nam si sprawi, aby nasza strona indeksowa
bya dobrym obywatelem internetu.
Kontynuacja
Dodajc kolejne skrypty JavaScript i Ajax do swoich stron, powinnimy mie
wiadomo dziaania uywanych interfejsów. Metoda
pushState()
HTML5
i API History pozwalaj nam przywróci normalne dziaanie kontrolek, do któ-
rych uytkownicy s przyzwyczajeni. Warstwy abstrakcji, takie jak History.js
12
,
jeszcze to uatwiaj, poniewa dostarczaj eleganckich rozwiza awaryjnych
dla starych przegldarek.
Opisane przez nas rozwizania zaczynaj te by implementowane w bibliotekach
JavaScript, jak np. Backbone.js, co oznacza, e moemy spodziewa si jeszcze
lepszej obsugi przycisku Wstecz nawet na najbardziej skomplikowanych jedno-
stronicowych aplikacjach.
Zobacz równie
Receptura 10.: „Tworzenie szablonów HTML przy uyciu systemu
Mustache”
Receptura 14.: „Organizacja kodu przy uyciu biblioteki Backbone.js”
Receptura 13.
Tworzenie interaktywnych
interfejsów uytkownika
przy uyciu biblioteki Knockout.js
Problem
Programujc nowoczesne aplikacje sieciowe, staramy si, aby w reakcji na dzia-
ania uytkownika aktualizowana bya jak najmniejsza cz interfejsu. Odwoania
do serwera s zawsze czasochonne, a odwieanie caej strony moe spowodowa
zniechcenie uytkownika.
12
http://plugins.jquery.com/plugin-tags/pushstate
Kup książkę
Poleć książkę
96
Web development. Receptury nowej generacji
Niestety, kod JavaScript uywany do implementacji tych mechanizmów czsto
szybko wymyka si spod kontroli. Na pocztku obserwowanych jest tylko kilka
zdarze, ale z czasem dodajemy kolejne funkcje zwrotne do aktualizowania ró-
nych obszarów strony i utrzymanie tego wszystkiego w ryzach staje si bardzo
kopotliwe.
Knockout to prosta, a zarazem bardzo funkcjonalna biblioteka, pozwalajca wi-
za obiekty z interfejsem i automatycznie aktualizowa jedn cz interfejsu,
podczas gdy zmieniana jest inna cz, bez potrzeby uywania wielu zagniedo-
nych procedur obsugi zdarze.
Skadniki
Knockout.js
13
Rozwizanie
Knockout.js uywa modeli widoków, które zawieraj logik widoku zwizan
ze zmianami interfejsu. Wasnoci tych modeli mona wiza z elementami
interfejsu.
Chcemy, aby uytkownicy naszej strony mogli zmienia liczb elementów
w koszyku i od razu otrzyma zaktualizowan nalen za nie sum. Do budowy
ekranu aktualizacji naszego koszyka moemy wykorzysta modele widoków Knock-
out. W koszyku kady produkt bdzie przedstawiony w postaci wiersza tabeli.
W kadym wierszu bdzie si znajdowa pole na liczb egzemplarzy danego
produktu oraz przycisk pozwalajcy usun ten produkt z koszyka. Gdy zmieni si
liczba egzemplarzy którego z produktów, aplikacja natychmiast obliczy now
sum czstkow oraz sum za wszystkie towary. Gdy skoczymy prac, finalny
efekt bdzie wyglda jak na rysunku 2.9.
Rysunek 2.9.
Interfejs koszyka
13
http://knockoutjs.com
Kup książkę
Poleć książkę
Rozdzia 2. • Interfejs uytkownika
97
Podstawy Knockout
Modele widoków Knockout to zwyke obiekty JavaScript z wasnociami i meto-
dami. Oto prosty obiekt Person z metodami dla imienia, nazwiska oraz imienia
i nazwiska.
knockout/binding.html
var Person = function(){
this.firstname = ko.observable("Jan");
this.lastname = ko.observable("Kowalski");
this.fullname = ko.dependentObservable(function(){
return(
this.firstname() + " " + this.lastname()
);
}, this);
};
ko.applyBindings( new Person );
Metody i logik tego obiektu z elementami interfejsu wiemy przy uyciu atry-
butu
data-
jzyka HTML5.
knockout/binding.html
<p>Imi: <input type="text" data-bind="value: firstname"></p>
<p>Nazwisko: <input type="text" data-bind="value: lastname"></p>
<p>Imi i nazwisko:
<span aria-live="polite" data-bind="text: fullname"></span>
</p>
Gdy zmienimy imi albo nazwisko w jednym z pól, pod spodem zostanie wywie-
tlone zaktualizowane imi i nazwisko. Poniewa aktualizacja odbywa si dyna-
micznie, moe sprawia problemy osobom niewidomym, które korzystaj z czyt-
ników ekranu. Rozwizaniem tego problemu jest uycie atrybutu
aria-live
, infor-
mujcego czytniki, e ta cz strony dynamicznie si zmienia.
To by bardzo prosty przykad, wic teraz pokopiemy troch gbiej i utworzymy
jeden wiersz danych naszego koszyka, w którym po zmianie liczby produktów
bdzie odpowiednio zmieniaa si suma nalena. Póniej na tej bazie zbudujemy
cay koszyk. Zaczniemy od utworzenia modelu danych.
Pojedynczy wiersz bdzie reprezentowa obiekt JavaScript o nazwie
LineItem
majcy wasnoci
name
i
price
. Utwórz stron HTML i docz do niej bibliotek
Knockout.js w sekcji nagówkowej:
knockout/item.html
<!DOCTYPE html>
<html>
<head>
<title>Aktualizacja liczby produktów</title>
<script type="text/javascript" src="knockout-1.3.0.js"></script>
</head>
Kup książkę
Poleć książkę
98
Web development. Receptury nowej generacji
<body>
</body>
</html>
Na dole strony, nad znacznikiem
</body>
, wstaw element
<script>
i wpisz w nim
nastpujcy kod:
knockout/item.html
var LineItem = function(product_name, product_price){
this.name = product_name;
this.price = product_price;
};
W JavaScripcie funkcje s konstruktorami obiektów, a wic mona ich uywa
do naladowania klas. W tym przypadku konstruktor egzemplarza
LineItem
przyj-
muje nazw i cen.
Teraz musimy poinformowa Knockout, e chcemy uy tej klasy
LineItem
jako
naszego modelu widoku, aby jej wasnoci byy widoczne dla kodu HTML.
W tym celu do skryptu dodajemy poniszy kod.
knockout/item.html
var item = new LineItem("Macbook Pro 15", 1699.00);
ko.applyBindings(item);
Tworzymy nowy egzemplarz obiektu
LineItem
, ustawiajc w nim nazw i cen
produktu, i wywoujemy na nim metod Knockout
applyBindings()
. Póniej
to zmienimy, ale na razie wystarczy nam zakodowanie danych na stae.
Majc obiekt, moemy zbudowa interfejs i pobra z tego obiektu dane. Koszyk
zbudujemy na bazie tabeli HTML z elementami strukturalnymi
<thead>
i
<tbody>
.
knockout/item.html
<div role="application">
<table>
<thead>
<tr>
<th>Produkt</th>
<th>Cena</th>
<th>Liczba</th>
<th>Suma</th>
</tr>
</thead>
<tbody>
<tr aria-live="polite">
<td data-bind="text: name"></td>
<td data-bind="text: price"></td>
</tr>
</tbody>
</table>
</div>
Kup książkę
Poleć książkę
Rozdzia 2. • Interfejs uytkownika
99
Poniewa wiersze tabeli s aktualizowane danymi wprowadzanymi przez uytkow-
nika, wierszom tym nadalimy atrybut
aria-live
, aby czytniki ekranu wiedziay,
e naley si w nich spodziewa zmian. Cay koszyk dodatkowo umiecilimy
w elemencie
<div>
z atrybutem HTML5-ARIA
application
, który informuje
czytniki, e jest to aplikacja interaktywna. Wicej informacji na temat tych atry-
butów mona przeczyta w specyfikacji HTML5
14
.
Szczególn uwag naley zwróci na ponisze dwa wiersze kodu:
knockout/item.html
<td data-bind="text: name"></td>
<td data-bind="text: price"></td>
Teraz nasz egzemplarz
LineInstance
jest widoczny globalnie na caej stronie, a wic
tak samo widoczne s jego wasnoci
name
i
price
. Te dwa wiersze kodu ozna-
czaj, e tekst (
text
) tych elementów chcemy pobiera z wasnoci o okrelonych
nazwach.
Gdy teraz wczytamy nasz stron w przegldarce, to zauwaymy, e zaczyna
nabiera ksztatu oraz e pola nazwy i ceny produktu s wypenione!
Teraz dodamy pole, w którym uytkownik bdzie móg zmieni liczb produktów
w zamówieniu.
knockout/item.html
<td><input type="text" name="quantity"
data-bind='value: quantity, valueUpdate: "keyup"'>
</td>
W bibliotece Knockout do odwoywania si do pól danych w postaci elementów
HTML suy parametr
text
, ale elementy formularzy HTML takie jak
<input>
maj atrybut
value
. Dlatego tym razem zwizalimy atrybut
value
z wasnoci
quantity
.
Wasno
quantity
suy nie tylko do wywietlania danych, lecz równie do ich
ustawiania. A gdy ustawimy dane, musimy te uruchomi zdarzenia. Do tego celu
uywamy funkcji Knockout
ko.observable()
jako wartoci wasnoci
quantity
naszej klasy.
this.quantity = ko.observable(1);
Funkcji
ko.observable()
przekazalimy domyln warto, aby po wywietleniu
strony po raz pierwszy pole tekstowe co ju zawierao.
Teraz moemy ju wpisa liczb, ale chcielibymy jeszcze dodatkowo wywietli
sum czstkow dla kadego wiersza. Dodamy do tabeli kolumn na t kwot:
14
http://www.w3.org/TR/html5-author/wai-aria.html
Kup książkę
Poleć książkę
100
Web development. Receptury nowej generacji
knockout/item.html
<td data-bind="text: subtotal "></td>
Podobnie jak w przypadku kolumn nazwy i ceny, tekst komórki ustawiamy na
warto wasnoci
subtotal
modelu widoku.
To doprowadzio nas do jednej z najwaniejszych czci biblioteki Knockout.js,
metody
dependentObservable()
. Wasno
quantity
zdefiniowalimy jako obser-
wowaln, co oznacza, e gdy pole zmieni warto, zmiana ta bdzie zauwaona
przez inne elementy. Deklarujemy metod
dependentObservable()
, która bdzie
wykonywa kod w reakcji na zmian wartoci obserwowanego pola, oraz przypi-
sujemy t metod do wasnoci naszego obiektu, aby mona j byo zwiza
z naszym interfejsem uytkownika.
this.subtotal = ko.dependentObservable(function() {
return(
this.price * parseInt("0"+this.quantity(), 10)
); //<label id="code.subtotal">
}, this);
Ale skd metoda
dependentObservable()
wie, które pola obserwowa? Przeglda
obserwowalne wasnoci, które wymieniamy w definiowanej funkcji. Poniewa
mnoymy cen i liczb, Knockout ledzi obie te wasnoci i wykonuje kod, gdy któ-
rakolwiek z nich si zmieni.
Metoda
dependentObservable()
przyjmuje take drugi parametr, który okrela
kontekst dla wasnoci. Ma to zwizek ze sposobem dziaania funkcji i obiektów
w JavaScripcie. Wicej na ten temat mona przeczyta w dokumentacji biblioteki
Knockout.js.
To wszystko, jeli chodzi o pojedynczy wiersz tabeli. Gdy zmienimy liczb pro-
duktów w zamówieniu, cena zostanie natychmiast zaktualizowana. Teraz roz-
budujemy uzyskan struktur, aby utworzy koszyk na wiele produktów, wywie-
tlajcy dodatkowo sumy czstkowe i ogóln sum nalenoci.
Wizania przepywu sterowania
Wizanie obiektów z elementami HTML jest bardzo wygodne, ale w koszyku
rzadko kiedy jest tylko jeden produkt, a duplikowanie caego tego kodu byoby
bardzo mudne, nie mówic ju o dodatkowych komplikacjach zwizanych z wik-
sz liczb obiektów
LineItem
. Musimy co zmieni.
Zamiast obiektu
LineItem
w roli modelu widoku, do reprezentowania koszyka
uyjemy innego obiektu. Nadamy mu nazw
Cart
i bdziemy w nim przechowy-
wa wszystkie obiekty
LineItem
. Wiedzc, jak dziaa metoda
dependentObservables()
,
Kup książkę
Poleć książkę
Rozdzia 2. • Interfejs uytkownika
101
moemy w obiekcie
Cart
utworzy wasno obliczajc sum nalenoci, gdy
zmieni si którykolwiek z elementów koszyka.
A co z kodem HTML dla pojedynczego produktu? Duplikowania kodu moemy
unikn dziki uyciu tzw. wizania przepywu sterowania (ang. control
flow binding) i nakazujc Knockout wyrenderowanie kodu HTML dla kadego
produktu w koszyku.
Najpierw zdefiniujemy tablic elementów, których uyjemy do napenienia
koszyka.
knockout/update_cart.html
var products = [
{name: "Macbook Pro 15 inch", price: 1699.00},
{name: "Przejciówka Mini Display Port na VGA", price: 29.00},
{name: "Magic Trackpad", price: 69.00},
{name: "Klawiatura bezprzewodowa Apple", price: 69.00}
];
W realnej aplikacji dane te pobieralibymy z usugi sieciowej lub wywoania Ajax
albo generowalibymy je na serwerze podczas serwowania strony.
Teraz utworzymy obiekt
Cart
do przechowywania produktów. Zdefiniujemy go
w taki sam sposób, jak obiekt
LineItem
.
knockout/update_cart.html
var Cart = function(items){
this.items = ko.observableArray();
for(var i in items){
var item = new LineItem(items[i].name, items[i].price);
this.items.push(item);
}
}
Musimy zmieni wizanie z
LineItem
na klas
Cart
.
knockout/update_cart.html
var cartViewModel = new Cart(products);
ko.applyBindings(cartViewModel);
Produkty s zapisywane w koszyku za pomoc metody
observableArray()
, która
dziaa tak samo jak
observable()
, ale ma waciwoci tablicy. Gdy utworzylimy
nowy egzemplarz naszego koszyka, przekazalimy do niego tablic danych. Nasz
obiekt iteruje po elementach danych i tworzy nowe egzemplarze
LineItem
, które
s zapisywane w tablicy produktów. Poniewa tablica ta jest obserwowalna,
interfejs zmieni si po kadej zmianie zawartoci tej tablicy. Oczywicie, teraz
mamy wicej ni jeden produkt, a wic musimy zmodyfikowa nasz interfejs.
Kup książkę
Poleć książkę
102
Web development. Receptury nowej generacji
Ja pyta:
Jak wyglda sprawa dostpnoci
w przypadku biblioteki Knockout?
Interfejsy w duym stopniu oparte na JavaScripcie czsto bardzo sabo
wypadaj pod wzgldem dostpnoci, jednak uycie tego jzyka samo
w sobie o niczym jeszcze nie wiadczy.
W tej recepturze uylimy ról i atrybutów HTML5 ARIA, aby pomóc czyt-
nikom ekranu w zrozumieniu dziaania naszej aplikacji. Jednak kwestie
dostpnoci dotycz nie tylko czytników. W dostpnoci chodzi ogólnie
o umoliwienie dostpu do treci jak najszerszemu gronu odbiorców.
Knockout to rozwizanie napisane w JavaScripcie, a wic dziaa tylko wów-
czas, gdy obsuga tego jzyka jest wczona. Trzeba to bra pod uwag.
Najlepiej jest najpierw napisa aplikacj, która jest uyteczna bez Java-
Scriptu, a nastpnie za pomoc biblioteki Knockout doda róne ulepszenia.
W naszym przykadzie zawarto koszyka jest renderowana za pomoc
biblioteki Knockout, ale gdybymy uyli której z technologii serwerowych,
moglibymy renderowa kod koszyka i stosowa wizania Knockout do
wyrenderowanego kodu HTML. Dostpno aplikacji zaley przede wszyst-
kim od sposobu jej zaimplementowania, a nie od konkretnej uytej do jej
budowy biblioteki.
Nastpnie zmodyfikujemy nasz stron HTML i nakaemy Knockout utworzy
wiersz tabeli dla kadego produktu za pomoc wywoania
data-bind
na elemencie
<tbody>
.
knockout/update_cart.html
h
<tbody data-bind="foreach: items">
<tr aria=live="polite">
<td data-bind="text: name"></td>
<td data-bind="text: price"></td>
<td><input type="text" name="quantity" data-bind='value: quantity'></td>
<td data-bind="text: subtotal "></td>
</tr>
</tbody>
Nakazalimy bibliotece Knockout wyrenderowa zawarto elementu
<tbody>
dla
kadego elementu tablicy
items
. Nie musimy nic wicej zmienia.
Teraz na naszej stronie moe by wywietlanych wiele wierszy tabeli i dla ka-
dego z nich bdzie wywietlana suma czstkowa. Zajmiemy si obliczaniem ca-
kowitej kwoty do zapaty i usuwaniem elementów.
Kup książkę
Poleć książkę
Rozdzia 2. • Interfejs uytkownika
103
Kwota do zapaty
Sposób dziaania metody Knockout
dependentObservable()
poznalimy ju przy
okazji obliczania sumy czstkowej dla kadego produktu. Dodajc j do obiektu
Cart
, moemy jej uy take do obliczania sumy cakowitej.
this.total = ko.dependentObservable(function(){
var total = 0;
for (item in this.items()){
total += this.items()[item].subtotal();
}
return total;
}, this);
Kod ten zostanie uruchomiony za kadym razem, gdy zmieni si którykolwiek
z produktów. Aby wywietli sum cakowit, musimy oczywicie jeszcze doda
jeden wiersz do tabeli. Poniewa ma to by suma cakowita nalenoci za wszyst-
kie produkty, wiersz ten umiecimy poza elementem
<tbody>
, w elemencie
<tfoot>
umieszczonym bezporednio pod zamykajcym znacznikiem
</thead>
. Umiesz-
czenie stopki nad treci tabeli pomaga niektórym przegldarkom i technologiom
pomocniczym w szybszym rozpracowaniu struktury tabeli.
knockout/update_cart.html
<tfoot>
<tr>
<td colspan="4">Naleno</td>
<td aria-live="polite" data-bind="text: total()"></td>
</tr>
</tfoot>
Gdy odwieymy stron i zmienimy liczb przy którym z produktów, nastpi
automatyczna aktualizacja sumy czstkowej i cakowitej. Teraz przejdziemy do
przycisku usuwania produktów.
Usuwanie produktów
Na zakoczenie musimy jeszcze doda przycisk Usu obok kadego produktu,
sucy do jego usunicia z koszyka. Dziki caej wykonanej do tej pory pracy
zadanie to jest ju bardzo atwe. Najpierw dodamy przycisk do tabeli.
<td>
<button
data-bind="click: function() { cartViewModel.remove(this) }">Usu
</button>
</td>
Tym razem zamiast wiza dane z interfejsem, wiemy zdarzenie i funkcj.
Przekazujemy
this
do metody
remove()
wywoywanej na rzecz egzemplarza
cartViewModel
. Przycisk ten jednak nie dziaa, poniewa jeszcze nie zdefiniowa-
limy metody
remove()
. Jej definicja znajduje si poniej:
Kup książkę
Poleć książkę
104
Web development. Receptury nowej generacji
yj w zgodzie z serwerem!
Coraz wiksz popularno zdobywaj koszyki na zakupy, których aktu-
alizacja odbywa si w caoci wycznie po stronie klienta. Czasami po pro-
stu niemoliwe jest wysyanie da Ajax za kadym razem, gdy uytkow-
nik zmieni co w interfejsie.
Stosujc to podejcie, musisz zadba o synchronizacj danych w koszyku
na kliencie z danymi na serwerze. Przecie nie chciaby, aby kto zmienia
ceny produktów za Ciebie!
Gdy uytkownik przechodzi do kasy, naley przesa zaktualizowane war-
toci na serwer i tam obliczy sumy przed sfinalizowaniem transakcji.
knockout/update_cart.html
this.remove = function(item){ this.items.remove(item); }
To wszystko! Poniewa tablica
items
jest obserwowalna (
observableArray
), aktuali-
zowany jest cay interfejs, wraz sum cakowit!
Kontynuacja
Biblioteka Knockout jest doskonaym narzdziem do tworzenia dynamicznych
jednostronicowych interfejsów, a dziki temu, e nie jest zwizana z adnym
frameworkiem sieciowym, moemy jej uywa, gdzie tylko chcemy.
Co waniejsze, modele widoków uywane w tej bibliotece s zwykym kodem
JavaScript, dziki czemu mona jej uywa do implementowania wielu czsto
potrzebnych funkcji interfejsu uytkownika. Na przykad przy uyciu Ajaksa
z atwoci mona by byo utworzy funkcj wyszukiwania biecego, zbudowa
kontrolki do edycji danych przesyajce dane na serwer w celu ich zachowania,
a nawet aktualizowa zawarto jednego menu rozwijanego na podstawie wartoci
wybranej w innym.
Zobacz równie
Receptura 14.: „Organizacja kodu przy uyciu biblioteki Backbone.js”
Kup książkę
Poleć książkę
Rozdzia 2. • Interfejs uytkownika
105
Receptura 14.
Organizacja kodu
przy uyciu biblioteki Backbone.js
Problem
W odpowiedzi na rosnce wymagania uytkowników w kwestii niezawodnoci
i interaktywnoci aplikacji dziaajcych po stronie klienta, programici cigle
tworz nowe niesamowite biblioteki JavaScript. Jednak im bardziej skompliko-
wana jest dana aplikacja, tym bardziej jej kod wyglda jak pobojowisko pene
porozrzucanych bez adu i skadu rozmaitych bibliotek, wiza zdarze, wywo-
a Ajax jQuery i funkcji przetwarzajcych dane w formacie JSON.
Potrzebna jest nam metoda tworzenia aplikacji dziaajcych po stronie klienta
w taki sam sposób, jak od lat tworzymy aplikacje serwerowe. Krótko mówic,
potrzebujemy jakiego frameworku. Majc solidny framework JavaScript, utrzy-
mamy porzdek w programie, zredukujemy powtarzalno kodu oraz zastosujemy
standard zrozumiay take dla innych programistów.
Poniewa Backbone to skomplikowana biblioteka, ta receptura jest
znacznie dusza i bardziej skomplikowana od innych.
Skadniki
Backbone.js
15
Underscore.js
16
JSON2.js
17
Mustache
18
jQuery
QEDServer
15
http://documentcloud.github.com/backbone
16
http://documentcloud.github.com/underscore/
17
https://github.com/douglascrockford/JSON-js
18
http://mustache.github.com/
Kup książkę
Poleć książkę
106
Web development. Receptury nowej generacji
Rozwizanie
To zadanie moemy wykona przy uyciu wielu rónych frameworków, ale
Backbone.js jest jednym z najpopularniejszych, dziki swojej elastycznoci,
niezawodnoci i ogólnie wysokiej jakoci kodu. W chwili pisania tych sów by
jeszcze wzgldnie nowy, a mia ju wielu uytkowników. Przy uyciu Backbone
moemy wiza zdarzenia w podobny sposób, jak to robilimy przy uyciu
Knockout w recepturze 13., „Tworzenie interaktywnych interfejsów uytkownika
przy uyciu biblioteki Knockout.js”, ale teraz otrzymujemy modele wspópracujce
z serwerem oraz system trasowania da, za pomoc którego mona ledzi zmiany
w adresach URL. Dziki Backbone otrzymujemy bardziej niezawodny zrb apli-
kacji, który moe doskonale sprawdzi si w przypadku skomplikowanych aplikacji
serwerowych, ale stanowi przerost formy nad treci w przypadku prostszych
programów.
Uyjemy Backbone do poprawienia wraliwoci interfejsu naszego sklepu inter-
netowego, tzn. sprawimy, e bdzie ywiej reagowa na dziaania uytkownika.
Z naszych logów i bada zachowa uytkowników wynika, e odwieanie strony
trwa zbyt dugo, a wiele rzeczy, które wykonuje si za porednictwem serwera,
mona by byo zrobi na kliencie. Nasz kierownik zasugerowa, abymy cay
interfejs zarzdzania produktami zmiecili na pojedynczej stronie, na której bdzie
mona dodawa i usuwa produkty bez odwieania strony.
Zanim rozpoczniemy budow naszego interfejsu, bliej poznamy Backbone
i dowiemy si, jak za pomoc tej biblioteki moemy rozwiza nasz problem.
Podstawy Backbone
Backbone to dziaajca po stronie klienta implementacja wzorca model-widok-
-kontroler, na powstanie której duy wpyw miay serwerowe frameworki, takie
jak ASP.NET MVC i Ruby on Rails. Backbone ma kilka komponentów poma-
gajcych dobrze zorganizowa kod zwizany z komunikacj z serwerem.
Modele reprezentuj dane i mog wspópracowa z naszym zapleczem za pored-
nictwem Ajaksa. Ponadto s doskonaym miejscem na wpisanie logiki biznesowej
i kodu sprawdzajcego poprawno danych.
Widoki w Backbone nieco róni si od widoków w innych frameworkach. S nie
tyle warstw prezentacji, co raczej „kontrolerami widoku”. W interfejsie typowej
aplikacji dziaajcej po stronie klienta moe by wiele zdarze. Kod wywoywany
przez te zdarzenia jest przechowywany wanie w tych widokach. Nastpnie mog
one renderowa szablony i modyfikowa nasz interfejs uytkownika.
Kup książkę
Poleć książkę
Rozdzia 2. • Interfejs uytkownika
107
Routery ledz zmiany adresu URL i mog wiza ze sob modele i widoki.
Gdy chcemy pokaza w interfejsie róne „strony” lub karty, do obsugi da
i w celu wywietlania rónych widoków moemy uy routerów. W Backbone
obsuguj one take przycisk Wstecz przegldarki.
W kocu w Backbone dostpne s kolekcje, dziki którym moemy atwo pobie-
ra zbiory egzemplarzy modeli, z którymi chcemy pracowa. Na rysunku 2.10
pokazano, jak poszczególne elementy Backbone ze sob wspópracuj oraz w jaki
sposób uyjemy ich do budowy naszego interfejsu do zarzdzania produktami.
Rysunek 2.10.
Skadniki Backbone
Domylnie modele Backbone komunikuj si z serwerow aplikacj RESTful
przy uyciu metody
ajax()
z biblioteki jQuery i formatu JSON. Zaplecze musi
akceptowa dania
GET
,
POST
,
PUT
i
DELETE
oraz rozpoznawa dane w formacie
JSON w treci tych da. S to jednak tylko ustawienia domylne, które mona
zmodyfikowa. W dokumentacji Backbone znajduj si informacje na temat tego,
jak zmodyfikowa kod dziaajcy po stronie klienta tak, aby wspópracowa
z rónymi rodzajami zapleczy.
Nasze zaplecze bdzie obsugiwa domylne ustawienia, a wic bdziemy mogli
wywoywa niektóre metody na modelach Backbone, a framework bdzie niepo-
strzeenie serializowa i deserializowa informacje o naszych produktach.
Kup książkę
Poleć książkę
108
Web development. Receptury nowej generacji
I jeszcze jedna uwaga na koniec: jak napisalimy w ramce „Jak wyglda sprawa
dostpnoci w przypadku biblioteki Knockout?”, frameworków typu Backbone
najlepiej jest uywa jako nakadek na ju istniejce strony internetowe, aby
ulepszy ich cechy uytkowe. Jeli Twój kod dziaajcy po stronie klienta bdzie
zbudowany na solidnej podstawie, atwiej bdzie opracowa rozwizanie dziaa-
jce take bez JavaScriptu. W tej recepturze pracujemy z interfejsem, który ju ma
wersj dziaajc bez JavaScriptu.
Budowa interfejsu
Zbudujemy prosty, mieszczcy si na jednej stronie interfejs do zarzdzania
produktami w naszym sklepie. Jego schemat przedstawiony jest na rysunku 2.11.
Na górze strony bdzie si znajdowa formularz do dodawania produktów, a pod
nim umiecimy list produktów. Dane z magazynu produktów bdziemy pobiera
i modyfikowa przy uyciu Backbone i jego interfejsu w stylu REST:
danie
GET()
do http://przyklad.com/products.json pobiera list pro-
duktów.
danie
GET
do /products/1.json pobiera dane produktu o identyfikatorze
1
w formacie JSON.
danie
POST
do /products.json z reprezentacj produktu w formacie
JSON w treci tworzy nowy produkt.
danie
PUT
do http://example.com/products/1.json z reprezentacj pro-
duktu w formacie JSON w treci aktualizuje produkt o identyfikatorze
1
.
danie
DELETE
do /products/1.json usuwa produkt o identyfikatorze
1
.
Poniewa dania Ajax musz by wykonywane do tej samej domeny, do testo-
wania uyjemy serwera QEDServer i jego API do zarzdzania produktami.
Wszystkie nasze pliki umiecimy w folderze public utworzonym przez serwer
w przestrzeni roboczej.
Budow interfejsu rozpoczniemy od utworzenia modelu produktu i kolekcji do
przechowywania wielu modeli produktów. dania wywietlenia listy produktów
i formularza dodawania nowego produktu obsuymy za pomoc routera. Ponadto
utworzymy widoki listy produktów i formularza produktu.
Najpierw utworzymy folder lib na bibliotek Backbone i jej zalenoci.
$ mkdir javascripts
$ mkdir javascripts/lib
Kup książkę
Poleć książkę
Rozdzia 2. • Interfejs uytkownika
109
Rysunek 2.11.
Nasz interfejs do zarzdzania produktami
Nastpnie pobierzemy Backbone.js wraz ze wszystkimi skadnikami ze strony in-
ternetowej
19
. W tej recepturze uywamy Backbone 0.5.3. Biblioteka ta wymaga
obecnoci biblioteki Underscore.js zawierajcej pewne funkcje wykorzystywane
wewntrznie przez Backbone, a dziki którym my moemy zaoszczdzi na
pisaniu kodu. Dodatkowo potrzebujemy biblioteki JSON2, która ma rozszerzone
moliwoci w zakresie obróbki danych w formacie JSON w przegldarkach.
Dodatkowo przyda nam si jzyk szablonowy biblioteki Mustache
20
. Pobierz
wszystkie te pliki i umie je w folderze javascripts/lib.
Na koniec utworzymy plik o nazwie app.js w folderze javascripts. W pliku tym
bd si znajdowa wszystkie nasze skadniki Backbone i nasz wasny kod.
19
http://documentcloud.github.com/backbone/
20
Aby nie traci czasu, wszystkie potrzebne pliki znajdziesz w kodzie ródowym doczo-
nym do tej ksiki.
Kup książkę
Poleć książkę
110
Web development. Receptury nowej generacji
Mimo i mona by byo utworzy z tego dwa pliki, to jednak w ten sposób przy
kadym wczytywaniu strony oszczdzamy jedno odwoanie do serwera.
Majc przygotowane wszystkie pliki, utworzymy bardzo prosty szkielet HTML
w pliku index.html, w którym bd znajdoway si skadniki naszego interfejsu
uytkownika oraz bd doczone pozostae pliki. Zaczniemy od zdefiniowania
typowych elementów strukturalnych oraz utworzymy elementy
<div>
na wiadomoci
dla uytkownika, formularz i list produktów (
<ul>
).
backbone/public/index.html
<!DOCTYPE html>
<html>
<head>
<title>Zarzdzanie produktami </title>
</head>
<body role="application">
<h1>Produkty</h1>
<div aria-live="polite" id="notice">
</div>
<div aria-live="polite" id="form">
</div>
<p><a href="#new">Nowy produkt</a></p>
<ul aria-live="polite" id="list">
</ul>
</body>
</html>
Te obszary bd aktualizowane bez odwieania strony, w zwizku z czym
dodalimy atrybuty ARIA HTML5, aby poinformowa czytniki ekranu, jak
maj obsugiwa te zdarzenia
21
.
Pod tymi obszarami, a bezporednio nad zamykajcym znacznikiem
</body>
umie-
cimy jQuery i Backbone z zalenociami oraz plik app.js:
Backbone/public/index.html
<script type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.7/jquery.min.js">
</script>
<script type="text/javascript"
src="javascripts/lib/json2.js"></script>
<script type="text/javascript"
src="javascripts/lib/underscore-min.js"></script>
<script type="text/javascript"
src="javascripts/lib/backbone-min.js"></script>
<script type="text/javascript"
src="javascripts/lib/mustache.js"></script>
<script type="text/javascript"
src="javascripts/app.js"></script>
21
http://www.w3.org/TR/html5-author/wai-aria.html
Kup książkę
Poleć książkę
Rozdzia 2. • Interfejs uytkownika
111
Teraz moemy rozpocz tworzenie listy produktów.
Tworzenie listy produktów
Aby utworzy list produktów, pobierzemy produkty z naszego zaplecza Ajax.
Do tego celu potrzebne nam bd model i kolekcja. Model bdzie reprezentowa
pojedynczy produkt, a kolekcja — grup produktów. Tworzc i usuwajc pro-
dukty, bdziemy korzysta bezporednio z modelu. Natomiast pobierajc list
produktów z serwera, moemy uy kolekcji w celu pobrania rekordów i otrzyma-
nia grupy modeli Backbone, z którymi bdziemy mogli pracowa.
Najpierw utworzymy model. W pliku javascripts/app.js umiecimy nastpujc
definicj obiektu
Product
:
backbone/public/javascripts/app.js
var Product = Backbone.Model.extend({
defaults: {
name: "",
description: "",
price: ""
},
url : function() {
return(this.isNew() ? "/products.json" : "/products/" + this.id + ".json");
}
});
Ustawilimy kilka domylnych wartoci dla przypadków, w których nie bdzie
adnych danych, jak np. gdy tworzymy nowy egzemplarz. Nastpnie informujemy
model, skd ma pobiera swoje dane. Backbone uywa do tego celu metody
url()
modelu, któr musimy wypeni.
Majc zdefiniowany model, moemy utworzy kolekcj, której uyjemy do pobra-
nia wszystkich produktów dla naszej strony listy.
backbone/public/javascripts/app.js
var ProductsCollection = Backbone.Collection.extend({
model: Product,
url: '/products.json'
});
Kolekcja, podobnie jak model, ma metod
url()
, któr musimy zaimplementowa.
Poniewa jednak chcemy tylko pobra list wszystkich produktów, moemy po
prostu na sztywno wpisa adres URL /products.json.
Poniewa z kolekcji tej bdziemy korzysta w kilku miejscach naszej aplikacji,
utworzymy jej egzemplarz. Obiekt ten zostanie utworzony na samym pocztku
pliku javascripts/app.js.
Kup książkę
Poleć książkę
112
Web development. Receptury nowej generacji
backbone/public/javascripts/app.js
$(function(){
window.products = new ProductsCollection();
Obiekt kolekcji wiemy z obiektem
window
, dziki czemu póniej bdziemy mieli
do niego atwy dostp z rónych widoków.
Mamy zdefiniowane model i kolekcj, a wic moemy przej do widoku.
Szablon listy i widok
Widoki w Backbone zawieraj logik odpowiedzialn za zmienianie interfejsu
w reakcji na zdarzenia. Do renderowania naszej listy produktów uyjemy dwóch
widoków. Jeden z nich bdzie reprezentowa pojedynczy produkt przy uyciu
szablonu Mustache i obsugiwa wszystkie zdarzenia zwizane z tym produktem.
Natomiast drugi widok bdzie iterowa przez kolekcj produktów i renderowa
pierwszy widok dla kadego obiektu, umieszczajc wyniki na naszej stronie. Dziki
temu bdziemy mieli szczegóow kontrol nad kadym skadnikiem.
Najpierw utworzymy prosty szablon Mustache, którego nasze widoki Backbone
bd uywa do iterowania przez kolekcj produktów. Szablon ten dodamy do
strony index.html, nad elementami
<script>
doczajcymi biblioteki:
backbone/public/index.html
<script type="text/html" id="product_template">
<li>
<h3>
{{name}} - {{price}}
<button class="delete">Usu</button>
</h3>
<p>{{description}}</p>
</li>
</script>
Wywietlamy nazw produktu, cen i opis oraz przycisk do usuwania tego pro-
duktu.
Nastpnie utworzymy nowy widok, o nazwie
ProductView
, rozszerzajc klas
Backbone
View
i definiujc kilka kluczowych elementów.
backbone/public/javascripts/app.js
ProductView = Backbone.View.extend({
template: $("#product_template"),
initialize: function(){
this.render();
},
render: function(){
}
});
Kup książkę
Poleć książkę
Rozdzia 2. • Interfejs uytkownika
113
Najpierw za pomoc jQuery pobralimy ze strony indeksowej nasz szablon
Mustache, posugujc si jego identyfikatorem, i zapisalimy go we wasnoci
o nazwie
template
. Dziki temu nie bdziemy musieli pobiera tego szablonu
ze strony za kadym razem, gdy chcemy wyrenderowa jaki produkt.
Nastpnie definiujemy funkcj
initialize()
, która bdzie uruchamiana po utwo-
rzeniu nowego egzemplarza
ListView
i która bdzie wywoywaa funkcj
render()
widoku.
Kady widok ma domyln funkcj
render()
, któr trzeba przedefiniowa, aby
robia to, co chcemy. W naszym przypadku bdzie ona renderowaa szablon
Mustache pobierany ze zmiennej
template
. Poniewa w zmiennej tej przechowy-
wany jest obiekt jQuery, musimy wywoa metod
html()
, aby pobra zawarto
szablonu z tego obiektu.
backbone/public/javascripts/app.js
render: function(){
var html = Mustache.to_html(this.template.html(), this.model.toJSON() );
$(this.el).html(html);
return this;
}
W metodzie tej uylimy odwoania do modelu
this.model
, który bdzie zawiera
potrzebn nam list produktów. Gdy utworzymy nowy egzemplarz widoku,
moemy do niego przypisa model lub kolekcj, aby móc si do nich odwoywa
w metodach widoku bez koniecznoci ich przekazywania, podobnie jak zrobilimy
z szablonem Mustache. Wywoujemy funkcj
toJSON()
na naszym modelu, który
przekazujemy do szablonu, aby dane tego modelu byy atwo dostpne w szablonie.
Metoda
render()
zapisuje kod HTML wyrenderowany z szablonu Mustache
we wasnoci widoku o nazwie
el
i zwraca ten egzemplarz widoku
ProductView
.
Gdy wywoamy t metod, pobierzemy wyniki z tej wasnoci i dodamy je do
strony.
W tym celu utworzymy widok o nazwie
ListView
i strukturze bardzo podobnej
do struktury widoku
ProductView
, tylko zamiast renderowa szablon Mustache,
bdzie on iterowa po kolekcji produktów i dla kadego z nich renderowa widok
ProductView
.
backbone/public/javascripts/app.js
ListView = Backbone.View.extend({
el: $("#list"),
initialize: function() {
this.render();
},
renderProduct: function(product){
Kup książkę
Poleć książkę
114
Web development. Receptury nowej generacji
var productView = new ProductView({model: product});
this.el.append(productView.render().el);
},
render: function() {
if(this.collection.length > 0) {
this.collection.each(this.renderProduct, this);
} else {
$("#notice").html("Brak produktów do wywietlenia.");
}
}
});
Musimy aktualizowa zawarto obszaru
list
na naszej stronie z list produktów.
Odwoanie do tego obszaru przechowujemy we wasnoci o nazwie
el
. Dziki
temu mamy wygodny dostp do tej listy w metodzie
render()
. W podobny sposób
postpilimy z szablonem Mustache w widoku
ProductView
.
Backbone korzysta z biblioteki Underscore.js, zawierajcej funkcje uatwiajce
prac z kolekcjami. W metodzie
render()
iterujemy przez kolekcj przy uyciu
metody
each()
i wywoujemy nasz metod
renderProduct
. Metoda
each()
automa-
tycznie przekazuje produkt. Jako drugi parametr przekazujemy
this
, co oznacza,
e kontekstem dla metody
renderProduct()
ma by widok. Bez tego metoda
each()
szukaaby metody
renderProduct()
w kolekcji, co uniemoliwioby jej dziaanie.
Zdefiniowalimy model, kolekcj i dwa widoki oraz dodalimy szablon, ale wci
nie mamy dla niego nic do wywietlenia. Musimy to wszystko poczy ze sob
podczas adowania strony w przegldarce. Do tego celu uyjemy routera.
Obsuga zmian adresów URL przy uyciu routerów
Podczas wczytywania strony bdzie uruchamiany kod pobierajcy kolekcj pro-
duktów z API Ajax. Nastpnie kolekcja ta bdzie przekazywana do nowego
egzemplarza widoku
ListView
w celu wywietlenia produktów. Routery Backbone
umoliwiaj wywoywanie funkcji w reakcji na zmiany adresu URL.
Utworzymy router o nazwie
ProductsRouter
. W tym celu rozszerzymy router
Backbone i zdefiniujemy tras mapujc cz adresu URL znajdujc si za
znakiem # na funkcj w naszym routerze. Dla domylnego przypadku odpowia-
dajcego sytuacji, gdy w adresie URL nie ma znaku #, zdefiniujemy pust tras,
któr zwiemy z funkcj o nazwie
index()
. Ta domylna trasa bdzie urucho-
miona przy wczytywaniu strony index.html.
backbone/public/javascripts/app.js
ProductsRouter = Backbone.Router.extend({
routes: {
"": "index"
},
Kup książkę
Poleć książkę
Rozdzia 2. • Interfejs uytkownika
115
index: function() {
}
});
W akcji
index()
wywoujemy metod
fetch()
naszej kolekcji produktów, aby
pobra dane z serwera.
backbone/public/javascripts/app.js
index: function() {
window.products.fetch({
success: function(){
new ListView({ collection: window.products });
},
error: function(){
$("#notice").html("Nie mona zaadowa produktów.");
}
});
}
Metoda
fetch()
pobiera funkcje zwrotne
success
i
error
. Gdy wystpi jaki bd,
wywietlamy komunikat o bdzie w obszarze
notice
strony. Gdy natomiast otrzy-
mamy kolekcj danych, zostaje wywoana funkcja zwrotna
success()
i nastpuje
utworzenie egzemplarza widoku. Poniewa dziki naszej metodzie widoku
initialize()
widok listy jest renderowany automatycznie, pozostaje nam jedynie
utworzenie nowego egzemplarza routera, aby to wszystko uruchomi.
W pliku javascripts/app.js pod definicj
window.productsCollection
tworzymy
egzemplarz routera. Nastpnie nakazujemy Backbone ledzenie zmian w adre-
sie URL.
backbone/public/javascripts/app.js
window.products = new ProductsCollection();
$.ajaxSetup({ cache: false });
window.router = new ProductsRouter();
Backbone.history.start();
Do rozpoczcia ledzenia zmian w adresie URL Backbone zmusza wiersz kodu
Backbone.history.start();
. Jeli zapomnimy o nim, router nie bdzie dziaa i na
stronie nic si nie bdzie dziao.
Poniszy wiersz wycza zapisywanie przez niektóre przegldarki w pamici
podrcznej odpowiedzi Ajax z serwera:
$.ajaxSetup({ cache: false });
Gdy teraz wejdziemy na stron http://localhost:8080/index.html, w kocu zoba-
czymy list naszych produktów.
Podsumujmy, co do tej pory zrobilimy. Mamy router obserwujcy adres URL
i wywoujcy metod, która przy uyciu naszej kolekcji pobiera modele z naszej
usugi sieciowej. Kolekcja ta jest nastpnie przekazywana do widoku, który
Kup książkę
Poleć książkę
116
Web development. Receptury nowej generacji
renderuje szablon i wysya go do interfejsu uytkownika. Interakcje te s przedsta-
wione w postaci schematu na rysunku 2.12. Moe si wydawa, e to wszystko
jest zbyt skomplikowane, jak na tak proste zadanie. Jednak w miar ewolucji
kodu pozwoli to zaoszczdzi ogromne iloci czasu. Stworzylimy podstawow
infrastruktur do dodawania, aktualizowania i usuwania produktów i nie bdziemy
musieli ju si tym wicej przejmowa. Teraz dodamy moliwo dodawania
produktów.
Rysunek 2.12.
Wywietlanie listy produktów przy uyciu Backbone
Tworzenie nowego produktu
Mechanizm tworzenia nowych produktów bdzie dziaa w ten sposób, e gdy
uytkownik kliknie cze Nowy produkt, na stronie pojawi si specjalny formularz.
Gdy uytkownik wypeni ten formularz, pobierzemy z niego dane, przekaemy je
do naszego zaplecza, a nastpnie wywietlimy na licie.
Zaczniemy od dodania szablonu Mustache dla formularza na stronie index.html.
Wstawimy go pod szablonem produktu, ale nad elementami
<script>
doczaj-
cymi nasze biblioteki:
backbone/public/index.html
<script type="text/html" id="product_form_template">
<form>
<div class="row">
<label>Nazwa<br>
<input id="product_name" type="text" name="name"
value="{{name}}">
</label>
Kup książkę
Poleć książkę
Rozdzia 2. • Interfejs uytkownika
117
</div>
<div class="row">
<label>Opis<br>
<textarea id="product_description"
name="description">{{description}}</textarea>
</label>
</div>
<div class="row">
<label>Cena<br>
<input id="product_price" type="text" name="price"
value="{{price}}">
</label>
</div>
<button>Zapisz</button>
</form>
<p><a id="cancel" href="#">Anuluj</a></p>
</script>
Znaczniki szablonu Mustache bd pobiera wartoci z modelu i wstawia je do
pól formularza. Dlatego wanie ustawilimy domylne wartoci w modelu Back-
bone. Szablonu tego moglibymy take uy ponownie do edycji rekordów.
Teraz potrzebujemy widoku do renderowania tego szablonu z modelu. W pliku
javascripts/app.js utworzymy nowy widok o nazwie
FormView
, podobny do tego,
który utworzylimy dla naszej listy. Tym razem jednak zmienn
el
ustawimy na
obszar
form
strony, a funkcja
render()
bdzie pobiera szablon formularza i ren-
derowa wynik w tym obszarze.
backbone/public/javascripts/app.js
FormView = Backbone.View.extend({
el: $("#form"),
template: $("#product_form_template"),
initialize: function(){
this.render();
},
render: function(){
var html = Mustache.to_html(this.template.html(), this.model.toJSON() );
this.el.html(html);
}
});
Gdy uytkownik kliknie cze Nowy produkt, widok powinien renderowa na
stronie formularz. Poniewa w wyniku tego nastpuje zmiana w adresie URL
polegajca na dodaniu do niego czci
#new
, moemy zdarzenie to obsuy za
pomoc routera. Najpierw musimy w sekcji tras doda tras
#new
, która odpowiada
miejscu wskazywanemu przez cze Nowy produkt.
backbone/public/javascripts/app.js
routes: {
"new": "newProduct",
"": "index"
},
Kup książkę
Poleć książkę
118
Web development. Receptury nowej generacji
Nastpnie musimy zdefiniowa funkcj pobierajc nowy model i przekazujc go
do nowego egzemplarza widoku formularza, aby widok ten móg zosta wyren-
derowany na stronie. Metod t umiecimy nad metod
index()
, a poniewa
deklaracje tych metod s zdefiniowane jako wasnoci obiektu
this
, musimy je
rozdzieli przecinkiem.
backbone/public/javascripts/app.js
newProduct: function() {
new FormView( {model: new Product()});
},
Gdy odwieymy stron i klikniemy cze Nowy produkt, zostanie wywietlony nasz
formularz. Dziki mechanizmowi ledzenia historii Backbone, gdy naciniemy
przycisk Wstecz przegldarki, adres URL ulegnie zmianie. Nie moemy jednak
jeszcze zapisywa nowych rekordów. Zajmiemy si tym teraz.
Reagowanie na zdarzenia w widoku
Uylimy naszego routera do wywietlenia formularza, ale routery reaguj tylko na
zmiany adresu URL. A musimy jeszcze doda obsug zdarze kliknicia przyci-
sków Zapisz i Anuluj. Zrobimy to w utworzonym wczeniej widoku formularza.
Zaczniemy od zdefiniowania zdarze dla widoku do obserwacji. Dodamy je do
widoku przed funkcj
initialize()
:
backbone/public/javascripts/app.js
events: {
"click .delete": "destroy"
},
events: {
"click #cancel": "close",
"submit form": "save",
},
Uyta tu skadnia nieco róni si od typowej skadni monitorowania zdarze
JavaScriptu. Klucz tablicy definiuje obserwowane zdarzenie. Po nim znajduje si
selektor CSS elementu, który ma by obserwowany. Natomiast warto okrela
funkcj widoku, któr chcemy wywoywa. W tym przypadku obserwujemy zda-
rzenie kliknicia dla przycisku anulowania i zdarzenie zatwierdzenia caego for-
mularza.
Kod obsugujcy cze „zamykania” jest prosty — po prostu usuwamy tre ele-
mentu HTML zawierajcego ten widok:
backbone/public/javascripts/app.js
close: function(){
this.el.unbind();
this.el.empty();
},
Kup książkę
Poleć książkę
Rozdzia 2. • Interfejs uytkownika
119
Metoda
save()
jest nieco bardziej skomplikowana. Najpierw wyczamy zatwier-
dzanie formularza, a nastpnie pobieramy wartoci wszystkich pól i umieszczamy
je w nowej tablicy. Póniej ustawiamy atrybuty modelu i wywoujemy jego metod
save()
.
backbone/public/javascripts/app.js
save: function(e){
e.preventDefault();
data = {
name: $("#product_name").val(),
description: $("#product_description").val(),
price: $("#product_price").val()
};
var self = this;
this.model.save(data, {
success: function(model, resp) {
$("#notice").html("Produkt zosta zapisany.");
window.products.add(self.model);
window.router.navigate("#");
self.close();
},
error: function(model, resp){
$("#notice").html("Bdy uniemoliwiy utworzenie produktu.");
}
});
},
Sposób uycia metody
save()
jest podobny do sposobu uycia metody
fetch()
,
tzn. naley zdefiniowa zarówno zachowanie w przypadku powodzenia, jak i nie-
powodzenia. Poniewa funkcje tych zachowa dziaaj w rónych kontekstach,
tworzymy tymczasow zmienn o nazwie
self
, do której przypisujemy biecy
kontekst, aby móc si do niego odwoa w metodzie powodzenia. W odrónieniu
od metody
each()
, której uywalimy do renderowania listy produktów, Backbone
nie umoliwia przekazywania parametru kontekstu do funkcji zwrotnych
22
.
Gdy zapisywanie danych powiedzie si, dodajemy nowy model do kolekcji i za
pomoc routera zmieniamy adres URL. Nie powoduje to jednak uruchomienia
odpowiedniej funkcji w routerze, przez co nie zobaczymy naszego produktu na
licie. Mona to jednak atwo naprawi dziki wizaniom zdarze w Backbone.
Gdy dodajemy model do kolekcji, kolekcja ta wywouje zdarzenie
add
, które
moemy obserwowa. Pamitasz metod
renderProduct()
z widoku listy? Moemy
sprawi, aby metoda ta bya wywoywana za kadym razem, gdy dodajemy model
do naszej kolekcji. Wystarczy w tym celu doda poniszy wiersz kodu do metody
initialize()
widoku
ListView
:
22
Przynajmniej w czasie pisania tej ksiki.
Kup książkę
Poleć książkę
120
Web development. Receptury nowej generacji
backbone/public/javascripts/app.js
this.collection.bind("add", this.renderProduct, this);
Metoda
bind()
umoliwia dokonywanie wiza ze zdarzeniami i jako argumenty
przyjmuje nazw zdarzenia, funkcj oraz kontekst. Jako trzeci argument przeka-
zalimy
this
, co oznacza, e chcemy, aby kontekstem by widok, a nie kolekcja.
Podobnie zrobilimy w metodzie
render()
widoku listy z
collection.each
.
Poniewa do dodania rekordu uylimy istniejcej metody
renderProduct()
, nowy
rekord zosta dodany na dole listy. Aby rekordy byy dodawane na pocztku listy,
moemy napisa now metod
addProduct()
, która uywaaby metody
prepend()
jQuery. Pozostawiamy to jednak jako zadanie do samodzielnego wykonania.
Moemy ju tworzy nowe produkty i wywietla ich list na stronie bez odwie-
ania. Czas doda mechanizm usuwania produktów. Teraz wanie skorzystamy
z dobrej organizacji naszego kodu.
Usuwanie produktu
Aby usun produkt, wykorzystamy umiejtnoci zdobyte podczas pracy nad wido-
kiem
FormView
oraz zaimplementujemy funkcj
destroy()
w widoku
ProductView
,
która bdzie wywoywana w wyniku nacinicia przycisku Usu.
Najpierw zdefiniujemy zdarzenie do obserwacji klikni przycisków nalecych
do klasy
delete
.
backbone/public/javascripts/app.js
events: {
"click .delete": "destroy"
},
events: {
"click #cancel": "close",
"submit form": "save",
},
Nastpnie definiujemy metod
destroy()
, któr to zdarzenie bdzie wywoywa.
W metodzie tej wywoamy metod
destroy()
modelu zwizanego z tym widokiem.
Zastosowanie ma w niej ta sama strategia powodzenia i bdu, której uywalimy
wczeniej. Skorzystamy te ze sztuczki ze sowem kluczowym
self
, aby obej
problemy z kontekstem, podobnie jak to zrobilimy przy zapisywaniu rekordów
w widoku formularza.
backbone/public/javascripts/app.js
destroy: function(){
var self = this;
this.model.destroy({
success: function(){
self.remove();
},
Kup książkę
Poleć książkę
Rozdzia 2. • Interfejs uytkownika
121
error: function(){
$("#notice").html("Wystpi problem podczas usuwania produktu.");
}
});
},
Gdy model zostanie usunity przez serwer, nastpuje wywoanie metody zwrotnej
success
wywoujcej metod
remove()
widoku, co powoduje zniknicie rekordu
z listy. Jeli co pójdzie nie tak, wywietlamy odpowiedni wiadomo.
To wszystko! Mamy prosty, dobrze zorganizowany prototyp, którym moemy si
ju chwali albo który moemy dalej rozwija.
Kontynuacja
Opisana aplikacja jest dobra na pocztek, ale jest par rzeczy, które mona
poprawi.
Po pierwsze, za pomoc jQuery aktualizujemy uwag
notice
w kilku miejscach:
$("#notice").html("Produkt zosta zapisany.");
Mona by byo utworzy funkcj opakowujc do oddzielenia tego od kodu
HTML albo nawet uy innego widoku Backbone i szablonu Mustache, aby
wywietli te wiadomoci.
Gdy zapisujemy rekordy, wartoci z formularza pobieramy przy uyciu selektorów
jQuery. Dane mona by byo umieszcza od razu w egzemplarzu modelu przy
uyciu zdarze
onchange
pól formularza.
W tej recepturze przedstawilimy rozwizania dotyczce dodawania i usuwania
rekordów, ale mona jeszcze doda moliwo ich edycji. Moemy uy routera
do wywietlania formularza, a nawet wykorzysta ten sam widok formularza, któ-
rego uywalimy do tworzenia produktów.
Backbone to doskonay system usprawniajcy prac z danymi zapleczowymi, ale
to dopiero pocztek. Nie musisz uywa Ajaksa. Równie dobrze dane moesz
zapisywa na kliencie przy uyciu HTML5.
W celu lepszej integracji z aplikacjami serwerowymi Backbone obsuguje metod
pushState()
obiektu
History
HTML5, dziki czemu mona uywa prawdziwych
adresów URL zamiast fragmentów ze znakiem #. Dodatkowo mona opracowa
mechanizmy awaryjne, które bd serwowa strony, gdy wyczona jest obsuga
JavaScriptu.
Kup książkę
Poleć książkę
122
Web development. Receptury nowej generacji
Dziki wielu opcjom i doskonaej obsudze Ajaksa Backbone jest niezwykle ela-
stycznym frameworkiem, który najlepiej sprawdza si w sytuacjach, gdy potrzebna
jest dobrze zorganizowana struktura kodu.
Zobacz równie
Receptura 10.: „Tworzenie szablonów HTML przy uyciu systemu
Mustache”
Receptura 13.: „Tworzenie interaktywnych interfejsów uytkownika przy
uyciu biblioteki Knockout.js”
Kup książkę
Poleć książkę
Skorowidz
A
adres URL, 94
akcja index(), 115
aktualizowanie adresu
URL, 94
animacja poysku, 31
animacje, 28
API Flickr, 144
API History, 95
API JavaScript Map
Google, 125
API Map Google, 123
API QEDServer, 86
API Sauce Labs, 250
aplikacja
RESTful, 107
CouchApp, 156
archiwum ClickHeat, 240
arkusze stylów, 54
asercje, 243
atrapa, mock, 267
atrybut
action, 138
aria-live, 99
data, 97
data-direction, 185
data-icon, 180
data-product-id, 183
data-role, 180
media, 165
value, 142
atrybuty HTML5 ARIA,
102, 110
automatyczne
dopasowanie treci, 165
przewijanie, 35
automatyzacja
procesów, 302
wdraania, 301
B
baza danych CouchDB,
153, 155, 161
bazy danych, 154
BDD, behavior-driven
development, 248
biblioteka
Backbone.js, 95, 105
HAML, 198
Highcharts, 130, 136
HTMLShiv, 194
Jekyll, 200
jQuery, 13
jQuery 1.6.4, 179
jQuery Mobile, 178
jQuery UI Effects, 45
Knockout, 96, 104
Mustache, 109
blog, 200
blok describe(), 262
blokowanie adresów IP, 291
bdy, 143
w formularzu, 140
w kodzie, 234
budowa serwisu, 203
C
cechy Cucumber, 253
certyfikaty SNI, 288
cienie, 197
CSS3, 22
CTH, Cucumber Testing
Harness, 249
cudzysów, 24
cytat blokowy, 24
czas transformacji, 32
czytniki ekranu, 99
D
debugowanie, 236
debugowanie JavaScriptu,
233, 265
definicja przejcia, 31
Kup książkę
Poleć książkę
312
Web development. Receptury nowej generacji
definiowanie wasnych
atrybutów, 41
deklaracja
box-shadow, 30
HUB, 251
dodatek
CoffeeScript, 215
Firebug, 234, 235
Firebug Lite, 233
Guard, 298
IE Developer Toolbar,
234
Selenium IDE, 243
dodawanie
cieni, 19
gradientu, 20
produktów, 116
zaokrgle, 19
dokumentacja
Backbone, 107
jQuery Mobile, 186
domieszki, mixin, 210
dostp do katalogu, 289
dymek, 26, 212
dynamiczne adowanie
treci, 183
dyrektywa DocumentRoot,
287
dzielenie treci na strony, 84
E
edytor Vim, 279–281, 284
efekt
fade, 36
poysku, 29
egzemplarz
LineInstance, 99
routera, 115
element
<blink>, 51
<blockquote>, 24, 27
<body>, 50
<center>, 51
<cite>, 24
<div>, 30, 43, 82
<footer>, 194
<header>, 194
<html>, 140
<img>, 29, 42, 195
<li>, 61
<link>, 165
<object>, 32
<script>, 81
<style>, 54
<tbody>, 98
<tfoot>, 103
<thead>, 98
meta viewport, 165
textarea, 142
F
faktura, 49, 56
faszywka, fake, 267
folder
_attachments, 156
_layouts, 201
_site, 203
bundles, 284
coffeescripts, 220
css, 204
Dropbox, 272
git_site, 223
image_cycling, 34
images, 205
Jasmine, 261
javascripts, 298
js, 205
sass, 209
statuses, 157
format
JSON, 90
JSONP, 144
PNG, 49
YAML, 202
formularz
HTML, 138
kontaktowy, 137, 139,
143
udostpniania folderu,
273
framework
CouchApp, 154
Evently, 160
Ruby on Rails, 305
funkcja
.fadeIn(), 62
.show(), 62
activateDialogFor(), 44
ajax(), 145
append_help_to(), 236
appendHelpTo(), 43
beforeEach(), 264
changePage(), 186
console.log(), 237
createTabs(), 63
cycle(), 36
displayHelpers(), 41,
44
displayHelpFor(), 44
displayTab(), 62
DomReady(), 268
dragPopup(), 175
event.preventDefault(),
69
event.stopPropagation(),
69
get(), 44
getCurrentPageNumber(),
76
getJSON(), 185
getNextPage(), 89
getQueryString(), 76
initialize(), 113, 118
jsonFlickrApi(), 145
ko.observable(), 99
loadData(), 88
loadMap(), 125
Kup książkę
Poleć książkę
Skorowidz
313
loadPhotos(), 145
mail(), 140
nextPageWithJSON(),
88
observeMove(), 175
phpinfo(), 293
prependToggleAllLinks(),
68
pushState(), 91, 94
randomString(), 43
ready, 41
render(), 113, 117
replacePageNumber(),
77
scrollToEntry(), 75
scrollToPrevious(), 75
set_icon_to(), 238
setHelperClassTo(), 42
setIconTo(), 42
setupButtons(), 36
setupCreateClickEvent(),
266
slideDown(), 62
styleExamples(), 60, 63
success(), 115
to_html(), 80
toggleControls(), 36
toggleDisplayOf(), 44,
45, 46
toggleExpandCollapse(),
68
toJSON(), 113
updateBrowserUrl(), 94
updateContent(), 94
widget(), 151
funkcje
nawigacyjne, 73
przecigania, 171, 173
przewijania, 74
zwijania, 66
Sauce Labs, 260
G
ga new_feature, 230
gazie, 228
generator stron statycznych,
200
generowanie arkuszy stylów,
213
gradient tekstury, 20
H
HTML5, 13
I
identyfikator widget, 151
implementacja kart, 198
informacje
o bdach, 246
o tecie, 256
inspekcja elementów, 237
instalowanie
Apache, 277
CoffeeScriptu, 217
Gita, 223
Jekylla, 200
Ruby
w OS X, 306
w Ubuntu, 307
w Windows, 305
RVM, 306
Selenium Grid, 252
instrukcja
@import, 210
@include, 210
Given, 255
return false, 69
switch, 73
interaktywne
animacje, 189
prototypy, 191
interfejs
do zarzdzania
produktami, 108, 109
Highcharts, 130
koszyka, 96
uytkownika, 47
interfejsy interaktywne, 95
interpreter
CoffeeScriptu, 218
Ruby, 200, 305
RubyGems, 305
iteracja po tablicy, 83
J
Java Runtime Environment,
14
jzyk
CoffeeScript, 216, 221
HTML 4.01, 50
Makrdown, 202
Ruby, 14, 305
Sass, 208
jzyki
szablonowe, 109
znacznikowe, 202
jQuery, 13
jQuery Theme, 39
jQuery UI, 39
JSONP, JSON with
Padding, 144
K
karty, 59
kaskadowe arkusze stylów,
22
katalog
public, 134
sample_data, 135
klasa
button, 18
Cart, 101
Kup książkę
Poleć książkę
314
Web development. Receptury nowej generacji
klasa
collapsed, 68
collapsible, 70
container, 193
delete, 120
disabled, 21
draggable, 175
entry, 72
examples, 60
expanded, 66
four columns, 199
help_link, 43
Highcharts, 134
LineItem, 98
loaded, 31
omega, 196
popup, 174
row, 196
scale-with-grid, 195
selected, 62
sheen, 30
View, 112
klauzula
Given, 253
Then, 253
klient SFTP, 278
kliknicie licia, 68
klucz
API, 250
niewymagajcy hasa,
286
SSH, 229
kod
formularza, 142
paginacji, 85
ródowy receptur, 15
kody klawiszy, 73
kolekcja produktów, 113
kolekcje, 111
kolumny, 195
komunikaty
o stanie serwerów, 159
o bdach, 160
konfiguracja
Apache, 277
ClickHeat, 240
Jasmine, 263
serwera WWW, 279
rodowiska testowego, 243
konkatenacja acuchów, 80
konstruktory obiektów, 98
konto
Cloudant, 153
Litmus, 48, 56
Sauce Labs, 248, 250
konwersja CoffeeScriptu, 220
L
liczba wpisów, 75
lista
nieuporzdkowana, 61,
202
pena, 67
produktów, 108, 164, 189
w iPhonie, 166
wpisów, 203
zaadowanych moduów,
293
ze zwinitymi gaziami,
67
zagniedona, 65
lokalizacja, 125
LTS, Long-term Support,
276
adowanie treci, 44
acuch sauce, 252
acuchy, 221
cze
Ajax, 90
do pliku, 34
Manage products, 245
czenie plików graficznych,
187
M
mapa
ciepa, 239–242
Google, 123
interaktywna, 124
maszyna wirtualna, 15, 229,
275, 278
mechanizm
przepisywania, 293
uwierzytelniania, 288
wdraania, 303
menu rozwijane, 168, 170
metoda
addProduct(), 120
ajax(), 107
append(), 79, 81
applyBindings(), 98
bind(), 120
click(), 258
clickAndWait(), 244
dependentObservable(),
100, 103
destroy(), 120
each(), 114
fetch(), 115
focus(), 78
getJSON(), 186
html(), 82
initialize(), 119
is_element_present(), 258
observableArray(), 101
pushState(), 95, 121
remove(), 103
render(), 113
renderProduct(), 120
save(), 119
serialize(), 70
stopPropagation(), 170
TDD, 269
to_html(), 80
type(), 258
url(), 111
Kup książkę
Poleć książkę
Skorowidz
315
minimalizacja pliku, 297
modele widoków, 96, 97
modelowanie zbiorów
danych, 133
modu mod_rewrite, 291
muteks, 88
N
nagówek
HTTP 301 Redirect,
295
strony, 194
narzdzia
do testowania, 56
do tworzenia projektów,
154
narzdzie
bundler, 250
Capistrano, 304
Ceaser, 31
ClickHeat, 240
CTH, 249
Cucumber, 305
do wysyania plików, 203
Dropbox, 274
Firebug Lite, 234
Git, 222
Git Bash, 223
Guarda, 218
Jammit, 297
MiddleMan, 221
Pathogen, 284
Placehold.it, 195
Rake, 297, 301
RVM, 306
RVM Ruby, 308
sass, 209
SassOs X, 305
Sauce Labs, 249
Selenium Grid, 247, 252
Selenium Remote
Control, 247
nawigacja
dla
urzdze
przenonych, 169
do produktów, 185
po stronie, 71
NPM, Node Package
Manager, 218
numer strony, 76
O
obiekt
Cart, 101
DOM, 69
LineItem, 97, 101
Product, 111
window, 112
obiekty kolekcji, 112
obramowanie, 27
obrazy w wiadomociach
e-mail, 57
obserwacja zdarze
dotykowych, 177
obsuga
bdów, 143
cieni, 197
CouchDB, 153
Firebuga, 235
lici, 68
cza, 118
przezroczystoci, 211
skrótów klawiszowych,
71
SSL, 285, 286
zdarze, 63, 96, 118
odwracanie gradientu, 20
okno
dialogowe, 39
draggable_window, 175
modalne, 41
powoki, 201
przegldarki, 193
Selenium IDE, 244
opcje modalnoci, 44
operator
#, 83
->, 216
organizacja certyfikacyjna
Thawte, 287
VeriSign, 287
P
paginacja, 85
parametr
page, 93
start_page, 93
pisanie widoków, 79
plik
.htaccess, 289, 291
.htpasswd, 289
_buttons.scss, 210
_config.yml, 205
_mixins.scss, 213
_speech_bubble.scss,
212
about_us.html, 226
add_todo.js, 266
add_todo_spec.js, 261
app.js, 109, 110, 219
assets.yml, 299
base.html, 201
buttons.scss, 209
contact.html, 206
contact.markdown, 206
contact.php, 138
cucumber.yml, 251
endless_pagination.js, 85
expand_collapse_sprite.
png, 187
form.coffee, 303
Guard, 302
Guardfile, 220, 299
helper-text-broken.js,
236
hosts, 251
Kup książkę
Poleć książkę
316
Web development. Receptury nowej generacji
plik
index.html, 15, 110, 179
iPhone.css, 165
layout.css, 196
map.js, 157
mixins.scss, 210
mustache.js, 219
mustachejs.js, 159
ondemand.yml, 250
page.html, 206
post.html, 204
products.html, 85, 226
Rake, 302
reduce.js, 157
rotate.js, 34
server.bat, 15
SpecRunner.html, 261,
263
style.css, 165, 204
pliki
CSS, 208
Sass, 208
wpisów, 203
Youth Technology
Days, 273
pobieranie
danych, 144, 157
zdj, 145
podmienianie istniejcego
systemu, 81
podzia na strony, 76
pokaz slajdów, 33
pole wyszukiwania, 72, 77
polecenia powoki, 14
polecenie
a git status, 224
cat, 289
chmod, 240
clickAndWait(), 245
couchapp, 157
git, 230
git stash list, 227
git status, 225
htpasswd, 289
jekyll, 207
scp, 141
potwierdzenie wysania
danych, 300
powiadomienia o bdach,
142, 246
powoka, 14
prekompilator, 208
program
Cyberduck, 278
ssh-keygen, 229
Vim, 279
VirtualBox, 275
VMware, 279
programowanie
behawioralne, 248
prototyp
jQuery.fn, 67
projektu, 191
przechowywanie
danych, 136
hase w skryptach, 303
listy produktów, 182
przechwytywanie zdarze,
73
przeciganie okienka, 172
przecianie serwera, 85
przecinek, 118
przedrostek
-moz-*, 20
-o-*, 20
-webkit-*, 20
przegldanie produktów,
182
przegldarka IE 8, 90
przegldarki do testowania,
252
przejcia, 28, 37
przekierowanie, 292
przeczanie kart, 61
przewijanie, 74
przezroczysto, 211
przycisk
Wstrzymaj, 37
Wznów, 37
przyciski bez ikon, 181
pseudoklasa hover, 31
punkt przywracania, 279
Q
QEDServer, 14, 85
R
regua
konfiguracyjna, 283
RewriteRule, 294
rejestrowanie, 244
relacyjne bazy danych, 154
renderowanie
szablonu, 80
widoku dla obiektu, 112
repozytorium Git, 224
resetowanie ustawie
elementów, 19
rodzaje certyfikatów SSL,
288
rola, 102
button, 180
controlgroup, 180
router ProductsRouter, 114
rozgazienia, 225
rozmiar
mapy, 125
okna przegldarki, 193
rozszerzenie Firebug, 234
rozwijanie wzów listy, 68
RVM, Ruby Version
Manager, 306
rysowanie wykresu, 136
S
scenariusze, scenario, 253
sekcja <head>, 54
Kup książkę
Poleć książkę
Skorowidz
317
selektor
before, 25
after, 25
serwer
Apache, 288
CouchDB, 158
Git, 228
QEDServer, 134
WEBrick, 203
serwis
Cloudant.com, 153
GitHub, 80, 207, 231,
261
HTML5 Rocks, 177
JSFiddle.net, 136
Litmus.com, 48
MailChimp, 58
MLS, 192
siatka Skeletona, 193
Skeleton, 192
skadnia CoffeeScriptu, 216
skadniki Backbone, 107
skróty klawiszowe, 72, 78
skrypt paginacji, 91
SNI, Server Name
Indication, 288
sprite’y w CSS, 187
statyczne strony, 296
stopniowe ulepszanie, 70
strona
bdu, 282
bdu 404, 280
kodowa UTF-8, 90
produktów, 184
strony statyczne, 206
struktura
folderów, 262
Skeletona, 192
stuknicie odnonika, 169
styl
animacji, 46
slide, 46
stylizowanie
cytatów, 21
elementów, 18
kart, 63
okienek pomocy, 38
okna dialogowego, 42
poysku, 32
przycisków, 17
symbol =>, 303
system
Compass, 199
Git, 236
Linux Ubuntu Server,
275
Mustache, 79
Ubuntu, 276
Ubuntu 10.04 Server,
275
systemy siatkowe, 192
szablon
domylny Skeletona, 198
faktury, 50
nagówek, 51
stopka, 53
tabele, 51
tre, 52
listy, 112
strony, 34
szablony
MailChimp, 58
Mustache, 84, 219
wewntrzne, 82
szkielet
Jasmine, 261
RSpec, 261
strony, 85
testowy, 261
szpieg, 267
ledzenie
aktywnoci
uytkowników, 239
zdarze kliknicia, 169,
240
zmian w adresie URL,
115
T
tablica
$_POST, 140
$errors, 141, 142
ages, 136
elementów, 101
items, 104
photos, 146
test, 243
testowanie, 257
behawioralne, 261
biblioteki jQuery
Mobile, 182
formularza
kontaktowego, 141
kodu JavaScript, 260
przegldarek, 242
stron, 247
wiadomoci e-mail, 48,
56
testy
Cucumber, 248, 253
Jasmine, 268
transformacje, 32
transformacje CSS3, 28
trasa
#new, 117
domylna, 114
tre na kartach, 59
tryb wstawiania, 282
tryby dziaania Vim, 281
Kup książkę
Poleć książkę
318
Web development. Receptury nowej generacji
tworzenie
animacji, 28
aplikacji CouchApp,
156
atrapy danych, 264
bazy danych, 154
bloga, 200
dynamicznych stron, 201
elementów <div>, 87
faktury, 49
folderu statuses, 156
formularza HTML, 138
grafów, 130
interfejsów, 178
kart, 60
listy produktów, 111
makiety, 193
mapy, 126
maszyny wirtualnej, 275
modelu produktu, 108
modularnych arkuszy
stylów, 207
nowego produktu, 116
oprogramowania, 269
podpisanego certyfikatu,
285
pokazu slajdów, 33
profili uytkowników,
133
projektu Sass, 208
prototypów, 191
routera, 114
stron, 180
stron bdów, 282
struktury plików, 201
szablonów HTML, 79
testu, 243
testu zaawansowanego,
246
wiadomoci e-mail, 47
widoku, 157
widetów, 147
wpisów, 202
wykresów, 129
znaczników, 126
typ sieci, 276
U
udostpnianie
folderu, 272
widetu, 152
ukad strony, 193
ukady pojedynczych
wpisów, 204
ukrywanie kart, 61
urzdzenia przenone, 163
usuga
Campaign Monitor, 54
chmurowa, 249
Dropbox, 272, 274
MailChimp, 54
Sauce Labs, 251
Sauce Labs
OnDemand, 250
testowania Selenium,
249
ustawienie typu sieci, 276
usuwanie
cieni, 197
produktów, 103, 120
wirujcego kóka, 89
uwierzytelnianie HTTP,
289, 290
W
wczytywanie mapy, 125
wzy licie, 68
wiadomoci e-mail, 47–49
wiadomo wieloczciowa,
54
wizania przepywu
sterowania, 100
wizanie
obiektów, 100
zdarzenia i funkcji, 103
widok
ListView, 119
ProductView, 112
widoki
Backbone, 106, 112
CouchDB, 157
widety, 147
wielokrotne
wczytywanie treci, 44
wykorzystanie kodu, 210
wirtualny serwer, 277
wirujce kóko, 89
wasnoci, feature, 253
wasno
border-radius, 27
box-shadow, 213
content, 27
linear-gradient, 27
notes, 83
plotOptions, 133
quantity, 99
series, 131
shiftKey, 78
transition, 30
z-index, 25
wspórzdne
geograficzne, 126
pooenia obrazu, 188
wspóuytkowanie folderu,
273
wstawianie mapy Google, 123
wtyczka
CouchDB, 159
Cycle, 33
guard-coffeescript, 220
Jasmine-jQuery, 261
wykres, 129
wykres koowy, 132
wyskakujce okienko, 174
Kup książkę
Poleć książkę
Skorowidz
319
wysyanie
gazi, 230
plików, 277
wiadomoci e-mail, 139
wywietlanie
danych klientów, 135
informacji, 128
listy produktów, 116
testów, 256
treci, 58
wiadomoci, 158
Z
zabezpieczanie
serwera Apache, 284
treci, 288
zachowanie czy, 292
zagniedanie
konstrukcji, 198
regu, 212
selektorów, 212
zapytania o media CSS,
164, 167, 196
zarzdzanie plikami, 222
zalepka, stub, 267
zdalny serwer, 144
Git, 228
zdarzenia
dotykowe, 175
onchange, 121
w widoku, 118
zdarzenie
add, 119
click(), 266
hover, 169
kliknicia, 69
mousemove, 175
mouseup, 175
submit, 70, 185
tap, 185
touchend, 172
touchmove, 177
touchstart, 172, 176
zdjcia, 145
zmienianie adresu URL,
91, 114
zmienna
chartOptions, 131
current_entry, 74
currentPage, 93
data, 80
el, 117
nextPage, 88
page_number, 77
rendered, 80
tabTitle, 62
template, 113
todo, 265
treshold, 90
zmienne globalne, 87
znaczniki szablonowe, 201
znak
\, 259
#, 92, 114
$, 67, 209
?, 77, 94
znaki ==, 238
zwijanie, 66
zwijanie wzów listy, 68
danie
DELETE, 108
GET, 82, 108
getJSON(), 183
POST, 70, 108
PUT, 108
Kup książkę
Poleć książkę
320
Web development. Receptury nowej generacji
Kup książkę
Poleć książkę