feat:text control input data
This commit is contained in:
@@ -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 {
|
||||||
|
newIndex,
|
||||||
|
newElement: element
|
||||||
|
}
|
||||||
|
} else if (element.controlComponent === ControlComponent.POSTFIX) {
|
||||||
// POSTFIX-移动到最后一个后缀字符后
|
// POSTFIX-移动到最后一个后缀字符后
|
||||||
if (element.controlComponent === ControlComponent.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,6 +499,11 @@ export class CanvasEvent {
|
|||||||
}
|
}
|
||||||
return newElement
|
return newElement
|
||||||
})
|
})
|
||||||
|
// 控件-移除placeholder
|
||||||
|
let curIndex: number
|
||||||
|
if (positionContext.isControl) {
|
||||||
|
curIndex = this.control.setValue(inputData)
|
||||||
|
} else {
|
||||||
let start = 0
|
let start = 0
|
||||||
if (isCollapsed) {
|
if (isCollapsed) {
|
||||||
start = index + 1
|
start = index + 1
|
||||||
@@ -488,7 +515,8 @@ export class CanvasEvent {
|
|||||||
for (let i = 0; i < inputData.length; i++) {
|
for (let i = 0; i < inputData.length; i++) {
|
||||||
elementList.splice(start + i, 0, inputData[i])
|
elementList.splice(start + i, 0, inputData[i])
|
||||||
}
|
}
|
||||||
const curIndex = (isCollapsed ? index : startIndex) + inputData.length
|
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,8 +81,7 @@ 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, {
|
||||||
@@ -94,7 +94,6 @@ export function formatElementList(elementList: IElement[], options: IFormatEleme
|
|||||||
})
|
})
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
}
|
|
||||||
// 值
|
// 值
|
||||||
if (value && value.length) {
|
if (value && value.length) {
|
||||||
for (let v = 0; v < value.length; v++) {
|
for (let v = 0; v < value.length; v++) {
|
||||||
@@ -133,8 +132,7 @@ 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, {
|
||||||
@@ -147,7 +145,6 @@ export function formatElementList(elementList: IElement[], options: IFormatEleme
|
|||||||
})
|
})
|
||||||
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) {
|
||||||
elementList.splice(i, 1)
|
elementList.splice(i, 1)
|
||||||
|
|||||||
Reference in New Issue
Block a user