1 38 package com.gargoylesoftware.htmlunit.html; 39 40 import java.io.IOException ; 41 import java.net.MalformedURLException ; 42 import java.net.URL ; 43 import java.util.ArrayList ; 44 import java.util.Arrays ; 45 import java.util.Collections ; 46 import java.util.Comparator ; 47 import java.util.HashMap ; 48 import java.util.Iterator ; 49 import java.util.List ; 50 import java.util.Map ; 51 52 import org.org.apache.commons.httpclient.util.EncodingUtil; 53 import org.apache.commons.lang.StringUtils; 54 import org.apache.commons.logging.Log; 55 import org.apache.commons.logging.LogFactory; 56 import org.mozilla.javascript.Function; 57 import org.mozilla.javascript.Scriptable; 58 59 import com.gargoylesoftware.htmlunit.Assert; 60 import com.gargoylesoftware.htmlunit.ElementNotFoundException; 61 import com.gargoylesoftware.htmlunit.Page; 62 import com.gargoylesoftware.htmlunit.ScriptEngine; 63 import com.gargoylesoftware.htmlunit.ScriptResult; 64 import com.gargoylesoftware.htmlunit.TextUtil; 65 import com.gargoylesoftware.htmlunit.WebClient; 66 import com.gargoylesoftware.htmlunit.WebRequestSettings; 67 import com.gargoylesoftware.htmlunit.WebResponse; 68 import com.gargoylesoftware.htmlunit.WebWindow; 69 import com.gargoylesoftware.htmlunit.javascript.host.Event; 70 import com.gargoylesoftware.htmlunit.javascript.host.Window; 71 72 86 public final class HtmlPage extends DomNode implements Page { 87 88 private final WebClient webClient_; 89 private final URL originatingUrl_; 90 private String originalCharset_ = null; 91 private final WebResponse webResponse_; 92 private final Map idMap_ = new HashMap (); 93 private HtmlElement documentElement_ = null; 94 95 private WebWindow enclosingWindow_; 96 97 private static int FunctionWrapperCount_ = 0; 98 private final Log javascriptLog_ = LogFactory.getLog("com.gargoylesoftware.htmlunit.javascript"); 99 100 private static final int TAB_INDEX_NOT_SPECIFIED = -10; 101 private static final int TAB_INDEX_OUT_OF_BOUNDS = -20; 102 103 112 public HtmlPage( 113 final WebClient webClient, 114 final URL originatingUrl, 115 final WebResponse webResponse, 116 final WebWindow webWindow ) { 117 this(originatingUrl, webResponse, webWindow); 118 } 119 126 public HtmlPage( 127 final URL originatingUrl, 128 final WebResponse webResponse, 129 final WebWindow webWindow ) { 130 131 super(null); 132 133 webClient_ = webWindow.getWebClient(); 134 originatingUrl_ = originatingUrl; 135 webResponse_ = webResponse; 136 setEnclosingWindow(webWindow); 137 138 final ScriptEngine engine = getWebClient().getScriptEngine(); 139 if( engine != null ) { 140 engine.initialize(this); 141 } 142 } 143 144 147 public HtmlPage getPage() { 148 return this; 149 } 150 151 155 public void initialize() throws IOException { 156 insertTbodyTagsAsNeeded(); 157 documentElement_.setReadyState(READY_STATE_COMPLETE); 158 executeOnLoadHandlersIfNeeded(); 159 executeRefreshIfNeeded(); 160 } 161 162 163 167 public void cleanUp() throws IOException { 168 deregisterFramesIfNeeded(); 169 } 171 172 176 public short getNodeType() { 177 return DOCUMENT_NODE; 178 } 179 180 184 public String getNodeName() { 185 return "#document"; 186 } 187 188 192 public HtmlElement getDocumentElement() { 193 if (documentElement_ == null) { 194 DomNode childNode = getFirstChild(); 195 while (childNode != null && ! (childNode instanceof HtmlElement)) { 196 childNode = childNode.getNextSibling(); 197 } 198 documentElement_ = (HtmlElement) childNode; 199 } 200 return documentElement_; 201 } 202 203 210 public String getPageEncoding() { 211 if( originalCharset_ != null ) { 212 return originalCharset_ ; 213 } 214 final ArrayList ar = new ArrayList (); 215 ar.add("meta"); 216 final List list = getDocumentElement().getHtmlElementsByTagNames(ar); 217 for(int i=0; i<list.size();i++ ){ 218 final HtmlMeta meta = (HtmlMeta) list.get(i); 219 final String httpequiv = meta.getHttpEquivAttribute(); 220 if( "content-type".equals(httpequiv.toLowerCase()) ){ 221 final String contents = meta.getContentAttribute(); 222 final int pos = contents.toLowerCase().indexOf("charset="); 223 if( pos>=0 ){ 224 originalCharset_ = contents.substring(pos+8); 225 getLog().debug("Page Encoding detected: " + originalCharset_); 226 return originalCharset_; 227 } 228 } 229 } 230 if( originalCharset_ == null ) { 231 originalCharset_ = webResponse_.getContentCharSet(); 232 } 233 return originalCharset_; 234 } 235 236 242 public HtmlElement createElement(final String tagName) { 243 final String tagLower = tagName.toLowerCase(); 244 return HTMLParser.getFactory(tagLower).createElement(this, tagLower, null); 245 } 246 247 254 public HtmlAnchor getAnchorByName( final String name ) throws ElementNotFoundException { 255 return ( HtmlAnchor )getDocumentElement().getOneHtmlElementByAttribute( "a", "name", name ); 256 } 257 258 265 public HtmlAnchor getAnchorByHref( final String href ) throws ElementNotFoundException { 266 return ( HtmlAnchor )getDocumentElement().getOneHtmlElementByAttribute( "a", "href", href ); 267 } 268 269 270 274 public List getAnchors() { 275 return getDocumentElement().getHtmlElementsByTagNames( Collections.singletonList("a") ); 276 } 277 278 279 285 public HtmlAnchor getFirstAnchorByText( final String text ) throws ElementNotFoundException { 286 Assert.notNull("text", text); 287 288 final Iterator iterator = getAnchors().iterator(); 289 while( iterator.hasNext() ) { 290 final HtmlAnchor anchor = (HtmlAnchor)iterator.next(); 291 if( text.equals(anchor.asText()) ) { 292 return anchor; 293 } 294 } 295 throw new ElementNotFoundException("a", "<text>", text); 296 } 297 298 299 305 public HtmlForm getFormByName( final String name ) throws ElementNotFoundException { 306 final List forms = getDocumentElement().getHtmlElementsByAttribute( "form", "name", name ); 307 if( forms.size() == 0 ) { 308 throw new ElementNotFoundException( "form", "name", name ); 309 } 310 else { 311 return ( HtmlForm )forms.get( 0 ); 312 } 313 } 314 315 321 public List getAllForms() { 322 return getForms(); 323 } 324 325 329 public List getForms() { 330 return getDocumentElement().getHtmlElementsByTagNames( Arrays.asList(new String []{"form"}) ); 331 } 332 333 338 public WebClient getWebClient() { 339 return webClient_; 340 } 341 342 351 public URL getFullyQualifiedUrl( final String relativeUrl ) 352 throws MalformedURLException { 353 354 final List baseElements = getDocumentElement().getHtmlElementsByTagNames( Collections.singletonList("base")); 355 final URL baseUrl; 356 if( baseElements.isEmpty() ) { 357 baseUrl = originatingUrl_; 358 } 359 else { 360 final HtmlBase htmlBase = (HtmlBase)baseElements.get(0); 361 final String href = htmlBase.getHrefAttribute(); 362 if (href == null || href.length() == 0) { 363 baseUrl = originatingUrl_; 364 } 365 else { 366 baseUrl = new URL (href); 367 } 368 } 369 return WebClient.expandUrl( baseUrl, relativeUrl ); 370 } 371 372 379 public String getResolvedTarget( final String elementTarget ) { 380 381 final List baseElements = 382 getDocumentElement().getHtmlElementsByTagNames( Collections.singletonList("base")); 383 final String resolvedTarget; 384 if( baseElements.isEmpty() ) { 385 resolvedTarget = elementTarget; 386 } 387 else if( elementTarget != null && elementTarget.length() > 0 ) { 388 resolvedTarget = elementTarget; 389 } 390 else { 391 final HtmlBase htmlBase = (HtmlBase)baseElements.get(0); 392 resolvedTarget = htmlBase.getTargetAttribute(); 393 } 394 return resolvedTarget; 395 } 396 397 398 403 public WebResponse getWebResponse() { 404 return webResponse_; 405 } 406 407 408 415 public List getTabbableElementIds() { 416 final List list = new ArrayList ( getTabbableElements() ); 417 final int listSize = list.size(); 418 419 for( int i = 0; i < listSize; i++ ) { 420 list.set( i, ( ( HtmlElement )list.get( i ) ).getAttributeValue( "id" ) ); 421 } 422 423 return Collections.unmodifiableList( list ); 424 } 425 426 427 454 public List getTabbableElements() { 455 456 final List acceptableTagNames = Arrays.asList( 457 new Object []{"a", "area", "button", "input", "object", "select", "textarea"} ); 458 final List tabbableElements = new ArrayList (); 459 460 final DescendantElementsIterator iterator = getAllHtmlChildElements(); 461 while( iterator.hasNext() ) { 462 final HtmlElement element = iterator.nextElement(); 463 final String tagName = element.getTagName(); 464 if( acceptableTagNames.contains( tagName ) ) { 465 final boolean isDisabled = element.isAttributeDefined("disabled"); 466 467 if( isDisabled == false && getTabIndex(element) != TAB_INDEX_OUT_OF_BOUNDS ) { 468 tabbableElements.add(element); 469 } 470 } 471 } 472 Collections.sort( tabbableElements, createTabOrderComparator() ); 473 return Collections.unmodifiableList( tabbableElements ); 474 } 475 476 private Comparator createTabOrderComparator() { 477 478 return new Comparator () { 479 public int compare( final Object object1, final Object object2 ) { 480 final HtmlElement element1 = ( HtmlElement )object1; 481 final HtmlElement element2 = ( HtmlElement )object2; 482 483 final int tabIndex1 = getTabIndex( element1 ); 484 final int tabIndex2 = getTabIndex( element2 ); 485 486 final int result; 487 if( tabIndex1 > 0 && tabIndex2 > 0 ) { 488 result = tabIndex1 - tabIndex2; 489 } 490 else if( tabIndex1 > 0 ) { 491 result = -1; 492 } 493 else if( tabIndex2 > 0 ) { 494 result = +1; 495 } 496 else if( tabIndex1 == tabIndex2 ) { 497 result = 0; 498 } 499 else { 500 result = tabIndex2 - tabIndex1; 501 } 502 503 return result; 504 } 505 }; 506 } 507 508 509 private int getTabIndex( final HtmlElement element ) { 510 final String tabIndexAttribute = element.getAttributeValue( "tabindex" ); 511 if( tabIndexAttribute == null || tabIndexAttribute.length() == 0 ) { 512 return TAB_INDEX_NOT_SPECIFIED; 513 } 514 515 final int tabIndex = Integer.parseInt( tabIndexAttribute ); 516 if( tabIndex >= 0 && tabIndex <= 32767 ) { 517 return tabIndex; 518 } 519 else { 520 return TAB_INDEX_OUT_OF_BOUNDS; 521 } 522 } 523 524 525 537 public HtmlElement getHtmlElementByAccessKey( final char accessKey ) { 538 final List elements = getHtmlElementsByAccessKey(accessKey); 539 if( elements.isEmpty() ) { 540 return null; 541 } 542 else { 543 return (HtmlElement)elements.get(0); 544 } 545 } 546 547 548 565 public List getHtmlElementsByAccessKey( final char accessKey ) { 566 567 final List elements = new ArrayList (); 568 569 final String searchString = ( "" + accessKey ).toLowerCase(); 570 final List acceptableTagNames = Arrays.asList( 571 new Object []{"a", "area", "button", "input", "label", "legend", "textarea"} ); 572 573 final DescendantElementsIterator iterator = getAllHtmlChildElements(); 574 while( iterator.hasNext() ) { 575 final HtmlElement element = iterator.nextElement(); 576 if( acceptableTagNames.contains( element.getTagName() ) ) { 577 final String accessKeyAttribute = element.getAttributeValue("accesskey"); 578 if( searchString.equalsIgnoreCase( accessKeyAttribute ) ) { 579 elements.add( element ); 580 } 581 } 582 } 583 584 return elements; 585 } 586 587 597 public void assertAllTabIndexAttributesSet() { 598 599 final List acceptableTagNames = Arrays.asList( 600 new Object []{"a", "area", "button", "input", "object", "select", "textarea"} ); 601 final List tabbableElements = getDocumentElement().getHtmlElementsByTagNames( acceptableTagNames ); 602 603 final Iterator iterator = tabbableElements.iterator(); 604 while( iterator.hasNext() ) { 605 final HtmlElement htmlElement = ( HtmlElement )iterator.next(); 606 final int tabIndex = getTabIndex( htmlElement ); 607 if( tabIndex == TAB_INDEX_OUT_OF_BOUNDS ) { 608 webClient_.assertionFailed( 609 "Illegal value for tab index: " 610 + htmlElement.getAttributeValue( "tabindex" ) ); 611 } 612 else if( tabIndex == TAB_INDEX_NOT_SPECIFIED ) { 613 webClient_.assertionFailed( "tabindex not set for " + htmlElement ); 614 } 615 } 616 } 617 618 624 public void assertAllAccessKeyAttributesUnique() { 625 626 final List accessKeyList = new ArrayList (); 627 628 final DescendantElementsIterator iterator = getAllHtmlChildElements(); 629 while( iterator.hasNext() ) { 630 final String id = iterator.nextElement().getAttributeValue("accesskey" ); 631 if( id != null && id.length() != 0 ) { 632 if( accessKeyList.contains( id ) ) { 633 webClient_.assertionFailed( "Duplicate access key: " + id ); 634 } 635 else { 636 accessKeyList.add( id ); 637 } 638 } 639 } 640 } 641 642 643 650 public void assertAllIdAttributesUnique() { 651 final List idList = new ArrayList (); 652 653 final DescendantElementsIterator iterator = getAllHtmlChildElements(); 654 while( iterator.hasNext() ) { 655 final String id = iterator.nextElement().getAttributeValue("id"); 656 if( id != null && id.length() != 0 ) { 657 if( idList.contains( id ) ) { 658 webClient_.assertionFailed( "Duplicate ID: " + id ); 659 } 660 else { 661 idList.add( id ); 662 } 663 } 664 } 665 } 666 667 692 public ScriptResult executeJavaScriptIfPossible( 693 String sourceCode, final String sourceName, final boolean wrapSourceInFunction, 694 final HtmlElement htmlElement ) { 695 696 final ScriptEngine engine = getWebClient().getScriptEngine(); 697 if( engine == null ) { 698 return new ScriptResult(null, this); 699 } 700 701 final String prefix = "javascript:"; 702 final int prefixLength = prefix.length(); 703 704 if( sourceCode.length() > prefixLength 705 && sourceCode.substring(0, prefixLength).equalsIgnoreCase(prefix)) { 706 sourceCode = sourceCode.substring(prefixLength); 707 } 708 709 final WebWindow window = getEnclosingWindow(); 710 getWebClient().pushClearFirstWindow(); 711 final Object result; 712 if( wrapSourceInFunction ) { 713 final String wrapperName = "GargoyleWrapper"+(FunctionWrapperCount_++); 716 sourceCode = "function "+wrapperName+"() {"+sourceCode+"\n}"; 717 getJsLog().debug("Now build JS function\n" + sourceCode); 718 engine.execute( this, sourceCode, "Wrapper definition for "+sourceName, htmlElement ); 719 result = engine.execute( this, wrapperName+"()", sourceName, htmlElement ); 720 } 721 else { 722 result = engine.execute( this, sourceCode, sourceName, htmlElement ); 723 } 724 725 WebWindow firstWindow = getWebClient().popFirstWindow(); 726 if ( firstWindow == null) { 727 firstWindow = window; 728 } 729 730 return new ScriptResult( result, firstWindow.getEnclosedPage() ); 731 } 732 733 745 public ScriptResult executeJavaScriptFunctionIfPossible( 746 final Function function, 747 final Scriptable thisObject, 748 final Object [] args, 749 final HtmlElement htmlElementScope) { 750 751 final WebWindow window = getEnclosingWindow(); 752 getWebClient().pushClearFirstWindow(); 753 754 final ScriptEngine engine = getWebClient().getScriptEngine(); 755 if( engine == null ) { 756 return new ScriptResult(null, this); 757 } 758 759 final Object result = engine.callFunction(this, function, thisObject, args, htmlElementScope); 760 761 WebWindow firstWindow = getWebClient().popFirstWindow(); 762 if ( firstWindow == null) { 763 firstWindow = window; 764 } 765 return new ScriptResult(result, firstWindow.getEnclosedPage()); 766 } 767 768 772 protected Log getJsLog() { 773 return javascriptLog_; 774 } 775 776 781 public void loadExternalJavaScriptFile( final String srcAttribute, 782 final String charset ) { 783 final ScriptEngine engine = getWebClient().getScriptEngine(); 784 if( engine != null ) { 785 engine.execute( this, loadJavaScriptFromUrl( srcAttribute, charset ), srcAttribute, null ); 786 } 787 } 788 789 796 public static boolean isJavaScript( final String typeAttribute, final String languageAttribute ) { 797 final boolean isJavaScript; 799 if( languageAttribute != null && languageAttribute.length() != 0 ) { 800 isJavaScript = TextUtil.startsWithIgnoreCase(languageAttribute, "javascript"); 801 } 802 else if( typeAttribute != null && typeAttribute.length() != 0 ) { 803 isJavaScript = typeAttribute.equals( "text/javascript" ); 804 } 805 else { 806 isJavaScript = true; 807 } 808 809 return isJavaScript; 810 } 811 812 private String loadJavaScriptFromUrl( final String urlString, 813 final String charset ) { 814 URL url = null; 815 String scriptEncoding = charset; 816 getPageEncoding(); 817 try { 818 url = getFullyQualifiedUrl(urlString); 819 final WebRequestSettings requestSettings = new WebRequestSettings(url); 820 final WebResponse webResponse = getWebClient().loadWebResponse(requestSettings); 821 if( webResponse.getStatusCode() == 200 ) { 822 final String contentType = webResponse.getContentType(); 823 final String contentCharset = webResponse.getContentCharSet(); 824 if( contentType.equals("text/javascript") == false 825 && contentType.equals("application/x-javascript") == false ) { 826 getLog().warn( 827 "Expected content type of text/javascript or application/x-javascript for remotely " 828 + "loaded javascript element " + url + " but got [" + webResponse.getContentType()+"]"); 829 } 830 if( scriptEncoding == null || scriptEncoding.length() == 0 ){ 831 if( contentCharset.equals("ISO-8859-1")==false ) { 832 scriptEncoding = contentCharset; 833 } 834 else if( originalCharset_.equals("ISO-8859-1")==false ){ 835 scriptEncoding = originalCharset_ ; 836 } 837 } 838 if( scriptEncoding == null || scriptEncoding.length() == 0 ){ 839 scriptEncoding = "ISO-8859-1"; 840 } 841 final byte [] data = webResponse.getResponseBody(); 842 return EncodingUtil.getString(data, 0, data.length, scriptEncoding ); 843 } 844 else { 845 getLog().error("Error loading javascript from ["+url.toExternalForm() 846 +"] status=["+webResponse.getStatusCode()+" " 847 +webResponse.getStatusMessage()+"]"); 848 } 849 } 850 catch( final MalformedURLException e ) { 851 getLog().error("Unable to build url for script src tag ["+urlString+"]"); 852 return ""; 853 } 854 catch( final Exception e ) { 855 getLog().error("Error loading javascript from ["+url.toExternalForm()+"]: ", e); 856 } 857 return ""; 858 } 859 860 865 public WebWindow getEnclosingWindow() { 866 return enclosingWindow_; 867 } 868 869 874 public void setEnclosingWindow( final WebWindow window ) { 875 enclosingWindow_ = window; 876 } 877 878 883 public String getTitleText() { 884 final HtmlTitle titleElement = getTitleElement(); 885 if (titleElement != null) { 886 return titleElement.asText(); 887 } 888 return ""; 889 } 890 891 896 public void setTitleText(final String message) { 897 HtmlTitle titleElement = getTitleElement(); 898 if (titleElement == null) { 899 getLog().debug("No title element, creating one"); 900 final HtmlHead head = (HtmlHead) getFirstChildElement(getDocumentElement(), HtmlHead.class); 901 if (head == null) { 902 throw new IllegalStateException ("Headelement was not defined for this page"); 904 } 905 titleElement = new HtmlTitle(this, Collections.EMPTY_MAP); 906 if (head.getFirstChild() != null) { 907 head.getFirstChild().insertBefore(titleElement); 908 } 909 else { 910 head.appendChild(titleElement); 911 } 912 } 913 914 titleElement.setNodeValue(message); 915 } 916 917 923 private HtmlElement getFirstChildElement(final HtmlElement startElement, final Class clazz) { 924 final Iterator iterator = startElement.getChildElementsIterator(); 925 while (iterator.hasNext()) { 926 final HtmlElement element = (HtmlElement) iterator.next(); 927 if (clazz.isInstance(element)) { 928 return element; 929 } 930 } 931 932 return null; 933 } 934 935 940 private HtmlTitle getTitleElement() { 941 final HtmlHead head = (HtmlHead) getFirstChildElement(getDocumentElement(), HtmlHead.class); 942 if (head != null) { 943 return (HtmlTitle) getFirstChildElement(head, HtmlTitle.class); 944 } 945 946 return null; 947 } 948 949 953 private void executeOnLoadHandlersIfNeeded() { 954 if (!getWebClient().isJavaScriptEnabled()) { 955 return; 956 } 957 958 final Window jsWindow = (Window) getEnclosingWindow().getScriptObject(); 960 if (jsWindow != null && jsWindow.jsxGet_onload() != null) { 961 final ScriptEngine engine = getWebClient().getScriptEngine(); 962 getLog().debug("Executing onload handler for the window"); 963 engine.callFunction(this, jsWindow.jsxGet_onload(), jsWindow, new Object []{}, null); 964 } 965 966 final List list = getDocumentElement().getHtmlElementsByTagNames( Arrays.asList( new String []{ 968 "frame", "iframe" } )); 969 for (final Iterator iter = list.iterator(); iter.hasNext();) { 970 final BaseFrame frame = (BaseFrame) iter.next(); 971 getLog().debug("Executing onload handler for " + frame); 972 executeOneOnLoadHandler(frame); 973 } 974 } 975 976 981 private void executeOneOnLoadHandler(final HtmlElement element) { 982 getLog().debug("Executing onload handler, for " + element); 983 final Function onloadFunction = element.getEventHandler("onload"); 984 if (onloadFunction != null) { 985 final ScriptEngine engine = getWebClient().getScriptEngine(); 986 engine.callFunction(this, onloadFunction, element.getScriptObject(), new Object []{}, element); 987 } 988 } 989 990 995 private void executeRefreshIfNeeded() throws IOException { 996 final WebWindow window = getEnclosingWindow(); 1000 if( window == null ) { 1001 return; 1002 } 1003 1004 final String refreshString = getRefreshStringOrNull(); 1005 if( refreshString == null || refreshString.length() == 0 ) { 1006 return; 1007 } 1008 1009 final int time; 1010 final URL url; 1011 1012 int index = refreshString.indexOf( ";" ); 1013 boolean timeOnly = ( index == -1 ); 1014 1015 if( timeOnly ) { 1016 try { 1018 time = Integer.parseInt( refreshString ); 1019 } 1020 catch( final NumberFormatException e ) { 1021 getLog().error( "Malformed refresh string (no ';' but not a number): " + refreshString, e ); 1022 return; 1023 } 1024 url = originatingUrl_; 1025 } 1026 else { 1027 time = Integer.parseInt( refreshString.substring( 0, index ) ); 1029 index = refreshString.indexOf( "URL=", index ); 1030 if( index == -1 ) { 1031 index = refreshString.indexOf( "url=", index ); 1032 } 1033 if( index == -1 ) { 1034 getLog().error( "Malformed refresh string (found ';' but no 'url='): " + refreshString ); 1035 return; 1036 } 1037 final StringBuffer buffer = new StringBuffer ( refreshString.substring( index + 4 ) ); 1038 if( buffer.charAt( 0 ) == '"' || buffer.charAt( 0 ) == 0x27 ) { 1039 buffer.deleteCharAt( 0 ); 1040 } 1041 if( buffer.charAt( buffer.length() - 1 ) == '"' || buffer.charAt( buffer.length() - 1 ) == 0x27 ) { 1042 buffer.deleteCharAt( buffer.length() - 1 ); 1043 } 1044 final String urlString = buffer.toString(); 1045 try { 1046 url = getFullyQualifiedUrl( urlString ); 1047 } 1048 catch( final MalformedURLException e ) { 1049 getLog().error( "Malformed url in refresh string: " + refreshString, e ); 1050 throw e; 1051 } 1052 } 1053 1054 getWebClient().getRefreshHandler().handleRefresh( this, url, time ); 1055 } 1056 1057 1062 private String getRefreshStringOrNull() { 1063 final Iterator iterator 1064 = getDocumentElement().getHtmlElementsByTagNames( Collections.singletonList("meta") ).iterator(); 1065 final boolean javaScriptEnabled = getWebClient().isJavaScriptEnabled(); 1066 while( iterator.hasNext() ) { 1067 final HtmlMeta meta = (HtmlMeta) iterator.next(); 1068 if( meta.getHttpEquivAttribute().equalsIgnoreCase("refresh") 1069 && (!javaScriptEnabled || getFirstParent(meta, HtmlNoScript.TAG_NAME) == null)) { 1070 return meta.getContentAttribute(); 1071 } 1072 } 1073 1074 return getWebResponse().getResponseHeaderValue("Refresh"); 1075 } 1076 1077 1083 private DomNode getFirstParent(final DomNode node, final String nodeName) { 1084 DomNode parent = node.getParentNode(); 1085 while (parent != null) { 1086 if (parent.getNodeName().equals(nodeName)) { 1087 return parent; 1088 } 1089 parent = parent.getParentNode(); 1090 } 1091 return null; 1092 } 1093 1094 1097 public void deregisterFramesIfNeeded() { 1098 for (final Iterator iter = getFrames().iterator(); iter.hasNext();) { 1099 final WebWindow window = (WebWindow) iter.next(); 1100 webClient_.deregisterWebWindow( window ); 1101 if (window.getEnclosedPage() instanceof HtmlPage) { 1102 final HtmlPage page = (HtmlPage) window.getEnclosedPage(); 1103 if (page != null) { 1104 page.deregisterFramesIfNeeded(); 1107 } 1108 } 1109 } 1110 } 1111 1112 1113 1117 public List getFrames() { 1118 final List list = new ArrayList (); 1119 final WebWindow enclosingWindow = getEnclosingWindow(); 1120 for (final Iterator iter = getWebClient().getWebWindows().iterator(); iter.hasNext();) 1121 { 1122 final WebWindow window = (WebWindow) iter.next(); 1123 if (enclosingWindow == window.getParentWindow() 1125 && enclosingWindow != window) { 1126 list.add(window); 1127 } 1128 } 1129 return list; 1130 } 1131 1132 1138 public BaseFrame.FrameWindow getFrameByName(final String name) throws ElementNotFoundException { 1139 final List frames = getFrames(); 1140 for (final Iterator iter = frames.iterator(); iter.hasNext();) { 1141 final BaseFrame.FrameWindow frame = (BaseFrame.FrameWindow) iter.next(); 1142 if (frame.getName().equals(name)) { 1143 return frame; 1144 } 1145 } 1146 1147 throw new ElementNotFoundException("frame or iframe", "name", name); 1148 } 1149 1150 1160 public HtmlElement pressAccessKey( final char accessKey ) throws IOException { 1161 final HtmlElement element = getHtmlElementByAccessKey(accessKey); 1162 final WebClient webClient = getWebClient(); 1163 if( element != null ) { 1164 if( element instanceof FocusableElement ) { 1165 ((FocusableElement) element).focus(); 1166 } 1167 1168 final Page newPage; 1169 if( element instanceof HtmlAnchor ) { 1170 newPage = ((HtmlAnchor)element).click(); 1171 } 1172 else if( element instanceof HtmlArea ) { 1173 newPage = ((HtmlArea)element).click(); 1174 } 1175 else if( element instanceof HtmlButton ) { 1176 newPage = ((HtmlButton)element).click(); 1177 } 1178 else if( element instanceof HtmlInput ) { 1179 newPage = ((HtmlInput)element).click(); 1180 } 1181 else if( element instanceof HtmlLabel ) { 1182 newPage = ((HtmlLabel)element).click(); 1183 } 1184 else if( element instanceof HtmlLegend ) { 1185 newPage = ((HtmlLegend)element).click(); 1186 } 1187 else if( element instanceof HtmlTextArea ) { 1188 newPage = ((HtmlTextArea)element).click(); 1189 } 1190 else { 1191 newPage = this; 1192 } 1193 1194 if( newPage != this && webClient.getElementWithFocus() == element ) { 1195 webClient.getElementWithFocus().blur(); 1197 } 1198 } 1199 1200 return webClient.getElementWithFocus(); 1201 } 1202 1203 1204 1210 public HtmlElement tabToNextElement() { 1211 final List elements = getTabbableElements(); 1212 final FocusableElement elementWithFocus = getWebClient().getElementWithFocus(); 1213 if( elements.isEmpty() ) { 1214 if (elementWithFocus != null) { 1215 elementWithFocus.blur(); 1216 } 1217 return null; 1218 } 1219 1220 final HtmlElement elementToGiveFocus; 1221 if( elementWithFocus == null ) { 1222 elementToGiveFocus = (HtmlElement)elements.get(0); 1223 } 1224 else { 1225 final int index = elements.indexOf( elementWithFocus ); 1226 if( index == -1 ) { 1227 elementToGiveFocus = (HtmlElement)elements.get(0); 1229 } 1230 else { 1231 if( index == elements.size() - 1 ) { 1232 elementToGiveFocus = (HtmlElement)elements.get(0); 1233 } 1234 else { 1235 elementToGiveFocus = (HtmlElement)elements.get(index+1); 1236 } 1237 } 1238 } 1239 1240 if( elementToGiveFocus instanceof FocusableElement ) { 1241 ((FocusableElement) elementToGiveFocus).focus(); 1242 } 1243 return elementToGiveFocus; 1244 } 1245 1246 1247 1253 public HtmlElement tabToPreviousElement() { 1254 final List elements = getTabbableElements(); 1255 final FocusableElement elementWithFocus = getWebClient().getElementWithFocus(); 1256 if( elements.isEmpty() ) { 1257 if (elementWithFocus != null) { 1258 elementWithFocus.blur(); 1259 } 1260 return null; 1261 } 1262 1263 final HtmlElement elementToGiveFocus; 1264 if( elementWithFocus == null ) { 1265 elementToGiveFocus = (HtmlElement)elements.get(elements.size()-1); 1266 } 1267 else { 1268 final int index = elements.indexOf( elementWithFocus ); 1269 if( index == -1 ) { 1270 elementToGiveFocus = (HtmlElement)elements.get(elements.size()-1); 1272 } 1273 else { 1274 if( index == 0 ) { 1275 elementToGiveFocus = (HtmlElement)elements.get(elements.size()-1); 1276 } 1277 else { 1278 elementToGiveFocus = (HtmlElement)elements.get(index-1); 1279 } 1280 } 1281 } 1282 1283 if( elementToGiveFocus instanceof FocusableElement ) { 1284 ((FocusableElement) elementToGiveFocus).focus(); 1285 } 1286 return elementToGiveFocus; 1287 } 1288 1289 1298 public HtmlElement getHtmlElementById( final String id ) 1299 throws ElementNotFoundException { 1300 1301 final HtmlElement idElement = (HtmlElement) idMap_.get(id); 1302 if(idElement != null) { 1303 return idElement; 1304 } 1305 throw new ElementNotFoundException( "*", "id", id ); 1306 } 1307 1308 1313 void addIdElement(final HtmlElement idElement) { 1314 final String id = idElement.getId(); 1315 if (!StringUtils.isEmpty(id)) { 1316 idMap_.put(id, idElement); 1317 } 1318 } 1319 1320 1325 void removeIdElement(final HtmlElement idElement) { 1326 idMap_.remove(idElement.getAttributeValue("id")); 1327 } 1328 1329 private void insertTbodyTagsAsNeeded() { 1330 final Iterator iterator = getDocumentElement().getHtmlElementsByTagName("table").iterator(); 1331 while( iterator.hasNext() ) { 1332 final HtmlTable table = (HtmlTable)iterator.next(); 1333 DomNode child = table.getFirstChild(); 1334 while( child != null && child instanceof HtmlElement == false ) { 1335 child = child.getNextSibling(); 1336 } 1337 if( child instanceof HtmlTableRow ) { 1338 final HtmlTableBody body = new HtmlTableBody(this, Collections.EMPTY_MAP); 1339 final List nodesToMove = new ArrayList (); 1340 child = table.getFirstChild(); 1341 while( child != null ) { 1342 nodesToMove.add(child); 1343 child = child.getNextSibling(); 1344 } 1345 1346 final Iterator movingIterator = nodesToMove.iterator(); 1347 while( movingIterator.hasNext() ) { 1348 child = (DomNode)movingIterator.next(); 1349 body.appendChild(child); 1350 } 1351 table.appendChild(body); 1352 } 1353 } 1354 } 1355 1356 1365 Page executeOnChangeHandlerIfAppropriate(final HtmlElement htmlElement) { 1366 final Function onchange = htmlElement.getEventHandler("onchange"); 1367 final ScriptEngine engine = getWebClient().getScriptEngine(); 1368 if (onchange != null && getWebClient().isJavaScriptEnabled() 1369 && engine != null && !engine.isScriptRunning()) { 1370 1371 final Event event = new Event(this, getScriptObject()); 1372 final Object [] args = new Object [] {event}; 1373 1374 final ScriptResult scriptResult = 1375 executeJavaScriptFunctionIfPossible( 1376 onchange, 1377 (Scriptable)htmlElement.getScriptObject(), 1378 args, 1379 htmlElement); 1380 1381 return scriptResult.getNewPage(); 1382 } 1383 1384 return this; 1385 } 1386 1387 1391 void notifyNodeAdded(final DomNode node) { 1392 if (node instanceof HtmlElement) { 1393 addIdElement((HtmlElement) node); 1394 } 1395 if (node instanceof BaseFrame) { 1396 ((BaseFrame) node).loadInnerPage(); 1397 } 1398 if (node instanceof HtmlScript) { 1399 final HtmlScript scriptNode = (HtmlScript) node; 1400 getLog().debug("Script node added: " + scriptNode.asXml()); 1401 scriptNode.executeScriptIfNeeded(); 1402 } 1403 } 1404 1405 1409 void notifyNodeRemoved(final DomNode node) { 1410 if (node instanceof HtmlElement) { 1411 removeIdElement((HtmlElement) node); 1412 } 1413 } 1414 1417 public String asXml() { 1418 return getDocumentElement().asXml(); 1419 } 1420} 1421 | Popular Tags |