Просмотр исходного кода

Merge branch 'support/apply-nextjs-2' into imprv/102320-omit-container-from-PageEditorByHackmd

yuken 3 лет назад
Родитель
Сommit
d16f0571b2

+ 9 - 8
packages/app/src/components/Page/DisplaySwitcher.tsx

@@ -27,17 +27,17 @@ const WIKI_HEADER_LINK = 120;
 
 const { isTopPage } = pagePathUtils;
 
+const PageEditor = dynamic(() => import('../PageEditor'), { ssr: false });
+const PageEditorByHackmd = dynamic(() => import('../PageEditorByHackmd').then(mod => mod.PageEditorByHackmd), { ssr: false });
+const EditorNavbarBottom = dynamic(() => import('../PageEditor/EditorNavbarBottom'), { ssr: false });
+const HashChanged = dynamic(() => import('../EventListeneres/HashChanged'), { ssr: false });
+const ContentLinkButtons = dynamic(() => import('../ContentLinkButtons'), { ssr: false });
+const NotFoundPage = dynamic(() => import('../NotFoundPage'), { ssr: false });
+
 
 const DisplaySwitcher = (): JSX.Element => {
   const { t } = useTranslation();
 
-  const PageEditor = dynamic(() => import('../PageEditor'), { ssr: false });
-  const PageEditorByHackmd = dynamic(() => import('../PageEditorByHackmd').then(mod => mod.PageEditorByHackmd), { ssr: false });
-  const EditorNavbarBottom = dynamic(() => import('../PageEditor/EditorNavbarBottom'), { ssr: false });
-  const HashChanged = dynamic(() => import('../EventListeneres/HashChanged'), { ssr: false });
-  const ContentLinkButtons = dynamic(() => import('../ContentLinkButtons'), { ssr: false });
-  const NotFoundPage = dynamic(() => import('../NotFoundPage'), { ssr: false });
-
   // get element for smoothScroll
   // const getCommentListDom = useMemo(() => { return document.getElementById('page-comments-list') }, []);
 
@@ -141,6 +141,7 @@ const DisplaySwitcher = (): JSX.Element => {
       { isEditable && <HashChanged></HashChanged> }
     </>
   );
-};
+});
+DisplaySwitcher.displayName = 'DisplaySwitcher';
 
 export default DisplaySwitcher;

+ 6 - 5
packages/app/src/components/PageEditor.tsx

