Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Output HTML per slide page as array by passing htmlAsArray env #119

Merged
merged 4 commits into from
Jan 18, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
### Added

- Add `env` argument to [`Marpit.render()`](https://marpit-api.marp.app/marpit#render) ([#118](https://github.com/marp-team/marpit/pull/118))
- Output HTML per slide page as array by passing `htmlAsArray` env ([#119](https://github.com/marp-team/marpit/pull/119))
- Update docs to explain SVG slide polyfill ([#117](https://github.com/marp-team/marpit/pull/117))

## v0.5.0 - 2018-12-28
Expand Down
24 changes: 24 additions & 0 deletions docs/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,30 @@ marpit.themeSet.default = marpit.themeSet.add('...')

## Advanced

### Output HTML as array

[`marpit.render()`](https://marpit-api.marp.app/marpit#render) has an optional second argument `env`, to pass data object into [markdown-it](https://markdown-it.github.io/markdown-it/#MarkdownIt.render).

When you passed `htmlAsArray: true`, the renderer will output HTML as array, that has consisted HTML per slide pages.

```javascript
const markdown = `
# Page 1

---

# Page 2
`

const { html } = marpit.render(markdown, { htmlAsArray: true })
/*
[ '<section id="1">\n<h1>Page 1</h1>\n</section>\n',
'<section id="2">\n<h1>Page 2</h1>\n</section>\n' ]
*/
```

!> Marpit initializer's `container` option is still enabled to scope CSS, so you have to render these HTMLs within `<div class="marpit">` or [customized element(s)](#package-customize-container-elements).

### Presenter notes

Marpit can collect HTML comments written in Markdown while rendering, except [directives](/directives). The collected `comments` are returned in the result of [`marpit.render()`](https://marpit-api.marp.app/marpit#render).
Expand Down
17 changes: 15 additions & 2 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ declare module '@marp-team/marpit' {

type MarpitHeadingDivider = 1 | 2 | 3 | 4 | 5 | 6

type MarpitRenderResult = {
html: string
type MarpitRenderResult<T = string> = {
html: T
css: string
comments: string[][]
}
Expand All @@ -29,6 +29,13 @@ declare module '@marp-team/marpit' {
inlineSVG?: boolean
}

namespace MarpitEnv {
export interface HTMLAsArray {
htmlAsArray: true
[key: string]: any
}
}

export class Marpit {
constructor(opts?: MarpitOptions)

Expand All @@ -40,9 +47,15 @@ declare module '@marp-team/marpit' {

protected lastComments?: MarpitRenderResult['comments']
protected lastGlobalDirectives?: { [directive: string]: any }
protected lastSlideTokens?: any[]
protected lastStyles?: string[]

render(
markdown: string,
env: MarpitEnv.HTMLAsArray
): MarpitRenderResult<string[]>
render(markdown: string, env?: any): MarpitRenderResult

use<P extends any[]>(
plugin: (
this: Marpit['markdown'],
Expand Down
67 changes: 67 additions & 0 deletions src/markdown/collect.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/** @module */

/**
* Marpit collect plugin.
*
* Collect parsed tokens per slide and comments except marked as used for
* internally. These will store to lastSlideTokens and lastComments member of
* Marpit instance. It would use in the returned object from
* {@link Marpit#render}.
*
* @alias module:markdown/collect
* @param {MarkdownIt} md markdown-it instance.
* @param {Marpit} marpit Marpit instance.
*/
function collect(md, marpit) {
md.core.ruler.push('marpit_collect', state => {
if (state.inlineMode) return

marpit.lastComments = []
marpit.lastSlideTokens = []

let currentPage

const collectComment = token => {
if (
currentPage >= 0 &&
!(token.meta && token.meta.marpitCommentParsed !== undefined)
)
marpit.lastComments[currentPage].push(token.content)
}

const collectable = () =>
currentPage >= 0 && marpit.lastSlideTokens[currentPage] !== undefined

for (const token of state.tokens) {
if (
token.type === 'marpit_slide_open' &&
token.meta &&
token.meta.marpitSlide !== undefined
) {
currentPage = token.meta.marpitSlide

if (
currentPage >= 0 &&
marpit.lastSlideTokens[currentPage] === undefined
) {
marpit.lastSlideTokens[currentPage] = [token]
marpit.lastComments[currentPage] = []
}
} else if (token.type === 'marpit_slide_close') {
if (collectable()) marpit.lastSlideTokens[currentPage].push(token)
currentPage = undefined
} else {
if (collectable()) marpit.lastSlideTokens[currentPage].push(token)

if (token.type === 'marpit_comment') {
collectComment(token)
} else if (token.type === 'inline') {
for (const t of token.children)
if (t.type === 'marpit_comment') collectComment(t)
}
}
}
})
}

export default collect
52 changes: 0 additions & 52 deletions src/markdown/collect_comment.js

This file was deleted.

20 changes: 16 additions & 4 deletions src/marpit.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import ThemeSet from './theme_set'
import { marpitContainer } from './element'
import marpitApplyDirectives from './markdown/directives/apply'
import marpitBackgroundImage from './markdown/background_image'
import marpitCollectComment from './markdown/collect_comment'
import marpitCollect from './markdown/collect'
import marpitComment from './markdown/comment'
import marpitContainerPlugin from './markdown/container'
import marpitHeaderAndFooter from './markdown/header_and_footer'
Expand Down Expand Up @@ -130,14 +130,14 @@ class Marpit {
.use(marpitSweep)
.use(marpitInlineSVG, this)
.use(marpitStyleAssign, this, { supportScoped: scopedStyle })
.use(marpitCollectComment, this)
.use(marpitCollect, this)

if (backgroundSyntax) md.use(marpitBackgroundImage)
}

/**
* @typedef {Object} Marpit~RenderResult
* @property {string} html Rendered HTML.
* @property {string|string[]} html Rendered HTML.
* @property {string} css Rendered CSS.
* @property {string[][]} comments Parsed HTML comments per slide pages,
* excepted YAML for directives. It would be useful for presenter notes.
Expand All @@ -148,6 +148,8 @@ class Marpit {
*
* @param {string} markdown A Markdown string.
* @param {Object} [env] Environment object for passing to markdown-it.
* @param {boolean} [env.htmlAsArray=false] Output rendered HTML as array per
* slide.
* @returns {Marpit~RenderResult} An object of rendering result.
*/
render(markdown, env = {}) {
Expand All @@ -167,9 +169,19 @@ class Marpit {
* @private
* @param {string} markdown A Markdown string.
* @param {Object} [env] Environment object for passing to markdown-it.
* @returns {string} The result string of rendering Markdown.
* @param {boolean} [env.htmlAsArray=false] Output rendered HTML as array per
* slide.
* @returns {string|string[]} The result string(s) of rendering Markdown.
*/
renderMarkdown(markdown, env = {}) {
if (env.htmlAsArray) {
this.markdown.parse(markdown, env)

return this.lastSlideTokens.map(slide =>
this.markdown.renderer.render(slide, this.markdown.options, env)
)
}

return this.markdown.render(markdown, env)
}

Expand Down
24 changes: 19 additions & 5 deletions test/markdown/collect_comment.js → test/markdown/collect.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import dedent from 'dedent'
import MarkdownIt from 'markdown-it'
import applyDirectives from '../../src/markdown/directives/apply'
import collectComment from '../../src/markdown/collect_comment'
import collect from '../../src/markdown/collect'
import comment from '../../src/markdown/comment'
import parseDirectives from '../../src/markdown/directives/parse'
import slide from '../../src/markdown/slide'

describe('Marpit collect comment plugin', () => {
describe('Marpit collect plugin', () => {
const themeSet = new Map()
themeSet.set('default', true)

Expand All @@ -21,11 +21,11 @@ describe('Marpit collect comment plugin', () => {
.use(slide)
.use(parseDirectives, { themeSet: marpitInstance.themeSet })
.use(applyDirectives)
.use(collectComment, marpitInstance)
.use(collect, marpitInstance)

const text = dedent`
---
frontMatter: would not correct
frontMatter: would not collect
---

# First page
Expand Down Expand Up @@ -53,7 +53,7 @@ describe('Marpit collect comment plugin', () => {

# Third page

<!-- theme: is-invalid-theme-but-not-collect-because-theme-iss-correct-directive -->
<!-- theme: is-invalid-theme-but-not-collect-because-theme-is-correct-directive -->

---

Expand All @@ -64,9 +64,23 @@ describe('Marpit collect comment plugin', () => {
const marpit = marpitStub()
md(marpit).renderInline(text)

expect(marpit.lastSlideTokens).toBeUndefined()
expect(marpit.lastComments).toBeUndefined()
})

it("collects parsed tokens and store to Marpit's lastSlideTokens member", () => {
const marpit = marpitStub()
const markdownIt = md(marpit)
const original = markdownIt.render(text)

expect(marpit.lastSlideTokens).toHaveLength(4)
expect(original).toBe(
marpit.lastSlideTokens
.map(tokens => markdownIt.renderer.render(tokens, markdownIt.options))
.join('')
)
})

it("collects comments and store to Marpit's lastComments member", () => {
const marpit = marpitStub()
md(marpit).render(text)
Expand Down
12 changes: 12 additions & 0 deletions test/marpit.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,18 @@ describe('Marpit', () => {
instance.render('Markdown', { env: 'env' })
expect(render).toBeCalledWith('Markdown', { env: 'env' })
})

context('when passed htmlAsArray prop as true', () => {
it('outputs HTML as array per slide', () => {
const { html } = new Marpit().render('# Page1\n***\n## Page2', {
htmlAsArray: true,
})

expect(html).toHaveLength(2)
expect(cheerio.load(html[0])('section#1 > h1')).toHaveLength(1)
expect(cheerio.load(html[1])('section#2 > h2')).toHaveLength(1)
})
})
})

context('with inlineSVG option', () => {
Expand Down