Kurs MooTools 1.2 Tomasz Dziuda

Logo MooTools

JavaScript staje się powoli nieodłączną częścią stron internetowych. Jednak nie służy już do tworzenia zupełnie zbytecznych ozdobników, które znamy ze stron tworzonych kilka lat temu. Dziś JavaScript stał się pełnoprawnym językiem programowania i metodą na ułatwienie i umilenie życia internautom. Jego użycie pozwala zaoszczędzić mnóstwo czasu, transferu i miejsca na stronie, bo możemy dzięki skryptom upchać na małym obszarze mnóstwo treści dostępnej jednym kliknięciem.

Ten sielankowy obraz psują dwie sprawy – obu z nich doświadczył każdy, kto poważniej zabrał się za pisanie skryptów JS. Pierwszy problem to brak standaryzacji JavaScript – wiele rzeczy inaczej obsługuje się w IE, a inaczej w alternatywnych przeglądarkach. Pewnych rzeczy IE w ogóle nie obsługuje i trzeba stosować różne „udziwnienia” w kodzie. Zatem często zdarza się, że musimy pisać kod JS dla IE i reszty przeglądarek.

Druga sprawa to powtarzalność problemów do realizacji – z reguły na różnych stronach powtarza się motyw zwijania/rozwijania jakiegoś elementu, menu itd. I dlatego właśnie warto stosować frameworki JS. Dobry framework to taki, który pozwala skrócić czas pisania kodu dzięki wbudowanej obsłudze różnych przeglądarek oraz gotowymi rozwiązaniami najczęstszych problemów. Nie muszę chyba pisać, że framework MooTools doskonale spełnia te warunki.

Spis treści

  1. Wprowadzenie
  2. Rdzeń frameworka
  3. Obiekty natywne – Tablice
  4. Obiekty natywne – Funkcje i zdarzenia

Wprowadzenie

W MooTools 1.2 masz wybór

Jeszcze niedawno piszący w opraciu o MooTools mogli trochę pozazdrościć krótkiej składni znanej z jQuery. W wersji 1.2 problem właściwie znikł – większość funkcji ma swoje odpowiedniki będące metodami klasy Element – dzięki temu można tworzyć zapisy postaci:

  1. kolekcjaElementów.jakasOperacja().innaOperacja().jeszczeInnaOperacja();

Oczywiście mamy auto-iterację (która swoją drogą istniała już w MooTools 1.11 dla kolekcji elementów zwracanych przez funkcję $$).

Ale tytuł mówi o tym, że w MooTools 1.2 mamy wybór – i tak jest. W większości wypadków mamy co najmniej dwa sposoby na zapisanie tego samego kodu – w sposób krótki i dłuższy. Przy czym sposób dłuższy jest z reguły bardziej czytelny. W wypadku stosowania dłuższej metody kod wygląda mniej więcej tak:

  1. var obiektKlasy = new Klasa("element",{opcje});

W wypadku obiektów natywnych (na przykład Array, String) możemy też łatwo stworzyć własne nazwy dla metod poprzez metodę alias (o niej w dalszej części kursu).

Zatem MooTools 1.2 już w samej kwestii zapisu kodu pozwala na wiele więcej niż poprzednik, a to dopiero początek (resztę poznamy w dalszej części kursu).

Jak zacząć ?

Aby w ogóle móc użyć MooTools na swojej stronie, należy najpierw dodać skonfigurowany dla własnych potrzeb plik mootools.js (pobrany ze strony mootools.net/download) w sekcji <head> swojej strony:

  1. <script type="text/javascript" src="sciezka_do_pliku_mootools.js"></script>

Osobiście polecam umieszczanie frameworka i skryptów z niego korzystających w oddzielnych plikach – dla zachowania porządku. Wyjątek mogą stanowić tutaj króciutkie skrypty o rozmiarach kilku KB – ale głównie wtedy, gdy naprawdę zależy nam na zredukowaniu liczby zapytań do serwera.

UWAGA!
Wszelkie pliki zawierające skrypty korzystające z MooTools muszą być umieszczone PO linijce dodającej plik mootools.js do strony ! Inaczej zobaczymy błąd JS spowodowany odwoływaniem się do obiektów/funkcji, które nie istnieją.

UWAGA!
Niech nie przyjdzie komukolwiek do głowy stosować więcej NIŻ JEDEN framework JS na stronie! Jednoczesne użycie MooTools/jQuery/Prototype = kłopoty.

Co oferuje nam MooTools 1.2 ?

Pozwolę sobie wymienić najważniejsze możliwości MooTools 1.2:

  • jeden kod działający we wszystkich przeglądarkach
  • zaawansowane możliwości selekcji elementów dokumentu (także z użyciem selektorów projektowanego dopiero CSS 3)
  • rozszerzenie możliwości obiektów natywnych
  • duże ułatwienia w kwestii manipulowania elementami dokumentu
  • wsparcie dla programowania obiektowego
  • możliwość tworzenia zaawansowanych animacji opartych o zmianę właściwości CSS elementów
  • obsługa AJAX wraz z wsparciem dla formatu JSON
  • obsługa technik drag’n’drop
  • oraz wiele innych klas stworzonych do obsługi efektów i rozwiązywania typowych problemów z jakimi spotykamy się podczas pisania skryptów JS

Na co zwrócić największą uwagę ?

Aby dobrze zrozumieć MooTools należy przede wszystkim oswoić się z obsługą obiektów natywnych i programowaniem obiektowym w tym frameworku – wszystkie pozostałe elementy bazują głównie na tych dwóch kwestiach i wymagają po prostu nauczenia się obsługi danej klasy MooTools. Dlatego, mimo że akurat ta część kursu może wydać się mało fascynująca (ze względu na swój teoretyczny charakter) to jest ona podstawą naszych dalszych działań, które będą dawać później najciekawsze efekty.

Rdzeń frameworka

W pierwszej „prawdziwej” części kursu MooTools 1.2 zajmę się opisem podstawowej części tego frameworka czyli plików Core.js i Browser.js. Te dwa pliki stanowią podstawę reszty MooTools, pierwszy z nich zawiera implementacje podstawowych funkcji, a drugi służy do jednej z podstawowych czynności w świecie JS – detekcji przeglądarki uzytkownika.

Konsola JavaScript

Zacznijmy od tego, że musimy mieć narzędzie do pracy – konsolę JS. W wypadku użytowników Firefoksa nie jest to problem – wystarczy wskazać odpowiednią pozycję w menu (Narzędzia » Konsola błędów) i już mamy dostęp do konsoli JavaScript. Oczywiście jeszcze lepiej mieć rozszerzenie Firebug. Co jednak z użytkownikami innych przeglądarek? Ponieważ nie chcę nikogo zmuszać do używania w celu testów Firefoksa wykorzystałem Firebug Lite i stworzyłem z jego użyciem stronę z prostą konsolą JS, którą znajdziecie pod tym adresem. I tak oto uzbrojeni w to potężne narzędzie możemy ruszać w świat MooTools :)

Informacje o wersji MooTools

Zacznijmy od tego co zawiera plik Core.js. Oczywiście kod zaczyna się od znanego już niektórym obiektu MooTools, zawierającego informacje o wersji frameworka. Ma on następującą budowę:

  1. var MooTools = { 'version': wersja, 'build': build };

Gdyby ktoś się zastanawiał kiedyś do czego ów obiekt może się przydać – pierwsza i podstawowa sprawa – dzięki niemu możemy sprawdzić czy w ogóle jakaś wersja MooTools została na danej stronie załadowana. Dokonamy tego poprzez prosty kod wywołany w konsoli JavaScript:

  1. try{
  2. MooTools
  3. }catch(e){
  4. false
  5. }

