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 }