mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-26 20:34:02 +03:00
Koenig - Improve MD text expansion behaviour
refs https://github.com/TryGhost/Ghost/issues/9505 - fix overzealous matching of inline formatting - ensure the match starts with a space or the start of the paragraph - ensure the start matched chars are not followed by a space - ensure the end matched chars are not preceded by a space - avoid matching more MD chars than expected - allow text expansions to work when editing text in the middle of a paragraph - do not add a trailing space after reformatting in this case
This commit is contained in:
parent
775e59f55b
commit
cc083ef93f
@ -20,27 +20,28 @@ export default function (editor) {
|
|||||||
editor.onTextInput({
|
editor.onTextInput({
|
||||||
name: 'inline_markdown',
|
name: 'inline_markdown',
|
||||||
match: /[*_)~`]$/,
|
match: /[*_)~`]$/,
|
||||||
run(postEditor, matches) {
|
run(editor, matches) {
|
||||||
let text = postEditor.range.head.section.textUntil(postEditor.range.head);
|
let text = editor.range.head.section.textUntil(editor.range.head);
|
||||||
|
let hasTextAfter = editor.range.head.section.text.length > text.length;
|
||||||
|
|
||||||
switch (matches[0]) {
|
switch (matches[0]) {
|
||||||
case '*':
|
case '*':
|
||||||
matchStrongStar(postEditor, text);
|
matchStrongStar(editor, text, hasTextAfter);
|
||||||
matchEmStar(postEditor, text);
|
matchEmStar(editor, text, hasTextAfter);
|
||||||
break;
|
break;
|
||||||
case '_':
|
case '_':
|
||||||
matchStrongUnderscore(postEditor, text);
|
matchStrongUnderscore(editor, text, hasTextAfter);
|
||||||
matchEmUnderscore(postEditor, text);
|
matchEmUnderscore(editor, text, hasTextAfter);
|
||||||
break;
|
break;
|
||||||
case ')':
|
case ')':
|
||||||
matchLink(postEditor, text);
|
matchLink(editor, text, hasTextAfter);
|
||||||
matchImage(postEditor, text);
|
matchImage(editor, text, hasTextAfter);
|
||||||
break;
|
break;
|
||||||
case '~':
|
case '~':
|
||||||
matchStrikethrough(postEditor, text);
|
matchStrikethrough(editor, text, hasTextAfter);
|
||||||
break;
|
break;
|
||||||
case '`':
|
case '`':
|
||||||
matchCode(postEditor, text);
|
matchCode(editor, text, hasTextAfter);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -99,37 +100,43 @@ export default function (editor) {
|
|||||||
|
|
||||||
/* inline markdown ------------------------------------------------------ */
|
/* inline markdown ------------------------------------------------------ */
|
||||||
|
|
||||||
function matchStrongStar(editor, text) {
|
function matchStrongStar(editor, text, hasTextAfter = false) {
|
||||||
let {range} = editor;
|
let {range} = editor;
|
||||||
let matches = text.match(/\*\*(.+?)\*\*$/);
|
let matches = text.match(/(^|\s)\*\*([^\s*].+?[^\s*])\*\*/);
|
||||||
if (matches) {
|
if (matches) {
|
||||||
range = range.extend(-(matches[0].length));
|
let match = matches[0][0] === '*' ? matches[0] : matches[0].substr(1);
|
||||||
|
range = range.extend(-(match.length));
|
||||||
editor.run((postEditor) => {
|
editor.run((postEditor) => {
|
||||||
let position = postEditor.deleteRange(range);
|
let position = postEditor.deleteRange(range);
|
||||||
let bold = postEditor.builder.createMarkup('strong');
|
let bold = postEditor.builder.createMarkup('strong');
|
||||||
let nextPosition = postEditor.insertTextWithMarkup(position, matches[1], [bold]);
|
let nextPosition = postEditor.insertTextWithMarkup(position, matches[2], [bold]);
|
||||||
postEditor.insertTextWithMarkup(nextPosition, ' ', []);
|
if (!hasTextAfter) {
|
||||||
|
postEditor.insertTextWithMarkup(nextPosition, ' ', []);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function matchStrongUnderscore(editor, text) {
|
function matchStrongUnderscore(editor, text, hasTextAfter = false) {
|
||||||
let {range} = editor;
|
let {range} = editor;
|
||||||
let matches = text.match(/__(.+?)__$/);
|
let matches = text.match(/(^|\s)__([^\s_].+?[^\s_])__/);
|
||||||
if (matches) {
|
if (matches) {
|
||||||
range = range.extend(-(matches[0].length));
|
let match = matches[0][0] === '_' ? matches[0] : matches[0].substr(1);
|
||||||
|
range = range.extend(-(match.length));
|
||||||
editor.run((postEditor) => {
|
editor.run((postEditor) => {
|
||||||
let position = postEditor.deleteRange(range);
|
let position = postEditor.deleteRange(range);
|
||||||
let bold = postEditor.builder.createMarkup('strong');
|
let bold = postEditor.builder.createMarkup('strong');
|
||||||
let nextPosition = postEditor.insertTextWithMarkup(position, matches[1], [bold]);
|
let nextPosition = postEditor.insertTextWithMarkup(position, matches[2], [bold]);
|
||||||
postEditor.insertTextWithMarkup(nextPosition, ' ', []);
|
if (!hasTextAfter) {
|
||||||
|
postEditor.insertTextWithMarkup(nextPosition, ' ', []);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function matchEmStar(editor, text) {
|
function matchEmStar(editor, text, hasTextAfter = false) {
|
||||||
let {range} = editor;
|
let {range} = editor;
|
||||||
let matches = text.match(/(^|[^*])\*([^*].*?)\*$/);
|
let matches = text.match(/(^|\s)\*([^\s*][^*]+?[^\s])\*/);
|
||||||
if (matches) {
|
if (matches) {
|
||||||
let match = matches[0][0] === '*' ? matches[0] : matches[0].substr(1);
|
let match = matches[0][0] === '*' ? matches[0] : matches[0].substr(1);
|
||||||
range = range.extend(-(match.length));
|
range = range.extend(-(match.length));
|
||||||
@ -137,14 +144,16 @@ export default function (editor) {
|
|||||||
let position = postEditor.deleteRange(range);
|
let position = postEditor.deleteRange(range);
|
||||||
let em = postEditor.builder.createMarkup('em');
|
let em = postEditor.builder.createMarkup('em');
|
||||||
let nextPosition = postEditor.insertTextWithMarkup(position, matches[2], [em]);
|
let nextPosition = postEditor.insertTextWithMarkup(position, matches[2], [em]);
|
||||||
postEditor.insertTextWithMarkup(nextPosition, ' ', []);
|
if (!hasTextAfter) {
|
||||||
|
postEditor.insertTextWithMarkup(nextPosition, ' ', []);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function matchEmUnderscore(editor, text) {
|
function matchEmUnderscore(editor, text, hasTextAfter = false) {
|
||||||
let {range} = editor;
|
let {range} = editor;
|
||||||
let matches = text.match(/(^|[^_])_([^_].+?)_$/);
|
let matches = text.match(/(^|\s)_([^\s_][^_]+?[^\s])_/);
|
||||||
if (matches) {
|
if (matches) {
|
||||||
let match = matches[0][0] === '_' ? matches[0] : matches[0].substr(1);
|
let match = matches[0][0] === '_' ? matches[0] : matches[0].substr(1);
|
||||||
range = range.extend(-(match.length));
|
range = range.extend(-(match.length));
|
||||||
@ -152,12 +161,48 @@ export default function (editor) {
|
|||||||
let position = postEditor.deleteRange(range);
|
let position = postEditor.deleteRange(range);
|
||||||
let em = postEditor.builder.createMarkup('em');
|
let em = postEditor.builder.createMarkup('em');
|
||||||
let nextPosition = postEditor.insertTextWithMarkup(position, matches[2], [em]);
|
let nextPosition = postEditor.insertTextWithMarkup(position, matches[2], [em]);
|
||||||
postEditor.insertTextWithMarkup(nextPosition, ' ', []);
|
if (!hasTextAfter) {
|
||||||
|
postEditor.insertTextWithMarkup(nextPosition, ' ', []);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function matchLink(editor, text) {
|
function matchStrikethrough(editor, text, hasTextAfter = false) {
|
||||||
|
let {range} = editor;
|
||||||
|
let matches = text.match(/(^|\s)~([^\s~][^~]+?[^\s])~/);
|
||||||
|
if (matches) {
|
||||||
|
let match = matches[0][0] === '~' ? matches[0] : matches[0].substr(1);
|
||||||
|
range = range.extend(-(match.length));
|
||||||
|
editor.run((postEditor) => {
|
||||||
|
let position = postEditor.deleteRange(range);
|
||||||
|
let s = postEditor.builder.createMarkup('s');
|
||||||
|
let nextPosition = postEditor.insertTextWithMarkup(position, matches[2], [s]);
|
||||||
|
if (!hasTextAfter) {
|
||||||
|
postEditor.insertTextWithMarkup(nextPosition, ' ', []); // insert the un-marked-up space
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function matchCode(editor, text, hasTextAfter = false) {
|
||||||
|
let {range} = editor;
|
||||||
|
let matches = text.match(/(^|\s)`([^\s`][^`]+?[^\s])`/);
|
||||||
|
if (matches) {
|
||||||
|
let match = matches[0][0] === '`' ? matches[0] : matches[0].substr(1);
|
||||||
|
range = range.extend(-(match.length));
|
||||||
|
editor.run((postEditor) => {
|
||||||
|
let position = postEditor.deleteRange(range);
|
||||||
|
let code = postEditor.builder.createMarkup('code');
|
||||||
|
let nextPosition = postEditor.insertTextWithMarkup(position, matches[2], [code]);
|
||||||
|
if (!hasTextAfter) {
|
||||||
|
postEditor.insertTextWithMarkup(nextPosition, ' ', []); // insert the un-marked-up space
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function matchLink(editor, text, hasTextAfter = false) {
|
||||||
let {range} = editor;
|
let {range} = editor;
|
||||||
let matches = text.match(/(^|[^!])\[(.*?)\]\((.*?)\)$/);
|
let matches = text.match(/(^|[^!])\[(.*?)\]\((.*?)\)$/);
|
||||||
if (matches) {
|
if (matches) {
|
||||||
@ -169,12 +214,14 @@ export default function (editor) {
|
|||||||
let position = postEditor.deleteRange(range);
|
let position = postEditor.deleteRange(range);
|
||||||
let a = postEditor.builder.createMarkup('a', {href: url});
|
let a = postEditor.builder.createMarkup('a', {href: url});
|
||||||
let nextPosition = postEditor.insertTextWithMarkup(position, text, [a]);
|
let nextPosition = postEditor.insertTextWithMarkup(position, text, [a]);
|
||||||
postEditor.insertTextWithMarkup(nextPosition, ' ', []); // insert the un-marked-up space
|
if (!hasTextAfter) {
|
||||||
|
postEditor.insertTextWithMarkup(nextPosition, ' ', []); // insert the un-marked-up space
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function matchImage(editor, text) {
|
function matchImage(editor, text, hasTextAfter = false) {
|
||||||
let matches = text.match(/^!\[(.*?)\]\((.*?)\)$/);
|
let matches = text.match(/^!\[(.*?)\]\((.*?)\)$/);
|
||||||
if (matches) {
|
if (matches) {
|
||||||
let {range: {head, head: {section}}} = editor;
|
let {range: {head, head: {section}}} = editor;
|
||||||
@ -208,32 +255,4 @@ export default function (editor) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function matchStrikethrough(editor, text) {
|
|
||||||
let {range} = editor;
|
|
||||||
let matches = text.match(/~(.+?)~$/);
|
|
||||||
if (matches) {
|
|
||||||
range = range.extend(-(matches[0].length));
|
|
||||||
editor.run((postEditor) => {
|
|
||||||
let position = postEditor.deleteRange(range);
|
|
||||||
let s = postEditor.builder.createMarkup('s');
|
|
||||||
let nextPosition = postEditor.insertTextWithMarkup(position, matches[1], [s]);
|
|
||||||
postEditor.insertTextWithMarkup(nextPosition, ' ', []); // insert the un-marked-up space
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function matchCode(editor, text) {
|
|
||||||
let {range} = editor;
|
|
||||||
let matches = text.match(/`(.+?)`/);
|
|
||||||
if (matches) {
|
|
||||||
range = range.extend(-(matches[0].length));
|
|
||||||
editor.run((postEditor) => {
|
|
||||||
let position = postEditor.deleteRange(range);
|
|
||||||
let code = postEditor.builder.createMarkup('code');
|
|
||||||
let nextPosition = postEditor.insertTextWithMarkup(position, matches[1], [code]);
|
|
||||||
postEditor.insertTextWithMarkup(nextPosition, ' ', []); // insert the un-marked-up space
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user