Code Monkey home page Code Monkey logo

elemento's Introduction

Verify Codebase Javadoc Maven Central GWT3/J2CL compatible Chat on Gitter

Elemento

Elemento simplifies working with Elemental2. In a nutshell Elemento brings the following features to the table:

  • Type safe builders, event handlers and CSS selectors
  • Helper methods to manipulate the DOM tree
  • Execute asynchronous tasks in parallel, in sequence or as long as a certain condition is met.
  • Simple, non-invasive, slash-based router (/a/b/c)
  • Small logging wrapper around console.log using categories, log levels, and a predefined log format.
  • Ready to be used with GWT and J2CL
  • Minimal dependencies
    • Elemental2 1.1.0 (elemental2-core, elemental2-dom and elemental2-webstorage)
    • GWT project (org.gwtproject.event:gwt-event and org.gwtproject.safehtml:gwt-safehtml)

TOC

Get Started

Elemento is available in Maven Central. The easiest way is to import its BOM

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.jboss.elemento</groupId>
            <artifactId>elemento-bom</artifactId>
            <version>1.4.12</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

and add a dependency to either

<dependency>
    <groupId>org.jboss.elemento</groupId>
    <artifactId>elemento-core</artifactId>
    <type>gwt-lib</type>
</dependency>

or

<dependency>
    <groupId>org.jboss.elemento</groupId>
    <artifactId>elemento-core</artifactId>
</dependency>

depending on your stack. If you're using GWT, inherit from org.jboss.elemento.Core:

<module>
    <inherits name="org.jboss.elemento.Core"/>
</module>

Builder API

When working with GWT Elemental it is often awkward and cumbersome to create an hierarchy of elements. Even simple structures like

<section class="main">
    <input class="toggle-all" type="checkbox">
    <label for="toggle-all">Mark all as complete</label>
    <ul class="todo-list">
        <li>
            <div class="view">
                <input class="toggle" type="checkbox" checked>
                <label>Taste Elemento</label>
                <button class="destroy"></button>
            </div>
            <input class="edit">
        </li>
    </ul>
</section>

lead to a vast amount of Document.createElement() and chained Node.appendChild() calls. With Elemento creating the above structure is as easy as

import static org.jboss.elemento.Elements.*;
import static org.jboss.elemento.InputType.checkbox;
import static org.jboss.elemento.InputType.text;

HTMLElement section = section().css("main")
        .add(input(checkbox).id("toggle-all").css("toggle-all"))
        .add(label()
                .apply(l -> l.htmlFor = "toggle-all")
                .textContent("Mark all as complete"))
        .add(ul().css("todo-list")
                .add(li()
                        .add(div().css("view")
                                .add(input(checkbox)
                                        .css("toggle")
                                        .checked(true))
                                .add(label().textContent("Taste Elemento"))
                                .add(button().css("destroy")))
                        .add(input(text).css("edit"))))
        .element();

The class Elements provides convenience methods to create the most common elements. It uses a fluent API to create and append elements on the fly. Take a look at the API documentation for more details.

References

When creating large hierarchies of elements you often need to assign an element somewhere in the tree. Use an inline assignment together with element() to create and assign the element in one go:

import static org.jboss.elemento.Elements.*;

final HTMLElement count;
final HTMLElement footer = footer()
        .add(count = span().css("todo-count").element())
        .element();

Event Handlers

Elemento provides methods to easily register event handlers. There are constants for most of the known event types.

You can either add event handlers when building the element hierarchy:

import static org.jboss.elemento.Elements.*;
import static org.jboss.elemento.EventType.*;
import static org.jboss.elemento.InputType.checkbox;
import static org.jboss.elemento.InputType.text;

HTMLLIElement listItem = li()
        .add(div().css("view")
                .add(input(checkbox)
                        .css("toggle")
                        .on(change, event -> toggle()))
                .add(label()
                        .textContent("Taste Elemento")
                        .on(dblclick, event -> edit()))
                .add(button()
                        .css("destroy")
                        .on(click, event -> destroy())))
        .add(input(text)
                .css("edit")
                .on(keydown, this::keyDown)
                .on(blur, event -> blur()))
        .element();

or register them later using EventType.bind():

import org.gwtproject.event.shared.HandlerRegistration;
import static elemental2.dom.DomGlobal.alert;
import static org.jboss.elemento.EventType.bind;
import static org.jboss.elemento.EventType.click;

HandlerRegistration handler = bind(listItem, click, event -> alert("Clicked"));

The latter approach returns org.gwtproject.event.shared.HandlerRegistration which you can use to remove the handler again.

In order to make it easier to work with keyboard events, Elemento provides an enum with the most common keyboard codes:

import elemental2.dom.KeyboardEvent;
import static org.jboss.elemento.Key.Escape;
import static org.jboss.elemento.Key.Enter;

void keyDown(KeyboardEvent event) {
    if (Escape.match(event)) {
        ...
    } else if (Enter.match(event)) {
        ...
    }
}

Typesafe CSS Selectors

Elemento provides a typesafe selector API. It can be used to express simple CSS selector like .class or #id up to complex selectors like

#main [data-list-item|=foo] a[href^="http://"] > .fas.fa-check, .external[hidden]

This selector can be created with

import org.jboss.elemento.By;
import static org.jboss.elemento.By.AttributeOperator.CONTAINS_TOKEN;
import static org.jboss.elemento.By.AttributeOperator.STARTS_WITH;

By selector = By.group(
        By.id("main")
                .desc(By.data("listItem", CONTAINS_TOKEN, "foo")
                        .desc(By.element("a").and(By.attribute("href", STARTS_WITH, "http://"))
                                .child(By.classname(new String[]{"fas", "fa-check"})))),
        By.classname("external").and(By.attribute("hidden"))
);

The selector can be used to find single or all HTML elements:

import org.jboss.elemento.By;
import static org.jboss.elemento.By.AttributeOperator.STARTS_WITH;
import static org.jboss.elemento.Elements.a;
import static org.jboss.elemento.Elements.body;

By selector = By.element("a").and(By.attribute("href", STARTS_WITH, "http://"));
for (HTMLElement element : body().findAll(selector)) {
    a(element).css("external");
}

Custom Elements

Elemento makes it easy to create custom elements. As for Elemento custom elements are a composite of HTML elements and / or other custom elements. They're ordinary classes which can hold state or register event handlers. The only requirement is to implement IsElement<E extends HTMLElement> and return a root element:

