diff --git a/CHANGELOG.md b/CHANGELOG.md index 48538567..7bc8be1a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,11 @@ ### Added -- Allow loose YAML parsing for custom directives ([#173](https://github.com/marp-team/marpit/pull/173)) +- Loose YAML parsing for custom directives ([#173](https://github.com/marp-team/marpit/pull/173)) + +### Changed + +- Allow customization the content of pagination ([#175](https://github.com/marp-team/marpit/pull/175)) ## v1.2.0 - 2019-06-17 diff --git a/docs/theme-css.md b/docs/theme-css.md index a746697f..d3a6012a 100644 --- a/docs/theme-css.md +++ b/docs/theme-css.md @@ -80,6 +80,25 @@ section::after { Please refer to [the default style of `section::after` in a scaffold theme](https://github.com/marp-team/marpit/blob/master/src/theme/scaffold.js) as well. +#### Customize content + +Marpit has a default content: `attr(data-marpit-pagination)`, indicates the current page number. Theme CSS can add other strings and attributes to the shown page number. + + + +```css +/* Add "Page" prefix and total page number */ +section::after { + content: 'Page ' attr(data-marpit-pagination) ' / ' attr(data-marpit-pagination-total); +} +``` + + + +`attr(data-marpit-pagination-total)` means the total page number of rendered slides. Thus, the above example would show as like as `Page 1 / 3`. + +!> Theme CSS must contain `attr(data-marpit-pagination)` in `content` declaration because user expects to show the page number by `paginate: true` directive. Marpit will ignore the whole of `content` declaration if the reference to that attribute is not contained. + ### Header and footer `header` and `footer` element have a possible to be rendered by [`header` / `footer` local directives](/directives#header-and-footer). _Marpit has no default style for these elements._ diff --git a/src/markdown/background_image/advanced.js b/src/markdown/background_image/advanced.js index feb94f1f..dac3da92 100644 --- a/src/markdown/background_image/advanced.js +++ b/src/markdown/background_image/advanced.js @@ -141,9 +141,14 @@ function advancedBackground(md) { class: open.attrGet('class'), style: style.toString(), 'data-marpit-advanced-background': 'pseudo', + + // For pagination styling 'data-marpit-pagination': open.attrGet( 'data-marpit-pagination' ), + 'data-marpit-pagination-total': open.attrGet( + 'data-marpit-pagination-total' + ), }) ) ) diff --git a/src/markdown/directives/apply.js b/src/markdown/directives/apply.js index 0ae52eeb..330c651c 100644 --- a/src/markdown/directives/apply.js +++ b/src/markdown/directives/apply.js @@ -35,7 +35,8 @@ function apply(md, opts = {}) { if (state.inlineMode) return for (const token of state.tokens) { - const { marpitDirectives, marpitSlide } = token.meta || {} + const { marpitDirectives, marpitSlide, marpitSlideTotal } = + token.meta || {} if (marpitDirectives) { const style = new InlineStyle(token.attrGet('style')) @@ -83,8 +84,10 @@ function apply(md, opts = {}) { style.set('background-size', marpitDirectives.backgroundSize) } - if (marpitDirectives.paginate) + if (marpitDirectives.paginate) { token.attrSet('data-marpit-pagination', marpitSlide + 1) + token.attrSet('data-marpit-pagination-total', marpitSlideTotal) + } if (marpitDirectives.header) token.meta.marpitHeader = marpitDirectives.header diff --git a/src/markdown/slide.js b/src/markdown/slide.js index 9a163097..6407b352 100644 --- a/src/markdown/slide.js +++ b/src/markdown/slide.js @@ -36,40 +36,40 @@ function slide(md, opts = {}) { md.core.ruler.push('marpit_slide', state => { if (state.inlineMode) return - state.tokens = split(state.tokens, t => t.type === 'hr', true).reduce( - (arr, slideTokens, idx) => { - const firstHr = - slideTokens[0] && slideTokens[0].type === 'hr' - ? slideTokens[0] - : undefined + const splittedTokens = split(state.tokens, t => t.type === 'hr', true) + const { length: marpitSlideTotal } = splittedTokens - const mapTarget = firstHr || slideTokens.find(t => t.map) + state.tokens = splittedTokens.reduce((arr, slideTokens, marpitSlide) => { + const firstHr = + slideTokens[0] && slideTokens[0].type === 'hr' + ? slideTokens[0] + : undefined - return [ - ...arr, - ...wrapTokens( - state.Token, - 'marpit_slide', - { - ...(opts.attributes || {}), - tag: 'section', - id: anchorCallback(idx), - open: { - block: true, - meta: { marpitSlide: idx, marpitSlideElement: 1 }, - map: mapTarget ? mapTarget.map : [0, 1], - }, - close: { - block: true, - meta: { marpitSlide: idx, marpitSlideElement: -1 }, - }, + const mapTarget = firstHr || slideTokens.find(t => t.map) + + return [ + ...arr, + ...wrapTokens( + state.Token, + 'marpit_slide', + { + ...(opts.attributes || {}), + tag: 'section', + id: anchorCallback(marpitSlide), + open: { + block: true, + meta: { marpitSlide, marpitSlideTotal, marpitSlideElement: 1 }, + map: mapTarget ? mapTarget.map : [0, 1], + }, + close: { + block: true, + meta: { marpitSlide, marpitSlideTotal, marpitSlideElement: -1 }, }, - slideTokens.slice(firstHr ? 1 : 0) - ), - ] - }, - [] - ) + }, + slideTokens.slice(firstHr ? 1 : 0) + ), + ] + }, []) }) } diff --git a/src/postcss/pagination.js b/src/postcss/pagination.js index ca9f61ab..98c82310 100644 --- a/src/postcss/pagination.js +++ b/src/postcss/pagination.js @@ -22,8 +22,8 @@ const plugin = postcss.plugin('marpit-postcss-pagination', () => css => { ) ) ) - rule.walkDecls(/^content$/, decl => { - if (decl.value !== 'attr(data-marpit-pagination)') + rule.walkDecls('content', decl => { + if (!decl.value.includes('attr(data-marpit-pagination)')) decl.replaceWith(`${decl.raw('before')}/* ${decl.toString()}; */`) }) }) diff --git a/test/markdown/background_image.js b/test/markdown/background_image.js index b2cb6f88..66d3cefe 100644 --- a/test/markdown/background_image.js +++ b/test/markdown/background_image.js @@ -405,7 +405,7 @@ describe('Marpit background image plugin', () => { ) ) - it('assigns data-marpit-pagination attribute to pseudo layer', () => { + it('assigns pagination attributes to pseudo layer', () => { const foreignObjects = $('svg > foreignObject') expect(foreignObjects).toHaveLength(3) @@ -414,11 +414,9 @@ describe('Marpit background image plugin', () => { true ) - expect( - pseudoFO - .find('> section.pseudo.layer') - .is('[data-marpit-pagination="1"]') - ).toBe(true) + const pseudoLayer = pseudoFO.find('> section.pseudo.layer') + expect(pseudoLayer.is('[data-marpit-pagination="1"]')).toBe(true) + expect(pseudoLayer.is('[data-marpit-pagination-total="1"]')).toBe(true) }) }) diff --git a/test/markdown/directives/apply.js b/test/markdown/directives/apply.js index 545c7818..c1356e46 100644 --- a/test/markdown/directives/apply.js +++ b/test/markdown/directives/apply.js @@ -228,7 +228,9 @@ describe('Marpit directives apply plugin', () => { 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')).toBeTruthy() + expect(sections.eq(1).data('marpit-pagination-total')).toBe(2) }) }) }) diff --git a/test/postcss/pagination.js b/test/postcss/pagination.js index 49d58f73..d6f0c34c 100644 --- a/test/postcss/pagination.js +++ b/test/postcss/pagination.js @@ -51,11 +51,20 @@ describe('Marpit PostCSS pagination plugin', () => { ])) it('keeps the content declaration of section::after for pagination', () => - expect( - run('section::after { content: attr(data-marpit-pagination); }') - ).resolves.toBe( - 'section::after { content: attr(data-marpit-pagination); }' - )) + Promise.all([ + expect( + run('section::after { content: attr(data-marpit-pagination); }') + ).resolves.toBe( + 'section::after { content: attr(data-marpit-pagination); }' + ), + expect( + run( + 'section::after { content: attr(data-marpit-pagination) "/" attr(data-marpit-pagination-total); }' + ) + ).resolves.toBe( + 'section::after { content: attr(data-marpit-pagination) "/" attr(data-marpit-pagination-total); }' + ), + ])) it('keeps the content declaration of section::after with combinators', () => Promise.all([