From f542739d3eb1be273e1f77c3a908dab329f8c619 Mon Sep 17 00:00:00 2001 From: Hufe921 Date: Wed, 27 Dec 2023 22:27:48 +0800 Subject: [PATCH] feat: enter to delete list #376 --- src/editor/core/command/CommandAdapt.ts | 29 +------ src/editor/core/draw/particle/ListParticle.ts | 75 +++++++++++++++++++ .../core/event/handlers/keydown/enter.ts | 70 +++++++++++++++++ .../handlers/{keydown.ts => keydown/index.ts} | 60 +++------------ src/editor/core/range/RangeManager.ts | 14 +++- 5 files changed, 167 insertions(+), 81 deletions(-) create mode 100644 src/editor/core/event/handlers/keydown/enter.ts rename src/editor/core/event/handlers/{keydown.ts => keydown/index.ts} (87%) diff --git a/src/editor/core/command/CommandAdapt.ts b/src/editor/core/command/CommandAdapt.ts index ad1f506b2..9f98fb1f5 100644 --- a/src/editor/core/command/CommandAdapt.ts +++ b/src/editor/core/command/CommandAdapt.ts @@ -559,34 +559,7 @@ export class CommandAdapt { public list(listType: ListType | null, listStyle?: ListStyle) { const isReadonly = this.draw.isReadonly() if (isReadonly) return - const { startIndex, endIndex } = this.range.getRange() - if (!~startIndex && !~endIndex) return - // 需要改变的元素列表 - const changeElementList = this.range.getRangeParagraphElementList() - if (!changeElementList || !changeElementList.length) return - // 如果包含列表则设置为取消列表 - const isUnsetList = changeElementList.find( - el => el.listType === listType && el.listStyle === listStyle - ) - // 设置值 - const listId = getUUID() - changeElementList.forEach(el => { - if (!isUnsetList && listType) { - el.listId = listId - el.listType = listType - el.listStyle = listStyle - } else { - if (el.listId) { - delete el.listId - delete el.listType - delete el.listStyle - } - } - }) - // 光标定位 - const isSetCursor = startIndex === endIndex - const curIndex = isSetCursor ? endIndex : startIndex - this.draw.render({ curIndex, isSetCursor }) + this.draw.getListParticle().setList(listType, listStyle) } public rowFlex(payload: RowFlex) { diff --git a/src/editor/core/draw/particle/ListParticle.ts b/src/editor/core/draw/particle/ListParticle.ts index 3d4c8ebcc..09418a54d 100644 --- a/src/editor/core/draw/particle/ListParticle.ts +++ b/src/editor/core/draw/particle/ListParticle.ts @@ -7,9 +7,13 @@ import { DeepRequired } from '../../../interface/Common' import { IEditorOption } from '../../../interface/Editor' import { IElement, IElementPosition } from '../../../interface/Element' import { IRow } from '../../../interface/Row' +import { getUUID } from '../../../utils' +import { RangeManager } from '../../range/RangeManager' import { Draw } from '../Draw' export class ListParticle { + private draw: Draw + private range: RangeManager private options: DeepRequired // 非递增样式直接返回默认值 @@ -18,9 +22,80 @@ export class ListParticle { private readonly LIST_GAP = 10 constructor(draw: Draw) { + this.draw = draw + this.range = draw.getRange() this.options = draw.getOptions() } + public setList(listType: ListType | null, listStyle?: ListStyle) { + const isReadonly = this.draw.isReadonly() + if (isReadonly) return + const { startIndex, endIndex } = this.range.getRange() + if (!~startIndex && !~endIndex) return + // 需要改变的元素列表 + const changeElementList = this.range.getRangeParagraphElementList() + if (!changeElementList || !changeElementList.length) return + // 如果包含列表则设置为取消列表 + const isUnsetList = changeElementList.find( + el => el.listType === listType && el.listStyle === listStyle + ) + if (isUnsetList || !listType) { + this.unsetList() + return + } + // 设置值 + const listId = getUUID() + changeElementList.forEach(el => { + el.listId = listId + el.listType = listType + el.listStyle = listStyle + }) + // 光标定位 + const isSetCursor = startIndex === endIndex + const curIndex = isSetCursor ? endIndex : startIndex + this.draw.render({ curIndex, isSetCursor }) + } + + public unsetList() { + const isReadonly = this.draw.isReadonly() + if (isReadonly) return + const { startIndex, endIndex } = this.range.getRange() + if (!~startIndex && !~endIndex) return + // 需要改变的元素列表 + const changeElementList = this.range + .getRangeParagraphElementList() + ?.filter(el => el.listId) + if (!changeElementList || !changeElementList.length) return + // 如果列表最后字符不是换行符则需插入换行符 + const elementList = this.draw.getElementList() + const endElement = elementList[endIndex] + if (endElement.listId) { + let start = endIndex + 1 + while (start < elementList.length) { + const element = elementList[start] + if (element.value === ZERO && !element.listWrap) break + if (element.listId !== endElement.listId) { + this.draw.spliceElementList(elementList, start, 0, { + value: ZERO + }) + break + } + start++ + } + } + // 取消设置 + changeElementList.forEach(el => { + delete el.listId + delete el.listType + delete el.listStyle + delete el.listWrap + }) + // 光标定位 + const isSetCursor = startIndex === endIndex + const curIndex = isSetCursor ? endIndex : startIndex + this.draw.render({ curIndex, isSetCursor }) + } + public computeListStyle( ctx: CanvasRenderingContext2D, elementList: IElement[] diff --git a/src/editor/core/event/handlers/keydown/enter.ts b/src/editor/core/event/handlers/keydown/enter.ts new file mode 100644 index 000000000..1c1c9a25e --- /dev/null +++ b/src/editor/core/event/handlers/keydown/enter.ts @@ -0,0 +1,70 @@ +import { ZERO } from '../../../../dataset/constant/Common' +import { IElement } from '../../../../interface/Element' +import { formatElementContext } from '../../../../utils/element' +import { CanvasEvent } from '../../CanvasEvent' + +export function enter(evt: KeyboardEvent, host: CanvasEvent) { + const draw = host.getDraw() + const isReadonly = draw.isReadonly() + const control = draw.getControl() + if (isReadonly || control.isPartRangeInControlOutside()) return + const rangeManager = draw.getRange() + const { startIndex, endIndex } = rangeManager.getRange() + const isCollapsed = rangeManager.getIsCollapsed() + const elementList = draw.getElementList() + const startElement = elementList[startIndex] + const endElement = elementList[endIndex] + // 最后一个列表项行首回车取消列表设置 + if ( + isCollapsed && + endElement.listId && + endElement.value === ZERO && + elementList[endIndex + 1]?.listId !== endElement.listId + ) { + draw.getListParticle().unsetList() + return + } + // 列表块内换行 + const enterText: IElement = { + value: ZERO + } + if (evt.shiftKey && startElement.listId) { + enterText.listWrap = true + } + // 标题结尾处回车无需格式化 + if ( + !( + endElement.titleId && + endElement.titleId !== elementList[endIndex + 1]?.titleId + ) + ) { + formatElementContext(elementList, [enterText], startIndex) + } + // 控件或文档插入换行元素 + const activeControl = control.getActiveControl() + let curIndex: number + if (activeControl && !control.isRangInPostfix()) { + curIndex = control.setValue([enterText]) + } else { + const position = draw.getPosition() + const cursorPosition = position.getCursorPosition() + if (!cursorPosition) return + const { index } = cursorPosition + if (isCollapsed) { + draw.spliceElementList(elementList, index + 1, 0, enterText) + } else { + draw.spliceElementList( + elementList, + startIndex + 1, + endIndex - startIndex, + enterText + ) + } + curIndex = index + 1 + } + if (~curIndex) { + rangeManager.setRange(curIndex, curIndex) + draw.render({ curIndex }) + } + evt.preventDefault() +} diff --git a/src/editor/core/event/handlers/keydown.ts b/src/editor/core/event/handlers/keydown/index.ts similarity index 87% rename from src/editor/core/event/handlers/keydown.ts rename to src/editor/core/event/handlers/keydown/index.ts index 440522981..c01f8d60d 100644 --- a/src/editor/core/event/handlers/keydown.ts +++ b/src/editor/core/event/handlers/keydown/index.ts @@ -1,12 +1,13 @@ -import { EditorMode, EditorZone } from '../../..' -import { ZERO } from '../../../dataset/constant/Common' -import { ElementType } from '../../../dataset/enum/Element' -import { KeyMap } from '../../../dataset/enum/KeyMap' -import { MoveDirection } from '../../../dataset/enum/Observer' -import { IElement, IElementPosition } from '../../../interface/Element' -import { formatElementContext } from '../../../utils/element' -import { isMod } from '../../../utils/hotkey' -import { CanvasEvent } from '../CanvasEvent' +import { ZERO } from '../../../../dataset/constant/Common' +import { EditorMode, EditorZone } from '../../../../dataset/enum/Editor' +import { ElementType } from '../../../../dataset/enum/Element' +import { KeyMap } from '../../../../dataset/enum/KeyMap' +import { MoveDirection } from '../../../../dataset/enum/Observer' +import { IElement, IElementPosition } from '../../../../interface/Element' +import { formatElementContext } from '../../../../utils/element' +import { isMod } from '../../../../utils/hotkey' +import { CanvasEvent } from '../../CanvasEvent' +import { enter } from './enter' export function keydown(evt: KeyboardEvent, host: CanvasEvent) { if (host.isComposing) return @@ -85,46 +86,7 @@ export function keydown(evt: KeyboardEvent, host: CanvasEvent) { rangeManager.setRange(curIndex, curIndex) draw.render({ curIndex }) } else if (evt.key === KeyMap.Enter) { - if (isReadonly || control.isPartRangeInControlOutside()) return - const enterText: IElement = { - value: ZERO - } - const startElement = elementList[startIndex] - const endElement = elementList[endIndex] - // 列表块内换行 - if (evt.shiftKey && startElement.listId) { - enterText.listWrap = true - } - // 标题结尾处回车无需格式化 - if ( - !( - endElement.titleId && - endElement.titleId !== elementList[endIndex + 1]?.titleId - ) - ) { - formatElementContext(elementList, [enterText], startIndex) - } - let curIndex: number - if (activeControl && !control.isRangInPostfix()) { - curIndex = control.setValue([enterText]) - } else { - if (isCollapsed) { - draw.spliceElementList(elementList, index + 1, 0, enterText) - } else { - draw.spliceElementList( - elementList, - startIndex + 1, - endIndex - startIndex, - enterText - ) - } - curIndex = index + 1 - } - if (~curIndex) { - rangeManager.setRange(curIndex, curIndex) - draw.render({ curIndex }) - } - evt.preventDefault() + enter(evt, host) } else if (evt.key === KeyMap.Left) { if (isReadonly) return if (index > 0) { diff --git a/src/editor/core/range/RangeManager.ts b/src/editor/core/range/RangeManager.ts index c45b19d1e..5e301474c 100644 --- a/src/editor/core/range/RangeManager.ts +++ b/src/editor/core/range/RangeManager.ts @@ -154,9 +154,12 @@ export class RangeManager { if (!rowArray.includes(rowNo)) { rowArray.unshift(rowNo) } + const element = elementList[start] + const preElement = elementList[start - 1] if ( - positionList[start]?.value === ZERO || - elementList[start].titleId !== elementList[start - 1]?.titleId + (element.value === ZERO && !element.listWrap) || + element.listId !== preElement?.listId || + element.titleId !== preElement?.titleId ) { break } @@ -181,9 +184,12 @@ export class RangeManager { // 向下查找 let end = endIndex while (end < positionList.length) { + const element = elementList[end] + const nextElement = elementList[end + 1] if ( - positionList[end].value === ZERO || - elementList[end].titleId !== elementList[end + 1]?.titleId + (element.value === ZERO && !element.listWrap) || + element.listId !== nextElement?.listId || + element.titleId !== nextElement?.titleId ) { break }