diff --git a/src/main/scala/gitbucket/core/controller/RepositoryViewerController.scala b/src/main/scala/gitbucket/core/controller/RepositoryViewerController.scala index c4fd085..75e1dee 100644 --- a/src/main/scala/gitbucket/core/controller/RepositoryViewerController.scala +++ b/src/main/scala/gitbucket/core/controller/RepositoryViewerController.scala @@ -1,6 +1,7 @@ package gitbucket.core.controller import gitbucket.core.api._ +import gitbucket.core.plugin.PluginRegistry import gitbucket.core.repo.html import gitbucket.core.helper import gitbucket.core.service._ @@ -546,7 +547,9 @@ } - private val readmeFiles = view.helpers.renderableSuffixes.map(suffix => s"readme${suffix}") ++ Seq("readme.txt", "readme") + private val readmeFiles = PluginRegistry().renderableExtensions.map { extension => + s"readme.${extension}" + } ++ Seq("readme.txt", "readme") /** * Provides HTML of the file list. diff --git a/src/main/scala/gitbucket/core/plugin/Plugin.scala b/src/main/scala/gitbucket/core/plugin/Plugin.scala index f51224b..2d3535c 100644 --- a/src/main/scala/gitbucket/core/plugin/Plugin.scala +++ b/src/main/scala/gitbucket/core/plugin/Plugin.scala @@ -33,6 +33,11 @@ val javaScripts: Seq[(String, String)] = Nil /** + * Override to declare this plug-in provides renderers. + */ + val renderers: Seq[(String, Renderer)] = Nil + + /** * This method is invoked in initialization of plugin system. * Register plugin functionality to PluginRegistry. */ @@ -46,6 +51,9 @@ javaScripts.foreach { case (path, script) => registry.addJavaScript(path, script) } + renderers.foreach { case (extension, renderer) => + registry.addRenderer(extension, renderer) + } } /** diff --git a/src/main/scala/gitbucket/core/plugin/PluginRegistory.scala b/src/main/scala/gitbucket/core/plugin/PluginRegistory.scala index fd2c329..374ac8a 100644 --- a/src/main/scala/gitbucket/core/plugin/PluginRegistory.scala +++ b/src/main/scala/gitbucket/core/plugin/PluginRegistory.scala @@ -24,6 +24,10 @@ private val javaScripts = new ListBuffer[(String, String)] private val controllers = new ListBuffer[(ControllerBase, String)] private val images = mutable.Map[String, String]() + private val renderers = mutable.Map[String, Renderer]() + renderers ++= Seq( + "md" -> MarkdownRenderer, "markdown" -> MarkdownRenderer + ) def addPlugin(pluginInfo: PluginInfo): Unit = { plugins += pluginInfo @@ -60,15 +64,23 @@ def getControllers(): List[(ControllerBase, String)] = controllers.toList def addJavaScript(path: String, script: String): Unit = { - javaScripts += Tuple2(path, script) + javaScripts += ((path, script)) } - //def getJavaScripts(): List[(String, String)] = javaScripts.toList - def getJavaScript(currentPath: String): List[String] = { javaScripts.filter(x => currentPath.matches(x._1)).toList.map(_._2) } + def addRenderer(extension: String, renderer: Renderer): Unit = { + renderers += ((extension, renderer)) + } + + def getRenderer(extension: String): Renderer = { + renderers.get(extension).getOrElse(DefaultRenderer) + } + + def renderableExtensions: Seq[String] = renderers.keys.toSeq + private case class GlobalAction( method: String, path: String, @@ -97,6 +109,10 @@ */ def apply(): PluginRegistry = instance + def isRenderable(fileName: String): Boolean = { + instance.renderableExtensions.exists(extension => fileName.toLowerCase.endsWith("." + extension)) + } + /** * Initializes all installed plugins. */ diff --git a/src/main/scala/gitbucket/core/plugin/Renderer.scala b/src/main/scala/gitbucket/core/plugin/Renderer.scala new file mode 100644 index 0000000..8efb125 --- /dev/null +++ b/src/main/scala/gitbucket/core/plugin/Renderer.scala @@ -0,0 +1,44 @@ +package gitbucket.core.plugin + +import gitbucket.core.controller.Context +import gitbucket.core.service.RepositoryService +import gitbucket.core.view.Markdown +import play.twirl.api.Html + +/** + * A render engine to render content to HTML. + */ +trait Renderer { + + /** + * Render the given request to HTML. + */ + def render(request: RenderRequest): Html + +} + +object MarkdownRenderer extends Renderer { + override def render(request: RenderRequest): Html = { + import request._ + Html(Markdown.toHtml(fileContent, repository, enableWikiLink, enableRefsLink)(context)) + } +} + +object DefaultRenderer extends Renderer { + override def render(request: RenderRequest): Html = { + import request._ + Html( + s"${ + fileContent.split("(\\r\\n)|\\n").map(xml.Utility.escape(_)).mkString("
") + }
" + ) + } +} + +case class RenderRequest(filePath: List[String], + fileContent: String, + branch: String, + repository: RepositoryService.RepositoryInfo, + enableWikiLink: Boolean, + enableRefsLink: Boolean, + context: Context) \ No newline at end of file diff --git a/src/main/scala/gitbucket/core/view/helpers.scala b/src/main/scala/gitbucket/core/view/helpers.scala index 3d52c21..1642353 100644 --- a/src/main/scala/gitbucket/core/view/helpers.scala +++ b/src/main/scala/gitbucket/core/view/helpers.scala @@ -5,8 +5,9 @@ import gitbucket.core.controller.Context import gitbucket.core.model.CommitState +import gitbucket.core.plugin.{RenderRequest, PluginRegistry, Renderer} import gitbucket.core.service.{RepositoryService, RequestCache} -import gitbucket.core.util.{JGitUtil, StringUtil} +import gitbucket.core.util.{FileUtil, JGitUtil, StringUtil} import play.twirl.api.Html @@ -83,14 +84,6 @@ 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, (List[String], String, String, RepositoryService.RepositoryInfo, Boolean, Boolean, Context) => Html)] = - Seq( - ".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)) - ) - - def renderableSuffixes: Seq[String] = renderersBySuffix.map(_._1) - /** * Converts Markdown of Wiki pages to HTML. */ @@ -107,15 +100,10 @@ repository: RepositoryService.RepositoryInfo, enableWikiLink: Boolean, enableRefsLink: Boolean)(implicit context: Context): Html = { - val fileNameLower = filePath.reverse.head.toLowerCase - renderersBySuffix.find { case (suffix, _) => fileNameLower.endsWith(suffix) } match { - 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("
") - }
" - ) - } + val fileName = filePath.reverse.head.toLowerCase + val extension = FileUtil.getExtension(fileName) + val renderer = PluginRegistry().getRenderer(extension) + renderer.render(RenderRequest(filePath, fileContent, branch, repository, enableWikiLink, enableRefsLink, context)) } /** diff --git a/src/main/twirl/gitbucket/core/repo/blob.scala.html b/src/main/twirl/gitbucket/core/repo/blob.scala.html index 37b2e73..026e97c 100644 --- a/src/main/twirl/gitbucket/core/repo/blob.scala.html +++ b/src/main/twirl/gitbucket/core/repo/blob.scala.html @@ -7,6 +7,7 @@ isBlame: Boolean)(implicit context: gitbucket.core.controller.Context) @import context._ @import gitbucket.core.view.helpers._ +@import gitbucket.core.plugin.PluginRegistry @html.main(s"${repository.owner}/${repository.name}", Some(repository)) { @html.menu("code", repository){
@@ -75,7 +76,7 @@ @if(content.viewType == "text"){ - @defining(renderableSuffixes.find(suffix => pathList.reverse.head.toLowerCase.endsWith(suffix))) { isRrenderable => + @defining(PluginRegistry.isRenderable(pathList.reverse.head)){ isRrenderable => @if(!isBlame && isRrenderable) {
@renderMarkup(pathList, content.content.get, branch, repository, false, false) diff --git a/src/main/twirl/gitbucket/core/repo/editor.scala.html b/src/main/twirl/gitbucket/core/repo/editor.scala.html index cdffde5..4466e3b 100644 --- a/src/main/twirl/gitbucket/core/repo/editor.scala.html +++ b/src/main/twirl/gitbucket/core/repo/editor.scala.html @@ -5,6 +5,7 @@ content: gitbucket.core.util.JGitUtil.ContentInfo)(implicit context: gitbucket.core.controller.Context) @import context._ @import gitbucket.core.view.helpers._ +@import gitbucket.core.plugin.PluginRegistry @html.main(if(fileName.isEmpty) "New File" else s"Editing ${fileName.get} at ${branch} - ${repository.owner}/${repository.name}", Some(repository)) { @html.menu("code", repository){
@@ -120,7 +121,7 @@ $('#editor').hide(); $('#preview').show() - @if(renderableSuffixes.find(suffix => fileName.map(_.toLowerCase.endsWith(suffix)).getOrElse(false))) { + @if(fileName.map(PluginRegistry.isRenderable _).getOrElse(false)) { // update preview $('#preview').html(' Previewing...'); $.post('@url(repository)/_preview', {