mirror of
https://github.com/silverstripe/doc.silverstripe.org
synced 2024-10-22 15:05:50 +00:00
FIX Don't break headings when they include sub-elements.
<code> tags added to headings via backticks are the main culprit, but ultimately if any elements other than text were being added to the heading, only part of the heading would display, and any custom ID for the heading anchor link would not be used.
This commit is contained in:
parent
6fe74b1fd8
commit
a8169164b4
@ -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);
|
||||
|
@ -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]);
|
||||
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
@ -43,6 +45,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,
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user