From: Lanius Trolling Date: Wed, 24 Aug 2022 13:45:05 +0000 (-0400) Subject: Add numbers to ToC header links X-Git-Url: https://gitweb.starshipfights.net/?a=commitdiff_plain;h=b33c9ee38cc2fbe308351a70ff1842519e889282;p=factbooks Add numbers to ToC header links --- diff --git a/src/main/kotlin/info/mechyrdia/lore/parser.kt b/src/main/kotlin/info/mechyrdia/lore/parser.kt index 1368bf6..8737a05 100644 --- a/src/main/kotlin/info/mechyrdia/lore/parser.kt +++ b/src/main/kotlin/info/mechyrdia/lore/parser.kt @@ -31,9 +31,9 @@ sealed class TextParserState( class Initial(scope: TextParserScope) : TextParserState(scope, listOf(), listOf()) { override fun processCharacter(char: Char): TextParserState { return if (char == '[') - OpenTag(scope, "", insideTags, insideDirectTags) + OpenTag(scope, "", insideTags, insideDirectTags) else - PlainText(scope, "$char", insideTags, insideDirectTags) + PlainText(scope, "$char", insideTags, insideDirectTags) } override fun processEndOfText() { @@ -45,7 +45,7 @@ sealed class TextParserState( override fun processCharacter(char: Char): TextParserState { return if (char == '[') { appendText(text) - OpenTag(scope, "", insideTags, insideDirectTags) + OpenTag(scope, "", insideTags, insideDirectTags) } else if (char == '\n' && text.endsWith('\n')) { appendText(text.removeSuffix("\n")) @@ -55,9 +55,9 @@ sealed class TextParserState( "
" appendTextRaw(newline) - PlainText(scope, "", insideTags, insideDirectTags) + PlainText(scope, "", insideTags, insideDirectTags) } else - PlainText(scope, text + char, insideTags, insideDirectTags) + PlainText(scope, text + char, insideTags, insideDirectTags) } override fun processEndOfText() { @@ -70,13 +70,13 @@ sealed class TextParserState( val newText = text + char return if (newText.endsWith("[/$NO_FORMAT_TAG]")) { appendText(newText.removeSuffix("[/$NO_FORMAT_TAG]")) - PlainText(scope, "", insideTags, insideDirectTags) + PlainText(scope, "", insideTags, insideDirectTags) } else if (newText.endsWith('\n')) { appendText(newText.removeSuffix("\n")) appendTextRaw("
") - NoFormatText(scope, "", insideTags, insideDirectTags) + NoFormatText(scope, "", insideTags, insideDirectTags) } else - NoFormatText(scope, newText, insideTags, insideDirectTags) + NoFormatText(scope, newText, insideTags, insideDirectTags) } override fun processEndOfText() { @@ -98,11 +98,11 @@ sealed class TextParserState( } else PlainText(scope, "", insideTags + (tag to null), insideDirectTags) } else if (char == '/' && tag == "") - CloseTag(scope, tag, insideTags, insideDirectTags) + CloseTag(scope, tag, insideTags, insideDirectTags) else if (char == '=' && tag != "") - TagParam(scope, tag, "", insideTags, insideDirectTags) + TagParam(scope, tag, "", insideTags, insideDirectTags) else - OpenTag(scope, tag + char, insideTags, insideDirectTags) + OpenTag(scope, tag + char, insideTags, insideDirectTags) } override fun processEndOfText() { @@ -166,15 +166,17 @@ sealed class TextParserState( .replace(">", ">") .replace("&", "&") - fun parseText(text: String, tags: TextParserTags, context: TContext): String { + fun parseText(text: String, tags: TextParserTags, context: TContext): ParseOutcome { val builder = StringBuilder() try { val fixedText = text.replace("\r\n", "\n").replace('\r', '\n') fixedText.fold>(Initial(TextParserScope(builder, tags, context))) { state, char -> state.processCharacter(char) }.processEndOfText() } catch (ex: Exception) { - return "

$builder

INTERNAL ERROR

${ex.stackTraceToString()}
" + return ParseOutcome("

$builder

Internal Error!

${ex.stackTraceToString()}
", false) } - return "

$builder

" + return ParseOutcome("

$builder

