1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package com.gargoylesoftware.htmlunit.javascript.host;
16
17 import java.io.IOException;
18
19 import net.sourceforge.htmlunit.corejs.javascript.Context;
20
21 import org.apache.commons.logging.Log;
22 import org.apache.commons.logging.LogFactory;
23
24 import com.gargoylesoftware.htmlunit.BrowserVersion;
25 import com.gargoylesoftware.htmlunit.BrowserVersionFeatures;
26 import com.gargoylesoftware.htmlunit.ElementNotFoundException;
27 import com.gargoylesoftware.htmlunit.SgmlPage;
28 import com.gargoylesoftware.htmlunit.html.DomComment;
29 import com.gargoylesoftware.htmlunit.html.DomDocumentFragment;
30 import com.gargoylesoftware.htmlunit.html.DomElement;
31 import com.gargoylesoftware.htmlunit.html.DomNode;
32 import com.gargoylesoftware.htmlunit.html.DomText;
33 import com.gargoylesoftware.htmlunit.html.FrameWindow;
34 import com.gargoylesoftware.htmlunit.html.HTMLParser;
35 import com.gargoylesoftware.htmlunit.html.HtmlDivision;
36 import com.gargoylesoftware.htmlunit.html.HtmlPage;
37 import com.gargoylesoftware.htmlunit.html.impl.SimpleRange;
38 import com.gargoylesoftware.htmlunit.javascript.SimpleScriptable;
39 import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLCollection;
40 import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLElement;
41 import com.gargoylesoftware.htmlunit.xml.XmlUtil;
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61 public class Document extends EventNode {
62
63 private static final Log LOG = LogFactory.getLog(Document.class);
64
65 private Window window_;
66 private DOMImplementation implementation_;
67 private String designMode_;
68
69
70
71
72
73 public void setWindow(final Window window) {
74 window_ = window;
75 }
76
77
78
79
80
81 public Location jsxGet_location() {
82 return window_.jsxGet_location();
83 }
84
85
86
87
88
89
90
91
92
93 public void jsxSet_location(final String location) throws IOException {
94 window_.jsxSet_location(location);
95 }
96
97
98
99
100
101 public String jsxGet_referrer() {
102 final String referrer = getPage().getWebResponse().getWebRequest().getAdditionalHeaders().get("Referer");
103 if (referrer == null) {
104 return "";
105 }
106 return referrer;
107 }
108
109
110
111
112
113 public Element jsxGet_documentElement() {
114 final Object documentElement = getPage().getDocumentElement();
115 if (documentElement == null) {
116
117 return null;
118 }
119 return (Element) getScriptableFor(documentElement);
120 }
121
122
123
124
125
126 public SimpleScriptable jsxGet_doctype() {
127 final Object documentType = getPage().getDoctype();
128 if (documentType == null) {
129 return null;
130 }
131 return getScriptableFor(documentType);
132 }
133
134
135
136
137
138 public String jsxGet_designMode() {
139 if (designMode_ == null) {
140 if (getBrowserVersion().hasFeature(BrowserVersionFeatures.GENERATED_30)) {
141 if (getWindow().getWebWindow() instanceof FrameWindow) {
142 designMode_ = "Inherit";
143 }
144 else {
145 designMode_ = "Off";
146 }
147 }
148 else {
149 designMode_ = "off";
150 }
151 }
152 return designMode_;
153 }
154
155
156
157
158
159 public void jsxSet_designMode(final String mode) {
160 final boolean ie = getBrowserVersion().hasFeature(BrowserVersionFeatures.GENERATED_31);
161 if (ie) {
162 if (!"on".equalsIgnoreCase(mode) && !"off".equalsIgnoreCase(mode) && !"inherit".equalsIgnoreCase(mode)) {
163 throw Context.reportRuntimeError("Invalid document.designMode value '" + mode + "'.");
164 }
165 else if (!(getWindow().getWebWindow() instanceof FrameWindow)) {
166
167 return;
168 }
169 else if ("on".equalsIgnoreCase(mode)) {
170 designMode_ = "On";
171 }
172 else if ("off".equalsIgnoreCase(mode)) {
173 designMode_ = "Off";
174 }
175 else if ("inherit".equalsIgnoreCase(mode)) {
176 designMode_ = "Inherit";
177 }
178 }
179 else {
180 if ("on".equalsIgnoreCase(mode)) {
181 designMode_ = "on";
182 final SgmlPage page = getPage();
183 if (page instanceof HtmlPage) {
184 final HtmlPage htmlPage = (HtmlPage) page;
185 final DomNode child = htmlPage.getBody().getFirstChild();
186 final DomNode rangeNode = child != null ? child : htmlPage.getBody();
187 htmlPage.setSelectionRange(new SimpleRange(rangeNode, 0));
188 }
189 }
190 else if ("off".equalsIgnoreCase(mode)) {
191 designMode_ = "off";
192 }
193 }
194 }
195
196
197
198
199
200 protected SgmlPage getPage() {
201 return (SgmlPage) getDomNodeOrDie();
202 }
203
204
205
206
207
208 public Object jsxGet_defaultView() {
209 return getWindow();
210 }
211
212
213
214
215
216 public Object jsxFunction_createDocumentFragment() {
217 final DomDocumentFragment fragment = this.<DomNode>getDomNodeOrDie().getPage().createDomDocumentFragment();
218 final DocumentFragment node = new DocumentFragment();
219 node.setParentScope(getParentScope());
220 node.setPrototype(getPrototype(node.getClass()));
221 node.setDomNode(fragment);
222 return getScriptableFor(fragment);
223 }
224
225
226
227
228
229
230
231 public Attr jsxFunction_createAttribute(final String attributeName) {
232 return (Attr) getPage().createAttribute(attributeName).getScriptObject();
233 }
234
235
236
237
238
239
240
241 public BoxObject jsxFunction_getBoxObjectFor(final HTMLElement element) {
242 return element.getBoxObject();
243 }
244
245
246
247
248
249
250
251
252
253
254 public Object jsxFunction_importNode(final Node importedNode, final boolean deep) {
255 return importedNode.<DomNode>getDomNodeOrDie().cloneNode(deep).getScriptObject();
256 }
257
258
259
260
261
262 public DOMImplementation jsxGet_implementation() {
263 if (implementation_ == null) {
264 implementation_ = new DOMImplementation();
265 implementation_.setParentScope(getWindow());
266 implementation_.setPrototype(getPrototype(implementation_.getClass()));
267 }
268 return implementation_;
269 }
270
271
272
273
274
275
276 public void jsxFunction_captureEvents(final String type) {
277
278 }
279
280
281
282
283
284
285
286
287 public XPathNSResolver jsxFunction_createNSResolver(final Node nodeResolver) {
288 final XPathNSResolver resolver = new XPathNSResolver();
289 resolver.setElement(nodeResolver);
290 resolver.setParentScope(getWindow());
291 resolver.setPrototype(getPrototype(resolver.getClass()));
292 return resolver;
293 }
294
295
296
297
298
299
300
301 public Object jsxFunction_createTextNode(final String newData) {
302 Object result = NOT_FOUND;
303 try {
304 final DomNode domNode = new DomText(this.<DomNode>getDomNodeOrDie().getPage(), newData);
305 final Object jsElement = getScriptableFor(domNode);
306
307 if (jsElement == NOT_FOUND) {
308 if (LOG.isDebugEnabled()) {
309 LOG.debug("createTextNode(" + newData
310 + ") cannot return a result as there isn't a JavaScript object for the DOM node "
311 + domNode.getClass().getName());
312 }
313 }
314 else {
315 result = jsElement;
316 }
317 }
318 catch (final ElementNotFoundException e) {
319
320 }
321 return result;
322 }
323
324
325
326
327
328
329 public Object jsxFunction_createComment(final String comment) {
330 final DomNode domNode = new DomComment(this.<DomNode>getDomNodeOrDie().getPage(), comment);
331 return getScriptableFor(domNode);
332 }
333
334
335
336
337
338
339
340
341
342
343
344 public XPathResult jsxFunction_evaluate(final String expression, final Node contextNode,
345 final Object resolver, final int type, final Object result) {
346 XPathResult xPathResult = (XPathResult) result;
347 if (xPathResult == null) {
348 xPathResult = new XPathResult();
349 xPathResult.setParentScope(getParentScope());
350 xPathResult.setPrototype(getPrototype(xPathResult.getClass()));
351 }
352 xPathResult.init(contextNode.<DomNode>getDomNodeOrDie().getByXPath(expression), type);
353 return xPathResult;
354 }
355
356
357
358
359
360
361
362 public Object jsxFunction_createElement(String tagName) {
363 Object result = NOT_FOUND;
364 try {
365 final BrowserVersion browserVersion = getBrowserVersion();
366
367 if (tagName.startsWith("<") && tagName.endsWith(">")
368 && browserVersion.hasFeature(BrowserVersionFeatures.GENERATED_153)) {
369 tagName = tagName.substring(1, tagName.length() - 1);
370 if (!tagName.matches("\\w+")) {
371 LOG.error("Unexpected exception occurred while parsing HTML snippet");
372 throw Context.reportRuntimeError("Unexpected exception occurred while parsing HTML snippet: "
373 + tagName);
374 }
375 }
376
377 final SgmlPage page = getPage();
378 final org.w3c.dom.Element element = page.createElement(tagName);
379 final Object jsElement = getScriptableFor(element);
380
381 if (jsElement == NOT_FOUND) {
382 if (LOG.isDebugEnabled()) {
383 LOG.debug("createElement(" + tagName
384 + ") cannot return a result as there isn't a JavaScript object for the element "
385 + element.getClass().getName());
386 }
387 }
388 else {
389 result = jsElement;
390 }
391 }
392 catch (final ElementNotFoundException e) {
393
394 }
395 return result;
396 }
397
398
399
400
401
402
403
404
405 public Object jsxFunction_createElementNS(final String namespaceURI, final String qualifiedName) {
406 final org.w3c.dom.Element element;
407 final BrowserVersion browserVersion = getBrowserVersion();
408 if (browserVersion.hasFeature(BrowserVersionFeatures.XUL_SUPPORT)
409 && "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul".equals(namespaceURI)) {
410
411 element = new HtmlDivision(namespaceURI, qualifiedName, getPage(), null);
412 }
413 else if (HTMLParser.XHTML_NAMESPACE.equals(namespaceURI)) {
414 element = getPage().createElementNS(namespaceURI, qualifiedName);
415 }
416 else {
417 element = new DomElement(namespaceURI, qualifiedName, getPage(), null);
418 }
419 return getScriptableFor(element);
420 }
421
422
423
424
425
426
427 public HTMLCollection jsxFunction_getElementsByTagName(final String tagName) {
428 final String description = "Document.getElementsByTagName('" + tagName + "')";
429
430 final HTMLCollection collection;
431 if ("*".equals(tagName)) {
432 collection = new HTMLCollection(getDomNodeOrDie(), false, description) {
433 @Override
434 protected boolean isMatching(final DomNode node) {
435 return true;
436 }
437 };
438 }
439 else {
440 final boolean useLocalName = getBrowserVersion().hasFeature(BrowserVersionFeatures.GENERATED_32);
441 final String tagNameLC = tagName.toLowerCase();
442
443 collection = new HTMLCollection(getDomNodeOrDie(), false, description) {
444 @Override
445 protected boolean isMatching(final DomNode node) {
446 if (useLocalName) {
447 return tagNameLC.equalsIgnoreCase(node.getLocalName());
448 }
449 return tagNameLC.equalsIgnoreCase(node.getNodeName());
450 }
451 };
452 }
453
454 return collection;
455 }
456
457
458
459
460
461
462
463
464 public Object jsxFunction_getElementsByTagNameNS(final Object namespaceURI, final String localName) {
465 final String description = "Document.getElementsByTagNameNS('" + namespaceURI + "', '" + localName + "')";
466 final DomElement domNode = getPage().getDocumentElement();
467
468 final String prefix;
469 if (namespaceURI != null && !"*".equals("*")) {
470 prefix = XmlUtil.lookupPrefix(domNode, Context.toString(namespaceURI));
471 }
472 else {
473 prefix = null;
474 }
475
476 final HTMLCollection collection = new HTMLCollection(domNode, false, description) {
477 @Override
478 protected boolean isMatching(final DomNode node) {
479 if (!localName.equals(node.getLocalName())) {
480 return false;
481 }
482 if (prefix == null) {
483 return true;
484 }
485 return true;
486 }
487 };
488
489 return collection;
490 }
491 }