Ghost/ghost/admin/lib/koenig-editor/addon/components/koenig-caption-input.js
Kevin Ansfield c33a0c23bc Koenig - Prevent "Enter" being inserted into captions
refs https://github.com/TryGhost/Ghost/issues/9724
- mobiledoc-kit's `key.isPrintable()` returns true for <kbd>Enter</kbd> but in this instance we don't want to capture newlines as printable chars
- swapped insertion of `event.key` for `key.toString()` for better handling of named keys that output characters (eg. when `event.key` === `Enter` which prints `\n`)
2018-08-11 18:26:30 +01:00

145 lines
4.0 KiB
JavaScript

import Component from '@ember/component';
import Key from 'mobiledoc-kit/utils/key';
import layout from '../templates/components/koenig-caption-input';
import {computed} from '@ember/object';
import {kgStyle} from 'ember-cli-ghost-spirit/helpers/kg-style';
import {run} from '@ember/runloop';
export default Component.extend({
tagName: 'figcaption',
classNameBindings: ['figCaptionClass'],
layout,
caption: '',
captureInput: false,
placeholder: '',
_keypressHandler: null,
_keydownHandler: null,
update() {},
addParagraphAfterCard() {},
moveCursorToNextSection() {},
moveCursorToPrevSection() {},
figCaptionClass: computed(function () {
return `${kgStyle(['figcaption'])} w-100 relative`;
}),
didReceiveAttrs() {
this._super(...arguments);
if (this.captureInput && !this._keypressHandler) {
this._attachHandlers();
}
if (!this.captureInput && this._keypressHandler) {
this._detachHandlers();
}
},
willDestroyElement() {
this._super(...arguments);
this._detachHandlers();
},
actions: {
registerEditor(editor) {
let commands = {
ENTER: run.bind(this, this._enter),
ESC: run.bind(this, this._escape),
UP: run.bind(this, this._upOrLeft),
LEFT: run.bind(this, this._upOrLeft),
DOWN: run.bind(this, this._rightOrDown),
RIGHT: run.bind(this, this._rightOrDown)
};
Object.keys(commands).forEach((str) => {
editor.registerKeyCommand({
str,
run() {
return commands[str](editor, str);
}
});
});
this.editor = editor;
},
handleEnter() {
this.addParagraphAfterCard();
}
},
_attachHandlers() {
if (!this._keypressHandler) {
this._keypressHandler = run.bind(this, this._handleKeypress);
window.addEventListener('keypress', this._keypressHandler);
}
},
_detachHandlers() {
window.removeEventListener('keypress', this._keypressHandler);
this._keypressHandler = null;
this._keydownHandler = null;
},
// only fires if the card is selected, moves focus to the caption input so
// that it's possible to start typing without explicitly focusing the input
_handleKeypress(event) {
let key = new Key(event);
let {editor} = this;
if (event.target.matches('[data-kg="editor"]') && editor && !editor._hasFocus() && key.isPrintableKey() && !key.isEnter()) {
editor.focus();
editor.run((postEditor) => {
postEditor.insertText(editor.post.tailPosition(), key.toString());
});
event.preventDefault();
}
},
/* key commands ----------------------------------------------------------*/
_enter() {
this.send('handleEnter');
},
_escape(editor) {
editor.blur();
},
_upOrLeft(editor, key) {
let {isCollapsed, head} = editor.range;
if (isCollapsed && head.isEqual(head.section.headPosition())) {
return this.moveCursorToPrevSection();
}
// we're simulating a text input so up/down move the cursor to the
// beginning/end of the input
if (isCollapsed && key === 'UP') {
return editor.selectRange(head.section.headPosition().toRange());
}
return false;
},
_rightOrDown(editor, key) {
let {isCollapsed, tail} = editor.range;
if (isCollapsed && tail.isEqual(tail.section.tailPosition())) {
return this.moveCursorToNextSection();
}
// we're simulating a text input so up/down move the cursor to the
// beginning/end of the input
if (isCollapsed && key === 'DOWN') {
return editor.selectRange(tail.section.tailPosition().toRange());
}
return false;
}
});