summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--client/src/com/vaadin/client/ui/VPopupView.java8
-rw-r--r--client/src/com/vaadin/client/ui/VRichTextArea.java165
-rw-r--r--client/src/com/vaadin/client/ui/richtextarea/RichTextAreaConnector.java42
-rw-r--r--uitest/src/com/vaadin/tests/components/richtextarea/RichTextAreaUpdateWhileTyping.html42
-rw-r--r--uitest/src/com/vaadin/tests/components/richtextarea/RichTextAreaUpdateWhileTyping.java51
5 files changed, 229 insertions, 79 deletions
diff --git a/client/src/com/vaadin/client/ui/VPopupView.java b/client/src/com/vaadin/client/ui/VPopupView.java
index 05fbd2c073..626780efee 100644
--- a/client/src/com/vaadin/client/ui/VPopupView.java
+++ b/client/src/com/vaadin/client/ui/VPopupView.java
@@ -40,6 +40,7 @@ import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.Widget;
import com.vaadin.client.ApplicationConnection;
import com.vaadin.client.ComponentConnector;
+import com.vaadin.client.Util;
import com.vaadin.client.VCaptionWrapper;
import com.vaadin.client.VConsole;
import com.vaadin.client.ui.ShortcutActionHandler.ShortcutActionHandlerOwner;
@@ -313,8 +314,11 @@ public class VPopupView extends HTML implements Iterable<Widget> {
private void checkForRTE(Widget popupComponentWidget2) {
if (popupComponentWidget2 instanceof VRichTextArea) {
- ((VRichTextArea) popupComponentWidget2)
- .synchronizeContentToServer();
+ ComponentConnector rtaConnector = Util
+ .findConnectorFor(popupComponentWidget2);
+ if (rtaConnector != null) {
+ rtaConnector.flush();
+ }
} else if (popupComponentWidget2 instanceof HasWidgets) {
HasWidgets hw = (HasWidgets) popupComponentWidget2;
Iterator<Widget> iterator = hw.iterator();
diff --git a/client/src/com/vaadin/client/ui/VRichTextArea.java b/client/src/com/vaadin/client/ui/VRichTextArea.java
index 1498c096ed..7ed6e7c78a 100644
--- a/client/src/com/vaadin/client/ui/VRichTextArea.java
+++ b/client/src/com/vaadin/client/ui/VRichTextArea.java
@@ -16,11 +16,12 @@
package com.vaadin.client.ui;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
import com.google.gwt.core.client.Scheduler;
-import com.google.gwt.event.dom.client.BlurEvent;
import com.google.gwt.event.dom.client.BlurHandler;
-import com.google.gwt.event.dom.client.ChangeEvent;
-import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.KeyDownEvent;
import com.google.gwt.event.dom.client.KeyDownHandler;
import com.google.gwt.event.dom.client.KeyPressEvent;
@@ -49,8 +50,8 @@ import com.vaadin.client.ui.richtextarea.VRichTextToolbar;
* @author Vaadin Ltd.
*
*/
-public class VRichTextArea extends Composite implements Field, ChangeHandler,
- BlurHandler, KeyPressHandler, KeyDownHandler, Focusable {
+public class VRichTextArea extends Composite implements Field, KeyPressHandler,
+ KeyDownHandler, Focusable {
/**
* The input node CSS classname.
@@ -91,11 +92,10 @@ public class VRichTextArea extends Composite implements Field, ChangeHandler,
private ShortcutActionHandlerOwner hasShortcutActionHandler;
- /** For internal use only. May be removed or replaced in the future. */
- public String currentValue = "";
-
private boolean readOnly = false;
+ private final Map<BlurHandler, HandlerRegistration> blurHandlers = new HashMap<BlurHandler, HandlerRegistration>();
+
public VRichTextArea() {
createRTAComponents();
fp.add(formatter);
@@ -110,9 +110,19 @@ public class VRichTextArea extends Composite implements Field, ChangeHandler,
private void createRTAComponents() {
rta = new RichTextArea();
rta.setWidth("100%");
- rta.addBlurHandler(this);
rta.addKeyDownHandler(this);
formatter = new VRichTextToolbar(rta);
+
+ // Add blur handlers
+ for (Entry<BlurHandler, HandlerRegistration> handler : blurHandlers
+ .entrySet()) {
+
+ // Remove old registration
+ handler.getValue().removeHandler();
+
+ // Add blur handlers
+ addBlurHandler(handler.getKey());
+ }
}
public void setEnabled(boolean enabled) {
@@ -127,6 +137,7 @@ public class VRichTextArea extends Composite implements Field, ChangeHandler,
* Swaps html to rta and visa versa.
*/
private void swapEditableArea() {
+ String value = getValue();
if (html.isAttached()) {
fp.remove(html);
if (BrowserInfo.get().isWebkit()) {
@@ -134,13 +145,12 @@ public class VRichTextArea extends Composite implements Field, ChangeHandler,
createRTAComponents(); // recreate new RTA to bypass #5379
fp.add(formatter);
}
- rta.setHTML(currentValue);
fp.add(rta);
} else {
- html.setHTML(currentValue);
fp.remove(rta);
fp.add(html);
}
+ setValue(value);
}
/** For internal use only. May be removed or replaced in the future. */
@@ -180,62 +190,6 @@ public class VRichTextArea extends Composite implements Field, ChangeHandler,
return readOnly;
}
- // TODO is this really used, or does everything go via onBlur() only?
- @Override
- public void onChange(ChangeEvent event) {
- synchronizeContentToServer();
- }
-
- /**
- * Method is public to let popupview force synchronization on close.
- */
- public void synchronizeContentToServer() {
- if (client != null && id != null) {
- final String html = sanitizeRichTextAreaValue(rta.getHTML());
- if (!html.equals(currentValue)) {
- client.updateVariable(id, "text", html, immediate);
- currentValue = html;
- }
- }
- }
-
- /**
- * Browsers differ in what they return as the content of a visually empty
- * rich text area. This method is used to normalize these to an empty
- * string. See #8004.
- *
- * @param html
- * @return cleaned html string
- */
- private String sanitizeRichTextAreaValue(String html) {
- BrowserInfo browser = BrowserInfo.get();
- String result = html;
- if (browser.isFirefox()) {
- if ("<br>".equals(html)) {
- result = "";
- }
- } else if (browser.isWebkit()) {
- if ("<div><br></div>".equals(html)) {
- result = "";
- }
- } else if (browser.isIE()) {
- if ("<P>&nbsp;</P>".equals(html)) {
- result = "";
- }
- } else if (browser.isOpera()) {
- if ("<br>".equals(html) || "<p><br></p>".equals(html)) {
- result = "";
- }
- }
- return result;
- }
-
- @Override
- public void onBlur(BlurEvent event) {
- synchronizeContentToServer();
- // TODO notify possible server side blur/focus listeners
- }
-
/**
* @return space used by components paddings and borders
*/
@@ -409,4 +363,81 @@ public class VRichTextArea extends Composite implements Field, ChangeHandler,
rta.setTabIndex(index);
}
+ /**
+ * Set the value of the text area
+ *
+ * @param value
+ * The text value. Can be html.
+ */
+ public void setValue(String value) {
+ if (rta.isAttached()) {
+ rta.setHTML(value);
+ } else {
+ html.setHTML(value);
+ }
+ }
+
+ /**
+ * Get the value the text area
+ */
+ public String getValue() {
+ if (rta.isAttached()) {
+ return rta.getHTML();
+ } else {
+ return html.getHTML();
+ }
+ }
+
+ /**
+ * Browsers differ in what they return as the content of a visually empty
+ * rich text area. This method is used to normalize these to an empty
+ * string. See #8004.
+ *
+ * @return cleaned html string
+ */
+ public String getSanitazedValue() {
+ BrowserInfo browser = BrowserInfo.get();
+ String result = getValue();
+ if (browser.isFirefox()) {
+ if ("<br>".equals(html)) {
+ result = "";
+ }
+ } else if (browser.isWebkit()) {
+ if ("<div><br></div>".equals(html)) {
+ result = "";
+ }
+ } else if (browser.isIE()) {
+ if ("<P>&nbsp;</P>".equals(html)) {
+ result = "";
+ }
+ } else if (browser.isOpera()) {
+ if ("<br>".equals(html) || "<p><br></p>".equals(html)) {
+ result = "";
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Adds a blur handler to the component.
+ *
+ * @param blurHandler
+ * the blur handler to add
+ */
+ public void addBlurHandler(BlurHandler blurHandler) {
+ blurHandlers.put(blurHandler, rta.addBlurHandler(blurHandler));
+ }
+
+ /**
+ * Removes a blur handler.
+ *
+ * @param blurHandler
+ * the handler to remove
+ */
+ public void removeBlurHandler(BlurHandler blurHandler) {
+ HandlerRegistration registration = blurHandlers.remove(blurHandler);
+ if (registration != null) {
+ registration.removeHandler();
+ }
+ }
}
diff --git a/client/src/com/vaadin/client/ui/richtextarea/RichTextAreaConnector.java b/client/src/com/vaadin/client/ui/richtextarea/RichTextAreaConnector.java
index 36182464a3..8135777c0a 100644
--- a/client/src/com/vaadin/client/ui/richtextarea/RichTextAreaConnector.java
+++ b/client/src/com/vaadin/client/ui/richtextarea/RichTextAreaConnector.java
@@ -15,6 +15,8 @@
*/
package com.vaadin.client.ui.richtextarea;
+import com.google.gwt.event.dom.client.BlurEvent;
+import com.google.gwt.event.dom.client.BlurHandler;
import com.google.gwt.user.client.Event;
import com.vaadin.client.ApplicationConnection;
import com.vaadin.client.Paintable;
@@ -24,33 +26,47 @@ import com.vaadin.client.ui.ShortcutActionHandler.BeforeShortcutActionListener;
import com.vaadin.client.ui.VRichTextArea;
import com.vaadin.shared.ui.Connect;
import com.vaadin.shared.ui.Connect.LoadStyle;
+import com.vaadin.shared.util.SharedUtil;
import com.vaadin.ui.RichTextArea;
@Connect(value = RichTextArea.class, loadStyle = LoadStyle.LAZY)
public class RichTextAreaConnector extends AbstractFieldConnector implements
Paintable, BeforeShortcutActionListener {
+ /*
+ * Last value received from the server
+ */
+ private String cachedValue = "";
+
+ @Override
+ protected void init() {
+ getWidget().addBlurHandler(new BlurHandler() {
+
+ @Override
+ public void onBlur(BlurEvent event) {
+ flush();
+ }
+ });
+ }
+
@Override
public void updateFromUIDL(final UIDL uidl, ApplicationConnection client) {
getWidget().client = client;
getWidget().id = uidl.getId();
if (uidl.hasVariable("text")) {
- getWidget().currentValue = uidl.getStringVariable("text");
- if (getWidget().rta.isAttached()) {
- getWidget().rta.setHTML(getWidget().currentValue);
- } else {
- getWidget().html.setHTML(getWidget().currentValue);
+ String newValue = uidl.getStringVariable("text");
+ if (!SharedUtil.equals(newValue, cachedValue)) {
+ getWidget().setValue(newValue);
+ cachedValue = newValue;
}
}
- if (isRealUpdate(uidl)) {
- getWidget().setEnabled(isEnabled());
- }
if (!isRealUpdate(uidl)) {
return;
}
+ getWidget().setEnabled(isEnabled());
getWidget().setReadOnly(isReadOnly());
getWidget().immediate = getState().immediate;
int newMaxLength = uidl.hasAttribute("maxLength") ? uidl
@@ -85,7 +101,13 @@ public class RichTextAreaConnector extends AbstractFieldConnector implements
@Override
public void flush() {
- getWidget().synchronizeContentToServer();
+ if (getConnection() != null && getConnectorId() != null) {
+ final String html = getWidget().getSanitazedValue();
+ if (!html.equals(cachedValue)) {
+ getConnection().updateVariable(getConnectorId(), "text", html,
+ getState().immediate);
+ getWidget().setValue(html);
+ }
+ }
};
-
}
diff --git a/uitest/src/com/vaadin/tests/components/richtextarea/RichTextAreaUpdateWhileTyping.html b/uitest/src/com/vaadin/tests/components/richtextarea/RichTextAreaUpdateWhileTyping.html
new file mode 100644
index 0000000000..6ddd1b4097
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/richtextarea/RichTextAreaUpdateWhileTyping.html
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<link rel="selenium.base" href="http://localhost:7070/" />
+<title>New Test</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">New Test</td></tr>
+</thead><tbody>
+<tr>
+ <td>open</td>
+ <td>/run/com.vaadin.tests.components.richtextarea.RichTextAreaUpdateWhileTyping?restartApplication</td>
+ <td></td>
+</tr>
+<tr>
+ <td>selectFrame</td>
+ <td>xpath=//div[@id='rta']/iframe</td>
+ <td></td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>//body</td>
+ <td>This text should be visible, even after an update while I type.</td>
+</tr>
+<tr>
+ <td>pause</td>
+ <td>2000</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>//body</td>
+ <td>This text should be visible, even after an update while I type.</td>
+</tr>
+
+</tbody></table>
+</body>
+</html>
diff --git a/uitest/src/com/vaadin/tests/components/richtextarea/RichTextAreaUpdateWhileTyping.java b/uitest/src/com/vaadin/tests/components/richtextarea/RichTextAreaUpdateWhileTyping.java
new file mode 100644
index 0000000000..df1d6df463
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/richtextarea/RichTextAreaUpdateWhileTyping.java
@@ -0,0 +1,51 @@
+package com.vaadin.tests.components.richtextarea;
+
+import com.vaadin.data.Property;
+import com.vaadin.data.Property.ValueChangeEvent;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.shared.ui.progressindicator.ProgressIndicatorServerRpc;
+import com.vaadin.tests.components.AbstractComponentTest;
+import com.vaadin.tests.components.AbstractTestCase;
+import com.vaadin.tests.components.AbstractTestUI;
+import com.vaadin.ui.ProgressIndicator;
+import com.vaadin.ui.RichTextArea;
+
+public class RichTextAreaUpdateWhileTyping extends AbstractTestUI {
+
+ private RichTextArea rta;
+
+ @Override
+ protected void setup(VaadinRequest request) {
+
+ // Progress indicator for changing the value of the RTA
+ ProgressIndicator pi = new ProgressIndicator() {
+ {
+ registerRpc(new ProgressIndicatorServerRpc() {
+
+ @Override
+ public void poll() {
+ rta.markAsDirty();
+ }
+ });
+ }
+ };
+ pi.setHeight("0px");
+ addComponent(pi);
+
+ rta = new RichTextArea();
+ rta.setId("rta");
+ rta.setImmediate(true);
+ addComponent(rta);
+ }
+
+ @Override
+ protected String getTestDescription() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return 11741;
+ }
+}