Jeżeli otrzymamy z niego false to znaczy, że obiekt MooTools nie jest zdefiniowany, a co za tym idzie framework nie został załadowany…

Oczywiście możliwości wykorzystania tego obiektu jest więcej jednak są one z reguły o wiele bardziej wyszukane niż ta podstawowa funkcja…

Informację o wersji wyświetlamy oczywiście poprzez odczytanie właściwości MooTools.version oraz MooTools.build np.:

  1. alert(MooTools.version);

Obiekty natywne

Bardzo ważną częścią pliku Core.js jest funkcja Native, która porządkuje i rozszerza możliwości obiektów natywnych JavaScript takich jak String, Function, Number, Array, RegExp, Date, Boolean, Native, Object.

Właściwie nas z tego fragmentu kodu powinny zainteresować dwie metody – implement, która pozwala na dodanie własnych metod do obiektów natywnych oraz alias, która pozwala tworzyć kilka nazw dla tej samej metody danego obiektu natywnego…

Jeżeli chodzi o metodę implement to ma ona następującą składnię:

  1. obiektNatywny.implement({
  2. nazwaMetody1: function(){
  3. // kod
  4. },
  5. nazwaMetody2: function(){
  6. // kod
  7. },
  8.  
  9. ...
  10.  
  11. nazwaMetodyN: function(){
  12. // kod
  13. }
  14. });

Przy czym jeżeli chcemy zaimplementować te same metody w wielu obiektach naraz to stosujemy tablicę obiektów jako pierwszy argument metody implement:

  1. Native.implement([obiektNatywny1, obiektNatywny2, obiektNatywny3],{
  2. nazwaMetody1: function(){
  3. // kod
  4. },
  5. nazwaMetody2: function(){
  6. // kod
  7. },
  8.  
  9. ...
  10.  
  11. nazwaMetodyN: function(){
  12. // kod
  13. }
  14. });

Jak widać możemy do kilku obiektów dodać od razu kilka/kilkanaście metod.

Jeżeli chodzi o metodę alias to składnia wygląda następująco:

  1. obiektNatywny.alias("pierwotnaNazwa","nowaNazwa");

Gdybyśmy chcieli na przykład zamiast Array.each stosować Array.e to zapiszemy:

  1. Array.alias("each","e");

Na oswojenie z łańcuchowym wywoływaniem metod obiektu dodam, że zamiast:

  1. Array.alias("metoda1","m1");
  2. Array.alias("metoda2","m2");

można stosować zapis:

  1. Array.alias("metoda1","m1").alias("metoda2","m2");

Obiekty i tablice

Plik Core.js zawiera także podstawowe implementacje obiektów Array i Hash. W wypadku Array została od razu zaimplementowana metoda forEach wraz z aliasem each. Oczywiście nie zabrakło funkcji $A, która zamienia kolekcję elementów na tablicę. W wypadku obiektu Hash, który jest swoistą nakładką na obiekt natywny Object, mamy zaimplementowaną także metodę forEach z aliasem each oraz skrót $H, który daje taki sam efekt jak zapis:

  1. var zmienna = new Hash({obiekt});

Skoro już obracamy się w otoczeniu obiektów, które można iteracyjnie przetwarzać to od razu wspomnę o funkcji $each, która służy do wykonania danej funkcji na każdym elemencie iterowalnym (argumenty, tablica, kolekcja elementów). Składnia wygląda następująco:

  1. $each(obiektIterowalny, funkcja, bind);

Zmienna obiektIterowalny już wiadomo czym może być, funkcja to oczywiście kod funkcji, która wykona się dla każdego elementu obiektu, a zmienna bind definiuje do czego odnosi się operator this w ciele funkcji (domyślnie odnosi się on do samej funkcji).

Dla wyklarowania sytuacji z Hash i Array kilka prostych przykładów :)

Obiekt daneUzytkownika możemy zdefiniować na dwa sposoby:

  1. var daneUzytkownika = new Hash({nick: "dziudek", imie: "Tomek"});
  2.  
  3. // lub
  4.  
  5. var daneUzytkownika = $H({nick: "dziudek", imie: "Tomek"});

Informacje z takiego obiektu możemy odczytać na co najmniej trzy sposoby:

  1. daneUzytkownika.forEach(function(el, key){alert(key);});
  2. daneUzytkownika.each(function(el, key){alert(key);});
  3. $each(daneUzytkownika, function(el, key){alert(key);});

Wszystkie te trzy zapisy są równoważne i spowodują wyświetlenie alertów z tekstami “dziudek” i “Tomek”.

Oczywiście dostęp do tych danych otrzymamy także poprzez zapisy:

  1. daneUzytkownika["imie"];
  2. daneUzytkownika["nick"];
  3.  
  4. // lub
  5.  
  6. daneUzytkownika.imie;
  7. daneUzytkownika.nick;

W wypadku tablic sytuacja ma się podobnie z tym, że charakter przechowywanych danych jest inny – nie posiadają one nazwanego odnośnika, a jedynie indeks w tablicy. Aby przy wyświetlaniu danych takim samym sposobem jak w wypadku obiektu Hash, otrzymać te same wyniki należy zmienną daneUzytkownika zdefiniować następująco:

  1. var daneUzytkownika = ["dziudek","Tomek"];

Pozostałe funkcje

Jeżeli chodzi o resztę funkcji pliku Core.js to mają one jedną wspólną cechę – zaczynają się od znaku $:

Możecie zauważyć, że pozwoliłem sobie je troszkę pogrupować tematycznie :)

Funkcje związane z czasem

Funkcje $time i $clear są związane z czasem – pierwsza zwraca aktualny czas w postaci ilości milisekund jakie upłynęły od 1 stycznia 1970 roku od godziny 00:00:00. Funkcja $clear natomiast służy do przerywania okresowego wykonania funkcji lub przerwania odliczania czasu do wykonania danej funkcji (nieodłącznie związane z metodami delay i periodical obiektu natywnego Function).

$time nie pobiera żadnego argumentu, a $clear pobiera zmienną przypisaną do funkcji wykonywanej okresowo/z opóźnieniem. Zatem jej wywołanie w wypadku, gdy mamy następujący kod w skrypcie:

  1. var czasomierz = (function(){alert("buum!");}).delay(5000);

wygląda następująco:

  1. $clear(czasomierz);
Funkcje badające zmienne

Przejdźmy teraz do funkcji związanych z typem zmiennych i tym, czy są one zdefiniowane.

Funkcje $chk i $defined działają podobnie – pierwsza zwraca wartość logiczną true gdy dana zmienna istnieje lub jest równa 0, a druga z nich zwraca taką wartość, gdy dana zmienna nie jest pusta (czyli ma zdefiniowaną wartość). W wypadku niespełnienia warunku funkcje te zwracają wartość logiczną false. Oczywiście pełny sens ma zastosowanie tych funkcji w ciele innej funkcji do sprawdzenia argumentów, ponieważ w innym wypadku nie obędzie się bez błędu jeżeli dana zmienna nie istnieje… Obie funkcje pobierają jeden argument – zmienną do sprawdzenia.

Przykłady:

  1. function test(zmienna){
  2. return $chk(zmienna);
  3. }
  4.  
  5. test();

Zwróci nam false, natomiast kod:

  1. function test(zmienna){
  2. return $chk(zmienna);
  3. }
  4.  
  5. test("testowy tekst");

zwróci nam wartość true.

Jeżeli chodzi o funkcję $defined:

  1. function test(zmienna){
  2. return $defined(zmienna);
  3. }
  4.  
  5. test("testowy tekst");

Powyższy kod zwróci nam oczywiście wartość true, natomiast false otrzymamy w każdym z poniższych wypadków:

  1. function test(zmienna){
  2. return $defined(zmienna);
  3. }
  4.  
  5. test(); //false
  6. test(null); //false
  7.  
  8. var zmienna;
  9. test(zmienna); //false

