It is possible to create web components with "fake" ES2015 classes built 
out of raw javascript.

https://github.com/WeTheInternet/xapi/blob/master/gwt/components/src/main/java/xapi/components/impl/WebComponentBuilder.java#L108

Note that the library above depends on a custom fork of Gwt that is not 
being released until after 2.8.2 goes out, however, the code for assembling 
custom web components does not actually depend on any of the magic I've 
added to the Gwt compiler (official release will not be dependent on my 
fork; I hope to deprecate / upstream everything I've had to do to it over 
the years). 

I also intend to remove all the ugly jsni to make it compatible with j2cl / 
gwt3... But, that bit I've linked to is the secret sauce for assembling a 
correct "extension" of HTMLElement.  In theory, you can define your custom 
element using a builder that attaches your lifecycle callbacks (created / 
attached / detached / attributeChanged), plus any extra methods / fields 
you want, and then the rest of your code can use a @JsType(isNative=true, 
name="MyCustomElement", namespace = JsPackage.GLOBAL) interface that 
defines how you want to access the custom element and/or cast directly to 
an Element.  This work is very imperative and copy-pasta, so I've also 
created a nice DSL for defining custom elements using... an xml-like, 
json-like, css-like extension of the java language (totally optional 
though; you can still use the builder directly).

The end goal (very near to completion) is that you can define your custom 
component with a bit of xml-like syntax, plugging in java methods wherever 
you please, and it will generate all the builder-y boilerplate and Element 
interface for you.  It is likely that I can actually make it extend 
HTMLElement directly as a class, and just define trampoline methods in the 
builder to call into the java code, but I have not had time to explore this 
option yet.

I have not "officially" released this library, but it will be making an 
official debut soon.  You should be able to use it earlier, if you are 
interested in some beta testing :-) (message me @ [email protected] so I 
can add you to my beta testers label).

The result is a custom element that has widget-like lifecycle callbacks (we 
are toying with the idea of actually making widget use something like this 
under the hood to survive in Gwt 3).  The one *big* gotcha is how the 
createdCallback works.  Per the web component spec, you may *not* write or 
*read* any elements attributes or children to a custom element in its 
constructor.  I have worked up a...  slightly scary "RunSoon" 
implementation which will ensure that the callback is fired as soon as 
possible after construction (but this can be hard, since setting innerHTML 
from plain javascript is an important part of interopability with JS/HTML). 
 I won't go into many details here, but, in practice, this ugliness can be 
hidden behind some cleverly generated code (which will lazy-init either at 
your command, whenever attached, or at the end of the current javascript 
event loop).

The very first iteration of these custom components actually took a js type 
interface, directly bound all default methods to the custom element 
definition (via code generator), and allowed you to use that interface in 
both java and javascript.  It actually worked quite well, but, 
unfortunately, that was for V0 of web component spec, and the ES2015 class 
syntax requirement (and other, imho, design mistakes) made it untenable for 
V1 (current version of web components).



To use web components with GWT, you do have to install a polyfill 
(webcomponentjs, with only a couple slight mods I had to make) for older 
browsers / browsers that do not have web components enabled by default. 
 The fact GWT runs in an iframe makes instanceof fail spectacularly, so I 
had to change usage of it to typeofs.


Shameless plug: Myself, Colin Alworth and Justin Hickman have started a 
company based on selling GWT support contracts called Vertispan.  While I 
am happy to share open source code and some pointers with you for free at 
any time, if you are interested in hiring any expertise to help you 
directly, you should email my aforementioned work account. :-)


Final note: Shadow DOM is completely optional, and you should likely avoid 
it unless you really need it (for encapsulation and css barriers mostly). 
 It... gets a bit hinky especially with polyfills and sane event bubbling, 
so if you are new to web components, only move on to shadow DOM if you've 
tried something without it, and actually need it (for example, to isolate 
component internals, or to avoid re-rendering piles of layout logic when 
all you want is your server to send elements with semantic significance).  


