mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2025-05-22 11:15:23 -04:00
Introduce Markdown extensions (#1614)
* Introduce markdown extensions Signed-off-by: Tilman Vatteroth <git@tilmanvatteroth.de>
This commit is contained in:
parent
e9defd60dc
commit
8a8bacc0aa
148 changed files with 1878 additions and 1128 deletions
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import { TravelerNodeProcessor } from '../../node-preprocessors/traveler-node-processor'
|
||||
import type { Node } from 'domhandler'
|
||||
import { isTag } from 'domhandler'
|
||||
|
||||
export class AnchorNodePreprocessor extends TravelerNodeProcessor {
|
||||
constructor(private baseUrl: string) {
|
||||
super()
|
||||
}
|
||||
|
||||
protected processNode(node: Node): void {
|
||||
if (!isTag(node) || node.name !== 'a' || !node.attribs || !node.attribs.href) {
|
||||
return
|
||||
}
|
||||
|
||||
const url = node.attribs.href.trim()
|
||||
|
||||
// eslint-disable-next-line no-script-url
|
||||
if (url.startsWith('data:') || url.startsWith('javascript:') || url.startsWith('vbscript:')) {
|
||||
delete node.attribs.href
|
||||
return
|
||||
}
|
||||
|
||||
const isJumpMark = url.substr(0, 1) === '#'
|
||||
|
||||
if (isJumpMark) {
|
||||
node.attribs['data-jump-target-id'] = url.substr(1)
|
||||
} else {
|
||||
node.attribs.rel = 'noreferer noopener'
|
||||
node.attribs.target = '_blank'
|
||||
}
|
||||
|
||||
try {
|
||||
node.attribs.href = new URL(url, this.baseUrl).toString()
|
||||
} catch (e) {
|
||||
node.attribs.href = url
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import type { Element } from 'domhandler'
|
||||
import type { AllHTMLAttributes } from 'react'
|
||||
import React from 'react'
|
||||
import type { NativeRenderer, NodeReplacement, SubNodeTransform } from '../../replace-components/component-replacer'
|
||||
import { ComponentReplacer, DO_NOT_REPLACE } from '../../replace-components/component-replacer'
|
||||
import { JumpAnchor } from './jump-anchor'
|
||||
|
||||
/**
|
||||
* Detects anchors that should jump to scroll to another element.
|
||||
*/
|
||||
export class JumpAnchorReplacer extends ComponentReplacer {
|
||||
public replace(node: Element, subNodeTransform: SubNodeTransform, nativeRenderer: NativeRenderer): NodeReplacement {
|
||||
if (node.name !== 'a' || !node.attribs || !node.attribs['data-jump-target-id']) {
|
||||
return DO_NOT_REPLACE
|
||||
}
|
||||
|
||||
const jumpId = node.attribs['data-jump-target-id']
|
||||
delete node.attribs['data-jump-target-id']
|
||||
const replacement = nativeRenderer()
|
||||
if (replacement === null || typeof replacement === 'string') {
|
||||
return replacement
|
||||
} else {
|
||||
return <JumpAnchor {...(replacement.props as AllHTMLAttributes<HTMLAnchorElement>)} jumpTargetId={jumpId} />
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import type { AllHTMLAttributes } from 'react'
|
||||
import React, { useCallback } from 'react'
|
||||
|
||||
export interface JumpAnchorProps extends AllHTMLAttributes<HTMLAnchorElement> {
|
||||
jumpTargetId: string
|
||||
}
|
||||
|
||||
export const JumpAnchor: React.FC<JumpAnchorProps> = ({ jumpTargetId, children, ...props }) => {
|
||||
const jumpToTargetId = useCallback(
|
||||
(event: React.MouseEvent<HTMLElement, MouseEvent>): void => {
|
||||
document.getElementById(jumpTargetId)?.scrollIntoView({ behavior: 'smooth' })
|
||||
event.preventDefault()
|
||||
},
|
||||
[jumpTargetId]
|
||||
)
|
||||
|
||||
return (
|
||||
<a {...props} onClick={jumpToTargetId}>
|
||||
{children}
|
||||
</a>
|
||||
)
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import { MarkdownExtension } from '../markdown-extension'
|
||||
import { JumpAnchorReplacer } from './jump-anchor-replacer'
|
||||
import type { ComponentReplacer } from '../../replace-components/component-replacer'
|
||||
import type { NodeProcessor } from '../../node-preprocessors/node-processor'
|
||||
import { AnchorNodePreprocessor } from './anchor-node-preprocessor'
|
||||
|
||||
/**
|
||||
* Adds tweaks for anchor tags which are needed for the use in the secured iframe.
|
||||
*/
|
||||
export class LinkAdjustmentMarkdownExtension extends MarkdownExtension {
|
||||
constructor(private baseUrl: string) {
|
||||
super()
|
||||
}
|
||||
|
||||
public buildNodeProcessors(): NodeProcessor[] {
|
||||
return [new AnchorNodePreprocessor(this.baseUrl)]
|
||||
}
|
||||
|
||||
public buildReplacers(): ComponentReplacer[] {
|
||||
return [new JumpAnchorReplacer()]
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue