Loading HTML templates via Ajax from Google Web Toolkit? - java

For my gwt app, I have certain html templates that are stored as static .html files on my website. e.g example.com/views/signup.html , example.com/views/foo.html , etc.
I want this to be a single page app like Twitter, so the user would navigate through all the pages without the page being refreshed.
I will have a HTMlPanel as the root element of my app on the host page. Whenever the user navigates to a different page, e.g by clicking a link in the navigation menu, I want to load the .html template for that page via ajax, and set the returned html into the HTMLPanel.
Is this a plausible solution? If so, how can I load the html templates via ajax from GWT?
Thanks.

That is precisely the case of http://gwtproject.org site.
It uses gwtquery to load an html page via ajax and insert it in a certain area of the page via the load() method.
// Load the file.html using ajax, and append the fragment with id=mid from
// the returned document inside the element with id=c in the current document.
$("#c").load("file.html #mid");
You can take a look to the GWTProjectEntryPoint.java (line 128) of the gwt-site-webapp as well.
Of course you have to handle any click on any anchor present in the inserted fragment, to do the appropriate action instead of replacing the gwt application. That can be done with the live() method of gQuery.
$("#c").live("click", new Function() {
public boolean f(Event e) {
String href = $(e).attr("href");
// Do something with href.
return false;
}
});

You may want to look at this SO Q&A.
The idea is:
You create a server call (e.g., RPC) to fetch your html template as a String.
You create a corresponding HTMLPanel that knows how to attach dynamic elements to your html template that you pass in the constructor.
You add this newly constructed HTMLPanel to your page root panel where you want it.
On this SO you can find a panel template code that may help you. The version therein does not have the "dynamic" html source, instead it is hard-coded in a ClientBundle. But it is easy to extend so the source html is dynamic, simply add a construtor like:
public HtmlPanelBase(final String htmlContentAsText)
where htmlContentAsText is your template html String from your server as follows:
public class HtmlPanelBase extends Composite
{
private String _dynPostfix = "";
protected final String id(final String staticId) { return staticId + _dynPostfix; }
private final String wrapId(final String id) { return "id=\"" + id + "\""; }
private final String wrapDynId(final String refId) { return wrapId(id(refId)); }
private String _htmlContentAsText = null;
protected String getHtmlContentAsText() { return _htmlContentAsText; }
private ArrayList<String> _idList = null;
protected HTMLPanel _holder = null;
private HTMLPanel createHtmlPanel(final boolean defineGloballyUniqueIds)
{
// HTML panel text containing the reference id's.
if (defineGloballyUniqueIds)
{
// Replace the reference id's with dynamic/unique id's.
for (String refId : _idList)
_htmlContentAsText = _htmlContentAsText.replace(wrapId(refId), wrapDynId(refId));
}
// Return the HTMLPanel containing the globally unique id's.
return new HTMLPanel(_htmlContentAsText);
}
public HtmlPanelBase(final String htmlContentAsText, final ArrayList<String> idList, final boolean defineGloballyUniqueIds)
{
_htmlContentAsText = htmlContentAsText;
_idList = idList;
this.setup(defineGloballyUniqueIds);
super.initWidget(_holder);
}
public HtmlPanelBase(final String htmlContentAsText)
{
this(htmlContentAsText, null, false);
}
private void setup(final boolean defineGloballyUniqueIds)
{
if (defineGloballyUniqueIds)
_dynPostfix = "_" + UUID.uuid().replace("-", "_");
_holder = createHtmlPanel(defineGloballyUniqueIds);
}
}
To use, fetch your htmlContentAsText on sever (could depend upon locale), upon success instantiate a derived class of the above base template passing the fetched htmlContentAsText in the constructor, and add therein all your logic modifying or adding upon the base html -- e.g., add handlers in response to user actions.

Related

How to print some elements in gwt

I want to print one panel of page in GWT.
However someone said that you must use iframe because it has print method.
I tried this code but it does not work:
HTML html=new HTML("<iframe id="myframe"></iframe>") ;....
searchButton.setWidth("80px");
searchButton.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
MyNative.printIframeContent("myframe", "onlineMap");
}
});
map = new SimplePanel();
map.getElement().setId("onlineMap");
map.add(mapView.getMapWidget());
mapView .is an instance of a class that returns a GWT MapWidget and in this manner I want to add GWT map to iframe then use print capability of iframe to print google map
MyNative is a class that use GWT JSNI to call the printPage javascript function
function printPage(idMap,idFrame) {
var myElement = document.getElementById(idMap);
var iframe = document.getElementById(idFrame);
var body = iframe.getElementsByTagName('body');
body.innerHTML = myElement;
iframe.contentWindow.print();
}
but browser can not load body of iframe.
You can try this:
String html = myPanel.getElement().getInnerHTML();
print(html);
public static final native void print(String html) /*-{
top.consoleRef=$wnd.open('','_blank', "");
top.consoleRef.document.write(html);
top.consoleRef.print();
top.consoleRef.document.close()
}-*/;

How can i get GWT HTML selected text?

i needed an Widget to display text properly, containing HTML elements. Therefore i used the GWT HTML-Widget like that.
HTML text= new HTML(new SafeHtml() {
#Override
public String asString() {
return "<b>TestText</b>";
}
});
Now i would like to select text displayed by that widget, and somehow get the String.
I would like to right click the marked text, and do something with that String
It's also no problem if your ideas making use of other gwt widgets, i am not too focused on that HTML one.
I also have access to Sencha GXT libarys.
Any ideas would be appreciated.
I'm assuming you want the user to select text and then retrieve the selected text on right click. Am I right? I don't recall any way of retrieving selected text in GWT, so I would use pure javascript for that. There is already a thread explaining how to do that with javascript, so you can grab that code and wrap it in a JSNI method:
public class MyClass implements IsWidget {
private final HTML text;
public MyClass() {
text = new HTML(SafeHtmlUtils.fromTrustedString("<b>Some text</b>"));
text.addDomHandler(new ContextMenuHandler() {
#Override
public void onContextMenu(ContextMenuEvent event) {
String test = getSelection();
Window.alert(test);
}
}, ContextMenuEvent.getType());
}
private native String getSelection() /*-{
var text = "";
if ($wnd.getSelection) {
text = $wnd.getSelection().toString();
} else if ($doc.selection && $doc.selection.type != "Control") {
text = $doc.selection.createRange().text;
}
return text;
}-*/;
#Override
public Widget asWidget() {
return text;
}
}
You can use sth like this:
final Label label = new Label("Some text");
label.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
label.getElement().getStyle().setBackgroundColor("#ff0"); //sth. like select
String txt = label.getText(); //get the String
Window.alert(txt); //do sth. with text
}
});
But it works on left click. If you have to use right click, you can use native JS code using eg. jQuery click.
And do not use b tag. It is deprecated in HTML5.
I've actually found a GWT-Libary that can get the selected text.
Watch this https://code.google.com/p/gwt-selection/
After installing the libary i just had to
String currentSelection = Selection.getBrowserRange().getText();
Thank you for answering though - you helped me a lot

Getting the internal DIV element and id of a GWT Panel

I have an app that have this JSNI that needs to be passed with a container id, in which I pass a DIV id:
HTML:
<div class='example-waveform' id='example4'></div>
JAVA:
initWave("example4");
public native void initWave(String __id)/*-{
var instance = this;
var data = $wnd.data = [];
var waveform = $wnd._waveform = new $wnd.Waveform({
container: $doc.getElementById(__id),
interpolate: false
});
}-*/;
This works fine, however I need to use a GWT container instead of just a HTML div.
I tried:
HTMLPanel container = new HTMLPanel("Test");
container.getElement().setId("someid");
String id = container.getElement().getId();
initWave(id);
However the Javascript function can't accept the element id I am passing into it (I am using a third-party JS Library so I can't debug this one) so I just assume that I just need to pass a DIV id, however DIV is OK, but I need a GWT widget that I can manipulate like show/hide/etc in the GWT UI.
In this case, is there a way to get the DIV element and id of a GWT Panel (HTMLPanel or VerticalPanel) so I can pass this onto my JSNI function.
It must be some error related to the order you are calling the methods, or in the use of the 3rd party lib. This code works perfectly fine in GWT 2.4.0.:
final HTMLPanel container = new HTMLPanel("Test");
container.getElement().setId("someid");
container.addAttachHandler(new Handler() {
#Override
public void onAttachOrDetach(AttachEvent event) {
initWave(container.getElement().getId());
}});
RootPanel.get().add(container);
with initWave being:
public native void initWave(String __id)/*-{
var x = $doc.getElementById(__id);
alert(x.innerHTML);
}-*/;
Works both with SimplePanel and HTMLPanel!

Wicket: make a generated csv available to a dygraphs JavaScript

