mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2025-05-15 23:54:42 -04:00
Deduplicate code (#217)
* Deduplicate code Signed-off-by: Tilman Vatteroth <tilman.vatteroth@tu-dortmund.de>
This commit is contained in:
parent
ab2a73c6a8
commit
5f4cc63eb4
5 changed files with 46 additions and 40 deletions
|
@ -12,7 +12,22 @@ import { TaskBar } from './task-bar/task-bar'
|
||||||
|
|
||||||
const Editor: React.FC = () => {
|
const Editor: React.FC = () => {
|
||||||
const editorMode: EditorMode = useSelector((state: ApplicationState) => state.editorConfig.editorMode)
|
const editorMode: EditorMode = useSelector((state: ApplicationState) => state.editorConfig.editorMode)
|
||||||
const [markdownContent, setMarkdownContent] = useState('# Embedding demo\n\n## Slideshare\n{%slideshare mazlan1/internet-of-things-the-tip-of-an-iceberg %}\n\n## Gist\nhttps://gist.github.com/schacon/1\n\n## YouTube\nhttps://www.youtube.com/watch?v=KgMpKsp23yY\n\n## Vimeo\nhttps://vimeo.com/23237102\n\n## PDF\n{%pdf https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf %}')
|
const [markdownContent, setMarkdownContent] = useState(`
|
||||||
|
# Embedding demo
|
||||||
|
## Slideshare
|
||||||
|
{%slideshare mazlan1/internet-of-things-the-tip-of-an-iceberg %}
|
||||||
|
|
||||||
|
## Gist
|
||||||
|
https://gist.github.com/schacon/1
|
||||||
|
|
||||||
|
## YouTube
|
||||||
|
https://www.youtube.com/watch?v=KgMpKsp23yY
|
||||||
|
|
||||||
|
## Vimeo
|
||||||
|
https://vimeo.com/23237102
|
||||||
|
|
||||||
|
## PDF
|
||||||
|
{%pdf https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf %}`)
|
||||||
const isWide = useMedia({ minWidth: 576 })
|
const isWide = useMedia({ minWidth: 576 })
|
||||||
const [firstDraw, setFirstDraw] = useState(true)
|
const [firstDraw, setFirstDraw] = useState(true)
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,16 @@
|
||||||
|
import { DomElement } from 'domhandler'
|
||||||
import MarkdownIt from 'markdown-it'
|
import MarkdownIt from 'markdown-it'
|
||||||
import abbreviation from 'markdown-it-abbr'
|
import abbreviation from 'markdown-it-abbr'
|
||||||
import markdownItContainer from 'markdown-it-container'
|
import markdownItContainer from 'markdown-it-container'
|
||||||
import definitionList from 'markdown-it-deflist'
|
import definitionList from 'markdown-it-deflist'
|
||||||
import emoji from 'markdown-it-emoji'
|
import emoji from 'markdown-it-emoji'
|
||||||
|
import footnote from 'markdown-it-footnote'
|
||||||
import inserted from 'markdown-it-ins'
|
import inserted from 'markdown-it-ins'
|
||||||
import marked from 'markdown-it-mark'
|
import marked from 'markdown-it-mark'
|
||||||
import markdownItRegex from 'markdown-it-regex'
|
import markdownItRegex from 'markdown-it-regex'
|
||||||
import subscript from 'markdown-it-sub'
|
import subscript from 'markdown-it-sub'
|
||||||
import superscript from 'markdown-it-sup'
|
import superscript from 'markdown-it-sup'
|
||||||
import taskList from 'markdown-it-task-lists'
|
import taskList from 'markdown-it-task-lists'
|
||||||
import footnote from 'markdown-it-footnote'
|
|
||||||
import React, { ReactElement, useMemo } from 'react'
|
import React, { ReactElement, useMemo } from 'react'
|
||||||
import ReactHtmlParser, { convertNodeToElement, Transform } from 'react-html-parser'
|
import ReactHtmlParser, { convertNodeToElement, Transform } from 'react-html-parser'
|
||||||
import { createRenderContainer, validAlertLevels } from './container-plugins/alert'
|
import { createRenderContainer, validAlertLevels } from './container-plugins/alert'
|
||||||
|
@ -33,13 +34,25 @@ export interface MarkdownPreviewProps {
|
||||||
content: string
|
content: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type ComponentReplacer = (node: DomElement, counterMap: Map<string, number>) => (ReactElement | undefined);
|
||||||
|
const allComponentReplacers: ComponentReplacer[] = [getYouTubeReplacement, getVimeoReplacement, getGistReplacement, getPDFReplacement]
|
||||||
|
type ComponentReplacer2Identifier2CounterMap = Map<ComponentReplacer, Map<string, number>>
|
||||||
|
|
||||||
|
const tryToReplaceNode = (node: DomElement, componentReplacer2Identifier2CounterMap: ComponentReplacer2Identifier2CounterMap) => {
|
||||||
|
return allComponentReplacers
|
||||||
|
.map((componentReplacer) => {
|
||||||
|
const identifier2CounterMap = componentReplacer2Identifier2CounterMap.get(componentReplacer) || new Map<string, number>()
|
||||||
|
return componentReplacer(node, identifier2CounterMap)
|
||||||
|
})
|
||||||
|
.find((replacement) => !!replacement)
|
||||||
|
}
|
||||||
|
|
||||||
const MarkdownPreview: React.FC<MarkdownPreviewProps> = ({ content }) => {
|
const MarkdownPreview: React.FC<MarkdownPreviewProps> = ({ content }) => {
|
||||||
const markdownIt = useMemo(() => {
|
const markdownIt = useMemo(() => {
|
||||||
const md = new MarkdownIt('default', {
|
const md = new MarkdownIt('default', {
|
||||||
html: true,
|
html: true,
|
||||||
breaks: true,
|
breaks: true,
|
||||||
langPrefix: '',
|
langPrefix: '',
|
||||||
linkify: false,
|
|
||||||
typographer: true
|
typographer: true
|
||||||
})
|
})
|
||||||
md.use(taskList)
|
md.use(taskList)
|
||||||
|
@ -70,36 +83,12 @@ const MarkdownPreview: React.FC<MarkdownPreviewProps> = ({ content }) => {
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const result: ReactElement[] = useMemo(() => {
|
const result: ReactElement[] = useMemo(() => {
|
||||||
const youtubeIdCounterMap = new Map<string, number>()
|
const componentReplacer2Identifier2CounterMap = new Map<ComponentReplacer, Map<string, number>>()
|
||||||
const vimeoIdCounterMap = new Map<string, number>()
|
|
||||||
const gistIdCounterMap = new Map<string, number>()
|
|
||||||
|
|
||||||
const html: string = markdownIt.render(content)
|
const html: string = markdownIt.render(content)
|
||||||
const transform: Transform = (node, index) => {
|
const transform: Transform = (node, index) => {
|
||||||
const resultYT = getYouTubeReplacement(node, youtubeIdCounterMap)
|
return tryToReplaceNode(node, componentReplacer2Identifier2CounterMap) || convertNodeToElement(node, index, transform)
|
||||||
if (resultYT) {
|
|
||||||
return resultYT
|
|
||||||
}
|
|
||||||
|
|
||||||
const resultVimeo = getVimeoReplacement(node, vimeoIdCounterMap)
|
|
||||||
if (resultVimeo) {
|
|
||||||
return resultVimeo
|
|
||||||
}
|
|
||||||
|
|
||||||
const resultGist = getGistReplacement(node, gistIdCounterMap)
|
|
||||||
if (resultGist) {
|
|
||||||
return resultGist
|
|
||||||
}
|
|
||||||
|
|
||||||
const resultPdf = getPDFReplacement(node, gistIdCounterMap)
|
|
||||||
if (resultPdf) {
|
|
||||||
return resultPdf
|
|
||||||
}
|
|
||||||
|
|
||||||
return convertNodeToElement(node, index, transform)
|
|
||||||
}
|
}
|
||||||
const ret: ReactElement[] = ReactHtmlParser(html, { transform: transform })
|
return ReactHtmlParser(html, { transform: transform })
|
||||||
return ret
|
|
||||||
}, [content, markdownIt])
|
}, [content, markdownIt])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { DomElement } from 'domhandler'
|
import React, { useCallback, useEffect, useMemo, useState } from 'react'
|
||||||
import React, { ReactElement, useCallback, useEffect, useMemo, useState } from 'react'
|
import { ComponentReplacer } from '../../markdown-preview'
|
||||||
import { OneClickEmbedding } from '../one-click-frame/one-click-embedding'
|
import { OneClickEmbedding } from '../one-click-frame/one-click-embedding'
|
||||||
import { getIdFromCodiMdTag } from '../video-util'
|
import { getIdFromCodiMdTag } from '../video-util'
|
||||||
import './gist-frame.scss'
|
import './gist-frame.scss'
|
||||||
|
@ -14,7 +14,7 @@ interface resizeEvent {
|
||||||
id: string
|
id: string
|
||||||
}
|
}
|
||||||
|
|
||||||
const getElementReplacement = (node: DomElement, counterMap: Map<string, number>): (ReactElement | undefined) => {
|
const getElementReplacement:ComponentReplacer = (node, counterMap) => {
|
||||||
const gistId = getIdFromCodiMdTag(node, 'gist')
|
const gistId = getIdFromCodiMdTag(node, 'gist')
|
||||||
if (gistId) {
|
if (gistId) {
|
||||||
const count = (counterMap.get(gistId) || 0) + 1
|
const count = (counterMap.get(gistId) || 0) + 1
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import { DomElement } from 'domhandler'
|
import React, { useCallback } from 'react'
|
||||||
import React, { ReactElement, useCallback } from 'react'
|
import { ComponentReplacer } from '../../markdown-preview'
|
||||||
import { OneClickEmbedding } from '../one-click-frame/one-click-embedding'
|
import { OneClickEmbedding } from '../one-click-frame/one-click-embedding'
|
||||||
import { getIdFromCodiMdTag, VideoFrameProps } from '../video-util'
|
import { getIdFromCodiMdTag, VideoFrameProps } from '../video-util'
|
||||||
|
|
||||||
const getElementReplacement = (node: DomElement, counterMap: Map<string, number>): (ReactElement | undefined) => {
|
const getElementReplacement:ComponentReplacer = (node, counterMap) => {
|
||||||
const videoId = getIdFromCodiMdTag(node, 'vimeo')
|
const videoId = getIdFromCodiMdTag(node, 'vimeo')
|
||||||
if (videoId) {
|
if (videoId) {
|
||||||
const count = (counterMap.get(videoId) || 0) + 1
|
const count = (counterMap.get(videoId) || 0) + 1
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import { DomElement } from 'domhandler'
|
import React from 'react'
|
||||||
import React, { ReactElement } from 'react'
|
import { ComponentReplacer } from '../../markdown-preview'
|
||||||
import { OneClickEmbedding } from '../one-click-frame/one-click-embedding'
|
import { OneClickEmbedding } from '../one-click-frame/one-click-embedding'
|
||||||
import { getIdFromCodiMdTag, VideoFrameProps } from '../video-util'
|
import { getIdFromCodiMdTag, VideoFrameProps } from '../video-util'
|
||||||
|
|
||||||
const getElementReplacement = (node: DomElement, counterMap: Map<string, number>): (ReactElement | undefined) => {
|
const getElementReplacement: ComponentReplacer = (node, counterMap) => {
|
||||||
const videoId = getIdFromCodiMdTag(node, 'youtube')
|
const videoId = getIdFromCodiMdTag(node, 'youtube')
|
||||||
if (videoId) {
|
if (videoId) {
|
||||||
const count = (counterMap.get(videoId) || 0) + 1
|
const count = (counterMap.get(videoId) || 0) + 1
|
||||||
|
@ -14,7 +14,9 @@ const getElementReplacement = (node: DomElement, counterMap: Map<string, number>
|
||||||
|
|
||||||
export const YouTubeFrame: React.FC<VideoFrameProps> = ({ id }) => {
|
export const YouTubeFrame: React.FC<VideoFrameProps> = ({ id }) => {
|
||||||
return (
|
return (
|
||||||
<OneClickEmbedding containerClassName={'embed-responsive embed-responsive-16by9'} previewContainerClassName={'embed-responsive-item'} hoverIcon={'youtube-play'} loadingImageUrl={`//i.ytimg.com/vi/${id}/maxresdefault.jpg`}>
|
<OneClickEmbedding containerClassName={'embed-responsive embed-responsive-16by9'}
|
||||||
|
previewContainerClassName={'embed-responsive-item'} hoverIcon={'youtube-play'}
|
||||||
|
loadingImageUrl={`//i.ytimg.com/vi/${id}/maxresdefault.jpg`}>
|
||||||
<iframe className='embed-responsive-item' title={`youtube video of ${id}`}
|
<iframe className='embed-responsive-item' title={`youtube video of ${id}`}
|
||||||
src={`//www.youtube-nocookie.com/embed/${id}?autoplay=1`}
|
src={`//www.youtube-nocookie.com/embed/${id}?autoplay=1`}
|
||||||
allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture"/>
|
allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture"/>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue