aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcin Aman <marcin.aman@gmail.com>2021-01-14 16:51:25 +0100
committerGitHub <noreply@github.com>2021-01-14 16:51:25 +0100
commitc04295aa7f0bdad9eb7b27e3dbc2b2c90094da86 (patch)
tree92952ccc055b3d466e85c9998d6ea5349d5c1ce2
parent4a0af562bc86ebb84ecd8a90f690214c79df8d40 (diff)
downloaddokka-c04295aa7f0bdad9eb7b27e3dbc2b2c90094da86.tar.gz
dokka-c04295aa7f0bdad9eb7b27e3dbc2b2c90094da86.tar.bz2
dokka-c04295aa7f0bdad9eb7b27e3dbc2b2c90094da86.zip
Footer customisation (#1691)
-rw-r--r--docs/src/doc/docs/user_guide/base-specific/frontend.md14
-rw-r--r--plugins/base/src/main/kotlin/DokkaBaseConfiguration.kt7
-rw-r--r--plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt65
-rw-r--r--plugins/base/src/test/kotlin/renderers/html/CustomFooterTest.kt44
-rw-r--r--plugins/base/src/test/kotlin/renderers/html/FooterMessageTest.kt27
-rw-r--r--plugins/base/src/test/kotlin/renderers/html/HtmlRenderingOnlyTestBase.kt9
6 files changed, 137 insertions, 29 deletions
diff --git a/docs/src/doc/docs/user_guide/base-specific/frontend.md b/docs/src/doc/docs/user_guide/base-specific/frontend.md
index 11c0c786..a9fd660f 100644
--- a/docs/src/doc/docs/user_guide/base-specific/frontend.md
+++ b/docs/src/doc/docs/user_guide/base-specific/frontend.md
@@ -1,5 +1,9 @@
# Configuration specific to HTML format
+!!! important
+ Concepts specified below apply only to configuration of the Base Plugin (that contains Html format)
+ and needs to be applied via pluginsConfiguration and not on the root one.
+
## Modifying assets
It is possible to change static assets that are used to generate dokka's HTML.
@@ -19,6 +23,16 @@ Dokka uses 3 stylesheets:
User can choose to add or override those files.
Resources will be overridden when in `pluginConfiguration` block there is a resource with the same name.
+## Modifying footer
+
+Dokka supports custom messages in the footer via `footerMessage` string property on base plugin configuration.
+Keep in mind that this value will be pased exactly to the output html, so it has to be valid and escaped correctly.
+
+## Separating inherited members
+
+By setting a boolean property `separateInheritedMembers` dokka will split inherited members (like functions, properties etc.)
+from ones declared in viewed class. Separated members will have it's own tabs on the page.
+
### Examples
In order to override a logo and style it accordingly a simple css file named `logo-styles.css` is needed:
```css
diff --git a/plugins/base/src/main/kotlin/DokkaBaseConfiguration.kt b/plugins/base/src/main/kotlin/DokkaBaseConfiguration.kt
index 5b93c209..21757d70 100644
--- a/plugins/base/src/main/kotlin/DokkaBaseConfiguration.kt
+++ b/plugins/base/src/main/kotlin/DokkaBaseConfiguration.kt
@@ -2,13 +2,16 @@ package org.jetbrains.dokka.base
import org.jetbrains.dokka.plugability.ConfigurableBlock
import java.io.File
+import java.time.Year
data class DokkaBaseConfiguration(
var customStyleSheets: List<File> = defaultCustomStyleSheets,
var customAssets: List<File> = defaultCustomAssets,
- var separateInheritedMembers: Boolean = separateInheritedMembersDefault
-): ConfigurableBlock {
+ var separateInheritedMembers: Boolean = separateInheritedMembersDefault,
+ var footerMessage: String = defaultFooterMessage
+) : ConfigurableBlock {
companion object {
+ val defaultFooterMessage = "© ${Year.now().value} Copyright"
val defaultCustomStyleSheets: List<File> = emptyList()
val defaultCustomAssets: List<File> = emptyList()
const val separateInheritedMembersDefault: Boolean = false
diff --git a/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt b/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt
index 5c877f03..6eb68280 100644
--- a/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt
+++ b/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt
@@ -4,6 +4,8 @@ import kotlinx.html.*
import kotlinx.html.stream.createHTML
import org.jetbrains.dokka.DokkaSourceSetID
import org.jetbrains.dokka.base.DokkaBase
+import org.jetbrains.dokka.base.DokkaBaseConfiguration
+import org.jetbrains.dokka.base.DokkaBaseConfiguration.Companion.defaultFooterMessage
import org.jetbrains.dokka.base.renderers.DefaultRenderer
import org.jetbrains.dokka.base.renderers.TabSortingStrategy
import org.jetbrains.dokka.base.renderers.html.command.consumers.ImmediateResolutionTagConsumer
@@ -20,16 +22,14 @@ import org.jetbrains.dokka.model.properties.PropertyContainer
import org.jetbrains.dokka.model.sourceSetIDs
import org.jetbrains.dokka.model.withDescendants
import org.jetbrains.dokka.pages.*
-import org.jetbrains.dokka.plugability.DokkaContext
-import org.jetbrains.dokka.plugability.plugin
-import org.jetbrains.dokka.plugability.query
-import org.jetbrains.dokka.plugability.querySingle
+import org.jetbrains.dokka.plugability.*
import org.jetbrains.dokka.utilities.htmlEscape
import java.net.URI
open class HtmlRenderer(
context: DokkaContext
) : DefaultRenderer<FlowContent>(context) {
+ private val configuration = configuration<DokkaBase, DokkaBaseConfiguration>(context)
private val sourceSetDependencyMap: Map<DokkaSourceSetID, List<DokkaSourceSetID>> =
context.configuration.sourceSets.map { sourceSet ->
@@ -107,8 +107,13 @@ open class HtmlRenderer(
}
node.hasStyle(TextStyle.Paragraph) -> p(additionalClasses) { childrenCallback() }
node.hasStyle(TextStyle.Block) -> div(additionalClasses) { childrenCallback() }
- node.isAnchorable -> buildAnchor(node.anchor!!, node.anchorLabel!!, node.sourceSetsFilters) { childrenCallback() }
- node.extra[InsertTemplateExtra] != null -> node.extra[InsertTemplateExtra]?.let { templateCommand(it.command) } ?: Unit
+ node.isAnchorable -> buildAnchor(
+ node.anchor!!,
+ node.anchorLabel!!,
+ node.sourceSetsFilters
+ ) { childrenCallback() }
+ node.extra[InsertTemplateExtra] != null -> node.extra[InsertTemplateExtra]?.let { templateCommand(it.command) }
+ ?: Unit
else -> childrenCallback()
}
}
@@ -147,7 +152,7 @@ open class HtmlRenderer(
}
}
- fun FlowContent.withHtml(content: String): Unit = when (this){
+ fun FlowContent.withHtml(content: String): Unit = when (this) {
is HTMLTag -> unsafe { +content }
else -> div { unsafe { +content } }
}
@@ -225,13 +230,14 @@ open class HtmlRenderer(
sourceSet.sourceSetIDs.all.flatMap { sourceSetDependencyMap[it].orEmpty() }
.any { sourceSetId -> sourceSetId in sourceSets.sourceSetIDs }
}.map {
- it to createHTML(prettyPrint = false).prepareForTemplates().div(classes = "content sourceset-depenent-content") {
- if (counter++ == 0) attributes["data-active"] = ""
- attributes["data-togglable"] = it.sourceSetIDs.merged.toString()
- unsafe {
- +html
+ it to createHTML(prettyPrint = false).prepareForTemplates()
+ .div(classes = "content sourceset-depenent-content") {
+ if (counter++ == 0) attributes["data-active"] = ""
+ attributes["data-togglable"] = it.sourceSetIDs.merged.toString()
+ unsafe {
+ +html
+ }
}
- }
}
}
}
@@ -423,15 +429,15 @@ open class HtmlRenderer(
div {
toRender.filter { it !is ContentLink && !it.hasStyle(ContentStyle.RowTitle) }
.takeIf { it.isNotEmpty() }?.let {
- if (ContentKind.shouldBePlatformTagged(contextNode.dci.kind) && contextNode.sourceSets.size == 1)
- createPlatformTags(contextNode)
+ if (ContentKind.shouldBePlatformTagged(contextNode.dci.kind) && contextNode.sourceSets.size == 1)
+ createPlatformTags(contextNode)
- div("title") {
- it.forEach {
- it.build(this, pageContext, sourceSetRestriction)
+ div("title") {
+ it.forEach {
+ it.build(this, pageContext, sourceSetRestriction)
+ }
}
}
- }
}
}
}
@@ -450,7 +456,9 @@ open class HtmlRenderer(
.forEach {
span("inline-flex") {
it.build(this, pageContext, sourceSetRestriction)
- if(it is ContentLink && !anchorDestination.isNullOrBlank()) buildAnchorCopyButton(anchorDestination)
+ if (it is ContentLink && !anchorDestination.isNullOrBlank()) buildAnchorCopyButton(
+ anchorDestination
+ )
}
}
}
@@ -472,7 +480,7 @@ open class HtmlRenderer(
toRender: List<ContentNode>,
pageContext: ContentPage,
sourceSetRestriction: Set<DisplaySourceSet>?,
- ){
+ ) {
toRender.filter { it !is ContentLink }.takeIf { it.isNotEmpty() }?.let {
it.forEach {
span(classes = if (it.dci.kind == ContentKind.Comment) "brief-comment" else "") {
@@ -573,7 +581,12 @@ open class HtmlRenderer(
}
}
- private fun FlowContent.buildAnchor(anchor: String, anchorLabel: String, sourceSets: String, content: FlowContent.() -> Unit) {
+ private fun FlowContent.buildAnchor(
+ anchor: String,
+ anchorLabel: String,
+ sourceSets: String,
+ content: FlowContent.() -> Unit
+ ) {
a {
attributes["data-name"] = anchor
attributes["anchor-label"] = anchorLabel
@@ -772,9 +785,13 @@ open class HtmlRenderer(
span("go-to-top-icon") {
a(href = "#content")
}
- span { text("© 2020 Copyright") }
+ span {
+ configuration?.footerMessage?.takeIf { it.isNotEmpty() }
+ ?.let { unsafe { raw(it) } }
+ ?: text(defaultFooterMessage)
+ }
span("pull-right") {
- span { text("Sponsored and developed by ") }
+ span { text("Generated by ") }
a(href = "https://github.com/Kotlin/dokka") {
span { text("dokka") }
span(classes = "padded-icon")
diff --git a/plugins/base/src/test/kotlin/renderers/html/CustomFooterTest.kt b/plugins/base/src/test/kotlin/renderers/html/CustomFooterTest.kt
new file mode 100644
index 00000000..c1ef6121
--- /dev/null
+++ b/plugins/base/src/test/kotlin/renderers/html/CustomFooterTest.kt
@@ -0,0 +1,44 @@
+package renderers.html
+
+import org.jetbrains.dokka.DokkaConfiguration
+import org.jetbrains.dokka.DokkaConfigurationImpl
+import org.jetbrains.dokka.PluginConfigurationImpl
+import org.jetbrains.dokka.base.DokkaBase
+import org.jetbrains.dokka.base.DokkaBaseConfiguration
+import org.jetbrains.dokka.base.renderers.html.HtmlRenderer
+import org.jetbrains.dokka.base.templating.toJsonString
+import org.jsoup.Jsoup
+import org.jsoup.nodes.Element
+import org.junit.jupiter.api.Test
+import renderers.testPage
+import utils.A
+import utils.Div
+import utils.Span
+import utils.match
+
+class CustomFooterTest : HtmlRenderingOnlyTestBase() {
+ @Test
+ fun `should include message from custom footer`() {
+ val page = testPage { }
+ HtmlRenderer(context).render(page)
+ renderedContent.match(
+ Span(A()),
+ Span(Div("Custom message")),
+ Span(Span("Generated by "), A(Span("dokka"), Span()))
+ )
+ }
+
+ override val configuration: DokkaConfigurationImpl
+ get() = super.configuration.copy(
+ pluginsConfiguration = listOf(
+ PluginConfigurationImpl(
+ DokkaBase::class.java.canonicalName,
+ DokkaConfiguration.SerializationFormat.JSON,
+ toJsonString(DokkaBaseConfiguration(footerMessage = """<div style="color: red">Custom message</div>"""))
+ )
+ )
+ )
+
+ override val renderedContent: Element
+ get() = files.contents.getValue("test-page.html").let { Jsoup.parse(it) }.select(".footer").single()
+} \ No newline at end of file
diff --git a/plugins/base/src/test/kotlin/renderers/html/FooterMessageTest.kt b/plugins/base/src/test/kotlin/renderers/html/FooterMessageTest.kt
new file mode 100644
index 00000000..d91c402e
--- /dev/null
+++ b/plugins/base/src/test/kotlin/renderers/html/FooterMessageTest.kt
@@ -0,0 +1,27 @@
+package renderers.html
+
+import org.jetbrains.dokka.base.DokkaBaseConfiguration.Companion.defaultFooterMessage
+import org.jetbrains.dokka.base.renderers.html.HtmlRenderer
+import org.jsoup.Jsoup
+import org.jsoup.nodes.Element
+import org.junit.jupiter.api.Test
+import renderers.testPage
+import utils.A
+import utils.Span
+import utils.match
+
+class FooterMessageTest : HtmlRenderingOnlyTestBase() {
+ @Test
+ fun `should include defaultFooter`() {
+ val page = testPage { }
+ HtmlRenderer(context).render(page)
+ renderedContent.match(
+ Span(A()),
+ Span(defaultFooterMessage),
+ Span(Span("Generated by "), A(Span("dokka"), Span()))
+ )
+ }
+
+ override val renderedContent: Element
+ get() = files.contents.getValue("test-page.html").let { Jsoup.parse(it) }.select(".footer").single()
+} \ No newline at end of file
diff --git a/plugins/base/src/test/kotlin/renderers/html/HtmlRenderingOnlyTestBase.kt b/plugins/base/src/test/kotlin/renderers/html/HtmlRenderingOnlyTestBase.kt
index 71d141e2..9b88a170 100644
--- a/plugins/base/src/test/kotlin/renderers/html/HtmlRenderingOnlyTestBase.kt
+++ b/plugins/base/src/test/kotlin/renderers/html/HtmlRenderingOnlyTestBase.kt
@@ -41,6 +41,11 @@ abstract class HtmlRenderingOnlyTestBase : RenderingOnlyTestBase<Element>() {
)
val files = TestOutputWriter()
+
+ open val configuration = DokkaConfigurationImpl(
+ sourceSets = listOf(js, jvm, native)
+ )
+
override val context = MockContext(
DokkaBase().outputWriter to { _ -> files },
DokkaBase().locationProviderFactory to ::DokkaLocationProviderFactory,
@@ -48,9 +53,7 @@ abstract class HtmlRenderingOnlyTestBase : RenderingOnlyTestBase<Element>() {
DokkaBase().externalLocationProviderFactory to { ::JavadocExternalLocationProviderFactory },
DokkaBase().externalLocationProviderFactory to { ::DefaultExternalLocationProviderFactory },
DokkaBase().tabSortingStrategy to { DefaultTabSortingStrategy() },
- testConfiguration = DokkaConfigurationImpl(
- sourceSets = listOf(js, jvm, native)
- )
+ testConfiguration = configuration
)
override val renderedContent: Element by lazy {