diff --git a/CHANGELOG.md b/CHANGELOG.md index 886f83007c..61b0c8f0b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Repository names may not end with ".git" ([#1277](https://github.com/scm-manager/scm-manager/pull/1277)) - Add preselected value to options in dropdown component if missing ([#1287](https://github.com/scm-manager/scm-manager/pull/1287)) +- Fix timing problem with anchor links for markdown view ([#1290](https://github.com/scm-manager/scm-manager/pull/1290)) ## [2.3.1] - 2020-08-04 ### Added diff --git a/scm-ui/ui-components/src/MarkdownView.tsx b/scm-ui/ui-components/src/MarkdownView.tsx index 946fdc37c9..164d49abaf 100644 --- a/scm-ui/ui-components/src/MarkdownView.tsx +++ b/scm-ui/ui-components/src/MarkdownView.tsx @@ -30,18 +30,23 @@ import ErrorBoundary from "./ErrorBoundary"; import SyntaxHighlighter from "./SyntaxHighlighter"; import MarkdownHeadingRenderer from "./MarkdownHeadingRenderer"; import { create } from "./MarkdownLinkRenderer"; -import {useTranslation, WithTranslation, withTranslation} from "react-i18next"; +import { useTranslation, WithTranslation, withTranslation } from "react-i18next"; import Notification from "./Notification"; import { createTransformer } from "./remarkChangesetShortLinkParser"; -type Props = RouteComponentProps & WithTranslation & { - content: string; - renderContext?: object; - renderers?: any; - skipHtml?: boolean; - enableAnchorHeadings?: boolean; - // basePath for markdown links - basePath?: string; +type Props = RouteComponentProps & + WithTranslation & { + content: string; + renderContext?: object; + renderers?: any; + skipHtml?: boolean; + enableAnchorHeadings?: boolean; + // basePath for markdown links + basePath?: string; + }; + +type State = { + contentRef: HTMLDivElement | null | undefined; }; const xmlMarkupSample = `\`\`\`xml @@ -73,27 +78,35 @@ const MarkdownErrorNotification: FC = () => { ); }; -class MarkdownView extends React.Component { +class MarkdownView extends React.Component { static defaultProps: Partial = { enableAnchorHeadings: false, skipHtml: false }; - contentRef: HTMLDivElement | null | undefined; - constructor(props: Props) { super(props); + this.state = { + contentRef: null + }; + } + + shouldComponentUpdate(nextProps: Readonly, nextState: Readonly, nextContext: any): boolean { + // We have check if the contentRef changed and update afterwards so the page can scroll to the anchor links. + // Otherwise it can happen that componentDidUpdate is never executed depending on how fast the markdown got rendered + return this.state.contentRef !== nextState.contentRef; } componentDidUpdate() { + const { contentRef } = this.state; // 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) { + if (contentRef && hash) { // we query only child elements, to avoid strange scrolling with multiple // markdown elements on one page. - const element = this.contentRef.querySelector(hash); + const element = contentRef.querySelector(hash); if (element && element.scrollIntoView) { element.scrollIntoView(); } @@ -128,7 +141,7 @@ class MarkdownView extends React.Component { return ( -
(this.contentRef = el)}> +
this.setState({ contentRef: el })}>