diff --git a/docs/directives.md b/docs/directives.md index 7b4d3f2..7948c7f 100644 --- a/docs/directives.md +++ b/docs/directives.md @@ -181,7 +181,7 @@ It is useful when you want to create a slide deck from a plain Markdown. Even if ### Pagination -We support a pagination by the `paginate` local directive. +We support pagination by the `paginate` local directive. ```markdown @@ -189,29 +189,82 @@ We support a pagination by the `paginate` local directive. You would be able to see a page number of slide in the lower right. ``` +#### Configuring pagination + +There are 2 things happening on each slide: + +- the page number is rendered _and_ +- the page number is being incremented. + +You can control both of these with the `paginate` directive: + +| `paginate` | Page number | Increment | +| ---------- | ----------- | --------- | +| `true` | Show | Yes | +| `false` | Hide | Yes | +| `hold` | Show | No | +| `skip` | Hide | No | + #### Skip pagination on title slide -Simply you have to move a definition of `paginate` directive to an inside of a second page. +A common use case is excluding the title slide from pagination. +For this you simply have to define the `paginate` directive on the second page instead of the first. ```markdown # Title slide -This page will not paginate by lack of `paginate` local directive. +This page will not have pagination by lack of the `paginate` directive. --- -It will paginate slide from a this page. +Pagination will render from this slide onwards (starting at 2). +``` + +Or you can use the spot directive. + +```markdown +--- +paginate: true +_paginate: false # or use `_paginate: skip` +--- +``` + +#### `paginate: skip` and `paginate: hold` + +To both exclude a page from pagination and hide the pagination at the same time use `skip`: + +```markdown + + +# Slide to exclude + +This page will not update the page number and also not show the pagination ``` -Or also can use the spot directive. +You can exclude a page from pagination but keep the pagination visible using `hold`: ```markdown --- paginate: true -_paginate: false --- + +# Slide 1 + +[](./assets/image_01.png) + +> Page 1 of 1 + +--- + + + +# Slide 2 + +[](./assets/image_02.png) + +> Page 1 of 1 ``` ### Header and footer diff --git a/src/markdown/directives/apply.js b/src/markdown/directives/apply.js index d481d76..74af371 100644 --- a/src/markdown/directives/apply.js +++ b/src/markdown/directives/apply.js @@ -34,6 +34,25 @@ function _apply(md, opts = {}) { (state) => { if (state.inlineMode) return + // compute the total number of skipped pages + let totalSkippedSlides = 0 + for (const token of state.tokens) { + const { marpitDirectives } = token.meta || {} + if ( + marpitDirectives && + (marpitDirectives.paginate === 'hold' || + marpitDirectives.paginate === 'skip') + ) { + totalSkippedSlides++ + } + } + + // keep track of slides that were skipped using one of the following + // directives: + // `paginate: skip`, `_paginate: skip`, + // `paginate: hold`, or `_paginate: hold + let currentSkippedSlides = 0 + for (const token of state.tokens) { const { marpitDirectives, marpitSlide, marpitSlideTotal } = token.meta || {} @@ -85,8 +104,23 @@ function _apply(md, opts = {}) { } if (marpitDirectives.paginate) { - token.attrSet('data-marpit-pagination', marpitSlide + 1) - token.attrSet('data-marpit-pagination-total', marpitSlideTotal) + if ( + marpitDirectives.paginate === 'hold' || + marpitDirectives.paginate === 'skip' + ) { + currentSkippedSlides++ + } + + if (marpitDirectives.paginate !== 'skip') { + token.attrSet( + 'data-marpit-pagination', + marpitSlide - currentSkippedSlides + 1 + ) + token.attrSet( + 'data-marpit-pagination-total', + marpitSlideTotal - totalSkippedSlides + ) + } } if (marpitDirectives.header) diff --git a/src/markdown/directives/directives.js b/src/markdown/directives/directives.js index ebf88f0..8bda455 100644 --- a/src/markdown/directives/directives.js +++ b/src/markdown/directives/directives.js @@ -78,7 +78,11 @@ export const locals = Object.assign(Object.create(null), { color: (v) => ({ color: v }), footer: (v) => (typeof v === 'string' ? { footer: v } : {}), header: (v) => (typeof v === 'string' ? { header: v } : {}), - paginate: (v) => ({ paginate: (v || '').toLowerCase() === 'true' }), + paginate: (v) => ({ + paginate: ['hold', 'skip'].includes(v) + ? v + : (v || '').toLowerCase() === 'true', + }), }) export default [...Object.keys(globals), ...Object.keys(locals)] diff --git a/test/markdown/directives/apply.js b/test/markdown/directives/apply.js index efaa305..fea7584 100644 --- a/test/markdown/directives/apply.js +++ b/test/markdown/directives/apply.js @@ -219,9 +219,55 @@ describe('Marpit directives apply plugin', () => { # Slide 1 + Pagination is not rendered + --- ## Slide 2 + + Pagination is rendered (2 of 2) + ` + + const $ = load(mdForTest().render(paginateDirs)) + const sections = $('section') + + expect(sections.eq(0).data('marpit-pagination')).toBeUndefined() + expect(sections.eq(0).data('marpit-pagination-total')).toBeUndefined() + expect(sections.eq(1).data('marpit-pagination')).toBe(2) + expect(sections.eq(1).data('marpit-pagination-total')).toBe(2) + }) + }) + + describe('Paginate with skipped slides', () => { + it('applies data-marpit-pagination attribute with a _paginate:hold slide', () => { + const paginateDirs = dedent` + --- + paginate: true + _paginate: + --- + + # Slide 1 + + - Page is counted (1 of 2) + - Pagination is not rendered + + --- + + + + ## Slide 2 + + - Page is not counted + - Pagination is rendered (1 of 2) + + --- + + ## Slide 3 + + - Page is counted + - Pagination is rendered (2 of 2) ` const $ = load(mdForTest().render(paginateDirs)) @@ -229,8 +275,52 @@ describe('Marpit directives apply plugin', () => { expect(sections.eq(0).data('marpit-pagination')).toBeUndefined() expect(sections.eq(0).data('marpit-pagination-total')).toBeUndefined() - expect(sections.eq(1).data('marpit-pagination')).toBeTruthy() + expect(sections.eq(1).data('marpit-pagination')).toBe(1) expect(sections.eq(1).data('marpit-pagination-total')).toBe(2) + expect(sections.eq(2).data('marpit-pagination')).toBe(2) + expect(sections.eq(2).data('marpit-pagination-total')).toBe(2) + }) + + it('applies data-marpit-pagination attribute with a _paginate:skip slide', () => { + const paginateDirs = dedent` + --- + paginate: true + _paginate: + --- + + # Slide 1 + + - Page is counted (1 of 2) + - Pagination is not rendered + + --- + + + + ## Slide 2 + + - Page is not counted + - Pagination is not rendered (1 of 2) + + --- + + ## Slide 3 + + - Page is counted + - Pagination is rendered (2 of 2) + ` + + const $ = load(mdForTest().render(paginateDirs)) + const sections = $('section') + + expect(sections.eq(0).data('marpit-pagination')).toBeUndefined() + expect(sections.eq(0).data('marpit-pagination-total')).toBeUndefined() + expect(sections.eq(1).data('marpit-pagination')).toBeUndefined() + expect(sections.eq(1).data('marpit-pagination-total')).toBeUndefined() + expect(sections.eq(2).data('marpit-pagination')).toBe(2) + expect(sections.eq(2).data('marpit-pagination-total')).toBe(2) }) }) })