From 6243a8e4ca63be6964de49f101522a1811a95234 Mon Sep 17 00:00:00 2001 From: Hufe921 Date: Mon, 4 Apr 2022 22:29:17 +0800 Subject: [PATCH] feat:text control delete --- src/editor/core/draw/control/Control.ts | 14 ++ .../core/draw/control/text/TextControl.ts | 157 +++++++++++++++++- src/editor/core/event/CanvasEvent.ts | 45 +++-- src/editor/core/event/GlobalEvent.ts | 4 + src/editor/interface/Control.ts | 4 + 5 files changed, 208 insertions(+), 16 deletions(-) diff --git a/src/editor/core/draw/control/Control.ts b/src/editor/core/draw/control/Control.ts index 018da44..ed5e207 100644 --- a/src/editor/core/draw/control/Control.ts +++ b/src/editor/core/draw/control/Control.ts @@ -1,6 +1,7 @@ import { ControlComponent, ControlType } from '../../../dataset/enum/Control' import { ElementType } from '../../../dataset/enum/Element' import { IControlInitOption, IControlInitResult, IControlInstance } from '../../../interface/Control' +import { IEditorOption } from '../../../interface/Editor' import { IElement } from '../../../interface/Element' import { RangeManager } from '../../range/RangeManager' import { Draw } from '../Draw' @@ -14,14 +15,20 @@ export class Control { private draw: Draw private range: RangeManager + private options: Required private activeControl: IControlInstance | null constructor(draw: Draw) { this.draw = draw this.range = draw.getRange() + this.options = draw.getOptions() this.activeControl = null } + public getOptions(): Required { + return this.options + } + public getElementList(): IElement[] { return this.draw.getElementList() } @@ -146,4 +153,11 @@ export class Control { return this.activeControl.setValue(data) } + public keydown(evt: KeyboardEvent): number { + if (!this.activeControl) { + throw new Error('active control is null') + } + return this.activeControl.keydown(evt) + } + } \ No newline at end of file diff --git a/src/editor/core/draw/control/text/TextControl.ts b/src/editor/core/draw/control/text/TextControl.ts index 809e6a3..4b7a0dc 100644 --- a/src/editor/core/draw/control/text/TextControl.ts +++ b/src/editor/core/draw/control/text/TextControl.ts @@ -1,5 +1,7 @@ import { ControlComponent } from '../../../../dataset/enum/Control' -import { IControlInstance } from '../../../../interface/Control' +import { ElementType } from '../../../../dataset/enum/Element' +import { KeyMap } from '../../../../dataset/enum/Keymap' +import { IControlInstance, IControlOption } from '../../../../interface/Control' import { IElement } from '../../../../interface/Element' import { IRange } from '../../../../interface/Range' import { Control } from '../Control' @@ -7,9 +9,11 @@ import { Control } from '../Control' export class TextControl implements IControlInstance { private control: Control + private options: IControlOption constructor(control: Control) { this.control = control + this.options = control.getOptions().control } public shrinkBoundary(elementList: IElement[], range: IRange) { @@ -97,6 +101,94 @@ export class TextControl implements IControlInstance { } } + public removeControl(elementList: IElement[], range: IRange): number { + const { startIndex } = range + const startElement = elementList[startIndex] + let leftIndex = -1 + let rightIndex = -1 + // 向左查找 + let preIndex = startIndex + while (preIndex > 0) { + const preElement = elementList[preIndex] + if (preElement.controlId !== startElement.controlId) { + leftIndex = preIndex + break + } + preIndex-- + } + // 向右查找 + let nextIndex = startIndex + 1 + while (nextIndex < elementList.length) { + const nextElement = elementList[nextIndex] + if (nextElement.controlId !== startElement.controlId) { + rightIndex = nextIndex - 1 + break + } + nextIndex++ + } + if (!~leftIndex || !~rightIndex) return -1 + // 删除元素 + elementList.splice(leftIndex + 1, rightIndex - leftIndex) + // 清除实例 + this.control.destroyControl() + return leftIndex + } + + public addPlaceholder(elementList: IElement[], startIndex: number) { + const startElement = elementList[startIndex] + const control = startElement.control! + const placeholderStrList = control.placeholder.split('') + for (let p = 0; p < placeholderStrList.length; p++) { + const value = placeholderStrList[p] + elementList.splice(startIndex + p + 1, 0, { + value, + controlId: startElement.controlId, + type: ElementType.CONTROL, + control: startElement.control, + controlComponent: ControlComponent.PLACEHOLDER, + color: this.options.placeholderColor + }) + } + } + + public getValue(): IElement[] { + const elementList = this.control.getElementList() + const { startIndex } = this.control.getRange() + const startElement = elementList[startIndex] + const data: IElement[] = [] + // 向左查找 + let preIndex = startIndex + while (preIndex > 0) { + const preElement = elementList[preIndex] + if ( + preElement.controlId !== startElement.controlId || + preElement.controlComponent === ControlComponent.PREFIX + ) { + break + } + if (preElement.controlComponent === ControlComponent.VALUE) { + data.unshift(preElement) + } + preIndex-- + } + // 向右查找 + let nextIndex = startIndex + 1 + while (nextIndex < elementList.length) { + const nextElement = elementList[nextIndex] + if ( + nextElement.controlId !== startElement.controlId || + nextElement.controlComponent === ControlComponent.POSTFIX + ) { + break + } + if (nextElement.controlComponent === ControlComponent.VALUE) { + data.push(nextElement) + } + nextIndex++ + } + return data + } + public setValue(data: IElement[]): number { const elementList = this.control.getElementList() const range = this.control.getRange() @@ -123,4 +215,67 @@ export class TextControl implements IControlInstance { return start + data.length - 1 } + public keydown(evt: KeyboardEvent): number { + const elementList = this.control.getElementList() + const range = this.control.getRange() + // 收缩边界到Value内 + this.shrinkBoundary(elementList, range) + const { startIndex, endIndex } = range + const startElement = elementList[startIndex] + const endElement = elementList[endIndex] + // backspace + if (evt.key === KeyMap.Backspace) { + // 移除选区元素 + if (startIndex !== endIndex) { + elementList.splice(startIndex + 1, endIndex - startIndex) + const value = this.getValue() + if (!value.length) { + this.addPlaceholder(elementList, startIndex) + } + return startIndex + } else { + if (startElement.controlComponent === ControlComponent.PREFIX) { + // 前缀 + return this.removeControl(elementList, range) + } else if (endElement.controlComponent === ControlComponent.POSTFIX) { + // 后缀 + return this.removeControl(elementList, range) + } else { + // 文本 + elementList.splice(startIndex, 1) + const value = this.getValue() + if (!value.length) { + this.addPlaceholder(elementList, startIndex - 1) + } + return startIndex - 1 + } + } + } else if (evt.key === KeyMap.Delete) { + // 移除选区元素 + if (startIndex !== endIndex) { + elementList.splice(startIndex + 1, endIndex - startIndex) + const value = this.getValue() + if (!value.length) { + this.addPlaceholder(elementList, startIndex) + } + return startIndex + } else { + const endNextElement = elementList[endIndex + 1] + if (endNextElement.controlComponent === ControlComponent.POSTFIX) { + // 后缀 + return this.removeControl(elementList, range) + } else { + // 文本 + elementList.splice(startIndex + 1, 1) + const value = this.getValue() + if (!value.length) { + this.addPlaceholder(elementList, startIndex) + } + return startIndex + } + } + } + return -1 + } + } \ No newline at end of file diff --git a/src/editor/core/event/CanvasEvent.ts b/src/editor/core/event/CanvasEvent.ts index 1a494f6..ed7559f 100644 --- a/src/editor/core/event/CanvasEvent.ts +++ b/src/editor/core/event/CanvasEvent.ts @@ -187,6 +187,8 @@ export class CanvasEvent { } else { positionResult.index = newIndex } + } else { + this.control.destroyControl() } const { index, @@ -273,29 +275,42 @@ export class CanvasEvent { 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) return - // 判断是否允许删除 - if (isCollapsed && elementList[index].value === ZERO && index === 0) { - evt.preventDefault() - return - } - if (!isCollapsed) { - elementList.splice(startIndex + 1, endIndex - startIndex) + if (isReadonly || isPartRangeInControlOutside) return + let curIndex: number + if (activeControl) { + curIndex = this.control.keydown(evt) } else { - elementList.splice(index, 1) + // 判断是否允许删除 + 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 } - const curIndex = isCollapsed ? index - 1 : startIndex this.range.setRange(curIndex, curIndex) this.draw.render({ curIndex }) } else if (evt.key === KeyMap.Delete) { - if (isReadonly) return - if (!isCollapsed) { - elementList.splice(startIndex + 1, endIndex - startIndex) + if (isReadonly || isPartRangeInControlOutside) return + let curIndex: number + if (activeControl) { + curIndex = this.control.keydown(evt) } else { - elementList.splice(index + 1, 1) + if (!isCollapsed) { + elementList.splice(startIndex + 1, endIndex - startIndex) + } else { + elementList.splice(index + 1, 1) + } + curIndex = isCollapsed ? index : startIndex } - const curIndex = isCollapsed ? index : startIndex this.range.setRange(curIndex, curIndex) this.draw.render({ curIndex }) } else if (evt.key === KeyMap.Enter) { diff --git a/src/editor/core/event/GlobalEvent.ts b/src/editor/core/event/GlobalEvent.ts index 4044156..c4077e9 100644 --- a/src/editor/core/event/GlobalEvent.ts +++ b/src/editor/core/event/GlobalEvent.ts @@ -2,6 +2,7 @@ import { EDITOR_COMPONENT } from '../../dataset/constant/Editor' import { IEditorOption } from '../../interface/Editor' import { findParent } from '../../utils' import { Cursor } from '../cursor/Cursor' +import { Control } from '../draw/control/Control' import { Draw } from '../draw/Draw' import { HyperlinkParticle } from '../draw/particle/HyperlinkParticle' import { ImageParticle } from '../draw/particle/ImageParticle' @@ -20,6 +21,7 @@ export class GlobalEvent { private imageParticle: ImageParticle private tableTool: TableTool private hyperlinkParticle: HyperlinkParticle + private control: Control constructor(draw: Draw, canvasEvent: CanvasEvent) { this.draw = draw @@ -31,6 +33,7 @@ export class GlobalEvent { this.imageParticle = draw.getImageParticle() this.tableTool = draw.getTableTool() this.hyperlinkParticle = draw.getHyperlinkParticle() + this.control = draw.getControl() } public register() { @@ -74,6 +77,7 @@ export class GlobalEvent { this.imageParticle.clearResizer() this.tableTool.dispose() this.hyperlinkParticle.clearHyperlinkPopup() + this.control.destroyControl() } public setDragState() { diff --git a/src/editor/interface/Control.ts b/src/editor/interface/Control.ts index f0feb90..850c1f6 100644 --- a/src/editor/interface/Control.ts +++ b/src/editor/interface/Control.ts @@ -41,5 +41,9 @@ export interface IControlInitResult { } export interface IControlInstance { + getValue(): IElement[]; + setValue(data: IElement[]): number; + + keydown(evt: KeyboardEvent): number; } \ No newline at end of file