/* * SonarQube * Copyright (C) 2009-2019 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 React from 'react'; import Helmet from 'react-helmet'; import { graphql } from 'gatsby'; import HeaderList from '../components/HeaderList'; import { MarkdownRemark, MarkdownRemarkConnection, MarkdownHeading } from '../@types/graphql-types'; interface Props { data: { allMarkdownRemark: Pick; markdownRemark: Pick; }; location: Location; } export default class Page extends React.PureComponent { baseUrl = ''; componentDidMount() { if (window) { this.baseUrl = window.location.origin + '/'; } const collapsables = document.getElementsByClassName('collapse'); for (let i = 0; i < collapsables.length; i++) { collapsables[i].classList.add('close'); const customBlockWrapper = collapsables[i].querySelector('.custom-block-body'); if (customBlockWrapper) { let firstChild = customBlockWrapper.firstElementChild; if (firstChild) { firstChild.outerHTML = firstChild.outerHTML .replace(/

/gi, ''); // We changed the element. It's reference is no longer correct in some // browsers. Fetch it again. firstChild = customBlockWrapper.firstElementChild; firstChild!.addEventListener('click', (event: Event & { currentTarget: HTMLElement }) => { event.preventDefault(); if ( event.currentTarget.parentElement && event.currentTarget.parentElement.parentElement ) { event.currentTarget.parentElement.parentElement.classList.toggle('close'); } }); } } } } render() { const page = this.props.data.markdownRemark; const version = process.env.GATSBY_DOCS_VERSION || ''; const mainTitle = 'SonarQube Docs'; const pageTitle = page.frontmatter && page.frontmatter.title; let htmlPageContent = page.html || ''; const realHeadingsList = removeExtraHeadings(htmlPageContent, page.headings || []); htmlPageContent = removeTableOfContents(htmlPageContent); htmlPageContent = createAnchorForHeadings(htmlPageContent, realHeadingsList); htmlPageContent = replaceDynamicLinks(htmlPageContent); htmlPageContent = replaceImageLinks(htmlPageContent); return ( <>

{pageTitle || mainTitle}

); } } export const query = graphql` query($slug: String!) { allMarkdownRemark { edges { node { html fields { slug } } } } markdownRemark(fields: { slug: { eq: $slug } }) { html headings { depth value } frontmatter { title } } } `; function replaceImageLinks(content: string) { const version = process.env.GATSBY_DOCS_VERSION || ''; if (version !== '') { content = content.replace(/(.*?)<\/a>/gim, '$2' ); // Render only the text part of links going inside the app return content.replace( /(.*?)<\/a>/gim, '$2' ); } /** * For the sidebar table of content, we do not want headers for sonarcloud, * collapsable container title, of table of contents headers. */ function removeExtraHeadings(content: string, headings: MarkdownHeading[]) { return headings .filter(heading => content.indexOf(`

${heading.value}

`) < 0) .filter(heading => !heading.value || !heading.value.match(/Table of content/i)) .filter(heading => { const regex = new RegExp( `[\\s\\S]*

${heading.value!.replace( /[.*+?^${}()|[\]\\]/g, '\\$&' )}<\\/h2>[\\s\\S]*`, 'gim' ); return !content.match(regex); }); } function createAnchorForHeadings(content: string, headings: MarkdownHeading[]) { let counter = 1; headings.forEach(h => { if (h.depth === 2) { content = content.replace( `${h.value}`, `${h.value}` ); counter++; } }); return content; } function removeTableOfContents(content: string) { return content.replace(/Table Of Contents<\/h[1-9]>/i, ''); }