Funkcja $pick służy do „grupowego” sprawdzania czy zmienne są zdefiniowane zwracajac przy tym pierwszą zdefiniowaną zmienną z podanych lub wartość null jeżeli żadna ze zmiennych podanych jako argumenty tej funkcji nie jest zdefiniowana.

Stwórzmy zatem przykładową funkcję:

  1. function test(a,b,c){
  2. return $pick(a,b,c);
  3. }
  4.  
  5. test();

Zwróci ona nam null, bo przy wywołaniu nie podaliśmy żadnych argumentów. Gdybyśmy funkcję test wywołali w taki sposób:

  1. test(10);

To zostanie zwrócone właśnie 10.

Gdy wywołanie będzie wyglądać tak:

  1. test(null,null,3);

To zostanie zwrócona wartość 3, a wywołanie:

  1. test(null,null,null);

Zwróci oczywiście wartość null.

Pora na coś bardziej złożonego czyli funkcję $type – zwraca ona typ argumentu. Ponieważ istnieje wiele wartości jakie może ona zwrócić podam tylko nazwy wartości przez nią zwracanych bez przykładów, by nie wydłużać i tak już długiego kursu :)

Wartości zwracane przez funkcję $type:

element gdy argument jest elementem DOM
textnode gdy argument jest węzłem tekstowym DOM
whitespace gdy argument jest węzłem zawierającym wyłącznie białe znaki
arguments gdy argument jest tablicą argumentów (w funkcji)
array gdy argument jest tablicą
object gdy argument jest obiektem
string gdy argument jest ciągiem znaków
number gdy argument jest liczbą
boolean gdy argument jest wartością logiczną
function gdy argument jest funkcją
regexp gdy argument jest wyrażeniem regularnym
class gdy argument jest klasą (stworzona przez Class lub rozszerzenie instancji Class)
collection gdy argument jest kolekcją elementów DOM (na przykład zwracaną przez funkcję $$)
window gdy argument to obiekt window
document gdy argument to obiekt document
false gdy argument jest niezdefiniowany lub nie jest jednym z wyżej wymienionych elementów

Przejdźmy teraz do funkcji związanych z… funkcjami :)

Funkcje operujące na funkcjach

Funkcje $lambda i $arguments są dość ciekawe zważywszy na możliwości jakie nam oferują – $lambda pozwala nam stworzyć ze zmiennej funkcję zwracającą ją samą (zmienną), a $arguments pozwala stworzyć funkcję zwracającą argument z określonej pozycji w liście argumentów.

$lambda pobiera jako argument zmienną lub funkcję, natomiast funkcja $arguments pobiera numer argumentu jaki ma zostać później zwrócony (przy czym argumenty są numerowane jak w tablicy tj. od zera).

Zapis:

  1. var d = $arguments(1);
  2.  
  3. d(1,2,3);

Spowoduje zwrócenie wartości 2.

Funkcja $lambda pozwala nam często skrócić kod – weźmy przykład, gdy mamy w kodzie obiektu zapis:

  1. metoda: function(){
  2. return false;
  3. }

Powyższy kod możemy zamienić na:

  1. metoda: $lambda(false);

Apropo metod obiektów – funkcja $empty oznacza po prostu pusta funkcję. Zatem zamiast w definicji klasy pisać:

  1. onZdarzenie: function(){}

Piszemy po prostu:

  1. onZdarzenie: $empty

Może wydawać się to sztuką dla sztuki, ale według mnie jest to czytelniejsze :)

Przydatną funkcją jest z pewnością $try – pozwala ona sprawdzić czy dana funkcja nie powoduje błędów, ma ona trochę bardziej złożoną składnię niż poznane przez nas już funkcje:

  1. $try(funkcja,this,argumenty);

Zmienna funkcja to oczywiście funkcja jaką chcemy przetestować, zmienna this to obiekt do jakiego odnosi się operator this w ciele funkcji, a zmienna argumenty to zmienne przekazywane do funkcji (gdy argumentów jest więcej niż jeden wtedy przekazujemy je jako tablicę).

Kod z początku artykułu:

  1. try{
  2. MooTools
  3. }catch(e){
  4. false
  5. }

Możemy zapisać jako:

  1. $try($lambda(MooTools));

Choć akurat przykład z obiektem MooTools może się wydać średnio udany (bo zakładamy, że MooTools jest załadowany :D) to warto zapamiętać, że możemy tak sprawdzić każdy obiekt/zmienną.

Funkcje operujące na obiektach

Funkcja $extend pozwala nam rozszerzyć dany obiekt o nowe właściwości, a $merge pozwala złączyć kilka obiektów w jeden. Ponadto $extend można zastosować na dwa sposoby:

  1. $extend(obiektPodstawowy,obiektRozszerzenie);

lub:

  1. Obiekt.extend = $extend;
  2. Obiekt.extend(obiektRozszerzenie);

Podobieństwo tych funkcji polega na tym, że w obu wypadkach następuje nadpisanie właściwości obiektu jeżeli się powtarzają w podawanych jako argumenty obiektach.

Dla przykładu przyjmijmy, że mamy trzy obiekty:

  1. przegladarka = {
  2. nazwa: "Lisek",
  3. wersja: 3
  4. }
  5.  
  6. oprogramowanie = {
  7. wersja: 5,
  8. wlasciciel: "Dziudek"
  9. }
  10.  
  11. system = {
  12. wersja: 6
  13. }

Jeżeli teraz wykonamy operację:

  1. $extend(przegladarka,oprogramowanie);

To otrzymamy obiekt postaci:

  1. {
  2. nazwa: "Lisek",
  3. wersja: 5,
  4. wlasciciel: "Dziudek"
  5. }

Jak widać nie występujące w obiekcie przegladarka właściwości zostały dodane, a właściwość wersja została zmieniona na wartość z obiektu oprogramowanie.

W wypadku funkcji $merge:

  1. $merge(przegladarka,oprogramowanie);

Otrzymalibyśmy taki sam obiekt, ale już po wykonaniu kodu:

  1. $merge(przegladarka,oprogramowanie,system);

Otrzymamy:

  1. {
  2. nazwa: "Lisek",
  3. wersja: 6,
  4. wlasciciel: "Dziudek"
  5. }

Zanim ktoś powie, że te funkcje działają w sumie tak samo poza liczbą argumentów, dodam jeszcze, że w wypadku funkcji $merge operacja rozszerzania/aktualizowania właściwości następuje także wtedy, gdy jedna z właściwości jest obiektem (tj. mamy zagnieżdżone obiekty). Zatem weźmy dwa nowe obiekty:

  1. strona = {
  2. title: "test",
  3. body: {
  4. menu: "opcje",
  5. stopka: "copyright"
  6. }
  7. }
  8.  
  9. nowaStrona = {
  10. title: "drugi test",
  11. body: {
  12. tresc: "tekst",
  13. stopka: "All right reserved"
  14. }
  15. }

W wypadku funkcji $extend:

  1. $extend(strona,nowaStrona);

Otrzymamy obiekt postaci:

  1. {
  2. title: "drugi test",
  3. body: {
  4. tresc: "tekst",
  5. stopka: "All right reserved"
  6. }
  7. }

Natomiast w wypadku $merge:

  1. $merge(strona,nowaStrona);

Zostanie zwrócony taki obiekt:

  1. {
  2. title: "drugi test",
  3. body: {
  4. menu: "opcje",
  5. tresc: "tekst",
  6. stopka: "All right reserved"
  7. }
  8. }

Jak widać w $extend właściwość body nie została rozszerzona tylko zamieniona, natomiast takie działanie miało miejsce w przypadku funkcji $merge.

Kwestię sprawdzenia czy mam rację pozostawiam Wam :) Jest to dobre ćwiczenie na wykazanie się znajomością obsługi obiektu Hash zaimplementowanej w pliku Core.js :)

Pozostała nam jeszcze funkcja $splat, która zamienia wszystko co nie jest tablicą w tablicę. Oczywiście nie w taki sposób jak funkcja $A – po prostu jeżeli jako argument tej funkcji podamy obiekt, to zostanie zwrócona tablica jednoelementowa zawierająca tenże obiekt:

  1. $splat(10);

Zwróci tablicę postaci:

  1. [10]
  1. $splat({1:"a",2:"b"});

Zwróci tablicę:

  1. [{1:"a",2:"b"}]

itd.

Funkcja związana z liczbami

Jak już sam tytuł tej części wskazuje – jest tylko jedna taka funkcja (przynajmniej w opisywanych plikach) – $random pobiera dwa argumenty, które tworzą przedział liczbowy z jakiego są generowane liczby pseudolosowe:

  1. $random(start,koniec);

powyższy kod zwróci nam liczbę pseudolosową z przedziału <start,koniec>.

Na przykład:

  1. $random(2,8);

Zwróci liczbę całkowitą z przedziału <2,8>.

Detekcja systemu operacyjnego i przeglądarki

Jak już pewnie zauważyliście MooTools 1.2 dorobił się osobnego pliku odpowiedzialnego za detekcję przeglądarki i systemu operacyjnego użytkownika.

Od teraz mamy zdefiniowany obiekt Browser posiadający trzy właściwości – Engine, Platform i Features. Pierwsza z nich z pewnością najbardziej nas zainteresuje, bo jest związana z detekcją przeglądarki.

To jakiej przeglądarki/systemu używa użytkownik sprawdzimy poprzez zbadanie jaką ma wartość logiczną właściwość:

  • Browser.Engine.trident – Internet Explorer (dowolny)
  • Browser.Engine.trident4 – Internet Explorer 6
  • Browser.Engine.trident5 – Internet Explorer 7
  • Browser.Engine.gecko – Mozilla/Gecko
  • Browser.Engine.webkit – Safari/Konqueror
  • Browser.Engine.webkit419 – Safari 2
  • Browser.Engine.webkit420 – Safari 3
  • Browser.Engine.presto – Opera

Dodatkowo właściwość Browser.Engine.name przechowuje nazwę przeglądarki.

W wypadku detekcji systemu badamy właściwości:

  • Browser.Platform.mac – MacOS
  • Browser.Platform.win – Windows
  • Browser.Platform.linux – Linux
  • Browser.Platform.nix – systemy z rodziny *nix
  • Browser.Platform.other – inny system operacyjny

Oczywiście we właściwości Browser.Platform.name mamy przechowywaną nazwę systemu operacyjnego użytkownika.

To czy przeglądarka natywnie wspiera XPath i XMLHttp sprawdzimy poprzez właściwości:

  • Browser.Features.xpath
  • Browser.Features.xhr

Dodatkowo właściwość Browser.Features.air poinformuje nas czy strona korzysta ze środowiska AIR.

Jak widać obiekt Browser dostarcza nam wielu potrzebnych informacji. Warto jeszcze zwrócić uwagę na pozostałą zawartość pliku Browser.js.

eval nie jest dobry na wszystko

Gdyby się kogoś spytać jak wykonać tekst jako kod JavaScript to z pewnością większość odpowie, że wystarczy użyć funkcji eval dostępnej natywnie w JS. Ta odpowiedź jest oczywiście dobra, ale nie w 100% wypadków.

Weźmy dla przykładu taki oto kod:

  1. function dodajZmienna() {
  2. var kod = 'var zmienna = "Tekst testowy"';
  3. eval(kod);
  4. }
  5. dodajZmienna();
  6. alert(zmienna);

Powyższy kod nie zadziała, ponieważ nowa zmienna nie istnieje poza funkcją. Gdybyśmy zastosowali taki kod:

  1. function dodajZmienna() {
  2. var kod = 'var zmienna = "Tekst testowy"';
  3. eval(kod);
  4. alert(zmienna);
  5. }
  6. dodajZmienna();

Wszystko będzie w porządku. Zatem jak widać problem polega na tym, że kod nie jest wykonywany przez funkcję eval globalnie. Lekarstwem na to w IE jest window.execScript, a uniwersalnym rozwiązaniem jakie oferuje MooTools jest funkcja $exec – zmieńmy pierwszy przykład, a dokładniej 3 linijkę:

  1. function dodajZmienna() {
  2. var kod = 'var zmienna = "Tekst testowy"';
  3. $exec(kod);
  4. }
  5. dodajZmienna();
  6. alert(zmienna);

Powyższy kod powinien zadziałać bez zarzutu. Podsumowując – jeżeli potrzebujemy GLOBALNIE wykonać kod JS zapisany w postaci ciągu znaków, to stosujemy funkcję $exec zamiast eval.

Obiekt document

Na koniec słów kilka o obiekcie document – MooTools dodaje do niego kilka właściwości, które mogą się przydać:

  • document.head – zwraca uchwyt do sekcji head dokumentu
  • document.html – zwraca uchwyt do elementu html dokumentu
  • document.window – zwraca uchwyt do obiektu okna dla danego dokumentu (to samo co document.defaultView i document.parentWindow tylko w wersji uniwersalnej)

I to by było na tyle w kwestii omawiania rdzenia MooTools – jak mogliśmy zauważyć opisywane pliki dają nam już całkiem sporą grupę narzędzi ułatwiających pisanie kodu w JavaScript, a to dopiero początek :)

Obiekty natywne – Tablice

Po zapoznaniu się z podstawowymi funkcjonalnościami MooTools pora zająć się dogłębnie tym, co tworzy w tym frameworku całą pokaźną grupę Native. Już w pliku Core.js mogliśmy znaleźć fragmenty kodu przeznaczone dla tego typu obiektów, a przez następne 4 części kursu będziemy poznawać kolejne rozszerzenia jakie oferuje nam MooTools dla tablic (o nich w tej części), funkcji, ciągów znaków, liczb, obiektów oraz zdarzeń. Generalnie obiekty te poza Element, który będzie miał cały swój dział to chleb powszedni przy pisaniu skryptów, dlatego warto nie traktować po macoszemu tych części kursu :)

Podobnie jak w wypadku poprzedniej części kursu będziemy korzystali z konsoli JavaScript (albo tej z Firebuga/Firefoxa, albo tej przygotowanej przeze mnie na potrzeby kursu).

Obiekt Array ma dzięki MooTools dodane metody, których nie obsługują natywnie wszystkie przeglądarki oraz metody do wykonywania najczęstszych operacji na tablicach. Zajmijmy się najpierw metodami, które występują natywnie w JavaScript 1.6, a których nie obsługują przeglądarki oparte na innym silniku niż Gecko. Te metody to every, filter, indexOf, map, some (poza nimi jeszcze forEach zaimplementowane w pliku Core.js i lastIndexOf, które wogóle w MooTools nie jest zaimplementowane).

Metody z JavaScript 1.6

Metody every i some działają na podobnej zasadzie – badają wartości elementów w tablicy. Jeżeli elementy te spełniają dany warunek (w wypadku metody every KAŻDY element musi spełniać dany warunek, a w wypadku metody some CO NAJMNIEJ JEDEN element tablicy musi spełniać warunek) to zwracana jest wartość true, a w przeciwnym wypadku false.

Najprostsze przykłady użycia metod every i some – wykorzystamy w nim tablicę liczb 1-5 i warunek mówiący, że elementy mają mieć wartości większe od 1:

  1. var tablicaLiczb = [1,2,3,4,5];
  2.  
  3. tablicaLiczb.every(function(element){
  4. return element > 1;
  5. });
  6.  
  7.  
  8. var tablicaLiczb = [1,2,3,4,5];
  9.  
  10. tablicaLiczb.some(function(element){
  11. return element > 1;
  12. });

