Newer
Older
gitbucket_jkp / src / main / scala / view / Asciidoc.scala
package view

import org.asciidoctor.Asciidoctor
import org.asciidoctor.AttributesBuilder
import org.asciidoctor.OptionsBuilder
import org.asciidoctor.SafeMode
import org.htmlcleaner.HtmlCleaner
import org.htmlcleaner.HtmlNode
import org.htmlcleaner.SimpleHtmlSerializer
import org.htmlcleaner.TagNode
import org.htmlcleaner.TagNodeVisitor

object Asciidoc {

  private[this] lazy val asciidoctor = Asciidoctor.Factory.create()

  /**
   * Converts Markdown of Wiki pages to HTML.
   */
  def toHtml(asciidoc: String, branch: String, repository: service.RepositoryService.RepositoryInfo,
             enableWikiLink: Boolean, enableRefsLink: Boolean)(implicit context: app.Context): String = {

    val options = OptionsBuilder.options()
    options.safe(SafeMode.SECURE)
    val attributes = AttributesBuilder.attributes()
    attributes.showTitle(true)
    options.attributes(attributes.get())
    val rendered = asciidoctor.render(asciidoc, options)

    // this is always relative to the base dir of the repo, as we currently only render README files.
    val relativeUrlPrefix = s"${helpers.url(repository)}/blob/${branch}/"
    prefixRelativeUrls(rendered, relativeUrlPrefix)
  }

  def prefixRelativeUrls(html: String, urlPrefix: String): String = {
    val cleaner = new HtmlCleaner()
    val node = cleaner.clean(html)
    node.traverse(new TagNodeVisitor() {
      override def visit(tagNode: TagNode, htmlNode: HtmlNode): Boolean = {
        htmlNode match {
          case tag: TagNode if tag.getName == "a" =>
            Option(tag.getAttributeByName("href")) foreach { href =>
              if (!href.startsWith("/") && !href.startsWith("http://") && !href.startsWith("https://")) {
                tag.addAttribute("href", s"${urlPrefix}${href}")
              }
            }
          case _ =>
        }
        // continue traversal
        true
      }
    })
    new SimpleHtmlSerializer(cleaner.getProperties()).getAsString(node)
  }

}