Spis treści. Kontakt:

Wielkość: px
Rozpocząć pokaz od strony:

Download "Spis treści. Kontakt: sebastian.rosik@gmail.com"

Transkrypt

1 1

2 Spis treści 1. Wstęp Czym jest HTML5 Storage? Współdzielenie instancji Storage Lokacja dokumentu a współdzielenie Storage Storage API Rzutowanie danych Indeksy i iteracja po wpisach Zdarzenie storage Pojemność Storage Ilość znaków a zajmowana przestrzeń Liczenie zajętej przestrzeni Rozszerzanie Storage o nowe możliwości Własne API Fundamenty Przykład użycia Przestrzenie nazw Limit pojemności w przestrzeni nazw Reagowanie na zmiany w Store Usuwanie najstarszych elementów gdy Store jest pełen Przykład użycia Usuwanie przeterminowanych elementów Przykład użycia Referencje...46 Sebastian Rosik Frontend developer w firmie RST sp. z o. o. sp. k., gdzie rozwija aplikacje typu Single Page Application dla branży logistycznej. Dawniej brał udział w projektowaniu gier i aplikacji mobilnych na platformę JAVA oraz ios. Dziś pisze aplikacje głównie w HTML5 pod przeglądarki, a także w Node.js dla rozwiązań serwerowych. Hobbystycznie tworzy grafikę 2D oraz 3D, a w wolnych chwilach zgłębia tajniki platformy Arduino. Kontakt: 2

3 Wstęp Książka ta jest przeznaczona dla każdego, kto chciałby poznać HTML5 Storage począwszy od podstaw a skończywszy na technikach zaawansowanych. W książce tej poruszone zostały techniki, które wiele razy były wykorzystywane w praktyce, zarównvo w projektach komercyjnych, jak i darmowych. HTML5 Storage jest niezwykle prosty w budowie, lecz jego dojrzałość i dostępność w wielu przeglądarkach sprawia, że znajduje on wiele bardziej złożonych zastosowań, aniżeli zwykłe przechowywanie prostych danych tekstowych. Dowiemy się między innymi w jaki sposób korzystać z API HTML5 Storage, w jaki sposób zapisywane są dane, czy chociażby w jaki sposób rozszerzyć API o dodatkowe możliwości. Stopniowo poruszane będą coraz to bardziej złożone problemy, oraz ich przykładowe rozwiązania w formie prostej biblioteki będącej nakładką na oryginalne API HTML5 Storage. Poniżej znajduje się mały słownik pojęć. Każde z wymienionych słów występuje dość często w książce i czasami kryje się za nim szersze znaczenie. Warto się z nimi zapoznać, by wiedzieć z czym mamy do czynienia podczas czytania. HTML5 Storage - Ogólna nazwa dla API przeglądarkowego do odczytu i modyfikacji danych przetrzymywanych w jednej z dwóch instancji: localstorage bądź sessionstorage. Instancja Storage (lub po prostu Storage) - Obiekty localstorage oraz sessionstorage. Dokument (DOM Document) - Strona internetowa, bądź element iframe. Okno, zakładka przeglądarki, popup - Okno przeglądarki, mogące być powiązane relacją z innym oknem na zasadzie dziecko - rodzic. Posiada globalny obiekt window oraz document. Lokacja, adres - Lokacja, inaczej adres dokumentu (URL) stanowi wspólny mianownik dla Storage. Jeżeli kilka dokumentów posiada tę samą lokacji, to mają dostęp do tej samej przestrzeni Storage (mają możliwość modyfikacji tych samych danych w Storage). Na lokację składają się takie elementy, jak np. host, port, protokuł, etc. Więcej na ten temat relacji dokumentów między sobą w rozdziale Współdzielenie instancji Storage. 3

4 Czym jest HTML5 Storage? Wszystkie przeglądarki dostępne obecnie na rynku, udostępniają API JavaScript, dzięki któremy możemy przechowywać dane, które zostaną zachowane pomiędzy przeładoniami dokumentu. Dane przechowywać możemy w jednej z dwóch instancji API Storage - localstorage oraz sessionstorage. Maksymalna ilość danych, jaką możemy zapisać jest niezależna dla sessionstorage i localstorage, zatem warto podczas pisania aplikacji zastanowić się jakie dane kiedy będą nam potrzebne, gdyż w przypadku limitu 5 MiB, sumarycznie będziemy mieli do dyspozycji 10 MiB, (5 MiB dla localstorage oraz 5 MiB dla sessionstorage). Sam limit różni się pomiędzy przeglądarkami - jedna przeglądarka może posiadać limit ustawiony na 5 MiB, a inna z kolei na 50 MiB. Standard nie precyzuje jaką ilość powinny domyślnie oferować przeglądarki, ani też w jaki sposób użytkownik mógłby zmodyfikować ilość zasobów jaka ma zostać na to przeznaczona [1]. W większości przypadków przeglądarki oferują obecnie (2014 r.) pojemność dla localstorage wynoszącą około 5 MiB, lecz limit ten oczywiście może ulec zmianie, w zależności od działań podjętych przez producentów przeglądarek. W przypadku HTML5 Storage, dane dzielimy na elementy (items), które posiadają postać klucz-wartość (key-value). Zarówno klucz, jak i wartość elementu zapisywane są jako typ String. Oczywiście możemy zapisywać dane o innych wartościach, ale podczas zapisu i tak zostaną one zrzutowane do typu String. Cechy localstorage Dane zapisane w localstorage pozostają w nim tak długo, aż nie zostaną usunięte przez skrypt bądź użytkownika. Po zamknięciu okna bądź przeglądarki i ponownym jego włączeniu, dane zapisane wcześniej w localstorage, nadal będą się tam znajdować. Wszystkie dokumenty, o ile znajdują się w jednej lokacji, mają dostęp do tej samej instancji localstorage. Cechy sessionstorage Dane zapisane w sessionstorage są dostępne tylko i wyłącznie podczas danej sesji (tak długo, jak długo okno przeglądarki jest otwarte). Po zamknięciu okna, dostęp do danych może zostać utracony, chyba że użytkownik ponownie otworzy zamknięte okno (dokładnie to samo okno), o ile przeglądarka oferuje taką funkcjonalność. Nie jest to oczywiście funkcjonalność, nad którą mamy jakąkolwiek kontrolę, dlatego też z góry powinnyśmy założyć, że z chwilą zamknięcia okna utracimy wszystkie informacje zapisane w sessionstorage. Warto też nadmienić, że zgodnie z założeniami standardu, przeglądarka powinna przywrócić zawartość sessionstorage w przypadku wznowienia sesji po awaryjnym zamknięciu się przeglądarki, natomiast nie mamy gwarancji, że tak właśnie się stanie. 4

5 Każdy z dokumentów ma swoją własną instancję sessionstorage, to znaczy, że dane zapisane w sessionstorage w jednej zakładce są niedostępne dla drugiej, mimo iż obie znajdują się pod tą samą lokacją. W przypadku dokumentów osadzonych poprzez element IFrame sprawa wygląda jednak trochę inaczej, dokument będzie współdzielił sessionstorage z dokumentem nadrzędnym (dokumentem, który posiada osadzony IFrame), pod warunkiem posiadania tej samej lokacji. Współdzienie instancji Storage Relacje pomiędzy dokumentami względem instancji Storage mogą być dosyć skomplikowane i być przyczyną wielu problemów, jeżeli nie są obsłużone prawidłowo. Poniżej zostały przedstawione ilustracje reprezentujące relacje pomiędzy dokumentami a instancjami localstorage oraz sessionstorage w różnych sytuacjach. Przykład 1. Cztery okna, z czego okna A, B oraz C posiadają dokumenty pod lokacją X. Dokument w oknie D jest umieszczony pod lokacją Y. Dokumenty A, B i C mają dostęp do wspólnej instancji localstorage, natomiast dokument w oknie D posiada dostęp do zupełnie innej instancji localstorage ze względu na lokacje różną od pozostałych dokumentów. Przykład 2. Dwa okna z dokumentami A i B, każde z nich z osadzonym poprzez element iframe dokumentem (C oraz D). Dokument A, B oraz C posiadają dostęp do wspólnej instancji localstorage ze względu na wspólną lokacje X, natomiast dokument D, który jest osadzony w dokumencie B posiada dostęp do osobnej instancji localstorage ze względu na różną lokacje. 5

6 Przykład 3. Przykład dostępu do instancji sessionstorage. Mamy tutaj sześć dokumentów, A, B, C, D, E oraz F z czego dokument C jest osadzony jako element iframe w dokumencie B, a dokument E jest oknem popup (dziecko) okna D (rodzic). Dokumenty A, B, D, F posiadają dostęp do osobnych instancji sessionstorage, bez względu na to czy mają taką samą lokacje czy nie. Wyjątkiem od reguły są dokumenty posiadające relacje dziecko - rodzic z innym dokumentem. Okna C oraz E mają dostęp do tej samej instancji sessionstorage co dokumenty nadrzędne (okna B i D), pod warunkiem, że mają taką samą lokacje jak dokument nadrzędny. Z powyższych przykładów wyłania się pewna prawidłowość. Dla localstorage wszystkie dokumenty niezależnie od tego czy są dokumentami nadrzędnymi (okno) czy podrzędnymi (iframe lub okno popup) mają dostęp do tej samej instancji localstorage pod warunkiem, że znajdują się w tej samej lokacji. Dla sessionstorage sytuacja wygląda inaczej: Każdy z dokumentów umieszczony w oknach ma dostęp do innej instancji sessionstorage, niezależnie od tego czy współdzielą tą samą lokacje czy też nie. Dokumenty w elemencie iframe, znajdujące się w innej lokacji aniżeli dokument nadrzędny, posiadają dostęp do innej instancji sessionstorage niż dokument nadrzędny. Wyjątek stanowią dokumenty, będące w tej samej lokacji co dokument nadrzędny, oba dokumenty posiadają dostęp do tej samej instancji sessionstorage. Zasada ta dotyczy zarówno dokumentów osadzonych poprzez element iframe oraz dokumentów w oknach popup. Lokacja dokumentu a współdzielenie Storage By dwa dokumenty miały dostęp do tej samej instancji Storage, muszą znajdować się w tej samej lokacji. Jeżeli adresy obu dokumentów są zgodne pod względem portu, 6

7 subdomeny, domeny oraz portu, to obie lokacja są takie same, zatem oba dokumenty mają dostęp do tej samej instancji Storage. Jedynym elementem adresu, który mimo swoich różnic pozwala na współdzielenie instancji Storage jest ścieżka do dokumentu. Poniżej został zilustrowany skład adresu oraz jego części, które mają wpływ na współdzielenie instancji Storage w przypadku wystąpienia potencjalnych różnić dla każdego z elementów adresu pomiędzy dwoma dokumentami. Dokument 1 Dokument 2 Współdzielona instancja Storage https://example.com Nie Nie Nie Nie Tak Tabela 1. Współdzielenie instancji Storage dla dokumentów o różnych wartościach podstawionych pod protokół, subdomenę, domenę oraz port i ścieżkę. 7

8 Storage API API dla localstorage oraz sessionstorage jest identyczne. Jak widać poniżej, jest to bardzo proste API składające się z zaledwie kilku metod, jednak możliwości jakie nam daje, w połączeniu z innymi funkcjonalnościami przeglądarek, są o wiele większe, niż widać to na pierwszy rzut oka. W dalszych rozdziałach zobaczymy, w jaki sposób możemy rozszerzyć API o dodatkowe funkcjonalności. Nazwa metody Argumenty Opis setitem key, value Tworzy nowy bądź modyfikuje istniejący wpis. Przyjmuje dwa argumenty, klucz (key), pod którym dany element powinien zostać zapisany oraz jego wartość (value). Metoda ta zwraca undefined po zapisie do Storage. getitem key Zwraca wpis w Storage o podanym kluczu. Jeżeli wpis nie zostanie odnaleziony, zostanie zwrócona wartość null. removeitem key Usuwa istniejący wpis o podanym kluczu w Storage. Metoda ta zawsze zwraca undefined bez względu na to czy wpis został usunięty czy też w ogóle nie istniał. clear Czyści zawartość Storage ze wszystkich zapisanych wpisów. Tak jak część powyższych metod, zwraca undefined bez względu na to czy w Storage znajdowały się jakieś dane do usunięcia czy też nie. key index Zwraca nazwę klucza elementu, który jest zapisany w Storage pod danym indeksem. Tabela 2. Metody dostępne w instancji Storage 8

