Ver Fonte

impl onLoaded event

Yuki Takei há 3 anos atrás
pai
commit
0e9aca7be0

+ 52 - 23
packages/app/src/components/Comments.tsx

@@ -1,9 +1,9 @@
-import React from 'react';
+import React, { useEffect, useRef } from 'react';
 
 
 import { type IRevisionHasId, pagePathUtils } from '@growi/core';
 import { type IRevisionHasId, pagePathUtils } from '@growi/core';
 import dynamic from 'next/dynamic';
 import dynamic from 'next/dynamic';
 
 
-import type { PageCommentProps } from '~/components/PageComment';
+import { ROOT_ELEM_ID as PageCommentRootElemId, type PageCommentProps } from '~/components/PageComment';
 import { useSWRxPageComment } from '~/stores/comment';
 import { useSWRxPageComment } from '~/stores/comment';
 import { useIsTrashPage } from '~/stores/page';
 import { useIsTrashPage } from '~/stores/page';
 
 
@@ -22,16 +22,47 @@ export type CommentsProps = {
   pageId: string,
   pageId: string,
   pagePath: string,
   pagePath: string,
   revision: IRevisionHasId,
   revision: IRevisionHasId,
+  onLoaded?: () => void,
 }
 }
 
 
 export const Comments = (props: CommentsProps): JSX.Element => {
 export const Comments = (props: CommentsProps): JSX.Element => {
 
 
-  const { pageId, pagePath, revision } = props;
+  const {
+    pageId, pagePath, revision, onLoaded,
+  } = props;
 
 
   const { mutate } = useSWRxPageComment(pageId);
   const { mutate } = useSWRxPageComment(pageId);
   const { data: isDeleted } = useIsTrashPage();
   const { data: isDeleted } = useIsTrashPage();
   const { data: currentUser } = useCurrentUser();
   const { data: currentUser } = useCurrentUser();
 
 
+  const pageCommentParentRef = useRef<HTMLDivElement>(null);
+
+  useEffect(() => {
+    const parent = pageCommentParentRef.current;
+    if (parent == null) return;
+
+    const observerCallback = (mutationRecords:MutationRecord[]) => {
+      mutationRecords.forEach((record:MutationRecord) => {
+        const target = record.target as HTMLElement;
+
+        for (const child of Array.from(target.children)) {
+          const childId = (child as HTMLElement).id;
+          if (childId === PageCommentRootElemId) {
+            onLoaded?.();
+            break;
+          }
+        }
+
+      });
+    };
+
+    const observer = new MutationObserver(observerCallback);
+    observer.observe(parent, { childList: true });
+    return () => {
+      observer.disconnect();
+    };
+  }, [onLoaded]);
+
   const isTopPagePath = isTopPage(pagePath);
   const isTopPagePath = isTopPage(pagePath);
 
 
   if (pageId == null || isTopPagePath) {
   if (pageId == null || isTopPagePath) {
@@ -41,29 +72,27 @@ export const Comments = (props: CommentsProps): JSX.Element => {
   return (
   return (
     <div className="page-comments-row mt-5 py-4 d-edit-none d-print-none">
     <div className="page-comments-row mt-5 py-4 d-edit-none d-print-none">
       <div className="container-lg">
       <div className="container-lg">
-        <div className="page-comments">
-          <div id="page-comments-list" className="page-comments-list">
-            <PageComment
+        <div id="page-comments-list" className="page-comments-list" ref={pageCommentParentRef}>
+          <PageComment
+            pageId={pageId}
+            pagePath={pagePath}
+            revision={revision}
+            currentUser={currentUser}
+            isReadOnly={false}
+            titleAlign="left"
+            hideIfEmpty={false}
+          />
+        </div>
+        { !isDeleted && (
+          <div id="page-comment-write">
+            <CommentEditor
               pageId={pageId}
               pageId={pageId}
-              pagePath={pagePath}
-              revision={revision}
-              currentUser={currentUser}
-              isReadOnly={false}
-              titleAlign="left"
-              hideIfEmpty={false}
+              isForNewComment
+              onCommentButtonClicked={mutate}
+              revisionId={revision._id}
             />
             />
           </div>
           </div>
-          { !isDeleted && (
-            <div id="page-comment-write">
-              <CommentEditor
-                pageId={pageId}
-                isForNewComment
-                onCommentButtonClicked={mutate}
-                revisionId={revision._id}
-              />
-            </div>
-          )}
-        </div>
+        )}
       </div>
       </div>
     </div>
     </div>
   );
   );

+ 30 - 2
packages/app/src/components/Page/PageView.tsx

@@ -1,4 +1,7 @@
-import React, { useEffect, useMemo } from 'react';
+import React, {
+  useEffect, useMemo, useRef, useState,
+} from 'react';
+
 
 
 import { type IPagePopulatedToShowRevision, pagePathUtils } from '@growi/core';
 import { type IPagePopulatedToShowRevision, pagePathUtils } from '@growi/core';
 import dynamic from 'next/dynamic';
 import dynamic from 'next/dynamic';
@@ -13,9 +16,11 @@ import { useViewOptions } from '~/stores/renderer';
 import { useIsMobile } from '~/stores/ui';
 import { useIsMobile } from '~/stores/ui';
 import { registerGrowiFacade } from '~/utils/growi-facade';
 import { registerGrowiFacade } from '~/utils/growi-facade';
 
 
+
 import type { CommentsProps } from '../Comments';
 import type { CommentsProps } from '../Comments';
 import { MainPane } from '../Layout/MainPane';
 import { MainPane } from '../Layout/MainPane';
 import { PageAlerts } from '../PageAlert/PageAlerts';
 import { PageAlerts } from '../PageAlert/PageAlerts';
+import { ROOT_ELEM_ID as PageCommentRootElemId } from '../PageComment';
 import { PageContentFooter } from '../PageContentFooter';
 import { PageContentFooter } from '../PageContentFooter';
 import type { PageSideContentsProps } from '../PageSideContents';
 import type { PageSideContentsProps } from '../PageSideContents';
 import { UserInfo } from '../User/UserInfo';
 import { UserInfo } from '../User/UserInfo';
@@ -47,6 +52,27 @@ type Props = {
 }
 }
 
 
 export const PageView = (props: Props): JSX.Element => {
 export const PageView = (props: Props): JSX.Element => {
+
+  const commentsContainerRef = useRef<HTMLDivElement>(null);
+
+  const [isCommentsLoaded, setCommentsLoaded] = useState(false);
+
+  // ***************************  Auto Scroll  ***************************
+  useEffect(() => {
+    // do nothing if hash is empty
+    const { hash } = window.location;
+    if (hash.length === 0) {
+      return;
+    }
+
+    const targetId = hash.slice(1);
+
+    const target = document.getElementById(targetId);
+    target?.scrollIntoView();
+
+  }, [isCommentsLoaded]);
+  // *******************************  end  *******************************
+
   const {
   const {
     pagePath, initialPage, rendererConfig,
     pagePath, initialPage, rendererConfig,
   } = props;
   } = props;
@@ -96,7 +122,9 @@ export const PageView = (props: Props): JSX.Element => {
   const footerContents = !isIdenticalPathPage && !isNotFound
   const footerContents = !isIdenticalPathPage && !isNotFound
     ? (
     ? (
       <>
       <>
-        <Comments pageId={page._id} pagePath={pagePath} revision={page.revision} />
+        <div id="comments-container" ref={commentsContainerRef}>
+          <Comments pageId={page._id} pagePath={pagePath} revision={page.revision} onLoaded={() => setCommentsLoaded(true)} />
+        </div>
         { isUsersHomePagePath && (
         { isUsersHomePagePath && (
           <UsersHomePageFooter creatorId={page.creator._id}/>
           <UsersHomePageFooter creatorId={page.creator._id}/>
         ) }
         ) }