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.
Related
I have a simple application structure that will contain three composites at any one time - my header, footer and content composites. The composites are laid out in the follow manner.
<body>
<div id="header">
<div id="content">
<div id="footer">
</body>
The composites are assigned to the three <div>'s in my EntryPoint. The EntryPoint also contains a History Handler as follows.
History.addValueChangeHandler(new ValueChangeHandler<String>() {
#Override
public void onValueChange(ValueChangeEvent<String> event) {
String historyToken = event.getValue();
if(historyToken.isEmpty()) {
parseTokens();
ContentContainer.INSTANCE.setContent(new IndexScreen());
}
else if(historyToken.equalsIgnoreCase("registration")) {
ContentContainer.INSTANCE.setContent(new RegisterScreen());
}
else if(historyToken.equalsIgnoreCase("login")) {
ContentContainer.INSTANCE.setContent(new LoginScreen());
}
}
});
History.fireCurrentHistoryState();
In my Composites, I have several ClickEvent handlers that look similar to the following.
#UiHandler("registerLink")
public void handleClick(ClickEvent event) {
ContentContainer.INSTANCE.setContent(new RegisterScreen());
History.newItem("registration", true);
}
This registers the history very nicely. It also brings me to the appropriate pages when I click the back button. However, it has the very odd effect of focusing the browser on the content composite, with the effect of the browser being scrolled to the bottom. It's not a deal breaker but it kind of breaks the user experience a little. (Do let me know if the explanation isn't clear, I'll add images)
What exactly is causing this and how can I fix it?
GWT history tokens work with the hash # token. In html this was originally intended to use the browser to focus on a specific part of the page, if an element has a name or id with the string after the # token. Could it be you have an id matching your history token?
Also in you handleClick you call setContent. But if I'm correct the call after it triggers a change event and will end up in the onValueChange, which also calls the setContent. So it looks like you are calling setContent twice here.
I just faced an interesting thing concerning HTML widget. The thing is...
If a word length is too long per line then HTML widget becomes wider to have it all placed in
so my question is... is it possible to make HTML widget to cut by pieces long words not to getting wider itself?
Comparing to Swing, I mean the effect something like JTextArea does when word wrapping is off (see image)
EDIT
I tried to use css word-break: break-all; here is the code:
composite code:
public MyTestUI(){//constructor
html.setStyleName("my-test");
}
public void setLongWord(String word)//method
{
html.setHTML(word);
}
css
.my-test {
color:gray;
font-family:verdana;
white-space: normal;
word-break: break-all;
}
... the css works in Chrome but doesn't in FF :( How to make the word breaking the crossbrowser one ?
GWT version 2.3
Any useful comment is much appreciated
Use CSS property word-wrap:break-word as described in following link. This will work even if the HTML widget is having static height and width.
http://www.w3schools.com/cssref/css3_pr_word-wrap.asp
Use CSS property word-break:normal; or try word-break:hyphenate;
Add a CSS style to your HTML widget to break long words:
http://www.w3schools.com/cssref/css3_pr_word-break.asp
EDIT:
I stay corrected: word-wrap is a better option. See more:
What is the difference between "word-break: break-all" versus "word-wrap: break-word" in CSS
I'm using jmesa in Java directly using the tableModel.render() to get the HTML directly. Some of my web objects in my result lists contain HTML - example:
class blah {
String email;
public String getEmailLink() {
return "<a href='" + email + "</a>"
}
}
In my Java code I would just do this:
htmlRow.addColumn(new HtmlColumn("emailLink"));
jmesa is rendering this as text. How can I tell jmesa to render the text as-is to be html in the document?
TIA
Looking at the JMesa soure code, HtmlCellEditor automatically escapes HTML.
I haven't tested it, but you should be able to override the default HtmlCellEditor with a different type... such as the bare-bones BasicCellEditor. It shouldn't be too much extra code:
HtmlColumn emailLinkColumn = new HtmlColumn("emailLink");
emailLinkColumn.setCellEditor(new BasicCellEditor());
htmlRow.addColumn(emailLinkColumn);
Another option to all of this is to create a custom CellEditor and have it create your <a> tag for you instead of doing it in your bean. This page should get you started with custom CellEditors if you want to go that route.
BTW, if you are messing with just a value inside of a cell, overriding/replacing CellEditor is probably all you need (CellEditor it is analogous to the body of a <td>). CellRenderer is concerned with the entire cell (analogous to the <td> as well as its contents).
Use a HtmlCellRenderer as shown in this tutorial.
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.
I use sitemesh for page decoration in my web app.
I have a form where the contents of a textarea field is a complete html page.
The problem is that when Sitemesh parses this page it extracts the title, head and body from my textarea field and decorates the page with it.
<textarea name="page_content">
<!-- tags below should not be parsed by Sitemesh -->
<html>
<head>...</head>
<body>...</body>
</html>
</textarea>
It seems that the Sitemesh page parser does care that it has already seen these tags in the page.
Do you have any ideas on how to prevent Sitemesh from parsing the content of the textarea?
I solved it myself. The solution is self evident when you examine the source code for HTMLPageParser
The trick is to write a custom PageParser that adds a new state with its own set of rules i.e no rules at all:
public class CustomPageParser extends HTMLPageParser {
#Override
protected void addUserDefinedRules(State html, PageBuilder page) {
super.addUserDefinedRules(html, page);
// Ensure that while in <textarea> tag, none of the other rules kick in.
State textarea = new State();
html.addRule(new StateTransitionRule("textarea", textarea));
}
}
You can't put <tags> inside a textarea. It is completely invalid. Textarea elements are not ‘CDATA elements’ like <script> and <style>, any < you put inside them is real markup and not a string literal.
In practice browsers will usually let you get away with it (until you try to include another textarea inside, of course), but what you should be writing is:
<textarea name="page_content">
<html>
...
</html>
</textarea>