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 static org.htmlunit.BrowserVersionFeatures.JS_DOCUMENT_EVALUATE_RECREATES_RESULT;
18  import static org.htmlunit.BrowserVersionFeatures.JS_DOCUMENT_SELECTION_RANGE_COUNT;
19  import static org.htmlunit.javascript.configuration.SupportedBrowser.CHROME;
20  import static org.htmlunit.javascript.configuration.SupportedBrowser.EDGE;
21  import static org.htmlunit.javascript.configuration.SupportedBrowser.FF;
22  import static org.htmlunit.javascript.configuration.SupportedBrowser.FF_ESR;
23  
24  import java.io.IOException;
25  import java.io.Serializable;
26  import java.lang.reflect.InvocationTargetException;
27  import java.net.URL;
28  import java.time.ZoneId;
29  import java.time.format.DateTimeFormatter;
30  import java.util.ArrayList;
31  import java.util.Date;
32  import java.util.HashSet;
33  import java.util.List;
34  import java.util.Locale;
35  import java.util.Map;
36  import java.util.Set;
37  import java.util.function.Predicate;
38  
39  import org.apache.commons.logging.Log;
40  import org.apache.commons.logging.LogFactory;
41  import org.htmlunit.HttpHeader;
42  import org.htmlunit.Page;
43  import org.htmlunit.SgmlPage;
44  import org.htmlunit.StringWebResponse;
45  import org.htmlunit.WebResponse;
46  import org.htmlunit.WebWindow;
47  import org.htmlunit.corejs.javascript.Callable;
48  import org.htmlunit.corejs.javascript.Context;
49  import org.htmlunit.corejs.javascript.Function;
50  import org.htmlunit.corejs.javascript.NativeFunction;
51  import org.htmlunit.corejs.javascript.Scriptable;
52  import org.htmlunit.corejs.javascript.ScriptableObject;
53  import org.htmlunit.corejs.javascript.VarScope;
54  import org.htmlunit.cssparser.parser.CSSException;
55  import org.htmlunit.html.DomComment;
56  import org.htmlunit.html.DomDocumentFragment;
57  import org.htmlunit.html.DomElement;
58  import org.htmlunit.html.DomNode;
59  import org.htmlunit.html.DomText;
60  import org.htmlunit.html.FrameWindow;
61  import org.htmlunit.html.Html;
62  import org.htmlunit.html.HtmlAnchor;
63  import org.htmlunit.html.HtmlArea;
64  import org.htmlunit.html.HtmlAttributeChangeEvent;
65  import org.htmlunit.html.HtmlElement;
66  import org.htmlunit.html.HtmlEmbed;
67  import org.htmlunit.html.HtmlForm;
68  import org.htmlunit.html.HtmlFrameSet;
69  import org.htmlunit.html.HtmlImage;
70  import org.htmlunit.html.HtmlPage;
71  import org.htmlunit.html.HtmlRb;
72  import org.htmlunit.html.HtmlRp;
73  import org.htmlunit.html.HtmlRt;
74  import org.htmlunit.html.HtmlRtc;
75  import org.htmlunit.html.HtmlScript;
76  import org.htmlunit.html.HtmlSvg;
77  import org.htmlunit.html.HtmlUnknownElement;
78  import org.htmlunit.html.UnknownElementFactory;
79  import org.htmlunit.html.XHtmlPage;
80  import org.htmlunit.html.impl.SimpleRange;
81  import org.htmlunit.http.Cookie;
82  import org.htmlunit.http.HttpUtils;
83  import org.htmlunit.httpclient.HtmlUnitBrowserCompatCookieSpec;
84  import org.htmlunit.javascript.HtmlUnitScriptable;
85  import org.htmlunit.javascript.JavaScriptEngine;
86  import org.htmlunit.javascript.configuration.JsxClass;
87  import org.htmlunit.javascript.configuration.JsxConstructor;
88  import org.htmlunit.javascript.configuration.JsxFunction;
89  import org.htmlunit.javascript.configuration.JsxGetter;
90  import org.htmlunit.javascript.configuration.JsxSetter;
91  import org.htmlunit.javascript.configuration.JsxStaticFunction;
92  import org.htmlunit.javascript.host.Element;
93  import org.htmlunit.javascript.host.FontFaceSet;
94  import org.htmlunit.javascript.host.Location;
95  import org.htmlunit.javascript.host.NativeFunctionPrefixResolver;
96  import org.htmlunit.javascript.host.Window;
97  import org.htmlunit.javascript.host.animations.AnimationEvent;
98  import org.htmlunit.javascript.host.css.StyleSheetList;
99  import org.htmlunit.javascript.host.dom.AbstractList.EffectOnCache;
100 import org.htmlunit.javascript.host.event.BeforeUnloadEvent;
101 import org.htmlunit.javascript.host.event.CompositionEvent;
102 import org.htmlunit.javascript.host.event.CustomEvent;
103 import org.htmlunit.javascript.host.event.DeviceMotionEvent;
104 import org.htmlunit.javascript.host.event.DeviceOrientationEvent;
105 import org.htmlunit.javascript.host.event.DragEvent;
106 import org.htmlunit.javascript.host.event.Event;
107 import org.htmlunit.javascript.host.event.FocusEvent;
108 import org.htmlunit.javascript.host.event.HashChangeEvent;
109 import org.htmlunit.javascript.host.event.KeyboardEvent;
110 import org.htmlunit.javascript.host.event.MessageEvent;
111 import org.htmlunit.javascript.host.event.MouseEvent;
112 import org.htmlunit.javascript.host.event.PointerEvent;
113 import org.htmlunit.javascript.host.event.PopStateEvent;
114 import org.htmlunit.javascript.host.event.ProgressEvent;
115 import org.htmlunit.javascript.host.event.TextEvent;
116 import org.htmlunit.javascript.host.event.UIEvent;
117 import org.htmlunit.javascript.host.event.WheelEvent;
118 import org.htmlunit.javascript.host.html.HTMLAllCollection;
119 import org.htmlunit.javascript.host.html.HTMLBodyElement;
120 import org.htmlunit.javascript.host.html.HTMLCollection;
121 import org.htmlunit.javascript.host.html.HTMLElement;
122 import org.htmlunit.javascript.host.html.HTMLFrameSetElement;
123 import org.htmlunit.util.StringUtils;
124 import org.htmlunit.util.UrlUtils;
125 import org.htmlunit.xpath.xml.utils.PrefixResolver;
126 import org.w3c.dom.CDATASection;
127 import org.w3c.dom.DOMException;
128 import org.w3c.dom.DocumentType;
129 import org.w3c.dom.ProcessingInstruction;
130 
131 /**
132  * A JavaScript object for {@code Document}.
133  *
134  * @author Mike Bowler
135  * @author David K. Taylor
136  * @author Chen Jun
137  * @author Christian Sell
138  * @author Chris Erskine
139  * @author Marc Guillemot
140  * @author Daniel Gredler
141  * @author Michael Ottati
142  * @author George Murnock
143  * @author Ahmed Ashour
144  * @author Rob Di Marco
145  * @author Ronald Brill
146  * @author Chuck Dumont
147  * @author Frank Danek
148  * @author Madis Pärn
149  * @author Lai Quang Duong
150  * @author Sven Strickroth
151  *
152  * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/Document">MDN Documentation</a>
153  * @see <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-7068919">W3C Dom Level 1</a>
154  */
155 @JsxClass
156 public class Document extends Node {
157 
158     private static final Log LOG = LogFactory.getLog(Document.class);
159 
160     /**
161      * See <a href="https://developer.mozilla.org/en/Rich-Text_Editing_in_Mozilla#Executing_Commands">
162      *     Executing Commands</a>.
163      */
164     private static final Set<String> EXECUTE_CMDS_FF = new HashSet<>();
165     private static final Set<String> EXECUTE_CMDS_CHROME = new HashSet<>();
166     /** The formatter to use for the <code>lastModified</code> attribute. */
167     private static final DateTimeFormatter LAST_MODIFIED_DATE_FORMATTER
168                                             = DateTimeFormatter.ofPattern("MM/dd/yyyy HH:mm:ss");
169 
170     /** Contains all supported DOM level 2 events. */
171     private static final Map<String, Class<? extends Event>> SUPPORTED_DOM2_EVENT_TYPE_MAP;
172     /** Contains all supported DOM level 3 events. DOM level 2 events are not included. */
173     private static final Map<String, Class<? extends Event>> SUPPORTED_DOM3_EVENT_TYPE_MAP;
174     /** Contains all supported vendor specific events. */
175     private static final Map<String, Class<? extends Event>> SUPPORTED_VENDOR_EVENT_TYPE_MAP;
176 
177     /*
178       Initializes the supported event type map.
179       Map<String, Class> which maps strings a caller may use when calling into
180       {@link #createEvent(String)} to the associated event class. To support a new
181       event creation type, the event type and associated class need to be added into this map in
182       the static initializer. The map is unmodifiable. Any class that is a value in this map MUST
183       have a no-arg constructor.
184      */
185     static {
186         SUPPORTED_DOM2_EVENT_TYPE_MAP = Map.of(
187                 "HTMLEvents", Event.class,
188                 "MouseEvents", MouseEvent.class,
189                 "UIEvents", UIEvent.class);
190 
191         SUPPORTED_DOM3_EVENT_TYPE_MAP = Map.ofEntries(
192                 Map.entry("Event", Event.class),
193                 Map.entry("KeyboardEvent", KeyboardEvent.class),
194                 Map.entry("MouseEvent", MouseEvent.class),
195                 Map.entry("MessageEvent", MessageEvent.class),
196                 Map.entry("UIEvent", UIEvent.class),
197                 Map.entry("CustomEvent", CustomEvent.class),
198                 Map.entry("CompositionEvent", CompositionEvent.class),
199                 Map.entry("DragEvent", DragEvent.class),
200                 Map.entry("TextEvent", TextEvent.class),
201                 Map.entry("DeviceMotionEvent", DeviceMotionEvent.class),
202                 Map.entry("DeviceOrientationEvent", DeviceOrientationEvent.class));
203 
204         SUPPORTED_VENDOR_EVENT_TYPE_MAP = Map.ofEntries(
205                 Map.entry("BeforeUnloadEvent", BeforeUnloadEvent.class),
206                 Map.entry("Events", Event.class),
207                 Map.entry("HashChangeEvent", HashChangeEvent.class),
208                 Map.entry("KeyEvents", KeyboardEvent.class),
209                 Map.entry("PointerEvent", PointerEvent.class),
210                 Map.entry("PopStateEvent", PopStateEvent.class),
211                 Map.entry("ProgressEvent", ProgressEvent.class),
212                 Map.entry("FocusEvent", FocusEvent.class),
213                 Map.entry("WheelEvent", WheelEvent.class),
214                 Map.entry("AnimationEvent", AnimationEvent.class));
215     }
216 
217     private Window window_;
218     private DOMImplementation implementation_;
219     private String designMode_;
220     private String compatMode_;
221     private int documentMode_ = -1;
222     private String domain_;
223     private String lastModified_;
224     private ScriptableObject currentScript_;
225     private transient FontFaceSet fonts_;
226     private transient StyleSheetList styleSheetList_;
227 
228     static {
229         // commands
230         String[] cmds = {
231             "BackColor", "BackgroundImageCache" /* Undocumented */,
232             "Bold",
233             "CreateLink", "Delete",
234             "FontName", "FontSize", "ForeColor", "FormatBlock",
235             "Indent", "InsertHorizontalRule", "InsertImage",
236             "InsertOrderedList", "InsertParagraph", "InsertUnorderedList",
237             "Italic", "JustifyCenter", "JustifyFull", "JustifyLeft", "JustifyNone",
238             "JustifyRight",
239             "Outdent",
240             "Print",
241             "Redo", "RemoveFormat",
242             "SelectAll", "StrikeThrough", "Subscript", "Superscript",
243             "Underline", "Undo", "Unlink", "Unselect"
244         };
245         for (final String cmd : cmds) {
246             if (!"Bold".equals(cmd)) {
247                 EXECUTE_CMDS_CHROME.add(cmd.toLowerCase(Locale.ROOT));
248             }
249         }
250 
251         cmds = new String[] {
252             "backColor", "bold", "contentReadOnly", "copy", "createLink", "cut", "decreaseFontSize", "delete",
253             "fontName", "fontSize", "foreColor", "formatBlock", "heading", "hiliteColor", "increaseFontSize",
254             "indent", "insertHorizontalRule", "insertHTML", "insertImage", "insertOrderedList", "insertUnorderedList",
255             "insertParagraph", "italic",
256             "justifyCenter", "JustifyFull", "justifyLeft", "justifyRight", "outdent", "paste", "redo",
257             "removeFormat", "selectAll", "strikeThrough", "subscript", "superscript", "underline", "undo", "unlink",
258             "useCSS", "styleWithCSS"
259         };
260         for (final String cmd : cmds) {
261             EXECUTE_CMDS_FF.add(cmd.toLowerCase(Locale.ROOT));
262             if (!"bold".equals(cmd)) {
263                 EXECUTE_CMDS_CHROME.add(cmd.toLowerCase(Locale.ROOT));
264             }
265         }
266     }
267 
268     /**
269      * JavaScript constructor.
270      */
271     @Override
272     @JsxConstructor
273     public void jsConstructor() {
274         throw JavaScriptEngine.typeErrorIllegalConstructor();
275     }
276 
277     /**
278      * Parses the given string of HTML without sanitizing it and returns a new HTMLDocument.
279      *
280      * @param cx the current context
281      * @param scope the scope
282      * @param thisObj the scriptable this object
283      * @param args the arguments
284      * @param funObj the function object
285      * @return a newly created {@link org.htmlunit.javascript.host.html.HTMLDocument}
286      *
287      * @see <a href="https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#dom-parsehtmlunsafe">
288      *     HTML spec - parseHTMLUnsafe</a>
289      */
290     @JsxStaticFunction
291     public static Document parseHTMLUnsafe(final Context cx, final VarScope scope,
292             final Scriptable thisObj, final Object[] args, final Function funObj) {
293         if (args.length < 1) {
294             throw JavaScriptEngine
295                     .typeError("Document.parseHTMLUnsafe: At least 1 argument required, but only 0 passed");
296         }
297 
298         final Window win = getWindow(thisObj);
299         if (JavaScriptEngine.isUndefined(args[0])) {
300             return win.getDocument();
301         }
302 
303         final String html = JavaScriptEngine.toString(args[0]);
304 
305         try {
306             final WebWindow webWindow = win.getWebWindow();
307             final WebResponse webResponse = new StringWebResponse(html, webWindow.getEnclosedPage().getUrl());
308             return DOMParser.parseHtmlDocument(win.getDocument(), webResponse, webWindow);
309         }
310         catch (final IOException e) {
311             throw JavaScriptEngine.syntaxError("Parsing failed" + e.getMessage());
312         }
313     }
314 
315     /**
316      * Sets the Window JavaScript object that encloses this document.
317      * @param window the Window JavaScript object that encloses this document
318      */
319     public void setWindow(final Window window) {
320         window_ = window;
321     }
322 
323     /**
324      * Returns the value of the {@code location} property.
325      * @return the value of the {@code location} property
326      */
327     @JsxGetter
328     public Location getLocation() {
329         if (window_ == null) {
330             return null;
331         }
332         return window_.getLocation();
333     }
334 
335     /**
336      * Sets the value of the {@code location} property. The location's default property is "href",
337      * so setting "document.location='http://www.sf.net'" is equivalent to setting
338      * "document.location.href='http://www.sf.net'".
339      * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/Document/location">MDN Documentation</a>
340      * @param location the location to navigate to
341      * @throws IOException when location loading fails
342      */
343     @JsxSetter
344     public void setLocation(final String location) throws IOException {
345         window_.setLocation(location);
346     }
347 
348     /**
349      * Returns the value of the {@code referrer} property.
350      * @return the value of the {@code referrer} property
351      */
352     @JsxGetter
353     public String getReferrer() {
354         String referrer = "";
355         final WebResponse webResponse = getPage().getWebResponse();
356         if (webResponse != null) {
357             referrer = webResponse.getWebRequest().getAdditionalHeaders().get(HttpHeader.REFERER);
358             if (referrer == null) {
359                 referrer = "";
360             }
361         }
362         return referrer;
363     }
364 
365     /**
366      * Gets the JavaScript property {@code documentElement} for the document.
367      * @return the root node for the document
368      */
369     @JsxGetter
370     public Element getDocumentElement() {
371         final Object documentElement = getPage().getDocumentElement();
372         if (documentElement == null) {
373             // for instance with an XML document with parsing error
374             return null;
375         }
376         return (Element) getScriptableFor(documentElement);
377     }
378 
379     /**
380      * Gets the JavaScript property {@code rootElement}.
381      * @return the root node for the document
382      */
383     @JsxGetter
384     public Element getRootElement() {
385         return null;
386     }
387 
388     /**
389      * Gets the JavaScript property {@code doctype} for the document.
390      * @return the DocumentType of the document
391      */
392     @JsxGetter
393     public HtmlUnitScriptable getDoctype() {
394         final Object documentType = getPage().getDoctype();
395         if (documentType == null) {
396             return null;
397         }
398         return getScriptableFor(documentType);
399     }
400 
401     /**
402      * Returns a value which indicates whether or not the document can be edited.
403      * @return a value which indicates whether or not the document can be edited
404      */
405     @JsxGetter
406     public String getDesignMode() {
407         if (designMode_ == null) {
408             designMode_ = "off";
409         }
410         return designMode_;
411     }
412 
413     /**
414      * Sets a value which indicates whether or not the document can be edited.
415      * @param mode a value which indicates whether or not the document can be edited
416      */
417     @JsxSetter
418     public void setDesignMode(final String mode) {
419         if ("on".equalsIgnoreCase(mode)) {
420             designMode_ = "on";
421             final SgmlPage page = getPage();
422             if (page != null && page.isHtmlPage()
423                     && getBrowserVersion().hasFeature(JS_DOCUMENT_SELECTION_RANGE_COUNT)) {
424                 final HtmlPage htmlPage = (HtmlPage) page;
425                 final DomNode child = htmlPage.getBody().getFirstChild();
426                 final DomNode rangeNode = child == null ? htmlPage.getBody() : child;
427                 htmlPage.setSelectionRange(new SimpleRange(rangeNode, 0));
428             }
429         }
430         else if ("off".equalsIgnoreCase(mode)) {
431             designMode_ = "off";
432         }
433     }
434 
435     /**
436      * Returns the page that this document is modeling.
437      * @return the page that this document is modeling
438      */
439     public SgmlPage getPage() {
440         return (SgmlPage) getDomNodeOrDie();
441     }
442 
443     /**
444      * Gets the window in which this document is contained.
445      * @return the window
446      */
447     @JsxGetter
448     public Object getDefaultView() {
449         return getWindow();
450     }
451 
452     /**
453      * Creates a new document fragment.
454      * @return a newly created document fragment
455      */
456     @JsxFunction
457     public HtmlUnitScriptable createDocumentFragment() {
458         final DomDocumentFragment fragment = getDomNodeOrDie().getPage().createDocumentFragment();
459         final DocumentFragment node = new DocumentFragment();
460         node.setParentScope(getParentScope());
461         node.setPrototype(getPrototype(node.getClass()));
462         node.setDomNode(fragment);
463         return getScriptableFor(fragment);
464     }
465 
466     /**
467      * Creates a new HTML attribute with the specified name.
468      *
469      * @param attributeName the name of the attribute to create
470      * @return an attribute with the specified name
471      */
472     @JsxFunction
473     public Attr createAttribute(final String attributeName) {
474         return getPage().createAttribute(attributeName).getScriptableObject();
475     }
476 
477     /**
478      * Imports a node from another document to this document.
479      * The source node is not altered or removed from the original document;
480      * this method creates a new copy of the source node.
481      *
482      * @param importedNode the node to import
483      * @param deep Whether to recursively import the subtree under the specified node; or not
484      * @return the imported node that belongs to this Document
485      */
486     @JsxFunction
487     public HtmlUnitScriptable importNode(final Node importedNode, final boolean deep) {
488         DomNode domNode = importedNode.getDomNodeOrDie();
489         domNode = domNode.cloneNode(deep);
490         domNode.processImportNode(this);
491         for (final DomNode childNode : domNode.getDescendants()) {
492             childNode.processImportNode(this);
493         }
494         return domNode.getScriptableObject();
495     }
496 
497     /**
498      * Adopts a node from an external document.
499      * The node and its subtree are removed from the document it's in (if any),
500      * and its ownerDocument is changed to the current document.
501      * The node can then be inserted into the current document.
502      *
503      * @param externalNode the node from another document to be adopted
504      * @return the adopted node that can be used in the current document
505      */
506     @JsxFunction
507     public HtmlUnitScriptable adoptNode(final Node externalNode) {
508         externalNode.remove();
509 
510         final DomNode domNode = externalNode.getDomNodeOrDie();
511         domNode.processImportNode(this);
512         for (final DomNode childNode : domNode.getDescendants()) {
513             childNode.processImportNode(this);
514         }
515         return domNode.getScriptableObject();
516     }
517 
518     /**
519      * Returns the implementation object of the current document.
520      * @return implementation-specific object
521      */
522     @JsxGetter
523     public DOMImplementation getImplementation() {
524         if (implementation_ == null) {
525             implementation_ = new DOMImplementation();
526             implementation_.setParentScope(getParentScope());
527             implementation_.setPrototype(getPrototype(implementation_.getClass()));
528         }
529         return implementation_;
530     }
531 
532     /**
533      * Adapts any DOM node to resolve namespaces so that an XPath expression can be easily
534      * evaluated relative to the context of the node where it appeared within the document.
535      * @param nodeResolver the node to be used as a context for namespace resolution
536      * @return an XPathNSResolver which resolves namespaces with respect to the definitions
537      *         in scope for a specified node
538      */
539     @JsxFunction
540     public NativeXPathNSResolver createNSResolver(final Node nodeResolver) {
541         final NativeXPathNSResolver resolver = new NativeXPathNSResolver();
542         resolver.setElement(nodeResolver);
543         resolver.setParentScope(getParentScope());
544         resolver.setPrototype(getPrototype(resolver.getClass()));
545         return resolver;
546     }
547 
548     /**
549      * Create a new DOM text node with the given data.
550      *
551      * @param newData the string value for the text node
552      * @return the new text node or NOT_FOUND if there is an error
553      */
554     @JsxFunction
555     public HtmlUnitScriptable createTextNode(final String newData) {
556         final DomNode domNode = new DomText(getDomNodeOrDie().getPage(), newData);
557         return makeScriptableFor(domNode);
558     }
559 
560     /**
561      * Creates a new Comment.
562      * @param comment the comment text
563      * @return the new Comment
564      */
565     @JsxFunction
566     public HtmlUnitScriptable createComment(final String comment) {
567         final DomNode domNode = new DomComment(getDomNodeOrDie().getPage(), comment);
568         return getScriptableFor(domNode);
569     }
570 
571     /**
572      * Evaluates an XPath expression string and returns a result of the specified type if possible.
573      * @param expression the XPath expression string to be parsed and evaluated
574      * @param contextNode the context node for the evaluation of this XPath expression
575      * @param resolver the resolver permits translation of all prefixes, including the XML namespace prefix,
576      *        within the XPath expression into appropriate namespace URIs.
577      * @param type If a specific type is specified, then the result will be returned as the corresponding type
578      * @param result the result object which may be reused and returned by this method
579      * @return the result of the evaluation of the XPath expression
580      */
581     @JsxFunction
582     public XPathResult evaluate(final String expression, final Node contextNode,
583             final Object resolver, final int type, final Object result) {
584         XPathResult xPathResult = null;
585         if (result instanceof XPathResult pathResult) {
586             xPathResult = pathResult;
587 
588             if (getBrowserVersion().hasFeature(JS_DOCUMENT_EVALUATE_RECREATES_RESULT)) {
589                 xPathResult = new XPathResult();
590                 xPathResult.setParentScope(getParentScope());
591                 xPathResult.setPrototype(getPrototype(xPathResult.getClass()));
592             }
593         }
594         else if (result == null
595                 || JavaScriptEngine.isUndefined(result)
596                 || result instanceof ScriptableObject) {
597             xPathResult = new XPathResult();
598             xPathResult.setParentScope(getParentScope());
599             xPathResult.setPrototype(getPrototype(xPathResult.getClass()));
600         }
601         else {
602             throw JavaScriptEngine.typeError("Argument 5 of Document.evaluate has to be an XPathResult or null.");
603         }
604 
605         try {
606             PrefixResolver prefixResolver = null;
607             if (resolver instanceof NativeFunction function) {
608                 prefixResolver = new NativeFunctionPrefixResolver(
609                                             function, contextNode.getParentScope());
610             }
611             else if (resolver instanceof PrefixResolver prefixResolver1) {
612                 prefixResolver = prefixResolver1;
613             }
614             xPathResult.init(contextNode.getDomNodeOrDie().getByXPath(expression, prefixResolver), type);
615             return xPathResult;
616         }
617         catch (final Exception e) {
618             throw JavaScriptEngine.asJavaScriptException(
619                     getWindow(),
620                     "Failed to execute 'evaluate': " + e.getMessage(),
621                     org.htmlunit.javascript.host.dom.DOMException.SYNTAX_ERR);
622         }
623     }
624 
625     /**
626      * Creates a new element with the given tag name.
627      *
628      * @param tagName the tag name
629      * @return the new HTML element, or NOT_FOUND if the tag is not supported
630      */
631     @JsxFunction
632     public HtmlUnitScriptable createElement(final Object tagName) {
633         if (tagName == null || JavaScriptEngine.isUndefined(tagName)) {
634             final org.w3c.dom.Node element = getPage().createElement("unknown");
635             ((HtmlUnknownElement) element).markAsCreatedByJavascript();
636             return getScriptableFor(element);
637         }
638 
639         // https://dom.spec.whatwg.org/#dom-document-createelement
640         // NameStartChar ::= ":" | [A-Z] | "_" | [a-z] | [#xC0-#xD6] | [#xD8-#xF6] | [#xF8-#x2FF] | [#x370-#x37D]
641         //                       | [#x37F-#x1FFF] | [#x200C-#x200D] | [#x2070-#x218F] | [#x2C00-#x2FEF]
642         //                       | [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF]
643         // NameChar      ::= NameStartChar | "-" | "." | [0-9] | #xB7 | [#x0300-#x036F] | [#x203F-#x2040]
644         // Name          ::= NameStartChar (NameChar)*
645 
646         // but I have no idea what the browsers are doing
647         // the following code is a wild guess that might be good enough for the moment
648 
649         // April 2026
650         // looks like the browsers using a more simple approach now
651         // see
652         //   org.htmlunit.javascript.host.dom.DocumentTest.documentCreateElementValidTagNames()
653         //   org.htmlunit.javascript.host.dom.DocumentTest.documentCreateElementValidTagNames1000()
654         //   org.htmlunit.javascript.host.dom.DocumentTest.documentCreateElementValidTagNames2000()
655         //   org.htmlunit.javascript.host.dom.DocumentTest.documentCreateElementValidTagNames3000()
656         //   org.htmlunit.javascript.host.dom.DocumentTest.documentCreateElementValidTagNames4000()
657 
658         final String tagNameString = JavaScriptEngine.toString(tagName);
659         if (tagNameString.length() > 0) {
660             final int firstChar = tagNameString.charAt(0);
661             if (firstChar < 128
662                     && !Character.isLetter(firstChar)
663                     && firstChar != ':' && firstChar != '_') {
664                 if (LOG.isInfoEnabled()) {
665                     LOG.info("createElement: Provided string '" + tagNameString + "' contains an invalid character");
666                 }
667                 throw JavaScriptEngine.asJavaScriptException(
668                         getWindow(),
669                         "createElement: Provided string '" + tagNameString + "' contains an invalid character",
670                         org.htmlunit.javascript.host.dom.DOMException.INVALID_CHARACTER_ERR);
671             }
672 
673             final int length = tagNameString.length();
674             for (int i = 1; i < length; i++) {
675                 final int c = tagNameString.charAt(i);
676                 if (c < 128) {
677                     if (c == 0
678                             || c == 9
679                             || c == 10
680                             || c == 12
681                             || c == 13
682                             || c == ' '
683                             || c == '/'
684                             || c == '>') {
685                         if (LOG.isInfoEnabled()) {
686                             LOG.info("createElement: Provided string '"
687                                         + tagNameString + "' contains an invalid character");
688                         }
689                         throw JavaScriptEngine.asJavaScriptException(
690                                 getWindow(),
691                                 "createElement: Provided string '" + tagNameString
692                                     + "' contains an invalid character",
693                                 org.htmlunit.javascript.host.dom.DOMException.INVALID_CHARACTER_ERR);
694                     }
695                 }
696             }
697         }
698 
699         org.w3c.dom.Node element = getPage().createElement(tagNameString);
700 
701         if (element instanceof HtmlImage image) {
702             image.markAsCreatedByJavascript();
703         }
704         else if (element instanceof HtmlRb rb) {
705             rb.markAsCreatedByJavascript();
706         }
707         else if (element instanceof HtmlRp rp) {
708             rp.markAsCreatedByJavascript();
709         }
710         else if (element instanceof HtmlRt rt) {
711             rt.markAsCreatedByJavascript();
712         }
713         else if (element instanceof HtmlRtc rtc) {
714             rtc.markAsCreatedByJavascript();
715         }
716         else if (element instanceof HtmlUnknownElement unknownElement) {
717             unknownElement.markAsCreatedByJavascript();
718         }
719         else if (element instanceof HtmlSvg) {
720             element = UnknownElementFactory.INSTANCE.createElementNS(getPage(), "", "svg", null);
721             ((HtmlUnknownElement) element).markAsCreatedByJavascript();
722         }
723         final HtmlUnitScriptable jsElement = getScriptableFor(element);
724 
725         if (jsElement == NOT_FOUND) {
726             if (LOG.isDebugEnabled()) {
727                 LOG.debug("createElement(" + tagName
728                     + ") cannot return a result as there isn't a JavaScript object for the element "
729                     + element.getClass().getName());
730             }
731         }
732         return jsElement;
733     }
734 
735     /**
736      * Creates a new HTML element with the given tag name, and name.
737      *
738      * @param namespaceURI the URI that identifies an XML namespace
739      * @param qualifiedName the qualified name of the element type to instantiate
740      * @return the new HTML element, or NOT_FOUND if the tag is not supported
741      */
742     @JsxFunction
743     public HtmlUnitScriptable createElementNS(final String namespaceURI, final String qualifiedName) {
744         if ("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul".equals(namespaceURI)) {
745             throw JavaScriptEngine.typeError("XUL not available");
746         }
747 
748         final org.w3c.dom.Element element;
749         if (Html.XHTML_NAMESPACE.equals(namespaceURI)
750                 || Html.SVG_NAMESPACE.equals(namespaceURI)) {
751             element = getPage().createElementNS(namespaceURI, qualifiedName);
752         }
753         else {
754             element = new DomElement(namespaceURI, qualifiedName, getPage(), null);
755         }
756         return getScriptableFor(element);
757     }
758 
759     /**
760      * Returns all the descendant elements with the specified tag name.
761      * @param tagName the name to search for
762      * @return all the descendant elements with the specified tag name
763      */
764     @JsxFunction
765     public HTMLCollection getElementsByTagName(final String tagName) {
766         final HTMLCollection collection = new HTMLCollection(getDomNodeOrDie(), false);
767 
768         if (StringUtils.equalsChar('*', tagName)) {
769             collection.setIsMatchingPredicate((Predicate<DomNode> & Serializable) node -> true);
770         }
771         else {
772             collection.setIsMatchingPredicate(
773                     (Predicate<DomNode> & Serializable)
774                     node -> tagName.equalsIgnoreCase(node.getNodeName()));
775         }
776 
777         return collection;
778     }
779 
780     /**
781      * Returns a list of elements with the given tag name belonging to the given namespace.
782      * @param namespaceURI the namespace URI of elements to look for
783      * @param localName is either the local name of elements to look for or the special value "*",
784      *                  which matches all elements.
785      * @return a live NodeList of found elements in the order they appear in the tree
786      */
787     @JsxFunction
788     public HTMLCollection getElementsByTagNameNS(final Object namespaceURI, final String localName) {
789         final HTMLCollection elements = new HTMLCollection(getDomNodeOrDie(), false);
790         elements.setIsMatchingPredicate(
791                 (Predicate<DomNode> & Serializable)
792                 node -> localName.equals(node.getLocalName()));
793         return elements;
794     }
795 
796     /**
797      * Returns the value of the {@code activeElement} property.
798      * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/Document/activeElement">MDN Documentation</a>
799      * @return the value of the {@code activeElement} property
800      */
801     @JsxGetter
802     public Object getActiveElement() {
803         return null;
804     }
805 
806     /**
807      * Returns the character encoding of the current document.
808      * @return the character encoding of the current document
809      */
810     @JsxGetter
811     public String getCharacterSet() {
812         if (!(getPage() instanceof HtmlPage)) {
813             // TODO: implement XmlPage.getCharset
814             return "";
815         }
816         return getPage().getCharset().name();
817     }
818 
819     /**
820      * Retrieves the character set used to encode the document.
821      * @return the character set used to encode the document
822      */
823     @JsxGetter
824     public String getCharset() {
825         if (!(getPage() instanceof HtmlPage)) {
826             // TODO: implement XmlPage.getCharset
827             return "";
828         }
829         return getPage().getCharset().name();
830     }
831 
832     /**
833      * Returns the value of the JavaScript property {@code anchors}.
834      * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/Document/anchors">MDN Documentation</a>
835      * @see <a href="http://www.mozilla.org/docs/dom/domref/dom_doc_ref4.html#1024543">
836      *     Gecko DOM reference</a>
837      * @return the value of this property
838      */
839     @JsxGetter
840     public HTMLCollection getAnchors() {
841         final HTMLCollection anchors = new HTMLCollection(getDomNodeOrDie(), true);
842 
843         anchors.setIsMatchingPredicate(
844                 (Predicate<DomNode> & Serializable)
845                 node -> {
846                     if (!(node instanceof HtmlAnchor anchor)) {
847                         return false;
848                     }
849                     return anchor.hasAttribute(DomElement.NAME_ATTRIBUTE);
850                 });
851 
852         anchors.setEffectOnCacheFunction(
853                 (java.util.function.Function<HtmlAttributeChangeEvent, EffectOnCache> & Serializable)
854                     event -> {
855                         if (DomElement.NAME_ATTRIBUTE.equals(event.getName())
856                                 || DomElement.ID_ATTRIBUTE.equals(event.getName())) {
857                             return EffectOnCache.RESET;
858                         }
859                         return EffectOnCache.NONE;
860                     });
861 
862         return anchors;
863     }
864 
865     /**
866      * Returns the value of the JavaScript property {@code applets}.
867      * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/Document/applets">
868      *     MDN Documentation</a>
869      * @return the value of this property
870      */
871     @JsxGetter
872     public HTMLCollection getApplets() {
873         return new HTMLCollection(getDomNodeOrDie(), false);
874     }
875 
876     /**
877      * Returns this document's {@code body} element.
878      * @return this document's {@code body} element
879      */
880     @JsxGetter
881     public HTMLElement getBody() {
882         final Page page = getPage();
883         if (page instanceof HtmlPage htmlPage) {
884             final HtmlElement body = htmlPage.getBody();
885             if (body != null) {
886                 return body.getScriptableObject();
887             }
888 
889             // strange but this returns the frameset element
890             final DomElement doc = htmlPage.getDocumentElement();
891             if (doc != null) {
892                 for (final DomNode node : doc.getChildren()) {
893                     if (node instanceof HtmlFrameSet) {
894                         return node.getScriptableObject();
895                     }
896                 }
897             }
898         }
899         return null;
900     }
901 
902     /**
903      * Sets the {@code body} element of the document.
904      * @param htmlElement the new html element
905      */
906     @JsxSetter
907     public void setBody(final HTMLElement htmlElement) {
908         if (htmlElement instanceof HTMLBodyElement || htmlElement instanceof HTMLFrameSetElement) {
909             final Page page = getPage();
910             if (page instanceof HtmlPage htmlPage) {
911                 final HtmlElement body = htmlPage.getBody();
912                 if (body != null) {
913                     body.replace(htmlElement.getDomNodeOrDie());
914                 }
915             }
916             return;
917         }
918         throw JavaScriptEngine.asJavaScriptException(
919                 getWindow(),
920                 "Failed to set the 'body' property on 'Document': "
921                         + "The new body element is of type '" +  htmlElement.getTagName() + "'. "
922                         + "It must be either a 'BODY' or 'FRAMESET' element.",
923                 org.htmlunit.javascript.host.dom.DOMException.HIERARCHY_REQUEST_ERR);
924     }
925 
926     /**
927      * JavaScript function {@code close}.
928      * <p>See <a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/section-dynamic.html">
929      * http://www.whatwg.org/specs/web-apps/current-work/multipage/section-dynamic.html</a> for
930      * a good description of the semantics of open(), write(), writeln() and close().</p>
931      *
932      * @throws IOException if an IO problem occurs
933      */
934     @JsxFunction({CHROME, EDGE})
935     public void close() throws IOException {
936         // nothing to do
937     }
938 
939     /**
940      * Returns the {@code compatMode} property.
941      * @return the {@code compatMode} property
942      */
943     @JsxGetter
944     public String getCompatMode() {
945         // initialize the modes
946         getDocumentMode();
947         return compatMode_;
948     }
949 
950     /**
951      * Returns the {@code documentMode} property.
952      * @return the {@code documentMode} property
953      */
954     public int getDocumentMode() {
955         if (documentMode_ != -1) {
956             return documentMode_;
957         }
958 
959         compatMode_ = "CSS1Compat";
960 
961         if (isQuirksDocType()) {
962             compatMode_ = "BackCompat";
963         }
964 
965         final float version = getBrowserVersion().getBrowserVersionNumeric();
966         documentMode_ = (int) Math.floor(version);
967         return documentMode_;
968     }
969 
970     private boolean isQuirksDocType() {
971         final DocumentType docType = getPage().getDoctype();
972         if (docType != null) {
973             final String systemId = docType.getSystemId();
974             if (systemId != null) {
975                 if ("http://www.w3.org/TR/html4/strict.dtd".equals(systemId)) {
976                     return false;
977                 }
978 
979                 if ("http://www.w3.org/TR/html4/loose.dtd".equals(systemId)) {
980                     final String publicId = docType.getPublicId();
981                     if ("-//W3C//DTD HTML 4.01 Transitional//EN".equals(publicId)) {
982                         return false;
983                     }
984                 }
985 
986                 if ("http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd".equals(systemId)
987                     || "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd".equals(systemId)) {
988                     return false;
989                 }
990             }
991             else if (docType.getPublicId() == null) {
992                 return docType.getName() == null;
993             }
994         }
995         return true;
996     }
997 
998     /**
999      * <span style="color:red">INTERNAL API - SUBJECT TO CHANGE AT ANY TIME - USE AT YOUR OWN RISK.</span><br>
1000      *
1001      * Called from the HTMLParser if an 'X-UA-Compatible' meta tag found.
1002      * @param documentMode the mode forced by the meta tag
1003      */
1004     public void forceDocumentMode(final int documentMode) {
1005         documentMode_ = documentMode;
1006         compatMode_ = documentMode == 5 ? "BackCompat" : "CSS1Compat";
1007     }
1008 
1009     /**
1010      * Returns the first element within the document that matches the specified group of selectors.
1011      * @param selectors the selectors
1012      * @return null if no matches are found; otherwise, it returns the first matching element
1013      */
1014     @JsxFunction
1015     public Node querySelector(final String selectors) {
1016         try {
1017             final Element doc = getDocumentElement();
1018             final DomNode scope = doc == null ? null : doc.getDomNodeOrNull();
1019             final DomNode node = getDomNodeOrDie().querySelector(selectors, scope);
1020             if (node != null) {
1021                 return node.getScriptableObject();
1022             }
1023             return null;
1024         }
1025         catch (final CSSException e) {
1026             throw JavaScriptEngine.asJavaScriptException(
1027                     getWindow(),
1028                     "An invalid or illegal selector was specified (selector: '"
1029                             + selectors + "' error: " + e.getMessage() + ").",
1030                     org.htmlunit.javascript.host.dom.DOMException.SYNTAX_ERR);
1031         }
1032     }
1033 
1034     /**
1035      * Retrieves all element nodes from descendants of the starting element node that match any selector
1036      * within the supplied selector strings.
1037      * The NodeList object returned by the querySelectorAll() method must be static, not live.
1038      * @param selectors the selectors
1039      * @return the static node list
1040      */
1041     @JsxFunction
1042     public NodeList querySelectorAll(final String selectors) {
1043         try {
1044             final DomNode domNode = getDomNodeOrDie();
1045             final Element doc = getDocumentElement();
1046             final DomNode scope = doc == null ? null : doc.getDomNodeOrNull();
1047             return NodeList.staticNodeList(getParentScope(), domNode.querySelectorAll(selectors, scope));
1048         }
1049         catch (final CSSException e) {
1050             throw JavaScriptEngine.asJavaScriptException(
1051                     getWindow(),
1052                     "An invalid or illegal selector was specified (selector: '"
1053                             + selectors + "' error: " + e.getMessage() + ").",
1054                     org.htmlunit.javascript.host.dom.DOMException.SYNTAX_ERR);
1055         }
1056     }
1057 
1058     /**
1059      * Indicates if the command is supported.
1060      * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/Document/queryCommandSupported">MDN Documentation</a>
1061      * @param cmd the command identifier
1062      * @return {@code true} if the command is supported
1063      */
1064     @JsxFunction
1065     public boolean queryCommandSupported(final String cmd) {
1066         return hasCommand(cmd, true);
1067     }
1068 
1069     private boolean hasCommand(final String cmd, final boolean includeBold) {
1070         if (cmd == null) {
1071             return false;
1072         }
1073 
1074         final String cmdLC = cmd.toLowerCase(Locale.ROOT);
1075         if (getBrowserVersion().isChrome() || getBrowserVersion().isEdge()) {
1076             return EXECUTE_CMDS_CHROME.contains(cmdLC) || (includeBold && "bold".equalsIgnoreCase(cmd));
1077         }
1078         return EXECUTE_CMDS_FF.contains(cmdLC);
1079     }
1080 
1081     /**
1082      * Indicates if the command can be successfully executed using <code>execCommand</code>, given
1083      * the current state of the document.
1084      * @param cmd the command identifier
1085      * @return {@code true} if the command can be successfully executed
1086      */
1087     @JsxFunction
1088     public boolean queryCommandEnabled(final String cmd) {
1089         return hasCommand(cmd, true);
1090     }
1091 
1092     /**
1093      * Executes a command.
1094      * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/Document/execCommand">MDN Documentation</a>
1095      * @param cmd the command identifier
1096      * @param userInterface display a user interface if the command supports one
1097      * @param value the string, number, or other value to assign (possible values depend on the command)
1098      * @return {@code true} if the command was successful, {@code false} otherwise
1099      */
1100     @JsxFunction
1101     public boolean execCommand(final String cmd, final boolean userInterface, final Object value) {
1102         if (!hasCommand(cmd, false)) {
1103             return false;
1104         }
1105         if (LOG.isWarnEnabled()) {
1106             LOG.warn("Nothing done for execCommand(" + cmd + ", ...) (feature not implemented)");
1107         }
1108         return true;
1109     }
1110 
1111     /**
1112      * Returns the value of the {@code URL} property.
1113      * @return the value of the {@code URL} property
1114      */
1115     @JsxGetter(propertyName = "URL")
1116     public String getURL_js() {
1117         return getPage().getUrl().toExternalForm();
1118     }
1119 
1120     /**
1121      * Returns the value of the {@code documentURI} property.
1122      * @return the value of the {@code documentURI} property
1123      */
1124     @JsxGetter
1125     public String getDocumentURI() {
1126         return getURL_js();
1127     }
1128 
1129     /**
1130      * Returns the {@code cookie} property.
1131      * @return the {@code cookie} property
1132      */
1133     @JsxGetter
1134     public String getCookie() {
1135         final SgmlPage sgmlPage = getPage();
1136 
1137         final StringBuilder builder = new StringBuilder();
1138         final Set<Cookie> cookies = sgmlPage.getWebClient().getCookies(sgmlPage.getUrl());
1139         final List<Cookie> visibleCookies = new ArrayList<>();
1140         for (final Cookie cookie : cookies) {
1141             if (cookie.isHttpOnly()) {
1142                 continue;
1143             }
1144             visibleCookies.add(cookie);
1145         }
1146 
1147         // RFC 6265 §5.4: longer path first; equal-length paths sorted by creation time ascending
1148         // TODO time ascending
1149         visibleCookies.sort((a, b) -> {
1150             final String pathA = a.getPath();
1151             final String pathB = b.getPath();
1152             final int lenA = pathA == null ? 0 : pathA.length();
1153             final int lenB = pathB == null ? 0 : pathB.length();
1154             return Integer.compare(lenB, lenA);
1155         });
1156 
1157         for (final Cookie cookie : visibleCookies) {
1158             if (builder.length() != 0) {
1159                 builder.append("; ");
1160             }
1161             if (!HtmlUnitBrowserCompatCookieSpec.EMPTY_COOKIE_NAME.equals(cookie.getName())) {
1162                 builder.append(cookie.getName()).append('=');
1163             }
1164             builder.append(cookie.getValue());
1165         }
1166 
1167         return builder.toString();
1168     }
1169 
1170     /**
1171      * Adds a cookie, as long as cookies are enabled.
1172      * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/Document/cookie">MDN Documentation</a>
1173      * @param newCookie in the format "name=value[;expires=date][;domain=domainname][;path=path][;secure]"
1174      */
1175     @JsxSetter
1176     public void setCookie(final String newCookie) {
1177         if (StringUtils.isBlank(newCookie)) {
1178             return;
1179         }
1180 
1181         final SgmlPage sgmlPage = getPage();
1182         sgmlPage.getWebClient().addCookie(newCookie, sgmlPage.getUrl(), this);
1183     }
1184 
1185     /**
1186      * Implementation of the {@link org.w3c.dom.events.DocumentEvent} interface's
1187      * {@link org.w3c.dom.events.DocumentEvent#createEvent(String)} method. The method creates an
1188      * uninitialized event of the specified type.
1189      *
1190      * @see <a href="http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-DocumentEvent">DocumentEvent</a>
1191      * @param eventType the event type to create
1192      * @return an event object for the specified type
1193      * @throws DOMException if the event type is not supported (will have a type of
1194      *         DOMException.NOT_SUPPORTED_ERR)
1195      */
1196     @JsxFunction
1197     public Event createEvent(final String eventType) throws DOMException {
1198         Class<? extends Event> clazz = SUPPORTED_DOM2_EVENT_TYPE_MAP.get(eventType);
1199         if (clazz == null) {
1200             clazz = SUPPORTED_DOM3_EVENT_TYPE_MAP.get(eventType);
1201         }
1202 
1203         if (clazz == null
1204                 && ("Events".equals(eventType)
1205                     || "HashChangeEvent".equals(eventType)
1206                     || "BeforeUnloadEvent".equals(eventType)
1207                     || "FocusEvent".equals(eventType))) {
1208             clazz = SUPPORTED_VENDOR_EVENT_TYPE_MAP.get(eventType);
1209         }
1210 
1211         if (clazz == null) {
1212             throw JavaScriptEngine.asJavaScriptException(
1213                     this,
1214                     "Event Type '" + eventType + "' is not supported.",
1215                     org.htmlunit.javascript.host.dom.DOMException.NOT_SUPPORTED_ERR);
1216         }
1217 
1218         try {
1219             final Event event = clazz.getDeclaredConstructor().newInstance();
1220             event.setParentScope(getParentScope());
1221             event.setPrototype(getPrototype(clazz));
1222             event.eventCreated();
1223             return event;
1224         }
1225         catch (final InstantiationException | IllegalAccessException
1226                 | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) {
1227             throw JavaScriptEngine.reportRuntimeError("Failed to instantiate event: class ='" + clazz.getName()
1228                             + "' for event type of '" + eventType + "': " + e.getMessage());
1229         }
1230     }
1231 
1232     /**
1233      * Returns a new NodeIterator object.
1234      *
1235      * @param root The root node at which to begin the NodeIterator's traversal.
1236      * @param whatToShow an optional long representing a bitmask created by combining
1237      *        the constant properties of {@link NodeFilter}
1238      * @param filter an object implementing the {@link NodeFilter} interface
1239      * @return a new NodeIterator object
1240      */
1241     @JsxFunction
1242     public NodeIterator createNodeIterator(final Node root, final int whatToShow, final Scriptable filter) {
1243         final org.w3c.dom.traversal.NodeFilter filterWrapper = createFilterWrapper(filter, false);
1244         final NodeIterator iterator = new NodeIterator(root, whatToShow, filterWrapper);
1245         iterator.setParentScope(getParentScope());
1246         iterator.setPrototype(getPrototype(iterator.getClass()));
1247         return iterator;
1248     }
1249 
1250     private static org.w3c.dom.traversal.NodeFilter createFilterWrapper(final Scriptable filter,
1251             final boolean filterFunctionOnly) {
1252         org.w3c.dom.traversal.NodeFilter filterWrapper = null;
1253         if (filter != null) {
1254             filterWrapper = n -> {
1255                 final Object[] args = {((DomNode) n).getScriptableObject()};
1256                 final Object response;
1257                 if (filter instanceof Callable callable) {
1258                     response = callable.call(Context.getCurrentContext(), filter.getParentScope(), filter, args);
1259                 }
1260                 else {
1261                     if (filterFunctionOnly) {
1262                         throw JavaScriptEngine.reportRuntimeError("only a function is allowed as filter");
1263                     }
1264                     response = ScriptableObject.callMethod(filter, "acceptNode", args);
1265                 }
1266                 return (short) JavaScriptEngine.toNumber(response);
1267             };
1268         }
1269         return filterWrapper;
1270     }
1271 
1272     /**
1273      * Creates and returns a new TreeWalker. The following JavaScript parameters are passed into this method:
1274      * <ul>
1275      *   <li>JavaScript param 1: The root node of the TreeWalker. Must not be {@code null}.</li>
1276      *   <li>JavaScript param 2: Flag specifying which types of nodes appear in the logical view of the TreeWalker.
1277      *       See {@link NodeFilter} for the set of possible Show_ values.</li>
1278      *   <li>JavaScript param 3: The {@link NodeFilter} to be used with this TreeWalker, or {@code null}
1279      *       to indicate no filter.</li>
1280      *   <li>JavaScript param 4: If {@code false}, the contents of EntityReference nodes are not present
1281      *       in the logical view.</li>
1282      * </ul>
1283      *
1284      * @see <a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/traversal.html">DOM-Level-2-Traversal-Range</a>
1285      * @param root the node which will serve as the root for the TreeWalker
1286      * @param whatToShow specifies which node types may appear in the logical view of the tree presented
1287      * @param filter the NodeFilter to be used with this TreeWalker, or null to indicate no filter
1288      * @param expandEntityReferences If false,
1289      *        the contents of EntityReference nodes are not presented in the logical view
1290      * @throws DOMException on attempt to create a TreeWalker with a root that is {@code null}
1291      * @return a new TreeWalker
1292      */
1293     @JsxFunction
1294     public TreeWalker createTreeWalker(final Node root, final double whatToShow, final Scriptable filter,
1295             final boolean expandEntityReferences) throws DOMException {
1296 
1297         // seems that Rhino doesn't like long as parameter type
1298         // this strange conversation preserves NodeFilter.SHOW_ALL
1299         final int whatToShowI = (int) Double.valueOf(whatToShow).longValue();
1300 
1301         final org.w3c.dom.traversal.NodeFilter filterWrapper = createFilterWrapper(filter, false);
1302         final TreeWalker t = new TreeWalker(root, whatToShowI, filterWrapper, false);
1303         t.setParentScope(getParentScope());
1304         t.setPrototype(staticGetPrototype(getWindow(this), TreeWalker.class));
1305         return t;
1306     }
1307 
1308     @SuppressWarnings("unchecked")
1309     private static Scriptable staticGetPrototype(final Window window,
1310             final Class<? extends HtmlUnitScriptable> javaScriptClass) {
1311         final Scriptable prototype = window.getPrototype(javaScriptClass);
1312         if (prototype == null && javaScriptClass != HtmlUnitScriptable.class) {
1313             return staticGetPrototype(window, (Class<? extends HtmlUnitScriptable>) javaScriptClass.getSuperclass());
1314         }
1315         return prototype;
1316     }
1317 
1318     /**
1319      * Creates and returns a new range.
1320      * @return a new range
1321      * @see <a href="http://www.xulplanet.com/references/objref/HTMLDocument.html#method_createRange">XUL Planet</a>
1322      */
1323     @JsxFunction
1324     public Range createRange() {
1325         final Range range = new Range(this);
1326         range.setParentScope(getParentScope());
1327         range.setPrototype(getPrototype(Range.class));
1328         return range;
1329     }
1330 
1331     /**
1332      * Returns the domain name of the server that served the document, or {@code null} if the server
1333      * cannot be identified by a domain name.
1334      * @return the domain name of the server that served the document
1335      * @see <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-2250147">
1336      *     W3C documentation</a>
1337      */
1338     @JsxGetter
1339     public String getDomain() {
1340         if (domain_ == null && getPage().getWebResponse() != null) {
1341             URL url = getPage().getUrl();
1342             if (url == UrlUtils.URL_ABOUT_BLANK) {
1343                 final WebWindow w = getWindow().getWebWindow();
1344                 if (w instanceof FrameWindow window) {
1345                     url = window.getEnclosingPage().getUrl();
1346                 }
1347                 else {
1348                     return null;
1349                 }
1350             }
1351             domain_ = url.getHost().toLowerCase(Locale.ROOT);
1352         }
1353 
1354         return domain_;
1355     }
1356 
1357     /**
1358      * Sets the domain of this document.
1359      *
1360      * <p>Domains can only be set to suffixes of the existing domain
1361      * with the except of setting the domain to itself.</p>
1362      * <p>
1363      * The domain will be set according to the following rules:
1364      * </p>
1365      * <ol>
1366      * <li>If the newDomain.equalsIgnoreCase(currentDomain) the method returns with no error.</li>
1367      * <li>If the browser version is netscape, the newDomain is downshifted.</li>
1368      * <li>The change will take place if and only if the suffixes of the
1369      *       current domain and the new domain match AND there are at least
1370      *       two domain qualifiers e.g. the following transformations are legal
1371      *       d1.d2.d3.gargoylesoftware.com may be transformed to itself or:
1372      *          d2.d3.gargoylesoftware.com
1373      *             d3.gargoylesoftware.com
1374      *                gargoylesoftware.com
1375      * <br>
1376      *        transformation to:        com
1377      *        will fail
1378      * </li>
1379      * </ol>
1380      * <p>
1381      * TODO This code could be modified to understand country domain suffixes.
1382      * The domain www.bbc.co.uk should be trimmable only down to bbc.co.uk
1383      * trimming to co.uk should not be possible.
1384      * </p>
1385      * @param newDomain the new domain to set
1386      */
1387     @JsxSetter
1388     public void setDomain(String newDomain) {
1389         newDomain = newDomain.toLowerCase(Locale.ROOT);
1390 
1391         final String currentDomain = getDomain();
1392         if (currentDomain.equalsIgnoreCase(newDomain)) {
1393             return;
1394         }
1395 
1396         if (newDomain.indexOf('.') == -1) {
1397             throw JavaScriptEngine.reportRuntimeError("Illegal domain value, cannot set domain from: \""
1398                     + currentDomain + "\" to: \"" + newDomain + "\" (new domain has to contain a dot).");
1399         }
1400 
1401         if (currentDomain.indexOf('.') > -1
1402                 && !currentDomain.toLowerCase(Locale.ROOT).endsWith("." + newDomain.toLowerCase(Locale.ROOT))) {
1403             throw JavaScriptEngine.reportRuntimeError("Illegal domain value, cannot set domain from: \""
1404                     + currentDomain + "\" to: \"" + newDomain + "\"");
1405         }
1406 
1407         domain_ = newDomain;
1408     }
1409 
1410     /**
1411      * Sets the {@code onclick} event handler for this element.
1412      * @param handler the {@code onclick} event handler for this element
1413      */
1414     @JsxSetter
1415     public void setOnclick(final Object handler) {
1416         setEventHandler(MouseEvent.TYPE_CLICK, handler);
1417     }
1418 
1419     /**
1420      * Returns the {@code onclick} event handler for this element.
1421      * @return the {@code onclick} event handler for this element
1422      */
1423     @JsxGetter
1424     public Function getOnclick() {
1425         return getEventHandler(MouseEvent.TYPE_CLICK);
1426     }
1427 
1428     /**
1429      * Sets the {@code ondblclick} event handler for this element.
1430      * @param handler the {@code ondblclick} event handler for this element
1431      */
1432     @JsxSetter
1433     public void setOndblclick(final Object handler) {
1434         setEventHandler(MouseEvent.TYPE_DBL_CLICK, handler);
1435     }
1436 
1437     /**
1438      * Returns the {@code ondblclick} event handler for this element.
1439      * @return the {@code ondblclick} event handler for this element
1440      */
1441     @JsxGetter
1442     public Function getOndblclick() {
1443         return getEventHandler(MouseEvent.TYPE_DBL_CLICK);
1444     }
1445 
1446     /**
1447      * Sets the {@code onblur} event handler for this element.
1448      * @param handler the {@code onblur} event handler for this element
1449      */
1450     @JsxSetter
1451     public void setOnblur(final Object handler) {
1452         setEventHandler(Event.TYPE_BLUR, handler);
1453     }
1454 
1455     /**
1456      * Returns the {@code onblur} event handler for this element.
1457      * @return the {@code onblur} event handler for this element
1458      */
1459     @JsxGetter
1460     public Function getOnblur() {
1461         return getEventHandler(Event.TYPE_BLUR);
1462     }
1463 
1464     /**
1465      * Sets the {@code onfocus} event handler for this element.
1466      * @param handler the {@code onfocus} event handler for this element
1467      */
1468     @JsxSetter
1469     public void setOnfocus(final Object handler) {
1470         setEventHandler(Event.TYPE_FOCUS, handler);
1471     }
1472 
1473     /**
1474      * Returns the {@code onfocus} event handler for this element.
1475      * @return the {@code onfocus} event handler for this element
1476      */
1477     @JsxGetter
1478     public Function getOnfocus() {
1479         return getEventHandler(Event.TYPE_FOCUS);
1480     }
1481 
1482     /**
1483      * Sets the {@code onkeydown} event handler for this element.
1484      * @param handler the {@code onkeydown} event handler for this element
1485      */
1486     @JsxSetter
1487     public void setOnkeydown(final Object handler) {
1488         setEventHandler(Event.TYPE_KEY_DOWN, handler);
1489     }
1490 
1491     /**
1492      * Returns the {@code onkeydown} event handler for this element.
1493      * @return the {@code onkeydown} event handler for this element
1494      */
1495     @JsxGetter
1496     public Function getOnkeydown() {
1497         return getEventHandler(Event.TYPE_KEY_DOWN);
1498     }
1499 
1500     /**
1501      * Sets the {@code onkeypress} event handler for this element.
1502      * @param handler the {@code onkeypress} event handler for this element
1503      */
1504     @JsxSetter
1505     public void setOnkeypress(final Object handler) {
1506         setEventHandler(Event.TYPE_KEY_PRESS, handler);
1507     }
1508 
1509     /**
1510      * Returns the {@code onkeypress} event handler for this element.
1511      * @return the {@code onkeypress} event handler for this element
1512      */
1513     @JsxGetter
1514     public Function getOnkeypress() {
1515         return getEventHandler(Event.TYPE_KEY_PRESS);
1516     }
1517 
1518     /**
1519      * Sets the {@code onkeyup} event handler for this element.
1520      * @param handler the {@code onkeyup} event handler for this element
1521      */
1522     @JsxSetter
1523     public void setOnkeyup(final Object handler) {
1524         setEventHandler(Event.TYPE_KEY_UP, handler);
1525     }
1526 
1527     /**
1528      * Returns the {@code onkeyup} event handler for this element.
1529      * @return the {@code onkeyup} event handler for this element
1530      */
1531     @JsxGetter
1532     public Function getOnkeyup() {
1533         return getEventHandler(Event.TYPE_KEY_UP);
1534     }
1535 
1536     /**
1537      * Sets the {@code onmousedown} event handler for this element.
1538      * @param handler the {@code onmousedown} event handler for this element
1539      */
1540     @JsxSetter
1541     public void setOnmousedown(final Object handler) {
1542         setEventHandler(MouseEvent.TYPE_MOUSE_DOWN, handler);
1543     }
1544 
1545     /**
1546      * Returns the {@code onmousedown} event handler for this element.
1547      * @return the {@code onmousedown} event handler for this element
1548      */
1549     @JsxGetter
1550     public Function getOnmousedown() {
1551         return getEventHandler(MouseEvent.TYPE_MOUSE_DOWN);
1552     }
1553 
1554     /**
1555      * Sets the {@code onmousemove} event handler for this element.
1556      * @param handler the {@code onmousemove} event handler for this element
1557      */
1558     @JsxSetter
1559     public void setOnmousemove(final Object handler) {
1560         setEventHandler(MouseEvent.TYPE_MOUSE_MOVE, handler);
1561     }
1562 
1563     /**
1564      * Returns the {@code onmousemove} event handler for this element.
1565      * @return the {@code onmousemove} event handler for this element
1566      */
1567     @JsxGetter
1568     public Function getOnmousemove() {
1569         return getEventHandler(MouseEvent.TYPE_MOUSE_MOVE);
1570     }
1571 
1572     /**
1573      * Sets the {@code onmouseout} event handler for this element.
1574      * @param handler the {@code onmouseout} event handler for this element
1575      */
1576     @JsxSetter
1577     public void setOnmouseout(final Object handler) {
1578         setEventHandler(MouseEvent.TYPE_MOUSE_OUT, handler);
1579     }
1580 
1581     /**
1582      * Returns the {@code onmouseout} event handler for this element.
1583      * @return the {@code onmouseout} event handler for this element
1584      */
1585     @JsxGetter
1586     public Function getOnmouseout() {
1587         return getEventHandler(MouseEvent.TYPE_MOUSE_OUT);
1588     }
1589 
1590     /**
1591      * Sets the {@code onmouseover} event handler for this element.
1592      * @param handler the {@code onmouseover} event handler for this element
1593      */
1594     @JsxSetter
1595     public void setOnmouseover(final Object handler) {
1596         setEventHandler(MouseEvent.TYPE_MOUSE_OVER, handler);
1597     }
1598 
1599     /**
1600      * Returns the {@code onmouseover} event handler for this element.
1601      * @return the {@code onmouseover} event handler for this element
1602      */
1603     @JsxGetter
1604     public Function getOnmouseover() {
1605         return getEventHandler(MouseEvent.TYPE_MOUSE_OVER);
1606     }
1607 
1608     /**
1609      * Sets the {@code onmouseup} event handler for this element.
1610      * @param handler the {@code onmouseup} event handler for this element
1611      */
1612     @JsxSetter
1613     public void setOnmouseup(final Object handler) {
1614         setEventHandler(MouseEvent.TYPE_MOUSE_UP, handler);
1615     }
1616 
1617     /**
1618      * Returns the {@code onmouseup} event handler for this element.
1619      * @return the {@code onmouseup} event handler for this element
1620      */
1621     @JsxGetter
1622     public Function getOnmouseup() {
1623         return getEventHandler(MouseEvent.TYPE_MOUSE_UP);
1624     }
1625 
1626     /**
1627      * Sets the {@code oncontextmenu} event handler for this element.
1628      * @param handler the {@code oncontextmenu} event handler for this element
1629      */
1630     @JsxSetter
1631     public void setOncontextmenu(final Object handler) {
1632         setEventHandler(MouseEvent.TYPE_CONTEXT_MENU, handler);
1633     }
1634 
1635     /**
1636      * Returns the {@code oncontextmenu} event handler for this element.
1637      * @return the {@code oncontextmenu} event handler for this element
1638      */
1639     @JsxGetter
1640     public Function getOncontextmenu() {
1641         return getEventHandler(MouseEvent.TYPE_CONTEXT_MENU);
1642     }
1643 
1644     /**
1645      * Sets the {@code onresize} event handler for this element.
1646      * @param handler the {@code onresize} event handler for this element
1647      */
1648     @JsxSetter
1649     public void setOnresize(final Object handler) {
1650         setEventHandler(Event.TYPE_RESIZE, handler);
1651     }
1652 
1653     /**
1654      * Returns the {@code onresize} event handler for this element.
1655      * @return the {@code onresize} event handler for this element
1656      */
1657     @JsxGetter
1658     public Function getOnresize() {
1659         return getEventHandler(Event.TYPE_RESIZE);
1660     }
1661 
1662     /**
1663      * Sets the {@code onerror} event handler for this element.
1664      * @param handler the {@code onerror} event handler for this element
1665      */
1666     @JsxSetter
1667     public void setOnerror(final Object handler) {
1668         setEventHandler(Event.TYPE_ERROR, handler);
1669     }
1670 
1671     /**
1672      * Returns the {@code onerror} event handler for this element.
1673      * @return the {@code onerror} event handler for this element
1674      */
1675     @JsxGetter
1676     public Function getOnerror() {
1677         return getEventHandler(Event.TYPE_ERROR);
1678     }
1679 
1680     /**
1681      * Returns the {@code oninput} event handler for this element.
1682      * @return the {@code oninput} event handler for this element
1683      */
1684     @JsxGetter
1685     public Function getOninput() {
1686         return getEventHandler(Event.TYPE_INPUT);
1687     }
1688 
1689     /**
1690      * Sets the {@code oninput} event handler for this element.
1691      * @param oninput the {@code oninput} event handler for this element
1692      */
1693     @JsxSetter
1694     public void setOninput(final Object oninput) {
1695         setEventHandler(Event.TYPE_INPUT, oninput);
1696     }
1697 
1698     /**
1699      * Returns the {@code hidden} property.
1700      * @return the {@code hidden} property
1701      */
1702     @JsxGetter
1703     public boolean isHidden() {
1704         return false;
1705     }
1706 
1707     /**
1708      * {@inheritDoc}
1709      */
1710     @Override
1711     @JsxGetter
1712     public int getChildElementCount() {
1713         int counter = 0;
1714         if (getPage().getDocumentElement() != null) {
1715             counter++;
1716         }
1717         return counter;
1718     }
1719 
1720     /**
1721      * Returns the element for the specified x coordinate and the specified y coordinate.
1722      * The current implementation always returns null element.
1723      *
1724      * @param x the x offset, in pixels
1725      * @param y the y offset, in pixels
1726      * @return the element for the specified x coordinate and the specified y coordinate
1727      */
1728     @JsxFunction
1729     public HtmlUnitScriptable elementFromPoint(final int x, final int y) {
1730         return null;
1731     }
1732 
1733     /**
1734      * Returns the value of the {@code forms} property.
1735      * @return the value of the {@code forms} property
1736      */
1737     @JsxGetter
1738     public HTMLCollection getForms() {
1739         final HTMLCollection forms = new HTMLCollection(getDomNodeOrDie(), false);
1740 
1741         forms.setIsMatchingPredicate(
1742                 (Predicate<DomNode> & Serializable)
1743                 node -> node instanceof HtmlForm && node.getPrefix() == null);
1744         return forms;
1745     }
1746 
1747     /**
1748      * Returns the value of the {@code embeds} property.
1749      * @return the value of the {@code embeds} property
1750      */
1751     @JsxGetter
1752     public HTMLCollection getEmbeds() {
1753         final HTMLCollection embeds = new HTMLCollection(getDomNodeOrDie(), false);
1754 
1755         embeds.setIsMatchingPredicate((Predicate<DomNode> & Serializable) node -> node instanceof HtmlEmbed);
1756         return embeds;
1757     }
1758 
1759     /**
1760      * Returns the value of the {@code embeds} property.
1761      * @return the value of the {@code embeds} property
1762      */
1763     @JsxGetter
1764     public HTMLCollection getImages() {
1765         final HTMLCollection images = new HTMLCollection(getDomNodeOrDie(), false);
1766 
1767         images.setIsMatchingPredicate((Predicate<DomNode> & Serializable) node -> node instanceof HtmlImage);
1768         return images;
1769     }
1770 
1771     /**
1772      * Returns the value of the {@code scripts} property.
1773      * @return the value of the {@code scripts} property
1774      */
1775     @JsxGetter
1776     public HTMLCollection getScripts() {
1777         final HTMLCollection scripts = new HTMLCollection(getDomNodeOrDie(), false);
1778 
1779         scripts.setIsMatchingPredicate((Predicate<DomNode> & Serializable) node -> node instanceof HtmlScript);
1780         return scripts;
1781     }
1782 
1783     /**
1784      * Retrieves a collection of stylesheet objects representing the style sheets that correspond
1785      * to each instance of a Link or
1786      * {@link org.htmlunit.javascript.host.css.CSSStyleDeclaration} object in the document.
1787      *
1788      * @return styleSheet collection
1789      */
1790     @JsxGetter
1791     public StyleSheetList getStyleSheets() {
1792         if (styleSheetList_ == null) {
1793             styleSheetList_ = new StyleSheetList(this);
1794         }
1795         return styleSheetList_;
1796     }
1797 
1798     /**
1799      * Returns the value of the {@code plugins} property.
1800      * @return the value of the {@code plugins} property
1801      */
1802     @JsxGetter
1803     public HTMLCollection getPlugins() {
1804         return getEmbeds();
1805     }
1806 
1807     /**
1808      * Returns the value of the JavaScript property {@code links}. Refer also to the
1809      * <a href="https://developer.mozilla.org/en-US/docs/Web/API/Document/links">MDN Documentation</a>.
1810      * @return the value of this property
1811      */
1812     @JsxGetter
1813     public HTMLCollection getLinks() {
1814         final HTMLCollection links = new HTMLCollection(getDomNodeOrDie(), true);
1815 
1816         links.setEffectOnCacheFunction(
1817                 (java.util.function.Function<HtmlAttributeChangeEvent, EffectOnCache> & Serializable)
1818                 event -> {
1819                     final HtmlElement node = event.getHtmlElement();
1820                     if ((node instanceof HtmlAnchor || node instanceof HtmlArea) && "href".equals(event.getName())) {
1821                         return EffectOnCache.RESET;
1822                     }
1823                     return EffectOnCache.NONE;
1824                 });
1825 
1826         links.setIsMatchingPredicate(
1827                 (Predicate<DomNode> & Serializable)
1828                 node ->
1829                     (node instanceof HtmlAnchor || node instanceof HtmlArea)
1830                     && ((HtmlElement) node).hasAttribute("href"));
1831 
1832         return links;
1833     }
1834 
1835     /**
1836      * Returns all the descendant elements with the specified class name.
1837      * @param className the name to search for
1838      * @return all the descendant elements with the specified class name
1839      * @see <a href="https://developer.mozilla.org/en/DOM/document.getElementsByClassName">Mozilla doc</a>
1840      */
1841     @JsxFunction
1842     public HTMLCollection getElementsByClassName(final String className) {
1843         return null;
1844     }
1845 
1846     /**
1847      * Returns all HTML elements that have a {@code name} attribute with the specified value.
1848      * <p>
1849      * Refer to <a href="http://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-71555259">
1850      * The DOM spec</a> for details.
1851      * </p>
1852      *
1853      * @param elementName - value of the {@code name} attribute to look for
1854      * @return all HTML elements that have a {@code name} attribute with the specified value
1855      */
1856     @JsxFunction
1857     public NodeList getElementsByName(final String elementName) {
1858         return null;
1859     }
1860 
1861     /**
1862      * Returns {@code false} if the active element in the document has no focus;
1863      * {@code true} if the active element in the document has focus.
1864      * @return whether the active element in the document has focus or not
1865      */
1866     @JsxFunction
1867     public boolean hasFocus() {
1868         return false;
1869     }
1870 
1871     /**
1872      * Returns this document's title.
1873      * @return this document's title
1874      */
1875     @JsxGetter
1876     public String getTitle() {
1877         return "";
1878     }
1879 
1880     /**
1881      * Sets this document's title.
1882      * @param title the new title
1883      */
1884     @JsxSetter
1885     public void setTitle(final String title) {
1886         // nothing to do
1887     }
1888 
1889     /**
1890      * {@inheritDoc}
1891      */
1892     @Override
1893     @JsxGetter
1894     public HTMLCollection getChildren() {
1895         return super.getChildren();
1896     }
1897 
1898     /**
1899      * Returns the {@code contentType} property.
1900      * @return the {@code contentType} property
1901      */
1902     @JsxGetter
1903     public String getContentType() {
1904         return getPage().getContentType();
1905     }
1906 
1907     /**
1908      * Returns the current selection.
1909      * @return the current selection
1910      */
1911     @JsxFunction
1912     public Selection getSelection() {
1913         return null;
1914     }
1915 
1916     /**
1917      * Returns this document's {@code head} element.
1918      * @return this document's {@code head} element
1919      */
1920     @JsxGetter
1921     public Object getHead() {
1922         return null;
1923     }
1924 
1925     /**
1926      * Returns a string representing the encoding under which the document was parsed.
1927      * @return a string representing the encoding under which the document was parsed
1928      */
1929     @JsxGetter
1930     public String getInputEncoding() {
1931         return getPage().getCharset().name();
1932     }
1933 
1934     /**
1935      * Returns the last modification date of the document.
1936      * @see <a href="https://developer.mozilla.org/en/DOM/document.lastModified">Mozilla documentation</a>
1937      * @return the date as string
1938      */
1939     @JsxGetter
1940     public String getLastModified() {
1941         if (lastModified_ == null) {
1942             final WebResponse webResponse = getPage().getWebResponse();
1943             final Date lastModified;
1944             if (webResponse != null) {
1945                 String stringDate = webResponse.getResponseHeaderValue("Last-Modified");
1946                 if (stringDate == null) {
1947                     stringDate = webResponse.getResponseHeaderValue("Date");
1948                 }
1949                 lastModified = parseDateOrNow(stringDate);
1950             }
1951             else {
1952                 lastModified = new Date();
1953             }
1954 
1955             final ZoneId zoneid = Context.getCurrentContext().getTimeZone().toZoneId();
1956             lastModified_ = LAST_MODIFIED_DATE_FORMATTER.format(lastModified.toInstant().atZone(zoneid));
1957         }
1958         return lastModified_;
1959     }
1960 
1961     private static Date parseDateOrNow(final String stringDate) {
1962         final Date date = HttpUtils.parseDate(stringDate);
1963         if (date == null) {
1964             return new Date();
1965         }
1966         return date;
1967     }
1968 
1969     /**
1970      * Mock for the moment.
1971      */
1972     @JsxFunction({FF, FF_ESR})
1973     public void releaseCapture() {
1974         // nothing to do
1975     }
1976 
1977     /**
1978      * Returns the ready state of the document.
1979      * @return the ready state of the document
1980      *
1981      * @see DomNode#READY_STATE_UNINITIALIZED
1982      * @see DomNode#READY_STATE_LOADING
1983      * @see DomNode#READY_STATE_LOADED
1984      * @see DomNode#READY_STATE_INTERACTIVE
1985      * @see DomNode#READY_STATE_COMPLETE
1986      */
1987     @JsxGetter
1988     public String getReadyState() {
1989         return getDomNodeOrDie().getReadyState();
1990     }
1991 
1992     /**
1993      * Does nothing special anymore.
1994      *
1995      * @param type the type of events to capture
1996      * @see Window#captureEvents(String)
1997      */
1998     @JsxFunction
1999     public void captureEvents(final String type) {
2000         // Empty.
2001     }
2002 
2003     /**
2004      * Does nothing special anymore.
2005      *
2006      * @param type the type of events to capture
2007      * @see Window#releaseEvents(String)
2008      */
2009     @JsxFunction
2010     public void releaseEvents(final String type) {
2011         // Empty.
2012     }
2013 
2014     /**
2015      * Returns the value of the {@code alinkColor} property.
2016      * @return the value of the {@code alinkColor} property
2017      */
2018     @JsxGetter
2019     public String getAlinkColor() {
2020         final HTMLElement body = getBody();
2021         if (body instanceof HTMLBodyElement element) {
2022             return element.getALink();
2023         }
2024         return null;
2025     }
2026 
2027     /**
2028      * Sets the value of the {@code alinkColor} property.
2029      * @param color the value of the {@code alinkColor} property
2030      */
2031     @JsxSetter
2032     public void setAlinkColor(final String color) {
2033         final HTMLElement body = getBody();
2034         if (body instanceof HTMLBodyElement element) {
2035             element.setALink(color);
2036         }
2037     }
2038 
2039     /**
2040      * Returns the value of the {@code bgColor} property.
2041      * @return the value of the {@code bgColor} property
2042      * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/Document/bgColor">MDN Documentation</a>
2043      */
2044     @JsxGetter
2045     public String getBgColor() {
2046         final HTMLElement body = getBody();
2047         if (body instanceof HTMLBodyElement element) {
2048             return element.getBgColor();
2049         }
2050         return null;
2051     }
2052 
2053     /**
2054      * Sets the value of the {@code bgColor} property.
2055      * @param color the value of the {@code bgColor} property
2056      * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/Document/bgColor">MDN Documentation</a>
2057      */
2058     @JsxSetter
2059     public void setBgColor(final String color) {
2060         final HTMLElement body = getBody();
2061         if (body instanceof HTMLBodyElement element) {
2062             element.setBgColor(color);
2063         }
2064     }
2065 
2066     /**
2067      * Returns the value of the {@code fgColor} property.
2068      * @return the value of the {@code fgColor} property
2069      */
2070     @JsxGetter
2071     public String getFgColor() {
2072         final HTMLElement body = getBody();
2073         if (body instanceof HTMLBodyElement element) {
2074             return element.getText();
2075         }
2076         return null;
2077     }
2078 
2079     /**
2080      * Sets the value of the {@code fgColor} property.
2081      * @param color the value of the {@code fgColor} property
2082      */
2083     @JsxSetter
2084     public void setFgColor(final String color) {
2085         final HTMLElement body = getBody();
2086         if (body instanceof HTMLBodyElement element) {
2087             element.setText(color);
2088         }
2089     }
2090 
2091     /**
2092      * Returns the value of the {@code linkColor} property.
2093      * @return the value of the {@code linkColor} property
2094      */
2095     @JsxGetter
2096     public String getLinkColor() {
2097         final HTMLElement body = getBody();
2098         if (body instanceof HTMLBodyElement element) {
2099             return element.getLink();
2100         }
2101         return null;
2102     }
2103 
2104     /**
2105      * Sets the value of the {@code linkColor} property.
2106      * @param color the value of the {@code linkColor} property
2107      */
2108     @JsxSetter
2109     public void setLinkColor(final String color) {
2110         final HTMLElement body = getBody();
2111         if (body instanceof HTMLBodyElement element) {
2112             element.setLink(color);
2113         }
2114     }
2115 
2116     /**
2117      * Returns the value of the {@code vlinkColor} property.
2118      * @return the value of the {@code vlinkColor} property
2119      */
2120     @JsxGetter
2121     public String getVlinkColor() {
2122         final HTMLElement body = getBody();
2123         if (body instanceof HTMLBodyElement element) {
2124             return element.getVLink();
2125         }
2126         return null;
2127     }
2128 
2129     /**
2130      * Sets the value of the {@code vlinkColor} property.
2131      * @param color the value of the {@code vlinkColor} property
2132      */
2133     @JsxSetter
2134     public void setVlinkColor(final String color) {
2135         final HTMLElement body = getBody();
2136         if (body instanceof HTMLBodyElement element) {
2137             element.setVLink(color);
2138         }
2139     }
2140 
2141     /**
2142      * {@inheritDoc}
2143      */
2144     @Override
2145     @JsxGetter
2146     public Element getLastElementChild() {
2147         return super.getLastElementChild();
2148     }
2149 
2150     /**
2151      * {@inheritDoc}
2152      */
2153     @Override
2154     @JsxGetter
2155     public Element getFirstElementChild() {
2156         return super.getFirstElementChild();
2157     }
2158 
2159     /**
2160      * Returns the {@code xmlEncoding} property.
2161      * @return the {@code xmlEncoding} property
2162      */
2163     @JsxGetter({CHROME, EDGE})
2164     public String getXmlEncoding() {
2165         return getPage().getXmlEncoding();
2166     }
2167 
2168     /**
2169      * Returns the {@code xmlStandalone} property.
2170      * @return the {@code xmlStandalone} property
2171      */
2172     @JsxGetter({CHROME, EDGE})
2173     public boolean isXmlStandalone() {
2174         return getPage().getXmlStandalone();
2175     }
2176 
2177     /**
2178      * Returns the {@code xmlVersion} property.
2179      * @return the {@code xmlVersion} property
2180      */
2181     @JsxGetter({CHROME, EDGE})
2182     public String getXmlVersion() {
2183         return getPage().getXmlVersion();
2184     }
2185 
2186     /**
2187      * Returns the {@code onabort} event handler for this element.
2188      * @return the {@code onabort} event handler for this element
2189      */
2190     @JsxGetter
2191     public Function getOnabort() {
2192         return getEventHandler(Event.TYPE_ABORT);
2193     }
2194 
2195     /**
2196      * Sets the {@code onabort} event handler for this element.
2197      * @param onabort the {@code onabort} event handler for this element
2198      */
2199     @JsxSetter
2200     public void setOnabort(final Object onabort) {
2201         setEventHandler(Event.TYPE_ABORT, onabort);
2202     }
2203 
2204     /**
2205      * Returns the {@code onauxclick} event handler for this element.
2206      * @return the {@code onauxclick} event handler for this element
2207      */
2208     @JsxGetter({CHROME, EDGE})
2209     public Function getOnauxclick() {
2210         return getEventHandler(Event.TYPE_AUXCLICK);
2211     }
2212 
2213     /**
2214      * Sets the {@code onauxclick} event handler for this element.
2215      * @param onauxclick the {@code onauxclick} event handler for this element
2216      */
2217     @JsxSetter({CHROME, EDGE})
2218     public void setOnauxclick(final Object onauxclick) {
2219         setEventHandler(Event.TYPE_AUXCLICK, onauxclick);
2220     }
2221 
2222     /**
2223      * Returns the {@code onbeforecopy} event handler for this element.
2224      * @return the {@code onbeforecopy} event handler for this element
2225      */
2226     @JsxGetter({CHROME, EDGE})
2227     public Function getOnbeforecopy() {
2228         return getEventHandler(Event.TYPE_BEFORECOPY);
2229     }
2230 
2231     /**
2232      * Sets the {@code onbeforecopy} event handler for this element.
2233      * @param onbeforecopy the {@code onbeforecopy} event handler for this element
2234      */
2235     @JsxSetter({CHROME, EDGE})
2236     public void setOnbeforecopy(final Object onbeforecopy) {
2237         setEventHandler(Event.TYPE_BEFORECOPY, onbeforecopy);
2238     }
2239 
2240     /**
2241      * Returns the {@code onbeforecut} event handler for this element.
2242      * @return the {@code onbeforecut} event handler for this element
2243      */
2244     @JsxGetter({CHROME, EDGE})
2245     public Function getOnbeforecut() {
2246         return getEventHandler(Event.TYPE_BEFORECUT);
2247     }
2248 
2249     /**
2250      * Sets the {@code onbeforecut} event handler for this element.
2251      * @param onbeforecut the {@code onbeforecut} event handler for this element
2252      */
2253     @JsxSetter({CHROME, EDGE})
2254     public void setOnbeforecut(final Object onbeforecut) {
2255         setEventHandler(Event.TYPE_BEFORECUT, onbeforecut);
2256     }
2257 
2258     /**
2259      * Returns the {@code onbeforepaste} event handler for this element.
2260      * @return the {@code onbeforepaste} event handler for this element
2261      */
2262     @JsxGetter({CHROME, EDGE})
2263     public Function getOnbeforepaste() {
2264         return getEventHandler(Event.TYPE_BEFOREPASTE);
2265     }
2266 
2267     /**
2268      * Sets the {@code onbeforepaste} event handler for this element.
2269      * @param onbeforepaste the {@code onbeforepaste} event handler for this element
2270      */
2271     @JsxSetter({CHROME, EDGE})
2272     public void setOnbeforepaste(final Object onbeforepaste) {
2273         setEventHandler(Event.TYPE_BEFOREPASTE, onbeforepaste);
2274     }
2275 
2276     /**
2277      * Returns the {@code oncancel} event handler for this element.
2278      * @return the {@code oncancel} event handler for this element
2279      */
2280     @JsxGetter({CHROME, EDGE})
2281     public Function getOncancel() {
2282         return getEventHandler(Event.TYPE_CANCEL);
2283     }
2284 
2285     /**
2286      * Sets the {@code oncancel} event handler for this element.
2287      * @param oncancel the {@code oncancel} event handler for this element
2288      */
2289     @JsxSetter({CHROME, EDGE})
2290     public void setOncancel(final Object oncancel) {
2291         setEventHandler(Event.TYPE_CANCEL, oncancel);
2292     }
2293 
2294     /**
2295      * Returns the {@code oncanplay} event handler for this element.
2296      * @return the {@code oncanplay} event handler for this element
2297      */
2298     @JsxGetter
2299     public Function getOncanplay() {
2300         return getEventHandler(Event.TYPE_CANPLAY);
2301     }
2302 
2303     /**
2304      * Sets the {@code oncanplay} event handler for this element.
2305      * @param oncanplay the {@code oncanplay} event handler for this element
2306      */
2307     @JsxSetter
2308     public void setOncanplay(final Object oncanplay) {
2309         setEventHandler(Event.TYPE_CANPLAY, oncanplay);
2310     }
2311 
2312     /**
2313      * Returns the {@code oncanplaythrough} event handler for this element.
2314      * @return the {@code oncanplaythrough} event handler for this element
2315      */
2316     @JsxGetter
2317     public Function getOncanplaythrough() {
2318         return getEventHandler(Event.TYPE_CANPLAYTHROUGH);
2319     }
2320 
2321     /**
2322      * Sets the {@code oncanplaythrough} event handler for this element.
2323      * @param oncanplaythrough the {@code oncanplaythrough} event handler for this element
2324      */
2325     @JsxSetter
2326     public void setOncanplaythrough(final Object oncanplaythrough) {
2327         setEventHandler(Event.TYPE_CANPLAYTHROUGH, oncanplaythrough);
2328     }
2329 
2330     /**
2331      * Returns the {@code onchange} event handler for this element.
2332      * @return the {@code onchange} event handler for this element
2333      */
2334     @JsxGetter
2335     public Function getOnchange() {
2336         return getEventHandler(Event.TYPE_CHANGE);
2337     }
2338 
2339     /**
2340      * Sets the {@code onchange} event handler for this element.
2341      * @param onchange the {@code onchange} event handler for this element
2342      */
2343     @JsxSetter
2344     public void setOnchange(final Object onchange) {
2345         setEventHandler(Event.TYPE_CHANGE, onchange);
2346     }
2347 
2348     /**
2349      * Returns the {@code onclose} event handler for this element.
2350      * @return the {@code onclose} event handler for this element
2351      */
2352     @JsxGetter({CHROME, EDGE})
2353     public Function getOnclose() {
2354         return getEventHandler(Event.TYPE_CLOSE);
2355     }
2356 
2357     /**
2358      * Sets the {@code onclose} event handler for this element.
2359      * @param onclose the {@code onclose} event handler for this element
2360      */
2361     @JsxSetter({CHROME, EDGE})
2362     public void setOnclose(final Object onclose) {
2363         setEventHandler(Event.TYPE_CLOSE, onclose);
2364     }
2365 
2366     /**
2367      * Returns the {@code oncopy} event handler for this element.
2368      * @return the {@code oncopy} event handler for this element
2369      */
2370     @JsxGetter
2371     public Function getOncopy() {
2372         return getEventHandler(Event.TYPE_COPY);
2373     }
2374 
2375     /**
2376      * Sets the {@code oncopy} event handler for this element.
2377      * @param oncopy the {@code oncopy} event handler for this element
2378      */
2379     @JsxSetter
2380     public void setOncopy(final Object oncopy) {
2381         setEventHandler(Event.TYPE_COPY, oncopy);
2382     }
2383 
2384     /**
2385      * Returns the {@code oncuechange} event handler for this element.
2386      * @return the {@code oncuechange} event handler for this element
2387      */
2388     @JsxGetter({CHROME, EDGE})
2389     public Function getOncuechange() {
2390         return getEventHandler(Event.TYPE_CUECHANGE);
2391     }
2392 
2393     /**
2394      * Sets the {@code oncuechange} event handler for this element.
2395      * @param oncuechange the {@code oncuechange} event handler for this element
2396      */
2397     @JsxSetter({CHROME, EDGE})
2398     public void setOncuechange(final Object oncuechange) {
2399         setEventHandler(Event.TYPE_CUECHANGE, oncuechange);
2400     }
2401 
2402     /**
2403      * Returns the {@code oncut} event handler for this element.
2404      * @return the {@code oncut} event handler for this element
2405      */
2406     @JsxGetter
2407     public Function getOncut() {
2408         return getEventHandler(Event.TYPE_CUT);
2409     }
2410 
2411     /**
2412      * Sets the {@code oncut} event handler for this element.
2413      * @param oncut the {@code oncut} event handler for this element
2414      */
2415     @JsxSetter
2416     public void setOncut(final Object oncut) {
2417         setEventHandler(Event.TYPE_CUT, oncut);
2418     }
2419 
2420     /**
2421      * Returns the {@code ondrag} event handler for this element.
2422      * @return the {@code ondrag} event handler for this element
2423      */
2424     @JsxGetter
2425     public Function getOndrag() {
2426         return getEventHandler(Event.TYPE_DRAG);
2427     }
2428 
2429     /**
2430      * Sets the {@code ondrag} event handler for this element.
2431      * @param ondrag the {@code ondrag} event handler for this element
2432      */
2433     @JsxSetter
2434     public void setOndrag(final Object ondrag) {
2435         setEventHandler(Event.TYPE_DRAG, ondrag);
2436     }
2437 
2438     /**
2439      * Returns the {@code ondragend} event handler for this element.
2440      * @return the {@code ondragend} event handler for this element
2441      */
2442     @JsxGetter
2443     public Function getOndragend() {
2444         return getEventHandler(Event.TYPE_DRAGEND);
2445     }
2446 
2447     /**
2448      * Sets the {@code ondragend} event handler for this element.
2449      * @param ondragend the {@code ondragend} event handler for this element
2450      */
2451     @JsxSetter
2452     public void setOndragend(final Object ondragend) {
2453         setEventHandler(Event.TYPE_DRAGEND, ondragend);
2454     }
2455 
2456     /**
2457      * Returns the {@code ondragenter} event handler for this element.
2458      * @return the {@code ondragenter} event handler for this element
2459      */
2460     @JsxGetter
2461     public Function getOndragenter() {
2462         return getEventHandler(Event.TYPE_DRAGENTER);
2463     }
2464 
2465     /**
2466      * Sets the {@code ondragenter} event handler for this element.
2467      * @param ondragenter the {@code ondragenter} event handler for this element
2468      */
2469     @JsxSetter
2470     public void setOndragenter(final Object ondragenter) {
2471         setEventHandler(Event.TYPE_DRAGENTER, ondragenter);
2472     }
2473 
2474     /**
2475      * Returns the {@code ondragleave} event handler for this element.
2476      * @return the {@code ondragleave} event handler for this element
2477      */
2478     @JsxGetter
2479     public Function getOndragleave() {
2480         return getEventHandler(Event.TYPE_DRAGLEAVE);
2481     }
2482 
2483     /**
2484      * Sets the {@code ondragleave} event handler for this element.
2485      * @param ondragleave the {@code ondragleave} event handler for this element
2486      */
2487     @JsxSetter
2488     public void setOndragleave(final Object ondragleave) {
2489         setEventHandler(Event.TYPE_DRAGLEAVE, ondragleave);
2490     }
2491 
2492     /**
2493      * Returns the {@code ondragover} event handler for this element.
2494      * @return the {@code ondragover} event handler for this element
2495      */
2496     @JsxGetter
2497     public Function getOndragover() {
2498         return getEventHandler(Event.TYPE_DRAGOVER);
2499     }
2500 
2501     /**
2502      * Sets the {@code ondragover} event handler for this element.
2503      * @param ondragover the {@code ondragover} event handler for this element
2504      */
2505     @JsxSetter
2506     public void setOndragover(final Object ondragover) {
2507         setEventHandler(Event.TYPE_DRAGOVER, ondragover);
2508     }
2509 
2510     /**
2511      * Returns the {@code ondragstart} event handler for this element.
2512      * @return the {@code ondragstart} event handler for this element
2513      */
2514     @JsxGetter
2515     public Function getOndragstart() {
2516         return getEventHandler(Event.TYPE_DRAGSTART);
2517     }
2518 
2519     /**
2520      * Sets the {@code ondragstart} event handler for this element.
2521      * @param ondragstart the {@code ondragstart} event handler for this element
2522      */
2523     @JsxSetter
2524     public void setOndragstart(final Object ondragstart) {
2525         setEventHandler(Event.TYPE_DRAGSTART, ondragstart);
2526     }
2527 
2528     /**
2529      * Returns the {@code ondrop} event handler for this element.
2530      * @return the {@code ondrop} event handler for this element
2531      */
2532     @JsxGetter
2533     public Function getOndrop() {
2534         return getEventHandler(Event.TYPE_DROP);
2535     }
2536 
2537     /**
2538      * Sets the {@code ondrop} event handler for this element.
2539      * @param ondrop the {@code ondrop} event handler for this element
2540      */
2541     @JsxSetter
2542     public void setOndrop(final Object ondrop) {
2543         setEventHandler(Event.TYPE_DROP, ondrop);
2544     }
2545 
2546     /**
2547      * Returns the {@code ondurationchange} event handler for this element.
2548      * @return the {@code ondurationchange} event handler for this element
2549      */
2550     @JsxGetter
2551     public Function getOndurationchange() {
2552         return getEventHandler(Event.TYPE_DURATIONCHANGE);
2553     }
2554 
2555     /**
2556      * Sets the {@code ondurationchange} event handler for this element.
2557      * @param ondurationchange the {@code ondurationchange} event handler for this element
2558      */
2559     @JsxSetter
2560     public void setOndurationchange(final Object ondurationchange) {
2561         setEventHandler(Event.TYPE_DURATIONCHANGE, ondurationchange);
2562     }
2563 
2564     /**
2565      * Returns the {@code onemptied} event handler for this element.
2566      * @return the {@code onemptied} event handler for this element
2567      */
2568     @JsxGetter
2569     public Function getOnemptied() {
2570         return getEventHandler(Event.TYPE_EMPTIED);
2571     }
2572 
2573     /**
2574      * Sets the {@code onemptied} event handler for this element.
2575      * @param onemptied the {@code onemptied} event handler for this element
2576      */
2577     @JsxSetter
2578     public void setOnemptied(final Object onemptied) {
2579         setEventHandler(Event.TYPE_EMPTIED, onemptied);
2580     }
2581 
2582     /**
2583      * Returns the {@code onended} event handler for this element.
2584      * @return the {@code onended} event handler for this element
2585      */
2586     @JsxGetter
2587     public Function getOnended() {
2588         return getEventHandler(Event.TYPE_ENDED);
2589     }
2590 
2591     /**
2592      * Sets the {@code onended} event handler for this element.
2593      * @param onended the {@code onended} event handler for this element
2594      */
2595     @JsxSetter
2596     public void setOnended(final Object onended) {
2597         setEventHandler(Event.TYPE_ENDED, onended);
2598     }
2599 
2600     /**
2601      * Returns the {@code ongotpointercapture} event handler for this element.
2602      * @return the {@code ongotpointercapture} event handler for this element
2603      */
2604     @JsxGetter({CHROME, EDGE})
2605     public Function getOngotpointercapture() {
2606         return getEventHandler(Event.TYPE_GOTPOINTERCAPTURE);
2607     }
2608 
2609     /**
2610      * Sets the {@code ongotpointercapture} event handler for this element.
2611      * @param ongotpointercapture the {@code ongotpointercapture} event handler for this element
2612      */
2613     @JsxSetter({CHROME, EDGE})
2614     public void setOngotpointercapture(final Object ongotpointercapture) {
2615         setEventHandler(Event.TYPE_GOTPOINTERCAPTURE, ongotpointercapture);
2616     }
2617 
2618     /**
2619      * Returns the {@code oninvalid} event handler for this element.
2620      * @return the {@code oninvalid} event handler for this element
2621      */
2622     @JsxGetter
2623     public Function getOninvalid() {
2624         return getEventHandler(Event.TYPE_INVALID);
2625     }
2626 
2627     /**
2628      * Sets the {@code oninvalid} event handler for this element.
2629      * @param oninvalid the {@code oninvalid} event handler for this element
2630      */
2631     @JsxSetter
2632     public void setOninvalid(final Object oninvalid) {
2633         setEventHandler(Event.TYPE_INVALID, oninvalid);
2634     }
2635 
2636     /**
2637      * Returns the {@code onload} event handler for this element.
2638      * @return the {@code onload} event handler for this element
2639      */
2640     @JsxGetter
2641     public Function getOnload() {
2642         return getEventHandler(Event.TYPE_LOAD);
2643     }
2644 
2645     /**
2646      * Sets the {@code onload} event handler for this element.
2647      * @param onload the {@code onload} event handler for this element
2648      */
2649     @JsxSetter
2650     public void setOnload(final Object onload) {
2651         setEventHandler(Event.TYPE_LOAD, onload);
2652     }
2653 
2654     /**
2655      * Returns the {@code onloadeddata} event handler for this element.
2656      * @return the {@code onloadeddata} event handler for this element
2657      */
2658     @JsxGetter
2659     public Function getOnloadeddata() {
2660         return getEventHandler(Event.TYPE_LOADEDDATA);
2661     }
2662 
2663     /**
2664      * Sets the {@code onloadeddata} event handler for this element.
2665      * @param onloadeddata the {@code onloadeddata} event handler for this element
2666      */
2667     @JsxSetter
2668     public void setOnloadeddata(final Object onloadeddata) {
2669         setEventHandler(Event.TYPE_LOADEDDATA, onloadeddata);
2670     }
2671 
2672     /**
2673      * Returns the {@code onloadedmetadata} event handler for this element.
2674      * @return the {@code onloadedmetadata} event handler for this element
2675      */
2676     @JsxGetter
2677     public Function getOnloadedmetadata() {
2678         return getEventHandler(Event.TYPE_LOADEDMETADATA);
2679     }
2680 
2681     /**
2682      * Sets the {@code onloadedmetadata} event handler for this element.
2683      * @param onloadedmetadata the {@code onloadedmetadata} event handler for this element
2684      */
2685     @JsxSetter
2686     public void setOnloadedmetadata(final Object onloadedmetadata) {
2687         setEventHandler(Event.TYPE_LOADEDMETADATA, onloadedmetadata);
2688     }
2689 
2690     /**
2691      * Returns the {@code onloadstart} event handler for this element.
2692      * @return the {@code onloadstart} event handler for this element
2693      */
2694     @JsxGetter
2695     public Function getOnloadstart() {
2696         return getEventHandler(Event.TYPE_LOAD_START);
2697     }
2698 
2699     /**
2700      * Sets the {@code onloadstart} event handler for this element.
2701      * @param onloadstart the {@code onloadstart} event handler for this element
2702      */
2703     @JsxSetter
2704     public void setOnloadstart(final Object onloadstart) {
2705         setEventHandler(Event.TYPE_LOAD_START, onloadstart);
2706     }
2707 
2708     /**
2709      * Returns the {@code onlostpointercapture} event handler for this element.
2710      * @return the {@code onlostpointercapture} event handler for this element
2711      */
2712     @JsxGetter({CHROME, EDGE})
2713     public Function getOnlostpointercapture() {
2714         return getEventHandler(Event.TYPE_LOSTPOINTERCAPTURE);
2715     }
2716 
2717     /**
2718      * Sets the {@code onlostpointercapture} event handler for this element.
2719      * @param onlostpointercapture the {@code onlostpointercapture} event handler for this element
2720      */
2721     @JsxSetter({CHROME, EDGE})
2722     public void setOnlostpointercapture(final Object onlostpointercapture) {
2723         setEventHandler(Event.TYPE_LOSTPOINTERCAPTURE, onlostpointercapture);
2724     }
2725 
2726     /**
2727      * Returns the {@code onmouseenter} event handler for this element.
2728      * @return the {@code onmouseenter} event handler for this element
2729      */
2730     @JsxGetter
2731     public Function getOnmouseenter() {
2732         return getEventHandler(Event.TYPE_MOUDEENTER);
2733     }
2734 
2735     /**
2736      * Sets the {@code onmouseenter} event handler for this element.
2737      * @param onmouseenter the {@code onmouseenter} event handler for this element
2738      */
2739     @JsxSetter
2740     public void setOnmouseenter(final Object onmouseenter) {
2741         setEventHandler(Event.TYPE_MOUDEENTER, onmouseenter);
2742     }
2743 
2744     /**
2745      * Returns the {@code onmouseleave} event handler for this element.
2746      * @return the {@code onmouseleave} event handler for this element
2747      */
2748     @JsxGetter
2749     public Function getOnmouseleave() {
2750         return getEventHandler(Event.TYPE_MOUSELEAVE);
2751     }
2752 
2753     /**
2754      * Sets the {@code onmouseleave} event handler for this element.
2755      * @param onmouseleave the {@code onmouseleave} event handler for this element
2756      */
2757     @JsxSetter
2758     public void setOnmouseleave(final Object onmouseleave) {
2759         setEventHandler(Event.TYPE_MOUSELEAVE, onmouseleave);
2760     }
2761 
2762     /**
2763      * Returns the {@code onmousewheel} event handler for this element.
2764      * @return the {@code onmousewheel} event handler for this element
2765      */
2766     @JsxGetter({CHROME, EDGE})
2767     public Function getOnmousewheel() {
2768         return getEventHandler(Event.TYPE_MOUSEWHEEL);
2769     }
2770 
2771     /**
2772      * Sets the {@code onmousewheel} event handler for this element.
2773      * @param onmousewheel the {@code onmousewheel} event handler for this element
2774      */
2775     @JsxSetter({CHROME, EDGE})
2776     public void setOnmousewheel(final Object onmousewheel) {
2777         setEventHandler(Event.TYPE_MOUSEWHEEL, onmousewheel);
2778     }
2779 
2780     /**
2781      * Returns the {@code onpaste} event handler for this element.
2782      * @return the {@code onpaste} event handler for this element
2783      */
2784     @JsxGetter
2785     public Function getOnpaste() {
2786         return getEventHandler(Event.TYPE_PASTE);
2787     }
2788 
2789     /**
2790      * Sets the {@code onpaste} event handler for this element.
2791      * @param onpaste the {@code onpaste} event handler for this element
2792      */
2793     @JsxSetter
2794     public void setOnpaste(final Object onpaste) {
2795         setEventHandler(Event.TYPE_PASTE, onpaste);
2796     }
2797 
2798     /**
2799      * Returns the {@code onpause} event handler for this element.
2800      * @return the {@code onpause} event handler for this element
2801      */
2802     @JsxGetter
2803     public Function getOnpause() {
2804         return getEventHandler(Event.TYPE_PAUSE);
2805     }
2806 
2807     /**
2808      * Sets the {@code onpause} event handler for this element.
2809      * @param onpause the {@code onpause} event handler for this element
2810      */
2811     @JsxSetter
2812     public void setOnpause(final Object onpause) {
2813         setEventHandler(Event.TYPE_PAUSE, onpause);
2814     }
2815 
2816     /**
2817      * Returns the {@code onplay} event handler for this element.
2818      * @return the {@code onplay} event handler for this element
2819      */
2820     @JsxGetter
2821     public Function getOnplay() {
2822         return getEventHandler(Event.TYPE_PLAY);
2823     }
2824 
2825     /**
2826      * Sets the {@code onplay} event handler for this element.
2827      * @param onplay the {@code onplay} event handler for this element
2828      */
2829     @JsxSetter
2830     public void setOnplay(final Object onplay) {
2831         setEventHandler(Event.TYPE_PLAY, onplay);
2832     }
2833 
2834     /**
2835      * Returns the {@code onplaying} event handler for this element.
2836      * @return the {@code onplaying} event handler for this element
2837      */
2838     @JsxGetter
2839     public Function getOnplaying() {
2840         return getEventHandler(Event.TYPE_PLAYING);
2841     }
2842 
2843     /**
2844      * Sets the {@code onplaying} event handler for this element.
2845      * @param onplaying the {@code onplaying} event handler for this element
2846      */
2847     @JsxSetter
2848     public void setOnplaying(final Object onplaying) {
2849         setEventHandler(Event.TYPE_PLAYING, onplaying);
2850     }
2851 
2852     /**
2853      * Returns the {@code onpointercancel} event handler for this element.
2854      * @return the {@code onpointercancel} event handler for this element
2855      */
2856     @JsxGetter({CHROME, EDGE})
2857     public Function getOnpointercancel() {
2858         return getEventHandler(Event.TYPE_POINTERCANCEL);
2859     }
2860 
2861     /**
2862      * Sets the {@code onpointercancel} event handler for this element.
2863      * @param onpointercancel the {@code onpointercancel} event handler for this element
2864      */
2865     @JsxSetter({CHROME, EDGE})
2866     public void setOnpointercancel(final Object onpointercancel) {
2867         setEventHandler(Event.TYPE_POINTERCANCEL, onpointercancel);
2868     }
2869 
2870     /**
2871      * Returns the {@code onpointerdown} event handler for this element.
2872      * @return the {@code onpointerdown} event handler for this element
2873      */
2874     @JsxGetter({CHROME, EDGE})
2875     public Function getOnpointerdown() {
2876         return getEventHandler(Event.TYPE_POINTERDOWN);
2877     }
2878 
2879     /**
2880      * Sets the {@code onpointerdown} event handler for this element.
2881      * @param onpointerdown the {@code onpointerdown} event handler for this element
2882      */
2883     @JsxSetter({CHROME, EDGE})
2884     public void setOnpointerdown(final Object onpointerdown) {
2885         setEventHandler(Event.TYPE_POINTERDOWN, onpointerdown);
2886     }
2887 
2888     /**
2889      * Returns the {@code onpointerenter} event handler for this element.
2890      * @return the {@code onpointerenter} event handler for this element
2891      */
2892     @JsxGetter({CHROME, EDGE})
2893     public Function getOnpointerenter() {
2894         return getEventHandler(Event.TYPE_POINTERENTER);
2895     }
2896 
2897     /**
2898      * Sets the {@code onpointerenter} event handler for this element.
2899      * @param onpointerenter the {@code onpointerenter} event handler for this element
2900      */
2901     @JsxSetter({CHROME, EDGE})
2902     public void setOnpointerenter(final Object onpointerenter) {
2903         setEventHandler(Event.TYPE_POINTERENTER, onpointerenter);
2904     }
2905 
2906     /**
2907      * Returns the {@code onpointerleave} event handler for this element.
2908      * @return the {@code onpointerleave} event handler for this element
2909      */
2910     @JsxGetter({CHROME, EDGE})
2911     public Function getOnpointerleave() {
2912         return getEventHandler(Event.TYPE_POINTERLEAVE);
2913     }
2914 
2915     /**
2916      * Sets the {@code onpointerleave} event handler for this element.
2917      * @param onpointerleave the {@code onpointerleave} event handler for this element
2918      */
2919     @JsxSetter({CHROME, EDGE})
2920     public void setOnpointerleave(final Object onpointerleave) {
2921         setEventHandler(Event.TYPE_POINTERLEAVE, onpointerleave);
2922     }
2923 
2924     /**
2925      * Returns the {@code onpointerlockchange} event handler for this element.
2926      * @return the {@code onpointerlockchange} event handler for this element
2927      */
2928     @JsxGetter({CHROME, EDGE})
2929     public Function getOnpointerlockchange() {
2930         return getEventHandler(Event.TYPE_POINTERLOCKCHANGE);
2931     }
2932 
2933     /**
2934      * Sets the {@code onpointerlockchange} event handler for this element.
2935      * @param onpointerlockchange the {@code onpointerlockchange} event handler for this element
2936      */
2937     @JsxSetter({CHROME, EDGE})
2938     public void setOnpointerlockchange(final Object onpointerlockchange) {
2939         setEventHandler(Event.TYPE_POINTERLOCKCHANGE, onpointerlockchange);
2940     }
2941 
2942     /**
2943      * Returns the {@code onpointerlockerror} event handler for this element.
2944      * @return the {@code onpointerlockerror} event handler for this element
2945      */
2946     @JsxGetter({CHROME, EDGE})
2947     public Function getOnpointerlockerror() {
2948         return getEventHandler(Event.TYPE_POINTERLOCKERROR);
2949     }
2950 
2951     /**
2952      * Sets the {@code onpointerlockerror} event handler for this element.
2953      * @param onpointerlockerror the {@code onpointerlockerror} event handler for this element
2954      */
2955     @JsxSetter({CHROME, EDGE})
2956     public void setOnpointerlockerror(final Object onpointerlockerror) {
2957         setEventHandler(Event.TYPE_POINTERLOCKERROR, onpointerlockerror);
2958     }
2959 
2960     /**
2961      * Returns the {@code onpointermove} event handler for this element.
2962      * @return the {@code onpointermove} event handler for this element
2963      */
2964     @JsxGetter({CHROME, EDGE})
2965     public Function getOnpointermove() {
2966         return getEventHandler(Event.TYPE_POINTERMOVE);
2967     }
2968 
2969     /**
2970      * Sets the {@code onpointermove} event handler for this element.
2971      * @param onpointermove the {@code onpointermove} event handler for this element
2972      */
2973     @JsxSetter({CHROME, EDGE})
2974     public void setOnpointermove(final Object onpointermove) {
2975         setEventHandler(Event.TYPE_POINTERMOVE, onpointermove);
2976     }
2977 
2978     /**
2979      * Returns the {@code onpointerout} event handler for this element.
2980      * @return the {@code onpointerout} event handler for this element
2981      */
2982     @JsxGetter({CHROME, EDGE})
2983     public Function getOnpointerout() {
2984         return getEventHandler(Event.TYPE_POINTEROUT);
2985     }
2986 
2987     /**
2988      * Sets the {@code onpointerout} event handler for this element.
2989      * @param onpointerout the {@code onpointerout} event handler for this element
2990      */
2991     @JsxSetter({CHROME, EDGE})
2992     public void setOnpointerout(final Object onpointerout) {
2993         setEventHandler(Event.TYPE_POINTEROUT, onpointerout);
2994     }
2995 
2996     /**
2997      * Returns the {@code onpointerover} event handler for this element.
2998      * @return the {@code onpointerover} event handler for this element
2999      */
3000     @JsxGetter({CHROME, EDGE})
3001     public Function getOnpointerover() {
3002         return getEventHandler(Event.TYPE_POINTEROVER);
3003     }
3004 
3005     /**
3006      * Sets the {@code onpointerover} event handler for this element.
3007      * @param onpointerover the {@code onpointerover} event handler for this element
3008      */
3009     @JsxSetter({CHROME, EDGE})
3010     public void setOnpointerover(final Object onpointerover) {
3011         setEventHandler(Event.TYPE_POINTEROVER, onpointerover);
3012     }
3013 
3014     /**
3015      * Returns the {@code onpointerup} event handler for this element.
3016      * @return the {@code onpointerup} event handler for this element
3017      */
3018     @JsxGetter({CHROME, EDGE})
3019     public Function getOnpointerup() {
3020         return getEventHandler(Event.TYPE_POINTERUP);
3021     }
3022 
3023     /**
3024      * Sets the {@code onpointerup} event handler for this element.
3025      * @param onpointerup the {@code onpointerup} event handler for this element
3026      */
3027     @JsxSetter({CHROME, EDGE})
3028     public void setOnpointerup(final Object onpointerup) {
3029         setEventHandler(Event.TYPE_POINTERUP, onpointerup);
3030     }
3031 
3032     /**
3033      * Returns the {@code onprogress} event handler for this element.
3034      * @return the {@code onprogress} event handler for this element
3035      */
3036     @JsxGetter
3037     public Function getOnprogress() {
3038         return getEventHandler(Event.TYPE_PROGRESS);
3039     }
3040 
3041     /**
3042      * Sets the {@code onprogress} event handler for this element.
3043      * @param onprogress the {@code onprogress} event handler for this element
3044      */
3045     @JsxSetter
3046     public void setOnprogress(final Object onprogress) {
3047         setEventHandler(Event.TYPE_PROGRESS, onprogress);
3048     }
3049 
3050     /**
3051      * Returns the {@code onratechange} event handler for this element.
3052      * @return the {@code onratechange} event handler for this element
3053      */
3054     @JsxGetter
3055     public Function getOnratechange() {
3056         return getEventHandler(Event.TYPE_RATECHANGE);
3057     }
3058 
3059     /**
3060      * Sets the {@code onratechange} event handler for this element.
3061      * @param onratechange the {@code onratechange} event handler for this element
3062      */
3063     @JsxSetter
3064     public void setOnratechange(final Object onratechange) {
3065         setEventHandler(Event.TYPE_RATECHANGE, onratechange);
3066     }
3067 
3068     /**
3069      * Returns the {@code onreadystatechange} event handler for this element.
3070      * @return the {@code onreadystatechange} event handler for this element
3071      */
3072     @JsxGetter
3073     public Function getOnreadystatechange() {
3074         return getEventHandler(Event.TYPE_READY_STATE_CHANGE);
3075     }
3076 
3077     /**
3078      * Sets the {@code onreadystatechange} event handler for this element.
3079      * @param onreadystatechange the {@code onreadystatechange} event handler for this element
3080      */
3081     @JsxSetter
3082     public void setOnreadystatechange(final Object onreadystatechange) {
3083         setEventHandler(Event.TYPE_READY_STATE_CHANGE, onreadystatechange);
3084     }
3085 
3086     /**
3087      * Returns the {@code onreset} event handler for this element.
3088      * @return the {@code onreset} event handler for this element
3089      */
3090     @JsxGetter
3091     public Function getOnreset() {
3092         return getEventHandler(Event.TYPE_RESET);
3093     }
3094 
3095     /**
3096      * Sets the {@code onreset} event handler for this element.
3097      * @param onreset the {@code onreset} event handler for this element
3098      */
3099     @JsxSetter
3100     public void setOnreset(final Object onreset) {
3101         setEventHandler(Event.TYPE_RESET, onreset);
3102     }
3103 
3104     /**
3105      * Returns the {@code onscroll} event handler for this element.
3106      * @return the {@code onscroll} event handler for this element
3107      */
3108     @JsxGetter
3109     public Function getOnscroll() {
3110         return getEventHandler(Event.TYPE_SCROLL);
3111     }
3112 
3113     /**
3114      * Sets the {@code onscroll} event handler for this element.
3115      * @param onscroll the {@code onscroll} event handler for this element
3116      */
3117     @JsxSetter
3118     public void setOnscroll(final Object onscroll) {
3119         setEventHandler(Event.TYPE_SCROLL, onscroll);
3120     }
3121 
3122     /**
3123      * Returns the {@code onsearch} event handler for this element.
3124      * @return the {@code onsearch} event handler for this element
3125      */
3126     @JsxGetter({CHROME, EDGE})
3127     public Function getOnsearch() {
3128         return getEventHandler(Event.TYPE_SEARCH);
3129     }
3130 
3131     /**
3132      * Sets the {@code onsearch} event handler for this element.
3133      * @param onsearch the {@code onsearch} event handler for this element
3134      */
3135     @JsxSetter({CHROME, EDGE})
3136     public void setOnsearch(final Object onsearch) {
3137         setEventHandler(Event.TYPE_SEARCH, onsearch);
3138     }
3139 
3140     /**
3141      * Returns the {@code onseeked} event handler for this element.
3142      * @return the {@code onseeked} event handler for this element
3143      */
3144     @JsxGetter
3145     public Function getOnseeked() {
3146         return getEventHandler(Event.TYPE_SEEKED);
3147     }
3148 
3149     /**
3150      * Sets the {@code onseeked} event handler for this element.
3151      * @param onseeked the {@code onseeked} event handler for this element
3152      */
3153     @JsxSetter
3154     public void setOnseeked(final Object onseeked) {
3155         setEventHandler(Event.TYPE_SEEKED, onseeked);
3156     }
3157 
3158     /**
3159      * Returns the {@code onseeking} event handler for this element.
3160      * @return the {@code onseeking} event handler for this element
3161      */
3162     @JsxGetter
3163     public Function getOnseeking() {
3164         return getEventHandler(Event.TYPE_SEEKING);
3165     }
3166 
3167     /**
3168      * Sets the {@code onseeking} event handler for this element.
3169      * @param onseeking the {@code onseeking} event handler for this element
3170      */
3171     @JsxSetter
3172     public void setOnseeking(final Object onseeking) {
3173         setEventHandler(Event.TYPE_SEEKING, onseeking);
3174     }
3175 
3176     /**
3177      * Returns the {@code onselect} event handler for this element.
3178      * @return the {@code onselect} event handler for this element
3179      */
3180     @JsxGetter
3181     public Function getOnselect() {
3182         return getEventHandler(Event.TYPE_SELECT);
3183     }
3184 
3185     /**
3186      * Sets the {@code onselect} event handler for this element.
3187      * @param onselect the {@code onselect} event handler for this element
3188      */
3189     @JsxSetter
3190     public void setOnselect(final Object onselect) {
3191         setEventHandler(Event.TYPE_SELECT, onselect);
3192     }
3193 
3194     /**
3195      * Returns the {@code onselectionchange} event handler for this element.
3196      * @return the {@code onselectionchange} event handler for this element
3197      */
3198     @JsxGetter({CHROME, EDGE})
3199     public Function getOnselectionchange() {
3200         return getEventHandler(Event.TYPE_SELECTIONCHANGE);
3201     }
3202 
3203     /**
3204      * Sets the {@code onselectionchange} event handler for this element.
3205      * @param onselectionchange the {@code onselectionchange} event handler for this element
3206      */
3207     @JsxSetter({CHROME, EDGE})
3208     public void setOnselectionchange(final Object onselectionchange) {
3209         setEventHandler(Event.TYPE_SELECTIONCHANGE, onselectionchange);
3210     }
3211 
3212     /**
3213      * Returns the {@code onselectstart} event handler for this element.
3214      * @return the {@code onselectstart} event handler for this element
3215      */
3216     @JsxGetter
3217     public Function getOnselectstart() {
3218         return getEventHandler(Event.TYPE_SELECTSTART);
3219     }
3220 
3221     /**
3222      * Sets the {@code onselectstart} event handler for this element.
3223      * @param onselectstart the {@code onselectstart} event handler for this element
3224      */
3225     @JsxSetter
3226     public void setOnselectstart(final Object onselectstart) {
3227         setEventHandler(Event.TYPE_SELECTSTART, onselectstart);
3228     }
3229 
3230     /**
3231      * Returns the {@code onstalled} event handler for this element.
3232      * @return the {@code onstalled} event handler for this element
3233      */
3234     @JsxGetter
3235     public Function getOnstalled() {
3236         return getEventHandler(Event.TYPE_STALLED);
3237     }
3238 
3239     /**
3240      * Sets the {@code onstalled} event handler for this element.
3241      * @param onstalled the {@code onstalled} event handler for this element
3242      */
3243     @JsxSetter
3244     public void setOnstalled(final Object onstalled) {
3245         setEventHandler(Event.TYPE_STALLED, onstalled);
3246     }
3247 
3248     /**
3249      * Returns the {@code onsubmit} event handler for this element.
3250      * @return the {@code onsubmit} event handler for this element
3251      */
3252     @JsxGetter
3253     public Function getOnsubmit() {
3254         return getEventHandler(Event.TYPE_SUBMIT);
3255     }
3256 
3257     /**
3258      * Sets the {@code onsubmit} event handler for this element.
3259      * @param onsubmit the {@code onsubmit} event handler for this element
3260      */
3261     @JsxSetter
3262     public void setOnsubmit(final Object onsubmit) {
3263         setEventHandler(Event.TYPE_SUBMIT, onsubmit);
3264     }
3265 
3266     /**
3267      * Returns the {@code onsuspend} event handler for this element.
3268      * @return the {@code onsuspend} event handler for this element
3269      */
3270     @JsxGetter
3271     public Function getOnsuspend() {
3272         return getEventHandler(Event.TYPE_SUSPEND);
3273     }
3274 
3275     /**
3276      * Sets the {@code onsuspend} event handler for this element.
3277      * @param onsuspend the {@code onsuspend} event handler for this element
3278      */
3279     @JsxSetter
3280     public void setOnsuspend(final Object onsuspend) {
3281         setEventHandler(Event.TYPE_SUSPEND, onsuspend);
3282     }
3283 
3284     /**
3285      * Returns the {@code ontimeupdate} event handler for this element.
3286      * @return the {@code ontimeupdate} event handler for this element
3287      */
3288     @JsxGetter
3289     public Function getOntimeupdate() {
3290         return getEventHandler(Event.TYPE_TIMEUPDATE);
3291     }
3292 
3293     /**
3294      * Sets the {@code ontimeupdate} event handler for this element.
3295      * @param ontimeupdate the {@code ontimeupdate} event handler for this element
3296      */
3297     @JsxSetter
3298     public void setOntimeupdate(final Object ontimeupdate) {
3299         setEventHandler(Event.TYPE_TIMEUPDATE, ontimeupdate);
3300     }
3301 
3302     /**
3303      * Returns the {@code ontoggle} event handler for this element.
3304      * @return the {@code ontoggle} event handler for this element
3305      */
3306     @JsxGetter({CHROME, EDGE})
3307     public Function getOntoggle() {
3308         return getEventHandler(Event.TYPE_TOGGLE);
3309     }
3310 
3311     /**
3312      * Sets the {@code ontoggle} event handler for this element.
3313      * @param ontoggle the {@code ontoggle} event handler for this element
3314      */
3315     @JsxSetter({CHROME, EDGE})
3316     public void setOntoggle(final Object ontoggle) {
3317         setEventHandler(Event.TYPE_TOGGLE, ontoggle);
3318     }
3319 
3320     /**
3321      * Returns the {@code onvolumechange} event handler for this element.
3322      * @return the {@code onvolumechange} event handler for this element
3323      */
3324     @JsxGetter
3325     public Function getOnvolumechange() {
3326         return getEventHandler(Event.TYPE_VOLUMECHANGE);
3327     }
3328 
3329     /**
3330      * Sets the {@code onvolumechange} event handler for this element.
3331      * @param onvolumechange the {@code onvolumechange} event handler for this element
3332      */
3333     @JsxSetter
3334     public void setOnvolumechange(final Object onvolumechange) {
3335         setEventHandler(Event.TYPE_VOLUMECHANGE, onvolumechange);
3336     }
3337 
3338     /**
3339      * Returns the {@code onwaiting} event handler for this element.
3340      * @return the {@code onwaiting} event handler for this element
3341      */
3342     @JsxGetter
3343     public Function getOnwaiting() {
3344         return getEventHandler(Event.TYPE_WAITING);
3345     }
3346 
3347     /**
3348      * Sets the {@code onwaiting} event handler for this element.
3349      * @param onwaiting the {@code onwaiting} event handler for this element
3350      */
3351     @JsxSetter
3352     public void setOnwaiting(final Object onwaiting) {
3353         setEventHandler(Event.TYPE_WAITING, onwaiting);
3354     }
3355 
3356     /**
3357      * Returns the {@code onwebkitfullscreenchange} event handler for this element.
3358      * @return the {@code onwebkitfullscreenchange} event handler for this element
3359      */
3360     @JsxGetter({CHROME, EDGE})
3361     public Function getOnwebkitfullscreenchange() {
3362         return getEventHandler(Event.TYPE_WEBKITFULLSCREENCHANGE);
3363     }
3364 
3365     /**
3366      * Sets the {@code onwebkitfullscreenchange} event handler for this element.
3367      * @param onwebkitfullscreenchange the {@code onwebkitfullscreenchange} event handler for this element
3368      */
3369     @JsxSetter({CHROME, EDGE})
3370     public void setOnwebkitfullscreenchange(final Object onwebkitfullscreenchange) {
3371         setEventHandler(Event.TYPE_WEBKITFULLSCREENCHANGE, onwebkitfullscreenchange);
3372     }
3373 
3374     /**
3375      * Returns the {@code onwebkitfullscreenerror} event handler for this element.
3376      * @return the {@code onwebkitfullscreenerror} event handler for this element
3377      */
3378     @JsxGetter({CHROME, EDGE})
3379     public Function getOnwebkitfullscreenerror() {
3380         return getEventHandler(Event.TYPE_WEBKITFULLSCREENERROR);
3381     }
3382 
3383     /**
3384      * Sets the {@code onwebkitfullscreenerror} event handler for this element.
3385      * @param onwebkitfullscreenerror the {@code onwebkitfullscreenerror} event handler for this element
3386      */
3387     @JsxSetter
3388     public void setOnwebkitfullscreenerror(final Object onwebkitfullscreenerror) {
3389         setEventHandler(Event.TYPE_WEBKITFULLSCREENERROR, onwebkitfullscreenerror);
3390     }
3391 
3392     /**
3393      * Returns the {@code onwheel} event handler for this element.
3394      * @return the {@code onwheel} event handler for this element
3395      */
3396     @JsxGetter
3397     public Function getOnwheel() {
3398         return getEventHandler(Event.TYPE_WHEEL);
3399     }
3400 
3401     /**
3402      * Sets the {@code onwheel} event handler for this element.
3403      * @param onwheel the {@code onwheel} event handler for this element
3404      */
3405     @JsxSetter
3406     public void setOnwheel(final Object onwheel) {
3407         setEventHandler(Event.TYPE_WHEEL, onwheel);
3408     }
3409 
3410     /**
3411      * Returns the {@code onafterscriptexecute} event handler for this element.
3412      * @return the {@code onafterscriptexecute} event handler for this element
3413      */
3414     @JsxGetter({FF, FF_ESR})
3415     public Function getOnafterscriptexecute() {
3416         return getEventHandler(Event.TYPE_AFTERSCRIPTEXECUTE);
3417     }
3418 
3419     /**
3420      * Sets the {@code onafterscriptexecute} event handler for this element.
3421      * @param onafterscriptexecute the {@code onafterscriptexecute} event handler for this element
3422      */
3423     @JsxSetter({FF, FF_ESR})
3424     public void setOnafterscriptexecute(final Object onafterscriptexecute) {
3425         setEventHandler(Event.TYPE_AFTERSCRIPTEXECUTE, onafterscriptexecute);
3426     }
3427 
3428     /**
3429      * Returns the {@code onbeforescriptexecute} event handler for this element.
3430      * @return the {@code onbeforescriptexecute} event handler for this element
3431      */
3432     @JsxGetter({FF, FF_ESR})
3433     public Function getOnbeforescriptexecute() {
3434         return getEventHandler(Event.TYPE_BEFORESCRIPTEXECUTE);
3435     }
3436 
3437     /**
3438      * Sets the {@code onbeforescriptexecute} event handler for this element.
3439      * @param onbeforescriptexecute the {@code onbeforescriptexecute} event handler for this element
3440      */
3441     @JsxSetter({FF, FF_ESR})
3442     public void setOnbeforescriptexecute(final Object onbeforescriptexecute) {
3443         setEventHandler(Event.TYPE_BEFORESCRIPTEXECUTE, onbeforescriptexecute);
3444     }
3445 
3446     /**
3447      * Returns the {@code onmozfullscreenchange} event handler for this element.
3448      * @return the {@code onmozfullscreenchange} event handler for this element
3449      */
3450     @JsxGetter({FF, FF_ESR})
3451     public Function getOnmozfullscreenchange() {
3452         return getEventHandler(Event.TYPE_MOZFULLSCREENCHANGE);
3453     }
3454 
3455     /**
3456      * Sets the {@code onmozfullscreenchange} event handler for this element.
3457      * @param onmozfullscreenchange the {@code onmozfullscreenchange} event handler for this element
3458      */
3459     @JsxSetter({FF, FF_ESR})
3460     public void setOnmozfullscreenchange(final Object onmozfullscreenchange) {
3461         setEventHandler(Event.TYPE_MOZFULLSCREENCHANGE, onmozfullscreenchange);
3462     }
3463 
3464     /**
3465      * Returns the {@code onmozfullscreenerror} event handler for this element.
3466      * @return the {@code onmozfullscreenerror} event handler for this element
3467      */
3468     @JsxGetter({FF, FF_ESR})
3469     public Function getOnmozfullscreenerror() {
3470         return getEventHandler(Event.TYPE_MOZFULLSCREENERROR);
3471     }
3472 
3473     /**
3474      * Sets the {@code onmozfullscreenerror} event handler for this element.
3475      * @param onmozfullscreenerror the {@code onmozfullscreenerror} event handler for this element
3476      */
3477     @JsxSetter({FF, FF_ESR})
3478     public void setOnmozfullscreenerror(final Object onmozfullscreenerror) {
3479         setEventHandler(Event.TYPE_MOZFULLSCREENERROR, onmozfullscreenerror);
3480     }
3481 
3482     /**
3483      * Returns the {@code currentScript} property.
3484      * @return the {@code currentScript}
3485      */
3486     @JsxGetter
3487     public ScriptableObject getCurrentScript() {
3488         return currentScript_;
3489     }
3490 
3491     /**
3492      * Sets the {@code currentScript} property.
3493      * @param script the {@code currentScript}
3494      */
3495     public void setCurrentScript(final ScriptableObject script) {
3496         currentScript_ = script;
3497     }
3498 
3499     /**
3500      * Returns the {@code FontFaceSet} property.
3501      * @return the {@code FontFaceSet}
3502      */
3503     @JsxGetter
3504     public ScriptableObject getFonts() {
3505         if (fonts_ == null) {
3506             final FontFaceSet fonts = new FontFaceSet();
3507             fonts.setParentScope(getParentScope());
3508             fonts.setPrototype(getPrototype(fonts.getClass()));
3509             fonts_ = fonts;
3510         }
3511         return fonts_;
3512     }
3513 
3514     /**
3515      * Returns the value of the {@code all} property.
3516      * @return the value of the {@code all} property
3517      */
3518     @JsxGetter
3519     public HTMLAllCollection getAll() {
3520         final HTMLAllCollection all = new HTMLAllCollection(getDomNodeOrDie());
3521         all.setAvoidObjectDetection(true);
3522         all.setIsMatchingPredicate((Predicate<DomNode> & Serializable) node -> true);
3523         return all;
3524     }
3525 
3526     /**
3527      * Returns the element with the specified ID, as long as it is an HTML element; {@code null} otherwise.
3528      * @param id the ID to search for
3529      * @return the element with the specified ID, as long as it is an HTML element; {@code null} otherwise
3530      */
3531     @JsxFunction
3532     public HtmlUnitScriptable getElementById(final String id) {
3533         final DomNode domNode = getDomNodeOrDie();
3534         for (final DomElement descendant : domNode.getDomElementDescendants()) {
3535             if (id.equals(descendant.getId())) {
3536                 return descendant.getScriptableObject();
3537             }
3538         }
3539         return null;
3540     }
3541 
3542     /**
3543      * Creates a new ProcessingInstruction.
3544      * @param context the JavaScript context
3545      * @param scope the scope
3546      * @param thisObj the scriptable
3547      * @param args the arguments passed into the method: target and data
3548      * @param function the function
3549      * @return the new ProcessingInstruction
3550      */
3551     @JsxFunction
3552     public static HtmlUnitScriptable createProcessingInstruction(final Context context, final VarScope scope,
3553             final Scriptable thisObj, final Object[] args, final Function function) {
3554         if (args.length < 2) {
3555             throw JavaScriptEngine.typeError("Failed to execute 'createProcessingInstruction' on 'Document': "
3556                     + "2 arguments required, but only " + args.length + " present.");
3557         }
3558 
3559         final Document document = (Document) thisObj;
3560         final String target = JavaScriptEngine.toString(args[0]);
3561         final String data = JavaScriptEngine.toString(args[1]);
3562 
3563         if (data.contains("?>") || !isValidProcessingInstructionTarget(target)) {
3564             throw JavaScriptEngine.asJavaScriptException(
3565                     document.getWindow(),
3566                     "createProcessingInstruction: Provided string contains an invalid character",
3567                     org.htmlunit.javascript.host.dom.DOMException.INVALID_CHARACTER_ERR);
3568         }
3569 
3570         final ProcessingInstruction node = document.getPage().createProcessingInstruction(target, data);
3571         return document.getScriptableFor(node);
3572     }
3573 
3574     // the XML Name production, simplified in the same way as it is done for createElement:
3575     // only the ASCII range is checked
3576     private static boolean isValidProcessingInstructionTarget(final String target) {
3577         if (target.isEmpty()) {
3578             return false;
3579         }
3580 
3581         final int first = target.charAt(0);
3582         if (first < 128 && !Character.isLetter(first) && first != ':' && first != '_') {
3583             return false;
3584         }
3585 
3586         final int length = target.length();
3587         for (int i = 1; i < length; i++) {
3588             final int c = target.charAt(i);
3589             if (c < 128 && !Character.isLetterOrDigit(c) && c != ':' && c != '_' && c != '-' && c != '.') {
3590                 return false;
3591             }
3592         }
3593         return true;
3594     }
3595 
3596     /**
3597      * Creates a new createCDATASection.
3598      * @param data the data
3599      * @return the new CDATASection
3600      */
3601     @JsxFunction
3602     public HtmlUnitScriptable createCDATASection(final String data) {
3603         final SgmlPage page = getPage();
3604         // https://dom.spec.whatwg.org/#dom-document-createcdatasection
3605         if (page instanceof HtmlPage && !(page instanceof XHtmlPage)) {
3606             throw JavaScriptEngine.asJavaScriptException(
3607                     getWindow(),
3608                     "createCDATASection: not supported for HTML documents",
3609                     org.htmlunit.javascript.host.dom.DOMException.NOT_SUPPORTED_ERR);
3610         }
3611         final CDATASection node = page.createCDATASection(data);
3612         return getScriptableFor(node);
3613     }
3614 
3615     /**
3616      * Does... nothing.
3617      * @see <a href="https://developer.mozilla.org/en/DOM/document.clear">Mozilla doc</a>
3618      */
3619     @JsxFunction
3620     public void clear() {
3621         // nothing
3622     }
3623 
3624     /**
3625      * {@inheritDoc}
3626      */
3627     @JsxFunction
3628     @Override
3629     public boolean contains(final Object element) {
3630         return getDocumentElement().contains(element);
3631     }
3632 }