jjb-lc-designable
Version:
基于alibaba-designable源码二次封装的表单设计器。
186 lines (181 loc) • 6.83 kB
text/typescript
import {
Engine,
ClosestPosition,
CursorType,
CursorDragType,
TreeNode,
} from '../models'
import {
DragStartEvent,
DragMoveEvent,
DragStopEvent,
ViewportScrollEvent,
} from '../events'
import { Point } from 'jjb-lc-designable/shared'
export const useDragDropEffect = (engine: Engine) => {
engine.subscribeTo(DragStartEvent, (event) => {
if (engine.cursor.type !== CursorType.Normal) return
const target = event.data.target as HTMLElement
const el = target?.closest(`
*[${engine.props.nodeIdAttrName}],
*[${engine.props.sourceIdAttrName}],
*[${engine.props.outlineNodeIdAttrName}]
`)
const handler = target?.closest(
`*[${engine.props.nodeDragHandlerAttrName}]`
)
const helper = handler?.closest(
`*[${engine.props.nodeSelectionIdAttrName}]`
)
if (!el?.getAttribute && !handler) return
const sourceId = el?.getAttribute(engine.props.sourceIdAttrName)
const outlineId = el?.getAttribute(engine.props.outlineNodeIdAttrName)
const handlerId = helper?.getAttribute(engine.props.nodeSelectionIdAttrName)
const nodeId = el?.getAttribute(engine.props.nodeIdAttrName)
engine.workbench.eachWorkspace((currentWorkspace) => {
const operation = currentWorkspace.operation
const moveHelper = operation.moveHelper
if (nodeId || outlineId || handlerId) {
const node = engine.findNodeById(outlineId || nodeId || handlerId)
if (node) {
if (!node.allowDrag()) return
if (node === node.root) return
const validSelected = engine
.getAllSelectedNodes()
.filter((node) => node.allowDrag())
if (validSelected.some((selectNode) => selectNode === node)) {
moveHelper.dragStart({ dragNodes: TreeNode.sort(validSelected) })
} else {
moveHelper.dragStart({ dragNodes: [node] })
}
}
} else if (sourceId) {
const sourceNode = engine.findNodeById(sourceId)
if (sourceNode) {
moveHelper.dragStart({ dragNodes: [sourceNode] })
}
}
})
engine.cursor.setStyle('move')
})
engine.subscribeTo(DragMoveEvent, (event) => {
if (engine.cursor.type !== CursorType.Normal) return
if (engine.cursor.dragType !== CursorDragType.Move) return
const target = event.data.target as HTMLElement
const el = target?.closest(`
*[${engine.props.nodeIdAttrName}],
*[${engine.props.outlineNodeIdAttrName}]
`)
const point = new Point(event.data.topClientX, event.data.topClientY)
const nodeId = el?.getAttribute(engine.props.nodeIdAttrName)
const outlineId = el?.getAttribute(engine.props.outlineNodeIdAttrName)
engine.workbench.eachWorkspace((currentWorkspace) => {
const operation = currentWorkspace.operation
const moveHelper = operation.moveHelper
const dragNodes = moveHelper.dragNodes
const tree = operation.tree
if (!dragNodes.length) return
const touchNode = tree.findById(outlineId || nodeId)
moveHelper.dragMove({
point,
touchNode,
})
})
})
engine.subscribeTo(ViewportScrollEvent, (event) => {
if (engine.cursor.type !== CursorType.Normal) return
if (engine.cursor.dragType !== CursorDragType.Move) return
const point = new Point(
engine.cursor.position.topClientX,
engine.cursor.position.topClientY
)
const currentWorkspace =
event?.context?.workspace ?? engine.workbench.activeWorkspace
if (!currentWorkspace) return
const operation = currentWorkspace.operation
const moveHelper = operation.moveHelper
if (!moveHelper.dragNodes.length) return
const tree = operation.tree
const viewport = currentWorkspace.viewport
const outline = currentWorkspace.outline
const viewportTarget = viewport.elementFromPoint(point)
const outlineTarget = outline.elementFromPoint(point)
const viewportNodeElement = viewportTarget?.closest(`
*[${engine.props.nodeIdAttrName}],
*[${engine.props.outlineNodeIdAttrName}]
`)
const outlineNodeElement = outlineTarget?.closest(`
*[${engine.props.nodeIdAttrName}],
*[${engine.props.outlineNodeIdAttrName}]
`)
const nodeId = viewportNodeElement?.getAttribute(
engine.props.nodeIdAttrName
)
const outlineNodeId = outlineNodeElement?.getAttribute(
engine.props.outlineNodeIdAttrName
)
const touchNode = tree.findById(outlineNodeId || nodeId)
moveHelper.dragMove({ point, touchNode })
})
engine.subscribeTo(DragStopEvent, () => {
if (engine.cursor.type !== CursorType.Normal) return
if (engine.cursor.dragType !== CursorDragType.Move) return
engine.workbench.eachWorkspace((currentWorkspace) => {
const operation = currentWorkspace.operation
const moveHelper = operation.moveHelper
const dragNodes = moveHelper.dragNodes
const closestNode = moveHelper.closestNode
const closestDirection = moveHelper.closestDirection
const selection = operation.selection
if (!dragNodes.length) return
if (dragNodes.length && closestNode && closestDirection) {
if (
closestDirection === ClosestPosition.After ||
closestDirection === ClosestPosition.Under
) {
if (closestNode.allowSibling(dragNodes)) {
selection.batchSafeSelect(
closestNode.insertAfter(
...TreeNode.filterDroppable(dragNodes, closestNode.parent)
)
)
}
} else if (
closestDirection === ClosestPosition.Before ||
closestDirection === ClosestPosition.Upper
) {
if (closestNode.allowSibling(dragNodes)) {
selection.batchSafeSelect(
closestNode.insertBefore(
...TreeNode.filterDroppable(dragNodes, closestNode.parent)
)
)
}
} else if (
closestDirection === ClosestPosition.Inner ||
closestDirection === ClosestPosition.InnerAfter
) {
if (closestNode.allowAppend(dragNodes)) {
selection.batchSafeSelect(
closestNode.append(
...TreeNode.filterDroppable(dragNodes, closestNode)
)
)
moveHelper.dragDrop({ dropNode: closestNode })
}
} else if (closestDirection === ClosestPosition.InnerBefore) {
if (closestNode.allowAppend(dragNodes)) {
selection.batchSafeSelect(
closestNode.prepend(
...TreeNode.filterDroppable(dragNodes, closestNode)
)
)
moveHelper.dragDrop({ dropNode: closestNode })
}
}
}
moveHelper.dragEnd()
})
engine.cursor.setStyle('')
})
}