From c06921718acac00967163bba7e918b892fbd25c2 Mon Sep 17 00:00:00 2001 From: Oleg Yukhnevich Date: Wed, 18 Oct 2023 21:37:35 +0300 Subject: [PATCH 1/8] Add the link to GitHub repo to the header if there are source links defined --- .../renderers/html/htmlPreprocessors.kt | 1 + .../DefaultTemplateModelFactory.kt | 35 ++++++- .../resources/dokka/images/github-link.svg | 5 + .../src/main/resources/dokka/styles/style.css | 32 ++++++- .../dokka/templates/includes/header.ftl | 3 + .../test/kotlin/renderers/html/HeaderTest.kt | 94 +++++++++++++++++++ .../html/HtmlRenderingOnlyTestBase.kt | 7 +- 7 files changed, 173 insertions(+), 4 deletions(-) create mode 100644 plugins/base/src/main/resources/dokka/images/github-link.svg create mode 100644 plugins/base/src/test/kotlin/renderers/html/HeaderTest.kt diff --git a/plugins/base/src/main/kotlin/renderers/html/htmlPreprocessors.kt b/plugins/base/src/main/kotlin/renderers/html/htmlPreprocessors.kt index dc877605e9..fe915f1fcc 100644 --- a/plugins/base/src/main/kotlin/renderers/html/htmlPreprocessors.kt +++ b/plugins/base/src/main/kotlin/renderers/html/htmlPreprocessors.kt @@ -111,6 +111,7 @@ public object AssetsInstaller : PageTransformer { "images/copy-successful-icon.svg", "images/theme-toggle.svg", "images/burger.svg", + "images/github-link.svg", // navigation icons "images/nav-icons/abstract-class.svg", diff --git a/plugins/base/src/main/kotlin/renderers/html/innerTemplating/DefaultTemplateModelFactory.kt b/plugins/base/src/main/kotlin/renderers/html/innerTemplating/DefaultTemplateModelFactory.kt index 3883bc4aed..72bf7a9663 100644 --- a/plugins/base/src/main/kotlin/renderers/html/innerTemplating/DefaultTemplateModelFactory.kt +++ b/plugins/base/src/main/kotlin/renderers/html/innerTemplating/DefaultTemplateModelFactory.kt @@ -71,6 +71,8 @@ public class DefaultTemplateModelFactory( } mapper["template_cmd"] = TemplateDirective(context.configuration, pathToRoot) + calculateSourceUrlFromSourceLinks()?.let { mapper["sourceUrl"] = it } + if (page is ContentPage) { val sourceSets = page.content.withDescendants() .flatMap { it.sourceSets } @@ -91,6 +93,30 @@ public class DefaultTemplateModelFactory( ?: DokkaBaseConfiguration.defaultFooterMessage) ) + private fun calculateSourceUrlFromSourceLinks(): String? { + val githubLinkRegex = Regex("http(s)?://github\\.com/([\\w,\\-_]+)/([\\w,\\-_]+)/.*") + + fun parseGithubInfo(link: String): Pair? { + val ( + _, // entire match + _, // optional 's' in http + owner, + repo + ) = githubLinkRegex.find(link)?.groupValues ?: return null + return owner to repo + } + + val (owner, repo) = context.configuration.sourceSets + .asSequence() + .flatMap { it.sourceLinks } + .map { it.remoteUrl.toString() } + .map(::parseGithubInfo) + .distinct() + .singleOrNull() ?: return null + + return "https://github.com/$owner/$repo/" + } + private val DisplaySourceSet.comparableKey get() = sourceSetIDs.merged.let { it.scopeId + it.sourceSetName } private val String.isAbsolute: Boolean @@ -107,6 +133,7 @@ public class DefaultTemplateModelFactory( rel = LinkRel.stylesheet, href = if (resource.isAbsolute) resource else "$pathToRoot$resource" ) + resource.URIExtension == "js" -> script( type = ScriptType.textJavaScript, @@ -117,6 +144,7 @@ public class DefaultTemplateModelFactory( else async = true } + resource.isImage() -> link(href = if (resource.isAbsolute) resource else "$pathToRoot$resource") else -> null } @@ -144,7 +172,10 @@ private class PrintDirective(val generateData: () -> String) : TemplateDirective } } -private class TemplateDirective(val configuration: DokkaConfiguration, val pathToRoot: String) : TemplateDirectiveModel { +private class TemplateDirective( + val configuration: DokkaConfiguration, + val pathToRoot: String +) : TemplateDirectiveModel { override fun execute( env: Environment, params: MutableMap?, @@ -170,6 +201,7 @@ private class TemplateDirective(val configuration: DokkaConfiguration, val pathT Context(env, body) ) } + "projectName" -> { body ?: throw TemplateModelException( "No directive body $commandName command." @@ -183,6 +215,7 @@ private class TemplateDirective(val configuration: DokkaConfiguration, val pathT Context(env, body) ) } + else -> throw TemplateModelException( "The parameter $PARAM_NAME $commandName is unknown" ) diff --git a/plugins/base/src/main/resources/dokka/images/github-link.svg b/plugins/base/src/main/resources/dokka/images/github-link.svg new file mode 100644 index 0000000000..ac671baa5f --- /dev/null +++ b/plugins/base/src/main/resources/dokka/images/github-link.svg @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/plugins/base/src/main/resources/dokka/styles/style.css b/plugins/base/src/main/resources/dokka/styles/style.css index 67a899a594..936524cc04 100644 --- a/plugins/base/src/main/resources/dokka/styles/style.css +++ b/plugins/base/src/main/resources/dokka/styles/style.css @@ -342,6 +342,7 @@ td:first-child { /* --- Navigation controls --- */ .navigation-controls { display: flex; + margin-left: 4px; } @media (min-width: 760px) { @@ -365,7 +366,6 @@ td:first-child { display: block; border-radius: 50%; background-color: inherit; - margin-left: 4px; padding: 0; border: none; cursor: pointer; @@ -394,6 +394,36 @@ td:first-child { } /* /--- Navigation THEME --- */ +/* --- Navigation SOURCE --- */ +.navigation-controls--source { + height: 40px; + width: 40px; + display: block; + border-radius: 50%; + cursor: pointer; +} + +.navigation-controls--source a::before { + height: 100%; + width: 20px; + margin-left: 10px; + display: block; + content: ""; + background: url("../images/github-link.svg"); + background-size: 100% 100%; +} + +.navigation-controls--source:hover { + background: var(--white-10); +} + +@media (max-width: 759px) { + .navigation-controls--source { + display: none; + } +} +/* /--- Navigation SOURCE --- */ + .navigation .platform-selector:not([data-active]) { color: #fff; } diff --git a/plugins/base/src/main/resources/dokka/templates/includes/header.ftl b/plugins/base/src/main/resources/dokka/templates/includes/header.ftl index d5c7a61315..4f0aca8aba 100644 --- a/plugins/base/src/main/resources/dokka/templates/includes/header.ftl +++ b/plugins/base/src/main/resources/dokka/templates/includes/header.ftl @@ -21,6 +21,9 @@ <@source_set_selector.display/> diff --git a/plugins/base/src/test/kotlin/renderers/html/HeaderTest.kt b/plugins/base/src/test/kotlin/renderers/html/HeaderTest.kt new file mode 100644 index 0000000000..449acf5ecc --- /dev/null +++ b/plugins/base/src/test/kotlin/renderers/html/HeaderTest.kt @@ -0,0 +1,94 @@ +/* + * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. + */ + +package renderers.html + +import org.jetbrains.dokka.SourceLinkDefinitionImpl +import org.jetbrains.dokka.base.renderers.html.HtmlRenderer +import org.jsoup.Jsoup +import org.jsoup.nodes.Element +import renderers.testPage +import java.net.URL +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertNotNull +import kotlin.test.assertNull + +class HeaderTest : HtmlRenderingOnlyTestBase() { + override val renderedContent: Element + get() = files.contents.getValue("test-page.html").let { Jsoup.parse(it) }.select(".navigation").single() + + @Test + fun `should include link to github if sourceLinks are pointed to github`() { + val sourceLink = SourceLinkDefinitionImpl( + localDirectory = "", + remoteUrl = URL("https://github.com/Kotlin/dokka/tree/main"), + remoteLineSuffix = null + ) + val context = context( + configuration.copy( + sourceSets = configuration.sourceSets.map { + it.copy(sourceLinks = setOf(sourceLink)) + } + ) + ) + + HtmlRenderer(context).render(testPage { }) + + val sourceLinkElement = + assertNotNull(renderedContent.getElementById("source-link"), "Source link element not found") + val aElement = assertNotNull(sourceLinkElement.selectFirst("a")) + assertEquals("https://github.com/Kotlin/dokka/", aElement.attr("href")) + } + + @Test + fun `should not include link to github if sourceLinks are different`() { + val sourceLink = SourceLinkDefinitionImpl( + localDirectory = "", + remoteUrl = URL("https://github.com/Kotlin/dokka/tree/main"), + remoteLineSuffix = null + ) + val context = context( + configuration.copy( + sourceSets = listOf( + js.copy(sourceLinks = setOf(sourceLink)), + jvm.copy(sourceLinks = setOf(sourceLink.copy(remoteUrl = URL("https://github.com/Kotlin/dokkatoo/tree/main")))) + ) + ) + ) + + HtmlRenderer(context).render(testPage { }) + + assertNull(renderedContent.getElementById("source-link"), "Source link element found") + } + + @Test + fun `should not include link to github if sourceLinks are pointed to gitlab`() { + val sourceLink = SourceLinkDefinitionImpl( + localDirectory = "", + remoteUrl = URL("https://gitlab.com/Kotlin/dokka/tree/main"), + remoteLineSuffix = null + ) + val context = context( + configuration.copy( + sourceSets = configuration.sourceSets.map { + it.copy(sourceLinks = setOf(sourceLink)) + } + ) + ) + + HtmlRenderer(context).render(testPage { }) + + assertNull(renderedContent.getElementById("source-link"), "Source link element found") + } + + @Test + fun `should not include link to github if there are no sourceLinks`() { + val context = context(configuration) + + HtmlRenderer(context).render(testPage { }) + + assertNull(renderedContent.getElementById("source-link"), "Source link element found") + } +} diff --git a/plugins/base/src/test/kotlin/renderers/html/HtmlRenderingOnlyTestBase.kt b/plugins/base/src/test/kotlin/renderers/html/HtmlRenderingOnlyTestBase.kt index 4e098371e7..0553c8ab59 100644 --- a/plugins/base/src/test/kotlin/renderers/html/HtmlRenderingOnlyTestBase.kt +++ b/plugins/base/src/test/kotlin/renderers/html/HtmlRenderingOnlyTestBase.kt @@ -4,6 +4,7 @@ package renderers.html +import org.jetbrains.dokka.DokkaConfiguration import org.jetbrains.dokka.DokkaConfigurationImpl import org.jetbrains.dokka.Platform import org.jetbrains.dokka.base.DokkaBase @@ -48,13 +49,15 @@ abstract class HtmlRenderingOnlyTestBase : RenderingOnlyTestBase() { finalizeCoroutines = false ) - override val context = MockContext( + override val context by lazy { context(configuration) } + + fun context(testConfiguration: DokkaConfiguration): MockContext = MockContext( DokkaBase().outputWriter to { files }, DokkaBase().locationProviderFactory to ::DokkaLocationProviderFactory, DokkaBase().htmlPreprocessors to { RootCreator }, DokkaBase().externalLocationProviderFactory to ::JavadocExternalLocationProviderFactory, DokkaBase().externalLocationProviderFactory to ::DefaultExternalLocationProviderFactory, - testConfiguration = configuration + testConfiguration = testConfiguration ) override val renderedContent: Element by lazy { From 52ed1f04150464ef564fbbdd7a1de04044b4c020 Mon Sep 17 00:00:00 2001 From: Oleg Yukhnevich Date: Tue, 24 Oct 2023 11:55:07 +0300 Subject: [PATCH 2/8] calculate sourceUrl in shared model --- .../DefaultTemplateModelFactory.kt | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/plugins/base/src/main/kotlin/renderers/html/innerTemplating/DefaultTemplateModelFactory.kt b/plugins/base/src/main/kotlin/renderers/html/innerTemplating/DefaultTemplateModelFactory.kt index 72bf7a9663..6771487e85 100644 --- a/plugins/base/src/main/kotlin/renderers/html/innerTemplating/DefaultTemplateModelFactory.kt +++ b/plugins/base/src/main/kotlin/renderers/html/innerTemplating/DefaultTemplateModelFactory.kt @@ -71,8 +71,6 @@ public class DefaultTemplateModelFactory( } mapper["template_cmd"] = TemplateDirective(context.configuration, pathToRoot) - calculateSourceUrlFromSourceLinks()?.let { mapper["sourceUrl"] = it } - if (page is ContentPage) { val sourceSets = page.content.withDescendants() .flatMap { it.sourceSets } @@ -88,18 +86,21 @@ public class DefaultTemplateModelFactory( return mapper } - override fun buildSharedModel(): TemplateMap = mapOf( - "footerMessage" to (configuration?.footerMessage?.takeIf { it.isNotEmpty() } - ?: DokkaBaseConfiguration.defaultFooterMessage) - ) + override fun buildSharedModel(): TemplateMap { + val mapper = mutableMapOf() + + mapper["footerMessage"] = + (configuration?.footerMessage?.takeIf(String::isNotBlank) ?: DokkaBaseConfiguration.defaultFooterMessage) - private fun calculateSourceUrlFromSourceLinks(): String? { - val githubLinkRegex = Regex("http(s)?://github\\.com/([\\w,\\-_]+)/([\\w,\\-_]+)/.*") + calculateSourceUrlFromSourceLinks()?.let { mapper["sourceUrl"] = it } + return mapper + } + + private fun calculateSourceUrlFromSourceLinks(): String? { fun parseGithubInfo(link: String): Pair? { val ( _, // entire match - _, // optional 's' in http owner, repo ) = githubLinkRegex.find(link)?.groupValues ?: return null @@ -153,6 +154,10 @@ public class DefaultTemplateModelFactory( append(resourceHtml) } } + + private companion object { + val githubLinkRegex = Regex("https?://github\\.com/([\\w,\\-_]+)/([\\w,\\-_]+)/.*") + } } private class PrintDirective(val generateData: () -> String) : TemplateDirectiveModel { From a9c8eb33d17ac2fb89356c4f43df7492bac12770 Mon Sep 17 00:00:00 2001 From: Oleg Yukhnevich Date: Tue, 24 Oct 2023 12:48:41 +0300 Subject: [PATCH 3/8] refactor tests to use BaseAbstractTest --- .../test/kotlin/renderers/html/HeaderTest.kt | 103 ++++++++++++------ 1 file changed, 72 insertions(+), 31 deletions(-) diff --git a/plugins/base/src/test/kotlin/renderers/html/HeaderTest.kt b/plugins/base/src/test/kotlin/renderers/html/HeaderTest.kt index 449acf5ecc..6f82cee473 100644 --- a/plugins/base/src/test/kotlin/renderers/html/HeaderTest.kt +++ b/plugins/base/src/test/kotlin/renderers/html/HeaderTest.kt @@ -4,20 +4,33 @@ package renderers.html +import org.jetbrains.dokka.DokkaConfigurationImpl import org.jetbrains.dokka.SourceLinkDefinitionImpl -import org.jetbrains.dokka.base.renderers.html.HtmlRenderer +import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest +import org.jetbrains.dokka.pages.RootPageNode +import org.jetbrains.dokka.plugability.DokkaContext import org.jsoup.Jsoup -import org.jsoup.nodes.Element -import renderers.testPage +import utils.TestOutputWriter +import utils.TestOutputWriterPlugin import java.net.URL import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertNotNull import kotlin.test.assertNull -class HeaderTest : HtmlRenderingOnlyTestBase() { - override val renderedContent: Element - get() = files.contents.getValue("test-page.html").let { Jsoup.parse(it) }.select(".navigation").single() +class HeaderTest : BaseAbstractTest() { + private val configuration = dokkaConfiguration { + sourceSets { + sourceSet { + name = "jvm" + sourceRoots = listOf("src/jvm") + } + sourceSet { + name = "js" + sourceRoots = listOf("src/js") + } + } + } @Test fun `should include link to github if sourceLinks are pointed to github`() { @@ -26,20 +39,20 @@ class HeaderTest : HtmlRenderingOnlyTestBase() { remoteUrl = URL("https://github.com/Kotlin/dokka/tree/main"), remoteLineSuffix = null ) - val context = context( + testRendering( configuration.copy( sourceSets = configuration.sourceSets.map { it.copy(sourceLinks = setOf(sourceLink)) } ) - ) - - HtmlRenderer(context).render(testPage { }) + ) { _, _, writer -> + val renderedContent = navigationElement(writer) - val sourceLinkElement = - assertNotNull(renderedContent.getElementById("source-link"), "Source link element not found") - val aElement = assertNotNull(sourceLinkElement.selectFirst("a")) - assertEquals("https://github.com/Kotlin/dokka/", aElement.attr("href")) + val sourceLinkElement = + assertNotNull(renderedContent.getElementById("source-link"), "Source link element not found") + val aElement = assertNotNull(sourceLinkElement.selectFirst("a")) + assertEquals("https://github.com/Kotlin/dokka/", aElement.attr("href")) + } } @Test @@ -49,18 +62,17 @@ class HeaderTest : HtmlRenderingOnlyTestBase() { remoteUrl = URL("https://github.com/Kotlin/dokka/tree/main"), remoteLineSuffix = null ) - val context = context( + testRendering( configuration.copy( sourceSets = listOf( - js.copy(sourceLinks = setOf(sourceLink)), - jvm.copy(sourceLinks = setOf(sourceLink.copy(remoteUrl = URL("https://github.com/Kotlin/dokkatoo/tree/main")))) + configuration.sourceSets[0].copy(sourceLinks = setOf(sourceLink)), + configuration.sourceSets[1].copy(sourceLinks = setOf(sourceLink.copy(remoteUrl = URL("https://github.com/Kotlin/dokkatoo/tree/main")))) ) ) - ) - - HtmlRenderer(context).render(testPage { }) - - assertNull(renderedContent.getElementById("source-link"), "Source link element found") + ) { _, _, writer -> + val renderedContent = navigationElement(writer) + assertNull(renderedContent.getElementById("source-link"), "Source link element found") + } } @Test @@ -70,25 +82,54 @@ class HeaderTest : HtmlRenderingOnlyTestBase() { remoteUrl = URL("https://gitlab.com/Kotlin/dokka/tree/main"), remoteLineSuffix = null ) - val context = context( + testRendering( configuration.copy( sourceSets = configuration.sourceSets.map { it.copy(sourceLinks = setOf(sourceLink)) } ) - ) - - HtmlRenderer(context).render(testPage { }) - - assertNull(renderedContent.getElementById("source-link"), "Source link element found") + ) { _, _, writer -> + val renderedContent = navigationElement(writer) + assertNull(renderedContent.getElementById("source-link"), "Source link element found") + } } @Test fun `should not include link to github if there are no sourceLinks`() { - val context = context(configuration) + testRendering(configuration) { _, _, writer -> + val renderedContent = navigationElement(writer) + assertNull(renderedContent.getElementById("source-link"), "Source link element found") + } + } - HtmlRenderer(context).render(testPage { }) - assertNull(renderedContent.getElementById("source-link"), "Source link element found") + private fun testRendering( + configuration: DokkaConfigurationImpl = this.configuration, + block: (RootPageNode, DokkaContext, writer: TestOutputWriter) -> Unit + ) { + val writerPlugin = TestOutputWriterPlugin() + testInline( + """ + |/src/jvm/Test.kt + |fun test() {} + |/src/js/Test.kt + |fun test() {} + """, + configuration, + pluginOverrides = listOf(writerPlugin) + ) { + renderingStage = { node, context -> + block(node, context, writerPlugin.writer) + } + } } + + private fun navigationElement(writer: TestOutputWriter) = + writer + .contents + .getValue("index.html") + .let(Jsoup::parse) + .select(".navigation") + .single() + } From 506ef29e20895cab3f208ab43bc2dcd5febfd116 Mon Sep 17 00:00:00 2001 From: Oleg Yukhnevich Date: Tue, 24 Oct 2023 12:50:35 +0300 Subject: [PATCH 4/8] revert changes in HtmlRenderingOnlyTestBase --- .../kotlin/renderers/html/HtmlRenderingOnlyTestBase.kt | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/plugins/base/src/test/kotlin/renderers/html/HtmlRenderingOnlyTestBase.kt b/plugins/base/src/test/kotlin/renderers/html/HtmlRenderingOnlyTestBase.kt index 0553c8ab59..4e098371e7 100644 --- a/plugins/base/src/test/kotlin/renderers/html/HtmlRenderingOnlyTestBase.kt +++ b/plugins/base/src/test/kotlin/renderers/html/HtmlRenderingOnlyTestBase.kt @@ -4,7 +4,6 @@ package renderers.html -import org.jetbrains.dokka.DokkaConfiguration import org.jetbrains.dokka.DokkaConfigurationImpl import org.jetbrains.dokka.Platform import org.jetbrains.dokka.base.DokkaBase @@ -49,15 +48,13 @@ abstract class HtmlRenderingOnlyTestBase : RenderingOnlyTestBase() { finalizeCoroutines = false ) - override val context by lazy { context(configuration) } - - fun context(testConfiguration: DokkaConfiguration): MockContext = MockContext( + override val context = MockContext( DokkaBase().outputWriter to { files }, DokkaBase().locationProviderFactory to ::DokkaLocationProviderFactory, DokkaBase().htmlPreprocessors to { RootCreator }, DokkaBase().externalLocationProviderFactory to ::JavadocExternalLocationProviderFactory, DokkaBase().externalLocationProviderFactory to ::DefaultExternalLocationProviderFactory, - testConfiguration = testConfiguration + testConfiguration = configuration ) override val renderedContent: Element by lazy { From 66628026d2ee184a018780b142a09b0e37960df1 Mon Sep 17 00:00:00 2001 From: Oleg Yukhnevich Date: Fri, 27 Oct 2023 18:27:05 +0300 Subject: [PATCH 5/8] Rework homepage links: * no GitHub support by default * use URL from base plugin configuration * add integration test for the multi-module project that the homepage link exists everywhere --- .../it-multimodule-0/moduleA/build.gradle.kts | 10 +++ .../it/gradle/MultiModule0IntegrationTest.kt | 15 ++++ .../src/main/kotlin/DokkaBaseConfiguration.kt | 1 + .../renderers/html/htmlPreprocessors.kt | 2 +- .../DefaultTemplateModelFactory.kt | 26 +----- .../resources/dokka/images/github-link.svg | 5 -- .../main/resources/dokka/images/homepage.svg | 5 ++ .../src/main/resources/dokka/styles/style.css | 14 +-- .../dokka/templates/includes/header.ftl | 4 +- .../test/kotlin/renderers/html/HeaderTest.kt | 85 ++++++------------- 10 files changed, 68 insertions(+), 99 deletions(-) delete mode 100644 plugins/base/src/main/resources/dokka/images/github-link.svg create mode 100644 plugins/base/src/main/resources/dokka/images/homepage.svg diff --git a/integration-tests/gradle/projects/it-multimodule-0/moduleA/build.gradle.kts b/integration-tests/gradle/projects/it-multimodule-0/moduleA/build.gradle.kts index 1e61f8b2b7..d24b90c50d 100644 --- a/integration-tests/gradle/projects/it-multimodule-0/moduleA/build.gradle.kts +++ b/integration-tests/gradle/projects/it-multimodule-0/moduleA/build.gradle.kts @@ -8,3 +8,13 @@ plugins { kotlin("jvm") id("org.jetbrains.dokka") } + +allprojects { + tasks.withType { + pluginsMapConfiguration.set( + mapOf( + "org.jetbrains.dokka.base.DokkaBase" to """{ "homepageLink" : "https://github.com/Kotlin/dokka/tree/master/integration-tests/gradle/projects/it-multimodule-0/" }""" + ) + ) + } +} diff --git a/integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/MultiModule0IntegrationTest.kt b/integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/MultiModule0IntegrationTest.kt index 54ac3ff8ab..9745a770a6 100644 --- a/integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/MultiModule0IntegrationTest.kt +++ b/integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/MultiModule0IntegrationTest.kt @@ -73,6 +73,21 @@ class MultiModule0IntegrationTest : AbstractGradleIntegrationTest() { "Expected moduleC being mentioned in -modules.html" ) + val indexHtmls = outputDir.walkTopDown().filter { + it.isFile && it.name == "index.html" + }.toList() + + assertEquals(10, indexHtmls.size) + + indexHtmls.forEach { + assertTrue( + it.readText().contains( + """https://github.com/Kotlin/dokka/tree/master/integration-tests/gradle/projects/it-multimodule-0/""" + ), + "File ${it.absolutePath} doesn't contain link to homepage" + ) + } + val gfmOutputDir = File(projectDir, "moduleA/build/dokka/gfmMultiModule") assertTrue(gfmOutputDir.isDirectory, "Missing dokka GFM output directory") diff --git a/plugins/base/src/main/kotlin/DokkaBaseConfiguration.kt b/plugins/base/src/main/kotlin/DokkaBaseConfiguration.kt index 1118412635..3e7ac0b983 100644 --- a/plugins/base/src/main/kotlin/DokkaBaseConfiguration.kt +++ b/plugins/base/src/main/kotlin/DokkaBaseConfiguration.kt @@ -12,6 +12,7 @@ public data class DokkaBaseConfiguration( var customStyleSheets: List = defaultCustomStyleSheets, var customAssets: List = defaultCustomAssets, var separateInheritedMembers: Boolean = separateInheritedMembersDefault, + var homepageLink: String? = null, var footerMessage: String = defaultFooterMessage, var mergeImplicitExpectActualDeclarations: Boolean = mergeImplicitExpectActualDeclarationsDefault, var templatesDir: File? = defaultTemplatesDir diff --git a/plugins/base/src/main/kotlin/renderers/html/htmlPreprocessors.kt b/plugins/base/src/main/kotlin/renderers/html/htmlPreprocessors.kt index fe915f1fcc..dad013e232 100644 --- a/plugins/base/src/main/kotlin/renderers/html/htmlPreprocessors.kt +++ b/plugins/base/src/main/kotlin/renderers/html/htmlPreprocessors.kt @@ -111,7 +111,7 @@ public object AssetsInstaller : PageTransformer { "images/copy-successful-icon.svg", "images/theme-toggle.svg", "images/burger.svg", - "images/github-link.svg", + "images/homepage.svg", // navigation icons "images/nav-icons/abstract-class.svg", diff --git a/plugins/base/src/main/kotlin/renderers/html/innerTemplating/DefaultTemplateModelFactory.kt b/plugins/base/src/main/kotlin/renderers/html/innerTemplating/DefaultTemplateModelFactory.kt index 6771487e85..fe6f008904 100644 --- a/plugins/base/src/main/kotlin/renderers/html/innerTemplating/DefaultTemplateModelFactory.kt +++ b/plugins/base/src/main/kotlin/renderers/html/innerTemplating/DefaultTemplateModelFactory.kt @@ -92,32 +92,11 @@ public class DefaultTemplateModelFactory( mapper["footerMessage"] = (configuration?.footerMessage?.takeIf(String::isNotBlank) ?: DokkaBaseConfiguration.defaultFooterMessage) - calculateSourceUrlFromSourceLinks()?.let { mapper["sourceUrl"] = it } + configuration?.homepageLink?.takeIf(String::isNotBlank)?.let { mapper["homepageLink"] = it } return mapper } - private fun calculateSourceUrlFromSourceLinks(): String? { - fun parseGithubInfo(link: String): Pair? { - val ( - _, // entire match - owner, - repo - ) = githubLinkRegex.find(link)?.groupValues ?: return null - return owner to repo - } - - val (owner, repo) = context.configuration.sourceSets - .asSequence() - .flatMap { it.sourceLinks } - .map { it.remoteUrl.toString() } - .map(::parseGithubInfo) - .distinct() - .singleOrNull() ?: return null - - return "https://github.com/$owner/$repo/" - } - private val DisplaySourceSet.comparableKey get() = sourceSetIDs.merged.let { it.scopeId + it.sourceSetName } private val String.isAbsolute: Boolean @@ -155,9 +134,6 @@ public class DefaultTemplateModelFactory( } } - private companion object { - val githubLinkRegex = Regex("https?://github\\.com/([\\w,\\-_]+)/([\\w,\\-_]+)/.*") - } } private class PrintDirective(val generateData: () -> String) : TemplateDirectiveModel { diff --git a/plugins/base/src/main/resources/dokka/images/github-link.svg b/plugins/base/src/main/resources/dokka/images/github-link.svg deleted file mode 100644 index ac671baa5f..0000000000 --- a/plugins/base/src/main/resources/dokka/images/github-link.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - \ No newline at end of file diff --git a/plugins/base/src/main/resources/dokka/images/homepage.svg b/plugins/base/src/main/resources/dokka/images/homepage.svg new file mode 100644 index 0000000000..a3d7602bb8 --- /dev/null +++ b/plugins/base/src/main/resources/dokka/images/homepage.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/plugins/base/src/main/resources/dokka/styles/style.css b/plugins/base/src/main/resources/dokka/styles/style.css index 936524cc04..62b0ddbd2c 100644 --- a/plugins/base/src/main/resources/dokka/styles/style.css +++ b/plugins/base/src/main/resources/dokka/styles/style.css @@ -394,8 +394,8 @@ td:first-child { } /* /--- Navigation THEME --- */ -/* --- Navigation SOURCE --- */ -.navigation-controls--source { +/* --- Navigation HOMEPAGE --- */ +.navigation-controls--homepage { height: 40px; width: 40px; display: block; @@ -403,26 +403,26 @@ td:first-child { cursor: pointer; } -.navigation-controls--source a::before { +.navigation-controls--homepage a::before { height: 100%; width: 20px; margin-left: 10px; display: block; content: ""; - background: url("../images/github-link.svg"); + background: url("../images/homepage.svg"); background-size: 100% 100%; } -.navigation-controls--source:hover { +.navigation-controls--homepage:hover { background: var(--white-10); } @media (max-width: 759px) { - .navigation-controls--source { + .navigation-controls--homepage { display: none; } } -/* /--- Navigation SOURCE --- */ +/* /--- Navigation HOMEPAGE --- */ .navigation .platform-selector:not([data-active]) { color: #fff; diff --git a/plugins/base/src/main/resources/dokka/templates/includes/header.ftl b/plugins/base/src/main/resources/dokka/templates/includes/header.ftl index 4f0aca8aba..d399e63354 100644 --- a/plugins/base/src/main/resources/dokka/templates/includes/header.ftl +++ b/plugins/base/src/main/resources/dokka/templates/includes/header.ftl @@ -21,8 +21,8 @@ <@source_set_selector.display/>