View Javadoc
1   /*
2    * Copyright (c) 2002-2025 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 static org.htmlunit.javascript.configuration.SupportedBrowser.CHROME;
18  import static org.htmlunit.javascript.configuration.SupportedBrowser.EDGE;
19  import static org.htmlunit.javascript.configuration.SupportedBrowser.FF;
20  
21  import org.htmlunit.corejs.javascript.Context;
22  import org.htmlunit.corejs.javascript.Function;
23  import org.htmlunit.corejs.javascript.Scriptable;
24  import org.htmlunit.cssparser.parser.CSSException;
25  import org.htmlunit.html.DomDocumentFragment;
26  import org.htmlunit.html.DomNode;
27  import org.htmlunit.html.HtmlPage;
28  import org.htmlunit.javascript.HtmlUnitScriptable;
29  import org.htmlunit.javascript.JavaScriptEngine;
30  import org.htmlunit.javascript.configuration.JsxClass;
31  import org.htmlunit.javascript.configuration.JsxConstructor;
32  import org.htmlunit.javascript.configuration.JsxFunction;
33  import org.htmlunit.javascript.configuration.JsxGetter;
34  import org.htmlunit.javascript.host.Element;
35  import org.htmlunit.javascript.host.html.HTMLCollection;
36  
37  /**
38   * A JavaScript object for {@code DocumentFragment}.
39   *
40   * @author Ahmed Ashour
41   * @author Frank Danek
42   * @author Ronald Brill
43   *
44   * @see <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-core.html#ID-B63ED1A3">
45   *     W3C Dom Level 1</a>
46   */
47  @JsxClass(domClass = DomDocumentFragment.class)
48  public class DocumentFragment extends Node {
49  
50      /**
51       * JavaScript constructor.
52       */
53      @Override
54      @JsxConstructor
55      public void jsConstructor() {
56          super.jsConstructor();
57  
58          final HtmlPage page = (HtmlPage) getWindow().getWebWindow().getEnclosedPage();
59          final DomDocumentFragment fragment = new DomDocumentFragment(page);
60          setDomNode(fragment);
61      }
62  
63      /**
64       * Inserts a set of Node objects or string objects after the last child
65       * of the document fragment. String objects are inserted as equivalent Text nodes.
66       * @param context the context
67       * @param scope the scope
68       * @param thisObj this object
69       * @param args the arguments
70       * @param function the function
71       */
72      @JsxFunction
73      public static void append(final Context context, final Scriptable scope,
74              final Scriptable thisObj, final Object[] args, final Function function) {
75          Node.append(context, thisObj, args, function);
76      }
77  
78      /**
79       * Inserts a set of Node objects or string objects before the first child
80       * of the document fragment. String objects are inserted as equivalent Text nodes.
81       * @param context the context
82       * @param scope the scope
83       * @param thisObj this object
84       * @param args the arguments
85       * @param function the function
86       */
87      @JsxFunction
88      public static void prepend(final Context context, final Scriptable scope,
89              final Scriptable thisObj, final Object[] args, final Function function) {
90          Node.prepend(context, thisObj, args, function);
91      }
92  
93      /**
94       * Replaces the existing children of a DocumentFragment with a specified
95       * new set of children. These can be string or Node objects.
96       * @param context the context
97       * @param scope the scope
98       * @param thisObj this object
99       * @param args the arguments
100      * @param function the function
101      */
102     @JsxFunction
103     public static void replaceChildren(final Context context, final Scriptable scope,
104             final Scriptable thisObj, final Object[] args, final Function function) {
105         Node.replaceChildren(context, thisObj, args, function);
106     }
107 
108     /**
109      * Moves a given Node inside the invoking node as a direct child, before a given reference node.
110      *
111      * @param context the JavaScript context
112      * @param scope the scope
113      * @param thisObj the scriptable
114      * @param args the arguments passed into the method
115      * @param function the function
116      */
117     @JsxFunction({CHROME, EDGE, FF})
118     public static void moveBefore(final Context context, final Scriptable scope,
119             final Scriptable thisObj, final Object[] args, final Function function) {
120         Node.moveBefore(context, scope, thisObj, args, function);
121     }
122 
123     /**
124      * Retrieves all element nodes from descendants of the starting element node that match any selector
125      * within the supplied selector strings.
126      * The NodeList object returned by the querySelectorAll() method must be static, not live.
127      * @param selectors the selectors
128      * @return the static node list
129      */
130     @JsxFunction
131     public NodeList querySelectorAll(final String selectors) {
132         try {
133             return NodeList.staticNodeList(this, getDomNodeOrDie().querySelectorAll(selectors));
134         }
135         catch (final CSSException e) {
136             throw JavaScriptEngine.reportRuntimeError("An invalid or illegal selector was specified (selector: '"
137                     + selectors + "' error: " + e.getMessage() + ").");
138         }
139     }
140 
141     /**
142      * Returns the first element within the document that matches the specified group of selectors.
143      * @param selectors the selectors
144      * @return null if no matches are found; otherwise, it returns the first matching element
145      */
146     @JsxFunction
147     public Node querySelector(final String selectors) {
148         try {
149             final DomNode node = getDomNodeOrDie().querySelector(selectors);
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 }