How to mix html with gwt widgets? - java

I try to generate a dynamically gwt ui. As a result I would get a html fragment like this:
<ol>
<li>MyLabel</li>
<li><input type="text"></li>
</ol>
The Label should be a GWT Label and the input should be a GWT TextBox.
How can I achieve this with GWT? I've tried to use the HTMLPanel class, but how can I inject the
<li>
Tags?
I can't use UIBinder, since I would like to dynamically create such fragments as shown above.

You should create your own subclass of ComplexPanel. This will give you something that works much the same as a HorizontalPanel or VerticalPanel, only based on list elements rather than table elements. It should look something like this:
public class OListPanel extends ComplexPanel {
final OListElement ol = Document.get().createOLElement();
public OListPanel() {
setElement(ol);
}
public void add(Widget w) {
LIElement li = Document.get().createLIElement();
ol.appendChild(li);
add(w, (Element)li.cast());
}
public void insert(Widget w, int beforeIndex) {
checkIndexBoundsForInsertion(beforeIndex);
LIElement li = Document.get().createLIElement();
ol.insertBefore(li, ol.getChild(beforeIndex));
insert(w, (Element)li.cast(), beforeIndex, false);
}
public boolean remove(Widget w) {
Element li = DOM.getParent(w.getElement());
boolean removed = super.remove(w);
if (removed) {
ol.removeChild(li);
}
return removed;
}
}
I haven't tested that but it's basically right. WRT the markup you posted in your question, this code will produce one slight difference, since GWT labels have their own <div> element:
<ol>
<li><div>MyLabel</div></li>
<li><input type="text"></li>
</ol>
You might prefer InlineLabel, which is based on the less intrusive <span> element.

You can always do something like:
Document doc = Document.get();
final OListElement ol = doc.createOLElement();
LIElement li = doc.createLIElement();
li.appendChild((new Label()).getElement());
ol.appendChild(li);
li = doc.createLIElement();
li.appendChild((new TextBox()).getElement());
ol.appendChild(li);
panel.add(new Widget() {{
setElement(ol);
}});

Why not put that fragment in a standalone Widget created via UiBinder? (if you know how the structure will look beforehand and just want to insert MyLabel and a TextBox)
Don't be afraid to split your widgets like this - the GWT Compiler is great at optimizing and UiBinder templates are processed at compile time so there shouldn't be any performance penalty (benchmarking is still strongly recommended - YMMV). I'd even say that it'd be faster then trying to add this structure via the DOM package - with UiBinder, the compiler knows what it's dealing with, with DOM you are basically saying: "I know what I'm doing, don't touch my code!" (at least that's my view on this :)). HTMLPanel could be an alternative, but you'd have to assign an id to every element you want to modify/attach stuff to... :/
Bottom line: use UiBinder for this, that's what it was built for.

Related

Webdriver: find element by html tag which contains an html tag which belongs to a certain class

to clarify a really messy title:
There is a piece of page code that looks like this (I have simplified the actual code):
<div class="CLASS1">
<p>...
<p>
<strong>
<i CLASS2 "></i>
THE DATA I WANT
</strong>
</p>
<p>...
<p>...
</div>
I am using Selenium Webdriver with Java and I've been trying to get the "DATA I WANT" line, but since it is contained between tags (and not the CLASS2 italic tag), I am having hard time accomplishing this. Note that the rest of the paragraphs (marked as <p>...) contain the analogous constructions.
Currently it seems like searching for a CLASS1 <strong> tag that contains CLASS2 element <i> might be the solution, but I have not been able to compose a correct search path so far. Now I am not sure if I am approaching this problem from a correct angle at all.
Any suggestions are greatly aprpeciated! I would like to have the shortest and the most reliable solution for this...
For the HTML you have posted. Following CSS selector should work.
div.CLASS1 > p:nth-child(2) > strong
If you need to get the the strong tag that contains i.CLASS2 then you could do something like this.
// get all p tags
List<WebElement> pTags = driver.findElements(By.cssSelector("div.CLASS1 > p"));
WebElement myWebElement = null;
// iterate and find p tag that contains i.CLASS2
for (WebElement element : pTags) {
if (element.findElements(By.cssSelector("i.CLASS2")).size() == 1) {
myWebElement = element.findElement(By.cssSelector("strong"));
break;
}
}
// the data you want
System.out.println(myWebElement.getText());

GWT FocusPanel clickHandler not working when created with a element

Hello fellow GWT folks.
In my usage of GWT, I'm having an issue with a FocusPanel not handling the clickEvent that is added to it. I don't do GWT the standard way, ie building the GUI with UI binder or pure java code widgets. My host GWT HTML file is 1 large file that has div tags that represent the 'pages' of content. I use GWT to control the DOM.
I have this HTML that I'm importing as the contents of the FocusPanel.
<div id="editCardsResponses">
<div id="editCardsSuccess" class="success-box clickable">
<span id="editCardsSuccessLabel">Your card was successfully deleted/edit/added.</span>
<span class="glyphicon glyphicon-remove"></span>
</div>
...
</div>
Here's the Code...
RootPanel editCardsSuccess = RootPanel.get("editCardsSuccess");
FocusPanel editCardsSuccessPanel = new FocusPanel(editCardsSuccess);
editCardsSuccessPanel.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
hideWidget(editCardsSuccessPanel);
}
});
This didn't work until I did this...
final HTMLPanel editCardsSuccess = view.getEditCardsSuccess();
editCardsSuccess.addDomHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
hideWidget(editCardsSuccess);
}
}, ClickEvent.getType());
I even tried adding the FocusPanel to the parent DIV, thinking that the FocusPanel wasn't attached to the DOM, but that also didn't work.
RootPanel.get("editCardsResponses").add(editCardsSuccessPanel);
I would like to use the FocusPanel, as GWT wants to add a hidden input the DOM, in addtion to the element it wraps. I assume the hidden input handles some cross browser issue that I might lose if I just use the domHandler method.
Can anyone help explain why the FocusPanel.ClickHandler wouldn't be taking effect, but an attached domHandler would?
If DOM attachment is the problem, Is there a way to re-attach elements/widgets that were detached?
If I go with the domHandler way... what compatibility do I loose by not getting the hidden input that the GWT FocusPanel widget provides?
Add DOM ONCLICK handler event on the Element.
sample code:
final Element desc = RootPanel.get("editCardsSuccess").getElement();
DOM.sinkEvents((com.google.gwt.user.client.Element) desc, Event.ONCLICK);
DOM.setEventListener((com.google.gwt.user.client.Element) desc, new EventListener() {
#Override
public void onBrowserEvent(Event e) {
switch (DOM.eventGetType(e)) {
case Event.ONCLICK:
System.out.println("click");
break;
}
}
});
There is nothing wrong with adding a DOM handler the way you described. It will work across all browsers.

Exception while adding a widget to iframe?

