Merge pull request #241 from creative-commoners/pulls/master/fix-headings

FIX Don't break headings when they include sub-elements.
This commit is contained in:
Steve Boyd 2022-05-20 12:27:59 +12:00 committed by GitHub
commit 415351f12e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 49 additions and 26 deletions

View File

@ -29,7 +29,7 @@ const parseHTML = (html: string): ReactElement | ReactElement[] | string => {
const domChildren = children || [];
if (name && attribs) {
if (name === 'a') {
return rewriteLink(attribs, domChildren, parseOptions);
return rewriteLink(attribs, domChildren, parseOptions, domNode);
}
if (name === 'table') {
return rewriteTable(domChildren, parseOptions);

View File

@ -1,6 +1,9 @@
import { createElement, ReactElement } from "react";
import { DomElement } from 'html-react-parser';
import { DomElement, domToReact, htmlToDOM } from 'html-react-parser';
/**
* Generate the ID for a heading
*/
const generateID = (title: string): string => {
return title
.replace('&', '-and-')
@ -11,45 +14,58 @@ const generateID = (title: string): string => {
.replace(/-$/g, '')
.toLowerCase();
}
/**
* 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;
}
/**
* If a header has a {#explicit-id}, add it as an attribute
* @param domNode
*/
const rewriteHeaders = (domNode: DomElement): ReactElement | false => {
if (!domNode.name) {
return false;
}
const firstChild = domNode.children ? domNode.children[0] : null;
if (firstChild && firstChild.type === 'text') {
const { data } = firstChild;
const matches = data.match(/^(.*?){#([A-Za-z0-9_-]+)\}$/);
const plainText = getFullHeading(domNode);
if (plainText) {
// const plainText = getFullHeading(firstChild);
const matches = plainText.match(/^(.*?)\{#([A-Za-z0-9_-]+)\}$/);
let header;
let id;
if (matches) {
header = matches[1];
id = matches[2];
} else {
header = data;
id = generateID(data);
header = plainText;
id = generateID(plainText);
}
const anchor = createElement(
'a',
{
"aria-hidden": true,
className: 'anchor',
href: `#${id}`,
id,
key: id,
},
'#'
);
const anchor = htmlToDOM(`<a id="${id}" class="anchor" aria-hidden="true" href="#${id}">#</a>`)[0];
return createElement(
domNode.name,
{},
[ header, anchor ]
);
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]);
}

View File

@ -8,6 +8,7 @@ import { SilverstripeDocument } from '../types';
interface LinkAttributes {
href?: string;
class?: string;
};
@ -31,7 +32,8 @@ const relativeLink = (currentNode: SilverstripeDocument, href: string): string =
const rewriteLink = (
attribs: LinkAttributes,
children: DomElement[],
parseOptions: HTMLReactParserOptions
parseOptions: HTMLReactParserOptions,
domNode: DomElement
): ReactElement|false => {
const { href } = attribs;
if (!href) {
@ -52,6 +54,11 @@ const rewriteLink = (
// hash links
if (href.startsWith('#')) {
// Just let normal parsing occur for heading links
if (attribs.class === 'anchor') {
return domToReact(domNode);
}
// rewrite all other hashlinks
return createElement(
Link,
{