1 38 package com.gargoylesoftware.htmlunit.html; 39 40 import java.io.PrintWriter ; 41 import java.net.MalformedURLException ; 42 import java.net.URL ; 43 import java.util.ArrayList ; 44 import java.util.Collections ; 45 import java.util.HashMap ; 46 import java.util.Iterator ; 47 import java.util.List ; 48 import java.util.Map ; 49 import java.util.NoSuchElementException ; 50 51 import org.mozilla.javascript.BaseFunction; 52 import org.mozilla.javascript.Function; 53 54 import com.gargoylesoftware.htmlunit.Assert; 55 import com.gargoylesoftware.htmlunit.ElementNotFoundException; 56 import com.gargoylesoftware.htmlunit.javascript.host.EventHandler; 57 58 69 public abstract class HtmlElement extends DomNode { 70 71 72 public static final String ATTRIBUTE_NOT_DEFINED = new String (""); 73 74 75 public static final String ATTRIBUTE_VALUE_EMPTY = new String (""); 76 77 78 private Map attributes_; 79 80 81 private Map eventHandlers_; 82 83 90 protected HtmlElement(final HtmlPage htmlPage, final Map attributes) { 91 92 super(htmlPage); 93 eventHandlers_ = Collections.EMPTY_MAP; 94 if(attributes != null) { 95 attributes_ = attributes; 96 attributesToEventHandlers(); 97 } 98 else { 99 attributes_ = Collections.EMPTY_MAP; 100 } 101 } 102 103 108 public DomNode cloneNode(final boolean deep) { 109 final HtmlElement newnode = (HtmlElement) super.cloneNode(deep); 110 111 newnode.attributes_ = new HashMap (); 112 113 for (final Iterator it = attributes_.keySet().iterator(); it.hasNext();) { 114 final Object key = it.next(); 115 116 if ("id".equals(key)) { 117 continue; 118 } 119 120 newnode.setAttributeValue((String ) key, (String ) attributes_.get(key)); 121 } 122 123 newnode.setId(ATTRIBUTE_VALUE_EMPTY); 124 125 return newnode; 126 } 127 128 138 public final String getAttributeValue( final String attributeName ) { 139 140 final String value = (String )attributes_.get(attributeName.toLowerCase()); 141 142 if(value != null) { 144 return value; 145 } 146 else { 147 return ATTRIBUTE_NOT_DEFINED; 148 } 149 } 150 151 157 public final void setAttributeValue(final String attributeName, final String attributeValue) { 158 159 String value = attributeValue; 160 161 if(attributes_ == Collections.EMPTY_MAP) { 162 attributes_ = new HashMap (); 163 } 164 if(value.length() == 0) { 165 value = ATTRIBUTE_VALUE_EMPTY; 166 } 167 final boolean isId = attributeName.equalsIgnoreCase("id"); 168 if (isId) { 169 getPage().removeIdElement(this); 170 } 171 attributes_.put(attributeName.toLowerCase(), value); 172 if (isId) { 173 getPage().addIdElement(this); 174 } 175 } 176 177 181 public final void removeAttribute(final String attributeName) { 182 if (attributeName.equalsIgnoreCase("id")) { 183 getPage().removeIdElement(this); 184 } 185 attributes_.remove(attributeName.toLowerCase()); 186 } 187 188 196 public boolean isAttributeDefined( final String attributeName ) { 197 return attributes_.get(attributeName.toLowerCase()) != null; 198 } 199 200 204 public Iterator getAttributeEntriesIterator() { 205 return attributes_.entrySet().iterator(); 206 } 207 208 214 public final Function getEventHandler(final String eventName) { 215 return (Function) eventHandlers_.get(eventName); 216 } 217 218 223 public final void setEventHandler(final String eventName, final Function eventHandler) { 224 if (eventHandlers_ == Collections.EMPTY_MAP) { 225 eventHandlers_ = new HashMap (); 226 } 227 eventHandlers_.put(eventName, eventHandler); 228 } 229 230 237 public final void setEventHandler(final String eventName, final String jsSnippet) { 238 239 final BaseFunction function = new EventHandler(this, jsSnippet); 240 setEventHandler(eventName, function); 241 getLog().debug("Created event handler " + function.getFunctionName() 242 + " for " + eventName + " on " + this); 243 } 244 245 253 public abstract String getTagName(); 254 255 256 public short getNodeType() { 257 return DomNode.ELEMENT_NODE; 258 } 259 260 263 public String getNodeName() { 264 return getTagName(); 265 } 266 267 270 public final String getId() { 271 return getAttributeValue("id"); 272 } 273 274 275 280 public final void setId(final String newId) { 281 setAttributeValue("id", newId); 282 } 283 284 285 291 public HtmlElement getEnclosingElement(final String tagName) { 292 final String tagNameLC = tagName.toLowerCase(); 293 294 DomNode currentNode = getParentNode(); 295 while (currentNode != null) { 296 if (currentNode instanceof HtmlElement 297 && currentNode.getNodeName().equals(tagNameLC)) { 298 299 return (HtmlElement) currentNode; 300 } 301 currentNode = currentNode.getParentNode(); 302 } 303 return null; 304 } 305 306 312 public HtmlForm getEnclosingForm() { 313 return (HtmlForm) getEnclosingElement("form"); 314 } 315 316 317 324 public HtmlForm getEnclosingFormOrDie() throws IllegalStateException { 325 final HtmlForm form = getEnclosingForm(); 326 if( form == null ) { 327 throw new IllegalStateException ("Element is not comtained within a form: "+this); 328 } 329 330 return form; 331 } 332 333 339 protected void printXml( final String indent, final PrintWriter printWriter ) { 340 341 final boolean hasChildren = (getFirstChild() != null); 342 printWriter.print(indent+"<"+getTagName().toLowerCase()); 343 final Map attributeMap = attributes_; 344 for( final Iterator it=attributeMap.keySet().iterator(); it.hasNext(); ) { 345 printWriter.print(" "); 346 final String name = (String )it.next(); 347 printWriter.print(name); 348 printWriter.print("=\""); 349 printWriter.print(attributeMap.get(name)); 350 printWriter.print("\""); 351 } 352 353 if( ! hasChildren ) { 354 printWriter.print("/"); 355 } 356 printWriter.println(">"); 357 printChildrenAsXml( indent, printWriter ); 358 if( hasChildren ) { 359 printWriter.println(indent+"</"+getTagName().toLowerCase()+">"); 360 } 361 } 362 363 364 369 public String toString() { 370 final StringBuffer buffer = new StringBuffer (); 371 372 final String className = getClass().getName(); 373 final int index = className.lastIndexOf( '.' ); 374 if( index == -1 ) { 375 buffer.append( className ); 376 } 377 else { 378 buffer.append( className.substring( index + 1 ) ); 379 } 380 381 buffer.append( "[<" ); 382 buffer.append(getTagName()); 383 384 for(final Iterator iterator=attributes_.keySet().iterator(); iterator.hasNext(); ) { 385 buffer.append( ' ' ); 386 final String name = (String )iterator.next(); 387 buffer.append(name); 388 buffer.append( "=\"" ); 389 buffer.append(attributes_.get(name)); 390 buffer.append( "\"" ); 391 } 392 buffer.append( ">]" ); 393 394 return buffer.toString(); 395 } 396 397 398 402 protected final void notImplemented() { 403 throw new RuntimeException ( "Not implemented yet" ); 404 } 405 406 407 416 protected final void assertNotEmpty( final String description, final String string ) 417 throws IllegalArgumentException { 418 419 if( string.length() == 0 ) { 420 throw new IllegalArgumentException ( "String may not be empty: " + description ); 421 } 422 } 423 424 425 436 public final HtmlElement getOneHtmlElementByAttribute( 437 final String elementName, 438 final String attributeName, 439 final String attributeValue ) 440 throws 441 ElementNotFoundException { 442 443 Assert.notNull( "elementName", elementName ); 444 Assert.notNull( "attributeName", attributeName ); 445 Assert.notNull( "attributeValue", attributeValue ); 446 447 final List list = getHtmlElementsByAttribute( elementName, attributeName, attributeValue ); 448 final int listSize = list.size(); 449 if( listSize == 0 ) { 450 throw new ElementNotFoundException( elementName, attributeName, attributeValue ); 451 } 452 453 return ( HtmlElement )list.get( 0 ); 454 } 455 456 457 466 public HtmlElement getHtmlElementById( final String id ) 467 throws ElementNotFoundException { 468 469 return getPage().getHtmlElementById(id); 470 } 471 472 473 490 public boolean hasHtmlElementWithId( final String id ) { 491 try { 492 getHtmlElementById(id); 493 return true; 494 } 495 catch( final ElementNotFoundException e ) { 496 return false; 497 } 498 } 499 500 501 510 public final List getHtmlElementsByAttribute( 511 final String elementName, 512 final String attributeName, 513 final String attributeValue ) { 514 515 final List list = new ArrayList (); 516 final DescendantElementsIterator iterator = new DescendantElementsIterator(); 517 final String lowerCaseTagName = elementName.toLowerCase(); 518 519 while(iterator.hasNext()) { 520 final HtmlElement next = iterator.nextElement(); 521 if(next.getTagName().equals(lowerCaseTagName)) { 522 final String attValue = next.getAttributeValue(attributeName); 523 if(attValue != null && attValue.equals(attributeValue)) { 524 list.add(next); 525 } 526 } 527 } 528 return list; 529 } 530 531 538 public final List getHtmlElementsByTagNames( final List acceptableTagNames ) { 539 540 final List list = new ArrayList (); 541 final Iterator iterator = acceptableTagNames.iterator(); 542 543 while(iterator.hasNext()) { 544 final String next = iterator.next().toString().toLowerCase(); 545 list.addAll(getHtmlElementsByTagName(next)); 546 } 547 return list; 548 } 549 550 557 public final List getHtmlElementsByTagName( final String tagName ) { 558 559 final List list = new ArrayList (); 560 final DescendantElementsIterator iterator = new DescendantElementsIterator(); 561 final String lowerCaseTagName = tagName.toLowerCase(); 562 563 while(iterator.hasNext()) { 564 final HtmlElement next = iterator.nextElement(); 565 if(lowerCaseTagName.equals(next.getTagName())) { 566 list.add(next); 567 } 568 } 569 return list; 570 } 571 572 580 public final HtmlElement appendChildIfNoneExists(final String tagName) { 581 final HtmlElement child; 582 final List children = getHtmlElementsByTagName(tagName); 583 if(children.isEmpty()) { 584 child = getPage().createElement(tagName); 586 appendChild(child); 587 } 588 else { 589 child = (HtmlElement) children.get(0); 591 } 592 return child; 593 } 594 595 601 public final void removeChild(final String tagName, final int i) { 602 final List children = getHtmlElementsByTagName(tagName); 603 if(i >= 0 && i < children.size()) { 604 final HtmlElement child = (HtmlElement) children.get(i); 605 child.remove(); 606 } 607 } 608 609 618 public final URL makeUrlFromHref( final String href ) 619 throws MalformedURLException { 620 621 return getPage().getFullyQualifiedUrl(href); 622 } 623 624 628 public final ChildElementsIterator getChildElementsIterator() { 629 return new ChildElementsIterator(); 630 } 631 632 636 private void attributesToEventHandlers() { 637 for (final Iterator iter=attributes_.entrySet().iterator(); iter.hasNext();) { 638 final Map.Entry entry = (Map.Entry ) iter.next(); 639 final String eventName = (String ) entry.getKey(); 640 641 if (eventName.startsWith("on")) { 642 setEventHandler(eventName, (String ) entry.getValue()); 643 } 644 } 645 646 } 647 648 651 protected class ChildElementsIterator implements Iterator { 652 653 private HtmlElement nextElement_; 654 655 656 public ChildElementsIterator() { 657 if(getFirstChild() != null) { 658 if(getFirstChild() instanceof HtmlElement) { 659 nextElement_ = (HtmlElement)getFirstChild(); 660 } 661 else { 662 setNextElement(getFirstChild()); 663 } 664 } 665 } 666 667 668 public boolean hasNext() { 669 return nextElement_ != null; 670 } 671 672 673 public Object next() { 674 return nextElement(); 675 } 676 677 678 public void remove() { 679 if(nextElement_ == null) { 680 throw new IllegalStateException (); 681 } 682 if(nextElement_.getPreviousSibling() != null) { 683 nextElement_.getPreviousSibling().remove(); 684 } 685 } 686 687 688 public HtmlElement nextElement() { 689 if(nextElement_ != null) { 690 final HtmlElement result = nextElement_; 691 setNextElement(nextElement_); 692 return result; 693 } 694 else { 695 throw new NoSuchElementException (); 696 } 697 } 698 699 private void setNextElement(final DomNode node) { 700 DomNode next = node.getNextSibling(); 701 while(next != null && !(next instanceof HtmlElement)) { 702 next = next.getNextSibling(); 703 } 704 nextElement_ = (HtmlElement)next; 705 } 706 } 707 } 708 | Popular Tags |