mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-04-15 03:01:37 -05:00
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
This commit is contained in:
parent
58aa531813
commit
e953a1c3a8
16 changed files with 424 additions and 146 deletions
|
@ -1,3 +1,5 @@
|
|||
var softReturn = require('./soft-return');
|
||||
'use strict';
|
||||
|
||||
const softReturn = require('./soft-return');
|
||||
|
||||
module.exports = [softReturn];
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
name: 'soft-return',
|
||||
type: 'dom',
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
name: 'hr',
|
||||
type: 'dom',
|
||||
|
|
|
@ -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 = `<p>${payload.caption}</p>`;
|
||||
}
|
||||
|
||||
let html = `<div class="kg-card-html">${payload.html}${caption}</div>`;
|
||||
|
||||
// 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);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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 = '<div class="kg-card-markdown">'
|
||||
+ converters.markdownConverter.render(opts.payload.markdown || '')
|
||||
+ '</div>';
|
||||
let html = converters.markdownConverter.render(payload.markdown || '');
|
||||
|
||||
// Ghost 1.0's markdown-only renderer wrapped cards
|
||||
if (version === 1) {
|
||||
html = `<div class="kg-card-markdown">${html}</div>`;
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -36,11 +36,38 @@ var SimpleDom = require('simple-dom'),
|
|||
// }
|
||||
|
||||
module.exports = {
|
||||
render: function (mobiledoc) {
|
||||
var renderer = new Renderer(options),
|
||||
rendered = renderer.render(mobiledoc),
|
||||
serializer = new SimpleDom.HTMLSerializer(SimpleDom.voidMap),
|
||||
html = serializer.serializeChildren(rendered.result);
|
||||
// version 1 === Ghost 1.0 markdown-only mobiledoc
|
||||
// version 2 === Ghost 2.0 full mobiledoc
|
||||
render: function (mobiledoc, version) {
|
||||
version = version || 1;
|
||||
|
||||
// pass the version through to the card renderers.
|
||||
// create a new object here to avoid modifying the default options
|
||||
// object because the version can change per-render until 2.0 is released
|
||||
let versionedOptions = Object.assign({}, options, {
|
||||
cardOptions: {version}
|
||||
});
|
||||
|
||||
let renderer = new Renderer(versionedOptions);
|
||||
let rendered = renderer.render(mobiledoc);
|
||||
let serializer = new SimpleDom.HTMLSerializer(SimpleDom.voidMap);
|
||||
|
||||
// Koenig keeps a blank paragraph at the end of a doc but we want to
|
||||
// make sure it doesn't get rendered
|
||||
let lastChild = rendered.result.lastChild;
|
||||
if (lastChild && lastChild.tagName === 'P' && !lastChild.firstChild) {
|
||||
rendered.result.removeChild(lastChild);
|
||||
}
|
||||
|
||||
let html = serializer.serializeChildren(rendered.result);
|
||||
|
||||
// full version of Koenig wraps the content with a specific class to
|
||||
// be targetted with our default stylesheet for vertical rhythm and
|
||||
// card-specific styles
|
||||
if (version === 2) {
|
||||
html = `<div class="kg-post">\n${html}\n</div>`;
|
||||
}
|
||||
|
||||
return html;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -9,6 +9,7 @@ var _ = require('lodash'),
|
|||
htmlToText = require('html-to-text'),
|
||||
ghostBookshelf = require('./base'),
|
||||
config = require('../config'),
|
||||
labs = require('../services/labs'),
|
||||
converters = require('../lib/mobiledoc/converters'),
|
||||
urlService = require('../services/url'),
|
||||
relations = require('./relations'),
|
||||
|
@ -185,7 +186,7 @@ Post = ghostBookshelf.Model.extend({
|
|||
prevSlug = this.previous('slug'),
|
||||
publishedAt = this.get('published_at'),
|
||||
publishedAtHasChanged = this.hasDateChanged('published_at', {beforeWrite: true}),
|
||||
mobiledoc = this.get('mobiledoc'),
|
||||
mobiledoc = JSON.parse(this.get('mobiledoc') || null),
|
||||
generatedFields = ['html', 'plaintext'],
|
||||
tagsToSave,
|
||||
ops = [];
|
||||
|
@ -249,8 +250,37 @@ Post = ghostBookshelf.Model.extend({
|
|||
}
|
||||
});
|
||||
|
||||
// render mobiledoc to HTML. Switch render version if Koenig is enabled
|
||||
// or has been edited with Koenig and is no longer compatible with the
|
||||
// Ghost 1.0 markdown-only renderer
|
||||
// TODO: re-render all content and remove the version toggle for Ghost 2.0
|
||||
if (mobiledoc) {
|
||||
this.set('html', converters.mobiledocConverter.render(JSON.parse(mobiledoc)));
|
||||
let version = 1;
|
||||
let devExperimentsEnabled = config.get('enableDeveloperExperiments');
|
||||
let koenigEnabled = labs.isSet('koenigEditor') === true;
|
||||
|
||||
let mobiledocIsCompatibleWithV1 = function mobiledocIsCompatibleWithV1(doc) {
|
||||
if (doc
|
||||
&& doc.markups.length === 0
|
||||
&& doc.cards.length === 1
|
||||
&& doc.cards[0][0].match(/(?:card-)?markdown/)
|
||||
&& doc.sections.length === 1
|
||||
&& doc.sections[0].length === 2
|
||||
&& doc.sections[0][0] === 10
|
||||
&& doc.sections[0][1] === 0
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
if ((devExperimentsEnabled && koenigEnabled) || !mobiledocIsCompatibleWithV1(mobiledoc)) {
|
||||
version = 2;
|
||||
}
|
||||
|
||||
let html = converters.mobiledocConverter.render(mobiledoc, version);
|
||||
this.set('html', html);
|
||||
}
|
||||
|
||||
if (this.hasChanged('html') || !this.get('plaintext')) {
|
||||
|
|
|
@ -1,17 +1,18 @@
|
|||
var should = require('should'), // jshint ignore:line
|
||||
card = require('../../../../../server/lib/mobiledoc/atoms/soft-return'),
|
||||
SimpleDom = require('simple-dom'),
|
||||
opts;
|
||||
'use strict';
|
||||
|
||||
describe('Soft return card', function () {
|
||||
const should = require('should'); // jshint ignore:line
|
||||
const atom = require('../../../../../server/lib/mobiledoc/atoms/soft-return');
|
||||
const SimpleDom = require('simple-dom');
|
||||
const serializer = new SimpleDom.HTMLSerializer(SimpleDom.voidMap);
|
||||
|
||||
describe('Soft return atom', function () {
|
||||
it('generates a `br` tag', function () {
|
||||
opts = {
|
||||
let opts = {
|
||||
env: {
|
||||
dom: new SimpleDom.Document()
|
||||
}
|
||||
};
|
||||
|
||||
var serializer = new SimpleDom.HTMLSerializer([]);
|
||||
serializer.serialize(card.render(opts)).should.match('<br></br>');
|
||||
serializer.serialize(atom.render(opts)).should.match('<br>');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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('<hr></hr>');
|
||||
serializer.serialize(card.render(opts)).should.match('<hr>');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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('<div class="kg-card-html"><h1>HEADING</h1><p>PARAGRAPH</p></div>');
|
||||
serializer.serialize(card.render(opts)).should.match('<h1>HEADING</h1><p>PARAGRAPH</p>');
|
||||
});
|
||||
|
||||
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('<div class="kg-card-html">CONTENT</div>');
|
||||
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('<div class="kg-card-html"><h1>HEADING<</div>');
|
||||
});
|
||||
|
||||
it('Caption renders', function () {
|
||||
opts = {
|
||||
env: {
|
||||
dom: new SimpleDom.Document()
|
||||
},
|
||||
payload: {
|
||||
html: '<iframe src="http://vimeo.com"></iframe>',
|
||||
caption: 'Embed caption test'
|
||||
}
|
||||
};
|
||||
|
||||
var serializer = new SimpleDom.HTMLSerializer([]);
|
||||
serializer.serialize(card.render(opts)).should.match('<div class="kg-card-html"><iframe src="http://vimeo.com"></iframe><p>Embed caption test</p></div>');
|
||||
serializer.serialize(card.render(opts)).should.match('<h1>HEADING<');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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('<figure><img src="https://www.ghost.org/image.png"></img></figure>');
|
||||
serializer.serialize(card.render(opts)).should.eql('<figure class="kg-image-card"><img src="https://www.ghost.org/image.png" class="kg-image"></figure>');
|
||||
});
|
||||
|
||||
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('<figure><img src="https://www.ghost.org/image.png"></img><figcaption>Test caption</figcaption></figure>');
|
||||
serializer.serialize(card.render(opts)).should.eql('<figure class="kg-image-card"><img src="https://www.ghost.org/image.png" class="kg-image"><figcaption>Test caption</figcaption></figure>');
|
||||
});
|
||||
|
||||
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('<figure class="kg-image-card"><img src="https://www.ghost.org/image.png" class="kg-image"></figure>');
|
||||
});
|
||||
|
||||
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('<figure class="kg-image-card"><img src="https://www.ghost.org/image.png" class="kg-image kg-image--wide"></figure>');
|
||||
});
|
||||
|
||||
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('<figure class="kg-image-card"><img src="https://www.ghost.org/image.png" class="kg-image kg-image--full"></figure>');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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'
|
||||
}
|
||||
};
|
||||
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
|
||||
}
|
||||
};
|
||||
|
||||
var serializer = new SimpleDom.HTMLSerializer([]);
|
||||
serializer.serialize(card.render(opts)).should.match('<div class="kg-card-markdown"><h1 id="heading">HEADING</h1>\n<ul>\n<li>list</li>\n<li>items</li>\n</ul>\n</div>');
|
||||
serializer.serialize(card.render(opts)).should.match('<div class="kg-card-markdown"><h1 id="heading">HEADING</h1>\n<ul>\n<li>list</li>\n<li>items</li>\n</ul>\n</div>');
|
||||
});
|
||||
|
||||
it('Accepts invalid HTML in markdown', function () {
|
||||
let opts = {
|
||||
env: {
|
||||
dom: new SimpleDom.Document()
|
||||
},
|
||||
payload: {
|
||||
markdown: '#HEADING\r\n<h2>Heading 2>'
|
||||
},
|
||||
options: {
|
||||
version: 1
|
||||
}
|
||||
};
|
||||
|
||||
serializer.serialize(card.render(opts)).should.match('<div class="kg-card-markdown"><h1 id="heading">HEADING</h1>\n<h2>Heading 2></div>');
|
||||
});
|
||||
});
|
||||
|
||||
it('Accepts invalid HTML in markdown', function () {
|
||||
opts = {
|
||||
env: {
|
||||
dom: new SimpleDom.Document()
|
||||
},
|
||||
payload: {
|
||||
markdown: '#HEADING\r\n<h2>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
|
||||
}
|
||||
};
|
||||
|
||||
var serializer = new SimpleDom.HTMLSerializer([]);
|
||||
serializer.serialize(card.render(opts)).should.match('<div class="kg-card-markdown"><h1 id="heading">HEADING</h1>\n<h2>Heading 2></div>');
|
||||
serializer.serialize(card.render(opts)).should.match('<h1 id="heading">HEADING</h1>\n<ul>\n<li>list</li>\n<li>items</li>\n</ul>\n');
|
||||
});
|
||||
|
||||
it('Accepts invalid HTML in markdown', function () {
|
||||
let opts = {
|
||||
env: {
|
||||
dom: new SimpleDom.Document()
|
||||
},
|
||||
payload: {
|
||||
markdown: '#HEADING\r\n<h2>Heading 2>'
|
||||
},
|
||||
options: {
|
||||
version: 2
|
||||
}
|
||||
};
|
||||
|
||||
serializer.serialize(card.render(opts)).should.match('<h1 id="heading">HEADING</h1>\n<h2>Heading 2>');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,34 +1,111 @@
|
|||
var should = require('should'), // jshint ignore:line
|
||||
converter = require('../../../../../server/lib/mobiledoc/converters/mobiledoc-converter');
|
||||
'use strict';
|
||||
|
||||
describe('Convert mobiledoc to HTML ', function () {
|
||||
var mobiledoc = {
|
||||
version: '0.3.1',
|
||||
atoms: [],
|
||||
cards: [
|
||||
['markdown',
|
||||
{
|
||||
pos: 'top',
|
||||
card_name: 'markdown',
|
||||
markdown: '#heading\n\n- list one\n- list two\n- list three'
|
||||
}
|
||||
],
|
||||
['html', {
|
||||
pos: 'top',
|
||||
card_name: 'html',
|
||||
html: '<p>HTML CARD</p>'
|
||||
}]
|
||||
],
|
||||
markups: [],
|
||||
sections: [
|
||||
[1, 'p', [
|
||||
[0, [], 0, 'test']
|
||||
]],
|
||||
[10, 0],
|
||||
[10, 1]
|
||||
]
|
||||
};
|
||||
it('Converts a mobiledoc to HTML', function () {
|
||||
converter.render(mobiledoc).should.match('<p>test</p><div class="kg-card-markdown"><h1 id="heading">heading</h1>\n<ul>\n<li>list one</li>\n<li>list two</li>\n<li>list three</li>\n</ul>\n</div><div class="kg-card-html"><p>HTML CARD</p></div>');
|
||||
const should = require('should'); // jshint ignore:line
|
||||
const converter = require('../../../../../server/lib/mobiledoc/converters/mobiledoc-converter');
|
||||
|
||||
describe('Mobiledoc converter', function () {
|
||||
// version 1 === Ghost 1.0 markdown-only renderer
|
||||
describe('version 1', function () {
|
||||
it('renders correctly', function () {
|
||||
let mobiledoc = {
|
||||
version: '0.3.1',
|
||||
atoms: [],
|
||||
cards: [
|
||||
['markdown',
|
||||
{
|
||||
pos: 'top',
|
||||
card_name: 'markdown',
|
||||
markdown: '#heading\n\n- list one\n- list two\n- list three'
|
||||
}
|
||||
]
|
||||
],
|
||||
markups: [],
|
||||
sections: [
|
||||
[10, 0]
|
||||
]
|
||||
};
|
||||
|
||||
converter.render(mobiledoc).should.eql('<div class="kg-card-markdown"><h1 id="heading">heading</h1>\n<ul>\n<li>list one</li>\n<li>list two</li>\n<li>list three</li>\n</ul>\n</div>');
|
||||
});
|
||||
});
|
||||
|
||||
// version 2 === Ghost 2.0 full Koenig renderer
|
||||
describe('version 2', function () {
|
||||
it('renders all default cards and atoms', function () {
|
||||
let mobiledoc = {
|
||||
version: '0.3.1',
|
||||
atoms: [
|
||||
['soft-return', '', {}]
|
||||
],
|
||||
cards: [
|
||||
['markdown', {
|
||||
markdown: '# Markdown card\nSome markdown'
|
||||
}],
|
||||
['hr', {}],
|
||||
['image', {
|
||||
imageStyle: 'wide',
|
||||
src: '/content/images/2018/04/NatGeo06.jpg',
|
||||
caption: 'Birdies'
|
||||
}],
|
||||
['html', {
|
||||
html: '<h2>HTML card</h2>\n<div><p>Some HTML</p></div>'
|
||||
}]
|
||||
],
|
||||
markups: [],
|
||||
sections: [
|
||||
[1, 'p', [
|
||||
[0, [], 0, 'One'],
|
||||
[1, [], 0, 0],
|
||||
[0, [], 0, 'Two']
|
||||
]],
|
||||
[10, 0],
|
||||
[1, 'p', [
|
||||
[0, [], 0, 'Three']
|
||||
]],
|
||||
[10, 1],
|
||||
[10, 2],
|
||||
[1, 'p', [
|
||||
[0, [], 0, 'Four']
|
||||
]],
|
||||
[10, 3],
|
||||
[1, 'p', []]
|
||||
]
|
||||
};
|
||||
|
||||
converter.render(mobiledoc, 2).should.eql('<div class="kg-post">\n<p>One<br>Two</p><h1 id="markdowncard">Markdown card</h1>\n<p>Some markdown</p>\n<p>Three</p><hr><figure class="kg-image-card"><img src="/content/images/2018/04/NatGeo06.jpg" class="kg-image kg-image--wide"><figcaption>Birdies</figcaption></figure><p>Four</p><h2>HTML card</h2>\n<div><p>Some HTML</p></div>\n</div>');
|
||||
});
|
||||
|
||||
it('wraps output with a .kg-post div', function () {
|
||||
let mobiledoc = {
|
||||
version: '0.3.1',
|
||||
atoms: [],
|
||||
cards: [],
|
||||
markups: [],
|
||||
sections: [
|
||||
[1, 'p', [
|
||||
[0, [], 0, 'Test']
|
||||
]]
|
||||
]
|
||||
};
|
||||
|
||||
converter.render(mobiledoc, 2).should.eql('<div class="kg-post">\n<p>Test</p>\n</div>');
|
||||
});
|
||||
|
||||
it('removes final blank paragraph', function () {
|
||||
let mobiledoc = {
|
||||
version: '0.3.1',
|
||||
atoms: [],
|
||||
cards: [],
|
||||
markups: [],
|
||||
sections: [
|
||||
[1, 'p', [
|
||||
[0, [], 0, 'Test']
|
||||
]],
|
||||
[1, 'p', []]
|
||||
]
|
||||
};
|
||||
|
||||
converter.render(mobiledoc, 2).should.eql('<div class="kg-post">\n<p>Test</p>\n</div>');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1889,4 +1889,69 @@ describe('Unit: models/post', function () {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Mobiledoc conversion', function () {
|
||||
let configUtils = require('../../utils/configUtils');
|
||||
let labs = require('../../../server/services/labs');
|
||||
let origLabs = _.cloneDeep(labs);
|
||||
let events;
|
||||
|
||||
beforeEach(function () {
|
||||
events = {
|
||||
post: []
|
||||
};
|
||||
|
||||
sandbox.stub(models.Post.prototype, 'emitChange').callsFake(function (event) {
|
||||
events.post.push({event: event, data: this.toJSON()});
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(configUtils.restore);
|
||||
|
||||
it('uses v2 if Koenig is enabled', function () {
|
||||
configUtils.set('enableDeveloperExperiments', true);
|
||||
sandbox.stub(labs, 'isSet').callsFake(function (key) {
|
||||
if (key === 'koenigEditor') {
|
||||
return true;
|
||||
}
|
||||
return origLabs.get(key);
|
||||
});
|
||||
|
||||
let newPost = testUtils.DataGenerator.forModel.posts[2];
|
||||
|
||||
return models.Post.add(
|
||||
newPost,
|
||||
testUtils.context.editor
|
||||
).then((post) => {
|
||||
should.exist(post);
|
||||
post.has('html').should.equal(true);
|
||||
post.get('html').should.equal('<div class="kg-post">\n<h2 id="testing">testing</h2>\n<p>mctesters</p>\n<ul>\n<li>test</li>\n<li>line</li>\n<li>items</li>\n</ul>\n\n</div>');
|
||||
});
|
||||
});
|
||||
|
||||
it('uses v2 if Koenig is disabled but post is not v1 compatible', function () {
|
||||
let newPost = testUtils.DataGenerator.forModel.posts[2];
|
||||
|
||||
newPost.mobiledoc = JSON.stringify({
|
||||
version: '0.3.1',
|
||||
atoms: [],
|
||||
cards: [],
|
||||
markups: [],
|
||||
sections: [
|
||||
[1, 'p', [
|
||||
[0, [], 0, 'Test']
|
||||
]]
|
||||
]
|
||||
});
|
||||
|
||||
return models.Post.add(
|
||||
newPost,
|
||||
testUtils.context.editor
|
||||
).then((post) => {
|
||||
should.exist(post);
|
||||
post.has('html').should.equal(true);
|
||||
post.get('html').should.equal('<div class="kg-post">\n<p>Test</p>\n</div>');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Add table
Reference in a new issue