Replaced mobiledoc cards with @tryghost/kg-default-cards

no issue

- moved card definitions to a new library `@tryghost/kg-default-cards`
- moved `createCard` factory function to a new library `@tryghost/kg-card-factory`
This commit is contained in:
Kevin Ansfield 2020-03-25 19:53:11 +00:00
parent a5b14419af
commit 1ee1e68adf
26 changed files with 47 additions and 1610 deletions

View File

@ -1,44 +0,0 @@
// this is a function so that when it's aliased across multiple cards we do not
// end up modifying the object by reference
module.exports = function markdownCardDefinition() {
return {
name: 'markdown',
type: 'dom',
config: {
commentWrapper: true
},
render: function (opts) {
let markdownHtmlRenderer = require('@tryghost/kg-markdown-html-renderer');
let payload = opts.payload;
let version = opts.options && opts.options.version || 2;
// convert markdown to HTML ready for insertion into dom
let html = markdownHtmlRenderer.render(payload.markdown || '');
if (!html) {
return '';
}
/**
* @deprecated Ghost 1.0's markdown-only renderer wrapped cards. Remove in Ghost 3.0
*/
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
return opts.env.dom.createRawHTMLSection(html);
},
absoluteToRelative(urlUtils, payload, options) {
payload.markdown = payload.markdown && urlUtils.markdownAbsoluteToRelative(payload.markdown, options);
return payload;
},
relativeToAbsolute(urlUtils, payload, options) {
payload.markdown = payload.markdown && urlUtils.markdownRelativeToAbsolute(payload.markdown, options);
return payload;
}
};
};

View File

@ -1,110 +0,0 @@
/**
<figure class="kg-card kg-bookmark-card">
<a href="[URL]" class="kg-bookmark-container">
<div class="kg-bookmark-content">
<div class="kg-bookmark-title">[TITLE]</div>
<div class="kg-bookmark-description">[DESCRIPTION]</div>
<div class="kg-bookmark-metadata">
<img src="[ICON]" class="kg-bookmark-icon">
<span class="kg-bookmark-author">[AUTHOR]</span>
<span class="kg-bookmark-publisher">[PUBLISHER]</span>
</div>
</div>
<div class="kg-bookmark-thumbnail">
<img src="[THUMBNAIL]">
</div>
</a>
</figure>
*/
const createCard = require('./lib/create-card');
function createElement(dom, elem, classNames = '', attributes = [], text) {
let element = dom.createElement(elem);
if (classNames) {
element.setAttribute('class', classNames);
}
attributes.forEach((attr) => {
element.setAttribute(attr.key, attr.value);
});
if (text) {
element.appendChild(dom.createTextNode(text));
}
return element;
}
module.exports = createCard({
name: 'bookmark',
type: 'dom',
render(opts) {
let {payload, env: {dom}} = opts;
if (!payload.metadata || !payload.metadata.url || !payload.metadata.title || !payload.metadata.description) {
return '';
}
let figure = createElement(dom, 'figure', 'kg-card kg-bookmark-card');
let linkTag = createElement(dom, 'a', 'kg-bookmark-container', [{
key: 'href',
value: payload.metadata.url
}]);
let contentDiv = createElement(dom, 'div', 'kg-bookmark-content');
let titleDiv = createElement(dom, 'div', 'kg-bookmark-title', [] , payload.metadata.title);
let descriptionDiv = createElement(dom, 'div', 'kg-bookmark-description', [] , payload.metadata.description);
let metadataDiv = createElement(dom, 'div', 'kg-bookmark-metadata');
let imgIcon = createElement(dom, 'img', 'kg-bookmark-icon', [{
key: 'src',
value: payload.metadata.icon
}]);
let authorSpan = createElement(dom, 'span', 'kg-bookmark-author', [] , payload.metadata.author);
let publisherSpan = createElement(dom, 'span', 'kg-bookmark-publisher', [] , payload.metadata.publisher);
let thumbnailDiv = createElement(dom, 'div', 'kg-bookmark-thumbnail');
let thumbnailImg = createElement(dom, 'img', '', [{
key: 'src',
value: payload.metadata.thumbnail
}]);
thumbnailDiv.appendChild(thumbnailImg);
if (payload.metadata.icon) {
metadataDiv.appendChild(imgIcon);
}
if (payload.metadata.author) {
metadataDiv.appendChild(authorSpan);
}
if (payload.metadata.publisher) {
metadataDiv.appendChild(publisherSpan);
}
contentDiv.appendChild(titleDiv);
contentDiv.appendChild(descriptionDiv);
contentDiv.appendChild(metadataDiv);
linkTag.appendChild(contentDiv);
if (payload.metadata.thumbnail) {
linkTag.appendChild(thumbnailDiv);
}
figure.appendChild(linkTag);
if (payload.caption) {
let figcaption = dom.createElement('figcaption');
figcaption.appendChild(dom.createRawHTMLSection(payload.caption));
figure.appendChild(figcaption);
figure.setAttribute('class', `${figure.getAttribute('class')} kg-card-hascaption`);
}
return figure;
},
absoluteToRelative(urlUtils, payload, options) {
if (payload.metadata) {
payload.metadata.url = payload.metadata.url && urlUtils.absoluteToRelative(payload.metadata.url, options);
}
payload.caption = payload.caption && urlUtils.htmlAbsoluteToRelative(payload.caption, options);
return payload;
},
relativeToAbsolute(urlUtils, payload, options) {
if (payload.metadata) {
payload.metadata.url = payload.metadata.url && urlUtils.relativeToAbsolute(payload.metadata.url, options);
}
payload.caption = payload.caption && urlUtils.htmlRelativeToAbsolute(payload.caption, options);
return payload;
}
});

View File

@ -1,9 +0,0 @@
// this card is just an alias of the `markdown` card which is necessary because
// our markdown-only editor was using the `card-markdown` card name
const markdownCard = require('./_markdown');
const createCard = require('./lib/create-card');
const v1CompatMarkdownCard = markdownCard();
v1CompatMarkdownCard.name = 'card-markdown';
module.exports = createCard(v1CompatMarkdownCard);

View File

