mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-11-28 22:43:30 +03:00
2f8de51d67
closes #4368, fixes #1240 (spellcheck), fixes #4974 & fixes #4983 (caret positioning bugs) - Drop CodeMirror in favour of a plain text area - Use rangyinputs to handle selections cross-browser - Create an API for interacting with the textarea - Replace marker manager with a much simpler image manager - Reimplement shortcuts, including some bug fixes
176 lines
5.1 KiB
JavaScript
176 lines
5.1 KiB
JavaScript
/* global moment, Showdown */
|
|
import Ember from 'ember';
|
|
import titleize from 'ghost/utils/titleize';
|
|
|
|
var simpleShortcutSyntax,
|
|
shortcuts,
|
|
EditorShortcuts;
|
|
|
|
// Used for simple, noncomputational replace-and-go! shortcuts.
|
|
// See default case in shortcut function below.
|
|
simpleShortcutSyntax = {
|
|
bold: {
|
|
regex: '**|**',
|
|
cursor: '|'
|
|
},
|
|
italic: {
|
|
regex: '*|*',
|
|
cursor: '|'
|
|
|
|
},
|
|
strike: {
|
|
regex: '~~|~~',
|
|
cursor: '|'
|
|
},
|
|
code: {
|
|
regex: '`|`',
|
|
cursor: '|'
|
|
},
|
|
blockquote: {
|
|
regex: '> |',
|
|
cursor: '|',
|
|
newline: true
|
|
},
|
|
list: {
|
|
regex: '* |',
|
|
cursor: '|',
|
|
newline: true
|
|
},
|
|
link: {
|
|
regex: '[|](http://)',
|
|
cursor: 'http://'
|
|
},
|
|
image: {
|
|
regex: '![|](http://)',
|
|
cursor: 'http://',
|
|
newline: true
|
|
}
|
|
};
|
|
|
|
shortcuts = {
|
|
simple: function (type, replacement, selection, line) {
|
|
var shortcut,
|
|
startIndex = 0;
|
|
|
|
if (simpleShortcutSyntax.hasOwnProperty(type)) {
|
|
shortcut = simpleShortcutSyntax[type];
|
|
// insert the markdown
|
|
replacement.text = shortcut.regex.replace('|', selection.text);
|
|
|
|
// add a newline if needed
|
|
if (shortcut.newline && line.text !== '') {
|
|
startIndex = 1;
|
|
replacement.text = '\n' + replacement.text;
|
|
}
|
|
|
|
// handle cursor position
|
|
if (selection.text === '' && shortcut.cursor === '|') {
|
|
// the cursor should go where | was
|
|
replacement.position = startIndex + replacement.start + shortcut.regex.indexOf(shortcut.cursor);
|
|
} else if (shortcut.cursor !== '|') {
|
|
// the cursor should select the string which matches shortcut.cursor
|
|
replacement.position = {
|
|
start: replacement.start + replacement.text.indexOf(shortcut.cursor)
|
|
};
|
|
replacement.position.end = replacement.position.start + shortcut.cursor.length;
|
|
}
|
|
}
|
|
|
|
return replacement;
|
|
},
|
|
cycleHeaderLevel: function (replacement, line) {
|
|
// jscs:disable
|
|
var match = line.text.match(/^#+/),
|
|
// jscs:enable
|
|
currentHeaderLevel,
|
|
hashPrefix;
|
|
|
|
if (!match) {
|
|
currentHeaderLevel = 1;
|
|
} else {
|
|
currentHeaderLevel = match[0].length;
|
|
}
|
|
|
|
if (currentHeaderLevel > 2) {
|
|
currentHeaderLevel = 1;
|
|
}
|
|
|
|
hashPrefix = new Array(currentHeaderLevel + 2).join('#');
|
|
|
|
// jscs:disable
|
|
replacement.text = hashPrefix + ' ' + line.text.replace(/^#* /, '');
|
|
// jscs:enable
|
|
|
|
replacement.start = line.start;
|
|
replacement.end = line.end;
|
|
|
|
return replacement;
|
|
},
|
|
copyHTML: function (editor, selection) {
|
|
var converter = new Showdown.converter(),
|
|
generatedHTML;
|
|
|
|
if (selection.text) {
|
|
generatedHTML = converter.makeHtml(selection.text);
|
|
} else {
|
|
generatedHTML = converter.makeHtml(editor.getValue());
|
|
}
|
|
|
|
// Talk to the editor
|
|
editor.sendAction('openModal', 'copy-html', {generatedHTML: generatedHTML});
|
|
},
|
|
currentDate: function (replacement) {
|
|
replacement.text = moment(new Date()).format('D MMMM YYYY');
|
|
return replacement;
|
|
},
|
|
uppercase: function (replacement, selection) {
|
|
replacement.text = selection.text.toLocaleUpperCase();
|
|
return replacement;
|
|
},
|
|
lowercase: function (replacement, selection) {
|
|
replacement.text = selection.text.toLocaleLowerCase();
|
|
return replacement;
|
|
},
|
|
titlecase: function (replacement, selection) {
|
|
replacement.text = titleize(selection.text);
|
|
return replacement;
|
|
}
|
|
};
|
|
|
|
EditorShortcuts = Ember.Mixin.create({
|
|
shortcut: function (type) {
|
|
var selection = this.getSelection(),
|
|
replacement = {
|
|
start: selection.start,
|
|
end: selection.end,
|
|
position: 'collapseToEnd'
|
|
};
|
|
|
|
switch (type) {
|
|
// This shortcut is special as it needs to send an action
|
|
case 'copyHTML':
|
|
shortcuts.copyHTML(this, selection);
|
|
break;
|
|
case 'cycleHeaderLevel':
|
|
replacement = shortcuts.cycleHeaderLevel(replacement, this.getLine());
|
|
break;
|
|
// These shortcuts all process the basic information
|
|
case 'currentDate':
|
|
case 'uppercase':
|
|
case 'lowercase':
|
|
case 'titlecase':
|
|
replacement = shortcuts[type](replacement, selection, this.getLineToCursor());
|
|
break;
|
|
// All the of basic formatting shortcuts work with a regex
|
|
default:
|
|
replacement = shortcuts.simple(type, replacement, selection, this.getLineToCursor());
|
|
}
|
|
|
|
if (replacement.text) {
|
|
this.replaceSelection(replacement.text, replacement.start, replacement.end, replacement.position);
|
|
}
|
|
}
|
|
});
|
|
|
|
export default EditorShortcuts;
|