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