Skip to content

Commit

Permalink
Fix HTML head and favicon in multi-module projects (#2365)
Browse files Browse the repository at this point in the history
  • Loading branch information
vmishenev committed Feb 22, 2022
1 parent c44bf54 commit b9b1b58
Show file tree
Hide file tree
Showing 18 changed files with 208 additions and 60 deletions.
2 changes: 2 additions & 0 deletions plugins/all-modules-page/api/all-modules-page.api
Expand Up @@ -83,5 +83,7 @@ public final class org/jetbrains/dokka/allModulesPage/ResolveLinkCommandHandler
public fun canHandle (Lorg/jetbrains/dokka/base/templating/Command;)Z
public fun finish (Ljava/io/File;)V
public fun handleCommand (Lorg/jsoup/nodes/Element;Lorg/jetbrains/dokka/base/templating/Command;Ljava/io/File;Ljava/io/File;)V
public fun handleCommandAsComment (Lorg/jetbrains/dokka/base/templating/Command;Ljava/util/List;Ljava/io/File;Ljava/io/File;)V
public fun handleCommandAsTag (Lorg/jetbrains/dokka/base/templating/Command;Lorg/jsoup/nodes/Element;Ljava/io/File;Ljava/io/File;)V
}

Expand Up @@ -16,29 +16,29 @@ class ResolveLinkCommandHandler(context: DokkaContext) : CommandHandler {
private val externalModuleLinkResolver =
context.plugin<AllModulesPagePlugin>().querySingle { externalModuleLinkResolver }

override fun handleCommand(element: Element, command: Command, input: File, output: File) {
override fun handleCommandAsTag(command: Command, body: Element, input: File, output: File) {
command as ResolveLinkCommand
val link = externalModuleLinkResolver.resolve(command.dri, output)
if (link == null) {
val children = element.childNodes().toList()
val children = body.childNodes().toList()
val attributes = Attributes().apply {
put("data-unresolved-link", command.dri.toString())
}
val el = Element(Tag.valueOf("span"), "", attributes).apply {
children.forEach { ch -> appendChild(ch) }
}
element.replaceWith(el)
body.replaceWith(el)
return
}

val attributes = Attributes().apply {
put("href", link)
}
val children = element.childNodes().toList()
val children = body.childNodes().toList()
val el = Element(Tag.valueOf("a"), "", attributes).apply {
children.forEach { ch -> appendChild(ch) }
}
element.replaceWith(el)
body.replaceWith(el)
}

override fun canHandle(command: Command): Boolean = command is ResolveLinkCommand
Expand Down
5 changes: 5 additions & 0 deletions plugins/base/api/base.api
Expand Up @@ -516,13 +516,18 @@ public final class org/jetbrains/dokka/base/renderers/html/StylesInstaller : org
}

public final class org/jetbrains/dokka/base/renderers/html/TagsKt {
public static final field TEMPLATE_COMMAND_BEGIN_BORDER Ljava/lang/String;
public static final field TEMPLATE_COMMAND_END_BORDER Ljava/lang/String;
public static final field TEMPLATE_COMMAND_SEPARATOR Ljava/lang/String;
public static final fun buildAsInnerHtml (Lkotlin/jvm/functions/Function1;)Ljava/lang/String;
public static final fun strike (Lkotlinx/html/FlowOrPhrasingContent;Ljava/lang/String;Lkotlin/jvm/functions/Function1;)V
public static synthetic fun strike$default (Lkotlinx/html/FlowOrPhrasingContent;Ljava/lang/String;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
public static final fun templateCommand (Lkotlinx/html/FlowOrMetaDataContent;Lorg/jetbrains/dokka/base/templating/Command;Lkotlin/jvm/functions/Function1;)V
public static final fun templateCommand (Lkotlinx/html/TagConsumer;Lorg/jetbrains/dokka/base/templating/Command;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static synthetic fun templateCommand$default (Lkotlinx/html/FlowOrMetaDataContent;Lorg/jetbrains/dokka/base/templating/Command;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
public static synthetic fun templateCommand$default (Lkotlinx/html/TagConsumer;Lorg/jetbrains/dokka/base/templating/Command;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ljava/lang/Object;
public static final fun templateCommandAsHtmlComment (Lkotlinx/html/FlowOrMetaDataContent;Lorg/jetbrains/dokka/base/templating/Command;Lkotlin/jvm/functions/Function1;)V
public static synthetic fun templateCommandAsHtmlComment$default (Lkotlinx/html/FlowOrMetaDataContent;Lorg/jetbrains/dokka/base/templating/Command;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
public static final fun templateCommandFor (Lorg/jetbrains/dokka/base/templating/Command;Lkotlinx/html/TagConsumer;)Lorg/jetbrains/dokka/base/renderers/html/TemplateCommand;
public static final fun wbr (Lkotlinx/html/FlowOrPhrasingContent;Ljava/lang/String;Lkotlin/jvm/functions/Function1;)V
public static synthetic fun wbr$default (Lkotlinx/html/FlowOrPhrasingContent;Ljava/lang/String;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
Expand Down
22 changes: 12 additions & 10 deletions plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt
Expand Up @@ -23,6 +23,8 @@ import org.jetbrains.dokka.utilities.htmlEscape
import org.jetbrains.kotlin.utils.addIfNotNull
import java.net.URI

internal const val TEMPLATE_REPLACEMENT: String = "###"

open class HtmlRenderer(
context: DokkaContext
) : DefaultRenderer<FlowContent>(context) {
Expand Down Expand Up @@ -779,11 +781,11 @@ open class HtmlRenderer(
head {
meta(name = "viewport", content = "width=device-width, initial-scale=1", charset = "UTF-8")
title(page.name)
templateCommand(PathToRootSubstitutionCommand("###", default = pathToRoot)) {
link(href = "###images/logo-icon.svg", rel = "icon", type = "image/svg")
templateCommandAsHtmlComment(PathToRootSubstitutionCommand(TEMPLATE_REPLACEMENT, default = pathToRoot)) {
link(href = "${TEMPLATE_REPLACEMENT}images/logo-icon.svg", rel = "icon", type = "image/svg")
}
templateCommand(PathToRootSubstitutionCommand("###", default = pathToRoot)) {
script { unsafe { +"""var pathToRoot = "###";""" } }
templateCommandAsHtmlComment(PathToRootSubstitutionCommand(TEMPLATE_REPLACEMENT, default = pathToRoot)) {
script { unsafe { +"""var pathToRoot = "$TEMPLATE_REPLACEMENT";""" } }
}
// This script doesn't need to be there but it is nice to have since app in dark mode doesn't 'blink' (class is added before it is rendered)
script {
Expand All @@ -804,10 +806,10 @@ open class HtmlRenderer(
rel = LinkRel.stylesheet,
href = it
)
else templateCommand(PathToRootSubstitutionCommand("###", default = pathToRoot)) {
else templateCommandAsHtmlComment(PathToRootSubstitutionCommand(TEMPLATE_REPLACEMENT, default = pathToRoot)) {
link(
rel = LinkRel.stylesheet,
href = "###$it"
href = TEMPLATE_REPLACEMENT + it
)
}
it.substringBefore('?').substringAfterLast('.') == "js" ->
Expand All @@ -816,10 +818,10 @@ open class HtmlRenderer(
src = it
) {
async = true
} else templateCommand(PathToRootSubstitutionCommand("###", default = pathToRoot)) {
} else templateCommandAsHtmlComment(PathToRootSubstitutionCommand(TEMPLATE_REPLACEMENT, default = pathToRoot)) {
script(
type = ScriptType.textJavaScript,
src = "###$it"
src = TEMPLATE_REPLACEMENT + it
) {
if (it == "scripts/main.js")
defer = true
Expand All @@ -828,8 +830,8 @@ open class HtmlRenderer(
}
}
it.isImage() -> if (it.isAbsolute) link(href = it)
else templateCommand(PathToRootSubstitutionCommand("###", default = pathToRoot)) {
link(href = "###$it")
else templateCommandAsHtmlComment(PathToRootSubstitutionCommand(TEMPLATE_REPLACEMENT, default = pathToRoot)) {
link(href = TEMPLATE_REPLACEMENT + it)
}
else -> unsafe { +it }
}
Expand Down
12 changes: 12 additions & 0 deletions plugins/base/src/main/kotlin/renderers/html/Tags.kt
Expand Up @@ -26,6 +26,18 @@ inline fun FlowOrPhrasingContent.strike(classes : String? = null, crossinline bl
open class STRIKE(initialAttributes: Map<String, String>, override val consumer: TagConsumer<*>) :
HTMLTag("strike", consumer, initialAttributes, null, false, false), HtmlBlockInlineTag

const val TEMPLATE_COMMAND_SEPARATOR = ":"
const val TEMPLATE_COMMAND_BEGIN_BORDER = "[+]cmd"
const val TEMPLATE_COMMAND_END_BORDER = "[-]cmd"

fun FlowOrMetaDataContent.templateCommandAsHtmlComment(data: Command, block: FlowOrMetaDataContent.() -> Unit = {}): Unit =
(consumer as? ImmediateResolutionTagConsumer)?.processCommand(data, block)
?: let{
comment( "$TEMPLATE_COMMAND_BEGIN_BORDER$TEMPLATE_COMMAND_SEPARATOR${toJsonString(data)}")
block()
comment(TEMPLATE_COMMAND_END_BORDER)
}

fun FlowOrMetaDataContent.templateCommand(data: Command, block: TemplateBlock = {}): Unit =
(consumer as? ImmediateResolutionTagConsumer)?.processCommand(data, block)
?: TemplateCommand(attributesMapOf("data", toJsonString(data)), consumer).visit(block)
Expand Down
Expand Up @@ -19,7 +19,7 @@ class ReplaceVersionsConsumer(private val context: DokkaContext) : ImmediateHtml
}

override fun <R> processCommandAndFinalize(command: Command, block: TemplateBlock, tagConsumer: ImmediateResolutionTagConsumer<R>): R {
PathToRootConsumer.processCommand(command, block, tagConsumer)
processCommand(command, block, tagConsumer)
return tagConsumer.finalize()
}
}
Expand Up @@ -4,10 +4,11 @@ import org.jetbrains.dokka.DokkaConfiguration
import org.jetbrains.dokka.PluginConfigurationImpl
import org.jetbrains.dokka.base.DokkaBase
import org.jetbrains.dokka.base.DokkaBaseConfiguration
import org.jetbrains.dokka.base.renderers.html.TEMPLATE_REPLACEMENT
import org.jetbrains.dokka.base.templating.toJsonString
import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest
import org.jetbrains.dokka.pages.RootPageNode
import org.jetbrains.dokka.plugability.DokkaPlugin
import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest
import org.jetbrains.dokka.transformers.pages.PageTransformer
import org.jsoup.Jsoup
import org.junit.jupiter.api.Test
Expand Down Expand Up @@ -125,11 +126,11 @@ class ResourceLinksTest : BaseAbstractTest() {
if (isMultiModule) {
Jsoup
.parse(writerPlugin.writer.contents["example.html"])
.body()
.head()
.select("link, script")
.let {
listOf("styles/customStyle.css").forEach { r ->
assert(it.`is`("[href=###$r]"))
assert(it.`is`("[href=$TEMPLATE_REPLACEMENT$r]"))
}
}
} else {
Expand Down
24 changes: 18 additions & 6 deletions plugins/templating/api/templating.api
Expand Up @@ -28,16 +28,23 @@ public final class org/jetbrains/dokka/templates/AddToNavigationCommandHandler :
public fun finish (Ljava/io/File;)V
public final fun getContext ()Lorg/jetbrains/dokka/plugability/DokkaContext;
public fun handleCommand (Lorg/jsoup/nodes/Element;Lorg/jetbrains/dokka/base/templating/Command;Ljava/io/File;Ljava/io/File;)V
public fun handleCommandAsComment (Lorg/jetbrains/dokka/base/templating/Command;Ljava/util/List;Ljava/io/File;Ljava/io/File;)V
public fun handleCommandAsTag (Lorg/jetbrains/dokka/base/templating/Command;Lorg/jsoup/nodes/Element;Ljava/io/File;Ljava/io/File;)V
}

public abstract interface class org/jetbrains/dokka/templates/CommandHandler {
public abstract fun canHandle (Lorg/jetbrains/dokka/base/templating/Command;)Z
public abstract fun finish (Ljava/io/File;)V
public abstract fun handleCommand (Lorg/jsoup/nodes/Element;Lorg/jetbrains/dokka/base/templating/Command;Ljava/io/File;Ljava/io/File;)V
public abstract fun handleCommandAsComment (Lorg/jetbrains/dokka/base/templating/Command;Ljava/util/List;Ljava/io/File;Ljava/io/File;)V
public abstract fun handleCommandAsTag (Lorg/jetbrains/dokka/base/templating/Command;Lorg/jsoup/nodes/Element;Ljava/io/File;Ljava/io/File;)V
}

public final class org/jetbrains/dokka/templates/CommandHandler$DefaultImpls {
public static fun finish (Lorg/jetbrains/dokka/templates/CommandHandler;Ljava/io/File;)V
public static fun handleCommand (Lorg/jetbrains/dokka/templates/CommandHandler;Lorg/jsoup/nodes/Element;Lorg/jetbrains/dokka/base/templating/Command;Ljava/io/File;Ljava/io/File;)V
public static fun handleCommandAsComment (Lorg/jetbrains/dokka/templates/CommandHandler;Lorg/jetbrains/dokka/base/templating/Command;Ljava/util/List;Ljava/io/File;Ljava/io/File;)V
public static fun handleCommandAsTag (Lorg/jetbrains/dokka/templates/CommandHandler;Lorg/jetbrains/dokka/base/templating/Command;Lorg/jsoup/nodes/Element;Ljava/io/File;Ljava/io/File;)V
}

public final class org/jetbrains/dokka/templates/DefaultMultiModuleTemplateProcessor : org/jetbrains/dokka/templates/MultiModuleTemplateProcessor {
Expand All @@ -54,7 +61,8 @@ public final class org/jetbrains/dokka/templates/DefaultSubmoduleTemplateProcess
public final class org/jetbrains/dokka/templates/DirectiveBasedHtmlTemplateProcessingStrategy : org/jetbrains/dokka/templates/TemplateProcessingStrategy {
public fun <init> (Lorg/jetbrains/dokka/plugability/DokkaContext;)V
public fun finish (Ljava/io/File;)V
public final fun handleCommand (Lorg/jsoup/nodes/Element;Lorg/jetbrains/dokka/base/templating/Command;Ljava/io/File;Ljava/io/File;)V
public final fun handleCommandAsComment (Lorg/jetbrains/dokka/base/templating/Command;Ljava/util/List;Ljava/io/File;Ljava/io/File;)V
public final fun handleCommandAsTag (Lorg/jsoup/nodes/Element;Lorg/jetbrains/dokka/base/templating/Command;Ljava/io/File;Ljava/io/File;)V
public fun process (Ljava/io/File;Ljava/io/File;Lorg/jetbrains/dokka/DokkaConfiguration$DokkaModuleDescription;)Z
}

Expand Down Expand Up @@ -82,6 +90,8 @@ public final class org/jetbrains/dokka/templates/SubstitutionCommandHandler : or
public fun canHandle (Lorg/jetbrains/dokka/base/templating/Command;)Z
public fun finish (Ljava/io/File;)V
public fun handleCommand (Lorg/jsoup/nodes/Element;Lorg/jetbrains/dokka/base/templating/Command;Ljava/io/File;Ljava/io/File;)V
public fun handleCommandAsComment (Lorg/jetbrains/dokka/base/templating/Command;Ljava/util/List;Ljava/io/File;Ljava/io/File;)V
public fun handleCommandAsTag (Lorg/jetbrains/dokka/base/templating/Command;Lorg/jsoup/nodes/Element;Ljava/io/File;Ljava/io/File;)V
}

public abstract interface class org/jetbrains/dokka/templates/Substitutor {
Expand All @@ -101,16 +111,16 @@ public abstract interface class org/jetbrains/dokka/templates/TemplateProcessor
}

public final class org/jetbrains/dokka/templates/TemplatingContext {
public fun <init> (Ljava/io/File;Ljava/io/File;Lorg/jsoup/nodes/Element;Lorg/jetbrains/dokka/base/templating/Command;)V
public fun <init> (Ljava/io/File;Ljava/io/File;Ljava/util/List;Lorg/jetbrains/dokka/base/templating/Command;)V
public final fun component1 ()Ljava/io/File;
public final fun component2 ()Ljava/io/File;
public final fun component3 ()Lorg/jsoup/nodes/Element;
public final fun component3 ()Ljava/util/List;
public final fun component4 ()Lorg/jetbrains/dokka/base/templating/Command;
public final fun copy (Ljava/io/File;Ljava/io/File;Lorg/jsoup/nodes/Element;Lorg/jetbrains/dokka/base/templating/Command;)Lorg/jetbrains/dokka/templates/TemplatingContext;
public static synthetic fun copy$default (Lorg/jetbrains/dokka/templates/TemplatingContext;Ljava/io/File;Ljava/io/File;Lorg/jsoup/nodes/Element;Lorg/jetbrains/dokka/base/templating/Command;ILjava/lang/Object;)Lorg/jetbrains/dokka/templates/TemplatingContext;
public final fun copy (Ljava/io/File;Ljava/io/File;Ljava/util/List;Lorg/jetbrains/dokka/base/templating/Command;)Lorg/jetbrains/dokka/templates/TemplatingContext;
public static synthetic fun copy$default (Lorg/jetbrains/dokka/templates/TemplatingContext;Ljava/io/File;Ljava/io/File;Ljava/util/List;Lorg/jetbrains/dokka/base/templating/Command;ILjava/lang/Object;)Lorg/jetbrains/dokka/templates/TemplatingContext;
public fun equals (Ljava/lang/Object;)Z
public final fun getBody ()Ljava/util/List;
public final fun getCommand ()Lorg/jetbrains/dokka/base/templating/Command;
public final fun getElement ()Lorg/jsoup/nodes/Element;
public final fun getInput ()Ljava/io/File;
public final fun getOutput ()Ljava/io/File;
public fun hashCode ()I
Expand Down Expand Up @@ -162,6 +172,8 @@ public final class templates/ReplaceVersionCommandHandler : org/jetbrains/dokka/
public fun canHandle (Lorg/jetbrains/dokka/base/templating/Command;)Z
public fun finish (Ljava/io/File;)V
public fun handleCommand (Lorg/jsoup/nodes/Element;Lorg/jetbrains/dokka/base/templating/Command;Ljava/io/File;Ljava/io/File;)V
public fun handleCommandAsComment (Lorg/jetbrains/dokka/base/templating/Command;Ljava/util/List;Ljava/io/File;Ljava/io/File;)V
public fun handleCommandAsTag (Lorg/jetbrains/dokka/base/templating/Command;Lorg/jsoup/nodes/Element;Ljava/io/File;Ljava/io/File;)V
}

public final class templates/SourcesetDependencyProcessingStrategy : org/jetbrains/dokka/templates/TemplateProcessingStrategy {
Expand Down
Expand Up @@ -13,12 +13,12 @@ import java.util.concurrent.ConcurrentHashMap
class AddToNavigationCommandHandler(val context: DokkaContext) : CommandHandler {
private val navigationFragments = ConcurrentHashMap<String, Element>()

override fun handleCommand(element: Element, command: Command, input: File, output: File) {
override fun handleCommandAsTag(command: Command, body: Element, input: File, output: File) {
command as AddToNavigationCommand
context.configuration.modules.find { it.name == command.moduleName }
?.relativePathToOutputDirectory
?.relativeToOrSelf(context.configuration.outputDir)
?.let { key -> navigationFragments[key.toString()] = element }
?.let { key -> navigationFragments[key.toString()] = body }
}

override fun canHandle(command: Command) = command is AddToNavigationCommand
Expand Down
12 changes: 10 additions & 2 deletions plugins/templating/src/main/kotlin/templates/CommandHandler.kt
Expand Up @@ -2,10 +2,18 @@ package org.jetbrains.dokka.templates

import org.jetbrains.dokka.base.templating.Command
import org.jsoup.nodes.Element
import org.jsoup.nodes.Node
import java.io.File

interface CommandHandler {
fun handleCommand(element: Element, command: Command, input: File, output: File)

interface CommandHandler {
@Deprecated("This was renamed to handleCommandAsTag", ReplaceWith("handleCommandAsTag(command, element, input, output)"))
fun handleCommand(element: Element, command: Command, input: File, output: File) { }

@Suppress("DEPRECATION")
fun handleCommandAsTag(command: Command, body: Element, input: File, output: File) =
handleCommand(body, command, input, output)
fun handleCommandAsComment(command: Command, body: List<Node>, input: File, output: File) { }
fun canHandle(command: Command): Boolean
fun finish(output: File) {}
}

0 comments on commit b9b1b58

Please sign in to comment.