fix scrolling for markdown content, which is loaded asynchronous

The code to find and scroll to the anchor is now moved from the
ScrollToTop component to the MarkdownView. The anchor with the id from
location hash, is searched after the MarkdownView and all its children
finished rendering.
This commit is contained in:
Sebastian Sdorra
2019-05-21 10:22:53 +02:00
parent 6f962ff4ce
commit 033c213cf2
2 changed files with 34 additions and 18 deletions

View File

@@ -4,12 +4,17 @@ import SyntaxHighlighter from "./SyntaxHighlighter";
import Markdown from "react-markdown/with-html"; import Markdown from "react-markdown/with-html";
import {binder} from "@scm-manager/ui-extensions"; import {binder} from "@scm-manager/ui-extensions";
import MarkdownHeadingRenderer from "./MarkdownHeadingRenderer"; import MarkdownHeadingRenderer from "./MarkdownHeadingRenderer";
import { withRouter } from "react-router-dom";
type Props = { type Props = {
content: string, content: string,
renderContext?: Object, renderContext?: Object,
renderers?: Object, renderers?: Object,
enableAnchorHeadings: boolean enableAnchorHeadings: boolean,
// context props
location: any
}; };
class MarkdownView extends React.Component<Props> { class MarkdownView extends React.Component<Props> {
@@ -18,10 +23,27 @@ class MarkdownView extends React.Component<Props> {
enableAnchorHeadings: false enableAnchorHeadings: false
}; };
contentRef: ?HTMLDivElement;
constructor(props: Props) { constructor(props: Props) {
super(props); super(props);
} }
componentDidUpdate() {
// we have to use componentDidUpdate, because we have to wait until all
// children are rendered and componentDidMount is called before the
// markdown content was rendered.
const hash = this.props.location.hash;
if (this.contentRef && hash) {
// we query only child elements, to avoid strange scrolling with multiple
// markdown elements on one page.
const element = this.contentRef.querySelector(hash);
if (element && element.scrollIntoView) {
element.scrollIntoView();
}
}
}
render() { render() {
const {content, renderers, renderContext, enableAnchorHeadings} = this.props; const {content, renderers, renderContext, enableAnchorHeadings} = this.props;
@@ -45,6 +67,7 @@ class MarkdownView extends React.Component<Props> {
} }
return ( return (
<div ref={el => (this.contentRef = el)}>
<Markdown <Markdown
className="content" className="content"
skipHtml={true} skipHtml={true}
@@ -52,8 +75,9 @@ class MarkdownView extends React.Component<Props> {
source={content} source={content}
renderers={rendererList} renderers={rendererList}
/> />
</div>
); );
} }
} }
export default MarkdownView; export default withRouter(MarkdownView);

View File

@@ -11,17 +11,9 @@ type Props = {
class ScrollToTop extends React.Component<Props> { class ScrollToTop extends React.Component<Props> {
componentDidUpdate(prevProps) { componentDidUpdate(prevProps) {
if (this.props.location.pathname !== prevProps.location.pathname) { if (this.props.location.pathname !== prevProps.location.pathname) {
const hash = this.props.location.hash;
if (hash) {
const element = document.getElementById(hash.substring(1));
if (element && element.scrollIntoView) {
element.scrollIntoView();
}
} else {
window.scrollTo(0, 0); window.scrollTo(0, 0);
} }
} }
}
render() { render() {
return this.props.children; return this.props.children;