Commits

Brad Baker committed 6f7e8d7

Added Java callback generation of html

  • Participants
  • Parent commits 3c5dc38

Comments (0)

Files changed (7)

File atlassian-jira-markdown-plugin/src/main/java/com/atlassian/labs/markdown/jira/JiraMarkdownHtmlGeneration.java

+package com.atlassian.labs.markdown.jira;
+
+import com.atlassian.jira.issue.RendererManager;
+import com.atlassian.jira.issue.fields.renderer.IssueRenderContext;
+import com.atlassian.jira.issue.fields.renderer.wiki.AtlassianWikiRenderer;
+import com.atlassian.labs.markdown.MarkdownHtmlGeneration;
+import org.apache.commons.lang.StringUtils;
+import org.jsoup.Jsoup;
+import org.jsoup.nodes.Document;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * This understands JIRA constructs such as attachments
+ */
+public class JiraMarkdownHtmlGeneration implements MarkdownHtmlGeneration
+{
+    public static final Pattern HTTP_URL = Pattern.compile("^http[s]*:https?:\\/\\/");
+    public static final Pattern P_TAGS = Pattern.compile("^<p>(.*)</p>$");
+    private final RendererManager rendererManager;
+    private final IssueRenderContext issueRenderContext;
+
+    public JiraMarkdownHtmlGeneration(RendererManager rendererManager, IssueRenderContext issueRenderContext)
+    {
+        this.rendererManager = rendererManager;
+        this.issueRenderContext = issueRenderContext;
+    }
+
+    public String generateImageHTML(String sharedSecret, String url, String alt_text, String title)
+    {
+        StringBuilder sb = new StringBuilder("!");
+        if (HTTP_URL.matcher(url).find())
+        {
+            sb.append(url);
+        }
+        else
+        {
+            sb.append(url).append("|thumbnail");
+        }
+        addWikiAttr(sb, "alt", alt_text);
+        addWikiAttr(sb, "title", title);
+
+        sb.append("!");
+
+        return addSharedSecret(sharedSecret, "img", render(sb.toString()));
+    }
+
+    public String generateLinkHTML(String sharedSecret, String url, String title, String linkText)
+    {
+        StringBuilder sb = new StringBuilder()
+                .append("[")
+                .append(linkText)
+                .append('|')
+                .append(url);
+        if (StringUtils.isNotBlank(title))
+        {
+            sb.append('|').append(title);
+        }
+
+        sb.append("]");
+
+        return addSharedSecret(sharedSecret, "a", render(sb.toString()));
+    }
+
+    private void addWikiAttr(StringBuilder sb, String name, String value)
+    {
+        if (StringUtils.isNotBlank(value))
+        {
+            appendChar(sb, '|', ',');
+            sb.append(name).append('=').append(value).append(',');
+        }
+    }
+
+    private boolean appendChar(StringBuilder sb, final char c, char ifnotChar)
+    {
+        if (sb.charAt(sb.length() - 1) != ifnotChar)
+        {
+            sb.append(c);
+            return true;
+        }
+        return false;
+    }
+
+    private String render(String wikiText)
+    {
+        return rendererManager.getRendererForType(AtlassianWikiRenderer.RENDERER_TYPE).render(wikiText, issueRenderContext);
+    }
+
+    private String addSharedSecret(String sharedSecret, String selector, String html)
+    {
+        // wiki rendering puts <p> tags that we dont want
+        Matcher matcher = P_TAGS.matcher(html);
+        if (matcher.matches())
+        {
+            html = matcher.group(1);
+        }
+
+        Document frag = Jsoup.parseBodyFragment(html);
+        frag.select(selector).attr("data-shared-secret", sharedSecret);
+        return frag.body().html();
+    }
+}

File atlassian-jira-markdown-plugin/src/main/java/com/atlassian/labs/markdown/jira/JiraMarkdownMacro.java

 package com.atlassian.labs.markdown.jira;
 
 import com.atlassian.jira.issue.Issue;
+import com.atlassian.jira.issue.RendererManager;
 import com.atlassian.jira.issue.fields.renderer.IssueRenderContext;
 import com.atlassian.jira.issue.fields.renderer.wiki.AtlassianWikiRenderer;
 import com.atlassian.renderer.RenderContext;
  */
 public class JiraMarkdownMacro extends BaseMacro
 {
+
+    private final RendererManager rendererManager;
+
+    public JiraMarkdownMacro(RendererManager rendererManager)
+    {
+        this.rendererManager = rendererManager;
+    }
+
     public boolean isInline()
     {
         return true;
 
     public String execute(Map map, String body, RenderContext renderContext) throws MacroException
     {
-        return new JiraMarkdownProcessor().markdown(body, buildIssueRenderContext(renderContext));
+        return new JiraMarkdownProcessor(rendererManager).markdown(body, buildIssueRenderContext(renderContext));
     }
 
     private IssueRenderContext buildIssueRenderContext(RenderContext renderContext)

File atlassian-jira-markdown-plugin/src/main/java/com/atlassian/labs/markdown/jira/JiraMarkdownProcessor.java

 import com.atlassian.jira.issue.fields.renderer.IssueRenderContext;
 import com.atlassian.jira.issue.fields.renderer.wiki.AtlassianWikiRenderer;
 import com.atlassian.jira.util.JiraKeyUtils;
+import com.atlassian.labs.markdown.MarkdownHtmlGeneration;
 import com.atlassian.labs.markdown.PageDownMarkdown;
 
 import java.util.regex.Matcher;
  */
 public class JiraMarkdownProcessor
 {
+    private final RendererManager rendererManager;
+
+    public JiraMarkdownProcessor(RendererManager rendererManager)
+    {
+        this.rendererManager = rendererManager;
+    }
+
     public String markdown(final String text, final IssueRenderContext issueRenderContext)
     {
-        // PageDown invocation
-        String markdown = new PageDownMarkdown().markdown(text);
+        final JiraMarkdownHtmlGeneration markdownHtmlGeneration = new JiraMarkdownHtmlGeneration(rendererManager, issueRenderContext);
+        final PageDownMarkdown pageDownMarkdown = new PageDownMarkdown(markdownHtmlGeneration);
+
+        String markdown = pageDownMarkdown.markdown(text);
 
         markdown = JiraKeyUtils.linkBugKeys(markdown);
         markdown = replaceMentionsWithNames(markdown, issueRenderContext);
     {
         // in order to get full user profile link rendering we end up using the wiki render to turn [~xxxxx] into a user profile link
         // freaky eh?  wiki in markup inside wiki?
-        String wikiLink = ComponentAccessor.getComponent(RendererManager.class).getRendererForType(AtlassianWikiRenderer.RENDERER_TYPE).render(markup, issueRenderContext);
+        String wikiLink = rendererManager.getRendererForType(AtlassianWikiRenderer.RENDERER_TYPE).render(markup, issueRenderContext);
         sb.append(wikiLink);
     }
 }

File atlassian-jira-markdown-plugin/src/main/java/com/atlassian/labs/markdown/jira/JiraMarkdownRenderer.java

 package com.atlassian.labs.markdown.jira;
 
+import com.atlassian.jira.issue.RendererManager;
 import com.atlassian.jira.issue.fields.renderer.IssueRenderContext;
 import com.atlassian.jira.issue.fields.renderer.JiraRendererPlugin;
 import com.atlassian.jira.plugin.renderer.JiraRendererModuleDescriptor;
 
     private JiraRendererModuleDescriptor jiraRendererModuleDescriptor;
 
+    private final RendererManager rendererManager;
+
+    public JiraMarkdownRenderer(RendererManager rendererManager)
+    {
+        this.rendererManager = rendererManager;
+    }
+
     public String render(String value, IssueRenderContext context)
     {
-        return new JiraMarkdownProcessor().markdown(value, context);
+        return new JiraMarkdownProcessor(rendererManager).markdown(value, context);
     }
 
     public String renderAsText(String value, IssueRenderContext context)

File atlassian-markdown-core/src/main/java/com/atlassian/labs/markdown/MarkdownHtmlGeneration.java

+package com.atlassian.labs.markdown;
+
+/**
+ * This interface allows the caller to get involved in the HTML generation
+ * that is passed back to the pageDown JS
+ */
+public interface MarkdownHtmlGeneration
+{
+    String generateImageHTML(String sharedSecret, String url, String alt_text, String title);
+    
+    String generateLinkHTML(String sharedSecret, String url, String title, String linkText);
+}

File atlassian-markdown-core/src/main/java/com/atlassian/labs/markdown/PageDownMarkdown.java

  */
 public class PageDownMarkdown
 {
+    private final MarkdownHtmlGeneration markdownHtmlGeneration;
+
+    public PageDownMarkdown(MarkdownHtmlGeneration markdownHtmlGeneration)
+    {
+        this.markdownHtmlGeneration = markdownHtmlGeneration;
+    }
+
+    public PageDownMarkdown()
+    {
+        this.markdownHtmlGeneration = null;
+    }
 
     public String markdown(final String markdownText)
     {
         try
         {
             final Bindings bindings = new SimpleBindings();
+            bindings.put("javaHtmlGeneration", markdownHtmlGeneration);
+
             String js = getPageDownJS();
+
             Object pageDownConverter = engine.eval(js, bindings);
             return invocableEngine.invokeMethod(pageDownConverter, "makeHtml", markdownText) + "";
         }

File atlassian-markdown-core/src/main/resources/pagedown/js/Markdown.SharedSecret.js

-(function ()
-{
+(function() {
     /**
      * This top level method instantiates a new shared secret per run and then invokes markdown with it
      *
      */
     Markdown.getSharedSecretConverter = function ()
     {
+        if (typeof javaHtmlGeneration == 'undefined') {
+            javaHtmlGeneration = false;
+        }
         /*
          This invoker script wraps up the PageDown code into something that can be more easily invoked from Java.  It was of course
          never part of the standard PageDown code base.
 
         converter.hooks.set("generateImageHTML", function (obj)
         {
+            if (javaHtmlGeneration) {
+                return javaHtmlGeneration.generateImageHTML(sharedSecret, obj.url,obj.alt_text,obj.title);
+            }
             return '<img' +
                     toAttr('src', obj.url) +
                     toAttr('alt', obj.alt_text) +
         });
         converter.hooks.set("generateLinkHTML", function (obj)
         {
+            if (javaHtmlGeneration) {
+                return javaHtmlGeneration.generateLinkHTML(sharedSecret, obj.url,obj.title, obj.link_text);
+            }
             return '<a' +
                     toAttr('href', obj.url) +
                     toAttr('title', obj.title) +
 
 
         return converter;
-    };
+   };
 
-})
-();
+})();
 
+// the java support requires that the last object evaluated is what is accessible to be called.
 Markdown.getSharedSecretConverter();