use markdown-it for markdown previews (#690)

 use markdown-it for markdown previews

no issue

- replaces SimpleMDE's default `marked` rendering with `markdown-it`
- add ember-browserify and markdown-it plugins
This commit is contained in:
Kevin Ansfield 2017-05-15 17:51:19 +01:00 committed by Katharina Irrgang
parent bbf5164b79
commit 4edebe9f1e
5 changed files with 875 additions and 42 deletions

View File

@ -4,6 +4,7 @@ import {assign} from 'ember-platform';
import {copy} from 'ember-metal/utils'; import {copy} from 'ember-metal/utils';
import {isEmpty} from 'ember-utils'; import {isEmpty} from 'ember-utils';
import run from 'ember-runloop'; import run from 'ember-runloop';
import formatMarkdown from 'ghost-admin/utils/format-markdown';
const MOBILEDOC_VERSION = '0.3.1'; const MOBILEDOC_VERSION = '0.3.1';
@ -57,11 +58,16 @@ export default Component.extend({
_toolbar: null, _toolbar: null,
_uploadedImageUrls: null, _uploadedImageUrls: null,
// Ghost-Specific SimpleMDE toolbar config - allows us to create a bridge
// between SimpleMDE buttons and Ember actions
simpleMDEOptions: computed('options', function () { simpleMDEOptions: computed('options', function () {
let options = this.get('options') || {}; let options = this.get('options') || {};
let defaultOptions = { let defaultOptions = {
// use our Showdown config with sanitization for previews
previewRender(markdown) {
return formatMarkdown(markdown);
},
// Ghost-specific SimpleMDE toolbar config - allows us to create a
// bridge between SimpleMDE buttons and Ember actions
toolbar: [ toolbar: [
'bold', 'italic', 'heading', '|', 'bold', 'italic', 'heading', '|',
'quote', 'unordered-list', 'ordered-list', '|', 'quote', 'unordered-list', 'ordered-list', '|',
@ -109,11 +115,17 @@ export default Component.extend({
title: 'Markdown Guide' title: 'Markdown Guide'
} }
], ],
// disable shortcuts for side-by-side and fullscreen because they
// trigger interal SimpleMDE methods that will result in broken
// layouts
shortcuts: { shortcuts: {
toggleFullScreen: null, toggleFullScreen: null,
togglePreview: null, togglePreview: null,
toggleSideBySide: null toggleSideBySide: null
}, },
// only include the number of words in the status bar
status: ['words'] status: ['words']
}; };

View File

@ -4,6 +4,7 @@
/** /**
* Check if URL is allowed * Check if URL is allowed
* URLs are allowed if they start with http://, https://, or /. * URLs are allowed if they start with http://, https://, or /.
* NOTE: # urls are not allowed as clicking them will break the editor when clicked
*/ */
let url = function (url) { let url = function (url) {
url = url.toString().replace(/['"]+/g, ''); url = url.toString().replace(/['"]+/g, '');

View File

@ -0,0 +1,47 @@
/* global html_sanitize */
import cajaSanitizers from './caja-sanitizers';
import markdownit from 'npm:markdown-it';
import markdownitFootnote from 'npm:markdown-it-footnote';
import markdownitLazyHeaders from 'npm:markdown-it-lazy-headers';
import markdownitMark from 'npm:markdown-it-mark';
import markdownitNamedHeaders from 'npm:markdown-it-named-headers';
// eslint-disable-next-line new-cap
let md = markdownit({
html: true,
breaks: true,
linkify: true
})
.use(markdownitFootnote)
.use(markdownitLazyHeaders)
.use(markdownitMark)
.use(markdownitNamedHeaders, {
// match legacy Showdown IDs otherwise default is github style dasherized
slugify(inputString, usedHeaders) {
let slug = inputString.replace(/[^\w]/g, '').toLowerCase();
if (usedHeaders[slug]) {
usedHeaders[slug]++;
slug += usedHeaders[slug];
}
return slug;
}
});
export default function formatMarkdown(_markdown) {
let markdown = _markdown || '';
let escapedhtml = '';
// convert markdown to HTML
escapedhtml = md.render(markdown);
// replace script and iFrame
escapedhtml = escapedhtml.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,
'<pre class="js-embed-placeholder">Embedded JavaScript</pre>');
escapedhtml = escapedhtml.replace(/<iframe\b[^<]*(?:(?!<\/iframe>)<[^<]*)*<\/iframe>/gi,
'<pre class="iframe-embed-placeholder">Embedded iFrame</pre>');
// sanitize html
escapedhtml = html_sanitize(escapedhtml, cajaSanitizers.url, cajaSanitizers.id);
return escapedhtml;
}

View File

@ -41,6 +41,7 @@
"csscomb": "4.0.1", "csscomb": "4.0.1",
"cssnano": "3.10.0", "cssnano": "3.10.0",
"ember-ajax": "2.5.6", "ember-ajax": "2.5.6",
"ember-browserify": "1.1.13",
"ember-cli": "2.13.1", "ember-cli": "2.13.1",
"ember-cli-active-link-wrapper": "0.3.2", "ember-cli-active-link-wrapper": "0.3.2",
"ember-cli-app-version": "3.0.0", "ember-cli-app-version": "3.0.0",
@ -97,6 +98,11 @@
"liquid-fire": "0.27.3", "liquid-fire": "0.27.3",
"liquid-wormhole": "2.0.5", "liquid-wormhole": "2.0.5",
"loader.js": "4.4.0", "loader.js": "4.4.0",
"markdown-it": "8.3.1",
"markdown-it-footnote": "3.0.1",
"markdown-it-lazy-headers": "0.1.3",
"markdown-it-mark": "2.0.0",
"markdown-it-named-headers": "0.0.4",
"matchdep": "1.0.1", "matchdep": "1.0.1",
"password-generator": "2.1.0", "password-generator": "2.1.0",
"postcss-color-function": "3.0.0", "postcss-color-function": "3.0.0",

File diff suppressed because it is too large Load Diff