164 lines
4.7 KiB
JavaScript
164 lines
4.7 KiB
JavaScript
import { Extension } from '@tiptap/core'
|
|
import { NodeSelection, Plugin } from 'prosemirror-state'
|
|
import { serializeForClipboard } from 'prosemirror-view/src/clipboard'
|
|
|
|
function removeNode(node) {
|
|
node.parentNode.removeChild(node)
|
|
}
|
|
|
|
function absoluteRect(node) {
|
|
const data = node.getBoundingClientRect()
|
|
|
|
return {
|
|
top: data.top,
|
|
left: data.left,
|
|
width: data.width,
|
|
}
|
|
}
|
|
|
|
export default Extension.create({
|
|
addProseMirrorPlugins() {
|
|
function blockPosAtCoords(coords, view) {
|
|
const pos = view.posAtCoords(coords)
|
|
let node = view.domAtPos(pos.pos)
|
|
|
|
node = node.node
|
|
|
|
while (node && node.parentNode) {
|
|
if (node.parentNode?.classList?.contains('ProseMirror')) { // todo
|
|
break
|
|
}
|
|
|
|
node = node.parentNode
|
|
}
|
|
|
|
if (node && node.nodeType === 1) {
|
|
const desc = view.docView.nearestDesc(node, true)
|
|
|
|
if (!(!desc || desc === view.docView)) {
|
|
return desc.posBefore
|
|
}
|
|
}
|
|
return null
|
|
}
|
|
|
|
function dragStart(e, view) {
|
|
view.composing = true
|
|
|
|
if (!e.dataTransfer) {
|
|
return
|
|
}
|
|
|
|
const coords = { left: e.clientX + 50, top: e.clientY }
|
|
const pos = blockPosAtCoords(coords, view)
|
|
|
|
if (pos != null) {
|
|
view.dispatch(view.state.tr.setSelection(NodeSelection.create(view.state.doc, pos)))
|
|
|
|
const slice = view.state.selection.content()
|
|
|
|
// console.log({
|
|
// from: view.nodeDOM(view.state.selection.from),
|
|
// to: view.nodeDOM(view.state.selection.to),
|
|
// })
|
|
const { dom, text } = serializeForClipboard(view, slice)
|
|
|
|
e.dataTransfer.clearData()
|
|
e.dataTransfer.setData('text/html', dom.innerHTML)
|
|
e.dataTransfer.setData('text/plain', text)
|
|
|
|
const el = document.querySelector('.ProseMirror-selectednode')
|
|
e.dataTransfer?.setDragImage(el, 0, 0)
|
|
|
|
view.dragging = { slice, move: true }
|
|
}
|
|
}
|
|
|
|
let dropElement
|
|
const WIDTH = 28
|
|
|
|
return [
|
|
new Plugin({
|
|
view(editorView) {
|
|
const element = document.createElement('div')
|
|
|
|
element.draggable = 'true'
|
|
element.classList.add('global-drag-handle')
|
|
element.addEventListener('dragstart', e => dragStart(e, editorView))
|
|
dropElement = element
|
|
document.body.appendChild(dropElement)
|
|
|
|
return {
|
|
// update(view, prevState) {
|
|
// },
|
|
destroy() {
|
|
removeNode(dropElement)
|
|
dropElement = null
|
|
},
|
|
}
|
|
},
|
|
props: {
|
|
handleDrop(view, event, slice, moved) {
|
|
if (moved) {
|
|
// setTimeout(() => {
|
|
// console.log('remove selection')
|
|
// view.dispatch(view.state.tr.deleteSelection())
|
|
// }, 50)
|
|
}
|
|
},
|
|
// handlePaste() {
|
|
// alert(2)
|
|
// },
|
|
handleDOMEvents: {
|
|
// drop(view, event) {
|
|
// setTimeout(() => {
|
|
// const node = document.querySelector('.ProseMirror-hideselection')
|
|
// if (node) {
|
|
// node.classList.remove('ProseMirror-hideselection')
|
|
// }
|
|
// }, 50)
|
|
// },
|
|
mousemove(view, event) {
|
|
const coords = {
|
|
left: event.clientX + WIDTH + 50,
|
|
top: event.clientY,
|
|
}
|
|
const pos = view.posAtCoords(coords)
|
|
|
|
if (pos) {
|
|
let node = view.domAtPos(pos?.pos)
|
|
|
|
if (node) {
|
|
node = node.node
|
|
while (node && node.parentNode) {
|
|
if (node.parentNode?.classList?.contains('ProseMirror')) { // todo
|
|
break
|
|
}
|
|
node = node.parentNode
|
|
}
|
|
|
|
if (node instanceof Element) {
|
|
const cstyle = window.getComputedStyle(node)
|
|
const lineHeight = parseInt(cstyle.lineHeight, 10)
|
|
// const top = parseInt(cstyle.marginTop, 10) + parseInt(cstyle.paddingTop, 10)
|
|
const top = 0
|
|
const rect = absoluteRect(node)
|
|
const win = node.ownerDocument.defaultView
|
|
|
|
rect.top += win.pageYOffset + ((lineHeight - 24) / 2) + top
|
|
rect.left += win.pageXOffset
|
|
rect.width = `${WIDTH}px`
|
|
|
|
dropElement.style.left = `${-WIDTH + rect.left}px`
|
|
dropElement.style.top = `${rect.top}px`
|
|
}
|
|
}
|
|
}
|
|
},
|
|
},
|
|
},
|
|
}),
|
|
]
|
|
},
|
|
})
|