Source Code Cross Referenced for Document.java in  » Testing » htmlunit » com » gargoylesoftware » htmlunit » javascript » host » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Testing » htmlunit » com.gargoylesoftware.htmlunit.javascript.host 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Copyright (c) 2002-2008 Gargoyle Software Inc. All rights reserved.
0003:         *
0004:         * Redistribution and use in source and binary forms, with or without
0005:         * modification, are permitted provided that the following conditions are met:
0006:         *
0007:         * 1. Redistributions of source code must retain the above copyright notice,
0008:         *    this list of conditions and the following disclaimer.
0009:         * 2. Redistributions in binary form must reproduce the above copyright notice,
0010:         *    this list of conditions and the following disclaimer in the documentation
0011:         *    and/or other materials provided with the distribution.
0012:         * 3. The end-user documentation included with the redistribution, if any, must
0013:         *    include the following acknowledgment:
0014:         *
0015:         *       "This product includes software developed by Gargoyle Software Inc.
0016:         *        (http://www.GargoyleSoftware.com/)."
0017:         *
0018:         *    Alternately, this acknowledgment may appear in the software itself, if
0019:         *    and wherever such third-party acknowledgments normally appear.
0020:         * 4. The name "Gargoyle Software" must not be used to endorse or promote
0021:         *    products derived from this software without prior written permission.
0022:         *    For written permission, please contact info@GargoyleSoftware.com.
0023:         * 5. Products derived from this software may not be called "HtmlUnit", nor may
0024:         *    "HtmlUnit" appear in their name, without prior written permission of
0025:         *    Gargoyle Software Inc.
0026:         *
0027:         * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
0028:         * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
0029:         * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GARGOYLE
0030:         * SOFTWARE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
0031:         * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
0032:         * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
0033:         * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
0034:         * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
0035:         * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
0036:         * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0037:         */
0038:        package com.gargoylesoftware.htmlunit.javascript.host;
0039:
0040:        import java.io.IOException;
0041:        import java.net.URL;
0042:        import java.util.Arrays;
0043:        import java.util.Collections;
0044:        import java.util.Date;
0045:        import java.util.HashMap;
0046:        import java.util.List;
0047:        import java.util.Map;
0048:        import java.util.StringTokenizer;
0049:
0050:        import org.apache.commons.httpclient.Cookie;
0051:        import org.apache.commons.httpclient.HttpState;
0052:        import org.apache.commons.httpclient.cookie.CookiePolicy;
0053:        import org.apache.commons.httpclient.cookie.CookieSpec;
0054:        import org.apache.commons.httpclient.util.DateParseException;
0055:        import org.apache.commons.httpclient.util.DateUtil;
0056:        import org.apache.commons.lang.StringUtils;
0057:        import org.jaxen.JaxenException;
0058:        import org.jaxen.XPathFunctionContext;
0059:        import org.mozilla.javascript.Context;
0060:        import org.mozilla.javascript.Function;
0061:        import org.mozilla.javascript.Scriptable;
0062:        import org.mozilla.javascript.UniqueTag;
0063:        import org.w3c.dom.DOMException;
0064:
0065:        import com.gargoylesoftware.htmlunit.BrowserVersion;
0066:        import com.gargoylesoftware.htmlunit.ElementNotFoundException;
0067:        import com.gargoylesoftware.htmlunit.SgmlPage;
0068:        import com.gargoylesoftware.htmlunit.StringWebResponse;
0069:        import com.gargoylesoftware.htmlunit.WebClient;
0070:        import com.gargoylesoftware.htmlunit.WebResponse;
0071:        import com.gargoylesoftware.htmlunit.WebWindow;
0072:        import com.gargoylesoftware.htmlunit.html.DomDocumentFragment;
0073:        import com.gargoylesoftware.htmlunit.html.DomNode;
0074:        import com.gargoylesoftware.htmlunit.html.DomText;
0075:        import com.gargoylesoftware.htmlunit.html.HTMLParser;
0076:        import com.gargoylesoftware.htmlunit.html.HtmlDivision;
0077:        import com.gargoylesoftware.htmlunit.html.HtmlElement;
0078:        import com.gargoylesoftware.htmlunit.html.HtmlForm;
0079:        import com.gargoylesoftware.htmlunit.html.HtmlImage;
0080:        import com.gargoylesoftware.htmlunit.html.HtmlInlineFrame;
0081:        import com.gargoylesoftware.htmlunit.html.HtmlPage;
0082:        import com.gargoylesoftware.htmlunit.html.HtmlScript;
0083:        import com.gargoylesoftware.htmlunit.html.xpath.FunctionContextWrapper;
0084:        import com.gargoylesoftware.htmlunit.html.xpath.HtmlUnitXPath;
0085:        import com.gargoylesoftware.htmlunit.html.xpath.LowerCaseFunction;
0086:        import com.gargoylesoftware.htmlunit.javascript.HTMLCollection;
0087:        import com.gargoylesoftware.htmlunit.javascript.SimpleScriptable;
0088:        import com.gargoylesoftware.htmlunit.xml.XmlPage;
0089:
0090:        /**
0091:         * A JavaScript object for a Document.
0092:         *
0093:         * @version $Revision: 2156 $
0094:         * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
0095:         * @author David K. Taylor
0096:         * @author <a href="mailto:chen_jun@users.sourceforge.net">Chen Jun</a>
0097:         * @author <a href="mailto:cse@dynabean.de">Christian Sell</a>
0098:         * @author Chris Erskine
0099:         * @author Marc Guillemot
0100:         * @author Daniel Gredler
0101:         * @author Michael Ottati
0102:         * @author <a href="mailto:george@murnock.com">George Murnock</a>
0103:         * @author Ahmed Ashour
0104:         * @author Rob Di Marco
0105:         * @see <a href="http://msdn.microsoft.com/workshop/author/dhtml/reference/objects/obj_document.asp">
0106:         * MSDN documentation</a>
0107:         * @see <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-7068919">
0108:         * W3C Dom Level 1</a>
0109:         */
0110:        public class Document extends Node {
0111:
0112:            private static final long serialVersionUID = -7646789903352066465L;
0113:
0114:            /**
0115:             * Map<String, Class> which maps strings a caller may use when calling into
0116:             * {@link #jsxFunction_createEvent(String)} to the associated event class. To support a new
0117:             * event creation type, the event type and associated class need to be added into this map in
0118:             * the static initializer. The map is unmodifiable. Any class that is a value in this map MUST
0119:             * have a no-arg constructor.
0120:             */
0121:            private static final Map SUPPORTED_EVENT_TYPE_MAP;
0122:
0123:            private HTMLCollection all_; // has to be a member to have equality (==) working
0124:            private HTMLCollection forms_; // has to be a member to have equality (==) working
0125:            private HTMLCollection links_; // has to be a member to have equality (==) working
0126:            private HTMLCollection images_; // has to be a member to have equality (==) working
0127:            private HTMLCollection scripts_; // has to be a member to have equality (==) working
0128:            private HTMLCollection anchors_; // has to be a member to have equality (==) working
0129:            private StyleSheetList styleSheets_; // has to be a member to have equality (==) working
0130:
0131:            /** The buffer that will be used for calls to document.write() */
0132:            private final StringBuffer writeBuffer_ = new StringBuffer();
0133:            private boolean writeInCurrentDocument_ = true;
0134:            private String domain_;
0135:            private Window window_;
0136:
0137:            private final FunctionContextWrapper functionContext_;
0138:            private DOMImplementation implementation_;
0139:
0140:            /** Initializes the supported event type map. */
0141:            static {
0142:                final Map eventMap = new HashMap();
0143:                eventMap.put("Event", Event.class);
0144:                eventMap.put("Events", Event.class);
0145:                eventMap.put("HTMLEvents", Event.class);
0146:                eventMap.put("UIEvent", UIEvent.class);
0147:                eventMap.put("UIEvents", UIEvent.class);
0148:                eventMap.put("MouseEvent", MouseEvent.class);
0149:                eventMap.put("MouseEvents", MouseEvent.class);
0150:                SUPPORTED_EVENT_TYPE_MAP = Collections
0151:                        .unmodifiableMap(eventMap);
0152:            }
0153:
0154:            /**
0155:             * Create an instance.  Javascript objects must have a default constructor.
0156:             */
0157:            public Document() {
0158:                // add custom functions to custom context
0159:                functionContext_ = new FunctionContextWrapper(
0160:                        XPathFunctionContext.getInstance());
0161:                functionContext_.registerFunction("lower-case",
0162:                        new LowerCaseFunction());
0163:            }
0164:
0165:            /**
0166:             * Javascript constructor.  This must be declared in every javascript file because
0167:             * the rhino engine won't walk up the hierarchy looking for constructors.
0168:             */
0169:            public void jsConstructor() {
0170:            }
0171:
0172:            /**
0173:             * Define the Window JavaScript object that encloses this Document object.
0174:             *
0175:             * @param window The Window JavaScript object that encloses this document.
0176:             */
0177:            void setWindow(final Window window) {
0178:                window_ = window;
0179:            }
0180:
0181:            /**
0182:             * Return the html page that this document is modeling..
0183:             * @return The page.
0184:             */
0185:            public HtmlPage getHtmlPage() {
0186:                return (HtmlPage) getDomNodeOrDie();
0187:            }
0188:
0189:            /**
0190:             * Return the html page that this document is modeling or null if the
0191:             * page is empty.
0192:             * @return The page.
0193:             */
0194:            public HtmlPage getHtmlPageOrNull() {
0195:                return (HtmlPage) getDomNodeOrNull();
0196:            }
0197:
0198:            /**
0199:             * Return the value of the javascript attribute "forms".
0200:             * @return The value of this attribute.
0201:             */
0202:            public Object jsxGet_forms() {
0203:                if (forms_ == null) {
0204:                    forms_ = new HTMLCollection(this );
0205:                    try {
0206:                        forms_.init(getDomNodeOrDie(), new HtmlUnitXPath(
0207:                                "//form"));
0208:                    } catch (final JaxenException e) {
0209:                        throw Context
0210:                                .reportRuntimeError("Failed to initialize collection document.forms: "
0211:                                        + e.getMessage());
0212:                    }
0213:                }
0214:                return forms_;
0215:            }
0216:
0217:            /**
0218:             * Return the value of the javascript attribute "links".  Refer also to the
0219:             * <a href="http://msdn.microsoft.com/workshop/author/dhtml/reference/collections/links.asp"
0220:             * MSDN documentation</a>
0221:             * @return The value of this attribute.
0222:             */
0223:            public Object jsxGet_links() {
0224:                if (links_ == null) {
0225:                    links_ = new HTMLCollection(this );
0226:                    try {
0227:                        links_.init(getDomNodeOrDie(), new HtmlUnitXPath(
0228:                                "//a[@href] | //area[@href]"));
0229:                    } catch (final JaxenException e) {
0230:                        throw Context
0231:                                .reportRuntimeError("Failed to initialize collection document.links: "
0232:                                        + e.getMessage());
0233:                    }
0234:                }
0235:                return links_;
0236:            }
0237:
0238:            /**
0239:             * Return the value of the javascript attribute "anchors".
0240:             * @see <a href="http://msdn.microsoft.com/workshop/author/dhtml/reference/collections/anchors.asp">
0241:             * MSDN documentation</a>
0242:             * @see <a href="http://www.mozilla.org/docs/dom/domref/dom_doc_ref4.html#1024543">
0243:             * Gecko DOM reference</a>
0244:             * @return The value of this attribute.
0245:             */
0246:            public Object jsxGet_anchors() {
0247:                if (anchors_ == null) {
0248:                    anchors_ = new HTMLCollection(this );
0249:                    try {
0250:                        final String xpath;
0251:                        if (getWindow().getWebWindow().getWebClient()
0252:                                .getBrowserVersion().isIE()) {
0253:                            xpath = "//a[@name or @id]";
0254:                        } else {
0255:                            xpath = "//a[@name]";
0256:                        }
0257:
0258:                        anchors_.init(getDomNodeOrDie(), new HtmlUnitXPath(
0259:                                xpath));
0260:                    } catch (final JaxenException e) {
0261:                        throw Context
0262:                                .reportRuntimeError("Failed to initialize collection document.anchors: "
0263:                                        + e.getMessage());
0264:                    }
0265:                }
0266:                return anchors_;
0267:            }
0268:
0269:            /**
0270:             * javascript function "write" may accept a variable number of args.
0271:             * It's not documented by W3C, Mozilla or MSDN but works with Mozilla and IE.
0272:             * @param context The javascript context
0273:             * @param thisObj The scriptable
0274:             * @param args The arguments passed into the method.
0275:             * @param function The function.
0276:             * @see <a href="http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/write.asp">
0277:             * MSDN documentation</a>
0278:             */
0279:            public static void jsxFunction_write(final Context context,
0280:                    final Scriptable this Obj, final Object[] args,
0281:                    final Function function) {
0282:
0283:                final Document this AsDocument = getDocument(this Obj);
0284:                this AsDocument.write(concatArgsAsString(args));
0285:            }
0286:
0287:            /**
0288:             * Converts the arguments to strings and concatenate them.
0289:             * @param args the javascript arguments
0290:             * @return the string concatenation
0291:             */
0292:            private static String concatArgsAsString(final Object[] args) {
0293:                final StringBuffer buffer = new StringBuffer();
0294:                for (int i = 0; i < args.length; i++) {
0295:                    buffer.append(Context.toString(args[i]));
0296:                }
0297:                return buffer.toString();
0298:            }
0299:
0300:            /**
0301:             * javascript function "writeln" may accept a variable number of args.
0302:             * It's not documented by W3C, Mozilla or MSDN but works with Mozilla and IE.
0303:             * @param context The javascript context
0304:             * @param thisObj The scriptable
0305:             * @param args The arguments passed into the method.
0306:             * @param function The function.
0307:             * @see <a href="http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/writeln.asp">
0308:             * MSDN documentation</a>
0309:             */
0310:            public static void jsxFunction_writeln(final Context context,
0311:                    final Scriptable this Obj, final Object[] args,
0312:                    final Function function) {
0313:
0314:                final Document this AsDocument = getDocument(this Obj);
0315:                this AsDocument.write(concatArgsAsString(args) + "\n");
0316:            }
0317:
0318:            /**
0319:             * Gets the document instance.
0320:             * @param document maybe the prototype when function is used without "this"
0321:             * @return the current document
0322:             */
0323:            private static Document getDocument(final Scriptable this Obj) {
0324:                // if function is used "detached", then thisObj is the top scope (ie Window), not the real object
0325:                // cf unit test DocumentTest#testDocumentWrite_AssignedToVar
0326:                if (this Obj instanceof  Document) {
0327:                    return (Document) this Obj;
0328:                } else {
0329:                    final Window window = getWindow(this Obj);
0330:                    final BrowserVersion browser = window.getWebWindow()
0331:                            .getWebClient().getBrowserVersion();
0332:                    if (browser.isIE()) {
0333:                        return window.jsxGet_document();
0334:                    } else {
0335:                        throw Context
0336:                                .reportRuntimeError("Function can't be used detached from document");
0337:                    }
0338:                }
0339:            }
0340:
0341:            /**
0342:             * javascript function "write".
0343:             * @param content the content to write
0344:             */
0345:            protected void write(final String content) {
0346:                getLog().debug("write: " + content);
0347:
0348:                writeBuffer_.append(content);
0349:
0350:                if (!writeInCurrentDocument_) {
0351:                    getLog().debug("written content added to buffer");
0352:                } else {
0353:                    // open() hasn't been called
0354:                    final String bufferedContent = writeBuffer_.toString();
0355:                    if (canAlreadyBeParsed(bufferedContent)) {
0356:                        writeBuffer_.setLength(0);
0357:                        getLog().debug(
0358:                                "parsing buffered content: " + bufferedContent);
0359:
0360:                        final HtmlPage page = (HtmlPage) getDomNodeOrDie();
0361:                        // get the node at which end the parsed content should be added
0362:                        HtmlElement current = getLastHtmlElement(page
0363:                                .getDocumentHtmlElement());
0364:                        getLog().debug("current: " + current);
0365:
0366:                        // quick and dirty workaround as long as IFRAME JS object aren't an HTMLElement
0367:                        if (current instanceof  HtmlInlineFrame) {
0368:                            current = (HtmlElement) current.getParentDomNode();
0369:                        }
0370:                        ((HTMLElement) getJavaScriptNode(current))
0371:                                .jsxFunction_insertAdjacentHTML(
0372:                                        HTMLElement.POSITION_BEFORE_END,
0373:                                        bufferedContent);
0374:                    } else {
0375:                        getLog().debug(
0376:                                "write: not enough content to parsed it now");
0377:                    }
0378:                }
0379:            }
0380:
0381:            /**
0382:             * Indicates if the content is a well formed html snippet that can already be parsed to be added
0383:             * to the dom
0384:             * @param content the html snippet
0385:             * @return <code>false</code> if it not well formed
0386:             */
0387:            private boolean canAlreadyBeParsed(final String content) {
0388:                // all <script> must have their </script> because the parser doesn't close automatically this tag
0389:                // All tags must be complete, that is from '<' to '>'.
0390:                final int tagOutside = 0;
0391:                final int tagSart = 1;
0392:                final int tagInName = 2;
0393:                final int tagInside = 3;
0394:                int tagState = tagOutside;
0395:                int tagNameBeginIndex = 0;
0396:                int scriptTagCount = 0;
0397:                boolean tagIsOpen = true;
0398:                for (int index = 0; index < content.length(); index++) {
0399:                    final char currentChar = content.charAt(index);
0400:                    switch (tagState) {
0401:                    case tagOutside:
0402:                        if (currentChar == '<') {
0403:                            tagState = tagSart;
0404:                            tagIsOpen = true;
0405:                        }
0406:                        break;
0407:                    case tagSart:
0408:                        if (currentChar == '/') {
0409:                            tagIsOpen = false;
0410:                            tagNameBeginIndex = index + 1;
0411:                        } else {
0412:                            tagNameBeginIndex = index;
0413:                        }
0414:                        tagState = tagInName;
0415:                        break;
0416:                    case tagInName:
0417:                        if (!Character.isLetter(currentChar)) {
0418:                            final String tagName = content.substring(
0419:                                    tagNameBeginIndex, index);
0420:                            if (tagName.equalsIgnoreCase("script")) {
0421:                                if (tagIsOpen) {
0422:                                    scriptTagCount++;
0423:                                } else if (scriptTagCount > 0) {
0424:                                    // Ignore extra close tags for now.  Let the
0425:                                    // parser deal with them.
0426:                                    scriptTagCount--;
0427:                                }
0428:                            }
0429:                            if (currentChar == '>') {
0430:                                tagState = tagOutside;
0431:                            } else {
0432:                                tagState = tagInside;
0433:                            }
0434:                        }
0435:                        break;
0436:                    case tagInside:
0437:                        if (currentChar == '>') {
0438:                            tagState = tagOutside;
0439:                        }
0440:                        break;
0441:                    default:
0442:                        // nothing
0443:                    }
0444:                }
0445:                if (scriptTagCount > 0 || tagState != tagOutside) {
0446:                    return false;
0447:                }
0448:
0449:                return true;
0450:            }
0451:
0452:            /**
0453:             * Gets the node that is the last one when exploring following nodes, depth-first.
0454:             * @param node the node to search
0455:             * @return the searched node
0456:             */
0457:            HtmlElement getLastHtmlElement(final HtmlElement node) {
0458:                final DomNode lastChild = node.getLastDomChild();
0459:                if (lastChild == null || !(lastChild instanceof  HtmlElement)
0460:                        || lastChild instanceof  HtmlScript) {
0461:                    return node;
0462:                }
0463:
0464:                return getLastHtmlElement((HtmlElement) lastChild);
0465:            }
0466:
0467:            /**
0468:             * Returns the cookie attribute.
0469:             * @return The cookie attribute
0470:             */
0471:            public String jsxGet_cookie() {
0472:
0473:                final HtmlPage page = getHtmlPage();
0474:                final HttpState state = page.getWebClient().getWebConnection()
0475:                        .getState();
0476:                final URL url = page.getWebResponse().getUrl();
0477:                final boolean secure = "https".equals(url.getProtocol());
0478:                final int port;
0479:                if (url.getPort() != -1) {
0480:                    port = url.getPort();
0481:                } else {
0482:                    port = url.getDefaultPort();
0483:                }
0484:
0485:                final CookieSpec spec = CookiePolicy
0486:                        .getCookieSpec(WebClient.HTMLUNIT_COOKIE_POLICY);
0487:                final Cookie[] cookies = spec.match(url.getHost(), port, url
0488:                        .getPath(), secure, state.getCookies());
0489:                if (cookies == null) {
0490:                    return "";
0491:                }
0492:
0493:                final StringBuffer buffer = new StringBuffer();
0494:
0495:                for (int i = 0; i < cookies.length; i++) {
0496:                    if (i != 0) {
0497:                        buffer.append(";");
0498:                    }
0499:                    buffer.append(cookies[i].getName());
0500:                    buffer.append("=");
0501:                    buffer.append(cookies[i].getValue());
0502:                }
0503:                return buffer.toString();
0504:            }
0505:
0506:            /**
0507:             * Adds a cookie.
0508:             * @see <a href="http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/cookie.asp">
0509:             * MSDN documentation</a>
0510:             * @param newCookie in the format "name=value[;expires=date][;domain=domainname][;path=path][;secure]
0511:             */
0512:            public void jsxSet_cookie(final String newCookie) {
0513:                final HttpState state = getHtmlPage().getWebClient()
0514:                        .getWebConnection().getState();
0515:
0516:                final Cookie cookie = buildCookie(newCookie, getHtmlPage()
0517:                        .getWebResponse().getUrl());
0518:                state.addCookie(cookie);
0519:                getLog().info("Added cookie: " + cookie);
0520:            }
0521:
0522:            /**
0523:             * Builds a cookie object from the string representation allowed in JS
0524:             * @param newCookie in the format "name=value[;expires=date][;domain=domainname][;path=path][;secure]
0525:             * @param currentURL the url of the current page
0526:             * @return the cookie
0527:             */
0528:            static Cookie buildCookie(final String newCookie,
0529:                    final URL currentURL) {
0530:                final StringTokenizer st = new StringTokenizer(newCookie, ";");
0531:                final String nameValue = st.nextToken();
0532:
0533:                final String name = StringUtils.substringBefore(nameValue, "=")
0534:                        .trim();
0535:                final String value = StringUtils.substringAfter(nameValue, "=")
0536:                        .trim();
0537:
0538:                final Map attributes = new HashMap();
0539:                // default values
0540:                attributes.put("domain", currentURL.getHost());
0541:                // default value "" as it seems that org.apache.commons.httpclient.cookie.CookieSpec
0542:                // doesn't like null as path
0543:                attributes.put("path", "");
0544:
0545:                while (st.hasMoreTokens()) {
0546:                    final String token = st.nextToken();
0547:                    final int indexEqual = token.indexOf("=");
0548:                    if (indexEqual > -1) {
0549:                        attributes.put(token.substring(0, indexEqual)
0550:                                .toLowerCase().trim(), token.substring(
0551:                                indexEqual + 1).trim());
0552:                    } else {
0553:                        attributes
0554:                                .put(token.toLowerCase().trim(), Boolean.TRUE);
0555:                    }
0556:                }
0557:
0558:                // Try to parse the <expires> value as a date if specified
0559:                Date expires = null;
0560:                final String date = (String) attributes.get("expires");
0561:                if (date != null) {
0562:                    try {
0563:                        expires = DateUtil.parseDate(date);
0564:                    } catch (final DateParseException e) {
0565:                        // nothing
0566:                    }
0567:                }
0568:
0569:                final String domain = (String) attributes.get("domain");
0570:                final String path = (String) attributes.get("path");
0571:                final boolean secure = (attributes.get("secure") != null);
0572:                final Cookie cookie = new Cookie(domain, name, value, path,
0573:                        expires, secure);
0574:
0575:                return cookie;
0576:            }
0577:
0578:            /**
0579:             * Return the value of the "location" property.
0580:             * @return The value of the "location" property
0581:             */
0582:            public Location jsxGet_location() {
0583:                return window_.jsxGet_location();
0584:            }
0585:
0586:            /**
0587:             * Sets the value of the "location" property. The location's default property is "href",
0588:             * so setting "document.location='http://www.sf.net'" is equivalent to setting
0589:             * "document.location.href='http://www.sf.net'".
0590:             * @see <a href="http://msdn.microsoft.com/workshop/author/dhtml/reference/objects/obj_location.asp">
0591:             * MSDN documentation</a>
0592:             * @param location the location to navigate to
0593:             * @throws IOException when location loading fails
0594:             */
0595:            public void jsxSet_location(final String location)
0596:                    throws IOException {
0597:                window_.jsxSet_location(location);
0598:            }
0599:
0600:            /**
0601:             * Return the value of the "images" property.
0602:             * @return The value of the "images" property
0603:             */
0604:            public Object jsxGet_images() {
0605:                if (images_ == null) {
0606:                    images_ = new HTMLCollection(this );
0607:                    try {
0608:                        images_.init(getDomNodeOrDie(), new HtmlUnitXPath(
0609:                                "//img"));
0610:                    } catch (final JaxenException e) {
0611:                        throw Context
0612:                                .reportRuntimeError("Failed to initialize collection document.images: "
0613:                                        + e.getMessage());
0614:                    }
0615:                }
0616:                return images_;
0617:            }
0618:
0619:            /**
0620:             * Return the value of the "referrer" property.
0621:             * @return The value of the "referrer" property
0622:             */
0623:            public String jsxGet_referrer() {
0624:                final String referrer = getHtmlPage().getWebResponse()
0625:                        .getResponseHeaderValue("referrer");
0626:                if (referrer == null) {
0627:                    return "";
0628:                } else {
0629:                    return referrer;
0630:                }
0631:            }
0632:
0633:            /**
0634:             * Return the value of the "URL" property.
0635:             * @return The value of the "URL" property
0636:             */
0637:            public String jsxGet_URL() {
0638:                return getHtmlPage().getWebResponse().getUrl().toExternalForm();
0639:            }
0640:
0641:            /**
0642:             * Return the value of the "all" property.
0643:             * @return The value of the "all" property
0644:             */
0645:            public HTMLCollection jsxGet_all() {
0646:                if (all_ == null) {
0647:                    all_ = new HTMLCollection(this );
0648:                    try {
0649:                        all_.init(getDomNodeOrDie(), new HtmlUnitXPath("//*"));
0650:                    } catch (final JaxenException e) {
0651:                        throw Context
0652:                                .reportRuntimeError("Failed to initialize collection document.all: "
0653:                                        + e.getMessage());
0654:                    }
0655:                }
0656:                return all_;
0657:            }
0658:
0659:            /**
0660:             * javascript function "open".
0661:             * @param context The javascript context
0662:             * @param scriptable The scriptable
0663:             * @param args The arguments passed into the method.
0664:             * @param function The function.
0665:             * @return Nothing
0666:             * @see <a href="http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/open_1.asp">
0667:             * MSDN documentation</a>
0668:             */
0669:            public static Object jsxFunction_open(final Context context,
0670:                    final Scriptable scriptable, final Object[] args,
0671:                    final Function function) {
0672:
0673:                final Document document = (Document) scriptable;
0674:                if (!document.writeInCurrentDocument_) {
0675:                    document.getLog().warn(
0676:                            "open() called when document is already open.");
0677:                }
0678:                document.writeInCurrentDocument_ = false;
0679:                return null;
0680:            }
0681:
0682:            /**
0683:             * javascript function "close".
0684:             * @throws IOException If an IO problem occurs.
0685:             */
0686:            public void jsxFunction_close() throws IOException {
0687:
0688:                if (writeInCurrentDocument_) {
0689:                    getLog().warn("close() called when document is not open.");
0690:                } else {
0691:                    final WebResponse webResponse = new StringWebResponse(
0692:                            writeBuffer_.toString());
0693:                    final HtmlPage page = getDomNodeOrDie().getPage();
0694:                    final WebClient webClient = page.getWebClient();
0695:                    final WebWindow window = page.getEnclosingWindow();
0696:
0697:                    webClient.loadWebResponseInto(webResponse, window);
0698:
0699:                    writeInCurrentDocument_ = true;
0700:                    writeBuffer_.setLength(0);
0701:                }
0702:            }
0703:
0704:            /**
0705:             * Get the JavaScript property "documentElement" for the document.
0706:             * @return The root node for the document.
0707:             */
0708:            public SimpleScriptable jsxGet_documentElement() {
0709:                return getScriptableFor(((HtmlPage) getDomNodeOrDie())
0710:                        .getDocumentHtmlElement());
0711:            }
0712:
0713:            /**
0714:             * Get the window in which this document is contained.
0715:             * @return the window
0716:             */
0717:            public Object jsxGet_defaultView() {
0718:                return getWindow();
0719:            }
0720:
0721:            /**
0722:             * Get the window in which this document is contained.
0723:             * @return the window
0724:             */
0725:            public Object jsxGet_parentWindow() {
0726:                return getWindow();
0727:            }
0728:
0729:            /**
0730:             * Create a new HTML element with the given tag name.
0731:             *
0732:             * @param tagName The tag name
0733:             * @return the new HTML element, or NOT_FOUND if the tag is not supported.
0734:             */
0735:            public Object jsxFunction_createElement(String tagName) {
0736:                Object result = NOT_FOUND;
0737:                try {
0738:                    final SgmlPage page = (SgmlPage) getDomNodeOrDie()
0739:                            .getNativePage();
0740:                    final BrowserVersion browserVersion = page.getWebClient()
0741:                            .getBrowserVersion();
0742:
0743:                    //IE can handle HTML
0744:                    if (tagName.startsWith("<") && browserVersion.isIE()) {
0745:                        try {
0746:                            final HtmlElement proxyNode = new HtmlDivision(
0747:                                    null, HtmlDivision.TAG_NAME,
0748:                                    getDomNodeOrDie().getPage(), null);
0749:                            HTMLParser.parseFragment(proxyNode, tagName);
0750:                            final DomNode resultNode = proxyNode
0751:                                    .getFirstDomChild();
0752:                            resultNode.removeAllChildren();
0753:                            result = resultNode.getScriptObject();
0754:                        } catch (final Exception e) {
0755:                            getLog()
0756:                                    .error(
0757:                                            "Unexpected exception occurred while parsing html snippet",
0758:                                            e);
0759:                            throw Context
0760:                                    .reportRuntimeError("Unexpected exception occurred while parsing html snippet: "
0761:                                            + e.getMessage());
0762:                        }
0763:                    } else {
0764:                        //Firefox handles only simple '<tagName>'
0765:                        if (tagName.startsWith("<") && tagName.endsWith(">")
0766:                                && browserVersion.isNetscape()) {
0767:                            tagName = tagName
0768:                                    .substring(1, tagName.length() - 1);
0769:                            if (!tagName.matches("\\w+")) {
0770:                                getLog()
0771:                                        .error(
0772:                                                "Unexpected exception occurred while parsing html snippet");
0773:                                throw Context
0774:                                        .reportRuntimeError("Unexpected exception occurred while parsing html snippet: "
0775:                                                + tagName);
0776:                            }
0777:                        }
0778:
0779:                        final DomNode element;
0780:                        if (page instanceof  HtmlPage) {
0781:                            element = ((HtmlPage) page)
0782:                                    .createHtmlElement(tagName);
0783:                        } else {
0784:                            element = ((XmlPage) page)
0785:                                    .createXmlElement(tagName);
0786:                        }
0787:                        final Object jsElement = getScriptableFor(element);
0788:
0789:                        if (jsElement == NOT_FOUND) {
0790:                            getLog()
0791:                                    .debug(
0792:                                            "createElement("
0793:                                                    + tagName
0794:                                                    + ") cannot return a result as there isn't a javascript object for the element "
0795:                                                    + element.getClass()
0796:                                                            .getName());
0797:                        } else {
0798:                            result = jsElement;
0799:                        }
0800:                    }
0801:                } catch (final ElementNotFoundException e) {
0802:                    // Just fall through - result is already set to NOT_FOUND
0803:                }
0804:                return result;
0805:            }
0806:
0807:            /**
0808:             * Create a new HTML element with the given tag name, and name
0809:             *
0810:             * @param namespaceURI the URI that identifies an XML namespace.
0811:             * @param qualifiedName The qualified name of the element type to instantiate
0812:             * @return the new HTML element, or NOT_FOUND if the tag is not supported.
0813:             */
0814:            public Object jsxFunction_createElementNS(
0815:                    final String namespaceURI, final String qualifiedName) {
0816:                Object result = NOT_FOUND;
0817:                try {
0818:                    final HtmlElement htmlElement = getDomNodeOrDie().getPage()
0819:                            .createHtmlElementNS(namespaceURI, qualifiedName);
0820:                    final Object jsElement = getScriptableFor(htmlElement);
0821:
0822:                    if (jsElement == NOT_FOUND) {
0823:                        getLog()
0824:                                .debug(
0825:                                        "createElementNS("
0826:                                                + namespaceURI
0827:                                                + ','
0828:                                                + qualifiedName
0829:                                                + ") cannot return a result as there isn't a javascript object for the html element "
0830:                                                + htmlElement.getClass()
0831:                                                        .getName());
0832:                    } else {
0833:                        result = jsElement;
0834:                    }
0835:                } catch (final ElementNotFoundException e) {
0836:                    // Just fall through - result is already set to NOT_FOUND
0837:                }
0838:                return result;
0839:            }
0840:
0841:            /**
0842:             * Create a new DocumentFragment
0843:             * @return a newly created DocumentFragment.
0844:             */
0845:            public Object jsxFunction_createDocumentFragment() {
0846:                final DomDocumentFragment fragment = ((SgmlPage) getDomNodeOrDie()
0847:                        .getNativePage()).createDomDocumentFragment();
0848:                final DocumentFragment node = new DocumentFragment();
0849:                node.setParentScope(getParentScope());
0850:                node.setPrototype(getPrototype(node.getClass()));
0851:                node.setDomNode(fragment);
0852:                return getScriptableFor(fragment);
0853:            }
0854:
0855:            /**
0856:             * Creates a new HTML attribute with the specified name.
0857:             *
0858:             * @param attributeName the name of the attribute to create
0859:             * @return an attribute with the specified name.
0860:             */
0861:            public Attribute jsxFunction_createAttribute(
0862:                    final String attributeName) {
0863:                final Attribute att = new Attribute();
0864:                att.setPrototype(getPrototype(Attribute.class));
0865:                att.setParentScope(getWindow());
0866:                att.init(attributeName, null);
0867:                return att;
0868:            }
0869:
0870:            /**
0871:             * Creates a new Stylesheet.
0872:             * Current implementation just creates an empty {@link Stylesheet} object.
0873:             * @param url the stylesheet url
0874:             * @param index where to insert the sheet in the collection
0875:             * @return the newly created stylesheet
0876:             */
0877:            public Stylesheet jsxFunction_createStyleSheet(final String url,
0878:                    final int index) {
0879:                // minimal implementation
0880:                final Stylesheet stylesheet = new Stylesheet();
0881:                stylesheet.setPrototype(getPrototype(Stylesheet.class));
0882:                stylesheet.setParentScope(getWindow());
0883:
0884:                return stylesheet;
0885:            }
0886:
0887:            /**
0888:             * Create a new DOM text node with the given data.
0889:             *
0890:             * @param newData The string value for the text node.
0891:             * @return the new text node or NOT_FOUND if there is an error.
0892:             */
0893:            public Object jsxFunction_createTextNode(final String newData) {
0894:                Object result = NOT_FOUND;
0895:                try {
0896:                    final DomNode domNode = new DomText(getDomNodeOrDie()
0897:                            .getNativePage(), newData);
0898:                    final Object jsElement = getScriptableFor(domNode);
0899:
0900:                    if (jsElement == NOT_FOUND) {
0901:                        getLog()
0902:                                .debug(
0903:                                        "createTextNode("
0904:                                                + newData
0905:                                                + ") cannot return a result as there isn't a javascript object for the DOM node "
0906:                                                + domNode.getClass().getName());
0907:                    } else {
0908:                        result = jsElement;
0909:                    }
0910:                } catch (final ElementNotFoundException e) {
0911:                    // Just fall through - result is already set to NOT_FOUND
0912:                }
0913:                return result;
0914:            }
0915:
0916:            /**
0917:             * Returns the {@link BoxObject} for the specific element.
0918:             *
0919:             * @param element target for BoxObject.
0920:             * @return the BoxObject
0921:             */
0922:            public BoxObject jsxFunction_getBoxObjectFor(
0923:                    final HTMLElement element) {
0924:                return element.getBoxObject();
0925:            }
0926:
0927:            /**
0928:             * Return the element with the specified id or null if that element could
0929:             * not be found
0930:             * @param id The ID to search for
0931:             * @return the element or null
0932:             */
0933:            public Object jsxFunction_getElementById(final String id) {
0934:                Object result = null;
0935:                try {
0936:                    final HtmlElement htmlElement = ((HtmlPage) getDomNodeOrDie())
0937:                            .getDocumentHtmlElement().getHtmlElementById(id);
0938:                    final Object jsElement = getScriptableFor(htmlElement);
0939:
0940:                    if (jsElement == NOT_FOUND) {
0941:                        getLog()
0942:                                .debug(
0943:                                        "getElementById("
0944:                                                + id
0945:                                                + ") cannot return a result as there isn't a javascript object for the html element "
0946:                                                + htmlElement.getClass()
0947:                                                        .getName());
0948:                    } else {
0949:                        result = jsElement;
0950:                    }
0951:                } catch (final ElementNotFoundException e) {
0952:                    // Just fall through - result is already set to null
0953:
0954:                    final BrowserVersion browser = getHtmlPage().getWebClient()
0955:                            .getBrowserVersion();
0956:                    if (browser.isIE()) {
0957:                        final HTMLCollection elements = (HTMLCollection) jsxFunction_getElementsByName(id);
0958:                        result = elements.get(0, elements);
0959:                        if (result instanceof  UniqueTag) {
0960:                            return null;
0961:                        }
0962:                        getLog()
0963:                                .warn(
0964:                                        "getElementById("
0965:                                                + id
0966:                                                + ") did a getElementByName for Internet Explorer");
0967:                        return result;
0968:                    }
0969:                    getLog().debug(
0970:                            "getElementById(" + id
0971:                                    + "): no DOM node found with this id");
0972:                }
0973:                return result;
0974:            }
0975:
0976:            /**
0977:             * Returns all the descendant elements with the specified tag name.
0978:             * @param tagName the name to search for
0979:             * @return all the descendant elements with the specified tag name
0980:             */
0981:            public Object jsxFunction_getElementsByTagName(final String tagName) {
0982:                final HTMLCollection collection = new HTMLCollection(this );
0983:                try {
0984:                    final String xpath = "//" + tagName.toLowerCase();
0985:                    collection
0986:                            .init(getDomNodeOrDie(), new HtmlUnitXPath(xpath));
0987:                } catch (final JaxenException e) {
0988:                    final String msg = "Error initializing collection getElementsByTagName("
0989:                            + tagName + "): ";
0990:                    throw Context.reportRuntimeError(msg + e.getMessage());
0991:                }
0992:                return collection;
0993:            }
0994:
0995:            /**
0996:             * Returns all HTML elements that have a "name" attribute with the given value.
0997:             *
0998:             * Refer to <a href="http://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-71555259">
0999:             * The DOM spec</a> for details.
1000:             *
1001:             * @param elementName - value of the "name" attribute to look for
1002:             * @return NodeList of elements
1003:             */
1004:            public Object jsxFunction_getElementsByName(final String elementName) {
1005:                final HTMLCollection collection = new HTMLCollection(this );
1006:                final String exp = "//*[@name='" + elementName + "']";
1007:                try {
1008:                    final HtmlUnitXPath xpath = new HtmlUnitXPath(exp);
1009:                    collection.init(getDomNodeOrDie(), xpath);
1010:                } catch (final JaxenException e) {
1011:                    throw Context
1012:                            .reportRuntimeError("Failed to initialize collection document.getElementsByName: "
1013:                                    + e.getMessage());
1014:                }
1015:                return collection;
1016:            }
1017:
1018:            /**
1019:             * Calls to <tt>document.XYZ</tt> should first look at elements named <tt>XYZ</tt> before
1020:             * using standard functions.
1021:             *
1022:             * {@inheritDoc}
1023:             */
1024:            protected Object getWithPreemption(final String name) {
1025:                final HtmlPage page = (HtmlPage) getDomNodeOrNull();
1026:                if (page == null) {
1027:                    return NOT_FOUND;
1028:                }
1029:                // Try to satisfy this request using a map-backed operation before punting and using XPath.
1030:                // XPath operations are very expensive, and this method gets invoked quite a bit.
1031:                // This little shortcut shaves ~35% off the build time (3 min -> 2 min, as of 8/10/2007).
1032:                final List elements = page.getHtmlElementsByName(name);
1033:                if (elements.isEmpty()) {
1034:                    return NOT_FOUND;
1035:                }
1036:                if (elements.size() == 1) {
1037:                    final HtmlElement element = (HtmlElement) elements.get(0);
1038:                    final String tagName = element.getTagName();
1039:                    if (HtmlImage.TAG_NAME.equals(tagName)
1040:                            || HtmlForm.TAG_NAME.equals(tagName)) {
1041:                        return getScriptableFor(element);
1042:                    } else {
1043:                        return NOT_FOUND;
1044:                    }
1045:                }
1046:                // The shortcut wasn't enough, which means we probably need to perform the XPath operation anyway.
1047:                // Note that the XPath expression below HAS TO MATCH the tag name checks performed in the shortcut above.
1048:                // TODO: Behavior for iframe seems to differ between IE and Moz.
1049:                final HTMLCollection collection = new HTMLCollection(this );
1050:                final String xpath = "//*[(@name = '" + name
1051:                        + "' and (name() = 'img' or name() = 'form'))]";
1052:                try {
1053:                    collection.init(page, new HtmlUnitXPath(xpath));
1054:                } catch (final JaxenException e) {
1055:                    final String msg = "Failed to initialize collection (using xpath "
1056:                            + xpath + "): " + e.getMessage();
1057:                    throw Context.reportRuntimeError(msg);
1058:                }
1059:                final int size = collection.jsxGet_length();
1060:                if (size == 1) {
1061:                    return collection.get(0, collection);
1062:                } else if (size > 1) {
1063:                    return collection;
1064:                }
1065:                return NOT_FOUND;
1066:            }
1067:
1068:            /**
1069:             * Returns this document's <tt>body</tt> element.
1070:             * @return this document's <tt>body</tt> element
1071:             */
1072:            public Object jsxGet_body() {
1073:                final List tagNames = Arrays.asList(new String[] { "body",
1074:                        "frameset" });
1075:                final List list = getHtmlPage().getDocumentHtmlElement()
1076:                        .getHtmlElementsByTagNames(tagNames);
1077:                if (list.isEmpty()) {
1078:                    return NOT_FOUND;
1079:                } else {
1080:                    final DomNode bodyElement = (DomNode) list.get(0);
1081:                    return getScriptableFor(bodyElement);
1082:                }
1083:            }
1084:
1085:            /**
1086:             * Returns this document's title.
1087:             * @return this document's title
1088:             */
1089:            public String jsxGet_title() {
1090:                return getHtmlPage().getTitleText();
1091:            }
1092:
1093:            /**
1094:             * Sets this document's title.
1095:             * @param title the new title
1096:             */
1097:            public void jsxSet_title(final String title) {
1098:                getHtmlPage().setTitleText(title);
1099:            }
1100:
1101:            /**
1102:             * Returns the ready state of the document. This is an IE-only property.
1103:             * @return The ready state of the document.
1104:             * @see DomNode#READY_STATE_UNINITIALIZED
1105:             * @see DomNode#READY_STATE_LOADING
1106:             * @see DomNode#READY_STATE_LOADED
1107:             * @see DomNode#READY_STATE_INTERACTIVE
1108:             * @see DomNode#READY_STATE_COMPLETE
1109:             */
1110:            public String jsxGet_readyState() {
1111:                final DomNode node = getDomNodeOrDie();
1112:                if (node instanceof  HtmlPage) {
1113:                    return ((HtmlPage) node).getDocumentHtmlElement()
1114:                            .getReadyState();
1115:                } else {
1116:                    return node.getReadyState();
1117:                }
1118:            }
1119:
1120:            /**
1121:             * The domain name of the server that served the document,
1122:             * or null if the server cannot be identified by a domain name.
1123:             * @return domain name
1124:             * @see <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-2250147">
1125:             * W3C documentation</a>
1126:             */
1127:            public String jsxGet_domain() {
1128:                if (domain_ == null) {
1129:                    domain_ = getHtmlPage().getWebResponse().getUrl().getHost();
1130:                    final BrowserVersion browser = getHtmlPage().getWebClient()
1131:                            .getBrowserVersion();
1132:                    if (browser.isNetscape()) {
1133:                        domain_ = domain_.toLowerCase();
1134:                    }
1135:                }
1136:
1137:                return domain_;
1138:            }
1139:
1140:            /**
1141:             * Set the the domain of this document.
1142:             *
1143:             * Domains can only be set to suffixes of the existing domain
1144:             * with the exception of setting the domain to itself.
1145:             * <p>
1146:             * The domain will be set according to the following rules:
1147:             * <ol>
1148:             * <li>If the newDomain.equalsIgnoreCase(currentDomain) the method returns with no error.</li>
1149:             * <li>If the browser version is netscape, the newDomain is downshifted.</li>
1150:             * <li>The change will take place if and only if the suffixes of the
1151:             *       current domain and the new domain match AND there are at least
1152:             *       two domain qualifiers e.g. the following transformations are legal
1153:             *       d1.d2.d3.gargoylesoftware.com may be transformed to itself or:
1154:             *          d2.d3.gargoylesoftware.com
1155:             *             d3.gargoylesoftware.com
1156:             *                gargoylesoftware.com
1157:             *
1158:             *        transformation to:        com
1159:             *        will fail
1160:             * </li>
1161:             * </ol>
1162:             * </p>
1163:             * TODO This code could be modified to understand country domain suffixes.
1164:             * The domain www.bbc.co.uk should be trimmable only down to bbc.co.uk
1165:             * trimming to co.uk should not be possible.
1166:             * @param newDomain the new domain to set
1167:             */
1168:            public void jsxSet_domain(final String newDomain) {
1169:                final String currentDomain = jsxGet_domain();
1170:                if (currentDomain.equalsIgnoreCase(newDomain)) {
1171:                    return;
1172:                }
1173:
1174:                if (newDomain.indexOf(".") == -1
1175:                        || !currentDomain.toLowerCase().endsWith(
1176:                                "." + newDomain.toLowerCase())) {
1177:                    throw Context
1178:                            .reportRuntimeError("Illegal domain value, can not set domain from: \""
1179:                                    + currentDomain
1180:                                    + "\" to: \""
1181:                                    + newDomain
1182:                                    + "\"");
1183:                }
1184:
1185:                // Netscape down shifts the case of the domain
1186:                if (getHtmlPage().getWebClient().getBrowserVersion()
1187:                        .isNetscape()) {
1188:                    domain_ = newDomain.toLowerCase();
1189:                } else {
1190:                    domain_ = newDomain;
1191:                }
1192:            }
1193:
1194:            /**
1195:             * Return the value of the javascript attribute "scripts".
1196:             * @return The value of this attribute.
1197:             */
1198:            public Object jsxGet_scripts() {
1199:                if (scripts_ == null) {
1200:                    scripts_ = new HTMLCollection(this );
1201:                    try {
1202:                        scripts_.init(getDomNodeOrDie(), new HtmlUnitXPath(
1203:                                "//script"));
1204:                    } catch (final JaxenException e) {
1205:                        throw Context
1206:                                .reportRuntimeError("Failed to initialize collection document.scripts: "
1207:                                        + e.getMessage());
1208:                    }
1209:                }
1210:                return scripts_;
1211:            }
1212:
1213:            /**
1214:             * Return the value of the frames property.
1215:             * @see <a href="http://msdn.microsoft.com/workshop/author/dhtml/reference/collections/frames.asp">
1216:             * MSDN documentation</a>
1217:             * @return The live collection of frames
1218:             */
1219:            public Object jsxGet_frames() {
1220:                return getWindow().jsxGet_frames();
1221:            }
1222:
1223:            /**
1224:             * Returns the implementation object of the current document.
1225:             * @return implementation-specific object.
1226:             */
1227:            public DOMImplementation jsxGet_implementation() {
1228:                if (implementation_ == null) {
1229:                    implementation_ = new DOMImplementation();
1230:                    implementation_.setParentScope(getWindow());
1231:                    implementation_.setPrototype(getPrototype(implementation_
1232:                            .getClass()));
1233:                }
1234:                return implementation_;
1235:            }
1236:
1237:            /**
1238:             * Retrieves a collection of styleSheet objects representing the style sheets that correspond
1239:             * to each instance of a Link or {@link Style} object in the document.
1240:             *
1241:             * @return styleSheet collection.
1242:             */
1243:            public Object jsxGet_styleSheets() {
1244:                if (styleSheets_ == null) {
1245:                    styleSheets_ = new StyleSheetList(this );
1246:                }
1247:                return styleSheets_;
1248:            }
1249:
1250:            /**
1251:             * Implementation of the {@link DocumentEvent} interface's
1252:             * {@link org.w3c.dom.events.DocumentEvent#createEvent(String)} method. The method creates an
1253:             * event of the specified type.
1254:             *
1255:             * @link http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-DocumentEvent
1256:             * @param eventType The event type to create.
1257:             * @return The associated event object for that type. The event object will NOT have had its
1258:             *         initialization method called. It is up to the caller of the method to initialize the
1259:             *         event.
1260:             * @throws DOMException Thrown if the event type is not supported. The DOMException will have a
1261:             *         type of DOMException.NOT_SUPPORTED_ERR
1262:             */
1263:            public Event jsxFunction_createEvent(final String eventType)
1264:                    throws DOMException {
1265:                final Class clazz = (Class) SUPPORTED_EVENT_TYPE_MAP
1266:                        .get(eventType);
1267:                if (clazz == null) {
1268:                    throw new DOMException(DOMException.NOT_SUPPORTED_ERR,
1269:                            "Event Type is not supported: " + eventType);
1270:                }
1271:                try {
1272:                    final Event event = (Event) clazz.newInstance();
1273:                    event.setEventType(eventType);
1274:                    event.setParentScope(getWindow());
1275:                    event.setPrototype(getPrototype(clazz));
1276:                    return event;
1277:                } catch (final InstantiationException e) {
1278:                    throw Context
1279:                            .reportRuntimeError("Failed to instantiate event: class ='"
1280:                                    + clazz.getName()
1281:                                    + "' for event type of '"
1282:                                    + eventType + "': " + e.getMessage());
1283:                } catch (final IllegalAccessException e) {
1284:                    throw Context
1285:                            .reportRuntimeError("Failed to instantiate event: class ='"
1286:                                    + clazz.getName()
1287:                                    + "' for event type of '"
1288:                                    + eventType + "': " + e.getMessage());
1289:                }
1290:            }
1291:
1292:            /**
1293:             * Implementation of the <tt>createEventObject</tt> method supported by Internet Explorer.
1294:             *
1295:             * @link http://msdn2.microsoft.com/en-us/library/ms536390.aspx
1296:             * @return An instance of the event object.  The event object will NOT have its
1297:             *         member variables initialized.  It is up to the caller of the method to initialize
1298:             *         the properties of the event.
1299:             */
1300:            public Event jsxFunction_createEventObject() {
1301:                final Event event = new Event();
1302:                event.setParentScope(getWindow());
1303:                event.setPrototype(getPrototype(event.getClass()));
1304:                return event;
1305:            }
1306:
1307:            /**
1308:             * Returns the element for the specified x coordinate and the specified y coordinate.
1309:             * The current implementation returns the &lt;body&gt; element.
1310:             *
1311:             * @param x Specifies the X-offset, in pixels.
1312:             * @param y Specifies the Y-offset, in pixels.
1313:             *
1314:             * @return the element for the specified x coordinate and the specified y coordinate.
1315:             */
1316:            public Object jsxFunction_elementFromPoint(final int x, final int y) {
1317:                return jsxGet_body();
1318:            }
1319:
1320:            /**
1321:             * Create a new range.
1322:             * @return the range.
1323:             * @see <a href="http://www.xulplanet.com/references/objref/HTMLDocument.html#method_createRange">
1324:             * XUL Planet</a>
1325:             */
1326:            public Object jsxFunction_createRange() {
1327:                final Range r = new Range();
1328:                r.setParentScope(getWindow());
1329:                r.setPrototype(getPrototype(Range.class));
1330:                return r;
1331:            }
1332:
1333:            /**
1334:             * Adapts any DOM node to resolve namespaces so that an XPath expression
1335:             * can be easily evaluated relative to the context of the node where it appeared within the document.
1336:             * @param nodeResolver The node to be used as a context for namespace resolution.
1337:             * @return XPathNSResolver which resolves namespaces with respect to the definitions in scope for a specified node.
1338:             */
1339:            public XPathNSResolver jsxFunction_createNSResolver(
1340:                    final Node nodeResolver) {
1341:                final XPathNSResolver resolver = new XPathNSResolver();
1342:                resolver.setElement(nodeResolver);
1343:                resolver.setParentScope(getWindow());
1344:                resolver.setPrototype(getPrototype(resolver.getClass()));
1345:                return resolver;
1346:            }
1347:
1348:            /**
1349:             * Evaluates an XPath expression string and returns a result of the specified type if possible.
1350:             * @param expression The XPath expression string to be parsed and evaluated.
1351:             * @param contextNode The context node for the evaluation of this XPath expression.
1352:             * @param resolver The resolver permits translation of all prefixes, including the xml namespace prefix,
1353:             *        within the XPath expression into appropriate namespace URIs.
1354:             * @param type If a specific type is specified, then the result will be returned as the corresponding type.
1355:             * @param result The result object which may be reused and returned by this method.
1356:             * @return The result of the evaluation of the XPath expression.
1357:             */
1358:            public XPathResult jsxFunction_evaluate(final String expression,
1359:                    final Node contextNode, final Object resolver,
1360:                    final int type, final Object result) {
1361:                XPathResult xPathResult = (XPathResult) result;
1362:
1363:                try {
1364:                    if (xPathResult == null) {
1365:                        xPathResult = new XPathResult();
1366:                        xPathResult.setPrototype(getPrototype(xPathResult
1367:                                .getClass()));
1368:                    }
1369:                    xPathResult.init(contextNode.getDomNodeOrDie().getByXPath(
1370:                            expression), type);
1371:                } catch (final JaxenException e) {
1372:                    throw Context.reportRuntimeError("Error using exression: "
1373:                            + expression);
1374:                }
1375:                return xPathResult;
1376:            }
1377:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.