diff --git a/src/editor/core/event/handlers/keydown/index.ts b/src/editor/core/event/handlers/keydown/index.ts index 7a6c41a..2cf031e 100644 --- a/src/editor/core/event/handlers/keydown/index.ts +++ b/src/editor/core/event/handlers/keydown/index.ts @@ -8,6 +8,8 @@ import { formatElementContext } from '../../../../utils/element' import { isMod } from '../../../../utils/hotkey' import { CanvasEvent } from '../../CanvasEvent' import { enter } from './enter' +import { left } from './left' +import { right } from './right' export function keydown(evt: KeyboardEvent, host: CanvasEvent) { if (host.isComposing) return @@ -95,119 +97,9 @@ export function keydown(evt: KeyboardEvent, host: CanvasEvent) { } else if (evt.key === KeyMap.Enter) { enter(evt, host) } else if (evt.key === KeyMap.Left) { - if (isReadonly) return - if (index > 0) { - const cursorPosition = position.getCursorPosition() - // 单词整体移动 - let moveCount = 1 - if (isMod(evt)) { - const LETTER_REG = draw.getLetterReg() - // 起始位置 - const moveStartIndex = - evt.shiftKey && !isCollapsed && startIndex === cursorPosition?.index - ? endIndex - : startIndex - if (LETTER_REG.test(elementList[moveStartIndex]?.value)) { - let i = moveStartIndex - 1 - while (i > 0) { - const element = elementList[i] - if (!LETTER_REG.test(element.value)) { - break - } - moveCount++ - i-- - } - } - } - const curIndex = startIndex - moveCount - // shift则缩放选区 - let anchorStartIndex = curIndex - let anchorEndIndex = curIndex - if (evt.shiftKey && cursorPosition) { - if (startIndex !== endIndex) { - if (startIndex === cursorPosition.index) { - // 减小选区 - anchorStartIndex = startIndex - anchorEndIndex = endIndex - moveCount - } else { - anchorStartIndex = curIndex - anchorEndIndex = endIndex - } - } else { - anchorEndIndex = endIndex - } - } - if (!~anchorStartIndex || !~anchorEndIndex) return - rangeManager.setRange(anchorStartIndex, anchorEndIndex) - const isAnchorCollapsed = anchorStartIndex === anchorEndIndex - draw.render({ - curIndex: isAnchorCollapsed ? anchorStartIndex : undefined, - isSetCursor: isAnchorCollapsed, - isSubmitHistory: false, - isCompute: false - }) - evt.preventDefault() - } + left(evt, host) } else if (evt.key === KeyMap.Right) { - if (isReadonly) return - if (index < positionList.length) { - const cursorPosition = position.getCursorPosition() - let moveCount = 1 - // 单词整体移动 - if (isMod(evt)) { - const LETTER_REG = draw.getLetterReg() - // 起始位置 - const moveStartIndex = - evt.shiftKey && !isCollapsed && startIndex === cursorPosition?.index - ? endIndex - : startIndex - if (LETTER_REG.test(elementList[moveStartIndex + 1]?.value)) { - let i = moveStartIndex + 2 - while (i < elementList.length) { - const element = elementList[i] - if (!LETTER_REG.test(element.value)) { - break - } - moveCount++ - i++ - } - } - } - const curIndex = endIndex + moveCount - // shift则缩放选区 - let anchorStartIndex = curIndex - let anchorEndIndex = curIndex - if (evt.shiftKey && cursorPosition) { - if (startIndex !== endIndex) { - if (startIndex === cursorPosition.index) { - // 增大选区 - anchorStartIndex = startIndex - anchorEndIndex = curIndex - } else { - anchorStartIndex = startIndex + moveCount - anchorEndIndex = endIndex - } - } else { - anchorStartIndex = startIndex - } - } - const maxElementListIndex = elementList.length - 1 - if ( - anchorStartIndex > maxElementListIndex || - anchorEndIndex > maxElementListIndex - ) { - return - } - rangeManager.setRange(anchorStartIndex, anchorEndIndex) - const isAnchorCollapsed = anchorStartIndex === anchorEndIndex - draw.render({ - curIndex: isAnchorCollapsed ? anchorStartIndex : undefined, - isSetCursor: isAnchorCollapsed, - isSubmitHistory: false, - isCompute: false - }) - evt.preventDefault() - } + right(evt, host) } else if (evt.key === KeyMap.Up || evt.key === KeyMap.Down) { if (isReadonly) return let anchorPosition: IElementPosition = cursorPosition diff --git a/src/editor/core/event/handlers/keydown/left.ts b/src/editor/core/event/handlers/keydown/left.ts new file mode 100644 index 0000000..54ffb08 --- /dev/null +++ b/src/editor/core/event/handlers/keydown/left.ts @@ -0,0 +1,140 @@ +import { ElementType } from '../../../../dataset/enum/Element' +import { isMod } from '../../../../utils/hotkey' +import { CanvasEvent } from '../../CanvasEvent' + +export function left(evt: KeyboardEvent, host: CanvasEvent) { + const draw = host.getDraw() + const isReadonly = draw.isReadonly() + if (isReadonly) return + const position = draw.getPosition() + const cursorPosition = position.getCursorPosition() + if (!cursorPosition) return + const positionContext = position.getPositionContext() + const { index } = cursorPosition + if (index <= 0 && !positionContext.isTable) return + const rangeManager = draw.getRange() + const { startIndex, endIndex } = rangeManager.getRange() + const isCollapsed = rangeManager.getIsCollapsed() + const elementList = draw.getElementList() + // 单词整体移动 + let moveCount = 1 + if (isMod(evt)) { + const LETTER_REG = draw.getLetterReg() + // 起始位置 + const moveStartIndex = + evt.shiftKey && !isCollapsed && startIndex === cursorPosition?.index + ? endIndex + : startIndex + if (LETTER_REG.test(elementList[moveStartIndex]?.value)) { + let i = moveStartIndex - 1 + while (i > 0) { + const element = elementList[i] + if (!LETTER_REG.test(element.value)) { + break + } + moveCount++ + i-- + } + } + } + const curIndex = startIndex - moveCount + // shift则缩放选区 + let anchorStartIndex = curIndex + let anchorEndIndex = curIndex + if (evt.shiftKey && cursorPosition) { + if (startIndex !== endIndex) { + if (startIndex === cursorPosition.index) { + // 减小选区 + anchorStartIndex = startIndex + anchorEndIndex = endIndex - moveCount + } else { + anchorStartIndex = curIndex + anchorEndIndex = endIndex + } + } else { + anchorEndIndex = endIndex + } + } + // 表格单元格间跳转 + if (!evt.shiftKey) { + const element = elementList[startIndex] + // 之前是表格则进入最后一个单元格最后一个元素 + if (element.type === ElementType.TABLE) { + const trList = element.trList! + const lastTrIndex = trList.length - 1 + const lastTr = trList[lastTrIndex] + const lastTdIndex = lastTr.tdList.length - 1 + const lastTd = lastTr.tdList[lastTdIndex] + position.setPositionContext({ + isTable: true, + index: startIndex, + trIndex: lastTrIndex, + tdIndex: lastTdIndex, + tdId: lastTd.id, + trId: lastTr.id, + tableId: element.id + }) + anchorStartIndex = lastTd.value.length - 1 + anchorEndIndex = anchorStartIndex + draw.getTableTool().render() + } else if (element.tableId) { + // 在表格单元格内&在首位则往前移动单元格 + if (startIndex === 0) { + const originalElementList = draw.getOriginalElementList() + const trList = originalElementList[positionContext.index!].trList! + for (let r = 0; r < trList.length; r++) { + const tr = trList[r] + if (tr.id !== element.trId) continue + const tdList = tr.tdList + for (let d = 0; d < tdList.length; d++) { + const td = tdList[d] + if (td.id !== element.tdId) continue + // 移动到表格前 + if (r === 0 && d === 0) { + position.setPositionContext({ + isTable: false + }) + anchorStartIndex = positionContext.index! - 1 + anchorEndIndex = anchorStartIndex + draw.getTableTool().dispose() + } else { + // 上一个单元格 + let preTrIndex = r + let preTdIndex = d - 1 + if (preTdIndex < 0) { + preTrIndex = r - 1 + preTdIndex = trList[preTrIndex].tdList.length - 1 + } + const preTr = trList[preTrIndex] + const preTd = preTr.tdList[preTdIndex] + position.setPositionContext({ + isTable: true, + index: positionContext.index, + trIndex: preTrIndex, + tdIndex: preTdIndex, + tdId: preTr.id, + trId: preTd.id, + tableId: element.id + }) + anchorStartIndex = preTd.value.length - 1 + anchorEndIndex = anchorStartIndex + draw.getTableTool().render() + } + break + } + } + } + } + } + // 执行跳转 + if (!~anchorStartIndex || !~anchorEndIndex) return + rangeManager.setRange(anchorStartIndex, anchorEndIndex) + const isAnchorCollapsed = anchorStartIndex === anchorEndIndex + draw.render({ + curIndex: isAnchorCollapsed ? anchorStartIndex : undefined, + isSetCursor: isAnchorCollapsed, + isSubmitHistory: false, + isCompute: false + }) + evt.preventDefault() +} diff --git a/src/editor/core/event/handlers/keydown/right.ts b/src/editor/core/event/handlers/keydown/right.ts new file mode 100644 index 0000000..201bee3 --- /dev/null +++ b/src/editor/core/event/handlers/keydown/right.ts @@ -0,0 +1,147 @@ +import { ElementType } from '../../../../dataset/enum/Element' +import { isMod } from '../../../../utils/hotkey' +import { CanvasEvent } from '../../CanvasEvent' + +export function right(evt: KeyboardEvent, host: CanvasEvent) { + const draw = host.getDraw() + const isReadonly = draw.isReadonly() + if (isReadonly) return + const position = draw.getPosition() + const cursorPosition = position.getCursorPosition() + if (!cursorPosition) return + const { index } = cursorPosition + const positionList = position.getPositionList() + const positionContext = position.getPositionContext() + if (index > positionList.length - 1 && !positionContext.isTable) return + const rangeManager = draw.getRange() + const { startIndex, endIndex } = rangeManager.getRange() + const isCollapsed = rangeManager.getIsCollapsed() + let elementList = draw.getElementList() + // 单词整体移动 + let moveCount = 1 + if (isMod(evt)) { + const LETTER_REG = draw.getLetterReg() + // 起始位置 + const moveStartIndex = + evt.shiftKey && !isCollapsed && startIndex === cursorPosition?.index + ? endIndex + : startIndex + if (LETTER_REG.test(elementList[moveStartIndex + 1]?.value)) { + let i = moveStartIndex + 2 + while (i < elementList.length) { + const element = elementList[i] + if (!LETTER_REG.test(element.value)) { + break + } + moveCount++ + i++ + } + } + } + const curIndex = endIndex + moveCount + // shift则缩放选区 + let anchorStartIndex = curIndex + let anchorEndIndex = curIndex + if (evt.shiftKey && cursorPosition) { + if (startIndex !== endIndex) { + if (startIndex === cursorPosition.index) { + // 增大选区 + anchorStartIndex = startIndex + anchorEndIndex = curIndex + } else { + anchorStartIndex = startIndex + moveCount + anchorEndIndex = endIndex + } + } else { + anchorStartIndex = startIndex + } + } + // 表格单元格间跳转 + if (!evt.shiftKey) { + const element = elementList[endIndex] + const nextElement = elementList[endIndex + 1] + // 后一个元素是表格,则进入单元格第一个起始位置 + if (nextElement?.type === ElementType.TABLE) { + const trList = nextElement.trList! + const nextTr = trList[0] + const nextTd = nextTr.tdList[0] + position.setPositionContext({ + isTable: true, + index: endIndex + 1, + trIndex: 0, + tdIndex: 0, + tdId: nextTd.id, + trId: nextTr.id, + tableId: nextElement.id + }) + anchorStartIndex = 0 + anchorEndIndex = 0 + draw.getTableTool().render() + } else if (element.tableId) { + // 在表格单元格内&单元格元素最后 + if (!nextElement) { + const originalElementList = draw.getOriginalElementList() + const trList = originalElementList[positionContext.index!].trList! + for (let r = 0; r < trList.length; r++) { + const tr = trList[r] + if (tr.id !== element.trId) continue + const tdList = tr.tdList + for (let d = 0; d < tdList.length; d++) { + const td = tdList[d] + if (td.id !== element.tdId) continue + // 移动到表格后 + if (r === trList.length - 1 && d === tdList.length - 1) { + position.setPositionContext({ + isTable: false + }) + anchorStartIndex = positionContext.index! + anchorEndIndex = anchorStartIndex + elementList = draw.getElementList() + draw.getTableTool().dispose() + } else { + // 下一个单元格 + let nextTrIndex = r + let nextTdIndex = d + 1 + if (nextTdIndex > tdList.length - 1) { + nextTrIndex = r + 1 + nextTdIndex = 0 + } + const preTr = trList[nextTrIndex] + const preTd = preTr.tdList[nextTdIndex] + position.setPositionContext({ + isTable: true, + index: positionContext.index, + trIndex: nextTrIndex, + tdIndex: nextTdIndex, + tdId: preTr.id, + trId: preTd.id, + tableId: element.id + }) + anchorStartIndex = 0 + anchorEndIndex = anchorStartIndex + draw.getTableTool().render() + } + break + } + } + } + } + } + // 执行跳转 + const maxElementListIndex = elementList.length - 1 + if ( + anchorStartIndex > maxElementListIndex || + anchorEndIndex > maxElementListIndex + ) { + return + } + rangeManager.setRange(anchorStartIndex, anchorEndIndex) + const isAnchorCollapsed = anchorStartIndex === anchorEndIndex + draw.render({ + curIndex: isAnchorCollapsed ? anchorStartIndex : undefined, + isSetCursor: isAnchorCollapsed, + isSubmitHistory: false, + isCompute: false + }) + evt.preventDefault() +}