` co poprzednio. Jest to użyteczny sposób na sprawdzenie, kiedy elementy zostały przerenderowane i kiedy nie ulegają zmianie.
+Teraz, w konsoli JavaScript, wstaw kolejny post. Jeżeli przejdziesz z powrotem do inspektora DOM, zobaczysz dodatkowy element `
` odpowiadający nowemu postowi, ale nadal będzie zaznaczony *ten sam* element `
` co poprzednio. Jest to użyteczny sposób na sprawdzenie, kiedy elementy zostały przerenderowane i kiedy nie ulegają zmianie.
<% end %>
-### Łączenie kolekcji: Publikacje i Subsrkrypcje
+### Łączenie kolekcji: Publikacje i Subskrypcje
Do tej pory używaliśmy pakietu `autopublish`, który nie jest zamierzony do użycia w środowisku produkcyjnym. Jak nazwa wskazuje, pakiet ten automatycznie publikuje w całości wszystkie kolekcje każdemu podłączonemu klientowi. Nie jest to, co chcemy osiągnąć, więc wyłączmy to.
@@ -305,9 +305,9 @@ Otwórz nowe okno terminala i wpisz:
$ meteor remove autopublish
~~~
-Ma to efekt natychmiastowy. Jeżeli będziesz obserwował przeglądarkę, zobaczysz, że wszystkie posty zniknęły! Dzieje się tak, poniewaź polegaliśmy na pakiecie `autopublish`, który tworzył lustrzane odbicie wszystkich postów z bazy danych w kolekcji po stronie klienta.
+Ma to efekt natychmiastowy. Jeżeli będziesz obserwował przeglądarkę, zobaczysz, że wszystkie posty zniknęły! Dzieje się tak, ponieważ polegaliśmy na pakiecie `autopublish`, który tworzył lustrzane odbicie wszystkich postów z bazy danych w kolekcji po stronie klienta.
-W końcu będzieli musieli się upewnić, że przesyłamy wyłącznie te posty, które użytkownik będzie miał zobaczyć (biorąc również po uwagę np. dzielenie dokumentu na strony). Na teraz, ustawimy publikację kolekcji `Posts` w całości.
+W końcu będziemy musieli się upewnić, że przesyłamy wyłącznie te posty, które użytkownik będzie miał zobaczyć (biorąc również po uwagę np. dzielenie dokumentu na strony). Na teraz, ustawimy publikację kolekcji `Posts` w całości.
Aby to osiągnąć, utworzymy prostą funkcję `publish()`, która zwraca kursor posiadający referencję do wszystkich postów:
@@ -329,6 +329,6 @@ Meteor.subscribe('posts');
Jeżeli ponownie sprawdzimy przeglądarkę, zobaczymy ponownie nasze posty. Świetnie!
-### Konluzja
+### Konkluzja
Co zatem osiągnęliśmy? Pomimo tego, że jeszcze nie posiadamy interfejsu użytkownika, mamy funkcjonalną aplikację webową. Moglibyśmy wystawić aplikację na zewnętrznym internetowym serwerze i (używając konsolę przeglądarki) zacząć dodawać posty, które byłyby widziane w każdej podłączonej do strony przeglądarki na całym świecie.
diff --git a/04s-publications-and-subscriptions.md.erb b/04s-publications-and-subscriptions.md.erb
index c88f6db..a834c3a 100644
--- a/04s-publications-and-subscriptions.md.erb
+++ b/04s-publications-and-subscriptions.md.erb
@@ -24,7 +24,7 @@ Gdy dane zostały znalezione, kolejnym zadaniem aplikacji jest przetłumaczenie
Używając metafory księgarni, można to skojarzyć z opakowaniem właśnie zakupionej książki i wrzucenie jej do torby. Jest to część nazywana "View" w znanym modelu MVC (Model-View-Controller).
-Ostatecznie, aplikacja wysyła wygenerowany kod HTML do przeglądarki. Praca aplikacji jest zakończona i kontrola zostaje przekazana z dala od jej wirtualnych rąk, oczekująć na kolejny dostęp.
+Ostatecznie, aplikacja wysyła wygenerowany kod HTML do przeglądarki. Praca aplikacji jest zakończona i kontrola zostaje przekazana z dala od jej wirtualnych rąk, oczekując na kolejny dostęp.
### Jak to robi Meteor
@@ -50,7 +50,7 @@ Wróćmy do Microscope. Poniżej znajdziesz wszystkie posty znajdujące się w b
Co prawda taka funkcjonalność nie istnieje w aplikacji Microscope, ale wyobraźmy sobie, że niektóre z postów zostały zaznaczone jako posiadające obraźliwe słownictwo. Mimo to, że chcemy je dalej przechowywać w bazie danych, nie powinny być udostępniane użytkownikom (tj. wysyłane do klienta).
-Naszym pierwszym zadaniem będzie przekazanie Meteorowi które dane *chcemy* wysłać klientowi. Bedą **publikowane** wyłącznie te posty, które nie zostały oznaczone flagą jako obraźliwe.
+Naszym pierwszym zadaniem będzie przekazanie Meteorowi które dane *chcemy* wysłać klientowi. Będą **publikowane** wyłącznie te posty, które nie zostały oznaczone flagą jako obraźliwe.
<%= diagram "collections-2", "Wyłączenie zaznaczonych postów.", "pull-center" %>
@@ -109,7 +109,7 @@ Okazuje się, że post Boba jest przyporządkowany do kliku kategorii (np. “Ja
<%= diagram "collections-4", "Zaznaczanie podzbioru dokumentów po stronie klienta.", "pull-center" %>
-Tak, jak po stronie serwera, użyjemy funkcję `Posts.find()` do zaznaczenia pozdbioru danych.
+Tak, jak po stronie serwera, użyjemy funkcję `Posts.find()` do zaznaczenia podzbioru danych.
~~~js
// po stronie klienta
@@ -134,7 +134,7 @@ Jak to działa? Przyjmijmy, że posiadasz aplikację `'posts'` po stronie serwer
Jeżeli zatem używasz pakietu `autopublish`, nie musisz się troszczyć o publikacje. Dane są wszechobecne i wszystko jest proste. Oczywiście możesz napotkać oczywiste problemy związane z utrzymywaniem kompletnej kopii bazy danych po stronie klienta na każdej maszynie po stronie klienta.
-Z tego powodu użycie autopublish jest odpowiednie wyłącznie wtedy gdy zaczynasz implementację i nie uzwględniłeś publikacji.
+Z tego powodu użycie autopublish jest odpowiednie wyłącznie wtedy gdy zaczynasz implementację i nie uwzględniłeś publikacji.
### Publikowanie całych kolekcji
@@ -170,7 +170,7 @@ Jeżeli czytałeś [dokumentację publikacji Meteora](http://docs.meteor.com/#pu
Jest to spowodowane bardzo ważnym ułatwieniem, które dostarcza Meteor: metodą `_publishCursor()`. Nie widziałeś również tej metody? Może nie bezpośrednio, ale jeżeli zwracasz [kursor](/chapter/meteor-vocabulary/) (np. `Posts.find({'author':'Tom'})`) w funkcji dokonującej publikacji, to Meteor używa właśnie tej funkcji.
-Gdy Meteor rozpoznaje, że publikacjia `somePosts` zwraca kursor, woła metodę `_publishCursor()` aby -- tak, zgadłeś -- automatycznie publikować powyższy kursor.
+Gdy Meteor rozpoznaje, że publikacja `somePosts` zwraca kursor, woła metodę `_publishCursor()` aby -- tak, zgadłeś -- automatycznie publikować powyższy kursor.
Pokrótce opiszmy sposób działania `_publishCursor()`:
diff --git a/05-routing.md.erb b/05-routing.md.erb
index 6a05272..bebd4b4 100644
--- a/05-routing.md.erb
+++ b/05-routing.md.erb
@@ -7,7 +7,7 @@ contents: o routingu w Meteorze.|jak tworzyć stronę z dyskusją o postach, z u
paragraphs: 72
---
-Teraz skoro mamy listę postów (która w końcu będzie wysłana) potrzebujemy stronę dla każdego posta, na której użytkownicy będą mogli prowadzić dyskuję.
+Teraz skoro mamy listę postów (która w końcu będzie wysłana) potrzebujemy stronę dla każdego posta, na której użytkownicy będą mogli prowadzić dyskusję.
Chcielibyśmy, żeby te strony były dostępne za pomocą *permanentnego linka*, URLa w formie `http://myapp.com/posts/xyz` (gdzie `xyz` jest identyfikatorem MongoDB `_id`), który jest unikalny dla każdego posta.
@@ -39,11 +39,11 @@ Poruszymy wiele różnych tematów routera w tym rozdziale. Jeżeli masz doświa
- **Routes** (trasy): Trasa jest fundamentalnym pojęciem routera. Jest to zbiór instrukcji, który wskaże aplikacji gdzie się kierować i co robić po napotkaniu danego URL.
- **Paths** (ścieżki): Ścieżka jest dowolnym URLem dostępnym w Twojej aplikacji. Może być statyczna (`/terms_of_service`) lub dynamiczna (`/posts/xyz`) i może nawet zawierać parametry zapytań (`/search?keyword=meteor`).
- **Segments** (segmenty): części ścieżki rozdzielone slashem (`/`).
-- **Hooks** (haki): Hak jest akcją, którą chciałbyć wykonać przed, po, lub podczas wykonywania procesu routowania. Typowym przykładem może być sprawdzenie, czy użytkownik ma wystarczające prawa, aby obejrzeć daną stronę.
+- **Hooks** (haki): Hak jest akcją, którą chciałbyś wykonać przed, po, lub podczas wykonywania procesu routowania. Typowym przykładem może być sprawdzenie, czy użytkownik ma wystarczające prawa, aby obejrzeć daną stronę.
- **Filters** (filtry): Filtry to globalne haki, które definiuje się dla jednej lub więcej tras.
- **Route Templates** (szablony trasy): Każda trasa musi wskazywać na szablon. Jeżeli nie określisz konkretnego szablonu, router będzie domyślnie szukał szablonu o tej samej nazwie, co trasa.
- **Layouts**: (układy) Możesz pomyśleć o układach jak o ramce na zdjęcia. Zawierają cały kod HTML, który opakowuje bieżący szablon i pozostanie nienaruszony po zmianach szablonu.
-- **Controllers** (kontrolery): Czasami zdasz sobie sprawę, że wiele Twoich szablonów używa tych samych parametrów. Zamiast duplikować kod, możesz sprawic aby wszystkie takie trasy dziedziczyły z jednego *kontrolera trasy*, który będzie zawierał logikę routingu.
+- **Controllers** (kontrolery): Czasami zdasz sobie sprawę, że wiele Twoich szablonów używa tych samych parametrów. Zamiast duplikować kod, możesz sprawić aby wszystkie takie trasy dziedziczyły z jednego *kontrolera trasy*, który będzie zawierał logikę routingu.
Aby dowiedzieć się więcej o Iron Router, sprawdź [pełną dokumentację na GitHub](https://github.com/EventedMind/iron-router).
@@ -103,7 +103,7 @@ Router.map(function() {
~~~
<%= caption "lib/router.js"%>
-Osiągneliśmy dwie ważne sprawy. Po pierwsze, wskazaliśmy routerowi, aby używał layout, który właśnie utworzyliśmy jako domyślny layout dla wszystkich tras. Po drugie, zdefiniowaliśmy nową trasę o nazwie `postLists` i powiązaliśmy ją ze ścieżką `/`.
+Osiągnęliśmy dwie ważne sprawy. Po pierwsze, wskazaliśmy routerowi, aby używał layout, który właśnie utworzyliśmy jako domyślny layout dla wszystkich tras. Po drugie, zdefiniowaliśmy nową trasę o nazwie `postLists` i powiązaliśmy ją ze ścieżką `/`.
<% note do %>
@@ -307,7 +307,7 @@ Nazwaliśmy ścieżkę posta `postPage`, zatem możemy użyć helpera `{{pathFor
~~~
<%= caption "client/views/posts/post_item.html"%>
<%= highlight "6" %>
-<%= commit "5-3", "Przekierowanie na pojedyńczą stronę posta." %>
+<%= commit "5-3", "Przekierowanie na pojedynczą stronę posta." %>
Ale chwila, skąd dokładnie router wie, skąd wziąć część `xyz` z `/posts/xyz`? W końcu nie przekazujemy tu żadnego `_id`.
diff --git a/05s-the-session.md.erb b/05s-the-session.md.erb
index 013c176..3a3781e 100644
--- a/05s-the-session.md.erb
+++ b/05s-the-session.md.erb
@@ -139,7 +139,7 @@ Jeżeli mielibyśmy ręcznie przeładować stronę, nasze zmienne Session natura
Jeżeli zatem używamy zmiennych sesji do śledzenia tego, co użytkownik właśnie robi, HCR powinien być prawie transparentny dla użytkownika, ponieważ zachowa wartość wszystkich zmiennych sesji. Pozwala to na instalację nowej wersji produkcyjnej naszej aplikacji Meteora mając pewność, że nasi użytkownicy będą w minimalnym stopniu zdezorganizowani.
-Rozważ to przez chwilę. Jeżeli możemy trzymać cały stan w URL i sesji, możemy transparetnie zmieniać _uruchomiony kod źródłowy_ każdej aplikacji klienta nie przeszkadzając im zbytnio.
+Rozważ to przez chwilę. Jeżeli możemy trzymać cały stan w URL i sesji, możemy transparentnie zmieniać _uruchomiony kod źródłowy_ każdej aplikacji klienta nie przeszkadzając im zbytnio.
Sprawdźmy co dzieje się, gdy ręcznie odświeżymy stronę:
diff --git a/06-adding-users.md.erb b/06-adding-users.md.erb
index 44b63bc..a9771d0 100644
--- a/06-adding-users.md.erb
+++ b/06-adding-users.md.erb
@@ -101,7 +101,7 @@ Teraz wyloguj się i ponownie utwórz konto z inną nazwą użytkownika. `Meteor
❯ Meteor.users.find().count();
1
~~~
-<%= caption "Konsola przeglądarkiu" %>
+<%= caption "Konsola przeglądarki" %>
Konsola zwraca wartość 1. Czy nie powinna mieć wartości 2? Czy pierwszy użytkownik został usunięty? Jeżeli spróbujesz zalogować się jako pierwszy użytkownik, zobaczysz, że tak się nie stało.
@@ -127,7 +127,7 @@ Pakiet `accounts` publikuje wyłącznie *bieżącego* użytkownika. Wyjaśnia to
Publikacja zatem publikuje wyłącznie jeden obiekt użytkownika dla każdego zalogowanego użytkownika (i nie publikuje żadnego, gdy nie jesteś zalogowany).
-Co więcej, dokumenty w naszej kolekcji użytkownika nie zawierają tych samych pól po stronie klienta i serwera. W Mongo, użytkownik posiada wiele danych. Aby to zobaczyć, wróc do terminala Mongo i wpisz:
+Co więcej, dokumenty w naszej kolekcji użytkownika nie zawierają tych samych pól po stronie klienta i serwera. W Mongo, użytkownik posiada wiele danych. Aby to zobaczyć, wróć do terminala Mongo i wpisz:
~~~bash
> db.users.findOne()
diff --git a/06s-reactivity.md.erb b/06s-reactivity.md.erb
index ee801c7..0a287bc 100644
--- a/06s-reactivity.md.erb
+++ b/06s-reactivity.md.erb
@@ -47,7 +47,7 @@ W takich przypadkach będziesz musiał używać callbacków `observe()` aby zmus
### Podejście deklaratywne
-Meteor daje nam lepsze rozwiązanie: reaktywność, która jest samym jądrem podejścia **deklaratywnego**. Bycie deklaratywnym pozwala na zdefiniowanie związku między obiektami raz i poźniej poleganie na tym, że będą automatycznie synchronizowane zamiast ustawiać akcje reagujące na każdą możliwą zmianę.
+Meteor daje nam lepsze rozwiązanie: reaktywność, która jest samym jądrem podejścia **deklaratywnego**. Bycie deklaratywnym pozwala na zdefiniowanie związku między obiektami raz i później poleganie na tym, że będą automatycznie synchronizowane zamiast ustawiać akcje reagujące na każdą możliwą zmianę.
Jest to bardzo mocny koncept, ponieważ system reagujący w czasie rzeczywistym ma wiele wejść, które mogą zmieniać się w nieoczekiwanych momentach. Przez deklaratywne określenie jak renderujemy bazowane na HTML lub jakiekolwiek inne źródła danych o które się troszczymy, Meteor może przejąć pracę monitorowania źródeł danych i w sposób niewidoczny uaktualniać interfejs użytkownika.
diff --git a/07-creating-posts.md.erb b/07-creating-posts.md.erb
index 79e7edc..1f20645 100644
--- a/07-creating-posts.md.erb
+++ b/07-creating-posts.md.erb
@@ -110,7 +110,7 @@ Uwaga: jest tu wiele znaczników pochodzących z Bootstrap Twittera. Podczas gdy
<%= screenshot "7-1", "Formularz dodawania posta" %>
-Jest to prosty formularz. Nie musimy się martwić o wykonanie konkretnej akcji, ponieważ będziemy przechwytywali zdarzenie `wyślij` na forumlarzu i uaktualniali dane za pomocą JavaScript. (Nie ma sensu dostarczać na wszelki wypadek rozwiązania nie-JavaScript, gdy weźmiesz pod uwagę, że aplikacja Meteora jest całkowicie niefunkcjonalna po wyłączeniu obsługi JavaScript).
+Jest to prosty formularz. Nie musimy się martwić o wykonanie konkretnej akcji, ponieważ będziemy przechwytywali zdarzenie `wyślij` na formularzu i uaktualniali dane za pomocą JavaScript. (Nie ma sensu dostarczać na wszelki wypadek rozwiązania nie-JavaScript, gdy weźmiesz pod uwagę, że aplikacja Meteora jest całkowicie niefunkcjonalna po wyłączeniu obsługi JavaScript).
### Tworzenie postów
@@ -138,9 +138,9 @@ Template.postSubmit.events({
Powyższa funkcja używa [jQuery](http://jquery.com) do parsowania wartości różnych pól formularza i tworzenia nowego obiektu posta z wyników parsowania. Musimy się upewnić, że używamy `preventDefault` na parametrze `event` naszego handlera aby upewnić się, że przeglądarka nie będzie kontynuowała i próbowała wysłać formularza.
-Ostatecznie, możemy przekierować uzytkownika to strony nowego posta. Funkcja kolekcji `insert` zwraca wygenerowany `id` dla obiektu, który został wstawiony do bazy danych, który użyje funkcja Routera `go()` aby utworzyć docelowy URL.
+Ostatecznie, możemy przekierować użytkownika to strony nowego posta. Funkcja kolekcji `insert` zwraca wygenerowany `id` dla obiektu, który został wstawiony do bazy danych, który użyje funkcja Routera `go()` aby utworzyć docelowy URL.
-Końcowym rezultatem jest to, że po wciśnieciu przycisku `wyślij` przez użytkownika, tworzony jest post i użytkownik jest natychmiastowo zabierany do strony z dyskusją na temat tego nowego posta.
+Końcowym rezultatem jest to, że po wciśnięciu przycisku `wyślij` przez użytkownika, tworzony jest post i użytkownik jest natychmiastowo zabierany do strony z dyskusją na temat tego nowego posta.
### Dodanie kilku środków bezpieczeństwa
@@ -155,7 +155,7 @@ $ meteor remove insecure
~~~
<%= caption "Terminal" %>
-Po wykonaniu tej komendy zauważyszm że formularz posta przestanie działać. Dzieje się to, ponieważ bez pakietu `insecure`wstawianie danych po stronie klienta _przestaje być dozwolone_. Musimy dodać Metorowi wyraźne zasady pozwalające na wstawianie postów przez klienta lub wstawiać posty po stronie serwera.
+Po wykonaniu tej komendy zauważysz że formularz posta przestanie działać. Dzieje się to, ponieważ bez pakietu `insecure`wstawianie danych po stronie klienta _przestaje być dozwolone_. Musimy dodać Metorowi wyraźne zasady pozwalające na wstawianie postów przez klienta lub wstawiać posty po stronie serwera.
### Zezwolenie na wstawianie postów
@@ -186,7 +186,7 @@ Zdołaliśmy upewnić się, że musisz być zalogowany, aby móc tworzyć posty.
Jednakże, wciąż musimy dać sobie radę z kilkoma problemami:
- - Wylogowani użytkownicy nadal mają dostę do formularza tworzenia posta
+ - Wylogowani użytkownicy nadal mają dostęp do formularza tworzenia posta
- Post nie jest związany z użytkownikiem w żaden sposób (i nie ma żadnego kodu po stronie serwera, który by to obsługiwał).
- Można utworzyć wiele postów, które będą wskazywały na ten sam URL.
@@ -304,7 +304,7 @@ Helper `currentUser` jest dostarczony przez pakiet `accounts` i jest odpowiednik
### Serwerowe metody Meteora: Większy stopień bezpieczeństwa i abstrakcji
-Zdołaliśmy zabezpieczyć dostęp do strony nowych postów dla niezalogowanych użytkowników, i odmówić takim użytkownim możliwość dodawania postów nawet jeżeli oszukują i używają konsoli przeglądarki. Jest jednak jeszcze kilka rzeczy, o które musimy się zatroszczyć:
+Zdołaliśmy zabezpieczyć dostęp do strony nowych postów dla niezalogowanych użytkowników, i odmówić takim użytkownikom możliwość dodawania postów nawet jeżeli oszukują i używają konsoli przeglądarki. Jest jednak jeszcze kilka rzeczy, o które musimy się zatroszczyć:
- Dodanie znacznika czasu do posta.
- Upewnienie się, że ten sam URL nie można dodać więcej, niż jeden raz.
@@ -344,7 +344,7 @@ Template.postSubmit.events({
~~~
<%= caption "client/views/posts/post_submit.js" %>
-Funkcja `Meteor.call` woła Metodę o nazwie określonej w pierwszym parametrze funkcji. Możesz dodać parametry do wywołania funkcji (w tym przypadku obiekt `post` skonstruowany na podstawie formularza) i ostatecznie dodać callback, który zostanie uruchomiony po zakończeniu Metody. Tutaj po prostu ostrzegamy użytkownika czy wystąpił jakiś problem lub przekierowujemy go nowoutworzonej strony dyskusji konkretnego posta.
+Funkcja `Meteor.call` woła Metodę o nazwie określonej w pierwszym parametrze funkcji. Możesz dodać parametry do wywołania funkcji (w tym przypadku obiekt `post` skonstruowany na podstawie formularza) i ostatecznie dodać callback, który zostanie uruchomiony po zakończeniu Metody. Tutaj po prostu ostrzegamy użytkownika czy wystąpił jakiś problem lub przekierowujemy go nowo utworzonej strony dyskusji konkretnego posta.
Następnie zdefiniujemy Metodą w pliku `collections/posts.js`. Usuniemy blok `allow()` z `posts.js`, ponieważ Metoda Meteora i tak go ominie. Pamiętaj, że Metody są wykonywane po stronie serwera, więc Meteor uważa, że można im ufać.
@@ -390,15 +390,15 @@ Meteor.methods({
Metoda ta jest trochę skomplikowana, ale mamy nadzieje że możesz nadążyć.
-Na początkek definiujemy zmienną `user` i sprawdzamy, czy post z tym samym linkiem już nie istnieje. Następnie sprawdzamy, czy użytkownik jest zalogowany, rzucając błąd (który końcowo będzie wyświetlony w przeglądarce), jeżeli nie jest. Przeprowadzamy także prostą walidację obiektu posta, aby upewnić się, że post zawiera tytuł.
+Na początek definiujemy zmienną `user` i sprawdzamy, czy post z tym samym linkiem już nie istnieje. Następnie sprawdzamy, czy użytkownik jest zalogowany, rzucając błąd (który końcowo będzie wyświetlony w przeglądarce), jeżeli nie jest. Przeprowadzamy także prostą walidację obiektu posta, aby upewnić się, że post zawiera tytuł.
-Następnie, jeżeli istnieje już post z tym samym URL, rzucamy błąd `302` (który oznacza przekierowanie), przekazaując użytkownikowi, że powinien sprawdzić poprzednio tworzony post.
+Następnie, jeżeli istnieje już post z tym samym URL, rzucamy błąd `302` (który oznacza przekierowanie), przekazując użytkownikowi, że powinien sprawdzić poprzednio tworzony post.
Klasa `Error` Meteora ma trzy parametry. Pierwszy, (`error`) będzie numerycznym kodem `302`, drugi (`reason`) zawiera wyjaśnienie zrozumiałe dla człowieka i trzeci (`details`) może być jakąkolwiek użyteczną informacją.
W naszym przypadku, użyjemy trzeci argument aby przekazać ID posta, który właśnie znaleźliśmy. Uwaga: użyjemy tego później aby przekierować użytkownika do jeszcze nieistniejącego posta.
-Jeżeli wszystkie kroki są sprawdzone i przechodzą poprawnie, bierzemy pola, które chcemy wstawić (upewniając się, że użytkownik wołający tą Metodę w konsoli przeglądarki nie może dodać fałszywych danych do bazy) i dodajemy pewne informacje o uzytkowniku dodającym posta -- jak również bieżący czas -- do posta.
+Jeżeli wszystkie kroki są sprawdzone i przechodzą poprawnie, bierzemy pola, które chcemy wstawić (upewniając się, że użytkownik wołający tą Metodę w konsoli przeglądarki nie może dodać fałszywych danych do bazy) i dodajemy pewne informacje o użytkowniku dodającym posta -- jak również bieżący czas -- do posta.
Ostatecznie, wstawiamy post do bazy danych i zwracamy nowy `id` użytkownikowi.
diff --git a/07s-latency-compensation.md.erb b/07s-latency-compensation.md.erb
index 017175e..fc7b0cb 100644
--- a/07s-latency-compensation.md.erb
+++ b/07s-latency-compensation.md.erb
@@ -12,7 +12,7 @@ W ostatnim rozdziale wprowadziliśmy nowy koncept w świecie Metora: **Metody**,
<%= diagram "latency1", "Bez kompensacji lagów", "pull-right" %>
-Metoda w Meteorze umożliwia uruchomienie serii komand na serwerze w uporządkowany sposób. W naszym przykładzie, użytliśmy Metody ponieważ chcieliśmy upewnić się, że nowe posty zostaną otagowane imieniem autora i jego id oraz bieżącym czasem serwera.
+Metoda w Meteorze umożliwia uruchomienie serii komand na serwerze w uporządkowany sposób. W naszym przykładzie, użyliśmy Metody ponieważ chcieliśmy upewnić się, że nowe posty zostaną otagowane imieniem autora i jego id oraz bieżącym czasem serwera.
Gdyby jednak Meteor uruchamiał Metody w sposób najbardziej podstawowy, mielibyśmy problem. Rozważ następującą sekwencję zdarzeń (uwaga: znaczniki czasu są losowymi wartościami, wybranymi wyłącznie dla celów demonstracyjnych):
@@ -128,6 +128,6 @@ Gdy definujesz kolekcję po stronie serwera o nazwie `posts`, definiujesz pośre
Jeżeli nadążasz, mogłeś zdać sobie sprawę, że nasza metoda `post` podczas wstawiania postów wywołuje inną metodę (`posts/insert`). Jak to działa?
-Gdy uruchamiana jest symulacja (wersja metody po stronie klienta), wykonujemy symulację `insert` (zatem wprowadzamy dane do koelekcji po stronie klienta), ale *nie wołamy* prawdziwej metody `insert` po stronie serwera, ponieważ oczekujemy, że wykona to *serwerowa* wersja metody `post`.
+Gdy uruchamiana jest symulacja (wersja metody po stronie klienta), wykonujemy symulację `insert` (zatem wprowadzamy dane do kolekcji po stronie klienta), ale *nie wołamy* prawdziwej metody `insert` po stronie serwera, ponieważ oczekujemy, że wykona to *serwerowa* wersja metody `post`.
Co za tym idzie, gdy serwerowa metoda `post` woła `insert`, nie ma potrzeby o martwienie się o symulację i wprowadzenie danych przebiega płynnie.
diff --git a/08-editing-posts.md.erb b/08-editing-posts.md.erb
index 2ae2805..f34a70b 100644
--- a/08-editing-posts.md.erb
+++ b/08-editing-posts.md.erb
@@ -7,7 +7,7 @@ contents: jak dodać formularz umożliwiający edytowanie postów.|jak ustawić
paragraphs: 29
---
-Teraz skoro możemy tworzyć posty, następnym krokiem będzie umożliwienie edycji i usuwanie postóœ. Kod UI który to umożliwi jest releatywnie prosty i jest to dobry moment na podjęcie tematu zarządzania praw użytkowników.
+Teraz skoro możemy tworzyć posty, następnym krokiem będzie umożliwienie edycji i usuwanie postów. Kod UI który to umożliwi jest relatywnie prosty i jest to dobry moment na podjęcie tematu zarządzania praw użytkowników.
Zacznijmy od podłączenia routera. Dodamy ścieżkę, która umożliwi dostęp do strony modyfikacji posta i ustawi jej kontekst danych:
@@ -52,7 +52,7 @@ Router.before(requireLogin, {only: 'postSubmit'});
### Szablon edytowania posta
-Możemy teraz skoncetrować się na szablonie. Nasz szablon `postEdit` będzie miał całkiem standardową formę:
+Możemy teraz skoncentrować się na szablonie. Nasz szablon `postEdit` będzie miał całkiem standardową formę:
~~~html
@@ -126,7 +126,7 @@ Template.postEdit.events({
Jak do tej pory większość kodu powinna się Tobie wydać znajoma. Na początku mamy helper szablonu, który pobiera bieżący post z bazy danych i przekazuje go do szablonu.
-Następnie mamy dwo callbacki zdarzeń szablonu: jeden dla zdarzenia `submit` formularza, drugi dla usunięcia zdarzenia 'click' dla linka.
+Następnie mamy dwa callbacki zdarzeń szablonu: jeden dla zdarzenia `submit` formularza, drugi dla usunięcia zdarzenia 'click' dla linka.
Callback usuwający zdarzenie click jest bardzo prosty: omija domyślne zdarzenie click i pyta o potwierdzenie. Jeżeli je dostanie, korzysta z post ID obecnego posta otrzymanego z kontekstu danych szablonu, usuwa go i ostatecznie przekierowuje użytkownika do strony domowej.
@@ -240,11 +240,11 @@ Posts.deny({
Używamy tablicy `fieldNames`, która zawiera listę zmienianych pól i używamy metody `without()` [Underscore](http://underscorejs.org/), aby zwrócić tablicę, która zawiera częściową tablicę zawierającą pola, te które *nie* są polami `url` czy `title`.
-Jeżeli wszystko przebiegnie prawidłowo, ta tablica powinna być pusta i jej długość powinna być równa 0. Jeżeli ktoś stara się dokonać czegoś nieoczekiwanego, długość tablicy będzie równa 1 lub więcej i callback zwrócie `true` (odrzucając w ten sposób uaktualnienie).
+Jeżeli wszystko przebiegnie prawidłowo, ta tablica powinna być pusta i jej długość powinna być równa 0. Jeżeli ktoś stara się dokonać czegoś nieoczekiwanego, długość tablicy będzie równa 1 lub więcej i callback zwróci `true` (odrzucając w ten sposób uaktualnienie).
<% note do %>
-### Zawołania metod vs manipulacja danych po stronie klienta
+### Zawołania metod vs. manipulacja danych po stronie klienta
Używamy metody `post` aby utworzyć nowe posty, natomiast do edycji i usuwania ich wołamy `update` i `remove` bezpośrednio po stronie klienta i ograniczamy dostęp przez `allow` i `deny`.
diff --git a/08s-allow-and-deny.md.erb b/08s-allow-and-deny.md.erb
index cfd4375..c2473a7 100644
--- a/08s-allow-and-deny.md.erb
+++ b/08s-allow-and-deny.md.erb
@@ -18,7 +18,7 @@ Używanie tych callbacków pozwala na bardziej deklaratywne modyfikowanie bazy d
### Wiele callbacków
-Możemy zdefiniować tyle callbacków `allow`, ile tylko potrzeba. Potrzebujemy, aby _przynajmniej jeden z nich_ zwracał wartość `true` dla bieżącej zmiany. Zatem gdy `Posts.insert` jest wołany w przeglądarce (nieważne, czy z kodu aplikacji po stronie klienta, czy z konsoli przeglądarki), serwer z kolei zawoła cokolwiek jest zezwolone-`insert` sprawdza wzystkie po kolei, aż znajdzie jeden, który zwróci `true`. Jeżeli nie znajdzie żadnego, nie pozwoli na wprowadzenie danych i zwróci klientowi błąd `403`.
+Możemy zdefiniować tyle callbacków `allow`, ile tylko potrzeba. Potrzebujemy, aby _przynajmniej jeden z nich_ zwracał wartość `true` dla bieżącej zmiany. Zatem gdy `Posts.insert` jest wołany w przeglądarce (nieważne, czy z kodu aplikacji po stronie klienta, czy z konsoli przeglądarki), serwer z kolei zawoła cokolwiek jest zezwolone-`insert` sprawdza wszystkie po kolei, aż znajdzie jeden, który zwróci `true`. Jeżeli nie znajdzie żadnego, nie pozwoli na wprowadzenie danych i zwróci klientowi błąd `403`.
Podobnie możemy zdefiniować jeden lub więcej callbacków `deny`. Jeżeli _jakikolwiek_ z tych callbacków zwróci wartość `true`, zmiana będzie odwołana i zostanie zwrócony błąd `403`. Logika tego jest taka, że dla udanego `insert` zostanie zawołany jeden lub więcej callbacków `insert` oraz _kazdy_ callback `deny`.
diff --git a/09-errors.md.erb b/09-errors.md.erb
index 8de18f7..1bb367a 100644
--- a/09-errors.md.erb
+++ b/09-errors.md.erb
@@ -13,9 +13,9 @@ Zamiast tego rozwiązania, zbudujemy wszechstronny mechanizm raportowania błęd
### Wprowadzenie do lokalnych kolekcji
-Zaimplementujemy prosty system, który śledzi, które błędy użytkownik zobaczył i wyświetla nowe błędy w odpowienim miejscu "migoczących wiadomości" na stronie. Ten wzorzec UX jest użyteczny, gdy chcemy poinformować użytkownika, że coś się stało bez przerywania ich pracy.
+Zaimplementujemy prosty system, który śledzi, które błędy użytkownik zobaczył i wyświetla nowe błędy w odpowiednim miejscu "migoczących wiadomości" na stronie. Ten wzorzec UX jest użyteczny, gdy chcemy poinformować użytkownika, że coś się stało bez przerywania ich pracy.
-Utworzymy coś podobnego do migoczących powiadomień znanych z aplikakcji Ruby on Rails, ale jest bardziej subtelne, bo zaimplementowane po stronie klienta i rozpoznające kiedy użytkownik zobaczył wiadomość.
+Utworzymy coś podobnego do migoczących powiadomień znanych z aplikacji Ruby on Rails, ale jest bardziej subtelne, bo zaimplementowane po stronie klienta i rozpoznające kiedy użytkownik zobaczył wiadomość.
Aby rozpocząć, utworzymy kolekcję, w której będziemy zapamiętywać błędy. Pod warunkiem, że błędy są przeznaczone tylko do bieżącej sesji i nie muszą być w żaden sposób zapisywane, zrobimy coś nowego i stworzymy _lokalną kolekcję_. Oznacza to, że kolekcja `Errors` będzie istniała tylko w przeglądarce po stronie klienta i nie będzie starała się synchronizować z serwerem.
@@ -101,7 +101,7 @@ Template.errors.helpers({
### Tworzenie błędów
-wiemy jak wyświetlać błędy, ale potrzebujemy utworzyć kilka zanim będzie można cokolwiek zobaczyć. Błędy są najczęściej uaktywniane przez użytkowników wproadzających nowe dane, zatem będziemy sprawdzali błędy w callbacku tworzenia postów i wyświetlać wiadomość dla jakichkolwiek błędów, które powstają.
+wiemy jak wyświetlać błędy, ale potrzebujemy utworzyć kilka zanim będzie można cokolwiek zobaczyć. Błędy są najczęściej uaktywniane przez użytkowników wprowadzających nowe dane, zatem będziemy sprawdzali błędy w callbacku tworzenia postów i wyświetlać wiadomość dla jakichkolwiek błędów, które powstają.
Dodatkowo, jeżeli otrzymamy błąd `302` (który oznacza, że post o tym samym URL już istnieje), przekierujemy użytkownika to bieżącego posta. Otrzymamy `_id` bieżącego posta z `error.details` (pamiętaj, że przekazaliśmy `_id` posta jako trzeci parametr do `details` naszej klasy `Errors` w rozdziale 7).
@@ -183,7 +183,7 @@ Jest to miejsce, w którym przyda się zmienna `seen` (widziany). Musimy się up
Aby tego dokonać, użyjemy funkcji `Meteor.defer()`. Funkcja ta przekazuje Meteorowi, aby uruchomić callback "zaraz po tym" co dzieje się w tej chwili. Jeżeli pomoże to zrozumieć, możesz pomyśleć, że `defer()` to jak przekazanie przeglądarce aby poczekać 1 milisekundę przed kontynuowaniem pracy.
-Osiągneliśmy to, że Meteor ustawia `seen` na `true` 1 milisekundę po renderowaniu szablonu `template`. Ale czy pamiętasz jak wspomnieliśmy, że przekierowanie dzieje się natychmiastowo? Oznacza to, że mechanizm przekierowania zostanie uruchomiony przed callbackiem `defer`, który nigdy nie będzie miał możliwości na wykonanie.
+Osiągnęliśmy to, że Meteor ustawia `seen` na `true` 1 milisekundę po renderowaniu szablonu `template`. Ale czy pamiętasz jak wspomnieliśmy, że przekierowanie dzieje się natychmiastowo? Oznacza to, że mechanizm przekierowania zostanie uruchomiony przed callbackiem `defer`, który nigdy nie będzie miał możliwości na wykonanie.
Jest to dokładnie to, co chcieliśmy osiągnąć: jeżeli nie został wykonany, nasz błąd nie zostanie zaznaczony jako `widziany`, co oznacza, że nie będzie usunięty, co również oznacza, że pojawi się na stronie na którą użytkownik został przekierowany, dokładnie tak, jak chcieliśmy!
@@ -216,6 +216,6 @@ Callback `rendered` jest wywołany ponownie po renderowaniu szablonu w przegląd
Callback `rendered` szablonu jest wywoływany za każdym razem po renderowaniu szablonu w przeglądarce. Zawiera to oczywiście pierwsze renderowanie, gdy pojawia się na ekranie, ale warto zapamiętać, że callback będzie także wywoływany za każdym razem, gdy szablon jest renderowany ponownie tj. za każdym razem, gdy jego dane ulegną zmianie.
-Callback `rendered` jest ogolnie wywoływany przynajmniej dwukrotnie: za pierwszym razem, gdy aplikakcja zostaje załadowana i za drugim razem gdy dane kolekcji zostają wczytane. Powinieneś być zatem ostrożny przy wstawianiu kodu, który nie powinien zostać uruchomiony dwukrotnie (np. alert, czy kod śledzący zdarzenia na stronie).
+Callback `rendered` jest ogólnie wywoływany przynajmniej dwukrotnie: za pierwszym razem, gdy aplikacja zostaje załadowana i za drugim razem gdy dane kolekcji zostają wczytane. Powinieneś być zatem ostrożny przy wstawianiu kodu, który nie powinien zostać uruchomiony dwukrotnie (np. alert, czy kod śledzący zdarzenia na stronie).
<% end %>
diff --git a/09s-creating-a-meteorite-package.md.erb b/09s-creating-a-meteorite-package.md.erb
index e218f9c..fdc5add 100644
--- a/09s-creating-a-meteorite-package.md.erb
+++ b/09s-creating-a-meteorite-package.md.erb
@@ -181,7 +181,7 @@ Package.on_test(function(api) {
<%= scommit "9-5-2", "Dodanie testów do pakietu." %>
-Nstępnie można uruchomić testy za pomocą:
+Następnie można uruchomić testy za pomocą:
~~~bash
$ meteor test-packages errors
@@ -199,7 +199,7 @@ Po pierwsze, musimy dodać plik `smart.json`, aby przekazać ważne szczegóły
~~~json
{
"name": "errors",
- "description": "Szablon do wyświetlania błędów aplikacji uźytkownikowi.",
+ "description": "Szablon do wyświetlania błędów aplikacji użytkownikowi.",
"homepage": "https://github.com/tmeasday/meteor-errors",
"author": "Tom Coleman ",
"version": "0.1.0",
diff --git a/10-comments.md.erb b/10-comments.md.erb
index bcf2f6d..fa2ccb6 100644
--- a/10-comments.md.erb
+++ b/10-comments.md.erb
@@ -105,7 +105,7 @@ Router.configure({
Zauważ, że aby uruchomić powyższy kod ustawiający dane początkowe, będziesz musiał wykonać `meteor reset` aby wyczyścić bazę danych. Po resecie nie zapomnij utworzyć nowego konta i się do niego zalogować!
-Na początek stworzyliśmy kilku (całkowicie wymyślonych) użytowników, wstawiliśmy ich dane do bazy danych i użyliśmy ich `id` aby później pobrać ich z bazy. Następnie dodaliśmy komentarz każdemu użytkownikowi do pierwszego posta, łącząc komentarz do posta (z `postId`) i użytkownika (z `userId`). Dodaliśmy także datę dodania posta i jego treść, jak również zdenormalizowane pole `author` wskazujące na autora komentarza.
+Na początek stworzyliśmy kilku (całkowicie wymyślonych) użytkowników, wstawiliśmy ich dane do bazy danych i użyliśmy ich `id` aby później pobrać ich z bazy. Następnie dodaliśmy komentarz każdemu użytkownikowi do pierwszego posta, łącząc komentarz do posta (z `postId`) i użytkownika (z `userId`). Dodaliśmy także datę dodania posta i jego treść, jak również zdenormalizowane pole `author` wskazujące na autora komentarza.
Również zmieniliśmy router, aby obsługiwał zarówno posty jak i komentarze.
@@ -318,7 +318,7 @@ Meteor.methods({
<%= caption "collections/comments.js" %>
<%= highlight "3~25" %>
-<%= commit "10-3", "Utworzony formularz do dodawania koentarzy." %>
+<%= commit "10-3", "Utworzony formularz do dodawania komentarzy." %>
Nie dzieje się tutaj nic szczególnego, jest tu proste sprawdzenie, że użytkownik jest zalogowany, komentarz ma treść i że jest połączony z postem.
diff --git a/10s-denormalization.md.erb b/10s-denormalization.md.erb
index 31848ee..dc8ce10 100644
--- a/10s-denormalization.md.erb
+++ b/10s-denormalization.md.erb
@@ -20,7 +20,7 @@ Jednakże normalne podejście do tego problemu ma także swoje minusy: bez pola
### Specjalna publikacja
-*Byłoby* również możliwe utworzenie specjalnej publikacji, która wysyła wyłącznie liczniki komenterzy, którymi jesteśmy zainteresowani (tj. liczników komentarzy które aktualnie widzimy, za pomocą zapytań aggregate po stronie serwera).
+*Byłoby* również możliwe utworzenie specjalnej publikacji, która wysyła wyłącznie liczniki komentarzy, którymi jesteśmy zainteresowani (tj. liczników komentarzy które aktualnie widzimy, za pomocą zapytań aggregate po stronie serwera).
Jest to jednak warte rozważenia, jeżeli stopień skomplikowania kodu takiej publikacji byłby mniejszy, niż wysiłek włożony w denormalizację...
@@ -32,9 +32,9 @@ Oczywiście takie rozważania są specyficzne dla konkretnych zastosowań: jeże
Jeżeli jesteś zaawansowanym użytkownikiem Mongo, mogłeś się zdziwić, że utworzyliśmy drugą kolekcję tylko dla komentarzy: dlaczego po prostu nie wstawiać komentarzy do listy znajdującej się w dokumencie posta?
-Okazuje się, że dla wielu narzędzi które oferuje Meteor, pracowuje się lepiej gdy operujemy na poziomie kolekcji. Na przykład:
+Okazuje się, że dla wielu narzędzi które oferuje Meteor, pracuje się lepiej gdy operujemy na poziomie kolekcji. Na przykład:
-1. Helper `{{#each}}` jest bardzo wydajny, jeżeli chodzi o iterację po kursorze (wyniku `collection.find()`). Nie jest to prawdą, gdy iteruje po tablicy objektów w środku większego obiektu.
+1. Helper `{{#each}}` jest bardzo wydajny, jeżeli chodzi o iterację po kursorze (wyniku `collection.find()`). Nie jest to prawdą, gdy iteruje po tablicy obiektów w środku większego obiektu.
2. `allow` i `deny` operują na poziomie dokumentu, ułatwia to potwierdzenie, że jakiekolwiek modyfikacje pojedyńczych komentarzy są poprawne i obsługa byłaby bardziej skomplikowana na poziomie posta.
3. DDP operuje na poziomie atrybutów dokumentu najwyższego poziomu -- oznacza to, że jeżeli `comments` byłyby własnością `post`, za każdym razem, gdy komentarz byłby dodawany do posta, serwer musiałby wysyłać całą uaktualnioną listę komentarzy tego posta do wszystkich podłączonych klientów.
4. Publikacje i subskrypcje można o wiele łatwiej kontrolować na poziomie dokumentów. Na przykład, jeżeli chcielibyśmy dzielić na strony komentarze do posta, byłoby to trudne do zrealizowania gdyby komentarze nie były umieszczone w odrębnej kolekcji.
diff --git a/11-notifications.md.erb b/11-notifications.md.erb
index f7e64fc..b20ec98 100644
--- a/11-notifications.md.erb
+++ b/11-notifications.md.erb
@@ -7,11 +7,11 @@ contents: Jak dodać kolekcję powiadomienia aby powiadamiać użytkowników o d
paragraphs: 25
---
-Teraz kiedy użykownicy mogą komentować na posty innych użytkowników, byłoby dobrze móc powiadamiać o rozpoczętej konwersacji.
+Teraz kiedy użytkownicy mogą komentować na posty innych użytkowników, byłoby dobrze móc powiadamiać o rozpoczętej konwersacji.
Aby tego dokonać, damy znać właścicielowi posta, że dodano komentarz i dostarczymy mu link, aby mógł go przeczytać.
-Jest to funkcjonalność, w której Meteor naprawdę błyszczy: ponieważ wszystko w Meteorze domyślnie dzieje się w czasie rzeczywistym, będziemy wyświetlali te notyfikacje _natychmiastowo_. Nie chcemy czekać na użytownika, aby odświeżył stronę czy sprawdzał to w jakikolwiek sposób, możemy po prostu pokazać nową notyfikację bez potrzeby pisania żadnego dodatkowego kodu.
+Jest to funkcjonalność, w której Meteor naprawdę błyszczy: ponieważ wszystko w Meteorze domyślnie dzieje się w czasie rzeczywistym, będziemy wyświetlali te notyfikacje _natychmiastowo_. Nie chcemy czekać na użytkownika, aby odświeżył stronę czy sprawdzał to w jakikolwiek sposób, możemy po prostu pokazać nową notyfikację bez potrzeby pisania żadnego dodatkowego kodu.
### Tworzenie powiadomień
@@ -163,7 +163,7 @@ I utworzyć szablony `notifications` i `notification` (będą dzieliły wspólny
Jak widać, zaplanowaliśmy, że każde powiadomienie ma zawierać link do posta, do którego dodano komentarz i nazwę użytkownika, który dodał komentarz.
-Następnie, musimy się upewnić, że zaznaczyliśmy prawidłową listę powiadomień w naszym managerze i uaktualnić powiadomienie jako `czytaj` gdy użytkownik kliknie na link, na który wzkazują.
+Następnie, musimy się upewnić, że zaznaczyliśmy prawidłową listę powiadomień w naszym managerze i uaktualnić powiadomienie jako `czytaj` gdy użytkownik kliknie na link, na który wskazują.
~~~js
Template.notifications.helpers({
@@ -191,7 +191,7 @@ Template.notification.events({
<%= commit "11-2", "Display notifications in the header." %>
-Możesz myśleć, że powiadomienia nie różnią się zbytnio od błedów i masz rację. Ich struktura jest podobna. Jest jednak jedna duża różnica między nimi: utworzyliśmy odpowiednią synchronizowaną kolekcję miedzy klientem i serwerem. Oznacza to, że nasze powiadomienia są *zapamiętywane* i tak długo jak używamy tego samego konta, będzie istniało po odświeżeniach przeglądarki i między różnymi urządzeniami, które przeglądają stronę.
+Możesz myśleć, że powiadomienia nie różnią się zbytnio od błędów i masz rację. Ich struktura jest podobna. Jest jednak jedna duża różnica między nimi: utworzyliśmy odpowiednią synchronizowaną kolekcję miedzy klientem i serwerem. Oznacza to, że nasze powiadomienia są *zapamiętywane* i tak długo jak używamy tego samego konta, będzie istniało po odświeżeniach przeglądarki i między różnymi urządzeniami, które przeglądają stronę.
Wypróbuj to: otwórz drugą przeglądarkę (powiedzmy Firefox), utwórz nowe konto użytkownika, i skomentuj posta, którego utworzyłeś za pomocą głównego konta (które zostawiłeś otwarte w Chrome). Powinieneś zobaczyć mniej więcej to:
@@ -244,4 +244,4 @@ Teraz, gdy sprawdzimy dwie niezależnie uruchomione przeglądarki, powinniśmy z
Tak naprawdę, lista publikacji powinna zmieniać się nawet po wylogowaniu i ponownym zalogowaniu się do aplikacji. Dzieje się tak dlatego, ponieważ publikacje po każdej zmianie konta użytkownika są publikowane ponownie.
-Nasza aplikacja staje się coraz bardziej funkcjonalna i im więcej użytkowników przyłącza się i zaczyna publikować linki, tym większe ryzyko nieskończonie ładującej się stronie głównej. Zajmiemy się tym w następnym rozdziale przez zaimplementowanie dzielenia dokumentu na strony.
+Nasza aplikacja staje się coraz bardziej funkcjonalna i im więcej użytkowników przyłącza się i zaczyna publikować linki, tym większe ryzyko nieskończenie ładującej się stronie głównej. Zajmiemy się tym w następnym rozdziale przez zaimplementowanie dzielenia dokumentu na strony.
diff --git a/11s-advanced-reactivity.md.erb b/11s-advanced-reactivity.md.erb
index 5c56c13..8393583 100644
--- a/11s-advanced-reactivity.md.erb
+++ b/11s-advanced-reactivity.md.erb
@@ -10,7 +10,7 @@ paragraphs: 29
Rzadko zachodzi potrzeba napisania samemu kodu do śledzenia zależności, ale z pewnością warto zrozumieć ten mechanizm aby później móc śledzić sposób jego działania.
-Wyobraź sobie, że chcemy śledzić liczbę przyjaciół danego użytkownika Facebooka, którzy 'polubili' każdy post na Microscope. Przyjmijmy, że już zaimplementowaliśmy logowanie użytkownika za pomocą Facebooka, wywołaliśmy odpowiednie funkcje API i parsowaliśmy odpowienie dane. Mamy asynchroniczną funkcję po stronie klienta, która zwraca liczbę polubień posta, `getFacebookLikeCount(user, url, callback)`.
+Wyobraź sobie, że chcemy śledzić liczbę przyjaciół danego użytkownika Facebooka, którzy 'polubili' każdy post na Microscope. Przyjmijmy, że już zaimplementowaliśmy logowanie użytkownika za pomocą Facebooka, wywołaliśmy odpowiednie funkcje API i parsowaliśmy odpowiednie dane. Mamy asynchroniczną funkcję po stronie klienta, która zwraca liczbę polubień posta, `getFacebookLikeCount(user, url, callback)`.
Ważną sprawą wartą zapamiętania jest, w jakim stopniu taka funkcja jest *niereaktywna* i w jakim stopniu nie jest czasu rzeczywistego. Funkcja wywołuje żądanie HTTP do Facebooka, odczyta trochę danych i udostępni je aplikacji w asynchronicznym callbacku. Nie wywoła się ponownie sama gdy liczba polubień ulegnie zmianie i nasze UI nie uaktualni się podczas zmiany danych.
@@ -50,7 +50,7 @@ Możesz myśleć o komputacji, jako o sekcji kodu, która "troszczy się" o reak
### Przemiana zwykłej zmiennej w funkcję reaktywną
-Aby zmienić naszą zmienną `currentLikeCount` w reaktywne źródło danych, musimy śledziź wszystkie komputacje, które używają jej w zależności. Wymaga to zmiany ze zmiennej na funkcję (która zwróci wartość):
+Aby zmienić naszą zmienną `currentLikeCount` w reaktywne źródło danych, musimy śledzić wszystkie komputacje, które używają jej w zależności. Wymaga to zmiany ze zmiennej na funkcję (która zwróci wartość):
~~~js
var _currentLikeCount = 0;
@@ -76,7 +76,7 @@ Meteor.setInterval(function() {
~~~
<%= highlight "1~7,14~17" %>
-Co osiągneliśmy to ustawienie zależności `_currentLikeCountListeners`, która śledzi wszystkie komputacje w której użyty był `currentLikeCount()`. Gdy wartość `_currentLikeCountListeners` ulega zmianie, wołamy funkcję `changed()` na tej zależności, która unieważnia wszystkie śledzone komputacje.
+Co osiągnęliśmy to ustawienie zależności `_currentLikeCountListeners`, która śledzi wszystkie komputacje w której użyty był `currentLikeCount()`. Gdy wartość `_currentLikeCountListeners` ulega zmianie, wołamy funkcję `changed()` na tej zależności, która unieważnia wszystkie śledzone komputacje.
Wtedy komputacje mogą kontynuować i reagować na zmiany odpowiednio do każdego przypadku. W przypadku komputacji szablonu oznacza to, że szablon się renderuje.
@@ -92,7 +92,7 @@ Po pierwsze, helper `{{#constant}}` *wyłącza* reaktywność. Jakiekolwiek dane
Po drugie, helper `{{#isolate}}` ustawia *nową* komputację w środku szablonu. Innymi słowy ma taki sam efekt jak zagnieżdżony szablon.
-Zatem jeżeli jeden z reaktywnych źródeł danych będący w obrębie bloku isolate zmieni się, izolowany obszer ulegnie odświeżeniu, ale reszta zawierającego go szablonu nie. Jednakże gdy szablon zewnętrzny się odświeży, odświeży się także izolowany obszar.
+Zatem jeżeli jeden z reaktywnych źródeł danych będący w obrębie bloku isolate zmieni się, izolowany obszar ulegnie odświeżeniu, ale reszta zawierającego go szablonu nie. Jednakże gdy szablon zewnętrzny się odświeży, odświeży się także izolowany obszar.
### Porównianie zależności do Angular
@@ -118,9 +118,9 @@ Oczywiście tak rzadko, jak ustawia się komputacje w Meteorze, zarówno w Angul
Po zmianie takiej reaktywnej zmiennej, musi być zawołana `scope.$apply()`. Funkcja ta przechodzi przez każdego obserwatora `scope` ale wywołuje wyłącznie funkcje obserwujące obserwatorów, których *zmieniła się* wartość wyrażenia.
-Zatem `scope.$apply()` jest podobne do `dependency.changed()`, z tym wyjątkiem, że działa z poziomu `scope` raczej niż daje pełną kontrolę nad tym, które funkcje oberwujące mają być przeliczone. Mówiąc o tym, ten lekki brak całkowitej kontroli daje Angular możliwość bycia sprytnym i wydajnym w sposobie w jakim ustalone zostaje które funkcje obserwujące mają być przeliczone.
+Zatem `scope.$apply()` jest podobne do `dependency.changed()`, z tym wyjątkiem, że działa z poziomu `scope` raczej niż daje pełną kontrolę nad tym, które funkcje obserwujące mają być przeliczone. Mówiąc o tym, ten lekki brak całkowitej kontroli daje Angular możliwość bycia sprytnym i wydajnym w sposobie w jakim ustalone zostaje które funkcje obserwujące mają być przeliczone.
-Z Angular, kod naszej funkcji`getFacebookLikeCount()` wyglądałby mniej więcej tak:
+Z Angular, kod naszej funkcji `getFacebookLikeCount()` wyglądałby mniej więcej tak:
~~~js
Meteor.setInterval(function() {
diff --git a/12-pagination.md.erb b/12-pagination.md.erb
index b6f993e..7b2443c 100644
--- a/12-pagination.md.erb
+++ b/12-pagination.md.erb
@@ -57,7 +57,7 @@ Po wywołaniu komendy `meteor reset` powinieneś zobaczyć coś podobnego do:
### Nieskończone dzielenie dokumentu na strony.
-Zaimplementujemy proste "nieskończone" dzielenie dokumentu na strony. Oznacza to, że wyświetlimy, przyjmijmy 10 postów na ekranie z linkem âpokaż więcejâ umieszczonym pod spodem. Kliknięcie na ten link doda kolejne 10 postów do listy i tak dalej *w nieskończoność*. Oznacza to, że możemy kontrolować nasz cały system dzielenia na strony przez pojedyńczy parametr zawierający liczbę postów do wyświetlenia na ekranie.
+Zaimplementujemy proste "nieskończone" dzielenie dokumentu na strony. Oznacza to, że wyświetlimy, przyjmijmy 10 postów na ekranie z linkem âpokaż więcejâ umieszczonym pod spodem. Kliknięcie na ten link doda kolejne 10 postów do listy i tak dalej *w nieskończoność*. Oznacza to, że możemy kontrolować nasz cały system dzielenia na strony przez pojedynczy parametr zawierający liczbę postów do wyświetlenia na ekranie.
Teraz będziemy musieli znaleźć sposób na przekazanie serwerowi o tym parametrze, tak aby wiedział ile postów wysłać klientowi. Tak się składa, że subskrybujemy już publikację `posts` w routerze, więc wykorzystamy to i pozwolimy routerowi na kontrolę nad dzieleniem na strony.
@@ -145,7 +145,7 @@ W naszym przypadku, jest to stosunkowo nieszkodliwe, ponieważ wszystko, co uży
Nie powinno się jednak używać tego wzorca podczas zapisywania prywatnych danych na niepublikowanych polach, ponieważ użytkownik odpowiednio modyfikując opcję `fields` mógłby mieć do nich dostęp i powinieneś również unikać używania go dla argumentu selektora `find()` dla tych samych powodów bezpieczeństwa.
-Bardziej bezpieczne byłoby przekazywanie pojedyńczych parametrów zamiast całego obiektu, aby upewnić się że masz pełną kontrolę nad dostępem do danych:
+Bardziej bezpieczne byłoby przekazywanie pojedynczych parametrów zamiast całego obiektu, aby upewnić się że masz pełną kontrolę nad dostępem do danych:
~~~js
Meteor.publish('posts', function(sort, limit) {
@@ -157,7 +157,7 @@ Meteor.publish('posts', function(sort, limit) {
Teraz kiedy subskrybujemy posty na poziomie konkretnej ścieżki URL, miałoby sens ustawić kontekst danych w tym samym miejscu. Odejdźmy trochę od poprzedniego schematu i zmieńmy funkcję `data` w ten sposób, aby zwracała obiekt JavaScript zamiast zwracania kursora. To pozwala na utworzenia *nazwanego* kontekstu danych, który nazwiemy `posts`.
-Oznacza to, że zamiast pośredniego dostępu jako `this` w środku szabklonu, nasz kontekst danych będzie dostępny jako `posts`. Oprócz tej małej zmiany, kod powinien wyglądać znajomo:
+Oznacza to, że zamiast pośredniego dostępu jako `this` w środku szablonu, nasz kontekst danych będzie dostępny jako `posts`. Oprócz tej małej zmiany, kod powinien wyglądać znajomo:
~~~js
Router.map(function() {
@@ -181,7 +181,7 @@ Router.map(function() {
<%= caption "lib/router.js" %>
<%= highlight "8~13" %>
-Teraz skoro ustawiamy kontekst danych na poziomie routera możemy bezpiecznie pozbyć się nagłówka szablonu `posts` w pliku `posts_lists.js`. Skoro nazwaliśmy kontekst danych `posts` (tak samo jak helper), nie podrzebujemy nawet dotykać szablonu `postList`!
+Teraz skoro ustawiamy kontekst danych na poziomie routera możemy bezpiecznie pozbyć się nagłówka szablonu `posts` w pliku `posts_lists.js`. Skoro nazwaliśmy kontekst danych `posts` (tak samo jak helper), nie potrzebujemy nawet dotykać szablonu `postList`!
Zbierzmy wszystko razem. Oto jak powinien wyglądać nowy i poprawiony kod `router.js`:
@@ -217,7 +217,7 @@ Router.map(function() {
<%= commit "12-2", "Zmieniona trasa postsList pozwalająca na ograniczenie liczby postów." %>
-Wypróbujmy nowy system dzielenia postów. Mamy teraz możliwość wyświetlania dowolnej liczby postów na stronie głównej za pomocą zmiany parametru URL. Przykładowo, sþróbuj odwiedzić `http://localhost:3000/3`. Powinieneś ujrzeć coś podobnego do:
+Wypróbujmy nowy system dzielenia postów. Mamy teraz możliwość wyświetlania dowolnej liczby postów na stronie głównej za pomocą zmiany parametru URL. Przykładowo, spróbuj odwiedzić `http://localhost:3000/3`. Powinieneś ujrzeć coś podobnego do:
<%= screenshot "12-2", "Kontrola liczby postów na stronie głównej. " %>
@@ -237,11 +237,11 @@ Wróćmy do poprzedniego przykładu. Publikujemy posty od 10 do 20 z kolekcji `P
Jednym rozwiązaniem byłoby publikowanie 10 postów po stronie serwera i następnie wywoływanie `Posts.find()` po stronie klienta, aby przechwycić *wszystkie* publikowane posty.
-Działa to, gdy masz tylko jedną subskrypcję. Ale co się stanie jeżeli będziesz miał więcej niż jedną subskrypcję postów, a stanie się to wrótce?
+Działa to, gdy masz tylko jedną subskrypcję. Ale co się stanie jeżeli będziesz miał więcej niż jedną subskrypcję postów, a stanie się to wkrótce?
-Powiedzmy, że jedna subskrypcja pyta o posty od 10 do 20, a inna o 30 do 40. Masz teraz 20 postów załadowane po stronie klenta, nie mając pojęcia które należą do odpowiedniej subskrypcji.
+Powiedzmy, że jedna subskrypcja pyta o posty od 10 do 20, a inna o 30 do 40. Masz teraz 20 postów załadowane po stronie klienta, nie mając pojęcia które należą do odpowiedniej subskrypcji.
-Ze względu na te wszytkie kwestie, tradycyjne dzielenie na dokumetu na strony nie ma większego sensu przy korzystaniu z Meteora.
+Ze względu na te wszystkie kwestie, tradycyjne dzielenie na dokumenty na strony nie ma większego sensu przy korzystaniu z Meteora.
<% end %>
@@ -249,7 +249,7 @@ Ze względu na te wszytkie kwestie, tradycyjne dzielenie na dokumetu na strony n
Mogłeś zauważyć, że powtórzyliśmy dwukrotnie linię `var limit = parseInt(this.params.postsLimit) || 5;`. Dodatkowo, numer zakodowany numer “5†nie jest idealny. To nie koniec świata, ale ponieważ zawsze warto stosować się do zasady DRY (Don't Repeat Yourself), sprawdźmy jak możemy zrobić refaktoryzację kodu.
-Wprowadźmy nową funkcję Iron Routera, *Kontrolerow ścieżki*. Kontroler ścieżki umożliwia na zebranie razem funkcjonalności w jeden spójny pakiet, z którego może dziedziczyć jakakolwiek ścieżka. Teraz użyjemy kontrolera do pojedyńczej ścieżki, a w następnym rozdziale dowiesz się jak pomocna będzie ta funkcjonalność.
+Wprowadźmy nową funkcję Iron Routera, *Kontrolerow ścieżki*. Kontroler ścieżki umożliwia na zebranie razem funkcjonalności w jeden spójny pakiet, z którego może dziedziczyć jakakolwiek ścieżka. Teraz użyjemy kontrolera do pojedynczej ścieżki, a w następnym rozdziale dowiesz się jak pomocna będzie ta funkcjonalność.
~~~js
PostsListController = RouteController.extend({
@@ -292,11 +292,11 @@ Ostatnią rzeczą do zrobienia jest zmiana ścieżki `postsList` prowadzącą do
### Dodawanie linku 'Pokaż więcej'
-Mamy teraz działające dzielenie dokumentu na strony i kod wygląda dobrze. Jest tylko jeden problem: nie ma innego sposobu na *używanie* tego dzielenia na strony niż ręczna zmiana URL. Zdecydowanie nie polepsza to używania go, więc weźmy się do pracym aby go polepszyć.
+Mamy teraz działające dzielenie dokumentu na strony i kod wygląda dobrze. Jest tylko jeden problem: nie ma innego sposobu na *używanie* tego dzielenia na strony niż ręczna zmiana URL. Zdecydowanie nie polepsza to używania go, więc weźmy się do pracy aby go polepszyć.
To, co chcemy osiągnąć jest wystarczająco proste. Dodamy przycisk *wczytaj więcej* na dole listy postów, co zwiększy o 5 liczbę postów wyświetlanych po każdym kliknięciu. Więc jeżeli jesteśmy na URL `http://localhost:3000/5`, kliknięcie na *wczytaj więcej* powinno przenieść na `http://localhost:3000/10`. Jeżeli zdołałeś przeczytać do te pory tą książkę, powinieneś dać sobie radę z prostą arytmetyką!
-Tak, jak poprzednio, dodamy logikę dzielenia na strony do naszej ścieżki. Pamietasz, gdy jawnie nazwaliśmy kontekst danych zamiast używać anonimowego kursora? Nie ma zasady, która mówiłaby, że funkcja `data` może przekazywać jedynie kursory, więc użyjemy tej samej techniki aby wygenerować przycisk *wczytaj więcej*.
+Tak, jak poprzednio, dodamy logikę dzielenia na strony do naszej ścieżki. Pamiętasz, gdy jawnie nazwaliśmy kontekst danych zamiast używać anonimowego kursora? Nie ma zasady, która mówiłaby, że funkcja `data` może przekazywać jedynie kursory, więc użyjemy tej samej techniki aby wygenerować przycisk *wczytaj więcej*.
~~~js
PostsListController = RouteController.extend({
@@ -339,7 +339,7 @@ Wiemy, e `this.limit()` zwraca bieżącą liczbę postów, którą chcielibyśmy
Z drugiej strony, `this.posts()` odnosi się do bieżącego kursora, zatem `this.posts.fetch().length` odnosi się do liczby postów znajdujących się w obrębie danego kursora.
-Zatem, jeżeli pytamy o `n` postów i dostajemy `n`, będziemy pokazywali przycisk *wczytaj więcej*. Jeżeli zapytamy o `n` i dostaniemy *mniej* niż `n`, oznacza to, że osiągneliśmy limit i nie powinniśmy wyświetlać tego przycisku.
+Zatem, jeżeli pytamy o `n` postów i dostajemy `n`, będziemy pokazywali przycisk *wczytaj więcej*. Jeżeli zapytamy o `n` i dostaniemy *mniej* niż `n`, oznacza to, że osiągnęliśmy limit i nie powinniśmy wyświetlać tego przycisku.
Niestety nie ma prostych rozwiązań tego problemu, z tego względu zostaniemy na razie z tą niezbyt perfekcyjną implementacją.
diff --git a/13-voting.md.erb b/13-voting.md.erb
index 29e9d16..3e54c9b 100644
--- a/13-voting.md.erb
+++ b/13-voting.md.erb
@@ -7,7 +7,7 @@ contents: jak zbudować system głosowania na posty użytkowników.|jak oceniać
paragraphs: 49
---
-Poniewaź nasza strona staje się coraz bardziej popularna, znajdowanie najlepszych linków stanie się szybko coraz bardziej skomplikowane. Z tego względu potrzebujemy zbudować system oceniania postów.
+Ponieważ nasza strona staje się coraz bardziej popularna, znajdowanie najlepszych linków stanie się szybko coraz bardziej skomplikowane. Z tego względu potrzebujemy zbudować system oceniania postów.
Moglibyśmy zbudować skomplikowany system oceniania używając karmy, zanikającej w miarę upływu czasu punktacji i wielu różnych zasad (większość z nich została zaimplementowana w Telescope](http://telesc.pe), większym bracie Microscope). Dla potrzeb naszej aplikacji użyjemy jednak czegoś prostszego i będziemy oceniać posty przez liczbę głosów jakie otrzymały.
@@ -267,7 +267,7 @@ Zmieniamy klasę z `.upvote` do `.upvotable`, więc nie zapomnij również zmien
<%= commit "13-2", "Ściemnienie przycisku do głosowania gdy nie zalogowany / już zagłosowano." %>
-Następnie, możesz zauważyć, że posty z jednym głosem są oznaczone jako "1 vote**s**" (jeden głos) więc spędźmy trochę czasu na poprawnej odmianie tych etykiet. Odmiana w liczbie mnogiej może być skomplikowana, ale na teraz zróbmy to w sposóp uproszczony. Zaimplementujemy ogólną funkcję pomocniczą szablonu (helper) , który będzie można użyć w dowolnym miejscu:
+Następnie, możesz zauważyć, że posty z jednym głosem są oznaczone jako "1 vote**s**" (jeden głos) więc spędźmy trochę czasu na poprawnej odmianie tych etykiet. Odmiana w liczbie mnogiej może być skomplikowana, ale na teraz zróbmy to w sposób uproszczony. Zaimplementujemy ogólną funkcję pomocniczą szablonu (helper) , który będzie można użyć w dowolnym miejscu:
~~~js
Handlebars.registerHelper('pluralize', function(n, thing) {
@@ -314,7 +314,7 @@ Prowadzi to do dwóch problemów. Pierwszy jest taki, że jest stosunkowo nieefe
2. Sprawdź, czy użytkownik już zagłosował.
3. Jeżeli nie, zagłosuj za pomocą użytkownika.
-Co się stanie, jeżeli ten sam użytkownik zagłosuje na ten sam post podczas wykonywania tego algortymu? W obecnej postaci umożliwia to zagłosowanie na ten sam post dwukrotnie. Na szczęście Mongo pozwala na połączenie kroków 1-3 w pojedyńczą komendę:
+Co się stanie, jeżeli ten sam użytkownik zagłosuje na ten sam post podczas wykonywania tego algortymu? W obecnej postaci umożliwia to zagłosowanie na ten sam post dwukrotnie. Na szczęście Mongo pozwala na połączenie kroków 1-3 w pojedynczą komendę:
~~~js
Meteor.methods({
@@ -343,7 +343,7 @@ Meteor.methods({
<%= commit "13-4", "Ulepszony algorytm głosowania." %>
-Powyżej wykonujemy polecenie "znajdź wszystkie posty z danym `id` na które ten użytkownik jeszcze nie zagłosował i uaktualnij je w ten sposób". Jeżeli użytkownik *jeszcze nie* zagłosował, wyszukane zostaną posty z danym `id`. Z drugiej strony, jeżeli użykownił *zagłosował*, wtedy zapytanie nie znajdzie żadnych dokumentów i w konsekwencji nic się nie wydarzy.
+Powyżej wykonujemy polecenie "znajdź wszystkie posty z danym `id` na które ten użytkownik jeszcze nie zagłosował i uaktualnij je w ten sposób". Jeżeli użytkownik *jeszcze nie* zagłosował, wyszukane zostaną posty z danym `id`. Z drugiej strony, jeżeli użytkownik *zagłosował*, wtedy zapytanie nie znajdzie żadnych dokumentów i w konsekwencji nic się nie wydarzy.
Jedynym minusem jest to, że nie możemy powiedzieć użytkownikowi, czy już zagłosował na dany post (ponieważ pozbyliśmy się zapytania do bazy danych, które to sprawdzało). Ale mimo wszystko powinien to zauważyć patrząc na wyłączony przycisk do głosowania w interfejsie użytkownika.
@@ -440,7 +440,7 @@ Router.map(function() {
<%= caption "lib/router.js" %>
<%= highlight "8,16,21~34,36~49" %>
-Zauważ, że mamy teraz więcej niż jedną trasę, wyjęliśmy logikę `nextPath` z kontrolera `PostListController` w `NewPostsListController` i `BestPostsListController`, ponieważ scieżka routingu będzie się różniła w obu przypadkach.
+Zauważ, że mamy teraz więcej niż jedną trasę, wyjęliśmy logikę `nextPath` z kontrolera `PostListController` w `NewPostsListController` i `BestPostsListController`, ponieważ ścieżka routingu będzie się różniła w obu przypadkach.
Dodatkowo, gdy sortujemy po liczbie głosów, mamy drugie sortowanie po czasie publikacji postów aby upewnić się, że sortowanie jest poprawne.
@@ -558,7 +558,7 @@ Template.header.helpers({
Aż do teraz nie używaliśmy tego konkretnego wzorca, ale zarówno jak każdy inny tag Handlebars, helper szablonu może także mieć parametry.
-I podczas, gdy oczywiście możesz przekazywać kontretne nazwane parametry do swojej funkcji, możesz także przekazać nieokreśloną liczbę anonimowych parametrów i mieć do nich dostęp w ciele funkcji za pomocą obiektu `arguments`.
+I podczas, gdy oczywiście możesz przekazywać konkretne nazwane parametry do swojej funkcji, możesz także przekazać nieokreśloną liczbę anonimowych parametrów i mieć do nich dostęp w ciele funkcji za pomocą obiektu `arguments`.
W tym ostatnim przypadku, prawdopodobnie będziesz chciał przekształcić obiekt `arguments` w zwykłą tablicę JavaScript i następnie wywołać `pop()` aby usunąć hash dodany na końcu przez Handlebars.
@@ -566,7 +566,7 @@ W tym ostatnim przypadku, prawdopodobnie będziesz chciał przekształcić obiek
Dla każdego elementu nawigacji, helper `activeRouteClass` przyjmuje listę nazw tras i następnie używa helpera `any()` biblioteki Underscore aby sprawdzić, czy jakakolwiek trasa przechodzi test (tj. czy odpowiadający jej URL jest równy aktualnej ścieżce).
-Jeżeli jakiekolwiek trasy są dopasowane do aktualnej ścieżki, `any()` zwróci `true`. Na samym końcu wykorzytamy wzorzec JavaScript o nazwie `boolean && string`, gdzie `false && myString` zwraca `false` ale `true && myString` zwraca `myString`.
+Jeżeli jakiekolwiek trasy są dopasowane do aktualnej ścieżki, `any()` zwróci `true`. Na samym końcu wykorzystamy wzorzec JavaScript o nazwie `boolean && string`, gdzie `false && myString` zwraca `false` ale `true && myString` zwraca `myString`.
<%= commit "13-6", "Dodane aktywne klasy do nagłówka strony." %>
diff --git a/13s-advanced-publications.md.erb b/13s-advanced-publications.md.erb
index 6032ce0..1a1ef87 100644
--- a/13s-advanced-publications.md.erb
+++ b/13s-advanced-publications.md.erb
@@ -14,13 +14,13 @@ Do tej pory powinieneś się zaznajomić ze sposobem działania publikacji i sub
W [rozdziale wprowadzającym publikacje i subskrypcje](/chapter/publications-and-subscriptions/) poznałeś niektóre ze wzorów stosowania publikacji i subskrypcji i nauczyłeś jak funkcja `_publishCursor` ułatwia ich implementacje podczas tworzenia własnych stron.
-Przypomnijmy sobie, co funkcja `publishCursor` faktycznie wykonuje: zbiera wszystkie dokumenty, które pasują do kursora i wysyła je do kolecji po stronie klienta która *ma tą samą nazwę*. Zauważ, że nazwa _publication_ nie jest w żaden sposób wymieniona.
+Przypomnijmy sobie, co funkcja `publishCursor` faktycznie wykonuje: zbiera wszystkie dokumenty, które pasują do kursora i wysyła je do kolekcji po stronie klienta która *ma tą samą nazwę*. Zauważ, że nazwa _publication_ nie jest w żaden sposób wymieniona.
Oznacza to, że możemy mieć _więcej niż jedną pulikację_ łączącą wersję jakichkolwiek kolekcji po stronie klienta i serwera.
Spotkaliśmy się już z tym wzorcem w [rozdziale Dzielenie dokumentu na strony](/chapter/pagination/), gdzie publikowaliśmy dzielony podzbiór wszystkich postów w dołączonych do bieżącego posta.
-Innym podobnym zastosowaniem publikacji jest publikacja *przeglądu* większego zbioru dokumentów, jak również szczegółów pojedyńczego elementu.
+Innym podobnym zastosowaniem publikacji jest publikacja *przeglądu* większego zbioru dokumentów, jak również szczegółów pojedynczego elementu.
<%= diagram "doublecollection", "Dwukrotne publikowanie kolekcji", "pull-center" %>
@@ -36,9 +36,9 @@ Meteor.publish('postDetail', function(postId) {
W momencie gdy klient subskrybuje powyższe dwie publikacje (używając `autorun` aby upewnić się, że właściwy `postId` jest wysyłany do subskrypcji `postDetail`), jego kolekcja `posts` jest uaktualniana danymi pochodzącymi z dwóch źródeł: listy tytułów i nazwisk autorów z pierwszej subskrypcji i pełnymi szczegółami posta z drugiej.
-Możesz zdać sobie sprawę, że post publikowany przez `postDetail` jest również publikowany przez `allPosts` (pomimo tego, że jedynie z podzbiorem jego danych). Jednakże, Meteor troszczey się o łączeniu pól i upewnienia się, żeby żaden post nie był duplikowany.
+Możesz zdać sobie sprawę, że post publikowany przez `postDetail` jest również publikowany przez `allPosts` (pomimo tego, że jedynie z podzbiorem jego danych). Jednakże, Meteor troszczy się o łączeniu pól i upewnienia się, żeby żaden post nie był duplikowany.
-Jest to bardzo duże ułatwienie, ponieważ w tym przypdaku gdy renderujemy listę streszczeń postów, mamy do czynienia z obiektami danych które mają tylko tyle danych do pokazania, ile potrzeba. Jednakże podczas renderowania strony dla pojedyńczego posta, mamy wszystkie potrzebne dane. Oczywiście musimy wziąć pod uwagę, żeby nie oczekiwać po stronie klenta dostępności wszystkich pól we wszystkich postach - jest to częste źródło nieporozumień i błędów.
+Jest to bardzo duże ułatwienie, ponieważ w tym przypadku gdy renderujemy listę streszczeń postów, mamy do czynienia z obiektami danych które mają tylko tyle danych do pokazania, ile potrzeba. Jednakże podczas renderowania strony dla pojedynczego posta, mamy wszystkie potrzebne dane. Oczywiście musimy wziąć pod uwagę, żeby nie oczekiwać po stronie klienta dostępności wszystkich pól we wszystkich postach - jest to częste źródło nieporozumień i błędów.
Należy odnotować, że nie jesteś ograniczony do zmieniających się właściwości dokumentu. Mógłbyś równie dobrze publikować te same własności w obu publikacjach ale uporządkować je w inny sposób.
@@ -57,13 +57,13 @@ Meteor.publish('bestPosts', function(limit) {
Powyżej przeczytałeś, że można publikować tą samą kolekcję wielokrotnie. Okazuje się, że można osiągnąć bardzo podobny rezultat za pomocą innego wzorca: stworzenie jednej publikacji i jej wielokrotną *subskrypcję*.
-W Microscope subskrybujemy publikację `posts` wielokrotnie, ale Iron Router zajmuje się tworzeniem i usuwaniem każdej z nich. Nie ma jednak przeciwskazań, aby *subskrybować* ją wiele razy.
+W Microscope subskrybujemy publikację `posts` wielokrotnie, ale Iron Router zajmuje się tworzeniem i usuwaniem każdej z nich. Nie ma jednak przeciwwskazań, aby *subskrybować* ją wiele razy.
Przykładowo, załóżmy, że chcemy wczytać zarówno najnowsze i najlepsze posty do pamięci równocześnie:
<%= diagram "subscribetwice", "Dwukrotna subskrypcja tej samej publikacji", "pull-center" %>
-Ustawiamy pojedyńczą publikację:
+Ustawiamy pojedynczą publikację:
~~~js
Meteor.publish('posts', function(options) {
@@ -82,13 +82,13 @@ Co dokładnie tu się dzieje? Każda przeglądarka otwiera *dwie* różne subskr
Każda subskrypcja dostarcza różne argumenty dla tej publikacji, ale zasadniczo za każdym razem (różny) zbiór dokumentów zostaje wydzielony z kolekcji `posts` i wysłany do kolekcji po stronie klienta.
-### Wiele kolekcji w pojedyńczej subskrypcji
+### Wiele kolekcji w pojedynczej subskrypcji
W przeciwieństwie do tradycyjnych relacyjnych baz danych takich jak MySQL, która korzysta z łączenia tabel *joins*, bazy danych NoSQL takie jak Mongo koncentrują się wyłącznie na *denormalizacji* i *wstawianiu*. Zobaczmy jak to działa w kontekście Meteora.
-Wybierzmy konkretny przykład. Dodaliśmy komentarze do postów i jak do tej pory byliśmy zadowoleni z zamieszczania komentarzy do pojedyńczych postów czytanych przez użytkownika.
+Wybierzmy konkretny przykład. Dodaliśmy komentarze do postów i jak do tej pory byliśmy zadowoleni z zamieszczania komentarzy do pojedynczych postów czytanych przez użytkownika.
-Jednakże, przyjmijmy, że chcielibyśmy pokazać komentarze do *wszystkich* postów na stronie początkowej (miejąc na uwadze, że te posty będą się zmieniały gdy będziemy je wyświetlali strona po stronie). Jest to dobry przykład dla którego powodem jest załączanie komentarzy w postach i tak naprawdę przyczyniło się to do tego, żebyśmy zdenormalizowali *liczniki* komentarzy.
+Jednakże, przyjmijmy, że chcielibyśmy pokazać komentarze do *wszystkich* postów na stronie początkowej (mając na uwadze, że te posty będą się zmieniały gdy będziemy je wyświetlali strona po stronie). Jest to dobry przykład dla którego powodem jest załączanie komentarzy w postach i tak naprawdę przyczyniło się to do tego, żebyśmy zdenormalizowali *liczniki* komentarzy.
Moglibyśmy oczywiście zawsze wstawiać komentarze do postów, pozbywając się kolekcji przechowującej komentarze (`Comments`). Ale jak widzieliśmy w rozdziale *Denormalizacja*, decydując się na to, pozbylibyśmy się dodatkowych korzyści pracy z osobnymi kolekcjami.
@@ -96,7 +96,7 @@ Okazuje się, że istnieje sztuczka, za pomocą której można wstawiać komenta
Przyjmijmy, że zarówno z naszą pierwszą stroną pokazującą listę postów, chcemy zasubkrybować listę najlepszych 2 komentarzy do każdego posta.
-Byłoby to trudne do realizacji z niezależną publikacją komentarzy, szczególnie gdyby lista postów była w jakiś sposób ograniczona (przymijmy, że do 10 ostatnich postów). Musielibyśmy napisać publikację, która wyglądała by mniej więcej w taki sposób:
+Byłoby to trudne do realizacji z niezależną publikacją komentarzy, szczególnie gdyby lista postów była w jakiś sposób ograniczona (przyjmijmy, że do 10 ostatnich postów). Musielibyśmy napisać publikację, która wyglądała by mniej więcej w taki sposób:
<%= diagram "multiplecollections", "Dwie kolekcje w jednej subskrypcji", "pull-center" %>
@@ -106,9 +106,9 @@ Meteor.publish('topComments', function(topPostIds) {
});
~~~
-Byłby to problem z punktu widzenia wydajności, ponieważ publikacja musiałaby być usuwana i ponownie tworzona za każdym razym, gdy zmienia się lista `topPostsIds`.
+Byłby to problem z punktu widzenia wydajności, ponieważ publikacja musiałaby być usuwana i ponownie tworzona za każdym razem, gdy zmienia się lista `topPostsIds`.
-Jest sposób na obejście tego. Możemy wykorzystać fakt, że możemy mieć nie tylko więcej niż jedną *publikację* dla pojedyńczej *kolekcji*, ale także więcej niż jedną *kolekcję* dla jednej *publikacji*:
+Jest sposób na obejście tego. Możemy wykorzystać fakt, że możemy mieć nie tylko więcej niż jedną *publikację* dla pojedynczej *kolekcji*, ale także więcej niż jedną *kolekcję* dla jednej *publikacji*:
~~~js
Meteor.publish('topPosts', function(limit) {
@@ -145,7 +145,7 @@ Meteor.publish('topPosts', function(limit) {
});
~~~
-Zwróć uwagę, że nie zwracami niczego w tej publikacjim ponieważ wysyłamy ręcznie wiadomości do `pod` kolekcji nas samych (korzystając z funkcji `.added()` i jej pochodnych). Z tego powodu nie musimy prosić `_publishCursor` o zrobienie tego dla nas przez zwrócenie kursora.
+Zwróć uwagę, że nie zwracamy niczego w tej publikacji ponieważ wysyłamy ręcznie wiadomości do `pod` kolekcji nas samych (korzystając z funkcji `.added()` i jej pochodnych). Z tego powodu nie musimy prosić `_publishCursor` o zrobienie tego dla nas przez zwrócenie kursora.
Od teraz za każdym razem gdy publikujemy posta, równocześnie publikujemy dwa najlepsze komentarze załączone do niego. I to wszystko za pomocą jednego wywołania subskrypcji!
@@ -157,13 +157,13 @@ Do czego możemy jeszcze wykorzystać nowo przyswojoną wiedzę? A więc, jeżel
<%= diagram "linkedcollections", "Jedna kolekcja dla dwóch subskrypcji", "pull-center" %>
-Jednym z powodów, dla którego chcielibyśmy to wykorzystać, jest *Dziedziczenie Pojedyńczej Tabeli*.
+Jednym z powodów, dla którego chcielibyśmy to wykorzystać, jest *Dziedziczenie Pojedynczej Tabeli*.
Przyjmijmy, że chcielibyśmy się odnieść do różnych typów obiektów z naszego posta. Każdy z nich przechowuje niektóre wspólne pola, ale różni się trochę treścią. Przykładowo, moglibyśmy budować silnik blogowy przypominający Tumblr, gdzie każdy post ma ID, datę utworzenia i tytuł; ale dodatkowo może także zawierać rysunek, video, link czy po prostu tekst.
-Moglibyśmy zapisywać wszystkie te obiekty w pojedyńczej kolekcji `'Resources'` po stronie serwera, używając atrybutu `type` aby określić jakim są typem obiektu (`video`, '`image`, `link` itd.).
+Moglibyśmy zapisywać wszystkie te obiekty w pojedynczej kolekcji `'Resources'` po stronie serwera, używając atrybutu `type` aby określić jakim są typem obiektu (`video`, '`image`, `link` itd.).
-Pomimo tego, że po stronie serwera istnieje pojedyńcza kolekcja `Resources`, moglibyśmy przekształcić ją w wiele kolekcji `Videos`, `Images`, itd. po stronie klienta używając sztuczki jak poniżej.
+Pomimo tego, że po stronie serwera istnieje pojedyncza kolekcja `Resources`, moglibyśmy przekształcić ją w wiele kolekcji `Videos`, `Images`, itd. po stronie klienta używając sztuczki jak poniżej.
~~~js
Meteor.publish('videos', function() {
diff --git a/14-animations.md.erb b/14-animations.md.erb
index 5f7212e..7a6f41a 100644
--- a/14-animations.md.erb
+++ b/14-animations.md.erb
@@ -13,7 +13,7 @@ Opanowaliśmy już głosowanie w czasie rzeczywistym, punktację i ranking. Nies
Zanim dojdziemy do prawdziwej zabawy (przemieszczania elementów na stronie), należy zrozumieć jak Meteor współpracuje z DOM (ang. Document Object Model -- kolekcją elementów HTML które składają się na zawartość strony).
-Główną zasadą o której należy pamiętać jest to, że elementy DOM *nie mogą się przemieszczać*. Mogą być wyłącznie usuwane i tworzone (miej na uwadze, że jest to ograniczenie DOM, a nie Meteora). Aby więc spowodawać iluzję zamiany elementów A i B Meteor usunie element B i wstawi całkiem nową kopię (B') przed elementem A.
+Główną zasadą o której należy pamiętać jest to, że elementy DOM *nie mogą się przemieszczać*. Mogą być wyłącznie usuwane i tworzone (miej na uwadze, że jest to ograniczenie DOM, a nie Meteora). Aby więc spowodować iluzję zamiany elementów A i B Meteor usunie element B i wstawi całkiem nową kopię (B') przed elementem A.
Nie ułatwia to animacji, ponieważ nie można po prostu animować elementu B na nową pozycję, ponieważ B zniknie zaraz po przerenderowaniu strony (co jak wiemy dzieje się natychmiastowo dzięki reaktywności). Zamiast tego należy animować nowo stworzony B', który przemieszcza się z początkowej pozycji B' do nowej pozycji przed elementem A.
@@ -56,7 +56,7 @@ Aby animować posty, które są zamieniane kolejnością na stronie, musimy wej
Elementy na stronie domyślnie używają **statycznego** pozycjonowania. Statycznie pozycjonowane elementy naturalnie wpasowują się w stronę i ich współrzędne nie mogą być zmieniane lub animowane.
-**Względne** pozycjonowanie oznacza z innej strony, że element także jest naturanie wpasowany w stronę, ale może być umieszczony z przesunięcięm *względnym do pozycji początkowej*.
+**Względne** pozycjonowanie oznacza z innej strony, że element także jest naturalnie wpasowany w stronę, ale może być umieszczony z przesunięciem *względnym do pozycji początkowej*.
**Bezwzględne** pozycjonowanie idzie o jeden krok dalej i pozwala nadać określony współrzędne x/y dla danego elementu względnie do punktu początkowego **dokumentu** lub **pierwszego bezwzględnego lub względnie przesuniętego elementu nadrzędnego**.
@@ -86,11 +86,11 @@ To w konsekwencji oznacza, że potrzebowalibyśmy sztucznie ustawić wysokość
### Pamięć absolutna.
-Pozostaje jeszcze jeden problem. Podczas gdy element A zostaje w DOM i może dzięki temu "pamiętać" poprzednią pozcyję, element B przeżywa reinkarnację jako element B' i ma wyczyszczoną pamięć o poprzedniej pozycji.
+Pozostaje jeszcze jeden problem. Podczas gdy element A zostaje w DOM i może dzięki temu "pamiętać" poprzednią pozycję, element B przeżywa reinkarnację jako element B' i ma wyczyszczoną pamięć o poprzedniej pozycji.
Na szczęście Meteor radzi sobie z tym problemem przez udostępnienie objektu **instancji szablonu** w callbacku `rendered`. Za oficjalną [dokumentacją Meteora](http://docs.meteor.com/#template_rendered):
-> W callbacku `this` odności się do obiektu instancji szablonu, który jest unikatowy do tego wystąpienia szablonu i zachowany przy renderowaniu.
+> W callbacku `this` odnosi się do obiektu instancji szablonu, który jest unikatowy do tego wystąpienia szablonu i zachowany przy renderowaniu.
Zatem co zrobimy, to odnajdziemy obecną pozycję posta na stronie i następnie zapamiętamy tą pozycję w obiekcie instancji szablonu. W ten sposób, nawet wtedy gdy post jest usuwany i ponownie tworzony jesteśmy w stanie określić skąd go animować.
@@ -104,7 +104,7 @@ Zauważ, że nie możemy wstawić tej własności "ranking" bezpośrednio do baz
Idealnie wstawilibyśmy tą własność w kolekcje `newPosts` i `topPosts` ale Meteor jeszcze nie dostarcza wygodnego mechanizmu pozwalającego to osiągnąć.
-Zatem wstawimy "ranking" jako ostatni możliwy krok managera szabloku `postList`:
+Zatem wstawimy "ranking" jako ostatni możliwy krok managera szablonu `postList`:
~~~js
Template.postsList.helpers({
@@ -145,7 +145,7 @@ Nie zapomnij uaktualnić szablonu `postList`:
### A teraz bądź tak miły i przewiń wstecz
-Meteor jest jednym z najbardziej przemyślanych i najnowocześniejszych z dostępnych frameworków webowych, ale jedna z jego funcji przywodzi na myśl lata 90te i kasety magnetowidowe: funkcja `rewind()`.
+Meteor jest jednym z najbardziej przemyślanych i najnowocześniejszych z dostępnych frameworków webowych, ale jedna z jego funkcji przywodzi na myśl lata 90-te i kasety magnetowidowe: funkcja `rewind()`.
Za każdym razem, gdy używasz kursora z `forEach()`, `map()`, czy `fetch()` będziesz zmuszony przewinąć kursor do tyłu zanim będzie mógł być ponownie użyty.
@@ -199,7 +199,7 @@ Nie powinno być trudne rozumienie tego, jeżeli spojrzysz na nasz poprzedni dia
Zwróć uwagę, że skoro ustawiamy własność `currentPosition` instancji szablonu w callbacku `defer`, oznacza to że ta własność nie będzie istniała podczas pierwszego renderowania fragmentu szablonu. Nie jest to jednak problemem, ponieważ i tak nie jesteśmy zainteresowani animowaniem pierwszego renderowania.
-Teraz otwórz swoją stronę w przeglądarce i zacznij dodawać głosy. Powinieneś zaobserować delikatne przemieszczanie się postów niczym podczas baletu!
+Teraz otwórz swoją stronę w przeglądarce i zacznij dodawać głosy. Powinieneś zaobserwować delikatne przemieszczanie się postów niczym podczas baletu!
### Animacja Nowych Postów
@@ -212,7 +212,7 @@ Jest to bardziej skomplikowane, niż wydaje się na pierwszy rzut oka. Problem p
Wyłącznie przypadek 1 powinien być animowany, chyba że masz na celu zmiany interfejsu użytkownia w choinkę przy każdej zmianie danych.
-Upewnijmy się, że tylko animujemy posty kiedy są nowe a nie kiedy są ponownie renderowane z powodu zmiany danych, z których korzystają. Już sprawdzamy istnienie zmiennej instancji (która jest ustawiana tylko po pierszym renderowaniu szablonu), zarem wystarczy wrócić do naszego callbacka `rendered` i dodać blok `else`:
+Upewnijmy się, że tylko animujemy posty kiedy są nowe a nie kiedy są ponownie renderowane z powodu zmiany danych, z których korzystają. Już sprawdzamy istnienie zmiennej instancji (która jest ustawiana tylko po pierwszym renderowaniu szablonu), zatem wystarczy wrócić do naszego callbacka `rendered` i dodać blok `else`:
~~~js
Template.postItem.helpers({
@@ -263,7 +263,7 @@ Zauważ, że że `removeClass("invisible")` którą dodaliśmy w funkcji `defer(
Jak już zapewne zauważyłeś, używamy klasy CSS `.invisible` aby wyzwolić animację zamiast bezpośrednio animować własność CSS `opacity` jak robiliśmy w przypadku `top`. Jest to spowodowane tym, że dla `top` potrzebna była animacja własności do określonej wartości, która zależała na danych instancji.
-Z innej strony, chcemy wyłącznie pokazać element niezależnie od jego danych. Ponieważ przechowywanie CSS z dala od kodu JavaScript jest dobrą praktyką, dodamy wyłącznie tutaj klasę tutaj a ustalimy szczegóły animacji w akruszu stylów (kodzie CSS).
+Z innej strony, chcemy wyłącznie pokazać element niezależnie od jego danych. Ponieważ przechowywanie CSS z dala od kodu JavaScript jest dobrą praktyką, dodamy wyłącznie tutaj klasę tutaj a ustalimy szczegóły animacji w arkuszu stylów (kodzie CSS).
<% end %>