GWT UiBinder and Image Sprites - gwt

I'm having trouble getting CSS image sprites to appear in GWT UiBinder. I did review how do i use image sprites in GWT?, but found I was already doing what was suggested.
I have a ui.xml, ClientBundle interface with a CssBundle nested interface, and a css file.
ui.xml:
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
xmlns:g="urn:import:com.google.gwt.user.client.ui">
<ui:with field="resources"
type="edu.wts.upholdingthetruth.poweroftheword.client.resources.POWResources" />
<g:FlowPanel width="100%" styleName="{resources.sprites.underMenuGlow}" />
</ui:UiBinder>
ClientBundle:
public interface POWResources extends ClientBundle {
public static final POWResources INSTANCE = GWT.create(POWResources.class);
#Source("site1/undertopglow.png")
ImageResource underTopGlow();
#Source("sprites.css")
public Sprites sprites();
public interface Sprites extends CssResource {
String underMenuGlow();
}
// other stuff
}
sprites.css:
#sprite .underMenuGlow {gwt-image: "underTopGlow"}
So, I compile my app (which does not complain), and in the browser, my image is missing. When I review the page in Chrome's Developer Tools, I see the corresponding div references the obfuscated css class, but I was not able to find that class defined anywhere.
I was, on the other hand, able to display the image using <g:Image resource="{resources.underTopGlow}" />.
Is there a step I am missing to get images to display via css sprites like this?

You have to call ensureInjected() on your CssResource somewhere in your code; either:
POWResources.INSTANCE.sprites().ensureInjected();
or
#UiField POWResources resources;
…
resources.sprites().ensureInjected();
Alternatively, if you don't share the styles/images with other code, you can replace your ClientBundle with the implicit one that UiBinder creates from ui:style and ui:image (and UiBinder will then take care of calling ensureInjected for you):
<ui:style>
#sprite .underMenuGlow {gwt-image: "underTopGlow"}
</ui:style>
<ui:image field="underTopGlow" src="site1/undertopglow.png" />
…
<span class="{style.underMenuGlow}">foo</span>

Related

How to use GWT UIbinder one inside another

I am creating a web application in java gwt. I am trying to use one uibinder xml into another. To make things common. Is it possible to do templeting in GWT uibinder so that I can separate my header footer and other common stuff?
Thanks
You create a widget, which may have as complex Ui:Binder template as necessary. Then you can use this widget inside another widget's Ui:Binder.
In the following example account and w indicate my own widgets, some of which have their own Ui:Binder templates:
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
xmlns:g='urn:import:com.google.gwt.user.client.ui'
xmlns:w='urn:import:com.filemambo.core.client.widgets'
xmlns:account='urn:import:com.filemambo.user.client.account'
ui:generateFormat='com.google.gwt.i18n.rebind.format.PropertiesFormat'
ui:generateKeys="com.google.gwt.i18n.rebind.keygen.MD5KeyGenerator"
ui:generateLocales="default">
<ui:with field="constants" type="com.filemambo.core.client.constants.AllConstants" />
<g:FlowPanel ui:field="container">
<account:ContactsPanel ui:field="contactsPanel" />
<g:FlowPanel ui:field="accountPanel" >
<g:Label text="{constants.payments}" />
<w:ExtendedDataGrid ui:field="table" checkColumn="false"/>
<w:ExtendedPager ui:field="pager" />
</g:FlowPanel>
</g:FlowPanel>

GWT - Loading browser-specific JavaScript

I've got a JavaScript fix specifically for IE9 and want to load it into my project only for that browser. I thought I might be able to do something like this in my .gwt.xml:
<script src="ie9svgfix.js">
<when-property-is name="user.agent" value="ie9"/>
</script>
But unfortunately this doesn't work. Does anybody know a clean way to do this in GWT?
Thanks,
Jon
You can try conditional comments:
<!--[if IE 9]>
<script src="ie9svgfix.js"></script>
<![endif]-->
The cleanest way in GWT would be to use deferred-binding and inject the script with the ScriptInjector in the IE9 permutation; or have the script loaded by the host page, in which case you can use conditional comments (as suggested by Stano).
With deferred-binding, you'd have to create a class to "deferred-bind" with a specific implementation for IE9.
class SvgFix {
public void fix() { /* no op */ }
}
class SvgFixIE9 {
#Override
public void fix() {
ScriptInjector.fromUrl(GWT.getModuleBaseForStaticFiles() + "ie9svgfix.js")
.setWindow(ScriptInjector.TOP_WINDOW)
.inject();
}
}
And in your EntryPoint, inject the script:
GWT.<SvgFix>create(SvgFix.class).fix();
And finally then choose the appropriate implementation based on permutation:
<replace-with class="com.example.client.SvgFixIE9">
<when-type-assignable class="com.example.client.SvgFix" />
<when-property-is name="user.agent" value="ie9" />
</replace-with>
BTW, note that <script> in gwt.xml files is not supported with the xsiframe linker, and I'd encourage you to use it going forward (it has all the advantages of all the other linkers, and none of their drawbacks, plus it adds Super Dev Mode, flexibility/configurability, etc.)

How to set Widget as Anchor content in GWT instead of the usual String?

I'm in a situation where I want a whole Widget to be a link to another page. Both Anchor and Hyperlink only accept Strings or SafeHTML as visual representation. However, I need e.g. a <div>...</div> to be a link.
This would be similar to:
<div><p>This whole thing is a link</p></div>
Is there a way to do this withou custom coding my own SafeHTML? To be more concrete, I want a GXT HBoxLayoutContainer to be clickable and bookmarkable.
The easiest solution would be using UiBinder:
<ui:UiBinder
xmlns:ui="urn:ui:com.google.gwt.uibinder"
xmlns:container="urn:import:com.sencha.gxt.widget.core.client.container">
...
<g:HTMLPanel>
<a href="somesite">
<container:HBoxLayoutContainer>...</container:HBoxLayoutContainer>
</a>
</g:HTMLPanel>

