aboutsummaryrefslogtreecommitdiff
path: root/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt
diff options
context:
space:
mode:
authorPaweł Marks <pmarks@virtuslab.com>2020-02-17 09:32:35 +0100
committerPaweł Marks <Kordyjan@users.noreply.github.com>2020-02-18 13:28:23 +0100
commitf625cef495d625d81ee22e950083f57cc4fab875 (patch)
treed4587be659154a3000ee58fe2297e55604e418e8 /plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt
parent3b200cf10e0c50c2eee4b9da3f7039d678fa4aad (diff)
downloaddokka-f625cef495d625d81ee22e950083f57cc4fab875.tar.gz
dokka-f625cef495d625d81ee22e950083f57cc4fab875.tar.bz2
dokka-f625cef495d625d81ee22e950083f57cc4fab875.zip
Moves PsiToDocumentablesTranslator to the base plugin
Diffstat (limited to 'plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt')
-rw-r--r--plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt216
1 files changed, 216 insertions, 0 deletions
diff --git a/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt b/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt
new file mode 100644
index 00000000..c9270681
--- /dev/null
+++ b/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt
@@ -0,0 +1,216 @@
+package org.jetbrains.dokka.renderers.html
+
+import kotlinx.html.*
+import kotlinx.html.stream.createHTML
+import org.jetbrains.dokka.base.renderers.DefaultRenderer
+import org.jetbrains.dokka.links.DRI
+import org.jetbrains.dokka.model.Function
+import org.jetbrains.dokka.pages.*
+import org.jetbrains.dokka.plugability.DokkaContext
+import org.jetbrains.dokka.renderers.OutputWriter
+import java.io.File
+
+open class HtmlRenderer(
+ context: DokkaContext
+) : DefaultRenderer<FlowContent>(context) {
+
+ private val pageList = mutableListOf<String>()
+
+ override val preprocessors = listOf(
+ RootCreator,
+ SearchPageInstaller,
+ ResourceInstaller,
+ NavigationPageInstaller,
+ StyleAndScriptsAppender
+ )
+
+ override fun FlowContent.buildList(node: ContentList, pageContext: ContentPage) =
+ if (node.ordered) ol {
+ buildListItems(node.children, pageContext)
+ }
+ else ul {
+ buildListItems(node.children, pageContext)
+ }
+
+ open fun OL.buildListItems(items: List<ContentNode>, pageContext: ContentPage) {
+ items.forEach {
+ if (it is ContentList)
+ buildList(it, pageContext)
+ else
+ li { it.build(this, pageContext) }
+ }
+ }
+
+ open fun UL.buildListItems(items: List<ContentNode>, pageContext: ContentPage) {
+ items.forEach {
+ if (it is ContentList)
+ buildList(it, pageContext)
+ else
+ li { it.build(this, pageContext) }
+ }
+ }
+
+ override fun FlowContent.buildResource(
+ node: ContentEmbeddedResource,
+ pageContext: ContentPage
+ ) { // TODO: extension point there
+ val imageExtensions = setOf("png", "jpg", "jpeg", "gif", "bmp", "tif", "webp", "svg")
+ return if (File(node.address).extension.toLowerCase() in imageExtensions) {
+ //TODO: add imgAttrs parsing
+ val imgAttrs = node.extras.filterIsInstance<HTMLSimpleAttr>().joinAttr()
+ img(src = node.address, alt = node.altText)
+ } else {
+ println("Unrecognized resource type: $node")
+ }
+ }
+
+ override fun FlowContent.buildTable(node: ContentTable, pageContext: ContentPage) {
+ table {
+ thead {
+ node.header.forEach {
+ tr {
+ it.children.forEach {
+ th {
+ it.build(this@table, pageContext)
+ }
+ }
+ }
+ }
+ }
+ tbody {
+ node.children.forEach {
+ tr {
+ it.children.forEach {
+ td {
+ it.build(this, pageContext)
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ override fun FlowContent.buildHeader(level: Int, content: FlowContent.() -> Unit) {
+ when (level) {
+ 1 -> h1(block = content)
+ 2 -> h2(block = content)
+ 3 -> h3(block = content)
+ 4 -> h4(block = content)
+ 5 -> h5(block = content)
+ else -> h6(block = content)
+ }
+ }
+
+ override fun FlowContent.buildNavigation(page: PageNode) =
+ locationProvider.ancestors(page).asReversed().forEach { node ->
+ text("/")
+ if (node.isNavigable) buildLink(node, page)
+ else text(node.name)
+ }
+
+ private fun FlowContent.buildLink(to: PageNode, from: PageNode) =
+ buildLink(locationProvider.resolve(to, from)) {
+ text(to.name)
+ }
+
+ fun FlowContent.buildLink(
+ to: DRI,
+ platforms: List<PlatformData>,
+ from: PageNode? = null,
+ block: FlowContent.() -> Unit
+ ) = buildLink(locationProvider.resolve(to, platforms, from), block)
+
+ override fun buildError(node: ContentNode) {
+ context.logger.error("Unknown ContentNode type: $node")
+ }
+
+ override fun FlowContent.buildNewLine() {
+ br()
+ }
+
+ override fun FlowContent.buildLink(address: String, content: FlowContent.() -> Unit) =
+ a(href = address, block = content)
+
+ override fun FlowContent.buildCode(code: List<ContentNode>, language: String, pageContext: ContentPage) {
+ buildNewLine()
+ code.forEach {
+ +((it as? ContentText)?.text ?: run { context.logger.error("Cannot cast $it as ContentText!"); "" })
+ buildNewLine()
+ }
+ }
+
+ override fun renderPage(page: PageNode) {
+ super.renderPage(page)
+ if (page is ContentPage) {
+ pageList.add(
+ """{ "name": "${page.name}", ${if (page is ClasslikePageNode) "\"class\": \"${page.name}\"," else ""} "location": "${locationProvider.resolve(
+ page
+ )}" }"""
+ )
+ }
+ }
+
+ override fun FlowContent.buildText(textNode: ContentText) {
+ text(textNode.text)
+ }
+
+ override fun render(root: RootPageNode) {
+ super.render(root)
+ outputWriter.write("scripts/pages", "var pages = [\n${pageList.joinToString(",\n")}\n]", ".js")
+ }
+
+ private fun PageNode.root(path: String) = locationProvider.resolveRoot(this) + path
+
+ override fun buildPage(page: ContentPage, content: (FlowContent, ContentPage) -> Unit): String =
+ buildHtml(page, page.embeddedResources) { content(this, page) }
+
+ open fun buildHtml(page: PageNode, resources: List<String>, content: FlowContent.() -> Unit) =
+ createHTML().html {
+ head {
+ title(page.name)
+ with(resources) {
+ filter { it.substringBefore('?').substringAfterLast('.') == "css" }
+ .forEach { link(rel = LinkRel.stylesheet, href = page.root(it)) }
+ filter { it.substringBefore('?').substringAfterLast('.') == "js" }
+ .forEach { script(type = ScriptType.textJavaScript, src = page.root(it)) { async = true } }
+ }
+ script { unsafe { +"""var pathToRoot = "${locationProvider.resolveRoot(page)}";""" } }
+ }
+ body {
+ div {
+ id = "navigation"
+ div {
+ id = "searchBar"
+ form(action = page.root("-search.html"), method = FormMethod.get) {
+ id = "searchForm"
+ input(type = InputType.search, name = "query")
+ input(type = InputType.submit) { value = "Search" }
+ }
+ }
+ div {
+ id = "sideMenu"
+ }
+ }
+ div {
+ id = "content"
+ content()
+ }
+ }
+ }
+}
+
+fun List<HTMLMetadata>.joinAttr() = joinToString(" ") { it.key + "=" + it.value }
+
+private fun PageNode.pageKind() = when (this) {
+ is PackagePageNode -> "package"
+ is ClasslikePageNode -> "class"
+ is MemberPageNode -> when (this.documentable) {
+ is Function -> "function"
+ else -> "other"
+ }
+ else -> "other"
+}
+
+private val PageNode.isNavigable: Boolean
+ get() = this !is RendererSpecificPage || strategy != RenderingStrategy.DoNothing \ No newline at end of file