diff options
Diffstat (limited to 'core/src/main/kotlin/renderers')
-rw-r--r-- | core/src/main/kotlin/renderers/DefaultRenderer.kt | 1 | ||||
-rw-r--r-- | core/src/main/kotlin/renderers/FileWriter.kt | 34 | ||||
-rw-r--r-- | core/src/main/kotlin/renderers/HtmlRenderer.kt | 167 | ||||
-rw-r--r-- | core/src/main/kotlin/renderers/OutputWriter.kt | 1 |
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 |