W pierwszym wypadku zostanie zwrócona wartość false, bo jeden z elementów nie jest większy od 1 (jest równy 1), a w drugim wypadku otrzymamy true, gdyż 4 elementy spełniają podany warunek.

Jeszcze dla przykładu sprawdzimy czy tablica nazwisk składa się tylko z nazwisk na literę „B”:

  1. var tablicaNazwisk = ["Borowski","Borewicz","Bogusławski"];
  2.  
  3. tablicaNazwisk.every(function(element){
  4. var reg = /^B+/;
  5. return reg.exec(element);
  6. });

Otrzymamy wartość true, ponieważ każde nazwisko zaczyna się dużą literą „B”. Warto dodać, że funkcja wywoływana przy metodzie every może pobierać dwa argumenty – uchwyt do elementu i numer indeksu aktualnie przetwarzanego elementu. Dla przykładu wykonajmy na tablicy liczb metodę some, która sprawdzi czy jakaś wartość elementu tablicy pokrywa się z indeksem tegoż elementu:

  1. var tablicaLiczb = [1,2,3,4,5];
  2.  
  3. tablicaLiczb.some(function(element,indeks){
  4. return element == indeks;
  5. });

W tym wypadku zwrócona zostanie wartość false, ale już dla tablicy:

  1. var tablicaLiczb = [0,1,2,3,4];

nawet w wypadku metody every zostanie zwrócona wartość true.

Przejdźmy teraz do metod filter i map. Mają one jedną wspólną cechę – tworzą nową tablicę na bazie starej – w wypadku metody filter nowa tablica zawiera elementy spełniające dany warunek, natomiast metoda map zwraca tablicę elementów, które są elementami starej tablicy z wartościami przetworzonymi według podanej jako argument metody funkcji.

Zatem gdybyśmy wzięli nasz pierwszy przykład i zmienili metodę na filter:

  1. var tablicaLiczb = [1,2,3,4,5];
  2.  
  3. var nowaTablicaLiczb = tablicaLiczb.filter(function(element){
  4. return element > 1;
  5. });

To otrzymamy tablicę postaci:

  1. [2, 3, 4, 5]

Potrzebujemy wartości drugiej potęgi dla każdego elementu tablicy? Zastosujmy metodę map:

  1. var tablicaLiczb = [1,2,3,4,5];
  2.  
  3. var nowaTablicaLiczb = tablicaLiczb.map(function(element){
  4. return element * element;
  5. });

Otrzymamy oczywiście tablicę postaci:

  1. [1, 4, 9, 16, 25]

Można też wykorzystać drugą zmienną funkcji i stworzyć tablicę kolejnych potęg (począwszy od zerowej potęgi) dla liczb z tablicy:

  1. var tablicaLiczb = [1,2,3,4,5];
  2.  
  3. var nowaTablicaLiczb = tablicaLiczb.map(function(element,indeks){
  4. return Math.pow(element,indeks);
  5. });

Otrzymamy:

  1. [1, 2, 9, 64, 625]

Z tej grupy metod pozostała nam jeszcze metoda indexOf – jak sama nazwa wskazuje chodzi o zwrócenie wartości indeksu dla elementu o danej wartości. Metoda indexOf pobiera dwa argumenty – szukaną wartość elementu oraz opcjonalnie numer indeksu, od którego ma być rozpoczęte przeszukiwanie. W wypadku, gdy element o danej wartości nie istnieje w tablicy (lub w jej fragmencie, którego początek definiuje drugi parametr metody) zostanie zwrócona wartość -1.

Dla przykładu weźmy tablicę będącą efektem działania ostatniego przykładu:

  1. var tablicaLiczb = [1, 2, 9, 64, 625];
  2.  
  3. tablicaLiczb.indexOf(9);

Powinniśmy otrzymać wartość 2.

Gdybyśmy zastosowali taki zapis:

  1. var tablicaLiczb = [1, 2, 9, 64, 625];
  2.  
  3. tablicaLiczb.indexOf(9,3);

Zostanie zwrócona wartość -1, bo wyszukiwanie zacznie się od fragmentu tablicy [64, 625] gdzie elementu o wartości 9 nie ma.

Pora omówić metody, dodane przez programistów MooTools…

Nowe metody obiektu Array

Takich metod jest sporo: associate, link, contains, extend, getLast, getRandom, include, merge, remove, empty, flatten, hexToRgb, rgbToHex.

Metody associate i link służą do tworzenia z tablic obiektów. W wypadku pierwszej z nich obiekt powstaje na bazie dwóch tablic (elementy jednej tablicy tworzą klucze, a elementy drugiej tworzą wartości), a w drugim wypadku do obiektu są przypisywane elementy danego typu (typ jest określony w każdym kluczu).

Stwórzmy zatem obiekt na bazie dwóch tablic:

  1. var Oprogramowanie = ["Przeglądarka", "Komunikator", "Program pocztowy"];
  2. var Programy = ["Firefox", "Konnekt", "GMail"];
  3.  
  4. Programy.associate(Oprogramowanie);

Otrzymamy obiekt postaci:

  1. {
  2. "Przeglądarka": "Firefox",
  3. "Komunikator": "Konnekt",
  4. "Program pocztowy": "GMail"
  5. }

Przy okazji dodam, że w dokumentacji i to zarówno dla wersji 1.2 beta jaki i najnowszej wersji z SVN jest błąd. Znajdziemy tam taki przykład:

  1. var animals = ['Cow', 'Pig', 'Dog', 'Cat'];
  2. var sounds = ['Moo', 'Oink', 'Woof', 'Miao'];
  3. animals.associate(sounds);
  4. //returns {'Cow': 'Moo', 'Pig': 'Oink', 'Dog': 'Woof', 'Cat': 'Miao'}

Problem w tym, że nie zwróci on takiego obiektu jak podano tylko podobny obiekt ale z zamienionymi parami klucz-wartość. Aby to naprawić musielibyśmy wykonać poniższy kod:

  1. Array.prototype.associate = function(keys){
  2. var obj = {}, length = Math.min(this.length, keys.length);
  3. for (var i = 0; i < length; i++) obj[this[i]] = keys[i];
  4. return obj;
  5. };

Lub jak kto woli – zamienić w pliku Array.js linijkę:

  1. for (var i = 0; i < length; i++) obj[keys[i]] = this[i];

na:

  1. for (var i = 0; i < length; i++) obj[this[i]] = keys[i];

Warto jeszcze dodać, że gdy nasze tablice mają nierówną długość, to obiekt będzie miał długość tablicy o mniejszej długości.

Pora na ciekawszą metodę link – do obiektu o danej strukturze przypisuje elementy danego typu z tablicy. Przy czym liczy się kolejność elementów w tablicy, a nie w obiekcie. Dla przykładu – mamy tablicę zawierającą kilka ciągów znaków i liczb i chcemy stworzyć obiekt gdzie klucze będą miały przypisane wartości będące dwoma pierwszymi ciągami znaków z tej tablicy:

  1. var wartosci = ["Test",1,2,"abc",3,4,"efg"];
  2.  
  3. wartosci.link({
  4. "Tekst1":String.type,
  5. "Tekst2":String.type
  6. });

Otrzymamy obiekt postaci:

  1. {
  2. Tekst1:"Test"
  3. Tekst2:"abc"
  4. }

Warto zauważyć, że typ możemy zdefiniować poprzez zapis:

  1. ObiektNatywny.type

Zatem jeżeli chcemy by do danego klucza był przypisany element będący liczbą zapiszemy:

  1. Number.type

