mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2024-11-22 09:46:30 -05:00
Extract clean title from first heading (#616)
* removed first-header-extractor get first heading from markdown rende * don't remove editor or renderer just hide them this way both are always up to date and can be shown very fast * extracted image alt attribute into first title. too * added tests as suggested by @mrdrogdrog
This commit is contained in:
parent
192f66d169
commit
1ab9b58031
5 changed files with 47 additions and 47 deletions
|
@ -63,5 +63,23 @@ describe('Document Title', () => {
|
|||
.type(`# ${title} [link](https://codimd.org)`)
|
||||
cy.title().should('eq', `${title} link - HedgeDoc @ ${branding.name}`)
|
||||
})
|
||||
|
||||
it('markdown syntax removed first', () => {
|
||||
cy.get('.CodeMirror textarea')
|
||||
.type(`# ${title} 1*2*3 4*5**`)
|
||||
cy.title().should('eq', `${title} 123 4*5** - HedgeDoc @ ${branding.name}`)
|
||||
})
|
||||
|
||||
it('markdown syntax removed second', () => {
|
||||
cy.get('.CodeMirror textarea')
|
||||
.type(`# ${title} **1 2*`)
|
||||
cy.title().should('eq', `${title} *1 2 - HedgeDoc @ ${branding.name}`)
|
||||
})
|
||||
|
||||
it('markdown syntax removed third', () => {
|
||||
cy.get('.CodeMirror textarea')
|
||||
.type(`# ${title} _asd_`)
|
||||
cy.title().should('eq', `${title} asd - HedgeDoc @ ${branding.name}`)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -54,7 +54,7 @@ export const Editor: React.FC = () => {
|
|||
} else if (noteMetadata.current?.opengraph && noteMetadata.current?.opengraph.get('title') && noteMetadata.current?.opengraph.get('title') !== '') {
|
||||
setDocumentTitle(noteMetadata.current.opengraph.get('title') ?? untitledNote)
|
||||
} else {
|
||||
setDocumentTitle(firstHeading.current ?? untitledNote)
|
||||
setDocumentTitle((firstHeading.current ?? untitledNote).trim())
|
||||
}
|
||||
}, [untitledNote])
|
||||
|
||||
|
|
|
@ -43,21 +43,17 @@ export const Splitter: React.FC<SplitterProps> = ({ containerClassName, left, ri
|
|||
}
|
||||
}}
|
||||
>
|
||||
<ShowIf condition={showLeft}>
|
||||
<div className={'splitter left'} style={{ flexBasis: `calc(${realSplit}% - 5px)` }}>
|
||||
{left}
|
||||
</div>
|
||||
</ShowIf>
|
||||
<div className={`splitter left ${!showLeft ? 'd-none' : ''}`} style={{ flexBasis: `calc(${realSplit}% - 5px)` }}>
|
||||
{left}
|
||||
</div>
|
||||
<ShowIf condition={showLeft && showRight}>
|
||||
<div className='splitter separator'>
|
||||
<SplitDivider onGrab={() => setDoResizing(true)}/>
|
||||
</div>
|
||||
</ShowIf>
|
||||
<ShowIf condition={showRight}>
|
||||
<div className={'splitter right'}>
|
||||
{right}
|
||||
</div>
|
||||
</ShowIf>
|
||||
<div className={`splitter right ${!showRight ? 'd-none' : ''}`}>
|
||||
{right}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ import mathJax from 'markdown-it-mathjax'
|
|||
import plantuml from 'markdown-it-plantuml'
|
||||
import markdownItRegex from 'markdown-it-regex'
|
||||
import toc from 'markdown-it-toc-done-right'
|
||||
import React, { useCallback, useMemo, useRef, useState } from 'react'
|
||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { Alert } from 'react-bootstrap'
|
||||
import { Trans } from 'react-i18next'
|
||||
import { useSelector } from 'react-redux'
|
||||
|
@ -20,7 +20,6 @@ import { slugify } from '../editor/table-of-contents/table-of-contents'
|
|||
import { RawYAMLMetadata, YAMLMetaData } from '../editor/yaml-metadata/yaml-metadata'
|
||||
import { BasicMarkdownRenderer } from './basic-markdown-renderer'
|
||||
import { createRenderContainer, validAlertLevels } from './markdown-it-plugins/alert-container'
|
||||
import { firstHeaderExtractor } from './markdown-it-plugins/first-header-extractor'
|
||||
import { highlightedCode } from './markdown-it-plugins/highlighted-code'
|
||||
import { LineMarkers, lineNumberMarker } from './markdown-it-plugins/line-number-marker'
|
||||
import { plantumlError } from './markdown-it-plugins/plantuml-error'
|
||||
|
@ -119,15 +118,28 @@ export const FullMarkdownRenderer: React.FC<FullMarkdownRendererProps & Addition
|
|||
const tocAst = useRef<TocAst>()
|
||||
usePostTocAstOnChange(tocAst, onTocChange)
|
||||
|
||||
const configureMarkdownIt = useCallback((md: MarkdownIt): void => {
|
||||
if (onFirstHeadingChange) {
|
||||
md.use(firstHeaderExtractor(), {
|
||||
firstHeaderFound: (firstHeader: string | undefined) => {
|
||||
firstHeadingRef.current = firstHeader
|
||||
}
|
||||
})
|
||||
const extractInnerText = useCallback((node: ChildNode) => {
|
||||
let innerText = ''
|
||||
if (node.childNodes && node.childNodes.length > 0) {
|
||||
node.childNodes.forEach((child) => { innerText += extractInnerText(child) })
|
||||
} else if (node.nodeName === 'IMG') {
|
||||
innerText += (node as HTMLImageElement).getAttribute('alt')
|
||||
} else {
|
||||
innerText += node.textContent
|
||||
}
|
||||
return innerText
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
if (onFirstHeadingChange && documentElement.current) {
|
||||
const firstHeading = documentElement.current.getElementsByTagName('h1').item(0)
|
||||
if (firstHeading) {
|
||||
onFirstHeadingChange(extractInnerText(firstHeading))
|
||||
}
|
||||
}
|
||||
}, [content, extractInnerText, onFirstHeadingChange])
|
||||
|
||||
const configureMarkdownIt = useCallback((md: MarkdownIt): void => {
|
||||
if (onMetaDataChange) {
|
||||
md.use(frontmatter, (rawMeta: string) => {
|
||||
try {
|
||||
|
@ -210,7 +222,7 @@ export const FullMarkdownRenderer: React.FC<FullMarkdownRendererProps & Addition
|
|||
currentLineMarkers.current = lineMarkers
|
||||
}
|
||||
})
|
||||
}, [onFirstHeadingChange, onMetaDataChange, plantumlServer])
|
||||
}, [onMetaDataChange, plantumlServer])
|
||||
|
||||
const clearMetadata = useCallback(() => {
|
||||
rawMetaRef.current = undefined
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
import MarkdownIt from 'markdown-it/lib'
|
||||
|
||||
export interface FirstHeaderExtractorOptions {
|
||||
firstHeaderFound: (firstHeader: string|undefined) => void
|
||||
}
|
||||
|
||||
export const firstHeaderExtractor: () => MarkdownIt.PluginWithOptions<FirstHeaderExtractorOptions> = () => {
|
||||
return (md, options) => {
|
||||
if (!options?.firstHeaderFound) {
|
||||
return
|
||||
}
|
||||
md.core.ruler.after('normalize', 'extract first L1 heading', (state) => {
|
||||
const lines = state.src.split('\n')
|
||||
const linkAltTextRegex = /!?\[([^\]]*)]\([^)]*\)/
|
||||
for (const line of lines) {
|
||||
if (line.startsWith('# ')) {
|
||||
const headerLine = line.replace('# ', '').replace(linkAltTextRegex, '$1')
|
||||
options.firstHeaderFound(headerLine)
|
||||
return true
|
||||
}
|
||||
}
|
||||
options.firstHeaderFound(undefined)
|
||||
return true
|
||||
})
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue