YUI 3 beta

Posted by Piotr Sarnacki Thu, 25 Jun 2009 14:46:00 GMT

We wczorajszym poście na blogu YUI ogłoszono wersję beta YUI3.

YUI (Yahoo User Interface) jest frameworkiem javascript rozwijanym przez YAHOO, który dostarcza nie tylko niskopoziomowe funkcje pomagające przy pisaniu kodu javascript, ale też zestaw komponentów (takich jak różnego rodzaju okienka dialog, color picker, czy nawet bardzo dobry edytor WYSIWYG). YUI jest dojrzałą biblioteką używaną na stronach YAHOO, co zapewnia bardzo dobrą jakość. Sam team YUI to jedni z najlepszych specjalistów od frontendu – zachęcam do czytania wpisów na ich blogu

To co najbardziej przekonywało mnie do używania YUI, to fakt dostarczenia całego zestawu narzędzi do budowania interfejsów użytkownika w javascripcie. W przypadku np. jQuery lekko może denerwować bardzo duże rozstrzelenie poszczególnych bibliotek. Są oczywiście takie projekty jak jqueryUI, ale większość pluginów trzeba ściągnąć z innych źródeł, a ich kod często pozostawia wiele do życzenia. W przypadku YUI mamy zwarty zestaw komponentów, łatwy do rozszerzania i rozwijany przez specjalistów w celu wykorzystania na stronach odwiedzanych codziennie przez miliony internautów.

Z drugiej strony to co było banalne w jQuery często było ciężkie do uzyskania w YUI. A jak wszyscy wiedzą jeżeli chodzi o zabawę z DOM, animacjami i ajaxem z jQuery jest ciężko wygrać. Dlatego gdy używałem komponentów YUI w jednym z projektów, w którym przy okazji używałem jQuery, to do manipulacji elementów DOM używałem jQuery, a z YUI wybierałem tylko komponenty.

Wersja trzecia YUI może to zmienić. Zespół z Yahoo postanowił przepisać bibliotekę zupełnie od nowa z naciskiem na lekkość i szybkość. Najważniejsze zmiany

  • zmienione API do manipulacji DOM, czyli “jQueryzacja” – łańcuchy komend, proste funkcje typu addClass, remove, append itp.
  • ułatwiona praca z eventami
  • modularyzacja biblioteki

Najbardziej obiecująco wygląda ostatni punkt. Do tej pory poszczególne komponenty nie były modularne, co prowadziło do powtarzającego się kodu w różnych komponentach. Dodatkowo jeżeli ktoś chciał stworzyć Tooltip dziedziczący po Overlay, to musiał wykorzystać wszystkie elementy, które Overlay zawiera. Jest to oczywiście zbędne wykorzystywanie pamięci i Tooltip, który jest obecnie dostępny w YUI właśnie z tego powodu nie jest najlepszą możliwą implementacją.

W YUI3 poszczególne funkcjonalności są rozbite do modułów. Dlatego, żeby zbudować wspomniany wyżej tooltip nie trzeba dziedziczyć po Overlay, tylko zmiksować (czy to nie brzmi znajomo?) na przykład: moduł pozycjonowania i moduł animacji. Dodatkowo można wmiksować poszczególne moduły nie tylko do klas, ale także instancji poszczególnych obiektów. Jeżeli będzie to rzeczywiście działało tak fajnie jak mówią programiści z YUI (polecam obejrzeć video ze zlinkowanego wcześniej posta), to YUI3 na pewno zagości w moich projektach.

To co najbardziej denerwuje mnie obecnie w różnego rodzaju bibliotekach do jQuery czy prototype, to całkowite oderwanie poszczególnych bibliotek od siebie. Używam na przykład jqueryUI i żeby użyć tooltipa, muszę ściągnąć zupełnie inną bibliotekę, która jest napisana zupełnie inaczej i nie dzieli żadnego kodu z innymi bibliotekami (tutaj też wychodzi swoboda javascriptu, jeżeli ktoś próbował porównywać implementacje różnych bibliotek, to na pewno wie na ile różnych sposobów można zaimplementować te same funkcje). Jeszcze gorzej jest gdy trzeba napisać własne komponenty – lekkość jQuery i brak oficjalnych bibliotek pomagających w takich wypadkach jest dość dużą przeszkodą.