Na przykład:

  1. var wartosci = ["Test",1,2,"abc",3,4,"efg"];
  2.  
  3. wartosci.link({
  4. "Tekst1":String.type,
  5. "Tekst2":String.type,
  6. "Liczba1":Number.type,
  7. "Liczba2":Number.type
  8. });

Warto zauważyć, że w tym wypadku zostanie zwrócony obiekt postaci:

  1. {
  2. Tekst1:"Test",
  3. Liczba1:"1",
  4. Liczba2:"2",
  5. Tekst2:"abc"
  6. }

Jak widać kolejność elementów w tablicy zdeterminowała kolejność właściwości obiektu.

Jeżeli zastosowali byśmy zapis:

  1. var wartosci = ["Test",1,2,"abc",3,4,"efg"];
  2.  
  3. wartosci.link({
  4. "Tekst1":String.type,
  5. "Tekst2":String.type,
  6. "Liczba1":Number.type,
  7. "Liczba2":Number.type,
  8. "Element1":Element.type
  9. });

To nadal otrzymamy obiekt tej samej postaci co poprzednio, bo jeżeli tablica nie zawiera elementu „wymaganego” przez jedną z właściwości obiektu to owa właściwość nie istnieje w zwracanym obiekcie.

Zamijmy się teraz metodami contains, getLast i getRandom – pierwsza z tych metod zwraca wartość logiczną zależną od tego czy element o danej wartości istnieje w tablicy (true) czy też nie (false). Metody getLast i getRandom jak sama nazwa wskazuje zwracają odpowiednio ostatni i losowy element tablicy.

Myślę, że funkcje te są na tyle proste, że trzy proste przykłady użycia wystarczą :

  1. [1,2,3,4,5].contains(1); //zwróci true
  2. [1,2,3,4,5].contains(0); //zwróci false

Zapis:

  1. [].getLast();

Zwróci wartość null – to samo stanie się w przypadku użycia dla pustej tablicy metody getRandom.

Pora na omówienie metod, które potrafią dodać co nieco do naszej tablicy – extend i merge. Teoretycznie robią to samo – łączą dwie tablice w jedną. W praktyce w wypadku metody extend następuje takowe połączenie bez względu na wartości elementów tablic, a w wypadku merge nie zostają dodane do pierwotnej tablicy elementy, które już w niej występują. Tradycyjne już przykłady z liczbami:

  1. [1,2,3].extend([3,4,5]);

Powyższy kod zwróci tablicę postaci:

  1. [1, 2, 3, 3, 4, 5]

Natomiast w wypadku użycia metody merge:

  1. [1,2,3].merge([3,4,5]);

Otrzymamy tablicę postaci:

  1. [1, 2, 3, 4, 5]

Tak jak w wypadku poprzednich metod – wielkiej filozofii tutaj nie ma, tak samo zresztą jak w wypadku dwóch kolejnych metod – include i remove. Pierwsza z nich dodaje nowy element o podanej wartości do tablicy jeżeli on jeszcze w niej nie istnieje, a metoda remove usunie dany element (o podanej wartości) z tablicy (o ile istnieje).

Jak widać metody te to typowe uproszczenia najczęściej wykonywanych operacji na tablicach – zamiast paru linijek (w wypadku remove musimy pętlą przeszukać tablicę, usunąć element jeżeli istnieje i zwrócić element) piszemy jedną (jak to w wielu wypadkach w MooTools bywa ;) ).

Zapis:

  1. [1,2,3,4,5].include(5);

Zwróci nam tablicę postaci:

  1. [1, 2, 3, 4, 5]

a zapis:

  1. [1,2,3,4,5].include(6);

zwróci tablicę postaci:

  1. [1, 2, 3, 4, 5, 6]

W wypadku metody remove ostatni przykład zwróci tablicę:

  1. [1, 2, 3, 4, 5]

a przedostatni przykład zwróci tablicę postaci:

  1. [1, 2, 3, 4]

Poza metodami konwertującymi pozostały nam jeszcze trzy metody, które dość mocno potrafią ingerować w strukturę tablicy – clean, empty i flatten. Metoda empty czyści tablicę zupełnie:

  1. [1,2,3,4,5].empty();

Zwróci nam po prostu:

  1. []

Metoda clean też czyści tablicę, ale z elementów „pustych”, takich jak “”, zera czy null:

  1. [1,'',0,null,2,3].clean();

Zwróci nam tablicę postaci:

  1. [1,2,3]

Metoda flatten „spłaszcza” tablice wymiarowe do jednowymiarowych. Parę przykładów w wymiarach od pierwszego do trzeciego :

  1. [1,2,3,4,5].flatten();

Powyższy kod zwróci nam po prostu tą samą tablicę bo sama w sobie jest już jednowymiarowa, ale jeżeli będziemy mieli tablicę dwuwymiarową 3 x 3:

  1. [[1,2,3],[1,2,3],[1,2,3]].flatten();

To zostanie zwrócona tablica postaci:

  1. [1, 2, 3, 1, 2, 3, 1, 2, 3]

Weźmy jeszcze tablicę trójwymiarową 3 x 3 x 3:

  1. [[[1,2,3],[1,2,3],[1,2,3]],[[1,2,3],[1,2,3],[1,2,3]],[[1,2,3],[1,2,3],[1,2,3]]].flatten();

Otrzymamy z tego tablicę :

  1. [1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]

Można łatwo zauważyć, że jeżeli rozpiszemy sobie nasza wielowymiarową tablicę to metoda flatten zwróci nam postać bez zbędnych nawiasów kwadratowych ;)

Na koniec pozostały nam do omówienia metody konwertujące zapis heksadecymalny na RGB i na odwrót – hexToRgb i rgbToHex.

Metoda hexToRgb konwertuje zapis heksadecymalny na zapis RGB, przy czym warto uważać bo zapis:

  1. '#FFFFFF'.hexToRgb();

nie oznacza wcale użycia metody hexToRgb z pliku Array.js tylko z pliku String.js. Aby użyć metody z pliku Array.js musimy zastosować zapis:

  1. ["FF","FF","FF"].hexToRgb();

choć w wypadku powtarzających się wartości „F” wystarczy nawet zapis:

  1. ["F","F","F"].hexToRgb();

Metoda hexToRgb pobiera jeden argument będący wartością logiczną, która decyduje o tym, czy zwracana wartość również jest tablicą (true) czy ciągiem postaci rgb(liczba,liczba,liczna) (false).

Jeżeli chodzi o metodę rgbToHex to także musimy wykorzystać zapis RGB w postaci tablicy, a zapis heksadecymalny zostanie zwrócony jako tablica gdy argument metody rgbToHex ma wartość true. W przeciwnym wypadku zostanie zwrócony ciąg postaci #XXXXXX, gdzie XXXXXX to dowolna wartość w zapisie heksadecymalnym…

I to wszystko co miałem do napisania o obsłudze tablic w MooTools 1.2 . W następnej części kursu zajmiemy się obiektami Function i Event.

Obiekty natywne – Funkcje i zdarzenia

Pora zająć się właściwie nieodłącznymi elementami każdego skryptu pisanego w JavaScript, a już na pewno pisanego przy użyciu frameworka MooTools – w tej części kursu omówię funkcje i związane z nimi zdarzenia. Zapewnienie jakiejkolwiek interakcji z użytkownikiem jest związane z tymi dwoma zagadnieniami – zdarzenia pozwalają skryptowi reagować na działania użytkownika, a owe reakcje są opisane przez funkcje. MooTools daje nam dostęp do obiektów Function i Event rozszerzonych o wiele przydatnych metod i właściwości.

Obiekt Function

Zacznijmy od obiektu Function – w MooTools posiada on następujące metody: create, pass, attempt, bind, bindWithEvent, delay, periodical, run.

