Tytuá oryginaáu: JavaScript Web Applications
Táumaczenie: Daniel Kaczmarek
ISBN: 978-83-246-3887-1
© 2012 Helion S.A.
Authorized Polish translation of the English edition of JavaScript Web Applications, 1st Edition
9781449303518 © 2011 Alex MacCaw
This translation is published and sold by permission of O’Reilly Media, Inc., which owns or controls all
rights to publish and sell the same.
All rights reserved. No part of this book may be reproduced or transmitted in any form or by any
means, electronic or mechanical, including photocopying, recording or by any information storage
retrieval system, without permission from the Publisher.
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.
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/jascww.zip
Drogi Czytelniku!
JeĪeli chcesz oceniü tĊ ksiąĪkĊ, zajrzyj pod adres
http://helion.pl/user/opinie/jascww
MoĪesz tam wpisaü swoje uwagi, spostrzeĪenia, recenzjĊ.
Printed in Poland.
•
Kup książkę
•
Poleć książkę
•
Oceń książkę
•
Księgarnia internetowa
•
Lubię to! » Nasza społeczność
3
Spis tre"ci
Przedmowa ...............................................................................................................................9
1. MVC i klasy ....................................................................................................................17
Pocz tki
17
Nadawanie struktury
18
Czym jest MVC?
19
Model
19
Widok
20
Kontroler
21
Ku modularyzacji, tworzenie klas
22
Dodawanie funkcji do klas
23
Dodawanie metod do w#asnej biblioteki klas
24
Dziedziczenie klas przy u$yciu prototypu
25
Dodawanie dziedziczenia do biblioteki klas
26
Wywo#ywanie funkcji
27
Kontrola zasi%gu we w#asnej bibliotece klas
29
Dodawanie funkcji prywatnych
31
Biblioteki klas
32
2. Zdarzenia i ich nas#uchiwanie ....................................................................................35
Nas#uchiwanie zdarze&
35
Kolejno'( zdarze&
36
Anulowanie zdarze&
37
Obiekt zdarzenia Event
37
Biblioteki zdarze&
39
Zmiana kontekstu
40
Delegowanie zdarze&
40
W#asne zdarzenia
41
W#asne zdarzenia i modu#y rozszerzaj ce jQuery
41
Zdarzenia inne ni$ zdarzenia DOM
43
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ
4
Spis tre"ci
3. Modele i dane ..............................................................................................................47
MVC i przestrzenie nazw
47
Tworzenie ORM
48
Dziedziczenie przez prototypy
49
Dodawanie w#a'ciwo'ci ORM
50
Utrzymywanie rekordów
51
Dodawanie obs#ugi identyfikatorów
52
Adresowanie odwo#a&
53
)adowanie danych
54
Wplatanie danych
55
)adowanie danych przy u$yciu Ajax
55
JSONP
59
Bezpiecze&stwo $ da& mi%dzy domenami
59
Wype#nienie ORM danymi
60
Przechowywanie danych lokalnie
60
Dodanie mechanizmu przechowywania danych lokalnie do ORM
61
Przesy#anie nowych rekordów na serwer
63
4. Kontrolery i stany ........................................................................................................65
Wzorzec modu#u
66
Import zmiennych globalnych
66
Eksport zmiennych globalnych
66
Dodawanie kontekstu
67
Wydzielanie kodu do oddzielnej biblioteki
68
)adowanie kontrolerów po za#adowaniu dokumentu
69
Dost%p do widoków
70
Delegowanie zdarze&
72
Maszyny stanów
74
Routing
76
Korzystanie z hash value adresu URL
76
Wykrywanie zmian hash value
77
Ajax Crawling
77
Wykorzystanie API History HTML5
78
5. Widoki i szablony ........................................................................................................ 81
Dynamiczne generowanie widoków
81
Szablony
82
Pomocnicze funkcje obs#ugi szablonów
84
Przechowywanie szablonów
85
Wi zanie
86
Wi zanie modeli
87
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ
Spis tre"ci
5
6. Zarz$dzanie zale%no"ciami .........................................................................................89
CommonJS
90
Deklarowanie modu#u
90
Modu#y i przegl darka
91
Biblioteki #adowania modu#ów
92
Yabble
92
RequireJS
93
Opakowywanie modu#ów
94
Rozwi zania alternatywne wzgl%dem modu#ów
95
LABjs
96
FUBC
96
7. Praca z plikami ............................................................................................................. 97
Obs#uga w przegl darkach
97
Pobieranie informacji na temat plików
98
Kontrolka do przesy#ania plików na serwer
98
Przeci ganie i upuszczanie
99
Przeci ganie
100
Upuszczanie
101
Anulowanie domy'lnej obs#ugi przeci gania i upuszczania
102
Kopiowanie i wklejanie
103
Kopiowanie
103
Wklejanie
104
Czytanie plików
105
Du$e obiekty binarne oraz fragmenty pliku
106
W#asne przyciski przegl darki
107
)adowanie plików na serwer
107
*ledzenie post%pu operacji
109
Przesy#anie pliku na serwer przy u$yciu przeci gania i upuszczania
oraz biblioteki jQuery
111
Obszar upuszczania
111
Przesy#anie pliku na serwer
111
8. Praca w sieci w czasie rzeczywistym .........................................................................113
Historia dzia#ania w czasie rzeczywistym
113
WebSockets
114
Node.js i Socket.IO
118
Architektura czasu rzeczywistego
119
Odczuwana pr%dko'( dzia#ania
121
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ
6
Spis tre"ci
9. Testowanie i usuwanie b#&dów ................................................................................ 123
Testy jednostkowe
125
Asercje
125
QUnit
126
Jasmine
129
Sterowniki
131
Testowanie niezale$ne
134
Zombie
134
Ichabod
136
Testowanie rozproszone
137
*wiadczenie wsparcia
137
Inspektory
138
Web Inspector
138
Firebug
140
Konsola
141
Funkcje pomocnicze konsoli
142
U$ywanie debuggera
143
Analiza $ da& sieciowych
144
Profilowanie i analiza czasu
145
10. Wdra%anie .................................................................................................................. 149
Wydajno'(
149
Wykorzystanie pami%ci podr%cznej
150
Minifikacja
152
Kompresja Gzip
153
Korzystanie z CDN
154
Audytory
155
Zasoby
156
11. Biblioteka Spine ..........................................................................................................157
Instalacja
157
Klasy
158
Tworzenie instancji
158
Rozszerzanie klas
159
Kontekst
160
Zdarzenia
161
Modele
161
Pobieranie rekordów
163
Zdarzenia modelu
163
Weryfikacja poprawno'ci
164
Zapisywanie
164
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ
Spis tre"ci
7
Kontrolery
166
Wskazywanie kontekstu
167
W#a'ciwo'( elements
167
Delegowanie zdarze&
168
Zdarzenia kontrolera
168
Zdarzenia globalne
169
Wzorzec Render
170
Wzorzec Element
170
Aplikacja do zarz dzania danymi kontaktowymi
171
Model Contact
173
Kontroler Sidebar
173
Kontroler Contacts
175
Kontroler App
178
12. Biblioteka Backbone .................................................................................................. 179
Modele
180
Modele i atrybuty
180
Kolekcje
181
Kontrola kolejno'ci elementów w kolekcji
183
Widoki
183
Generowanie widoków
184
Delegowanie zdarze&
184
Wi zanie i kontekst
185
Kontrolery
186
Synchronizacja z serwerem
188
Wype#nianie kolekcji
189
Po stronie serwera
189
Implementacja w#asnej logiki
190
Aplikacja do zarz dzania list rzeczy do zrobienia
192
13. Biblioteka JavaScriptMVC ......................................................................................... 199
Konfiguracja
200
Klasy
200
Tworzenie instancji
200
Wywo#ywanie metody bazowej
201
Okre'lanie kontekstu
201
Dziedziczenie statyczne
201
Introspekcja
202
Przyk#adowy model
202
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ
8
Spis tre"ci
Model
203
Atrybuty i dane obserwowalne
203
Rozszerzanie modeli
205
Metody ustawiaj ce warto'ci
205
Warto'ci domy'lne
206
Metody pomocnicze
206
Enkapsulacja us#ug
207
Przekszta#canie typów
209
Zdarzenia CRUD
210
Wykorzystanie w widokach szablonów dzia#aj cych po stronie klienta
210
Sposób u$ycia
211
Modyfikatory jQuery
211
)adowanie widoku ze znacznika skryptu
212
$.View i subszablony
212
Obiekty wstrzymane
212
Pakowanie, #adowanie wst%pne i wydajno'(
213
$.Controller: fabryka modu#ów rozszerzaj cych jQuery
213
Informacje ogólne
215
Tworzenie instancji kontrolera
216
Wi zanie zdarze&
216
Akcje szablonowe
217
Kompletne rozwi zanie: abstrakcyjna lista czynno'ci CRUD
218
A. Wprowadzenie do biblioteki jQuery ........................................................................ 221
B. Rozszerzenia CSS ....................................................................................................... 231
C. Przegl$d CSS3 ............................................................................................................235
Skorowidz .............................................................................................................................255
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ
47
ROZDZIA* 3.
Modele i dane
Gdy aplikacja ma utrzymywa( stan na kliencie, jednym z wyzwa& stoj cym przed programi-
st jest zapewnienie odpowiedniego zarz dzania danymi. Standardowo w momencie wy-
wo#ania strony dane pobiera si% bezpo'rednio z bazy danych, a wynik ich przetwarzania
umieszcza si% bezpo'rednio na stronie. Jednak w stanowych aplikacjach JavaScript proces za-
rz dzania danymi przebiega zupe#nie inaczej. Nie obowi zuje w nich model wywo#anie-
odpowied/, nie s tak$e dost%pne zmienne na serwerze. Dane s za to pobierane zdalnie i tym-
czasowo przechowywane po stronie klienta.
Wprawdzie zaimplementowanie odpowiedniego mechanizmu mo$e by( do'( trudnym za-
daniem, jednak uzyska si% dzi%ki temu co najmniej kilka korzy'ci. Na przyk#ad dost%p do da-
nych znajduj cych si% po stronie klienta jest praktycznie natychmiastowy, tak jakby dane po-
bierane by#y z pami%ci. Mo$e to zdecydowanie poprawi( dzia#anie interfejsu aplikacji, poniewa$
ka$da czynno'( u$ytkownika skutkuje natychmiastowym zwróceniem wyniku. Dzi%ki temu
aplikacja znajduje zdecydowanie wi%ksze uznanie u u$ytkowników.
Aby odpowiednio skonstruowa( mechanizm przechowywania danych po stronie klienta,
trzeba najpierw szczegó#owo przeanalizowa( wszystkie okoliczno'ci. Zadanie naje$one jest
ró$norodnymi przeszkodami i pu#apkami, w które wpadaj zw#aszcza pocz tkuj cy progra-
mi'ci — szczególnie gdy ich aplikacje coraz bardziej si% rozrastaj . W tym rozdziale zoba-
czymy, jak w najbardziej efektywny sposób zaimplementowa( przechowywanie danych po
stronie klienta. Wskazane zostan tak$e najbardziej zalecane wzorce i praktyki.
MVC i przestrzenie nazw
Aby opracowa( tak architektur% aplikacji, która b%dzie przejrzysta i #atwa w utrzymaniu,
trzeba przede wszystkim zapewni( pe#n separacj% widoków aplikacji, jej stanu i danych.
W przypadku wykorzystania wzorca MVC zarz dzanie danymi odbywa si% w modelu („M”
w nazwie MVC). Modele powinny by( roz# czne wzgl%dem widoków i kontrolerów. Natomiast
logika wyznaczaj ca sposób manipulowania danymi oraz odpowiedzialna za zachowanie
aplikacji powinna by( osadzona w modelu oraz oznaczona odpowiedni przestrzeni nazw.
W JavaScripcie odpowiedni przestrze& nazw dla funkcji i zmiennych mo$na zapewni( przez
uczynienie ich w#a'ciwo'ciami obiektu. Na przyk#ad:
var User = {
records: [ /* ... */ ]
};
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ
48
Rozdzia# 3. Modele i dane
Tablica u$ytkowników ma teraz odpowiedni przestrze& nazw
User.records
. Funkcje zwi za-
ne z obs#ug u$ytkowników równie$ mog nale$e( do przestrzeni nazw wyznaczanej przez
model
User
. Mo$na na przyk#ad zaimplementowa( funkcj%
fetchRemote()
, która b%dzie pobiera(
z serwera dane u$ytkownika:
var User = {
records: [],
fetchRemote: function(){ /* ... */ }
};
Umieszczenie wszystkich w#a'ciwo'ci modelu w przestrzeni nazw zapewni, $e nie wyst pi
$adne konflikty, a jednocze'nie utrzymana zostanie zgodno'( z paradygmatem MVC. Poza
tym zmniejszy si% zagro$enie, $e tworzony kod /ród#owy zamieni si% z biegiem czasu w nie-
zrozumia# spiral% funkcji i wywo#a& zwrotnych.
Zakres wykorzystania przestrzeni nazw mo$na jeszcze pog#%bi( i umie'ci( wszystkie funkcje
operuj ce na instancjach u$ytkowników w rzeczywistych obiektach u$ytkowników. Przyjmij-
my, $e na rekordzie u$ytkownika zaimplementowana jest funkcja
destroy()
. Odnosi si% ona
do konkretnego u$ytkownika, zatem powinna by( wywo#ywana na instancji obiektu
User
:
var user = new User;
user.destroy()
Aby osi gn ( zamierzony efekt, nale$y uczyni( z
User
klas%, a nie zwyk#y obiekt:
var User = function(atts){
this.attributes = atts || {};
};
User.prototype.destroy = function(){
/* ... */
};
Natomiast wszelkie funkcje i w#a'ciwo'ci, które nie dotycz konkretnego u$ytkownika, mog
by( w#a'ciwo'ciami bezpo'rednio obiektu
User
:
User.fetchRemote = function(){
/* ... */
};
Wi%cej ciekawych informacji na temat przestrzeni nazw mo$na znale/( na blogu Petera
Michaux, który opublikowa# bardzo ciekawy artyku# na ten w#a'nie temat (http://michaux.ca/
articles/javascript-namespacing
).
Tworzenie ORM
Biblioteki odwzorowa& obiektowo-relacyjnych, czyli ORM, s zwykle wykorzystywane w j%-
zykach programowania innych ni$ JavaScript. Stanowi one jednak bardzo przydatne narz%-
dzia do zarz dzania danymi, a tak$e znacznie u#atwiaj u$ycie modeli w aplikacji JavaScript.
Za pomoc ORM mo$na na przyk#ad powi za( model ze zdalnym serwerem — w wyniku
takiego powi zania wszelkie zmiany w instancjach modelu b%d wysy#ane w tle do serwera
w ramach wywo#a& Ajax. Mo$na tak$e powi za( instancj% modelu z elementem HTML, dzi%ki
czemu wszelkie zmiany w instancji modelu spowoduj odpowiedni zmian% w widoku.
Przyk#ady te zostan rozwini%te nieco pó/niej, a na razie zobaczmy, jak tworzy si% ORM.
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ
Tworzenie ORM
49
Zasadniczo ORM jest po prostu warstw obiektów opakowuj c jakie' dane. Standardowo
ORM stanowi warstw% abstrakcji dla baz danych SQL, jednak w naszym przypadku ORM
b%dzie po prostu warstw abstrakcji dla typów danych JavaScriptu. Zalet takiej dodatkowej
warstwy jest to, $e podstawowy zbiór danych mo$na rozszerzy( o dodatkowe rozwi zania
przez dodanie w#asnych funkcji i w#a'ciwo'ci. Dzi%ki temu mo$na dodawa( mechanizmy wery-
fikacji poprawno'ci albo utrzymywania danych, obserwatory czy wywo#ania zwrotne do ser-
wera, a jednocze'nie nadal mie( mo$liwo'( wielokrotnego wykorzystywania kodu /ród#owego.
Dziedziczenie przez prototypy
Do stworzenia naszej w#asnej biblioteki ORM wykorzystamy
Object.create()
, co jest podej-
'ciem nieco odmiennym od przyk#adów opisywanych w rozdziale 1, w których korzystali-
'my z klas. Nowe podej'cie pozwoli nam jednak na skorzystanie z dziedziczenia przez pro-
totypy zamiast u$ywania funkcji konstruktorów i s#owa kluczowego
new
.
Funkcja
Object.create()
przyjmuje jeden argument — obiekt prototypu — i zwraca nowy
obiekt z przekazanym obiektem prototypu. Inaczej mówi c, przekazuje si% do niej obiekt,
a funkcja zwraca nowy obiekt, potomny po obiekcie przekazanym.
Funkcja
Object.create()
zosta#a dopiero niedawno dodana do specyfikacji ECMAScript, 5th
Edition i dlatego jeszcze nie wszystkie przegl darki j obs#uguj — nale$y do nich mi%dzy
innymi IE. Nie jest to jednak wielki problem, poniewa$ w razie potrzeby obs#ug% tej funkcji
mo$na zaimplementowa( samemu:
if (typeof Object.create !== "function")
Object.create = function(o) {
function F() {}
F.prototype = o;
return new F();
};
Powy$szy przyk#ad pochodzi z artyku#u Douglasa Crockforda na temat dziedziczenia przez
prototypy (http://javascript.crockford.com/prototypal.html). Warto si% z nim zapozna(, aby lepiej
pozna( mechanizmy rz dz ce prototypami i dziedziczeniem w j%zyku JavaScript.
Utworzymy teraz obiekt
Model
, którego zadaniem b%dzie tworzenie nowych modeli i instancji:
var Model = {
inherited: function(){},
created: function(){},
prototype: {
init: function(){}
},
create: function(){
var object = Object.create(this);
object.parent = this;
object.prototype = object.fn = Object.create(this.prototype);
object.created();
this.inherited(object);
return object;
},
init: function(){
var instance = Object.create(this.prototype);
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ
50
Rozdzia# 3. Modele i dane
instance.parent = this;
instance.init.apply(instance, arguments);
return instance;
}
};
Programistów, którzy nie poznali dotychczas funkcji
Object.create()
, definicja
Model
mo$e
nieco zniech%ca(, wi%c roz#o$ymy j na czynniki pierwsze. Funkcja
create()
zwraca nowy
obiekt, który dziedziczy po obiekcie
Model
. W ten sposób tworzone b%d nowe modele. Funkcja
init()
zwraca natomiast nowy obiekt, który dziedziczy po
Model.prototype
— czyli instancj%
obiektu
Model
:
var Asset = Model.create();
var User = Model.create();
var user = User.init();
Dodawanie w#a"ciwo"ci ORM
Je'li teraz do
Model
dodamy w#a'ciwo'ci, stan si% one dost%pne we wszystkich modelach
potomnych:
// Dodanie w%a&ciwo&ci obiektu
jQuery.extend(Model, {
find: function(){}
});
// Dodanie w%a&ciwo&ci instancji
jQuery.extend(Model.prototype, {
init: function(atts) {
if (atts) this.load(atts);
},
load: function(attributes){
for(var name in attributes)
this[name] = attributes[name];
}
});
Metoda
jQuery.extend()
odpowiada wykonaniu p%tli
for
i wykonaniu w niej r%cznego kopio-
wania w#a'ciwo'ci. Tak w#a'nie post%pujemy w funkcji
load()
. Teraz w#a'ciwo'ci obiektu
i instancji s propagowane w dó#, do konkretnych modeli:
assertEqual( typeof Asset.find, "function" );
W praktyce liczba dodawanych w#a'ciwo'ci b%dzie do'( znaczna, dlatego najlepiej jest od razu
zawrze( w obiekcie
Model
funkcje
extend()
i
include()
:
var Model = {
/* ... ci*cie ... */
extend: function(o){
var extended = o.extended;
jQuery.extend(this, o);
if (extended) extended(this);
},
include: function(o){
var included = o.included;
jQuery.extend(this.prototype, o);
if (included) included(this);
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ
Tworzenie ORM
51
}
};
// Dodanie w%a&ciwo&ci obiektu
Model.extend({
find: function(){}
});
// Dodanie w%a&ciwo&ci instancji
Model.include({
init: function(atts) { /* ... */ },
load: function(attributes){ /* ... */ }
});
Mo$na ju$ zatem tworzy( nowe zasoby i ustawia( ich atrybuty:
var asset = Asset.init({name: "foo.png"});
Utrzymywanie rekordów
Potrzebny jest równie$ mechanizm utrzymywania rekordów, to znaczy zapami%tywania od-
wo#a& do utworzonych instancji, aby móc z nich korzysta( w pó/niejszym czasie. Do tego
celu wykorzystany zostanie obiekt
records
ustawiony w modelu
Model
. Obiekt b%dzie dodawany
do modelu w momencie zapisywania instancji modelu i usuwany z obiektu modelu, gdy usu-
wana b%dzie instancja modelu:
// Obiekt z zapisanymi zasobami
Model.records = {};
Model.include({
newRecord: true,
create: function(){
this.newRecord = false;
this.parent.records[this.id] = this;
},
destroy: function(){
delete this.parent.records[this.id];
}
});
A w jaki sposób mo$na zmienia( istniej c instancj%? To proste — wystarczy zmieni( odwo-
#anie do obiektu:
Model.include({
update: function(){
this.parent.records[this.id] = this;
}
});
Warto tak$e zaimplementowa( wygodn funkcj% odpowiedzialn za zapisywanie instancji,
tak by nie trzeba by#o pó/niej sprawdza(, czy instancja zosta#a zapisana ju$ wcze'niej albo
czy trzeba t% instancj% utworzy(:
// Zapisanie obiektu do records i zapami*tanie odwo%ania do obiektu
Model.include({
save: function(){
this.newRecord ? this.create() : this.update();
}
});
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ
52
Rozdzia# 3. Modele i dane
Wreszcie dobrze te$ zaimplementowa( funkcj%
find()
, która b%dzie wyszukiwa( zasoby o wska-
zanym identyfikatorze:
Model.extend({
// Znalezienie zasobu o danym ID lub rzucenie wyj1tku
find: function(id){
return this.records[id] || throw("Rekord nieznany");
}
});
ORM w najprostszej postaci jest ju$ gotowy, mo$na go zatem wykorzysta( w praktyce:
var asset = Asset.init();
asset.name = "taki sam, taki sam";
asset.id = 1
asset.save();
var asset2 = Asset.init();
asset2.name = "ale inny";
asset2.id = 2;
asset2.save();
assertEqual( Asset.find(1).name, "taki sam, taki sam" );
asset2.destroy();
Dodawanie obs#ugi identyfikatorów
Obecnie za ka$dym razem, gdy zapisywany jest rekord, trzeba r%cznie zdefiniowa( jego
identyfikator ID. To przykry obowi zek, ale na szcz%'cie mo$na to zadanie zautomatyzowa(.
Najpierw potrzebny jest jaki' mechanizm generowania identyfikatorów — mo$e nim by( ge-
nerator identyfikatorów GUID (ang. Globally Unique Identifier). Z technicznego punktu wi-
dzenia JavaScript nie mo$e generowa( pe#noprawnych, 128-bitowych identyfikatorów GUID
z powodu ogranicze& API, które potrafi generowa( tylko liczby pseudolosowe. Generowanie
prawdziwie losowych identyfikatorów jest zawsze trudnym zadaniem i systemy operacyjne
obliczaj je na podstawie adresu MAC, pozycji myszy, sum kontrolnych BIOS-u, a nawet na
podstawie pomiarów szumu elektrycznego albo produktów rozpadu radioaktywnego; cza-
sami wr%cz u$ywa si% lamp z zawarto'ci cieczy oraz wosku, które po rozgrzaniu tworz
ró$ne efekty kolorystyczne! Jednak natywna funkcja
Math.random()
, cho( pseudolosowa, w zu-
pe#no'ci nam wystarczy.
Robert Kieffer napisa# prosty i zwi%z#y generator identyfikatorów GUID, który za pomoc funkcji
Math.random()
generuje GUID pseudolosowe (http://www.broofa.com/2008/09/javascript-uuid-function/).
Generator jest na tyle prosty, $e mo$emy jego kod /ród#owy zaprezentowa( w ca#o'ci:
Math.guid = function(){
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
return v.toString(16);
}).toUpperCase();
};
Mamy wi%c funkcj%, która generuje identyfikatory GUID, zatem zintegrowanie jej z ORM nie
nastr%czy ju$ trudno'ci. Wystarczy w tym celu zmieni( kod funkcji
create()
:
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ
Adresowanie odwo#a-
53
Model.extend({
create: function(){
if ( !this.id ) this.id = Math.guid();
this.newRecord = false;
this.parent.records[this.id] = this;
}
});
Od teraz ka$dy nowo utworzony rekord b%dzie mia# identyfikator w postaci losowego GUID:
ar asset = Asset.init();
asset.save();
asset.id //=> "54E52592-313E-4F8B-869B-58D61F00DC74"
Adresowanie odwo#a-
Uwa$ni Czytelnicy zapewne zwrócili uwag% na b# d zwi zany z odwo#aniami w naszej bi-
bliotece ORM. Nie klonujemy instancji ani wtedy, gdy zostaj zwrócone przez
find()
, ani
w momencie ich zapisywania, przez co je'li zmienimy któr ' z ich w#a'ciwo'ci, zmiana
dotknie oryginalnego zasobu. Jest to powa$ny problem, poniewa$ oczekujemy, $e zasoby
b%d si% zmienia( jedynie po wykonaniu funkcji
update()
:
var asset = new Asset({name: "foo"});
asset.save();
// Asercja przekazuje prawid%owo
assertEqual( Asset.find(asset.id).name, "foo" );
// Zmiana w%a&ciwo&ci bez wywo%ywanai update()
asset.name = "wem";
// O nie! Asercja koHczy si* niepowodzeniem, poniewaJ nazw1 jest teraz "wem"
assertEqual( Asset.find(asset.id).name, "foo" );
Aby wyeliminowa( b# d, w trakcie dzia#ania
find()
utworzymy nowy obiekt. Ponadto konieczne
b%dzie zduplikowanie obiektu zawsze wtedy, gdy dojdzie do utworzenia lub zmiany rekordu:
Asset.extend({
find: function(id){
var record = this.records[id];
if ( !record ) throw("Rekord nieznany");
return record.dup();
}
});
Asset.include({
create: function(){
this.newRecord = false;
this.parent.records[this.id] = this.dup();
},
update: function(){
this.parent.records[this.id] = this.dup();
},
dup: function(){
return jQuery.extend(true, {}, this);
}
});
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ
54
Rozdzia# 3. Modele i dane
Jest jeszcze jeden problem —
Model.records
to obiekt, który jest wspó#u$ytkowany przez
wszystkie modele:
assertEqual( Asset.records, Person.records );
Daje to niepo$ dany efekt wymieszania ze sob wszystkich rekordów:
var asset = Asset.init();
asset.save();
assert( asset in Person.records );
Rozwi zanie polega na tym, by za ka$dym razem, gdy tworzony jest nowy model, ustawia(
te$ nowy obiekt
records
.
Model.created()
jest wywo#aniem zwrotnym do tworzenia nowego
obiektu, dlatego mo$na w nim ustawia( dowolne obiekty dotycz ce tego w#a'nie modelu:
Model.extend({
created: function(){
this.records = {};
}
});
*adowanie danych
Je'li aplikacja internetowa dzia#a w jakiej' cz%'ci poza przegl dark , konieczne jest umo$li-
wienie #adowania danych zdalnie z serwera. Zazwyczaj w trakcie uruchamiania aplikacji #a-
dowany jest jaki' podzbiór danych, a po wykonaniu okre'lonych czynno'ci przez u$ytkow-
nika aplikacja #aduje kolejne potrzebne dane. Zale$nie od rodzaju aplikacji i ilo'ci danych
komplet danych mo$na pozyskiwa( od razu w momencie pierwszego #adowania strony. Jest
to przypadek idealny, poniewa$ wówczas u$ytkownicy nie b%d ju$ musieli czeka( na za#a-
dowanie dodatkowych danych. Jednak w przypadku wi%kszo'ci aplikacji rozwi zanie takie
nie wchodzi w gr%, poniewa$ zbiór potrzebnych danych jest zbyt du$y, by bez problemu
zmie'ci# si% w pami%ci dost%pnej dla przegl darki.
Tylko dzi%ki za#adowaniu danych od razu przy starcie aplikacji b%dzie mo$na zapewni(
u$ytkownikom komfort pracy z ni , a czas odpowiedzi zredukowa( do minimum. Istnieje
jednak istotna ró$nica mi%dzy pocz tkowym #adowaniem danych, które rzeczywi'cie s po-
tem wykorzystywane, a #adowaniem danych nadmiarowych, które nigdy nie zostan u$yte.
Trzeba zatem przewidzie(, których danych u$ytkownicy b%d potrzebowa(, albo dokona(
odpowiednich pomiarów ju$ w trakcie pracy aplikacji.
Na przyk#ad je'li #adowana jest lista stronicowana, to dlaczego nie za#adowa( od razu za-
warto'ci nast%pnej strony, aby prze# czanie mi%dzy stronami nast%powa#o od razu? Albo,
co da#oby jeszcze lepszy efekt, po prostu wy'wietli( d#ug list% i automatycznie #adowa(
i wstawia( do niej dane, gdy u$ytkownik b%dzie t% list% przewija# (s#u$y do tego wzorzec nie-
sko&czonego suwaka). Im mniejsze b%dzie opó/nienie widoczne dla u$ytkownika, tym lepiej.
Nale$y zapewni(, $e w trakcie pobierania nowych danych interfejs u$ytkownika nie b%dzie
si% blokowa#. Warto wy'wietli( jaki' wska/nik post%pu #adowania danych, ale ca#o'( interfej-
su powinna przez ca#y czas by( dost%pna dla u$ytkownika. Liczba sytuacji, w której b%dzie
dochodzi#o do zablokowania interfejsu, powinna by( jak najmniejsza, a najlepiej, by w ogóle
do tego nie dochodzi#o.
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ
*adowanie danych
55
Dane mo$na wplata( w definicj% strony b d/ pobiera( je w oddzielnych $ daniach HTTP za
pomoc Ajax lub JSONP. Polecam raczej to drugie rozwi zanie, poniewa$ wplatanie w kod
strony du$ych ilo'ci danych powoduje znaczne zwi%kszenie rozmiaru strony, natomiast
dzi%ki pobieraniu danych równolegle z #adowaniem strony skraca si% ca#kowity czas jej #a-
dowania. Technologie AJAX i JSONP pozwalaj dodatkowo umieszcza( strony HTML w pa-
mi%ci podr%cznej, dzi%ki czemu nie trzeba ich #adowa( na nowo przy ka$dym kolejnym
wywo#aniu.
Wplatanie danych
Nie polecam stosowania tego podej'cia z powodów opisanych w poprzednim akapicie, jed-
nak technika wplatania danych mo$e by( w niektórych okoliczno'ciach przydatna, zw#aszcza
gdy #adowane s niewielkie zbiory danych. Technika wplatania danych ma t% niezaprzeczaln
zalet%, $e bardzo prosto si% j implementuje.
Wystarczy w tym celu generowa( obiekt JSON bezpo'rednio w kodzie strony. W technologii
Ruby on Rails odpowiednie rozwi zanie mia#oby tak posta(:
<script type="text/javascript">
var User = {};
User.records = <%= raw @users.to_json %>;
</script>
W przedstawionym kodzie wykorzystano znaczniki ERB, aby zwróci( przetworzone przez
JSON dane u$ytkownika. Metoda
raw
zapobiega wstawianiu znaków ucieczki przez JSON.
W wyniku przetworzenia strony jej kod HTML b%dzie wygl da# tak:
<script type="text/javascript">
var User = {};
User.records = [{"first_name": "Alex"}];
</script>
JavaScript mo$e przetwarza( dane JSON bez ich dodatkowego przekszta#cania, poniewa$
JSON ma tak sam struktur% jak obiekty j%zyka JavaScript.
*adowanie danych przy u%yciu Ajax
)adowanie danych przy u$yciu Ajax to chyba pierwsza metoda #adowania zdalnych danych,
która przychodzi na my'l programistom, gdy mowa o wywo#aniach w tle. To nie przypadek:
technologia ta zosta#a wypróbowana, przetestowana i udost%pniona we wszystkich wspó#-
czesnych przegl darkach. Ajax nie jest oczywi'cie pozbawiony wad — historia rozwoju tej
technologii, dla której nie istnia#y $adne standardy, zako&czy#a si% powstaniem niespójnych API.
Przez to w#a'nie, oraz ze wzgl%du na wymogi bezpiecze&stwa przegl darek internetowych,
#adowanie danych z innych domen jest zadaniem do'( skomplikowanym.
Programistom, którzy potrzebuj krótkiego wprowadzenia do technologii Ajax i klasy
XMLHttpRequest
,
warto poleci( artyku# Getting Started w witrynie Mozilla Developer (https://developer.mozilla.org/
en/Ajax/Getting_Started
). Z du$ym prawdopodobie&stwem mo$na za#o$y(, $e i tak wi%kszo'(
programistów ostatecznie wykorzysta bibliotek%, na przyk#ad jQuery, która b%dzie udost%pnia(
warstw% abstrakcji nad API Ajax i ukrywa( przed programist ró$nice w obs#udze technologii
mi%dzy poszczególnymi przegl darkami. Dlatego w tym punkcie b%dzie mowa o API biblioteki
jQuery, a nie o samej klasie
XMLHttpRequest
.
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ
56
Rozdzia# 3. Modele i dane
API Ajax biblioteki jQuery zawiera jedn funkcj% niskiego poziomu o nazwie
jQuery.ajax()
oraz kilka jej abstrakcji wy$szego poziomu, dzi%ki którym znacznie zmniejsza si% ilo'( wy-
maganego do napisania kodu /ród#owego. Funkcja
jQuery.ajax()
przyjmuje mi%dzy innymi
zbiór ustawie& parametrów wywo#ania, typ zawarto'ci oraz odwo#ania zwrotne. W momencie
wywo#ania funkcji $ danie jest asynchronicznie wykonywane w tle.
url
Adres URL $ dania. Domy'lnym adresem URL jest adres bie$ cej strony.
success
Funkcja, która ma zosta( wywo#ana, gdy $ danie zako&czy si% powodzeniem. Wszystkie
dane zwrócone przez serwer s przekazywane do funkcji jako jej parametr.
contentType
Ustawia nag#ówek
Content-Type
$ dania. Je$eli $ danie zawiera dane, domy'lnym typem
zawarto'ci jest
application/x-www-form-urlencoded
, które sprawdza si% w wi%kszo'ci przy-
padków.
data
Dane, które nale$y przes#a( do serwera. Je$eli nie jest to ci g znaków, jQuery je zseriali-
zuje i zakoduje.
type
Metoda HTTP, której nale$y u$y( do wykonania $ dania:
GET
,
POST
lub
DELETE
. Metod
domy'ln jest
GET
.
dataType
Typ danych, jakiego oczekuje si% od serwera. Biblioteka jQuery wymaga podania typu
danych wynikowych, aby wiedzie(, w jaki sposób je przetwarza( po ich otrzymaniu. Je$eli
dataType
nie zostanie okre'lony, jQuery spróbuje ten typ odgadn ( na podstawie typu
MIME odpowiedzi z serwera. Obs#ugiwane s nast%puj ce warto'ci parametru:
text
Odpowied/ tekstowa, która nie wymaga $adnego dodatkowego przetwarzania.
script
jQuery przyjmie, $e danymi wynikowymi jest kod JavaScript, i odpowiednio te dane
przetworzy.
json
jQuery przyjmie, $e danymi wynikowymi s dane JSON, i przetworzy je przy u$yciu
dok#adnego parsera.
jsonp
Oznacza format JSONP, który zostanie przedstawiony w dalszej cz%'ci ksi $ki.
Jako przyk#ad zdefiniujemy proste $ danie Ajax, które wy'wietli dane zwrócone przez serwer:
jQuery.ajax({
url: "/ajax/endpoint",
type: "GET",
success: function(data) {
alert(data);
}
});
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ
*adowanie danych
57
Jednak definiowanie wszystkich opcji jest do'( uci $liwe. Na szcz%'cie jQuery udost%pnia
kilka krótszych rozwi za&. Funkcja
jQuery.get()
pobiera adres URL, opcjonalne dane oraz
wywo#anie zwrotne:
jQuery.get("/ajax/endpoint", function(data){
$(".ajaxResult").text(data);
});
Natomiast aby wys#a( kilka parametrów w ramach $ dania
GET
, mo$na to zrobi( nast%puj co:
jQuery.get("/ajax/endpoint", {foo: "bar"}, function(data){
/* ... */
});
Je$eli spodziewamy si%, $e serwer zwróci dane JSON, trzeba u$y( funkcji
jQuery.getJSON()
,
która automatycznie ustawia opcj%
dataType
$ dania na
"json"
:
jQuery.getJSON("/json/endpoint", function(json){
/* ... */
});
Dost%pna jest analogiczna funkcja
jQuery.post()
, która równie$ przyjmuje adres URL, dane
i wywo#anie zwrotne:
jQuery.post("/users", {first_name: "Alex"}, function(result){
/* K1danie POST Ajax zakoHczy%o si* powodzeniem */
});
Aby skorzysta( z innych metod HTTP, czyli
DELETE
,
HEAD
i
OPTIONS
, trzeba u$y( niskopoziomowej
funkcji
jQuery.ajax()
.
W tym punkcie przedstawiono krótki opis API Ajax biblioteki jQuery. Wi%cej informacji na
ten temat mo$na znale/( w kompletnej dokumentacji dost%pnej na stronie pod adresem
http://api.jquery.com/category/ajax
.
Istotnym ograniczeniem Ajax jest obowi zuj ca w tej technologii zasada to$samego pocho-
dzenia
(ang. same origin policy), która ogranicza mo$liwo'( obs#ugi tylko do $ da& o tej samej
domenie, subdomenie i tym samym porcie, co adres strony, która $ danie wykonuje. Jest po
temu istotna przyczyna: otó$ zawsze, gdy wysy#ane jest $ danie Ajax, wraz z nim wysy#ane
s wszystkie dane cookie domeny. Dla serwera zdalnego jest to znak, $e $ danie pochodzi od
zalogowanego u$ytkownika. Gdyby nie obowi zywa#a zasada to$samego pochodzenia, po-
tencjalny napastnik móg#by pobra( wszystkie wiadomo'ci pocztowe innej osoby z jej skrzynki
Gmail, zmienia( statusy na czyim' profilu Facebooka albo publikowa( wiadomo'ci w czyim'
imieniu na Twitterze — jednym s#owem, by#oby to istotne zagro$enie bezpiecze&stwa.
Jednak zasada to$samego pochodzenia, która jest istotnym elementem systemu bezpiecze&-
stwa w sieci WWW, nak#ada na programistów bardzo niewygodne ograniczenia, poniewa$
odbiera im mo$liwo'( korzystania z w pe#ni bezpiecznych zasobów zdalnych. Inne technologie,
na przyk#ad Adobe Flash i Java, udost%pniaj obej'cia tego problemu w postaci plików z re-
gu#ami dost%pu do innych domen. Do tego towarzystwa do# czy# ostatnio Ajax wraz ze swoim
standardem o nazwie CORS (http://www.w3.org/TR/access-control), wyznaczaj cym zasady wspó#-
u$ytkowania zasobów mi%dzy domenami.
Dzi%ki CORS mo$na wy#ama( si% z zasady to$samego pochodzenia i uzyska( dost%p do au-
toryzowanych, zdalnych serwerów. Specyfikacja standardu CORS zosta#a zaimplementowana
w najwa$niejszych przegl darkach, dlatego je'li tylko nie jest u$ywana przegl darka IE6, nie
powinno by( z tym standardem wi%kszych problemów.
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ
58
Rozdzia# 3. Modele i dane
Zakres obs#ugi standardu CORS w poszczególnych przegl darkach opisano poni$ej:
"
IE >= 8 (z pewnymi ograniczeniami).
"
Firefox >= 3.
"
Safari: pe#na obs#uga.
"
Chrome: pe#na obs#uga.
"
Opera: brak obs#ugi.
Korzystanie z CORS nie sprawia $adnych problemów. Aby autoryzowa( dost%p do w#asnego
serwera, wystarczy do nag#ówka zwracanych odpowiedzi dodawa( te dwa wiersze:
Access-Control-Allow-Origin: przyklad.com
Access-Control-Request-Method: GET,POST
Powy$szy nag#ówek autoryzuje $ dania
GET
i
POST
do innej domeny wykonywane z domeny
przyklad.com
. Gdy warto'ci jest wi%cej ni$ jedna, nale$y oddzieli( je od siebie przecinkami,
tak samo jak w przypadku metod
GET
,
POST
powy$ej. Aby umo$liwi( dost%p z wi%cej ni$
jednej domeny, wystarczy zawrze( ich list% oddzielon od siebie przecinkami w nag#ówku
Access-Control-Allow-Origin
. Natomiast aby zezwoli( na dost%p z dowolnej domeny, nale$y
w nag#ówku
Origin
wpisa( znak gwiazdki (
*
).
Niektóre przegl darki, na przyk#ad Safari, najpierw wykonuj $ danie
OPTIONS
, aby spraw-
dzi(, czy kolejne $ danie b%dzie dozwolone. Z kolei Firefox prze'le od razu w#a'ciwe $ danie
i dopiero w przypadku braku nag#ówków CORS rzuci wyj tek. W trakcie implementowania
kodu /ród#owego trzeba wzi ( pod uwag% te ró$nice w dzia#aniu serwerów.
Standard CORS pozwala nawet na autoryzowanie $ da& z niestandardowymi nag#ówkami.
S#u$y do tego nag#ówek
Access-Control-Request-Headers
:
Access-Control-Request-Headers: Authorization
Tak skonstruowany nag#ówek oznacza, $e klienty mog dodawa( w#asne nag#ówki do $ da&
Ajax i na przyk#ad podpisywa( $ dania za pomoc OAuth:
var req = new XMLHttpRequest();
req.open("POST", "/endpoint", true);
req.setRequestHeader("Authorization", oauth_signature);
Niestety, mimo $e standard CORS jest obs#ugiwany w Internet Explorerze 8 i jego nowszych wer-
sjach, Microsoft zignorowa# specyfikacj% standardu i grup% robocz (http://lists.w3.org/Archives/
Public/public-webapps/2008AprJun/0168.html
) i utworzy# w#asny obiekt
XDomainRequest
(http://msdn.
microsoft.com/en-us/library/cc288060%28VS.85%29.aspx
), którym w przypadku $ da& mi%dzy
domenami nale$y zast pi( obiekt
XMLHttpRequest
. Obiekt
XDomainRequest
ma interfejs podobny
do interfejsu obiektu
XMLHttpRequest
, jednak zdefiniowano dla niego wiele dodatkowych ograni-
cze& i restrykcji (http://blogs.msdn.com/b/ieinternals/archive/2010/05/13/xdomainrequest-restrictions-
limitations-and-workarounds.aspx
). Na przyk#ad obiekt obs#uguje tylko metody
GET
i
POST
, nie s
obs#ugiwane nag#ówki uwierzytelniania ani nag#ówki niestandardowe, a w ko&cu — i to
jest najdziwniejsze — spo'ród typów zawarto'ci obs#ugiwany jest wy# cznie
Content-Type:
text/plain
. Zatem aby skorzysta( z CORS w IE, trzeba — oprócz u$ycia prawid#owych na-
g#ówków
Access-Control
— opracowa( odpowiednie obej'cia dla wspomnianych przed chwil
ogranicze&.
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ
*adowanie danych
59
JSONP
JSONP (http://bob.pythonmac.org/archives/2005/12/05/remote-json-jsonp), albo inaczej JSON z wy-
pe#nianiem, to technologia opracowana przed zdefiniowaniem standardu CORS. JSONP sta-
nowi kolejne narz%dzie do pobierania danych ze zdalnych serwerów. Mechanizm dzia#ania
JSONP polega na tym, $e definiowany jest znacznik skryptu, który wskazuje na ko&cówk%
JSONP. Tam w#a'nie zwracane dane s opakowywane w wywo#anie funkcji. Znaczniki skryp-
tów nie podlegaj ograniczeniom zwi zanym z komunikacj mi%dzy domenami, a poza tym
opisywana technika jest obs#ugiwana w#a'ciwie przez ka$d przegl dark%.
Poni$ej przedstawiono znacznik skryptu, który wskazuje na zdalny serwer:
<script src="http://przyklad.com/dane.json"> </script>
Ko&cówka dane.json zwraca obiekt JSON opakowany w wywo#anie funkcji:
jsonCallback({"data": "foo"})
Nast%pnie definiuje si% funkcj% dost%pn globalnie. Gdy tylko skrypt zostanie za#adowany,
nast pi wywo#anie tej funkcji:
window.jsonCallback = function(result){
// Przetwarzanie danych wynikowych
}
Jak wida(, proces jest do'( zawi#y. Na szcz%'cie jQuery udost%pnia o wiele bardziej zwi%z#e
API do niego:
jQuery.getJSON("http://przyklad.com/dane.json?callback=?", function(result){
// Przetwarzanie danych wynikowych
});
Biblioteka jQuery zast pi ostatni znak zapytania w powy$szym adresie URL losow nazw
utworzonej tymczasowej funkcji. Serwer b%dzie musia# natomiast odczytywa( parametr
callback
i u$ywa( go w roli nazwy zwracanej funkcji opakowuj cej.
Bezpiecze-stwo %$da- mi&dzy domenami
Je$eli posiadany serwer jest udost%pniany dla $ da& JSONP z ró$nych domen, trzeba do-
g#%bnie przemy'le( kwesti% jego zabezpieczenia. Zazwyczaj zasada wspó#u$ytkowania zaso-
bów mi%dzy domenami uniemo$liwia potencjalnemu napastnikowi na przyk#ad wywo#anie
API Twittera i pobranie osobistych danych innych u$ytkowników. Wszystko zmienia si% jed-
nak w przypadku zastosowania CORS i JSONP. Podobnie jak w przypadku zwyk#ego $ dania
Ajax, wszystkie cookie sesji s przekazywane w ramach $ dania, co oznacza, $e zalogowanie
do API Twittera ju$ si% dokona#o. Potencjalny napastnik b%dzie wi%c móg# przej ( pe#n
kontrol% nad kontem, a to przes dza spraw% — bezpiecze&stwo wymaga najwy$szej uwagi.
Je$eli zatem nie mo$na z góry ograniczy( zbioru domen, które b%d korzysta( z API i planuje
si% u$y( technologii CORS/JSONP, nale$y zastosowa( si% do nast%puj cych wytycznych:
"
Nie nale$y ujawnia( $adnych poufnych danych, takich jak adresy poczty elektronicznej.
"
Nie mo$na zezwala( na wywo#anie jakichkolwiek akcji (jak na przyk#ad „follow” na
Twitterze).
Aby zapewni( odpowiedni poziom bezpiecze&stwa, mo$na tak$e z góry wyznaczy( okre'lone
domeny, które b%d mog#y korzysta( z API, lub u$y( uwierzytelnienia OAuth.
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ
60
Rozdzia# 3. Modele i dane
Wype#nienie ORM danymi
Wype#nienie biblioteki ORM odpowiednimi danymi jest bardzo prostym zadaniem. Wystar-
czy pobra( dane z serwera, po czym uaktualni( rekordy modelu. Dodamy zatem funkcj%
populate()
do obiektu
Model
. Funkcja
populate()
b%dzie iterowa( przez kolejne przekazane do
niej warto'ci oraz tworzy( instancje i uaktualnia( obiekty
records
:
Model.extend({
populate: function(values){
// Reset modelu i obiektu records
this.records = {};
for (var i=0, il = values.length; i < il; i++) {
var record = this.init(values[i]);
record.newRecord = false;
this.records[record.id] = record;
}
}
});
Teraz mo$na ju$ u$y( funkcji
Model.populate()
wraz z wynikiem $ dania, które pobiera dane:
jQuery.getJSON("/assets", function(result){
Asset.populate(result);
});
W ten sposób wszystkie dane zwrócone przez serwer stan si% dost%pne w bibliotece ORM.
Przechowywanie danych lokalnie
W przesz#o'ci przechowywanie danych na lokalnym komputerze by#o ogromnym wyzwa-
niem. Jedynym dost%pnym rozwi zaniem by#o wykorzystanie plików cookie oraz modu#ów
rozszerzaj cych, takich jak Adobe Flash. Cookie maj przestarza#e API, nie mog przecho-
wywa( zbyt du$ej ilo'ci danych, a wszystkie znajduj ce si% w nich dane s przesy#ane do
serwera wraz z ka$dym $ daniem, co niepotrzebnie zwi%ksza transfer. Je'li za' chodzi o Flash,
wystarczy powiedzie(, $e najlepiej trzyma( si% z dala od wszystkich modu#ów rozszerzaj cych.
Na szcz%'cie mechanizm przechowywania danych lokalnie zawarto w specyfikacji HTML5
i jest on obs#ugiwany przez wi%kszo'( wspó#czesnych przegl darek. W odró$nieniu od cookies
dane s w tym przypadku przechowywane wy# cznie po stronie klienta i nigdy nie s prze-
sy#ane na serwery. Ilo'( danych, które mo$na w ten sposób przechowywa(, jest tak$e niepo-
równanie wi%ksza, a maksymalny dozwolony wolumen zale$y od przegl darki (oraz jej wersji,
zgodnie z list poni$ej); nigdy jednak wolumen ten nie jest mniejszy ni$ 5 MB na domen%:
"
IE >= 8.
"
Firefox >= 3.5.
"
Safari >= 4.
"
Chrome >= 4.
"
Opera >= 10.6.
Mechanizm przechowywania danych zosta# opisany w specyfikacji Web Storage HTML5
(http://www.w3.org/TR/webstorage) i sk#ada si% z dwóch elementów: przechowywania lokalnie
(ang. local storage) oraz przechowywania w sesji (ang. session storage). Dane przechowywane
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ
Dodanie mechanizmu przechowywania danych lokalnie do ORM
61
lokalnie zostaj utrzymane równie$ po zamkni%ciu przegl darki, natomiast dane przecho-
wywane w sesji s dost%pne wy# cznie do czasu zamkni%cia okna. Wszystkie dane s prze-
chowywane w kontek'cie ich domeny i udost%pniane wy# cznie tym skryptom, które pocho-
dz z domen stanowi cych /ród#o tych danych.
Aby skorzysta( z mechanizmów przechowywania danych lokalnie i przechowywania danych
w sesji, nale$y u$y( odpowiednio obiektu
localStorage
oraz
sessionStorage
. Odpowiednie API
jest bardzo podobne do w dzia#aniu do mechanizmu ustawiania w#a'ciwo'ci na obiektach
JavaScriptu i, je'li nie liczy( ró$nic w nazwach obydwóch wspomnianych obiektów, jest iden-
tyczne dla obydwóch mechanizmów:
// Ustawienie warto&ci
localStorage["someData"] = "wem";
API WebStorage udost%pnia jeszcze kilka innych funkcji:
// Liczba przechowywanych elementów danych
var itemsStored = localStorage.length;
// Ustawienie danych
localStorage.setItem("someData", "wem");
// Pobranie danych, zwrócenie null, je&li dane s1 nieznane
localStorage.getItem("someData"); //=> "wem";
// Usuni*cie danych, zwrócenie null, je&li dane s1 nieznane
localStorage.removeItem("someData");
// Wyczyszczenie wszystkich elementów danych
localStorage.clear();
Dane s przechowywane w postaci ci gów znaków, dlatego je'li konieczne b%dzie zapisanie
obiektów albo liczb ca#kowitych, trzeba b%dzie samodzielnie dokona( odpowiednich prze-
kszta#ce&. Aby to zrobi( przy u$yciu JSON, nale$y zserializowa( obiekty do postaci JSON
przed ich zapisaniem, natomiast w przypadku odczytywania obiektów — zdeserializowa(
ci gi znaków JSON:
var object = {some: "object"};
// Serializacja i zapisanie obiektu
localStorage.setItem("seriData", JSON.stringify(object));
// Za%adowanie i deserializacja obiektu
var result = JSON.parse(localStorage.getItem("seriData"));
Je$eli wolumen danych przekroczy dozwolony rozmiar (zwykle jest to 5 MB na jeden serwer /ró-
d#owy), w momencie próby zapisania kolejnych danych zwrócony zostanie b# d
QUOTA_EXCEEDED_ERR
.
Dodanie mechanizmu
przechowywania danych lokalnie do ORM
Dodajmy do biblioteki ORM opcj% przechowywania danych na lokalnym komputerze, aby
umo$liwi( utrzymanie rekordów mi%dzy kolejnymi od'wie$eniami strony. Aby skorzysta(
z obiektu localStorage, nale$y zserializowa( rekordy do postaci ci gu znaków JSON. Problem
polega na tym, $e obecnie zserializowane obiekty wygl daj nast%puj co:
var json = JSON.stringify(Asset.init({name: "foo"}));
json //=> "{"parent":{"parent":{"prototype":{}},"records":[]},"name":"foo"}"
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ
62
Rozdzia# 3. Modele i dane
Trzeba wi%c pokry( mechanizm serializacji JSON dla naszych modeli. W tym celu najpierw
ustalmy, które w#a'ciwo'ci trzeba zserializowa(. Do obiektu
Model
dodamy tablic%
attributes
,
w której ka$dy z modeli b%dzie wskazywa# odpowiednie atrybuty przeznaczone do serializacji:
Model.extend({
created: function(){
this.records = {};
this.attributes = [];
}
});
Asset.attributes = ["name", "ext"];
Poniewa$ ka$dy model ma odmienne atrybuty, przez co modele nie mog wspó#u$ytkowa(
tej samej tablicy
attributes
, w#a'ciwo'ci tej nie ustawia si% bezpo'rednio na obiekcie
Model
.
Zamiast tego nowa tablica jest tworzona w momencie tworzenia modelu — analogicznie jak
w przypadku obiektu
records
.
Utworzymy teraz funkcj%
attributes()
, która zwróci obiekt dla atrybutów i warto'ci:
Model.include({
attributes: function(){
var result = {};
for(var i in this.parent.attributes) {
var attr = this.parent.attributes[i];
result[attr] = this[attr];
}
result.id = this.id;
return result;
}
});
Dla ka$dego modelu mo$na ju$ zdefiniowa( tablic% atrybutów:
Asset.attributes = ["name", "ext"];
Wówczas funkcja
attributes()
b%dzie zwraca( obiekt z odpowiednimi w#a'ciwo'ciami:
var asset = Asset.init({name: "document", ext: ".txt"});
asset.attributes(); //=> {name: "document", ext: ".txt"};
Aby pokry( funkcj%
JSON.stringify()
, wystarczy wykona( metod%
toJSON()
na instancjach
modeli. Biblioteka JSON wyszuka za pomoc tej funkcji obiekt przeznaczony do zserializo-
wania, zamiast zserializowa( obiekt
records
w jego obecnej postaci:
Model.include({
toJSON: function(){
return(this.attributes());
}
});
Spróbujmy teraz ponownie zserializowa( rekordy. Tym razem wynikowy ci g znaków JSON
b%dzie zawiera# prawid#owe w#a'ciwo'ci:
var json = JSON.stringify(Asset.records);
json //= "{"7B2A9E8D...":"{"name":"document","ext":".txt","id":"7B2A9E8D..."}"}"
Skoro serializacja JSON dzia#a bez zarzutu, dodanie obs#ugi przechowywania danych lokal-
nie do naszego modelu b%dzie trywialne. Do obiektu
Model
dodamy w tym celu dwie funkcje:
saveLocal()
oraz
loadLocal()
. W trakcie zapisywania obiekt
Model.records
zostanie przekszta#-
cony w tablic%, zserializowany i wys#any do
localStorage
:
var Model.LocalStorage = {
saveLocal: function(name){
// Przekszta%cenie records w tablic*
var result = [];
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ
Przesy#anie nowych rekordów na serwer
63
for (var i in this.records)
result.push(this.records[i])
localStorage[name] = JSON.stringify(result);
},
loadLocal: function(name){
var result = JSON.parse(localStorage[name]);
this.populate(result);
}
};
Asset.extend(Model.LocalStorage);
Zapewne dobrym pomys#em b%dzie odczytywanie rekordów z lokalnego repozytorium
w trakcie #adowania strony i ich zapisywanie, gdy strona b%dzie zamykana. Zostawiam to
jednak jako (wiczenie dla Czytelników.
Przesy#anie nowych rekordów na serwer
Nieco wcze'niej w tej ksi $ce pokazano, jak wykorzystywa( funkcj%
post()
biblioteki jQuery,
aby przesy#a( dane do serwera. Funkcja przyjmuje trzy argumenty: docelowy adres URL,
dane $ dania i wywo#anie zwrotne:
jQuery.post("/users", {first_name: "Alex"}, function(result){
/* K1danie POST Ajax zakoHczy%o sie powodzeniem */
});
Dzi%ki wcze'niejszemu zaimplementowaniu funkcji
attributes()
tworzenie rekordów na ser-
werze jest ju$ proste — wystarczy metod
POST
przes#a( atrybuty rekordu:
jQuery.post("/assets", asset.attributes(), function(result){
/* K1danie POST Ajax zakoHczy%o sie powodzeniem */
});
Aby konsekwentnie trzyma( si% konwencji REST, w momencie tworzenia rekordu nale$y
wykonywa( $ danie HTTP
POST
, za' w chwili zmiany tego rekordu — $ danie HTTP
PUT
.
Dodajmy zatem do instancji
Model
dwie funkcje o nazwach
createRemote()
i
updateRemote()
,
które b%d odpowiada( za wys#anie do serwera $ dania HTTP odpowiedniego rodzaju:
Model.include({
createRemote: function(url, callback){
$.post(url, this.attributes(), callback);
},
updateRemote: function(url, callback){
$.ajax({
url: url,
data: this.attributes(),
success: callback,
type: "PUT"
});
}
});
Teraz, je'li na instancji zasobu
Asset
zostaje wywo#ana funkcja
createRemote()
, atrybuty in-
stancji s przesy#ane do serwera metod
POST
:
// Sposób uJycia:
Asset.init({name: "jason.txt"}).createRemote("/assets");
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ
64
Rozdzia# 3. Modele i dane
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ
255
Skorowidz
A
Adobe Flash, 116
Ajax, 226
Ajax Crawling, 77
akcje szablonowe, 217
alias $, 221, 227
alias fn, 23
Alman Ben, 44
AMD, Asynchronous Module Definition, 93
analiza
DOM, 140
CSS, 140
wydajno'ci sieci WWW, 156
$ da& sieciowych, 144
anulowanie zdarze&, 101
API, 33
Ajax, 226
biblioteki jQuery, 39, 55, 221
biblioteki Spine, 171
do obs#ugi plików, 97
History, 79, 80
History HTML5, 78
Socket.IO, 119
WebSocket, 119
aplikacja
Less.app, 234
Holla, 15, 120
architektura aplikacji, 18, 47
arkusze stylów Less, 234
asercje, 125
atrybut, 180, 203
data-main, 94
defer, 150
files, 99
multiple, 98
audyt strony internetowej, 155
audytory, 155
automat sko&czony, 74
automatyczna aktualizacja widoku, 88
B
Backbone, 179
aplikacja, 192
delegowanie zdarze&, 184
kolekcje, 181
komunikacja z serwerem, 188
kontrolery, 186
modele, 180
obs#uga historii, 187
wi zanie, 185
widoki, 183
barwa, hue, 236
bezpiecze&stwo, 98, 115
bezpiecze&stwo $ da&, 59
biblioteka
Backbone, 179
Controller, 73
Envjs, 134
gem Ruby-YUI-compressor, 153
Growl, 228
Ichabod, 136
Jammit, 153
JavaScriptMVC, 199
jQuery, 15, 32, 221
jQuery UI, 228
jQuery.tmpl, 83, 86, 195
Less, 231
Less.js, 234
Modernizr, 248
ORM, 60
Prototype, 33
QUnit, 126
Rhino, 90
Selenium, 132
Socket.IO, 118
SpiderMonkey, 90
Spine, 33, 157
Sprocket, 153
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ
256
Skorowidz
biblioteka
Sprockets, 95
Super.js, 27
Watir, 131
Vows.js, 135
YUI Compressor, 153
YSlow, 155
Zepto.js, 179
Zombie.js, 134
biblioteki
asercji, 126
#adowania modu#ów, 92
odwzorowa& obiektowo-relacyjnych, 48
pomocnicze, 20
powiadomie&, 228
szablonów, 83
testuj ce, 129
zdarze&, 39
b#%dy aplikacji, 142
C
CDN, Content Delivery Network, 92, 154
cieniowanie, 238
Comet, 113
CommonJS, 90
CORS, 57
CRUD, Create, Read, Update, Delete, 188
CSS, 231
rozszerzenia, 231
CSS3, 232, 235, 250
czas wykonania kodu, 147
czat, 120
czcionki, 246
D
Dangoor Kevin, 90
data wyga'ni%cia zasobu, 151
debugger JavaScriptu, 140, 143
definiowanie cieni, 238
deklarowanie modu#u, 90
delegowanie, 29
delegowanie zdarze&, 40, 72, 168, 184
d#ugotrwa#e po# czenie, long polling, 113
dodawanie
dziedziczenia, 26
funkcji, 23
funkcji prywatnych, 31
kontekstu, 67
metod, 24
przezroczysto'ci, 237
w#a'ciwo'ci, 24
w#a'ciwo'ci instancji, 33
w#a'ciwo'ci klasy, 33
dokumentacja jQuery, 225
dokumentacja LABjs, 96
DOM, 39
domenowy j%zyk skryptowy DSL, 132
dost%p do plików, 97, 99
dost%p do widoków, 70
DRY, Don’t Repeat Yourself, 69
duszki CSS, CSS sprites, 149
dynamiczna wersja strony, 78
dziedziczenie, 26
dziedziczenie klas, 25
dziedziczenie statyczne, 201
E
ECMAScript, 17
eksport przypadków testowych, 133
elegancka degradacja, graceful degradation, 235, 247
element Socket.IO, 119
enkapsulacja us#ug, 207
Envjs, 134
ES5, 30
etykietowanie elementu, 219
F
Firebug, 140
format JSON, 116
formularz form, 108
FSM, Finite State Machine, 74
FUBC, 96
funkcja
$$(), 142
$(), 142
$x(), 142
activate(), 75
add(), 74
addChange(), 87
addClass(), 224
addElement(element, x, y), 101
addEventListener(), 35, 40
listener, 35
type, 35
useCapture, 35
ajax(), 226
App.log(), 142
append(), 223
apply(), 27
assert(), 14, 125
assertEqual(), 14
attributes(), 63, 162
autoLink(), 84
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ
Skorowidz
257
Backbone.sync(), 188, 190
method, 191
model, 191
options, 191
bind(), 30, 39, 45, 225
call(), 27
change(), 87
clear(), 142
close(), 116
comparator(), 183
confirm(), 37
console.log(), 141, 144
console.profile(), 146
console.profileEnd(), 146
contextFunction(), 67
create(), 50
created(), 159
createRemote(), 63
deactivate(), 75
delegate(), 40, 42
delegateEvents(), 72
destroy(), 48
dir(), 142
document.createElement(), 81
eval(), 91
extend(), 25, 45
fetch(), 189
find(), 52
getData(), 104
getJSON(), 226
history.pushState(), 79
html(), 224
include(), 25, 68
init(), 50, 71
inspect(), 143
jQuery.ajax(), 56, 57
jquery.makeArray(), 29
jQuery.post(), 57
jQuery.proxy(), 29, 226
jQuery.tmpl(), 83
keys(), 143
loadLocal(), 62
Math.random(), 52
module(), 127
Object.create(), 49
populate(), 60
post(), 63
prepend(), 223
preventDefault(), 37
proxy(), 29, 40, 68
publish(), 45
ready(), 39
refresh(), 189
refreshElements(), 72, 168
removeEventListener(), 35
render(), 184
require(), 90, 93
route(), 187
saveLocal(), 62
saveLocation(), 187
send(), 108, 115
setData(), 100
setDragImage(), 101
slice(), 106
stopImmediatePropagation(), 37
stopPropagation(), 37
subscribe(), 45
template(), 175
test(), 127
text(), 225
toggleClass(), 69
toJSON(), 184
trigger(), 41, 161
update(), 53
uploadFile(), 111
validate(), 164, 181
values(), 143
funkcje
anonimowe, 31
konstruktora, 22
obs#ugi szablonów, 84
pomocnicze aplikacji, 84
pomocnicze konsoli, 142
porównuj ce, 130
G
generator identyfikatorów GUID, 52
generowanie obiektu JSON, 55
generowanie widoku, 81, 184
Go, 119
Google Chrome Frame (GCF), 249
gradienty, 239, 251
GUID, Globally Unique Identifier, 52
Gzip, 153
H
hash value, 76, 79
historia przegl darki, 79
HJS, 32
Holla, 15, 120
HTML5, 97
I
Ichabod, 136
identyfikator ID, 52
implementowanie sterownika, 131
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ
258
Skorowidz
informacje o pliku, 101, 109
inkapsulacja zasi%gu, 21
inspektory, 138
instalacja Spine, 157
interfejs kana#owy, 119
interoperacyjno'( kodu, 90
iteracje, 84
iterator
each(), 223
map(), 223
J
Jasmine, 129
jasno'(, lightness, 236
JavaScriptMVC, 199
$.Class, 199
$.Controller, 199
$.Model, 199
$.View, 199
kontrolery, 213
metoda bazowa, 201
modele, 203, 205
obs#uga szablonów, 211, 213
tworzenie klasy, 200
jQuery
nextPrev, 204
JSMin, 153
JSON, 207
Juggernaut, 119
K
kana# alfa, 236
kana# RSS, 120
kaskadowe arkusze stylów, 231
klasa
$.Class, 200
$.Controller, 200, 215
$.Model, 207
$.View, 210, 212
active, 41
Backbone.Controllers, 186
Class, 202
Clicky, 201
Controller, 69
foo, 221
nag#ówków, 151
no-js, 248
potomna, 26
selected, 221
Spine.List, 174
WebSockets, 115
kolejno'( elementów, 183
kolekcje, 182
kolory, 236
kompilacja Less, 233, 234
kompresja Gzip, 153
komunikacja z serwerem, 188
konfiguracja JavaScriptMVC, 200
konsola, 141
konstruktor jQuery, 223
konteksty, 28, 134, 160
kontroler, 21, 166, 186, 213
aplikacji, 65
App, 178
Contacts, 175
Sidebar, 173
kontrolka do przesy#ania plików, 98
kontrolki stronicowania
count, 203
limit, 203
offset, 203
kontrolowanie zasi%gu, 30
konwencja REST, 63
kopiowanie, 103
L
LABjs, 96
Less.app, 234
liczba $ da& HTTP, 149
lista dozwolonych domen klientów, 117
lista mechanizmów transportowych, 118
lista zada&, 218
logika prezentacji, 20
*
#adowanie
danych, 54, 55
modu#u, 92
plików na serwer, 107
równoleg#e, 96
synchroniczne modu#ów, 91
szablonów, 85
widoku, 212
#a&cuchy wywo#a&, 227
# czenie modu#ów, 95
M
manipulowanie modelem DOM, 223
maszyna stanów, 45, 74
metoda
alert(), 138
DELETE, 207
GET, 207
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ
Skorowidz
259
multipart/form-data, 109
POST, 207
PUT, 207
toJSON(), 62
metody pomocnicze, 206
migawki, 147
minifikacja, 95, 152
model, 19
Contact, 173
danych kontaktowych, 173
DOM, 223
elastycznych kontenerów, 245
Paginate, 205
warto'ci domy'lne, 206
Task, 207
modele, 161, 180, 203
modu#, 25
Adobe Flash, 60
application, 92
CommonJS, 92
HJS, 32
maths.js, 91
mod_deflate, 154
nextPrev, 204
Spine.Events, 161
utils, 93
V8 JS, 118
Web Inspector, 136
modu#y, 89
modyfikatory jQuery, 211
MVC, Model View Controller, 18, 85, 180
N
nag#ówek
Expires, 150
Last-Modified, 152
protoko#u HTTP, 114
nagrywanie sesji, 132
narz%dzie
Fetch as Googlebot, 78
Firebug, 140, 155
Firebug Lite, 141
Juggernaut, 119
LABjs, 96
MooTools, 39
Prototype, 39
Pusher, 119
rack-modulr, 95
Selenium IDE, 132
TestSwarm, 137
Web Inspector, 138
YUI, 39
narz%dzie do przesy#ania plików, 98
nas#uch zdarzenia click, 21
nas#uchiwanie zdarze&, 218
nasycenie, saturation, 236
natywna implementacja klas, 22
natywna obs#uga klas, 32
natywny inspektor kodu, 140
nazwy funkcji konstruktorów, 22
negacja selektorów, 242
negocjowanie po# cze& TCP, 114
Node.js, 118
O
obiekt
Asset, 45
Blob, 106
clipboardData, 103
Controller, 68
dataTransfer, 102
elements, 72
event, 36, 37
Events, 72, 74
exports, 68
File
name, 98
size, 98
type, 98
FileList, 98
FileReader, 105
FormData, 108
localStorage, 61
Model, 49
prototypowy, 26
rpc, 116
sessionStorage, 61
User, 48
obiekty wstrzymane, deferred objects, 212
obserwatory zdarze&, 115
obs#uga
IE6, 235
modu#ów, 25
przeci gania, 100
przej'(, 242
szablonów, 211
szablonów HTML, 195
wywo#a& zwrotnych, 25
zdarze&, 161
obszar upuszczania, 111
odpytywanie ci g#e serwera, 113
opakowywanie modu#ów, 94
opcje nag#ówka, 151
max-age, 151
must-revalidate, 151
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ
260
Skorowidz
no-store, 151
public, 151
operator
new, 22
not, 242
this, 225
var, 31
ORM, 45, 48, 52
P
pami%( podr%czna, 150
pasek post%pu, 109
platforma programistyczna JS, 199
platforma Rack, 233
plik
application.rb, 233
helpers.js, 84
production.rb, 234
spine.model.local.js, 164
pliki cookie, 60
pliki PSD, 235
polecenie rackup, 95
po# czenia wss, 117
po# czenie zdublowane, 115
pr%dko'( dzia#ania, 121
pr%dko'( generowania stron, 156
proces JuggernautObserver, 120
profilowanie kodu, 146
protokó# WebSocket, 117
prototyp
Function, 31
Object.prototype, 26
prototype, 23
przechowywanie
danych, 60
lokalne, local storage, 60
stanu na kliencie, 65
szablonów, 85
w sesji, session storage, 60
przeci ganie, 100
plików poza przegl dark%, 101
tekstu, 100
przedrostki stylów, 236
przegl darka
Chrome, 123, 235
Firefox, 123, 235
IE, 123, 235
Opera, 123
Safari, 123, 235
przej'cia, 242
przekierowanie
robota, 78
sta#e, 78
tymczasowe, 78
przep#yw zdarze&, 19
przestrze& nazw, 20, 89
przesy#anie plików, 108, 111
przetwarzanie plików, 97
przezroczysto'(, 236
punkt przerwania, 143
Pusher, 119
Q
QUnit, 126
R
Rack, 119
Rack and Rails, 96
regu#y zagnie$d$one, 232
rekomendacje, 155
rekordy, 162, 163
repozytorium GitHub, 15
RequireJS, 93
Resig John, 33
REST, Representational State Transfer, 189, 207
robot, 78
rozmiar $ dania, 114
rozszerzanie klas, 159
rozszerzanie modeli, 205
rozszerzenia jQuery, 227
RPC, Remote Procedure Call, 116
Ruby, 25
S
selektor nth-child, 241
selektory, 221, 241
Selenium IDE, 132
serwer zdarzeniowy, 118
serwis Quirksmode, 36
sie( dostarczania tre'ci, 154
silnik generowania stron WWW, 235
silnik WebKit, 103
sk#adnia stylów CSS3, 254
s#owo kluczowe
class, 23
new, 23
this, 23, 67
Socket.IO, 118
specyfikacja
Ajax Crawling, 78
JavaScript, 30
Web Storage, 60
Spine, 32, 157
aplikacja, 172, 178
delegowanie zdarze&, 168
klasy, 158
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ
Skorowidz
261
kontrolery, 166
modele, 161
proxied, 167
w#a'ciwo'( elements, 167
zapisywanie, 164
zdarzenia, 161
zdarzenia standardowe, 163
Sprockets, 95
stan aplikacji, 76
stan strony, 65
standard CORS, 58
sterowniki, drivers, 131
stronicowanie, 203
styl
@font-face, 246
border-image, 244
border-radius, 237
box-shadow, 238
box-sizing, 244
hsl, 236
rgb, 236
text-shadow, 239
style gradientów CSS3, 236
style standardowe, 235
subszablony, 212
szablony, 82
EJS, 211
JAML, 211
#adowanie wst%pne, 213
Micro, 211
pakowanie, 213
Tmpl, 211
@
'rodowisko testowe, 126
T
tabela zgodno'ci zdarze&, 36
tablica
asocjacyjna atrybutów, 180
asocjacyjna zdarze&, 184
attributes, 62
nazw atrybutów, 161
nazw funkcji, 167
technologia
AJAX, 55
JSONP, 55, 59
Rails, 120
Ruby, 95
testowanie
kodu, 123
niezale$ne, 134
rozproszone, 137
testy
Jasmine, 131
JavaScript, 131
jednostkowe, 125
QUnit, 128
t#o, 241
tooltip, 215
Tornado, 119
transformacje, 244
Transport C, 92
Transport D, 92
tworzenie
asercji, 130
biblioteki Growl, 228
gniazdka, 115
graficznych interfejsów u$ytkownika, 245
instancji, 22, 158, 200
instancji kontrolera, 216
instancji modelu na serwerze, 208
klas, 22
klasy, 200
kolekcji, 182
kontrolerów, 65, 70, 186
modeli, 180
ORM, 48
rekordów na serwerze, 63
statycznych szablonów, 235
uk#adu, 250
widoków, 81
wid$etów, 219
typ
atrybutów, 209
MIME, 56
zwracanych danych, 105
typy zdarze&, 37
U
ukrywanie zak#adek, 42
upuszczanie, 101
us#uga REST, 207
ustawianie warto'ci, setters, 205
utrzymywanie rekordów, 51
W
W3C, 35
warstwa abstrakcji, 121, 180
warstwa abstrakcji dla zdarzenia, 100
Watir, 131
wczytywanie pliku, 105
wdra$enie aplikacji internetowej, 149
Web Inspector, 138, 145
WebKit, 235
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ
262
Skorowidz
WebSockets, 114
Web-sockets-js, 116
weryfikacja poprawno'ci, 164
wiadomo'ci Message, 120
wi zanie, 86
modeli, 87
zdarze&, 216
widok, 20
AppView, 195
TodoView, 195
widoki, 183
wid$et
dymku z porad , 214
listy, 215
nextPrev, 214
witryna Mozilla Developer, 55
wklejanie, 104
w#asne
przyciski przegl darki, 107
wywo#anie zwrotne, 86
zdarzenia, 168
znaczniki skryptów, 85
w#asny protokó#, 116
w#a'ciwo'ci, 24
ORM, 50
zdarze&, 38
w#a'ciwo'( elements, 167
wplatanie danych, 55
wplecenia, 232
wyciekanie pami%ci, 214
wydajno'( aplikacji, 90, 94, 114, 149
wydzielanie biblioteki, 68
wykrywanie WebSockets, 115
wype#nianie kolekcji, 189
wywo#anie zwrotne, 45
wywo#ywanie funkcji, 27
wywo#ywanie metody bazowej, 201
wzorzec
Element, 170
Module, 228
modu#u, 66
MVC, 47, 180
Publish/Subscribe, 43
PubSub, 119, 120
Render, 170
X
XHR, 92
XMLHttpRequest, 108, 226
Y
Yabble, 92
Z
zadanie CRUD
pobieranie, 208
tworzenie, 208
uaktualnianie, 209
usuwanie, 209
zamykanie po# czenia, 116
zarz dzanie
oczekiwaniami, expectation management, 122
zale$no'ciami, 89, 96
zdarzeniami, 39
zasada to$samego pochodzenia, 57
zasi%g klasy, 29
zasi%g kontekstu, 67
zdarzenia
anulowanie, 37
CRUD, 210
delegowanie, 40
globalne, 169
kontrolera, 168
modelu, 163
nas#uchiwanie, 35
przechodz ce w dó#, event capturing, 36
przechodz ce w gór%, event bubbling, 36
typy, 37
w#asne, 41
w#a'ciwo'ci, 38
zdarzenie
beforecopy, 103
beforecut, 103
beforepaste, 104
blur, 36
change, 36, 87
change.tabs, 42
click, 36
copy, 103
cut, 103
dblclick, 36
document.ready, 225, 227
DOMContentLoaded, 39
drag, 100
dragend, 100
dragenter, 100
dragleave, 100
dragover, 100, 102
dragstart, 100
drop, 100, 101
focus, 36
hashchange, 77
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ
Skorowidz
263
load, 110
mousemove, 36
mouseout, 36
mouseover, 36
onerror, 105
onhashchange, 187
onload, 105
onmessage, 115
onopen, 115
onprogress, 105
paste, 104
popevent, 80
popstate, 80
progress, 110
submit, 36
zmienna self, 225
zmienne globalne, 31
eksport, 66
import, 66
znaczniki ETags, 152
znak
dolara, 221
dwukropka, 101
hash, 221
podkre'lenia, 31
uko'nika, 150
wykrzyknika, 78
Zombie.js, 134
F
$ dania Ajax, 56, 226
$ dania HTTP, 55, 63
$ danie
DELETE, 56
GET, 56, 57
OPTIONS, 58
POST, 56, 63
PUT, 63
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