Fixed an issue where programmatically attaching and detaching a RichTextArea creates a JavaScript error because the RichTextArea uses a timeout to initialize its event system.  When detach is called, RichTextArea attempts to unitialize the event system before it is completely setup.

Patch by: jlabanca
Review by: ecc (desk review)
Issue: 1897



git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@2536 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 8d568bc..5fcb331 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
@@ -1,5 +1,5 @@
 /*
- * Copyright 2007 Google Inc.
+ * Copyright 2008 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
@@ -33,6 +33,7 @@
   @Override
   public native void initElement() /*-{
     var _this = this;
+    _this.@com.google.gwt.user.client.ui.impl.RichTextAreaImplStandard::initializing = true;
     window.setTimeout(function() {
       var elem = _this.@com.google.gwt.user.client.ui.impl.RichTextAreaImpl::elem;
       var doc = elem.contentWindow.document;
diff --git a/user/src/com/google/gwt/user/client/ui/impl/RichTextAreaImplMozilla.java b/user/src/com/google/gwt/user/client/ui/impl/RichTextAreaImplMozilla.java
index 38fd83e..dca7920 100644
--- a/user/src/com/google/gwt/user/client/ui/impl/RichTextAreaImplMozilla.java
+++ b/user/src/com/google/gwt/user/client/ui/impl/RichTextAreaImplMozilla.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2007 Google Inc.
+ * Copyright 2008 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
@@ -26,6 +26,7 @@
     // fully loaded.
     var _this = this;
     var iframe = _this.@com.google.gwt.user.client.ui.impl.RichTextAreaImpl::elem;
+    _this.@com.google.gwt.user.client.ui.impl.RichTextAreaImplStandard::initializing = true;
 
     iframe.onload = function() {
       // Some Mozillae have the nasty habit of calling onload again when you set
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 cde363f..0b688b6 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
@@ -1,5 +1,5 @@
 /*
- * Copyright 2007 Google Inc.
+ * Copyright 2008 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
@@ -33,6 +33,14 @@
    */
   private Element beforeInitPlaceholder = DOM.createDiv();
 
+  /**
+   * Set to true when the {@link RichTextArea} is attached to the page and
+   * {@link #initElement()} is called.  If the {@link RichTextArea} is detached
+   * before {@link #onElementInitialized()} is called, this will be set to
+   * false.  See issue 1897 for details.
+   */
+  protected boolean initializing;
+
   @Override
   public native Element createElement() /*-{
     return $doc.createElement('iframe');
@@ -66,6 +74,7 @@
     // the iframe becomes attached to the DOM. Any non-zero timeout will do
     // just fine.
     var _this = this;
+    _this.@com.google.gwt.user.client.ui.impl.RichTextAreaImplStandard::initializing = true;
     setTimeout(function() {
       // Turn on design mode.
       _this.@com.google.gwt.user.client.ui.impl.RichTextAreaImpl::elem.contentWindow.document.designMode = 'On';
@@ -224,6 +233,14 @@
 
   @Override
   public void uninitElement() {
+    // Issue 1897: initElement uses a timeout, so its possible to call this
+    // method after calling initElement, but before the event system is in
+    // place.
+    if (initializing) {
+      initializing = false;
+      return;
+    }
+
     // Unhook all custom event handlers when the element is detached.
     unhookEvents();
 
@@ -288,6 +305,13 @@
 
   @Override
   protected void onElementInitialized() {
+    // Issue 1897: This method is called after a timeout, during which time the
+    // element might by detached.
+    if (!initializing) {
+      return;
+    }
+    initializing = false;
+
     super.onElementInitialized();
 
     // When the iframe is ready, ensure cached content is set.
diff --git a/user/test/com/google/gwt/user/client/ui/RichTextAreaTest.java b/user/test/com/google/gwt/user/client/ui/RichTextAreaTest.java
index 08dbb2f..9a55823 100644
--- a/user/test/com/google/gwt/user/client/ui/RichTextAreaTest.java
+++ b/user/test/com/google/gwt/user/client/ui/RichTextAreaTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2007 Google Inc.
+ * Copyright 2008 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
@@ -23,6 +23,7 @@
  */
 public class RichTextAreaTest extends GWTTestCase {
 
+  @Override
   public String getModuleName() {
     return "com.google.gwt.user.User";
   }
@@ -41,6 +42,7 @@
     // finish initializing (on some browsers).
     this.delayTestFinish(1000);
     new Timer() {
+      @Override
       public void run() {
         RootPanel.get().remove(area);
         RootPanel.get().add(area);
@@ -54,6 +56,16 @@
   }
 
   /**
+   * Test that adding and removing an RTA before initialization completes
+   * doesn't throw an exception.
+   */
+  public void testAddRemoveBeforeInit() {
+    final RichTextArea richTextArea = new RichTextArea();
+    RootPanel.get().add(richTextArea);
+    RootPanel.get().remove(richTextArea);
+  }
+
+  /**
    * Test that a delayed set of HTML is reflected. Some platforms have timing
    * subtleties that need to be tested.
    */
@@ -61,6 +73,7 @@
     final RichTextArea richTextArea = new RichTextArea();
     RootPanel.get().add(richTextArea);
     new Timer() {
+      @Override
       public void run() {
         richTextArea.setHTML("<b>foo</b>");
         assertEquals("<b>foo</b>", richTextArea.getHTML().toLowerCase());
@@ -80,6 +93,7 @@
     richTextArea.setHTML("<b>foo</b>");
     assertEquals("<b>foo</b>", richTextArea.getHTML().toLowerCase());
     new Timer() {
+      @Override
       public void run() {
         assertEquals("<b>foo</b>", richTextArea.getHTML().toLowerCase());
         finishTest();
@@ -96,6 +110,7 @@
     final RichTextArea richTextArea = new RichTextArea();
     RootPanel.get().add(richTextArea);
     new Timer() {
+      @Override
       public void run() {
         richTextArea.setText("foo");
         assertEquals("foo", richTextArea.getText());
@@ -115,6 +130,7 @@
     richTextArea.setText("foo");
     assertEquals("foo", richTextArea.getText());
     new Timer() {
+      @Override
       public void run() {
         assertEquals("foo", richTextArea.getText());
         finishTest();