improve dragable

This commit is contained in:
fantasticit 2022-12-21 16:54:42 +08:00
parent 87bccec882
commit d0411a03da
1 changed files with 50 additions and 5 deletions

View File

@ -1,8 +1,8 @@
import { Extension } from '@tiptap/core'; import { Extension } from '@tiptap/core';
import { Plugin, PluginKey, Selection } from 'prosemirror-state'; import { Plugin, PluginKey, Selection } from 'prosemirror-state';
import { NodeSelection } from 'prosemirror-state'; import { NodeSelection, TextSelection } from 'prosemirror-state';
import { __serializeForClipboard, EditorView } from 'prosemirror-view'; import { __serializeForClipboard, EditorView } from 'prosemirror-view';
import { ActiveNode, getNodeAtPos, removePossibleTable, selectRootNodeByDom } from 'tiptap/prose-utils'; import { ActiveNode, getNodeAtPos, removePossibleTable, safePos, selectRootNodeByDom } from 'tiptap/prose-utils';
export const DragablePluginKey = new PluginKey('dragable'); export const DragablePluginKey = new PluginKey('dragable');
@ -15,6 +15,7 @@ export const Dragable = Extension.create({
let activeNode: ActiveNode; let activeNode: ActiveNode;
let activeSelection: Selection; let activeSelection: Selection;
let dragging = false; let dragging = false;
let mouseleaveTimer = null;
const createDragHandleDOM = () => { const createDragHandleDOM = () => {
const dom = document.createElement('div'); const dom = document.createElement('div');
@ -51,6 +52,18 @@ export const Dragable = Extension.create({
showDragHandleDOM(); showDragHandleDOM();
}; };
const handleMouseEnter = () => {
if (!activeNode) return null;
clearTimeout(mouseleaveTimer);
showDragHandleDOM();
};
const handleMouseLeave = () => {
if (!activeNode) return null;
hideDragHandleDOM();
};
const handleMouseDown = () => { const handleMouseDown = () => {
if (!activeNode) return null; if (!activeNode) return null;
@ -75,13 +88,14 @@ export const Dragable = Extension.create({
const handleDragStart = (event) => { const handleDragStart = (event) => {
dragging = true; dragging = true;
if (event.dataTransfer && activeSelection) { if (event.dataTransfer && activeSelection) {
const brokenClipboardAPI = false;
const slice = activeSelection.content(); const slice = activeSelection.content();
event.dataTransfer.effectAllowed = 'copyMove'; event.dataTransfer.effectAllowed = 'copyMove';
const { dom, text } = __serializeForClipboard(editorView, slice); const { dom, text } = __serializeForClipboard(editorView, slice);
event.dataTransfer.clearData(); event.dataTransfer.clearData();
event.dataTransfer.setData(brokenClipboardAPI ? 'Text' : 'text/html', dom.innerHTML); event.dataTransfer.setData('text/html', dom.innerHTML);
if (!brokenClipboardAPI) event.dataTransfer.setData('text/plain', text); event.dataTransfer.setData('text/plain', text);
event.dataTransfer.setDragImage(activeNode?.el as any, 0, 0);
editorView.dragging = { editorView.dragging = {
slice, slice,
move: true, move: true,
@ -95,6 +109,8 @@ export const Dragable = Extension.create({
view: (view) => { view: (view) => {
if (view.editable) { if (view.editable) {
dragHandleDOM = createDragHandleDOM(); dragHandleDOM = createDragHandleDOM();
dragHandleDOM.addEventListener('mouseenter', handleMouseEnter);
dragHandleDOM.addEventListener('mouseleave', handleMouseLeave);
dragHandleDOM.addEventListener('mousedown', handleMouseDown); dragHandleDOM.addEventListener('mousedown', handleMouseDown);
dragHandleDOM.addEventListener('mouseup', handleMouseUp); dragHandleDOM.addEventListener('mouseup', handleMouseUp);
dragHandleDOM.addEventListener('dragstart', handleDragStart); dragHandleDOM.addEventListener('dragstart', handleDragStart);
@ -108,6 +124,8 @@ export const Dragable = Extension.create({
destroy: () => { destroy: () => {
if (!dragHandleDOM) return; if (!dragHandleDOM) return;
dragHandleDOM.removeEventListener('mouseenter', handleMouseEnter);
dragHandleDOM.removeEventListener('mouseleave', handleMouseLeave);
dragHandleDOM.removeEventListener('mousedown', handleMouseDown); dragHandleDOM.removeEventListener('mousedown', handleMouseDown);
dragHandleDOM.removeEventListener('mouseup', handleMouseUp); dragHandleDOM.removeEventListener('mouseup', handleMouseUp);
dragHandleDOM.removeEventListener('dragstart', handleDragStart); dragHandleDOM.removeEventListener('dragstart', handleDragStart);
@ -125,6 +143,26 @@ export const Dragable = Extension.create({
return true; return true;
} }
setTimeout(() => {
if (activeSelection) {
[
'ProseMirror-selectednode',
'ProseMirror-selectedblocknode-dragable',
'ProseMirror-selectedblocknode-normal',
].forEach((cls) => {
(view.dom as HTMLElement).querySelectorAll(`.${cls}`).forEach((dom) => dom.classList.remove(cls));
});
const noneSelection = new TextSelection(
view.state.doc.resolve(safePos(view.state, eventPos?.pos ?? 0))
);
view.dispatch(view.state.tr.setSelection(noneSelection));
this.editor.commands.blur();
activeSelection = null;
activeNode = null;
}
}, 100);
const $mouse = view.state.doc.resolve(eventPos.pos); const $mouse = view.state.doc.resolve(eventPos.pos);
/** /**
@ -196,6 +234,13 @@ export const Dragable = Extension.create({
renderDragHandleDOM(view, result.el); renderDragHandleDOM(view, result.el);
return false; return false;
}, },
mouseleave: () => {
clearTimeout(mouseleaveTimer);
mouseleaveTimer = setTimeout(() => {
hideDragHandleDOM();
}, 400);
return false;
},
keydown: () => { keydown: () => {
if (!editorView.editable || !dragHandleDOM) return false; if (!editorView.editable || !dragHandleDOM) return false;
hideDragHandleDOM(); hideDragHandleDOM();