From f6effeb78aada06ad8c728a0af68aa4a73e166a1 Mon Sep 17 00:00:00 2001 From: Kevin Ansfield Date: Fri, 4 May 2018 14:59:39 +0100 Subject: [PATCH] Koenig - Versioned renderer (#9606) refs https://github.com/TryGhost/Ghost/issues/9505 - updates mobiledoc converter's `render` method to accept a `version` argument - `1` === Ghost 1.0's markdown-only renderer output - `2` === Koenig's full mobiledoc renderer output - switch between mobiledoc renderer versions in Post model's `onSaving` hook - version 1 by default - version 2 if Koenig is enabled (currently behind dev experiments config + labs flag) - version 2 if the post's mobiledoc is not compatible with the markdown-only renderer - "version 2" full-Koenig mobiledoc renderer output - wraps content in a `.kg-post` div - removes wrapper around markdown and html card output - adds classes to image card output including selected image size/style - standardises es6 usage across mobiledoc related files --- packages/kg-default-cards/lib/cards/hr.js | 2 + packages/kg-default-cards/lib/cards/html.js | 14 +-- packages/kg-default-cards/lib/cards/image.js | 10 +- packages/kg-default-cards/lib/cards/index.js | 12 ++- .../kg-default-cards/lib/cards/markdown.js | 21 ++-- .../kg-default-cards/test/cards/hr_spec.js | 15 +-- .../kg-default-cards/test/cards/html_spec.js | 40 +++----- .../kg-default-cards/test/cards/image_spec.js | 64 ++++++++++-- .../test/cards/markdown_spec.js | 98 +++++++++++++------ 9 files changed, 175 insertions(+), 101 deletions(-) diff --git a/packages/kg-default-cards/lib/cards/hr.js b/packages/kg-default-cards/lib/cards/hr.js index 3df54808ec..8ff7e9e0a9 100644 --- a/packages/kg-default-cards/lib/cards/hr.js +++ b/packages/kg-default-cards/lib/cards/hr.js @@ -1,3 +1,5 @@ +'use strict'; + module.exports = { name: 'hr', type: 'dom', diff --git a/packages/kg-default-cards/lib/cards/html.js b/packages/kg-default-cards/lib/cards/html.js index aec08b2571..31a9386357 100644 --- a/packages/kg-default-cards/lib/cards/html.js +++ b/packages/kg-default-cards/lib/cards/html.js @@ -2,20 +2,8 @@ module.exports = { name: 'html', type: 'dom', render(opts) { - let payload = opts.payload; - let dom = opts.env.dom; - let caption = ''; - - if (payload.caption) { - caption = `

${payload.caption}

`; - } - - let html = `
${payload.html}${caption}
`; - // use the SimpleDOM document to create a raw HTML section. // avoids parsing/rendering of potentially broken or unsupported HTML - let element = dom.createRawHTMLSection(html); - - return element; + return opts.env.dom.createRawHTMLSection(opts.payload.html); } }; diff --git a/packages/kg-default-cards/lib/cards/image.js b/packages/kg-default-cards/lib/cards/image.js index 2ed12d2958..18e1797279 100644 --- a/packages/kg-default-cards/lib/cards/image.js +++ b/packages/kg-default-cards/lib/cards/image.js @@ -3,12 +3,20 @@ module.exports = { type: 'dom', render(opts) { let payload = opts.payload; + // let version = opts.options.version; let dom = opts.env.dom; + let figure = dom.createElement('figure'); + figure.setAttribute('class', 'kg-image-card'); let img = dom.createElement('img'); - img.className = 'kg-card-image'; + let imgClass = 'kg-image'; + if (payload.imageStyle) { + imgClass = `${imgClass} kg-image--${payload.imageStyle}`; + } img.setAttribute('src', payload.src); + img.setAttribute('class', imgClass); + figure.appendChild(img); if (payload.caption) { diff --git a/packages/kg-default-cards/lib/cards/index.js b/packages/kg-default-cards/lib/cards/index.js index 045726d1ce..1cbca3a3ba 100644 --- a/packages/kg-default-cards/lib/cards/index.js +++ b/packages/kg-default-cards/lib/cards/index.js @@ -1,7 +1,9 @@ -var hr = require('./hr'), - html = require('./html'), - image = require('./image'), - markdown = require('./markdown'), - cardMarkdown = require('./card-markdown'); +'use strict'; + +const hr = require('./hr'); +const html = require('./html'); +const image = require('./image'); +const markdown = require('./markdown'); +const cardMarkdown = require('./card-markdown'); module.exports = [hr, html, image, markdown, cardMarkdown]; diff --git a/packages/kg-default-cards/lib/cards/markdown.js b/packages/kg-default-cards/lib/cards/markdown.js index 459dc4c92e..cc965a76d3 100644 --- a/packages/kg-default-cards/lib/cards/markdown.js +++ b/packages/kg-default-cards/lib/cards/markdown.js @@ -1,19 +1,22 @@ +'use strict'; + module.exports = { name: 'markdown', type: 'dom', render: function (opts) { - var converters = require('../converters'), - html, element; - + let converters = require('../converters'); + let payload = opts.payload; + let version = opts.options.version; // convert markdown to HTML ready for insertion into dom - html = '
' - + converters.markdownConverter.render(opts.payload.markdown || '') - + '
'; + let html = converters.markdownConverter.render(payload.markdown || ''); + + // Ghost 1.0's markdown-only renderer wrapped cards + if (version === 1) { + html = `
${html}
`; + } // use the SimpleDOM document to create a raw HTML section. // avoids parsing/rendering of potentially broken or unsupported HTML - element = opts.env.dom.createRawHTMLSection(html); - - return element; + return opts.env.dom.createRawHTMLSection(html); } }; diff --git a/packages/kg-default-cards/test/cards/hr_spec.js b/packages/kg-default-cards/test/cards/hr_spec.js index f52a9e696b..6814b35d82 100644 --- a/packages/kg-default-cards/test/cards/hr_spec.js +++ b/packages/kg-default-cards/test/cards/hr_spec.js @@ -1,17 +1,18 @@ -var should = require('should'), // jshint ignore:line - card = require('../../../../../server/lib/mobiledoc/cards/hr'), - SimpleDom = require('simple-dom'), - opts; +'use strict'; + +const should = require('should'); // jshint ignore:line +const card = require('../../../../../server/lib/mobiledoc/cards/hr'); +const SimpleDom = require('simple-dom'); +const serializer = new SimpleDom.HTMLSerializer(SimpleDom.voidMap); describe('HR card', function () { it('generates a horizontal rule', function () { - opts = { + let opts = { env: { dom: new SimpleDom.Document() } }; - var serializer = new SimpleDom.HTMLSerializer([]); - serializer.serialize(card.render(opts)).should.match('
'); + serializer.serialize(card.render(opts)).should.match('
'); }); }); diff --git a/packages/kg-default-cards/test/cards/html_spec.js b/packages/kg-default-cards/test/cards/html_spec.js index fc69be6245..39c130f820 100644 --- a/packages/kg-default-cards/test/cards/html_spec.js +++ b/packages/kg-default-cards/test/cards/html_spec.js @@ -1,11 +1,13 @@ -var should = require('should'), // jshint ignore:line - card = require('../../../../../server/lib/mobiledoc/cards/html'), - SimpleDom = require('simple-dom'), - opts; +'use strict'; + +const should = require('should'); // jshint ignore:line +const card = require('../../../../../server/lib/mobiledoc/cards/html'); +const SimpleDom = require('simple-dom'); +const serializer = new SimpleDom.HTMLSerializer(SimpleDom.voidMap); describe('HTML card', function () { it('HTML Card renders', function () { - opts = { + let opts = { env: { dom: new SimpleDom.Document() }, @@ -14,12 +16,11 @@ describe('HTML card', function () { } }; - var serializer = new SimpleDom.HTMLSerializer([]); - serializer.serialize(card.render(opts)).should.match('

HEADING

PARAGRAPH

'); + serializer.serialize(card.render(opts)).should.match('

HEADING

PARAGRAPH

'); }); it('Plain content renders', function () { - opts = { + let opts = { env: { dom: new SimpleDom.Document() }, @@ -28,12 +29,11 @@ describe('HTML card', function () { } }; - var serializer = new SimpleDom.HTMLSerializer([]); - serializer.serialize(card.render(opts)).should.match('
CONTENT
'); + serializer.serialize(card.render(opts)).should.match('CONTENT'); }); it('Invalid HTML returns', function () { - opts = { + let opts = { env: { dom: new SimpleDom.Document() }, @@ -42,22 +42,6 @@ describe('HTML card', function () { } }; - var serializer = new SimpleDom.HTMLSerializer([]); - serializer.serialize(card.render(opts)).should.match('

HEADING<

'); - }); - - it('Caption renders', function () { - opts = { - env: { - dom: new SimpleDom.Document() - }, - payload: { - html: '', - caption: 'Embed caption test' - } - }; - - var serializer = new SimpleDom.HTMLSerializer([]); - serializer.serialize(card.render(opts)).should.match('

Embed caption test

'); + serializer.serialize(card.render(opts)).should.match('

HEADING<'); }); }); diff --git a/packages/kg-default-cards/test/cards/image_spec.js b/packages/kg-default-cards/test/cards/image_spec.js index c3b5fc9031..6b5e18b1ca 100644 --- a/packages/kg-default-cards/test/cards/image_spec.js +++ b/packages/kg-default-cards/test/cards/image_spec.js @@ -1,11 +1,13 @@ -var should = require('should'), // jshint ignore:line - card = require('../../../../../server/lib/mobiledoc/cards/image'), - SimpleDom = require('simple-dom'), - opts; +'use strict'; + +const should = require('should'); // jshint ignore:line +const card = require('../../../../../server/lib/mobiledoc/cards/image'); +const SimpleDom = require('simple-dom'); +const serializer = new SimpleDom.HTMLSerializer(SimpleDom.voidMap); describe('Image card', function () { it('generates an image', function () { - opts = { + let opts = { env: { dom: new SimpleDom.Document() }, @@ -14,12 +16,11 @@ describe('Image card', function () { } }; - var serializer = new SimpleDom.HTMLSerializer([]); - serializer.serialize(card.render(opts)).should.match('
'); + serializer.serialize(card.render(opts)).should.eql('
'); }); it('generates an image with caption', function () { - opts = { + let opts = { env: { dom: new SimpleDom.Document() }, @@ -29,7 +30,50 @@ describe('Image card', function () { } }; - var serializer = new SimpleDom.HTMLSerializer([]); - serializer.serialize(card.render(opts)).should.match('
Test caption
'); + serializer.serialize(card.render(opts)).should.eql('
Test caption
'); + }); + + describe('sizes', function () { + it('standard', function () { + let opts = { + env: { + dom: new SimpleDom.Document() + }, + payload: { + src: 'https://www.ghost.org/image.png', + imageStyle: '' + } + }; + + serializer.serialize(card.render(opts)).should.eql('
'); + }); + + it('wide', function () { + let opts = { + env: { + dom: new SimpleDom.Document() + }, + payload: { + src: 'https://www.ghost.org/image.png', + imageStyle: 'wide' + } + }; + + serializer.serialize(card.render(opts)).should.eql('
'); + }); + + it('full', function () { + let opts = { + env: { + dom: new SimpleDom.Document() + }, + payload: { + src: 'https://www.ghost.org/image.png', + imageStyle: 'full' + } + }; + + serializer.serialize(card.render(opts)).should.eql('
'); + }); }); }); diff --git a/packages/kg-default-cards/test/cards/markdown_spec.js b/packages/kg-default-cards/test/cards/markdown_spec.js index 64e025f877..00cdeafe62 100644 --- a/packages/kg-default-cards/test/cards/markdown_spec.js +++ b/packages/kg-default-cards/test/cards/markdown_spec.js @@ -1,34 +1,76 @@ -var should = require('should'), // jshint ignore:line - card = require('../../../../../server/lib/mobiledoc/cards/markdown'), - SimpleDom = require('simple-dom'), - opts; +'use strict'; + +const should = require('should'); // jshint ignore:line +const card = require('../../../../../server/lib/mobiledoc/cards/markdown'); +const SimpleDom = require('simple-dom'); +const serializer = new SimpleDom.HTMLSerializer(SimpleDom.voidMap); describe('Markdown card', function () { - it('Markdown Card renders', function () { - opts = { - env: { - dom: new SimpleDom.Document() - }, - payload: { - markdown: '#HEADING\r\n- list\r\n- items' - } - }; - - var serializer = new SimpleDom.HTMLSerializer([]); - serializer.serialize(card.render(opts)).should.match('

HEADING

\n
    \n
  • list
  • \n
  • items
  • \n
\n
'); + describe('version 1', function () { + it('Markdown Card renders', function () { + let opts = { + env: { + dom: new SimpleDom.Document() + }, + payload: { + markdown: '#HEADING\r\n- list\r\n- items' + }, + options: { + version: 1 + } + }; + + serializer.serialize(card.render(opts)).should.match('

HEADING

\n
    \n
  • list
  • \n
  • items
  • \n
\n
'); + }); + + it('Accepts invalid HTML in markdown', function () { + let opts = { + env: { + dom: new SimpleDom.Document() + }, + payload: { + markdown: '#HEADING\r\n

Heading 2>' + }, + options: { + version: 1 + } + }; + + serializer.serialize(card.render(opts)).should.match('

HEADING

\n

Heading 2>

'); + }); }); - it('Accepts invalid HTML in markdown', function () { - opts = { - env: { - dom: new SimpleDom.Document() - }, - payload: { - markdown: '#HEADING\r\n

Heading 2>' - } - }; - - var serializer = new SimpleDom.HTMLSerializer([]); - serializer.serialize(card.render(opts)).should.match('

HEADING

\n

Heading 2>

'); + describe('version 2', function () { + it('Markdown Card renders', function () { + let opts = { + env: { + dom: new SimpleDom.Document() + }, + payload: { + markdown: '#HEADING\r\n- list\r\n- items' + }, + options: { + version: 2 + } + }; + + serializer.serialize(card.render(opts)).should.match('

HEADING

\n\n'); + }); + + it('Accepts invalid HTML in markdown', function () { + let opts = { + env: { + dom: new SimpleDom.Document() + }, + payload: { + markdown: '#HEADING\r\n

Heading 2>' + }, + options: { + version: 2 + } + }; + + serializer.serialize(card.render(opts)).should.match('

HEADING

\n

Heading 2>'); + }); }); });