@@ -4,7 +4,7 @@ import React, {
 
 import EventEmitter from 'events';
 
-import { envUtils } from '@growi/core';
+import { envUtils, PageGrant } from '@growi/core';
 import detectIndent from 'detect-indent';
 import { throttle, debounce } from 'throttle-debounce';
 
@@ -80,7 +80,7 @@ let lastScrolledDateWithCursor: Date | null = null;
 let isOriginOfScrollSyncEditor = false;
 let isOriginOfScrollSyncPreview = false;
 
-const PageEditor = (props: Props): JSX.Element => {
+const PageEditor = React.memo((props: Props): JSX.Element => {
   // const {
   //   pageContainer, editorContainer,
   // } = props;
@@ -222,7 +222,7 @@ const PageEditor = (props: Props): JSX.Element => {
       editorRef.current.terminateUploadingState();
     }
   // }, [editorMode, mutateGrant, pageContainer]);
-  }, [editorMode, mutateGrant]);
+  }, [currentPagePath, mutateGrant, pageId]);
 
 
   const scrollPreviewByEditorLine = useCallback((line: number) => {
@@ -348,7 +348,7 @@ const PageEditor = (props: Props): JSX.Element => {
       return;
     }
 
-    const grant = grantData?.grant || 1;
+    const grant = grantData?.grant || PageGrant.GRANT_PUBLIC;
     const grantedGroup = grantData?.grantedGroup;
 
     if (isSlackEnabled == null || currentPathname == null) {
@@ -477,7 +477,8 @@ const PageEditor = (props: Props): JSX.Element => {
       /> */}
     </div>
   );
-};
+});
+PageEditor.displayName = 'PageEditor';
 
 /**
    * Wrapper component for using unstated

+ 4 - 3
packages/app/src/components/PageEditor/CodeMirrorEditor.jsx

@@ -116,6 +116,7 @@ class CodeMirrorEditor extends AbstractEditor {
       emojiSearchText: null,
     };
 
+    this.cm = React.createRef();
     this.gridEditModal = React.createRef();
     this.linkEditModal = React.createRef();
     this.handsontableModal = React.createRef();
@@ -227,7 +228,7 @@ class CodeMirrorEditor extends AbstractEditor {
   }
 
   getCodeMirror() {
-    return this.cm.editor;
+    return this.cm.current?.editor;
   }
 
   /**
@@ -279,7 +280,7 @@ class CodeMirrorEditor extends AbstractEditor {
     }
 
     const editor = this.getCodeMirror();
-    const linePosition = Math.max(0, line);
+    const linePosition = Math.max(0, line - 1);
 
     editor.setCursor({ line: linePosition }); // leave 'ch' field as null/undefined to indicate the end of line
 
@@ -991,7 +992,7 @@ class CodeMirrorEditor extends AbstractEditor {
       <div className={`grw-codemirror-editor ${styles['grw-codemirror-editor']}`}>
 
         <UncontrolledCodeMirror
-          ref={(c) => { this.cm = c }}
+          ref={this.cm}
           className={additionalClasses}
           placeholder="search"
           editorDidMount={(editor) => {

+ 10 - 15
packages/app/src/components/PageEditor/Editor.tsx

@@ -60,38 +60,33 @@ const Editor = React.forwardRef((props: EditorPropsType, ref): JSX.Element => {
   const cmEditorRef = useRef<CodeMirrorEditor>(null);
   const taEditorRef = useRef<TextAreaEditor>(null);
 
-  const editorSubstance = isMobile ? taEditorRef.current : cmEditorRef.current;
+  const editorSubstance = useCallback(() => {
+    return isMobile ? taEditorRef.current : cmEditorRef.current;
+  }, [isMobile]);
 
   const methods: Partial<IEditorMethods> = useMemo(() => {
     return {
       forceToFocus: () => {
-        if (editorSubstance == null) { return }
-        editorSubstance.forceToFocus();
+        editorSubstance()?.forceToFocus();
       },
       setValue: (newValue: string) => {
-        if (editorSubstance == null) { return }
-        editorSubstance.setValue(newValue);
+        editorSubstance()?.setValue(newValue);
       },
       setGfmMode: (bool: boolean) => {
-        if (editorSubstance == null) { return }
-        editorSubstance.setGfmMode(bool);
+        editorSubstance()?.setGfmMode(bool);
       },
       setCaretLine: (line: number) => {
-        if (editorSubstance == null) { return }
-        editorSubstance.setCaretLine(line);
+        editorSubstance()?.setCaretLine(line);
       },
       setScrollTopByLine: (line: number) => {
-        if (editorSubstance == null) { return }
-        editorSubstance.setScrollTopByLine(line);
+        editorSubstance()?.setScrollTopByLine(line);
       },
       insertText: (text: string) => {
-        if (editorSubstance == null) { return }
-        editorSubstance.insertText(text);
+        editorSubstance()?.insertText(text);
       },
       getNavbarItems: (): JSX.Element[] => {
-        if (editorSubstance == null) { return [] }
         // concat common items and items specific to CodeMirrorEditor or TextAreaEditor
-        const navbarItems = editorSubstance.getNavbarItems() ?? [];
+        const navbarItems = editorSubstance()?.getNavbarItems() ?? [];
         return navbarItems;
       },
     };

+ 3 - 4
packages/app/src/components/PageEditor/TextAreaEditor.jsx

@@ -2,15 +2,14 @@ import React from 'react';
 // import PropTypes from 'prop-types';
 
 import { Input } from 'reactstrap';
+
 import InterceptorManager from '~/services/interceptor-manager';
 import loggerFactory from '~/utils/logger';
 
 
 import AbstractEditor from './AbstractEditor';
-
-import pasteHelper from './PasteHelper';
 import mlu from './MarkdownListUtil';
-
+import pasteHelper from './PasteHelper';
 import PreventMarkdownListInterceptor from './PreventMarkdownListInterceptor';
 
 export default class TextAreaEditor extends AbstractEditor {
@@ -89,7 +88,7 @@ export default class TextAreaEditor extends AbstractEditor {
     // scroll to bottom
     this.textarea.scrollTop = this.textarea.scrollHeight;
 
-    const lines = this.textarea.value.split('\n').slice(0, line + 1);
+    const lines = this.textarea.value.split('\n').slice(0, line);
     /* eslint-disable no-param-reassign, no-return-assign */
     const pos = lines
       .map((lineStr) => { return lineStr.length + 1 }) // correct length+1 of each lines

+ 12 - 2
packages/app/src/components/ReactMarkdownComponents/Header.tsx

@@ -1,3 +1,5 @@
+import EventEmitter from 'events';
+
 import { Element } from 'react-markdown/lib/rehype-filter';
 
 import { NextLink } from './NextLink';
@@ -6,6 +8,14 @@ import { NextLink } from './NextLink';
 import styles from './Header.module.scss';
 
 
+declare const globalEmitter: EventEmitter;
+
+function setCaretLine(line?: number): void {
+  if (line != null) {
+    globalEmitter.emit('setCaretLine', line);
+  }
+}
+
 type EditLinkProps = {
   line?: number,
 }
