|
|
@@ -5,7 +5,8 @@ import React, {
|
|
|
import EventEmitter from 'events';
|
|
|
import nodePath from 'path';
|
|
|
|
|
|
-
|
|
|
+import { Compartment } from '@codemirror/state';
|
|
|
+import { keymap } from '@codemirror/view';
|
|
|
import type { IPageHasId } from '@growi/core';
|
|
|
import { pathUtils } from '@growi/core/dist/utils';
|
|
|
import { CodeMirrorEditorContainer, useCodeMirrorEditorMain } from '@growi/editor';
|
|
|
@@ -116,7 +117,11 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
|
|
|
const { mutate: mutateRemoteRevisionLastUpdateUser } = useRemoteRevisionLastUpdateUser();
|
|
|
|
|
|
const { data: codemirrorEditor } = useCodeMirrorEditorMain(codeMirrorEditorContainerRef.current);
|
|
|
- const { initDoc, focus: focusToEditor, setCaretLine } = codemirrorEditor ?? {};
|
|
|
+ const {
|
|
|
+ appendExtension,
|
|
|
+ initDoc, getDoc,
|
|
|
+ focus: focusToEditor, setCaretLine,
|
|
|
+ } = codemirrorEditor ?? {};
|
|
|
|
|
|
const { data: rendererOptions } = usePreviewOptions();
|
|
|
const { mutate: mutateIsEnabledUnsavedWarning } = useIsEnabledUnsavedWarning();
|
|
|
@@ -221,10 +226,7 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
|
|
|
mutateWaitingSaveProcessing(true);
|
|
|
|
|
|
const { page } = await saveOrUpdate(
|
|
|
- // TODO: get contents from the custom hook
|
|
|
- // refs: https://redmine.weseek.co.jp/issues/128973
|
|
|
- // markdownToSave.current,
|
|
|
- '',
|
|
|
+ getDoc?.() ?? '',
|
|
|
{ pageId, path: currentPagePath || currentPathname, revisionId: currentRevisionId },
|
|
|
options,
|
|
|
);
|
|
|
@@ -250,16 +252,13 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
|
|
|
}
|
|
|
|
|
|
}, [
|
|
|
+ getDoc,
|
|
|
currentPathname, optionsToSave, grantData, isSlackEnabled, saveOrUpdate, pageId,
|
|
|
currentPagePath, currentRevisionId,
|
|
|
mutateWaitingSaveProcessing, mutateRemotePageId, mutateRemoteRevisionId, mutateRemoteRevisionLastUpdatedAt, mutateRemoteRevisionLastUpdateUser,
|
|
|
]);
|
|
|
|
|
|
const saveAndReturnToViewHandler = useCallback(async(opts: {slackChannels: string, overwriteScopesOfDescendants?: boolean}) => {
|
|
|
- if (editorMode !== EditorMode.Editor) {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
const page = await save(opts);
|
|
|
if (page == null) {
|
|
|
return;
|
|
|
@@ -272,13 +271,9 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
|
|
|
updateStateAfterSave?.();
|
|
|
}
|
|
|
mutateEditorMode(EditorMode.View);
|
|
|
- }, [editorMode, save, isNotFound, mutateEditorMode, router, updateStateAfterSave]);
|
|
|
+ }, [save, isNotFound, mutateEditorMode, router, updateStateAfterSave]);
|
|
|
|
|
|
const saveWithShortcut = useCallback(async() => {
|
|
|
- if (editorMode !== EditorMode.Editor) {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
const page = await save();
|
|
|
if (page == null) {
|
|
|
return;
|
|
|
@@ -293,7 +288,7 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
|
|
|
toastSuccess(t('toaster.save_succeeded'));
|
|
|
mutateEditorMode(EditorMode.Editor);
|
|
|
|
|
|
- }, [editorMode, isNotFound, mutateEditorMode, router, save, t, updateStateAfterSave]);
|
|
|
+ }, [isNotFound, mutateEditorMode, router, save, t, updateStateAfterSave]);
|
|
|
|
|
|
|
|
|
/**
|
|
|
@@ -301,12 +296,6 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
|
|
|
* @param {any} file
|
|
|
*/
|
|
|
const uploadHandler = useCallback(async(file) => {
|
|
|
- // TODO: implement
|
|
|
- // refs: https://redmine.weseek.co.jp/issues/126528
|
|
|
- // if (editorRef.current == null) {
|
|
|
- // return;
|
|
|
- // }
|
|
|
-
|
|
|
try {
|
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
|
let res: any = await apiGet('/attachments.limit', {
|
|
|
@@ -326,11 +315,9 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
|
|
|
if (pageId != null) {
|
|
|
formData.append('page_id', pageId);
|
|
|
}
|
|
|
- // TODO: get contents from the custom hook
|
|
|
- // refs: https://redmine.weseek.co.jp/issues/128973
|
|
|
- // if (pageId == null && markdownToSave.current != null) {
|
|
|
- // formData.append('page_body', markdownToSave.current);
|
|
|
- // }
|
|
|
+ if (pageId == null) {
|
|
|
+ formData.append('page_body', getDoc?.() ?? '');
|
|
|
+ }
|
|
|
|
|
|
res = await apiPostForm('/attachments.add', formData);
|
|
|
const attachment = res.attachment;
|
|
|
@@ -520,6 +507,25 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
|
|
|
};
|
|
|
}, [saveAndReturnToViewHandler]);
|
|
|
|
|
|
+ // set handler to save with shortcut key
|
|
|
+ useEffect(() => {
|
|
|
+ const compartment = new Compartment();
|
|
|
+ const extension = keymap.of([
|
|
|
+ {
|
|
|
+ key: 'Mod-s',
|
|
|
+ preventDefault: true,
|
|
|
+ run: () => {
|
|
|
+ saveWithShortcut();
|
|
|
+ return false;
|
|
|
+ },
|
|
|
+ },
|
|
|
+ ]);
|
|
|
+
|
|
|
+ const cleanupFunction = appendExtension?.(extension, compartment);
|
|
|
+
|
|
|
+ return cleanupFunction;
|
|
|
+ }, [appendExtension, saveWithShortcut]);
|
|
|
+
|
|
|
// set handler to focus
|
|
|
useLayoutEffect(() => {
|
|
|
if (editorMode === EditorMode.Editor) {
|