tiptap: fix paste link

pull/82/head
fantasticit 2022-06-10 19:28:51 +08:00
parent 4340b3122d
commit d309d538f5
4 changed files with 57 additions and 14 deletions

View File

@ -73,6 +73,7 @@
"markdown-it-sup": "^1.0.0",
"next": "12.1.0",
"next-pwa": "^5.5.2",
"prosemirror-commands": "^1.3.0",
"prosemirror-markdown": "^1.7.0",
"prosemirror-model": "^1.16.1",
"prosemirror-schema-list": "^1.1.6",

View File

@ -1,5 +1,6 @@
import { Extension } from '@tiptap/core';
import { safeJSONParse } from 'helpers/json';
import { toggleMark } from 'prosemirror-commands';
import { Fragment, Schema } from 'prosemirror-model';
import { Plugin, PluginKey } from 'prosemirror-state';
import { EXTENSION_PRIORITY_HIGHEST } from 'tiptap/core/constants';
@ -9,6 +10,7 @@ import {
isInCode,
isMarkdown,
isTitleNode,
isValidURL,
LANGUAGES,
normalizeMarkdown,
} from 'tiptap/prose-utils';
@ -76,7 +78,9 @@ export const Paste = Extension.create<IPasteOptions>({
if (view.props.editable && !view.props.editable(view.state)) {
return false;
}
if (!event.clipboardData) return false;
// 文件
const files = Array.from(event.clipboardData.files);
if (files.length) {
@ -87,19 +91,39 @@ export const Paste = Extension.create<IPasteOptions>({
return true;
}
const { markdownToProsemirror } = extensionThis.options;
const text = event.clipboardData.getData('text/plain');
const html = event.clipboardData.getData('text/html');
const vscode = event.clipboardData.getData('vscode-editor-data');
const node = event.clipboardData.getData('text/node');
const markdownText = event.clipboardData.getData('text/markdown');
const { state, dispatch } = view;
const { markdownToProsemirror } = extensionThis.options;
// 直接复制节点
if (node) {
const doc = safeJSONParse(node);
const json = safeJSONParse(node);
const tr = view.state.tr;
const selection = tr.selection;
view.dispatch(tr.insert(selection.from - 1, view.state.schema.nodeFromJSON(doc)).scrollIntoView());
view.dispatch(tr.insert(selection.from - 1, view.state.schema.nodeFromJSON(json)).scrollIntoView());
return true;
}
// 链接
if (isValidURL(text)) {
if (!state.selection.empty) {
toggleMark(this.editor.schema.marks.link, { href: text })(state, dispatch);
return true;
}
const transaction = view.state.tr
.insertText(text, state.selection.from, state.selection.to)
.addMark(
state.selection.from,
state.selection.to + text.length,
state.schema.marks.link.create({ href: text })
);
view.dispatch(transaction);
return true;
}
@ -116,16 +140,21 @@ export const Paste = Extension.create<IPasteOptions>({
if (pasteCodeLanguage && pasteCodeLanguage !== 'markdown') {
event.preventDefault();
view.dispatch(
view.state.tr.replaceSelectionWith(
view.state.schema.nodes.codeBlock.create({
language: Object.keys(LANGUAGES).includes(vscodeMeta.mode) ? vscodeMeta.mode : null,
})
)
view.state.tr
.replaceSelectionWith(
view.state.schema.nodes.codeBlock.create({
language: Object.keys(LANGUAGES).includes(vscodeMeta.mode) ? vscodeMeta.mode : null,
})
)
.insertText(text)
);
view.dispatch(view.state.tr.insertText(text).scrollIntoView());
return true;
}
if (html?.includes('data-pm-slice')) {
return false;
}
// 处理 markdown
if (markdownText || isMarkdown(text) || html.length === 0 || pasteCodeLanguage === 'markdown') {
event.preventDefault();
@ -147,11 +176,13 @@ export const Paste = Extension.create<IPasteOptions>({
view.dispatch(tr.scrollIntoView());
return true;
}
if (text.length !== 0) {
event.preventDefault();
view.dispatch(view.state.tr.insertText(text));
return true;
}
return false;
},
handleDrop: (view, event: any) => {

View File

@ -1,3 +1,12 @@
export function isValidURL(str: string) {
return str && str.startsWith('http');
export function isValidURL(text: string) {
if (text.match(/\n/)) {
return false;
}
try {
const url = new URL(text);
return url.hostname !== '';
} catch (err) {
return false;
}
}

View File

@ -118,6 +118,7 @@ importers:
markdown-it-sup: ^1.0.0
next: 12.1.0
next-pwa: ^5.5.2
prosemirror-commands: ^1.3.0
prosemirror-markdown: ^1.7.0
prosemirror-model: ^1.16.1
prosemirror-schema-list: ^1.1.6
@ -209,6 +210,7 @@ importers:
markdown-it-sup: 1.0.0
next: 12.1.0_react-dom@17.0.2+react@17.0.2
next-pwa: 5.5.2_next@12.1.0
prosemirror-commands: 1.3.0
prosemirror-markdown: 1.7.0
prosemirror-model: 1.16.1
prosemirror-schema-list: 1.1.6
@ -2688,7 +2690,7 @@ packages:
'@types/prosemirror-state': 1.2.8
'@types/prosemirror-transform': 1.1.5
'@types/prosemirror-view': 1.23.1
prosemirror-commands: 1.2.1
prosemirror-commands: 1.3.0
prosemirror-keymap: 1.1.5
prosemirror-model: 1.16.1
prosemirror-schema-list: 1.1.6
@ -9143,8 +9145,8 @@ packages:
object-assign: 4.1.1
react-is: 16.13.1
/prosemirror-commands/1.2.1:
resolution: {integrity: sha512-S/IkpXfpuLFsRynC2HQ5iYROUPiZskKS1+ClcWycGJvj4HMb/mVfeEkQrixYxgTl96EAh+RZQNWPC06GZXk5tQ==}
/prosemirror-commands/1.3.0:
resolution: {integrity: sha512-BwBbZ5OAScPcm0x7H8SPbqjuEJnCU2RJT9LDyOiiIl/3NbL1nJZI4SFNHwU2e/tRr2Xe7JsptpzseqvZvToLBQ==}
dependencies:
prosemirror-model: 1.16.1
prosemirror-state: 1.3.4