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