diff options
author | Paweł Marks <pmarks@virtuslab.com> | 2020-09-23 19:48:14 +0200 |
---|---|---|
committer | Błażej Kardyś <bkardys@virtuslab.com> | 2020-11-27 03:15:02 +0100 |
commit | 52f64c664573567259f8f678d32924f86b4f147c (patch) | |
tree | 0882ce51f477acc71412b36307495a0e0ba97359 /plugins | |
parent | 80b6d1824960205e1c1d57c0c51e913d3c2360db (diff) | |
download | dokka-52f64c664573567259f8f678d32924f86b4f147c.tar.gz dokka-52f64c664573567259f8f678d32924f86b4f147c.tar.bz2 dokka-52f64c664573567259f8f678d32924f86b4f147c.zip |
Add navigation fragments for templating
Diffstat (limited to 'plugins')
9 files changed, 81 insertions, 137 deletions
diff --git a/plugins/all-module-page/src/main/kotlin/templates/DirectiveBasedTemplateProcessing.kt b/plugins/all-module-page/src/main/kotlin/templates/DirectiveBasedTemplateProcessing.kt index 7786ca18..705e6678 100644 --- a/plugins/all-module-page/src/main/kotlin/templates/DirectiveBasedTemplateProcessing.kt +++ b/plugins/all-module-page/src/main/kotlin/templates/DirectiveBasedTemplateProcessing.kt @@ -4,6 +4,7 @@ import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +import org.jetbrains.dokka.base.templating.AddToNavigationCommand import org.jetbrains.dokka.base.templating.Command import org.jetbrains.dokka.base.templating.ResolveLinkCommand import org.jetbrains.dokka.base.templating.parseJson @@ -14,8 +15,11 @@ import org.jsoup.nodes.Element import org.jsoup.parser.Tag import java.io.File import java.nio.file.Files +import java.util.concurrent.ConcurrentHashMap + +class DirectiveBasedTemplateProcessingStrategy(private val context: DokkaContext) : TemplateProcessingStrategy { + private val navigationFragments = ConcurrentHashMap<String, Element>() -class DirectiveBasedTemplateProcessingStrategy(context: DokkaContext) : TemplateProcessingStrategy { override suspend fun process(input: File, output: File): Unit = coroutineScope { if (input.extension == "html") { launch { @@ -23,8 +27,10 @@ class DirectiveBasedTemplateProcessingStrategy(context: DokkaContext) : Template document.outputSettings().indentAmount(0).prettyPrint(false) document.select("dokka-template-command").forEach { val command = parseJson<Command>(it.attr("data")) - if (command is ResolveLinkCommand) { - resolveLink(it, command) + when (command) { + is ResolveLinkCommand -> resolveLink(it, command) + is AddToNavigationCommand -> navigationFragments[command.moduleName] = it + else -> context.logger.warn("Unknown templating command $command") } } withContext(IO) { Files.writeString(output.toPath(), document.outerHtml()) } @@ -36,6 +42,40 @@ class DirectiveBasedTemplateProcessingStrategy(context: DokkaContext) : Template } } + override suspend fun finish(output: File) { + val attributes = Attributes().apply { + put("class", "sideMenu") + } + val node = Element(Tag.valueOf("div"), "", attributes) + navigationFragments.entries.sortedBy { it.key }.forEach { (moduleName, command) -> + command.select("a").forEach { a -> + a.attr("href")?.also { a.attr("href", "${moduleName}/${it}") } + } + command.childNodes().toList().forEachIndexed { index, child -> + if (index == 0) { + child.attr("id", "$moduleName-nav-submenu") + } + node.appendChild(child) + } + } + + withContext(IO) { + Files.writeString(output.resolve("navigation.html").toPath(), node.outerHtml()) + } + + node.select("a").forEach { a -> + a.attr("href")?.also { a.attr("href", "../${it}") } + } + navigationFragments.keys.forEach { + withContext(IO) { + Files.writeString( + output.resolve(it).resolve("navigation.html").toPath(), + node.outerHtml() + ) + } + } + } + private fun resolveLink(it: Element, command: ResolveLinkCommand) { val attributes = Attributes().apply { put("href", "") // TODO: resolve diff --git a/plugins/all-module-page/src/main/kotlin/templates/TemplateProcessor.kt b/plugins/all-module-page/src/main/kotlin/templates/TemplateProcessor.kt index 4c247d94..cd144046 100644 --- a/plugins/all-module-page/src/main/kotlin/templates/TemplateProcessor.kt +++ b/plugins/all-module-page/src/main/kotlin/templates/TemplateProcessor.kt @@ -5,6 +5,7 @@ import org.jetbrains.dokka.plugability.DokkaContext import java.io.File import java.nio.file.Files import java.nio.file.Path +import kotlin.coroutines.coroutineContext interface TemplateProcessor { fun process() @@ -12,6 +13,7 @@ interface TemplateProcessor { interface TemplateProcessingStrategy { suspend fun process(input: File, output: File) + suspend fun finish(output: File) {} } class DefaultTemplateProcessor( @@ -19,11 +21,14 @@ class DefaultTemplateProcessor( private val strategy: TemplateProcessingStrategy ): TemplateProcessor { override fun process() = runBlocking(Dispatchers.Default) { - context.configuration.modules.forEach { - launch { - it.sourceOutputDirectory.visit(context.configuration.outputDir.resolve(it.relativePathToOutputDirectory)) + coroutineScope { + context.configuration.modules.forEach { + launch { + it.sourceOutputDirectory.visit(context.configuration.outputDir.resolve(it.relativePathToOutputDirectory)) + } } } + strategy.finish(context.configuration.outputDir) } private suspend fun File.visit(target: File): Unit = coroutineScope { diff --git a/plugins/base/src/main/kotlin/DokkaBase.kt b/plugins/base/src/main/kotlin/DokkaBase.kt index afda6f24..8289447c 100644 --- a/plugins/base/src/main/kotlin/DokkaBase.kt +++ b/plugins/base/src/main/kotlin/DokkaBase.kt @@ -209,4 +209,4 @@ class DokkaBase : DokkaPlugin() { val baseSearchbarDataInstaller by extending { htmlPreprocessors providing ::SearchbarDataInstaller order { after(sourceLinksTransformer) } } -} +}
\ No newline at end of file diff --git a/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt b/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt index 661e1e58..16f60a83 100644 --- a/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt +++ b/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt @@ -706,7 +706,8 @@ open class HtmlRenderer( buildHtml(page, page.embeddedResources) { div("main-content") { id = "content" - attributes["pageIds"] = page.pageId + // TODO: Investigate possible problem + attributes["pageIds"] = "${context.configuration.moduleName}::${page.pageId}" content(this, page) } } diff --git a/plugins/base/src/main/kotlin/renderers/html/NavigationPage.kt b/plugins/base/src/main/kotlin/renderers/html/NavigationPage.kt index 3758b8d3..15d2473f 100644 --- a/plugins/base/src/main/kotlin/renderers/html/NavigationPage.kt +++ b/plugins/base/src/main/kotlin/renderers/html/NavigationPage.kt @@ -3,6 +3,7 @@ package org.jetbrains.dokka.base.renderers.html import kotlinx.html.* import kotlinx.html.stream.createHTML import org.jetbrains.dokka.base.renderers.pageId +import org.jetbrains.dokka.base.templating.AddToNavigationCommand import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.model.DisplaySourceSet import org.jetbrains.dokka.model.WithChildren @@ -10,7 +11,7 @@ import org.jetbrains.dokka.pages.PageNode import org.jetbrains.dokka.pages.RendererSpecificPage import org.jetbrains.dokka.pages.RenderingStrategy -class NavigationPage(val root: NavigationNode) : RendererSpecificPage { +class NavigationPage(val root: NavigationNode, val moduleName: String) : RendererSpecificPage { override val name = "navigation" override val children = emptyList<PageNode>() @@ -18,14 +19,20 @@ class NavigationPage(val root: NavigationNode) : RendererSpecificPage { override fun modified(name: String, children: List<PageNode>) = this override val strategy = RenderingStrategy<HtmlRenderer> { - createHTML().visit(root, "nav-submenu", this) + createHTML().visit(root, this) + } + + private fun <R> TagConsumer<R>.visit(node: NavigationNode, renderer: HtmlRenderer): R = with(renderer) { + templateCommand(AddToNavigationCommand(moduleName)) { + visit(node,"${moduleName}-nav-submenu", renderer) + } } private fun <R> TagConsumer<R>.visit(node: NavigationNode, navId: String, renderer: HtmlRenderer): R = with(renderer) { div("sideMenuPart") { id = navId - attributes["pageId"] = node.pageId + attributes["pageId"] = "${moduleName}::${node.pageId}" div("overview") { buildLink(node.dri, node.sourceSets.toList()) { buildBreakableText(node.name) } if (node.children.isNotEmpty()) { @@ -47,7 +54,7 @@ data class NavigationNode( override val children: List<NavigationNode> ): WithChildren<NavigationNode> -fun NavigationPage.transform(block: (NavigationNode) -> NavigationNode) = NavigationPage(root.transform(block)) +fun NavigationPage.transform(block: (NavigationNode) -> NavigationNode) = NavigationPage(root.transform(block), moduleName) fun NavigationNode.transform(block: (NavigationNode) -> NavigationNode) = run(block).let { NavigationNode(it.name, it.dri, it.sourceSets, it.children.map(block)) } diff --git a/plugins/base/src/main/kotlin/renderers/html/Tags.kt b/plugins/base/src/main/kotlin/renderers/html/Tags.kt index 67eed686..3db49ebf 100644 --- a/plugins/base/src/main/kotlin/renderers/html/Tags.kt +++ b/plugins/base/src/main/kotlin/renderers/html/Tags.kt @@ -13,9 +13,19 @@ open class WBR(initialAttributes: Map<String, String>, consumer: TagConsumer<*>) HTMLTag("wbr", consumer, initialAttributes, namespace = null, inlineTag = true, emptyTag = false), HtmlBlockInlineTag -fun FlowOrPhrasingContent.templateCommand(data: Command, block: TemplateCommand.() -> Unit = {}):Unit = +fun FlowOrPhrasingContent.templateCommand(data: Command, block: TemplateCommand.() -> Unit = {}): Unit = TemplateCommand(attributesMapOf("data", toJsonString(data)), consumer).visit(block) +fun <T> TagConsumer<T>.templateCommand(data: Command, block: TemplateCommand.() -> Unit = {}): T = + TemplateCommand(attributesMapOf("data", toJsonString(data)), this).visitAndFinalize(this, block) + class TemplateCommand(initialAttributes: Map<String, String>, consumer: TagConsumer<*>) : - HTMLTag("dokka-template-command", consumer, initialAttributes, namespace = null, inlineTag = true, emptyTag = false), + HTMLTag( + "dokka-template-command", + consumer, + initialAttributes, + namespace = null, + inlineTag = true, + emptyTag = false + ), CommonAttributeGroupFacadeFlowInteractivePhrasingContent diff --git a/plugins/base/src/main/kotlin/renderers/html/htmlPreprocessors.kt b/plugins/base/src/main/kotlin/renderers/html/htmlPreprocessors.kt index 45159fea..fbebec70 100644 --- a/plugins/base/src/main/kotlin/renderers/html/htmlPreprocessors.kt +++ b/plugins/base/src/main/kotlin/renderers/html/htmlPreprocessors.kt @@ -177,5 +177,4 @@ class SourcesetDependencyAppender(val context: DokkaContext) : PageTransformer { children = input.children + deps ).transformContentPagesTree { it.modified(embeddedResources = it.embeddedResources + name) } } -} - +}
\ No newline at end of file diff --git a/plugins/base/src/main/kotlin/templating/AddToNavigationCommand.kt b/plugins/base/src/main/kotlin/templating/AddToNavigationCommand.kt new file mode 100644 index 00000000..817501d7 --- /dev/null +++ b/plugins/base/src/main/kotlin/templating/AddToNavigationCommand.kt @@ -0,0 +1,3 @@ +package org.jetbrains.dokka.base.templating + +class AddToNavigationCommand(val moduleName: String) : Command diff --git a/plugins/base/src/test/kotlin/locationProvider/DokkaLocationProviderTest.kt b/plugins/base/src/test/kotlin/locationProvider/DokkaLocationProviderTest.kt index b35310a5..e69de29b 100644 --- a/plugins/base/src/test/kotlin/locationProvider/DokkaLocationProviderTest.kt +++ b/plugins/base/src/test/kotlin/locationProvider/DokkaLocationProviderTest.kt @@ -1,121 +0,0 @@ -package locationProvider - -import org.jetbrains.dokka.base.resolvers.local.DokkaLocationProvider -import org.jetbrains.dokka.model.dfs -import org.jetbrains.dokka.plugability.DokkaContext -import org.jetbrains.dokka.testApi.testRunner.AbstractCoreTest -import org.junit.jupiter.api.Assertions.assertNotEquals -import org.junit.jupiter.api.Test -import org.junit.jupiter.params.ParameterizedTest -import org.junit.jupiter.params.provider.MethodSource -import kotlin.test.assertEquals -import kotlin.test.assertNotNull - -class DefaultLocationProviderTest : AbstractCoreTest() { - val configuration = dokkaConfiguration { - sourceSets { - sourceSet { - sourceRoots = listOf("src/") - } - } - } - - @Test - fun `#644 same directory for module and package`() { - testInline( - """ - |/src/main/kotlin/basic/Test.kt - | - |class Test { - | val x = 1 - |} - """.trimMargin(), - configuration - ) { - var context: DokkaContext? = null - pluginsSetupStage = { - context = it - } - - pagesGenerationStage = { module -> - val lp = DokkaLocationProvider(module, context!!) - assertNotEquals(lp.resolve(module.children.single()).removePrefix("/"), lp.resolve(module)) - } - } - } - - @Test - fun `should escape illegal pipe character in file name`() { - /* - Currently even kotlin doesn't escape pipe characters in file names so it is impossible to have a - class named || on windows - */ - testInline( - """ - |/src/main/kotlin/basic/Test.kt - | - |class Test { - | fun `||`() { } - |} - """.trimMargin(), - configuration - ) { - var context: DokkaContext? = null - pluginsSetupStage = { - context = it - } - - pagesGenerationStage = { module -> - val lp = DokkaLocationProvider(module, context!!) - val functionWithPipes = module.dfs { it.name == "||" } - assertNotNull(functionWithPipes, "Failed to find a page for a function named ||") - assertEquals(lp.resolve(functionWithPipes), "[root]/-test/[124][124].html") - } - } - } - - @ParameterizedTest - @MethodSource - fun runEscapeTestForCharacter(data: TestData) { - testInline( - """ - |/src/main/kotlin/basic/Test.kt - | - |class Test { - | fun `${data.tested}`() { } - |} - """.trimMargin(), - configuration - ) { - var context: DokkaContext? = null - pluginsSetupStage = { - context = it - } - - pagesGenerationStage = { module -> - val lp = DokkaLocationProvider(module, context!!) - val functionWithPipes = module.dfs { it.name == "${data.tested}" } - assertNotNull(functionWithPipes, "Failed to find a page for a function named ${data.tested}") - assertEquals(lp.resolve(functionWithPipes), "[root]/-test/${data.expectedReplacement}.html") - } - } - } - - data class TestData(val tested: Char, val expectedReplacement: String) - - companion object TestDataSources { - @JvmStatic - fun runEscapeTestForCharacter(): List<TestData> = listOf( - '|' to "[124]", - '>' to "[62]", - '<' to "[60]", - '*' to "[42]", - ':' to "[58]", - '"' to "[34]", - '?' to "[63]", - '%' to "[37]" - ).map { - TestData(it.first, it.second) - } - } -} |