KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > gargoylesoftware > htmlunit > javascript > host > Document


1 /*
2  * Copyright (c) 2002, 2005 Gargoyle Software Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  * 1. Redistributions of source code must retain the above copyright notice,
8  * this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright notice,
10  * this list of conditions and the following disclaimer in the documentation
11  * and/or other materials provided with the distribution.
12  * 3. The end-user documentation included with the redistribution, if any, must
13  * include the following acknowledgment:
14  *
15  * "This product includes software developed by Gargoyle Software Inc.
16  * (http://www.GargoyleSoftware.com/)."
17  *
18  * Alternately, this acknowledgment may appear in the software itself, if
19  * and wherever such third-party acknowledgments normally appear.
20  * 4. The name "Gargoyle Software" must not be used to endorse or promote
21  * products derived from this software without prior written permission.
22  * For written permission, please contact info@GargoyleSoftware.com.
23  * 5. Products derived from this software may not be called "HtmlUnit", nor may
24  * "HtmlUnit" appear in their name, without prior written permission of
25  * Gargoyle Software Inc.
26  *
27  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
28  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
29  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GARGOYLE
30  * SOFTWARE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
31  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
32  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
33  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
36  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37  */

38 package com.gargoylesoftware.htmlunit.javascript.host;
39
40 import java.io.IOException JavaDoc;
41 import java.net.URL JavaDoc;
42 import java.util.Collections JavaDoc;
43 import java.util.Date JavaDoc;
44 import java.util.HashMap JavaDoc;
45 import java.util.List JavaDoc;
46 import java.util.Map JavaDoc;
47 import java.util.StringTokenizer JavaDoc;
48
49 import org.apache.commons.collections.CollectionUtils;
50 import org.org.apache.commons.httpclient.Cookie;
51 import org.org.apache.commons.httpclient.HttpState;
52 import org.apache.commons.lang.StringUtils;
53 import org.jaxen.JaxenException;
54 import org.mozilla.javascript.Context;
55 import org.mozilla.javascript.Function;
56 import org.mozilla.javascript.NativeArray;
57 import org.mozilla.javascript.Scriptable;
58 import org.mozilla.javascript.UniqueTag;
59
60 import com.gargoylesoftware.htmlunit.BrowserVersion;
61 import com.gargoylesoftware.htmlunit.ElementNotFoundException;
62 import com.gargoylesoftware.htmlunit.StringWebResponse;
63 import com.gargoylesoftware.htmlunit.WebClient;
64 import com.gargoylesoftware.htmlunit.WebConnection;
65 import com.gargoylesoftware.htmlunit.WebResponse;
66 import com.gargoylesoftware.htmlunit.WebWindow;
67 import com.gargoylesoftware.htmlunit.html.DomNode;
68 import com.gargoylesoftware.htmlunit.html.DomText;
69 import com.gargoylesoftware.htmlunit.html.HtmlElement;
70 import com.gargoylesoftware.htmlunit.html.HtmlInlineFrame;
71 import com.gargoylesoftware.htmlunit.html.HtmlPage;
72 import com.gargoylesoftware.htmlunit.html.HtmlScript;
73 import com.gargoylesoftware.htmlunit.html.xpath.HtmlUnitXPath;
74 import com.gargoylesoftware.htmlunit.javascript.ElementArray;
75
76 /**
77  * A JavaScript object for a Document.
78  *
79  * @version $Revision: 100 $
80  * @author <a HREF="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
81  * @author David K. Taylor
82  * @author <a HREF="mailto:chen_jun@users.sourceforge.net">Chen Jun</a>
83  * @author <a HREF="mailto:cse@dynabean.de">Christian Sell</a>
84  * @author Chris Erskine
85  * @author Marc Guillemot
86  * @author Daniel Gredler
87  * @author Michael Ottati
88  * @author <a HREF="mailto:george@murnock.com">George Murnock</a>
89  * @see <a HREF="http://msdn.microsoft.com/workshop/author/dhtml/reference/objects/obj_document.asp">
90  * MSDN documentation</a>
91  * @see <a HREF="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-7068919">
92  * W3C Dom Level 1</a>
93  */

