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 }