This change allows setHTML/getHTML and setText/getText to work on a RichTextArea before the underlying iframe is properly initialized. It does so by caching the data in a temporary div, and copying the contents into the iframe once its ready.
Suggested by: knorton
Review by: knorton
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@1168 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/user/client/ui/impl/RichTextAreaImplIE6.java b/user/src/com/google/gwt/user/client/ui/impl/RichTextAreaImplIE6.java
index 4f47335..c186e13 100644
--- a/user/src/com/google/gwt/user/client/ui/impl/RichTextAreaImplIE6.java
+++ b/user/src/com/google/gwt/user/client/ui/impl/RichTextAreaImplIE6.java
@@ -62,25 +62,28 @@
body.onclick = handler;
}-*/;
+ private static native void setText(Element elem, String text) /*-{
+ elem.contentWindow.document.body.innerText = text;
+ }-*/;
+
public Element createElement() {
Element elem = super.createElement();
DOM.setElementProperty(elem, "src", "javascript:''");
return elem;
}
- public String getText() {
- return getText(elem);
- }
-
public native void initElement() /*-{
- var elem = this.@com.google.gwt.user.client.ui.impl.RichTextAreaImpl::elem;
-
+ var _this = this;
window.setTimeout(function() {
+ var elem = _this.@com.google.gwt.user.client.ui.impl.RichTextAreaImpl::elem;
var doc = elem.contentWindow.document;
doc.write('<html><body CONTENTEDITABLE="true"></body></html>');
// Initialize event handling.
@com.google.gwt.user.client.ui.impl.RichTextAreaImplIE6::initEvents(Lcom/google/gwt/user/client/Element;)(elem);
+
+ // Send notification that the iframe has reached design mode.
+ _this.@com.google.gwt.user.client.ui.impl.RichTextAreaImplStandard::onElementInitialized()();
}, 1);
}-*/;
@@ -89,6 +92,14 @@
detachEvents(elem);
}
+ protected String getTextImpl() {
+ return getText(elem);
+ }
+
+ protected void setTextImpl(String text) {
+ setText(elem, text);
+ }
+
boolean isRichEditingActive(Element elem) {
return true;
}
diff --git a/user/src/com/google/gwt/user/client/ui/impl/RichTextAreaImplOpera.java b/user/src/com/google/gwt/user/client/ui/impl/RichTextAreaImplOpera.java
index 1b2b997..07c0dad 100644
--- a/user/src/com/google/gwt/user/client/ui/impl/RichTextAreaImplOpera.java
+++ b/user/src/com/google/gwt/user/client/ui/impl/RichTextAreaImplOpera.java
@@ -52,20 +52,6 @@
return super.getElement();
}
- public String getHTML() {
- if (old != null) {
- return old.getHTML();
- }
- return super.getHTML();
- }
-
- public String getText() {
- if (old != null) {
- return old.getText();
- }
- return super.getText();
- }
-
public void hookEvents(RichTextArea owner) {
if (old != null) {
old.hookEvents(owner);
@@ -105,26 +91,40 @@
}
}-*/;
- public void setHTML(String html) {
- if (old != null) {
- old.setHTML(html);
- return;
- }
- super.setHTML(html);
- }
-
- public void setText(String text) {
- if (old != null) {
- old.setText(text);
- return;
- }
- super.setText(text);
- }
-
public void unhookEvents() {
if (old != null) {
old.unhookEvents();
}
super.unhookEvents();
}
+
+ protected String getHTMLImpl() {
+ if (old != null) {
+ return old.getHTML();
+ }
+ return super.getHTMLImpl();
+ }
+
+ protected String getTextImpl() {
+ if (old != null) {
+ return old.getText();
+ }
+ return super.getTextImpl();
+ }
+
+ protected void setHTMLImpl(String html) {
+ if (old != null) {
+ old.setHTML(html);
+ return;
+ }
+ super.setHTMLImpl(html);
+ }
+
+ protected void setTextImpl(String text) {
+ if (old != null) {
+ old.setText(text);
+ return;
+ }
+ super.setTextImpl(text);
+ }
}
diff --git a/user/src/com/google/gwt/user/client/ui/impl/RichTextAreaImplStandard.java b/user/src/com/google/gwt/user/client/ui/impl/RichTextAreaImplStandard.java
index 6b9eaab..1d98669 100644
--- a/user/src/com/google/gwt/user/client/ui/impl/RichTextAreaImplStandard.java
+++ b/user/src/com/google/gwt/user/client/ui/impl/RichTextAreaImplStandard.java
@@ -15,6 +15,7 @@
*/
package com.google.gwt.user.client.ui.impl;
+import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.ui.RichTextArea;
import com.google.gwt.user.client.ui.RichTextArea.FontSize;
@@ -26,6 +27,12 @@
public class RichTextAreaImplStandard extends RichTextAreaImpl implements
RichTextArea.BasicFormatter, RichTextArea.ExtendedFormatter {
+ /**
+ * Holds a cached copy of any user setHTML/setText actions until the real
+ * text area is fully initialized. Becomes <code>null</code> after init.
+ */
+ private Element beforeInitPlaceholder = DOM.createDiv();
+
public native Element createElement() /*-{
return $doc.createElement('iframe');
}-*/;
@@ -42,13 +49,13 @@
return queryCommandValue("ForeColor");
}
- public native String getHTML() /*-{
- return this.@com.google.gwt.user.client.ui.impl.RichTextAreaImpl::elem.contentWindow.document.body.innerHTML;
- }-*/;
+ public final String getHTML() {
+ return beforeInitPlaceholder == null ? getHTMLImpl() : DOM.getInnerHTML(beforeInitPlaceholder);
+ }
- public native String getText() /*-{
- return this.@com.google.gwt.user.client.ui.impl.RichTextAreaImpl::elem.contentWindow.document.body.textContent;
- }-*/;
+ public final String getText() {
+ return beforeInitPlaceholder == null ? getTextImpl() : DOM.getInnerText(beforeInitPlaceholder);
+ }
public native void hookEvents(RichTextArea owner) /*-{
this.@com.google.gwt.user.client.ui.impl.RichTextAreaImpl::elem.__listener = owner;
@@ -65,6 +72,9 @@
// Initialize event handling.
_this.@com.google.gwt.user.client.ui.impl.RichTextAreaImplStandard::initEvents()();
+
+ // Send notification that the iframe has reached design mode.
+ _this.@com.google.gwt.user.client.ui.impl.RichTextAreaImplStandard::onElementInitialized()();
}, 1);
}-*/;
@@ -160,9 +170,13 @@
execCommand("ForeColor", color);
}
- public native void setHTML(String html) /*-{
- this.@com.google.gwt.user.client.ui.impl.RichTextAreaImpl::elem.contentWindow.document.body.innerHTML = html;
- }-*/;
+ public final void setHTML(String html) {
+ if (beforeInitPlaceholder == null) {
+ setHTMLImpl(html);
+ } else {
+ DOM.setInnerHTML(beforeInitPlaceholder, html);
+ }
+ }
public void setJustification(Justification justification) {
if (justification == Justification.CENTER) {
@@ -174,9 +188,13 @@
}
}
- public native void setText(String text) /*-{
- this.@com.google.gwt.user.client.ui.impl.RichTextAreaImpl::elem.contentWindow.document.body.textContent = text;
- }-*/;
+ public final void setText(String text) {
+ if (beforeInitPlaceholder == null) {
+ setTextImpl(text);
+ } else {
+ DOM.setInnerText(beforeInitPlaceholder, text);
+ }
+ }
public void toggleBold() {
execCommand("Bold", "false");
@@ -202,6 +220,22 @@
execCommand("Underline", "False");
}
+ protected native String getHTMLImpl() /*-{
+ return this.@com.google.gwt.user.client.ui.impl.RichTextAreaImpl::elem.contentWindow.document.body.innerHTML;
+ }-*/;
+
+ protected native String getTextImpl() /*-{
+ return this.@com.google.gwt.user.client.ui.impl.RichTextAreaImpl::elem.contentWindow.document.body.textContent;
+ }-*/;
+
+ protected native void setHTMLImpl(String html) /*-{
+ this.@com.google.gwt.user.client.ui.impl.RichTextAreaImpl::elem.contentWindow.document.body.innerHTML = html;
+ }-*/;
+
+ protected native void setTextImpl(String text) /*-{
+ this.@com.google.gwt.user.client.ui.impl.RichTextAreaImpl::elem.contentWindow.document.body.textContent = text;
+ }-*/;
+
void execCommand(String cmd, String param) {
if (isRichEditingActive(elem)) {
// When executing a command, focus the iframe first, since some commands
@@ -239,6 +273,12 @@
return ((e.contentWindow.document.designMode).toUpperCase()) == 'ON';
}-*/;
+ void onElementInitialized() {
+ // When the iframe is ready, ensure cached content is set.
+ setHTMLImpl(DOM.getInnerHTML(beforeInitPlaceholder));
+ beforeInitPlaceholder = null;
+ }
+
boolean queryCommandState(String cmd) {
if (isRichEditingActive(elem)) {
// When executing a command, focus the iframe first, since some commands
diff --git a/user/test/com/google/gwt/user/client/ui/RichTextAreaTest.java b/user/test/com/google/gwt/user/client/ui/RichTextAreaTest.java
new file mode 100644
index 0000000..c4a7953
--- /dev/null
+++ b/user/test/com/google/gwt/user/client/ui/RichTextAreaTest.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2007 Google Inc.
+ *
+ * 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.google.gwt.user.client.ui;
+
+import com.google.gwt.junit.client.GWTTestCase;
+import com.google.gwt.user.client.Timer;
+
+/**
+ * Tests the {@link RichTextArea} widget.
+ */
+public class RichTextAreaTest extends GWTTestCase {
+
+ public String getModuleName() {
+ return "com.google.gwt.user.User";
+ }
+
+ /**
+ * Test that a delayed set of HTML is reflected. Some platforms have timing
+ * subtleties that need to be tested.
+ */
+ public void testSetHTMLAfterInit() {
+ final RichTextArea richTextArea = new RichTextArea();
+ RootPanel.get().add(richTextArea);
+ new Timer() {
+ public void run() {
+ richTextArea.setHTML("<b>foo</b>");
+ assertEquals("<b>foo</b>", richTextArea.getHTML().toLowerCase());
+ finishTest();
+ }
+ }.schedule(200);
+ delayTestFinish(1000);
+ }
+
+ /**
+ * Test that an immediate set of HTML is reflected immediately and after a
+ * delay. Some platforms have timing subtleties that need to be tested.
+ */
+ public void testSetHTMLBeforeInit() {
+ final RichTextArea richTextArea = new RichTextArea();
+ RootPanel.get().add(richTextArea);
+ richTextArea.setHTML("<b>foo</b>");
+ assertEquals("<b>foo</b>", richTextArea.getHTML().toLowerCase());
+ new Timer() {
+ public void run() {
+ assertEquals("<b>foo</b>", richTextArea.getHTML().toLowerCase());
+ finishTest();
+ }
+ }.schedule(200);
+ delayTestFinish(1000);
+ }
+
+ /**
+ * Test that delayed set of text is reflected. Some platforms have timing
+ * subtleties that need to be tested.
+ */
+ public void testSetTextAfterInit() {
+ final RichTextArea richTextArea = new RichTextArea();
+ RootPanel.get().add(richTextArea);
+ new Timer() {
+ public void run() {
+ richTextArea.setText("foo");
+ assertEquals("foo", richTextArea.getText());
+ finishTest();
+ }
+ }.schedule(200);
+ delayTestFinish(1000);
+ }
+
+ /**
+ * Test that an immediate set of text is reflected immediately and after a
+ * delay. Some platforms have timing subtleties that need to be tested.
+ */
+ public void testSetTextBeforeInit() {
+ final RichTextArea richTextArea = new RichTextArea();
+ RootPanel.get().add(richTextArea);
+ richTextArea.setText("foo");
+ assertEquals("foo", richTextArea.getText());
+ new Timer() {
+ public void run() {
+ assertEquals("foo", richTextArea.getText());
+ finishTest();
+ }
+ }.schedule(200);
+ delayTestFinish(1000);
+ }
+}