jsinterop: GWT app as a widdget: default script injection fails.

270 views
Skip to first unread message

Vassilis Virvilis

unread,
May 26, 2016, 6:02:26 AM5/26/16
to google-we...@googlegroups.com
Hi,

This issue has been discussed before https://github.com/gwtproject/gwt/issues/9264

Here is the problem in my own words:

When a script is injected GWT has the option to inject it in the TOP_WINDOW ($wnd) or in the iframe window where GWT code is located normally.

Case 1: Insert in $wnd

Everything works but the page is polluted with the scripts you inject. This is not a problem when the GWT application controls the whole page. It is however a problem when GWT program is loaded as part of a page (Widget). Then all kind of problems may arise due to javascript libraries clashing.

Case 2: insert in iframe window (default)

The script is loaded but jsinterop assumes that the scripts are loaded in $wnd which is not true.

Question:

Is it possible to
1) add a compile time flag in jsinterop that will not prepend $wnd in all global objects defined by the script ...OR...
2) add a namespace JsPackage.LOCAL (as opposed to JsPackage.GLOBAL) option that does not imply $wnd ...OR...
3) do something that fixes the problem somehow!

--
Vassilis Virvilis

Vassilis Virvilis

unread,
May 30, 2016, 3:59:27 AM5/30/16
to google-we...@googlegroups.com
This looks like the logical conclusion to my question.
https://github.com/w3c/webcomponents/blob/gh-pages/proposals/Isolated-Imports-Proposal.md

Since the aboveis probably several years down the road I wonder if anyone has any more ideas or workarounds in how to work with GWT/jsinterop and foreign js libraries __loaded in GWT context__ (iframe) in the immediate future...

Anyone?

  Thanks in advance.
--
Vassilis Virvilis

Vassilis Virvilis

unread,
Jun 3, 2016, 8:10:15 AM6/3/16
to google-we...@googlegroups.com
So here is a hacky workaround:

Q: What the hacky workaround enables?

A: You can inject any js library you want in the GWT iframe thus succeeding encapsulation of the GWT and js code from the rest of the page. No duplicate libaries - no clashed versions etc.

Q: Does it work?

A: sort of. jquery works because you can always search for elements with in $wnd and thus works correctly (at least the 3% I tried). Bootstrap modals on the other hand need to access the body element and there is no way to tell bootstrap (at least without a patch) that it should try to access the body that is parent of the $wnd.modal and not just "body". The same will be true for all javascript libraries that assume that they are running in page all by themselves.

Q: So what's the trick?

Pretty easy actually. The problem is that jsinterop assumes that js libraries are loaded in TOP_WINDOW ($wnd) and when this is not true it fails to find the functions to call them.

So let's give jsinterop a clue.

1) First of all create a js variable in top window that holds GWT iframe

    public static native void jsInit() /*-{
               $wnd.__gwtIFrame = $wnd.document.querySelectorAll('iframe#YourGWTApplicationID')[0].contentWindow;
    }-*/;

2) The load the jslibrary in GWT iframe

package com.common.lib.gwt.client.js.resources;

import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.ScriptInjector;
import com.google.gwt.resources.client.ClientBundle;
import com.google.gwt.resources.client.TextResource;

public interface JQueryResources extends ClientBundle {
    public static final JQueryResources INSTANCE = GWT
            .create(JQueryResources.class);

    public static JQueryResources load() {
        // loads by default in GWT Iframe
        ScriptInjector.fromString(INSTANCE.js().getText()).inject();
        return INSTANCE;
    }

   @Source("jquery.min.js")
    TextResource js();
}

3) Then in jsinterop define __gwtIFrame as the namespace
 
    // instead of that
    // @JsMethod(namespace = JsPackage.GLOBAL)
    // do that
    @JsMethod(namespace = "__gwtIFrame")
     public static native <T extends JQuerySelection> T $(String selector);

Now you can call $ from GWT Iframe

Hope that helps somebody.

Any comments on the approach?
--
Vassilis Virvilis

Jens

unread,
Jun 3, 2016, 9:51:52 AM6/3/16
to GWT Users
Probably needs to be updated a bit if you want to run multiple GWT apps with different names/iframes as widgets on the page as you need a global variable per app then.

If you know everything is served from the same domain you can probably also use window.frames['appId'].contentWindow 

But yes, would be nice if JsInterop would provide a shortcut to generate a reference to the iframe automatically if desired.

-- J.

Vassilis Virvilis

unread,
Jun 3, 2016, 10:07:23 AM6/3/16
to google-we...@googlegroups.com
I haven't thought of multiple gwt widgets (I am struggling with one).

Obviously you are correct in what you are saying. It would be cool if we could feed jsinterop the scope per js injection. However I can't imagine how that would be. You may need to change your interface (namespace argument) in lots of points depending if the script is loaded at the top level or in gwt iframe. Maybe jsinterop N+1?

One very big problem is the beating you have to perform to bring the foreign js libraries into shape for that type of inclusion. Probably anything UI related would have a problem unless is very well written.

A more clear solution if of course https://github.com/w3c/webcomponents/blob/gh-pages/proposals/Isolated-Imports-Proposal.md for anybody that has a time machine handy and doesn't mind a trip to the future... :-)

Thanks for the tips and the reassurance I am not alone in a corner case that doesn't exist.

   Vassilis



--
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 google-web-tool...@googlegroups.com.
To post to this group, send email to google-we...@googlegroups.com.
Visit this group at https://groups.google.com/group/google-web-toolkit.
For more options, visit https://groups.google.com/d/optout.



--
Vassilis Virvilis
Reply all
Reply to author
Forward
0 new messages