google / elemental2

Type checked access to browser APIs for Java code.
Apache License 2.0
147 stars 35 forks source link

Is there a good way to extend dom elements? #162

Open raindroplvy opened 2 weeks ago

raindroplvy commented 2 weeks ago

I want to add some new UI components by extends dom elements, so as to preserve the basic operation of dom elements, if wrap the dom elements to implement it, I need add some bridging methods, which are not as natural to use as dom elements.

If I extends like this, how would the Composite object be created? class Composite extends HTMLDivElement { ... }

If I extends like this, will some extended methods not be able to be overridden by subclasses? `@JsType(isNative = true, name = "HTMLDivElement", namespace = JsPackage.GLOBAL) class Composite extends HTMLDivElement { @JsOverlay public Composite create() { return Js.cast(DomGlobal.document.createElement("div")); }

@JsOverlay
protected void createContent()
{
    // override by sub class
}

}`

niloc132 commented 2 weeks ago

(This might be better submitted as a discussion, either here, the jsinterop-annotations repo, or GWT/j2cl depending on what you are targeting. Also consider the matrix/gitter chat room for GWT, at https://matrix.to/#/#gwtproject_gwt:gitter.im.)

Can you describe how you would achieve what you're aiming for in plain JS? That should help make it clearer how you would do it with jsinterop/elemental2. For example, if you're trying to make custom elements, you will use document.createElement("my-element-name") to create your Composite instances, after registering them. Note though that if you are not compiling to ES6 classes (either because you are using GWT, or because you are using j2cl with closure compiling to a lower JS source level), you will need to take some extra steps before you can pass the class to register().

Methods annotated with @JsOverlay can never be overridden by subclasses, so this isn't going to do what you want at all. With that said, your Java Composite type probably shouldn't be isNative=true at all, since you are going to define your own logic in Java (and may want to override custom element callback methods from JS, or have java-only methods that can be used and need not follow all JS rules, so can be annotated with @JsIgnore).

raindroplvy commented 2 weeks ago

For example, the domino-ui Badge component is implemented via wrapper SpanElement, like this: public class Badge { private SpanElement element;

public Badge() { element = span().addCss(dui_badge); ... } }

I want to check if the implementation can be implemented by inheriting SpanElement from the Badge, like this: public class Badge extends SpanElement { public Badge() { ... } protected void createContent() { // override by sub class } }

This way the Badge comes with some of the properties and methods of the span element, can be used directly, but the two possible issues are how the Badge object create, and how some Badge new methods be overwritten by subclasses.

zbynek commented 1 week ago

If you do this, i.e. Badge is just a span with some convenience methods defined as @JsOverlay, you can instantiate it like this: Badge myBadge = Js.uncheckedCast(DomGlobal.document.createElement("span")).

If you want to take advantage of writing the code in Java (e.g. overriding methods as mentioned above), you're better off using wrappers like the Domino UI example you shared or the current GWT Widget class.

raindroplvy commented 1 week ago

@zbynek Thanks for your reply, I tried your suggestion, Badge object can be successfully created, but the extend methods of Badge will not be called successfully, the extend methods subclass rewriting will also be a problem, maybe wrap way is more extensible, thanks again.