Dawno nie pisałem… opieprzam się jak trzeba 😀 no, ale…

Ostatnio w fabryczce postanowiłem użyć JQuery by wzbogacić aplikację GWT. Generalnie JQuery jest obecnie najlepszą biblioteką JavaScript jaka istnieje. Lekka (25KB – z kompresją), szybka, wydajna i co najważniejsze z bardzo prostym API. GWT znowuż jest chyba najwygodniejszym narzędziem do tworzenia GUI jeżeli nie chcemy wychodzić poza Javę lub gdy mamy w zespole „Swingersów” (nie mylić z pewną grupą eksperymentatorów seksualnych). API zbliżone do Swinga/AWT z niewielkimi rozszerzeniami właściwymi dla html.

Z JQuery interesował mnie tylko kawałek o animacjach, jednak wmyśl zasady DRY należało wykorzystać gotowy port, albo napisać coś przenośnego. Oczywiście Woojek Google od razu podpowiedział GWTQuery. Po szybkiej lustracji listy błędów doszedłem do wniosku, że to nie dla mnie. Szczególnie, że jak przeczytałem komentarz do błędu nr 8, to mało co z krzesła nie spadłem. Podwojenie czasu kompilacji nie jest możliwe (obecnie mamy klika modułów – 30 min walki w samym GWT). Trzeba zatem własnymi siłami przeportować JQuery na GWT.

Co nam jest tak naprawdę potrzebne

Jak się szybko okazało nie będzie to port 1:1, a raczej adapter wykorzystujący JSNI. Po drugie dość poważnym wrzodem okazał się brak metody setId pozwalającej na ustawienie htmlowego id dla obiektu w GWT. Jest za to ensureDebugId, ale wymaga dodania modułu com.google.gwt.user.Debug. No, ale nikt nie powiedział, że będzie łatwo. W każdym bądź razie, po dodaniu odpowiednich elementów w plikach xml przyszedł czas na stworzenie klasy JQuery. Klasa jest dość prosta do metody o takiej samej nazwie jak w JQuery dodaję jeszcze jeden parametr, ktory pozwala na identyfikację elementu. Następnie całość idzie przez JSNI bezpośrednio do metody JQuery. Na chwilę obecną wygląda to tak:

Listing 1. Adapter JQuery w GWT

package pl.koziolekweb.gwt.jquery;

/**
 * Klasa - fasada dla natywnych wywołań JQuery.
 *
 * @author Bartłomiej Kuczyński
 *
 */
public class JQuery {

	public static native void fadeIn(String elementSelector, Integer duration, String callback)/*-{
																$wnd.$(elementSelector).fadeIn(duration, function() {
																	eval(callback+"");
																});
																}-*/;

	public static native void fadeIn(String elementSelector, String duration, String callback)/*-{
																$wnd.$(elementSelector).fadeIn(duration, function() {
																	eval(callback+"");
																});
																}-*/;

	public static native void fadeOut(String elementSelector, Integer duration, String callback)/*-{
																$wnd.$(elementSelector).fadeOut(duration, function() {
																	eval(callback+"");
																});
																}-*/;

	public static native void fadeOut(String elementSelector, String duration, String callback)/*-{
																$wnd.$(elementSelector).fadeOut(duration, function() {
																	eval(callback+"");
																});
																}-*/;

	public static native void fadeTo(String elementSelector, Integer duration, Double opacity, String callback)/*-{
																		$wnd.$(elementSelector).fadeTo(duration, opacity, function() {
																			eval(callback+"");
																		});
																		}-*/;

	public static native void fadeTo(String elementSelector, String duration, Double opacity, String callback)/*-{
																		$wnd.$(elementSelector).fadeTo(duration, opacity, function() {
																			eval(callback+"");
																		});
																		}-*/;

	public static native void slideDown(String elementSelector, Integer duration, String callback)/*-{
																	$wnd.$(elementSelector).slideDown(duration, function() {
																		eval(callback+"");
																	});
																	}-*/;

	public static native void slideDown(String elementSelector, String duration, String callback)/*-{
																	$wnd.$(elementSelector).slideDown(duration, function() {
																		eval(callback+"");
																	});
																	}-*/;

	public static native void slideToggle(String elementSelector, Integer duration, String callback)/*-{
																	$wnd.$(elementSelector).slideToggle(duration, function() {
																		eval(callback+"");
																	});
																	}-*/;

	public static native void slideToggle(String elementSelector, String duration, String callback)/*-{
																	$wnd.$(elementSelector).slideToggle(duration, function() {
																		eval(callback+"");
																	});
																	}-*/;

	public static native void slideUp(String elementSelector, Integer duration, String callback)/*-{
																$wnd.$(elementSelector).slideUp(duration, function() {
																	eval(callback+"");
																});
																}-*/;

	public static native void slideUp(String elementSelector, String duration, String callback)/*-{
																$wnd.$(elementSelector).slideUp(duration, function() {
																	eval(callback+"");
																});
																}-*/;

}

Każda metoda ma dwie wersje, wynika to z faktu, że Java w przeciwieństwie do JS jest silnie typowana. Dodatkowo użycie metody eval() i parametru callback pozwala na wywołanie dodatkowego kodu JS po zakończeniu animacji.
Całość jest bardzo prosta i w miarę bezpieczna. Czasami tylko JQuery pójdzie w maliny… zapętli się przy jakiś dziwnych wywołaniach liczb jako string. Bywa zdarza się.