/*******************************************************************************
* Copyright (c) 2011 Subgraph.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Subgraph - initial API and implementation
******************************************************************************/
package com.subgraph.vega.impl.scanner.modules.scripting.dom;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.FunctionObject;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableObject;
import org.w3c.dom.Attr;
import org.w3c.dom.CharacterData;
import org.w3c.dom.Comment;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
import org.w3c.dom.html2.HTMLDocument;
import org.w3c.dom.html2.HTMLElement;
public class NodeJS extends ScriptableObject {
static NodeJS domNodeToJS(Node node, DocumentJS document) {
synchronized(document) {
if(node == null)
return null;
NodeJS cachedNode = document.findCachedNode(node);
if(cachedNode != null)
return cachedNode;
NodeJS newNode = createNodeJSFromDomNode(node, document);
if(newNode != null)
document.putCachedNode(node, newNode);
return newNode;
}
}
private static NodeJS createNodeJSFromDomNode(Node node, DocumentJS document) {
if(node == null) {
return null;
} else if (node instanceof HTMLElement) {
return HTMLElementJS.domHTMLElementToJS((HTMLElement) node, document);
} else if (node instanceof HTMLDocument) {
return document;
} else if(node instanceof Comment) {
return new CommentJS((Comment) node, document);
} else if(node instanceof Text) {
return new TextJS((Text) node, document);
} else if(node instanceof CharacterData) {
return new CharacterDataJS((CharacterData) node, document);
} else if(node instanceof Attr) {
return new AttrJS((Attr) node, document);
} else if(node instanceof Document) {
return document;
} else if(node instanceof Element) {
return new ElementJS((Element) node, document);
} else {
return new NodeJS(node, document);
}
}
private static final long serialVersionUID = 1L;
private Node node;
private DocumentJS documentJS;
public NodeJS() {
this.node = null;
this.documentJS = null;
}
public NodeJS(Node node, DocumentJS document) {
if(node == null)
throw new NullPointerException("Node cannot be null");
this.node = node;
this.documentJS = document;
}
protected void setNode(Node node) {
this.node = node;
}
protected void setDocumentJS(DocumentJS document) {
this.documentJS = document;
}
DocumentJS getDocumentJS() {
return documentJS;
}
public void jsConstructor(Object ob) {
}
protected void exportObject(Scriptable ob) {
if(ob == null)
return;
final Scriptable scope = ScriptableObject.getTopLevelScope(this);
ob.setParentScope(scope);
ob.setPrototype(ScriptableObject.getClassPrototype(scope, ob.getClassName()));
}
protected NodeJS exportNode(Node node) {
if(node == null)
return null;
NodeJS nodeJS = domNodeToJS(node, documentJS);
exportObject(nodeJS);
return nodeJS;
}
protected NodeListJS exportNodeList(NodeList nodeList) {
if(nodeList == null)
return null;
NodeListJS nl = new NodeListJS(nodeList, ScriptableObject.getTopLevelScope(this), documentJS);
exportObject(nl);
return nl;
}
private Scriptable createNodeArray(Object[] nodes) {
final Scriptable scope = ScriptableObject.getTopLevelScope(this);
final Context cx = Context.getCurrentContext();
Scriptable array = cx.newArray(scope, nodes);
exportObject(array);
return array;
}
public Scriptable jsGet_attributes() {
final NamedNodeMap attributes = node.getAttributes();
final Object[] nodes = new Object[attributes.getLength()];
for(int i = 0; i < attributes.getLength(); i++) {
nodes[i] = exportNode(attributes.item(i));
}
return createNodeArray(nodes);
}
public Scriptable jsGet_childNodes() {
return exportNodeList(node.getChildNodes());
}
public Scriptable jsGet_firstChild() {
return exportNode(node.getFirstChild());
}
public Scriptable jsGet_lastChild() {
return exportNode(node.getLastChild());
}
public String jsGet_localname() {
return node.getLocalName();
}
public String jsGet_namespaceURI() {
return node.getNamespaceURI();
}
public Scriptable jsGet_nextSibling() {
return exportNode(node.getNextSibling());
}
public String jsGet_nodeName() {
return node.getNodeName();
}
public int jsGet_nodeType() {
return node.getNodeType();
}
public String jsGet_nodeValue() {
return node.getNodeValue();
}
public Scriptable jsGet_ownerDocument() {
return exportNode(node.getOwnerDocument());
}
public Scriptable jsGet_parentNode() {
return exportNode(node.getParentNode());
}
public String jsGet_prefix() {
return node.getPrefix();
}
public Scriptable jsGet_previousSibling() {
return exportNode(node.getPreviousSibling());
}
public Scriptable jsFunction_appendChild(Scriptable newChild) throws DOMException {
return null;
}
public Scriptable jsFunction_cloneNode(boolean deep) {
return null;
}
public boolean jsFunction_hasAttributes() {
return node.hasAttributes();
}
public boolean jsFunction_hasChildNodes() {
return node.hasChildNodes();
}
public Scriptable jsFunction_insertBefore(Scriptable newChild, Scriptable refChild) throws DOMException {
return null;
}
public boolean jsFunction_isSupported(String feature, String version) {
return node.isSupported(feature, version);
}
public void jsFunction_normalize() {
node.normalize();
}
public Scriptable jsFunction_removeChild(Scriptable oldChild) throws DOMException {
return null;
}
public Scriptable jsFunction_replaceChild(Scriptable newChild, Scriptable oldChild) throws DOMException {
return null;
}
@Override
public String getClassName() {
return "Node";
}
public static void finishInit(Scriptable scope, FunctionObject ctor, Scriptable prototype) {
ctor.defineProperty("ELEMENT_NODE", Node.ELEMENT_NODE, READONLY);
ctor.defineProperty("ATTRIBUTE_NODE", Node.ATTRIBUTE_NODE, READONLY);
ctor.defineProperty("TEXT_NODE", Node.TEXT_NODE, READONLY);
ctor.defineProperty("CDATA_SECTION_NODE", Node.CDATA_SECTION_NODE, READONLY);
ctor.defineProperty("PROCESSING_INSTRUCTION_NODE", Node.PROCESSING_INSTRUCTION_NODE, READONLY);
ctor.defineProperty("COMMENT_NODE", Node.COMMENT_NODE, READONLY);
ctor.defineProperty("DOCUMENT_NODE", Node.DOCUMENT_NODE, READONLY);
ctor.defineProperty("DOCUMENT_TYPE_NODE", Node.DOCUMENT_TYPE_NODE, READONLY);
ctor.defineProperty("DOCUMENT_FRAGMENT_NODE", Node.DOCUMENT_FRAGMENT_NODE, READONLY);
}
public int jsFunction_compareDocumentPosition(Scriptable other) {
if(!(other instanceof NodeJS)) {
throw Context.reportRuntimeError("compareDocumentPosition must be called with a Node argument");
}
final Node otherNode = ((NodeJS)other).node;
return node.compareDocumentPosition(otherNode);
}
}