/* * SonarQube * Copyright (C) 2009-2020 SonarSource SA * mailto:info AT sonarsource DOT com * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as classNames from 'classnames'; import * as React from 'react'; import rehypeRaw from 'rehype-raw'; import rehypeReact from 'rehype-react'; import rehypeSlug from 'rehype-slug'; import remark from 'remark'; import remarkCustomBlocks from 'remark-custom-blocks'; import remarkRehype from 'remark-rehype'; import MetaData from 'sonar-ui-common/components/ui/update-center/MetaData'; import { scrollToElement } from 'sonar-ui-common/helpers/scrolling'; import DocCollapsibleBlock from './DocCollapsibleBlock'; import DocImg from './DocImg'; import DocLink from './DocLink'; import './DocMarkdownBlock.css'; import DocToc from './DocToc'; import DocTooltipLink from './DocTooltipLink'; interface Props { childProps?: T.Dict; className?: string; content: string; isTooltip?: boolean; stickyToc?: boolean; title?: string; } export default class DocMarkdownBlock extends React.PureComponent { node: HTMLElement | null = null; handleAnchorClick = (href: string, event: React.MouseEvent) => { if (this.node) { const element = this.node.querySelector(href); if (element) { event.preventDefault(); scrollToElement(element, { bottomOffset: window.innerHeight - 80 }); if (history.pushState) { history.pushState(null, '', href); } } } }; render() { const { childProps, content, className, title, stickyToc, isTooltip } = this.props; const md = remark(); // TODO find a way to replace these custom blocks with real Alert components md.use(remarkCustomBlocks, { danger: { classes: 'alert alert-danger' }, warning: { classes: 'alert alert-warning' }, info: { classes: 'alert alert-info' }, success: { classes: 'alert alert-success' }, collapse: { classes: 'collapse' } }) .use(remarkRehype, { allowDangerousHTML: true }) .use(rehypeSlug) .use(rehypeRaw) .use(rehypeReact, { createElement: React.createElement, components: { div: Block, // use custom link to render documentation anchors a: isTooltip ? withChildProps(DocTooltipLink, childProps) : withChildProps(DocLink, { onAnchorClick: this.handleAnchorClick }), // use custom img tag to render documentation images img: DocImg, 'update-center': ({ updatecenterkey }: { updatecenterkey: string }) => ( ) } }); return (
(this.node = ref)}>
{title !== undefined &&

{title}

} {md.processSync(content).contents}
{stickyToc && }
); } } function withChildProps

( WrappedComponent: React.ComponentType

}>, childProps?: T.Dict ) { return function withChildProps(props: P) { return ; }; } function Block(props: React.HtmlHTMLAttributes) { if (props.className) { if (props.className.includes('collapse')) { return {props.children}; } else { return

{props.children}
; } } else { return props.children; } }