aboutsummaryrefslogtreecommitdiff
path: root/core/src/main/kotlin/renderers
diff options
context:
space:
mode:
Diffstat (limited to 'core/src/main/kotlin/renderers')
-rw-r--r--core/src/main/kotlin/renderers/DefaultRenderer.kt1
-rw-r--r--core/src/main/kotlin/renderers/FileWriter.kt34
-rw-r--r--core/src/main/kotlin/renderers/HtmlRenderer.kt167
-rw-r--r--core/src/main/kotlin/renderers/OutputWriter.kt1
4 files changed, 180 insertions, 23 deletions
diff --git a/core/src/main/kotlin/renderers/DefaultRenderer.kt b/core/src/main/kotlin/renderers/DefaultRenderer.kt
index 1152bcc5..5e3eadbe 100644
--- a/core/src/main/kotlin/renderers/DefaultRenderer.kt
+++ b/core/src/main/kotlin/renderers/DefaultRenderer.kt
@@ -6,7 +6,6 @@ import org.jetbrains.dokka.plugability.DokkaContext
import org.jetbrains.dokka.plugability.single
import org.jetbrains.dokka.resolvers.LocationProvider
-
abstract class DefaultRenderer<T>(
protected val outputWriter: OutputWriter,
protected val context: DokkaContext
diff --git a/core/src/main/kotlin/renderers/FileWriter.kt b/core/src/main/kotlin/renderers/FileWriter.kt
index 5439db17..22a2e8f9 100644
--- a/core/src/main/kotlin/renderers/FileWriter.kt
+++ b/core/src/main/kotlin/renderers/FileWriter.kt
@@ -1,8 +1,10 @@
package org.jetbrains.dokka.renderers
+import com.intellij.util.io.isDirectory
import java.io.File
import java.io.IOException
-import java.nio.file.Paths
+import java.net.URI
+import java.nio.file.*
class FileWriter(val root: String, override val extension: String): OutputWriter {
private val createdFiles: MutableSet<String> = mutableSetOf()
@@ -19,15 +21,43 @@ class FileWriter(val root: String, override val extension: String): OutputWriter
val dir = Paths.get(root, path.dropLastWhile { it != '/' }).toFile()
dir.mkdirsOrFail()
Paths.get(root, "$path$ext").toFile().writeText(text)
- } catch (e : Throwable) {
+ } catch (e: Throwable) {
println("Failed to write $this. ${e.message}")
e.printStackTrace()
}
}
+ override fun writeResources(pathFrom: String, pathTo: String) {
+ val rebase = fun(path: String) =
+ "$pathTo/${path.removePrefix(pathFrom)}"
+ val dest = Paths.get(root, pathTo).toFile()
+ dest.mkdirsOrFail()
+ val uri = javaClass.getResource(pathFrom).toURI()
+ val fs = getFileSystemForURI(uri)
+ val path = fs.getPath(pathFrom)
+ for (file in Files.walk(path).iterator()) {
+ if (file.isDirectory()) {
+ val dirPath = file.toAbsolutePath().toString()
+ Paths.get(root, rebase(dirPath)).toFile().mkdirsOrFail()
+ } else {
+ val filePath = file.toAbsolutePath().toString()
+ Paths.get(root, rebase(filePath)).toFile().writeBytes(
+ javaClass.getResourceAsStream(filePath).readBytes()
+ )
+ }
+ }
+ }
+
private fun File.mkdirsOrFail() {
if (!mkdirs() && !exists()) {
throw IOException("Failed to create directory $this")
}
}
+
+ private fun getFileSystemForURI(uri: URI): FileSystem =
+ try {
+ FileSystems.newFileSystem(uri, emptyMap<String, Any>())
+ } catch (e: FileSystemAlreadyExistsException) {
+ FileSystems.getFileSystem(uri)
+ }
} \ No newline at end of file
diff --git a/core/src/main/kotlin/renderers/HtmlRenderer.kt b/core/src/main/kotlin/renderers/HtmlRenderer.kt
index 8742f202..ae120795 100644
--- a/core/src/main/kotlin/renderers/HtmlRenderer.kt
+++ b/core/src/main/kotlin/renderers/HtmlRenderer.kt
@@ -1,9 +1,13 @@
package org.jetbrains.dokka.renderers
import kotlinx.html.*
+import kotlinx.html.dom.document
import kotlinx.html.stream.appendHTML
+import org.jetbrains.dokka.links.DRI
+import org.jetbrains.dokka.model.Documentable
import org.jetbrains.dokka.pages.*
import org.jetbrains.dokka.plugability.DokkaContext
+import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty
import java.io.File
import java.net.URL
@@ -12,6 +16,29 @@ open class HtmlRenderer(
context: DokkaContext
) : DefaultRenderer<FlowContent>(outputWriter, context) {
+ private val pageList = mutableListOf<String>()
+
+ private var idCounter = 0
+ get() = ++field
+
+ private fun FlowContent.buildSideMenu(context: PageNode, node: PageNode) {
+ val children = node.children.filter { it !is MemberPageNode }
+ val className = children.ifNotEmpty { "nav$idCounter" }
+ div("sideMenuPart") {
+ className?.let { id = it }
+ div("overview") {
+ buildLink(node, context)
+ className?.let {
+ span("navButton") {
+ onClick = """document.getElementById("$it").classList.toggle("hidden");"""
+ span("navButtonContent")
+ }
+ }
+ }
+ children.forEach { buildSideMenu(context, it) }
+ }
+ }
+
override fun FlowContent.buildList(node: ContentList, pageContext: PageNode) =
if (node.ordered) ol {
buildListItems(node.children, pageContext)
@@ -89,25 +116,28 @@ open class HtmlRenderer(
}
}
- override fun FlowContent.buildNavigation(page: PageNode) {
+ override fun FlowContent.buildNavigation(page: PageNode) =
locationProvider.ancestors(page).forEach { node ->
text("/")
- buildLink(locationProvider.resolve(node, page)) {
- text(node.name)
- }
+ 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.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: PageNode) {
buildNewLine()
code.forEach {
@@ -116,29 +146,126 @@ open class HtmlRenderer(
}
}
+ override fun renderPage(page: PageNode) {
+ super.renderPage(page)
+ 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: PageNode) {
+ super.render(root)
+ outputWriter.write("scripts/pages", "var pages = [\n${pageList.joinToString(",\n")}\n]", ".js")
+ }
override fun buildSupportFiles() { // TODO copy file instead of reading
outputWriter.write(
"style.css",
javaClass.getResourceAsStream("/dokka/styles/style.css").reader().readText()
)
+ renderPage(searchPageNode)
+ outputWriter.writeResources("/dokka/styles", "styles")
+ outputWriter.writeResources("/dokka/scripts", "scripts")
+ outputWriter.writeResources("/dokka/images", "images")
}
- 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()
+ private fun PageNode.root(path: String) =
+ "${if (this != searchPageNode) locationProvider.resolveRoot(this) else ""}$path"
+
+ override fun buildPage(page: PageNode, content: (FlowContent, PageNode) -> Unit): String =
+ StringBuilder().appendHTML().html {
+ document {
+
+ }
+ head {
+ title(page.name)
+ link(rel = LinkRel.stylesheet, href = page.root("styles/style.css"))
+ page.embeddedResources.filter {
+ URL(it).path.substringAfterLast('.') == "js"
+ }.forEach {
+ script(type = ScriptType.textJavaScript, src = it) { async = true }
+ }
+ if (page == searchPageNode) {
+ script(
+ type = ScriptType.textJavaScript,
+ src = page.root("scripts/pages.js")
+ ) { 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"
+ img(src = page.root("images/logo-icon.svg"))
+ img(src = page.root("images/logo-text.svg"))
+ hr()
+ input(type = InputType.search) {
+ id = "navigationFilter"
+ }
+ script(
+ type = ScriptType.textJavaScript,
+ src = page.root("scripts/scripts.js")
+ ) { async = true }
+ buildSideMenu(page, locationProvider.top())
+ }
+ }
+ div {
+ id = "content"
+ if (page != searchPageNode) content(this, page)
+ else {
+ h1 {
+ id = "searchTitle"
+ text("Search results for ")
+ }
+ table {
+ tbody {
+ id = "searchTable"
+ }
+ }
+ script(
+ type = ScriptType.textJavaScript,
+ src = page.root("scripts/search.js")
+ ) { async = true }
+ }
+ }
+ }
+ }.toString()
protected open fun List<HTMLMetadata>.joinAttr() = this.joinToString(" ") { it.key + "=" + it.value }
+
+ private val searchPageNode =
+ object: PageNode {
+ override val name: String
+ get() = "Search"
+ override val content = object: ContentNode{
+ override val dci: DCI = DCI(DRI.topLevel, ContentKind.Main)
+ override val platforms: Set<PlatformData> = emptySet()
+ override val style: Set<Style> = emptySet()
+ override val extras: Set<Extra> = emptySet()
+
+ }
+ override val dri: DRI = DRI.topLevel
+ override val documentable: Documentable? = null
+ override val embeddedResources: List<String> = emptyList()
+ override val children: List<PageNode> = emptyList()
+
+ override fun modified(
+ name: String,
+ content: ContentNode,
+ embeddedResources: List<String>,
+ children: List<PageNode>
+ ): PageNode = this
+
+ }
} \ No newline at end of file
diff --git a/core/src/main/kotlin/renderers/OutputWriter.kt b/core/src/main/kotlin/renderers/OutputWriter.kt
index 84cc124d..8ef7e8b2 100644
--- a/core/src/main/kotlin/renderers/OutputWriter.kt
+++ b/core/src/main/kotlin/renderers/OutputWriter.kt
@@ -3,4 +3,5 @@ package org.jetbrains.dokka.renderers
interface OutputWriter{
val extension: String
fun write(path: String, text: String, ext: String = extension)
+ fun writeResources(pathFrom: String, pathTo: String)
} \ No newline at end of file