Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement generic JavaScript component wrapper #1165

Closed
jreznot opened this issue Aug 17, 2018 · 2 comments
Closed

Implement generic JavaScript component wrapper #1165

jreznot opened this issue Aug 17, 2018 · 2 comments
Assignees
Labels
severity: major The defect affects major functionality. It has a workaround but is difficult. state: fixed Fixed by the developer type: enhancement New feature or request ver: 7.0.0 Fixed in version
Milestone

Comments

@jreznot
Copy link
Contributor

jreznot commented Aug 17, 2018

Provide simple UI component that can work with any JS wrapper without Vaadin component implementation.

It should be easy to use it:

JavaScriptComponent map = uiComponents.create(JavaScriptComponent.class);
map.setScriptLocation("map.js"); // set entry point
map.setDependencies("leaflet.js", "leaflet-draw.js"); // add dependencies
map.setFunction("callMe", args -> {}); // expose fuinctions
map.setState(new MapState()); // any POJO as state

Provide XML element with properties for declarative configuration, e.g. we can configure dynamic properties and JS dependencies in XML.

Do not forget:

  • CSS resources
  • Images
  • JS resources

Dependency sources:

  • classpath (default)
  • webjar://
  • vaadin://
@jreznot jreznot added the type: enhancement New feature or request label Aug 17, 2018
@jreznot jreznot added this to the Release 7.0 milestone Aug 17, 2018
@jreznot jreznot self-assigned this Aug 17, 2018
@jreznot
Copy link
Contributor Author

jreznot commented Aug 17, 2018

Also, we should provide base class in case we need to create subclass with API.

@jreznot jreznot modified the milestones: Release 7.0, Release 7.1 Aug 21, 2018
@jreznot jreznot modified the milestones: Release 7.1, Release 7.0 Sep 25, 2018
@jreznot jreznot assigned glebfox and unassigned jreznot Nov 26, 2018
@jreznot jreznot added client: web severity: major The defect affects major functionality. It has a workaround but is difficult. labels Nov 26, 2018
glebfox pushed a commit to cuba-platform/vaadin that referenced this issue Dec 7, 2018
@haulmont-git haulmont-git added the ver: 7.0.0 Fixed in version label Dec 7, 2018
@glebfox
Copy link
Member

glebfox commented Dec 7, 2018

Description

A new UI component that can work with any JS wrapper without Vaadin component implementation has been added. And its name is JavaScriptComponent.

This component has the following features:

  1. Define a list of dependencies(js, css). Each dependency corresponds to one of the sources
    • WebJar resource - starts with webjar://
    • File placed within VAADIN directory - starts with vaadin://

Example:

jsComponent.addDependencies(
        "webjar://jquery:jquery.min.js",
        "webjar://jquery-ui:jquery-ui.min.js",
        "webjar://jquery-ui:jquery-ui.css",
        "vaadin://slider-connector.js"
);
  1. Sets an initialization function name that will be used to find an entry point for the JS component connector. CAUTION: the initialization function name must be unique within window.

  2. Sets a state object that can be used in the client-side JS connector and accessible from the data field of the component's state.

Example:

MyState state = new MyState();
state.minValue = 0;
state.maxValue = 100;
jsComponent.setState(state);

Example:

jsComponent.setInitFunctionName("com_company_demo_web_toolkit_ui_slider_SliderServerComponent");
  1. Register a function that can be called from the JavaScript using the provided name.

Example:
Java

jsComponent.addFunction("valueChanged", callbackEvent -> {
    JsonArray arguments = callbackEvent.getArguments();

    notifications.create()
            .withCaption(StringUtils.join(arguments, ", "))
            .show();
});

JS

this.valueChanged(values);
  1. Invoke a named function that the connector JavaScript has added to the JavaScript connector wrapper object.

Java

jsComponent.callFunction("showNotification ");

JS

this.showNotification = function () {
	alert("TEST");
};

Example

Let's integrate Quill Rich Text Editor from https://quilljs.com/.

  1. Add the following dependency to the web module
compile('org.webjars.npm:quill:1.3.6')
  1. Withint the web/VAADIN/quill directory on the web module craete quill-connector.js.

  2. Add the following connector implementation:

com_company_demo_web_screens_Sandbox = function () {
    var connector = this;
    var element = connector.getElement();
    element.innerHTML = "<div id=\"editor\">" +
        "<p>Hello World!</p>" +
        "<p>Some initial <strong>bold</strong> text</p>" +
        "<p><br></p>" +
        "</div>";

    connector.onStateChange = function () {
        var state = connector.getState();
        var data = state.data;

        var quill = new Quill('#editor', data.options);

        // Subscribe on textChange event
        quill.on('text-change', function (delta, oldDelta, source) {
            if (source === 'user') {
                connector.valueChanged(quill.getText(), quill.getContents());
            }
        });
    }
};
  1. Create a screen with the following jsComponent definition:
<jsComponent id="quill"
             initFunctionName="com_company_demo_web_screens_Sandbox"
             height="200px"
             width="400">
    <dependencies>
        <dependency path="webjar://quill:dist/quill.js"/>
        <dependency path="webjar://quill:dist/quill.snow.css"/>
        <dependency path="vaadin://quill/quill-connector.js"/>
    </dependencies>
</jsComponent>
  1. Add the following screen controller implementation:
@UiController("demo_Sandbox")
@UiDescriptor("sandbox.xml")
public class Sandbox extends Screen {
    @Inject
    private JavaScriptComponent quill;

    @Inject
    private Notifications notifications;

    @Subscribe
    protected void onInit(InitEvent event) {
        QuillState state = new QuillState();
        state.options = ParamsMap.of("theme", "snow",
                "placeholder", "Compose an epic...");

        quill.setState(state);

        quill.addFunction("valueChanged", javaScriptCallbackEvent -> {
            String value = javaScriptCallbackEvent.getArguments().getString(0);
            notifications.create()
                    .withCaption(value)
                    .withPosition(Notifications.Position.BOTTOM_RIGHT)
                    .show();
        });
    }

    class QuillState {
        public Map<String, Object> options;
    }
}

Or simply download a demo project: js-component.zip

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
severity: major The defect affects major functionality. It has a workaround but is difficult. state: fixed Fixed by the developer type: enhancement New feature or request ver: 7.0.0 Fixed in version
Projects
None yet
Development

No branches or pull requests

4 participants