http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/051db092/wave/src/main/java/org/waveprotocol/wave/client/clipboard/PasteBufferImpl.java
----------------------------------------------------------------------
diff --git 
a/wave/src/main/java/org/waveprotocol/wave/client/clipboard/PasteBufferImpl.java
 
b/wave/src/main/java/org/waveprotocol/wave/client/clipboard/PasteBufferImpl.java
deleted file mode 100644
index 7dad28c..0000000
--- 
a/wave/src/main/java/org/waveprotocol/wave/client/clipboard/PasteBufferImpl.java
+++ /dev/null
@@ -1,154 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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 org.waveprotocol.wave.client.clipboard;
-
-import com.google.gwt.dom.client.Document;
-import com.google.gwt.dom.client.Element;
-import com.google.gwt.dom.client.Node;
-import com.google.gwt.dom.client.Style.Overflow;
-import com.google.gwt.dom.client.Style.Position;
-import com.google.gwt.dom.client.Style.Unit;
-import org.waveprotocol.wave.client.common.util.JsoView;
-import org.waveprotocol.wave.client.common.util.QuirksConstants;
-import org.waveprotocol.wave.client.common.util.UserAgent;
-import org.waveprotocol.wave.client.editor.selection.html.NativeSelectionUtil;
-
-import org.waveprotocol.wave.model.document.util.Point;
-
-/**
- * Provides an offscreen, HTML paste buffer for various browsers.
- *
- */
-public class PasteBufferImpl {
-
-  /**
-   * The actual element that contains the paste.
-   */
-  protected Element element = null;
-
-  private static final boolean SHOW_DEBUG_PASTEBUFFER = false;
-
-  /**
-   * Factory constructor, creates and attaches the buffer to the DOM.
-   *
-   * @return Browser specific implementation of a paste buffer.
-   */
-  static PasteBufferImpl create() {
-    PasteBufferImpl pasteBuffer;
-
-    if (UserAgent.isSafari() || QuirksConstants.FIREFOX_GREATER_THAN_VER_15) {
-      pasteBuffer = new PasteBufferImplSafariAndNewFirefox();
-    } else if (UserAgent.isFirefox() && 
!QuirksConstants.SANITIZES_PASTED_CONTENT) {
-      // Older versions of firefox doesn't sanitize pasted content and 
requires the
-      // paste buffer to be an iframe to prevent XSS.
-      pasteBuffer = new PasteBufferImplOldFirefox();
-    } else {
-      pasteBuffer = new PasteBufferImpl();
-    }
-
-    pasteBuffer.setupDom();
-    return pasteBuffer;
-  }
-
-  /**
-   * Empty protected constructor. Use static create for instantiation.
-   */
-  protected PasteBufferImpl() {
-  }
-
-  /**
-   * Clears and sets the content of the paste element.
-   *
-   * @param node The DOM to append.
-   */
-  void setContent(Node node) {
-    element.setInnerHTML("");
-    element.appendChild(node);
-  }
-
-  /**
-   * Use this to get the root level container.
-   *
-   * @return The offscreen element.
-   */
-  public Element getContainer() {
-    return element;
-  }
-
-  /**
-   * Use this to get the paste contents (from innerHTML).
-   *
-   * @return The pasted contents.
-   */
-  public Element getPasteContainer() {
-    return element;
-  }
-
-  /**
-   * Prepare the buffer to accept a paste event by setting the selection and
-   * focus to the container.
-   */
-  public void prepareForPaste() {
-    element.setInnerHTML("");
-    element.appendChild(Document.get().createTextNode(""));
-
-    NativeSelectionUtil.setCaret(Point.inText(element.getFirstChild(), 0));
-  }
-
-  protected void positionPasteBuffer(Element element) {
-    if (SHOW_DEBUG_PASTEBUFFER) {
-      element.getStyle().setPosition(Position.ABSOLUTE);
-      element.getStyle().setHeight(150, Unit.PX);
-      element.getStyle().setLeft(1000, Unit.PX);
-      element.getStyle().setTop(10, Unit.PX);
-    } else {
-      element.getStyle().setPosition(Position.ABSOLUTE);
-      element.getStyle().setTop(-100, Unit.PX); // arbitrary numbers
-      element.getStyle().setHeight(50, Unit.PX);
-    }
-  }
-
-  /**
-   * Sets up the PasteBuffer DOM.
-   *
-   * Implementations should call positionPasteBuffer
-   */
-  protected void setupDom() {
-    element = Document.get().createDivElement();
-    // For some reason setting display to none prevents this trick from working
-    // instead, we move it away from view, so it's still "visible"
-    // NOTE(user): We setwhitespace pre-wrap prevents the browser from
-    // collapsing sequences of whitespace. This is important to ensure that the
-    // spaces after a start tag, or before an end tag are preserved through 
copy/paste.
-    // Also, we can't use DomHelper.setContentEditable as setting 
-webkit-user-modify
-    // to read-write-plaintext-only will force the pasted content to plain 
text and
-    // kill all formatting and semantic paste.
-    // This trick doesn't work in Firefox, because the pre-wrap attribute is 
not
-    // preserved through copy, to fix this in Firefox, we'll need to manually
-    // replace spaces with  
-    element.setAttribute("contentEditable", "true");
-    JsoView.as(element.getStyle()).setString("white-space", "pre-wrap");
-    // DomHelper.setContentEditable(element, true, false);
-    element.getStyle().setOverflow(Overflow.HIDDEN);
-
-    positionPasteBuffer(element);
-    Document.get().getBody().appendChild(element);
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/051db092/wave/src/main/java/org/waveprotocol/wave/client/clipboard/PasteBufferImplOldFirefox.java
----------------------------------------------------------------------
diff --git 
a/wave/src/main/java/org/waveprotocol/wave/client/clipboard/PasteBufferImplOldFirefox.java
 
b/wave/src/main/java/org/waveprotocol/wave/client/clipboard/PasteBufferImplOldFirefox.java
deleted file mode 100644
index afd4e1e..0000000
--- 
a/wave/src/main/java/org/waveprotocol/wave/client/clipboard/PasteBufferImplOldFirefox.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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 org.waveprotocol.wave.client.clipboard;
-
-import com.google.gwt.dom.client.Document;
-import com.google.gwt.dom.client.IFrameElement;
-import com.google.gwt.dom.client.Node;
-import org.waveprotocol.wave.client.common.util.DomHelper;
-import org.waveprotocol.wave.client.editor.selection.html.NativeSelectionUtil;
-import org.waveprotocol.wave.model.document.util.Point;
-
-/**
- * Firefox old implementation of the paste buffer. We cannot use a standard 
div set
- * to contentEditable because pasting any javascript will automatically
- * execute it. Instead, use an offscreen iframe whose document is set to
- * "designMode". This is roughly equivalent to contentEditable with the
- * exception of being more sandbox-like and prevents script execution.
- *
- * NOTE(user): There's actually a lot of blackmagic in this class. In setupDom,
- * the real contentDocument of the iframe is actually created asynchronously. 
In
- * this code are actually using a transient element inside a transient
- * contentDocument, that just happens to work.
- *
- * Why don't we get contentDocument().getBody() after a delay then?
- *
- * If we get the use the real element, i.e. assign element from
- * iframe.getContentDocument().getBody() asynchronously we'll suffers from 
paste
- * self-xss. This seems strange, because we're using designMode in an IFrame,
- * which is supposed to guard against javascript execution. If we make this
- * iframe visible and paste in html that executes js directly, we are protected
- * from js execution. However, if we are doing it programmatically inside a 
copy
- * event, we are not protected.
- *
- * Tested on: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2)
- * Gecko/20100115 Firefox/3.6 GTB7.0 < 15.0
- *
- */
-class PasteBufferImplOldFirefox extends PasteBufferImpl {
-
-  private final IFrameElement iframe;
-
-  /**
-   * Protected empty constructor. Will be created by factory constructor in
-   * PasteBufferImpl.
-   */
-  protected PasteBufferImplOldFirefox() {
-    iframe = Document.get().createIFrameElement();
-  }
-
-  @Override
-  protected void setupDom() {
-    Document.get().getBody().appendChild(iframe);
-
-    positionPasteBuffer(iframe);
-    element = iframe.getContentDocument().getBody();
-    setDesignMode(iframe.getContentDocument());
-  }
-
-  private static native void setDesignMode(Document doc) /*-{
-    doc.designMode = "on";
-  }-*/;
-
-  @Override
-  public void prepareForPaste() {
-    super.prepareForPaste();
-    // N.B.(davidbyttow): In FF3, focus is not implicitly set by setting the
-    // selection when appending a DOM element dynamically. So we must 
explicitly
-    // set the focus.
-    DomHelper.focus(iframe);
-    NativeSelectionUtil.setCaret(Point.<Node>end(element));
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/051db092/wave/src/main/java/org/waveprotocol/wave/client/clipboard/PasteBufferImplSafariAndNewFirefox.java
----------------------------------------------------------------------
diff --git 
a/wave/src/main/java/org/waveprotocol/wave/client/clipboard/PasteBufferImplSafariAndNewFirefox.java
 
b/wave/src/main/java/org/waveprotocol/wave/client/clipboard/PasteBufferImplSafariAndNewFirefox.java
deleted file mode 100644
index db5ba68..0000000
--- 
a/wave/src/main/java/org/waveprotocol/wave/client/clipboard/PasteBufferImplSafariAndNewFirefox.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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 org.waveprotocol.wave.client.clipboard;
-
-import com.google.gwt.dom.client.Document;
-import com.google.gwt.dom.client.Element;
-import com.google.gwt.dom.client.Node;
-import com.google.gwt.dom.client.Text;
-import org.waveprotocol.wave.client.common.util.DomHelper;
-import org.waveprotocol.wave.client.editor.selection.html.NativeSelectionUtil;
-import org.waveprotocol.wave.model.document.util.Point;
-
-/**
- * Safari implementation of the paste buffer. In Safari, we need to have the
- * paste occur inside of a text node in order to consistently get the
- * leading and trailing inline text. If that is not present, we sometimes
- * cannot tell the difference between a new paragraph or inline text.
- *
- * Also works for Firefox >= 15
- *
- */
-class PasteBufferImplSafariAndNewFirefox extends PasteBufferImpl {
-
-  private boolean markersStripped = false;
-
-  private static final char MARKER_CHAR = '\u007F';
-  private static final String MARKER_NODE_STRING = String.valueOf(MARKER_CHAR) 
+ MARKER_CHAR;
-
-  /**
-   * Use this to get the paste contents (from innerHTML). Note, this
-   * implementation will strip the extra markers injected for Safari.
-   *
-   * @return The pasted contents.
-   */
-  @Override
-  public Element getPasteContainer() {
-    stripMarkers();
-    return element;
-  }
-
-  @Override
-  public void prepareForPaste() {
-    element.setInnerHTML("");
-    element.appendChild(Document.get().createTextNode(MARKER_NODE_STRING));
-    NativeSelectionUtil.setCaret(Point.inText(element.getFirstChild(), 1));
-    markersStripped = false;
-  }
-
-  private void stripMarkers() {
-    if (markersStripped) {
-      return;
-    }
-
-    // Remove the leading and trailing markers.
-    maybeStripMarker(element.getFirstChild(), element, true);
-    maybeStripMarker(element.getLastChild(), element, false);
-    markersStripped = true;
-  }
-
-  // TODO(user): Remove this when we can confirm this no longer happens.
-  private void logEndNotFound(String detail) {
-    Clipboard.LOG.error().log("end not found: " + detail);
-  }
-
-  private void maybeStripMarker(Node node, Element parent, boolean leading) {
-    if (node == null) {
-      logEndNotFound("node is null");
-      return;
-    }
-    if (DomHelper.isTextNode(node)) {
-      Text textNode = node.cast();
-      String text = textNode.getData();
-      if (!text.isEmpty()) {
-        if (leading) {
-          if (text.charAt(0) == MARKER_CHAR) {
-            textNode.setData(text.substring(1));
-          }
-        } else {
-          if (text.charAt(text.length() - 1) == MARKER_CHAR) {
-            textNode.setData(text.substring(0, text.length() - 1));
-          } else {
-            logEndNotFound("last character is not marker");
-          }
-        }
-      } else {
-        logEndNotFound("text node is empty");
-      }
-      if (textNode.getData().isEmpty()) {
-        parent.removeChild(textNode);
-      }
-    } else {
-      // In some cases, Safari will put the marker inside of a div, so this
-      // traverses down the left or right side of the tree to find it.
-      // For example: x<div><span>pasted</span>x</div>
-      maybeStripMarker(leading ? node.getFirstChild() : node.getLastChild(), 
node.<Element> cast(),
-          leading);
-    }
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/051db092/wave/src/main/java/org/waveprotocol/wave/client/common/safehtml/EscapeUtils.java
----------------------------------------------------------------------
diff --git 
a/wave/src/main/java/org/waveprotocol/wave/client/common/safehtml/EscapeUtils.java
 
b/wave/src/main/java/org/waveprotocol/wave/client/common/safehtml/EscapeUtils.java
deleted file mode 100644
index 9bdece0..0000000
--- 
a/wave/src/main/java/org/waveprotocol/wave/client/common/safehtml/EscapeUtils.java
+++ /dev/null
@@ -1,201 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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 org.waveprotocol.wave.client.common.safehtml;
-
-// NOTE: In the near future, the files in this package will be open sourced as
-// part of a different project. Do not rely on them staying here.
-
-/**
- * Utility class containing static methods for escaping and sanitizing strings.
- */
-// TODO(user): The naming of this class and the methods herein isn't exactly
-// consistent anymore; clean this up.
-public final class EscapeUtils {
-
-  private static final String HTML_ENTITY_REGEX = 
"[a-z]+|#[0-9]+|#x[0-9a-fA-F]+";
-
-  public static final SafeHtml EMPTY_SAFE_HTML = new SafeHtmlString("");
-
-  // prevent instantiation
-  private EscapeUtils() {
-  }
-
-  /**
-   * Returns a SafeHtml constructed from a safe string, i.e. without escaping 
the string.
-   */
-  public static SafeHtml fromSafeConstant(String s) {
-    return new SafeHtmlString(s);
-  }
-
-  /**
-   * Returns a SafeHtml constructed from a plain string that does not contain 
any HTML markup.
-   */
-  public static SafeHtml fromPlainText(String s) {
-    // TODO(user) assert that there are no HTML elements in the string
-    // TODO(user) verify that this is actually faster than calling htmlEscape()
-    return new SafeHtmlString(s);
-  }
-
-  /**
-   * Returns a SafeHtml containing the escaped string.
-   */
-  public static SafeHtml fromString(String s) {
-    return new SafeHtmlString(htmlEscape(s));
-  }
-
-  /**
-   * HTML-escapes a string.
-   *
-   * @param s the string to be escaped
-   * @return the input string, with all occurrences of HTML meta-characters 
replaced with their
-   *         corresponding HTML Entity References
-   */
-  public static String htmlEscape(String s) {
-    // TODO(user): GWT does not seem to have java.util.regex, so leave this 
out for now.
-    /*
-    if (!HTML_META_CHARS.matcher(s).find()) {
-      // short cirquit and bail out if no work to be done, without allocating 
objects.
-      return s;
-    }
-    */
-
-    // TODO(user): maybe do some benchmarking and work out if this is the most 
efficient way to go
-    // about escaping.
-    return s.replaceAll("&", "&amp;")
-        .replaceAll("\"", "&quot;")
-        .replaceAll("\'", "&#39;")
-        .replaceAll("<", "&lt;")
-        .replaceAll(">", "&gt;");
-  }
-
-  /**
-   * HTML-escapes a string, but does not double-escape HTML-entities already 
present in the string.
-   *
-   * @param text the string to be escaped
-   * @return the input string, with all occurrences of HTML meta-characters 
replaced with their
-   *         corresponding HTML Entity References, with the exception that 
ampersand characters are
-   *         not double-escaped if they form the start of an HTML Entity 
Reference
-   */
-  public static String htmlEscapeAllowEntities(String text) {
-    StringBuilder escaped = new StringBuilder();
-
-    boolean firstSegment = true;
-    for (String segment : text.split("&", -1)) {
-      if (firstSegment) {
-        // The first segment is never part of an entity reference, so we 
always escape it.
-        // Note that if the input starts with an ampersand, we will get an 
empty segment
-        // before that.
-        firstSegment = false;
-        escaped.append(htmlEscape(segment));
-        continue;
-      }
-
-      int entityEnd = segment.indexOf(';');
-      if (entityEnd > 0 &&
-          segment.substring(0, entityEnd).matches(HTML_ENTITY_REGEX)) {
-        // Append the entity without escaping.
-        escaped.append("&")
-            .append(segment.substring(0, entityEnd + 1));
-
-        // Append the rest of the segment, escaped.
-        escaped.append(htmlEscape(segment.substring(entityEnd + 1)));
-      } else {
-        // The segment did not start with an entity reference, so escape the 
whole segment.
-        escaped.append("&amp;")
-            .append(htmlEscape(segment));
-      }
-    }
-
-    return escaped.toString();
-  }
-
-  /*
-   * Methods to validate/sanitize URIs.
-   */
-
-  // TODO(user): Figure out if GWT supports some parsed representation of URIs,
-  // and add equivalent methods that operate on those rather than string (which
-  // would likely be more efficient in cases where URIs are constructed with a
-  // common base). I tried java.net.URI, but alas it's not supported at this
-  // time.
-
-  /**
-   * Extracts the scheme of a URI.
-   *
-   * @param uri the URI to extract the scheme from
-   * @return the URI's scheme, or {@code null} if the URI does not have one
-   */
-  public static String extractScheme(String uri) {
-    int colonPos = uri.indexOf(':');
-    if (colonPos < 0) {
-      return null;
-    }
-    String scheme = uri.substring(0, colonPos);
-    if (scheme.indexOf('/') >= 0 || scheme.indexOf('#') >= 0) {
-      // The URI's prefix up to the first ':' contains other URI special
-      // chars, and won't be interpreted as a scheme.
-      // TODO(user): Consider basing this on URL#isValidProtocol or similar;
-      // however I'm worried that being too strict here will effectively
-      // allow dangerous schemes accepted in loosely parsing browsers.
-      return null;
-    }
-    return scheme;
-  }
-
-  /**
-   * Determines if a {@link String} is safe to use as the value of a URI-valued
-   * HTML attribute such as {@code src} or {@code href}.
-   *
-   * <p>In this context, a URI is safe if it can be established that using it 
as
-   * the value of a URI-valued HTML attribute such as {@code src} or {@code
-   * href} cannot result in script execution. Specifically, this method deems a
-   * URI safe if it either does not have a scheme, or its scheme is one of
-   * {@code http, https, ftp, mailto}.
-   *
-   * @param uri the URI to validate
-   * @return {@code true} if {@code uri} is safe in the above sense; {@code
-   *         false} otherwise
-   */
-  public static boolean isSafeUri(String uri) {
-    String scheme = extractScheme(uri);
-    return (scheme == null
-            || "http".equalsIgnoreCase(scheme)
-            || "https".equalsIgnoreCase(scheme)
-            || "mailto".equalsIgnoreCase(scheme)
-            || "ftp".equalsIgnoreCase(scheme));
-  }
-
-  /**
-   * Sanitizes a URI.
-   *
-   * <p>This method returns the URI provided if it is safe to use as the the
-   * value of a URI-valued HTML attribute according to {@link #isSafeUri}, or
-   * the URI "{@code #}" otherwise.
-   *
-   * @param uri the URI to sanitize.
-   */
-  public static String sanitizeUri(String uri) {
-    if (isSafeUri(uri)) {
-      return uri;
-    } else {
-      return "#";
-    }
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/051db092/wave/src/main/java/org/waveprotocol/wave/client/common/safehtml/SafeHtml.java
----------------------------------------------------------------------
diff --git 
a/wave/src/main/java/org/waveprotocol/wave/client/common/safehtml/SafeHtml.java 
b/wave/src/main/java/org/waveprotocol/wave/client/common/safehtml/SafeHtml.java
deleted file mode 100644
index 06074ad..0000000
--- 
a/wave/src/main/java/org/waveprotocol/wave/client/common/safehtml/SafeHtml.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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 org.waveprotocol.wave.client.common.safehtml;
-
-import java.io.Serializable;
-
-//NOTE: In the near future, the files in this package will be open sourced as
-//part of a different project. Do not rely on them staying here.
-
-/**
- * An object that implements this interface encapsulates HTML that is 
guaranteed to be safe to use
- * (with respect to potential Cross-Site-Scripting vulnerabilities) in an HTML 
context.
- *
- * <p>All implementing classes must maintain the class invariant (by design 
and implementation
- * and/or convention of use), that invoking {@link #asString()} on any 
instance will return a string
- * that is safe to assign to the {@code .innerHTML} DOM property in a browser 
(or to use similarly
- * in an "inner HTML" context), in the sense that doing so must not cause 
execution of script in the
- * browser.
- *
- * <p>Implementations of this interface must not implement
- * {@link com.google.gwt.user.client.rpc.IsSerializable}, since 
deserialization can result in
- * violation of the class invariant.
- */
-public interface SafeHtml extends Serializable {
-/* Notes regading serialization:
- *   - It may be reasonable to allow deserialization on the client of objects
- *     serialized on the server (i.e. RPC responses), based on the assumption 
that
- *     server code is trusted and would not provide a malicious serialized form
- *     (if a MitM were able to modify server responses, the client would be
- *     fully compromised in any case). However, the GWT RPC framework currently
- *     does not seem to provide a facility for restricting deserialization on 
the
- *     Server only (thought this shouldn't be difficult to implement through a
- *     custom SerializationPolicy)
- *
- *   - Some implementations of SafeHtml would in principle be able to enforce
- *     their class invariant on deserialization (e.g., SimpleHtmlSanitizer 
could apply
- *     HTML sanitization on deserialization).  However, the GWT RPC framework 
does
- *     not provide for an equivalent of readResolve() to enforce the class
- *     invariant on deserialization.
- *
- */
-
-
-  /**
-   * Returns this object's contained HTML as a string.  Based on this class' 
contract, the returned
-   * string will be safe to use in an HTML context.
-   */
-  String asString();
-}

http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/051db092/wave/src/main/java/org/waveprotocol/wave/client/common/safehtml/SafeHtmlBuilder.java
----------------------------------------------------------------------
diff --git 
a/wave/src/main/java/org/waveprotocol/wave/client/common/safehtml/SafeHtmlBuilder.java
 
b/wave/src/main/java/org/waveprotocol/wave/client/common/safehtml/SafeHtmlBuilder.java
deleted file mode 100644
index 27e4219..0000000
--- 
a/wave/src/main/java/org/waveprotocol/wave/client/common/safehtml/SafeHtmlBuilder.java
+++ /dev/null
@@ -1,213 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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 org.waveprotocol.wave.client.common.safehtml;
-
-//NOTE: In the near future, the files in this package will be open sourced as
-//part of a different project. Do not rely on them staying here.
-
-/** A builder that facilitates the building up of XSS-safe HTML from text
- * snippets.  It is used essentially like a {@link StringBuilder}; unlike a
- * {@link StringBuilder}, it automatically HTML-escapes appended input where
- * necessary.
- *
- * <p>In addition, it supports methods that allow strings with HTML markup to 
be
- * appended without escaping: One can append other {@link SafeHtml} objects, 
and
- * one can append constant strings.  The method that appends constant strings
- * ({@link #appendHtmlConstant(String)}) requires a convention of use to be
- * adhered to in order for this class to adhere to the contract required by
- * {@link SafeHtml}.
- *
- * <p>The accumulated XSS-safe HTML can be obtained in the form of a {@link
- * SafeHtml} via the {@link #toSafeHtml()} method.
- *
- * <p>This class is not thread-safe.
- */
-public final class SafeHtmlBuilder {
-
-  private final StringBuilder sb = new StringBuilder();
-
-  /**
-   * Constructs an empty SafeHtmlBuilder.
-   */
-  public SafeHtmlBuilder() {
-  }
-
-  /**
-   * Returns the safe HTML accumulated in the builder as a {@link SafeHtml}.
-   */
-  public SafeHtml toSafeHtml() {
-    return new SafeHtmlString(sb.toString());
-  }
-
-  /**
-   * Appends a compile-time-constant string, which will <em>not</em> be 
escaped.
-   *
-   * <p><b>Important</b>: For this class to be able to honour its contract as 
required by {@link
-   * SafeHtml}, all uses of this method must satisfy the following 
requirements:
-   *
-   * <ul>
-   *
-   * <li>The argument expression must be fully determined and known to be safe 
at
-   * compile time.
-   *
-   * <li>The value of the argument must not contain incomplete HTML tags. 
I.e., the following is not
-   * a correct use of this method, because the {@code <a>} tag is incomplete:
-   * <pre class="code">{@code shb.appendConstantHtml("<a 
href='").append(url)}</pre>
-   *
-   * </ul>
-   *
-   * @param html the HTML snippet to be appended
-   * @return a reference to this object
-   */
-  public SafeHtmlBuilder appendHtmlConstant(String html) {
-    // TODO(user): (hosted-mode only) assert that html satisfies the second 
constraint.
-    sb.append(html);
-    return this;
-  }
-
-  /**
-   * Appends the contents of another {@link SafeHtml} object, without applying 
HTML-escaping to it.
-   *
-   * @param html the {@link SafeHtml} to append
-   * @return a reference to this object
-   */
-  public SafeHtmlBuilder append(SafeHtml html) {
-    sb.append(html.asString());
-    return this;
-  }
-
-  /**
-   * Appends a string after HTML-escaping it.
-   *
-   * @param text the string to append
-   * @return a reference to this object
-   */
-  public SafeHtmlBuilder appendEscaped(String text) {
-    sb.append(EscapeUtils.htmlEscape(text));
-    return this;
-  }
-
-  /**
-   * Appends a string consisting of several newline-separated lines
-   * after HTML-escaping it.  Newlines in the original string are
-   * converted to {@code <br>}.
-   *
-   * @param text the string to append
-   * @return a reference to this object
-   */
-  public SafeHtmlBuilder appendEscapedLines(String text) {
-    sb.append(EscapeUtils.htmlEscape(text).replaceAll("\n", "<br>"));
-    return this;
-  }
-
-  /**
-   * Appends a plain text string that does not contain any HTML elements.
-   *
-   * @param text the string to append
-   * @return a reference to this object
-   */
-  public SafeHtmlBuilder appendPlainText(String text) {
-    // TODO(user) assert text does not contain any HTML elements
-    // TODO(user) verify that this is actually faster than calling htmlEscape()
-    sb.append(text);
-    return this;
-  }
-
-  /*
-   * Boolean and numeric types converted to String are always HTML safe -- no 
escaping necessary.
-   */
-
-  /**
-   * Appends the string representation of a boolean.
-   *
-   * @param b the boolean whose string representation to append
-   * @return a reference to this object
-   */
-  public SafeHtmlBuilder append(boolean b) {
-    sb.append(b);
-    return this;
-  }
-
-  /**
-   * Appends the string representation of a char.
-   *
-   * @param num the number whose string representation to append
-   * @return a reference to this object
-   */
-  public SafeHtmlBuilder append(char num) {
-    sb.append(num);
-    return this;
-  }
-
-  /**
-   * Appends the string representation of a number.
-   *
-   * @param num the number whose string representation to append
-   * @return a reference to this object
-   */
-  public SafeHtmlBuilder append(int num) {
-    sb.append(num);
-    return this;
-  }
-
-  /**
-   * Appends the string representation of a number.
-   *
-   * @param num the number whose string representation to append
-   * @return a reference to this object
-   */
-  public SafeHtmlBuilder append(byte num) {
-    sb.append(num);
-    return this;
-  }
-
-  /**
-   * Appends the string representation of a number.
-   *
-   * @param num the number whose string representation to append
-   * @return a reference to this object
-   */
-  public SafeHtmlBuilder append(long num) {
-    sb.append(num);
-    return this;
-  }
-
-  /**
-   * Appends the string representation of a number.
-   *
-   * @param num the number whose string representation to append
-   * @return a reference to this object
-   */
-  public SafeHtmlBuilder append(float num) {
-    sb.append(num);
-    return this;
-  }
-
-  /**
-   * Appends the string representation of a number.
-   *
-   * @param num the number whose string representation to append
-   * @return a reference to this object
-   */
-  public SafeHtmlBuilder append(double num) {
-    sb.append(num);
-    return this;
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/051db092/wave/src/main/java/org/waveprotocol/wave/client/common/safehtml/SafeHtmlString.java
----------------------------------------------------------------------
diff --git 
a/wave/src/main/java/org/waveprotocol/wave/client/common/safehtml/SafeHtmlString.java
 
b/wave/src/main/java/org/waveprotocol/wave/client/common/safehtml/SafeHtmlString.java
deleted file mode 100644
index 85777fe..0000000
--- 
a/wave/src/main/java/org/waveprotocol/wave/client/common/safehtml/SafeHtmlString.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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 org.waveprotocol.wave.client.common.safehtml;
-
-//NOTE: In the near future, the files in this package will be open sourced as
-//part of a different project. Do not rely on them staying here.
-
-/**
- * A string wrapped as an object of type {@link SafeHtml}.
- *
- * <p>This class is package-private and intended for internal use by the
- * {@link org.waveprotocol.wave.client.common.safehtml} package.
- */
-class SafeHtmlString implements SafeHtml {
-  private String html;
-
-  /**
-   * Constructs a {@link SafeHtmlString} from a string.  Callers are 
responsible for ensuring that
-   * the string passed as the argument to this constructor satisfies the 
constraints of the contract
-   * imposed by the {@link SafeHtml} interface.
-   *
-   * @param html the string to be wrapped as a {@link SafeHtml}
-   */
-  SafeHtmlString(String html) {
-    this.html = html;
-  }
-
-  /**
-   * No-arg constructor for compatibility with GWT serialization.
-   */
-  SafeHtmlString() {
-  }
-
-  /** {@inheritDoc} */
-  @Override
-  public String asString() {
-    return html;
-  }
-}
-

http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/051db092/wave/src/main/java/org/waveprotocol/wave/client/common/scrub/Scrub.java
----------------------------------------------------------------------
diff --git 
a/wave/src/main/java/org/waveprotocol/wave/client/common/scrub/Scrub.java 
b/wave/src/main/java/org/waveprotocol/wave/client/common/scrub/Scrub.java
deleted file mode 100644
index a35f472..0000000
--- a/wave/src/main/java/org/waveprotocol/wave/client/common/scrub/Scrub.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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 org.waveprotocol.wave.client.common.scrub;
-
-import com.google.gwt.http.client.URL;
-
-import org.waveprotocol.wave.client.common.safehtml.EscapeUtils;
-
-/**
- * Helper for scrubbing URLs
- *
- * @author [email protected] (Daniel Danilatos)
- */
-public class Scrub {
-
-  /** If true, then we scrub URLs */
-  private static boolean enableScrubbing = false;
-
-  public static void setEnableScrubbing(final boolean enableScrubbing) {
-    Scrub.enableScrubbing = enableScrubbing;
-  }
-
-  /** Scrubbing prefix */
-  public static final String REFERRER_SCRUBBING_URL =
-      "http://www.google.com/url?sa=D&q=";;
-
-  /**
-   * Scrub a url if scrubbing is turned on
-   *
-   * Does not scrub urls with leading hashes
-   *
-   * @param url
-   * @return The scrubbed version of the url, if it's not already scrubbed
-   */
-  public static String scrub(String url) {
-    if (enableScrubbing) {
-      if (url.startsWith("#") || url.startsWith(REFERRER_SCRUBBING_URL)) {
-        // NOTE(user): The caller should be responsible for url encoding if
-        // neccessary. There is no XSS risk here as it is a fragment.
-        return url;
-      } else {
-        String x = REFERRER_SCRUBBING_URL + URL.encodeComponent(url);
-        return x;
-      }
-    } else {
-      // If we are not scrubbing the url, then we still need to sanitize it,
-      // to protect against e.g. javascript.
-      String sanitizedUri = EscapeUtils.sanitizeUri(url);
-      return sanitizedUri;
-    }
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/051db092/wave/src/main/java/org/waveprotocol/wave/client/common/util/AsyncHolder.java
----------------------------------------------------------------------
diff --git 
a/wave/src/main/java/org/waveprotocol/wave/client/common/util/AsyncHolder.java 
b/wave/src/main/java/org/waveprotocol/wave/client/common/util/AsyncHolder.java
deleted file mode 100644
index 317bb41..0000000
--- 
a/wave/src/main/java/org/waveprotocol/wave/client/common/util/AsyncHolder.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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 org.waveprotocol.wave.client.common.util;
-
-import com.google.common.base.Preconditions;
-
-import org.waveprotocol.wave.model.util.CollectionUtils;
-
-import java.util.Queue;
-
-/**
- * Something that holds a value, revealed by potentially asynchronous access.
- *
- * @param <T> type of held value
- */
-public interface AsyncHolder<T> {
-
-  /** Accessor of a value in this holder. */
-  public interface Accessor<T> {
-    void use(T x);
-  }
-
-  /**
-   * Reveals the value held by this holder to a consumer. The value may be
-   * revealed synchronously or asynchronously.
-   *
-   * @param accessor procedure to apply
-   */
-  void call(Accessor<T> accessor);
-
-  public abstract class Impl<T> implements AsyncHolder<T>, Accessor<T> {
-    private Queue<Accessor<T>> waiting;
-    private T value;
-
-    @Override
-    public final void call(Accessor<T> accessor) {
-      if (value == null) {
-        addWaiter(accessor);
-      } else {
-        accessor.use(value);
-      }
-    }
-
-    private void addWaiter(Accessor<T> accessor) {
-      assert value == null;
-      if (waiting == null) {
-        waiting = CollectionUtils.createQueue();
-        waiting.add(accessor);
-        create(this);
-      } else {
-        waiting.add(accessor);
-      }
-    }
-
-    protected abstract void create(Accessor<T> whenReady);
-
-    @Override
-    public void use(T x) {
-      Preconditions.checkState(value == null && waiting != null);
-      value = x;
-      for (Accessor<T> waiter : waiting) {
-        waiter.use(value);
-      }
-      waiting = null;
-    }
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/051db092/wave/src/main/java/org/waveprotocol/wave/client/common/util/ChainComparator.java
----------------------------------------------------------------------
diff --git 
a/wave/src/main/java/org/waveprotocol/wave/client/common/util/ChainComparator.java
 
b/wave/src/main/java/org/waveprotocol/wave/client/common/util/ChainComparator.java
deleted file mode 100644
index 50dc0cf..0000000
--- 
a/wave/src/main/java/org/waveprotocol/wave/client/common/util/ChainComparator.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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 org.waveprotocol.wave.client.common.util;
-
-import java.util.Comparator;
-
-/**
- * Used to chain comparators. First compare the arguments using the first
- * comparator. If non-zero, return the result. Return the results of the second
- * comparator.
- *
- * This can be nested to combine arbitrary number of comparators.
- *
- *
- * @param <T>
- */
-public final class ChainComparator<T> implements Comparator<T> {
-  private final Comparator<? super T> firstComparator;
-  private final Comparator<? super T> secondComparator;
-
-  public ChainComparator(Comparator<? super T> firstComparator,
-      Comparator<? super T> secondComparator) {
-    this.firstComparator = firstComparator;
-    this.secondComparator = secondComparator;
-  }
-
-  /** {@inheritDoc} **/
-  public int compare(T o1, T o2) {
-    int cmp = firstComparator.compare(o1, o2);
-    return cmp != 0 ? cmp : secondComparator.compare(o1, o2);
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/051db092/wave/src/main/java/org/waveprotocol/wave/client/common/util/ChecksComparability.java
----------------------------------------------------------------------
diff --git 
a/wave/src/main/java/org/waveprotocol/wave/client/common/util/ChecksComparability.java
 
b/wave/src/main/java/org/waveprotocol/wave/client/common/util/ChecksComparability.java
deleted file mode 100644
index 153e91d..0000000
--- 
a/wave/src/main/java/org/waveprotocol/wave/client/common/util/ChecksComparability.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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 org.waveprotocol.wave.client.common.util;
-
-/**
- * Interface for volatile objects that may or may not be comparable to one
- * another at any given moment.
- * 
- * @author [email protected] (Daniel Danilatos)
- */
-public interface ChecksComparability {
-
-  /**
-   * @return true if it makes sense for this object to be compared to a similar
-   *         object.
-   */
-  boolean isComparable();
-}

http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/051db092/wave/src/main/java/org/waveprotocol/wave/client/common/util/ClientDebugException.java
----------------------------------------------------------------------
diff --git 
a/wave/src/main/java/org/waveprotocol/wave/client/common/util/ClientDebugException.java
 
b/wave/src/main/java/org/waveprotocol/wave/client/common/util/ClientDebugException.java
deleted file mode 100644
index 7b4d0df..0000000
--- 
a/wave/src/main/java/org/waveprotocol/wave/client/common/util/ClientDebugException.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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 org.waveprotocol.wave.client.common.util;
-
-/**
- * We use this exception class for debugging purposes. Mainly, this class is
- * used to wrap NPEs that are caught with a try/catch around code that is
- * suspected of generating them. NOTE: Once we'll have stack traces for these
- * NPEs in all browsers the use of this exception should cease.
- *
- */
-public class ClientDebugException extends RuntimeException {
-
-  /**
-   * @param message Some useful message about the exception
-   */
-  public ClientDebugException(String message) {
-    super(message);
-  }
-
-  /**
-   * @param message Some useful message about the exception
-   * @param cause The original exception to be wrapped.
-   */
-  public ClientDebugException(String message, Throwable cause) {
-    super(message, cause);
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/051db092/wave/src/main/java/org/waveprotocol/wave/client/common/util/ClientPercentEncoderDecoder.java
----------------------------------------------------------------------
diff --git 
a/wave/src/main/java/org/waveprotocol/wave/client/common/util/ClientPercentEncoderDecoder.java
 
b/wave/src/main/java/org/waveprotocol/wave/client/common/util/ClientPercentEncoderDecoder.java
deleted file mode 100644
index ebaf41b..0000000
--- 
a/wave/src/main/java/org/waveprotocol/wave/client/common/util/ClientPercentEncoderDecoder.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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 org.waveprotocol.wave.client.common.util;
-
-import com.google.gwt.http.client.URL;
-
-import org.waveprotocol.wave.model.id.URIEncoderDecoder;
-
-/**
- * Uses GWT {@link URL} to percent encode.
- */
-public final class ClientPercentEncoderDecoder implements 
URIEncoderDecoder.PercentEncoderDecoder {
-  @Override
-  public String decode(String encodedValue) throws 
URIEncoderDecoder.EncodingException {
-    String ret = URL.decodePathSegment(encodedValue);
-    if (ret.indexOf(0xFFFD) != -1) {
-      throw new URIEncoderDecoder.EncodingException("Unable to decode value " 
+ encodedValue
-          + " it contains invalid UTF-8");
-    }
-    return ret;
-  }
-
-  @Override
-  public String encode(String decodedValue) {
-    return URL.encode(decodedValue);
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/051db092/wave/src/main/java/org/waveprotocol/wave/client/common/util/CountdownLatch.java
----------------------------------------------------------------------
diff --git 
a/wave/src/main/java/org/waveprotocol/wave/client/common/util/CountdownLatch.java
 
b/wave/src/main/java/org/waveprotocol/wave/client/common/util/CountdownLatch.java
deleted file mode 100644
index 4319f4b..0000000
--- 
a/wave/src/main/java/org/waveprotocol/wave/client/common/util/CountdownLatch.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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 org.waveprotocol.wave.client.common.util;
-
-import com.google.common.base.Preconditions;
-import com.google.gwt.user.client.Command;
-
-/**
- * Simple synchronization tool that waits for some fixed number of calls to
- * {@link #tick()}, and invokes a command on the last one. Any further calls to
- * {@link #tick()} produce an error.
- * <p>
- * The intended use case for this class is a gate that waits for some set of
- * asynchronous tasks to complete.
- *
- */
-public final class CountdownLatch {
-  /** Command to execute when the all ticks have occurred. */
-  private final Command whenZero;
-
-  /** Number of expected ticks. */
-  private int count;
-
-  private CountdownLatch(int count, Command whenZero) {
-    this.whenZero = whenZero;
-    this.count = count;
-  }
-
-  /**
-   * Creates a countdown latch.
-   *
-   * @param count number of ticks
-   * @param whenZero command to execute after {@code count} ticks
-   * @return a new latch.
-   */
-  public static CountdownLatch create(int count, Command whenZero) {
-    return new CountdownLatch(count, whenZero);
-  }
-
-  /**
-   * Ticks this counter.
-   *
-   * @throws IllegalStateException if this counter has already been ticked the
-   *         expected number of times.
-   */
-  public void tick() {
-    Preconditions.checkState(count > 0);
-    count--;
-    if (count == 0) {
-      whenZero.execute();
-    }
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/051db092/wave/src/main/java/org/waveprotocol/wave/client/common/util/DateUtils.java
----------------------------------------------------------------------
diff --git 
a/wave/src/main/java/org/waveprotocol/wave/client/common/util/DateUtils.java 
b/wave/src/main/java/org/waveprotocol/wave/client/common/util/DateUtils.java
deleted file mode 100644
index 515a478..0000000
--- a/wave/src/main/java/org/waveprotocol/wave/client/common/util/DateUtils.java
+++ /dev/null
@@ -1,171 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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 org.waveprotocol.wave.client.common.util;
-
-import com.google.gwt.core.client.Duration;
-import com.google.gwt.core.client.GWT;
-import com.google.gwt.i18n.client.DateTimeFormat;
-
-import java.util.Date;
-
-/**
- * Date formatting utilities.
- *
- */
-@SuppressWarnings("deprecation")  // GWT supports Date.getXXX, but java 
doesn't anymore
-public final class DateUtils {
-
-  private final static long SEC_MS = 1000;
-  private final static long MIN_MS = 60 * SEC_MS;
-  private final static long HOUR_MS = 60 * MIN_MS;
-  private final static long DAY_MS = 24 * HOUR_MS;
-
-  // Singleton class.
-  private DateUtils() { }
-  private static final DateUtils INSTANCE = new DateUtils();
-
-  /**
-   * Please avoid invoking getInstance() inside methods but rather inject the
-   * instance into the class through the constructor. This will
-   *   - make it easier to move to GIN in the future, and
-   *   - make the class easier to test since DateUtils needs to be mocked out
-   *     in non-GWT tests.
-   *
-   * @return the shared DateUtils instance
-   */
-  public static DateUtils getInstance() {
-    return INSTANCE;
-  }
-
-  /**
-   * Formats a date in the past, taking into account how long ago it was
-   *
-   * @param time The date to format, in ms since whenever
-   * @return The formatted date
-   */
-  public String formatPastDate(long time) {
-    return formatPastDate(new Date(time), new Date());
-  }
-
-  private static DateTimeFormat monthDayFormat;
-
-  private static DateTimeFormat getMonthDayFormat() {
-    if (monthDayFormat == null) {
-      monthDayFormat = 
DateTimeFormat.getFormat(DateTimeFormat.PredefinedFormat.MONTH_ABBR_DAY);
-    }
-    return monthDayFormat;
-  }
-
-  /**
-   * Package-private version, takes a fixed "now" time - used for testing
-   */
-  String formatPastDate(Date date, Date now) {
-
-    // NOTE(zdwang): For now skip it for junit code; also see formatDateTime()
-    if (!GWT.isClient()) {
-      return "formatPastDate is not yet implemented in unit test code";
-    }
-
-    if (!isValid(date, now)) {
-      GWT.log("formatPastDate can only format time in the past, trying 
anyway", null);
-    }
-
-    if (isRecent(date, now, 6 * HOUR_MS) || onSameDay(date, now)) {
-      return formatTime(date);
-    } else if (isRecent(date, now, 30 * DAY_MS)) {
-      return getMonthDayFormat().format(date) + " " + formatTime(date);
-    } else if (isSameYear(date, now)) {
-      return getMonthDayFormat().format(date);
-    } else {
-      return DateTimeFormat.getMediumDateFormat().format(date);
-    }
-  }
-
-  /**
-   * Formats the specified time as a String.
-   */
-  public String formatTime(Date date) {
-    // NOTE(zdwang): For now skip it for junit code; also see formatPastDate()
-    if (!GWT.isClient()) {
-      return "formatDateTime is not yet implemented in unit test code";
-    }
-
-    // AM/PM -> am/pm for consistency with formatPastDate()
-    return DateTimeFormat.getShortTimeFormat().format(date).toLowerCase();
-  }
-
-  /**
-   * Formats the specified date and time as a String.
-   */
-  public String formatDateTime(Date date) {
-    // NOTE(zdwang): For now skip it for junit code; also see formatPastDate()
-    if (!GWT.isClient()) {
-      return "formatDateTime is not yet implemented in unit test code";
-    }
-
-    // AM/PM -> am/pm for consistency with formatPastDate()
-    return DateTimeFormat.getShortDateTimeFormat().format(date).toLowerCase();
-  }
-
-  /**
-   * @return true if a date is approximately in the past (i.e., before a
-   *         minute in the future).
-   */
-  private boolean isValid(Date date, Date now) {
-    long diff = (now.getTime() + MIN_MS) - date.getTime();
-    return diff >= 0;
-  }
-
-  /**
-   * @return true if a duration is less than x ms.
-   */
-  private boolean isRecent(Date date, Date now, long ms) {
-   return (now.getTime() - date.getTime()) < ms;
-  }
-
- /**
-  * @return true if a date occurs on the same day as today.
-  */
-  private boolean onSameDay(Date date, Date now) {
-    return (date.getDate() == now.getDate())
-        && (date.getMonth() == now.getMonth())
-        && (date.getYear() == now.getYear());
-  }
-
-  /**
-   * @return true if a date occurs in the same year as this year.
-   */
-  private boolean isSameYear(Date date, Date now) {
-    return date.getYear() == now.getYear();
-  }
-
-  /**
-   * This is used to get a efficient time for JS.
-   * Warning! Use TimerService if you want to actually test and control the 
time.
-   */
-  public double currentTimeMillis() {
-    // Use an optimised time for JS when running in JS.
-    if (!GWT.isClient()) {
-      return System.currentTimeMillis();
-    } else {
-      return Duration.currentTimeMillis();
-    }
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/051db092/wave/src/main/java/org/waveprotocol/wave/client/common/util/DomHelper.java
----------------------------------------------------------------------
diff --git 
a/wave/src/main/java/org/waveprotocol/wave/client/common/util/DomHelper.java 
b/wave/src/main/java/org/waveprotocol/wave/client/common/util/DomHelper.java
deleted file mode 100644
index 518a9b3..0000000
--- a/wave/src/main/java/org/waveprotocol/wave/client/common/util/DomHelper.java
+++ /dev/null
@@ -1,730 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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 org.waveprotocol.wave.client.common.util;
-
-import com.google.gwt.core.client.JavaScriptException;
-import com.google.gwt.core.client.JavaScriptObject;
-import com.google.gwt.core.client.JsArray;
-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.dom.client.Node;
-import com.google.gwt.dom.client.NodeList;
-import com.google.gwt.dom.client.Style.Display;
-import com.google.gwt.user.client.Event;
-import com.google.gwt.user.client.ui.impl.FocusImpl;
-
-import org.waveprotocol.wave.model.document.util.Point;
-import org.waveprotocol.wave.model.util.CollectionUtils;
-import org.waveprotocol.wave.model.util.IdentitySet;
-import org.waveprotocol.wave.model.util.Preconditions;
-import org.waveprotocol.wave.model.util.ReadableStringSet;
-import org.waveprotocol.wave.model.util.StringSet;
-
-
-/**
- * Helper methods
- *
- * Some adapted from UIElement, so the interface could do with increasing 
consistency
- *
- * TODO(danilatos,user): Clean up / organise methods in this class
- *
- * @author [email protected] (Daniel Danilatos)
- */
-public class DomHelper {
-
-  /**
-   * Describes the editability of an element, ignoring its context (ancestor 
nodes, etc).
-   */
-  public enum ElementEditability {
-    /** The element is definitely editable */
-    EDITABLE,
-    /** The element is not editable */
-    NOT_EDITABLE,
-    /** The element is "neutral", which means its editability is inherited */
-    NEUTRAL
-  }
-
-  /** Webkit editability controlling css property */
-  public static final String WEBKIT_USER_MODIFY = "-webkit-user-modify";
-
-  /**
-   * Interface for receiving low-level javascript events
-   */
-  public interface JavaScriptEventListener {
-
-    /**
-     * @param name The event name, without any leading "on-" prefix
-     * @param event The native event object
-     */
-    void onJavaScriptEvent(String name, Event event);
-  }
-
-  private DomHelper() {}
-
-  /**
-   * Return true if the element is a text box
-   * @param element
-   * @return true if the element is a text box
-   */
-  public static boolean isTextBox(Element element) {
-    return "input".equalsIgnoreCase(element.getTagName())
-        && "text".equalsIgnoreCase(element.getAttribute("type"));
-  }
-
-  /**
-   * @param element
-   * @param styleName
-   * @return true if the element or an ancestor has the given stylename
-   */
-  public static boolean hasStyleOrAncestorHasStyle(Element element, String 
styleName) {
-    while (element != null) {
-      if (element.getClassName().indexOf(styleName) >= 0) {
-        return true;
-      }
-      element = element.getParentElement();
-    }
-    return false;
-  }
-
-  /**
-   * Cast to old-style Element.
-   *
-   * TODO(danilatos): Deprecate this method when GWT has updated everything to 
not require
-   * the old style Element.
-   *
-   * @param element new style element
-   * @return old style element
-   */
-  public static com.google.gwt.user.client.Element castToOld(Element element) {
-    return element.cast();
-  }
-
-  /**
-   * Create a div with the given style name set. Convenience method because
-   * this is such a common task
-   * @param styleName
-   * @return The created div element
-   */
-  public static DivElement createDivWithStyle(String styleName) {
-    DivElement d = Document.get().createDivElement();
-    d.setClassName(styleName);
-    return d;
-  }
-
-  /**
-   * Focus the element, if possible
-   * @param element
-   */
-  public static void focus(Element element) {
-    // NOTE(user): This may not work for divs, rather use getFocusImplForPanel
-    //               for divs.
-    try {
-      FocusImpl.getFocusImplForWidget().focus(castToOld(element));
-    } catch (Exception e) {
-      // Suppress null pointer condition
-    }
-  }
-
-  /**
-   * Blur the element, if possible
-   * @param element
-   *
-   * NOTE(user): Dan thinks this method should be deprecated, but is not
-   *               sure why... Dan, please update once you remember.
-   */
-  public static void blur(Element element) {
-    FocusImpl.getFocusImplForWidget().blur(castToOld(element));
-  }
-
-  /**
-   * Sets display:none on the given element if isVisible is false, and clears
-   * the display css property if isVisible is true.
-   *
-   * This idiom is commonly switched on a boolean, so this method takes care of
-   * the 5 lines of boilerplate.
-   *
-   * @param element
-   * @param isVisible
-   */
-  public static void setDisplayVisible(Element element, boolean isVisible) {
-    if (isVisible) {
-      element.getStyle().clearDisplay();
-    } else {
-      element.getStyle().setDisplay(Display.NONE);
-    }
-  }
-
-  /**
-   * Finds the index of an element in its parent's list of child elements.
-   * This is not the same as {@link #findChildIndex(Node)}, since it ignores
-   * non-element nodes. It is in line with the element-only view of a 
collection
-   * of children exposed by {@link Element#getFirstChildElement()} and
-   * {@link Element#getNextSiblingElement()}.
-   *
-   * @param child  an element
-   * @return the index of {@code child}, or -1 if {@code child} is not a child
-   *   of its parent.
-   * @see #findChildIndex(Node)
-   */
-  public static final int findChildElementIndex(Element child) {
-    Element parent = child.getParentElement();
-    Element e = parent.getFirstChildElement();
-    int i = 0;
-    while (e != null) {
-      if (e.equals(child)) {
-        return i;
-      } else {
-        e = e.getNextSiblingElement();
-        i++;
-      }
-    }
-    return -1;
-  }
-
-  /**
-   * Wrap at least one node
-   * @param with The element in which to wrap the nodes
-   * @param from First node to wrap
-   * @param toExcl Node after end of wrap range
-   */
-  public static void wrap(Element with, Node from, Node toExcl) {
-    from.getParentNode().insertBefore(with, from);
-    moveNodes(with, from, toExcl, null);
-  }
-
-  /**
-   * @param element The element to unwrap. If not attached, does nothing.
-   */
-  public static void unwrap(Element element) {
-    if (element.hasParentElement()) {
-      moveNodes(element.getParentElement(),
-          element.getFirstChild(), null, element.getNextSibling());
-      element.removeFromParent();
-    }
-  }
-
-  /**
-   * Insert before, but for a range of adjacent siblings
-   *
-   * TODO(danilatos): Apparently safari and firefox let you do this in one
-   *   go using ranges, which could be a lot faster than iterating manually.
-   *   Create a deferred binding implementation.
-   * @param parent
-   * @param from
-   * @param toExcl
-   * @param refChild
-   */
-  public static void moveNodes(Element parent, Node from, Node toExcl, Node 
refChild) {
-    for (Node n = from; n != toExcl; ) {
-      Node m = n;
-      n = n.getNextSibling();
-      parent.insertBefore(m, refChild);
-    }
-  }
-
-  /**
-   * Remove nodes in the given range from the DOM
-   * @param from
-   * @param toExcl
-   */
-  public static void removeNodes(Node from, Node toExcl) {
-    if (from == null || !from.hasParentElement()) {
-      return;
-    }
-    for (Node n = from; n != toExcl && n != null;) {
-      Node r = n;
-      n = n.getNextSibling();
-      r.removeFromParent();
-    }
-  }
-
-  /**
-   * Remove all children from an element
-   * @param element
-   */
-  public static void emptyElement(Element element) {
-    while (element.getFirstChild() != null) {
-      element.removeChild(element.getFirstChild());
-    }
-  }
-
-  /**
-   * Ensures the given container contains exactly one child, the given one.
-   * Provides the important property that if the container is already the 
parent
-   * of the given child, then the child is not removed and re-added, it is left
-   * there; any siblings, if present, are removed.
-   *
-   * @param container
-   * @param child
-   */
-  public static void setOnlyChild(Element container, Node child) {
-    if (child.getParentElement() != container) {
-      // simple case
-      emptyElement(container);
-      container.appendChild(child);
-    } else {
-      // tricky case - avoid removing then re-appending the same child
-      while (child.getNextSibling() != null) {
-        child.getNextSibling().removeFromParent();
-      }
-      while (child.getPreviousSibling() != null) {
-        child.getPreviousSibling().removeFromParent();
-      }
-    }
-  }
-
-  /**
-   * Swaps out the old element for the new element.
-   * The old element's children are added to the new element
-   *
-   * @param oldElement
-   * @param newElement
-   */
-  public static void replaceElement(Element oldElement, Element newElement) {
-
-    // TODO(danilatos): Profile this to see if it is faster to move the nodes 
first,
-    // and then remove, or the other way round. Profile and optimise some of 
these
-    // other methods too. Take dom mutation event handlers being registered 
into account.
-
-    if (oldElement.hasParentElement()) {
-      oldElement.getParentElement().insertBefore(newElement, oldElement);
-      oldElement.removeFromParent();
-    }
-
-    DomHelper.moveNodes(newElement, oldElement.getFirstChild(), null, null);
-  }
-
-  /**
-   * Make an element editable or not
-   *
-   * @param element
-   * @param whiteSpacePreWrap Whether to additionally turn on the white space
-   *   pre wrap property. If in doubt, set to true. This is what we use for
-   *   the editor. So for any concurrently editable areas and such, we must
-   *   use true. If false, does nothing (it does not clear the property).
-   * @param isEditable
-   * @return the same element for convenience
-   */
-  public static Element setContentEditable(Element element, boolean isEditable,
-      boolean whiteSpacePreWrap) {
-    if (UserAgent.isSafari()) {
-      // We MUST use the "plaintext-only" variant to prevent nasty things like
-      // Apple+B munging our dom without giving us a key event.
-
-      // Assertion in GWT stuffs this up... fix GWT, in the meantime use a 
string map
-      //      element.getStyle().setProperty("-webkit-user-modify",
-      //          isEditable ? "read-write-plaintext-only" : "read-only");
-
-      JsoView.as(element.getStyle()).setString("-webkit-user-modify",
-          isEditable ? "read-write-plaintext-only" : "read-only");
-    } else {
-      element.setAttribute("contentEditable", isEditable ? "true" : "false");
-    }
-
-    if (whiteSpacePreWrap) {
-      // More GWT assertion fun!
-      JsoView.as(element.getStyle()).setString("white-space", "pre-wrap");
-    }
-
-    return element;
-  }
-
-  /**
-   * Checks whether the given DOM element is editable, either explicitly or
-   * inherited from its ancestors.
-   * @param e Element to check
-   */
-  public static boolean isEditable(Element e) {
-    // special early-exit for problematic shadow dom:
-    if (isUnreadable(e)) {
-      return true;
-    }
-
-    Element docElement = Document.get().getDocumentElement();
-    do {
-      ElementEditability editability = getElementEditability(e);
-      if (editability == ElementEditability.NEUTRAL) {
-        if (e == docElement) {
-          return false;
-        }
-        e = e.getParentElement();
-      } else {
-        return editability == ElementEditability.EDITABLE ? true : false;
-      }
-    } while (e != null);
-
-    // NOTE(danilatos): We didn't hit the body. The only way I know that this 
can happen
-    // is if the browser gave us a text node from its SHADOW dom, e.g. in a 
text box,
-    // which doesn't have any text node children. I've observed the parent of 
this text node
-    // to be reported as a div, and the parent of that div to be null.
-    return true;
-  }
-
-  public static ElementEditability getElementEditability(Element elem) {
-    // NOTE(danilatos): This is not necessarily accurate in 100% of 
situations, with weird
-    // combinations of editability/enabled etc attributes and tagnames...
-
-    String tagName = null;
-    try {
-      tagName = elem.getTagName();
-    } catch (Exception exception) {
-      // Couldn't get access to the tag name for some reason (see b/2314641).
-    }
-
-    if (tagName != null) {
-      tagName = tagName.toLowerCase();
-      if (tagName.equals("input") || tagName.equals("textarea")) {
-        return ElementEditability.EDITABLE;
-      }
-    }
-
-    return getContentEditability(elem);
-  }
-
-  /**
-   * @param element
-   * @return editability in terms of content-editable only (ignore tag names)
-   */
-  public static ElementEditability getContentEditability(Element element) {
-    String editability = null;
-    if (UserAgent.isSafari()) {
-      JsoView style = JsoView.as(element.getStyle());
-      editability = style.getString(WEBKIT_USER_MODIFY);
-      if ("read-write-plaintext-only".equalsIgnoreCase(editability) ||
-          "read-write".equalsIgnoreCase(editability)) {
-        return ElementEditability.EDITABLE;
-      } else if (editability != null && !editability.isEmpty()) {
-        return ElementEditability.NOT_EDITABLE;
-      }
-
-      // NOTE(danilatos): The css property overrides the contentEditable 
attribute.
-      // Still keep going just to check the content editable prop, if no css 
property set.
-    }
-    try {
-      editability = element.getAttribute("contentEditable");
-    } catch (JavaScriptException e) {
-      String elementString = "<couldn't get element string>";
-      String elementTag = "<couldn't get element tag>";
-      try {
-        elementString = element.toString();
-      } catch (Exception exception) { }
-      try {
-        elementTag = element.getTagName();
-      } catch (Exception exception) { }
-
-      StringBuilder sb = new StringBuilder();
-      sb.append("Couldn't get the 'contentEditable' attribute for element '");
-      sb.append(elementString).append("' tag name = ").append(elementTag);
-      throw new RuntimeException(sb.toString(), e);
-    }
-    if (editability == null || editability.isEmpty()) {
-      return ElementEditability.NEUTRAL;
-    } else {
-      return "true".equalsIgnoreCase(editability)
-          ? ElementEditability.EDITABLE : ElementEditability.NOT_EDITABLE;
-    }
-  }
-
-  /**
-   * Sets the spell check attribute on the element.
-   * @param enabled  true to enable spell check, false to disable.
-   */
-  public static void setNativeSpellCheck(Element element, boolean enabled) {
-    element.setAttribute("spellcheck", enabled ? "true" : "false");
-  }
-
-  /**
-   * Makes an element, and all its descendant elements, unselectable.
-   */
-  public static void makeUnselectable(Element e) {
-    if (UserAgent.isIE()) {
-      e.setAttribute("unselectable", "on");
-      e = e.getFirstChildElement();
-      while (e != null) {
-        makeUnselectable(e);
-        e = e.getNextSiblingElement();
-      }
-    }
-  }
-
-  /**
-   * Used to remove event handlers from elements
-   *
-   * @see DomHelper#registerEventHandler(Element, String, 
JavaScriptEventListener)
-   */
-  public static final class HandlerReference extends JavaScriptObject {
-
-    /***/
-    protected HandlerReference() {}
-
-    /**
-     * Unregister a handler registered with
-     * {@link #registerEventHandler(Element, String, JavaScriptEventListener)} 
or
-     * {@link #registerEventHandler(Element, String, boolean, 
JavaScriptEventListener)}
-     *
-     * @return true if the handler was unregistered, false if unregister had
-     *   already been called.
-     */
-    public native boolean unregister() /*-{
-      var el = this.$el;
-      if (el == null) {
-        return false;
-      }
-
-      if (el.removeEventListener) {
-        el.removeEventListener(this.$ev, this, this.$cp);
-      } else if (el.detachEvent) {
-        el.detachEvent('on' + this.$ev, this);
-      } else {
-        el['on' + this.$ev] = null;
-      }
-
-      this.$ev = null;
-      return true;
-    }-*/;
-  }
-
-  /**
-   * A set of {@link HandlerReference} for when registering and unregistering a
-   * handler on multiple events at once.
-   */
-  public static final class HandlerReferenceSet {
-    public IdentitySet<HandlerReference> references = 
CollectionUtils.createIdentitySet();
-
-    public void unregister() {
-      Preconditions.checkState(references != null, "References already 
unregistered");
-      references.each(new IdentitySet.Proc<HandlerReference>() {
-        @Override
-        public void apply(HandlerReference ref) {
-          ref.unregister();
-        }
-      });
-      references = null;
-    }
-  }
-
-  /**
-   * A low level way to register event handlers on dom elements. This differs
-   * from sinkEvents in that it has nothing to do with widgets, and also allows
-   * specifying any event name as a string.
-   *
-   * NOTE(danilatos): Care must be taken when using this low-level technique,
-   * you will need to handle your own cleanup to avoid memory leaks.
-   *
-   * @param el The dom element on which to listen to events
-   * @param eventName The name of the event, without any "on-" prefix
-   * @param listener
-   * @return a handler to be used with de-registering
-   */
-  public static HandlerReference registerEventHandler(Element el,
-      String eventName, JavaScriptEventListener listener) {
-    return registerEventHandler(el, eventName, false, listener);
-  }
-
-  // TODO(danilatos): Split the implementation out into browser-specific 
versions
-
-  /**
-   * Same as {@link #registerEventHandler(Element, String, 
JavaScriptEventListener)}
-   * except provides the (non-cross-browser) capture parameter
-   */
-  public static native HandlerReference registerEventHandler(Element el,
-      String eventName, boolean capture, JavaScriptEventListener listener) /*-{
-
-    var func = $entry(function(e) {
-      var evt = e || $wnd.event;
-      listener.
-          
@org.waveprotocol.wave.client.common.util.DomHelper.JavaScriptEventListener::onJavaScriptEvent(Ljava/lang/String;Lcom/google/gwt/user/client/Event;)
-          (eventName, evt);
-    });
-
-    if (el.addEventListener) {
-        el.addEventListener(eventName, func, capture);
-    } else if (el.attachEvent) {
-        el.attachEvent('on' + eventName, func);
-    } else {
-        el['on' + eventName.toLowerCase()] = func;
-    }
-
-    // Setup handler reference object
-    func.$ev = eventName;
-    func.$cp = capture;
-    func.$el = el;
-    return func;
-  }-*/;
-
-  /**
-   * Registers a listener for multiple browser events in one go
-   *
-   * @param el element to listen on
-   * @param eventNames set of events
-   * @param listener
-   * @return a reference set to be used for unregistering the handler for all
-   *         events in one go
-   */
-  public static HandlerReferenceSet registerEventHandler(final Element el,
-      ReadableStringSet eventNames, final JavaScriptEventListener listener) {
-    Preconditions.checkArgument(!eventNames.isEmpty(), "registerEventHandler: 
Event set is empty");
-    final HandlerReferenceSet referenceSet = new HandlerReferenceSet();
-    eventNames.each(new StringSet.Proc() {
-      @Override
-      public void apply(String eventName) {
-        referenceSet.references.add(registerEventHandler(el, eventName, 
listener));
-      }
-    });
-    return referenceSet;
-  }
-
-  /**
-   * @return true if it is an element
-   */
-  public static boolean isElement(Node n) {
-    return n.getNodeType() == Node.ELEMENT_NODE;
-  }
-
-  /**
-   * @return true if it is a text node
-   */
-  public static boolean isTextNode(Node n) {
-    return n.getNodeType() == Node.TEXT_NODE;
-  }
-
-  /**
-   * Finds the index of an element among its parent's children, including
-   * text nodes.
-   * @param toFind the node to retrieve the index for
-   * @return index of element
-   *
-   * TODO(danilatos): This could probably be done faster with
-   * a binary search using text ranges.
-   * TODO(lars): adapt to non standard browsers.
-   * TODO(lars): is there a single js call that does this?
-   */
-  public static native int findChildIndex(Node toFind) /*-{
-    var parent = toFind.parentNode;
-    var count = 0, child = parent.firstChild;
-    while (child) {
-      if (child == toFind)
-        return count;
-      if (child.nodeType == 1 || child.nodeType == 3)
-        ++count;
-      child = child.nextSibling;
-    }
-
-    return -1;
-  }-*/;
-
-  /**
-   * The last child of element this element. If there is no such element, this
-   * returns null.
-   */
-  // GWT forgot to add Element.getLastChildElement(), to be symmetric with
-  // Element.getFirstChildElement().
-  public static native Element getLastChildElement(Element elem) /*-{
-    var child = elem.lastChild;
-    while (child && child.nodeType != 1)
-      child = child.previousSibling;
-    return child;
-  }-*/;  
-  
-  /**
-   * Gets a list of descendants of e that match the given class name.
-   *
-   * If the browser has the native method, that will be called. Otherwise, it
-   * traverses descendents of the given element and returns the list of 
elements
-   * with matching classname.
-   *
-   * @param e
-   * @param className
-   */
-  public static NodeList<Element> getElementsByClassName(Element e, String 
className) {
-    if (QuirksConstants.SUPPORTS_GET_ELEMENTS_BY_CLASSNAME) {
-      return getElementsByClassNameNative(e, className);
-    } else {
-      NodeList<Element> all = e.getElementsByTagName("*");
-      if (all == null) {
-        return null;
-      }
-      JsArray<Element> ret = JavaScriptObject.createArray().cast();
-      for (int i = 0; i < all.getLength(); ++i) {
-        Element item = all.getItem(i);
-        if (className.equals(item.getClassName())) {
-          ret.push(item);
-        }
-      }
-      return ret.cast();
-    }
-  }
-
-  private static native NodeList<Element> getElementsByClassNameNative(
-      Element e, String className) /*-{
-    return e.getElementsByClassName(className);
-  }-*/;
-
-
-  /**
-   * Checks whether the properties of given node cannot be accessed (by 
testing the nodeType).
-   *
-   * It is sometimes the case where we need to access properties of a Node, 
but the properties
-   * on that node are not readable (for example, a shadow node like a div 
created to hold the
-   * selection within an input field).
-   *
-   * In these cases, when the javascript cannot access the node's properties, 
any attempt to do
-   * so may cause an internal permissions exception. This method swallows the 
exception and uses
-   * its existence to indicate whether or not the node is actually readable.
-   *
-   * @param n Node to check
-   * @return Whether or not the node can have properties read.
-   */
-  public static boolean isUnreadable(Node n) {
-    try {
-      n.getNodeType();
-      return false;
-    } catch (RuntimeException e) {
-      return true;
-    }
-  }
-
-  /**
-   * Converts a nodelet/offset pair to a Point of Node.
-   * Just a simple mapping, it is agnostic to inconsistencies, filtered views, 
etc.
-   * @param node
-   * @param offset
-   * @return html node point
-   */
-  public static Point<Node> nodeOffsetToNodeletPoint(Node node, int offset) {
-    if (isTextNode(node)) {
-      return Point.inText(node, offset);
-    } else {
-      Element container = node.<Element>cast();
-      return Point.inElement(container, nodeAfterFromOffset(container, 
offset));
-    }
-  }
-
-  /**
-   * Given a node/offset pair, return the node after the point.
-   *
-   * @param container
-   * @param offset
-   */
-  public static Node nodeAfterFromOffset(Element container, int offset) {
-    return offset >= container.getChildCount() ? null : 
container.getChild(offset);
-  }
-}

Reply via email to