Fix markdown link saving
This commit is contained in:
parent
996565f56b
commit
d63574a09f
3 changed files with 9087 additions and 9172 deletions
4
package-lock.json
generated
4
package-lock.json
generated
|
|
@ -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": {
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue