Skip to content

Commit

Permalink
Add the link to GitHub repo to the header if there are source links d…
Browse files Browse the repository at this point in the history
…efined
  • Loading branch information
whyoleg committed Oct 18, 2023
1 parent f225faf commit e38ff6b
Show file tree
Hide file tree
Showing 7 changed files with 173 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Expand All @@ -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<String, String>? {
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
Expand All @@ -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,
Expand All @@ -117,6 +144,7 @@ public class DefaultTemplateModelFactory(
else
async = true
}

resource.isImage() -> link(href = if (resource.isAbsolute) resource else "$pathToRoot$resource")
else -> null
}
Expand Down Expand Up @@ -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<Any?, Any?>?,
Expand All @@ -170,6 +201,7 @@ private class TemplateDirective(val configuration: DokkaConfiguration, val pathT
Context(env, body)
)
}

"projectName" -> {
body ?: throw TemplateModelException(
"No directive body $commandName command."
Expand All @@ -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"
)
Expand Down
5 changes: 5 additions & 0 deletions plugins/base/src/main/resources/dokka/images/github-link.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
32 changes: 31 additions & 1 deletion plugins/base/src/main/resources/dokka/styles/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,7 @@ td:first-child {
/* --- Navigation controls --- */
.navigation-controls {
display: flex;
margin-left: 4px;
}

@media (min-width: 760px) {
Expand All @@ -365,7 +366,6 @@ td:first-child {
display: block;
border-radius: 50%;
background-color: inherit;
margin-left: 4px;
padding: 0;
border: none;
cursor: pointer;
Expand Down Expand Up @@ -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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@
<@source_set_selector.display/>
</div>
<div class="navigation-controls">
<#if sourceUrl?has_content>
<div class="navigation-controls--btn navigation-controls--source" id="source-link" role="button"><a href="${sourceUrl}"></a></div>
</#if>
<button class="navigation-controls--btn navigation-controls--theme" id="theme-toggle-button" type="button">switch theme</button>
<div class="navigation-controls--btn navigation-controls--search" id="searchBar" role="button">search in API</div>
</div>
Expand Down
94 changes: 94 additions & 0 deletions plugins/base/src/test/kotlin/renderers/html/HeaderTest.kt
Original file line number Diff line number Diff line change
@@ -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")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -48,13 +49,15 @@ abstract class HtmlRenderingOnlyTestBase : RenderingOnlyTestBase<Element>() {
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 {
Expand Down

0 comments on commit e38ff6b

Please sign in to comment.