🐛 Fixed ` not triggering code text expansions on German keyboards (Win/macOS only) (#1042)
closes https://github.com/TryGhost/Ghost/issues/9825 - the <code>`</code> key on German keyboard layouts is a dead key and so does not trigger the typical keyboard events our editor relies on - added custom keyboard event listeners to watch for specific keyboard event sequences triggered by using the dead key + spacebar to insert a <code>`</code> - trigger text input handlers when we detect a <code>`</code> insertion - Linux unfortunately does not trigger events that can be used to track the sequence so this will not work there although it is easier to set up keyboard layouts without dead keys on Linux - moved modifier key tracking into global event handlers from ember event handlers - reduce confusion from duplicated event handling - allows modifier key handlers to fire when keys are pressed without the editor element having focus
This commit is contained in:
parent
7896f2ed90
commit
5ae15e2b04
|
@ -431,6 +431,11 @@ export default Component.extend({
|
|||
this._scrollContainer = document.querySelector(this.scrollContainerSelector);
|
||||
}
|
||||
|
||||
this._keydownHandler = run.bind(this, this.handleKeydown);
|
||||
window.addEventListener('keydown', this._keydownHandler);
|
||||
this._keyupHandler = run.bind(this, this.handleKeyup);
|
||||
window.addEventListener('keyup', this._keyupHandler);
|
||||
|
||||
this._dropTarget = document.querySelector(this.dropTargetSelector) || this.element;
|
||||
this._dragOverHandler = run.bind(this, this.handleDragOver);
|
||||
this._dragLeaveHandler = run.bind(this, this.handleDragLeave);
|
||||
|
@ -460,6 +465,9 @@ export default Component.extend({
|
|||
_dropTarget.removeEventListener('dragleave', this._dragLeaveHandler);
|
||||
_dropTarget.removeEventListener('drop', this._dropHandler);
|
||||
|
||||
window.removeEventListener('keydown', this._keydownHandler);
|
||||
window.removeEventListener('keyup', this._keyupHandler);
|
||||
|
||||
let editorElement = this.element.querySelector('[data-kg="editor"]');
|
||||
editorElement.removeEventListener('paste', this._pasteHandler);
|
||||
|
||||
|
@ -759,6 +767,42 @@ export default Component.extend({
|
|||
|
||||
/* custom event handlers ------------------------------------------------ */
|
||||
|
||||
// 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.
|
||||
//
|
||||
// German keyboard layouts use a dead key for the ` char so it doesn't
|
||||
// fire keypress events. We watch for the event triggered when pressing
|
||||
// spacebar to "finalise" the backtick input then call the text input
|
||||
// handlers manually instead.
|
||||
//
|
||||
// Does not work on Linux but it's easier to have keymaps without dead keys there
|
||||
handleKeydown(event) {
|
||||
let key = Key.fromEvent(event);
|
||||
this._updateModifiersFromKey(key, {isDown: true});
|
||||
|
||||
if (event.key === 'Dead' && event.keyCode === 192) {
|
||||
return this._isGraveInput = true;
|
||||
}
|
||||
|
||||
this._isGraveInput = false;
|
||||
|
||||
// Chrome/Safari can be matched immediately on keydown unlike Firefox
|
||||
if (event.key === '`' && event.code === 'Space') {
|
||||
this._triggerTextHandlers();
|
||||
}
|
||||
},
|
||||
|
||||
handleKeyup(event) {
|
||||
let key = Key.fromEvent(event);
|
||||
this._updateModifiersFromKey(key, {isDown: false});
|
||||
|
||||
if (this._isGraveInput && event.key === ' ') {
|
||||
this._isGraveInput = false;
|
||||
this._triggerTextHandlers();
|
||||
}
|
||||
},
|
||||
|
||||
handlePaste(event) {
|
||||
let {editor} = this;
|
||||
|
||||
|
@ -970,19 +1014,6 @@ export default Component.extend({
|
|||
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 ------------------------------------------------------- */
|
||||
|
||||
selectCard(card, isEditing = false) {
|
||||
|
@ -1234,6 +1265,26 @@ export default Component.extend({
|
|||
}
|
||||
},
|
||||
|
||||
_triggerTextHandlers() {
|
||||
let {editor} = this;
|
||||
|
||||
// don't trigger our text input handlers for pastes within cards or
|
||||
// outside of the editor canvas
|
||||
if (!editor.cursor.isAddressable(event.target)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// must be run after the normal events have finished so that the
|
||||
// backtick char exists in the editor
|
||||
run.next(this, function () {
|
||||
let matchedHandler = editor._eventManager._textInputHandler._findHandler();
|
||||
if (matchedHandler) {
|
||||
let [handler, matches] = matchedHandler;
|
||||
handler.run(editor, matches);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// store a reference to the editor for the acceptance test helpers
|
||||
_setExpandoProperty(editor) {
|
||||
let config = getOwner(this).resolveRegistration('config:environment');
|
||||
|
|
Loading…
Reference in New Issue