diff --git a/src/main/scala/gitbucket/core/plugin/CompletionProposalProvider.scala b/src/main/scala/gitbucket/core/plugin/CompletionProposalProvider.scala new file mode 100644 index 0000000..a92e753 --- /dev/null +++ b/src/main/scala/gitbucket/core/plugin/CompletionProposalProvider.scala @@ -0,0 +1,33 @@ +package gitbucket.core.plugin + +import gitbucket.core.controller.Context +import gitbucket.core.util.EmojiUtil + +trait CompletionProposalProvider { + + val id: String + val prefix: String + val suffix: String = " " + val values: Seq[String] + + def template(implicit context: Context): String = "value" + def additionalScript(implicit context: Context): String = "" +} + +class EmojiCompletionProposalProvider extends CompletionProposalProvider { + override val id: String = "emoji" + override val values: Seq[String] = EmojiUtil.emojis.toSeq + override val prefix: String = ":" + override val suffix: String = ": " + override def template(implicit context: Context): String = + s"""'' + value""" +} + +class UserCompletionProposalProvider extends CompletionProposalProvider { + override val id: String = "user" + override val values: Seq[String] = Nil + override val prefix: String = "@" + override def template(implicit context: Context): String = "'@' + value" + override def additionalScript(implicit context: Context): String = + s"""$$.get('${context.path}/_user/proposals', { query: '' }, function (data) { user = data.options; });""" +} \ No newline at end of file diff --git a/src/main/scala/gitbucket/core/plugin/Plugin.scala b/src/main/scala/gitbucket/core/plugin/Plugin.scala index 62b2ccb..3478d5b 100644 --- a/src/main/scala/gitbucket/core/plugin/Plugin.scala +++ b/src/main/scala/gitbucket/core/plugin/Plugin.scala @@ -170,6 +170,16 @@ def textDecorators(registry: PluginRegistry, context: ServletContext, settings: SystemSettings): Seq[TextDecorator] = Nil /** + * Override to add completion proposal provider. + */ + val completionProposalProvider: Seq[CompletionProposalProvider] = Nil + + /** + * Override to add completion proposal provider. + */ + def completionProposalProvider(registry: PluginRegistry, context: ServletContext, settings: SystemSettings): Seq[CompletionProposalProvider] = Nil + + /** * This method is invoked in initialization of plugin system. * Register plugin functionality to PluginRegistry. */ @@ -219,6 +229,9 @@ (textDecorators ++ textDecorators(registry, context, settings)).foreach { textDecorator => registry.addTextDecorator(textDecorator) } + (completionProposalProvider ++ completionProposalProvider(registry, context, settings)).foreach { completionProposalProvider => + registry.addCompletionProposalProvider(completionProposalProvider) + } } /** diff --git a/src/main/scala/gitbucket/core/plugin/PluginRegistory.scala b/src/main/scala/gitbucket/core/plugin/PluginRegistory.scala index e3a7f2a..c867d35 100644 --- a/src/main/scala/gitbucket/core/plugin/PluginRegistory.scala +++ b/src/main/scala/gitbucket/core/plugin/PluginRegistory.scala @@ -43,9 +43,13 @@ private val dashboardTabs = new ListBuffer[(Context) => Option[Link]] private val assetsMappings = new ListBuffer[(String, String, ClassLoader)] private val textDecorators = new ListBuffer[TextDecorator] + // TODO textDecorators += new TextDecorator { override def decorate(text: String)(implicit context: Context): String = EmojiUtil.convertEmojis(text) } + private val completionProposalProviders = new ListBuffer[CompletionProposalProvider] + completionProposalProviders += new EmojiCompletionProposalProvider() + completionProposalProviders += new UserCompletionProposalProvider() def addPlugin(pluginInfo: PluginInfo): Unit = plugins += pluginInfo @@ -136,6 +140,10 @@ def addTextDecorator(textDecorator: TextDecorator): Unit = textDecorators += textDecorator def getTextDecorators: Seq[TextDecorator] = textDecorators.toSeq + + def addCompletionProposalProvider(completionProposalProvider: CompletionProposalProvider): Unit = completionProposalProviders += completionProposalProvider + + def getCompletionProposalProviders: Seq[CompletionProposalProvider] = completionProposalProviders.toSeq } /** diff --git a/src/main/scala/gitbucket/core/view/helpers.scala b/src/main/scala/gitbucket/core/view/helpers.scala index 34c01f1..91317e4 100644 --- a/src/main/scala/gitbucket/core/view/helpers.scala +++ b/src/main/scala/gitbucket/core/view/helpers.scala @@ -315,6 +315,14 @@ case CommitState.FAILURE => "Failed" } + /** + * Render a given object as the JSON string. + */ + def json(obj: AnyRef): String = { + implicit val formats = org.json4s.DefaultFormats + org.json4s.jackson.Serialization.write(obj) + } + // This pattern comes from: http://stackoverflow.com/a/4390768/1771641 (extract-url-from-string) private[this] val detectAndRenderLinksRegex = """(?i)\b((?:https?://|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,13}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))""".r diff --git a/src/main/twirl/gitbucket/core/helper/attached.scala.html b/src/main/twirl/gitbucket/core/helper/attached.scala.html index aaed7c4..d1d5557 100644 --- a/src/main/twirl/gitbucket/core/helper/attached.scala.html +++ b/src/main/twirl/gitbucket/core/helper/attached.scala.html @@ -1,5 +1,6 @@ @(owner: String, repository: String, completion: Seq[String], generateScript: Boolean = true)(textarea: Html)(implicit context: gitbucket.core.controller.Context) @import gitbucket.core.util.{FileUtil, EmojiUtil} +@import gitbucket.core.view.helpers
@textarea
Attach images or documents by dragging & dropping, or selecting them.
@@ -7,47 +8,32 @@ @defining("(id=\")([\\w\\-]*)(\")".r.findFirstMatchIn(textarea.body).map(_.group(2))){ textareaId =>