W tym momencie YUI team zachęca programistów do używania YUI3 w nowych projektach, szczególnie tych, które nie planują wykorzystywać dużej ilości widgetów obecnych w YUI2. Oficjalna wersja ma być dostępna w 3 kwartale tego roku. Rozwój można biblioteki śledzić tutaj

Posted in  | Tags , , , ,  | no comments | no trackbacks

Jak użyć jQuery na stronie bez jQuery?

Posted by Piotr Sarnacki Thu, 06 Nov 2008 22:07:00 GMT

Czasami gdy chodzę po sieci chciałbym mieć możliwość wykonania jakiegoś kodu na stronie, na której aktualnie się znajduję. Do tego wystarczy konsola javascript w firebugu. Niestety można wtedy używać jedynie bibliotek, które są dołączone do strony. Co jeżeli nie ma tam jakiegoś prototype’a czy innego jquery? Najczęściej potrzebne mi są selectory i traversing – ostatnio na przykład chciałem na szybko policzyć jakieś dane na podstawie sporej tabeli na stronie internetowej. I co wtedy? Bawić się w getElementById i inne tego typu historie? Niefajne to, szczególnie jeżeli strona to jedna wielka tabelka bez prawie żadnych id, klas czy innych elementów pomocnych w wybraniu upragnionego kawałka.

Trochę ponad rok temu z kilkoma ludźmi pisałem startupa (po 2-3 miesiącach wszystko się rozpadło, ale było ciekawie), w którym duży nacisk był na dostarczenie prostych narzędzi (coś w rodzaju małego toolbara) do dowolnej strony internetowej. Oczywiście nie można zmusić właścicieli stron do wklejenia czegokolwiek na swoją stronę, ale można użyć zakładek przeglądarki, żeby coś takiego udostępnić.

Przeglądarki mogą obsługiwać adresy w postaci “javascript: alert(‘Why are you so serious?’);”. Wystarczy wkleić coś takiego w pasku adresu – oczywiście wyskoczy alert. A skoro użytkownik może dodać zakładkę do dowolnego adresu, to adres tej postaci też przejdzie.

Cały myk polegał więc na tym, żeby w kodzie javascript, który był dodawany do zakładek dołączyć jakąś bibliotekę (wtedy akurat używałem jQuery) i samą aplikację, która wyświetlała toolbar z różnymi opcjami.

Używając tej techniki można zrobić całkiem fajne rzeczy, ale w tym momencie ograniczę się do pokazania jak załączyć samą bibliotekę jQuery.

Kod wygląda mniej więcej tak:

(function( {
  var s = document.createElement('script');
  s.src="http://drogomir.com/jquery.js";
  document.body.appendChild(s);
})()

Można jeszcze dodatkowo zrobić drugi skrypt, który dołączymy po jQuery, a w nim dodać na przykład jQuery.noConflict, albo jakiś inny kod wykonany po załączeniu jQuery.

Dodajcie do zakładek tego linka i po wybraniu go na jakiekolwiek stronie jQuery zostanie dodane do skryptów na stronie.

Mam nadzieję, że komuś się przyda. Próbowałem znaleźć kod, o którym pisałem powyżej, który wyświetlał warstwę z toolboxem, z różnymi fajnymi opcjami, ale cholera chyba zniknął w pomroce dziejów. Będę musiał bardziej dbać o kod starych projektów, fajnie byłoby się teraz przyjrzeć pracy sprzed roku ;-)

Posted in  | Tags  | no comments | no trackbacks

Po dłuższej przerwie

Posted by Piotr Sarnacki Tue, 30 Sep 2008 14:38:00 GMT

Przez jakiś czas nie pisałem nic na blogu. Długo zbierałem się do napisania czegokolwiek, od dawien dawna miałem przetłumaczyć wpisy na moim angielskojęzycznym blogusiu. Tak bardzo mi się nie chciało, że jak tylko siadałem do kompa z zamiarem przetłumaczenia czy napisania czegoś podobnego coś mnie odrzucało.

Dlatego, żeby więcej się nie męczyć podsumuję ten temat i podam linki – większość ludzi, którzy tutaj trafią i tak na pewno zna angielski.