import static org.jboss.elemento.Elements.*;

class TodoItemElement implements IsElement<HTMLElement> {

    private final HTMLElement root;
    private final HTMLInputElement toggle;
    private final HTMLElement label;
    private final HTMLInputElement summary;

    TodoItemElement(TodoItem item) {
        this.root = li().data("item", item.id)
                .add(div().css("view")
                        .add(toggle = input(checkbox).css("toggle")
                                .checked(item.completed)
                                .element())
                        .add(label = label().textContent(item.text).element())
                        .add(destroy = button().css("destroy").element()))
                .add(summary = input(text).css("edit").element())
                .element();
        this.root.classList.toggle("completed", item.completed);
    }

    @Override
    public HTMLElement element() {
        return root;
    }

    // event handlers omitted
}

The builder API has support for IsElement<E extends HTMLElement> which makes it easy to use custom elements when building the element hierarchy:

import static org.jboss.elemento.Elements.ul;

TodoItemRepository repository = ...;
TodoItemElement[] itemElements = repository.items().stream()
        .map(TodoItemElement::new)
        .toArray();
ul().addAll(itemElements).element();

Goodies

Besides the builder API, Elemento comes with a bunch of static helper methods that roughly fall into these categories:

  1. Get notified when an element is attached to and detached from the DOM tree.
  2. Iterate over elements.
  3. Methods to manipulate the DOM tree (add, insert and remove elements).
  4. Methods to manipulate an element.
  5. Methods to generate safe IDs.

See the API documentation of Elements for more details.

Attach / Detach

Implement Attachable to get notified when an element is attached to and detached from the DOM tree. The attachable interface provides a static method to easily register the callbacks to attach(MutationRecord) and detach(MutationRecord):

import elemental2.dom.MutationRecord;
import org.jboss.elemento.Attachable;
import org.jboss.elemento.IsElement;
import static elemental2.dom.DomGlobal.console;
import static org.jboss.elemento.Elements.li;

class TodoItemElement implements IsElement<HTMLElement>, Attachable {

    private final HTMLElement root;

    TodoItemElement(TodoItem item) {
        this.root = li().element();
        Attachable.register(root, this);
    }

    @Override
    public HTMLElement element() {
        return root;
    }

    @Override
    public void attach(MutationRecord mutationRecord) {
        console.log("Todo item has been attached");
    }

    @Override
    public void detach(MutationRecord mutationRecord) {
        console.log("Todo item has been detached");
    }
}

Elemento uses the MutationObserver API to detect changes in the DOM tree and passes an MutationRecord instance to the attach(MutationRecord) and detach(MutationRecord) methods. This instance contains additional information about the DOM manipulation.

Iterators / Iterables / Streams

Elemento provides several methods to iterate over node lists, child elements or elements returned by a selector. There are methods which return Iterator, Iterable and Stream.

See the API documentation of Elements for more details.

SVG & MathML

Elemento comes with basic support for SVG and MathML.

SVG

To create SVG elements, add the following dependency to your POM:

<dependency>
    <groupId>org.jboss.elemento</groupId>
    <artifactId>elemento-svg</artifactId>
    <version>1.4.12</version>
</dependency>

In your GWT module inherit from org.jboss.elemento.SVG:

<module>
    <inherits name="org.jboss.elemento.SVG"/>
</module>

Finally, use the static methods in org.jboss.elemento.svg.SVG to create SVG elements.

MathML

To create MathML elements, add the following dependency to your POM:

<dependency>
    <groupId>org.jboss.elemento</groupId>
    <artifactId>elemento-mathml</artifactId>
    <version>1.4.12</version>
</dependency>

In your GWT module inherit from org.jboss.elemento.MathML:

<module>
    <inherits name="org.jboss.elemento.MathML"/>
</module>

Finally, use the static methods in org.jboss.elemento.mathml.MathML to create MathML elements.

Flow

The module elemento-flow provides a way to execute a list of asynchronous tasks in parallel or sequentially, or to execute a single task repeatedly as long as certain conditions are met.

See the API documentation of Flow for more details.

Parallel

// datetime format is "2022-03-31T11:03:39.348365+02:00"
Task<FlowContext> currentTime = context -> fetch("https://worldtimeapi.org/api/timezone/Europe/Berlin")
        .then(Response::json)
        .then(json -> Promise.resolve(Js.<JsPropertyMap<String>>cast(json).get("datetime").substring(11, 23)))
        .then(context::resolve);
double ms = 500 + new Random().nextInt(2000);
Task<FlowContext> delay = context -> new Promise<>((res, __) -> setTimeout(___ -> res.onInvoke(context), ms));

// execute the two tasks in parallel
Flow.parallel(new FlowContext(), List.of(currentTime, delay))
        .subscribe(context -> console.log("Current time: " + context.pop("n/a")));

Sequential

// datetime format is "2022-03-31T11:03:39.348365+02:00"
Task<FlowContext> currentTime = context -> fetch("https://worldtimeapi.org/api/timezone/Europe/Berlin")
        .then(Response::json)
        .then(json -> Promise.resolve(Js.<JsPropertyMap<String>>cast(json).get("datetime").substring(11, 23)))
        .then(context::resolve);
double ms = 500 + new Random().nextInt(2_000);
Task<FlowContext> delay = context -> new Promise<>((res, __) -> setTimeout(___ -> res.onInvoke(context), ms));

// execute the two tasks in sequence and cancel after 1_000 ms
Flow.parallel(new FlowContext(), List.of(currentTime, delay))
        .timeout(1_000)
        .subscribe(context -> console.log("Current time: " + context.pop("n/a")));

Repeated

Task<FlowContext> currentTime = context -> fetch("https://worldtimeapi.org/api/timezone/Europe/Berlin")
        .then(Response::json)
        .then(json -> Promise.resolve(Js.<JsPropertyMap<String>>cast(json).get("datetime").substring(11, 23)))
        .then(context::resolve);

// fetch the current time until the milliseconds end with "0" and cancel after 5 iterations
Flow.repeat(new FlowContext(), currentTime)
        .while_(context -> !context.pop("").endsWith("0"))
        .iterations(5)
        .subscribe(context -> console.log("Current time: " + context.pop("n/a")));

Router