Metoda create jest tutaj podstawą istnienia pozostałych metod, gdyż wszystkie inne metody obiektu Function to po prostu create wywołana z odpowiednimi parametrami – celem ich istnienia jest zwięzłość zapisu, gdyż jak się za chwilę przekonamy, metoda create jest dość rozbudowana.

Przyjmuje ona następujące parametry:

  • bind – uchwyt do obiektu, który będzie w ciele funkcji powiązany z operatorem this. Domyślnie operator this odnosi się do funkcji
  • event – wartość logiczna określająca czy funkcja będzie używana jako obserwator zdarzeń (ang. event listener). Domyślna wartość to false. Jeżeli funkca jest obserwatorem zdarzeń to jako pierwszy argument pobiera uchwyt do zdarzenia
  • arguments – argument/y pobierane przez funkcję. Jeżeli argument jest jeden to zapisujemy go normalnie, w wypadku większej ilości argumentów podajemy je jako tablicę argumentów
  • delay – opóźnienie wykonania danej funkcji podane w milisekundach
  • periodical – parametr określający czas, który mija pomiędzy kolejnymi wykonaniami funkcji (jest ona wykonywana okresowo co podaną ilość milisekund)
  • attempt – parametr logiczny, który w wypadku wartości true powoduje wykonanie funkcji, a gdy zostaną stwierdzone błędy w jej działaniu funkcja zwraca wartość logiczną false

Stwórzmy teraz kopię już istniejącej funkcji zdefiniowanej jako:

  1. var funkcjaTestowa = function(){
  2. alert("Test funkcji");
  3. }

Aby skopiować sobie tą funkcję i móc nią dalej manipulować w MooTools zapisujemy co następuje:

  1. var tester = funkcjaTestowa.create();

Od teraz obiekt tester działa tak samo jak nasza funkcjaTestowa. Możemy to łatwo sprawdzić wpisując w konsoli:

  1. tester();

Ujrzymy alert z komunikatem takim jaki generuje właśnie funkcjaTestowa.

Gdybyśmy zapisali :

  1. var tester = funkcjaTestowa.create({delay: 2000});

Wtedy ten sam alert pokazałby się dopiero po dwóch sekundach.

Warto jeszcze zwrócić uwagę na parametry event i arguments – jeżeli oba są podane (event ma wartość true, a arguments jest niepusty lub jest tablicą) wtedy funkcja przy wywołaniu jako pierwszy argument pobiera obiekt zdarzenia, a jako kolejne pobiera argumenty. Jeżeli tylko jeden z parametrów jest określony, wtedy jest on pobierany z pierwszej pozycji.

Metoda create jest przydatna wtedy gdy musimy zmodyfikować kilka parametrów naraz. W sytuacji pojedynczych zmian lepiej stosować pozostałe metody obiektu Function.

Zacznijmy od metody pass – jest to metoda create ograniczona do określenia parametrów arguments i bind. Stwórzmy prostą funkcję dodającą podane jako argumenty liczby:

  1. var dodawanie = function(){
  2. var suma = 0;
  3.  
  4. for(var i = 0;i < arguments.length;i++) suma += arguments[i];
  5.  
  6. return suma;
  7. }

Zwróćmy uwagę, że powyższa funkcja jest elastyczna – nie ma określonej stałej liczby argumentów – możemy ich podać nieskończenie wiele, a ta funkcja je wszystkie doda.

Stwórzmy jej wersję z różnymi liczbami podanymi jako obiekt dodawanie z metodą pass:

  1. var dwa = dodawanie.pass([1,1]);
  2. var siedem = dodawanie.pass([1,2,4]);
  3. var dwadziescia = dodawanie.pass(20);

Gdy wywołamy powyższe funkcje otrzymamy wyniki:

  1. 2
  2. 7
  3. 20

Dla odmiany teraz będziemy dzielić :) Stworzymy funkcję, która ma błąd składniowy:

  1. var dzielenie = function(){
  2. return 100/a;
  3. }

Zmienna a nie jest zadeklarowana i normalne wywołanie:

  1. dzielenie();

spowoduje wystąpienie błędu. Aby tego uniknąć zastosujemy metodę attempt:

  1. dzielenie.attempt();

Zamiast nieoczekiwanego błędu uzyskamy po prostu wartość false.

Warto dodać, że metoda attempt może pobierać dwa argumenty – argumenty funkcji oraz parametr bind.

Kolejna z metod – bind pobiera trzy parametry – bind, arguments i event (w tej właśnie kolejności). Stwórzmy funkcję, która obiektowi do którego odnosi się operator this nada szary kolor tła:

  1. var tlo = function(){
  2. this.style.backgroundColor = '#EEE';
  3. }
  4.  
  5. tloNowe = tlo.bind(document.body);
  6.  
  7. tloNowe();

Przy okazji mała uwaga – w naszym wypadku lepiej byłoby wykorzystać metodę attempt – ponieważ bardzo łatwo podać argument nie będący elementem, któremu można zmienić tło:

  1. var tlo = function(){
  2. this.style.backgroundColor = '#EEE';
  3. }
  4.  
  5. tlo.attempt(false,document.body);

Zauważmy jednak, że wywołanie metody attempt jest równoznaczne z wykonaniem naszej funkcji, w wypadku metody bind możemy zmodyfikować funkcję i wywołać ją kiedy chcemy.

Metoda bindWithEvent pobiera takie same parametry jak metoda bind poza event. Jaka jest różnica pomiędzy nimi? Właśnie to, że nie pobiera parametru event – jest on domyślnie ustawiony jako true. Dzięki temu w ciele funkcji możemy wykorzystywać różne możliwości związane z obiektem Event, ale o tym połączeniu napiszę nieco później, gdy zdobędziemy wystarczającą ku temu wiedzę.

Metody delay i periodical to jedne z częściej używanych metod – pozwalają szybko ustalić opóźnienie lub okresowość funkcji. Warto przy ich stosowaniu zapisywać uchwyt do tzw. timera, po to by mieć możliwość zatrzymania odliczania, bądź przerwania okresowego wykonywania funkcji:

  1. var timer = (function(){alert("Test");}).delay(5000);

Możemy przerwać odliczanie wykonaniem kodu:

  1. $clear(timer);

To samo ma miejsce w wypadku metody periodical.

Większość z prezentowanych tutaj funkcji poznamy bliżej podczas opisu manipulowania elementami i tworzenia animacji z użyciem MooTools – wtedy będzie można zobaczyć jak ogromny drzemie w nich potencjał i jak bardzo są one pomocne w skracaniu zapisu.

Ostatnia metoda obiektu Function to metoda run – pobiera ona takie same parametry jak metoda pass, ale jej działanie jest inne – w wypadku użycia metody run następuje od razu wykonanie funkcji. Dla przykłady weźmy nasz kod z przykładu dla metody pass:

  1. var dodawanie = function(){
  2. var suma = 0;
  3.  
  4. for(var i = 0;i < arguments.length;i++) suma += arguments[i];
  5.  
  6. return suma;
  7. }
  8.  
  9. var siedem = dodawanie.pass([1,2,4]);
  10.  
  11. siedem();

i zamieńmy go na wersję z użyciem metody run:

  1. var dodawanie = function(){
  2. var suma = 0;
  3.  
  4. for(var i = 0;i < arguments.length;i++) suma += arguments[i];
  5.  
  6. return suma;
  7. }
  8.  
  9. dodawanie.run([1,2,4]);

Krótko mówiąc nie musimy tworzyć nowej zmiennej by uruchomić funkcję.

A gdy jeszcze wykorzystamy chaining obecny we wszystkich obiektach natywnych to zauważymy, że na przykład kod:

  1. var tlo = function(){
  2. this.style.backgroundColor = '#EEE';
  3. }
  4.  
  5. tloNowe = tlo.bind(document.body);
  6.  
  7. tloNowe();