94 public final class Document extends NodeImpl {
95
96     private static final long serialVersionUID = -7646789903352066465L;
97     private ElementArray all_; // has to be a member to have equality (==) working
98
private ElementArray forms_; // has to be a member to have equality (==) working
99
private ElementArray links_; // has to be a member to have equality (==) working
100
private ElementArray images_; // has to be a member to have equality (==) working
101
private ElementArray scripts_; // has to be a member to have equality (==) working
102

103     /** The buffer that will be used for calls to document.write() */
104     private final StringBuffer JavaDoc writeBuffer_ = new StringBuffer JavaDoc();
105     private boolean writeInCurrentDocument_ = true;
106     private String JavaDoc domain_;
107
108     /**
109      * Create an instance. Javascript objects must have a default constructor.
110      */

111     public Document() {
112     }
113
114
115     /**
116      * Javascript constructor. This must be declared in every javascript file because
117      * the rhino engine won't walk up the hierarchy looking for constructors.
118      */

119     public void jsConstructor() {
120     }
121
122
123     /**
124      * Return the html page that this document is modeling..
125      * @return The page.
126      */

127     public HtmlPage getHtmlPage() {
128         return (HtmlPage)getDomNodeOrDie();
129     }
130
131
132     /**
133      * Return the value of the javascript attribute "forms".
134      * @return The value of this attribute.
135      */

136     public Object JavaDoc jsxGet_forms() {
137         if (forms_ == null) {
138             forms_ = (ElementArray) makeJavaScriptObject(ElementArray.JS_OBJECT_NAME);
139             try {
140                 forms_.init(getHtmlPage(), new HtmlUnitXPath("//form"));
141             }
142             catch (final JaxenException e) {
143                 throw Context.reportRuntimeError("Failed to initialize collection document.forms: " + e.getMessage());
144             }
145         }
146         return forms_;
147     }
148
149
150     /**
151      * Return the value of the javascript attribute "links". Refer also to the
152      * <a HREF="http://msdn.microsoft.com/workshop/author/dhtml/reference/collections/links.asp"
153      * MSDN documentation</a>
154      * @return The value of this attribute.
155      */

156     public Object JavaDoc jsxGet_links() {
157         if (links_ == null) {
158             links_ = (ElementArray) makeJavaScriptObject(ElementArray.JS_OBJECT_NAME);
159             try {
160                 links_.init(getHtmlPage(),
161                         new HtmlUnitXPath("//a[@href] | //area[@href]"));
162             }
163             catch (final JaxenException e) {
164                 throw Context.reportRuntimeError("Failed to initialize collection document.links: " + e.getMessage());
165             }
166         }
167         return links_;
168     }
169
170     /**
171      * javascript function "write" may accept a variable number of args.
172      * It's not documented by W3C, Mozilla or MSDN but works with Mozilla and IE.
173      * @param context The javascript context
174      * @param scriptable The scriptable
175      * @param args The arguments passed into the method.
176      * @param function The function.
177      * @see <a HREF="http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/write.asp">
178      * MSDN documentation</a>
179      */

180     public static void jsxFunction_write(
181         final Context context, final Scriptable scriptable, final Object JavaDoc[] args, final Function function ) {
182
183         ((Document) scriptable).write(concatArgsAsString(args));
184     }
185
186
187     /**
188      * Converts the arguments to strings and concatenate them.
189      * @param args the javascript arguments
190      * @return the string concatenation
191      */

192     private static String JavaDoc concatArgsAsString(final Object JavaDoc[] args) {
193         final StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
194         for (int i=0; i<args.length; ++i) {
195             buffer.append(Context.toString(args[i]));
196         }
197         return buffer.toString();
198     }
199
200     /**
201      * javascript function "writeln" may accept a variable number of args.
202      * It's not documented by W3C, Mozilla or MSDN but works with Mozilla and IE.
203      * @param context The javascript context
204      * @param scriptable The scriptable
205      * @param args The arguments passed into the method.
206      * @param function The function.
207      * @see <a HREF="http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/writeln.asp">
208      * MSDN documentation</a>
209      */

210     public static void jsxFunction_writeln(
211         final Context context, final Scriptable scriptable, final Object JavaDoc[] args, final Function function ) {
212
213         ((Document) scriptable).write(concatArgsAsString(args) + "\n");
214     }
215
216     /**
217      * javascript function "write".
218      * @param content the content to write
219      */

220     protected void write(final String JavaDoc content) {
221         getLog().debug("write: " + content);
222
223         writeBuffer_.append(content);
224
225         if (!writeInCurrentDocument_) {
226             getLog().debug("written content added to buffer");
227         }
228         else {
229             // open() hasn't been called
230
final String JavaDoc bufferedContent = writeBuffer_.toString();
231             if (canAlreadyBeParsed(bufferedContent)) {
232                 writeBuffer_.setLength(0);
233                 getLog().debug("parsing buffered content: " + bufferedContent);
234
235                 final HtmlPage page = (HtmlPage) getDomNodeOrDie();
236                 // get the node at which end the parsed content should be added
237
HtmlElement current = getLastHtmlElement(page.getDocumentElement());
238                 getLog().debug("current: " + current);
239
240                 // quick and dirty workaround as long as IFRAME JS object aren't an HTMLElement
241
if (current instanceof HtmlInlineFrame) {
242                     current = (HtmlElement) current.getParentNode();
243                 }
244                 ((HTMLElement) getJavaScriptNode(current))
245                 .jsxFunction_insertAdjacentHTML(HTMLElement.POSITION_BEFORE_END, bufferedContent);
246             }
247             else {
248                 getLog().debug("write: not enough content to parsed it now");
249             }
250         }
251     }
252
253
254     /**
255      * Indicates if the content is a well formed html snippet that can already be parsed to be added
256      * to the dom
257      * @param content the html snippet
258      * @return <code>false</code> if it not well formed
259      */

260     private boolean canAlreadyBeParsed(final String JavaDoc content) {
261         // all <script> must have their </script> because the parser doesn't close automatically this tag
262
final String JavaDoc contentLowerCase = content.toLowerCase();
263         if (count(contentLowerCase, "<script") != count(contentLowerCase, "</script>")) {
264             return false;
265         }
266
267         return true;
268     }
269
270
271     /**
272      * Computes the number of occurences of the searched string in the in string
273      * @param in the string to search in
274      * @param what the string to search for
275      * @return 0 or more
276      */

277     private int count(final String JavaDoc in, final String JavaDoc what) {
278         int index = in.indexOf(what);
279         int nbOccurences = 0;
280         while (index != -1) {
281             ++nbOccurences;
282             index = in.indexOf(what, index + 1);
283         }
284
285         return nbOccurences;
286     }
287
288
289     /**
290      * Gets the node that is the last one when exploring following nodes, depth-first.
291      * @param node the node to search
292      * @return the searched node
293      */

294     HtmlElement getLastHtmlElement(final HtmlElement node) {
295         final DomNode lastChild = node.getLastChild();
296         if (lastChild == null
297                 || !(lastChild instanceof HtmlElement)
298                 || lastChild instanceof HtmlScript) {
299             return node;
300         }
301
302         return getLastHtmlElement((HtmlElement) lastChild);
303     }
304
305
306     private HttpState getHttpState() {
307         final HtmlPage htmlPage = getHtmlPage();
308         final WebConnection connection = htmlPage.getWebClient().getWebConnection();
309         final URL JavaDoc url = htmlPage.getWebResponse().getUrl();
310
311         return connection.getStateForUrl( url );
312     }
313
314     /**
315      * Return the cookie attribute.
316      * @return The cookie attribute
317      */

318     public String JavaDoc jsxGet_cookie() {
319         final HttpState state = getHttpState();
320         final Cookie[] cookies = state.getCookies();
321         if( cookies == null ) {
322             return "";
323         }
324
325         final StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
326
327         for( int i=0; i<cookies.length; i++ ) {
328             if( i != 0 ) {
329                 buffer.append(";");
330             }
331             buffer.append( cookies[i].getName() );
332             buffer.append( "=" );
333             buffer.append( cookies[i].getValue() );
334         }
335         return buffer.toString();
336     }
337
338     /**
339      * Adds a cookie
340      * @see <a HREF="http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/cookie.asp">
341      * MSDN documentation</a>
342      * @param newCookie in the format "name=value[;expires=date][;domain=domainname][;path=path][;secure]
343      */

344     public void jsxSet_cookie(final String JavaDoc newCookie) {
345         final HttpState state = getHttpState();
346
347         final Cookie cookie = buildCookie(newCookie, getHtmlPage().getWebResponse().getUrl());
348         state.addCookie(cookie);
349         getLog().info("Added cookie: " + cookie);
350     }
351
352
353     /**
354      * Builds a cookie object from the string representation allowed in JS
355      * @param newCookie in the format "name=value[;expires=date][;domain=domainname][;path=path][;secure]
356      * @param currentURL the url of the current page
357      * @return the cookie
358      */

359     static Cookie buildCookie(final String JavaDoc newCookie, final URL JavaDoc currentURL) {
360         final StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(newCookie, ";");
361         final String JavaDoc nameValue = st.nextToken();
362
363         final String JavaDoc name = StringUtils.substringBefore(nameValue, "=");
364         final String JavaDoc value = StringUtils.substringAfter(nameValue, "=");
365
366         final Map JavaDoc attributes = new HashMap JavaDoc();
367         // default values
368
attributes.put("domain", currentURL.getHost());
369         // default value "" as it seems that org.org.apache.commons.httpclient.cookie.CookieSpec
370
// doesn't like null as path
371
attributes.put("path", "");
372
373         while (st.hasMoreTokens()) {
374             final String JavaDoc token = st.nextToken();
375             final int indexEqual = token.indexOf("=");
376             if (indexEqual > -1) {
377                 attributes.put(token.substring(0, indexEqual), token.substring(indexEqual+1));
378             }
379             else {
380                 attributes.put(token, Boolean.TRUE);
381             }
382         }
383
384         final String JavaDoc domain = (String JavaDoc) attributes.get("domain");
385         final String JavaDoc path = (String JavaDoc) attributes.get("path");
386         final Date JavaDoc expires = null;
387         final boolean secure = (attributes.get("secure") != null);
388         final Cookie cookie = new Cookie(domain, name, value, path, expires, secure);
389
390         return cookie;
391     }
392
393
394     /**
395      * Return the value of the "location" property.
396      * @return The value of the "location" property
397      */

398     public Location jsxGet_location() {
399         final WebWindow webWindow = ((HtmlPage)getDomNodeOrDie()).getEnclosingWindow();
400         return ((Window)webWindow.getScriptObject()).jsxGet_location();
401     }
402
403
404     /**
405      * Sets the value of the "location" property. The location's default property is "href",
406      * so setting "document.location='http://www.sf.net'" is equivalent to setting
407      * "document.location.href='http://www.sf.net'".
408      * @see <a HREF="http://msdn.microsoft.com/workshop/author/dhtml/reference/objects/obj_location.asp">
409      * MSDN documentation</a>
410      * @param location the location to navigate to
411      * @throws IOException when location loading fails
412      */

413     public void jsxSet_location(final String JavaDoc location) throws IOException JavaDoc {
414         final WebWindow webWindow = getHtmlPage().getEnclosingWindow();
415         ((Window)webWindow.getScriptObject()).jsxSet_location(location);
416     }
417
418
419     /**
420      * Return the value of the "images" property.
421      * @return The value of the "images" property
422      */

423     public Object JavaDoc jsxGet_images() {
424         if (images_ == null) {
425             images_ = (ElementArray) makeJavaScriptObject(ElementArray.JS_OBJECT_NAME);
426             try {
427                 images_.init(getHtmlPage(), new HtmlUnitXPath("//img"));
428             }
429             catch (final JaxenException e) {
430                 throw Context.reportRuntimeError("Failed to initialize collection document.images: " + e.getMessage());
431             }
432         }
433         return images_;
434     }
435
436
437     /**
438      * Return the value of the "referrer" property.
439      * @return The value of the "referrer" property
440      */

441     public String JavaDoc jsxGet_referrer() {
442         final String JavaDoc referrer = getHtmlPage().getWebResponse().getResponseHeaderValue("referrer");
443         if( referrer == null ) {
444             return "";
445         }
446         else {
447             return referrer;
448         }
449     }
450
451
452     /**
453      * Return the value of the "URL" property.
454      * @return The value of the "URL" property
455      */

456     public String JavaDoc jsxGet_URL() {
457         return getHtmlPage().getWebResponse().getUrl().toExternalForm();
458     }
459
460
461     /**
462      * Return the value of the "all" property.
463      * @return The value of the "all" property
464      */

465     public ElementArray jsxGet_all() {
466         if (all_ == null) {
467             all_ = (ElementArray) makeJavaScriptObject(ElementArray.JS_OBJECT_NAME);
468             try {
469                 all_.init(getHtmlPage(), new HtmlUnitXPath("//*"));
470             }
471             catch (final JaxenException e) {
472                 throw Context.reportRuntimeError("Failed to initialize collection document.all: " + e.getMessage());
473             }
474         }
475         return all_;
476     }
477
478
479     /**
480      * javascript function "open".
481      * @param context The javascript context
482      * @param scriptable The scriptable
483      * @param args The arguments passed into the method.
484      * @param function The function.
485      * @return Nothing
486      * @see <a HREF="http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/open_1.asp">
487      * MSDN documentation</a>
488      */

489     public static Object JavaDoc jsxFunction_open(
490         final Context context, final Scriptable scriptable, final Object JavaDoc[] args, final Function function ) {
491
492         final Document document = (Document) scriptable;
493         if (!document.writeInCurrentDocument_) {
494             document.getLog().warn("open() called when document is already open.");
495         }
496         document.writeInCurrentDocument_ = false;
497         return null;
498     }
499
500
501     /**
502      * javascript function "close".
503      * @throws IOException If an IO problem occurs.
504      */

505     public void jsxFunction_close()
506         throws
507             IOException JavaDoc {
508
509         if (writeInCurrentDocument_) {
510             getLog().warn("close() called when document is not open.");
511         }
512         else {
513             final WebResponse webResponse
514                 = new StringWebResponse(writeBuffer_.toString());
515             final HtmlPage page = getDomNodeOrDie().getPage();
516             final WebClient webClient = page.getWebClient();
517             final WebWindow window = page.getEnclosingWindow();
518
519             webClient.loadWebResponseInto(webResponse, window);
520
521             writeInCurrentDocument_ = true;
522             writeBuffer_.setLength(0);
523         }
524     }
525
526     /**
527      * Get the JavaScript property "documentElement" for the document.
528      * @return The root node for the document.
529      */

530     public Object JavaDoc jsxGet_documentElement() {
531         return getScriptableFor(((HtmlPage)getDomNodeOrDie()).getDocumentElement());
532     }
533
534
535     /**
536      * Create a new HTML element with the given tag name.
537      *
538      * @param tagName The tag name
539      * @return the new HTML element, or NOT_FOUND if the tag is not supported.
540      */

541     public Object JavaDoc jsxFunction_createElement( final String JavaDoc tagName ) {
542         Object JavaDoc result = NOT_FOUND;
543         try {
544             final HtmlElement htmlElement = getDomNodeOrDie().getPage().createElement(tagName);
545             final Object JavaDoc jsElement = getScriptableFor(htmlElement);
546
547             if( jsElement == NOT_FOUND ) {
548                 getLog().debug("createElement("+tagName
549                     +") cannot return a result as there isn't a javascript object for the html element "
550                     + htmlElement.getClass().getName());
551             }
552             else {
553                 result = jsElement;
554             }
555         }
556         catch( final ElementNotFoundException e ) {
557             // Just fall through - result is already set to NOT_FOUND
558
}
559         return result;
560     }
561
562
563     /**
564      * Creates a new HTML attribute with the specified name.
565      *
566      * @param attributeName the name of the attribute to create
567      * @return an attribute with the specified name.
568      */

569     public Attribute jsxFunction_createAttribute( final String JavaDoc attributeName ) {
570         final Attribute att = (Attribute) makeJavaScriptObject(Attribute.JS_OBJECT_NAME);
571         att.init(attributeName, null);
572         return att;
573     }
574
575
576     /**
577      * Create a new DOM text node with the given data.
578      *
579      * @param newData The string value for the text node.
580      * @return the new text node or NOT_FOUND if there is an error.
581      */

582     public Object JavaDoc jsxFunction_createTextNode( final String JavaDoc newData ) {
583         Object JavaDoc result = NOT_FOUND;
584         try {
585             final DomNode domNode = new DomText(getDomNodeOrDie().getPage(), newData);
586             final Object JavaDoc jsElement = getScriptableFor(domNode);
587
588             if( jsElement == NOT_FOUND ) {
589                 getLog().debug("createTextNode("+newData
590                     +") cannot return a result as there isn't a javascript object for the DOM node "
591                     + domNode.getClass().getName());
592             }
593             else {
594                 result = jsElement;
595             }
596         }
597         catch( final ElementNotFoundException e ) {
598             // Just fall through - result is already set to NOT_FOUND
599
}
600         return result;
601     }
602
603
604     /**
605      * Return the element with the specified id or null if that element could
606      * not be found
607      * @param id The ID to search for
608      * @return the element or null
609      */

610     public Object JavaDoc jsxFunction_getElementById( final String JavaDoc id ) {
611         Object JavaDoc result = null;
612         try {
613             final HtmlElement htmlElement = ((HtmlPage)getDomNodeOrDie()).getDocumentElement().getHtmlElementById(id);
614             final Object JavaDoc jsElement = getScriptableFor(htmlElement);
615
616             if( jsElement == NOT_FOUND ) {
617                 getLog().debug("getElementById("+id
618                     +") cannot return a result as there isn't a javascript object for the html element "
619                     + htmlElement.getClass().getName());
620             }
621             else {
622                 result = jsElement;
623             }
624         }
625         catch (final ElementNotFoundException e) {
626             // Just fall through - result is already set to null
627

628             final BrowserVersion browser = getHtmlPage().getWebClient().getBrowserVersion();
629             if (browser.isIE()) {
630                 final NativeArray elements = (NativeArray) jsxFunction_getElementsByName(id);
631                 result = elements.get(0, this);
632                 if (result instanceof UniqueTag) {
633                     return null;
634                 }
635                 getLog().warn("getElementById(" + id + ") did a getElementByName for Internet Explorer");
636                 return result;
637             }
638             getLog().warn("getElementById(" + id
639                 + ") cannot return a result as there isn't a javascript object for the html element ");
640         }
641         return result;
642     }
643
644
645     /**
646      * Return all the elements with the specified tag name
647      * @param tagName The name to search for
648      * @return the list of elements
649      */

650     public Object JavaDoc jsxFunction_getElementsByTagName( final String JavaDoc tagName ) {
651         final HtmlPage page = (HtmlPage)getDomNodeOrDie();
652         final List JavaDoc list = page.getDocumentElement().getHtmlElementsByTagNames(
653             Collections.singletonList(tagName.toLowerCase()));
654         CollectionUtils.transform(list, getTransformerScriptableFor());
655
656         return new NativeArray( list.toArray() );
657     }
658
659     /**
660      * Returns all HTML elements that have a "name" attribute with the given value
661      *
662      * Refer to <a HREF="http://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-71555259">
663      * The DOM spec</a> for details.
664      *
665      * @param elementName - value of the "name" attribute to look for
666      * @return NodeList of elements
667      */

668     public Object JavaDoc jsxFunction_getElementsByName( final String JavaDoc elementName ) {
669         final HtmlPage page = (HtmlPage)getDomNodeOrDie();
670         final String JavaDoc exp = "//*[@name='" + elementName + "']";
671         final List JavaDoc list;
672         try {
673             final HtmlUnitXPath xpath = new HtmlUnitXPath(exp);
674             list = xpath.selectNodes(page);
675         }
676         catch (final JaxenException e) {
677             return new NativeArray(0);
678         }
679         CollectionUtils.transform(list, getTransformerScriptableFor());
680         return new NativeArray( list.toArray() );
681     }
682
683
684     /**
685      * Return the specified property or NOT_FOUND if it could not be found. This is
686      * overridden to get elements by name within this document.
687      * @param name The name of the property
688      * @param start The scriptable object that was originally queried for this property
689      * @return The property.
690      */

691     public Object JavaDoc get( final String JavaDoc name, final Scriptable start ) {
692         // Some calls to get will happen during the initialization of the superclass.
693
// At this point, we don't have enough information to do our own initialization
694
// so we have to just pass this call through to the superclass.
695
final HtmlPage htmlPage = (HtmlPage)getDomNodeOrNull();
696         if( htmlPage == null ) {
697             return super.get(name, start);
698         }
699
700         // document.xxx allows to retrieve some elements by name like img or form but not input, a, ...
701
// TODO: behaviour for iframe seems to differ between IE and Moz
702
final ElementArray collection = (ElementArray) makeJavaScriptObject(ElementArray.JS_OBJECT_NAME);
703         try {
704             collection.init(htmlPage, new HtmlUnitXPath("//*[(@name = '" + name
705                     + "' and (name() = 'img' or name() = 'form'))"));
706         }
707         catch (final JaxenException e) {
708             throw Context.reportRuntimeError("Failed to initialize collection: " + e.getMessage());
709         }
710
711         final int size = collection.jsGet_length();
712         if (size == 1) {
713             return collection.get(0, collection);
714         }
715         else if (size > 1) {
716             return collection;
717         }
718
719         return super.get(name, start);
720     }
721
722     /**
723      * Gets the body element this document
724      * @return body element
725      */

726     public Object JavaDoc jsxGet_body() {
727         final List JavaDoc list = getHtmlPage().getDocumentElement().getHtmlElementsByTagName("body");
728         if( list.size() == 0 ) {
729             return NOT_FOUND;
730         }
731         else {
732             final DomNode bodyElement = (DomNode)list.get(0);
733             return getScriptableFor(bodyElement);
734         }
735     }
736
737
738     /**
739      * Gets the title of this document
740      * @return body element
741      */

742     public String JavaDoc jsxGet_title() {
743         return getHtmlPage().getTitleText();
744     }
745
746     /**
747      * Set the title.
748      * @param message The new title
749      */

750     public void jsxSet_title(final String JavaDoc message ) {
751         getHtmlPage().setTitleText(message);
752     }
753
754     /**
755      * Get the readyState of this document. This is an IE only function
756      * @return the state - uninitilized, loading or complete - The interactive state is not returned
757      *
758      */

759     public String JavaDoc jsxGet_readyState() {
760         final DomNode node = getDomNodeOrDie();
761         if (node instanceof HtmlPage) {
762             return ((HtmlPage) node).getDocumentElement().getReadyState();
763         }
764         return getDomNodeOrDie().getReadyState();
765     }
766
767     /**
768      * The domain name of the server that served the document,
769      * or null if the server cannot be identified by a domain name.
770      * @return domain name
771      * @see <a HREF="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-2250147">
772      * W3C documentation</a>
773      */

774     public String JavaDoc jsxGet_domain() {
775         if (domain_ == null) {
776             domain_ = getHtmlPage().getWebResponse().getUrl().getHost();
777             final BrowserVersion browser = getHtmlPage().getWebClient().getBrowserVersion();
778             if (browser.isNetscape()) {
779                 domain_ = domain_.toLowerCase();
780             }
781         }
782
783         return domain_;
784     }
785
786     /**
787      * Set the the domain of this document.
788      *
789      * Domains can only be set to suffixes of the existing domain
790      * with the exception of setting the domain to itself.
791      * <p>
792      * The domain will be set according to the following rules:
793      * <ol>
794      * <li>If the newDomain.equalsIgnoreCase(currentDomain)
795      * the method returns with no error.</li>
796      * <li>If the browser version is netscape, the newDomain is downshifted.</li>
797      * <li>The change will take place if and only if the suffixes of the
798      * current domain and the new domain match AND there are at least
799      * two domain qualifiers e.g. the following transformations are legal
800      * d1.d2.d3.gargoylesoftware.com may be transformed to itself or:
801      * d2.d3.gargoylesoftware.com
802      * d3.gargoylesoftware.com
803      * gargoylesoftware.com
804      *
805      * tranformation to: com
806      * will fail
807      * </li>
808      * </ol>
809      * </p>
810      * TODO This code could be modified to understand country domain suffixes.
811      * The domain www.bbc.co.uk should be trimmable only down to bbc.co.uk
812      * trimming to co.uk should not be possible.
813      * @param newDomain the new domain to set
814      */

815     public void jsxSet_domain( final String JavaDoc newDomain ) {
816         final String JavaDoc currentDomain = jsxGet_domain();
817         if (currentDomain.equalsIgnoreCase(newDomain)) {
818             return;
819         }
820
821         if (newDomain.indexOf(".") == -1
822                 || !currentDomain.toLowerCase().endsWith("." + newDomain.toLowerCase())) {
823             throw Context.reportRuntimeError("Illegal domain value, can not set domain from: \""
824                     + currentDomain + "\" to: \"" + newDomain +"\"");
825         }
826
827         // Netscape down shifts the cse of the domain
828
if (getHtmlPage().getWebClient().getBrowserVersion().isNetscape()) {
829             domain_ = newDomain.toLowerCase();
830         }
831         else {
832             domain_ = newDomain;
833         }
834     }
835
836     /**
837      * Return the value of the javascript attribute "scripts".
838      * @return The value of this attribute.
839      */

840     public Object JavaDoc jsxGet_scripts() {
841         if (scripts_ == null) {
842             scripts_ = (ElementArray) makeJavaScriptObject(ElementArray.JS_OBJECT_NAME);
843             try {
844                 scripts_.init(getHtmlPage(), new HtmlUnitXPath("//script"));
845             }
846             catch (final JaxenException e) {
847                 throw Context.reportRuntimeError("Failed to initialize collection document.scripts: " + e.getMessage());
848             }
849         }
850         return scripts_;
851     }
852 }
853
854
Popular Tags