5.8.8.3. Подключение JavaScript библиотеки
В данном примере мы подключим компонент Slider из библиотеки jQuery UI. Слайдер будет иметь два ползунка, определяющих диапазон значений.
Создайте новый проект в CUBA Studio и назовите его jscomponent.
Далее нажмите на кнопку Create new UI component. Откроется окно создания визуального компонента New UI component page. В секции Component type выберите значение JavaScript component.
 
  В поле Vaadin component class name диалога генерации компонента введите значение SliderServerComponent.
Уберите флажок Integrate into Generic UI. Процесс интеграции компонента в универсальный интерфейс аналогичен описанному в разделе Подключение аддона Vaadin с интеграцией в Generic UI, поэтому рассматривать его здесь мы не будем.
После нажатия кнопки OK Studio сгенерирует файлы:
-  
SliderServerComponent- интегрированный с JavaScript компонент Vaadin. -  
SliderState- класс состояния компонента Vaadin. -  
slider-connector.js- JavaScript коннектор для компонента Vaadin 
Последовательно пройдемся по сгенерированным заготовкам файлов и внесем в них необходимые изменения.
-  
Класс состояния
SliderStateопределяет, какие данные будут пересылаться между сервером и клиентом. В нашем случае мы будем пересылать информацию о минимальном и максимальном возможном значении и выбранных значениях слайдера.package com.company.jscomponent.web.toolkit.ui.slider; import com.vaadin.shared.ui.JavaScriptComponentState; public class SliderState extends JavaScriptComponentState { public double[] values; public double minValue; public double maxValue; } -  
Серверный компонент Vaadin
SliderServerComponent.package com.company.jscomponent.web.toolkit.ui.slider; import com.vaadin.annotations.StyleSheet; import com.vaadin.ui.AbstractJavaScriptComponent; import com.vaadin.annotations.JavaScript; import elemental.json.JsonArray; @JavaScript({"slider-connector.js", "jquery-ui.js"}) @StyleSheet({"jquery-ui.css"}) public class SliderServerComponent extends AbstractJavaScriptComponent { public interface ValueChangeListener { void valueChanged(double[] newValue); } private ValueChangeListener listener; public SliderServerComponent() { addFunction("valueChanged", arguments -> { JsonArray array = arguments.getArray(0); double[] values = new double[2]; values[0] = array.getNumber(0); values[1] = array.getNumber(1); listener.valueChanged(values); }); } public void setValue(double[] value) { getState().values = value; } public double[] getValue() { return getState().values; } public double getMinValue() { return getState().minValue; } public void setMinValue(double minValue) { getState().minValue = minValue; } public double getMaxValue() { return getState().maxValue; } public void setMaxValue(double maxValue) { getState().maxValue = maxValue; } @Override protected SliderState getState() { return (SliderState) super.getState(); } public ValueChangeListener getListener() { return listener; } public void setListener(ValueChangeListener listener) { this.listener = listener; } }Серверный компонент Vaadin определяет набор геттеров и сеттеров для работы с состоянием слайдера, а также интерфейс слушателя изменения значений. Класс компонента должен быть унаследован от
AbstractJavaScriptComponent.Метод
addFunction()в конструкторе класса объявляет обработчик RPC-вызова функцииvalueChanged()с клиента.Аннотации
@JavaScriptи@StyleSheetуказывают на файлы, которые должны быть загружены на веб-страницу. В нашем примере это JavaScript файлы библиотеки jQuery UI и коннектора, а также файл со стилями для jQuery UI. Расположим их в одном Java-пакете с серверным компонентом. 
Скачайте архив jQuery UI с сайта http://jqueryui.com/download и поместите файлы jquery-ui.js и jquery-ui.css в пакет с классом SliderServerComponent. На странице скачивания jQuery UI у вас будет возможность выбрать компоненты, которые будут помещены в архив. Для нашего примера достаточно выделить пункт Slider группы Widgets.
 
  -  
JavaScript коннектор
slider-connector.js.com_company_jscomponent_web_toolkit_ui_slider_SliderServerComponent = function() { var connector = this; var element = connector.getElement(); $(element).html("<div/>"); $(element).css("padding", "5px 10px"); var slider = $("div", element).slider({ range: true, slide: function(event, ui) { connector.valueChanged(ui.values); } }); connector.onStateChange = function() { var state = connector.getState(); slider.slider("values", state.values); slider.slider("option", "min", state.minValue); slider.slider("option", "max", state.maxValue); $(element).width(state.width); } }Коннектор представляет собой функцию, которая при загрузке веб-страницы проинициализирует JavaScript компонент. Имя функции должно соответствовать полному имени класса серверного компонента, где точки в имени пакета заменены на символ подчеркивания.
Vaadin добавляет ряд полезных методов в фунцию коннектора. Например,
this.getElement()возвращает HTML DOM элемент компонента,this.getState()возвращает объект-состояние.В нашем примере коннектор делает следующее:
-  
Инициализирует компонент
sliderиз библиотеки jQuery UI. При изменении положения одного из ползунков будет вызывана функцияslide(). Мы видим, что она в свою очередь вызывает методvalueChanged()коннектора.valueChanged()- это метод, который мы объявили на стороне сервера в классеSliderServerComponent. -  
Объявляет функцию
onStateChange(). Она будет вызываться при изменении объекта-состояния на стороне сервера. 
 -  
 
