diff --git a/core/src/main/kotlin/eu/iamgio/quarkdown/ast/quarkdown/inline/PageCounter.kt b/core/src/main/kotlin/eu/iamgio/quarkdown/ast/quarkdown/inline/PageCounter.kt new file mode 100644 index 00000000..4626bcc9 --- /dev/null +++ b/core/src/main/kotlin/eu/iamgio/quarkdown/ast/quarkdown/inline/PageCounter.kt @@ -0,0 +1,26 @@ +package eu.iamgio.quarkdown.ast.quarkdown.inline + +import eu.iamgio.quarkdown.ast.Node +import eu.iamgio.quarkdown.visitor.node.NodeVisitor + +/** + * A counter for the current or total page number. + * In case the current document type does not support page counting (e.g. plain document), + * a placeholder is used at rendering time. + * @param target whether the counter should display the current or total page number + */ +data class PageCounter(val target: Target) : Node { + enum class Target { + /** + * The current page number. + */ + CURRENT, + + /** + * The total amount of pages. + */ + TOTAL, + } + + override fun <T> accept(visitor: NodeVisitor<T>): T = visitor.visit(this) +} diff --git a/core/src/main/kotlin/eu/iamgio/quarkdown/ast/quarkdown/invisible/PageCounterInitializer.kt b/core/src/main/kotlin/eu/iamgio/quarkdown/ast/quarkdown/invisible/PageCounterInitializer.kt deleted file mode 100644 index 0f1ffc2e..00000000 --- a/core/src/main/kotlin/eu/iamgio/quarkdown/ast/quarkdown/invisible/PageCounterInitializer.kt +++ /dev/null @@ -1,20 +0,0 @@ -package eu.iamgio.quarkdown.ast.quarkdown.invisible - -import eu.iamgio.quarkdown.ast.Node -import eu.iamgio.quarkdown.document.page.PageMarginPosition -import eu.iamgio.quarkdown.visitor.node.NodeVisitor - -/** - * A non-visible node that triggers a property in paged documents that allows displaying a page counter on each page. - * @param content action that returns the text of the counter. - * Arguments: index of the current page and total amount of pages. - * These are strings instead of numbers since the arguments can be placeholders. - * e.g. when using PagedJS for HTML rendering, CSS properties `counter(page)` and `counter(pages)` are used. - * @param position position of the counter within the page - */ -data class PageCounterInitializer( - val content: (String, String) -> List<Node>, - val position: PageMarginPosition, -) : Node { - override fun <T> accept(visitor: NodeVisitor<T>) = visitor.visit(this) -} diff --git a/core/src/main/kotlin/eu/iamgio/quarkdown/rendering/html/BaseHtmlNodeRenderer.kt b/core/src/main/kotlin/eu/iamgio/quarkdown/rendering/html/BaseHtmlNodeRenderer.kt index 874ab178..a8aaba28 100644 --- a/core/src/main/kotlin/eu/iamgio/quarkdown/rendering/html/BaseHtmlNodeRenderer.kt +++ b/core/src/main/kotlin/eu/iamgio/quarkdown/rendering/html/BaseHtmlNodeRenderer.kt @@ -39,9 +39,9 @@ import eu.iamgio.quarkdown.ast.quarkdown.block.SlidesFragment import eu.iamgio.quarkdown.ast.quarkdown.block.Stacked import eu.iamgio.quarkdown.ast.quarkdown.block.TableOfContentsView import eu.iamgio.quarkdown.ast.quarkdown.inline.MathSpan +import eu.iamgio.quarkdown.ast.quarkdown.inline.PageCounter import eu.iamgio.quarkdown.ast.quarkdown.inline.TextTransform import eu.iamgio.quarkdown.ast.quarkdown.inline.Whitespace -import eu.iamgio.quarkdown.ast.quarkdown.invisible.PageCounterInitializer import eu.iamgio.quarkdown.ast.quarkdown.invisible.PageMarginContentInitializer import eu.iamgio.quarkdown.ast.quarkdown.invisible.SlidesConfigurationInitializer import eu.iamgio.quarkdown.context.Context @@ -261,7 +261,7 @@ open class BaseHtmlNodeRenderer(context: Context) : TagNodeRenderer<HtmlTagBuild override fun visit(node: PageMarginContentInitializer): CharSequence = throw UnsupportedRenderException(node) - override fun visit(node: PageCounterInitializer): CharSequence = throw UnsupportedRenderException(node) + override fun visit(node: PageCounter): CharSequence = throw UnsupportedRenderException(node) override fun visit(node: SlidesConfigurationInitializer): CharSequence = throw UnsupportedRenderException(node) diff --git a/core/src/main/kotlin/eu/iamgio/quarkdown/rendering/html/QuarkdownHtmlNodeRenderer.kt b/core/src/main/kotlin/eu/iamgio/quarkdown/rendering/html/QuarkdownHtmlNodeRenderer.kt index e78439bf..b614ed88 100644 --- a/core/src/main/kotlin/eu/iamgio/quarkdown/rendering/html/QuarkdownHtmlNodeRenderer.kt +++ b/core/src/main/kotlin/eu/iamgio/quarkdown/rendering/html/QuarkdownHtmlNodeRenderer.kt @@ -21,9 +21,9 @@ import eu.iamgio.quarkdown.ast.quarkdown.block.SlidesFragment import eu.iamgio.quarkdown.ast.quarkdown.block.Stacked import eu.iamgio.quarkdown.ast.quarkdown.block.TableOfContentsView import eu.iamgio.quarkdown.ast.quarkdown.inline.MathSpan +import eu.iamgio.quarkdown.ast.quarkdown.inline.PageCounter import eu.iamgio.quarkdown.ast.quarkdown.inline.TextTransform import eu.iamgio.quarkdown.ast.quarkdown.inline.Whitespace -import eu.iamgio.quarkdown.ast.quarkdown.invisible.PageCounterInitializer import eu.iamgio.quarkdown.ast.quarkdown.invisible.PageMarginContentInitializer import eu.iamgio.quarkdown.ast.quarkdown.invisible.SlidesConfigurationInitializer import eu.iamgio.quarkdown.context.Context @@ -220,23 +220,19 @@ class QuarkdownHtmlNodeRenderer(context: Context) : BaseHtmlNodeRenderer(context // In slides and paged documents, these elements are copied to each page through the slides.js or paged.js script. div("page-margin-content page-margin-${node.position.asCSS}", node.children) - override fun visit(node: PageCounterInitializer) = - visit( - PageMarginContentInitializer( - children = - node.content( - // The current page number. - tagBuilder("span") - .`class`("current-page-number") - .build(), - // The total amount of pages. - tagBuilder("span") - .`class`("total-page-number") - .build(), - ), - position = node.position, - ), - ) + override fun visit(node: PageCounter) = + // The current or total page number. + // The actual number is filled by a script at runtime + // (either slides.js or paged.js, depending on the document type). + buildTag("span") { + +"-" // The default placeholder in case it is not filled by a script (e.g. plain documents). + `class`( + when (node.target) { + PageCounter.Target.CURRENT -> "current-page-number" + PageCounter.Target.TOTAL -> "total-page-number" + }, + ) + } override fun visit(node: SlidesConfigurationInitializer): CharSequence = buildTag("script") { diff --git a/core/src/main/kotlin/eu/iamgio/quarkdown/visitor/node/NodeVisitor.kt b/core/src/main/kotlin/eu/iamgio/quarkdown/visitor/node/NodeVisitor.kt index 002f4ba4..94dfb128 100644 --- a/core/src/main/kotlin/eu/iamgio/quarkdown/visitor/node/NodeVisitor.kt +++ b/core/src/main/kotlin/eu/iamgio/quarkdown/visitor/node/NodeVisitor.kt @@ -39,9 +39,9 @@ import eu.iamgio.quarkdown.ast.quarkdown.block.SlidesFragment import eu.iamgio.quarkdown.ast.quarkdown.block.Stacked import eu.iamgio.quarkdown.ast.quarkdown.block.TableOfContentsView import eu.iamgio.quarkdown.ast.quarkdown.inline.MathSpan +import eu.iamgio.quarkdown.ast.quarkdown.inline.PageCounter import eu.iamgio.quarkdown.ast.quarkdown.inline.TextTransform import eu.iamgio.quarkdown.ast.quarkdown.inline.Whitespace -import eu.iamgio.quarkdown.ast.quarkdown.invisible.PageCounterInitializer import eu.iamgio.quarkdown.ast.quarkdown.invisible.PageMarginContentInitializer import eu.iamgio.quarkdown.ast.quarkdown.invisible.SlidesConfigurationInitializer @@ -140,13 +140,13 @@ interface NodeVisitor<T> { fun visit(node: TextTransform): T + fun visit(node: PageCounter): T + fun visit(node: SlidesFragment): T // Quarkdown invisible nodes fun visit(node: PageMarginContentInitializer): T - fun visit(node: PageCounterInitializer): T - fun visit(node: SlidesConfigurationInitializer): T } diff --git a/stdlib/src/main/kotlin/eu/iamgio/quarkdown/stdlib/Document.kt b/stdlib/src/main/kotlin/eu/iamgio/quarkdown/stdlib/Document.kt index 5c2eb649..15027a69 100644 --- a/stdlib/src/main/kotlin/eu/iamgio/quarkdown/stdlib/Document.kt +++ b/stdlib/src/main/kotlin/eu/iamgio/quarkdown/stdlib/Document.kt @@ -3,9 +3,8 @@ package eu.iamgio.quarkdown.stdlib import eu.iamgio.quarkdown.ast.InlineMarkdownContent import eu.iamgio.quarkdown.ast.MarkdownContent import eu.iamgio.quarkdown.ast.base.block.Heading -import eu.iamgio.quarkdown.ast.base.inline.Text import eu.iamgio.quarkdown.ast.quarkdown.block.TableOfContentsView -import eu.iamgio.quarkdown.ast.quarkdown.invisible.PageCounterInitializer +import eu.iamgio.quarkdown.ast.quarkdown.inline.PageCounter import eu.iamgio.quarkdown.ast.quarkdown.invisible.PageMarginContentInitializer import eu.iamgio.quarkdown.context.Context import eu.iamgio.quarkdown.context.MutableContext @@ -25,7 +24,6 @@ import eu.iamgio.quarkdown.function.value.NodeValue import eu.iamgio.quarkdown.function.value.OutputValue import eu.iamgio.quarkdown.function.value.StringValue import eu.iamgio.quarkdown.function.value.VoidValue -import eu.iamgio.quarkdown.function.value.data.Lambda import eu.iamgio.quarkdown.function.value.wrappedAsValue import eu.iamgio.quarkdown.pipeline.error.IOPipelineException @@ -44,7 +42,8 @@ val Document: Module = ::pageFormat, ::pageMarginContent, ::footer, - ::pageCounter, + ::currentPage, + ::totalPages, ::autoPageBreak, ::disableAutoPageBreak, ::marker, @@ -242,34 +241,22 @@ fun footer(content: MarkdownContent): NodeValue = ) /** - * Sets the global page counter for a paged document. - * @param position position of the counter within the page - * @param text action that returns the text of the counter. - * Accepts two arguments: index of the current page and total amount of pages. - * Markdown content is not supported. - * @return a wrapped [PageCounterInitializer] node + * Displays the index (beginning from 1) of the page this element lies in. + * In case the current document type does not support page counting (e.g. plain document), + * a placeholder is used. + * @return a [PageCounter] node */ -@Name("pagecounter") -fun pageCounter( - @Injected context: Context, - position: PageMarginPosition = PageMarginPosition.BOTTOM_CENTER, - text: Lambda = - Lambda(context) { (current, total), _ -> - "$current / $total".wrappedAsValue() - }, -): NodeValue = - PageCounterInitializer( - content = { current, total -> - val textValue = - text.invoke<String, StringValue>( - StringValue(current), - StringValue(total), - ).unwrappedValue +@Name("currentpage") +fun currentPage() = PageCounter(PageCounter.Target.CURRENT).wrappedAsValue() - listOf(Text(textValue)) - }, - position, - ).wrappedAsValue() +/** + * Displays the total amount of pages in the document. + * In case the current document type does not support page counting (e.g. plain document), + * a placeholder is used. + * @return a [PageCounter] node + */ +@Name("totalpages") +fun totalPages() = PageCounter(PageCounter.Target.TOTAL).wrappedAsValue() /** * Sets a new automatic page break threshold when a heading is found: