View Javadoc

1   /**********************************************
2    * Copyright (C) 2010 Lukas Laag
3    * This file is part of lib-gwt-svg.
4    * 
5    * libgwtsvg is free software: you can redistribute it and/or modify
6    * it under the terms of the GNU Lesser General Public License as published by
7    * the Free Software Foundation, either version 3 of the License, or
8    * (at your option) any later version.
9    * 
10   * libgwtsvg is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   * GNU Lesser General Public License for more details.
14   * 
15   * You should have received a copy of the GNU Lesser General Public License
16   * along with libgwtsvg.  If not, see http://www.gnu.org/licenses/
17   **********************************************/
18  /*
19   * Copyright (c) 2004 World Wide Web Consortium,
20   *
21   * (Massachusetts Institute of Technology, European Research Consortium for
22   * Informatics and Mathematics, Keio University). All Rights Reserved. This
23   * work is distributed under the W3C(r) Software License [1] in the hope that
24   * it will be useful, but WITHOUT ANY WARRANTY; without even the implied
25   * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
26   *
27   * [1] http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231
28   */
29  package org.vectomatic.dom.svg.utils;
30  
31  import java.util.Iterator;
32  import java.util.NoSuchElementException;
33  
34  import org.vectomatic.dom.svg.OMElement;
35  import org.vectomatic.dom.svg.OMNode;
36  import org.vectomatic.dom.svg.OMSVGElement;
37  import org.vectomatic.dom.svg.impl.Attr;
38  import org.vectomatic.dom.svg.impl.DOMHelperImpl;
39  import org.vectomatic.dom.svg.impl.NamedNodeMap;
40  import org.w3c.dom.DOMException;
41  
42  import com.google.gwt.core.client.GWT;
43  import com.google.gwt.core.client.JavaScriptException;
44  import com.google.gwt.core.client.JavaScriptObject;
45  import com.google.gwt.dom.client.Document;
46  import com.google.gwt.dom.client.Element;
47  import com.google.gwt.dom.client.Node;
48  import com.google.gwt.dom.client.NodeList;
49  import com.google.gwt.dom.client.Text;
50  import com.google.gwt.event.dom.client.LoseCaptureHandler;
51  import com.google.gwt.event.shared.HandlerRegistration;
52  
53  /**
54   * Class to group miscellaneous DOM level 2 methods. These
55   * methods are missing from the GWT DOM overlay types (such as 
56   * {@link com.google.gwt.dom.client.Element} or {@link com.google.gwt.dom.client.Node})
57   * but exist in almost all browsers and are sometimes required
58   * to develop an SVG application.
59   * @author laaglu
60   */
61  public class DOMHelper {
62  	private static final DOMHelperImpl impl = GWT.create(DOMHelperImpl.class);
63  	
64      /**
65       * Creates an element of the given qualified name and namespace URI.
66       * <br>Per [<a href='http://www.w3.org/TR/1999/REC-xml-names-19990114/'>XML Namespaces</a>]
67       * , applications must use the value <code>null</code> as the 
68       * namespaceURI parameter for methods if they wish to have no namespace.
69       * @param document The document in which the element is to be created.
70       * @param namespaceURI The namespace URI of the element to create.
71       * @param qualifiedName The qualified name of the element type to 
72       *   instantiate.
73       * @return A new <code>Element</code> object with the following 
74       *   attributes:
75       * <table border='1' cellpadding='3'>
76       * <tr>
77       * <th>Attribute</th>
78       * <th>Value</th>
79       * </tr>
80       * <tr>
81       * <td valign='top' rowspan='1' colspan='1'><code>Node.nodeName</code></td>
82       * <td valign='top' rowspan='1' colspan='1'>
83       *   <code>qualifiedName</code></td>
84       * </tr>
85       * <tr>
86       * <td valign='top' rowspan='1' colspan='1'><code>Node.namespaceURI</code></td>
87       * <td valign='top' rowspan='1' colspan='1'>
88       *   <code>namespaceURI</code></td>
89       * </tr>
90       * <tr>
91       * <td valign='top' rowspan='1' colspan='1'><code>Node.prefix</code></td>
92       * <td valign='top' rowspan='1' colspan='1'>prefix, extracted 
93       *   from <code>qualifiedName</code>, or <code>null</code> if there is 
94       *   no prefix</td>
95       * </tr>
96       * <tr>
97       * <td valign='top' rowspan='1' colspan='1'><code>Node.localName</code></td>
98       * <td valign='top' rowspan='1' colspan='1'>local name, extracted from 
99       *   <code>qualifiedName</code></td>
100      * </tr>
101      * <tr>
102      * <td valign='top' rowspan='1' colspan='1'><code>Element.tagName</code></td>
103      * <td valign='top' rowspan='1' colspan='1'>
104      *   <code>qualifiedName</code></td>
105      * </tr>
106      * </table>
107      * @exception DOMException
108      *   INVALID_CHARACTER_ERR: Raised if the specified 
109      *   <code>qualifiedName</code> is not an XML name according to the XML 
110      *   version in use specified in the <code>Document.xmlVersion</code> 
111      *   attribute.
112      *   <br>NAMESPACE_ERR: Raised if the <code>qualifiedName</code> is a 
113      *   malformed qualified name, if the <code>qualifiedName</code> has a 
114      *   prefix and the <code>namespaceURI</code> is <code>null</code>, or 
115      *   if the <code>qualifiedName</code> has a prefix that is "xml" and 
116      *   the <code>namespaceURI</code> is different from "<a href='http://www.w3.org/XML/1998/namespace'>
117      *   http://www.w3.org/XML/1998/namespace</a>" [<a href='http://www.w3.org/TR/1999/REC-xml-names-19990114/'>XML Namespaces</a>]
118      *   , or if the <code>qualifiedName</code> or its prefix is "xmlns" and 
119      *   the <code>namespaceURI</code> is different from "<a href='http://www.w3.org/2000/xmlns/'>http://www.w3.org/2000/xmlns/</a>", or if the <code>namespaceURI</code> is "<a href='http://www.w3.org/2000/xmlns/'>http://www.w3.org/2000/xmlns/</a>" and neither the <code>qualifiedName</code> nor its prefix is "xmlns".
120      *   <br>NOT_SUPPORTED_ERR: Always thrown if the current document does not 
121      *   support the <code>"XML"</code> feature, since namespaces were 
122      *   defined by XML.
123      */
124 	public static final native Element createElementNS(Document document, String namespaceURI, String qualifiedName) throws JavaScriptException /*-{
125 	  return document.createElementNS(namespaceURI, qualifiedName);
126 	}-*/;
127 	
128 	/**
129 	 * Creates a new empty SVG document
130 	 * @return
131 	 * a new empty SVG document
132 	 */
133 	public static final native Document createDocument(String uri, String qname) /*-{
134     	return $doc.implementation.createDocument(uri, qname, null);
135 	}-*/;
136 
137     /**
138      * Imports a node from another document to this document, without altering 
139      * or removing the source node from the original document; this method 
140      * creates a new copy of the source node. The returned node has no 
141      * parent; (<code>parentNode</code> is <code>null</code>).
142      * <br>For all nodes, importing a node creates a node object owned by the 
143      * importing document, with attribute values identical to the source 
144      * node's <code>nodeName</code> and <code>nodeType</code>, plus the 
145      * attributes related to namespaces (<code>prefix</code>, 
146      * <code>localName</code>, and <code>namespaceURI</code>). As in the 
147      * <code>cloneNode</code> operation, the source node is not altered. 
148      * User data associated to the imported node is not carried over. 
149      * However, if any <code>UserDataHandlers</code> has been specified 
150      * along with the associated data these handlers will be called with the 
151      * appropriate parameters before this method returns.
152      * <br>Additional information is copied as appropriate to the 
153      * <code>nodeType</code>, attempting to mirror the behavior expected if 
154      * a fragment of XML or HTML source was copied from one document to 
155      * another, recognizing that the two documents may have different DTDs 
156      * in the XML case. The following list describes the specifics for each 
157      * type of node. 
158      * <dl>
159      * <dt>ATTRIBUTE_NODE</dt>
160      * <dd>The <code>ownerElement</code> attribute 
161      * is set to <code>null</code> and the <code>specified</code> flag is 
162      * set to <code>true</code> on the generated <code>Attr</code>. The 
163      * descendants of the source <code>Attr</code> are recursively imported 
164      * and the resulting nodes reassembled to form the corresponding subtree.
165      * Note that the <code>deep</code> parameter has no effect on 
166      * <code>Attr</code> nodes; they always carry their children with them 
167      * when imported.</dd>
168      * <dt>DOCUMENT_FRAGMENT_NODE</dt>
169      * <dd>If the <code>deep</code> option 
170      * was set to <code>true</code>, the descendants of the source 
171      * <code>DocumentFragment</code> are recursively imported and the 
172      * resulting nodes reassembled under the imported 
173      * <code>DocumentFragment</code> to form the corresponding subtree. 
174      * Otherwise, this simply generates an empty 
175      * <code>DocumentFragment</code>.</dd>
176      * <dt>DOCUMENT_NODE</dt>
177      * <dd><code>Document</code> 
178      * nodes cannot be imported.</dd>
179      * <dt>DOCUMENT_TYPE_NODE</dt>
180      * <dd><code>DocumentType</code> 
181      * nodes cannot be imported.</dd>
182      * <dt>ELEMENT_NODE</dt>
183      * <dd><em>Specified</em> attribute nodes of the source element are imported, and the generated 
184      * <code>Attr</code> nodes are attached to the generated 
185      * <code>Element</code>. Default attributes are <em>not</em> copied, though if the document being imported into defines default 
186      * attributes for this element name, those are assigned. If the 
187      * <code>importNode</code> <code>deep</code> parameter was set to 
188      * <code>true</code>, the descendants of the source element are 
189      * recursively imported and the resulting nodes reassembled to form the 
190      * corresponding subtree.</dd>
191      * <dt>ENTITY_NODE</dt>
192      * <dd><code>Entity</code> nodes can be 
193      * imported, however in the current release of the DOM the 
194      * <code>DocumentType</code> is readonly. Ability to add these imported 
195      * nodes to a <code>DocumentType</code> will be considered for addition 
196      * to a future release of the DOM.On import, the <code>publicId</code>, 
197      * <code>systemId</code>, and <code>notationName</code> attributes are 
198      * copied. If a <code>deep</code> import is requested, the descendants 
199      * of the the source <code>Entity</code> are recursively imported and 
200      * the resulting nodes reassembled to form the corresponding subtree.</dd>
201      * <dt>
202      * ENTITY_REFERENCE_NODE</dt>
203      * <dd>Only the <code>EntityReference</code> itself is 
204      * copied, even if a <code>deep</code> import is requested, since the 
205      * source and destination documents might have defined the entity 
206      * differently. If the document being imported into provides a 
207      * definition for this entity name, its value is assigned.</dd>
208      * <dt>NOTATION_NODE</dt>
209      * <dd>
210      * <code>Notation</code> nodes can be imported, however in the current 
211      * release of the DOM the <code>DocumentType</code> is readonly. Ability 
212      * to add these imported nodes to a <code>DocumentType</code> will be 
213      * considered for addition to a future release of the DOM.On import, the 
214      * <code>publicId</code> and <code>systemId</code> attributes are copied.
215      * Note that the <code>deep</code> parameter has no effect on this type 
216      * of nodes since they cannot have any children.</dd>
217      * <dt>
218      * PROCESSING_INSTRUCTION_NODE</dt>
219      * <dd>The imported node copies its 
220      * <code>target</code> and <code>data</code> values from those of the 
221      * source node.Note that the <code>deep</code> parameter has no effect 
222      * on this type of nodes since they cannot have any children.</dd>
223      * <dt>TEXT_NODE, 
224      * CDATA_SECTION_NODE, COMMENT_NODE</dt>
225      * <dd>These three types of nodes inheriting 
226      * from <code>CharacterData</code> copy their <code>data</code> and 
227      * <code>length</code> attributes from those of the source node.Note 
228      * that the <code>deep</code> parameter has no effect on these types of 
229      * nodes since they cannot have any children.</dd>
230      * </dl> 
231      * @param document The document in which to import the node.
232      * @param importedNode The node to import.
233      * @param deep If <code>true</code>, recursively import the subtree under 
234      *   the specified node; if <code>false</code>, import only the node 
235      *   itself, as explained above. This has no effect on nodes that cannot 
236      *   have any children, and on <code>Attr</code>, and 
237      *   <code>EntityReference</code> nodes.
238      * @return The imported node that belongs to this <code>Document</code>.
239      * @exception DOMException
240      *   NOT_SUPPORTED_ERR: Raised if the type of node being imported is not 
241      *   supported.
242      *   <br>INVALID_CHARACTER_ERR: Raised if one of the imported names is not 
243      *   an XML name according to the XML version in use specified in the 
244      *   <code>Document.xmlVersion</code> attribute. This may happen when 
245      *   importing an XML 1.1 [<a href='http://www.w3.org/TR/2004/REC-xml11-20040204/'>XML 1.1</a>] element 
246      *   into an XML 1.0 document, for instance.
247      */
248 	public static final native Node importNode(Document document, Node importedNode, boolean deep) /*-{
249 		return document.importNode(importedNode, deep);
250 	}-*/;
251 	
252     /**
253      *  Puts all <code>Text</code> nodes in the full depth of the sub-tree 
254      * underneath this <code>Node</code>, including attribute nodes, into a 
255      * "normal" form where only structure (e.g., elements, comments, 
256      * processing instructions, CDATA sections, and entity references) 
257      * separates <code>Text</code> nodes, i.e., there are neither adjacent 
258      * <code>Text</code> nodes nor empty <code>Text</code> nodes. This can 
259      * be used to ensure that the DOM view of a document is the same as if 
260      * it were saved and re-loaded, and is useful when operations (such as 
261      * XPointer [<a href='http://www.w3.org/TR/2003/REC-xptr-framework-20030325/'>XPointer</a>]
262      *  lookups) that depend on a particular document tree structure are to 
263      * be used. If the parameter "normalize-characters" of the 
264      * <code>DOMConfiguration</code> object attached to the 
265      * <code>Node.ownerDocument</code> is <code>true</code>, this method 
266      * will also fully normalize the characters of the <code>Text</code> 
267      * nodes. 
268      * <p ><b>Note:</b> In cases where the document contains 
269      * <code>CDATASections</code>, the normalize operation alone may not be 
270      * sufficient, since XPointers do not differentiate between 
271      * <code>Text</code> nodes and <code>CDATASection</code> nodes.
272      * @param node the node to normalize
273      */
274 	public static final native void normalize(Node node) /*-{
275 		return node.normalize();
276 	}-*/;
277 
278     /**
279      * Extracts a range of data from the node.
280      * @param text the text node
281      * @param offset Start offset of substring to extract.
282      * @param count The number of 16-bit units to extract.
283      * @return The specified substring. If the sum of <code>offset</code> and 
284      *   <code>count</code> exceeds the <code>length</code>, then all 16-bit 
285      *   units to the end of the data are returned.
286      * @exception DOMException
287      *   INDEX_SIZE_ERR: Raised if the specified <code>offset</code> is 
288      *   negative or greater than the number of 16-bit units in 
289      *   <code>data</code>, or if the specified <code>count</code> is 
290      *   negative.
291      *   <br>DOMSTRING_SIZE_ERR: Raised if the specified range of text does 
292      *   not fit into a <code>String</code>.
293      */
294 	public static final native String substringData(Text text, int offset, int count) throws JavaScriptException /*-{
295 	  return text.substringData(offset, count);
296 	}-*/;
297 
298     /**
299      * Append the string to the end of the character data of the node. Upon 
300      * success, <code>data</code> provides access to the concatenation of 
301      * <code>data</code> and the <code>String</code> specified.
302      * @param text the text node
303      * @param arg The <code>String</code> to append.
304      * @exception DOMException
305      *   NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
306      */
307 	public static final native void appendData(Text text, String arg) throws JavaScriptException /*-{
308 	  text.appendData(offset, arg);
309 	}-*/;
310 	
311     /**
312      * Retrieves an attribute value by local name and namespace URI on
313      * the specified element.
314      * <br>Per [<a href='http://www.w3.org/TR/1999/REC-xml-names-19990114/'>XML Namespaces</a>]
315      * , applications must use the value <code>null</code> as the 
316      * <code>namespaceURI</code> parameter for methods if they wish to have 
317      * no namespace.
318      * @param elem the element
319      * @param namespaceURI The namespace URI of the attribute to retrieve.
320      * @param localName The local name of the attribute to retrieve.
321      * @return The <code>Attr</code> value as a string, or the empty string 
322      *   if that attribute does not have a specified or default value.
323      * @exception DOMException
324      *   NOT_SUPPORTED_ERR: May be raised if the implementation does not 
325      *   support the feature <code>"XML"</code> and the language exposed 
326      *   through the Document does not support XML Namespaces (such as [<a href='http://www.w3.org/TR/1999/REC-html401-19991224/'>HTML 4.01</a>]). 
327      * @since DOM Level 2
328      */
329 	public static final native String getAttributeNS(Element elem, String namespaceURI, String localName) throws JavaScriptException /*-{
330 	  return elem.getAttributeNS(namespaceURI, localName);
331 	}-*/;
332 	
333     /**
334      * Returns a <code>NodeList</code> of all the descendant 
335      * <code>Elements</code> of the specified element
336      * with a given local name and namespace URI in 
337      * document order.
338      * @param elem The element
339      * @param namespaceURI The namespace URI of the elements to match on. The 
340      *   special value "*" matches all namespaces.
341      * @param localName The local name of the elements to match on. The 
342      *   special value "*" matches all local names.
343      * @return A new <code>NodeList</code> object containing all the matched 
344      *   <code>Elements</code>.
345      * @exception DOMException
346      *   NOT_SUPPORTED_ERR: May be raised if the implementation does not 
347      *   support the feature <code>"XML"</code> and the language exposed 
348      *   through the Document does not support XML Namespaces (such as [<a href='http://www.w3.org/TR/1999/REC-html401-19991224/'>HTML 4.01</a>]). 
349      * @since DOM Level 2
350      */
351 	public static final native NodeList<? extends Node> getElementsByTagNameNS(Element elem, String namespaceURI, String localName) throws JavaScriptException /*-{
352 	  return elem.getElementsByTagNameNS(namespaceURI, localName);
353 	}-*/;
354 	
355     /**
356      * Returns a <code>NodeList</code> of all the <code>Elements</code> 
357      * in the specified document with a 
358      * given local name and namespace URI in document order.
359      * @param doc The document
360      * @param namespaceURI The namespace URI of the elements to match on. The 
361      *   special value <code>"*"</code> matches all namespaces.
362      * @param localName The local name of the elements to match on. The 
363      *   special value "*" matches all local names.
364      * @return A new <code>NodeList</code> object containing all the matched 
365      *   <code>Elements</code>.
366      * @since DOM Level 2
367      */
368 	public static final native NodeList<? extends Node> getElementsByTagNameNS(Document doc, String namespaceURI, String localName) throws JavaScriptException /*-{
369 	  return doc.getElementsByTagNameNS(namespaceURI, localName);
370 	}-*/;
371 
372 	/**
373 	 * Returns the current document
374 	 * @return the current document
375 	 */
376 	public static final native Document getCurrentDocument() /*-{
377 	  return $doc;
378 	}-*/;
379 	
380     /**
381      * Returns a <code>NamedNodeMap</code> containing the attributes of the
382      * specified element.
383      * @param elem The element
384      * @return a <code>NamedNodeMap</code> containing the attributes of the
385      * specified element
386      */
387 	public static final native NamedNodeMap<Attr> getAttributes(Element elem) /*-{
388 	  return elem.attributes;
389 	}-*/;
390 	
391     /**
392      * Retrieves an attribute node by name on the specified element.
393      * <br>To retrieve an attribute node by qualified name and namespace URI, 
394      * use the <code>getAttributeNodeNS</code> method.
395      * @param elt The element
396      * @param attrName The name (<code>nodeName</code>) of the attribute to 
397      *   retrieve.
398      * @return The <code>Attr</code> node with the specified name (
399      *   <code>nodeName</code>) or <code>null</code> if there is no such 
400      *   attribute.
401      */
402 	public static final native Attr getAttributeNode(Element elt, String attrName) /*-{
403 	  return elt.getAttributeNode(attrName);
404 	}-*/;
405 	
406     /**
407      * Adds a new attribute node to the specified element. If an attribute with that name (
408      * <code>nodeName</code>) is already present in the element, it is 
409      * replaced by the new one. Replacing an attribute node by itself has no 
410      * effect.
411      * <br>To add a new attribute node with a qualified name and namespace 
412      * URI, use the <code>setAttributeNodeNS</code> method.
413      * @param elt The element
414      * @param attr The <code>Attr</code> node to add to the attribute list.
415      * @return If the <code>attr</code> attribute replaces an existing 
416      *   attribute, the replaced <code>Attr</code> node is returned, 
417      *   otherwise <code>null</code> is returned.
418      * @exception DOMException
419      *   WRONG_DOCUMENT_ERR: Raised if <code>attr</code> was created from a 
420      *   different document than the one that created the element.
421      *   <br>NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
422      *   <br>INUSE_ATTRIBUTE_ERR: Raised if <code>attr</code> is already an 
423      *   attribute of another <code>Element</code> object. The DOM user must 
424      *   explicitly clone <code>Attr</code> nodes to re-use them in other 
425      *   elements.
426      */
427 	public static final native Attr setAttributeNode(Element elt, Attr attr) throws JavaScriptException /*-{
428 	  return elt.setAttributeNode(attr);
429 	}-*/;
430 
431     /**
432      * Returns <code>true</code> when an attribute with a given local name and 
433      * namespace URI is specified on the specified element or has a default value, 
434      * <code>false</code> otherwise.
435      * <br>Per [<a href='http://www.w3.org/TR/1999/REC-xml-names-19990114/'>XML Namespaces</a>]
436      * , applications must use the value <code>null</code> as the 
437      * <code>namespaceURI</code> parameter for methods if they wish to have 
438      * no namespace.
439      * @param elem The element
440      * @param namespaceURI The namespace URI of the attribute to look for.
441      * @param localName The local name of the attribute to look for.
442      * @return <code>true</code> if an attribute with the given local name 
443      *   and namespace URI is specified or has a default value on this 
444      *   element, <code>false</code> otherwise.
445      * @exception DOMException
446      *   NOT_SUPPORTED_ERR: May be raised if the implementation does not 
447      *   support the feature <code>"XML"</code> and the language exposed 
448      *   through the Document does not support XML Namespaces (such as [<a href='http://www.w3.org/TR/1999/REC-html401-19991224/'>HTML 4.01</a>]). 
449      */
450 	public static final native boolean hasAttributeNS(Element elem, String namespaceURI, String localName) throws JavaScriptException /*-{
451 	  return elem.hasAttributeNS(namespaceURI, localName);
452 	}-*/;
453 	
454     /**
455      * Adds a new attribute to the specified element. If an attribute with the same local name and 
456      * namespace URI is already present on the element, its prefix is 
457      * changed to be the prefix part of the <code>qualifiedName</code>, and 
458      * its value is changed to be the <code>value</code> parameter. This 
459      * value is a simple string; it is not parsed as it is being set. So any 
460      * markup (such as syntax to be recognized as an entity reference) is 
461      * treated as literal text, and needs to be appropriately escaped by the 
462      * implementation when it is written out. In order to assign an 
463      * attribute value that contains entity references, the user must create 
464      * an <code>Attr</code> node plus any <code>Text</code> and 
465      * <code>EntityReference</code> nodes, build the appropriate subtree, 
466      * and use <code>setAttributeNodeNS</code> or 
467      * <code>setAttributeNode</code> to assign it as the value of an 
468      * attribute.
469      * <br>Per [<a href='http://www.w3.org/TR/1999/REC-xml-names-19990114/'>XML Namespaces</a>]
470      * , applications must use the value <code>null</code> as the 
471      * <code>namespaceURI</code> parameter for methods if they wish to have 
472      * no namespace.
473      * @param elem The element
474      * @param namespaceURI The namespace URI of the attribute to create or 
475      *   alter.
476      * @param localName The local name of the attribute to create or 
477      *   alter.
478      * @param value The value to set in string form.
479      * @exception DOMException
480      *   INVALID_CHARACTER_ERR: Raised if the specified qualified name is not 
481      *   an XML name according to the XML version in use specified in the 
482      *   <code>Document.xmlVersion</code> attribute.
483      *   <br>NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
484      *   <br>NAMESPACE_ERR: Raised if the <code>qualifiedName</code> is 
485      *   malformed per the Namespaces in XML specification, if the 
486      *   <code>qualifiedName</code> has a prefix and the 
487      *   <code>namespaceURI</code> is <code>null</code>, if the 
488      *   <code>qualifiedName</code> has a prefix that is "xml" and the 
489      *   <code>namespaceURI</code> is different from "<a href='http://www.w3.org/XML/1998/namespace'>
490      *   http://www.w3.org/XML/1998/namespace</a>", if the <code>qualifiedName</code> or its prefix is "xmlns" and the 
491      *   <code>namespaceURI</code> is different from "<a href='http://www.w3.org/2000/xmlns/'>http://www.w3.org/2000/xmlns/</a>", or if the <code>namespaceURI</code> is "<a href='http://www.w3.org/2000/xmlns/'>http://www.w3.org/2000/xmlns/</a>" and neither the <code>qualifiedName</code> nor its prefix is "xmlns".
492      *   <br>NOT_SUPPORTED_ERR: May be raised if the implementation does not 
493      *   support the feature <code>"XML"</code> and the language exposed 
494      *   through the Document does not support XML Namespaces (such as [<a href='http://www.w3.org/TR/1999/REC-html401-19991224/'>HTML 4.01</a>]). 
495      */
496 	public static final native void setAttributeNS(Element elem, String namespaceURI, String localName, String value) throws JavaScriptException /*-{
497 	  elem.setAttributeNS(namespaceURI, localName, value);
498 	}-*/;
499 	
500     /**
501      * The namespace URI of the specified node, or <code>null</code> if it is 
502      * unspecified (see ).
503      * <br>This is not a computed value that is the result of a namespace 
504      * lookup based on an examination of the namespace declarations in 
505      * scope. It is merely the namespace URI given at creation time.
506      * <br>For nodes of any type other than <code>ELEMENT_NODE</code> and 
507      * <code>ATTRIBUTE_NODE</code> and nodes created with a DOM Level 1 
508      * method, such as <code>Document.createElement()</code>, this is always 
509      * <code>null</code>.
510      * <p ><b>Note:</b> Per the <em>Namespaces in XML</em> Specification [<a href='http://www.w3.org/TR/1999/REC-xml-names-19990114/'>XML Namespaces</a>]
511      *  an attribute does not inherit its namespace from the element it is 
512      * attached to. If an attribute is not explicitly given a namespace, it 
513      * simply has no namespace.
514      * @param node a DOM node
515      * @return The namespace URI of this node
516      */
517 	public static native String getNamespaceURI(Node node) /*-{
518 	  return node.namespaceURI;
519 	}-*/;
520 
521     /**
522      * Returns the local part of the qualified name of this node.
523      * <br>For nodes of any type other than <code>ELEMENT_NODE</code> and 
524      * <code>ATTRIBUTE_NODE</code> and nodes created with a DOM Level 1 
525      * method, such as <code>Document.createElement()</code>, this is always 
526      * <code>null</code>.
527      * @param node a DOM node
528      * @return The local part of the qualified name of this node
529      */
530 	public static native String getLocalName(Node node) /*-{
531 	  return node.localName;
532 	}-*/;
533 
534 	/**
535 	 * Makes a node sink the events emitted by the specified element
536 	 * @param elem The element emitting the events
537 	 * @param eventName The event name
538 	 */
539 	public static void bindEventListener(Element elem, String eventName) {
540 		impl.bindEventListener(elem, eventName);
541 	}
542 	
543 	/**
544 	 * Returns the element which currently captures all the
545 	 * events after a call to {@link org.vectomatic.dom.svg.utils.DOMHelper#setCaptureElement(OMSVGElement, LoseCaptureHandler)}
546 	 * or null if element is set to capture events
547 	 * @return The event capturing element
548 	 */
549 	public static OMSVGElement getCaptureElement() {
550 		return impl.getCaptureElement();
551 	}
552 	
553 	/**
554 	 * Makes the specified element capture all the events, until
555 	 * a call to {@link org.vectomatic.dom.svg.utils.DOMHelper#releaseCaptureElement()}
556 	 * terminates the capture
557 	 * @param element The capturing element
558 	 * @param loseCaptureHandler A handler which will be invoked
559 	 * if the element loses capture
560 	 * @return  {@link HandlerRegistration} used to remove this handler
561 	 */
562 	public static HandlerRegistration setCaptureElement(OMSVGElement element, LoseCaptureHandler loseCaptureHandler) {
563 		return impl.setCaptureElement(element, loseCaptureHandler);
564 	}
565 	
566 	/**
567 	 * Stops the forwarding of all events to the capturing element
568 	 * specified by {@link org.vectomatic.dom.svg.utils.DOMHelper#setCaptureElement(OMSVGElement, LoseCaptureHandler)}
569 	 */
570 	public static void releaseCaptureElement() {
571 		impl.releaseCaptureElement();
572 	}
573 	
574 	/**
575 	 * Returns the JavaScript type of an object. 
576 	 * The function getType is borrowed from: 
577 	 * JavaScript: The Definitive Guide, 5th Edition
578 	 * By David Flanagan
579 	 */
580 	public static final native String getType(JavaScriptObject x) /*-{
581 	    // If x is null, return "null"
582 	    if (x == null) {
583 	        return "null";
584 	    }
585 	    // Next try the typeof operator
586 	    var t = typeof x;
587 	    // If the result is not vague, return it
588 	    if (t != "object")  {
589 	        return t;
590 	    }
591 	    // Otherwise, x is an object. Use the default toString( ) method to
592 	    // get the class value of the object.
593 	    var c = Object.prototype.toString.apply(x);  // Returns "[object class]"
594 	    c = c.substring(8, c.length-1);              // Strip off "[object" and "]"
595 	
596 	    // If the class is not a vague one, return it.
597 	    if (c != "Object") {
598 	        return c;
599 	    }
600 	    // If we get here, c is "Object".  Check to see if
601 	    // the value x is really just a generic object.
602 	    if (x.constructor == Object) {
603 	        return c;  // Okay the type really is "Object"
604 	    }
605 	    // For user-defined classes, look for a string-valued property named
606 	    // classname, that is inherited from the object's prototype
607 	    if ("classname" in x.constructor.prototype &&  // inherits classname
608 	        typeof x.constructor.prototype.classname == "string") // its a string
609 	        return x.constructor.prototype.classname;
610 	
611 	    // If we really can't figure it out, say so.
612 	    return "<unknown type>";
613 	}-*/;
614 	
615 	/**
616 	 * Creates a value of the formed expected by SVG
617 	 * href attribtues.
618 	 * @param s the identifier of the data pointed by the href.
619 	 * @return a value of the formed expected by SVG
620 	 * href attribtues.
621 	 */
622 	public static final String toUrl(String s) {
623 		return "url(#" + s + ")";
624 	}
625 	
626 	/**
627 	 * Tests if the underlying DOM implementation supports the specified feature
628 	 * @param featureName
629 	 * The name of the feature to test
630 	 * @return
631 	 * true if the feature is supported, false otherwise 
632 	 */
633 	public static native boolean hasFeature(String featureName) /*-{
634 		return $doc.implementation.hasFeature(featureName, 1.1);
635 	}-*/;
636 
637 	/**
638 	 * Evaluates the specified XPath expression and returns
639 	 * a iterator for the selected {@link org.vectomatic.dom.svg.OMNode} node list.
640 	 * The expression must evaluate to a node list.
641 	 * @param root
642 	 * The element the expression is rooted at
643 	 * @param expr
644 	 * The XPath expression
645 	 * @param resolver
646 	 * A prefix resolver if the expression has prefix
647 	 * @return
648 	 * A node iterator for the selected nodes.
649 	 */
650 	public static <T extends OMNode> Iterator<T> evaluateXPath(OMElement root, String expr, XPathPrefixResolver resolver) {
651 		final JavaScriptObject result = impl.evaluateNodeListXPath_(root.getElement(), expr, resolver);
652 		return new Iterator<T>() {
653 			boolean fetched;
654 			Node next;
655 			
656 			@Override
657 			public boolean hasNext() {
658 				if (!fetched) {
659 					next = iterateNext(result);
660 					fetched = true;
661 				}
662 				return next != null;
663 			}
664 
665 			@Override
666 			public T next() {
667 				if (!hasNext()) {
668 					throw new NoSuchElementException();
669 				}
670 				fetched = false;
671 				return OMNode.<T>convert(next);
672 			}
673 
674 			@Override
675 			public void remove() {
676 				throw new UnsupportedOperationException();
677 			}
678 			
679 			private native Node iterateNext(JavaScriptObject result) /*-{
680 				return result.iterateNext();
681 			}-*/;			
682 		};
683 
684 	}
685 
686 	/**
687 	 * Evaluates the specified XPath expression and returns
688 	 * a iterator for the selected {@link com.google.gwt.dom.client.Node} node list.
689 	 * The expression must evaluate to a node list.
690 	 * @param root
691 	 * The element the expression is rooted at
692 	 * @param expr
693 	 * The XPath expression
694 	 * @param resolver
695 	 * A prefix resolver if the expression has prefix
696 	 * @return
697 	 * A node iterator for the selected nodes.
698 	 */
699 	public static <T extends Node> Iterator<T> evaluateNodeListXPath(Element root, String expr, XPathPrefixResolver resolver) {
700 		final JavaScriptObject result = impl.evaluateNodeListXPath_(root, expr, resolver);
701 		return new Iterator<T>() {
702 			boolean fetched;
703 			T next;
704 			
705 			@Override
706 			public boolean hasNext() {
707 				if (!fetched) {
708 					next = iterateNext(result);
709 					fetched = true;
710 				}
711 				return next != null;
712 			}
713 
714 			@Override
715 			public T next() {
716 				if (!hasNext()) {
717 					throw new NoSuchElementException();
718 				}
719 				fetched = false;
720 				return next;
721 			}
722 
723 			@Override
724 			public void remove() {
725 				throw new UnsupportedOperationException();
726 			}
727 			
728 			private native T iterateNext(JavaScriptObject result) /*-{
729 				return result.iterateNext();
730 			}-*/;			
731 		};
732 	}
733 
734 	/**
735 	 * Evaluates the specified XPath expression and returns
736 	 * the matching {@link com.google.gwt.dom.client.Node} node.
737 	 * The expression must evaluate to a single node.
738 	 * @param root
739 	 * The element the expression is rooted at
740 	 * @param expr
741 	 * The XPath expression
742 	 * @param resolver
743 	 * A prefix resolver if the expression has prefix
744 	 * @return
745 	 * The selected node, or null if no such node exists.
746 	 */
747 	public static <T extends Node> T evaluateNodeXPath(Element root, String expr, XPathPrefixResolver resolver) {
748 		return (T)(impl.evaluateNodeXPath_(root, expr, resolver));
749 	}
750 	
751 	/**
752 	 * Evaluates the specified XPath expression and returns
753 	 * the matching {@link java.lang.String}.
754 	 * The expression must evaluate to a string.
755 	 * @param root
756 	 * The element the expression is rooted at
757 	 * @param expr
758 	 * The XPath expression
759 	 * @param resolver
760 	 * A prefix resolver if the expression has prefix
761 	 * @return
762 	 * The matching string, or null if no such string exists.
763 	 */
764 	public static String evaluateStringXPath(Element root, String expr, XPathPrefixResolver resolver) {
765 		return impl.evaluateStringXPath_(root, expr, resolver);
766 	}
767 
768 	/**
769 	 * Evaluates the specified XPath expression and returns
770 	 * the matching float.
771 	 * The expression must evaluate to a number.
772 	 * @param root
773 	 * The element the expression is rooted at
774 	 * @param expr
775 	 * The XPath expression
776 	 * @param resolver
777 	 * A prefix resolver if the expression has prefix
778 	 * @return
779 	 * The matching float, or NaN if no such number exists.
780 	 */
781 	public static float evaluateNumberXPath(Element root, String expr, XPathPrefixResolver resolver) {
782 		return impl.evaluateNumberXPath_(root, expr, resolver);
783 	}
784 
785 	/**
786 	 * Evaluates the specified XPath expression and returns
787 	 * the matching boolean.
788 	 * The expression must evaluate to a boolean.
789 	 * @param root
790 	 * The element the expression is rooted at
791 	 * @param expr
792 	 * The XPath expression
793 	 * @param resolver
794 	 * A prefix resolver if the expression has prefix
795 	 * @return
796 	 * The matching boolean.
797 	 */
798 	public static boolean evaluateBooleanXPath(Element root, String expr, XPathPrefixResolver resolver) {
799 		return impl.evaluateBooleanXPath_(root, expr, resolver);
800 	}
801 
802 	/**
803 	 * Returns an XPath expression which enables reaching the specified node
804 	 * from the root node
805 	 * @param node
806 	 * The node to reach
807 	 * @param root
808 	 * The root node, or null to specify the document root
809 	 * @return
810 	 * An XPath expression which enables reaching the specified node
811 	 * from the root node
812 	 */
813 	public static String getXPath(Node node, Node root) {
814 		StringBuilder builder = new StringBuilder();
815 		Node parentNode;
816 		while ((node != root) && (parentNode = node.getParentNode()) != null) {
817 			NodeList<Node> siblings = parentNode.getChildNodes();
818 			int index = 0;
819 			for (int i = 0, length = siblings.getLength(); i < length; i++) {
820 				Node sibling = siblings.getItem(i);
821 				if (sibling.getNodeType() == Node.ELEMENT_NODE) {
822 					index++;
823 					if (node == sibling) {
824 						builder.insert(0, "/*[" + index + "]");
825 						break;
826 					}
827 				}
828 			}
829 			node = parentNode;
830 		}
831 		return builder.toString();
832 	}
833 	
834 	/***
835 	 * Returns whether touch events on SVG elements are supported
836 	 * on the current platform.
837 	 * @return true if touch events on SVG elements are supported
838 	 * on the current platform, false otherwise
839 	 */
840 	public static native boolean supportsSvgTouchEvents() /*-{
841 	   var elem = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
842 	   elem.setAttribute('ontouchstart', 'return;');
843 	   return (typeof elem.ontouchstart) == "function";
844 	}-*/;
845 }