//DEVGURU

Category archives ‘javascript’

Firebug dla IE 6!!!

Friday, January 2nd, 2009

Jakis (dość już długi) czas temu, znajomy pokazał mi rozszerzenie do Firefoxa o nazwie Firebug. Wtedy byłem nim zachwycony i ten zachwyt choć z małymi przerwami nie przestał mnie opuszczać aż do dziś. Ciężko sobie wyobrazić w obecnej chwili webdevelopment bez użycia tego narzędzia, co można zresztą zobaczyć chociażby w poprzednim poście.

I choć jest to niesamowicie przydatne narzędzie ma ono jedną poważną wadę – jak sama nazwa wskazuje będzie działać tylko w Firefoxie.  Część przeglądarek udostępnia nam podobne, mniej lub bardziej przydatne narzędzia (np. Web Inspector w Safari czy Chrome) ale pozostaje jeden duży problem – co z Internet Explorerem 6?

W IE6 oczywiście takie narzędzie przydało by się najbardziej, ze względu na niesamowitą ilość błędów interpretacji CSS’a, czy dość specyficzne (innaczej mówiąc złe) podejście do interpretacji JavaScriptu. Z pomocą może nam przyjść IE Developer Toolbar, jest to jednak narzędzie przygotowane przez sam MS co niech świadczy o jego jakości – co za tym idzie nawet do niego nie zalinkuje.

Dlaczego? Bo z odsieczą przybywa nam DebugBar – i to już jest bardzo poważne narzędzie, którego autorzy większość czasu spędzają prawdopodobnie patrząc na samego Firebuga i myśląc w czym by tu jeszcze go naśladować.

I tak DebugBar udostępnia nam wszystkie najważniejsze funkcjonalności jakie oferuje Firebug, w prawdopodobnie maksymalnej jakości jaką sie da wyciągnąc z IE. Dostajemy dostęp do prawdziwej działającej konsoli JS i prawdzej działającej przeglądarki zasobów http(s) i prawdziwego działającego inspektora elementów strony. Wszystko jest w ogóle prawdziwe i działające, a development w IE6 nagle przestaje być taki straszny.

Ahhh… (westchenie kodera CSS któremu development w IE nagle przestał być taki straszny).

Rails, Ajax i jQuery

Tuesday, December 9th, 2008

Poniżej przedstawiam swoje podejście do wprowadzania ajaxowych funkcjonalności do aplikacji napisanych w Ruby on Rails. Jest to zbitka rozwiązań znalezionych na różnych blogach, forach oraz trochę moich przemyśleń. Do obsługi Javascript używam biblioteki jQuery, nie korzystam z jRails ani żadnych helperów do JS/Ajax dostępnych z Rails. Dzięki temu cały kod javascriptowy/htmlowy zaprezentowany poniżej może być bez trudu użyty w aplikacjach napisanych w innych językach/frameworkach. Zacznijmy.

Ruby on Rails a REST

Requesty ajaxowe różnią się trochę od zwykłych requestów, które dochodzą do serwera gdy użytkownik wpisze URL w przeglądarce. A przynajmniej powinny się różnić, żebyśmy po stronie serwera wiedzieli jaką odpowiedź (widok) zwrócić, nie ma bowiem sensu renderować całego layoutu np. dla requestu ajaxowego oceniającego zdjęcie w naszym serwisie. Tym aspektem odróżniającym różne typy requestów jest w tym przypadku nagłówek zawierający oczekiwany format odpowiedzi od serwera.

Dzięki implementacji REST w Railsach, sposób w jaki obsługujemy akcje jest zawsze taki sam niezależnie od typu requestu, jedyna zmiana dotyczy zwracanego przez nas widoku. Decydujemy o tym w kontrolerze:

To, który blok zostanie wywołany i w efekcie tego jaki widok zwrócony, zależy od route’ów zdefiniowanych w routes.rb oraz od oczekiwanego przez klienta formatu danych. W większości chcielibyśmy, żeby wszelkie ajaxowe requesty oczekiwały formatu XML (w odróżnieniu od HTML dla normalnych requestów), dlatego musimy zadbać o to, by przeglądarka odpowiednio ustawiała nagłówek Accept na ‘text/xml’ przy wywołaniach ajaxowych. W jQuery możemy ustawić to od razu dla wszystkich requestów z góry:

