четверг, 14 февраля 2013 г.

Vaadin, доступ к недрам JavaScript. (перевод)

Заинтересовала тема JavaScript в Vaadin, а тут как раз Michael Vogt из команды Vaadin опубликовал небольшую статью в блоге Vaadin.
Представляю вам перевод статьи на русский, прошу поправить в комментариях, если где-то что-то не так переведено, так как опыта с переводами подобных статей пока мало.






Одним из наибольших плюсов Vaadin в том, что он определяет front-end часть на очень высоком уровне и заботиться о мелких деталях за вас. Но иногда требования к вашему приложению такие, что кое-что не может быть реализовано стандартными методами. Именно тогда вы может создать свои собственные виджеты.

Но есть такие ситуации, когда и этого не достаточно.
Причины могут быть следующие:
- Вам необходим прямой доступ к JavaScript из клиентской части приложения.
- Вам необходим доступ к клиентской части из JavaScript.
- Вам необходим доступ к некоторым функциям или полям которые объявлены как приватные в виджетах по-умолчанию, примером может быть рефлекция на стороне сервера.
- Код на стороне клиента компилируется слишком медленно.

JSNI JavaScript Native Interface спасет ваш день. Он позволит вам сделать все вышеперечисленное. Замечательно, не так ли?

Есть и загвоздки, конечно. Пожалуйста, обратите внимание, используйте это осторожно. При использовании этих методов вся ответственность лежит на вас. Придется заботиться, например, о различиях браузеров, о том, нет ли утечек памяти, о безопасности.
Для Java, тело функции JavaScript абсолютно непрозрачно, как и любой объект JavaScript.
Это значит, что для отладки JavaScript, придется использовать JavaScript отладчик, так как встроеный в Eclipse дебагер его не видит. В остальном JSNI работает очень прозрачно.

Давайте посмотрим как это работает:
- Добавьте ключевое слово native в описание функции.
- Тело функции оберните специальной комбинацией /*-{}-*/;
- Напишите ваш JavaScript между фигурными скобками.

Вот и все  JSNI функция выглядит например вот так:
private native void jsniFunction()
/*-{
           
}-*/;

или

public static native String jsniFunction( int value)
/*-{
    return "Parameter value: " + value;
}-*/;

или любой другой код.

Вас может удивить знак комментариев в начале строки, но ничего страшного, так надо, Eclipse все правильно отформатирует, проще говоря, поймет.

Теперь давайте рассмотрим решение тех 4-х ситуаций, которые были описаны выше, в начале:

- Вам необходим прямой доступ к JavaScript из клиентской части приложения.

Во-первых загрузите ваш JavaScript на главной странице. Это очень легко сделать с помощью аннотации @JavaScript({ "external.js" }) в вашем классе интерфейса. Подробное описание этого процесса здесь.
external.js может содержать что-то вроде этого:

function callme(String name) {
    alert("Hello " + name);
}

тогда вы можете получить к этому доступ так:

private native void jsniFunction() /*-{
           $wnd.callme("Vaadin");
}-*/;


- Вам необходим доступ к клиентской части из JavaScript.

Сначала нужно создать функцию, которая вызовет свой код на стороне клиента. Это требует специального синтаксиса, который выглядит так:

[instance-expr.]@class-name::method-name(param-signature)(arguments)

где:
instance-expr.: должен присутствовать при вызове экземпляра метода и отсутствовать при вызове статического метода.

class-name: это полное имя класса или его подкласса в котором объявлен метод.

param-signature : это внутренний Java метод, подписанный как определнный в JNI Type Signatures, но без указания возвращаемого методом типа, так как перегрузка метода не требуется.

arguments: список аргументов для передачи вызываемому методу.


Например:
Чтобы получить доступ к JavaScript функции, зарегистрируйте ее во время запуска вашего приложения, например как глобальный объект Window у JavaScript:

private native void registerJsniFunction() /*-{
           $wnd.jsnifunction = this.@com.example.Example::callIntoJava;
}-*/;

Примечание: код на стороне клиента запущен внутри фрейма, вы можете использовать  $wnd и $doc для обращения к нужным Window или Document элементам.

- Вам необходим доступ к некоторым функциям или полям которые объявлены как приватные в виджетах по-умолчанию.

Это может быть одна из самых недооцененных функций использования JNDI. Так как весь front-end код компилируется в JavaScript и все функции и переменные доступны глобально. Это означает, что когда ограничения доступа к Java не позволяет вам получить доступ к функции или полю, то можно легко получить его через JSNI.
Вот пример из DataGrid где мне нужен был доступ к ScrollPanel внутри него.

private native ScrollPanel getTableDataScroller()
    /*-{
       return this.@com.google.gwt.user.cellview.client.CustomDataGrid::tableDataScroller;
    }-*/;

Теперь вы можете получить доступ к нему, если он будет доступен в Java.

public HandlerRegistration addScrollHandler(ScrollHandler handler) {
           return getTableDataScroller().addScrollHandler(handler);
    }


- Код на стороне клиента компилируется слишком медленно.

Даже тогда, когда компилятор с большим усердием создал лучший на его взгляд JavaScript, ваш профайлер может сказать обратное. В этом случае вы можете представить собственную реализацию. Но, пожалуйста, в этом случае, не забывайте постить в баг-трекинг GWT.
Остались некоторые особенности, которые я не включил в примеры, для того, чтобы не усложнять их. Пожалуйста, посмотрите их в документации GWT.
В дополнение к этому посмотрите JavaScript Overlay Types, которые предоставят вам легкий доступ к JavaScript объектам, таким как JSON, например.

Я надеюсь, что мог бы показать вам больше, для понимания того, насколько мощным является JSNI. Но как говорится, с большой силой приходит и большая ответственность. Будьте, пожалуйста, осторожней ;-)

Вот и все сообщение о работе с GWT на низком-уровне. В следующий раз я расскажу как вы можете добавить WAI-ARIA  поддержку вашим виджетам.

Комментариев нет :

Отправить комментарий