(refs #775)Add new extension point to add markup render

This commit is contained in:
Naoki Takezoe
2015-06-05 01:30:00 +09:00
parent fd1ee07297
commit aa5a07b98e
7 changed files with 85 additions and 24 deletions

View File

@@ -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 @@ trait RepositoryViewerControllerBase extends ControllerBase {
}
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.

View File

@@ -32,6 +32,11 @@ trait Plugin {
*/
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 @@ trait Plugin {
javaScripts.foreach { case (path, script) =>
registry.addJavaScript(path, script)
}
renderers.foreach { case (extension, renderer) =>
registry.addRenderer(extension, renderer)
}
}
/**

View File

@@ -24,6 +24,10 @@ class PluginRegistry {
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 @@ class PluginRegistry {
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 @@ object PluginRegistry {
*/
def apply(): PluginRegistry = instance
def isRenderable(fileName: String): Boolean = {
instance.renderableExtensions.exists(extension => fileName.toLowerCase.endsWith("." + extension))
}
/**
* Initializes all installed plugins.
*/

View File

@@ -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"<tt>${
fileContent.split("(\\r\\n)|\\n").map(xml.Utility.escape(_)).mkString("<br/>")
}</tt>"
)
}
}
case class RenderRequest(filePath: List[String],
fileContent: String,
branch: String,
repository: RepositoryService.RepositoryInfo,
enableWikiLink: Boolean,
enableRefsLink: Boolean,
context: Context)

View File

@@ -5,8 +5,9 @@ import java.util.{Date, Locale, TimeZone}
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 @@ 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, (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 @@ object helpers extends AvatarImageProvider with LinkConverter with RequestCache
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"<tt>${
fileContent.split("(\\r\\n)|\\n").map(xml.Utility.escape(_)).mkString("<br/>")
}</tt>"
)
}
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))
}
/**

View File

@@ -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){
<div class="head">
@@ -75,7 +76,7 @@
<tr>
<td>
@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) {
<div class="box-content markdown-body" style="border: none; padding-left: 16px; padding-right: 16px;">
@renderMarkup(pathList, content.content.get, branch, repository, false, false)

View File

@@ -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){
<form method="POST" action="@url(repository)/@if(fileName.isEmpty){create}else{update}" validate="true">
@@ -120,7 +121,7 @@ $(function(){
$('#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('<img src="@assets/common/images/indicator.gif"> Previewing...');
$.post('@url(repository)/_preview', {