Różnice między przeglądarkami

Ręczne ustawienie nagłówka Accept niestety potrafi dawać różne efekty w różnych przeglądarkach. Wartością domyślnie ustawianą w przeglądarkach dla tego nagłówka jest text/html. Przy wywołaniu powyższego kodu Firefox zmieni wartość na ‘text/xml’, podczas gdy niektóre wersje IE i Safari ustawią ‘text/html; text/xml’ oczekując w ten sposób odpowiedzi od serwera w jednym z tych dwóch formatów.

Jest to dość istotna różnica, ponieważ Railsy decydując o tym, który format odpowiedzi wybrać, biorą pod uwagę pierwszy format napotkany w tablicy request.accept, którym w przypadku IE i Safari będzie text/html. Takie zachowanie zaobserwowałem chociażby w wersji 2.1.0 Railsów.

Poniższy kod naprawia opisane zachowanie przenosząc format xml na początek tablicy (jeśli się tam w ogóle znajduje), dzięki czemu będzie on znaleziony jako pierwszy.

Ajaxowe linki

Poniższy kod Javascript pozwala szybko zamienić istniejące już linki na działające ajaxowo. Proponuję go wrzucić do pliku appliacation.js.

 

Teraz wystarczy dodać do istniejących linków klasę (CSS’ową) get, post, put lub delete w zależności od pożądanej metody wywołania linku, by zmienić je w linki ajaxowe. Polecam do tego plugin LiveQuery, który to zachowanie automatycznie podepnie także do każdego nowego linku opatrzonego którąś z tych klas, który pojawi się na stronie (np. w efekcie działania jakiegoś wywołania ajaxowego). Dodatkowo do naszych linków możemy dodać opcjonalny atrybut ajaxtaget i ustawić jego wartość na selektor CSS’owy wskazujący na element, do którego zostanie załadowany widok zwrócony przez serwer.

Ajaxowe formularze

Do wysyłki formularzy porzez ajax będziemy potrzebować kolejnego pluginu – jQuery Form.

Ajaxowe formularze będą identyfikowane poprzez CSS’ową klasę ‘ajax’.

Modyfikacja strony po wywołaniu ajaxowym

Standardowym sposobem wyświetlania efektów wywołania ajaxowego jest odbieranie, obróbka i umieszczenie tego, co ono zwróci w jakimś miejscu na stronie. Innym sposobem jest umieszczenie całego kodu modyfikującego stronę w odpowiedzi zwracanej przez ajaxowe wywołanie i tylko wykonywanie go przez przeglądarkę. Taką funkcjonalność daje nam kolejny plugin do jQuery – Taconite. Cytując autora pluginu: “Taconite pozwala wykonywać modyfikacji wielu elementów strony naraz, korzystając z odpowiedzi zrwóconej przez pojedyncze wywołanie ajaxowe. Taconite używa do tego XML’owego dokumentu zawierającego instrukcję jak modyfikować stronę”.

Przykładowy widok XML z instrukcjami dla Taconite wygląda tak:

Dzięki podejściu oferowanym przez Taconite możemy poprawić strukturę aplikacji. Weźmy dla przykładu wspomnianą wcześniej funkcjonalność głosowania. Do tej pory kod Javascriptowy, który dbał o wyświetlenie rezultatów oddania głosu (np. zwiększenie countera, usunięcie linku ‘głosuj’, wyświetlenie komunikatu ‘głos został oddany’, itp) musiał być umieszczany na każdej stronie, na której było możliwe oddanie głosu. Teraz jest on po prostu zwracany jako odpowiedź serwera na oddanie głosu, czyli znajduje się tam gdzie być powinien.

Kolejny przykład – wyświetlanie flash messages w odpowiedzi na wywołania ajaxowe. Załóżmy, że to jest fragment layoutu naszej strony, w którym wyświetlamy komunikaty flash[:notice]:

Niech to będzie layout taconite, w którym zagnieżdzamy widoki zwracane na wywołania ajaxowe:

