http://git-wip-us.apache.org/repos/asf/jspwiki/blob/c1793a18/jspwiki-markdown/src/main/java/org/apache/wiki/markdown/extensions/jspwikilinks/postprocessor/NodePostProcessorStateCommonOperations.java ---------------------------------------------------------------------- diff --git a/jspwiki-markdown/src/main/java/org/apache/wiki/markdown/extensions/jspwikilinks/postprocessor/NodePostProcessorStateCommonOperations.java b/jspwiki-markdown/src/main/java/org/apache/wiki/markdown/extensions/jspwikilinks/postprocessor/NodePostProcessorStateCommonOperations.java new file mode 100755 index 0000000..b6da8f9 --- /dev/null +++ b/jspwiki-markdown/src/main/java/org/apache/wiki/markdown/extensions/jspwikilinks/postprocessor/NodePostProcessorStateCommonOperations.java @@ -0,0 +1,79 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ +package org.apache.wiki.markdown.extensions.jspwikilinks.postprocessor; + +import org.apache.wiki.WikiContext; +import org.apache.wiki.parser.MarkupParser; +import org.apache.wiki.render.RenderingManager; + +import com.vladsch.flexmark.ast.HtmlInline; +import com.vladsch.flexmark.ast.Link; +import com.vladsch.flexmark.ast.Node; +import com.vladsch.flexmark.util.NodeTracker; +import com.vladsch.flexmark.util.sequence.CharSubSequence; + + +/** + * Internal class with common post-processor operations. + */ +class NodePostProcessorStateCommonOperations { + + static void addContent( final NodeTracker state, final Node node, final Node content ) { + final Node previous = node.getPrevious() != null ? node.getPrevious() : node.getNext(); + if( previous != null ) { + previous.insertAfter( content ); + node.unlink(); + state.nodeRemoved( node ); + content.takeChildren( node ); + state.nodeAddedWithChildren( content ); + } else { + node.getParent().appendChild( content ); + } + } + + static void addOutlinkImage( final NodeTracker state, final Node node, final WikiContext wikiContext, final boolean useOutlinkImage ) { + final Boolean wysiwygVariable = ( Boolean )wikiContext.getVariable( RenderingManager.WYSIWYG_EDITOR_MODE ); + boolean wysiwygEditorMode = wysiwygVariable != null ? wysiwygVariable.booleanValue() : false; + + if( useOutlinkImage && !wysiwygEditorMode ) { + final String m_outlinkImageURL = wikiContext.getURL( WikiContext.NONE, MarkupParser.OUTLINK_IMAGE ); + final HtmlInline img = new HtmlInline( CharSubSequence.of( "<img class=\""+ MarkupParser.OUTLINK + "\" " + + "alt=\"\" src=\""+ m_outlinkImageURL + "\" />" ) ); + node.insertAfter( img ); + state.nodeAdded( img ); + } + } + + static String inlineLinkTextOnWysiwyg( final NodeTracker state, final Link link, final boolean wysiwygEditorMode ) { + final String line = link.getUrl().toString(); + if( wysiwygEditorMode ) { + final HtmlInline content = new HtmlInline( CharSubSequence.of( "[" + line + "]()" ) ); + addContent( state, link, content ); + } + return line; + } + + static void makeError( final NodeTracker state, final Node node, final String errMsg ) { + final HtmlInline error = new HtmlInline( CharSubSequence.of( "<span class=\"error\">" + + errMsg + + "</span>" ) ); + addContent( state, node, error ); + } + +}
http://git-wip-us.apache.org/repos/asf/jspwiki/blob/c1793a18/jspwiki-markdown/src/main/java/org/apache/wiki/markdown/extensions/jspwikilinks/postprocessor/PluginLinkNodePostProcessorState.java ---------------------------------------------------------------------- diff --git a/jspwiki-markdown/src/main/java/org/apache/wiki/markdown/extensions/jspwikilinks/postprocessor/PluginLinkNodePostProcessorState.java b/jspwiki-markdown/src/main/java/org/apache/wiki/markdown/extensions/jspwikilinks/postprocessor/PluginLinkNodePostProcessorState.java new file mode 100755 index 0000000..b9a79e5 --- /dev/null +++ b/jspwiki-markdown/src/main/java/org/apache/wiki/markdown/extensions/jspwikilinks/postprocessor/PluginLinkNodePostProcessorState.java @@ -0,0 +1,138 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ +package org.apache.wiki.markdown.extensions.jspwikilinks.postprocessor; + +import java.text.MessageFormat; +import java.util.ResourceBundle; + +import org.apache.log4j.Logger; +import org.apache.wiki.WikiContext; +import org.apache.wiki.api.exceptions.PluginException; +import org.apache.wiki.api.plugin.WikiPlugin; +import org.apache.wiki.parser.PluginContent; +import org.apache.wiki.preferences.Preferences; +import org.apache.wiki.render.RenderingManager; + +import com.vladsch.flexmark.ast.HtmlInline; +import com.vladsch.flexmark.ast.Link; +import com.vladsch.flexmark.ext.toc.TocBlock; +import com.vladsch.flexmark.util.NodeTracker; +import com.vladsch.flexmark.util.sequence.CharSubSequence; + + +/** + * {@link NodePostProcessorState} which further post processes plugin links. + */ +public class PluginLinkNodePostProcessorState implements NodePostProcessorState< Link > { + + private static final Logger LOG = Logger.getLogger( PluginLinkNodePostProcessorState.class ); + private final WikiContext wikiContext; + private final boolean m_wysiwygEditorMode; + + public PluginLinkNodePostProcessorState( final WikiContext wikiContext ) { + this.wikiContext = wikiContext; + final Boolean wysiwygVariable = ( Boolean )wikiContext.getVariable( RenderingManager.WYSIWYG_EDITOR_MODE ); + m_wysiwygEditorMode = wysiwygVariable != null ? wysiwygVariable.booleanValue() : false; + } + + /** + * {@inheritDoc} + * + * @see NodePostProcessorState#process(NodeTracker, Link) + */ + @Override + public void process( final NodeTracker state, final Link link ) { + if( link.getText().toString().startsWith( "{TableOfContents" ) ) { + handleTableOfContentsPlugin( state, link ); + return; + } + PluginContent pluginContent = null; + try { + pluginContent = PluginContent.parsePluginLine( wikiContext, link.getUrl().toString(), -1 ); // -1 == do not generate _bounds parameter + // + // This might sometimes fail, especially if there is something which looks + // like a plugin invocation but is really not. + // + if( pluginContent != null ) { + final String pluginInvocation = pluginInvocation( link.getText().toString(), pluginContent ); + final HtmlInline content = new HtmlInline( CharSubSequence.of( pluginInvocation ) ); + pluginContent.executeParse( wikiContext ); + NodePostProcessorStateCommonOperations.addContent( state, link, content ); + } + } catch( final PluginException e ) { + LOG.info( wikiContext.getRealPage().getWiki() + " : " + wikiContext.getRealPage().getName() + " - Failed to insert plugin: " + e.getMessage() ); + if( !m_wysiwygEditorMode ) { + final ResourceBundle rbPlugin = Preferences.getBundle( wikiContext, WikiPlugin.CORE_PLUGINS_RESOURCEBUNDLE ); + NodePostProcessorStateCommonOperations.makeError( state, link, MessageFormat.format( rbPlugin.getString( "plugin.error.insertionfailed" ), + wikiContext.getRealPage().getWiki(), + wikiContext.getRealPage().getName(), + e.getMessage() ) ); + } + } finally { + if( pluginContent != null ) { + removeLink( state, link ); + } + } + } + + /** + * Return plugin execution. As plugin execution may not fire the plugin (i.e., on WYSIWYG editors), on those cases, the plugin line is returned. + * + * @param pluginMarkup plugin markup line + * @param pluginContent the plugin content. + * @return plugin execution, or plugin markup line if it wasn't executed. + */ + String pluginInvocation( final String pluginMarkup, final PluginContent pluginContent ) { + final String pluginInvocation = pluginContent.invoke( wikiContext ); + if( pluginMarkup.equals( pluginInvocation + "()" ) ) { // plugin line markup == plugin execution + "()" -> hasn't been executed + return pluginMarkup; + } else { + return pluginInvocation; + } + } + + void handleTableOfContentsPlugin(final NodeTracker state, final Link link) { + if( !m_wysiwygEditorMode ) { + final ResourceBundle rb = Preferences.getBundle( wikiContext, WikiPlugin.CORE_PLUGINS_RESOURCEBUNDLE ); + final HtmlInline divToc = new HtmlInline( CharSubSequence.of( "<div class=\"toc\">\n" ) ); + final HtmlInline divCollapseBox = new HtmlInline( CharSubSequence.of( "<div class=\"collapsebox\">\n" ) ); + final HtmlInline divsClosing = new HtmlInline( CharSubSequence.of( "</div>\n</div>\n" ) ); + final HtmlInline h4Title = new HtmlInline( CharSubSequence.of( "<h4 id=\"section-TOC\">" + // FIXME proper plugin parameters handling + rb.getString( "tableofcontents.title" ) + + "</h4>\n" ) ); + final TocBlock toc = new TocBlock( CharSubSequence.of( "[TOC]" ), CharSubSequence.of( "levels=1-3" ) ); + + link.insertAfter( divToc ); + divToc.insertAfter( divCollapseBox ); + divCollapseBox.insertAfter( h4Title ); + h4Title.insertAfter( toc ); + toc.insertAfter( divsClosing ); + + } else { + NodePostProcessorStateCommonOperations.inlineLinkTextOnWysiwyg( state, link, m_wysiwygEditorMode ); + } + removeLink( state, link ); + } + + void removeLink(final NodeTracker state, final Link link) { + link.unlink(); + state.nodeRemoved( link ); + } + +} http://git-wip-us.apache.org/repos/asf/jspwiki/blob/c1793a18/jspwiki-markdown/src/main/java/org/apache/wiki/markdown/extensions/jspwikilinks/postprocessor/VariableLinkNodePostProcessorState.java ---------------------------------------------------------------------- diff --git a/jspwiki-markdown/src/main/java/org/apache/wiki/markdown/extensions/jspwikilinks/postprocessor/VariableLinkNodePostProcessorState.java b/jspwiki-markdown/src/main/java/org/apache/wiki/markdown/extensions/jspwikilinks/postprocessor/VariableLinkNodePostProcessorState.java new file mode 100755 index 0000000..b15cfbd --- /dev/null +++ b/jspwiki-markdown/src/main/java/org/apache/wiki/markdown/extensions/jspwikilinks/postprocessor/VariableLinkNodePostProcessorState.java @@ -0,0 +1,65 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ +package org.apache.wiki.markdown.extensions.jspwikilinks.postprocessor; + +import org.apache.commons.lang.StringEscapeUtils; +import org.apache.wiki.WikiContext; +import org.apache.wiki.api.exceptions.NoSuchVariableException; +import org.apache.wiki.render.RenderingManager; + +import com.vladsch.flexmark.ast.HtmlInline; +import com.vladsch.flexmark.ast.Link; +import com.vladsch.flexmark.util.NodeTracker; +import com.vladsch.flexmark.util.sequence.CharSubSequence; + + +/** + * {@link NodePostProcessorState} which further post processes WikiVariable links. + */ +public class VariableLinkNodePostProcessorState implements NodePostProcessorState< Link > { + + private final WikiContext wikiContext; + private final boolean m_wysiwygEditorMode; + + public VariableLinkNodePostProcessorState( final WikiContext wikiContext ) { + this.wikiContext = wikiContext; + final Boolean wysiwygVariable = ( Boolean )wikiContext.getVariable( RenderingManager.WYSIWYG_EDITOR_MODE ); + m_wysiwygEditorMode = wysiwygVariable != null ? wysiwygVariable.booleanValue() : false; + } + + /** + * {@inheritDoc} + * + * @see NodePostProcessorState#process(NodeTracker, Link) + */ + @Override + public void process( NodeTracker state, Link link ) { + final String variable = NodePostProcessorStateCommonOperations.inlineLinkTextOnWysiwyg( state, link, m_wysiwygEditorMode ); + if( !m_wysiwygEditorMode ) { + try { + final String parsedVariable = wikiContext.getEngine().getVariableManager().parseAndGetValue( wikiContext, variable ); + final HtmlInline content = new HtmlInline( CharSubSequence.of( StringEscapeUtils.escapeXml( parsedVariable ) ) ); + NodePostProcessorStateCommonOperations.addContent( state, link, content ); + } catch( final NoSuchVariableException e ) { + NodePostProcessorStateCommonOperations.makeError( state, link, "No such variable: " + variable + " (" + e.getMessage() + ")" ); + } + } + } + +} http://git-wip-us.apache.org/repos/asf/jspwiki/blob/c1793a18/jspwiki-markdown/src/main/java/org/apache/wiki/markdown/extensions/jspwikilinks/postprocessor/package.html ---------------------------------------------------------------------- diff --git a/jspwiki-markdown/src/main/java/org/apache/wiki/markdown/extensions/jspwikilinks/postprocessor/package.html b/jspwiki-markdown/src/main/java/org/apache/wiki/markdown/extensions/jspwikilinks/postprocessor/package.html new file mode 100755 index 0000000..a067a22 --- /dev/null +++ b/jspwiki-markdown/src/main/java/org/apache/wiki/markdown/extensions/jspwikilinks/postprocessor/package.html @@ -0,0 +1,34 @@ +<!-- + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. +--> + +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> +<html> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<title>Insert title here</title> +</head> +<body> +Wikilinks' nodes custom post processing. + +<h3>Package Specification</h3> + +<h3>Related Documentation</h3> + +</body> +</html> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/jspwiki/blob/c1793a18/jspwiki-markdown/src/main/java/org/apache/wiki/markdown/package.html ---------------------------------------------------------------------- diff --git a/jspwiki-markdown/src/main/java/org/apache/wiki/markdown/package.html b/jspwiki-markdown/src/main/java/org/apache/wiki/markdown/package.html new file mode 100755 index 0000000..93bcd81 --- /dev/null +++ b/jspwiki-markdown/src/main/java/org/apache/wiki/markdown/package.html @@ -0,0 +1,34 @@ +<!-- + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. +--> + +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> +<html> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<title>Insert title here</title> +</head> +<body> +Entry point for JSPWiki Flexmark's custom extensions. + +<h3>Package Specification</h3> + +<h3>Related Documentation</h3> + +</body> +</html> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/jspwiki/blob/c1793a18/jspwiki-markdown/src/main/java/org/apache/wiki/parser/markdown/MarkdownDocument.java ---------------------------------------------------------------------- diff --git a/jspwiki-markdown/src/main/java/org/apache/wiki/parser/markdown/MarkdownDocument.java b/jspwiki-markdown/src/main/java/org/apache/wiki/parser/markdown/MarkdownDocument.java new file mode 100755 index 0000000..fb51dec --- /dev/null +++ b/jspwiki-markdown/src/main/java/org/apache/wiki/parser/markdown/MarkdownDocument.java @@ -0,0 +1,73 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ +package org.apache.wiki.parser.markdown; + +import java.util.Arrays; + +import org.apache.wiki.WikiContext; +import org.apache.wiki.WikiPage; +import org.apache.wiki.markdown.MarkdownForJSPWikiExtension; +import org.apache.wiki.parser.JSPWikiMarkupParser; +import org.apache.wiki.parser.WikiDocument; + +import com.vladsch.flexmark.Extension; +import com.vladsch.flexmark.ast.Node; +import com.vladsch.flexmark.ext.footnotes.FootnoteExtension; +import com.vladsch.flexmark.ext.toc.TocExtension; +import com.vladsch.flexmark.parser.Parser; +import com.vladsch.flexmark.parser.ParserEmulationProfile; +import com.vladsch.flexmark.util.options.MutableDataSet; + + +/** + * Simple placeholder for Markdown Nodes + */ +public class MarkdownDocument extends WikiDocument { + + private static final long serialVersionUID = 1L; + + private final Node md; + + public MarkdownDocument( final WikiPage page, final Node md ) { + super( page ); + this.md = md; + } + + public Node getMarkdownNode() { + return md; + } + + /** + * configuration options for MarkdownRenderers. + * + * @param context current wikicontext + * @return configuration options for MarkdownRenderers. + */ + public static MutableDataSet options( final WikiContext context ) { + MutableDataSet options = new MutableDataSet(); + options.setFrom( ParserEmulationProfile.COMMONMARK ); + // align style of Markdown's footnotes extension with jspwiki footnotes refs + options.set( FootnoteExtension.FOOTNOTE_LINK_REF_CLASS, JSPWikiMarkupParser.CLASS_FOOTNOTE_REF ); + options.set( Parser.EXTENSIONS, Arrays.asList( new Extension[] { new MarkdownForJSPWikiExtension( context ), + FootnoteExtension.create(), + TocExtension.create() } ) ); + return options; + } + +} http://git-wip-us.apache.org/repos/asf/jspwiki/blob/c1793a18/jspwiki-markdown/src/main/java/org/apache/wiki/parser/markdown/MarkdownParser.java ---------------------------------------------------------------------- diff --git a/jspwiki-markdown/src/main/java/org/apache/wiki/parser/markdown/MarkdownParser.java b/jspwiki-markdown/src/main/java/org/apache/wiki/parser/markdown/MarkdownParser.java new file mode 100755 index 0000000..3c259e8 --- /dev/null +++ b/jspwiki-markdown/src/main/java/org/apache/wiki/parser/markdown/MarkdownParser.java @@ -0,0 +1,59 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ +package org.apache.wiki.parser.markdown; + +import java.io.IOException; +import java.io.Reader; + +import org.apache.wiki.WikiContext; +import org.apache.wiki.parser.MarkupParser; +import org.apache.wiki.parser.WikiDocument; + +import com.vladsch.flexmark.ast.Node; +import com.vladsch.flexmark.parser.Parser; + + +/** + * Class handling the markdown parsing. + */ +public class MarkdownParser extends MarkupParser { + + private final Parser parser; + + public MarkdownParser( final WikiContext context, final Reader in ) { + super( context, in ); + if( context.getEngine().getUserManager().getUserDatabase() == null || context.getEngine().getAuthorizationManager() == null ) { + disableAccessRules(); + } + parser = Parser.builder( MarkdownDocument.options( context ) ).build(); + } + + /** + * {@inheritDoc} + */ + @Override + public WikiDocument parse() throws IOException { + Node document = parser.parseReader( m_in ); + MarkdownDocument md = new MarkdownDocument( m_context.getPage(), document ); + md.setContext( m_context ); + + return md; + } + +} http://git-wip-us.apache.org/repos/asf/jspwiki/blob/c1793a18/jspwiki-markdown/src/main/java/org/apache/wiki/parser/markdown/package.html ---------------------------------------------------------------------- diff --git a/jspwiki-markdown/src/main/java/org/apache/wiki/parser/markdown/package.html b/jspwiki-markdown/src/main/java/org/apache/wiki/parser/markdown/package.html new file mode 100755 index 0000000..b54d53f --- /dev/null +++ b/jspwiki-markdown/src/main/java/org/apache/wiki/parser/markdown/package.html @@ -0,0 +1,34 @@ +<!-- + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. +--> + +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> +<html> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<title>Insert title here</title> +</head> +<body> +Markdown parsing. + +<h3>Package Specification</h3> + +<h3>Related Documentation</h3> + +</body> +</html> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/jspwiki/blob/c1793a18/jspwiki-markdown/src/main/java/org/apache/wiki/render/markdown/MarkdownRenderer.java ---------------------------------------------------------------------- diff --git a/jspwiki-markdown/src/main/java/org/apache/wiki/render/markdown/MarkdownRenderer.java b/jspwiki-markdown/src/main/java/org/apache/wiki/render/markdown/MarkdownRenderer.java new file mode 100755 index 0000000..bf13633 --- /dev/null +++ b/jspwiki-markdown/src/main/java/org/apache/wiki/render/markdown/MarkdownRenderer.java @@ -0,0 +1,56 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ +package org.apache.wiki.render.markdown; + +import java.io.IOException; + +import org.apache.wiki.WikiContext; +import org.apache.wiki.parser.WikiDocument; +import org.apache.wiki.parser.markdown.MarkdownDocument; +import org.apache.wiki.render.WikiRenderer; + +import com.vladsch.flexmark.html.HtmlRenderer; + + +/** + * Class handling the markdown rendering. + */ +public class MarkdownRenderer extends WikiRenderer { + + private final HtmlRenderer renderer; + + public MarkdownRenderer( final WikiContext context, final WikiDocument doc ) { + super( context, doc ); + renderer = HtmlRenderer.builder( MarkdownDocument.options( context ) ).build(); + } + + /** + * {@inheritDoc} + */ + @Override + public String getString() throws IOException { + m_document.setContext( m_context ); + if( m_document instanceof MarkdownDocument ) { + return renderer.render( ( ( MarkdownDocument )m_document ).getMarkdownNode() ); + } else { + throw new IOException( "MarkdownRenderer requires to be used with MarkdownParser" ); + } + } + +} http://git-wip-us.apache.org/repos/asf/jspwiki/blob/c1793a18/jspwiki-markdown/src/main/java/org/apache/wiki/render/markdown/package.html ---------------------------------------------------------------------- diff --git a/jspwiki-markdown/src/main/java/org/apache/wiki/render/markdown/package.html b/jspwiki-markdown/src/main/java/org/apache/wiki/render/markdown/package.html new file mode 100755 index 0000000..e1bb604 --- /dev/null +++ b/jspwiki-markdown/src/main/java/org/apache/wiki/render/markdown/package.html @@ -0,0 +1,34 @@ +<!-- + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. +--> + +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> +<html> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<title>Insert title here</title> +</head> +<body> +Markdown rendering. + +<h3>Package Specification</h3> + +<h3>Related Documentation</h3> + +</body> +</html> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/jspwiki/blob/c1793a18/jspwiki-markdown/src/test/java/org/apache/wiki/render/MarkdownRendererTest.java ---------------------------------------------------------------------- diff --git a/jspwiki-markdown/src/test/java/org/apache/wiki/render/MarkdownRendererTest.java b/jspwiki-markdown/src/test/java/org/apache/wiki/render/MarkdownRendererTest.java new file mode 100755 index 0000000..d6f9be1 --- /dev/null +++ b/jspwiki-markdown/src/test/java/org/apache/wiki/render/MarkdownRendererTest.java @@ -0,0 +1,322 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ +package org.apache.wiki.render; + +import java.io.BufferedReader; +import java.io.StringReader; +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; + +import org.apache.wiki.TestEngine; +import org.apache.wiki.WikiContext; +import org.apache.wiki.WikiEngine; +import org.apache.wiki.WikiPage; +import org.apache.wiki.api.exceptions.WikiException; +import org.apache.wiki.attachment.Attachment; +import org.apache.wiki.parser.markdown.MarkdownParser; +import org.apache.wiki.render.markdown.MarkdownRenderer; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import net.sf.ehcache.CacheManager; + + +public class MarkdownRendererTest { + + Properties props = TestEngine.getTestProperties(); + List<String> created = new ArrayList<>(); + + static final String PAGE_NAME = "testpage"; + + TestEngine testEngine; + + @Test + public void testMarkupSimpleMarkdown() throws Exception { + String src = "This should be a **bold**"; + + Assert.assertEquals( "<p>This should be a <strong>bold</strong></p>\n", translate( src ) ); + } + + @Test + public void testMarkupExtensionSelfViewLink() throws Exception { + newPage( "MarkupExtensionSelfViewLink" ); + String src = "This should be a [MarkupExtensionSelfViewLink]()"; + + Assert.assertEquals( "<p>This should be a <a href=\"/test/Wiki.jsp?page=MarkupExtensionSelfViewLink\" class=\"wikipage\">MarkupExtensionSelfViewLink</a></p>\n", + translate( src ) ); + } + + @Test + public void testMarkupExtensionSelfEditLink() throws Exception { + String src = "This should be a [self<->link]()"; + + Assert.assertEquals( "<p>This should be a <a href=\"/test/Edit.jsp?page=self%3C-%3Elink\" title=\"Create "self<->link"\" class=\"createpage\">self<->link</a></p>\n", + translate( src ) ); + } + + @Test + public void testMarkupExtensionExternalLink() throws Exception { + testEngine.getWikiProperties().setProperty( "jspwiki.translatorReader.useOutlinkImage", "true" ); + String src = "This should be an [external link](https://jspwiki.apache.org)"; + + Assert.assertEquals( "<p>This should be an <a href=\"https://jspwiki.apache.org\" class=\"external\">external link</a><img class=\"outlink\" alt=\"\" src=\"/test/images/out.png\" /></p>\n", + translate( src ) ); + testEngine.getWikiProperties().remove( "jspwiki.translatorReader.useOutlinkImage" ); + } + + @Test + public void testMarkupExtensionInterWikiLink() throws Exception { + String src = "This should be an [interwiki link](JSPWiki:About)"; + + Assert.assertEquals( "<p>This should be an <a href=\"http://jspwiki-wiki.apache.org/Wiki.jsp?page=About\" class=\"interwiki\">interwiki link</a></p>\n", + translate( src ) ); + } + + @Test + public void testMarkupExtensionWrongInterWikiLink() throws Exception { + String src = "This should be an [interwiki link](JSPWiko:About)"; + + Assert.assertEquals( "<p>This should be an <span class=\"error\">No InterWiki reference defined in properties for Wiki called \"JSPWiko\"!</span></p>\n", + translate( src ) ); + } + + @Test + public void testMarkupExtensionACL() throws Exception { + String src = "[{ALLOW view PerryMason}]() This should be visible if the ACL allows you to see it"; + // text is seen because although ACL is added to the page, it is not applied while parsing / rendering + Assert.assertEquals( "<p> This should be visible if the ACL allows you to see it</p>\n", translate( src ) ); + // in any case, we also check that the created wikipage has the ACL added + Assert.assertEquals( " user = PerryMason: ((\"org.apache.wiki.auth.permissions.PagePermission\",\"JSPWiki:testpage\",\"view\"))\n", + testEngine.getPage( PAGE_NAME ).getAcl().toString() ); + } + + @Test + public void testMarkupExtensionMetadata() throws Exception { + String src = "[{SET Perry='Mason'}]() Some text after setting metadata"; + Assert.assertEquals( "<p> Some text after setting metadata</p>\n", translate( src ) ); + Assert.assertEquals( "Mason", testEngine.getPage( PAGE_NAME ).getAttribute( "Perry" ) ); + } + + @Test + public void testMarkupExtensionPlugin() throws Exception { + String src = "[{SamplePlugin text=test}]()"; + Assert.assertEquals( "<p>test</p>\n", translate( src ) ); + } + + @Test + public void testMarkupExtensionTOCPluginGetsSubstitutedWithMDTocExtension() throws Exception { + String src = "[{TableOfContents}]()\n" + + "# Header 1\n" + + "## Header 2\n" + + "## Header 2\n"; + Assert.assertEquals( "<p><div class=\"toc\">\n" + + "<div class=\"collapsebox\">\n" + + "<h4 id=\"section-TOC\">Table of Contents</h4>\n" + + "<ul>\n" + + "<li><a href=\"#header-1\">Header 1</a>\n" + + "<ul>\n" + + "<li><a href=\"#header-2\">Header 2</a></li>\n" + + "<li><a href=\"#header-2-1\">Header 2</a></li>\n" + + "</ul>\n" + + "</li>\n" + + "</ul>\n" + + "</div>\n" + + "</div>\n" + + "</p>\n" + + "<h1 id=\"header-1\">Header 1</h1>\n" + + "<h2 id=\"header-2\">Header 2</h2>\n" + + "<h2 id=\"header-2-1\">Header 2</h2>\n", translate( src ) ); + } + + @Test + public void testMarkupExtensionNonExistentPlugin() throws Exception { + String src = "[{PampleSlugin text=test}]()"; + Assert.assertEquals( "<p><span class=\"error\">JSPWiki : testpage - Plugin insertion failed: Could not find plugin PampleSlugin</span></p>\n", translate( src ) ); + } + + @Test + public void testMarkupExtensionVariable0() throws Exception { + String src = "Some text with some pre-set variable: [{$applicationname}]()"; + Assert.assertEquals( "<p>Some text with some pre-set variable: JSPWiki</p>\n", translate( src ) ); + } + + @Test + public void testMarkupExtensionVariable1() throws Exception { + String src = "[{SET Perry='Mason'}]() Some text after setting some metadata: [{$Perry}]()"; + Assert.assertEquals( "<p> Some text after setting some metadata: Mason</p>\n", translate( src ) ); + } + + @Test + public void testMarkupExtensionFootnote0() throws Exception { + String src = "Footnote[1]()"; + Assert.assertEquals( "<p>Footnote<a href=\"#ref-testpage-1\" class=\"footnoteref\">[1]</a></p>\n", translate( src ) ); + } + + @Test + public void testMarkupExtensionFootnoteMD() throws Exception { + String src = "text [^footnote] embedded.\n\n" + + "[^footnote]: footnote text\n" + + "with continuation"; + Assert.assertEquals( "<p>text <sup id=\"fnref-1\"><a class=\"footnoteref\" href=\"#fn-1\">1</a></sup> embedded.</p>\n" + + "<div class=\"footnotes\">\n" + + "<hr />\n" + + "<ol>\n" + + "<li id=\"fn-1\">\n" + + "<p>footnote text\n" + + "with continuation</p>\n" + + "<a href=\"#fnref-1\" class=\"footnote-backref\">↩</a>\n" + + "</li>\n" + + "</ol>\n" + + "</div>\n", translate( src ) ); + } + + @Test + public void testAttachmentLink() throws Exception { + String src = "This should be an [attachment link](Test/TestAtt.txt)"; + newPage( "Test" ); + + Attachment att = new Attachment( testEngine, "Test", "TestAtt.txt" ); + att.setAuthor( "FirstPost" ); + testEngine.getAttachmentManager().storeAttachment( att, testEngine.makeAttachmentFile() ); + + Assert.assertEquals( "<p>This should be an <a href=\"/test/attach/Test/TestAtt.txt\" class=\"attachment\">attachment link</a>" + + "<a href=\"/test/PageInfo.jsp?page=Test/TestAtt.txt\" class=\"infolink\">" + + "<img src=\"/test/images/attachment_small.png\" border=\"0\" alt=\"(info)\" />" + + "</a></p>\n", + translate( src ) ); + } + + @Test + public void testInlineImages() throws Exception { + String src = "Link [test](http://www.ecyrd.com/test.png)"; + + Assert.assertEquals( "<p>Link <img class=\"inline\" src=\"http://www.ecyrd.com/test.png\" alt=\"test\" /></p>\n", translate( src ) ); + } + + @Test + public void testInlineImages2() throws Exception { + String src = "Link [test](http://www.ecyrd.com/test.ppm)"; + + Assert.assertEquals( "<p>Link <a href=\"http://www.ecyrd.com/test.ppm\" class=\"external\">test</a></p>\n", translate( src ) ); + } + + @Test + public void testInlineImages3() throws Exception { + String src = "Link [test](http://images.com/testi)"; + + Assert.assertEquals( "<p>Link <img class=\"inline\" src=\"http://images.com/testi\" alt=\"test\" /></p>\n", translate( src ) ); + } + + @Test + public void testInlineImages4() throws Exception { + String src = "Link [test](http://foobar.jpg)"; + + Assert.assertEquals( "<p>Link <img class=\"inline\" src=\"http://foobar.jpg\" alt=\"test\" /></p>\n", translate( src ) ); + } + + // No link text should be just embedded link. + @Test + public void testInlineImagesLink2() throws Exception { + String src = "Link [http://foobar.jpg]()"; + + Assert.assertEquals( "<p>Link <img class=\"inline\" src=\"http://foobar.jpg\" alt=\"http://foobar.jpg\" /></p>\n", translate( src ) ); + } + + @Test + public void testInlineImagesLink() throws Exception { + String src = "Link [http://link.to/](http://foobar.jpg)"; + + Assert.assertEquals( "<p>Link <a href=\"http://link.to/\" class=\"external\"><img class=\"inline\" src=\"http://foobar.jpg\" alt=\"http://link.to/\" /></a></p>\n", + translate( src ) ); + } + + @Test + public void testInlineImagesLink3() throws Exception { + String src = "Link [SandBox](http://foobar.jpg)"; + + newPage( "SandBox" ); + + Assert.assertEquals( "<p>Link <a href=\"/test/Wiki.jsp?page=SandBox\" class=\"wikipage\"><img class=\"inline\" src=\"http://foobar.jpg\" alt=\"SandBox\" /></a></p>\n", + translate( src ) ); + } + + @Test + public void testHeadersWithSameNameGetIdWithCounter() throws Exception { + String src = "### Awesome H3\n" + + "### Awesome H3"; + + Assert.assertEquals( "<h3 id=\"awesome-h3\">Awesome H3</h3>\n" + + "<h3 id=\"awesome-h3-1\">Awesome H3</h3>\n", + translate( src ) ); + } + + @Before + public void setUp() throws Exception { + CacheManager.getInstance().removeAllCaches(); + props.setProperty( "jspwiki.translatorReader.matchEnglishPlurals", "true" ); + props.setProperty( "jspwiki.fileSystemProvider.pageDir", "./target/md-pageDir" ); + props.setProperty( "jspwiki.renderingManager.markupParser", MarkdownParser.class.getName() ); + props.setProperty( "jspwiki.renderingManager.renderer", MarkdownRenderer.class.getName() ); + testEngine = new TestEngine( props ); + } + + @After + public void tearDown() { + for( String name : created ) { + testEngine.deleteTestPage(name); + TestEngine.deleteAttachments(name); + } + + created.clear(); + } + + String translate( final String src ) throws Exception { + return translate( new WikiPage( testEngine, PAGE_NAME ), src ); + } + + String translate( final WikiEngine e, final String src) throws Exception { + return translate( e, new WikiPage( testEngine, PAGE_NAME ), src ); + } + + String translate( final WikiPage p, final String src ) throws Exception { + return translate( testEngine, p, src ); + } + + String translate( final WikiEngine e, final WikiPage p, final String src ) throws Exception { + WikiContext context = new WikiContext( e, testEngine.newHttpRequest(), p ); + MarkdownParser tr = new MarkdownParser( context, new BufferedReader( new StringReader( src ) ) ); + MarkdownRenderer conv = new MarkdownRenderer( context, tr.parse() ); + newPage( p.getName(), src ); + + return conv.getString(); + } + + void newPage( final String name ) throws WikiException { + newPage( name, "<test>" ); + } + + void newPage( final String name, final String text ) throws WikiException { + testEngine.saveText( name, text ); + created.add( name ); + } + +} http://git-wip-us.apache.org/repos/asf/jspwiki/blob/c1793a18/pom.xml ---------------------------------------------------------------------- diff --git a/pom.xml b/pom.xml index 8d59078..0c548c8 100644 --- a/pom.xml +++ b/pom.xml @@ -17,7 +17,9 @@ specific language governing permissions and limitations under the License. --> -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <parent> <groupId>org.apache</groupId> @@ -39,6 +41,7 @@ <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> + <flexmark.version>0.28.14</flexmark.version> <jdk.version>1.6</jdk.version> <lucene.version>4.7.0</lucene.version> <selenium.version>2.42.0</selenium.version> @@ -68,6 +71,24 @@ <dependencies> <!-- ordered alphabetically by scope:groupId:artifactId --> <!-- compile dependencies --> <dependency> + <groupId>com.vladsch.flexmark</groupId> + <artifactId>flexmark</artifactId> + <version>${flexmark.version}</version> + </dependency> + + <dependency> + <groupId>com.vladsch.flexmark</groupId> + <artifactId>flexmark-ext-footnotes</artifactId> + <version>${flexmark.version}</version> + </dependency> + + <dependency> + <groupId>com.vladsch.flexmark</groupId> + <artifactId>flexmark-ext-toc</artifactId> + <version>${flexmark.version}</version> + </dependency> + + <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.3.1</version> @@ -228,7 +249,7 @@ <dependency> <groupId>net.sourceforge.stripes</groupId> <artifactId>stripes</artifactId> - <version>1.5.8</version> + <version>1.6.0</version> </dependency> <!-- @@ -269,11 +290,11 @@ </dependency> <!-- runtime dependencies --> - <dependency> - <groupId>net.sourceforge.nekohtml</groupId> - <artifactId>nekohtml</artifactId> - <version>1.9.21</version> - </dependency> + <dependency> + <groupId>net.sourceforge.nekohtml</groupId> + <artifactId>nekohtml</artifactId> + <version>1.9.21</version> + </dependency> </dependencies> </dependencyManagement> @@ -668,6 +689,20 @@ </plugins> </build> </profile> + + <profile> + <id>markdown-support</id> + <activation> + <jdk>[1.7,)</jdk> + </activation> + <modules> + <module>jspwiki-wikipages</module> + <module>jspwiki-war</module> + <module>jspwiki-markdown</module> + <module>jspwiki-portable</module> + <module>jspwiki-it-tests</module><!-- IT tests are launched only if -Pintegration-tests is given --> + </modules> + </profile> </profiles> <organization>