@ -1,48 +0,0 @@
const createCard = require('./lib/create-card');
module.exports = createCard({
name: 'code',
type: 'dom',
render(opts) {
let payload = opts.payload;
let dom = opts.env.dom;
if (!payload.code) {
return '';
}
let pre = dom.createElement('pre');
let code = dom.createElement('code');
if (payload.language) {
code.setAttribute('class', `language-${payload.language}`);
}
code.appendChild(dom.createTextNode(payload.code));
pre.appendChild(code);
if (payload.caption) {
let figure = dom.createElement('figure');
figure.setAttribute('class', 'kg-card kg-code-card');
figure.appendChild(pre);
let figcaption = dom.createElement('figcaption');
figcaption.appendChild(dom.createRawHTMLSection(payload.caption));
figure.appendChild(figcaption);
return figure;
} else {
return pre;
}
},
absoluteToRelative(urlUtils, payload, options) {
payload.caption = payload.caption && urlUtils.htmlAbsoluteToRelative(payload.caption, options);
return payload;
},
relativeToAbsolute(urlUtils, payload, options) {
payload.caption = payload.caption && urlUtils.htmlRelativeToAbsolute(payload.caption, options);
return payload;
}
});

View File

@ -1,38 +0,0 @@
const createCard = require('./lib/create-card');
module.exports = createCard({
name: 'embed',
type: 'dom',
render(opts) {
if (!opts.payload.html) {
return '';
}
let {payload, env: {dom}} = opts;
let figure = dom.createElement('figure');
figure.setAttribute('class', 'kg-card kg-embed-card');
let html = dom.createRawHTMLSection(payload.html);
figure.appendChild(html);
if (payload.caption) {
let figcaption = dom.createElement('figcaption');
figcaption.appendChild(dom.createRawHTMLSection(payload.caption));
figure.appendChild(figcaption);
figure.setAttribute('class', `${figure.getAttribute('class')} kg-card-hascaption`);
}
return figure;
},
absoluteToRelative(urlUtils, payload, options) {
payload.caption = payload.caption && urlUtils.htmlAbsoluteToRelative(payload.caption, options);
return payload;
},
relativeToAbsolute(urlUtils, payload, options) {
payload.caption = payload.caption && urlUtils.htmlRelativeToAbsolute(payload.caption, options);
return payload;
}
});

View File

@ -1,138 +0,0 @@
/**
* <figure class="kg-gallery-card kg-width-wide">
* <div class="kg-gallery-container>
* <div class="kg-gallery-row">
* <div class="kg-gallery-image"><img width="" height=""></div>
* <div class="kg-gallery-image"><img width="" height=""></div>
* <div class="kg-gallery-image"><img width="" height=""></div>
* </div>
* <div class="kg-gallery-row">
* <div class="kg-gallery-image"><img></div>
* <div class="kg-gallery-image"><img></div>
* </div>
* </div>
* <figcaption></figcaption>
* </figure>
*/
const createCard = require('./lib/create-card');
const MAX_IMG_PER_ROW = 3;
module.exports = createCard({
name: 'gallery',
type: 'dom',
render(opts) {
let payload = opts.payload;
// let version = opts.options.version;
let dom = opts.env.dom;
let isValidImage = (image) => {
return image.fileName
&& image.src
&& image.width
&& image.height;
};
let validImages = [];
if (payload.images && payload.images.length) {
validImages = payload.images.filter(isValidImage);
}
if (validImages.length === 0) {
return '';
}
let figure = dom.createElement('figure');
figure.setAttribute('class', 'kg-card kg-gallery-card kg-width-wide');
let container = dom.createElement('div');
container.setAttribute('class', 'kg-gallery-container');
figure.appendChild(container);
let buildStructure = function buildStructure(images) {
let rows = [];
let noOfImages = images.length;
images.forEach((image, idx) => {
let row = image.row;
if (noOfImages > 1 && (noOfImages % MAX_IMG_PER_ROW === 1) && (idx === (noOfImages - 2))) {
row = row + 1;
}
if (!rows[row]) {
rows[row] = [];
}
rows[row].push(image);
});
return rows;
};
let rows = buildStructure(validImages);
rows.forEach((row) => {
let rowDiv = dom.createElement('div');
rowDiv.setAttribute('class', 'kg-gallery-row');
row.forEach((image) => {
let imgDiv = dom.createElement('div');
imgDiv.setAttribute('class', 'kg-gallery-image');
let img = dom.createElement('img');
img.setAttribute('src', image.src);
img.setAttribute('width', image.width);
img.setAttribute('height', image.height);
if (image.alt) {
img.setAttribute('alt', image.alt);
}
if (image.title) {
img.setAttribute('title', image.title);
}
imgDiv.appendChild(img);
rowDiv.appendChild(imgDiv);
});
container.appendChild(rowDiv);
});
if (payload.caption) {
let figcaption = dom.createElement('figcaption');
figcaption.appendChild(dom.createRawHTMLSection(payload.caption));
figure.appendChild(figcaption);
figure.setAttribute('class', `${figure.getAttribute('class')} kg-card-hascaption`);
}
return figure;
},
absoluteToRelative(urlUtils, payload, options) {
if (payload.images) {
payload.images.forEach((image) => {
image.src = image.src && urlUtils.absoluteToRelative(image.src, options);
image.caption = image.caption && urlUtils.htmlAbsoluteToRelative(image.caption, options);
});
}
payload.caption = payload.caption && urlUtils.htmlAbsoluteToRelative(payload.caption, options);
return payload;
},
relativeToAbsolute(urlUtils, payload, options) {
if (payload.images) {
payload.images.forEach((image) => {
image.src = image.src && urlUtils.relativeToAbsolute(image.src, options);
image.caption = image.caption && urlUtils.htmlRelativeToAbsolute(image.caption, options);
});
}
payload.caption = payload.caption && urlUtils.htmlRelativeToAbsolute(payload.caption, options);
return payload;
}
});

View File

@ -1,9 +0,0 @@
const createCard = require('./lib/create-card');
module.exports = createCard({
name: 'hr',
type: 'dom',
render(opts) {
return opts.env.dom.createElement('hr');
}
});

View File

@ -1,28 +0,0 @@
const createCard = require('./lib/create-card');
module.exports = createCard({
name: 'html',
type: 'dom',
config: {
commentWrapper: true
},
render(opts) {
if (!opts.payload.html) {
return '';
}
// use the SimpleDOM document to create a raw HTML section.
// avoids parsing/rendering of potentially broken or unsupported HTML
return opts.env.dom.createRawHTMLSection(opts.payload.html);
},
absoluteToRelative(urlUtils, payload, options) {
payload.html = payload.html && urlUtils.htmlAbsoluteToRelative(payload.html, options);
return payload;
},
relativeToAbsolute(urlUtils, payload, options) {
payload.html = payload.html && urlUtils.htmlRelativeToAbsolute(payload.html, options);
return payload;
}
});

View File

@ -1,55 +0,0 @@
const createCard = require('./lib/create-card');
module.exports = createCard({
name: 'image',
type: 'dom',
render(opts) {
let payload = opts.payload;
// let version = opts.options.version;
let dom = opts.env.dom;
if (!payload.src) {
return '';
}
let figure = dom.createElement('figure');
let figureClass = 'kg-card kg-image-card';
if (payload.cardWidth) {
figureClass = `${figureClass} kg-width-${payload.cardWidth}`;
}
figure.setAttribute('class', figureClass);
let img = dom.createElement('img');
img.setAttribute('src', payload.src);
img.setAttribute('class', 'kg-image');
if (payload.alt) {
img.setAttribute('alt', payload.alt);
}
if (payload.title) {
img.setAttribute('title', payload.title);
}
figure.appendChild(img);
if (payload.caption) {
let figcaption = dom.createElement('figcaption');
figcaption.appendChild(dom.createRawHTMLSection(payload.caption));
figure.appendChild(figcaption);
figure.setAttribute('class', `${figure.getAttribute('class')} kg-card-hascaption`);
}
return figure;
},
absoluteToRelative(urlUtils, payload, options) {
payload.src = payload.src && urlUtils.absoluteToRelative(payload.src, options);
payload.caption = payload.caption && urlUtils.htmlAbsoluteToRelative(payload.caption, options);
return payload;
},
relativeToAbsolute(urlUtils, payload, options) {
payload.src = payload.src && urlUtils.relativeToAbsolute(payload.src, options);
payload.caption = payload.caption && urlUtils.htmlRelativeToAbsolute(payload.caption, options);
return payload;
}
});

View File

@ -1,11 +0,0 @@
module.exports = [
require('./card-markdown'),
require('./code'),
require('./embed'),
require('./bookmark'),
require('./hr'),
require('./html'),
require('./image'),
require('./markdown'),
require('./gallery')
];

View File

@ -1,65 +0,0 @@
let urlUtils;
module.exports = function createCard(card) {
const defaultTransformer = function (urlUtils, payload) {
return payload;
};
const {
name,
type,
config = {},
absoluteToRelative = defaultTransformer,
relativeToAbsolute = defaultTransformer
} = card;
return {
name,
type,
render({env, payload, options}) {
const {dom} = env;
const cleanName = name.replace(/^card-/, '');
const cardOutput = card.render({env, payload, options});
if (!cardOutput) {
return cardOutput;
}
if (config.commentWrapper) {
const beginComment = dom.createComment(`kg-card-begin: ${cleanName}`);
const endComment = dom.createComment(`kg-card-end: ${cleanName}`);
const fragment = dom.createDocumentFragment();
fragment.appendChild(beginComment);
fragment.appendChild(cardOutput);
fragment.appendChild(endComment);
return fragment;
}
return cardOutput;
},
absoluteToRelative() {
// it's necessary to wait until the method is called to require
// urlUtils to ensure the class has actually been instantiated
// as cards are passed in as an arg to the class instantiation
if (!urlUtils) {
urlUtils = require('../../../url-utils');
}
return absoluteToRelative(urlUtils, ...arguments);
},
relativeToAbsolute() {
// it's necessary to wait until the method is called to require
// urlUtils to ensure the class has actually been instantiated
// as cards are passed in as an arg to the class instantiation
if (!urlUtils) {
urlUtils = require('../../../url-utils');
}
return relativeToAbsolute(urlUtils, ...arguments);
}
};
};

View File

@ -1,6 +0,0 @@
const markdownCard = require('./_markdown');
const createCard = require('./lib/create-card');
// uses the _markdown card definition function so that the card definition
// can be re-used in aliased cards
module.exports = createCard(markdownCard());

View File

