Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

KT-50452 Make flexible html for customization #2374

Merged
merged 10 commits into from Mar 10, 2022
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
39 changes: 35 additions & 4 deletions docs/src/doc/docs/user_guide/base-specific/frontend.md
Expand Up @@ -2,12 +2,12 @@

## Prerequisites

Dokka's Html format requires a web server to view documentation correctly.
Dokka's HTML format requires a web server to view documentation correctly.
This can be achieved by using the one that is build in IntelliJ or providing your own.
If this requisite is not fulfilled Dokka with fail to load navigation pane and search bars.

!!! important
Concepts specified below apply only to configuration of the Base Plugin (that contains Html format)
Concepts specified below apply only to configuration of the Base Plugin (that contains HTML format)
vmishenev marked this conversation as resolved.
Show resolved Hide resolved
and needs to be applied via pluginsConfiguration and not on the root one.

## Modifying assets
Expand All @@ -20,19 +20,21 @@ Currently, user can modify:

Every file provided in those values will be applied to **every** page.

Dokka uses 3 stylesheets:
Dokka uses 4 stylesheets:

* `style.css` - main css file responsible for styling the page
* `jetbrains-mono.css` - fonts used across dokka
* `logo-styles.css` - logo styling
* [`prism.css`](https://github.com/Kotlin/dokka/blob/master/plugins/base/src/main/resources/dokka/styles/prism.css) - code highlighting

Also, it uses js scripts. The actual ones are [here](https://github.com/Kotlin/dokka/tree/master/plugins/base/src/main/resources/dokka/scripts).
User can choose to add or override those files.
vmishenev marked this conversation as resolved.
Show resolved Hide resolved
Resources will be overridden when in `pluginConfiguration` block there is a resource with the same name.

## Modifying footer

Dokka supports custom messages in the footer via `footerMessage` string property on base plugin configuration.
Keep in mind that this value will be passed exactly to the output html, so it has to be valid and escaped correctly.
Keep in mind that this value will be passed exactly to the output HTML, so it has to be valid and escaped correctly.

## Separating inherited members

Expand Down Expand Up @@ -69,3 +71,32 @@ In order to override a logo and style it accordingly a css file named `logo-styl


For build system specific instructions please visit dedicated pages: [gradle](../gradle/usage.md#applying-plugins), [maven](../maven/usage.md#applying-plugins) and [cli](../cli/usage.md#configuration-options)

## Custom HTML pages

Dokka uses [FreeMarker](https://freemarker.apache.org/) template engine to render pages.
It takes templates from a folder that is set by a property `templatesDir`.
To custom HTML output user can use a [default template](https://github.com/Kotlin/dokka/blob/master/plugins/base/src/main/resources/dokka/templates) as a basic.

!!! note
To change page assets user can set properties `customAssets` and `customStyleSheets`.
Assets are handled by Dokka.

Currently, there is one template file `base.ftl`. It defines general design of all pages to render.

Variables given below are available to a template:
- `${pageName}` - a page name
- `${footerMessage}` - a text is set by `footerMessage` property
- `${sourceSets}` - a nullable list of source set, only for multi-platform pages. Each source set has `name`, `platfrom` and `filter` properties.

Also, Dokka-defined [directives](https://freemarker.apache.org/docs/ref_directive_userDefined.html) can be used:
- `<@content/>` - a main content
- `<@resources/>` - scripts, stylesheets
- `<@version/>` - version (A version plugin replace this with a version navigator)
- `<@template_cmd name="...""> ...</@template_cmd>` - is used for stuff (`pathToRoot`, `projectName` are `name` parameter, local variables as well) that dependent on a root project. This is processed by a multi-module task that assembles a partial outputs from modules.
Example:
```
<@template_cmd name="projectName">
<span>${projectName}</span>
</@template_cmd>
```
vmishenev marked this conversation as resolved.
Show resolved Hide resolved
1 change: 1 addition & 0 deletions gradle.properties
Expand Up @@ -11,6 +11,7 @@ jsoup_version=1.13.1
idea_version=211.7442.40
language_version=1.4
jackson_version=2.12.4
freemarker_version=2.3.31
# Code style
kotlin.code.style=official
# Gradle settings
Expand Down
81 changes: 77 additions & 4 deletions plugins/base/api/base.api
Expand Up @@ -71,34 +71,38 @@ public final class org/jetbrains/dokka/base/DokkaBaseConfiguration : org/jetbrai
public static final field mergeImplicitExpectActualDeclarationsDefault Z
public static final field separateInheritedMembersDefault Z
public fun <init> ()V
public fun <init> (Ljava/util/List;Ljava/util/List;ZLjava/lang/String;Z)V
public synthetic fun <init> (Ljava/util/List;Ljava/util/List;ZLjava/lang/String;ZILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun <init> (Ljava/util/List;Ljava/util/List;ZLjava/lang/String;ZLjava/io/File;)V
public synthetic fun <init> (Ljava/util/List;Ljava/util/List;ZLjava/lang/String;ZLjava/io/File;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun component1 ()Ljava/util/List;
public final fun component2 ()Ljava/util/List;
public final fun component3 ()Z
public final fun component4 ()Ljava/lang/String;
public final fun component5 ()Z
public final fun copy (Ljava/util/List;Ljava/util/List;ZLjava/lang/String;Z)Lorg/jetbrains/dokka/base/DokkaBaseConfiguration;
public static synthetic fun copy$default (Lorg/jetbrains/dokka/base/DokkaBaseConfiguration;Ljava/util/List;Ljava/util/List;ZLjava/lang/String;ZILjava/lang/Object;)Lorg/jetbrains/dokka/base/DokkaBaseConfiguration;
public final fun component6 ()Ljava/io/File;
public final fun copy (Ljava/util/List;Ljava/util/List;ZLjava/lang/String;ZLjava/io/File;)Lorg/jetbrains/dokka/base/DokkaBaseConfiguration;
public static synthetic fun copy$default (Lorg/jetbrains/dokka/base/DokkaBaseConfiguration;Ljava/util/List;Ljava/util/List;ZLjava/lang/String;ZLjava/io/File;ILjava/lang/Object;)Lorg/jetbrains/dokka/base/DokkaBaseConfiguration;
public fun equals (Ljava/lang/Object;)Z
public final fun getCustomAssets ()Ljava/util/List;
public final fun getCustomStyleSheets ()Ljava/util/List;
public final fun getFooterMessage ()Ljava/lang/String;
public final fun getMergeImplicitExpectActualDeclarations ()Z
public final fun getSeparateInheritedMembers ()Z
public final fun getTemplatesDir ()Ljava/io/File;
public fun hashCode ()I
public final fun setCustomAssets (Ljava/util/List;)V
public final fun setCustomStyleSheets (Ljava/util/List;)V
public final fun setFooterMessage (Ljava/lang/String;)V
public final fun setMergeImplicitExpectActualDeclarations (Z)V
public final fun setSeparateInheritedMembers (Z)V
public final fun setTemplatesDir (Ljava/io/File;)V
public fun toString ()Ljava/lang/String;
}

public final class org/jetbrains/dokka/base/DokkaBaseConfiguration$Companion {
public final fun getDefaultCustomAssets ()Ljava/util/List;
public final fun getDefaultCustomStyleSheets ()Ljava/util/List;
public final fun getDefaultFooterMessage ()Ljava/lang/String;
public final fun getDefaultTemplatesDir ()Ljava/io/File;
}

public final class org/jetbrains/dokka/base/generation/SingleModuleGeneration : org/jetbrains/dokka/generation/Generation {
Expand Down Expand Up @@ -216,6 +220,7 @@ public final class org/jetbrains/dokka/base/parsers/moduleAndPackage/ParseModule
}

public final class org/jetbrains/dokka/base/renderers/ContentTypeCheckingKt {
public static final fun getURIExtension (Ljava/lang/String;)Ljava/lang/String;
public static final fun isImage (Ljava/lang/String;)Z
public static final fun isImage (Lorg/jetbrains/dokka/pages/ContentEmbeddedResource;)Z
}
Expand Down Expand Up @@ -330,6 +335,13 @@ public final class org/jetbrains/dokka/base/renderers/html/CustomResourceInstall
public fun invoke (Lorg/jetbrains/dokka/pages/RootPageNode;)Lorg/jetbrains/dokka/pages/RootPageNode;
}

public final class org/jetbrains/dokka/base/renderers/html/DokkaTemplateTypes : java/lang/Enum {
public static final field BASE Lorg/jetbrains/dokka/base/renderers/html/DokkaTemplateTypes;
public final fun getPath ()Ljava/lang/String;
public static fun valueOf (Ljava/lang/String;)Lorg/jetbrains/dokka/base/renderers/html/DokkaTemplateTypes;
public static fun values ()[Lorg/jetbrains/dokka/base/renderers/html/DokkaTemplateTypes;
}

public final class org/jetbrains/dokka/base/renderers/html/HtmlFormatingUtilsKt {
public static final fun buildBreakableDotSeparatedHtml (Lkotlinx/html/FlowContent;Ljava/lang/String;)V
public static final fun buildBreakableText (Lkotlinx/html/FlowContent;Ljava/lang/String;)V
Expand Down Expand Up @@ -388,6 +400,12 @@ public final class org/jetbrains/dokka/base/renderers/html/HtmlRendererKt {
public static final fun joinAttr (Ljava/util/List;)Ljava/lang/String;
}

public final class org/jetbrains/dokka/base/renderers/html/HtmlTemplater {
public fun <init> (Lorg/jetbrains/dokka/plugability/DokkaContext;)V
public final fun renderFromTemplate (Lorg/jetbrains/dokka/base/renderers/html/DokkaTemplateTypes;Lkotlin/jvm/functions/Function0;)Ljava/lang/String;
public final fun setupSharedModel (Ljava/util/Map;)V
}

public abstract class org/jetbrains/dokka/base/renderers/html/NavigationDataProvider {
public fun <init> ()V
public fun navigableChildren (Lorg/jetbrains/dokka/pages/RootPageNode;)Lorg/jetbrains/dokka/base/renderers/html/NavigationNode;
Expand Down Expand Up @@ -526,6 +544,7 @@ public final class org/jetbrains/dokka/base/renderers/html/TagsKt {
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 (Ljava/lang/Appendable;Lorg/jetbrains/dokka/base/templating/Command;Lkotlin/jvm/functions/Function1;)V
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;
Expand All @@ -537,6 +556,60 @@ public final class org/jetbrains/dokka/base/renderers/html/TemplateCommand : kot
public fun <init> (Ljava/util/Map;Lkotlinx/html/TagConsumer;)V
}

public final class org/jetbrains/dokka/base/renderers/html/TemplateModelFactory {
public fun <init> (Lorg/jetbrains/dokka/plugability/DokkaContext;)V
public final fun buildModel (Lorg/jetbrains/dokka/pages/PageNode;Ljava/util/List;Lorg/jetbrains/dokka/base/resolvers/local/LocationProvider;ZLjava/lang/String;)Ljava/util/Map;
public final fun buildSharedModel ()Ljava/util/Map;
public final fun getContext ()Lorg/jetbrains/dokka/plugability/DokkaContext;
}

public final class org/jetbrains/dokka/base/renderers/html/TemplateModelFactory$PrintDirective : freemarker/template/TemplateDirectiveModel {
public fun <init> (Lkotlin/jvm/functions/Function0;)V
public fun execute (Lfreemarker/core/Environment;Ljava/util/Map;[Lfreemarker/template/TemplateModel;Lfreemarker/template/TemplateDirectiveBody;)V
public final fun getGenerateData ()Lkotlin/jvm/functions/Function0;
}

public final class org/jetbrains/dokka/base/renderers/html/TemplateModelFactory$SourceSetModel {
public fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
public final fun component1 ()Ljava/lang/String;
public final fun component2 ()Ljava/lang/String;
public final fun component3 ()Ljava/lang/String;
public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lorg/jetbrains/dokka/base/renderers/html/TemplateModelFactory$SourceSetModel;
public static synthetic fun copy$default (Lorg/jetbrains/dokka/base/renderers/html/TemplateModelFactory$SourceSetModel;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lorg/jetbrains/dokka/base/renderers/html/TemplateModelFactory$SourceSetModel;
public fun equals (Ljava/lang/Object;)Z
public final fun getFilter ()Ljava/lang/String;
public final fun getName ()Ljava/lang/String;
public final fun getPlatform ()Ljava/lang/String;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}

public final class org/jetbrains/dokka/base/renderers/html/TemplateModelFactory$TemplateDirective : freemarker/template/TemplateDirectiveModel {
public static final field Companion Lorg/jetbrains/dokka/base/renderers/html/TemplateModelFactory$TemplateDirective$Companion;
public static final field PARAM_NAME Ljava/lang/String;
public static final field PARAM_REPLACEMENT Ljava/lang/String;
public fun <init> (Lorg/jetbrains/dokka/DokkaConfiguration;Ljava/lang/String;)V
public fun execute (Lfreemarker/core/Environment;Ljava/util/Map;[Lfreemarker/template/TemplateModel;Lfreemarker/template/TemplateDirectiveBody;)V
public final fun getConfiguration ()Lorg/jetbrains/dokka/DokkaConfiguration;
public final fun getPathToRoot ()Ljava/lang/String;
}

public final class org/jetbrains/dokka/base/renderers/html/TemplateModelFactory$TemplateDirective$Companion {
}

public final class org/jetbrains/dokka/base/renderers/html/TemplateModelFactory$TemplateDirective$Context {
public fun <init> (Lfreemarker/core/Environment;Lfreemarker/template/TemplateDirectiveBody;)V
public final fun component1 ()Lfreemarker/core/Environment;
public final fun component2 ()Lfreemarker/template/TemplateDirectiveBody;
public final fun copy (Lfreemarker/core/Environment;Lfreemarker/template/TemplateDirectiveBody;)Lorg/jetbrains/dokka/base/renderers/html/TemplateModelFactory$TemplateDirective$Context;
public static synthetic fun copy$default (Lorg/jetbrains/dokka/base/renderers/html/TemplateModelFactory$TemplateDirective$Context;Lfreemarker/core/Environment;Lfreemarker/template/TemplateDirectiveBody;ILjava/lang/Object;)Lorg/jetbrains/dokka/base/renderers/html/TemplateModelFactory$TemplateDirective$Context;
public fun equals (Ljava/lang/Object;)Z
public final fun getBody ()Lfreemarker/template/TemplateDirectiveBody;
public final fun getEnv ()Lfreemarker/core/Environment;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}

public class org/jetbrains/dokka/base/renderers/html/WBR : kotlinx/html/HTMLTag, kotlinx/html/HtmlBlockInlineTag {
public fun <init> (Ljava/util/Map;Lkotlinx/html/TagConsumer;)V
}
Expand Down
4 changes: 4 additions & 0 deletions plugins/base/build.gradle.kts
Expand Up @@ -11,6 +11,10 @@ dependencies {

val jackson_version: String by project
implementation("com.fasterxml.jackson.module:jackson-module-kotlin:$jackson_version")

val freemarker_version: String by project
implementation("org.freemarker:freemarker:$freemarker_version")

testImplementation(project(":plugins:base:base-test-utils"))
testImplementation(project(":core:content-matcher-test-utils"))

Expand Down
4 changes: 3 additions & 1 deletion plugins/base/src/main/kotlin/DokkaBaseConfiguration.kt
Expand Up @@ -9,13 +9,15 @@ data class DokkaBaseConfiguration(
var customAssets: List<File> = defaultCustomAssets,
var separateInheritedMembers: Boolean = separateInheritedMembersDefault,
var footerMessage: String = defaultFooterMessage,
var mergeImplicitExpectActualDeclarations: Boolean = mergeImplicitExpectActualDeclarationsDefault
var mergeImplicitExpectActualDeclarations: Boolean = mergeImplicitExpectActualDeclarationsDefault,
var templatesDir: File? = defaultTemplatesDir
) : ConfigurableBlock {
companion object {
val defaultFooterMessage = "© ${Year.now().value} Copyright"
val defaultCustomStyleSheets: List<File> = emptyList()
val defaultCustomAssets: List<File> = emptyList()
const val separateInheritedMembersDefault: Boolean = false
const val mergeImplicitExpectActualDeclarationsDefault: Boolean = false
val defaultTemplatesDir: File? = null
}
}
Expand Up @@ -8,8 +8,11 @@ fun ContentEmbeddedResource.isImage(): Boolean {
return File(address).extension.toLowerCase() in imageExtensions
}

val String.URIExtension: String
get() = substringBefore('?').substringAfterLast('.')

fun String.isImage(): Boolean =
substringBefore('?').substringAfterLast('.') in imageExtensions
URIExtension in imageExtensions

object HtmlFileExtensions {
val imageExtensions = setOf("png", "jpg", "jpeg", "gif", "bmp", "tif", "webp", "svg")
Expand Down