From 8677146a8ded862b4555188dfd77d88d8270df63 Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Wed, 26 Feb 2014 12:09:14 +0100 Subject: [PATCH 01/10] Show the correct name of the readme file (instead of showing always README.md). --- src/main/scala/app/RepositoryViewerController.scala | 2 +- src/main/twirl/repo/files.scala.html | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/scala/app/RepositoryViewerController.scala b/src/main/scala/app/RepositoryViewerController.scala index 272613682..fcc81dfe6 100644 --- a/src/main/scala/app/RepositoryViewerController.scala +++ b/src/main/scala/app/RepositoryViewerController.scala @@ -276,7 +276,7 @@ trait RepositoryViewerControllerBase extends ControllerBase { val readme = files.find { file => readmeFiles.contains(file.name.toLowerCase) }.map { file => - StringUtil.convertFromByteArray(JGitUtil.getContent(Git.open(getRepositoryDir(repository.owner, repository.name)), file.id, true).get) + file -> StringUtil.convertFromByteArray(JGitUtil.getContent(Git.open(getRepositoryDir(repository.owner, repository.name)), file.id, true).get) } repo.html.files(revision, repository, diff --git a/src/main/twirl/repo/files.scala.html b/src/main/twirl/repo/files.scala.html index 94f6dac3d..823298ec7 100644 --- a/src/main/twirl/repo/files.scala.html +++ b/src/main/twirl/repo/files.scala.html @@ -3,7 +3,7 @@ pathList: List[String], latestCommit: util.JGitUtil.CommitInfo, files: List[util.JGitUtil.FileInfo], - readme: Option[String])(implicit context: app.Context) + readme: Option[(util.JGitUtil.FileInfo, String)])(implicit context: app.Context) @import context._ @import view.helpers._ @html.main(s"${repository.owner}/${repository.name}", Some(repository)) { @@ -77,9 +77,9 @@ - @readme.map { content => + @readme.map { case(file, content) =>
-
README.md
+
@file.name
@markdown(content, repository, false, false)
} From 9078aa6d085b6a268a7f6343a5c37536b054b38f Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Wed, 26 Feb 2014 13:53:50 +0100 Subject: [PATCH 02/10] Added asciidoctorj dependency. --- project/build.scala | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/project/build.scala b/project/build.scala index ce6d4d9f9..a87a457c6 100644 --- a/project/build.scala +++ b/project/build.scala @@ -15,6 +15,7 @@ object MyBuild extends Build { "gitbucket", file("."), settings = Defaults.defaultSettings ++ ScalatraPlugin.scalatraWithJRebel ++ Seq( + sourcesInBase := false, organization := Organization, name := Name, version := Version, @@ -42,7 +43,8 @@ object MyBuild extends Build { "ch.qos.logback" % "logback-classic" % "1.0.13" % "runtime", "org.eclipse.jetty" % "jetty-webapp" % "8.1.8.v20121106" % "container;provided", "org.eclipse.jetty.orbit" % "javax.servlet" % "3.0.0.v201112011016" % "container;provided;test" artifacts Artifact("javax.servlet", "jar", "jar"), - "junit" % "junit" % "4.11" % "test" + "junit" % "junit" % "4.11" % "test", + "org.asciidoctor" % "asciidoctor-java-integration" % "0.1.4" ), EclipseKeys.withSource := true, javacOptions in compile ++= Seq("-target", "6", "-source", "6"), From 97b1a0090ddd1ab6f92a1286b118957e403a6ea2 Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Wed, 26 Feb 2014 15:14:39 +0100 Subject: [PATCH 03/10] Initial support for rendering asciidoc files. --- .../app/RepositoryViewerController.scala | 2 +- src/main/scala/view/Asciidoc.scala | 30 +++++++++++++++++++ src/main/scala/view/helpers.scala | 25 ++++++++++++++++ src/main/twirl/repo/files.scala.html | 2 +- 4 files changed, 57 insertions(+), 2 deletions(-) create mode 100644 src/main/scala/view/Asciidoc.scala diff --git a/src/main/scala/app/RepositoryViewerController.scala b/src/main/scala/app/RepositoryViewerController.scala index fcc81dfe6..7337c2f25 100644 --- a/src/main/scala/app/RepositoryViewerController.scala +++ b/src/main/scala/app/RepositoryViewerController.scala @@ -251,7 +251,7 @@ trait RepositoryViewerControllerBase extends ControllerBase { } - private val readmeFiles = Seq("readme.md", "readme.markdown") + private val readmeFiles = view.helpers.renderableSuffixes.map(suffix => s"readme${suffix}") /** * Provides HTML of the file list. diff --git a/src/main/scala/view/Asciidoc.scala b/src/main/scala/view/Asciidoc.scala new file mode 100644 index 000000000..523f14651 --- /dev/null +++ b/src/main/scala/view/Asciidoc.scala @@ -0,0 +1,30 @@ +package view + +import util.StringUtil +import util.ControlUtil._ +import util.Directory._ +import org.parboiled.common.StringUtils +import org.pegdown._ +import org.pegdown.ast._ +import org.pegdown.LinkRenderer.Rendering +import java.text.Normalizer +import java.util.Locale +import scala.collection.JavaConverters._ +import service.{ RequestCache, WikiService } +import org.asciidoctor.{ Asciidoctor, OptionsBuilder, SafeMode } + +object Asciidoc { + + private[this] lazy val asciidoctor = Asciidoctor.Factory.create() + + /** + * Converts Markdown of Wiki pages to HTML. + */ + def toHtml(asciidoc: String, repository: service.RepositoryService.RepositoryInfo, + enableWikiLink: Boolean, enableRefsLink: Boolean)(implicit context: app.Context): String = { + val options = OptionsBuilder.options() + options.safe(SafeMode.SECURE) + asciidoctor.render(asciidoc, options) + } +} + diff --git a/src/main/scala/view/helpers.scala b/src/main/scala/view/helpers.scala index 8dc2adf43..a06f97f4a 100644 --- a/src/main/scala/view/helpers.scala +++ b/src/main/scala/view/helpers.scala @@ -27,6 +27,16 @@ object helpers extends AvatarImageProvider with LinkConverter with RequestCache def plural(count: Int, singular: String, plural: String = ""): String = if(count == 1) singular else if(plural.isEmpty) singular + "s" else plural + private[this] val renderersBySuffix: Seq[(String, (String, service.RepositoryService.RepositoryInfo, Boolean, Boolean, app.Context) => Html)] = + Seq( + ".md" -> ((fileContent, repository, enableWikiLink, enableRefsLink, context) => markdown(fileContent, repository, enableWikiLink, enableRefsLink)(context)), + ".markdown" -> ((fileContent, repository, enableWikiLink, enableRefsLink, context) => markdown(fileContent, repository, enableWikiLink, enableRefsLink)(context)), + ".adoc" -> ((fileContent, repository, enableWikiLink, enableRefsLink, context) => asciidoc(fileContent, repository, enableWikiLink, enableRefsLink)(context)), + ".asciidoc" -> ((fileContent, repository, enableWikiLink, enableRefsLink, context) => asciidoc(fileContent, repository, enableWikiLink, enableRefsLink)(context)) + ) + + def renderableSuffixes: Seq[String] = renderersBySuffix.map(_._1) + /** * Converts Markdown of Wiki pages to HTML. */ @@ -34,6 +44,21 @@ object helpers extends AvatarImageProvider with LinkConverter with RequestCache enableWikiLink: Boolean, enableRefsLink: Boolean)(implicit context: app.Context): Html = Html(Markdown.toHtml(value, repository, enableWikiLink, enableRefsLink)) + def renderMarkup(fileName: String, fileContent: String, + repository: service.RepositoryService.RepositoryInfo, + enableWikiLink: Boolean, enableRefsLink: Boolean)(implicit context: app.Context): Html = { + + val fileNameLower = fileName.toLowerCase + renderersBySuffix.find { case (suffix, _) => fileNameLower.endsWith(suffix) } match { + case Some((_, handler)) => handler(fileContent, repository, enableWikiLink, enableRefsLink, context) + case None => Html("UNSUPPORTED MARKUP TYPE") + } + } + + def asciidoc(value: String, repository: service.RepositoryService.RepositoryInfo, + enableWikiLink: Boolean, enableRefsLink: Boolean)(implicit context: app.Context): Html = + Html(Asciidoc.toHtml(value, repository, enableWikiLink, enableRefsLink)) + /** * Returns <img> which displays the avatar icon for the given user name. * This method looks up Gravatar if avatar icon has not been configured in user settings. diff --git a/src/main/twirl/repo/files.scala.html b/src/main/twirl/repo/files.scala.html index 823298ec7..814e498f7 100644 --- a/src/main/twirl/repo/files.scala.html +++ b/src/main/twirl/repo/files.scala.html @@ -80,7 +80,7 @@ @readme.map { case(file, content) =>
@file.name
-
@markdown(content, repository, false, false)
+
@renderMarkup(file.name, content, repository, false, false)
} } From cbf615d699bdc9facdea642d95e0358bd4a1caa8 Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Wed, 26 Feb 2014 16:13:39 +0100 Subject: [PATCH 04/10] Support plain text readme files (with .txt or no extension). --- src/main/scala/app/RepositoryViewerController.scala | 2 +- src/main/scala/view/helpers.scala | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/scala/app/RepositoryViewerController.scala b/src/main/scala/app/RepositoryViewerController.scala index 7337c2f25..5c796353f 100644 --- a/src/main/scala/app/RepositoryViewerController.scala +++ b/src/main/scala/app/RepositoryViewerController.scala @@ -251,7 +251,7 @@ trait RepositoryViewerControllerBase extends ControllerBase { } - private val readmeFiles = view.helpers.renderableSuffixes.map(suffix => s"readme${suffix}") + private val readmeFiles = view.helpers.renderableSuffixes.map(suffix => s"readme${suffix}") ++ Seq("readme.txt", "readme") /** * Provides HTML of the file list. diff --git a/src/main/scala/view/helpers.scala b/src/main/scala/view/helpers.scala index a06f97f4a..b60b4b3d5 100644 --- a/src/main/scala/view/helpers.scala +++ b/src/main/scala/view/helpers.scala @@ -51,7 +51,11 @@ object helpers extends AvatarImageProvider with LinkConverter with RequestCache val fileNameLower = fileName.toLowerCase renderersBySuffix.find { case (suffix, _) => fileNameLower.endsWith(suffix) } match { case Some((_, handler)) => handler(fileContent, repository, enableWikiLink, enableRefsLink, context) - case None => Html("UNSUPPORTED MARKUP TYPE") + case None => Html( + s"${ + fileContent.split("(\\r\\n)|\\n").map(xml.Utility.escape(_)).mkString("
") + }
" + ) } } From 4600b5a3bfa5d38dfbfbc461279ab1f7b0987087 Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Fri, 28 Feb 2014 09:36:04 +0100 Subject: [PATCH 05/10] Enabled rendering of page document title. --- src/main/scala/view/Asciidoc.scala | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/scala/view/Asciidoc.scala b/src/main/scala/view/Asciidoc.scala index 523f14651..978f49f13 100644 --- a/src/main/scala/view/Asciidoc.scala +++ b/src/main/scala/view/Asciidoc.scala @@ -11,7 +11,7 @@ import java.text.Normalizer import java.util.Locale import scala.collection.JavaConverters._ import service.{ RequestCache, WikiService } -import org.asciidoctor.{ Asciidoctor, OptionsBuilder, SafeMode } +import org.asciidoctor.{ Asciidoctor, Attributes, AttributesBuilder, OptionsBuilder, SafeMode } object Asciidoc { @@ -24,6 +24,9 @@ object Asciidoc { 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()) asciidoctor.render(asciidoc, options) } } From 3db3bf1b74d2e64d89da6521bdce47031aae65ed Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Tue, 4 Mar 2014 11:38:56 +0100 Subject: [PATCH 06/10] Rewrite relative links to reflect the base url of the repo. --- project/build.scala | 3 +- src/main/scala/view/Asciidoc.scala | 52 ++++++++++++++++++++-------- src/main/scala/view/helpers.scala | 18 +++++----- src/main/twirl/repo/files.scala.html | 2 +- 4 files changed, 50 insertions(+), 25 deletions(-) diff --git a/project/build.scala b/project/build.scala index a87a457c6..bcf125e95 100644 --- a/project/build.scala +++ b/project/build.scala @@ -44,7 +44,8 @@ object MyBuild extends Build { "org.eclipse.jetty" % "jetty-webapp" % "8.1.8.v20121106" % "container;provided", "org.eclipse.jetty.orbit" % "javax.servlet" % "3.0.0.v201112011016" % "container;provided;test" artifacts Artifact("javax.servlet", "jar", "jar"), "junit" % "junit" % "4.11" % "test", - "org.asciidoctor" % "asciidoctor-java-integration" % "0.1.4" + "org.asciidoctor" % "asciidoctor-java-integration" % "0.1.4", + "net.sourceforge.htmlcleaner" % "htmlcleaner" % "2.7" ), EclipseKeys.withSource := true, javacOptions in compile ++= Seq("-target", "6", "-source", "6"), diff --git a/src/main/scala/view/Asciidoc.scala b/src/main/scala/view/Asciidoc.scala index 978f49f13..8d9d37601 100644 --- a/src/main/scala/view/Asciidoc.scala +++ b/src/main/scala/view/Asciidoc.scala @@ -1,17 +1,14 @@ package view -import util.StringUtil -import util.ControlUtil._ -import util.Directory._ -import org.parboiled.common.StringUtils -import org.pegdown._ -import org.pegdown.ast._ -import org.pegdown.LinkRenderer.Rendering -import java.text.Normalizer -import java.util.Locale -import scala.collection.JavaConverters._ -import service.{ RequestCache, WikiService } -import org.asciidoctor.{ Asciidoctor, Attributes, AttributesBuilder, OptionsBuilder, SafeMode } +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 { @@ -20,14 +17,41 @@ object Asciidoc { /** * Converts Markdown of Wiki pages to HTML. */ - def toHtml(asciidoc: String, repository: service.RepositoryService.RepositoryInfo, + 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()) - asciidoctor.render(asciidoc, options) + 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) + } + } diff --git a/src/main/scala/view/helpers.scala b/src/main/scala/view/helpers.scala index b60b4b3d5..4c7ad5b31 100644 --- a/src/main/scala/view/helpers.scala +++ b/src/main/scala/view/helpers.scala @@ -27,12 +27,12 @@ object helpers extends AvatarImageProvider with LinkConverter with RequestCache def plural(count: Int, singular: String, plural: String = ""): String = if(count == 1) singular else if(plural.isEmpty) singular + "s" else plural - private[this] val renderersBySuffix: Seq[(String, (String, service.RepositoryService.RepositoryInfo, Boolean, Boolean, app.Context) => Html)] = + private[this] val renderersBySuffix: Seq[(String, (String, String, service.RepositoryService.RepositoryInfo, Boolean, Boolean, app.Context) => Html)] = Seq( - ".md" -> ((fileContent, repository, enableWikiLink, enableRefsLink, context) => markdown(fileContent, repository, enableWikiLink, enableRefsLink)(context)), - ".markdown" -> ((fileContent, repository, enableWikiLink, enableRefsLink, context) => markdown(fileContent, repository, enableWikiLink, enableRefsLink)(context)), - ".adoc" -> ((fileContent, repository, enableWikiLink, enableRefsLink, context) => asciidoc(fileContent, repository, enableWikiLink, enableRefsLink)(context)), - ".asciidoc" -> ((fileContent, repository, enableWikiLink, enableRefsLink, context) => asciidoc(fileContent, repository, enableWikiLink, enableRefsLink)(context)) + ".md" -> ((fileContent, branch, repository, enableWikiLink, enableRefsLink, context) => markdown(fileContent, repository, enableWikiLink, enableRefsLink)(context)), + ".markdown" -> ((fileContent, branch, repository, enableWikiLink, enableRefsLink, context) => markdown(fileContent, repository, enableWikiLink, enableRefsLink)(context)), + ".adoc" -> ((fileContent, branch, repository, enableWikiLink, enableRefsLink, context) => asciidoc(fileContent, branch, repository, enableWikiLink, enableRefsLink)(context)), + ".asciidoc" -> ((fileContent, branch, repository, enableWikiLink, enableRefsLink, context) => asciidoc(fileContent, branch, repository, enableWikiLink, enableRefsLink)(context)) ) def renderableSuffixes: Seq[String] = renderersBySuffix.map(_._1) @@ -44,13 +44,13 @@ object helpers extends AvatarImageProvider with LinkConverter with RequestCache enableWikiLink: Boolean, enableRefsLink: Boolean)(implicit context: app.Context): Html = Html(Markdown.toHtml(value, repository, enableWikiLink, enableRefsLink)) - def renderMarkup(fileName: String, fileContent: String, + def renderMarkup(fileName: String, fileContent: String, branch: String, repository: service.RepositoryService.RepositoryInfo, enableWikiLink: Boolean, enableRefsLink: Boolean)(implicit context: app.Context): Html = { val fileNameLower = fileName.toLowerCase renderersBySuffix.find { case (suffix, _) => fileNameLower.endsWith(suffix) } match { - case Some((_, handler)) => handler(fileContent, repository, enableWikiLink, enableRefsLink, context) + case Some((_, handler)) => handler(fileContent, branch, repository, enableWikiLink, enableRefsLink, context) case None => Html( s"${ fileContent.split("(\\r\\n)|\\n").map(xml.Utility.escape(_)).mkString("
") @@ -59,9 +59,9 @@ object helpers extends AvatarImageProvider with LinkConverter with RequestCache } } - def asciidoc(value: String, repository: service.RepositoryService.RepositoryInfo, + def asciidoc(value: String, branch: String, repository: service.RepositoryService.RepositoryInfo, enableWikiLink: Boolean, enableRefsLink: Boolean)(implicit context: app.Context): Html = - Html(Asciidoc.toHtml(value, repository, enableWikiLink, enableRefsLink)) + Html(Asciidoc.toHtml(value, branch, repository, enableWikiLink, enableRefsLink)) /** * Returns <img> which displays the avatar icon for the given user name. diff --git a/src/main/twirl/repo/files.scala.html b/src/main/twirl/repo/files.scala.html index 470021fce..5362b1448 100644 --- a/src/main/twirl/repo/files.scala.html +++ b/src/main/twirl/repo/files.scala.html @@ -80,7 +80,7 @@ @readme.map { case(file, content) =>
@file.name
-
@renderMarkup(file.name, content, repository, false, false)
+
@renderMarkup(file.name, content, branch, repository, false, false)
} } From 9e1352c8b155390ac8a5e0ab048e8a2c32c8914b Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Tue, 4 Mar 2014 16:19:00 +0100 Subject: [PATCH 07/10] Enabled rendering of renderable files in blob view. --- src/main/twirl/repo/blob.scala.html | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/twirl/repo/blob.scala.html b/src/main/twirl/repo/blob.scala.html index 25a9910b1..182a334d2 100644 --- a/src/main/twirl/repo/blob.scala.html +++ b/src/main/twirl/repo/blob.scala.html @@ -37,7 +37,13 @@ @if(content.viewType == "text"){ -
@content.content.get
+ @defining(pathList.reverse.head) { file => + @if(renderableSuffixes.find(suffix => file.toLowerCase.endsWith(suffix))) { + @renderMarkup(file, content.content.get, branch, repository, false, false) + } else { +
@content.content.get
+ } + } } @if(content.viewType == "image"){ From 4276c8f23ee08f4c173dba8111f90265c6ad34dc Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Tue, 4 Mar 2014 16:42:41 +0100 Subject: [PATCH 08/10] Support relative links in asciidoc files. --- .../app/RepositoryViewerController.scala | 23 +++++++++++-------- src/main/scala/view/Asciidoc.scala | 9 +++++--- src/main/scala/view/helpers.scala | 20 ++++++++-------- src/main/twirl/repo/blob.scala.html | 2 +- src/main/twirl/repo/files.scala.html | 8 +++---- 5 files changed, 34 insertions(+), 28 deletions(-) diff --git a/src/main/scala/app/RepositoryViewerController.scala b/src/main/scala/app/RepositoryViewerController.scala index 5c796353f..6893e63b1 100644 --- a/src/main/scala/app/RepositoryViewerController.scala +++ b/src/main/scala/app/RepositoryViewerController.scala @@ -268,16 +268,19 @@ trait RepositoryViewerControllerBase extends ControllerBase { using(Git.open(getRepositoryDir(repository.owner, repository.name))){ git => val revisions = Seq(if(revstr.isEmpty) repository.repository.defaultBranch else revstr, repository.branchList.head) // get specified commit - JGitUtil.getDefaultBranch(git, repository, revstr).map { case (objectId, revision) => - defining(JGitUtil.getRevCommitFromId(git, objectId)){ revCommit => - // get files - val files = JGitUtil.getFileList(git, revision, path) - // process README.md or README.markdown - val readme = files.find { file => - readmeFiles.contains(file.name.toLowerCase) - }.map { file => - file -> StringUtil.convertFromByteArray(JGitUtil.getContent(Git.open(getRepositoryDir(repository.owner, repository.name)), file.id, true).get) - } + JGitUtil.getDefaultBranch(git, repository, revstr).map { + case (objectId, revision) => + defining(JGitUtil.getRevCommitFromId(git, objectId)) { revCommit => + // get files + val files = JGitUtil.getFileList(git, revision, path) + val parentPath = if (path == ".") Nil else path.split("/").toList + // process README.md or README.markdown + val readme = files.find { file => + readmeFiles.contains(file.name.toLowerCase) + }.map { file => + val path = (file.name :: parentPath.reverse).reverse + path -> StringUtil.convertFromByteArray(JGitUtil.getContent(Git.open(getRepositoryDir(repository.owner, repository.name)), file.id, true).get) + } repo.html.files(revision, repository, if(path == ".") Nil else path.split("/").toList, // current path diff --git a/src/main/scala/view/Asciidoc.scala b/src/main/scala/view/Asciidoc.scala index 8d9d37601..88c80fb1d 100644 --- a/src/main/scala/view/Asciidoc.scala +++ b/src/main/scala/view/Asciidoc.scala @@ -17,7 +17,7 @@ object Asciidoc { /** * Converts Markdown of Wiki pages to HTML. */ - def toHtml(asciidoc: String, branch: String, repository: service.RepositoryService.RepositoryInfo, + def toHtml(filePath: List[String], asciidoc: String, branch: String, repository: service.RepositoryService.RepositoryInfo, enableWikiLink: Boolean, enableRefsLink: Boolean)(implicit context: app.Context): String = { val options = OptionsBuilder.options() @@ -27,8 +27,11 @@ object Asciidoc { 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}/" + val path = filePath.reverse.tail.reverse match { + case Nil => "" + case p => p.mkString("", "/", "/") + } + val relativeUrlPrefix = s"${helpers.url(repository)}/blob/${branch}/${path}" prefixRelativeUrls(rendered, relativeUrlPrefix) } diff --git a/src/main/scala/view/helpers.scala b/src/main/scala/view/helpers.scala index 4c7ad5b31..feb5f21fb 100644 --- a/src/main/scala/view/helpers.scala +++ b/src/main/scala/view/helpers.scala @@ -27,12 +27,12 @@ object helpers extends AvatarImageProvider with LinkConverter with RequestCache def plural(count: Int, singular: String, plural: String = ""): String = if(count == 1) singular else if(plural.isEmpty) singular + "s" else plural - private[this] val renderersBySuffix: Seq[(String, (String, String, service.RepositoryService.RepositoryInfo, Boolean, Boolean, app.Context) => Html)] = + private[this] val renderersBySuffix: Seq[(String, (List[String], String, String, service.RepositoryService.RepositoryInfo, Boolean, Boolean, app.Context) => Html)] = Seq( - ".md" -> ((fileContent, branch, repository, enableWikiLink, enableRefsLink, context) => markdown(fileContent, repository, enableWikiLink, enableRefsLink)(context)), - ".markdown" -> ((fileContent, branch, repository, enableWikiLink, enableRefsLink, context) => markdown(fileContent, repository, enableWikiLink, enableRefsLink)(context)), - ".adoc" -> ((fileContent, branch, repository, enableWikiLink, enableRefsLink, context) => asciidoc(fileContent, branch, repository, enableWikiLink, enableRefsLink)(context)), - ".asciidoc" -> ((fileContent, branch, repository, enableWikiLink, enableRefsLink, context) => asciidoc(fileContent, branch, repository, enableWikiLink, enableRefsLink)(context)) + ".md" -> ((filePath, fileContent, branch, repository, enableWikiLink, enableRefsLink, context) => markdown(fileContent, repository, enableWikiLink, enableRefsLink)(context)), + ".markdown" -> ((filePath, fileContent, branch, repository, enableWikiLink, enableRefsLink, context) => markdown(fileContent, repository, enableWikiLink, enableRefsLink)(context)), + ".adoc" -> ((filePath, fileContent, branch, repository, enableWikiLink, enableRefsLink, context) => asciidoc(filePath, fileContent, branch, repository, enableWikiLink, enableRefsLink)(context)), + ".asciidoc" -> ((filePath, fileContent, branch, repository, enableWikiLink, enableRefsLink, context) => asciidoc(filePath, fileContent, branch, repository, enableWikiLink, enableRefsLink)(context)) ) def renderableSuffixes: Seq[String] = renderersBySuffix.map(_._1) @@ -44,13 +44,13 @@ object helpers extends AvatarImageProvider with LinkConverter with RequestCache enableWikiLink: Boolean, enableRefsLink: Boolean)(implicit context: app.Context): Html = Html(Markdown.toHtml(value, repository, enableWikiLink, enableRefsLink)) - def renderMarkup(fileName: String, fileContent: String, branch: String, + def renderMarkup(filePath: List[String], fileContent: String, branch: String, repository: service.RepositoryService.RepositoryInfo, enableWikiLink: Boolean, enableRefsLink: Boolean)(implicit context: app.Context): Html = { - val fileNameLower = fileName.toLowerCase + val fileNameLower = filePath.reverse.head.toLowerCase renderersBySuffix.find { case (suffix, _) => fileNameLower.endsWith(suffix) } match { - case Some((_, handler)) => handler(fileContent, branch, repository, enableWikiLink, enableRefsLink, context) + case Some((_, handler)) => handler(filePath, fileContent, branch, repository, enableWikiLink, enableRefsLink, context) case None => Html( s"${ fileContent.split("(\\r\\n)|\\n").map(xml.Utility.escape(_)).mkString("
") @@ -59,9 +59,9 @@ object helpers extends AvatarImageProvider with LinkConverter with RequestCache } } - def asciidoc(value: String, branch: String, repository: service.RepositoryService.RepositoryInfo, + def asciidoc(filePath: List[String], value: String, branch: String, repository: service.RepositoryService.RepositoryInfo, enableWikiLink: Boolean, enableRefsLink: Boolean)(implicit context: app.Context): Html = - Html(Asciidoc.toHtml(value, branch, repository, enableWikiLink, enableRefsLink)) + Html(Asciidoc.toHtml(filePath, value, branch, repository, enableWikiLink, enableRefsLink)) /** * Returns <img> which displays the avatar icon for the given user name. diff --git a/src/main/twirl/repo/blob.scala.html b/src/main/twirl/repo/blob.scala.html index 182a334d2..acb193a14 100644 --- a/src/main/twirl/repo/blob.scala.html +++ b/src/main/twirl/repo/blob.scala.html @@ -39,7 +39,7 @@ @if(content.viewType == "text"){ @defining(pathList.reverse.head) { file => @if(renderableSuffixes.find(suffix => file.toLowerCase.endsWith(suffix))) { - @renderMarkup(file, content.content.get, branch, repository, false, false) + @renderMarkup(pathList, content.content.get, branch, repository, false, false) } else {
@content.content.get
} diff --git a/src/main/twirl/repo/files.scala.html b/src/main/twirl/repo/files.scala.html index 5362b1448..c7e97e51d 100644 --- a/src/main/twirl/repo/files.scala.html +++ b/src/main/twirl/repo/files.scala.html @@ -3,7 +3,7 @@ pathList: List[String], latestCommit: util.JGitUtil.CommitInfo, files: List[util.JGitUtil.FileInfo], - readme: Option[(util.JGitUtil.FileInfo, String)])(implicit context: app.Context) + readme: Option[(List[String], String)])(implicit context: app.Context) @import context._ @import view.helpers._ @html.main(s"${repository.owner}/${repository.name}", Some(repository)) { @@ -77,10 +77,10 @@ - @readme.map { case(file, content) => + @readme.map { case(filePath, content) =>
-
@file.name
-
@renderMarkup(file.name, content, branch, repository, false, false)
+
@filePath.reverse.head
+
@renderMarkup(filePath, content, branch, repository, false, false)
} } From af397ba150f2267ee59513afbf9aa80745c4b28a Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Wed, 5 Mar 2014 09:12:03 +0100 Subject: [PATCH 09/10] Fix page-relative links, e.g. in TOC. --- src/main/scala/view/Asciidoc.scala | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/scala/view/Asciidoc.scala b/src/main/scala/view/Asciidoc.scala index 88c80fb1d..9404f7abf 100644 --- a/src/main/scala/view/Asciidoc.scala +++ b/src/main/scala/view/Asciidoc.scala @@ -35,6 +35,8 @@ object Asciidoc { prefixRelativeUrls(rendered, relativeUrlPrefix) } + private[this] val exceptionPrefixes = Seq("#", "/", "http://", "https://") + def prefixRelativeUrls(html: String, urlPrefix: String): String = { val cleaner = new HtmlCleaner() val node = cleaner.clean(html) @@ -43,7 +45,8 @@ object Asciidoc { htmlNode match { case tag: TagNode if tag.getName == "a" => Option(tag.getAttributeByName("href")) foreach { href => - if (!href.startsWith("/") && !href.startsWith("http://") && !href.startsWith("https://")) { + if (exceptionPrefixes.forall(p => !href.startsWith(p))) { + // if (!href.startsWith("/") && !href.startsWith("http://") && !href.startsWith("https://")) { tag.addAttribute("href", s"${urlPrefix}${href}") } } From 10a40bfcaf460d372f743e9226a38131994205e8 Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Wed, 5 Mar 2014 09:28:13 +0100 Subject: [PATCH 10/10] Removed commented out code. --- src/main/scala/view/Asciidoc.scala | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/scala/view/Asciidoc.scala b/src/main/scala/view/Asciidoc.scala index 9404f7abf..5c131c491 100644 --- a/src/main/scala/view/Asciidoc.scala +++ b/src/main/scala/view/Asciidoc.scala @@ -46,7 +46,6 @@ object Asciidoc { case tag: TagNode if tag.getName == "a" => Option(tag.getAttributeByName("href")) foreach { href => if (exceptionPrefixes.forall(p => !href.startsWith(p))) { - // if (!href.startsWith("/") && !href.startsWith("http://") && !href.startsWith("https://")) { tag.addAttribute("href", s"${urlPrefix}${href}") } }