można z powodzeniem zamienić na :

  1. var tlo = function(){
  2. this.style.backgroundColor = '#EEE';
  3. }
  4.  
  5. tlo.bind(document.body).run();

To wszystkie metody obiektu Function, omówimy teraz obiekt Event tak by uzupełnić trochę naszą wiedzę, gdyż w większości skryptów JavaScript te dwa obiekty jak już wspominałem są nierozłączne.

Obiekt Event

Obiekt Event w MooTools posiada kilkanaście właściwości oraz trzy metody. Te metody będą nam przydatne dopiero w wypadku operowania na elementach dokumentu jednak już teraz warto być świadomym ich istnienia.

Metoda stopPropagation jest przydatna na przykład w sytuacji, gdy element nadrzędny posiada przypisane jakieś zdarzenie, dla przykładu onclick – wtedy po dodaniu tego zdarzenia do elementu potomnego kliknięcie w tenże element powoduje wywołanie dwóch zdarzeń – elementu potomnego i jego rodzica. Aby tego uniknąć stosujemy metodę stopPropagation. Składnia jest prosta:

  1. obiektKlasyEvent.stopPropagation();

Powyższy kod umieszczony w funkcji przypisanej do obserwatora zdarzeń spowoduje, że żadne zdarzenia z elementów nadrzędnych nie będą wykonywane.

Druga istotna metoda to preventDefault – składnia podobna jak poprzednio:

  1. obiektKlasyEvent.preventDefault();

Metoda ta jest niezwykle przydatna w wypadku zdarzeń onclick takich elementów jak linki czy chociażby przycisk submit w formularzu. Dlaczego? Domyślnie po kliknięciu w link niezależnie od tego co dalej zrobimy zostaniemy przeniesieni do adresu wskazywanego przez atrybut href linka. Metoda preventDefault blokuje tę standardową akcję. Warto zauważyć, że w wypadku przycisku submit w formularzu jest to nieoceniona pomoc – gdy mamy interfejs, który pracuje zarówno z jak i bez JS.

Jeżeli musimy naraz powstrzymać propagowanie zdarzeń i akcję domyślną możemy skorzystać z metody stop:

  1. obiektKlasyEvent.stop();

Powyższy zapis jest równoznaczny zapisowi:

  1. obiektKlasyEvent.stopPropagation();
  2. obiektKlasyEvent.preventDefault();

czyli krótko mówiąc – takie 2w1 :)

Omówię teraz właściwości obiektów klasy Event:

Poniższe właściwości przyjmują wartość true, jeżeli użytkownik kliknął dany klawisz:

  • shift – klawisz Shift
  • control – klawisz Ctrl
  • alt – klawisz Alt
  • meta – metaklawisz

Obiekt Event ma także właściwość związaną z rolką myszki:

  • wheel – właściwość ta zwraca nam ilość obrotów rolki

Dzięki obiektowi klasy Event możemy także odczytać informacje o wciskanych klawiszach:

  • code – kod wciśniętego klawisza
  • key – wartość wciskanego klawisza (małe litery). Dodatkowo klawisze mogą mieć wartości: enter, up, down, left, right, space, backspace, delete, esc.

Dzięki poniższym właściwościom możemy odczytać dokładną pozycję kursora myszki:

  • page.x – współrzędna x kursora myszki względem całego okna
  • page.y – współrzędna y kursora myszki względem całego okna
  • client.x – współrzędna x kursora myszki względem widocznego fragmentu okna
  • client.y – współrzędna y kursora myszki względem widocznego fragmentu okna

Na koniec dwie właściwości związane z elementem, którego dotyczy zdarzenie:

  • target – ta właściwość zwraca uchwyt do elementu dla którego zostało wykonane zdarzenie
  • relatedTarget – dzięki tej właściwości możemy uzyskać uchwyt do elementu nad jakim znalazł się kursor po opuszczeniu obszaru elementu z przypisanym zdarzeniem mouseout

Ja osobiście bardzo upodobałem sobie właściwość target – dzięki niej mogę drastycznie ograniczyć ilość event listenerów – zamiast tworzyć kilkanaście zdarzeń, tworzę jedno i na podstawie wartości tej właściwości wykonuję odpowiednią operację – jest to nieoceniona pomoc zwłaszcza w wypadku interfejsów opartych na AJAX, gdzie pewne elementy mogą być ładowane dynamicznie – dzięki stosowaniu właściwości target nie trzeba tworzyć kilkunastu event listenerów przy każdym wczytaniu danych :) Z pewnością zaprezentuję tą użyteczną metodę w przykładach omawiających manipulowanie elementami dokumentu – póki co ciągle studiujemy teoretyczne podstawy MooTools ;)

Pozostaje nam jeszcze obiekt Event.keys – zawiera on kody wybranych klawiszy. Jeżeli chcemy do wartości zwracanych przez właściwość key obiektu Event dodać własne klawisze z własnymi nazwami stosujemy zapis:

  1. Event.keys.nazwaKlawisza = kodKlawisza;

Dzięki temu możemy potem stosować zapis postaci:

  1. if(event.key == "nazwaKlawisza") { ... }

Teorię już znamy – na praktykę przyjdzie czas podczas omawiania możliwości Element.Event i nie tylko ;)

Dalsze części kursu MooTools 1.2 już wkrótce…

Czytaj więcej:
Artykuły » JavaScript
Tagi:
,

Tomasz Dziuda

Tomasz "Dziudek" Dziuda - blogger, twórca stron internetowych, student informatyki na Politechnice Łódzkiej. W obszarze jego zainteresowań znajduje się przede wszystkim JavaScript i framework MooTools.

Zobacz wszystkie artykuły tego autora (1)

  1. MooTools jest jednym z częściej używanych przeze mnie frameworków JS – jest moim ulubionym.

    Ten tutorial okazał się bardzo przydatny szczególnie, że dotyczy wersji 1.2, którą napewno zacznę już teraz stosować.

    Dzięki

  2. :-) dzięki za pomoc
    bardzo się przyda, mootools jest super :D
    niedługo zrobię aktualizację stronki :) będzie z użyciem mootools :)

  3. mrk 3

    Bóg Ci zapłać dobry człowieku. Bardzo fajny tutorial.

  4. Robert 4

    bardzo fajny opis! kiedy pojawi się opis pozostałych funkcji Mootools1.2??

  5. bodek 5

    bardzo fajny i sensowny artykul jakiego szukalem

  6. Bardzo fajny tut. Przydałoby się więcej coś z multimediów, zdjęcia, filmy?

  7. Korkie 7

    NooTools jest świetny, a ten tutorial bardzo przydatny.
    Cieszę się, że powstają takie kursy.
    Ten będę szczególnie polecał innym.

  8. Robert 8

    Czysto, przejrzystym językiem i rzeczowo napisany kurs. Mam nadzieję, że wiele osób z niego skorzysta. Polecę zapoznanie się z nim na swojej stronie. Od jakiegoś czasu stosuję 1.11 teraz “przesiadam” się na 1.2. Szacun: Robert.

  9. Adam 9

    Ja teraz używam naraz Mootools i jQuery i jak na razie nie mam z nimi kłopotów :]

Dodaj komentarz * pola obowiązkowe

 
 

Dozwolone tagi HTML: <strong> <em> <a href="" title=""> <code> <pre lang=""> <blockquote cite="">

Komentarze są moderowane. Mile widziane wpisy wnoszące nowe, ciekawe informacje do omawianego tematu
lub sygnalizujące ewentualne błędy merytoryczne. Wszelkie przejawy spamu lub nieetycznego zachowania bedą
karane blokadą adresu IP/domeny.