Elemento offers a very basic router. The router is minimal invasive and built around a few simple concepts:

  • Route: Annotation that can be used to decorate pages. An annotation processor collects all classes annotated with @Route and generates an implementation of Routes.
  • Routes: Provides a map of places and their corresponding pages. This can be used to register all places in one go.
  • Place: Data class that represents a place in an application. A place is identified by a route, and can have an optional title and a custom root element. If present the children of the root element are replaced by the elements of the page.
  • Page: Simple interface that represents a collection of HTML elements. Implementations need to implement a single method: Iterable<HTMLElement> elements()
  • PlaceManager: Class that keeps track of registered places, handles navigation events, and updates the DOM accordingly. The place manager can be customized using builder like methods and has a start() method to show the initial page.

See the API documentation of PlaceManager for more details.

@Route("/")
public class HomePage implements Page {

    @Override
    public Iterable<HTMLElement> elements() {
        return singletonList(div()
                .add(h(1, "Welcome"))
                .add(p().textContent("Hello world!"))
                .element());
    }
}

public class Application {

    public void entryPoint() {
        body().add(div().id("main"));
        new PlaceManager()
                .root(By.id("main"))
                .register(new Place("/"), HomePage::new)
                // could also be registered with
                // .register(RoutesImpl.INSTANCE.places());
                .start();
    }
}

Logger

Elemento contains a small wrapper around console.log that uses categories, log levels, and a predefined log format.

The different log methods delegate to the corresponding methods in console:

  1. Logger.error(String, Object... params) โ†’ console.error()
  2. Logger.warn(String, Object... params) โ†’ console.warn()
  3. Logger.info(String, Object... params) โ†’ console.info()
  4. Logger.debug(String, Object... params) โ†’ console.debug()

Get loggers

To get a logger use Logger.getLogger(String category).

package org.acme;

public class Foo {

    private static final Logger logger = Logger.getLogger(Foo.class.getName());
}

You can use an arbitrary string as category. By using a hierarchical category, you can override subcategories. String substitutions are supported, and you can pass a variable list of parameters to the log methods.

The log level is set globally for all categories using Logger.setLevel(Level level). You can override the level for one category using Logger.setLevel(String category, Level level). To reset a category, use Logger.resetLevel(String category). If the category contains ., it is interpreted hierarchically. This means that if the category org.jboss is overridden, this is also applied to all subcategories (unless overridden otherwise).

Log format

The log format is predefined as

HH:mm:ss.SSS <level> [<category>] <message>

and cannot be customized. If the category is a fully qualified class name, the package names are shortened. In any case the category is trimmed, and right aligned.

Controlling log levels from JavaScript

The logger module exports some methods with slightly adjusted signatures to JavaScript. You can use them for instance in the browser dev tools to control the global and category based log levels:

  • org.jboss.elemento.logger.Logger.setLevel(String level) - sets the global log level
  • org.jboss.elemento.logger.Logger.setLevel(String category, String level) - overrides the log level for one category
  • org.jboss.elemento.logger.Logger.resetLevel(String category) - resets the log level for the category to the global log level

Please use the fully qualified name!

Samples

Elemento comes with different sample applications to showcase and test the various modules. They're available at https://hal.github.io/elemento/samples/

Contributing

If you want to contribute to Elemento, please follow the steps in contribution.

Get Help

If you need help feel free to contact us at Gitter, browse the API documentation or file an issue.

elemento's People

Contributors

alejandrocq avatar anbuck avatar anbuckim avatar dependabot[bot] avatar gte619n avatar hpehl avatar ibaca avatar mseele avatar tdesjardins avatar tyler-ham avatar vegegoku avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

elemento's Issues

Foreach loop in body observer throws class cast exception in chrome

iterate over a node list received from mutation observer with foreach

for (Node node : nodes) {
}

it throws class cast exception
and this happens when the node is not an element, but a text or comment node
in firefox it works without errors

the solution for this is to use normal loops and do Js.uncheckedCast() to node, then we check the type of the node if it is an element node.

Alternative builder strategy

