Allow flexibilty on root tag of HTMLPanel

Merge branch 'fix-htmlpanel'


git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@5760 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/user/client/ui/HTMLPanel.java b/user/src/com/google/gwt/user/client/ui/HTMLPanel.java
index 1bbdeb6..a00b1c5 100644
--- a/user/src/com/google/gwt/user/client/ui/HTMLPanel.java
+++ b/user/src/com/google/gwt/user/client/ui/HTMLPanel.java
@@ -15,6 +15,8 @@
  */
 package com.google.gwt.user.client.ui;
 
+import com.google.gwt.dom.client.DivElement;
+import com.google.gwt.dom.client.Document;
 import com.google.gwt.user.client.DOM;
 import com.google.gwt.user.client.Element;
 
@@ -40,17 +42,55 @@
   }
 
   /**
-   * Creates an HTML panel with the specified HTML contents. Any element within
-   * this HTML that has a specified id can contain a child widget.
+   * Creates an HTML panel with the specified HTML contents inside a DIV
+   * element. Any element within this HTML that has a specified id can contain a
+   * child widget.
    * 
    * @param html the panel's HTML
    */
   public HTMLPanel(String html) {
-    setElement(DOM.createDiv());
-    DOM.setInnerHTML(getElement(), html);
+    /*
+     * Normally would call this("div", html), but that method
+     * has some slightly expensive IE defensiveness that we just
+     * don't need for a div
+     */
+    setElement(Document.get().createDivElement());
+    getElement().setInnerHTML(html);
   }
 
   /**
+   * Creates an HTML panel whose root element has the given tag, and with the
+   * specified HTML contents. Any element within this HTML that has a specified
+   * id can contain a child widget.
+   * 
+   * @param tag the tag of the root element
+   * @param html the panel's HTML
+   */
+  public HTMLPanel(String tag, String html) {
+    /*
+     * IE has very arbitrary rules about what will and will not accept
+     * innerHTML. <table> and <tbody> simply won't, the property is read only.
+     * <p> will explode if you incorrectly try to put another <p> inside of it.
+     * And who knows what else.
+     * 
+     * However, if you cram a complete, possibly incorrect structure inside a
+     * div, IE will swallow it gladly. So that's what we do here in the name of
+     * IE robustification.
+     */
+    StringBuilder b = new StringBuilder();
+    b.append('<').append(tag).append('>').append(html);
+    b.append("</").append(tag).append('>');
+    
+    // We could use the static hiddenDiv, but that thing is attached
+    // to the document. The caller might not want that.
+    
+    DivElement scratchDiv = Document.get().createDivElement();
+    scratchDiv.setInnerHTML(b.toString());
+    setElement(scratchDiv.getFirstChildElement());
+    getElement().removeFromParent();
+  }
+  
+  /**
    * Adds a child widget to the panel, contained within the HTML element
    * specified by a given id.
    * 
diff --git a/user/test/com/google/gwt/user/client/ui/HTMLPanelTest.java b/user/test/com/google/gwt/user/client/ui/HTMLPanelTest.java
index 9e7f8ac..9409b7d 100644
--- a/user/test/com/google/gwt/user/client/ui/HTMLPanelTest.java
+++ b/user/test/com/google/gwt/user/client/ui/HTMLPanelTest.java
@@ -1,12 +1,12 @@
 /*
  * 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
  * 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
@@ -120,6 +120,29 @@
   }
 
   /**
+   * Tests table root tag.
+   */
+  public void testCustomRootTagAsTable() {
+    HTMLPanel hp = new HTMLPanel("table",
+        "<tr><td>Hello <span id='labelHere'></span></td></tr></table>");
+    InlineLabel label = new InlineLabel("World");
+    hp.addAndReplaceElement(label, "labelHere");
+
+    Element parent = label.getElement().getParentElement();
+    assertEquals("td", parent.getTagName().toLowerCase());
+
+    parent = parent.getParentElement();
+    assertEquals("tr", parent.getTagName().toLowerCase());
+
+    while (parent != null && parent != hp.getElement()) {
+      parent = parent.getParentElement();
+    }
+
+    assertNotNull(parent);
+    assertEquals("table", parent.getTagName().toLowerCase());
+  }
+
+  /**
    * Ensure that {@link HTMLPanel#getElementById(String)} behaves properly in
    * both attached and unattached states.
    */