diff --git a/core/server/data/importer/importers/data/posts.js b/core/server/data/importer/importers/data/posts.js
index 61703dffe3..a53185f082 100644
--- a/core/server/data/importer/importers/data/posts.js
+++ b/core/server/data/importer/importers/data/posts.js
@@ -216,7 +216,7 @@ class PostsImporter extends BaseImporter {
});
model.mobiledoc = JSON.stringify(mobiledoc);
- model.html = mobiledocLib.renderers.mobiledocHtmlRenderer.render(JSON.parse(model.mobiledoc));
+ model.html = mobiledocLib.mobiledocHtmlRenderer.render(JSON.parse(model.mobiledoc));
}
this.sanitizePostsMeta(model);
});
diff --git a/core/server/data/migrations/versions/1.25/1-update-koenig-beta-html.js b/core/server/data/migrations/versions/1.25/1-update-koenig-beta-html.js
index c4d23e534d..bc813322d0 100644
--- a/core/server/data/migrations/versions/1.25/1-update-koenig-beta-html.js
+++ b/core/server/data/migrations/versions/1.25/1-update-koenig-beta-html.js
@@ -1,7 +1,7 @@
const _ = require('lodash');
const Promise = require('bluebird');
const common = require('../../../../lib/common');
-const renderers = require('../../../../lib/mobiledoc/renderers');
+const mobiledocLib = require('../../../../lib/mobiledoc');
const models = require('../../../../models');
const message1 = 'Migrating Koenig beta post\'s mobiledoc/HTML to 2.0 format';
const message2 = 'Migrated Koenig beta post\'s mobiledoc/HTML to 2.0 format';
@@ -54,7 +54,7 @@ module.exports.up = function regenerateKoenigBetaHTML(options) {
// re-render the html to remove .kg-post wrapper and adjust image classes
let version = 2;
- let html = renderers.mobiledocHtmlRenderer.render(mobiledoc, version);
+ let html = mobiledocLib.mobiledocHtmlRenderer.render(mobiledoc, version);
return models.Post.edit({
html,
diff --git a/core/server/data/migrations/versions/2.0/2-update-posts.js b/core/server/data/migrations/versions/2.0/2-update-posts.js
index 067e870e40..85ff782ea5 100644
--- a/core/server/data/migrations/versions/2.0/2-update-posts.js
+++ b/core/server/data/migrations/versions/2.0/2-update-posts.js
@@ -61,7 +61,7 @@ module.exports.up = (options) => {
// CASE: if mobiledoc field is null, we auto set a blank structure in the model layer
// CASE: if html field is null, we auto generate the html in the model layer
if (mobiledoc && post.html && post.html.match(/^
/)) {
- html = mobiledocLib.renderers.mobiledocHtmlRenderer.render(mobiledoc);
+ html = mobiledocLib.mobiledocHtmlRenderer.render(mobiledoc);
}
return localOptions
.transacting('posts')
@@ -101,7 +101,7 @@ module.exports.down = (options) => {
// CASE: revert: all new editor posts to the old editor format
if (mobiledoc && post.html) {
- html = mobiledocLib.renderers.mobiledocHtmlRenderer.render(mobiledoc, version);
+ html = mobiledocLib.mobiledocHtmlRenderer.render(mobiledoc, version);
}
return localOptions
diff --git a/core/server/data/migrations/versions/3.0/11-update-posts-html.js b/core/server/data/migrations/versions/3.0/11-update-posts-html.js
index 99b6527e0b..8f77a05d5b 100644
--- a/core/server/data/migrations/versions/3.0/11-update-posts-html.js
+++ b/core/server/data/migrations/versions/3.0/11-update-posts-html.js
@@ -2,7 +2,7 @@ const _ = require('lodash');
const Promise = require('bluebird');
const htmlToText = require('html-to-text');
const common = require('../../../../lib/common');
-const renderers = require('../../../../lib/mobiledoc/renderers');
+const mobiledocLib = require('../../../../lib/mobiledoc');
module.exports.config = {
transaction: true
@@ -36,7 +36,7 @@ module.exports.up = (options) => {
return Promise.resolve();
}
- const html = renderers.mobiledocHtmlRenderer.render(mobiledoc);
+ const html = mobiledocLib.mobiledocHtmlRenderer.render(mobiledoc);
const updatedAttrs = {
html: html
diff --git a/core/server/lib/mobiledoc/index.js b/core/server/lib/mobiledoc/index.js
index 631464718c..ebd426d9a6 100644
--- a/core/server/lib/mobiledoc/index.js
+++ b/core/server/lib/mobiledoc/index.js
@@ -1,7 +1,7 @@
const common = require('../common');
const config = require('../../config');
-let cardFactory, cards;
+let cardFactory, cards, mobiledocHtmlRenderer;
module.exports = {
get blankDocument() {
@@ -19,21 +19,19 @@ module.exports = {
},
get cards() {
- if (cards) {
- return cards;
+ if (!cards) {
+ const CardFactory = require('@tryghost/kg-card-factory');
+ const defaultCards = require('@tryghost/kg-default-cards');
+
+ cardFactory = new CardFactory({
+ siteUrl: config.get('url')
+ });
+
+ cards = defaultCards.map((card) => {
+ return cardFactory.createCard(card);
+ });
}
- const CardFactory = require('@tryghost/kg-card-factory');
- const defaultCards = require('@tryghost/kg-default-cards');
-
- cardFactory = new CardFactory({
- siteUrl: config.get('url')
- });
-
- cards = defaultCards.map((card) => {
- return cardFactory.createCard(card);
- });
-
return cards;
},
@@ -41,8 +39,22 @@ module.exports = {
return require('@tryghost/kg-default-atoms');
},
- get renderers() {
- return require('./renderers');
+ get mobiledocHtmlRenderer() {
+ if (!mobiledocHtmlRenderer) {
+ const MobiledocHtmlRenderer = require('@tryghost/kg-mobiledoc-html-renderer');
+
+ mobiledocHtmlRenderer = new MobiledocHtmlRenderer({
+ cards: this.cards,
+ atoms: this.atoms,
+ unknownCardHandler(args) {
+ common.logging.error(new common.errors.InternalServerError({
+ message: 'Mobiledoc card \'' + args.env.name + '\' not found.'
+ }));
+ }
+ });
+ }
+
+ return mobiledocHtmlRenderer;
},
get htmlToMobiledocConverter() {
diff --git a/core/server/lib/mobiledoc/renderers/index.js b/core/server/lib/mobiledoc/renderers/index.js
deleted file mode 100644
index 1d3fcbe4bc..0000000000
--- a/core/server/lib/mobiledoc/renderers/index.js
+++ /dev/null
@@ -1,5 +0,0 @@
-module.exports = {
- get mobiledocHtmlRenderer() {
- return require('./mobiledoc-html-renderer');
- }
-};
diff --git a/core/server/lib/mobiledoc/renderers/mobiledoc-html-renderer.js b/core/server/lib/mobiledoc/renderers/mobiledoc-html-renderer.js
deleted file mode 100644
index 6e3b4895d3..0000000000
--- a/core/server/lib/mobiledoc/renderers/mobiledoc-html-renderer.js
+++ /dev/null
@@ -1,115 +0,0 @@
-const SimpleDom = require('simple-dom');
-const Renderer = require('mobiledoc-dom-renderer').default;
-const common = require('../../common');
-const mobiledoc = require('../');
-const options = {
- dom: new SimpleDom.Document(),
- cards: mobiledoc.cards,
- atoms: mobiledoc.atoms,
- unknownCardHandler: function (args) {
- common.logging.error(new common.errors.InternalServerError({
- message: 'Mobiledoc card \'' + args.env.name + '\' not found.'
- }));
- }
-};
-
-const walkDom = function (node, func) {
- func(node);
- node = node.firstChild;
-
- while (node) {
- walkDom(node, func);
- node = node.nextSibling;
- }
-};
-
-const nodeTextContent = function (node) {
- let textContent = '';
-
- walkDom(node, (node) => {
- if (node.nodeType === 3) {
- textContent += node.nodeValue;
- }
- });
-
- return textContent;
-};
-
-// used to walk the rendered SimpleDOM output and modify elements before
-// serializing to HTML. Saves having a large HTML parsing dependency such as
-// jsdom that may break on malformed HTML in MD or HTML cards
-class DomModifier {
- constructor() {
- this.usedIds = [];
- }
-
- addHeadingId(node) {
- if (!node.firstChild || node.getAttribute('id')) {
- return;
- }
-
- let text = nodeTextContent(node);
- let id = text
- .replace(/[<>&"?]/g, '')
- .trim()
- .replace(/[^\w]/g, '-')
- .replace(/-{2,}/g, '-')
- .toLowerCase();
-
- if (this.usedIds[id] !== undefined) {
- this.usedIds[id] += 1;
- id += `-${this.usedIds[id]}`;
- } else {
- this.usedIds[id] = 0;
- }
-
- node.setAttribute('id', id);
- }
-
- modifyChildren(node) {
- walkDom(node, this.modify.bind(this));
- }
-
- modify(node) {
- // add id attributes to H* tags
- if (node.nodeType === 1 && node.nodeName.match(/^h\d$/i)) {
- this.addHeadingId(node);
- }
- }
-}
-
-module.exports = {
- render(mobiledoc, version) {
- /**
- * @deprecated: version 1 === Ghost 1.0 markdown-only mobiledoc
- * We keep the version 1 logic till Ghost 3.0 to be able to rollback posts.
- *
- * version 2 (latest) === Ghost 2.0 full mobiledoc
- */
- version = version || 2;
-
- const versionedOptions = Object.assign({}, options, {
- cardOptions: {version}
- });
-
- const renderer = new Renderer(versionedOptions);
- const rendered = renderer.render(mobiledoc);
- const 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
- const lastChild = rendered.result.lastChild;
- if (lastChild && lastChild.tagName === 'P') {
- if (!nodeTextContent(lastChild)) {
- rendered.result.removeChild(lastChild);
- }
- }
-
- // Walk the DOM output and modify nodes as needed
- // eg. to add ID attributes to heading elements
- const modifier = new DomModifier();
- modifier.modifyChildren(rendered.result);
-
- return serializer.serializeChildren(rendered.result);
- }
-};
diff --git a/core/server/models/post.js b/core/server/models/post.js
index 67dee5150e..a83eefe9f0 100644
--- a/core/server/models/post.js
+++ b/core/server/models/post.js
@@ -405,7 +405,7 @@ Post = ghostBookshelf.Model.extend({
// CASE: html is null, but mobiledoc exists (only important for migrations & importing)
if (this.hasChanged('mobiledoc') || (!this.get('html') && (options.migrating || options.importing))) {
try {
- this.set('html', mobiledocLib.renderers.mobiledocHtmlRenderer.render(JSON.parse(this.get('mobiledoc'))));
+ this.set('html', mobiledocLib.mobiledocHtmlRenderer.render(JSON.parse(this.get('mobiledoc'))));
} catch (err) {
throw new common.errors.ValidationError({
message: 'Invalid mobiledoc structure.',
diff --git a/package.json b/package.json
index 7d47084b8b..04dee7e95f 100644
--- a/package.json
+++ b/package.json
@@ -49,6 +49,7 @@
"@tryghost/kg-default-atoms": "1.0.0",
"@tryghost/kg-default-cards": "1.0.1",
"@tryghost/kg-markdown-html-renderer": "1.0.2",
+ "@tryghost/kg-mobiledoc-html-renderer": "^1.0.0",
"@tryghost/members-api": "0.18.0",
"@tryghost/members-ssr": "0.7.4",
"@tryghost/mw-session-from-token": "0.1.0",
@@ -109,7 +110,6 @@
"metascraper-publisher": "5.11.8",
"metascraper-title": "5.11.8",
"metascraper-url": "5.11.8",
- "mobiledoc-dom-renderer": "0.7.0",
"moment": "2.24.0",
"moment-timezone": "0.5.23",
"multer": "1.4.2",
@@ -124,7 +124,6 @@
"rss": "1.2.2",
"sanitize-html": "1.22.1",
"semver": "7.2.1",
- "simple-dom": "0.3.2",
"uuid": "7.0.3",
"validator": "6.3.0",
"xml": "1.0.1"
diff --git a/test/unit/lib/mobiledoc/renderers/mobiledoc-html-renderer_spec.js b/test/unit/lib/mobiledoc/renderers/mobiledoc-html-renderer_spec.js
deleted file mode 100644
index b4f7547b9d..0000000000
--- a/test/unit/lib/mobiledoc/renderers/mobiledoc-html-renderer_spec.js
+++ /dev/null
@@ -1,215 +0,0 @@
-const should = require('should');
-const converter = require('../../../../../core/server/lib/mobiledoc/renderers/mobiledoc-html-renderer');
-
-describe('Mobiledoc HTML renderer', function () {
- describe('default', 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', {
- cardWidth: 'wide',
- src: '/content/images/2018/04/NatGeo06.jpg',
- caption: 'Birdies'
- }],
- ['html', {
- html: '