From 216a7f6b89ce769bcf4d41301ecc34636dc20155 Mon Sep 17 00:00:00 2001 From: Paweł Marks Date: Fri, 31 Jan 2020 18:16:38 +0100 Subject: Html related things moved to its own package --- .../main/kotlin/plugability/DefaultExtensions.kt | 2 +- core/src/main/kotlin/renderers/HtmlRenderer.kt | 216 -------------------- .../src/main/kotlin/renderers/html/HtmlRenderer.kt | 218 +++++++++++++++++++++ .../kotlin/renderers/html/htmlPreprocessors.kt | 57 ++++++ .../src/main/kotlin/renderers/htmlPreprocessors.kt | 57 ------ 5 files changed, 276 insertions(+), 274 deletions(-) delete mode 100644 core/src/main/kotlin/renderers/HtmlRenderer.kt create mode 100644 core/src/main/kotlin/renderers/html/HtmlRenderer.kt create mode 100644 core/src/main/kotlin/renderers/html/htmlPreprocessors.kt delete mode 100644 core/src/main/kotlin/renderers/htmlPreprocessors.kt (limited to 'core/src') diff --git a/core/src/main/kotlin/plugability/DefaultExtensions.kt b/core/src/main/kotlin/plugability/DefaultExtensions.kt index c45f28be..9f36b2a4 100644 --- a/core/src/main/kotlin/plugability/DefaultExtensions.kt +++ b/core/src/main/kotlin/plugability/DefaultExtensions.kt @@ -3,7 +3,7 @@ package org.jetbrains.dokka.plugability import org.jetbrains.dokka.CoreExtensions import org.jetbrains.dokka.pages.DocTagToContentConverter import org.jetbrains.dokka.renderers.FileWriter -import org.jetbrains.dokka.renderers.HtmlRenderer +import org.jetbrains.dokka.renderers.html.HtmlRenderer import org.jetbrains.dokka.resolvers.DefaultLocationProviderFactory import org.jetbrains.dokka.transformers.descriptors.DefaultDescriptorToDocumentationTranslator import org.jetbrains.dokka.transformers.documentation.DefaultDocumentationNodeMerger diff --git a/core/src/main/kotlin/renderers/HtmlRenderer.kt b/core/src/main/kotlin/renderers/HtmlRenderer.kt deleted file mode 100644 index e8c3a486..00000000 --- a/core/src/main/kotlin/renderers/HtmlRenderer.kt +++ /dev/null @@ -1,216 +0,0 @@ -package org.jetbrains.dokka.renderers - -import kotlinx.html.* -import kotlinx.html.stream.createHTML -import org.jetbrains.dokka.model.Function -import org.jetbrains.dokka.pages.* -import org.jetbrains.dokka.plugability.DokkaContext -import java.io.File - -open class HtmlRenderer( - outputWriter: OutputWriter, - context: DokkaContext -) : DefaultRenderer(outputWriter, context) { - - private val pageList = mutableListOf() - - private var idCounter = 0 - get() = ++field - - private fun FlowContent.buildSideMenu(context: PageNode, node: PageNode) { - val children = node.children.filter { it !is MemberPageNode } - val submenuId = if (children.isNotEmpty()) "nav$idCounter" else null - div("sideMenuPart") { - submenuId?.also { id = it } - div("overview") { - buildLink(node, context) - submenuId?.also { - span("navButton") { - onClick = """document.getElementById("$it").classList.toggle("hidden");""" - span("navButtonContent") - } - } - } - children.forEach { buildSideMenu(context, it) } - } - } - - override val preprocessors = listOf(RootCreator, SearchPageInstaller, ResourceInstaller, StyleAndScriptsAppender) - - override fun FlowContent.buildList(node: ContentList, pageContext: ContentPage) = - if (node.ordered) ol { - buildListItems(node.children, pageContext) - } - else ul { - buildListItems(node.children, pageContext) - } - - protected open fun OL.buildListItems(items: List, pageContext: ContentPage) { - items.forEach { - if (it is ContentList) - buildList(it, pageContext) - else - li { it.build(this, pageContext) } - } - } - - protected open fun UL.buildListItems(items: List, 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().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) - else -> h5(block = content) - } - } - - override fun FlowContent.buildNavigation(page: PageNode) = - locationProvider.ancestors(page).forEach { node -> - text("/") - buildLink(node, page) - } - - private fun FlowContent.buildLink(to: PageNode, from: PageNode) = - buildLink(locationProvider.resolve(to, from)) { - text(to.name) - } - - 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, 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 ClassPageNode) "\"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, 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 = it) { async = true } } - } - } - 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.joinAttr() = joinToString(" ") { it.key + "=" + it.value } - -private fun PageNode.pageKind() = when (this) { - is PackagePageNode -> "package" - is ClassPageNode -> "class" - is MemberPageNode -> when (this.documentable) { - is Function -> "function" - else -> "other" - } - else -> "other" -} diff --git a/core/src/main/kotlin/renderers/html/HtmlRenderer.kt b/core/src/main/kotlin/renderers/html/HtmlRenderer.kt new file mode 100644 index 00000000..462a8acc --- /dev/null +++ b/core/src/main/kotlin/renderers/html/HtmlRenderer.kt @@ -0,0 +1,218 @@ +package org.jetbrains.dokka.renderers.html + +import kotlinx.html.* +import kotlinx.html.stream.createHTML +import org.jetbrains.dokka.model.Function +import org.jetbrains.dokka.pages.* +import org.jetbrains.dokka.plugability.DokkaContext +import org.jetbrains.dokka.renderers.DefaultRenderer +import org.jetbrains.dokka.renderers.OutputWriter +import java.io.File + +open class HtmlRenderer( + outputWriter: OutputWriter, + context: DokkaContext +) : DefaultRenderer(outputWriter, context) { + + private val pageList = mutableListOf() + + private var idCounter = 0 + get() = ++field + + private fun FlowContent.buildSideMenu(context: PageNode, node: PageNode) { + val children = node.children.filter { it !is MemberPageNode } + val submenuId = if (children.isNotEmpty()) "nav$idCounter" else null + div("sideMenuPart") { + submenuId?.also { id = it } + div("overview") { + buildLink(node, context) + submenuId?.also { + span("navButton") { + onClick = """document.getElementById("$it").classList.toggle("hidden");""" + span("navButtonContent") + } + } + } + children.forEach { buildSideMenu(context, it) } + } + } + + override val preprocessors = listOf(RootCreator, SearchPageInstaller, ResourceInstaller, StyleAndScriptsAppender) + + override fun FlowContent.buildList(node: ContentList, pageContext: ContentPage) = + if (node.ordered) ol { + buildListItems(node.children, pageContext) + } + else ul { + buildListItems(node.children, pageContext) + } + + protected open fun OL.buildListItems(items: List, pageContext: ContentPage) { + items.forEach { + if (it is ContentList) + buildList(it, pageContext) + else + li { it.build(this, pageContext) } + } + } + + protected open fun UL.buildListItems(items: List, 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().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) + else -> h5(block = content) + } + } + + override fun FlowContent.buildNavigation(page: PageNode) = + locationProvider.ancestors(page).forEach { node -> + text("/") + buildLink(node, page) + } + + private fun FlowContent.buildLink(to: PageNode, from: PageNode) = + buildLink(locationProvider.resolve(to, from)) { + text(to.name) + } + + 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, 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 ClassPageNode) "\"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, 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 = it) { async = true } } + } + } + 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.joinAttr() = joinToString(" ") { it.key + "=" + it.value } + +private fun PageNode.pageKind() = when (this) { + is PackagePageNode -> "package" + is ClassPageNode -> "class" + is MemberPageNode -> when (this.documentable) { + is Function -> "function" + else -> "other" + } + else -> "other" +} diff --git a/core/src/main/kotlin/renderers/html/htmlPreprocessors.kt b/core/src/main/kotlin/renderers/html/htmlPreprocessors.kt new file mode 100644 index 00000000..382cb204 --- /dev/null +++ b/core/src/main/kotlin/renderers/html/htmlPreprocessors.kt @@ -0,0 +1,57 @@ +package org.jetbrains.dokka.renderers.html + +import kotlinx.html.h1 +import kotlinx.html.id +import kotlinx.html.table +import kotlinx.html.tbody +import org.jetbrains.dokka.pages.RendererSpecificResourcePage +import org.jetbrains.dokka.pages.RendererSpecificRootPage +import org.jetbrains.dokka.pages.RenderingStrategy +import org.jetbrains.dokka.pages.RootPageNode +import org.jetbrains.dokka.transformers.pages.PageNodeTransformer + +object RootCreator : PageNodeTransformer { + override fun invoke(input: RootPageNode) = + RendererSpecificRootPage("", listOf(input), RenderingStrategy.DoNothing) +} + +object SearchPageInstaller : PageNodeTransformer { + override fun invoke(input: RootPageNode) = input.modified(children = input.children + searchPage) + + private val searchPage = RendererSpecificResourcePage( + name = "Search", + children = emptyList(), + strategy = RenderingStrategy { + buildHtml(it, listOf("styles/style.css", "scripts/pages.js")) { + h1 { + id = "searchTitle" + text("Search results for ") + } + table { + tbody { + id = "searchTable" + } + } + } + }) + +} + +object ResourceInstaller : PageNodeTransformer { + override fun invoke(input: RootPageNode) = input.modified(children = input.children + resourcePages) + + private val resourcePages = listOf("styles", "scripts", "images").map { + RendererSpecificResourcePage(it, emptyList(), RenderingStrategy.Copy("/dokka/$it")) + } +} + +object StyleAndScriptsAppender : PageNodeTransformer { + override fun invoke(input: RootPageNode) = input.transformContentPagesTree { + it.modified( + embeddedResources = it.embeddedResources + listOf( + "styles/style.css", + "scripts/navigationLoader.js" + ) + ) + } +} diff --git a/core/src/main/kotlin/renderers/htmlPreprocessors.kt b/core/src/main/kotlin/renderers/htmlPreprocessors.kt deleted file mode 100644 index a6ad267b..00000000 --- a/core/src/main/kotlin/renderers/htmlPreprocessors.kt +++ /dev/null @@ -1,57 +0,0 @@ -package org.jetbrains.dokka.renderers - -import kotlinx.html.h1 -import kotlinx.html.id -import kotlinx.html.table -import kotlinx.html.tbody -import org.jetbrains.dokka.pages.RendererSpecificResourcePage -import org.jetbrains.dokka.pages.RendererSpecificRootPage -import org.jetbrains.dokka.pages.RenderingStrategy -import org.jetbrains.dokka.pages.RootPageNode -import org.jetbrains.dokka.transformers.pages.PageNodeTransformer - -object RootCreator : PageNodeTransformer { - override fun invoke(input: RootPageNode) = - RendererSpecificRootPage("", listOf(input), RenderingStrategy.DoNothing) -} - -object SearchPageInstaller : PageNodeTransformer { - override fun invoke(input: RootPageNode) = input.modified(children = input.children + searchPage) - - private val searchPage = RendererSpecificResourcePage( - name = "Search", - children = emptyList(), - strategy = RenderingStrategy { - buildHtml(it, listOf("styles/style.css", "scripts/pages.js")) { - h1 { - id = "searchTitle" - text("Search results for ") - } - table { - tbody { - id = "searchTable" - } - } - } - }) - -} - -object ResourceInstaller : PageNodeTransformer { - override fun invoke(input: RootPageNode) = input.modified(children = input.children + resourcePages) - - private val resourcePages = listOf("styles", "scripts", "images").map { - RendererSpecificResourcePage(it, emptyList(), RenderingStrategy.Copy("/dokka/$it")) - } -} - -object StyleAndScriptsAppender : PageNodeTransformer { - override fun invoke(input: RootPageNode) = input.transformContentPagesTree { - it.modified( - embeddedResources = it.embeddedResources + listOf( - "styles/style.css", - "scripts/navigationLoader.js" - ) - ) - } -} -- cgit