Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GWT bookmarket or GWT as an external library

I simply want to load a GWT(Google Web Toolkit) app by adding a script tag to the DOM, however because the GWT linker uses document.write() I'm unable to find any good way of doing so. I've found some hacks for doing so on various blog posts but they all seem to fail with the latest version of GWT. Any reasonably non-invasive approach for doing this come to mind?

Clarification:

Normal way to start up a GWT app, in your host html page:

<script type="text/javascript" language="javascript" src="myapp.nocache.js"></script> 

This, of course, starts up as soon as the page loads. I want to do it at a later time:

function startapp() {
    var head = document.getElementsByTagName('head');
    var s = document.createElement('script');
    s.setAttribute('type', 'text/javascript');
    s.setAttribute('src', 'myapp.nocache.js');
    head[0].appendChild(s);
}
like image 400
Abdullah Jibaly Avatar asked Dec 14 '10 00:12

Abdullah Jibaly


2 Answers

Here's what seems to work so far:

Add this to the top of your App.gwt.xml:

<!-- Cross site linker -->
<inherits name="com.google.gwt.core.Core" />
<add-linker name="xs" />

After compiling your app with the above setting, modify (or copy) the generated app.nocache.js as follows:

1) Comment the last $doc.write... statement

2) Copy this portion from the $doc.write statement you just commented out and eval it. Example:

eval('window.__gwtStatsEvent && window.__gwtStatsEvent({' + 'moduleName:"app", sessionId:window.__gwtStatsSessionId, subSystem:"startup",' + 'evtGroup: "loadExternalRefs", millis:(new Date()).getTime(),' + 'type: "end"});' + 'window.__gwtStatsEvent && window.__gwtStatsEvent({' + 'moduleName:"app", sessionId:window.__gwtStatsSessionId, subSystem:"startup",' + 'evtGroup: "moduleStartup", millis:(new Date()).getTime(),' + 'type: "moduleRequested"});');

3) Add this line right after.

document.body.appendChild(document.createElement('script')).src=base + strongName + ".cache.js";

So you're basically replacing the $doc.write with those two lines.

Now, your bookmarklet will look something like:

<a href="javascript:(function(){document.body.appendChild(document.createElement('script')).src='http://abc.com/app.nocache.js';})();">My App</a>
like image 107
Abdullah Jibaly Avatar answered Oct 21 '22 14:10

Abdullah Jibaly


I'm assuming you are already using the cross-domain linker and this does not resolve your problem with document.write. If not, it might be worth a look (sorry, not enough experience with it to say.)

One approach that I am fairly sure could be made to work is this:

Your bookmarklet adds a script tag to the page (as now)

This script is not GWT compiler output. It is a plain-old javascript that adds an IFrame to the page, and the src of that IFrame is pointed at an HTML page on your server that loads your GWT module.

Presumably the goal is for your GWT module to get things out of the page it was loaded into. Of course, it can't do this directly in this case because the IFrame comes from a different domain than the parent page.

In order to make this work you would have to use window.postMessage and window.addEventListener to communicate between your GWT module in the IFrame and your javascript stub in the parent (using JSNI on the GWT side.)

If you have to support older browsers, postMessage won't work - but you might be able to get away with hash manipulation - but this is probably where I'd draw a line on practicality.

like image 45
Mark Allerton Avatar answered Oct 21 '22 15:10

Mark Allerton