Napisałem apache upload progress module do apacha. Moduł, dzięki któremu można pobrać dane o wysyłanych plikach. Format odpowiedzi oparłem o moduły tego typu dla nginxa i lighttpd dlatego jeżeli wcześniej ktoś używał któregoś z nich, przesiadka będzie całkowicie bezbolesna. Sam używałem wcześniej nginx upload progress (głównie dlatego napisałem moduł do apacha) i po przerzuceniu aplikacji na apacha z nowym modułem nie trzea było zmieniać ani jednej linijki. Na angielskim blogu zamieściłem opis instalacji i konfiguracji modułu.

Żeby można było w miarę łatwo używać modułu napisałem także pluginy do “prototype’a”http://github.com/drogus/prototype-upload-progress/tree/master i jquery, które obsługują pasek postępu. Przykłady są w repozytoriach, umieściłem je także na serwerze dla obczajenia w akcji. Popełniłem także tekst o tym jak hackowałem plugin, żeby działał w safari – safari w tym momencie nie było wcale lepsze od IE… nawet powiedziałbym, że gorsze. Swoją drogą plugin nie działa w najnowszej operze (działał w 9.5 zdaje się), więc jeżeli ktoś ma chwile czasu i mógłby sprawdzić dlaczego i co można zrobić, żeby działał, to może wnieść swój wkład w rozwój (dodam, że nie jest to ta sama kwestia co dla safari, bo to już sprawdziłem) – nie sądzę żebym miał teraz czas sam na tym siedzieć.

Dodatkowo napisałem jeszcze tekst o tym jak można fajnie uatrakcyjnić aplikację używając jQuery. Część pierwsza. Część druga będzie jak będę miał więcej czasu, czyli pewnie niezbyt szybko.

Pozdrowienia ze słonecznego Wrocławia, gdzie mam zamiar mieszkać przez najbliższy rok (miła odmiana od Pruszkowa :).

Posted in , ,  | Tags , , , ,  | no comments | no trackbacks

HotRuby

Posted by Piotr Sarnacki Sat, 05 Apr 2008 05:31:00 GMT

Jakiś czas temu pojawiły się wzmianki o hotruby (tylko wtedy nie miałem czasu o tym napisać). Krótko mówiąc jest to “implementacja rubiego w javascripcie”. Możemy używać rubiego w przeglądarce i we flashu.

Kod rubiego jest wysyłany do skompilowania przez skrypt cgi, skrypt cgi kompiluje go do bytecodu, po czym javascript wykonuje ów bytecode.

Na stronie HotRuby jest wzmianka o tym, że składnia języka jest w większości zaimplementowana (na pewno nie ma wyjątków), ale jak na razie większość funkcji i bibliotek nie. Na razie nie wiem do czego mogłoby mi się takie połączenie przydać, ale patrząc na dema łatwo można zauważyć, że całkiem fajne rzeczy da się stworzyć z pomocą hotrubiego. Oby tak dalej.

Posted in  | Tags , ,  | no comments | 1 trackback

Livequery

Posted by Piotr Sarnacki Mon, 03 Mar 2008 20:41:00 GMT

Pisałem jakiś czas temu o nieinwazyjnym javascripcie w ruby on rails. Zapomniałem wtedy napisać o pluginie do jQuery, który ułatwia pracę stosując nieinwazyjny javascript.

Livequery ułatwia znacznie korzystanie ze zdarzeń. Często podczas manipulowania DOM tworzy się i/lub usuwa nowe elementy. Co gdy przypiszemy do kilku elementów jakieś zdarzenie po czym dodamy nowe elementy?

Zmontowałem prosty przykład, na którym można to sprawdzić. Do pierwszej listy linki dodawane są bez żadnych dodatków. Zwykłe:


  $('<li><a href="#">Link</a></li>').appendTo($('.without ul'));

Dlatego funkcja clicked uruchomi się tylko dla 2 pierwszych linków.

W drugim przypadku dodałem bind dla nowo stworzonego elementu:

  $('<li><a href="#">Link</a></li>').
          appendTo($('.with ul')).
          bind('click', clicked);

Zdarzenie jest więc przypisywane również dla nowych linków.

