diff options
| author | Vadim Mishenev <vad-mishenev@yandex.ru> | 2023-02-24 17:44:24 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-02-24 17:44:24 +0200 |
| commit | 1040288ca76e070445f1400df2fcc5a56310be28 (patch) | |
| tree | 52bed40e8a320f0835540b0cd38ea1899800e395 | |
| parent | 8d23340d1c377b8f490cdee3c2c874453d321dd8 (diff) | |
| download | dokka-1040288ca76e070445f1400df2fcc5a56310be28.tar.gz dokka-1040288ca76e070445f1400df2fcc5a56310be28.tar.bz2 dokka-1040288ca76e070445f1400df2fcc5a56310be28.zip | |
Reorganize tabs for Classlike (#2764)
28 files changed, 873 insertions, 453 deletions
diff --git a/core/api/core.api b/core/api/core.api index f51d7043..4c755aae 100644 --- a/core/api/core.api +++ b/core/api/core.api @@ -1460,6 +1460,7 @@ public final class org/jetbrains/dokka/model/DocumentableUtilsKt { public static final fun filter (Lorg/jetbrains/dokka/model/DTypeParameter;Ljava/util/Set;)Lorg/jetbrains/dokka/model/DTypeParameter; public static final fun filtered (Ljava/util/Map;Ljava/util/Set;)Ljava/util/Map; public static final fun filtered (Lorg/jetbrains/dokka/DokkaConfiguration$DokkaSourceSet;Ljava/util/Set;)Lorg/jetbrains/dokka/DokkaConfiguration$DokkaSourceSet; + public static final fun isExtension (Lorg/jetbrains/dokka/model/Documentable;)Z } public final class org/jetbrains/dokka/model/DoubleConstant : org/jetbrains/dokka/model/Expression { @@ -3469,6 +3470,18 @@ public abstract interface class org/jetbrains/dokka/model/properties/WithExtraPr public abstract fun withNewExtras (Lorg/jetbrains/dokka/model/properties/PropertyContainer;)Ljava/lang/Object; } +public final class org/jetbrains/dokka/pages/BasicTabbedContentType : java/lang/Enum, org/jetbrains/dokka/pages/TabbedContentType { + public static final field CONSTRUCTOR Lorg/jetbrains/dokka/pages/BasicTabbedContentType; + public static final field ENTRY Lorg/jetbrains/dokka/pages/BasicTabbedContentType; + public static final field EXTENSION_FUNCTION Lorg/jetbrains/dokka/pages/BasicTabbedContentType; + public static final field EXTENSION_PROPERTY Lorg/jetbrains/dokka/pages/BasicTabbedContentType; + public static final field FUNCTION Lorg/jetbrains/dokka/pages/BasicTabbedContentType; + public static final field PROPERTY Lorg/jetbrains/dokka/pages/BasicTabbedContentType; + public static final field TYPE Lorg/jetbrains/dokka/pages/BasicTabbedContentType; + public static fun valueOf (Ljava/lang/String;)Lorg/jetbrains/dokka/pages/BasicTabbedContentType; + public static fun values ()[Lorg/jetbrains/dokka/pages/BasicTabbedContentType; +} + public abstract interface class org/jetbrains/dokka/pages/ClasslikePage : org/jetbrains/dokka/pages/ContentPage, org/jetbrains/dokka/pages/WithDocumentables { } @@ -4248,17 +4261,12 @@ public abstract class org/jetbrains/dokka/pages/RootPageNode : org/jetbrains/dok } public final class org/jetbrains/dokka/pages/SimpleAttr : org/jetbrains/dokka/model/properties/ExtraProperty { - public static final field Companion Lorg/jetbrains/dokka/pages/SimpleAttr$Companion; public fun <init> (Ljava/lang/String;Ljava/lang/String;)V public final fun getExtraKey ()Ljava/lang/String; public final fun getExtraValue ()Ljava/lang/String; public fun getKey ()Lorg/jetbrains/dokka/model/properties/ExtraProperty$Key; } -public final class org/jetbrains/dokka/pages/SimpleAttr$Companion { - public final fun header (Ljava/lang/String;)Lorg/jetbrains/dokka/pages/SimpleAttr; -} - public final class org/jetbrains/dokka/pages/SimpleAttr$SimpleAttrKey : org/jetbrains/dokka/model/properties/ExtraProperty$Key { public fun <init> (Ljava/lang/String;)V public final fun component1 ()Ljava/lang/String; @@ -4282,6 +4290,21 @@ public final class org/jetbrains/dokka/pages/SymbolContentKind : java/lang/Enum, public static fun values ()[Lorg/jetbrains/dokka/pages/SymbolContentKind; } +public abstract interface class org/jetbrains/dokka/pages/TabbedContentType { +} + +public final class org/jetbrains/dokka/pages/TabbedContentTypeExtra : org/jetbrains/dokka/model/properties/ExtraProperty { + public static final field Companion Lorg/jetbrains/dokka/pages/TabbedContentTypeExtra$Companion; + public fun <init> (Lorg/jetbrains/dokka/pages/TabbedContentType;)V + public fun getKey ()Lorg/jetbrains/dokka/model/properties/ExtraProperty$Key; + public final fun getValue ()Lorg/jetbrains/dokka/pages/TabbedContentType; +} + +public final class org/jetbrains/dokka/pages/TabbedContentTypeExtra$Companion : org/jetbrains/dokka/model/properties/ExtraProperty$Key { + public synthetic fun mergeStrategyFor (Ljava/lang/Object;Ljava/lang/Object;)Lorg/jetbrains/dokka/model/properties/MergeStrategy; + public fun mergeStrategyFor (Lorg/jetbrains/dokka/pages/TabbedContentTypeExtra;Lorg/jetbrains/dokka/pages/TabbedContentTypeExtra;)Lorg/jetbrains/dokka/model/properties/MergeStrategy; +} + public final class org/jetbrains/dokka/pages/TextStyle : java/lang/Enum, org/jetbrains/dokka/pages/Style { public static final field Block Lorg/jetbrains/dokka/pages/TextStyle; public static final field Bold Lorg/jetbrains/dokka/pages/TextStyle; diff --git a/core/content-matcher-test-utils/api/content-matcher-test-utils.api b/core/content-matcher-test-utils/api/content-matcher-test-utils.api index 0a7f153b..58881a15 100644 --- a/core/content-matcher-test-utils/api/content-matcher-test-utils.api +++ b/core/content-matcher-test-utils/api/content-matcher-test-utils.api @@ -30,6 +30,8 @@ public final class matchers/content/ContentMatchersDslKt { public static final fun platformHinted (Lmatchers/content/ContentMatcherBuilder;Lkotlin/jvm/functions/Function1;)V public static final fun skipAllNotMatching (Lmatchers/content/ContentMatcherBuilder;)V public static final fun somewhere (Lmatchers/content/ContentMatcherBuilder;Lkotlin/jvm/functions/Function1;)V + public static final fun tab (Lmatchers/content/ContentMatcherBuilder;Lorg/jetbrains/dokka/pages/TabbedContentType;Lkotlin/jvm/functions/Function1;)V + public static final fun tabbedGroup (Lmatchers/content/ContentMatcherBuilder;Lkotlin/jvm/functions/Function1;)V public static final fun table (Lmatchers/content/ContentMatcherBuilder;Lkotlin/jvm/functions/Function1;)V } diff --git a/core/content-matcher-test-utils/src/main/kotlin/matchers/content/ContentMatchersDsl.kt b/core/content-matcher-test-utils/src/main/kotlin/matchers/content/ContentMatchersDsl.kt index 08442536..13780718 100644 --- a/core/content-matcher-test-utils/src/main/kotlin/matchers/content/ContentMatchersDsl.kt +++ b/core/content-matcher-test-utils/src/main/kotlin/matchers/content/ContentMatchersDsl.kt @@ -3,6 +3,7 @@ package matchers.content import assertk.assertThat import assertk.assertions.contains import assertk.assertions.isEqualTo +import assertk.assertions.isNotNull import org.jetbrains.dokka.model.withDescendants import org.jetbrains.dokka.pages.* import org.jetbrains.dokka.test.tools.matchers.content.* @@ -70,6 +71,23 @@ fun ContentMatcherBuilder<*>.skipAllNotMatching() { // Convenience functions: fun ContentMatcherBuilder<*>.group(block: ContentMatcherBuilder<ContentGroup>.() -> Unit) = composite(block) +fun ContentMatcherBuilder<*>.tabbedGroup( + block: ContentMatcherBuilder<ContentGroup>.() -> Unit +) = composite<ContentGroup> { + block() + check { assertThat(this::style).transform { style -> style.contains(ContentStyle.TabbedContent) }.isEqualTo(true) } +} + +fun ContentMatcherBuilder<*>.tab( + tabbedContentType: TabbedContentType, block: ContentMatcherBuilder<ContentGroup>.() -> Unit +) = composite<ContentGroup> { + block() + check { + assertThat(this::extra).transform { extra -> extra[TabbedContentTypeExtra]?.value } + .isEqualTo(tabbedContentType) + } +} + fun ContentMatcherBuilder<*>.header(expectedLevel: Int? = null, block: ContentMatcherBuilder<ContentHeader>.() -> Unit) = composite<ContentHeader> { block() diff --git a/core/src/main/kotlin/model/Documentable.kt b/core/src/main/kotlin/model/Documentable.kt index 73ab35d4..adc51cfc 100644 --- a/core/src/main/kotlin/model/Documentable.kt +++ b/core/src/main/kotlin/model/Documentable.kt @@ -519,4 +519,4 @@ interface DocumentableSource { val path: String } -data class TypeConstructorWithKind(val typeConstructor: TypeConstructor, val kind: ClassKind) +data class TypeConstructorWithKind(val typeConstructor: TypeConstructor, val kind: ClassKind)
\ No newline at end of file diff --git a/core/src/main/kotlin/model/documentableUtils.kt b/core/src/main/kotlin/model/documentableUtils.kt index e32605ca..076ca23a 100644 --- a/core/src/main/kotlin/model/documentableUtils.kt +++ b/core/src/main/kotlin/model/documentableUtils.kt @@ -19,3 +19,5 @@ fun DTypeParameter.filter(filteredSet: Set<DokkaSourceSet>) = extra ) } + +fun Documentable.isExtension() = this is Callable && receiver != null
\ No newline at end of file diff --git a/core/src/main/kotlin/pages/ContentNodes.kt b/core/src/main/kotlin/pages/ContentNodes.kt index 3c6fa5ac..78760044 100644 --- a/core/src/main/kotlin/pages/ContentNodes.kt +++ b/core/src/main/kotlin/pages/ContentNodes.kt @@ -392,7 +392,14 @@ enum class TextStyle : Style { } enum class ContentStyle : Style { - RowTitle, TabbedContent, WithExtraAttributes, RunnableSample, InDocumentationAnchor, Caption, + RowTitle, + /** + * The style is used only for HTML. It is applied only for [ContentGroup]. + * Creating and rendering tabs is a part of a renderer. + */ + TabbedContent, + + WithExtraAttributes, RunnableSample, InDocumentationAnchor, Caption, Wrapped, Indented, KDocTag, Footnote } diff --git a/core/src/main/kotlin/pages/contentNodeProperties.kt b/core/src/main/kotlin/pages/contentNodeProperties.kt index cfd7f769..3c9bd422 100644 --- a/core/src/main/kotlin/pages/contentNodeProperties.kt +++ b/core/src/main/kotlin/pages/contentNodeProperties.kt @@ -6,9 +6,23 @@ class SimpleAttr(val extraKey: String, val extraValue: String) : ExtraProperty<C data class SimpleAttrKey(val key: String) : ExtraProperty.Key<ContentNode, SimpleAttr> override val key: ExtraProperty.Key<ContentNode, SimpleAttr> = SimpleAttrKey(extraKey) - companion object { - fun header(value: String) = SimpleAttr("data-togglable", value) - } +} + +enum class BasicTabbedContentType : TabbedContentType { + TYPE, CONSTRUCTOR, FUNCTION, PROPERTY, ENTRY, EXTENSION_PROPERTY, EXTENSION_FUNCTION +} + +/** + * It is used only to mark content for tabs in HTML format + */ +interface TabbedContentType + +/** + * @see TabbedContentType + */ +class TabbedContentTypeExtra(val value: TabbedContentType) : ExtraProperty<ContentNode> { + companion object : ExtraProperty.Key<ContentNode, TabbedContentTypeExtra> + override val key: ExtraProperty.Key<ContentNode, TabbedContentTypeExtra> = TabbedContentTypeExtra } object HtmlContent : ExtraProperty<ContentNode>, ExtraProperty.Key<ContentNode, HtmlContent> { diff --git a/plugins/base/api/base.api b/plugins/base/api/base.api index f529b0ee..5e36f375 100644 --- a/plugins/base/api/base.api +++ b/plugins/base/api/base.api @@ -10,7 +10,6 @@ public final class org/jetbrains/dokka/base/DokkaBase : org/jetbrains/dokka/plug public final fun getDefaultExternalDocumentablesProvider ()Lorg/jetbrains/dokka/plugability/Extension; public final fun getDefaultKotlinAnalysis ()Lorg/jetbrains/dokka/plugability/Extension; public final fun getDefaultSamplesTransformer ()Lorg/jetbrains/dokka/plugability/Extension; - public final fun getDefaultTabSortingStrategy ()Lorg/jetbrains/dokka/plugability/Extension; public final fun getDeprecatedDocumentableFilter ()Lorg/jetbrains/dokka/plugability/Extension; public final fun getDescriptorToDocumentableTranslator ()Lorg/jetbrains/dokka/plugability/Extension; public final fun getDocTagToContentConverter ()Lorg/jetbrains/dokka/plugability/Extension; @@ -272,11 +271,6 @@ public final class org/jetbrains/dokka/base/renderers/DefaultRendererKt { public static final fun sourceSets (Lorg/jetbrains/dokka/pages/ContentPage;)Ljava/util/Set; } -public final class org/jetbrains/dokka/base/renderers/DefaultTabSortingStrategy : org/jetbrains/dokka/base/renderers/TabSortingStrategy { - public fun <init> ()V - public fun sort (Ljava/util/Collection;)Ljava/util/List; -} - public final class org/jetbrains/dokka/base/renderers/FileWriter : org/jetbrains/dokka/base/renderers/OutputWriter { public fun <init> (Lorg/jetbrains/dokka/plugability/DokkaContext;)V public final fun getContext ()Lorg/jetbrains/dokka/plugability/DokkaContext; @@ -1450,16 +1444,19 @@ public class org/jetbrains/dokka/base/translators/documentables/DefaultPageCreat public synthetic fun <init> (Lorg/jetbrains/dokka/base/DokkaBaseConfiguration;Lorg/jetbrains/dokka/base/transformers/pages/comments/CommentsToContentConverter;Lorg/jetbrains/dokka/base/signatures/SignatureProvider;Lorg/jetbrains/dokka/utilities/DokkaLogger;Ljava/util/List;ILkotlin/jvm/internal/DefaultConstructorMarker;)V protected fun contentForBrief (Lorg/jetbrains/dokka/base/translators/documentables/PageContentBuilder$DocumentableContentBuilder;Lorg/jetbrains/dokka/model/Documentable;)V protected fun contentForClasslikesAndEntries (Ljava/util/List;)Lorg/jetbrains/dokka/pages/ContentGroup; + protected fun contentForConstructors (Ljava/util/List;Ljava/util/Set;Ljava/util/Set;)Lorg/jetbrains/dokka/pages/ContentGroup; protected fun contentForDescription (Lorg/jetbrains/dokka/model/Documentable;)Ljava/util/List; + protected fun contentForEntries (Ljava/util/List;Ljava/util/Set;Ljava/util/Set;)Lorg/jetbrains/dokka/pages/ContentGroup; protected fun contentForFunction (Lorg/jetbrains/dokka/model/DFunction;)Lorg/jetbrains/dokka/pages/ContentGroup; protected fun contentForMember (Lorg/jetbrains/dokka/model/Documentable;)Lorg/jetbrains/dokka/pages/ContentGroup; protected fun contentForMembers (Ljava/util/List;)Lorg/jetbrains/dokka/pages/ContentGroup; protected fun contentForModule (Lorg/jetbrains/dokka/model/DModule;)Lorg/jetbrains/dokka/pages/ContentGroup; protected fun contentForPackage (Lorg/jetbrains/dokka/model/DPackage;)Lorg/jetbrains/dokka/pages/ContentGroup; protected fun contentForProperty (Lorg/jetbrains/dokka/model/DProperty;)Lorg/jetbrains/dokka/pages/ContentGroup; - protected fun contentForScope (Ljava/util/Set;Ljava/util/Set;Ljava/util/List;Ljava/util/List;Ljava/util/List;)Lorg/jetbrains/dokka/pages/ContentGroup; - protected fun contentForScope (Lorg/jetbrains/dokka/model/WithScope;Lorg/jetbrains/dokka/links/DRI;Ljava/util/Set;)Lorg/jetbrains/dokka/pages/ContentGroup; - protected fun contentForScopes (Ljava/util/List;Ljava/util/Set;)Lorg/jetbrains/dokka/pages/ContentGroup; + protected fun contentForScope (Lorg/jetbrains/dokka/model/WithScope;Lorg/jetbrains/dokka/links/DRI;Ljava/util/Set;Ljava/util/List;)Lorg/jetbrains/dokka/pages/ContentGroup; + public static synthetic fun contentForScope$default (Lorg/jetbrains/dokka/base/translators/documentables/DefaultPageCreator;Lorg/jetbrains/dokka/model/WithScope;Lorg/jetbrains/dokka/links/DRI;Ljava/util/Set;Ljava/util/List;ILjava/lang/Object;)Lorg/jetbrains/dokka/pages/ContentGroup; + protected fun contentForScopes (Ljava/util/List;Ljava/util/Set;Ljava/util/List;)Lorg/jetbrains/dokka/pages/ContentGroup; + public static synthetic fun contentForScopes$default (Lorg/jetbrains/dokka/base/translators/documentables/DefaultPageCreator;Ljava/util/List;Ljava/util/Set;Ljava/util/List;ILjava/lang/Object;)Lorg/jetbrains/dokka/pages/ContentGroup; protected fun divergentBlock (Lorg/jetbrains/dokka/base/translators/documentables/PageContentBuilder$DocumentableContentBuilder;Ljava/lang/String;Ljava/util/Collection;Lorg/jetbrains/dokka/pages/ContentKind;Lorg/jetbrains/dokka/model/properties/PropertyContainer;)V public static synthetic fun divergentBlock$default (Lorg/jetbrains/dokka/base/translators/documentables/DefaultPageCreator;Lorg/jetbrains/dokka/base/translators/documentables/PageContentBuilder$DocumentableContentBuilder;Ljava/lang/String;Ljava/util/Collection;Lorg/jetbrains/dokka/pages/ContentKind;Lorg/jetbrains/dokka/model/properties/PropertyContainer;ILjava/lang/Object;)V protected fun getContentBuilder ()Lorg/jetbrains/dokka/base/translators/documentables/PageContentBuilder; diff --git a/plugins/base/src/main/kotlin/DokkaBase.kt b/plugins/base/src/main/kotlin/DokkaBase.kt index 456a587b..f76eef63 100644 --- a/plugins/base/src/main/kotlin/DokkaBase.kt +++ b/plugins/base/src/main/kotlin/DokkaBase.kt @@ -54,6 +54,7 @@ class DokkaBase : DokkaPlugin() { val outputWriter by extensionPoint<OutputWriter>() val htmlPreprocessors by extensionPoint<PageTransformer>() val kotlinAnalysis by extensionPoint<KotlinAnalysis>() + @Deprecated("It is not used anymore") val tabSortingStrategy by extensionPoint<TabSortingStrategy>() val immediateHtmlCommandConsumer by extensionPoint<ImmediateHtmlCommandConsumer>() val externalDocumentablesProvider by extensionPoint<ExternalDocumentablesProvider>() @@ -182,10 +183,6 @@ class DokkaBase : DokkaPlugin() { } } - val defaultTabSortingStrategy by extending { - tabSortingStrategy with DefaultTabSortingStrategy() - } - val htmlRenderer by extending { CoreExtensions.renderer providing ::HtmlRenderer } diff --git a/plugins/base/src/main/kotlin/renderers/DefaultTabSortingStrategy.kt b/plugins/base/src/main/kotlin/renderers/DefaultTabSortingStrategy.kt deleted file mode 100644 index 056e0f93..00000000 --- a/plugins/base/src/main/kotlin/renderers/DefaultTabSortingStrategy.kt +++ /dev/null @@ -1,30 +0,0 @@ -package org.jetbrains.dokka.base.renderers - -import org.jetbrains.dokka.pages.ContentKind -import org.jetbrains.dokka.pages.ContentNode -import org.jetbrains.dokka.pages.Kind - -private val kindsOrder = listOf( - ContentKind.Classlikes, - ContentKind.Constructors, - ContentKind.Functions, - ContentKind.Properties, - ContentKind.Extensions, - ContentKind.Parameters, - ContentKind.Inheritors, - ContentKind.Source, - ContentKind.Sample, - ContentKind.Comment -) - -class DefaultTabSortingStrategy : TabSortingStrategy { - override fun <T: ContentNode> sort(tabs: Collection<T>): List<T> { - val tabMap: Map<Kind, MutableList<T>> = kindsOrder.asSequence().map { it to mutableListOf<T>() }.toMap() - val unrecognized: MutableList<T> = mutableListOf() - tabs.forEach { - tabMap[it.dci.kind]?.add(it) ?: unrecognized.add(it) - } - return tabMap.values.flatten() + unrecognized - } - -} diff --git a/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt b/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt index b4d98b58..dfefbad8 100644 --- a/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt +++ b/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt @@ -14,9 +14,11 @@ 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.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.* @@ -24,6 +26,7 @@ import org.jetbrains.dokka.utilities.htmlEscape import org.jetbrains.kotlin.utils.addIfNotNull internal const val TEMPLATE_REPLACEMENT: String = "###" +internal const val TOGGLEABLE_CONTENT_TYPE_ATTR = "data-togglable" open class HtmlRenderer( context: DokkaContext @@ -45,19 +48,102 @@ open class HtmlRenderer( override val preprocessors = context.plugin<DokkaBase>().query { htmlPreprocessors } - private val tabSortingStrategy = context.plugin<DokkaBase>().querySingle { tabSortingStrategy } + /** + * 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 + fun List<Documentable>.shouldDocumentConstructors() = !this.any { it is DAnnotation } + 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.FUNCTION, + BasicTabbedContentType.PROPERTY + ) + ), + if (extensions.isEmpty()) null else ContentTab( + "Members & Extensions", + listOf( + BasicTabbedContentType.CONSTRUCTOR, + BasicTabbedContentType.TYPE, + BasicTabbedContentType.FUNCTION, + BasicTabbedContentType.PROPERTY, + 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( + 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) - private fun <T : ContentNode> sortTabs(strategy: TabSortingStrategy, tabs: Collection<T>): List<T> { - val sorted = strategy.sort(tabs) - if (sorted.size != tabs.size) - context.logger.warn("Tab sorting strategy has changed number of tabs from ${tabs.size} to ${sorted.size}") - return sorted - } - override fun FlowContent.wrapGroup( node: ContentGroup, pageContext: ContentPage, @@ -66,20 +152,16 @@ open class HtmlRenderer( val additionalClasses = node.style.joinToString(" ") { it.toString().toLowerCase() } return when { node.hasStyle(ContentStyle.TabbedContent) -> div(additionalClasses) { - val secondLevel = node.children.filterIsInstance<ContentComposite>().flatMap { it.children } - .filterIsInstance<ContentHeader>().flatMap { it.children }.filterIsInstance<ContentText>() - val firstLevel = node.children.filterIsInstance<ContentHeader>().flatMap { it.children } - .filterIsInstance<ContentText>() - - val renderable = sortTabs(tabSortingStrategy, firstLevel.union(secondLevel)) + val contentTabs = createTabs(pageContext) div(classes = "tabs-section") { attributes["tabs-section"] = "tabs-section" - renderable.forEachIndexed { index, node -> + contentTabs.forEachIndexed { index, contentTab -> button(classes = "section-tab") { if (index == 0) attributes["data-active"] = "" - attributes["data-togglable"] = node.text - text(node.text) + attributes[TOGGLEABLE_CONTENT_TYPE_ATTR] = + contentTab.tabbedContentTypes.joinToString(",") { it.toHtmlAttribute() } + text(contentTab.text) } } } @@ -104,7 +186,9 @@ open class HtmlRenderer( span("breakable-word") { childrenCallback() } } node.hasStyle(TextStyle.Span) -> span { childrenCallback() } - node.dci.kind == ContentKind.Symbol -> div("symbol $additionalClasses") { childrenCallback() } + node.dci.kind == ContentKind.Symbol -> div("symbol $additionalClasses") { + childrenCallback() + } node.dci.kind == SymbolContentKind.Parameters -> { span("parameters $additionalClasses") { childrenCallback() @@ -122,7 +206,9 @@ open class HtmlRenderer( } 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.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() } @@ -139,6 +225,10 @@ open class HtmlRenderer( 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() } } @@ -433,6 +523,7 @@ open class HtmlRenderer( ) { 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) @@ -786,11 +877,19 @@ open class HtmlRenderer( content(this, page) } + private fun PageNode.getDocumentableType(): String? = + when(this) { + is PackagePage -> "package" + is ClasslikePage -> "classlike" + is MemberPage -> "member" + else -> null + } open fun buildHtml(page: PageNode, resources: List<String>, content: FlowContent.() -> Unit): String = templater.renderFromTemplate(DokkaTemplateTypes.BASE) { val generatedContent = createHTML().div("main-content") { + page.getDocumentableType()?.let { attributes["data-page-type"] = it } id = "content" (page as? ContentPage)?.let { attributes["pageIds"] = "${context.configuration.moduleName}::${page.pageId}" @@ -851,6 +950,28 @@ open class HtmlRenderer( private val isPartial = context.configuration.delayTemplateSubstitution } +private fun TabbedContentType.toHtmlAttribute(): String = + when(this) { + is BasicTabbedContentType -> + when(this) { + BasicTabbedContentType.ENTRY -> "ENTRY" + BasicTabbedContentType.TYPE -> "TYPE" + BasicTabbedContentType.CONSTRUCTOR -> "CONSTRUCTOR" + BasicTabbedContentType.FUNCTION -> "FUNCTION" + BasicTabbedContentType.PROPERTY -> "PROPERTY" + BasicTabbedContentType.EXTENSION_PROPERTY -> "EXTENSION_PROPERTY" + BasicTabbedContentType.EXTENSION_FUNCTION -> "EXTENSION_FUNCTION" + } + else -> throw IllegalStateException("Unknown TabbedContentType $this") + } + +/** + * Tabs for a content with [ContentStyle.TabbedContent]. + * + * @see ContentStyle.TabbedContent] + */ +private data class ContentTab(val text: String, val tabbedContentTypes: List<TabbedContentType>) + fun List<SimpleAttr>.joinAttr() = joinToString(" ") { it.extraKey + "=" + it.extraValue } private fun String.stripDiv() = drop(5).dropLast(6) // TODO: Find a way to do it without arbitrary trims @@ -859,6 +980,7 @@ private val PageNode.isNavigable: Boolean get() = this !is RendererSpecificPage || strategy != RenderingStrategy.DoNothing private fun PropertyContainer<ContentNode>.extraHtmlAttributes() = allOfType<SimpleAttr>() +private fun PropertyContainer<ContentNode>.extraTabbedContentType() = this[TabbedContentTypeExtra] private val ContentNode.sourceSetsFilters: String get() = sourceSets.sourceSetIDs.joinToString(" ") { it.toString() } diff --git a/plugins/base/src/main/kotlin/translators/documentables/DefaultPageCreator.kt b/p |