Teraz komunikaty flash[:notice] będą wyświetlane w standardowym miejscu na stronie z efektem fade-in. W podobny sposób możemy aktualizować inne elementy strony, np. wszelakie countery.

A Ty jakich narzędzi używasz?

Jestem ciekaw jakich rozwiązań używacie do implementacji Ajaxa w Waszych aplikacjach. Preferujecie jakieś inne pluginy/biblioteki?

Javascript, jQuery i preloading obrazków

Wednesday, November 26th, 2008

Wiemy już w czym problem, prawda? Chodzi o te pół, jedną trzecią, dwie szóste czy nawet całą, a nie daj Boże dwie i więcej sekundy, po których pojawia się obrazke zdefiniowany w css na zdarzeniu hover. Rozwiązań jest kilka, z czego na chwilę obecną przychodzi mi do głowy np. CSS Sprites, czyli działające-aczkolwiek-średnio-wygodne rozwiązanie.

Jakie rozwiązanie jest zadowalające-prawie-wszystkich a zarazem banalne w użyciu? Preloading przy użyciu jQuery.

Ot, cała filozofia: w DOMie tworzony jest obiekt img, który dostaje odpowiedni atrybut src, co powoduje wczytanie tego pliku do cache przeglądarki. Problem “opóźnionych hoverów” z głowy.

Javascript a ładny kod: Object Literal

Tuesday, November 18th, 2008

Problem

Jak wygląda praca z Javascriptem z punktu widzenia server-side’owego developera?

Przeszliśmy pierwszą falę szału nad bibliotekami JS: Prototype, Mootools, jQuery (czy mniej buzzowe ext.js, YUI). Zachwycamy się ładnymi rzeczami tworzonymi przy użyciu canvas, które znajdujemy na oursignal.com (też przecież napisanym w JS). Widzimy, jak za pomocą jednej linii możemy schować, animować, przetransformować i zrobić milion rzeczy z DIVem, Paragrafem czy Anchorem. Wybieramy jedną z bibliotek. Czytamy dokumentację, widzimy milion fajnych selektorów, czytamy książki, w których zachwycamy się jak fajnie można rozszerzyć funkcjonalność o pluginy… Myślimy sobie: “tak, teraz, gdy JS nie jest tak paskudny i skopmlikowany jak kiedyś, mogę stać się JS-developerem!”. Piszemy więc accordion, animujemy kilka rzeczy w naszej aplikacji (żeby user widział, że się dzieje!), kilka formularzy wysyłamy AJAXem. Wszystko jest ładne i unobtrusive. I co?

Zdajemy sobie nagle sprawę, że nasz application.js ma o kilkaset linii kodu za dużo, że kod jest nieczytelny, że nie wszystko da się wrzucić do document.ready(), że kilku rzeczy moglibyśmy użyć w kilku miejscach – zaczynamy pisać więc funkcje, staramy się przyjąć jakąś konwencję nazewnictwa… I kończymy z jeszcze większym bałaganem – chociaż bałaganem rozszerzonym o DRY.

Rozwiązanie?

Dobrym punktem wyjścia jest trzymanie wszelkich akcji w jednym obiekcie – korzystając z object literal (kawałek kodu korzysta z jQuery):

Co nam teraz pozostaje? Wywołanie funkcji bob.init(); w document.ready. Korzyści? Mając jeden obiekt “bob” możemy wywoływać jego funkcje w środku odwołując się do self. Trzymając wszelkie informacje, które mogą ulec zmianie – takie, jak długość timeoutu, klasy css czy wiadomości komunikatów – w bob.config – możemy łatwo je zmienić (gdy np. mamy konflikt z koderem CSS). Zresztą kod jest całkiem “samowyjaśniający się“.

Potencjalne zastosowanie? Dajmy na to, że wszystkim input type=submit podpinamy event, który powoduje, że po kliknięciu na niego zmienia value na “ładuję…” i staje się disabled. Ok, pięknie działa dla wszystkich przycisków wygenerowanych przez aplikację. Co jednak, gdy stworzymy nowy input przez javascript? Mamy doczepić mu event w momencie tworzenia? Nie, po umieszczeniu go w DOMie wywołujemy tę samą funkcję, która jest wywoływana przy init(). Warto rozpisywać nawet najmniejsze rzeczy w osobnych funkcjach – nigdy nie wiadomo, czy nie będziemy musieli ich kiedyś użyć ponownie.