9 Nazwa Opis właściwości length Ilość elementów jaka obecnie znajduje się w Storage. * Dowolny ciąg znaków, będacy kluczem, pod którym wcześniej zapisaliśmy element. Jeżeli odwołamy się do jakiejkolwiek właściwości, która nie jest z góry zdefiniowaną metodą (setitem, clear itp.) ani właściwością (length) to wartość ta będzie odwoływać się do zapisanego pola o kluczu, którego nazwa jest taka sama jak nazwa właściwości. Jeżeli dany element nie występuje w danej instancji Storage, właściwość ta będzie wynosić undefined. Jest to zachowanie diametralnie różne od pobierania zapisanych danych za pomocą metody getitem, gdyż w przypadku braku elementu metoda ta zwróci wartość null. Tabela 3. Właściwości dostępne w instancji Storage Podczas zapisu do Storage, przeglądarka może rzucić wyjątek QuotaExceededError (lub błędem odpowiednim dla danej przeglądarki), gdy pojemność instancji Storage została przekroczona bądź użytkownik wyłączył w przeglądarce Storage. Wszelkie operacje na Storage, które się nie powiodą, nie modyfikują w żaden sposób już istniejących danych. Zatem, jeżeli podczas aktualizacji danych o kluczu foo w localstorage wystąpi błąd, to istniejące dane pod tym kluczem nie zostaną zmodyfikowane. Dostęp do danych oraz ich zapis może się odbywać na dwa sposoby. Pierwszy to użycie metod setitem oraz getitem. Drugi sposób to potraktowanie instancji Storage jako zwykłego obiektu i odczytanie bądź zapisanie danych przez ustawienie odpowiedniej właściwości. localstorage.setitem( foo, 1 ); console.log( localstorage.getitem( foo ) ); // Wyświetli w konsoli: // Wynik > 1 localstorage.foo = 2; console.log( localstorage.foo ); // Wyświetli w konsoli: // Wynik > 2 console.log( localstorage.getitem( foo ) ); // Wyświetli w konsoli: // Wynik > 2 Podczas pobierania wartości zapisanych elementów należy pamiętać o tym, że właściwości instancji Storage mają priorytet. Dlatego też istnieje możliwość zapisania elementu o kluczu length jedynie poprzez użycie metody setitem. W przeciwnym razie próba ustawienia właściwości length się nie powiedzie, odczyanie właściwości length da nam ilość zapisanych elementów, a nie wartość, którą wcześniej ustawiliśmy. 9

10 Zaleca się zatem używanie tylko i wyłącznie metod do odczytu i zapisu danych w Storage, dzięki czemu uniknie się wielu błędów. Instancja Storage reprezentuje pewne cechy obiektu hash-mapy, tablicy oraz zwykłego interfejsu. Niesie to za sobą pewne skutki, które mogą wprowadzić zamieszanie do naszego kodu, jeżeli nie wiemy w jaki sposób korzystać z Storage lub nie znamy jego wszystkich możliwości i ograniczeń. Do instancji Storage możemy zapisać dane na trzy różne sposoby: // Metoda localstorage.setitem( foo, bar ); // Jako indeks/klucz localstorage[ foo ] = bar ; // Jako właściwość localstorage.foo = bar ; Oczywiście można też usunąć dany wpis na tyle samo sposobów: localstorage.removeitem( foo ); delete localstorage[ foo ]; delete localstorage.foo; Jako że wszystkie powyższe sposoby zapisu służą do zapisu danych do Storage, nie ma sposobu na wzbogacenie localstorage o nowe funkcjonalności (brak też prototypu, który można by rozszerzyć). Przyjrzyjmy się poniższemu przykładowi: localstorage.foreach = function( fn ) { var key; for ( var i = 0; i < this.length; ++i ) { key = this.key( i ); typeof fn === function && fn( this.getitem( key ), key ); localstorage.foreach(function( value, key ) { console.log( key: %s, value: %s, key, value ); ); // Wyjątek w konsoli: // Uncaught TypeError: string is not a function Powyższa próba implementacji metody foreach znanej z tablic spełznie na niczym, gdyż na podanej funkcji zostanie wywołana metoda Function.prototype.toString, a zwrócona przez nią wartość trafi do Storage pod klucz o nazwie foreach. Próba wywołania funkcji foreach spowoduje jedynie wystąpienie wyjątku informującego o tym że ciąg znaków nie jest funkcją. Jedynym sposobem na rozszerzenie możliwości Storage, jest stworzenie adapteru. Więcej o tym w osobnym rozdziale Rozszerzanie Storage o nowe możliwości. 10

