Merge pull request #2207 from raizasafeel/fix/ui-teardown

feat(lesson): add support for html (heading, block code, list)
This commit is contained in:
Raizaaa
2026-03-16 21:34:47 +05:30
committed by GitHub
+88 -6
View File
@@ -70,6 +70,21 @@ export class Markdown {
if (!clipboardData) return
const pastedText = clipboardData.getData('text/plain')
const pastedHTML = clipboardData.getData('text/html')
const hasHTMLTags = (s) => /<(pre|h[1-6]|ul|ol)[\s>]/i.test(s)
const html =
(pastedText && hasHTMLTags(pastedText) && pastedText) ||
(pastedHTML && hasHTMLTags(pastedHTML) && pastedHTML)
if (html) {
event.preventDefault()
event.stopPropagation()
event.stopImmediatePropagation()
this._insertBlocks(this._parsePastedHTMLToBlocks(html))
return
}
if (pastedText && this._looksLikeMarkdown(pastedText)) {
event.preventDefault()
@@ -91,9 +106,7 @@ export class Markdown {
return markdownPatterns.some((pattern) => pattern.test(text))
}
async _insertMarkdownAsBlocks(markdown) {
const blocks = this._parseMarkdownToBlocks(markdown)
async _insertBlocks(blocks) {
if (blocks.length === 0) return
const currentIndex = this.api.blocks.getCurrentBlockIndex()
@@ -114,8 +127,8 @@ export class Markdown {
try {
await this.api.blocks.delete(currentIndex + blocks.length)
} catch (error) {
console.error('Failed to delete original block:', error)
} catch (e) {
// original block may already be gone
}
setTimeout(() => {
@@ -123,6 +136,10 @@ export class Markdown {
}, 100)
}
_insertMarkdownAsBlocks(markdown) {
this._insertBlocks(this._parseMarkdownToBlocks(markdown))
}
_parseMarkdownToBlocks(markdown) {
const lines = markdown.split('\n')
const blocks = []
@@ -291,7 +308,7 @@ export class Markdown {
block: {
type: 'codeBox',
data: {
code: codeLines.join('\n'),
code: escapeHTML(codeLines.join('\n')),
language: language || 'plaintext',
},
},
@@ -424,6 +441,71 @@ export class Markdown {
_isEmbed(text) {
return /^https?:\/\/.+/.test(text.trim())
}
_parsePastedHTMLToBlocks(html) {
const doc = new DOMParser().parseFromString(html, 'text/html')
const blocks = []
const walk = (node) => {
if (node.nodeType === Node.TEXT_NODE) {
const text = node.textContent.trim()
if (text)
blocks.push({
type: 'paragraph',
data: { text: escapeHTML(text) },
})
return
}
if (node.nodeType !== Node.ELEMENT_NODE) return
const tag = node.tagName
if (tag === 'PRE') {
blocks.push({
type: 'codeBox',
data: {
code: escapeHTML(node.textContent),
language: 'Auto-detect',
},
})
} else if (/^H[1-6]$/.test(tag)) {
blocks.push({
type: 'header',
data: {
text: escapeHTML(node.textContent.trim()),
level: +tag[1],
},
})
} else if (tag === 'UL' || tag === 'OL') {
const items = [...node.querySelectorAll(':scope > li')].map(
(li) => ({
content: escapeHTML(li.textContent.trim()),
items: [],
})
)
blocks.push({
type: 'list',
data: {
style: tag === 'UL' ? 'unordered' : 'ordered',
items,
},
})
} else if (node.childNodes.length) {
for (const child of node.childNodes) walk(child)
} else {
const text = node.textContent.trim()
if (text)
blocks.push({
type: 'paragraph',
data: { text: escapeHTML(text) },
})
}
}
for (const child of doc.body.childNodes) walk(child)
return blocks
}
}
export default Markdown