Для демонстрации работы компонента создадим сущность Product с тремя атрибутами:
-  
nameтипа String -  
minDiscountтипа Double -  
maxDiscountтипа Double 
Затем сгенерируем стандартные экраны для данной сущности. Обратите внимание, что мы используем не универсальный компонент платформы, а "нативный" компонент Vaadin. Следовательно экраны должны располагаться в модуле Web, а не в GUI - укажите это в окне генерации стандартных экранов.
В редакторе сущности мы хотим устанавливать минимальное и максимальное значение скидки с помощью компонента slider, который мы только что создали.
Перейдите к файлу product-edit.xml. Поля minDiscount и maxDiscount сделайте нередактируемыми, добавив к соответствующим элементам атрибут editable="false". Затем добавьте в fieldGroup новое кастомное поле slider.
В результате XML-дескриптор экрана редактирования должен выглядеть следующим образом:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<window xmlns="http://schemas.haulmont.com/cuba/window.xsd"
        caption="msg://editCaption"
        class="com.company.jscomponent.web.product.ProductEdit"
        datasource="productDs"
        focusComponent="fieldGroup"
        messagesPack="com.company.jscomponent.web.product">
    <dsContext>
        <datasource id="productDs"
                    class="com.company.jscomponent.entity.Product"
                    view="_local"/>
    </dsContext>
    <layout expand="windowActions"
            spacing="true">
        <fieldGroup id="fieldGroup"
                    datasource="productDs">
            <column width="250px">
                <field id="name"/>
                <field id="minDiscount" editable="false"/>
                <field id="maxDiscount" editable="false"/>
                <field id="slider" custom="true"/>
            </column>
        </fieldGroup>
        <frame id="windowActions"
               screen="editWindowActions"/>
    </layout>
</window> 
  Перейдите к файлу ProductEdit.java. Замените его содержимое следующим кодом:
package com.company.jscomponent.web.product;
import com.company.jscomponent.entity.Product;
import com.company.jscomponent.web.toolkit.ui.slider.SliderServerComponent;
import com.haulmont.cuba.gui.components.AbstractEditor;
import com.haulmont.cuba.gui.components.Component;
import com.haulmont.cuba.gui.components.FieldGroup;
import com.haulmont.cuba.gui.components.VBoxLayout;
import com.haulmont.cuba.gui.xml.layout.ComponentsFactory;
import com.haulmont.cuba.web.gui.components.WebComponentsHelper;
import com.vaadin.ui.Layout;
import javax.inject.Inject;
public class ProductEdit extends AbstractEditor<Product> {
    @Inject
    private FieldGroup fieldGroup;
    @Inject
    private ComponentsFactory componentsFactory;
    @Override
    protected void initNewItem(Product item) {
        super.initNewItem(item);
        item.setMinDiscount(15.0);
        item.setMaxDiscount(70.0);
    }
    @Override
    protected void postInit() {
        super.postInit();
        fieldGroup.addCustomField("slider", (datasource, propertyId) -> {
            Component box = componentsFactory.createComponent(VBoxLayout.class);
            Layout vBox = (Layout) WebComponentsHelper.unwrap(box);
            SliderServerComponent slider = new SliderServerComponent();
            slider.setValue(new double[] {getItem().getMinDiscount(), getItem().getMaxDiscount()});
            slider.setMinValue(0);
            slider.setMaxValue(100);
            slider.setWidth("240px");
            slider.setListener(newValue -> {
                getItem().setMinDiscount(newValue[0]);
                getItem().setMaxDiscount(newValue[1]);
            });
            vBox.addComponent(slider);
            return box;
        });
    }
} 
  В методе initNewItem() мы проставляем начальные значения скидок для нового продукта.
В методе init() инициализируем кастомное поле для слайдера. Для компонента слайдера мы проставляем текущие значения, максимальное и минимальное значения, а также объявляем слушатель изменений значений. При движении ползунка мы будем проставлять новые значения скидок в соответвующие поля редактируемой сущности.
Запустите проект и откройте экран редактирования продукта. Изменение положения ползунка на слайдере должно изменять значение в соответствующем текстовом поле.