I am using GWT. have below code in my host page.
<div id="mainDiv"/>
<iframe id="__printingFrame" style="width:0;height:0;border:0"> </iframe>
in EntryPoint's onModuleLoad() i have below code:
#Override
public void onModuleLoad() {
RootPanel.get("mainDiv").add(new SomePage());
}
in one of the methods of SomePage.java i am doing:
RootPanel rootPanel = RootPanel.get("__printingFrame");
rootPanel.add(new Html(" "));//adding some widget
But bcaz of above line i am getting below exception. Am i missing anything here?
java.lang.AssertionError: A widget that has an existing parent widget may not be added to the detach list
at com.google.gwt.user.client.ui.RootPanel.detachOnWindowClose(RootPanel.java:136)
at com.google.gwt.user.client.ui.RootPanel.get(RootPanel.java:211)
Thanks!
There are 2 issues in your code (but you're only seeing one for now):
You cannot have nested RootPanels (see http://code.google.com/p/google-web-toolkit/issues/detail?id=3511 and http://code.google.com/p/google-web-toolkit/issues/detail?id=3528), this is what's causing the error you're seeing
You cannot add widgets to an iframe. Well, wrapping it within a RootPanel, technically, you could, but they'd be added as children of the iframe element, so they wouldn't be visible to your users (I cannot think of a single browser that interprets JavaScript but doesn't support iframes).
RootPanel.get("id") can only get <div> element.you can wrap existed element like that.
Frame frame=Frame.wrap(DOM.getElementById("__printingFrame"));

Which is the best Wicket component for rendering arbitrary HTML?

I am implementing a simple markdown wiki using Apache Wicket. The wiki would typically render any arbitrary HTML based on what the user has entered.
I am a bit confused about which Wicket component would be best suited to render such arbitrary HTML.
I tried the Label component but it does not render lists properly, neither does the MultilineLabel (which puts breaks instead of the regular list HTML).
Thanks for any help.
UPDATE: The Label component works perfectly. It was my mistake that I was not able to get it to work earlier. It was a combination of some bad stylesheets and late night coding. Thanks for the helpfull answers. As suggested, I am also going to check out some WYSIWYG editors, which actually might work out better than markdown. Visural Wicket seems especially promising.
If what you want to render is not big, or is already represented as a String, Label will work well, just call label.setEscapeModelStrings(false); to ensure it prints the string as is.
But, if your HTML content is generated dynamically, or read from an InputStream/Reader, and you don't want to keep it in memory, you could use WebComponent directly, and override the method onComponentTagBody(). This way, you write directly to the response, instead of filling a in-memory buffer, transform it to a String, and then write to the response (which happens if you use Label).
Sample code, for both cases:
HomePage.java
public class HomePage extends WebPage {
public HomePage() {
add(new Label("label", "<ul><li>test</li><li>test</li><li>test</li><li>test</li><li>test</li></ul>")
.setEscapeModelStrings(false));
add(new WebComponent("html") {
#Override
protected void onComponentTagBody(MarkupStream markupStream, ComponentTag openTag) {
Response response = getRequestCycle().getResponse();
response.write("<ul>");
for (int i = 0; i < 5; i++)
response.write("<li>test</li>");
response.write("</ul>");
}
});
}
}
HomePage.html
<html xmlns:wicket="http://wicket.apache.org">
<body>
<h2>Label</h2>
<div wicket:id="label"></div>
<h2>WebComponent</h2>
<div wicket:id="html"></div>
</body>
</html>
It is Label, call Component.setEscapeModelStrings(false) though to render the raw html your model returns.

HTMLDocument: does Swing "optimize out" span elements?

I'm messing about with HTMLDocument in a JTextPane in Swing. If I have this situation:
<html>...
<p id='paragraph1'><span>something</span></p>
<span id='span1'><span>something else</span></span>
...</html>
(the extra <span> tags are to prevent Swing from complaining that I can't change the innerHTML of a leaf) or this situation
<html>...
<p id='paragraph1' />
<span id='span1' />
...</html>
I can call HTMLDocument.getElement() and find the element with ID 'paragraph1' but not the element with id 'span1'. If I change the tag for 'span1' from "span" to "p" then I'm fine. WTF is going on here? Is there another HTML element I can use instead that will allow me to access a particular portion of the document using the id attribute, that will not cause linebreaks? (span would have been perfect :( argh!)
edit: I think the solution is to re-examine what I'm trying to do, which was to leverage the fact that I know how to make GUIs + tables + displays in HTML a lot more than I do in Swing, so I'll ask a different question....
I don't know Swing, but
<p style="display: inline;"> does not line-break, the same as <span>
I have exactly this problem. My span elements disappear.
Whereas if i used div i can see them. But of course I don't want div elements, because it causes a line break.
Damn it! Damn java.
Edit!
STOP THE PRESS!!
Found the answer. At least, an answer which fixes it for me.
I was still able to determine that I had my span element. I will describe what I am doing, an d provide the code to how i did it.
I want to know what element the caret is in. So, this code exists within the caretUpdate function, which provides me with the caret position each time it moves.
#Override
public void caretUpdate(CaretEvent e)
{
System.out.println("caret event: " + e.toString());
Object source = e.getSource();
if (source instanceof JEditorPane)
{
JEditorPane jep = (JEditorPane)source;
Document doc = jep.getDocument();
if (doc instanceof HTMLDocument)
{
HTMLDocument hdoc = (HTMLDocument)doc;
int pos = e.getDot();
Element elem = hdoc.getCharacterElement(pos);
AttributeSet a = elem.getAttributes();
AttributeSet spanAttributeSet = (AttributeSet)a.getAttribute(HTML.Tag.SPAN);
// if spanAttributeSet is not null, then we properly found ' a span '.
// now we need to discover if it is one of OUR spans
if (spanAttributeSet!=null)
{
Object type = spanAttributeSet.getAttribute(HTML.Attribute.TYPE);
if (type !=null && type.equals("dragObject"))
{
// for our logging, we get the ref, which holds the source
// of our value later
System.out.println("the value is: " + spanAttributeSet.getAttribute("ref"));
}
}
}
}
}
Edit!!!
Scratch that... This almost works... except the idiots at Sun decided the key was going to be of type HTML.Attribute. Not only that, that the constructor for the HTML.Attribute is private, and it just so happens that the attribute type that I wanted doesn't exist within their privileged set of attributes. Bastards!
So, all is not lost... I can still get it via the enumerator.. but it is a little more difficult than it needed to be.
LAST EDIT!
Ok, I get it now. If the attribute is of a known type, it is stored in the AttributeSet as an instance of HTML.Attribute("type").
Otherwise, it is stored in the AttributeSet with a 'String' as the key.
Stupid. But i've got there.
I took a look at the javadoc for HTMLDocument, which pointed me to HTMLReader.
I don't see any mention of span in HTMLReader. Maybe it just doesn't know that element.
P probably isn't a good replacement for span. P is a block-level element and span is a text-level element (see description of those terms). Maybe try font (another text-level element) with no attributes?

Categories