2022-08-23 13:45:50 +03:00
|
|
|
import Component from '@glimmer/component';
|
|
|
|
import ghostPaths from 'ghost-admin/utils/ghost-paths';
|
|
|
|
import {action} from '@ember/object';
|
|
|
|
import {inject as service} from '@ember/service';
|
|
|
|
import {tracked} from '@glimmer/tracking';
|
|
|
|
|
|
|
|
export default class GhKoenigEditorReactComponent extends Component {
|
|
|
|
@service settings;
|
|
|
|
|
|
|
|
containerElement = null;
|
|
|
|
titleElement = null;
|
|
|
|
mousedownY = 0;
|
|
|
|
uploadUrl = `${ghostPaths().apiRoot}/images/upload/`;
|
|
|
|
|
2022-12-01 01:04:02 +03:00
|
|
|
editorAPI = null;
|
|
|
|
|
2022-08-23 13:45:50 +03:00
|
|
|
@tracked titleIsHovered = false;
|
|
|
|
@tracked titleIsFocused = false;
|
|
|
|
|
|
|
|
get title() {
|
|
|
|
return this.args.title === '(Untitled)' ? '' : this.args.title;
|
|
|
|
}
|
|
|
|
|
|
|
|
get accentColor() {
|
2022-10-07 16:23:21 +03:00
|
|
|
const color = this.settings.accentColor;
|
2022-08-23 13:45:50 +03:00
|
|
|
if (color && color[0] === '#') {
|
|
|
|
return color.slice(1);
|
|
|
|
}
|
|
|
|
return color;
|
|
|
|
}
|
|
|
|
|
|
|
|
@action
|
|
|
|
registerElement(element) {
|
|
|
|
this.containerElement = element;
|
|
|
|
}
|
|
|
|
|
|
|
|
@action
|
|
|
|
trackMousedown(event) {
|
|
|
|
// triggered when a mousedown is registered on .gh-koenig-editor-pane
|
|
|
|
this.mousedownY = event.clientY;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Title actions -----------------------------------------------------------
|
|
|
|
|
|
|
|
@action
|
|
|
|
registerTitleElement(element) {
|
|
|
|
this.titleElement = element;
|
|
|
|
|
|
|
|
// this is needed because focus event handler won't be fired if input has focus when rendering
|
|
|
|
if (this.titleElement === document.activeElement) {
|
|
|
|
this.titleIsFocused = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@action
|
|
|
|
updateTitle(event) {
|
|
|
|
this.args.onTitleChange?.(event.target.value);
|
|
|
|
}
|
|
|
|
|
2022-11-10 16:43:15 +03:00
|
|
|
@action
|
|
|
|
cleanPastedTitle(event) {
|
|
|
|
const pastedText = (event.clipboardData || window.clipboardData).getData('text');
|
|
|
|
|
|
|
|
if (!pastedText) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
event.preventDefault();
|
|
|
|
|
|
|
|
const cleanValue = pastedText.replace(/(\n|\r)+/g, ' ').trim();
|
|
|
|
document.execCommand('insertText', false, cleanValue);
|
|
|
|
}
|
|
|
|
|
2022-08-23 13:45:50 +03:00
|
|
|
@action
|
|
|
|
focusTitle() {
|
|
|
|
this.titleElement.focus();
|
|
|
|
}
|
|
|
|
|
2022-12-01 01:04:02 +03:00
|
|
|
// 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) {
|
|
|
|
const {editorAPI} = this;
|
|
|
|
|
|
|
|
if (!editorAPI) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const {key} = event;
|
|
|
|
const {value, selectionStart} = event.target;
|
|
|
|
|
|
|
|
const couldLeaveTitle = !value || selectionStart === value.length;
|
|
|
|
const arrowLeavingTitle = ['ArrowDown', 'ArrowRight'].includes(key) && couldLeaveTitle;
|
|
|
|
|
|
|
|
if (key === 'Enter' || key === 'Tab' || arrowLeavingTitle) {
|
|
|
|
event.preventDefault();
|
|
|
|
|
|
|
|
if (key === 'Enter' && !editorAPI.editorIsEmpty()) {
|
|
|
|
editorAPI.insertParagraphAtTop({focus: true});
|
|
|
|
} else {
|
|
|
|
editorAPI.focusEditor({position: 'top'});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-08-23 13:45:50 +03:00
|
|
|
|
|
|
|
// Body actions ------------------------------------------------------------
|
|
|
|
|
2022-12-01 01:04:02 +03:00
|
|
|
@action
|
|
|
|
registerEditorAPI(API) {
|
|
|
|
this.editorAPI = API;
|
2023-04-20 13:43:22 +03:00
|
|
|
this.args.registerAPI(API);
|
2022-12-01 01:04:02 +03:00
|
|
|
}
|
|
|
|
|
2022-09-13 13:30:07 +03:00
|
|
|
// @action
|
|
|
|
// onEditorCreated(koenig) {
|
|
|
|
// this._setupEditor(koenig);
|
|
|
|
// this.args.onEditorCreated?.(koenig);
|
|
|
|
// }
|
|
|
|
|
2023-02-22 18:01:25 +03:00
|
|
|
@action
|
|
|
|
focusEditor(event) {
|
|
|
|
if (event.target.classList.contains('gh-koenig-editor-pane')) {
|
|
|
|
let editorCanvas = this.editorAPI.editorInstance.getRootElement();
|
|
|
|
let {bottom} = editorCanvas.getBoundingClientRect();
|
|
|
|
|
|
|
|
// if a mousedown and subsequent mouseup occurs below the editor
|
|
|
|
// canvas, focus the editor and put the cursor at the end of the
|
|
|
|
// document
|
|
|
|
if (this.mousedownY > bottom && event.clientY > bottom) {
|
|
|
|
this.editorAPI.focusEditor();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-09-13 13:30:07 +03:00
|
|
|
|
|
|
|
// _setupEditor(koenig) {
|
|
|
|
// let component = this;
|
|
|
|
|
|
|
|
// this.koenigEditor = koenig;
|
|
|
|
|
|
|
|
// // focus the title when pressing SHIFT+TAB
|
|
|
|
// this.koenigEditor.registerKeyCommand({
|
|
|
|
// str: 'SHIFT+TAB',
|
|
|
|
// run() {
|
|
|
|
// component.focusTitle();
|
|
|
|
// return true;
|
|
|
|
// }
|
|
|
|
// });
|
|
|
|
// }
|
|
|
|
|
|
|
|
// _addParaAtTop() {
|
|
|
|
// if (!this.koenigEditor) {
|
|
|
|
// return;
|
|
|
|
// }
|
|
|
|
|
|
|
|
// let editor = this.koenigEditor;
|
|
|
|
// let section = editor.post.toRange().head.section;
|
|
|
|
|
|
|
|
// // create a blank paragraph at the top of the editor unless it's already
|
|
|
|
// // a blank paragraph
|
|
|
|
// if (section.isListItem || !section.isBlank || section.text !== '') {
|
|
|
|
// editor.run((postEditor) => {
|
|
|
|
// let {builder} = postEditor;
|
|
|
|
// let newPara = builder.createMarkupSection('p');
|
|
|
|
// let sections = section.isListItem ? section.parent.parent.sections : section.parent.sections;
|
|
|
|
|
|
|
|
// postEditor.insertSectionBefore(sections, newPara, section);
|
|
|
|
// });
|
|
|
|
// }
|
|
|
|
// }
|
2022-08-23 13:45:50 +03:00
|
|
|
}
|