Jednak gdy ilość różnych zdarzeń zaczyna się niepokojąco powiększać, a cały interfejs strony zmienia się przy każdym prawie kliknięciu często można zapomnieć o przypisaniu zdarzeń. Nawet jeżeli ktoś nie jest zapominalski, to zapewne jest leniwy (ponoć dobrego programistę cechuje lenistwo). Na ratunek przychodzi Livequery, plugin, który sam dba o przypisywanie lub usuwanie zdarzeń w razie manipulacji DOM.

Drugi przykład# wykorzystuje już LiveQuery – jak można łatwo zauważyć nie trzeba już dopisywać żadnych dodatkowych funkcji.

I jedno zmartwienie przy pisaniu mniej ;-)

Posted in  | Tags , , ,  | no comments | 1 trackback

Rails 2.0 i js.erb

Posted by Piotr Sarnacki Tue, 15 Jan 2008 20:36:00 GMT

Niedawno pisałem o nieinwazyjnym kodzie javascript w railsach. Wspomniałem tam o pluginie MinusMor, który dodaje pliki ejs. Czyli kod javascript parsowany erbem. Zainstalowałem plugin w mojej aplikacji przeniesionej na rails 2.0. Kod pluginu nie działa… zacząłem przeglądać kod railsów, żeby poprawić minusmor (w internecie nie mogłem znaleźć poprawki). Po chwili przemyślenia sprawdziłem co dzieje się gdy wyrzucę plik rjs. Komunikat o błędzie:


Missing template pages/index.js.erb in view path

Git! W railsach 2.0 możemy przecież wskazać jakiego parsera mają użyć.

Tworzymy plik index.js.erb. I jeszcze mała zmiana, ustawiamy brak layoutu, żeby renderował się sam template:

respond_to do |format|
  render.html
  render.js { render :layout => false }
end

I to wszystko! Po prostu działa.

Nawet lepiej. Można zdefiniować layout, na przykład:


render.js { render :layout => 'jquery' }
a w nim można na przykład napisać:

(function ($) {
  <%= yield %>
})(jQuery);

I można używać w template’ach js.erb $ pomimo tego, że wcześniej użyło się jQuery.noConflict.

Przeszukałem później jeszcze net w poszukiwaniu informacji na ten temat i znalazłem artykuł na mad.ly o dodaniu helperów z MinusMor

Posted in  | Tags , ,  | no comments | no trackbacks

Nieinwazyjny javascript razem z Ruby on Rails

Posted by Piotr Sarnacki Tue, 25 Dec 2007 20:15:00 GMT

Jakiś czas temu Riddle napisał o tym dlaczego nie można zakładać, że ktoś ma włączony javascript. Temat był już wcześniej wiele razy poruszany, mi bardzo podobał się artykuł Chrisa Heilmanna The seven rules of Unobtrusive JavaScript. Zachęcam do zapoznania się z tymi dwoma tekstami – pomogą zrozumieć dlaczego “tracić” czas na rozwiązywanie problemów, o których napiszę poniżej. Streszczając krótko artykuły mogę napisać, że jeżeli to możliwe, należy pisać aplikację tak, żeby działała bez włączonego javascriptu. Skrypty mogą nie działać z kilku powodów:

  • użytkownik ma wyłączony javascript w przeglądarce
  • wystąpi błąd w kodzie (nie możemy sprawdzić kodu na wszystkich urządzeniach)
  • strona nie załaduje się do końca
  • boty wyszukiwarek nie używają javascriptu, więc w skrajnym wypadku możemy uniemożliwić zindeksowanie naszej strony

Jak to wygląda w Railsach?