Co dalej? Walidujemy nasz JS przy użyciu JSLint, przez co oszczędzimy sobie żmudnego procesu debugowania (który nie jest, swoją drogą, zbyt przyjazny). Kilka ciekawych praktyk zawarł w swojej prezentacji Chris Heilmann (część 1, część 2, wygrzebane przez Filipa Teppera) – m.in. jak umożliwić designerowi/koderowi CSS pracę nad wyglądem strony z Javascriptem lub bez niego – korzystając jedynie z CSS.

Dlaczego JSON Object + eval() = Parse Error?

Tuesday, June 3rd, 2008

Podczas pisania iBlipa natrafiłem na dość ciekawy problem: Gdy chciałem użyć funkcji eval() do parsowania obiektu JSON który otrzymałem z API otrzymywałem Parse Error. Wyjaśnienie tego problemu znalazłem, ale zajęło mi to dość dużo czasu, zatem warto się nim podzielić .

Netvibes – dlaczego (nie) warto go używać?

Sunday, June 1st, 2008

Kolejna prezentacja z cyklu FridayTalks – tym razem na temat uniwersalnego API do tworzenia widgetów od Netvibes.

SlideShare | View | Upload your own

Jaki wniosek nasuwa się po obejrzeniu prezentacji? Z pewnością entuzjazm jaki towarzyszył ukazaniu się pierwszej wersji API był uzasadniony. Zbudowanie środowiska uniwersalnego, które będzie obsługiwane przez różne urządzenia i platformy jest czymś bardzo cennym. Uwagi można jednak mieć już do samej zasady działania API.

Widgety napisane w Netvibes są zależne od działania serwerów Netvibes. Najpierw serwer parsuje kod i dopasowuje do wybranej platformy, a następnie wszystkie zapytania ajaxowe tworzone zgodnie ze specyfikacją przechodzą za każdym razem przez Netvibes. Wady takie rozwiązania mogą być wielorakie:

- gdy serwer Netvibes pada – co miało miejsce podczas ostatniej migracji na nową wersję – nasz widget też zamiera

- zapytania poprzez Ajax trwają dłużej, gdyż muszą być jeszcze obsłużone przez momentami bardzo obciążony serwer Netvibes

- przeglądarki internetowe blokują często zapytania do serwera Netvibes – gdyż naruszają one zabezpieczenia (odwołując się do domeny innej niż macierzysta)

Odrębne problemy sprawia to, iż API Netvibes ciągle nie zostało jeszcze ukończone. W dokumentacji czytamy o brakach w obsłudze preferencji, itp… Sprawia to problem gdy chcemy stworzyć ciut bardziej skomplikowany widget i musimy rezygnować z pewnych rozwiązań z powodu braków w API.

Kolejny zarzut jaki się pojawia to niedopasowanie widgetów do poszczególnych platform, np. Windows Vista nasz gadżet będzie miał nadal szerokość taką jak inne gadżety w Netvibes i na pasku gadżetów się nie zmieści. Za to w Dashboard w Mac OS X musimy najpierw ściągnąć widget pośredniczący, do którego dopiero wklejamy URL właściwego widgeta…

Najprościej byłoby nie korzystać z API Netvibes i zadowolić się np. Google Gadgets – gdyż jak pokazują statystyki popularnosć Netvibes jest znikoma. Co zrobić jeżeli jednak musimy korzystać z Netvibes?

Rozwiązaniem jest z pewnością zastosowanie <iframe> – możemy stworzyć prostą stronkę, którą będzie parsował serwer Netvibes – a w niej iframe z właściwym widgetem, do którego już Netvibes zaglądać nie będzie (możemy zatem użyć np. jQuery). Takie rozwiązanie pozwala nam też zrezygnować z Netvibesowych zapytań AJAX – możemy zatem stworzyć własny plik proxy w PHP przez którego będą przechodziły wszystkie zapytania. Pozwoli to nam “oszukać” przeglądarkę w kwestii zabezpieczeń XSS i przyspieszyć uzyskiwanie odpowiedzi.