@@ -18,7 +28,7 @@ const EditLink = (props: EditLinkProps): JSX.Element => {
 
   return (
     <span className="revision-head-edit-button">
-      <a href="#edit" aria-disabled={isDisabled} onClick={() => console.log(`TODO: Jump to the line '${props.line}'`)}>
+      <a href="#edit" aria-disabled={isDisabled} onClick={() => setCaretLine(props.line)}>
         <i className="icon-note"></i>
       </a>
     </span>
@@ -41,7 +51,7 @@ export const Header = (props: HeaderProps): JSX.Element => {
   const CustomTag = `h${level}` as keyof JSX.IntrinsicElements;
 
   return (
-    <CustomTag id={id} className={`revision-head ${styles['revision-head']} ${styles.hoge}`}>
+    <CustomTag id={id} className={`revision-head ${styles['revision-head']}`}>
       {children}
       <NextLink href={`#${id}`} className="revision-head-link">
         <span className="icon-link"></span>

+ 2 - 2
packages/app/src/components/SavePageControls.tsx

@@ -1,6 +1,6 @@
 import React, { useCallback } from 'react';
 
-import { pagePathUtils } from '@growi/core';
+import { pagePathUtils, PageGrant } from '@growi/core';
 import { useTranslation } from 'next-i18next';
 import {
   UncontrolledButtonDropdown, Button,
@@ -81,7 +81,7 @@ export const SavePageControls = (props: Props): JSX.Element | null => {
     return null;
   }
 
-  const grant = grantData?.grant || 1;
+  const grant = grantData?.grant || PageGrant.GRANT_PUBLIC;
   const grantedGroup = grantData?.grantedGroup;
 
   // const {  pageContainer } = props;

+ 3 - 4
packages/app/src/pages/[[...path]].page.tsx

@@ -4,7 +4,7 @@ import React, { useEffect } from 'react';
 import EventEmitter from 'events';
 
 import {
-  IDataWithMeta, IPageInfoForEntity, IPagePopulatedToShowRevision, isClient, isIPageInfoForEntity, isServer, IUser, IUserHasId, pagePathUtils, pathUtils,
+  IDataWithMeta, IPageInfoForEntity, IPagePopulatedToShowRevision, isClient, isIPageInfoForEntity, IUser, IUserHasId, pagePathUtils, pathUtils,
 } from '@growi/core';
 import ExtensibleCustomError from 'extensible-custom-error';
 import { model as mongooseModel } from 'mongoose';
@@ -61,7 +61,7 @@ import {
   useHackmdUri,
   useIsAclEnabled, useIsUserPage, useIsNotCreatable,
   useCsrfToken, useIsSearchScopeChildrenAsDefault, useCurrentPageId, useCurrentPathname,
-  useIsSlackConfigured, useIsBlinkedHeaderAtBoot, useRendererConfig, useEditingMarkdown,
+  useIsSlackConfigured, useRendererConfig, useEditingMarkdown,
   useEditorConfig, useIsAllReplyShown, useIsUploadableFile, useIsUploadableImage,
 } from '../stores/context';
 
@@ -205,7 +205,6 @@ const GrowiPage: NextPage<Props> = (props: Props) => {
   useIsIdenticalPath(false); // TODO: need to initialize from props
   // useIsAbleToDeleteCompletely(props.isAbleToDeleteCompletely);
   useIsEnabledStaleNotification(props.isEnabledStaleNotification);
-  useIsBlinkedHeaderAtBoot(false);
 
   useIsSearchServiceConfigured(props.isSearchServiceConfigured);
   useIsSearchServiceReachable(props.isSearchServiceReachable);
@@ -337,7 +336,7 @@ const GrowiPage: NextPage<Props> = (props: Props) => {
           <Comments pageId={pageId} />
           {/* )} */}
           {/* TODO: Create UsersHomePageFooter conponent */}
-          { isUsersHomePage(pageWithMeta?.data.path) && (
+          { isUsersHomePage(props.currentPathname) && (
             <div className="container-lg user-page-footer py-5">
               <div className="grw-user-page-list-m d-edit-none">
                 <h2 id="bookmarks-list" className="grw-user-page-header border-bottom pb-2 mb-3">

+ 1 - 1
packages/app/src/stores/context.tsx

@@ -240,7 +240,7 @@ export const useIsAllReplyShown = (initialData?: boolean): SWRResponse<boolean,
 };
 
 export const useIsBlinkedHeaderAtBoot = (initialData?: boolean): SWRResponse<boolean, Error> => {
-  return useStaticSWR('isBlinkedAtBoot', initialData);
+  return useStaticSWR('isBlinkedAtBoot', initialData, { fallbackData: false });
 };
 
 export const useEditingMarkdown = (initialData?: string): SWRResponse<string, Error> => {

+ 3 - 0
packages/app/src/stores/renderer.tsx

@@ -53,6 +53,9 @@ export const useViewOptions = (storeTocNodeHandler: (toc: HtmlElementNode) => vo
   return useSWRImmutable<RendererOptions, Error>(
     key,
     (rendererId, currentPagePath, rendererConfig) => generateViewOptions(currentPagePath, rendererConfig, storeTocNodeHandler),
+    {
+      fallbackData: isAllDataValid ? generateViewOptions(currentPagePath, rendererConfig, storeTocNodeHandler) : undefined,
+    },
   );
 };
 

+ 6 - 5
packages/app/src/styles/_mixins.scss

@@ -117,12 +117,13 @@
   }
 }
 
-@mixin blink-bgcolor($bgcolor) {
-  @keyframes fadeout {
-    100% {
-      opacity: 0;
-    }
+@keyframes fadeout {
+  100% {
+    opacity: 0;
   }
+}
+
+@mixin blink-bgcolor($bgcolor) {
   position: relative;
   z-index: 1;