Railsy są wyposażone w zestaw helperów generujących różnego rodzaju kawałki kodu javascript. Pomysł jest z pozoru bardzo fajny. Początkujący mogą szybko zacząć używać javascriptu razem z dobrodziejstwami, które daje nam Ajax bez znajomości samego języka. Jest jednak sporo minusów używania helperów:

  • generują one dodatkowy niepotrzebny kod javascript. jeżeli na stronie mamy kilkadziesiąt linków, a każdy z nich ma wklejony kod `onclick=”new Ajax.Request(’/controller/action?n=33’, {asynchronous:true, evalScripts:true, onComplete:function(request){undoRequestCompleted(request)}}); return false;”` strona będzie ważyć dużo więcej.
  • javascript w nich użyty jest “inwazyjny”. Jeżeli javascript nie będzie działał, to element wygenerowany w taki sposób również nie zadziała1
  • ciężko jest się przy nich trzymać zasady DRY. Mając 5 linków wygenerowanych metodą link_to_remote z takimi samymi opcjami, za każdym razem gdy coś musimy zmienić, zmieniamy to w 5 miejscach. Powinno się oczywiście napisać helpera, który wygeneruje link z danymi opcjami. Tylko chyba nie tędy droga – w dalszej części artykułu postaram się pokazać dlaczego nieinwazyjny javascript jest lepszy w tego typu zadaniach.
  • z mojego doświadczenia wynika, że bardzo często, gdy ilość kodu się powiększa i javascript generowany przez railsy miesza się z tym z plików js można łatwo się pogubić. Tyczy się to także różnego rodzaju api – na przykład google maps. Najłatwiej działać, gdy javascript jest odseparowany od kodu railsów
  • jesteśmy związani z jedną biblioteką (w tym wypadku prototype+script.aculo.us) – jeżeli chcemy zamienić ją na coś innego (ja ostatnio przesiadłem się na jQuery, zastanawiałem się też nad YUI) helpery przestaną działać – można je oczywiście przepisać, ale komu by się chciało. DHH nie zamierza nic w tej kwestii zmieniać, więc na zmianę tego w Railsach nie ma co czekać.

Jakie są minusy? Trzeba lepiej poznać javascript (właściwie dla mnie to nie jest minus, ale dla niektórych być może tak). Nie jest to jednak przeszkoda nie do pokonania dla początkujących. Javascript, który jest potrzebny do zadań możliwych do wykonania z użyciem samych helperów nie jest z reguły przesadnie trudny do nauczenia. Ratunkiem dla osób, które nadal chcą korzystać z helperów jest plugin UJS. Jeżeli bardzo nie chcesz pisać wszystkiego w czystym javascripcie, to jest to bardzo fajne połączenie prostoty helperów i zalet nieinwazyjnego javascriptu. Jest ona jednak pisana dla Prototype’a, więc tak jak w ostatnim punkcie z powyższej listy można o niej zapomnieć, jeżeli używana jest jakakolwiek inna biblioteka.

W komentarzach apohllo zauważył, że plugin UJS nie jest już rozwijany. Używacie na własną odpowiedzialność. :)

Przejdę do przykładów, bo przecież nie samą teorią człowiek żyje.

Przerzuciłem się ostatnio na jQuery i chyba przy niej zostanę. Rozumiem jednak, że większość użytkowników railsów jest związana z Prototype’em, więc kod będę podawał w dwóch wersjach, dla Prototype’a i jQuery.

Na początek wprowadzenie. Co zrobić, żeby wyrzucić z htmla (i railsów) wstawki Javascript? Wszystko wstawiamy do aplikacji używając zdarzeń. Przypuśćmy, że mamy linka o id=”someLink”. Zamiast dopisania onclick:


    <a href="#" onclick="alert('Klik!'); return false;">Link</a>
  
należy użyć:

Prototype:

    Event.observe($('someLink'), 'click', function(event) {
      alert('Klik!');
      Event.stop(event);
    }
  
jQuery:

    $('#someLink').click(function (){
      alert('Klik!');
      return false;
    });
  

Oba przykłady dodają zdarzenie uaktywniane kliknięciem w linka. Ostatnia linijka w obu funkcjach, które są wykonywane po kliknięciu (nazywane są z reguły handlerami) jest wstawiona po to, żeby kliknięcie linka nie przeładowało strony.

Kod taki w aplikacji Rails można wrzucić do pliku application.js, lub jakiegoś specyficznego pliku js ładowanego na danej stronie. Należy też go załadować dopiero po wczytaniu się całego dokumentu. Normalnie coś takiego uzyskiwało się wpisując w body: `onload=”jakasFunkcjaJavascript();”`, ale takie dodawanie jest passe, więc:

Prototype:

    Event.observe(window, 'load', function() {
      //kod który wykona się po załadowaniu strony
    }

    // lub zdefiniowana wcześniej funkcja, która wykona się po załadowaniu strony
    Event.observe(window, 'load', jakasFunkcjaJavascript());
  
jQuery:

    $(function() {
      //kod który wykona się po załadowaniu strony
    });

    // lub zdefiniowana wcześniej funkcja, która wykona się po załadowaniu strony
    $(jakasFunkcjaJavascript);
    //powyższe przykłady, to skrócone wersje document.ready:
    $(document).ready(function () {});
  

Dzięki tym konstrukcjom mamy pewność, że kod wykona się dopiero gdy załaduje się cały dokument, a nie w momencie, gdy dołączony jest plik js.

Teraz przykład prostego zapytania ajax (przykład z dokumentacji railsów):

  link_to_remote 'hello', :url => { :action => "action" }, 
    404 => "alert('Not found...? Wrong URL...?')",
    :failure => "alert('HTTP Error ' + request.status + '!')" 
  # Wygeneruje: <a href="#" onclick="new Ajax.Request('/testing/action', {asynchronous:true, evalScripts:true,
  #            on404:function(request){alert('Not found...? Wrong URL...?')},
  #            onFailure:function(request){alert('HTTP Error ' + request.status + '!')}}); return false;">hello</a>
Jak widać powyżej wygenerowanego kodu jest całkiem sporo. Jeżeli będzie trzeba wstawić taki link w paru miejscach dobrze by było napisać swojego własnego helpera, który automatycznie będzie wklejał komunikaty o błędach. Jak można to zrobić lepiej? Na początek wystarczy stworzyć zwykłego linka z jakąś klasą, lub id:

  link_to 'hello', { :action => 'action' }, :class => 'ajax'
Teraz trzeba użyć trochę javascriptu :

        $$('a.ajax').each(function (element) {
          Event.observe(element, 'click', function(event) {
            new Ajax.Request(this.readAttribute('href'), {asynchronous:true, evalScripts:true, 
              on404:function(request){alert('Not found...? Wrong URL...?')}, 
              onFailure:function(request){alert('HTTP Error ' + request.status + '!')}}); 
            Event.stop(event);
          });
        });

Na początku pobieramy wszystkie linki z klasą ajax i dla każdego z nich wywołujemy funkcję `Event.observe(element, ‘click’....`. Dalszy kod wykona się więc po kliknięciu w danego linka. W tym wypadku wykonujemy zapytanie ajaxowe (`new Ajax.Request`). Pierwszy argument to atrybut href linka (uwaga, kod ten nie zadziała w starszych wersjach prototype’a, które niepoprawnie obsługiwały this w tego typu funkcji). Reszta kodu to standardowe opcje, po więcej odsyłam do dokumentacji Prototype.

A w jQuery wyglądać to będzie tak:

    $('a.ajax').click(function (){
      $.ajax({
        url: this.href,
        dataType: "script",
        beforeSend: function(xhr) {xhr.setRequestHeader("Accept", "text/javascript");},
        error: function(){
          alert( "Error loading page");
        }
      });     
      return false;
    });

Kod zasadniczo robi to samo, co poprzedni przykład. Można przy okazji porównać prostotę jQuery i porównać ją z Prototype’em (ostatnio dużo się w tej bibliotece pozmieniało, a ja nie jestem na bieżąco, więc jeżeli ktoś zna lepszy sposób na napisanie czegoś takiego, to proszę o komentarz). Skomentuję tylko atrybuty dataType i beforeSend w funkcji ajax(). Ustawiając je w taki sposób przekazujemy serwerowi, że chcemy dostać odpowiedź jako skrypt i akceptujemy typ MIME “text/javascript”. Należy te 2 rzeczy dodać, ponieważ inaczej nie będzie renderować się plik RJS. Więcej na ten temat w artykule jQuery Ajax + Rails

Rozwiązanie proste i efektywne. Żeby link wykonał javascript wystarczy dodać do niego klasę ajax. Jeżeli strona i kody javascript nie wczytają się, link dalej będzie działał poprawnie. Przy założeniu, że poprawnie obsłużymy wszystko w kontrolerze. Służy do tego metoda `respond_to`


  respond_to do |format|
    format.js # jeżeli to zapytanie wykonane ajaxem uruchomi się plik RJS
    format.html # w przeciwnym wypadku wyrenderowany zostanie template rhtml
  end

Więcej o takim sposobie renderowania templatów pisał na przykład Jamis Buck.

Można też w podobny sposób zamienić zwykłą formę na taką wysyłaną ajaxem:

Prototype:

       $$('form.ajax').each(function (element) {
          Event.observe(element, 'submit', function(event) {
            new Ajax.Request(this.readAttribute('action'), {
              parameters: Form.serialize(this),
              asynchronous:true, 
              evalScripts:true
              }); 
            Event.stop(event);
          });
        });  
  

Powyższy kod jest bardzo podobny do poprzedniego przykładu. Różnica polega na tym, że zdarzeniem nie jest ‘click’ tylko ‘submit’ i jako parametry podajmy wynik funkcji `Form.serialize(this)` – zbiera ona wartości pól i zwraca string typu: “pole1=wartosc1&pole2=wartosc2”

jQuery:

    $("form.ajax").ajaxForm({
      dataType: 'script',
      beforeSend: function(xhr) {xhr.setRequestHeader("Accept", "text/javascript");},
      resetForm: true
    });
  

W jQuery najłatwiej skorzystać z pluginu jQuery Form – załatwia on za nas wszelkie formalności ;-)

W ten sposób zmiana jakiegoś linka lub formy na jego ajaxową formę to kwestia dodania jednej klasy. Można oczywiście napisac wiele takich funkcji dla różnych przypadków, dowiązanych do tagów z innymi klasami, lub z konkretnym id.

Na koniec krótkie podsumowanie.

Kod javascript dodajemy do aplikacji tak, żeby nie zablokować dostępu w wypadku braku jego wykonania. Zapomnieć można o wszelakich “onclick” i innych tego typu sprawach. Wszystko powinno być dołączone jako zdarzenia. Dzięki temu zmniejsza i upraszcza się kod railsów i ten przez nie generowany.

Warto obejrzeć również plugin MinusMOR, który zmienia trochę podejście do javascriptu. Zamiast plików rjs, w których używamy rubiego zamienianego później na javascript, mamy pliki ejs, w których wpisujemy kod javascript z możliwością wstawiania kodu rubiego. Tak samo jak w rhtmlu poprzez <% %>.

W komentarzach apohllo zauważył, że plugin MinusMOR nie jest już rozwijany. Trzeba o tym pamiętać zaczynając go używać. Z drugiej strony widziałem kod pluginu i rejestruje on tylko nowe rozszerzenie “ejs”. Na początku szukane będą pliki z tym rozszerzeniem, a jeżeli ich nie będzie Railsy wyrenderują RJS. W każdym razie zaczynacie używać na własną odpowiedzialność. :)

Zapraszam do komentowania – prosiłbym o opinie dotyczące tego typu artykułów. Czy są zrozumiałe? Czy przydają się wam? Konstruktywna krytyka mile widziana. :)


  1. W tym miejscu trzeba zaznaczyć, że jest możliwość wygenerowania linku, czy formy, która będzie działała przy wyłączonym javascripcie, ale niewiele osób o tym wie i z tego korzysta. I trzeba dopisać 2 url, który z reguły jest taki sam – łamana jest zasada DRY

Posted in  | Tags , , ,  | no comments | no trackbacks

jQuery.noConflict i $ - fajny trick

Posted by Piotr Sarnacki Tue, 18 Sep 2007 11:46:00 GMT

Dzisiaj króciutko: fajny trick podpatrzony gdzieś w skryptach jQuery.

Pisząc skrypty najlepiej robić to tak, żeby można było je uruchamiać na każdej stronie. Nie mogą się gryźć z innymi bibliotekami. Dlatego jQuery wprowadziło funkcję:

jQuery.noConflict();

Po jej wywołaniu kontrola $ jest zwracana bibliotece, która wcześniej go używała. Dzięki temu można używać jQuery w połączeniu z innymi bibliotekami, a nawet ze starszymi wersjami jQuery (bardzo przydatne przy pisaniu widgetów). Minusem jest konieczność pisania jQuery zamiast $. Można oczywiście przypisać jQuery na krótszą zmienną, ale wtedy ciężej jest wklejać kod napisany przez innych.

Aby temu zaradzić wystarczy użyć takiej konstrukcji:


