diff --git a/src/main/scala/view/Markdown.scala b/src/main/scala/view/Markdown.scala index 6def4df..dba9670 100644 --- a/src/main/scala/view/Markdown.scala +++ b/src/main/scala/view/Markdown.scala @@ -7,6 +7,8 @@ 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} @@ -110,6 +112,20 @@ printer.print(' ').print(name).print('=').print('"').print(value).print('"') } + private def printHeaderTag(node: HeaderNode): Unit = { + val tag = s"h${node.getLevel}" + val headerTextString = printChildrenToString(node) + val anchorName = GitBucketHtmlSerializer.generateAnchorName(headerTextString) + printer.print(s"<$tag>") + printer.print(s"""""") + visitChildren(node) + printer.print(s"") + } + + override def visit(node: HeaderNode): Unit = { + printHeaderTag(node) + } + override def visit(node: TextNode): Unit = { // convert commit id and username to link. val text = if(enableRefsLink) convertRefsLinks(node.getText, repository, "issue:") else node.getText @@ -120,5 +136,18 @@ printWithAbbreviations(text) } } +} +object GitBucketHtmlSerializer { + + private val Whitespace = "[\\s]".r + + private val SpecialChars = "[^\\w-]".r + + def generateAnchorName(text: String): String = { + val noWhitespace = Whitespace.replaceAllIn(text, "-") + val normalized = Normalizer.normalize(noWhitespace, Normalizer.Form.NFD) + val noSpecialChars = SpecialChars.replaceAllIn(normalized, "") + noSpecialChars.toLowerCase(Locale.ENGLISH) + } } diff --git a/src/test/scala/view/GitBucketHtmlSerializerSpec.scala b/src/test/scala/view/GitBucketHtmlSerializerSpec.scala new file mode 100644 index 0000000..d82630d --- /dev/null +++ b/src/test/scala/view/GitBucketHtmlSerializerSpec.scala @@ -0,0 +1,28 @@ +package view + +import org.specs2.mutable._ + +class GitBucketHtmlSerializerSpec extends Specification { + + import GitBucketHtmlSerializer._ + + "generateAnchorName" should { + "convert whitespace characters to hyphens" in { + val before = "foo bar baz" + val after = generateAnchorName(before) + after mustEqual "foo-bar-baz" + } + + "normalize characters with diacritics" in { + val before = "Dónde estará mi vida" + val after = generateAnchorName(before) + after mustEqual "donde-estara-mi-vida" + } + + "omit special characters" in { + val before = "foo!bar@baz>9000" + val after = generateAnchorName(before) + after mustEqual "foobarbaz9000" + } + } +}