Package com.google.gwt.user.client.ui

Source Code of com.google.gwt.user.client.ui.PotentialElement

/*
* Copyright 2011 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.core.client.JavaScriptObject;
import com.google.gwt.dom.builder.shared.HtmlBuilderFactory;
import com.google.gwt.dom.builder.shared.HtmlElementBuilder;
import com.google.gwt.dom.client.Element;

/**
* EXPERIMENTAL and subject to change. Do not use this in production code.
* <p>
* A simple {@link Element} implementation (<strong>not</strong> an actual dom
* object) that can serve as stand in to be used by {@link IsRenderable} widgets
* before they are fully built. For example, it can accumulate simple set*()
* values to be used when the widget is actually ready to render. Thus, most
* {@link IsRenderable} widget code can be written without taking into account
* whether or not the widget has yet been rendered.
* <p>
* {@link DOM#appendChild} is aware of PotentialElement, and calls its
* resolve() method. This triggers a call to
* {@link UIObject#resolvePotentialElement()}, which widgets can customize
* to get a real {@link Element} in place at the last moment.
*
* TODO(rdcastro): Cover all unsupported methods with helpful error messages.
*/
public class PotentialElement extends Element {

  static {
    declareShim();
  }

  public static PotentialElement as(Element e) {
    assert isPotential(e);
    return (PotentialElement) e;
  }

  /**
   * Builds a new PotentialElement with the tag name set to "div".
   *
   * @see #build(UIObject,String)
   */
  public static PotentialElement build(UIObject o) {
    return build(o, "div");
  }

  /**
   * Builds a new PotentialElement. This element keeps track of the
   * {@link UIObject} so that it can call
   * {@link UIObject#resolvePotentialElement} to get a real element when
   * that is needed.
   */
  public static native PotentialElement build(UIObject o, String tagName) /*-{
    var el = new $wnd.GwtPotentialElementShim();
    el.tagName = tagName;
    el.__gwt_resolve = @com.google.gwt.user.client.ui.PotentialElement::buildResolveCallback(Lcom/google/gwt/user/client/ui/UIObject;)(o);
    return @com.google.gwt.dom.client.Element::as(Lcom/google/gwt/core/client/JavaScriptObject;)(el);
  }-*/;

  /**
   * Creates an {@link HtmlElementBuilder} instance inheriting all attributes
   * set for the given PotentialElement.
   *
   * @param potentialElement assumed to be a PotentialElement, used as basis for
   *     the builder
   * @return a propertly configured {@link HtmlElementBuilder} instance
   */
  public static HtmlElementBuilder createBuilderFor(Element potentialElement) {
    PotentialElement el = PotentialElement.as(potentialElement);
    HtmlElementBuilder builder = HtmlBuilderFactory.get().trustedCreate(
        el.getTagName());
    el.mergeInto(builder);
    return builder;
  }

  /**
   * Tests whether a given {@link JavaScriptObject} represents a PotentialElement.
   *
   * @param o the {@link JavaScriptObject} to be tested
   * @return true if the given object is a PotentialElement instance
   */
  public static native boolean isPotential(JavaScriptObject o) /*-{
    return @com.google.gwt.user.client.DOM::isPotential(*)(o);
  }-*/;

  /**
   * If given a PotentialElement, returns the real Element to be
   * built from it. Otherwise returns the given Element itself.
   * <p>
   * Note that a PotentialElement can only be resolved once.
   * Making repeated calls to this method with the same PotentialElement
   * is an error.
   */
  public static Element resolve(Element maybePotential) {
    return maybePotential.<PotentialElement>cast().resolve();
  }

  private static native JavaScriptObject buildResolveCallback(UIObject resolver) /*-{
    return function() {
        this.__gwt_resolve = @com.google.gwt.user.client.ui.PotentialElement::cannotResolveTwice();
        return resolver.@com.google.gwt.user.client.ui.UIObject::resolvePotentialElement()();
      };
  }-*/;

  private static final native void cannotResolveTwice() /*-{
    throw "A PotentialElement cannot be resolved twice.";
  }-*/;

  private static final native void declareShim() /*-{
    var shim = function() {};
    shim.prototype = {
      className: '',
      clientHeight: 0,
      clientWidth: 0,
      dir: '',
      getAttribute: function(name, value) {
        return this[name];
      },
      href: '',
      id: '',
      lang: '',
      // should be @com.google.gwt.dom.client.Node.ELEMENT_MODE, but the compiler
      // doesn't like that.
      nodeType: 1,
      removeAttribute: function(name, value) {
        this[name] = undefined;
      },
      setAttribute: function(name, value) {
        this[name] = value;
      },
      src: '',
      style: {},
      title: ''
    };
    $wnd.GwtPotentialElementShim = shim;
  }-*/;

  protected PotentialElement() {
  }

  final native Element setResolver(UIObject resolver) /*-{
    this.__gwt_resolve = @com.google.gwt.user.client.ui.PotentialElement::buildResolveCallback(Lcom/google/gwt/user/client/ui/UIObject;)(resolver);
  }-*/;

  /**
   * Copy only the fields that have actually changed from the values in the shim
   * prototype. Do this by severing the __proto__ link, allowing us to iterate
   * only on the fields set in this specific instance.
   */
  private native void mergeInto(HtmlElementBuilder builder) /*-{
    var savedProto = this.__proto__;
    var tagName = this.tagName;
    var gwtResolve = this.__gwt_resolve;
    var className = this.className;

    try {
      this.__proto__ = null;
      this.tagName = null;
      this.__gwt_resolve = null;

      // className needs special treatment because the actual HTML attribute is
      // called "class" and not "className".
      if (this.className) {
        builder.@com.google.gwt.dom.builder.shared.ElementBuilder::className(Ljava/lang/String;)(
            this.className);
        this.className = null;
      }

      // Iterate over all attributes, and copy them to the ElementBuilder.
      // TODO(rdcastro): Deal with the "style" attribute.
      for (attr in this) {
        if (!this[attr]) {
          continue;
        }
        if (typeof this[attr] == 'number') {
          builder.@com.google.gwt.dom.builder.shared.ElementBuilder::attribute(Ljava/lang/String;I)(
              attr, this[attr]);
        } else if (typeof this[attr] == 'string') {
          builder.@com.google.gwt.dom.builder.shared.ElementBuilder::attribute(Ljava/lang/String;Ljava/lang/String;)(
              attr, this[attr]);
        }
      }
    } finally {
      this.__proto__ = savedProto;
      if (className) {
        this.className = className;
      }
      this.__gwt_resolve = gwtResolve;
      this.tagName = tagName;
    }
  }-*/;

  /**
   * Calls the <code>__gwt_resolve</code> method on the underlying
   * JavaScript object if it exists. On objects created via {@link #build}, this
   * method is a call to the {@link UIObject#resolvePotentialElement} method
   * on the associated UIObject.
   */
  private native Element resolve() /*-{
    return @com.google.gwt.user.client.DOM::resolve(*)(o)
  }-*/;
TOP

Related Classes of com.google.gwt.user.client.ui.PotentialElement

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.