You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

400 lines
13 KiB

import { deepClone, getUUID, splitText } from '.'
import { ElementType, IEditorOption, IElement } from '..'
import { LaTexParticle } from '../core/draw/particle/latex/LaTexParticle'
import { defaultCheckboxOption } from '../dataset/constant/Checkbox'
import { ZERO } from '../dataset/constant/Common'
import { defaultControlOption } from '../dataset/constant/Control'
import { EDITOR_ELEMENT_ZIP_ATTR } from '../dataset/constant/Element'
import { ControlComponent, ControlType } from '../dataset/enum/Control'
interface IFormatElementListOption {
isHandleFirstElement?: boolean;
editorOptions: Required<IEditorOption>;
}
export function formatElementList(elementList: IElement[], options: IFormatElementListOption) {
const { isHandleFirstElement, editorOptions } = <IFormatElementListOption>{
isHandleFirstElement: true,
...options
}
if (isHandleFirstElement && elementList[0]?.value !== ZERO) {
elementList.unshift({
value: ZERO
})
}
let i = 0
while (i < elementList.length) {
let el = elementList[i]
if (el.type === ElementType.TABLE) {
const tableId = getUUID()
el.id = tableId
if (el.trList) {
for (let t = 0; t < el.trList.length; t++) {
const tr = el.trList[t]
const trId = getUUID()
tr.id = trId
for (let d = 0; d < tr.tdList.length; d++) {
const td = tr.tdList[d]
const tdId = getUUID()
td.id = tdId
formatElementList(td.value, options)
for (let v = 0; v < td.value.length; v++) {
const value = td.value[v]
value.tdId = tdId
value.trId = trId
value.tableId = tableId
}
}
}
}
} else if (el.type === ElementType.HYPERLINK) {
const valueList = el.valueList || []
// 移除父节点
elementList.splice(i, 1)
// 追加字节点
if (valueList.length) {
// 元素展开
if (valueList[0].value.length > 1) {
const deleteValue = valueList.splice(0, 1)[0]
const deleteTextList = splitText(deleteValue.value)
for (let d = 0; d < deleteTextList.length; d++) {
valueList.splice(d, 0, { ...deleteValue, value: deleteTextList[d] })
}
}
const hyperlinkId = getUUID()
for (let v = 0; v < valueList.length; v++) {
const value = valueList[v]
value.type = el.type
value.url = el.url
value.hyperlinkId = hyperlinkId
elementList.splice(i, 0, value)
i++
}
}
i--
} else if (el.type === ElementType.DATE) {
const valueList = el.valueList || []
// 移除父节点
elementList.splice(i, 1)
// 追加字节点
if (valueList.length) {
// 元素展开
if (valueList[0].value.length > 1) {
const deleteValue = valueList.splice(0, 1)[0]
const deleteTextList = splitText(deleteValue.value)
for (let d = 0; d < deleteTextList.length; d++) {
valueList.splice(d, 0, { ...deleteValue, value: deleteTextList[d] })
}
}
const dateId = getUUID()
for (let v = 0; v < valueList.length; v++) {
const value = valueList[v]
value.type = el.type
value.dateFormat = el.dateFormat
value.dateId = dateId
elementList.splice(i, 0, value)
i++
}
}
i--
} else if (el.type === ElementType.CONTROL) {
const { prefix, postfix, value, placeholder, code, type, valueSets } = el.control!
const controlId = getUUID()
// 移除父节点
elementList.splice(i, 1)
// 前后缀个性化设置
const thePrePostfixArgs: Pick<IElement, 'color'> = {}
if (editorOptions && editorOptions.control) {
thePrePostfixArgs.color = editorOptions.control.bracketColor
}
// 前缀
const prefixStrList = splitText(prefix || defaultControlOption.prefix)
for (let p = 0; p < prefixStrList.length; p++) {
const value = prefixStrList[p]
elementList.splice(i, 0, {
controlId,
value,
type: el.type,
control: el.control,
controlComponent: ControlComponent.PREFIX,
...thePrePostfixArgs
})
i++
}
// 值
if (
(value && value.length) ||
type === ControlType.CHECKBOX ||
(type === ControlType.SELECT && code && (!value || !value.length))
) {
let valueList: IElement[] = value || []
if (type === ControlType.CHECKBOX) {
const codeList = code ? code.split(',') : []
if (Array.isArray(valueSets) && valueSets.length) {
for (let v = 0; v < valueSets.length; v++) {
const valueSet = valueSets[v]
// checkbox组件
elementList.splice(i, 0, {
controlId,
value: '',
type: el.type,
control: el.control,
controlComponent: ControlComponent.CHECKBOX,
checkbox: {
code: valueSet.code,
value: codeList.includes(valueSet.code)
}
})
i++
// 文本
const valueStrList = splitText(valueSet.value)
for (let e = 0; e < valueStrList.length; e++) {
const value = valueStrList[e]
const isLastLetter = e === valueStrList.length - 1
elementList.splice(i, 0, {
controlId,
value,
type: el.type,
letterSpacing: isLastLetter ? defaultCheckboxOption.gap : 0,
control: el.control,
controlComponent: ControlComponent.VALUE
})
i++
}
}
}
} else {
if (!value || !value.length) {
if (Array.isArray(valueSets) && valueSets.length) {
const valueSet = valueSets.find(v => v.code === code)
if (valueSet) {
valueList = [{
value: valueSet.value
}]
}
}
}
for (let v = 0; v < valueList.length; v++) {
const element = valueList[v]
const valueStrList = splitText(element.value)
for (let e = 0; e < valueStrList.length; e++) {
const value = valueStrList[e]
elementList.splice(i, 0, {
...element,
controlId,
value,
type: el.type,
control: el.control,
controlComponent: ControlComponent.VALUE
})
i++
}
}
}
} else if (placeholder) {
// placeholder
const thePlaceholderArgs: Pick<IElement, 'color'> = {}
if (editorOptions && editorOptions.control) {
thePlaceholderArgs.color = editorOptions.control.placeholderColor
}
const placeholderStrList = splitText(placeholder)
for (let p = 0; p < placeholderStrList.length; p++) {
const value = placeholderStrList[p]
elementList.splice(i, 0, {
controlId,
value,
type: el.type,
control: el.control,
controlComponent: ControlComponent.PLACEHOLDER,
...thePlaceholderArgs
})
i++
}
}
// 后缀
const postfixStrList = splitText(postfix || defaultControlOption.postfix)
for (let p = 0; p < postfixStrList.length; p++) {
const value = postfixStrList[p]
elementList.splice(i, 0, {
controlId,
value,
type: el.type,
control: el.control,
controlComponent: ControlComponent.POSTFIX,
...thePrePostfixArgs
})
i++
}
i--
} else if ((!el.type || el.type === ElementType.TEXT) && el.value.length > 1) {
elementList.splice(i, 1)
const valueList = splitText(el.value)
for (let v = 0; v < valueList.length; v++) {
elementList.splice(i + v, 0, { ...el, value: valueList[v] })
}
el = elementList[i]
}
if (el.value === '\n') {
el.value = ZERO
}
if (el.type === ElementType.IMAGE || el.type === ElementType.BLOCK) {
el.id = getUUID()
}
if (el.type === ElementType.LATEX) {
const { svg, width, height } = LaTexParticle.convertLaTextToSVG(el.value)
el.width = el.width || width
el.height = el.height || height
el.laTexSVG = svg
el.id = getUUID()
}
i++
}
}
export function isSameElementExceptValue(source: IElement, target: IElement): boolean {
const sourceKeys = Object.keys(source)
const targetKeys = Object.keys(target)
if (sourceKeys.length !== targetKeys.length) return false
for (let s = 0; s < sourceKeys.length; s++) {
const key = sourceKeys[s] as never
if (key === 'value') continue
if (source[key] !== target[key]) {
return false
}
}
return true
}
export function pickElementAttr(payload: IElement): IElement {
const element: IElement = {
value: payload.value === ZERO ? `\n` : payload.value,
}
EDITOR_ELEMENT_ZIP_ATTR.forEach(attr => {
const value = payload[attr] as never
if (value !== undefined) {
element[attr] = value
}
})
return element
}
export function zipElementList(payload: IElement[]): IElement[] {
const elementList = deepClone(payload)
const zipElementListData: IElement[] = []
let e = 0
while (e < elementList.length) {
let element = elementList[e]
// 筛选所需项
if (e === 0 && element.value === ZERO) {
e++
continue
}
// 表格、超链接递归处理
if (element.type === ElementType.TABLE) {
if (element.trList) {
for (let t = 0; t < element.trList.length; t++) {
const tr = element.trList[t]
delete tr.id
for (let d = 0; d < tr.tdList.length; d++) {
const td = tr.tdList[d]
tr.tdList[d] = {
colspan: td.colspan,
rowspan: td.rowspan,
value: zipElementList(td.value)
}
}
}
}
} else if (element.type === ElementType.HYPERLINK) {
// 超链接处理
const hyperlinkId = element.hyperlinkId
const hyperlinkElement: IElement = {
type: ElementType.HYPERLINK,
value: '',
url: element.url
}
const valueList: IElement[] = []
while (e < elementList.length) {
const hyperlinkE = elementList[e]
if (hyperlinkId !== hyperlinkE.hyperlinkId) {
e--
break
}
delete hyperlinkE.type
delete hyperlinkE.url
valueList.push(hyperlinkE)
e++
}
hyperlinkElement.valueList = zipElementList(valueList)
element = hyperlinkElement
} else if (element.type === ElementType.DATE) {
const dateId = element.dateId
const dateElement: IElement = {
type: ElementType.DATE,
value: '',
dateFormat: element.dateFormat
}
const valueList: IElement[] = []
while (e < elementList.length) {
const dateE = elementList[e]
if (dateId !== dateE.dateId) {
e--
break
}
delete dateE.type
delete dateE.dateFormat
valueList.push(dateE)
e++
}
dateElement.valueList = zipElementList(valueList)
element = dateElement
} else if (element.type === ElementType.CONTROL) {
// 控件处理
const controlId = element.controlId
const control = element.control!
const controlElement: IElement = {
type: ElementType.CONTROL,
value: '',
control
}
const valueList: IElement[] = []
while (e < elementList.length) {
const controlE = elementList[e]
if (controlId !== controlE.controlId) {
e--
break
}
if (controlE.controlComponent === ControlComponent.VALUE) {
delete controlE.type
delete controlE.control
valueList.push(controlE)
}
e++
}
controlElement.control!.value = zipElementList(valueList)
element = controlElement
}
// 组合元素
const pickElement = pickElementAttr(element)
if (!element.type || element.type === ElementType.TEXT) {
while (e < elementList.length) {
const nextElement = elementList[e + 1]
e++
if (
nextElement
&& isSameElementExceptValue(pickElement, pickElementAttr(nextElement))
) {
const nextValue = nextElement.value === ZERO ? '\n' : nextElement.value
pickElement.value += nextValue
} else {
break
}
}
} else {
e++
}
zipElementListData.push(pickElement)
}
return zipElementListData
}