netguru friday talks… javascript

Saturday, November 24th, 2007

Co piątek, w okolicach godziny 14, przerywamy pracę nad projektami aby ugruntować swoją wiedzę związaną z programowaniem.

Dzisiejszy epizod “netguru friday talks” został poświęcony ugruntowaniu wiedzy na temat JavaScript. Rozmawialiśmy o nowoczesnym tworzeniu kodu, separacji JS i HTML, zasięgu, kontekście, operacjach na DOM, JS Closures, jQuery, pluginach do jQuery (jak tworzyć własne i z których istniejących warto korzystać).

Za tydzień o dobrych praktykach w serwisach /społecznościowych/ opowie Kuba. Znany Blogger, znany Designer i trzon netguru. Na pewno będzie ciekawie.

Ładowanie Google Maps na żądanie

Wednesday, November 7th, 2007

Dość długo zastanawiałem się jak załadować GoogleMaps na żadanie ( i chyba nie tylko ja….. Lazy loading of Google Maps API Javascript) w końcu development Google zmiłował się i na przełomie pażdziernika/listopada wraz z GM API 2.92 wypuścił taką możliwość

Do “tradycyjnego” wywołania (czyli nie via AJAX LOADER) należy dodać “&v=2.x&async=2&callback=loadMap”gdzie loadMap to nazwa naszej funkcji konfigurującej i inicjującej mapę (wcześniej jej wywołanie musieliśmy przypisać do zdarzenia onload).

Przykład

jQuery UI, jQuery 1.2 – najlepsze jest jeszcze lepsze!

Tuesday, September 11th, 2007

jQuery User Interface Library

To czego brakowało zwolennikom biblioteki jQuery to z pewnością brak akompaniującej biblioteki spełniającej zadania “prototype’owego” script.aculo.us’a. Biblioteka Interface – która pretendowała do tej roli – nie zyskała zbyt wielu sympatyków (powody: rozmiar, mała elastyczność, brak 100% kompatybilności z przeglądarkami). Twórca jQuery, John Resig, zapowiadał od kilku miesięcy, że jQuery dorobi się w końcu dopracowanej biblioteki obsługującej łebdwazerowe wodotryski. jQuery UI zapewni front-end developerom cały zestaw możliwości – drag&drop, zakładki (zapewne ze wsparciem dla przycisków nawigacji przeglądarki i zapamiętywaniem stanu via cookie), overlay i wiele innych… To wszystko już w niedzielę, 16. września. Nie mogę się doczekać!

Dla osłody dla wyczekujących jQuery Team wypuścił bibliotekę jQuery w odsłonie 1.2. Skok w numeracji wersji ma widoczne odzwierciedlenie w zmianach i nowych możliwościach. Wiele potrzebnych nowości, które powiększyły bibliotekę tylko o 5kB (biorąc pod uwagę wersję spakowaną p.a.c.k.e.r’em Deana Edwardsa, którą zapewne najczęściej się wykorzystuje w środowisku produkcyjnym).

Po pełną listę dodanych funkcjonalności odsyłam do WIKI jQuery. Moje faworyty to:

  • metoda offset(), która zapewnia dostęp do koordynatów elementu (top,left); oddzielna biblioteka dimensions będzie w wielu przypadkach zbędna
  • cross-domenowy JSON – od teraz nie trzeba tworzyć rozwiązań a’la proxy
  • poprawiona i rozbudowana serializacja wartości pól formularza – oddzielna biblioteka do obsługi formularzy będzie wielu w wypadkach zbędna
  • animacja stylu elementu w zakresie koloru, tła – wreszcie będziemy mogli tworzyć efektowne powiadomienia :-)
  • metoda triggerHandler() pozwalająca na wywołanie wszystkich event’ów przypisanych do konkretnego elementu DOM poza akcją domyślną
  • i ciekawa funkcja jak klonowanie fragmentu DOM wraz z przypisanymi do niego eventami.

Wielkie “jQuery’owe” święto