001package org.apache.maven.doxia.module.confluence; 002 003/* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022import java.io.PrintWriter; 023import java.io.StringWriter; 024import java.io.Writer; 025import java.util.ArrayList; 026import java.util.List; 027import java.util.Stack; 028 029import javax.swing.text.html.HTML.Attribute; 030 031import org.apache.maven.doxia.sink.SinkEventAttributes; 032import org.apache.maven.doxia.sink.impl.AbstractTextSink; 033import org.apache.maven.doxia.sink.impl.SinkEventAttributeSet; 034import org.apache.maven.doxia.util.HtmlTools; 035import org.codehaus.plexus.util.StringUtils; 036 037/** 038 * Confluence Sink implementation. 039 * <br> 040 * <b>Note</b>: The encoding used is UTF-8. 041 * 042 * @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton</a> 043 * @version $Id$ 044 * @since 1.0 045 */ 046public class ConfluenceSink 047 extends AbstractTextSink 048 implements ConfluenceMarkup 049{ 050 /** The writer to use. */ 051 private final PrintWriter out; 052 053 /** The writer to use. */ 054 private StringWriter writer; 055 056 /** An indication on if we're in head mode. */ 057 private boolean headFlag; 058 059 private int levelList = 0; 060 061 /** listStyles. */ 062 private final Stack<String> listStyles; 063 064 /** An indication on if we're in monospaced mode. */ 065 private boolean monospacedFlag; 066 067 /** Keep track of the closing tags for inline events. */ 068 protected Stack<List<String>> inlineStack = new Stack<>(); 069 070 /** An indication on if we're in verbatim box mode. */ 071 private boolean verbatimBoxedFlag; 072 073 /** An indication on if we're in table mode. */ 074 private boolean tableFlag; 075 076 /** An indication on if we're in table header mode. */ 077 private boolean tableHeaderFlag; 078 079 /** The link name. */ 080 private String linkName; 081 082 /** 083 * Constructor, initialize the Writer and the variables. 084 * 085 * @param writer not null writer to write the result. <b>Should</b> be an UTF-8 Writer. 086 * You could use <code>newWriter</code> methods from {@link org.codehaus.plexus.util.WriterFactory}. 087 */ 088 protected ConfluenceSink( Writer writer ) 089 { 090 this.out = new PrintWriter( writer ); 091 this.listStyles = new Stack<>(); 092 093 init(); 094 } 095 096 /** {@inheritDoc} */ 097 public void anchor( String name ) 098 { 099 write( ANCHOR_START_MARKUP + name + ANCHOR_END_MARKUP ); 100 } 101 102 /** {@inheritDoc} */ 103 public void anchor( String name, SinkEventAttributes attributes ) 104 { 105 anchor( name ); 106 } 107 108 /** 109 * Not used. 110 * {@inheritDoc} 111 */ 112 public void anchor_() 113 { 114 // nop 115 } 116 117 /** 118 * Not used. 119 * {@inheritDoc} 120 */ 121 public void author() 122 { 123 // nop 124 } 125 126 /** {@inheritDoc} */ 127 public void author( SinkEventAttributes attributes ) 128 { 129 author(); 130 } 131 132 /** 133 * Not used. 134 * {@inheritDoc} 135 */ 136 public void author_() 137 { 138 // nop 139 } 140 141 /** 142 * Not used. 143 * {@inheritDoc} 144 */ 145 public void body() 146 { 147 // nop 148 } 149 150 /** {@inheritDoc} */ 151 public void body( SinkEventAttributes attributes ) 152 { 153 body(); 154 } 155 156 /** 157 * Not used. 158 * {@inheritDoc} 159 */ 160 public void body_() 161 { 162 // nop 163 } 164 165 /** {@inheritDoc} */ 166 public void bold() 167 { 168 inline( SinkEventAttributeSet.Semantics.BOLD ); 169 } 170 171 /** {@inheritDoc} */ 172 public void bold_() 173 { 174 inline_(); 175 } 176 177 /** 178 * Not used. 179 * {@inheritDoc} 180 */ 181 public void comment( String comment ) 182 { 183 // nop 184 } 185 186 /** {@inheritDoc} */ 187 public void close() 188 { 189 out.write( writer.toString() ); 190 out.close(); 191 192 init(); 193 } 194 195 /** 196 * Not used. 197 * {@inheritDoc} 198 */ 199 public void date() 200 { 201 // nop 202 } 203 204 /** {@inheritDoc} */ 205 public void date( SinkEventAttributes attributes ) 206 { 207 date(); 208 } 209 210 /** 211 * Not used. 212 * {@inheritDoc} 213 */ 214 public void date_() 215 { 216 // nop 217 } 218 219 /** {@inheritDoc} */ 220 public void definedTerm() 221 { 222 // nop 223 } 224 225 /** {@inheritDoc} */ 226 public void definedTerm( SinkEventAttributes attributes ) 227 { 228 definedTerm(); 229 } 230 231 /** 232 * {@inheritDoc} 233 */ 234 public void definedTerm_() 235 { 236 writeEOL( true ); 237 } 238 239 /** 240 * {@inheritDoc} 241 */ 242 public void definition() 243 { 244 writer.write( CITATION_START_MARKUP ); 245 } 246 247 /** 248 * {@inheritDoc} 249 */ 250 public void definition( SinkEventAttributes attributes ) 251 { 252 definition(); 253 } 254 255 /** 256 * {@inheritDoc} 257 */ 258 public void definition_() 259 { 260 writer.write( CITATION_END_MARKUP ); 261 writeEOL( true ); 262 } 263 264 /** 265 * Not used. 266 * {@inheritDoc} 267 */ 268 public void definitionList() 269 { 270 // nop 271 } 272 273 /** 274 * Not used. 275 * {@inheritDoc} 276 */ 277 public void definitionList( SinkEventAttributes attributes ) 278 { 279 // nop 280 } 281 282 /** 283 * {@inheritDoc} 284 */ 285 public void definitionList_() 286 { 287 writeEOL(); 288 } 289 290 /** 291 * Not used. 292 * {@inheritDoc} 293 */ 294 public void definitionListItem() 295 { 296 // nop 297 } 298 299 /** 300 * Not used. 301 * {@inheritDoc} 302 */ 303 public void definitionListItem( SinkEventAttributes attributes ) 304 { 305 // nop 306 } 307 308 /** 309 * Not used. 310 * {@inheritDoc} 311 */ 312 public void definitionListItem_() 313 { 314 // nop 315 } 316 317 /** 318 * Not used. 319 * {@inheritDoc} 320 */ 321 public void figure() 322 { 323 // nop 324 } 325 326 /** {@inheritDoc} */ 327 public void figure( SinkEventAttributes attributes ) 328 { 329 figure(); 330 } 331 332 /** 333 * Not used. 334 * {@inheritDoc} 335 */ 336 public void figure_() 337 { 338 // nop 339 } 340 341 /** 342 * Not used. 343 * {@inheritDoc} 344 */ 345 public void figureCaption() 346 { 347 // nop 348 } 349 350 /** {@inheritDoc} */ 351 public void figureCaption( SinkEventAttributes attributes ) 352 { 353 figureCaption(); 354 } 355 356 /** 357 * Not used. 358 * {@inheritDoc} 359 */ 360 public void figureCaption_() 361 { 362 // nop; 363 } 364 365 /** {@inheritDoc} */ 366 public void figureGraphics( String name ) 367 { 368 writeEOL(); 369 write( FIGURE_START_MARKUP + name + FIGURE_END_MARKUP ); 370 } 371 372 /** {@inheritDoc} */ 373 public void figureGraphics( String src, SinkEventAttributes attributes ) 374 { 375 figureGraphics( src ); 376 if ( attributes != null && attributes.getAttribute( Attribute.ALT.toString() ) != null ) 377 { 378 write( attributes.getAttribute( Attribute.ALT.toString() ).toString() ); 379 writeEOL( true ); 380 } 381 } 382 383 /** {@inheritDoc} */ 384 public void flush() 385 { 386 close(); 387 writer.flush(); 388 } 389 390 /** {@inheritDoc} */ 391 public void head() 392 { 393 init(); 394 395 headFlag = true; 396 } 397 398 /** {@inheritDoc} */ 399 public void head( SinkEventAttributes attributes ) 400 { 401 head(); 402 } 403 404 /** {@inheritDoc} */ 405 public void head_() 406 { 407 headFlag = false; 408 } 409 410 /** 411 * Not used. 412 * {@inheritDoc} 413 */ 414 public void horizontalRule() 415 { 416 // nop 417 } 418 419 /** {@inheritDoc} */ 420 public void horizontalRule( SinkEventAttributes attributes ) 421 { 422 horizontalRule(); 423 } 424 425 /** {@inheritDoc} */ 426 public void inline() 427 { 428 inline( null ); 429 } 430 431 /** {@inheritDoc} */ 432 public void inline( SinkEventAttributes attributes ) 433 { 434 if ( !headFlag ) 435 { 436 List<String> tags = new ArrayList<>(); 437 438 if ( attributes != null ) 439 { 440 441 if ( attributes.containsAttribute( SinkEventAttributes.SEMANTICS, "italic" ) ) 442 { 443 write( ITALIC_START_MARKUP ); 444 tags.add( 0, ITALIC_END_MARKUP ); 445 } 446 447 if ( attributes.containsAttribute( SinkEventAttributes.SEMANTICS, "bold" ) ) 448 { 449 write( BOLD_START_MARKUP ); 450 tags.add( 0, BOLD_END_MARKUP ); 451 } 452 453 if ( attributes.containsAttribute( SinkEventAttributes.SEMANTICS, "code" ) ) 454 { 455 write( MONOSPACED_START_MARKUP ); 456 tags.add( 0, MONOSPACED_END_MARKUP ); 457 } 458 459 } 460 461 inlineStack.push( tags ); 462 } 463 } 464 465 /** {@inheritDoc} */ 466 public void inline_() 467 { 468 if ( !headFlag ) 469 { 470 for ( String tag: inlineStack.pop() ) 471 { 472 write( tag ); 473 } 474 } 475 } 476 477 /** {@inheritDoc} */ 478 public void italic() 479 { 480 inline( SinkEventAttributeSet.Semantics.ITALIC ); 481 } 482 483 /** {@inheritDoc} */ 484 public void italic_() 485 { 486 inline_(); 487 } 488 489 /** {@inheritDoc} */ 490 public void lineBreak() 491 { 492 write( LINE_BREAK_MARKUP ); 493 writeEOL(); 494 } 495 496 /** {@inheritDoc} */ 497 public void lineBreak( SinkEventAttributes attributes ) 498 { 499 lineBreak(); 500 } 501 502 /** {@inheritDoc} */ 503 public void link( String name ) 504 { 505 linkName = name; 506 } 507 508 /** {@inheritDoc} */ 509 public void link( String name, SinkEventAttributes attributes ) 510 { 511 link( name ); 512 } 513 514 /** {@inheritDoc} */ 515 public void link_() 516 { 517 linkName = null; 518 write( LINK_END_MARKUP ); 519 } 520 521 /** {@inheritDoc} */ 522 public void list() 523 { 524 if ( !writer.toString().endsWith( EOL + EOL ) ) 525 { 526 writeEOL( true ); 527 } 528 529 levelList++; 530 } 531 532 /** {@inheritDoc} */ 533 public void list( SinkEventAttributes attributes ) 534 { 535 list(); 536 } 537 538 /** {@inheritDoc} */ 539 public void list_() 540 { 541 levelList--; 542 if ( levelList == 0 ) 543 { 544 writeEOL( true ); 545 writeEOL(); 546 } 547 } 548 549 /** {@inheritDoc} */ 550 public void listItem() 551 { 552 write( StringUtils.repeat( "*", levelList ) + " " ); 553 } 554 555 /** {@inheritDoc} */ 556 public void listItem( SinkEventAttributes attributes ) 557 { 558 listItem(); 559 } 560 561 /** {@inheritDoc} */ 562 public void listItem_() 563 { 564 writeEOL( true ); 565 } 566 567 /** {@inheritDoc} */ 568 public void monospaced() 569 { 570 monospacedFlag = true; 571 inline( SinkEventAttributeSet.Semantics.CODE ); 572 } 573 574 /** {@inheritDoc} */ 575 public void monospaced_() 576 { 577 monospacedFlag = false; 578 inline_(); 579 } 580 581 /** 582 * Not used. 583 * {@inheritDoc} 584 */ 585 public void nonBreakingSpace() 586 { 587 // nop 588 } 589 590 /** {@inheritDoc} */ 591 public void numberedList( int numbering ) 592 { 593 if ( !writer.toString().endsWith( EOL + EOL ) ) 594 { 595 writeEOL( true ); 596 } 597 levelList++; 598 599 String style; 600 switch ( numbering ) 601 { 602 case NUMBERING_UPPER_ALPHA: 603 case NUMBERING_LOWER_ALPHA: 604 case NUMBERING_UPPER_ROMAN: 605 case NUMBERING_LOWER_ROMAN: 606 case NUMBERING_DECIMAL: 607 default: 608 style = NUMBERING_MARKUP; 609 } 610 611 listStyles.push( style ); 612 } 613 614 /** {@inheritDoc} */ 615 public void numberedList( int numbering, SinkEventAttributes attributes ) 616 { 617 numberedList( numbering ); 618 } 619 620 /** {@inheritDoc} */ 621 public void numberedList_() 622 { 623 levelList--; 624 if ( levelList == 0 ) 625 { 626 writeEOL( true ); 627 writeEOL(); 628 } 629 listStyles.pop(); 630 } 631 632 /** {@inheritDoc} */ 633 public void numberedListItem() 634 { 635 writeEOL( true ); 636 String style = listStyles.peek(); 637 // We currently only handle one type of numbering style for Confluence, 638 // so we can just repeat the latest numbering markup for each level. 639 // If we ever decide to handle multiple different numbering styles, we'd 640 // need to traverse the entire listStyles stack and use the correct 641 // numbering style for each level. 642 write( StringUtils.repeat( style, levelList ) + SPACE ); 643 } 644 645 /** {@inheritDoc} */ 646 public void numberedListItem( SinkEventAttributes attributes ) 647 { 648 numberedListItem(); 649 } 650 651 /** {@inheritDoc} */ 652 public void numberedListItem_() 653 { 654 writeEOL( true ); 655 } 656 657 /** 658 * Not used. 659 * {@inheritDoc} 660 */ 661 public void pageBreak() 662 { 663 // nop 664 } 665 666 /** 667 * Not used. 668 * {@inheritDoc} 669 */ 670 public void paragraph() 671 { 672 // nop 673 } 674 675 /** {@inheritDoc} */ 676 public void paragraph( SinkEventAttributes attributes ) 677 { 678 paragraph(); 679 } 680 681 /** {@inheritDoc} */ 682 public void paragraph_() 683 { 684 writeEOL( true ); 685 writeEOL(); 686 } 687 688 /** 689 * Not used. 690 * {@inheritDoc} 691 */ 692 public void rawText( String text ) 693 { 694 // nop 695 } 696 697 /** 698 * Not used. 699 * {@inheritDoc} 700 */ 701 public void section( int level, SinkEventAttributes attributes ) 702 { 703 // nop 704 } 705 706 /** 707 * Not used. 708 * {@inheritDoc} 709 */ 710 public void section1() 711 { 712 // nop 713 } 714 715 /** 716 * Not used. 717 * {@inheritDoc} 718 */ 719 public void section1_() 720 { 721 // nop 722 } 723 724 /** 725 * Not used. 726 * {@inheritDoc} 727 */ 728 public void section2() 729 { 730 // nop 731 } 732 733 /** 734 * Not used. 735 * {@inheritDoc} 736 */ 737 public void section2_() 738 { 739 // nop 740 } 741 742 /** 743 * Not used. 744 * {@inheritDoc} 745 */ 746 public void section3() 747 { 748 // nop 749 } 750 751 /** 752 * Not used. 753 * {@inheritDoc} 754 */ 755 public void section3_() 756 { 757 // nop 758 } 759 760 /** 761 * Not used. 762 * {@inheritDoc} 763 */ 764 public void section4() 765 { 766 // nop 767 } 768 769 /** 770 * Not used. 771 * {@inheritDoc} 772 */ 773 public void section4_() 774 { 775 // nop 776 } 777 778 /** 779 * Not used. 780 * {@inheritDoc} 781 */ 782 public void section5() 783 { 784 // nop 785 } 786 787 /** 788 * Not used. 789 * {@inheritDoc} 790 */ 791 public void section5_() 792 { 793 // nop 794 } 795 796 /** 797 * Not used. 798 * {@inheritDoc} 799 */ 800 public void section_( int level ) 801 { 802 // nop 803 } 804 805 /** 806 * Not used. 807 * {@inheritDoc} 808 */ 809 public void sectionTitle() 810 { 811 // nop 812 } 813 814 /** {@inheritDoc} */ 815 public void sectionTitle( int level, SinkEventAttributes attributes ) 816 { 817 if ( level > 0 && level < 6 ) 818 { 819 write( "h" + level + ". " ); 820 } 821 } 822 823 /** {@inheritDoc} */ 824 public void sectionTitle1() 825 { 826 sectionTitle( 1, null ); 827 } 828 829 /** {@inheritDoc} */ 830 public void sectionTitle1_() 831 { 832 sectionTitle_( 1 ); 833 } 834 835 /** {@inheritDoc} */ 836 public void sectionTitle2() 837 { 838 sectionTitle( 2, null ); 839 } 840 841 /** {@inheritDoc} */ 842 public void sectionTitle2_() 843 { 844 sectionTitle_( 2 ); 845 } 846 847 /** {@inheritDoc} */ 848 public void sectionTitle3() 849 { 850 sectionTitle( 3, null ); 851 } 852 853 /** {@inheritDoc} */ 854 public void sectionTitle3_() 855 { 856 sectionTitle_( 3 ); 857 } 858 859 /** {@inheritDoc} */ 860 public void sectionTitle4() 861 { 862 sectionTitle( 4, null ); 863 } 864 865 /** {@inheritDoc} */ 866 public void sectionTitle4_() 867 { 868 sectionTitle_( 4 ); 869 } 870 871 /** {@inheritDoc} */ 872 public void sectionTitle5() 873 { 874 sectionTitle( 5, null ); 875 } 876 877 /** {@inheritDoc} */ 878 public void sectionTitle5_() 879 { 880 sectionTitle_( 5 ); 881 } 882 883 /** 884 * Not used. 885 * {@inheritDoc} 886 */ 887 public void sectionTitle_() 888 { 889 // nop 890 } 891 892 /** {@inheritDoc} */ 893 public void sectionTitle_( int level ) 894 { 895 writeEOL( true ); 896 writeEOL(); 897 } 898 899 /** {@inheritDoc} */ 900 public void table() 901 { 902 // nop 903 tableFlag = true; 904 writeEOL( true ); 905 writeEOL(); 906 } 907 908 /** {@inheritDoc} */ 909 public void table( SinkEventAttributes attributes ) 910 { 911 table(); 912 } 913 914 /** {@inheritDoc} */ 915 public void table_() 916 { 917 tableFlag = false; 918 writeEOL( true ); 919 writeEOL(); 920 } 921 922 /** 923 * Not used. 924 * {@inheritDoc} 925 */ 926 public void tableCaption() 927 { 928 // nop 929 } 930 931 /** {@inheritDoc} */ 932 public void tableCaption( SinkEventAttributes attributes ) 933 { 934 tableCaption(); 935 } 936 937 /** 938 * Not used. 939 * {@inheritDoc} 940 */ 941 public void tableCaption_() 942 { 943 // nop 944 } 945 946 /** {@inheritDoc} */ 947 public void tableCell() 948 { 949 write( " " ); 950 } 951 952 /** {@inheritDoc} */ 953 public void tableCell( SinkEventAttributes attributes ) 954 { 955 tableCell(); 956 } 957 958 /** {@inheritDoc} */ 959 public void tableCell( String width ) 960 { 961 tableCell(); 962 } 963 964 /** {@inheritDoc} */ 965 public void tableCell_() 966 { 967 write( " " ); 968 write( TABLE_CELL_MARKUP ); 969 } 970 971 /** {@inheritDoc} */ 972 public void tableHeaderCell() 973 { 974 tableHeaderFlag = true; 975 write( TABLE_CELL_HEADER_START_MARKUP ); 976 } 977 978 /** {@inheritDoc} */ 979 public void tableHeaderCell( SinkEventAttributes attributes ) 980 { 981 tableHeaderCell(); 982 } 983 984 /** {@inheritDoc} */ 985 public void tableHeaderCell( String width ) 986 { 987 tableHeaderCell(); 988 } 989 990 /** {@inheritDoc} */ 991 public void tableHeaderCell_() 992 { 993 write( TABLE_CELL_HEADER_END_MARKUP ); 994 } 995 996 /** {@inheritDoc} */ 997 public void tableRow() 998 { 999 write( TABLE_ROW_MARKUP ); 1000 } 1001 1002 /** {@inheritDoc} */ 1003 public void tableRow( SinkEventAttributes attributes ) 1004 { 1005 tableRow(); 1006 } 1007 1008 /** {@inheritDoc} */ 1009 public void tableRow_() 1010 { 1011 if ( tableHeaderFlag ) 1012 { 1013 tableHeaderFlag = false; 1014 write( TABLE_ROW_MARKUP ); 1015 } 1016 writeEOL( true ); 1017 } 1018 1019 /** 1020 * Not used. 1021 * {@inheritDoc} 1022 */ 1023 public void tableRows( int[] justification, boolean grid ) 1024 { 1025 // nop 1026 } 1027 1028 /** 1029 * Not used. 1030 * {@inheritDoc} 1031 */ 1032 public void tableRows_() 1033 { 1034 // nop 1035 } 1036 1037 /** {@inheritDoc} */ 1038 public void text( String text ) 1039 { 1040 if ( headFlag ) 1041 { 1042 return; 1043 } 1044 1045 if ( linkName != null ) 1046 { 1047 write( LINK_START_MARKUP ); 1048 } 1049 1050 if ( tableFlag ) 1051 { 1052 // Remove line breaks, because it interferes with the table syntax 1053 String strippedText = StringUtils.replace( text, "\n", "" ); 1054 // Trim if only whitespace, to handle ignorable whitespace from xdoc documents 1055 if ( StringUtils.isWhitespace( strippedText ) ) 1056 { 1057 strippedText = StringUtils.trim( strippedText ); 1058 } 1059 content( strippedText ); 1060 } 1061 else if ( monospacedFlag ) 1062 { 1063 content( text, true ); 1064 } 1065 else 1066 { 1067 content( text ); 1068 } 1069 1070 if ( linkName != null ) 1071 { 1072 write( LINK_MIDDLE_MARKUP + linkName ); 1073 } 1074 } 1075 1076 /** {@inheritDoc} */ 1077 public void text( String text, SinkEventAttributes attributes ) 1078 { 1079 if ( attributes == null ) 1080 { 1081 text( text ); 1082 } 1083 else 1084 { 1085 if ( attributes.containsAttribute( SinkEventAttributes.DECORATION, "underline" ) ) 1086 { 1087 write( UNDERLINED_START_MARKUP ); 1088 } 1089 else if ( attributes.containsAttribute( SinkEventAttributes.DECORATION, "line-through" ) ) 1090 { 1091 write( STRIKETHROUGH_START_MARKUP ); 1092 } 1093 if ( attributes.containsAttribute( SinkEventAttributes.VALIGN, "sub" ) ) 1094 { 1095 write( SUBSCRIPT_START_MARKUP ); 1096 } 1097 else if ( attributes.containsAttribute( SinkEventAttributes.VALIGN, "sup" ) ) 1098 { 1099 write( SUPERSCRIPT_START_MARKUP ); 1100 } 1101 1102 text( text ); 1103 1104 if ( attributes.containsAttribute( SinkEventAttributes.VALIGN, "sup" ) ) 1105 { 1106 write( SUPERSCRIPT_END_MARKUP ); 1107 } 1108 else if ( attributes.containsAttribute( SinkEventAttributes.VALIGN, "sub" ) ) 1109 { 1110 write( SUBSCRIPT_END_MARKUP ); 1111 } 1112 if ( attributes.containsAttribute( SinkEventAttributes.DECORATION, "line-through" ) ) 1113 { 1114 write( STRIKETHROUGH_END_MARKUP ); 1115 } 1116 else if ( attributes.containsAttribute( SinkEventAttributes.DECORATION, "underline" ) ) 1117 { 1118 write( UNDERLINED_END_MARKUP ); 1119 } 1120 } 1121 } 1122 1123 /** 1124 * Not used. 1125 * {@inheritDoc} 1126 */ 1127 public void title() 1128 { 1129 // nop 1130 } 1131 1132 /** {@inheritDoc} */ 1133 public void title( SinkEventAttributes attributes ) 1134 { 1135 title(); 1136 } 1137 1138 /** 1139 * Not used. 1140 * {@inheritDoc} 1141 */ 1142 public void title_() 1143 { 1144 // nop 1145 } 1146 1147 /** 1148 * Not used. 1149 * {@inheritDoc} 1150 */ 1151 public void unknown( String name, Object[] requiredParams, SinkEventAttributes attributes ) 1152 { 1153 // nop 1154 } 1155 1156 /** {@inheritDoc} */ 1157 public void verbatim( boolean boxed ) 1158 { 1159 if ( boxed ) 1160 { 1161 verbatimBoxedFlag = true; 1162 } 1163 1164 if ( verbatimBoxedFlag ) 1165 { 1166 write( "{code:borderStyle=solid}" ); 1167 } 1168 else 1169 { 1170 write( "{noformat}" ); 1171 } 1172 writeEOL( true ); 1173 } 1174 1175 /** {@inheritDoc} */ 1176 public void verbatim_() 1177 { 1178 if ( verbatimBoxedFlag ) 1179 { 1180 write( "{code}" ); 1181 } 1182 else 1183 { 1184 write( "{noformat}" ); 1185 } 1186 1187 writeEOL( true ); 1188 writeEOL(); 1189 } 1190 1191 // ---------------------------------------------------------------------- 1192 // Private methods 1193 // ---------------------------------------------------------------------- 1194 1195 private void write( String text ) 1196 { 1197 writer.write( unifyEOLs( text ) ); 1198 } 1199 1200 /** 1201 * Writes a system EOL. 1202 */ 1203 private void writeEOL() 1204 { 1205 write( EOL ); 1206 } 1207 1208 /** 1209 * Writes a system EOL, with or without trim. 1210 */ 1211 private void writeEOL( boolean trim ) 1212 { 1213 if ( !trim ) 1214 { 1215 writeEOL(); 1216 return; 1217 } 1218 1219 String tmp = writer.toString().trim(); 1220 writer = new StringWriter(); 1221 writer.write( tmp ); 1222 write( EOL ); 1223 } 1224 1225 /** 1226 * Write HTML escaped text to output. 1227 * 1228 * @param text The text to write. 1229 */ 1230 protected void content( String text ) 1231 { 1232 write( escapeHTML( text ) ); 1233 } 1234 1235 /** 1236 * Write HTML, and optionally Confluence, escaped text to output. 1237 * 1238 * @param text The text to write. 1239 */ 1240 protected void content( String text, boolean escapeConfluence ) 1241 { 1242 if ( escapeConfluence ) 1243 { 1244 write( escapeConfluence( escapeHTML( text ) ) ); 1245 } 1246 else 1247 { 1248 content( text ); 1249 } 1250 } 1251 1252 /** {@inheritDoc} */ 1253 protected void init() 1254 { 1255 super.init(); 1256 1257 this.writer = new StringWriter(); 1258 this.monospacedFlag = false; 1259 this.headFlag = false; 1260 this.levelList = 0; 1261 this.listStyles.clear(); 1262 this.verbatimBoxedFlag = false; 1263 this.tableHeaderFlag = false; 1264 this.linkName = null; 1265 } 1266 1267 /** 1268 * Escape characters that have special meaning in Confluence. 1269 * 1270 * @param text the String to escape, may be null 1271 * @return the text escaped, "" if null String input 1272 */ 1273 protected static String escapeConfluence( String text ) 1274 { 1275 if ( text == null ) 1276 { 1277 return ""; 1278 } 1279 else 1280 { 1281 int length = text.length(); 1282 StringBuilder buffer = new StringBuilder( length ); 1283 1284 for ( int i = 0; i < length; ++i ) 1285 { 1286 char c = text.charAt( i ); 1287 switch ( c ) 1288 { 1289 case '{': 1290 buffer.append( "\\{" ); 1291 break; 1292 case '}': 1293 buffer.append( "\\}" ); 1294 break; 1295 default: 1296 buffer.append( c ); 1297 } 1298 } 1299 1300 return buffer.toString(); 1301 } 1302 } 1303 1304 /** 1305 * Forward to HtmlTools.escapeHTML( text ). 1306 * 1307 * @param text the String to escape, may be null 1308 * @return the text escaped, "" if null String input 1309 * @see org.apache.maven.doxia.util.HtmlTools#escapeHTML(String) 1310 */ 1311 protected static String escapeHTML( String text ) 1312 { 1313 return HtmlTools.escapeHTML( text ); 1314 } 1315}