From 1cee9750337564c62e3d67c9012566b8fbe4334b Mon Sep 17 00:00:00 2001 From: Hufe921 Date: Tue, 5 Apr 2022 17:36:27 +0800 Subject: [PATCH] feat:optimize control active and destroy --- src/editor/core/draw/control/Control.ts | 217 +++++++++++++++--- .../core/draw/control/text/TextControl.ts | 181 +++------------ src/editor/core/event/CanvasEvent.ts | 9 +- src/editor/core/range/RangeManager.ts | 11 + src/editor/interface/Control.ts | 2 + 5 files changed, 229 insertions(+), 191 deletions(-) diff --git a/src/editor/core/draw/control/Control.ts b/src/editor/core/draw/control/Control.ts index ed5e207..1ebdde5 100644 --- a/src/editor/core/draw/control/Control.ts +++ b/src/editor/core/draw/control/Control.ts @@ -1,7 +1,6 @@ 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 { IControlInitOption, IControlInstance, IControlOption } from '../../../interface/Control' import { IElement } from '../../../interface/Element' import { RangeManager } from '../../range/RangeManager' import { Draw } from '../Draw' @@ -15,32 +14,16 @@ export class Control { private draw: Draw private range: RangeManager - private options: Required + private options: IControlOption private activeControl: IControlInstance | null constructor(draw: Draw) { this.draw = draw this.range = draw.getRange() - this.options = draw.getOptions() + this.options = draw.getOptions().control this.activeControl = null } - public getOptions(): Required { - return this.options - } - - public getElementList(): IElement[] { - return this.draw.getElementList() - } - - public getRange() { - return this.range.getRange() - } - - public getActiveControl(): IControlInstance | null { - return this.activeControl - } - // 判断选区部分在控件边界外 public isPartRangeInControlOutside(): boolean { const { startIndex, endIndex } = this.getRange() @@ -57,20 +40,41 @@ export class Control { return false } - public initControl(option: IControlInitOption): IControlInitResult { - // 调整光标位置 - const { newIndex, newElement } = this.moveCursor(option) - const control = newElement.control! - // 销毁激活控件 + public getElementList(): IElement[] { + return this.draw.getElementList() + } + + public getRange() { + return this.range.getRange() + } + + public getActiveControl(): IControlInstance | null { + return this.activeControl + } + + public initControl() { + const elementList = this.getElementList() + const range = this.getRange() + const element = elementList[range.startIndex] + // 判断控件是否已经激活 + if (this.activeControl) { + const controlElement = this.activeControl.getElement() + if (element.controlId === controlElement.controlId) return + } + // 销毁旧激活控件 this.destroyControl() // 激活控件 - if (control.type === ControlType.TEXT) { - this.activeControl = new TextControl(this) + if (element.control!.type === ControlType.TEXT) { + this.activeControl = new TextControl(element, this) + } + } + + public destroyControl() { + if (this.activeControl) { + this.activeControl = null } - return { newIndex } } - // 调整起始光标位置到控件合适的位置 public moveCursor(position: IControlInitOption): IMoveCursorResult { const { index, trIndex, tdIndex, tdValueIndex } = position let elementList = this.draw.getOriginalElementList() @@ -140,9 +144,158 @@ export class Control { } } - public destroyControl() { - if (this.activeControl) { - this.activeControl = null + public removeControl(startIndex: number): number { + const elementList = this.getElementList() + 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) + return leftIndex + } + + public shrinkBoundary() { + const elementList = this.getElementList() + const range = this.getRange() + const { startIndex, endIndex } = range + const startElement = elementList[startIndex] + const endElement = elementList[endIndex] + if (startIndex === endIndex) { + if (startElement.controlComponent === ControlComponent.PLACEHOLDER) { + // 找到第一个placeholder字符 + let index = startIndex - 1 + while (index > 0) { + const preElement = elementList[index] + if ( + preElement.controlId !== startElement.controlId || + preElement.controlComponent === ControlComponent.PREFIX + ) { + console.log(index) + range.startIndex = index + range.endIndex = index + break + } + index-- + } + } + } else { + // 首、尾为占位符时,收缩到最后一个前缀字符后 + if ( + startElement.controlComponent === ControlComponent.PLACEHOLDER || + endElement.controlComponent === ControlComponent.PLACEHOLDER + ) { + let index = endIndex - 1 + while (index > 0) { + const preElement = elementList[index] + if ( + preElement.controlId !== endElement.controlId + || preElement.controlComponent === ControlComponent.PREFIX + ) { + range.startIndex = index + range.endIndex = index + return + } + index-- + } + } + // 向右查找到第一个Value + if (startElement.controlComponent === ControlComponent.PREFIX) { + let index = startIndex + 1 + while (index < elementList.length) { + const nextElement = elementList[index] + if ( + nextElement.controlId !== startElement.controlId + || nextElement.controlComponent === ControlComponent.VALUE + ) { + range.startIndex = index - 1 + break + } else if (nextElement.controlComponent === ControlComponent.PLACEHOLDER) { + range.startIndex = index - 1 + range.endIndex = index - 1 + return + } + index++ + } + } + // 向左查找到第一个Value + if (endElement.controlComponent !== ControlComponent.VALUE) { + let index = startIndex - 1 + while (index > 0) { + const preElement = elementList[index] + if ( + preElement.controlId !== startElement.controlId + || preElement.controlComponent === ControlComponent.VALUE + ) { + range.startIndex = index + break + } else if (preElement.controlComponent === ControlComponent.PLACEHOLDER) { + range.startIndex = index + range.endIndex = index + return + } + index-- + } + } + } + } + + public removePlaceholder(startIndex: number) { + const elementList = this.getElementList() + const startElement = elementList[startIndex] + const nextElement = elementList[startIndex + 1] + if ( + startElement.controlComponent === ControlComponent.PLACEHOLDER || + nextElement.controlComponent === ControlComponent.PLACEHOLDER + ) { + let index = startIndex + while (index < elementList.length) { + const curElement = elementList[index] + if (curElement.controlId !== startElement.controlId) break + if (curElement.controlComponent === ControlComponent.PLACEHOLDER) { + elementList.splice(index, 1) + } else { + index++ + } + } + } + } + + public addPlaceholder(startIndex: number) { + const elementList = this.getElementList() + 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 + }) } } diff --git a/src/editor/core/draw/control/text/TextControl.ts b/src/editor/core/draw/control/text/TextControl.ts index 4b7a0dc..b515370 100644 --- a/src/editor/core/draw/control/text/TextControl.ts +++ b/src/editor/core/draw/control/text/TextControl.ts @@ -1,154 +1,21 @@ import { ControlComponent } from '../../../../dataset/enum/Control' -import { ElementType } from '../../../../dataset/enum/Element' import { KeyMap } from '../../../../dataset/enum/Keymap' -import { IControlInstance, IControlOption } from '../../../../interface/Control' +import { IControlInstance } from '../../../../interface/Control' import { IElement } from '../../../../interface/Element' -import { IRange } from '../../../../interface/Range' import { Control } from '../Control' export class TextControl implements IControlInstance { + private element: IElement private control: Control - private options: IControlOption - constructor(control: Control) { + constructor(element: IElement, control: Control) { + this.element = element this.control = control - this.options = control.getOptions().control } - public shrinkBoundary(elementList: IElement[], range: IRange) { - const { startIndex, endIndex } = range - if (startIndex === endIndex) return - const startElement = elementList[startIndex] - const endElement = elementList[endIndex] - // 首、尾为占位符时,收缩到最后一个前缀字符后 - if ( - startElement.controlComponent === ControlComponent.PLACEHOLDER || - endElement.controlComponent === ControlComponent.PLACEHOLDER - ) { - let index = endIndex - 1 - while (index > 0) { - const preElement = elementList[index] - if ( - preElement.controlId !== endElement.controlId - || preElement.controlComponent === ControlComponent.PREFIX - ) { - range.startIndex = index - range.endIndex = index - return - } - index-- - } - } - // 向右查找到第一个Value - if (startElement.controlComponent === ControlComponent.PREFIX) { - let index = startIndex + 1 - while (index < elementList.length) { - const nextElement = elementList[index] - if ( - nextElement.controlId !== startElement.controlId - || nextElement.controlComponent === ControlComponent.VALUE - ) { - range.startIndex = index - 1 - break - } else if (nextElement.controlComponent === ControlComponent.PLACEHOLDER) { - range.startIndex = index - 1 - range.endIndex = index - 1 - return - } - index++ - } - } - // 向左查找到第一个Value - if (endElement.controlComponent !== ControlComponent.VALUE) { - let index = startIndex - 1 - while (index > 0) { - const preElement = elementList[index] - if ( - preElement.controlId !== startElement.controlId - || preElement.controlComponent === ControlComponent.VALUE - ) { - range.startIndex = index - break - } else if (preElement.controlComponent === ControlComponent.PLACEHOLDER) { - range.startIndex = index - range.endIndex = index - return - } - index-- - } - } - } - - public removePlaceholder(elementList: IElement[], range: IRange) { - const { startIndex } = range - const startElement = elementList[startIndex] - const nextElement = elementList[startIndex + 1] - if ( - startElement.controlComponent === ControlComponent.PLACEHOLDER || - nextElement.controlComponent === ControlComponent.PLACEHOLDER - ) { - let index = startIndex - while (index < elementList.length) { - const curElement = elementList[index] - if (curElement.controlId !== startElement.controlId) break - if (curElement.controlComponent === ControlComponent.PLACEHOLDER) { - elementList.splice(index, 1) - } else { - index++ - } - } - } - } - - 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 getElement(): IElement { + return this.element } public getValue(): IElement[] { @@ -193,14 +60,14 @@ export class TextControl implements IControlInstance { const elementList = this.control.getElementList() const range = this.control.getRange() // 收缩边界到Value内 - this.shrinkBoundary(elementList, range) + this.control.shrinkBoundary() const { startIndex, endIndex } = range // 移除选区元素 if (startIndex !== endIndex) { elementList.splice(startIndex + 1, endIndex - startIndex) } else { // 移除空白占位符 - this.removePlaceholder(elementList, range) + this.control.removePlaceholder(startIndex) } // 插入 const startElement = elementList[startIndex] @@ -219,7 +86,7 @@ export class TextControl implements IControlInstance { const elementList = this.control.getElementList() const range = this.control.getRange() // 收缩边界到Value内 - this.shrinkBoundary(elementList, range) + this.control.shrinkBoundary() const { startIndex, endIndex } = range const startElement = elementList[startIndex] const endElement = elementList[endIndex] @@ -230,22 +97,23 @@ export class TextControl implements IControlInstance { elementList.splice(startIndex + 1, endIndex - startIndex) const value = this.getValue() if (!value.length) { - this.addPlaceholder(elementList, startIndex) + this.control.addPlaceholder(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) + if ( + startElement.controlComponent === ControlComponent.PREFIX || + endElement.controlComponent === ControlComponent.POSTFIX || + startElement.controlComponent === ControlComponent.PLACEHOLDER + ) { + // 前缀、后缀、占位符 + return this.control.removeControl(startIndex) } else { // 文本 elementList.splice(startIndex, 1) const value = this.getValue() if (!value.length) { - this.addPlaceholder(elementList, startIndex - 1) + this.control.addPlaceholder(startIndex - 1) } return startIndex - 1 } @@ -256,20 +124,23 @@ export class TextControl implements IControlInstance { elementList.splice(startIndex + 1, endIndex - startIndex) const value = this.getValue() if (!value.length) { - this.addPlaceholder(elementList, startIndex) + this.control.addPlaceholder(startIndex) } return startIndex } else { const endNextElement = elementList[endIndex + 1] - if (endNextElement.controlComponent === ControlComponent.POSTFIX) { - // 后缀 - return this.removeControl(elementList, range) + if (startElement.controlComponent === ControlComponent.PREFIX || + endNextElement.controlComponent === ControlComponent.POSTFIX || + startElement.controlComponent === ControlComponent.PLACEHOLDER + ) { + // 前缀、后缀、占位符 + return this.control.removeControl(startIndex) } else { // 文本 elementList.splice(startIndex + 1, 1) const value = this.getValue() if (!value.length) { - this.addPlaceholder(elementList, startIndex) + this.control.addPlaceholder(startIndex) } return startIndex } diff --git a/src/editor/core/event/CanvasEvent.ts b/src/editor/core/event/CanvasEvent.ts index ed7559f..ab11b40 100644 --- a/src/editor/core/event/CanvasEvent.ts +++ b/src/editor/core/event/CanvasEvent.ts @@ -175,7 +175,7 @@ export class CanvasEvent { tdIndex, tdValueIndex } = positionResult - const { newIndex } = this.control.initControl({ + const { newIndex } = this.control.moveCursor({ index, isTable, trIndex, @@ -187,8 +187,6 @@ export class CanvasEvent { } else { positionResult.index = newIndex } - } else { - this.control.destroyControl() } const { index, @@ -303,6 +301,8 @@ export class CanvasEvent { 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) @@ -476,6 +476,7 @@ export class CanvasEvent { // 忽略选区部分在控件的输入 return } + const activeControl = this.control.getActiveControl() const { TEXT, HYPERLINK, SUBSCRIPT, SUPERSCRIPT } = ElementType const text = data.replaceAll(`\n`, ZERO) const elementList = this.draw.getElementList() @@ -516,7 +517,7 @@ export class CanvasEvent { }) // 控件-移除placeholder let curIndex: number - if (positionContext.isControl) { + if (activeControl) { curIndex = this.control.setValue(inputData) } else { let start = 0 diff --git a/src/editor/core/range/RangeManager.ts b/src/editor/core/range/RangeManager.ts index 4366aa3..3a02e5d 100644 --- a/src/editor/core/range/RangeManager.ts +++ b/src/editor/core/range/RangeManager.ts @@ -53,6 +53,17 @@ export class RangeManager { this.range.startTrIndex = startTrIndex this.range.endTrIndex = endTrIndex this.range.isCrossRowCol = !!(startTdIndex || endTdIndex || startTrIndex || endTrIndex) + // 激活控件 + const control = this.draw.getControl() + if (~startIndex && ~endIndex && startIndex === startIndex) { + const elementList = this.draw.getElementList() + const element = elementList[startIndex] + if (element.type === ElementType.CONTROL) { + control.initControl() + return + } + } + control.destroyControl() } public setRangeStyle() { diff --git a/src/editor/interface/Control.ts b/src/editor/interface/Control.ts index 850c1f6..3554ecf 100644 --- a/src/editor/interface/Control.ts +++ b/src/editor/interface/Control.ts @@ -41,6 +41,8 @@ export interface IControlInitResult { } export interface IControlInstance { + getElement(): IElement; + getValue(): IElement[]; setValue(data: IElement[]): number;