feat:optimize event code structure
This commit is contained in:
@@ -1,81 +1,70 @@
|
|||||||
import { ElementType, IEditorOption } from '../..'
|
|
||||||
import { ZERO } from '../../dataset/constant/Common'
|
|
||||||
import { EDITOR_ELEMENT_COPY_ATTR } from '../../dataset/constant/Element'
|
|
||||||
import { ElementStyleKey } from '../../dataset/enum/ElementStyle'
|
import { ElementStyleKey } from '../../dataset/enum/ElementStyle'
|
||||||
import { MouseEventButton } from '../../dataset/enum/Event'
|
import { IElement, IElementPosition } from '../../interface/Element'
|
||||||
import { KeyMap } from '../../dataset/enum/KeyMap'
|
|
||||||
import { IElement } from '../../interface/Element'
|
|
||||||
import { ICurrentPosition } from '../../interface/Position'
|
import { ICurrentPosition } from '../../interface/Position'
|
||||||
import { writeElementList } from '../../utils/clipboard'
|
|
||||||
import { Cursor } from '../cursor/Cursor'
|
|
||||||
import { Draw } from '../draw/Draw'
|
import { Draw } from '../draw/Draw'
|
||||||
import { HyperlinkParticle } from '../draw/particle/HyperlinkParticle'
|
|
||||||
import { TableTool } from '../draw/particle/table/TableTool'
|
|
||||||
import { HistoryManager } from '../history/HistoryManager'
|
|
||||||
import { Listener } from '../listener/Listener'
|
|
||||||
import { Position } from '../position/Position'
|
import { Position } from '../position/Position'
|
||||||
import { RangeManager } from '../range/RangeManager'
|
import { RangeManager } from '../range/RangeManager'
|
||||||
import { LETTER_REG, NUMBER_LIKE_REG } from '../../dataset/constant/Regular'
|
import { threeClick } from '../../utils'
|
||||||
import { Control } from '../draw/control/Control'
|
import { IRange } from '../../interface/Range'
|
||||||
import { CheckboxControl } from '../draw/control/checkbox/CheckboxControl'
|
import { mousedown } from './handlers/mousedown'
|
||||||
import { findParent, splitText, threeClick } from '../../utils'
|
import { mouseup } from './handlers/mouseup'
|
||||||
import { Previewer } from '../draw/particle/previewer/Previewer'
|
import { mouseleave } from './handlers/mouseleave'
|
||||||
import { DeepRequired } from '../../interface/Common'
|
import { mousemove } from './handlers/mousemove'
|
||||||
import { DateParticle } from '../draw/particle/date/DateParticle'
|
import { keydown } from './handlers/keydown'
|
||||||
|
import { input } from './handlers/input'
|
||||||
|
import { cut } from './handlers/cut'
|
||||||
|
import { copy } from './handlers/copy'
|
||||||
|
import { drop } from './handlers/drop'
|
||||||
|
import click from './handlers/click'
|
||||||
|
import composition from './handlers/composition'
|
||||||
|
import drag from './handlers/drag'
|
||||||
|
|
||||||
export class CanvasEvent {
|
export class CanvasEvent {
|
||||||
|
|
||||||
private isAllowSelection: boolean
|
public isAllowSelection: boolean
|
||||||
private isCompositing: boolean
|
public isCompositing: boolean
|
||||||
private mouseDownStartPosition: ICurrentPosition | null
|
public isAllowDrag: boolean
|
||||||
|
public isAllowDrop: boolean
|
||||||
|
public cacheRange: IRange | null
|
||||||
|
public cacheElementList: IElement[] | null
|
||||||
|
public cachePositionList: IElementPosition[] | null
|
||||||
|
public mouseDownStartPosition: ICurrentPosition | null
|
||||||
|
|
||||||
private draw: Draw
|
private draw: Draw
|
||||||
private options: DeepRequired<IEditorOption>
|
|
||||||
private pageContainer: HTMLDivElement
|
private pageContainer: HTMLDivElement
|
||||||
private pageList: HTMLCanvasElement[]
|
private pageList: HTMLCanvasElement[]
|
||||||
private position: Position
|
|
||||||
private range: RangeManager
|
private range: RangeManager
|
||||||
private cursor: Cursor | null
|
private position: Position
|
||||||
private historyManager: HistoryManager
|
|
||||||
private previewer: Previewer
|
|
||||||
private tableTool: TableTool
|
|
||||||
private hyperlinkParticle: HyperlinkParticle
|
|
||||||
private dateParticle: DateParticle
|
|
||||||
private listener: Listener
|
|
||||||
private control: Control
|
|
||||||
|
|
||||||
constructor(draw: Draw) {
|
constructor(draw: Draw) {
|
||||||
this.isAllowSelection = false
|
this.draw = draw
|
||||||
this.isCompositing = false
|
|
||||||
this.mouseDownStartPosition = null
|
|
||||||
|
|
||||||
this.pageContainer = draw.getPageContainer()
|
this.pageContainer = draw.getPageContainer()
|
||||||
this.pageList = draw.getPageList()
|
this.pageList = draw.getPageList()
|
||||||
this.draw = draw
|
|
||||||
this.options = draw.getOptions()
|
|
||||||
this.cursor = null
|
|
||||||
this.position = this.draw.getPosition()
|
|
||||||
this.range = this.draw.getRange()
|
this.range = this.draw.getRange()
|
||||||
this.historyManager = this.draw.getHistoryManager()
|
this.position = this.draw.getPosition()
|
||||||
this.previewer = this.draw.getPreviewer()
|
|
||||||
this.tableTool = this.draw.getTableTool()
|
this.isAllowSelection = false
|
||||||
this.hyperlinkParticle = this.draw.getHyperlinkParticle()
|
this.isCompositing = false
|
||||||
this.dateParticle = this.draw.getDateParticle()
|
this.isAllowDrag = false
|
||||||
this.listener = this.draw.getListener()
|
this.isAllowDrop = false
|
||||||
this.control = this.draw.getControl()
|
this.cacheRange = null
|
||||||
|
this.cacheElementList = null
|
||||||
|
this.cachePositionList = null
|
||||||
|
this.mouseDownStartPosition = null
|
||||||
|
}
|
||||||
|
|
||||||
|
public getDraw(): Draw {
|
||||||
|
return this.draw
|
||||||
}
|
}
|
||||||
|
|
||||||
public register() {
|
public register() {
|
||||||
// 延迟加载
|
|
||||||
this.cursor = this.draw.getCursor()
|
|
||||||
this.pageContainer.addEventListener('mousedown', this.mousedown.bind(this))
|
this.pageContainer.addEventListener('mousedown', this.mousedown.bind(this))
|
||||||
|
this.pageContainer.addEventListener('mouseup', this.mouseup.bind(this))
|
||||||
this.pageContainer.addEventListener('mouseleave', this.mouseleave.bind(this))
|
this.pageContainer.addEventListener('mouseleave', this.mouseleave.bind(this))
|
||||||
this.pageContainer.addEventListener('mousemove', this.mousemove.bind(this))
|
this.pageContainer.addEventListener('mousemove', this.mousemove.bind(this))
|
||||||
this.pageContainer.addEventListener('dblclick', this.dblclick.bind(this))
|
this.pageContainer.addEventListener('dblclick', this.dblclick.bind(this))
|
||||||
|
|
||||||
this.pageContainer.addEventListener('dragover', this.dragover.bind(this))
|
this.pageContainer.addEventListener('dragover', this.dragover.bind(this))
|
||||||
this.pageContainer.addEventListener('drop', this.drop.bind(this))
|
this.pageContainer.addEventListener('drop', this.drop.bind(this))
|
||||||
|
|
||||||
threeClick(this.pageContainer, this.threeClick.bind(this))
|
threeClick(this.pageContainer, this.threeClick.bind(this))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,6 +75,11 @@ export class CanvasEvent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public setIsAllowDrag(payload: boolean) {
|
||||||
|
this.isAllowDrag = payload
|
||||||
|
this.isAllowDrop = payload
|
||||||
|
}
|
||||||
|
|
||||||
public clearPainterStyle() {
|
public clearPainterStyle() {
|
||||||
this.pageList.forEach(p => {
|
this.pageList.forEach(p => {
|
||||||
p.style.cursor = 'text'
|
p.style.cursor = 'text'
|
||||||
@@ -113,538 +107,6 @@ export class CanvasEvent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public mousemove(evt: MouseEvent) {
|
|
||||||
if (!this.isAllowSelection || !this.mouseDownStartPosition) return
|
|
||||||
const target = evt.target as HTMLDivElement
|
|
||||||
const pageIndex = target.dataset.index
|
|
||||||
// 设置pageNo
|
|
||||||
if (pageIndex) {
|
|
||||||
this.draw.setPageNo(Number(pageIndex))
|
|
||||||
}
|
|
||||||
// 结束位置
|
|
||||||
const positionResult = this.position.getPositionByXY({
|
|
||||||
x: evt.offsetX,
|
|
||||||
y: evt.offsetY
|
|
||||||
})
|
|
||||||
const {
|
|
||||||
index,
|
|
||||||
isTable,
|
|
||||||
tdValueIndex,
|
|
||||||
tdIndex,
|
|
||||||
trIndex,
|
|
||||||
tableId
|
|
||||||
} = positionResult
|
|
||||||
const {
|
|
||||||
index: startIndex,
|
|
||||||
isTable: startIsTable,
|
|
||||||
tdIndex: startTdIndex,
|
|
||||||
trIndex: startTrIndex
|
|
||||||
} = this.mouseDownStartPosition
|
|
||||||
const endIndex = isTable ? tdValueIndex! : index
|
|
||||||
// 判断是否是表格跨行/列
|
|
||||||
if (isTable && startIsTable && (tdIndex !== startTdIndex || trIndex !== startTrIndex)) {
|
|
||||||
this.range.setRange(
|
|
||||||
endIndex,
|
|
||||||
endIndex,
|
|
||||||
tableId,
|
|
||||||
startTdIndex,
|
|
||||||
tdIndex,
|
|
||||||
startTrIndex,
|
|
||||||
trIndex
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
let end = ~endIndex ? endIndex : 0
|
|
||||||
// 开始位置
|
|
||||||
let start = startIndex
|
|
||||||
if (start > end) {
|
|
||||||
[start, end] = [end, start]
|
|
||||||
}
|
|
||||||
if (start === end) return
|
|
||||||
this.range.setRange(start, end)
|
|
||||||
}
|
|
||||||
// 绘制
|
|
||||||
this.draw.render({
|
|
||||||
isSubmitHistory: false,
|
|
||||||
isSetCursor: false,
|
|
||||||
isComputeRowList: false
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
public mousedown(evt: MouseEvent) {
|
|
||||||
if (evt.button === MouseEventButton.RIGHT) return
|
|
||||||
const isReadonly = this.draw.isReadonly()
|
|
||||||
const target = evt.target as HTMLDivElement
|
|
||||||
const pageIndex = target.dataset.index
|
|
||||||
// 设置pageNo
|
|
||||||
if (pageIndex) {
|
|
||||||
this.draw.setPageNo(Number(pageIndex))
|
|
||||||
}
|
|
||||||
this.isAllowSelection = true
|
|
||||||
const positionResult = this.position.adjustPositionContext({
|
|
||||||
x: evt.offsetX,
|
|
||||||
y: evt.offsetY
|
|
||||||
})
|
|
||||||
const {
|
|
||||||
index,
|
|
||||||
isDirectHit,
|
|
||||||
isCheckbox,
|
|
||||||
isImage,
|
|
||||||
isTable,
|
|
||||||
tdValueIndex,
|
|
||||||
} = positionResult
|
|
||||||
// 记录选区开始位置
|
|
||||||
this.mouseDownStartPosition = {
|
|
||||||
...positionResult,
|
|
||||||
index: isTable ? tdValueIndex! : index
|
|
||||||
}
|
|
||||||
const elementList = this.draw.getElementList()
|
|
||||||
const positionList = this.position.getPositionList()
|
|
||||||
const curIndex = isTable ? tdValueIndex! : index
|
|
||||||
const curElement = elementList[curIndex]
|
|
||||||
// 绘制
|
|
||||||
const isDirectHitImage = !!(isDirectHit && isImage)
|
|
||||||
const isDirectHitCheckbox = !!(isDirectHit && isCheckbox)
|
|
||||||
if (~index) {
|
|
||||||
this.range.setRange(curIndex, curIndex)
|
|
||||||
this.position.setCursorPosition(positionList[curIndex])
|
|
||||||
// 复选框
|
|
||||||
const isSetCheckbox = isDirectHitCheckbox && !isReadonly
|
|
||||||
if (isSetCheckbox) {
|
|
||||||
const { checkbox } = curElement
|
|
||||||
if (checkbox) {
|
|
||||||
checkbox.value = !checkbox.value
|
|
||||||
} else {
|
|
||||||
curElement.checkbox = {
|
|
||||||
value: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const activeControl = this.control.getActiveControl()
|
|
||||||
if (activeControl instanceof CheckboxControl) {
|
|
||||||
activeControl.setSelect()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.draw.render({
|
|
||||||
curIndex,
|
|
||||||
isSubmitHistory: isSetCheckbox,
|
|
||||||
isSetCursor: !isDirectHitImage && !isDirectHitCheckbox,
|
|
||||||
isComputeRowList: false
|
|
||||||
})
|
|
||||||
}
|
|
||||||
// 预览工具组件
|
|
||||||
this.previewer.clearResizer()
|
|
||||||
if (isDirectHitImage && !isReadonly) {
|
|
||||||
this.previewer.drawResizer(curElement, positionList[curIndex],
|
|
||||||
curElement.type === ElementType.LATEX
|
|
||||||
? {
|
|
||||||
mime: 'svg',
|
|
||||||
srcKey: 'laTexSVG'
|
|
||||||
}
|
|
||||||
: {})
|
|
||||||
}
|
|
||||||
// 表格工具组件
|
|
||||||
this.tableTool.dispose()
|
|
||||||
if (isTable && !isReadonly) {
|
|
||||||
const originalElementList = this.draw.getOriginalElementList()
|
|
||||||
const originalPositionList = this.position.getOriginalPositionList()
|
|
||||||
this.tableTool.render(originalElementList[index], originalPositionList[index])
|
|
||||||
}
|
|
||||||
// 超链接
|
|
||||||
this.hyperlinkParticle.clearHyperlinkPopup()
|
|
||||||
if (curElement.type === ElementType.HYPERLINK) {
|
|
||||||
this.hyperlinkParticle.drawHyperlinkPopup(curElement, positionList[curIndex])
|
|
||||||
}
|
|
||||||
// 日期控件
|
|
||||||
this.dateParticle.clearDatePicker()
|
|
||||||
if (curElement.type === ElementType.DATE && !isReadonly) {
|
|
||||||
this.dateParticle.renderDatePicker(curElement, positionList[curIndex])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public mouseleave(evt: MouseEvent) {
|
|
||||||
// 是否还在canvas内部
|
|
||||||
const { x, y, width, height } = this.pageContainer.getBoundingClientRect()
|
|
||||||
if (evt.x >= x && evt.x <= x + width && evt.y >= y && evt.y <= y + height) return
|
|
||||||
this.setIsAllowSelection(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
public keydown(evt: KeyboardEvent) {
|
|
||||||
const isReadonly = this.draw.isReadonly()
|
|
||||||
const cursorPosition = this.position.getCursorPosition()
|
|
||||||
if (!cursorPosition) return
|
|
||||||
const elementList = this.draw.getElementList()
|
|
||||||
const position = this.position.getPositionList()
|
|
||||||
const { index } = cursorPosition
|
|
||||||
const { startIndex, endIndex } = this.range.getRange()
|
|
||||||
const isCollapsed = startIndex === endIndex
|
|
||||||
// 当前激活控件
|
|
||||||
const isPartRangeInControlOutside = this.control.isPartRangeInControlOutside()
|
|
||||||
const activeControl = this.control.getActiveControl()
|
|
||||||
if (evt.key === KeyMap.Backspace) {
|
|
||||||
if (isReadonly || isPartRangeInControlOutside) return
|
|
||||||
let curIndex: number
|
|
||||||
if (activeControl) {
|
|
||||||
curIndex = this.control.keydown(evt)
|
|
||||||
} else {
|
|
||||||
// 判断是否允许删除
|
|
||||||
if (isCollapsed && elementList[index].value === ZERO && index === 0) {
|
|
||||||
evt.preventDefault()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (!isCollapsed) {
|
|
||||||
elementList.splice(startIndex + 1, endIndex - startIndex)
|
|
||||||
} else {
|
|
||||||
elementList.splice(index, 1)
|
|
||||||
}
|
|
||||||
curIndex = isCollapsed ? index - 1 : startIndex
|
|
||||||
}
|
|
||||||
this.range.setRange(curIndex, curIndex)
|
|
||||||
this.draw.render({ curIndex })
|
|
||||||
} else if (evt.key === KeyMap.Delete) {
|
|
||||||
if (isReadonly || isPartRangeInControlOutside) return
|
|
||||||
let curIndex: number
|
|
||||||
if (activeControl) {
|
|
||||||
curIndex = this.control.keydown(evt)
|
|
||||||
} else if (elementList[endIndex + 1]?.type === ElementType.CONTROL) {
|
|
||||||
curIndex = this.control.removeControl(endIndex + 1)
|
|
||||||
} else {
|
|
||||||
if (!isCollapsed) {
|
|
||||||
elementList.splice(startIndex + 1, endIndex - startIndex)
|
|
||||||
} else {
|
|
||||||
elementList.splice(index + 1, 1)
|
|
||||||
}
|
|
||||||
curIndex = isCollapsed ? index : startIndex
|
|
||||||
}
|
|
||||||
this.range.setRange(curIndex, curIndex)
|
|
||||||
this.draw.render({ curIndex })
|
|
||||||
} else if (evt.key === KeyMap.Enter) {
|
|
||||||
if (isReadonly || isPartRangeInControlOutside) return
|
|
||||||
// 表格需要上下文信息
|
|
||||||
const positionContext = this.position.getPositionContext()
|
|
||||||
let restArg = {}
|
|
||||||
if (positionContext.isTable) {
|
|
||||||
const { tdId, trId, tableId } = positionContext
|
|
||||||
restArg = { tdId, trId, tableId }
|
|
||||||
}
|
|
||||||
const enterText: IElement = {
|
|
||||||
value: ZERO,
|
|
||||||
...restArg
|
|
||||||
}
|
|
||||||
let curIndex: number
|
|
||||||
if (activeControl) {
|
|
||||||
curIndex = this.control.setValue([enterText])
|
|
||||||
} else {
|
|
||||||
if (isCollapsed) {
|
|
||||||
elementList.splice(index + 1, 0, enterText)
|
|
||||||
} else {
|
|
||||||
elementList.splice(startIndex + 1, endIndex - startIndex, enterText)
|
|
||||||
}
|
|
||||||
curIndex = index + 1
|
|
||||||
}
|
|
||||||
this.range.setRange(curIndex, curIndex)
|
|
||||||
this.draw.render({ curIndex })
|
|
||||||
evt.preventDefault()
|
|
||||||
} else if (evt.key === KeyMap.Left) {
|
|
||||||
if (isReadonly) return
|
|
||||||
if (index > 0) {
|
|
||||||
const curIndex = index - 1
|
|
||||||
this.range.setRange(curIndex, curIndex)
|
|
||||||
this.draw.render({
|
|
||||||
curIndex,
|
|
||||||
isSubmitHistory: false,
|
|
||||||
isComputeRowList: false
|
|
||||||
})
|
|
||||||
}
|
|
||||||
} else if (evt.key === KeyMap.Right) {
|
|
||||||
if (isReadonly) return
|
|
||||||
if (index < position.length - 1) {
|
|
||||||
const curIndex = index + 1
|
|
||||||
this.range.setRange(curIndex, curIndex)
|
|
||||||
this.draw.render({
|
|
||||||
curIndex,
|
|
||||||
isSubmitHistory: false,
|
|
||||||
isComputeRowList: false
|
|
||||||
})
|
|
||||||
}
|
|
||||||
} else if (evt.key === KeyMap.Up || evt.key === KeyMap.Down) {
|
|
||||||
if (isReadonly) return
|
|
||||||
const { rowNo, index, coordinate: { leftTop, rightTop } } = cursorPosition
|
|
||||||
if ((evt.key === KeyMap.Up && rowNo !== 0) || (evt.key === KeyMap.Down && rowNo !== this.draw.getRowCount())) {
|
|
||||||
// 下一个光标点所在行位置集合
|
|
||||||
const probablePosition = evt.key === KeyMap.Up
|
|
||||||
? position.slice(0, index).filter(p => p.rowNo === rowNo - 1)
|
|
||||||
: position.slice(index, position.length - 1).filter(p => p.rowNo === rowNo + 1)
|
|
||||||
// 查找与当前位置元素点交叉最多的位置
|
|
||||||
let maxIndex = 0
|
|
||||||
let maxDistance = 0
|
|
||||||
for (let p = 0; p < probablePosition.length; p++) {
|
|
||||||
const position = probablePosition[p]
|
|
||||||
// 当前光标在前
|
|
||||||
if (position.coordinate.leftTop[0] >= leftTop[0] && position.coordinate.leftTop[0] <= rightTop[0]) {
|
|
||||||
const curDistance = rightTop[0] - position.coordinate.leftTop[0]
|
|
||||||
if (curDistance > maxDistance) {
|
|
||||||
maxIndex = position.index
|
|
||||||
maxDistance = curDistance
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 当前光标在后
|
|
||||||
else if (position.coordinate.leftTop[0] <= leftTop[0] && position.coordinate.rightTop[0] >= leftTop[0]) {
|
|
||||||
const curDistance = position.coordinate.rightTop[0] - leftTop[0]
|
|
||||||
if (curDistance > maxDistance) {
|
|
||||||
maxIndex = position.index
|
|
||||||
maxDistance = curDistance
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 匹配不到
|
|
||||||
if (p === probablePosition.length - 1 && maxIndex === 0) {
|
|
||||||
maxIndex = position.index
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const curIndex = maxIndex
|
|
||||||
this.range.setRange(curIndex, curIndex)
|
|
||||||
this.draw.render({
|
|
||||||
curIndex,
|
|
||||||
isSubmitHistory: false,
|
|
||||||
isComputeRowList: false
|
|
||||||
})
|
|
||||||
}
|
|
||||||
} else if (evt.ctrlKey && evt.key === KeyMap.Z) {
|
|
||||||
if (isReadonly) return
|
|
||||||
this.historyManager.undo()
|
|
||||||
evt.preventDefault()
|
|
||||||
} else if (evt.ctrlKey && evt.key === KeyMap.Y) {
|
|
||||||
if (isReadonly) return
|
|
||||||
this.historyManager.redo()
|
|
||||||
evt.preventDefault()
|
|
||||||
} else if (evt.ctrlKey && evt.key === KeyMap.C) {
|
|
||||||
this.copy()
|
|
||||||
evt.preventDefault()
|
|
||||||
} else if (evt.ctrlKey && evt.key === KeyMap.X) {
|
|
||||||
this.cut()
|
|
||||||
evt.preventDefault()
|
|
||||||
} else if (evt.ctrlKey && evt.key === KeyMap.A) {
|
|
||||||
this.selectAll()
|
|
||||||
evt.preventDefault()
|
|
||||||
} else if (evt.ctrlKey && evt.key === KeyMap.S) {
|
|
||||||
if (isReadonly) return
|
|
||||||
if (this.listener.saved) {
|
|
||||||
this.listener.saved(this.draw.getValue())
|
|
||||||
}
|
|
||||||
evt.preventDefault()
|
|
||||||
} else if (evt.key === KeyMap.ESC) {
|
|
||||||
this.clearPainterStyle()
|
|
||||||
evt.preventDefault()
|
|
||||||
} else if (evt.key === KeyMap.TAB) {
|
|
||||||
this.draw.insertElementList([{
|
|
||||||
type: ElementType.TAB,
|
|
||||||
value: ''
|
|
||||||
}])
|
|
||||||
evt.preventDefault()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public dblclick() {
|
|
||||||
const cursorPosition = this.position.getCursorPosition()
|
|
||||||
if (!cursorPosition) return
|
|
||||||
const { value, index } = cursorPosition
|
|
||||||
const elementList = this.draw.getElementList()
|
|
||||||
// 判断是否是数字或英文
|
|
||||||
let upCount = 0
|
|
||||||
let downCount = 0
|
|
||||||
const isNumber = NUMBER_LIKE_REG.test(value)
|
|
||||||
if (isNumber || LETTER_REG.test(value)) {
|
|
||||||
// 向上查询
|
|
||||||
let upStartIndex = index - 1
|
|
||||||
while (upStartIndex > 0) {
|
|
||||||
const value = elementList[upStartIndex].value
|
|
||||||
if ((isNumber && NUMBER_LIKE_REG.test(value)) || (!isNumber && LETTER_REG.test(value))) {
|
|
||||||
upCount++
|
|
||||||
upStartIndex--
|
|
||||||
} else {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 向下查询
|
|
||||||
let downStartIndex = index + 1
|
|
||||||
while (downStartIndex < elementList.length) {
|
|
||||||
const value = elementList[downStartIndex].value
|
|
||||||
if ((isNumber && NUMBER_LIKE_REG.test(value)) || (!isNumber && LETTER_REG.test(value))) {
|
|
||||||
downCount++
|
|
||||||
downStartIndex++
|
|
||||||
} else {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 设置选中区域
|
|
||||||
this.range.setRange(index - upCount - 1, index + downCount)
|
|
||||||
// 刷新文档
|
|
||||||
this.draw.render({
|
|
||||||
isSubmitHistory: false,
|
|
||||||
isSetCursor: false,
|
|
||||||
isComputeRowList: false
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
public threeClick() {
|
|
||||||
const cursorPosition = this.position.getCursorPosition()
|
|
||||||
if (!cursorPosition) return
|
|
||||||
const { index } = cursorPosition
|
|
||||||
const elementList = this.draw.getElementList()
|
|
||||||
// 判断是否是零宽字符
|
|
||||||
let upCount = 0
|
|
||||||
let downCount = 0
|
|
||||||
// 向上查询
|
|
||||||
let upStartIndex = index - 1
|
|
||||||
while (upStartIndex > 0) {
|
|
||||||
const value = elementList[upStartIndex].value
|
|
||||||
if (value !== ZERO) {
|
|
||||||
upCount++
|
|
||||||
upStartIndex--
|
|
||||||
} else {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 向下查询
|
|
||||||
let downStartIndex = index + 1
|
|
||||||
while (downStartIndex < elementList.length) {
|
|
||||||
const value = elementList[downStartIndex].value
|
|
||||||
if (value !== ZERO) {
|
|
||||||
downCount++
|
|
||||||
downStartIndex++
|
|
||||||
} else {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 设置选中区域
|
|
||||||
this.range.setRange(index - upCount - 1, index + downCount)
|
|
||||||
// 刷新文档
|
|
||||||
this.draw.render({
|
|
||||||
isSubmitHistory: false,
|
|
||||||
isSetCursor: false,
|
|
||||||
isComputeRowList: false
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
public input(data: string) {
|
|
||||||
const isReadonly = this.draw.isReadonly()
|
|
||||||
if (isReadonly) return
|
|
||||||
if (!this.cursor) return
|
|
||||||
const cursorPosition = this.position.getCursorPosition()
|
|
||||||
if (!data || !cursorPosition || this.isCompositing) return
|
|
||||||
if (this.control.isPartRangeInControlOutside()) {
|
|
||||||
// 忽略选区部分在控件的输入
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const activeControl = this.control.getActiveControl()
|
|
||||||
const { TEXT, HYPERLINK, SUBSCRIPT, SUPERSCRIPT, DATE } = ElementType
|
|
||||||
const text = data.replaceAll(`\n`, ZERO)
|
|
||||||
const elementList = this.draw.getElementList()
|
|
||||||
const agentDom = this.cursor.getAgentDom()
|
|
||||||
agentDom.value = ''
|
|
||||||
const { index } = cursorPosition
|
|
||||||
const { startIndex, endIndex } = this.range.getRange()
|
|
||||||
const isCollapsed = startIndex === endIndex
|
|
||||||
// 表格需要上下文信息
|
|
||||||
const positionContext = this.position.getPositionContext()
|
|
||||||
let restArg = {}
|
|
||||||
if (positionContext.isTable) {
|
|
||||||
const { tdId, trId, tableId } = positionContext
|
|
||||||
restArg = { tdId, trId, tableId }
|
|
||||||
}
|
|
||||||
const element = elementList[endIndex]
|
|
||||||
const inputData: IElement[] = splitText(text).map(value => {
|
|
||||||
const newElement: IElement = {
|
|
||||||
value,
|
|
||||||
...restArg
|
|
||||||
}
|
|
||||||
const nextElement = elementList[endIndex + 1]
|
|
||||||
if (
|
|
||||||
element.type === TEXT
|
|
||||||
|| (!element.type && element.value !== ZERO)
|
|
||||||
|| (element.type === HYPERLINK && nextElement?.type === HYPERLINK)
|
|
||||||
|| (element.type === DATE && nextElement?.type === DATE)
|
|
||||||
|| (element.type === SUBSCRIPT && nextElement?.type === SUBSCRIPT)
|
|
||||||
|| (element.type === SUPERSCRIPT && nextElement?.type === SUPERSCRIPT)
|
|
||||||
) {
|
|
||||||
EDITOR_ELEMENT_COPY_ATTR.forEach(attr => {
|
|
||||||
const value = element[attr] as never
|
|
||||||
if (value !== undefined) {
|
|
||||||
newElement[attr] = value
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return newElement
|
|
||||||
})
|
|
||||||
// 控件-移除placeholder
|
|
||||||
let curIndex: number
|
|
||||||
if (activeControl && elementList[endIndex + 1]?.controlId === element.controlId) {
|
|
||||||
curIndex = this.control.setValue(inputData)
|
|
||||||
} else {
|
|
||||||
let start = 0
|
|
||||||
if (isCollapsed) {
|
|
||||||
start = index + 1
|
|
||||||
} else {
|
|
||||||
start = startIndex + 1
|
|
||||||
elementList.splice(startIndex + 1, endIndex - startIndex)
|
|
||||||
}
|
|
||||||
// 禁止直接使用解构存在性能问题
|
|
||||||
for (let i = 0; i < inputData.length; i++) {
|
|
||||||
elementList.splice(start + i, 0, inputData[i])
|
|
||||||
}
|
|
||||||
curIndex = (isCollapsed ? index : startIndex) + inputData.length
|
|
||||||
}
|
|
||||||
this.range.setRange(curIndex, curIndex)
|
|
||||||
this.draw.render({ curIndex })
|
|
||||||
}
|
|
||||||
|
|
||||||
public cut() {
|
|
||||||
const { startIndex, endIndex } = this.range.getRange()
|
|
||||||
if (!~startIndex && !~startIndex) return
|
|
||||||
const isReadonly = this.draw.isReadonly()
|
|
||||||
if (isReadonly) return
|
|
||||||
const isPartRangeInControlOutside = this.control.isPartRangeInControlOutside()
|
|
||||||
if (isPartRangeInControlOutside) return
|
|
||||||
const activeControl = this.control.getActiveControl()
|
|
||||||
const elementList = this.draw.getElementList()
|
|
||||||
let start = startIndex
|
|
||||||
let end = endIndex
|
|
||||||
// 无选区则剪切一行
|
|
||||||
if (startIndex === endIndex) {
|
|
||||||
const positionList = this.position.getPositionList()
|
|
||||||
const curRowNo = positionList[startIndex].rowNo
|
|
||||||
const cutElementIndexList: number[] = []
|
|
||||||
for (let p = 0; p < positionList.length; p++) {
|
|
||||||
const position = positionList[p]
|
|
||||||
if (position.rowNo > curRowNo) break
|
|
||||||
if (position.rowNo === curRowNo) {
|
|
||||||
cutElementIndexList.push(p)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const firstElementIndex = cutElementIndexList[0] - 1
|
|
||||||
start = firstElementIndex < 0 ? 0 : firstElementIndex
|
|
||||||
end = cutElementIndexList[cutElementIndexList.length - 1]
|
|
||||||
}
|
|
||||||
// 写入粘贴板
|
|
||||||
writeElementList(elementList.slice(start + 1, end + 1), this.options)
|
|
||||||
let curIndex: number
|
|
||||||
if (activeControl) {
|
|
||||||
curIndex = this.control.cut()
|
|
||||||
} else {
|
|
||||||
elementList.splice(start + 1, end - start)
|
|
||||||
curIndex = start
|
|
||||||
}
|
|
||||||
this.range.setRange(curIndex, curIndex)
|
|
||||||
this.draw.render({ curIndex })
|
|
||||||
}
|
|
||||||
|
|
||||||
public copy() {
|
|
||||||
const { startIndex, endIndex } = this.range.getRange()
|
|
||||||
const elementList = this.draw.getElementList()
|
|
||||||
if (startIndex !== endIndex) {
|
|
||||||
writeElementList(elementList.slice(startIndex + 1, endIndex + 1), this.options)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public selectAll() {
|
public selectAll() {
|
||||||
const position = this.position.getPositionList()
|
const position = this.position.getPositionList()
|
||||||
this.range.setRange(0, position.length - 1)
|
this.range.setRange(0, position.length - 1)
|
||||||
@@ -655,51 +117,60 @@ export class CanvasEvent {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public mousemove(evt: MouseEvent) {
|
||||||
|
mousemove(evt, this)
|
||||||
|
}
|
||||||
|
|
||||||
|
public mousedown(evt: MouseEvent) {
|
||||||
|
mousedown(evt, this)
|
||||||
|
}
|
||||||
|
|
||||||
|
public mouseup(evt: MouseEvent) {
|
||||||
|
mouseup(evt, this)
|
||||||
|
}
|
||||||
|
|
||||||
|
public mouseleave(evt: MouseEvent) {
|
||||||
|
mouseleave(evt, this)
|
||||||
|
}
|
||||||
|
|
||||||
|
public keydown(evt: KeyboardEvent) {
|
||||||
|
keydown(evt, this)
|
||||||
|
}
|
||||||
|
|
||||||
|
public dblclick() {
|
||||||
|
click.dblclick(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
public threeClick() {
|
||||||
|
click.threeClick(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
public input(data: string) {
|
||||||
|
input(data, this)
|
||||||
|
}
|
||||||
|
|
||||||
|
public cut() {
|
||||||
|
cut(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
public copy() {
|
||||||
|
copy(this)
|
||||||
|
}
|
||||||
|
|
||||||
public compositionstart() {
|
public compositionstart() {
|
||||||
this.isCompositing = true
|
composition.compositionstart(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
public compositionend() {
|
public compositionend() {
|
||||||
this.isCompositing = false
|
composition.compositionend(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
public drop(evt: DragEvent) {
|
public drop(evt: DragEvent) {
|
||||||
evt.preventDefault()
|
drop(evt, this)
|
||||||
const data = evt.dataTransfer?.getData('text')
|
|
||||||
if (data) {
|
|
||||||
this.input(data)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public dragover(evt: DragEvent) {
|
public dragover(evt: DragEvent | MouseEvent) {
|
||||||
const isReadonly = this.draw.isReadonly()
|
drag.dragover(evt, this)
|
||||||
if (isReadonly) return
|
|
||||||
evt.preventDefault()
|
|
||||||
// 非编辑器区禁止拖放
|
|
||||||
const pageContainer = findParent(
|
|
||||||
evt.target as Element,
|
|
||||||
(node: Element) => node === this.pageContainer,
|
|
||||||
true
|
|
||||||
)
|
|
||||||
if (!pageContainer) return
|
|
||||||
const target = evt.target as HTMLDivElement
|
|
||||||
const pageIndex = target.dataset.index
|
|
||||||
// 设置pageNo
|
|
||||||
if (pageIndex) {
|
|
||||||
this.draw.setPageNo(Number(pageIndex))
|
|
||||||
}
|
|
||||||
const { isTable, tdValueIndex, index } = this.position.adjustPositionContext({
|
|
||||||
x: evt.offsetX,
|
|
||||||
y: evt.offsetY
|
|
||||||
})
|
|
||||||
// 设置选区及光标位置
|
|
||||||
const positionList = this.position.getPositionList()
|
|
||||||
const curIndex = isTable ? tdValueIndex! : index
|
|
||||||
if (~index) {
|
|
||||||
this.range.setRange(curIndex, curIndex)
|
|
||||||
this.position.setCursorPosition(positionList[curIndex])
|
|
||||||
}
|
|
||||||
this.cursor?.drawCursor()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -48,7 +48,7 @@ export class GlobalEvent {
|
|||||||
window.addEventListener('blur', this.recoverEffect)
|
window.addEventListener('blur', this.recoverEffect)
|
||||||
document.addEventListener('keyup', this.setRangeStyle)
|
document.addEventListener('keyup', this.setRangeStyle)
|
||||||
document.addEventListener('click', this.recoverEffect)
|
document.addEventListener('click', this.recoverEffect)
|
||||||
document.addEventListener('mouseup', this.setSelectionAbility)
|
document.addEventListener('mouseup', this.setCanvasEventAbility)
|
||||||
document.addEventListener('wheel', this.setPageScale, { passive: false })
|
document.addEventListener('wheel', this.setPageScale, { passive: false })
|
||||||
document.addEventListener('visibilitychange', this._handleVisibilityChange)
|
document.addEventListener('visibilitychange', this._handleVisibilityChange)
|
||||||
}
|
}
|
||||||
@@ -57,7 +57,7 @@ export class GlobalEvent {
|
|||||||
window.removeEventListener('blur', this.recoverEffect)
|
window.removeEventListener('blur', this.recoverEffect)
|
||||||
document.removeEventListener('keyup', this.setRangeStyle)
|
document.removeEventListener('keyup', this.setRangeStyle)
|
||||||
document.removeEventListener('click', this.recoverEffect)
|
document.removeEventListener('click', this.recoverEffect)
|
||||||
document.removeEventListener('mouseup', this.setSelectionAbility)
|
document.removeEventListener('mouseup', this.setCanvasEventAbility)
|
||||||
document.removeEventListener('wheel', this.setPageScale)
|
document.removeEventListener('wheel', this.setPageScale)
|
||||||
document.removeEventListener('visibilitychange', this._handleVisibilityChange)
|
document.removeEventListener('visibilitychange', this._handleVisibilityChange)
|
||||||
}
|
}
|
||||||
@@ -90,7 +90,8 @@ export class GlobalEvent {
|
|||||||
this.dateParticle.clearDatePicker()
|
this.dateParticle.clearDatePicker()
|
||||||
}
|
}
|
||||||
|
|
||||||
public setSelectionAbility = () => {
|
public setCanvasEventAbility = () => {
|
||||||
|
this.canvasEvent.setIsAllowDrag(false)
|
||||||
this.canvasEvent.setIsAllowSelection(false)
|
this.canvasEvent.setIsAllowSelection(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,97 @@
|
|||||||
|
import { ZERO } from '../../../dataset/constant/Common'
|
||||||
|
import { LETTER_REG, NUMBER_LIKE_REG } from '../../../dataset/constant/Regular'
|
||||||
|
import { CanvasEvent } from '../CanvasEvent'
|
||||||
|
|
||||||
|
function dblclick(host: CanvasEvent) {
|
||||||
|
const draw = host.getDraw()
|
||||||
|
const position = draw.getPosition()
|
||||||
|
const cursorPosition = position.getCursorPosition()
|
||||||
|
if (!cursorPosition) return
|
||||||
|
const { value, index } = cursorPosition
|
||||||
|
// 判断是否是数字或英文
|
||||||
|
let upCount = 0
|
||||||
|
let downCount = 0
|
||||||
|
const isNumber = NUMBER_LIKE_REG.test(value)
|
||||||
|
if (isNumber || LETTER_REG.test(value)) {
|
||||||
|
const elementList = draw.getElementList()
|
||||||
|
// 向上查询
|
||||||
|
let upStartIndex = index - 1
|
||||||
|
while (upStartIndex > 0) {
|
||||||
|
const value = elementList[upStartIndex].value
|
||||||
|
if ((isNumber && NUMBER_LIKE_REG.test(value)) || (!isNumber && LETTER_REG.test(value))) {
|
||||||
|
upCount++
|
||||||
|
upStartIndex--
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 向下查询
|
||||||
|
let downStartIndex = index + 1
|
||||||
|
while (downStartIndex < elementList.length) {
|
||||||
|
const value = elementList[downStartIndex].value
|
||||||
|
if ((isNumber && NUMBER_LIKE_REG.test(value)) || (!isNumber && LETTER_REG.test(value))) {
|
||||||
|
downCount++
|
||||||
|
downStartIndex++
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 设置选中区域
|
||||||
|
const rangeManager = draw.getRange()
|
||||||
|
rangeManager.setRange(index - upCount - 1, index + downCount)
|
||||||
|
// 刷新文档
|
||||||
|
draw.render({
|
||||||
|
isSubmitHistory: false,
|
||||||
|
isSetCursor: false,
|
||||||
|
isComputeRowList: false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function threeClick(host: CanvasEvent) {
|
||||||
|
const draw = host.getDraw()
|
||||||
|
const position = draw.getPosition()
|
||||||
|
const cursorPosition = position.getCursorPosition()
|
||||||
|
if (!cursorPosition) return
|
||||||
|
const { index } = cursorPosition
|
||||||
|
const elementList = draw.getElementList()
|
||||||
|
// 判断是否是零宽字符
|
||||||
|
let upCount = 0
|
||||||
|
let downCount = 0
|
||||||
|
// 向上查询
|
||||||
|
let upStartIndex = index - 1
|
||||||
|
while (upStartIndex > 0) {
|
||||||
|
const value = elementList[upStartIndex].value
|
||||||
|
if (value !== ZERO) {
|
||||||
|
upCount++
|
||||||
|
upStartIndex--
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 向下查询
|
||||||
|
let downStartIndex = index + 1
|
||||||
|
while (downStartIndex < elementList.length) {
|
||||||
|
const value = elementList[downStartIndex].value
|
||||||
|
if (value !== ZERO) {
|
||||||
|
downCount++
|
||||||
|
downStartIndex++
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 设置选中区域
|
||||||
|
const rangeManager = draw.getRange()
|
||||||
|
rangeManager.setRange(index - upCount - 1, index + downCount)
|
||||||
|
// 刷新文档
|
||||||
|
draw.render({
|
||||||
|
isSubmitHistory: false,
|
||||||
|
isSetCursor: false,
|
||||||
|
isComputeRowList: false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
dblclick,
|
||||||
|
threeClick
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import { CanvasEvent } from '../CanvasEvent'
|
||||||
|
|
||||||
|
function compositionstart(host: CanvasEvent) {
|
||||||
|
host.isCompositing = true
|
||||||
|
}
|
||||||
|
|
||||||
|
function compositionend(host: CanvasEvent) {
|
||||||
|
host.isCompositing = false
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
compositionstart,
|
||||||
|
compositionend
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import { writeElementList } from '../../../utils/clipboard'
|
||||||
|
import { CanvasEvent } from '../CanvasEvent'
|
||||||
|
|
||||||
|
export function copy(host: CanvasEvent) {
|
||||||
|
const draw = host.getDraw()
|
||||||
|
const rangeManager = draw.getRange()
|
||||||
|
const { startIndex, endIndex } = rangeManager.getRange()
|
||||||
|
if (startIndex !== endIndex) {
|
||||||
|
const options = draw.getOptions()
|
||||||
|
const elementList = draw.getElementList()
|
||||||
|
writeElementList(elementList.slice(startIndex + 1, endIndex + 1), options)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
import { writeElementList } from '../../../utils/clipboard'
|
||||||
|
import { CanvasEvent } from '../CanvasEvent'
|
||||||
|
|
||||||
|
export function cut(host: CanvasEvent) {
|
||||||
|
const draw = host.getDraw()
|
||||||
|
const rangeManager = draw.getRange()
|
||||||
|
const { startIndex, endIndex } = rangeManager.getRange()
|
||||||
|
if (!~startIndex && !~startIndex) return
|
||||||
|
const isReadonly = draw.isReadonly()
|
||||||
|
if (isReadonly) return
|
||||||
|
const control = draw.getControl()
|
||||||
|
const isPartRangeInControlOutside = control.isPartRangeInControlOutside()
|
||||||
|
if (isPartRangeInControlOutside) return
|
||||||
|
const activeControl = control.getActiveControl()
|
||||||
|
const elementList = draw.getElementList()
|
||||||
|
let start = startIndex
|
||||||
|
let end = endIndex
|
||||||
|
// 无选区则剪切一行
|
||||||
|
if (startIndex === endIndex) {
|
||||||
|
const position = draw.getPosition()
|
||||||
|
const positionList = position.getPositionList()
|
||||||
|
const curRowNo = positionList[startIndex].rowNo
|
||||||
|
const cutElementIndexList: number[] = []
|
||||||
|
for (let p = 0; p < positionList.length; p++) {
|
||||||
|
const position = positionList[p]
|
||||||
|
if (position.rowNo > curRowNo) break
|
||||||
|
if (position.rowNo === curRowNo) {
|
||||||
|
cutElementIndexList.push(p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const firstElementIndex = cutElementIndexList[0] - 1
|
||||||
|
start = firstElementIndex < 0 ? 0 : firstElementIndex
|
||||||
|
end = cutElementIndexList[cutElementIndexList.length - 1]
|
||||||
|
}
|
||||||
|
const options = draw.getOptions()
|
||||||
|
// 写入粘贴板
|
||||||
|
writeElementList(elementList.slice(start + 1, end + 1), options)
|
||||||
|
let curIndex: number
|
||||||
|
if (activeControl) {
|
||||||
|
curIndex = control.cut()
|
||||||
|
} else {
|
||||||
|
elementList.splice(start + 1, end - start)
|
||||||
|
curIndex = start
|
||||||
|
}
|
||||||
|
rangeManager.setRange(curIndex, curIndex)
|
||||||
|
draw.render({ curIndex })
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
import { findParent } from '../../../utils'
|
||||||
|
import { CanvasEvent } from '../CanvasEvent'
|
||||||
|
|
||||||
|
function dragover(evt: DragEvent | MouseEvent, host: CanvasEvent) {
|
||||||
|
const draw = host.getDraw()
|
||||||
|
const isReadonly = draw.isReadonly()
|
||||||
|
if (isReadonly) return
|
||||||
|
evt.preventDefault()
|
||||||
|
// 非编辑器区禁止拖放
|
||||||
|
const pageContainer = draw.getPageContainer()
|
||||||
|
const editorRegion = findParent(
|
||||||
|
evt.target as Element,
|
||||||
|
(node: Element) => node === pageContainer,
|
||||||
|
true
|
||||||
|
)
|
||||||
|
if (!editorRegion) return
|
||||||
|
const target = evt.target as HTMLDivElement
|
||||||
|
const pageIndex = target.dataset.index
|
||||||
|
// 设置pageNo
|
||||||
|
if (pageIndex) {
|
||||||
|
draw.setPageNo(Number(pageIndex))
|
||||||
|
}
|
||||||
|
const position = draw.getPosition()
|
||||||
|
const { isTable, tdValueIndex, index } = position.adjustPositionContext({
|
||||||
|
x: evt.offsetX,
|
||||||
|
y: evt.offsetY
|
||||||
|
})
|
||||||
|
// 设置选区及光标位置
|
||||||
|
const positionList = position.getPositionList()
|
||||||
|
const curIndex = isTable ? tdValueIndex! : index
|
||||||
|
if (~index) {
|
||||||
|
const rangeManager = draw.getRange()
|
||||||
|
rangeManager.setRange(curIndex, curIndex)
|
||||||
|
position.setCursorPosition(positionList[curIndex])
|
||||||
|
}
|
||||||
|
const cursor = draw.getCursor()
|
||||||
|
cursor.drawCursor()
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
dragover
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import { CanvasEvent } from '../CanvasEvent'
|
||||||
|
|
||||||
|
export function drop(evt: DragEvent, host: CanvasEvent) {
|
||||||
|
evt.preventDefault()
|
||||||
|
const data = evt.dataTransfer?.getData('text')
|
||||||
|
if (data) {
|
||||||
|
host.input(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
import { ZERO } from '../../../dataset/constant/Common'
|
||||||
|
import { EDITOR_ELEMENT_COPY_ATTR } from '../../../dataset/constant/Element'
|
||||||
|
import { ElementType } from '../../../dataset/enum/Element'
|
||||||
|
import { IElement } from '../../../interface/Element'
|
||||||
|
import { splitText } from '../../../utils'
|
||||||
|
import { CanvasEvent } from '../CanvasEvent'
|
||||||
|
|
||||||
|
export function input(data: string, host: CanvasEvent) {
|
||||||
|
const draw = host.getDraw()
|
||||||
|
const isReadonly = draw.isReadonly()
|
||||||
|
if (isReadonly) return
|
||||||
|
const position = draw.getPosition()
|
||||||
|
const cursorPosition = position.getCursorPosition()
|
||||||
|
if (!data || !cursorPosition || host.isCompositing) return
|
||||||
|
const control = draw.getControl()
|
||||||
|
if (control.isPartRangeInControlOutside()) {
|
||||||
|
// 忽略选区部分在控件的输入
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const activeControl = control.getActiveControl()
|
||||||
|
const { TEXT, HYPERLINK, SUBSCRIPT, SUPERSCRIPT, DATE } = ElementType
|
||||||
|
const text = data.replaceAll(`\n`, ZERO)
|
||||||
|
const cursor = draw.getCursor()
|
||||||
|
const agentDom = cursor.getAgentDom()
|
||||||
|
agentDom.value = ''
|
||||||
|
const { index } = cursorPosition
|
||||||
|
const rangeManager = draw.getRange()
|
||||||
|
const { startIndex, endIndex } = rangeManager.getRange()
|
||||||
|
const isCollapsed = startIndex === endIndex
|
||||||
|
// 表格需要上下文信息
|
||||||
|
const positionContext = position.getPositionContext()
|
||||||
|
let restArg = {}
|
||||||
|
if (positionContext.isTable) {
|
||||||
|
const { tdId, trId, tableId } = positionContext
|
||||||
|
restArg = { tdId, trId, tableId }
|
||||||
|
}
|
||||||
|
const elementList = draw.getElementList()
|
||||||
|
const element = elementList[endIndex]
|
||||||
|
const inputData: IElement[] = splitText(text).map(value => {
|
||||||
|
const newElement: IElement = {
|
||||||
|
value,
|
||||||
|
...restArg
|
||||||
|
}
|
||||||
|
const nextElement = elementList[endIndex + 1]
|
||||||
|
if (
|
||||||
|
element.type === TEXT
|
||||||
|
|| (!element.type && element.value !== ZERO)
|
||||||
|
|| (element.type === HYPERLINK && nextElement?.type === HYPERLINK)
|
||||||
|
|| (element.type === DATE && nextElement?.type === DATE)
|
||||||
|
|| (element.type === SUBSCRIPT && nextElement?.type === SUBSCRIPT)
|
||||||
|
|| (element.type === SUPERSCRIPT && nextElement?.type === SUPERSCRIPT)
|
||||||
|
) {
|
||||||
|
EDITOR_ELEMENT_COPY_ATTR.forEach(attr => {
|
||||||
|
const value = element[attr] as never
|
||||||
|
if (value !== undefined) {
|
||||||
|
newElement[attr] = value
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return newElement
|
||||||
|
})
|
||||||
|
// 控件-移除placeholder
|
||||||
|
let curIndex: number
|
||||||
|
if (activeControl && elementList[endIndex + 1]?.controlId === element.controlId) {
|
||||||
|
curIndex = control.setValue(inputData)
|
||||||
|
} else {
|
||||||
|
let start = 0
|
||||||
|
if (isCollapsed) {
|
||||||
|
start = index + 1
|
||||||
|
} else {
|
||||||
|
start = startIndex + 1
|
||||||
|
elementList.splice(startIndex + 1, endIndex - startIndex)
|
||||||
|
}
|
||||||
|
// 禁止直接使用解构存在性能问题
|
||||||
|
for (let i = 0; i < inputData.length; i++) {
|
||||||
|
elementList.splice(start + i, 0, inputData[i])
|
||||||
|
}
|
||||||
|
curIndex = (isCollapsed ? index : startIndex) + inputData.length
|
||||||
|
}
|
||||||
|
rangeManager.setRange(curIndex, curIndex)
|
||||||
|
draw.render({ curIndex })
|
||||||
|
}
|
||||||
@@ -0,0 +1,186 @@
|
|||||||
|
import { ZERO } from '../../../dataset/constant/Common'
|
||||||
|
import { ElementType } from '../../../dataset/enum/Element'
|
||||||
|
import { KeyMap } from '../../../dataset/enum/KeyMap'
|
||||||
|
import { IElement } from '../../../interface/Element'
|
||||||
|
import { CanvasEvent } from '../CanvasEvent'
|
||||||
|
|
||||||
|
export function keydown(evt: KeyboardEvent, host: CanvasEvent) {
|
||||||
|
const draw = host.getDraw()
|
||||||
|
const position = draw.getPosition()
|
||||||
|
const cursorPosition = position.getCursorPosition()
|
||||||
|
if (!cursorPosition) return
|
||||||
|
const isReadonly = draw.isReadonly()
|
||||||
|
const historyManager = draw.getHistoryManager()
|
||||||
|
const elementList = draw.getElementList()
|
||||||
|
const positionList = position.getPositionList()
|
||||||
|
const { index } = cursorPosition
|
||||||
|
const rangeManager = draw.getRange()
|
||||||
|
const { startIndex, endIndex } = rangeManager.getRange()
|
||||||
|
const isCollapsed = startIndex === endIndex
|
||||||
|
// 当前激活控件
|
||||||
|
const control = draw.getControl()
|
||||||
|
const isPartRangeInControlOutside = control.isPartRangeInControlOutside()
|
||||||
|
const activeControl = control.getActiveControl()
|
||||||
|
if (evt.key === KeyMap.Backspace) {
|
||||||
|
if (isReadonly || isPartRangeInControlOutside) return
|
||||||
|
let curIndex: number
|
||||||
|
if (activeControl) {
|
||||||
|
curIndex = control.keydown(evt)
|
||||||
|
} else {
|
||||||
|
// 判断是否允许删除
|
||||||
|
if (isCollapsed && elementList[index].value === ZERO && index === 0) {
|
||||||
|
evt.preventDefault()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!isCollapsed) {
|
||||||
|
elementList.splice(startIndex + 1, endIndex - startIndex)
|
||||||
|
} else {
|
||||||
|
elementList.splice(index, 1)
|
||||||
|
}
|
||||||
|
curIndex = isCollapsed ? index - 1 : startIndex
|
||||||
|
}
|
||||||
|
rangeManager.setRange(curIndex, curIndex)
|
||||||
|
draw.render({ curIndex })
|
||||||
|
} else if (evt.key === KeyMap.Delete) {
|
||||||
|
if (isReadonly || isPartRangeInControlOutside) return
|
||||||
|
let curIndex: number
|
||||||
|
if (activeControl) {
|
||||||
|
curIndex = control.keydown(evt)
|
||||||
|
} else if (elementList[endIndex + 1]?.type === ElementType.CONTROL) {
|
||||||
|
curIndex = control.removeControl(endIndex + 1)
|
||||||
|
} else {
|
||||||
|
if (!isCollapsed) {
|
||||||
|
elementList.splice(startIndex + 1, endIndex - startIndex)
|
||||||
|
} else {
|
||||||
|
elementList.splice(index + 1, 1)
|
||||||
|
}
|
||||||
|
curIndex = isCollapsed ? index : startIndex
|
||||||
|
}
|
||||||
|
rangeManager.setRange(curIndex, curIndex)
|
||||||
|
draw.render({ curIndex })
|
||||||
|
} else if (evt.key === KeyMap.Enter) {
|
||||||
|
if (isReadonly || isPartRangeInControlOutside) return
|
||||||
|
// 表格需要上下文信息
|
||||||
|
const positionContext = position.getPositionContext()
|
||||||
|
let restArg = {}
|
||||||
|
if (positionContext.isTable) {
|
||||||
|
const { tdId, trId, tableId } = positionContext
|
||||||
|
restArg = { tdId, trId, tableId }
|
||||||
|
}
|
||||||
|
const enterText: IElement = {
|
||||||
|
value: ZERO,
|
||||||
|
...restArg
|
||||||
|
}
|
||||||
|
let curIndex: number
|
||||||
|
if (activeControl) {
|
||||||
|
curIndex = control.setValue([enterText])
|
||||||
|
} else {
|
||||||
|
if (isCollapsed) {
|
||||||
|
elementList.splice(index + 1, 0, enterText)
|
||||||
|
} else {
|
||||||
|
elementList.splice(startIndex + 1, endIndex - startIndex, enterText)
|
||||||
|
}
|
||||||
|
curIndex = index + 1
|
||||||
|
}
|
||||||
|
rangeManager.setRange(curIndex, curIndex)
|
||||||
|
draw.render({ curIndex })
|
||||||
|
evt.preventDefault()
|
||||||
|
} else if (evt.key === KeyMap.Left) {
|
||||||
|
if (isReadonly) return
|
||||||
|
if (index > 0) {
|
||||||
|
const curIndex = index - 1
|
||||||
|
rangeManager.setRange(curIndex, curIndex)
|
||||||
|
draw.render({
|
||||||
|
curIndex,
|
||||||
|
isSubmitHistory: false,
|
||||||
|
isComputeRowList: false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else if (evt.key === KeyMap.Right) {
|
||||||
|
if (isReadonly) return
|
||||||
|
if (index < positionList.length - 1) {
|
||||||
|
const curIndex = index + 1
|
||||||
|
rangeManager.setRange(curIndex, curIndex)
|
||||||
|
draw.render({
|
||||||
|
curIndex,
|
||||||
|
isSubmitHistory: false,
|
||||||
|
isComputeRowList: false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else if (evt.key === KeyMap.Up || evt.key === KeyMap.Down) {
|
||||||
|
if (isReadonly) return
|
||||||
|
const { rowNo, index, coordinate: { leftTop, rightTop } } = cursorPosition
|
||||||
|
if ((evt.key === KeyMap.Up && rowNo !== 0) || (evt.key === KeyMap.Down && rowNo !== draw.getRowCount())) {
|
||||||
|
// 下一个光标点所在行位置集合
|
||||||
|
const probablePosition = evt.key === KeyMap.Up
|
||||||
|
? positionList.slice(0, index).filter(p => p.rowNo === rowNo - 1)
|
||||||
|
: positionList.slice(index, positionList.length - 1).filter(p => p.rowNo === rowNo + 1)
|
||||||
|
// 查找与当前位置元素点交叉最多的位置
|
||||||
|
let maxIndex = 0
|
||||||
|
let maxDistance = 0
|
||||||
|
for (let p = 0; p < probablePosition.length; p++) {
|
||||||
|
const position = probablePosition[p]
|
||||||
|
// 当前光标在前
|
||||||
|
if (position.coordinate.leftTop[0] >= leftTop[0] && position.coordinate.leftTop[0] <= rightTop[0]) {
|
||||||
|
const curDistance = rightTop[0] - position.coordinate.leftTop[0]
|
||||||
|
if (curDistance > maxDistance) {
|
||||||
|
maxIndex = position.index
|
||||||
|
maxDistance = curDistance
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 当前光标在后
|
||||||
|
else if (position.coordinate.leftTop[0] <= leftTop[0] && position.coordinate.rightTop[0] >= leftTop[0]) {
|
||||||
|
const curDistance = position.coordinate.rightTop[0] - leftTop[0]
|
||||||
|
if (curDistance > maxDistance) {
|
||||||
|
maxIndex = position.index
|
||||||
|
maxDistance = curDistance
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 匹配不到
|
||||||
|
if (p === probablePosition.length - 1 && maxIndex === 0) {
|
||||||
|
maxIndex = position.index
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const curIndex = maxIndex
|
||||||
|
rangeManager.setRange(curIndex, curIndex)
|
||||||
|
draw.render({
|
||||||
|
curIndex,
|
||||||
|
isSubmitHistory: false,
|
||||||
|
isComputeRowList: false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else if (evt.ctrlKey && evt.key === KeyMap.Z) {
|
||||||
|
if (isReadonly) return
|
||||||
|
historyManager.undo()
|
||||||
|
evt.preventDefault()
|
||||||
|
} else if (evt.ctrlKey && evt.key === KeyMap.Y) {
|
||||||
|
if (isReadonly) return
|
||||||
|
historyManager.redo()
|
||||||
|
evt.preventDefault()
|
||||||
|
} else if (evt.ctrlKey && evt.key === KeyMap.C) {
|
||||||
|
host.copy()
|
||||||
|
evt.preventDefault()
|
||||||
|
} else if (evt.ctrlKey && evt.key === KeyMap.X) {
|
||||||
|
host.cut()
|
||||||
|
evt.preventDefault()
|
||||||
|
} else if (evt.ctrlKey && evt.key === KeyMap.A) {
|
||||||
|
host.selectAll()
|
||||||
|
evt.preventDefault()
|
||||||
|
} else if (evt.ctrlKey && evt.key === KeyMap.S) {
|
||||||
|
if (isReadonly) return
|
||||||
|
const listener = draw.getListener()
|
||||||
|
if (listener.saved) {
|
||||||
|
listener.saved(draw.getValue())
|
||||||
|
}
|
||||||
|
evt.preventDefault()
|
||||||
|
} else if (evt.key === KeyMap.ESC) {
|
||||||
|
host.clearPainterStyle()
|
||||||
|
evt.preventDefault()
|
||||||
|
} else if (evt.key === KeyMap.TAB) {
|
||||||
|
draw.insertElementList([{
|
||||||
|
type: ElementType.TAB,
|
||||||
|
value: ''
|
||||||
|
}])
|
||||||
|
evt.preventDefault()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
import { ElementType } from '../../../dataset/enum/Element'
|
||||||
|
import { MouseEventButton } from '../../../dataset/enum/Event'
|
||||||
|
import { deepClone } from '../../../utils'
|
||||||
|
import { CheckboxControl } from '../../draw/control/checkbox/CheckboxControl'
|
||||||
|
import { CanvasEvent } from '../CanvasEvent'
|
||||||
|
|
||||||
|
export function mousedown(evt: MouseEvent, host: CanvasEvent) {
|
||||||
|
if (evt.button === MouseEventButton.RIGHT) return
|
||||||
|
const draw = host.getDraw()
|
||||||
|
const isReadonly = draw.isReadonly()
|
||||||
|
const rangeManager = draw.getRange()
|
||||||
|
const position = draw.getPosition()
|
||||||
|
// 是否是选区拖拽
|
||||||
|
if (!host.isAllowDrag) {
|
||||||
|
const range = rangeManager.getRange()
|
||||||
|
if (!isReadonly && range.startIndex !== range.endIndex) {
|
||||||
|
const isPointInRange = rangeManager.getIsPointInRange(evt.offsetX, evt.offsetY)
|
||||||
|
if (isPointInRange) {
|
||||||
|
host.isAllowDrag = true
|
||||||
|
host.cacheRange = deepClone(range)
|
||||||
|
host.cacheElementList = draw.getElementList()
|
||||||
|
host.cachePositionList = position.getPositionList()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const target = evt.target as HTMLDivElement
|
||||||
|
const pageIndex = target.dataset.index
|
||||||
|
// 设置pageNo
|
||||||
|
if (pageIndex) {
|
||||||
|
draw.setPageNo(Number(pageIndex))
|
||||||
|
}
|
||||||
|
host.isAllowSelection = true
|
||||||
|
const positionResult = position.adjustPositionContext({
|
||||||
|
x: evt.offsetX,
|
||||||
|
y: evt.offsetY
|
||||||
|
})
|
||||||
|
const {
|
||||||
|
index,
|
||||||
|
isDirectHit,
|
||||||
|
isCheckbox,
|
||||||
|
isImage,
|
||||||
|
isTable,
|
||||||
|
tdValueIndex,
|
||||||
|
} = positionResult
|
||||||
|
// 记录选区开始位置
|
||||||
|
host.mouseDownStartPosition = {
|
||||||
|
...positionResult,
|
||||||
|
index: isTable ? tdValueIndex! : index
|
||||||
|
}
|
||||||
|
const elementList = draw.getElementList()
|
||||||
|
const positionList = position.getPositionList()
|
||||||
|
const curIndex = isTable ? tdValueIndex! : index
|
||||||
|
const curElement = elementList[curIndex]
|
||||||
|
// 绘制
|
||||||
|
const isDirectHitImage = !!(isDirectHit && isImage)
|
||||||
|
const isDirectHitCheckbox = !!(isDirectHit && isCheckbox)
|
||||||
|
if (~index) {
|
||||||
|
rangeManager.setRange(curIndex, curIndex)
|
||||||
|
position.setCursorPosition(positionList[curIndex])
|
||||||
|
// 复选框
|
||||||
|
const isSetCheckbox = isDirectHitCheckbox && !isReadonly
|
||||||
|
if (isSetCheckbox) {
|
||||||
|
const { checkbox } = curElement
|
||||||
|
if (checkbox) {
|
||||||
|
checkbox.value = !checkbox.value
|
||||||
|
} else {
|
||||||
|
curElement.checkbox = {
|
||||||
|
value: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const control = draw.getControl()
|
||||||
|
const activeControl = control.getActiveControl()
|
||||||
|
if (activeControl instanceof CheckboxControl) {
|
||||||
|
activeControl.setSelect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
draw.render({
|
||||||
|
curIndex,
|
||||||
|
isSubmitHistory: isSetCheckbox,
|
||||||
|
isSetCursor: !isDirectHitImage && !isDirectHitCheckbox,
|
||||||
|
isComputeRowList: false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// 预览工具组件
|
||||||
|
const previewer = draw.getPreviewer()
|
||||||
|
previewer.clearResizer()
|
||||||
|
if (isDirectHitImage && !isReadonly) {
|
||||||
|
previewer.drawResizer(curElement, positionList[curIndex],
|
||||||
|
curElement.type === ElementType.LATEX
|
||||||
|
? {
|
||||||
|
mime: 'svg',
|
||||||
|
srcKey: 'laTexSVG'
|
||||||
|
}
|
||||||
|
: {})
|
||||||
|
}
|
||||||
|
// 表格工具组件
|
||||||
|
const tableTool = draw.getTableTool()
|
||||||
|
tableTool.dispose()
|
||||||
|
if (isTable && !isReadonly) {
|
||||||
|
const originalElementList = draw.getOriginalElementList()
|
||||||
|
const originalPositionList = position.getOriginalPositionList()
|
||||||
|
tableTool.render(originalElementList[index], originalPositionList[index])
|
||||||
|
}
|
||||||
|
// 超链接
|
||||||
|
const hyperlinkParticle = draw.getHyperlinkParticle()
|
||||||
|
hyperlinkParticle.clearHyperlinkPopup()
|
||||||
|
if (curElement.type === ElementType.HYPERLINK) {
|
||||||
|
hyperlinkParticle.drawHyperlinkPopup(curElement, positionList[curIndex])
|
||||||
|
}
|
||||||
|
// 日期控件
|
||||||
|
const dateParticle = draw.getDateParticle()
|
||||||
|
dateParticle.clearDatePicker()
|
||||||
|
if (curElement.type === ElementType.DATE && !isReadonly) {
|
||||||
|
dateParticle.renderDatePicker(curElement, positionList[curIndex])
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import { CanvasEvent } from '../CanvasEvent'
|
||||||
|
|
||||||
|
export function mouseleave(evt: MouseEvent, host: CanvasEvent) {
|
||||||
|
// 是否还在canvas内部
|
||||||
|
const draw = host.getDraw()
|
||||||
|
const pageContainer = draw.getPageContainer()
|
||||||
|
const { x, y, width, height } = pageContainer.getBoundingClientRect()
|
||||||
|
if (evt.x >= x && evt.x <= x + width && evt.y >= y && evt.y <= y + height) return
|
||||||
|
host.setIsAllowSelection(false)
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
import { CanvasEvent } from '../CanvasEvent'
|
||||||
|
|
||||||
|
export function mousemove(evt: MouseEvent, host: CanvasEvent) {
|
||||||
|
const draw = host.getDraw()
|
||||||
|
// 是否是拖拽文字
|
||||||
|
if (host.isAllowDrag) {
|
||||||
|
// 是否允许拖拽到选区
|
||||||
|
const x = evt.offsetX
|
||||||
|
const y = evt.offsetY
|
||||||
|
const { startIndex, endIndex } = host.cacheRange!
|
||||||
|
const positionList = host.cachePositionList!
|
||||||
|
for (let p = startIndex + 1; p <= endIndex; p++) {
|
||||||
|
const { coordinate: { leftTop, rightBottom } } = positionList[p]
|
||||||
|
if (x >= leftTop[0] && x <= rightBottom[0] && y >= leftTop[1] && y <= rightBottom[1]) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
host.dragover(evt)
|
||||||
|
host.isAllowDrop = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!host.isAllowSelection || !host.mouseDownStartPosition) return
|
||||||
|
const target = evt.target as HTMLDivElement
|
||||||
|
const pageIndex = target.dataset.index
|
||||||
|
// 设置pageNo
|
||||||
|
if (pageIndex) {
|
||||||
|
draw.setPageNo(Number(pageIndex))
|
||||||
|
}
|
||||||
|
// 结束位置
|
||||||
|
const position = draw.getPosition()
|
||||||
|
const positionResult = position.getPositionByXY({
|
||||||
|
x: evt.offsetX,
|
||||||
|
y: evt.offsetY
|
||||||
|
})
|
||||||
|
const {
|
||||||
|
index,
|
||||||
|
isTable,
|
||||||
|
tdValueIndex,
|
||||||
|
tdIndex,
|
||||||
|
trIndex,
|
||||||
|
tableId
|
||||||
|
} = positionResult
|
||||||
|
const {
|
||||||
|
index: startIndex,
|
||||||
|
isTable: startIsTable,
|
||||||
|
tdIndex: startTdIndex,
|
||||||
|
trIndex: startTrIndex
|
||||||
|
} = host.mouseDownStartPosition
|
||||||
|
const endIndex = isTable ? tdValueIndex! : index
|
||||||
|
// 判断是否是表格跨行/列
|
||||||
|
const rangeManager = draw.getRange()
|
||||||
|
if (isTable && startIsTable && (tdIndex !== startTdIndex || trIndex !== startTrIndex)) {
|
||||||
|
rangeManager.setRange(
|
||||||
|
endIndex,
|
||||||
|
endIndex,
|
||||||
|
tableId,
|
||||||
|
startTdIndex,
|
||||||
|
tdIndex,
|
||||||
|
startTrIndex,
|
||||||
|
trIndex
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
let end = ~endIndex ? endIndex : 0
|
||||||
|
// 开始位置
|
||||||
|
let start = startIndex
|
||||||
|
if (start > end) {
|
||||||
|
[start, end] = [end, start]
|
||||||
|
}
|
||||||
|
if (start === end) return
|
||||||
|
rangeManager.setRange(start, end)
|
||||||
|
}
|
||||||
|
// 绘制
|
||||||
|
draw.render({
|
||||||
|
isSubmitHistory: false,
|
||||||
|
isSetCursor: false,
|
||||||
|
isComputeRowList: false
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
import { EDITOR_ELEMENT_STYLE_ATTR } from '../../../dataset/constant/Element'
|
||||||
|
import { IElement } from '../../../interface/Element'
|
||||||
|
import { CanvasEvent } from '../CanvasEvent'
|
||||||
|
|
||||||
|
export function mouseup(evt: MouseEvent, host: CanvasEvent) {
|
||||||
|
// 判断是否允许拖放
|
||||||
|
if (host.isAllowDrop) {
|
||||||
|
const draw = host.getDraw()
|
||||||
|
const position = draw.getPosition()
|
||||||
|
const rangeManager = draw.getRange()
|
||||||
|
const cacheRange = host.cacheRange!
|
||||||
|
const cacheElementList = host.cacheElementList!
|
||||||
|
const cachePositionList = host.cachePositionList!
|
||||||
|
// 如果同一上下文拖拽位置向后移动,则重置光标位置
|
||||||
|
const range = rangeManager.getRange()
|
||||||
|
const elementList = draw.getElementList()
|
||||||
|
const positionList = position.getPositionList()
|
||||||
|
const startPosition = positionList[range.startIndex]
|
||||||
|
const cacheStartElement = cacheElementList[cacheRange.startIndex]
|
||||||
|
const startElement = elementList[range.startIndex]
|
||||||
|
let curIndex = range.startIndex
|
||||||
|
if (cacheStartElement.tdId === startElement.tdId && range.startIndex > cacheRange.endIndex) {
|
||||||
|
curIndex -= (cacheRange.endIndex - cacheRange.startIndex)
|
||||||
|
}
|
||||||
|
// 删除原有拖拽元素
|
||||||
|
const deleteElementList = cacheElementList.splice(cacheRange.startIndex + 1, cacheRange.endIndex - cacheRange.startIndex)
|
||||||
|
// 格式化元素
|
||||||
|
let restArg = {}
|
||||||
|
if (startElement.tableId) {
|
||||||
|
const { tdId, trId, tableId } = startElement
|
||||||
|
restArg = { tdId, trId, tableId }
|
||||||
|
}
|
||||||
|
const replaceElementList = deleteElementList.map(el => {
|
||||||
|
const newElement: IElement = {
|
||||||
|
value: el.value,
|
||||||
|
...restArg
|
||||||
|
}
|
||||||
|
EDITOR_ELEMENT_STYLE_ATTR.forEach(attr => {
|
||||||
|
const value = el[attr] as never
|
||||||
|
if (value !== undefined) {
|
||||||
|
newElement[attr] = value
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return newElement
|
||||||
|
})
|
||||||
|
elementList.splice(curIndex + 1, 0, ...replaceElementList)
|
||||||
|
// 重设上下文
|
||||||
|
const cacheStartPosition = cachePositionList[cacheRange.startIndex]
|
||||||
|
const positionContext = position.getPositionContext()
|
||||||
|
let positionContextIndex = positionContext.index
|
||||||
|
if (positionContextIndex) {
|
||||||
|
if (startElement.tableId && !cacheStartElement.tableId) {
|
||||||
|
// 表格外移动到表格内&&表格之前
|
||||||
|
if (cacheStartPosition.index < positionContextIndex) {
|
||||||
|
positionContextIndex -= deleteElementList.length
|
||||||
|
}
|
||||||
|
} else if (!startElement.tableId && cacheStartElement.tableId) {
|
||||||
|
// 表格内移到表格外&&表格之前
|
||||||
|
if (startPosition.index < positionContextIndex) {
|
||||||
|
positionContextIndex += deleteElementList.length
|
||||||
|
}
|
||||||
|
}
|
||||||
|
position.setPositionContext({
|
||||||
|
...positionContext,
|
||||||
|
index: positionContextIndex
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// 设置选区
|
||||||
|
rangeManager.setRange(
|
||||||
|
curIndex,
|
||||||
|
curIndex + deleteElementList.length,
|
||||||
|
range.tableId,
|
||||||
|
range.startTdIndex,
|
||||||
|
range.endTdIndex,
|
||||||
|
range.startTrIndex,
|
||||||
|
range.endTrIndex
|
||||||
|
)
|
||||||
|
// 重新渲染&重设状态
|
||||||
|
draw.render({
|
||||||
|
isSetCursor: false
|
||||||
|
})
|
||||||
|
host.isAllowDrag = false
|
||||||
|
host.isAllowDrop = false
|
||||||
|
} else if (host.isAllowDrag) {
|
||||||
|
// 如果是允许拖拽不允许拖放则光标重置
|
||||||
|
host.mousedown(evt)
|
||||||
|
host.isAllowDrag = false
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { ElementType } from '../enum/Element'
|
import { ElementType } from '../enum/Element'
|
||||||
import { IElement } from '../../interface/Element'
|
import { IElement } from '../../interface/Element'
|
||||||
|
|
||||||
export const EDITOR_ELEMENT_STYLE_ATTR = [
|
export const EDITOR_ELEMENT_STYLE_ATTR: Array<keyof IElement> = [
|
||||||
'bold',
|
'bold',
|
||||||
'color',
|
'color',
|
||||||
'highlight',
|
'highlight',
|
||||||
|
|||||||
Reference in New Issue
Block a user