(Iuff... I'll update this comment later)

  • AttacheableElement alternative: usually you either use inside-widget events or logic events, inside-widget event are safe to just leave it connected forever, ignoring the registration handler, otherwise, logic event frequently requires a correct event subscription handling, but as this is usually done in the presenter, this not need to be supported in the Builder. So, it is safe to just ignore the registration handlers in the builder.
  • element stack might be useful but, as the most important point is type safety, this make much more difficult to use element type-specific builder, also the references and event handlers are only required because this stacks, if the stack is removed and a per element builder is created both implementation and use gets easier, and a builder-specific-per-type can be created.
  • The current implementation uses inheritance to extends HTMLElement utilities, but there is an alternative that is using inheritance to create a more specific builder per element type.

https://github.com/ibaca/elemento
https://github.com/ibaca/rxtodo-gwt

This also revealed various problems with the old testing strategy, I have fixed using gwtmokito and making a dynamic mock of elements, but I'm not sure this is practical in the long term.

org.gwtproject.safehtml:safehtml has dependency on gwt-user

I'm fairly new to all this stuff so I apologize if this is more of a question than an issue...

I noticed the org.gwtproject.safehtml:safehtml still has a transitive dependency on gwt-user:

[INFO] |  \- org.gwtproject.safehtml:safehtml:jar:1.0-SNAPSHOT:compile
[INFO] |     \- com.google.gwt:gwt-user:jar:2.8.2:compile
[INFO] |        +- com.google.jsinterop:jsinterop-annotations:jar:sources:1.0.2:compile
[INFO] |        +- javax.validation:validation-api:jar:sources:1.0.0.GA:compile
[INFO] |        +- javax.servlet:javax.servlet-api:jar:3.1.0:compile
[INFO] |        \- org.w3c.css:sac:jar:1.3:compile

Wasn't the purpose of using this library to specifically avoid depending on gwt-user? or does it not matter because it is not actually being used?

Also, it would be helpful in the Getting Started section to mention that anyone declaring a dependency on elemento-core will also need to declare the Vertispan snapshot repository, otherwise it won't be able to resolve the 1.0.0-SNAPSHOT version of safehtml. It is easy to figure this out, but would save people a little bit of time.

J2CL / GWT3 compatibility

Make sure Elemento works with J2CL / GWT3 and GWT2. Most of this should already be fixed by #48.

  • Verify J2CL compatible dependencies

error while compiling when having log4j on the classpath

i'm getting an error while compiling when i have log4j on the classpath:

ERROR elemento.shaded.freemarker.log.LoggerFactory: Unexpected error when initializing logging for "Log4j". Exception: java.lang.RuntimeException: Unexpected error when creating logger factory for "Log4j". Caused by: java.lang.ClassNotFoundException: elemento.shaded.freemarker.log._Log4jLoggerFactory

sample: https://github.com/halkosajtarevic/elemento-log4j-issue

is there any way to workaround this? thanks in advance!

@DataElement type mismatch is not caught at compile time

If I put a @DataElement annotation on a field with a misspelled name that doesn't match the name in the template, I get a compile error, which is great. However, if instead the field name is spelled correctly, but the type is incorrect, e.g. HTMLButtonElement instead of HTMLAnchorElement, instead of a compile error, I get a hard to read exception at runtime. Can the data element type be verified at compile time the same way that the field name is verified? I spent a few minutes looking in the TemplatedProcessor.java code, but I'm having a difficult time understanding how it works.

Question: can I use widgets in combination with Elemento/templating ?

I want to migrate my code that is depending on UiBinder and some custom widgets to Elemento. I really like the design.

What is not clear to me if it is possible to still use some old widgets inside an Elemento template ? Or if there is a way to insert a widget as a child of an HTMLElement somehow ?

All I am missing is support for a binding framework (2-way) in combination with javax.validation support and I think I will have a nice replacement for the old GWT widgets and features.

InnerHtml GWT generator fails when the template contains `$`

if you have $ in your template like this example <paper-button class$='[[something]]>test</paper-button> the generator will produce a compile error
the use of $ is common in polymer and is being used to dynamically bind and inject css styles and image sources.

#34

Templates not updated in super dev mode

If I make a change to a template while running in super dev mode, I have to restart the super dev mode server to get the updated template to take effect. Is there any way to make the templates update automatically when I refresh the page using super dev mode, just like code changes update automatically without restarting the server?

Duplicate finder methods

Currently finder methods are provided as static methods in org.jboss.gwt.elemento.core.Elements. The element which is used for the underlying querySelector() method has to be provided as first parameter:

import static org.jboss.gwt.elemento.core.Elements.body;
import static org.jboss.gwt.elemento.core.Elements.find;

HTMLElement foo = find(body(), By.classname("foo")); 

The finder methods could also be provided for HTML builders. This would be the more object-oriented way and the first parameter would no longer be necessary:

import static org.jboss.gwt.elemento.core.Elements.body;

HTMLElement foo = body().find(By.classname("foo")); 

Normally I'm a friend of clear API design and like to avoid ambiguity. I'd like to get your feedback whether I should duplicate the finder methods for HTML builders (vote with ๐Ÿ‘) or leave it as it is and only provide static finder methods in org.jboss.gwt.elemento.core.Elements (vote with ๐Ÿ‘Ž)

Naming

  • Rename maven group ID from org.jboss.gwt.elemento to org.elemento.
  • Rename package org.jboss.gwt.elemento to org.elemento.

APT Error while build inside Eclipse: Unsupported location: CLASS_PATH

Command line generation is Ok, but in the Eclipse I see the error.

template class:

@Templated("Todo.html#todos")
abstract class ApplicationElement implements IsElement<HTMLElement> {

	static ApplicationElement create() {
		return new Templated_ApplicationElement();
	}
}

html template:

<section data-element="todos" class="todoapp">
   <h1>Hi</h1>
</section>

Stacktrace:

@Templated processor threw an exception: java.lang.IllegalArgumentException: Unsupported location: CLASS_PATH
	at org.eclipse.jdt.internal.apt.pluggable.core.filer.IdeFilerImpl.getFileFromOutputLocation(IdeFilerImpl.java:186)
	at org.eclipse.jdt.internal.apt.pluggable.core.filer.IdeFilerImpl.getResource(IdeFilerImpl.java:154)
	at org.jboss.gwt.elemento.processor.TemplatedProcessor.parseTemplate(TemplatedProcessor.java:366)
	at org.jboss.gwt.elemento.processor.TemplatedProcessor.processType(TemplatedProcessor.java:296)
	at org.jboss.gwt.elemento.processor.TemplatedProcessor.onProcess(TemplatedProcessor.java:245)
	at elemento.shaded.org.jboss.auto.AbstractProcessor.process(AbstractProcessor.java:115)
	at org.eclipse.jdt.internal.compiler.apt.dispatch.RoundDispatcher.handleProcessor(RoundDispatcher.java:139)
	at org.eclipse.jdt.internal.compiler.apt.dispatch.RoundDispatcher.round(RoundDispatcher.java:121)
	at org.eclipse.jdt.internal.compiler.apt.dispatch.BaseAnnotationProcessorManager.processAnnotations(BaseAnnotationProcessorManager.java:159)
	at org.eclipse.jdt.internal.apt.pluggable.core.dispatch.IdeAnnotationProcessorManager.processAnnotations(IdeAnnotationProcessorManager.java:135)
	at org.eclipse.jdt.internal.compiler.Compiler.processAnnotations(Compiler.java:933)
	at org.eclipse.jdt.internal.compiler.Compiler.compile(Compiler.java:443)
	at org.eclipse.jdt.internal.compiler.Compiler.compile(Compiler.java:419)
	at org.eclipse.jdt.internal.core.builder.AbstractImageBuilder.compile(AbstractImageBuilder.java:372)
	at org.eclipse.jdt.internal.core.builder.IncrementalImageBuilder.compile(IncrementalImageBuilder.java:331)
	at org.eclipse.jdt.internal.core.builder.AbstractImageBuilder.compile(AbstractImageBuilder.java:305)
	at org.eclipse.jdt.internal.core.builder.IncrementalImageBuilder.build(IncrementalImageBuilder.java:136)
	at org.eclipse.jdt.internal.core.builder.JavaBuilder.buildDeltas(JavaBuilder.java:267)
	at org.eclipse.jdt.internal.core.builder.JavaBuilder.build(JavaBuilder.java:195)
	at org.eclipse.core.internal.events.BuildManager$2.run(BuildManager.java:735)
	at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:42)
	at org.eclipse.core.internal.events.BuildManager.basicBuild(BuildManager.java:206)
	at org.eclipse.core.internal.events.BuildManager.basicBuild(BuildManager.java:246)
	at org.eclipse.core.internal.events.BuildManager$1.run(BuildManager.java:301)
	at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:42)
	at org.eclipse.core.internal.events.BuildManager.basicBuild(BuildManager.java:304)
	at org.eclipse.core.internal.events.BuildManager.basicBuildLoop(BuildManager.java:360)
	at org.eclipse.core.internal.events.BuildManager.build(BuildManager.java:383)
	at org.eclipse.core.internal.events.AutoBuildJob.doBuild(AutoBuildJob.java:142)
	at org.eclipse.core.internal.events.AutoBuildJob.run(AutoBuildJob.java:232)
	at org.eclipse.core.internal.jobs.Worker.run(Worker.java:56)

