View Javadoc
1   /*
2    * Copyright (c) 2002-2026 Gargoyle Software Inc.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * https://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software
10   * distributed under the License is distributed on an "AS IS" BASIS,
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   * See the License for the specific language governing permissions and
13   * limitations under the License.
14   */
15  package org.htmlunit.javascript.host.dom;
16  
17  import org.htmlunit.corejs.javascript.Context;
18  import org.htmlunit.corejs.javascript.Function;
19  import org.htmlunit.corejs.javascript.Scriptable;
20  import org.htmlunit.corejs.javascript.VarScope;
21  import org.htmlunit.cssparser.parser.CSSException;
22  import org.htmlunit.html.DomDocumentFragment;
23  import org.htmlunit.html.DomNode;
24  import org.htmlunit.html.HtmlPage;
25  import org.htmlunit.javascript.HtmlUnitScriptable;
26  import org.htmlunit.javascript.JavaScriptEngine;
27  import org.htmlunit.javascript.configuration.JsxClass;
28  import org.htmlunit.javascript.configuration.JsxConstructor;
29  import org.htmlunit.javascript.configuration.JsxFunction;
30  import org.htmlunit.javascript.configuration.JsxGetter;
31  import org.htmlunit.javascript.host.Element;
32  import org.htmlunit.javascript.host.html.HTMLCollection;
33  
34  /**
35   * A JavaScript object for {@code DocumentFragment}.
36   *
37   * @author Ahmed Ashour
38   * @author Frank Danek
39   * @author Ronald Brill
40   *
41   * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/DocumentFragment">MDN Documentation</a>
42   * @see <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-core.html#ID-B63ED1A3">
43   *     W3C Dom Level 1</a>
44   */
45  @JsxClass(domClass = DomDocumentFragment.class)
46  public class DocumentFragment extends Node {
47  
48      /**
49       * JavaScript constructor.
50       */
51      @Override
52      @JsxConstructor
53      public void jsConstructor() {
54          super.jsConstructor();
55  
56          final HtmlPage page = (HtmlPage) getWindow().getWebWindow().getEnclosedPage();
57          final DomDocumentFragment fragment = new DomDocumentFragment(page);
58          setDomNode(fragment);
59      }
60  
61      /**
62       * Inserts a set of Node objects or string objects after the last child
63       * of the document fragment. String objects are inserted as equivalent Text nodes.
64       * @param context the context
65       * @param scope the scope
66       * @param thisObj this object
67       * @param args the arguments
68       * @param function the function
69       */
70      @JsxFunction
71      public static void append(final Context context, final VarScope scope,
72              final Scriptable thisObj, final Object[] args, final Function function) {
73          Node.append(context, thisObj, args, function);
74      }
75  
76      /**
77       * Inserts a set of Node objects or string objects before the first child
78       * of the document fragment. String objects are inserted as equivalent Text nodes.
79       * @param context the context
80       * @param scope the scope
81       * @param thisObj this object
82       * @param args the arguments
83       * @param function the function
84       */
85      @JsxFunction
86      public static void prepend(final Context context, final VarScope scope,
87              final Scriptable thisObj, final Object[] args, final Function function) {
88          Node.prepend(context, thisObj, args, function);
89      }
90  
91      /**
92       * Replaces the existing children of a DocumentFragment with a specified
93       * new set of children. These can be string or Node objects.
94       * @param context the context
95       * @param scope the scope
96       * @param thisObj this object
97       * @param args the arguments
98       * @param function the function
99       */
100     @JsxFunction
101     public static void replaceChildren(final Context context, final VarScope scope,
102             final Scriptable thisObj, final Object[] args, final Function function) {
103         Node.replaceChildren(context, thisObj, args, function);
104     }
105 
106     /**
107      * Moves a given Node inside the invoking node as a direct child, before a given reference node.
108      *
109      * @param context the JavaScript context
110      * @param scope the scope
111      * @param thisObj the scriptable
112      * @param args the arguments passed into the method
113      * @param function the function
114      */
115     @JsxFunction
116     public static void moveBefore(final Context context, final VarScope scope,
117             final Scriptable thisObj, final Object[] args, final Function function) {
118         Node.moveBefore(context, scope, thisObj, args, function);
119     }
120 
121     /**
122      * Retrieves all element nodes from descendants of the starting element node that match any selector
123      * within the supplied selector strings.
124      * The NodeList object returned by the querySelectorAll() method must be static, not live.
125      * @param selectors the selectors
126      * @return the static node list
127      */
128     @JsxFunction
129     public NodeList querySelectorAll(final String selectors) {
130         try {
131             final DomNode domNode = getDomNodeOrDie();
132             return NodeList.staticNodeList(getParentScope(), domNode.querySelectorAll(selectors, domNode));
133         }
134         catch (final CSSException e) {
135             throw JavaScriptEngine.reportRuntimeError("An invalid or illegal selector was specified (selector: '"
136                     + selectors + "' error: " + e.getMessage() + ").");
137         }
138     }
139 
140     /**
141      * Returns the first element within the document that matches the specified group of selectors.
142      * @param selectors the selectors
143      * @return null if no matches are found; otherwise, it returns the first matching element
144      */
145     @JsxFunction
146     public Node querySelector(final String selectors) {
147         try {
148             final DomNode domNode = getDomNodeOrDie();
149             final DomNode node = domNode.querySelector(selectors, domNode);
150             if (node != null) {
151                 return node.getScriptableObject();
152             }
153             return null;
154         }
155         catch (final CSSException e) {
156             throw JavaScriptEngine.reportRuntimeError("An invalid or illegal selector was specified (selector: '"
157                     + selectors + "' error: " + e.getMessage() + ").");
158         }
159     }
160 
161     /**
162      * {@inheritDoc}
163      */
164     @Override
165     public Object getDefaultValue(final Class<?> hint) {
166         if (String.class.equals(hint) || hint == null) {
167             return "[object " + getClassName() + "]";
168         }
169         return super.getDefaultValue(hint);
170     }
171 
172     /**
173      * {@inheritDoc}
174      */
175     @Override
176     @JsxGetter
177     public int getChildElementCount() {
178         return super.getChildElementCount();
179     }
180 
181     /**
182      * {@inheritDoc}
183      */
184     @Override
185     @JsxGetter
186     public Element getFirstElementChild() {
187         return super.getFirstElementChild();
188     }
189 
190     /**
191      * {@inheritDoc}
192      */
193     @Override
194     @JsxGetter
195     public Element getLastElementChild() {
196         return super.getLastElementChild();
197     }
198 
199     /**
200      * {@inheritDoc}
201      */
202     @Override
203     @JsxGetter
204     public HTMLCollection getChildren() {
205         return super.getChildren();
206     }
207 
208     /**
209      * Returns the element with the specified ID, or {@code null} if that element could not be found.
210      * @param id the ID to search for
211      * @return the element, or {@code null} if it could not be found
212      */
213     @JsxFunction
214     public HtmlUnitScriptable getElementById(final Object id) {
215         if (id == null || JavaScriptEngine.isUndefined(id)) {
216             return null;
217         }
218         final String idString = JavaScriptEngine.toString(id);
219         if (idString == null || idString.length() == 0) {
220             return null;
221         }
222         for (final DomNode child : getDomNodeOrDie().getChildren()) {
223             final Element elem = child.getScriptableObject();
224             if (idString.equals(elem.getId())) {
225                 return elem;
226             }
227         }
228         return null;
229     }
230 
231     /**
232      * {@inheritDoc}
233      */
234     @Override
235     public Node getRootNode() {
236         return this;
237     }
238 }