001/* 002 * Shredzone Commons 003 * 004 * Copyright (C) 2012 Richard "Shred" Körber 005 * http://commons.shredzone.org 006 * 007 * This program is free software: you can redistribute it and/or modify 008 * it under the terms of the GNU Library General Public License as 009 * published by the Free Software Foundation, either version 3 of the 010 * License, or (at your option) any later version. 011 * 012 * This program is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 015 * GNU General Public License for more details. 016 * 017 * You should have received a copy of the GNU Library General Public License 018 * along with this program. If not, see <http://www.gnu.org/licenses/>. 019 */ 020package org.shredzone.commons.text.filter; 021 022import java.io.Writer; 023 024import edu.umd.cs.findbugs.annotations.Nullable; 025import org.eclipse.mylyn.wikitext.parser.Attributes; 026import org.eclipse.mylyn.wikitext.parser.DocumentBuilder; 027import org.eclipse.mylyn.wikitext.parser.LinkAttributes; 028import org.eclipse.mylyn.wikitext.parser.MarkupParser; 029import org.eclipse.mylyn.wikitext.parser.builder.HtmlDocumentBuilder; 030import org.eclipse.mylyn.wikitext.textile.TextileLanguage; 031import org.shredzone.commons.text.LinkAnalyzer; 032import org.shredzone.commons.text.TextFilter; 033import org.shredzone.commons.text.utils.FastStringWriter; 034 035/** 036 * A filter that converts Textile markup to HTML. 037 * <p> 038 * Currently, Mylyn WikiText Textile (formerly known as Textile-J) is used for conversion. 039 * Future releases may come with an own, lightweight implementation. 040 * 041 * @see <a href="http://wiki.eclipse.org/Mylyn/Incubator/WikiText">Mylyn WikiText</a> 042 * @author Richard "Shred" Körber 043 */ 044public class TextileFilter implements TextFilter { 045 046 private @Nullable LinkAnalyzer analyzer; 047 048 /** 049 * Sets a {@link LinkAnalyzer} to be used for converting links and image source URLs. 050 * 051 * @param analyzer 052 * {@link LinkAnalyzer} to be used 053 */ 054 public void setAnalyzer(@Nullable LinkAnalyzer analyzer) { 055 this.analyzer = analyzer; 056 } 057 058 /** 059 * Creates a Textile-j {@link DocumentBuilder} to be used for writing. 060 * <p> 061 * Note that this method is Textile-j specific and might be removed in future 062 * versions. 063 * 064 * @param writer 065 * {@link Writer} to write the HTML output to 066 * @return {@link DocumentBuilder} to be used for the markup parser 067 */ 068 protected DocumentBuilder createDocumentBuilder(Writer writer) { 069 if (analyzer != null) { 070 return new LinkAnalyzingHtmlDocumentBuilder(writer, analyzer); 071 } else { 072 HtmlDocumentBuilder builder = new HtmlDocumentBuilder(writer); 073 builder.setEmitAsDocument(false); 074 return builder; 075 } 076 } 077 078 @Override 079 public CharSequence apply(CharSequence text) { 080 FastStringWriter writer = new FastStringWriter(text.length() * 15 / 10); 081 082 MarkupParser parser = new MarkupParser(new TextileLanguage()); 083 parser.setBuilder(createDocumentBuilder(writer)); 084 parser.parse(text.toString()); 085 086 return writer.toStringBuilder(); 087 } 088 089 /** 090 * A {@link HtmlDocumentBuilder} that uses a {@link LinkAnalyzer}. 091 */ 092 private static class LinkAnalyzingHtmlDocumentBuilder extends HtmlDocumentBuilder { 093 private final LinkAnalyzer analyzer; 094 095 public LinkAnalyzingHtmlDocumentBuilder(Writer writer, LinkAnalyzer analyzer) { 096 super(writer); 097 this.analyzer = analyzer; 098 setEmitAsDocument(false); 099 } 100 101 @Override 102 public void beginSpan(SpanType type, Attributes attributes) { 103 if (type.equals(SpanType.LINK) && attributes instanceof LinkAttributes) { 104 LinkAttributes la = (LinkAttributes) attributes; 105 106 la.setHref(analyzer.linkUrl(la.getHref())); 107 String linkType = analyzer.linkType(la.getHref()); 108 if (linkType != null) { 109 la.setCssClass(linkType); 110 } 111 } 112 super.beginSpan(type, attributes); 113 } 114 115 @Override 116 public void imageLink(Attributes linkAttributes, Attributes imageAttributes, String href, String imageUrl) { 117 String resolvedHref = analyzer.linkUrl(href); 118 String resolvedImageUrl = analyzer.imageUrl(imageUrl); 119 super.imageLink(linkAttributes, imageAttributes, resolvedHref, resolvedImageUrl); 120 } 121 122 @Override 123 public void image(Attributes attributes, String url) { 124 super.image(attributes, analyzer.imageUrl(url)); 125 } 126 } 127 128}