feat:text control input data

pr675
Hufe921 4 years ago
parent 546eb43ac8
commit 3602093d59

@ -1,39 +1,96 @@
import { ControlComponent } from '../../../dataset/enum/Control' import { ControlComponent, ControlType } from '../../../dataset/enum/Control'
import { ElementType } from '../../../dataset/enum/Element' import { ElementType } from '../../../dataset/enum/Element'
import { IControlInitOption, IControlInitResult, IControlInstance } from '../../../interface/Control'
import { IElement } from '../../../interface/Element' import { IElement } from '../../../interface/Element'
import { ICurrentPosition } from '../../../interface/Position' import { RangeManager } from '../../range/RangeManager'
import { Draw } from '../Draw' import { Draw } from '../Draw'
import { TextControl } from './text/TextControl'
interface IMoveCursorResult {
newIndex: number;
newElement: IElement;
}
export class Control { export class Control {
private draw: Draw private draw: Draw
private range: RangeManager
private activeControl: IControlInstance | null
constructor(draw: Draw) { constructor(draw: Draw) {
this.draw = draw this.draw = draw
this.range = draw.getRange()
this.activeControl = null
}
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()
if (!~startIndex && !~endIndex) return false
const elementList = this.getElementList()
const startElement = elementList[startIndex]
const endElement = elementList[endIndex]
if (
(startElement.type === ElementType.CONTROL || endElement.type === ElementType.CONTROL)
&& startElement.controlId !== endElement.controlId
) {
return true
}
return false
}
public initControl(option: IControlInitOption): IControlInitResult {
// 调整光标位置
const { newIndex, newElement } = this.moveCursor(option)
const control = newElement.control!
// 销毁激活控件
this.destroyControl()
// 激活控件
if (control.type === ControlType.TEXT) {
this.activeControl = new TextControl(this)
}
return { newIndex }
} }
// 调整起始光标位置到控件合适的位置 // 调整起始光标位置到控件合适的位置
public moveCursorIndex(position: ICurrentPosition) { public moveCursor(position: IControlInitOption): IMoveCursorResult {
const { index, trIndex, tdIndex, tdValueIndex } = position const { index, trIndex, tdIndex, tdValueIndex } = position
let elementList = this.draw.getOriginalElementList() let elementList = this.draw.getOriginalElementList()
let element: IElement let element: IElement
const newIndex = position.isTable ? tdValueIndex! : index
if (position.isTable) { if (position.isTable) {
elementList = elementList[index!].trList![trIndex!].tdList[tdIndex!].value elementList = elementList[index!].trList![trIndex!].tdList[tdIndex!].value
element = elementList[tdValueIndex!] element = elementList[tdValueIndex!]
} else { } else {
element = elementList[index] element = elementList[index]
} }
if (element.type !== ElementType.CONTROL) return if (element.controlComponent === ControlComponent.VALUE) {
// VALUE-无需移动 // VALUE-无需移动
if (element.controlComponent === ControlComponent.VALUE) return return {
// POSTFIX-移动到最后一个后缀字符后 newIndex,
if (element.controlComponent === ControlComponent.POSTFIX) { newElement: element
}
} else if (element.controlComponent === ControlComponent.POSTFIX) {
// POSTFIX-移动到最后一个后缀字符后
let startIndex = index + 1 let startIndex = index + 1
while (startIndex < elementList.length) { while (startIndex < elementList.length) {
const nextElement = elementList[startIndex] const nextElement = elementList[startIndex]
if (nextElement.controlId !== element.controlId) { if (nextElement.controlId !== element.controlId) {
position.index = startIndex - 1 return {
break newIndex: startIndex - 1,
newElement: elementList[startIndex - 1]
}
} }
startIndex++ startIndex++
} }
@ -46,8 +103,10 @@ export class Control {
nextElement.controlId !== element.controlId nextElement.controlId !== element.controlId
|| nextElement.controlComponent !== ControlComponent.PREFIX || nextElement.controlComponent !== ControlComponent.PREFIX
) { ) {
position.index = startIndex - 1 return {
break newIndex: startIndex - 1,
newElement: elementList[startIndex - 1]
}
} }
startIndex++ startIndex++
} }
@ -60,12 +119,31 @@ export class Control {
preElement.controlId !== element.controlId preElement.controlId !== element.controlId
|| preElement.controlComponent === ControlComponent.PREFIX || preElement.controlComponent === ControlComponent.PREFIX
) { ) {
position.index = startIndex return {
break newIndex: startIndex,
newElement: elementList[startIndex]
}
} }
startIndex-- startIndex--
} }
} }
return {
newIndex,
newElement: element
}
}
public destroyControl() {
if (this.activeControl) {
this.activeControl = null
}
}
public setValue(data: IElement[]): number {
if (!this.activeControl) {
throw new Error('active control is null')
}
return this.activeControl.setValue(data)
} }
} }

@ -1,3 +1,126 @@
export class TextControl { import { ControlComponent } from '../../../../dataset/enum/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 control: Control
constructor(control: Control) {
this.control = 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 setValue(data: IElement[]): number {
const elementList = this.control.getElementList()
const range = this.control.getRange()
// 收缩边界到Value内
this.shrinkBoundary(elementList, range)
const { startIndex, endIndex } = range
// 移除选区元素
if (startIndex !== endIndex) {
elementList.splice(startIndex + 1, endIndex - startIndex)
} else {
// 移除空白占位符
this.removePlaceholder(elementList, range)
}
// 插入
const startElement = elementList[startIndex]
const start = range.startIndex + 1
for (let i = 0; i < data.length; i++) {
elementList.splice(start + i, 0, {
...startElement,
...data[i],
controlComponent: ControlComponent.VALUE
})
}
return start + data.length - 1
}
} }

