Skip to content
This repository has been archived by the owner on Nov 28, 2022. It is now read-only.

Commit

Permalink
Koenig - Fixed trailing-spaces when using markdown text expansions
Browse files Browse the repository at this point in the history
refs TryGhost/Ghost#9505
- previous attempts at toggling the markup state failed because mobiledoc-kit was automatically setting the activeMarkupState after we made the replacement
- by scheduling the toggle we change the active markup state after mobiledoc has done it's thing so you can continue typing without the markdown markup being applied and without needing to insert an unexpected space
  • Loading branch information
kevinansfield committed Apr 3, 2018
1 parent b96c6b9 commit 9aef06c
Showing 1 changed file with 65 additions and 44 deletions.
109 changes: 65 additions & 44 deletions lib/koenig-editor/addon/options/text-expansions.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {
replaceWithHeaderSection,
replaceWithListSection
} from 'mobiledoc-kit/editor/text-input-handlers';
import {run} from '@ember/runloop';

// Text expansions watch text entry events and will look for matches, replacing
// the matches with additional markup, atoms, or cards
Expand All @@ -22,26 +23,25 @@ export default function (editor) {
match: /[*_)~`]$/,
run(editor, matches) {
let text = editor.range.head.section.textUntil(editor.range.head);
let hasTextAfter = editor.range.head.section.text.length > text.length;

switch (matches[0]) {
case '*':
matchStrongStar(editor, text, hasTextAfter);
matchEmStar(editor, text, hasTextAfter);
matchStrongStar(editor, text);
matchEmStar(editor, text);
break;
case '_':
matchStrongUnderscore(editor, text, hasTextAfter);
matchEmUnderscore(editor, text, hasTextAfter);
matchStrongUnderscore(editor, text);
matchEmUnderscore(editor, text);
break;
case ')':
matchLink(editor, text, hasTextAfter);
matchImage(editor, text, hasTextAfter);
matchLink(editor, text);
matchImage(editor, text);
break;
case '~':
matchStrikethrough(editor, text, hasTextAfter);
matchStrikethrough(editor, text);
break;
case '`':
matchCode(editor, text, hasTextAfter);
matchCode(editor, text);
break;
}
}
Expand Down Expand Up @@ -100,123 +100,144 @@ export default function (editor) {

/* inline markdown ------------------------------------------------------ */

function matchStrongStar(editor, text, hasTextAfter = false) {
function matchStrongStar(editor, text) {
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 bold = postEditor.builder.createMarkup('strong');
let nextPosition = postEditor.insertTextWithMarkup(position, matches[2], [bold]);
if (!hasTextAfter) {
postEditor.insertTextWithMarkup(nextPosition, ' ', []);
}
postEditor.insertTextWithMarkup(position, matches[2], [bold]);
});
}

// must be scheduled so that the toggle isn't reset automatically
run.schedule('actions', this, function () {
editor.toggleMarkup('strong');
});
}

function matchStrongUnderscore(editor, text, hasTextAfter = false) {
function matchStrongUnderscore(editor, text) {
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 bold = postEditor.builder.createMarkup('strong');
let nextPosition = postEditor.insertTextWithMarkup(position, matches[2], [bold]);
if (!hasTextAfter) {
postEditor.insertTextWithMarkup(nextPosition, ' ', []);
}
postEditor.insertTextWithMarkup(position, matches[2], [bold]);
});

// must be scheduled so that the toggle isn't reset automatically
run.schedule('actions', this, function () {
editor.toggleMarkup('strong');
});
}
}

function matchEmStar(editor, text, hasTextAfter = false) {
function matchEmStar(editor, text) {
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 em = postEditor.builder.createMarkup('em');
let nextPosition = postEditor.insertTextWithMarkup(position, matches[2], [em]);
if (!hasTextAfter) {
postEditor.insertTextWithMarkup(nextPosition, ' ', []);
}
postEditor.insertTextWithMarkup(position, matches[2], [em]);
});

// must be scheduled so that the toggle isn't reset automatically
run.schedule('actions', this, function () {
editor.toggleMarkup('em');
});
}
}

function matchEmUnderscore(editor, text, hasTextAfter = false) {
function matchEmUnderscore(editor, text) {
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 em = postEditor.builder.createMarkup('em');
let nextPosition = postEditor.insertTextWithMarkup(position, matches[2], [em]);
if (!hasTextAfter) {
postEditor.insertTextWithMarkup(nextPosition, ' ', []);
}
postEditor.insertTextWithMarkup(position, matches[2], [em]);
});

// must be scheduled so that the toggle isn't reset automatically
run.schedule('actions', this, function () {
editor.toggleMarkup('code');
});
}
}

function matchStrikethrough(editor, text, hasTextAfter = false) {
function matchStrikethrough(editor, text) {
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
}
postEditor.insertTextWithMarkup(position, matches[2], [s]);
});

// must be scheduled so that the toggle isn't reset automatically
run.schedule('actions', this, function () {
editor.toggleMarkup('s');
});
}
}

function matchCode(editor, text, hasTextAfter = false) {
function matchCode(editor, text) {
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
}
postEditor.insertTextWithMarkup(position, matches[2], [code]);
});

// must be scheduled so that the toggle isn't reset automatically
run.schedule('actions', this, function () {
editor.toggleMarkup('code');
});
}
}

function matchLink(editor, text, hasTextAfter = false) {
function matchLink(editor, text) {
let {range} = editor;
let matches = text.match(/(^|[^!])\[(.*?)\]\((.*?)\)$/);
if (matches) {
let url = matches[3];
let text = matches[2];
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 a = postEditor.builder.createMarkup('a', {href: url});
let nextPosition = postEditor.insertTextWithMarkup(position, text, [a]);
if (!hasTextAfter) {
postEditor.insertTextWithMarkup(nextPosition, ' ', []); // insert the un-marked-up space
}
postEditor.insertTextWithMarkup(position, text, [a]);
});

// must be scheduled so that the toggle isn't reset automatically
run.schedule('actions', this, function () {
editor.toggleMarkup('code');
});
}
}
Expand Down

0 comments on commit 9aef06c

Please sign in to comment.