Getting the internal DIV element and id of a GWT Panel - java

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!

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()
}-*/;

GXT - send forms on enter, project-wide

I have an application which uses GXT and contains ±30 forms. I would like to make these forms so that when the user hits enter in a text field, the form gets submitted, like a regular browser form would.
I know I can add a key press listener to every text field, which would invoke the submit after enter is pressed, but since I want to apply this to every field in every form I am not sure if this is ideal.
Is there a simpler way to implement this in the entire application?
If not, which pattern should I use to add this functionality to every field? I can extend the TextField class, add the functionality in the child class and use the child class in the application. Or I can create a factory for the text field class which would also add the listener to the field. Or is there some other way, Decorator perhaps? I was wondering which of these approaches, if any, is generally preferred.
I would try something like this:
Event.addNativePreviewHandler(new NativePreviewHandler() {
#Override
public void onPreviewNativeEvent(NativePreviewEvent event) {
if (event.getNativeEvent().getKeyCode() == KeyCodes.KEY_ENTER) {
if (event.getNativeEvent().getEventTarget() != null) {
Element as = Element.as(event.getNativeEvent().getEventTarget());
if (as.getTagName().toLowerCase().equals("input") ||
as.getTagName().toLowerCase().equals("textarea")) {
// TODO submit data;
}
}
}
}
});
Every time someone hits the Enter Key and the cursor is placed on a input- or textarea-tag, you will get the control and can submit your data.
I don't think there is a way to do what you're asking directly in the GXT library. I do want to stress that extending the TextField class just to add an event handler to it is not the correct way to handle this. Event handlers are based on the composition of a class. It would be like extending a class with a List field just to add another element into the list.
A singleton factory class that created and initialises the Textfield for you would be the cleanest solution, in my opinion. It would allow you to effectively change defaults and add other handlers as required at a later time in a single place if requirements change.
You can try it with GWT JSNI also.
Steps to follow:
define a function in JavaScript that is called on Enter key press
call GWT JSNI from above JavaScript function that is exported at the time of onModuleLoad using GWT JSNI
get the Element from where this event is triggered and finally submit the form based on its tag name or Id
Sample code:
HTML/JSP:
<script>
window.onkeydown = keydown;
function keydown(event) {
if (event.which == 13) {
formSubmit(event.target);
}
}
</script>
JAVA(Entry Point):
import com.google.gwt.dom.client.Element;
public void onModuleLoad() {
exportFormSubmit();
...
}
public static void formSubmit(Element element) {
Window.alert("element tag name:" + element.getTagName() + "form ID:"
+ element.getParentElement().getId());
}
public static native void exportFormSubmit() /*-{
$wnd.formSubmit = $entry(#com.x.y.z.client.GWTTestProject::formSubmit(Lcom/google/gwt/dom/client/Element;));
}-*/;

Loading HTML templates via Ajax from Google Web Toolkit?

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.

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