FlowPanel vs. HTMLPanel in GWT UiBinder

When using UiBinder what is the preferred method of creating a simple layout like this?
FlowPanel:
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
xmlns:g='urn:import:com.google.gwt.user.client.ui'>
<ui:style>
.outer {
display: table;
height: 100%;
width: 100%;
}
.inner {
background: #DDD;
display: table-cell;
vertical-align: middle;
}
</ui:style>
<g:FlowPanel styleName="{style.outer}">
<g:FlowPanel styleName="{style.inner}">
<g:Label ui:field="someLabel"/>
</g:FlowPanel>
</g:FlowPanel>
</ui:UiBinder>
HTMLPanel:
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
xmlns:g='urn:import:com.google.gwt.user.client.ui'>
<ui:style>
.outer {
display: table;
height: 100%;
width: 100%;
}
.inner {
background: #DDD;
display: table-cell;
vertical-align: middle;
}
</ui:style>
<g:HTMLPanel styleName="{style.outer}">
<div class="{style.inner}">
<g:Label ui:field="someLabel"/>
</div>
</g:HTMLPanel>
</ui:UiBinder>
Edit: I know they produce the same html when rendering, I'm wondering if there is any justification for using one style over the other.
The javadocs say that the FlowPanel is the simplest panel, but at what point does using an HTMLPanel become preferable. e.g.
<FlowPanel>
<FlowPanel>
<Widget>
</FlowPanel>
<FlowPanel>
<Widget>
</FlowPanel>
</FlowPanel>
vs.
<HTMLPanel>
<div>
<Widget>
</div>
<div>
<Widget>
</div>
</HTMLPanel>
Thanks.
UiBinder - HTMLPanel vs. div is a fairly similar question but asks about using a div vs. a HTMLPanel.
Actually they will render same in your case - div. There is no difference unless you start adding more elements to FlowPanel.
You can try FlowPanel behaviour here:
http://examples.roughian.com/index.htm#Panels~FlowPanel
You should use HTMLPanel in cases when you need to write your own custom HTML code on the page. It allows to write HTML code inside of HTMLPanel tag.
For example you can't do such trick with FlowPanel.
I recently read Tags First GWT Programming. It seems to me, that the technique he describes would allow you to have much better control over the ultimate rendering of your page, while maintaining the advantages of GWT.
I think the dichotomy that you're asking about between FlowPanel and HTMLPanel isn't really the right question. Instead, it is best to recognize that they're meant for different things.
HTMLPanel is capable of a lot more than FlowPanel is. When you need to dynamically add and remove widgets that are embedded in some custom html, use an HTMLPanel. If you just want some widgets to align together on the page with normal html flow (like some text and pictures) use a FlowPanel.
My personal advice would be to use the simplest thing that can do what you need it to.
I recommend the second example. If possible you should prefer using a plain HTML tag such as "div" over a widget such as "FlowPanel" because of the overhead having an unused logical widget.
This may seems trivial first but it saves you a lot of headache (memory leaks, gquery operations, ...) when you have to deal with a lot of items.

Get UiBinder widget to display inline instead of block

I'm trying to get my UiBinder-defined widget to display inline, but I can't. My current code is:
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder' xmlns:g='urn:import:com.google.gwt.user.client.ui'>
<ui:style>
.section {
border: 1px solid #000000;
width: 330px;
padding: 5px;
display: run-in;
}
</ui:style>
<g:HTMLPanel>
<div class="{style.section}">
<div ui:field="titleSpan" class="{style.title}" />
<div class="{style.contents}">
<g:VerticalPanel ui:field="messagesPanel" />
</div>
</div>
</g:HTMLPanel>
</ui:UiBinder>
This works fine in terms of how the widget looks internally, but I want to throw a bunch of these widgets into a FlowPanel and have them flow when the window is resized. The HTMLPanel is a div, but I can't get the display attribute to assign. I can't force the style name, since the following throws an error:
<g:HTMLPanel styleNames="{style.section}">
And I can assign an additional style, but it doesn't apply the display setting.
<g:HTMLPanel addStyleNames="{style.section}">
This displays the border and sets the size, as expected, but it doesn't flow. Firebug shows the styles on the div are border, width, and padding, but no display.
Is there a way to make a widget in UiBinder so that it'll display inline instead of block? And if so, can I make it compatible with having a VerticalPanel inside (can I do it without making the entire widget pure HTML without any GWT widgets)?
PS: I saw question 2257924 but it hasn't had any answers lately, and he seems to be focused on getting a tag, not specifically getting inline layout. I don't care directly about , if I can just get the top-level tag for my widget to flow inline, I'm happy.
It seems your problem is caused by using display: run-in instead of the more "standard" display: inline. IE and Firefox don't support run-in and it seems that Firebug prunes the style upon adding.
Try changing the style to display: inline (or inline-block if you want some properties of a block, like width, but beware of the quirks of IE + inline-block).
It should be <g:HTMLPanel styleName="{style.section}">, not <g:HTMLPanel styleNames="{style.section}"> - styleNames is a typo (which appears in the UiBinder docs, so I'm sure that's where you got it from). styleName is the correct thing to use.
Also, Igor Klimer is correct that you should use display: inline or display: inline-block rather than display: run-in.
In general, you can tell the available attribute names by looking for setXXX methods on the UIObject class, and the attribute name is just the XXX. So, UIObject has a setStyleName method, which you access using the attribute called styleName.