|
@@ -1,4 +1,6 @@
|
|
|
-import React, { FC, useCallback } from 'react';
|
|
|
|
|
|
|
+import React, {
|
|
|
|
|
+ FC, useCallback, useEffect, useRef,
|
|
|
|
|
+} from 'react';
|
|
|
|
|
|
|
|
import { DropdownItem } from 'reactstrap';
|
|
import { DropdownItem } from 'reactstrap';
|
|
|
import { useTranslation } from 'react-i18next';
|
|
import { useTranslation } from 'react-i18next';
|
|
@@ -10,6 +12,7 @@ import { exportAsMarkdown } from '~/client/services/page-operation';
|
|
|
|
|
|
|
|
import RevisionLoader from '../Page/RevisionLoader';
|
|
import RevisionLoader from '../Page/RevisionLoader';
|
|
|
import AppContainer from '../../client/services/AppContainer';
|
|
import AppContainer from '../../client/services/AppContainer';
|
|
|
|
|
+import { smoothScrollIntoView } from '~/client/util/smooth-scroll';
|
|
|
import { GrowiSubNavigation } from '../Navbar/GrowiSubNavigation';
|
|
import { GrowiSubNavigation } from '../Navbar/GrowiSubNavigation';
|
|
|
import { SubNavButtons } from '../Navbar/SubNavButtons';
|
|
import { SubNavButtons } from '../Navbar/SubNavButtons';
|
|
|
import { AdditionalMenuItemsRendererProps } from '../Common/Dropdown/PageItemControl';
|
|
import { AdditionalMenuItemsRendererProps } from '../Common/Dropdown/PageItemControl';
|
|
@@ -40,6 +43,8 @@ const AdditionalMenuItems = (props: AdditionalMenuItemsProps): JSX.Element => {
|
|
|
);
|
|
);
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
|
|
+const SCROLL_OFFSET_TOP = 175; // approximate height of (navigation + subnavigation)
|
|
|
|
|
+const MUTATION_OBSERVER_CONFIG = { childList: true, subtree: true };
|
|
|
|
|
|
|
|
type Props ={
|
|
type Props ={
|
|
|
appContainer: AppContainer,
|
|
appContainer: AppContainer,
|
|
@@ -48,7 +53,45 @@ type Props ={
|
|
|
showPageControlDropdown?: boolean,
|
|
showPageControlDropdown?: boolean,
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+const scrollTo = (scrollElement:HTMLElement) => {
|
|
|
|
|
+ // use querySelector to intentionally get the first element found
|
|
|
|
|
+ const highlightedKeyword = scrollElement.querySelector('.highlighted-keyword') as HTMLElement | null;
|
|
|
|
|
+ if (highlightedKeyword != null) {
|
|
|
|
|
+ smoothScrollIntoView(highlightedKeyword, SCROLL_OFFSET_TOP, scrollElement);
|
|
|
|
|
+ }
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const generateObserverCallback = (doScroll: ()=>void) => {
|
|
|
|
|
+ return (mutationRecords:MutationRecord[]) => {
|
|
|
|
|
+ mutationRecords.forEach((record:MutationRecord) => {
|
|
|
|
|
+ const target = record.target as HTMLElement;
|
|
|
|
|
+ const targetId = target.id as string;
|
|
|
|
|
+ if (targetId !== 'wiki') return;
|
|
|
|
|
+ doScroll();
|
|
|
|
|
+ });
|
|
|
|
|
+ };
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
const SearchResultContent: FC<Props> = (props: Props) => {
|
|
const SearchResultContent: FC<Props> = (props: Props) => {
|
|
|
|
|
+ const scrollElementRef = useRef(null);
|
|
|
|
|
+
|
|
|
|
|
+ // *************************** Auto Scroll ***************************
|
|
|
|
|
+ useEffect(() => {
|
|
|
|
|
+ const scrollElement = scrollElementRef.current as HTMLElement | null;
|
|
|
|
|
+ if (scrollElement == null) return;
|
|
|
|
|
+
|
|
|
|
|
+ const observerCallback = generateObserverCallback(() => {
|
|
|
|
|
+ scrollTo(scrollElement);
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ const observer = new MutationObserver(observerCallback);
|
|
|
|
|
+ observer.observe(scrollElement, MUTATION_OBSERVER_CONFIG);
|
|
|
|
|
+ return () => {
|
|
|
|
|
+ observer.disconnect();
|
|
|
|
|
+ };
|
|
|
|
|
+ });
|
|
|
|
|
+ // ******************************* end *******************************
|
|
|
|
|
+
|
|
|
const {
|
|
const {
|
|
|
appContainer,
|
|
appContainer,
|
|
|
focusedSearchResultData,
|
|
focusedSearchResultData,
|
|
@@ -114,7 +157,7 @@ const SearchResultContent: FC<Props> = (props: Props) => {
|
|
|
page={page}
|
|
page={page}
|
|
|
controls={ControlComponents}
|
|
controls={ControlComponents}
|
|
|
/>
|
|
/>
|
|
|
- <div className="search-result-page-content">
|
|
|
|
|
|
|
+ <div className="search-result-page-content" ref={scrollElementRef}>
|
|
|
<RevisionLoader
|
|
<RevisionLoader
|
|
|
growiRenderer={growiRenderer}
|
|
growiRenderer={growiRenderer}
|
|
|
pageId={page._id}
|
|
pageId={page._id}
|