How to use buttons with GWT's UiBinder? - gwt

In MyPanel.ui.xml:
<button class="btn" ui:field="myButton">Save</button>
In MyPanel.java:
public class MyPanel extends Composite {
...
#UiField ButtonElement myButtonUi;
...
public MyScreen() {
final HTMLPanel panel = uiBinder.createAndBindUi(this);
initWidget(panel);
Button myButton = Button.wrap(myButtonUi);
In MyEntryPoint.java:
if (....)
RootPanel.get().add(new MyPanel());
So I think I don't really understand how to use UiBinder.
It's my intention to use HTML with ui:field=".." so that the web-designer can set things like class="xx" on the UI fields. Most of the GWT documentation assumes you've got a Button not a ButtonElement. But if I use a Button I need to have a <g:Button> in the HTML document which means my web-designer can't set the class? I mean the point of UiBinder is to allow one to use normal HTML and integrate it with the GWT code?
When I do the above, on the wrap line, I get a NullPointerException in development mode from:
public static Button wrap(com.google.gwt.dom.client.Element element) {
// Assert that the element is attached.
assert Document.get().getBody().isOrHasChild(element);
In production mode it seems to work OK. In the debugger of development mode in Eclipse, when I right-click and "Inspect" the expression "Document.get().getBody()" Eclipse says "Cannot send a static message to a non class type object".
What should I do? Is the null pointer exception happening because I need to attach the element first? If so, how? (I am already calling createAndBindUi and the element passed to wrap is non-null).

So finally, here's the answer. I Edited it and deleted useless comments.
You can't use HTML in your ui.xml if your plan is to use UiBinder to wire a component from the ui.xml to your view's Java code. Instead of
<button class="btn" ui:field="myButton">Save</button>
use
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder' xmlns:g='urn:import:com.google.gwt.user.client.ui'>
<g:Button styleName="btn" text="Save" ui:field="myButton"/>
Then in your view -java code- simply type
#UiField com.google.gwt.user.client.ui.Button myButton;
public MyScreen() {
final HTMLPanel panel = uiBinder.createAndBindUi(this);
initWidget(panel);
}
That's it.
The "styleName" attribute is enough for your designer to hook a CSS class. This other post might interest you. Designers will have to learn about what attributes are available on which components. Using UiBinder is not as straighforward as using HTML.
UiBinder is not for writing HTML but to write XML that can be understood by GWT and compiled to javascript (which in turn will produce the page's HTML). It's not like the JSP mechanism where you can insert plain HTML right away.
UiBinder is most helpful when you have to wire ui elements (widgets or composites from the ui.xml) with your Java view code (i.e. using the #UiField or #UiHandler annotations).

You can use HTML. The only restriction is that g:Button must be inside a container like g:HTMLPanel.
The good thing about g:HTMLPanel is that it can render HTML.
See the example below:
<g:HTMLPanel>
<div>
test
</div>
<table border="1">
<th>
button
</th>
<tr>
<td>
<g:Button styleName="{style.important}" ui:field="button"/>
</td>
</tr>
</table>
<div>
test
</div>
</g:HTMLPanel>

Related

How to set Ui:Field name for HTML <tr> tag (not Google Widget)?

I want to set Ui:Field name for HTML tag (not Google Widget), something like this:
in my UiBinder file
<g:HTMLPanel>
<table> <tr ui:field="myRow"><td>Test</td></tr></table>
</g:HTMLPanel>
And my View.java
#UiField Tr myRow;
Can we do this? how to do it properly?
I also want to hide the Tr after clicking hideRow button & how to do that?
In your Java, list it as
#UiField
TableRowElement myRow;
or just as
#UiField
Element myRow;
This is documented at http://www.gwtproject.org/doc/latest/DevGuideUiBinder.html#Hello_World - see the SpanElement called nameSpan or the DivElement called root.
Edit to answer hiding issue added after question was posted:
There isn't a built-in way to hide an Element, but you can manipulate the element in GWT/Java the same as you would in JS, something like this:
myRow.getStyle().setDisplay(Display.NONE);
Other ways to set this include visibility:hidden, or just removing it from its parent element.

Dynamic String in UiBinder (not for i18n)

I'm trying to make a Widget that generalizes a bootstrap style from twitter for collapsible items.
I got to make it work hardcoding it, but I find some dificulties abstracting it.
The widget looks like:
<div class="accordion" id="accordion1">
<div class="accordion-group">
<div class="accordion-heading">
<a class="accordion-toggle" data-toggle="collapse" data-parent="#accordion1" href="#collapseOne">
... text to show collapsed ...
</a>
</div>
<div id="collapseOne" class="accordion-body collapse">
<div class="accordion-inner">
... anything to show expanded ...
</div>
</div>
</div>
</div>
The thing is, this uses a javascript which depends on ids of some div tags. The generalized widget would need this to be randomized or depending on some seed passed in the constructor.
It would also be nice to have access to those generated Strings from Java part, as it would be a fancy way to set the text showing in the widget.
My first approach was to use something like <ui:with type="com.a.b.c.IdGenerator" field="idGenerator"></ui:with> but it seems to instanciate dynamically the class IdGenerator so no access to the Strings is obtained in Java part.
Is there any fancy way to dinamically generate those Strings having access to them from the Java part?
You simply need a #UiField IdGenerator idGenerator on the Java side to have the instance created by the <ui:with> injected in it (or you can #UiField(provided = true) it).

Defining GWT CellTables with UiBinder

If I define my CellTable in MyView.ui.xml UiBinder file like this:
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
xmlns:g='urn:import:com.google.gwt.user.client.ui'
xmlns:c="urn:import:com.google.gwt.user.cellview.client"
ui:generateFormat='com.google.gwt.i18n.rebind.format.PropertiesFormat'
ui:generateKeys='com.google.gwt.i18n.rebind.keygen.MD5KeyGenerator'
ui:generateLocales='default' xmlns:p1="urn:import:com.google.gwt.user.cellview.client">
...
<g:HTMLPanel>
<c:CellTable
addStyleNames='{style.cellTable}'
pageSize='15'
ui:field='cellTable' width="100%">
</c:CellTable>
</g:HTMLPanel>
and then programmaticaly add the columns to the CellTable, everything works fine.
But in an attempt to reduce boilerplate code I would like to define also the table columns in my UiBinder file. I've tried this:
...
<g:HTMLPanel>
<c:CellTable
addStyleNames='{style.cellTable}'
pageSize='15'
ui:field='cellTable' width="100%">
<c:TextColumn
addStyleNames='{style.titleColumn}'
ui:field="titleColumn"/>
</c:CellTable>
</g:HTMLPanel>
But it produces the following error:
[ERROR] [dialective] - Found unexpected child element Element addStyleNames='{style.titleColumn}'ui:field='titleColumn'> (:33)
How could I define the whole CellTable using UiBinder?
Evidently, in the second listing you're trying to add a column as a child object. Cell table doesn't accept children directly (meaning there is no addChild(...) method).
If you have fixed number of columns and want to use UIBinder consider using mere HTML table. In that case you will have all columns in the XML file, but the table will become harder to work with - HtmlElement not Widget.
<table ui:field="table">
<col ui:field="firstColumn" class="{style.firstColumn}">
<col ui:field="secondColumn" class="{style.secondColumn}">
...
</table>
And the code might look like the following
...
#UiField
private TableColElement firstColumn;
#UiField
private TableColElement secondColumn;
But all other operations with the table will be via DOM. Like table.appentChild(rowElement). I think doing like this doesn't worth it.

How to bind form based actions like 'Save' to designated Java classes mentioned in xwork in Confluence

I have made some significant progress in my customization efforst thanks to your help and looking forward to move forward similarly.
I have created the custom tab in the 'Advanced' tab and it now looks like this.
I have been able to add a text field as well as a 'Save' button. I actually followed the 'Edit Space Details' option and took two of its form elements to achieve the output.
This is how my VM looks now.
##requireResource("confluence.web.resources:space-admin")
<html>
<head>
<title>Freeway Project Creation</title>
<meta name="decorator" content="atl.general" />
</head>
<content tag="key">$action.space.key</content>
<body>
#applyDecorator("root")
#decoratorParam("helper" $action.helper)
#decoratorParam("context" "space-administration")
#decoratorParam("mode" "view-space-administration")
#applyDecorator ("root")
#decoratorParam ("context" "spaceadminpanel")
#decoratorParam ("selection" "add-fpc-label-action-web-ui")
#decoratorParam ("title" $action.getText("action.name"))
#decoratorParam ("selectedTab" "admin")
#decoratorParam("helper" $action.helper)
<div >
<table width="95%" border=0 cellspacing=0 cellpadding=5>
<form name="editspace" method="POST" >
#bodytag( "TextField" "label='space-name'" "name='name'" "size=40" )
#param ("labelwidth" "100")
#param ("tdcolor" "f0f0f0")
#end
<tr>
<td colspan="2" align="center">
#tag( "Submit" "name='confirm'" "value='update.name'" "theme='notable'" )
#tag( "Submit" "name='cancel'" "value='cancel.name'" "theme='notable'" )
</td>
</tr>
</form>
</table>
</div>
#end
#end
</body>
</html>
I would like to understand how this interaction with my JAVA class will result in the output like. For eg: I will enter the name in the text box for name and hit save and on a resulting page it must display the name entered.
As of now my designated java class looks like this.
package com.atlassian.myorg;
import com.atlassian.confluence.core.ConfluenceActionSupport;
import com.atlassian.confluence.pages.AbstractPage;
import com.atlassian.confluence.pages.actions.PageAware;
import com.opensymphony.xwork.Action;
/**
* The simplest action possible
*/
public class FreewayProjectAction extends ConfluenceActionSupport
{
#Override
public String execute() throws Exception
{
return Action.SUCCESS;
}
}
So I have 3 questions:
The 'Edit Space Details' shows the following URL 'http://localhost:1990/confluence/spaces/doeditspace.action?key=LBTEST' when i mouse over the 'Save' button. I am assuming that its governing Java class is EditSpaceDetails. So is the doEdit() method (see here )inside that class that swings into action when we try to save the edit action of the space ? Can i get to see the xml that has this mapping specifically for this edit space details action? Is my assumptin correct ?
In order to have such a functionality i have mentioned earlier i.e. displaying the name entered in my custom page as detailed above what will be the changes required in my Java class.
In the page i have just customised there is the text box and the label is 'Name' . Should i use a different xml so that i can provide my custom label like "Project Name" ?
Please do kindly advice me on the same.
Thanks
Angie
to answer your first question - you're able to get a deeper insight into the xwork action mappings, interceptors and possible result types if you're taking a look at confluence-core/confluence/src/etc/java/xwork.xml.
The following example is the corresponding mapping for your "doeditspace.action":
<action name="doeditspace" class="com.atlassian.confluence.spaces.actions.EditSpaceAction" method="doEdit">
<param name="RequireSecurityToken">true</param>
<result name="error" type="velocity">/spaces/editspace.vm</result>
<result name="input" type="velocity">/spaces/editspace.vm</result>
<result name="cancel" type="redirect">viewspacedetails.action?key=${key}</result>
<result name="success" type="redirect">viewspacedetails.action?key=${key}</result>
</action>
So if the return value from your execute method is ActionType.SUCCESS or "success", the request will be redirected to the viewspacedetails action.
Additional information is documented in the Atlassian Developer Website:
https://developer.atlassian.com/display/CONFDEV/XWork-WebWork+Module

Modify Wicket FormComponent markup without panel?

In Wicket, I'd like to subclass TextField form component to add additional markup around the tag.
Why I do not want to create a Panel:
1) I want the web page designer to use the input tag:
<input wicket:id="blah">
2) I don't want the subclass to lose the FormField semantics in Java, e.g.:
field.setRequired(true);, etc.
I'm fine with hard-coding the wrapping markup in Java. But I'd like this to behave like a FormField in Java.
Any ideas? Looked around for examples, but stumped on this one
Edit:
I'm aware of Borders, but my issue with them is you have to add them in both the markup and in Java. For example:
<div wicket:id="border">
<input type="text" wicket:id="field"/>
</div>
--
FormComponent<Integer> field = new TextField<Integer>("field", new Model(1));
field.setRequired(true);
Border border = new MyBorder("border");
border.add(field);
form.add(border);
This makes the web page designer have to be aware of special markup, and the Java can't be encapsulated (as a FormField subclass).
Ah, this is what I wanted via IBehavior:
My wrapper behavior (sorry for the Scala syntax):
class FieldWrapper extends AbstractTransformerBehavior {
def transform(component: Component, output: CharSequence): CharSequence = """
<div class="blah">
Blah blah blah
%s
</div>
""".format(output)
}
My subclass:
class MyField[T](id: String, model: IModel[T]) extends TextField[T](id, model) {
add(new FieldWrapper)
}
Original Markup:
<input type="text" wicket:id="foobar"/>
Generated markup:
<div class="blah">
Blah blah blah
<input type="text" value="" name="foobar" xmlns:wicket="http://wicket.apache.org">
</div>
Thanks S.O. for jumpstarting my mind :-)
You wouldn't even need to subclass TextField. although it might be easier to to so if you want to reuse it. If you just want to add markup outside of the original tag, it's the poster use case for a Border.
If digging into the rendering of a Component is needed
MarkupContainer#onRender()
is your friend.
An example might be:
AbstractTree#onRender()
mf