On Friday, October 13, 2017 at 6:25:00 AM UTC-7, Thomas Broyer wrote:
>
> Web Components require using ES2015 class syntax, so you would need some 
> trickery make them work from GWT (see 
> https://github.com/webcomponents/custom-elements#es5-vs-es2015 or 
> https://github.com/webcomponents/webcomponentsjs#custom-elements-es5-adapterjs
> )
> At least this is the theory…
>
> On Friday, October 13, 2017 at 11:58:14 AM UTC+2, nikola wrote:
>>
>> Thanks for the link.. But I can't see what I was looking for.. 
>>
>>  Can someone please create and register custom web component using only 
>> elemental 2. e.g  that says "hello from shadow DOM!".
>> Cause I'm not able to do it or find working example .. at least without 
>> losing whole week on it...
>> Thanks in advance
>>
>> On Thursday, October 12, 2017 at 4:04:16 PM UTC+2, harshyadav wrote:
>>>
>>> You can try the GWT polymer (web components) wrapper:
>>> https://github.com/manolo/gwt-polymer-elements
>>>
>>> Wither you can use built-in polymer components; or create your own (just 
>>> look at the source code)
>>>
>>> Also take a look at:
>>> https://github.com/manolo/gwt-api-generator
>>>
>>> which auto generates GWT api for polymer elements, so no need to be out 
>>> of Java world for most cases.
>>>
>>>
>>> On Thursday, October 12, 2017 at 7:08:05 AM UTC-4, nikola wrote:
>>>>
>>>> Ok, Thanks! I'll try with web components. As a java programer I'v been 
>>>> trying to avoid digging too much in javascript but it's inevitable it 
>>>> seems 
>>>> :)
>>>>
>>>> On Thursday, October 12, 2017 at 12:43:56 PM UTC+2, Thomas Broyer wrote:
>>>>>
>>>>> This is not how the DOM works I'm afraid. How would your proposed code 
>>>>> would translate to JS? (feel free to use ES2015 classes for clarity)
>>>>> (btw, I really do think Web Components would solve your issues, as I 
>>>>> see them)
>>>>>
>>>>> On Thursday, October 12, 2017 at 12:21:11 PM UTC+2, nikola wrote:
>>>>>>
>>>>>>
>>>>>> When I say "custom element" I mean:
>>>>>>
>>>>>>
>>>>>> *public class *CustomElement *implements *IsElement {
>>>>>>
>>>>>>
>>>>>>
>>>>>> *//    private HandlerManager handlerManager; ?     *List<String> 
>>>>>> *someUserObject*; 
>>>>>>
>>>>>> *//state object of CustomElement     *HTMLElement *root *= Js.*cast*
>>>>>> (DomGlobal.*document*.createElement(*"div"*));
>>>>>>
>>>>>>     @Override
>>>>>>     *public *HTMLElement asElement() {
>>>>>>         *return **root*;
>>>>>>     }
>>>>>>
>>>>>>     *public static void *test() {
>>>>>>         CustomElement customElement = *new *CustomElement();
>>>>>>         customElement.asElement().addEventListener(*"click"*, evt -> 
>>>>>> {
>>>>>>
>>>>>>              //evt.target is not CustomElement so we can't access 
>>>>>> e.g *someUserObject *
>>>>>>
>>>>>>
>>>>>> *           //We can map DOM events to custom events fired through 
>>>>>> HandlerManager with source field set to CustomElement (double work.. )   
>>>>>>   
>>>>>>     *});
>>>>>>     }
>>>>>>     
>>>>>> *// *}
>>>>>>
>>>>>>
>>>>>> Also when working with custom elements constructed as above *we need 
>>>>>> some discipline to remove objects both logically and from DOM (as you 
>>>>>> said 
>>>>>> we need to keep them in sync).. *
>>>>>>
>>>>>> *We are coming to something that looks like a Panel*
>>>>>>
>>>>>>
>>>>>> *class *Panel *implements *IsElement {
>>>>>>
>>>>>>     List<IsElement> *componentList*;
>>>>>>
>>>>>>     HTMLElement *root*;
>>>>>>
>>>>>>     @Override
>>>>>>     *public *HTMLElement asElement() {
>>>>>>         *return **root*;
>>>>>>     }
>>>>>>
>>>>>>     *public void *add(IsElement component) {
>>>>>>         
>>>>>>
>>>>>> *// add to componentList         // add to DOM     *}
>>>>>>
>>>>>>     *public void *remove(IsElement component) {
>>>>>>         
>>>>>>
>>>>>> *//remove from componentList         //remove from DOM     *}
>>>>>> }
>>>>>>
>>>>>>
>>>>>> So it would be good to have something like this :
>>>>>>
>>>>>>
>>>>>> *public abstract class *CustomElementComposite *extends *HTMLElement 
>>>>>> *implements 
>>>>>> *IsElement {
>>>>>>
>>>>>>     List<String> *someUserObject*;
>>>>>>
>>>>>>     *protected void *initComposite(HTMLElement element) {
>>>>>>         
>>>>>> *//If we could encapsulate element to become actually 
>>>>>> CustomElementComposite like Widget Composite     *}
>>>>>>
>>>>>>     @Override
>>>>>>     *public *HTMLElement asElement() {
>>>>>>         *return this*;
>>>>>>     }
>>>>>>
>>>>>>     *public static void *test() {
>>>>>>         CustomElementComposite element = *new *CustomElementComposite() 
>>>>>> {};
>>>>>>
>>>>>>         element.addEventListener(*"click"*, evt -> {
>>>>>>             
>>>>>> *// evt.target  is CustomElementComposite         *});
>>>>>>
>>>>>>         
>>>>>> *// we don't need any additional mapping for adding and removing     
>>>>>>     *HTMLElement parent = Js.*cast*(DomGlobal.*document*
>>>>>> .createElement(*"div"*));
>>>>>>         parent.appendChild(element);
>>>>>>         parent.removeChild(element);
>>>>>>     }
>>>>>> }
>>>>>>
>>>>>> This way we are adding events directly and there is no additional 
>>>>>> synchronization with DOM when adding and removing components.
>>>>>>
>>>>>> I must inspect but I'm not sure if Web Component can solve this (in 
>>>>>> the way widget's composite did).. I'd rather have web component as a 
>>>>>> option.
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>> On Thursday, October 12, 2017 at 10:48:05 AM UTC+2, Thomas Broyer 
>>>>>> wrote:
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> On Wednesday, October 11, 2017 at 4:12:14 PM UTC+2, nikola wrote:
>>>>>>>>
>>>>>>>>
>>>>>>>>   Users would expect to have events with source from where event 
>>>>>>>> was fired. That was source field in GWT events. In your implementation 
>>>>>>>> we 
>>>>>>>> will need to intercept DOM event and fire new event with source field 
>>>>>>>> of 
>>>>>>>> custom element. (e.g re-fire through EventHandler). This is kind of 
>>>>>>>> double 
>>>>>>>> work. 
>>>>>>>>
>>>>>>>>   Another thing that we need to care about is if add and then 
>>>>>>>> remove some custom element from DOM like 
>>>>>>>> *element.removeChild(customElement.asElement()) *we also need to 
>>>>>>>> remove reference to custom element to be garbage collected? Since only 
>>>>>>>> *asElement() *is removed from DOM not custom element object 
>>>>>>>> itself. If I'm right...
>>>>>>>>
>>>>>>>>   This is why it would be good if custom element can extends 
>>>>>>>> Element and wrap inner element like Widget Composite.
>>>>>>>>
>>>>>>>
>>>>>>> I'm really not clear about what you want to do, and what you 
>>>>>>> actually mean by "custom element".
>>>>>>> Do you mean Web Components? In this case, they'd have to extend 
>>>>>>> HTMLElement and, at least with elemental2-dom 1.0.0-beta-1, set the 
>>>>>>> connectedCallback, attachedCalback, etc. Encapsulation is then provided 
>>>>>>> by 
>>>>>>> the shadow DOM.
>>>>>>> Or do you mean "kind of widgets, that just happen to map one-to-one 
>>>>>>> with a DOM element and its subtree"? In this case, you're indeed 
>>>>>>> *wrapping* 
>>>>>>> an element, and that means you're going to have parallel hierarchies or 
>>>>>>> such widgets/components on one hand, and DOM elements on the other 
>>>>>>> hand, 
>>>>>>> and will need to maintain both in sync (this is what GWT Widgets do, 
>>>>>>> and I 
>>>>>>> believe more or less how React works too).
>>>>>>>
>>>>>>

-- 
You received this message because you are subscribed to the Google Groups "GWT 
Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at https://groups.google.com/group/google-web-toolkit.
For more options, visit https://groups.google.com/d/optout.

Reply via email to