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                          return true;
76                      case "3.0":
77                          return true;
78                      default:
79                  }
80                  break;
81  
82              case "Views":
83                  switch (version) {
84                      case "1.0":
85                          return true;
86                      case "2.0":
87                          return true;
88                      case "3.0":
89                          return true;
90                      default:
91                  }
92                  break;
93  
94              case "StyleSheets":
95                  return true;
96  
97              case "CSS":
98                  switch (version) {
99                      case "1.0":
100                         return true;
101                     case "2.0":
102                         return true;
103                     case "3.0":
104                         return true;
105                     default:
106                 }
107                 break;
108 
109             case "CSS2":
110                 switch (version) {
111                     case "1.0":
112                         return true;
113                     case "2.0":
114                         return true;
115                     case "3.0":
116                         return true;
117                     default:
118                 }
119                 break;
120 
121             case "CSS3":
122                 switch (version) {
123                     case "1.0":
124                         return true;
125                     case "2.0":
126                         return true;
127                     case "3.0":
128                         return true;
129                     default:
130                 }
131                 break;
132 
133             case "Events":
134             case "HTMLEvents":
135             case "MouseEvents":
136             case "MutationEvents":
137                 switch (version) {
138                     case "1.0":
139                         return true;
140                     case "2.0":
141                     case "3.0":
142                         return true;
143                     default:
144                 }
145                 break;
146 
147             case "UIEvents":
148                 switch (version) {
149                     case "1.0":
150                     case "2.0":
151                         return true;
152                     case "3.0":
153                         return true;
154                     default:
155                 }
156                 break;
157 
158             case "KeyboardEvents":
159                 return true;
160 
161             case "MutationNameEvents":
162                 return true;
163 
164             case "TextEvents":
165                 return true;
166 
167             case "LS":
168             case "LS-Async":
169                 return true;
170 
171             case "Range":
172             case "Traversal":
173                 switch (version) {
174                     case "1.0":
175                         return true;
176                     case "2.0":
177                         return true;
178                     case "3.0":
179                         return true;
180                     default:
181                 }
182                 break;
183 
184             case "Validation":
185                 return true;
186 
187             case "XPath":
188                 return true;
189 
190             case "http://www.w3.org/TR/SVG11/feature#BasicStructure":
191             case "http://www.w3.org/TR/SVG11/feature#Shape":
192                 switch (version) {
193                     case "1.0":
194                     case "1.1":
195                         return true;
196                     case "1.2":
197                         return true;
198                     default:
199                 }
200                 break;
201 
202             default:
203         }
204         //TODO: other features.
205         return false;
206     }
207 
208     /**
209      * Creates an {@link XMLDocument}.
210      *
211      * @param namespaceURI the URI that identifies an XML namespace
212      * @param qualifiedName the qualified name of the document to instantiate
213      * @param doctype the document types of the document
214      * @return the newly created {@link XMLDocument}
215      */
216     @JsxFunction
217     public XMLDocument createDocument(final String namespaceURI, final String qualifiedName,
218             final DocumentType doctype) {
219         final XMLDocument document = new XMLDocument(getWindow().getWebWindow());
220         document.setParentScope(getParentScope());
221         document.setPrototype(getPrototype(document.getClass()));
222         if (qualifiedName != null && !qualifiedName.isEmpty()) {
223             final XmlPage page = (XmlPage) document.getDomNodeOrDie();
224             page.appendChild(page.createElementNS(
225                     StringUtils.isEmptyString(namespaceURI) ? null : namespaceURI, qualifiedName));
226         }
227         return document;
228     }
229 
230     /**
231      * Creates an {@link HTMLDocument}.
232      * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/DOMImplementation/createHTMLDocument">
233      *     createHTMLDocument (MDN)</a>
234      *
235      * @param titleObj the document title
236      * @return the newly created {@link HTMLDocument}
237      */
238     @JsxFunction
239     public HTMLDocument createHTMLDocument(final Object titleObj) {
240         // a similar impl is in
241         // org.htmlunit.javascript.host.dom.DOMParser.parseFromString(String, Object)
242         try {
243             final WebWindow webWindow = getWindow().getWebWindow();
244             final String html;
245             if (JavaScriptEngine.isUndefined(titleObj)) {
246                 html = Html.DOCTYPE_HTML + "<html><head></head><body></body></html>";
247             }
248             else {
249                 html = Html.DOCTYPE_HTML
250                         + "<html><head><title>"
251                         + JavaScriptEngine.toString(titleObj)
252                         + "</title></head><body></body></html>";
253             }
254             final WebResponse webResponse = new StringWebResponse(html, UrlUtils.URL_ABOUT_BLANK);
255             final HtmlPage page = new HtmlPage(webResponse, webWindow);
256             // According to spec and behavior of function in browsers new document
257             // has no location object and is not connected with any window
258             page.setEnclosingWindow(null);
259 
260             // document knows the window but is not the windows document
261             final HTMLDocument document = new HTMLDocument();
262             document.setParentScope(getWindow());
263             document.setPrototype(getPrototype(document.getClass()));
264             // document.setWindow(getWindow());
265             document.setDomNode(page);
266 
267             final WebClient webClient = webWindow.getWebClient();
268             final HTMLParser htmlParser = webClient.getPageCreator().getHtmlParser();
269             htmlParser.parse(webClient, webResponse, page, false, false);
270             return page.getScriptableObject();
271         }
272         catch (final IOException e) {
273             throw JavaScriptEngine.reportRuntimeError("Parsing failed" + e.getMessage());
274         }
275     }
276 }