All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.gwt.user.client.ui.HTMLPanel Maven / Gradle / Ivy

There is a newer version: 2.10.0
Show newest version
/*
 * 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
 * License for the specific language governing permissions and limitations under
 * the License.
 */
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.dom.client.Element;
import com.google.gwt.safehtml.shared.SafeHtml;

import java.util.NoSuchElementException;

/**
 * A panel that contains HTML, and which can attach child widgets to identified
 * elements within that HTML.
 */
public class HTMLPanel extends ComplexPanel {

  private static Element hiddenDiv;

  /**
   * A helper method for creating unique IDs for elements within dynamically-
   * generated HTML. This is important because no two elements in a document
   * should have the same id.
   * 
   * @return a new unique identifier
   */
  public static String createUniqueId() {
    return Document.get().createUniqueId();
  }

  /**
   * 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) {
    /*
     * 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);
  }
  
  /**
   * Initializes the panel's HTML from a given {@link SafeHtml} object.
   * 
   * Similar to {@link #HTMLPanel(String)}
   * 
   * @param safeHtml the html to set.
   */
  public HTMLPanel(SafeHtml safeHtml) {
    this(safeHtml.asString());
  }

  /**
   * 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.  and  simply won't, the property is read only.
     * 

will explode if you incorrectly try to put another

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("'); // 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. * * @param widget the widget to be added * @param id the id of the element within which it will be contained */ public void add(Widget widget, String id) { final Element elem = getElementById(id); if (elem == null) { throw new NoSuchElementException(id); } add(widget, elem); } /** * Adds a child widget to the panel, contained within an HTML * element. It is up to the caller to ensure that the given element * is a child of this panel's root element. * * @param widget the widget to be added * @param elem the element within which it will be contained */ public void add(Widget widget, Element elem) { com.google.gwt.user.client.Element clientElem = elem.cast(); super.add(widget, clientElem); } /** * Adds a child widget to the panel, replacing the HTML element. * * @param widget the widget to be added * @param toReplace the element to be replaced by the widget */ public final void addAndReplaceElement(Widget widget, Element toReplace) { com.google.gwt.user.client.Element clientElem = toReplace.cast(); addAndReplaceElement(widget, clientElem); } /** * Adds a child widget to the panel, replacing the HTML element. * * @param widget the widget to be added * @param toReplace the element to be replaced by the widget * @deprecated use {@link #addAndReplaceElement(Widget, Element)} */ @Deprecated public void addAndReplaceElement(Widget widget, com.google.gwt.user.client.Element toReplace) { // Logic pulled from super.add(), replacing the element rather than adding. widget.removeFromParent(); getChildren().add(widget); toReplace.getParentNode().replaceChild(widget.getElement(), toReplace); adopt(widget); } /** * Adds a child widget to the panel, replacing the HTML element specified by a * given id. * * @param widget the widget to be added * @param id the id of the element to be replaced by the widget */ public void addAndReplaceElement(Widget widget, String id) { final Element toReplace = getElementById(id); if (toReplace == null) { throw new NoSuchElementException(id); } addAndReplaceElement(widget, toReplace); } /** * Finds an {@link Element element} within this panel by its id. * * This method uses * {@link com.google.gwt.dom.client.Document#getElementById(String)}, so the * id must still be unique within the document. * * @param id the id of the element to be found * @return the element with the given id, or null if none is found */ public com.google.gwt.user.client.Element getElementById(String id) { Element elem = isAttached() ? Document.get().getElementById(id) : attachToDomAndGetElement(id); return elem.cast(); } /** * Performs a {@link DOM#getElementById(String)} after attaching the panel's * element into a hidden DIV in the document's body. Attachment is necessary * to be able to use the native getElementById. The panel's element will be * re-attached to its original parent (if any) after the method returns. * * @param id the id whose associated element is to be retrieved * @return the associated element, or null if none is found */ private Element attachToDomAndGetElement(String id) { // If the hidden DIV has not been created, create it. if (hiddenDiv == null) { hiddenDiv = Document.get().createDivElement(); UIObject.setVisible(hiddenDiv, false); RootPanel.getBodyElement().appendChild(hiddenDiv); } // Hang on to the panel's original parent and sibling elements so that it // can be replaced. Element origParent = getElement().getParentElement(); Element origSibling = getElement().getNextSiblingElement(); // Attach the panel's element to the hidden div. hiddenDiv.appendChild(getElement()); // Now that we're attached to the DOM, we can use getElementById. Element child = Document.get().getElementById(id); // Put the panel's element back where it was. if (origParent != null) { origParent.insertBefore(getElement(), origSibling); } else { hiddenDiv.removeChild(getElement()); } return child; } }