Change-Id: I08099673c5dd0d688d3243e5fd169edb05f046f3tags/7.6.0.alpha7
@@ -55,6 +55,7 @@ import com.vaadin.shared.ui.dd.VerticalDropLocation; | |||
import com.vaadin.ui.declarative.DesignAttributeHandler; | |||
import com.vaadin.ui.declarative.DesignContext; | |||
import com.vaadin.ui.declarative.DesignException; | |||
import com.vaadin.ui.declarative.DesignFormatter; | |||
/** | |||
* <p> | |||
@@ -2232,12 +2233,13 @@ public abstract class AbstractSelect extends AbstractField<Object> implements | |||
} | |||
String itemId; | |||
String caption = DesignFormatter.unencodeFromTextNode(child.html()); | |||
if (child.hasAttr("item-id")) { | |||
itemId = child.attr("item-id"); | |||
addItem(itemId); | |||
setItemCaption(itemId, child.html()); | |||
setItemCaption(itemId, caption); | |||
} else { | |||
addItem(itemId = child.html()); | |||
addItem(itemId = caption); | |||
} | |||
if (child.hasAttr("icon")) { | |||
@@ -2300,10 +2302,10 @@ public abstract class AbstractSelect extends AbstractField<Object> implements | |||
String caption = getItemCaption(itemId); | |||
if (caption != null && !caption.equals(itemId.toString())) { | |||
element.html(caption); | |||
element.html(DesignFormatter.encodeForTextNode(caption)); | |||
element.attr("item-id", itemId.toString()); | |||
} else { | |||
element.html(itemId.toString()); | |||
element.html(DesignFormatter.encodeForTextNode(itemId.toString())); | |||
} | |||
Resource icon = getItemIcon(itemId); |
@@ -22,9 +22,9 @@ import java.util.Collection; | |||
import org.jsoup.nodes.Attributes; | |||
import org.jsoup.nodes.Element; | |||
import org.jsoup.parser.Parser; | |||
import com.vaadin.event.Action; | |||
import com.vaadin.event.FieldEvents.FocusAndBlurServerRpcImpl; | |||
import com.vaadin.event.ShortcutAction; | |||
import com.vaadin.event.ShortcutAction.KeyCode; | |||
import com.vaadin.event.ShortcutAction.ModifierKey; | |||
@@ -35,6 +35,7 @@ import com.vaadin.shared.ui.button.ButtonServerRpc; | |||
import com.vaadin.shared.ui.button.ButtonState; | |||
import com.vaadin.ui.declarative.DesignAttributeHandler; | |||
import com.vaadin.ui.declarative.DesignContext; | |||
import com.vaadin.ui.declarative.DesignFormatter; | |||
import com.vaadin.util.ReflectTools; | |||
/** | |||
@@ -573,14 +574,19 @@ public class Button extends AbstractFocusable implements | |||
public void readDesign(Element design, DesignContext designContext) { | |||
super.readDesign(design, designContext); | |||
Attributes attr = design.attributes(); | |||
String content = design.html(); | |||
setCaption(content); | |||
String content; | |||
// plain-text (default is html) | |||
Boolean plain = DesignAttributeHandler.readAttribute( | |||
DESIGN_ATTR_PLAIN_TEXT, attr, Boolean.class); | |||
if (plain == null || !plain) { | |||
setHtmlContentAllowed(true); | |||
content = design.html(); | |||
} else { | |||
// content is not intended to be interpreted as HTML, | |||
// so html entities need to be decoded | |||
content = DesignFormatter.unencodeFromTextNode(design.html()); | |||
} | |||
setCaption(content); | |||
if (attr.hasKey("icon-alt")) { | |||
setIconAlternateText(DesignAttributeHandler.readAttribute( | |||
"icon-alt", attr, String.class)); | |||
@@ -630,6 +636,10 @@ public class Button extends AbstractFocusable implements | |||
// plain-text (default is html) | |||
if (!isHtmlContentAllowed()) { | |||
design.attr(DESIGN_ATTR_PLAIN_TEXT, ""); | |||
// encode HTML entities | |||
if (content != null) { | |||
design.html(DesignFormatter.encodeForTextNode(content)); | |||
} | |||
} | |||
// icon-alt | |||
DesignAttributeHandler.writeAttribute("icon-alt", attr, |
@@ -108,6 +108,7 @@ import com.vaadin.shared.util.SharedUtil; | |||
import com.vaadin.ui.declarative.DesignAttributeHandler; | |||
import com.vaadin.ui.declarative.DesignContext; | |||
import com.vaadin.ui.declarative.DesignException; | |||
import com.vaadin.ui.declarative.DesignFormatter; | |||
import com.vaadin.ui.renderers.HtmlRenderer; | |||
import com.vaadin.ui.renderers.Renderer; | |||
import com.vaadin.ui.renderers.TextRenderer; | |||
@@ -2273,7 +2274,9 @@ public class Grid extends AbstractFocusable implements SelectionNotifier, | |||
setHtml(cellElement.html()); | |||
} | |||
} else { | |||
setText(cellElement.html()); | |||
// text – need to unescape HTML entities | |||
setText(DesignFormatter.unencodeFromTextNode(cellElement | |||
.html())); | |||
} | |||
} | |||
} | |||
@@ -4981,7 +4984,7 @@ public class Grid extends AbstractFocusable implements SelectionNotifier, | |||
/* | |||
* This method is a workaround for the fact that Vaadin re-applies | |||
* widget dimensions (height/width) on each state change event. The | |||
* original design was to have setHeight an setHeightByRow be equals, | |||
* original design was to have setHeight and setHeightByRow be equals, | |||
* and whichever was called the latest was considered in effect. | |||
* | |||
* But, because of Vaadin always calling setHeight on the widget, this | |||
@@ -6752,7 +6755,8 @@ public class Grid extends AbstractFocusable implements SelectionNotifier, | |||
Object value = datasource.getItem(itemId) | |||
.getItemProperty(c.getPropertyId()).getValue(); | |||
tableRow.appendElement("td").append( | |||
(value != null ? value.toString() : "")); | |||
(value != null ? DesignFormatter | |||
.encodeForTextNode(value.toString()) : "")); | |||
} | |||
} | |||
} |
@@ -31,6 +31,7 @@ import com.vaadin.shared.ui.label.ContentMode; | |||
import com.vaadin.shared.ui.label.LabelState; | |||
import com.vaadin.shared.util.SharedUtil; | |||
import com.vaadin.ui.declarative.DesignContext; | |||
import com.vaadin.ui.declarative.DesignFormatter; | |||
/** | |||
* Label component for showing non-editable short texts. | |||
@@ -585,14 +586,18 @@ public class Label extends AbstractComponent implements Property<String>, | |||
public void readDesign(Element design, DesignContext designContext) { | |||
super.readDesign(design, designContext); | |||
String innerHtml = design.html(); | |||
if (innerHtml != null && !"".equals(innerHtml)) { | |||
setValue(innerHtml); | |||
} | |||
if (design.hasAttr(DESIGN_ATTR_PLAIN_TEXT)) { | |||
boolean plainText = design.hasAttr(DESIGN_ATTR_PLAIN_TEXT); | |||
if (plainText) { | |||
setContentMode(ContentMode.TEXT); | |||
} else { | |||
setContentMode(ContentMode.HTML); | |||
} | |||
if (innerHtml != null && !"".equals(innerHtml)) { | |||
if (plainText) { | |||
innerHtml = DesignFormatter.unencodeFromTextNode(innerHtml); | |||
} | |||
setValue(innerHtml); | |||
} | |||
} | |||
/* | |||
@@ -625,6 +630,7 @@ public class Label extends AbstractComponent implements Property<String>, | |||
// plain-text (default is html) | |||
if (getContentMode() == ContentMode.TEXT) { | |||
design.attr(DESIGN_ATTR_PLAIN_TEXT, ""); | |||
design.html(DesignFormatter.encodeForTextNode(getValue())); | |||
} | |||
} | |||
} |
@@ -33,6 +33,7 @@ import com.vaadin.server.PaintException; | |||
import com.vaadin.server.PaintTarget; | |||
import com.vaadin.shared.ui.optiongroup.OptionGroupConstants; | |||
import com.vaadin.ui.declarative.DesignContext; | |||
import com.vaadin.ui.declarative.DesignFormatter; | |||
/** | |||
* Configures select to be used as an option group. | |||
@@ -276,6 +277,14 @@ public class OptionGroup extends AbstractSelect implements | |||
if (!isItemEnabled(itemId)) { | |||
elem.attr("disabled", ""); | |||
} | |||
if (isHtmlContentAllowed()) { | |||
// need to unencode HTML entities. AbstractSelect.writeDesign can't | |||
// check if HTML content is allowed, so it always encodes entities | |||
// like '>', '<' and '&'; in case HTML content is allowed this is | |||
// undesirable so we need to unencode entities. Entities other than | |||
// '<' and '>' will be taken care by Jsoup. | |||
elem.html(DesignFormatter.unencodeFromTextNode(elem.html())); | |||
} | |||
return elem; | |||
} |
@@ -69,6 +69,7 @@ import com.vaadin.shared.util.SharedUtil; | |||
import com.vaadin.ui.declarative.DesignAttributeHandler; | |||
import com.vaadin.ui.declarative.DesignContext; | |||
import com.vaadin.ui.declarative.DesignException; | |||
import com.vaadin.ui.declarative.DesignFormatter; | |||
import com.vaadin.util.ReflectTools; | |||
/** | |||
@@ -279,7 +280,7 @@ public class Table extends AbstractSelect implements Action.Container, | |||
ICON_ONLY(ItemCaptionMode.ICON_ONLY), | |||
/** | |||
* Row caption mode: Item captions are read from property specified with | |||
* {@link #setItemCaptionPropertyId(Object)}. | |||
* {@link #setItemCaptionPropertyId(Object)} . | |||
*/ | |||
PROPERTY(ItemCaptionMode.PROPERTY); | |||
@@ -2055,7 +2056,9 @@ public class Table extends AbstractSelect implements Action.Container, | |||
} else if (minPageBufferIndex < pageBufferFirstIndex) { | |||
newCachedRowCount -= pageBufferFirstIndex - minPageBufferIndex; | |||
} | |||
/* calculate the internal location of the new rows within the new cache */ | |||
/* | |||
* calculate the internal location of the new rows within the new cache | |||
*/ | |||
int firstIndexInNewPageBuffer = firstIndex - pageBufferFirstIndex | |||
- rowsFromBeginning; | |||
@@ -6199,7 +6202,8 @@ public class Table extends AbstractSelect implements Action.Container, | |||
} | |||
Iterator<?> propertyIt = propertyIds.iterator(); | |||
for (Element e : elems) { | |||
String columnValue = e.html(); | |||
String columnValue = DesignFormatter.unencodeFromTextNode(e | |||
.html()); | |||
Object propertyId = propertyIt.next(); | |||
if (header) { | |||
setColumnHeader(propertyId, columnValue); | |||
@@ -6240,7 +6244,7 @@ public class Table extends AbstractSelect implements Action.Container, | |||
} | |||
Object[] data = new String[cells.size()]; | |||
for (int c = 0; c < cells.size(); ++c) { | |||
data[c] = cells.get(c).html(); | |||
data[c] = DesignFormatter.unencodeFromTextNode(cells.get(c).html()); | |||
} | |||
Object itemId = addItem(data, |
@@ -21,6 +21,7 @@ import org.jsoup.nodes.Element; | |||
import com.vaadin.data.Property; | |||
import com.vaadin.shared.ui.textarea.TextAreaState; | |||
import com.vaadin.ui.declarative.DesignContext; | |||
import com.vaadin.ui.declarative.DesignFormatter; | |||
/** | |||
* A text field that supports multi line editing. | |||
@@ -145,7 +146,7 @@ public class TextArea extends AbstractTextField { | |||
@Override | |||
public void readDesign(Element design, DesignContext designContext) { | |||
super.readDesign(design, designContext); | |||
setValue(design.html()); | |||
setValue(DesignFormatter.unencodeFromTextNode(design.html())); | |||
} | |||
/* | |||
@@ -157,7 +158,7 @@ public class TextArea extends AbstractTextField { | |||
@Override | |||
public void writeDesign(Element design, DesignContext designContext) { | |||
super.writeDesign(design, designContext); | |||
design.html(getValue()); | |||
design.html(DesignFormatter.encodeForTextNode(getValue())); | |||
} | |||
@Override |
@@ -28,12 +28,15 @@ import java.util.Set; | |||
import java.util.TimeZone; | |||
import java.util.concurrent.ConcurrentHashMap; | |||
import org.jsoup.parser.Parser; | |||
import com.vaadin.data.util.converter.Converter; | |||
import com.vaadin.data.util.converter.StringToBigDecimalConverter; | |||
import com.vaadin.data.util.converter.StringToDoubleConverter; | |||
import com.vaadin.data.util.converter.StringToFloatConverter; | |||
import com.vaadin.event.ShortcutAction; | |||
import com.vaadin.server.Resource; | |||
import com.vaadin.ui.AbstractSelect; | |||
import com.vaadin.ui.declarative.converters.DesignDateConverter; | |||
import com.vaadin.ui.declarative.converters.DesignEnumConverter; | |||
import com.vaadin.ui.declarative.converters.DesignObjectConverter; | |||
@@ -360,4 +363,52 @@ public class DesignFormatter implements Serializable { | |||
return findConverterFor(sourceType, false); | |||
} | |||
/** | |||
* <p> | |||
* Encodes <em>some</em> special characters in a given input String to make | |||
* it ready to be written as contents of a text node. WARNING: this will | |||
* e.g. encode "<someTag>" to "&lt;someTag&gt;" as this method | |||
* doesn't do any parsing and assumes that there are no intended HTML | |||
* elements in the input. Only some entities are actually encoded: | |||
* &,<, > It's assumed that other entities are taken care of by | |||
* Jsoup. | |||
* </p> | |||
* <p> | |||
* Typically, this method will be used by components to encode data (like | |||
* option items in {@link AbstractSelect}) when dumping to HTML format | |||
* </p> | |||
* | |||
* @since | |||
* @param input | |||
* String to be encoded | |||
* @return String with &,< and > replaced with their HTML entities | |||
*/ | |||
public static String encodeForTextNode(String input) { | |||
if (input == null) { | |||
return null; | |||
} | |||
return input.replace("&", "&").replace(">", ">") | |||
.replace("<", "<"); | |||
} | |||
/** | |||
* <p> | |||
* Decodes HTML entities in a text from text node and replaces them with | |||
* actual characters. | |||
* </p> | |||
* | |||
* <p> | |||
* Typically this method will be used by components to read back data (like | |||
* option items in {@link AbstractSelect}) from HTML. Note that this method | |||
* unencodes more characters than {@link #encodeForTextNode(String)} encodes | |||
* </p> | |||
* | |||
* @since | |||
* @param input | |||
* @return | |||
*/ | |||
public static String unencodeFromTextNode(String input) { | |||
return Parser.unescapeEntities(input, false); | |||
} | |||
} |
@@ -36,6 +36,18 @@ import com.vaadin.ui.declarative.DesignContext; | |||
import com.vaadin.ui.declarative.ShouldWriteDataDelegate; | |||
public abstract class DeclarativeTestBaseBase<T extends Component> { | |||
private static final class AlwaysWriteDelegate implements | |||
ShouldWriteDataDelegate { | |||
private static final long serialVersionUID = -6345914431997793599L; | |||
@Override | |||
public boolean shouldWriteData(Component component) { | |||
return true; | |||
} | |||
} | |||
public static final ShouldWriteDataDelegate ALWAYS_WRITE_DATA = new AlwaysWriteDelegate(); | |||
public interface EqualsAsserter<TT> { | |||
public void assertObjectEquals(TT o1, TT o2); | |||
} | |||
@@ -55,12 +67,7 @@ public abstract class DeclarativeTestBaseBase<T extends Component> { | |||
DesignContext dc = new DesignContext(); | |||
if (writeData) { | |||
dc.setShouldWriteDataDelegate(new ShouldWriteDataDelegate() { | |||
@Override | |||
public boolean shouldWriteData(Component component) { | |||
return true; | |||
} | |||
}); | |||
dc.setShouldWriteDataDelegate(DeclarativeTestBaseBase.ALWAYS_WRITE_DATA); | |||
} | |||
dc.setRootComponent(object); | |||
Design.write(dc, outputStream); |
@@ -26,6 +26,7 @@ import com.vaadin.data.util.IndexedContainer; | |||
import com.vaadin.server.ExternalResource; | |||
import com.vaadin.server.Resource; | |||
import com.vaadin.tests.design.DeclarativeTestBase; | |||
import com.vaadin.tests.design.DeclarativeTestBaseBase; | |||
import com.vaadin.ui.AbstractSelect; | |||
import com.vaadin.ui.AbstractSelect.ItemCaptionMode; | |||
import com.vaadin.ui.ComboBox; | |||
@@ -257,6 +258,27 @@ public class AbstractSelectDeclarativeTest extends | |||
|| "true".equals(e.attr("multi-select"))); | |||
} | |||
@Test | |||
public void testHtmlEntities() { | |||
String design = "<v-combo-box>" | |||
+ " <option item-id=\"one\">> One</option>" | |||
+ " <option>> Two</option>" + "</v-combo-box>"; | |||
AbstractSelect read = read(design); | |||
Assert.assertEquals("> One", read.getItemCaption("one")); | |||
AbstractSelect underTest = new ComboBox(); | |||
underTest.addItem("> One"); | |||
Element root = new Element(Tag.valueOf("v-combo-box"), ""); | |||
DesignContext dc = new DesignContext(); | |||
dc.setShouldWriteDataDelegate(DeclarativeTestBaseBase.ALWAYS_WRITE_DATA); | |||
underTest.writeDesign(root, dc); | |||
Assert.assertEquals("> One", root.getElementsByTag("option").first() | |||
.html()); | |||
} | |||
public ComboBox createSingleSelectWithOnlyAttributes() { | |||
ComboBox cb = new ComboBox(); | |||
Container dataSource = new IndexedContainer(); |
@@ -128,13 +128,13 @@ public class OptionGroupDeclarativeTests extends | |||
og.addItems("foo", "bar", "baz", "bang"); | |||
og.setItemCaption("foo", "<b>True</b>"); | |||
og.setItemCaption("bar", "<font color='red'>False</font>"); | |||
og.setItemCaption("bar", "<font color=\"red\">False</font>"); | |||
//@formatter:off | |||
String expected = | |||
"<v-option-group>" | |||
+ "<option item-id=\"foo\"><b>True</b></option>" | |||
+ "<option item-id=\"bar\"><font color='red'>False</font></option>" | |||
+ "<option item-id=\"foo\"><b>True</b></option>" | |||
+ "<option item-id=\"bar\"><font color=\"red\">False</font></option>" | |||
+ "<option>baz</option>" | |||
+ "<option>bang</option>" | |||
+ "</v-option-group>"; |
@@ -15,6 +15,9 @@ | |||
*/ | |||
package com.vaadin.tests.server.component.button; | |||
import org.jsoup.nodes.Element; | |||
import org.jsoup.parser.Tag; | |||
import org.junit.Assert; | |||
import org.junit.Test; | |||
import com.vaadin.event.ShortcutAction.KeyCode; | |||
@@ -22,6 +25,7 @@ import com.vaadin.event.ShortcutAction.ModifierKey; | |||
import com.vaadin.tests.design.DeclarativeTestBase; | |||
import com.vaadin.ui.Button; | |||
import com.vaadin.ui.NativeButton; | |||
import com.vaadin.ui.declarative.DesignContext; | |||
/** | |||
* Tests declarative support for implementations of {@link Button} and | |||
@@ -71,6 +75,41 @@ public class ButtonDeclarativeTest extends DeclarativeTestBase<Button> { | |||
testButtonAndNativeButton(design, true, "", expectedWritten); | |||
} | |||
@Test | |||
public void testHtmlEntitiesInCaption() { | |||
String designPlainText = "<v-button plain-text=\"true\">> One</v-button>"; | |||
String expectedCaptionPlainText = "> One"; | |||
Button read = read(designPlainText); | |||
Assert.assertEquals(expectedCaptionPlainText, read.getCaption()); | |||
designPlainText = designPlainText | |||
.replace("v-button", "v-native-button"); | |||
Button nativeButton = read(designPlainText); | |||
Assert.assertEquals(expectedCaptionPlainText, nativeButton.getCaption()); | |||
String designHtml = "<v-button>> One</v-button>"; | |||
String expectedCaptionHtml = "> One"; | |||
read = read(designHtml); | |||
Assert.assertEquals(expectedCaptionHtml, read.getCaption()); | |||
designHtml = designHtml.replace("v-button", "v-native-button"); | |||
nativeButton = read(designHtml); | |||
Assert.assertEquals(expectedCaptionHtml, nativeButton.getCaption()); | |||
read = new Button("& Test"); | |||
read.setHtmlContentAllowed(true); | |||
Element root = new Element(Tag.valueOf("v-button"), ""); | |||
read.writeDesign(root, new DesignContext()); | |||
assertEquals("& Test", root.html()); | |||
read.setHtmlContentAllowed(false); | |||
root = new Element(Tag.valueOf("v-button"), ""); | |||
read.writeDesign(root, new DesignContext()); | |||
assertEquals("&amp; Test", root.html()); | |||
} | |||
public void testButtonAndNativeButton(String design, boolean html, | |||
String caption) { | |||
testButtonAndNativeButton(design, html, caption, design); |
@@ -15,6 +15,9 @@ | |||
*/ | |||
package com.vaadin.tests.server.component.grid.declarative; | |||
import org.jsoup.nodes.Element; | |||
import org.jsoup.parser.Tag; | |||
import org.junit.Assert; | |||
import org.junit.Test; | |||
import com.vaadin.shared.ui.label.ContentMode; | |||
@@ -23,21 +26,27 @@ import com.vaadin.ui.Grid.Column; | |||
import com.vaadin.ui.Grid.FooterRow; | |||
import com.vaadin.ui.Grid.HeaderRow; | |||
import com.vaadin.ui.Label; | |||
import com.vaadin.ui.declarative.DesignContext; | |||
public class GridHeaderFooterDeclarativeTest extends GridDeclarativeTestBase { | |||
@Test | |||
public void testSingleDefaultHeader() { | |||
String design = "<v-grid><table>"// | |||
//@formatter:off | |||
String design = "<v-grid><table>" | |||
+ "<colgroup>" | |||
+ " <col sortable='' property-id='Column1'>" | |||
+ " <col sortable='' property-id='Column2'>" | |||
+ " <col sortable='' property-id='Column3'>" | |||
+ "</colgroup>" // | |||
+ "<thead>" // | |||
+ " <tr default=''><th plain-text=''>Column1<th plain-text=''>Column2<th plain-text=''>Column3</tr>" // | |||
+ "</thead>" // | |||
+ "</colgroup>" | |||
+ "<thead>" | |||
+ " <tr default=''>" | |||
+ " <th plain-text=''>Column1</th>" | |||
+ " <th plain-text=''>Column2</th>" | |||
+ " <th plain-text=''>Column3</tr>" | |||
+ "</thead>" | |||
+ "</table></v-grid>"; | |||
//@formatter:on | |||
Grid grid = new Grid(); | |||
grid.addColumn("Column1", String.class); | |||
grid.addColumn("Column2", String.class); | |||
@@ -49,15 +58,18 @@ public class GridHeaderFooterDeclarativeTest extends GridDeclarativeTestBase { | |||
@Test | |||
public void testSingleDefaultHTMLHeader() { | |||
String design = "<v-grid><table>"// | |||
//@formatter:off | |||
String design = "<v-grid><table>" | |||
+ "<colgroup>" | |||
+ " <col sortable='' property-id='Column1'>" | |||
+ " <col sortable='' property-id='Column2'>" | |||
+ " <col sortable='' property-id='Column3'>" + "</colgroup>" // | |||
+ "<thead>" // | |||
+ " <tr default=''><th>Column1<th>Column2<th>Column3</tr>" // | |||
+ "</thead>" // | |||
+ " <col sortable='' property-id='Column3'>" | |||
+ "</colgroup>" | |||
+ "<thead>" | |||
+ " <tr default=''><th>Column1<th>Column2<th>Column3</tr>" | |||
+ "</thead>" | |||
+ "</table></v-grid>"; | |||
//@formatter:on | |||
Grid grid = new Grid(); | |||
grid.addColumn("Column1", String.class); | |||
grid.addColumn("Column2", String.class); | |||
@@ -74,13 +86,14 @@ public class GridHeaderFooterDeclarativeTest extends GridDeclarativeTestBase { | |||
@Test | |||
public void testNoHeaderRows() { | |||
String design = "<v-grid><table>"// | |||
//@formatter:off | |||
String design = "<v-grid><table>" | |||
+ "<colgroup>" | |||
+ " <col sortable='' property-id='Column1'>" | |||
+ "</colgroup>" // | |||
+ "<thead />" // | |||
+ "</colgroup>" | |||
+ "<thead />" | |||
+ "</table></v-grid>"; | |||
//@formatter:on | |||
Grid grid = new Grid(); | |||
grid.addColumn("Column1", String.class); | |||
grid.removeHeaderRow(grid.getDefaultHeaderRow()); | |||
@@ -91,18 +104,20 @@ public class GridHeaderFooterDeclarativeTest extends GridDeclarativeTestBase { | |||
@Test | |||
public void testMultipleHeadersWithColSpans() { | |||
String design = "<v-grid><table>"// | |||
//@formatter:off | |||
String design = "<v-grid><table>" | |||
+ "<colgroup>" | |||
+ " <col sortable='' property-id='Column1'>" | |||
+ " <col sortable='' property-id='Column2'>" | |||
+ " <col sortable='' property-id='Column3'>" | |||
+ "</colgroup>" // | |||
+ "<thead>" // | |||
+ "</colgroup>" | |||
+ "<thead>" | |||
+ " <tr><th colspan=3>Baz</tr>" | |||
+ " <tr default=''><th>Column1<th>Column2<th>Column3</tr>" // | |||
+ " <tr><th>Foo<th colspan=2>Bar</tr>" // | |||
+ "</thead>" // | |||
+ " <tr default=''><th>Column1<th>Column2<th>Column3</tr>" | |||
+ " <tr><th>Foo<th colspan=2>Bar</tr>" | |||
+ "</thead>" | |||
+ "</table></v-grid>"; | |||
//@formatter:on | |||
Grid grid = new Grid(); | |||
grid.addColumn("Column1", String.class); | |||
grid.addColumn("Column2", String.class); | |||
@@ -125,17 +140,19 @@ public class GridHeaderFooterDeclarativeTest extends GridDeclarativeTestBase { | |||
@Test | |||
public void testSingleDefaultFooter() { | |||
String design = "<v-grid><table>"// | |||
//@formatter:off | |||
String design = "<v-grid><table>" | |||
+ "<colgroup>" | |||
+ " <col sortable='' property-id='Column1'>" | |||
+ " <col sortable='' property-id='Column2'>" | |||
+ " <col sortable='' property-id='Column3'>" | |||
+ "</colgroup>" // | |||
+ "</colgroup>" | |||
+ "<thead />" // No headers read or written | |||
+ "<tfoot>" // | |||
+ " <tr><td plain-text=''>Column1<td plain-text=''>Column2<td plain-text=''>Column3</tr>" // | |||
+ "</tfoot>" // | |||
+ "<tfoot>" | |||
+ " <tr><td plain-text=''>Column1<td plain-text=''>Column2<td plain-text=''>Column3</tr>" | |||
+ "</tfoot>" | |||
+ "</table></v-grid>"; | |||
//@formatter:on | |||
Grid grid = new Grid(); | |||
grid.addColumn("Column1", String.class); | |||
grid.addColumn("Column2", String.class); | |||
@@ -154,16 +171,19 @@ public class GridHeaderFooterDeclarativeTest extends GridDeclarativeTestBase { | |||
@Test | |||
public void testSingleDefaultHTMLFooter() { | |||
String design = "<v-grid><table>"// | |||
//@formatter:off | |||
String design = "<v-grid><table>" | |||
+ "<colgroup>" | |||
+ " <col sortable='' property-id='Column1'>" | |||
+ " <col sortable='' property-id='Column2'>" | |||
+ " <col sortable='' property-id='Column3'>" + "</colgroup>" // | |||
+ " <col sortable='' property-id='Column3'>" | |||
+ "</colgroup>" | |||
+ "<thead />" // No headers read or written | |||
+ "<tfoot>" // | |||
+ " <tr><td>Column1<td>Column2<td>Column3</tr>" // | |||
+ "</tfoot>" // | |||
+ "<tfoot>" | |||
+ " <tr><td>Column1<td>Column2<td>Column3</tr>" | |||
+ "</tfoot>" | |||
+ "</table></v-grid>"; | |||
//@formatter:on | |||
Grid grid = new Grid(); | |||
grid.addColumn("Column1", String.class); | |||
grid.addColumn("Column2", String.class); | |||
@@ -182,19 +202,21 @@ public class GridHeaderFooterDeclarativeTest extends GridDeclarativeTestBase { | |||
@Test | |||
public void testMultipleFootersWithColSpans() { | |||
String design = "<v-grid><table>"// | |||
//@formatter:off | |||
String design = "<v-grid><table>" | |||
+ "<colgroup>" | |||
+ " <col sortable='' property-id='Column1'>" | |||
+ " <col sortable='' property-id='Column2'>" | |||
+ " <col sortable='' property-id='Column3'>" | |||
+ "</colgroup>" // | |||
+ "</colgroup>" | |||
+ "<thead />" // No headers read or written. | |||
+ "<tfoot>" // | |||
+ "<tfoot>" | |||
+ " <tr><td colspan=3>Baz</tr>" | |||
+ " <tr><td>Column1<td>Column2<td>Column3</tr>" // | |||
+ " <tr><td>Foo<td colspan=2>Bar</tr>" // | |||
+ "</tfoot>" // | |||
+ " <tr><td>Column1<td>Column2<td>Column3</tr>" | |||
+ " <tr><td>Foo<td colspan=2>Bar</tr>" | |||
+ "</tfoot>" | |||
+ "</table></v-grid>"; | |||
//@formatter:on | |||
Grid grid = new Grid(); | |||
grid.addColumn("Column1", String.class); | |||
grid.addColumn("Column2", String.class); | |||
@@ -219,15 +241,16 @@ public class GridHeaderFooterDeclarativeTest extends GridDeclarativeTestBase { | |||
@Test | |||
public void testComponentInGridHeader() { | |||
String design = "<v-grid><table>"// | |||
//@formatter:off | |||
String design = "<v-grid><table>" | |||
+ "<colgroup>" | |||
+ " <col sortable='' property-id='Column1'>" | |||
+ "</colgroup>" // | |||
+ "<thead>" // | |||
+ "</colgroup>" | |||
+ "<thead>" | |||
+ "<tr default=''><th><v-label><b>Foo</b></v-label></tr>" | |||
+ "</thead>"// | |||
+ "</thead>" | |||
+ "</table></v-grid>"; | |||
//@formatter:on | |||
Label component = new Label("<b>Foo</b>"); | |||
component.setContentMode(ContentMode.HTML); | |||
@@ -241,16 +264,17 @@ public class GridHeaderFooterDeclarativeTest extends GridDeclarativeTestBase { | |||
@Test | |||
public void testComponentInGridFooter() { | |||
String design = "<v-grid><table>"// | |||
//@formatter:off | |||
String design = "<v-grid><table>" | |||
+ "<colgroup>" | |||
+ " <col sortable='' property-id='Column1'>" | |||
+ "</colgroup>" // | |||
+ "</colgroup>" | |||
+ "<thead />" // No headers read or written | |||
+ "<tfoot>" // | |||
+ "<tr><td><v-label><b>Foo</b></v-label></tr>"// | |||
+ "</tfoot>" // | |||
+ "<tfoot>" | |||
+ "<tr><td><v-label><b>Foo</b></v-label></tr>" | |||
+ "</tfoot>" | |||
+ "</table></v-grid>"; | |||
//@formatter:on | |||
Label component = new Label("<b>Foo</b>"); | |||
component.setContentMode(ContentMode.HTML); | |||
@@ -262,4 +286,67 @@ public class GridHeaderFooterDeclarativeTest extends GridDeclarativeTestBase { | |||
testRead(design, grid, true); | |||
testWrite(design, grid); | |||
} | |||
@Test | |||
public void testHtmlEntitiesinGridHeaderFooter() { | |||
// @formatter off | |||
String design = "<v-grid><table>" + "<colgroup>" | |||
+ " <col sortable=\"true\" property-id=\"> test\">" | |||
+ "</colgroup>" + "<thead>" | |||
+ " <tr><th plain-text=\"true\">> Test</th></tr>" | |||
+ "</thead>" + "<tfoot>" | |||
+ " <tr><td plain-text=\"true\">> Test</td></tr>" | |||
+ "</tfoot>" + "<tbody />" + "</table></v-grid>"; | |||
// @formatter off | |||
Grid grid = read(design); | |||
String actualHeader = grid.getHeaderRow(0).getCell("> test").getText(); | |||
String actualFooter = grid.getFooterRow(0).getCell("> test").getText(); | |||
String expected = "> Test"; | |||
Assert.assertEquals(expected, actualHeader); | |||
Assert.assertEquals(expected, actualFooter); | |||
design = design.replace("plain-text=\"true\"", ""); | |||
grid = read(design); | |||
actualHeader = grid.getHeaderRow(0).getCell("> test").getHtml(); | |||
actualFooter = grid.getFooterRow(0).getCell("> test").getHtml(); | |||
expected = "> Test"; | |||
Assert.assertEquals(expected, actualHeader); | |||
Assert.assertEquals(expected, actualFooter); | |||
grid = new Grid(); | |||
grid.setColumns("test"); | |||
HeaderRow header = grid.addHeaderRowAt(0); | |||
FooterRow footer = grid.addFooterRowAt(0); | |||
grid.removeHeaderRow(grid.getDefaultHeaderRow()); | |||
// entities should be encoded when writing back, not interpreted as HTML | |||
header.getCell("test").setText("& Test"); | |||
footer.getCell("test").setText("& Test"); | |||
Element root = new Element(Tag.valueOf("v-grid"), ""); | |||
grid.writeDesign(root, new DesignContext()); | |||
Assert.assertEquals("&amp; Test", root.getElementsByTag("th") | |||
.get(0).html()); | |||
Assert.assertEquals("&amp; Test", root.getElementsByTag("td") | |||
.get(0).html()); | |||
header = grid.addHeaderRowAt(0); | |||
footer = grid.addFooterRowAt(0); | |||
// entities should not be encoded, this is already given as HTML | |||
header.getCell("test").setHtml("& Test"); | |||
footer.getCell("test").setHtml("& Test"); | |||
root = new Element(Tag.valueOf("v-grid"), ""); | |||
grid.writeDesign(root, new DesignContext()); | |||
Assert.assertEquals("& Test", root.getElementsByTag("th").get(0) | |||
.html()); | |||
Assert.assertEquals("& Test", root.getElementsByTag("td").get(0) | |||
.html()); | |||
} | |||
} |
@@ -15,8 +15,10 @@ | |||
*/ | |||
package com.vaadin.tests.server.component.grid.declarative; | |||
import org.junit.Assert; | |||
import org.junit.Test; | |||
import com.vaadin.data.Container; | |||
import com.vaadin.ui.Grid; | |||
public class GridInlineDataDeclarativeTest extends GridDeclarativeTestBase { | |||
@@ -32,6 +34,7 @@ public class GridInlineDataDeclarativeTest extends GridDeclarativeTestBase { | |||
+ "<tr><td>Foo</tr>" // | |||
+ "<tr><td>Bar</tr>" // | |||
+ "<tr><td>Baz</tr>" // | |||
+ "</tbody>" | |||
+ "</table></v-grid>"; | |||
Grid grid = new Grid(); | |||
@@ -59,6 +62,7 @@ public class GridInlineDataDeclarativeTest extends GridDeclarativeTestBase { | |||
+ "<tbody>" // | |||
+ "<tr><td>Foo<td>Bar<td>Baz</tr>" // | |||
+ "<tr><td>My<td>Summer<td>Car</tr>" // | |||
+ "</tbody>" | |||
+ "</table></v-grid>"; | |||
Grid grid = new Grid(); | |||
@@ -87,6 +91,7 @@ public class GridInlineDataDeclarativeTest extends GridDeclarativeTestBase { | |||
+ "<tbody>" // | |||
+ "<tr><td>Bar<td>Baz<td>Foo</tr>" // | |||
+ "<tr><td>Summer<td>Car<td>My</tr>" // | |||
+ "</tbody>" | |||
+ "</table></v-grid>"; | |||
Grid grid = new Grid(); | |||
@@ -103,4 +108,23 @@ public class GridInlineDataDeclarativeTest extends GridDeclarativeTestBase { | |||
testWrite(design, grid, true); | |||
testRead(design, grid, true, true); | |||
} | |||
@Test | |||
public void testHtmlEntities() { | |||
String design = "<v-grid><table>"// | |||
+ "<colgroup>" | |||
+ " <col property-id='test' />" | |||
+ "</colgroup>" // | |||
+ "<thead />" // No headers read or written | |||
+ "<tbody>" | |||
+ " <tr><td>&Test</tr></td>" | |||
+ "</tbody>" | |||
+ "</table></v-grid>"; | |||
Grid read = read(design); | |||
Container cds = read.getContainerDataSource(); | |||
Assert.assertEquals("&Test", | |||
cds.getItem(cds.getItemIds().iterator().next()) | |||
.getItemProperty("test").getValue()); | |||
} | |||
} |
@@ -15,11 +15,16 @@ | |||
*/ | |||
package com.vaadin.tests.server.component.label; | |||
import org.jsoup.nodes.Element; | |||
import org.jsoup.parser.Tag; | |||
import org.junit.Assert; | |||
import org.junit.Test; | |||
import com.vaadin.shared.ui.label.ContentMode; | |||
import com.vaadin.tests.design.DeclarativeTestBase; | |||
import com.vaadin.ui.Label; | |||
import com.vaadin.ui.declarative.DesignContext; | |||
import com.vaadin.ui.declarative.DesignFormatter; | |||
/** | |||
* Tests declarative support for implementations of {@link Label}. | |||
@@ -57,11 +62,11 @@ public class LabelDeclarativeTest extends DeclarativeTestBase<Label> { | |||
@Test | |||
public void testPlainText() { | |||
String design = "<v-label plain-text>This is only <b>text</b>" | |||
String design = "<v-label plain-text>This is only <b>text</b>" | |||
+ " and will contain visible tags</v-label>"; | |||
Label l = createLabel( | |||
"This is only \n<b>text</b> and will contain visible tags", | |||
null, false); | |||
"This is only <b>text</b> and will contain visible tags", null, | |||
false); | |||
testRead(design, l); | |||
testWrite(design, l); | |||
} | |||
@@ -84,6 +89,29 @@ public class LabelDeclarativeTest extends DeclarativeTestBase<Label> { | |||
testWrite(design, l); | |||
} | |||
@Test | |||
public void testHtmlEntities() { | |||
String design = "<v-label plain-text=\"true\">> Test</v-label>"; | |||
Label read = read(design); | |||
Assert.assertEquals("> Test", read.getValue()); | |||
design = design.replace("plain-text=\"true\"", ""); | |||
read = read(design); | |||
Assert.assertEquals("> Test", read.getValue()); | |||
Label label = new Label("& Test"); | |||
label.setContentMode(ContentMode.TEXT); | |||
Element root = new Element(Tag.valueOf("v-label"), ""); | |||
label.writeDesign(root, new DesignContext()); | |||
Assert.assertEquals("&amp; Test", root.html()); | |||
label.setContentMode(ContentMode.HTML); | |||
root = new Element(Tag.valueOf("v-label"), ""); | |||
label.writeDesign(root, new DesignContext()); | |||
Assert.assertEquals("& Test", root.html()); | |||
} | |||
private Label createLabel(String content, String caption, boolean html) { | |||
Label label = new Label(); | |||
label.setContentMode(html ? ContentMode.HTML : ContentMode.TEXT); | |||
@@ -91,7 +119,7 @@ public class LabelDeclarativeTest extends DeclarativeTestBase<Label> { | |||
label.setValue(content); | |||
} | |||
if (caption != null) { | |||
label.setCaption(caption); | |||
label.setCaption(DesignFormatter.encodeForTextNode(caption)); | |||
} | |||
return label; | |||
} |
@@ -15,6 +15,7 @@ | |||
*/ | |||
package com.vaadin.tests.server.component.table; | |||
import org.junit.Assert; | |||
import org.junit.Test; | |||
import com.vaadin.server.ExternalResource; | |||
@@ -24,6 +25,7 @@ import com.vaadin.ui.Table.Align; | |||
import com.vaadin.ui.Table.ColumnHeaderMode; | |||
import com.vaadin.ui.Table.RowHeaderMode; | |||
import com.vaadin.ui.Table.TableDragMode; | |||
import com.vaadin.ui.declarative.Design; | |||
/** | |||
* Test declarative support for {@link Table}. | |||
@@ -166,4 +168,30 @@ public class TableDeclarativeTest extends TableDeclarativeTestBase { | |||
testRead(design, table); | |||
testWrite(design, table, true); | |||
} | |||
@Test | |||
public void testHtmlEntities() { | |||
String design = "<v-table>" | |||
+ "<table>" | |||
+ " <colgroup>" | |||
+ " <col property-id=\"test\"" | |||
+ " </colgroup>" | |||
+ " <thead>" | |||
+ " <tr><th>& Test</th></tr>" | |||
+ " </thead>" | |||
+ " <tbody>" | |||
+ " <tr item-id=\"test\"><td>& Test</tr>" | |||
+ " </tbody>" | |||
+ " <tfoot>" | |||
+ " <tr><td>& Test</td></tr>" | |||
+ " </tfoot>" | |||
+ "</table>" | |||
+ "</v-table>"; | |||
Table read = read(design); | |||
Assert.assertEquals("& Test", | |||
read.getContainerProperty("test", "test").getValue()); | |||
Assert.assertEquals("& Test", read.getColumnHeader("test")); | |||
Assert.assertEquals("& Test", read.getColumnFooter("test")); | |||
} | |||
} |
@@ -15,10 +15,16 @@ | |||
*/ | |||
package com.vaadin.tests.server.component.textarea; | |||
import java.io.IOException; | |||
import org.jsoup.nodes.Element; | |||
import org.jsoup.parser.Tag; | |||
import org.junit.Assert; | |||
import org.junit.Test; | |||
import com.vaadin.tests.design.DeclarativeTestBase; | |||
import com.vaadin.ui.TextArea; | |||
import com.vaadin.ui.declarative.DesignContext; | |||
/** | |||
* Tests declarative support for implementations of {@link TextArea}. | |||
@@ -38,4 +44,20 @@ public class TextAreaDeclarativeTest extends DeclarativeTestBase<TextArea> { | |||
testRead(design, ta); | |||
testWrite(design, ta); | |||
} | |||
@Test | |||
public void testHtmlEntities() throws IOException { | |||
String design = "<v-text-area>& Test</v-text-area>"; | |||
TextArea read = read(design); | |||
Assert.assertEquals("& Test", read.getValue()); | |||
read.setValue("& Test"); | |||
DesignContext dc = new DesignContext(); | |||
Element root = new Element(Tag.valueOf("v-text-area"), ""); | |||
read.writeDesign(root, dc); | |||
Assert.assertEquals("&amp; Test", root.html()); | |||
} | |||
} |