fix timing problem with anchor links on markdown view

This commit is contained in:
Eduard Heimbuch
2020-08-12 14:34:27 +02:00
parent 0861cd4ceb
commit d25efebefd
2 changed files with 29 additions and 15 deletions

View File

@@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed ### Fixed
- Repository names may not end with ".git" ([#1277](https://github.com/scm-manager/scm-manager/pull/1277)) - 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)) - 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 ## [2.3.1] - 2020-08-04
### Added ### Added

View File

@@ -30,18 +30,23 @@ import ErrorBoundary from "./ErrorBoundary";
import SyntaxHighlighter from "./SyntaxHighlighter"; import SyntaxHighlighter from "./SyntaxHighlighter";
import MarkdownHeadingRenderer from "./MarkdownHeadingRenderer"; import MarkdownHeadingRenderer from "./MarkdownHeadingRenderer";
import { create } from "./MarkdownLinkRenderer"; import { create } from "./MarkdownLinkRenderer";
import {useTranslation, WithTranslation, withTranslation} from "react-i18next"; import { useTranslation, WithTranslation, withTranslation } from "react-i18next";
import Notification from "./Notification"; import Notification from "./Notification";
import { createTransformer } from "./remarkChangesetShortLinkParser"; import { createTransformer } from "./remarkChangesetShortLinkParser";
type Props = RouteComponentProps & WithTranslation & { type Props = RouteComponentProps &
content: string; WithTranslation & {
renderContext?: object; content: string;
renderers?: any; renderContext?: object;
skipHtml?: boolean; renderers?: any;
enableAnchorHeadings?: boolean; skipHtml?: boolean;
// basePath for markdown links enableAnchorHeadings?: boolean;
basePath?: string; // basePath for markdown links
basePath?: string;
};
type State = {
contentRef: HTMLDivElement | null | undefined;
}; };
const xmlMarkupSample = `\`\`\`xml const xmlMarkupSample = `\`\`\`xml
@@ -73,27 +78,35 @@ const MarkdownErrorNotification: FC = () => {
); );
}; };
class MarkdownView extends React.Component<Props> { class MarkdownView extends React.Component<Props, State> {
static defaultProps: Partial<Props> = { static defaultProps: Partial<Props> = {
enableAnchorHeadings: false, enableAnchorHeadings: false,
skipHtml: false skipHtml: false
}; };
contentRef: HTMLDivElement | null | undefined;
constructor(props: Props) { constructor(props: Props) {
super(props); super(props);
this.state = {
contentRef: null
};
}
shouldComponentUpdate(nextProps: Readonly<Props>, nextState: Readonly<State>, 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() { componentDidUpdate() {
const { contentRef } = this.state;
// we have to use componentDidUpdate, because we have to wait until all // we have to use componentDidUpdate, because we have to wait until all
// children are rendered and componentDidMount is called before the // children are rendered and componentDidMount is called before the
// markdown content was rendered. // markdown content was rendered.
const hash = this.props.location.hash; const hash = this.props.location.hash;
if (this.contentRef && hash) { if (contentRef && hash) {
// we query only child elements, to avoid strange scrolling with multiple // we query only child elements, to avoid strange scrolling with multiple
// markdown elements on one page. // markdown elements on one page.
const element = this.contentRef.querySelector(hash); const element = contentRef.querySelector(hash);
if (element && element.scrollIntoView) { if (element && element.scrollIntoView) {
element.scrollIntoView(); element.scrollIntoView();
} }
@@ -128,7 +141,7 @@ class MarkdownView extends React.Component<Props> {
return ( return (
<ErrorBoundary fallback={MarkdownErrorNotification}> <ErrorBoundary fallback={MarkdownErrorNotification}>
<div ref={el => (this.contentRef = el)}> <div ref={el => this.setState({ contentRef: el })}>
<Markdown <Markdown
className="content is-word-break" className="content is-word-break"
skipHtml={skipHtml} skipHtml={skipHtml}