001 
002 /*
003  *  JScripter Standard 1.0 - To Script In Java
004  *  Copyright (C) 2008-2011  J.J.Liu<jianjunliu@126.com> <http://www.jscripter.org>
005  *  
006  *  This program is free software: you can redistribute it and/or modify
007  *  it under the terms of the GNU Affero General Public License as published by
008  *  the Free Software Foundation, either version 3 of the License, or
009  *  (at your option) any later version.
010  *  
011  *  This program is distributed in the hope that it will be useful,
012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
014  *  GNU Affero General Public License for more details.
015  *  
016  *  You should have received a copy of the GNU Affero General Public License
017  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
018  */
019 
020 package jsx.dom;
021 
022 import js.*;
023 import js.core.*;
024 import js.user.*;
025 import jsx.client.Win;
026 
027 /**
028  * <p>A utility class manipulating DOM nodes with its static methods.</p>
029  * 
030  * @author <a href="mailto:jianjunliu@126.com">J.J.Liu (Jianjun Liu)</a> at <a href="http://www.jscripter.org" target="_blank">http://www.jscripter.org</a>
031  */
032 public final class Nodes extends Disposable
033 {
034     private Nodes() {}
035 
036     /**
037      * <p>Adds a node to the document tree by appending it to the {@link JsNode#childNodes} 
038      * array of this node.</p>
039      * <p>This method adds the node <tt>c</tt> to the document, inserting it as 
040      * the last child of this node. If <tt>c</tt> is already in the document tree, 
041      * it is removed from the tree and then reinserted at its new location. If <tt>c</tt> 
042      * is a {@link JsDocumentFragment} node, it is not inserted itself; instead, all its 
043      * children are appended, in order, to the end of this node's {@link JsNode#childNodes} 
044      * array. Note that a node from (or created by) one document cannot be inserted into 
045      * a different document. That is, the {@link JsNode#ownerDocument} property of <tt>c</tt> 
046      * must be the same as the {@link JsNode#ownerDocument} property of this node.</p>
047      * @param p The current node. 
048      * @param c The node to be inserted into the document. If the node is of 
049      * {@link JsDocumentFragment}, it is not directly inserted, but each of its children 
050      * are.
051      * @return The node that was added.
052      * @throws RuntimeException JavaScript throws a {@link JsDOMException} object with 
053      * the {@link JsDOMException#code} property of the value {@link JsDOMException#HIERARCHY_REQUEST_ERR} 
054      * if the node does not allow children, it does not allow children of the specified 
055      * type, or <tt>c</tt> is an ancestor of this node (or is this node itself), 
056      * the value {@link JsDOMException#WRONG_DOCUMENT_ERR} if the {@link JsNode#ownerDocument} 
057      * property of <tt>c</tt> is not the same as the {@link JsNode#ownerDocument} 
058      * property of this node, or the value {@link JsDOMException#NO_MODIFICATION_ALLOWED_ERR} 
059      * if the node is read-only and does not allow children to be appended, or the node 
060      * being appended is already part of the document tree, and its parent is read-only 
061      * and does not allow children to be removed. See {@link Js#err(Object)} for JS 
062      * Simulation.
063      * @see #removeChild(JsNode, JsNode)
064      * @see JsNode#appendChild(JsNode)
065      * @since 1.0
066      */
067     public final static JsNode appendChild(JsNode p, JsNode c) {
068         return p.appendChild(c);
069     }
070 
071     /**
072      * <p>Removes and returns the specified child node from the document tree.</p>
073      * <p>This method removes the specified child from the {@link JsNode#childNodes} array of 
074      * this node. It is an error to call this method with a node that is not a child. 
075      * This method returns the <tt>c</tt> node after removing it. <tt>c</tt> 
076      * continues to be a valid node and may be reinserted into the document later.</p>
077      * @param p The current node. 
078      * @param c The child node to remove. 
079      * @return The node that was removed.
080      * @throws RuntimeException JavaScript throws a {@link JsDOMException} object with 
081      * the {@link JsDOMException#code} property of the value {@link JsDOMException#NO_MODIFICATION_ALLOWED_ERR} 
082      * if the node is read-only and does not allow children to be removed, or the value 
083      * {@link JsDOMException#NOT_FOUND_ERR} if <tt>c</tt> is not a child of this 
084      * node. See {@link Js#err(Object)} for JS Simulation.
085      * @see #appendChild(JsNode, JsNode)
086      * @see JsNode#removeChild(JsNode)
087      * @since 1.0
088      */
089     public final static JsNode removeChild(JsNode p, JsNode c) {
090         return p.removeChild(c);
091     }
092 
093     /**
094      * <p>Inserts a node into the current document tree immediately before the specified 
095      * child node.</p>
096      * <p>This method inserts the node <tt>newChild</tt> into the document tree as a 
097      * child of this node. The new node is positioned within this node's {@link JsNode#childNodes} 
098      * array so that it comes immediately before the <tt>refChild</tt> node. If <tt>refChild</tt> 
099      * is <tt>null</tt>, <tt>newChild</tt> is inserted at the end of {@link JsNode#childNodes}, 
100      * just as with the {@link JsNode#appendChild(JsNode)} method. Note that it is illegal to 
101      * call this method with a <tt>refChild</tt> that is not a child of this node.</p>
102      * <p>If the node being inserted is already in the tree, it is removed and 
103      * reinserted at its new location.</p>
104      * <p>If <tt>newChild</tt> is a {@link JsDocumentFragment} node, it is not inserted 
105      * itself; instead, each of its children is inserted, in order, at the specified 
106      * location.</p>
107      * @param node The current node. 
108      * @param newChild The node to be inserted into the document. If the node is of 
109      * {@link JsDocumentFragment}, it is not directly inserted, but each of its children 
110      * are.
111      * @param refChild The child of this node before which <tt>newChild</tt> is to be 
112      * inserted. If this argument is <tt>null</tt>, <tt>newChild</tt> is inserted as 
113      * the last child of this node. 
114      * @return The node that was inserted.
115      * @throws RuntimeException JavaScript throws a {@link JsDOMException} object with 
116      * the {@link JsDOMException#code} property of the value {@link JsDOMException#HIERARCHY_REQUEST_ERR} 
117      * if the node does not allow children, it does not allow children of the specified 
118      * type, or <tt>newChild</tt> is an ancestor of this node (or is this node itself), 
119      * the value {@link JsDOMException#WRONG_DOCUMENT_ERR} if the {@link JsNode#ownerDocument} 
120      * property of <tt>newChild</tt> is not the same as the {@link JsNode#ownerDocument} 
121      * property of this node, the value {@link JsDOMException#NO_MODIFICATION_ALLOWED_ERR} 
122      * if the node is read-only and does not allow insertion, or the parent of <tt>newChild</tt> 
123      * is read-only and does not allow deletion, or the value {@link JsDOMException#NOT_FOUND_ERR} 
124      * if <tt>refChild</tt> is not a child of this node. See {@link Js#err(Object)} for JS 
125      * Simulation.
126      * @since 1.0
127      * @see JsNode#insertBefore(JsNode, JsNode)
128      */
129     public static final JsNode insertBefore(JsNode node, JsNode newChild, JsNode refChild) {
130         return node.insertBefore(newChild, refChild);
131     }
132 
133     /**
134      * <p>Inserts the given HTML text into the element at the location.</p>
135      * <p>This method is IE-specific.</p>
136      * @param node The current node.
137      * @param where A string that specifies where to insert the HTML text, using one of
138      * the following values: 
139      * <ul>
140      * <li>"beforeBegin": Inserts <tt>html</tt> immediately before the object.</li>
141      * <li>"afterBegin": Inserts <tt>html</tt> after the start of the object but before all other 
142      * content in the object.</li>
143      * <li>"beforeEnd": Inserts <tt>html</tt> immediately before the end of the object but after 
144      * all other content in the object.</li>
145      * <li>"afterEnd": Inserts <tt>html</tt> immediately after the end of the object.</li>
146      * </ul>
147      * @param html A string that specifies the HTML text to insert. The string can be a 
148      * combination of text and HTML tags. This must be well-formed, valid HTML or this 
149      * method will fail.
150      * @see JsNode#insertAdjacentHTML(String, String)
151      * @since 1.0
152      */
153     public final static void insertAdjacentHTML(JsNode node, String where, String html) {
154         node.insertAdjacentHTML(where, html);
155     }
156 
157     /**
158      * <p>Removes and returns the specified child node from the document tree, replacing 
159      * it with another node.</p>
160      * <p>This method replaces one node of the document tree with another. <tt>oldChild</tt> 
161      * is the node to be replaced and must be a child of this node. <tt>newChild</tt> is 
162      * the node that takes its place in the {@link JsNode#childNodes} array of this node.</p>
163      * <p>If <tt>newChild</tt> is already part of the document, it is first removed from 
164      * the document before being reinserted at its new position.</p>
165      * <p>If <tt>newChild</tt> is a {@link JsDocumentFragment} node, it is not inserted 
166      * itself; instead, each of its children is inserted, in order, at the position 
167      * formerly occupied by <tt>oldChild</tt>.</p>
168      * @param node The current node.
169      * @param newChild The replacement node. 
170      * @param oldChild The node to be replaced. 
171      * @return The node that was removed from the document and replaced.
172      * @throws RuntimeException JavaScript throws a {@link JsDOMException} object with 
173      * the {@link JsDOMException#code} property of the value {@link JsDOMException#HIERARCHY_REQUEST_ERR} 
174      * if the node does not allow children, it does not allow children of the specified 
175      * type, or <tt>newChild</tt> is an ancestor of this node (or is this node itself), 
176      * the value {@link JsDOMException#WRONG_DOCUMENT_ERR} if <tt>newChild</tt> and this 
177      * node have different values for {@link JsNode#ownerDocument} property, the value {@link JsDOMException#NO_MODIFICATION_ALLOWED_ERR} 
178      * if the node is read-only and does not allow replacement, or <tt>newChild</tt> is 
179      * the child of a node that does not allow removals, or the value {@link JsDOMException#NOT_FOUND_ERR} 
180      * if <tt>oldChild</tt> is not a child of this node. See {@link Js#err(Object)} for JS 
181      * Simulation.
182      * @see JsNode#replaceChild(JsNode, JsNode)
183      * @since 1.0
184      */
185     public static final JsNode replaceChild(JsNode node, JsNode oldChild, JsNode newChild) {
186         return node.replaceChild(oldChild, newChild);
187     }
188 
189     /**
190      * <p>Gets parent node of a given node.</p>
191      * @param c The child node. 
192      * @return The parent node or <tt>null</tt> for none.
193      * @since 1.0
194      */
195     public final static JsNode parentNode(JsNode c) {
196         return JsNode.parentNode.with(c);
197     }
198 
199     /**
200      * <p>Detaches a node from its parent if it has one.</p>
201      * @param n The node to detach. 
202      * @return The node that was detached.
203      * @since 1.0
204      */
205     public final static JsNode detach(JsNode n) {
206         JsNode p = parentNode(n);
207         return Js.be(p) ? p.removeChild(n) : n;
208     }
209 
210     /**
211      * <p>Returns a descendant {@link JsElement} element of the current document that has the 
212      * specified value for its <tt>id</tt> attribute, or <tt>null</tt> if no such 
213      * element exists in the document.</p>
214      * <p>This method searches the document for an {@link JsElement} node with an <tt>id</tt> 
215      * attribute whose value is <tt>elementId</tt> and returns that element. If no such 
216      * element is found, it returns <tt>null</tt>. The value of the <tt>id</tt> attribute 
217      * is intended to be unique within a document, and if this method finds more than 
218      * one element with the specified <tt>elementId</tt>, it may return one at random, 
219      * or it may return <tt>null</tt>.</p>
220      * <p>This is an important and commonly used method because it provides a simple 
221      * way to obtain the {@link JsElement} object that represents a specific document 
222      * element.</p>
223      * <p>For HTML documents, this method searches for an element based on the value of 
224      * its <tt>id</tt> attribute. Use {@link JsHTMLDocument#getElementsByName(String)} 
225      * to search for HTML elements based on the value of their <tt>name</tt> attributes.</p>
226      * <p>For XML documents, this method performs its search using any attribute whose 
227      * type is <tt>id</tt>, regardless of what the name of that attribute is. If, for example, 
228      * because the XML parser ignored or could not locate the document's DTD, XML attribute 
229      * types are not known, this method always returns <tt>null</tt>. In JavaScript, 
230      * this method is not usually useful with XML documents. In fact, it was originally 
231      * defined as a member of the <tt>HTMLDocument</tt> interface but was then moved to 
232      * the <tt>Document</tt> interface in DOM Level 2.</p>
233      * @param elementId The value of the <tt>id</tt> attribute of the desired element.
234      * @return The {@link JsElement} node that represents the document element with the 
235      * specified <tt>id</tt> attribute or <tt>null</tt> if no such element is found.
236      * @since 1.0
237      * @see JsDocument#getElementsByTagName(String)
238      */
239     public static final JsHTMLElement getElementById(String elementId) {
240         return new JsHTMLElement(Win.document.var().getElementById(elementId));
241     }
242 
243     /**
244      * <p>Returns an array, technically a {@link JsNodeList} object, of all {@link JsElement} 
245      * nodes in the current document that have the specified tag name by traversing all 
246      * descendants of this element. The {@link JsElement} nodes appear in the returned 
247      * array in the same order in which they appear in the document source.</p>
248      * <p>Note that the {@link JsDocument#getElementsByTagName(String)} method works 
249      * just like this one but that traverses the entire document, rather than just the 
250      * descendants of a single element. Do not confuse this method with {@link JsHTMLDocument#getElementsByName(String)}, 
251      * which searches for elements based on the value of their <tt>name</tt> attributes 
252      * rather than by their tag names.</p>
253      * @param node The current node.
254      * @param name The tag name of the desired elements, or the value "*" to specify 
255      * that all descendant elements should be returned, regardless of their tag names.
256      * @return An read-only array, technically a {@link JsNodeList} object, of 
257      * {@link JsElement} nodes that are descendants of this element and have the 
258      * specified tag name.
259      * @since 1.0
260      * @see JsDocument#getElementsByTagName(String)
261      */
262     public static final JsNodeList<? extends JsElement> getElementsByTagName(JsNode node, String name) {
263         return new JsElement(node).getElementsByTagName(name);
264     }
265 
266     /**
267      * <p>Gets {@link JsHTMLElement#tagName} of a given node.</p>
268      * @param e The given node. 
269      * @return The property value.
270      * @since 1.0
271      */
272     public final static String tagName(JsNode e) {
273         return JsHTMLElement.tagName.with(e);
274     }
275 
276     /**
277      * <p>Gets {@link JsNode#nodeValue} of a given node.</p>
278      * @param n The given node. 
279      * @return The property value.
280      * @since 1.0
281      */
282     public static final String nodeValue(JsNode n) {
283         return JsNode.nodeValue.with(n);
284     }
285 
286     /**
287      * <p>Gets {@link JsNode#firstChild} of a given node.</p>
288      * @param node The given node. 
289      * @return The property value.
290      * @since 1.0
291      */
292     public static final JsNode firstChild(JsNode node) {
293         return JsNode.firstChild.with(node);
294     }
295 
296     /**
297      * <p>Gets {@link JsNode#lastChild} of a given node.</p>
298      * @param node The given node. 
299      * @return The property value.
300      * @since 1.0
301      */
302     public static final JsNode lastChild(JsNode node) {
303         return JsNode.lastChild.with(node);
304     }
305 
306     /**
307      * <p>Gets {@link JsNode#previousSibling} of a given node.</p>
308      * @param node The given node. 
309      * @return The property value.
310      * @since 1.0
311      */
312     public static final JsNode previousSibling(JsNode node) {
313         return JsNode.previousSibling.with(node);
314     }
315 
316     /**
317      * <p>Gets {@link JsNode#nextSibling} of a given node.</p>
318      * @param node The given node. 
319      * @return The property value.
320      * @since 1.0
321      */
322     public static final JsNode nextSibling(JsNode node) {
323         return JsNode.nextSibling.with(node);
324     }
325 
326     /**
327      * <p>Gets {@link JsNode#nodeType} of a given node.</p>
328      * @param node The given node. 
329      * @return The property value.
330      * @since 1.0
331      */
332     public static final Number nodeType(JsNode node) {
333         return JsNode.nodeType.with(node);
334     }
335 
336     private static final JsNode nextType(JsNode node, int type) {
337         while (Js.be(node) && Js.neq(nodeType(node), type)) {
338             node = nextSibling(node);
339         }
340         return node;
341     }
342 
343     private static final JsNode previousType(JsNode node, int type) {
344         while (Js.be(node) && Js.neq(nodeType(node), type)) {
345             node = previousSibling(node);
346         }
347         return node;
348     }
349 
350     /**
351      * <p>Gets the first child with a given type of a given node.</p>
352      * @param node The given node. 
353      * @param type The given node type. The legal node types are:
354      * <ul>
355      * <li>{@link js.dom.DOM2Core.Node#ELEMENT_NODE} or {@link JsNode#ELEMENT_NODE} for {@link JsElement} nodes</li>
356      * <li>{@link js.dom.DOM2Core.Node#ATTRIBUTE_NODE} or {@link JsNode#ATTRIBUTE_NODE} for {@link JsAttr} nodes</li>
357      * <li>{@link js.dom.DOM2Core.Node#TEXT_NODE} or {@link JsNode#TEXT_NODE} for {@link JsText} nodes</li>
358      * <li>{@link js.dom.DOM2Core.Node#CDATA_SECTION_NODE} or {@link JsNode#CDATA_SECTION_NODE} for {@link JsCDATASection} nodes</li>
359      * <li>{@link js.dom.DOM2Core.Node#PROCESSING_INSTRUCTION_NODE} or {@link JsNode#PROCESSING_INSTRUCTION_NODE} for {@link JsProcessingInstruction} nodes</li>
360      * <li>{@link js.dom.DOM2Core.Node#COMMENT_NODE} or {@link JsNode#COMMENT_NODE} for {@link JsComment} nodes</li>
361      * <li>{@link js.dom.DOM2Core.Node#DOCUMENT_NODE} or {@link JsNode#DOCUMENT_NODE} for {@link JsDocument} nodes</li>
362      * <li>{@link js.dom.DOM2Core.Node#DOCUMENT_TYPE_NODE} or {@link JsNode#DOCUMENT_TYPE_NODE} for {@link JsDocumentType} nodes</li>
363      * <li>{@link js.dom.DOM2Core.Node#DOCUMENT_FRAGMENT_NODE} or {@link JsNode#DOCUMENT_FRAGMENT_NODE} for {@link JsDocumentFragment} nodes</li>
364      * </ul>
365      * @return The result node.
366      * @since 1.0
367      */
368     public static final JsNode firstChild(JsNode node, int type) {
369         return nextType(firstChild(node), type);
370     }
371 
372     /**
373      * <p>Gets the last child with a given type of a given node.</p>
374      * @param node The given node. 
375      * @param type The given node type. The legal node types are:
376      * <ul>
377      * <li>{@link js.dom.DOM2Core.Node#ELEMENT_NODE} or {@link JsNode#ELEMENT_NODE} for {@link JsElement} nodes</li>
378      * <li>{@link js.dom.DOM2Core.Node#ATTRIBUTE_NODE} or {@link JsNode#ATTRIBUTE_NODE} for {@link JsAttr} nodes</li>
379      * <li>{@link js.dom.DOM2Core.Node#TEXT_NODE} or {@link JsNode#TEXT_NODE} for {@link JsText} nodes</li>
380      * <li>{@link js.dom.DOM2Core.Node#CDATA_SECTION_NODE} or {@link JsNode#CDATA_SECTION_NODE} for {@link JsCDATASection} nodes</li>
381      * <li>{@link js.dom.DOM2Core.Node#PROCESSING_INSTRUCTION_NODE} or {@link JsNode#PROCESSING_INSTRUCTION_NODE} for {@link JsProcessingInstruction} nodes</li>
382      * <li>{@link js.dom.DOM2Core.Node#COMMENT_NODE} or {@link JsNode#COMMENT_NODE} for {@link JsComment} nodes</li>
383      * <li>{@link js.dom.DOM2Core.Node#DOCUMENT_NODE} or {@link JsNode#DOCUMENT_NODE} for {@link JsDocument} nodes</li>
384      * <li>{@link js.dom.DOM2Core.Node#DOCUMENT_TYPE_NODE} or {@link JsNode#DOCUMENT_TYPE_NODE} for {@link JsDocumentType} nodes</li>
385      * <li>{@link js.dom.DOM2Core.Node#DOCUMENT_FRAGMENT_NODE} or {@link JsNode#DOCUMENT_FRAGMENT_NODE} for {@link JsDocumentFragment} nodes</li>
386      * </ul>
387      * @return The result node.
388      * @since 1.0
389      */
390     public static final JsNode lastChild(JsNode node, int type) {
391         return previousType(lastChild(node), type);
392     }
393 
394     /**
395      * <p>Gets the next sibling with a given type of a given node.</p>
396      * @param node The given node. 
397      * @param type The given node type. The legal node types are:
398      * <ul>
399      * <li>{@link js.dom.DOM2Core.Node#ELEMENT_NODE} or {@link JsNode#ELEMENT_NODE} for {@link JsElement} nodes</li>
400      * <li>{@link js.dom.DOM2Core.Node#ATTRIBUTE_NODE} or {@link JsNode#ATTRIBUTE_NODE} for {@link JsAttr} nodes</li>
401      * <li>{@link js.dom.DOM2Core.Node#TEXT_NODE} or {@link JsNode#TEXT_NODE} for {@link JsText} nodes</li>
402      * <li>{@link js.dom.DOM2Core.Node#CDATA_SECTION_NODE} or {@link JsNode#CDATA_SECTION_NODE} for {@link JsCDATASection} nodes</li>
403      * <li>{@link js.dom.DOM2Core.Node#PROCESSING_INSTRUCTION_NODE} or {@link JsNode#PROCESSING_INSTRUCTION_NODE} for {@link JsProcessingInstruction} nodes</li>
404      * <li>{@link js.dom.DOM2Core.Node#COMMENT_NODE} or {@link JsNode#COMMENT_NODE} for {@link JsComment} nodes</li>
405      * <li>{@link js.dom.DOM2Core.Node#DOCUMENT_NODE} or {@link JsNode#DOCUMENT_NODE} for {@link JsDocument} nodes</li>
406      * <li>{@link js.dom.DOM2Core.Node#DOCUMENT_TYPE_NODE} or {@link JsNode#DOCUMENT_TYPE_NODE} for {@link JsDocumentType} nodes</li>
407      * <li>{@link js.dom.DOM2Core.Node#DOCUMENT_FRAGMENT_NODE} or {@link JsNode#DOCUMENT_FRAGMENT_NODE} for {@link JsDocumentFragment} nodes</li>
408      * </ul>
409      * @return The result node.
410      * @since 1.0
411      */
412     public static final JsNode nextSibling(JsNode node, int type) {
413         return nextType(nextSibling(node), type);
414     }
415 
416     /**
417      * <p>Gets the previous sibling with a given type of a given node.</p>
418      * @param node The given node. 
419      * @param type The given node type. The legal node types are:
420      * <ul>
421      * <li>{@link js.dom.DOM2Core.Node#ELEMENT_NODE} or {@link JsNode#ELEMENT_NODE} for {@link JsElement} nodes</li>
422      * <li>{@link js.dom.DOM2Core.Node#ATTRIBUTE_NODE} or {@link JsNode#ATTRIBUTE_NODE} for {@link JsAttr} nodes</li>
423      * <li>{@link js.dom.DOM2Core.Node#TEXT_NODE} or {@link JsNode#TEXT_NODE} for {@link JsText} nodes</li>
424      * <li>{@link js.dom.DOM2Core.Node#CDATA_SECTION_NODE} or {@link JsNode#CDATA_SECTION_NODE} for {@link JsCDATASection} nodes</li>
425      * <li>{@link js.dom.DOM2Core.Node#PROCESSING_INSTRUCTION_NODE} or {@link JsNode#PROCESSING_INSTRUCTION_NODE} for {@link JsProcessingInstruction} nodes</li>
426      * <li>{@link js.dom.DOM2Core.Node#COMMENT_NODE} or {@link JsNode#COMMENT_NODE} for {@link JsComment} nodes</li>
427      * <li>{@link js.dom.DOM2Core.Node#DOCUMENT_NODE} or {@link JsNode#DOCUMENT_NODE} for {@link JsDocument} nodes</li>
428      * <li>{@link js.dom.DOM2Core.Node#DOCUMENT_TYPE_NODE} or {@link JsNode#DOCUMENT_TYPE_NODE} for {@link JsDocumentType} nodes</li>
429      * <li>{@link js.dom.DOM2Core.Node#DOCUMENT_FRAGMENT_NODE} or {@link JsNode#DOCUMENT_FRAGMENT_NODE} for {@link JsDocumentFragment} nodes</li>
430      * </ul>
431      * @return The result node.
432      * @since 1.0
433      */
434     public static final JsNode previousSibling(JsNode node, int type) {
435         return previousType(previousSibling(node), type);
436     }
437 
438     /**
439      * <p>Gets {@link JsHTMLElement#innerHTML} of a given node.</p>
440      * @param node The given node. 
441      * @return The property value.
442      * @since 1.0
443      */
444     public final static String innerHTML(JsNode node) {
445         return JsHTMLElement.innerHTML.with(node);
446     }
447 
448     /**
449      * <p>Sets {@link JsHTMLElement#innerHTML} of a given element.</p>
450      * @param node The given node. 
451      * @param html The new HTML for the element. 
452      * @return The property value.
453      * @since 1.0
454      */
455     public final static String innerHTML(JsNode node, String html) {
456         return JsHTMLElement.innerHTML.with(node, html);
457     }
458 
459     /**
460      * <p>A function that returns a copy of this object.</p>
461      * @since 1.0
462      */
463     public final static Var<JsFunction<JsObject>> copy = new Static<JsFunction<JsObject>>(
464             new Var<JsFunction<JsObject>>() {
465                 @Override
466                 public JsFunction<JsObject> var() {
467                     return Js.function(
468                             "var c={};for(var p in this){c[p]=this[p];}return c;"
469                     );
470                 }
471             }
472     );
473 
474     /**
475      * <p>A function that checks whether a node is contained within another node.</p>
476      * @since 1.0
477      */
478     public final static Var<JsFunction<Boolean>> contains = new Static<JsFunction<Boolean>>(
479             new Var<JsFunction<Boolean>>() {
480                 @Override
481                 public JsFunction<Boolean> var() {
482                     return Js.function(
483                             "c",
484                             "while(c){c=c.parentNode;if(this==c)return true;}return false;"
485                     );
486                 }
487             }
488     );
489 
490     /**
491      * <p>Checks whether a node is contained within another node.</p>
492      * @param p The containing node. 
493      * @param c The contained node. 
494      * @return <tt>true</tt> if the node contains the other; <tt>false</tt>, otherwise.
495      * @since 1.0
496      */
497     public final static boolean contains(JsNode p, JsNode c) {
498         try {
499             return contains.var().call(p, c);
500         } catch (NullPointerException npe) {
501             npe.printStackTrace();
502             throw npe;
503         }
504     }
505 
506     /**
507      * <p>Checks whether a node is contained within another node.</p>
508      * @param p The containing node. 
509      * @param c The contained node. 
510      * @return <tt>true</tt> if the node contains the other; <tt>false</tt>, otherwise.
511      * @since 1.0
512      */
513     public final static boolean contains2(JsNode p, JsNode c) {
514         while(Js.be(c)) {
515             c = parentNode(c);
516             if (Js.eq(c, p)) return true;
517         }
518         return false;
519     }
520 }