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 java.io.IOException;
18  
19  import org.htmlunit.StringWebResponse;
20  import org.htmlunit.WebClient;
21  import org.htmlunit.WebResponse;
22  import org.htmlunit.WebWindow;
23  import org.htmlunit.html.Html;
24  import org.htmlunit.html.HtmlPage;
25  import org.htmlunit.html.parser.HTMLParser;
26  import org.htmlunit.javascript.HtmlUnitScriptable;
27  import org.htmlunit.javascript.JavaScriptEngine;
28  import org.htmlunit.javascript.configuration.JsxClass;
29  import org.htmlunit.javascript.configuration.JsxConstructor;
30  import org.htmlunit.javascript.configuration.JsxFunction;
31  import org.htmlunit.javascript.host.html.HTMLDocument;
32  import org.htmlunit.javascript.host.xml.XMLDocument;
33  import org.htmlunit.util.StringUtils;
34  import org.htmlunit.util.UrlUtils;
35  import org.htmlunit.xml.XmlPage;
36  
37  /**
38   * A JavaScript object for {@code DOMImplementation}.
39   *
40   * @author Ahmed Ashour
41   * @author Frank Danek
42   * @author Ronald Brill
43   * @author Adam Afeltowicz
44   *
45   * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/DOMImplementation">MDN Documentation</a>
46   * @see <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-core.html#ID-102161490">
47   *     W3C Dom Level 1</a>
48   */
49  @JsxClass
50  public class DOMImplementation extends HtmlUnitScriptable {
51  
52      /**
53       * JavaScript constructor.
54       */
55      @JsxConstructor
56      public void jsConstructor() {
57          // nothing to do
58      }
59  
60      /**
61       * Tests if the DOM implementation implements a specific feature.
62       * @param feature the name of the feature to test (case-insensitive)
63       * @param version the version number of the feature to test
64       * @return true if the feature is implemented in the specified version, false otherwise
65       */
66      @JsxFunction
67      public boolean hasFeature(final String feature, final String version) {
68          switch (feature) {
69              case "Core":
70              case "HTML":
71              case "XHTML":
72              case "XML":
73                  switch (version) {
74                      case "1.0":
75                      case "2.0":
76                      case "3.0":
77                          return true;
78                      default:
79                  }
80                  break;
81  
82              case "Views":
83                  switch (version) {
84                      case "1.0":
85                      case "2.0":
86                      case "3.0":
87                          return true;
88                      default:
89                  }
90                  break;
91  
92              case "StyleSheets":
93              case "KeyboardEvents":
94              case "MutationNameEvents":
95              case "TextEvents":
96              case "LS":
97              case "LS-Async":
98              case "Validation":
99              case "XPath":
100                 return true;
101 
102             case "CSS":
103                 switch (version) {
104                     case "1.0":
105                     case "2.0":
106                     case "3.0":
107                         return true;
108                     default:
109                 }
110                 break;
111 
112             case "CSS2":
113                 switch (version) {
114                     case "1.0":
115                     case "2.0":
116                     case "3.0":
117                         return true;
118                     default:
119                 }
120                 break;
121 
122             case "CSS3":
123                 switch (version) {
124                     case "1.0":
125                     case "2.0":
126                     case "3.0":
127                         return true;
128                     default:
129                 }
130                 break;
131 
132             case "Events":
133             case "HTMLEvents":
134             case "MouseEvents":
135             case "MutationEvents":
136                 switch (version) {
137                     case "1.0":
138                     case "2.0":
139                     case "3.0":
140                         return true;
141                     default:
142                 }
143                 break;
144 
145             case "UIEvents":
146                 switch (version) {
147                     case "1.0":
148                     case "2.0":
149                     case "3.0":
150                         return true;
151                     default:
152                 }
153                 break;
154 
155             case "Range":
156             case "Traversal":
157                 switch (version) {
158                     case "1.0":
159                     case "2.0":
160                     case "3.0":
161                         return true;
162                     default:
163                 }
164                 break;
165 
166             case "http://www.w3.org/TR/SVG11/feature#BasicStructure":
167             case "http://www.w3.org/TR/SVG11/feature#Shape":
168                 switch (version) {
169                     case "1.0":
170                     case "1.1":
171                     case "1.2":
172                         return true;
173                     default:
174                 }
175                 break;
176 
177             default:
178         }
179         //TODO: other features.
180         return false;
181     }
182 
183     /**
184      * Creates an {@link XMLDocument}.
185      *
186      * @param namespaceURI the URI that identifies an XML namespace
187      * @param qualifiedName the qualified name of the document to instantiate
188      * @param doctype the document types of the document
189      * @return the newly created {@link XMLDocument}
190      */
191     @JsxFunction
192     public XMLDocument createDocument(final String namespaceURI, final String qualifiedName,
193             final DocumentType doctype) {
194         final XMLDocument document = new XMLDocument(getWindow().getWebWindow());
195         document.setParentScope(getParentScope());
196         document.setPrototype(getPrototype(document.getClass()));
197         if (qualifiedName != null && !qualifiedName.isEmpty()) {
198             final XmlPage page = (XmlPage) document.getDomNodeOrDie();
199             page.appendChild(page.createElementNS(
200                     StringUtils.isEmptyString(namespaceURI) ? null : namespaceURI, qualifiedName));
201         }
202         return document;
203     }
204 
205     /**
206      * Creates an {@link HTMLDocument}.
207      * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/DOMImplementation/createHTMLDocument">
208      *     createHTMLDocument (MDN)</a>
209      *
210      * @param titleObj the document title
211      * @return the newly created {@link HTMLDocument}
212      */
213     @JsxFunction
214     public HTMLDocument createHTMLDocument(final Object titleObj) {
215         // a similar impl is in
216         // org.htmlunit.javascript.host.dom.DOMParser.parseFromString(String, Object)
217         try {
218             final WebWindow webWindow = getWindow().getWebWindow();
219             final String html;
220             if (JavaScriptEngine.isUndefined(titleObj)) {
221                 html = Html.DOCTYPE_HTML + "<html><head></head><body></body></html>";
222             }
223             else {
224                 html = Html.DOCTYPE_HTML
225                         + "<html><head><title>"
226                         + JavaScriptEngine.toString(titleObj)
227                         + "</title></head><body></body></html>";
228             }
229             final WebResponse webResponse = new StringWebResponse(html, UrlUtils.URL_ABOUT_BLANK);
230             final HtmlPage page = new HtmlPage(webResponse, webWindow);
231             // According to spec and behavior of function in browsers new document
232             // has no location object and is not connected with any window
233             page.setEnclosingWindow(null);
234 
235             // document knows the window but is not the windows document
236             final HTMLDocument document = new HTMLDocument();
237             document.setParentScope(getTopLevelScope(getParentScope()));
238             document.setPrototype(getPrototype(document.getClass()));
239             // document.setWindow(getWindow());
240             document.setDomNode(page);
241 
242             final WebClient webClient = webWindow.getWebClient();
243             final HTMLParser htmlParser = webClient.getPageCreator().getHtmlParser();
244             htmlParser.parse(webClient, webResponse, page, false, false);
245             return page.getScriptableObject();
246         }
247         catch (final IOException e) {
248             throw JavaScriptEngine.reportRuntimeError("Parsing failed" + e.getMessage());
249         }
250     }
251 }