mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-26 12:21:36 +03:00
✨ 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:
parent
bbf5164b79
commit
4edebe9f1e
@ -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']
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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, '');
|
||||||
|
47
ghost/admin/app/utils/format-markdown.js
Normal file
47
ghost/admin/app/utils/format-markdown.js
Normal 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;
|
||||||
|
}
|
@ -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
Loading…
Reference in New Issue
Block a user