(function($) {
  //tutaj można używać $ bez strachu o konflikt
})(jQuery);

Stworzona zostaje funkcja, która jest od razu wywołana z podanym argumentem. I voilla :)

Posted in  | Tags , ,  | 2 comments | no trackbacks

Nowy jQuery UI

Posted by Piotr Sarnacki Mon, 17 Sep 2007 09:08:00 GMT

Tak jak zapowiedziano już wcześniej, wypuszczona została wersja 1.0 jQuery User Interface.

Uruchomiona została nowa, dużo ładniejsza strona, dodane zostały nowe przykłady i dema.

Celem twórców biblioteki jest stworzenie zwartego zestawu komponentów, dobrze napisanych i udokumentowanych. Bardzo dobrze, że takie projekty powstają, bo wrzucanie 15 pluginów z różnych źródeł, co do przyszłości których nikt nie ma pewności jest gorszym rozwiązaniem. Na stronie jest dostępny downloader, w którym zaznaczamy potrzebne elementy, po czym tworzony jest plik zawierający spakowane kommponenty.

Naprawdę polecam. :)

Tags , , , ,  | no comments | 1 trackback

Generowanie HTMLa w javacripcie

Posted by Piotr Sarnacki Sun, 16 Sep 2007 10:43:00 GMT

Czasami bywa tak, że jakaś wyższa siła każe nam generować duże ilości HTMLa. Wygląda to dość nieładnie:


var el = document.createElement("div");
el.setAttribute('id','elementId');
el.setAttribute('class','someClass');
document.body.appendChild(el);

Stworzony został jeden element. A jakby elementów było 10? I każdy miałby po parę atrybutów? Masakra.

Na szczęście powstają różnego rodzaju DOM buildery. Od wersji 1.5.1 użytkownicy prototype’a będą mogli cieszyć się jego dobrodziejstwami. Jeżeli chodzi o jQuery to znalazłem dość fajną implementację. W komentarzach jest też inna wersja, która mi osobiście bardziej odpowiada.


$.create(
   'table', { 'class':"MyTable" }, [
      'tbody', {}, [
         'tr', {}, [
            'td', { 'class':"MyTableCol1" }, [ "howdy" ],
            'td', { 'class':"MyTableCol2" }, [
               "Link:", 'a', { 'class':"MyLink", 'href':"http://www.example.com" }, ["example.com"] ] ] ] ]
).appendTo(document.body);

Całkiem ładnie to wygląda. używając createElement wyszłoby pewnie ze 20 linijek.

Są oczywiście inne implementacje, które nie wymagają jQuery czy prototype’a, przydatne szczególnie w przypadku różnego rodzaju widgetów. Odsyłam do wujka G ;)

Tak jak obiecałem, wrzucam ostateczne wersje zaproponowanych w powyższym linku funkcji. Teraz powinno działać bez zarzutu.


jQuery.create = function() {
  var ret = [], a = arguments, i, e;
  a = a[0].constructor == Array ? a[0] : a;
  for(i=0; i<a.length; i++) {
    if(a[i+1] && a[i+1].constructor == Object) { // item is element if attributes follow
      var tag = a[i];
      attrs = a[++i];
      if(jQuery.browser.msie && (attrs.name || attrs.checked)) {
        tag = '<' + tag + ' ' + (attrs.name ? 'name="' + attrs.name + '" ' : '')+ (attrs.checked ? "checked" : " ") +'>';
        if(attrs.name) delete attrs.name;
        if(attrs.checked) delete attrs.checked;
      }
      e = document.createElement(tag);
      jQuery(e).attr(attrs); // apply attributes
      if(a[i+1] && a[i+1].constructor == Array) jQuery(e).append(jQuery.create(a[++i])); // optional children
      ret.push(e);
    } else { // item is just a text node
      ret.push(document.createTextNode(a[i]));
    }
  }
  return ret;
};

jQuery.tpl = function(json, tpl) {
  var ret = [];
  jQuery.each(json.constructor == Array ? json : [json], function() {
    var o = jQuery.create(tpl.apply(this));
    for(var i=0;i<o.length;i++) ret.push(o[i]);
  });
  return ret;
};

Posted in  | Tags , , , ,  | no comments | no trackbacks

Older posts: 1 2