mirror of
https://github.com/silverstripe/doc.silverstripe.org
synced 2024-10-22 15:05:50 +00:00
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:
commit
415351f12e
@ -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) {
|
||||
@ -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,
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user