2019-11-08 03:40:20 +01:00
|
|
|
import { createElement, ReactElement } from "react";
|
2022-05-05 07:39:43 +02:00
|
|
|
import { DomElement, domToReact, htmlToDOM } from 'html-react-parser';
|
2019-11-08 03:40:20 +01:00
|
|
|
|
2022-05-05 07:39:43 +02:00
|
|
|
/**
|
|
|
|
* Generate the ID for a heading
|
|
|
|
*/
|
2019-11-19 05:03:40 +01:00
|
|
|
const generateID = (title: string): string => {
|
|
|
|
return title
|
|
|
|
.replace('&', '-and-')
|
|
|
|
.replace('&', '-and-')
|
|
|
|
.replace(/[^A-Za-z0-9]/g, '-')
|
|
|
|
.replace(/-+/g, '-')
|
|
|
|
.replace(/^-/g, '')
|
|
|
|
.replace(/-$/g, '')
|
|
|
|
.toLowerCase();
|
|
|
|
}
|
2022-05-05 07:39:43 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the full plain text of the heading for checking and generating the ID
|
|
|
|
*/
|
|
|
|
const getFullHeading = (element: DomElement): string => {
|
|
|
|
let text = '';
|
|
|
|
if (element.type === 'text') {
|
|
|
|
text += element.data;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (element.children) {
|
|
|
|
for (const child of element.children) {
|
|
|
|
text += getFullHeading(child);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return text;
|
|
|
|
}
|
|
|
|
|
2019-11-19 04:29:29 +01:00
|
|
|
/**
|
|
|
|
* If a header has a {#explicit-id}, add it as an attribute
|
|
|
|
*/
|
2019-11-08 03:40:20 +01:00
|
|
|
const rewriteHeaders = (domNode: DomElement): ReactElement | false => {
|
|
|
|
if (!domNode.name) {
|
|
|
|
return false;
|
|
|
|
}
|
2022-05-05 07:39:43 +02:00
|
|
|
|
|
|
|
const plainText = getFullHeading(domNode);
|
|
|
|
|
|
|
|
if (plainText) {
|
|
|
|
// const plainText = getFullHeading(firstChild);
|
|
|
|
const matches = plainText.match(/^(.*?)\{#([A-Za-z0-9_-]+)\}$/);
|
2019-11-19 05:03:40 +01:00
|
|
|
let header;
|
|
|
|
let id;
|
2019-11-08 03:40:20 +01:00
|
|
|
if (matches) {
|
2019-11-19 05:03:40 +01:00
|
|
|
header = matches[1];
|
|
|
|
id = matches[2];
|
|
|
|
} else {
|
2022-05-05 07:39:43 +02:00
|
|
|
header = plainText;
|
|
|
|
id = generateID(plainText);
|
2019-11-08 03:40:20 +01:00
|
|
|
}
|
2019-11-19 05:03:40 +01:00
|
|
|
|
2022-05-05 07:39:43 +02:00
|
|
|
const anchor = htmlToDOM(`<a id="${id}" class="anchor" aria-hidden="true" href="#${id}">#</a>`)[0];
|
|
|
|
|
|
|
|
const lastChild = domNode.children ? domNode.children[domNode.children.length - 1] : null;
|
|
|
|
if (lastChild && lastChild.type === 'text') {
|
|
|
|
lastChild.data = lastChild.data.replace(/\s*{#([A-Za-z0-9_-]+)\}$/, '');
|
|
|
|
}
|
|
|
|
|
|
|
|
domNode.children?.push(anchor);
|
|
|
|
|
|
|
|
return domToReact([domNode]);
|
2019-11-19 05:03:40 +01:00
|
|
|
|
2019-11-08 03:40:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-11-19 05:03:40 +01:00
|
|
|
|
2019-11-08 03:40:20 +01:00
|
|
|
export default rewriteHeaders;
|