Fixes Issue #1741
The homegrown version of getElementById for in HTMLPanel was slow.
This change ensures that we are able to use the native
getElementById for both attached and unattached cases of
add(Widget, Sring).
Review by: jgw, jlabanca
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@1834 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 0c907e9..323ed2e 100644
--- a/user/src/com/google/gwt/user/client/ui/HTMLPanel.java
+++ b/user/src/com/google/gwt/user/client/ui/HTMLPanel.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
@@ -39,6 +39,8 @@
return "HTMLPanel_" + (++sUid);
}
+ private Element hiddenDiv;
+
/**
* Creates an HTML panel with the specified HTML contents. Any element within
* this HTML that has a specified id can contain a child widget.
@@ -58,7 +60,9 @@
* @param id the id of the element within which it will be contained
*/
public void add(Widget widget, String id) {
- Element elem = getElementById(getElement(), id);
+ final Element elem = (isAttached()) ? DOM.getElementById(id)
+ : attachToDomAndGetElement(id);
+
if (elem == null) {
throw new NoSuchElementException(id);
}
@@ -66,26 +70,36 @@
super.add(widget, elem);
}
- /*
- * Implements getElementById() downward from the given element. We need to do
- * this because {@link #add(Widget, String)} must often be called before the
- * panel is attached to the DOM, so {@link Dom#getElementById} won't yet work.
+ @Override
+ protected void onLoad() {
+ if (hiddenDiv != null) {
+ // This widget's element has already been moved, just need to remove the
+ // hidden DIV.
+ DOM.removeChild(RootPanel.getBodyElement(), hiddenDiv);
+ hiddenDiv = null;
+ }
+ super.onLoad();
+ }
+
+ /**
+ * Performs a {@link DOM#getElementById(String)} after attaching the widget's
+ * element into a hidden DIV in the document's body. Attachment is necessary
+ * to be able to use the native getElementById. The hidden DIV will remain
+ * attached to the DOM until the Widget itself is fully attached.
+ *
+ * @param id the id whose associated element is to be retrieved
+ * @return the associated element, or <code>null</code> if none is found
*/
- private Element getElementById(Element elem, String id) {
- String elemId = DOM.getElementProperty(elem, "id");
- if ((elemId != null) && elemId.equals(id)) {
- return elem;
+ private Element attachToDomAndGetElement(String id) {
+ // If the hidden DIV has not been created, create it.
+ if (hiddenDiv == null) {
+ hiddenDiv = DOM.createDiv();
+ UIObject.setVisible(hiddenDiv, false);
+ DOM.appendChild(hiddenDiv, getElement());
+ DOM.appendChild(RootPanel.getBodyElement(), hiddenDiv);
}
- Element child = DOM.getFirstChild(elem);
- while (child != null) {
- Element ret = getElementById(child, id);
- if (ret != null) {
- return ret;
- }
- child = DOM.getNextSibling(child);
- }
-
- return null;
+ // Now that we're attached to the DOM, we can use getElementById.
+ return DOM.getElementById(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 a9e9e2b..74205e4 100644
--- a/user/test/com/google/gwt/user/client/ui/HTMLPanelTest.java
+++ b/user/test/com/google/gwt/user/client/ui/HTMLPanelTest.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
@@ -16,6 +16,7 @@
package com.google.gwt.user.client.ui;
import com.google.gwt.junit.client.GWTTestCase;
+import com.google.gwt.user.client.DOM;
/**
* Tests the HTMLPanel widget.
@@ -32,6 +33,21 @@
return "com.google.gwt.user.User";
}
+ /**
+ * Tests {@link HTMLPanel#add(Widget, String)}.
+ */
+ public void testAddToElementWithId() {
+ Label labelA = new Label("A"), labelB = new Label("B");
+ HTMLPanel p = new HTMLPanel("<div id=\"a\"></div><div id=\"b\"></div>");
+ p.add(labelA, "a");
+ p.add(labelB, "b");
+ // Ensure that both Label's have the correct parent.
+ assertEquals("a", DOM.getElementAttribute(
+ DOM.getParent(labelA.getElement()), "id"));
+ assertEquals("b", DOM.getElementAttribute(
+ DOM.getParent(labelB.getElement()), "id"));
+ }
+
public void testAttachDetachOrder() {
HTMLPanel p = new HTMLPanel("<div id='w00t'></div>");
HasWidgetsTester.testAll(p, new Adder());