Ver código fonte

impl PageEditorReadOnly.tsx

Shun Miyazawa 2 anos atrás
pai
commit
007321896e

+ 7 - 5
apps/app/src/components/Page/DisplaySwitcher.tsx

@@ -2,17 +2,15 @@ import React from 'react';
 
 import dynamic from 'next/dynamic';
 
-
 import { useHashChangedEffect } from '~/client/services/side-effects/hash-changed';
 import { usePageUpdatedEffect } from '~/client/services/side-effects/page-updated';
-import { useIsEditable } from '~/stores/context';
+import { useIsEditable, useIsOldRevisionPage } from '~/stores/context';
 import { EditorMode, useEditorMode } from '~/stores/ui';
 
 import { LazyRenderer } from '../Common/LazyRenderer';
 
-
 const PageEditor = dynamic(() => import('../PageEditor'), { ssr: false });
-
+const PageEditorReadOnly = dynamic(() => import('../PageEditor/PageEditorReadOnly').then(mod => mod.PageEditorReadOnly), { ssr: false });
 
 type Props = {
   pageView: JSX.Element,
@@ -23,6 +21,7 @@ export const DisplaySwitcher = (props: Props): JSX.Element => {
 
   const { data: editorMode = EditorMode.View } = useEditorMode();
   const { data: isEditable } = useIsEditable();
+  const { data: isOldRevisionPage } = useIsOldRevisionPage();
 
   usePageUpdatedEffect();
   useHashChangedEffect();
@@ -34,7 +33,10 @@ export const DisplaySwitcher = (props: Props): JSX.Element => {
       { isViewMode && pageView }
 
       <LazyRenderer shouldRender={isEditable === true && editorMode === EditorMode.Editor}>
-        <PageEditor />
+        { isOldRevisionPage
+          ? <PageEditorReadOnly />
+          : <PageEditor />
+        }
       </LazyRenderer>
     </>
   );

+ 16 - 26
apps/app/src/components/PageEditor/PageEditor.tsx

@@ -10,7 +10,7 @@ import nodePath from 'path';
 import { type IPageHasId, Origin } from '@growi/core';
 import { pathUtils } from '@growi/core/dist/utils';
 import {
-  CodeMirrorEditorMain, CodeMirrorEditorMainReadOnly, GlobalCodeMirrorEditorKey,
+  CodeMirrorEditorMain, GlobalCodeMirrorEditorKey,
   useCodeMirrorEditorIsolated, useResolvedThemeForEditor,
 } from '@growi/editor';
 import { useRect } from '@growi/ui/dist/utils';
@@ -27,7 +27,7 @@ import {
   useDefaultIndentSize, useCurrentUser,
   useCurrentPathname, useIsEnabledAttachTitleHeader,
   useIsEditable, useIsIndentSizeForced,
-  useAcceptedUploadFileType, useIsOldRevisionPage,
+  useAcceptedUploadFileType,
 } from '~/stores/context';
 import {
   useEditorSettings,
@@ -109,7 +109,6 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
   const { data: acceptedUploadFileType } = useAcceptedUploadFileType();
   const { data: editorSettings } = useEditorSettings();
   const { data: user } = useCurrentUser();
-  const { data: isOldRevisionPage } = useIsOldRevisionPage();
   const { onEditorsUpdated } = useEditingUsers();
   const onConflict = useConflictResolver();
 
@@ -402,28 +401,19 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
 
       <div className={`flex-expand-horiz ${props.visibility ? '' : 'd-none'}`}>
         <div className="page-editor-editor-container flex-expand-vert border-end">
-          { !isOldRevisionPage
-            ? (
-              <CodeMirrorEditorMain
-                onChange={markdownChangedHandler}
-                onSave={saveWithShortcut}
-                onUpload={uploadHandler}
-                acceptedUploadFileType={acceptedUploadFileType}
-                onScroll={scrollEditorHandlerThrottle}
-                indentSize={currentIndentSize ?? defaultIndentSize}
-                user={user ?? undefined}
-                pageId={pageId ?? undefined}
-                initialValue={initialValue}
-                editorSettings={editorSettings}
-                onEditorsUpdated={onEditorsUpdated}
-              />
-            )
-            : (
-              <CodeMirrorEditorMainReadOnly
-                body={initialValue}
-              />
-            )
-          }
+          <CodeMirrorEditorMain
+            onChange={markdownChangedHandler}
+            onSave={saveWithShortcut}
+            onUpload={uploadHandler}
+            acceptedUploadFileType={acceptedUploadFileType}
+            onScroll={scrollEditorHandlerThrottle}
+            indentSize={currentIndentSize ?? defaultIndentSize}
+            user={user ?? undefined}
+            pageId={pageId ?? undefined}
+            initialValue={initialValue}
+            editorSettings={editorSettings}
+            onEditorsUpdated={onEditorsUpdated}
+          />
         </div>
         <div
           ref={previewRef}
@@ -440,7 +430,7 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
         </div>
       </div>
 
-      { !isOldRevisionPage && (<EditorNavbarBottom />) }
+      <EditorNavbarBottom />
 
     </div>
   );

+ 108 - 0
apps/app/src/components/PageEditor/PageEditorReadOnly.tsx

@@ -0,0 +1,108 @@
+import react, {
+  useCallback, useMemo, useRef, type CSSProperties,
+} from 'react';
+
+import { CodeMirrorEditorMainReadOnly, GlobalCodeMirrorEditorKey, useCodeMirrorEditorIsolated } from '@growi/editor';
+import { useRect } from '@growi/ui/dist/utils';
+import { throttle } from 'throttle-debounce';
+
+import { useShouldExpandContent } from '~/client/services/layout';
+import { useIsOldRevisionPage } from '~/stores/context';
+import { useEditingMarkdown } from '~/stores/editor';
+import { useSWRxCurrentPage } from '~/stores/page';
+import { usePreviewOptions } from '~/stores/renderer';
+
+import { EditorNavbar } from './EditorNavbar';
+import Preview from './Preview';
+import { scrollEditor, scrollPreview } from './ScrollSyncHelper';
+
+let isOriginOfScrollSyncEditor = false;
+let isOriginOfScrollSyncPreview = false;
+
+export const PageEditorReadOnly = react.memo((): JSX.Element => {
+  const previewRef = useRef<HTMLDivElement>(null);
+  const [previewRect] = useRect(previewRef);
+
+  const { data: currentPage } = useSWRxCurrentPage();
+  const { data: rendererOptions } = usePreviewOptions();
+  const { data: editingMarkdown } = useEditingMarkdown();
+  const { data: isOldRevisionPage } = useIsOldRevisionPage();
+  const { data: codeMirrorEditor } = useCodeMirrorEditorIsolated(GlobalCodeMirrorEditorKey.MAIN);
+
+  const shouldExpandContent = useShouldExpandContent(currentPage);
+
+  const pastEndStyle: CSSProperties | undefined = useMemo(() => {
+    if (previewRect == null) {
+      return undefined;
+    }
+
+    const previewRectHeight = previewRect.height;
+
+    // containerHeight - 1.5 line height
+    return { paddingBottom: `calc(${previewRectHeight}px - 2em)` };
+  }, [previewRect]);
+
+  const scrollEditorHandler = useCallback(() => {
+    if (codeMirrorEditor?.view?.scrollDOM == null || previewRef.current == null) {
+      return;
+    }
+
+    if (isOriginOfScrollSyncPreview) {
+      isOriginOfScrollSyncPreview = false;
+      return;
+    }
+
+    isOriginOfScrollSyncEditor = true;
+    scrollEditor(codeMirrorEditor.view.scrollDOM, previewRef.current);
+  }, [codeMirrorEditor]);
+
+  const scrollEditorHandlerThrottle = useMemo(() => throttle(25, scrollEditorHandler), [scrollEditorHandler]);
+
+  const scrollPreviewHandler = useCallback(() => {
+    if (codeMirrorEditor?.view?.scrollDOM == null || previewRef.current == null) {
+      return;
+    }
+
+    if (isOriginOfScrollSyncEditor) {
+      isOriginOfScrollSyncEditor = false;
+      return;
+    }
+
+    isOriginOfScrollSyncPreview = true;
+    scrollPreview(codeMirrorEditor.view.scrollDOM, previewRef.current);
+  }, [codeMirrorEditor]);
+
+  const scrollPreviewHandlerThrottle = useMemo(() => throttle(25, scrollPreviewHandler), [scrollPreviewHandler]);
+
+  if (rendererOptions == null || !isOldRevisionPage) {
+    return <></>;
+  }
+
+  return (
+    <div data-testid="page-editor" id="page-editor" className="flex-expand-vert">
+      <EditorNavbar />
+
+      <div className="flex-expand-horiz">
+        <div className="page-editor-editor-container flex-expand-vert border-end">
+          <CodeMirrorEditorMainReadOnly
+            body={editingMarkdown}
+            onScroll={scrollEditorHandlerThrottle}
+          />
+        </div>
+        <div
+          ref={previewRef}
+          onScroll={scrollPreviewHandlerThrottle}
+          className="page-editor-preview-container flex-expand-vert overflow-y-auto d-none d-lg-flex"
+        >
+          <Preview
+            rendererOptions={rendererOptions}
+            markdown={editingMarkdown}
+            pagePath={currentPage?.path}
+            expandContentWidth={shouldExpandContent}
+            style={pastEndStyle}
+          />
+        </div>
+      </div>
+    </div>
+  );
+});