Browse Source

Option for rendering Calendar event captions as HTML (#9030)

Change-Id: Ib7f6e67c242449e58a10359c596489fea2f679f6
tags/7.4.0.beta2
Artur Signell 9 years ago
parent
commit
26832b6947

+ 2
- 1
WebContent/release-notes.html View File

@@ -112,7 +112,7 @@
<li>Declarative layout support for initializing a component hierarchy from an HTML file.</li>
<li>Uses GWT 2.7 for improved compilation times when using Super Dev Mode.</li>
<li>@Viewport annotation for declaratively defining a mobile viewport definition for a UI.</li>
<li>Captions can be configured to be displayed as HTML.</li>
<li>Component captions, TabSheet/Accordion tab captions and Calendar event captions can be configured to be displayed as HTML.</li>
<li>Selects use converters when presenting itemids.</li>
<li>Improved performance when server response contains no visual changing (e.g. empty polling responses).</li>
<li>Unified JSON library for using the same API in both server-side and client-side code.</li>
@@ -134,6 +134,7 @@
<p>Raw JSON values passed to AbstractJavaScriptComponent.callFunction and AbstractJavaScriptExtension.callFunction should be changed to use elemental.json types.</p>
</li>
<li>The semantics of empty and required for Field classes has been made more consistent. This mainly affects Checkbox which is now considered to be empty when it is not checked.</li>
<li>The previously inconsistent behavior in HTML vs plain text rendering of Calendar event captions has been made consistent.</li>
<li>Support for Opera 12 has been dropped. Newer versions based on the Blink rendering engine are still supported.</li>
</ul>
<h3 id="knownissues">Known issues</h3>

+ 30
- 0
client/src/com/vaadin/client/ui/VCalendar.java View File

@@ -1342,6 +1342,7 @@ public class VCalendar extends Composite implements VHasDropHandler {
private MouseEventListener mouseEventListener;
private boolean forwardNavigationEnabled = true;
private boolean backwardNavigationEnabled = true;
private boolean eventCaptionAsHtml = false;

/**
* Get the listener that listen to mouse events
@@ -1467,4 +1468,33 @@ public class VCalendar extends Composite implements VHasDropHandler {
public void setDropHandler(CalendarDropHandler dropHandler) {
this.dropHandler = dropHandler;
}

/**
* Sets whether the event captions are rendered as HTML.
* <p>
* If set to true, the captions are rendered in the browser as HTML and the
* developer is responsible for ensuring no harmful HTML is used. If set to
* false, the caption is rendered in the browser as plain text.
* <p>
* The default is false, i.e. to render that caption as plain text.
*
* @param captionAsHtml
* true if the captions are rendered as HTML, false if rendered
* as plain text
*/
public void setEventCaptionAsHtml(boolean eventCaptionAsHtml) {
this.eventCaptionAsHtml = eventCaptionAsHtml;
}

/**
* Checks whether event captions are rendered as HTML
* <p>
* The default is false, i.e. to render that caption as plain text.
*
* @return true if the captions are rendered as HTML, false if rendered as
* plain text
*/
public boolean isEventCaptionAsHtml() {
return eventCaptionAsHtml;
}
}

+ 2
- 0
client/src/com/vaadin/client/ui/calendar/CalendarConnector.java View File

@@ -345,6 +345,8 @@ public class CalendarConnector extends AbstractComponentConnector implements
widget.setEventMoveAllowed(hasEventListener(CalendarEventId.EVENTMOVE));
widget.setEventResizeAllowed(hasEventListener(CalendarEventId.EVENTRESIZE));

widget.setEventCaptionAsHtml(state.eventCaptionAsHtml);

List<CalendarState.Day> days = state.days;
List<CalendarState.Event> events = state.events;


+ 10
- 4
client/src/com/vaadin/client/ui/calendar/schedule/DateCellDayEvent.java View File

@@ -184,14 +184,20 @@ public class DateCellDayEvent extends FocusableHTML implements
*/
private void updateCaptions(boolean bigMode) {
String innerHtml;
String escapedCaption = Util.escapeHTML(calendarEvent.getCaption());
String timeAsText = calendarEvent.getTimeAsText();
String htmlOrText;

if (dateCell.weekgrid.getCalendar().isEventCaptionAsHtml()) {
htmlOrText = calendarEvent.getCaption();
} else {
htmlOrText = Util.escapeHTML(calendarEvent.getCaption());
}

if (bigMode) {
innerHtml = "<span>" + timeAsText + "</span><br />"
+ escapedCaption;
innerHtml = "<span>" + timeAsText + "</span><br />" + htmlOrText;
} else {
innerHtml = "<span>" + timeAsText + "<span>:</span></span> "
+ escapedCaption;
+ htmlOrText;
}
caption.setInnerHTML(innerHtml);
eventContent.setInnerHTML("");

+ 12
- 3
client/src/com/vaadin/client/ui/calendar/schedule/MonthEventLabel.java View File

@@ -20,6 +20,7 @@ import java.util.Date;
import com.google.gwt.event.dom.client.ContextMenuEvent;
import com.google.gwt.event.dom.client.ContextMenuHandler;
import com.google.gwt.user.client.ui.HTML;
import com.vaadin.client.Util;
import com.vaadin.client.ui.VCalendar;

/**
@@ -75,7 +76,8 @@ public class MonthEventLabel extends HTML implements HasTooltipKey {
* Set the caption of the event label
*
* @param caption
* The caption string, can be HTML
* The caption string, can be HTML if
* {@link VCalendar#isEventCaptionAsHtml()} is true
*/
public void setCaption(String caption) {
this.caption = caption;
@@ -87,13 +89,20 @@ public class MonthEventLabel extends HTML implements HasTooltipKey {
*/
private void renderCaption() {
StringBuilder html = new StringBuilder();
String textOrHtml;
if (calendar.isEventCaptionAsHtml()) {
textOrHtml = caption;
} else {
textOrHtml = Util.escapeHTML(caption);
}

if (caption != null && time != null) {
html.append("<span class=\"" + STYLENAME + "-time\">");
html.append(calendar.getTimeFormat().format(time));
html.append("</span> ");
html.append(caption);
html.append(textOrHtml);
} else if (caption != null) {
html.append(caption);
html.append(textOrHtml);
} else if (time != null) {
html.append("<span class=\"" + STYLENAME + "-time\">");
html.append(calendar.getTimeFormat().format(time));

+ 5
- 1
client/src/com/vaadin/client/ui/calendar/schedule/WeeklyLongEvents.java View File

@@ -102,7 +102,11 @@ public class WeeklyLongEvents extends HorizontalPanel implements HasTooltipKey {
eventLabel.addStyleDependentName(extraStyle + "-all-day");
}
if (!started) {
eventLabel.setText(calendarEvent.getCaption());
if (calendar.isEventCaptionAsHtml()) {
eventLabel.setHTML(calendarEvent.getCaption());
} else {
eventLabel.setText(calendarEvent.getCaption());
}
started = true;
}
}

+ 36
- 1
server/src/com/vaadin/ui/Calendar.java View File

@@ -296,6 +296,11 @@ public class Calendar extends AbstractComponent implements
return (CalendarState) super.getState();
}

@Override
protected CalendarState getState(boolean markAsDirty) {
return (CalendarState) super.getState(markAsDirty);
}

@Override
public void beforeClientResponse(boolean initial) {
super.beforeClientResponse(initial);
@@ -1667,7 +1672,7 @@ public class Calendar extends AbstractComponent implements
* weekly mode
*/
public boolean isMonthlyMode() {
CalendarState state = (CalendarState) getState(false);
CalendarState state = getState(false);
if (state.days != null) {
return state.days.size() > 7;
} else {
@@ -1895,4 +1900,34 @@ public class Calendar extends AbstractComponent implements
dropHandler.getAcceptCriterion().paint(target);
}
}

/**
* Sets whether the event captions are rendered as HTML.
* <p>
* If set to true, the captions are rendered in the browser as HTML and the
* developer is responsible for ensuring no harmful HTML is used. If set to
* false, the caption is rendered in the browser as plain text.
* <p>
* The default is false, i.e. to render that caption as plain text.
*
* @param captionAsHtml
* true if the captions are rendered as HTML, false if rendered
* as plain text
*/
public void setEventCaptionAsHtml(boolean eventCaptionAsHtml) {
getState().eventCaptionAsHtml = eventCaptionAsHtml;
}

/**
* Checks whether event captions are rendered as HTML
* <p>
* The default is false, i.e. to render that caption as plain text.
*
* @return true if the captions are rendered as HTML, false if rendered as
* plain text
*/
public boolean isEventCaptionAsHtml() {
return getState(false).eventCaptionAsHtml;
}

}

+ 1
- 0
shared/src/com/vaadin/shared/ui/calendar/CalendarState.java View File

@@ -38,6 +38,7 @@ public class CalendarState extends AbstractComponentState {
public List<CalendarState.Day> days;
public List<CalendarState.Event> events;
public List<CalendarState.Action> actions;
public boolean eventCaptionAsHtml;

public static class Day implements java.io.Serializable {
public String date;

+ 101
- 0
uitest/src/com/vaadin/tests/components/calendar/CalendarHtmlInEvents.java View File

@@ -0,0 +1,101 @@
/*
* Copyright 2000-2014 Vaadin Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.vaadin.tests.components.calendar;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import com.vaadin.data.Property.ValueChangeEvent;
import com.vaadin.data.Property.ValueChangeListener;
import com.vaadin.data.util.MethodProperty;
import com.vaadin.server.VaadinRequest;
import com.vaadin.tests.components.AbstractTestUIWithLog;
import com.vaadin.ui.Alignment;
import com.vaadin.ui.Calendar;
import com.vaadin.ui.CheckBox;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.NativeSelect;
import com.vaadin.ui.components.calendar.event.BasicEvent;
import com.vaadin.ui.components.calendar.event.CalendarEvent;
import com.vaadin.ui.components.calendar.event.CalendarEventProvider;

public class CalendarHtmlInEvents extends AbstractTestUIWithLog {

private Calendar calendar = new Calendar();

@Override
protected void setup(VaadinRequest request) {
final NativeSelect ns = new NativeSelect("Period");
ns.addItems("Day", "Week", "Month");
ns.addValueChangeListener(new ValueChangeListener() {
@Override
public void valueChange(ValueChangeEvent event) {
if ("Day".equals(ns.getValue())) {
calendar.setStartDate(new Date(2014 - 1900, 1 - 1, 1));
calendar.setEndDate(new Date(2014 - 1900, 1 - 1, 1));
} else if ("Week".equals(ns.getValue())) {
calendar.setStartDate(new Date(2014 - 1900, 1 - 1, 1));
calendar.setEndDate(new Date(2014 - 1900, 1 - 1, 7));
} else if ("Month".equals(ns.getValue())) {
calendar.setStartDate(new Date(2014 - 1900, 1 - 1, 1));
calendar.setEndDate(new Date(2014 - 1900, 2 - 1, 1));
}
}
});
ns.setValue("Month");
final CheckBox allowHtml = new CheckBox("Allow HTML in event caption",
new MethodProperty<Boolean>(calendar, "eventCaptionAsHtml"));
allowHtml.addValueChangeListener(new ValueChangeListener() {
@Override
public void valueChange(ValueChangeEvent event) {
log("HTML in event caption: " + allowHtml.getValue());
}
});
HorizontalLayout hl = new HorizontalLayout();
hl.setDefaultComponentAlignment(Alignment.BOTTOM_LEFT);
hl.addComponents(ns, allowHtml);
hl.setSpacing(true);
hl.setMargin(true);
calendar.setEventProvider(new CalendarEventProvider() {

@Override
public List<CalendarEvent> getEvents(Date startDate, Date endDate) {
Date d = startDate;
ArrayList<CalendarEvent> events = new ArrayList<CalendarEvent>();
while (d.before(endDate)) {
BasicEvent ce = new BasicEvent();
ce.setAllDay(false);
ce.setCaption("<b>Hello</b> <u>world</u>!");
ce.setDescription("Nothing really important");
Date start = new Date(d.getTime());
start.setHours(d.getDay());
Date end = new Date(d.getTime());
end.setHours(d.getDay() + 3);
ce.setStart(start);
ce.setEnd(end);
events.add(ce);
d.setTime(d.getTime() + 1000 * 60 * 60 * 24);
}

return events;
}

});
addComponent(hl);
addComponent(calendar);
}
}

+ 103
- 0
uitest/src/com/vaadin/tests/components/calendar/CalendarHtmlInEventsTest.java View File

@@ -0,0 +1,103 @@
/*
* Copyright 2000-2014 Vaadin Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.vaadin.tests.components.calendar;

import org.junit.Assert;
import org.junit.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;

import com.vaadin.testbench.elements.CalendarElement;
import com.vaadin.testbench.elements.CheckBoxElement;
import com.vaadin.testbench.elements.NativeSelectElement;
import com.vaadin.tests.tb3.SingleBrowserTest;

public class CalendarHtmlInEventsTest extends SingleBrowserTest {

private NativeSelectElement periodSelect;
private CheckBoxElement htmlAllowed;
private CalendarElement calendar;

@Override
public void setup() throws Exception {
super.setup();
openTestURL();
periodSelect = $(NativeSelectElement.class).first();
htmlAllowed = $(CheckBoxElement.class).first();
calendar = $(CalendarElement.class).first();
}

@Test
public void monthViewEventCaptions() {
Assert.assertEquals(getMonthEvent(0).getText(),
"12:00 AM <b>Hello</b> <u>world</u>!");

// Switch to HTML mode
click(htmlAllowed);
Assert.assertEquals("1. HTML in event caption: true", getLogRow(0));

Assert.assertEquals(getMonthEvent(0).getText(), "12:00 AM Hello world!");
}

@Test
public void weekViewEventCaptions() {
periodSelect.selectByText("Week");
Assert.assertEquals("4:00 AM\n<b>Hello</b> <u>world</u>!",
getWeekEvent(1).getText());

// Switch to HTML mode
click(htmlAllowed);
Assert.assertEquals("1. HTML in event caption: true", getLogRow(0));

Assert.assertEquals("4:00 AM\nHello world!", getWeekEvent(1).getText());
}

@Test
public void dayViewEventCaptions() {
periodSelect.selectByText("Day");
Assert.assertEquals("3:00 AM\n<b>Hello</b> <u>world</u>!",
getWeekEvent(0).getText());

// Switch to HTML mode
click(htmlAllowed);
Assert.assertEquals("1. HTML in event caption: true", getLogRow(0));
Assert.assertEquals("3:00 AM\nHello world!", getWeekEvent(0).getText());
}

private WebElement getMonthEvent(int dayInCalendar) {
return getMonthDay(dayInCalendar).findElement(
By.className("v-calendar-event"));
}

private WebElement getWeekEvent(int dayInCalendar) {
return getWeekDay(dayInCalendar).findElement(
By.className("v-calendar-event"));
}

private void click(CheckBoxElement htmlAllowed2) {
htmlAllowed2.findElement(By.xpath("input")).click();
}

private WebElement getMonthDay(int i) {
return calendar.findElements(By.className("v-calendar-month-day")).get(
i);
}

private WebElement getWeekDay(int i) {
return calendar.findElements(By.className("v-calendar-day-times")).get(
i);
}
}

Loading…
Cancel
Save