mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-02-10 23:36:14 -05:00
Improving the showdown extensions
fixes #2381 - renamed the ghost extensions - added new html tests
This commit is contained in:
parent
3ad4c27968
commit
c02fd70c63
8 changed files with 93 additions and 67 deletions
|
@ -460,8 +460,8 @@ var path = require('path'),
|
||||||
'bower_components/showdown/src/showdown.js',
|
'bower_components/showdown/src/showdown.js',
|
||||||
'bower_components/validator-js/validator.js',
|
'bower_components/validator-js/validator.js',
|
||||||
|
|
||||||
'core/client/assets/lib/showdown/extensions/ghostdown.js',
|
'core/shared/lib/showdown/extensions/ghostimagepreview.js',
|
||||||
'core/shared/lib/showdown/extensions/github.js',
|
'core/shared/lib/showdown/extensions/ghostgfm.js',
|
||||||
|
|
||||||
// ToDo: Remove or replace
|
// ToDo: Remove or replace
|
||||||
'core/client/assets/vendor/shortcuts.js',
|
'core/client/assets/vendor/shortcuts.js',
|
||||||
|
@ -522,8 +522,8 @@ var path = require('path'),
|
||||||
'bower_components/showdown/src/showdown.js',
|
'bower_components/showdown/src/showdown.js',
|
||||||
'bower_components/validator-js/validator.js',
|
'bower_components/validator-js/validator.js',
|
||||||
|
|
||||||
'core/client/assets/lib/showdown/extensions/ghostdown.js',
|
'core/shared/lib/showdown/extensions/ghostimagepreview.js',
|
||||||
'core/shared/lib/showdown/extensions/github.js',
|
'core/shared/lib/showdown/extensions/ghostgfm.js',
|
||||||
|
|
||||||
// ToDo: Remove or replace
|
// ToDo: Remove or replace
|
||||||
'core/client/assets/vendor/shortcuts.js',
|
'core/client/assets/vendor/shortcuts.js',
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var HTMLPreview = function (markdown, uploadMgr) {
|
var HTMLPreview = function (markdown, uploadMgr) {
|
||||||
var converter = new Showdown.converter({extensions: ['ghostdown', 'github']}),
|
var converter = new Showdown.converter({extensions: ['ghostimagepreview', 'ghostgfm']}),
|
||||||
preview = document.getElementsByClassName('rendered-markdown')[0],
|
preview = document.getElementsByClassName('rendered-markdown')[0],
|
||||||
update;
|
update;
|
||||||
|
|
||||||
|
|
|
@ -3,8 +3,8 @@ var _ = require('lodash'),
|
||||||
when = require('when'),
|
when = require('when'),
|
||||||
errors = require('../errorHandling'),
|
errors = require('../errorHandling'),
|
||||||
Showdown = require('showdown'),
|
Showdown = require('showdown'),
|
||||||
github = require('../../shared/lib/showdown/extensions/github'),
|
ghostgfm = require('../../shared/lib/showdown/extensions/ghostgfm'),
|
||||||
converter = new Showdown.converter({extensions: [github]}),
|
converter = new Showdown.converter({extensions: [ghostgfm]}),
|
||||||
User = require('./user').User,
|
User = require('./user').User,
|
||||||
Tag = require('./tag').Tag,
|
Tag = require('./tag').Tag,
|
||||||
Tags = require('./tag').Tags,
|
Tags = require('./tag').Tags,
|
||||||
|
|
|
@ -1,10 +1,16 @@
|
||||||
|
/* jshint node:true, browser:true */
|
||||||
|
|
||||||
|
// Ghost GFM
|
||||||
|
// Taken and extended from the Showdown Github Extension (WIP)
|
||||||
|
// Makes a number of pre and post-processing changes to the way markdown is handled
|
||||||
//
|
//
|
||||||
// Github Extension (WIP)
|
// ~~strike-through~~ -> <del>strike-through</del> (Pre)
|
||||||
// ~~strike-through~~ -> <del>strike-through</del>
|
// GFM newlines & underscores (Pre)
|
||||||
//
|
// 4 or more underscores (Pre)
|
||||||
|
// autolinking / custom image handling (Post)
|
||||||
|
|
||||||
(function () {
|
(function () {
|
||||||
var github = function (converter) {
|
var ghostgfm = function () {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
// strike-through
|
// strike-through
|
||||||
|
@ -73,6 +79,17 @@
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// 4 or more inline underscores e.g. Ghost rocks my _____!
|
||||||
|
{
|
||||||
|
type: 'lang',
|
||||||
|
filter: function (text) {
|
||||||
|
return text.replace(/([^_\n\r])(_{4,})/g, function (match, prefix, underscores) {
|
||||||
|
return prefix + underscores.replace(/_/g, '_');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
// GFM autolinking & custom image handling, happens AFTER showdown
|
// GFM autolinking & custom image handling, happens AFTER showdown
|
||||||
type : 'html',
|
type : 'html',
|
||||||
|
@ -131,7 +148,11 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
// Client-side export
|
// Client-side export
|
||||||
if (typeof window !== 'undefined' && window.Showdown && window.Showdown.extensions) { window.Showdown.extensions.github = github; }
|
if (typeof window !== 'undefined' && window.Showdown && window.Showdown.extensions) {
|
||||||
|
window.Showdown.extensions.ghostgfm = ghostgfm;
|
||||||
|
}
|
||||||
// Server-side export
|
// Server-side export
|
||||||
if (typeof module !== 'undefined') module.exports = github;
|
if (typeof module !== 'undefined') {
|
||||||
|
module.exports = ghostgfm;
|
||||||
|
}
|
||||||
}());
|
}());
|
|
@ -1,7 +1,15 @@
|
||||||
/* jshint node:true, browser:true */
|
/* jshint node:true, browser:true */
|
||||||
|
|
||||||
|
// Ghost Image Preview
|
||||||
|
//
|
||||||
|
// Manages the conversion of image markdown `![]()` from markdown into the HTML image preview
|
||||||
|
// This provides a dropzone and other interface elements for adding images
|
||||||
|
// Is only used in the admin client.
|
||||||
|
|
||||||
|
|
||||||
var Ghost = Ghost || {};
|
var Ghost = Ghost || {};
|
||||||
(function () {
|
(function () {
|
||||||
var ghostdown = function () {
|
var ghostimagepreview = function () {
|
||||||
return [
|
return [
|
||||||
// ![] image syntax
|
// ![] image syntax
|
||||||
{
|
{
|
||||||
|
@ -33,26 +41,16 @@ var Ghost = Ghost || {};
|
||||||
return output;
|
return output;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
|
||||||
|
|
||||||
// 4 or more inline underscores e.g. Ghost rocks my _____!
|
|
||||||
{
|
|
||||||
type: 'lang',
|
|
||||||
filter: function (text) {
|
|
||||||
return text.replace(/([^_\n\r])(_{4,})/g, function (match, prefix, underscores) {
|
|
||||||
return prefix + underscores.replace(/_/g, '_');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
// Client-side export
|
// Client-side export
|
||||||
if (typeof window !== 'undefined' && window.Showdown && window.Showdown.extensions) {
|
if (typeof window !== 'undefined' && window.Showdown && window.Showdown.extensions) {
|
||||||
window.Showdown.extensions.ghostdown = ghostdown;
|
window.Showdown.extensions.ghostimagepreview = ghostimagepreview;
|
||||||
}
|
}
|
||||||
// Server-side export
|
// Server-side export
|
||||||
if (typeof module !== 'undefined') {
|
if (typeof module !== 'undefined') {
|
||||||
module.exports = ghostdown;
|
module.exports = ghostimagepreview;
|
||||||
}
|
}
|
||||||
}());
|
}());
|
|
@ -5,14 +5,15 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*globals describe, it */
|
/*globals describe, it */
|
||||||
var testUtils = require('../utils'),
|
var testUtils = require('../utils'),
|
||||||
should = require('should'),
|
should = require('should'),
|
||||||
|
|
||||||
// Stuff we are testing
|
// Stuff we are testing
|
||||||
Showdown = require('showdown'),
|
Showdown = require('showdown'),
|
||||||
github = require('../../shared/lib/showdown/extensions/github'),
|
ghostgfm = require('../../shared/lib/showdown/extensions/ghostgfm'),
|
||||||
ghostdown = require('../../client/assets/lib/showdown/extensions/ghostdown'),
|
ghostimagepreview = require('../../shared/lib/showdown/extensions/ghostimagepreview'),
|
||||||
converter = new Showdown.converter({extensions: [ghostdown, github]});
|
|
||||||
|
converter = new Showdown.converter({extensions: [ghostimagepreview, ghostgfm]});
|
||||||
|
|
||||||
describe("Showdown client side converter", function () {
|
describe("Showdown client side converter", function () {
|
||||||
/*jslint regexp: true */
|
/*jslint regexp: true */
|
||||||
|
@ -107,7 +108,7 @@ describe("Showdown client side converter", function () {
|
||||||
it("should turn newlines into br tags in simple cases", function () {
|
it("should turn newlines into br tags in simple cases", function () {
|
||||||
var testPhrases = [
|
var testPhrases = [
|
||||||
{input: "fizz\nbuzz", output: /^<p>fizz <br \/>\nbuzz<\/p>$/},
|
{input: "fizz\nbuzz", output: /^<p>fizz <br \/>\nbuzz<\/p>$/},
|
||||||
{input: "Hello world\nIt's a fine day", output: /^<p>Hello world <br \/>\nIt\'s a fine day<\/p>$/},
|
{input: "Hello world\nIt is a fine day", output: /^<p>Hello world <br \/>\nIt is a fine day<\/p>$/},
|
||||||
{input: "\"first\nsecond", output: /^<p>\"first <br \/>\nsecond<\/p>$/},
|
{input: "\"first\nsecond", output: /^<p>\"first <br \/>\nsecond<\/p>$/},
|
||||||
{input: "\'first\nsecond", output: /^<p>\'first <br \/>\nsecond<\/p>$/}
|
{input: "\'first\nsecond", output: /^<p>\'first <br \/>\nsecond<\/p>$/}
|
||||||
],
|
],
|
||||||
|
@ -122,7 +123,7 @@ describe("Showdown client side converter", function () {
|
||||||
it("should convert newlines in all groups", function () {
|
it("should convert newlines in all groups", function () {
|
||||||
var testPhrases = [
|
var testPhrases = [
|
||||||
{input: "ruby\npython\nerlang", output: /^<p>ruby <br \/>\npython <br \/>\nerlang<\/p>$/},
|
{input: "ruby\npython\nerlang", output: /^<p>ruby <br \/>\npython <br \/>\nerlang<\/p>$/},
|
||||||
{input: "Hello world\nIt's a fine day\nout", output: /^<p>Hello world <br \/>\nIt\'s a fine day <br \/>\nout<\/p>$/}
|
{input: "Hello world\nIt is a fine day\nout", output: /^<p>Hello world <br \/>\nIt is a fine day <br \/>\nout<\/p>$/}
|
||||||
],
|
],
|
||||||
processedMarkup;
|
processedMarkup;
|
||||||
|
|
||||||
|
@ -134,10 +135,13 @@ describe("Showdown client side converter", function () {
|
||||||
|
|
||||||
it("should convert newlines in even long groups", function () {
|
it("should convert newlines in even long groups", function () {
|
||||||
var testPhrases = [
|
var testPhrases = [
|
||||||
{input: "ruby\npython\nerlang\ngo", output: /^<p>ruby <br \/>\npython <br \/>\nerlang <br \/>\ngo<\/p>$/},
|
|
||||||
{
|
{
|
||||||
input: "Hello world\nIt's a fine day\noutside\nthe window",
|
input: "ruby\npython\nerlang\ngo",
|
||||||
output: /^<p>Hello world <br \/>\nIt\'s a fine day <br \/>\noutside <br \/>\nthe window<\/p>$/
|
output: /^<p>ruby <br \/>\npython <br \/>\nerlang <br \/>\ngo<\/p>$/
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "Hello world\nIt is a fine day\noutside\nthe window",
|
||||||
|
output: /^<p>Hello world <br \/>\nIt is a fine day <br \/>\noutside <br \/>\nthe window<\/p>$/
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
processedMarkup;
|
processedMarkup;
|
||||||
|
@ -150,8 +154,14 @@ describe("Showdown client side converter", function () {
|
||||||
|
|
||||||
it("should not convert newlines in lists", function () {
|
it("should not convert newlines in lists", function () {
|
||||||
var testPhrases = [
|
var testPhrases = [
|
||||||
{input: "#fizz\n# buzz\n### baz", output: /^<h1 id="fizz">fizz<\/h1>\n\n<h1 id="buzz">buzz<\/h1>\n\n<h3 id="baz">baz<\/h3>$/},
|
{
|
||||||
{input: "* foo\n* bar", output: /^<ul>\n<li>foo<\/li>\n<li>bar<\/li>\n<\/ul>$/}
|
input: "#fizz\n# buzz\n### baz",
|
||||||
|
output: /^<h1 id="fizz">fizz<\/h1>\n\n<h1 id="buzz">buzz<\/h1>\n\n<h3 id="baz">baz<\/h3>$/
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "* foo\n* bar",
|
||||||
|
output: /^<ul>\n<li>foo<\/li>\n<li>bar<\/li>\n<\/ul>$/
|
||||||
|
}
|
||||||
],
|
],
|
||||||
processedMarkup;
|
processedMarkup;
|
||||||
|
|
|
@ -4,12 +4,11 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*globals describe, it */
|
/*globals describe, it */
|
||||||
var testUtils = require('../utils'),
|
var testUtils = require('../utils'),
|
||||||
should = require('should'),
|
should = require('should'),
|
||||||
|
|
||||||
// Stuff we are testing
|
// Stuff we are testing
|
||||||
ghPath = "../../shared/lib/showdown/extensions/github.js",
|
ghostgfm = require('../../shared/lib/showdown/extensions/ghostgfm');
|
||||||
github = require(ghPath);
|
|
||||||
|
|
||||||
function _ExecuteExtension(ext, text) {
|
function _ExecuteExtension(ext, text) {
|
||||||
if (ext.regex) {
|
if (ext.regex) {
|
||||||
|
@ -21,20 +20,20 @@ function _ExecuteExtension(ext, text) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function _ConvertPhrase(testPhrase) {
|
function _ConvertPhrase(testPhrase) {
|
||||||
return github().reduce(function (text, ext) {
|
return ghostgfm().reduce(function (text, ext) {
|
||||||
return _ExecuteExtension(ext, text);
|
return _ExecuteExtension(ext, text);
|
||||||
}, testPhrase);
|
}, testPhrase);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
describe("Github showdown extensions", function () {
|
describe("Ghost GFM showdown extension", function () {
|
||||||
/*jslint regexp: true */
|
/*jslint regexp: true */
|
||||||
|
|
||||||
it("should export an array of methods for processing", function () {
|
it("should export an array of methods for processing", function () {
|
||||||
github.should.be.a.function;
|
ghostgfm.should.be.a.function;
|
||||||
github().should.be.an.Array;
|
ghostgfm().should.be.an.Array;
|
||||||
|
|
||||||
github().forEach(function (processor) {
|
ghostgfm().forEach(function (processor) {
|
||||||
processor.should.be.an.Object;
|
processor.should.be.an.Object;
|
||||||
processor.should.have.property("type");
|
processor.should.have.property("type");
|
||||||
processor.type.should.be.a.String;
|
processor.type.should.be.a.String;
|
||||||
|
@ -50,6 +49,14 @@ describe("Github showdown extensions", function () {
|
||||||
processedMarkup.should.match(testPhrase.output);
|
processedMarkup.should.match(testPhrase.output);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should allow 4 underscores", function () {
|
||||||
|
var testPhrase = {input: 'Ghost ____', output: /Ghost\s(?:_){4}$/},
|
||||||
|
processedMarkup = _ConvertPhrase(testPhrase.input);
|
||||||
|
|
||||||
|
processedMarkup.should.match(testPhrase.output);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
it("should auto-link URL in text with markdown syntax", function () {
|
it("should auto-link URL in text with markdown syntax", function () {
|
||||||
var testPhrases = [
|
var testPhrases = [
|
||||||
{
|
{
|
|
@ -6,21 +6,20 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*globals describe, it */
|
/*globals describe, it */
|
||||||
var testUtils = require('../utils'),
|
var testUtils = require('../utils'),
|
||||||
should = require('should'),
|
should = require('should'),
|
||||||
|
|
||||||
// Stuff we are testing
|
// Stuff we are testing
|
||||||
gdPath = "../../client/assets/lib/showdown/extensions/ghostdown.js",
|
ghostimagepreview = require('../../shared/lib/showdown/extensions/ghostimagepreview');
|
||||||
ghostdown = require(gdPath);
|
|
||||||
|
|
||||||
describe("Ghostdown showdown extensions", function () {
|
describe("Ghost Image Preview showdown extension", function () {
|
||||||
|
|
||||||
it("should export an array of methods for processing", function () {
|
it("should export an array of methods for processing", function () {
|
||||||
|
|
||||||
ghostdown.should.be.a.function;
|
ghostimagepreview.should.be.a.function;
|
||||||
ghostdown().should.be.an.instanceof(Array);
|
ghostimagepreview().should.be.an.instanceof(Array);
|
||||||
|
|
||||||
ghostdown().forEach(function (processor) {
|
ghostimagepreview().forEach(function (processor) {
|
||||||
processor.should.be.an.Object;
|
processor.should.be.an.Object;
|
||||||
processor.should.have.property("type");
|
processor.should.have.property("type");
|
||||||
processor.should.have.property("filter");
|
processor.should.have.property("filter");
|
||||||
|
@ -46,7 +45,7 @@ describe("Ghostdown showdown extensions", function () {
|
||||||
]
|
]
|
||||||
.forEach(function (imageMarkup) {
|
.forEach(function (imageMarkup) {
|
||||||
var processedMarkup =
|
var processedMarkup =
|
||||||
ghostdown().reduce(function (prev, processor) {
|
ghostimagepreview().reduce(function (prev, processor) {
|
||||||
return processor.filter(prev);
|
return processor.filter(prev);
|
||||||
}, imageMarkup);
|
}, imageMarkup);
|
||||||
|
|
||||||
|
@ -55,15 +54,6 @@ describe("Ghostdown showdown extensions", function () {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should allow 4 underscores", function () {
|
|
||||||
var processedMarkup =
|
|
||||||
ghostdown().reduce(function (prev, processor) {
|
|
||||||
return processor.filter(prev);
|
|
||||||
}, "Ghost ____");
|
|
||||||
|
|
||||||
processedMarkup.should.match(/Ghost\s(?:_){4}$/);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should correctly include an image", function () {
|
it("should correctly include an image", function () {
|
||||||
[
|
[
|
||||||
"![image and another,/ image](http://dsurl.stuff)",
|
"![image and another,/ image](http://dsurl.stuff)",
|
||||||
|
@ -75,7 +65,7 @@ describe("Ghostdown showdown extensions", function () {
|
||||||
]
|
]
|
||||||
.forEach(function (imageMarkup) {
|
.forEach(function (imageMarkup) {
|
||||||
var processedMarkup =
|
var processedMarkup =
|
||||||
ghostdown().reduce(function (prev, processor) {
|
ghostimagepreview().reduce(function (prev, processor) {
|
||||||
return processor.filter(prev);
|
return processor.filter(prev);
|
||||||
}, imageMarkup);
|
}, imageMarkup);
|
||||||
|
|
Loading…
Add table
Reference in a new issue