diff options
Diffstat (limited to 'core')
-rw-r--r-- | core/build.gradle | 2 | ||||
-rw-r--r-- | core/src/main/kotlin/renderers/DefaultRenderer.kt | 67 | ||||
-rw-r--r-- | core/src/main/kotlin/renderers/HtmlRenderer.kt | 159 |
3 files changed, 133 insertions, 95 deletions
diff --git a/core/build.gradle b/core/build.gradle index f9ab0f37..23e2ff24 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -35,7 +35,7 @@ dependencies { compile "org.jetbrains:markdown:$markdownVersion" - compile 'org.jetbrains.kotlinx:kotlinx-html-jvm:0.6.8' + compile 'org.jetbrains.kotlinx:kotlinx-html-jvm:0.6.10' //tools.jar // def toolsJar = files(((URLClassLoader) ToolProvider.getSystemToolClassLoader()).getURLs().findAll { it.path.endsWith("jar") }) diff --git a/core/src/main/kotlin/renderers/DefaultRenderer.kt b/core/src/main/kotlin/renderers/DefaultRenderer.kt index ae065305..e2ebf8b3 100644 --- a/core/src/main/kotlin/renderers/DefaultRenderer.kt +++ b/core/src/main/kotlin/renderers/DefaultRenderer.kt @@ -4,62 +4,67 @@ import org.jetbrains.dokka.pages.* import org.jetbrains.dokka.plugability.DokkaContext import org.jetbrains.dokka.resolvers.LocationProvider -abstract class DefaultRenderer( +abstract class DefaultRenderer<T>( protected val fileWriter: FileWriter, protected val locationProvider: LocationProvider, protected val context: DokkaContext ) : Renderer { - protected abstract fun buildHeader(level: Int, text: String): String - protected abstract fun buildLink(text: String, address: String): String - protected abstract fun buildList(node: ContentList, pageContext: PageNode): String - protected abstract fun buildNewLine(): String - protected abstract fun buildResource(node: ContentEmbeddedResource, pageContext: PageNode): String - protected abstract fun buildTable(node: ContentTable, pageContext: PageNode): String + protected abstract fun T.buildHeader(level: Int, content: T.() -> Unit) + protected abstract fun T.buildLink(address: String, content: T.() -> Unit) + protected abstract fun T.buildList(node: ContentList, pageContext: PageNode) + protected abstract fun T.buildNewLine() + protected abstract fun T.buildResource(node: ContentEmbeddedResource, pageContext: PageNode) + protected abstract fun T.buildTable(node: ContentTable, pageContext: PageNode) + protected abstract fun T.buildText(textNode: ContentText) + protected abstract fun T.buildNavigation(page: PageNode) - protected open fun buildText(textNode: ContentText): String = textNode.text + protected abstract fun buildPage(page: PageNode, content: (T, PageNode) -> Unit): String + protected abstract fun buildError(node: ContentNode) - protected open fun buildGroup(node: ContentGroup, pageContext: PageNode): String = node.children.joinToString("") { it.build(pageContext) } - - protected open fun buildLinkText(nodes: List<ContentNode>, pageContext: PageNode): String = - nodes.joinToString(" ") { it.build(pageContext) } + protected open fun T.buildGroup(node: ContentGroup, pageContext: PageNode){ + node.children.forEach { it.build(this, pageContext) } + } - protected open fun buildCode(code: List<ContentNode>, language: String, pageContext: PageNode): String = - code.joinToString { it.build(pageContext) } + protected open fun T.buildLinkText(nodes: List<ContentNode>, pageContext: PageNode) { + nodes.forEach { it.build(this, pageContext) } + } - protected open fun buildHeader(node: ContentHeader, pageContext: PageNode): String = - buildHeader(node.level, node.children.joinToString { it.build(pageContext) }) + protected open fun T.buildCode(code: List<ContentNode>, language: String, pageContext: PageNode) { + code.forEach { it.build(this, pageContext) } + } - protected open fun buildNavigation(page: PageNode): String = - locationProvider.ancestors(page).fold("") { acc, node -> "$acc/${buildLink( - node.name, - locationProvider.resolve(node, page) - )}" } + protected open fun T.buildHeader(node: ContentHeader, pageContext: PageNode) { + buildHeader(node.level) { node.children.forEach { it.build(this, pageContext) } } + } - protected open fun ContentNode.build(pageContext: PageNode): String = buildContentNode(this, pageContext) + protected open fun ContentNode.build(builder: T, pageContext: PageNode) = builder.buildContentNode(this, pageContext) - protected open fun buildContentNode(node: ContentNode, pageContext: PageNode): String = + protected open fun T.buildContentNode(node: ContentNode, pageContext: PageNode) { when (node) { is ContentText -> buildText(node) is ContentHeader -> buildHeader(node, pageContext) is ContentCode -> buildCode(node.children, node.language, pageContext) is ContentDRILink -> buildLink( - buildLinkText(node.children, pageContext), - locationProvider.resolve(node.address, node.platforms.toList(), pageContext) - ) - is ContentResolvedLink -> buildLink(buildLinkText(node.children, pageContext), node.address) + locationProvider.resolve(node.address, node.platforms.toList(), pageContext)) { + buildLinkText(node.children, pageContext) + } + is ContentResolvedLink -> buildLink(node.address) {buildLinkText(node.children, pageContext)} is ContentEmbeddedResource -> buildResource(node, pageContext) is ContentList -> buildList(node, pageContext) is ContentTable -> buildTable(node, pageContext) is ContentGroup -> buildGroup(node, pageContext) - else -> "".also { println("Unrecognized ContentNode: $node") } + else -> buildError(node) } + } - protected open fun buildPageContent(page: PageNode): String = - buildNavigation(page) + page.content.build(page) + protected open fun buildPageContent(context: T, page: PageNode) { + context.buildNavigation(page) + page.content.build(context, page) + } protected open fun renderPage(page: PageNode) = - fileWriter.write(locationProvider.resolve(page), buildPageContent(page), "") + fileWriter.write(locationProvider.resolve(page), buildPage(page, ::buildPageContent), "") protected open fun renderPages(root: PageNode) { renderPage(root) diff --git a/core/src/main/kotlin/renderers/HtmlRenderer.kt b/core/src/main/kotlin/renderers/HtmlRenderer.kt index 961e942c..2c450ae5 100644 --- a/core/src/main/kotlin/renderers/HtmlRenderer.kt +++ b/core/src/main/kotlin/renderers/HtmlRenderer.kt @@ -1,6 +1,7 @@ package org.jetbrains.dokka.renderers -import org.jetbrains.dokka.utilities.htmlEscape +import kotlinx.html.* +import kotlinx.html.stream.appendHTML import org.jetbrains.dokka.pages.* import org.jetbrains.dokka.plugability.DokkaContext import org.jetbrains.dokka.resolvers.LocationProvider @@ -11,71 +12,112 @@ open class HtmlRenderer( fileWriter: FileWriter, locationProvider: LocationProvider, context: DokkaContext -) : DefaultRenderer(fileWriter, locationProvider, context) { +) : DefaultRenderer<FlowContent>(fileWriter, locationProvider, context) { - override fun buildList(node: ContentList, pageContext: PageNode): String = if (node.ordered) { - "<ol>${buildListItems(node.children, pageContext)}</ol>" - } else { - "<ul>${buildListItems(node.children, pageContext)}</ul>" + override fun FlowContent.buildList(node: ContentList, pageContext: PageNode) = + if (node.ordered) ol { + buildListItems(node.children, pageContext) + } + else ul { + buildListItems(node.children, pageContext) + } + + protected open fun OL.buildListItems(items: List<ContentNode>, pageContext: PageNode) { + items.forEach { + if (it is ContentText) + li { it.build(this, pageContext) } + else buildList(it as ContentList, pageContext) + } } - protected open fun buildListItems(items: List<ContentNode>, pageContext: PageNode) = - items.joinToString("") { - if (it is ContentList) buildList( - it, - pageContext - ) else "<li>\n${it.build(pageContext)}\n</li>\n" + protected open fun UL.buildListItems(items: List<ContentNode>, pageContext: PageNode) { + items.forEach { + if (it is ContentText) + li { it.build(this, pageContext) } + else buildList(it as ContentList, pageContext) } + } - override fun buildResource( + override fun FlowContent.buildResource( node: ContentEmbeddedResource, pageContext: PageNode - ): String { // TODO: extension point there + ) { // 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}" $imgAttrs>""" + img(src = node.address, alt = node.altText) } else { println("Unrecognized resource type: $node") - "" } } - override fun buildTable(node: ContentTable, pageContext: PageNode): String { - val tableHeader = - """<thead> - |<tr> - |<th> ${node.header.joinToString("<th>\n</tr>\n<tr>\n<th>") { it.build(pageContext) }} </th> - |</tr> - |</thead>""".trimMargin() - - return """<table> - |$tableHeader - |<tbody> - |<tr> - |<td>${node.children.joinToString("</td>\n</tr>\n<tr>\n<td>\n") { it.buildTableRow(pageContext) }}</td> - |</tr> - |</tbody> - |</table>""".trimMargin() + override fun FlowContent.buildTable(node: ContentTable, pageContext: PageNode) { + 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) + } + } + } + } + } + } } - protected open fun ContentGroup.buildTableRow(pageContext: PageNode) = - children.joinToString("</td>\n<td>\n") { it.build(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 buildHeader(level: Int, text: String): String = "<h$level>$text</h$level>\n" + override fun FlowContent.buildNavigation(page: PageNode) { + locationProvider.ancestors(page).forEach { node -> + text("/") + buildLink(locationProvider.resolve(node, page)) { + text(node.name) + } + } + } - override fun buildNewLine(): String = "<br/>" + override fun buildError(node: ContentNode) { + context.logger.error("Unknown ContentNode type: $node") + } - override fun buildLink(text: String, address: String): String = "<a href=\"$address\">$text</a>" + override fun FlowContent.buildNewLine() { br() } - override fun buildCode(code: List<ContentNode>, language: String, pageContext: PageNode): String = - buildNewLine() + "<code>${code.joinToString("") { (it as ContentText).text + buildNewLine() }}</code>" + override fun FlowContent.buildLink(address: String, content: FlowContent.() -> Unit) { + a (href = address, block = content) + } - override fun buildText(textNode: ContentText): String = super.buildText(textNode).htmlEscape() + override fun FlowContent.buildCode(code: List<ContentNode>, language: String, pageContext: PageNode) { + buildNewLine() + code.forEach { + + (it as ContentText).text + buildNewLine() + } + } - override fun renderPage(page: PageNode) { - val pageText = buildStartHtml(page) + buildPageContent(page) + buildEndHtml() - fileWriter.write(locationProvider.resolve(page), pageText, "") + override fun FlowContent.buildText(textNode: ContentText) { + text(textNode.text) } override fun buildSupportFiles() { // TODO copy file instead of reading @@ -85,26 +127,17 @@ open class HtmlRenderer( ) } - protected open fun buildScripts(page: PageNode) = - page.embeddedResources.filter { URL(it).path.substringAfterLast('.') == "js" } - .joinToString(separator = "") { """<script type = "text/javascript" async src = "$it"></script>""" + "\n" } - - protected open fun buildStartHtml(page: PageNode) = """<!DOCTYPE html> - |<html> - |<head> - |<title>${page.name}</title> - |<link rel="stylesheet" href="${locationProvider.resolveRoot(page)}style.css" /> - |${buildScripts(page)} - |</head> - |<body> - |""".trimMargin() - - protected open fun buildEndHtml() = - """ - | - |</body> - |</html> - """.trimMargin() + override fun buildPage(page: PageNode, content: (FlowContent, PageNode) -> Unit): String = StringBuilder().appendHTML().html { + head { + title(page.name) + link(rel = LinkRel.stylesheet, href = "${locationProvider.resolveRoot(page)}style.css") + page.embeddedResources.filter { URL(it).path.substringAfterLast('.') == "js" } + .forEach { script(type = ScriptType.textJavaScript, src = it) { async = true } } + } + body { + content(this, page) + } + }.toString() protected open fun List<HTMLMetadata>.joinAttr() = this.joinToString(" ") { it.key + "=" + it.value } }
\ No newline at end of file |