11 Rzutowanie danych Rzutowanie danych do ciągu znaków podczas zapisu do Storage w większości przypadków będzie się ograniczało do wywołania metody setitem na instancji Storage, niemniej jednak mogą zdarzyć się przypadki, w których będziemy potrzebować większej kontroli nad tym w jaki sposób nasze dane są zapisywane do Storage. Proces rzutowania danych jest wbrew pozorom trochę bardziej skomplikowany i zależy od typu naszej danej, oraz od tego po czym ona dziedziczy. Poniższa tabela, przedstawia wartości jakie są zapisywane w JavaScript do localstorage oraz wartość jaka zostanie odczytana w postaci ciągu znaków. value Wartość zapisywana 1 1 Number.MAX_VALUE null undefined {test:1 value Wartość odczytana e+308 null undefined [0,1,2] 0,1,2 function(){ alert( test ); /* comment */ [object Object] function(){ alert( test ); /* comment */ Tabela 4. Rzutowanie danych różnego typu podczas zapisu do localstorage. Jak widać w Tabeli 1. rzutowanie wygląda dość intuicyjnie, aż do momentu w którym nie będziemy chcieli zapisać w Storage całego obiektu. Każdy obiekt (instancja Object) będzie zapisany jako ciąg znaków [object Object] (dokładna wartość może, ale nie musi różnić się pomiędzy przeglądarkami), dzieje się tak dlatego iż przeglądarka podczas zapisu do Storage, próbuje wywołać metodę tostring na obiekcie, który chcemy zapisać. Jeżeli metoda tostring istnieje to wartość przez nią zwrócona (niezależnie od typu) zostanie zapisana do Storage. Literały obiektowe w JavaScript są dość dziwnym tworem pod względem dziedziczenia metody tostring (oraz innych metod). Skupmy się na literale obiektowym dla liczb - literał ten posiada co prawda metodę tostring, lecz już nie prototype. Literały jednak zachowują pewną cechę dzieczenia, zupełnie jakby zostały utworzone poprzez konstruktor im odpowiadający, otóż gdy usuniemy funkcję tostring z Number.prototype to każda liczba podczas użycia metody tostring odwoła się do prototypu klasy bazowej Object. 11

12 Usunięcie metody tostring z Number.prototype co prawda wpływa na to skąd litrał bierze swoją metodę tostring, jednak w żaden sposób nie wpływa na rzutowanie do ciągów znaków np. poprzez łączenie zmiennych o różnych typach. delete Number.prototype.toString; var n = 2; console.log( 2..toString() ); // Wynik > [object Number] console.log( 2 + a ); // Wynik > 2 Jeżeli do każdego z literałów bezpośrednio przypiszemy własną funkcję tostring (bez modyfikowania prototypu), to zostanie ona zignorowana podczas zapisu do Storage. Wyjątek tutaj stanowi literał obiektu Function, którego metoda tostring jako jedyna zostanie wykorzystywana w takiej sytuacji. var num = 1; num.tostring = function() { return [custom Number] ; ; localstorage.setitem( test, num ); console.log( localstorage.getitem( test ) ); // Wyświetli w konsoli: // Wynik > 1 var fn = function FN() { /*comment*/ fn.tostring = function() { return [custom Function1] ; ; localstorage.setitem( test, fn ); console.log( localstorage.getitem( test ) ); // Wyświetli w konsoli: // Wynik > [custom Function1] var fn = new Function( /*comment*/ ); fn.tostring = function() { return [custom Function2] ; ; localstorage.setitem( test, fn ); console.log( localstorage.getitem( test ) ); // Wynik > [custom Function2] Sposobem na wywołanie funkcji tostring podczas zapisu do Storage dla wszystkich typów danych jest użycie konstruktorów zamiast literałów obiektowych. Poniżej został przedstawiony przykład zapisu liczby poprzez użycie literału obiektowego oraz konstruktora new Number. Sposób ten działa dla nie tylko dla liczb, ale też dla wszystkich konstruktorów odpowiadających każdemu z literałów, gdyż każdy z nich konstruuje obiekt, których dziedziczy po klasie Object. 12

13 var a = 1; a.tostring = function() { console.log( Ta wiadomość NIE zostanie wyświetlona podczas zapisu do localstorage ); return 0 ; ; var b = new Number( 1 ); b.tostring = function() { console.log( Ta wiadomość zostanie wyświetlona podczas zapisu do localstorage ); return 0 ; ; localstorage.setitem( test1, a ); console.log( localstorage.getitem( test1 ) ); // Wyświetli w konsoli: // Wynik > 1 localstorage.setitem( test2, b ); console.log( localstorage.getitem( test2 ) ); // Wyświetli w konsoli: // Wynik > Ta wiadomość zostanie wyświetlona podczas zapisu do localstorage // Wynik > 0 Powyższy konstruktor Number (a także String, Boolean oraz wiele innych) tworzy nowy obiekt. Jeżeli nowo utworzony obiekt posiada metodę tostring, zostanie ona wywołana podczas zapisu, a zwrócona wartość będzie zapisana do Storage. Wszystkie obiekty, które dziedziczą po klasie bazowej Object nie muszą posiadać zdefiniowanej metody tostring, gdyż sam Object już takową posiada. Podczas zapisu do Storage przeglądarka odpyta po kolei cały łańcuch dziedziczenia, aż nie odnajdzie metody tostring w najbliższym rodzicu. Jeżeli jednak metoda tostring nie zostanie odnaleziona w całym łańcuchu dziedziczenia, bądź jej wartość tak naprawdę będzie czymkolwiek innym niż funkcją, przeglądarka rzuci błędem podczas zapisu do Storage. Gdy obiekt dziedziczący po klasie bazowej Object nie posiada metody tostring, podczas zapisu zostanie rzucony odpowiedni wyjątek: var A = function() {; A.prototype.toString = undefined; localstorage.setitem( test, new A() ); // Wynik > Uncaught TypeError: Cannot convert object to primitive value Identycznie wygląda to w przypadku, gdy metoda tostring jest czymkolwiek innym aniżeli funkcją: Object.prototype.toString = null; var A = function() {; localstorage.setitem( test, new A() ); // Wynik > Uncaught TypeError: Cannot convert object to primitive value Jeżeli podamy ciąg znaków jako argument dla new Object to zostanie wewnętrznie użyty konstruktor String, który ma własną implementację metody tostring. W tym przypadku przeszukiwanie łańcucha dziedziczenia kończy się na String.prototype, przez co nie zostanie rzucony wyjątek. Poniższy przykład dotyczy ciągu znaków, ale może zostać powtórzony też dla innych typów takich jak np. Boolean czy Number: 13

14 Object.prototype.toString = undefined; localstorage.setitem( test, new Object( string ) ); Poniżej dziedziczymy metodę tostring na przykładzie obiektu utworzonego przez konstruktor String. Identyczny proces zachodzi dla wszystkich innych obiektów dziedziczących po Object: var a = new String( a ); console.log( a.tostring() ); // Wynik > a delete String.prototype.toString; console.log( a.tostring() ); // Wynik > [object String] Object.prototype.toString = function() { return Inheriting from Object.prototype ; console.log( a.tostring() ); // Wynik > Inheriting from Object.prototype delete Object.prototype.toString; console.log( a.tostring() ); // Wynik > Uncaught TypeError: undefined is not a function Indeksy i iteracja po wpisach Każdy z elementów w Storage jest dostępny nie tylko po kluczu, ale także po jego indeksie. Zapisując dane do localstorage w żaden sposób nie dostajemy informacji o tym pod jakim indeksem został dany element zapisany. Indeksy elementów w Storage wykorzystuje się głównie do iteracji po wszystkich elementach znajdujących się w Storage. Możemy odczytać zawartośc elementu (a dokładniej jego klucza) poprzez użycie metody key, która jako argument przyjmuje indeks, pod którym element został zapisany: // Czyścimy localstorage ze wszystkim poprzednich elementów localstorage.clear(); localstorage.setitem( foo, bar ); console.log( localstorage.key( 0 ) ); // Wynik > foo console.log( localstorage.key( 1 ) ); // Wynik > undefined console.log( localstorage.length ); // Wynik > 1 Storage nie posiada metody, która umożliwiałaby nam iterowanie po wszystkich elementach w danej instancji Storage (np. metody foreach, która jest dostępna dla każdej tablicy w JavaScript). Możemy jednak iterować po elementach poprzez użycie pętli. Pierwszym sposobem jest użycie pętli for, gdzie musimy znać ilość przechowywanych elementów - informacji o tym 14

15 dostarcza nam właściwość length. Posiadając informacje na temat ilości elementów, możemy w pętli odczytywać każdy z elementów poprzez odczyt klucza elementu spod danego indeksu. Indeks elementu natomiast zwiększamy w pętli od zera aż po ilość elementów w instancji Storage. localstorage.clear(); localstorage.setitem( a, value 1 ); localstorage.setitem( b, value 2 ); localstorage.setitem( c, value 3 ); var key; for ( var i = 0; i < localstorage.length; ++i ) { key = localstorage.key( i ); console.log( index: %s, key: %s, value: %s, i, key, localstorage.getitem( key ) ); // Wynik > index: 0, key: a, value: value 1 // Wynik > index: 1, key: b, value: value 2 // Wynik > index: 2, key: c, value: value 3 Drugim sposobem jest skorzystanie z pętli for...in, dzięki której możemy całkowicie pominąć odczytywanie kluczy poprzez indeksy. Ten sposób korzysta z alternatywnego API Storage, które umożliwia odczyt danych w Storage poprzez odwołanie się do kluczy elementów jak do zwykłych właściwości obiektów. localstorage.clear(); localstorage.setitem( a, value 1 ); localstorage.setitem( b, value 2 ); localstorage.setitem( c, value 3 ); for ( var key in localstorage ) { console.log( key: %s, value: %s, key, localstorage.getitem( key ) ); // Wynik > key: a, value: 1 // Wynik > key: b, value: 2 // Wynik > key: c, value: 3 Powyższe przykłady nasuwają na myśl następujące pytanie, w jaki sposób są przydzielane indeksy do elementów i czy kolejność indeksów może się zmienić? Przeprowadźmy mały eksperyment. Poniższy kod zapisuje do localstorage dane pod kluczem znaku ASCII (o wartości od 0 do 99), każdy ze znaków zapisywany jest w kolejności malejącej, to jest od 99 do 0. Gdy wszystkie znaki zostaną już zapisane, odczytuje całą zawartość localstorage i wyświetla ją w konsoli. localstorage.clear(); var chr = 100, key; while ( chr-- ) { localstorage.setitem( String.fromCharCode( chr ), CharCode: + chr ); for ( var i = 0; i < localstorage.length; ++i ) { key = localstorage.key( i ); console.log( key: %s, value: %s, key, localstorage.getitem( key ) ); 15

16 Kod ten uruchomiony pod różnymi przeglądarkami da różne wyniki, gdyż każda z przeglądarek różni się pod względem: Liczenia unikalnego hash a dla każdego z kluczy oraz obsługi kolizji Mechanizmu przechowującego dane na dysku lub w pamięci Wewnętrznego cache Żaden standard nie mówi, w jaki sposób elementy w localstorage powinny zostać posortowane, dlatego też przeglądarki nie są zunifikowane pod tym względem. Indeks elementu jest w przeglądarkach liczony zazwyczaj z nazwy klucza. Na podstawie klucza jest liczony hash, jeżeli więcej elementów posiada taki sam hash, hash przeliczony jest jeszcze raz, tym razem innym algorytmem. Cały proces jest skomplikowany i każda z przeglądarek liczy indeks w inny sposób. Zatem kolejność elementów w localstorage może dla jednego zestawu danych być identyczna w każdej z przeglądarek, dla innego zestawu jednak różnić się diametralnie. Korzystając z indeksów w localstorage musimy pamiętać, że nie mamy żadnej gwarancji, że kolejność w jakiej zapiszemy elementy będzie odpowiadała kolejności indeksów, ani że każdy klucz będzie się już zawsze znajdował pod danym indeksem. Zdarzenie storage Za każdym razem, gdy wprowadzamy zmiany w danych przetrzymywanych w Storage, występuje zdarzenie storage na globalnym obiekcie window przeglądarki. window.addeventlistener( storage, function( e ) { console.log( Storage event, e ); ); Zdarzenie storage dostarcza, między innymi takich informacji jak: Właściwość zdarzenia key newvalue oldvalue url storagearea timestamp Opis Klucz, pod którym nastąpiła zmiana. Wartość elementu o podanym kluczu. Poprzednia wartość jaką posiadał element o podanym kluczu bądź null, jeżeli dany element wcześniej nie istniał. Adres URL, do którego Storage jest przypisany i na którym wystąpiło zdarzenie. Storage, dla którego wystąpiło zdarzenie. Czas wystąpienia zdarzenia. 16

17 Istnieje jeden bardzo istotny fakt o którym należy zawsze pamiętać podczas pracy ze zdarzeniem storage, otóż nie jest ono wywoływane w oknie, w którym miało ono swoje źródło, lecz w pozostałych oknach (lub zakładkach), które współdzielą dany Storage. Oznacza to, że jeżeli mamy otwarte dwie zakładki, które posiadają tę samą lokacje i w jednej z zakładek zapiszemy dane do Storage, to zdarzenie, które nas o tym poinformuje zostanie wywołane w drugiej zakładce. W pierwszej zakładce zdarzenie to nigdy nie wystąpi. Jest to zachowanie przewidziane przez standard, natomiast przeglądarki niekoniecznie się tego zachowania trzymają. Na przykład, dla przeglądarki Internet Explorer 9 oraz 10 zdarzenie to może być równie dobrze wywołane w obu zakładkach. Należy pamiętać o tym zachowaniu, gdyż w przeciwnym razie może to doprowadzić do niepotrzebnego bólu głowy i niestabilności działania aplikacji. Inną dość dużą niekompatybilnością związaną z obsługą zdarzenia storage pomiędzy przeglądarkami jest moment wystąpienia tego zdarzenia. Większość przeglądarek wywołuje zdarzenia storage po zapisie do Storage, natomiast Internet Explorer robi to przed. Skutek tego jest taki, że jeżeli podczas wystąpienia zdarzenia storage odczytamy zawartość pola, które zostało zmodyfikowane, to w Internet Explorer pod tym polem będzie się znajdowała stara wartość tuż sprzed zapisu: window.addeventlistener( storage, function( e ) { // W IE zawartość tego pola nie będzie aktualna console.log( Value:, localstorage.getitem( e.key ) ); ); 17

18 Poniższy skrypt jest przykładem, jak mogłaby wyglądać prosta komunikacja pomiędzy oknami przeglądarki (o ile znajdują się w tej samej lokacji).!function() { var KEY = com ; function _genid( n ) { var str =, n = n 9; while ( n-- ) { str += Math.round( Math.random() * 100 ).tostring( 16 ); return str; var id = _genid(), listeners = []; function send( message ) { localstorage.setitem( KEY, JSON.stringify({ id: id, message: message, token: _genid() ) ); function addlistener( fn ) { if ( typeof fn === function ) { listeners.push( fn ); window.addeventlistener( storage, function( e ) { var value = e.newvalue; if ( value === null ) { return; var data = JSON.parse( value ); if ( data.id!== id ) { listeners.foreach(function( fn ) { fn( data.message, data ); ); ); window.tabmessenger = { id: id, send: send, addlistener: addlistener (); 18

19 Cały skrypt opiera się na bardzo prostych założeniach: Każde z okien generuje swoje unikalne id, które będzie rozsyłane wraz z treścią wiadomości do innych okien. Każde okno podczas odczytywania wiadomości porówna przesłane id ze swoim własnym id, jeżeli będą się różnić, wtedy okno przyjmie wiadomość, w przeciwnym razie wiadomość zostanie zignorowana. Jest to zabezpieczenie przed sytuacją jaka ma miejsce w przeglądarce Internet Explorer - gdy zdarzenie storage występuje też w oknie, w którym została dokonana zmiana w Storage. Ta prosta biblioteka udostępnia dwie metody, send - wysyła wiadomość do innych okien, oraz addlistener - dodaje funkcję nasłuchującą wiadomości przychodzących z innych okien. Wiadomości są zapisywane w Storage w formacie JSON. W samej wiadomości będą przesyłane: id okna, z którego wiadomość pochodzi; treść wiadomości, która ma zostać przekazana do pozostałych okien oraz unikalny token. Token jest przesyłany dlatego, by umożliwić przesyłanie wiadomości o tej samej treści kilka razy pod rząd, gdyż zdarzenie storage jest przekazywane tylko raz w przypadku próby zapisu do Storage elementu o tej samej treści. Należy jednak pamiętać, że to jest bardzo prosty skrypt i nie jest on przystosowany do ekstremalnych przypadków, np.: rozsyłania setek wiadomości jedna po drugiej z wielu okien w tym samym czasie. Generalnie należy pamiętać o tym, że HTML5 Storage nie został stworzony w celu wymiany danych pomiędzy oknami, lecz w celu przechowywania danych. Oznacza to, że możemy wymieniać dane pomiędzy oknami, lecz nie powinniśmy się spodziewać dużej wydajności i niezawodności. Istnieje jednak mechanizm, który został stworzony z myślą o komunikacji pomiędzy oknami: HTML5 Web Messaging. 19

20 Pojemność Storage Ilość znaków a zajmowana przestrzeń Ilość danych, jaką możemy zapisać do Storage, jest ściśle ustalona poprzez kodowanie znaków, jakie jest używane do przechowywania ciągów znaków. Język JavaScript używa kodowania UTF-16 do przechowywania znaków, który różni się nieznacznie od obecnie najpopularniejszego kodowania w siecii - UTF-8 [2]. Właściwości UTF-8: Wymagane jest minimalnie 8 bitów, by zakodować jeden znak. Kompatybilność z ASCII - Jeżeli dane zawierają znaki zawarte także w standardzie ASCII, to ciąg znaków UTF-8 jest w pełni kompatybilny z ASCII i może zostać odczytany przez oprogramowanie, które nie posiada wsparcia dla UTF-8. Zorientowany bajtowo, czyli jeden bajt to jeden znak. W przeciwnieństwie do UTF- 16 nie ma dwóch kolejności bajtów, lecz mimo to na początku danych nadal można spotkać bajt BOM Lepiej sobie radzi z błędami - pojedynczy bajt na każdy znak sprawia, że w przypadku znaków zgodnych z ASCII, jeżeli jeden z bajtów zostanie usunięty z wiadomości, to reszta znaków nadal będzie możliwa do odczytania (zachowa swoje znaczenie) Właściwości UTF-16: Wymagane jest minimalnie 16 bitów, by zakodować jeden znak. Niekompatybilny z ASCII - ze względu na różnice w ilości bitów, znaki z ASCII nie mogą zostać zaprezentowane poprzez UTF-16. Nie jest zorientowany bajtowo. Jeden znak wymaga pary bajtów. Co oznacza także, że w UTF-16 kolejność występowania bajtów ma znaczenie (np. 0a 01 oraz 01 0a może, ale nie musi być tym samym znakiem), dlatego rozróżniamy UTF-16LE (little endian) oraz UTF-16BE (big endian). Informacja o kolejności znaków w UTF-16 jest zazwyczaj przekazywana na początku ciągu znaków, jako pierwszy znak (BOM), lub w osobnej partii danych - meta danych. Jeżeli w wiadomości wystąpi błąd i jeden z bajtów zostanie pominięty, reszta wiadomości zmieni znaczenie, gdyż następujące bajty zmienią swoje pary. Należy zatem zadać sobie pytanie, dlaczego wszelkie dane przesyłamy zazwyczaj w UTF-8 (np. plik HTML, który wysyłamy do przeglądarki), ale już dane w pamięci (JavaScript) czy na dysku (Storage) są przechowywane w formie UTF-16. Otóż musimy wziąć pod uwagę dwa problemy: Czas przesyłu danych oraz ilość zajętej przestrzeni. UTF-8 zajmuje mniej przestrzeni, ale jest trudniejszy do zdekodowania, dlatego też o wiele bardziej nadaje się do przesyłanie danych aniżeli ich przechowania. 20

21 By zrekompensować problem potrzebnej pracy procesora, by zdekodować dane, są one dekodowane raz, ale do UTF-16, gdzie w takiej formie są przechowywane w pamięci operacyjnej (np. wszelkie ciągi znaków w JavaScript) lub na dysku (Storage np. w postaci bazy SQLite w wewnętrznym mechaniźmie przeglądarki). UTF-16 jest o wiele prostszy do zdekodowania, lecz ilość przestrzeni jaką mogą zająć dane nim zakodowane jest nieoptymalna do przesyłania przez sieć, natomiast w dobie pojemnych pamięci operacyjnych oraz dyskowych nie jest problemem przechowywanie tych danych. Tekst J A V A S C R I P T UTF-8 4A UTF A Przykład zakodowania ciągu znaków za pomocą UTF-8 oraz UTF-16 Liczenie zajętej przestrzeni W przypadku Storage możemy jedynie liczyć zajętą przestrzeń, lecz w żaden sposób przeglądarki nie dają nam możliwości pobrania informacji na temat wolnej przestrzeni. Oznacza to, że w każdej chwili podczas zapisu danych możemy natrafić na limit nałożony na objętość Storage dla danej domeny. Z chwilą przekroczenia limitu nałożonego przez przeglądarkę, zostanie rzucony błąd o tym informujący (odmienny dla każdej przeglądarki, a jakże). var n = 0, s = new Array( 1024 ).join( 1 ); localstorage.clear(); while ( 1 ) { localstorage.setitem( n, s ); n++; // Wynik > Uncaught QuotaExceededError: Failed to execute setitem on Storage : Setting the value of 5106 exceeded the quota. Powyższy przykład pochodzi z przeglądarki Google Chrome i prezentuje błąd, jaki wystąpi po przekroczeniu limitu na danym Storage. Ilość przestrzeni jaką mamy dostępną różni się dla każdej przeglądarki, obecnie (rok 2014) minimalna pojemność jaką oferuje część przeglądarek to 5 MiB. Oznacza to, że nawet jeżeli przeglądarka, na której jest uruchomiony nasz skrypt posiada większy limit, to i tak nie dowiemy się o tym, dopóki nie przekroczymy tego limitu. By poznać prawdziwą pojemność instancji Storage z jakiej korzystamy, możemy zawsze użyć argumentu siły i w pętli zapełnić całe Storage, po czym obliczyć zajętą przestrzeń, gdy wystąpi błąd związany z przekroczeniem limitu pojemności. Poniższa funkcja getstoragequotadirty prezentuje sposób, w jaki można to zrobić. 21

22 // Nasza funkcja przyjmuje dwa argumenty: // - storage - Instancja Storage, którą chcemy zbadać // - pref - prefix jakiego użyć dla kluczy // - chunksize - długość ciągu znaków jaka ma zostać // zapisana z każdym użyciem metody // setitem, aż do zapełnienia Storage. // Domyślnie 512 znaków. function getstoragequotadirty( storage, pref, chunksize ) { pref = pref ; chunksize = chunksize 512; lastchunksize = 0; var quota = 0; var keys = []; try { var n = 0, s = new Array( chunksize + 1 ).join( 1 ); while ( 1 ) {/ lastchunksize = s.length; lastchunksize += n.tostring().length; storage.setitem( pref + n, s ); keys.push( pref + n ); n++; catch (e) { var key; for ( var i = 0; i < storage.length; ++i ) { key = storage.key( i ); quota += key.length; quota += storage.getitem( key ).length; quota += lastchunksize; keys.foreach(function( key ) { storage.removeitem( key ); ); return quota; console.log( Limit wynosi około: %s MiB, getstoragequotadirty( localstorage ) / 1024 / 1024 ); Skrypt ten wypełnia całą wolną przestrzeń wygenerowanymi danymi, aż do momentu wystąpienia błędu o przekroczeniu dostępnego limitu. Następnie liczy ile zdołał zapełnić przestrzeni oraz dodaje do uzyskanej liczby długość ciągu znaków, którego nie udało się zapisać. Na koniec skrypt usuwa wszystkie elementeny z Storage, które sam dodał, natomiast nie usuwa danych, które istniały już wcześniej. By uniknąć sytuacji (a raczej zmniejszyć jej prawdopodobieństwo), w której nasz skrypt nadpisze istniejący już element w Storage, użyliśmy znaku ASCII jako prefixu. Mało prawdopodobne jest byśmy użyli tego (lub innego) znaku jako klucza do przechowywania wartościowych danych. Funkcja na koniec zwróci nam ilość znaków jaka się mieści w Storage. Jest to wartość przybliżona, gdyż podczas zapisu ostatniego ciągu znaków do Storage wystąpił błąd, więc jeżeli ciąg ten miał długość 516 znaków, to nie wiemy czy limit został przekroczony już przy pierwszym znaku, gdzieś w połowie czy na samym końcu. Jest to zatem też przyczyna dlaczego zapisujemy dane w małych częściach po 516 znaków, im mniejsza ilość znaków, którą zapisujemy do Storage na raz, tym precyzyjniejszy wynik badania pojemności Storage. Z drugiej strony, przy mniejszym ciągu znaków sam zapis do Storage potrwa w pętli o wiele dłużej, gdyż wywołań metody setitem nastąpi o wiele więcej nim wystąpi błąd z przekroczeniem limitu, co wiąże się z tym iż interfejs przeglądarki przestanie być responsywny na czas wywoływania pętli. 22

23 Więcej informacji na: it.pwn.pl Grafika 3D czasu rzeczywistego Nowoczesny OpenGL Z książki dowiesz się: jak tworzyć aplikacje korzystające z grafiki trójwymiarowej tworzonej za pomocą OpenGL, w tym z nowych wersji tej biblioteki nauczysz się programować shadery w GLSL poznasz teoretyczne podstawy rachunku macierzy niezbędne w grafice trójwymiarowej poznasz model oświetlenia Phonga i nauczysz się go implementować Powinieneś znać: podstawy programowania w C++ w tym programowania obiektowego podstawową wiedzę o programowaniu dla systemu Windows Box2D: fizyczny świat w pudełku Z książki dowiesz się: jak napisać porządną, zgodną z obecnymi standardami, grę na swój smartfona jak zaimplementować funkcjonalność podobną do zastosowanej w sztandarowych tytułach jak tworzyć własne rozwiązania z użyciem fizyki jak wzbogacić swój program o fizykę Powinieneś znać: C++ w stopniu podstawowym środowisko Microsoft Visual Studio podstawy mechaniki Newtona OpenCL Akceleracja GPU w praktyce Z książki dowiesz się: jak korzystać z technologii OpenCL jak tworzyć własne jądra obliczeniowe jak przetwarzać grafikę za pomocą wbudowanych możliwości OpenCL Powinieneś znać: wybrane pojęcia algebry liniowej, m.in. macierze, wektory podstawy języków C, C++ oraz Python środowisko IDE, np. Visual Studio Android w praktyce. Projektowanie aplikacji Z książki dowiesz się: jak utworzyć mobilną aplikację z systemem Android jak działa aplikacja na urządzeniu mobilnym (cykl życia) jak utworzyć projekt rozbudowanej aplikacji jak projektować podstawowe i rozbudowane GUI dla własnych aplikacji jak zaprojektować i zaimplementować własną relacyjną bazę danych SQLite jak pobierać i zapisywać dane do bazy danych SQLite z wykorzystaniem języka SQL jak tworzyć rozbudowaną grafikę 2D oraz elementy grafiki 3D jak skonfigurować i zastosować emulator urządzenia mobilnego AVD 23

24 Rozszerzanie Storage o nowe możliwości Własne API Jak już wcześniej zostało to opisane, nie możemy rozszerzyć bezpośrednio obiektu Storage (np. localstorage) o nowe funkcje, gdyż nowa właściwość czy metoda zostanie potraktowana jako kolejna dana do zapisu w Storage. By obejść to zachowanie, musimy najpierw opakować oryginalne API Storage w nasz obiekt z naszymi własnymi metodami i właściwościami. Po stworzeniu własnego API nie będzie możliwe zapisanie danych do Storage poprzez przypisanie właściwości do obiektu, tak jak to ma miejsce w przypadku natywnej instancji Storage. Jest to jednocześnie minus jak i plus takiego rozwiązania. Mamy, co prawda, mniejsze możliwości, ale jednak zyskujemy stabilny, z góry określony punkt dostępu i manipulacji danych. Fundamenty W pierwszej kolejności nasz cały kod umieścimy w samowywołującej się funkcji, dzięki czemu unikniemy zaśmiecenia globalnej przestrzeni. Nasza klasa będzie nosić nazwę Store, jej możliwości będą na razie niewielkie i ograniczymy się głównie do opakowania istniejącego natywnego API instancji Storage. Konstruktor naszej klasy będzie odpowiedzialny jedynie za konfigurowanie właściwości nowo utworzonego obiektu.!function() { strict ; var Store = function( options ) { options = options {; for ( var i in options ) { this[ i ] = options[ i ]; W prototypie natomiast umieścimy metody, które odwołują się do istniejących już metod dostępnych w natywnym API Storage. Dodatkowo na końcu umieścimy nową metodę each, które nie posiada swojego odpowiednika w istniejącym API. Jak łatwo się domyślić służy ona do iteracji po elementach znajdujących się w instancji Storage. Jako jedyny parametr będzie przyjmowana funkcja, które będzie wywołana na każdym z elementów z osoba. Podczas wywołania tej funkcji, jej argumentami będą takie dane jak: wartość elementów, nazwa klucza, pod którym element został zapisany oraz dodatkowo indeks elementu. 24

25 Store.prototype = { storage: window.localstorage, set: function( key, value ) { this.storage.setitem( key, value );, get: function( key ) { return this.storage.getitem( key );, remove: function( key ) { this.storage.removeitem( key );, clear: function() { this.storage.clear();, key: function( index ) { return this.storage.key( index );, each: function( fn ) { if ( typeof fn === function ) { for ( var i = 0, key; i < this.storage.length; ++i ) { key = this.storage.key( i ); fn( this.storage.getitem( key ), key, i ); Tak skonstruowaną klasę od razu wykorzystamy poprzez stworzenie dwóch jej instancji. Każda z instancji będzie odpowiadała natywnym instancją dostępnym w przeglądarce, tj.: localstorage oraz sessionstorage. Obie instancje następnie udostępnimy pod wspólnym obiektem store o zasięgu globalnym. window.store = { local: new Store({ storage: window.localstorage ), session: new Store({ storage: window.sessionstorage ) (); 25

26 Przykład użycia store.local.set( foo1, bar1 ); store.local.set( foo2, bar1 ); store.local.set( foo3, bar1 ); var msg = "Item key: %s, value: %s, index: %s ; store.local.each(function( key, value, index ) { console.log( msg, key, value, index ); ); store.local.clear(); Przestrzenie nazw Załóżmy, że w naszej aplikacji umieściliśmy kilka niezależnych skryptów, z których każdy będzie musiał w pewnym momencie wyczyścić dane zapisane w Storage. Jeśli jeden ze skryptów za pomocą metody clear() wyczyści zapisane przez siebie dane, może okazać się, że dane zapisane przez drugi skrypt także zostaną usunięte, mimo iż nie powinny, a ich brak może doprowadzić do problemów w działaniu aplikacji. Natywne API Storage nie oferuje tworzenia własnych instancji Storage ani też żadnego wbudowanego mechanizmu przestrzeni nazw. Mechanizm taki uchroniłby nas przed wcześniej opisanym przypadkiem. Musimy zatem sami zadbać o taki mechanizm, który zadbałby o to żeby tylko określony zbiór danych został wyczyszczony, a nie cała zawartość instancji Storage. Główne założenia mechanizmu: Odrębne przestrzenie, o unikalnej nazwie W obrębie pojedynczej przestrzeni elementy muszą posiadać unikatowy klucz Klucze elementów mogą jednak występować w innych przestrzeniach Zmiany w jednej przestrzeni nie wpływają na zawartość innych przestrzeni By spełnić te wymagania musimy zatem zapewnić: Możliwość tworzenia nowych instancji klasy Store Wyposażyć instancje Store w unikatowe id Id każdej instancji będzie musiało być ciągiem znaków, zawierającym znaki 0-9, a-z, A-Z oraz _. By nie kolidować z istniejącymi danymi, zapisanymi poza przestrzenią nazw oferowaną przez klasę Store, każdy z elementów zapisany w Storage z pomocą klasy Store będzie posiadał prefiksowany klucz. By zmniejszyć prawdopodobieństwo wystąpienia kolizji z istniejącymi kluczami, użyjemy jako prefiksa znaku ASCII (U+2707 TAPE DRIVE). Prefiks taki zmniejszy prawodpodobieństwo wystąpienia kolizji znacząco. Pełna nazwa klucza będzie posiadała postać prefix:idinstancji:nazwaklucza, czyli np. :myid:mykey. Taka postać klucza będzie jednak używana prytwanie w klasie Store, natomiast manipulacja danymi poprzez udostępniony interfejs nadal będzie odbywać się za pomocą prostej nazwy klucza, np. mykey. 26

27 By rozbudować naszą klasę Store o funkcjonalność przestrzeni nazw, musimy najpierw stworzyć kilka przydatnych obiektów oraz stałych. Każdą z utworzonych instancji Store, będziemy przetrzymywać w prywatnym obiekcie _instances, niedostępnym na zewnątrz. By zapewnić unikalność id każdej instancji, użyjemy prostego walidatora w postaci wyrażenia regularnego. Sprawdzi ono czy podane id posiada jedynie znaki z przedziału 0-9, a-z, A-Z oraz _.!function() { strict ; var _instances = {; var ID_VALIDATOR = /\W/gi; var PREFIX = ; var SEPARATOR = : ; var ERR_NOID = Store instance needs to have a unique id ; var ERR_TKNID = Given Store id is already taken. ; var ERR_INVID = Given id is invalid. Id should match + any alphanumeric character from the + basic Latin alphabet, including the + underscore [A-Za-z0-9_]. ; W obiekcie utlis, będziemy przetrzymywać funkcje do manipulowania postaciami kluczy: getprefix - Zwraca prefiks dla danej instancji Store. Przyjmuje jeden argument: id. addprefix - Dodaje prefiks do podanego klucza. Przyjmuje dwa argumenty: key oraz id. removeprefix - Usuwa prefiks z klucza. Przyjmuje dwa argumenty: key oraz id. iskeyprefixed - Sprawdza czy dany klucz posiada już nałożony prefiks. Przyjmuje dwa argumenty: key oraz id. var utils = { addprefix: function( key, id ) { return this.getprefix( id ) + key;, removeprefix: function( key, id ) { return key.replace( this.getprefix( id ), );, getprefix: function( id ) { return [ PREFIX, id, ].join( SEPARATOR );, iskeyprefixed: function( key, id ) { var p = this.getprefix( id ); return key.substr( 0, p.length ) === p; Do konstruktora dodajemy walidację podanego id. Walidujemy id pod względem poprawności formatu oraz jego unikalności. Gdy będziemy już pewni, że instancja posiada poprawne i unikalne id, będziemy mogli ją zapamiętać w obiekcie _instances. 27

28 var Store = function( options ) { options = options {; for ( var i in options ) { this[ i ] = options[ i ]; if ( typeof this.id === undefined this.id === null ) { throw new Error( ERR_NOID ); if ( this.id in _instances ) { throw new Error( ERR_TKNID ); if ( ID_VALIDATOR.test( this.id ) ) { throw new Error( ERR_INVID ); _instances[ this.id ] = this; Każdą z wcześniej zaimplementowanych metod musimy wzbogacić o obsługę prefiksów. Wcześniej posiadaliśmy jedynie dwie instancje Store - local oraz session, dlatego prefiksy i unikalne id nie były koniecznie, gdyż już z założenia localstorage oraz sessionstorage posiadają niezależne zestawy kluczy, tym razem jednak umożliwimy tworzenie własnych instancji. Świat poza jquery W książce przedstawiono alternatywne do jquery biblioteki skryptowe, dość powszechnie już używane w nowych projektach, których znajomość jest coraz częściej poszukiwana na rynku pracy. Z książki dowiesz się: jakie masz możliwości rozwoju, gdy czujesz, że jquery to za mało jakie biblioteki skryptowe są teraz popularne jak poprawić tworzony do tej pory kod jak tworzyć strony typu Single Page App Powinieneś znać: HTML (najlepiej HTML5) Java Script i jquery Więcej informacji na: it.pwn.pl 28

29 Store.prototype = { id: null, storage: window.localstorage, set: function( key, value ) { var pkey = utils.addprefix( key, this.id ); this.storage.setitem( pkey, value );, get: function( key ) { var pkey = utils.addprefix( key, this.id ); return this.storage.getitem( pkey );, remove: function( key ) { var pkey = utils.addprefix( key, this.id ); this.storage.removeitem( pkey );, clear: function() { var self = this; this.keys().foreach(function( key ) { self.remove( key ); );, keys: function() { var keys = []; for ( var i = 0, key; i < this.storage.length; ++i ) { key = this.storage.key( i ); if ( utils.iskeyprefixed( key, this.id ) ) { keys.push( utils.removeprefix( key, this.id ) ); return keys;, each: function( fn ) { if ( typeof fn === function ) { for ( var i = 0, key; i < this.storage.length; ++i ) { key = this.storage.key( i ); if ( utils.iskeyprefixed( key, this.id ) ) { fn( this.storage.getitem( key ), utils.removeprefix( key, this.id ), i ); Podczas zapisu i odczytu danych musimy dodać prefiks dla klucza. Natomiast jedynym miejscem, w którym usuwanie prefiksu z klucza może być do czegokolwiek przydatne, jest moment, w którym musimy zaprezentować na zewnątrz dany klucz w czystej postaci. Ma to miejsce podczas iteracji po wszystkich elementach należących do danej instancji, gdzie będziemy zwracać informacje na temat danego elementu w Storage. Mechanizm ten jest widoczny w dwóch metodach - keys - zwracającej zbiór wszystkich kluczy dostępnych w danej instancji, oraz each - metodzie iterującej po wszystkich elementach i wywołującej operacje na każdym z elementów. Obie metody udostępniają informację na temat danego elementu, w tym także nazwę klucza w czystej postaci, bez prefiksa ani id instancji. 29

30 window.store = { TYPE_LOCAL: local, TYPE_SESSION: session, local: new Store({ id: locdef, storage: window.localstorage ), session: new Store({ id: sessdef, storage: window.sessionstorage ), create: function( id, type, options ) { options = options {; options.id = id; if (!type type === store.type_local ) { options.storage = window.localstorage; else if ( type === store.type_session ) { options.storage = window.sessionstorage; (); return new Store( options ); Na zewnątrz udostępniamy także możliwość tworzenia nowych instancji Store o dwóch typach: local oraz session. Całość rozwiązania posiada dwie główne cechy: 1. Możemy manipulować niezależnymi zbiorami danych. Każdy ze zbiorów znajduje się we własnej przestrzeni. Dane ze zbioru A nie mają żadnego wpływu na dane ze zbioru B, nawet jeżeli dane w zbiorze A i B posiadają identyczne nazwy kluczy. 2. Każdy ze zbiorów może potencjalnie zająć całą wolna przestrzeń, nie pozostawiając innym zbiorom żadnego miejsca na zapis danych. To samo tyczy się także danych zapisanych bezpośrednio w Storage poza określonym zbiorem. Rozwiązaniem problemu z punktu drugiego będzie wprowadzenie ograniczeń w postaci maksymalnej pojemności danej przestrzeni. Nie będzie to jednak sposób łatwy, gdyż nie będziemy mogli pozwolić sobie na przeliczanie zajętej przestrzeni poprzez iteracje po wszystkich elementach danej przestrzeni, podczas każdej zmiany w Store. Więcej o tym zagadnieniu oraz jak sobie z nim poradzić w kolejnym podrozdziale. 30

Programowanie obiektowe

Programowanie obiektowe Laboratorium z przedmiotu Programowanie obiektowe - zestaw 02 Cel zajęć. Celem zajęć jest zapoznanie z praktycznymi aspektami projektowania oraz implementacji klas i obiektów z wykorzystaniem dziedziczenia.

Bardziej szczegółowo

Wprowadzenie do projektu QualitySpy

Wprowadzenie do projektu QualitySpy Wprowadzenie do projektu QualitySpy Na podstawie instrukcji implementacji prostej funkcjonalności. 1. Wstęp Celem tego poradnika jest wprowadzić programistę do projektu QualitySpy. Będziemy implementować

Bardziej szczegółowo

Ćwiczenie: JavaScript Cookies (3x45 minut)

Ćwiczenie: JavaScript Cookies (3x45 minut) Ćwiczenie: JavaScript Cookies (3x45 minut) Cookies niewielkie porcje danych tekstowych, które mogą być przesyłane między serwerem a przeglądarką. Przeglądarka przechowuje te dane przez określony czas.

Bardziej szczegółowo

Podstawy JavaScript ćwiczenia

Podstawy JavaScript ćwiczenia Podstawy JavaScript ćwiczenia Kontekst:

Bardziej szczegółowo

znajdowały się różne instrukcje) to tak naprawdę definicja funkcji main.

znajdowały się różne instrukcje) to tak naprawdę definicja funkcji main. Część XVI C++ Funkcje Jeśli nasz program rozrósł się już do kilkudziesięciu linijek, warto pomyśleć o jego podziale na mniejsze części. Poznajmy więc funkcje. Szybko się przekonamy, że funkcja to bardzo

Bardziej szczegółowo

Sesje, ciasteczka, wyjątki. Ciasteczka w PHP. Zastosowanie cookies. Sprawdzanie obecności ciasteczka

Sesje, ciasteczka, wyjątki. Ciasteczka w PHP. Zastosowanie cookies. Sprawdzanie obecności ciasteczka Sesje, ciasteczka, wyjątki Nie sposób wyobrazić sobie bez nich takich podstawowych zastosowań, jak logowanie użytkowników czy funkcjonowanie koszyka na zakupy. Oprócz tego dowiesz się, czym są wyjątki,

Bardziej szczegółowo

TOPIT Załącznik nr 3 Programowanie aplikacji internetowych

TOPIT Załącznik nr 3 Programowanie aplikacji internetowych Szkolenie przeznaczone jest dla osób chcących poszerzyć swoje umiejętności o tworzenie rozwiązań internetowych w PHP. Zajęcia zostały przygotowane w taki sposób, aby po ich ukończeniu można było rozpocząć

Bardziej szczegółowo

akademia androida Składowanie danych część VI

akademia androida Składowanie danych część VI akademia androida Składowanie danych część VI agenda 1. SharedPreferences. 2. Pamięć wewnętrzna i karta SD. 3. Pliki w katalogach /res/raw i /res/xml. 4. Baza danych SQLite. 5. Zadanie. 1. SharedPreferences.

Bardziej szczegółowo

Dokumentacja techniczna API systemu SimPay.pl

Dokumentacja techniczna API systemu SimPay.pl Wprowadzenie Dokumentacja techniczna API systemu SimPay.pl Wersja 1.0 z dnia 24.03.2015 r. API serwisu SimPay.pl opiera się o danych wysyłanych i zwracanych w formie JSON. W przypadku napotkania jakiegokolwiek

Bardziej szczegółowo

Programowanie obiektowe i zdarzeniowe wykład 4 Kompozycja, kolekcje, wiązanie danych

Programowanie obiektowe i zdarzeniowe wykład 4 Kompozycja, kolekcje, wiązanie danych Programowanie obiektowe i zdarzeniowe wykład 4 Kompozycja, kolekcje, wiązanie danych Obiekty reprezentują pewne pojęcia, przedmioty, elementy rzeczywistości. Obiekty udostępniają swoje usługi: metody operacje,

Bardziej szczegółowo

Rozdział 4 KLASY, OBIEKTY, METODY

Rozdział 4 KLASY, OBIEKTY, METODY Rozdział 4 KLASY, OBIEKTY, METODY Java jest językiem w pełni zorientowanym obiektowo. Wszystkie elementy opisujące dane, za wyjątkiem zmiennych prostych są obiektami. Sam program też jest obiektem pewnej

Bardziej szczegółowo

Rys.2.1. Drzewo modelu DOM [1]

Rys.2.1. Drzewo modelu DOM [1] 1. CEL ĆWICZENIA Celem ćwiczenia jest przedstawienie możliwości wykorzystania języka JavaScript do tworzenia interaktywnych aplikacji działających po stronie klienta. 2. MATERIAŁ NAUCZANIA 2.1. DOM model

Bardziej szczegółowo

Laboratorium 7 Blog: dodawanie i edycja wpisów

Laboratorium 7 Blog: dodawanie i edycja wpisów Laboratorium 7 Blog: dodawanie i edycja wpisów Dodawanie nowych wpisów Tworzenie formularza Za obsługę formularzy odpowiada klasa Zend_Form. Dla każdego formularza w projekcie tworzymy klasę dziedziczącą

Bardziej szczegółowo

Funkcje i instrukcje języka JavaScript

Funkcje i instrukcje języka JavaScript Funkcje i instrukcje języka JavaScript 1. Cele lekcji a) Wiadomości Uczeń : zna operatory i typy danych języka JavaScript, zna konstrukcję definicji funkcji, zna pętlę If i For, Do i While oraz podaje

Bardziej szczegółowo

JavaScript - korzenie

JavaScript - korzenie JavaScript - korzenie Dowiesz się o historii JavaScript, jego dialektach i wersjach. Poznasz złe i dobre strony języka, a gdy zaskoczy Cię działanie któregoś z jego elementów, będziesz wiedział, gdzie

Bardziej szczegółowo

Programowanie w Sieci Internet Python - c. d. Kraków, 28 listopada 2014 r. mgr Piotr Rytko Wydział Matematyki i Informatyki

Programowanie w Sieci Internet Python - c. d. Kraków, 28 listopada 2014 r. mgr Piotr Rytko Wydział Matematyki i Informatyki Programowanie w Sieci Internet Python - c. d. Kraków, 28 listopada 2014 r. mgr Piotr Rytko Wydział Matematyki i Informatyki Co dziś będziemy robić Uwierzytelnianie użytkowników, Obiekt session, Silniki

Bardziej szczegółowo

Jak używać funkcji prostego udostępniania plików do udostępniania plików w systemie Windows XP

Jak używać funkcji prostego udostępniania plików do udostępniania plików w systemie Windows XP Jak używać funkcji prostego udostępniania plików do udostępniania plików w systemie Windows XP System Windows XP umożliwia udostępnianie plików i dokumentów innym użytkownikom komputera oraz innym użytkownikom

Bardziej szczegółowo

Lekcja 10. Uprawnienia. Dołączanie plików przy pomocy funkcji include() Sprawdzanie, czy plik istnieje przy pmocy funkcji file_exists()

Lekcja 10. Uprawnienia. Dołączanie plików przy pomocy funkcji include() Sprawdzanie, czy plik istnieje przy pmocy funkcji file_exists() Paweł Gmys PHP strona 1 Lekcja 10 Uprawnienia Aby skrypt PHP mógł odwołać się do pliku, musi mieć odpowiednie uprawnienia. Szczegóły są zależne od serwera. Najczęściej chyba skrypt ma uprawnienia takie,

Bardziej szczegółowo

Dokumentacja smsapi wersja 1.4

Dokumentacja smsapi wersja 1.4 Dokumentacja smsapi wersja 1.4 1. Wprowadzenie Platforma smsapi została skierowana do użytkowników chcących rozbudować swoje aplikacje o system wysyłania smsów. Aplikacja ta w prosty sposób umożliwia integrację

Bardziej szczegółowo

REFERAT PRACY DYPLOMOWEJ

REFERAT PRACY DYPLOMOWEJ REFERAT PRACY DYPLOMOWEJ Temat pracy: Projekt i implementacja środowiska do automatyzacji przeprowadzania testów aplikacji internetowych w oparciu o metodykę Behavior Driven Development. Autor: Stepowany

Bardziej szczegółowo

Języki skryptowe w programie Plans

Języki skryptowe w programie Plans Języki skryptowe w programie Plans Warsztaty uŝytkowników programu PLANS Kościelisko 2010 Zalety skryptów Automatyzacja powtarzających się czynności Rozszerzenie moŝliwości programu Budowa własnych algorytmów

Bardziej szczegółowo

KORPORACYJNE SYSTEMY ZARZĄDZANIA INFORMACJĄ

KORPORACYJNE SYSTEMY ZARZĄDZANIA INFORMACJĄ KORPORACYJNE SYSTEMY ZARZĄDZANIA INFORMACJĄ Wykład 3 Katedra Inżynierii Komputerowej Jakub Romanowski jakub.romanowski@kik.pcz.pl POBIERANIE DANYCH C/AL Poniższe funkcje używane są do operacji pobierania

Bardziej szczegółowo

Programowanie w Sieci Internet JSP ciąg dalszy. Kraków, 9 stycznia 2015 r. mgr Piotr Rytko Wydział Matematyki i Informatyki

Programowanie w Sieci Internet JSP ciąg dalszy. Kraków, 9 stycznia 2015 r. mgr Piotr Rytko Wydział Matematyki i Informatyki Programowanie w Sieci Internet JSP ciąg dalszy Kraków, 9 stycznia 2015 r. mgr Piotr Rytko Wydział Matematyki i Informatyki Co dziś będziemy robić JSP tags, Używanie tagów, Custom tags, JSP objests, Obiekty

Bardziej szczegółowo

Platformy programistyczne:.net i Java L ABORATORIUM 7,8: HACKATHON - JTTT

Platformy programistyczne:.net i Java L ABORATORIUM 7,8: HACKATHON - JTTT Platformy programistyczne:.net i Java L ABORATORIUM 7,8: HACKATHON - JTTT O co chodzi? - Przypomnienie Hackathon - http://en.wikipedia.org/wiki/hackathon A hackathon is an event in which computer programmers

Bardziej szczegółowo

2 INSTALACJA OPROGRAMOWANIA. 3 3 GŁÓWNE OKNO PROGRAMU 3 4 MODUŁ OBSŁUGI ARCHIWUM 7

2 INSTALACJA OPROGRAMOWANIA. 3 3 GŁÓWNE OKNO PROGRAMU 3 4 MODUŁ OBSŁUGI ARCHIWUM 7 LUBUSKIE ZAKŁADY APARATÓW ELEKTRYCZNYCH LUMEL S.A. W ZIELONEJ GÓRZE PROGRAM DO KONFIGURACJI KONCENTRATORA DANYCH TYPU PD22 PD22Wiz.exe INSTRUKCJA OBSŁUGI Zielona Góra 2007 2 SPIS TREŚCI: 1 WSTĘP. 3 2 INSTALACJA

Bardziej szczegółowo

ASP.NET MVC. Podstawy. Zaawansowane programowanie internetowe Instrukcja nr 3

ASP.NET MVC. Podstawy. Zaawansowane programowanie internetowe Instrukcja nr 3 3 ASP.NET MVC Podstawy 1 1. Cel zajęć Celem zajęć jest zapoznanie się z podstawami ASP.NET MVC 2.0 Framework. 2. Zadanie Proszę zbudować prostą aplikację WWW przy zastosowaniu framework a ASP.NET MVC 2.0

Bardziej szczegółowo

Zaawansowane aplikacje internetowe

Zaawansowane aplikacje internetowe Zaawansowane aplikacje internetowe AJAX 1 Celem tego laboratorium jest pokazanie moŝliwości technologii AJAX. W ramach ćwiczeń zostanie zbudowana prosta aplikacja, przechwytująca kliknięcia uŝytkownika

Bardziej szczegółowo

Temat: Ułatwienia wynikające z zastosowania Frameworku CakePHP podczas budowania stron internetowych

Temat: Ułatwienia wynikające z zastosowania Frameworku CakePHP podczas budowania stron internetowych PAŃSTWOWA WYŻSZA SZKOŁA ZAWODOWA W ELBLĄGU INSTYTUT INFORMATYKI STOSOWANEJ Sprawozdanie z Seminarium Dyplomowego Temat: Ułatwienia wynikające z zastosowania Frameworku CakePHP podczas budowania stron internetowych

Bardziej szczegółowo

Ciekawym rozwiązaniem służącym do obsługi zdarzeń dla kilku przycisków w ramach jednej aktywności może być następujący kod:

Ciekawym rozwiązaniem służącym do obsługi zdarzeń dla kilku przycisków w ramach jednej aktywności może być następujący kod: 1. Listener dla przycisku. Ciekawym rozwiązaniem służącym do obsługi zdarzeń dla kilku przycisków w ramach jednej aktywności może być następujący kod: W linii 24 tworzymy globalną metodę mglobal_onclicklistener,

Bardziej szczegółowo

Wysyłanie pliku na serwer. Plik na serwerze.

Wysyłanie pliku na serwer. Plik na serwerze. Wysyłanie pliku na serwer Dzięki PHP możemy w łatwy i przyjemny sposób obsłużyć pliki uploadowane na serwer. Jednak, by prawidłowo wysłać plik, niezbędny będzie odpowiedni formularz HTML. Poniżej przedstawię

Bardziej szczegółowo

Specyfikacja techniczna. mprofi Interfejs API

Specyfikacja techniczna. mprofi Interfejs API Warszawa 09.04.2015. Specyfikacja techniczna mprofi Interfejs API wersja 1.0.2 1 Specyfikacja techniczna mprofi Interfejs API wersja 1.0.2 WERSJA DATA STATUTS AUTOR 1.0.0 10.03.2015 UTWORZENIE DOKUMENTU

Bardziej szczegółowo

Programowanie 3 - Funkcje, pliki i klasy

Programowanie 3 - Funkcje, pliki i klasy Instytut Informatyki Uniwersytetu Śląskiego Laborki funkcja; parametry funkcji; typ zwracany; typ void; funkcje bez parametrów; napis.length() - jako przykład funkcji. Zadania funkcja dodająca dwie liczby;

Bardziej szczegółowo

Podstawy Programowania 2

Podstawy Programowania 2 Podstawy Programowania 2 Laboratorium 7 Instrukcja 6 Object Pascal Opracował: mgr inż. Leszek Ciopiński Wstęp: Programowanie obiektowe a programowanie strukturalne. W programowaniu strukturalnym, któremu

Bardziej szczegółowo

Programowanie. programowania. Klasa 3 Lekcja 9 PASCAL & C++

Programowanie. programowania. Klasa 3 Lekcja 9 PASCAL & C++ Programowanie Wstęp p do programowania Klasa 3 Lekcja 9 PASCAL & C++ Język programowania Do przedstawiania algorytmów w postaci programów służą języki programowania. Tylko algorytm zapisany w postaci programu

Bardziej szczegółowo

Pliki. Operacje na plikach w Pascalu

Pliki. Operacje na plikach w Pascalu Pliki. Operacje na plikach w Pascalu ścieżka zapisu, pliki elementowe, tekstowe, operacja plikowa, etapy, assign, zmienna plikowa, skojarzenie, tryby otwarcia, reset, rewrite, append, read, write, buforowanie

Bardziej szczegółowo

Obiektowy PHP. Czym jest obiekt? Definicja klasy. Składowe klasy pola i metody

Obiektowy PHP. Czym jest obiekt? Definicja klasy. Składowe klasy pola i metody Obiektowy PHP Czym jest obiekt? W programowaniu obiektem można nazwać każdy abstrakcyjny byt, który programista utworzy w pamięci komputera. Jeszcze bardziej upraszczając to zagadnienie, można powiedzieć,

Bardziej szczegółowo

Instrukcja do programu Przypominacz 1.5

Instrukcja do programu Przypominacz 1.5 Instrukcja do programu Przypominacz 1.5 Program Przypominacz 1.5 pozwala w prosty sposób wykorzystać dane z systemu sprzedaży Subiekt GT do prowadzenia tzw. miękkiej windykacji poprzez wysyłanie kontrahentom

Bardziej szczegółowo

Zasady programowania Dokumentacja

Zasady programowania Dokumentacja Marcin Kędzierski gr. 14 Zasady programowania Dokumentacja Wstęp 1) Temat: Przeszukiwanie pliku za pomocą drzewa. 2) Założenia projektu: a) Program ma pobierać dane z pliku wskazanego przez użytkownika

Bardziej szczegółowo

Aplikacje Internetowe

Aplikacje Internetowe Aplikacje Internetowe ITA-103 Wersja 1 Warszawa, październik 2008 Spis treści Wprowadzenie i-4 Moduł 1 Podstawy HTML 1-1 Moduł 2 Kaskadowe Arkusze Stylów CSS 2-1 Moduł 3 Podstawy JavaScript 3-1 Moduł 4

Bardziej szczegółowo

Wprowadzenie do programowania

Wprowadzenie do programowania do programowania ITA-104 Wersja 1 Warszawa, Wrzesień 2009 ITA-104 do programowania Informacje o kursie Zakres tematyczny kursu Opis kursu Kurs przeznaczony jest do prowadzenia przedmiotu do programowania

Bardziej szczegółowo

media Blitz wydajne sytemy szablonów

media Blitz wydajne sytemy szablonów Blitz wydajne sytemy szablonów Dlaczego stosować szablony? MVC Kontroler Model Widok Co to jest Blitz? Rozszerzenie PHP stworzone przez Alexey A. Rybak a. Regularnie rozwijany od 2005 roku. Szybki i lekki

Bardziej szczegółowo

Wyjątki. Streszczenie Celem wykładu jest omówienie tematyki wyjątków w Javie. Czas wykładu 45 minut.

Wyjątki. Streszczenie Celem wykładu jest omówienie tematyki wyjątków w Javie. Czas wykładu 45 minut. Wyjątki Streszczenie Celem wykładu jest omówienie tematyki wyjątków w Javie. Czas wykładu 45 minut. Wydaje się, że żaden użytkownik oprogramowania nie lubi, kiedy stosowany program nagle zawiesza się,

Bardziej szczegółowo

Technologie sieciowe Sprawozdanie z labolatorium. Lista 5

Technologie sieciowe Sprawozdanie z labolatorium. Lista 5 Politechnika Wrocławska Wydział Podstawowych Problemów Techniki Technologie sieciowe Sprawozdanie z labolatorium Lista 5 Autor: Piotr Kosytorz IIrokInf. indeks: 166174 Prowadzący: dr inż. Łukasz Krzywiecki

Bardziej szczegółowo

Kurs walut. Specyfikacja projektu. Marek Zając 2013-12-16

Kurs walut. Specyfikacja projektu. Marek Zając 2013-12-16 Kurs walut Specyfikacja projektu Marek Zając 2013-12-16 Spis treści 1. Podsumowanie... 2 1.1 Wstęp... 2 1.2 Projekt interfejsu... 2 1.2.1 Rozmiar głównego okna... 2 2. Słownik pojęć... 2 2.1 Definicja

Bardziej szczegółowo

Instrukcja do programu Przypominacz 1.6

Instrukcja do programu Przypominacz 1.6 Instrukcja do programu Przypominacz 1.6 Program Przypominacz 1.6 pozwala w prosty sposób wykorzystać dane z systemu sprzedaży Subiekt GT do prowadzenia tzw. miękkiej windykacji poprzez wysyłanie kontrahentom

Bardziej szczegółowo

Automater.pl zdalne tworzenie i zarządzanie transakcjami dokumentacja API wersja 0.1

Automater.pl zdalne tworzenie i zarządzanie transakcjami dokumentacja API wersja 0.1 Dokumentacja API 0.1 Automater.pl zdalne tworze i zarządza transakcjami dokumentacja API wersja 0.1 Automater sp. z o.o., ul. Belgradzka 4/42, 02-793 Warszawa 2 1. Wstęp System Automater.pl udostępnia

Bardziej szczegółowo

Scenariusz zajęć. Moduł VI. Projekt Gra logiczna zgadywanie liczby

Scenariusz zajęć. Moduł VI. Projekt Gra logiczna zgadywanie liczby Scenariusz zajęć Moduł VI Projekt Gra logiczna zgadywanie liczby Moduł VI Projekt Gra logiczna zgadywanie liczby Cele ogólne: przypomnienie i utrwalenie poznanych wcześniej poleceń i konstrukcji języka

Bardziej szczegółowo

Co to są relacyjne bazy danych?

Co to są relacyjne bazy danych? Co to są relacyjne bazy danych? Co to są relacyjne bazy danych? O Są to zbiory danych pogrupowane w tabele o strukturze: kolejne kolumny określają kolejne porcje informacji potrzebne dla każdego wystąpienia,

Bardziej szczegółowo

Komunikator internetowy w C#

Komunikator internetowy w C# PAŃSTWOWA WYśSZA SZKOŁA ZAWODOWA W ELBLĄGU INSTYTUT INFORMATYKI STOSOWANEJ Sprawozdanie Komunikator internetowy w C# autor: Artur Domachowski Elbląg, 2009 r. Komunikacja przy uŝyciu poczty internetowej

Bardziej szczegółowo

Algorytm. a programowanie -

Algorytm. a programowanie - Algorytm a programowanie - Program komputerowy: Program komputerowy można rozumieć jako: kod źródłowy - program komputerowy zapisany w pewnym języku programowania, zestaw poszczególnych instrukcji, plik

Bardziej szczegółowo

Strumienie, pliki. Sortowanie. Wyjątki.

Strumienie, pliki. Sortowanie. Wyjątki. Strumienie, pliki. Sortowanie. Wyjątki. Operacje I/O w Javie Serializacja Zapisuje całą klasę Plik binarny Delimiter nieokreślony Nie da się podglądać Pliki tekstowe Zapisuje wybrane informacje Plik tekstowy

Bardziej szczegółowo

Gatesms.eu Mobilne Rozwiązania dla biznesu

Gatesms.eu Mobilne Rozwiązania dla biznesu Mobilne Rozwiązania dla biznesu SPECYFIKACJA TECHNICZNA WEB API-USSD GATESMS.EU wersja 0.9 Opracował: Gatesms.eu Spis Historia wersji dokumentu...3 Bezpieczeństwo...3 Wymagania ogólne...3 Mechanizm zabezpieczenia

Bardziej szczegółowo

Kurs WWW. Paweł Rajba. pawel@ii.uni.wroc.pl http://pawel.ii.uni.wroc.pl/

Kurs WWW. Paweł Rajba. pawel@ii.uni.wroc.pl http://pawel.ii.uni.wroc.pl/ Paweł Rajba pawel@ii.uni.wroc.pl http://pawel.ii.uni.wroc.pl/ Spis treści Wprowadzenie Automatyczne ładowanie klas Składowe klasy, widoczność składowych Konstruktory i tworzenie obiektów Destruktory i

Bardziej szczegółowo

Budowa aplikacji ASP.NET współpracującej z bazą dany do obsługi przesyłania wiadomości

Budowa aplikacji ASP.NET współpracującej z bazą dany do obsługi przesyłania wiadomości Budowa aplikacji ASP.NET współpracującej z bazą dany do obsługi przesyłania wiadomości część 2 Zaprojektowaliśmy stronę dodaj_dzial.aspx proszę jednak spróbować dodać nowy dział nie podając jego nazwy

Bardziej szczegółowo

Programowanie na poziomie sprzętu. Programowanie w Windows API

Programowanie na poziomie sprzętu. Programowanie w Windows API Programowanie w Windows API Windows API Windows Application Programming Interface (API) to zestaw funkcji systemu operacyjnego Windows, które umożliwiają aplikacjom korzystanie z wszystkich usług systemu.

Bardziej szczegółowo

Temat 1. Podstawy Środowiska Xcode i wprowadzenie do języka Objective-C

Temat 1. Podstawy Środowiska Xcode i wprowadzenie do języka Objective-C Temat 1. Podstawy Środowiska Xcode i wprowadzenie do języka Objective-C Wymagana wiedza wstępna: 1) Student musi 1) Znać język C 2) Znać zasady zarządzania pamięcią w komputerze 3) Znać pojecie wskaźnika

Bardziej szczegółowo

Informacja o języku. Osadzanie skryptów. Instrukcje, komentarze, zmienne, typy, stałe. Operatory. Struktury kontrolne. Tablice.

Informacja o języku. Osadzanie skryptów. Instrukcje, komentarze, zmienne, typy, stałe. Operatory. Struktury kontrolne. Tablice. Informacja o języku. Osadzanie skryptów. Instrukcje, komentarze, zmienne, typy, stałe. Operatory. Struktury kontrolne. Tablice. Język PHP Język interpretowalny, a nie kompilowany Powstał w celu programowania

Bardziej szczegółowo

Tworzenie Stron Internetowych. odcinek 10

Tworzenie Stron Internetowych. odcinek 10 Tworzenie Stron Internetowych odcinek 10 JavaScript JavaScript (ECMAScript) skryptowy język programowania powszechnie używany w Internecie. Skrypty JS dodają do stron www interaktywność i funkcjonalności,

Bardziej szczegółowo

API transakcyjne BitMarket.pl

API transakcyjne BitMarket.pl API transakcyjne BitMarket.pl Wersja 20140402 1. Sposób łączenia się z API... 2 1.1. Klucze API... 2 1.2. Podpisywanie wiadomości... 2 1.3. Parametr tonce... 2 1.4. Limity zapytań... 3 1.5. Odpowiedzi

Bardziej szczegółowo

Cw.12 JAVAScript w dokumentach HTML

Cw.12 JAVAScript w dokumentach HTML Cw.12 JAVAScript w dokumentach HTML Wstawienie skryptu do dokumentu HTML JavaScript jest to interpretowany, zorientowany obiektowo, skryptowy język programowania.skrypty Java- Script mogą być zagnieżdżane

Bardziej szczegółowo

JAVAScript w dokumentach HTML (1) JavaScript jest to interpretowany, zorientowany obiektowo, skryptowy język programowania.

JAVAScript w dokumentach HTML (1) JavaScript jest to interpretowany, zorientowany obiektowo, skryptowy język programowania. IŚ ćw.8 JAVAScript w dokumentach HTML (1) JavaScript jest to interpretowany, zorientowany obiektowo, skryptowy język programowania. Skrypty JavaScript są zagnieżdżane w dokumentach HTML. Skrypt JavaScript

Bardziej szczegółowo

Systemy baz danych w zarządzaniu przedsiębiorstwem. W poszukiwaniu rozwiązania problemu, najbardziej pomocna jest znajomość odpowiedzi

Systemy baz danych w zarządzaniu przedsiębiorstwem. W poszukiwaniu rozwiązania problemu, najbardziej pomocna jest znajomość odpowiedzi Systemy baz danych w zarządzaniu przedsiębiorstwem W poszukiwaniu rozwiązania problemu, najbardziej pomocna jest znajomość odpowiedzi Proces zarządzania danymi Zarządzanie danymi obejmuje czynności: gromadzenie

Bardziej szczegółowo

Systemy wirtualnej rzeczywistości. Komponenty i serwisy

Systemy wirtualnej rzeczywistości. Komponenty i serwisy Uniwersytet Zielonogórski Instytut Sterowania i Systemów Informatycznych Systemy wirtualnej rzeczywistości Laboratorium Komponenty i serwisy Wstęp: W trzeciej części przedstawione zostaną podstawowe techniki

Bardziej szczegółowo

Java - tablice, konstruktory, dziedziczenie i hermetyzacja

Java - tablice, konstruktory, dziedziczenie i hermetyzacja Java - tablice, konstruktory, dziedziczenie i hermetyzacja Programowanie w językach wysokiego poziomu mgr inż. Anna Wawszczak PLAN WYKŁADU zmienne tablicowe konstruktory klas dziedziczenie hermetyzacja

Bardziej szczegółowo

Co to jest NODE.JS? Nowoczesne środowisko programistyczne

Co to jest NODE.JS? Nowoczesne środowisko programistyczne Node.js Co to jest NODE.JS? Nowoczesne środowisko programistyczne Środowisko programistyczne w sensie zestawu gotowych klas i metod których można używać do przygotowania własnych skalowalnych i wydajnych

Bardziej szczegółowo

Tworzenie stron internetowych z wykorzystaniem HTM5, JavaScript, CSS3 i jquery. Łukasz Bartczuk

Tworzenie stron internetowych z wykorzystaniem HTM5, JavaScript, CSS3 i jquery. Łukasz Bartczuk Tworzenie stron internetowych z wykorzystaniem HTM5, JavaScript, CSS3 i jquery Łukasz Bartczuk Moduł 5 Podstawy JavaScript Agenda Czym jest JavaScript? Podstawowe typy danych Zmienne Tablice Funkcje Zakres

Bardziej szczegółowo

Konstruktory. Streszczenie Celem wykładu jest zaprezentowanie konstruktorów w Javie, syntaktyki oraz zalet ich stosowania. Czas wykładu 45 minut.

Konstruktory. Streszczenie Celem wykładu jest zaprezentowanie konstruktorów w Javie, syntaktyki oraz zalet ich stosowania. Czas wykładu 45 minut. Konstruktory Streszczenie Celem wykładu jest zaprezentowanie konstruktorów w Javie, syntaktyki oraz zalet ich stosowania. Czas wykładu 45 minut. Rozpatrzmy przykład przedstawiający klasę Prostokat: class

Bardziej szczegółowo

16) Wprowadzenie do raportowania Rave

16) Wprowadzenie do raportowania Rave 16) Wprowadzenie do raportowania Rave Tematyka rozdziału: Przegląd wszystkich komponentów Rave Tworzenie nowego raportu przy użyciu formatki w środowisku Delphi Aktywacja środowiska Report Authoring Visual

Bardziej szczegółowo

LINQ TO SQL w dużym skrócie jest to zintegrowany język zapytao pozwalający na mapowanie relacyjnych baz danych na model obiektowy.

LINQ TO SQL w dużym skrócie jest to zintegrowany język zapytao pozwalający na mapowanie relacyjnych baz danych na model obiektowy. LINQ TO SQL w dużym skrócie jest to zintegrowany język zapytao pozwalający na mapowanie relacyjnych baz danych na model obiektowy. Zanim ktokolwiek postanowi użyd tego w swoim projekcie, należy zaznaczyd

Bardziej szczegółowo

Gerard Frankowski, Zespół Bezpieczeństwa PCSS. Nowoczesne technologie bliżej nas Poznań, 04.03.2010

Gerard Frankowski, Zespół Bezpieczeństwa PCSS. Nowoczesne technologie bliżej nas Poznań, 04.03.2010 Bezpieczeństwo interoperacyjnego hostingu Gerard Frankowski, Zespół Bezpieczeństwa PCSS 4. Konferencja MIC Nowoczesne technologie bliżej nas Poznań, 04.03.2010 1 Agenda Wprowadzenie Zespół Bezpieczeństwa

Bardziej szczegółowo

Zaawansowane aplikacje WWW - laboratorium

Zaawansowane aplikacje WWW - laboratorium Zaawansowane aplikacje WWW - laboratorium Przetwarzanie XML (część 2) Celem ćwiczenia jest przygotowanie aplikacji, która umożliwi odczyt i przetwarzanie pliku z zawartością XML. Aplikacja, napisana w

Bardziej szczegółowo

Wprowadzenie do Doctrine ORM

Wprowadzenie do Doctrine ORM Wprowadzenie do Doctrine ORM Przygotowanie środowiska Do wykonania ćwiczenia konieczne będzie zainstalowanie narzędzia Composer i odpowiednie skonfigurowanie Netbeans (Tools->Options->Framework & Tools->Composer,

Bardziej szczegółowo

16MB - 2GB 2MB - 128MB

16MB - 2GB 2MB - 128MB FAT Wprowadzenie Historia FAT jest jednym z najstarszych spośród obecnie jeszcze używanych systemów plików. Pierwsza wersja (FAT12) powstała w 1980 roku. Wraz z wzrostem rozmiaru dysków i nowymi wymaganiami

Bardziej szczegółowo

Przypisywanie bibliotek w architekturze SAS

Przypisywanie bibliotek w architekturze SAS SAS Institute TECHNICAL SUPPORT Przypisywanie bibliotek w architekturze SAS Platforma SAS pozwala na zdefiniowanie wspólnych zasobów w metadanych oraz ustalanie praw dostępu dla użytkowników i grup. Ze

Bardziej szczegółowo

PROBLEMY TECHNICZNE. Co zrobić, gdy natrafię na problemy związane z użytkowaniem programu DYSONANS

PROBLEMY TECHNICZNE. Co zrobić, gdy natrafię na problemy związane z użytkowaniem programu DYSONANS PROBLEMY TECHNICZNE Co zrobić, gdy natrafię na problemy związane z użytkowaniem programu DYSONANS Jeżeli stwierdziłeś występowanie błędów lub problemów podczas pracy z programem DYSONANS możesz skorzystać

Bardziej szczegółowo

Programowanie Strukturalne i Obiektowe Słownik podstawowych pojęć 1 z 5 Opracował Jan T. Biernat

Programowanie Strukturalne i Obiektowe Słownik podstawowych pojęć 1 z 5 Opracował Jan T. Biernat Programowanie Strukturalne i Obiektowe Słownik podstawowych pojęć 1 z 5 Program, to lista poleceń zapisana w jednym języku programowania zgodnie z obowiązującymi w nim zasadami. Celem programu jest przetwarzanie

Bardziej szczegółowo

Budowa aplikacji ASP.NET współpracującej z bazą dany do przeprowadzania ankiet internetowych

Budowa aplikacji ASP.NET współpracującej z bazą dany do przeprowadzania ankiet internetowych Budowa aplikacji ASP.NET współpracującej z bazą dany do przeprowadzania ankiet internetowych widok ankiety w przeglądarce Rozpoczniemy od zaprojektowania bazy danych w programie SYBASE/PowerDesigner umieszczamy

Bardziej szczegółowo

Podręcznik użytkownika Publikujący aplikacji Wykaz2

Podręcznik użytkownika Publikujący aplikacji Wykaz2 Podręcznik użytkownika Publikujący aplikacji Wykaz2 TiMSI Sp z o o ul Czapli 63, 02-781 Warszawa tel : +48 22 644 86 76, fax: +48 22 644 78 52 NIP: 951-19-39-800 Sąd Rejonowy dla mst Warszawy w Warszawie,

Bardziej szczegółowo

System Kancelaris. Zdalny dostęp do danych

System Kancelaris. Zdalny dostęp do danych Kancelaris krok po kroku System Kancelaris Zdalny dostęp do danych Data modyfikacji: 2008-07-10 Z czego składaj adają się systemy informatyczne? System Kancelaris składa się z dwóch części: danych oprogramowania,

Bardziej szczegółowo

Dokumentacja interfejsu MySQL. Platforma BSMS.PL Instrukcja podłączenia po przez mysql

Dokumentacja interfejsu MySQL. Platforma BSMS.PL Instrukcja podłączenia po przez mysql Dokumentacja interfejsu MySQL Platforma BSMS.PL Instrukcja podłączenia po przez mysql Dokumentacja interfejsu mysql (strona 2) SPIS TREŚCI 1. Zawartość dokumentu str.3 2. Informacje ogólne 2.1 Zastosowanie

Bardziej szczegółowo

Obsługa błędów w SQL i transakcje. Obsługa błędów w SQL

Obsługa błędów w SQL i transakcje. Obsługa błędów w SQL Obsługa błędów w SQL i transakcje Zacznijmy od najprostszego przykładu: CREATE PROCEDURE podziel1 Obsługa błędów w SQL Powyższa procedura w większości przypadków zadziała prawidłowo, lecz na przykład poniższe

Bardziej szczegółowo

Zacznij Tu! Poznaj Microsoft 2012. Visual Basic. Michael Halvorson. Przekład: Joanna Zatorska

Zacznij Tu! Poznaj Microsoft 2012. Visual Basic. Michael Halvorson. Przekład: Joanna Zatorska Zacznij Tu! Poznaj Microsoft 2012 Visual Basic Michael Halvorson Przekład: Joanna Zatorska APN Promise, Warszawa 2013 Spis treści Wstęp...................................................................vii

Bardziej szczegółowo

Ustalanie dostępu do plików - Windows XP Home/Professional

Ustalanie dostępu do plików - Windows XP Home/Professional Ustalanie dostępu do plików - Windows XP Home/Professional Aby edytować atrybuty dostępu do plikow/ katalogow w systemie plików NTFS wpierw sprawdź czy jest Wyłączone proste udostępnianie czyli przejdź

Bardziej szczegółowo

Języki programowania wysokiego poziomu. PHP cz.4. Bazy danych

Języki programowania wysokiego poziomu. PHP cz.4. Bazy danych Języki programowania wysokiego poziomu PHP cz.4. Bazy danych PHP i bazy danych PHP może zostać rozszerzony o mechanizmy dostępu do różnych baz danych: MySQL moduł mysql albo jego nowsza wersja mysqli (moduł

Bardziej szczegółowo

Klasy i obiekty cz II

Klasy i obiekty cz II Materiał pomocniczy do kursu Podstawy programowania Autor: Grzegorz Góralski ggoralski.com Klasy i obiekty cz II Hermetyzacja, mutatory, akcesory, ArrayList Rozwijamy aplikację Chcemy, aby obiekty klasy

Bardziej szczegółowo

Rys.2.1. Trzy warstwy stanowiące podstawę popularnego podejścia w zakresie budowy stron internetowych [2]

Rys.2.1. Trzy warstwy stanowiące podstawę popularnego podejścia w zakresie budowy stron internetowych [2] 1. CEL ĆWICZENIA Celem ćwiczenia jest przedstawienie możliwości wykorzystania języka JavaScript do tworzenia interaktywnych aplikacji działających po stronie klienta. 2. MATERIAŁ NAUCZANIA JavaScript tak

Bardziej szczegółowo

Funkcje dodatkowe. Wersja 1.2.1

Funkcje dodatkowe. Wersja 1.2.1 Funkcje dodatkowe Wersja 1..1 Dokumentacja SMSAPI (https) FUNKCJE DODATKOWE z dnia 1.06.01 Wersja 1..1 SPIS TREŚCI 1.Wprowadzenie 1.1 Adresy URL do połączenia z aplikacją dla funkcji zarządzania kontem

Bardziej szczegółowo

Laboratorium nr 5 Podpis elektroniczny i certyfikaty

Laboratorium nr 5 Podpis elektroniczny i certyfikaty Laboratorium nr 5 Podpis elektroniczny i certyfikaty Wprowadzenie W roku 2001 Prezydent RP podpisał ustawę o podpisie elektronicznym, w która stanowi że podpis elektroniczny jest równoprawny podpisowi

Bardziej szczegółowo

Kontrola sesji w PHP HTTP jest protokołem bezstanowym (ang. stateless) nie utrzymuje stanu między dwoma transakcjami. Kontrola sesji służy do

Kontrola sesji w PHP HTTP jest protokołem bezstanowym (ang. stateless) nie utrzymuje stanu między dwoma transakcjami. Kontrola sesji służy do Sesje i ciasteczka Kontrola sesji w PHP HTTP jest protokołem bezstanowym (ang. stateless) nie utrzymuje stanu między dwoma transakcjami. Kontrola sesji służy do śledzenia użytkownika podczas jednej sesji

Bardziej szczegółowo

Programowanie obiektowe. Wykład 4

Programowanie obiektowe. Wykład 4 Programowanie obiektowe Wykład 4 Tworzenie własnych obiektów Słowo kluczowe this W JavaScriptmożna tworzyć własne obiekty. Wykorzystuje się tu zapis utworzonej funkcji o nazwie takiej samej jak klasa,

Bardziej szczegółowo

Integracja sklepu internetowego z serwisem aukcyjnym Swistak.pl

Integracja sklepu internetowego z serwisem aukcyjnym Swistak.pl Integracja sklepu internetowego z serwisem aukcyjnym Swistak.pl email: swistak@swistak.pl Spis treści 1. Wstęp...2 2. Import oferty...2 3. Plik CSV...3 4. Przykład pliku...7 5. Aktualizacja oferty...7

Bardziej szczegółowo

Strona główna. Strona tytułowa. Programowanie. Spis treści. Sobera Jolanta 16.09.2006. Strona 1 z 26. Powrót. Full Screen. Zamknij.

Strona główna. Strona tytułowa. Programowanie. Spis treści. Sobera Jolanta 16.09.2006. Strona 1 z 26. Powrót. Full Screen. Zamknij. Programowanie Sobera Jolanta 16.09.2006 Strona 1 z 26 1 Wprowadzenie do programowania 4 2 Pierwsza aplikacja 5 3 Typy danych 6 4 Operatory 9 Strona 2 z 26 5 Instrukcje sterujące 12 6 Podprogramy 15 7 Tablice

Bardziej szczegółowo

Wprowadzenie db4o - podstawy db4o - technikalia Przydatne wiadomości. Wprowadzenie. db4o. Norbert Potocki. 1 czerwca 2009. Norbert Potocki db4o

Wprowadzenie db4o - podstawy db4o - technikalia Przydatne wiadomości. Wprowadzenie. db4o. Norbert Potocki. 1 czerwca 2009. Norbert Potocki db4o Wprowadzenie - podstawy - technikalia Przydatne wiadomości Wprowadzenie 1 czerwca 2009 Wprowadzenie - podstawy - technikalia Przydatne wiadomości Wprowadzenie = bjects = database for objects w pełni obiektowa

Bardziej szczegółowo

1 Podstawy c++ w pigułce.

1 Podstawy c++ w pigułce. 1 Podstawy c++ w pigułce. 1.1 Struktura dokumentu. Kod programu c++ jest zwykłym tekstem napisanym w dowolnym edytorze. Plikowi takiemu nadaje się zwykle rozszerzenie.cpp i kompiluje za pomocą kompilatora,

Bardziej szczegółowo

WTYCZKA FARA-TCM Dane techniczne dla twórców zewnętrznych aplikacji do obsługi map cmentarza

WTYCZKA FARA-TCM Dane techniczne dla twórców zewnętrznych aplikacji do obsługi map cmentarza 2015 WTYCZKA FARA-TCM Dane techniczne dla twórców zewnętrznych aplikacji do obsługi map cmentarza Dokumentacja techniczna dostępu do podstawowych danych cmentarnych w programie FARA. wersja 1.0 aktualizacja:

Bardziej szczegółowo

Instrukcja użytkowania

Instrukcja użytkowania Instrukcja użytkowania Aby skutecznie pracować z programem Agrinavia Map należy zrozumieć zasadę interfejsu aplikacji. Poniżej można odszukać zasady działania Agrinavia Map. Szczegółowe informacje na temat

Bardziej szczegółowo

Laboratorium Systemów Operacyjnych

Laboratorium Systemów Operacyjnych Laboratorium Systemów Operacyjnych Użytkownicy, Grupy, Prawa Tworzenie kont użytkowników Lokalne konto pozwala użytkownikowi na uzyskanie dostępu do zasobów lokalnego komputera. Konto domenowe pozwala

Bardziej szczegółowo

Zdarzenia Zdarzenia onload i onunload

Zdarzenia Zdarzenia onload i onunload Zdarzenia Zdarzenia onload i onunload Ćwiczenie 1. Rysunek 1. Okno powitalne wykorzystujące zdarzenie onload Na stronie mogą zachodzić różne zdarzenia, np. użytkownik kliknie myszą lub zacznie wprowadzać

Bardziej szczegółowo