Skip to content

Commit

Permalink
prototyping with other client-server-comm improvements that could be …
Browse files Browse the repository at this point in the history
…useful for Flow (add-ons)
  • Loading branch information
mstahv committed Aug 20, 2024
1 parent 37478fd commit 5804d80
Show file tree
Hide file tree
Showing 2 changed files with 120 additions and 0 deletions.
69 changes: 69 additions & 0 deletions src/main/java/org/vaadin/addons/velocitycomponent/VElement.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package org.vaadin.addons.velocitycomponent;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.vaadin.flow.dom.Element;
import com.vaadin.flow.function.SerializableConsumer;
import com.vaadin.flow.shared.Registration;
import elemental.json.JsonType;
import elemental.json.JsonValue;
import org.apache.commons.lang3.StringUtils;

import static java.util.Arrays.stream;

public class VElement {

private static ObjectMapper objectMapper = new ObjectMapper();

private final Element element;

private VElement(Element element) {
this.element = element;
}

public static VElement of(Element element) {
return new VElement(element);
}

/**
* Listen to an event of a specific type. The event type is determined by the class of the event,
* the name can contain optional "Event" postfix which is ignored in DOM event name.
* The event payload is expected to be a JSON object or a string and serialized to the event type
* using Jackson ObjectMapper.
*
* On the client side, the event should be dispatched with a CustomEvent with the detail property.
*
* @param eventType the class of the event
* @param listener the listener to be called when the event is fired
* @return a registration that can be used to remove the listener
* @param <T> the type of the event
*/
public <T> Registration on(Class<T> eventType, SerializableConsumer<T> listener) {
String simpleName = eventType.getSimpleName();
if(simpleName.endsWith("Event")) {
simpleName = simpleName.substring(0, simpleName.length() - 5);
}
String kebabCased = stream(StringUtils.splitByCharacterTypeCamelCase(simpleName))
.map(s -> s.toLowerCase())
.reduce((a, b) -> a + "-" + b).get();

return element.addEventListener(kebabCased, event -> {
JsonValue jsonValue = event.getEventData().get("event.detail");
T value;
if(jsonValue.getType() == JsonType.OBJECT) {
try {
value = objectMapper.readValue(jsonValue.toJson(), eventType);
} catch (Exception e) {
throw new RuntimeException(e);
}
} else {
try {
value = objectMapper.readValue(jsonValue.asString().toString(), eventType);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
listener.accept(value);
}).addEventData("event.detail");
}
}
51 changes: 51 additions & 0 deletions src/test/java/org/vaadin/addons/usageexample/VElementView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package org.vaadin.addons.usageexample;

import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.html.H1;
import com.vaadin.flow.component.html.Paragraph;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.router.Route;
import org.vaadin.addons.velocitycomponent.VElement;

@Route
public class VElementView extends VerticalLayout {

public record FooBar(String foo, String bar, String car) {}

public VElementView() {
add(new H1("Example to listen DOM events easily!"));

VElement.of(getElement()).on(FooBar.class, event -> {
String bar = event.bar();
add(new Paragraph("Received foo-bar event with detail: " + event));
});

add(new Button("Click me", e -> {
getElement().executeJs("""
this.dispatchEvent(new CustomEvent('foo-bar', {
detail: {
foo: 'foo',
bar: 'bar',
car: 'car'
}
}));
""");
}));

add(new Button("Click me too", e -> {
// This is in theory bit more efficient for the server
// as it does not need to deserialize-serialize (with GWT library)
// and then desirialize with Jackson, but only once with Jackson
getElement().executeJs("""
this.dispatchEvent(new CustomEvent('foo-bar', {
detail: JSON.stringify({
foo: 'foo',
bar: 'bar',
car: 'car'
})
}));
""");
}));

}
}

0 comments on commit 5804d80

Please sign in to comment.