mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-02-24 23:48:13 -05:00
Koenig - Parse pasted plain text as markdown
refs https://github.com/TryGhost/Ghost/issues/9623 - plain text that's pasted will be run through our markdown parser then mobiledoc-kit will perform it's usual rich-text paste handling on the resulting HTML - add a <kbd>Cmd/Ctrl+V+Shift</kbd> escape valve that will skip markdown parsing so mobiledoc-kit's default plain text parsing is invoked - will not work with IE or Edge <= 16 due to missing browser support for distinguishing plain text vs html pastes
This commit is contained in:
parent
54cb053fa5
commit
772675d294
1 changed files with 62 additions and 2 deletions
|
@ -6,9 +6,11 @@
|
||||||
import Component from '@ember/component';
|
import Component from '@ember/component';
|
||||||
import Editor from 'mobiledoc-kit/editor/editor';
|
import Editor from 'mobiledoc-kit/editor/editor';
|
||||||
import EmberObject, {computed} from '@ember/object';
|
import EmberObject, {computed} from '@ember/object';
|
||||||
|
import Key from 'mobiledoc-kit/utils/key';
|
||||||
import MobiledocRange from 'mobiledoc-kit/utils/cursor/range';
|
import MobiledocRange from 'mobiledoc-kit/utils/cursor/range';
|
||||||
import defaultAtoms from '../options/atoms';
|
import defaultAtoms from '../options/atoms';
|
||||||
import defaultCards from '../options/cards';
|
import defaultCards from '../options/cards';
|
||||||
|
import formatMarkdown from 'ghost-admin/utils/format-markdown';
|
||||||
import layout from '../templates/components/koenig-editor';
|
import layout from '../templates/components/koenig-editor';
|
||||||
import registerKeyCommands from '../options/key-commands';
|
import registerKeyCommands from '../options/key-commands';
|
||||||
import registerTextExpansions from '../options/text-expansions';
|
import registerTextExpansions from '../options/text-expansions';
|
||||||
|
@ -109,6 +111,7 @@ export default Component.extend({
|
||||||
_lastIsEditingDisabled: false,
|
_lastIsEditingDisabled: false,
|
||||||
_isRenderingEditor: false,
|
_isRenderingEditor: false,
|
||||||
_skipCursorChange: false,
|
_skipCursorChange: false,
|
||||||
|
_modifierKeys: null,
|
||||||
|
|
||||||
// closure actions
|
// closure actions
|
||||||
willCreateEditor() {},
|
willCreateEditor() {},
|
||||||
|
@ -156,6 +159,12 @@ export default Component.extend({
|
||||||
this.set('activeMarkupTagNames', {});
|
this.set('activeMarkupTagNames', {});
|
||||||
this.set('activeSectionTagNames', {});
|
this.set('activeSectionTagNames', {});
|
||||||
|
|
||||||
|
this._modifierKeys = {
|
||||||
|
shift: false,
|
||||||
|
alt: false,
|
||||||
|
ctrl: false
|
||||||
|
};
|
||||||
|
|
||||||
this._startedRunLoop = false;
|
this._startedRunLoop = false;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -605,12 +614,11 @@ export default Component.extend({
|
||||||
|
|
||||||
/* custom event handlers ------------------------------------------------ */
|
/* custom event handlers ------------------------------------------------ */
|
||||||
|
|
||||||
// if a URL is pasted and we have a selection, make that selection a link
|
|
||||||
handlePaste(event) {
|
handlePaste(event) {
|
||||||
let editor = this.editor;
|
let editor = this.editor;
|
||||||
let range = editor.range;
|
let range = editor.range;
|
||||||
|
|
||||||
// only attempt link if we have a text selection in a single section
|
// if a URL is pasted and we have a selection, make that selection a link
|
||||||
if (range && !range.isCollapsed && range.headSection === range.tailSection && range.headSection.isMarkerable) {
|
if (range && !range.isCollapsed && range.headSection === range.tailSection && range.headSection.isMarkerable) {
|
||||||
let {text} = getContentFromPasteEvent(event);
|
let {text} = getContentFromPasteEvent(event);
|
||||||
if (text && validator.isURL(text)) {
|
if (text && validator.isURL(text)) {
|
||||||
|
@ -622,8 +630,37 @@ export default Component.extend({
|
||||||
// prevent mobiledoc's default paste event handler firing
|
// prevent mobiledoc's default paste event handler firing
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopImmediatePropagation();
|
event.stopImmediatePropagation();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if plain text is pasted we run it through our markdown parser so that
|
||||||
|
// we get better output than mobiledoc's default text parsing and we can
|
||||||
|
// provide an easier MD->Mobiledoc conversion route
|
||||||
|
// NOTE: will not work in IE/Edge which only ever expose `html`
|
||||||
|
let {html, text} = getContentFromPasteEvent(event);
|
||||||
|
if (text && !html && !this._modifierKeys.shift) {
|
||||||
|
// prevent mobiledoc's default paste event handler firing
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopImmediatePropagation();
|
||||||
|
|
||||||
|
// we can't modify the paste event itself so we trigger a mock
|
||||||
|
// paste event with our own data
|
||||||
|
let pasteEvent = {
|
||||||
|
type: 'paste',
|
||||||
|
preventDefault() {},
|
||||||
|
target: editor.element,
|
||||||
|
clipboardData: {
|
||||||
|
getData(type) {
|
||||||
|
if (type === 'text/html') {
|
||||||
|
return formatMarkdown(text, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
editor.triggerEvent(editor.element, 'paste', pasteEvent);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/* Ember event handlers ------------------------------------------------- */
|
/* Ember event handlers ------------------------------------------------- */
|
||||||
|
@ -634,6 +671,19 @@ export default Component.extend({
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// we keep track of the modifier keys that are pressed so that in other event
|
||||||
|
// handlers we can adjust the behaviour. Necessary because the browser doesn't
|
||||||
|
// natively provide any info on non-key events about which keys are pressed
|
||||||
|
keyDown(event) {
|
||||||
|
let key = Key.fromEvent(event);
|
||||||
|
this._updateModifiersFromKey(key, {isDown: true});
|
||||||
|
},
|
||||||
|
|
||||||
|
keyUp(event) {
|
||||||
|
let key = Key.fromEvent(event);
|
||||||
|
this._updateModifiersFromKey(key, {isDown: false});
|
||||||
|
},
|
||||||
|
|
||||||
/* public methods ------------------------------------------------------- */
|
/* public methods ------------------------------------------------------- */
|
||||||
|
|
||||||
selectCard(card, isEditing = false) {
|
selectCard(card, isEditing = false) {
|
||||||
|
@ -767,6 +817,16 @@ export default Component.extend({
|
||||||
this.editor.element.style.caretColor = 'auto';
|
this.editor.element.style.caretColor = 'auto';
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_updateModifiersFromKey(key, {isDown}) {
|
||||||
|
if (key.isShiftKey()) {
|
||||||
|
this._modifierKeys.shift = isDown;
|
||||||
|
} else if (key.isAltKey()) {
|
||||||
|
this._modifierKeys.alt = isDown;
|
||||||
|
} else if (key.isCtrlKey()) {
|
||||||
|
this._modifierKeys.ctrl = isDown;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
// store a reference to the editor for the acceptance test helpers
|
// store a reference to the editor for the acceptance test helpers
|
||||||
_setExpandoProperty(editor) {
|
_setExpandoProperty(editor) {
|
||||||
let config = getOwner(this).resolveRegistration('config:environment');
|
let config = getOwner(this).resolveRegistration('config:environment');
|
||||||
|
|
Loading…
Add table
Reference in a new issue