@ -1,8 +1,26 @@
const common = require('../common');
const config = require('../../config');
let cardFactory, cards;
module.exports = {
get cards() {
return require('./cards');
if (cards) {
return 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);
});
return cards;
},
get atoms() {

View File

@ -1,12 +1,11 @@
const SimpleDom = require('simple-dom');
const Renderer = require('mobiledoc-dom-renderer').default;
const common = require('../../common');
const atoms = require('../atoms');
const cards = require('../cards');
const mobiledoc = require('../');
const options = {
dom: new SimpleDom.Document(),
cards: cards,
atoms: atoms,
cards: mobiledoc.cards,
atoms: mobiledoc.atoms,
unknownCardHandler: function (args) {
common.logging.error(new common.errors.InternalServerError({
message: 'Mobiledoc card \'' + args.env.name + '\' not found.'

View File

@ -1,6 +1,6 @@
const UrlUtils = require('@tryghost/url-utils');
const config = require('../../config');
const cards = require('../mobiledoc/cards');
const mobiledoc = require('../mobiledoc');
const urlUtils = new UrlUtils({
url: config.get('url'),
@ -10,7 +10,9 @@ const urlUtils = new UrlUtils({
slugs: config.get('slugs').protected,
redirectCacheMaxAge: config.get('caching:301:maxAge'),
baseApiPath: '/ghost/api',
cardTransformers: cards
get cardTransformers() {
return mobiledoc.cards;
}
});
module.exports = urlUtils;

View File

@ -1,238 +0,0 @@
const should = require('should');
const card = require('../../../../../server/lib/mobiledoc/cards/bookmark');
const SimpleDom = require('simple-dom');
const serializer = new SimpleDom.HTMLSerializer(SimpleDom.voidMap);
describe('Bookmark card', function () {
it('renders', function () {
let opts = {
env: {dom: new SimpleDom.Document()},
payload: {
metadata: {
url: 'http://example.com',
title: 'Title',
description: 'Description',
icon: 'http://example.com/icon.png',
thumbnail: 'http://exampple.com/thumbnail.png',
author: 'Author',
publisher: 'Publisher'
},
caption: 'Caption'
}
};
serializer.serialize(card.render(opts))
.should.equal('<figure class="kg-card kg-bookmark-card kg-card-hascaption"><a class="kg-bookmark-container" href="http://example.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Title</div><div class="kg-bookmark-description">Description</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="http://example.com/icon.png"><span class="kg-bookmark-author">Author</span><span class="kg-bookmark-publisher">Publisher</span></div></div><div class="kg-bookmark-thumbnail"><img src="http://exampple.com/thumbnail.png"></div></a><figcaption>Caption</figcaption></figure>');
});
it('skips icon when missing', function () {
let opts = {
env: {dom: new SimpleDom.Document()},
payload: {
metadata: {
url: 'http://example.com',
title: 'Title',
description: 'Description',
icon: null,
thumbnail: 'http://exampple.com/thumbnail.png',
author: 'Author',
publisher: 'Publisher'
},
caption: 'Caption'
}
};
serializer.serialize(card.render(opts))
.should.equal('<figure class="kg-card kg-bookmark-card kg-card-hascaption"><a class="kg-bookmark-container" href="http://example.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Title</div><div class="kg-bookmark-description">Description</div><div class="kg-bookmark-metadata"><span class="kg-bookmark-author">Author</span><span class="kg-bookmark-publisher">Publisher</span></div></div><div class="kg-bookmark-thumbnail"><img src="http://exampple.com/thumbnail.png"></div></a><figcaption>Caption</figcaption></figure>');
});
it('skips thumbnail when missing', function () {
let opts = {
env: {dom: new SimpleDom.Document()},
payload: {
metadata: {
url: 'http://example.com',
title: 'Title',
description: 'Description',
icon: 'http://example.com/icon.png',
thumbnail: null,
author: 'Author',
publisher: 'Publisher'
},
caption: 'Caption'
}
};
serializer.serialize(card.render(opts))
.should.equal('<figure class="kg-card kg-bookmark-card kg-card-hascaption"><a class="kg-bookmark-container" href="http://example.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Title</div><div class="kg-bookmark-description">Description</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="http://example.com/icon.png"><span class="kg-bookmark-author">Author</span><span class="kg-bookmark-publisher">Publisher</span></div></div></a><figcaption>Caption</figcaption></figure>');
});
it('skips author when missing', function () {
let opts = {
env: {dom: new SimpleDom.Document()},
payload: {
metadata: {
url: 'http://example.com',
title: 'Title',
description: 'Description',
icon: 'http://example.com/icon.png',
thumbnail: 'http://exampple.com/thumbnail.png',
author: null,
publisher: 'Publisher'
},
caption: 'Caption'
}
};
serializer.serialize(card.render(opts))
.should.equal('<figure class="kg-card kg-bookmark-card kg-card-hascaption"><a class="kg-bookmark-container" href="http://example.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Title</div><div class="kg-bookmark-description">Description</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="http://example.com/icon.png"><span class="kg-bookmark-publisher">Publisher</span></div></div><div class="kg-bookmark-thumbnail"><img src="http://exampple.com/thumbnail.png"></div></a><figcaption>Caption</figcaption></figure>');
});
it('skips publisher when missing', function () {
let opts = {
env: {dom: new SimpleDom.Document()},
payload: {
metadata: {
url: 'http://example.com',
title: 'Title',
description: 'Description',
icon: 'http://example.com/icon.png',
thumbnail: 'http://exampple.com/thumbnail.png',
author: 'Author',
publisher: null
},
caption: 'Caption'
}
};
serializer.serialize(card.render(opts))
.should.equal('<figure class="kg-card kg-bookmark-card kg-card-hascaption"><a class="kg-bookmark-container" href="http://example.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Title</div><div class="kg-bookmark-description">Description</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="http://example.com/icon.png"><span class="kg-bookmark-author">Author</span></div></div><div class="kg-bookmark-thumbnail"><img src="http://exampple.com/thumbnail.png"></div></a><figcaption>Caption</figcaption></figure>');
});
it('skips caption when missing', function () {
let opts = {
env: {dom: new SimpleDom.Document()},
payload: {
metadata: {
url: 'http://example.com',
title: 'Title',
description: 'Description',
icon: 'http://example.com/icon.png',
thumbnail: 'http://exampple.com/thumbnail.png',
author: 'Author',
publisher: 'Publisher'
},
caption: ''
}
};
serializer.serialize(card.render(opts))
.should.equal('<figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="http://example.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Title</div><div class="kg-bookmark-description">Description</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="http://example.com/icon.png"><span class="kg-bookmark-author">Author</span><span class="kg-bookmark-publisher">Publisher</span></div></div><div class="kg-bookmark-thumbnail"><img src="http://exampple.com/thumbnail.png"></div></a></figure>');
});
it('renders nothing when payload is undefined', function () {
let opts = {
env: {dom: new SimpleDom.Document()},
payload: {
metadata: undefined
}
};
serializer.serialize(card.render(opts))
.should.equal('');
});
it('renders nothing when payload metadata is empty', function () {
let opts = {
env: {dom: new SimpleDom.Document()},
payload: {
metadata: {}
}
};
serializer.serialize(card.render(opts))
.should.equal('');
});
it('renders nothing when url is missing', function () {
let opts = {
env: {dom: new SimpleDom.Document()},
payload: {
metadata: {
url: null,
title: 'Test bookmark',
description: 'This is just a test'
}
}
};
serializer.serialize(card.render(opts))
.should.equal('');
});
it('renders nothing when title is missing', function () {
let opts = {
env: {dom: new SimpleDom.Document()},
payload: {
metadata: {
url: 'http://example.com',
title: null,
description: 'This is just a test'
}
}
};
serializer.serialize(card.render(opts))
.should.equal('');
});
it('renders nothing when description is missing', function () {
let opts = {
env: {dom: new SimpleDom.Document()},
payload: {
metadata: {
url: 'http://example.com',
title: 'Test bookmark',
description: null
}
}
};
serializer.serialize(card.render(opts))
.should.equal('');
});
it('transforms urls absolute to relative', function () {
let payload = {
metadata: {
url: 'http://127.0.0.1:2369/post'
},
caption: 'A link to <a href="http://127.0.0.1:2369/post">an internal post</a>'
};
const transformed = card.absoluteToRelative(payload, {});
transformed.metadata.url
.should.equal('/post');
transformed.caption
.should.equal('A link to <a href="/post">an internal post</a>');
});
it('transforms urls relative to absolute', function () {
let payload = {
metadata: {
url: '/post'
},
caption: 'A link to <a href="/post">an internal post</a>'
};
const transformed = card.relativeToAbsolute(payload, {});
transformed.metadata.url
.should.equal('http://127.0.0.1:2369/post');
transformed.caption
.should.equal('A link to <a href="http://127.0.0.1:2369/post">an internal post</a>');
});
});

View File

@ -1,83 +0,0 @@
const should = require('should');
const card = require('../../../../../server/lib/mobiledoc/cards/card-markdown');
const SimpleDom = require('simple-dom');
const serializer = new SimpleDom.HTMLSerializer(SimpleDom.voidMap);
describe('Markdown card (v1 compatibility card)', function () {
it('renders', function () {
let opts = {
env: {
dom: new SimpleDom.Document()
},
payload: {
markdown: '#HEADING\r\n- list\r\n- items'
}
};
serializer.serialize(card.render(opts)).should.eql('<!--kg-card-begin: markdown--><h1 id="heading">HEADING</h1>\n<ul>\n<li>list</li>\n<li>items</li>\n</ul>\n<!--kg-card-end: markdown-->');
});
it('Accepts invalid HTML in markdown', function () {
let opts = {
env: {
dom: new SimpleDom.Document()
},
payload: {
markdown: '#HEADING\r\n<h2>Heading 2>'
}
};
serializer.serialize(card.render(opts)).should.eql('<!--kg-card-begin: markdown--><h1 id="heading">HEADING</h1>\n<h2>Heading 2><!--kg-card-end: markdown-->');
});
it('Renders nothing when payload is undefined', function () {
let opts = {
env: {
dom: new SimpleDom.Document()
},
payload: {
markdown: undefined
}
};
serializer.serialize(card.render(opts)).should.eql('');
});
it('[deprecated] version 1', 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.eql('<!--kg-card-begin: markdown--><div class="kg-card-markdown"><h1 id="heading">HEADING</h1>\n<ul>\n<li>list</li>\n<li>items</li>\n</ul>\n</div><!--kg-card-end: markdown-->');
});
it('transforms urls absolute to relative', function () {
let payload = {
markdown: 'A link to [an internal post](http://127.0.0.1:2369/post)'
};
const transformed = card.absoluteToRelative(payload, {});
transformed.markdown
.should.equal('A link to [an internal post](/post)');
});
it('transforms urls relative to absolute', function () {
let payload = {
markdown: 'A link to [an internal post](/post)'
};
const transformed = card.relativeToAbsolute(payload, {});
transformed.markdown
.should.equal('A link to [an internal post](http://127.0.0.1:2369/post)');
});
});

View File

@ -1,83 +0,0 @@
const should = require('should');
const card = require('../../../../../server/lib/mobiledoc/cards/code');
const SimpleDom = require('simple-dom');
const serializer = new SimpleDom.HTMLSerializer(SimpleDom.voidMap);
describe('Code card', function () {
it('Renders and escapes', function () {
let opts = {
env: {
dom: new SimpleDom.Document()
},
payload: {
code: '<p>Test</p>'
}
};
serializer.serialize(card.render(opts)).should.match('<pre><code>&lt;p&gt;Test&lt;/p&gt;</code></pre>');
});
it('Renders language class if provided', function () {
let opts = {
env: {
dom: new SimpleDom.Document()
},
payload: {
code: '<p>Test</p>',
language: 'html'
}
};
serializer.serialize(card.render(opts)).should.match('<pre><code class="language-html">&lt;p&gt;Test&lt;/p&gt;</code></pre>');
});
it('Renders nothing when payload is undefined', function () {
let opts = {
env: {
dom: new SimpleDom.Document()
},
payload: {
code: undefined
}
};
serializer.serialize(card.render(opts)).should.match('');
});
it('Renders a figure if a caption is provided', function () {
let opts = {
env: {
dom: new SimpleDom.Document()
},
payload: {
code: '<p>Test</p>',
language: 'html',
caption: 'Some <strong>HTML</strong>'
}
};
serializer.serialize(card.render(opts)).should.match('<figure class="kg-card kg-code-card"><pre><code class="language-html">&lt;p&gt;Test&lt;/p&gt;</code></pre><figcaption>Some <strong>HTML</strong></figcaption></figure>');
});
it('transforms urls absolute to relative', function () {
let payload = {
caption: 'A link to <a href="http://127.0.0.1:2369/post">an internal post</a>'
};
const transformed = card.absoluteToRelative(payload, {});
transformed.caption
.should.equal('A link to <a href="/post">an internal post</a>');
});
it('transforms urls relative to absolute', function () {
let payload = {
caption: 'A link to <a href="/post">an internal post</a>'
};
const transformed = card.relativeToAbsolute(payload, {});
transformed.caption
.should.equal('A link to <a href="http://127.0.0.1:2369/post">an internal post</a>');
});
});

View File

@ -1,94 +0,0 @@
const should = require('should');
const card = require('../../../../../server/lib/mobiledoc/cards/embed');
const SimpleDom = require('simple-dom');
const serializer = new SimpleDom.HTMLSerializer(SimpleDom.voidMap);
describe('Embed card', function () {
it('Embed Card renders', function () {
let opts = {
env: {
dom: new SimpleDom.Document()
},
payload: {
html: '<h1>HEADING</h1><p>PARAGRAPH</p>'
}
};
serializer.serialize(card.render(opts)).should.match('<figure class="kg-card kg-embed-card"><h1>HEADING</h1><p>PARAGRAPH</p></figure>');
});
it('Plain content renders', function () {
let opts = {
env: {
dom: new SimpleDom.Document()
},
payload: {
html: 'CONTENT'
}
};
serializer.serialize(card.render(opts)).should.match('<figure class="kg-card kg-embed-card">CONTENT</figure>');
});
it('Invalid HTML returns', function () {
let opts = {
env: {
dom: new SimpleDom.Document()
},
payload: {
html: '<h1>HEADING<'
}
};
serializer.serialize(card.render(opts)).should.match('<figure class="kg-card kg-embed-card"><h1>HEADING<</figure>');
});
it('Renders nothing when payload is undefined', function () {
let opts = {
env: {
dom: new SimpleDom.Document()
},
payload: {
html: undefined
}
};
serializer.serialize(card.render(opts)).should.match('');
});
it('Renders caption when provided', function () {
let opts = {
env: {
dom: new SimpleDom.Document()
},
payload: {
html: 'Testing',
caption: '<strong>Caption</strong>'
}
};
serializer.serialize(card.render(opts)).should.match('<figure class="kg-card kg-embed-card kg-card-hascaption">Testing<figcaption><strong>Caption</strong></figcaption></figure>');
});
it('transforms urls absolute to relative', function () {
let payload = {
caption: 'A link to <a href="http://127.0.0.1:2369/post">an internal post</a>'
};
const transformed = card.absoluteToRelative(payload, {});
transformed.caption
.should.equal('A link to <a href="/post">an internal post</a>');
});
it('transforms urls relative to absolute', function () {
let payload = {
caption: 'A link to <a href="/post">an internal post</a>'
};
const transformed = card.relativeToAbsolute(payload, {});
transformed.caption
.should.equal('A link to <a href="http://127.0.0.1:2369/post">an internal post</a>');
});
});

View File

@ -1,211 +0,0 @@
const should = require('should');
const card = require('../../../../../server/lib/mobiledoc/cards/gallery');
const SimpleDom = require('simple-dom');
const serializer = new SimpleDom.HTMLSerializer(SimpleDom.voidMap);
describe('Gallery card', function () {
it('renders a gallery', function () {
let opts = {
env: {
dom: new SimpleDom.Document()
},
payload: {
images: [
{
row: 0,
fileName: 'NatGeo01.jpg',
src: '/content/images/2018/08/NatGeo01-9.jpg',
width: 3200,
height: 1600
},
{
row: 0,
fileName: 'NatGeo02.jpg',
src: '/content/images/2018/08/NatGeo02-10.jpg',
width: 3200,
height: 1600
},
{
row: 0,
fileName: 'NatGeo03.jpg',
src: '/content/images/2018/08/NatGeo03-6.jpg',
width: 3200,
height: 1600
},
{
row: 1,
fileName: 'NatGeo04.jpg',
src: '/content/images/2018/08/NatGeo04-7.jpg',
alt: 'Alt test',
width: 3200,
height: 1600
},
{
row: 1,
fileName: 'NatGeo05.jpg',
src: '/content/images/2018/08/NatGeo05-4.jpg',
title: 'Title test',
width: 3200,
height: 1600
},
{
row: 1,
fileName: 'NatGeo06.jpg',
src: '/content/images/2018/08/NatGeo06-6.jpg',
width: 3200,
height: 1600
},
{
row: 2,
fileName: 'NatGeo07.jpg',
src: '/content/images/2018/08/NatGeo07-5.jpg',
width: 3200,
height: 1600
},
{
row: 2,
fileName: 'NatGeo09.jpg',
src: '/content/images/2018/08/NatGeo09-8.jpg',
width: 3200,
height: 1600
}
],
caption: 'Test caption'
}
};
serializer.serialize(card.render(opts)).should.eql('<figure class="kg-card kg-gallery-card kg-width-wide kg-card-hascaption"><div class="kg-gallery-container"><div class="kg-gallery-row"><div class="kg-gallery-image"><img src="/content/images/2018/08/NatGeo01-9.jpg" width="3200" height="1600"></div><div class="kg-gallery-image"><img src="/content/images/2018/08/NatGeo02-10.jpg" width="3200" height="1600"></div><div class="kg-gallery-image"><img src="/content/images/2018/08/NatGeo03-6.jpg" width="3200" height="1600"></div></div><div class="kg-gallery-row"><div class="kg-gallery-image"><img src="/content/images/2018/08/NatGeo04-7.jpg" width="3200" height="1600" alt="Alt test"></div><div class="kg-gallery-image"><img src="/content/images/2018/08/NatGeo05-4.jpg" width="3200" height="1600" title="Title test"></div><div class="kg-gallery-image"><img src="/content/images/2018/08/NatGeo06-6.jpg" width="3200" height="1600"></div></div><div class="kg-gallery-row"><div class="kg-gallery-image"><img src="/content/images/2018/08/NatGeo07-5.jpg" width="3200" height="1600"></div><div class="kg-gallery-image"><img src="/content/images/2018/08/NatGeo09-8.jpg" width="3200" height="1600"></div></div></div><figcaption>Test caption</figcaption></figure>');
});
it('renders nothing with no images', function () {
let opts = {
env: {
dom: new SimpleDom.Document()
},
payload: {
images: [],
caption: 'Test caption'
}
};
serializer.serialize(card.render(opts)).should.eql('');
});
it('renders nothing with no valid images', function () {
let opts = {
env: {
dom: new SimpleDom.Document()
},
payload: {
images: [{src: 'undefined'}],
caption: 'Test caption'
}
};
serializer.serialize(card.render(opts)).should.eql('');
});
it('skips invalid images', function () {
let opts = {
env: {
dom: new SimpleDom.Document()
},
payload: {
images: [
{
row: 0,
fileName: 'NatGeo01.jpg',
src: '/content/images/2018/08/NatGeo01-9.jpg',
width: 3200,
height: 1600
},
{
row: 0,
fileName: 'NatGeo02.jpg',
src: '/content/images/2018/08/NatGeo02-10.jpg'
},
{
row: 0,
fileName: 'NatGeo03.jpg',
src: '/content/images/2018/08/NatGeo03-6.jpg',
width: 3200,
height: 1600
}
],
caption: 'Test caption'
}
};
serializer.serialize(card.render(opts)).should.eql('<figure class="kg-card kg-gallery-card kg-width-wide kg-card-hascaption"><div class="kg-gallery-container"><div class="kg-gallery-row"><div class="kg-gallery-image"><img src="/content/images/2018/08/NatGeo01-9.jpg" width="3200" height="1600"></div><div class="kg-gallery-image"><img src="/content/images/2018/08/NatGeo03-6.jpg" width="3200" height="1600"></div></div></div><figcaption>Test caption</figcaption></figure>');
});
it('transforms urls absolute to relative', function () {
let payload = {
images: [
{
row: 0,
fileName: 'NatGeo01.jpg',
src: 'http://127.0.0.1:2369/content/images/2018/08/NatGeo01-9.jpg',
width: 3200,
height: 1600,
caption: 'A link to <a href="http://127.0.0.1:2369/post">an internal post</a>'
},
{
row: 0,
fileName: 'NatGeo02.jpg',
src: 'http://127.0.0.1:2369/content/images/2018/08/NatGeo02-10.jpg',
caption: 'A link to <a href="http://127.0.0.1:2369/post">an internal post</a>'
}
],
caption: 'A link to <a href="http://127.0.0.1:2369/post">an internal post</a>'
};
const transformed = card.absoluteToRelative(payload, {});
transformed.images[0].src
.should.equal('/content/images/2018/08/NatGeo01-9.jpg');
transformed.images[0].caption
.should.equal('A link to <a href="/post">an internal post</a>');
transformed.images[1].src
.should.equal('/content/images/2018/08/NatGeo02-10.jpg');
transformed.images[1].caption
.should.equal('A link to <a href="/post">an internal post</a>');
transformed.caption
.should.equal('A link to <a href="/post">an internal post</a>');
});
it('transforms urls relative to absolute', function () {
let payload = {
images: [
{
row: 0,
fileName: 'NatGeo01.jpg',
src: '/content/images/2018/08/NatGeo01-9.jpg',
width: 3200,
height: 1600
},
{
row: 0,
fileName: 'NatGeo02.jpg',
src: '/content/images/2018/08/NatGeo02-10.jpg'
}
],
caption: 'A link to <a href="/post">an internal post</a>'
};
const transformed = card.relativeToAbsolute(payload, {});
transformed.images[0].src
.should.equal('http://127.0.0.1:2369/content/images/2018/08/NatGeo01-9.jpg');
transformed.images[1].src
.should.equal('http://127.0.0.1:2369/content/images/2018/08/NatGeo02-10.jpg');
transformed.caption
.should.equal('A link to <a href="http://127.0.0.1:2369/post">an internal post</a>');
});
});

View File

@ -1,28 +0,0 @@
const should = require('should');
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 () {
let opts = {
env: {
dom: new SimpleDom.Document()
}
};
serializer.serialize(card.render(opts)).should.match('<hr>');
});
it('transforms urls absolute to relative', function () {
let payload = {};
const transformed = card.absoluteToRelative(payload, {});
transformed.should.deepEqual({});
});
it('transforms urls relative to absolute', function () {
let payload = {};
const transformed = card.relativeToAbsolute(payload, {});
transformed.should.deepEqual({});
});
});

View File

@ -1,80 +0,0 @@
const should = require('should');
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 () {
let opts = {
env: {
dom: new SimpleDom.Document()
},
payload: {
html: '<h1>HEADING</h1><p>PARAGRAPH</p>'
}
};
serializer.serialize(card.render(opts)).should.eql('<!--kg-card-begin: html--><h1>HEADING</h1><p>PARAGRAPH</p><!--kg-card-end: html-->');
});
it('Plain content renders', function () {
let opts = {
env: {
dom: new SimpleDom.Document()
},
payload: {
html: 'CONTENT'
}
};
serializer.serialize(card.render(opts)).should.eql('<!--kg-card-begin: html-->CONTENT<!--kg-card-end: html-->');
});
it('Invalid HTML returns', function () {
let opts = {
env: {
dom: new SimpleDom.Document()
},
payload: {
html: '<h1>HEADING<'
}
};
serializer.serialize(card.render(opts)).should.eql('<!--kg-card-begin: html--><h1>HEADING<<!--kg-card-end: html-->');
});
it('Renders nothing when payload is undefined', function () {
let opts = {
env: {
dom: new SimpleDom.Document()
},
payload: {
html: undefined
}
};
serializer.serialize(card.render(opts)).should.eql('');
});
it('transforms urls absolute to relative', function () {
let payload = {
html: 'A link to <a href="http://127.0.0.1:2369/post">an internal post</a>'
};
const transformed = card.absoluteToRelative(payload, {});
transformed.html
.should.equal('A link to <a href="/post">an internal post</a>');
});
it('transforms urls relative to absolute', function () {
let payload = {
html: 'A link to <a href="/post">an internal post</a>'
};
const transformed = card.relativeToAbsolute(payload, {});
transformed.html
.should.equal('A link to <a href="http://127.0.0.1:2369/post">an internal post</a>');
});
});

View File

@ -1,149 +0,0 @@
const should = require('should');
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('renders an image', function () {
let opts = {
env: {
dom: new SimpleDom.Document()
},
payload: {
src: 'https://www.ghost.org/image.png'
}
};
serializer.serialize(card.render(opts)).should.eql('<figure class="kg-card kg-image-card"><img src="https://www.ghost.org/image.png" class="kg-image"></figure>');
});
it('renders an image with caption', function () {
let opts = {
env: {
dom: new SimpleDom.Document()
},
payload: {
src: 'https://www.ghost.org/image.png',
caption: '<b>Test caption</b>'
}
};
serializer.serialize(card.render(opts)).should.eql('<figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.ghost.org/image.png" class="kg-image"><figcaption><b>Test caption</b></figcaption></figure>');
});
it('renders an image with alt text', function () {
let opts = {
env: {
dom: new SimpleDom.Document()
},
payload: {
src: 'https://www.ghost.org/image.png',
alt: 'example image'
}
};
serializer.serialize(card.render(opts)).should.eql('<figure class="kg-card kg-image-card"><img src="https://www.ghost.org/image.png" class="kg-image" alt="example image"></figure>');
});
it('renders an image with title attribute', function () {
let opts = {
env: {
dom: new SimpleDom.Document()
},
payload: {
src: 'https://www.ghost.org/image.png',
title: 'example image'
}
};
serializer.serialize(card.render(opts)).should.eql('<figure class="kg-card kg-image-card"><img src="https://www.ghost.org/image.png" class="kg-image" title="example image"></figure>');
});
it('renders nothing with no src', function () {
let opts = {
env: {
dom: new SimpleDom.Document()
},
payload: {
src: '',
caption: 'Test caption'
}
};
serializer.serialize(card.render(opts)).should.eql('');
});
describe('sizes', function () {
it('standard', function () {
let opts = {
env: {
dom: new SimpleDom.Document()
},
payload: {
src: 'https://www.ghost.org/image.png',
cardWidth: ''
}
};
serializer.serialize(card.render(opts)).should.eql('<figure class="kg-card 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',
cardWidth: 'wide'
}
};
serializer.serialize(card.render(opts)).should.eql('<figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.ghost.org/image.png" class="kg-image"></figure>');
});
it('full', function () {
let opts = {
env: {
dom: new SimpleDom.Document()
},
payload: {
src: 'https://www.ghost.org/image.png',
cardWidth: 'full'
}
};
serializer.serialize(card.render(opts)).should.eql('<figure class="kg-card kg-image-card kg-width-full"><img src="https://www.ghost.org/image.png" class="kg-image"></figure>');
});
});
it('transforms urls absolute to relative', function () {
let payload = {
src: 'http://127.0.0.1:2369/content/images/2018/08/NatGeo01-9.jpg',
caption: 'A link to <a href="http://127.0.0.1:2369/post">an internal post</a>'
};
const transformed = card.absoluteToRelative(payload, {});
transformed.src
.should.equal('/content/images/2018/08/NatGeo01-9.jpg');
transformed.caption
.should.equal('A link to <a href="/post">an internal post</a>');
});
it('transforms urls relative to absolute', function () {
let payload = {
src: '/content/images/2018/08/NatGeo01-9.jpg',
caption: 'A link to <a href="/post">an internal post</a>'
};
const transformed = card.relativeToAbsolute(payload, {});
transformed.src
.should.equal('http://127.0.0.1:2369/content/images/2018/08/NatGeo01-9.jpg');
transformed.caption
.should.equal('A link to <a href="http://127.0.0.1:2369/post">an internal post</a>');
});
});

