diff options
author | Błażej Kardyś <bkardys@virtuslab.com> | 2020-08-19 15:42:29 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-08-19 15:42:29 +0200 |
commit | 6bd58a22b06c6e879b8e93ade631ca6f119976e3 (patch) | |
tree | 737ab304f41cc9efa64457acde4144aa7c852ffb /plugins/javadoc/src/main | |
parent | 3100728f92e8d4ce828609d7447c3b486230218a (diff) | |
download | dokka-6bd58a22b06c6e879b8e93ade631ca6f119976e3.tar.gz dokka-6bd58a22b06c6e879b8e93ade631ca6f119976e3.tar.bz2 dokka-6bd58a22b06c6e879b8e93ade631ca6f119976e3.zip |
Index page for javadoc (#1244)
Diffstat (limited to 'plugins/javadoc/src/main')
11 files changed, 238 insertions, 43 deletions
diff --git a/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/JavadocPageCreator.kt b/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/JavadocPageCreator.kt index 20fe9831..01adf767 100644 --- a/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/JavadocPageCreator.kt +++ b/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/JavadocPageCreator.kt @@ -42,6 +42,7 @@ open class JavadocPageCreator( name = c.name.orEmpty(), content = contentForClasslike(c), dri = setOf(c.dri), + brief = c.brief(), signature = signatureForNode(c, jvm), description = c.descriptionToContentNodes(), constructors = (c as? WithConstructors)?.constructors?.mapNotNull { it.toJavadocFunction() }.orEmpty(), diff --git a/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/location/JavadocLocationProvider.kt b/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/location/JavadocLocationProvider.kt index 3359b32f..359cfef0 100644 --- a/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/location/JavadocLocationProvider.kt +++ b/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/location/JavadocLocationProvider.kt @@ -33,6 +33,8 @@ class JavadocLocationProvider(pageRoot: RootPageNode, dokkaContext: DokkaContext listOfNotNull(page.dri.first().classNames) else if (page is JavadocPackagePageNode) listOf(packagePath, "package-summary") + else if (page is IndexPage) + listOf("index-files", page.name) else listOf("index") else -> emptyList() @@ -120,6 +122,7 @@ class JavadocLocationProvider(pageRoot: RootPageNode, dokkaContext: DokkaContext JavadocContentKind.AllClasses -> it.dropLast(1) + "allclasses" JavadocContentKind.OverviewTree -> it.dropLast(1) + "overview-tree" JavadocContentKind.PackageTree -> it.dropLast(1) + "package-tree" + JavadocContentKind.IndexPage -> it.dropLast(1) + "index-1" else -> it } }?.relativeTo(pathIndex[contextRoot].orEmpty())?.let { if (skipExtension) "$it.html" else it }.orEmpty() diff --git a/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/pages/JavadocContentNodes.kt b/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/pages/JavadocContentNodes.kt index d1ccb73e..2b6ebb1c 100644 --- a/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/pages/JavadocContentNodes.kt +++ b/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/pages/JavadocContentNodes.kt @@ -6,7 +6,7 @@ import org.jetbrains.dokka.model.properties.PropertyContainer import org.jetbrains.dokka.pages.* enum class JavadocContentKind : Kind { - AllClasses, OverviewSummary, PackageSummary, Class, OverviewTree, PackageTree + AllClasses, OverviewSummary, PackageSummary, Class, OverviewTree, PackageTree, IndexPage } abstract class JavadocContentNode( diff --git a/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/pages/JavadocPageNodes.kt b/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/pages/JavadocPageNodes.kt index ec4591c3..7bc6d6d8 100644 --- a/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/pages/JavadocPageNodes.kt +++ b/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/pages/JavadocPageNodes.kt @@ -1,6 +1,7 @@ package org.jetbrains.dokka.javadoc.pages import com.intellij.psi.PsiClass +import org.jetbrains.dokka.DokkaConfiguration import org.jetbrains.dokka.Platform import org.jetbrains.dokka.analysis.DescriptorDocumentableSource import org.jetbrains.dokka.analysis.PsiDocumentableSource @@ -14,7 +15,6 @@ import org.jetbrains.dokka.pages.* import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.resolve.DescriptorUtils.getClassDescriptorForType -import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance interface JavadocPageNode : ContentPage @@ -23,6 +23,14 @@ interface WithJavadocExtra<T : Documentable> : WithExtraProperties<T> { throw IllegalStateException("Merging extras is not applicable for javadoc") } +interface WithIndexables { + fun getAllIndexables(): List<IndexableJavadocNode> +} + +interface WithBrief { + val brief: List<ContentNode> +} + class JavadocModulePageNode( override val name: String, override val content: JavadocContentNode, @@ -54,7 +62,13 @@ class JavadocPackagePageNode( override val documentable: Documentable? = null, override val children: List<PageNode> = emptyList(), override val embeddedResources: List<String> = listOf() -) : JavadocPageNode { +) : JavadocPageNode, WithIndexables, IndexableJavadocNode { + + override fun getAllIndexables(): List<IndexableJavadocNode> = + children.filterIsInstance<IndexableJavadocNode>().flatMap { + if (it is WithIndexables) it.getAllIndexables() + else listOf(it) + } override fun modified( name: String, @@ -83,44 +97,56 @@ class JavadocPackagePageNode( children, embeddedResources ) + + override fun getId(): String = name + + override fun getDRI(): DRI = dri.first() } -sealed class AnchorableJavadocNode(open val dri: DRI) +interface IndexableJavadocNode { + fun getId(): String + fun getDRI(): DRI +} + +sealed class AnchorableJavadocNode(open val name: String, open val dri: DRI) : IndexableJavadocNode { + override fun getId(): String = name + override fun getDRI(): DRI = dri +} data class JavadocEntryNode( override val dri: DRI, - val name: String, + override val name: String, val signature: JavadocSignatureContentNode, - val brief: List<ContentNode>, + override val brief: List<ContentNode>, override val extra: PropertyContainer<DEnumEntry> = PropertyContainer.empty() -): AnchorableJavadocNode(dri), WithJavadocExtra<DEnumEntry> +) : AnchorableJavadocNode(name, dri), WithJavadocExtra<DEnumEntry>, WithBrief data class JavadocParameterNode( override val dri: DRI, - val name: String, + override val name: String, val type: ContentNode, val description: List<ContentNode>, val typeBound: Bound, override val extra: PropertyContainer<DParameter> = PropertyContainer.empty() -): AnchorableJavadocNode(dri), WithJavadocExtra<DParameter> +) : AnchorableJavadocNode(name, dri), WithJavadocExtra<DParameter> data class JavadocPropertyNode( override val dri: DRI, - val name: String, + override val name: String, val signature: JavadocSignatureContentNode, - val brief: List<ContentNode>, + override val brief: List<ContentNode>, override val extra: PropertyContainer<DProperty> = PropertyContainer.empty() -): AnchorableJavadocNode(dri), WithJavadocExtra<DProperty> +) : AnchorableJavadocNode(name, dri), WithJavadocExtra<DProperty>, WithBrief data class JavadocFunctionNode( val signature: JavadocSignatureContentNode, - val brief: List<ContentNode>, + override val brief: List<ContentNode>, val description: List<ContentNode>, val parameters: List<JavadocParameterNode>, - val name: String, + override val name: String, override val dri: DRI, override val extra: PropertyContainer<DFunction> = PropertyContainer.empty() -): AnchorableJavadocNode(dri), WithJavadocExtra<DFunction> { +) : AnchorableJavadocNode(name, dri), WithJavadocExtra<DFunction>, WithBrief { val isInherited: Boolean get() { val extra = extra[InheritedFunction] @@ -141,15 +167,22 @@ class JavadocClasslikePageNode( val entries: List<JavadocEntryNode>, val classlikes: List<JavadocClasslikePageNode>, val properties: List<JavadocPropertyNode>, + override val brief: List<ContentNode>, override val documentable: Documentable? = null, override val children: List<PageNode> = emptyList(), override val embeddedResources: List<String> = listOf(), override val extra: PropertyContainer<DClasslike> = PropertyContainer.empty(), -) : JavadocPageNode, WithJavadocExtra<DClasslike> { +) : JavadocPageNode, WithJavadocExtra<DClasslike>, IndexableJavadocNode, WithIndexables, WithBrief { + + override fun getAllIndexables(): List<IndexableJavadocNode> = + methods + entries + classlikes.map { it.getAllIndexables() }.flatten() + this val kind: String? = documentable?.kind() val packageName = dri.first().packageName + override fun getId(): String = name + override fun getDRI(): DRI = dri.first() + override fun modified( name: String, children: List<PageNode> @@ -164,6 +197,7 @@ class JavadocClasslikePageNode( entries, classlikes, properties, + brief, documentable, children, embeddedResources, @@ -188,6 +222,7 @@ class JavadocClasslikePageNode( entries, classlikes, properties, + brief, documentable, children, embeddedResources, @@ -227,6 +262,43 @@ class AllClassesPage(val classes: List<JavadocClasslikePageNode>) : JavadocPageN } +class IndexPage( + val id: Int, + val elements: List<IndexableJavadocNode>, + val keys: List<Char>, + sourceSet: Set<DisplaySourceSet> + +) : JavadocPageNode { + override val name: String = "index-$id" + override val dri: Set<DRI> = setOf(DRI.topLevel) + override val documentable: Documentable? = null + override val children: List<PageNode> = emptyList() + override val embeddedResources: List<String> = listOf() + val title: String = "${keys[id - 1]}-index" + + override val content: ContentNode = EmptyNode( + DRI.topLevel, + ContentKind.Classlikes, + sourceSet + ) + + override fun modified( + name: String, + children: List<PageNode> + ): PageNode = + TODO() + + override fun modified( + name: String, + content: ContentNode, + dri: Set<DRI>, + embeddedResources: List<String>, + children: List<PageNode> + ): ContentPage = + TODO() + +} + class TreeViewPage( override val name: String, val packages: List<JavadocPackagePageNode>?, diff --git a/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/pages/htmlPreprocessors.kt b/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/pages/htmlPreprocessors.kt index 42276dd4..a2c3cf22 100644 --- a/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/pages/htmlPreprocessors.kt +++ b/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/pages/htmlPreprocessors.kt @@ -1,9 +1,11 @@ package org.jetbrains.dokka.javadoc.pages +import org.jetbrains.dokka.base.renderers.sourceSets import org.jetbrains.dokka.pages.* import org.jetbrains.dokka.transformers.pages.PageTransformer +import kotlin.collections.HashMap -val preprocessors = listOf(ResourcesInstaller, TreeViewInstaller, AllClassesPageInstaller) +val preprocessors = listOf(ResourcesInstaller, TreeViewInstaller, AllClassesPageInstaller, IndexGenerator) object ResourcesInstaller : PageTransformer { override fun invoke(input: RootPageNode): RootPageNode = input.modified( @@ -65,4 +67,27 @@ object AllClassesPageInstaller : PageTransformer { return input.modified(children = input.children + AllClassesPage(classes)) } +} + +object IndexGenerator: PageTransformer { + override fun invoke(input: RootPageNode): RootPageNode { + val elements = HashMap<Char, MutableSet<IndexableJavadocNode>>() + (input as JavadocModulePageNode).children.filterIsInstance<JavadocPackagePageNode>().forEach { + it.getAllIndexables().forEach { d -> + val name = when(d) { + is JavadocPageNode -> d.name + is AnchorableJavadocNode -> d.name + else -> null + } + if (name != null && name.isNotBlank()) { + elements.getOrPut(name[0].toUpperCase(), ::mutableSetOf).add(d) + } + } + elements.getOrPut(it.name[0].toUpperCase(), ::mutableSetOf).add(it) + } + val keys = elements.keys.sortedBy { it } + return input.modified(children = input.children + elements.entries.mapIndexed { i, (_, set) -> + IndexPage(i + 1, set.sortedBy { it.getId().toLowerCase() }, keys, input.sourceSets()) + }) + } }
\ No newline at end of file diff --git a/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/renderer/JavadocContentToTemplateMapTranslator.kt b/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/renderer/JavadocContentToTemplateMapTranslator.kt index 49ba1b25..ab12f50c 100644 --- a/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/renderer/JavadocContentToTemplateMapTranslator.kt +++ b/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/renderer/JavadocContentToTemplateMapTranslator.kt @@ -4,13 +4,15 @@ import org.jetbrains.dokka.javadoc.location.JavadocLocationProvider import org.jetbrains.dokka.javadoc.pages.* import org.jetbrains.dokka.javadoc.toNormalized import org.jetbrains.dokka.Platform -import org.jetbrains.dokka.base.resolvers.local.LocationProvider +import org.jetbrains.dokka.base.renderers.sourceSets import org.jetbrains.dokka.links.DRI +import org.jetbrains.dokka.links.parent import org.jetbrains.dokka.links.sureClassNames import org.jetbrains.dokka.model.ImplementedInterfaces import org.jetbrains.dokka.model.InheritedFunction import org.jetbrains.dokka.pages.* import org.jetbrains.dokka.plugability.DokkaContext +import org.jetbrains.dokka.utilities.formatToEndWithHtml import java.nio.file.Paths internal class JavadocContentToTemplateMapTranslator( @@ -34,11 +36,12 @@ internal class JavadocContentToTemplateMapTranslator( is JavadocPackagePageNode -> InnerTranslator(node).templateMapForPackagePageNode(node) is TreeViewPage -> InnerTranslator(node).templateMapForTreeViewPage(node) is AllClassesPage -> InnerTranslator(node).templateMapForAllClassesPage(node) + is IndexPage -> InnerTranslator(node).templateMapForIndexPage(node) else -> emptyMap() } private fun pathToRoot(node: JavadocPageNode): String { - return when(node){ + return when (node) { is JavadocModulePageNode -> "" else -> run { val link = locationProvider.resolve(node, skipExtension = true) @@ -50,19 +53,29 @@ internal class JavadocContentToTemplateMapTranslator( } } - private inner class InnerTranslator(val contextNode: PageNode) { + private inner class InnerTranslator(val contextNode: JavadocPageNode) { private val htmlTranslator = JavadocContentToHtmlTranslator(locationProvider, context) - fun templateMapForAllClassesPage(node: AllClassesPage): TemplateMap { - return mapOf( + fun templateMapForAllClassesPage(node: AllClassesPage): TemplateMap = + mapOf( "title" to "All Classes", "list" to node.classEntries ) - } - fun templateMapForTreeViewPage(node: TreeViewPage): TemplateMap { - return mapOf( + fun templateMapForIndexPage(node: IndexPage): TemplateMap = + mapOf( + "id" to node.id, + "title" to node.title, + "kind" to "indexPage", + "prevLetter" to if (node.id > 1) "index-${node.id - 1}" else "", + "nextLetter" to if (node.id < node.keys.size) "index-${node.id + 1}" else "", + "dictionary" to node.keys, + "elements" to node.elements.map { templateMapForIndexableNode(it) } + ) + + fun templateMapForTreeViewPage(node: TreeViewPage): TemplateMap = + mapOf( "title" to node.title, "name" to node.name, "kind" to node.kind, @@ -70,23 +83,20 @@ internal class JavadocContentToTemplateMapTranslator( "classGraph" to node.classGraph, "interfaceGraph" to node.interfaceGraph ) - } - fun templateMapForPackagePageNode(node: JavadocPackagePageNode): TemplateMap = - mapOf( - "kind" to "package" - ) + templateMapForJavadocContentNode(node.content) + fun templateMapForPackagePageNode(node: JavadocPackagePageNode): TemplateMap = mapOf( + "kind" to "package" + ) + templateMapForJavadocContentNode(node.content) - fun templateMapForFunctionNode(node: JavadocFunctionNode): TemplateMap = - mapOf( - "brief" to htmlForContentNodes(node.brief, contextNode), - "description" to htmlForContentNodes(node.description, contextNode), - "parameters" to node.parameters.map { templateMapForParameterNode(it) }, - "inlineParameters" to node.parameters.joinToString { renderInlineParameter(it) }, - "anchorLink" to locationProvider.anchorForFunctionNode(node), - "signature" to templateMapForSignatureNode(node.signature), - "name" to node.name - ) + fun templateMapForFunctionNode(node: JavadocFunctionNode): TemplateMap = mapOf( + "brief" to htmlForContentNodes(node.brief, contextNode), + "description" to htmlForContentNodes(node.description,contextNode), + "parameters" to node.parameters.map { templateMapForParameterNode(it) }, + "inlineParameters" to node.parameters.joinToString { renderInlineParameter(it) }, + "anchorLink" to locationProvider.anchorForFunctionNode(node), + "signature" to templateMapForSignatureNode(node.signature), + "name" to node.name + ) fun templateMapForClasslikeNode(node: JavadocClasslikePageNode): TemplateMap = mapOf( @@ -111,6 +121,43 @@ internal class JavadocContentToTemplateMapTranslator( "supertypes" to node.supertypes?.let { htmlForContentNode(it, contextNode) } ) + private fun IndexableJavadocNode.typeForIndexable() = when (this) { + is JavadocClasslikePageNode -> "class" + is JavadocFunctionNode -> "function" + is JavadocEntryNode -> "enum entry" + is JavadocParameterNode -> "parameter" + is JavadocPropertyNode -> "property" + is JavadocPackagePageNode -> "package" + else -> "" + } + + fun templateMapForIndexableNode(node: IndexableJavadocNode): TemplateMap { + val origin = node.getDRI().parent + return mapOf( + "address" to locationProvider.resolve(node.getDRI(), contextNode.sourceSets(), contextNode) + ?.formatToEndWithHtml().orEmpty(), + "type" to node.typeForIndexable(), + "isMember" to (node !is JavadocPackagePageNode), + "name" to if (node is JavadocFunctionNode) locationProvider.anchorForFunctionNode(node) else node.getId(), + "description" to ((node as? WithBrief)?.let { + htmlForContentNodes( + it.brief, + contextNode + ).takeIf { desc -> desc.isNotBlank() } + } ?: " "), + "origin" to origin.indexableOriginSignature(), + ) + } + + private fun DRI.indexableOriginSignature(): String { + val packageName = packageName?.takeIf { it.isNotBlank() } + val className = classNames?.let { + "<a href=${locationProvider.resolve(this, contextNode.sourceSets(), contextNode) + ?.formatToEndWithHtml().orEmpty()}>$it</a>" + } + return listOfNotNull(packageName, className).joinToString(".") + } + fun templateMapForJavadocContentNode(node: JavadocContentNode): TemplateMap = when (node) { is TitleNode -> templateMapForTitleNode(node) diff --git a/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/renderer/KorteJavadocRenderer.kt b/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/renderer/KorteJavadocRenderer.kt index 669f4979..20115ac8 100644 --- a/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/renderer/KorteJavadocRenderer.kt +++ b/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/renderer/KorteJavadocRenderer.kt @@ -48,6 +48,7 @@ class KorteJavadocRenderer(private val outputWriter: OutputWriter, val context: is JavadocClasslikePageNode -> "class.korte" is AllClassesPage -> "listPage.korte" is TreeViewPage -> "treePage.korte" + is IndexPage -> "indexPage.korte" else -> "" } diff --git a/plugins/javadoc/src/main/resources/views/components/bottomNavbar.korte b/plugins/javadoc/src/main/resources/views/components/bottomNavbar.korte index 789e3c54..a9d83e5c 100644 --- a/plugins/javadoc/src/main/resources/views/components/bottomNavbar.korte +++ b/plugins/javadoc/src/main/resources/views/components/bottomNavbar.korte @@ -13,7 +13,7 @@ </div> <a id="skip.navbar.bottom"> <!-- --> - </a></div> + </a> {% set type="bottom" %}{% include "components/subNav.korte" -%} <!-- ======== END OF BOTTOM NAVBAR ======= --> </nav> diff --git a/plugins/javadoc/src/main/resources/views/components/navList.korte b/plugins/javadoc/src/main/resources/views/components/navList.korte index e27bdecb..d18b44c4 100644 --- a/plugins/javadoc/src/main/resources/views/components/navList.korte +++ b/plugins/javadoc/src/main/resources/views/components/navList.korte @@ -22,6 +22,6 @@ <li><a href="package-tree.html">Tree</a></li> {% end %} <li>Deprecated</li> - <li>Index</li> + <li><a href="{{ pathToRoot }}index-files/index-1.html">Index</a></li> <li>Help</li> </ul>
\ No newline at end of file diff --git a/plugins/javadoc/src/main/resources/views/components/subNav.korte b/plugins/javadoc/src/main/resources/views/components/subNav.korte index aa0905cf..7869d747 100644 --- a/plugins/javadoc/src/main/resources/views/components/subNav.korte +++ b/plugins/javadoc/src/main/resources/views/components/subNav.korte @@ -1,6 +1,20 @@ <div class="subNav"> +{% if kind == "indexPage" %} + <ul class="navList"> + {%- if prevLetter != "" %} + <li><a href="{{ prevLetter }}.html">PREV LETTER</a></li> + {% else %} + <li>PREV LETTER</li> + {% endif -%} + {%- if nextLetter != "" %} + <li><a href="{{ nextLetter }}.html">NEXT LETTER</a></li> + {% else %} + <li>NEXT LETTER</li> + {% endif -%} + </ul> +{% end -%} <ul class="navList" id="allclasses_navbar_top" style="display: block;"> -<li><a href="{{ pathToRoot }}allclasses.html">All Classes</a></li> + <li><a href="{{ pathToRoot }}allclasses.html">All Classes</a></li> </ul> {% if type != "bottom" %} <ul class="navListSearch"> diff --git a/plugins/javadoc/src/main/resources/views/indexPage.korte b/plugins/javadoc/src/main/resources/views/indexPage.korte new file mode 100644 index 00000000..2881e86d --- /dev/null +++ b/plugins/javadoc/src/main/resources/views/indexPage.korte @@ -0,0 +1,32 @@ +{% extends "components/base.korte" %} +{% block content %} + +<main role="main"> + <div class="contentContainer"> + {% for key in dictionary %} + <a href="index-{{ loop.index }}.html">{{ key }}</a> + {% endfor %} + <h2 class="title">{{ dictionary[id - 1] }}</h2> + <dl> + {% for key in elements %} + <dt> + {% if key.isMember %} + <span class="memberNameLink"> + {% endif %} + <a href="{{ key.address }}">{{ key.name }}</a> + {% if key.isMember %} + </span> - {{ key.type }} in {{ key.origin|raw }} + {% else %} + - {{ key.type }} {{ key.name }} + {% endif %} + + </dt> + <dd>{{ key.description|raw }}</dd> + + {% endfor %} + </dl> + {% for key in dictionary %} + <a href="index-{{ loop.index }}.html">{{ key }}</a> + {% endfor %} + </div> +</main>
\ No newline at end of file |