/**
* Copyright 2010 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 org.waveprotocol.wave.client.wavepanel.block.xml;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
import org.waveprotocol.wave.client.wavepanel.block.BlockStructure;
/**
* Exposes an XML block dom as a view structure.
*
*/
public final class XmlStructure implements BlockStructure {
/**
* JSO access to a DOM node.
*/
public final static class XmlNode extends JavaScriptObject implements BlockStructure.Node {
//
// Schema: <x id="X..." k="n"></x>
//
// Block ids are quoted by prepending "X", so as not to clash with HTML
// views.
// "n" is the ordinal of the NodeType enum.
//
protected XmlNode() {
}
public static XmlNode of(JavaScriptObject jso) {
return (XmlNode) jso;
}
private static String quoteId(String id) {
return "X" + id;
}
private static String unquoteId(String value) {
return value.substring(1);
}
@Override
public String getId() {
return unquoteId(getAttribute("id"));
}
@Override
public NodeType getType() {
int type = getTypeInt();
if (type < 0) {
String id = getAttribute("id");
String kind = getAttribute("k");
throw new RuntimeException("bad kind: " + kind + ", on id: " + id);
}
return NodeType.values()[type];
}
private native String getAttribute(String name) /*-{
return this.getAttribute(name);
}-*/;
// For some reason, parseInt fails come back as doubles (NaN), so the JSNI
// has to handle the error case in order to return ints safely.
private native int getTypeInt() /*-{
var k = parseInt(this.getAttribute("k"));
return k >= 0 ? k : -1;
}-*/;
@Override
public native XmlNode getFirstChild() /*-{
return this.firstChild;
}-*/;
@Override
public native XmlNode getLastChild() /*-{
return this.lastChild;
}-*/;
@Override
public native XmlNode getNextSibling() /*-{
return this.nextSibling;
}-*/;
@Override
public native XmlNode getParent() /*-{
return this.parentNode;
}-*/;
@Override
public native XmlNode getPreviousSibling() /*-{
return this.previousSibling;
}-*/;
}
private final XmlNode root;
private XmlStructure(XmlNode root) {
this.root = root;
}
public static XmlStructure create(String id) {
return new XmlStructure(XmlNode.of(Document.get().getElementById(XmlNode.quoteId(id))));
}
@Override
public XmlNode getRoot() {
return root;
}
@Override
public XmlNode getNode(String id) {
return XmlNode.of(Document.get().getElementById(XmlNode.quoteId(id)));
}
/**
* Detaches the XML tree from the DOM. Use with caution.
* {@link #getNode(String)} will not work after this.
*/
public void detach() {
if (root != null) {
Element.as(root).removeFromParent();
}
}
}