View File

@ -1,67 +0,0 @@
const should = require('should');
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('renders', function () {
let opts = {
env: {
dom: new SimpleDom.Document()
},
payload: {
markdown: '#HEADING\r\n- list\r\n- items'
}
};
serializer.serialize(card.render(opts)).should.eql('<!--kg-card-begin: markdown--><h1 id="heading">HEADING</h1>\n<ul>\n<li>list</li>\n<li>items</li>\n</ul>\n<!--kg-card-end: markdown-->');
});
it('Accepts invalid HTML in markdown', function () {
let opts = {
env: {
dom: new SimpleDom.Document()
},
payload: {
markdown: '#HEADING\r\n<h2>Heading 2>'
}
};
serializer.serialize(card.render(opts)).should.eql('<!--kg-card-begin: markdown--><h1 id="heading">HEADING</h1>\n<h2>Heading 2><!--kg-card-end: markdown-->');
});
it('Renders nothing when payload is undefined', function () {
let opts = {
env: {
dom: new SimpleDom.Document()
},
payload: {
markdown: undefined
}
};
serializer.serialize(card.render(opts)).should.eql('');
});
it('transforms urls absolute to relative', function () {
let payload = {
markdown: 'A link to [an internal post](http://127.0.0.1:2369/post)'
};
const transformed = card.absoluteToRelative(payload, {});
transformed.markdown
.should.equal('A link to [an internal post](/post)');
});
it('transforms urls relative to absolute', function () {
let payload = {
markdown: 'A link to [an internal post](/post)'
};
const transformed = card.relativeToAbsolute(payload, {});
transformed.markdown
.should.equal('A link to [an internal post](http://127.0.0.1:2369/post)');
});
});

