Fixed cursor movement across title/subtitle/editor
closes https://linear.app/tryghost/issue/MOM-175 - matches cursor behaviour on Up/Down/Left/Right/Tab/Enter to our previous behaviour when we only had the title and editor
This commit is contained in:
parent
833ac83921
commit
76a41d4e92
@ -67,6 +67,7 @@
|
||||
@value={{readonly this.excerpt}}
|
||||
@input={{this.onExcerptInput}}
|
||||
@keyDown={{this.onExcerptKeydown}}
|
||||
@didCreateTextarea={{this.registerSubtitleElement}}
|
||||
data-test-textarea="subtitle"
|
||||
/>
|
||||
{{#if @excerptErrorMessage}}
|
||||
@ -84,7 +85,7 @@
|
||||
@cardConfig={{@cardOptions}}
|
||||
@onChange={{@onBodyChange}}
|
||||
@registerAPI={{this.registerEditorAPI}}
|
||||
@cursorDidExitAtTop={{this.focusTitle}}
|
||||
@cursorDidExitAtTop={{if this.feature.editorSubtitle this.focusSubtitle this.focusTitle}}
|
||||
@updateWordCount={{@updateWordCount}}
|
||||
@updatePostTkCount={{@updatePostTkCount}}
|
||||
/>
|
||||
|
@ -10,6 +10,7 @@ export default class GhKoenigEditorReactComponent extends Component {
|
||||
|
||||
containerElement = null;
|
||||
titleElement = null;
|
||||
subtitleElement = null;
|
||||
mousedownY = 0;
|
||||
uploadUrl = `${ghostPaths().apiRoot}/images/upload/`;
|
||||
|
||||
@ -111,21 +112,34 @@ export default class GhKoenigEditorReactComponent extends Component {
|
||||
this.titleElement.focus();
|
||||
}
|
||||
|
||||
// move cursor to the editor on
|
||||
// - Tab
|
||||
// - Arrow Down/Right when input is empty or caret at end of input
|
||||
// - Enter, creating an empty paragraph when editor is not empty
|
||||
@action
|
||||
onTitleKeydown(event) {
|
||||
if (this.feature.get('editorSubtitle')) {
|
||||
if (event.key === 'Enter') {
|
||||
// move cursor to the subtitle on
|
||||
// - Tab (handled by browser)
|
||||
// - Arrow Down/Right when input is empty or caret at end of input
|
||||
// - Enter
|
||||
const {key} = event;
|
||||
const {value, selectionStart} = event.target;
|
||||
|
||||
if (key === 'Enter') {
|
||||
event.preventDefault();
|
||||
const subheadElement = document.querySelector('.gh-editor-subtitle');
|
||||
if (subheadElement) {
|
||||
subheadElement.focus();
|
||||
this.subtitleElement?.focus();
|
||||
}
|
||||
|
||||
if ((key === 'ArrowDown' || key === 'ArrowRight') && !event.shiftKey) {
|
||||
const couldLeaveTitle = !value || selectionStart === value.length;
|
||||
|
||||
if (couldLeaveTitle) {
|
||||
event.preventDefault();
|
||||
this.subtitleElement?.focus();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// move cursor to the editor on
|
||||
// - Tab
|
||||
// - Arrow Down/Right when input is empty or caret at end of input
|
||||
// - Enter, creating an empty paragraph when editor is not empty
|
||||
const {editorAPI} = this;
|
||||
|
||||
if (!editorAPI || event.originalEvent.isComposing) {
|
||||
@ -152,6 +166,21 @@ export default class GhKoenigEditorReactComponent extends Component {
|
||||
|
||||
// Subhead ("excerpt") Actions -------------------------------------------
|
||||
|
||||
@action
|
||||
registerSubtitleElement(element) {
|
||||
this.subtitleElement = element;
|
||||
}
|
||||
|
||||
@action
|
||||
focusSubtitle() {
|
||||
this.subtitleElement?.focus();
|
||||
|
||||
// timeout ensures this occurs after the keyboard events
|
||||
setTimeout(() => {
|
||||
this.subtitleElement?.setSelectionRange(-1, -1);
|
||||
}, 0);
|
||||
}
|
||||
|
||||
@action
|
||||
onExcerptInput(event) {
|
||||
this.args.setExcerpt?.(event.target.value);
|
||||
@ -159,9 +188,37 @@ export default class GhKoenigEditorReactComponent extends Component {
|
||||
|
||||
@action
|
||||
onExcerptKeydown(event) {
|
||||
if (event.key === 'Enter') {
|
||||
// move cursor to the title on
|
||||
// - Shift+Tab (handled by the browser)
|
||||
// - Arrow Up/Left when input is empty or caret at start of input
|
||||
// move cursor to the editor on
|
||||
// - Tab
|
||||
// - Arrow Down/Right when input is empty or caret at end of input
|
||||
// - Enter, creating an empty paragraph when editor is not empty
|
||||
const {key} = event;
|
||||
const {value, selectionStart} = event.target;
|
||||
|
||||
if ((key === 'ArrowUp' || key === 'ArrowLeft') && !event.shiftKey) {
|
||||
const couldLeaveTitle = !value || selectionStart === 0;
|
||||
|
||||
if (couldLeaveTitle) {
|
||||
event.preventDefault();
|
||||
this.focusTitle();
|
||||
}
|
||||
}
|
||||
|
||||
const {editorAPI} = this;
|
||||
const couldLeaveTitle = !value || selectionStart === value.length;
|
||||
const arrowLeavingTitle = (key === 'ArrowRight' || key === 'ArrowDown') && couldLeaveTitle;
|
||||
|
||||
if (key === 'Enter' || (key === 'Tab' && !event.shiftKey) || arrowLeavingTitle) {
|
||||
event.preventDefault();
|
||||
this.editorAPI.focusEditor({position: 'top'});
|
||||
|
||||
if (key === 'Enter' && !editorAPI.editorIsEmpty()) {
|
||||
editorAPI.insertParagraphAtTop({focus: true});
|
||||
} else {
|
||||
editorAPI.focusEditor({position: 'top'});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user