Merge pull request #2217 from omnivore-app/fix/highlighted-markdown

fix/highlighted markdown
This commit is contained in:
Hongbo Wu
2023-05-19 17:22:08 +08:00
committed by GitHub
3 changed files with 106 additions and 10 deletions

View File

@ -948,9 +948,13 @@ export const searchResolver = authorized<
if (params.includeContent && r.content) {
// convert html to the requested format
const format = params.format || ArticleFormat.Html
const converter = contentConverter(format)
if (converter) {
r.content = converter(r.content, r.highlights)
try {
const converter = contentConverter(format)
if (converter) {
r.content = converter(r.content, r.highlights)
}
} catch (error) {
console.log('Error converting content', error)
}
}

View File

@ -66,6 +66,8 @@ function getTextNodesBetween(rootNode: Node, startNode: Node, endNode: Node) {
}
function getTextNodes(node: Node) {
if (!node) return
if (node == startNode) {
pastStartNode = true
}
@ -384,7 +386,7 @@ export function makeHighlightNodeAttributes(
patch: string,
document: Document
) {
const rootNode = document.documentElement
const rootNode = document.getRootNode()
const allArticleNodes = getTextNodesBetween(rootNode, rootNode, rootNode)
const { highlightTextStart, highlightTextEnd, textNodes, textNodeIndex } =
@ -393,7 +395,10 @@ export function makeHighlightNodeAttributes(
let startingTextNodeIndex = textNodeIndex
let quote = ''
while (highlightTextEnd > textNodes[startingTextNodeIndex].startIndex) {
while (
startingTextNodeIndex < textNodes.length &&
highlightTextEnd > textNodes[startingTextNodeIndex].startIndex
) {
const { node, textPartsToHighlight, isParagraphStart } = fillHighlight({
textNodes,
startingTextNodeIndex,

View File

@ -11,6 +11,7 @@ import { decode } from 'html-entities'
import * as jwt from 'jsonwebtoken'
import { parseHTML } from 'linkedom'
import { NodeHtmlMarkdown, TranslatorConfigObject } from 'node-html-markdown'
import { ElementNode } from 'node-html-markdown/dist/nodes'
import { ILike } from 'typeorm'
import { promisify } from 'util'
import { v4 as uuid } from 'uuid'
@ -494,13 +495,86 @@ export const fetchFavicon = async (
// custom transformer to wrap <span class="highlight"> tags in markdown highlight tags `==`
export const highlightTranslators: TranslatorConfigObject = {
/* Link */
a: ({ node, options, visitor }) => {
const href = node.getAttribute('href')
if (!href) return {}
// Encodes symbols that can cause problems in markdown
let encodedHref = ''
for (const chr of href) {
switch (chr) {
case '(':
encodedHref += '%28'
break
case ')':
encodedHref += '%29'
break
case '_':
encodedHref += '%5F'
break
case '*':
encodedHref += '%2A'
break
default:
encodedHref += chr
}
}
const title = node.getAttribute('title')
let hasHighlight = false
// If the link is a highlight, wrap it in `==` tags
node.childNodes.forEach((child) => {
if (
child.nodeType === 1 &&
(child as ElementNode).getAttribute(highlightIdAttribute)
) {
hasHighlight = true
return
}
})
// Inline link, when possible
// See: https://github.com/crosstype/node-html-markdown/issues/17
if (node.textContent === href && options.useInlineLinks)
return {
prefix: hasHighlight ? '==' : undefined,
postfix: hasHighlight ? '==' : undefined,
content: `<${encodedHref}>`,
}
const prefix = hasHighlight ? '==[' : '['
const postfix =
']' +
(!options.useLinkReferenceDefinitions
? `(${encodedHref}${title ? ` "${title}"` : ''})`
: `[${visitor.addOrGetUrlDefinition(encodedHref)}]`) +
`${hasHighlight ? '==' : ''}`
return {
postprocess: ({ content }) => content.replace(/(?:\r?\n)+/g, ' '),
childTranslators: visitor.instance.aTagTranslators,
prefix,
postfix,
}
},
span: ({ node }) => {
const id = node.getAttribute(highlightIdAttribute)
if (!id) return {}
const hasLeadingSpace = node.innerHTML.startsWith(' ')
const hasTrailingSpace = node.innerHTML.endsWith(' ')
// remove the leading and trailing space
const content = node.innerHTML.trim()
const prefix = hasLeadingSpace ? ' ==' : '=='
const postfix = hasTrailingSpace ? '== ' : '=='
return {
prefix: '==',
postfix: '==',
prefix,
postfix,
content,
}
},
}
@ -535,11 +609,24 @@ export const htmlToHighlightedMarkdown = (
html: string,
highlights?: Highlight[]
): string => {
if (!highlights) {
if (!highlights || highlights.length == 0) {
return nhm.translate(/* html */ html)
}
let document: Document
try {
document = parseHTML(html).document
if (!document || !document.documentElement) {
// the html is invalid
throw new Error('Invalid html content')
}
} catch (err) {
console.log(err)
return nhm.translate(/* html */ html)
}
const document = parseHTML(html).document
// wrap highlights in special tags
highlights
.filter((h) => h.type == 'HIGHLIGHT' && h.patch)
@ -551,7 +638,7 @@ export const htmlToHighlightedMarkdown = (
document
)
} catch (err) {
console.error(err)
console.log(err)
}
})
html = document.documentElement.outerHTML