diff options
| author | Ignat Beresnev <ignat.beresnev@jetbrains.com> | 2023-11-10 11:46:54 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-11-10 11:46:54 +0100 |
| commit | 8e5c63d035ef44a269b8c43430f43f5c8eebfb63 (patch) | |
| tree | 1b915207b2b9f61951ddbf0ff2e687efd053d555 /plugins/base/src/main/kotlin/renderers/html | |
| parent | a44efd4ba0c2e4ab921ff75e0f53fc9335aa79db (diff) | |
| download | dokka-8e5c63d035ef44a269b8c43430f43f5c8eebfb63.tar.gz dokka-8e5c63d035ef44a269b8c43430f43f5c8eebfb63.tar.bz2 dokka-8e5c63d035ef44a269b8c43430f43f5c8eebfb63.zip | |
Restructure the project to utilize included builds (#3174)
* Refactor and simplify artifact publishing
* Update Gradle to 8.4
* Refactor and simplify convention plugins and build scripts
Fixes #3132
---------
Co-authored-by: Adam <897017+aSemy@users.noreply.github.com>
Co-authored-by: Oleg Yukhnevich <whyoleg@gmail.com>
Diffstat (limited to 'plugins/base/src/main/kotlin/renderers/html')
18 files changed, 0 insertions, 2253 deletions
diff --git a/plugins/base/src/main/kotlin/renderers/html/HtmlContent.kt b/plugins/base/src/main/kotlin/renderers/html/HtmlContent.kt deleted file mode 100644 index 1ef6e04c..00000000 --- a/plugins/base/src/main/kotlin/renderers/html/HtmlContent.kt +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.base.renderers.html - -import org.jetbrains.dokka.pages.ContentBreakLine -import org.jetbrains.dokka.pages.Style - - -/** - * Html-specific style that represents <hr> tag if used in conjunction with [ContentBreakLine] - */ -internal object HorizontalBreakLineStyle : Style { - // this exists as a simple internal solution to avoid introducing unnecessary public API on content level. - // If you have the need to implement proper horizontal divider (i.e to support `---` markdown element), - // consider removing this and providing proper API for all formats and levels -} diff --git a/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt b/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt deleted file mode 100644 index 083876d5..00000000 --- a/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt +++ /dev/null @@ -1,1013 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.base.renderers.html - -import kotlinx.html.* -import kotlinx.html.stream.createHTML -import org.jetbrains.dokka.DokkaSourceSetID -import org.jetbrains.dokka.Platform -import org.jetbrains.dokka.base.DokkaBase -import org.jetbrains.dokka.base.renderers.* -import org.jetbrains.dokka.base.renderers.html.command.consumers.ImmediateResolutionTagConsumer -import org.jetbrains.dokka.base.renderers.html.innerTemplating.DefaultTemplateModelFactory -import org.jetbrains.dokka.base.renderers.html.innerTemplating.DefaultTemplateModelMerger -import org.jetbrains.dokka.base.renderers.html.innerTemplating.DokkaTemplateTypes -import org.jetbrains.dokka.base.renderers.html.innerTemplating.HtmlTemplater -import org.jetbrains.dokka.base.resolvers.anchors.SymbolAnchorHint -import org.jetbrains.dokka.base.resolvers.local.DokkaBaseLocationProvider -import org.jetbrains.dokka.base.templating.* -import org.jetbrains.dokka.base.transformers.documentables.CallableExtensions -import org.jetbrains.dokka.base.translators.documentables.shouldDocumentConstructors -import org.jetbrains.dokka.links.DRI -import org.jetbrains.dokka.model.* -import org.jetbrains.dokka.model.properties.PropertyContainer -import org.jetbrains.dokka.model.properties.WithExtraProperties -import org.jetbrains.dokka.pages.* -import org.jetbrains.dokka.pages.HtmlContent -import org.jetbrains.dokka.plugability.* -import org.jetbrains.dokka.transformers.pages.PageTransformer -import org.jetbrains.dokka.utilities.htmlEscape - -internal const val TEMPLATE_REPLACEMENT: String = "###" -internal const val TOGGLEABLE_CONTENT_TYPE_ATTR = "data-togglable" - -public open class HtmlRenderer( - context: DokkaContext -) : DefaultRenderer<FlowContent>(context) { - private val sourceSetDependencyMap: Map<DokkaSourceSetID, List<DokkaSourceSetID>> = - context.configuration.sourceSets.associate { sourceSet -> - sourceSet.sourceSetID to context.configuration.sourceSets - .map { it.sourceSetID } - .filter { it in sourceSet.dependentSourceSets } - } - - private val templateModelFactories = listOf(DefaultTemplateModelFactory(context)) // TODO: Make extension point - private val templateModelMerger = DefaultTemplateModelMerger() - private val templater = HtmlTemplater(context).apply { - setupSharedModel(templateModelMerger.invoke(templateModelFactories) { buildSharedModel() }) - } - - private var shouldRenderSourceSetTabs: Boolean = false - - override val preprocessors: List<PageTransformer> = context.plugin<DokkaBase>().query { htmlPreprocessors } - - /** - * Tabs themselves are created in HTML plugin since, currently, only HTML format supports them. - * [TabbedContentType] is used to mark content that should be inside tab content. - * A tab can display multiple [TabbedContentType]. - * The content style [ContentStyle.TabbedContent] is used to determine where tabs will be generated. - * - * @see TabbedContentType - * @see ContentStyle.TabbedContent - */ - private fun createTabs(pageContext: ContentPage): List<ContentTab> { - return when(pageContext) { - is ClasslikePage -> createTabsForClasslikes(pageContext) - is PackagePage -> createTabsForPackage(pageContext) - else -> throw IllegalArgumentException("Page ${pageContext.name} cannot have tabs") - } - } - - private fun createTabsForClasslikes(page: ClasslikePage): List<ContentTab> { - val documentables = page.documentables - val csEnum = documentables.filterIsInstance<DEnum>() - val csWithConstructor = documentables.filterIsInstance<WithConstructors>() - val scopes = documentables.filterIsInstance<WithScope>() - val constructorsToDocumented = csWithConstructor.flatMap { it.constructors } - - val containsRenderableConstructors = constructorsToDocumented.isNotEmpty() && documentables.shouldDocumentConstructors() - val containsRenderableMembers = - containsRenderableConstructors || scopes.any { it.classlikes.isNotEmpty() || it.functions.isNotEmpty() || it.properties.isNotEmpty() } - - @Suppress("UNCHECKED_CAST") - val extensions = (documentables as List<WithExtraProperties<DClasslike>>).flatMap { - it.extra[CallableExtensions]?.extensions - ?.filterIsInstance<Documentable>().orEmpty() - } - .distinctBy { it.sourceSets to it.dri } // [Documentable] has expensive equals/hashCode at the moment, see #2620 - return listOfNotNull( - if(!containsRenderableMembers) null else - ContentTab( - "Members", - listOf( - BasicTabbedContentType.CONSTRUCTOR, - BasicTabbedContentType.TYPE, - BasicTabbedContentType.PROPERTY, - BasicTabbedContentType.FUNCTION - ) - ), - if (extensions.isEmpty()) null else ContentTab( - "Members & Extensions", - listOf( - BasicTabbedContentType.CONSTRUCTOR, - BasicTabbedContentType.TYPE, - BasicTabbedContentType.PROPERTY, - BasicTabbedContentType.FUNCTION, - BasicTabbedContentType.EXTENSION_PROPERTY, - BasicTabbedContentType.EXTENSION_FUNCTION - ) - ), - if(csEnum.isEmpty()) null else ContentTab( - "Entries", - listOf( - BasicTabbedContentType.ENTRY - ) - ) - ) - } - - private fun createTabsForPackage(page: PackagePage): List<ContentTab> { - val p = page.documentables.single() as DPackage - return listOfNotNull( - if (p.typealiases.isEmpty() && p.classlikes.isEmpty()) null else ContentTab( - "Types", - listOf( - BasicTabbedContentType.TYPE, - ) - ), - if (p.functions.isEmpty()) null else ContentTab( - "Functions", - listOf( - BasicTabbedContentType.FUNCTION, - BasicTabbedContentType.EXTENSION_FUNCTION, - ) - ), - if (p.properties.isEmpty()) null else ContentTab( - "Properties", - listOf( - BasicTabbedContentType.PROPERTY, - BasicTabbedContentType.EXTENSION_PROPERTY, - ) - ) - ) - } - - private fun <R> TagConsumer<R>.prepareForTemplates() = - if (context.configuration.delayTemplateSubstitution || this is ImmediateResolutionTagConsumer) this - else ImmediateResolutionTagConsumer(this, context) - - override fun FlowContent.wrapGroup( - node: ContentGroup, - pageContext: ContentPage, - childrenCallback: FlowContent.() -> Unit - ) { - val additionalClasses = node.style.joinToString(" ") { it.toString().toLowerCase() } - return when { - node.hasStyle(ContentStyle.TabbedContent) -> div(additionalClasses) { - val contentTabs = createTabs(pageContext) - - div(classes = "tabs-section") { - attributes["tabs-section"] = "tabs-section" - contentTabs.forEachIndexed { index, contentTab -> - button(classes = "section-tab") { - if (index == 0) attributes["data-active"] = "" - attributes[TOGGLEABLE_CONTENT_TYPE_ATTR] = - contentTab.tabbedContentTypes.joinToString(",") { it.toHtmlAttribute() } - text(contentTab.text) - } - } - } - div(classes = "tabs-section-body") { - childrenCallback() - } - } - node.hasStyle(ContentStyle.WithExtraAttributes) -> div { - node.extra.extraHtmlAttributes().forEach { attributes[it.extraKey] = it.extraValue } - childrenCallback() - } - node.dci.kind in setOf(ContentKind.Symbol) -> div("symbol $additionalClasses") { - childrenCallback() - } - node.hasStyle(ContentStyle.KDocTag) -> span("kdoc-tag") { childrenCallback() } - node.hasStyle(ContentStyle.Footnote) -> div("footnote") { childrenCallback() } - node.hasStyle(TextStyle.BreakableAfter) -> { - span { childrenCallback() } - wbr { } - } - node.hasStyle(TextStyle.Breakable) -> { - span("breakable-word") { childrenCallback() } - } - node.hasStyle(TextStyle.Span) -> span { childrenCallback() } - node.dci.kind == ContentKind.Symbol -> div("symbol $additionalClasses") { - childrenCallback() - } - node.dci.kind == SymbolContentKind.Parameters -> { - span("parameters $additionalClasses") { - childrenCallback() - } - } - node.dci.kind == SymbolContentKind.Parameter -> { - span("parameter $additionalClasses") { - childrenCallback() - } - } - node.hasStyle(TextStyle.InlineComment) -> div("inline-comment") { childrenCallback() } - node.dci.kind == ContentKind.BriefComment -> div("brief $additionalClasses") { childrenCallback() } - node.dci.kind == ContentKind.Cover -> div("cover $additionalClasses") { //TODO this can be removed - childrenCallback() - } - node.dci.kind == ContentKind.Deprecation -> div("deprecation-content") { childrenCallback() } - node.hasStyle(TextStyle.Paragraph) -> p(additionalClasses) { childrenCallback() } - node.hasStyle(TextStyle.Block) -> div(additionalClasses) { - childrenCallback() - } - node.hasStyle(TextStyle.Quotation) -> blockQuote(additionalClasses) { childrenCallback() } - node.hasStyle(TextStyle.FloatingRight) -> span("clearfix") { span("floating-right") { childrenCallback() } } - node.hasStyle(TextStyle.Strikethrough) -> strike { childrenCallback() } - node.isAnchorable -> buildAnchor( - node.anchor!!, - node.anchorLabel!!, - node.buildSourceSetFilterValues() - ) { childrenCallback() } - node.extra[InsertTemplateExtra] != null -> node.extra[InsertTemplateExtra]?.let { templateCommand(it.command) } - ?: Unit - node.hasStyle(ListStyle.DescriptionTerm) -> DT(emptyMap(), consumer).visit { - this@wrapGroup.childrenCallback() - } - node.hasStyle(ListStyle.DescriptionDetails) -> DD(emptyMap(), consumer).visit { - this@wrapGroup.childrenCallback() - } - node.extra.extraTabbedContentType() != null -> div() { - node.extra.extraTabbedContentType()?.let { attributes[TOGGLEABLE_CONTENT_TYPE_ATTR] = it.value.toHtmlAttribute() } - this@wrapGroup.childrenCallback() - } - else -> childrenCallback() - } - } - - private fun FlowContent.copyButton() = span(classes = "top-right-position") { - span("copy-icon") - copiedPopup("Content copied to clipboard", "popup-to-left") - } - - private fun FlowContent.copiedPopup(notificationContent: String, additionalClasses: String = "") = - div("copy-popup-wrapper $additionalClasses") { - span("copy-popup-icon") - span { - text(notificationContent) - } - } - - override fun FlowContent.buildPlatformDependent( - content: PlatformHintedContent, - pageContext: ContentPage, - sourceSetRestriction: Set<DisplaySourceSet>? - ) { - buildPlatformDependent( - content.sourceSets.filter { - sourceSetRestriction == null || it in sourceSetRestriction - }.associateWith { setOf(content.inner) }, - pageContext, - content.extra, - content.style - ) - } - - private fun FlowContent.buildPlatformDependent( - nodes: Map<DisplaySourceSet, Collection<ContentNode>>, - pageContext: ContentPage, - extra: PropertyContainer<ContentNode> = PropertyContainer.empty(), - styles: Set<Style> = emptySet(), - shouldHaveTabs: Boolean = shouldRenderSourceSetTabs - ) { - val contents = contentsForSourceSetDependent(nodes, pageContext) - val isOnlyCommonContent = contents.singleOrNull()?.let { (sourceSet, _) -> - sourceSet.platform == Platform.common - && sourceSet.name.equals("common", ignoreCase = true) - && sourceSet.sourceSetIDs.all.all { sourceSetDependencyMap[it]?.isEmpty() == true } - } ?: false - - // little point in rendering a single "common" tab - it can be - // assumed that code without any tabs is common by default - val renderTabs = shouldHaveTabs && !isOnlyCommonContent - - val divStyles = "platform-hinted ${styles.joinToString()}" + if (renderTabs) " with-platform-tabs" else "" - div(divStyles) { - attributes["data-platform-hinted"] = "data-platform-hinted" - extra.extraHtmlAttributes().forEach { attributes[it.extraKey] = it.extraValue } - if (renderTabs) { - div("platform-bookmarks-row") { - attributes["data-toggle-list"] = "data-toggle-list" - contents.forEachIndexed { index, pair -> - button(classes = "platform-bookmark") { - attributes["data-filterable-current"] = pair.first.sourceSetIDs.merged.toString() - attributes["data-filterable-set"] = pair.first.sourceSetIDs.merged.toString() - if (index == 0) attributes["data-active"] = "" - attributes["data-toggle"] = pair.first.sourceSetIDs.merged.toString() - text(pair.first.name) - } - } - } - } - contents.forEach { - consumer.onTagContentUnsafe { +it.second } - } - } - } - - private fun contentsForSourceSetDependent( - nodes: Map<DisplaySourceSet, Collection<ContentNode>>, - pageContext: ContentPage, - ): List<Pair<DisplaySourceSet, String>> { - var counter = 0 - return nodes.toList().map { (sourceSet, elements) -> - val htmlContent = createHTML(prettyPrint = false).prepareForTemplates().div { - elements.forEach { - buildContentNode(it, pageContext, sourceSet) - } - }.stripDiv() - sourceSet to createHTML(prettyPrint = false).prepareForTemplates() - .div(classes = "content sourceset-dependent-content") { - if (counter++ == 0) attributes["data-active"] = "" - attributes["data-togglable"] = sourceSet.sourceSetIDs.merged.toString() - unsafe { - +htmlContent - } - } - }.sortedBy { it.first.comparableKey } - } - - override fun FlowContent.buildDivergent(node: ContentDivergentGroup, pageContext: ContentPage) { - if (node.implicitlySourceSetHinted) { - val groupedInstancesBySourceSet = node.children.flatMap { instance -> - instance.sourceSets.map { sourceSet -> instance to sourceSet } - }.groupBy( - Pair<ContentDivergentInstance, DisplaySourceSet>::second, - Pair<ContentDivergentInstance, DisplaySourceSet>::first - ) - - val nodes = groupedInstancesBySourceSet.mapValues { - val distinct = - groupDivergentInstancesWithSourceSet(it.value, it.key, pageContext, - beforeTransformer = { instance, _, sourceSet -> - createHTML(prettyPrint = false).prepareForTemplates().div { - instance.before?.let { before -> - buildContentNode(before, pageContext, sourceSet) - } - }.stripDiv() - }, - afterTransformer = { instance, _, sourceSet -> - createHTML(prettyPrint = false).prepareForTemplates().div { - instance.after?.let { after -> - buildContentNode(after, pageContext, sourceSet) - } - }.stripDiv() - }) - - val isPageWithOverloadedMembers = pageContext is MemberPage && pageContext.documentables().size > 1 - - val contentOfSourceSet = mutableListOf<ContentNode>() - distinct.onEachIndexed{ index, (_, distinctInstances) -> - distinctInstances.firstOrNull()?.before?.let { contentOfSourceSet.add(it) } - contentOfSourceSet.addAll(distinctInstances.map { it.divergent }) - (distinctInstances.firstOrNull()?.after ?: if (index != distinct.size - 1) ContentBreakLine(setOf(it.key)) else null) - ?.let { contentOfSourceSet.add(it) } - - // content kind main is important for declarations list to avoid double line breaks - if (node.dci.kind == ContentKind.Main && index != distinct.size - 1) { - if (isPageWithOverloadedMembers) { - // add some spacing and distinction between function/property overloads. - // not ideal, but there's no other place to modify overloads page atm - contentOfSourceSet.add(ContentBreakLine(setOf(it.key), style = setOf(HorizontalBreakLineStyle))) - } else { - contentOfSourceSet.add(ContentBreakLine(setOf(it.key))) - } - } - } - contentOfSourceSet - } - buildPlatformDependent(nodes, pageContext) - } else { - node.children.forEach { - buildContentNode(it.divergent, pageContext, it.sourceSets) - } - } - } - - private fun groupDivergentInstancesWithSourceSet( - instances: List<ContentDivergentInstance>, - sourceSet: DisplaySourceSet, - pageContext: ContentPage, - beforeTransformer: (ContentDivergentInstance, ContentPage, DisplaySourceSet) -> String, - afterTransformer: (ContentDivergentInstance, ContentPage, DisplaySourceSet) -> String - ): Map<SerializedBeforeAndAfter, List<ContentDivergentInstance>> = - instances.map { instance -> - instance to Pair( - beforeTransformer(instance, pageContext, sourceSet), - afterTransformer(instance, pageContext, sourceSet) - ) - }.groupBy( - Pair<ContentDivergentInstance, SerializedBeforeAndAfter>::second, - Pair<ContentDivergentInstance, SerializedBeforeAndAfter>::first - ) - - private fun ContentPage.documentables(): List<Documentable> { - return (this as? WithDocumentables)?.documentables ?: emptyList() - } - - override fun FlowContent.buildList( - node: ContentList, - pageContext: ContentPage, - sourceSetRestriction: Set<DisplaySourceSet>? - ) { - return when { - node.ordered -> { - ol { buildListItems(node.children, pageContext, sourceSetRestriction) } - } - node.hasStyle(ListStyle.DescriptionList) -> { - dl { node.children.forEach { it.build(this, pageContext, sourceSetRestriction) } } - } - else -> { - ul { buildListItems(node.children, pageContext, sourceSetRestriction) } - } - } - } - - public open fun OL.buildListItems( - items: List<ContentNode>, - pageContext: ContentPage, - sourceSetRestriction: Set<DisplaySourceSet>? = null - ) { - items.forEach { - if (it is ContentList) - buildList(it, pageContext) - else - li { it.build(this, pageContext, sourceSetRestriction) } - } - } - - public open fun UL.buildListItems( - items: List<ContentNode>, - pageContext: ContentPage, - sourceSetRestriction: Set<DisplaySourceSet>? = null - ) { - items.forEach { - if (it is ContentList) - buildList(it, pageContext) - else - li { it.build(this, pageContext) } - } - } - - override fun FlowContent.buildResource( - node: ContentEmbeddedResource, - pageContext: ContentPage - ) { // TODO: extension point there - if (node.isImage()) { - img(src = node.address, alt = node.altText) - } else { - println("Unrecognized resource type: $node") - } - } - - private fun FlowContent.buildRow( - node: ContentGroup, - pageContext: ContentPage, - sourceSetRestriction: Set<DisplaySourceSet>? - ) { - node.children - .filter { sourceSetRestriction == null || it.sourceSets.any { s -> s in sourceSetRestriction } } - .takeIf { it.isNotEmpty() } - ?.let { - when (pageContext) { - is MultimoduleRootPage -> buildRowForMultiModule(node, it, pageContext, sourceSetRestriction) - is ModulePage -> buildRowForModule(node, it, pageContext, sourceSetRestriction) - else -> buildRowForContent(node, it, pageContext, sourceSetRestriction) - } - } - } - - private fun FlowContent.buildRowForMultiModule( - contextNode: ContentGroup, - toRender: List<ContentNode>, - pageContext: ContentPage, - sourceSetRestriction: Set<DisplaySourceSet>? - ) { - buildAnchor(contextNode) - div(classes = "table-row") { - div("main-subrow " + contextNode.style.joinToString(separator = " ")) { - buildRowHeaderLink(toRender, pageContext, sourceSetRestriction, contextNode.anchor, "w-100") - div { - buildRowBriefSectionForDocs(toRender, pageContext, sourceSetRestriction) - } - } - } - } - - private fun FlowContent.buildRowForModule( - contextNode: ContentGroup, - toRender: List<ContentNode>, - pageContext: ContentPage, - sourceSetRestriction: Set<DisplaySourceSet>? - ) { - buildAnchor(contextNode) - div(classes = "table-row") { - addSourceSetFilteringAttributes(contextNode) - div { - div("main-subrow " + contextNode.style.joinToString(separator = " ")) { - buildRowHeaderLink(toRender, pageContext, sourceSetRestriction, contextNode.anchor) - div("pull-right") { - if (ContentKind.shouldBePlatformTagged(contextNode.dci.kind)) { - createPlatformTags(contextNode, cssClasses = "no-gutters") - } - } - } - div { - buildRowBriefSectionForDocs(toRender, pageContext, sourceSetRestriction) - } - } - } - } - - private fun FlowContent.buildRowForContent( - contextNode: ContentGroup, - toRender: List<ContentNode>, - pageContext: ContentPage, - sourceSetRestriction: Set<DisplaySourceSet>? - ) { - buildAnchor(contextNode) - div(classes = "table-row") { - contextNode.extra.extraTabbedContentType()?.let { attributes[TOGGLEABLE_CONTENT_TYPE_ATTR] = it.value.toHtmlAttribute() } - addSourceSetFilteringAttributes(contextNode) - div("main-subrow keyValue " + contextNode.style.joinToString(separator = " ")) { - buildRowHeaderLink(toRender, pageContext, sourceSetRestriction, contextNode.anchor) - div { - toRender.filter { it !is ContentLink && !it.hasStyle(ContentStyle.RowTitle) } - .takeIf { it.isNotEmpty() }?.let { - div("title") { - it.forEach { - it.build(this, pageContext, sourceSetRestriction) - } - } - } - } - } - } - } - - private fun FlowContent.buildRowHeaderLink( - toRender: List<ContentNode>, - pageContext: ContentPage, - sourceSetRestriction: Set<DisplaySourceSet>?, - anchorDestination: String?, - classes: String = "" - ) { - toRender.filter { it is ContentLink || it.hasStyle(ContentStyle.RowTitle) }.takeIf { it.isNotEmpty() }?.let { - div(classes) { - it.filter { sourceSetRestriction == null || it.sourceSets.any { s -> s in sourceSetRestriction } } - .forEach { - span("inline-flex") { - div { - it.build(this, pageContext, sourceSetRestriction) - } - if (it is ContentLink && !anchorDestination.isNullOrBlank()) { - buildAnchorCopyButton(anchorDestination) - } - } - } - } - } - } - - private fun FlowContent.addSourceSetFilteringAttributes( - contextNode: ContentGroup, - ) { - attributes["data-filterable-current"] = contextNode.buildSourceSetFilterValues() - attributes["data-filterable-set"] = contextNode.buildSourceSetFilterValues() - } - - private fun ContentNode.buildSourceSetFilterValues(): String { - // This value is used in HTML and JS for filtering out source set declarations, - // it is expected that the separator is the same here and there. - // See https://github.com/Kotlin/dokka/issues/3011#issuecomment-1568620493 - return this.sourceSets.joinToString(",") { - it.sourceSetIDs.merged.toString() - } - } - - private fun FlowContent.buildRowBriefSectionForDocs( - toRender: List<ContentNode>, - pageContext: ContentPage, - sourceSetRestriction: Set<DisplaySourceSet>?, - ) { - toRender.filter { it !is ContentLink }.takeIf { it.isNotEmpty() }?.let { - it.forEach { - span(classes = if (it.dci.kind == ContentKind.Comment) "brief-comment" else "") { - it.build(this, pageContext, sourceSetRestriction) - } - } - } - } - - private fun FlowContent.createPlatformTagBubbles(sourceSets: List<DisplaySourceSet>, cssClasses: String = "") { - div("platform-tags $cssClasses") { - sourceSets.sortedBy { it.name }.forEach { - div("platform-tag") { - when (it.platform.key) { - "common" -> classes = classes + "common-like" - "native" -> classes = classes + "native-like" - "jvm" -> classes = classes + "jvm-like" - "js" -> classes = classes + "js-like" - "wasm" -> classes = classes + "wasm-like" - } - text(it.name) - } - } - } - } - - private fun FlowContent.createPlatformTags( - node: ContentNode, - sourceSetRestriction: Set<DisplaySourceSet>? = null, - cssClasses: String = "" - ) { - node.takeIf { sourceSetRestriction == null || it.sourceSets.any { s -> s in sourceSetRestriction } }?.let { - createPlatformTagBubbles(node.sourceSets.filter { - sourceSetRestriction == null || it in sourceSetRestriction - }.sortedBy { it.name }, cssClasses) - } - } - - override fun FlowContent.buildTable( - node: ContentTable, - pageContext: ContentPage, - sourceSetRestriction: Set<DisplaySourceSet>? - ) { - when { - node.style.contains(CommentTable) -> buildDefaultTable(node, pageContext, sourceSetRestriction) - else -> div(classes = "table") { - node.extra.extraHtmlAttributes().forEach { attributes[it.extraKey] = it.extraValue } - node.children.forEach { - buildRow(it, pageContext, sourceSetRestriction) - } - } - } - - } - - public fun FlowContent.buildDefaultTable( - node: ContentTable, - pageContext: ContentPage, - sourceSetRestriction: Set<DisplaySourceSet>? - ) { - table { - thead { - node.header.forEach { - tr { - it.children.forEach { - th { - it.build(this@table, pageContext, sourceSetRestriction) - } - } - } - } - } - tbody { - node.children.forEach { - tr { - it.children.forEach { - td { - it.build(this, pageContext, sourceSetRestriction) - } - } - } - } - } - } - } - - - override fun FlowContent.buildHeader(level: Int, node: ContentHeader, content: FlowContent.() -> Unit) { - val classes = node.style.joinToString { it.toString() }.toLowerCase() - whe |
