Kurs Mootools 1.11
Autor: Dziudek. Pierwotna wersja kursu.
Spis treści
Jądro frameworka
Obsługa klas
Klasy natywne
Obsługa elementów
Obsługa okna
Obsługa połączeń i plików
Efekty
Przenoszenie elementów
Pluginy
- Hash.js
- Hash.Cookie.js
- Color.js
- Group.js
- Scroller.js
- Slider.js
- SmoothScroll.js
- Sortables.js
- Tips.js
- Accordion.js
Mootools 1.11 - Core.js do góry
Tym wpisem zaczynam omawianie frameworka mootools w wersji 1.1, jak zapewne wiele osób się orientuje nie kontynuuję kursu mootools 1.0 , ponieważ w trakcie jego powstawania wyszła nowa wersja mootools - właśnie 1.1 . Jednak osoby, które czytały poprzednią wersję kursu nie powinny się martwić - wiele rzeczy jest podobnych, a pierwsze wpisy o Mootools 1.11 będą służyły tak naprawdę uporządkowaniu struktury kursu opartej na nowej strukturze frameworka mootools.
Plik core.js jak się pewnie domyślacie stanowi jądro frameworka mootools - zawiera podstawowe funkcje i tworzy podstawowe obiekty. Warto zwrócić uwagę na fakt powstania obiektu MooTools, który obecnie zawiera informację o aktualnie używanej wersji frameworka, ale w przyszłości z pewnością będzie rozbudowywany o dodatkowe informacje (bo po co stosowano by obiekt, gdyby chciano tylko przechowywać numer wersji ?).
Dostęp do informacji o aktualnej wersji frameworka uzyskamy poprzez zapis:
MooTools.version;
więc aby wyświetlić tą informację np. w alercie zapiszemy:
alert(Mootools.version);
Poza wspomnianym obiektem MooTools w pliku core.js zawarte są także funkcje do operowania na obiektach, klasa Abstract, dodatkowe funkcje oraz kilka dodatkowych rozszerzeń dla obiektów window i document. Zacznijmy od funkcji do operowania na obiektach - jest ich 5 : $defined, $type, $merge, $extend i $native...
$defined
Funkcja $defined służy do sprawdzania czy dany obiekt jest zdefiniowany - jeśli tak to zwraca ona wartość logiczną true, w przeciwnym wypadku zwracaną wartością jest logiczne false.
Użycie tej funkcji jest bardzo proste - przebiega według następującego schematu:
$defined(sprawdzany_obiekt);
Na przykład:
$defined(document.html);
Zwróci wartość false, natomiast:
$defined(document.body);
Zwróci wartość true... Skoro już tak mówimy o tych document.* to sprawdźcie co zwróci wywołanie:
$defined(document.head);
True ? Tak to prawda - w pliku core.js zdefiniowano także obiekt document.head, który odnosi się do sekcji HEAD naszego dokumentu...
No to mały przykład na podsumowanie funkcji $defined:
$type
Funkcja $type zwraca typ obiektu podanego jako argument. Zwracane są następujące wartości:
- 'element' - gdy obiekt jest węzłem drzewa dokumentu (DOM),
- 'textnode' - gdy obiekt jest węzłem tekstowym drzewa dokumentu,
- 'whitespace' - gdy obiekt jest węzłem drzewa dokumentu będącym białymi znakami,
- 'object' - gdy obiekt jest obiektem ( ;-) ),
- 'string' - gdy obiekt jest ciągiem znaków,
- 'number' - gdy obiekt jest liczbą,
- 'boolean' - gdy obiekt jest wartością logiczną,
- 'function' - gdy obiekt jest funkcją,
- 'array' - gdy obiekt jest tablicą,
- 'regexp' - gdy obiekt jest wyrażeniem regularnym,
- 'class' - gdy obiekt jest klasą,
- 'collection' - gdy obiekt jest kolekcją węzłów drzewa dokumentu,
- false - gdy obiekt nie jest zdefiniowany lub nie należy do żadnego z powyższych typów.
Użycie funkcji $type wygląda tak samo jak w wypadku funkcji $definied:
$type(obiekt);
Na przykład :
$type(25);
Zwróci nam wartość 'number'.
Więcej przykładów użycia zawarłem w poniższym przykładzie:
$merge
Funkcja $merge służy do łączenia wielu obiektów w jeden. Warto pamiętać, że w momencie gdy pewne pola powtarzają się w kilku obiektach to będą one nadpisywane i w obiekcie złożonym ze złączonych obiektów zostanie wartość pola pochodząca z ostatniego obiektu w którym powtarzające się pole wystąpiło.
Składnia funkcji wygląda następująco:
$merge(obiekt_1,obiekt_2,...,obiekt_n);
Na przykład:
var obiekt1 = {
'test1': 1,
'test2': 2
}
var obiekt2 = {
'test3': 3,
'test4': 4
}
var obiekt3 = {
'test5': 5
}
var obiekt123 = $merge(obiekt1,obiekt2,obiekt3);
Powstały obiekt obiekt123 będzie zawierał pola test1, test2, test3, test4 i test5 o wartościach od 1 do 5.
W wypadku gdy dane pole występuje w kilku obiektach:
var obiekt1 = {
'test1': 1,
'test2': 2
}
var obiekt2 = {
'test1': 2,
'test2': 3
}
var obiekt3 = {
'test3': 3
}
var obiekt123 = $merge(obiekt1,obiekt2,obiekt3);
Powstały obiekt obiekt123 będzie zawierał trzy pola - test1, test2 i test3 o wartościach odpowiednio - 2,3 i 3.
Przykład działania funkcji $merge:
$extend
Funkcja $extend ma podobne działanie co funkcja $merge z tą różnicą, że jako argumenty podajemy tylko dwa obiekty i zwracany jest pierwszy obiekt rozszerzony o pola drugiego obiektu.
Składnia funkcji wygląda następująco:
$extend(Obiekt_rozszerzany,Obiekt2);
W tym wypadku zostanie zwrócony Obiekt_rozszerzany rozszerzony o pola obiektu Obiekt2.
I przykład działania funkcji $extend:
$native
Funkcja $native służy do rozszerzania obiektu o pola innych obiektów wtedy gdy nie posiada on pól, które posiadają podawane jako argumenty obiekty - mootools wykorzystuje funkcję $native aby dodać do przeglądarek obsługę niektórych funkcji, które nie są obsługiwane przez wszystkie przeglądarki.
Składnia funkcji $native:
$native(Obiekt1, Obiekt2, Obiekt3,... , ObiektN);
Klasa Abstract
Klasa ta to w rzeczywistości funkcja, która działając według wzorca singletonu pozwala na ograniczenie liczby instancji danej klasy...
Z wykorzystaniem klasy Abstract mootools generuje dwa dodatkowe obiekty - Window i Document dzięki czemu możemy je stosować zamiennie z obiektami window i document...
Aby wykorzystać klasę Abstract do stworzenia obiektu z wykorzystaniem wzorca singleton wystarczy zapis:
var NowyObiekt = new Abstract(ObiektPodstawowy);
Przejdźmy teraz do pozostałych funkcji zawartych w pliku core.js . Są to : $chk, $pick, $random, $time oraz $clear.
$chk
Funkcja $chk służy do sprawdzania czy podany jako argument obiekt istnieje lub jest zerem. W takim wypadku funkcja ta zwraca wartośc logiczną true, w przeciwnym wypadku zostaje zwrócona wartość logiczna false.
Składnia funkcji $chk:
$chk(obiekt_do_sprawdzenia);
$pick
Funkcja $pick wykorzystuje się do sprawdzania czy dany obiekt istnieje - w wypadku gdy nie jest on zdefiniowany jest używany podany jako drugi argument obiekt. Składnia tej funkcji wygląda następująco:
$pick(Obiekt1, Obiekt2);
W wypadku gdy obiekt Obiekt1 nie jest zdefiniowany zwracany jest obiekt Obiekt2 w przeciwnym wypadku zwracany jest obiekt Obiekt1.
Przykład użycia:
function informacja(text){
alert($pick(text,'Brak treści informacji !'));
}
W wypadku gdy nie zdefiniowano zmiennej text zostanie pokazany alert z tekstem 'Brak treści informacji !'.
$random
Funkcja $random służy do generowania pseudolosowej liczby z podanego zakresu. Użycie funkcji:
$random(min,max);
Powyższy kod zwróci liczbę pseudolosową z zakresu <min,max>, na przykład:
$random(10,20);
Zwróci liczbę z przedziału <10,20>
$time
Funkcja $time zwraca ilość milisekund jakie upłynęły od 1 stycznia 1970 00:00:00.
Funkcja ta nie pobiera żadnych argumentów, zatem jej użycie ogranicza się do zapisu :
$time();
$clear
Ostatnią funkcją w pliku core.js jest $clear(), która służy do usuwania okresowego lub opóźnionego wywoływania funkcji z użyciem setInterval() i setTimeout() (ich mootools'owe odpowiedniki to periodical() i delay(), ale o nich dowiemy się więcej przy okazji omawiania pliku function.js).
Użycie funkcji ogranicza się do podania jako argumentu danej zmiennej odpowiadającej funkcji setInterval() lub setTimeout():
var timer = setInterval("funkcja()",2500);
$clear(timer);
Obiekt window
Plik core.js rozszerza obiekt window o właściwości, które pozwalają na identyfikację typu przeglądarki. W stosunku do mootools 1.0 doszło kilka nowych właściwości. Przedstawiam wszystkie poniżej i odpowiadające im przeglądarki:
window.ie- Internet Explorer (dowolna wersja),window.ie6- Internet Explorer 6window.ie7- Internet Explorer 7window.gecko- wszystkie przeglądarki oparte o Gecko - Firefox, Mozilla itd.window.webkit- Safari / Konquerorwindow.webkit419- Safari 2window.webkit420- Safari 3window.opera- Opera
Sprawdzenie jakiej przeglądarki używa internauta ogranicza się do sprawdzenia czy dany obiekt istnieje np.:
if(!window.ie){
alert('Używasz przeglądarki innej niż Internet Explorer');
}
else{
alert('Używasz przeglądarki Internet Explorer');
}
To wszystko na temat pliku core.js - w dwóch następnych częściach kursu zajmiemy się plikami z grupy Class wspomagających programowanie obiektowe w JavaScript.
Mootools 1.11 - Class.js do góry
Plik class.js to pierwszy z dwóch plików grupy Class we frameworku mootools. Zawiera on podstawowe funkcje przydatne przy programowaniu obiektowym w JavaScript. Grupa Class powstała dopiero w wersji 1.1 mootools - wcześniej funkcje, które oferuje były dostępne w plikach moo.js, event.js oraz common.js . Obecna forma podziału jest według mnie o wiele lepsza, choć framework składa się teraz z większej ilości części...
Tworzenie klas przy użyciu mootools jest bardzo proste - w najprostszym wypadku ograniczy się do zapisu:
var NowaKlasa = new Class();
Ale oczywiście w tym wypadku żadnego pożytku z takiej klasy mieć nie będziemy ;) Dlatego warto dodać do naszej klasy kod, który wykona się zaraz po jej stworzeniu - służy do tego metoda initialize. Przykładowy kod (Przy okazji zmienię nazwę klasy):
var Komputer = new Class({
initialize: function(){
alert('Komputer został stworzony :D');
}
});
Dzięki zastosowaniu metody initialize po wystąpieniu zapisu:
var Pecet = new Komputer();
Pojawi się alert z odpowiednim tekstem.
A może chcemy by nasz komputer posiadał jakieś własne cechy ? Co to za komputer bez IP ;) Tak więc dodajmy przy inicjalizacji naszemu komputerkowi IP. Możemy to zrobić na dwa sposoby - sami zdecydować jakie IP będzie miał komputer, albo też dać użytkownikowi pole do popisu i pozwolić mu samemu wybrać. Zaprezentuje oba przypadki:
Sami nadajemy IP komputerowi:
var Komputer = new Class({
initialize: function(){
this.IP = '127.0.0.1';
}
});
Dajemy możliwość podania IP komputera użytkownikowi przy inicjalizacji:
var Komputer = new Class({
initialize: function(ip){
this.IP = ip;
}
});
IP jest od tej pory polem każdego obiektu klasy Komputer. Stwórzmy sobie teraz dwa komputery :
var Pecet = new Komputer();
powyższy kod dla pierwszego kodu z nadawanie IP komputerowi, a poniższy kod dla drugiego kodu:
var Pecet = new Komputer('192.168.0.1');
W obu wypadkach aby odczytać IP obiektu Pecet wystarczy zapis:
Pecet.IP;
To tak słowem wstępu o tworzeniu klas z użyciem mootools. A teraz przejdźmy do tego co jeszcze udostępnia nam plik class.js . Zacznijmy od metody empty - gdy tworzymy klasy zawierające kilka metod, może się zdarzyć potrzeba stworzenia pustej funkcji. Wtedy zamiast zapisu:
var Komputer = new Class({
initialize: function(ip){
this.IP = ip;
},
uruchom: function(){}
});
Możemy zastosować zapis:
var Komputer = new Class({
initialize: function(ip){
this.IP = ip;
},
uruchom: this.empty;
});
Oczywiście działanie metody jest natury nazwijmy to "uczytelniającej" ;) O wiele ciekawsze będą dla nas metody extend i implement.
extend
Jeżeli mamy dużo klas w projekcie to z pewnością pomiędzy nimi istnieją jakieś podobieństwa. Bazując już na znanej nam klasie Komputer - podobieństwo pomiędzy makiem, a PC będzie takie, że na pewno oba mają jakieś IP. Zatem zamiast tworzyć od podstaw klasy MAC i PC możemy rozszerzyć możliwości klasy Komputer. Do tego celu używamy właśnie metody extend. Gdy chcemy stworzyć klasę opartą o istniejącą już klasę zapiszemy:
var NowaKlasa = StaraKlasa.extend({
initialize: function(nowa_cecha,stara_cecha){
this.parent(stara_cecha);
this.cecha = nowa_cecha;
}
});
Powyższy kod spowoduje, że zapis:
var NowyObiekt = new NowaKlasa(nowa_cecha,stara_cecha);
Stworzy nowy obiekt oparty o klasę NowaKlasa, która posiada dwie właściwości - nowa_cecha i stara_cecha, przy czym zapis this.parent(stara_cecha) powoduje odwołanie do klasy StaraKlasa, która tworzy właściwość stara_cecha... Tak na sucho to pewnie ciężko to przyswoić ale myślę, że konkretne przykłady rozjaśnią sprawę ;)
Stwórzmy zatem dwie klasy - MAC i PC będące rozszerzeniem klasy Komputer:
var Komputer = new Class({
initialize: function(ip){
this.IP = ip;
}
});
var PC = Komputer.extend({
initialize: function(os,ip){
this.parent(ip);
this.system = os;
}
});
var MAC = Komputer.extend({
initialize: function(wyglad,ip){
this.parent(ip);
this.wyglad = wyglad;
}
});
var Mak = new MAC('uroczy','127.0.0.1');
var Blaszak = new PC('linux','192.168.0.1');
Mamy zatem dwa obiekty i każdy z nich posiada po dwie właściwości - jedną dziedziczoną z klasy Komputer i jedną charakterystyczną tylko dla siebie - w wypadku klasy MAC jest to właściwość "wyglad", a w wypadku klasy PC jest to właściwość "system".
Oczywiście do właściwości odwołujemy się tak jak już wcześniej pokazywałem:
Mak.IP;
Mak.wyglad;
Blaszak.IP;
Blaszak.system;
Oczywiście rozszerzanie możliwości klasy metodą extend nie ogranicza się tylko do dodawania nowych pól - możemy też dodawać całe funkcje do klas bazujących na innej klasie - wszystko zależy od tego co umieścimy w argumentach metody extend ;)
implement
Czasami zachodzi potrzeba rozszerzenia funkcjonalności danej klasy, oczywiście można to zrobić za pomocą metody extend, ale po co generować sobie dodatkowe klasy ? Metoda extend przydaje się raczej gdy chcemy ujednolicić pewne właściwości wielu klas, a gdy chcemy sprawić by nasza klasa oferowała większe możliwości wykorzystajmy metodę implement. Służy ona do rozszerzania funkcjonalności danej klasy bez tworzenia nowych klas. Składnia tej metody wygląda następująco:
Klasa.implement({
NowaFunkcja: function(argumenty){
// kod nowej funkcji
}
});
Po wykonaniu powyższego kodu nasza klasa będzie oferowała dodatkową funkcjonalność. To teraz bardziej konkretny przykład - oczywiście bazujący na klasie Komputer ;)
var Komputer = new Class({
initialize: function(ip){
this.IP = ip;
}
});
Komputer.implement({
uruchom: function(){
alert('Komputer został uruchomiony...');
}
});
Dzięki powyższemu zapisowi możemy teraz z powodzeniem stosować zapis:
var Blaszak = new Komputer('127.0.0.1');
Blaszak.uruchom();
Tym razem nie daję przykładów bo nie chcę Was zamęczyć alertami ;) Ale w następnej części kursu przykłady będą bo jest co pokazać ;)
W następnej części kursu przejdziemy do pliku class.extras.js , który zawiera więcej funkcji do operowania na klasach.
Mootools 1.11 - Class.Extras.js do góry
Plik class.extras.js zawiera trzy klasy - Chain, Events i Options. Rozszerzają one możliwości operowania na klasach. Klasa Chain umożliwia łańcuchowe wykonywanie funkcji (jedna po drugiej). Dzięki klasie Events możemy operować zdarzeniami towarzyszącymi wykonywaniu metod klas, a klasa Options pozwoli nam na trzymanie konfiguracji klasy w oddzielnym obiekcie i oczywiście zapewni nam odpowiedni dostęp do tego obiektu.
Chain
Klasa Chain jak już wspominałem służy do wykonywania jedna po drugiej funkcji - gdy jedna funkcja zakończy swe działanie, zaczyna wykonywać się druga funkcja, po niej trzecia itd. Klasa ta udostępnia trzy metody:
- chain()
- callChain()
- clearChain()
chain
Metoda chain służy do łączenia funkcji w swego rodzaju łańcuch. Aby do danej funkcji dodać kolejną wykonywanej po niej stosujemy następujący zapis:
obiekt.funkcja().chain(function({
// kod jaki wykona się po pierwszej funkcji
}));
Jeżeli chcemy dodać kolejny element naszego "łańcucha" zapiszemy:
obiekt.funkcja().chain(function(){
// kod jaki wykona się po pierwszej funkcji
}).chain(function(){
// kod jaki wykona się po drugiej funkcji
});
W ten sposób możemy dodać tyle elementów łańcucha ile tylko dusza zapragnie. Co bardzo ważne klasy Chain możemy używać w mootools tylko z wybranymi klasami - Fx.Base, AJAX i XHRoraz oczywiście z klasami, które są zbudowane na podstawie wymienionych klas.
Alternatywnym sposobem tworzenia łańcucha jest stworzenie obiektu Chain i dołączanie do niego kolejnych elementów metodą chain :
var lancuch = new Chain;
lancuch.chain(function(){
//kod funkcji
});
W tym wypadku możemy zwiększyć ilość ogniw w pętli zamiast pisania:
chain(...).chain(...).chain(...);
Jeszcze warto dodać przed przejściem do przykładów, że zapisując:
lancuch.chains.length;
Otrzymamy dostęp do informacji o tym ile elementów posiada nasz łańcuch...
Przedstawię teraz przykład łańcuchowego wykonywania funkcji. W przykładzie oprę się na klasie Fx.Styles - poznamy ją dokładniej dopiero przy omawianiu grupy Effects, ale chciałbym już teraz pokazać jakiś ciekawy przykład, a nie suche alerty czy inne proste zmiany treści divów...
W przykładzie wykonamy następującą animację - div zwiększy swoje rozmiary dwukrotnie, następnie zmniejszy wysokość do pierwotnego poziomu, potem zmieni poziom przezroczystości do 0.25 (25%), by następnie zmniejszyć szerokość do poprzedniego poziomu i na koniec przywrócić opacity równe 1. Jak łatwo policzyć musimy wykonać łańcuch złożony z 5 operacji:
var efekty = $('div_testowy').effects({
transition: Fx.Transitions.Elastic.easeOut
});
efekty.start({
"width": [300,600],
"height": [300,600]
}).chain(function(){
efekty.start({
"height": [600,300]
});
}).chain(function(){
efekty.start({
"opacity": [1,0.25]
});
}).chain(function(){
efekty.start({
"width": [600,300]
});
}).chain(function(){
efekty.start({
"opacity": [0.25,1]
});
});
W poniższym przykładzie zaprezentowałem dłuższy łańcuch (ciekawszy niż ten powyżej ;) ):
callChain
Pisałem już o dwóch sposobach tworzenia łańcucha funkcji, ale nie napisałem o pewnej subtelnej różnicy pomiędzy nimi. Otóż metoda tworzenia łańcucha jaką zaprezentowałem w poprzednim przykładzie spowoduje wykonanie od razu funkcji w danej kolejności, natomiast w wypadku tworzenia obiektu klasy Chain łańcuch taki nie zostanie wykonany - ma to swoją zaletę w tym, że nie zawsze będziemy chcieli wykonać od razu dany łańcuch funkcji - do uruchomienia takiego łańcucha, opartego na obiekcie klasy Chain wykorzystuje się metodę callChain. Jak ona działa ? W sposób bardzo prosty - przy jej wywołaniu, które wygląda następująco:
lancuch.callChain();
wykonywany jest pierwsze ogniwo łańcucha, po czym jest ono z tego łańcucha usuwane, a zatem drugie ogniwo łańcucha staje się pierwszym ogniwem. A więc aby wykonać cały łańcuch potrzebujemy uruchamiać okresowo funkcję callChain dla danego łańcucha aż do momentu gdy długość łańcucha będzie równa 0 (wspominałem już jak pobrać długość łańcucha). W stosunku do poprzedniego przykładu musimy na końcu funkcji chaining() dodać kod:
var timer = (function(){
(lancuch.chains.length == 0) ? $clear(timer) : lancuch.callChain();
}).periodical(1200);
A na początku kodu funkcji dodajemy kod:
var lancuch = new Chain();
Oczywiście pierwszy element poprzedniej wersji łańcucha musimy też złączyć metodą chain z obiektem lancuch ;)
clearChain
Ostatnia metoda klasy Chain służy jak sama nazwa wskazuje do czyszczenia łańcucha. Wywołujemy ją tak samo jak metodę callChain:
obiekt_lancucha.clearChain();
Gdzie ta metoda może być przydatna ? W sytuacji gdy na przykład chcemy przerwać łańcuch w czasie jego wykonywania, po spełnieniu jakiegoś warunku, albo w sytuacji gdy chcemy "wyczyścić" zmienną łańcucha i użyć jej przy innym łańcuchu... Przykładów nie będę tutaj dawał - bardzo dociekliwi mogą sobie sami dodać w drugim przykładzie kod:
lancuch.clearChain();
w wybranym ogniwie łańcucha i zobaczyć efekty ;)
Events
Klasa Events pozwala nam zarządzać zdarzeniami naszych klas. W skład klasy Events wchodzą trzy metody:
- addEvent
- fireEvent
- removeEvent
addEvent
Metoda addEvent służy do dodania zdarzenia do danej klasy. Wszystkie klasy oparte na klasie Fx.Base mają automatycznie zaimplementowaną klasę Event oraz mają dostępne trzy zdarzenia :
- onStart
- onCancel
- onComplete
W wypadku dodawania tych zdarzeń do danego obiektu jednej z klas posiadających "Fx" w nazwie nie musimy więc implementować klasy Events. Samo dodanie zdarzenia wygląda następująco:
obiekt.addEvent(zdarzenie, function(){
// kod funkcji
});
Na przykład:
var animacja = new Fx.Style('div_testowy','height').addEvent("onStart",function(){
alert("Zaczynam powiększać diva...");
});
W wypadku wszystkich innych klas (czyli tych nie opartych na Fx.Base) musimy najpierw dodać linijkę:
NazwaObiektu.implement(new Events);
I dopiero wtedy dodajemy linijkę:
NazwaObiektu.addEvent(zdarzenie,function(){
// kod funkcji
});
Oczywiście trzeba jeszcze to zdarzenie gdzieś umieścić i je uruchomić w odpowiednim momencie, ale to już zadanie dla metody fireEvent o której napiszę za chwilę - najpierw przykład użycia metody addEvent z klasą Fx.Style (tak naprawdę głównie z klasami z grupy "Fx" używa się zdarzeń).
Pamiętacie jeszcze drugi przykład (oj dawno był ;) ) ? Wywoływaliśmy tam okresowo funkcję callChain by wykonać cały łańcuch. Jaka była wada tego rozwiązania ? Każdy z łańcuchów musiał się wykonać w jednym określonym przedziale czasowym. Dzięki zastosowaniu metody addEvent ten problem zostanie rozwiązany. Co musimy zrobić ? Usuwamy z naszego kodu linijkę z timerem i okresowym wywoływaniem funkcji, a dodajemy linijkę:
lancuch.callChain();
Ona rozpocznie cały łańcuch. A co potem ? Zmieniamy linijkę definiującą efekty z :
var efekty = $('div_testowy').effects({
duration: 1000,transition: Fx.Transitions.Elastic.easeOut
});
na:
var efekty = $('div_testowy').effects({
duration: 1000,
transition: Fx.Transitions.Elastic.easeOut
}).addEvent("onComplete",function(){
if(lancuch.chains.length !== 0) lancuch.callChain();
});
W ten sposób każdemu wywołaniu efektu będzie towarzyszyło zdarzenie onComplete, które wykona metodę callChain()w odpowiednim momencie (tj. po zakończeniu efektu). Przykład:
fireEvent
Metoda fireEvent jak już wspominałem jest przydatna przede wszystkim przy klasach nie należących do grupy "Fx". Pozwala nam na wywołanie funkcji przypisanej do danego zdarzenia. Ma dość złożoną składnię bo poza typem zdarzenia może pobierać argumenty (gdy są 2 lub więcej zapisujemy je w tablicy) oraz opóźnienie z jakim zostanie wykonana funkcja zdarzenia:
obiekt.fireEvent("zdarzenie",[argument1,argument2,argument3],opóźnienie);
Oczywiście metody fireEvent możemy używać także wtedy gdy chcemy od razu wykonać jakieś zdarzenie bez czekania na moment kiedy powinno się samo wykonać.
removeEvent
Metoda removeEvent to ostatnia z metod klasy Events, pozwala nam na usuwanie danego zdarzenia z grupy zdarzeń danej klasy. Jej obsługa jest bardzo prosta i ogranicza się do zapisu:
obiekt.removeEvent(zdarzenie);
Na przykład by usunąć zdarzenie onComplete z obiektu Testowy zapiszemy:
Testowy.removeEvent("onComplete");
Options
Ostatnią klasą wchodzącą w skład pliku class.extras.js jest klasa Options - pozwala nam na łatwe zarządzanie parametrami używanymi w klasach. Dzięki tej klasie możemy przy tworzeniu obiektu danej klasy dodać w argumentach opcje klasy.
Aby umożliwić naszej klasie korzystanie z opcji musimy przy jej tworzeniu dodać obiekt options:
options: {
opcja1: wartosc1,
opcja2: {
pole1: wartosc2,
pole2: wartosc3
}
}
i dodatkowo przy inicjalizacji klasy dodać zapis:
this.setOptions(options);
a sam zapis metody initialize:
initialize: function(){
zmienić na :
initialize: function(options){
Ponadto jeżeli nasza klasa nie jest z grupy "Fx" musimy podobnie jak w wypadku klasy Events dodać przed pierwszym stworzeniem obiektu zapis:
Klasa.implement(new Options);
Od tego momentu wywołanie naszej klasy będzie wyglądało następująco:
var Obiekt = new Klasa({
opcja1: wartosc_x,
opcja2: {
pole1: wartosc_y,
pole2: wartosc_z
}
});
Przy czym warto pamiętać, że nie musimy wpisywać wszystkich opcji przy tworzeniu nowego obiektu - gdy jakąś opcję pominiemy zostanie ustawiona dla tej opcji wartość domyślna, czyli ta jaką zdefiniowaliśmy przy tworzeniu klasy.
W następnej części kursu przejdziemy już do plików z grupy Native...
Mootools 1.11 - Array.js do góry
Plik array.js to pierwszy z plików zawierających klasy natywne. W array.js znajdziemy implementacje kilku funkcji do obsługi tablic, których nie obsługują natywnie niektóre przeglądarki, a także rozszerzenia dla obiektu Array i dwie dodatkowe funkcje powiązane z tablicami.
Te funkcje to:
forEach- funkcja ta wykonuję daną jako parametr funkcję dla każdego elementu tablicy,filter- ta funkcja jak sama nazwa wskazuje filtruje elementy tablicy, z użyciem funkcji podanej jako parametr,map- funkcja ta wykonuję kopię danej tablicy z równoczesnym wykonaniem na nich funkcji podanej jako parametr,every- funkcja ta zwróci wartość logiczną true, jeżeli wszystkie elementy tablicy spełniają podane warunki,some- ta funkcja zwróci wartość logiczną true, jeżeli co najmniej jeden element tablicy spełniaja podane warunki,indexOf- funkcja ta zwraca numer indeksu danego elementu.
Oprócz nich mamy do dyspozycji takie metody jak:
each- metoda o takim samym działaniu jak forEach,copy- metoda służąca do kopiowania tablicy,remove- metoda ta usuwa podany jako parametr element tablicy,test- metoda, która sprawdzi czy podany element znajduje się w tablicy,extend- metoda służąca do dodawania elementu do tablicy,associate- metoda tworząca tablicę asocjacyjną z podanych dwóch tablic.
Plik array.js posiada jeszcze dwie dodatkowe funkcje :
$A- to samo co metodacopytylko, że dotycząca nie tablic a na przykład argumentów obiektu czy kolekcji elementów DOM,$each- funkcja do wykonywania iteracji na nieregularnych tablicach.
forEach
Funkcja ta ma za zadanie wykonanie danej funkcji na każdym z elementów tablicy. Jej składnia wygląda następująco:
W wypadku gdy korzystamy z samodzielnej funkcji:
tablica.forEach(nazwa_funkcji);
Natomiast w sytuacji gdy korzystamy z funkcji obiektu:
tablica.forEach(obiekt.nazwa_funkcji, obiekt);
I przykłady :
Samodzielna funkcja:
var tablica = [10, 20, 30];
function alerty(element, index) {
alert("[" + index + "] = " + element);
}
tablica.forEach(alerty);
W powyższym wypadku ujrzymy trzy alerty o treściach : "[0] = 10", "[1] = 20" i "[2] = 30". Oczywiście przypominam, że indeksy w tablicach zaczynają się od zera ;)
Funkcja obiektu:
var tablica = [5, 10, 15];
var alerty = {
pokaz_tablice: function (element) {
alert(element);
}
};
tablica.forEach(alerty.pokaz_tablice, alerty);
W tym wypadku zobaczymy trzy alerty o treściach : "5", "10" i "15".
I jeszcze mała wskazówka do powyższych kodów - przy wykonywaniu funkcji forEach mamy do dyspozycji trzy zmienne - element, index i array. Element to aktualny element tablicy, index to aktualny indeks tegoż elementu, a array reprezentuje całą tablicę wykorzystywaną przy funkcji forEach.
filter
Funkcja ta służy do przefiltrowania danych z tablicy i zostawienia tylko tych potrzebnych. Składnia funkcji filter jest taka sama jak w wypadku funkcji forEach, stąd tylko krótki przykład z omówieniem:
var tablica = [20, 21, 22];
function wieksze_niz_10(element) {
return (element > 20);
}
var przefiltrowane = tablica.filter(wieksze_niz_10);
function alerty(element){
alert(element);
}
przefiltrowane.forEach(alerty);
W powyższym wypadku tablica przefiltrowane będzie zawierała elementy 21 i 22, które zostaną wyświetlone jako treści alertów przy użyciu funkcji forEach.
map
Funkcja map służy do wykonania funkcji na każdym elemencie i stworzenia tablicy z wynikami działania funkcji. Składnia taka sama jak w wypadku funkcji forEach. Przykład użycia:
var liczby = [1, 4, 9];
var pierwiastki_liczb = liczby.map(Math.sqrt);
Tablica pierwiastki_liczb po wykonaniu kodu będzie miała postać [1,2,3].
every
Funkcja every zwraca wartość true, jeżeli wszystkie elementy tablicy spełniają dane warunki. Składnia funkcji taka jak w wypadku funkcji filter. Przykład działania:
var tablica1 = [2,22,222,2222];
var tablica2 = [11,111,1111,11111];
function wieksze_niz_10(element) {
return (element > 10);
}
var wynik = tablica1.every(wieksze_niz_10);
alert(wynik);
wynik = tablica2.every(wieksze_niz_10);
alert(wynik);
W pierwszym wypadku zobaczymy alert o treści "false", ponieważ liczba 2 jest mniejsza od 10. W drugim wypadku zobaczymy alert o treści "true", gdyż każdy z elementów tablicy tablica2 jest większy od 10.
some
Funkcja some działa analogicznie do funkcji every - dlatego nie podaję przykładu działaniu. Jedyna różnica polega na tym, że w przypadku funkcji some dane warunki musi spełniać co najmniej jeden element tablicy, natomiast w wypadku funkcji every, każdy z elementów tablicy musi spełniać dane warunki.
indexOf
Ostatnia z omawianych funkcji natywnych - indexOf zwraca nam indeks danego elementu w tablicy. Składnia prezentuje się następująco:
var indeks_elementu = nazwa_tablicy.indexOf(zawartosc_elementu);
Na przykład:
var tablica = [3,5,7,9];
var indeks = tablica.indexOf(9);
alert(indeks);
var indeks2 = tablica.indexOf(11);
alert(indeks2);
Po uruchomieniu powyższego kodu ujrzymy dwa alerty - pierwszy o treści "4", a drugi o treści "-1". Wartość -1 otrzymamy zawsze wtedy gdy element o danej wartości nie istnieje w danej tablicy.
Pora przejść do metod rozszerzających funkcjonalność obiektu Array.
each
Metoda each to nic innego jak alias funkcji forEach, a więc jej sposób działania jest taki sam ;)
copy
Metoda copy służy do kopiowania danej tablicy. Posiada dwa parametry, które wpływają na ilość kopiowanych danych:
start- Określa indeks elementu od którego zaczyna się kopiowanie tablicy .Domyślnie ma wartość 0,length- określa ilość elementów do skopiowania. Domyślna wartość jest równa długości danej tablicy.
Składnia funkcji copy:
var nazwa_kopii = nazwa_tablicy.copy(start, length);
No i oczywiście przykłady użycia ;)
Na początek kopiowanie całej tablicy:
var tablica = [10,20,30,40,50,60,70,80];
var kopia = tablica.copy();
// po tym zabiegu
// var kopia = [10,20,30,40,50,60,70,80];
Teraz kopiowanie począwszy od trzeciego elementu tablicy (trzeci element ma indeks równy 2)
var tablica = [10,20,30,40,50,60,70,80];
var kopia = tablica.copy(2);
// po tym zabiegu
// var kopia = [30,40,50,60,70,80];
Kopiowanie 4 pierwszych elementów:
var tablica = [10,20,30,40,50,60,70,80];
var kopia = tablica.copy(0,4);
// po tym zabiegu
// var kopia = [10,20,30,40];
I na koniec kopiowanie 3 elementów począwszy od czwartego:
var tablica = [10,20,30,40,50,60,70,80];
var kopia = tablica.copy(3,3);
// po tym zabiegu
// var kopia = [40,50,60];
Jak widać dzięki tym dwóm argumentom metody copy, możemy dokładnie określić interesującą nas część tablicy do kopiowania.
remove
Metoda remove służy do usuwania elementów tablicy. Jest banalna w obsłudze. Składnia prezentuje się następująco:
nazwa_tablicy.remove(wartosc_elementu_do_usuniecia);
I przykład działania:
var tablica = [20,30,40,50];
tablica.remove("20");
// teraz tablica ma postać:
// tablica = [30,40,50];
contains
Metoda contains (w mootools 1.0 znana jako test) służy do sprawdzania czy dana wartość występuje w danej tablicy. Metoda ta zwraca wartość logiczną - true jeśli dana wartość występuje w tablicy oraz false gdy danego elementu w tablicy nie ma.
Składnia funkcji:
nazwa_tablicy.contains("wartosc_elementu");
Przykład działania:
var tablica = [1,2,3,4,5,6];
alert(tablica.contains("2"));
alert(tablica.contains("7"));
Podczas wykonywania powyższego kodu ujrzymy dwa alerty - pierwszy o treści "true", ponieważ element o wartości 2 występuje w tablicy, natomiast drugi alert będzie miał treść "false" ponieważ element o wartości 7 nie występuje w danej tablicy.
extend
Metoda extend służy do dodawania elementów do tablicy. Możemy dodawać pojedyncze elementy, jak i całe tablice. Składnia funkcji:
nazwa_tablicy.extend(['element1','element2', ... ,'elementN']);
Przykład użycia tej metody:
var tablica = ['jeden','dwa','trzy'];
tablica.extend(['cztery','pięć']);
Po wykonaniu powyższego kodu zmienna tablica, będzie zawierała elementy: jeden, dwa, trzy, cztery i pięć.
Oczywiście częściej zapewne będzie się stosować zapis w którym zamiast listy elementów będzie po prostu zmienna tablicy:
var tablica = ['jeden','dwa','trzy'];
var tab = ['cztery','pięć'];
tablica.extend(tab);
merge
Metoda merge służy do łączenia tablic bez duplikowania ich elementów - z dwóch tablic otrzymamy jedną złożoną z takiej ilości elementów ile było w obu tablicach unikalnych składników. Składnia funkcji merge wygląda następująco:
['arg1','arg2'].merge(['arg3','arg2']);
A dokładniej:
tablica1.merge(tablica2);
Zostanie zwrócona tablica, która w wypadku pierwszego przykładu będzie wyglądała następująco:
['arg1','arg2','arg3'];
Jak widzimy podwójny element 'arg2' nie zostanie powtórzony przy używaniu metody merge.
include
Metoda include pozwala dodać nam podany jako argument element do tablicy, ale pod warunkiem, że dany element jeszcze w tej tablicy nie występuje. Składnia tej metody wygląda następująco:
tablica.include(element);
Na przykład kod:
['arg1','arg2','arg3'].include('arg4');
zwróci nam tablicę:
['arg1','arg2','arg3','arg4'];
Ale już zapis:
['arg1','arg2','arg3'].include('arg2');
zwróci nam tą samą tablicę:
['arg1','arg2','arg3'];
ponieważ element 'arg2' występuje już w niej.
getRandom i getLast
Metody getRandom i getLast zwracają nam pojedyncze elementy tablicy - getRandom element losowy, a getLast ostatni element tablicy.
Składnia obu funkcji jest podobna i wygląda następująco:
tablica.getRandom();
tablica.getLast();
associate
Jeżeli mamy dwie tablice powiązane ze sobą, o tej samej ilości elementów, to dzięki metodzie associate, możemy stworzyć z tych tablic jedną tablicę asocjacyjną. Składnia funkcji prezentuje się następująco:
var tablica_asocjacyjna = tablica_elementow.associate(tablica_indeksow);
I jak zawsze przykład działania:
var skroty = ['CPU', 'GPU', 'HDD'];
var sprzet = ['Procesor', 'Karta graficzna', 'Dysk twardy'];
var skojarzenia = skroty.associate(sprzet);
Po wykonaniu powyższego kodu będziemy mogli wykonywać odwołania typu:
var hardware = skojarzenia['Procesor'];
// zmienna hardware przyjmie wartość 'CPU'
Pozostały nam jeszcze do omówienia dwie funkcje nie będące metodami obiektu Array.
$A
Funkcja $A, której składnia wygląda następująco :
$A(zbior_argumentow).funkcja_dla_obiektu_Array;
Pozwala nam na zamienienie na tablice obiektów, które nimi nie są - na przykład kolekcji elementów DOM. A zatem możemy od nich stosować takie funkcje jakie stosujemy do tablic.
Dla przykładu - gdybyśmy chcieli wyświetlić alerty z atrybutami id występujących w dokumencie elementów div, tworzymy taki kod:
window.onload = function(){
var dom = $$('div');
$A(dom).each(function(dom){
alert(dom.id);
});
}
$each
Funkcja $each ma działanie takie jak funkcja forEach i metoda each dla tablic, tylko, że funkcja $each operuje tak jak funkcja $A na obiektach nie będących tablicami.
Składnia tej funkcji wygląda następująco:
$each(argumenty,funkcja);
I przykład użycia podobny do poprzedniego:
window.onload = function(){ var dom = $$('div');
$each(dom, function(dom){
alert(dom.id);
});
}
Tu jeszcze mała uwaga odnośnie dwóch ostatnich kodów - pozwoliłem sobie użyć funkcji $$ pochodzącej z pliku element.js, o którym napiszę niebawem w kursie. Krótko mówiąc służy on do selekcji wszystkich elementów danego typu.
Mootools 1.11 - Element.js do góry
Przed przejściem do lektury na temat pliku element.js polecam osobom, które o DOM mają małe pojęcie przeczytać trochę materiałów na ten temat. Osobiście polecam ten artykuł o obiektach DOM oraz wpisy Riddle'a na ten temat:
- Document Object Model, wstęp
- Sposoby odnajdywania elementów w DOM
- Węzły w DOM i podstawowe ich dodawanie
Plik element.js to moim zdaniem jeden z bardziej przydatnych elementów frameworka mootools. Udostępnia on nam funkcje pozwalające na manipulowanie drzewem dokumentu. Każdy kto pisał jakiekolwiek skrypty w JS wie, że operacje na DOM pozwalają na osiągnięcie większości pożądanych efektów. Właściwie bez operacji na DOM nie możemy zbyt wiele zrobić przy użyciu JS. Sam plik element.js udostępnia nam około 40 funkcji - niektóre to tylko aliasy standardowych funkcji służących do operacji na drzewie dokumentu, inne to funkcje wykonujące operacje na których wykonanie normalnie potrzebowalibyśmy wielu linijek kodu.
Tworzenie elementów drzewa dokumentu
Aby stworzyć element z użyciem klasy element należy stworzyć nowy obiekt Element, a jako parametry podać wszystkie cechy elementu jaki chcielibyśmy stworzyć. Schematycznie kod wygląda następująco:
new Element('typ_elementu', {
'styles': {
'właściwość1': 'wartość',
'właściwość2': 'wartość'
},
'events': {
'zdarzenie1': function(){
// kod funkcji
},
'zdarzenie2': function(){
// kod funkcji
}
},
'class': 'nazwa klasy',
'id': 'id_elementu',
'href': 'link'
});
Typ elementu to oczywiście tag na przykład 'a', 'b', 'div' itd... Warto jeszcze pamiętać, że nazwy zdarzeń w obiekcie events podajemy bez przedrostka 'on' , oczywiście dodatkowe atrybuty elementu podajemy tak jak class, id i href .Tutaj trzeba dodać, że tak stworzony element nie znajduje się jeszcze w drzewie naszego dokumentu - musimy go dopiero w nim umieścić. Aby więc zaprezentować działanie przedstawionego wcześniej kodu, pozwolę sobie wykorzystać dwie z funkcji, które poznamy dopiero później - injectInside i setProperty. injectInside umieści nasz nowo powstały element w innym żądanym elemencie dokumentu, a setProperty ustawi żądaną wartość danego atrybutu.
Warto w tym miejscu wspomnieć o metodzie set, która działa podobnie jak tworzenie nowego elementu, ale z tą różnicą, że służy tylko do ustalania wartości właściwości elementu. Zatem gdy chcemy do elementu dodać style, zdarzenia to stosujemy takie obiekty jak w wypadku tworzenia nowego elementu i podajemy je jako argumenty metody set przypisane do danego elementu:
element.set(właściwości);
Selekcja elementów
Plik element.js zawiera dwie funkcje do selekcji elementów: $ i $$. Funkcja $ pozwala wybrać element posiadający id podany jako parametr tejże funkcji. Dla przykładu:
var div = $('jakis_div');
Po wykonaniu powyższego kodu zmienna div będzie odpowiadała divowi, który posiada id "jakis_div".
Gdy zajdzie potrzeba operowania na większej liczbie elementów, możemy skorzystać z funkcji $$, która zwróci nam tablicę elementów zgodnych z podanymi parametrami. Możemy wybierać elementy według nazwy tagu - a, b, div itd. Na przykład:
var linki = $$('a');
Zmienna linki będzie tablicą zawierającą wszystkie linki z naszego dokumentu. Możemy korzystać z selektorów CSS jako parametrów funkcji $$. Na przykład:
var linki_z_diva = $$('#jakis_div a');
Powyższy kod zwróci wszystkie linki zawarte w divie posiadającym identyfikator "jakis_div".
Metody klasy Element
W dalszej części kursu pozwolę sobie grupować podobne funkcje tak by skrócić wpis - opisanie każdej z prawie 50 funkcji zajęłoby wiele miejsca gdybym robił to oddzielnie, a tak pogrupuję powiązane typem przykłady i skrócę w ten sposób wpis do akceptowalnej długości ;)
injectBefore, injectAfter, injectInside, injectTop
Funkcje ze słowem inject w nazwie służą do umieszczania elementów w odpowiednim miejscu względem innych elementów. Zatem funkcja injectBefore umieści dany element przed innym, funkcja injectAfter umieści element po innym elemencie, funkcja injectInside umieści dany element wewnątrz innego elementu, a funkcja injectTop umieści dany element na początku innego elementu (w swym działaniu podobna jest do injectInside tylko umieszcza element na początku, a nie na końcu). Budowa tych funkcji jest podobna i wygląda następująco:
$('element_1').inject*****('element_2');
Gdzie element_1 oznacza id elementu, który zostanie przemieszczony względem elementu posiadającego id element_2.
Przykładowe kody dla danych funkcji wraz z otrzymywanym kodem:
Początkowy kod XML:
<div id="div1">pierwszy div</div>
<div id="div2">drugi div</div>
Kod JS:
$('div2').injectBefore('div1');
Otrzymywany kod XML:
<div id="div2">drugi div</div>
<div id="div1">pierwszy div</div>
W dalszych dwóch przykładach kod XML na początku jest taki sam, więc podaję tylko kod JS i otrzymywany kod XML:
Kod JS:
$('div1').injectAfter('div2');
Otrzymywany kod XML:
<div id="div2">drugi div</div>
<div id="div1">pierwszy div</div>
Kod JS:
$('div1').injectInside('div2');
Otrzymywany kod XML:
<div id="div2">drugi div
<div id="div1">pierwszy div</div>
</div>
Przykład prezentujący działanie powyższych funkcji:
Początkowy kod XML:
<div id="div1">pierwszy div</div>
<div id="div2">
drugi div
<div id="div3"> </div> </div>
$('div1').injectTop('div2');
Otrzymywany kod XML:
<div id="div1">pierwszy div</div>
<div id="div2">
<div id="div1">pierwszy div</div>
drugi div
<div id="div3"> </div> </div>
adopt, remove , clone , replaceWith
Funkcje adopt, remove, clone i replaceWith służą odpowiednio do umieszczania elementu wewnątrz innego, usuwania elementu, powielania elementu i zastępowania elementów.
Funkcja adopt działa na tej samej zasadzie co injectInside. Różni sie jedynie zapis:
$('div1').adopt('div2');
Powyższy kod spowoduje, że div posiadający id div2 znajdzie się wewnątrz diva z id div1 (tak więc w stosunku do zapisu injectInside oprócz zmiany nazwy funkcji mamy też zmianę kolejności elementów - umieszczanego wewnątrz i elementu w którym inny element jest umieszczany).
Użycie funkcji remove jest banalnie proste :
$('id_elementu').remove();
Po wykonaniu powyższego kodu z drzewa dokumentu zniknie element posiadający id id_elementu.
Funkcja clone pozwala nam kopiować dany element. Składnie ma podobną do funkcji remove:
var div_kopia = $('div1').clone();
Kod znajdujący się powyżej spowoduje przypisanie zmiennej div_kopia kopii elementu posiadającego id div1. Oczywiście element ten nie znajduje się jeszcze w drzewie dokumentu - trzeba go tam umieścić na przykład korzystając z funkcji typu inject.
Ostatnia z tej grupy funkcji - replaceWith, jak sama nazwa wskazuje służy do zamiany miejscami elementów. Składnia wygląda następująco :
$('element_1').replaceWith($('element_2'));
Po wykonaniu powyższego kodu element posiadający id element_1 zostanie zamieniony na element posiadający id element_2.
I przykład pokazujący działanie wyżej wymienionych funkcji:
appendText, setHTML
Funkcje appendText i setHTML służą do ustawiania zawartości elementu. appendText służy do dodawania tekstu w elemencie, natomiast setHTML służy do operowania na zawartości elementu - nie tylko tekstowej (działanie takie samo jak innerHTML).
Przyjrzyjmy się działaniu funkcji appendText:
Przyjmijmy, że mamy element typu div posiadający tekst "to jest div " i chcielibyśmy zmienić ten ciąg znaków na "to jest div testowy":
kod XML:
<div id="element">to jest div </div>
kod JS:
$('element').appendText('testowy');
Po wykonaniu kod nasz kod XML będzie wyglądał następująco:
<div id="element">to jest div testowy</div>
A gdybyśmy chcieli aby treść tego diva wyglądała tak jak wcześniej ale, żeby napis "testowy" był pogrubiony ? Korzystamy w tym wypadku z setHTML:
var kodXHTML = 'to jest div <strong>testowy</strong>';
$('element').appendText(kodXHTML);
I przykłady działania:
hasClass, addClass, removeClass, toggleClass
Funkcje, które zawierają w nazwie człon Class służą do operowania na atrybucie class elementu.
Składnia wszystkich funkcji z tej grupy wygląda następująco:
$('id_elementu').******Class('nazwa_klasy');
Funkcja hasClass służy do sprawdzenia czy dany element posiada daną klasę w atrybucie class. Jeżeli element posiada daną klasę to funkcja zwraca wartość logiczną true, w przeciwnym wypadku false. Przykłady :
kod XML:
<div id="div1" class="klasa1">Div 1</div>
<div id="div2" class="klasa2">Div 2</div>
kod JS:
var pierwszy = $('div1').hasClass('klasa1');
var drugi = $('div2').hasClass('klasa1');
Po wykonaniu powyższego kodu zmienna pierwszy przyjmie wartość true, natomiast zmienna drugi przyjmie wartość false (ponieważ div posiadający id div2 ma atrybut class równy klasa2, a nie klasa1).
Aby dodać/usunąć klasę z naszego elementu korzystamy z funkcji addClass (dodawanie klasy) i removeClass (usuwanie klasy). Przykład użycia:
kod XML:
<div id="div1" class="klasa1">Div 1</div>
<div id="div2" class="klasa2">Div 2</div>
kod JS:
$('div1').addClass('klasa2');
$('div2').removeClass('klasa2');
Otrzymamy następujący kod XML:
<div id="div1" class="klasa1 klasa2">Div 1</div>
<div id="div2" class="">Div 2</div>
Funkcja toggleClass służy do naprzemiennego dodawania i usuwania danej klasy z atrybutu class elementu:
kod XML:
<div id="element" class="klasa1">Div</div>
kod JS:
$('element').toggleClass('klasa1');
otrzymamy kod XML:
<div id="element" class="">Div</div>
Po ponownym wykonaniu kodu JS:
$('element').toggleClass('klasa1');
otrzymamy kod XML taki jak na początku:
<div id="element" class="klasa1">Div</div>
Strona z prezentacją przykładów:
setStyle, setStyles, setOpacity, getStyle
Funkcje z tej grupy służą do operowania na stylu elementów.
Funkcja setStyle służy do ustawiania wartości właściwości CSS. Jej składnia wygląda następująco:
$('id_elementu').setStyle('właściwość', 'wartość');
Zatem, jeśli chcielibyśmy ustawić wysokość diva posiadającego id "testowy" na 250 pikseli wykorzystamy zapis:
$('testowy').setStyle('height','250px');
Ograniczeniem funkcji setStyle jest fakt, że możemy za jej pomocą ustawić wartość tylko jednej właściwości. Gdy chcemy zmienić naraz wartości kilku właściwości, korzystamy z funkcji setStyles, która posiada następującą składnię:
$('id_elementu').setStyles({
właściwość_1: 'wartość',
właściwość_2: 'wartość',
właściwość_3: 'wartość',
...
właściwość_n: 'wartość'
});
Dla przykładu - gdybyśmy chcieli zmienić jednocześnie wysokość, szerokość i padding diva posiadającego id "testowy", stosujemy zapis:
$('testowy').setStyles({
width: '500px',
height: '500px',
padding: '10px'
});
Kiedy chcemy zmienić poziom przezroczystości elementu, stosujemy funkcję setOpacity:
$('id_elementu').setOpacity(poziom_przezroczystości);
Gdzie zmienna poziom_przezroczystości przyjmuje wartości od 0 do 1, natomiast wartości z tego przedziału zapisujemy używając kropki np.: 0.2 .
Przykładowo, gdybyśmy chcieli uzyskać przezroczystość na poziomie 35% dla diva posiadającego id "testowy", zapiszemy:
$('testowy').setOpacity(0.35);
Na koniec z tej grupy funkcji, pozostała nam getStyle, służąca do pobierania aktualnej wartości właściwości CSS danego elementu. Jej składnia wygląda następująco:
$('id_elementu').getStyle('właściwość');
I przykład - pobierzemy wartość właściwości width diva posiadającego id "testowy":
$('testowy').getStyle('width');
Na koniec tej części przykład pokazujący w akcji przedstawione wyżej funkcje:
addEvent, removeEvents, fireEvent
Funkcje posiadające w nazwie człon "Event" służą do operowania na zdarzeniach elementów. Ich użyteczność jest bardzo wysoka, ponieważ dają nam taką samą funkcjonalność jak przedstawiania kiedyś przeze mnie klasa Behaviour .
Zatem gdy chcemy dodać zdarzenie do danego elementu, będziemy korzystali z funkcji addEvent. Jej składnia wygląda następująco:
$('id_elementu').addEvent('zdarzenie', function(){
kod_funkcji_jaka_się_wykona_przy_wystąpieniu_zdarzenia;
});
Gdzie zmienna zdarzenie to nazwa zdarzenia bez przedrostka "on" np.: onclick zapiszemy jako click, onmouseover zapiszemy jako mouseover itd.
Drugi argument tej funkcji to funkcja, która się wykona w wypadku wystąpienia naszego zdarzenia.
I przykład - przyjmijmy, że chcemy aby po kliknięciu diva posiadającego id "testowy" pokazał się alert z napisem "Div został klikniety":
$('testowy').addEvent('click',function(){
alert('Div został kliknięty');
});
Gdy mamy przypisane zdarzenia do danego elementu, możemy je usunąć wszystkie naraz, korzystając z funkcji removeEvents. Możemy też usunąć wybrane zdarzenia. Wszystko zależy od zapisu. Gdy zapiszemy:
$('id_elementu').removeEvents();
Zostaną usunięte wszystkie zdarzenia. Jeśli jednak zapiszemy:
$('id_elementu').removeEvents('zdarzenie_1', 'zdarzenie_2', 'zdarzenie_3');
To zostaną usunięte tylko wybrane zdarzenia danego elementu...
Ciekawą funkcją jest funkcja fireEvent, która powoduje wykonanie wszystkich funkcji przypisanych zdarzeniom danego elementu. Jej składnia wygląda następująco:
$('id_elementu').fireEvent();
Przykładowo gdy mamy element div posiadający id "testowy", który ma określone zdarzenia onclick i onmouseover to przy wywołaniu:
$('testowy').fireEvent();
Zostaną wykonane obie funkcje przypisane zdarzeniom tego elementu (np.: zostaną pokazane dwa alerty).
Na koniec tej części przykład obrazujący działanie wyżej przedstawionych funkcji:
getPrevious, getNext, getFirst, getLast, getParent, getChildren, hasChild
Funkcje, których nazwy są przedstawione w tytule tej części wpisu, służą do selekcji elementów na podstawie relacji pomiędzy nimi w drzewie dokumentu. Ponieważ nie będę się tu rozpisywał na temat samego DOM odsyłam po raz kolejny do linków umieszczonych na początku wpisu.
Tą część możemy potraktować jako teoretyczną i opiszę tylko pokrótce działanie tychże funkcji:
getPrevious- zwraca element umieszczony bezpośrednio przed danym elementem,getNext- zwraca element umieszczony bezpośrednio za danym elementem,getFirst- zwraca pierwszy element-dziecko danego elementu,getLast- zwraca ostatni element-dziecko danego elementu,getParent- zwraca element-rodzica danego elementu,getChildren- zwraca wszystkie elementy-dzieci danego elementu,hasChild- zwraca true gdy dany element posiada elementy-dzieci.
Wszystkie powyższe funkcje wywołujemy tak samo przez składnię:
$('id_elementu').get**********();
setProperty, setProperties, getProperty, getTag, removeProperty
Funkcje z tej grupy służą do operowania na atrybutach elementów i pobierania takich danych jak wartość pola formularza czy tagu danego elementu.
Funkcja setProperty służy do ustawiania wartości danego atrybutu. Jej składnia jest taka jak funkcji setStyle:
$('id_elementu').setProperty('atrybut','wartosc');
Analogicznie funkcja setProperties ma taką samą składnię jak funkcja setStyles:
$('id_elementu').setStyles({
atrybut_1: 'wartość',
atrybut_2: 'wartość',
atrybut_3: 'wartość',
...
atrybut_n: 'wartość'
});
Funkcje getProperty i getTag służą do pobierania informacji o elemencie - odpowiednio: wartości danego atrybutu, typu elementu (tagu) i wartości pola formularza.
Składnie tych funkcji prezentują się następująco:
$('id_elementu').getProperty('alt');
Powyższy kod zwróci wartość atrybutu alt elementu.
var tag = $('id_elementu').getTag();
Zmienna tag przyjmie wartość "img" jeżeli w kodzie strony mamy zapis:
<img src="ścieżka" id="id_elementu" alt="tekst" />
Działanie powyższych funkcji zostało przedstawione w poniższym przykładzie:
Funkcja removeProperty służy do usuwania właściwości elementu .
Składnia tej funkcji prezentuje się następująco:
$('id_elementu').removeProperty('alt');
Powyższy kod usunie atrybut alt z elementu.
empty
Metoda empty służy do usunięcia wszystkich elementów - dzieci z danego elementu. Po wykonaniu tej operacji metoda ta zwraca element z którego usuwała elementy potomne. Składnia funkcji wygląda następująco:
$('div_id').empty();
Powyższy kod spowoduje, że cała zawartość diva "div_id" zostanie usunięta...
I tym sposobem dotarliśmy do końca omawiania jednego z najbardziej rozbudowanych elementów frameworka mootools - posiadającego dużo funkcji przydatnych przy wielu typowych zastosowaniach JavaScript.
mootools - event.js do góry
Plik event.js to kolejny z elementów frameworka mootools, który z pewnością można zaliczyć do bardzo przydatnych. Wraz z tą częścią kursu nauczymy się likwidować dwa ważne problemy związane ze zdarzeniami, a na koniec poskromimy klawiaturę przy użyciu JavaScript ;)
W pliku event.js mamy zawartą klasę Event zawierającą 4 metody (i konstruktor oczywiście) oraz kilkanaście właściwości dla obiektów typu event.
Zacznijmy od stworzenia zdarzenia onclick.
Nasz kod będzie wyglądał następująco :
$('id_elementu').zdarzenie = function(){
// kod jaki wykona się przy wystąpieniu zdarzenia
};
W wypadku gdy w kodzie zdarzenia będzie wykorzystywany obiekt klasy Event, nasz kod będzie wyglądał tak:
$('id_elementu').zdarzenie = function(event){
var event = new Event(event);
// kod jaki wykona się przy wystąpieniu zdarzenia
};
Przykładowo dodajmy do diva posiadającego id "div1" zdarzenie onclick, które spowoduje pokazanie się alertu z id tego diva:
$('div1').onclick = function(){
alert(this.id);
};
Teraz umieśćmy w naszym divie drugi div posiadający id "div2" i dodajmy do niego w taki sam sposób zdarzenie onclick:
$('div2').onclick = function(event){
alert(this.id);
};
Mając te dwa divy możemy przejść do omawiania metody stopPropagation.
stopPropagation
Metoda stopPropagation służy do obsługi sytuacji w której mamy jeden element umieszczony w drugim i oba z nich posiadają zdarzenie np.: onclick. Jak się pewnie orientujecie, taki układ spowoduje przy kliknięciu wewnętrznego diva, wykonanie obu funkcji / kodów JS przypisanych do zdarzeń elementów.
Dla zainteresowanych - dobry artykuł na ten temat.
Przyjmijmy, że nie chcemy aby po kliknięciu diva wewnętrznego pojawiał się także alert związany z kliknięciem zewnętrznego diva. Do osiągnięcia tego celu służy właśnie metoda stopPropagation - jej użycie spowoduje, że po kliknięciu zewnętrznego diva, zdarzenia onclick przypisane do elementów nadrzędnych względem niego, nie zostaną wykonane.
Zatem tworzymy w tym wewnętrznym divie button i dodajemy do niego id "button", a do zdarzenia window.onload dodajmy kod:
$('button').onclick = function(event){
var event = new Event(event);
event.stopPropagation();
$('div2').onclick = function(event){
var event = new Event(event);
alert(this.id);
event.stopPropagation();
};
alert('stopPropagation');
};
Po pierwsze - blokujemy wywoływanie zdarzeń elementów nadrzędnych w stosunku do buttona, a po drugie zmieniamy kod zdarzenia onclick elementu div2.
Przykład prezentujący przedstawianą sytuację:
preventDefault
Są takie elementy dokumentu XML, które np.: po kliknięciu wykonują pewną określoną akcję zgodnie z podanymi atrybutami. Na przykład linki czy przycisk submit formularza. Czasami jednak, chcemy aby przed wysłaniem formularza dane zostały sprawdzone, albo chcemy by nasz link nie prowadził do danej strony według atrybutu href, a jedynie żeby ten atrybut był wykorzystywany jako zmienna dla skryptu.
Metoda preventDefault pozwoli nam na zatrzymanie domyślnych akcji onclick dla danych elementów i pozwoli w ten sposób na rozszerzenie możliwości elementów linków czy przycisków wysyłania formularzy. Warto zauważyć, że takie podejście do tych elementów zwiększy użyteczność naszych stron dla osób z wyłączoną obsługą JS. Przykładowo dla aktywnych linków z adresem "#" możemy stosować normalne adresy pozwalające wykonać dane operacje, normalnie dostępne przy użyciu efektów napisanych w JS. Podobnie z formularzami - przed wysłaniem można sprawdzić wszystkie dane, prosić użytkownika o potwierdzenie wprowadzonych danych itd. a użytkownicy bez JS zostaną poprowadzeni od razu do odpowiedniej strony...
W przykładzie posłużę się linkiem, który normalnie poprowadziłby nas do jakiejś strony, jednak dzięki zastosowaniu preventDefault pokazany zostanie jedynie alert z adresem linka.
Stwórzmy zatem w dokumencie dwa linki, posiadające id odpowiednio "link1" i "link2". Ustawmy też obu linkom atrybuty href "http://www.dziudek.jogger.pl".
Następnie dodajmy następujący kod JS:
$('link2').onclick = function(event){
var event = new Event(event);
event.preventDefault();
alert(this.href);
};
Spowoduje on zatrzymanie wykonywania domyślnego zdarzenia dla drugiego linku i pokazanie alertu.
Powyższy przykład znajduje się na stronie poniżej:
stop
Jeśli chodzi o metodę stop, to nie będę się nad nią dłużej rozwodził ponieważ wykonuje ona dla danego zdarzenia po prostu dwie metody jednocześnie - preventDefault i stopPropagination. Zatem możemy po prostu dzięki niej skrócić zapis kodu gdy stosujemy obie metody jednocześnie dla danego eventu.
bindWithEvent
Metoda bindWithEvent to ostatnia z 4 metod udostępnianych przez klasę Event. Służy ona do automatycznego tworzenia obiektu event i wykorzystywania go w danej funkcji. Funkcja musi oczywiście pobierać jako argument dane zdarzenie...
Najlepiej będzie to wyjaśnić na podstawie przykładu. Mamy funkcję mysz:
function mysz(event){
alert(event.client.x);
};
Służy ona do zwracania współrzędnej x położenia kursora myszy (o właściwościach obiektu Event będzie za chwilę).
Zatem powiążmy naszą funkcję ze zdarzeniem kliknięcia jakiegoś elementu. Tworzymy zmienną będącą referencją do danego obiektu:
element = $('id_elementu');
a następnie tworzymy powiązanie:
element.onclick = mysz.bindWithEvent(element);
W ten sposób nasze zdarzenie onclick danego elementu zostanie powiązane z funkcją mysz, która od tego momentu będzie się wykonywała po jego kliknięciu...
Zaletą wykorzystania tej metody jest fakt, że nie musimy tworzyć "ręcznie" nowego obiektu Event dla naszej funkcji...
Właściwości obiektu klasy Event
Obiekt klasy Event ma wiele właściwości powiązanych z położeniem kursora, czy wciskanymi klawiszami... Przejdźmy najpierw do pozycji kursora. Możemy pobierać współrzędne jego położenia na dwa sposoby - względem całej strony lub względem widocznej części strony.
Aby pobrać współrzędne kursora względem całej strony, wykorzystujemy dwie właściwości:
event.page.x;
event.page.y;
Aby zrobić to samo, ale względem widocznej części strony, korzystamy z właściwości:
event.client.x;
event.client.y;
Oczywiście w obu przypadkach x i y oznaczają odpowiednio współrzędną x i współrzędną y położenia kursora...
Przykład działania:
Zanim przejdziemy do obsługi klawiatury, omówię jeszcze dwie właściwości - target i relatedTarget. Właściwość target zwraca nam uchwyt do obiektu z jakim powiązane jest zdarzenie, natomiast właściwość relatedTarget występuje tylko w wypadku zdarzeń onmouseover i onmouseout. W wypadku zdarzenia onmouseover właściwość relatedTarget zwraca nam uchwyt do obiektu jaki opuścił kursor mysz przed znalezieniem się nad danym obiektem, natomiast przy zdarzeniu onmouseout zwracany jest uchwyt obiektu nad jakim znalazł się kursor po przejściu z danego obiektu dokumentu...
Oczywiście dostęp do obu właściwości otrzymujemy poprzez zapis:
event.target;
oraz
event.relatedTarget;
Aby lepiej zrozumieć działanie tych właściwości proponuję przetestować mały przykład :
A teraz przejdźmy już do klawiatury...
W przypadku obsługi klawiatury mamy do dyspozycji kilka właściwości :
event.shift;
event.control;
event.alt;
event.meta;
event.code;
event.key;
Pierwsze cztery zwracają wartość logiczną true, jeżeli użytkownik wcisnął dany klawisz (odpowiednio Shift, Ctrl, Alt lub metaklawisz). Pozostałe dwie właściwości zwracają ciągi znaków - kod wpisanego znaku lub sam znak (jako małą literę) , albo ewentualnie słowo ‘enter’, ‘up’, ‘down’, ‘left’, ‘ right’, ‘space’, ‘backspace’, ‘delete’ lub ‘esc’.
Oczywiście te możliwości można wykorzystać w aplikacjach np. przy skrótach klawiaturowych itd...
Przygotowałem przykład, który pozwala na zmianę stylu tekstu poprzez wciśnięcie odpowiedniej kombinacji klawiszy... Całość ogranicza się do sprawdzenia czy klawisz Ctrl został wciśnięty wraz z innym klawiszem.
Oczywiście pojawiła się mała trudność - na przykład kombinacja Ctrl + B powodowała pokazywanie zakładek w Firefoxie. Dlatego też należało zastosować zapis:
event.stop();
by uniknąć problemów z zarezerwowanymi przez przeglądarkę skrótami... Oczywiście należy pamiętać, że stosowanie skrótów pokrywających się ze skrótami przeglądarki może sfrustrować użytkownika, ponieważ odcina mu się dostęp do normalnej funkcjonalności tychże skrótów... Dlatego lepiej nie przesadzać ze stosowaniem skrótów...
Przykład o którym wspominałem wcześniej:
I to by było na tyle apropo pliku event.js - w następnej części kursu przejdziemy do pliku function.js, odpowiadającego za operowanie na funkcjach...
Mootools 1.11 - Function.js do góry
W tej części kursu mootools zajmiemy się obsługą funkcji za pomocą pliku function.js . Plik ten zawiera 7 metod, które wymienię poniżej:
create- metoda do dodawania parametrów dla funkcji,bind- metoda służąca do tworzenia elementu odniesienia dla operatorathis,pass- mniej rozbudowana wersja metody create do dodawania argumentów i elementu odniesienia dla operatorathis,attempt- metoda do testowania poprawności działania funkcji,bindAsEventListener- metoda do przypisywania funkcji jako EventListener'a danego elementu,delay- metoda pozwalająca określić czas po którym zostanie wykonana dana funkcja,periodical- metoda do określania co jaki okres czasu ma się wykonywać dana funkcja.
create
Metoda create to najbardziej rozbudowana z wszystkim metod pliku function.js . Właściwie to pozwala ona zrobić za pomocą jednej metody to co normalnie moglibyśmy zrobić za pomocą kilku metod zawartych w tym pliku. Przedstawię tu tylko krótki opis użycia tej funkcji, a sam opis poszczególnych parametrów jej wywołania zawrę w opisie poszczególnych metod. Można powiedzieć, że użycie metody create ma sens tylko wtedy gdy chcemy do funkcji dodać kilka parametrów naraz, w pozostałych wypadkach czytelniejsze będzie zastosowanie poszczególnych metod...
Metoda create jako argument pobiera obiekt następującej postaci:
{
"bind": value,
"event": value,
"arguments": value,
"delay": value,
"periodical": value,
"attempt": value,
}
Gdzie poszczególne właściwości obiektu to odpowiedniki poszczególnych metod pliku function.js.
Gdybyśmy chcieli na przykład sprawić by nasza funkcja wywołana została z opóźnieniem, okresowo i była testowana czy wykonuje się poprawnie zapiszemy:
Funkcja.create({"delay": 5000,"periodical": 10000,"attempt": true});
Pełnię możliwości tej metody poznacie wraz z zapoznaniem się ze wszystkimi metodami pliku function.js .
bind
Metoda bind służy do określenia elementu odniesienia (a dokładniej obiektu odniesienia) dla operatora this. Normalnie wykorzystując operator this odniesiemy się do funkcji w której tenże operator zostanie użyty, jednak metoda bind pozwoli nam to zmienić. Składnia metody bind wygląda następująco:
Funkcja.bind(obiekt_dla_this, argumenty);
Tak tak - oprócz obiektu odniesienia dla this za pomocą metody bind możemy też podać argumenty dla funkcji - ale o nich napiszę przy okazji metody pass... Skupmy się na istocie działania metody bind. Gdybyśmy chcieli sprawić by operator this odnosił się do elementu strony na którym operuje dana funkcja zapiszemy następujący kod:
function zmianaElementu(){
this.setStyle("border","2px solid #CCC");
}
var nowaFunkcja = zmianaElementu.bind($('id_elementu'));
W ten sposób zapis:
this.setStyle("border","2px solid #CCC");
Będzie oznaczał to samo co zapis:
$('id_elementu').setStyle("border","2px solid #CCC");
Oczywiście pamiętajmy o tym, że każda z metod pliku function.js zwraca odpowiednio przerobioną funkcję - zatem musimy naszą przerabianą funkcję przypisać do jakiejś zmiennej lub zdarzenia by móc korzystać z nowej, przerobionej funkcji.
Przykład działania podobnego skryptu:
pass
Metoda pass służy do określenia argumentów dla danej funkcji i elementu odniesienia dla operatora this. Już wiem jak obsługiwać się z operatorem this skupimy się teraz na argumentach funkcji. Właściwie metoda pass to to samo co metoda bind - obie pobierają takie same argumenty, a jedyna różnica polega na kolejności pobierania argumentów. Zapis metody pass wygląda następująco:
Funkcja.pass(argumenty, obiekt_dla_this);
Ważne jest, że gdy argumentów jest kilka (czyli więcej niż jeden argument) to trzeba je podawać jako tablicę argumentów. Czyli:
Funkcja_pobierajaca_jeden_arg.pass(argument);
Funkcja_pobierajaca_wiele_arg.pass([argument1,argument2,argument3]);
Przekażmy zatem do funkcji kilka argumentów i stwórzmy sobie coś co działa prawie jak kalkulator ;)
attempt
Metoda attempt pozwala na testowanie poprawności działania funkcji. W wypadku gdy funkcja zawiera błąd w operacjach metoda attempt zwróci wartość false, w przeciwnym wypadku zostanie zwrócona dana funkcja...
Metoda attempt jako argumenty pobiera liste argumentów oraz obiekt odniesienia dla operatora this:
Funkcja.attempt(argumenty,obiekt_odniesienia_dla_this);
Gdy przypiszemy taką funkcję na przykład do zdarzenia onclick jakiegoś elementu i funkcja będzie zawierała błąd (przykładowo brak jakiegoś argumentu) to po kliknięciu danego elementu po prostu nic się nie stanie. Gdy funkcja pobierze poprawne dane, zostanie wykonana normalnie...
I przykładowy kod:
function funkcjaNieprawidlowa(){
$('div').setHTML(argument);
}
button.onclick = funkcjaNieprawidlowa.attempt();
Klikniecie na przycisk sprawi, że nic się nie stanie dzięki użyciu metody attempt - gdybyśmy nie zastosowali tej metody konsola JavaScript zwróciłaby w tej sytuacji błąd.
I przykład:
bindAsEventListener
Metodę bindAsEventListener wykorzystujemy w momencie gdy chcemy dodać funkcję jako EventListener do danego zdarzenia. Dzięki temu używana funkcja jako pierwszy argument pobiera zdarzenie.
Aby móc pobierać właściwości obiektu Event musimy stworzyć funkcję o następującej postaci:
function Nazwa_funkcji(event,pozostale_argumenty){
event = new Event(event);
// dalszy kod
}
Dzięki temu zapisowi możemy dalej odwoływać się do właściwości obiektu Event, na przykład:
mojElement = $('btn');
function events(event){
event = new Event(event);
alert(event.page.x);
};
mojElement.onclick = events.bindAsEventListener();
Powyższy kod spowoduje pokazanie alertu z informacją o współrzędnej X miejsca kliknięcia.
Warto jeszcze dodać, że metoda bindAsEventListener jako argumenty przyjmuje dodatkowo obiekt odniesienia dla operatora this i listę argumentów dla danej funkcji...
delay
Pozostały nam już tylko dwie metody, ale chyba te najczęściej używane - delay i periodical. Metoda delay służy do opóźnienia wykonania kodu danej funkcji. Poza czasem opóźnienia (podajemy go w milisekundach !) pobiera też obiekt odniesienia dla operatora this oraz argumenty danej funkcji. Możemy opóźniać wykonanie już zdefiniowanej funkcji jak i wykonanie fragmentu kodu...
Aby opóźnić wykonanie funkcji wykorzystujemy kod:
Funkcja.delay(10000);
Powyższy kod spowoduje wykonanie funkcji o nazwie Funkcja po 10 sekundach od użycia tego kodu. Aby opóźnić wykonanie fragmentu kody zapiszemy:
(function(){alert("Minęło 10 sekund...");}).delay(10000);
Zatem umieszczamy kod w takim szablonie:
(function(){KOD}).delay(10000);
periodical
Metoda periodical służy do okresowego wykonywania danej funkcji. Jako argumenty pobiera czas co jaki ma się wykonać funkcja (oczywiście w milisekundach) oraz obiekt odniesienia dla operatora this i argumenty danej funkcji. Tak jak w wypadku metody delay możliwe jest okresowe wykonanie już zdefiniowanej funkcji jak i fragmentu kodu...
Składnia metody jest podobna do składni metody delay:
Funkcja.periodical(10000);
lub:
(function(){KOD}).periodical(10000);
To teraz przydałby się jeden przykład dla obu metod - delay i periodical . Ale najpierw jeszcze małe przypomnienie...
Funkcja $clear, a metody delay i periodical
Pewnie niektórzy jeszcze pamiętają do czego służyła funkcja $clear z pliku core.js - pozwalała przerwać okresowe wykonywanie funkcji lub jej opóźnienie. To teraz przykłady użycia:
var timer = funkcja.delay(5000);
Aby móc zatrzymać opóźnienie najlepiej by było ono przypisane do jakiejś zmiennej, wtedy celem zatrzymania odliczania zapiszemy:
$clear(timer);
Analogicznie w wypadku metody periodical:
var timer = funkcja.periodical(5000);
i zatrzymujemy okresowe wykonywanie funkcji:
$clear(timer);
No to na koniec ostatni przykład z metodami delay, periodical oraz funkcją $clear:
Jeszcze raz krótko o metodzie create
Aby jeszcze dokończyć temat metody create, chciałbym dodać, że w wypadku opcji bind, arguments, delay i periodical wartości podajemy tak jak w wypadku odpowiadających im metod, natomiast w wypadku opcji event i attempt podajemy wartości true lub false w zależności od tego czy chcemy z danej opcji skorzystać... Ponadto dla opcji event można podać nazwę klasy - wtedy obiekt Event jest podawany jako pierwszy argument metody initialize danej klasy...
To by było na tyle jeśli chodzi o plik function.js, w dwóch następnych częściach kursu omówię pliki Number.js i Strong.js ...
Mootools 1.11 - Number.js do góry
Plik number.js to jeden z mniej rozbudowanych składników frameworka mootools - zawiera 5 metod do operowania na liczbach.
toInt
Metoda toInt zwraca z podanego ciągu znaków liczbę całkowitą. Jej użycie jest bardzo proste:
zmienna.toInt();
lub:
('12px').toInt();
Powyższy kod spowoduje zamienienie zmiennej zmienna na liczbę całkowitą. Najczęściej używa się tej metody by uzyskać liczbę oznaczającą długość danego elementu (gdy trzeba usunąć zapis 'px' z końca ciągu znaków). W przykładzie, który zamieszczę po omówieniu kilku metod zauważycie, że zamiana na liczbę całkowitą ma miejsce tylko wtedy gdy dany ciąg znaków zaczyna się od cyfry/cyfr i jest brane pod uwagę pierwsze wystąpienie liczby. To znaczy:
10lol zostanie zamienione na 10, ale już:
lol10 zostanie zamienione na NaN - z ang. Not a Number...
Inny przypadek 10lol10 - nie zostanie zamienione na 1010, ale na 10 (pierwsze wystąpienie ciągu cyfr (lub cyfry)).
toFloat
Metoda toFloat ma podobne działanie co metoda toInt tylko zamiast liczby całkowitej zwraca liczbę zmiennoprzecinkową. Użycie jest takie samo ja w wypadku metody toInt:
zmienna.toFloat();
lub:
('12.5razy').toFloat();
Po wykonaniu tego kodu zostanie zwrócona liczba zmiennoprzecinkowa z danej zmiennej...
Zasady zamiany są podobne jak w wypadku metody toInt - ciąg musi się zaczynać od cyfry, a jedynym znakiem rozdzielającym cyfry może być kropka - wtedy dalsza część zostanie potraktowana jako ułamek dodany do danej liczby:
10.56px zamienione zostanie na 10.56
1,23 zamienione zostanie na 1
isNaN
Skoro już wspominam o metodach toInt i toFloat to pozwolę sobie jeszcze wspomnieć o funkcji isNaN jaką daje nam do dyspozycji sam JavaScript - jest to funkcja, która jako argument pobiera zmienną, którą sprawdza pod względem nie bycia liczbą. Zatem możemy dzięki temu elegancko napisać warunek sprawdzający poprawność podanych argumentów...
isNaN(zmienna);
Funkcja isNaN zwraca true w wypadku gdy dana zmienna nie jest liczbą i false w wypadku gdy dana zmienna jest liczbą...
limit
Metoda limit pozwala określić przedział do jakiego zostanie ograniczona dana zmienna. Pobiera ona dwa argumenty - wartość minimalną i maksymalną danego przedziału:
(150).limit(min,max);
Jeżeli liczba jest mniejsza od dolnej granicy przedziału to jej wartość zostanie zwiększona do tejże granicy, w wypadku gdy liczba jest większa od górnej granicy przedziału wtedy jej wartość zostanie pomniejszona do tej granicy. W wypadku gdy dana liczba mieści się w danym przedziale, jej wartość nie ulegnie zmianie... Przykłady:
10.limit(5,9); // zwróci 9
3.limit(5,9); // zwróci 5
9.limit(5,9); // zwróci 9
6.limit(5,9); // zwróci 6
round
Metoda round służy do zaokrąglania liczby z ustaloną precyzją. Jako argument przyjmuje wielkość precyzji zaokrąglenia. Domyślna wartość to 0, zatem liczba zaokrąglana zostanie zamieniona w liczbę całkowitą (jeżeli jest liczbą zmiennoprzecinkową). Jeśli jako wartość precyzji podamy liczbę większą od zera to liczba będzie zaokrąglana do tylu miejsc po przecinku , w wypadku liczb mniejszych od zera liczba będzie zaokrąglana kolejno do jedności, setek, tysięcy itd.
Składnia metody:
liczba.round(precyzja);
W wypadku zaokrąglania np.: 15 z precyzją 1 otrzymamy 20 natomiast dla liczby 14.9 otrzymamy już 10...
To pora na taki zbiorczy przykład dla wymienionych wyżej metod pliku number.js :
times
Metoda times służy do wywoływania funkcji określoną liczbę razy. Składnia metody:
(ilość_wywołań).times(funkcja);
Dzięki tej metodzie możemy więc wykonać coś w rodzaju pętli określoną liczbę razy. Według mnie jest to dobre rozwiązanie skracające kod - zamiast pisania prostej pętli piszemy liczbę wykonań (lub podajemy zmienną) i wykonujemy dany kod żądaną liczbę razy.
Przykład użycia metody times poniżej:
W następnej części kursu mootools zajmiemy się ostatnim składnikiem grupy Native - plikiem strong.jsm umożliwiającym operacje na ciągach znaków...
Mootools 1.11 - String.js do góry
Plik string.js to ostatni składnik grupy Native frameworka mootools. Służy do operowania na ciągach znaków i ma też trochę wspólnego z poznanymi już metodami pliku number.js . Mianowicie chodzi mi o metody toInt i toFloat - obie znajdowały się pliku number.js i znajdują się także w pliku string.js - ponieważ ich działanie zostało już wcześniej omówione, nie będę ich tu opisywał i zajmę się pozostałymi 10 metodami pliku string.js . Dodatkowo wspomnę krótko o wyrażeniach regularnych w JavaScript, ponieważ wiedza ta przyda się w wypadku tegoż pliku... Ponadto poprawimy troszkę funkcjonalność mootools nowymi funkcjami tak by uzupełnić małe braki w kodzie ;) ...
Krótko o wyrażeniach regularnych w JavaScript
Wyrażenia regularne wykorzystują wzorce i opcje - wzorzec to jak sama nazwa wskazuje schemat poszukiwanego ciągu znaków, natomiast opcje określają parametry wyszukiwania tegoż ciągu znaków. Wyrażenia regularne pozwalają nam na przykład sprawdzić poprawność podanego przez użytkownika adresu e-mail, przydają się także przy przeszukiwaniu i podmianie ciągów znaków... Ponieważ temat ten jest dość rozbudowany odsyłam wszystkich, którzy nie mieli z nim styczności pod ten adres:
szczególnie interesujące nas sekcje to:
- Parametry oraz
- Znaki specjalne w wyrażeniach regularnych
test
Metoda test bazuje na wspomnianych wyrażeniach regularnych - pozwala sprawdzić czy dany wzorzec występuje w danym ciągu znaków. Jeżeli tak to metoda zwraca wartość logiczną true, w przeciwnym wypadku zwracana jest wartość logiczna false.
Przykłady użycia:
("dziudek@mail.pl").test('^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$');
Powyższy kod zwróci wartość true, ponieważ podany adres e-mail jest poprawny w kontekście użytego wyrażenia regularnego...
Jeszcze opiszę krótko prezentowane wyrażenie regularne, bo z pewnością wielu osobom wydaje się ono skomplikowane. Wyrażenie to sprawdza czy podany adres e-mail zaczyna się od ciągu znaków alfanumerycznych, ponadto akceptuje wszelkie wystąpienia kropek i myślników oraz podkreśleń w nazwie użytkownika. Po takim ciągu musi znaleźć się znak @, a po nim znów ciąg znaków podobny do tego co na początku z tym, że na końcu musi wystąpić sekwencja dwu- lub trzy-znakowych ciągów znaków zaczynających się od kropki (domeny). Myślę, że po lekturze wspomnianego wcześniej artykułu z MDC wszystko stanie się jasne, jeżeli jeszcze nie jest ;)
camelCase
Metoda camelCase pozwala zamienić dany tekst (zapisany z użyciem metody hyphenate) na tak zwany styl wielbłądzi - krótko mówiąc wszelkie myślniki są usuwane z tekstu, a każdy wyraz ciągu znaków zaczyna się z dużej litery (poza pierwszym wyrazem).
Użycie:
("to-jest-test").camelCase();
Zwrócony zostanie ciąg "toJestTest".
Pewnie wielu z Was dostrzega małą niedogodność - otóż o wiele bardziej przydatne byłoby zamienianie spacji na styl wielbłądzi... Ale możemy łatwo dodać odpowiednią funkcję bazująca na metodzie camelCase. Możemy to uczynić na dwa sposoby - dodać tą funkcję w kodzie pliku string.js lub w kodzie naszego skryptu. Ja wybrałem tą drugą metodę i stworzyłem funkcję camelCaseSpace poprzez zmianę wyrażenia regularnego stosowanego w metodzie camelCase:
String.extend({
camelCaseSpace: function(){
return this.replace(/\s\D/g, function(match){
return match.charAt(1).toUpperCase();
});
}
});
Można też jeszcze inaczej zbudować tą funkcję tak aby działała jak wyżej wymieniona oraz metoda camelCase (czyli zamieniała i spacje i myślniki):
String.extend({
camelCaseSpace: function(){
return this.replace(/[\s,-]\D/g, function(match){
return match.charAt(1).toUpperCase();
});
}
});
hyphenate
Metoda hyphenate pozwala zamienić styl wielbłądzi na ciąg znaków gdzie wyrazy zaczynają się z małej litery, a wyrazy są rozdzielone myślnikami...
Użycie:
("toJestTest").hyphenate();
Zwrócony zostanie ciąg "to-jest-test".
Podobnie jak w wypadku metody camelCase z pewnością wiele osób z chęcią ujrzałoby możliwość zamiany na taki ciąg znaków nie tylko stringów zapisanych za pomocą camelCase, ale także ciągów gdzie wyrazy rozdzielone są spacją... Dodajmy zatem funkcję hyphenateSpace :
String.extend({
hyphenateSpace: function(){
return this.replace(/\s[A-Z]/g, function(match){
return ('-' + match.charAt(1).toLowerCase());
});
}
});
W jej wypadku trzeba było troszkę bardziej pokombinować niż tylko zmieniać wyrażenie regularne ;) Bardziej spostrzegawcze osoby zauważą jednak małe niedopracowanie - otóż owszem zaprezentowana metoda zadziała prawidłowo, ale tylko w wypadku gdy każde słowo zaczyna się z dużej litery. Nie muszę chyba mówić, że rzadko zdarzają się zdania pisane "W Ten Sposób" ;) Dodajmy zatem do tej funkcji obsługę małych liter na początku wyrazów:
String.extend({
hyphenateSpace: function(){
return this.replace(/\s\w/g, function(match){
return ('-' + match.charAt(1).toLowerCase());
});
}
});
Teraz już powinno działać elegancko ;)
capitalize
Metoda capitalize zamienia wszystkie pierwsze litery wyrazów na duże litery. Można powiedzieć, że jej działanie jest podobne do działania metody camelCase z dwoma różnicami :
capitalizenie usuwa spacji / myśliników,capitalizepowiększa także literę w pierwszym wyrazie (czegocamelCasenie robi).
Użycie:
("to jest test").camelCase();
Zwróci nam "To Jest Test".
No to pora na zbiorczy przykładzik użycia metod camelCase, hyphenate, capitalize oraz moich dwóch - camelCaseSpace i hyphenateSpace:
trim
Metoda trim usuwa spacje z początku i końca danego ciągu znaków...
Przykład użycia:
("To jest test").trim();
Zwróci "To jest test".
clean
Metoda clean usuwa spacje tak jak metoda trim, a ponadto usuwa powielone spacje z danego ciągu znaków...
Przykład użycia:
("Tojesttest ").clean();
Zwróci "To jest test".
contains
Metoda contains służy sprawdzeniu czy podany jako pierwszy argument ciąg znaków występuje w sprawdzanym stringu. Ponadto metoda ta pozwala określić jako drugi argument ciąg znaków, który występuje przed i po szukanym ciągu podanym w pierwszym argumencie. Metoda contains zwraca wartość logiczną true w wypadku gdy badany ciąg znaków spełnia podane warunki i false w wypadku ich nie spełnienia...
Przykłady użycia:
("test test1 test2 test3").contains("test"); // zwróci true
("test test1 test2 test3").contains("test1"); // zwróci true
("test test1 test2 test3").contains("test1"," "); // zwróci true
("test test1 test2 test3").contains("tes"); // zwróci true
("test test1 test2 test3").contains("tes"," "); // zwróci false
("test test1 test2 test3").contains("test"," "); // zwróci true
Pora na kolejny zbiorczy przykład dla metod trim, clean i contains:
rgbToHex i hexToRgb
Metody rgbToHex oraz hexToRgb mają podobne działanie tylko inny kierunek działania ;) Jak same nazwy wskazują służą one do zamiany zapisu koloru w postaci RGB do zapisu heksadecymalnego i na odwrót.
Metoda rgbToHex przetwarza ciągi postaci:
"rgb(wartość1,wartość2,wartość3)"
na ciągi:
"#6_znaków"
Metoda rgbToHex może ponadto przetwarzać także ciągi postaci:
"rgba(wartość1,wartość2,wartość3,alpha)"
Gdzie
alpha
to liczba z przedziału 0,1. Warto wiedzieć, że gdy wartość zmiennej alpha wynosi 0 to metoda rgbToHex zwróci wartość "transparent".
W wypadku metody hexToRgb zamieniane są ciągi postaci:
"#6_znaków"
na ciągi:
"rgb(wartość1,wartość2,wartość3)"
Czyli jak już wspominałem działanie odwrotne do działania metody rgbToHex.
Warto jeszcze dodać, że obie metody pobierają jeden argument, który w wypadku przyjęcia wartości true spowoduje, że obie metody zamiast ciągu znaków będą zwracały tablice postaci:
['wartość1','wartość2','wartość3']
W wypadku metody rgbToHex oraz:
[wartość1,wartość2,wartość3]
w wypadku metody hexToRgb.
Warto jeszcze dodać, że metoda hexToRgb akceptuje skrócony zapis heksadecymalny w postaci:
#CCC
Obie metody w wypadku wystąpienia błędów w zapisie przetwarzanego ciągu zwracają wartość logiczną false.
Na podsumowanie obu metod przykład:
escapeRegExp
Metoda escapeRegExp pozwala na przerobienie wszelkich znaków wykorzystywanych w wyrażeniach regularnych z danego ciągu tak by były interpretowane jako normalne znaki poprzez wstawienie slashy przed tymi znakami...
Przykładowo zapis:
"funkcja(){}"
Zawiera znaki wykorzystywane w wyrażeniach regularnych, jeżeli chcemy jednak wykorzystać jako wzorzec właśnie ten ciąg znaków to potrzebujemy przed znakami ( , ) , { oraz } wstawić slashe co wykona za nas właśnie metoda escapeRegExp:
("funkcja(){}").escapeRegExp();
zwróci ciąg:
"funkcja\(\)\{\}"
To już wszystko co chciałem opisać na temat pliku string.js, tym samym zakończyliśmy omawianie grupy Native frameworka mootools. W następnej części kursu przejdziemy do grupy Elements...
Mootools 1.11 - Element.Selectors.js do góry
Plik Element.Selectors.js oddaje nam do dyspozycji kilka metod i funkcji do selekcji elementów z drzewa dokumentu. Zawarte w nim metody i funkcje pozwalają na selekcję zarówno pojedynczych elementów jak i grup elementów. Zawartość tego pliku możemy podzielić na dwie części : samodzielne funkcje i metody klasy Element. Do pierwszej grupy zaliczamy funkcje:
- $E
- $ES
natomiast do drugiej grupy metody:
- getElements
- getElement
- getElementsBySelector
- getElementsByClassName
- getElementById
$E
Funkcja $E zwraca pierwszy element typu podanego jako pierwszy argument i znajdujący sie wewnątrz elementu posiadającego identyfikator podany jako drugi argument tej funkcji (domyślnie wyszukiwanie elementu danego typu odbywa się w całym dokumencie).
Na przykład:
$E('a');
zwróci pierwszy link w dokumencie, ale już:
$E('a','linki');
zwróci pierwszy link znajdujący się w elemencie posiadającym id "linki".
$ES
Funkcja $ES podobnie jak funkcja $E służy do selekcji elementów na podobnej zasadzie, z tą różnicą, że zwraca tablicę elementów spełniających warunki podane w argumentach jakie pobiera ta funkcja. Przykładowo zapis:
$ES('a');
zwróci tablicę zawierającą wszystkie linki z dokumentu, a zapis:
$ES('a','linki');
zwróci tablicę wszystkich linków zawartych w elemencie posiadającym id "linki".
getElements
Metoda getElements służy do bardziej szczegółowej selekcji wielu elementów. Metoda ta należy do klasy Elements, zatem jej metody dołączamy do elementów dokumentu. Metoda ta ma podobne działanie do funkcji $ES jednak jej składnia wygląda zupełnie inaczej ze względu na powiązanie z klasą Element - najpierw określony zostaje element w którym chcemy wyselekcjonować elementy potomne, a następnie do tegoż elementu dodajemy metodę getElements z odpowiednim argumentem:
$('id_elementu').getElements(selektor);
Składnia tej metody pozwala nie tylko określić typ poszukiwanych elementów, ale także pozwala określić jakie wartości atrybutów, dany element ma posiadać.
Wszystko zależy od tego jak zapiszemy atrybut, który w zapisie składni oznaczyłem jako selektor.
Aby wyselekcjonować wszystkie obrazki z danego elementu zapiszemy:
$('id_elementu').getElements('img');
Ponadto możemy zaraz po nazwie typu selekcjonowanych elementów zapisać nawias kwadratowy, a w nim umieścić regułę jaką musi spełniać dany atrybut by element został wyselekcjonowany.
Zapis ten ma postać następującą:
typ_elementu[nazwa_atrybutaOPERATORciąg_znaków]
Przykładowo reguła:
a[id=test]
pozwoli na selekcję tylko linków posiadających id "test".
Z kolei reguła:
a[id!=test]
pozwoli na selekcję wszystkich linków poza tymi, które posiadają id "test".
Mamy do dyspozycji jeszcze dwa operatory - ^= oraz $=:
a[id^=test]
pozwoli na selekcję wszystkich linków, których id zaczyna się od ciągu znaków "test", natomiast reguła:
a[id$=test]
pozwoli na selekcję tych linków, których id kończy się ciągiem znaków "test".
getElement
Metoda getElement działa na takiej samej zasadzie jak metoda getElements (bo wykorzystuje ją w czasie działania) jednak zwraca tylko pierwszy element. Skoro już znamy zasady selekcji elementów na podstawie metody getElements więc tylko dla formalności podaję składnie metody getElement:
$('id_elementu').getElement(selektor);
getElementsBySelector
Metoda getElementsBySelector to kolejna metoda działająca na podstawie metody getElements jednak w odróżnieniu od niej pozwala nam na rozdzielanie selektorów średnikiem, a co za tym idzie pozwala na wybór elementów kilku typów naraz.
Przykładowo aby otrzymać tablicę zawierającą wszystkie linki i obrazki z dokumentu zapiszemy:
document.getElementsBySelector('a,img');
getElementsByClassName
Metoda getElementsByClassName służy do selekcji elementów według atrybutu class. Gdybyśmy chcieli wyselekcjonować wszystkie elementy przypisane do klasy "test" to zapiszemy:
document.getElementsByClassName('test');
co jest równoznaczne z zapisami:
document.getElements('.test');
oraz:
$$('.test');
getElementById
Metoda getElementById z pewnością wielu kojarzy się jako podstawowa metoda związana z obiektem document. Na czym polega różnica ? Otóż tą metodę możemy zastosować z każdym elementem dokumentu (nie tylko z obiektem document) i zawęzić krąg poszukiwań elementów do danego elementu. Jaką mamy z tego korzyść ? Czasami może się zdarzyć, że w dokumencie znajdują się dwa lub więcej elementów posiadające ten sam id - wtedy możemy wyselekcjonować jeden z nich na podstawie różniącego ich elementu nadrzędnego. Oczywiście powtarzające się identyfikatory elementów to błąd, ponieważ powinny być to nazwy unikalne, ale kto wie co nas spotka podczas pisania skryptu dla nie swojego dokumentu ? Dobra te 2 ostatnie zdania to oczywiście mały joke (choć czasami może mieć związek z brutalną rzeczywistością :P ) ;] Tak naprawdę korzyść z używania tej metody jest taka, że możemy sprawdzić czy element o danym identyfikatorze znajduje się wewnątrz określonego elementu. Dzięki temu mamy ułatwione zadanie w wypadku selekcji danego elementu pod warunkiem, że znajduje się w określonym miejscu drzewa dokumentu (wewnątrz pożądanego dokumentu).
$('id_elementu').getElementById('id_szukanego');
Na podsumowanie przykład zbiorczy dla wszystkich prezentowanych powyżej metod, gdzie prezentuję także kilka bardziej skomplikowanych sposobów ich użycia:
Apropo powyższego linka - wyselekcjonowane elementy są zaznaczane czerwonym obramowaniem w chwili najechania na dany "przycisk" wykonujący daną funkcję i są odznaczane po przesunięciu kursora znad obszaru "przycisku".
Internet Explorer jak zwykle nie zawiódł i ma lekkie problemy z kilkoma metodami, a dokładniej ich argumentami. W sumie to może nie tyle problemy to są co dziwne zachowanie - przy metodzie getElementById gdy dany element nie znajdował się w wymaganym miejscu wszystko ok - pojawia się alert itd. ale już gdy powinno pojawić się zaznaczenie (przedostatni button) IE wywala błąd o nieobsługiwanej metodzie, a żeby było fajniej to gdy najedziemy na "przycisk" z napisem $ES('li') nagle wspomniana metoda zaczyna działać O.o (i nie wywala błędu). Z innych ciekawych zjawisk zaobserwowałem jeszcze problemy z niektórymi operatorami - brak reakcji na $('obrazki').getElements('img[src=av.gif]') i zaznaczenie wszystkich obrazków mimo reguły img[src!=av.gif]. IE olał też sobie $('obrazki').getElements('img[src^=av]'), za to bezbłędnie zadziałał w przypadku $('structure').getElements('li[id=pierwszy] li[class=drugi]'), a przecież wcześniej operator = sobie olewał... Poprawnie też zadziałał w wypadku $('linki1').getElementsByClassName('link[rel=page]') O.o
No cóż IE zawsze potrafił zaskoczyć czymś i tym razem także nie zawiódł ;)
Na pocieszenie wszystkich testujących i tych, którzy zaraz zaczną pisać jaki ten mootools zły dodam, że z wymienionych wyżej błędów w Mootools 1.111 został tylko jeden - ten zagadkowy z getElementById, która raz zwraca błąd, a raz działa poprawnie ;] Reszta błędów w najnowszej wersji mootools nie występuje ;] I na niej też oparłem ten przykład, ale dzięki temu co napisałem macie mały pogląd na to co się ulepszyło pomiędzy mootools 1.1, a mootools 1.11 ;]
Tak jeszcze dodam tylko, że właśnie sobie pobrałem najnowszą wersję mootools z SVN i ciepło mi się zrobiło jak zobaczyłem, że w mootools rev.676 rozbili opisywany tu przeze mnie plik na nową grupę Selectors i umieścili w niej dwa plik , ale z tego co obejrzałem w kodzie zmiany są duże ;] W każdym razie trzeba poczekać na wydanie stabilne (mootools 1.2 lub mootools 2.0) zobaczymy wtedy jak daleko pójdą zmiany w tej grupie funkcji (ale tak jak pisałem zmiany wyglądają na duże zwłaszcza, że sporo bugów powstawało gdy testowałem przykład na najnowszym mootools ;) ). W następnej części kursu opiszę plik Element.Filters.js, który rozszerzy funkcję $$ o możliwość filtrowania zwracanych przez nią elementów...
Mootools 1.11 - Element.Filters.js do góry
W pliku element.filters.js znajdziemy metody, które pozwolą nam na zwiększenie możliwości selekcji z danej kolekcji elementów (na przykład tej zwracanej za pomocą funkcji $$). Dzięki tym metodom możemy dokonać filtrowania zwracanych elementów według tagu, klasy, identyfikatora oraz atrybutu.
filterByTag
Metoda filterByTag pozwala wyselekcjonować nam z danej grupy elementów tylko te elementy, które są danego typu - na przykład linki, grafiki czy elementy listy. Gdybyśmy przykładowo chcieli wyselekcjonować z grupy wszystkich obrazków i linków danego dokumentu tylko linki to zapiszemy:
document.getElementsBySelector('a, img').filterByTag('a');
Jak widzimy składnia tej metody jest prosta:
kolekcja_elementów.filterByTag('typ_elementu');
filterByClass
Metoda filterByClass pozwala nam na wyselekcjonowanie z danej kolekcji elementów tych, które mają przypisaną daną klasę.
Składnia tej metody:
kolekcja_elementów.filterByClass('nazwa_klasy');
i przykład użycia - wyselekcjonowanie z danej grupy linków wszystkich elementów klasy 'link':
$$('.linki').filterByClass('link');
Ktoś się pewnie by powiedział, że te metody to to samo co poznane wcześniej metody z pliku element.selectors.js, ale różnica jest pomiędzy tymi metodami duża. Można powiedzieć, że poznane wcześniej metody służą do selekcji danej grupy elementów, a metody z pliku element.filters.js służą do filtrowania wyselekcjonowanej tymi metodami grupy elementów. Dlatego metod tych używamy w odniesieniu na przykład do grupy linków, a nie w odniesieniu do całego dokumentu by wyselekcjonować wszystkie linki...
filterById
Zasada działania tej metody jest podobna jak w wypadku dwóch poprzednich - z tą różnicą, że ta metoda zwróci tylko elementy posiadające dany identyfikator.
Składnia:
kolekcja_elementów.filterById('id_szukanych_elementow');
Na przykład wyselekcjonowanie linków posiadających id "ostatni" z grupy linków wygląda następująco:
$$('a').filterById('ostatni');
filterByAttribute
Metoda filterByAttribute to zdecydowanie najbardziej złożona metoda z wszystkich wymienionych - pozwala nam nie tylko wyszukiwać elementy posiadające dany atrybut, ale także za pomocą operatorów określić jaką zawartość powinien mieć ten atrybut.
Pełna składnia tej metody wygląda następująco:
kolekcja_elementów.filterByAttribute('atrybut','operator','wartość_atrybutu');
gdzie argument "wartość_atrybutu" jest uwzględniany tylko wtedy gdy podany jest argument "operator". Co do operatora to może on przyjąć jedną z 6 poniższych wartości :
- "=" - operator ten oznacza, że wyselekcjonowane zostaną tylko te elementy, które mają atrybut o dokładnie takiej wartości jak podana jako 3. argument metody.
- "!=" - operator ten oznacza, że wyselekcjonowane zostaną tylko te elementy, które mają atrybut różny od takiej wartości jak podana jako 3. argument metody.
- "^=" - ten operator służy do wyselekcjonowania elementów, których atrybut zaczyna się ciągiem znaków podanym jako 3. argument metody.
- "$=" - ten operator służy do wyselekcjonowania elementów, których atrybut kończy się ciągiem znaków podanym jako 3. argument metody.
- "*=" - użycie tego operatora oznacza selekcję tych elementów, które w atrybucie zawierają podany jako 3. argument metody ciąg znaków.
-
"~=" - użycie tego operatora oznacza selekcję tych elementów, które w atrybucie zawierają podany jako 3. argument metody ciąg znaków, ale pod warunkiem, że jest on oddzielnym słowem:
przy takich argumentach metody:
('name','~=','test')w wypadku takiego elementu:
<element name="test"/>lub
<element name="exam test"/>zostanie on zaakceptowany, natomiast element:
<element name="examtest"/>zostanie odrzucony.
Na koniec przykład podsumowujący powyższe metody:
W następnej części kursu zajmiemy się plikiem element.form.js, służącym do obsługi formularzy (przy okazji dodam, że jest to najmniejszy plik w grupie Element).
Mootools 1.11 - Element.Form.js do góry
Plik element.form.js zawiera dwie metody rozszerzające możliwości klasy Element w zakresie obsługi formularzy.
getValue
Metoda getValue zwraca nam wartość danego elementu formularza. W wypadku pól input, textarea czy select (jednokrotnego wyboru) zwracana jest sama wartość, natomiast w wypadku pola select wielokrotnego wyboru jest zwracana tablica wybranych wartości.
Składnia metody jest bardzo prosta:
element.getValue();
toQueryString
Metoda toQueryString służy do zamiany zawartości pól formularza na łańcuch postaci:
nazwa_pola=wartość_pola&nazwa_drugiego_pola=wartość_pola
znany dobrze wszystkim, którzy przesyłają dane metodą GET ;]
Składnia metody jest podobna do składni getValue:
element.toQueryString();
Z tą różnicą, że element musi być odwołaniem do formularza zatem zapis będzie wyglądał następująco:
$('id_formularza').toQueryString();
Jeszcze może dodam, że plik element.form.js zawiera trzecią metodę getFormElements, która zwraca wszystkie elementy danego formularza - a nuż komuś się przyda ;) Składnia:
$('id_formularza').getFormElements()
I to by było wszystko na temat najmniejszego w grupie Element pliku ;) Dla odmiany w następnej części kursu zajmiemy się najbardziej rozbudowanym plikiem w tej grupie - element.events.js , którego zawartość pewnie już w dużym stopniu znacie z opisu pliku event.js jeszcze z mootools 1.0, ale zmiany jakie się pojawił są dość ciekawe więc wypada napisać nowy wpis ;)
Mootools 1.11 - Element.Event.js do góry
Plik element.event.js to kolejny z elementów frameworka mootools, który z pewnością można zaliczyć do bardzo przydatnych. Wraz z tą częścią kursu nauczymy się likwidować dwa ważne problemy związane ze zdarzeniami, poskromimy klawiaturę przy użyciu JavaScript oraz zajmiemy się dodawaniem, usuwaniem i klonowaniem zdarzeń elementów ;)
W pliku element.event.js mamy zawarte 4 metody dla klasy Event oraz kilkanaście właściwości dla obiektów typu event, do tego dochodzi 6 metod klasy Element oraz trzy nowe zdarzenia i jedna metoda rozszerzająca klasę Function.
Zacznijmy od stworzenia zdarzenia onclick dla elementu.
Nasz kod będzie wyglądał następująco :
$('id_elementu').zdarzenie = function(){
// kod jaki wykona się przy wystąpieniu zdarzenia
};
W wypadku gdy w kodzie zdarzenia będzie wykorzystywany obiekt klasy Event, nasz kod będzie wyglądał tak:
$('id_elementu').zdarzenie = function(event){
var event = new Event(event);
// kod jaki wykona się przy wystąpieniu zdarzenia
};
Przykładowo dodajmy do diva posiadającego id "div1" zdarzenie onclick, które spowoduje pokazanie się alertu z id tego diva:
$('div1').onclick = function(){
alert(this.id);
};
Teraz umieśćmy w naszym divie drugi div posiadający id "div2" i dodajmy do niego w taki sam sposób zdarzenie onclick:
$('div2').onclick = function(event){
alert(this.id);
};
Mając te dwa divy możemy przejść do omawiania metody stopPropagation().
stopPropagation
Metoda stopPropagation służy do obsługi sytuacji w której mamy jeden element umieszczony w drugim i oba z nich posiadają zdarzenie np.: onclick. Jak się pewnie orientujecie, taki układ spowoduje przy kliknięciu wewnętrznego diva, wykonanie obu funkcji / kodów JS przypisanych do zdarzeń elementów.
Dla zainteresowanych - dobry artykuł na ten temat.
Przyjmijmy, że nie chcemy aby po kliknięciu diva wewnętrznego pojawiał się także alert związany z kliknięciem zewnętrznego diva. Do osiągnięcia tego celu służy właśnie metoda stopPropagation - jej użycie spowoduje, że po kliknięciu zewnętrznego diva, zdarzenia onclick przypisane do elementów nadrzędnych względem niego, nie zostaną wykonane.
Zatem tworzymy w tym wewnętrznym divie button i dodajemy do niego id "button", a do zdarzenia window.onload dodajmy kod:
$('button').onclick = function(event){
var event = new Event(event);
event.stopPropagation();
$('div2').onclick = function(event){
var event = new Event(event);
alert(this.id);
event.stopPropagation();
};
alert('stopPropagation');
};
Po pierwsze - blokujemy wywoływanie zdarzeń elementów nadrzędnych w stosunku do buttona, a po drugie zmieniamy kod zdarzenia onclick elementu div2.
Przykład prezentujący przedstawiana sytuację:
preventDefault
Są takie elementy dokumentu XML, które np.: po kliknięciu wykonują pewną określoną akcję zgodnie z podanymi atrybutami. Na przykład linki czy przycisk submit formularza. Czasami jednak, chcemy aby przed wysłaniem formularza dane zostały sprawdzone, albo chcemy by nasz link nie prowadził do danej strony według atrybutu href, a jedynie żeby ten atrybut był wykorzystywany jako zmienna dla skryptu.
Metoda preventDefault pozwoli nam na zatrzymanie domyślnych akcji onclick dla danych elementów i pozwoli w ten sposób na rozszerzenie możliwości elementów linków czy przycisków wysyłania formularzy. Warto zauważyć, że takie podejście do tych elementów zwiększy użyteczność naszych stron dla osób z wyłączoną obsługą JS. Przykładowo dla aktywnych linków z adresem "#" możemy stosować normalne adresy pozwalające wykonać dane operacje, normalnie dostępne przy użyciu efektów napisanych w JS. Podobnie z formularzami - przed wysłaniem można sprawdzić wszystkie dane, prosić użytkownika o potwierdzenie wprowadzonych danych itd. a użytkownicy bez JS zostaną poprowadzeni od razu do odpowiedniej strony...
W przykładzie posłużę się linkiem, który normalnie poprowadziłby nas do jakiejś strony, jednak dzięki zastosowaniu preventDefault pokazany zostanie jedynie alert z adresem linka.
Stwórzmy zatem w dokumencie dwa linki, posiadające id odpowiednio "link1" i "link2". Ustawmy też obu linkom atrybuty href "http://www.dziudek.jogger.pl".
Następnie dodajmy następujący kod JS:
$('link2').onclick = function(event){
var event = new Event(event);
event.preventDefault();
alert(this.href);
};
Spowoduje on zatrzymanie wykonywania domyślnego zdarzenia dla drugiego linku i pokazanie alertu.
Powyższy przykład znajduje się na stronie poniżej:
stop
Jeśli chodzi o metodę stop, to nie będę się nad nią dłużej rozwodził ponieważ wykonuje ona dla danego zdarzenia po prostu dwie metody jednocześnie - preventDefault i stopPropagination. Zatem możemy po prostu dzięki niej skrócić zapis kodu gdy stosujemy obie metody jednocześnie dla danego eventu.
Właściwości obiektu event
Obiekt event ma wiele właściwości powiązanych z położeniem kursora, czy wciskanymi klawiszami... Przejdźmy najpierw do pozycji kursora. Możemy pobierać współrzędne jego położenia na dwa sposoby - względem całej strony lub względem widocznej części strony.
Aby pobrać współrzędne kursora względem całej strony, wykorzystujemy dwie właściwości:
event.page.x;
event.page.y;
Aby zrobić to samo, ale względem widocznej części strony, korzystamy z właściwości:
event.client.x;
event.client.y;
Oczywiście w obu przypadkach x i y oznaczają odpowiednio współrzędną x i współrzędną y położenia kursora...
Przykład działania:
Zanim przejdziemy do obsługi klawiatury, omówię jeszcze dwie właściwości - target i relatedTarget. Właściwość target zwraca nam uchwyt do obiektu z jakim powiązane jest zdarzenie, natomiast właściwość relatedTarget występuje tylko w wypadku zdarzeń onmouseover i onmouseout. W wypadku zdarzenia onmouseover właściwość relatedTarget zwraca nam uchwyt do obiektu jaki opuścił kursor mysz przed znalezieniem się nad danym obiektem, natomiast przy zdarzeniu onmouseout zwracany jest uchwyt obiektu nad jakim się znalazł kursor po przejściu z danego obiektu dokumentu...
Oczywiście dostęp do obu właściwości otrzymujemy poprzez zapis:
event.target;
oraz
event.relatedTarget;
Aby lepiej zrozumieć działanie tych właściwości proponuję przetestować mały przykład :
A teraz przejdźmy już do klawiatury...
W przypadku obsługi klawiatury mamy do dyspozycji kilka właściwości :
event.shift;
event.control;
event.alt;
event.meta;
event.code;
event.key;
Pierwsze cztery zwracają wartość logiczną true, jeżeli użytkownik wcisnął dany klawisz (odpowiednio Shift, Ctrl, Alt lub metaklawisz). Pozostałe dwie właściwości zwracają ciągi znaków - kod wpisanego znaku lub sam znak (jako małą literę) , albo ewentualnie słowo ‘enter’, ‘up’, ‘down’, ‘left’, ‘ right’, ‘space’, ‘backspace’, ‘delete’ lub ‘esc’.
Oczywiście te możliwości można wykorzystać w aplikacjach np. przy skrótach klawiaturowych itd...
Przygotowałem przykład, który pozwala na zmianę stylu tekstu poprzez wciśnięcie odpowiedniej kombinacji klawiszy... Całość ogranicza się do sprawdzenia czy klawisz Ctrl został wciśnięty wraz z innym klawiszem.
Oczywiście pojawiła się mała trudność - na przykład kombinacja Ctrl + b powodowała pokazywanie zakładek w Firefoxie. Dlatego też należało zastosować zapis:
event.stop();
by uniknąć problemów z zarezerwowanymi przez przeglądarkę skrótami... Oczywiście należy pamiętać, że stosowanie skrótów pokrywających się ze skrótami przeglądarki może sfrustrować użytkownika, ponieważ odcina mu się dostęp do normalnej funkcjonalności tychże skrótów... Dlatego lepiej nie przesadzać ze stosowaniem skrótów...
Przykład o którym wspominałem wcześniej:
Warto jeszcze wspomnieć o właściwości wheel (event.wheel), zwracającej ilość obrotów kółkiem myszki no i o obiekcie keys.
Właściwość wheel zwraca wartość dodatnią przy obrocie kółkiem myszki "w górę" i ujemną wartość przy obrocie kółkiem myszki "w dół".
Obiekt keys pozwala nam rozszerzyć standardową liczbę nazwanych klawiszy o własne. Pod pojęciem nazwane klawisze rozumiem te klawisze, które reagują na zapis postaci:
event.key == 'nazwa_klawisza'.
Jak nazwać przykładowy klawisz swoją wybraną nazwą ?
Stosujemy zapis:
Event.keys.nazwa_klawisza = kod_klawisza;
Gdybyśmy chcieli w ten sposób nazwać klawisz enter (hipotetycznie oczywiście bo jest on już nazwany) to zapisalibyśmy:
Event.keys.enter = 13;
Operowanie na zdarzeniach
W tej części opiszę krótko jak dodawać, usuwać i klonować zdarzenia. Krótko bo z podobnymi funkcjami mieliśmy już do czynienia przy omawianiu pliku class.extras.js .
addEvent i addEvents
Metoda addEvent służy oczywiście dodawaniu zdarzeń do danego elementu. Metoda addEvents różni się od niej tym, że pozwala na dodanie kilku zdarzeń na raz. Składnie obu metod:
element.addEvent('typ_zdarzenia',function(){
//kod wykonywany przy zdarzeniu
});
element.addEvents({
'typ_zdarzenia': function(){
// kod funkcji
},
'typ_zdarzenia': function(){
// kodu funkcji
}
});
Przykładowo kod, który występował w jednym z moich poprzednich przykładów:
$('btn1').addEvent('mouseover',function(){
$E('a','linki2').setStyle('border','3px solid #F00');
});
$('btn1').addEvent('mouseout',function(){
$E('a','linki2').setStyle('border','none');
});
mogłem zastąpić poniższym kodem:
$('btn1').addEvents({
'mouseover': function(){
$E('a','linki2').setStyle('border','3px solid #F00');
},
'mouseout': function(){
$E('a','linki2').setStyle('border','none');
}
});
removeEvents
Metoda jest podobna do dwóch poprzednich z tą różnicą, że ta metoda usuwają zdarzenia elementu. Składnia tej metody jest prostsza niż w poprzednim wypadku:
element.removeEvents();
Powyższy kod usuwa wszystkie zdarzenia z danego elementu. Gdybyśmy chcieli usunąć tylko jedno zdarzenie to zapiszemy:
element.removeEvents('typ_zdarzenia1');
Od siebie jeszcze dodam, że do tej pory nie udało mi się dojść jak działa metoda removeEvent - wszystkie przykłady jej zastosowania jakie widziałem stanowiły długi kod więc patrząc na możliwości metody removeEvents wydaje mi się ona dobrym zastępcą metody removeEvent ;)
fireEvent
Metoda fireEvent pozwala na uruchomienie funkcji przypisanej do danego zdarzenia. Pobiera trzy argumenty - typ zdarzenia, argumenty dla uruchamianej funkcji (w wypadku gdy jest ich więcej niż jeden podajemy je jako tablicę) i opóźnienie wykonania tej funkcji:
element.fireEvent('typ_zdarzenia','argument','opóźnienie');
cloneEvents
Metoda cloneEvents służy do kopiowania zdarzeń jednego elementu do drugiego. Pozwala skopiować zarówno wszystkie zdarzenia jak i tylko jedno wybrane.
Składnia tej metody:
element.cloneEvent('element2');
Powyższy kod spowoduje skopiowanie wszystkich zdarzeń elementu element2 do elementu element.
element.cloneEvent('element2','click');
Powyższy kod sprawi, że skopiowane zostanie tylko zdarzenie onclick elementu element2 do elementu element.
Zdarzenia mouseenter i mouseleave
Te zdarzenia są wprost bezcenne w wypadku tworzenia rozwijanego menu opartego na liście nieuporządkowanej - zdarzenie mouseenter występuje w momencie najechania na dany element i nie jest wywoływane ponownie gdy najedziemy myszką na jeden z elementów potomnych tego elementu. Drugie zdarzenie występuje wtedy gdy opuścimy dany element (czyli obszar zajmowany także przez jego elementy potomne). Jak widać są to świetni zastępcy zdarzeń onmouseover i onmouseout w wielu sytuacjach.
Zdarzenie mousewheel
Zdarzenie to występuje w momencie obracania kółkiem myszki - wtedy można też odczytać ilość obrotów za pomocą właściwości wheel obiektu event.
bindWithEvent
Metoda bindWithEvent służy do automatycznego tworzenia obiektu event i wykorzystywania go w danej funkcji. Funkcja musi oczywiście pobierać jako argument dane zdarzenie...
Najlepiej będzie to wyjaśnić na podstawie przykładu. Mamy funkcję mysz:
function mysz(event){
alert(event.client.x);
};
Zatem powiążmy naszą funkcję ze zdarzeniem kliknięcia jakiegoś elementu. Tworzymy zmienną będącą referencją do danego obiektu:
element = $('id_elementu');
a następnie tworzymy powiązanie:
element.onclick = mysz.bindWithEvent(element);
W ten sposób nasze zdarzenie onclick danego elementu zostanie powiązane z funkcją mysz, która od tego momentu będzie się wykonywała po jego kliknięciu...
Zaletą wykorzystania tej metody jest fakt, że nie musimy tworzyć "ręcznie" nowego obiektu event dla naszej funkcji...
Wpis ten jest rozszerzoną wersją artykułu o pliku event.js z kursu mootools 1.0 napisanym na potrzeby kursu Mootools 1.11
W następnej części kursu zajmiemy się między innymi rozmiarami i pozycją elementów - omówię plik element.dimensions.js
Mootools 1.11 - Element.Dimensions.js do góry
Plik element.dimensions.js służy do odczytywania informacji na temat rozmiarów i pozycji elementów w dokumencie. Dodatkowo zawiera funkcję do przewijania w żądane miejsce elementów posiadających właściwość overflow. Wpis ten podobnie jak wpis o pliku element.form.js ze względu na możliwości funkcji skupi się na teoretycznym omówieniu działania metod, ponieważ do wykorzystania tych metod wystarczy wiedza o tym jakie obiekty / wartości są przez nie zwracane.
getSize
Metoda getSize wywoływana w następujący sposób:
$('id_elementu').getSize();
Zwraca obiekt postaci:
{
'scroll': {'x': wartosc, 'y': wartosc},
'size': {'x': wartosc, 'y': wartosc},
'scrollSize': {'x': wartosc, 'y': wartosc}
}
Dzięki niemu mamy dostęp do takich informacji jak:
scroll- miejsce do którego jest przewinięty element (jeśli istnieje dla niegooverflow),size- rozmiar elementu (wraz z wszelkimi obramowaniami itd.),scrollSize- rozmiar obszaru jaki można przewijać.
Każdy z wyżej wymienionych obiektów posiada dwa pola x i y.
Oczywiście do wartości odwołujemy się w sposób następujący:
jakaś_zmienna.size.x;
Gdzie do zmiennej jakaś_zmienna przypisujemy obiekt zwracany przez metodę getSize() danego elementu. Wyżej podany kod zawiera długość danego elementu.
getPosition
Metoda getPosition zwraca położenie danego elementu w postaci obiektu. Wywołujemy ją następująco:
$('id_elementu').getPosition();
A otrzymujemy obiekt postaci:
{x: wartosc, y: wartosc}
Dodatkowo metoda getPosition - jak i metody - getTop, getLeft i getCoordinates może pobierać tablicę elementów wewnątrz, których znajduje się nasz element, którego właściwości chcemy pobrać. Oczywiście podawane w tablicy elementy muszą posiadać atrybut overflow.
Zatem gdyby nasz element znajdował się w elemencie, który posiada overflow zapiszemy:
id('elementu').getPosition(['element_nadrzedny']);
getTop i getLeft
Metody getTop i getLeft zwracają odpowiednio wartości: odległości elementu od górnej części okna i odległości elementu od lewej części okna.
Wywołanie tych metod jest podobne jak w poprzednich przypadkach:
$('id_elementu').getTop();
$('id_elementu').getLeft();
Dodatkowo tak jak wspominałem za argument mogą pobierać elementy, które już wymieniłem przy okazji opisu metody getPosition.
getCoordinates
Najwięcej informacji o położeniu i rozmiarach obiektu, zwróci nam metoda getCoordinates:
Po wywołaniu:
$('id_elementu').getCoordinates();
Zostanie zwrócony obiekt postaci:
{
width: wartosc,
height: wartosc,
left: wartosc,
top: wartosc,
right: wartosc,
bottom: wartosc
}
Gdzie width i height to odpowiednio długość i wysokość elementu, a left,top,right i bottom to odpowiednio odległości od: lewej, górnej, prawej i dolnej części okna...
Ta metoda także może pobierać takie argumenty jak metody getPosition, getTop i getLeft
scrollTo
Funkcja scrollTo służy do przewijania danego elementu do określonych współrzędnych. Oczywiście element musi posiadać overflow i odpowiednią ilość treści.
Składnia funkcji wygląda następująco:
$('id_elementu').scrollTo(x,y);
Gdzie x i y to współrzędne punktu do którego ma zostać przewinięty element.
Przykładowo - gdybyśmy mieli div mający długość 200 pikseli wypełniony treścią o długości 400 pikseli i chcielibyśmy przewinąć zawartość elementu tak by była widoczna niewidoczna część to zapiszemy :
$('testowy').scrollTo(200,0);
W następnej części kursu przejdziemy już do grupy Window.
Mootools 1.11 - Window.DomReady.js do góry
Plik window.domready.js robi właściwie tylko jedno - dodaje nowe zdarzenie - domready. Na czym ono polega ? Jest ono wywoływane w momencie załadowania drzewa dokumentu - ma tą przewagę nad zdarzeniem onload, że z reguły ma miejsce szybciej bo nie są brane pod uwagę grafiki, które mają główny wpływ na czas ładowania strony. Jakie mamy z tego korzyści ? Możemy wykonać pewne operacje przed pełnym załadowaniem strony - na przykład zmienić/dostosować rozmiar niektórych elementów itd.
Zdarzenie domready dodajemy w następujący sposób:
window.addEvent('domready', function(){
alert('DOM gotowy...');
});
Osobom pragnącym bardziej zgłębić tematykę tego zdarzenia polecam wpis Riddle'a pod tytułem "Wykonywanie skryptów po załadowaniu DOM"bardzo dobrze opisujący to zagadnienie ;)
Mootools 1.11 - Window.Size.js do góry
Plik window.size.js zawiera metody rozszerzające obiekt window o możliwość pobierania informacji na temat wielkości okna. Wpis ten także będzie natury teoretycznej gdyż chodzi tak naprawdę jedynie o to by wiedzieć co zwracają poszczególne metody ;) Po tej części kursu przejdziemy do sekcji o wiele ciekawszej niż znane nam już grupy plików - grupy Remote (AJAX,JSON i te sprawy ;D ) ;)
getWidth i getHeight
Powyższe metody służą do odczytywania szerokości i wysokości okna przeglądarki. Obie zwracają wartość jako liczbę całkowitą.
Użycie:
window.getWidth();
oraz:
window.getHeight();
getScrollWidth i getScrollHeight
Powyższe metody zwracają szerokość i wysokość obszaru jaki w rzeczywistości zajmuje strona. Podobnie jak w wypadku poprzedniej pary metod zwracane są liczby całkowite.
Użycie:
window.getScrollWidth();
oraz:
window.getScrollHeight();
getScrollLeft i getScrollTop
Metody te służą do sprawdzenia o ile zostało przewinięte okno przeglądarki wszerz i wzdłuż. Oczywiście zwracane są liczby całkowite.
Użycie podobnie jak w wypadku poprzednich metod:
window.getScrollLeft();
oraz:
window.getScrollTop();
getSize
Ostatnia metoda w tym pliku. Ma identyczne działanie jak metoda getSize z pliku element.dimensions.js z tą różnicą, że jest metodą obiektu window, a nie obiektu klasy Element.
Użycie:
window.getSize();
Natomiast zwracany obiekt, jest taki sam jak w wypadku metody getSize dla klasy Element:
{
'scroll': {'x': wartość, 'y': wartość},
'size': {'x': wartość, 'y': wartość},
'scrollSize': {'x': wartość, 'y': wartość}
}
Tak naprawdę metoda ta zwraca wartości wszystkich wymienionych wyżej sześciu metod w jednym obiekcie.
W następnej części kursu zajmiemy się już zagadnieniami jak najbardziej praktycznymi - obiektem XMLHttpRequest i jego obsługą za pomocą mootools ;)
Mootools 1.11 - XHR.js do góry
W kursie mootools przebrnęliśmy już przez 5 z 9 grup plików. Do tej pory poznawaliśmy jednak z reguły rozwiązania, jakie daje nam mootools w zakresie programowania obiektowego, obsługi podstawowych obiektów JavaScript (window, string czy array). Obecnie zajmiemy się moim zdaniem tą fajniejszą częścią frameworka mootools. Przed nami sekcje Remote, Effects, Drag i Plugins - to one sprawią, że nasze strony naprawdę "ożyją" ;) Oczywiście zaczynamy od sekcji Remote - poznamy obsługę AJAX, pobawimy się cookies, pododajemy dynamicznie pliki do naszych stron, a na koniec zgłębimy trochę tematykę przesyłu danych w formacie JSON.
Zaczynamy od pliku XHR.js , który z pewnością wielu osobom skojarzy się z obiektem XMLHttpRequest - można powiedzieć sercem AJAX, który zmienił znacząco oblicze Internetu - wystarczy spojrzeć na aplikacje webowe Google - GMail, Google Maps czy Google Reader w których AJAX jest wykorzystywany na szeroką skalę.
Plik XHR.js zawiera podstawową obsługę wysyłania i odbierania zapytań. Dodatkowa funkcjonalność została zaimplementowana w plikach Ajax.js i Json.Remote.js, ale by móc je omówić trzeba znać obsługę rozwiązań jakie udostępnia nam plik XHR.js.
Klasa XHR posiada 3 metody oraz 5 parametrów jakie możemy jej ustawić.
Wspomniane parametry to:
method- określa metodę zapytania : GET lub POST. Wartości zapisujemy jako'get'lub'post'przy czym'post'jest wartością domyślną i w wypadku wywoływania zapytań metodą POST nie musimy zapisywać tego parametru.async- jest to wartość logiczna, która określa rodzaj zapytań - asynchroniczne w wypadku wartości logicznejtruei synchroniczne gdy parametr ten jest ustawiony jako wartość logicznafalse. Jaka jest różnica pomiędzy zapytaniami synchronicznymi i asynchronicznymi ? Żądania asynchroniczne są wywoływane "w tle", a zatem w czasie ich wykonywania można dalej normalnie korzystać ze strony do czasu otrzymania żądania zwrotnego z rezultatami dla wysłanego zapytania. Synchroniczne żądania oznaczają z reguły (w zależności od czasu trwania zapytania) wstrzymanie pracy interfejsu użytkownika do czasu otrzymania odpowiedzi. Domyślna wartość tego parametru to oczywiścietrue.-
encoding- parametr ten teoretycznie służy do określania kodowania wysyłanych danych. Domyślna wartość to'utf-8'oznaczająca oczywiście, że wysyłane dane będą używały kodowaniaUTF-8. W praktyce nie zauważyłem by ten parametr coś zmieniał. O wiele poważniejszy problem występuje przy odbiorze danych wykorzystujących kodowanie inne niżUTF-8- wtedy tzw."krzaczki" są gwarantowane ;] Jak to można rozwiązać ? Z pewnością od strony PHP łatwiej bo wystarczy w generowanym pliku wykorzystać funkcjęheaderz odpowiednimi parametrami. Gdybyśmy chcieli to zrobić od strony JS to może być problem. Jest funkcja, która wymusza dany typ dokumentu -overrideMimeType, którą musimy koniecznie wywołać przed wysłaniem zapytania ( przed metodąsend()), ale jest mały szczególik - metoda ta działa tylko (przynajmniej z tego co testowałem) na Firefoxie i Safari - Opera nie reaguje zupełnie (żadnej zmiany ani błędu w konsoli), a IE zwraca błąd. Jakby jednak ktoś chciał użyć z mootools tej funkcji to przykładowy kod prezentuję poniżej - pozwala on na poprawne wyświetlenie odpowiedzi ze strony kodowanej wwindows-1250, oczywiście pod warunkiem, że strona na jakiej ją wyświetlamy też używa tego kodowania:obiekt_XHR.transport.overrideMimeType('text/html;charset=windows-1250'); autoCancel- jest to parametr, który określa czy zapytanie ma być anulowane, jeżeli w momencie jego wysyłania inne zapytanie było uruchomione. Wartością tego parametru jest wartość logiczna -truelubfalse. Domyślnie ta opcja jest wyłączona (ma wartośćfalse).-
headers- to parametr, który jest obiektem zawierającym nagłówki wysyłane wraz z zapytaniem. Nagłówki w tym obiekcie zapisujemy w postaci:'nazwa_naglowka':'zawartosc_naglowka'Domyślnie obiekt ten jest pusty.
Zanim przejdziemy do praktyki, zapoznajmy się jeszcze ze zdarzeniami jakie udostępnia nam obiekt klasy XHR i jego właściwościami.
Zdarzenia związane z obiektem klasy XHR
onRequest- zdarzenie to występuje w momencie wysyłania zapytania,onSuccess- zdarzenie, które wystąpi po zakończeniu (odebraniu odpowiedzi) zapytania,onStateChange- to zdarzenie występuje w momencie gdy zmieni się stan obiektuXMLHttpRequest,onFailure- zdarzenie występujące gdy zaistnieją błędy podczas wykonywania zapytania.
Właściwości obiektu klasy XHR
running- właściwość będąca wartością logiczną, która określa czy zapytanie jest aktualnie uruchomione (true) czy jest nieaktywne (false),-
response- jest to właściwość, która zawiera odpowiedź na dane zapytanie (w postaci obiektu). Dostęp do tej właściwości uzyskujemy w momencie wystąpienia zdarzeniaonSuccess. Odpowiedź może być zapisana jako tekst lub jako format XML.Jeśli chcemy uzyskać tekst zapiszemy:
this.response.text;gdy chcemy mieć zwrócony format XML zapiszemy:
this.response.xml;
Metody obiektu klasy XHR
Tworzenie obiektu klasy XHR przebiega w dobrze nam już znany sposób:
var nowy_obiekt = new XHR({opcje});
Wywołanie metod będzie w tym wypadku wyglądało następująco:
nowy_obiekt.metoda(argumenty);
Metody udostępniane przez obiekt XHR to:
- setHeader
- send
- cancel
setHeader
Metoda setHeader służy do dodawania nagłówka do wysyłanego zapytania. Nie zastępuje przy tym nagłówków dodanych za pomocą parametru headers.
Składnia tej metody:
obiekt_XHR.setHeader('nazwa_naglowka','tresc_naglowka');
Na przykład:
obiekt_XHR.setHeader('Content-type','application/x-www-form-urlencoded');
send
Metoda send to to na co chyba wszyscy czekali od początku tej części kursu ;) Służy ona oczywiście do wysyłania zapytań. Po tęgiej dawce teorii czas na praktykę ;) Składnia metody send wygląda następująco:
obiekt_XHR.send('url','dane');
Gdzie argument url to adres na jaki zostanie wysłane zapytanie, a argument dane to ciąg znaków zawierający zmienne zapisane za pomocą znanego nam już z pliku element.form.js zapisu jak uzyskiwaliśmy za pomocą metody toQueryString.
Zacznijmy może od małej "wizualizacji" różnicy pomiędzy zapytaniem synchronicznym i asynchronicznym.
Stwórzmy dwa obiekty klasy XHR, z czego jeden niech będzie wywoływał zapytanie synchroniczne:
var XHR1 = new XHR({async:false});
var XHR2 = new XHR();
Ponieważ warto by podczas rozpoczęcia wywołania pojawił się jakiś "sygnał", że ładowanie jest w toku, definiujemy dla obu obiektów znane nam już zdarzenie onRequest:
var XHR1 = new XHR({
async:false,
onRequest: function(){
$('load').setStyle('display','block');
}
});
var XHR2 = new XHR({
onRequest: function(){
$('load').setStyle('display','block');
}
});
Na koniec warto pokazać jakąś informację, że ładowanie danych się zakończyło i ukryć loader - wykorzystujemy tutaj zdarzenie onSuccess:
var XHR1 = new XHR({
async:false,
onRequest: function(){
$('load').setStyle('display','block');
},
onSuccess: function(){
$('load').setStyle('display','none');
alert('Dane zostały pobrane...');
}
});
var XHR2 = new XHR({
onRequest: function(){
$('load').setStyle('display','block');
},
onSuccess: function(){
$('load').setStyle('display','none');
alert('Dane zostały pobrane...');
}
});
Teraz tylko podpiąć zdarzenia onclick pod odpowiednie buttony i całość pod zdarzenie window.onload, w wyniku czego otrzymamy poniższy przykład:
No a co jeśli zamiast tekstu chcemy pobrać plik XML ? Wiadomo, że XML'a można użyć do eleganckiego obrazowania struktur danych. W kolejnym przykładzie pobierzemy plik XML następującej postaci:
<?xml version="1.0" encoding="UTF-8"?>
<comment>
<author>Jakiś nick</author>
<text>Lorem ipsum dolor sit amet...</text>
<date>2007-06-25</date>
</comment>
Oczywiście nie potrzebujemy wyświetlać na stronie całej treści pliku XML, a tylko interesującą nas zawartość. Jak to zrobić ? Najpierw w ogóle stwórzmy obiekt klasy XHR, który pobierze nam ten plik xml:
var XHR_object = new XHR();
Potrzebujemy wyświetlić jedynie nick, tekst i datę z danego pliku XML w odpowiednich divach zatem korzystamy z metody onSuccess i oczywiście odczytanych danych do których dostęp w postaci pliku XML otrzymamy za pomocą zapisu:
this.response.xml;
Dane z pliku XML odczytamy według tagów - skorzystamy z funkcji getElementsByTagName, a jako nazwę tagu podajemy nazwę interesującej nas pozycji w pliku XML.
Oczywiście trzeba pamiętać, że może istnieć kilka takich samych tagów, a sam zwracany obiekt to kolekcja elementów, zatem należy dodać po funkcji getElementsByTagName zapis item(0) by pobrać pierwszy element. Mamy już dostęp do elementu, ale nas interesuje węzeł tekstowy umieszczony w tym elemencie więc korzystamy z metody firstChild i właściwości data tegoż obiektu.
Finalny wzorzec kodu:
this.response.xml.getElementsByTagName('nazwa_tagu').item(0).firstChild.data;
Teraz tylko scalamy całość w odpowiedni ciąg znaków i można wyświetlić wynik zapytania:
var XHR_object = new XHR({
onSuccess: function(){
var dane = '<strong>Autor komentarza:</strong> ' +
this.response.xml.getElementsByTagName('author').item(0).firstChild.data
+ ' <br /><strong>Treść komentarza:</strong> ' +
this.response.xml.getElementsByTagName('text').item(0).firstChild.data
+ '<br /><strong>Data dodania komentarza:</strong> ' +
this.response.xml.getElementsByTagName('date').item(0).firstChild.data;
$('load').setHTML(dane);
}
});
Wszystko można obejrzeć w akcji w poniższym przykładzie:
Dodajmy teraz do tego kodu obsługę błędu połączenia za pomocą zdarzenia onFailure. Ogranicza się to do dodania dodatkowej opcji i funkcji, która się wykona gdy wystąpi błąd, ja zdecydowałem, że zamiast treści z pliku XML pojawi się komunikat:
var XHR_object = new XHR({
onFailure: function(){
$('load').setHTML('Wystąpił błąd podczas wykonywania zapytania !');
},
onSuccess: function(){
var dane = '<strong>Autor komentarza:</strong> ' +
this.response.xml.getElementsByTagName('author').item(0).firstChild.data
+ ' <br /><strong>Treść komentarza:</strong> ' +
this.response.xml.getElementsByTagName('text').item(0).firstChild.data
+ '<br /><strong>Data dodania komentarza:</strong> ' +
this.response.xml.getElementsByTagName('date').item(0).firstChild.data;
$('load').setHTML(dane);
}
});
Oczywiście przy wysyłaniu zapytania zmieniłem adres pliku na błędny, by zdarzenie mogło zaistnieć ;)
Do obejrzenia w poniższym przykładzie:
Zanim przejdziemy do ostatniej metody klasy XHR chciałbym jeszcze pokazać mały przykład tłumaczący działanie zdarzenia onStateChange. Po pierwsze i najważniejsze - w Mootools 1.111 w stosunku do Mootools 1.11 ... to zdarzenie przestało działać ;) W sumie nie wiem czy to błąd czy celowe działanie... Fakt faktem informacja o stanie obiektu XMLHttpRequest nie jest może jakaś strasznie ważna, ale mimo to ktoś może potrzebować tej funkcjonalności...
Zacznijmy może od tego jak zmienia się stan obiektu XMLHttpRequest.
Obiekt XMLHttpRequest posiada właściwość readyState, do której używając mootools i klasy XHR mamy dostęp poprzez zapis:
this.transport.readyState;
Wspomniana właściwość może przybierać 5 wartości od 0 do 4:
- 0 - niezainicjowane
- 1 - w trakcie pobierania
- 2 - pobrano
- 3 - interaktywne
- 4 - gotowe
No dobrze - wspominałem, że Mootools 1.111 "zgubił" obsługę tego zdarzenia, jak to naprawić ? Potrzebujemy dodać dosłownie 6 krótkich linijek kodu przed użyciem klasy XHR. Cofamy się teraz do czasów omawiania plików z grupy Class i przypominamy sobie metodę extend:
XHR = XHR.extend({
onStateChange: function() {
this.fireEvent('onStateChange', this.transport);
this.parent();
}
});
Po dodaniu tego kodu metoda onStateChange powinna pracować już poprawnie ;] Dodam jeszcze, ze gdybyśmy zastosowali metodę implement (wydawałoby się, że krótszy zapis) to owszem zdarzenie onStateChange zacznie działać, ale zdarzenie onSuccess przestaje występować ;]
Żeby nie być gołosłownym daję poniższy przykład by zaprezentować zdarzenie onStateChange w akcji :
Pora już przejść do ostatniej metody pliku XHR.js - metody cancel
cancel
Metoda cancel służy do przerwania wykonywania danego zapytania obiektu XHR. Jej składnia jest bardzo prosta:
obiekt_XHR.cancel();
Najlepiej będzie zaprezentować jej działanie na przykładzie pierwszym, gdzie wykonywane zapytanie trwa dość długo...
Warto jeszcze wiedzieć, że w momencie anulowania zapytanie, wywoływane jest zdarzenie onCancel. Zatem możemy w opcjach obiektu klasy XHR dodać opcję :
onCancel: function(){
// wykonywany kod
}
W poniższym przykładzie prezentuję użycie wyżej wymienionego zdarzenia i samej metody na zmodyfikowanym przykładzie pierwszym:
To by było na tyle, jeśli chodzi o plik XHR.js, w następnej części kursu przejdę do omawiania pliku Ajax.js, który rozszerza możliwości poznanej w tej części kursu klasy XHR.
Mootools 1.11 - Ajax.js do góry
Plik ajax.js zawiera klasę Ajax, która jest rozszerzeniem poznanej w poprzedniej części kursu klasy XHR. Klasa Ajax zawiera 4 metody i posiada dodatkowe zdarzenie... Poza tym mamy do dyspozycji wszystkie metody, opcje i zdarzenia klasy XHR.
Stworzenie nowego obiektu tej klasy wygląda następująco:
obiekt = new Ajax(adres,opcje);
Gdzie zmienna adres to najczęściej adres pod którym znajduje się skrypt przetwarzający otrzymane dane. Zmienna opcje to tak naprawdę cały obiekt, przechowujący parametry wywołania obiektu klasy Ajax. Oprócz opcji znanych z klasy XHR mamy jeszcze do dyspozycji 4 dodatkowe opcje:
data- opcja ta przechowuje dane jakie chcemy wysłać zapytaniem Ajax. Może być zarówno ciągiem znaków urlescape jak i obiektem gdzie rolę pól pełnią nazwy zmiennych. Trzecią możliwością jest umieszczenie w tym miejscu odwołania do elementu formularza.update- w tej opcji określamy element w którym pojawią się pobrane przez zapytanie dane.evalScripts- jeżeli pobieramy za pomocą zapytania kod JavaScript to po jego pobraniu możemy go wykonać wtedy gdy opcja ta ustawiona jest jakotrue. Domyślna wartość tej opcji tofalse.evalResponse- ta opcja ma podobne działanie do poprzedniej z tą różnicą, że wykonuje skrypty JS niezależnie od tego jakiego typu są pobierane dane... Domyślna wartość tej opcji tofalse.
Jak już wspominałem klasa Ajax udostępnia nam jedno dodatkowe zdarzenie - onComplete, które jest wywoływane w momencie zakończenia wykonywania zapytania. Jaka jest różnica pomiędzy zdarzeniem onComplete, zdarzeniem onSuccess znanym z klasy XHR ? Opcje takie jak update czy evalScripts i evalResponse zadziałają tylko w momencie wywoływania zdarzenia onComplete - stosując zdarzenie onSuccess stosowanie tych opcji mija się z celem.
Przejdźmy teraz do tego co nas najbardziej interesuje - do metod udostępnianych przez klasę Ajax.
Request
Metoda request to podstawa działania klasy Ajax - służy do wysłania zapytania zgodnie z podanymi parametrami.
Metodę tę możemy wywoływać na dwa sposoby:
obiekt = new Ajax(adres,opcje);
obiekt.request();
lub:
new Ajax(adres,opcje).request();
Pierwszy sposób jest lepszy gdy chcemy wykonywać dane zapytanie wielokrotnie, a drugie rozwiązanie jest przydatne w wypadku pojedynczych wywołań.
Wykonajmy zatem zapytanie Ajax, które pobierze tekst z danej strony i umieści go w odpowiednim elemencie. Żeby było ciekawiej to będziemy mogli pobrany tekst umieścić w wybranym przez nas elemencie. Ponieważ będziemy wykonywać kilka zapytań warto skorzystać z pierwszego sposobu zapisu by nie tworzyć kilku-kilkunastu instancji klasy Ajax - będziemy po prostu dynamicznie zmieniać wartość jednej z opcji naszego obiektu.
Ponieważ wszystko będzie najlepiej widoczne w przykładzie tu skupię się tylko na samym schemacie działania skryptu.
Stworzymy listę wyboru typu select, która pozwoli nam na wybór elementu w którym znajdzie się pobrany przez zapytanie tekst. Zapytanie zostanie wykonane w momencie kliknięcia przycisku. Zatem w tym momencie musimy zmienić wartość opcji update obiektu klasy Ajax (który utworzymy wraz ze zdarzeniem onload obiektu window).
Tworzymy obiekt klasy Ajax przy zdarzeniu onload :
window.addEvent("load",function(){
zapytanie = new Ajax('http://adres.pl');
});
Dodajemy zdarzenie onclick do przycisku, które pobiera wartość pola select i na tej podstawie zmienia opcję update obiektu klasy Ajax i wykonuje zapytanie:
window.addEvent("load",function(){
zapytanie = new Ajax('http://adres.pl');
$('btn').addEvent("click",function(){
zapytanie.options.update = $($('select').value);
zapytanie.request();
});
});
Powyższy kod w akcji prezentuję w poniższym przykładzie:
evalScripts
Metoda evalScripts służy do wykonywania skryptów zawartych w zwróconym przez zapytanie tekście, zgodnie z podanymi opcjami. Metody tej z reguły nie stosujemy ręcznie, ponieważ jest ona automatycznie wywoływana w momencie zaistnienia zdarzenia onComplete, gdy opcja evalResponse lub evalScripts ma wartość true.
Oczywiście można użyć tej metody ręcznie w momencie, gdy chcemy wykonać kody JS zawarte w wyniku zapytania w innym momencie działania naszego skryptu - czyli niekoniecznie zaraz po zakończeniu wykonania zapytania.
Przykładowo pobraliśmy kod skryptu i chcemy go wykonać na przykład w momencie kliknięcia jakiegoś elementu. Jeżeli pobraliśmy tylko kod skryptu to nie musimy zmieniać wartości opcji obiektu klasy Ajax - gdy chcemy skorzystać z właściwości opcji evalResponse to przed wywołaniem tej metody musimy zmienić wartość tej opcji na true (gdyby miała ona taką wartość od momentu inicjalizacji obiektu to nie moglibyśmy wykonać skryptu w dowolnym momencie, gdyż wykonałby się on wraz ze zdarzeniem onComplete obiektu).
Tworzymy zatem nowy obiekt klasy Ajax przy zdarzeniu onload:
window.addEvent("load",function(){
zapytanie = new Ajax('http://adres.pl');
});
Tworzymy też dwa przyciski - btn1 i btn2 z których pierwszy będzie wykonywał zapytanie, a drugi wykona zawarty w zapytaniu kod JS.
Zatem:
window.addEvent("load",function(){
zapytanie = new Ajax('http://adres.pl');
$('btn1').addEvent("click",function(){
zapytanie.request();
});
$('btn2').addEvent("click",function(){
zapytanie.evalScripts();
});
});
Jeszcze by się przydało dać jakiś sygnał, że zapytanie się wykonało - dodajemy do obiektu klasy Ajax zdarzenie onComplete:
window.addEvent("load",function(){
zapytanie = new Ajax('http://adres.pl',{onComplete: function(){alert('zapytanie zakończone...')}});
$('btn1').addEvent("click",function(){
zapytanie.request();
});
$('btn2').addEvent("click",function(){
zapytanie.evalScripts();
});
});
Oczywiście powyższy kod dotyczy sytuacji gdzie pobieramy czysty kod JS - z odpowiednim Content-Type lub kod zawarty pomiędzy znacznikami script:
To teraz wersja dla pobierania kodu JS ale bez Content-Type - to samo tylko z drobnymi modyfikacjami:
window.addEvent("load",function(){
zapytanie = new Ajax('http://adres.pl',{onComplete: function(){alert('zapytanie zakończone...')}});
$('btn1').addEvent("click",function(){
zapytanie.request();
});
$('btn2').addEvent("click",function(){
zapytanie.options.evalResponse = true;
zapytanie.evalScripts();
});
});
Jak widać zmieniła się tylko jedna linijka kodu w funkcji wykonywanej przy zdarzeniu onclick dla drugiego przycisku.
I oczywiście kod w działaniu:
getHeader
Metoda getHader służy do pobierania zawartości danego nagłówka odpowiedzi. Jako jej argument podajemy nazwę nagłówka - w wypadku gdy takowy nagłówek nie istnieje zwrócona zostaje wartość null.
Składnia tej metody wygląda następująco :
obiekt_ajax.getHeader('nazwa_naglowka');
Przykładowo gdybyśmy chcieli pobrać nagłówek Content-Type to zapiszemy:
obiekt_ajax.getHeader('Content-Type');
No i musimy pamiętać by umieścić kod pobierający zawartość nagłówka tak by wykonał się po wykonaniu zapytania - na przykład w zdarzeniu onComplete.
Przykład używający tej metody poniżej:
Object.toQueryString
Funkcja Object.toQueryString zamienia podany jako argument obiekt na ciąg znaków urlescape. Składnia tej funkcji:
Object.toQueryString(obiekt);
Na przykład:
Object.toQueryString({imie: "Tomek",nick: "Dziudek", www: "dziudek.jogger.pl"});
Powyższy kod zamieni podany obiekt na następujący ciąg znaków:
imie=Tomek&nick=Dziudek&www=dziudek.jogger.pl
Myślę, że przykład działania niepotrzebny bo podobne funkcje już poznawaliśmy i powinniście już wiedzieć kiedy ta funkcja się przyda ;)
send
Ostatnia metoda w pliku ajax.js - jest rozszerzeniem klasy Element, a co za tym idzie możemy ją łączyć z wybranym elementem - w tym wypadku formularzem. Jej działanie polega na wysyłaniu za pomocą Ajax danego formularza. Składnia funkcji:
$('formularz').send(opcje);
Opcje to w tym wypadku opcje klas Ajax i XHR - oczywiście poza parametrami typu adres czy dane, które są generowane automatycznie na podstawie zawartości formularza.
Przykładowo zapis:
$('form').send();
Spowoduje wysłanie formularza posiadającego identyfikator "form" pod adres zgodny z atrybutem action elementu form i z danymi automatycznie zamienionymi na format urlescape. Warto jeszcze dodać, że dane w tym wypadku są wysyłane metodą post.
I przykład korzystający z tej metody:
Może jest mało ciekawy, ale ma po prostu pokazać jak to mniej więcej działa ;]
To by było na tyle w temacie pliku ajax.js . W następnej części kursu zajmę się plikiem assets.js, który pozwala na dynamiczne dołączanie skryptów, styli i grafik do stron.
Mootools 1.11 - Assets.js do góry
Plik assets.js pozwala nam na dynamiczne dołączanie do naszych stron styli CSS, plików JS i grafik. Jest to bardzo przydatny plik. Zresztą zaraz sami się przekonacie jak bardzo pozwala on usprawnić działanie strony. W pliku tym zawarte są 4 metody klasy Asset - javascript, css, image, images. Myślę, że już same nazwy wiele mówią.
javascript
Metoda ta służy oczywiście do dynamicznego dołączania pliku JavaScript. Zastosowanie ? Wyobraźmy sobie sytuację w której mamy sporą aplikację online opartą o JavaScript - z reguły jest tak, że potrzeba tylko podstaw tej aplikacji, a większość pozostałych funkcji jest używanych okazjonalnie. Możemy więc sprawić, że ładowany będzie tylko rdzeń aplikacji z podstawowymi funkcjami (i tymi najczęściej używanymi), a reszta funkcji będzie doładowywana w razie potrzeby. Bardzo ładnie można taki proces zorganizować za pomocą klas i ich metod jakie udostępnia nam mootools - mam nadzieję, że czytelnicy kursu pamiętają jeszcze metody implement i $defined ? Jeżeli nie to polecam szybką powtórkę plików Core.js i Class.js ;)
Zanim przejdziemy do samego zastosowania najpierw podstawy użycia metody javascript. Jej składnia jest bardzo prosta:
new Asset.javascript('url',{opcje});
Zmienna url to oczywiście adres pliku JavaScript ,który chcemy dołączyć do naszej strony, a obiekt {opcje} to dodatkowe parametry wywołania tej metody. Obiekt ten zawierać może atrybuty dodawanego do dokumentu znacznika script - id, title - jak także w tym właśnie obiekcie definiujemy co się stanie po załadowaniu pliku - poprzez właściwość onload.
Przykładowo - gdybyśmy chcieli dołączyć do naszej strony plik on nazwie skrypt.js z katalogu skrypty i chcielibyśmy by znacznik script posiadał id new_script, a po załadowaniu tegoż pliku miałby się wyświetlić alert to zapiszemy:
new Asset.javascript("skrypty/skrypt.js",{
id: "new_script",
onload: function(){
alert("Skrypt został załadowany...");
}
});
Teraz możemy przejść do przykładu bardziej związanego z rzeczywistością - stworzymy klasę Aplikacja, która będzie podzielona na dwa pliki - w jednym (ładowanym wraz ze stroną) będzie się znajdowała metoda basic_function, a w drugim pliku, który będziemy chcieli dołączyć w odpowiednim momencie dynamicznie - metoda additional_function. Tworzymy zatem naszą klasę:
var Aplikacja = new Class({
basic_function: function(){
$('konsola').setHTML($('konsola').innerHTML+' To jest tekst dodany przez podstawową funkcję');
}
});
Jak widzimy metoda basic_function dodaje w danym elemencie tekst z informacją.
Oczywiście nie zapominamy stworzyć instancji tej klasy :
var App = new Aplikacja();
I podpinamy jej metodę pod zdarzenie onclick jednego z przycisków:
$('btn1').addEvent('click',function(){
App.basic_function();
});
Tworzymy też od razu powiązanie drugiej metody z drugim przyciskiem:
$('btn2').addEvent('click',function(){
App.additional_function();
});
No ale problem w tym, że metoda additional_function może jeszcze nie istnieć w momencie jej wywołania, bo plik, który ją zawiera mógł być jeszcze nie dodany do naszej strony. Zatem korzystamy z funkcji $defined :
$('btn2').addEvent('click',function(){
if($defined(App.additional_function)){
App.additional_function();
}
else{
alert('Ta funkcja nie została jeszcze dodana !');
}
});
I teraz już nie będzie problemów ;)
To teraz dynamiczne dołączanie pliku skrypt.js podpinamy pod trzeci przycisk:
$('btn3').addEvent('click',function(){
new Asset.javascript('plik.js',{onload: function(){alert('Plik załadowany...');}});
});
Jak widać po dodaniu pliku pojawi się alert ze stosowną informacją.
I sam plik.js:
Aplikacja.implement({
additional_function: function(){
$('konsola').setHTML($('konsola').innerHTML+' To jest tekst dodany przez dodatkową funkcję');
}
});
W powyższym kodzie korzystamy z metody implement, która rozszerza możliwości klasy bez tworzenia nowej.
Napisaliśmy sporo kodu to pora zobaczyć jak się to wszystko razem sprawuje :
Elegancko prawda ? Oczywiście życie jest zbyt brutalne by wszystko działało idealnie. Na IE ( oraz na Operze 8.5 ale jej można wybaczyć z racji wieku ;D ) nie pojawia się alert po załadowaniu pliku... Tak jakby IE nie obsługiwał zdarzenia onload dla tego pliku... Cóż pozostaje nam zrobić ? Najpierw należałoby się zastanowić czy zdarzenie onload dla ładowanego pliku jest nam potrzebne i jak duże ładujemy pliki - jeśli zdarzenie onload niekoniecznie jest nam potrzebne, a ładowane pliki ważą po kilka kB to warto sobie darować metodę, którą zaraz zaprezentuję - z gatunku "czołgiem" ;)
Mianowicie dodajemy przy zdarzeniu onclick trzeciego przycisku taki kod:
if(window.ie){
var timer = (function(){
if($defined(App.additional_function)){
$clear(timer);
alert('Plik został załadowany...');
}
}).delay(200);
}
Co robi powyższy kod ? Przede wszystkim sprawdza czy przeglądarka to IE, a jeśli tak to tworzy funkcję, która wykonuje się co 200ms aż do momentu w którym nie będzie zdefiniowana nowa funkcja (czyli plik JS będzie już załadowany). Oczywiście nie jest to tak dokładne jak zdarzenie onload dla pliku, ani nie jest może zbyt wydajne, ale cóż zrobić jeśli przeglądarka nie ma natywnej obsługi danego zdarzenia ?
css
Metoda css służy do dynamicznego dołączania plików styli CSS do naszej strony. Można jej użyć między innymi do dynamicznej zmiany stylu strony. Przykładowo spójrzmy na stronę grono.net - można zmieniać jej styl za pomocą przycisków w prawym górnym rogu. Wada ? Każde kliknięcie oznacza przeładowanie strony - nie muszę chyba mówić, że przejrzenie wszystkich dostępnych styli to po prostu masakra zwłaszcza, że sama strona grono.net nie jest lekka.
Składnia metody css jest podobna do poprzedniej metody:
new Asset.css('url', {opcje});
Różnica polega na tym, że w metodzie css nie występuje zdarzenie onload. Zmienna url to oczywiście adres do pliku CSS, jaki ma zostać załadowany, a {opcje} to dodatkowe atrybuty znacznika link.
Użycie tej metody jest banalne więc zaprezentuję od razu przykład, który opiera się na zdarzeniach onclick dowiązanych do przycisków, które to zdarzenia mają ładować poszczególne pliki ze stylami.
image
Kolejną metodą pliku assets.js jest image - służy ona do dynamicznego załadowania obrazka - jest to przydatne w skryptach typu lightbox, prostych galeriach itd.
Składnia tej metody jest bardzo podobna do składni poprzednich metod:
new Asset.image('url',{opcje});
Już chyba wiecie co znaczą obie zmienne, więc pora omówić różnice - metoda image posiada trzy zdarzenia - onload, onabort i onerror. Pierwsze z nich działa tak jak w metodzie javascript, drugie występuje w momencie przerwania ładowania pliku, a trzecie pojawia się gdy wystąpi błąd podczas jego ładowania (pliku).
Metoda image w odróżnieniu do metod css i javascript nie umieszcza gdzieś obrazka (wspomniane metody umieszczają odpowiednie znaczniki w sekcji head dokumentu), ale zwraca uchwyt do niego.
Tak więc umieszczenie pobranego obrazka spoczywa na nas.
Stwórzmy teraz jakiś prosty skrypt obrazujący użycie tej metody.
Przyjmijmy, że mamy miniaturkę jakiegoś obrazka i chcemy by po kliknięciu na nią pojawiał się jej oryginał.
Może od razu wytłumaczę jak działa cały poniższy kod:
var img = new Asset.image('img.png',{onload: function(){
img.injectInside('content');
img.setStyles({
'display':'none',
'opacity':0.25
});
$('image').setStyle('opacity',0.25);
$('image').effects().start({
'width': [320,800],
'height': [240,600],
});
(function(){
$('new_image').setStyle('display','block');
$('image').replaceWith($('new_image'));
$('new_image').setStyle('opacity',1);
}).delay(600);
},'id': 'new_image'});
Który jest przypisany do zdarzenia onclick obrazka.
Powyższy kod działa następująco:
- pobiera obrazek
- gdy obrazek zostanie pobrany wywoływane jest zdarzenie
onload - podczas zdarzenia
onloadpobrany obrazek jest umieszczany w dokumencie i zostaje ukryty poprzezdisplay: none. - rozmiar małego obrazka jest zwiększany do rozmiarów dużego obrazka,
- po animacji duży obrazek jest pokazywany i zamieniany z małym obrazkiem.
A całość w przykładzie wygląda następująco:
Swoją drogą nie wiem czemu, ale mam wrażenie, że zdarzenie onload dla obrazka pojawia się nie po załadowaniu tylko w momencie rozpoczęcia ładowania, a co za tym idzie należy wykonać podobne obejście jak w wypadku metody javascript tylko tym razem testowaną właściwością będzie właściwość complete danego obrazka - jeśli ma wartość true to obrazek jest załadowany.
images
Ostatnia metoda klasy Asset służy do ładowania kilku grafik - dzięki zdarzeniom onProgress i onComplete możemy nawet stworzyć wskaźnik postępu ładowania się kilku grafik. Składnia metody jest oczywiście bardzo podobna do pozostałych w tej klasie. Różnica polega na tym, że nie podajemy ścieżki do pliku jako ciąg znaków, ale jako tablicę ciągów znaków.
Składnia:
new Asset.images(['obrazek1', 'obrazek2'], {opcje});
Gdzie zmienne obrazek1 i obrazek2 to ścieżki do obrazków, a zmienna {opcje} to oczywiście parametry wywołania metody.
Zdarzenie onProgress występuje w momencie załadowania jednego z obrazków, a zdarzenie onComplete następuje po załadowaniu wszystkich grafik.
W przykładzie wykorzystamy 10 grafik - dla ułatwienia będą one ponumerowane od 1 do 10 - dzięki temu nie musimy też tworzyć ręcznie długiej tablicy - wystarczy poniższy zapis:
var img_tab = [];
for(var i = 0;i < 10;i++){
img_tab[i] = 'images/' + (i+1) + '.png';
}
do tego deklarujemy też zmienną amount oznaczającą ilość załadowanych obrazków:
var amount = 0;
Najważniejsza część kodu będzie przypisana do zdarzenia onclick przycisku:
$('btn').addEvent('click',function(){
new Asset.images(img_tab,{
onProgress: function(){
amount++;
$('progress_info_percent').setHTML(amount+'/10');
this.injectInside($('content'));
},
onComplete: function(){
$('progress_info_percent').setHTML('Grafiki pobrane...');
$('btn').remove();
}
});
});
Co wykonuje powyższy kod ? Jest definiowany nowy obiekt klasy Asset, który ma pobrać wszystkie grafiki z tablicy, którą wcześniej zapełniliśmy pętlą. Ponadto zdefiniowałem dwa wspomniane wcześniej zdarzenia - w wypadku zdarzenia onProgress zostanie zwiększona zmienna oznaczająca ilość załadowanych obrazków, następnie zostanie zmieniona zawartość diva przechowującego informację o ilość załadowanych grafik - no i na koniec zostanie do treści strony dołączony załadowany obrazek. W wypadku zdarzenia onComplete zmieniana jest treść komunikatu i usuwany jest przycisk do ładowania grafik.
Całość kodu prezentuje się następująco:
window.addEvent("load",function(){
var amount = 0;
var img_tab = [];
for(var i = 0;i < 10;i++){
img_tab[i] = 'images/' + (i+1) + '.png';
}
$('btn').addEvent('click',function(){
new Asset.images(img_tab,{
onProgress: function(){
amount++;
$('progress_info_percent').setHTML(amount+'/10');
this.injectInside($('content'));
},
onComplete: function(){
$('progress_info_percent').setHTML('Grafiki pobrane...');
$('btn').remove();
}
});
});
});
I powyższy kod w akcji:
I to by było na tyle, jeśli chodzi o plik assets.js - w następnej części kursu zajmiemy się przechowywaniem danych po stronie użytkownika - omówimy plik cookie.js .
Mootools 1.11 - Cookie.js do góry
W tej części kursu zajmiemy się ... ciasteczkami ;) Jak pewnie wiecie, ciasteczka to jedna z możliwości przechowywania danych użytkownika - przydają się przykładowo do przechowywania konfiguracji strony. Ponadto można je wykorzystać nie tylko w JavaScript, ale także na przykład w PHP - w ten sposób tworząc sobie pomost do przekazywania informacji pomiędzy językami server-side i client-side.
W pliku, który dziś omawiamy znajduje się klasa Cookie posiadająca 3 metody - set, get i remove. Pierwsza z nich odpowiada za stworzenie i zapis danych w ciasteczku. Druga służy do pobierania danych z danego ciasteczka, a trzecia usuwa ciasteczka.
set
Metoda set jest najbardziej rozbudowana ze wszystkich wymienionych metod - wymaga podania nazwy, wartości i opcji ciasteczka. Jej składnia wygląda następująco:
Cookie.set('nazwa', 'wartosc', {opcje});
Pierwsze dwie zmienne i ich przeznaczenie jest chyba jasne, jeśli chodzi o opcje to mamy do dyspozycji 4 właściwości:
domain- to domena do jakiej należy tworzone ciasteczko,path- ścieżka do jakiej należy ciasteczko - jeżeli chcemy by działało ono na wszystkich podstronach zapisujemy wartość tej opcji jako "/",duration- czas ważności ciasteczka - podajemy go jak liczbę dni,secure- wartość logiczna, która decyduje o tym czy ciasteczko ma być widoczne tylko podczas połączeń szyfrowanych (https).
To stwórzmy ciasteczko, które będzie przechowywało nick użytkownika i będzie dostępne w obrębie całej domeny przez 20 dni:
Cookie.set('nick','Dziudek'{path: "/",duration: 20});
Prawda, że proste w użytkowaniu ? Główny przykład pokażę później, a teraz przejdźmy do metody get...
get
Metoda get służy do pobierania wartości ciasteczek według podanej nazwy. Jej jedynym argumentem jest nazwa ciasteczka, jakie chcemy odczytać.
Składnia jest oczywiście banalna:
Cookie.get('nazwa');
Tak więc gdybyśmy chcieli pobrać wartość wspomnianego wcześniej ciasteczka, zapiszemy:
Cookie.get('nick');
Powyższy kod zwróci wartość 'Dziudek'.
Jak widzicie obsługa możliwości klasy Cookie jest bardzo łatwa, a ostatnia metoda - remove ma składnię prawie identyczną co metoda get.
remove
Ostatnia metoda klasy Cookie - remove służy oczywiście usuwaniu ciasteczek - robimy to pod względem składniowym podobnie jak w metodzie get:
Cookie.remove(cookie);
Różnica polega na tym, że zamiast nazwy musimy podać uchwyt co danego ciasteczka.
Zatem gdybyśmy chcieli usunąć wspomniane już dwa razy ciasteczko "nick" to zapiszemy:
var value = Cookie.get('nick');
var cookie = Cookie.set('nick',value);
Cookie.remove(cookie);
I tym sposobem mamy za sobą omówienie obsługi pliku Cookie.js - pora na przykład bardziej życiowy. Pamiętacie zapewne jeden z przykładów, który pojawił się przy pliku Assets.js, a służył do dynamicznej zmiany stylu strony ? Wszystko fajnie, ale co to za funkcjonalność, która nie pozwala zapamiętać ulubionego stylu użytkownika ? Teraz sobie już z tym poradzimy :)
Przyda się odrobina kodu PHP - zmiana stylu podczas ładowania strony wydaje mi się bezsensowna, a z pomocą PHP styl zmienimy już na etapie generowania kodu strony.
Przyjmijmy, że styl strony będzie przechowywany w ciasteczku o nazwie style, a jego wartością będzie liczba od 1 do 3. Ponieważ notacja nazw styli wygląda tak - style-x.css gdzie x to liczba od 1 do 3 pozwolę sobie w miejsce kodu:
wstawić kod:
A gdzieś przed tym jeszcze kod:
<?php
(isset($_COOKIE['style'])) ? $styl = $_COOKIE['style'] : $styl = 1;
?>
Który sprawi, że domyślnie załadowany zostanie ostatnio wybrany styl.
To teraz od strony server-side - do zdarzeń onclick przycisków wyboru styli musimy dodać zapis w cookie:
if(Cookie.get('style') !== 1){
Cookie.set('style',1,{duration: 365,path: "/"});
}
Oczywiście w kolejnych przyciskach zmieniamy 1 na 2 lub 3.
Pokazany powyżej kod sprawdzi czy aktualna wartość ciasteczka nie jest taka jak właśnie wybierana i jeżeli jest różnica (lub ciasteczka nie ma) to zostanie ustawiona nowa wybrana przez użytkownika wartość.
To jeszcze wypadałoby dodać przycisk, który będzie usuwał ciasteczko ze stylem:
$('btn4').addEvent('click',function(){
var value = Cookie.get('style');
var cookie = Cookie.set('style',value,{duration: 365,path: "/"});
Cookie.remove(cookie);
});
I działający przykład:
W następnej części kursu zajmiemy się formatem JSON, a dokładniej plikiem json.js
Mootools 1.11 - Json.js do góry
JSON to format wymiany danych, który moim zdaniem naprawdę warto poznać, zwłaszcza w kontekście bardziej zaawansowanego użycia skryptów JavaScript na stronie. Do czego możemy użyć tego formatu ? Możemy elegancko wymieniać złożone dane pomiędzy PHP, a JavaScript - oczywiście nie tylko PHP posiada wsparcie dla JSON - posiada je mnóstwo języków programowania co zresztą sami zobaczycie czytając podlinkowaną na początku wpisu stronę. Dzięki JSON uzyskujemy łatwy dostęp do poszczególnych elementów obiektu danych.
Mootools w pliku json.js posiada dwie metody składowe klasy Json - toString i evaluate - pierwsza zamienia obiekt JavaScript na ciąg znaków, a druga zamienia ciąg znaków na obiekt JavaScript. Dzięki temu możemy używać przechowywać złożone dane na przykład w cookies - zapisujemy obiekt konfiguracji jako ciąg znaków, który umieszczamy w ciasteczku, a następnie możemy tenże obiekt w dowolnym momencie odczytać.
Nie muszę chyba mówić, że zapis konfiguracji w postaci takiego obiektu:
{
"styl": 1,
"nick": 'Dziudek'
}
Jest łatwiejszy do ponownego użycia niż jakiś ciąg znaków, który można odczytać tylko na znany autorowi skryptu sposób ;)
Oczywiście format JSON to nie tylko obiekty - to także tablice i ciągi znaków - wszystkie informacje na ten temat zawarte są na wspomnianej już stronie o JSON.
Warto dodać, że PHP posiada identycznie działające metody jak mootools - json_decode i json_encode, różnica polega na tym, że po stronie PHP obiekty JavaScript są tablicami.
toString
Metoda toString jak już wspomniałem zamienia obiekt na ciąg znaków. Składnia tej metody jest oczywiście nieskomplikowana, gdyż pobiera ona tylko jeden argument - obiekt do przetworzenia:
Json.toString(obiekt);
Powyższy zapis zwróci nam nasz obiekt zamieniony na ciąg znaków, przykładowo:
Json.toString({styl: 'red', nick: 'Dziudek'}});
Ten zapis zwróci nam taki oto ciąg znaków:
'{"styl":"red","nick":"Dziudek"}'
I taki ciąg możemy już śmiało zapisywać w ciasteczku lub wysyłać jakiemuś skryptowi PHP do przetworzenia...
To pora na jakiś mały przykład - wykorzystamy przy tym naszą wiedzę o pliku cookie.js (poprzednia część kursu).
Stworzymy skrypt, który zapisze kilka danych z prostego formularza w ciasteczku. Przyjmijmy, że te dane to preferowana kolorystyka strony nick użytkownika i krótka notatka.
Całość będzie polegała na odczytaniu wartości poszczególnych pól formularza i zapisaniu ich w obiekcie. Następnie obiekt ten zostanie zamieniony na ciąg znaków i zapisany w cookie.
Do tego dołożymy przycisk, który pokaże nam zawartość ciasteczka, ale na razie bez dekodowania jej do postaci pierwotnej.
Tworzymy obiekt, w którym to wszystko zapiszemy:
var dane = {
styl: '',
nick: '',
notatka: ''
}
Następnie tworzymy zdarzenie onclick przycisku wykonującego całą operację:
$('btn-save').addEvent('click',function(){
dane.styl = $('form-styl').getValue();
dane.nick = $('form-nick').getValue();
dane_notatka = $('form-notatka').getValue();
Cookie.set('dane',Json.toString(dane),{duration: 10,path: "/"});
});
I do tego przycisk, który wczyta nam zawartość ciasteczka do wybranego diva:
$('btn-read').addEvent('click',function(){
$('cookie-content').setHTML(Cookie.get('dane'));
});
I cały powyższy kod w akcji:
evaluate
Metoda evaluate ma działanie odwrotne do metody toString - zamienia ciąg znaków w obiekt formatu JSON. Pobiera dwa argumenty - ciąg znaków do przetworzenia i parametr decydujący o tym czy ma być sprawdzana poprawność podanego ciągu znaków.
W wypadku gdy pierwszy argument nie jest ciągiem znaków, bądź jest niepoprawnym zapisem formatu JSON i drugi argument jest ustawiony jako true to zwrócona zostanie wartość false.
Składnia metody evaluate:
Json.evaluate('{obiekt}',secure);
Rozbudujmy zatem nasz przykład od kod, który odczyta elegancko zawartości ciasteczka.
Zmienimy jedynie kod funkcji przypisanej jako zdarzenie onclick przycisku btn-read:
$('btn-read').addEvent('click',function(){ var dane = Json.evaluate(Cookie.get('dane'));
var string = '<strong>Styl:</strong>' + dane.styl + '<br />';
string += '<strong>Nick:</strong>' + dane.nick + '<br />';
string += '<strong>Notatka:</strong> ' + dane.notatka + '<br />';
$('cookie-content').setHTML(string);
});
Poniżej zmieniony kod:
Jak widać plik json.js mimo zaledwie dwóch metod jakie zawiera, otwiera przed nami zupełnie nowe możliwości przekazywania, przechowywania i pobierania danych.
W następnej części kursu omówimy plik Json.Remote.js - ostatni z plików grupy Remote.
Mootools 1.11 - Json.Remote.js do góry
Plik json.remote.js to ostatni składnik grupy Remote. Jest on rozszerzeniem klasy XHR i służy do wymiany danych w formacie JSON za pomocą obiektu XMLHttpRequest.
Posiada on jedną metodę - send oraz jedno własne zdarzenie - onComplete.
Pełna składnia wygląda następująco:
var obiekt = new Json.Remote("adres",{
onComplete: function(json){
// w tej funkcji otrzymujemy uchwyt do pobranego obiektu JSON
// na przykład json.nick
}
}).send({json});
Składnia może się wydać skomplikowana, ale zaraz wszystko po kolei wytłumaczę ;)
Zmienna adres to oczywiście lokalizacja pliku do którego wyślemy obiekt JSON zadeklarowany jako argument metody send. Zdarzenie onComplete definiuje funkcję, która wykona się po zakończeniu zapytania. Może ona pobierać za argument zwrócony przez skrypt obiekt JSON i w ten sposób otrzymujemy uchwyt do tego obiektu w ciele tej funkcji, zatem możemy się później łatwo odwoływać do właściwości tego obiektu.
Klasa Json.Remote działa w ten sposób, że zamienia podany jako argument metody send obiekt na ciąg znaków i jednocześnie od razu zamienia zwrócony przez skrypt ciąg znaków na obiekt JSON.
Przy wywołaniu możemy zdefiniować w opcjach obok zdarzenia onComplete, także parametr secure, którego działanie już znamy po omówieniu metody evaluate klasy Json.
Pora na przykład użycia tej klasy.
Ponieważ nie mam za bardzo gdzie umieścić przykładu ze skryptem odczytującym JSON (Wymaga PHP 5.2.0, a pisanie skryptu, który by to odczytał według mnie mija się z celem dla tak prostego przykładu) więc skupimy się na pobraniu danych w formacie JSON i ich łatwemu odczytaniu.
Pobierzemy z testowej strony następujący obiekt:
{
nazwaPliku: "json.txt",
autorPliku: "Dziudek",
domena: "dziudek.ovh.org"
}
Oczywiście na stronie będzie on widniał w postaci:
{"nazwaPliku": "json.txt","autorPliku": "Dziudek","domena": "dziudek.ovh.org"}
Odczytana zawartość zostanie umieszczona w odpowiednim elemencie strony z przykładem.
Tworzymy obiekt klasy Json.Remote:
new Json.Remote("json.txt").send();
Nasz uchwyt do pobranego obiektu nazwiemy danePliku - tworzymy szkielet zdarzenia onComplete:
new Json.Remote("json.txt",{
onComplete: function(danePliku){
var string = '<strong>Nazwa pliku:</strong> ' + danePliku.nazwaPliku + '<br />';
string += '<strong>Autor pliku:</strong> ' + danePliku.autorPliku + '<br />';
string += '<strong>Domena:</strong> ' + danePliku.domena + '<br />';
$('console').setHTML(string);
}
}).send();
Ważna uwaga - niezależnie od tego czy wysyłamy jakieś dane w formacie JSON, czy tylko zamierzamy je pobrać MUSIMY dodać metodę send - dopiero wtedy będzie można odczytać dane - przy inicjalizacji obiektu jest tylko tworzony obiekt klasy XHR, ale NIE jest wysyłane od razu zapytanie...
Na koniec podpinamy nasz kod pod zdarzenie onclick przycisku i całość umieszczamy jako kod zdarzenia onload (lub DOMContentLoaded jak kto woli) obiektu window.
Działający przykład poniżej:
Jak widać klasa Json.Remote znacząco upraszcza proces wysyłania i pobierania danych zapisanych w formacie JSON. Tą częścią kursu zakończyliśmy omawianie sekcji Remote - w następnej części kursu zajmiemy się efektami, krótko mówiąc będziemy co nieco animowali ;)
Mootools 1.11 - Fx.Base.js do góry
Od omówienia pliku fx.base.js zaczynam opis sekcji Effects. Sekcja ta zawiera 8 plików - wszystkie z prefiksem "Fx" - zawierają one metody do animowania elementów - zarówno pojedynczych jak i kilku naraz.
Na czym w ogóle polegają animacje z użyciem mootools ? Na płynnej zmianie określonych właściwości CSS danego elementu. Ważne jest tutaj słowo "płynnej", ponieważ same właściwości CSS potrafimy już zmieniać, ale tylko skokowo - teraz będziemy mogli trochę bardziej "ożywić" te zmiany wyglądu...
Klasa Fx.Base to podstawa animacji w mootools - opierają się na niej pozostałe pliki z sekcji Effects. Sama klasa posiada 3 metody, 5 opcji i własne zdarzenia. Oczywiście dla nas najważniejsze są metody i 2 opcje, które mają kluczowy wpływ na wygląd animacji. Opis klasy Fx.Base będzie się składał tylko z części teoretycznej, ponieważ jest ona tylko rdzeniem silnika animacji w mootools - same animacje można tworzyć dopiero z użyciem klas Fx.Style, Fx.Styles itd. Niemniej jednak teoretyczne podstawy są niezbędne do używania wspomnianych klas.
Zatem w tej części kursu zapoznamy się pokrótce z opcjami, zdarzeniami i metodami klasy Fx.Base. Znajdą one zastosowanie w kolejnych częściach kursu...
Opcje klasy Fx.Base:
transition- opcja ta decyduje o wyglądzie animacji. Mootools posiada kilkadziesiąt wzorów według, których przebiegają animacje - wszystkie znajdują się w plikuFx.Transitions.duration- w tej opcji podajemy czas trwania animacji wms. Domyślny czas trwania animacji to 500ms.unit- jednostka używana w animacji - domyślnie jest to 'px', ale możemy także używać jednostek 'em' i '%'.wait- wartość logiczna określająca czy dana animacja może być uruchomiona przed zakończeniem poprzedniej opartej o ten sam obiekt.fps- ilość klatek na sekundę w animacji - im mniejsza wartość tym animacja jest mniej płynna. Domyślna wartość to 50.
Zdarzenia klasy Fx.Base:
onStart- zdarzenie występujące przy rozpoczęciu animacji (metodastart).onComplete- zdarzenie występujące po zakończeniu animacji.onCancel- zdarzenie, które ma miejsce przy zatrzymaniu animacji w trakcie jej trwania - metodąstop.
Metody klasy Fx.Base:
set- metoda ta pobiera jeden argument - wartość jaka ma być ustawiona dla danej właściwości stylu elementu, bez animacji.start- ta metoda służy do uruchomienia animacji i zmiany wartości danej właściwości stylu w podanym jako atrybuty tej metody przedziale. Pierwszy argument to oczywiście wartość początkowa, a drugi argument to końcowa wartość danej właściwości stylu. Wraz z użyciem tej metody występuje zdarzenieonStart, a po zakończeniu działania zdarzenieonComplete(o ile wcześniej nie zostanie użyta metodastop).stop- ostania metoda klasyFx.Basesłużąca do zatrzymywania animacji. Wraz z jej użyciem pojawia się zdarzenieonCancel.
Powyższe wiadomości tak jak już pisałem, znajdą zastosowanie przy omawianiu plików Fx.Style, Fx.Styles itd.
Mootools 1.11 - Fx.Transitions.js do góry
To ostatni wpis o treści teoretycznej przy omawianiu grupy Effects - celowo piszę go przed wpisami o plikach fx.style.js i fx.styles.js gdyż chcę abyśmy mieli całą teorię za sobą :)
Mootools udostępnia nam kilkadziesiąt rodzajów animacji - pisałem już przy pliku fx.base.js, że rodzaj animacji ustalamy za pomocą parametru transition.
Jako rodzaj animacji w Mootools 1.11(1) podajemy następujący ciąg znaków:
Fx.Transitions.rodzaj.typ
Gdzie rodzaj to jedna z poniższych wartości:
- linear
- Quad
- Cubic
- Quart
- Quint
- Pow
- Expo
- Circ
- Sine
- Back
- Bounce
- Elastic
A typ przyjmuję jedną z trzech poniższych wartości:
- easeIn
- easeOut
- easeInOut
Przy czym rodzaj linear nie ma żadnej z trzech powyższych opcji (gdyż nie mają one w jego przypadku zastosowania). Tak więc w wypadku tego rodzaju animacji zapis wygląda następująco:
Fx.Transitions.linear
Dodatkową nowością w Mootools 1.11(1) jest fakt iż możemy tworzyć wspomniane rodzaje animacji z własnymi parametrami - zmieniając przy tym trochę ich wygląd. Tą funkcjonalność obsługują trzy rodzaje animacji - Pow, Back i Elastic. W ich wypadku możemy tworzyć własny styl animacji w następujący sposób:
var moja_animacja = new Fx.Transitions(Fx.Transitions.rodzaj, liczba);
Gdzie zmienna rodzaj to oczywiście Pow, Back lub Elastic, a zmienna liczba to jakaś liczba - w wypadku animacji Pow będzie to potęga do jakiej zostanie podniesiona liczba przetwarzana przez funkcję (przy czym liczby 1,2,3,4,5,6 odpadają bo uzyskamy jedną z dostępnych animacji). W wypadku animacji Elastic i Back podana liczba będzie wpływała na "wyrazistość" animacji. Moim zdaniem najlepiej potestować tą funkcjonalność samemu :)
Tym razem przykładu mojego nie będzie zamiast tego polecam po pierwsze analizę wykresów na tej stronie oraz zabawę z przykładem pochodzącym z sekcji demos - dla niezorientowanych dodam, że duration to czas trwania animacji, a samą animację można zobaczyć przenosząc i puszczając czerwony kwadracik lub klikając na szarym obszarze.
W następnej części kursu skorzystamy wreszcie z opisanych w ostatnich częściach kursu informacji i stworzymy własne animacje omawiając przy tym plik fx.style.js :)
Mootools 1.11 - Fx.Style.js do góry
W tej części kursu wreszcie spożytkujemy zdobyte wcześniej wiadomości z zakresu tworzenia animacji z użyciem mootools :) Zaczniemy od rzeczy prostych, a skończymy na stworzeniu menu, które dopieścimy w dwóch kolejnych częściach kursu.
Podstawę pliku fx.style.js stanowi klasa Fx.Style - służy ona do płynnej zmiany wartości jednej z właściwości CSS danego elementu. Posiada ona trzy metody:
- hide
- set
- start
Po zapoznaniu się z klasą Fx.Base myślę, że działania dwóch ostatnich metod nie muszę tłumaczyć, natomiast metoda hide oznacza to samo co użycie metody set z podanym argumentem o wartości 0.
Tworzenie efektu
Stworzenie efektu jest bardzo proste - polega oczywiście na stworzeniu obiektu klasy Fx.Style:
var efekt = new Fx.Style(element,właściwość,{opcje});
Gdzie zmienna element to oczywiście element drzewa dokumentu do którego odnosi się dany efekt - uwaga musi to być pojedynczy element ! Zmienna właściwość to zmieniana właściwość CSS w czasie trwania efektu, a obiekt {opcje} zawiera pozostałe parametry znane nam już z klasy Fx.Base - nas najbardziej niedługo będą interesowały opcje transition i duration, ale o tym niedługo... Najpierw stworzymy najprostszy efekt - bez podawania żadnych dodatkowych parametrów.
Powiedzmy, że chcielibyśmy zmienić grubość obramowania danego elementu z 2 na 10 pikseli. Stworzymy dwa przyciski - jeden do zwiększania grubości obramowania, a drugi do jej zmniejszania.
Tworzymy nasz efekt:
var efekt = new Fx.Style('div_testowy','border-width');
Do naszych przycisków przypisujemy zdarzenia onclick wraz z odpowiednim wywołaniem metody start naszego efektu:
$('powiekszanie').addEvent('click',function(){
efekt.start(2,10);
});
$('pomniejszanie').addEvent('click',function(){
efekt.start(10,2);
});
Całość umieszczamy w zdarzeniu onload obiektu window (lub DOMContentLoaded jak kto woli) i już mamy gotowy nasz pierwszy przykład z prostym efektem:
Do naszego poprzedniego przykładu dodajmy teraz jeszcze dwa przyciski wykorzystujące metody hide i set - pierwszy z nich ukryje całkowicie obramowanie elementu, a drugi przywróci je do stanu początkowego (2 piksele grubości).
Kod zdarzeń onclick tych przycisków:
$('ukrywanie').addEvent('click',function(){
efekt.hide();
});
$('przywracanie').addEvent('click',function(){
efekt.set(2);
});
Jak widzimy użycie tych metod (hide i set) jest bardzo proste.
I gotowy przykład:
W kolejnym przykładzie zajmiemy się opcjami duration i transition. Stworzymy animację diva, który będzie można przemieszczać z lewej na prawą stronę dokumentu i odwrotnie z efektem bounce i różną prędkością.
Animacja będzie polegała na zmianie wartości właściwości margin-left. Stwórzmy nasz efekt zmiany położenia diva:
var efekt = new Fx.Style('div_testowy','margin-left',{
duration: 1000,
transition: Fx.Transitions.Bounce.easeOut
});
Powyższy kod spowoduje stworzenie efektu, który będzie trwał jedną sekundę i będzie to animacja rodzaju Bounce...
Dodajemy teraz zdarzenia onclick do przycisków przesuwających diva:
$('wprawo').addEvent('click',function(){
efekt.start(0,500);
});
$('wlewo').addEvent('click',function(){
efekt.start(500,0);
});
Do tego dołóżmy trzy przyciski - do trzykrotnego przyśpieszenia i spowolnienia animacji oraz do ustawienia standardowej prędkości animacji. Dostęp do opcji duration uzyskujemy poprzez zapis:
efekt.options.duration;
$('szybko').addEvent('click',function(){
efekt.options.duration = 333;
});
$('normalnie').addEvent('click',function(){
efekt.options.duration = 1000;
});
$('wolno').addEvent('click',function(){
efekt.options.duration = 3000;
});
Oczywiście całość umieszczamy w zdarzeniu onload obiektu window i już możemy testować kolejny przykład:
Pora skorzystać ze zdarzeń jakie daje nam do dyspozycji klasa Fx.Base (a zatem i klasa Fx.Style) - do naszego poprzedniego przykładu dodamy jeszcze jeden przycisk - stop - będzie on zatrzymywał animację, a po 2 sekundach przywracał ją do początkowego stanu. Poza tym na czas trwania animacji zablokujemy przyciski do uruchamiania i zmiany parametrów animacji.
Zacznijmy od blokowania i odblokowywania przycisków do uruchamiania animacji i zmiany jej prędkości - musimy je zablokować przy wystąpieniu zdarzenia onStart i odblokować przy wystąpieniu zdarzenia onComplete - później przyda się też odblokowywanie przy zdarzeniu onCancel, ale to opiszę dokładniej przy opisie przycisku zatrzymywania animacji - będzie on wykorzystywał metodę stop:
$('stop').addEvent('click',function(){
efekt.stop();
});
Dodajemy zatem dwa nowe parametry do naszego efektu:
var efekt = new Fx.Style('div_testowy','margin-left',{
duration: 1000,
transition: Fx.Transitions.Bounce.easeOut,
onStart: function(){
$$('#content button').each(function(element,index){
if(index != 2){
element.setProperty('disabled','disabled');
}
else{
element.removeProperty('disabled');
}
});
},
onComplete: function(){
$$('#content button').each(function(element,index){
if(index == 2){
element.setProperty('disabled','disabled');
}
else{
element.removeProperty('disabled');
}
});
}
});
Jak widać selekcjonujemy wszystkie przyciski z diva content i nadajemy im atrybut disabled - nie dotyczy to trzeciego przycisku, który od początku jest zablokowany i odblokowywany w tym momencie. Zdarzenie onComplete daje odwrotny rezultat - usuwa atrybut disabled z wszystkich przycisków poza trzecim, któremu ten atrybut dodaje...
Teraz pora dodać zdarzenie onCancel - ma ono po 2 sekundach przywracać div na pierwotne miejsce i odblokowywać przyciski - najprościej zrobić to za pomocą metod set i fireEvent:
onCancel: function(){
(function(){
efekt.set(0);
efekt.fireEvent('onComplete');
}).delay(2000);
}
I to już właściwie wszystko co musieliśmy zrobić - pora przetestować stworzony kod:
Na koniec tej części kursu rozpoczniemy tworzenie menu, które udoskonalimy w dwóch kolejnych częściach kursu - będzie to menu w którym po najechaniu na daną opcję będzie się zmieniał kolor jej tła, a po odjechaniu kursora tło będzie powracało do pierwotnego stanu - poza zmianą koloru tła, zmianie będzie ulegał też kolor czcionki tak by była ona czytelna na nowym tle.
Musimy zatem stworzyć dwa efekty - jeden od zmiany koloru tła, a drugi od zmiany koloru czcionki - dla ułatwienia sprawy kolory będą się zmieniały od białego do czarnego i na odwrót tak by na czarnym tle była biała czcionka (i na odwrót).
Menu oparte będzie o listę nieuporządkowaną posiadającą id "menu". Dla każdego elementu listy musimy stworzyć po dwa efekty i dodać po dwa zdarzenia - mouseenter i mouseleave. Ponieważ elementów listy jest kilka, najlepiej cała tą operację wykonać w pętli. Selekcjonujemy wszystkie elementy naszej listy:
$$("#menu li");
Wykorzystujemy funkcję each z podanym argumentem element:
$$("#menu li").each(function(element){});
W ciele funkcji umieszczamy kody naszych dwóch efektów:
var efekt1 = new Fx.Style(element,'background-color', {duration:600, wait:false});
var efekt2 = new Fx.Style($E('a',element),'color', {duration:600, wait:false});
Warto zwrócić uwagę na dwie rzeczy - animacja nie może czekać na zakończenie jej poprzedniej instancji, stąd:
wait:false;
Dodatkowo przy ustalaniu koloru tekstu nie możemy odwoływać się do elementu listy, ale do linka w nim umieszczonego - dlatego zamiast identyfikatora elementu umieszczamy funkcję selekcjonującą - tak samo w pierwszym efekcie umieszczamy uchwyt do elementu, a nie jego id - możemy tak zrobić bo funkcja $ , która selekcjonuje element do animacji przyjmuje za argument nie tylko ciągi znaków, ale i uchwyty do elementów czy inne funkcje.
No i na koniec tworzymy kody zdarzeń dla elementów listy:
element.addEvent('mouseenter', function(){
efekt1.start('#FFF','#000');
efekt2.start('#000','#FFF');
});
element.addEvent('mouseleave', function(){
efekt1.start('#000','#FFF');
efekt2.start('#FFF','#000');
});
Całość w akcji można obejrzeć w poniższym przykładzie:
Alternatywny sposób tworzenia efektów
Już kończąc wspomnę jeszcze krótko o alternatywnym sposobie tworzenia efektów. Do tej pory poznaliśmy sposób w którym jednym z argumentów jest element do którego odnosi się dany efekt, ale nie zapomniano też o klasie Element i wzbogacono ją o metodę effect. Tworzenie efektów z jej użyciem przebiega podobnie z tą różnicą, że metoda effect pobiera dwa argumenty - zmienianą w trakcie animacji właściwość i opcje animacji, a sama jest przypisana do elementu jakiego dotyczyć ma animacja:
$('element').effect('właściwość',{opcje});
Z powyższym sposobem zapisu spotkamy się ponownie przy omawianiu następnej części kursu, dotyczącej pliku fx.styles.js .
Mootools 1.11 - Fx.Styles.js do góry
W kolejnej części kursu mootools zapoznamy się z plikiem fx.styles.js - ma on podobne zadanie jak plik fx.style.js - służy do animowania elementów. Różnica polega na tym, że za pomocą klasy Fx.Styles tworzymy efekty oparte o zmianę kilku właściwości CSS naraz. W tej części kursu zajmiemy się realizacją dwóch zadań - dodania jeszcze jednego efektu do menu z poprzedniej części kursu oraz stworzymy menu a'la fisheye znane z MacOS :)
Najpierw jednak mała dawka teorii. Klasa Fx.Styles zawiera tylko jedną metodę - start, jednak jej budowa znacznie odbiega od składni metody start w klasie Fx.Style. Argumentem tej metody jest obiekt złożony z par :
"nazwa_właściwości" : "wartość_właściwości"
Przy czym jest to uproszczony zapis, który spowoduje zmianę danej właściwości ze stanu początkowego do danej wartości. Możemy też określić początek przedziału. W tym wypadku składnia pary wygląda następująco:
"nazwa_właściwosci" : ["wartość_początkowa","wartość_końcowa"]
Sam efekt tworzymy następująco:
var efekty = new Fx.Styles("element",{opcje});
Jak widać w porównaniu do klasy Fx.Style znikł nam parametr określający zmienianą właściwość. Został on zastąpiony wspomnianymi parami i występuje przy metodzie start:
efekty.start({
"właściwość1" : ['2px','10px'],
"właściwość2" : ['#FFF','#000']
});
Widzimy więc że składnia metody start się lekko skomplikowała, ale możemy przecież stosować prostszy zapis par właściwość-wartość.
Podobnie jak plik fx.style.js, także plik fx.styles.js posiada alternatywny sposób tworzenia animacji poprzez klasę Element - używana jest do tego celu metoda effects. Jej składnia wygląda następująco:
$('element').effects({opcje});
Użycie polega oczywiście na użyciu metody start. Na przykład:
var efekty = $('element').effects({opcje});
efekty.start({
"właściwość1" : ['2px','10px'],
"właściwość2" : ['#FFF','#000']
});
Myślę, że całość nie jest trudna do zrozumienia, bo zmiany w stosunku do klasy Fx.Style są dość logiczne. Przejdźmy do praktyki :)
Pamiętacie zapewne menu z poprzedniej części kursu. Miało ono następujący kod JavaScript:
window.addEvent("domready",function(){
$$("#menu li").each(function(element){
var efekt1 = new Fx.Style(element,'background-color', {duration:600, wait:false});
var efekt2 = new Fx.Style($E('a',element),'color', {duration:600, wait:false});
element.addEvent('mouseenter', function(){
efekt1.start('#FFF','#000');
efekt2.start('#000','#FFF');
});
element.addEvent('mouseleave', function(){
efekt1.start('#000','#FFF');
efekt2.start('#FFF','#000');
});
});
});
Teraz chciałbym dodać do niego jeszcze jeden efekt - przesuwanie się w górę linka po najechaniu na opcję menu i jego opadanie po odjechaniu kursora z obszaru opcji. Chodzi tutaj o zmianę dwóch wartości - padding-top i padding-bottom. Ponieważ zmiany tych wartości dotyczą elementu listy więc odnoszą się do tego samego elementu co efekt przypisany zmiennej efekt1. Z użyciem klasy Fx.Styles stworzymy zmianę trzech wartości naraz - wspomnianych paddingów i koloru tła.
Przy okazji pozwolę sobie zmienić też nazewnictwo - zmiana elementu listy otrzyma nazwę efekty, a zmiana linka dostanie nazwę efekt.
Zmieniamy zatem kod :
var efekty = new Fx.Styles(element,{duration:600, wait:false});
var efekt = new Fx.Style($E('a',element),'color', {duration:600, wait:false});
Dzięki temu zyskujemy możliwość zastosowania zmian wielu właściwości jednym efektem przy wystąpieniu zdarzeń mouseenter i mouseleave:
element.addEvent('mouseenter', function(){
efekty.start({
'background-color': ['#FFF','#000'],
'padding-top': [12,4],
'padding-bottom': [12,20]
});
efekt.start('#000','#FFF');
});
element.addEvent('mouseleave', function(){
efekty.start({
'background-color': ['#000','#FFF'],
'padding-top': [4,12],
'padding-bottom': [20,12]
});
efekt.start('#FFF','#000');
});
jak widzicie zastosowałem dłuższy zapis par właściwość-wartości, a zmiana wysokości będzie wynosiła 8 pikseli.
I po tych zmianach możemy obejrzeć nasze ulepszone menu:
Myślę, że wygląda to już całkiem ciekawie. Może kolory nie są idealne, ale dobrałem kontrastowe by widać było wyraźnie "smugę" przy przesuwaniu kursora nad kolejnymi opcjami menu :)
Pora na coś bardziej skomplikowanego, ale opartego na podobnej zasadzie działania. Stworzymy sobie menu typu fisheye - dla niewtajemniczonych podpowiem, że chodzi o powiększanie się danego obrazka do określonego rozmiaru po najechaniu nań kursorem. Dodatkowo powiększeniu (choć mniejszemu) ulegają też sąsiednie obrazki - w naszym wypadku powiększać będziemy obrazek nad którym znajduje się kursor i dwa sąsiednie obrazki.
Zacznijmy od podstaw - aby uzyskać ładny efekt potrzebujemy zmieniać tak rozmiar obrazka by powiększał się on rozszerzając w dół - dlatego trzeba ustalić sztywny rozmiar elementu listy nieuporządkowanej - w naszym wypadku 128x128px. Dodatkowo trzeba ustawić podstawowy rozmiar obrazka - 48x48px. Przy powiększaniu obrazek będzie zmieniał rozmiar do 128x128px, a dwa sąsiednie obrazki do rozmiaru 72x72px.
Działanie skryptu będzie opierało się w sporym stopniu na tablicy przechowującej efekty - przy dodawaniu za pomocą funkcji forEach zdarzeń, każde zdarzenie zostanie umieszczone także w tablicy efekty. Dlaczego ? Żeby móc łatwo wywołać efekt przypisany do poprzedniego i następnego z kolei elementu (w odniesieniu do elementu nad którym aktualnie znajduje się kursor).
Tworzymy zatem tablicę, która przechowa nasze uporządkowane efekty:
var efekty = [];
Podstawa animacji będzie oparta na takiej samej metodzie jak w poprzednim przykładzie:
$$("#menu li").each(function(element,index){
// tutaj będą dodawane eventy
}
Każdy obieg funkcji each będzie się składał z dodania dwóch zdarzeń - mouseenter i mouseleave oraz z umieszczenia efektu w tablicy.
Efekt przypisany do danego elementu listy umieszczamy w tablicy następująco:
efekty[index] = new Fx.Styles($E('img',element),{duration:400, wait:false});
Jak widać korzystamy przy tym z automatycznie generowanej zmiennej index i z funkcji selekcji elementu - gdybyśmy od razu odwołali się do elementu img zamiast elementu li to bardzo ograniczylibyśmy obszar nad którym trzeba umieścić kursor by uruchomić animację.
Po dodaniu efektu do tablicy czas na zdarzenie mouseenter:
element.addEvent('mouseenter', function(){
efekty[index].start({
'width': 128,
'height': 128
});
if(efekty[index-1]){
efekty[index-1].start({
'width': 72,
'height': 72
});
}
if(efekty[index+1]){
efekty[index+1].start({
'width': 72,
'height': 72
});
}
});
Kod może się wydać długi, ale jest prosty - działa w następujący sposób:
- uruchamiany jest efekt powiększenia obrazka nad którym znajduje się kursor,
- sprawdzane jest czy istnieje efekt dla poprzedniego elementu (jeśli nie istnieje efekt to nie ma też elementu),
- jeżeli efekt istnieje to poprzedni element jest animowany,
- sprawdzane jest czy istnieje efekt dla następnego elementu (jeżeli tego efektu nie ma to znaczy, że dany element jest ostatnim).
Bardzo ważne jest użycie w metodzie start pojedynczych wartości, a nie tablic - gdybyśmy użyli tablic to animacja by wykonywała się w sztywnym przedziale wartości, a może się zdarzyć, że użytkownik przejedzie z jednego elementu na sąsiedni (powiększony) i spowoduje to powiększenie od mniejszej wartości niż aktualna dla elementu - jakby to wyglądało nie muszę chyba opisywać :)
Na koniec tworzymy zdarzenie mouseleave:
element.addEvent('mouseleave', function(){
efekty[index].start({
'width': 48,
'height': 48
});
if(efekty[index-1]){
efekty[index-1].start({
'width': 48,
'height': 48
});
}
if(efekty[index+1]){
efekty[index+1].start({
'width': 48,
'height': 48
});
}
});
Działa ono na podobnej zasadzie co poprzednie zdarzenie - zmieniają się tylko wartości do jakich dążą właściwości w animacji.
Cały kod umieszczamy oczywiście w zdarzeniu onload i gotowe :
Oczywiście jest to bardzo podstawowa wersja tego menu. Można ją oczywiście samemu ją rozbudować i osobiście to polecam. Moje propozycje rozbudowy skryptu:
- dodać do linków atrybut
titlei podczas dodawanie eventów, wykonać generowanie na ich podstawie etykiet tekstowych, które pokażą się przy animacji (przy towarzyszącej animacji właściwościopacityifont-size). Potrzeba przy tym oczywiście paru zmian kodu CSS ;) - dodać możliwość dynamicznej zmiany rozmiarów końcowych animowanych elementów (czyli jak ja to nazywam - możliwość zmiany "wyrazistości animacji")
Jeżeli ktoś to przypadkiem zrobi to niech pochwali się w komentarzach do tego wpisu :)
W następnej części kursu zajmiemy się plikiem fx.elements.js.
Mootools 1.11 - Fx.Elements.js do góry
Opisywałem już jak tworzyć efekty wykorzystujące zmianę jednej właściwości CSS (Fx.Style), kilku właściwości (Fx.Styles), a dziś dowiemy się jak wykonywać te operacje na wielu elementach naraz - do tego właśnie służy plik fx.elements.js
Głównym składnikiem tego pliku jest oczywiście klasa Fx.Elements, która posiada tylko jedną metodę - start. Oczywiście poza tym klasa ta dziedziczy wszystkie opcje klasy Fx.Base.
Składnia metody start tej klasy jest trochę bardziej skomplikowana niż wypadku poprzednich metod, bo jako argument przyjmuje dość rozbudowany obiekt.
Bardzo ważną cechą tej klasy jest fakt, że możemy za jej pomocą animować każdy z grupy elementów na inny sposób.
Składnia za pomocą której tworzymy sam efekt jest bardzo prosta:
var efekty = new Fx.Elements($$('elementy'),{opcje});
Gdzie zmienna $$('elementy') oznacza dowolny zbiór elementów, a obiekt {opcje} to pozostałe parametry efektu dziedziczone z klasy Fx.Base .
Bardziej złożona jest budowa metody start:
efekty.start({
"0":{
"wlasciwosc1" : [start,koniec],
"wlasciwosc2" : [start,koniec]
},
"1":{
"wlasciwosc" : [start,koniec]
},
...
"5":{
"wlasciwosc" : koniec
}
});
Metoda start pobiera obiekt w którym kolejne pola są identyfikatorami elementów w tablicy zwracanej przez funkcję selekcjonującą elementy - numerowanie zaczyna się od zera. Obiekt przypisany do takiego identyfikatora składa się z właściwości i zakresu wartości (lub wartości końcowej) w jakim przebiega animacja tegoż elementu.
Według mnie ręczne zapisywanie tego typu obiektów jest mało sensowne chyba, że mamy do czynienia z bardzo zróżnicowanymi animacjami dla elementów z danej grupy. W innych wypadkach polecam tworzenie obiektów z identyfikatorami w pętli i dołączanie ich do tablicy w sposób dynamiczny - dzięki temu zyskamy na elastyce rozwiązania (dodanie kolejnych elementów do kodu struktury animacji nie wymaga dodatkowych ingerencji w kod JavaScript).
Zaletą klasy Fx.Elements jest fakt, że nie tworzymy kilkunastu obiektów efektów tylko jeden obiekt w momencie gdy chcemy na różne sposoby animować różne elementy naraz.
Zapewne kojarzycie menu ze strony głównej mootools - jest tam zastosowany ładny efekt, który można także znaleźć na stronie z demami . Na tym demie będę się wzorował w swoim przykładzie, jednak od siebie dodam iż mój kod zajmuje 19 linijek w stosunku do 27 jakie zajmuje wersja oryginalna. Moja wersja jest także trochę wydajniejsza bo wykonuje mniej zbędnych operacji. Także ten przykład będzie dziś mówił nie tylko o Fx.Elements, ale także o optymalizacji kodu (troszeczkę ;) ).
Zapoznajmy się może z wersją oryginalną:
var szNormal = 117, szSmall = 100, szFull = 219;
var kwicks = $$("#kwicks .kwick");
var fx = new Fx.Elements(kwicks, {wait: false, duration: 300, transition: Fx.Transitions.Back.easeOut});
kwicks.each(function(kwick, i) {
kwick.addEvent("mouseenter", function(event) {
var o = {};
o[i] = {width: [kwick.getStyle("width").toInt(), szFull]}
kwicks.each(function(other, j) {
if(i != j) {
var w = other.getStyle("width").toInt();
if(w != szSmall) o[j] = {width: [w, szSmall]};
}
});
fx.start(o);
});
});
$("kwicks").addEvent("mouseleave", function(event) {
var o = {};
kwicks.each(function(kwick, i) {
o[i] = {width: [kwick.getStyle("width").toInt(), szNormal]}
});
fx.start(o);
});
Wygląda dość skomplikowanie, ale wraz z moją wersją wyjaśnię co i jak.
Zacząłem oczywiście od zmiennych wykorzystywanych w dalszym kodzie:
var opcje = $$("#menu li");
var obiekt = {}, obiekt_l = {};
var efekt = new Fx.Elements(opcje, {wait: false, transition: Fx.Transitions.Back.easeOut});
Jak widać stworzyłem zmienną opcje, która jest kolekcją wszystkich opcji listy. Do tego stworzyłem dwa obiekty, które zostaną wykorzystane w metodach start efektu. No i oczywiście zmienna definiująca sam efekt. W stosunku do oryginału usunąłem zmienne odpowiedzialne za rozmiary elementów - u mnie te liczby są wykorzystywane tylko raz więc tworzenie zmiennych było bezsensowne. kwicks to moje opcje, #menu to #kwicks, a klasę .kwick zastąpiłem po prostu elementem li - nie widziałem potrzeby generowania dodatkowych klas w kodzie skoro mogę się odwołać po typie elementów. Oczywiście doszły moje dwa obiekty, które w oryginale znajdują się w ciele funkcji.
Sprawę zdarzeń mouseenter zrealizowałem w następujący sposób:
opcje.each(function(opcja, i){
opcja.addEvent("mouseenter", function(){
opcje.each(function(x,j){
(i != j) ? obiekt[j] = {width: 100} : obiekt[j] = {width: 219};
});
efekt.start(obiekt);
});
obiekt_l[i] = {width: 117};
});
Jak widać przy każdej z opcji dodawane jest zdarzenie i generowany jest obiekt dla metody start. W stosunku do oryginału zrezygnowałem z określonego przedziału w jakim odbywa się animacja oraz skróciłem generowanie obiektu do trzech linijek dzięki skróconej postaci instrukcji warunkowej if.
Dodatkowo przy okazji głównej pętli realizuję w tym kodzie generowanie obiektu dla metody start użytej pryz zdarzeniu mouseleave - dzięki temu pozbyłem się tam dodatkowej pętli generującej obiekt.
Generowanie zdarzenia mouselave skróciło mi się do trzech linijek:
$("menu").addEvent("mouseleave", function(){
efekt.start(obiekt_l);
});
Obiekt obiekt_l mam wygenerowany wcześniej więc wystarczyło dodać wywołanie metody start klasy Fx.Elements. I tym sposobem skróciłem 27-linijkowy kod do 19-linijkowego kodu, który jest według mnie wydajniejszy bo pozbyłem się z niego zbędnych zmiennych i pętli:
window.addEvent("domready",function(){
var opcje = $$("#menu li");
var obiekt = {}, obiekt_l = {};
var efekt = new Fx.Elements(opcje, {wait: false, transition: Fx.Transitions.Back.easeOut});
opcje.each(function(opcja, i){
opcja.addEvent("mouseenter", function(){
opcje.each(function(x,j){
(i != j) ? obiekt[j] = {width: 100} : obiekt[j] = {width: 219};
});
efekt.start(obiekt);
});
obiekt_l[i] = {width: 117};
});
$("menu").addEvent("mouseleave", function(){
efekt.start(obiekt_l);
});
});
I oczywiście przykład prezentujący moją wersję menu:
Jak widać przy dość krótkim kodzie (można go jeszcze bardziej skrócić usuwając zbędne białe znaki, ale chciałem zadbać o jako taką czytelność) możemy uzyskać miły dla oka efekt :) Poza tym (to informacja dla tych co mają gdzieś przyjemności dla oka :) ) tego typu efekt pozwala zmniejszyć ilość miejsca potrzebnego do prezentacji informacji - część mniej kluczowych informacji widoczna jest po najechaniu na daną opcję menu (oczywiście mówimy tu o rzeczywistym wykorzystaniu, a nie przykładzie).
W następnej części kursu omówię plik Fx.Scroll.js .
Mootools 1.11 - Fx.Scroll.js do góry
W tej części kursu poprzewijamy sobie elementy z atrybutem overflow:hidden we wszystkie strony :) Do przewijania służy klasa Fx.Scroll z tytułowego pliku. W mootools elementy możemy przewijać na trzy sposoby - poprzez określenie współrzędnych punktu do jakiego ma zostać przewinięty element, możemy także przewijać element do jego krańców oraz możemy przewijać element według miejsca położenia elementów w nim umieszczonych.
Na tą część kursu przewidziałem dwa zadania - przewijanie elementu przyciskami (w górę i w dół), oraz wykonanie elementu na stronę, który pozwoli nam na małym obszarze upchać sporo treści i na dodatek ładnie ją prezentować.
Na początek tradycyjna dawka teorii, która później zostanie wykorzystana w praktyce. Klasa Fx.Scroll ma składnię podobną do już poznanych wcześniej klas. Oprócz tego co dziedziczy po klasie Fx.Base, posiada jeszcze jedną własną opcję - overflown, która jest tablicą elementów w których jest umieszczony element jaki chcemy przewijać - chodzi tylko o te elementy, które także są przewijane.
Składnia prezentuje się następująco:
var przewijanie = new Fx.Scroll("id_elementu");
Gdzie zmienna id_elementu to oczywiście identyfikator elementu jaki będziemy przewijali.
Klasa Fx.Scroll posiada 6 metod z których cztery nie pobierają dodatkowych argumentów:
- toLeft
- toRight
- toTop
- toBottom
Tak więc ich składnia wygląda następująco (korzystamy z wcześniej utworzonego obiektu klasy Fx.Scroll):
przewijanie.toTop();
Gdzie toTop() możemy zastąpić jedną z pozostałych metod.
Dwie pozostałe metody tej klasy pobierają argumenty. W wypadku metody scrollTo są to współrzędne punktu do jakiego zostanie przewinięty element:
przewijanie.scrollTo(x, y);
Natomiast metoda toElement jako argument pobiera element do jakiego ma zostać przewinięty element nadrzędny.
przewijanie.toElement("id_elementu");
Myślę, że użycie tej klasy nie powinno być dla czytelników kursu skomplikowane zwłaszcza, że z podobnymi zagadnieniami mieliśmy już styczność przy omawianiu pliku Element. Dimensions.js . Pora zatem przejść do przykładów, które rozjaśnią resztę wątpliwości.
Na początek stworzymy przewijany za pomocą dwóch przycisków element wypełniony tekstem i oczywiście mający mniejszą wysokość niż potrzebna do prezentacji tekstu w całości.
W tym wypadku skorzystamy z metody scrollTo - będziemy przewijać nasz element o ilość pikseli równą jego wysokości (przyjmijmy 300 pikseli).
Nasz div będzie miał identyfikator "div_przewijany". Stwórzmy na początek obiekt klasy Fx.Scroll dla tego elementu:
var przewijanie = new Fx.Scroll("div_przewijany");
Teraz pora na działanie przycisków - działanie będzie się opierało na dodawaniu/odejmowaniu od aktualnego położenia zapisanego w zmiennej aktualna_pozycja odpowiedniej wartości (300). O ile z przyciskiem "Przewiń w górę" nie będzie problemu bo przewijanie zostanie przerwane gdy zmienna aktualna_pozycja osiągnie wartość 0 to w wypadku przycisku "Przewiń w dół" pojawia się mały problem - musimy znać wysokość naszego elementu aby wiedzieć do którego momentu możemy przewijać.
W tym momencie musimy skorzystać z tego co udostępnia nam plik Element. Dimensions.js, a dokładniej z właściwości scrollSize.y zwracanego przez metodę getSize obiektu.
Stwórzmy zatem zmienną aktualna_pozycja i zmienną wysokosc_diva:
var aktualna_pozycja = 0;
var wysokosc_diva = $("div_przewijany").getSize().scrollSize.y;
Teraz już możemy zająć się dodaniem zdarzeń onclick do naszych przycisków, którym nadałem identyfikatory wGore i wDol. W wypadku przycisku wGore działanie polega na sprawdzeniu czy zmienna aktualna_pozycja jest większa od zera - jeżeli tak to można przewijać (poprzez zmniejszenie wartości wspomnianej zmiennej i jej wykorzystanie w metodzie scrollTo), w przeciwnym wypadku po prostu nic się nie stanie:
$("wGore").addEvent("click",function(){
if(aktualna_pozycja > 0){
aktualna_pozycja -= 300;
przewijanie.scrollTo(0,aktualna_pozycja);
}
});
W wypadku przycisku wDol sprawdzamy czy zmienna aktualna_pozycja powiększona o 300 ma wartość mniejszą od zmiennej wysokosc_diva - jeżeli tak to możemy przewijać (poprzez zwiększenie wartości zmiennej aktualna_pozycja i jej wykorzystanie w metodzie scrollTo).
$("wDol").addEvent("click",function(){
if( (aktualna_pozycja + 300) < wysokosc_diva){
aktualna_pozycja += 300;
przewijanie.scrollTo(0,aktualna_pozycja);
}
});
Całość tradycyjnie już umieszczamy w zdarzeniu onload i możemy podziwiać skrypt w akcji:
Pora na drugi przykład, który zapozna Was z pozostałymi metodami klasy Fx.Scroll.
Całość opiera się na tym, że w divie są wyświetlane inne divy, które mają taki sam rozmiar jak ten główny div i są umieszczone w jeszcze jednym divie, którego długość jest równa długości wszystkich tych divów razem wziętych po to by móc umieścić wszystkie te elementy obok siebie za pomocą :
float:left;
Poruszanie się po tym ciągu elementów polega na korzystaniu z dwóch przycisków: wLewo i wPrawo.
Na początek tworzymy potrzebne zmienne - obiekt efektu przewijania, tablicę elementów tworzących ciąg jaki przewijamy oraz zmienną przechowującą informację jaki element jest aktualnie pokazywany:
var przewijanie = new Fx.Scroll("scrollinfo");
var el_tab = [];
var aktualny_div = 0;
Następnie wypełniamy naszą tablicę elementami tworzącymi animowany ciąg:
$$("#scrollinfo div.news").each(function(element,index){
el_tab[index] = element;
});
Dodam tylko, że główny div ma w tym wypadku id scrollinfo, a wszystkie elementy, które są pokazywane mają przypisaną klasę news.
Pora na rzecz najważniejszą - obsługa przycisków, które będą służyły do przewijania. Na początek przycisk do przewijania w lewo - musi on działać w ten sposób, że będzie sprawdzane czy aktualnie pokazywany element jest pierwszym w ciągu - jeżeli tak to nastąpi przewinięcie do ostatniego elementu poprzez wykorzystanie metody toRight (mógłbym użyć takiego zapisu jak w wypadku drugiej części warunku, ale ten zapis jest dłuższy) i zwiększenie wartości zmiennej przechowującej informację o aktualnie pokazywanym elemencie do 4. W pozostałych wypadkach będzie zmniejszana wspomniana zmienna, a następnie zostanie wykorzystana jako identyfikator w tablicy elementów, której element zostanie użyty jako argument metody toElement:
$("wLewo").addEvent("click",function(){
if(aktualny_div == 0){
aktualny_div = 4;
przewijanie.toRight();
}
else{
aktualny_div--;
przewijanie.toElement(el_tab[aktualny_div]);
}
});
W przypadku przycisku wPrawo wszystko działa jakby na odwrót - sprawdzamy czy aktualnie pokazywany element jest ostatnim w ciągu. Jeżeli tak to za pomocą metody toLeft przechodzimy na początek. W pozostałych wypadkach zwiększamy zmienną z informacją o aktualnie pokazywanym elemencie i używamy jej by wskazać element tablicy do którego chcemy przejść z użyciem metody toElement:
$("wPrawo").addEvent("click",function(){
if(aktualny_div == 4){
aktualny_div = 0;
przewijanie.toLeft();
}
else{
aktualny_div++;
przewijanie.toElement(el_tab[aktualny_div]);
}
});
Kod skryptu nie jest zbyt długi, a sam efekt według mnie całkiem ładny (oczywiście po małej zabawie z CSS):
Jeszcze parę propozycji co do drugiego przykładu:
- zauważmy, że możemy wykonać skrypt tego samego typu, ale działający w kierunku pionowym. Wystarczy wyrzucić div posiadający identyfikator
flex(bo jest w tym wypadku zbędny) i usunąćfloat:leftz kodu CSS dla klasy news. No i oczywiście zmienić metodętoLeftna metodętoBottom, a metodętoRightnatoTop. - nie każdemu pewnie spodoba się to przewijanie w momencie gdy przechodzimy z pierwszego elementu do ostatniego lub na odwrót. Możemy tego uniknąć na dwa sposoby :
- po prostu nie pozwalać na dalsze przewijanie po dotarciu do początku, końca ciągu lub
- stworzyć jeszcze jeden efekt przewijania dla diva
scrollinfoz opcjądurationrówną 0. Następnie przy ładowaniu skryptu skopiować ostatni div z newsem przed pierwszy, a pierwszy element skopiować za ostatni element. I teraz wykorzystać mały trick - w wypadku gdy znajdziemy się przy pierwszym lub ostatnim elemencie w chwili przejścia do kolejnego elementu najpierw wykonać standardową animację (do kopii elementu), a potem po wykonaniu tego przewinięcia wykonać cofnięcie do prawdziwego elementu z użyciem drugiego efektu, który ma najkrótszy możliwy czas wykonania. Oczywiście jest to rozwiązanie dla tych, którzy bardzo chcą utrzymać ładną ciągłość animacji.
W następnej części kursu zajmiemy się plikiem Fx.Slide.js, który jest ostatnim omawianym plikiem z grupy Effects.
Mootools 1.11 - Fx.Slide.js do góry
Przyszła pora na ostatni plik z grupy Effects - fx.slide.js, który służy do zwijania i rozwijania elementów, zarówno w pionie jak i w poziomie. Wcześniej do tego celu były używane klasy Fx.Width i Fx.Height, które pewnie niektórzy znają z mojego kursu moo.fx .
Zaletą w stosunku do klas Fx.Width i Fx.Height jest fakt iż ukrywanie elementu nie zmienia jego rozmiaru - nie zobaczymy zatem "upychania" zawartości na coraz mniejszym obszarze jak miało to miejsce w przypadku wspomnianych klas.
Klasa Fx.Slide bo to jej poświęcimy uwagę w tej części kursu, posiada 5 metod:
- slideIn
- slideOut
- show
- hide
- toggle
Dwie pierwsze metody służą odpowiednio do pokazywania i ukrywania elementu, dwie kolejne metody służą do tego samego tyle, że bez stosowania animacji, a ostatnia metoda służy do pokazywania/ukrywania elementu w zależności od tego czy jest on ukryty czy nie.
Efekt slide, jest bardzo często stosowany w Internecie, bo pozwala na ukrycie mniej istotnych informacji do momentu kliknięcia jakiegoś elementu, który je pokaże, poza tym pozwala też na przykład na ukrywanie przez użytkownika mniej ważnych dla niego zawartości itd. Krótko mówiąc możliwości zastosowania ograniczone tylko naszą wyobraźnią :)
Nasze działania skupią się dziś wokół trzech przykładów - pierwszego z ukrywaniem pionowym treści kilku akapitów, drugiego związanego z ukrywaniem poziomym i trzeciego w którym dzięki analizie kodu pliku fx.slide.js stworzymy sobie w prosty sposób pewne udogodnienie, ale o tym później :)
Tworzenie efektu slide jest oczywiście bardzo podobne do tworzenia efektów pozostałych typów. Składnia wygląda następująco:
var slider = new Fx.Slide('id_elementu', {opcje});
Poza standardowymi opcjami jakie klasa Fx.Slide dziedziczy z klasy Fx.Base, dochodzi jeszcze opcja mode - która określa kierunek animacji - vertical (pionowy) lub horizontal (poziomy).
Zatem stworzenie pionowego efektu slide polega na stworzeniu obiektu z użyciem opcji mode ustawionej na vertical:
var slider = new Fx.Slide('div_testowy',{mode: 'vertical'});
W praktyce jednak wystarczy zapis:
var slider = new Fx.Slide('div_testowy');
ponieważ domyślną wartością opcji mode jest właśnie 'vertical'.
Jak wspominałem pierwszy przykład będzie służył zwijaniu bloków teksty (akapitów). Przyjmijmy, że rozwijać/zwijać akapity ma użytkownik poprzez kliknięcie odpowiedniego nagłówka tekstu. Oczywiście moglibyśmy stworzyć teraz po kolei efekty slide i dodać zdarzenia do odpowiednich nagłówków, ale z reguły taka struktura jest powtarzalna - jest określona liczba nagłówków i paragrafów. Dlatego by uelastycznić kod skorzystamy z pętli, która automatycznie stworzy efekty i doda zdarzenia onclick do nagłówków. Dzięki temu dodanie kolejnych nagłówków i paragrafów tekstu nie będzie wymagało zmiany skryptu, a jedynie skorzystania z określonej struktury kodu.
Nasze nagłówki będą miały przypisaną klasę "naglowek", a paragrafy klasę "akapit".
Z akapitów tworzymy tablicę :
var tab_p = $$(".akapit");
A na tablicy nagłówków wykonujemy bezpośrednio nasze operacje - na początek stworzenie efektu slide:
$$(".naglowek").each(function(element,index){
var slider = new Fx.Slide(tab_p[index]);
});
Następnie dodajemy zdarzenie onclick do samego nagłówka:
$$(".naglowek").each(function(element,index){
var slider = new Fx.Slide(tab_p[index]);
element.addEvent("click",function(){
slider.toggle();
});
});
I powyższy kod w połączeniu z odpowiednią strukturą kodu pozwoli nam uzyskać efekt taki jak w poniższym przykładzie:
Jak widzicie pierwszy przykład jest banalny w implementacji. Gdyby ktoś chciał go umieścić na swojej stronie to oczywiście wypadałoby dopisać zapis w cookies informacji o tym, które paragrafy są ukryte. Ale to już zadanie dla tych, którzy chcą ten efekt u siebie mieć ;)
W kolejnym przykładzie zajmiemy się trochę bardziej złożonym zadaniem. Każdy pewnie kojarzy efekt accordion, a jak nie kojarzy to polecam spojrzeć na stronkę biblioteki moo.fx. My stworzymy działający na tej samej zasadzie efekt, ale w poziomie. Jakie są założenia działania naszego skryptu ? Przede wszystkim zawsze musi być widoczny tylko jeden rozwinięty element. Kliknięcie na przycisk aktywujący drugi element musi ukryć ten poprzedni. Pewnie sposobów na napisanie tego typu skryptu jest wiele więc będziecie mogli pokombinować co zmienić i ulepszyć :)
Element naszej układanki będzie składał się z aktywatora i akapitu - kliknięcie na aktywator będzie rozwijało akapit. Pierwszy akapit będzie od razu rozwinięty - pozostałe będą ukryte. Aby nie rozbijać struktury strony będziemy musieli wykorzystać małą sztuczkę - wszystkie akapity poza pierwszym ukryjemy za pomocą stylu display:none; a następnie przy ładowaniu strony zmienimy ten styl na display:block; i oczywiście od razu zastosujemy metodę hide. No ale po kolei: zacznijmy od przygotowania sobie potrzebnych w tym skrypcie zmiennych - nasze paragrafy musimy umieścić w tablicy - a na tablicy aktywatorów wykonamy przypisanie wszystkich parametrów:
var tab_p = $$(".akapit");
Przyda się też zmienna przechowująca informację o tym, który paragraf jest aktualnie rozwinięty :
var aktualny_p = 0;
Zaczynamy od 0 bo tak samo są liczone indeksy w tablicach - po co wykonywać później zbędne operacje dodawania ?
Przyda się jeszcze tablica w której będziemy trzymali nasze efekty:
var tab_e = [];
Przy każdym aktywatorze musimy wykonać następujące operacje: stworzenie efektu, zapisanie efektu w tablicy, dodanie zdarzenia onclick do aktywatora, nadanie paragrafowi (poza pierwszym) atrybutu style="display: block;" i ukrycie go metodą hide. Dodatkowo tworzonemu przez klasę Fx.Slide divowi nadrzędnemu nadawany jest styl float:left tak aby nie następowało rozbicie elementów na kilka linii.
Zatem:
$$(".aktywator").each(function(element,index){
var slider = new Fx.Slide(tab_p[index],{mode: "horizontal"});
tab_e[index] = slider;
if(index > 0){
tab_p[index].setStyle("display","block");
slider.hide();
tab_p[index].getParent().setStyle("float","left");
}
else{
tab_p[index].getParent().setStyle("float","left");
}
element.addEvent("click",function(){
if(aktualny_p !== index){
tab_e[aktualny_p].slideOut();
aktualny_p = index;
tab_e[index].slideIn();
}
});
});
Z powyższego kodu chyba tylko kod zdarzenia onclick przypisywanego do aktywatora może wydać się skomplikowany, dlatego już tłumaczę - na początku sprawdzane jest czy chcemy rozwinąć już rozwinięty element - jeżeli tak to nic się nie stanie bo chcemy aby zawsze co najmniej jeden element był rozwinięty. W drugim wypadku aktualnie rozwinięty element jest ukrywany (zwijany), następuje zmiana wartości zmiennej przechowującej informację o aktualnie otwartym paragrafie i zostaje rozwinięty paragraf do którego jest przypisany klikany aktywator.
I powyższy kod w akcji:
Na koniec opiszę małe usprawnienie dla klasy Fx.Slide, które może się niektórym przydać. Posiada ona małą wadę, otóż animacja przebiega tylko w jedną stronę ustaloną przez programistów mootools. A co jeśli chcielibyśmy, żeby zwijanie/rozwijanie pionowe przebiegało od dołu do góry, a nie od góry do dołu (tzn. aby przy zwijaniu pionowym dolna krawędź przemieszczała się do góry, powodując tym samym widoczność tekstu w górnej części elementu do końca) ? Jest to do zrobienia. Gorzej w wypadku animacji poziomej - jeżeli chcemy ukrywać element poprzez jego odsunięcie w prawą stronę to zamiast przerabiać klasę Fx.Slide lepiej stworzyć div w divie i nadać im tą samą szerokość, a następnie operować na właściwości margin-right wewnętrznego diva (oczywiście ba divy muszą mieć ustawione overflow:hidden).
Natomiast jeśli chodzi o zwijanie pionowe to musimy dodać do naszego skryptu taki kod:
Fx.Slide.implement({
vertical: function(){
this.margin = 'margin-bottom';
this.layout = 'height';
this.offset = this.element.offsetHeight;
}
});
Zmieniamy właściwość this.margin z "margin-top" na "margin-bottom" i to wystarczy by efekt przebiegał w inny sposób. Oczywiście zmiany dotyczą całej klasy Fx.Slide. Jeśli chcemy mieć dostęp do obu typów pionowych animacji to musimy stworzyć klasę potomną klasy Fx.Slide i dopiero do niej dopisać powyższy kod:
Fx.SlideReverse = Fx.Slide.extend({
vertical: function(){
this.margin = 'margin-bottom';
this.layout = 'height';
this.offset = this.element.offsetHeight;
}
});
Oczywiście dalej tworzymy efekt na tej samej zasadzie co wcześniej.
Ja z tego rozwiązania skorzystałem w swoim przykładzie po to by łatwo było zauważyć różnicę pomiędzy oboma typami animacji:
I to już wszystko na temat nie tylko klasy Fx.Slide, ale i grupy Effects. W dwóch kolejnych częściach kursu zajmiemy się grupą Drag
Mootools 1.11 - Drag.Base.js do góry
Dziś rozpoczynamy ostatnią, że tak to ujmę "zwartą" grupę plików frameworka mootools - po niej pozostaną do omówienia już tylko pluginy, które mają między sobą dość luźne powiązania lub nie mają ich wcale. Sekcja Drag zawiera dwa pliki - omawiany w tej części plik drag.base.js i będący tematem następnej części kursu drag.move.js .
Plik drag.base.js służy do realizacji dwóch zadań - przenoszenia elementów oraz zmiany ich rozmiarów. Przy czym implementacja przenoszenia elementów jest dość uboga w tym pliku i tak naprawdę pełnię drag & drop zobaczymy dopiero przy omawianiu drugiego pliku sekcji Drag.
Zadania jakie postawimy sobie na dziś to : stworzenie elementu div, który będzie można swobodnie przenosić oraz projekt ulepszonego pola textarea.
Zaczniemy jak zwykle od dawki teorii.
Klasa Drag.Base pobiera dwa argumenty - element, którego mają dotyczyć modyfikacje i obiekt opcji:
new Drag.Base("element",{opcje});
W czasie działania obiektu tej klasy mamy do dyspozycji 5 zdarzeń:
onBeforeStart- zdarzenie występujące przed rozpoczęciem operowania na elemencie - przydatne w momencie, gdy potrzebujemy zmienić parametry obiektu przed samą akcją.onStart- zdarzenie to występuje w momencie ustawienia parametrów dla modyfikacji elementu.onSnap- zdarzenie, które występuje przy przekroczeniu limitu określonego w opcjisnap.onDrag- zdarzenie to występuje w momencie rozpoczęcia przenoszenia elementu.onComplete- zdarzenie wywoływane w momencie zakończenia modyfikacji elementu.
Oprócz tego mamy do dyspozycji dużo opcji:
handle- element jaki będzie służył do modyfikacji parametrów - domyślnie jest to element podany jako argument klasyDrag.Base,modifiers- obiekt posiadający dwa pola -xorazydo których przypisane są nazwy właściwości modyfikowanych w czasie ruchu myszą. Domyślnie dlaxprzypisana jest właściwośćleft, a dlaywłaściwośćtop,limit- podobny obiekt jak w wypadku opcjimodifiersz tą różnicą, że wartością jest tablica, której pierwszy i drugi element odpowiada przedziałowi w jakim mogą się dokonywać modyfikacje - zarówno w pionie jak i w poziomie.snap- opcja ta zawiera dystans jaki musi przebyć kursor myszki aby rozpocząć operację modyfikacji elementu. Domyślnie opcja ta ma wartość 6 (oznacza to, że po wciśnięciu klawisza myszy, możemy przebyć kursorem dystans 5 pikseli i element nie zostanie przesunięty).grid- dzięki tej opcji możemy sprawić, że zamiast płynnej zmiany wartości będą się one zmieniały co określoną wielkość - na przykład 10 pikseli. Domyślnie opcja ta jest wyłączona.unit- jednostka w jakiej dokonywane są modyfikacje. Domyślnie piksele - "px".
Poza klasą Drag.Base w tytułowym pliku jest jeszcze metoda makeResizable - służy ona do automatycznego tworzenia możliwości zmiany rozmiaru elementu. Jej składnia wygląda następująco :
element.makeResizable({opcje});
Gdzie obiekt {opcje} to oczywiście wspomniane wcześniej parametry, ale nie ma sensu ustawiać opcji modifiers bo i tak jest ona już domyślnie ustawiona na width i height elementu. Ale najpierw zajmijmy się prostym przykładem przenoszenia elementu.
Jak zrobić nasz pierwszy przenośny element ? Sprawa jest niesamowicie banalna - wymaga dodania 4 linijek kodu - 3 JavaScript i jednej CSS przy czym samo utworzenie przenośnego elementu to jedna linijka, a dwie pozostałe odpowiadają za zdarzenie onload obiektu window :)
Zatem elementowi, których chcemy przenosić nadajemy właściwość:
position: absolute;
Oraz tworzymy następujacy kod JS:
new Drag.Base("przenosny");
Oczywiście kod ten umieszczamy w zdarzeniu onload obiektu window - myślę, że powinniście już mieć to we krwi ;) Jak widzicie nasz div ma identyfikator przenosny co całkiem dobrze oddaje jego możliwości:
No dobrze - przykład z serii "prościej już się nie da" mamy za sobą ;) Pora na coś bardziej złożonego. Zapoznajmy się bliżej z opcją snap, oraz ze zdarzeniami onSnap i onDrag - nasz poprzedni przykład ulepszymy o opóźnienie rozpoczęcia przenoszenia (snap), które wystąpi dopiero po przemieszczeniu się przez kursor myszy o 20 pikseli, a dodatkowo w wypadku gdy wystąpią zdarzenia onSnap i onDrag pojawi się stosowny komunikat w elemencie.
Do naszego obiektu klasy Drag.Base dodajemy obiekt z odpowiednimi parametrami:
new Drag.Base("przenosny",{
snap: 20,
onSnap: function(){
this.element.innerHTML = "Snap";
},
onDrag: function(){
this.element.innerHTML = "Drag";
}
});
Warto zwrócić uwagę na odwołanie this.element przy tworzeniu klasy - pozwala mi ono odwołać się do przenoszonego diva, bez jego ponownej selekcji z drzewa dokumentu.
I powyższy kod w akcji (aby zobaczyć napis "Snap" zalecam wolne przesuwanie myszką gdyż występuje on tylko po przebyciu 20 pikseli, a potem zaraz znika na rzecz napisu "Drag"):
Zanim przejdziemy do przykładu z polem textarea, jeszcze jeden przykład z naszym przenośnym divem - dodamy dwa przyciski, które pozwolą nam decydować czy ruch diva ma się ograniczać do ruchu poziomego lub pionowego. Wykorzystamy do tego zdarzenie onBeforeStart i opcję modifiers.
Na początku tworzymy sobie zmienną przechowującą informacje o aktualnej możliwości ruchu:
var mozliwosci_ruchu = false;
Na początek będzie ona pozbawiona wartości, bo będziemy ją zmieniać za pomocą dwóch przycisków - pion i poziom. Dodajmy do tych przycisków zdarzenia onclick:
$("pion").addEvent("click",function(){
mozliwosci_ruchu = "pion";
});
$("poziom").addEvent("click",function(){
mozliwosci_ruchu = "poziom";
});
Mając te "przełączniki" wystarczy już tylko stworzyć odpowiednia funkcję dla zdarzenia onBeforeStart - musi ona w zależności od żądanego kierunku ruchu zmieniać opcję modifiers tak by tylko jedna modyfikacja była dokonywana w czasie ruchu myszą. Osiągamy to poprzez przypisanie do jednej z właściwości obiektu wartości false:
new Drag.Base("przenosny",{
onBeforeStart: function(){
switch(mozliwosci_ruchu){
case "pion": this.modifiers = {x: false, y: "top"};break;
case "poziom": this.modifiers = {x: "left", y: false};break;
default:;break;
}
}
});
I to właściwie wszystko co trzeba było napisać:
No to teraz jeszcze krótka, ale bardzo istotna uwaga - otóż zarówno na IE jak i na Safari 3 powyższe przykłady nie zadziałałyby gdyby w stylu CSS dla diva "przenosny" nie byłyby ustawione właściwości top i left - bez ich określenia, chociażby:
top: 0;
left: 0;
efekt zadziała tylko pod Firefoksem i Operą...
Pora na zajęcie się polem textarea - użytkownicy Joggera pewnie nie zaprzeczą iż rozciągane pole tego typu to świetna sprawa, zwłaszcza dla posiadaczy większych monitorów :) Zatem przygotujemy rozciągane pole textarea. Będzie je można rozciągać wzdłuż, ale tylko w ograniczonym zakresie, dla małego upiększenia, podczas zmiany rozmiarów pola będzie zmieniane jego obramowanie.
Zaczniemy oczywiście od podstaw, czyli pola textarea, które można rozciągać do dowolnych rozmiarów, przemieszczając odpowiedni element. Nasze pole textarea będzie posiadało identyfikator "text", a element służący do rozciągania tego pola będzie miał identyfikator "suwak". Dodajemy metodę makeResizable do naszego pola:
$("text").makeResizable();
Następnie dodajemy opcję handle, a jako jej wartość podajemy nasz suwak:
$("text").makeResizable({
handle: "suwak"
});
Po tych operacjach nasz przykład prezentuje się następująco:
Ale wciąż nie ma ograniczenia na zmianę szerokości elementu. Ponieważ przy wywołaniu makeResizable modyfikowane parametry są narzucane z góry, musimy skorzystać ze zdarzenia onBeforeStart i zmienić właściwość pola x obiektu modifiers:
$("text").makeResizable({
handle: "suwak",
onBeforeStart: function(){
this.options.modifiers.x = false;
}
});
Teraz już wszystko powinno działać poprawnie:
Pora na ostatni efekt - zmianę stylu obramowania pola textarea na czas rozciągania. Skorzystamy tutaj z dwóch zdarzeń - onStart i onComplete. Zdarzenie onStart będzie zmieniało obramowanie na wykropkowane, a przy zdarzeniu onComplete będzie przywracane normalne obramowanie:
$("text").makeResizable({
handle: "suwak",
onBeforeStart: function(){
this.options.modifiers.x = false;
},
onStart: function(){
this.element.setStyle("border-style","dotted");
},
onComplete: function(){
this.element.setStyle("border-style","solid");
}
});
Przyda się jeszcze ograniczenie możliwości rozciągania elementu (opcja limit) - powiedzmy, ze minimalną wysokością ma być 100 pikseli, a maksymalną 500 pikseli. Ponieważ nie interesuje nas szerokość jako wartość pola x podajemy false, a jako wartość pola y wspomniany przedział w postaci tabeli:
$("text").makeResizable({
handle: "suwak",
limit: {
x: false,
y: [100,500]
},
onBeforeStart: function(){
this.options.modifiers.x = false;
},
onStart: function(){
this.element.setStyle("border-style","dotted");
},
onComplete: function(){
this.element.setStyle("border-style","solid");
}
});
I w ten sposób otrzymamy poniższy efekt:
Jeżeli ktoś ma ochotę dopieścić jeszcze bardziej to pole textarea, to osobiście proponuję by zastosować opcję grid tak by wysokość pola była zawsze iloczynem pewnej liczby linii tekstu (obecnie można "uciąć" linijkę tekstu w połowie wysokości podczas zmiany rozmiaru elementu).
W następnej części kursu zajmiemy się plikiem drag.move.js i będziemy kontynuowali naszą naukę obsługi przenośnych elementów :)
Mootools 1.11 - Drag.Move.js do góry
Pora dokończyć temat przenoszenia elementów. Dzięki plikowi drag.move.js możemy do naszych stron dodać prawdziwy efekt drag & drop. A wszystko dzięki nowym opcjom i zdarzeniom rozszerzających klasę Drag.Base.
Dzięki nowym opcjom możemy określić w obrębie jakiego elementu może poruszać się przenośny obiekt oraz obiekty gdzie możemy przenieść nasze elementy. Mamy także do dyspozycji 4 nowe zdarzenia oraz metodę klasy Element - makeDraggable.
W przykładach skupimy się na ograniczaniu przestrzeni, gdzie można przemieszczać element, oraz na zaprezentowaniu działania nowych zdarzeń. Jeśli chodzi o praktyczne przykłady to polecam ten - świetnie oddaje to co można uzyskać za pomocą plików z sekcji Drag.
Obiekt klasy Drag.Move możemy tworzyć na dwa sposoby:
new Drag.Move("element",{opcje});
lub:
$("element").makeDraggable({opcje});
Oba sposoby dają taki sam efekt.
Nowe opcje to:
droppables- tablica elementów, nad które można przenieść nasz przenośny obiekt,container- element w obrębie którego będzie poruszać naszym obiektem,overflown- to opcja znana nam już z poprzednich części kurs - chodzi o nadrzędne w stosunku do przenoszonego elementy, które posiadają atrybutoverflow.
Trzy spośród czterech zdarzeń dotyczą elementu na który mamy zamiar przenieść przenośny obiekt, a czwarte zdarzenie dotyczy tegoż obiektu:
onemptydrop- zdarzenie to występuje w momencie gdy puścimy przenoszony obiekt nad elementem nie będącym w tablicy opcjidroppables(czyli puścimy go poza wyznaczonymi do przenoszenia obszarami),ondrop- zdarzenie wywoływane w momencie puszczenia obiektu nad elementem z tablicydroppables(krótko mówiąc: przeciwieństwo zdarzeniaonemptydrop),onover- zdarzenie występujące wtedy kiedy nasz element znajdzie się nad miejscem docelowym (czyli jednym z elementów tablicydroppables),onleave- zdarzenie przeciwne doonover- występuje w momencie opuszczenia miejsca docelowego.
Na dobry początek stworzymy przenośny element z użyciem metody makeDraggable:
$("przenosny").makeDraggable();
Teraz dobra wiadomość dla leniwych (:P) - w wypadku klasy Drag.Move nie musimy elementowi nadawać dodatkowych właściwości CSS - takich jak position czy top orax left (by efekt działał w IE i Safari) - powyższa linijka wraz z definicją zdarzenia onload to wszystko czego potrzeba, by móc przenosić elementy :)
Ograniczymy teraz obszar nad jakim można przemieszczać przenośny element. Dzięki wykorzystaniu opcji container:
$("przenosny").makeDraggable({
container: "content"
});
Po zastosowaniu powyższego zapisu, użytkownik nie przeniesie diva "przenosny" poza obszar diva "content":
Pora na prawdziwe drag & drop - stworzymy sobie nową strukturę, która posłuży nam jako miejsce do przenoszenia elementów - będą to dwa umieszczone obok siebie elementy div. W pierwszym z nich będzie się znajdowało 9 divów przypisanych do klasy "przenosny". Na początek uczynimy je wszystkie przenośnymi zgodnie z nazwą klasy i ograniczymy obszar do diva "content":
$$(".przenosny").each(function(element,index){
element.makeDraggable({
container: "content"
});
});
Stosujemy do tego celu metodę each, która do każdego elementu doda metodę makeDraggable:
W powyższym przykładzie oba divy nieprzypadkowo są czarne i białe - zapoznamy się teraz z działaniem zdarzeń dotyczących obszarów na, które można upuszczać przenośne obiekty.
Do metody makeDraggable z poprzedniego przykładu dodajemy opcję droppables:
$$(".przenosny").each(function(element){
element.makeDraggable({
container: $("container"),
droppables: ["dobro", "zuo"]
});
});
Jak widać będą to dwa divy - czarny i biały, dodatkowo ograniczyłem obszar poruszania obiektami do nowego diva "container".
Naszym celem jest zmiana treści przenoszonego diva na "DOBRO" lub "ZUO" w zależności od tego nad jakim divem się znajdzie (chyba nie muszę mówić kiedy, który napis ma się pojawiać ;) ), dodatkowo po upuszczeniu diva ma się zmieniać kolor jego tła na stosowny do elementu docelowego. W wypadku diva "dobro" rozszerzamy naszą metodę each o następujący kod:
$("dobro").addEvents({
"drop" : function(el){
el.setStyles({
"background": "#FFF",
"color": "#AAA"
});
}
});
każde zdarzenie z klasy Drag.Move pobiera jako argument uchwyt (w tym wypadku zmienna el) do przenoszonego elementu - jak widać wykorzystałem to do zmiany stylu elementu w wypadku upuszczenia go na obszarze diva "dobro". Jeżeli chcemy odnieść się do diva, którego dotyczy zdarzenie to odwołujemy się przez operator this.
Teraz jeszcze dodajemy zdarzenia do diva "zuo" - do niego dodamy wszystkie trzy zdarzenia over, leave i drop:
$("zuo").addEvents({
"drop" : function(el){
el.setStyles({
"background": "#000",
"color": "#FFF"
});
},
"over" : function(el){
el.setHTML("ZUO");
},
"leave" : function(el){
el.setHTML("DOBRO");
}
});
Wszędzie odnosimy się przez uchwyt do przenoszonego elementu, by operować na jego zawartości i stylu - jak widzimy w wypadku upuszczenia obiektu nad danym elementem zmieni się jego styl, gdy obiekt będzie się nad tym elementem znajdował, zmieniona zostanie jego zawartość (tak samo przy opuszczaniu tego elementu):
Pozostało nam jeszcze zdarzenie emptydrop - jak wspominałem występuje ono wtedy gdy przenoszony obiekt nie znajdzie się w momencie "puszczenia" nad żadnym z docelowych elementów określonych w opcji droppables - w naszym wypadku rozszerzymy obszar nad którym można przemieszczać divy do diva "content" (tak jak to było pierwotnie) i w wypadku upuszczenia diva poza dwoma wspominanymi już elementami, przenoszony obiekt zostanie usunięty :
element.addEvent("emptydrop",function(){
this.remove();
});
Nasz rozszerzony przykład w akcji:
To były oczywiście bardzo proste i mało użyteczne przykłady użycia drag'n'drop jednak ich głównym celem było zaprezentować istotę tego zagadnienia z punktu widzenia mootools - zrozumienie działania zdarzeń jest w tym wypadku kluczem do efektywnego i efektownego użycia tego sposobu przemieszczania elementów.
Tym sposobem zakończyliśmy omawianie głównej części frameworka mootools - pozostała nam jeszcze do omówienia sekcja pluginów jednak nie są one tak ważne jak to co już omówiliśmy, bo służą one głównie do tworzenia ciekawych efektów z gotowców. Przy okazji zmieni się sposób omawiania pluginów - będą one omawiane nie zgodnie ze spisem treści, ale w sposób losowy ;)
Mootools 1.11 - Group.js do góry
Od pliku group.js zacznę opis pluginów frameworka mootools. W pliku tym znajdziemy jedną klasę - Group, z jedną tylko metodą - addEvent. Jakie jest przeznaczenie tej klasy ? Służy ona do wywoływania funkcji w momencie, gdy wszystkie podane jako argumenty obiekty klas wywołają określone zdarzenie.
Jeżeli na przykład ładujemy kilka obrazków korzystając z klasy Asset to możemy sprawić, że po załadowaniu wszystkich grafik zostanie wywołana określona funkcja. Oczywiście to tylko przykład, bo o wiele lepiej w tym wypadku skorzystać z metody images klasy Asset. O wiele lepiej klasa Group sprawdzi się, że tak to ujmę "rozproszonych" sytuacjach, czyli nie takich gdzie kilka operacji wykonuje się jedna po drugiej, ale tam gdzie pewne zdarzenia występują w różnych momentach działania skryptu, a muszą po wykonaniu całości dać znać, że wszystkie zostały wykonane.
Składnia tworzenia obiektu klasy Group wygląda następująco:
var grupa = new Group(obiekt_1, obiekt_2, ... , obiekt_n);
Jak widzimy jako argumenty klasy Group podajemy dowolnie długi ciąg obiektów.
Gdy mamy już grupę możemy dodać do niej zdarzenie, którego wykonanie we wszystkich instancjach spowoduje wywołanie funkcji:
grupa.addEvent("onzdarzenie",function(){
// kod funkcji
});
Jak widzimy w przeciwieństwie do standardowej metody addEvent klasy Element w wypadku klasy Group do nazwy zdarzenia dodajemy też prefiks "on".
Klasa Group jak widać nie jest zbyt skomplikowana w użyciu, więc pora na jakiś przykład użycia. Proponuję rozbudowę ostatniego przykładu z poprzedniej części kursu. Będzie ona polegała na tym, że w momencie usunięcia wszystkich przenośnych divów, będzie usuwana cała struktura służąca do drag'n'drop (biały i czarny element), a zamiast nich pojawi się stosowny komunikat.
Na początku musimy pamiętać o tym, że klasa Group jako argumenty nie przyjmuje tablic - zatem musimy rozdzielić wszystkie elementy tablicy $$(".przenosny") - zrobię to poprzez stworzenie nowej tablicy, choć oczywiście można się odwoływać bezpośrednio poprzez zapis $$(".przenosny")[indeks], ale spowodowałoby to wykonanie dziewięć razy selekcji elementów.
Tworzymy zmienną elementy:
var elementy = [];
Następnie zmieniamy linijkę:
$$(".przenosny").each(function(element){
na zapis:
$$(".przenosny").each(function(element,index){
elementy[index] = element;
Dzięki temu dodajemy automatycznie zmienną iteracyjną i dodajemy elementy do nowej tablicy.
Na koniec już poza metodą each tworzymy obiekt klasy Group i jako argumenty wypisujemy po kolei wszystkie pozycje tablicy elementy:
var grupa = new Group(
elementy[0],
elementy[1],
elementy[2],
elementy[3],
elementy[4],
elementy[5],
elementy[6],
elementy[7],
elementy[8]
);
oraz dodajemy zdarzenie do nowo utworzonego obiektu:
grupa.addEvent("emptydrop",function(){
$("dobro").remove();
$("zuo").remove();
$("content").setHTML("Usunąłeś/aś wszystkie divy i nie ma już co przenosić...");
});
Warto zapamiętać, że zdarzenie emptydrop nie posiada przedrostka "on" (przy innych zdarzeniach musimy ów przedrostek zapisać). A kod funkcji powinien być już chyba dla każdego zrozumiały :)
No to teraz usuńcie wszystkie elementy z obszaru dobra i zła :D
I to by było właściwie wszystko o tym prostym pluginie. Może jeszcze dodam, że możemy za jego pomocą monitorować kilka zdarzeń dla danej grupy - w tym wypadku oczywiście wywołujemy metodę addEvent odpowiednią ilość razy.
Kolejnym omawianym pluginem będzie SmoothScroll.js
Mootools 1.11 - SmoothScroll.js do góry
Plugin smoothscroll.js to chyba najprostszy składnik sekcji plugins - zawiera klasę, która nie posiada żadnych metod, które możemy użyć. Użycie klasy SmoothScroll sprowadza się do jej inicjalizacji.
Służy ona do łatwego stworzenia efektu przewijania dokumentu przy naciśnięciu kotwicy (czyli linka prowadzącego do innego miejsca w tym samym dokumencie).
Jedynym argumentem pobieranym przez tą klasę jest obiekt opcji, które dziedziczy ona po klasie Fx.Scroll. Dodatkowo posiada ona jedną opcję własną - links, która jest ciągiem znaków odpowiadającym selektorowi CSS. Opcji links używamy w momencie, gdy chcemy zdecydować, które kotwice mają przewijać się płynnie do miejsca docelowego. Domyślnie klasa SmoothScroll przypisuje ten efekt, do wszystkich kotwic w dokumencie.
Pozwolę sobie zaprezentować dwa przykłady - jeden w którym wszystkie kotwice będą płynnie przewijały dokument i drugi w którym efekt ten wystąpi tylko na określonych kotwicach.
Składnia klasy SmoothScroll wygląda następująco:
new SmoothScroll({opcje});
A dodanie efektu do wszystkich linków w dokumencie wymaga tylko zapisu:
new SmoothScroll();
Oczywiście kod ten umieszczamy w zdarzeniu onload obiektu window.
I zaprezentowany kod w akcji:
A teraz sprawimy, że efekt przewijania pojawi się tylko w wypadku linków należących do klasy efekt:
new SmoothScroll({links: "a.efekt"});
Zmiany można obejrzeć w poniższym przykładzie (płynnie przewijają się linki do drugiego i czwartego paragrafu ):
I tym sposobem omówiliśmy ten prościutki, ale według mnie przydatny plugin :)
W kolejnej części kursu opiszę plugin slider.js .
Mootools 1.11 - Slider.js do góry
Wraz z tą częścią kursu rozpoczynamy dwuczęściowe dokształcanie się w dziedzinie przewijania elementów. Plugin slider.js służy do tworzenia paska przewijania. Sam pasek jest tworzony przez klasę Slider, która na podstawie informacji o elementach tworzy go.
Do stworzenia paska przewijania potrzebujemy zaledwie dwóch elementów - dwóch divów z których jeden jest zagnieżdżony w drugim. Ten zagnieżdżony będzie służył do przewijania, a ten nadrzędny będzie ścieżką dla przewijanego w nim diva.
Klasa Slider jest dość rozbudowana w stosunku do już poznanych pluginów - posiada 3 własne opcje, jedną metodę, 3 zdarzenia, a przy inicjalizacji pobiera 3 argumenty (a więc małe odstępstwo od dotychczasowych reguł - zwykle klasa związana z efektami pobierała dwa argumenty).
Zaczniemy od teorii, a następnie zajmiemy się stworzeniem dwóch pasków przewijania - poziomego i pionowego.
Składnia klasy Slider jest ściśle związana z budową samego paska przewijania:
var pasek = new Slider("sciezka","galka",{opcje});
gdzie zmienna "sciezka" to oczywiście identyfikator ścieżki po jakiej będzie można poruszać elementem posiadającym identyfikator przypisany do zmiennej "galka". Obiekt opcji to oczywiście dodatkowe parametry klasy i zdarzenia:
steps- opcja ta definiuje ilość miejsc na ścieżce w których przy przesuwaniu gałki wystąpi zdarzenieonChange(domyślna wartość to 100),mode- opcja w której możemy zdecydować o typie paska przewijania - poziomy ("horizontal" - wartość domyślna) lub pionowy ("vertical"),offset- dzięki temu parametrowi możemy określić jak daleko (w pikselach) poza ścieżkę może wyjść podczas przesuwania nasza gałka - jest opcja raczej o znaczeniu estetycznym. Domyślna wartość to 0.onChange- zdarzenie to występuje w momencie przemieszczenia się gałki. Jego częstotliwość zależy od opcjisteps. W tym zdarzeniu definiujemy to co ma się dziać w czasie przemieszczania gałki.onComplete- zdarzenie, które pojawi się w momencie zakończenia przesuwania gałki.onTick- to zdarzenie określa co stanie się gdy użytkownik kliknie w dowolnym miejscu ścieżki. Domyślnie do miejsca kliknięcia zostaje przesunięta gałka.
I pozostaje nam metoda set. Jest ona bardzo prosta w użyciu - przy wywołaniu jako argument pobiera miejsce do jakiego ma się przesunąć gałka (oczywiście argument ten należy do przedziału [0, steps] ):
pasek.set(0);
Powyższy kod ustawi gałkę na początku ścieżki.
Jak widzimy klasa Slider oddaje nam do dyspozycji wszystkie narzędzia niezbędne do stworzenia pełnowartościowego paska przewijania. Tak naprawdę możnaby się pokusić o stworzenie odpowiednika standardowego paska przewijania, jednak złożoność tego zagadnienia (trzeba uwzględnić przytrzymywanie przycisków góra/dół czy poruszanie rolką myszki w obrębie przewijanego elementu i nad paskiem, długość gałki do przewijania zależna od ilości treści w elemencie), sprawia, że skupimy się na prostszych przykładach. Warto jednak mieć świadomość, że dzięki klasie Slider istnieje możliwość stworzenia nietypowego paska przewijania, które z reguły spotykamy w animacjach flash.
Nasze przykłady zaczniemy od poziomego paska przewijania - będziemy przewijać div z bardzo długim tekstem, którego widoczność została ograniczona przez parametr overflow.
Jeśli chodzi o kod XML to wystarczy nam wiedza, że identyfikatory elementów są takie same jak w przypadku prezentowanej składni klasy Slider, a przewijany element ma identyfikator "przewijany".
Zaczynamy od pobrania danych o przewijanym elemencie po to by móc ustalić wartość niektórych opcji klasy Slider:
var rozmiary = $("przewijany").getSize();
Interesuje nas długość elementu na której podstawie określimy wartość opcji steps. Przyjmijmy, że przewinięcie będzie powodowało przesunięcie o 5 pikseli:
var s = (rozmiary.scrollSize.x/5).round();
Jak widzimy zaokrąglamy wynik dzielenia długości elementu przez wartość pojedynczego przesunięcia, a następnie w wypadku gdy wartość długości przewijanego elementu nie była podzielna przez 5, zwiększamy zmienną s o jeden:
if(rozmiary.scrollSize.x > s){
s++;
}
Teraz możemy już przejść do samej klasy Slider:
var pasek = new Slider("sciezka","galka",{steps: s});
Pozostaje jeszcze dodać zdarzenie onChange i metodę set:
var pasek = new Slider("sciezka","galka",{
steps: s,
onChange: function(step){
$("przewijany").scrollTo(step*5,0);
}
}).set(0);
Jak widzimy zdarzenie onChange pobiera jako argument aktualną pozycję gałki. Powyższy kod umieszczamy oczywiście w zdarzeniu onload obiektu window i już możemy podziwiać pasek przewijania w akcji:
To teraz pora na to samo tylko, że pionie i z paroma dodatkami.
Po pierwsze - pierwsza linijka pozostaje bez zmian - nadal musimy mieć dostęp do rozmiarów elementów:
var rozmiary = $("przewijany").getSize();
W kolejnych linijkach zmienia się tylko x na y:
var s = (rozmiary.scrollSize.y/5).round();
if(rozmiary.scrollSize.y > s){
s++;
}
Także klasę Slider inicjujemy w podobny sposób, zmienia się kod zdarzenia onChange i dodajemy opcję mode:
var pasek = new Slider("sciezka","galka",{
steps: s,
mode: "vertical",
onChange: function(step){
$("przewijany").scrollTo(0,step*5);
}
}).set(0);
A dokładniej odwróceniu ulegają argumenty metody scrollTo.
Żeby nie było tak nudno to dodamy jeszcze przyciski góra/dół, ale tylko z reakcją na jednokrotne kliknięcie (bez trzymania) - tworzymy dwa przyciski posiadające identyfikatory "gora" i "dol" i dodajemy do nich zdarzenia onclick. Aby zdobyć informację o aktualnym położeniu gałki korzystamy w właściwości step klasy Slider:
$("gora").addEvent("click",function(){
pasek.set(this.step++);
});
$("dol").addEvent("click",function(){
pasek.set(this.step--);
});
No tylko pojawia się teraz mały problem, bo przez klikanie przycisków możemy przekroczyć zakres [0, steps] - trzeba się przed tym zabezpieczyć:
$("gora").addEvent("click",function(){
if(pasek.step > 0){
pasek.set(pasek.step-1);
}
});
$("dol").addEvent("click",function(){
if(pasek.step < pasek.options.steps){
pasek.set(pasek.step+1);
}
});
Teraz już powinno być bezpiecznie :)
I cały powyższy kod w akcji:
W ten oto sposób przebyliśmy połowę drogi naszego dokształcania się w dziedzinie przewijania elementów :) Drugą połowę przebędziemy podczas omawiania pluginu Scroller.js ;)
Mootools 1.11 - Scroller.js do góry
Pora zakończyć tematykę przewijania elementów z użyciem frameworka mootools. Dziś skupimy się na kursorze myszki i pluginie scroller.js. Ów plugin zawiera jak się pewnie domyślacie klasę Scroller, która służy do przewijania elementów, których zawartość jest po części ukryta dzięki atrybutowi overflow. Klasa ta odczytuje położenie kursora myszki i na tej podstawie przewija dany element. Pewnie każdy kojarzy pewną funkcjonalność Google Maps pozwalającą na "chwycenie" w pewnym punkcie mapki i jej przewijanie za pomocą poruszania kursorem do czasu "puszczenia" mapy. Na uzyskanie tego typu efektów pozwala właśnie klasa Scroller.
Składnia tej klasy jest typowa dla klas efektów:
var scroll = new Scroller(element,{opcje});
Jak widzimy, żadnych nowości w tym zakresie. Mamy do dyspozycji dwie opcje, jedno zdarzenie, a dodatkowo klasa Scroller posiada dwie kluczowe metody - start i stop. Ale zacznijmy od obiektu opcji:
area- jest to podawany w pikselach rozmiar swego rodzaju "ramki", która otacza od wewnątrz nasz przewijany element - jeżeli kursor znajdzie się nad jej obszarem to dopiero wtedy może zacząć przewijać element. Jest to więc grubość aktywnego obszaru przewijanego elementu. Domyślna wartość to 20 pikseli.velocity- opcja ta określa prędkość z jaką następuje przewijanie - domyślna wartość to 1.onChange- zdarzenie, które występuje w momencie przesunięcia kursora nad obszarem aktywnym określonym (jeśli chodzi o rozmiar) w opcji area. Domyślnie ma przypisaną pewną funkcję więc trzeba ją podmienić tak by nie uniemożliwić działania klasy Scroller.
Jeśli chodzi o wspomniane metody - pierwsza (start) służy do rozpoczęcia przewijania (pod warunkiem, że kursor porusza się nad obszarem aktywnym, poza nim nic się nie stanie), a druga (stop) do jego przerwania.
Mamy zasadniczo dwie główne możliwości wykorzystania tych metod, które przedstawię w przykładach.
Na początek przyjmijmy, że mamy element typu div z mapką w środku - mapka jest dużo większa od elementu nadrzędnego więc nie mieści się cała w tymże elemencie. Trzeba jakoś zorganizować przewijanie. Zaczniemy od wersji gdzie aby móc przewijać trzeba przytrzymać lewy przycisk myszy.
Tworzymy naszą instancję klasy Scroller i ustawiamy grubość obszaru aktywnego na 200 pikseli:
var przewijanie = new Scroller("przewijany",{area: 250});
I to już właściwie jedna trzecia całego kodu :) Teraz tylko dodajemy do przewijanego elementu zdarzenia mouseup i mousedown wraz z odpowiednimi funkcjami:
$("przewijany").addEvent("mousedown", function(){przewijanie.start();});
$("przewijany").addEvent("mouseup", function(){przewijanie.stop();});
Jak widać przy wciśnięciu przycisku myszy rozpoczynamy przewijanie, a kończymy je wraz z puszczeniem tego przycisku.
Oczywiście cały kod ląduje w zdarzeniu onload obiektu window (będę to powtarzał do upadłego, aż niektórzy przestaną popełniać ten irytujący błąd :P ) i już możemy oglądać nasz kod w akcji:
Proste ? Drugi przykład będzie bardzo podobny - zmieniają się tylko zdarzenia i obszar aktywny:
var przewijanie = new Scroller("przewijany",{area: 100, velocity: 1});
$("przewijany").addEvent("mouseover", function(){przewijanie.start();});
$("przewijany").addEvent("mouseout", function(){przewijanie.stop();}
Jak widzimy w drugim wypadku aktywacja przewijania następuje w momencie znalezienia się kursora nad przewijanym elementem, a kończy się po opuszczeniu go przez kursor. Zmniejszyłem obszar aktywny bo im byłby on większy tym bardziej irytujące byłoby przewijanie :)
I kod w akcji:
Plugin scroller.js jest jak mogliście zauważyć prościutki w użytku, a daje przyjemne efekty ;) I to już wszystko co mogłem napisać o przewijaniu elementów w mootools. W następnej części kursu zajmiemy się pluginem sortables.js związanym z techniką drag'n'drop.
Mootools 1.11 - Sortables.js do góry
Zajmiemy się dziś tworzeniem dającej się posortować grupy elementów - z pomocą przyjdzie nam plugin sortables.js . Plugin ten zawiera klasę Sortables, która w procesie tworzenia docelowego efektu odwali za nas czarną robotę - my musimy jedynie określić kilka opcji i argumentów. Lista (uporządkowana, nieuporządkowana, ewentualnie lista definicji) wydaje się w wypadku tego pluginu najbardziej odpowiednim elementem do uporządkowania.
Skupimy się więc na stworzeniu przykładu w którym użytkownik będzie mógł ustalić kolejność elementów listy nieuporządkowanej (mogłaby być to lista uporządkowana, ale wtedy mało logiczne wydaje się jej układanie w innej kolejności skoro jest już z założenia uporządkowana ;) ).
Klasa Sortables posiada trzy opcje i dwa zdarzenia. Składnia dobrze nam znana:
var sortowanie = new Sortables("lista",{opcje});
Jeśli chodzi o wspomniane opcje i zdarzenia:
handles- kolekcja elementów, która będzie służyć do "uchwycenia" elementów. Domyślnie cały element listy stanowi "uchwyt".snap- opcja określająca odległość jaką musi przebyć kursor by rozpoczęło się przenoszenie elementu.onStart- zdarzenie występujące przy rozpoczęciu przenoszenia elementu.onComplete- zdarzenie, które występuje po "upuszczeniu" elementu.
Teorii jak widać do opanowania mamy niewiele - pora na przykład. Na początek najprostsza sytuacja, kiedy to musimy jedynie określić element listy:
var sortowanie = new Sortables("lista");
W połączeniu z odpowiednim kodem XML i CSS zawierającym element ul posiadający identyfikator "lista", otrzymamy:
Niewiele trudniejsze będzie dodanie uchwytów do elementów list - uchwytami będą w naszym przypadku wszystkie elementy klasy uchwyt:
var sortowanie = new Sortables("lista",{handles: ".uchwyt"});
I powyższy kod w akcji :
Żeby nie było tak prosto to pora na bardziej złożony przykład - sortowanie to jedno, ale po sortowaniu często występuje potrzeba zapisania nowej kolejności elementów - ja przedstawię jeden ze sposobów na odczytanie nowej kolejności elementów, kwestia zapisu pominę bo jest ona zależna od indywidualnych potrzeb.
Klasa Sortables oferuje nam bardzo przydatną metodę serialize - zwraca nam ona tablicę zawierającą numery elementów na danych pozycjach listy - jeżeli na przykład przeniesiemy piąty element na drugą pozycję to po wywołaniu drugiego elementu tablicy (czyli indeks równy 1) zostanie zwrócona liczba 4.
Wykorzystajmy zatem tą metodę i zdarzenie onComplete do pokazywania aktualnej kolejności elementów.
Zaczynamy od kodu użytego w poprzednim przykładzie:
var sortowanie = new Sortables("lista",{handles: ".uchwyt"});
musimy teraz stworzyć zdarzenie onComplete - funkcja musi odczytać kolejność elementów i wyświetlić je na odpowiedniej liści uporządkowanej. Nasza lista uporządkowana będzie posiadać pozycje przypisane do klasy "kolejnosc".
var sortowanie = new Sortables("lista",{
handles: ".uchwyt",
onComplete: function(){
var tab = sortowanie.serialize();
tab.each(function(element,index){
$$(".kolejnosc")[index].setHTML("<strong>" + element + "</strong>");
});
}
});
Dodane linijki po przeniesieniu każdego elementu tworzą tablicę z użyciem metody serialize klasy Sortables. Następnie dla każdego elementu stworzonej tablicy jest wykonywana operacja przypisania wartości danej pozycji jako treści kolejnych pozycji listy uporządkowanej.
Powyższy kod w akcji:
Jak mogliście zauważyć z pluginem sortables.js stworzenie dającej się posortować listy jest niezwykle proste - nawet odczyt kolejności elementów wymaga niewiele kodu. W następnej części kursu poznamy plugin color.js .
Mootools 1.11 - Color.js do góry
Wraz z tą częścią kursu mootools poznamy kolejny plugin - color.js . Ta i dwie następne części kursu skupią się na zagadnieniach teoretycznych - do testów wykorzystamy tym razem konsolę JavaScript. Jak sama nazwa wskazuje omawiany plugin służy on do operowania na kolorach. Zawiera on klasę Color, która posiada 5 metod, dodatkowo w pliku znajdują się dwie metody konwertujące tablice oraz dwie funkcje będące skrótami do tworzenia instancji klasy Color.
Klasa Color wspiera trzy formy zapisu barw - heksadecymalną, RGB i HSB. Sama klasa przy inicjalizacji tworzy tablicę na której można później operować odpowiednimi metodami. Mamy do dyspozycji 5 metod operujących na kolorze:
mix- metoda mieszająca dowolną ilość kolorów - jako argument podajemy dowolną ilość kolorów wygenerowanych poprzez klasęColoroddzielonych przecinkami. Ponadto jeżeli jako ostatni "kolor" podamy wartość numeryczną to będzie to procentowa wartość parametrualphaokreślającego w jakich proporcjach zostaną zmieszane kolory - bliżej przyjrzymy się temu zagadnieniu niedługo.invert- metoda tworząca z danego koloru kolor do niego przeciwny (odwraca kolor).setHue- metoda pozwalająca zmienić odcień danego koloru - jako argument przyjmuje wartość odcieniu (od 0 do 255)setSaturation- metoda określająca nasycenie koloru - nasycenie podajemy w procentach.setBrightness- metoda do określania jasności kolorów, podobnie jak w wypadku poprzedniej metody jako argument podajemy wartość procentową (oczywiście w obu wypadkach bez znaku %).
Oprócz wspomnianych metod mamy jeszcze do dyspozycji funkcje skracające tworzenie koloru:
$RGB- jako argumenty przyjmuje kolejne wartości składowych opisujących kolor w formacie RGB,$HSB- jak wyżej tylko tym razem chodzi o format HSB.
I pozostały nam jeszcze dwie nowe metody obiektu Array:
rgbToHsb - metoda konwertująca format RGB na format HSB,
hsbToRgb - metoda konwertująca format HSB na RGB.
Obie wyżej wymienione metody jako argument przyjmują tablicę składowych koloru w danym formacie.
Pora na praktykę. Jak już wspominałem posłużymy się dziś konsolą JavaScript. Zdaje sobie jednak sprawę, że tylko Firefoks ma to narzędzie zaimplementowane - nie zostawię jednak użytkowników Opery i IE (są tacy :>) na pastwę losu ;) Przygotowałem maleńki (3 linijki JS z czego dwie odpowiadają za dodanie zdarzenia onload obiektu window) skrypt, który symuluje konsolę JavaScript:
Konsola JS [prawie jak konsola :P]
Ale zacznijmy od podstaw - stwórzmy nasz pierwszy kolor z użyciem plugina color.js, niech będzie to kolor zielony - możemy go stworzyć na trzy sposoby :
var zielony = new Color("#008000");
var zielony = new Color([0,128,0]);
var zielony = new Color([120,100,50],"hsb");
Każdy z powyższych zapisów definiuje kolor zielony - pierwszy to zapis heksadecymalny, drugi to format RGB, a ostatni to format HSB.
UWAGA użytkownicy IE ;) W poniższych przykładam document.body zamieńcie na $("run") - Wasza przeglądarka ma jakieś dziwne problemy z document.body i metodą setStyle (razem wziętymi) więc musicie zadowolić się zmianą koloru tła przycisku (jaka przeglądarka taki efekt xD).
Pora na pierwszy kod "użytkowy" ;) Do konsoli JS kopiujemy poniższy kod:
var zielony = new Color("#008000");
document.body.setStyle( 'background-color', zielony);
Powyższy kod tworzy kolor zielony, a następnie ustawia go jako kolor tła strony.
Na razie mało praktyczne było nasze pierwsze użycie klasy Color - przecież mogliśmy dodać po prostu w miejsce zmiennej zielony zapis heksadecymalny. Sytuacja zmienia się w momencie gdy potrzebujemy pokombinować z kolorami. Powiedzmy, że chcemy zobaczyć co wyjdzie z mieszanki zielony + pomarańczowy:
var zielony = new Color("#008000");
var pomaranczowy = new Color("#FFA500");
zielony = zielony.mix(pomaranczowy);
document.body.setStyle( 'background-color', zielony);
Powyższy kod najpierw tworzy dwa kolory - zielony i pomarańczowy. Następnie korzystamy z metody mix o następującej składni:
kolor_bazowy.mix(kolor_1, kolor_2, kolor_3, ... , kolor_n, alpha);
gdzie zmienna alpha jest opcjonalna.
W efekcie tło powinno się zmienić na ładny według mnie odcień zieleni :)
I jeszcze jedno - domyślna wartość zmiennej alpha wynosi 50 w wypadku jednego koloru i spada w wypadku większej liczby kolorów - chodzi o to, że mieszamy w ten sposób kolory pół na pół - w pozostałych wypadkach każdy kolor stanowi taką samą część końcowego koloru co pozostałe kolory składowe.
Zresztą co ja będę się rozpisywał - dodajcie do linijki:
zielony = zielony.mix(pomaranczowy);
nowy argument i zmieniajcie go do woli patrząc jak wpływa on na kolor tła strony ;)
Oczywiście możecie dodać kolejne kolory i mieszać do woli - to są właśnie zalety konsoli ;) [koniec rymowania :P]
Pora na kolejną metodę - invert. Jak wspominałem służy ona odwracaniu kolorów. Biały zamienia na czarny i odwrotnie. Pozostańmy przy kolorze zielonym i zapiszmy:
var zielony = new Color("#008000");
zielony = zielony.invert();
document.body.setStyle('background-color', zielony);
Efekt powinien troszkę porażać ;)
Oczywiście nic nie stoi na przeszkodzie do tworzenia większych miksów:
var zielony = new Color("#008000");
var pomaranczowy = new Color("#FFA500");
zielony = zielony.mix(pomaranczowy).invert();
document.body.setStyle( 'background-color', zielony);
Nie ma to jak zamieszać i wywrócić wszystko do góry nogami (bardzo często spotykane w pewnych grupach ludzi :P) ;)
Oczywiście dalszą inwencję twórczą pozostawiam w tej kwestii Wam - w końcu możecie sami wybrać co chcecie zrobić...
Pora zająć się formatem HSB i operowaniem na jego poszczególnych wartościach - metody setHue, setSaturation i setBrightness są banalne w użyciu więc zabierzemy się za wszystkie naraz - od czego mamy chaining:
var zielony = new Color("#008000").setHue(10).setSaturation(200).setBrightness(200);
document.body.setStyle( 'background-color', zielony);
Jak ktoś jest bardzo dociekliwy to sam sobie usunie odpowiednie części łańcucha i zobaczy jak co działa (gdyby przypadkiem nazewnictwo nie oddziaływało wystarczająco na wyobraźnie ;) ).
Także życzę miłej zabawy z kolorami, bo wiecie już w zakresie mieszania i wpływania na cechy koloru wszystko co powinniście wiedzieć (przynajmniej w przypadku pluginiu color.js).
Myślę, że pozostałe funkcje (te skracające jak i metody obiektu Array) nie wymagają dodatkowego komentarza, a i ich działanie z punktu "efektowności" nie ma większego znaczenia - przydają się głównie przy prezentacji/operowaniu na danych i skracaniu kodu.
Mam nadzieję, że operowcy i użytkownicy IE zaprzyjaźnili się już z konsolą JS - jeszcze dwie części kursu nas z nią czekają ;)
W następnej części kursu omówię plik Hash.js .
Mootools 1.11 - Hash.js do góry
Zajmiemy się dziś pluginem hash.js - służy on do operowania na obiektach. Wraz z klasą Hash dostajemy do dyspozycji 10 metod operujących na obiektach. Dzięki nim możemy zmieniać właściwości obiektów, rozszerzać obiekty itd.
Ta część kursu jak i następna będzie przebiegała według podobnego schematu jak poprzednia część kursu na temat pluginu color.js - zatem wszystkie przykłady wykonamy z użyciem konsoli JavaScript - użytkowników Opery i IE odsyłam do namiastki konsoli:
Zacznijmy od omówienia metod klasy Hash:
get- metoda ta zwraca nam wartość pola o danej nazwie.hasKey- metoda sprawdzająca czy dane pole występuje w danym obiekcie.set- dzięki tej metodzie stworzymy nowe pole obiektu lub nadpiszemy już istniejące.remove- metoda ta usuwa dane pole z obiektu.each- metoda określająca funkcję, która wykona się dla każdego pola obiektu.extend- metoda rozszerzająca dany obiekt o inny.merge- metoda służąca do łączenia danego obiektu z innymi obiektami.empty- metoda ta "czyści" nasz obiekt pól i wartości.keys- metoda zwracająca nazwy pól jako tablicę.values- metoda działająca analogicznie do poprzedniej z tą różnicą, że zwraca wartości pól w tablicy.
Jak widzimy metod jest sporo, a sam obiekt klasy Hash możemy tworzyć na dwa sposoby - tradycyjnie:
var obj = new Hash({obiekt});
oraz przez funkcję-skrót $H :
var obj = $H({obiekt});
Zmienna {obiekt} to oczywiście dowolny obiekt JavaScript.
Tyle z teorii, pora na praktykę - na początek stworzymy prosty obiekt opisujący naszą osobę:
{
imie: "Tomek",
nick: "Dziudek"
}
Teraz przeróbmy go na instancję klasy Hash:
var mojeDane = new Hash({imie: "Tomek",nick: "Dziudek"});
Pora na użycie konsoli w akcji - pobierzmy wartość pola "imie" i wyświetlmy ją w alercie (lub jak kto woli gdzieś indziej - konsola i cały mootools do dyspozycji ;) ):
var mojeDane = new Hash({imie: "Tomek",nick: "Dziudek"});
alert(mojeDane.get("imie"));
To teraz sprawdźmy czy przypadkiem w naszym obiekcie znajduje się pole "mail":
var mojeDane = new Hash({imie: "Tomek",nick: "Dziudek"});
alert(mojeDane.hasKey("mail"));
Zobaczymy wartość false w alercie. Pora to zmienić - stwórzmy pole mail i nadajmy mu odpowiednią wartość:
var mojeDane = new Hash({imie: "Tomek",nick: "Dziudek"});
mojeDane.set("mail","dziudek@test.pl");
alert(mojeDane.hasKey("mail"));
Jak widzimy metoda set jako pierwszy argument pobiera nazwę pola, a jako drugi argument wartość tego pola.
Pora wyrzucić pole "imie" (po co macie je znać :P ):
var mojeDane = new Hash({imie: "Tomek",nick: "Dziudek"});
mojeDane.remove("imie");
alert(mojeDane.hasKey("imie"));
A teraz wyświetlmy wartość wszystkich pól obiektu w alertach (lub jak gdzie kto woli - konsola = wybór ;) ):
var mojeDane = new Hash({imie: "Tomek",nick: "Dziudek"});
mojeDane.each(function(element,index){
alert(this[index]);
});
Jak widzimy składnia metody each jest podobna do składni metody forEach obiektu Array.
Pora do naszego obiektu dorzucić trochę więcej danych naraz (po co się męczyć z metodą set przy większej ilości danych ?):
var mojeDane = new Hash({imie: "Tomek",nick: "Dziudek"});
mojeDane.extend({mail: "dziudek@test.pl",gg: "8769415",jabber:"dziudek@jabber.org"});
mojeDane.each(function(element,index){
alert(this[index]);
});
To teraz scalmy kilka obiektów naraz:
var mojeDane = new Hash({imie: "Tomek",nick: "Dziudek"});
var kontakt = {mail: "dziudek@test.pl",gg: "8769415",jabber:"dziudek@jabber.org"};
var strony = {www1: "dziudek.jogger.pl",www2: "dziudek.n3o.pl"};
mojeDane.merge(kontakt,strony);
mojeDane.each(function(element,index){
alert(this[index]);
});
Jak widzimy metoda merge jako argumenty przyjmuje ciąg obiektów.
Po tym wszystkim wypadałoby posprzątać :
var mojeDane = new Hash({imie: "Tomek",nick: "Dziudek"});
var kontakt = {mail: "dziudek@test.pl",gg: "8769415",jabber:"dziudek@jabber.org"};
var strony = {www1: "dziudek.jogger.pl",www2: "dziudek.n3o.pl"};
mojeDane.merge(kontakt,strony);
mojeDane.each(function(element,index){
alert(this[index]);
});
mojeDane.empty();
mojeDane.each(function(element,index){
alert(this[index]);
});
Pora na poznanie nazw wszystkich pól i ich wartości :
var mojeDane = new Hash({imie: "Tomek",nick: "Dziudek"});
var kontakt = {mail: "dziudek@test.pl",gg: "8769415",jabber:"dziudek@jabber.org"};
var strony = {www1: "dziudek.jogger.pl",www2: "dziudek.n3o.pl"};
mojeDane.merge(kontakt,strony);
var k = mojeDane.keys();
var v = mojeDane.values();
var kk = "";var vv = "";
k.each(function(el){kk += el + ", "});
v.each(function(el){vv += el + ", "});
alert("Nazwy pól: "+kk+"\nWartości pól: "+vv);
I w ten szybki sposób przebrnęliśmy przez klasę Hash. Jest ona według mnie bardzo przydatna bo tworzy swoistą mapę danego obiektu dzięki której odczytanie jego zawartości jest banalne. W następnej części kursu zajmiemy się plikiem hash.cookie.js bezpośrednio związanym z pluginem hash.js .
Mootools 1.11 - Hash.Cookie.js do góry
Przed nami ostatnia przygoda z konsolą JavaScript w tym kursie ;) Zajmiemy się pluginem hash.cookie.js . Jego zadaniem jest zapis i odczyt danych typu obiektowego z ciasteczek. Pewnie niektórzy pamiętają jak przy okazji omawiania sekcji Remote robiliśmy podobne rzeczy z formatem JSON. Omawiany plugin tworzy nam wygodny interfejs do tego typu operacji bo stanowi połączenie wygody operowania na obiektach jaką daje nam plugin hash.js oraz klas Cookie i Json. Sam plugin oferuje nam kilka dodatkowych udogodnień, które wcześniej musielibyśmy sami oprogramować - szczegóły omówię w części teoretycznej.
Oczywiście do celów badawczych posłuży nam JS - dla użytkowników Opery i IE namiastka tego co jest w Firefoksie:
Klasa Hash.Cookie będąca głównym składnikiem pluginu o tej samej nazwie posiada dwie własne metody:
save- metoda zapisująca obiekt w ciasteczku,load- metoda odczytujące dane z ciasteczka
Poza tym mamy do dyspozycji metody extend, set, merge, empty i remove znane z pluginu Hash.
Co do opcji to klasa Hash.Cookie ma jedną własną opcję - autoSave - jeżeli ma ona wartość true to po każdej zmianie obiektu, który mamy zamiar umieścić w ciasteczku, zostanie on automatycznie zapisany. Prawda, że wygodne ? Zamiast co chwila zapisywać "ręcznie" zmiany, skrypt robi to za nas :) Oczywiście nie polecam tego rozwiązania przy bardzo częstych modyfikacjach obiektu, ale w wypadku obiektów przechowujących konfigurację strony czy inne dane, które użytkownik zmienia względnie rzadko rozwiązanie w sam raz.
Pozostałe opcje to wszystko to co oferuje nam klasa Cookie.
Jest jeszcze jedna rzecz warta wspomnienia przed przejściem do zagadnień praktycznych - metoda save posiada bardzo przydatne zabezpieczenie. Jakie ? Otóż jak pewnie wiecie każde ciasteczko może przechowywać do 4kB danych. Metoda save w trakcie swojego działania zwraca nam wartość logiczną - jeżeli jest to true to dane zostały pomyślnie zapisane w ciasteczku, jeżeli jednak zwróci nam false oznacza to iż powstały ciąg znaków jest zbyt długi i nie został zapisany w ciasteczku.
Obiekt, który zamierzamy zapisać w ciasteczku tworzymy w następujący sposób:
var obiekt = new Hash.Cookie("nazwa_ciasteczka", {opcje});
Myślę, że zmienne w prezentowanym przykładzie mówią same za siebie :)
Stwórzmy zatem nasz pierwszy obiekt, który chcielibyśmy zapisać w ciasteczku:
var dane = new Hash.Cookie("daneDziudka", {duration: 7200, path: "/"});
Po wykonaniu tego kodu mamy już pusty obiekt dane. Pora go zapełnić jakimiś informacjami:
var dane = new Hash.Cookie("daneDziudka", {duration: 7200, path: "/"});
dane.extend({
imie: "Tomek",
nick: "Dziudek",
mail: "dziudek@test.pl"
});
I oczywiście korzystamy z metody save po tym wszystkim by zapisać dane :
var dane = new Hash.Cookie("daneDziudka", {duration: 7200, path: "/"});
dane.extend({
imie: "Tomek",
nick: "Dziudek",
mail: "dziudek@test.pl"
});
dane.save();
Co bardziej nadgorliwi mogą od razu zrobić sprawdzanie czy przypadkiem nie za dużo upakowali do ciasteczka :
var dane = new Hash.Cookie("daneDziudka", {duration: 7200, path: "/"});
dane.extend({
imie: "Tomek",
nick: "Dziudek",
mail: "dziudek@test.pl"
});
var czyZapisano = dane.save();
alert((czyZapisano) ? "Dane zapisane !" : "Błąd zapisu: za dużo danych !");
Ponieważ jednak nie mamy ochoty co chwila wywoływać metody save, korzystamy z opcji autoSave:
var dane = new Hash.Cookie("daneDziudka", {autoSave: true,duration: 7200, path: "/"});
dane.extend({
imie: "Tomek",
nick: "Dziudek",
mail: "dziudek@test.pl"
});
Oczywiście opcja autoSave ma tą wadę, że nie pozwala nam sprawdzić czy dane się poprawnie zapisały. Ale spokojnie wystarczy jedna linijka i wszystko będzie jasne:
(Json.toString(dane).length > 4096) ? false : true;
Oczywiście jak poinformujecie użytkownika o rezultacie operacji zapisu zależy już od Was ;)
Co do metody load - w sumie raczej jej nie użyjecie "ręcznie", bo jest ona wywoływana przy inicjalizacji obiektu klasy Hash.Cookie - zatem jeżeli dane ciasteczko już istnieje to nasza zmienna od razu będzie obiektem o zawartości wcześniej zapisanym w ciasteczku. Uruchamiamy w konsoli poniższy kod:
var dane = new Hash.Cookie("daneDziudka", {autoSave: true});
dane.extend({
imie: "Tomek",
nick: "Dziudek",
mail: "dziudek@test.pl"
});
a następnie odświeżamy stronę i uruchamiamy kod:
var dane = new Hash.Cookie("daneDziudka", {autoSave: true});
alert(dane.get("mail"));
Powinniśmy w alercie zobaczyć "dziudek@test.pl". Oczywiście możecie w konsoli sprawdzić wszystko po kolei lub w pętli lub na jeszcze inne sposoby - wybór należy do Was :)
To wszystko o pluginie hash.cookie.js - w następnej części kursu zajmiemy się pluginem tips.js .
Mootools 1.11 - Tips.js do góry
Po bardziej teoretycznych rozważaniach pora znów zająć się czymś efektownym :) Tym razem padło na plugin tips.js służący do generowania ładnych "dymków". Nie ukrywam, że sprawa przydatności tego typu skryptów jest troszkę kontrowersyjna - jednej osobie będą się bardzo podobać ładnie pojawiające się i znikające informacje, a druga osoba uzna to za zbędny gadżet . Warto pamiętać, że IE często oprócz efektownych dymków pokazuje także własne dymki, co wygląda dość brzydko - na pocieszenie dodam iż dotyczy to tylko atrybutu alt w grafikach - plugin tips.js usuwa atrybut title po wygenerowaniu dymków. Ja osobiście stosuję warunek z window.ie by uniknąć problemów w niektórych miejscach by wyłączyć wtedy dymki. Oczywiście ktoś kto ma więcej czasu po prostu w IE pousuwa atrybuty alt z wybranych obrazków (korzystając również z window.ie) "w locie".
Cały plugin tips.js tworzy klasa Tips, która nie posiada żadnych metod, jednak posiada bardzo dużo opcji. Składnia klasy Tips wygląda następująco:
var dymki = new Tips($$("kolekcja_elementow"), {opcje});
zmienna kolekcja_elementow to oczywiście selektor CSS, który oznacza wszystkie elementy dla jakich chcemy stworzyć "dymki", obiekt {opcje} to oczywiście pozostałe parametry klasy Tips.
Opcje klasy Tips:
maxTitleChars- opcja ta określa maksymalną długość tytułu dymka. Warto dodać, że w atrybucietitledanego elementu wszystko co jest umieszczone przed podwójnym dwukropkiem "::" oznacza tytuł dymka. Wszystko po oznacza treść dymka.showDelay- opóźnienie pojawiania się dymka w milisekundach.hideDelay- opóźnienie ukrywania dymka w milisekundach.className- nazwa klas stosowanych w stylach CSS. Domyślna wartość to "tool". Poszczególne klasy są tworzone następująco :className+ sufiks "-tip" - klasa całego dymka,className+ sufiks "-title" - klasa tytułu dymka,className+ sufiks "-text" - klasa treści dymka .offsets- obiekt określający odległość dymka od kursora. Oczywiście obiekt ma postać:{x : wartość, y : wartość}fixed- wartość logiczna określająca czy dymek ma podążać za kursorem (false), czy też pozostać w jednej pozycji (true)
Dodatkowo mamy do dyspozycji dwa zdarzenia:
onShow- zdarzenie występujące w momencie pojawienia się dymka,onHide- zdarzenie występujące podczas ukrywania dymka.
Pora na praktykę - zacznijmy od stworzenia najprostszego dymka, który pojawi się po najechaniu na wybrane akronimy w tekście - tworzymy podstawowy kod klasy Tips, a jako kolekcja elementów posłużą nam wszystkie elementy ACRONYM:
var dymki = new Tips($$("acronym"));
Po małej stylizacji poprzez stworzeniu w pliku CSS klas tool-tip, tool-title oraz tool-text uzyskamy następujący efekt:
Pora na małe ulepszenia naszego dymka - dodajmy opóźnienie pojawiania się dymka i ustalmy inną odległość dymka od kursora:
var dymki = new Tips($$("acronym"), {
showDelay: 500,
offsets: {x: 10, y: 10}
});
Powyższy kod spowoduje zmiany widoczne w następnym przykładzie:
A teraz zanim przejdziemy do bardziej złożonego przykładu, wykorzystajmy w praktyce opcję fixed:
var dymki = new Tips($$("acronym"), {
showDelay: 500,
offsets: {x: 10, y: 10},
fixed: true
});
I powyższy kod w akcji:
Pora skorzystać ze zdarzeń jakie oferuje klasa Tips - stwórzmy dymki, które zawierają dużą ilość treści i animują się z efektem zmiany przezroczystości podczas pojawiania się i znikania. Do podstawowego kodu klasy Tips dodajemy zdarzenia onShow i onHide oraz definicję efektu:
var dymki = new Tips($$("acronym"), {
onShow: function(toolTip) {this.efekt.start(0,1);},
onHide: function(toolTip) {this.efekt.start(1,0);}
});
dymki.efekt = new Fx.Style(dymki.toolTip,"opacity",{wait: false});
Efekt jest według mnie interesujący:
I to by było na tyle jeżeli chodzi o mootoolsowe dymki :) W następnej części kursu omówię plugin accordion.js .
Mootools 1.11 - Accordion.js do góry
Oto i on - ostatni z pluginów mootools - chyba wiecie co to oznacza :) Muszę w tym miejscu dodać iż mam szczególny sentyment do tego plugina - to on jeszcze jako składnik biblioteki moo.fx i jej strony głównej sprawił, że zainteresowałem się najpierw wspomnianą biblioteką, a później samym mootools. Kto wie czy gdyby nie ten plugin to czy kurs mootools w ogóle by powstał :) Sam efekt, który oferuje do dziś robi na mnie wrażenie - ja po prostu akurat ten efekt uwielbiam i mam nadzieję, że Wy też go polubicie :)
Klasa Accordion pozwala nam na animację elementów w taki sposób, że po aktywowaniu danego elementu poprzedni element aktywny jest ukrywany. W ten sposób zawsze aktywny jest tylko jeden element.
Składnia klasy Accordion wygląda następująco:
var efekt = new Accordion("aktywatory", "elementy", {opcje}, $("kontener"));
Zmienna aktywatory to selektor CSS odnoszący się do kolekcji elementów po których kliknięciu dany element zostanie aktywowany. Zmienna elementy to to samo co zmienna aktywatory, ale dotyczy elementów zależnych od aktywatorów. Obiekt {opcje} to oczywiście pozostałe parametry klasy Accordion, a zmienna kontener to identyfikator elementu w jakim zawarte są składniki naszego elementu.
Opcje klasy Accordion:
show- opcja określająca, który element ma być rozwinięty po uruchomieniu skryptu. Jako wartość podajemy indeks elementu (numerowanie jak w tablicach czyli od 0),display- opcja działająca na tej samej zasadzie co opcja show z tą różnicą, że element jest rozwijany z animacją (w wypadkushowpo prostu się pojawia),fixedHeight- wartość określająca stałą wysokość rozwijanych elementów. Domyślnie (false) każdy element ma wysokość dostosowaną do ilości tekstu.fixedWidth- opcja tego samego typu cofixedHeighttyle, że dotyczy ona szerokości elementów.height- wartość logiczna określająca czy w animacji ma być stosowana zmiana wysokości elementu. Domyślnie opcja ta ma wartośćtrue.opacity- wartość logiczna określająca czy w animacji ma być stosowana zmiana przezroczystości elementu. Domyślnie opcja ta ma wartośćtrue.width- wartość logiczna określająca czy w animacji ma być stosowana zmiana szerokości elementu. Domyślnie opcja ta ma wartośćfalse. Opcja ta ma raczej zastosowanie w efektach poziomych podobnych do tych jakie prezentowałem przy okazji prezentacji klasyFx.Slide.alwaysHide- wartość logiczna określająca czy można zwinąć wszystkie elementy (true), czy też zawsze jeden element ma być rozwinięty (false).
Wszelkie operacje związane ze zmianą szerokości elementu w trakcie animacji mogą powodować pewne problemy związane z CSS i wyglądem elementów - osobiście polecam nie polecam tego typu animacji. Pokazałem już, że Fx.Slide może godnie zastąpić klasę Accordion w tej kwestii.
Zdarzenia klasy Accordion:
onActive- zdarzenie wywoływane w momencie rozwijania elementu.onBackground- zdarzenie wywoływane w momencie zwijania elementu.
Metody klasy Accordion:
addSection- metoda dodająca kolejny element efektu.display- metoda pozwalająca na aktywowanie danego aktywatora bez klikania go. Jej wadą jest fakt iż po dodaniu nowego elementu metodąaddSection, nadal poprzez indeksy odnosi się do podstawowych elementów bez uwzględnienia nowych.
Pora na praktykę :) Stworzymy efekt klasy Accordion najpierw wersji podstawowej, a później dodamy parę upiększeń ;)
Aktywatorami w naszym wypadku będą nagłówki drugiego poziomu klasy "toggler", a rozwijanymi elementami będą paragrafy klasy "element":
var efekt = new Accordion('h2.toggler', 'p.element');
Powyższa linijka spowoduje powstanie bardzo ładnego efektu - kliknijcie na jednym z paragrafów poniższego przykładu:
W powyższym przykładzie kliknięcie na rozwinięty paragraf nie spowoduje nic. Ale wystarczy dodać opcję alwaysHide i teraz kliknięcie na jakikolwiek nagłówek spowoduje animację (ukrywania lub pokazywania):
var efekt = new Accordion('h2.toggler', 'p.element', {
alwaysHide: true
});
I powyższy kod w akcji:
Ustalmy teraz stałą wysokość wszystkich rozwijanych elementów na 150 pikseli:
var efekt = new Accordion('h2.toggler', 'p.element', {
alwaysHide: true,
fixedHeight: 150
});
Dobrze by też było gdyby dla odmiany zamiast pierwszego rozwijał się jako pierwszy trzeci element:
var efekt = new Accordion('h2.toggler', 'p.element', {
alwaysHide: true,
fixedHeight: 150,
display: 2
});
Pora wykorzystać potencjał zdarzeń klasy Accordion - dodamy efekt zmiany koloru tła z szarego na biały dla aktywnego aktywatora - najpierw tworzymy podstawy zdarzeń onActive i onBackground:
var efekt = new Accordion('h2.toggler', 'p.element', {
alwaysHide: true,
fixedHeight: 150,
display: 2,
onActive: function(toggler){},
onBackground: function(toggler){}
});
Jak widać oba zdarzenia jako pierwszy argument przyjmują uchwyt do aktywatora. Warto dodać, że drugi argumentem może być rozwijany/zwijany element.
Ważne jest by do zmiany koloru tła wykorzystać klasę Fx.Styles ponieważ oferuje nam ona możliwość nie określania początkowej wartości zmienianej właściwości. W wypadku klasy Fx.Style animacja przebiegałaby od danego koloru do końcowego co w naszym wypadku spowodowałoby zmiany koloru wszystkich aktywatorów. A dzięki klasie Fx.Styles kolor pozostałych aktywatorów nie ulega zmianie bo animacja dąży od koloru podstawowego do końcowego więc w wypadku pozostałych aktywatorów kolor się po prostu nie zmienia:
var efekt = new Accordion('h2.toggler', 'p.element', {
alwaysHide: true,
fixedHeight: 150,
display: 2,
onActive: function(toggler){
new Fx.Styles(toggler).start({
"background-color" : "#FFF"
});
},
onBackground: function(toggler){
new Fx.Styles(toggler).start({
"background-color": "#EFEFEF"
});
}
});
I cały przykład w akcji:
Pozostało nam jeszcze omówić metody klasy Accordion. Metoda addSection jako pierwszy argument przyjmuje uchwyt do aktywatora, drugi argument to uchwyt do elementu rozwijanego, a trzeci argument to pozycja na jakiej ma się znaleźć nowy element po dodaniu do pozostałych elementów. Tworzymy przycisk "dodaj", który będzie dodawał nowy element do naszego efektu na pierwszej pozycji:
var efekt = new Accordion('h2.toggler', 'p.element', {
alwaysHide: true,
fixedHeight: 150,
display: 2,
onActive: function(toggler){
new Fx.Styles(toggler).start({
"background-color" : "#FFF"
});
},
onBackground: function(toggler){
new Fx.Styles(toggler).start({
"background-color": "#EFEFEF"
});
}
});
$("dodaj").addEvent("click",function(){
efekt.addSection(new Element('h2', {'class': 'toggler'}).appendText('Wstęp'), new Element('p', {'class': 'element'}).appendText('Kliknij na wybranym paragrafie by aktywować efekt klasy Accordion...'), 0);
});
Pozwoliłem sobie od razu tworzyć elementy zamiast tworzyć kolejne zmienne.
Dodajmy do tego wszystkiego przycisk, który aktywuje pierwszy paragraf:
var efekt = new Accordion('h2.toggler', 'p.element', {
alwaysHide: true,
fixedHeight: 150,
display: 2,
onActive: function(toggler){
new Fx.Styles(toggler).start({
"background-color" : "#FFF"
});
},
onBackground: function(toggler){
new Fx.Styles(toggler).start({
"background-color": "#EFEFEF"
});
}
});
$("dodaj").addEvent("click",function(){
efekt.addSection(new Element('h2', {'class': 'toggler'}).appendText('Wstęp'), new Element('p', {'class': 'element'}).appendText('Kliknij na wybranym paragrafie by aktywować efekt klasy Accordion...'), 0);
});
$("pokaz").addEvent("click",function(){
efekt.display(0);
});
W efekcie otrzymamy coś takiego:
I tym akcentem zakończyliśmy kurs frameworka MooTools 1.1(1) :) Mam nadzieję, że się przydało ;)