@ -166,9 +166,27 @@ export class CanvasEvent {
x: evt.offsetX, x: evt.offsetX,
y: evt.offsetY y: evt.offsetY
}) })
// 如果是控件-光标需移动到合适位置 // 激活控件
if (positionResult.isControl) { if (positionResult.isControl) {
this.control.moveCursorIndex(positionResult) const {
index,
isTable,
trIndex,
tdIndex,
tdValueIndex
} = positionResult
const { newIndex } = this.control.initControl({
index,
isTable,
trIndex,
tdIndex,
tdValueIndex
})
if (isTable) {
positionResult.tdValueIndex = newIndex
} else {
positionResult.index = newIndex
}
} }
const { const {
index, index,
@ -439,6 +457,10 @@ export class CanvasEvent {
if (!this.cursor) return if (!this.cursor) return
const cursorPosition = this.position.getCursorPosition() const cursorPosition = this.position.getCursorPosition()
if (!data || !cursorPosition || this.isCompositing) return if (!data || !cursorPosition || this.isCompositing) return
if (this.control.isPartRangeInControlOutside()) {
// 忽略选区部分在控件的输入
return
}
const { TEXT, HYPERLINK, SUBSCRIPT, SUPERSCRIPT } = ElementType const { TEXT, HYPERLINK, SUBSCRIPT, SUPERSCRIPT } = ElementType
const text = data.replaceAll(`\n`, ZERO) const text = data.replaceAll(`\n`, ZERO)
const elementList = this.draw.getElementList() const elementList = this.draw.getElementList()
@ -477,18 +499,24 @@ export class CanvasEvent {
} }
return newElement return newElement
}) })
let start = 0 // 控件-移除placeholder
if (isCollapsed) { let curIndex: number
start = index + 1 if (positionContext.isControl) {
curIndex = this.control.setValue(inputData)
} else { } else {
start = startIndex + 1 let start = 0
elementList.splice(startIndex + 1, endIndex - startIndex) if (isCollapsed) {
} start = index + 1
// 禁止直接使用解构存在性能问题 } else {
for (let i = 0; i < inputData.length; i++) { start = startIndex + 1
elementList.splice(start + i, 0, inputData[i]) 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
} }
const curIndex = (isCollapsed ? index : startIndex) + inputData.length
this.range.setRange(curIndex, curIndex) this.range.setRange(curIndex, curIndex)
this.draw.render({ curIndex }) this.draw.render({ curIndex })
} }

@ -27,3 +27,19 @@ export interface IControlOption {
prefix?: string; prefix?: string;
postfix?: string; postfix?: string;
} }
export interface IControlInitOption {
index: number;
isTable?: boolean;
trIndex?: number;
tdIndex?: number;
tdValueIndex?: number;
}
export interface IControlInitResult {
newIndex: number;
}
export interface IControlInstance {
setValue(data: IElement[]): number;
}

@ -1,6 +1,7 @@
import { deepClone, getUUID } from '.' import { deepClone, getUUID } from '.'
import { ElementType, IEditorOption, IElement } from '..' import { ElementType, IEditorOption, IElement } from '..'
import { ZERO } from '../dataset/constant/Common' import { ZERO } from '../dataset/constant/Common'
import { defaultControlOption } from '../dataset/constant/Control'
import { EDITOR_ELEMENT_ZIP_ATTR } from '../dataset/constant/Element' import { EDITOR_ELEMENT_ZIP_ATTR } from '../dataset/constant/Element'
import { ControlComponent } from '../dataset/enum/Control' import { ControlComponent } from '../dataset/enum/Control'
@ -80,20 +81,18 @@ export function formatElementList(elementList: IElement[], options: IFormatEleme
thePrePostfixArgs.color = editorOptions.control.bracketColor thePrePostfixArgs.color = editorOptions.control.bracketColor
} }
// 前缀 // 前缀
if (prefix) { const prefixStrList = (prefix || defaultControlOption.prefix).split('')
const prefixStrList = prefix.split('') for (let p = 0; p < prefixStrList.length; p++) {
for (let p = 0; p < prefixStrList.length; p++) { const value = prefixStrList[p]
const value = prefixStrList[p] elementList.splice(i, 0, {
elementList.splice(i, 0, { controlId,
controlId, value,
value, type: el.type,
type: el.type, control: el.control,
control: el.control, controlComponent: ControlComponent.PREFIX,
controlComponent: ControlComponent.PREFIX, ...thePrePostfixArgs
...thePrePostfixArgs })
}) i++
i++
}
} }
// 值 // 值
if (value && value.length) { if (value && value.length) {
@ -133,20 +132,18 @@ export function formatElementList(elementList: IElement[], options: IFormatEleme
} }
} }
// 后缀 // 后缀
if (postfix) { const postfixStrList = (postfix || defaultControlOption.postfix).split('')
const postfixStrList = postfix.split('') for (let p = 0; p < postfixStrList.length; p++) {
for (let p = 0; p < postfixStrList.length; p++) { const value = postfixStrList[p]
const value = postfixStrList[p] elementList.splice(i, 0, {
elementList.splice(i, 0, { controlId,
controlId, value,
value, type: el.type,
type: el.type, control: el.control,
control: el.control, controlComponent: ControlComponent.POSTFIX,
controlComponent: ControlComponent.POSTFIX, ...thePrePostfixArgs
...thePrePostfixArgs })
}) i++
i++
}
} }
i-- i--
} else if ((!el.type || el.type === ElementType.TEXT) && el.value.length > 1) { } else if ((!el.type || el.type === ElementType.TEXT) && el.value.length > 1) {

Loading…
Cancel
Save