I'm trying to figure out how to make a dynamically generated csv available to a dygraphs JavaScript.
I'm using a wicket behavior to add the dygraph (JavaScript graph) to my markup like shown in the codesample bellow. Right now I've hardcoded it to use a csv file named "dygraph.csv". I want to change this, and instead make dygraph use the values from String csv, how do I achieve this?
Any help help is greatly appreciated.
public class DygraphBehavior extends AbstractBehavior {
private static final long serialVersionUID = -516501274090062937L;
private static final CompressedResourceReference DYGRAPH_JS = new CompressedResourceReference(DygraphBehavior.class, "dygraph-combined.js");
#Override
public void renderHead(IHeaderResponse response) {
response.renderJavascriptReference(DYGRAPH_JS);
}
#Override
public void onRendered(Component component) {
final String id = component.getId();
Response response = component.getResponse();
response.write(JavascriptUtils.SCRIPT_OPEN_TAG);
response.write("new Dygraph(document.getElementById(\""+id+"\"), \"dygraph.csv\", {rollPeriod: 7, showRoller: true, errorBars: true});");
response.write(JavascriptUtils.SCRIPT_CLOSE_TAG);
}
}
public class Dygraph extends WebPage {
public Dygraph() {
String csv = "Date,ms\n20070101,62\n20070102,62";
add(new ResourceLink<File>("csv", new ByteArrayResource("text/csv", csv.getBytes())));
add(new Label("graphdiv").add(new DygraphBehavior()));
}
}
<div>
<h1>Dygraph:</h1>
<div wicket:id="graphdiv" id="graphdiv" style="width:500px; height:300px;"></div>
<a wicket:id="csv" href="#">dl generated csv</a>
</div>
public class Dygraph extends WebPage {
public Dygraph() {
String csv = "Date,ms\n20070101,62\n20070102,62";
ResourceLink<File> link = new ResourceLink<File>("csv", new ByteArrayResource("text/csv", csv.getBytes()));
add( link );
//this is the url that should be passed to the javascript code
CharSequence url = link.urlFor( IResourceListener.INTERFACE );
add(new Label("graphdiv").add(new DygraphBehavior()));
}
}
There are other solutions based on the scope of your resource, maybe a dynamic shared resource would work better (if your graph parameters can simply be passed as url parameters), but this will work.
The JavaScript needs to see the data in some way after the page has been rendered. So you have two options:
Embed the data in the page (say in a hidden div) and then let JavaScript read the data from there as text.
Create a servlet where the JavaScript can download the data from.
The second option means that your page rendering code has to pass the data somehow to the servlet. You can try to put it into the session but then, it will sit there, occupying RAM. Probably not a problem if it's just a little bit of data and you have only a few users. But if that's not true, option #1 is probably better.

How can I replace a div with a widget when it is already contained in another widget?

I'm using Ext-GWT and I think ListView is the right layout for what I need. My problem is that I have to use a HTML template for all of my items, but I want to build GWT/Ext-GWT widgets instead, so I'm using div placeholders that I will replace with the proper widgets.
How can I replace my div with a widget? My first attempt was to use RootPanel.get('div-id'), but apparently you can't create a RootPanel that is in a widget (I used debug mode to step through the code till I found that silent exception).
public class TicketContainer extends LayoutContainer {
private ArrayList<BasicTicket> tickets;
public TicketContainer(ArrayList<BasicTicket> tickets) {
this.tickets = tickets;
}
#Override
protected void onRender(Element parent, int index) {
super.onRender(parent, index);
setLayout(new FlowLayout(1));
ListStore<BasicTicket> store = new ListStore<BasicTicket>();
store.add(this.tickets);
ListView<BasicTicket> view = new ListView<BasicTicket>(store);
view.addListener(Events.Refresh, new Listener<BaseEvent>() {
#Override
public void handleEvent(BaseEvent be) {
for (BasicTicket ticket : tickets) {
// At this point I need to find the div with the id
// "ticket_"+ticket.getId() and replace it with a GWT
// widget that I can add events to and enable drag and drop
}
}
});
add(view);
}
private native String getTemplate() /*-{
return ['<tpl for=".">',
'<div id="ticket_{id}"></div>',
'</tpl>'].join("");
}-*/;
}
The full source is at https://code.launchpad.net/~asa-ayers/+junk/Kanban if you need additional context in the code.
In "pure" GWT, the answer would be to use HTMLPanel:
String id = DOM.createUniqueId();
HTMLPanel panel = new HTMLPanel("<div class=\"content\" id=\"" + id + "\"></div>");
panel.add(new Label("Something cool"), id);
As you can see, the com.google.gwt.user.client.ui.HTMLPanel.add(Widget, String) takes the id of an element withing the HTMLPanel and places the Widget inside that element.
I haven't used Ext-GWT, but you can either use HTMLPanel or search for an exquivalent in Ext-GWT.
You can also wrap an existing div in an HTML Panel.
HTMLPanel newPanel = HTMLPanel.wrap(Document.get().getElementById("yourDivId"));
newPanel.add(your_widget);

Categories