View Javadoc
1   /*
2    * Copyright (c) 2002-2017 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    * http://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 com.gargoylesoftware.htmlunit.javascript.host;
16  
17  import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_BOUNDINGCLIENTRECT_THROWS_IF_DISCONNECTED;
18  import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_ELEMENT_GET_ATTRIBUTE_RETURNS_EMPTY;
19  import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_INNER_HTML_ADD_CHILD_FOR_NULL_VALUE;
20  import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_INNER_TEXT_CR_NL;
21  import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_OUTER_HTML_NULL_AS_STRING;
22  import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_OUTER_HTML_REMOVES_CHILDREN_FOR_DETACHED;
23  import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_OUTER_HTML_THROWS_FOR_DETACHED;
24  import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.QUERYSELECTORALL_NOT_IN_QUIRKS;
25  import static com.gargoylesoftware.htmlunit.html.DomElement.ATTRIBUTE_NOT_DEFINED;
26  import static com.gargoylesoftware.htmlunit.javascript.configuration.SupportedBrowser.CHROME;
27  import static com.gargoylesoftware.htmlunit.javascript.configuration.SupportedBrowser.EDGE;
28  import static com.gargoylesoftware.htmlunit.javascript.configuration.SupportedBrowser.FF;
29  import static com.gargoylesoftware.htmlunit.javascript.configuration.SupportedBrowser.FF52;
30  import static com.gargoylesoftware.htmlunit.javascript.configuration.SupportedBrowser.IE;
31  
32  import java.io.IOException;
33  import java.util.HashMap;
34  import java.util.Locale;
35  import java.util.Map;
36  import java.util.Objects;
37  import java.util.regex.Pattern;
38  
39  import org.apache.commons.logging.LogFactory;
40  import org.w3c.css.sac.CSSException;
41  import org.xml.sax.SAXException;
42  
43  import com.gargoylesoftware.htmlunit.html.DomAttr;
44  import com.gargoylesoftware.htmlunit.html.DomCharacterData;
45  import com.gargoylesoftware.htmlunit.html.DomComment;
46  import com.gargoylesoftware.htmlunit.html.DomElement;
47  import com.gargoylesoftware.htmlunit.html.DomNode;
48  import com.gargoylesoftware.htmlunit.html.DomText;
49  import com.gargoylesoftware.htmlunit.html.HTMLParser;
50  import com.gargoylesoftware.htmlunit.html.HtmlElement;
51  import com.gargoylesoftware.htmlunit.html.HtmlElement.DisplayStyle;
52  import com.gargoylesoftware.htmlunit.javascript.NamedNodeMap;
53  import com.gargoylesoftware.htmlunit.javascript.configuration.JsxClass;
54  import com.gargoylesoftware.htmlunit.javascript.configuration.JsxConstructor;
55  import com.gargoylesoftware.htmlunit.javascript.configuration.JsxFunction;
56  import com.gargoylesoftware.htmlunit.javascript.configuration.JsxGetter;
57  import com.gargoylesoftware.htmlunit.javascript.configuration.JsxSetter;
58  import com.gargoylesoftware.htmlunit.javascript.host.css.CSSStyleDeclaration;
59  import com.gargoylesoftware.htmlunit.javascript.host.css.ComputedCSSStyleDeclaration;
60  import com.gargoylesoftware.htmlunit.javascript.host.dom.Attr;
61  import com.gargoylesoftware.htmlunit.javascript.host.dom.DOMTokenList;
62  import com.gargoylesoftware.htmlunit.javascript.host.dom.Document;
63  import com.gargoylesoftware.htmlunit.javascript.host.dom.Node;
64  import com.gargoylesoftware.htmlunit.javascript.host.dom.NodeList;
65  import com.gargoylesoftware.htmlunit.javascript.host.dom.TextRange;
66  import com.gargoylesoftware.htmlunit.javascript.host.event.EventHandler;
67  import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLCollection;
68  import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLDocument;
69  import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLElement;
70  import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLElement.ProxyDomNode;
71  import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLScriptElement;
72  import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLStyleElement;
73  
74  import net.sourceforge.htmlunit.corejs.javascript.BaseFunction;
75  import net.sourceforge.htmlunit.corejs.javascript.Context;
76  import net.sourceforge.htmlunit.corejs.javascript.Function;
77  import net.sourceforge.htmlunit.corejs.javascript.FunctionObject;
78  import net.sourceforge.htmlunit.corejs.javascript.ScriptRuntime;
79  import net.sourceforge.htmlunit.corejs.javascript.Scriptable;
80  
81  /**
82   * A JavaScript object for {@code Element}.
83   *
84   * @author Ahmed Ashour
85   * @author Marc Guillemot
86   * @author Sudhan Moghe
87   * @author Ronald Brill
88   * @author Frank Danek
89   */
90  @JsxClass(domClass = DomElement.class)
91  public class Element extends Node {
92  
93      static final String POSITION_BEFORE_BEGIN = "beforebegin";
94      static final String POSITION_AFTER_BEGIN = "afterbegin";
95      static final String POSITION_BEFORE_END = "beforeend";
96      static final String POSITION_AFTER_END = "afterend";
97  
98      private static final Pattern CLASS_NAMES_SPLIT_PATTERN = Pattern.compile("\\s");
99      private static final Pattern PRINT_NODE_PATTERN = Pattern.compile("  ");
100     private static final Pattern PRINT_NODE_QUOTE_PATTERN = Pattern.compile("\"");
101 
102     private NamedNodeMap attributes_;
103     private Map<String, HTMLCollection> elementsByTagName_; // for performance and for equality (==)
104     private int scrollLeft_;
105     private int scrollTop_;
106     private CSSStyleDeclaration style_;
107 
108     /**
109      * Default constructor.
110      */
111     @JsxConstructor({CHROME, FF, EDGE})
112     public Element() {
113         // Empty.
114     }
115 
116     /**
117      * Sets the DOM node that corresponds to this JavaScript object.
118      * @param domNode the DOM node
119      */
120     @Override
121     public void setDomNode(final DomNode domNode) {
122         super.setDomNode(domNode);
123 
124         style_ = new CSSStyleDeclaration(this);
125 
126         setParentScope(getWindow().getDocument());
127 
128         /**
129          * Convert JavaScript snippets defined in the attribute map to executable event handlers.
130          * Should be called only on construction.
131          */
132         final DomElement htmlElt = (DomElement) domNode;
133         for (final DomAttr attr : htmlElt.getAttributesMap().values()) {
134             final String eventName = attr.getName().toLowerCase(Locale.ROOT);
135             if (eventName.startsWith("on")) {
136                 createEventHandler(eventName.substring(2), attr.getValue());
137             }
138         }
139     }
140 
141     /**
142      * Create the event handler function from the attribute value.
143      * @param eventName the event name (ex: "onclick")
144      * @param attrValue the attribute value
145      */
146     protected void createEventHandler(final String eventName, final String attrValue) {
147         final DomElement htmlElt = getDomNodeOrDie();
148         // TODO: check that it is an "allowed" event for the browser, and take care to the case
149         final BaseFunction eventHandler = new EventHandler(htmlElt, eventName, attrValue);
150         setEventHandler(eventName, eventHandler);
151     }
152 
153     /**
154      * Returns the tag name of this element.
155      * @return the tag name
156      */
157     @JsxGetter
158     public String getTagName() {
159         return getNodeName();
160     }
161 
162     /**
163      * Returns the attributes of this XML element.
164      * @see <a href="https://developer.mozilla.org/en-US/docs/DOM/Node.attributes">Gecko DOM Reference</a>
165      * @return the attributes of this XML element
166      */
167     @Override
168     @JsxGetter
169     public NamedNodeMap getAttributes() {
170         if (attributes_ == null) {
171             attributes_ = createAttributesObject();
172         }
173         return attributes_;
174     }
175 
176     /**
177      * Creates the JS object for the property attributes. This object will the be cached.
178      * @return the JS object
179      */
180     protected NamedNodeMap createAttributesObject() {
181         return new NamedNodeMap(getDomNodeOrDie());
182     }
183 
184     /**
185      * Returns the value of the specified attribute.
186      * @param attributeName attribute name
187      * @param flags IE-specific flags (see the MSDN documentation for more info)
188      * @return the value of the specified attribute, {@code null} if the attribute is not defined
189      * @see <a href="http://msdn.microsoft.com/en-us/library/ms536429.aspx">MSDN Documentation</a>
190      * @see <a href="http://reference.sitepoint.com/javascript/Element/getAttribute">IE Bug Documentation</a>
191      */
192     @JsxFunction
193     public String getAttribute(final String attributeName, final Integer flags) {
194         String value = getDomNodeOrDie().getAttribute(attributeName);
195 
196         if (value == ATTRIBUTE_NOT_DEFINED) {
197             value = null;
198         }
199 
200         return value;
201     }
202 
203     /**
204      * Sets an attribute.
205      *
206      * @param name Name of the attribute to set
207      * @param value Value to set the attribute to
208      */
209     @JsxFunction
210     public void setAttribute(final String name, final String value) {
211         getDomNodeOrDie().setAttribute(name, value);
212     }
213 
214     /**
215      * Returns all the descendant elements with the specified tag name.
216      * @param tagName the name to search for
217      * @return all the descendant elements with the specified tag name
218      */
219     @JsxFunction
220     public HTMLCollection getElementsByTagName(final String tagName) {
221         final String tagNameLC = tagName.toLowerCase(Locale.ROOT);
222 
223         if (elementsByTagName_ == null) {
224             elementsByTagName_ = new HashMap<>();
225         }
226 
227         HTMLCollection collection = elementsByTagName_.get(tagNameLC);
228         if (collection != null) {
229             return collection;
230         }
231 
232         final DomNode node = getDomNodeOrDie();
233         if ("*".equals(tagName)) {
234             collection = new HTMLCollection(node, false) {
235                 @Override
236                 protected boolean isMatching(final DomNode nodeToMatch) {
237                     return true;
238                 }
239             };
240         }
241         else {
242             collection = new HTMLCollection(node, false) {
243                 @Override
244                 protected boolean isMatching(final DomNode nodeToMatch) {
245                     return tagNameLC.equalsIgnoreCase(nodeToMatch.getNodeName());
246                 }
247             };
248         }
249 
250         elementsByTagName_.put(tagName, collection);
251 
252         return collection;
253     }
254 
255     /**
256      * Retrieves an attribute node by name.
257      * @param name the name of the attribute to retrieve
258      * @return the XMLAttr node with the specified name or {@code null} if there is no such attribute
259      */
260     @JsxFunction
261     public Object getAttributeNode(final String name) {
262         final Map<String, DomAttr> attributes = getDomNodeOrDie().getAttributesMap();
263         for (final DomAttr attr : attributes.values()) {
264             if (attr.getName().equals(name)) {
265                 return attr.getScriptableObject();
266             }
267         }
268         return null;
269     }
270 
271     /**
272      * Returns a list of elements with the given tag name belonging to the given namespace.
273      * @param namespaceURI the namespace URI of elements to look for
274      * @param localName is either the local name of elements to look for or the special value "*",
275      *                  which matches all elements.
276      * @return a live NodeList of found elements in the order they appear in the tree
277      */
278     @JsxFunction
279     public Object getElementsByTagNameNS(final Object namespaceURI, final String localName) {
280         final HTMLCollection collection = new HTMLCollection(getDomNodeOrDie(), false) {
281             @Override
282             protected boolean isMatching(final DomNode node) {
283                 return ("*".equals(namespaceURI) || Objects.equals(namespaceURI, node.getNamespaceURI()))
284                         && ("*".equals(localName) || Objects.equals(localName, node.getLocalName()));
285             }
286         };
287 
288         return collection;
289     }
290 
291     /**
292      * Returns true when an attribute with a given name is specified on this element or has a default value.
293      * See also <a href="http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-ElHasAttr">
294      * the DOM reference</a>
295      * @param name the name of the attribute to look for
296      * @return true if an attribute with the given name is specified on this element or has a default value
297      */
298     @JsxFunction
299     public boolean hasAttribute(final String name) {
300         return getDomNodeOrDie().hasAttribute(name);
301     }
302 
303     /**
304      * {@inheritDoc}
305      */
306     @Override
307     @JsxFunction({CHROME, FF})
308     public boolean hasAttributes() {
309         return super.hasAttributes();
310     }
311 
312     /**
313      * {@inheritDoc}
314      */
315     @Override
316     public DomElement getDomNodeOrDie() {
317         return (DomElement) super.getDomNodeOrDie();
318     }
319 
320     /**
321      * Removes the specified attribute.
322      * @param name the name of the attribute to remove
323      */
324     @JsxFunction
325     public void removeAttribute(final String name) {
326         getDomNodeOrDie().removeAttribute(name);
327     }
328 
329     /**
330      * Retrieves an object that specifies the bounds of a collection of TextRectangle objects.
331      * @see <a href="http://msdn.microsoft.com/en-us/library/ms536433.aspx">MSDN doc</a>
332      * @return an object that specifies the bounds of a collection of TextRectangle objects
333      */
334     @JsxFunction
335     public ClientRect getBoundingClientRect() {
336         if (!getDomNodeOrDie().isAttachedToPage()
337                 && getBrowserVersion().hasFeature(JS_BOUNDINGCLIENTRECT_THROWS_IF_DISCONNECTED)) {
338             throw Context.reportRuntimeError("Element is not attache to a page");
339         }
340 
341         final ClientRect textRectangle = new ClientRect(1, 1, 1, 1);
342         textRectangle.setParentScope(getWindow());
343         textRectangle.setPrototype(getPrototype(textRectangle.getClass()));
344         return textRectangle;
345     }
346 
347     /**
348      * {@inheritDoc}
349      */
350     @Override
351     @JsxGetter
352     public int getChildElementCount() {
353         return getDomNodeOrDie().getChildElementCount();
354     }
355 
356     /**
357      * {@inheritDoc}
358      */
359     @Override
360     @JsxGetter
361     public Element getFirstElementChild() {
362         return super.getFirstElementChild();
363     }
364 
365     /**
366      * {@inheritDoc}
367      */
368     @Override
369     @JsxGetter
370     public Element getLastElementChild() {
371         return super.getLastElementChild();
372     }
373 
374     /**
375      * Returns the next element sibling.
376      * @return the next element sibling
377      */
378     @JsxGetter
379     public Element getNextElementSibling() {
380         final DomElement child = getDomNodeOrDie().getNextElementSibling();
381         if (child != null) {
382             return (Element) child.getScriptableObject();
383         }
384         return null;
385     }
386 
387     /**
388      * Returns the previous element sibling.
389      * @return the previous element sibling
390      */
391     @JsxGetter
392     public Element getPreviousElementSibling() {
393         final DomElement child = getDomNodeOrDie().getPreviousElementSibling();
394         if (child != null) {
395             return (Element) child.getScriptableObject();
396         }
397         return null;
398     }
399 
400     /**
401      * Gets the first ancestor instance of {@link Element}. It is mostly identical
402      * to {@link #getParent()} except that it skips non {@link Element} nodes.
403      * @return the parent element
404      * @see #getParent()
405      */
406     @Override
407     public Element getParentElement() {
408         Node parent = getParent();
409         while (parent != null && !(parent instanceof Element)) {
410             parent = parent.getParent();
411         }
412         return (Element) parent;
413     }
414 
415     /**
416      * Callback method which allows different HTML element types to perform custom
417      * initialization of computed styles. For example, body elements in most browsers
418      * have default values for their margins.
419      *
420      * @param style the style to initialize
421      */
422     public void setDefaults(final ComputedCSSStyleDeclaration style) {
423         // Empty by default; override as necessary.
424     }
425 
426     /**
427      * {@inheritDoc}
428      */
429     @Override
430     @JsxGetter({CHROME, FF})
431     public HTMLCollection getChildren() {
432         return super.getChildren();
433     }
434 
435     /**
436      * Gets the token list of class attribute.
437      * @return the token list of class attribute
438      */
439     @JsxGetter({CHROME, FF})
440     public DOMTokenList getClassList() {
441         return new DOMTokenList(this, "class");
442     }
443 
444     /**
445      * Gets the specified attribute.
446      * @param namespaceURI the namespace URI
447      * @param localName the local name of the attribute to look for
448      * @return the value of the specified attribute, {@code null} if the attribute is not defined
449      */
450     @JsxFunction
451     public String getAttributeNS(final String namespaceURI, final String localName) {
452         final String value = getDomNodeOrDie().getAttributeNS(namespaceURI, localName);
453         if (ATTRIBUTE_NOT_DEFINED == value
454                 && !getBrowserVersion().hasFeature(JS_ELEMENT_GET_ATTRIBUTE_RETURNS_EMPTY)) {
455             return null;
456         }
457         return value;
458     }
459 
460     /**
461      * Test for attribute.
462      * See also <a href="http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-ElHasAttrNS">
463      * the DOM reference</a>
464      *
465      * @param namespaceURI the namespace URI
466      * @param localName the local name of the attribute to look for
467      * @return {@code true} if the node has this attribute
468      */
469     @JsxFunction
470     public boolean hasAttributeNS(final String namespaceURI, final String localName) {
471         return getDomNodeOrDie().hasAttributeNS(namespaceURI, localName);
472     }
473 
474     /**
475      * Sets the specified attribute.
476      * @param namespaceURI the namespace URI
477      * @param qualifiedName the qualified name of the attribute to look for
478      * @param value the new attribute value
479      */
480     @JsxFunction
481     public void setAttributeNS(final String namespaceURI, final String qualifiedName, final String value) {
482         getDomNodeOrDie().setAttributeNS(namespaceURI, qualifiedName, value);
483     }
484 
485     /**
486      * Removes the specified attribute.
487      * @param namespaceURI the namespace URI of the attribute to remove
488      * @param localName the local name of the attribute to remove
489      */
490     @JsxFunction
491     public void removeAttributeNS(final String namespaceURI, final String localName) {
492         getDomNodeOrDie().removeAttributeNS(namespaceURI, localName);
493     }
494 
495     /**
496      * Sets the attribute node for the specified attribute.
497      * @param newAtt the attribute to set
498      * @return the replaced attribute node, if any
499      */
500     @JsxFunction
501     public Attr setAttributeNode(final Attr newAtt) {
502         final String name = newAtt.getName();
503 
504         final NamedNodeMap nodes = getAttributes();
505         final Attr replacedAtt = (Attr) nodes.getNamedItemWithoutSytheticClassAttr(name);
506         if (replacedAtt != null) {
507             replacedAtt.detachFromParent();
508         }
509 
510         final DomAttr newDomAttr = newAtt.getDomNodeOrDie();
511         getDomNodeOrDie().setAttributeNode(newDomAttr);
512         return replacedAtt;
513     }
514 
515     /**
516      * {@inheritDoc}
517      */
518     @Override
519     public Object get(final String name, final Scriptable start) {
520         final Object response = super.get(name, start);
521 
522         // IE support .querySelector(All) but not in quirks mode
523         // => TODO: find a better way to handle this!
524         if (response instanceof FunctionObject
525                 && ("querySelectorAll".equals(name) || "querySelector".equals(name))
526                 && getBrowserVersion().hasFeature(QUERYSELECTORALL_NOT_IN_QUIRKS)) {
527             final Document doc = getWindow().getDocument();
528             if (doc instanceof HTMLDocument && ((HTMLDocument) doc).getDocumentMode() < 8) {
529                 return NOT_FOUND;
530             }
531         }
532 
533         return response;
534     }
535 
536     /**
537      * Retrieves all element nodes from descendants of the starting element node that match any selector
538      * within the supplied selector strings.
539      * The NodeList object returned by the querySelectorAll() method must be static, not live.
540      * @param selectors the selectors
541      * @return the static node list
542      */
543     @JsxFunction
544     public NodeList querySelectorAll(final String selectors) {
545         try {
546             return NodeList.staticNodeList(this, getDomNodeOrDie().querySelectorAll(selectors));
547         }
548         catch (final CSSException e) {
549             throw Context.reportRuntimeError("An invalid or illegal selector was specified (selector: '"
550                     + selectors + "' error: " + e.getMessage() + ").");
551         }
552     }
553 
554     /**
555      * Returns the first element within the document that matches the specified group of selectors.
556      * @param selectors the selectors
557      * @return null if no matches are found; otherwise, it returns the first matching element
558      */
559     @JsxFunction
560     public Node querySelector(final String selectors) {
561         try {
562             final DomNode node = getDomNodeOrDie().querySelector(selectors);
563             if (node != null) {
564                 return (Node) node.getScriptableObject();
565             }
566             return null;
567         }
568         catch (final CSSException e) {
569             throw Context.reportRuntimeError("An invalid or illegal selector was specified (selector: '"
570                     + selectors + "' error: " + e.getMessage() + ").");
571         }
572     }
573 
574     /**
575      * Returns the class defined for this element.
576      * @return the class name
577      */
578     @JsxGetter(propertyName = "className", value = {CHROME, FF})
579     public Object getClassName_js() {
580         return getDomNodeOrDie().getAttribute("class");
581     }
582 
583     /**
584      * Sets the class attribute for this element.
585      * @param className the new class name
586      */
587     @JsxSetter(propertyName = "className", value = {CHROME, FF})
588     public void setClassName_js(final String className) {
589         getDomNodeOrDie().setAttribute("class", className);
590     }
591 
592     /**
593      * Returns the {@code clientHeight} attribute.
594      * @return the {@code clientHeight} attribute
595      */
596     @JsxGetter
597     public int getClientHeight() {
598         final ComputedCSSStyleDeclaration style = getWindow().getComputedStyle(this, null);
599         return style.getCalculatedHeight(false, true);
600     }
601 
602     /**
603      * Returns the {@code clientWidth} attribute.
604      * @return the {@code clientWidth} attribute
605      */
606     @JsxGetter
607     public int getClientWidth() {
608         final ComputedCSSStyleDeclaration style = getWindow().getComputedStyle(this, null);
609         return style.getCalculatedWidth(false, true);
610     }
611 
612     /**
613      * Returns the {@code clientLeft} attribute.
614      * @return the {@code clientLeft} attribute
615      */
616     @JsxGetter
617     public int getClientLeft() {
618         final ComputedCSSStyleDeclaration style = getWindow().getComputedStyle(this, null);
619         return style.getBorderLeftValue();
620     }
621 
622     /**
623      * Returns {@code clientTop} attribute.
624      * @return the {@code clientTop} attribute
625      */
626     @JsxGetter
627     public int getClientTop() {
628         final ComputedCSSStyleDeclaration style = getWindow().getComputedStyle(this, null);
629         return style.getBorderTopValue();
630     }
631 
632     /**
633      * Returns the specified attribute.
634      * @param namespaceURI the namespace URI
635      * @param localName the local name of the attribute to look for
636      * @return the specified attribute, {@code null} if the attribute is not defined
637      */
638     @JsxFunction
639     public Object getAttributeNodeNS(final String namespaceURI, final String localName) {
640         return getDomNodeOrDie().getAttributeNodeNS(namespaceURI, localName).getScriptableObject();
641     }
642 
643     /**
644      * Returns all the descendant elements with the specified class.
645      * @param className the name to search for
646      * @return all the descendant elements with the specified class name
647      */
648     @JsxFunction({CHROME, FF})
649     public HTMLCollection getElementsByClassName(final String className) {
650         final DomElement elt = getDomNodeOrDie();
651         final String[] classNames = CLASS_NAMES_SPLIT_PATTERN.split(className, 0);
652 
653         final HTMLCollection collection = new HTMLCollection(elt, true) {
654             @Override
655             protected boolean isMatching(final DomNode node) {
656                 if (!(node instanceof HtmlElement)) {
657                     return false;
658                 }
659                 String classAttribute = ((HtmlElement) node).getAttribute("class");
660                 if (classAttribute == DomElement.ATTRIBUTE_NOT_DEFINED) {
661                     return false; // probably better performance as most of elements won't have a class attribute
662                 }
663 
664                 classAttribute = " " + classAttribute + " ";
665                 for (final String aClassName : classNames) {
666                     if (!classAttribute.contains(" " + aClassName + " ")) {
667                         return false;
668                     }
669                 }
670                 return true;
671             }
672         };
673 
674         return collection;
675     }
676 
677     /**
678      * Retrieves a collection of rectangles that describes the layout of the contents of an object
679      * or range within the client. Each rectangle describes a single line.
680      * @return a collection of rectangles that describes the layout of the contents
681      */
682     @JsxFunction
683     public ClientRectList getClientRects() {
684         final ClientRectList rectList = new ClientRectList();
685         rectList.setParentScope(getWindow());
686         rectList.setPrototype(getPrototype(rectList.getClass()));
687 
688         if (!isDisplayNone() && getDomNodeOrDie().isAttachedToPage()) {
689             final ClientRect rect = new ClientRect(0, 0, 1, 1);
690             rect.setParentScope(getWindow());
691             rect.setPrototype(getPrototype(rect.getClass()));
692             rectList.add(rect);
693         }
694 
695         return rectList;
696     }
697 
698     /**
699      * Returns whether the {@code display} is {@code none} or not.
700      * @return whether the {@code display} is {@code none} or not
701      */
702     protected final boolean isDisplayNone() {
703         Element element = this;
704         while (element != null) {
705             final CSSStyleDeclaration style = element.getWindow().getComputedStyle(element, null);
706             final String display = style.getDisplay();
707             if (DisplayStyle.NONE.value().equals(display)) {
708                 return true;
709             }
710             element = element.getParentElement();
711         }
712         return false;
713     }
714 
715     /**
716      * Creates a new TextRange object for this element.
717      * @return a new TextRange object for this element
718      */
719     protected TextRange createTextRange() {
720         final TextRange range = new TextRange(this);
721         range.setParentScope(getParentScope());
722         range.setPrototype(getPrototype(range.getClass()));
723         return range;
724     }
725 
726     /**
727      * Inserts the given element into the element at the location.
728      * @param where specifies where to insert the element, using one of the following values (case-insensitive):
729      *        beforebegin, afterbegin, beforeend, afterend
730      * @param insertedElement the element to be inserted
731      * @return an element object
732      *
733      * @see <a href="http://msdn.microsoft.com/en-us/library/ie/ms536451.aspx">MSDN</a>
734      */
735     @JsxFunction({CHROME, FF52})
736     public Object insertAdjacentElement(final String where, final Object insertedElement) {
737         if (insertedElement instanceof Node) {
738             final DomNode childNode = ((Node) insertedElement).getDomNodeOrDie();
739             final Object[] values = getInsertAdjacentLocation(where);
740             final DomNode node = (DomNode) values[0];
741             final boolean append = ((Boolean) values[1]).booleanValue();
742 
743             if (append) {
744                 node.appendChild(childNode);
745             }
746             else {
747                 node.insertBefore(childNode);
748             }
749             return insertedElement;
750         }
751         throw Context.reportRuntimeError("Passed object is not an element: " + insertedElement);
752     }
753 
754     /**
755      * Inserts the given text into the element at the specified location.
756      * @param where specifies where to insert the text, using one of the following values (case-insensitive):
757      *      beforebegin, afterbegin, beforeend, afterend
758      * @param text the text to insert
759      *
760      * @see <a href="http://msdn.microsoft.com/en-us/library/ie/ms536453.aspx">MSDN</a>
761      */
762     @JsxFunction({CHROME, FF52})
763     public void insertAdjacentText(final String where, final String text) {
764         final Object[] values = getInsertAdjacentLocation(where);
765         final DomNode node = (DomNode) values[0];
766         final boolean append = ((Boolean) values[1]).booleanValue();
767 
768         final DomText domText = new DomText(node.getPage(), text);
769         // add the new nodes
770         if (append) {
771             node.appendChild(domText);
772         }
773         else {
774             node.insertBefore(domText);
775         }
776     }
777 
778     /**
779      * Returns where and how to add the new node.
780      * Used by {@link #insertAdjacentHTML(String, String)},
781      * {@link #insertAdjacentElement(String, Object)} and
782      * {@link #insertAdjacentText(String, String)}.
783      * @param where specifies where to insert the element, using one of the following values (case-insensitive):
784      *        beforebegin, afterbegin, beforeend, afterend
785      * @return an array of 1-DomNode:parentNode and 2-Boolean:append
786      */
787     private Object[] getInsertAdjacentLocation(final String where) {
788         final DomNode currentNode = getDomNodeOrDie();
789         final DomNode node;
790         final boolean append;
791 
792         // compute the where and how the new nodes should be added
793         if (POSITION_AFTER_BEGIN.equalsIgnoreCase(where)) {
794             if (currentNode.getFirstChild() == null) {
795                 // new nodes should appended to the children of current node
796                 node = currentNode;
797                 append = true;
798             }
799             else {
800                 // new nodes should be inserted before first child
801                 node = currentNode.getFirstChild();
802                 append = false;
803             }
804         }
805         else if (POSITION_BEFORE_BEGIN.equalsIgnoreCase(where)) {
806             // new nodes should be inserted before current node
807             node = currentNode;
808             append = false;
809         }
810         else if (POSITION_BEFORE_END.equalsIgnoreCase(where)) {
811             // new nodes should appended to the children of current node
812             node = currentNode;
813             append = true;
814         }
815         else if (POSITION_AFTER_END.equalsIgnoreCase(where)) {
816             if (currentNode.getNextSibling() == null) {
817                 // new nodes should appended to the children of parent node
818                 node = currentNode.getParentNode();
819                 append = true;
820             }
821             else {
822                 // new nodes should be inserted before current node's next sibling
823                 node = currentNode.getNextSibling();
824                 append = false;
825             }
826         }
827         else {
828             throw Context.reportRuntimeError("Illegal position value: \"" + where + "\"");
829         }
830 
831         if (append) {
832             return new Object[] {node, Boolean.TRUE};
833         }
834         return new Object[] {node, Boolean.FALSE};
835     }
836 
837     /**
838      * Parses the given text as HTML or XML and inserts the resulting nodes into the tree in the position given by the
839      * position argument.
840      * @param position specifies where to insert the nodes, using one of the following values (case-insensitive):
841      *        <code>beforebegin</code>, <code>afterbegin</code>, <code>beforeend</code>, <code>afterend</code>
842      * @param text the text to parse
843      *
844      * @see <a href="http://www.w3.org/TR/DOM-Parsing/#methods-2">W3C Spec</a>
845      * @see <a href="http://domparsing.spec.whatwg.org/#dom-element-insertadjacenthtml">WhatWG Spec</a>
846      * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/Element.insertAdjacentHTML"
847      *      >Mozilla Developer Network</a>
848      * @see <a href="http://msdn.microsoft.com/en-us/library/ie/ms536452.aspx">MSDN</a>
849      */
850     @JsxFunction({CHROME, FF})
851     public void insertAdjacentHTML(final String position, final String text) {
852         final Object[] values = getInsertAdjacentLocation(position);
853         final DomNode domNode = (DomNode) values[0];
854         final boolean append = ((Boolean) values[1]).booleanValue();
855 
856         // add the new nodes
857         final DomNode proxyDomNode = new ProxyDomNode(domNode.getPage(), domNode, append);
858         parseHtmlSnippet(proxyDomNode, text);
859     }
860 
861     /**
862      * Parses the specified HTML source code, appending the resulting content at the specified target location.
863      * @param target the node indicating the position at which the parsed content should be placed
864      * @param source the HTML code extract to parse
865      */
866     private static void parseHtmlSnippet(final DomNode target, final String source) {
867         try {
868             HTMLParser.parseFragment(target, source);
869         }
870         catch (final IOException e) {
871             LogFactory.getLog(HtmlElement.class).error("Unexpected exception occurred while parsing HTML snippet", e);
872             throw Context.reportRuntimeError("Unexpected exception occurred while parsing HTML snippet: "
873                     + e.getMessage());
874         }
875         catch (final SAXException e) {
876             LogFactory.getLog(HtmlElement.class).error("Unexpected exception occurred while parsing HTML snippet", e);
877             throw Context.reportRuntimeError("Unexpected exception occurred while parsing HTML snippet: "
878                     + e.getMessage());
879         }
880     }
881 
882     /**
883      * Gets the {@code innerHTML} attribute.
884      * @return the contents of this node as HTML
885      */
886     @JsxGetter({CHROME, FF})
887     public String getInnerHTML() {
888         final DomNode domNode;
889         try {
890             domNode = getDomNodeOrDie();
891         }
892         catch (final IllegalStateException e) {
893             Context.throwAsScriptRuntimeEx(e);
894             return "";
895         }
896         return getInnerHTML(domNode);
897     }
898 
899     /**
900      * Replaces all child elements of this element with the supplied value.
901      * @param value the new value for the contents of this element
902      */
903     @JsxSetter({CHROME, FF})
904     public void setInnerHTML(final Object value) {
905         final DomNode domNode;
906         try {
907             domNode = getDomNodeOrDie();
908         }
909         catch (final IllegalStateException e) {
910             Context.throwAsScriptRuntimeEx(e);
911             return;
912         }
913 
914         domNode.removeAllChildren();
915 
916         final boolean addChildForNull = getBrowserVersion().hasFeature(JS_INNER_HTML_ADD_CHILD_FOR_NULL_VALUE);
917         if ((value == null && addChildForNull) || (value != null && !"".equals(value))) {
918 
919             final String valueAsString = Context.toString(value);
920             parseHtmlSnippet(domNode, valueAsString);
921         }
922     }
923 
924     /**
925      * Helper for getInnerHtml (to be reuses bei HTMLTemplate.
926      * @param domNode the node
927      * @return the contents of this node as HTML
928      */
929     protected String getInnerHTML(final DomNode domNode) {
930         final StringBuilder buf = new StringBuilder();
931 
932         final String tagName = getTagName();
933         boolean isPlain = "SCRIPT".equals(tagName);
934 
935         isPlain = isPlain || "STYLE".equals(tagName);
936 
937         // we can't rely on DomNode.asXml because it adds indentation and new lines
938         printChildren(buf, domNode, !isPlain);
939         return buf.toString();
940     }
941 
942     /**
943      * Gets the outerHTML of the node.
944      * @see <a href="http://msdn.microsoft.com/en-us/library/ms534310.aspx">MSDN documentation</a>
945      * @return the contents of this node as HTML
946      */
947     @JsxGetter({CHROME, FF})
948     public String getOuterHTML() {
949         final StringBuilder buf = new StringBuilder();
950         // we can't rely on DomNode.asXml because it adds indentation and new lines
951         printNode(buf, getDomNodeOrDie(), true);
952         return buf.toString();
953     }
954 
955     /**
956      * Replaces this element (including all child elements) with the supplied value.
957      * @param value the new value for replacing this element
958      */
959     @JsxSetter({CHROME, FF})
960     public void setOuterHTML(final Object value) {
961         final DomNode domNode = getDomNodeOrDie();
962         final DomNode parent = domNode.getParentNode();
963         if (null == parent) {
964             if (getBrowserVersion().hasFeature(JS_OUTER_HTML_REMOVES_CHILDREN_FOR_DETACHED)) {
965                 domNode.removeAllChildren();
966             }
967             if (getBrowserVersion().hasFeature(JS_OUTER_HTML_THROWS_FOR_DETACHED)) {
968                 throw Context.reportRuntimeError("outerHTML is readonly for detached nodes");
969             }
970             return;
971         }
972 
973         if (value == null && !getBrowserVersion().hasFeature(JS_OUTER_HTML_NULL_AS_STRING)) {
974             domNode.remove();
975             return;
976         }
977         final String valueStr = Context.toString(value);
978         if (valueStr.isEmpty()) {
979             domNode.remove();
980             return;
981         }
982 
983         final DomNode nextSibling = domNode.getNextSibling();
984         domNode.remove();
985 
986         final DomNode target;
987         final boolean append;
988         if (nextSibling != null) {
989             target = nextSibling;
990             append = false;
991         }
992         else {
993             target = parent;
994             append = true;
995         }
996 
997         final DomNode proxyDomNode = new ProxyDomNode(target.getPage(), target, append);
998         parseHtmlSnippet(proxyDomNode, valueStr);
999     }
1000 
1001     /**
1002      * Helper for getting code back from nodes.
1003      * @param builder the builder to write to
1004      * @param node the node to be serialized
1005      * @param html flag
1006      */
1007     protected void printChildren(final StringBuilder builder, final DomNode node, final boolean html) {
1008         for (final DomNode child : node.getChildren()) {
1009             printNode(builder, child, html);
1010         }
1011     }
1012 
1013     private void printNode(final StringBuilder builder, final DomNode node, final boolean html) {
1014         if (node instanceof DomComment) {
1015             if (html) {
1016                 // Remove whitespace sequences.
1017                 final String s = PRINT_NODE_PATTERN.matcher(node.getNodeValue()).replaceAll(" ");
1018                 builder.append("<!--").append(s).append("-->");
1019             }
1020         }
1021         else if (node instanceof DomCharacterData) {
1022             // Remove whitespace sequences, possibly escape XML characters.
1023             String s = node.getNodeValue();
1024             if (html) {
1025                 s = com.gargoylesoftware.htmlunit.util.StringUtils.escapeXmlChars(s);
1026             }
1027             builder.append(s);
1028         }
1029         else if (html) {
1030             final DomElement element = (DomElement) node;
1031             final Element scriptObject = (Element) node.getScriptableObject();
1032             final String tag = element.getTagName();
1033 
1034             Element htmlElement = null;
1035             if (scriptObject instanceof HTMLElement) {
1036                 htmlElement = scriptObject;
1037             }
1038             builder.append("<").append(tag);
1039             // Add the attributes. IE does not use quotes, FF does.
1040             for (final DomAttr attr : element.getAttributesMap().values()) {
1041                 if (!attr.getSpecified()) {
1042                     continue;
1043                 }
1044 
1045                 final String name = attr.getName();
1046                 final String value = PRINT_NODE_QUOTE_PATTERN.matcher(attr.getValue()).replaceAll("&quot;");
1047                 builder.append(' ').append(name).append("=");
1048                 builder.append("\"");
1049                 builder.append(value);
1050                 builder.append("\"");
1051             }
1052             builder.append(">");
1053             // Add the children.
1054             final boolean isHtml = html
1055                     && !(scriptObject instanceof HTMLScriptElement)
1056                     && !(scriptObject instanceof HTMLStyleElement);
1057             printChildren(builder, node, isHtml);
1058             if (null == htmlElement || !htmlElement.isEndTagForbidden()) {
1059                 builder.append("</").append(tag).append(">");
1060             }
1061         }
1062         else {
1063             if (node instanceof HtmlElement) {
1064                 final HtmlElement element = (HtmlElement) node;
1065                 if ("p".equals(element.getTagName())) {
1066                     if (getBrowserVersion().hasFeature(JS_INNER_TEXT_CR_NL)) {
1067                         builder.append("\r\n"); // \r\n because it's to implement something IE specific
1068                     }
1069                     else {
1070                         int i = builder.length() - 1;
1071                         while (i >= 0 && Character.isWhitespace(builder.charAt(i))) {
1072                             i--;
1073                         }
1074                         builder.setLength(i + 1);
1075                         builder.append("\n");
1076                     }
1077                 }
1078                 if (!"script".equals(element.getTagName())) {
1079                     printChildren(builder, node, html);
1080                 }
1081             }
1082         }
1083     }
1084 
1085     /**
1086      * Returns whether the end tag is forbidden or not.
1087      * @see <a href="http://www.w3.org/TR/html4/index/elements.html">HTML 4 specs</a>
1088      * @return whether the end tag is forbidden or not
1089      */
1090     protected boolean isEndTagForbidden() {
1091         return false;
1092     }
1093 
1094     /**
1095      * Returns the element ID.
1096      * @return the ID of this element
1097      */
1098     @JsxGetter({CHROME, FF})
1099     public String getId() {
1100         return getDomNodeOrDie().getId();
1101     }
1102 
1103     /**
1104      * {@inheritDoc}
1105      */
1106     @JsxSetter({CHROME, FF})
1107     public void setId(final String newId) {
1108         getDomNodeOrDie().setId(newId);
1109     }
1110 
1111     /**
1112      * Removes the specified attribute.
1113      * @param attribute the attribute to remove
1114      */
1115     @JsxFunction
1116     public void removeAttributeNode(final Attr attribute) {
1117         final String name = attribute.getName();
1118         final Object namespaceUri = attribute.getNamespaceURI();
1119         if (namespaceUri instanceof String) {
1120             removeAttributeNS((String) namespaceUri, name);
1121             return;
1122         }
1123         removeAttributeNS(null, name);
1124     }
1125 
1126     /**
1127      * Gets the scrollTop value for this element.
1128      * @return the scrollTop value for this element
1129      * @see <a href="http://msdn.microsoft.com/en-us/library/ms534618.aspx">MSDN documentation</a>
1130      */
1131     @JsxGetter
1132     public int getScrollTop() {
1133         // It's easier to perform these checks and adjustments in the getter, rather than in the setter,
1134         // because modifying the CSS style of the element is supposed to affect the attribute value.
1135         if (scrollTop_ < 0) {
1136             scrollTop_ = 0;
1137         }
1138         else if (scrollTop_ > 0) {
1139             final ComputedCSSStyleDeclaration style = getWindow().getComputedStyle(this, null);
1140             if (!style.isScrollable(false)) {
1141                 scrollTop_ = 0;
1142             }
1143         }
1144         return scrollTop_;
1145     }
1146 
1147     /**
1148      * Sets the scrollTop value for this element.
1149      * @param scroll the scrollTop value for this element
1150      */
1151     @JsxSetter
1152     public void setScrollTop(final int scroll) {
1153         scrollTop_ = scroll;
1154     }
1155 
1156     /**
1157      * Gets the scrollLeft value for this element.
1158      * @return the scrollLeft value for this element
1159      * @see <a href="http://msdn.microsoft.com/en-us/library/ms534617.aspx">MSDN documentation</a>
1160      */
1161     @JsxGetter
1162     public int getScrollLeft() {
1163         // It's easier to perform these checks and adjustments in the getter, rather than in the setter,
1164         // because modifying the CSS style of the element is supposed to affect the attribute value.
1165         if (scrollLeft_ < 0) {
1166             scrollLeft_ = 0;
1167         }
1168         else if (scrollLeft_ > 0) {
1169             final ComputedCSSStyleDeclaration style = getWindow().getComputedStyle(this, null);
1170             if (!style.isScrollable(true)) {
1171                 scrollLeft_ = 0;
1172             }
1173         }
1174         return scrollLeft_;
1175     }
1176 
1177     /**
1178      * Sets the scrollLeft value for this element.
1179      * @param scroll the scrollLeft value for this element
1180      */
1181     @JsxSetter
1182     public void setScrollLeft(final int scroll) {
1183         scrollLeft_ = scroll;
1184     }
1185 
1186     /**
1187      * Gets the scrollHeight for this element.
1188      * @return at the moment the same as client height
1189      * @see <a href="http://msdn.microsoft.com/en-us/library/ms534615.aspx">MSDN documentation</a>
1190      */
1191     @JsxGetter
1192     public int getScrollHeight() {
1193         return getClientHeight();
1194     }
1195 
1196     /**
1197      * Gets the scrollWidth for this element.
1198      * @return a dummy value of 10
1199      * @see <a href="http://msdn.microsoft.com/en-us/library/ms534619.aspx">MSDN documentation</a>
1200      */
1201     @JsxGetter
1202     public int getScrollWidth() {
1203         return getClientWidth();
1204     }
1205 
1206     /**
1207      * Returns the style object for this element.
1208      * @return the style object for this element
1209      */
1210     protected CSSStyleDeclaration getStyle() {
1211         return style_;
1212     }
1213 
1214     /**
1215      * Sets the styles for this element.
1216      * @param style the style of the element
1217      */
1218     protected void setStyle(final String style) {
1219         if (!getBrowserVersion().hasFeature(JS_ELEMENT_GET_ATTRIBUTE_RETURNS_EMPTY)) {
1220             getStyle().setCssText(style);
1221         }
1222     }
1223 
1224     /**
1225      * Implement the {@code scrollIntoView()} JavaScript function but don't actually do
1226      * anything. The requirement
1227      * is just to prevent scripts that call that method from failing
1228      */
1229     @JsxFunction({CHROME, FF})
1230     public void scrollIntoView() { /* do nothing at the moment */ }
1231 
1232     /**
1233      * Implement the {@code scrollIntoViewIfNeeded()} JavaScript function but don't actually do
1234      * anything.
1235      */
1236     @JsxFunction(CHROME)
1237     public void scrollIntoViewIfNeeded() { /* do nothing at the moment */ }
1238 
1239     /**
1240      * {@inheritDoc}
1241      */
1242     @Override
1243     @JsxGetter({CHROME, FF52})
1244     public Object getPrefix() {
1245         return super.getPrefix();
1246     }
1247 
1248     /**
1249      * {@inheritDoc}
1250      */
1251     @Override
1252     @JsxGetter({CHROME, FF52})
1253     public Object getLocalName() {
1254         return super.getLocalName();
1255     }
1256 
1257     /**
1258      * {@inheritDoc}
1259      */
1260     @Override
1261     @JsxGetter({CHROME, FF52})
1262     public Object getNamespaceURI() {
1263         return super.getNamespaceURI();
1264     }
1265 
1266     /**
1267      * Returns the {@code onbeforecopy} event handler for this element.
1268      * @return the {@code onbeforecopy} event handler for this element
1269      */
1270     @JsxGetter(CHROME)
1271     public Function getOnbeforecopy() {
1272         return getEventHandler("beforecopy");
1273     }
1274 
1275     /**
1276      * Sets the {@code onbeforecopy} event handler for this element.
1277      * @param onbeforecopy the {@code onbeforecopy} event handler for this element
1278      */
1279     @JsxSetter(CHROME)
1280     public void setOnbeforecopy(final Object onbeforecopy) {
1281         setEventHandler("beforecopy", onbeforecopy);
1282     }
1283 
1284     /**
1285      * Returns the {@code onbeforecut} event handler for this element.
1286      * @return the {@code onbeforecut} event handler for this element
1287      */
1288     @JsxGetter(CHROME)
1289     public Function getOnbeforecut() {
1290         return getEventHandler("beforecut");
1291     }
1292 
1293     /**
1294      * Sets the {@code onbeforecut} event handler for this element.
1295      * @param onbeforecut the {@code onbeforecut} event handler for this element
1296      */
1297     @JsxSetter(CHROME)
1298     public void setOnbeforecut(final Object onbeforecut) {
1299         setEventHandler("beforecut", onbeforecut);
1300     }
1301 
1302     /**
1303      * Returns the {@code onbeforepaste} event handler for this element.
1304      * @return the {@code onbeforepaste} event handler for this element
1305      */
1306     @JsxGetter(CHROME)
1307     public Function getOnbeforepaste() {
1308         return getEventHandler("beforepaste");
1309     }
1310 
1311     /**
1312      * Sets the {@code onbeforepaste} event handler for this element.
1313      * @param onbeforepaste the {@code onbeforepaste} event handler for this element
1314      */
1315     @JsxSetter(CHROME)
1316     public void setOnbeforepaste(final Object onbeforepaste) {
1317         setEventHandler("beforepaste", onbeforepaste);
1318     }
1319 
1320     /**
1321      * Returns the {@code oncopy} event handler for this element.
1322      * @return the {@code oncopy} event handler for this element
1323      */
1324     @JsxGetter(CHROME)
1325     public Function getOncopy() {
1326         return getEventHandler("copy");
1327     }
1328 
1329     /**
1330      * Sets the {@code oncopy} event handler for this element.
1331      * @param oncopy the {@code oncopy} event handler for this element
1332      */
1333     @JsxSetter(CHROME)
1334     public void setOncopy(final Object oncopy) {
1335         setEventHandler("copy", oncopy);
1336     }
1337 
1338     /**
1339      * Returns the {@code oncut} event handler for this element.
1340      * @return the {@code oncut} event handler for this element
1341      */
1342     @JsxGetter(CHROME)
1343     public Function getOncut() {
1344         return getEventHandler("cut");
1345     }
1346 
1347     /**
1348      * Sets the {@code oncut} event handler for this element.
1349      * @param oncut the {@code oncut} event handler for this element
1350      */
1351     @JsxSetter(CHROME)
1352     public void setOncut(final Object oncut) {
1353         setEventHandler("cut", oncut);
1354     }
1355 
1356     /**
1357      * Returns the {@code onpaste} event handler for this element.
1358      * @return the {@code onpaste} event handler for this element
1359      */
1360     @JsxGetter(CHROME)
1361     public Function getOnpaste() {
1362         return getEventHandler("paste");
1363     }
1364 
1365     /**
1366      * Sets the {@code onpaste} event handler for this element.
1367      * @param onpaste the {@code onpaste} event handler for this element
1368      */
1369     @JsxSetter(CHROME)
1370     public void setOnpaste(final Object onpaste) {
1371         setEventHandler("paste", onpaste);
1372     }
1373 
1374     /**
1375      * Returns the {@code onsearch} event handler for this element.
1376      * @return the {@code onsearch} event handler for this element
1377      */
1378     @JsxGetter(CHROME)
1379     public Function getOnsearch() {
1380         return getEventHandler("search");
1381     }
1382 
1383     /**
1384      * Sets the {@code onsearch} event handler for this element.
1385      * @param onsearch the {@code onsearch} event handler for this element
1386      */
1387     @JsxSetter(CHROME)
1388     public void setOnsearch(final Object onsearch) {
1389         setEventHandler("search", onsearch);
1390     }
1391 
1392     /**
1393      * Returns the {@code onselectstart} event handler for this element.
1394      * @return the {@code onselectstart} event handler for this element
1395      */
1396     @JsxGetter(CHROME)
1397     public Function getOnselectstart() {
1398         return getEventHandler("selectstart");
1399     }
1400 
1401     /**
1402      * Sets the {@code onselectstart} event handler for this element.
1403      * @param onselectstart the {@code onselectstart} event handler for this element
1404      */
1405     @JsxSetter(CHROME)
1406     public void setOnselectstart(final Object onselectstart) {
1407         setEventHandler("selectstart", onselectstart);
1408     }
1409 
1410     /**
1411      * Returns the {@code onwebkitfullscreenchange} event handler for this element.
1412      * @return the {@code onwebkitfullscreenchange} event handler for this element
1413      */
1414     @JsxGetter(CHROME)
1415     public Function getOnwebkitfullscreenchange() {
1416         return getEventHandler("webkitfullscreenchange");
1417     }
1418 
1419     /**
1420      * Sets the {@code onwebkitfullscreenchange} event handler for this element.
1421      * @param onwebkitfullscreenchange the {@code onwebkitfullscreenchange} event handler for this element
1422      */
1423     @JsxSetter(CHROME)
1424     public void setOnwebkitfullscreenchange(final Object onwebkitfullscreenchange) {
1425         setEventHandler("webkitfullscreenchange", onwebkitfullscreenchange);
1426     }
1427 
1428     /**
1429      * Returns the {@code onwebkitfullscreenerror} event handler for this element.
1430      * @return the {@code onwebkitfullscreenerror} event handler for this element
1431      */
1432     @JsxGetter(CHROME)
1433     public Function getOnwebkitfullscreenerror() {
1434         return getEventHandler("webkitfullscreenerror");
1435     }
1436 
1437     /**
1438      * Sets the {@code onwebkitfullscreenerror} event handler for this element.
1439      * @param onwebkitfullscreenerror the {@code onwebkitfullscreenerror} event handler for this element
1440      */
1441     @JsxSetter(CHROME)
1442     public void setOnwebkitfullscreenerror(final Object onwebkitfullscreenerror) {
1443         setEventHandler("webkitfullscreenerror", onwebkitfullscreenerror);
1444     }
1445 
1446     /**
1447      * Returns the {@code onwheel} event handler for this element.
1448      * @return the {@code onwheel} event handler for this element
1449      */
1450     @JsxGetter({CHROME, FF})
1451     public Function getOnwheel() {
1452         return getEventHandler("wheel");
1453     }
1454 
1455     /**
1456      * Sets the {@code onwheel} event handler for this element.
1457      * @param onwheel the {@code onwheel} event handler for this element
1458      */
1459     @JsxSetter({CHROME, FF})
1460     public void setOnwheel(final Object onwheel) {
1461         setEventHandler("wheel", onwheel);
1462     }
1463 
1464     /**
1465      * Returns the {@code ongotpointercapture} event handler for this element.
1466      * @return the {@code ongotpointercapture} event handler for this element
1467      */
1468     @JsxGetter(IE)
1469     public Function getOngotpointercapture() {
1470         return getEventHandler("gotpointercapture");
1471     }
1472 
1473     /**
1474      * Sets the {@code ongotpointercapture} event handler for this element.
1475      * @param ongotpointercapture the {@code ongotpointercapture} event handler for this element
1476      */
1477     @JsxSetter(IE)
1478     public void setOngotpointercapture(final Object ongotpointercapture) {
1479         setEventHandler("gotpointercapture", ongotpointercapture);
1480     }
1481 
1482     /**
1483      * Returns the {@code onlostpointercapture} event handler for this element.
1484      * @return the {@code onlostpointercapture} event handler for this element
1485      */
1486     @JsxGetter(IE)
1487     public Function getOnlostpointercapture() {
1488         return getEventHandler("lostpointercapture");
1489     }
1490 
1491     /**
1492      * Sets the {@code onlostpointercapture} event handler for this element.
1493      * @param onlostpointercapture the {@code onlostpointercapture} event handler for this element
1494      */
1495     @JsxSetter(IE)
1496     public void setOnlostpointercapture(final Object onlostpointercapture) {
1497         setEventHandler("lostpointercapture", onlostpointercapture);
1498     }
1499 
1500     /**
1501      * Returns the {@code onmsgesturechange} event handler for this element.
1502      * @return the {@code onmsgesturechange} event handler for this element
1503      */
1504     @JsxGetter(IE)
1505     public Function getOnmsgesturechange() {
1506         return getEventHandler("msgesturechange");
1507     }
1508 
1509     /**
1510      * Sets the {@code onmsgesturechange} event handler for this element.
1511      * @param onmsgesturechange the {@code onmsgesturechange} event handler for this element
1512      */
1513     @JsxSetter(IE)
1514     public void setOnmsgesturechange(final Object onmsgesturechange) {
1515         setEventHandler("msgesturechange", onmsgesturechange);
1516     }
1517 
1518     /**
1519      * Returns the {@code onmsgesturedoubletap} event handler for this element.
1520      * @return the {@code onmsgesturedoubletap} event handler for this element
1521      */
1522     @JsxGetter(IE)
1523     public Function getOnmsgesturedoubletap() {
1524         return getEventHandler("msgesturedoubletap");
1525     }
1526 
1527     /**
1528      * Sets the {@code onmsgesturedoubletap} event handler for this element.
1529      * @param onmsgesturedoubletap the {@code onmsgesturedoubletap} event handler for this element
1530      */
1531     @JsxSetter(IE)
1532     public void setOnmsgesturedoubletap(final Object onmsgesturedoubletap) {
1533         setEventHandler("msgesturedoubletap", onmsgesturedoubletap);
1534     }
1535 
1536     /**
1537      * Returns the {@code onmsgestureend} event handler for this element.
1538      * @return the {@code onmsgestureend} event handler for this element
1539      */
1540     @JsxGetter(IE)
1541     public Function getOnmsgestureend() {
1542         return getEventHandler("msgestureend");
1543     }
1544 
1545     /**
1546      * Sets the {@code onmsgestureend} event handler for this element.
1547      * @param onmsgestureend the {@code onmsgestureend} event handler for this element
1548      */
1549     @JsxSetter(IE)
1550     public void setOnmsgestureend(final Object onmsgestureend) {
1551         setEventHandler("msgestureend", onmsgestureend);
1552     }
1553 
1554     /**
1555      * Returns the {@code onmsgesturehold} event handler for this element.
1556      * @return the {@code onmsgesturehold} event handler for this element
1557      */
1558     @JsxGetter(IE)
1559     public Function getOnmsgesturehold() {
1560         return getEventHandler("msgesturehold");
1561     }
1562 
1563     /**
1564      * Sets the {@code onmsgesturehold} event handler for this element.
1565      * @param onmsgesturehold the {@code onmsgesturehold} event handler for this element
1566      */
1567     @JsxSetter(IE)
1568     public void setOnmsgesturehold(final Object onmsgesturehold) {
1569         setEventHandler("msgesturehold", onmsgesturehold);
1570     }
1571 
1572     /**
1573      * Returns the {@code onmsgesturestart} event handler for this element.
1574      * @return the {@code onmsgesturestart} event handler for this element
1575      */
1576     @JsxGetter(IE)
1577     public Function getOnmsgesturestart() {
1578         return getEventHandler("msgesturestart");
1579     }
1580 
1581     /**
1582      * Sets the {@code onmsgesturestart} event handler for this element.
1583      * @param onmsgesturestart the {@code onmsgesturestart} event handler for this element
1584      */
1585     @JsxSetter(IE)
1586     public void setOnmsgesturestart(final Object onmsgesturestart) {
1587         setEventHandler("msgesturestart", onmsgesturestart);
1588     }
1589 
1590     /**
1591      * Returns the {@code onmsgesturetap} event handler for this element.
1592      * @return the {@code onmsgesturetap} event handler for this element
1593      */
1594     @JsxGetter(IE)
1595     public Function getOnmsgesturetap() {
1596         return getEventHandler("msgesturetap");
1597     }
1598 
1599     /**
1600      * Sets the {@code onmsgesturetap} event handler for this element.
1601      * @param onmsgesturetap the {@code onmsgesturetap} event handler for this element
1602      */
1603     @JsxSetter(IE)
1604     public void setOnmsgesturetap(final Object onmsgesturetap) {
1605         setEventHandler("msgesturetap", onmsgesturetap);
1606     }
1607 
1608     /**
1609      * Returns the {@code onmsgotpointercapture} event handler for this element.
1610      * @return the {@code onmsgotpointercapture} event handler for this element
1611      */
1612     @JsxGetter(IE)
1613     public Function getOnmsgotpointercapture() {
1614         return getEventHandler("msgotpointercapture");
1615     }
1616 
1617     /**
1618      * Sets the {@code onmsgotpointercapture} event handler for this element.
1619      * @param onmsgotpointercapture the {@code onmsgotpointercapture} event handler for this element
1620      */
1621     @JsxSetter(IE)
1622     public void setOnmsgotpointercapture(final Object onmsgotpointercapture) {
1623         setEventHandler("msgotpointercapture", onmsgotpointercapture);
1624     }
1625 
1626     /**
1627      * Returns the {@code onmsinertiastart} event handler for this element.
1628      * @return the {@code onmsinertiastart} event handler for this element
1629      */
1630     @JsxGetter(IE)
1631     public Function getOnmsinertiastart() {
1632         return getEventHandler("msinertiastart");
1633     }
1634 
1635     /**
1636      * Sets the {@code onmsinertiastart} event handler for this element.
1637      * @param onmsinertiastart the {@code onmsinertiastart} event handler for this element
1638      */
1639     @JsxSetter(IE)
1640     public void setOnmsinertiastart(final Object onmsinertiastart) {
1641         setEventHandler("msinertiastart", onmsinertiastart);
1642     }
1643 
1644     /**
1645      * Returns the {@code onmslostpointercapture} event handler for this element.
1646      * @return the {@code onmslostpointercapture} event handler for this element
1647      */
1648     @JsxGetter(IE)
1649     public Function getOnmslostpointercapture() {
1650         return getEventHandler("mslostpointercapture");
1651     }
1652 
1653     /**
1654      * Sets the {@code onmslostpointercapture} event handler for this element.
1655      * @param onmslostpointercapture the {@code onmslostpointercapture} event handler for this element
1656      */
1657     @JsxSetter(IE)
1658     public void setOnmslostpointercapture(final Object onmslostpointercapture) {
1659         setEventHandler("mslostpointercapture", onmslostpointercapture);
1660     }
1661 
1662     /**
1663      * Returns the {@code onmspointercancel} event handler for this element.
1664      * @return the {@code onmspointercancel} event handler for this element
1665      */
1666     @JsxGetter(IE)
1667     public Function getOnmspointercancel() {
1668         return getEventHandler("mspointercancel");
1669     }
1670 
1671     /**
1672      * Sets the {@code onmspointercancel} event handler for this element.
1673      * @param onmspointercancel the {@code onmspointercancel} event handler for this element
1674      */
1675     @JsxSetter(IE)
1676     public void setOnmspointercancel(final Object onmspointercancel) {
1677         setEventHandler("mspointercancel", onmspointercancel);
1678     }
1679 
1680     /**
1681      * Returns the {@code onmspointerdown} event handler for this element.
1682      * @return the {@code onmspointerdown} event handler for this element
1683      */
1684     @JsxGetter(IE)
1685     public Function getOnmspointerdown() {
1686         return getEventHandler("mspointerdown");
1687     }
1688 
1689     /**
1690      * Sets the {@code onmspointerdown} event handler for this element.
1691      * @param onmspointerdown the {@code onmspointerdown} event handler for this element
1692      */
1693     @JsxSetter(IE)
1694     public void setOnmspointerdown(final Object onmspointerdown) {
1695         setEventHandler("mspointerdown", onmspointerdown);
1696     }
1697 
1698     /**
1699      * Returns the {@code onmspointerenter} event handler for this element.
1700      * @return the {@code onmspointerenter} event handler for this element
1701      */
1702     @JsxGetter(IE)
1703     public Function getOnmspointerenter() {
1704         return getEventHandler("mspointerenter");
1705     }
1706 
1707     /**
1708      * Sets the {@code onmspointerenter} event handler for this element.
1709      * @param onmspointerenter the {@code onmspointerenter} event handler for this element
1710      */
1711     @JsxSetter(IE)
1712     public void setOnmspointerenter(final Object onmspointerenter) {
1713         setEventHandler("mspointerenter", onmspointerenter);
1714     }
1715 
1716     /**
1717      * Returns the {@code onmspointerleave} event handler for this element.
1718      * @return the {@code onmspointerleave} event handler for this element
1719      */
1720     @JsxGetter(IE)
1721     public Function getOnmspointerleave() {
1722         return getEventHandler("mspointerleave");
1723     }
1724 
1725     /**
1726      * Sets the {@code onmspointerleave} event handler for this element.
1727      * @param onmspointerleave the {@code onmspointerleave} event handler for this element
1728      */
1729     @JsxSetter(IE)
1730     public void setOnmspointerleave(final Object onmspointerleave) {
1731         setEventHandler("mspointerleave", onmspointerleave);
1732     }
1733 
1734     /**
1735      * Returns the {@code onmspointermove} event handler for this element.
1736      * @return the {@code onmspointermove} event handler for this element
1737      */
1738     @JsxGetter(IE)
1739     public Function getOnmspointermove() {
1740         return getEventHandler("mspointermove");
1741     }
1742 
1743     /**
1744      * Sets the {@code onmspointermove} event handler for this element.
1745      * @param onmspointermove the {@code onmspointermove} event handler for this element
1746      */
1747     @JsxSetter(IE)
1748     public void setOnmspointermove(final Object onmspointermove) {
1749         setEventHandler("mspointermove", onmspointermove);
1750     }
1751 
1752     /**
1753      * Returns the {@code onmspointerout} event handler for this element.
1754      * @return the {@code onmspointerout} event handler for this element
1755      */
1756     @JsxGetter(IE)
1757     public Function getOnmspointerout() {
1758         return getEventHandler("mspointerout");
1759     }
1760 
1761     /**
1762      * Sets the {@code onmspointerout} event handler for this element.
1763      * @param onmspointerout the {@code onmspointerout} event handler for this element
1764      */
1765     @JsxSetter(IE)
1766     public void setOnmspointerout(final Object onmspointerout) {
1767         setEventHandler("mspointerout", onmspointerout);
1768     }
1769 
1770     /**
1771      * Returns the {@code onmspointerover} event handler for this element.
1772      * @return the {@code onmspointerover} event handler for this element
1773      */
1774     @JsxGetter(IE)
1775     public Function getOnmspointerover() {
1776         return getEventHandler("mspointerover");
1777     }
1778 
1779     /**
1780      * Sets the {@code onmspointerover} event handler for this element.
1781      * @param onmspointerover the {@code onmspointerover} event handler for this element
1782      */
1783     @JsxSetter(IE)
1784     public void setOnmspointerover(final Object onmspointerover) {
1785         setEventHandler("mspointerover", onmspointerover);
1786     }
1787 
1788     /**
1789      * Returns the {@code onmspointerup} event handler for this element.
1790      * @return the {@code onmspointerup} event handler for this element
1791      */
1792     @JsxGetter(IE)
1793     public Function getOnmspointerup() {
1794         return getEventHandler("mspointerup");
1795     }
1796 
1797     /**
1798      * Sets the {@code onmspointerup} event handler for this element.
1799      * @param onmspointerup the {@code onmspointerup} event handler for this element
1800      */
1801     @JsxSetter(IE)
1802     public void setOnmspointerup(final Object onmspointerup) {
1803         setEventHandler("mspointerup", onmspointerup);
1804     }
1805 
1806     /**
1807      * Returns the {@code onpointercancel} event handler for this element.
1808      * @return the {@code onpointercancel} event handler for this element
1809      */
1810     @JsxGetter(IE)
1811     public Function getOnpointercancel() {
1812         return getEventHandler("pointercancel");
1813     }
1814 
1815     /**
1816      * Sets the {@code onpointercancel} event handler for this element.
1817      * @param onpointercancel the {@code onpointercancel} event handler for this element
1818      */
1819     @JsxSetter(IE)
1820     public void setOnpointercancel(final Object onpointercancel) {
1821         setEventHandler("pointercancel", onpointercancel);
1822     }
1823 
1824     /**
1825      * Returns the {@code onpointerdown} event handler for this element.
1826      * @return the {@code onpointerdown} event handler for this element
1827      */
1828     @JsxGetter(IE)
1829     public Function getOnpointerdown() {
1830         return getEventHandler("pointerdown");
1831     }
1832 
1833     /**
1834      * Sets the {@code onpointerdown} event handler for this element.
1835      * @param onpointerdown the {@code onpointerdown} event handler for this element
1836      */
1837     @JsxSetter(IE)
1838     public void setOnpointerdown(final Object onpointerdown) {
1839         setEventHandler("pointerdown", onpointerdown);
1840     }
1841 
1842     /**
1843      * Returns the {@code onpointerenter} event handler for this element.
1844      * @return the {@code onpointerenter} event handler for this element
1845      */
1846     @JsxGetter(IE)
1847     public Function getOnpointerenter() {
1848         return getEventHandler("pointerenter");
1849     }
1850 
1851     /**
1852      * Sets the {@code onpointerenter} event handler for this element.
1853      * @param onpointerenter the {@code onpointerenter} event handler for this element
1854      */
1855     @JsxSetter(IE)
1856     public void setOnpointerenter(final Object onpointerenter) {
1857         setEventHandler("pointerenter", onpointerenter);
1858     }
1859 
1860     /**
1861      * Returns the {@code onpointerleave} event handler for this element.
1862      * @return the {@code onpointerleave} event handler for this element
1863      */
1864     @JsxGetter(IE)
1865     public Function getOnpointerleave() {
1866         return getEventHandler("pointerleave");
1867     }
1868 
1869     /**
1870      * Sets the {@code onpointerleave} event handler for this element.
1871      * @param onpointerleave the {@code onpointerleave} event handler for this element
1872      */
1873     @JsxSetter(IE)
1874     public void setOnpointerleave(final Object onpointerleave) {
1875         setEventHandler("pointerleave", onpointerleave);
1876     }
1877 
1878     /**
1879      * Returns the {@code onpointermove} event handler for this element.
1880      * @return the {@code onpointermove} event handler for this element
1881      */
1882     @JsxGetter(IE)
1883     public Function getOnpointermove() {
1884         return getEventHandler("pointermove");
1885     }
1886 
1887     /**
1888      * Sets the {@code onpointermove} event handler for this element.
1889      * @param onpointermove the {@code onpointermove} event handler for this element
1890      */
1891     @JsxSetter(IE)
1892     public void setOnpointermove(final Object onpointermove) {
1893         setEventHandler("pointermove", onpointermove);
1894     }
1895 
1896     /**
1897      * Returns the {@code onpointerout} event handler for this element.
1898      * @return the {@code onpointerout} event handler for this element
1899      */
1900     @JsxGetter(IE)
1901     public Function getOnpointerout() {
1902         return getEventHandler("pointerout");
1903     }
1904 
1905     /**
1906      * Sets the {@code onpointerout} event handler for this element.
1907      * @param onpointerout the {@code onpointerout} event handler for this element
1908      */
1909     @JsxSetter(IE)
1910     public void setOnpointerout(final Object onpointerout) {
1911         setEventHandler("pointerout", onpointerout);
1912     }
1913 
1914     /**
1915      * Returns the {@code onpointerover} event handler for this element.
1916      * @return the {@code onpointerover} event handler for this element
1917      */
1918     @JsxGetter(IE)
1919     public Function getOnpointerover() {
1920         return getEventHandler("pointerover");
1921     }
1922 
1923     /**
1924      * Sets the {@code onpointerover} event handler for this element.
1925      * @param onpointerover the {@code onpointerover} event handler for this element
1926      */
1927     @JsxSetter(IE)
1928     public void setOnpointerover(final Object onpointerover) {
1929         setEventHandler("pointerover", onpointerover);
1930     }
1931 
1932     /**
1933      * Returns the {@code onpointerup} event handler for this element.
1934      * @return the {@code onpointerup} event handler for this element
1935      */
1936     @JsxGetter(IE)
1937     public Function getOnpointerup() {
1938         return getEventHandler("pointerup");
1939     }
1940 
1941     /**
1942      * Sets the {@code onpointerup} event handler for this element.
1943      * @param onpointerup the {@code onpointerup} event handler for this element
1944      */
1945     @JsxSetter(IE)
1946     public void setOnpointerup(final Object onpointerup) {
1947         setEventHandler("pointerup", onpointerup);
1948     }
1949 
1950     /**
1951      * {@inheritDoc}
1952      */
1953     @Override
1954     @JsxFunction({CHROME, FF, EDGE})
1955     public void remove() {
1956         super.remove();
1957     }
1958 
1959     /**
1960      * Inserts a set of Node or DOMString objects in the children list of this ChildNode's parent,
1961      * just before this ChildNode.
1962      * @param context the context
1963      * @param thisObj this object
1964      * @param args the arguments
1965      * @param function the function
1966      */
1967     @JsxFunction({CHROME, FF})
1968     public static void before(final Context context, final Scriptable thisObj, final Object[] args,
1969             final Function function) {
1970         Node.before(context, thisObj, args, function);
1971     }
1972 
1973     /**
1974      * Inserts a set of Node or DOMString objects in the children list of this ChildNode's parent,
1975      * just after this ChildNode.
1976      * @param context the context
1977      * @param thisObj this object
1978      * @param args the arguments
1979      * @param function the function
1980      */
1981     @JsxFunction({CHROME, FF})
1982     public static void after(final Context context, final Scriptable thisObj, final Object[] args,
1983             final Function function) {
1984         Node.after(context, thisObj, args, function);
1985     }
1986 
1987     /**
1988      * Replaces the node wit a set of Node or DOMString objects.
1989      * @param context the context
1990      * @param thisObj this object
1991      * @param args the arguments
1992      * @param function the function
1993      */
1994     @JsxFunction({CHROME, FF})
1995     public static void replaceWith(final Context context, final Scriptable thisObj, final Object[] args,
1996             final Function function) {
1997         Node.replaceWith(context, thisObj, args, function);
1998     }
1999 
2000     /**
2001      * Returns true if the element would be selected by the specified selector string; otherwise, returns false.
2002      * @param context the JavaScript context
2003      * @param thisObj the scriptable
2004      * @param args the arguments passed into the method
2005      * @param function the function
2006      * @return the value
2007      */
2008     @JsxFunction({CHROME, FF})
2009     public static boolean matches(
2010             final Context context, final Scriptable thisObj, final Object[] args, final Function function) {
2011         final String selectorString = (String) args[0];
2012         if (!(thisObj instanceof Element)) {
2013             throw ScriptRuntime.typeError("Illegal invocation");
2014         }
2015         try {
2016             final DomNode domNode = ((Element) thisObj).getDomNodeOrNull();
2017             return domNode != null && ((DomElement) domNode).matches(selectorString);
2018         }
2019         catch (final CSSException e) {
2020             throw ScriptRuntime.constructError("SyntaxError",
2021                     "An invalid or illegal selector was specified (selector: '"
2022                     + selectorString + "' error: " + e.getMessage() + ").");
2023         }
2024     }
2025 
2026     /**
2027      * Returns true if the element would be selected by the specified selector string; otherwise, returns false.
2028      * @param context the JavaScript context
2029      * @param thisObj the scriptable
2030      * @param args the arguments passed into the method
2031      * @param function the function
2032      * @return the value
2033      */
2034     @JsxFunction(FF)
2035     public static boolean mozMatchesSelector(
2036             final Context context, final Scriptable thisObj, final Object[] args, final Function function) {
2037         return matches(context, thisObj, args, function);
2038     }
2039 
2040     /**
2041      * Returns true if the element would be selected by the specified selector string; otherwise, returns false.
2042      * @param context the JavaScript context
2043      * @param thisObj the scriptable
2044      * @param args the arguments passed into the method
2045      * @param function the function
2046      * @return the value
2047      */
2048     @JsxFunction({CHROME, FF})
2049     public static boolean webkitMatchesSelector(
2050             final Context context, final Scriptable thisObj, final Object[] args, final Function function) {
2051         return matches(context, thisObj, args, function);
2052     }
2053 
2054     /**
2055      * Returns true if the element would be selected by the specified selector string; otherwise, returns false.
2056      * @param context the JavaScript context
2057      * @param thisObj the scriptable
2058      * @param args the arguments passed into the method
2059      * @param function the function
2060      * @return the value
2061      */
2062     @JsxFunction(IE)
2063     public static boolean msMatchesSelector(
2064             final Context context, final Scriptable thisObj, final Object[] args, final Function function) {
2065         return matches(context, thisObj, args, function);
2066     }
2067 }