My Blog has moved to Github Pages
Showing posts with label gwt. Show all posts
Showing posts with label gwt. Show all posts
Saturday, 12 November 2011
progressive enhancement with gwt
I just made my progressive-enhancement library available on github. Read more about it on my new blog
Labels:
apache2,
gwt,
library,
open source,
progressive enhancement
Wednesday, 12 October 2011
Tuesday, 15 February 2011
Progressive Enhancement with GWT, part 3
Read this article on my new blog
Read about my GWT.Progressive library on my new blog
In my previous posts I described an idea for progressive enhancement using GWT - "activating" server-generated html, to combine GWT goodness with an SEO friendly server-generated website, and my findings after some initial trials.
One of the problems I described in that second post was that it would be very difficult to work with these widgets if nested widgets could not be automatically (or at least easily) bound to fields within this widget.
After a little playing around and learning about GWT Generators I now have what seems like a nice solution, using a Generator to do almost all of the donkey work. Think of it like UiBinder, but with the templates provided at runtime (courtesy of the server). Here's an example class that automatically binds sub-widgets - an Image in this case - to a field of that class:
A remaining question is how to bind the outer-most Widget. Currently I'm doing that using the DOM scanning code I wrote during earlier experiments and which I'm also using in the automatic scanning process set up by the Generator. For example to find the outer-most widgets and kick off the binding process I have something like this in my EntryPoint:
I think of this as very similar to the RootPanel situation - "normal" GWT apps kick off by getting a RootPanel(body tag) or RootPanel's (looked up by id), to which everything else is added. It would be nice to hide away some of that scanning code inside a "top-level" widget - much like RootPanel does for the normal case. I can imagine this might look something like:
Read about my GWT.Progressive library on my new blog
This is the third part in a series, following my thoughts on using GWT in SEO'able web applications. The other parts in the series are part 1 and part 2.
In my previous posts I described an idea for progressive enhancement using GWT - "activating" server-generated html, to combine GWT goodness with an SEO friendly server-generated website, and my findings after some initial trials.
One of the problems I described in that second post was that it would be very difficult to work with these widgets if nested widgets could not be automatically (or at least easily) bound to fields within this widget.
After a little playing around and learning about GWT Generators I now have what seems like a nice solution, using a Generator to do almost all of the donkey work. Think of it like UiBinder, but with the templates provided at runtime (courtesy of the server). Here's an example class that automatically binds sub-widgets - an Image in this case - to a field of that class:
public class MyWidget extends Widget {
interface MyActivator extends ElementActivator<MyWidget> {}
private static MyActivator activator = GWT.create(MyActivator.class);
@RuntimeUiField(tag="img", cssClass="small") Image small;
public MyWidget(Element anElement) {
// this will set our element and bind our image field.
setElement(activator.activate(this, anElement));
// now we can play with our fields.
small.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent aEvent) {
Window.alert("clicked!");
}
});
}
}
This class will bind onto any html that has an image tag somewhere in its inner-html, for example:
<div> <!-- Say our MyWidget is bound here -->
<div>
<span>
<img class="small" src="/images/image.jpg"> <!-- will be bound to our Image widget -->
</span>
</div>
</div>Anyone familiar with UiBinder will recognize the pattern I've used for the "activator":
- Extend an interface with no methods
interface MyActivator extends ElementActivator<MyWidget> {} - GWT.create() an instance of that interface
private static MyActivator activator = GWT.create(MyActivator.class);
- Then use it to initialize your widget
setElement(activator.activate(this, anElement));
The nice thing about this is we can automatically bind as many widgets as we like onto various sites within the inner-html of our current widget's element. It doesn't mess with the structure (unless you explicitly do so after the binding is done for you), and you can have as much other html within the elements as you like - it will just be left alone, which gives your designers the flexibility to change the layout quite a lot without necessarily needing to re-compile your GWT code.
Currently I have my generator set up to allow your widgets to bind to a choice of tag-name or css-class or both, for example:
Currently I have my generator set up to allow your widgets to bind to a choice of tag-name or css-class or both, for example:
// bind to the first <div> found by breadth-first search of child elements @RuntimeUiField(tag="div") Label label; // bind to first element with class="my-widget" found by breadth-first search @RuntimeUiField(cssClass="my-widget") Label label; // bind to first <div> with class="my-widget" found by breadth-first search @RuntimeUiField(tag="div", cssClass="my-widget") Label label;
Notice in my examples so far I'm binding standard GWT widgets onto the nested elements. This works for the elements I've used in these examples because they all have a
public static Type wrap(Element anElement)method which allows those widgets to be bound onto elements that are already attached to the DOM.
It is also possible to bind widgets of your own making in one of two ways:
- Create a wrap method like
public static MyWidget wrap(Element anElement)
- Create a single-argument public Constructor that accepts an Element as its argument.
Activate-able widgets can be nested within other such widgets - with no limits that I am aware of so far - and it is also possible to assign nested widgets to a List field in the enclosing widget, like this:
@RuntimeUiField(tag="img") List<Image> images;This will search recursively for any <img> tags inside the enclosing widget's element and bind them all to Image widget's that will be added to the List. The current limitations here are that the List must be declared either as List or ArrayList, and parameterized with a concrete type that meets the criteria defined above (i.e. has a static wrap(Element) method, or a single-arg constructor that takes an Element as the argument).
A remaining question is how to bind the outer-most Widget. Currently I'm doing that using the DOM scanning code I wrote during earlier experiments and which I'm also using in the automatic scanning process set up by the Generator. For example to find the outer-most widgets and kick off the binding process I have something like this in my EntryPoint:
public void onModuleLoad() {
List<MyWidget> _myWidgets = new ArrayList<mywidget>();
for (Element _e : Elements.getByCssClass("outer-most-widget")) {
new MyWidget(_e);
}
// do stuff with our widgets ...
}
I think of this as very similar to the RootPanel situation - "normal" GWT apps kick off by getting a RootPanel(body tag) or RootPanel's (looked up by id), to which everything else is added. It would be nice to hide away some of that scanning code inside a "top-level" widget - much like RootPanel does for the normal case. I can imagine this might look something like:
public void onModuleLoad() {
Page _page = Page.activate();
_page.doStuffWithWidgets();
// ...
}
I still have lots of things to figure out and questions to answer, for example:
I'll try to keep posting as I work things out.
This probably belongs in a separate post, but with reference to that last point on TSA (Thin Server Architecture) - the working group list the following points to define the concept:
- What's the performance like when binding many hundreds of widgets?
- How will this really work when I make ajax requests for more data? (should I make ajax requests for html snippets which I add to the DOM and then bind onto, or switch to json for ajax requests and make my widgets able to replicate themselves from an initial html template?)
- What's the best way to divide labour between developers and designers, and for them to organize their interaction? (Ideally I'd like there to be something of a cycle between them, where the designer can rough-out a page design, agree the componentisation with the developer, the developer knocks out some components and a build which the designer can use to activate their static designs, add fidelity, work on other pages with the same components, etc).
- Where is the sweet-spot between creating high-fidelity html server-side and decorating it client-side using GWT? Should the GWT components really be just for adding dynamism, or is it a good idea to use them to build additional html sweetness? - I mean the server could dish out html that is more of a model than a view (just enough "view" to satisfy SEO), and the GWT layer acts as a client-side controller and view (SOFEA/TSA with a nod to SEO).
I'll try to keep posting as I work things out.
This probably belongs in a separate post, but with reference to that last point on TSA (Thin Server Architecture) - the working group list the following points to define the concept:
- Do not use server-side templating to create the web page.
- Use a classical and simple client-server model, where the client runs in the browser.
- Separate concerns using protocol between client and server and get a much more efficient and less costly development model.
- Use server-side templating to produce a model for the client to consume which minimally satisfies the needs of SEO.
Labels:
ajax,
designer,
enhancement,
gwt,
progressive,
SEO,
SOFEA,
TSA,
UiBinder
Sunday, 13 February 2011
Progressive Enhancement with GWT, part 2
This is the second part in a series, following my thoughts on using GWT in SEO'able web applications. The other parts in the series are part 1 and part 3.
Since my earlier post, I spent a little time (only a few hours really, so far) trying a few things out. Here's a smattering of things I learned...
Scanning for elements and binding widgets onto them is easy. Making those widgets behave just like widgets in any normal GWT app needs a little more work.
Who's the daddy?
One big problem to get around is that normally GWT widgets are attached via a hierarchy of other widgets (parents) leading back to the RootPanel, whereas when you bind onto some arbitrary element that is already on the page you don't get this hierarchy for free.
When widgets are added to a parent widget some magic happens to set up things like the eventing system. Without that magic you can add as much event-handling plumbing as you like, but it won't work because your widget isn't wired into the eventing system.
Actually getting around this is not all that difficult. Simply invoking onAttach() will wire up your widget, though its a little unpleasant to have to do that.
Another problem with the lack of hierarchy is, well, there's no hierarchy. Things that you would normally do in GWT widgets - like adding, removing or replacing child widgets - gets a little trickier. If you want to use the technique recursively (and why wouldn't you?), you need to allow widgets to bind to elements inside other widgets without causing them to be removed from and re-attached to the DOM, but crucially you still need to add them as 'logical' children of the parent widget, otherwise the parent knows nothing about the child widgets and can't do any of those "normal" operations with them.
To do that there are two problems to overcome:
Scanning for elements and binding widgets onto them is easy. Making those widgets behave just like widgets in any normal GWT app needs a little more work.
Who's the daddy?
One big problem to get around is that normally GWT widgets are attached via a hierarchy of other widgets (parents) leading back to the RootPanel, whereas when you bind onto some arbitrary element that is already on the page you don't get this hierarchy for free.
When widgets are added to a parent widget some magic happens to set up things like the eventing system. Without that magic you can add as much event-handling plumbing as you like, but it won't work because your widget isn't wired into the eventing system.
Actually getting around this is not all that difficult. Simply invoking onAttach() will wire up your widget, though its a little unpleasant to have to do that.
Another problem with the lack of hierarchy is, well, there's no hierarchy. Things that you would normally do in GWT widgets - like adding, removing or replacing child widgets - gets a little trickier. If you want to use the technique recursively (and why wouldn't you?), you need to allow widgets to bind to elements inside other widgets without causing them to be removed from and re-attached to the DOM, but crucially you still need to add them as 'logical' children of the parent widget, otherwise the parent knows nothing about the child widgets and can't do any of those "normal" operations with them.
To do that there are two problems to overcome:
- The parent needs to have the children added to it, so that the set of child widgets is known and available for manipulation (say by extending ComplexPanel and using the getChildren() method).
- Some of the child widgets might need hard, typed references in the parent widget to allow direct manipulation of the child widget - just like in a "normal" GWT widget you would keep a reference to the Button you added in the constructor in order that you can bind ClickHandler's to it or toggle its enabled-ness.
public void logicalAdd(Widget aWidget) {
getChildren().add(aWidget);
adopt(aWidget);
}
I've yet to try to solve point 2. So far I've built:
- Tools to help with scanning for elements to bind to, and then binding the right widget.
- Plumbing to allow recursively binding widgets with logical hierarchy intact (point 1 above).
- An example that binds widgets recursively - an outer container, an inner container, and a bunch of widgets inside that are manipulated by the inner container.
As an aside, I lay awake for a while last night pondering the ability to give designers a client-side templating system, where they can write the html for a component once (declaring it to be a template, which may include recursive binding points for GWT-activated widgets) and then re-use it elsewhere within their html by reference to the template. I'm sure this would be possible, though its utility might extend only to mock-ups.
Sunday, 30 January 2011
Progressive Enhancement with GWT, part 1
This is the first part in a series, following my thoughts on using GWT in SEO'able web applications. The other parts in the series are part 2 and part 3.
GWT Is a superb framework for developing complex, componentized html & javascript widgets. You can have your cake and eat it:
It isn't so great when:
The SEO Problem
To a search engine, GWT apps just look like a big fat lump of dense javascript. Nothing to see here, move along. Its a similar problem for any web-app that uses ajax to collect data from the server, but the problem is magnified with GWT due to the fact that the entire application tends to present as a large lump of dense javascript, whereas many other ajax technologies typically involve some amount of server-side content rendering that can make the site at least partially visible to crawlers.
Google have a recommendation for how to get around the problems of SEO for ajax applications, which entails a special url form and the creation of "html snapshots" - effectively a parallel, ajax-disabled site that the crawler can index. This seems to me to be a workable but irritating solution that involves doing a lot of extra work just to allow a search engine to crawl the site. Its effectively just a Google-approved cloaking method. Also it isn't clear to me whether any other search engines than Google support this approach.
The Design Problem
Don't get me wrong, its not as bad as all that. You can, of course, leverage your UI/UX designer's talents when building GWT apps. They can produce designs that the GWT developers base their components on, and with UIBinder the html fragments produced by a designer can be used in large chunks, but there is always some disconnect between what the designers produce and what is actually output by the application - usually because there is a developer translating the designer's work into GWT components.
In retrospect, having built a number of "monolithic" GWT applications, it seems to me that what we're missing is a way to step back just a little from the "GWT does everything" mind-set, and instead to leverage GWT where it is best suited, and something a little more flexible where GWT can be too restrictive - for example when laying out high level components on a page it would be advantageous to be able to escape from the restrictions of having to compile that page layout into js, and instead work at the level of straight-forward declarative markup.
Introducing "GWT-Activated Pages"
How can we solve these two issues? One idea I've been toying with, is to use GWT for progressive enhancement of simple html + css, and goes as follows:
Rather than try to build two almost parallel versions of your application (one for SEO, one for real users), why not build one with a layered approach that allows graceful degradation for browsers with javascript disabled (of which search-engines could be considered a sub-set).
The base-layer that non-javascript browsers would render, and which search-engines would see, would be generated by some typical server-side technology - php, jsp, struts, jfaces, ... take your pick. This would build a "wireframe" of your page, giving it a basic shape and layout, and filling in some starter content. The markup would ideally be meaningful, in the sense that headings would appear in <h1> tags to indicate that they are headings, rather than to give them any particular styling.
This base layer would be something that designers could work on directly, including any and all css styling.
The second layer would be a set of GWT widgets that "activate" or progressively enhance the page, by scanning the DOM for certain signs that denote activateable sections of markup. When the base page loads, GWT widgets search for elements to bind themselves to. When a widget finds such an element it binds to it and "activates" it. Activation could mean anything from completely changing the html markup, to binding event-listeners, to handling interaction with ajax data loading from the server.
Here's a simple example "base" layer:
Notice the elements with css class-names prefixed with "gwt-". These are the signs that our gwt widgets will be looking for in order to know which elements they should activate.
As you probably guessed, the navigation widget would detect any elements with a class-name matching "gwt-navigation-widget", while the news-ticker will search for "gwt-news-ticker-widget".
OK, so what do we get for our troubles? Well, several things potentially:
In my simple example I showed the scripts being loaded separately, just for clarity, but I'm sure you wouldn't want to load each widget as a separate script - that would lose a good chunk of GWT's advantage. Rather, the whole widget-set could be loaded as one script, cached forever, and used all over.
Now, if you want to see an example of GWT-activated pages at work, just take a look at my older post on rendering 3D Rubiks Cubes with GWT and HTML5 Canvas, where the rubik's cubes are rendered by a gwt widget that "activates" a <div> element containing the configuration for the cube.
OK, but what are the down-sides? Here's a few...- Drop down into native javascript as and when you feel the need
- Integrate easily with native js components and libraries
- Use GWT components relatively easily from native javascript
- Create super-condensed, fast, platform-specific code, easily
- All the benefits of Java's static type-system, packages, and tooling to manage and refactor your code
It isn't so great when:
- You need to expose the content of your site for search-engines to index (The SEO Problem).
- You want to leverage the html and css skills of your UI designers, and to be able to generate more flexible layouts without requiring a re-compile (The Design Problem).
The SEO Problem
To a search engine, GWT apps just look like a big fat lump of dense javascript. Nothing to see here, move along. Its a similar problem for any web-app that uses ajax to collect data from the server, but the problem is magnified with GWT due to the fact that the entire application tends to present as a large lump of dense javascript, whereas many other ajax technologies typically involve some amount of server-side content rendering that can make the site at least partially visible to crawlers.
Google have a recommendation for how to get around the problems of SEO for ajax applications, which entails a special url form and the creation of "html snapshots" - effectively a parallel, ajax-disabled site that the crawler can index. This seems to me to be a workable but irritating solution that involves doing a lot of extra work just to allow a search engine to crawl the site. Its effectively just a Google-approved cloaking method. Also it isn't clear to me whether any other search engines than Google support this approach.
The Design Problem
Don't get me wrong, its not as bad as all that. You can, of course, leverage your UI/UX designer's talents when building GWT apps. They can produce designs that the GWT developers base their components on, and with UIBinder the html fragments produced by a designer can be used in large chunks, but there is always some disconnect between what the designers produce and what is actually output by the application - usually because there is a developer translating the designer's work into GWT components.
In retrospect, having built a number of "monolithic" GWT applications, it seems to me that what we're missing is a way to step back just a little from the "GWT does everything" mind-set, and instead to leverage GWT where it is best suited, and something a little more flexible where GWT can be too restrictive - for example when laying out high level components on a page it would be advantageous to be able to escape from the restrictions of having to compile that page layout into js, and instead work at the level of straight-forward declarative markup.
Introducing "GWT-Activated Pages"
How can we solve these two issues? One idea I've been toying with, is to use GWT for progressive enhancement of simple html + css, and goes as follows:
Rather than try to build two almost parallel versions of your application (one for SEO, one for real users), why not build one with a layered approach that allows graceful degradation for browsers with javascript disabled (of which search-engines could be considered a sub-set).
The base-layer that non-javascript browsers would render, and which search-engines would see, would be generated by some typical server-side technology - php, jsp, struts, jfaces, ... take your pick. This would build a "wireframe" of your page, giving it a basic shape and layout, and filling in some starter content. The markup would ideally be meaningful, in the sense that headings would appear in <h1> tags to indicate that they are headings, rather than to give them any particular styling.
This base layer would be something that designers could work on directly, including any and all css styling.
The second layer would be a set of GWT widgets that "activate" or progressively enhance the page, by scanning the DOM for certain signs that denote activateable sections of markup. When the base page loads, GWT widgets search for elements to bind themselves to. When a widget finds such an element it binds to it and "activates" it. Activation could mean anything from completely changing the html markup, to binding event-listeners, to handling interaction with ajax data loading from the server.
Here's a simple example "base" layer:
<html> <body> <h1>Page Header</h1> <ol class="gwt-navigation-widget"> <!-- the listitems are generated server side --> <li><a href="..">Home</a></li> <li><a href="..">News</a></li> <li><a href="..">Videos</a></li> <li><a href="..">Photos</a></li> <li><a href="..">About</a></li> </ol> <ol class="gwt-news-ticker-widget"> <!-- the listitems are generated server side --> <li>News story 1</li> <li>News story 2</li> ... <!-- this last listitem gives a link that a search engine can follow to get more data --> <li><a href="..">older stories</a></li> </ol>
<script type="text/javascript" language="javascript" src="widgets/navigation-widget.js"></script> <script type="text/javascript" language="javascript" src="widgets/news-ticker-widget.js"></script> </body></html>Notice the elements with css class-names prefixed with "gwt-". These are the signs that our gwt widgets will be looking for in order to know which elements they should activate.
As you probably guessed, the navigation widget would detect any elements with a class-name matching "gwt-navigation-widget", while the news-ticker will search for "gwt-news-ticker-widget".
OK, so what do we get for our troubles? Well, several things potentially:
- One request to the server to get our initial page full of data (rather than multiple widgets requesting async loading of little chunks of data)
- A page that contains the data and is search-engine friendly, allowing pages deep within your app to indexed by search-engines
- A very clear separation of widgets and page layout, allowing you more flexibility to change the page layout without GWT re-compile
- Flexibility in dividing work between designers and developers:
- designers can focus on the design-heavy html and css work, and the overall page layout
- developers can focus on interaction with the server, complex widget behaviour, etc.
- Examine the content of the element - this will very likely be the source of its initial configuration and/or data-set, and also might include some information about how to load more content, as in the news-ticker example whose last <li> is a link to "older stories". I'm sure it would be a good idea to make this even more explicit, but like I said this is supposed to be a simple example :)
- Replace or modify the content of the element - perhaps the widget displays a very complicated UI, so it removes the html and replaces it with something nifty that it generates, or maybe it just adds some decoration in the form of small visible changes, or perhaps it binds a bunch of event handlers to do neat tricks like adding gesture handling for touch-screen users.
In my simple example I showed the scripts being loaded separately, just for clarity, but I'm sure you wouldn't want to load each widget as a separate script - that would lose a good chunk of GWT's advantage. Rather, the whole widget-set could be loaded as one script, cached forever, and used all over.
Now, if you want to see an example of GWT-activated pages at work, just take a look at my older post on rendering 3D Rubiks Cubes with GWT and HTML5 Canvas, where the rubik's cubes are rendered by a gwt widget that "activates" a <div> element containing the configuration for the cube.
- Compiler no longer has visibility across the whole UI.
- Messaging between components becomes more difficult (but not impossible). This has its advantages too - it forces low coupling. Messaging via OpenAjax Hub or similar would be worth considering.
- It's more work than a straight-out GWT UI, and many would argue why bother to use GWT at all if you need SEO (depends on your skill-set and the complexity of the components you're building in my view).
- I'm sure that there are others which I'm currently blind to ... I need to try to build some more complex and interesting examples to find these out.
tl;dr ?
Sunday, 2 January 2011
3D graphics using the html5 canvas
I thought i'd put up a quick sample of my latest play-thing - a 3D rendering of a rubik's cube, using javascript (GWT) to implement the z-buffer and the html5 canvas as the display. I originally built this in plain old javascript, but have now converted it to GWT - partly just for fun and partly to make the code a bit more manageable and refactorable (if that's even a word). Along the way I made a few optimisations like caching radian, sin and cosine values of angles.
The cube is made from 27 "blocks", each of which has a face in each of the rubik-cube face colours. When the 27 blocks are put together we get the completed cube. Admittedly the 27th block isn't really necessary (its right in the middle where it is never visible), but it made life just that little bit simpler to ignore that and go with it.
The cubes you can see below are rendered when the page loads. The scenes are pretty simple, so render very quickly. You may have seen the cube configuration instead of the cubes for a short while until the javascript loaded, at which point the configuration is replaced by the rendered cubes.
Configuring a cube to display is as simple as adding a <div> element like this:
<div class="rubiks" style="width:150px; height:150px;">
{"rubik-cube":{}, "camera":{}}
</div>
This sets up the default position and orientation for both camera and cube, which looks like this:
{ "rubik-cube": {}, "camera":{} }
That's a pretty boring view, so lets rotate the cube so that we can see more than just the red-face nearest us. To do that we supply some rotations around the x and y axis like this:
<div class="rubiks" style="width:150px; height:150px;">
{ "rubik-cube":{ "rotate-x":35, "rotate-y":35, "rotate-z":35 }, "camera":{} }
</div>
This results in the following cube:
{ "rubik-cube": { "rotate-x":35, "rotate-y":35, "rotate-z":35 }, "camera":{} }
I'm quite pleased with the results so far, and the performance is not bad either it seems. The speed of actually drawing on the canvas seems to be plenty good enough to get away with a bit of animation. On my (Core i7) laptop I can spin the cube on all 3 axis at a couple-hundred frames per second (hopefully i'll put up an example in a later post). Next steps for the rubik's application (yeah, like i'll get around to it) would be:
- Supply "twist" information in the configuration so I can show cubes in various stages of completion.
- Animate the twists, allowing a viewer to step through the twists, for example to see how to solve a particular part of a cube.
- Interactive mode where the viewer can play with the cube.
In a separate direction, the z-buffer i've built up in order to render the cubes could be improved in lots of nice ways too.
Just before I finish off with a few more views of the cube, I wanted to mention that I had a few issues finding a way to host the scripts and use them in Blogger. Annoyingly you can't host javascript or html files directly from Blogger, so I had to find somewhere else to put them.
My usual approach for hosting source code is to use github "gists", which provides a neat way of showing prettified source, but also lets you view the "raw" source. That allowed me to host the js somewhere, but I had to work around a cross-site scripting issue loading the GWT sources from a different domain.
Fortunately GWT makes that easy with its "xs" linker, which produces a bunch of ".no-cache.js" files instead of "no-cache.html" files, and solves the XSS problem. To use the xs linker you just add a single line to your .gwt.xml file:
Sadly that prevents hosted mode from working (currently), but that's easy enough to work around :)
Just before I finish off with a few more views of the cube, I wanted to mention that I had a few issues finding a way to host the scripts and use them in Blogger. Annoyingly you can't host javascript or html files directly from Blogger, so I had to find somewhere else to put them.
My usual approach for hosting source code is to use github "gists", which provides a neat way of showing prettified source, but also lets you view the "raw" source. That allowed me to host the js somewhere, but I had to work around a cross-site scripting issue loading the GWT sources from a different domain.
Fortunately GWT makes that easy with its "xs" linker, which produces a bunch of ".no-cache.js" files instead of "no-cache.html" files, and solves the XSS problem. To use the xs linker you just add a single line to your .gwt.xml file:
<add-linker name="xs" />
Sadly that prevents hosted mode from working (currently), but that's easy enough to work around :)
{ "rubik-cube": { "rotate-x":35, "rotate-y":35 }, "camera":{} } | { "rubik-cube": { "rotate-x":45, "rotate-y":135 }, "camera":{} } | { "rubik-cube": { "rotate-x":45, "rotate-z":135 }, "camera":{} } | { "rubik-cube": { "rotate-x":45, "rotate-y":215 }, "camera":{} } |
{ "rubik-cube": { "rotate-x":135, "rotate-y":35 }, "camera":{} } | { "rubik-cube": { "rotate-x":95, "rotate-y":125 }, "camera":{} } | { "rubik-cube": { "rotate-x":15, "rotate-y":15, "rotate-z":15 }, "camera":{} } | { "rubik-cube": { "rotate-x":25, "rotate-y":-25 }, "camera":{} } |
Tuesday, 7 December 2010
Using non-standard css properties in GWT
Sometimes you'll want to use a non-standard CSS property in GWT - say to use rounded-corners on your borders using -moz-border-radius and -webkit-border-radius.
However, if you just plonk those properties in your CSSResource you're in for some warnings. GWT doesn't like property names that start with "-". The solution is very simple: escape the leading "-" with a "\", e.g. \-moz-border-radius: 5px.
However, if you just plonk those properties in your CSSResource you're in for some warnings. GWT doesn't like property names that start with "-". The solution is very simple: escape the leading "-" with a "\", e.g. \-moz-border-radius: 5px.
Saturday, 16 October 2010
GWT Widgets with html id attributes
It isn't immediately obvious how to get your GWT widgets to produce id attributes that you can use from external scripts or testing tools like WebDriver or Selenium.
To make your widgets produce id attributes you need to invoke the ensureDebugId method with an id string, e.g.
Now, if you run that you still won't get any id attributes. The clue is in the method name ensureDebugId. You actually need to inherit the Debug module in your module descriptor (.gwt.xml) file. The module to inherit is:
Now if you view the source of your label you'll see that it has an id attribute, but you might be surprised that it doesn't quite match the id you supplied ("myLabel"). In fact it will say "gwt-debug-myLabel".
To make your widgets produce id attributes you need to invoke the ensureDebugId method with an id string, e.g.
Label myLabel = new Label("Say something");
myLabel.ensureDebugId("myLabel");
Now, if you run that you still won't get any id attributes. The clue is in the method name ensureDebugId. You actually need to inherit the Debug module in your module descriptor (.gwt.xml) file. The module to inherit is:
<inherits name="com.google.gwt.user.Debug"/>
Now if you view the source of your label you'll see that it has an id attribute, but you might be surprised that it doesn't quite match the id you supplied ("myLabel"). In fact it will say "gwt-debug-myLabel".
Testing GWT OOPHM with WebDriver
Reminder to self: When testing GWT OOPHM with WebDriver, don't use the HtmlUnitDriver you damned fool - it does not have a GWT plugin, so it just sees the bootstrap html and nothing more than that. To test in OOPHM with WebDriver you have to use a real browser that has a GWT plugin :)
Testing GWT apps with WebDriver
Today I've been playing a little with WebDriver for testing GWT apps. First impressions:
To get started I made a new toy project to play in. I don't use the Google Eclipse plugins for GWT dev - if you do you could create this project using the wizards instead. I develop in Eclipse, but always set up my projects with Maven, so the first step for me was to create a new maven project:
mvn archetype:create -DgroupId=com.sjl -DartifactId=webdriver
mvn eclipse:eclipse
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium</artifactId>
<version>2.0a4</version>
</dependency>
mvn eclipse:eclipse
Pushing the button adds a new Label for each push - something we should be able to detect pretty easily.
My gwt module file looks like this:
Next I made an "ApplicationDriver" class to wrap up the details of getting WebDriver to interact with the web app and let our tests deal with the web app in terms of a ubiquitous domain language - overkill for this simple example i'm sure, but if you want to write expressive tests for a complex web app you really need to do so at a higher level than WebDriver invocations. The ApplicationDriver class looks like this:
Now there are a few things worth noting here, as it took me a while to arrive at this point with something that actually worked.
First of all, notice that i'm using the FirefoxDriver implementation. I had started out with HtmlUnitDriver which works just fine for testing a compiled GWT app (provided you create it with javascript support - new HtmlUnitDriver(true), and ignore the warnings about x-javascript) but I wanted to test during development by running OOPHM. Stupidly I was trying to get this to work with the HtmlUnitDriver for a while, til I had a Homer Simpson moment (doh!) and realized that of course HtmlUnitDriver can't work - it doesn't have a GWT plugin :).
Secondly, the FirefoxDriver implementation starts up an instance of Firefox with a profile called "WebDriver". If you don't have a profile with that name Firefox will create one when it starts, but it won't have any of your plugins (including the GWT plugin!). Its easy to create a new profile (close all instances of firefox down completely then run it from the cmdline with the -profilemanager switch) - precise instructions vary by platform. I created the profile then just copied my existing profile contents to it to save installing all the plugins again. In the sample code above i've told WebDriver to use the "default" profile instead by setting a system property.
Finally, note that I'm finding the PushButton by id lookup. To make this work you have to force GWT to spit out an id for the element, and allow for the fact that GWT adds a prefix ("gwt-debug-") to the id you specify. To force GWT to produce id's for your Widget elements:
Finally I built the testcase on top of the ApplicationDriver, starting with a test to detect the first Label, then a test to click the PushButton and check that a new Label is added. The testcase looks like this:
That's it ... start up GWT OOPHM, run the Junit testcase, and marvel as Firefox starts up, runs the app, and shuts down again (3 times - once for each test), leaving you with a nice green bar in JUnit. I'm sure that restarting firefox between each test would be a bad idea - slooooow - in practice, I just wanted to try it to see that it worked :)
The next interesting test to play with will be testing asynchronous activity like AJAX requests. I'm hoping there'll be some nice Patterns described by the WebDriver community for writing such tests.
- WebDriver is awesome - can't wait to try testing more complex web-apps!
- WebDriver opens up all kinds of possibilities beyond testing web-apps - for example to drive interactive demos and tutorials.
- Did I mention WebDriver is awesome? :)
Preparing the Eclipse project
To get started I made a new toy project to play in. I don't use the Google Eclipse plugins for GWT dev - if you do you could create this project using the wizards instead. I develop in Eclipse, but always set up my projects with Maven, so the first step for me was to create a new maven project:
mvn archetype:create -DgroupId=com.sjl -DartifactId=webdriver
Next, create the Eclipse project so I can use eclipse to edit the maven pom...
mvn eclipse:eclipse
And then edit pom.xml in Eclipse to add the GWT, JUnit4 and WebDriver dependencies (by default maven adds JUnit 3.8, so I replace that with JUnit 4.4).
To add the GWT dependencies you also need a repository that actually has them - I use the CodeHaus gwt maven plugins during the build step, which also exposes the CodeHaus repository for fetching the dependences:
<pluginRepositories>
<pluginRepository>
<id>codehaus-snapshots</id>
<name>Codehaus plugin snapshot repository</name>
<url>http://snapshots.repository.codehaus.org</url>
</pluginRepository>
</pluginRepositories>
<pluginRepository>
<id>codehaus-snapshots</id>
<name>Codehaus plugin snapshot repository</name>
<url>http://snapshots.repository.codehaus.org</url>
</pluginRepository>
</pluginRepositories>
...
<dependencies>
<dependency>
<groupId>com.google.gwt</groupId>
<artifactId>gwt-dev</artifactId>
<version>2.0.4</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.google.gwt</groupId>
<artifactId>gwt-user</artifactId>
<version>2.0.4</version>
<scope>provided</scope>
</dependency>
...<groupId>com.google.gwt</groupId>
<artifactId>gwt-dev</artifactId>
<version>2.0.4</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.google.gwt</groupId>
<artifactId>gwt-user</artifactId>
<version>2.0.4</version>
<scope>provided</scope>
</dependency>
Next the WebDriver dependencies - I got these as transitive dependencies of selenium2:
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium</artifactId>
<version>2.0a4</version>
</dependency>
Having edited the pom.xml file you need to rebuild the eclipse project using the eclipse maven plugin:
mvn eclipse:eclipse
This will take a little while to download the dependencies if you don't already have them - the gwt dependencies in particular are quite large. Once the command completes you need to refresh the project in Eclipse for it to reload the project classpath.
Creating a simple GWT app
I made a really simple application to play with, consisting of just an EntryPoint that displays a Label, and a PushButton which adds more Label's when clicked. I had just a handful of aims in mind for this first attempt:
- Get a GWT app to load via WebDriver
- Find an element which GWT has created (the first Label)
- Interact with an element that does something (the PushButton)
- Check that the something actually happened and that we can test for it.
Pushing the button adds a new Label for each push - something we should be able to detect pretty easily.
My gwt module file looks like this:
Next I made an "ApplicationDriver" class to wrap up the details of getting WebDriver to interact with the web app and let our tests deal with the web app in terms of a ubiquitous domain language - overkill for this simple example i'm sure, but if you want to write expressive tests for a complex web app you really need to do so at a higher level than WebDriver invocations. The ApplicationDriver class looks like this:
Now there are a few things worth noting here, as it took me a while to arrive at this point with something that actually worked.
First of all, notice that i'm using the FirefoxDriver implementation. I had started out with HtmlUnitDriver which works just fine for testing a compiled GWT app (provided you create it with javascript support - new HtmlUnitDriver(true), and ignore the warnings about x-javascript) but I wanted to test during development by running OOPHM. Stupidly I was trying to get this to work with the HtmlUnitDriver for a while, til I had a Homer Simpson moment (doh!) and realized that of course HtmlUnitDriver can't work - it doesn't have a GWT plugin :).
Secondly, the FirefoxDriver implementation starts up an instance of Firefox with a profile called "WebDriver". If you don't have a profile with that name Firefox will create one when it starts, but it won't have any of your plugins (including the GWT plugin!). Its easy to create a new profile (close all instances of firefox down completely then run it from the cmdline with the -profilemanager switch) - precise instructions vary by platform. I created the profile then just copied my existing profile contents to it to save installing all the plugins again. In the sample code above i've told WebDriver to use the "default" profile instead by setting a system property.
Finally, note that I'm finding the PushButton by id lookup. To make this work you have to force GWT to spit out an id for the element, and allow for the fact that GWT adds a prefix ("gwt-debug-") to the id you specify. To force GWT to produce id's for your Widget elements:
- Inherit the Debug module in your module descriptor file (.gwt.xml)
- Set an id on the Widget using widget.ensureDebugId("theId");
Finally I built the testcase on top of the ApplicationDriver, starting with a test to detect the first Label, then a test to click the PushButton and check that a new Label is added. The testcase looks like this:
That's it ... start up GWT OOPHM, run the Junit testcase, and marvel as Firefox starts up, runs the app, and shuts down again (3 times - once for each test), leaving you with a nice green bar in JUnit. I'm sure that restarting firefox between each test would be a bad idea - slooooow - in practice, I just wanted to try it to see that it worked :)
The next interesting test to play with will be testing asynchronous activity like AJAX requests. I'm hoping there'll be some nice Patterns described by the WebDriver community for writing such tests.
Subscribe to:
Posts (Atom)