[Feature Request] Add "onAttach" helper method

Comming from gwt widgets something i hardly miss is the "onAttached/Detached" functionality gwt widgets provides to the developer: You can override to get notified when the widget is added/removed to the dom.

We need this to, e.g. focus and select input when it's attached, initialize Split.js, ...

This i something that would fit perfect into the org.jboss.gwt.elemento.core.Elements class.
Here's the code i've wrote for onAttach:

private static String UID_KEY = "onattach-uid"; //$NON-NLS-1$

/**
 * Utility method to listen when a element is attached to the dom
 * 
 * @param element
 *            the element to listen for
 * @param callback
 *            will be called when the element has been attached to the dom
 */
public static void onAttach(HTMLElement element, Consumer<HTMLElement> callback) {
	String uid = Elements.createDocumentUniqueId();
	element.setAttribute(UID_KEY, uid);
	MutationObserver observer = new MutationObserver((records, o) -> {
		for (MutationRecord record : records) {
			if (record.addedNodes != null && record.addedNodes.length > 0) {
				if (DomGlobal.document.body.querySelector("[" + UID_KEY + "='" + uid + "']") != null) { //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
					element.removeAttribute(UID_KEY);
					o.disconnect();
					callback.accept(element);
				}
			}
		}
		return null;
	});
	MutationObserverInit ops = MutationObserverInit.create();
	ops.setChildList(true);
	ops.setSubtree(true);
	observer.observe(DomGlobal.document.body, ops);
}

elemento-core 1.0.1 has a dependency to gwt-safehtml with SNAPSHOT version

Hi All,

elemento-core 1.0.1 has a dependency to gwt-safehtml with SNAPSHOT version. This should not happen, I also don't know why Maven Central allows a RELEASE artifact to be dependent on SNAPSHOT artifact.

This is not good for all the developers who are in the enterprise environment and can only access Maven through Nexus with only RELEASES artifacts.

Expressions in root element wont be processed

Assume we have the following template

<div id="${item().title()}">
    ${item().title()}
</div>

and the following template class

@Templated
public abstract class Foo implements IsElement<HTMLDivElement>{

    interface Item{
        String icon();
        String title();
    }

    abstract Item item();

    public static Foo create(Item item){
        return new Templated_Foo(item);
    }
}

the generated templated class wont have the code to replace the expressions of the root element

@Generated("org.jboss.gwt.elemento.processor.TemplatedProcessor")
public final class Templated_Foo extends Foo {

    private final somepackage.Item item;
    private final elemental2.dom.HTMLDivElement templated_foo_root_element;

 public Templated_Foo(somepackage.Item item) {
        this.item = item;

        this.templated_foo_root_element = (elemental2.dom.HTMLDivElement)DomGlobal.document.createElement("div");
        this.templated_foo_root_element.setAttribute("id", "${item().title()}");

    }

    @Override
    public elemental2.dom.HTMLDivElement asElement() {
        return templated_foo_root_element;
    }

    @Override
    somepackage.Item item() {
        return item;
    }
}

Cannot find template

I have given Elemento a try in myproject. I have tried to use HTML templates, but when I compile, the following error is thrown:

Cannot find template "path/to/template". Please make sure the template exists and resides in the source path.

The resource does exist in the path specified.

Does this sound familiar ? anybody have an idea ?

I am facing a bug in Elemento wp Plugin

After updating my Elemento Plugin, I can no longer edit my pages.

I saw a message like "Database update process is running in the background.", I don't know what it means.

pls help

Move templates to crysknife

I plan to move the templating part of Elemento to Crysknife. Crysknife already contains most of the templating code of Elemento, integrates nicely with CDI and offers some extra features like GSS support on top of that.

The motivation behind this is that we don't want to have two very similar and competing template solutions. Please feel free to comment on this issue if you have a different opinion.

See also https://github.com/treblereel/crysknife/issues/27.

ElementBuilder.css(String... classes) does not work for multiple classes in IE11

Acording to https://developer.mozilla.org/en-US/docs/Web/API/Element/classList IE11 does not support "Multiple arguments for add() & remove()".
Therefor get().classList.add(failSafeClasses.toArray(new String[]{})); should be re-written to add classes via foreach to get it work.

Changing from

    /** Adds the specified CSS classes to the class list of the element. */
    public B css(String... classes) {
        if (classes != null) {
            List<String> failSafeClasses = new ArrayList<>();
            for (String c : classes) {
                if (c != null) {
                    if (c.contains(" ")) {
                        failSafeClasses.addAll(asList(c.split(" ")));
                    } else {
                        failSafeClasses.add(c);
                    }
                }
            }
            if (!failSafeClasses.isEmpty()) {
                get().classList.add(failSafeClasses.toArray(new String[]{}));
            }
        }
        return that();
    }

to

    /** Adds the specified CSS classes to the class list of the element. */
    public B css(String... classes) {
        if (classes != null) {
            List<String> failSafeClasses = new ArrayList<>();
            for (String c : classes) {
                if (c != null) {
                    if (c.contains(" ")) {
                        failSafeClasses.addAll(asList(c.split(" ")));
                    } else {
                        failSafeClasses.add(c);
                    }
                }
            }
            for (String failSafeClass : failSafeClasses) {
                get().classList.add(failSafeClass);
            }
        }
        return that();
    }

will fix the issue under IE11.

Multiple Classes

One method that I'm adding to all my builders is a css( String... classes) method. I'm just joining the class names using Guava at the moment, but I think this is probably something we should handle in the Builder. PR?

APT Processors (for templates) don't work well in Eclipse

Hi!

I'm just getting started w/ this awesome project. Although I don't plan to use primarily the templates feature, some colleagues of mine might use it, as they prefer the readability of a HTML vs DSL.

