KickJava   Java API By Example, From Geeks To Geeks.

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


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.MalformedURLException JavaDoc;
42 import java.net.URL JavaDoc;
43 import java.util.ArrayList JavaDoc;
44 import java.util.Arrays JavaDoc;
45 import java.util.Collection JavaDoc;
46 import java.util.Collections JavaDoc;
47 import java.util.Iterator JavaDoc;
48 import java.util.List JavaDoc;
49 import java.util.Map JavaDoc;
50
51 import org.apache.commons.collections.CollectionUtils;
52 import org.jaxen.JaxenException;
53 import org.jaxen.XPath;
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.xml.sax.helpers.AttributesImpl JavaDoc;
59
60 import com.gargoylesoftware.htmlunit.Page;
61 import com.gargoylesoftware.htmlunit.StringWebResponse;
62 import com.gargoylesoftware.htmlunit.WebClient;
63 import com.gargoylesoftware.htmlunit.WebResponse;
64 import com.gargoylesoftware.htmlunit.WebWindow;
65 import com.gargoylesoftware.htmlunit.html.DomCharacterData;
66 import com.gargoylesoftware.htmlunit.html.DomNode;
67 import com.gargoylesoftware.htmlunit.html.DomText;
68 import com.gargoylesoftware.htmlunit.html.HTMLParser;
69 import com.gargoylesoftware.htmlunit.html.HtmlBody;
70 import com.gargoylesoftware.htmlunit.html.HtmlElement;
71 import com.gargoylesoftware.htmlunit.html.HtmlPage;
72 import com.gargoylesoftware.htmlunit.html.IElementFactory;
73 import com.gargoylesoftware.htmlunit.html.xpath.HtmlUnitXPath;
74 import com.gargoylesoftware.htmlunit.javascript.ElementArray;
75
76 /**
77  * The javascript object "HTMLElement" which is the base class for all html
78  * objects. This will typically wrap an instance of {@link HtmlElement}.
79  *
80  * @version $Revision: 100 $
81  * @author <a HREF="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
82  * @author David K. Taylor
83  * @author Barnaby Court
84  * @author <a HREF="mailto:cse@dynabean.de">Christian Sell</a>
85  * @author Chris Erskine
86  * @author David D. Kilzer
87  * @author Daniel Gredler
88  * @author Marc Guillemot
89  * @author Hans Donner
90  */

91 public class HTMLElement extends NodeImpl {
92     private static final long serialVersionUID = -6864034414262085851L;
93     private static final int BEHAVIOR_ID_UNKNOWN = -1;
94     private static final int BEHAVIOR_ID_CLIENT_CAPS = 0;
95     private static final int BEHAVIOR_ID_HOMEPAGE = 1;
96     private static final String JavaDoc BEHAVIOR_CLIENT_CAPS = "#default#clientCaps";
97     private static final String JavaDoc BEHAVIOR_HOMEPAGE = "#default#homePage";
98     static final String JavaDoc POSITION_BEFORE_BEGIN = "beforeBegin";
99     static final String JavaDoc POSITION_AFTER_BEGIN = "afterBegin";
100     static final String JavaDoc POSITION_BEFORE_END = "beforeEnd";
101     static final String JavaDoc POSITION_AFTER_END = "afterEnd";
102
103     /**
104      * The tag names of the objects for which outerHTML is readonly
105      */

106     private static final List JavaDoc OUTER_HTML_READONLY =
107         Arrays.asList(new String JavaDoc[] {
108             "caption", "col", "colgroup", "frameset", "html",
109             "tbody", "td", "tfoot", "th", "thead", "tr"});
110
111     private Style style_;
112
113     /**
114      * Create an instance.
115      */

116     public HTMLElement() {
117     }
118
119
120     /**
121      * Javascript constructor. This must be declared in every javascript file because
122      * the rhino engine won't walk up the hierarchy looking for constructors.
123      */

124     public void jsConstructor() {
125     }
126
127
128     /**
129      * Return the style object for this element.
130      *
131      * @return The style object
132      */

133     public Object JavaDoc jsxGet_style() {
134         return style_;
135     }
136
137
138     /**
139      * Set the DOM node that corresponds to this javascript object
140      * @param domNode The DOM node
141      */

142     public void setDomNode( final DomNode domNode ) {
143         super.setDomNode(domNode);
144
145         style_ = (Style)makeJavaScriptObject("Style");
146         style_.initialize(this);
147     }
148
149
150     /**
151      * Return the element ID.
152      * @return The ID of this element.
153      */

154     public String JavaDoc jsxGet_id() {
155         return getHtmlElementOrDie().getId();
156     }
157
158
159     /**
160      * Set the identifier this element.
161      *
162      * @param newId The new identifier of this element.
163      */

164     public void jsxSet_id( final String JavaDoc newId ) {
165         getHtmlElementOrDie().setId( newId );
166     }
167
168
169     /**
170      * Return true if this element is disabled.
171      * @return True if this element is disabled.
172      */

173     public boolean jsxGet_disabled() {
174         return getHtmlElementOrDie().isAttributeDefined("disabled");
175     }
176
177
178     /**
179      * Set whether or not to disable this element
180      * @param disabled True if this is to be disabled.
181      */

182     public void jsxSet_disabled( final boolean disabled ) {
183         final HtmlElement element = getHtmlElementOrDie();
184         if( disabled ) {
185             element.setAttributeValue("disabled", "disabled");
186         }
187         else {
188             element.removeAttribute("disabled");
189         }
190     }
191
192
193     /**
194      * Return the tag name of this element
195      * @return The tag name in uppercase
196      */

197     public String JavaDoc jsxGet_tagName() {
198         return getHtmlElementOrDie().getTagName().toUpperCase();
199     }
200
201
202     /**
203      * Return the value of the named attribute.
204      * @param name The name of the variable
205      * @param start The scriptable to get the variable from.
206      * @return The attribute value
207      */

208     public Object JavaDoc get( final String JavaDoc name, final Scriptable start ) {
209         Object JavaDoc result = super.get( name, start );
210         if ( result == NOT_FOUND ) {
211             final HtmlElement htmlElement = getHtmlElementOrNull();
212             // can name be an attribute of current element?
213
// first approximation: attribute are all lowercase
214
// this should be improved because it's wrong. For instance: tabIndex, hideFocus, acceptCharset
215
if ( htmlElement != null && name.toLowerCase().equals(name)) {
216                 final String JavaDoc value = htmlElement.getAttributeValue(name);
217                 if (HtmlElement.ATTRIBUTE_NOT_DEFINED != value) {
218                     getLog().debug("Found attribute for evalution of property \"" + name
219                             + "\" for of " + start);
220                     result = value;
221                 }
222             }
223         }
224         
225         return result;
226     }
227
228     /**
229      * Gets the specified property.
230      * @param attributeName attribute name.
231      * @return The value of the specified attribute, <code>null</code> if the attribute is not defined
232      */

233     public String JavaDoc jsxFunction_getAttribute(final String JavaDoc attributeName) {
234         final String JavaDoc value = getHtmlElementOrDie().getAttributeValue(attributeName);
235         if (value == HtmlElement.ATTRIBUTE_NOT_DEFINED) {
236             return null;
237         }
238         else {
239             return value;
240         }
241     }
242
243     /**
244      * Set an attribute.
245      * See also <a HREF="http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-F68F082">
246      * the DOM reference</a>
247      *
248      * @param name Name of the attribute to set
249      * @param value Value to set the attribute to
250      */

251     public void jsxFunction_setAttribute(final String JavaDoc name, final String JavaDoc value) {
252         getHtmlElementOrDie().setAttributeValue(name, value);
253     }
254
255     /**
256      * Remove an attribute.
257      *
258      * @param name Name of the attribute to remove
259      */

260     public void jsxFunction_removeAttribute(final String JavaDoc name) {
261         getHtmlElementOrDie().removeAttribute(name);
262     }
263
264     /**
265      * Gets the attribute node for the specified attribute.
266      * @param attributeName the name of the attribute to retrieve
267      * @return the attribute node for the specified attribute.
268      */

269     public Object JavaDoc jsxFunction_getAttributeNode(final String JavaDoc attributeName) {
270         final Attribute att = (Attribute) makeJavaScriptObject(Attribute.JS_OBJECT_NAME);
271         att.init(attributeName, getHtmlElementOrDie());
272         return att;
273     }
274
275     /**
276      * Sets the attribute node for the specified attribute.
277      * @param newAtt the attribute to set.
278      * @return the replaced attribute node, if any.
279      */

280     public Attribute jsxFunction_setAttributeNode(final Attribute newAtt) {
281         final String JavaDoc name = newAtt.jsxGet_name();
282         final String JavaDoc value = newAtt.jsxGet_value();
283         final Attribute replacedAtt = (Attribute) jsxFunction_getAttributeNode(name);
284         replacedAtt.detachFromParent();
285         getHtmlElementOrDie().setAttributeValue(name, value);
286         return replacedAtt;
287     }
288
289     /**
290      * Return all the elements with the specified tag name
291      * @param tagName The name to search for
292      * @return the list of elements
293      */

294     public Object JavaDoc jsxFunction_getElementsByTagName( final String JavaDoc tagName ) {
295         final HtmlElement element = (HtmlElement)getDomNodeOrDie();
296         final List JavaDoc list = element.getHtmlElementsByTagNames(
297             Collections.singletonList(tagName.toLowerCase()));
298
299         CollectionUtils.transform(list, getTransformerScriptableFor());
300
301         return new NativeArray( list.toArray() );
302     }
303     
304     /**
305      * Return the class defined for this element
306      * @return the class name
307      */

308     public Object JavaDoc jsxGet_className() {
309         return getHtmlElementOrDie().getAttributeValue("class");
310     }
311
312     /**
313      * Set the class attribute for this element.
314      * @param className - the new class name
315      */

316     public void jsxSet_className(final String JavaDoc className) {
317         getHtmlElementOrDie().setAttributeValue("class", className);
318     }
319     
320     /**
321      * Get the innerHTML attribute
322      * @return the contents of this node as html
323      */

324     public String JavaDoc jsxGet_innerHTML() {
325         final StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
326         // we can't rely on DomNode.asXml because it adds indentation and new lines
327
printChildren(buf, getDomNodeOrDie());
328
329         return buf.toString();
330     }
331
332     /**
333      * Get the innerText attribute
334      * @return the contents of this node as text
335      */

336     public String JavaDoc jsxGet_innerText() {
337         final StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
338         // we can't rely on DomNode.asXml because it adds indentation and new lines
339
printChildren(buf, getDomNodeOrDie(), false);
340
341         return buf.toString();
342     }
343     
344     
345     /**
346      * Gets the outerHTML of the node.
347      * @see <a HREF="http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/outerhtml.asp">
348      * MSDN documentation</a>
349      * @return the contents of this node as html
350      * (note: the formatting isn't currently exactly the same as IE)
351      */

352     public String JavaDoc jsxGet_outerHTML() {
353         final StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
354         // we can't rely on DomNode.asXml because it adds indentation and new lines
355
printNode(buf, getDomNodeOrDie());
356
357         return buf.toString();
358     }
359
360     private void printChildren(final StringBuffer JavaDoc buffer, final DomNode node) {
361         printChildren(buffer, node, true);
362     }
363     
364     private void printChildren(final StringBuffer JavaDoc buffer, final DomNode node, final boolean asInnerHTML) {
365         for (final Iterator JavaDoc iter = node.getChildIterator(); iter.hasNext();) {
366             printNode(buffer, (DomNode) iter.next(), asInnerHTML);
367         }
368     }
369    
370     private void printNode(final StringBuffer JavaDoc buffer, final DomNode node) {
371         printNode(buffer, node, true);
372     }
373     
374     private void printNode(
375             final StringBuffer JavaDoc buffer, final DomNode node,
376             final boolean asInnerHTML) {
377         if (node instanceof DomCharacterData) {
378             buffer.append(node.getNodeValue().replaceAll(" ", " ")); // remove white space sequences
379
}
380         else if (asInnerHTML) {
381             final HtmlElement htmlElt = (HtmlElement) node;
382             buffer.append("<");
383             buffer.append(htmlElt.getTagName());
384             
385             // the attributes
386
for (final Iterator JavaDoc iterator=htmlElt.getAttributeEntriesIterator(); iterator.hasNext(); ) {
387                 buffer.append(' ' );
388                 final Map.Entry JavaDoc entry = (Map.Entry JavaDoc) iterator.next();
389                 buffer.append(entry.getKey());
390                 buffer.append( "=\"" );
391                 buffer.append(entry.getValue());
392                 buffer.append( "\"" );
393             }
394             if (htmlElt.getFirstChild() == null) {
395                 buffer.append("/");
396             }
397             buffer.append(">");
398             
399             printChildren(buffer, node, asInnerHTML);
400             if (htmlElt.getFirstChild() != null) {
401                 buffer.append("</");
402                 buffer.append(htmlElt.getTagName());
403                 buffer.append(">");
404             }
405         }
406         else {
407             final HtmlElement htmlElement = (HtmlElement) node;
408             if (htmlElement.getTagName().equals("p")) {
409                 buffer.append("\r\n"); // \r\n because it's to implement something IE specific
410
}
411
412             if (!htmlElement.getTagName().equals("script")) {
413                 printChildren(buffer, node, asInnerHTML);
414             }
415
416         }
417     }
418
419     /**
420      * Replace all children elements of this element with the supplied value.
421      * @param value - the new value for the contents of this node
422      */

423     public void jsxSet_innerHTML(final String JavaDoc value) {
424         final DomNode domNode = getDomNodeOrDie();
425         domNode.removeAllChildren();
426
427         for (final Iterator JavaDoc iter = parseHtmlSnippet(value).iterator(); iter.hasNext();) {
428             final DomNode child = (DomNode) iter.next();
429             domNode.appendChild(child);
430         }
431     }
432
433     /**
434      * Replace all children elements of this element with the supplied value.
435      * @param value - the new value for the contents of this node
436      */

437     public void jsxSet_innerText(final String JavaDoc value) {
438         final DomNode domNode = getDomNodeOrDie();
439         domNode.removeAllChildren();
440
441         final DomNode node = new DomText(getDomNodeOrDie().getPage(), value);
442         domNode.appendChild(node);
443     }
444
445     
446     /**
447      * Replace all children elements of this element with the supplied value.
448      * Sets the outerHTML of the node.
449      * @see <a HREF="http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/outerhtml.asp">
450      * MSDN documentation</a>
451      * @param value - the new value for replacing this node
452      */

453     public void jsxSet_outerHTML(final String JavaDoc value) {
454         final DomNode domNode = getDomNodeOrDie();
455         
456         if (OUTER_HTML_READONLY.contains(domNode.getNodeName())) {
457             throw Context.reportRuntimeError("outerHTML is read-only for tag " + domNode.getNodeName());
458         }
459
460         for (final Iterator JavaDoc iter = parseHtmlSnippet(value).iterator(); iter.hasNext();) {
461             final DomNode child = (DomNode) iter.next();
462             domNode.insertBefore(child);
463         }
464         domNode.remove();
465     }
466
467     /**
468      * Parses the html code
469      * @param htmlSnippet the html code extract to parse
470      * @return collection of {@link DomNode}: the parsed nodes
471      */

472     private Collection JavaDoc parseHtmlSnippet(final String JavaDoc htmlSnippet) {
473         if (htmlSnippet.indexOf('<') >= 0) {
474             // build a pseudo WebResponse
475
final WebClient webClient = getDomNodeOrDie().getPage().getWebClient();
476             final boolean jsEnabled = webClient.isJavaScriptEnabled();
477             // disable js while interpreting the html snippet: it only needs to be interpreted
478
// when integrated in the real page
479
webClient.setJavaScriptEnabled(false);
480
481             final WebResponse webResp = new StringWebResponse("<html><body>" + htmlSnippet + "</body></html>",
482                     getDomNodeOrDie().getPage().getWebResponse().getUrl());
483             try {
484                 final WebWindow pseudoWindow = new WebWindow() {
485                     public Page getEnclosedPage() {
486                         return null;
487                     }
488                     public String JavaDoc getName() {
489                         return null;
490                     }
491                     public void setName(final String JavaDoc name) {
492                         // nothing
493
}
494                     public WebWindow getParentWindow() {
495                         return null;
496                     }
497                     public Object JavaDoc getScriptObject() {
498                         return null;
499                     }
500                     public WebWindow getTopWindow() {
501                         return null;
502                     }
503                     public WebClient getWebClient() {
504                         return webClient;
505                     }
506                     public void setEnclosedPage(final Page page) {
507                     }
508                     public void setScriptObject(final Object JavaDoc scriptObject) {
509                     }
510                 };
511                 final HtmlPage pseudoPage = HTMLParser.parse(webResp, pseudoWindow);
512                 final HtmlBody body = (HtmlBody) pseudoPage.getDocumentElement().getFirstChild();
513                 
514                 final Collection JavaDoc nodes = new ArrayList JavaDoc();
515                 for (final Iterator JavaDoc iter = body.getChildIterator(); iter.hasNext();) {
516                     final DomNode child = (DomNode) iter.next();
517                     nodes.add(copy(child, getHtmlElementOrDie().getPage()));
518                 }
519                 return nodes;
520             }
521             catch (final Exception JavaDoc e) {
522                 getLog().error("Unexpected exception occured while parsing html snippet", e);
523                 throw Context.reportRuntimeError("Unexpected exception occured while parsing html snippet: "
524                         + e.getMessage());
525             }
526             finally {
527                 // set javascript enabled back to original state
528
webClient.setJavaScriptEnabled(jsEnabled);
529             }
530         }
531         else {
532             // just text, keep it simple
533
final DomNode node = new DomText(getDomNodeOrDie().getPage(), htmlSnippet);
534             return Collections.singleton(node);
535         }
536     }
537
538     /**
539      * Copies the node to make it available to the page.
540      * All this stuff just to change the htmlPage_ property on all nodes!
541      *
542      * @param node The node to copy.
543      * @param page The page containing the node.
544      * @return a node with the same properties but bound to the page.
545      */

546     private DomNode copy(final DomNode node, final HtmlPage page) {
547         final DomNode copy;
548         if (node instanceof DomText) {
549             copy = new DomText(page, node.getNodeValue());
550         }
551         else {
552             final HtmlElement htmlElt = (HtmlElement) node;
553             final IElementFactory factory = HTMLParser.getFactory(htmlElt.getNodeName());
554             copy = factory.createElement(page, node.getNodeName(), readAttributes(htmlElt));
555             for (final Iterator JavaDoc iter = node.getChildIterator(); iter.hasNext();) {
556                 final DomNode child = (DomNode) iter.next();
557                 copy.appendChild(copy(child, page));
558             }
559         }
560         
561         return copy;
562     }
563
564     /**
565      * Gets the attributes of the element in the form of a {@link org.xml.sax.Attributes}
566      * @param element the element to read the attributes from
567      * @return the attributes
568      */

569     protected AttributesImpl JavaDoc readAttributes(final HtmlElement element) {
570         final AttributesImpl JavaDoc attributes = new AttributesImpl JavaDoc();
571         for (final Iterator JavaDoc iter = element.getAttributeEntriesIterator(); iter.hasNext();) {
572             final Map.Entry JavaDoc entry = (Map.Entry JavaDoc) iter.next();
573             final String JavaDoc name = (String JavaDoc) entry.getKey();
574             final String JavaDoc value = (String JavaDoc) entry.getValue();
575             attributes.addAttribute(null, name, name, null, value);
576         }
577         
578         return attributes;
579     }
580
581     /**
582      * Inserts the given HTML text into the element at the location.
583      * @see <a HREF="http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/insertadjacenthtml.asp">
584      * MSDN documentation</a>
585      * @param where specifies where to insert the HTML text, using one of the following value:
586      * beforeBegin, afterBegin, beforeEnd, afterEnd
587      * @param text the HTML text to insert
588      */

589     public void jsxFunction_insertAdjacentHTML(final String JavaDoc where, final String JavaDoc text) {
590         final DomNode currentNode = getDomNodeOrDie();
591         final DomNode node;
592         final boolean append;
593         
594         // compute the where and how the new nodes should be added
595
if (POSITION_AFTER_BEGIN.equals(where)) {
596             if (currentNode.getFirstChild() == null) {
597                 // new nodes should appended to the children of current node
598
node = currentNode;
599                 append = true;
600             }
601             else {
602                 // new nodes should be inserted before first child
603
node = currentNode.getFirstChild();
604                 append = false;
605             }
606         }
607         else if (POSITION_BEFORE_BEGIN.equals(where)) {
608             // new nodes should be inserted before current node
609
node = currentNode;
610             append = false;
611         }
612         else if (POSITION_BEFORE_END.equals(where)) {
613             // new nodes should appended to the children of current node
614
node = currentNode;
615             append = true;
616         }
617         else if (POSITION_AFTER_END.equals(where)) {
618             if (currentNode.getNextSibling() == null) {
619                 // new nodes should appended to the children of parent node
620
node = currentNode.getParentNode();
621                 append = true;
622             }
623             else {
624                 // new nodes should be inserted before current node's next sibling
625
node = currentNode.getNextSibling();
626                 append = false;
627             }
628         }
629         else {
630             throw Context.reportRuntimeError("Illegal position value: \"" + where + "\"");
631         }
632
633         // add the new nodes
634
for (final Iterator JavaDoc iter = parseHtmlSnippet(text).iterator(); iter.hasNext();) {
635             final DomNode child = (DomNode) iter.next();
636             if (append) {
637                 node.appendChild(child);
638             }
639             else {
640                 node.insertBefore(child);
641             }
642         }
643     }
644
645     /**
646      * Adds the specified behavior to this HTML element. Currently only supports
647      * the following default IE behaviors:
648      * <ul>
649      * <li>#default#clientCaps</li>
650      * <li>#default#homePage</li>
651      * </ul>
652      * @param behavior the URL of the behavior to add, or a default behavior name
653      * @return an identifier that can be user later to detach the behavior from the element
654      */

655     public int jsxFunction_addBehavior(final String JavaDoc behavior) {
656         if (BEHAVIOR_CLIENT_CAPS.equalsIgnoreCase(behavior)) {
657             final Class JavaDoc c = getClass();
658             defineProperty("availHeight", c, 0);
659             defineProperty("availWidth", c, 0);
660             defineProperty("bufferDepth", c, 0);
661             defineProperty("colorDepth", c, 0);
662             defineProperty("connectionType", c, 0);
663             defineProperty("cookieEnabled", c, 0);
664             defineProperty("cpuClass", c, 0);
665             defineProperty("height", c, 0);
666             defineProperty("javaEnabled", c, 0);
667             defineProperty("platform", c, 0);
668             defineProperty("systemLanguage", c, 0);
669             defineProperty("userLanguage", c, 0);
670             defineProperty("width", c, 0);
671             defineFunctionProperties(new String JavaDoc[] {"addComponentRequest"}, c, 0);
672             defineFunctionProperties(new String JavaDoc[] {"clearComponentRequest"}, c, 0);
673             defineFunctionProperties(new String JavaDoc[] {"compareVersions"}, c, 0);
674             defineFunctionProperties(new String JavaDoc[] {"doComponentRequest"}, c, 0);
675             defineFunctionProperties(new String JavaDoc[] {"getComponentVersion"}, c, 0);
676             defineFunctionProperties(new String JavaDoc[] {"isComponentInstalled"}, c, 0);
677             return BEHAVIOR_ID_CLIENT_CAPS;
678         }
679         else if (BEHAVIOR_HOMEPAGE.equalsIgnoreCase(behavior)) {
680             final Class JavaDoc c = getClass();
681             defineFunctionProperties(new String JavaDoc[] {"isHomePage"}, c, 0);
682             defineFunctionProperties(new String JavaDoc[] {"setHomePage"}, c, 0);
683             defineFunctionProperties(new String JavaDoc[] {"navigateHomePage"}, c, 0);
684             return BEHAVIOR_ID_HOMEPAGE;
685         }
686         else {
687             getLog().warn("Unimplemented behavior: " + behavior);
688             return BEHAVIOR_ID_UNKNOWN;
689         }
690     }
691
692     /**
693      * Removes the behavior corresponding to the specified identifier from this element.
694      * @param id the identifier for the behavior to remove
695      */

696     public void jsxFunction_removeBehavior(final int id) {
697         switch (id) {
698             case BEHAVIOR_ID_CLIENT_CAPS:
699                 delete("availHeight");
700                 delete("availWidth");
701                 delete("bufferDepth");
702                 delete("colorDepth");
703                 delete("connectionType");
704                 delete("cookieEnabled");
705                 delete("cpuClass");
706                 delete("height");
707                 delete("javaEnabled");
708                 delete("platform");
709                 delete("systemLanguage");
710                 delete("userLanguage");
711                 delete("width");
712                 delete("addComponentRequest");
713                 delete("clearComponentRequest");
714                 delete("compareVersions");
715                 delete("doComponentRequest");
716                 delete("getComponentVersion");
717                 delete("isComponentInstalled");
718                 break;
719             case BEHAVIOR_ID_HOMEPAGE:
720                 delete("isHomePage");
721                 delete("setHomePage");
722                 delete("navigateHomePage");
723                 break;
724             default:
725                 getLog().warn("Unexpected behavior id: " + id + ". Ignoring.");
726         }
727     }
728
729     //----------------------- START #default#clientCaps BEHAVIOR -----------------------
730

731     /**
732      * Returns the screen's available height. Part of the <tt>#default#clientCaps</tt>
733      * default IE behavior implementation.
734      * @return the screen's available height.
735      */

736     public int getAvailHeight() {
737         return getWindow().jsxGet_screen().jsxGet_availHeight();
738     }
739
740     /**
741      * Returns the screen's available width. Part of the <tt>#default#clientCaps</tt>
742      * default IE behavior implementation.
743      * @return the screen's available width.
744      */

745     public int getAvailWidth() {
746         return getWindow().jsxGet_screen().jsxGet_availWidth();
747     }
748
749     /**
750      * Returns the screen's buffer depth. Part of the <tt>#default#clientCaps</tt>
751      * default IE behavior implementation.
752      * @return the screen's buffer depth.
753      */

754     public int getBufferDepth() {
755         return getWindow().jsxGet_screen().jsxGet_bufferDepth();
756     }
757
758     /**
759      * Returns the screen's color depth. Part of the <tt>#default#clientCaps</tt>
760      * default IE behavior implementation.
761      * @return the screen's color depth.
762      */

763     public int getColorDepth() {
764         return getWindow().jsxGet_screen().jsxGet_colorDepth();
765     }
766
767     /**
768      * Returns the connection type being used. Part of the <tt>#default#clientCaps</tt>
769      * default IE behavior implementation.
770      * @return the connection type being used.
771      * Current implementation always return "modem"
772      */

773     public String JavaDoc getConnectionType() {
774         return "modem";
775     }
776
777     /**
778      * Returns <tt>true</tt> if cookies are enabled. Part of the <tt>#default#clientCaps</tt>
779      * default IE behavior implementation.
780      * @return whether or not cookies are enabled.
781      */

782     public boolean getCookieEnabled() {
783         return getWindow().jsxGet_navigator().jsxGet_cookieEnabled();
784     }
785
786     /**
787      * Returns the type of CPU used. Part of the <tt>#default#clientCaps</tt>
788      * default IE behavior implementation.
789      * @return the type of CPU used.
790      */

791     public String JavaDoc getCpuClass() {
792         return getWindow().jsxGet_navigator().jsxGet_cpuClass();
793     }
794
795     /**
796      * Returns the screen's height. Part of the <tt>#default#clientCaps</tt>
797      * default IE behavior implementation.
798      * @return the screen's height.
799      */

800     public int getHeight() {
801         return getWindow().jsxGet_screen().jsxGet_height();
802     }
803
804     /**
805      * Returns <tt>true</tt> if Java is enabled. Part of the <tt>#default#clientCaps</tt>
806      * default IE behavior implementation.
807      * @return whether or not Java is enabled.
808      */

809     public boolean getJavaEnabled() {
810         return getWindow().jsxGet_navigator().jsxFunction_javaEnabled();
811     }
812
813     /**
814      * Returns the platform used. Part of the <tt>#default#clientCaps</tt>
815      * default IE behavior implementation.
816      * @return the platform used.
817      */

818     public String JavaDoc getPlatform() {
819         return getWindow().jsxGet_navigator().jsxGet_platform();
820     }
821
822     /**
823      * Returns the system language. Part of the <tt>#default#clientCaps</tt>
824      * default IE behavior implementation.
825      * @return the system language.
826      */

827     public String JavaDoc getSystemLanguage() {
828         return getWindow().jsxGet_navigator().jsxGet_systemLanguage();
829     }
830
831     /**
832      * Returns the user language. Part of the <tt>#default#clientCaps</tt>
833      * default IE behavior implementation.
834      * @return the user language.
835      */

836     public String JavaDoc getUserLanguage() {
837         return getWindow().jsxGet_navigator().jsxGet_userLanguage();
838     }
839
840     /**
841      * Returns the screen's width. Part of the <tt>#default#clientCaps</tt>
842      * default IE behavior implementation.
843      * @return the screen's width.
844      */

845     public int getWidth() {
846         return getWindow().jsxGet_screen().jsxGet_width();
847     }
848
849     /**
850      * Adds the specified component to the queue of components to be installed. Note
851      * that no components ever get installed, and this call is always ignored. Part of
852      * the <tt>#default#clientCaps</tt> default IE behavior implementation.
853      * @param id the identifier for the component to install
854      * @param idType the type of identifier specified
855      * @param minVersion the minimum version of the component to install
856      */

857     public void addComponentRequest(final String JavaDoc id, final String JavaDoc idType, final String JavaDoc minVersion) {
858         getLog().debug("Call to addComponentRequest(" + id + ", " + idType + ", " + minVersion + ") ignored.");
859     }
860
861     /**
862      * Clears the component install queue of all component requests. Note that no components
863      * ever get installed, and this call is always ignored. Part of the <tt>#default#clientCaps</tt>
864      * default IE behavior implementation.
865      */

866     public void clearComponentRequest() {
867         getLog().debug("Call to clearComponentRequest() ignored.");
868     }
869
870     /**
871      * Compares the two specified version numbers. Part of the <tt>#default#clientCaps</tt>
872      * default IE behavior implementation.
873      * @param v1 the first of the two version numbers to compare
874      * @param v2 the second of the two version numbers to compare
875      * @return -1 if v1 < v2, 0 if v1 = v2, and 1 if v1 > v2
876      */

877     public int compareVersions(final String JavaDoc v1, final String JavaDoc v2) {
878         final int i = v1.compareTo(v2);
879         if(i == 0) { return 0; }
880         else if(i < 0) { return -1; }
881         else { return 1; }
882     }
883
884     /**
885      * Downloads all the components queued via {@link #addComponentRequest(String, String, String)}.
886      * @return <tt>true</tt> if the components are downloaded successfully.
887      * Current implementation always return <code>false</code>
888      */

889     public boolean doComponentRequest() {
890         return false;
891     }
892
893     /**
894      * Returns the version of the specified component.
895      * @param id the identifier for the component whose version is to be returned
896      * @param idType the type of identifier specified
897      * @return the version of the specified component.
898      * Current implementation always return "1.0"
899      */

900     public String JavaDoc getComponentVersion(final String JavaDoc id, final String JavaDoc idType) {
901         return "1.0";
902     }
903
904     /**
905      * Returns <tt>true</tt> if the specified component is installed.
906      * @param id the identifier for the component to check for
907      * @param idType the type of id specified
908      * @param minVersion the minimum version to check for
909      * @return <tt>true</tt> if the specified component is installed.
910      */

911     public boolean isComponentInstalled(final String JavaDoc id, final String JavaDoc idType, final String JavaDoc minVersion) {
912         return false;
913     }
914
915     /**
916      * Returns the JavaScript object for the window containing this HTML element's page.
917      * @return the JavaScript object for the window containing this HTML element's page.
918      */

919     protected Window getWindow() {
920         return (Window) getDomNodeOrDie().getPage().getEnclosingWindow().getScriptObject();
921     }
922
923     //----------------------- START #default#homePage BEHAVIOR -----------------------
924

925     /**
926      * Returns <tt>true</tt> if the specified URL is the web client's current
927      * homepage and the document calling the method is on the same domain as the
928      * user's homepage. Part of the <tt>#default#homePage</tt> default IE behavior
929      * implementation.
930      * @param url the URL to check
931      * @return <tt>true</tt> if the specified URL is the current homepage
932      */

933     public boolean isHomePage(final String JavaDoc url) {
934         try {
935             final URL JavaDoc newUrl = new URL JavaDoc(url);
936             final URL JavaDoc currentUrl = getDomNodeOrDie().getPage().getWebResponse().getUrl();
937             final String JavaDoc home = getDomNodeOrDie().getPage().getWebClient().getHomePage();
938             final boolean sameDomains = newUrl.getHost().equalsIgnoreCase(currentUrl.getHost());
939             final boolean isHomePage = (home != null && home.equals(url));
940             return (sameDomains && isHomePage);
941         }
942         catch(final MalformedURLException JavaDoc e) {
943             return false;
944         }
945     }
946
947     /**
948      * Sets the web client's current homepage. Part of the <tt>#default#homePage</tt>
949      * default IE behavior implementation.
950      * @param url the new homepage URL
951      */

952     public void setHomePage(final String JavaDoc url) {
953         getDomNodeOrDie().getPage().getWebClient().setHomePage(url);
954     }
955
956     /**
957      * Causes the web client to navigate to the current home page. Part of the
958      * <tt>#default#homePage</tt> default IE behavior implementation.
959      * @throws IOException if loading home page fails
960      */

961     public void navigateHomePage() throws IOException JavaDoc {
962         final WebClient webClient = getDomNodeOrDie().getPage().getWebClient();
963         webClient.getPage(new URL JavaDoc(webClient.getHomePage()));
964     }
965
966     //----------------------- END #default#homePage BEHAVIOR -----------------------
967

968     /**
969      * Set the onclick event handler for this element.
970      * @param onclick the new handler
971      */

972     public void jsxSet_onclick(final Function onclick) {
973         getHtmlElementOrDie().setEventHandler("onclick", onclick);
974     }
975
976     /**
977      * Get the onclick event handler for this element.
978      * @return <code>org.mozilla.javascript.Function</code>
979      */

980     public Function jsxGet_onclick() {
981         return getHtmlElementOrDie().getEventHandler("onclick");
982     }
983
984     /**
985      * Get the children of the current node.
986      * @see <a HREF="http://msdn.microsoft.com/workshop/author/dhtml/reference/collections/children.asp">
987      * MSDN documentation</a>
988      * @return the child at the given position
989      */

990     public Object JavaDoc jsxGet_children() {
991         final DomNode element = getDomNodeOrDie();
992         final ElementArray children = (ElementArray) makeJavaScriptObject(ElementArray.JS_OBJECT_NAME);
993         
994         try {
995             final XPath xpath = new HtmlUnitXPath("./*", HtmlUnitXPath.buildSubtreeNavigator(element));
996             children.init(element, xpath);
997         }
998         catch (final JaxenException e) {
999             // should never occur
1000
throw Context.reportRuntimeError("Failed initializing children: " + e.getMessage());
1001        }
1002        return children;
1003    }
1004
1005     /**
1006     * Set the ondblclick event handler for this element.
1007     * @param ondblclick the new handler */

1008    public void jsxSet_ondblclick(final Function ondblclick) {
1009        getHtmlElementOrDie().setEventHandler("ondblclick", ondblclick);
1010    }
1011
1012    /**
1013     * Get the ondblclick event handler for this element.
1014     * @return <code>org.mozilla.javascript.Function</code>
1015     */

1016    public Function jsxGet_ondblclick() {
1017        return getHtmlElementOrDie().getEventHandler("ondblclick");
1018    }
1019
1020    /**
1021     * Set the onblur event handler for this element.
1022     * @param onblur the new handler
1023     */

1024    public void jsxSet_onblur(final Function onblur) {
1025        getHtmlElementOrDie().setEventHandler("onblur", onblur);
1026    }
1027
1028    /**
1029     * Get the onblur event handler for this element.
1030     * @return <code>org.mozilla.javascript.Function</code>
1031     */

1032    public Function jsxGet_onblur() {
1033        return getHtmlElementOrDie().getEventHandler("onblur");
1034    }
1035
1036    /**
1037     * Set the onfocus event handler for this element.
1038     * @param onfocus the new handler
1039     */

1040    public void jsxSet_onfocus(final Function onfocus) {
1041        getHtmlElementOrDie().setEventHandler("onfocus", onfocus);
1042    }
1043
1044    /**
1045     * Get the onfocus event handler for this element.
1046     * @return <code>org.mozilla.javascript.Function</code>
1047     */

1048    public Function jsxGet_onfocus() {
1049        return getHtmlElementOrDie().getEventHandler("onfocus");
1050    }
1051
1052    /**
1053     * Set the onkeydown event handler for this element.
1054     * @param onkeydown the new handler
1055     */

1056    public void jsxSet_onkeydown(final Function onkeydown) {
1057        getHtmlElementOrDie().setEventHandler("onkeydown", onkeydown);
1058    }
1059
1060    /**
1061     * Get the onkeydown event handler for this element.
1062     * @return <code>org.mozilla.javascript.Function</code>
1063     */

1064    public Function jsxGet_onkeydown() {
1065        return getHtmlElementOrDie().getEventHandler("onkeydown");
1066    }
1067
1068    /**
1069     * Set the onkeypress event handler for this element.
1070     * @param onkeypress the new handler
1071     */

1072    public void jsxSet_onkeypress(final Function onkeypress) {
1073        getHtmlElementOrDie().setEventHandler("onkeypress", onkeypress);
1074    }
1075
1076    /**
1077     * Get the onkeypress event handler for this element.
1078     * @return <code>org.mozilla.javascript.Function</code>
1079     */

1080    public Function jsxGet_onkeypress() {
1081        return getHtmlElementOrDie().getEventHandler("onkeypress");
1082    }
1083
1084    /**
1085     * Set the onkeyup event handler for this element.
1086     * @param onkeyup the new handler
1087     */

1088    public void jsxSet_onkeyup(final Function onkeyup) {
1089        getHtmlElementOrDie().setEventHandler("onkeyup", onkeyup);
1090    }
1091
1092    /**
1093     * Get the onkeyup event handler for this element.
1094     * @return <code>org.mozilla.javascript.Function</code>
1095     */

1096    public Function jsxGet_onkeyup() {
1097        return getHtmlElementOrDie().getEventHandler("onkeyup");
1098    }
1099
1100    /**
1101     * Set the onmousedown event handler for this element.
1102     * @param onmousedown the new handler
1103     */

1104    public void jsxSet_onmousedown(final Function onmousedown) {
1105        getHtmlElementOrDie().setEventHandler("onmousedown", onmousedown);
1106    }
1107
1108    /**
1109     * Get the onmousedown event handler for this element.
1110     * @return <code>org.mozilla.javascript.Function</code>
1111     */

1112    public Function jsxGet_onmousedown() {
1113        return getHtmlElementOrDie().getEventHandler("onmousedown");
1114    }
1115
1116    /**
1117     * Set the onmousemove event handler for this element.
1118     * @param onmousemove the new handler
1119     */

1120    public void jsxSet_onmousemove(final Function onmousemove) {
1121        getHtmlElementOrDie().setEventHandler("onmousemove", onmousemove);
1122    }
1123
1124    /**
1125     * Get the onmousemove event handler for this element.
1126     * @return <code>org.mozilla.javascript.Function</code>
1127     */

1128    public Function jsxGet_onmousemove() {
1129        return getHtmlElementOrDie().getEventHandler("onmousemove");
1130    }
1131
1132    /**
1133     * Set the onmouseout event handler for this element.
1134     * @param onmouseout the new handler
1135     */

1136    public void jsxSet_onmouseout(final Function onmouseout) {
1137        getHtmlElementOrDie().setEventHandler("onmouseout", onmouseout);
1138    }
1139
1140    /**
1141     * Get the onmouseout event handler for this element.
1142     * @return <code>org.mozilla.javascript.Function</code>
1143     */

1144    public Function jsxGet_onmouseout() {
1145        return getHtmlElementOrDie().getEventHandler("onmouseout");
1146    }
1147
1148    /**
1149     * Set the onmouseover event handler for this element.
1150     * @param onmouseover the new handler
1151     */

1152    public void jsxSet_onmouseover(final Function onmouseover) {
1153        getHtmlElementOrDie().setEventHandler("onmouseover", onmouseover);
1154    }
1155
1156    /**
1157     * Get the onmouseover event handler for this element.
1158     * @return <code>org.mozilla.javascript.Function</code>
1159     */

1160    public Function jsxGet_onmouseover() {
1161        return getHtmlElementOrDie().getEventHandler("onmouseover");
1162    }
1163
1164    /**
1165     * Set the onmouseup event handler for this element.
1166     * @param onmouseup the new handler
1167     */

1168    public void jsxSet_onmouseup(final Function onmouseup) {
1169        getHtmlElementOrDie().setEventHandler("onmouseup", onmouseup);
1170    }
1171
1172    /**
1173     * Get the onmouseup event handler for this element.
1174     * @return <code>org.mozilla.javascript.Function</code>
1175     */

1176    public Function jsxGet_onmouseup() {
1177        return getHtmlElementOrDie().getEventHandler("onmouseup");
1178    }
1179
1180    /**
1181     * Set the onresize event handler for this element.
1182     * @param onresize the new handler
1183     */

1184    public void jsxSet_onresize(final Function onresize) {
1185        getHtmlElementOrDie().setEventHandler("onresize", onresize);
1186    }
1187
1188    /**
1189     * Get the onresize event handler for this element.
1190     * @return <code>org.mozilla.javascript.Function</code>
1191     */

1192    public Function jsxGet_onresize() {
1193        return getHtmlElementOrDie().getEventHandler("onresize");
1194    }
1195
1196    /**
1197     * Get the offsetHeight for this element.
1198     * @return a dummy value
1199     * @see <a HREF="http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/offsetwidth.asp">
1200     * MSDN documentation</a>
1201     */

1202    public int jsxGet_offsetHeight() {
1203        return 1;
1204    }
1205
1206    /**
1207     * Get the offsetWidth for this element.
1208     * @return a dummy value
1209     * @see <a HREF="http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/offsetWidth.asp">
1210     * MSDN documentation</a>
1211     */

1212    public int jsxGet_offsetWidth() {
1213        return 1;
1214    }
1215
1216    /**
1217     * Get the offsetLeft for this element.
1218     * @return a dummy value
1219     * @see <a HREF="http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/offsetLeft.asp">
1220     * MSDN documentation</a>
1221     */

1222    public int jsxGet_offsetLeft() {
1223        return 1;
1224    }
1225
1226    /**
1227     * Get the offsetTop for this element.
1228     * @return a dummy value
1229     * @see <a HREF="http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/offsetTop.asp">
1230     * MSDN documentation</a>
1231     */

1232    public int jsxGet_offsetTop() {
1233        return 1;
1234    }
1235
1236    /**
1237     * Just for debug purposes
1238     * @see java.lang.Object#toString()
1239     */

1240    public String JavaDoc toString() {
1241        return "HTMLElement for " + getHtmlElementOrNull();
1242    }
1243}
1244
Popular Tags