View Javadoc
1   /*
2    * Copyright (c) 2002-2025 Gargoyle Software Inc.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * https://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software
10   * distributed under the License is distributed on an "AS IS" BASIS,
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   * See the License for the specific language governing permissions and
13   * limitations under the License.
14   */
15  package org.htmlunit.javascript.host.dom;
16  
17  import 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="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-core.html#ID-102161490">
46   *     W3C Dom Level 1</a>
47   */
48  @JsxClass
49  public class DOMImplementation extends HtmlUnitScriptable {
50  
51      /**
52       * JavaScript constructor.
53       */
54      @JsxConstructor
55      public void jsConstructor() {
56          // nothing to do
57      }
58  
59      /**
60       * Test if the DOM implementation implements a specific feature.
61       * @param feature the name of the feature to test (case-insensitive)
62       * @param version the version number of the feature to test
63       * @return true if the feature is implemented in the specified version, false otherwise
64       */
65      @JsxFunction
66      public boolean hasFeature(final String feature, final String version) {
67          switch (feature) {
68              case "Core":
69              case "HTML":
70              case "XHTML":
71              case "XML":
72                  switch (version) {
73                      case "1.0":
74                      case "2.0":
75                      case "3.0":
76                          return true;
77                      default:
78                  }
79                  break;
80  
81              case "Views":
82                  switch (version) {
83                      case "1.0":
84                      case "2.0":
85                      case "3.0":
86                          return true;
87                      default:
88                  }
89                  break;
90  
91              case "StyleSheets":
92              case "KeyboardEvents":
93              case "MutationNameEvents":
94              case "TextEvents":
95              case "LS":
96              case "LS-Async":
97              case "Validation":
98              case "XPath":
99                  return true;
100 
101             case "CSS":
102                 switch (version) {
103                     case "1.0":
104                     case "2.0":
105                     case "3.0":
106                         return true;
107                     default:
108                 }
109                 break;
110 
111             case "CSS2":
112                 switch (version) {
113                     case "1.0":
114                     case "2.0":
115                     case "3.0":
116                         return true;
117                     default:
118                 }
119                 break;
120 
121             case "CSS3":
122                 switch (version) {
123                     case "1.0":
124                     case "2.0":
125                     case "3.0":
126                         return true;
127                     default:
128                 }
129                 break;
130 
131             case "Events":
132             case "HTMLEvents":
133             case "MouseEvents":
134             case "MutationEvents":
135                 switch (version) {
136                     case "1.0":
137                     case "2.0":
138                     case "3.0":
139                         return true;
140                     default:
141                 }
142                 break;
143 
144             case "UIEvents":
145                 switch (version) {
146                     case "1.0":
147                     case "2.0":
148                     case "3.0":
149                         return true;
150                     default:
151                 }
152                 break;
153 
154             case "Range":
155             case "Traversal":
156                 switch (version) {
157                     case "1.0":
158                     case "2.0":
159                     case "3.0":
160                         return true;
161                     default:
162                 }
163                 break;
164 
165             case "http://www.w3.org/TR/SVG11/feature#BasicStructure":
166             case "http://www.w3.org/TR/SVG11/feature#Shape":
167                 switch (version) {
168                     case "1.0":
169                     case "1.1":
170                     case "1.2":
171                         return true;
172                     default:
173                 }
174                 break;
175 
176             default:
177         }
178         //TODO: other features.
179         return false;
180     }
181 
182     /**
183      * Creates an {@link XMLDocument}.
184      *
185      * @param namespaceURI the URI that identifies an XML namespace
186      * @param qualifiedName the qualified name of the document to instantiate
187      * @param doctype the document types of the document
188      * @return the newly created {@link XMLDocument}
189      */
190     @JsxFunction
191     public XMLDocument createDocument(final String namespaceURI, final String qualifiedName,
192             final DocumentType doctype) {
193         final XMLDocument document = new XMLDocument(getWindow().getWebWindow());
194         document.setParentScope(getParentScope());
195         document.setPrototype(getPrototype(document.getClass()));
196         if (qualifiedName != null && !qualifiedName.isEmpty()) {
197             final XmlPage page = (XmlPage) document.getDomNodeOrDie();
198             page.appendChild(page.createElementNS(
199                     StringUtils.isEmptyString(namespaceURI) ? null : namespaceURI, qualifiedName));
200         }
201         return document;
202     }
203 
204     /**
205      * Creates an {@link HTMLDocument}.
206      * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/DOMImplementation/createHTMLDocument">
207      *     createHTMLDocument (MDN)</a>
208      *
209      * @param titleObj the document title
210      * @return the newly created {@link HTMLDocument}
211      */
212     @JsxFunction
213     public HTMLDocument createHTMLDocument(final Object titleObj) {
214         // a similar impl is in
215         // org.htmlunit.javascript.host.dom.DOMParser.parseFromString(String, Object)
216         try {
217             final WebWindow webWindow = getWindow().getWebWindow();
218             final String html;
219             if (JavaScriptEngine.isUndefined(titleObj)) {
220                 html = Html.DOCTYPE_HTML + "<html><head></head><body></body></html>";
221             }
222             else {
223                 html = Html.DOCTYPE_HTML
224                         + "<html><head><title>"
225                         + JavaScriptEngine.toString(titleObj)
226                         + "</title></head><body></body></html>";
227             }
228             final WebResponse webResponse = new StringWebResponse(html, UrlUtils.URL_ABOUT_BLANK);
229             final HtmlPage page = new HtmlPage(webResponse, webWindow);
230             // According to spec and behavior of function in browsers new document
231             // has no location object and is not connected with any window
232             page.setEnclosingWindow(null);
233 
234             // document knows the window but is not the windows document
235             final HTMLDocument document = new HTMLDocument();
236             document.setParentScope(getWindow());
237             document.setPrototype(getPrototype(document.getClass()));
238             // document.setWindow(getWindow());
239             document.setDomNode(page);
240 
241             final WebClient webClient = webWindow.getWebClient();
242             final HTMLParser htmlParser = webClient.getPageCreator().getHtmlParser();
243             htmlParser.parse(webClient, webResponse, page, false, false);
244             return page.getScriptableObject();
245         }
246         catch (final IOException e) {
247             throw JavaScriptEngine.reportRuntimeError("Parsing failed" + e.getMessage());
248         }
249     }
250 }