When importing a project (e.g. sample/gin) in Eclipse, it won't work out of the box. After a clean + build, there are compile errors because of the processor. E.g. for ApplicationElement.java = Unable to read template "org/jboss/gwt/elemento/sample/gin/client/Todo.html": Java Model Exception: Core Exception [code 368] Resource '/gin/target/classes/org/jboss/gwt/elemento/sample/gin/client/Todo.html' does not exist..

When I look there, Todo.html does exist. But it was probably copied during the compile phase, and probably ApplicationElement.java was compiled (thus processor invoked) before. So maybe at that time the file didn't exist.

The work around: go to ApplicationElement.java, modify something meaningless => incremental build only on this file => error gone. However, a full clean + build will lead to the initial situation.

My question: are there users that successfully use the template processors in Eclipse? If yes, then somehow there is something wrong w/ my setup. If no => the processor may need to be adapted for use in Eclipse. I assume that it works correctly during a maven build.

I have experience w/ processors and APT. And there are many compatibility issues between execution within maven and within Eclipse. Some of them due to the incremental approach of Eclipse, but the majority due to the fact that "illegal" operations are done from within processors. Normally, a processor should only output content based on the content of the annotated file. In this case, the content is based on the *.html file, which is something that's not officially supported by the APT API.

Cheers!
Cristian

Update samples

Remove deprecated samples and add new samples for J2CL and Nalu.

Debugging Clues

Hey Harald,

So I've got another enhancement idea. If I've got a bunch of Builders being thrown around, I tend to forget to close things (enough .end()). While this is fairly simple to debug, the messaging doesn't give me any indication as to WHICH builder is still open.

In my branch, I've added a String to the default constructor. In the case of an exception getting thrown, it simply prepends this string if it's not null. This way, I can tell where the issue is coming from.

I've been trying to figure out a way to add this automatically, but without any reflection cases it makes it quite difficult. What do you think?

Widgets.asElement does not wire up events

This is probably going to be tricky to get right, so it might be worth making this into a documentation bug, rather than a fault in the library.

A GWT Widget does not attach its event listeners to the dom until the widget it attached. Being attached means that its root node has a parent node, and so on until a RootPanel instance - so the root element of the widget is actually attached to the page's body.