View File

@ -44,7 +44,9 @@
"@tryghost/errors": "^0.1.0",
"@tryghost/helpers": "1.1.23",
"@tryghost/image-transform": "^0.1.0",
"@tryghost/kg-markdown-html-renderer": "1.0.0",
"@tryghost/kg-card-factory": "1.0.1",
"@tryghost/kg-default-cards": "1.0.1",
"@tryghost/kg-markdown-html-renderer": "1.0.2",
"@tryghost/members-api": "0.18.0",
"@tryghost/members-ssr": "0.7.4",
"@tryghost/social-urls": "0.1.6",

View File

@ -343,19 +343,29 @@
optionalDependencies:
sharp "^0.25.2"
"@tryghost/kg-card-factory@1.0.1":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@tryghost/kg-card-factory/-/kg-card-factory-1.0.1.tgz#ad4973bab4f7dbc99722c739b2c520831febed54"
integrity sha512-qMWypZEths/F5pvbPKSlHJJ4CK4uwMaGM3jB7IdG9uw4kHPxWJFnuUn+QHvEUbcAvS484QTExVEzIc8vmSSN5A==
"@tryghost/kg-clean-basic-html@^0.1.5":
version "0.1.5"
resolved "https://registry.yarnpkg.com/@tryghost/kg-clean-basic-html/-/kg-clean-basic-html-0.1.5.tgz#21cbe9036472c04b2320b1feb359c9c40ff3a300"
integrity sha512-jl+NKYryIL+KUQb4XNcMgu9l/K12oASgZYuRqi6GCm0JKhz1qD56vavIpKAlPjJyMOhSfD0MicoX887ijgvqyQ==
"@tryghost/kg-markdown-html-renderer@1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@tryghost/kg-markdown-html-renderer/-/kg-markdown-html-renderer-1.0.0.tgz#7a68a5700955b031b29b3a70f7ab5b5391d7746e"
integrity sha512-MC+rxwaxkM7g+EkihYr6dmyc8CUkVVahDxjxEcKlVAVWpnB8GN/paaS1Lgv9n9KxqEHCuvewhCDPwH93sczTNg==
"@tryghost/kg-default-cards@1.0.1":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@tryghost/kg-default-cards/-/kg-default-cards-1.0.1.tgz#f6855db115af0868ecbe443a46123f856e006d9a"
integrity sha512-rca9u9dHq9bxvjnZ40LW0DgmBqAcrPT8hnQiC+i67pm+SHixGwcZ/IjB5Y4iilfDffq4k1Rk2sFgfHw+WBUcew==
dependencies:
"@tryghost/kg-markdown-html-renderer" "^1.0.2"
"@tryghost/url-utils" "^0.6.14"
"@tryghost/kg-markdown-html-renderer@1.0.2", "@tryghost/kg-markdown-html-renderer@^1.0.2":
version "1.0.2"
resolved "https://registry.yarnpkg.com/@tryghost/kg-markdown-html-renderer/-/kg-markdown-html-renderer-1.0.2.tgz#c2cb8ab23803ce72501831740c6950d12881de9d"
integrity sha512-gM0LvLgw+PeK+opUaqqtxY6gMNWaw7oNfUrDzjfYWszRw6CJDp4JrzE5vlyM+divh5HegGUeGsym2yXBBOIQ8g==
dependencies:
bluebird "^3.7.2"
ghost-ignition "^4.1.0"
lodash "^4.17.15"
markdown-it "^10.0.0"
markdown-it-footnote "^3.0.2"
markdown-it-lazy-headers "^0.1.3"
@ -439,7 +449,7 @@
dependencies:
unidecode "^0.1.8"
"@tryghost/url-utils@0.6.14":
"@tryghost/url-utils@0.6.14", "@tryghost/url-utils@^0.6.14":
version "0.6.14"
resolved "https://registry.yarnpkg.com/@tryghost/url-utils/-/url-utils-0.6.14.tgz#aa1ef94531530635cba0cb6d75933bda1a557719"
integrity sha512-GpEN2ZJXqESsp5lUEDEBNPm0HQholhF3pfPlOUx/r/B6YHXBHCH7blgXwDAoo+/I7mKMDCVNf+AA/FXdCrVgJQ==