Custom paste event fails to render when copying from Office to rich text. #7526
Replies: 1 comment
-
|
I've solved it. After removing non-standard attributes from the HTML and returning to standard HTML format, I was able to insert the text editor. |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
-
After copying and pasting content from Office into the editor, it freezes. After debugging, I found that after the
handlePastefunction returnstrue, the browser displays "[Violation] 'paste' handler took 30104ms" and the page eventually freezes. I haven't found the cause. Could you help me locate the cause or explain how to fix it?env:"@tiptap/vue-3": "^3.6.5"
const isOfficeOrFile = html && html.trim() && (
/urn:schemas-microsoft-com/i.test(html) && /file:[/]+/i.test(html)
)
const stripLocalResourceRefs = (html: string): string => {
if (!/file:[/]+/i.test(html)) return html
const px = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'
return html
.replace(/\bsrc\s*=\s*["']file:[^"']["']/gi,
src="${px}").replace(/\bsrc\s=\sfile:[^\s>]/gi,
src="${px}").replace(/\bhref\s*=\s*["']file:[^"']["']/gi, 'href="#"')
.replace(/url\s(\s*["']?file:[^"')]["']?\s)/gi, 'url("")')
.replace(/file:///?[^\s"'<>)\]]+/gi, px)
}
const htmlToParseableDom = (html: string): HTMLElement => {
const wrapMap: Record<string, string[]> = {
thead: ['table'], tbody: ['table'], tfoot: ['table'], caption: ['table'],
colgroup: ['table'], col: ['table', 'colgroup'], tr: ['table', 'tbody'],
td: ['table', 'tbody', 'tr'], th: ['table', 'tbody', 'tr'],
}
const firstTag = /<([a-z][^>\s]+)/i.exec(html)
const wrap = firstTag && wrapMap[firstTag[1].toLowerCase()]
if (wrap) {
html = wrap.map(n =>
<${n}>).join('') + html + wrap.map(n =></${n}>).reverse().join('')}
const div = document.createElement('div')
div.innerHTML = html
if (wrap) {
const el = div.querySelector(wrap[0])
return (el as HTMLElement) || div
}
return div
}
const handlePaste = (e: ClipboardEvent): boolean => {
if (!editor.value || previewMode.value) return false
const isOfficeOrFile = html && html.trim() && (
/urn:schemas-microsoft-com/i.test(html) && /file:[/]+/i.test(html)
)
if (isOfficeOrFile) {
e.preventDefault()
e.stopPropagation()
const ed = editor.value
if (!ed) return true
try {
const htmlSafe = stripLocalResourceRefs(html)
const dom = htmlToParseableDom(htmlSafe)
const slice = DOMParser.fromSchema(ed.schema).parseSlice(dom, { preserveWhitespace: true })
ed.chain().focus().deleteSelection().insertContent(slice.content).run();
return true;
} catch (err) {
const textToInsert = (text || '').trim()
if (textToInsert) ed.chain().focus().deleteSelection().insertContent(textToInsert).run()
}
return true
}
}
new Editor({
extensions: [
editorProps: {
paste: (view, event) => {
const clipboardEvent = event as ClipboardEvent
if (clipboardEvent.clipboardData?.files?.length) return false
return handlePaste(clipboardEvent)
},
}]
})
Beta Was this translation helpful? Give feedback.
All reactions