This solves a memory leak that old browsers had - ancient versions of firefox had this issue, as did most every version of IE until Edge came around (I am certain that IE9 has the bug, IE10 and 11 haven't been tested by me).

This also provides a set of lifecycle methods to Widget which normal Elements do not have (though WebComponents do, in the form of the custom element's connected/disconnected callbacks - this could be one way to implement this in general).

However, when Widgets.asElement is called on a widget, it returns the root element of that widget, and the widget will never be marked as attached, so none of its event listeners will ever be attached to the DOM. If Widgets.asElement were to trigger the attach lifecycle when called, this could break the widget, since its own handlers would not be able to find a parent element, and would not be able to check the element's sizes, etc. That said, this is what gwtquery does in cases like this, where there is no higher widget in the page's structure, or the element this is being attached to is not yet itself connected to the document: https://github.com/gwtquery/gwtquery/blob/master/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/widgets/WidgetsUtils.java#L176-L217

--

Other cases to consider:

  • Elements (1)
    • Widget (2)
      • Elements (3)
        • Widget (4)

In this case, the widget isn't directly attached to another widget, and if the elements at (3) were not connected to the widget at (2) when (4) is added to them, you'll get different behavior than if they were. Likewise, removing (2) from the dom should cause (4) to be told it has detached.

--

Not all widgets are going to care if you get this exactly right, so I think this library needs to describe what level of correctness is offered, and possibly offer some utility methods to enable projects to attain their preferred level of correctness from there.

Compile on windows10

I was looking for a GWT sample and found this source.

I am very grateful to you for teaching me the latest coding.

I downloaded this and mavened but got a little error.

I modified pom.xml for gwt28.

    <elemental2.version>1.0.0</elemental2.version>
    <elemento.version>1.0.3</elemento.version>

Then I did "mvn gwt: devmode" at gwt28.

I got the following error. (Translating Japanese to English)

Main.java:[33,70] Can't find symbol. method getHash()
Location: Variable location of type elementary2.dom.Location
Main.java:[34,36] Can't find symbol. method getHash()
Location: Variable location of type elementary2.dom.Location

I'm using adopt open jdk8.
Can this source be compiled on Windows 10 ?

If I can compile on Linux, which distribution should I use?

GWT entry wrap not used in listeners

There is a problem with JsInterop that it facilitates and do not propose a solution about the gwt $entry function wrapping. This will make the standard scheduler, error handling and maybe something else to produce unexpected behavior.

I have created this issue just to remember and apply the GWT solution when it gets chosen. There are various pull requests to fix the same problem in the GWT SDK itself (https://gwt-review.googlesource.com/#/q/user/src/com/google/gwt/core/client/internal/Entry.java).

Internet Explorer JavaScriptException due to createTreeWalker API difference

Background

The Document.createTreeWalker()
method creates a TreeWalker object. TemplateUtil uses this to walk
nodes to replace expressions.

The createTreeWalker specification documents an optional third argument,
filter, which is described as a NodeFilter object containing an
acceptNode method. The Elemental2 implementation of createTreeWalker follows
this specification.

Problem

However, Internet Explorer expects the filter argument to be a function,
not an object with an acceptNode method. When an object is passed in instead,
Internet Explorer throws a JavaScriptException on the first call to the
nextNode() method of the tree walker object.

See the answer to:
https://stackoverflow.com/questions/32163076/createtreewalker-in-ie-is-there-a-limit

Scope

This issue affects applications using HTML templates with expressions
in Internet Explorer. I've tested IE11 but believe older versions are
similarly affected.

The issue exists in the template-based samples, such as dagger, and
templated. These samples fail to load in Internet Explorer.

Proposed Solution

My proposed solution is to pass in null as the filter argument when calling
createTreeWalker and handle the filtering within the while loop
after each call to nextNode().

I will submit a pull request with the proposed solution.

Elements.Builder Inheritence?

Hello! So I've finally resolved all my 2.8 funny business and have begun using Elemento in my application. I really like the API; however, I was wondering why Elements.Builder is final?

I would like to extend Builder to have some more application specific helpers. In a bunch of places, I create a lot of nav elements and then there's the case of a list of links, which could nicely be wrapped, helping reduce the boiler plate even further.

I've seen people use recurring generics to have inheritable builders. Would this be something that Elemento could handle?

Thanks for such a helpful library!

Maven Dependency Conflict; MoreTypes.asTypeElement() method signature changed

I am experiencing a Maven dependency conflict between hal/elemento and intendia-oss/autorest.

The hal/elemento template processor relies on auto-common 0.3, while intendia-oss/autorest relies on auto-common 0.4. In my project, Maven ends up using the 0.4 version of auto-common, but because of a method signature change, the hal/elemento TemplatedProcessor crashes with java.lang.NoSuchMethodError. The method signature of MoreTypes.asTypeElemen() changed between auto-common 0.3 and 0.4.

Relevant intendia-oss/autorest dependency tree:

com.intendia.gwt.autorest:autorest-processor:jar:0.6:provided
+- com.google.auto:auto-common:jar:0.4:provided

Relevant hal/elemento dependency tree:

org.jboss.gwt.elemento:elemento-template:gwt-lib:HEAD-SNAPSHOT
+- com.google.auto.service:auto-service:jar:1.0-rc2:compile
   \- com.google.auto:auto-common:jar:0.3:compile

Method signature in auto-common 0.3:
public static TypeElement asTypeElement(Types types, TypeMirror mirror)

Method signature in auto-common 0.4:
public static TypeElement asTypeElement(TypeMirror mirror)

(Here is the commit that implemented the change: google/auto@a428e7b#diff-117761445d686cc88f0b75d965af5a1a)

In my project, I can explicitly set the auto-common dependency to either 0.3 or 0.4. However, when I set it to 0.3, the intendia-oss/autorest processor similarly breaks with java.lang.NoSuchMethodError since it is using the newer method signature for MoreTypes.asTypeElement().

There are several lines in TemplatedProcessor.java that call MoreTypes.asTypeElement(). It appears that deleting the first parameter from these calls fixes the problem when used with auto-common 0.4.

What is the best practice for dealing with this type of conflict? Would it be reasonable for hal/elemento to explicitly set its auto-common dependency to 0.4 and update the MoreTypes.asTypeElement() calls to match? If so, I can submit a pull request.

One alternative is suggesting that intendia-oss/autorest downgrade its auto-common dependency to 0.3 instead of 0.4, but I feel better pushing a project like hal/elemento forward rather than intendia-oss/autorest backwards.

Are there any other solutions I'm missing that I could implement in any of these projects (or my own)?

Java 8 compatibility?

Is there a reason why published jars are compiled to target Java 11? From what I can see, elemento can be compiled using Java 8 as well.

I hope I'm not the only one still on Java 8 with need to use elemento :)

CSS glitch in samples (missing checkbox)

The samples are missing the (visual) checkbox of Todo entries. The element does exist, because clicking the empty space, toggles the element. So it seems to be only a visual issue.

image

I think it should look like this:

image

Prepare Elemento for J2CL / GWT3

  • Remove or move the helper methods to convert Widget and IsWidget
  • Replace SafeHtml with https://github.com/Vertispan/gwt-safehtml
  • Check that there's no usage of JSNI
  • Check dependencies: Elemento should no longer depend on com.google.gwt:gwt-*, but only on com.google.elemental2:elemental2-*

After going thru the sources, these are the classes we use from gwt-user:

import com.google.gwt.safehtml.shared.SafeHtml;
import com.google.gwt.safehtml.shared.SafeHtmlUtils;
import com.google.gwt.user.client.ui.IsWidget;
import com.google.gwt.user.client.ui.Widget;
import com.google.web.bindery.event.shared.HandlerRegistration;

Additional Resources:

Support for Dagger (or any other type of) injection

The TemplateProcessor currently adds injection annotations only if GIN is in the classpath. However, GIN is no longer maintained and the movement appears to be towards Dagger 2 as an annotation processor-based replacement.

However, when I switch to Dagger and remove GIN as a dependency, Elemento's TemplatedProcessor no longer generates Templated_* classes with the injection annotations.

Workaround

I can keep GIN as a dependency in my project in the meantime, even though it is only being used to indicate to Elemento's TemplatedProcessor that the inject annotation should be applied to generated template classes.

Proposed Change

I'd like to propose the following change in Elemento's Templated annotation and the TemplatedProcessor.

Add an injectiable attribute on the Templated annotation:

public @interface Templated {
    
    enum Injectable { TRUE, FALSE, IF_GIN_PRESENT };
    
    String value() default "";
    Injectable injectable() default Injectable.IF_GIN_PRESENT;
}

And then in TemplatedProcessor,

String inject = ginInClasspath() ? "@javax.inject.Inject" : "";

becomes something determined for each type

boolean isInjectable = templated.injectable() == Injectable.TRUE
        || (templated.injectable() == Injectable.IF_GIN_PRESENT && ginInClasspath());
String inject = isInjectable ? "@javax.inject.Inject" : "";

Notes

This would maintain backwards compatibility for existing Templated classes that rely on the IF_GIN_PRESENT-type functionality, but would also add the ability to explicitly declare whether (or not) to include the inject annotation.

An alternative would be to make the injectable attribute a simple boolean defaulting to false where true means to include the Inject annotation and false means to exclude it. This would be a breaking change that no longer checks for GIN in the classpath. Any classes relying on GIN would then need to explicitly declare injectable=true.

If one of these approaches seems reasonable to you, I would be happy to put together a pull request.

Processor fails to locate the template html file when placed next to the template class

if the template file is moved from the resources folder and placed next to the template class the processor will fail to locate the template file and application wont compile.

intellij ide will not copy the resource until a manual rebuild is executed while the application is running
having the template in the resources folder, this will produce a stale copy of the template file in the target folder.

https://intellij-support.jetbrains.com/hc/en-us/community/posts/115000539104-IntelliJ-stopped-copying-resources-into-target-folder-when-running-JUnit-tests-

meanwhile the html template is meant only for gwt compilation, tbroyer plugin does not copy these resources from the sources folder, which prevent the creation of a stale copy anyway, and to be aligned with tbroyer setup we need the templates to be in the sources folder not the resources folder.
Thanks

gwt-user.jar shouldn't be included in war

My understanding is that gwt-user.jar doesn't need to be included in the war file, but it is getting included in my project's war. I believe this is because elemento lists gwt-user.jar as a compile scope dependency rather than a provided scope dependency, but I'm not confident that changing the scope to provided is the correct solution. Would making this change cause other problems?

Documentation

  • Review README.md
  • Make sure all important public elements have at least basic documentation.

NullPointerException thrown in TemplatedProcessor

Occasionally I get the following exception in the Eclipse IDE. I am using elemento 0.8.1 .

@Templated processor threw an exception: java.lang.NullPointerException at org.jboss.gwt.elemento.processor.TemplatedProcessor.ancestorIsTemplated(TemplatedProcessor.java:669) at org.jboss.gwt.elemento.processor.TemplatedProcessor.validateType(TemplatedProcessor.java:278) at org.jboss.gwt.elemento.processor.TemplatedProcessor.onProcess(TemplatedProcessor.java:243) at elemento.shaded.org.jboss.auto.AbstractProcessor.process(AbstractProcessor.java:115) at org.eclipse.jdt.internal.compiler.apt.dispatch.RoundDispatcher.handleProcessor(RoundDispatcher.java:139) at org.eclipse.jdt.internal.compiler.apt.dispatch.RoundDispatcher.round(RoundDispatcher.java:110) at org.eclipse.jdt.internal.compiler.apt.dispatch.BaseAnnotationProcessorManager.processAnnotations(BaseAnnotationProcessorManager.java:159) at org.eclipse.jdt.internal.apt.pluggable.core.dispatch.IdeAnnotationProcessorManager.processAnnotations(IdeAnnotationProcessorManager.java:135) at org.eclipse.jdt.internal.compiler.Compiler.processAnnotations(Compiler.java:937) at org.eclipse.jdt.internal.compiler.Compiler.compile(Compiler.java:447) at org.eclipse.jdt.internal.compiler.Compiler.compile(Compiler.java:423) at org.eclipse.jdt.internal.core.builder.AbstractImageBuilder.compile(AbstractImageBuilder.java:383) at org.eclipse.jdt.internal.core.builder.IncrementalImageBuilder.compile(IncrementalImageBuilder.java:368) at org.eclipse.jdt.internal.core.builder.AbstractImageBuilder.compile(AbstractImageBuilder.java:315) at org.eclipse.jdt.internal.core.builder.IncrementalImageBuilder.incrementalBuildLoop(IncrementalImageBuilder.java:183) at org.eclipse.jdt.internal.core.builder.IncrementalImageBuilder.build(IncrementalImageBuilder.java:140) at org.eclipse.jdt.internal.core.builder.JavaBuilder.buildDeltas(JavaBuilder.java:276) at org.eclipse.jdt.internal.core.builder.JavaBuilder.build(JavaBuilder.java:197) at org.eclipse.core.internal.events.BuildManager$2.run(BuildManager.java:795) at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:42) at org.eclipse.core.internal.events.BuildManager.basicBuild(BuildManager.java:216) at org.eclipse.core.internal.events.BuildManager.basicBuild(BuildManager.java:259) at org.eclipse.core.internal.events.BuildManager$1.run(BuildManager.java:312) at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:42) at org.eclipse.core.internal.events.BuildManager.basicBuild(BuildManager.java:315) at org.eclipse.core.internal.events.BuildManager.basicBuildLoop(BuildManager.java:367) at org.eclipse.core.internal.events.BuildManager.build(BuildManager.java:388) at org.eclipse.core.internal.events.AutoBuildJob.doBuild(AutoBuildJob.java:142) at org.eclipse.core.internal.events.AutoBuildJob.run(AutoBuildJob.java:232) at org.eclipse.core.internal.jobs.Worker.run(Worker.java:60)

Chrome 69 breaks org.jboss.gwt.elemento.core.BodyObserver

Since Chrome 69 we got the following ClassCastExceptions when we use

org.jboss.gwt.elemento.core.Elements.onAttach(HTMLElement, ObserverCallback)

Uncaught Error: java.lang.ClassCastException
    at qGc_g$.ah_g$ [as createError_0_g$] (Throwable.java:120)
    at qGc_g$.kh_g$ [as initializeBackingError_0_g$] (Throwable.java:112)
    at qGc_g$.Vg_g$ (Throwable.java:66)
    at qGc_g$.zh_g$ (Exception.java:29)
    at qGc_g$.Hh_g$ (RuntimeException.java:29)
    at new qGc_g$ (ClassCastException.java:27)
    at r1d_g$ (InternalPreconditions.java:154)
    at D1d_g$ (InternalPreconditions.java:138)
    at C1d_g$ (InternalPreconditions.java:133)
    at lvb_g$ (Cast.java:155)
    at C7d_g$.H7d_g$ [as test_1_g$] (Elements.java:818)
    at JYd_g$.LYd_g$ [as lambda$0_50_g$] (StreamImpl.java:425)
    at PYd_g$.QYd_g$ [as accept_1_g$] (StreamImpl.java:424)
    at vhd_g$.Ehd_g$ [as tryAdvance_0_g$] (Spliterators.java:463)
    at JYd_g$.MYd_g$ [as tryAdvance_0_g$] (StreamImpl.java:422)
    at EZd_g$.GZd_g$ [as tryAdvance_0_g$] (StreamImpl.java:317)
    at Lhd_g$ (Spliterator.java:52)
    at EZd_g$.zjd_g$ [as forEachRemaining_1_g$] (Spliterator.java:51)
    at vVd_g$.eWd_g$ [as reduce_6_g$] (StreamImpl.java:663)
    at vVd_g$.AVd_g$ [as collect_5_g$] (StreamImpl.java:587)
    at A4d_g$ (BodyObserver.java:67)
    at y4d_g$ (BodyObserver.java:30)
    at Function.O4d_g$ (BodyObserver.java:28)
    at MutationObserver.lambda_0_g$ (Runtime.java:166)

The bug is in class org.jboss.gwt.elemento.core.Elements.FilterHTMLElements<T>:

FilterHTMLElements<T extends Node> should be replaced with FilterHTMLElements<T>

I don't know what they changed in chrome 69 but if there is a or something, it will fail with the above ClassCastException.

The generic type used in IsElement interface is not reflected to the generated template

Assume that we have a classes annotaed as templated like below

@Templated("beneficiaries-list.html")
abstract class Foo implements IsElement<VaadinGridElement>

in the generated template the the generic type will not be used and HTMLElement will be used instead, and will cause a compilation error.

in the generated file we will see this code

private final HTMLElement templated_foo_root_element;

@Override
 public HTMLElement asElement() {
        return templated_foo_root_element;
 }

while it should be

private final VaadinGridElement templated_foo_root_element;

@Override
 public VaadinGridElement asElement() {
        return templated_foo_root_element;
 }

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.