Fix markdown link saving

This commit is contained in:
Justin Edmund 2025-06-12 02:07:12 -07:00
parent 996565f56b
commit d63574a09f
3 changed files with 9087 additions and 9172 deletions

4
package-lock.json generated
View file

@ -95,6 +95,10 @@
"typescript": "^5.5.3", "typescript": "^5.5.3",
"typescript-eslint": "^8.0.0-alpha.20", "typescript-eslint": "^8.0.0-alpha.20",
"vite": "^5.0.3" "vite": "^5.0.3"
},
"engines": {
"node": ">=20.0.0",
"npm": ">=10.0.0"
} }
}, },
"node_modules/@aarkue/tiptap-math-extension": { "node_modules/@aarkue/tiptap-math-extension": {

View file

@ -239,20 +239,21 @@
return true // Prevent default paste behavior return true // Prevent default paste behavior
} }
// Handle text paste - strip HTML formatting // Handle text paste - preserve links while stripping other formatting
const htmlData = clipboardData.getData('text/html') const htmlData = clipboardData.getData('text/html')
const plainText = clipboardData.getData('text/plain') const plainText = clipboardData.getData('text/plain')
if (htmlData && plainText) { if (htmlData && plainText) {
// If we have both HTML and plain text, use plain text to strip formatting
event.preventDefault() event.preventDefault()
// Use editor commands to insert text so all callbacks are triggered // Use editor commands to insert HTML content, but let Tiptap handle the parsing
// This will preserve links while stripping unwanted formatting based on editor config
const editorInstance = (view as any).editor const editorInstance = (view as any).editor
if (editorInstance) { if (editorInstance) {
editorInstance.chain().focus().insertContent(plainText).run() // Use pasteHTML to let Tiptap process the HTML and apply configured extensions
editorInstance.chain().focus().insertContent(htmlData, { parseOptions: { preserveWhitespace: false } }).run()
} else { } else {
// Fallback to manual transaction // Fallback to plain text if editor instance not available
const { state, dispatch } = view const { state, dispatch } = view
const { selection } = state const { selection } = state
const transaction = state.tr.insertText(plainText, selection.from, selection.to) const transaction = state.tr.insertText(plainText, selection.from, selection.to)

View file

@ -135,93 +135,6 @@
} }
} }
// Convert Tiptap format back to blocks format for saving
function convertTiptapToBlocks(tiptapContent: JSONContent): any {
if (!tiptapContent || !tiptapContent.content) {
return { blocks: [] }
}
const blocks = tiptapContent.content
.map((node: any) => {
switch (node.type) {
case 'paragraph':
const text = extractTextFromNode(node)
return text ? { type: 'paragraph', content: text } : null
case 'heading':
return {
type: 'heading',
level: node.attrs?.level || 1,
content: extractTextFromNode(node)
}
case 'bulletList':
return {
type: 'bulletList',
content:
node.content
?.map((item: any) => {
const itemText = extractTextFromNode(item.content?.[0])
return itemText
})
.filter(Boolean) || []
}
case 'orderedList':
return {
type: 'orderedList',
content:
node.content
?.map((item: any) => {
const itemText = extractTextFromNode(item.content?.[0])
return itemText
})
.filter(Boolean) || []
}
case 'blockquote':
return {
type: 'blockquote',
content: extractTextFromNode(node.content?.[0])
}
case 'codeBlock':
return {
type: 'codeBlock',
language: node.attrs?.language || '',
content: node.content?.[0]?.text || ''
}
case 'image':
return {
type: 'image',
src: node.attrs?.src || '',
alt: node.attrs?.alt || '',
caption: node.attrs?.title || ''
}
case 'horizontalRule':
return { type: 'hr' }
default:
// Skip unknown types
return null
}
})
.filter(Boolean)
return { blocks }
}
// Helper function to extract text from a node
function extractTextFromNode(node: any): string {
if (!node) return ''
if (node.text) return node.text
if (node.content && Array.isArray(node.content)) {
return node.content.map((n: any) => extractTextFromNode(n)).join('')
}
return ''
}
onMount(async () => { onMount(async () => {
// Wait a tick to ensure page params are loaded // Wait a tick to ensure page params are loaded
@ -310,11 +223,8 @@
saving = true saving = true
// Convert content to blocks format if it's in Tiptap format // Save content in native Tiptap format to preserve all formatting
let saveContent = content const saveContent = content
if (config?.showContent && content && content.type === 'doc') {
saveContent = convertTiptapToBlocks(content)
}
const postData = { const postData = {
title: config?.showTitle ? title : null, title: config?.showTitle ? title : null,