", true) } } } + +data class ParseOutcome(val html: String, val succeeded: Boolean) diff --git a/src/main/kotlin/info/mechyrdia/lore/parser_tags.kt b/src/main/kotlin/info/mechyrdia/lore/parser_tags.kt index 6ada308..bf39cd0 100644 --- a/src/main/kotlin/info/mechyrdia/lore/parser_tags.kt +++ b/src/main/kotlin/info/mechyrdia/lore/parser_tags.kt @@ -304,43 +304,38 @@ enum class TextParserFormattingTag(val type: TextParserTagType) { enum class TextParserToCBuilderTag(val type: TextParserTagType) { H1( TextParserTagType.Indirect { _, content, builder -> - builder.add(headerContentToLabel(content), headerContentToAnchor(content)) - content + builder.add(headerContentToLabel(content), 0, headerContentToAnchor(content)) + "[h1]$content[/h1]" } ), H2( TextParserTagType.Indirect { _, content, builder -> - val label = headerContentToLabel(content) - builder.add("- $label", headerContentToAnchor(content)) - content + builder.add(headerContentToLabel(content), 1, headerContentToAnchor(content)) + "[h2]$content[/h2]" } ), H3( TextParserTagType.Indirect { _, content, builder -> - val label = headerContentToLabel(content) - builder.add("-- $label", headerContentToAnchor(content)) - content + builder.add(headerContentToLabel(content), 2, headerContentToAnchor(content)) + "[h3]$content[/h3]" } ), H4( TextParserTagType.Indirect { _, content, builder -> - val label = headerContentToLabel(content) - builder.add("--- $label", headerContentToAnchor(content)) - content + builder.add(headerContentToLabel(content), 3, headerContentToAnchor(content)) + "[h4]$content[/h4]" } ), H5( TextParserTagType.Indirect { _, content, builder -> - val label = headerContentToLabel(content) - builder.add("---- $label", headerContentToAnchor(content)) - content + builder.add(headerContentToLabel(content), 4, headerContentToAnchor(content)) + "[h5]$content[/h5]" } ), H6( TextParserTagType.Indirect { _, content, builder -> - val label = headerContentToLabel(content) - builder.add("----- $label", headerContentToAnchor(content)) - content + builder.add(headerContentToLabel(content), 5, headerContentToAnchor(content)) + "[h6]$content[/h6]" } ); diff --git a/src/main/kotlin/info/mechyrdia/lore/parser_toc.kt b/src/main/kotlin/info/mechyrdia/lore/parser_toc.kt index 9ce1d59..9e17a38 100644 --- a/src/main/kotlin/info/mechyrdia/lore/parser_toc.kt +++ b/src/main/kotlin/info/mechyrdia/lore/parser_toc.kt @@ -1,10 +1,31 @@ package info.mechyrdia.lore -@JvmInline -value class TableOfContentsBuilder private constructor(private val links: MutableList) { - constructor() : this(mutableListOf()) +class TableOfContentsBuilder { + private var title: String? = null + private val levels = mutableListOf() + private val links = mutableListOf() - fun add(text: String, toAnchor: String) = links.plusAssign(NavLink("#$toAnchor", text, aClasses = "left")) + fun add(text: String, level: Int, toAnchor: String) { + if (level == 0) { + title = text + return + } + + val number = if (level > levels.size) { + if (level == levels.size + 1) { + levels.add(1) + levels.joinToString(separator = ".") { it.toString() } + } else + throw IllegalArgumentException("[h${level + 1}] cannot come after [h${levels.size + 1}]!") + } else { + levels.addAll(levels.take(level).also { levels.clear() }.mapIndexed { i, n -> if (i == level - 1) n + 1 else n }) + levels.joinToString(separator = ".") { it.toString() } + } + + links.plusAssign(NavLink("#$toAnchor", "$number. $text", aClasses = "left")) + } + + fun toPageTitle() = title!! fun toNavBar(): List = links.toList() } diff --git a/src/main/kotlin/info/mechyrdia/lore/views_lore.kt b/src/main/kotlin/info/mechyrdia/lore/views_lore.kt index 0a855a4..07366f8 100644 --- a/src/main/kotlin/info/mechyrdia/lore/views_lore.kt +++ b/src/main/kotlin/info/mechyrdia/lore/views_lore.kt @@ -27,7 +27,7 @@ fun ApplicationCall.loreArticlePage(): HTML.() -> Unit { } } else { val pageMarkup = pageFile.readText() - val pageHtml = TextParserState.parseText(pageMarkup, TextParserFormattingTag.asTags, Unit) + val pageHtml = TextParserState.parseText(pageMarkup, TextParserFormattingTag.asTags, Unit).html val pageToC = TableOfContentsBuilder() TextParserState.parseText(pageMarkup, TextParserToCBuilderTag.asTags, pageToC) @@ -35,7 +35,7 @@ fun ApplicationCall.loreArticlePage(): HTML.() -> Unit { val navbar = standardNavBar(pagePathParts) val sidebar = PageNavSidebar(pageToC.toNavBar()) - return page("~/${pagePath}", navbar, sidebar) { + return page(pageToC.toPageTitle(), navbar, sidebar) { section { a { id = "page-top" } unsafe { raw(pageHtml) } diff --git a/src/main/resources/static/init.js b/src/main/resources/static/init.js index a3b5a28..b816e8d 100644 --- a/src/main/resources/static/init.js +++ b/src/main/resources/static/init.js @@ -27,7 +27,7 @@ window.addEventListener("load", function () { // Preview themes const themeChoices = document.getElementsByName("theme"); - for (let themeChoice of themeChoices) { + for (const themeChoice of themeChoices) { const theme = themeChoice.value; themeChoice.addEventListener("click", () => { document.documentElement.setAttribute("data-theme", theme);